Subagent task payload invisible to custom non-OpenAI providers (DeepSeek): encrypted_content block dropped with multi_agent_version v2
Summary
When using a custom non-OpenAI provider (DeepSeek) with Codex multi-agent (subagents), tasks
dispatched via spawn_agent / followup_task are never seen by the subagent. The subagent
initializes, reads the workspace, and then replies that it has no task input ("no new task
input"), so every subagent run is a no-op.
Environment
- Codex CLI
0.145.0on Windows - Custom provider in
config.toml:[model_providers.deepseek]with
base_url = "https://api.deepseek.com/" and wire_api = "responses"
model = "deepseek-v4-flash",model_catalog_json = "~/.codex/models.json"(written by the
official DeepSeek one-command setup, which sets "multi_agent_version": "v2" in both entries)
- Multi-agent tools:
collaboration__spawn_agent/followup_task(MultiAgentV2 tool surface)
Reproduction
- Start a session with
deepseek-v4-flash(models.json entry has
"multi_agent_version": "v2").
- Spawn a subagent with a simple task, e.g. "reply exactly: PONG".
- The subagent replies with a workspace status summary and asks what to work on; it never
executes the dispatched task. followup_task with the same prompt also yields
"no new task input".
Same setup with a native catalog model (e.g. gpt-5.6-sol) executes subagent tasks correctly.
Root cause
For MultiAgentV2, the task payload is always delivered through anInterAgentCommunication::new_encrypted(..) record whose content is a[input_text header, encrypted_content] pair:
codex-rs/core/src/tools/handlers/multi_agents_v2.rs—communication_from_tool_message
uses new_encrypted(author, recipient, vec![], message, trigger_turn) for every
non-DirectPlaintextMessage source, so the task text lives in the encrypted_content
content block.
codex-rs/core/src/client.rs— inbuild_responses_request, the!is_openaibranch only
clears FunctionCall.encrypted_function_args; it does not handle
ResponseItem::AgentMessage content, so the encrypted_content block is sent to the
provider API unchanged.
codex-rs/core/src/client_common.rs—get_formatted_input_for_requestpasses the items
through as-is.
For OpenAI endpoints the agent-message payload is decrypted/rendered server-side, which is why
native models work. The DeepSeek Responses API does not understand the encrypted_content
content block type and drops it, so the model only receivesMessage Type: NEW_TASK\nTask name: ...\nSender: ...\nPayload: with an empty payload.
Workaround (validated)
Set "multi_agent_version": "v1" for the custom model entries in ~/.codex/models.json
(instead of "v2"). With V1 the spawn initial input is delivered as a plain user message
(SpawnInitialInput::UserInput) instead of an inter-agent communication, and DeepSeek
subagents execute tasks correctly (verified with a codex exec spawn test returning the
expected output). Restart the session after editing models.json.
Note: this means custom non-OpenAI models cannot currently use the MultiAgentV2 tool surface
at all.
Suggested fix
In build_responses_request (codex-rs/core/src/client.rs), extend the !is_openai branch
to transform ResponseItem::AgentMessage content: fold the encrypted_content block into a
single InputText (header text + payload), mirroring the plaintext rendering already used bycommunication_from_tool_message's DirectPlaintextMessage path. This lets customwire_api = "responses" providers receive subagent task payloads while keeping V2 behavior.
Related
- #36382 — MCP tools silently unavailable with DeepSeek official setup (same family:
custom models.json + non-OpenAI provider gaps in tool/content handling)
8 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
Additional reproduction and a working local patch (codex-cli 0.146.0 source, deepseek-v4-flash,
wire_api = "responses",multi_agent_version = "v2").Wire-level finding: even when the
agent_messagecontent is rewritten so the payload is plaintextinput_text(noencrypted_content), DeepSeek still ignores theagent_messageitem in most runs and the child replies that it has no task. The task is only consumed reliably when it is delivered as a plainusermessage.Working local patch: for non-OpenAI providers, deliver V2 spawn / followup_task / send_message payloads as plain user input (
UserInput), mirroring the V1SpawnInitialInput::UserInputpath. The OpenAI path keeps encryptedInterAgentCommunicationunchanged. Verified end-to-end with the real provider:spawn_agent->PONG,followup_task->PONG2.The
multi_agent_version: "v1"workaround does not work with deepseek-v4-flash: with DeepSeek's catalog (supports_search_tool: true), the V1 tool family is registered as Deferred behindtool_search. Thetool_searchtool is present in the request tools array, but deepseek-v4-flash does not recognize or call it (same family as #36382), so the V1 tools are unreachable and v1 stays broken for this model.Full patch, build/install steps, QA evidence and config templates (sanitized) are published here: https://github.com/CCanxue/codex-deepseek-subagent-fix
Reproducing on Codex Desktop (macOS), app version 26.727.51351, with
deepseek-v4-flashvia the official one-command DeepSeek setup (wire_api = "responses",multi_agent_version: "v2"in models.json).Both
spawn_agent(initial task) andfollowup_taskfail the same way: the child initializes, reads the workspace, then replies "I don't see a task in this message yet" / "Ready when you are — just send over the task."Log evidence (rollout JSONL): the delivered
agent_messagecontains aninput_textenvelope with an emptyPayload:plus anencrypted_contentblock holding the actual task. The HTTP request POSTed tohttps://api.deepseek.com/responsescarries thatencrypted_contentblock untouched, so DeepSeek only sees the empty envelope. Normal user messages are plaininput_textand work fine in the same session.This confirms the issue is not CLI-only — it also affects the Desktop app with a non-OpenAI model as the root agent. Happy to provide full rollout logs or test a proposed fix.
Same issue on codex-cli 0.146.0 with the official DeepSeek setup
Environment:
wire_api = "responses", base_url = "https://api.deepseek.com/",
model_catalog_json with multi_agent_version = "v2"
Reproduction:
(e.g. "run Get-Date and return the output").
with a generic greeting: "I'm ready to help. What would you like me to
work on?"
receives/executes the follow-up.
replays the parent's spawn calls from the inherited context, creating
recursive spawn chains (I had to interrupt them manually).
What I found in the logs:
input item of type "agent_message", with the real payload inside
"encrypted_content". The visible content stops at "Payload:" with an
empty text.
item types: message, function_call, function_call_output, reasoning,
web_search_call. It explicitly says other types are ignored.
Expected behavior:
user message (like the community patch does), or Codex should fail fast
with a clear "provider does not support agent_message input items"
error instead of silently dropping the task.
Happy to provide redacted request/response logs or test a patched build.
Thanks for the additional reproductions. trillox9's point about DeepSeek's Responses compatibility table (only
message,function_call,function_call_output,reasoning, andweb_search_callare accepted; other input item types are ignored) explains why foldingencrypted_contentinto plaintextinput_textinside theagent_messageitem is not enough: the whole item type is dropped, not just the encrypted block.For anyone who wants to test a fix now: we published a local patch for 0.146.0 that delivers V2 spawn / followup_task / send_message tasks as plain user messages for non-OpenAI providers (OpenAI path unchanged), verified on CLI and applicable to the Desktop bundled CLI. liushiyao110, the build/install steps in the repo cover the Desktop case as well. We also saw the same recursive spawn chains with
fork_turns: allthat trillox9 described, when the parent prompt leaks into the child context.Repo: https://github.com/CCanxue/codex-deepseek-subagent-fix
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.
Thanks for confirming the root cause and for the refined v1 workaround. We can confirm the mechanism: with
supports_search_tool = false, V1 tools are registered with direct exposure instead of being deferred behindtool_search, which addresses the discoverability problem we hit earlier with deepseek-v4-flash. This is a config-only change, so it also works on the official unpatched binary (no rebuild needed). The tradeoff is losing the V2 tool family (followup_task,send_message,list_agents,interrupt_agent); if you need those, a local patch that keeps V2 and delivers payloads as plain user messages for non-OpenAI providers is verified end-to-end: https://github.com/CCanxue/codex-deepseek-subagent-fixAdditional reproduction: Codex Desktop (Windows) + DeepSeek official setup, CLI 0.149.0 / app 26.818.5229.0 — confirms the same
encrypted_contentdrop; workaround (multi_agent_version v1) matches your analysis.Environment
26.818.5229.0; embedded runtimecodex-cli 0.149.0(internal kernel string0.149.0-alpha.4fromapp\resources\codex.exe; UI version string differs — checked the binary, not the UI, percodex-desktop-diagnostics).deepseek-v4-flash-vision-exp;model_provider = "deepseek";base_url = "https://api.deepseek.com/";wire_api = "responses".~/.codex/models.jsonwritten by the official DeepSeek one-command setup: all three entries (deepseek-v4-flash,deepseek-v4-pro,deepseek-v4-flash-vision-exp) have"multi_agent_version": "v2".Reproduction (stable)
spawn_agent(task_name="acceptance", message="...", fork_turns="none")andwait_agent.list_agentsshows the sub-agent completing with: “I only received session context; I don't see the concrete task content.”agent_messagein the session rollout (~/.codex/sessions/**/*.jsonl) is exactly:``
`Message Type: NEW_TASK
Task name: /root/acceptance
Sender: /root
Payload:
Payload:— length **82 chars,
is empty**. Reproduced 3+ times acrossspawn_agent/followup_task/send_message`, both before and after a full Desktop restart.Causal isolation
models.json: setting"multi_agent_version": "v1"for the three DeepSeek entries delivers the task as plaintextuserinput and the sub-agent executes correctly (verified once, then rolled back).model_provider="deepseek"unchanged,fork_turns=1partially masks the issue (child receives forked history but still not the per-agent spawn message), whilefork_turns="none"yields a fully empty agent — consistent withencrypted_contentbeing dropped by the third-party endpoint.spawn_agentreturns success andfollowup_taskreturns silently empty.Boundary
v1is usable but loses the v2 tool surface (per your note) — I reverted it to keep the default v2 baseline while upstream decides.Request
This repo already tracks it in #37237/#37822; adding my Windows Desktop + 0.149.0 data point. Expected: task body reaches the sub-agent (plaintext expansion before serialization, or a loud error for third-party providers). Actual: empty
Payload:header, zero diagnostics. Please confirm and prioritize the suggested fix inbuild_responses_request(foldencrypted_contentintoInputTextfor non-OpenAI providers).