@kenkaiiii/ggcoder 4.11.2 → 4.12.1

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.
Files changed (124) hide show
  1. package/dist/app-sidecar.js +427 -62
  2. package/dist/app-sidecar.js.map +1 -1
  3. package/dist/cli.d.ts.map +1 -1
  4. package/dist/cli.js +5 -3
  5. package/dist/cli.js.map +1 -1
  6. package/dist/config.d.ts +5 -0
  7. package/dist/config.d.ts.map +1 -1
  8. package/dist/config.js +3 -0
  9. package/dist/config.js.map +1 -1
  10. package/dist/core/agent-session.d.ts +66 -11
  11. package/dist/core/agent-session.d.ts.map +1 -1
  12. package/dist/core/agent-session.js +219 -39
  13. package/dist/core/agent-session.js.map +1 -1
  14. package/dist/core/api-benchmark.d.ts +64 -0
  15. package/dist/core/api-benchmark.d.ts.map +1 -0
  16. package/dist/core/api-benchmark.js +381 -0
  17. package/dist/core/api-benchmark.js.map +1 -0
  18. package/dist/core/event-bus.d.ts +1 -0
  19. package/dist/core/event-bus.d.ts.map +1 -1
  20. package/dist/core/mcp/client.d.ts +32 -0
  21. package/dist/core/mcp/client.d.ts.map +1 -1
  22. package/dist/core/mcp/client.js +232 -27
  23. package/dist/core/mcp/client.js.map +1 -1
  24. package/dist/core/mcp/index.d.ts +3 -1
  25. package/dist/core/mcp/index.d.ts.map +1 -1
  26. package/dist/core/mcp/index.js +2 -0
  27. package/dist/core/mcp/index.js.map +1 -1
  28. package/dist/core/mcp/loopback.d.ts +27 -0
  29. package/dist/core/mcp/loopback.d.ts.map +1 -0
  30. package/dist/core/mcp/loopback.js +66 -0
  31. package/dist/core/mcp/loopback.js.map +1 -0
  32. package/dist/core/mcp/loopback.test.d.ts +2 -0
  33. package/dist/core/mcp/loopback.test.d.ts.map +1 -0
  34. package/dist/core/mcp/loopback.test.js +87 -0
  35. package/dist/core/mcp/loopback.test.js.map +1 -0
  36. package/dist/core/mcp/oauth-provider.d.ts +51 -0
  37. package/dist/core/mcp/oauth-provider.d.ts.map +1 -0
  38. package/dist/core/mcp/oauth-provider.js +95 -0
  39. package/dist/core/mcp/oauth-provider.js.map +1 -0
  40. package/dist/core/mcp/oauth-store.d.ts +39 -0
  41. package/dist/core/mcp/oauth-store.d.ts.map +1 -0
  42. package/dist/core/mcp/oauth-store.js +63 -0
  43. package/dist/core/mcp/oauth-store.js.map +1 -0
  44. package/dist/core/mcp/oauth-store.test.d.ts +2 -0
  45. package/dist/core/mcp/oauth-store.test.d.ts.map +1 -0
  46. package/dist/core/mcp/oauth-store.test.js +94 -0
  47. package/dist/core/mcp/oauth-store.test.js.map +1 -0
  48. package/dist/core/mcp/parse-add-command.d.ts.map +1 -1
  49. package/dist/core/mcp/parse-add-command.js +1 -0
  50. package/dist/core/mcp/parse-add-command.js.map +1 -1
  51. package/dist/core/mcp/parse-add-command.test.js +8 -2
  52. package/dist/core/mcp/parse-add-command.test.js.map +1 -1
  53. package/dist/core/mcp/store.d.ts +4 -4
  54. package/dist/core/mcp/store.d.ts.map +1 -1
  55. package/dist/core/mcp/store.js +7 -1
  56. package/dist/core/mcp/store.js.map +1 -1
  57. package/dist/core/mcp/store.test.js +11 -2
  58. package/dist/core/mcp/store.test.js.map +1 -1
  59. package/dist/core/mcp/types.d.ts +5 -1
  60. package/dist/core/mcp/types.d.ts.map +1 -1
  61. package/dist/core/process-manager.d.ts.map +1 -1
  62. package/dist/core/process-manager.js +5 -1
  63. package/dist/core/process-manager.js.map +1 -1
  64. package/dist/core/settings-manager.d.ts +4 -0
  65. package/dist/core/settings-manager.d.ts.map +1 -1
  66. package/dist/core/settings-manager.js +5 -0
  67. package/dist/core/settings-manager.js.map +1 -1
  68. package/dist/core/shell.d.ts +51 -0
  69. package/dist/core/shell.d.ts.map +1 -0
  70. package/dist/core/shell.js +82 -0
  71. package/dist/core/shell.js.map +1 -0
  72. package/dist/core/shell.test.d.ts +2 -0
  73. package/dist/core/shell.test.d.ts.map +1 -0
  74. package/dist/core/shell.test.js +87 -0
  75. package/dist/core/shell.test.js.map +1 -0
  76. package/dist/core/speed-benchmark.d.ts +133 -0
  77. package/dist/core/speed-benchmark.d.ts.map +1 -0
  78. package/dist/core/speed-benchmark.js +410 -0
  79. package/dist/core/speed-benchmark.js.map +1 -0
  80. package/dist/core/speed-benchmark.test.d.ts +2 -0
  81. package/dist/core/speed-benchmark.test.d.ts.map +1 -0
  82. package/dist/core/speed-benchmark.test.js +97 -0
  83. package/dist/core/speed-benchmark.test.js.map +1 -0
  84. package/dist/interactive.d.ts.map +1 -1
  85. package/dist/interactive.js +4 -3
  86. package/dist/interactive.js.map +1 -1
  87. package/dist/tools/bash.d.ts.map +1 -1
  88. package/dist/tools/bash.js +17 -1
  89. package/dist/tools/bash.js.map +1 -1
  90. package/dist/tools/edit-diff.d.ts.map +1 -1
  91. package/dist/tools/edit-diff.js +25 -8
  92. package/dist/tools/edit-diff.js.map +1 -1
  93. package/dist/tools/generate-image.d.ts +39 -0
  94. package/dist/tools/generate-image.d.ts.map +1 -0
  95. package/dist/tools/generate-image.js +301 -0
  96. package/dist/tools/generate-image.js.map +1 -0
  97. package/dist/tools/generate-image.test.d.ts +2 -0
  98. package/dist/tools/generate-image.test.d.ts.map +1 -0
  99. package/dist/tools/generate-image.test.js +223 -0
  100. package/dist/tools/generate-image.test.js.map +1 -0
  101. package/dist/tools/index.d.ts +12 -1
  102. package/dist/tools/index.d.ts.map +1 -1
  103. package/dist/tools/index.js +16 -1
  104. package/dist/tools/index.js.map +1 -1
  105. package/dist/tools/ls.d.ts.map +1 -1
  106. package/dist/tools/ls.js +7 -4
  107. package/dist/tools/ls.js.map +1 -1
  108. package/dist/tools/plan-mode.test.js +5 -5
  109. package/dist/tools/plan-mode.test.js.map +1 -1
  110. package/dist/tools/prompt-hints.d.ts.map +1 -1
  111. package/dist/tools/prompt-hints.js +2 -0
  112. package/dist/tools/prompt-hints.js.map +1 -1
  113. package/dist/tools/safe-env.d.ts.map +1 -1
  114. package/dist/tools/safe-env.js +27 -0
  115. package/dist/tools/safe-env.js.map +1 -1
  116. package/dist/ui/App.d.ts +1 -1
  117. package/dist/ui/App.d.ts.map +1 -1
  118. package/dist/ui/hooks/usePixelFixFlow.d.ts +1 -1
  119. package/dist/ui/hooks/usePixelFixFlow.d.ts.map +1 -1
  120. package/dist/ui/hooks/usePixelFixFlow.js +1 -1
  121. package/dist/ui/hooks/usePixelFixFlow.js.map +1 -1
  122. package/dist/ui/render.d.ts +1 -1
  123. package/dist/ui/render.d.ts.map +1 -1
  124. package/package.json +5 -5
@@ -0,0 +1,301 @@
1
+ import path from "node:path";
2
+ import { mkdir, writeFile, readFile } from "node:fs/promises";
3
+ import { z } from "zod";
4
+ import { resolvePath } from "./path-utils.js";
5
+ import { downscaleForPreview, shrinkToFit } from "../utils/image.js";
6
+ /**
7
+ * The Codex backend endpoint — the SAME endpoint our OpenAI Codex streaming
8
+ * provider uses for chat. ChatGPT OAuth tokens (from auth.openai.com PKCE flow)
9
+ * are rejected by api.openai.com/v1/images/* (missing `api.model.images.request`
10
+ * scope), but they work here. Image generation is done via the Responses API's
11
+ * built-in `image_generation` tool, which the backend routes to gpt-image-2.
12
+ */
13
+ const CODEX_ENDPOINT = "https://chatgpt.com/backend-api/codex/responses";
14
+ /** Model that supports the image_generation Responses API tool. */
15
+ const IMAGE_GEN_MODEL = "gpt-5.5";
16
+ const GenerateImageParams = z.object({
17
+ prompt: z.string().describe("Text description of the image to generate or the edit to apply"),
18
+ image: z
19
+ .string()
20
+ .optional()
21
+ .describe("Path to an existing image file to edit (use the path returned by a previous " +
22
+ "generate_image call, or a user-attached image path). When omitted, a new " +
23
+ "image is generated from scratch."),
24
+ size: z
25
+ .string()
26
+ .optional()
27
+ .describe("Output resolution. gpt-image-2 accepts any size where both edges are multiples " +
28
+ "of 16px, max edge ≤3840px, long:short ratio ≤3:1, total pixels 655,360–8,294,400. " +
29
+ "Popular: 1024x1024, 1536x1024, 1024x1536, 2048x2048. Default: auto."),
30
+ quality: z
31
+ .enum(["low", "medium", "high", "auto"])
32
+ .optional()
33
+ .describe("Rendering quality. Use 'low' for fast drafts, 'high' for final assets. Default: auto."),
34
+ n: z
35
+ .number()
36
+ .int()
37
+ .min(1)
38
+ .max(4)
39
+ .optional()
40
+ .describe("Number of images to generate (1–4, default 1)"),
41
+ out_path: z
42
+ .string()
43
+ .optional()
44
+ .describe("Where to save the generated image (relative to cwd or absolute). " +
45
+ "Defaults to .gg/generated/<timestamp>.png"),
46
+ output_format: z
47
+ .enum(["png", "jpeg", "webp"])
48
+ .optional()
49
+ .describe("Output file format (default png)"),
50
+ background: z
51
+ .enum(["opaque", "auto"])
52
+ .optional()
53
+ .describe("Background type (default auto; gpt-image-2 does not support transparent)"),
54
+ });
55
+ function defaultOutPath(cwd, format) {
56
+ const stamp = new Date().toISOString().replace(/[:.]/g, "-");
57
+ const ext = format === "png" ? "png" : format === "jpeg" ? "jpg" : "webp";
58
+ return path.join(cwd, ".gg", "generated", `${stamp}.${ext}`);
59
+ }
60
+ /** Format → media type for StructuredToolResult. */
61
+ function mediaTypeFor(format) {
62
+ if (format === "jpeg")
63
+ return "image/jpeg";
64
+ if (format === "webp")
65
+ return "image/webp";
66
+ return "image/png";
67
+ }
68
+ export function createGenerateImageTool(cwd, auth) {
69
+ return {
70
+ name: "generate_image",
71
+ description: "Generate or edit images using OpenAI's gpt-image-2 model. Works even when a different " +
72
+ "chat provider is active — only requires OpenAI to be connected. Only use this tool when " +
73
+ "the user explicitly asks to create, generate, or edit an image. Pass `image` with a " +
74
+ "file path to edit an existing image (e.g. a previously generated one or a user attachment). " +
75
+ "Use `out_path` to save to a specific location (defaults to .gg/generated/).",
76
+ parameters: GenerateImageParams,
77
+ async execute(args, context) {
78
+ if (context.signal.aborted)
79
+ return "Image generation aborted before start.";
80
+ // Resolve OpenAI credentials at execution time (lazy — token refresh
81
+ // happens on use, not at registration).
82
+ let token;
83
+ let accountId;
84
+ try {
85
+ const creds = await auth.resolveCredentials("openai");
86
+ token = creds.accessToken;
87
+ accountId = creds.accountId;
88
+ }
89
+ catch {
90
+ return ("OpenAI is not connected. The user needs to connect their OpenAI account " +
91
+ "to use image generation.");
92
+ }
93
+ const outputFormat = args.output_format ?? "png";
94
+ const mediaType = mediaTypeFor(outputFormat);
95
+ const outPath = args.out_path
96
+ ? resolvePath(cwd, args.out_path)
97
+ : defaultOutPath(cwd, outputFormat);
98
+ try {
99
+ // Build the image_generation tool definition with the requested params.
100
+ const imageTool = {
101
+ type: "image_generation",
102
+ output_format: outputFormat,
103
+ };
104
+ if (args.size)
105
+ imageTool.size = args.size;
106
+ if (args.quality)
107
+ imageTool.quality = args.quality;
108
+ if (args.n)
109
+ imageTool.n = args.n;
110
+ if (args.background)
111
+ imageTool.background = args.background;
112
+ // Build the input content — prompt text, optionally with a reference image.
113
+ const inputContent = [
114
+ { type: "input_text", text: args.prompt },
115
+ ];
116
+ if (args.image) {
117
+ // Edit mode: read the reference image and include it as input_image.
118
+ const imagePath = resolvePath(cwd, args.image);
119
+ let fileBuffer;
120
+ try {
121
+ fileBuffer = await readFile(imagePath);
122
+ }
123
+ catch {
124
+ return `Could not read the image at ${args.image}. Check the path is correct.`;
125
+ }
126
+ // The Responses API accepts images as data URLs.
127
+ const refMediaType = imagePath.toLowerCase().endsWith(".jpg") || imagePath.toLowerCase().endsWith(".jpeg")
128
+ ? "image/jpeg"
129
+ : imagePath.toLowerCase().endsWith(".webp")
130
+ ? "image/webp"
131
+ : "image/png";
132
+ inputContent.push({
133
+ type: "input_image",
134
+ image_url: `data:${refMediaType};base64,${fileBuffer.toString("base64")}`,
135
+ });
136
+ imageTool.action = "edit";
137
+ }
138
+ else {
139
+ imageTool.action = "generate";
140
+ }
141
+ // Call the Codex responses endpoint (same one our Codex streaming
142
+ // provider uses) with the image_generation built-in tool. ChatGPT OAuth
143
+ // tokens work here, unlike api.openai.com/v1/images/*.
144
+ const imageBuffers = await callImageGeneration(inputContent, imageTool, token, accountId, context.signal);
145
+ if (imageBuffers.length === 0) {
146
+ return "Image generation returned no results. The prompt may have been blocked by content moderation.";
147
+ }
148
+ // Save each image and build preview content.
149
+ const savedPaths = [];
150
+ for (let i = 0; i < imageBuffers.length; i++) {
151
+ const buf = imageBuffers[i];
152
+ const savePath = imageBuffers.length === 1 ? outPath : insertIndex(outPath, i);
153
+ await mkdir(path.dirname(savePath), { recursive: true });
154
+ await writeFile(savePath, buf);
155
+ savedPaths.push(savePath);
156
+ }
157
+ // The primary image (first) gets the full treatment: model-visible
158
+ // image + inline preview. Additional images are previewed only.
159
+ const primary = imageBuffers[0];
160
+ const primaryPath = savedPaths[0];
161
+ // Shrink for the model (provider image limits) and a smaller copy for
162
+ // the inline terminal/webview preview.
163
+ const { buffer: shrunk, mediaType: detectedType } = await shrinkToFit(primary, mediaType);
164
+ const previewBuffer = await downscaleForPreview(shrunk);
165
+ const imagePreviews = [
166
+ {
167
+ base64: previewBuffer.toString("base64"),
168
+ mediaType: detectedType,
169
+ path: primaryPath,
170
+ },
171
+ ];
172
+ // Include additional images as previews too.
173
+ for (let i = 1; i < imageBuffers.length; i++) {
174
+ const extraBuf = imageBuffers[i];
175
+ const extraPath = savedPaths[i];
176
+ const extraShrunk = await shrinkToFit(extraBuf, mediaType);
177
+ const extraPreview = await downscaleForPreview(extraShrunk.buffer);
178
+ imagePreviews.push({
179
+ base64: extraPreview.toString("base64"),
180
+ mediaType: extraShrunk.mediaType,
181
+ path: extraPath,
182
+ });
183
+ }
184
+ const summary = savedPaths.length === 1
185
+ ? `Generated image → ${primaryPath}`
186
+ : `Generated ${savedPaths.length} images → ${savedPaths.join(", ")}`;
187
+ const allContent = [
188
+ { type: "text", text: summary },
189
+ {
190
+ type: "image",
191
+ mediaType: detectedType,
192
+ data: shrunk.toString("base64"),
193
+ },
194
+ ];
195
+ return {
196
+ content: allContent,
197
+ details: { imagePreviews },
198
+ };
199
+ }
200
+ catch (err) {
201
+ if (context.signal.aborted)
202
+ return "Image generation aborted.";
203
+ const reason = err instanceof Error ? err.message : String(err);
204
+ return `Image generation failed: ${reason}`;
205
+ }
206
+ },
207
+ };
208
+ }
209
+ /** Insert a numeric index before the extension for multi-image output. */
210
+ function insertIndex(filePath, index) {
211
+ const ext = path.extname(filePath);
212
+ const base = filePath.slice(0, filePath.length - ext.length);
213
+ return `${base}_${index}${ext}`;
214
+ }
215
+ /**
216
+ * Call the Codex responses endpoint with the `image_generation` built-in tool.
217
+ * Reads the SSE stream and extracts base64 image data from
218
+ * `response.output_item.done` events where `item.type === "image_generation_call"`.
219
+ *
220
+ * The Codex backend requires `stream: true` and the ChatGPT OAuth token (which
221
+ * our auth.openai.com PKCE flow produces). The underlying image model is
222
+ * gpt-image-2, routed internally by the backend.
223
+ */
224
+ async function callImageGeneration(inputContent, imageTool, token, accountId, signal) {
225
+ const body = {
226
+ model: IMAGE_GEN_MODEL,
227
+ store: false,
228
+ stream: true,
229
+ instructions: "Generate the image the user requested.",
230
+ input: [{ role: "user", content: inputContent }],
231
+ tools: [imageTool],
232
+ tool_choice: "auto",
233
+ reasoning: { effort: "low" },
234
+ };
235
+ const response = await fetch(CODEX_ENDPOINT, {
236
+ method: "POST",
237
+ headers: {
238
+ "Content-Type": "application/json",
239
+ Authorization: `Bearer ${token}`,
240
+ ...(accountId ? { "chatgpt-account-id": accountId } : {}),
241
+ originator: "ggcoder",
242
+ },
243
+ body: JSON.stringify(body),
244
+ signal,
245
+ });
246
+ if (!response.ok) {
247
+ const text = await response.text();
248
+ let detail = text;
249
+ try {
250
+ const parsed = JSON.parse(text);
251
+ if (parsed.detail)
252
+ detail = parsed.detail;
253
+ else if (parsed.error?.message)
254
+ detail = parsed.error.message;
255
+ }
256
+ catch {
257
+ // Keep raw text
258
+ }
259
+ throw new Error(`OpenAI Image API (${response.status}): ${detail}`);
260
+ }
261
+ if (!response.body) {
262
+ throw new Error("OpenAI Image API returned no response body.");
263
+ }
264
+ // Read the SSE stream and extract image_generation_call output items.
265
+ const reader = response.body.getReader();
266
+ const decoder = new TextDecoder();
267
+ let buffer = "";
268
+ const imageBuffers = [];
269
+ while (true) {
270
+ const { done, value } = await reader.read();
271
+ if (done)
272
+ break;
273
+ buffer += decoder.decode(value, { stream: true });
274
+ const lines = buffer.split("\n");
275
+ buffer = lines.pop() ?? "";
276
+ for (const line of lines) {
277
+ if (!line.startsWith("data: "))
278
+ continue;
279
+ const data = line.slice(6);
280
+ if (data === "[DONE]")
281
+ continue;
282
+ try {
283
+ const evt = JSON.parse(data);
284
+ // The final image data arrives in `response.output_item.done` where
285
+ // item.type is "image_generation_call" and item.status is "completed"
286
+ // (or "generating" — both carry the result). We capture from either,
287
+ // preferring the last one with actual result data.
288
+ if (evt.type === "response.output_item.done" &&
289
+ evt.item?.type === "image_generation_call" &&
290
+ evt.item.result) {
291
+ imageBuffers.push(Buffer.from(evt.item.result, "base64"));
292
+ }
293
+ }
294
+ catch {
295
+ // Partial JSON — skip, the next chunk will complete it.
296
+ }
297
+ }
298
+ }
299
+ return imageBuffers;
300
+ }
301
+ //# sourceMappingURL=generate-image.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate-image.js","sourceRoot":"","sources":["../../src/tools/generate-image.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAerE;;;;;;GAMG;AACH,MAAM,cAAc,GAAG,iDAAiD,CAAC;AACzE,mEAAmE;AACnE,MAAM,eAAe,GAAG,SAAS,CAAC;AAElC,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;IACnC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,gEAAgE,CAAC;IAC7F,KAAK,EAAE,CAAC;SACL,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CACP,8EAA8E;QAC5E,2EAA2E;QAC3E,kCAAkC,CACrC;IACH,IAAI,EAAE,CAAC;SACJ,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CACP,iFAAiF;QAC/E,oFAAoF;QACpF,qEAAqE,CACxE;IACH,OAAO,EAAE,CAAC;SACP,IAAI,CAAC,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;SACvC,QAAQ,EAAE;SACV,QAAQ,CACP,uFAAuF,CACxF;IACH,CAAC,EAAE,CAAC;SACD,MAAM,EAAE;SACR,GAAG,EAAE;SACL,GAAG,CAAC,CAAC,CAAC;SACN,GAAG,CAAC,CAAC,CAAC;SACN,QAAQ,EAAE;SACV,QAAQ,CAAC,+CAA+C,CAAC;IAC5D,QAAQ,EAAE,CAAC;SACR,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CACP,mEAAmE;QACjE,2CAA2C,CAC9C;IACH,aAAa,EAAE,CAAC;SACb,IAAI,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;SAC7B,QAAQ,EAAE;SACV,QAAQ,CAAC,kCAAkC,CAAC;IAC/C,UAAU,EAAE,CAAC;SACV,IAAI,CAAC,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;SACxB,QAAQ,EAAE;SACV,QAAQ,CAAC,0EAA0E,CAAC;CACxF,CAAC,CAAC;AAIH,SAAS,cAAc,CAAC,GAAW,EAAE,MAAc;IACjD,MAAM,KAAK,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IAC7D,MAAM,GAAG,GAAG,MAAM,KAAK,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;IAC1E,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,KAAK,IAAI,GAAG,EAAE,CAAC,CAAC;AAC/D,CAAC;AAED,oDAAoD;AACpD,SAAS,YAAY,CAAC,MAAc;IAClC,IAAI,MAAM,KAAK,MAAM;QAAE,OAAO,YAAY,CAAC;IAC3C,IAAI,MAAM,KAAK,MAAM;QAAE,OAAO,YAAY,CAAC;IAC3C,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,MAAM,UAAU,uBAAuB,CACrC,GAAW,EACX,IAAuB;IAEvB,OAAO;QACL,IAAI,EAAE,gBAAgB;QACtB,WAAW,EACT,wFAAwF;YACxF,0FAA0F;YAC1F,sFAAsF;YACtF,8FAA8F;YAC9F,6EAA6E;QAC/E,UAAU,EAAE,mBAAmB;QAC/B,KAAK,CAAC,OAAO,CACX,IAAuB,EACvB,OAAoB;YAEpB,IAAI,OAAO,CAAC,MAAM,CAAC,OAAO;gBAAE,OAAO,wCAAwC,CAAC;YAE5E,qEAAqE;YACrE,wCAAwC;YACxC,IAAI,KAAa,CAAC;YAClB,IAAI,SAA6B,CAAC;YAClC,IAAI,CAAC;gBACH,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC;gBACtD,KAAK,GAAG,KAAK,CAAC,WAAW,CAAC;gBAC1B,SAAS,GAAG,KAAK,CAAC,SAAS,CAAC;YAC9B,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,CACL,0EAA0E;oBAC1E,0BAA0B,CAC3B,CAAC;YACJ,CAAC;YAED,MAAM,YAAY,GAAG,IAAI,CAAC,aAAa,IAAI,KAAK,CAAC;YACjD,MAAM,SAAS,GAAG,YAAY,CAAC,YAAY,CAAC,CAAC;YAC7C,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ;gBAC3B,CAAC,CAAC,WAAW,CAAC,GAAG,EAAE,IAAI,CAAC,QAAQ,CAAC;gBACjC,CAAC,CAAC,cAAc,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;YAEtC,IAAI,CAAC;gBACH,wEAAwE;gBACxE,MAAM,SAAS,GAA4B;oBACzC,IAAI,EAAE,kBAAkB;oBACxB,aAAa,EAAE,YAAY;iBAC5B,CAAC;gBACF,IAAI,IAAI,CAAC,IAAI;oBAAE,SAAS,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;gBAC1C,IAAI,IAAI,CAAC,OAAO;oBAAE,SAAS,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;gBACnD,IAAI,IAAI,CAAC,CAAC;oBAAE,SAAS,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;gBACjC,IAAI,IAAI,CAAC,UAAU;oBAAE,SAAS,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;gBAE5D,4EAA4E;gBAC5E,MAAM,YAAY,GAAmC;oBACnD,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE;iBAC1C,CAAC;gBAEF,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;oBACf,qEAAqE;oBACrE,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;oBAC/C,IAAI,UAAkB,CAAC;oBACvB,IAAI,CAAC;wBACH,UAAU,GAAG,MAAM,QAAQ,CAAC,SAAS,CAAC,CAAC;oBACzC,CAAC;oBAAC,MAAM,CAAC;wBACP,OAAO,+BAA+B,IAAI,CAAC,KAAK,8BAA8B,CAAC;oBACjF,CAAC;oBACD,iDAAiD;oBACjD,MAAM,YAAY,GAChB,SAAS,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,SAAS,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC;wBACnF,CAAC,CAAC,YAAY;wBACd,CAAC,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC;4BACzC,CAAC,CAAC,YAAY;4BACd,CAAC,CAAC,WAAW,CAAC;oBACpB,YAAY,CAAC,IAAI,CAAC;wBAChB,IAAI,EAAE,aAAa;wBACnB,SAAS,EAAE,QAAQ,YAAY,WAAW,UAAU,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE;qBAC1E,CAAC,CAAC;oBACH,SAAS,CAAC,MAAM,GAAG,MAAM,CAAC;gBAC5B,CAAC;qBAAM,CAAC;oBACN,SAAS,CAAC,MAAM,GAAG,UAAU,CAAC;gBAChC,CAAC;gBAED,kEAAkE;gBAClE,wEAAwE;gBACxE,uDAAuD;gBACvD,MAAM,YAAY,GAAG,MAAM,mBAAmB,CAC5C,YAAY,EACZ,SAAS,EACT,KAAK,EACL,SAAS,EACT,OAAO,CAAC,MAAM,CACf,CAAC;gBAEF,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;oBAC9B,OAAO,+FAA+F,CAAC;gBACzG,CAAC;gBAED,6CAA6C;gBAC7C,MAAM,UAAU,GAAa,EAAE,CAAC;gBAEhC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,YAAY,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;oBAC7C,MAAM,GAAG,GAAG,YAAY,CAAC,CAAC,CAAE,CAAC;oBAC7B,MAAM,QAAQ,GAAG,YAAY,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;oBAC/E,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;oBACzD,MAAM,SAAS,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;oBAC/B,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;gBAC5B,CAAC;gBAED,mEAAmE;gBACnE,gEAAgE;gBAChE,MAAM,OAAO,GAAG,YAAY,CAAC,CAAC,CAAE,CAAC;gBACjC,MAAM,WAAW,GAAG,UAAU,CAAC,CAAC,CAAE,CAAC;gBAEnC,sEAAsE;gBACtE,uCAAuC;gBACvC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,GAAG,MAAM,WAAW,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;gBAC1F,MAAM,aAAa,GAAG,MAAM,mBAAmB,CAAC,MAAM,CAAC,CAAC;gBAExD,MAAM,aAAa,GAAG;oBACpB;wBACE,MAAM,EAAE,aAAa,CAAC,QAAQ,CAAC,QAAQ,CAAC;wBACxC,SAAS,EAAE,YAAY;wBACvB,IAAI,EAAE,WAAW;qBAClB;iBACF,CAAC;gBAEF,6CAA6C;gBAC7C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,YAAY,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;oBAC7C,MAAM,QAAQ,GAAG,YAAY,CAAC,CAAC,CAAE,CAAC;oBAClC,MAAM,SAAS,GAAG,UAAU,CAAC,CAAC,CAAE,CAAC;oBACjC,MAAM,WAAW,GAAG,MAAM,WAAW,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;oBAC3D,MAAM,YAAY,GAAG,MAAM,mBAAmB,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;oBACnE,aAAa,CAAC,IAAI,CAAC;wBACjB,MAAM,EAAE,YAAY,CAAC,QAAQ,CAAC,QAAQ,CAAC;wBACvC,SAAS,EAAE,WAAW,CAAC,SAAS;wBAChC,IAAI,EAAE,SAAS;qBAChB,CAAC,CAAC;gBACL,CAAC;gBAED,MAAM,OAAO,GACX,UAAU,CAAC,MAAM,KAAK,CAAC;oBACrB,CAAC,CAAC,qBAAqB,WAAW,EAAE;oBACpC,CAAC,CAAC,aAAa,UAAU,CAAC,MAAM,aAAa,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gBAEzE,MAAM,UAAU,GAAoC;oBAClD,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE;oBAC/B;wBACE,IAAI,EAAE,OAAO;wBACb,SAAS,EAAE,YAAY;wBACvB,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC;qBAChC;iBACF,CAAC;gBAEF,OAAO;oBACL,OAAO,EAAE,UAAU;oBACnB,OAAO,EAAE,EAAE,aAAa,EAAE;iBAC3B,CAAC;YACJ,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,OAAO,CAAC,MAAM,CAAC,OAAO;oBAAE,OAAO,2BAA2B,CAAC;gBAC/D,MAAM,MAAM,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBAChE,OAAO,4BAA4B,MAAM,EAAE,CAAC;YAC9C,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC;AAED,0EAA0E;AAC1E,SAAS,WAAW,CAAC,QAAgB,EAAE,KAAa;IAClD,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACnC,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC;IAC7D,OAAO,GAAG,IAAI,IAAI,KAAK,GAAG,GAAG,EAAE,CAAC;AAClC,CAAC;AAED;;;;;;;;GAQG;AACH,KAAK,UAAU,mBAAmB,CAChC,YAA4C,EAC5C,SAAkC,EAClC,KAAa,EACb,SAA6B,EAC7B,MAAmB;IAEnB,MAAM,IAAI,GAA4B;QACpC,KAAK,EAAE,eAAe;QACtB,KAAK,EAAE,KAAK;QACZ,MAAM,EAAE,IAAI;QACZ,YAAY,EAAE,wCAAwC;QACtD,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC;QAChD,KAAK,EAAE,CAAC,SAAS,CAAC;QAClB,WAAW,EAAE,MAAM;QACnB,SAAS,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE;KAC7B,CAAC;IAEF,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,cAAc,EAAE;QAC3C,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,cAAc,EAAE,kBAAkB;YAClC,aAAa,EAAE,UAAU,KAAK,EAAE;YAChC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,oBAAoB,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACzD,UAAU,EAAE,SAAS;SACtB;QACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;QAC1B,MAAM;KACP,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QACnC,IAAI,MAAM,GAAG,IAAI,CAAC;QAClB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAsD,CAAC;YACrF,IAAI,MAAM,CAAC,MAAM;gBAAE,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;iBACrC,IAAI,MAAM,CAAC,KAAK,EAAE,OAAO;gBAAE,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC;QAChE,CAAC;QAAC,MAAM,CAAC;YACP,gBAAgB;QAClB,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,qBAAqB,QAAQ,CAAC,MAAM,MAAM,MAAM,EAAE,CAAC,CAAC;IACtE,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IACjE,CAAC;IAED,sEAAsE;IACtE,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;IACzC,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;IAClC,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,MAAM,YAAY,GAAa,EAAE,CAAC;IAElC,OAAO,IAAI,EAAE,CAAC;QACZ,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;QAC5C,IAAI,IAAI;YAAE,MAAM;QAChB,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;QAClD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACjC,MAAM,GAAG,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC;QAC3B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;gBAAE,SAAS;YACzC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAC3B,IAAI,IAAI,KAAK,QAAQ;gBAAE,SAAS;YAChC,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAO1B,CAAC;gBACF,oEAAoE;gBACpE,sEAAsE;gBACtE,qEAAqE;gBACrE,mDAAmD;gBACnD,IACE,GAAG,CAAC,IAAI,KAAK,2BAA2B;oBACxC,GAAG,CAAC,IAAI,EAAE,IAAI,KAAK,uBAAuB;oBAC1C,GAAG,CAAC,IAAI,CAAC,MAAM,EACf,CAAC;oBACD,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;gBAC5D,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,wDAAwD;YAC1D,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,YAAY,CAAC;AACtB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=generate-image.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate-image.test.d.ts","sourceRoot":"","sources":["../../src/tools/generate-image.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,223 @@
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import { mkdtemp, rm, readFile, writeFile, mkdir } from "node:fs/promises";
5
+ // A real, decodable 1×1 PNG so sharp (shrinkToFit / downscaleForPreview) works.
6
+ const TINY_PNG = Buffer.from("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==", "base64");
7
+ const TINY_PNG_B64 = TINY_PNG.toString("base64");
8
+ function ctx(signal) {
9
+ return { signal: signal ?? new AbortController().signal, toolCallId: "test" };
10
+ }
11
+ function isStructured(result) {
12
+ return typeof result !== "string";
13
+ }
14
+ /** A fake auth that always resolves the OpenAI token successfully. */
15
+ function fakeAuth() {
16
+ return {
17
+ async resolveCredentials() {
18
+ return { accessToken: "test-token", accountId: "acct-123" };
19
+ },
20
+ async hasProviderAuth() {
21
+ return true;
22
+ },
23
+ };
24
+ }
25
+ /** A fake auth that throws (OpenAI not connected). */
26
+ function noAuth() {
27
+ return {
28
+ async resolveCredentials() {
29
+ throw new Error("Not logged in to openai");
30
+ },
31
+ async hasProviderAuth() {
32
+ return false;
33
+ },
34
+ };
35
+ }
36
+ /**
37
+ * Build a fake SSE stream that emits a response.output_item.done event with
38
+ * image_generation_call result data, mimicking the Codex responses endpoint.
39
+ */
40
+ function makeImageSSEResponse(b64Images, status = 200) {
41
+ const events = [
42
+ `data: ${JSON.stringify({ type: "response.created" })}`,
43
+ `data: ${JSON.stringify({ type: "response.in_progress" })}`,
44
+ ];
45
+ for (const b64 of b64Images) {
46
+ events.push(`data: ${JSON.stringify({
47
+ type: "response.output_item.done",
48
+ item: {
49
+ type: "image_generation_call",
50
+ status: "completed",
51
+ result: b64,
52
+ },
53
+ })}`);
54
+ }
55
+ events.push(`data: ${JSON.stringify({ type: "response.completed" })}`);
56
+ events.push("data: [DONE]");
57
+ const sseBody = events.join("\n\n") + "\n\n";
58
+ const encoder = new TextEncoder();
59
+ const stream = new ReadableStream({
60
+ start(controller) {
61
+ controller.enqueue(encoder.encode(sseBody));
62
+ controller.close();
63
+ },
64
+ });
65
+ return new Response(stream, {
66
+ status,
67
+ headers: { "Content-Type": "text/event-stream" },
68
+ });
69
+ }
70
+ let tmpDir;
71
+ let originalFetch;
72
+ beforeEach(async () => {
73
+ tmpDir = await mkdtemp(path.join(os.tmpdir(), "ggcoder-genimg-"));
74
+ originalFetch = globalThis.fetch;
75
+ });
76
+ afterEach(async () => {
77
+ globalThis.fetch = originalFetch;
78
+ vi.restoreAllMocks();
79
+ await rm(tmpDir, { recursive: true, force: true });
80
+ });
81
+ describe("generate_image param schema", () => {
82
+ it("requires prompt and accepts optional params", async () => {
83
+ const { createGenerateImageTool } = await import("./generate-image.js");
84
+ const tool = createGenerateImageTool(tmpDir, fakeAuth());
85
+ const schema = tool.parameters;
86
+ expect(schema.safeParse({}).success).toBe(false);
87
+ expect(schema.safeParse({ prompt: "a cat" }).success).toBe(true);
88
+ expect(schema.safeParse({
89
+ prompt: "a cat",
90
+ size: "1024x1024",
91
+ quality: "high",
92
+ n: 2,
93
+ output_format: "webp",
94
+ background: "opaque",
95
+ out_path: "out.png",
96
+ }).success).toBe(true);
97
+ // Invalid quality rejected.
98
+ expect(schema.safeParse({ prompt: "x", quality: "ultra" }).success).toBe(false);
99
+ // n out of range.
100
+ expect(schema.safeParse({ prompt: "x", n: 5 }).success).toBe(false);
101
+ });
102
+ });
103
+ describe("generate_image — generation (no image input)", () => {
104
+ it("calls the Codex responses endpoint and returns structured image result", async () => {
105
+ const fetchMock = vi.fn().mockResolvedValue(makeImageSSEResponse([TINY_PNG_B64]));
106
+ globalThis.fetch = fetchMock;
107
+ const { createGenerateImageTool } = await import("./generate-image.js");
108
+ const tool = createGenerateImageTool(tmpDir, fakeAuth());
109
+ const result = await tool.execute({ prompt: "a cat sitting on a desk" }, ctx());
110
+ expect(fetchMock).toHaveBeenCalledOnce();
111
+ const [url, init] = fetchMock.mock.calls[0];
112
+ expect(url).toBe("https://chatgpt.com/backend-api/codex/responses");
113
+ expect(init?.method).toBe("POST");
114
+ const headers = init?.headers;
115
+ expect(headers["Authorization"]).toBe("Bearer test-token");
116
+ expect(headers["chatgpt-account-id"]).toBe("acct-123");
117
+ // The body should have image_generation tool with action: "generate"
118
+ const body = JSON.parse(init?.body);
119
+ expect(body.model).toBe("gpt-5.5");
120
+ expect(body.stream).toBe(true);
121
+ expect(body.tools[0].type).toBe("image_generation");
122
+ expect(body.tools[0].action).toBe("generate");
123
+ // The prompt should be in the input content
124
+ const inputContent = body.input[0].content;
125
+ expect(inputContent[0].type).toBe("input_text");
126
+ expect(inputContent[0].text).toBe("a cat sitting on a desk");
127
+ expect(isStructured(result)).toBe(true);
128
+ if (!isStructured(result))
129
+ return;
130
+ const blocks = Array.isArray(result.content) ? result.content : [];
131
+ const texts = blocks.filter((c) => c.type === "text");
132
+ const images = blocks.filter((c) => c.type === "image");
133
+ expect(texts.length).toBe(1);
134
+ expect(images.length).toBe(1);
135
+ // Should have imagePreviews in details.
136
+ const details = result.details;
137
+ expect(Array.isArray(details?.imagePreviews)).toBe(true);
138
+ expect(details.imagePreviews.length).toBe(1);
139
+ });
140
+ it("saves the image to out_path when provided", async () => {
141
+ globalThis.fetch = vi
142
+ .fn()
143
+ .mockResolvedValue(makeImageSSEResponse([TINY_PNG_B64]));
144
+ const { createGenerateImageTool } = await import("./generate-image.js");
145
+ const outPath = path.join(tmpDir, "custom.png");
146
+ const tool = createGenerateImageTool(tmpDir, fakeAuth());
147
+ await tool.execute({ prompt: "a logo", out_path: outPath }, ctx());
148
+ const saved = await readFile(outPath);
149
+ expect(saved.length).toBe(TINY_PNG.length);
150
+ });
151
+ });
152
+ describe("generate_image — edit (with image input)", () => {
153
+ it("includes the reference image as input_image and sets action to edit", async () => {
154
+ const refPath = path.join(tmpDir, "input.png");
155
+ await mkdir(path.dirname(refPath), { recursive: true });
156
+ await writeFile(refPath, TINY_PNG);
157
+ const fetchMock = vi.fn().mockResolvedValue(makeImageSSEResponse([TINY_PNG_B64]));
158
+ globalThis.fetch = fetchMock;
159
+ const { createGenerateImageTool } = await import("./generate-image.js");
160
+ const tool = createGenerateImageTool(tmpDir, fakeAuth());
161
+ const result = await tool.execute({ prompt: "make the background darker", image: refPath }, ctx());
162
+ expect(fetchMock).toHaveBeenCalledOnce();
163
+ const [url] = fetchMock.mock.calls[0];
164
+ expect(url).toBe("https://chatgpt.com/backend-api/codex/responses");
165
+ const body = JSON.parse(fetchMock.mock.calls[0][1].body);
166
+ expect(body.tools[0].action).toBe("edit");
167
+ // The input should have both text and input_image
168
+ const inputContent = body.input[0].content;
169
+ expect(inputContent).toHaveLength(2);
170
+ expect(inputContent[0].type).toBe("input_text");
171
+ expect(inputContent[1].type).toBe("input_image");
172
+ expect(inputContent[1].image_url).toContain("data:image/png;base64,");
173
+ expect(isStructured(result)).toBe(true);
174
+ });
175
+ it("returns a helpful error when the image path does not exist", async () => {
176
+ const { createGenerateImageTool } = await import("./generate-image.js");
177
+ const tool = createGenerateImageTool(tmpDir, fakeAuth());
178
+ const result = await tool.execute({ prompt: "edit this", image: path.join(tmpDir, "nonexistent.png") }, ctx());
179
+ expect(typeof result).toBe("string");
180
+ expect(result).toContain("Could not read");
181
+ });
182
+ });
183
+ describe("generate_image — error handling", () => {
184
+ it("returns a user-facing message when OpenAI is not connected", async () => {
185
+ const { createGenerateImageTool } = await import("./generate-image.js");
186
+ const tool = createGenerateImageTool(tmpDir, noAuth());
187
+ const result = await tool.execute({ prompt: "a cat" }, ctx());
188
+ expect(typeof result).toBe("string");
189
+ expect(result).toContain("not connected");
190
+ });
191
+ it("returns a user-facing message on API error (non-200)", async () => {
192
+ globalThis.fetch = vi
193
+ .fn()
194
+ .mockResolvedValue(new Response(JSON.stringify({ detail: "content moderation blocked" }), { status: 400 }));
195
+ const { createGenerateImageTool } = await import("./generate-image.js");
196
+ const tool = createGenerateImageTool(tmpDir, fakeAuth());
197
+ const result = await tool.execute({ prompt: "blocked content" }, ctx());
198
+ expect(typeof result).toBe("string");
199
+ expect(result).toContain("failed");
200
+ expect(result).toContain("moderation");
201
+ });
202
+ it("returns empty-results message when API succeeds but returns no image data", async () => {
203
+ // SSE stream with no image_generation_call events
204
+ globalThis.fetch = vi
205
+ .fn()
206
+ .mockResolvedValue(makeImageSSEResponse([]));
207
+ const { createGenerateImageTool } = await import("./generate-image.js");
208
+ const tool = createGenerateImageTool(tmpDir, fakeAuth());
209
+ const result = await tool.execute({ prompt: "something" }, ctx());
210
+ expect(typeof result).toBe("string");
211
+ expect(result).toContain("no results");
212
+ });
213
+ it("respects abort signal before making the API call", async () => {
214
+ const ac = new AbortController();
215
+ ac.abort();
216
+ const { createGenerateImageTool } = await import("./generate-image.js");
217
+ const tool = createGenerateImageTool(tmpDir, fakeAuth());
218
+ const result = await tool.execute({ prompt: "a cat" }, ctx(ac.signal));
219
+ expect(typeof result).toBe("string");
220
+ expect(result).toContain("aborted");
221
+ });
222
+ });
223
+ //# sourceMappingURL=generate-image.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate-image.test.js","sourceRoot":"","sources":["../../src/tools/generate-image.test.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  import type { AgentTool } from "@kenkaiiii/gg-agent";
2
2
  import { ProcessManager } from "../core/process-manager.js";
3
3
  import { LspManager } from "../core/lsp/manager.js";
4
+ import { type GenerateImageAuth } from "./generate-image.js";
4
5
  import { type ToolOperations } from "./operations.js";
5
6
  import type { AgentDefinition } from "../core/agents.js";
6
7
  import type { Skill } from "../core/skills.js";
@@ -47,6 +48,15 @@ export interface CreateToolsOptions {
47
48
  * a matching file — disabling this is a pure opt-out, not a capability loss.
48
49
  */
49
50
  lspDiagnostics?: boolean;
51
+ /**
52
+ * Auth storage for conditional tool registration. When provided AND the user
53
+ * has OpenAI connected, the `generate_image` tool is registered — letting the
54
+ * agent generate/edit images via OpenAI's Image API regardless of the active
55
+ * chat provider. Omitted by callers that don't want image generation.
56
+ */
57
+ authStorage?: GenerateImageAuth & {
58
+ hasProviderAuth(provider: string): Promise<boolean>;
59
+ };
50
60
  }
51
61
  export interface CreateToolsResult {
52
62
  tools: AgentTool[];
@@ -68,7 +78,7 @@ export interface CreateToolsResult {
68
78
  */
69
79
  lspManager?: LspManager;
70
80
  }
71
- export declare function createTools(cwd: string, opts?: CreateToolsOptions): CreateToolsResult;
81
+ export declare function createTools(cwd: string, opts?: CreateToolsOptions): Promise<CreateToolsResult>;
72
82
  export { createReadTool } from "./read.js";
73
83
  export { createWriteTool } from "./write.js";
74
84
  export { createEditTool } from "./edit.js";
@@ -85,6 +95,7 @@ export { createTaskStopTool } from "./task-stop.js";
85
95
  export { createTasksTool } from "./tasks.js";
86
96
  export { createSkillTool } from "./skill.js";
87
97
  export { createScreenshotTool } from "./screenshot.js";
98
+ export { createGenerateImageTool, type GenerateImageAuth } from "./generate-image.js";
88
99
  export { createEnterPlanTool } from "./enter-plan.js";
89
100
  export { createExitPlanTool } from "./exit-plan.js";
90
101
  export { ProcessManager } from "../core/process-manager.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"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"}