one more fix

This commit is contained in:
Vikhyath Mondreti
2026-04-10 15:31:02 -07:00
parent 09f06cb683
commit d11d3df349
3 changed files with 64 additions and 1 deletions

View File

@@ -77,6 +77,7 @@ import { getNextWorkflowColor } from '@/lib/workflows/colors'
import { getQueryClient } from '@/app/_shell/providers/get-query-client'
import { invalidateResourceQueries } from '@/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-registry'
import {
buildCompletedPreviewSessions,
type FilePreviewSessionsState,
INITIAL_FILE_PREVIEW_SESSIONS_STATE,
reduceFilePreviewSessions,
@@ -766,6 +767,18 @@ export function useChat(
[completePreviewSession, syncPreviewSessionRefs]
)
const reconcileTerminalPreviewSessions = useCallback(() => {
const completedAt = new Date().toISOString()
const completedSessions = buildCompletedPreviewSessions(
previewSessionsStateRef.current.sessions,
completedAt
)
for (const session of completedSessions) {
applyCompletedPreviewSession(session)
}
}, [applyCompletedPreviewSession])
const removePreviewSessionImmediate = useCallback(
(sessionId: string) => {
const nextState = reduceFilePreviewSessions(previewSessionsStateRef.current, {
@@ -2305,6 +2318,7 @@ export function useChat(
const finalize = useCallback(
(options?: { error?: boolean }) => {
reconcileTerminalPreviewSessions()
sendingRef.current = false
setIsSending(false)
setIsReconnecting(false)
@@ -2333,7 +2347,7 @@ export function useChat(
})
}
},
[invalidateChatQueries]
[invalidateChatQueries, reconcileTerminalPreviewSessions]
)
finalizeRef.current = finalize

View File

@@ -4,6 +4,7 @@
import { describe, expect, it } from 'vitest'
import type { FilePreviewSession } from '@/lib/copilot/request/session'
import {
buildCompletedPreviewSessions,
INITIAL_FILE_PREVIEW_SESSIONS_STATE,
reduceFilePreviewSessions,
} from '@/app/workspace/[workspaceId]/home/hooks/use-file-preview-sessions'
@@ -30,6 +31,40 @@ function createSession(
}
describe('reduceFilePreviewSessions', () => {
it('builds complete sessions for terminal stream reconciliation', () => {
const completedAt = '2026-04-10T00:00:10.000Z'
const nextSessions = buildCompletedPreviewSessions(
{
'preview-1': createSession({
id: 'preview-1',
toolCallId: 'preview-1',
status: 'pending',
previewText: 'draft',
}),
'preview-2': createSession({
id: 'preview-2',
toolCallId: 'preview-2',
status: 'streaming',
previewText: 'partial',
}),
'preview-3': createSession({
id: 'preview-3',
toolCallId: 'preview-3',
status: 'complete',
previewText: 'done',
completedAt: '2026-04-10T00:00:03.000Z',
}),
},
completedAt
)
expect(nextSessions).toHaveLength(2)
expect(nextSessions.map((session) => session.id)).toEqual(['preview-1', 'preview-2'])
expect(nextSessions.every((session) => session.status === 'complete')).toBe(true)
expect(nextSessions.every((session) => session.updatedAt === completedAt)).toBe(true)
expect(nextSessions.every((session) => session.completedAt === completedAt)).toBe(true)
})
it('hydrates the latest active preview session', () => {
const state = reduceFilePreviewSessions(INITIAL_FILE_PREVIEW_SESSIONS_STATE, {
type: 'hydrate',

View File

@@ -48,6 +48,20 @@ export function pickActiveSessionId(
return latestActive?.id ?? null
}
export function buildCompletedPreviewSessions(
sessions: Record<string, FilePreviewSession>,
completedAt: string
): FilePreviewSession[] {
return Object.values(sessions)
.filter((session) => session.status !== 'complete')
.map((session) => ({
...session,
status: 'complete' as const,
updatedAt: completedAt,
completedAt,
}))
}
export function reduceFilePreviewSessions(
state: FilePreviewSessionsState,
action: FilePreviewSessionsAction