Here is a bug report I have now heard three separate versions of:
“The agent works fine for about twenty minutes. Then it starts redoing things it already did.”
Every time, the team’s first instinct is that the model got confused, or the prompt needs work, or the task was too hard. Every time, the actual answer is that the run crossed a compaction boundary and nobody was looking.
Compaction is the most consequential thing happening in your agent runtime that you almost certainly have no telemetry for.
The thing that happens quietly
When a long-running agent’s conversation approaches the context window, something has to give. The standard answer is to summarize the earlier history into a compact form and drop the raw turns. Anthropic’s server-side compaction triggers by default around 150K tokens and returns a compaction block that replaces the compacted history on subsequent requests. Most frameworks do their own version. Most do it automatically, and most do it silently.
From the outside it looks like an optimization. A memory-management detail. The kind of thing you would be pleased the platform handles for you.
It is not an optimization. It is a state transition in the middle of a running job, and it is the only state transition in your agent runtime that fires without anyone deciding it should.
What the research found
There is now a decent empirical answer to what compaction costs you.
An August 2026 study of long-horizon agents — Min, Wu, Darbari, Chen, and Hong, submitted August 6 — looked specifically at recurrent context compression and execution instability. Their finding, tested on AppWorld:
Compression diminishes the influence of recent interactions, and the observable consequences are:
- Blocked actions — the agent attempts something that cannot proceed given state it no longer remembers
- Repeated exploration — it re-investigates ground it already covered
- Multi-run inconsistency — the same task, run repeatedly, produces meaningfully different outcomes
They trace this to execution-state mislocalization. The agent does not lose the facts. It loses its place.
That distinction is the whole article, so let me sit on it.
Narrative survives. Bookkeeping does not.
Ask a summarizer to compress twelve turns of an agent transcript, and it will do what summarizers are trained to do: preserve the narrative. What was the goal, what was learned, what is the situation.
What it will not reliably preserve:
- I have already edited
handlers.pyandconfig.yaml, and not the other four files - The
/v2/accountsendpoint returned 403 twice — that is a permissions problem, not a transient one, do not retry it - I tried the batch approach and ruled it out because of the rate limit
- Step 4 of 9 is done; step 5 is in progress and half-applied
None of that is narratively interesting. All of it is what the next action depends on.
This is why the failure looks like amnesia about actions rather than amnesia about facts. Ask the post-compaction agent what it is working on and it will tell you correctly. Ask it to take the next step and it may take a step it already took.
The related finding worth pairing this with is Chroma’s Context Rot work, which showed model performance degrading as input token count grows, across models, even on deliberately controlled tasks. Put the two together and you get an uncomfortable shape: performance degrades as you approach the window, and then degrades differently when you compact to escape it. There is no comfortable region — only a set of tradeoffs you should be choosing deliberately rather than inheriting.
I argued in context engineering: the window is a budget that you should treat the window as a resource you allocate rather than a bucket you fill. This is the operational sequel: the moment your allocation runs out is an event, and events get instrumented.
Instrument it like the state transition it is
Here is the concrete ask. Three things.
1. Emit a span for every compaction.
Not a log line. A span, on the same trace as the run, following the OTel GenAI conventions you are hopefully already using for the agent loop. Attributes worth carrying:
| Attribute | Why |
|---|---|
pre_compaction_tokens | How much was squeezed |
run_id | Correlate to the parent run |
step_index | Where in the plan it happened |
compaction_count | Which compaction this is for this run |
tool_calls_dropped | How much execution history went into the summary |
Anthropic’s Managed Agents surface already emits an agent.thread_context_compacted event carrying pre_compaction_tokens — if you are on that runtime, you are being handed this for free and you should be routing it somewhere.
2. Track three derived metrics.
- Compaction rate per run. How often does a typical run compact? If your p50 run compacts zero times and your p95 compacts four, you have two different reliability populations wearing the same SLO.
- Post-compaction step failure rate vs. baseline step failure rate. This is the one that proves the cost. Compare the failure rate of the N steps immediately after a compaction against the run’s overall step failure rate. A gap is your compaction tax, in numbers, on your workload.
- Repeated-action rate in the post-compaction window. Hash the action — tool name plus normalized arguments — and count repeats within a run. Repeats clustering right after a compaction boundary is the signature the research describes, and you can detect it without reading a single transcript.
3. Alert on the second one moving.
Not on compaction happening — compaction happening is fine and normal. Alert when the post-compaction failure gap widens, because that means either your workloads got longer or your summarizer got worse, and both are things you want to know about before a customer tells you.
The bug that gets everyone
Before the sophisticated stuff, the unglamorous one.
If you are on the Anthropic API and using server-side compaction, the compaction state comes back inside the response content. You must append the full response.content to your message history. Not the extracted text — the content.
# Wrong — silently loses compaction state
text = next(b.text for b in response.content if b.type == "text")
messages.append({"role": "assistant", "content": text})
# Right — compaction blocks are preserved
messages.append({"role": "assistant", "content": response.content})
The first version does not error. It does not warn. The conversation just stops working the way you think it does, and you spend a day blaming the model.
I mention it because in a codebase that has been through a few refactors, “extract the text and append it” is an extremely natural thing for someone to write.
Compaction and context editing are not the same thing
Worth being precise, because these get conflated and they fail differently.
| Compaction | Context editing | |
|---|---|---|
| What it does | Summarizes old history into a condensed block | Clears stale tool results or thinking blocks outright |
| What is lost | Precision — the summary may distort | The content — but nothing is distorted |
| Failure mode | Agent misremembers its own state | Agent has no record at all |
| Best for | Runs that need the arc of what happened | Runs where old tool output is genuinely dead weight |
On the Anthropic API these are separate features with separate beta flags — compaction under compact-2026-01-12, context editing under context-management-2025-06-27 with strategies like clear_tool_uses_20250919. Mixing up the strategy type and the beta header is a common and confusing failure.
The design instinct I would offer: clear what is dead, summarize what is narrative, and externalize what is state. Old tool results from a resolved sub-task are dead — clear them. The arc of the investigation is narrative — summarize it. Which files you have edited is state, and state does not belong in the context window at all.
The structural fix: stop putting execution state in the transcript
The research paper’s own contribution is TRACE, a verifier-guided framework that evaluates individual compaction events by running paired continuations from the same environment state and optimizing the compression prompt against which summary actually continues better — all with the models frozen. That is a genuinely clever evaluation design, and it reports gains on task performance, multi-run reliability, and context-execution efficiency over existing compression baselines.
But notice what it is optimizing: how well the summarizer preserves the things the next step needs.
The more robust move is to stop asking a summarizer to preserve them.
Give the agent an explicit, external, structured record of execution state:
- A task ledger — steps, status, evidence for each. Written to a file or a store, not accumulated in the conversation.
- Idempotent tools where you can manage it, so a repeated action after compaction is wasteful rather than wrong.
- A re-orientation step immediately after compaction: the first thing the agent does post-compaction is read the ledger.
The ledger survives compaction because it was never in the window to begin with. The agent reads it back in, deliberately, as a tool call. That is a durable structure, versus a summarizer you are hoping keeps the right details this time.
This is the same reasoning behind treating agentic memory as a typed thing rather than “whatever is in the transcript.” Execution state is a specific type with specific requirements, and the transcript is a bad store for it.
Why I think this matters more than it sounds
Agent runs are getting longer. That is the direction of the whole field — more delegation, more autonomy, longer horizons. Which means more runs will cross compaction boundaries, and more of them will cross several.
If your reliability model treats an agent run as one unit that either succeeds or fails, you will not see this. You will see a success rate that sags as tasks get longer, and you will attribute it to task difficulty, because that is the available explanation.
The available explanation is wrong. Some meaningful fraction of it is a state transition your platform performs automatically, without telling you, at a moment nobody chose.
Emit the span. Compare the failure rates. Then you will know.
Related
- Context engineering: the window is a budget, not a bucket — the allocation argument this builds on
- Types of agentic memory — why execution state needs its own store
- Tracing the agent loop with OTel GenAI conventions — where the compaction span belongs
- Error budgets for autonomy — turning per-step failure rates into something you can spend
Sources: Toward Reliable Context Compression for Long-Horizon Agents (arXiv:2608.06503) · Anthropic: compaction and context editing documentation
Comments