Repository navigation
Document / gate Ultra multi-agent features when using API-key custom model_providers #37859
Description
What version of Codex CLI is running?
0.147.0 (CLI + Desktop)
What subscription do you have?
ChatGPT Pro for account features; inference often via custom model_providers with API key (wire_api = "responses", env_key, requires_openai_auth = false).
Which model were you using?
gpt-5.6-sol with model_reasoning_effort = "ultra" on a custom API provider.
What platform is your computer?
macOS (applies generally)
What issue are you seeing?
Codex currently advertises or accepts Ultra-related settings for sessions that use a regular API-key model provider, but several Ultra product capabilities only work on the ChatGPT / first-party backend path.
Concretely:
| Capability | ChatGPT-auth / first-party provider | Regular API-key model_providers.* |
|---|---|---|
Reasoning effort ultra |
works | often works (effort enum only) |
Server-side multi-agent / Responses multi_agent |
works | fails (Unsupported parameter: multi_agent or no multi-agent tree) |
| Native Ultra-style parallel subagent product | works | incomplete / broken (see #17598, #37858) |
Client multi_agent_v2 / spawn_agent |
works | partial; known custom-provider bugs |
Users reasonably assume that:
model_provider = "my_api" # API key provider
model = "gpt-5.6-sol"
model_reasoning_effort = "ultra"
[features]
multi_agent_v2 = truemeans they get the same Ultra multi-agent experience as ChatGPT-signed-in Codex. They do not. There is no clear in-product warning, and docs do not draw a hard line between:
- Ultra as reasoning effort (portable to many providers), vs
- Ultra as multi-agent product (ChatGPT-backend / first-party only today).
What steps can reproduce the bug?
- Configure any working custom Responses API provider with API key auth.
- Set Sol +
model_reasoning_effort = "ultra"+ enable multi-agent features. - Use Desktop/CLI as if Ultra multi-agent were fully available (spawn parallel subagents, multi-agent coordination).
- Observe failures or silent single-agent answers; switch to ChatGPT-auth default provider and see full behavior.
What is the expected behavior?
Please do one or both of:
- Document in config reference / subagents / models docs:
- which Ultra capabilities require ChatGPT authentication / first-party backend
- which work with arbitrary Responses-compatible API providers
- Gate or label in UI/CLI when
model_provideris a custom API-key provider:- show that multi-agent Ultra is unavailable or degraded
- avoid implying that effort=
ultraalone enables full Ultra multi-agent
Without this, power users waste time debugging config when the limit is product architecture.
Additional information
Related:
- Ultra multi-agent / Responses multi_agent does not work with regular API-key model providers #37858 — Ultra multi-agent / Responses multi_agent broken on regular API providers
- Native subagent orchestration does not work correctly with non-OpenAI custom providers #17598 — native subagent orchestration with custom providers
- gpt-5.6-sol/terra/luna hardcode use_responses_lite / multi_agent_version, causing 400s on Azure (and likely any non-ChatGPT-backend) model_provider #31882 / Codex with GPT-5.6-Sol through Azure fails every turn with X-OpenAI-Internal-Codex-Responses-Lite #31870 — ChatGPT-backend-only headers / responses-lite assumptions on Sol/Terra/Luna
This issue is specifically about honest product surface + docs, not only the protocol fix requested in #37858.
Activity
github-actions commentedon Aug 10, 2026
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
jdcodes1 commentedon Aug 18, 2026
Supporting this documentation/gating request with the client-side mechanism (detailed in #37858 and #37822): inter-agent task payloads are transported as
encrypted_contentblobs that only the originating ChatGPT-backed session can have decrypted server-side — the client never decrypts them (InterAgentCommunication::to_model_input_item,protocol/src/protocol.rs#L813-L846). Withrequires_openai_auth = falseAPI-key providers there is no decrypting backend, so sub-agents receive an empty payload and idle. That's why the failure is silent and partial rather than a clean error: the spawn machinery works, only the message content evaporates.Which means the gate you're asking for has a precise, checkable condition: at spawn time, if the thread's provider isn't the first-party ChatGPT-auth backend (or once a plaintext fallback lands, whenever sender/receiver providers differ), fail the multi-agent tool call with an explicit "multi-agent requires ChatGPT auth on the first-party provider" — and the docs statement falls out of the same condition. Fixing the transport (plaintext path exists:
InterAgentCommunication::new) would eventually lift the restriction, but documenting + gating is worth shipping first since it converts hours of silent debugging into one clear message.RaviTharuma commentedon Sep 3, 2026
Dug into where your proposed gate would actually have to live, since "if provider isn't first-party ChatGPT-auth" turns out not to be the real branch condition. I traced the encrypt/plaintext split for details (posted the full trace on #37858) — the short version relevant to this issue's gating ask:
The client doesn't decide encrypted vs. plaintext from
model_providers/requires_openai_authat all.ToolCall::direct_source(codex-rs/core/src/tools/router.rs) setsToolCallSource::DirectPlaintextMessageonly when the upstream response'sencrypted_function_argsfor thatspawn_agent/send_message/followup_taskcall came back empty; otherwisecommunication_from_tool_message(codex-rs/core/src/tools/handlers/multi_agents_v2.rs) takes theInterAgentCommunication::new_encrypted(...)branch, which is the one only a ChatGPT-auth backend can expand. So a static "provider != first-party ChatGPT-auth → fail at spawn" gate would produce false failures for any custom backend whose Responses-compatible endpoint happens to return emptyencrypted_function_argsfor those tool calls (there's an existing report of exactly that working, non-OpenAI-to-non-OpenAI, over on #37858).That changes what a correct spawn-time gate needs to check: not "is auth mode ChatGPT" but "did this session's first collaboration tool call round-trip with a non-empty
encrypted_function_args" — i.e. detect the failure mode after the first turn resolves it, not before spawn, since the client can't know in advance what a custom Responses-compatible server will populate. A pre-spawn static check on provider type would either over-block backends that work today or under-block ones a maintainer hasn't audited.What's still needed from a maintainer: confirm whether
encrypted_function_argsnon-emptiness is intended to be the authoritative provider-capability signal here, or whether there's amodel_providers-level capability field (separate fromrequires_openai_auth) that's supposed to be authoritative instead — and if the latter, that field doesn't appear to be threaded intoToolCall::direct_sourcetoday, which would itself be the gap to close before "document + gate" is implementable as a one-condition check.