Skip to content

fix(opencode): break auto-compact loop when compaction makes no progress#29150

Open
ZehuaWang wants to merge 3 commits into
anomalyco:devfrom
ZehuaWang:fix/auto-compact-loop-guard
Open

fix(opencode): break auto-compact loop when compaction makes no progress#29150
ZehuaWang wants to merge 3 commits into
anomalyco:devfrom
ZehuaWang:fix/auto-compact-loop-guard

Conversation

@ZehuaWang
Copy link
Copy Markdown

@ZehuaWang ZehuaWang commented May 25, 2026

Issue for this PR

Closes #28543

Type of change

  • Bug fix

What does this PR do?

When a model's context limit in models.dev is smaller than what the provider actually serves, every turn reports overflow tokens and auto-compaction fires forever. Once from the pre-model-call isOverflow check, then again from the processor's own finish-step overflow check inside handle.process.

Track the token count from the last auto-compaction in this runLoop invocation. If we'd fire again without the count having dropped by at least 5%, throw ContextOverflowError instead. Reset the tracker when overflow is no longer detected so healthy long sessions aren't affected.

How did you verify your code works?

bun test test/session/compaction.test.ts test/session/prompt.test.ts — all pass. Added unit tests around the 5% boundary and one integration test that seeds an overflow assistant message, calls prompt.loop, and asserts it exits with ContextOverflowError.

Also built the binary and pointed it at a stub openai-compatible server that always reports overflow usage. Original 1.15.10 made 20 LLM calls before timing out at 90s. Patched build exits in ~4s with the typed error.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

Closes anomalyco#28543

When a model's configured context window is smaller than what the
provider actually serves (e.g. GitHub Copilot's claude-opus-4.7 mapped
at 144K in models.dev when the real ceiling is higher), every successful
turn keeps reporting "overflowing" token counts. Auto-compaction then
fires before each new prompt AND inside the processor on each finish-step,
and we never escape it.

Add a stall detector that compares the reported token count between
consecutive auto-compaction triggers in a single run. If a second
auto-compaction would fire with the token count not having dropped by at
least 5%, throw a typed ContextOverflowError instead of recreating the
compaction task forever.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

The following comment was made by an LLM, it may be inaccurate:

Based on my search, I found several related PRs addressing auto-compaction and context overflow issues:

Potentially Related PRs:

  1. fix(session): break infinite compaction loop #27919 - fix(session): break infinite compaction loop

    • Directly addresses the same infinite compaction loop problem
  2. fix(session): prevent double compaction after auto-compact #26484 - fix(session): prevent double compaction after auto-compact

    • Addresses compaction logic preventing redundant compaction attempts
  3. fix(session): compact finished overflowed turns #27730 - fix(session): compact finished overflowed turns

    • Related to handling overflow detection during session compaction
  4. fix: enable auto-compaction for sub-agents and improve context overflow detection #25180 - fix: enable auto-compaction for sub-agents and improve context overflow detection

    • Improves context overflow detection mechanism
  5. feat(session): add custom compaction thresholds along with prevention of continuous compaction #10123 - feat(session): add custom compaction thresholds along with prevention of continuous compaction

    • Adds threshold logic and prevents continuous/infinite compaction
  6. fix: include reasoning tokens in overflow detection #28585 - fix: include reasoning tokens in overflow detection

    • Related to token counting in overflow detection

Why they might be related: These PRs all address aspects of the auto-compaction loop, token overflow detection, and preventing infinite compaction cycles. PR #27919 appears most similar as it also fixes an "infinite compaction loop." You should verify whether #27919 was already attempted, what its status is, and how this PR (#29150) differs in its approach (using a stall detector vs. other mechanisms).

chenney0552 and others added 2 commits May 24, 2026 22:28
Review found the boundary check used >= instead of >, so a reduction that
hit exactly the threshold (e.g. 200K → 190K) was flagged as stalled and
threw ContextOverflowError, contradicting the PR description that requires
"at least 5% reduction" to escape stall. The boundary test name said
"returns false right at the 5% boundary" but the assertion said true —
which made the inconsistency obvious.

Change the comparison to strict `>`. Now exactly-(1-threshold) reduction
counts as progress; only reductions strictly less than the threshold trip
the guard. Update the boundary test name, comment, and assertions to
match.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Switching the percentage check from >= to > closed the boundary
false-positive (200K -> 190K now counts as progress) but opened a
zero-token hole: when the provider directly throws ContextOverflowError,
SessionProcessor.halt sets needsCompaction without running step-finish,
so handle.message.tokens stays at the zero-initialized values. The
percentage check then evaluates 0 > 0 * 0.95 = false on every fire and
the loop keeps recreating compactions.

Add a one-line guard so two consecutive zero-token compactions trip the
stall detector. Unit test added alongside the boundary cases.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Auto-compact infinite loop with claude-opus-4.7-1m (GitHub Copilot) due to wrong context window

2 participants