[Bug] GPT-5.6 Sol routes agent wait calls to unrelated functions.wait after spawn_agent

Open 💬 3 comments Opened Aug 5, 2026 by Muelmue

What version of the Codex App are you using (from the “About Codex” dialog)?

26.730.61639

What subscription do you have?

ChatGPT Pro 20x

What platform is your computer?

Microsoft Windows NT 10.0.19044.0 x64

What issue are you seeing?

Codex App exposes two unrelated waiting tools:

  • collaboration.wait_agent, which waits for subagents
  • functions.wait, which waits for a previously started exec cell

After collaboration.spawn_agent succeeds, the coordinator is explicitly
instructed to call collaboration.wait_agent, but it sometimes emits
functions.wait instead, using arguments derived from the agent-wait request.

I observed two failure shapes.

Failure 1

Expected:

collaboration.wait_agent({"timeout_ms": 30000})

Actual:

functions.wait({"timeout_ms": 30000})

The call failed argument parsing because functions.wait requires an exec
cell_id. No agent wait was performed, and the child result was not collected.

Failure 2

One correct collaboration.wait_agent call first timed out normally. The next
intended agent wait was emitted as:

functions.wait({
  "cell_id": "30",
  "yield_time_ms": 30000,
  "max_tokens": 2000
})

The runtime returned:

exec cell 30 not found

No exec cell had been created. The coordinator then stopped without retrying.

This prevents reliable parent/subagent workflows even though the child was
created successfully and continued running.

What steps can reproduce the bug?

  1. Start a fresh Local task in Codex App.
  2. Select gpt-5.6-sol.
  3. Use a repository containing enough documentation for a read-only child

review to take longer than one wait interval.

  1. Give the coordinator this instruction:

```text
Create one fresh-context, read-only subagent using collaboration.spawn_agent.

After spawn succeeds, immediately call:
collaboration.wait_agent with timeout_ms=30000.

If the child has not completed, call the same collaboration.wait_agent again.
Use only collaboration.wait_agent or collaboration.list_agents for agent
status. Do not use terminal polling.
```

  1. Observe the tool call emitted after collaboration.spawn_agent.

In two fresh reproductions, the spawn succeeded, but the intended
collaboration.wait_agent call was eventually or immediately replaced by
functions.wait.

One affected session ID:

019fcfe5-5c94-7772-b82b-07890d0b1e43

No token-limit or context-window warning was shown. One reproduction failed
immediately after spawn in a fresh task.

What is the expected behavior?

After a successful collaboration.spawn_agent call, an explicitly requested
agent wait must call:

collaboration.wait_agent({"timeout_ms": 30000})

If the wait times out, subsequent waits must continue to call
collaboration.wait_agent.

functions.wait must only be selected when an actual exec command has returned
a real exec cell_id. Agent-wait arguments must never be routed to that tool.

Additional information

The problem was reproduced in two unrelated repositories.

  • The first reproduction occurred without loading the repository's reusable

workflow Skill.

  • The second occurred in a repository where the same native parent/subagent

pattern had historically worked reliably.

  • Both repositories passed frozen snapshot checks.
  • collaboration.spawn_agent succeeded in both cases.
  • No files were modified.
  • No dependency installation, network access, or Git write occurred.
  • Prompt safeguards detected the wrong tool and stopped without retrying.

Historical successful runs in the control repository recorded:

codex-cli 0.146.0-alpha.3.1

One failing reproduction recorded:

codex-cli 0.147.0-alpha.1.2

The problem still reproduced after updating Codex App to 26.730.61639.

This suggests a possible tool-identity or schema-routing collision between
collaboration.wait_agent and functions.wait. Black-box evidence cannot
determine whether the exact owning layer is model tool selection, the agent
runtime, or Codex App tool registration.

Related but apparently distinct issues:

Sanitized rollout excerpts can be provided if needed. Full rollout files are
not attached because they contain private local paths and repository context.

View original on GitHub ↗

3 Comments

KNaiFen · 22 days ago

I reproduced the first failure shape again today while auditing this report.

Additional reproduction

  • Codex CLI: 0.146.0
  • Model surface: MultiAgentV2 (gpt-5.6-sol)
  • Host tool names: agents.wait_agent and functions.wait
  • Provider: an OpenAI-compatible Responses proxy in inactive/pass-through bridge mode, with no stream-modifying plugin. This is therefore useful confirmation of the client/tool-catalog failure shape, but not an official-backend-only reproduction.

After a successful agents.spawn_agent, the coordinator needed to wait for the child and had an explicit instruction to use the agent wait tool. It emitted:

functions.wait({"timeout_ms":120000})

The result was the same schema error reported here:

failed to parse function arguments: missing field `cell_id`

Further attempts sometimes selected functions.wait again with invented cell IDs and returned exec cell ... not found. Calling agents.wait_agent({"timeout_ms":120000}) explicitly worked and delivered the child completion.

Current-main source audit

I also checked current main at c38a60ded2ffbad510f8b512e2902f0128e998e8:

  • create_wait_tool exposes the exec-cell tool as wait and requires cell_id: codex-rs/core/src/tools/code_mode/wait_spec.rs.
  • create_wait_agent_tool_v2 exposes the agent-mailbox tool as wait_agent: codex-rs/core/src/tools/handlers/multi_agents_spec.rs.
  • The router preserves (namespace, name) from the model response and resolves the full ToolName; I found no path that rewrites a correctly emitted agents.wait_agent/collaboration.wait_agent call into functions.wait.

That points to model tool selection between two valid, simultaneously visible tools rather than a registry rewrite. It also lines up temporally with #37022 making the functions namespace explicit for default tools, although that PR is not itself evidence of the root cause.

Small OSS mitigation candidate

A narrow client-side mitigation would make the two schemas mutually explicit:

  1. In create_wait_tool, state that it is only valid after functions.exec returned a real cell_id, and must never be used for subagent waiting.
  2. In create_wait_agent_tool_v2, state that it is the only wait tool for agent/mailbox updates and that functions.wait is only for yielded exec cells.
  3. Add spec tests that keep those disambiguating constraints present in both tool descriptions.

I do not recommend automatically redirecting a functions.wait call that lacks cell_id; the arguments do not prove the caller intended an agent wait.

Per docs/contributing.md, I will not open an unsolicited PR. If a maintainer agrees with this mitigation and invites a contribution, I can submit the focused wording and test change.

Muelmue · 22 days ago

Thanks for the independent reproduction and source audit. This is especially useful because your reproduction uses agents.wait_agent rather than collaboration.wait_agent. That shows the failure is not specific to the collaboration namespace.

Your observed call:

functions.wait({"timeout_ms":120000})

matches our first failure shape. The later invented exec cell IDs also match our second failure shape.

Our reproductions were performed in the official Codex Desktop app, while yours used an OpenAI-compatible pass-through proxy. The reports are therefore complementary:

  • The official Desktop reproduction establishes the product impact.
  • Your reproduction shows that the same model/tool-catalog confusion can occur through a different namespace and provider path.

The source audit also narrows the likely failure point. If the router preserves the emitted (namespace, name), the failure appears to happen before dispatch: the model selects functions.wait while carrying arguments intended for the agent wait tool.

I agree that mutually explicit tool descriptions and regression tests would be a reasonable narrow mitigation. I also agree that automatically redirecting malformed functions.wait calls would be unsafe.

For clarity, I do not consider #37022 proven as the cause. It is currently only a possible temporal or tool-visibility-related factor.

Muelmue · 22 days ago

Before adding the fail-fast safeguard, repeated retries in the same coordinator
turn did not recover. The model selected functions.wait and invented different
exec cell IDs dozens of times, producing a persistent retry loop. This is why
the current workflow stops on the first wrong-tool emission.