fix(mobile): retain structured transcript during reconnect

This commit is contained in:
Merge Sim
2026-09-01 16:27:20 -07:00
parent 3031756319
commit ae6873ef1f
3 changed files with 30 additions and 1 deletions
@@ -803,4 +803,22 @@ describe('useMobileStructuredAgentSession', () => {
expect(hook?.session.messages).toHaveLength(1)
expect(hook?.session.status).toBe('ready')
})
it('keeps the transcript visible while a reconnect is loading', async () => {
await act(async () => {
renderer = create(createElement(Harness, { connected: true }))
})
await vi.waitFor(() => expect(listener).toEqual(expect.any(Function)))
act(() => listener?.(snapshotWithMessage()))
expect(hook?.session.messages).toHaveLength(1)
await act(async () => {
renderer?.update(createElement(Harness, { connected: false }))
})
await act(async () => {
renderer?.update(createElement(Harness, { connected: true }))
})
expect(hook?.session.messages).toHaveLength(1)
})
})
@@ -40,6 +40,7 @@ export function useMobileStructuredAgentState(args: {
const [state, setState] = useState<StructuredAgentSessionState>(EMPTY_STRUCTURED_AGENT_SESSION)
const [loadingOlder, setLoadingOlder] = useState(false)
const stateRef = useRef(state)
const sessionIdentityRef = useRef<{ client: RpcClient; sessionId: string } | null>(null)
useLayoutEffect(() => {
stateRef.current = state
}, [state])
@@ -50,6 +51,7 @@ export function useMobileStructuredAgentState(args: {
useEffect(() => {
if (!client || !sessionId || !enabled) {
sessionIdentityRef.current = null
setState(EMPTY_STRUCTURED_AGENT_SESSION)
setLoadingOlder(false)
return
@@ -60,6 +62,14 @@ export function useMobileStructuredAgentState(args: {
// nor empty-state copy, so the chat reads as gone rather than offline.
return
}
const sessionChanged =
sessionIdentityRef.current?.client !== client ||
sessionIdentityRef.current?.sessionId !== sessionId
sessionIdentityRef.current = { client, sessionId }
if (sessionChanged) {
// Do not leak the previous tab's transcript while the new session loads.
setState(EMPTY_STRUCTURED_AGENT_SESSION)
}
apply({ type: 'loading' })
const holderId = structuredAgentSessionHolderId('mobile-chat')
let cancelled = false
@@ -95,7 +95,8 @@ export function reduceStructuredAgentSession(
action: StructuredAgentSessionAction
): StructuredAgentSessionState {
if (action.type === 'loading') {
return { ...EMPTY_STRUCTURED_AGENT_SESSION, status: 'loading' }
// Keep the last transcript visible while a reconnect rehydrates the stream.
return { ...state, status: 'loading', error: undefined }
}
if (action.type === 'error') {
return { ...state, status: 'error', error: action.message }