You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
V2: compaction fires on first request / loops when compaction.buffer >= model context limit #56783
With compaction.buffer set to a value greater than or equal to the model's context limit, V2 starts automatic compaction on the very first request and re-triggers it on every turn. This emits meaningless structured summaries at session start and sometimes surfaces an internal Session.StepFailedError: Nothing to compact yet.
Environment
opencode v2.0.32 (Linux x64; also confirmed config is read by V1 1.19.0)
Start a V2 session (any directory with an AGENTS.md).
Send a single first message.
Observe the message stream: a compaction message is created immediately after the user message (reason: "auto"), summarizing an empty history, and repeats every 1-2 turns.
Startup log line:
ERROR "Failed to drain Session" cause="Session.StepFailedError: Nothing to compact yet
at SessionRunner.runStep
at SessionRunner.drain
at ServerProcess.start"
Expected
An oversized buffer should be clamped to < context limit (or rejected with a clear warning at config load).
Compaction should not run when there is no older history to compact.
The internal StepFailedError should not surface as a user-facing failure at server start.
Actual
The trigger is estimated_tokens > context_limit - max(requested_output_tokens, buffer) (docs state buffer default = 10% of the limit). When buffer >= context_limit, the right-hand side is negative, so the condition is always true and compaction fires on every step, including the first. Because buffer is a single global value evaluated against each model's own limit, a value chosen for a large-context model (e.g. 400000 for a 1M model) breaks every smaller model.
Additional context / feature request
buffer and keep.tokens are only configurable globally in the top-level compaction block; per-model settings.compaction only accepts type: native|summary. This forces a single compaction policy across models with very different context windows. It would help to allow a per-model (or per-provider) buffer, and/or support an absolute "compact at N tokens" threshold, so users can pick different compaction points for a 200k model vs a 1M model without a global value that is unsafe for one of them.
Opened #56786 with a fix: the ceiling now keeps at most 90% of the window free, automatic compaction waits for an older assistant reply before it summarizes, and an automatic no-op is reported as skipped instead of a failed compaction. The new test fails on the parent commit (both cases complete) and passes with the fix; session-runner's existing buffer cases still pass.
An automatic compaction starts straight after each user message, including the very first one, and neither message gets a normal reply. The recording and screenshot below show it. The script below reproduces it with a simulated model, so the compaction summaries fail on a template check. What matters is that compaction runs at all on a near-empty session. I didn't see the exact Nothing to compact yet log line in this run, but compaction fired on every turn as you described.
As you worked out, the automatic trigger uses window - buffer with no lower limit. A buffer at or above the model's window makes compaction due on every turn. Until this is addressed, keeping buffer below the smallest context window you use avoids it.
The per-model buffer part of your request is tracked in #43703, and #56443 is an open PR for it.
recording.mp4
Reproduction script (drive.ts)
// Repro for anomalyco/opencode#56783: compaction.buffer >= model context limit// makes auto compaction fire on every turn, starting with the very first one.// Simulated model has limit.context = 128000; buffer = 600000.import{Effect}from"effect"import{Llm,OpenCodeDriver}from"opencode-drive"exportdefaultOpenCodeDriver.use({
...(process.env.OC_DEV ? {opencode: {dev: process.env.OC_DEV}} : {}),tui: {recording: true},project: {git: true,files: {"AGENTS.md": "# Project\n"}},config: {compaction: {auto: true,buffer: 600000,keep: {tokens: 15000}},}asany,},({ ui, llm })=>Effect.gen(function*(){// Enough responses for the reply and any (unexpected) compaction summaries.for(leti=0;i<6;i++)yield*llm.queue(Llm.text(`Reply number ${i+1}.`))yield*ui.submit("hello")yield*Effect.sleep(6000)yield*ui.screenshot("after-first-message")yield*ui.submit("second message")yield*Effect.sleep(6000)yield*ui.screenshot("after-second-message")}),)
Run it with opencode-drive: opencode-drive run ./drive.ts. It drives opencode from your PATH; set OC_DEV to the path of an OpenCode checkout to run that from source instead.
Activity
reynold-hu commentedon Oct 18, 2026
Opened #56786 with a fix: the ceiling now keeps at most 90% of the window free, automatic compaction waits for an older assistant reply before it summarizes, and an automatic no-op is reported as skipped instead of a failed compaction. The new test fails on the parent commit (both cases complete) and passes with the fix; session-runner's existing buffer cases still pass.
opencode-agent commentedon Oct 18, 2026
Thanks for the detailed report. I was able to reproduce this on v2.0.32, and it still happens on the latest
dev(da9d436).Steps:
"compaction": { "auto": true, "buffer": 600000, "keep": { "tokens": 15000 } }.hello, then a second message.An automatic compaction starts straight after each user message, including the very first one, and neither message gets a normal reply. The recording and screenshot below show it. The script below reproduces it with a simulated model, so the compaction summaries fail on a template check. What matters is that compaction runs at all on a near-empty session. I didn't see the exact
Nothing to compact yetlog line in this run, but compaction fired on every turn as you described.As you worked out, the automatic trigger uses
window - bufferwith no lower limit. A buffer at or above the model's window makes compaction due on every turn. Until this is addressed, keepingbufferbelow the smallest context window you use avoids it.The per-model
bufferpart of your request is tracked in #43703, and #56443 is an open PR for it.recording.mp4
Reproduction script (drive.ts)
Run it with opencode-drive:
opencode-drive run ./drive.ts. It drivesopencodefrom yourPATH; setOC_DEVto the path of an OpenCode checkout to run that from source instead.