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

@ -560,25 +560,27 @@ export class InteractiveMode {
this.ui.requestRender();
break;
case "auto_compaction_start":
case "auto_compaction_start": {
// Set up escape to abort auto-compaction
this.autoCompactionEscapeHandler = this.editor.onEscape;
this.editor.onEscape = () => {
this.session.abortCompaction();
};
// Show compacting indicator
// Show compacting indicator with reason
this.statusContainer.clear();
const reasonText = event.reason === "overflow" ? "Context overflow detected, " : "";
this.autoCompactionLoader = new Loader(
this.ui,
(spinner) => theme.fg("accent", spinner),
(text) => theme.fg("muted", text),
"Auto-compacting... (esc to cancel)",
`${reasonText}Auto-compacting... (esc to cancel)`,
);
this.statusContainer.addChild(this.autoCompactionLoader);
this.ui.requestRender();
break;
}
case "auto_compaction_end":
case "auto_compaction_end": {
// Restore escape handler
if (this.autoCompactionEscapeHandler) {
this.editor.onEscape = this.autoCompactionEscapeHandler;
@ -602,9 +604,14 @@ export class InteractiveMode {
compactionComponent.setExpanded(this.toolOutputExpanded);
this.chatContainer.addChild(compactionComponent);
this.footer.updateState(this.session.state);
if (event.willRetry) {
this.showStatus("Compacted context, retrying...");
}
}
this.ui.requestRender();
break;
}
}
}