`app-server` ignores `[features].image_generation = false` and `--disable image_generation` (only `exec` honors them)
Summary
On 0.130.0, codex exec correctly omits the built-in image_generation tool from the /v1/responses request when it is disabled via [features] or --disable image_generation, but codex app-server (which is what the VSCode openai.chatgpt extension launches) keeps emitting {"type":"image_generation"} (and {"type":"web_search"}) in tools[] regardless of either knob. For users on Responses-compatible third-party providers (OneAPI-style proxies, Azure groups without image gen, etc.) this produces an unrecoverable 403 Forbidden: Image generation is not enabled for this group on every turn through the IDE extension while the CLI works fine.
Environment
- codex-cli:
0.130.0(npm@openai/codex, bundledlinux-x64-muslbinary; both reportcodex-cli 0.130.0) - VSCode extension (the IDE plugin launching app-server):
openai.chatgptv26.506.31421(engines.vscode: ^1.96.2) - VSCode:
1.119.0(commit8b640eef5a6c6089c029249d48efa5c99adf7d51, x64) - OS: Linux x86_64
- Provider: a third-party OneAPI-compatible deployment,
wire_api = "responses" - Default
chatgpt.cliExecutable: "codex". Spawn observed viaps:
````
codex --disable image_generation app-server --analytics-default-enabled
codex --disable image_generation app-server --listen unix://
Reproduction
- Configure a custom provider with
wire_api = "responses"whose upstream account does not allow image generation (any OneAPI deployment with image gen disabled reproduces this; OpenRouter behaves similarly per #18307). - Set:
``toml`
[features]
image_generation = false
`
Confirm:
``
$ codex features list | grep image_generation
image_generation stable false
- CLI path (works):
```
$ codex exec "hello"
Hello.
tools[]
Captured request: does **not** contain image_generation`.
- App-server path (broken):
- Trigger any message from the VSCode extension, OR run
codex app-server --analytics-default-enabledand drive it. - Whether or not
--disable image_generationis on the command line, the capturedPOST /v1/responsesbody contains:
``json``
"tools": [
…,
{ "type": "web_search" },
{ "type": "image_generation" },
…
]
- Server returns
403 {"error":{"message":"Image generation is not enabled for this group","type":"permission_error"}}.
Evidence (network capture)
mitmdump in reverse-proxy mode in front of the upstream, with [model_providers.<name>].base_url redirected to the local proxy. Identical session, single user message "hello":
| codepath | tools.length | image_generation in tools[] | result |
|---|---|---|---|
| codex exec | 14 | no | 200 OK |
| codex app-server with [features].image_generation=false | 16 | yes | 403 |
| codex --disable image_generation app-server … | 16 | yes | 403 |
Confirmed via ps -o cmd that --disable image_generation is in fact present on the spawned app-server process; it just doesn't propagate to the Responses tool builder.
Root-cause guess
PR #19442 ("feat: disable capabilities by model provider") routes built-in tool selection for Responses through ProviderCapabilities / ToolCapabilityBounds. The bounds appear to be hard-coded for first-party providers only; user-defined providers fall through to the default "all caps allowed", which silently overrides [features].image_generation = false on the app-server path. PR #20049 only exposes the same bounds to app-server clients; it doesn't extend them to user providers. The CLI --disable flag and [features] setting flow into the session/exec tool builder, not into ToolCapabilityBounds. Net effect: two separate sources of truth for "is this tool allowed", and only one is reachable from user config.
Expected behavior
[features].image_generation = false (or --disable image_generation) should suppress the {"type":"image_generation"} entry from tools[] regardless of subcommand and regardless of whether the provider is a built-in.
Suggested fix (any one of these would unblock)
- Have the
app-serverResponses request builder consult[features]/ the--disableset with the same precedence asexecdoes — or have ToolCapabilityBounds intersect with[features]before the request is built. - Allow user providers to set their own bounds, e.g.:
``toml``
[model_providers.example]
disabled_capabilities = ["image_generation", "web_search"]
This also addresses #6049 (disable built-in tools) and #18307 (third-party Responses providers rejecting built-ins).
- Honor
--disable image_generation/--disable web_searchoncodex app-serverdirectly.
Related
- #19442 – disable capabilities by model provider (introduced the divergent codepath)
- #20049 – expose provider capability bounds to app-server clients
- #6049 – feature request: disable built-in tools for MCP-only execution
- #18307 – OpenRouter rejects Responses payloads with
image_generation/web_search(same class of failure) - #19133 – inverse case (image gen unavailable on Azure exec)
Workaround currently used
Local mitmproxy reverse proxy that strips {"type":"image_generation"} (and optionally web_search) from tools[] of POST /v1/responses before forwarding upstream, with [model_providers.<name>].base_url pointed at the local proxy. Works but is not something users should have to deploy.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗