Skip to content

Ad-hoc spawn_agent subagents are never announced with native subagent sessions: their output is dropped and the spawn tool call stays in_progress #592

Open

Description

@venmakli

Summary

With native subagent sessions negotiated, a subagent started by an ad-hoc spawn_agent call never gets subagent_spawned. The client receives no child session and no child output, and the spawnAgent tool call stays in_progress for the rest of the session. If the child needs an approval, the turn hangs.

This is the bug that #482 described and fixed for 1.7.0. That PR was closed without merge, and the code path is unchanged on current main (4583cb3978276c2b7ea87fcfa5ae66e1e9817f13). There is no open issue for it, so I am filing one with a reproduction on current releases.

Environment

  • codex-acp 2.1.1 with Codex CLI 0.159.3, and codex-acp 2.1.0 with Codex CLI 0.160.1. Both show the same behavior.
  • macOS (arm64), Node 22.23.1.
  • Model gpt-5.6-luna, reasoning_effort low, feature multi_agent enabled (the default).
  • Minimal ACP client over stdio. clientCapabilities: fs read/write false, terminal: false, elicitation: { form: {} }.
  • Native subagent sessions are negotiated through _meta.jetbrains.air: { version: 1, capabilities: ["nativeSubagentSessions"] }. The canonical clientCapabilities.subagents: {} does not reach the adapter: the bundled @agentclientprotocol/sdk 1.5.1 parses clientCapabilities with a strict z.object and drops the field. I can file that separately if useful.

Reproduction

  1. initialize with the capabilities above, then session/new in an empty directory that contains b.txt.

  2. session/set_config_option: model = gpt-5.6-luna, reasoning_effort = low, mode = agent.

  3. session/prompt:

    Use your multi-agent tools (spawn_agent) to start exactly two sub-agents in parallel, then wait for both. Sub-agent 'reader': read the file b.txt in the current directory and report its content. Sub-agent 'writer': run the shell command 'touch sub-writer.txt' in the current directory and report the result. Do not do these tasks yourself. When both finish, reply with one short line summarizing both results.

Observed

  • The turn ends with end_turn after 25–30 s. Both subagents did their work: sub-writer.txt exists, and the final answer reports the content of b.txt.

  • No subagent_spawned and no subagent_state_update arrive. No session/update arrives for any session other than the root.

  • The client only sees the item/started copy of each spawn, with empty receiverThreadIds. No completion update follows, so the tool call stays in_progress:

    {"sessionUpdate":"tool_call","toolCallId":"exec-…","kind":"other","title":"spawnAgent","status":"in_progress",
     "rawInput":{"prompt":"You are sub-agent 'writer'. …","senderThreadId":"01a11650-…","receiverThreadIds":[],"agentsStates":{}},
     "_meta":{"jetbrains":{"air":{"version":1,"subagent":true}}}}
  • The wait tool calls that follow carry the child thread ids in receiverThreadIds and complete normally. Codex writes a separate rollout for each child thread in ~/.codex/sessions.

  • Approvals. With mode = read-only, the writer's command needs approval. No session/request_permission reaches the client, for the root or any other session. The parent keeps calling wait and sendInput, and after more than 6 minutes the turn still had not finished. It looks like the approval waits for a child session that is never announced (interactionSessionId → waitForChildSession).

  • Replay. session/load of the same session in a new process with the same capabilities replays no spawnAgent tool calls and announces no children. Only the two wait calls remain.

  • Without native negotiation. Without the AIR capability, the same prompt behaves consistently: the spawnAgent tool calls complete, and the writer's approval arrives on the root session.

Expected

Each spawned child is announced with subagent_spawned before its first output, as docs/subagent-sessions.md describes. Child output, approvals and elicitations use the child session id, and the child ends with subagent_state_update. The spawn tool call does not stay in_progress, and session/load rebuilds the same tree.

Cause

In src/subagents/CodexSubagentEventRouter.ts on main, materialize() is only called from the subAgentActivity branch (line 108). The spawnAgent branch only records a pending spawn (lines 127–153) and returns true (line 170), so the spawn's item/completed is treated as represented and suppressed. For an ad-hoc spawn_agent, no subAgentActivity item ever comes, so the child is never materialized. Its notifications stay in the pending buffer until it overflows, and the client is left with the item/started copy.

I did not capture APP_SERVER_LOGS this time. The ACP-side behavior matches the app-server trace in #482 (subAgentActivity items: 0, hundreds of child-thread notifications, a "Pending subagent … exceeded the notification buffer" log line).

#482's fix still looks right: announce from the spawn's own item/completed, which already carries receiverThreadIds and arrives before any child output. Named subagents keep their path-based name, because materializing a known child is a no-op.

Related

Activity

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