Skip to content

OpenCode agent: tool-call JSON in stdout breaks review and refine output #122

@beettlle

Description

@beettlle

Summary

When using the OpenCode agent, roborev shows raw tool-call JSON in review output and in refine (commit messages and stored responses) instead of only the final assistant text.

Root Cause

OpenCode: opencode run --format default writes tool-call objects like {"name":"read","arguments":{...}} to stdout. In a headless/piped setting, callers typically expect only the final assistant text.

Roborev: It treats all stdout from the agent as the review/fix output. That works for agents that emit only text (e.g. Claude Code with --output-format stream-json and custom parsing, Codex, etc.) but breaks when OpenCode interleaves tool-call JSON in the same stream.

So the underlying issue is OpenCode’s run format; roborev could add a workaround by filtering that JSON from the stream before using it as the agent result.

Who is affected

Anyone using roborev + OpenCode will see:

  • Tool-call JSON in the stored review output and in the UI
  • Tool-call JSON in refine’s commit messages and in the “Address review findings” responses stored by roborev refine

Proposed fix (roborev-side workaround)

  • In internal/agent/opencode.go, after reading stdout, run a helper that drops lines that look like OpenCode tool-call JSON (e.g. valid JSON with both name and arguments).
  • Use the filtered string as the agent output for both review and refine flows.

Scope: Small change (~40–60 lines: filter helper, wiring in Review(), and tests in a new internal/agent/opencode_test.go).

Out of scope: The “Agent made no changes” behavior in roborev refine when using OpenCode. That comes from git.IsWorkingTreeClean() after the run—roborev only checks whether the worktree changed. If OpenCode’s run never runs (or doesn’t successfully run) edit tools in non-TTY mode, there will be no git changes regardless of stdout filtering. Fixing or clarifying that would need changes on the OpenCode side (e.g. whether opencode run executes tools in headless mode and with the right permissions).

Proper fix (OpenCode)

A robust fix would be in OpenCode: e.g. a --format or mode that omits tool-call events on stdout when stdout is not a TTY, or that sends them to stderr / a separate stream, so headless consumers only see the final text.

Metadata

Metadata

Assignees

No one assigned

    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