Conversation Compaction: Keeping Long Sessions Alive
How long agent sessions compact context using preemptive triggers, cache-aware deletion, rollback, and journals.
A large tool result can push an agent beyond its context limit before a reactive compactor runs. If the summarizer has a smaller window, it may reject the same buffer and leave the session unable to continue. A reliable harness compacts with headroom, commits changes atomically, and keeps a degraded truncation path for summarizer failure.
When compaction runs
Conversation compaction is the harness operation that, when triggered, reduces the size of the live conversation buffer in place so that the next model call fits. Three properties distinguish conversation compaction in a long session from the broader compression operation. It is in-place mutation of the live buffer, not an offline pass; the next call must succeed against the new buffer. It is non-optional once triggered: there is no path forward if it fails. And it is cache-disruptive by default: any rewrite invalidates the prompt-cache prefix from the rewrite boundary onward, so a naive implementation pays full prefill on every subsequent call. The orchestration question is how to fire it as rarely and cheaply as possible, and how to keep the session alive when it fails.
Reactive vs preemptive triggers
Two philosophies, and most production harnesses end up running both.
Reactive compaction fires after the buffer crosses a watermark. Anthropic’s compaction beta is the cleanest example; the server detects when input tokens exceed the configured trigger (default 150,000), runs compaction inline, emits a compaction block, and continues. OpenAI’s server-side compaction via the Responses API (shipped February 11, 2026) is conceptually identical: pass context_management.compact_threshold and the server fires compaction when the rendered token count crosses it. Claude Code’s auto-compact at ~95% is the client-side version. The pros are operational simplicity: a single number, a single conditional. The cons: the user-facing turn that crosses the watermark pays 1-5s of compaction latency, and there’s no head-room; if the model emits a 50K-token tool result at 90K of a 100K budget, the compaction must succeed on the first try because there’s no room for retry tokens.
Preemptive compaction fires before the buffer is dangerous, by projecting whether the next turn will breach the budget after the model’s reply. The estimate is the current buffer size plus a conservative max_tokens bound on output plus the expected tool-result size from the most recent tool_use block. The pros: the user-facing turn never gets surprise latency, and there is always head-room for the model to reply. The cons: some compactions are wasted (the prediction was conservative), and the trigger requires a reasonably accurate token estimator plus policy about max output size, which often lives outside the core compaction module.
The defensible production pattern is preemptive as primary, reactive as fallback. Run preemptive at ~70% of effective context; keep reactive as a backstop at ~95% for cases where the estimator misses a heavy-tailed tool result. This mirrors generational garbage collection: frequent cheap cleanup with a less frequent full fallback.
Cache-aware compaction: surgical deletion
Compaction should preserve stable cached prefixes. Rewriting the whole history invalidates prompt-cache reuse after the first changed token. Prefer removing superseded tool results or replacing an old range with an immutable summary block.
Three patterns ship in production:
Surgical tool-result deletion, system prompt and assistant turns preserved. The cheapest operation: identify tool-call/tool-result pairs where the result has since been superseded (e.g., five Read calls on the same file; keep the latest, replace the earlier ones with [result superseded; see turn N]). The system prompt, assistant reasoning, and the recent tail are unchanged; the cacheable prefix grows monotonically. This is what Anthropic’s clear_tool_uses_20250919 does at the API level and what Claude Code’s micro-compact does client-side. Compression ratio is modest (10-30%), but the cache hit rate stays high, and the operation can run frequently.
Append-only summary block, untouched tail. When micro-compaction isn’t enough: write a new “session summary” block at a stable position (right after the system prompt), and drop the messages it summarizes. The summary, once written, is treated as immutable for the next K turns; it doesn’t get re-summarized on every turn; the cache treats it as a stable prefix. The conversation tail after the summary keeps growing and benefits from incremental caching. The Anthropic beta’s pause_after_compaction option exists for this pattern: pause after the summary is generated, let the client preserve any instruction-oriented messages, then continue. Compression ratio is high (80-95%); cache invalidation cost is paid once per K turns rather than every turn.
Anti-pattern: summary-as-system-prompt mutation. Some harnesses fold the running summary into the system prompt, mutating it every cycle. This is the worst thing you can do for the cache; the system prompt is the most-cached prefix, and rewriting it every turn recomputes the entire prefix on every turn. The cost graph reads “we turned on caching” but the bill stays flat. The harness anatomy article flagged this; it bears repeating because every team seems to invent it independently.
Rule of thumb: compress as far from the cache-hit prefix as possible; rewrite as little of the prefix as possible; treat the summary block as an immutable record between compactions, not a running state.
Error recovery: circuit breakers and snapshot-rollback
Compaction can fail because the summarizer is unavailable, its output violates the schema, required fields are empty, its own context limit is exceeded, or the compacted buffer remains too large. Each case needs a typed recovery path.
Take a snapshot before mutating the live buffer. Run the summarizer against that snapshot, validate the schema and required fields, then swap the compacted buffer atomically. On failure, retain the original. Long-horizon checkpointing applies the same commit discipline at a larger scope.
Circuit breaker around compaction failures. Maintain a per-session counter of consecutive failures. Trip at N=3 (a defensible default; lower if throughput-bounded, higher if the summarizer is flaky). When tripped, do not retry compaction; fall back to a degraded strategy and emit a structured failure. The breaker’s purpose is to break the infinite-failure loop: a session that fails once is recoverable; a session that fails repeatedly while burning the full timeout window each time is a service outage. After M turns of cool-down, reset.
Lossy truncation as the last-resort fallback. When the breaker is tripped or the summarizer is unreachable, fall back to unconditional head-tail truncation: keep the system prompt, keep the most recent K turns, drop everything in the middle. This is the default eviction policy from short-term memory, used here as the fallback when the smarter policy fails. The agent loses semantic context but the session stays alive; and a degraded session is recoverable; a crashed one is not. The fallback should be loud: log the event, expose a UI indicator, mark the failure for downstream review.
The wedged-buffer escape hatch. For the case where the summarizer itself can’t fit the buffer in its context: either keep a secondary summarizer with a larger context window, or run a chunked-and-merge pass that splits the buffer in half, summarizes each half independently, then summarizes the summaries. The chunked-and-merge pattern is the same shape as map-reduce summarization and is the right recovery primitive when the foreground model’s context exceeds the summarizer’s.
Append-only memory journals: the architectural alternative
A radically different design ports the database log-vs-LSM-tree decision: instead of compacting the live buffer, run the live buffer at near-zero retention and write everything important to an external append-only memory journal, queried at retrieval time rather than loaded wholesale.
Mechanically: every turn, before the model call, the harness extracts decisions, files, errors, or load-bearing facts and appends them to a per-session journal (JSONL file, Postgres table, vector store; substrate-agnostic). The live buffer stays short; last 10-20 turns; by aggressive truncation. When the model needs earlier context, it queries the journal via a recall tool the harness exposes. The journal grows linearly; the live buffer is bounded by design.
The journal model replaces the orchestration-failure surface with a retrieval-quality surface: no compaction to fail, but a recall query whose quality determines whether the agent finds the relevant fact. It makes the trade-off explicit: the operator can inspect, query, and audit the journal; versus a summary block whose contents are at the summarizer’s discretion. And it plays well with sleep-time compute: the journal is exactly the artifact an offline consolidation pass needs.
The pattern shows up under several names in 2026 production systems. Doug Turnbull’s “give your coding agent a journal” is the cleanest articulation; an agent maintains a journal file in the working directory, one entry per significant action, queried when it needs to remember. OpenCode’s append-only journal blocks productize the idea with semantic search. LangGraph’s checkpoint-and-store split implements the architectural distinction at the framework level. The unifying claim: aggressive truncation plus a queryable external journal beats summarization-in-place for any task where audit and reproducibility matter more than the gist surviving in prose.
The journal wins for coding agents (audit trail needs to survive verbatim), compliance workflows (regulators want exact actions, not paraphrases), long-horizon research (the journal is the research log), and multi-session agents (journals are naturally cross-session). Compaction still wins for open-ended conversational agents where the gist is what matters, latency-sensitive interactive agents where the journal round-trip dominates, and single-session ephemeral workflows. The patterns are complementary; the production answer for most agents is both; a journal for durable state, compaction for the live buffer’s working set.
A preemptive, cache-aware compactor in Python
Realizes the full orchestration shape: preemptive triggering, snapshot-and-rollback, circuit-breaker recovery, cache-aware mutation. Uses the Anthropic SDK.
| |
The interesting parts aren’t the summarizer call; that’s the context-compression article’s domain; but the orchestration. The snapshot-and-rollback cannot leave the buffer half-rewritten. The breaker prevents the infinite-failure loop. The lossy-truncation fallback keeps the session moving. The chunked-and-merge escape hatch handles the wedged case. The preemptive trigger gates on projected, not on current buffer size, so head-room is reserved before the call.
Further reading
- Anthropic; Compaction documentation; the reference for the
compact_20260112server-managed strategy. Thepause_after_compactionoption and the custom-instructions surface are the production levers worth knowing before you build a client-side compactor. - OpenAI; Compaction guide for the Responses API; the parallel server-side primitive (
context_management.compact_threshold), shipped February 11, 2026. The shape is conceptually identical to Anthropic’s beta; the trigger semantics differ slightly (token-count threshold vs. trigger-with-strategy). - Doug Turnbull; “Give your coding agent a journal”; the cleanest articulation of the append-only-journal alternative. The “journal-file-in-the-working-directory” pattern is the operational shape every coding-agent team eventually converges on, and the post explains why.
- Morph LLM; “Claude Code auto-compact: what triggers it, what it loses, how to fix it”; the production-incident perspective on auto-compaction. The empirical observations on micro-compact vs full-compact thresholds and the cataloged loss modes are the closest thing to a public post-mortem on a widely-deployed compactor.
- Phil Schmid; “The importance of Agent Harness in 2026”; the broader framing of the harness as the new competitive surface. The “build-to-delete” argument and the trajectory-data point are load-bearing background for any team deciding whether to invest in a custom compactor.