codex-grok-bridge 1.0.2 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +554 -86
- package/package.json +1 -1
- package/src/imagegen.mjs +6 -2
package/README.md
CHANGED
|
@@ -1,163 +1,631 @@
|
|
|
1
1
|
# codex-grok-bridge
|
|
2
2
|
|
|
3
|
-
Run **Grok 4.6 as the model inside Codex
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
Run **Grok 4.6 as the model inside Codex**. Codex still owns tools, permissions,
|
|
4
|
+
history and MCP. Inference uses the installed `grok` CLI login session — not an
|
|
5
|
+
xAI API key.
|
|
6
|
+
|
|
7
|
+
Codex 안에서 **Grok 4.6**을 모델로 씁니다. 도구·권한·히스토리·MCP는 Codex가
|
|
8
|
+
그대로 가집니다. 추론은 설치된 `grok` CLI의 로그인 세션으로 하며 `XAI_API_KEY`는
|
|
9
|
+
쓰지 않습니다.
|
|
6
10
|
|
|
7
11
|
```
|
|
8
|
-
Codex UI/CLI → app-server → codex-wrapper.mjs (adds grok-4.6 to the model list)
|
|
12
|
+
Codex UI/CLI → app-server → scripts/codex-wrapper.mjs (adds grok-4.6 to the model list)
|
|
9
13
|
→ localhost /v1/responses (the bridge)
|
|
10
14
|
→ cli-chat-proxy.grok.com
|
|
11
15
|
→ Codex executes every tool call; results return as the next input
|
|
12
16
|
```
|
|
13
17
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
18
|
+
The published package is **macOS-only** (`"os": ["darwin"]`). Linux and Windows
|
|
19
|
+
installs are rejected by npm.
|
|
20
|
+
|
|
21
|
+
게시된 패키지는 **macOS 전용**입니다(`"os": ["darwin"]`). Linux·Windows는 npm이
|
|
22
|
+
설치를 거절합니다.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
# English
|
|
27
|
+
|
|
28
|
+
## What this is
|
|
29
|
+
|
|
30
|
+
A local bridge that puts Grok 4.6 on Codex’s model list and sends Codex
|
|
31
|
+
`/v1/responses` traffic to `cli-chat-proxy.grok.com`. Grok does the inference.
|
|
32
|
+
Codex runs every tool call (shell, patch, MCP, …) and feeds the results back as
|
|
33
|
+
the next request’s `input`. That is the same agent loop as the GPT path.
|
|
34
|
+
|
|
35
|
+
The bridge does **not** execute Grok-native tools. It translates Codex tools into
|
|
36
|
+
function calling, streams the upstream Responses events, and rewrites names back
|
|
37
|
+
so Codex still recognizes them.
|
|
38
|
+
|
|
39
|
+
Thirteen files under `src/`. Zero runtime dependencies. Node.js ≥ 22.
|
|
17
40
|
|
|
18
|
-
|
|
41
|
+
This is not a second-opinion review product, not a Grok 4.7 adapter, and not a
|
|
42
|
+
Grok-native search product. If Codex exposes a web-search tool, Grok can call
|
|
43
|
+
that tool the same way it calls any other Codex tool.
|
|
44
|
+
|
|
45
|
+
## Requirements
|
|
46
|
+
|
|
47
|
+
- macOS
|
|
48
|
+
- Node.js ≥ 22
|
|
49
|
+
- `/Applications/Codex.app`
|
|
50
|
+
- `grok` CLI at `~/.grok/bin/grok`
|
|
51
|
+
- a completed `grok login`
|
|
52
|
+
|
|
53
|
+
The `.command` launcher resolves paths from its own location, so moving the
|
|
54
|
+
folder does not require edits. Set `NODE=/path/to/node` if `node` is not on
|
|
55
|
+
`PATH`.
|
|
56
|
+
|
|
57
|
+
Verified against: Codex 0.153.4 / app 26.901.51231, Grok CLI 1.0.24, Node 22.23.0.
|
|
58
|
+
An app update that changes `CODEX_CLI_PATH` or the app-server protocol needs
|
|
59
|
+
re-verification.
|
|
60
|
+
|
|
61
|
+
## Install and run
|
|
62
|
+
|
|
63
|
+
### Terminal (npm)
|
|
19
64
|
|
|
20
65
|
```sh
|
|
21
66
|
npm install -g codex-grok-bridge # macOS, Node ≥ 22
|
|
22
|
-
codex-grok # Codex
|
|
67
|
+
codex-grok # launches Codex with Grok 4.6 available
|
|
68
|
+
codex-grok exec --skip-git-repo-check --sandbox workspace-write 'your task'
|
|
23
69
|
```
|
|
24
70
|
|
|
25
|
-
|
|
71
|
+
`codex-grok` registers the bridge as a model provider for the Codex process it
|
|
72
|
+
starts, and tears the provider down with that process.
|
|
73
|
+
|
|
74
|
+
### From a checkout
|
|
26
75
|
|
|
27
76
|
```sh
|
|
28
77
|
git clone https://github.com/deximple/codex-grok-bridge.git
|
|
29
78
|
cd codex-grok-bridge
|
|
30
|
-
npm test #
|
|
79
|
+
npm test # 132 tests, no network, no inference
|
|
31
80
|
node scripts/codex-grok.mjs
|
|
32
81
|
```
|
|
33
82
|
|
|
34
|
-
|
|
35
|
-
|
|
83
|
+
### Desktop
|
|
84
|
+
|
|
85
|
+
Double-click **Open Codex with Grok.command** in this folder, or keep a
|
|
86
|
+
**separate** `Codex Grok.app` in sync with
|
|
87
|
+
`scripts/install-codex-grok-app.sh` (see [Desktop install and update](#desktop-install-and-update)).
|
|
88
|
+
|
|
89
|
+
In the new Codex window, **select Grok 4.6 / xAI before starting a new
|
|
90
|
+
thread**. Existing GPT models stay on the list. A Codex window that was already
|
|
91
|
+
open does not get this extension.
|
|
92
|
+
|
|
93
|
+
The dedicated window stores UI data under
|
|
94
|
+
`~/.local/share/codex-grok-bridge/desktop` and **shares** the normal Codex home
|
|
95
|
+
for account, threads and settings. Work and setting changes can show up in other
|
|
96
|
+
Codex windows.
|
|
97
|
+
|
|
98
|
+
The installer never writes the stock Codex.app bundle, its signature,
|
|
99
|
+
`~/.codex/config.toml`, or Grok auth files. It does not register a launch
|
|
100
|
+
agent or a global environment variable.
|
|
101
|
+
|
|
102
|
+
Stop by closing the Codex window this extension opened. Ordinary Codex still
|
|
103
|
+
launches from its usual icon.
|
|
104
|
+
|
|
105
|
+
## How it connects
|
|
106
|
+
|
|
107
|
+
1. A wrapper set as `CODEX_CLI_PATH` starts the Codex app-server.
|
|
108
|
+
2. The wrapper adds Grok to the model catalog and sets the provider of a new
|
|
109
|
+
Grok thread to `grok_build_cli`.
|
|
110
|
+
3. Codex `/v1/responses` requests go to the localhost bridge.
|
|
111
|
+
4. The bridge flattens Codex tools (plain functions, namespaced functions,
|
|
112
|
+
freeform custom tools, `web_search`) into function tools, then pipes the
|
|
113
|
+
`cli-chat-proxy.grok.com` Responses stream through.
|
|
114
|
+
5. Tool results return as the next Codex request `input`.
|
|
115
|
+
|
|
116
|
+
Authentication is the `grok login` session. `XAI_API_KEY` is not used.
|
|
117
|
+
|
|
118
|
+
Upstream sockets use `node:http(s)` with a keep-alive `Agent` (30 s, max 4
|
|
119
|
+
sockets) and a 5-minute DNS cache. A failed lookup still uses a valid cached
|
|
120
|
+
address when one exists, so a 5–20 s tool gap does not force a fresh name
|
|
121
|
+
lookup every time. `GROK_BRIDGE_TRANSPORT=fetch` restores the older `fetch`
|
|
122
|
+
path.
|
|
123
|
+
|
|
124
|
+
A request that dies **before** the first SSE block is written to Codex is
|
|
125
|
+
retried once. After the first block, the bridge never retries — Codex already
|
|
126
|
+
saw bytes, so a replay would duplicate them. Deterministic refusals (422) and
|
|
127
|
+
user aborts are not retried either.
|
|
128
|
+
|
|
129
|
+
If the Responses path misbehaves, `GROK_BRIDGE_INFERENCE=cli` falls back to the
|
|
130
|
+
older CLI envelope. That path pastes the whole JSON into a prompt each turn, so
|
|
131
|
+
it is slower and more expensive, has no token-by-token streaming, and is capped
|
|
132
|
+
at three minutes per request.
|
|
133
|
+
|
|
134
|
+
The default Responses path streams. Codex `prompt_cache_key` is forwarded as
|
|
135
|
+
`x-grok-conv-id`.
|
|
136
|
+
|
|
137
|
+
## What works and what does not
|
|
138
|
+
|
|
139
|
+
Measured, not guessed:
|
|
140
|
+
|
|
141
|
+
- Mixed catalog of the six GPT models plus `grok-4.6`, with Grok provider
|
|
142
|
+
routing, on a real app-server.
|
|
143
|
+
- Live Grok CLI → Codex `exec_command` → result → Grok final reply
|
|
144
|
+
(`BRIDGE_TOOL_OK`).
|
|
145
|
+
- A separate Codex window showing `Grok 4.6 / xAI Extra High`.
|
|
146
|
+
- cli-chat-proxy accepted a 339-function-tool request. The public API’s 200-tool
|
|
147
|
+
cap does not apply on this login path.
|
|
148
|
+
|
|
149
|
+
### Provenance lines
|
|
150
|
+
|
|
151
|
+
Codex does not put provider or model into the prompt. The bridge appends a
|
|
152
|
+
`Transport:` line to `instructions` so the model can answer “is Grok attached?”
|
|
153
|
+
without opening config files. That line is transport provenance, in the same
|
|
154
|
+
category as a `User-Agent` header.
|
|
155
|
+
|
|
156
|
+
When image generation is on, an `Images:` line is appended as well: pictures on
|
|
157
|
+
this transport use Grok’s `image_generation` tool already on the request; do
|
|
158
|
+
not read Codex’s `imagegen` skill and do not send the picture to OpenAI.
|
|
159
|
+
`GROK_BRIDGE_IMAGE_GEN=off` drops both the tool and that line.
|
|
160
|
+
|
|
161
|
+
### Reasoning
|
|
162
|
+
|
|
163
|
+
Plain-text summaries on Codex `reasoning` items are forwarded. Encrypted
|
|
164
|
+
`encrypted_content` and Codex’s own item ids are stripped. This is so a
|
|
165
|
+
multi-call turn can continue its own reasoning. The upstream has been observed
|
|
166
|
+
to accept this shape.
|
|
167
|
+
|
|
168
|
+
### Concurrency
|
|
169
|
+
|
|
170
|
+
Up to **4** inferences run at once per bridge; the rest wait in a queue of 8.
|
|
171
|
+
Only a full queue returns `429`. Waiting is better than refusing because the
|
|
172
|
+
bridge has already sent response headers and is holding the stream with
|
|
173
|
+
keepalive. Setting concurrency to 1 kills Codex `spawn_agent` child inferences
|
|
174
|
+
that overlap the parent turn.
|
|
175
|
+
|
|
176
|
+
### Tools
|
|
177
|
+
|
|
178
|
+
Ordinary function tools, namespaced function tools, and freeform custom tools
|
|
179
|
+
are translated. File edits, MCP, and similar work inside whatever Codex
|
|
180
|
+
exposed, at whatever approval policy the user set. Not every tool has been
|
|
181
|
+
live-tested individually.
|
|
182
|
+
|
|
183
|
+
### Image attachments (vision)
|
|
184
|
+
|
|
185
|
+
PNG / JPEG / WebP. **10 MiB per image, 20 MiB per request**, up to four distinct
|
|
186
|
+
images, PNG up to 32 megapixels. The cap is measured: the upstream answered a
|
|
187
|
+
12.5 MiB PNG, and the limit sits below that.
|
|
188
|
+
|
|
189
|
+
One unusable attachment no longer kills the conversation. The bridge walks the
|
|
190
|
+
whole history; a single over-limit image used to make every later turn fail
|
|
191
|
+
with 400. Now that attachment is replaced with an explanation and the rest
|
|
192
|
+
goes through. Usable images stay `input_image` (Grok reads them). Remote URLs
|
|
193
|
+
are not fetched.
|
|
194
|
+
|
|
195
|
+
### Image generation
|
|
196
|
+
|
|
197
|
+
The bridge declares `{ type: "image_generation" }` on the upstream request.
|
|
198
|
+
Codex does not offer an image-generation tool to this provider (263 tools, none
|
|
199
|
+
of them generate — `view_image` only), so without the declaration Codex’s
|
|
200
|
+
`imagegen` skill falls back to OpenAI (`image_gen` or `OPENAI_API_KEY` +
|
|
201
|
+
`gpt-image-*`): thinking on Grok, pixels on another vendor.
|
|
202
|
+
|
|
203
|
+
Returned bytes are written to
|
|
204
|
+
`~/.local/share/codex-grok-bridge/generated-images/` as mode `0600`. Codex
|
|
205
|
+
cannot host those bytes, so the bridge turns the result into an assistant
|
|
206
|
+
message whose path is a markdown `file://` link:
|
|
207
|
+
|
|
208
|
+
`[ /path/to/grok-….jpg ](file:///path/to/grok-….jpg)`
|
|
209
|
+
|
|
210
|
+
Whether that link is clickable depends on Codex’s markdown renderer. Codex
|
|
211
|
+
events it does not know (`response.image_generation_call.*`) are dropped.
|
|
212
|
+
|
|
213
|
+
Grok’s `image_generation` is text-to-image only:
|
|
214
|
+
|
|
215
|
+
| Capability | Result |
|
|
216
|
+
|---|---|
|
|
217
|
+
| Text → image | Works |
|
|
218
|
+
| Transparent background | **No.** Always JPEG, no alpha. The model will say “transparent” and paint a checkerboard into the picture |
|
|
219
|
+
| Tool parameters (`background`, `output_format`) | Accepted and **silently ignored** |
|
|
220
|
+
| Image edit (image-to-image) | **Not a real edit.** The input is described in text and regenerated; composition and resolution change |
|
|
221
|
+
|
|
222
|
+
The bridge inspects the saved file. If there is no alpha channel it tells the
|
|
223
|
+
model not to describe the picture as transparent. If you need a real alpha
|
|
224
|
+
channel or accurate inpainting, use Codex’s OpenAI path.
|
|
225
|
+
|
|
226
|
+
### GPT ↔ Grok switching
|
|
227
|
+
|
|
228
|
+
Supported on an idle persisted root thread. `turn/start`,
|
|
229
|
+
`thread/settings/update` and `turn/settings/update` cannot change
|
|
230
|
+
`modelProvider`; extra provider fields are ignored. The wrapper unsubscribes,
|
|
231
|
+
resumes the same id with an explicit model/provider, checks the returned
|
|
232
|
+
provider and permissions, then forwards the original request. Active threads,
|
|
233
|
+
ephemeral threads and child agents refuse a switch. Other subscribers can block
|
|
234
|
+
the reload; if they do, no inference is sent. Pick the model you want when
|
|
235
|
+
starting a new thread, before the first turn is saved.
|
|
236
|
+
|
|
237
|
+
### Not guaranteed
|
|
238
|
+
|
|
239
|
+
Voice, cloud tasks, and video generation are not promised.
|
|
240
|
+
|
|
241
|
+
Upstream sometimes resets the connection mid-response (three measured cases:
|
|
242
|
+
25 s / 27 s / 253 s, 726 KB–22 MB). The bridge cannot retry after the first
|
|
243
|
+
SSE byte. The provider sets Codex `request_max_retries` / `stream_max_retries`
|
|
244
|
+
to 2 so **Codex** can resend the same request. Only the side that owns the
|
|
245
|
+
conversation can retry safely.
|
|
246
|
+
|
|
247
|
+
## Diagnostics
|
|
248
|
+
|
|
249
|
+
Every turn is one JSONL line at
|
|
250
|
+
`~/.local/share/codex-grok-bridge/logs/bridge.jsonl` (directory `0700`, file
|
|
251
|
+
`0600`, rotated once to `.1` above 4 MiB). `GROK_BRIDGE_DIAGNOSTICS=off` disables
|
|
252
|
+
it.
|
|
253
|
+
|
|
254
|
+
```jsonl
|
|
255
|
+
{"at":"…","event":"turn_ok","mode":"proxy","elapsedMs":14118,"requestBytes":469749,"items":4,"tools":29}
|
|
256
|
+
{"at":"…","event":"turn_failed","kind":"dns","signature":"TypeError <- Error[EAI_AGAIN]","elapsedMs":15071,…}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
Structural facts only: time, success/failure, error class, error-chain names
|
|
260
|
+
and codes, elapsed ms, request bytes, item and tool counts. **No prompt text,
|
|
261
|
+
tool output, upstream body, or tokens.** `detail` is redacted (bearer tokens,
|
|
262
|
+
JWTs, API keys, home paths) and truncated to 400 characters.
|
|
263
|
+
|
|
264
|
+
Completed turns are logged too: an empty log on failure means the bridge was
|
|
265
|
+
never called.
|
|
266
|
+
|
|
267
|
+
`turn_failed.kind` is one of: `aborted`, `auth`, `dns`, `connect`,
|
|
268
|
+
`upstream_timeout`, `upstream_closed`, `upstream_protocol`, `payload`,
|
|
269
|
+
`internal`. Codex UI shows the same class as `bridge_<kind>`.
|
|
36
270
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
updates an existing bundle; it does not create one, and it will not touch the
|
|
40
|
-
normal `Codex.app`. It never deletes a live bundle and refuses to run while a
|
|
41
|
-
Codex Grok window is open. ESM is not hot-reloaded, so reopen the window after
|
|
42
|
-
an update.
|
|
271
|
+
Start here when something breaks. Do not open `~/.grok/auth.json` or
|
|
272
|
+
`~/.codex/auth.json` to “check” the bridge.
|
|
43
273
|
|
|
44
|
-
|
|
45
|
-
`docs/solution-20260909.md` is the long one: how a fixed 15-second failure was
|
|
46
|
-
traced, what it turned out to be, and every measurement behind the fixes.
|
|
47
|
-
`docs/experiments/` reproduces those measurements.
|
|
274
|
+
## Environment variables
|
|
48
275
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
276
|
+
| Variable | Effect |
|
|
277
|
+
|---|---|
|
|
278
|
+
| `GROK_BRIDGE_IMAGE_GEN=off` | Do not declare Grok `image_generation`; do not append the `Images:` line |
|
|
279
|
+
| `GROK_BRIDGE_TRANSPORT=fetch` | Use Node `fetch` instead of `node:http(s)` |
|
|
280
|
+
| `GROK_BRIDGE_INFERENCE=cli` | Fall back to the CLI envelope path |
|
|
281
|
+
| `GROK_BRIDGE_DIAGNOSTICS=off` | Do not write the JSONL log |
|
|
282
|
+
| `NODE` | Absolute `node` binary for the `.command` launcher / desktop scripts |
|
|
283
|
+
| `CODEX_GROK_APP` | Alternate app bundle path for `install-codex-grok-app.sh` (default `/Applications/Codex Grok.app`) |
|
|
284
|
+
|
|
285
|
+
## Verify
|
|
286
|
+
|
|
287
|
+
```sh
|
|
288
|
+
npm test # 132 tests, no remote inference
|
|
289
|
+
npm run test:coverage # 80% line / branch / function gate
|
|
290
|
+
npm run verify:app-server # real app-server routing; also runs against an installed bundle
|
|
291
|
+
npm audit --omit=dev
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
`npm test` does not call remote inference. `verify:app-server` talks to a real
|
|
295
|
+
app-server for the model list and a temporary thread; it does not run model
|
|
296
|
+
inference. A live CLI check spends the user’s quota.
|
|
297
|
+
|
|
298
|
+
## Desktop install and update
|
|
299
|
+
|
|
300
|
+
```sh
|
|
301
|
+
sh scripts/install-codex-grok-app.sh # sync bridge JS only (default)
|
|
302
|
+
sh scripts/install-codex-grok-app.sh --full # also rebuild and sign the launcher applet
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
The default copies this checkout’s `src/` and `scripts/*.mjs` into the bundle,
|
|
306
|
+
prunes files the checkout no longer has, and `cmp`s every file at the end. It
|
|
307
|
+
never `rm -rf`s the live bundle. It refuses while a Codex Grok window is open
|
|
308
|
+
(`--force` to override). ESM is not hot-reloaded: **reopen the window** after a
|
|
309
|
+
sync.
|
|
310
|
+
|
|
311
|
+
The script updates an existing `Codex Grok.app`. It does not create one, and it
|
|
312
|
+
does not touch `/Applications/Codex.app`.
|
|
313
|
+
|
|
314
|
+
## Security notes
|
|
315
|
+
|
|
316
|
+
The bridge binds loopback only. Each inference request needs a per-run
|
|
317
|
+
temporary token. Browser `Origin` requests, unsupported models, oversized
|
|
318
|
+
bodies, and unknown tool calls are rejected. Grok prompt temp files are `0600`
|
|
319
|
+
and deleted on exit. CLI error text and credentials are not returned in
|
|
320
|
+
responses. Codex’s and Grok’s own retention policies still apply.
|
|
321
|
+
|
|
322
|
+
## Further docs
|
|
323
|
+
|
|
324
|
+
- `docs/HANDOFF.md` — current state, pitfalls, open items
|
|
325
|
+
- `docs/solution-20260909.md` — how a fixed 15-second failure was traced, and
|
|
326
|
+
every measurement behind the fixes
|
|
327
|
+
- `docs/experiments/` — scripts that reproduce those measurements
|
|
328
|
+
|
|
329
|
+
## References
|
|
330
|
+
|
|
331
|
+
- [Grok Build headless scripting](https://docs.x.ai/build/cli/headless-scripting)
|
|
332
|
+
- [Grok Build source](https://github.com/xai-org/grok-build)
|
|
333
|
+
- [Codex source](https://github.com/openai/codex)
|
|
52
334
|
|
|
53
335
|
---
|
|
54
336
|
|
|
55
|
-
|
|
337
|
+
# 한국어
|
|
338
|
+
|
|
339
|
+
## 이게 뭔가
|
|
340
|
+
|
|
341
|
+
Grok 4.6을 Codex 모델 목록에 넣고, Codex의 `/v1/responses`를
|
|
342
|
+
`cli-chat-proxy.grok.com`으로 넘기는 로컬 브리지입니다. 추론은 Grok이 합니다.
|
|
343
|
+
도구 호출(셸, 패치, MCP, …)은 Codex가 실행하고, 결과는 다음 요청의 `input`으로
|
|
344
|
+
돌아갑니다. GPT 경로와 같은 에이전트 루프입니다.
|
|
345
|
+
|
|
346
|
+
브리지는 Grok 네이티브 도구를 실행하지 않습니다. Codex 도구를 function
|
|
347
|
+
calling으로 옮기고, 상류 Responses 스트림을 전달한 뒤, Codex가 알아보는
|
|
348
|
+
이름으로 되돌립니다.
|
|
349
|
+
|
|
350
|
+
`src/` 아래 파일 13개. 런타임 의존성 없음. Node.js 22 이상.
|
|
56
351
|
|
|
57
|
-
|
|
352
|
+
코드 리뷰 전용 제품이 아니고, Grok 4.7 어댑터도 아니며, Grok 네이티브 검색
|
|
353
|
+
제품도 아닙니다. Codex가 웹 검색 도구를 노출하면 Grok은 다른 Codex 도구와 같이
|
|
354
|
+
그 도구를 호출할 수 있습니다.
|
|
58
355
|
|
|
59
|
-
|
|
356
|
+
## 필요한 것
|
|
60
357
|
|
|
61
|
-
|
|
358
|
+
- macOS
|
|
359
|
+
- Node.js 22 이상
|
|
360
|
+
- `/Applications/Codex.app`
|
|
361
|
+
- `~/.grok/bin/grok`
|
|
362
|
+
- 완료된 `grok login`
|
|
62
363
|
|
|
63
|
-
|
|
364
|
+
`.command` 런처는 자기 위치를 기준으로 경로를 잡으므로 폴더를 옮겨도 수정할
|
|
365
|
+
필요가 없습니다. `PATH`에 `node`가 없으면 `NODE=/path/to/node`로 지정합니다.
|
|
64
366
|
|
|
65
|
-
|
|
367
|
+
검증 버전: Codex 0.153.4 / 앱 26.901.51231, Grok CLI 1.0.24, Node 22.23.0.
|
|
368
|
+
앱 업데이트가 `CODEX_CLI_PATH`나 app-server 프로토콜을 바꾸면 재검증이
|
|
369
|
+
필요합니다.
|
|
370
|
+
|
|
371
|
+
## 설치와 실행
|
|
372
|
+
|
|
373
|
+
### 터미널 (npm)
|
|
66
374
|
|
|
67
375
|
```sh
|
|
68
|
-
npm install -g codex-grok-bridge
|
|
69
|
-
codex-grok
|
|
376
|
+
npm install -g codex-grok-bridge # macOS, Node ≥ 22
|
|
377
|
+
codex-grok # Grok 4.6이 있는 Codex를 띄움
|
|
70
378
|
codex-grok exec --skip-git-repo-check --sandbox workspace-write '작업 내용'
|
|
71
379
|
```
|
|
72
380
|
|
|
73
|
-
|
|
381
|
+
`codex-grok`는 자기가 띄운 Codex 프로세스에만 브리지를 모델 제공자로 등록하고,
|
|
382
|
+
그 프로세스와 함께 내립니다.
|
|
74
383
|
|
|
75
|
-
|
|
384
|
+
### 체크아웃에서
|
|
76
385
|
|
|
77
|
-
|
|
386
|
+
```sh
|
|
387
|
+
git clone https://github.com/deximple/codex-grok-bridge.git
|
|
388
|
+
cd codex-grok-bridge
|
|
389
|
+
npm test # 132건, 네트워크·추론 없음
|
|
390
|
+
node scripts/codex-grok.mjs
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
### 데스크톱
|
|
394
|
+
|
|
395
|
+
이 폴더의 **Open Codex with Grok.command**를 더블 클릭하거나,
|
|
396
|
+
`scripts/install-codex-grok-app.sh`로 **별도의** `Codex Grok.app`을 체크아웃과
|
|
397
|
+
맞춥니다([데스크톱 설치와 갱신](#데스크톱-설치와-갱신)).
|
|
398
|
+
|
|
399
|
+
새로 열린 Codex 창에서 **새 작업을 시작하기 전에 Grok 4.6 / xAI를 선택**하세요.
|
|
400
|
+
기존 GPT 모델도 목록에 남습니다. 이미 열려 있던 일반 Codex 창에는 이 확장이
|
|
401
|
+
주입되지 않습니다.
|
|
402
|
+
|
|
403
|
+
전용 창은 UI 데이터를 `~/.local/share/codex-grok-bridge/desktop`에 두고,
|
|
404
|
+
계정·작업·설정은 기존 Codex 홈을 **공유**합니다. 작업 내용과 설정 변경은 다른
|
|
405
|
+
Codex 창에도 보일 수 있습니다.
|
|
406
|
+
|
|
407
|
+
설치 스크립트는 정품 Codex.app 번들, 코드 서명, `~/.codex/config.toml`, Grok
|
|
408
|
+
인증 파일을 수정하지 않습니다. 자동 시작 서비스나 전역 환경변수도 등록하지
|
|
409
|
+
않습니다.
|
|
410
|
+
|
|
411
|
+
중지하려면 이 확장으로 연 Codex 창을 닫으면 됩니다. 일반 Codex는 기존 아이콘으로
|
|
412
|
+
실행합니다.
|
|
413
|
+
|
|
414
|
+
## 연결 방식
|
|
78
415
|
|
|
79
416
|
1. `CODEX_CLI_PATH`로 지정한 래퍼가 Codex app-server를 실행합니다.
|
|
80
|
-
2. 래퍼가 모델 목록에 Grok를
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
417
|
+
2. 래퍼가 모델 목록에 Grok를 추가하고, 새 Grok 작업의 제공자를
|
|
418
|
+
`grok_build_cli`로 설정합니다.
|
|
419
|
+
3. Codex의 `/v1/responses` 요청은 localhost 브리지로 갑니다.
|
|
420
|
+
4. 브리지는 Codex 도구(일반 함수, namespace 함수, freeform 커스텀, `web_search`)를
|
|
421
|
+
function tool로 펼친 뒤 `cli-chat-proxy.grok.com` Responses 스트림을 이어줍니다.
|
|
422
|
+
5. 도구 결과는 다음 Codex 요청의 `input`으로 돌아갑니다.
|
|
84
423
|
|
|
85
|
-
|
|
424
|
+
인증은 `grok login` 세션입니다. `XAI_API_KEY`는 쓰지 않습니다.
|
|
86
425
|
|
|
87
|
-
|
|
426
|
+
상류 소켓은 `node:http(s)` keep-alive `Agent`(30초, 최대 4개)와 TTL 5분 DNS
|
|
427
|
+
캐시를 씁니다. 조회가 실패해도 유효한 캐시가 있으면 그것으로 버팁니다. 도구
|
|
428
|
+
실행으로 5–20초가 비어도 매번 이름을 다시 찾지 않기 위해서입니다.
|
|
429
|
+
`GROK_BRIDGE_TRANSPORT=fetch`로 이전 `fetch` 경로로 되돌릴 수 있습니다.
|
|
88
430
|
|
|
89
|
-
|
|
431
|
+
Codex에 첫 SSE 블록을 쓰기 **전**에 죽은 요청은 한 번 다시 보냅니다. 아직
|
|
432
|
+
아무것도 전달하지 않았으므로 재전송이 대화를 오염시키지 않습니다. 첫 블록을
|
|
433
|
+
쓴 뒤에는 절대 재시도하지 않습니다. 422 같은 결정적 거절과 사용자 중단도
|
|
434
|
+
재시도하지 않습니다.
|
|
90
435
|
|
|
91
|
-
|
|
436
|
+
Responses 경로가 이상하면 `GROK_BRIDGE_INFERENCE=cli`로 이전 CLI 봉투 경로를
|
|
437
|
+
씁니다. 매 턴 전체 JSON을 프롬프트로 넣으므로 더 느리고 비싸며, 토큰 단위
|
|
438
|
+
실시간 출력이 없고, 요청당 3분 제한입니다.
|
|
439
|
+
|
|
440
|
+
기본 Responses 경로는 스트림을 전달합니다. Codex `prompt_cache_key`는
|
|
441
|
+
`x-grok-conv-id`로 넘깁니다.
|
|
92
442
|
|
|
93
443
|
## 확인된 동작과 제한
|
|
94
444
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
-
|
|
98
|
-
-
|
|
99
|
-
|
|
100
|
-
-
|
|
101
|
-
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
445
|
+
추측이 아니라 실측입니다.
|
|
446
|
+
|
|
447
|
+
- 실제 app-server에서 GPT 6개 모델과 `grok-4.6`의 혼합 목록, Grok 제공자 라우팅.
|
|
448
|
+
- 실제 Grok CLI → Codex `exec_command` → 결과 → Grok 최종 응답
|
|
449
|
+
(`BRIDGE_TOOL_OK`).
|
|
450
|
+
- 별도 Codex 창에 `Grok 4.6 / xAI Extra High` 표시.
|
|
451
|
+
- cli-chat-proxy가 function tool 339개 요청을 수락. 공개 API 문서의 200개 한도는
|
|
452
|
+
이 로그인 경로에 적용되지 않음.
|
|
453
|
+
|
|
454
|
+
### 출처 한 줄
|
|
455
|
+
|
|
456
|
+
Codex는 provider·model을 프롬프트에 넣지 않습니다. 브리지는 `instructions` 끝에
|
|
457
|
+
`Transport:` 줄을 붙여, 모델이 설정 파일을 열지 않고도 “Grok이 붙었는가”에
|
|
458
|
+
답하게 합니다. 대화 내용을 판단하는 것이 아니라 전송이 자기 출처를 밝히는
|
|
459
|
+
것이며, `User-Agent` 헤더와 같은 범주입니다.
|
|
460
|
+
|
|
461
|
+
이미지 생성이 켜져 있으면 `Images:` 줄도 붙습니다. 이 전송의 그림은 요청에 이미
|
|
462
|
+
있는 Grok `image_generation` 도구로 만들고, Codex `imagegen` 스킬을 읽거나
|
|
463
|
+
OpenAI로 보내지 말라는 뜻입니다. `GROK_BRIDGE_IMAGE_GEN=off`면 도구와 그 줄이
|
|
464
|
+
같이 빠집니다.
|
|
465
|
+
|
|
466
|
+
### reasoning
|
|
467
|
+
|
|
468
|
+
Codex `reasoning` 항목의 평문 요약은 상류로 전달합니다. 암호화된
|
|
469
|
+
`encrypted_content`와 Codex 자체 아이템 id는 제거합니다. 여러 번 호출이 이어지는
|
|
470
|
+
턴에서 모델이 자기 추론을 이어받게 하기 위한 것이며, 상류가 이 형태를 수락하는
|
|
471
|
+
것을 확인했습니다.
|
|
472
|
+
|
|
473
|
+
### 동시성
|
|
474
|
+
|
|
475
|
+
변환기당 추론은 **동시 4건**, 나머지는 큐(기본 8)에서 대기합니다. 큐까지 가득
|
|
476
|
+
찼을 때만 `429`입니다. 브리지가 이미 응답 헤더를 보냈고 keepalive로 스트림을
|
|
477
|
+
살려 두기 때문에 대기가 거절보다 낫습니다. 동시 1로 조이면 Codex `spawn_agent`
|
|
478
|
+
자식 추론이 부모 턴과 겹쳐 죽습니다.
|
|
479
|
+
|
|
480
|
+
### 도구
|
|
481
|
+
|
|
482
|
+
일반 함수 도구, namespace 함수 도구, freeform 커스텀 도구를 변환합니다. 파일
|
|
483
|
+
변경·MCP 등은 Codex가 노출한 도구와 사용자가 정한 승인 정책 안에서 동작합니다.
|
|
484
|
+
개별 기능을 모두 실검증한 것은 아닙니다.
|
|
485
|
+
|
|
486
|
+
### 이미지 첨부 (인식)
|
|
487
|
+
|
|
488
|
+
PNG / JPEG / WebP. **이미지당 10 MiB, 요청 전체 20 MiB**, 서로 다른 이미지
|
|
489
|
+
4장까지, PNG는 32메가픽셀까지. 한도는 실측입니다 — 상류가 12.5 MiB PNG를 받아
|
|
490
|
+
답하는 것을 확인하고 그 아래로 잡았습니다.
|
|
491
|
+
|
|
492
|
+
쓸 수 없는 첨부 하나가 대화를 죽이지 않습니다. 브리지는 대화 전체를 훑기
|
|
493
|
+
때문에, 예전에는 한도를 넘는 이미지가 히스토리에 한 번 들어가면 이후 모든 턴이
|
|
494
|
+
영구히 400이었습니다. 지금은 그 첨부만 이유를 밝힌 텍스트로 바꾸고 나머지는
|
|
495
|
+
그대로 보냅니다. 쓸 수 있는 이미지는 `input_image` 그대로 넘어가며 Grok가 직접
|
|
496
|
+
읽습니다. 원격 URL은 가져오지 않습니다.
|
|
497
|
+
|
|
498
|
+
### 이미지 생성
|
|
499
|
+
|
|
500
|
+
브리지가 상류 요청에 `{ type: "image_generation" }`을 직접 선언합니다. Codex는
|
|
501
|
+
이 프로바이더에 이미지 생성 도구를 주지 않습니다(263개 중 없음, `view_image`
|
|
502
|
+
뿐). 선언이 없으면 Codex `imagegen` 스킬이 OpenAI 경로(`image_gen` 또는
|
|
503
|
+
`OPENAI_API_KEY` + `gpt-image-*`)로 가서, 추론은 Grok인데 그림만 다른 벤더가
|
|
504
|
+
그립니다.
|
|
505
|
+
|
|
506
|
+
돌아온 바이트는 `~/.local/share/codex-grok-bridge/generated-images/`에 `0600`으로
|
|
507
|
+
저장합니다. Codex는 그 바이트를 둘 곳이 없어서, 브리지는 경로를 마크다운
|
|
508
|
+
`file://` 링크로 넣은 assistant 메시지로 바꿉니다.
|
|
509
|
+
|
|
510
|
+
`[ /path/to/grok-….jpg ](file:///path/to/grok-….jpg)`
|
|
511
|
+
|
|
512
|
+
클릭 여부는 Codex 마크다운 렌더러에 달립니다. Codex가 모르는
|
|
513
|
+
`response.image_generation_call.*` 이벤트는 걸러냅니다.
|
|
514
|
+
|
|
515
|
+
Grok의 `image_generation`은 텍스트→이미지만 제대로 됩니다.
|
|
516
|
+
|
|
517
|
+
| 기능 | 결과 |
|
|
518
|
+
|---|---|
|
|
519
|
+
| 텍스트→이미지 | 됨 |
|
|
520
|
+
| 투명 배경 | **안 됨.** 항상 JPEG, 알파 없음. 모델은 “투명”이라고 말하면서 체커보드를 그림에 칠함 |
|
|
521
|
+
| 도구 파라미터(`background`, `output_format`) | 받아 주고 **조용히 무시** |
|
|
522
|
+
| 이미지 편집(image-to-image) | **진짜 편집이 아님.** 입력을 텍스트로 묘사해 재생성하므로 구도·해상도가 바뀜 |
|
|
523
|
+
|
|
524
|
+
브리지는 저장한 파일의 포맷을 확인합니다. 알파가 없으면 모델에게 투명하다고
|
|
525
|
+
설명하지 말라고 적습니다. 진짜 알파나 정확한 인페인팅이 필요하면 Codex의
|
|
526
|
+
OpenAI 경로가 맞습니다.
|
|
527
|
+
|
|
528
|
+
### GPT ↔ Grok 전환
|
|
529
|
+
|
|
530
|
+
대기 중인 저장된 루트 작업에서만 됩니다. `turn/start`,
|
|
531
|
+
`thread/settings/update`, `turn/settings/update`는 `modelProvider`를 바꾸지
|
|
532
|
+
못하고, 추가 provider 필드는 무시됩니다. 래퍼가 구독 해제 → 같은 ID로
|
|
533
|
+
모델/제공자를 지정해 재개 → 돌아온 제공자·권한을 확인한 뒤 원래 요청을
|
|
534
|
+
전달합니다. 실행 중인 작업, 임시 작업, 하위 에이전트는 전환을 거부합니다. 다른
|
|
535
|
+
구독자가 재로드를 막으면 추론을 보내지 않습니다. 첫 턴이 저장되기 전에 새
|
|
536
|
+
작업을 시작할 때 원하는 모델을 고르세요.
|
|
537
|
+
|
|
538
|
+
### 아직 보장하지 않는 것
|
|
539
|
+
|
|
540
|
+
음성, 클라우드 작업, 영상 생성은 약속하지 않습니다.
|
|
541
|
+
|
|
542
|
+
상류가 응답 중간에 연결을 리셋하는 경우가 있습니다(실측 3건: 25초 / 27초 /
|
|
543
|
+
253초, 726 KB–22 MB). 첫 SSE 바이트 이후에는 브리지가 재시도할 수 없습니다.
|
|
544
|
+
provider에 Codex `request_max_retries` / `stream_max_retries`를 2로 두어
|
|
545
|
+
**Codex**가 같은 요청을 다시 보내게 했습니다. 대화를 소유한 쪽만 안전하게
|
|
546
|
+
재시도할 수 있습니다.
|
|
123
547
|
|
|
124
548
|
## 진단 로그
|
|
125
549
|
|
|
126
|
-
|
|
550
|
+
매 턴을 `~/.local/share/codex-grok-bridge/logs/bridge.jsonl`에 한 줄씩 기록합니다
|
|
551
|
+
(디렉터리 `0700`, 파일 `0600`, 4 MiB 초과 시 `.1`로 1회 회전).
|
|
552
|
+
`GROK_BRIDGE_DIAGNOSTICS=off`로 끕니다.
|
|
127
553
|
|
|
128
554
|
```jsonl
|
|
129
555
|
{"at":"…","event":"turn_ok","mode":"proxy","elapsedMs":14118,"requestBytes":469749,"items":4,"tools":29}
|
|
130
556
|
{"at":"…","event":"turn_failed","kind":"dns","signature":"TypeError <- Error[EAI_AGAIN]","elapsedMs":15071,…}
|
|
131
557
|
```
|
|
132
558
|
|
|
133
|
-
구조적 사실만 남깁니다 — 시각, 성공/실패, 오류 분류, 오류 체인의 이름·코드,
|
|
559
|
+
구조적 사실만 남깁니다 — 시각, 성공/실패, 오류 분류, 오류 체인의 이름·코드,
|
|
560
|
+
경과 시간, 요청 바이트, 아이템·도구 개수. **프롬프트 본문, 도구 출력, 상류 응답
|
|
561
|
+
본문, 토큰은 기록하지 않습니다.** `detail`은 Bearer 토큰·JWT·API 키·홈 경로를
|
|
562
|
+
지운 뒤 400자로 자릅니다.
|
|
563
|
+
|
|
564
|
+
성공 턴도 남깁니다. 실패했는데 로그가 비어 있으면 브리지가 호출되지 않은
|
|
565
|
+
것입니다.
|
|
566
|
+
|
|
567
|
+
`turn_failed.kind`는 다음 중 하나입니다 — `aborted`, `auth`, `dns`, `connect`,
|
|
568
|
+
`upstream_timeout`, `upstream_closed`, `upstream_protocol`, `payload`,
|
|
569
|
+
`internal`. Codex UI에는 같은 분류가 `bridge_<kind>`로 보입니다.
|
|
570
|
+
|
|
571
|
+
문제가 있으면 여기부터 봅니다. 브리지를 “확인”하려고 `~/.grok/auth.json`이나
|
|
572
|
+
`~/.codex/auth.json`을 열지 마세요.
|
|
134
573
|
|
|
135
|
-
|
|
574
|
+
## 환경 변수
|
|
136
575
|
|
|
137
|
-
|
|
576
|
+
| 변수 | 효과 |
|
|
577
|
+
|---|---|
|
|
578
|
+
| `GROK_BRIDGE_IMAGE_GEN=off` | Grok `image_generation`을 선언하지 않고 `Images:` 줄도 붙이지 않음 |
|
|
579
|
+
| `GROK_BRIDGE_TRANSPORT=fetch` | `node:http(s)` 대신 Node `fetch` |
|
|
580
|
+
| `GROK_BRIDGE_INFERENCE=cli` | CLI 봉투 경로로 폴백 |
|
|
581
|
+
| `GROK_BRIDGE_DIAGNOSTICS=off` | JSONL 로그를 쓰지 않음 |
|
|
582
|
+
| `NODE` | `.command` / 데스크톱 스크립트가 쓸 `node` 절대 경로 |
|
|
583
|
+
| `CODEX_GROK_APP` | `install-codex-grok-app.sh`가 쓸 앱 번들 경로 (기본 `/Applications/Codex Grok.app`) |
|
|
138
584
|
|
|
139
585
|
## 검증
|
|
140
586
|
|
|
141
587
|
```sh
|
|
142
|
-
npm test #
|
|
588
|
+
npm test # 132건, 외부 추론 없음
|
|
143
589
|
npm run test:coverage # line/branch/function 80% 게이트
|
|
144
|
-
npm run verify:app-server # 실제 app-server 라우팅. 설치된 앱 번들에서도
|
|
590
|
+
npm run verify:app-server # 실제 app-server 라우팅. 설치된 앱 번들에서도 실행
|
|
145
591
|
npm audit --omit=dev
|
|
146
592
|
```
|
|
147
593
|
|
|
148
|
-
|
|
594
|
+
`npm test`는 외부 추론을 호출하지 않습니다. `verify:app-server`는 실제
|
|
595
|
+
app-server에 모델 목록과 임시 작업을 요청하며, 모델 추론은 하지 않습니다. 실제
|
|
596
|
+
CLI 검증은 사용자 계정 사용량을 씁니다.
|
|
597
|
+
|
|
598
|
+
## 데스크톱 설치와 갱신
|
|
149
599
|
|
|
150
600
|
```sh
|
|
151
601
|
sh scripts/install-codex-grok-app.sh # 브리지 JS만 동기화 (기본)
|
|
152
|
-
sh scripts/install-codex-grok-app.sh --full # 런처 applet 재빌드 +
|
|
602
|
+
sh scripts/install-codex-grok-app.sh --full # 런처 applet 재빌드 + 서명
|
|
153
603
|
```
|
|
154
604
|
|
|
155
|
-
기본 동작은
|
|
605
|
+
기본 동작은 이 체크아웃의 `src/`와 `scripts/*.mjs`를 번들에 복사하고, 저장소에
|
|
606
|
+
없는 파일만 고른 뒤, 끝에서 모든 파일을 `cmp`합니다. 살아있는 번들을
|
|
607
|
+
`rm -rf`하지 않습니다. Codex Grok 창이 열려 있으면 거부합니다(`--force`로
|
|
608
|
+
무시). ESM은 핫리로드되지 않으므로 **동기화 후 창을 다시 열어야** 합니다.
|
|
609
|
+
|
|
610
|
+
이 스크립트는 이미 있는 `Codex Grok.app`을 갱신합니다. 번들을 새로 만들지
|
|
611
|
+
않고, `/Applications/Codex.app`은 건드리지 않습니다.
|
|
612
|
+
|
|
613
|
+
## 보안
|
|
614
|
+
|
|
615
|
+
브리지는 loopback에만 붙습니다. 추론 요청마다 실행 단위 임시 토큰이 필요합니다.
|
|
616
|
+
브라우저 `Origin` 요청, 지원하지 않는 모델, 과대 본문, 알 수 없는 도구 호출은
|
|
617
|
+
거절합니다. Grok 프롬프트 임시 파일은 `0600`으로 만들고 종료 후 지웁니다. CLI
|
|
618
|
+
오류 원문과 인증 정보는 응답에 넣지 않습니다. Codex와 Grok 자체의 보관 정책은
|
|
619
|
+
그대로입니다.
|
|
156
620
|
|
|
157
|
-
|
|
621
|
+
## 더 깊은 문서
|
|
158
622
|
|
|
159
|
-
|
|
623
|
+
- `docs/HANDOFF.md` — 현재 상태, 함정, 남은 항목
|
|
624
|
+
- `docs/solution-20260909.md` — 15초 고정 실패를 추적한 기록과 측정
|
|
625
|
+
- `docs/experiments/` — 그 측정을 재현하는 스크립트
|
|
160
626
|
|
|
161
|
-
|
|
627
|
+
## 참고
|
|
162
628
|
|
|
163
|
-
|
|
629
|
+
- [Grok Build headless scripting](https://docs.x.ai/build/cli/headless-scripting)
|
|
630
|
+
- [Grok Build source](https://github.com/xai-org/grok-build)
|
|
631
|
+
- [Codex source](https://github.com/openai/codex)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codex-grok-bridge",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "Run Grok 4.6 as the model inside Codex, with Codex still owning tools, permissions, history and MCP. Uses the grok login session, not an API key.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
package/src/imagegen.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { mkdirSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import path from "node:path";
|
|
4
|
+
import { pathToFileURL } from "node:url";
|
|
4
5
|
|
|
5
6
|
// Codex offers no image generation tool to this provider — 263 tools arrive and
|
|
6
7
|
// none of them generates an image — so its imagegen skill falls back to the
|
|
@@ -80,9 +81,12 @@ export function describeGeneratedImage(item, saved) {
|
|
|
80
81
|
? " It has an alpha channel."
|
|
81
82
|
: ` This format carries no alpha channel, so the background is opaque —` +
|
|
82
83
|
` do not describe it as transparent or cut out, even if it looks that way.`;
|
|
84
|
+
// Codex renders assistant markdown. A file:// link is the only way to make
|
|
85
|
+
// the path clickable; wrapping the whole note in [] would swallow that link.
|
|
86
|
+
const linked = `[${saved.file}](${pathToFileURL(saved.file).href})`;
|
|
83
87
|
return (
|
|
84
|
-
`
|
|
88
|
+
`Image generated by Grok and saved to ${linked} ` +
|
|
85
89
|
`(${saved.extension.toUpperCase()}, ${kb} KB).${alpha}${prompt} ` +
|
|
86
|
-
`Move or copy it into the workspace if the user wants it there, and tell them the path
|
|
90
|
+
`Move or copy it into the workspace if the user wants it there, and tell them the path.`
|
|
87
91
|
);
|
|
88
92
|
}
|