@@ -176,11 +176,6 @@ describe('reduceFilePreviewSessions', () => {
176176 } )
177177
178178 it ( 'lingers on the completed session when it is the only one (no successor)' , ( ) => {
179- // Completing the only session must NOT drop activeSessionId to null.
180- // The linger keeps the completed session active so downstream consumers
181- // continue to receive previewText and the file viewer stays mounted,
182- // preserving the user's scroll position until a new tool call arrives
183- // or the session store is reset.
184179 const onlyStreaming = reduceFilePreviewSessions ( INITIAL_FILE_PREVIEW_SESSIONS_STATE , {
185180 type : 'upsert' ,
186181 session : createSession ( {
@@ -247,9 +242,6 @@ describe('reduceFilePreviewSessions', () => {
247242 } )
248243
249244 it ( 'holds the linger when an empty pending session arrives (no content yet)' , ( ) => {
250- // Between tool calls, a new empty/pending session may arrive before its
251- // first content chunk. The active session must not switch to it so the
252- // file viewer stays mounted and scroll position is preserved.
253245 const lingered = reduceFilePreviewSessions ( INITIAL_FILE_PREVIEW_SESSIONS_STATE , {
254246 type : 'upsert' ,
255247 session : createSession ( {
@@ -271,7 +263,6 @@ describe('reduceFilePreviewSessions', () => {
271263 } ) ,
272264 } )
273265
274- // New session arrives but with no renderable content (pending, empty).
275266 const afterEmptyUpsert = reduceFilePreviewSessions ( afterComplete , {
276267 type : 'upsert' ,
277268 session : createSession ( {
@@ -285,7 +276,6 @@ describe('reduceFilePreviewSessions', () => {
285276
286277 expect ( afterEmptyUpsert . activeSessionId ) . toBe ( 'preview-1' )
287278
288- // Once the first content chunk arrives, active switches.
289279 const afterContent = reduceFilePreviewSessions ( afterEmptyUpsert , {
290280 type : 'upsert' ,
291281 session : createSession ( {
@@ -467,6 +457,88 @@ describe('reduceFilePreviewSessions', () => {
467457 expect ( hydrated . sessions [ 'preview-2' ] ?. previewText ) . toBe ( 'new' )
468458 } )
469459
460+ it ( 'hydrate preserves linger when no non-complete session exists in incoming batch' , ( ) => {
461+ const lingered = reduceFilePreviewSessions (
462+ reduceFilePreviewSessions ( INITIAL_FILE_PREVIEW_SESSIONS_STATE , {
463+ type : 'upsert' ,
464+ session : createSession ( {
465+ id : 'preview-1' ,
466+ toolCallId : 'preview-1' ,
467+ previewVersion : 2 ,
468+ previewText : 'final' ,
469+ } ) ,
470+ } ) ,
471+ {
472+ type : 'complete' ,
473+ session : createSession ( {
474+ id : 'preview-1' ,
475+ toolCallId : 'preview-1' ,
476+ status : 'complete' ,
477+ previewVersion : 3 ,
478+ completedAt : '2026-04-10T00:00:02.000Z' ,
479+ previewText : 'final' ,
480+ } ) ,
481+ }
482+ )
483+
484+ // Hydrate with the same completed session — no non-complete successor.
485+ const afterHydrate = reduceFilePreviewSessions ( lingered , {
486+ type : 'hydrate' ,
487+ sessions : [
488+ createSession ( {
489+ id : 'preview-1' ,
490+ toolCallId : 'preview-1' ,
491+ status : 'complete' ,
492+ previewVersion : 3 ,
493+ previewText : 'final' ,
494+ completedAt : '2026-04-10T00:00:02.000Z' ,
495+ } ) ,
496+ ] ,
497+ } )
498+
499+ expect ( afterHydrate . activeSessionId ) . toBe ( 'preview-1' )
500+ } )
501+
502+ it ( 'hydrate releases linger when a non-complete session is present in the incoming batch' , ( ) => {
503+ const lingered = reduceFilePreviewSessions (
504+ reduceFilePreviewSessions ( INITIAL_FILE_PREVIEW_SESSIONS_STATE , {
505+ type : 'upsert' ,
506+ session : createSession ( {
507+ id : 'preview-1' ,
508+ toolCallId : 'preview-1' ,
509+ previewVersion : 2 ,
510+ previewText : 'final' ,
511+ } ) ,
512+ } ) ,
513+ {
514+ type : 'complete' ,
515+ session : createSession ( {
516+ id : 'preview-1' ,
517+ toolCallId : 'preview-1' ,
518+ status : 'complete' ,
519+ previewVersion : 3 ,
520+ completedAt : '2026-04-10T00:00:02.000Z' ,
521+ previewText : 'final' ,
522+ } ) ,
523+ }
524+ )
525+
526+ const afterHydrate = reduceFilePreviewSessions ( lingered , {
527+ type : 'hydrate' ,
528+ sessions : [
529+ createSession ( {
530+ id : 'preview-2' ,
531+ toolCallId : 'preview-2' ,
532+ status : 'streaming' ,
533+ previewVersion : 1 ,
534+ previewText : 'new content' ,
535+ } ) ,
536+ ] ,
537+ } )
538+
539+ expect ( afterHydrate . activeSessionId ) . toBe ( 'preview-2' )
540+ } )
541+
470542 it ( 'complete for a non-active session updates the session but keeps activeSessionId' , ( ) => {
471543 let state = reduceFilePreviewSessions ( INITIAL_FILE_PREVIEW_SESSIONS_STATE , {
472544 type : 'upsert' ,
0 commit comments