Description
OpenCode V2 auto-compaction does not trigger for long Fable sessions that exceed the Zen/Fable request byte envelope before they approach the advertised token context limit.
Observed behavior:
- Model:
opencode/claude-fable-5#high through Zen.
- Catalog limit for Fable:
context=1000000, output=128000.
- V2 auto-compaction threshold:
context - max(output, buffer) = 872000 estimated tokens.
- A real long session translated to
646 LLM messages and about 1.31 MB of request JSON before system/tools.
Token.estimate(JSON.stringify({ system, messages, tools })) for messages-only shape was about 328000, below the 872000 threshold, so SessionCompaction.compactIfNeeded returned false.
- The provider then failed before any assistant output with HTTP 400:
Provider request failed with HTTP 400: {"type":"error","error":{"type":"invalid_request_error","message":"Error from provider (Console): Upstream request failed"}}
No session.next.compaction.* events were emitted. The turn became session.next.step.failed.2.
Why This Happens
The proactive path in packages/core/src/session/compaction.ts only checks estimated tokens against the advertised model context:
estimate({ system: input.request.system, messages: input.request.messages, tools: input.request.tools }) <=
context - Math.max(output, config.buffer)
The reactive overflow path in packages/core/src/session/runner/llm.ts only recovers when isContextOverflowFailure(...) is true. The Zen/Fable response body says only Upstream request failed, so packages/llm/src/provider-error.ts does not classify it as context overflow.
Synthetic Reproduction
Against https://opencode.ai/zen/v1/messages with model=claude-fable-5, max_tokens=1, and no private content:
700000 characters in one user text message succeeds.
1000000 characters in one user text message returns the same generic HTTP 400 Upstream request failed.
650 tiny alternating messages ending in a user turn succeeds, so this is not simply message count.
- Small Anthropic tool-use/tool-result shapes also succeed, so this is not obviously invalid tool-result ordering.
Expected Behavior
V2 should compact before sending requests that are too large for the route/provider envelope, or classify this generic Zen/Fable 400 as recoverable overflow when it happens before assistant output.
Possible fixes:
- Add a byte-envelope guard to
SessionCompaction.compactIfNeeded, perhaps route/model configurable and separate from token context.
- Add provider/route metadata for max request bytes or a lower effective compaction threshold for Zen/Fable.
- Improve Zen/Fable error classification so this generic request-size failure becomes
context-overflow when appropriate.
Related Issues
Related but not the same:
This report is specifically about V2 packages/core/src/session/compaction.ts using token context only while Zen/Fable appears to fail at a smaller request-byte envelope.
Description
OpenCode V2 auto-compaction does not trigger for long Fable sessions that exceed the Zen/Fable request byte envelope before they approach the advertised token context limit.
Observed behavior:
opencode/claude-fable-5#highthrough Zen.context=1000000,output=128000.context - max(output, buffer)=872000estimated tokens.646LLM messages and about1.31 MBof request JSON before system/tools.Token.estimate(JSON.stringify({ system, messages, tools }))for messages-only shape was about328000, below the872000threshold, soSessionCompaction.compactIfNeededreturned false.No
session.next.compaction.*events were emitted. The turn becamesession.next.step.failed.2.Why This Happens
The proactive path in
packages/core/src/session/compaction.tsonly checks estimated tokens against the advertised model context:The reactive overflow path in
packages/core/src/session/runner/llm.tsonly recovers whenisContextOverflowFailure(...)is true. The Zen/Fable response body says onlyUpstream request failed, sopackages/llm/src/provider-error.tsdoes not classify it as context overflow.Synthetic Reproduction
Against
https://opencode.ai/zen/v1/messageswithmodel=claude-fable-5,max_tokens=1, and no private content:700000characters in one user text message succeeds.1000000characters in one user text message returns the same generic HTTP 400Upstream request failed.650tiny alternating messages ending in a user turn succeeds, so this is not simply message count.Expected Behavior
V2 should compact before sending requests that are too large for the route/provider envelope, or classify this generic Zen/Fable 400 as recoverable overflow when it happens before assistant output.
Possible fixes:
SessionCompaction.compactIfNeeded, perhaps route/model configurable and separate from token context.context-overflowwhen appropriate.Related Issues
Related but not the same:
This report is specifically about V2
packages/core/src/session/compaction.tsusing token context only while Zen/Fable appears to fail at a smaller request-byte envelope.