Compaction uses the same DAG visibility, tool-result rendering and aging rules as model requests. Top-level conversation defines only the replaceable range; each range's budget includes actually visible subcalls. Always retain the latest complete user turn, and retain the latest two by default; the token budget may allow fewer than twenty top-level messages. Short history already below the retention budget does not invoke the summary model.
When keeping two turns leaves more than the requested token budget, select the next complete user-turn boundary and retain the latest turn. This avoids a large completed tool-heavy turn making compaction ineffective. Never split an active user turn or discard its tool evidence without including it in the summary. The completion event reports both token counts and whether a summary was actually applied.
Summary input starts at the first message of the selected range and includes original user requests, the prior summary and visible tool results. Summary input and covers_ids describe the same range; no removed prefix is omitted from model input. The previous summary comes only from records applicable to the current branch, not a session cache from another branch.
After generation, perform the same replacement and rendering in the in-memory graph and persist only if estimated tokens strictly decrease. Estimates include summary markers and tool results; compaction markers and the context panel use the same message rendering. Failure, cancellation, empty summary, no gain or content changes during generation neither commit a summary nor increment compaction count. Failures do not substitute a structural summary that discards content.
Storage retains one rolling summary and existing covers_ids without migrating or deleting history. Repeated compaction incorporates the currently applicable summary; existing DAG rendering rules preserve branch isolation, unchanged HEAD and tool-call/result pairing. Historical incorrect summaries are not automatically rewritten.
Reference sources remain those already compared on this page; this change adds no external implementation or changes to other multi-tier compaction policies.
These corrections are implemented. Regression tests cover complete summary input, retaining the latest two turns, rejecting no-gain summaries, cancellation/concurrent changes, repeated compaction and statistics consistency. Session-graph compaction scope uses the same message snapshot, avoiding inconsistent summary state if compaction repeats during loading.
Aligned with Claude Code, with two categories:
Routine operation(before every LLM call, regardless of context length): Budget Reduction
Cascading compaction(escalate through Tiers 1โ2โ3โ4โ5, cheapest first, advancing only if the previous tier is insufficient):
| Name | Action | Trigger | Calls LLM | Invalidates cache | Status | |
|---|---|---|---|---|---|---|
| Routine | Budget Reduction | Truncate oversized individual outputs | Individual tool_result > 4000 characters | No | No | โ |
| Tier 1 | Microcompact | Clean up old tool outputs | Tool calls โฅ 50 calls(then every 25 calls) / idle for 90 minutes | No | Cache-aware preserves cache | โ |
| Tier 2 | Snip | Remove the oldest turns | Still over budget after Tier 1 | No | Yes | โ |
| Tier 3 | Context Collapse | Segment summaries | Still over after Tier 2, ~90% | Yes (once per segment) | Yes | โณ |
| Tier 4 | Auto-Compact | Full summary | Still over after Tier 3 / user /compact | Yes (once) | Yes | โ |
| Tier 5 | Reactive | Emergency compaction | API returns 413 | Yes | Yes | โณ |
Cascade logic: before every LLM call, check from Tier 1. Execute when conditions match, then recheck the budget. Advance to the next tier if still over.
Note: reverse engineering describes Claude Code Tiers 3 and 4 as overlapping strategies, not necessarily a strict cascade./compact The manual command directly triggers Tier 4, skipping Tiers 1โ3.
Claude Code uses linear conversations without a DAG and does not need this layer. Our function-call nodes (๐ข) require additional handling.
render_context callers/subcalls/exposeMatches Claude Code: runs before every LLM call, regardless of context length.
context/tool_aging/truncate.py: middle_truncate, context/tool_aging/policy.py: MAX_TOOL_RESULT_CHARS = 4000After Budget Reduction, check tiers in order. Advance only if the preceding tier leaves context over threshold.
Matches Claude Code: clean up old ๐ก tool outputs.
cache_edits, beta header context-management-2025-06-27). Client messages stay unchanged,cache remains valid. Sentinel bytes are normalized for byte stability; repeated operations do not change cached content.context/microcompact.py, context/rules/microcompact.pyMatches Claude Code: directly remove the oldest turns without summaries or LLM calls.
context/snip.pyMatches Claude Code: segmented LLM summaries, retaining original messages for rollback.
Matches Claude Code: full LLM summary replacing all old messages, without rollback.
/compact (jump directly here)/compact or /compact retain the database-migration discussion. Manual use is recommended at 60% .context/engine.py: compact()Emergency compaction when the API returns 413 (prompt too long), at most once per turn. Stop if all attempts fail.
Before every LLM call:
1. Budget Reduction โ truncate oversized tool outputs (every turn)
2. Cascade checks (tier order):
Tier 1: Microcompact condition met? โ clean old tool outputs
Tier 2: Still over threshold? โ Snip older turns
Tier 3: Still over? โ Context Collapse segment summaries
Tier 4: Still over? โ Auto-Compact full summary
3. Call the LLM
4. If the API returns 413:
Tier 5: Reactive โ emergency compaction โ retry
โ stop on failure
Scenario: 200K context, several hours of work, with research_agent invoked midway.
๐ต user โ ๐ต assistant; Budget Reduction checks tool outputs and skips those within limits. No cascade tier triggers.
Tool calls exceed 50. Cache-aware Microcompact triggers for the first time, cleaning old outputs and freeing about 15K tokens. It repeats every 25 calls. Tiers 2โ5 do not trigger.
While the function runs, internal ๐ก tool calls expand. Budget Reduction truncates oversized outputs. On completion, expose=io hides the internal subtree and the node enters normal cascading.
Microcompact leaves context over budget. Snip removes the oldest five turns, including completed function nodes, bringing it below threshold. Tiers 3โ5 do not trigger.
After repeated Snip, little removable content remains. Context Collapse summarizes segments; if insufficient, Auto-Compact summarizes everything. This is rare.
Conversation continues normally after compaction. Repeat the cascade when over threshold again. The model can inspect old function internals by reading DAG children through tools.
| Ours | Claude Code | Description |
|---|---|---|
| ยง2 Function-node lifecycle | None | Our addition (DAG + expose=io) |
| ยง3 Budget Reduction | Budget Reduction | Matches (4000-character threshold, 60/40 truncation) |
| Tier 1 Microcompact | Tier 1 Microcompact | Matches; Anthropic uses the cache-aware path |
| Tier 2 Snip | Tier 2 Snip | Matches (remove whole turns) |
| Tier 3 Context Collapse | Tier 3 Context Collapse | Matches (segment summaries with rollback) |
| Tier 4 Auto-Compact / /compact | Tier 4 Auto-Compact / /compact | Matches (full summary) |
| Tier 5 Reactive | Tier 5 Reactive | Matches (413 emergency compaction) |
Source:Claude Code compaction reference(based on reverse engineering, not official documentation)
| Step | Action | Status | Code |
|---|---|---|---|
| 1 | Budget Reduction โ truncate oversized outputs (ยง3) | โ | context/tool_aging/truncate.py |
| 2 | Tier 1 Microcompact โ clean old tool outputs | โ | context/microcompact.py |
| 3 | Tier 2 Snip โ remove oldest turns | โ | context/snip.py |
| 4 | Tier 3 Context Collapse โ segmented LLM summaries | โณ | |
| 5 | Tier 4 Auto-Compact โ full LLM summary | โ | context/engine.py |
| 6 | Tier 5 Reactive โ 413 emergency compaction | โณ | |
| 7 | /compact command | โณ | |
| 8 | /context command (token distribution) | โ | cli/repl/handlers.py |
| 9 | Anthropic Context Editing API integration | โณ |
Chat and internal function execution share AgentLoop's pre-send processing: measure the request after message conversion, memory injection and actual-tool resolution. Compaction replaces only completed tool-group result text in the current request view, preserving call arguments, result IDs, error states, original user text and multimodal content. Original execution records are not rewritten.
Summaries use independently budgeted chunks with bounded calls and total duration; summary requests do not reenter AgentLoop. Cache belongs only to the current AgentContext and matches original result content and model configuration, never spanning function views. Older results are preferred and the latest tool group is retained; completed latest groups may also be processed when necessary. Recheck actual tools and system content on every send.
Without an explicit output cap, use the minimum of model capability, default output reserve and one quarter of the context window; measurement and provider requests use the same value. Never silently reduce explicit caps; reject sending if protected content plus that cap exceeds budget.
Scope: request compaction for tool accumulation within one turn. It does not replace existing cross-turn DAG summaries or promise lossless semantics or exact agreement between local estimates and provider counts. Do not send a known over-budget request when uncompressible protected content exceeds budget.
Implementation status: connected to the shared AgentLoop request entry and passed independent specification and quality reviews. Regression tests cover consecutive calls within a turn, internal function entry, original-text retention, summary budgets, cancellation and credential propagation. This processing creates no persistent DAG summary node.
This implementation plan extends request-local compaction without changing DAG storage. It is intended for maintainers reviewing model-request safety.
| Stage | Behavior | Boundary |
|---|---|---|
| Budget | Count system prompt, tools, response schema, output reserve and history before every model request. | Recalculate for fallback models. |
| Tool evidence | Summarize complete text-only tool results first. | Preserve call identifiers and error flags. |
| Checkpoint | When still over budget, replace an older complete text-only execution prefix with a task summary; retain every user message verbatim and the latest assistant segment. | Never split tool groups or discard multimodal or unresolved content. |
| Summary request | Process all source text in budgeted chunks with rolling summaries. Retry a provider overflow using a smaller chunk. | Bound calls and time; cancellation, errors and exhausted budgets preserve original history. |
| Continue | Reuse checkpoints only for an identical source prefix and model. Send only a verified smaller request. | Keep raw execution messages and DAG nodes unchanged. |
Reference: Codex local compaction retains user messages and replaces execution history. OpenProgram adapts this behavior to request views. It does not copy Rust source, truncate user instructions, adopt remote encrypted compaction, or replace the DAG. Summary text remains assistant data, never system instructions.
Review-passed; full-gate-failed. Focused tests and independent specification and quality reviews pass. Four unrelated repository checks also fail at the unchanged base. This feature is not marked complete; mainline integration and installed-App acceptance remain pending.