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
Compaction can reuse an oversized request and leave only 1024 output tokens #62943
Compaction can reuse a request that its measured token count already ruled out, leaving only 1024 output tokens for the summary.
With no retained tail, withoutTail() returns the original request. deliver() rejects it using measured usage, then accepts the same object using a lower character estimate. fitOutput() still uses the measurement, so it cuts the summary's output allowance instead of using the existing text fallback.
OpenCode version
Observed on 2.2.5; reproduced on dev at 12a661ea40cd5863b271a89bb06b8a3ddb7ab5a0.
Steps to reproduce
Add this case beside the existing summaryFixture tests in packages/core/test/session-compaction.test.ts:
it.effect("summary keeps output room despite a low character estimate",()=>Effect.gen(function*(){constfixture=yield*summaryFixture([textUser("Latest question"),measured("Latest answer",summaryWindow-1024),])expect(yield*fixture.run()).toEqual({status: "completed"})expect(requests[0].maxTokens).toBe(summaryBuffer)}),)
Run bun run script/test.ts test/session-compaction.test.ts from packages/core.
Expected: the oversized measured request takes the text fallback, leaving the fixture's 25,000-token summary allowance. Actual: maxTokens is 1024. The synthetic usage count makes the disagreement deterministic without a live provider.
Related: #59951 also addresses this case within a broader context-budget rewrite.
Thanks for the precise report. I reproduced this with your unit test on the latest dev (7524e5f). Compaction completes, but the summary request is sent with maxTokens = 1024 instead of the fixture's 25000.
On the v2.2.5 tag the same test can't show it: the test model there has no output limit, so maxTokens is undefined. The code involved is the same in that release.
The cause is as you describe. With no retained tail, withoutTail() returns prepared.request itself. In deliver(), that request fails the measured check, then passes the character-estimate check as shrink.history. Because it is the same object, the measured size still reaches fitOutput(), which cuts the output allowance instead of taking the text fallback.
The script below adds your test, runs it against a checkout and restores the file. Related: #62944 (targeted fix) and #59951 (broader context-budget rewrite).
Reproduction script (repro.sh)
#!/usr/bin/env bash# Reproduces #62943: compaction reuses an oversized measured request and cuts the# summary's output allowance to 1024 tokens instead of taking the text fallback.# Usage: repro.sh <path to opencode checkout> (dependencies installed with `bun install`)set -euo pipefail
REPO="${1:-/workspace/repo}"cd"$REPO/packages/core"
TEST=test/session-compaction.test.ts
cp "$TEST" /tmp/session-compaction.test.ts.bak
trap'cp /tmp/session-compaction.test.ts.bak "$TEST"' EXIT
cat >>"$TEST"<<'EOF'it.effect("repro #62943: summary keeps output room despite a low character estimate", () => Effect.gen(function* () { const fixture = yield* summaryFixture([ textUser("Latest question"), measured("Latest answer", summaryWindow - 1024), ]) expect(yield* fixture.run()).toEqual({ status: "completed" }) console.log("REPRO maxTokens =", requests[0].maxTokens, "expected summaryBuffer =", summaryBuffer) expect(requests[0].maxTokens).toBe(summaryBuffer) }),)EOF
bun run script/test.ts "$TEST" -t "repro #62943"2>&1| grep -E "REPRO|pass|fail|Expected|Received|error"| head -20
Activity
opencodejr commentedon Nov 9, 2026
Thanks for the precise report. I reproduced this with your unit test on the latest
dev(7524e5f). Compaction completes, but the summary request is sent withmaxTokens= 1024 instead of the fixture's 25000.On the
v2.2.5tag the same test can't show it: the test model there has no output limit, somaxTokensisundefined. The code involved is the same in that release.The cause is as you describe. With no retained tail,
withoutTail()returnsprepared.requestitself. Indeliver(), that request fails the measured check, then passes the character-estimate check asshrink.history. Because it is the same object, the measured size still reachesfitOutput(), which cuts the output allowance instead of taking the text fallback.The script below adds your test, runs it against a checkout and restores the file. Related: #62944 (targeted fix) and #59951 (broader context-budget rewrite).
Reproduction script (repro.sh)
Run it:
bash repro.sh