Skip to content

Commit de35caa

Browse files
authored
feat(images): Grok image bridge (maintainer takeover of lidge-jun#424) (lidge-jun#577)
Credit: @tizerluo for the original feature on lidge-jun#424. Folds stacked lidge-jun#528 hardening and maintainer review/security follow-ups. Reconciled with lidge-jun#355 artifact helpers on latest dev. Closes lidge-jun#424 Closes lidge-jun#528
1 parent 65e3fee commit de35caa

28 files changed

Lines changed: 3865 additions & 104 deletions

docs-site/src/content/docs/guides/codex-integration.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,11 @@ The proxy listens on port `10100` by default and serves `POST /v1/responses`,
3636
Codex's built-in `image_gen` tool does not go through `/v1/responses` — the codex-rs extension
3737
POSTs `{base_url}/images/generations` (or `/images/edits` when reference images are attached)
3838
directly, with the same ChatGPT bearer auth it uses for chat. Because the injected `base_url`
39-
points at opencodex, the proxy relays those calls to the OpenAI upstream:
39+
points at opencodex, the proxy relays those calls to the OpenAI upstream.
40+
41+
This is separate from the [Image Bridge](/guides/image-bridge/), which only activates when a
42+
**Responses** turn lists the hosted `image_generation` tool while a non-OpenAI model is selected.
43+
Standalone `/images/generations` calls never enter that bridge.
4044

4145
- **One mode-aware forward candidate:** Pool selects an eligible main/added account; Direct uses the
4246
caller OAuth bearer. The configured mode applies consistently to the image request.
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
---
2+
title: Image Bridge
3+
description: Route image_generation hosted-tool calls to xAI Grok Imagine when using a non-OpenAI provider.
4+
---
5+
6+
## Overview
7+
8+
When you route Codex through a non-OpenAI model (Claude, Gemini, Grok, etc.), the
9+
`image_generation` **hosted tool** normally doesn't work — it requires OpenAI's server-side
10+
execution environment. The Image Bridge detects these calls and transparently reroutes them to
11+
xAI Grok Imagine, so the model you're actually chatting with can still generate images.
12+
13+
## Prerequisites
14+
15+
- **Enable the bridge** by setting `images.bridgeEnabled: true` in your config (it is off by
16+
default to avoid unexpected xAI charges — see [Configuration](#configuration) below).
17+
- An `xai` provider entry with an **API key**. The bridge pins fulfillment to the registry xAI
18+
Images endpoint (`https://api.x.ai/v1`); any configured `baseUrl` override is ignored for image
19+
calls. OAuth / `ocx login xai` alone does **not** arm the bridge (the Grok CLI OAuth transport is
20+
chat-oriented and is not used for `/images/*`).
21+
22+
```json
23+
{
24+
"providers": {
25+
"xai": { "adapter": "openai-chat", "apiKey": "xai-…", "authMode": "key" }
26+
}
27+
}
28+
```
29+
30+
- A non-OpenAI model selected as your active provider. (When the active provider is OpenAI,
31+
the native hosted tool is used directly and the bridge is bypassed.)
32+
33+
## Configuration
34+
35+
Image Bridge options live under `images` in `~/.opencodex/config.json`. Bridging is
36+
**opt-in** — you must set `bridgeEnabled: true` to enable paid xAI Grok Imagine generation:
37+
38+
```json
39+
{
40+
"images": {
41+
"bridgeEnabled": true,
42+
"bridgeModel": "grok-imagine-image-quality",
43+
"maxRounds": 3,
44+
"timeoutMs": 60000
45+
}
46+
}
47+
```
48+
49+
| Option | Default | Description |
50+
| --- | --- | --- |
51+
| `bridgeEnabled` | `false` | Master switch. Set `true` to enable bridging. Off by default to avoid unexpected xAI charges. |
52+
| `bridgeModel` | `grok-imagine-image-quality` | The xAI image model id to send prompts to. |
53+
| `maxRounds` | `3` | Maximum image-generation loop iterations per turn. Floored to an integer and clamped to `[0, 10]`; non-finite values fall back to `3`. |
54+
| `timeoutMs` | `60000` | Per-call xAI deadline in milliseconds. Finite positive values are floored and passed to the xAI request. |
55+
| `artifactsKeepCount` | `200` | Maximum number of files retained under `artifacts/`. When exceeded, the oldest files are deleted after each fulfilled call. Set to `0` or a negative value to disable pruning. |
56+
57+
## Artifact Retention
58+
59+
Generated images are written to `~/.opencodex/artifacts/`. To prevent unbounded disk
60+
growth in long-running sessions, the directory is pruned automatically after each fulfilled
61+
image call (once the full batch for that call is on disk) — the oldest files (by modification
62+
time) are deleted when the count exceeds the configured maximum (default 200, configurable via
63+
`images.artifactsKeepCount`). Only paths that survive pruning are returned to the model.
64+
65+
## How It Works
66+
67+
The Image Bridge activates only on **Responses** turns that include the hosted
68+
`image_generation` tool in the `/v1/responses` tools array while a **non-OpenAI**
69+
model is selected. It does **not** intercept Codex's built-in `image_gen` tool,
70+
which POSTs directly to `/v1/images/generations` (or `/images/edits`) — that path
71+
is covered separately in [Codex Integration](/guides/codex-integration/#built-in-image-generation-image_gen).
72+
73+
1. When a Responses request lists `image_generation` in `tools`, OpenCodex detects it
74+
during request preprocessing.
75+
2. The hosted tool is replaced with a **synthetic function tool** that the routed model can call
76+
normally — the model sees a callable tool rather than an opaque hosted tool it can't execute.
77+
3. When the model invokes that tool, OpenCodex intercepts the call and sends the prompt to xAI's
78+
image generation API.
79+
4. Generated images are saved to `~/.opencodex/artifacts/` and the **local file path** is returned
80+
to the model as the tool result.
81+
5. The model continues the conversation with knowledge of the generated image and its location.
82+
83+
From the model's perspective nothing changed — it called a tool and got a result. From the user's
84+
perspective, image generation works with any routed provider instead of silently failing.
85+
86+
## Limitations
87+
88+
- **Only xAI Grok Imagine is supported.** DALL-E and other image providers may be added later.
89+
- **Web search takes priority** on adapters that support the web-search sidecar loop. If both web
90+
search and image generation are requested in the same turn, web-search runs and image
91+
generation is skipped. Cursor/`runTurn` adapters cannot use that sidecar today, so the image
92+
bridge may still run for those dual-tool turns.
93+
- **xAI costs apply.** Image generation via xAI requires an active xAI subscription or API credits.
94+
- **Streaming only.** The bridge works by intercepting the SSE response stream; requests with
95+
`stream: false` are rejected with a 400 error.

0 commit comments

Comments
 (0)