fix(server): relay /v1/images to an OpenAI upstream for built-in image_gen - #87
Merged
Conversation
…e_gen (#83) codex-rs's standalone image_gen extension POSTs {base_url}/images/generations (and /images/edits) client-side with its ChatGPT bearer auth. Under Design B injection base_url is the proxy, so the call died on the /v1/* JSON-404 guard: "Unknown endpoint: POST /v1/images/generations". codex 0.144.0 made the tool stable/default-on, so ChatGPT users now hit this organically. Add POST /v1/images/{generations,edits} (src/server/images.ts), relaying the body verbatim to the ChatGPT forward provider (caller bearer or routed pool token; pool outcomes recorded) with fallback to a keyed openai-responses provider, and an honest 400 when neither exists (4xx, not 5xx — codex retries every 5xx up to 5 attempts). The forward candidate is only used when the request carries a relayable bearer (startServer auto-upserts the chatgpt provider, so presence proves nothing), forward-auth failures fall back to the keyed provider before surfacing, and a bearer matching the proxy's own admission secret is never relayed upstream. Client cancel maps to 499, upstream hang to 504 after config.images.timeoutMs (default 300s). Closes #83 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #83.
Problem
Codex's built-in
image_gentool failed instantly with:The 404 is opencodex's own
/v1/*data-plane guard. codex-rs's standalone image-generation extension executes client-side: it POSTs{base_url}/images/generations(/images/editswhen reference images are attached) with the same ChatGPT bearer auth it uses for chat. Under Design B injectionbase_urlis the proxy, and no route existed — the path was even test-pinned as an intentional 404.Why reports started now: codex 0.144.0 graduated
image_generationfrom the disabled-by-defaultimagegenextexperiment to stable / default-enabled, so ChatGPT-signed-in users hit the tool organically. (The hostedimage_generationentry intools[]on/v1/responseswas never affected — passthrough already forwards it; only the extension's direct REST call 404'd.)Fix
New relay route
POST /v1/images/{generations,edits}(src/server/images.ts), inserted before the/v1/*guard with the standard data-plane preamble (drain 503,requireApiAuth, origin check,withCors, request log incl.client_cancelmeta).Upstream selection:
resolveCodexAuthContext/headersForCodexAuthContext); pool upstream outcomes are recorded for rotation failover.startServerauto-upserts achatgptforward entry into every config, so its presence proves nothing; without this gate an unauthenticated request bounces off chatgpt.com as an opaque{"detail":"Unauthorized"}.Authorization: Bearer $OPENCODEX_API_AUTH_TOKEN) is stripped and never relayed to chatgpt.com.openai-responsesprovider (e.g.api.openai.com) — URL normalized like the adapter (baseUrlwith or without/v1both work).codex features disable image_generation). 4xx, not 5xx, because codex retries every 5xx up to 5 total attempts and this is a permanent config state.Relay:
readJsonRequestBody(zstd/gzip + 256MB cap) →fetchWithResetRetrywithconfig.images.timeoutMs(default 300s) linked to client abort → response passed through status+content-type+body verbatim so upstream plan-gating errors stay legible to codex (it Debug-prints the body into the model-visible failure). Client cancel → 499, upstream hang → 504.Docs: endpoint lists + new "Built-in image generation" section in the codex-integration guide (en/ko/zh-cn) and architecture reference (en/ko/zh-cn). Design notes in
devlog/260710_issue83_images_endpoint/.Tests
tests/server-images.test.ts: forward relay (auth/path/body), edits path, pool-token override (caller bearer must not leak), zstd decode, keyed fallback +/v1normalization, unauthenticated-request gate, forward-auth-failure fallback, no-upstream 400, upstream error passthrough, 504 timeout, GET→404 guard, non-loopback auth/origin, admission-secret never relayed.tests/server-auth.test.ts404-guard list swaps/v1/images/generationsfor/v1/realtime/sessions.tsc --noEmitclean.🤖 Generated with Claude Code