Context Compaction

Advanced5 min

Compaction replaces older turns with a summary Claude writes on the server, and the swap that follows has two mistakes that raise no error. Images and documents inside the summarized range do not survive it.

#techniques

Two ways to shrink a conversation

A long conversation outgrows its window. There are two server-side answers, and they are different features that solve the problem differently.

Context editing clears by rule. It drops the oldest tool results or thinking blocks and leaves a placeholder, keeping what it does not clear word for word.

Compaction summarizes. Claude writes a summary of the older turns on the server, and that summary stands in for the messages it replaces.

This page is compaction. State and historical context covers why a long conversation gets expensive and what a running summary costs you. Here the question is how to get one without writing the summarizer.

You cannot send both on one request: compaction and context_management are mutually exclusive.

Who decides when

Compaction comes in two forms, behind the beta header compact-2026-09-04 and a top-level compaction parameter.

On demand. You send a separate request carrying the conversation and "compaction": {"type": "summarize"}. No reply is generated. You get back one compaction block and a stop_reason of "compaction".

At a token threshold. The API compacts inside an ordinary request when input tokens reach a trigger you set. One parameter, no loop of your own.

Anthropic's guidance is to prefer on demand where it is available, and the reason is control. Your code knows when a turn finished and whether the user is waiting; the API only knows the token count.

The block, and the swap that has no error

The response carries the summary as readable text plus a signature:

{
  "type": "compaction",
  "content": "Summary of the conversation: the user is designing the data model for a recipe app...",
  "signature": "EuYBCkQY..."
}

Send it back exactly as returned. A changed content or signature fails with compaction_signature_invalid or compaction_content_mismatch.

From then on the block goes first in messages, the summarized messages come out, and your next turn follows it. Leaving summarized messages in front of the block returns a 400, compaction_block_misplaced.

Two neighbouring mistakes raise nothing at all, and they are the ones to write a test for:

  • Summarized messages left after the block get sent to Claude again. You paid for a summary and kept the thing it replaced.
  • A later request that omits the block loses the summary entirely. Claude does not have it, and the conversation carries on as though those turns never happened.

Neither is an error. Both are a bill or a quality problem you find later.

A summary is not guaranteed

The summarization call can end without producing one, and the response is still a 200 with empty content. So check stop_reason before reaching for the block.

stop_reasonWhat happenedWhat to do
max_tokensthe summary was cut offresend with a larger max_tokens
model_context_window_exceededno room for the summarization promptshorter instructions, fewer messages
tool_usethe model called a tool insteadtell it not to, in instructions
refusalthe request was declinedcarry on without a summary
end_turnthe call returned no textcarry on without a summary

You can always continue without one and compact after the next turn. The failed call is still billed.

max_tokens caps the whole summarization call including any thinking, so give it several thousand rather than the value you use for a reply.

What the summary cannot carry

Images, documents, container_upload blocks and fetched URLs inside the summarized range are gone once the block replaces them. The summary is text.

If a later turn still needs the screenshot from turn six, re-upload it. This is the failure that looks like the model forgetting something it was shown, and it is worth checking first when a compacted agent starts behaving oddly.

Mid-conversation role: "system" messages have the same problem. They get summarized like anything else, so their instructions stop applying. State anything that still matters again after your next user turn.

Steering the summary

Without instructions the API uses its own prompt. A non-blank instructions string, up to 16,384 characters, replaces that prompt entirely rather than adding to it.

Reach for it when the default drops something later turns need. Name what must survive, and tell the model not to call tools, which removes one of the five ways a summary fails to arrive.

Reading the bill

Top-level input_tokens and output_tokens come back zero on a compaction response, because no reply was generated. The real figures are in usage.iterations, under the compaction entry.

Anything summing the top-level fields will report that compaction is free. It is not; sum across usage.iterations instead. Sending the block back on later requests adds no further compaction cost, which is the part that does save you money.

When to reach for it

Compaction earns its place when a conversation must continue past the window and the older turns are finished with. It is a poor fit when the agent keeps needing specific earlier detail, because a summary is lossy by construction and you cannot predict which detail it drops.

For that case, keep the material outside the transcript and fetch the piece that matters. External memory covers that shape, and pairs well with this one: compaction keeps the active context small, and memory holds what must survive being summarized.

Further reading

Knowledge check

Question 1 of 4

What distinguishes compaction from context editing?

Sign in to save your progress and pick up where you left off.