`spawn_agent` silently creates empty sub-agents for any non-OpenAI Responses provider — task body sent as `encrypted_content` and dropped, with zero diagnostics
Summary
The ChatGPT desktop app's embedded Codex runtime (cli 0.147.0-alpha.1.2, app 26.730.61639) creates sub-agents via spawn_agent / followup_task, but when model_provider points at a non-OpenAI Responses-compatible endpoint (wire_api="responses" -> e.g. https://api.deepseek.com), the task body never reaches the sub-agent. The sub-agent spawns, sees only an empty "Message Type: NEW_TASK ... Payload:" header, and replies "I don't see a specific task." Switching model_provider to the OpenAI backend makes it work. No error is surfaced anywhere. This silently breaks the multi-agent feature for every third-party provider.
Repro
config.toml:
model = "deepseek-v4-flash"
model_provider = "deepseek"
[model_providers.deepseek]
name = "DeepSeek"
base_url = "https://api.deepseek.com"
wire_api = "responses"
In a session:
spawn_agent(task_name="test", message="Reply with DELIVERY_OK only", fork_turns="none")wait_agentlist_agents
Observed: spawn_agent returns {"task_name": "/root/test"} (success). But list_agents shows the sub-agent completed with "Hi! It looks like your message may not have come through yet — I don't see a specific request to work on."
Root cause — captured from the wire
The HTTP request the app sends to the third-party endpoint serializes the task as:
{"type":"agent_message","author":"/root","recipient":"/root/test","content":[
{"type":"input_text","text":"Message Type: NEW_TASK\nTask name: /root/test\nSender: /root\nPayload:\n"},
{"type":"encrypted_content","encrypted_content":"Reply with DELIVERY_OK only"}
]}
The encrypted_content content item is forwarded verbatim. A third-party Responses endpoint has no way to render that type, so the body is dropped and the model only sees the empty Payload: header. The same spawn under model_provider="openai" resolves correctly.
Notes:
- This is not a tool-contract problem:
spawn_agent'stask_name/message/fork_turnsarguments are exactly as documented, and the handler returns a valid task path. followup_task(target+message) fails the same way; its output is silently empty.fork_turns="all"partially masks it: the child gets the parent's forked history, but still not the per-agent spawn message.fork_turns="none"yields a fully empty agent.
Suspected area: the multi-agent v2 delivery path (core/src/tools/handlers/multi_agents_v2/spawn_agent.rs, followup_task.rs) and core/src/agent_communication.rs, where inter-agent messages are stored/transported as encrypted_content items and only expanded on the OpenAI backend.
Expected behavior
encrypted_contentin agent-message payloads must be decrypted/expanded to plaintextinput_textbefore the request is serialized to any provider; or- if that expansion is intentionally OpenAI-only,
spawn_agent/followup_taskmust fail loudly with a clear error instead of silently spawning an empty agent.
Silently creating a sub-agent with no task — and silently returning empty results for followup_task / send_message — is the worst possible failure mode: no exception, no log, just empty agents doing nothing.
Environment
- macOS (Darwin 25.5.0)
- ChatGPT desktop app
26.730.61639(build 6234), embedded Codex runtimecli 0.147.0-alpha.1.2 model=deepseek-v4-flash,model_provider=deepseek,base_url=https://api.deepseek.com,wire_api=responses
3 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
Root cause
MultiAgentV2 delivers tasks through InterAgentCommunication: the plaintext content is empty, and the entire task text is placed in the encrypted_content content block. OpenAI endpoints decrypt and render this block server-side, which is why native models work; DeepSeek's Responses implementation does not recognize encrypted_content (community packet captures show that sending a request containing this content item directly returns a 400 / it gets dropped), so the sub-agent only sees an empty Payload:. This is the same family of issues as openai/codex #36493, #36321, #36586, #37237, and #37822.
Verified workaround (currently in effect on this machine)
Modify both entries in ~/.codex/models.json:
Rationale: supports_search_tool=false makes search_tool_enabled=false, so deferred tools are no longer hidden behind tool_search but are exposed directly to the model (the same mechanism as the workaround in #36382). The v1 tool family then becomes directly visible, and v1 delivers tasks as plain user messages (UserInput), which DeepSeek consumes reliably.
Confirming this with additional reproduction data on the desktop app.
Environment
deepseek_v4_propointing at a non-OpenAI provider (wire_api="responses")Controlled
fork_turnscomparison (same parent turn, same message)| fork_turns | result |
|---|---|
|
"none"| child completes with "only system/collaboration metadata, no assignment content" — message body fully dropped ||
"1"| child appears to work, but only because it inherits forked parent history; the spawnmessageitself still never arrives, so in a complex thread the child follows the old topic instead of the new task |This matches the
encrypted_contentroot cause exactly:fork_turns="1"/"all"merely masks the bug via inherited history;"none"yields a fully empty agent.Additional data point worth triage: an OpenAI-backend built-in role (
explorer) spawned withfork_turns="none"also returned "I don't see a task yet" for a one-token message. This suggests the loss may not be limited to non-OpenAI providers — worth confirming whether theencrypted_contentexpansion is actually provider-gated or also skipped for certain built-in role spawns.Requested behavior (same as OP): fail loudly with a clear error rather than silently spawning an empty agent, so orchestrating agents don't produce garbage "I see no task" replies with zero diagnostics.