Repository navigation
Description
Summary
Automatic context compression triggers far too early (after ~15k tokens) despite a 200k token context window, because the configured compaction.buffer is subtracted directly from the model's input limit, leaving only 195,904 − 180,904 = 15,000 tokens of headroom before compaction fires.
Environment
- opencode version: 2.1.3
- OS: Darwin 27.0.0 (darwin arm64)
- Terminal: Unavailable (terminal environment variables not set)
- Shell: /bin/zsh
- Install/channel: latest
- Active plugins: -opencode.browser, /Users/thtesche/.config/openchamber/run/instances/52345/agent-tool/openchamber-agent-tool, @openchamber/opencode-claude@^1
- Active model:
strata/qwen3.8-flash-next-q2_0(context: 200,000 / input: 195,904 / output: 4,096) - User config:
compaction: { auto: true, buffer: 180904 }
Reproduction
- Set
compaction.bufferto a large value close to the model's input limit (e.g.180904of195904). - Start a session and exchange enough messages that the measured context passes ~15k tokens.
- Observe automatic compaction firing on nearly every turn, well before the 200k window is approached.
Expected Behavior
With a 200k context window and buffer unset, automatic compaction should not fire until roughly 85% of the window is used (~166k tokens). A large buffer should not collapse the ceiling to ~15k tokens.
Actual Behavior
The ceiling is calculated as window - buffer = 15,000 tokens, so due() returns true as soon as estimateContext(context) >= 15,000. Compaction fires after only a few exchanges, repeatedly rewriting history and discarding prompt-cache benefits.
Root Cause
calculateCeiling in packages/core/src/session/compaction.ts (introduced 2026-10-23 in commit 33726e8, PR #58313):
const calculateCeiling = (limit, buffer) => {
const window = limit.input || limit.context // 195,904
if (buffer !== undefined && buffer < window) // 180,904 < 195,904 → true
return window - buffer // 195,904 − 180,904 = 15,000
return window - Math.max(Math.floor(window * RESERVE_SHARE), RESERVE_MIN)
}When buffer is set but still smaller than window, it is subtracted in full. The fallback to RESERVE_SHARE (15%) only applies when buffer >= window or buffer is unset.
The same day's commit added a guard ("ignore a compaction buffer that leaves the model no room"), but it only ignores buffers >= window. A buffer of 180,904 against an input limit of 195,904 still passes the buffer < window check, so the 15k ceiling stands.
Additional Context
- Evidence from
opencode.db: two local sessions exist, both measured well under the current 15k ceiling; the active strata/qwen3.8 session showsinput 707 / output 8847 / reasoning 3165 / cache read 245141 / cache write 127909— cache-heavy, soestimateContextclimbs quickly. - The
eventtable inopencode.dbis empty; compaction events are not persisted there, so the DB alone cannot confirm trigger counts. The code path is sufficient evidence. - This is not issue compaction: auto-compaction loops when provider reports input tokens above the model's context limit #50474 (auto-compaction loop on provider-reported overflow). This is a config/ceiling interaction: a user-set buffer collapses the trigger threshold.
- Suggested fix: validate
compaction.bufferso it cannot reduce the ceiling below a sane floor (e.g.RESERVE_SHAREof the window), or document thatbuffervalues close toinputwill cause near-immediate compaction.
Activity
opencode-agent commentedon Oct 24, 2026
Thanks for the detailed write-up, @thtesche!
What you're seeing is how
compaction.bufferis meant to work. Per the compaction docs,bufferis the number of tokens to keep free below the model's limit, and larger values start automatic compaction earlier. Sobuffer: 180904on a model with a 195,904-token input limit asks OpenCode to keep 180,904 tokens free. That leaves 15,000 tokens before compaction, which is what you're getting. Only a buffer at least as large as the whole window is ignored (#58313).To get the behaviour you expected (compaction at about 85% of the window), remove
bufferfrom your config so the default reserve applies (15% of the limit, at least 16k). Or set it to a small value like30000:{ "compaction": { "auto": true } }I've filed this as a feature request: OpenCode could validate or cap
compaction.bufferso that a value close to the window can't push the threshold down to a few thousand tokens, or at least warn about it. Maintainers will consider it.Related: