Skip to content

C5 · lesson 1 · 10 min read

Context windows and compaction

What fills the context window, how to measure it before you send, and how to keep long sessions small with compaction and context editing.

Ընտրեք տեքստը՝ հայերեն թարգմանությունը տեսնելու համար։Highlight text to see Armenian. Machine-assisted translation; English is the source of truth.

Official video by Anthropic on YouTube. Pressing play loads it from youtube-nocookie.com. ·open on YouTube

The context window is the model’s working memory for one request. It is not the training data. It is everything you send plus everything Claude writes back. A big window is useful, but more context is not automatically better: as the token count grows, recall and accuracy drop. The docs call this context rot. So the skill being tested is choosing what goes in, not only fitting it in.

What counts

Every part of a request takes up space in the same window:

toolssystemhistory + tool resultsnew msgoutputinput: what count_tokens estimatesincl. thinkingwindow limitinput alone over the limit → 400 "prompt is too long"
One request, one budget. Input and output share the window.
  • Tool definitions, the system prompt, and every message in messages, including tool results, images and documents.
  • The output for this turn, including thinking tokens. Thinking is part of max_tokens and is billed as output.
  • Earlier thinking blocks, on current models. Recent Opus, Sonnet and Haiku models keep earlier thinking in the history by default, where it counts as input. Older models strip it automatically.

The API never drops earlier turns for you. Each turn, the whole history is sent again. An on-call bot that pastes 200 lines of kubectl logs into every tool result can fill its window long before the incident is over.

Current Opus, Sonnet and Haiku models have a 1M-token window, and one request can produce up to 128k output tokens. Some older models have 200k. Check the model comparison table rather than assuming.

What happens at the limit

Situation Result
The input alone is larger than the window 400 invalid_request_error (“prompt is too long”)
Input plus max_tokens exceeds the window (Claude 4.5+) Accepted. If generation hits the limit: stop_reason: "model_context_window_exceeded"

Your code has to handle both: catch the 400 before you retry blindly, and treat that stop reason as a truncated answer, not a finished one.

Measure before you send

The token counting endpoint takes the same shape as a Messages request (system, tools, images, PDFs, thinking) and returns input_tokens:

# count_timeline.py - estimate tokens for an incident timeline before sending it
import sys
import anthropic

client = anthropic.Anthropic()  # reads ANTHROPIC_API_KEY from the environment
MODEL = "claude-sonnet-5-5"

timeline = open(sys.argv[1], encoding="utf-8").read()
count = client.messages.count_tokens(
    model=MODEL,
    system="You are an SRE assistant. Summarise incidents for a postmortem.",
    messages=[{"role": "user", "content": f"<timeline>\n{timeline}\n</timeline>"}],
)
print(f"{MODEL}: {count.input_tokens} input tokens")

Things to know about it:

  • It is an estimate. The real number can differ slightly.
  • It is free but rate-limited, and its limits are separate from message creation.
  • It does not use prompt caching, even if you include cache_control.
  • Counts depend on the tokenizer. Claude Opus 4.7 and later models use a newer tokenizer that produces roughly 30% more tokens for the same text. Count against the model you will actually call.

Keep long sessions small

Compaction (API, beta). The server summarises older turns so a conversation can continue past the limit. You can ask for it when you choose (on demand) or let the API do it when input reaches a token threshold you set. It is in beta for Claude 4.6 and later models.

Context editing (API, beta). Rule-based clearing instead of summarising. It is enabled with the context-management-2025-06-27 beta header:

response = client.beta.messages.create(
    model=MODEL,
    max_tokens=2048,
    betas=["context-management-2025-06-27"],
    tools=tools,
    messages=messages,
    context_management={
        "edits": [{
            "type": "clear_tool_uses_20250919",
            "trigger": {"type": "input_tokens", "value": 60000},
            "keep": {"type": "tool_uses", "value": 3},
            "exclude_tools": ["get_incident"],
        }]
    },
)
print(response.context_management)  # applied_edits: what was cleared

clear_tool_uses_20250919 replaces the oldest tool results with a placeholder and keeps the most recent ones. clear_thinking_20251015 manages old thinking blocks. If you use both, the thinking strategy has to come first in edits.

Other ways to keep context small, all in the docs: let a hook grep a 10,000-line log down to its ERROR lines, send noisy work such as test runs to a subagent so only a summary comes back, and move rarely used CLAUDE.md sections into skills that load on demand.

Recap

  • Tools, system, messages, tool results and output (including thinking) all share one window, and more context can make answers worse.
  • Input over the limit returns a 400. Generation that runs out of room stops with model_context_window_exceeded.
  • count_tokens gives a free estimate. Count against the model you will call, because tokenizers differ.
  • Use compaction to summarise and context editing to clear old tool results or thinking. In Claude Code use /context, /compact <focus> and /clear.

$ ./try-it.sh

Try it: size an incident timeline before you send it

  1. Export ANTHROPIC_API_KEY in your shell (never paste it into the script) and pip install anthropic.
  2. Save the script from this lesson as count_timeline.py and point it at a long log or incident timeline file.
  3. Run it and note input_tokens. Then trim the file to the last 30 minutes, or grep it down to ERROR lines, and run it again.
  4. In Claude Code, run /context in a long session, then /compact Keep the timeline of actions and the open hypotheses and compare.

Check yourself

3 questions. Original practice questions, not taken from the real exam.

  1. Your incident bot appends the full output of every kubectl tool call to the conversation. After two hours of an incident, its answers start mixing up pod names from different namespaces, although the request is still well under the model's context window.

    1. What is the most likely explanation?

  2. A postmortem generator sends a 300k-token timeline plus instructions to a model and sets a large max_tokens. Sometimes the response ends mid-sentence with stop_reason "model_context_window_exceeded"; on other days the request fails with a 400 "prompt is too long".

    2. Which two statements explain these outcomes? (Choose two.)

    Choose 2.

  3. An agent running on claude-sonnet-5-5 calls a monitoring tool every few minutes during a long investigation. You want old tool results cleared automatically once input passes about 60k tokens, but you never want results from the get_incident tool removed, and you want to keep the three most recent tool results.

    3. Which configuration does this?

Answer every question to check.