anomalyco / anomalyco/opencode

Running subagent task is not navigable with fast tool-call providers

Open
#41,055 3 comments 1 reaction 1 assignee View on GitHub

@rekram1-node is already working on this.

Since Aug 7, 2026.

Dominant language
TypeScript
Stars
209k
Forks
27.5k
PR merge metrics
PR metrics pending

Description

Description

Running subagent tasks can become non-navigable when a custom LanguageModelV3 provider emits a complete client-side tool-call followed immediately by finish with reason tool-calls.

The task tool successfully creates the child session and runs the subagent, but clicking the task row does nothing while it is running. The session.child.first keybinding also does not enter the child session at that point. Other providers used in the same environment do not consistently reproduce the problem, while this provider timing reproduces it reliably.

This appears to be the metadata race previously reported in #20184. The tool execution calls ctx.metadata() with sessionId, but the processor can subsequently replace the pending state with a fresh running state before preserving that metadata. The TUI depends on state.metadata.sessionId to hydrate and navigate to the child session.

OpenCode version

1.18.10

I also inspected the 1.18.15 packages/opencode/src/session/processor.ts source. The previously proposed synchronous metadata buffering from #20210 does not appear to be present.

Steps to reproduce
  1. Use a custom LanguageModelV3 provider that returns a complete client-side task tool call without streaming tool-input-start / tool-input-delta / tool-input-end.
  2. The provider emits tool-call, then immediately emits finish with unified: "tool-calls", and closes the public model stream.
  3. Ask the model to launch a subagent that runs long enough to observe it.
  4. While the task row is running, click it or invoke session.child.first.
Actual behavior

Nothing happens. The running subagent session cannot be opened from the parent session.

Expected behavior

The task row and session.child.first should navigate to the child session as soon as the native task tool creates it and publishes metadata.sessionId.

Diagnostic evidence

After the task completes, exporting the parent session shows that the task part has valid metadata:

{
  "tool": "task",
  "state": {
    "status": "completed",
    "metadata": {
      "parentSessionId": "<parent-session>",
      "sessionId": "<child-session>",
      "model": {
        "providerID": "kiro",
        "modelID": "gpt-5.6-sol"
      }
    }
  }
}

Exporting the referenced child session succeeds and shows its parent ID plus the complete subagent message history. Therefore the child is created correctly; only live navigation/hydration fails.

Suspected cause

There is a race between detached client tool execution and processing the provider tool-call event:

  1. Native task.execute() starts and calls ctx.metadata({ metadata: { sessionId } }).
  2. The processor handles the provider tool-call and transitions the part from pending to running.
  3. That transition can replace the state without the metadata written in step 1.
  4. The TUI sees no state.metadata.sessionId, so its click handler is a no-op and the child is not available to session-tree navigation.

The provider emits a valid complete tool call; manufacturing incremental tool-input events would only be a timing workaround and would not eliminate the race.

Related work
  • #20184 reported the same pending-to-running metadata race.
  • #20210 proposed synchronously buffering and merging tool metadata, with an E2E regression test, but was closed without merge.
  • #14424 reported non-interactive Explore tasks with zero live tool calls.
  • #32773 covered loss of sessionId metadata during task completion/post-processing.

A robust fix should preserve or synchronously buffer tool metadata across pending-to-running transitions, independent of provider event timing.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.