@@ -409,6 +409,73 @@ describe("repairSessionFileIfNeeded", () => {
409409 expect ( result . trimmedTrailingAssistantMessages ?? 0 ) . toBe ( 0 ) ;
410410 } ) ;
411411
412+ it ( "preserves trailing assistant messages that contain tool calls" , async ( ) => {
413+ const { file } = await createTempSessionPath ( ) ;
414+ const { header, message } = buildSessionHeaderAndMessage ( ) ;
415+ const toolCallAssistant = {
416+ type : "message" ,
417+ id : "msg-asst-tc" ,
418+ parentId : null ,
419+ timestamp : new Date ( ) . toISOString ( ) ,
420+ message : {
421+ role : "assistant" ,
422+ content : [
423+ { type : "text" , text : "Let me check that." } ,
424+ { type : "toolCall" , id : "call_1" , name : "read" , input : { path : "/tmp/test" } } ,
425+ ] ,
426+ stopReason : "toolUse" ,
427+ } ,
428+ } ;
429+ const original = `${ JSON . stringify ( header ) } \n${ JSON . stringify ( message ) } \n${ JSON . stringify ( toolCallAssistant ) } \n` ;
430+ await fs . writeFile ( file , original , "utf-8" ) ;
431+
432+ const result = await repairSessionFileIfNeeded ( { sessionFile : file } ) ;
433+
434+ expect ( result . repaired ) . toBe ( false ) ;
435+ expect ( result . trimmedTrailingAssistantMessages ?? 0 ) . toBe ( 0 ) ;
436+ const after = await fs . readFile ( file , "utf-8" ) ;
437+ expect ( after ) . toBe ( original ) ;
438+ } ) ;
439+
440+ it ( "trims non-tool-call assistant but stops at tool-call assistant" , async ( ) => {
441+ const { file } = await createTempSessionPath ( ) ;
442+ const { header, message } = buildSessionHeaderAndMessage ( ) ;
443+ const toolCallAssistant = {
444+ type : "message" ,
445+ id : "msg-asst-tc" ,
446+ parentId : null ,
447+ timestamp : new Date ( ) . toISOString ( ) ,
448+ message : {
449+ role : "assistant" ,
450+ content : [ { type : "toolUse" , id : "call_1" , name : "read" } ] ,
451+ stopReason : "toolUse" ,
452+ } ,
453+ } ;
454+ const plainAssistant = {
455+ type : "message" ,
456+ id : "msg-asst-plain" ,
457+ parentId : null ,
458+ timestamp : new Date ( ) . toISOString ( ) ,
459+ message : {
460+ role : "assistant" ,
461+ content : [ { type : "text" , text : "stale" } ] ,
462+ stopReason : "stop" ,
463+ } ,
464+ } ;
465+ const original = `${ JSON . stringify ( header ) } \n${ JSON . stringify ( message ) } \n${ JSON . stringify ( toolCallAssistant ) } \n${ JSON . stringify ( plainAssistant ) } \n` ;
466+ await fs . writeFile ( file , original , "utf-8" ) ;
467+
468+ const result = await repairSessionFileIfNeeded ( { sessionFile : file } ) ;
469+
470+ expect ( result . repaired ) . toBe ( true ) ;
471+ expect ( result . trimmedTrailingAssistantMessages ) . toBe ( 1 ) ;
472+
473+ const repaired = await fs . readFile ( file , "utf-8" ) ;
474+ const repairedLines = repaired . trim ( ) . split ( "\n" ) ;
475+ expect ( repairedLines ) . toHaveLength ( 3 ) ;
476+ expect ( JSON . parse ( repairedLines [ 2 ] ) . id ) . toBe ( "msg-asst-tc" ) ;
477+ } ) ;
478+
412479 it ( "never trims below the session header" , async ( ) => {
413480 const { file } = await createTempSessionPath ( ) ;
414481 const { header } = buildSessionHeaderAndMessage ( ) ;
0 commit comments