anomalyco / anomalyco/opencode

core: session shell output bypasses tool limits and strands sessions

Open
#45,099 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

2.0 bug core
Dominant language
TypeScript
Stars
209k
Forks
27.5k
PR merge metrics
PR metrics pending

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

  1. Start a V2 session with a model whose remaining context budget is smaller than approximately 1 MiB of shell output.
  2. Execute a user shell command through the session that writes more than 1 MiB, such as a failing typecheck with extensive diagnostics.
  3. Submit another prompt so OpenCode assembles a model request containing the persisted shell message.
  4. 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_BYTES in packages/core/src/session.ts.
  • packages/core/src/session/runner/to-llm-message.ts inserts 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.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with packages/core/src/session.ts and compare its SHELL_MAX_CAPTURE_BYTES handling with the 50 KiB limit in packages/core/src/tool-output.ts. Then trace how packages/core/src/session/runner/to-llm-message.ts builds the model-facing message. Done means large session shell output is bounded consistently and regression coverage shows it cannot create an oversized request.

Written by the indexing model from the issue text.

Assessment

Tech stack
shell, typescript
Domain
backend, testing-qa
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
74/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.