Skip to content

Code Mode: model writes tool call markup as plain text — call is dropped and the step ends idle #57344

Open

Description

@untitledds

Summary

In Code Mode, the model intermittently writes its tool call as plain
assistant text
(Anthropic-style <invoke> / <parameter name="…"> markup)
instead of emitting a structured tool call. OpenCode does not parse or execute
that text: no tool part is created, the step finishes with idle, and the
intended tool call is silently lost. The session then stalls and only proceeds
when another turn is issued.

Environment

  • opencode version: 2.0.32 (latest release, Oct 16 2026)
  • OS: Linux 6.18.54.1-microsoft-standard-WSL2 x86_64 GNU/Linux
  • Agent: build, Code Mode
  • Provider/model: opencode/big-pickle, variant default
  • Plugins: none (no opencode.json / .opencode/opencode.json)

Reproduction

  1. Run a long multi-step build task in Code Mode.
  2. Observe the last assistant message of a step. Instead of a structured tool
    call it contains prose followed by raw call markup, and no tool part.

Concrete transcript from session ses_ea9cd281cffe9pJbrBsyPQSpup (read-only
query against ~/.local/share/opencode/opencode.db):

10:50:33  assistant  [text, TOOL:grep:completed, TOOL:shell:completed]   <- real calls, fine
10:50:36  assistant  [text*MK*]                                          <- only text, NO tool part
10:50:39  idle                                                           <- step ends
10:52:03  user                                                            <- new turn needed to continue

The text*MK* message body looks like:

Let me look at `get_deployed_stems` and `_refresh_deployed_flag` — this is the core of the bug.
<parameter name="path">/root/zorq-sigma-bridge/app/…

The read it asks for never runs in that step; the same read is repeated and
executed only in the following turn.

Expected Behavior

The intended tool call should not be dropped. Either:

  • parse the text-form call and execute it (a text fallback parser), or
  • immediately re-prompt the model to emit a real tool call instead of ending
    the step and leaving the session idle,

and in all cases surface why the step ended.

Actual Behavior

No tool part is created, the step ends with idle, the call is lost, and the
session needs an extra turn to move on — effectively stalling long agent runs.

Occurrences (text parts containing call markup, excluding transcripts where the
agent itself quotes the markup while discussing it):

session text-parts with markup window
ses_eaea51780ffex7kzsnKf1s1lak 7 19 Oct 23:02
ses_eaa3947b1ffeexwKdX3g4RKT3t (fork of the above) 36 19 Oct 23:02 → 20 Oct 01:04
ses_ea9cd281cffe9pJbrBsyPQSpup (new session) 6 20 Oct 10:40 → 10:54

9 other sessions on the same provider/model/version never produced it, so it
is intermittent and session-dependent.

Additional Context

  • Prompt-level workarounds do not help. A repo AGENTS.md rule was added
    that forbids emitting this markup (initially listing the forbidden tokens as
    examples, then rewritten to avoid mentioning them at all). The rules were
    removed from the instructions before the last reproduction: session
    ses_ea9cd281… was created at 01:05 on 20 Oct, after the instruction files
    were already clean, and still reproduced at 10:40–10:54. Its recorded
    instruction blob contains no markup tokens.
  • Not a skills/plugins issue. All installed skill files were scanned for
    <invoke / <parameter name= / antml: / function_calls — no matches;
    no plugins are configured.
  • The markup always appears in the final assistant message of a step,
    immediately before the idle message, and is interleaved with normal
    structured tool calls earlier in the same step.
  • A separate issue in the same environment is a recurring
    AI.Error: Rate limit exceeded (provider.quota, FreeUsageLimitError) on
    the free tier; it is independent of the markup problem and is not
    contributing to the reports above.

Related

Activity

  1. opencode-agent commented on Oct 20, 2026

    @opencode-agent
    Contributor

    Thanks for the detailed report and the database evidence, @untitledds!

    What happens here is that Big Pickle sometimes writes its tool call as plain <invoke> / <parameter> text instead of making a real tool call. OpenCode doesn't add that markup itself: neither the Code Mode instructions nor the session history contain it. The response therefore arrives as text only with a normal stop. OpenCode currently treats a text-only reply as the end of the turn, and nothing in 2.x converts tool calls written as text into real ones.

    What you're asking for is new behaviour: when a reply contains tool-call markup but no real tool call, either run it through a text fallback parser or prompt the model again, and show why the step ended. I've marked this as a feature request for the maintainers to consider.

    Related issues:

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

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