feat(agent): compact on a token ceiling and rewrite the handoff prompt - #3147
Open
atishpatel wants to merge 1 commit into
Open
feat(agent): compact on a token ceiling and rewrite the handoff prompt#3147atishpatel wants to merge 1 commit into
atishpatel wants to merge 1 commit into
Conversation
The handoff gate fired at a hard-coded 90% of the context window, which is a reasonable default at 200k and a bad one at 1M: a single compaction near the top of a large window has to summarize ~900k tokens of history in one call. Make the fraction configurable and add an absolute ceiling (default 272k, OpenAI's long-context pricing boundary) so handoff fires at whichever binds first. The ceiling is inert at a 200k window, so existing deployments are unchanged. Rewrite the summary prompt around a fixed section contract so the next turn inherits the specifics it would otherwise have to rediscover, and raise the summary output budget from 8k to 32k tokens now that it has more to carry. Raise the handoff cap to 80, since it is a backstop against a compaction loop rather than a session length limit, and hitting it degrades the agent to dropping its oldest turns. Signed-off-by: Atish Patel <atish@squareup.com> Co-authored-by: Cursor <cursoragent@cursor.com>
tlongwell-block
requested changes
Jul 28, 2026
tlongwell-block
left a comment
Collaborator
There was a problem hiding this comment.
I think just lowering the max context here probably works in most cases
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Tweaks
buzz-agent's context handoff (self-compaction): when it fires, and what the summary it produces is asked to contain.When it fires. The gate was a hard-coded 90% of the context window. That's a fine default at 200K and a bad one at 1M — a single compaction near the top of a large window has to summarize ~900K tokens of history in one call, which costs more than most whole sessions and throws away detail the agent was still using. Two changes:
BUZZ_AGENT_HANDOFF_PERCENT(default90) makes the fraction configurable instead of hard-coded.BUZZ_AGENT_HANDOFF_AT_TOKENS(default272000) adds an absolute ceiling, and handoff fires at whichever binds first. 272K is OpenAI's input boundary above which the higher long-context rates apply, so compacting just under it also keeps every request in the cheaper pricing tier.0disables the ceiling.A ceiling rather than an override because the two knobs protect different things: the percentage protects the window, the ceiling protects the summarization call, whose cost scales with how much history it has to read. One pair of defaults covers both 200K and 1M without per-model config. Staying well inside the window is also just better for the agent: cheaper per request, and models degrade at recall and instruction-following as the window fills, so a compacted 200K of relevant context tends to beat 900K of raw history.
What the summary contains. The old prompt asked for "concise but thorough" free prose over five topics. The next turn's failure mode isn't a missing overview, it's a specific missing fact — a path, a command that worked, a dead end already ruled out — and "concise" quietly permits dropping exactly those. The prompt now specifies a fixed set of sections (
TASK,CONSTRAINTS,DONE,DECISIONS,FACTS,REMAINING,NEXT STEP) that must all be present, tells the summarizer its output is the only thing the agent will still know, and asks for specifics over description. It also treats the session history as data rather than instructions, so text in the transcript can't redirect the summarizer.Supporting changes:
8192→32000tokens, since the section contract asks it to carry more. Clamped to half the context window so a small-window deployment can't reserve more output than the window holds.BUZZ_AGENT_MAX_HANDOFFS10→80. This is a backstop against a pathological compaction loop, not a session length limit — reaching it doesn't stop the agent, it silently degrades it to dropping its oldest turns, which loses strictly more than compacting again would. A long autonomous run can legitimately compact dozens of times, and a cap low enough to hit in normal operation makes the degraded path the common one.Related issue
None found — no existing issue or PR covers the handoff threshold or summary prompt.
Testing
No UI surface; this is agent-internal.
cargo test -p buzz-agent(296 unit tests),cargo clippy -p buzz-agent --all-targets -- -D warnings, andcargo fmt --checkall pass.New unit tests cover the threshold policy and the prompt contract:
BUZZ_AGENT_HANDOFF_AT_TOKENS=0hands control back to the percentage.Manual verification of the new defaults against a live provider is the main thing not covered here — the tests pin the policy math and the prompt's shape, not summary quality.
Follow-ups deferred
BUZZ_AGENT_HANDOFF_AT_TOKENSis one global value, so a deployment mixing providers with different long-context boundaries has to pick one or disable the ceiling.max_handoffsfallback is reached; if the degraded path is being hit in practice we'd currently only see it in logs.