Repository navigation
fix(providers): route Codex GPT Image models to dedicated Images API - #14976
Conversation
Codex image generation went through /backend-api/codex/responses with the hosted image_generation tool. The backend pins that tool to gpt-image-2-codex regardless of the requested model, so GPT Image 2.5 was unreachable, and the chat model that must call the tool can decline, which surfaced as "502 Codex completed without producing an image_generation_call". Codex CLI (openai/codex#23989) uses dedicated unary routes instead: POST {codex}/images/generations and POST {codex}/images/edits, which take the image model as a request field. Route `gpt-image-*` Codex ids there: - add codex/gpt-image-2.5-flare and codex/gpt-image-2 to the Codex image catalog; the codex/gpt-5.6-*-image ids stay on the hosted tool unchanged - new codexImages.ts builds the typed request (model, n=1, size, quality, background, images[] for edits), fans out n>1, keeps the free-plan skip, the retryable model-access 400, error sanitization and the b64_json/url defaults (cheaper-inference#12268), and passes the upstream usage block through - edits reuse the same path via handleCodexImageEdit Tests drive the handler, /v1/images/generations and /v1/images/edits with a mocked upstream; disabling the new dispatch fails 5 of the 6 new tests.
|
I reviewed the exact Draft head
I ran a three-case regression against that exact head in an isolated detached worktree with a mocked upstream: 0/3 pass. The |
|
Re-homed to |
# Conflicts: # open-sse/handlers/imageGeneration.ts
…spatch (cheaper-inference#14976) Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
25196cb
into
cheaper-inference:release/v3.8.52
* test(translator): expect boolean is_error on tool_result blocks (#15754) #15754 made the OpenAI-to-Messages translator always emit a boolean is_error on every tool_result block (strict upstreams such as the Zed hosted proxy reject requests without it). The older multimodal translation test still pinned the block shape without the field. * test(images): include Codex GPT Image models in the image catalog listing (#14976) #14976 registered gpt-image-2.5-flare and gpt-image-2 under the codex image provider (routed to the dedicated Codex Images API) and updated the registry test to the five-id list, but the image catalog route test still pinned the three GPT-5.6 hosted-tool ids. * docs(flags): keep RATE_LIMIT_AUTO_ENABLE catalog default in sync with its definition #15736 changed the catalog Default cell to _(unset)_, but the catalog documents FEATURE_FLAG_DEFINITIONS 1:1 and the definition (what the feature-flags API/UI resolves when nothing is set) is still "false". Restore the code value and keep the corrected runtime explanation in the description: rateLimitManager reads only the env var and falls back to the dashboard setting (default on) when it is unset. * test(combos): pin on-demand per-candidate reads on the tables #15378 left unmemoized #15353 added a contrast test asserting the on-demand capability path re-reads the synced catalog per candidate (>50 reads). #15378, merged just before it, memoized the synced vision verdict behind the catalog version, so that path now issues 7 synced reads and the contrast went red on the tip. Keep the contrast on the capability and override tables (still thousands of per-candidate reads on demand vs <=2 / bounded on the snapshot route) and pin the memo itself: synced reads stay within the per-provider bound. With the pre-#15378 module the new assertion fails (336 synced reads). * test(chatcore): end the prompt-cache fixture on a user turn (#15830) #15830 re-landed #13572: the first-party Messages provider now strips a trailing text-only assistant turn (upstream rejects assistant prefill). The prompt-cache metadata fixture ended on an assistant text block carrying a cache_control breakpoint, so the strip dropped it and the recorded totalBreakpoints fell from 3 to 2. Append a user turn so the fixture still exercises system, user and assistant breakpoints; the assertions are unchanged. * fix(providers): keep discovered Codex effort variants in the exclusive dashboard listing #13224 lists one <model>-<tier> row per reasoning level the Codex account advertises (appendSyncedEffortVariants, non-exclusive branch). #15132 then made Codex an exclusive synced-listing provider, and the exclusive branch returns before that step, so the provider dashboard / Test All listing lost the discovered tier rows while /v1/models still advertised them (cx/<model>-max). Apply the same variant step on the exclusive branch for codex. The variants come from the live inventory, so #15132's contract (no static aliases the account does not advertise) still holds; its own tests stay green. The one assertion in codex-discovered-reasoning that expected a static registry-only row (gpt-5.6-sol-ultra) next to the live inventory is flipped to #15132's contract. * test(providers): keep the custom gpt-6 max_tokens case on an unregistered id (#15164) The #14869 custom-model case used gpt-6-luna because it was not in the openai registry, so it stayed on Chat Completions and had to be renamed to max_completion_tokens. #15164 registered gpt-6-luna with targetFormat openai-responses, so the request now goes through the Responses translator (max_output_tokens) and the Chat Completions assertion read undefined. Use an unregistered gpt-6 id for the custom-model case and add a case for the registered gpt-6-luna Responses path (max_output_tokens, no max_tokens). * chore(changelog): add fragment for the v3.8.52 tip unit-red drain
Summary
Refs #14617.
Codex GPT Image models now use the dedicated Codex Images API routes instead of the Responses hosted
image_generationtool:gpt-image-*generation →/backend-api/codex/images/generations/backend-api/codex/images/editsmodelis forwarded unchangedusageis preserved on the internal result for the follow-up usage-accounting slice*-imagecatalog entries remain on the hosted Responses tool pathThis removes the hosted-tool failure mode where the backend pins the image model to
gpt-image-2-codexand where the chat model can decline to call the tool. It does not claim that the backend's output alone proves which image model served a request; the fix establishes the correct dedicated route and request model contract.The implementation keeps the existing Codex free-plan guard, sibling-account retry classification, error sanitization, response defaults, reference-image handling, and
n>1fan-out. Fan-out is capped at 10 per request, and response-body read failures become a controlled 502 instead of escaping as an unhandled exception.Tests
Focused suite on the exact
release/v3.8.51-rebased candidate:Also passed:
changelog.d/fixes/14976-codex-dedicated-images.mdFocused coverage includes generation,
n>1, response formatting, free-plan/access errors, sanitization, unreadable response bodies, multipart reference edits, route dispatch, and preservation of the GPT-5.6 hosted-tool path.Boundary
sizeremains forwarded but is not asserted as a backend guarantee: the Codex Images backend chooses the actual output dimensions, as documented in the linked issue evidence.