Repository navigation
Description
Summary
In OpenCode V2, shell commands executed directly through a session can persist approximately 1 MiB of output and inject it into the next model request without applying the normal 50 KiB tool-output limit. The oversized request can exceed the model context window, fail as provider.unknown, and leave the session unable to continue automatically.
Environment
- opencode version:
opencode2 v0.0.0-beta-18230 - OS: macOS Darwin 25.5.0, arm64
- Terminal: Ghostty (
TERM=xterm-256color,COLORTERM=truecolor) - Shell:
/bin/zsh - Install/channel: V2 beta
- Active plugins: Not relevant; reproducible through the built-in session shell path.
Reproduction
- Start a V2 session with a model whose remaining context budget is smaller than approximately 1 MiB of shell output.
- Execute a user shell command through the session that writes more than 1 MiB, such as a failing typecheck with extensive diagnostics.
- Submit another prompt so OpenCode assembles a model request containing the persisted shell message.
- Observe the provider reject the oversized request and the session fail instead of recovering automatically.
Expected Behavior
Session shell output should obey the same bounded preview behavior as normal shell tool output. The model should receive a compact preview, with full output retained separately when appropriate, and the session should remain usable.
Actual Behavior
- Normal tool output defaults to 50 KiB in
packages/core/src/tool-output.ts. - The session shell path captures up to 1 MiB through
SHELL_MAX_CAPTURE_BYTESinpackages/core/src/session.ts. packages/core/src/session/runner/to-llm-message.tsinserts the entire persisted shell output directly into the model-facing message.- Automatic compaction considers token usage reported by the preceding model response, which does not include subsequently added shell output.
- The resulting provider failure can surface as
provider.unknown, bypassing context-overflow recovery.
Additional Context
Observed in a production session where a bun typecheck shell command persisted 1,048,701 characters despite output metadata reporting truncated: true. The session required manual compaction to recover.
The smallest likely fix is to apply the existing 50 KiB tool-output cap to session shell capture, rather than introducing request-wide token estimation solely to compensate for this inconsistent limit. Regression coverage should verify that a large session shell command cannot create an oversized model-facing shell message.
Activity
argszero commentedon Aug 26, 2026
I'd like to work on this. The suggested minimal fix — applying the existing 50 KiB tool-output cap from
packages/core/src/tool-output.tsto session shell capture inpackages/core/src/session.ts(SHELL_MAX_CAPTURE_BYTES), soto-llm-message.tsnever inserts an oversized shell message — matches the code paths described here. I'll add regression coverage verifying a large session shell command cannot produce an oversized model-facing message.argszero commentedon Aug 26, 2026
Standing down — I see PR #45136 (and #45109) already address this. I'll defer to those.
lab1207 commentedon Sep 29, 2026
Taking this one - opened fix in #52024. Note: on current master the capture-side names from the issue are gone and V2 shell is unimplemented, so I bounded the model-facing interpolation (50 KiB preview, history intact) with a regression test.
xxwtiancai commentedon Oct 25, 2026
Confirmed on current
dev(e0b6039e1): the session shell path still has no bounded preview.packages/core/src/session/shell.tscaptures up to 1 MiB (shell.output(info.id, { limit: 1024 * 1024 })),ShellResult.userNotificationembeds the full captured output in the synthetic message, and both replay paths into-llm-message.ts(syntheticandshellcases) insert it whole — the 50 KiB cap fromtool-output.tsnever applies here.The previous attempts all fell to process, not review: #45136/#45942 to the guideline window, #50660 to cleanup, and #51890 only because it targeted the retiring
v2branch. If nobody is on it, I'd like to take this. Planned shape: keep the 1 MiB capture for display, but bound what reaches the model (at synthetic-message construction or replay) to match tool-output behavior, with regression coverage insession-shell.test.ts.rekram1-node commentedon Oct 26, 2026
This is fixed on dev by ad9117b (fix(session): run user shells immediately in the background).
Output from shell commands you run yourself in a session now goes through the same limit as the shell tool (2,000 lines / 50 KiB, configurable via
tool_output) before the model sees it. The rest is saved to a file and the model gets a pointer to it.The 1 MiB capture is still there, but it's only the copy shown in the UI. That message is marked as background and isn't sent to the model, so seeing 1 MiB in the UI doesn't mean the model got it. If you still see oversized shell output reaching the model on a current build, let me know and I'll reopen.