Skip to content

"Session too large to compact" — the summarization request itself has no size budget #48844

Closed as not planned

Description

@whitesm2000

"Session too large to compact" — the summarization request itself has no size budget

Summary

Follow-up to #48827 (auto-compaction ping-pong). Even with the loop guard in place, compaction of a genuinely large session fails outright with:

Session too large to compact - context exceeds model limit even after stripping media

Three compounding causes in session/compaction.ts:

  1. The head has no budget. select() caps only the retained tail (preserveRecentBudget, 25% of the usable window). Everything older — the head — is serialized and sent to the summarizer as a single request. A 60k-token session on a 64k-context model, or a 900k-token session on a 1M-context model, produces a summarization request that doesn't fit the model — so compaction (the mechanism whose entire job is shrinking oversized sessions) fails precisely when it is most needed.

  2. The tail budget derives from the wrong model. When a dedicated compaction model is configured (agent.compaction.model, e.g. a cheap 1M model), select() sizes the retained tail from the compaction model's window. The compacted session must fit the session model's window — with a 1M compactor and a 64k session model, the retained tail alone (15k tokens) plus system prompt permanently overflows the session model.

  3. No escalation. If the post-compaction context still overflows, the next auto-compaction retains the same-sized tail and fails identically, until the loop guard from Auto-compaction loops forever when a session's irreducible context exceeds the model's usable window #48827 stops the session.

Proposed fix

PR linked below:

  • Chunked (map-reduce) summarization. The serialized head is packed into chunks capped at half the compaction model's usable window; each chunk is summarized; partial summaries that still exceed the budget are packed and re-summarized until the final request fits. Sessions whose head fits take the previous single-request path unchanged, byte for byte.
  • Tail budget from the session model, escalating full → half → none on each consecutive failed auto-compaction (tracked by the Auto-compaction loops forever when a session's irreducible context exceeds the model's usable window #48827 streak machinery), so a session whose floor exceeds the window sheds retained context before the loop guard stops it. The guard's limit becomes the ladder length (3).

With both, compaction succeeds by construction for any session size on any (working) model pair, and the session loop still stops cleanly when even a summary-only context fits no better.

Environment

  • OpenCode desktop v1.18.30 (macOS), session model cerebras/qwen-3.8-27b (64k context), compaction model deepseek/deepseek-v4-flash (1M context), ~60k-token session.

Activity

  1. github-actions commented on Sep 13, 2026

    @github-actions
    Contributor

    This issue might be a duplicate of existing issues. Please check:

    If this is intentionally a follow-up to #48827 with a distinct root cause and proposed fix, it may be worth clarifying that relationship and whether a linked PR has been opened.

  2. stweil commented on Sep 24, 2026

    @stweil

    Does PR #51121 work for you?

  3. aitrawog commented on Sep 25, 2026

    @aitrawog

    Confirmed live, and the mechanism is now exactly pinned: the summarizer's head is the entire history, because select() budgets only the retained tail and the default tail is tiny.

    Environment: opencode 1.18.32 (stable), provider ollama-cloud (https://ollama.com/v1), model deepseek-v4.1-flash (1,048,576 context / 393,216 max output).

    Auto-compaction fired at a 666,763-token live context and failed with The prompt is too long: 1122556, model maximum context length: 1048576; the session was permanently wedged.

    Two verified facts:

    1. The provider admits on input tokens only — the output budget is not counted against the window. Probed directly: prompt 800,031 + max_tokens 393,216 → accepted; prompt 1,050,041 + max_tokens 1 → rejected (The prompt is too long: 1050041).
    2. The head was the whole history. I reconstructed the serialized head with the exact serialize() rules (all reasoning text retained, tool output capped at 2,000 chars) and measured it through the real provider: 1,128,448 input tokens, against the logged crash prompt of 1,122,556 (0.5% apart). The live context was only 666,763 — so the serialized request was ~1.7× the live context.

    The select() trigger: preserveRecentBudget defaults to min(15_000, max(2_000, 25% of usable)). With the newest turn (~43k tokens here) above that budget, the retained tail is empty and head becomes all messages — precisely the request that overflowed.

    Mitigation for an existing session (opencode.json):

    • set limit.input so compaction.reserved is honored, e.g. limit: {context: 1048576, input: 1048576, output: 384000};
    • keep reserved large — it makes isOverflow fire earlier, when the serialized head is smaller;
    • compaction.prune: true;
    • compaction.preserve_recent_tokens: 500000 — on this session that cut the reconstructed head from ~1,128,448 to 634,064 real tokens, under the input window.

    This is explicitly a stopgap: preserve_recent_tokens caps the tail, so the head keeps growing as the session grows. Only dropping oldest turns when the head exceeds budget (PR #51121) bounds it permanently.

    Assisted-by: opencode ollama-cloud/deepseek-v4.1-flash (analysed on a live system)

  4. thdxr commented on Oct 11, 2026

    @thdxr
    Member

    Thanks for the report! OpenCode 2.0 is now out and development is focused on V2, so we're closing issues filed against OpenCode 1. Please upgrade (opencode upgrade --major, details: https://anoma.ly/notes/opencode-2-0), and if this is still relevant on 2.0, reopen this issue or open a new one with your 2.0 version.

    — from 𝕺𝖕𝖊𝖓𝕮𝖔𝖉𝖊

  5. thymikee commented on Oct 12, 2026

    @thymikee

    This is still happening on v2

  6. stweil commented on Oct 12, 2026

    @stweil

    @thdxr, could you please reopen this issue? I don't have the required permission.

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

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions