@@ -289,7 +289,7 @@ describe("session.compaction.prune", () => {
289289
290290 // Create large output to exceed PRUNE_PROTECT (40,000 tokens = 160,000 chars)
291291 const largeOutput = "x" . repeat ( 200_000 )
292- const toolPart = await Session . updatePart ( {
292+ await Session . updatePart ( {
293293 id : Identifier . ascending ( "part" ) ,
294294 messageID : assistantMsg1 . id ,
295295 sessionID : session . id ,
@@ -318,7 +318,7 @@ describe("session.compaction.prune", () => {
318318 } as MessageV2 . ToolPart )
319319
320320 // Create a second user message (turn 2)
321- const userMsg2 = await Session . updateMessage ( {
321+ await Session . updateMessage ( {
322322 id : Identifier . ascending ( "message" ) ,
323323 role : "user" ,
324324 sessionID : session . id ,
@@ -328,7 +328,7 @@ describe("session.compaction.prune", () => {
328328 } )
329329
330330 // Create a third user message (turn 3) to get past the turn protection
331- const userMsg3 = await Session . updateMessage ( {
331+ await Session . updateMessage ( {
332332 id : Identifier . ascending ( "message" ) ,
333333 role : "user" ,
334334 sessionID : session . id ,
@@ -377,8 +377,72 @@ describe("session.compaction.prune", () => {
377377 fn : async ( ) => {
378378 const session = await Session . create ( { } )
379379
380- // Create minimal messages to run prune
381- const userMsg = await Session . updateMessage ( {
380+ // Create user message
381+ const userMsg1 = await Session . updateMessage ( {
382+ id : Identifier . ascending ( "message" ) ,
383+ role : "user" ,
384+ sessionID : session . id ,
385+ time : { created : Date . now ( ) - 10000 } ,
386+ agent : "coder" ,
387+ model : { providerID : "test" , modelID : "test-model" } ,
388+ } )
389+
390+ // Create an assistant message with a tool part containing large output
391+ const assistantMsg = await Session . updateMessage ( {
392+ id : Identifier . ascending ( "message" ) ,
393+ role : "assistant" ,
394+ parentID : userMsg1 . id ,
395+ sessionID : session . id ,
396+ mode : "normal" ,
397+ agent : "coder" ,
398+ path : { cwd : tmp . path , root : tmp . path } ,
399+ cost : 0 ,
400+ tokens : { output : 0 , input : 0 , reasoning : 0 , cache : { read : 0 , write : 0 } } ,
401+ modelID : "test-model" ,
402+ providerID : "test" ,
403+ time : { created : Date . now ( ) - 9000 } ,
404+ } )
405+
406+ // Create large output
407+ const largeOutput = "x" . repeat ( 200_000 )
408+ await Session . updatePart ( {
409+ id : Identifier . ascending ( "part" ) ,
410+ messageID : assistantMsg . id ,
411+ sessionID : session . id ,
412+ type : "tool" ,
413+ callID : "call-1" ,
414+ tool : "read" ,
415+ state : {
416+ status : "completed" ,
417+ input : { path : "/test/file.ts" } ,
418+ output : largeOutput ,
419+ title : "Read file" ,
420+ metadata : { } ,
421+ time : { start : Date . now ( ) - 8000 , end : Date . now ( ) - 7000 } ,
422+ attachments : [
423+ {
424+ id : Identifier . ascending ( "part" ) ,
425+ messageID : assistantMsg . id ,
426+ sessionID : session . id ,
427+ type : "file" ,
428+ mime : "image/png" ,
429+ filename : "screenshot.png" ,
430+ url : "data:image/png;base64," + "A" . repeat ( 50000 ) ,
431+ } ,
432+ ] ,
433+ } ,
434+ } as MessageV2 . ToolPart )
435+
436+ // Create additional user messages to get past turn protection
437+ await Session . updateMessage ( {
438+ id : Identifier . ascending ( "message" ) ,
439+ role : "user" ,
440+ sessionID : session . id ,
441+ time : { created : Date . now ( ) - 5000 } ,
442+ agent : "coder" ,
443+ model : { providerID : "test" , modelID : "test-model" } ,
444+ } )
445+ await Session . updateMessage ( {
382446 id : Identifier . ascending ( "message" ) ,
383447 role : "user" ,
384448 sessionID : session . id ,
@@ -390,6 +454,16 @@ describe("session.compaction.prune", () => {
390454 // Run prune - should return early due to config
391455 await SessionCompaction . prune ( { sessionID : session . id } )
392456
457+ // Verify output and attachments remain unchanged (not compacted)
458+ const parts = await MessageV2 . parts ( assistantMsg . id )
459+ const toolPart = parts . find ( ( p ) => p . type === "tool" ) as MessageV2 . ToolPart
460+ expect ( toolPart . state . status ) . toBe ( "completed" )
461+ if ( toolPart . state . status === "completed" ) {
462+ expect ( toolPart . state . output . length ) . toBe ( 200_000 )
463+ expect ( toolPart . state . attachments ?. length ) . toBe ( 1 )
464+ expect ( toolPart . state . time . compacted ) . toBeUndefined ( )
465+ }
466+
393467 // Cleanup
394468 await Session . remove ( session . id )
395469 } ,
0 commit comments