Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# wp5 — PR #2986 xAI Imagine image_gen relay (carry of #2083)

State at entry: head `842170b6f`, 25 files +1175/-64, exact-head CI fully green, rebased cleanly onto
`origin/dev` (`6a6efa928`) as `codex/carry-2083-xai-imagine-2` (`b7ad8820c`) with no conflicts.
Reviewer (Ingwannu) confirmed all three code blockers resolved at `842170b6f` and left two
documentation-boundary items before approval. No code redesign requested.

## Scope (docs only)

1. `docs-site/src/content/docs/guides/codex-integration.md` — xAI Imagine relay bullet:
- state that the Grok grant is used only when the `xai` provider has `authMode: "oauth"`
(`resolveXaiImageAuthToken` in `src/images/plan.ts`); any other authMode uses the API key.
- state that an explicit `images.provider` owns `/v1/images` and prevents the xAI fallback.
- result URL contract beside the 100 MiB cap: public HTTPS only, no redirects, no file/loopback,
bounded download (`MAX_DOWNLOAD_BYTES` 50 MiB per file), artifacts served through the
authenticated management endpoint.
2. Same factual sentences in the locale copies of the same bullet (ja/ko/zh-cn/zh-tw/ru/fr/tr) where
the bullet exists, so a translation does not contradict English.
3. Resolve the now-fixed `maxBytes` review thread.

## Acceptance

- English bullet contains: authMode oauth condition, explicit images.provider precedence, URL contract.
- Locales that carry the bullet do not contradict it.
- `bun x tsc --noEmit` and `bun run privacy:scan` clean; focused `tests/server-images.test.ts`,
`tests/responses-parser.test.ts` green (unchanged code, sanity).
- Push `--no-verify` to the same PR branch (force since rebased), admin squash merge, landing proof, close #2083
as landed-via-carry.

Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# wp5 audit r1 — synthesis

Audit input is the maintainer-reviewer's incremental review of exact head `842170b6f` (Ingwannu,
2026-08-31): all three code blockers resolved, focused regressions meaningful, exact-head CI and the
service lifecycle matrix green. Residual: two documentation-boundary items and one review thread to
resolve. Verdict carried as **near-pass**; residuals are the whole of the B scope in 050.

Source verification for the doc sentences (read in this worktree):
- `src/images/plan.ts` `resolveXaiImageAuthToken`: Grok grant only when `authMode === "oauth"`, else API key.
- `src/images/artifacts.ts`: HTTPS-only (`:278`, `:313`), `redirect: "manual"` with 3xx rejected
(`xai-client.ts:124-128`), `MAX_DOWNLOAD_BYTES` 50 MiB default (`:14`, `:281`, `:327`).
- Image-bridge precedence sentence already present and correct; mirror it into codex-integration.

16 changes: 16 additions & 0 deletions docs-site/src/content/docs/guides/codex-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,22 @@ Standalone `/images/generations` calls never enter that bridge.
`openai-responses` provider whose endpoint implements the OpenAI Images API. Explicit selection
fails closed and never falls back to a different paid upstream. Registry-managed provider ids
are not accepted here; omit `images.provider` to use the built-in OpenAI tiers.
- **xAI Imagine (Grok OAuth) relay:** when `images.bridgeEnabled` is `true`, `images.provider` is
omitted, and an `xai` provider is configured, `/v1/images/generations` and `/v1/images/edits`
are sent to `https://api.x.ai/v1`. The credential depends on the provider's `authMode`: with
`"oauth"` the relay reuses the Grok CLI grant from `ocx login xai`; with any other mode it uses
the provider's API key. An OAuth login does not arm a keyed provider, and vice versa. ChatGPT
credentials are not forwarded. If the credential is missing, the proxy returns 400 instead of
billing ChatGPT. Setting `images.provider` explicitly hands `/v1/images` to that provider; its
own validation errors are returned as-is and the xAI relay is never tried.
The relay maps Codex `size` / `aspect_ratio` onto xAI's Imagine body and returns
the same `{created, data:[{b64_json}]}` shape. Combined decoded bytes and base64-encoded output
across the batch (inline `b64_json` and downloaded URLs) stay under 100 MiB; a batch that would
Comment thread
coderabbitai[bot] marked this conversation as resolved.
exceed that cap returns 502. When xAI returns an image URL instead of inline bytes, the proxy
fetches it itself with no credential: the URL must be public HTTPS (no redirects, no
`file:`, no loopback or private addresses), each download is capped at 50 MiB, and the result is
materialized as a local artifact that is served only through the authenticated management
endpoint. This is independent of the Responses Image Bridge loop (which remains API-key-only).
- **Google Antigravity (CCA) fallback:** when neither an OpenAI forward candidate nor a keyed
provider is configured, `/v1/images/generations` (not `/images/edits`) falls back to the
Antigravity **Cloud Code Assist** endpoint using the `gemini-3.1-flash-image` model. The fallback
Expand Down
17 changes: 13 additions & 4 deletions docs-site/src/content/docs/guides/image-bridge.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,19 @@ xAI Grok Imagine, so the model you're actually chatting with can still generate

- **Enable the bridge** by setting `images.bridgeEnabled: true` in your config (it is off by
default to avoid unexpected xAI charges — see [Configuration](#configuration) below).
- An `xai` provider entry with an **API key**. The bridge pins fulfillment to the registry xAI
Images endpoint (`https://api.x.ai/v1`); any configured `baseUrl` override is ignored for image
calls. OAuth / `ocx login xai` alone does **not** arm the bridge (the Grok CLI OAuth transport is
chat-oriented and is not used for `/images/*`).
- An `xai` provider entry with an **API key**. The Responses Image Bridge pins fulfillment to the
registry xAI Images endpoint (`https://api.x.ai/v1`); any configured `baseUrl` override is
ignored for image calls. OAuth / `ocx login xai` alone does **not** arm this sidecar loop.
The same `bridgeEnabled` flag does arm the separate Codex `/v1/images` relay so the built-in
`image_gen` client can call Imagine with the Grok CLI grant — see
[Built-in image generation](/guides/codex-integration/#built-in-image-generation-image_gen).
If that grant (or an xAI API key) is missing, `/v1/images` returns an error instead of
falling through to ChatGPT.

The relay only owns the route when no image provider is configured: it runs when
`images.bridgeEnabled` is `true` **and** `images.provider` is omitted. Setting
`images.provider` explicitly hands `/v1/images` to that provider, and its own
validation errors are returned as-is rather than being retried through xAI.

```json
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ Codex の組み込み `image_gen` ツールは、`/v1/responses` を経由しま
失敗。壊れた/期限切れのプール認証情報が、別途請求される API 使用量の背後に隠れることはありません。
- **明示的なカスタム プロバイダー:** `images.provider` をカスタム API キーの ID に設定します。
`openai-responses` プロバイダー。そのエンドポイントは OpenAI Images API を実装します。明示的な選択はクローズに失敗し、別の有料アップストリームにフォールバックすることはありません。レジストリで管理されているプロバイダー ID はここでは受け入れられません。組み込みの OpenAI 層を使用するには、`images.provider` を省略します。
- **xAI Imagine (Grok OAuth) リレー:** `images.bridgeEnabled` が `true` で、`images.provider` が未設定、かつ `xai` プロバイダーが設定されている場合、`/v1/images/generations` と `/v1/images/edits` は `https://api.x.ai/v1` に送られます。使われる資格情報はプロバイダーの `authMode` で決まります。`"oauth"` なら `ocx login xai` の Grok CLI グラントを再利用し、それ以外ならプロバイダーの API キーを使います。OAuth ログインがキー方式のプロバイダーを有効にすることはなく、その逆もありません。ChatGPT の資格情報は転送されません。資格情報が無い場合、プロキシは ChatGPT に課金せず 400 を返します。`images.provider` を明示すると `/v1/images` はそのプロバイダーが受け持ち、その検証エラーがそのまま返され、xAI リレーは試行されません。リレーは Codex の `size` / `aspect_ratio` を xAI Imagine のボディに写し、同じ `{created, data:[{b64_json}]}` 形を返します。バッチ全体(インライン `b64_json` とダウンロードした URL)のデコード済みバイトと base64 エンコード出力は合わせて 100 MiB 未満です。上限を超えるバッチは 502 を返します。xAI がインラインのバイト列ではなく画像 URL を返した場合、プロキシは資格情報なしで自ら取得します。URL は公開 HTTPS でなければならず(リダイレクト、`file:`、ループバックやプライベートアドレスは不可)、1 ファイルあたり 50 MiB が上限で、結果はローカルのアーティファクトとして保存され、認証済みの管理エンドポイント経由でのみ配信されます。これは API キー専用の Responses Image Bridge ループとは独立です。
- **Google Antigravity (CCA) フォールバック:** OpenAI 前方候補でもキー付きでもない場合
プロバイダーが構成されている場合、`/v1/images/generations` (`/images/edits` ではありません) は、`gemini-3.1-flash-image` モデルを使用して Antigravity **Cloud Code Assist** エンドポイントにフォールバックします。フォールバックは、OpenAI 候補が構成されていない場合だけでなく、OpenAI 認証の解決が失敗した後 (ChatGPT 資格情報の期限切れまたは欠落など) にも起動されます。これには `ocx login google-antigravity` が必要です。 OAuth トークンは、固定された CCA レジストリ ホストにのみ送信され、構成レベルの `baseUrl` オーバーライドには送信されません。応答は、Codex が期待するのと同じ `{created, data:[{b64_json}]}` 形状で返されます。
- **どちらでもない:** プロキシは一般的な 404 ではなく明確なエラーを返します。 ルーティングされたプロバイダー
Expand Down
2 changes: 1 addition & 1 deletion docs-site/src/content/docs/ja/guides/image-bridge.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ OpenAI 以外のモデル (Claude、Gemini、Grok など) を介して Codex を
- **設定で `images.bridgeEnabled: true` を設定してブリッジを有効にします** (これはオフになっています)
予期しない xAI 請求を避けるためのデフォルト — 以下の [構成](#configuration) を参照してください)。
- **API キー**を持つ `xai` プロバイダー エントリ。ブリッジはフルフィルメントをレジストリ xAI に固定します
画像エンドポイント (`https://api.x.ai/v1`);設定された `baseUrl` オーバーライドは、イメージ呼び出しでは無視されます。 OAuth / `ocx login xai` だけではブリッジを準備しません** (Grok CLI OAuth トランスポートはチャット指向であり、`/images/*` には使用されません)
画像エンドポイント (`https://api.x.ai/v1`);設定された `baseUrl` オーバーライドは、イメージ呼び出しでは無視されます。 OAuth / `ocx login xai` だけではこのサイドカー・ループは有効になりません。同じ `bridgeEnabled` フラグは、別系統の Codex `/v1/images` リレーを有効にし、組み込みの `image_gen` クライアントが Grok CLI の認可で Imagine を呼べるようにします。認可(または xAI API キー)が無い場合、`/v1/images` は ChatGPT にフォールスルーせずエラーを返します。詳細は [組み込み画像生成](/guides/codex-integration/#built-in-image-generation-image_gen) を参照してください。このリレーが経路を持つのは、`images.bridgeEnabled` が `true` で、かつ `images.provider` が未指定のときだけです。`images.provider` を明示すると `/v1/images` はそのプロバイダーが担当し、そのバリデーションエラーは xAI で再試行されずそのまま返ります

「`json { "providers": { "xai": { "adapter": "openai-chat", "apiKey": "xai-…", "authMode": "key" } } } `」

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ Codex의 내장 `image_gen` 도구는 `/v1/responses`를 거치지 않습니다.
- **모드 인식 forward 후보 하나:** Pool은 적격한 메인/추가 계정을 선택하고, Direct는 호출자 OAuth bearer를 사용합니다. 설정된 모드는 이미지 요청에도 일관되게 적용됩니다.
- **OpenAI API-key provider:** forward 후보 중 누구도 인증 실패를 가지지 않을 때만 사용합니다. 고장 나거나 만료된 Pool credential을 별도로 청구되는 API 사용 뒤에 숨기지 않습니다.
- **명시적 커스텀 provider:** `images.provider`를 OpenAI Images API를 구현한 커스텀 API-key `openai-responses` provider id로 설정할 수 있습니다. 명시적으로 선택한 provider는 닫힌 상태로 실패하며, 다른 유료 upstream으로 fallback하지 않습니다. registry-managed provider id는 여기서 허용하지 않습니다. 기본 제공 OpenAI tiers를 쓰려면 `images.provider`를 생략하세요.
- **xAI Imagine (Grok OAuth) relay:** `images.bridgeEnabled`가 `true`이고 `images.provider`가 비어 있으며 `xai` provider가 설정되어 있으면 `/v1/images/generations`와 `/v1/images/edits`가 `https://api.x.ai/v1`로 전송됩니다. 어떤 credential을 쓰는지는 provider의 `authMode`가 정합니다. `"oauth"`면 `ocx login xai`로 받은 Grok CLI grant를 재사용하고, 그 외에는 provider의 API key를 씁니다. OAuth 로그인이 key 방식 provider를 활성화하지는 않으며 반대도 마찬가지입니다. ChatGPT credential은 전달되지 않습니다. credential이 없으면 프록시는 ChatGPT에 과금하지 않고 400을 반환합니다. `images.provider`를 명시하면 `/v1/images`는 그 provider가 맡고, 그 provider의 검증 오류가 그대로 반환되며 xAI relay는 시도되지 않습니다. relay는 Codex `size` / `aspect_ratio`를 xAI Imagine body에 매핑하고 같은 `{created, data:[{b64_json}]}` 형태를 반환합니다. 배치 전체(인라인 `b64_json`과 내려받은 URL)의 디코드 바이트와 base64 인코드 출력은 합쳐서 100 MiB 미만입니다. 한도를 넘는 배치는 502를 반환합니다. xAI가 인라인 바이트 대신 이미지 URL을 돌려주면 프록시가 credential 없이 직접 내려받습니다. URL은 공개 HTTPS여야 하고(리다이렉트, `file:`, loopback·사설 주소 불가), 파일당 50 MiB 상한이 있으며, 결과는 로컬 artifact로 저장되어 인증된 management endpoint로만 제공됩니다. 이 경로는 API-key-only Responses Image Bridge 루프와 별개입니다.
- **Google Antigravity (CCA) fallback:** OpenAI forward 후보도 keyed provider도 없을 때, `/v1/images/generations`(`/images/edits`는 제외)는 `gemini-3.1-flash-image` 모델을 사용해서 Antigravity **Cloud Code Assist** endpoint로 fallback합니다. OpenAI 인증 해석이 실패할 때(예: 만료되었거나 누락된 ChatGPT credential)에도 이 fallback이 동작하며, OpenAI 후보가 아예 없을 때만 발생하는 것은 아닙니다. 이 기능은 `ocx login google-antigravity`를 필요로 합니다. OAuth token은 오직 고정된 CCA registry host로만 전송되며, config-level `baseUrl` override로는 가지 않습니다. 응답은 Codex가 기대하는 `{created, data:[{b64_json}]}` 형식으로 반환됩니다.
- **둘 다 없음:** 프록시는 generic 404 대신 명확한 오류를 반환합니다. 라우팅되는 provider(Cursor, Gemini, Kiro 등)는 `image_generation` tool relay를 제공할 수 없습니다. 이 도구를 아예 노출하고 싶지 않다면 Codex에서 `codex features disable image_generation`(`config.toml`의 `[features] image_generation = false`)으로 끄세요.

Expand Down
2 changes: 1 addition & 1 deletion docs-site/src/content/docs/ko/guides/image-bridge.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Codex를 Claude, Gemini, Grok 같은 OpenAI가 아닌 모델로 라우팅하면
## 사전 조건

- 구성에서 `images.bridgeEnabled: true`로 설정해 브리지를 켭니다. 예상치 못한 xAI 요금을 피하려고 기본값은 꺼져 있습니다. 아래 [Configuration](#configuration)을 참고합니다.
- API 키가 있는 `xai` provider 항목이 필요합니다. 브리지는 처리를 레지스트리의 xAI Images endpoint (`https://api.x.ai/v1`)에 고정하며, 이미지 호출에서는 설정된 `baseUrl` override를 무시합니다. OAuth / `ocx login xai`만으로는 브리지가 활성화되지 않습니다. Grok CLI OAuth transport는 채팅용이며 `/images/*`에는 사용되지 않습니다.
- API 키가 있는 `xai` provider 항목이 필요합니다. 브리지는 처리를 레지스트리의 xAI Images endpoint (`https://api.x.ai/v1`)에 고정하며, 이미지 호출에서는 설정된 `baseUrl` override를 무시합니다. OAuth / `ocx login xai`만으로는 이 sidecar 루프가 켜지지 않습니다. 같은 `bridgeEnabled` 플래그는 별도의 Codex `/v1/images` relay를 켜서, 내장 `image_gen` 클라이언트가 Grok CLI grant로 Imagine을 호출할 수 있게 합니다. 그 grant(또는 xAI API key)가 없으면 `/v1/images`는 ChatGPT로 넘어가지 않고 오류를 반환합니다. 이 relay가 경로를 맡는 건 `images.bridgeEnabled`가 `true`이고 `images.provider`를 비워둔 경우뿐입니다. `images.provider`를 지정하면 `/v1/images`는 그 provider가 담당하고, 그쪽 검증 오류는 xAI로 재시도하지 않고 그대로 반환합니다. [Built-in image generation](/guides/codex-integration/#built-in-image-generation-image_gen)을 참고하세요.

```json
{
Expand Down
Loading
Loading