feat(default): auto-compaction via summarize_at_tokens - #1983
Conversation
da50ccb to
32ddfde
Compare
| # Compact after the turn's tool results land, so the summary sees them. The summary | ||
| # is its own (tool-free) completion; the rebuilt list keeps the initial prompt so the | ||
| # task statement itself is never summarized away. | ||
| if args.summarize_at_tokens and context_tokens >= args.summarize_at_tokens: |
There was a problem hiding this comment.
🟡 Medium default/program.py:359
The compaction check uses context_tokens from the completion returned before the current turn's tool results were appended to messages. A bash, search, or MCP call can return a large payload that pushes messages past the context limit, but the code won't detect this until the next chat call. When it finally does detect it, it appends SUMMARIZE_PROMPT to the already-oversized messages list and sends that as the summary request — which fails because the list is already over the limit, so the episode still terminates at the context boundary instead of compacting. The threshold check needs to account for the size of the newly appended tool-result content before deciding whether to compact, rather than relying on stale token counts from before the tool results were added.
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @verifiers/v1/harnesses/default/program.py around line 359:
The compaction check uses `context_tokens` from the completion returned *before* the current turn's tool results were appended to `messages`. A `bash`, search, or MCP call can return a large payload that pushes `messages` past the context limit, but the code won't detect this until the next `chat` call. When it finally does detect it, it appends `SUMMARIZE_PROMPT` to the already-oversized `messages` list and sends that as the summary request — which fails because the list is already over the limit, so the episode still terminates at the context boundary instead of compacting. The threshold check needs to account for the size of the newly appended tool-result content before deciding whether to compact, rather than relying on stale token counts from before the tool results were added.
Adds rlm-parity context compaction to the default (bash+edit) harness, matching rlm's engine semantics exactly: trigger on usage.prompt_tokens >= threshold; summary requested with rlm's CHECKPOINT_COMPACTION_PROMPT while tools stay in the request under tool_choice="none" (the prompt renders like a regular turn); the rebuilt list is the system message plus the summary wrapped in rlm's POST_COMPACTION_FRAMING — the original task prompt is dropped and the summary carries the goal. Config mirrors rlm's summarize_at_tokens: fixed int or (lo, hi) per-task draw seeded by task index. Validated in production RL runs (GLM-4.5-Air on scaleswe-v1, 131k contexts). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
/tmp/vf-rate-limiters is a fixed path; on multi-user hosts another user's bucket file makes every tunnel fail with Permission denied (observed killing 100% of container-runtime rollouts on a shared SLURM node). Suffix the directory with the username. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
32ddfde to
2bcc6af
Compare
224e6e7 to
2bcc6af
Compare
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 85f56fb. Configure here.
| ] | ||
| if self.config.edit: | ||
| args.append("--edit") | ||
| threshold = self.summarize_threshold(trace.task.idx) |
There was a problem hiding this comment.
Wrong task index attribute path
High Severity
summarize_threshold is called with trace.task.idx, but TraceTask only exposes data (and type). The index lives on trace.task.data.idx, as the rlm harness already uses. Because the argument is evaluated eagerly, every DefaultHarness.launch raises AttributeError, including when auto-compaction is disabled.
Reviewed by Cursor Bugbot for commit 85f56fb. Configure here.
| the model to summarize its progress and restarts the message list from the initial prompt plus | ||
| that summary. An int is a fixed threshold; a `(lo, hi)` pair draws a per-group threshold | ||
| (seeded by the task index, so a task's rollouts share one draw and tasks vary). `None` | ||
| disables auto-compaction; ints must be positive.""" |
There was a problem hiding this comment.
Skills docs omit new config
Medium Severity
This PR adds user-facing summarize_at_tokens to DefaultHarnessConfig for eval/RL workflows, but skills/evaluate-environments/references/REFERENCE.md still lists only edit and search under that config. The skills-update rule requires matching skill updates when evaluation/training knobs change; RLMHarnessConfig already documents the same field.
Triggered by project rule: BugBot Instructions
Reviewed by Cursor Bugbot for commit 85f56fb. Configure here.
ApprovabilityVerdict: Needs human review 1 blocking correctness issue found. New auto-compaction feature with significant runtime behavior changes. Unresolved review comments identify a high-severity bug (wrong attribute path You can customize Macroscope's approvability policy. Learn more. |


Auto-compaction for the default harness, validated in multi-day production RL runs (GLM-4.5-Air on
scaleswe-v1/swebench-verified-v1at 131k context, ~100k rollouts).Auto-compaction (
summarize_at_tokens)rlm-parity context compaction, matching rlm's engine semantics exactly:
usage.prompt_tokens >= thresholdafter a turn's tool results land.CHECKPOINT_COMPACTION_PROMPT, with tools kept in the request undertool_choice="none"so the prompt renders like a regular turn; tool calls in the reply are ignored.POST_COMPACTION_FRAMING— the original task prompt is dropped and the summary carries the goal, exactly as rlm does.summarize_at_tokens— fixed int, or a(lo, hi)per-task draw seeded by task index so a group's rollouts share one threshold.Long multi-turn episodes survive past the context window; observed in production that agents resume coherently across the boundary (including completing tasks post-compaction).
🤖 Generated with Claude Code
Note
Medium Risk
Changes the default agent chat loop and issues extra model calls when compaction fires; behavior is gated behind config but affects long-running eval/RL rollouts and trace continuity.
Overview
Adds optional context auto-compaction to the default harness so long agent episodes can continue past the context window without manual truncation.
Harness config: New
summarize_at_tokensonDefaultHarnessConfig— fixed positive int,(lo, hi)range (per-task threshold seeded bytask_idxso rollouts on the same task share one draw), orNoneto disable. Pydantic validation rejects invalid bounds.DefaultHarness.summarize_threshold()resolves the value and passes--summarize-at-tokensinto the uv program when enabled.Program loop: After each tool-using turn, if
usage.prompt_tokensmeets the threshold, the agent runs an extra completion with rlm-style checkpoint prompts (CHECKPOINT_COMPACTION_PROMPT,POST_COMPACTION_FRAMING), usingtool_choice="none"for the summary call. The message list is then rebuilt to system messages only plus a single user message with the framed summary — the original task user prompt is dropped, matching rlm semantics.chat()now returns prompt token usage to drive the trigger.Reviewed by Cursor Bugbot for commit 85f56fb. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Add auto-compaction via
--summarize-at-tokensto the default harnesssummarize_at_tokensfield toDefaultHarnessConfigthat accepts a fixed int or a(lo, hi)range; invalid values raise a validation error at config instantiation.--summarize-at-tokens={threshold}to the launched program, with per-task thresholds drawn deterministically from the range usingrandom.Random(task_idx).tool_choice='none', then rebuilds the conversation to system messages plus a framed summary, discarding prior history.Macroscope summarized 85f56fb.