ima2-gen 1.1.7 → 1.1.9

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 (229) hide show
  1. package/README.md +56 -27
  2. package/bin/commands/annotate.js +137 -0
  3. package/bin/commands/annotate.ts +118 -0
  4. package/bin/commands/cancel.js +37 -33
  5. package/bin/commands/cancel.ts +45 -0
  6. package/bin/commands/canvas-versions.js +91 -0
  7. package/bin/commands/canvas-versions.ts +80 -0
  8. package/bin/commands/cardnews.js +293 -0
  9. package/bin/commands/cardnews.ts +248 -0
  10. package/bin/commands/comfy.js +63 -0
  11. package/bin/commands/comfy.ts +54 -0
  12. package/bin/commands/config.js +270 -0
  13. package/bin/commands/config.ts +265 -0
  14. package/bin/commands/edit.js +97 -72
  15. package/bin/commands/edit.ts +116 -0
  16. package/bin/commands/gen.js +140 -118
  17. package/bin/commands/gen.ts +176 -0
  18. package/bin/commands/history.js +164 -0
  19. package/bin/commands/history.ts +145 -0
  20. package/bin/commands/ls.js +60 -42
  21. package/bin/commands/ls.ts +60 -0
  22. package/bin/commands/metadata.js +45 -0
  23. package/bin/commands/metadata.ts +36 -0
  24. package/bin/commands/multimode.js +159 -0
  25. package/bin/commands/multimode.ts +146 -0
  26. package/bin/commands/node.js +176 -0
  27. package/bin/commands/node.ts +157 -0
  28. package/bin/commands/observability.js +201 -0
  29. package/bin/commands/observability.ts +176 -0
  30. package/bin/commands/ping.js +26 -20
  31. package/bin/commands/ping.ts +29 -0
  32. package/bin/commands/prompt.js +506 -0
  33. package/bin/commands/prompt.ts +421 -0
  34. package/bin/commands/ps.js +78 -71
  35. package/bin/commands/ps.ts +78 -0
  36. package/bin/commands/session.js +308 -0
  37. package/bin/commands/session.ts +265 -0
  38. package/bin/commands/show.js +75 -40
  39. package/bin/commands/show.ts +69 -0
  40. package/bin/ima2.js +324 -310
  41. package/bin/ima2.ts +444 -0
  42. package/bin/lib/args.js +75 -66
  43. package/bin/lib/args.ts +73 -0
  44. package/bin/lib/browser-id.js +15 -0
  45. package/bin/lib/browser-id.ts +16 -0
  46. package/bin/lib/client.js +91 -83
  47. package/bin/lib/client.ts +109 -0
  48. package/bin/lib/error-hints.js +14 -17
  49. package/bin/lib/error-hints.ts +23 -0
  50. package/bin/lib/files.js +26 -28
  51. package/bin/lib/files.ts +39 -0
  52. package/bin/lib/output.js +44 -42
  53. package/bin/lib/output.ts +58 -0
  54. package/bin/lib/platform.js +60 -56
  55. package/bin/lib/platform.ts +97 -0
  56. package/bin/lib/sse.js +73 -0
  57. package/bin/lib/sse.ts +73 -0
  58. package/bin/lib/star-prompt.js +69 -76
  59. package/bin/lib/star-prompt.ts +97 -0
  60. package/bin/lib/storage-doctor.js +34 -35
  61. package/bin/lib/storage-doctor.ts +38 -0
  62. package/config.js +147 -190
  63. package/config.ts +331 -0
  64. package/docs/API.md +48 -8
  65. package/docs/CLI.md +190 -0
  66. package/docs/FAQ.ko.md +5 -5
  67. package/docs/FAQ.md +5 -5
  68. package/docs/README.ja.md +71 -25
  69. package/docs/README.ko.md +61 -24
  70. package/docs/README.zh-CN.md +73 -27
  71. package/lib/assetLifecycle.js +130 -130
  72. package/lib/assetLifecycle.ts +142 -0
  73. package/lib/canvasVersionStore.js +135 -153
  74. package/lib/canvasVersionStore.ts +181 -0
  75. package/lib/cardNewsGenerator.js +127 -142
  76. package/lib/cardNewsGenerator.ts +162 -0
  77. package/lib/cardNewsJobStore.js +78 -84
  78. package/lib/cardNewsJobStore.ts +107 -0
  79. package/lib/cardNewsManifestStore.js +88 -93
  80. package/lib/cardNewsManifestStore.ts +112 -0
  81. package/lib/cardNewsPlanner.js +157 -152
  82. package/lib/cardNewsPlanner.ts +180 -0
  83. package/lib/cardNewsPlannerClient.js +101 -98
  84. package/lib/cardNewsPlannerClient.ts +114 -0
  85. package/lib/cardNewsPlannerPrompt.js +56 -56
  86. package/lib/cardNewsPlannerPrompt.ts +60 -0
  87. package/lib/cardNewsPlannerSchema.js +231 -223
  88. package/lib/cardNewsPlannerSchema.ts +259 -0
  89. package/lib/cardNewsRoleTemplateStore.js +39 -41
  90. package/lib/cardNewsRoleTemplateStore.ts +47 -0
  91. package/lib/cardNewsTemplateStore.js +171 -175
  92. package/lib/cardNewsTemplateStore.ts +210 -0
  93. package/lib/codexDetect.js +44 -47
  94. package/lib/codexDetect.ts +69 -0
  95. package/lib/comfyBridge.js +164 -184
  96. package/lib/comfyBridge.ts +214 -0
  97. package/lib/db.js +41 -51
  98. package/lib/db.ts +166 -0
  99. package/lib/errorClassify.js +62 -78
  100. package/lib/errorClassify.ts +100 -0
  101. package/lib/generationErrors.js +140 -103
  102. package/lib/generationErrors.ts +125 -0
  103. package/lib/historyList.js +149 -147
  104. package/lib/historyList.ts +164 -0
  105. package/lib/imageMetadata.js +86 -89
  106. package/lib/imageMetadata.ts +111 -0
  107. package/lib/imageMetadataStore.js +46 -51
  108. package/lib/imageMetadataStore.ts +67 -0
  109. package/lib/imageModels.js +38 -45
  110. package/lib/imageModels.ts +52 -0
  111. package/lib/inflight.js +131 -150
  112. package/lib/inflight.ts +204 -0
  113. package/lib/localImportStore.js +105 -0
  114. package/lib/localImportStore.ts +111 -0
  115. package/lib/logger.js +105 -112
  116. package/lib/logger.ts +150 -0
  117. package/lib/nodeStore.js +65 -64
  118. package/lib/nodeStore.ts +81 -0
  119. package/lib/oauthLauncher.js +61 -59
  120. package/lib/oauthLauncher.ts +64 -0
  121. package/lib/oauthNormalize.js +15 -19
  122. package/lib/oauthNormalize.ts +30 -0
  123. package/lib/oauthProxy.js +834 -832
  124. package/lib/oauthProxy.ts +995 -0
  125. package/lib/openDirectory.js +41 -40
  126. package/lib/openDirectory.ts +45 -0
  127. package/lib/pngInfo.js +18 -20
  128. package/lib/pngInfo.ts +26 -0
  129. package/lib/promptImport/curatedSources.js +135 -0
  130. package/lib/promptImport/curatedSources.ts +139 -0
  131. package/lib/promptImport/discoveryRegistry.js +218 -0
  132. package/lib/promptImport/discoveryRegistry.ts +236 -0
  133. package/lib/promptImport/errors.js +10 -10
  134. package/lib/promptImport/errors.ts +18 -0
  135. package/lib/promptImport/githubDiscovery.js +238 -0
  136. package/lib/promptImport/githubDiscovery.ts +248 -0
  137. package/lib/promptImport/githubFolder.js +302 -0
  138. package/lib/promptImport/githubFolder.ts +308 -0
  139. package/lib/promptImport/githubSource.js +194 -171
  140. package/lib/promptImport/githubSource.ts +239 -0
  141. package/lib/promptImport/gptImageHints.js +61 -0
  142. package/lib/promptImport/gptImageHints.ts +68 -0
  143. package/lib/promptImport/parsePromptCandidates.js +110 -112
  144. package/lib/promptImport/parsePromptCandidates.ts +153 -0
  145. package/lib/promptImport/promptIndex.js +230 -0
  146. package/lib/promptImport/promptIndex.ts +248 -0
  147. package/lib/promptImport/rankPromptCandidates.js +52 -0
  148. package/lib/promptImport/rankPromptCandidates.ts +49 -0
  149. package/lib/providerOptions.js +31 -0
  150. package/lib/providerOptions.ts +41 -0
  151. package/lib/referenceImageCompress.js +51 -62
  152. package/lib/referenceImageCompress.ts +75 -0
  153. package/lib/refs.js +93 -81
  154. package/lib/refs.ts +117 -0
  155. package/lib/requestLogger.js +32 -38
  156. package/lib/requestLogger.ts +48 -0
  157. package/lib/responsesImageAdapter.js +351 -0
  158. package/lib/responsesImageAdapter.ts +352 -0
  159. package/lib/runtimePorts.js +71 -73
  160. package/lib/runtimePorts.ts +93 -0
  161. package/lib/sessionStore.js +179 -230
  162. package/lib/sessionStore.ts +272 -0
  163. package/lib/storageMigration.js +247 -245
  164. package/lib/storageMigration.ts +284 -0
  165. package/lib/styleSheet.js +86 -90
  166. package/lib/styleSheet.ts +128 -0
  167. package/lib/systemTrash.js +18 -0
  168. package/lib/systemTrash.ts +20 -0
  169. package/package.json +26 -10
  170. package/routes/annotations.js +76 -79
  171. package/routes/annotations.ts +95 -0
  172. package/routes/canvasVersions.js +50 -54
  173. package/routes/canvasVersions.ts +64 -0
  174. package/routes/cardNews.js +158 -171
  175. package/routes/cardNews.ts +183 -0
  176. package/routes/comfy.js +23 -31
  177. package/routes/comfy.ts +39 -0
  178. package/routes/edit.js +183 -214
  179. package/routes/edit.ts +230 -0
  180. package/routes/generate.js +269 -291
  181. package/routes/generate.ts +309 -0
  182. package/routes/health.js +102 -107
  183. package/routes/health.ts +114 -0
  184. package/routes/history.js +136 -144
  185. package/routes/history.ts +153 -0
  186. package/routes/imageImport.js +33 -0
  187. package/routes/imageImport.ts +33 -0
  188. package/routes/index.js +18 -16
  189. package/routes/index.ts +35 -0
  190. package/routes/metadata.js +60 -64
  191. package/routes/metadata.ts +71 -0
  192. package/routes/multimode.js +228 -263
  193. package/routes/multimode.ts +280 -0
  194. package/routes/nodes.js +378 -424
  195. package/routes/nodes.ts +455 -0
  196. package/routes/promptImport.js +291 -152
  197. package/routes/promptImport.ts +354 -0
  198. package/routes/prompts.js +333 -360
  199. package/routes/prompts.ts +379 -0
  200. package/routes/sessions.js +277 -285
  201. package/routes/sessions.ts +292 -0
  202. package/routes/storage.js +29 -31
  203. package/routes/storage.ts +39 -0
  204. package/server.js +189 -196
  205. package/server.ts +235 -0
  206. package/ui/dist/.vite/manifest.json +101 -0
  207. package/ui/dist/assets/CardNewsWorkspace-BJOCey7Z.js +2 -0
  208. package/ui/dist/assets/NodeCanvas-BZV40eAE.css +1 -0
  209. package/ui/dist/assets/NodeCanvas-C3dzYNsk.js +7 -0
  210. package/ui/dist/assets/PromptImportDialog-Dqu1VpUh.js +2 -0
  211. package/ui/dist/assets/PromptImportDiscoverySection-Dg8T9X0L.js +1 -0
  212. package/ui/dist/assets/PromptImportFolderSection-DBaqsFO4.js +1 -0
  213. package/ui/dist/assets/PromptLibraryPanel-p5QqR97M.js +2 -0
  214. package/ui/dist/assets/SettingsWorkspace-B5bSAZ6u.js +1 -0
  215. package/ui/dist/assets/index-C9cXwiWE.js +25 -0
  216. package/ui/dist/assets/index-CGMIkZXn.css +1 -0
  217. package/ui/dist/assets/index-Cvld7dUZ.js +1 -0
  218. package/ui/dist/index.html +6 -3
  219. package/assets/screenshot.png +0 -0
  220. package/assets/screenshots/classic-generate-light.png +0 -0
  221. package/assets/screenshots/node-graph-branching.png +0 -0
  222. package/assets/screenshots/settings-oauth-generation.png +0 -0
  223. package/assets/screenshots/settings-workspace.png +0 -0
  224. package/assets/screenshots/style-sheet-editor.png +0 -0
  225. package/integrations/comfyui/ima2_gen_bridge/__pycache__/__init__.cpython-313.pyc +0 -0
  226. package/integrations/comfyui/ima2_gen_bridge/__pycache__/nodes.cpython-313.pyc +0 -0
  227. package/ui/dist/assets/index-DARPdT4Q.css +0 -1
  228. package/ui/dist/assets/index-ht80GMq4.js +0 -31
  229. package/ui/dist/assets/index-ht80GMq4.js.map +0 -1
@@ -0,0 +1,351 @@
1
+ import { setJobPhase } from "./inflight.js";
2
+ import { logEvent } from "./logger.js";
3
+ import { classifyUpstreamError, classifyUpstreamErrorCode } from "./errorClassify.js";
4
+ import { compressReferenceB64ForOAuth } from "./referenceImageCompress.js";
5
+ import { detectImageMimeFromB64 } from "./refs.js";
6
+ import { AUTO_PROMPT_FIDELITY_SUFFIX, DIRECT_PROMPT_FIDELITY_SUFFIX, EDIT_DEVELOPER_PROMPT, EDIT_NO_SEARCH_DEVELOPER_PROMPT, GENERATE_DEVELOPER_PROMPT, GENERATE_NO_SEARCH_DEVELOPER_PROMPT, buildEditTextPrompt, buildMultimodeSequencePrompt, buildUserTextPrompt, waitForOAuthReady, } from "./oauthProxy.js";
7
+ function makeError(message, { status = 500, code = "RESPONSES_IMAGE_ERROR", cause, ...rest } = {}) {
8
+ const err = new Error(message);
9
+ err.status = status;
10
+ err.code = code;
11
+ if (cause)
12
+ err.cause = cause;
13
+ Object.assign(err, rest);
14
+ return err;
15
+ }
16
+ function parseOpenAIErrorBody(text) {
17
+ try {
18
+ const parsed = JSON.parse(text);
19
+ const error = parsed?.error || {};
20
+ return {
21
+ message: typeof error.message === "string" && error.message ? error.message : "OpenAI request failed",
22
+ code: typeof error.code === "string" ? error.code : null,
23
+ type: typeof error.type === "string" ? error.type : null,
24
+ param: typeof error.param === "string" ? error.param : null,
25
+ };
26
+ }
27
+ catch {
28
+ return null;
29
+ }
30
+ }
31
+ function normalizedCode(upstream) {
32
+ const byCode = classifyUpstreamErrorCode(upstream?.code);
33
+ if (byCode !== "UNKNOWN")
34
+ return byCode;
35
+ const byType = classifyUpstreamErrorCode(upstream?.type);
36
+ if (byType !== "UNKNOWN")
37
+ return byType;
38
+ const byMessage = classifyUpstreamError(upstream?.message);
39
+ return byMessage !== "UNKNOWN" ? byMessage : "RESPONSES_IMAGE_ERROR";
40
+ }
41
+ function safeUpstreamClientMessage(upstream, status) {
42
+ const code = normalizedCode(upstream);
43
+ if (code === "AUTH_API_KEY_INVALID")
44
+ return "API key is invalid or unavailable.";
45
+ if (code === "MODERATION_REFUSED")
46
+ return "OpenAI refused the image request for safety reasons.";
47
+ if (code === "INVALID_REQUEST")
48
+ return "OpenAI rejected the image request parameters.";
49
+ if (status === 401 || status === 403)
50
+ return "OpenAI authentication failed.";
51
+ if (status === 429)
52
+ return "OpenAI rate limited the image request.";
53
+ return "OpenAI rejected the image request.";
54
+ }
55
+ async function getEndpoint(ctx, provider, scope) {
56
+ if (provider === "api") {
57
+ if (!ctx?.apiKey) {
58
+ throw makeError("API key is required for API provider image generation", {
59
+ status: 401,
60
+ code: "API_KEY_REQUIRED",
61
+ });
62
+ }
63
+ return {
64
+ url: "https://api.openai.com/v1/responses",
65
+ headers: {
66
+ "Content-Type": "application/json",
67
+ Accept: "text/event-stream",
68
+ Authorization: `Bearer ${ctx.apiKey}`,
69
+ },
70
+ };
71
+ }
72
+ await waitForOAuthReady(ctx);
73
+ const port = ctx?.config?.oauth?.proxyPort || 10531;
74
+ return {
75
+ url: `${ctx?.oauthUrl || `http://127.0.0.1:${port}`}/v1/responses`,
76
+ headers: { "Content-Type": "application/json", Accept: "text/event-stream" },
77
+ };
78
+ }
79
+ function tools(webSearchEnabled, imageOptions) {
80
+ return [
81
+ ...(webSearchEnabled ? [{ type: "web_search" }] : []),
82
+ { type: "image_generation", ...imageOptions },
83
+ ];
84
+ }
85
+ function normalizeRef(ref) {
86
+ const b64 = typeof ref === "string" ? ref : ref?.b64;
87
+ const detectedMime = typeof ref === "object" && ref?.detectedMime
88
+ ? ref.detectedMime
89
+ : detectImageMimeFromB64(b64);
90
+ const declaredMime = typeof ref === "object" ? ref?.declaredMime : null;
91
+ const mime = ["image/png", "image/jpeg", "image/webp"].includes(detectedMime)
92
+ ? detectedMime
93
+ : ["image/png", "image/jpeg", "image/webp"].includes(declaredMime)
94
+ ? declaredMime
95
+ : "image/png";
96
+ return { type: "input_image", image_url: `data:${mime};base64,${b64}` };
97
+ }
98
+ function extractSseData(block) {
99
+ let eventData = "";
100
+ for (const line of block.split("\n")) {
101
+ if (line.startsWith("data: "))
102
+ eventData += line.slice(6);
103
+ }
104
+ return eventData;
105
+ }
106
+ function extractPartialImage(data) {
107
+ if (typeof data?.type !== "string" || !data.type.includes("partial"))
108
+ return null;
109
+ const item = data.item || {};
110
+ const b64 = data.partial_image || data.image || data.result || item.partial_image || item.image || item.result;
111
+ if (typeof b64 !== "string" || b64.length === 0)
112
+ return null;
113
+ const index = Number.isFinite(data.index) ? data.index : Number.isFinite(item.index) ? item.index : null;
114
+ return { b64, index };
115
+ }
116
+ async function parseStream(res, { requestId, scope, maxImages = 1, onPartialImage = null } = {}) {
117
+ const reader = res.body.getReader();
118
+ const decoder = new TextDecoder();
119
+ const images = [];
120
+ const eventTypes = {};
121
+ let buffer = "";
122
+ let usage = null;
123
+ let webSearchCalls = 0;
124
+ let eventCount = 0;
125
+ let extraIgnored = 0;
126
+ while (true) {
127
+ const { done, value } = await reader.read();
128
+ if (done)
129
+ break;
130
+ buffer += decoder.decode(value, { stream: true });
131
+ let boundary;
132
+ while ((boundary = buffer.indexOf("\n\n")) !== -1) {
133
+ const block = buffer.slice(0, boundary);
134
+ buffer = buffer.slice(boundary + 2);
135
+ const eventData = extractSseData(block);
136
+ if (!eventData || eventData === "[DONE]")
137
+ continue;
138
+ let data;
139
+ try {
140
+ data = JSON.parse(eventData);
141
+ }
142
+ catch {
143
+ continue;
144
+ }
145
+ eventCount++;
146
+ eventTypes[data.type || "_unknown"] = (eventTypes[data.type || "_unknown"] || 0) + 1;
147
+ const partial = extractPartialImage(data);
148
+ if (partial && typeof onPartialImage === "function")
149
+ onPartialImage(partial);
150
+ if (data.type === "response.output_item.done" && data.item?.type === "image_generation_call") {
151
+ if (data.item.result && images.length < maxImages) {
152
+ images.push({
153
+ b64: data.item.result,
154
+ revisedPrompt: typeof data.item.revised_prompt === "string" ? data.item.revised_prompt : null,
155
+ });
156
+ if (requestId)
157
+ setJobPhase(requestId, "decoding");
158
+ }
159
+ else if (data.item.result)
160
+ extraIgnored++;
161
+ }
162
+ if (data.type === "response.output_item.done" && data.item?.type === "web_search_call")
163
+ webSearchCalls++;
164
+ if (data.type === "response.completed") {
165
+ usage = data.response?.usage || null;
166
+ const wsNum = data.response?.tool_usage?.web_search?.num_requests;
167
+ if (typeof wsNum === "number" && wsNum > webSearchCalls)
168
+ webSearchCalls = wsNum;
169
+ }
170
+ if (data.type === "error") {
171
+ throw makeError("Responses stream returned an error", {
172
+ code: data.error?.code || "RESPONSES_STREAM_ERROR",
173
+ eventCount,
174
+ eventType: data.type,
175
+ });
176
+ }
177
+ }
178
+ }
179
+ logEvent(scope, "stream_end", { requestId, events: eventCount, imageCount: images.length });
180
+ return { images, usage, webSearchCalls, eventCount, eventTypes, extraIgnored };
181
+ }
182
+ async function parseJson(res, maxImages) {
183
+ const json = await res.json();
184
+ const images = [];
185
+ let webSearchCalls = 0;
186
+ for (const item of json.output || []) {
187
+ if (item.type === "image_generation_call" && item.result && images.length < maxImages) {
188
+ images.push({
189
+ b64: item.result,
190
+ revisedPrompt: typeof item.revised_prompt === "string" ? item.revised_prompt : null,
191
+ });
192
+ }
193
+ if (item.type === "web_search_call")
194
+ webSearchCalls++;
195
+ }
196
+ return { images, usage: json.usage || null, webSearchCalls, eventCount: 0, eventTypes: {}, extraIgnored: 0 };
197
+ }
198
+ async function postResponses({ ctx, provider, scope, payload, requestId, maxImages = 1, onPartialImage = null }) {
199
+ const { url, headers } = await getEndpoint(ctx, provider, scope);
200
+ const timeoutMs = ctx?.config?.oauth?.generationTimeoutMs || 400 * 1000;
201
+ const controller = new AbortController();
202
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
203
+ try {
204
+ const res = await fetch(url, {
205
+ method: "POST",
206
+ headers,
207
+ signal: controller.signal,
208
+ body: JSON.stringify(payload),
209
+ });
210
+ logEvent(scope, "response", { requestId, provider, status: res.status, contentType: res.headers.get("content-type") });
211
+ if (!res.ok) {
212
+ const text = await res.text();
213
+ const upstream = parseOpenAIErrorBody(text);
214
+ if (res.status >= 400 && res.status < 500 && upstream?.message) {
215
+ throw makeError(safeUpstreamClientMessage(upstream, res.status), {
216
+ status: res.status,
217
+ code: normalizedCode(upstream),
218
+ upstreamBodyChars: text.length,
219
+ upstreamCode: upstream.code,
220
+ upstreamType: upstream.type,
221
+ upstreamParam: upstream.param,
222
+ upstreamMessageRedacted: true,
223
+ });
224
+ }
225
+ throw makeError(`${provider === "api" ? "OpenAI API" : "OAuth proxy"} returned ${res.status}`, {
226
+ status: res.status,
227
+ upstreamBodyChars: text.length,
228
+ });
229
+ }
230
+ if (requestId)
231
+ setJobPhase(requestId, "streaming");
232
+ const contentType = res.headers.get("content-type") || "";
233
+ return contentType.includes("text/event-stream")
234
+ ? await parseStream(res, { requestId, scope, maxImages, onPartialImage })
235
+ : await parseJson(res, maxImages);
236
+ }
237
+ catch (err) {
238
+ if (err?.name === "AbortError") {
239
+ throw makeError("Responses image generation timed out", { status: 504, code: "RESPONSES_IMAGE_TIMEOUT", cause: err });
240
+ }
241
+ throw err;
242
+ }
243
+ finally {
244
+ clearTimeout(timer);
245
+ }
246
+ }
247
+ export async function generateViaResponses(provider, prompt, quality, size, moderation = "low", references = [], requestId = null, mode = "auto", ctx = {}, options = {}) {
248
+ const webSearchEnabled = options.webSearchEnabled !== false && options.searchMode !== "off";
249
+ const referenceInputs = references.map(normalizeRef);
250
+ const userContent = referenceInputs.length
251
+ ? [...referenceInputs, { type: "input_text", text: buildUserTextPrompt(prompt, mode, { webSearchEnabled }) }]
252
+ : buildUserTextPrompt(prompt, mode, { webSearchEnabled });
253
+ const result = await postResponses({
254
+ ctx,
255
+ provider,
256
+ scope: provider === "api" ? "api-generate" : "oauth",
257
+ requestId,
258
+ maxImages: 1,
259
+ onPartialImage: options.onPartialImage,
260
+ payload: {
261
+ model: options.model || ctx.config?.imageModels?.default || "gpt-5.4-mini",
262
+ input: [
263
+ { role: "developer", content: webSearchEnabled ? GENERATE_DEVELOPER_PROMPT : GENERATE_NO_SEARCH_DEVELOPER_PROMPT },
264
+ { role: "user", content: userContent },
265
+ ],
266
+ tools: tools(webSearchEnabled, { quality, size, moderation, ...(options.partialImages ? { partial_images: options.partialImages } : {}) }),
267
+ tool_choice: "required",
268
+ reasoning: { effort: options.reasoningEffort || "low" },
269
+ stream: true,
270
+ },
271
+ });
272
+ const image = result.images[0];
273
+ if (!image?.b64)
274
+ throw makeError("No image data received from Responses API", { code: "EMPTY_RESPONSE", eventCount: result.eventCount });
275
+ return { b64: image.b64, usage: result.usage, webSearchCalls: result.webSearchCalls, revisedPrompt: image.revisedPrompt };
276
+ }
277
+ export async function generateMultimodeViaResponses(provider, prompt, quality, size, moderation = "low", references = [], requestId = null, mode = "auto", ctx = {}, options = {}) {
278
+ const maxImages = Math.min(8, Math.max(1, Math.trunc(Number(options.maxImages) || 1)));
279
+ const webSearchEnabled = options.webSearchEnabled !== false && options.searchMode !== "off";
280
+ const userText = buildMultimodeSequencePrompt(mode === "direct"
281
+ ? `${prompt}${DIRECT_PROMPT_FIDELITY_SUFFIX}`
282
+ : `${prompt}${webSearchEnabled ? "" : ""}${AUTO_PROMPT_FIDELITY_SUFFIX}`, maxImages, { webSearchEnabled });
283
+ const referenceInputs = references.map(normalizeRef);
284
+ const userContent = referenceInputs.length
285
+ ? [...referenceInputs, { type: "input_text", text: userText }]
286
+ : userText;
287
+ return await postResponses({
288
+ ctx,
289
+ provider,
290
+ scope: provider === "api" ? "api-multimode" : "oauth-multimode",
291
+ requestId,
292
+ maxImages,
293
+ onPartialImage: options.onPartialImage,
294
+ payload: {
295
+ model: options.model || ctx.config?.imageModels?.default || "gpt-5.4-mini",
296
+ input: [
297
+ { role: "developer", content: `Create up to ${maxImages} separate image_generation_call outputs. Do not create a collage, grid, contact sheet, storyboard sheet, or multi-panel single image.` },
298
+ { role: "user", content: userContent },
299
+ ],
300
+ tools: tools(webSearchEnabled, { quality, size, moderation, ...(options.partialImages ? { partial_images: options.partialImages } : {}) }),
301
+ tool_choice: "required",
302
+ reasoning: { effort: options.reasoningEffort || "low" },
303
+ stream: true,
304
+ },
305
+ });
306
+ }
307
+ export async function editViaResponses(provider, prompt, imageB64, quality, size, moderation = "low", mode = "auto", ctx = {}, requestId = null, options = {}) {
308
+ const webSearchEnabled = options.webSearchEnabled !== false && options.searchMode !== "off";
309
+ const imageForRequest = await compressReferenceB64ForOAuth(imageB64, {
310
+ maxB64Bytes: ctx.config?.limits?.maxRefB64Bytes,
311
+ force: true,
312
+ });
313
+ const referenceImages = await Promise.all((Array.isArray(options.references) ? options.references : []).map((ref) => compressReferenceB64ForOAuth(typeof ref === "string" ? ref : ref?.b64, {
314
+ maxB64Bytes: ctx.config?.limits?.maxRefB64Bytes,
315
+ force: true,
316
+ })));
317
+ const maskContent = typeof options.mask === "string" && options.mask.length > 0
318
+ ? [
319
+ { type: "input_image", image_url: `data:image/png;base64,${options.mask}` },
320
+ { type: "input_text", text: "The previous image is an edit mask guide. Use it as prompt guidance for where the edit should apply; it is not a visible final image element." },
321
+ ]
322
+ : [];
323
+ const userContent = [
324
+ { type: "input_image", image_url: `data:image/jpeg;base64,${imageForRequest.b64}` },
325
+ ...referenceImages.map(({ b64 }) => ({ type: "input_image", image_url: `data:image/jpeg;base64,${b64}` })),
326
+ ...maskContent,
327
+ { type: "input_text", text: buildEditTextPrompt(prompt, mode, { webSearchEnabled }) },
328
+ ];
329
+ const result = await postResponses({
330
+ ctx,
331
+ provider,
332
+ scope: provider === "api" ? "api-edit" : "oauth-edit",
333
+ requestId,
334
+ maxImages: 1,
335
+ payload: {
336
+ model: options.model || ctx.config?.imageModels?.default || "gpt-5.4-mini",
337
+ input: [
338
+ { role: "developer", content: webSearchEnabled ? EDIT_DEVELOPER_PROMPT : EDIT_NO_SEARCH_DEVELOPER_PROMPT },
339
+ { role: "user", content: userContent },
340
+ ],
341
+ tools: tools(webSearchEnabled, { quality, size, moderation }),
342
+ tool_choice: "required",
343
+ reasoning: { effort: options.reasoningEffort || "low" },
344
+ stream: true,
345
+ },
346
+ });
347
+ const image = result.images[0];
348
+ if (!image?.b64)
349
+ throw makeError("No image data received from Responses edit", { code: "EMPTY_RESPONSE", eventCount: result.eventCount });
350
+ return { b64: image.b64, usage: result.usage, revisedPrompt: image.revisedPrompt, webSearchCalls: result.webSearchCalls };
351
+ }