@@ -2611,6 +2611,95 @@ describe("compaction-safeguard double-compaction guard", () => {
26112611 expect ( JSON . stringify ( messages ) ) . not . toContain ( "sessions_send" ) ;
26122612 } ) ;
26132613
2614+ it ( "preserves assistant text while filtering sessions_send tool calls as fallback history" , async ( ) => {
2615+ mockSummarizeInStages . mockReset ( ) ;
2616+ mockSummarizeInStages . mockResolvedValue ( "mixed branch summary" ) ;
2617+
2618+ const now = Date . now ( ) ;
2619+ const sessionManager = {
2620+ ...stubSessionManager ( ) ,
2621+ getBranch : ( ) => [
2622+ {
2623+ type : "message" ,
2624+ id : "user-1" ,
2625+ parentId : null ,
2626+ timestamp : new Date ( now ) . toISOString ( ) ,
2627+ message : {
2628+ role : "user" ,
2629+ content : "ask the bee session to respond" ,
2630+ timestamp : now ,
2631+ } ,
2632+ } ,
2633+ {
2634+ type : "message" ,
2635+ id : "assistant-1" ,
2636+ parentId : "user-1" ,
2637+ timestamp : new Date ( now + 1 ) . toISOString ( ) ,
2638+ message : {
2639+ role : "assistant" ,
2640+ content : [
2641+ { type : "text" , text : "I will ask the bee session and keep context." } ,
2642+ {
2643+ type : "toolCall" ,
2644+ id : "call-1" ,
2645+ name : "sessions_send" ,
2646+ arguments : { sessionKey : "agent:bee" , message : "say bee" } ,
2647+ } ,
2648+ ] ,
2649+ timestamp : now + 1 ,
2650+ } ,
2651+ } ,
2652+ {
2653+ type : "message" ,
2654+ id : "tool-1" ,
2655+ parentId : "assistant-1" ,
2656+ timestamp : new Date ( now + 2 ) . toISOString ( ) ,
2657+ message : {
2658+ role : "toolResult" ,
2659+ toolCallId : "call-1" ,
2660+ toolName : "sessions_send" ,
2661+ content : [ { type : "text" , text : "delivered" } ] ,
2662+ timestamp : now + 2 ,
2663+ } ,
2664+ } ,
2665+ ] ,
2666+ } as ExtensionContext [ "sessionManager" ] ;
2667+ const model = createAnthropicModelFixture ( ) ;
2668+ setCompactionSafeguardRuntime ( sessionManager , { model, recentTurnsPreserve : 0 } ) ;
2669+
2670+ const mockEvent = {
2671+ preparation : {
2672+ messagesToSummarize : [ ] as AgentMessage [ ] ,
2673+ turnPrefixMessages : [ ] as AgentMessage [ ] ,
2674+ firstKeptEntryId : "entry-9" ,
2675+ tokensBefore : 38085 ,
2676+ fileOps : { read : [ ] , edited : [ ] , written : [ ] } ,
2677+ settings : { reserveTokens : 4000 } ,
2678+ isSplitTurn : true ,
2679+ } ,
2680+ customInstructions : "" ,
2681+ signal : new AbortController ( ) . signal ,
2682+ } ;
2683+ const { result } = await runCompactionScenario ( {
2684+ sessionManager,
2685+ event : mockEvent ,
2686+ apiKey : "test-key" ,
2687+ } ) ;
2688+
2689+ const compaction = expectCompactionResult ( result ) ;
2690+ expect ( compaction . summary ) . toContain ( "mixed branch summary" ) ;
2691+ expect ( mockSummarizeInStages ) . toHaveBeenCalledTimes ( 1 ) ;
2692+ const summarizeCall = requireRecord ( mockCallArg ( mockSummarizeInStages ) ) ;
2693+ const messages = requireArray ( summarizeCall . messages ) ;
2694+ expect ( messages . map ( ( message ) => requireRecord ( message ) . role ) ) . toEqual ( [ "user" , "assistant" ] ) ;
2695+ const assistantMessage = requireRecord ( messages [ 1 ] ) ;
2696+ expect ( assistantMessage . content ) . toEqual ( [
2697+ { type : "text" , text : "I will ask the bee session and keep context." } ,
2698+ ] ) ;
2699+ expect ( JSON . stringify ( messages ) ) . not . toContain ( "sessions_send" ) ;
2700+ expect ( JSON . stringify ( messages ) ) . not . toContain ( "delivered" ) ;
2701+ } ) ;
2702+
26142703 it ( "recovers user and assistant branch turns when compaction preparation has only tool output" , async ( ) => {
26152704 mockSummarizeInStages . mockReset ( ) ;
26162705 mockSummarizeInStages . mockResolvedValue ( "branch summary with visible turns" ) ;
0 commit comments