Skip to content

core: session shell output bypasses tool limits and strands sessions #45099

Description

@kitlangton

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    2.0bugSomething isn't workingcoreAnything pertaining to core functionality of the application (opencode server stuff)

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions