@@ -204,17 +204,12 @@ export type CompactorConfig = {
204204 // errors) before the summary stub. Pulled from the end of the older set
205205 // so the most-recent anchors survive.
206206 maxAnchorTurns : number ;
207- // When true, replace tool_result content in every kept turn with a
208- // one-line stub. Safe at compaction time because the cache is already
209- // cold from the compaction event itself.
210- stripResultContent : boolean ;
211207} ;
212208
213209const DEFAULT_COMPACTOR_CONFIG : CompactorConfig = {
214210 keepRecentTurns : 5 ,
215211 summaryMaxChars : 2000 ,
216212 maxAnchorTurns : 8 ,
217- stripResultContent : false ,
218213} ;
219214
220215// Recent turns kept verbatim by both real pruning-compactor registrations
@@ -233,33 +228,6 @@ export function compactorNoOpFloor(keepRecentTurns: number): number {
233228// Minimum anchor score for a turn to be pulled forward past the summary boundary.
234229const ANCHOR_SCORE_THRESHOLD = 5 ;
235230
236- // Tool name → path argument, used to build readable stubs.
237- type ToolCallInfo = {
238- name : string ;
239- pathArg ?: string ;
240- commandArg ?: string ;
241- } ;
242-
243- // Build a callId → tool info index from the full turn list so the strip
244- // function can produce named stubs without searching across turns.
245- function buildCallIndex ( turns : ConversationTurn [ ] ) : Map < string , ToolCallInfo > {
246- const index = new Map < string , ToolCallInfo > ( ) ;
247- for ( const turn of turns ) {
248- for ( const block of turn . content ) {
249- if ( block . type !== "tool_call" ) continue ;
250- const info : ToolCallInfo = { name : block . name } ;
251- const args = block . arguments ;
252- if ( typeof args === "object" && args !== null ) {
253- const a = args as Record < string , unknown > ;
254- if ( typeof a [ "path" ] === "string" ) info . pathArg = a [ "path" ] ;
255- if ( typeof a [ "command" ] === "string" ) info . commandArg = a [ "command" ] ;
256- }
257- index . set ( block . id , info ) ;
258- }
259- }
260- return index ;
261- }
262-
263231// Locate the turn index of each tool_call and its matching tool_result. In this
264232// runtime a call lives on one turn and its result on the following turn, so the
265233// two halves of a pair can straddle a keep/summarize boundary.
@@ -309,39 +277,6 @@ function resultContentSize(block: Extract<ConversationTurn["content"][number], {
309277 return block . content . reduce ( ( sum , c ) => sum + ( c . type === "text" ? c . text . length : 0 ) , 0 ) ;
310278}
311279
312- function buildResultStub (
313- block : Extract < ConversationTurn [ "content" ] [ number ] , { type : "tool_result" } > ,
314- callIndex : Map < string , ToolCallInfo > ,
315- ) : string {
316- const info = callIndex . get ( block . callId ) ;
317- const name = info ?. name ?? "tool_result" ;
318- const size = resultContentSize ( block ) ;
319- if ( info ?. pathArg !== undefined ) {
320- const path = info . pathArg ;
321- const spillHint =
322- path . startsWith ( "tool-output://" ) ? " Re-read with read_file offset/limit or grep on that URI." : "" ;
323- return `[${ name } ${ path } — ${ size } chars omitted from context; source unchanged.${ spillHint } ]` ;
324- }
325- if ( info ?. commandArg !== undefined ) {
326- const cmd = info . commandArg . slice ( 0 , 40 ) ;
327- return `[${ name } "${ cmd } " — ${ size } chars, omitted]` ;
328- }
329- return `[${ name } — ${ size } chars, omitted]` ;
330- }
331-
332- // Replace tool_result content with a one-line stub. Errors are kept in full
333- // because they may describe constraints the model still needs to respect.
334- function stripTurnResults (
335- turn : ConversationTurn ,
336- callIndex : Map < string , ToolCallInfo > ,
337- ) : ConversationTurn {
338- const content = turn . content . map ( ( block ) : ConversationTurn [ "content" ] [ number ] => {
339- if ( block . type !== "tool_result" || block . isError === true ) return block ;
340- return { ...block , content : [ { type : "text" , text : buildResultStub ( block , callIndex ) } ] } ;
341- } ) ;
342- return { ...turn , content } ;
343- }
344-
345280// True when a turn carries no tool_call/tool_result blocks.
346281function isPlainTextTurn ( turn : ConversationTurn ) : boolean {
347282 return ! turn . content . some ( ( b ) => b . type === "tool_call" || b . type === "tool_result" ) ;
@@ -429,7 +364,7 @@ export function createPruningCompactor(
429364
430365 return {
431366 name : "pruning-compactor" ,
432- version : "1.1 .0" ,
367+ version : "1.2 .0" ,
433368 async apply (
434369 turns : ConversationTurn [ ] ,
435370 _ctx : StrategyContext ,
@@ -455,8 +390,6 @@ export function createPruningCompactor(
455390 } ;
456391 }
457392
458- const callIndex = buildCallIndex ( aged . turns ) ;
459-
460393 const keepCount = Math . min ( cfg . keepRecentTurns , aged . turns . length - 1 ) ;
461394 const keepFrom = aged . turns . length - keepCount ;
462395 const recentTurns = aged . turns . slice ( keepFrom ) ;
@@ -513,15 +446,17 @@ export function createPruningCompactor(
513446 timestamp : olderTurns [ olderTurns . length - 1 ] ?. timestamp ?? Date . now ( ) ,
514447 } ;
515448
516- const process = ( t : ConversationTurn ) : ConversationTurn =>
517- cfg . stripResultContent ? stripTurnResults ( t , callIndex ) : t ;
518-
519- // Anchors are already image-aged (outside the recent window). Recent
520- // turns keep live base64 so a just-pasted screenshot still reaches the model.
449+ // Anchors and recent turns are exactly what compaction chose to keep —
450+ // pulling a turn forward and then hollowing out its tool_result defeats
451+ // the reason it was kept. Only summarizedTurns lose their content, and
452+ // they lose it wholesale (folded into `summary` above), not stubbed
453+ // in place. Anchors are already image-aged (outside the recent window).
454+ // Recent turns keep live base64 so a just-pasted screenshot still
455+ // reaches the model.
521456 const output = coalesceAdjacentTextTurns ( [
522457 summaryTurn ,
523- ...anchorTurns . map ( process ) ,
524- ...recentTurns . map ( process ) ,
458+ ...anchorTurns ,
459+ ...recentTurns ,
525460 ] ) ;
526461
527462 return {
@@ -533,7 +468,6 @@ export function createPruningCompactor(
533468 keepRecentTurns : cfg . keepRecentTurns ,
534469 summaryMaxChars : cfg . summaryMaxChars ,
535470 maxAnchorTurns : cfg . maxAnchorTurns ,
536- stripResultContent : cfg . stripResultContent ,
537471 } ,
538472 reason : `compacted ${ summarizedTurns . length } turns, anchored ${ anchorTurns . length } , keeping ${ keepCount } recent` ,
539473 decisions : {
0 commit comments