MultiAgentV2 plaintext support in 0.147.0-alpha.1 does not complete cross-provider task delivery
Summary
#35845, included in 0.147.0-alpha.1, added support for processing plaintext collaboration tool messages.
However, that change covers the receiving path only when plaintext has already been selected upstream. It does not provide an end-to-end way for an OpenAI parent to select plaintext delivery when spawning a child backed by a third-party provider.
As a result, the cross-provider failure reported in #34833 remains reproducible on a source baseline of 0.147.0-alpha.4: the child is created with the intended role, provider, and model, but cannot consume its initial task because the assignment is still delivered as provider-specific encrypted content.
Environment
- Windows
- Codex Desktop
- Source baseline:
codex-cli 0.147.0-alpha.4 - Parent: OpenAI provider
- Child: third-party provider using an OpenAI-compatible API
- Multi-agent implementation: V2
- Direct requests to the third-party provider succeed
Provider names, endpoints, credentials, account information, and third-party model identifiers have been intentionally omitted.
Observed behavior
- Enable MultiAgentV2.
- Configure a registered child role backed by a third-party provider.
- Start an OpenAI-backed parent.
- Invoke
spawn_agentfor that child role. - Codex resolves the intended child role, provider, and model and creates the child.
- The child cannot read the initial assignment and therefore cannot begin the task.
The same third-party provider succeeds when invoked directly, which isolates the failure to the MultiAgentV2 provider boundary rather than authentication, networking, or model availability.
Why the 0.147.0-alpha.1 fix is incomplete
The implementation added by #35845 preserves encrypted_function_args and introduces ToolCallSource::DirectPlaintextMessage. A collaboration call is classified as plaintext only when all of the following are true:
- the namespace is exactly
collaboration; - the tool is
spawn_agent,send_message, orfollowup_task; encrypted_function_args == Some([]).
When that marker is present, the handlers construct a structured plaintext agent message. Otherwise, they retain the existing encrypted path.
The remaining gap is that the MultiAgentV2 tool schemas still unconditionally apply .with_encrypted() to the message fields for spawn_agent, send_message, and followup_task. An OpenAI parent therefore normally produces actual encrypted arguments rather than the empty marker required by DirectPlaintextMessage. The call is classified as Direct, and the handler still uses:
InterAgentCommunication::new_encrypted(...)
The third-party child then receives content it cannot decrypt or interpret.
The alpha.1 implementation also has the following limitations for this topology:
- plaintext classification is hard-coded to the
collaborationnamespace; - a configured custom namespace cannot enter the plaintext branch;
- providers without namespace-tool support cannot match that condition;
- there is no provider-aware delivery selection;
- there is no explicit configuration to request plaintext delivery;
- encrypted delivery to a third-party child is not rejected before the unusable child is created.
The relevant schema, classification, and message-construction behavior remains materially unchanged between 0.147.0-alpha.1 and 0.147.0-alpha.4.
Simply removing .with_encrypted() is also insufficient. A modified plaintext schema under the reserved collaboration namespace is rejected by the OpenAI API because reserved collaboration functions must match the configured schema exactly. A complete fix therefore also needs a supported non-reserved namespace or an upstream-compatible schema mechanism.
Local source-level fix path
I implemented and validated an opt-in, backwards-compatible delivery policy across the following source paths.
Configuration and schema
codex-rs/features/src/feature_configs.rscodex-rs/features/src/lib.rscodex-rs/core/src/config/mod.rscodex-rs/core/config.schema.json
The local configuration shape is:
[features.multi_agent_v2]
enabled = true
message_delivery = "plaintext"
tool_namespace = "agents"
encrypted remains the default.
Tool schemas
codex-rs/core/src/tools/handlers/multi_agents_spec.rs
The encrypted marker is applied conditionally to the message fields for spawn_agent, send_message, and followup_task.
Tool planning and call classification
codex-rs/core/src/tools/spec_plan.rscodex-rs/core/src/tools/router.rscodex-rs/core/src/tools/parallel.rs
Plaintext mode classifies the relevant calls as DirectPlaintextMessage using the configured tool namespace rather than only the hard-coded collaboration namespace.
MultiAgentV2 message handling
codex-rs/core/src/tools/handlers/multi_agents_v2.rscodex-rs/core/src/tools/handlers/multi_agents_v2/spawn.rscodex-rs/core/src/tools/handlers/multi_agents_v2/send_message.rscodex-rs/core/src/tools/handlers/multi_agents_v2/followup_task.rscodex-rs/core/src/stream_events_utils.rs
Plaintext mode reuses the structured input_text path. If an encrypted task is about to be delivered to a non-OpenAI child, the spawn fails before child creation with an actionable configuration error.
Validation results
- Feature configuration tests: 34/34 passed.
- Targeted MultiAgentV2 tests: 74/74 passed.
- Plaintext tool-schema tests passed.
- Custom and unnamespaced collaboration-tool tests passed.
- Structured parent-to-child
input_textdelivery tests passed. - Fail-closed tests for encrypted delivery to a third-party child passed.
- Release build succeeded.
- After fully restarting Codex Desktop with the local build, an OpenAI parent successfully spawned a third-party-provider child.
- The child received the assignment, executed it, and returned the expected fixed marker.
- The default encrypted behavior remains unchanged.
Expected upstream behavior
A complete upstream solution should:
- Keep encrypted delivery as the default.
- Provide an explicit plaintext delivery policy for providers that cannot consume OpenAI encrypted tool parameters.
- Apply the policy consistently across tool schemas, planning, routing, and message construction.
- Support a non-reserved tool namespace for plaintext collaboration schemas.
- Fail before spawning when encrypted delivery is incompatible with the selected child provider.
- Add an end-to-end integration test for an OpenAI parent spawning a third-party-provider child.
2 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
CodexHub Beta4.1 status update (sanitized; no credentials or raw ciphertext included).
We independently confirmed that the plaintext receiving path alone does not complete cross-provider delivery. In the OpenAI-parent -> non-OpenAI-child case, the parent-side V2 handoff can still carry a real Fernet-like ciphertext in
encrypted_content; a downstream Gateway cannot decrypt it, so envelope rewrites or removal of theencryptedJSON-schema marker cannot recover the task text.Implemented in CodexHub Beta4.1 at the Gateway boundary:
This proves the protocol/tool-surface adapter direction, not full OpenAI-parent -> external-child delivery. The external model is not being treated as natively V2-capable; the Gateway is adapting ordinary tool-calling behavior into the Codex V2 lifecycle surface.
Requested upstream resolution:
Until that producer-side change exists, CodexHub can ship the tool-surface adapter separately but cannot honestly claim complete cross-provider V2 lifecycle support.