Skip to content

OpenCode foreground subagents keep the parent run active, so the thread reads as "Thinking" with no waiting state #17767

Open

Description

@Marker-bit

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Area

apps/web

Steps to reproduce

  1. Use the OpenCode provider (OpenCode v2 / opencode2, opencode v2.0.22).
  2. In a thread, ask the agent to launch several independent subagents such that the model calls the native subagent tool without background: true (the default; e.g. parallel research tasks whose results the parent needs before continuing).
  3. Watch the parent thread while the children run.

Expected behavior

The parent should be visibly parked "waiting on subagents" (the same presentation used for background subagents / delegate_task children), and the composer should be usable, even if the run is technically still open. At minimum the live activity row should say something like "Waiting on subagents" rather than "Thinking".

Actual behavior

The parent shows a live Thinking row and the composer stays in the busy/waiting-for-agent state for the entire duration of the children. The pending-background roster ("Waiting on N subagents") never appears, so there is no way to tell "blocked on subagents" from "model is generating".

The pending-background roster is gated on run settlement, and the web client mirrors it, so while the parent run is running the roster is dropped and the generic Thinking row is appended instead:

packages/shared/src/orchestrationV2PendingBackgroundWork.ts

const hasActiveRun = input.runs?.some(
  (run) => run.status === "preparing" || run.status === "starting" || run.status === "running",
) ?? false;
if (hasActiveRun) return [];

apps/web/src/components/ChatView.tsx

const isWorking = phase === "running" || isSendBusy || isConnecting || isCompacting || runlessWorkStartedAt !== null;
const activeBackgroundTasks = !isWorking && activeThread ? pendingBackgroundTasks : [];

apps/web/src/components/chat/MessagesTimeline.logic.ts

if (input.isWorking && ...) {
  nextRows.push({ kind: "thinking", id: LIVE_ACTIVITY_ROW_ID, createdAt: input.activeTurnStartedAt ?? null });
}

For OpenCode, a subagent call is foreground unless the model passes background: true, so the parent turn cannot end until the child returns:

packages/provider-opencode/src/server/v2/adapter.ts

// startCall default
background: false,
...
// session.tool.called
call.background = input["background"] === true;
...
// finishTurn() only runs when OpenCode's execution ends; a foreground
// subagent's tool call does not return until the child completes.

OpenCode v2's own tool description confirms the default (packages/core/src/tool/plugin/subagent.ts, anomalyco/opencode@v2): "Foreground (default) runs the subagent to completion and returns its final response."

Impact

Major degradation or frequent failure. For long foreground subagent fleets (minutes), the thread looks hung, the composer stays busy, and users cannot easily send a follow-up or tell what is happening.

Version or commit

0.0.46-nightly.20261010.2908 (commit 3e94afa7c267)

Environment

macOS (arm64), T3 Code Nightly desktop app; provider opencode (binary opencode2), model opencode-go/deepseek-v4.1-flash, OpenCode v2.0.22.

Logs or stack traces

Projection rows for the reproduced thread (statev2.sqlite):

  • parent run run:thread:92e8c040-…:ordinal:1 → status running
  • three subagents, origin: provider_native, provider: opencode, status: running, each bound to the same parent run_id

i.e. the subagents that would populate the roster are running while the parent run is still active — exactly the state the roster gate drops.

SELECT origin, status, count(*) FROM orchestration_v2_projection_subagents GROUP BY origin, status;
-- provider_native | running | 2
-- provider_native | completed | 1

Screenshots, recordings, or supporting files

Parent OpenCode thread: a "3 subagents / 3 working" group above the message "Time to parallelize. Dispatching three subagents." with a live "Thinking" row below it

Workaround

  • Have the agent launch subagents with background: true (OpenCode v2 supports this as a normal per-call option), or use T3's delegate_task in the default mode: "async"; then the parent turn ends and the parked "Waiting on subagents" view appears.
  • Otherwise use Stop to release the parent.

Activity

  1. Marker-bit commented on Oct 12, 2026

    @Marker-bit
    Author

    This is a proposal for product behavior, so per CONTRIBUTING it belongs in Ideas: #18499. The direction and scope question is there; this issue tracks the underlying bug (#17767).

  2. added
    needs more infoInitial triage showed no bug. Awaiting more info
    and removed
    needs more infoInitial triage showed no bug. Awaiting more info
    on Oct 21, 2026
  3. caitlon commented on Oct 31, 2026

    @caitlon

    Also reproduces with the Claude provider (Opus 5.5). While the parent waits on foreground subagents (4 subagents, 2 working, 2 done), the timeline shows a bare Thinking row. Unlike a real thinking row it cannot be expanded, so there is no way to tell that the model is only waiting. With Follow-up behavior set to Queue, a message sent meanwhile sits in the queue unless you press Steer.

  4. supermicro-danem commented on Nov 2, 2026

    @supermicro-danem

    Additional Claude Agent provider evidence on T3 Code 0.1.6, Linux x86_64 server, model claude-opus-5-5 (high effort), installed Claude Code CLI 2.1.316. Adding here per the maintainer request in #20369 to report non-OpenCode occurrences.

    The user reports that T3 has remained on Thinking after a turn appeared finished in recent releases. I inspected the matching long-lived thread's provider event logs and read-only statev2.sqlite projections on 2026-11-02 around 06:39–06:43 UTC. I did not inspect the user's browser or run a fresh reproduction, so the displayed Thinking state is user-reported; the following runtime state is observed.

    Current occurrence: live foreground Claude subagent

    • Run ordinal 112 started at 06:34:01.497Z, with run, attempt, and provider turn still running, completion time null.
    • Last root assistant message at 06:34:06.868Z says it is verifying a head and starting the next review round (project details omitted).
    • At 06:34:53.567Z, the SDK emitted system/task_started for task a3513fa5448c25bce, task_type: local_agent, is_backgrounded: false. The enclosing tool is Agent, tool-use ID toolu_01Ti1sWGACKTacRchhZQCayT.
    • The subagent turn item remained running, with an update at 06:39:39.990Z. Its provider frames contain actual tool results at 06:39:40.241Z.
    • tool_progress heartbeats for the enclosing Agent tool continued at 06:39:53.562Z, 06:40:23.566Z, and 06:40:53.562Z, reporting elapsed times 300, 330, and 360 seconds.
    • No root terminal result for this run was present at inspection. This particular run is doing real foreground child work, rather than having already emitted a terminal result that T3 lost.

    Completed-turn control

    The thread has 112 runs: 104 completed, 7 cancelled, and the one current running run. Across the retained provider logs, I matched all 104 completed runs to root result frames with terminal_reason: completed within each run's start/completion interval. The largest provider-result → persisted-run-completion interval was 1.085 seconds. Recent examples:

    • Run 110: provider result 06:03:46.348Z, run completed 06:03:46.389Z.
    • Run 111: provider result 06:16:44.137Z, run completed 06:16:44.185Z.

    This supports extending the foreground-subagent status problem to Claude: the parent can look finished to the user while a foreground Agent call keeps its run open. A status such as Waiting on subagent, with child progress, would distinguish this from model generation or a hung turn.

    This evidence does not establish the lost-terminal-transition bug in #15197, a client subscription failure such as #14046, or a regression introduced by a particular release. A separate client-side stale view remains possible because the browser state was not captured. No Stop/restart or modifications to the affected thread were performed. Raw logs are not attached because they contain private project data; the fields above are restricted to runtime metadata and correlation IDs.

  5. supermicro-danem commented on Nov 2, 2026

    @supermicro-danem

    Additional impact confirmed by the user: pending messages do not send and remain in the queue while this behavior persists. This is therefore more than a misleading activity label: the user cannot get queued follow-up instructions delivered during the wait.

    This queue behavior is user-reported; I have not independently traced a queued message through dispatch. The earlier runtime evidence showed an active foreground Claude Agent call. Please include queued-message delivery in the scope of this report: a clearer waiting label alone would not address the user's inability to deliver pending instructions. It would help to distinguish whether queued follow-ups intentionally wait for the foreground run to end, or remain blocked after the run actually completes.

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