Allow custom (non-ChatGPT) model providers to opt into the built-in `image_generation` hosted tool

Open 💬 3 comments Opened May 25, 2026 by gaojian1123

What variant of Codex are you using?

Codex CLI (any 0.12x–0.13x). Applies to anyone running codex with a non-ChatGPT auth, including:

  • bare OPENAI_API_KEY against the OpenAI Responses endpoint
  • custom [model_providers.X] with wire_api = "responses" — Azure OpenAI, OneAPI-style proxies, self-hosted Responses-compatible gateways, GitHub Copilot proxies, etc.

What feature would you like to see?

A per-provider opt-in to expose the built-in image_generation (a.k.a. image_gen) tool, e.g.:

[model_providers.example]
name = "Custom"
base_url = "https://example.com/v1"
wire_api = "responses"

[model_providers.example.capabilities]
image_generation = true   # default: false for non-OpenAI custom providers
namespace_tools  = true
web_search       = true

This is the natural dual of the disabled_capabilities block proposed in #21952 — same mechanism, opposite default. Both can coexist: disabled_capabilities clamps the upper bound, capabilities.* raises it.

Why this matters

The gate at codex-rs/core/src/tools/spec_plan.rs:317 ANDs four conditions before adding image_generation to tools[]:

fn image_generation_tool_enabled(turn_context: &TurnContext) -> bool {
    turn_context.auth_manager.as_deref()
        .is_some_and(AuthManager::current_auth_uses_codex_backend) // ① auth must be ChatGPT
    && turn_context.provider.capabilities().image_generation       // ② provider upper bound
    && turn_context.features.get().enabled(Feature::ImageGeneration) // ③ user toggle
    && turn_context.model_info.input_modalities.contains(&InputModality::Image) // ④ modality
}

Gate ① is:

// codex-rs/login/src/auth/manager.rs
pub fn current_auth_uses_codex_backend(&self) -> bool {
    matches!(self.auth_mode(),
        Some(AuthMode::Chatgpt | AuthMode::ChatgptAuthTokens | AuthMode::AgentIdentity))
}

i.e. AuthMode::ApiKey is hard-coded false, regardless of:

  • [features].image_generation = true in ~/.codex/config.toml (overridden by AND)
  • --enable image_generation (same)
  • the provider actually being able to fulfill image-generation requests through the Responses API

This is asserted by Codex's own unit tests at codex-rs/core/src/tools/spec_plan_tests.rs:920:

let api_key_auth = probe(|turn| {
    set_feature(turn, Feature::ImageGeneration, /*enabled*/ true);
    turn.model_info.input_modalities = vec![InputModality::Image];
    // no use_chatgpt_auth() call → AuthMode::ApiKey
}).await;
api_key_auth.assert_visible_lacks(&["image_generation"]);  // explicitly NOT visible

The user-visible consequence (already documented in #19133, #21640, etc.): Codex loads the bundled imagegen skill (codex-rs/skills/src/assets/samples/imagegen/SKILL.md), the skill tells the model to "use the built-in image_gen tool by default," and the model then can't find the tool — it was never put in tools[]. The model either errors with built-in image_gen tool is not available in this session or falls back to a deterministic placeholder PNG.

Why a server-side advertisement can't fix this

This is a client-side gate that runs before the request is built. The proxy/provider has no way to influence it — no header, no /v1/models capability flag, no response shape can convince Codex to put image_generation in tools[]. Only a config-level opt-in on the Codex side works.

Proposed change

  1. Add an optional capabilities block to ModelProviderInfo deserialization:

``toml
[model_providers.example.capabilities]
image_generation = true
namespace_tools = true
web_search = true
``

  1. When provider_info.capabilities is set, have ConfiguredModelProvider::capabilities() return those values instead of the trait default — exactly the seam AmazonBedrockModelProvider already uses (PR #19442) to clamp capabilities downward.
  2. In image_generation_tool_enabled (and the parallel web_search / namespace_tools checks), replace the current_auth_uses_codex_backend short-circuit with:

``rust
let auth_or_explicit_optin =
turn_context.auth_manager.as_deref()
.is_some_and(AuthManager::current_auth_uses_codex_backend)
|| provider_explicitly_opted_in; // ← user-asserted capability overrides auth gate
`
The intent of gate ① is "don't expose tools the OpenAI-hosted backend implicitly provides when we aren't talking to it." A user explicitly setting
[model_providers.X.capabilities].image_generation = true` is asserting "I know my provider supports this" — the same contract a first-party provider entry implicitly carries.

A more conservative version (no behavior change for current configs, only adds the opt-in path) is to leave gate ① alone for the default case and only OR in the explicit per-provider capability flag.

Related

  • #19133 — symptom report (Azure OpenAI custom provider, Windows/WSL)
  • #21640 — same symptom from a ChatGPT Plus user via custom config
  • #21952 — exact dual: app-server over-emits image_generation to providers that don't support it; the proposed disabled_capabilities slots in here trivially
  • PR #19442 — introduced ProviderCapabilities / ToolCapabilityBounds; this issue asks to expose that abstraction to user config
  • #18307 — OpenRouter rejects Responses payloads with image_generation (same architectural divergence between built-in providers and custom providers)

Workarounds today

  • Sign in with ChatGPT (not viable for users without a ChatGPT plan, or for self-hosted/proxied providers)
  • Use the bundled scripts/image_gen.py CLI fallback (requires OPENAI_API_KEY, can't share auth with the proxy, can't reuse the model's conversation context)
  • Fork Codex and patch the gate

View original on GitHub ↗

3 Comments

yui-stingray · 3 months ago

I checked current main around the hosted tool gating path. One extra boundary to account for here is that image_generation is not only gated by provider capability/config.

In codex-rs/core/src/tools/spec_plan.rs, image_generation_tool_enabled() currently requires all of these before adding the hosted tool:

  • the active auth manager reports current_auth_uses_codex_backend
  • turn_context.provider.capabilities().image_generation
  • the image_generation feature flag is enabled
  • the selected model advertises image input modality support

There is also a regression test in codex-rs/core/src/tools/spec_plan_tests.rs (hosted_tools_follow_provider_auth_model_and_config_gates) that asserts API-key auth does not expose image_generation, while ChatGPT auth with the right feature/model gates does.

So a per-provider opt-in would probably need to define whether it only changes ProviderCapabilities::image_generation, or whether custom Responses-compatible providers can also bypass/replace the current Codex-backend auth requirement. That distinction seems important before wiring a TOML shape such as [model_providers.<id>.capabilities].

matheusgalvao1 · 1 month ago

Confirmed on Codex CLI 0.145.0 on macOS arm64. With API-key auth, $imagegen confidently announced it was using the preferred built-in path, then discovered thatimage_gen was unavailable and hit a dead end. Switching only the authentication to ChatGPT made the identical prompt work.

Codex and the bundled skill appear completely unaware of this auth limitation until after choosing the unavailable tool. +1 for fixing the gate, or at least exposing the limitation upfront.

linshuboy · 21 days ago

Adding context on the user need, independent of any particular implementation.

OpenAI-compatible model providers increasingly expose both the Responses API and the Images API. When a user selects one of these providers, being able to use Codex's built-in image-generation workflow is valuable for the same reasons it is valuable with the first-party provider: the model can request an image in context, receive the generated artifact, and continue the task without a separate tool or credential path.

Today the CLI can load the image-generation workflow while omitting the required tool from the model request. This makes a valid provider capability look like a broken workflow and creates a confusing difference between Codex surfaces.

The desired product behavior is a clear, documented provider capability opt-in for compatible Images API support, with a conservative disabled default and an explicit explanation when the capability is unavailable. The Codex team can choose the configuration shape and implementation that best fits the roadmap.