ima2-gen 1.1.21 → 1.1.22

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 (208) hide show
  1. package/README.md +30 -4
  2. package/bin/ima2.js +14 -4
  3. package/bin/lib/platform.js +34 -5
  4. package/docs/README.ko.md +31 -0
  5. package/lib/agentQueueWorker.js +6 -0
  6. package/lib/agentRuntime.js +3 -2
  7. package/lib/atomicWrite.js +14 -0
  8. package/lib/grokProxyLauncher.js +5 -3
  9. package/lib/inflight.js +1 -1
  10. package/lib/oauthLauncher.js +5 -0
  11. package/lib/videoFrameExtract.js +3 -3
  12. package/package.json +5 -7
  13. package/routes/edit.js +2 -1
  14. package/routes/generate.js +4 -3
  15. package/routes/health.js +4 -3
  16. package/routes/multimode.js +2 -1
  17. package/routes/video.js +4 -2
  18. package/server.js +29 -2
  19. package/ui/dist/.vite/manifest.json +12 -12
  20. package/ui/dist/assets/{AgentWorkspace-B_hq9CLg.js → AgentWorkspace-COxQ5TjU.js} +1 -1
  21. package/ui/dist/assets/{CardNewsWorkspace-wD12J7qk.js → CardNewsWorkspace-B0OkcuVz.js} +1 -1
  22. package/ui/dist/assets/{NodeCanvas-CI_wuPMf.js → NodeCanvas-BSsclEBh.js} +1 -1
  23. package/ui/dist/assets/{PromptBuilderPanel-CUTujJUV.js → PromptBuilderPanel-DpC9A5Rz.js} +1 -1
  24. package/ui/dist/assets/{PromptImportDialog-CUi66jPK.js → PromptImportDialog-CVwT0rLd.js} +2 -2
  25. package/ui/dist/assets/{PromptImportDiscoverySection-Cm3vrjY4.js → PromptImportDiscoverySection-BDCkRCRs.js} +1 -1
  26. package/ui/dist/assets/{PromptImportFolderSection-DOtWTD9n.js → PromptImportFolderSection-QoKbZD83.js} +1 -1
  27. package/ui/dist/assets/{PromptLibraryPanel-BMjQegRa.js → PromptLibraryPanel-BhFgeKnY.js} +2 -2
  28. package/ui/dist/assets/SettingsWorkspace-CfjrlH5R.js +1 -0
  29. package/ui/dist/assets/index-C-mur7pa.css +1 -0
  30. package/ui/dist/assets/index-CCP5nUOj.js +42 -0
  31. package/ui/dist/assets/{index-31uVIdt4.js → index-Cxhzi3bs.js} +1 -1
  32. package/ui/dist/index.html +2 -2
  33. package/bin/commands/annotate.ts +0 -119
  34. package/bin/commands/cancel.ts +0 -48
  35. package/bin/commands/canvas-versions.ts +0 -80
  36. package/bin/commands/capabilities.ts +0 -110
  37. package/bin/commands/cardnews.ts +0 -249
  38. package/bin/commands/comfy.ts +0 -54
  39. package/bin/commands/config.ts +0 -186
  40. package/bin/commands/defaults.ts +0 -192
  41. package/bin/commands/doctor.ts +0 -202
  42. package/bin/commands/edit.ts +0 -150
  43. package/bin/commands/gen.ts +0 -214
  44. package/bin/commands/grok.ts +0 -90
  45. package/bin/commands/history.ts +0 -146
  46. package/bin/commands/ls.ts +0 -64
  47. package/bin/commands/metadata.ts +0 -39
  48. package/bin/commands/multimode.ts +0 -196
  49. package/bin/commands/node.ts +0 -166
  50. package/bin/commands/observability.ts +0 -176
  51. package/bin/commands/ping.ts +0 -31
  52. package/bin/commands/prompt-sub/build.ts +0 -101
  53. package/bin/commands/prompt.ts +0 -492
  54. package/bin/commands/ps.ts +0 -81
  55. package/bin/commands/session.ts +0 -266
  56. package/bin/commands/show.ts +0 -72
  57. package/bin/commands/skill.ts +0 -70
  58. package/bin/commands/video.ts +0 -442
  59. package/bin/ima2.ts +0 -430
  60. package/bin/lib/args.ts +0 -92
  61. package/bin/lib/browser-id.ts +0 -16
  62. package/bin/lib/client.ts +0 -122
  63. package/bin/lib/config-store.ts +0 -120
  64. package/bin/lib/destructive-confirm.ts +0 -19
  65. package/bin/lib/doctor-checks.ts +0 -91
  66. package/bin/lib/error-hints.ts +0 -23
  67. package/bin/lib/files.ts +0 -39
  68. package/bin/lib/output.ts +0 -73
  69. package/bin/lib/platform.ts +0 -99
  70. package/bin/lib/recover-output.ts +0 -139
  71. package/bin/lib/sse.ts +0 -73
  72. package/bin/lib/star-prompt.ts +0 -97
  73. package/bin/lib/storage-doctor.ts +0 -39
  74. package/bin/lib/ui-build.ts +0 -85
  75. package/config.ts +0 -354
  76. package/lib/agentCommandParser.ts +0 -69
  77. package/lib/agentGenerationPlanner.ts +0 -273
  78. package/lib/agentQuestionResponder.ts +0 -266
  79. package/lib/agentQueueStore.ts +0 -270
  80. package/lib/agentQueueWorker.ts +0 -89
  81. package/lib/agentRuntime.ts +0 -604
  82. package/lib/agentSettings.ts +0 -72
  83. package/lib/agentStore.ts +0 -422
  84. package/lib/agentStoreRows.ts +0 -136
  85. package/lib/agentTypes.ts +0 -154
  86. package/lib/apiCachePolicy.ts +0 -11
  87. package/lib/assetLifecycle.ts +0 -146
  88. package/lib/canvasVersionStore.ts +0 -223
  89. package/lib/capabilities.ts +0 -126
  90. package/lib/cardNewsGenerator.ts +0 -271
  91. package/lib/cardNewsJobStore.ts +0 -142
  92. package/lib/cardNewsManifestStore.ts +0 -154
  93. package/lib/cardNewsPlanner.ts +0 -236
  94. package/lib/cardNewsPlannerClient.ts +0 -155
  95. package/lib/cardNewsPlannerPrompt.ts +0 -62
  96. package/lib/cardNewsPlannerSchema.ts +0 -321
  97. package/lib/cardNewsRoleTemplateStore.ts +0 -47
  98. package/lib/cardNewsTemplateStore.ts +0 -252
  99. package/lib/codexDetect.ts +0 -71
  100. package/lib/comfyBridge.ts +0 -235
  101. package/lib/composerSnapshot.ts +0 -33
  102. package/lib/configKeys.ts +0 -62
  103. package/lib/db.ts +0 -295
  104. package/lib/errInfo.ts +0 -43
  105. package/lib/errorClassify.ts +0 -100
  106. package/lib/generationCancel.ts +0 -28
  107. package/lib/generationErrors.ts +0 -238
  108. package/lib/grokImageAdapter.ts +0 -513
  109. package/lib/grokMultimodeAdapter.ts +0 -84
  110. package/lib/grokProxyLauncher.ts +0 -153
  111. package/lib/grokRuntime.ts +0 -23
  112. package/lib/grokSizeMapper.ts +0 -71
  113. package/lib/grokVideoAdapter.ts +0 -458
  114. package/lib/grokVideoCanvas.ts +0 -26
  115. package/lib/grokVideoDownload.ts +0 -59
  116. package/lib/grokVideoPlannerPrompt.ts +0 -67
  117. package/lib/historyIndex.ts +0 -51
  118. package/lib/historyList.ts +0 -181
  119. package/lib/imageMetadata.ts +0 -113
  120. package/lib/imageMetadataStore.ts +0 -67
  121. package/lib/imageModels.ts +0 -165
  122. package/lib/inflight.ts +0 -281
  123. package/lib/localImportStore.ts +0 -114
  124. package/lib/logger.ts +0 -161
  125. package/lib/nodeStore.ts +0 -91
  126. package/lib/oauthLauncher.ts +0 -94
  127. package/lib/oauthNormalize.ts +0 -30
  128. package/lib/oauthProxy/errors.ts +0 -128
  129. package/lib/oauthProxy/generators.ts +0 -494
  130. package/lib/oauthProxy/index.ts +0 -28
  131. package/lib/oauthProxy/prompts.ts +0 -123
  132. package/lib/oauthProxy/references.ts +0 -45
  133. package/lib/oauthProxy/runtime.ts +0 -115
  134. package/lib/oauthProxy/streams.ts +0 -232
  135. package/lib/oauthProxy/types.ts +0 -9
  136. package/lib/oauthProxy.ts +0 -3
  137. package/lib/openDirectory.ts +0 -47
  138. package/lib/pngInfo.ts +0 -26
  139. package/lib/promptBuilder/attachments.ts +0 -74
  140. package/lib/promptBuilder/client.ts +0 -130
  141. package/lib/promptBuilder/constants.ts +0 -9
  142. package/lib/promptBuilder/context.ts +0 -36
  143. package/lib/promptBuilder/errors.ts +0 -12
  144. package/lib/promptBuilder/requestSchema.ts +0 -56
  145. package/lib/promptBuilder/responseParser.ts +0 -219
  146. package/lib/promptBuilder/systemPrompt.ts +0 -135
  147. package/lib/promptBuilder/transport.ts +0 -94
  148. package/lib/promptBuilder/types.ts +0 -109
  149. package/lib/promptImport/curatedSources.ts +0 -141
  150. package/lib/promptImport/discoveryRegistry.ts +0 -329
  151. package/lib/promptImport/errors.ts +0 -18
  152. package/lib/promptImport/githubDiscovery.ts +0 -309
  153. package/lib/promptImport/githubFolder.ts +0 -397
  154. package/lib/promptImport/githubSource.ts +0 -257
  155. package/lib/promptImport/gptImageHints.ts +0 -70
  156. package/lib/promptImport/parsePromptCandidates.ts +0 -179
  157. package/lib/promptImport/promptIndex.ts +0 -326
  158. package/lib/promptImport/rankPromptCandidates.ts +0 -65
  159. package/lib/promptImport/types.ts +0 -103
  160. package/lib/promptSafetyPolicy.ts +0 -5
  161. package/lib/providerOptions.ts +0 -56
  162. package/lib/referenceImageCompress.ts +0 -84
  163. package/lib/refs.ts +0 -133
  164. package/lib/requestLogger.ts +0 -49
  165. package/lib/responsesDoctor.ts +0 -456
  166. package/lib/responsesErrors.ts +0 -83
  167. package/lib/responsesFallback.ts +0 -114
  168. package/lib/responsesImageAdapter.ts +0 -466
  169. package/lib/responsesParse.ts +0 -452
  170. package/lib/responsesTools.ts +0 -28
  171. package/lib/runtimeContext.ts +0 -146
  172. package/lib/runtimePorts.ts +0 -105
  173. package/lib/sessionStore.ts +0 -308
  174. package/lib/storageMigration.ts +0 -310
  175. package/lib/styleSheet.ts +0 -139
  176. package/lib/systemTrash.ts +0 -20
  177. package/lib/videoContinuity.ts +0 -180
  178. package/lib/videoFrameExtract.ts +0 -78
  179. package/lib/videoSeriesChain.ts +0 -29
  180. package/lib/visibleTextLanguagePolicy.ts +0 -7
  181. package/routes/agent.ts +0 -308
  182. package/routes/annotations.ts +0 -118
  183. package/routes/canvasVersions.ts +0 -69
  184. package/routes/capabilities.ts +0 -18
  185. package/routes/cardNews.ts +0 -211
  186. package/routes/comfy.ts +0 -43
  187. package/routes/edit.ts +0 -352
  188. package/routes/generate.ts +0 -492
  189. package/routes/grok.ts +0 -24
  190. package/routes/health.ts +0 -123
  191. package/routes/history.ts +0 -221
  192. package/routes/imageImport.ts +0 -37
  193. package/routes/index.ts +0 -52
  194. package/routes/metadata.ts +0 -77
  195. package/routes/multimode.ts +0 -499
  196. package/routes/nodes.ts +0 -578
  197. package/routes/promptBuilder.ts +0 -37
  198. package/routes/promptImport.ts +0 -379
  199. package/routes/prompts.ts +0 -428
  200. package/routes/quota.ts +0 -89
  201. package/routes/sessions.ts +0 -317
  202. package/routes/storage.ts +0 -47
  203. package/routes/video.ts +0 -300
  204. package/routes/videoExtended.ts +0 -284
  205. package/server.ts +0 -293
  206. package/ui/dist/assets/SettingsWorkspace-PiaVnsdA.js +0 -1
  207. package/ui/dist/assets/index-CjgnNtgt.css +0 -1
  208. package/ui/dist/assets/index-Da2s4_-5.js +0 -36
@@ -1,45 +0,0 @@
1
- import { detectImageMimeFromB64 } from "../refs.js";
2
-
3
- export interface OAuthReferenceInput {
4
- b64?: string;
5
- declaredMime?: string | null;
6
- detectedMime?: string | null;
7
- warnings?: string[];
8
- approxBytes?: number | null;
9
- source?: string | null;
10
- }
11
-
12
- export type OAuthReferenceRef = string | OAuthReferenceInput | null | undefined;
13
-
14
- export function supportedImageMime(mime: string | null | undefined): boolean {
15
- return mime === "image/png" || mime === "image/jpeg" || mime === "image/webp";
16
- }
17
-
18
- export function normalizeReferenceForOAuth(ref: OAuthReferenceRef, index: number) {
19
- const refObj = (typeof ref === "object" && ref) ? ref : null;
20
- const b64 = typeof ref === "string" ? ref : refObj?.b64;
21
- const declaredMime = refObj ? refObj.declaredMime || null : null;
22
- const detectedMime = refObj
23
- ? refObj.detectedMime || detectImageMimeFromB64(b64)
24
- : detectImageMimeFromB64(b64);
25
- const warnings = Array.isArray(refObj?.warnings) ? [...(refObj?.warnings ?? [])] : [];
26
- if (declaredMime && detectedMime && declaredMime !== detectedMime && !warnings.includes("mime_mismatch")) {
27
- warnings.push("mime_mismatch");
28
- }
29
- const requestMime = supportedImageMime(detectedMime)
30
- ? detectedMime
31
- : supportedImageMime(declaredMime)
32
- ? declaredMime
33
- : "image/png";
34
- return {
35
- index,
36
- b64,
37
- declaredMime,
38
- detectedMime,
39
- requestMime,
40
- b64Chars: typeof b64 === "string" ? b64.length : 0,
41
- approxBytes: Number.isFinite(refObj?.approxBytes) ? refObj?.approxBytes ?? null : null,
42
- source: refObj?.source || (declaredMime ? "dataUrl" : "rawBase64"),
43
- warnings,
44
- };
45
- }
@@ -1,115 +0,0 @@
1
- import { config } from "../../config.js";
2
- import { logEvent } from "../logger.js";
3
- import { isAbortError, makeOAuthError } from "./errors.js";
4
- import type { RouteRuntimeContext } from "../runtimeContext.js";
5
-
6
- import { errInfo } from "../errInfo.js";
7
- const FALLBACK_REASONING_EFFORT = "none";
8
- const VALID_REASONING_EFFORTS = new Set(["none", "low", "medium", "high", "xhigh"]);
9
-
10
- export interface OAuthRuntimeOptions {
11
- reasoningEffort?: unknown;
12
- webSearchEnabled?: unknown;
13
- searchMode?: unknown;
14
- }
15
-
16
- export function resolveReasoningEffort(ctx: RouteRuntimeContext | undefined, options: OAuthRuntimeOptions = {}) {
17
- const fromOptions = typeof options.reasoningEffort === "string" ? options.reasoningEffort : null;
18
- const fromCtx = typeof ctx?.config?.imageModels?.reasoningEffort === "string"
19
- ? ctx.config.imageModels.reasoningEffort
20
- : null;
21
- const candidate = fromOptions || fromCtx || FALLBACK_REASONING_EFFORT;
22
- return VALID_REASONING_EFFORTS.has(candidate) ? candidate : FALLBACK_REASONING_EFFORT;
23
- }
24
-
25
- export function resolveWebSearchEnabled(options: OAuthRuntimeOptions = {}) {
26
- return options.webSearchEnabled !== false && options.searchMode !== "off";
27
- }
28
-
29
- export function buildImageTools(webSearchEnabled: boolean, imageOptions: Record<string, unknown>) {
30
- return [
31
- ...(webSearchEnabled ? [{ type: "web_search" }] : []),
32
- { type: "image_generation", ...imageOptions },
33
- ];
34
- }
35
-
36
- export function getOAuthUrl(ctx: RouteRuntimeContext = {}) {
37
- return ctx.oauthUrl || `http://127.0.0.1:${config.oauth.proxyPort}`;
38
- }
39
-
40
- export function getOAuthGenerationTimeoutMs(ctx: RouteRuntimeContext = {}) {
41
- return ctx.config?.oauth?.generationTimeoutMs ?? config.oauth.generationTimeoutMs ?? 400 * 1000;
42
- }
43
-
44
- export function createOAuthGenerationTimeout(ctx: RouteRuntimeContext = {}, requestId: string | null = null, scope: string = "oauth") {
45
- const timeoutMs = getOAuthGenerationTimeoutMs(ctx);
46
- if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
47
- return {
48
- signal: undefined as AbortSignal | undefined,
49
- timeoutMs,
50
- clear: () => {},
51
- isTimeoutError: (_err: unknown) => false,
52
- };
53
- }
54
- const controller = new AbortController();
55
- let timedOut = false;
56
- const timer = setTimeout(() => {
57
- timedOut = true;
58
- logEvent(scope, "timeout", { requestId, timeoutMs });
59
- controller.abort();
60
- }, timeoutMs);
61
- return {
62
- signal: controller.signal as AbortSignal | undefined,
63
- timeoutMs,
64
- clear: () => clearTimeout(timer),
65
- isTimeoutError: (err: unknown) => timedOut && isAbortError(err),
66
- };
67
- }
68
-
69
- export async function waitForOAuthReady(ctx: RouteRuntimeContext = {}) {
70
- if (!ctx || ctx.oauthReadyState === undefined) return;
71
- const initialState = ctx.oauthReadyState;
72
- if (initialState === "ready" || initialState === "disabled") return;
73
- if (initialState === "failed") {
74
- throw makeOAuthError("OAuth proxy is unavailable", { code: "OAUTH_UNAVAILABLE", status: 503 });
75
- }
76
- const timeoutMs = ctx.config?.oauth?.statusTimeoutMs ?? config.oauth.statusTimeoutMs;
77
- if (ctx.oauthReadyPromise) {
78
- await Promise.race([
79
- ctx.oauthReadyPromise,
80
- new Promise((resolve) => setTimeout(resolve, timeoutMs)),
81
- ]);
82
- }
83
- const finalState = ctx.oauthReadyState;
84
- if (finalState !== "ready" && finalState !== "disabled") {
85
- throw makeOAuthError("OAuth proxy is not ready yet", { code: "OAUTH_UNAVAILABLE", status: 503 });
86
- }
87
- }
88
-
89
- export async function fetchOAuth(url: string, init: RequestInit, { requestId, scope }: { requestId?: string | null; scope?: string } = {}) {
90
- try {
91
- return await fetch(url, init);
92
- } catch (e) {
93
- const err = errInfo(e);
94
- if (isAbortError(err.raw)) throw err.raw;
95
- logEvent(scope || "oauth", "proxy_unavailable", { requestId, message: err.message });
96
- throw makeOAuthError("OAuth proxy is unavailable", {
97
- code: "OAUTH_UNAVAILABLE",
98
- status: 503,
99
- cause: err.raw,
100
- });
101
- }
102
- }
103
-
104
- export function summarizeEventTypes(eventTypes: Record<string, unknown> = {}) {
105
- const entries = Object.entries(eventTypes || {});
106
- const countFor = (needle: string) =>
107
- entries.reduce((sum, [key, value]) => sum + (key.includes(needle) && Number.isFinite(value) ? (value as number) : 0), 0);
108
- return {
109
- eventTypeCount: entries.length,
110
- eventTypeKeys: entries.slice(0, 12).map(([key]) => key).join(","),
111
- imageEventCount: countFor("image"),
112
- partialEventCount: countFor("partial"),
113
- completedEventCount: countFor("completed"),
114
- };
115
- }
@@ -1,232 +0,0 @@
1
- import { setJobPhase } from "../inflight.js";
2
- import { logEvent } from "../logger.js";
3
- import { makeOAuthError } from "./errors.js";
4
-
5
- import { errInfo } from "../errInfo.js";
6
- export function extractSseData(block: string): string {
7
- let eventData = "";
8
- for (const line of block.split("\n")) {
9
- if (line.startsWith("data: ")) eventData += line.slice(6);
10
- }
11
- return eventData;
12
- }
13
-
14
- interface SseImageData {
15
- type?: string;
16
- partial_image?: string;
17
- image?: string;
18
- result?: string;
19
- index?: number;
20
- item?: {
21
- type?: string;
22
- partial_image?: string;
23
- image?: string;
24
- result?: string;
25
- revised_prompt?: string;
26
- index?: number;
27
- };
28
- error?: { code?: string };
29
- response?: {
30
- usage?: unknown;
31
- tool_usage?: { web_search?: { num_requests?: number } };
32
- };
33
- }
34
-
35
- export function extractPartialImage(data: SseImageData | null | undefined) {
36
- if (!data || typeof data?.type !== "string" || !data.type.includes("partial")) return null;
37
- const item = data.item || {};
38
- const b64 =
39
- data.partial_image ||
40
- data.image ||
41
- data.result ||
42
- item.partial_image ||
43
- item.image ||
44
- item.result;
45
- if (typeof b64 !== "string" || b64.length === 0) return null;
46
- const index =
47
- Number.isFinite(data.index) ? data.index :
48
- Number.isFinite(item.index) ? item.index :
49
- null;
50
- return { b64, index, eventType: data.type };
51
- }
52
-
53
- export async function readImageStream(res: Response, { requestId = null, scope = "oauth", onPartialImage = null as ((p: any) => void) | null }: { requestId?: string | null; scope?: string; onPartialImage?: ((p: any) => void) | null } = {}) {
54
- const eventTypes: Record<string, number> = {};
55
- let parseSkipCount = 0;
56
- if (!res.body) throw makeOAuthError("OAuth response missing body", { code: "OAUTH_NO_BODY" });
57
- const reader = res.body.getReader();
58
- const decoder = new TextDecoder();
59
- let buffer = "";
60
- let imageB64: string | null = null;
61
- let usage: unknown = null;
62
- let webSearchCalls = 0;
63
- let eventCount = 0;
64
- let revisedPrompt: string | null = null;
65
-
66
- while (true) {
67
- const { done, value } = await reader.read();
68
- if (done) break;
69
- buffer += decoder.decode(value, { stream: true });
70
-
71
- let boundary;
72
- while ((boundary = buffer.indexOf("\n\n")) !== -1) {
73
- const block = buffer.slice(0, boundary);
74
- buffer = buffer.slice(boundary + 2);
75
- const eventData = extractSseData(block);
76
- if (!eventData || eventData === "[DONE]") continue;
77
-
78
- try {
79
- const data = JSON.parse(eventData) as SseImageData;
80
- eventCount++;
81
- const t = typeof data.type === "string" ? data.type : "_unknown";
82
- eventTypes[t] = (eventTypes[t] || 0) + 1;
83
-
84
- const partial = extractPartialImage(data);
85
- if (partial) {
86
- logEvent(scope, "partial", {
87
- requestId,
88
- index: partial.index,
89
- imageChars: partial.b64.length,
90
- eventType: partial.eventType,
91
- });
92
- if (requestId) setJobPhase(requestId, "partial");
93
- if (typeof onPartialImage === "function") onPartialImage(partial);
94
- }
95
- if (data.type === "response.output_item.done" && data.item?.type === "image_generation_call") {
96
- if (data.item.result) {
97
- const imageB64Local: string = data.item.result;
98
- imageB64 = imageB64Local;
99
- logEvent(scope, "image", { requestId, imageChars: imageB64.length });
100
- if (requestId) setJobPhase(requestId, "decoding");
101
- }
102
- if (typeof data.item.revised_prompt === "string" && data.item.revised_prompt.length) {
103
- revisedPrompt = data.item.revised_prompt;
104
- }
105
- }
106
- if (data.type === "response.output_item.done" && data.item?.type === "web_search_call") {
107
- webSearchCalls += 1;
108
- }
109
- if (data.type === "response.completed") {
110
- usage = data.response?.usage || null;
111
- const wsNum = data.response?.tool_usage?.web_search?.num_requests;
112
- if (typeof wsNum === "number" && wsNum > webSearchCalls) webSearchCalls = wsNum;
113
- }
114
- if (data.type === "error") {
115
- const code = data.error?.code || "OAUTH_STREAM_ERROR";
116
- logEvent(scope, "stream_error", { requestId, code, eventType: data.type, eventCount });
117
- throw makeOAuthError("OAuth stream returned an error", {
118
- code,
119
- eventType: data.type,
120
- eventCount,
121
- });
122
- }
123
- } catch (e) {
124
- const err = errInfo(e);
125
- if (err.message && !err.message.startsWith("Unexpected")) throw e;
126
- parseSkipCount++;
127
- }
128
- }
129
- }
130
-
131
- if (parseSkipCount > 0) {
132
- logEvent(scope, "parse_skip", { requestId, count: parseSkipCount });
133
- }
134
-
135
- return { imageB64, usage, webSearchCalls, revisedPrompt, eventCount, eventTypes };
136
- }
137
-
138
- export async function readMultimodeImageStream(
139
- res: Response,
140
- { requestId = null, maxImages = 1, scope = "oauth-multimode", onPartialImage = null as ((p: any) => void) | null }: { requestId?: string | null; maxImages?: number; scope?: string; onPartialImage?: ((p: any) => void) | null } = {},
141
- ) {
142
- const eventTypes: Record<string, number> = {};
143
- let parseSkipCount = 0;
144
- if (!res.body) throw makeOAuthError("OAuth response missing body", { code: "OAUTH_NO_BODY" });
145
- const reader = res.body.getReader();
146
- const decoder = new TextDecoder();
147
- let buffer = "";
148
- const images: Array<{ b64: string; revisedPrompt: string | null; index?: number }> = [];
149
- let usage: unknown = null;
150
- let webSearchCalls = 0;
151
- let eventCount = 0;
152
- const limit = Math.min(8, Math.max(1, Math.trunc(Number(maxImages) || 1)));
153
- let extraIgnored = 0;
154
-
155
- while (true) {
156
- const { done, value } = await reader.read();
157
- if (done) break;
158
- buffer += decoder.decode(value, { stream: true });
159
-
160
- let boundary;
161
- while ((boundary = buffer.indexOf("\n\n")) !== -1) {
162
- const block = buffer.slice(0, boundary);
163
- buffer = buffer.slice(boundary + 2);
164
- const eventData = extractSseData(block);
165
- if (!eventData || eventData === "[DONE]") continue;
166
-
167
- try {
168
- const data = JSON.parse(eventData) as SseImageData;
169
- eventCount++;
170
- const t = typeof data.type === "string" ? data.type : "_unknown";
171
- eventTypes[t] = (eventTypes[t] || 0) + 1;
172
-
173
- const partial = extractPartialImage(data);
174
- if (partial) {
175
- logEvent(scope, "partial", {
176
- requestId,
177
- index: partial.index,
178
- imageChars: partial.b64.length,
179
- eventType: partial.eventType,
180
- });
181
- if (requestId) setJobPhase(requestId, "partial");
182
- if (typeof onPartialImage === "function") onPartialImage(partial);
183
- }
184
- if (data.type === "response.output_item.done" && data.item?.type === "image_generation_call") {
185
- if (data.item.result) {
186
- if (images.length < limit) {
187
- images.push({
188
- b64: data.item.result,
189
- revisedPrompt:
190
- typeof data.item.revised_prompt === "string" && data.item.revised_prompt.length
191
- ? data.item.revised_prompt
192
- : null,
193
- });
194
- logEvent(scope, "image", { requestId, imageChars: data.item.result.length, index: images.length });
195
- if (requestId) setJobPhase(requestId, "decoding");
196
- } else {
197
- extraIgnored += 1;
198
- logEvent(scope, "extra_ignored", { requestId, maxImages: limit });
199
- }
200
- }
201
- }
202
- if (data.type === "response.output_item.done" && data.item?.type === "web_search_call") {
203
- webSearchCalls += 1;
204
- }
205
- if (data.type === "response.completed") {
206
- usage = data.response?.usage || null;
207
- const wsNum = data.response?.tool_usage?.web_search?.num_requests;
208
- if (typeof wsNum === "number" && wsNum > webSearchCalls) webSearchCalls = wsNum;
209
- }
210
- if (data.type === "error") {
211
- const code = data.error?.code || "OAUTH_STREAM_ERROR";
212
- logEvent(scope, "stream_error", { requestId, code, eventType: data.type, eventCount });
213
- throw makeOAuthError("OAuth stream returned an error", {
214
- code,
215
- eventType: data.type,
216
- eventCount,
217
- });
218
- }
219
- } catch (e) {
220
- const err = errInfo(e);
221
- if (err.message && !err.message.startsWith("Unexpected")) throw e;
222
- parseSkipCount++;
223
- }
224
- }
225
- }
226
-
227
- if (parseSkipCount > 0) {
228
- logEvent(scope, "parse_skip", { requestId, count: parseSkipCount });
229
- }
230
-
231
- return { images, usage, webSearchCalls, eventCount, eventTypes, extraIgnored };
232
- }
@@ -1,9 +0,0 @@
1
- // Shared loose types for the oauthProxy module split.
2
- //
3
- // Behavior parity with the pre-split lib/oauthProxy.ts is the priority during
4
- // Phase 3; strict cleanup is deferred to later phases. The aliases below are
5
- // intentionally `any` so callers do not see signature changes.
6
-
7
- export type ImageOptions = any;
8
- export type OAuthCtx = any;
9
- export type Reference = any;
package/lib/oauthProxy.ts DELETED
@@ -1,3 +0,0 @@
1
- // Facade — preserves the public import path `./oauthProxy.js`.
2
- // All implementation lives under `lib/oauthProxy/`.
3
- export * from "./oauthProxy/index.js";
@@ -1,47 +0,0 @@
1
- import { spawn } from "node:child_process";
2
- import { mkdir } from "node:fs/promises";
3
-
4
- import { errInfo } from "./errInfo.js";
5
- export async function openDirectory(dir: string, options: any = {}) {
6
- await mkdir(dir, { recursive: true });
7
- const platform = options.platform || process.platform;
8
- const spawnImpl = options.spawnImpl || spawn;
9
- const settleMs = Number.isFinite(options.settleMs) ? options.settleMs : 250;
10
- const command =
11
- platform === "darwin" ? "open"
12
- : platform === "win32" ? "explorer"
13
- : "xdg-open";
14
-
15
- return new Promise((resolve) => {
16
- try {
17
- const isWin = platform === "win32";
18
- const child = spawnImpl(command, [dir], {
19
- detached: !isWin,
20
- stdio: "ignore",
21
- windowsHide: !isWin,
22
- });
23
- let settled = false;
24
- const done = (result: { ok: boolean; error?: string }) => {
25
- if (settled) return;
26
- settled = true;
27
- resolve(result);
28
- };
29
- child.on("error", (err: Error) => {
30
- done({ ok: false, error: err.message || String(err) });
31
- });
32
- child.on("exit", (code: number | null) => {
33
- if (platform === "win32") {
34
- done({ ok: true });
35
- return;
36
- }
37
- if (code === 0) done({ ok: true });
38
- else if (code != null) done({ ok: false, error: `${command} exited with code ${code}` });
39
- });
40
- child.unref?.();
41
- setTimeout(() => done({ ok: true }), settleMs).unref?.();
42
- } catch (e) {
43
- const err = errInfo(e);
44
- resolve({ ok: false, error: err.message || String(err.raw) });
45
- }
46
- });
47
- }
package/lib/pngInfo.ts DELETED
@@ -1,26 +0,0 @@
1
- const PNG_SIGNATURE_HEX = "89504e470d0a1a0a";
2
- const IHDR_TYPE = "IHDR";
3
-
4
- export function parsePngInfo(buffer: Buffer) {
5
- if (!Buffer.isBuffer(buffer) || buffer.length < 33) {
6
- return { error: "INVALID_PNG" };
7
- }
8
- if (buffer.subarray(0, 8).toString("hex") !== PNG_SIGNATURE_HEX) {
9
- return { error: "INVALID_PNG" };
10
- }
11
- const ihdrLength = buffer.readUInt32BE(8);
12
- const chunkType = buffer.subarray(12, 16).toString("ascii");
13
- if (ihdrLength !== 13 || chunkType !== IHDR_TYPE) {
14
- return { error: "INVALID_PNG_IHDR" };
15
- }
16
- return {
17
- width: buffer.readUInt32BE(16),
18
- height: buffer.readUInt32BE(20),
19
- bitDepth: buffer.readUInt8(24),
20
- colorType: buffer.readUInt8(25),
21
- };
22
- }
23
-
24
- export function hasPngAlphaChannel(info: { colorType?: number } | null | undefined) {
25
- return info?.colorType === 4 || info?.colorType === 6;
26
- }
@@ -1,74 +0,0 @@
1
- import {
2
- MAX_ATTACHMENTS,
3
- MAX_TEXT_ATTACHMENT_CHARS,
4
- MAX_ATTACHMENT_NAME_CHARS,
5
- MAX_ATTACHMENT_MIME_CHARS,
6
- } from "./constants.js";
7
- import type { PromptBuilderAttachment } from "./types.js";
8
-
9
- export function normalizeAttachments(
10
- raw: unknown,
11
- ): PromptBuilderAttachment[] | undefined {
12
- if (!Array.isArray(raw)) return undefined;
13
- const attachments = raw.slice(0, MAX_ATTACHMENTS).flatMap((attachment): PromptBuilderAttachment[] => {
14
- if (!attachment || typeof attachment !== "object") return [];
15
- const item = attachment as Record<string, unknown>;
16
- const kind =
17
- item.kind === "image" || item.kind === "text" || item.kind === "file"
18
- ? item.kind
19
- : "file";
20
- const name =
21
- typeof item.name === "string" && item.name.trim()
22
- ? item.name.trim().slice(0, MAX_ATTACHMENT_NAME_CHARS)
23
- : "attachment";
24
- const mimeType =
25
- typeof item.mimeType === "string" && item.mimeType.trim()
26
- ? item.mimeType.trim().slice(0, MAX_ATTACHMENT_MIME_CHARS)
27
- : "application/octet-stream";
28
- const size =
29
- typeof item.size === "number" && Number.isFinite(item.size)
30
- ? Math.max(0, Math.trunc(item.size))
31
- : 0;
32
- if (kind === "image") {
33
- const dataUrl =
34
- typeof item.dataUrl === "string" && item.dataUrl.startsWith("data:image/")
35
- ? item.dataUrl
36
- : "";
37
- if (!dataUrl) return [];
38
- return [{ kind, name, mimeType, size, dataUrl }];
39
- }
40
- if (kind === "text") {
41
- const text = typeof item.text === "string" ? item.text.slice(0, MAX_TEXT_ATTACHMENT_CHARS) : "";
42
- return [{ kind, name, mimeType, size, text }];
43
- }
44
- return [{ kind, name, mimeType, size }];
45
- });
46
- return attachments.length > 0 ? attachments : undefined;
47
- }
48
-
49
- export function attachmentText(
50
- attachments: PromptBuilderAttachment[] | undefined,
51
- ): string {
52
- if (!attachments || attachments.length === 0) return "";
53
- const lines = attachments.flatMap((attachment, index) => {
54
- const label = `Attachment ${index + 1}: ${attachment.name} (${attachment.mimeType}, ${attachment.size} bytes)`;
55
- if (attachment.kind === "text" && attachment.text?.trim()) {
56
- return [`${label}\n${attachment.text.trim()}`];
57
- }
58
- if (attachment.kind === "image") {
59
- return [`${label}\nImage is attached as visual reference.`];
60
- }
61
- return [label];
62
- });
63
- return `User attachments:\n${lines.join("\n\n")}`;
64
- }
65
-
66
- export function hasImageAttachments(
67
- messages: Array<{ attachments?: PromptBuilderAttachment[] }>,
68
- ): boolean {
69
- return messages.some((message) =>
70
- message.attachments?.some(
71
- (attachment) => attachment.kind === "image" && attachment.dataUrl,
72
- ),
73
- );
74
- }
@@ -1,130 +0,0 @@
1
- import { errInfo } from "../errInfo.js";
2
- import { logWarn } from "../logger.js";
3
- import { fetchOAuth, waitForOAuthReady } from "../oauthProxy/runtime.js";
4
- import type { RouteRuntimeContext } from "../runtimeContext.js";
5
- import { promptBuilderError } from "./errors.js";
6
- import { normalizeModel, normalizeMessages } from "./requestSchema.js";
7
- import { buildTransportPayload } from "./transport.js";
8
- import {
9
- parseUpstreamError,
10
- responseSummary,
11
- extractChatText,
12
- readResponsesResult,
13
- } from "./responseParser.js";
14
- import type {
15
- PromptBuilderRequest,
16
- PromptBuilderChatResult,
17
- ChatCompletionBody,
18
- ResponsesReadResult,
19
- } from "./types.js";
20
-
21
- export async function requestPromptBuilderChat(
22
- ctx: RouteRuntimeContext,
23
- input: PromptBuilderRequest,
24
- ): Promise<PromptBuilderChatResult> {
25
- const model = normalizeModel(input.model);
26
- const messages = normalizeMessages(input.messages);
27
-
28
- await waitForOAuthReady(ctx);
29
-
30
- const timeoutMs = ctx.config?.oauth?.generationTimeoutMs ?? 120_000;
31
- const controller = new AbortController();
32
- const timer = setTimeout(() => controller.abort(), timeoutMs);
33
-
34
- try {
35
- const { endpoint, body: payload } = buildTransportPayload(
36
- model,
37
- messages,
38
- input.context,
39
- );
40
- const url = `${ctx.oauthUrl}${endpoint === "responses" ? "/v1/responses" : "/v1/chat/completions"}`;
41
-
42
- const res = await fetchOAuth(
43
- url,
44
- {
45
- method: "POST",
46
- headers: { "Content-Type": "application/json" },
47
- signal: controller.signal,
48
- body: JSON.stringify(payload),
49
- },
50
- { scope: "prompt-builder" },
51
- );
52
-
53
- if (!res.ok) {
54
- const text = await res.text();
55
- const upstream = parseUpstreamError(text);
56
- logWarn("prompt-builder", "upstream_failed", {
57
- endpoint,
58
- model,
59
- status: res.status,
60
- hasImageAttachments: endpoint === "responses",
61
- upstreamBodyChars: text.length,
62
- upstreamCode: upstream.upstreamCode,
63
- upstreamType: upstream.upstreamType,
64
- upstreamParam: upstream.upstreamParam,
65
- });
66
- const err = promptBuilderError(
67
- "Prompt builder upstream failed",
68
- "PROMPT_BUILDER_UPSTREAM_FAILED",
69
- 502,
70
- );
71
- err.upstreamStatus = res.status;
72
- err.upstreamBodyChars = text.length;
73
- err.upstreamEndpoint = endpoint;
74
- err.upstreamCode = upstream.upstreamCode;
75
- err.upstreamType = upstream.upstreamType;
76
- err.upstreamParam = upstream.upstreamParam;
77
- throw err;
78
- }
79
-
80
- const useResponses = endpoint === "responses";
81
- const responseBody = useResponses
82
- ? await readResponsesResult(res)
83
- : ((await res.json()) as ChatCompletionBody);
84
- const content = (
85
- useResponses
86
- ? (responseBody as ResponsesReadResult).content
87
- : extractChatText(responseBody as ChatCompletionBody)
88
- ).trim();
89
-
90
- if (!content) {
91
- const summary = useResponses
92
- ? (responseBody as ResponsesReadResult).summary
93
- : responseSummary(responseBody);
94
- logWarn("prompt-builder", "empty_response", {
95
- endpoint,
96
- model,
97
- ...summary,
98
- });
99
- const err = promptBuilderError(
100
- "Prompt builder returned an empty response",
101
- "PROMPT_BUILDER_EMPTY_RESPONSE",
102
- 502,
103
- );
104
- err.upstreamEndpoint = endpoint;
105
- Object.assign(err, summary);
106
- throw err;
107
- }
108
-
109
- return {
110
- provider: "oauth",
111
- model,
112
- message: { role: "assistant", content },
113
- usage: useResponses
114
- ? (responseBody as ResponsesReadResult).usage
115
- : ((responseBody as ChatCompletionBody).usage ?? null),
116
- };
117
- } catch (error) {
118
- const info = errInfo(error);
119
- if (info.name === "AbortError") {
120
- throw promptBuilderError(
121
- "Prompt builder timed out",
122
- "PROMPT_BUILDER_TIMEOUT",
123
- 504,
124
- );
125
- }
126
- throw info.raw;
127
- } finally {
128
- clearTimeout(timer);
129
- }
130
- }