Skip to content

[Bug]: Async pi-subagents runs never show in the subagent UI on Pi threads #17363

Description

@marianomacri

Before submitting

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

Area

apps/server. The Pi provider adapter (packages/provider-pi/src/server/adapter.ts), observed in the desktop app.

Steps to reproduce

  1. Install the pi-subagents extension for Pi and start a Pi thread in T3 Code.
  2. Ask the agent to call the subagent tool for one agent with async: true, for example { "agent": "reviewer", "task": "Review the diff", "async": true }.
  3. Watch the Agents panel and the thread timeline while the child runs and after it finishes.

Expected behavior

The async child shows as a running subagent of the run that launched it, the way Claude background agents do and the way pi-subagents' synchronous mode already does. It settles as completed or failed when pi-subagents reports that the child finished.

Actual behavior

Nothing appears in the subagent UI. The subagent tool row turns completed as soon as the launch returns, while the child keeps running. In the thread where I hit this, a review child ran for about four minutes with no sign in T3 Code that anything was running or that it finished.

The adapter's subagent support (emitSubagentTasks in adapter.ts) reads only result.details.results[], the shape of Pi's synchronous example extension. pi-subagents' async mode reports differently:

  • At launch, the subagent tool returns details = { mode: "single", asyncId, asyncDir, results: [] }, so the adapter emits no subagent.
  • When the child finishes, pi-subagents sends a custom message with customType: "subagent-notify". Its details.runs lists each run's agent and status, and its text names each run's directory. The message arrives between turns, before the wake turn starts, and handleSessionEvent ignores non-assistant message_end events.

Impact

Minor bug or occasional failure

Version or commit

Observed on desktop 0.0.46-nightly.20261008.2833. The same code is on main at d81afa0a6.

Environment

macOS 27.0, Pi 1.1.0 (@earendil-works/pi-coding-agent), pi-subagents 0.76.1, Pi provider with openai-codex/gpt-6.1-sol as the parent model.

Logs or stack traces

# Inbound `pi --mode rpc` frames, in order, from a live run with only pi-subagents loaded.
# T3 Code's Pi replay recorder normalized ids and paths. "..." marks trimmed fields.
{"type":"tool_execution_end","toolName":"subagent","isError":false,"result":{"content":[{"type":"text","text":"Run fan-out: 1/64 used, 63 remaining\nAsync: echo [00000000-0000-4000-8000-000000000005]\n\nThe async run is deta ..."}],"details":{"mode":"single","runId":"00000000-0000-4000-8000-000000000005","results":[],"asyncId":"00000000-0000-4000-8000-000000000005","asyncDir":"/tmp/pi-rec-tmp/pi-subagents-uid-501/async-subagent-runs/00000000-0000-4000-8000-000000000005","...":"..."}}}
{"type":"agent_settled","aborted":false}
{"type":"message_end","message":{"role":"custom","customType":"subagent-notify","content":"Background task completed: **echo**\n\necho:\nECHO_DONE\n\nRetention-managed async directory: /tmp/pi-rec-tmp/pi-subagents-uid-501/async-subagent-runs/00000000-0000-4000-8000-000000000005\n\n...","display":false,"details":{"runs":[{"agent":"echo","status":"completed"}]}}}
{"type":"agent_start"}

Workaround

Ask the agent for subagent({ action: "status" }), or read the run's result from pi-subagents' async directory. Once the wake turn runs (#15589, fixed by #17214), the parent model also sees the result, but T3 Code's subagent UI still shows nothing.

I have a fix with a recorded replay fixture and will link the PR here.

Activity

  1. kushaldotdev commented on Oct 9, 2026

    @kushaldotdev

    Additional confirmation, and one scope note.

    With #17214 merged (the first nightly after the merge is 0.0.46-nightly.20261008.2849), the wake no longer kills the Pi session, but the runs are still invisible: the adapter continues to require the synchronous shape (toolName === "subagent" plus details.results[] with agent and task), while an async launch returns

    details: { mode: "single", runId, toolCallId, asyncId, asyncDir, results: [] }
    

    so emitSubagentTasks returns without emitting anything (pi-subagents 0.76.1, src/runs/foreground/subagent-executor.js).

    Also worth tracking separately: workflow, chain and parallel launches are outside #17393's scope, so they will still show nothing after it lands. Filed as a follow-up with the widget-snapshot data source that already carries that tree: #17564

  2. freezscholte commented on Oct 26, 2026

    @freezscholte

    Still reproducible on pi-subagents 0.83.0 (released 2026-10-26).

    Repro on a Pi thread in T3 Code:

    1. Ask the Pi agent to launch a single pi-subagents child with async: true that counts 1→200, one bash call per number.
    2. The child runs and finishes, but it never appears in T3's subagent UI. The thread shows only the parent's launch tool call.
    3. Steering still works: a message sent to the thread at count 6 was forwarded by the parent with the steer action, and the child stopped at 10 and answered as instructed. The child's session file under ~/.pi/agent/sessions/ confirms it.

    For comparison, the same test with a foreground child: the steer stays queued behind the blocked parent turn and never reaches the child, which counts to 200. That's expected, but it means background is the only steerable mode, and it's also the one T3 doesn't show.

  3. giovanecesar commented on Oct 30, 2026

    @giovanecesar

    Still reproducible on T3 Code 0.1.5 (desktop app, local server) with pi-subagents 0.84.0 and Pi 1.4.0 on macOS arm64.

    With asyncByDefault: true in the pi-subagents config, a subagent launch that omits async runs in the background. The tool returns Detached right away. The children ran for several minutes and completed. None of them appeared in the Agents panel. The thread's orchestration_v2_projection_subagents table has 0 rows.

    emitSubagentTasks in packages/provider-pi/src/server/adapter.ts still reads only details.results[], and main has not changed this since 0.1.5.

    Workaround: set asyncByDefault: false so launches run in the foreground and render. The parent then waits for each child.


    Produced by Claude Code (Opus 5.5) via t3 triage.

  4. StiensWout commented on Nov 9, 2026

    @StiensWout
    Contributor

    Note

    🤖 GPT 6.1 Sol responding on behalf of StiensWout

    The maintainer closed our independent #33590 and is retaining our earlier #23786, which covers single, workflow, chain and parallel native Pi subagent lifecycles with regression and runtime evidence. Our new PR preserves additional original-turn, pause/terminal, late-member and bounded-retention cases plus running/incremental/completed client captures. Once a build contains the retained fix, could you retry the reported async launches and close the corresponding issue if rows appear and settle correctly after that fix lands? General extension background-job lifetime from #24187 remains separate.

  5. thanhpp commented on Nov 13, 2026

    @thanhpp

    Additional runtime confirmation on T3 Code 0.1.8, Pi 1.5.2, and pi-subagents 0.88.1:

    Two real native async subagent discovery runs were correlated to their T3 parent through provider thread mapping. Both children exited 0. T3 persisted both launches as completed dynamic_tool calls, but the parent had zero orchestration_v2_projection_subagents rows and zero subagent-named events; the run IDs were absent from those child projections/events. The UI was not inspected. Expected: track each native async child through its terminal state; actual: no child projection.

    The installed 0.1.8 executable and checkout bf469bb19669671d0df2efda74ed73867a7137c0 show the same likely seam: async launch returns details.results: [] plus runId/asyncId, but emitSubagentTasks reads only details.results (packages/provider-pi/src/server/adapter.ts:1258-1277,1305-1328). Foreground native results already have projection; the synthetic adapter test covers foreground-shaped results only. Native Pi children are distinct from T3 delegate_task, which uses an app-owned thread path.

    Proposed minimal reproduction (not the exact discovery-run prompts used above): in a T3 Pi session, call subagent({agent: "scout", task: "Return OK.", async: true}), wait for native completion, and compare the child projection with the completed tool call.

    Note

    🤖 AI assistant responding on behalf of thanhpp

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