Multi-Agent V2 sends OpenAI-specific agent_message items to external Responses providers

Open 💬 1 comment Opened Jul 16, 2026 by sdwolf4103

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 no encrypted_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?

  1. Configure an external Responses provider, for example an Ollama Responses endpoint, in Codex configuration.
  2. Configure a native agent role in ~/.codex/agents/*.toml whose model_provider points to that external provider.
  3. Enable Multi-Agent and Multi-Agent V2.
  4. Start a fresh task using a parent model for which the model catalog selects V2, and send the first message with that model.
  5. Invoke spawn_agent for the external-provider role.
  6. 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:

  1. Create a new task.
  2. Select a V1-capable parent model such as Luna before sending the first message.
  3. Set multi_agent = true and multi_agent_v2 = false.
  4. 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.rs
  • codex-rs/core/src/tools/handlers/multi_agents_v2.rs
  • codex-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_message path 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 message item, for example:
{
  "type": "message",
  "role": "user",
  "content": [
    {
      "type": "input_text",
      "text": "..."
    }
  ]
}
  • Apply the same provider-aware conversion to initial spawn instructions, follow-up/send_message instructions, 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.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗