@@ -33,6 +33,7 @@ const {
3333 ExecutionState,
3434} = require ( './agenticChatHelpers' ) ;
3535const { LLMEngine } = require ( './llmEngine' ) ;
36+ const { RollingSummary } = require ( './rollingSummary' ) ;
3637const { repairToolCalls : repairToolCallsFn } = require ( './tools/toolParser' ) ;
3738
3839/**
@@ -637,7 +638,7 @@ function register(ctx) {
637638
638639 const hwContextSize = modelStatus . modelInfo ?. contextSize || 32768 ;
639640
640- const estimateTokens = ( text ) => Math . ceil ( ( text || '' ) . length / 3.5 ) ;
641+ const estimateTokens = ( text ) => Math . ceil ( ( text || '' ) . length / 4 ) ;
641642
642643 // ModelProfile-driven budgeting
643644 const modelTier = llmEngine . getModelTier ( ) ;
@@ -859,6 +860,9 @@ function register(ctx) {
859860 const summarizer = new ConversationSummarizer ( ) ;
860861 summarizer . setGoal ( message ) ;
861862
863+ const rollingSummary = new RollingSummary ( ) ;
864+ rollingSummary . setGoal ( message ) ;
865+
862866 // Auto-create todos for large/incremental tasks (helps model track progress across rotations)
863867 const autoTodoResult = autoCreateLargeTaskTodos ( message , mcpToolServer ) ;
864868 if ( autoTodoResult ?. success ) {
@@ -1704,16 +1708,18 @@ function register(ctx) {
17041708 if ( isStale ( ) ) break ;
17051709
17061710 // Record plan
1707- if ( responseText . length > 50 ) summarizer . recordPlan ( responseText ) ;
1711+ if ( responseText . length > 50 ) {
1712+ summarizer . recordPlan ( responseText ) ;
1713+ rollingSummary . recordPlanFromResponse ( responseText ) ;
1714+ }
17081715
17091716 // ── Progressive Context Compaction ──
17101717 try {
17111718 let contextUsed = 0 ;
17121719 try { if ( llmEngine . sequence ?. nextTokenIndex ) contextUsed = llmEngine . sequence . nextTokenIndex ; } catch ( _ ) { }
17131720 if ( ! contextUsed ) {
17141721 const pLen = typeof currentPrompt === 'string' ? currentPrompt . length : ( ( currentPrompt . systemContext || '' ) . length + ( currentPrompt . userMessage || '' ) . length ) ;
1715- // Use /3.5 instead of /4 for more conservative token estimation
1716- contextUsed = Math . ceil ( ( pLen + fullResponseText . length ) / 3.5 ) ;
1722+ contextUsed = Math . ceil ( ( pLen + fullResponseText . length ) / 4 ) ;
17171723 }
17181724 const compaction = progressiveContextCompaction ( {
17191725 contextUsedTokens : contextUsed , totalContextTokens : totalCtx ,
@@ -1896,6 +1902,7 @@ function register(ctx) {
18961902 summarizer . recordToolCall ( tr . tool , tr . params , tr . result ) ;
18971903 summarizer . markPlanStepCompleted ( tr . tool , tr . params ) ;
18981904 executionState . update ( tr . tool , tr . params , tr . result , iteration ) ;
1905+ rollingSummary . recordToolCall ( tr . tool , tr . params , tr . result , iteration ) ;
18991906 }
19001907
19011908 // UI events — send only non-deferred results to prevent duplicate bubbles
@@ -1953,6 +1960,21 @@ function register(ctx) {
19531960 const iterContext = executionBlock + stepDirective + taskReminder ;
19541961 const allFeedback = toolFeedback + snapFeedback ;
19551962
1963+ // ── Rolling Summary Injection ──
1964+ // Generate context-proportional summary for the next prompt.
1965+ // This ensures the model always has task awareness, not just post-rotation.
1966+ let rollingSummaryBlock = '' ;
1967+ {
1968+ let _rsCtxUsed = 0 ;
1969+ try { if ( llmEngine . sequence ?. nextTokenIndex ) _rsCtxUsed = llmEngine . sequence . nextTokenIndex ; } catch ( _ ) { }
1970+ if ( ! _rsCtxUsed ) _rsCtxUsed = Math . ceil ( ( fullResponseText . length + ( iterContext + allFeedback ) . length ) / 4 ) ;
1971+ const _rsCtxPct = _rsCtxUsed / totalCtx ;
1972+ if ( rollingSummary . shouldInjectSummary ( iteration , _rsCtxPct ) ) {
1973+ const summaryBudget = rollingSummary . getSummaryBudget ( totalCtx , _rsCtxPct ) ;
1974+ rollingSummaryBlock = rollingSummary . generateSummary ( summaryBudget ) ;
1975+ }
1976+ }
1977+
19561978 if ( sessionJustRotated ) {
19571979 sessionJustRotated = false ;
19581980 currentPrompt = {
@@ -1962,7 +1984,7 @@ function register(ctx) {
19621984 } else {
19631985 currentPrompt = {
19641986 systemContext : buildStaticPrompt ( ) ,
1965- userMessage : iterContext + buildDynamicContext ( ) + '\n' + allFeedback + continueInstruction ,
1987+ userMessage : iterContext + buildDynamicContext ( ) + ( rollingSummaryBlock ? '\n' + rollingSummaryBlock : '' ) + '\n' + allFeedback + continueInstruction ,
19661988 } ;
19671989 }
19681990 }
0 commit comments