Agent(llm=llm) already does this.
How the history is measured
- The window comes from the model: an explicit
context_window, the server’s listing, the built-in table, or a fallback. See Models. - The count is anchored on the provider’s own report: after each reply, the agent records the input and output tokens the provider billed, which cover the system prompt, the tool schemas and any files. Only the messages added since are estimated locally (tiktoken by default), so a tokenizer mismatch cannot drift.
ContextUsage also tells the limit (limit_tokens), whether the window is known (resolved) and whether the count is anchored on the provider (anchored). on_context_usage is called with it before every request:
When compaction happens
Compaction triggers when the history reachesmax_fraction of the window (0.85 for the agent’s default buffer), and stops once it is back under a target, 70 % of that limit by default (about 60 % of the window). That gap means compaction runs in batches, and between two batches the prefix sent to the model stays identical, so the provider’s prompt cache stays valid.
The tiers
The tiers are applied in this order, re-measuring after each, until the history fits. Whatever happens:
- a tool call and its result always move together;
- the first user message, the task of the current run, and any message marked with
pin()(gwenflow.memory.compaction) survive every tier; - a summarizer that fails never fails the run: the sliding window takes over for that batch.
agent.history.compactions[-1].removed, and each compaction emits a compact_messages span with the tiers applied and the counts before and after (never the content).
The summarizer
The summary tier calls a model. By default it is a copy of the agent’sllm; give a cheaper one with summarizer:
Compacting by hand
Large tool outputs
A single grep or file read can fill a small window.max_tool_output_tokens caps one tool result: a longer one is set aside, the model gets its beginning and a reference, and a read_tool_output(ref, offset, length) tool to page through the rest.
Warning the model
Withwarn_near_limits=True, the system prompt of a request carries a notice when the run nears a limit, so the model concludes instead of seeing its history rewritten or being cut off:
- URGENT when the history reaches
warning_threshold(0.7) of its budget, or the runwarning_thresholdofmax_turns; - CRITICAL when a compaction is imminent, or
critical_remaining_turns(3) turns are left.
A custom buffer
Pass your own buffer ashistory to tune everything:
default_strategies(summarizer=..., deduplicate={...}, clamp={...}, clear={...}, summarize={...}, sliding={...}) builds the default tiers with per-tier options; without a summarizer it skips the summary tier.
A coding agent on a 32K window
Recommended configuration for a coding agent on a model served by vLLM with a 32K window:hf_tokenizer(model, **kwargs) counts with the Hugging Face tokenizer of the served model (kwargs go to AutoTokenizer.from_pretrained: trust_remote_code, token…); tiktoken under-counts for Mistral, Qwen or Gemma models.