`collab_tool_call` "spawn_agent" item missing from `exec --experimental-json` stream; "wait" item's `receiver_thread_ids` stays empty despite a real, successful delegation underneath

Open
#34,919 1 comment 2 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
48/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Quiet
Tech stack
rust, typescript

Research direction

Start with node_modules/@openai/codex-sdk/src/exec.ts and reproduce the delegation through Codex.startThread().runStreamed() using codex exec --experimental-json. Compare the emitted stream with the full session rollout JSONL and the thread_spawn_edges records in state_5.sqlite. Done means the public stream includes the spawn_agent item and the wait item contains the actual receiver thread IDs.

Written by the indexing model from the issue text.

Description

bug CLI exec subagent
What version of Codex CLI is running?

0.144.5 (installed via @openai/codex-sdk / @openai/codex npm packages)

Which model were you using?

gpt-5.6-sol

What platform is your computer?

Linux (Ubuntu 20.04 focal), invoked via @openai/codex-sdk's Codex.startThread().runStreamed(), which shells out to codex exec --experimental-json (see node_modules/@openai/codex-sdk/src/exec.ts).

What happened?

Using native subagent support ([features] multi_agent = true, a custom
agent defined at <CODEX_HOME>/agents/<name>.toml), I asked the root agent
to spawn a named custom agent and relay its exact reply. The
--experimental-json event stream only ever shows:

{"type":"item.started","item":{"id":"item_1","type":"collab_tool_call","tool":"wait","sender_thread_id":"...","receiver_thread_ids":[],"prompt":null,"agents_states":{},"status":"in_progress"}}
{"type":"item.completed","item":{"id":"item_1","type":"collab_tool_call","tool":"wait","sender_thread_id":"...","receiver_thread_ids":[],"prompt":null,"agents_states":{},"status":"completed"}}
{"type":"item.completed","item":{"id":"item_2","type":"agent_message","text":"SPECIALIST SAID: PONG"}}

Note: no collab_tool_call with tool: "spawn_agent" (or similar) ever
appears in this stream, and the wait item's receiver_thread_ids is
always [], even though the final agent_message content is correct.

This reproduced identically across 6 separate runs, with and without
[features.multi_agent_v2].

Reading the FULL session rollout (~/.codex/sessions/**/*.jsonl) for the
same turn tells a different, complete story — it contains the actual
function_call/function_call_output pair for the spawn, a
sub_agent_activity event ("kind": "started"), the child thread's own
rollout file (session_meta subagent.thread_spawn with the correct
agent_path/agent_nickname), and the real agent_message reply routed
back from the child. state_5.sqlite's thread_spawn_edges table also
correctly records the parent→child edge for every one of the 6 runs.

So: delegation genuinely works end-to-end. The bug is that the
--experimental-json stream — the one @openai/codex-sdk consumes and
exposes to SDK users — is missing the spawn_agent collab_tool_call event
entirely, and the wait item it does emit never reflects the real
receiver thread. This is different from #28318 (missing TypeScript type for
collab_tool_call — that reporter's runtime JSON did include a populated
spawn_agent item with real receiver_thread_ids); here the data itself
is missing from this event source, not just its type.

Expected behavior

exec --experimental-json (and therefore @openai/codex-sdk's public
event stream) should include the spawn_agent collab_tool_call item, and
wait's receiver_thread_ids should reflect the actual spawned child
thread(s) — matching what the full session rollout already records
correctly.

Why this matters

Any SDK consumer trying to observe or verify subagent delegation
(logging, tracing, debugging, deciding whether to trust a delegated
result) via the public event stream currently gets a false negative —
delegation looks like a silent no-op even when it succeeded. We only
caught this by cross-referencing the full rollout JSONL and
state_5.sqlite directly, which isn't part of the SDK's public surface.

Dominant language
Rust
Stars
125k
Forks
19.5k
Avg merge
1m
Merged PRs (30d)
1k

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.

More from openai/codex

All issues in openai/codex

Similar issues

More Rust issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.