feat(coding-agent): implement new compaction system with overflow recovery

Phase 1: Updated compaction.ts
- findCutPoint now returns CutPointResult with isSplitTurn and turnStartIndex
- Can cut at user, assistant, or bashExecution messages (never tool results)
- Added turnPrefixSummary support for split turns (parallel summarization)
- estimateTokens helper for context size estimation

Phase 2: Updated session-manager.ts
- CompactionEntry now has optional turnPrefixSummary field
- loadSessionFromEntries injects both summaries when turn was split

Phase 3: Updated agent-session.ts
- Overflow detection via isContextOverflow after agent_end
- Proactive compaction check on turn_end before next LLM call
- _abortingForCompaction flag to skip saving aborted messages
- Auto-retry after overflow recovery or proactive compaction
- New event fields: reason (overflow/threshold), willRetry

Phase 4: Updated interactive-mode.ts
- Shows reason in compaction status (Context overflow detected...)
- Shows retry status after compaction

Tests updated for new CutPointResult return type.
This commit is contained in:
Mario Zechner 2025-12-09 17:18:53 +01:00
parent ee9acdb49d
commit a38e619095
5 changed files with 411 additions and 91 deletions

View file

@ -50,6 +50,8 @@ export interface CompactionEntry {
type: "compaction";
timestamp: string;
summary: string;
/** Summary of turn prefix when a turn was split (user message to first kept message) */
turnPrefixSummary?: string;
firstKeptEntryIndex: number; // Index into session entries where we start keeping
tokensBefore: number;
}
@ -178,9 +180,19 @@ export function loadSessionFromEntries(entries: SessionEntry[]): LoadedSession {
}
}
// Build final messages: summary + kept messages
const summaryMessage = createSummaryMessage(compactionEvent.summary);
const messages = [summaryMessage, ...keptMessages];
// Build final messages: summaries + kept messages
const messages: AppMessage[] = [];
// Add history summary
messages.push(createSummaryMessage(compactionEvent.summary));
// Add turn prefix summary if present (when a turn was split)
if (compactionEvent.turnPrefixSummary) {
messages.push(createSummaryMessage(compactionEvent.turnPrefixSummary));
}
// Add kept messages
messages.push(...keptMessages);
return { messages, thinkingLevel, model };
}