Skip to content

Compaction keeps an unbounded recent-context in agent sessions with few user messages #60391

Closed as duplicate

Description

@ualtinok

Description

Summary compaction keeps the newest compaction.keep.tokens (default 15,000) of conversation verbatim beside the summary. But recentStart then moves the start back to the latest type: "user" message at or before the cut, so tool calls stay with their results (packages/core/src/session/compaction.ts:1004-1027, v2.2.2).

In a long agent session, real user messages can be far apart. Synthetic, skill and shell rows don't count as user messages. So the kept range can run from a weeks-old user message to now: thousands of tool steps, whatever keep says. Nothing bounds it against the model's context window.

The kept text isn't stored. withRecentText (packages/core/src/session/history.ts:226-263) rebuilds it from every row between metadata.keepID and the compaction on each load. So the oversized checkpoint is resent on every request, and the session can't recover by itself.

We saw this on 2.2.2 in a session of about 5,900 messages. The compaction was triggered by /goal when its reviewer request overflowed. The rendered checkpoint was about 9 MB, almost all of it in <recent-context>, and every later request failed at about 2.2M tokens.

Suggested fix: cap the kept range in tokens. If the nearest user message would push it past the cap, start at an assistant step boundary instead, keeping each tool call with its result. Or summarize everything and keep no recent context.

Plugins

Magic Context supplied the summary through the compaction hook. The kept range comes from the host either way: summarize adds keepID to a hook-supplied result too (compaction.ts:523-525).

OpenCode version

2.2.2

Steps to reproduce

  1. Run an agent session with one user message followed by many tool steps, well past 15,000 tokens.
  2. Compact it, with /compact or /goal overflow.
  3. Inspect the next request: <recent-context> contains everything since that user message, not about 15,000 tokens.

Operating System

macOS

Activity

  1. opencodejr commented on Oct 29, 2026

    @opencodejr

    Thanks for the detailed write-up and the numbers from your 5,900-message session.

    I think this is a duplicate of #43250. It reports the same problem: after the keep.tokens cut, recentStart moves the start back to the nearest type: "user" message with no limit, and synthetic and shell rows are skipped. So a long agent run after one prompt is kept verbatim in the recent context. That issue already has measured cases from autonomous sessions on 2.0.15 through 2.0.24, and the code is still the same in 2.2.2 and on dev. Your /goal trigger and the rebuild in withRecentText on every load make the impact worse, but the root cause is the same.

    Possible duplicates and related issues, ordered by likelihood:

    Your measurements, especially the ~9 MB checkpoint and the session that couldn't recover, would be useful on #43250.

    The bot will close this issue as a duplicate in 1 day unless you reply explaining how your problem is different.

  2. opencodejr commented on Oct 30, 2026

    @opencodejr

    We haven't heard back, so I'm closing this as a duplicate of #43250. That issue covers the same problem: the kept range moves back to the latest user message with no limit, so agent sessions with few user messages keep far more than compaction.keep.tokens verbatim beside the summary. Please follow #43250 for updates; open PR #53233 is the fix aimed at it. Your measurements, especially the ~9 MB checkpoint from /goal and the session that couldn't recover, would be useful there. If your case turns out to be different, reply here and we can reopen.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions