All posts
Fundamentals

Four ways to keep an agent's context small

The record is safe and tokens are counted. Shrinking the view for a call is now a matter of strategy, and there are three that matter, plus a rule for choosing between them.

The three cost different amounts and lose different things, so the skill is spending the least you can to get under budget.

Strategy one: the sliding window

The simplest strategy keeps only the most recent messages and drops the older ones. Keep the last n turns, discard the rest.

def sliding_window(contents, keep=10):
    """Keep the original question plus the most recent messages."""
    question = contents[0]                 # never drop what the agent is solving
    recent = contents[-keep:]
    return [question, *recent]

The one detail that keeps this from breaking the agent: hold on to the original question. Drop everything old including the task, and the agent forgets what it was doing. Keep the question and the last few turns, and it stays oriented.

Sliding window is nearly free and nearly blind. It cannot tell an important old message from a trivial one; it just keeps the recent and drops the rest. For many runs that is enough.

Strategy two: compaction

Compaction is smarter about a specific, common case: data the agent has already used. Read a file, finish analysing it, and the file's full contents are dead weight for the rest of the run. Compaction replaces them with a short reference.

before:  [tool_result: read_file("report.csv") -> <40,000 tokens of CSV>]
after:   [note: read report.csv (40,000 tokens), re-read if needed]

The full contents leave the view, and a hint stays in their place. If a later step genuinely needs the file again, the agent re-reads it, because the events still hold it. This follows a scope-by-default principle: give the agent the minimum it needs now, and let it reach back for more only when it does.

Compaction targets tool results, where the biggest, most re-readable blobs live. It leaves the conversation and the reasoning alone.

Strategy three: summarization

Summarization is the last resort, for when the conversation itself has grown long and compaction has nothing left to compact. It takes the oldest stretch of messages and replaces them with a model-written summary.

def summarize_old(contents, keep_recent=6):
    old, recent = contents[:-keep_recent], contents[-keep_recent:]
    summary = ask(f"Summarise this conversation so far:\n{render(old)}")
    return [Message(role="system", content=f"Summary so far: {summary}"), *recent]

Summarization is the most powerful and the most lossy. It buys the most room, and it decides, via another model call, what to keep and what to drop. That is a real cost and a real risk: a summary is a compression you cannot fully predict, and a later security post looks at what a summary can quietly lose.

The hierarchy: cheapest first

The three strategies form a ladder to climb only as far as you must, because each step costs more and loses more than the last. They are not alternatives you pick once.

measure the view
   under budget?        -> send it, do nothing
   still over?          -> compaction   (references for used data, near-free)
   still over?          -> sliding window (drop old turns, near-free)
   still over?          -> summarization (a model call, lossy, last resort)

Measure, and if the view fits, do nothing at all. Over budget, reach for the cheap, low-loss strategies first. Only when those are exhausted do you pay for summarization. Reaching straight for the summariser on every call burns money and loses information you did not need to lose.

A hierarchy: do nothing if it fits, then the cheap strategies, then summarization only as a last resort.A hierarchy: do nothing if it fits, then the cheap strategies, then summarization only as a last resort.

The four, side by side

StrategyWhat it doesCostWhat it loses
Sliding windowKeep recent messages, drop oldNear-freeOld context, indiscriminately
CompactionReplace used data with a referenceNear-freeNothing, if the agent re-reads
SummarizationReplace old messages with a summaryA model callWhatever the summary left out
HierarchyApply the above cheapest-firstThe check itselfNothing; it minimises the rest

Three strategies plus a hierarchy: pay the least you can to get under budget.Three strategies plus a hierarchy: pay the least you can to get under budget.

What to take from this

  • Three strategies shrink the view. A sliding window keeps recent messages, compaction replaces used data with references, summarization rewrites the oldest stretch.
  • They cost and lose different amounts, so a hierarchy applies them cheapest-first and only as far as the budget forces.
  • Keep the original question through a sliding window, and lean on compaction before summarization, because summarization is the one that pays a model call and loses the most.

Compression solves the space problem inside one run. The next post turns to the time problem across runs, starting with the container that lets an agent remember the previous conversation at all.