Skip to content

parallel streamed tool calls with empty arguments {} hang in "Writing command" (shell) or "delegating" ("General Subagent - Subagent") #58481

Closed as not planned

Description

@ashemedai

Description

When a model via litellm-proxy/gemini-4-argon emits multiple tool calls in one assistant turn (for example, shell + subagent or multiple subagent calls with escaped quotes), the streamed arguments can arrive at OpenCode as an empty object {} during or after tool-call stream assembly. This happens before permission evaluation and leaves tool calls stuck in "Writing command" or "delegating" with {} arguments. Instead of immediately failing schema validation (required: ["agent", "description", "prompt"]) and returning a tool error to the model so it can retry, OpenCode may fall back to display defaults ("General Subagent - Subagent").

Plugins

No response

OpenCode version

2.1.2

Steps to reproduce

  1. Configure a provider using litellm-proxy with a Gemini model (gemini-4-argon).
  2. Prompt the agent to emit multiple tool calls in one assistant turn, such as shell + subagent or multiple subagent calls with escaped quotes in their prompts.
  3. Observe that this happens before permission evaluation, during or after tool-call stream assembly; the serialized arguments may be {} (for example, [Assistant tool call]: subagent({})).
  4. Observe the TUI: tool calls remain stuck in "Writing command" or delegating with labels such as General Subagent - Subagent, until manually interrupted.

Expected Behavior

If a subagent tool call finishes streaming with missing required fields (agent, description, prompt — e.g. {}), OpenCode should immediately reject the tool call with a validation error (e.g. Invalid arguments for tool "subagent": missing required fields "agent", "description", "prompt") rather than attempting to spawn/delegate to a fallback "general" subagent or hanging in "delegating".

Actual Behavior

The UI displays General Subagent - Subagent waiting in delegating indefinitely, requiring manual user interruption (Esc / cancel).

Workarounds found

  • Adding an explicit {"action": "subagent", "resource": "*", "effect": "deny"} + allowlist for named subagents in opencode.json.
  • Instructing the model in AGENTS.md to emit at most 1 subagent call per turn, never combine subagent with other tool calls in the same turn, and avoid escaped quotes or code fences inside subagent prompts.

Screenshot

No response

Operating System

macOS

Terminal

Ghostty

Activity

  1. opencode-agent commented on Oct 23, 2026

    @opencode-agent
    Contributor

    Thanks for the report. I couldn't reproduce the hang on 2.1.2. I set up an OpenAI-compatible provider pointing at a mock server that streams a shell call and a subagent call in one assistant turn (with escaped quotes in the prompt), and tried several ways of streaming them:

    • Both calls in one chunk (index 0 and 1), or with no index: both ran and completed.
    • Separate chunks that both use index: 0 with different ids: the second call's arguments were appended to the first. The subagent call was lost, and the first call showed {} and failed straight away with a JSON parse error, which went back to the model. That may be where your {} comes from, but it didn't hang.
    • The stream ending without a finish_reason: the call failed straight away with "stream ended without finish_reason".

    In every case the tool calls settled within a second. None stayed in "Writing command" or "delegating". Related issues, most likely first:

    These would help:

    1. A raw capture of the streaming response LiteLLM sends for one of these turns (the data: chunks with tool_calls), especially the index, id and finish_reason fields, and whether the stream actually ends.
    2. The OpenCode logs from such a session (e.g. run with --print-logs --log-level debug).
    3. The LiteLLM version you're using.
  2. opencode-agent commented on Oct 26, 2026

    @opencode-agent
    Contributor

    Closing this for now, since we haven't heard back. I couldn't reproduce the hang on 2.1.2. With a mock LiteLLM-style server streaming parallel shell + subagent calls, every tool call settled within a second: it either ran or failed straight away with an error the model could see. None stayed stuck in "Writing command" or "delegating". Without a capture of what LiteLLM actually streams, there's no clear way to dig further.

    If it still happens, please reopen or comment here with:

    • the raw data: chunks LiteLLM sends for such a turn (especially index, id, finish_reason, and whether the stream ends);
    • logs from --print-logs --log-level debug;
    • your LiteLLM version.

    A stream that stops partway through a tool call without ending is tracked in #51291, which may be the same problem. Thanks for the report!

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