@@ -279,7 +279,11 @@ export function useChat(
279279
280280 const sendMessageRef = useRef < UseChatReturn [ 'sendMessage' ] > ( async ( ) => { } )
281281 const processSSEStreamRef = useRef <
282- ( reader : ReadableStreamDefaultReader < Uint8Array > , assistantId : string ) => Promise < void >
282+ (
283+ reader : ReadableStreamDefaultReader < Uint8Array > ,
284+ assistantId : string ,
285+ expectedGen ?: number
286+ ) => Promise < void >
283287 > ( async ( ) => { } )
284288 const finalizeRef = useRef < ( options ?: { error ?: boolean } ) => void > ( ( ) => { } )
285289
@@ -379,7 +383,8 @@ export function useChat(
379383 }
380384
381385 appliedChatIdRef . current = chatHistory . id
382- setMessages ( chatHistory . messages . map ( mapStoredMessage ) )
386+ const mappedMessages = chatHistory . messages . map ( mapStoredMessage )
387+ setMessages ( mappedMessages )
383388
384389 if ( chatHistory . resources . length > 0 ) {
385390 setResources ( chatHistory . resources )
@@ -392,6 +397,7 @@ export function useChat(
392397 }
393398
394399 if ( activeStreamId && ! sendingRef . current ) {
400+ abortControllerRef . current ?. abort ( )
395401 const gen = ++ streamGenRef . current
396402 const abortController = new AbortController ( )
397403 abortControllerRef . current = abortController
@@ -461,7 +467,7 @@ export function useChat(
461467 } ,
462468 } )
463469
464- await processSSEStreamRef . current ( combinedStream . getReader ( ) , assistantId )
470+ await processSSEStreamRef . current ( combinedStream . getReader ( ) , assistantId , gen )
465471 } catch ( err ) {
466472 if ( err instanceof Error && err . name === 'AbortError' ) return
467473 } finally {
@@ -489,7 +495,11 @@ export function useChat(
489495 } , [ activeResourceId , resources ] )
490496
491497 const processSSEStream = useCallback (
492- async ( reader : ReadableStreamDefaultReader < Uint8Array > , assistantId : string ) => {
498+ async (
499+ reader : ReadableStreamDefaultReader < Uint8Array > ,
500+ assistantId : string ,
501+ expectedGen ?: number
502+ ) => {
493503 const decoder = new TextDecoder ( )
494504 let buffer = ''
495505 const blocks : ContentBlock [ ] = [ ]
@@ -511,10 +521,15 @@ export function useChat(
511521 return b
512522 }
513523
524+ const isStale = ( ) =>
525+ expectedGen !== undefined && streamGenRef . current !== expectedGen
526+
514527 const flush = ( ) => {
528+ if ( isStale ( ) ) return
515529 streamingBlocksRef . current = [ ...blocks ]
516530 const snapshot = { content : runningText , contentBlocks : [ ...blocks ] }
517531 setMessages ( ( prev ) => {
532+ if ( expectedGen !== undefined && streamGenRef . current !== expectedGen ) return prev
518533 const idx = prev . findIndex ( ( m ) => m . id === assistantId )
519534 if ( idx >= 0 ) {
520535 return prev . map ( ( m ) => ( m . id === assistantId ? { ...m , ...snapshot } : m ) )
@@ -524,6 +539,10 @@ export function useChat(
524539 }
525540
526541 while ( true ) {
542+ if ( isStale ( ) ) {
543+ reader . cancel ( ) . catch ( ( ) => { } )
544+ break
545+ }
527546 const { done, value } = await reader . read ( )
528547 if ( done ) break
529548
@@ -975,15 +994,15 @@ export function useChat(
975994 content : message ,
976995 ...( storedAttachments && { fileAttachments : storedAttachments } ) ,
977996 }
978- queryClient . setQueryData < TaskChatHistory > ( taskKeys . detail ( chatIdRef . current ) , ( old ) =>
979- old
997+ queryClient . setQueryData < TaskChatHistory > ( taskKeys . detail ( chatIdRef . current ) , ( old ) => {
998+ return old
980999 ? {
9811000 ...old ,
9821001 messages : [ ...old . messages , cachedUserMsg ] ,
9831002 activeStreamId : userMessageId ,
9841003 }
9851004 : undefined
986- )
1005+ } )
9871006 }
9881007
9891008 const userAttachments = storedAttachments ?. map ( toDisplayAttachment )
@@ -1180,6 +1199,8 @@ export function useChat(
11801199
11811200 useEffect ( ( ) => {
11821201 return ( ) => {
1202+ abortControllerRef . current ?. abort ( )
1203+ abortControllerRef . current = null
11831204 streamGenRef . current ++
11841205 sendingRef . current = false
11851206 }
0 commit comments