Multi-Agent V2 sends OpenAI-specific agent_message items to external Responses providers
What issue are you seeing?
Codex Multi-Agent V2 sends child-agent instructions as the OpenAI-specific Responses item type agent_message. External Responses-compatible providers such as Ollama do not recognize this item type and cannot decrypt its encrypted_content when present.
This prevents a V2 parent from spawning a native Codex agent whose configured model_provider is external. The failure is at the provider request boundary, before the external model can correctly receive the delegated task.
A captured comparison showed:
- Working V1 Kimi/GLM requests: every input item had
type: "message", with noencrypted_content. - Failing V2 GLM request: the final input item had
type: "agent_message". Even when that captured request had no encrypted payload, Ollama Responses still could not process the non-standard item type.
External-provider routing itself works under V1. The important distinction is that the Multi-Agent version is selected and stored by the root task's first parent turn, then inherited by the whole spawned agent tree:
- If a fresh task sends its first message using a V1-capable parent model such as Luna, the root task resolves to V1 and every subsequently spawned agent also uses V1.
- Switching models after the first message does not change the already stored Multi-Agent version.
- Starting the task with a catalog-forced V2 parent such as Sol or Terra therefore keeps the whole tree on V2, including external-provider children.
This is related to, but distinct from, #33284. That issue concerns plaintext visibility to local hooks before execution. This issue concerns wire-format compatibility with non-OpenAI model providers after dispatch.
What steps can reproduce the bug?
- Configure an external Responses provider, for example an Ollama Responses endpoint, in Codex configuration.
- Configure a native agent role in
~/.codex/agents/*.tomlwhosemodel_providerpoints to that external provider. - Enable Multi-Agent and Multi-Agent V2.
- Start a fresh task using a parent model for which the model catalog selects V2, and send the first message with that model.
- Invoke
spawn_agentfor the external-provider role. - Inspect the request sent to the external Responses endpoint.
The child instruction is serialized as an input item resembling:
{
"type": "agent_message",
"encrypted_content": "..."
}
or as a plaintext agent_message item. Ollama cannot decrypt the encrypted form, and its Responses implementation does not accept the agent_message item type in either form.
Disabling the multi_agent_v2 feature flag alone may not avoid the issue when the model catalog forces V2 for the selected parent model.
The current workaround requires all of the following:
- Create a new task.
- Select a V1-capable parent model such as Luna before sending the first message.
- Set
multi_agent = trueandmulti_agent_v2 = false. - Keep using that task after its first turn has resolved to V1.
This makes the entire task and every child agent use V1. It is not a provider-specific fallback, and it does not allow an OpenAI parent to retain V2 while only an external-provider child uses a compatible transport.
Relevant implementation areas appear to include:
codex-rs/core/src/tools/handlers/multi_agents_spec.rscodex-rs/core/src/tools/handlers/multi_agents_v2.rscodex-rs/protocol/src/protocol.rs(InterAgentCommunication::to_model_input_item)codex-rs/core/src/client.rs(Responses request construction)
What is the expected behavior?
Multi-Agent V2 should remain usable when either endpoint in an inter-agent route uses a non-OpenAI provider.
The requested behavior is not to downgrade external agents to V1 inside an otherwise V2 task. The root task and the entire agent tree should retain V2 lifecycle and coordination semantics. Only the wire representation at a non-OpenAI provider boundary should be adapted.
A provider-aware compatibility behavior would be:
- Preserve the existing encrypted
agent_messagepath for OpenAI-to-OpenAI routes. - For a route involving a non-OpenAI provider, keep the task text plaintext and serialize the outbound instruction as a standard Responses
messageitem, for example:
{
"type": "message",
"role": "user",
"content": [
{
"type": "input_text",
"text": "..."
}
]
}
- Apply the same provider-aware conversion to initial spawn instructions, follow-up/
send_messageinstructions, and child return messages as needed. - Preserve V2 lifecycle behavior such as task identity, graph state, wait, follow-up, and completion.
- Leave existing OpenAI-provider behavior unchanged.
- Allow catalog-forced V2 parents such as Sol or Terra to spawn explicitly configured external-provider roles without requiring the root task to start under Luna/V1.
Additional information
The compatibility decision should be made using the actual caller and recipient provider identities, not only the parent model name.
The current Luna-first workaround demonstrates that the configured external provider and native agent role can function when the payload uses standard V1 message items. It also demonstrates why that workaround is insufficient: it disables V2 for the entire root/child tree rather than making V2 interoperable with external Responses providers.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗