Skip to content

Tool output truncation loses the most important content (background_output synthesis drop, read offset ignored, grep head_limit bypassed) #33650

Closed as not planned

Description

@junbong-yu

Summary

Multiple tools that return large content truncate their output in ways that consistently lose the most important part. The common thread: when serialized output exceeds an internal buffer/byte threshold (~256 KB), the truncation falls back to showing the beginning and dropping the end — but the end is where the answer lives (subagent synthesis, later file lines, final grep matches).

Reproduction

All observed against opencode on macOS (darwin), session running an explore-type subagent analyzing a large Rust workspace (~2500-line files, subagent histories of 15-25 messages).

Symptom 1 — background_output never returns the subagent's final synthesis

After an explore subagent completes (full conversation: thinking + tool invocations + final synthesis message), attempts to retrieve its result via background_output consistently drop the synthesis.

  • background_output(task_id="...", full_session=true) → returns messages [1..N-1] with Has more: false, but the last message is cut with ...(output truncated for display). The final synthesis message (index N) is the one truncated.
  • Tried combinations: message_limit=5, message_limit=15, include_tool_results=true|false, thinking_max_chars=12000 — none recover the tail.
  • The mid-conversation tool results and thinking frames all display; only the final conclusion is lost.
  • Workaround attempted: since_message_id — but there is no reliable way to know the last message id without first seeing it.

Impact: Delegation to background subagents becomes pointless if the synthesis can't be retrieved. Forces re-exploring the same topic manually, doubling token spend.

Symptom 2 — read ignores offset when limit is large

Reading the same file with increasing offsets:

offset limit expected start line actual start line
small large ~offset 1 (offset ignored)
large small ~offset offset (correct)
large large ~offset 1 (offset ignored)
  • When offset + limit exceeds a threshold, the tool appears to reset to line 1 and return from there, still applying limit to the truncated slice.
  • Small limits (e.g. 80 lines) respect offset; large limits (e.g. 200-320) do not.
  • Same file, reproducible across calls.

Impact: Reading deep into a large file is impossible — the tool silently returns the head again, hiding the requested range. The user/agent cannot reach lines past a certain depth without splitting into many tiny reads (and those reads don't always overlap cleanly).

Symptom 3 — grep head_limit is overridden by byte threshold

Setting head_limit to a small value still returns matches up to the byte cap, followed by Output truncated due to size limit — the same content size comes back regardless of the head_limit value, suggesting the 256 KB byte cap fires first and the head_limit parameter is non-functional.

Impact: Cannot bound grep output deterministically; downstream consumers expecting ≤ N entries still receive up-to-256-KB payloads.

Symptom 4 — read truncates silently with no end-marker

The tool sometimes returns content that was truncated (fewer lines than requested, no ...(output truncated for display) marker at the end). The caller has no way to distinguish "file ended" from "output was cut mid-stream".

Impact: Either unnecessary follow-up reads (file actually ended) or missing tail content (truncation mistaken for EOF).

Expected behaviour

  1. background_output should prioritise returning the final message of a subagent session — that is the synthesised answer the caller wants. If buffer limits are unavoidable, truncate the in-conversation tool results (verbose, recoverable via re-read) rather than the synthesis.
  2. read should honour offset regardless of limit. If the underlying buffer cannot hold limit lines from offset, it should clamp limit (and signal via a truncation marker), not reset offset.
  3. grep head_limit should bound the entry count before any byte cap, so callers get a deterministic upper bound on output size.
  4. All truncated tool outputs should end with a clearly visible marker so callers can decide whether to follow up.

Environment

  • OS: macOS (darwin)
  • Architecture: observed while running explore subagents over a large repo
  • Versions: current opencode (subagent task tooling)

Severity

High for symptom 1 (delegation value is broken) and symptom 2 (large-file navigation is broken). Medium for symptoms 3 and 4.

Activity

  1. github-actions commented on Jun 24, 2026

    @github-actions
    Contributor

    This issue might be a duplicate of existing issues. Please check:

  2. github-actions commented on Aug 24, 2026

    @github-actions
    Contributor

    To stay organized issues are automatically closed after 60 days of no activity. If the issue is still relevant please open a new one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions