ima2-gen 1.1.21 → 1.1.23

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 (214) hide show
  1. package/README.md +44 -7
  2. package/bin/commands/video.js +14 -0
  3. package/bin/ima2.js +14 -4
  4. package/bin/lib/platform.js +34 -5
  5. package/docs/README.ko.md +43 -2
  6. package/lib/agentQueueWorker.js +6 -0
  7. package/lib/agentRuntime.js +3 -2
  8. package/lib/atomicWrite.js +14 -0
  9. package/lib/grokImageAdapter.js +6 -0
  10. package/lib/grokProxyLauncher.js +5 -3
  11. package/lib/grokVideoAdapter.js +1 -1
  12. package/lib/grokVideoPlannerPrompt.js +10 -0
  13. package/lib/inflight.js +1 -1
  14. package/lib/oauthLauncher.js +5 -0
  15. package/lib/videoFrameExtract.js +3 -3
  16. package/package.json +5 -7
  17. package/routes/capabilities.js +13 -0
  18. package/routes/edit.js +2 -1
  19. package/routes/generate.js +32 -6
  20. package/routes/health.js +4 -3
  21. package/routes/multimode.js +2 -1
  22. package/routes/video.js +35 -3
  23. package/server.js +29 -2
  24. package/skills/ima2/SKILL.md +48 -6
  25. package/ui/dist/.vite/manifest.json +12 -12
  26. package/ui/dist/assets/{AgentWorkspace-B_hq9CLg.js → AgentWorkspace-C21zqdTZ.js} +1 -1
  27. package/ui/dist/assets/{CardNewsWorkspace-wD12J7qk.js → CardNewsWorkspace-BN-ga1lG.js} +1 -1
  28. package/ui/dist/assets/{NodeCanvas-CI_wuPMf.js → NodeCanvas-BbMa4IhI.js} +1 -1
  29. package/ui/dist/assets/{PromptBuilderPanel-CUTujJUV.js → PromptBuilderPanel-DRwBJRDQ.js} +1 -1
  30. package/ui/dist/assets/{PromptImportDialog-CUi66jPK.js → PromptImportDialog-Dp85kHCq.js} +2 -2
  31. package/ui/dist/assets/{PromptImportDiscoverySection-Cm3vrjY4.js → PromptImportDiscoverySection-BE8Q8MLD.js} +1 -1
  32. package/ui/dist/assets/{PromptImportFolderSection-DOtWTD9n.js → PromptImportFolderSection-PtH5x0sc.js} +1 -1
  33. package/ui/dist/assets/{PromptLibraryPanel-BMjQegRa.js → PromptLibraryPanel-FnM9tHI9.js} +2 -2
  34. package/ui/dist/assets/SettingsWorkspace-MARPGyBL.js +1 -0
  35. package/ui/dist/assets/index-BAFI6htx.js +42 -0
  36. package/ui/dist/assets/{index-31uVIdt4.js → index-BSXxr_Bt.js} +1 -1
  37. package/ui/dist/assets/index-DS-ADE7U.css +1 -0
  38. package/ui/dist/index.html +2 -2
  39. package/bin/commands/annotate.ts +0 -119
  40. package/bin/commands/cancel.ts +0 -48
  41. package/bin/commands/canvas-versions.ts +0 -80
  42. package/bin/commands/capabilities.ts +0 -110
  43. package/bin/commands/cardnews.ts +0 -249
  44. package/bin/commands/comfy.ts +0 -54
  45. package/bin/commands/config.ts +0 -186
  46. package/bin/commands/defaults.ts +0 -192
  47. package/bin/commands/doctor.ts +0 -202
  48. package/bin/commands/edit.ts +0 -150
  49. package/bin/commands/gen.ts +0 -214
  50. package/bin/commands/grok.ts +0 -90
  51. package/bin/commands/history.ts +0 -146
  52. package/bin/commands/ls.ts +0 -64
  53. package/bin/commands/metadata.ts +0 -39
  54. package/bin/commands/multimode.ts +0 -196
  55. package/bin/commands/node.ts +0 -166
  56. package/bin/commands/observability.ts +0 -176
  57. package/bin/commands/ping.ts +0 -31
  58. package/bin/commands/prompt-sub/build.ts +0 -101
  59. package/bin/commands/prompt.ts +0 -492
  60. package/bin/commands/ps.ts +0 -81
  61. package/bin/commands/session.ts +0 -266
  62. package/bin/commands/show.ts +0 -72
  63. package/bin/commands/skill.ts +0 -70
  64. package/bin/commands/video.ts +0 -442
  65. package/bin/ima2.ts +0 -430
  66. package/bin/lib/args.ts +0 -92
  67. package/bin/lib/browser-id.ts +0 -16
  68. package/bin/lib/client.ts +0 -122
  69. package/bin/lib/config-store.ts +0 -120
  70. package/bin/lib/destructive-confirm.ts +0 -19
  71. package/bin/lib/doctor-checks.ts +0 -91
  72. package/bin/lib/error-hints.ts +0 -23
  73. package/bin/lib/files.ts +0 -39
  74. package/bin/lib/output.ts +0 -73
  75. package/bin/lib/platform.ts +0 -99
  76. package/bin/lib/recover-output.ts +0 -139
  77. package/bin/lib/sse.ts +0 -73
  78. package/bin/lib/star-prompt.ts +0 -97
  79. package/bin/lib/storage-doctor.ts +0 -39
  80. package/bin/lib/ui-build.ts +0 -85
  81. package/config.ts +0 -354
  82. package/lib/agentCommandParser.ts +0 -69
  83. package/lib/agentGenerationPlanner.ts +0 -273
  84. package/lib/agentQuestionResponder.ts +0 -266
  85. package/lib/agentQueueStore.ts +0 -270
  86. package/lib/agentQueueWorker.ts +0 -89
  87. package/lib/agentRuntime.ts +0 -604
  88. package/lib/agentSettings.ts +0 -72
  89. package/lib/agentStore.ts +0 -422
  90. package/lib/agentStoreRows.ts +0 -136
  91. package/lib/agentTypes.ts +0 -154
  92. package/lib/apiCachePolicy.ts +0 -11
  93. package/lib/assetLifecycle.ts +0 -146
  94. package/lib/canvasVersionStore.ts +0 -223
  95. package/lib/capabilities.ts +0 -126
  96. package/lib/cardNewsGenerator.ts +0 -271
  97. package/lib/cardNewsJobStore.ts +0 -142
  98. package/lib/cardNewsManifestStore.ts +0 -154
  99. package/lib/cardNewsPlanner.ts +0 -236
  100. package/lib/cardNewsPlannerClient.ts +0 -155
  101. package/lib/cardNewsPlannerPrompt.ts +0 -62
  102. package/lib/cardNewsPlannerSchema.ts +0 -321
  103. package/lib/cardNewsRoleTemplateStore.ts +0 -47
  104. package/lib/cardNewsTemplateStore.ts +0 -252
  105. package/lib/codexDetect.ts +0 -71
  106. package/lib/comfyBridge.ts +0 -235
  107. package/lib/composerSnapshot.ts +0 -33
  108. package/lib/configKeys.ts +0 -62
  109. package/lib/db.ts +0 -295
  110. package/lib/errInfo.ts +0 -43
  111. package/lib/errorClassify.ts +0 -100
  112. package/lib/generationCancel.ts +0 -28
  113. package/lib/generationErrors.ts +0 -238
  114. package/lib/grokImageAdapter.ts +0 -513
  115. package/lib/grokMultimodeAdapter.ts +0 -84
  116. package/lib/grokProxyLauncher.ts +0 -153
  117. package/lib/grokRuntime.ts +0 -23
  118. package/lib/grokSizeMapper.ts +0 -71
  119. package/lib/grokVideoAdapter.ts +0 -458
  120. package/lib/grokVideoCanvas.ts +0 -26
  121. package/lib/grokVideoDownload.ts +0 -59
  122. package/lib/grokVideoPlannerPrompt.ts +0 -67
  123. package/lib/historyIndex.ts +0 -51
  124. package/lib/historyList.ts +0 -181
  125. package/lib/imageMetadata.ts +0 -113
  126. package/lib/imageMetadataStore.ts +0 -67
  127. package/lib/imageModels.ts +0 -165
  128. package/lib/inflight.ts +0 -281
  129. package/lib/localImportStore.ts +0 -114
  130. package/lib/logger.ts +0 -161
  131. package/lib/nodeStore.ts +0 -91
  132. package/lib/oauthLauncher.ts +0 -94
  133. package/lib/oauthNormalize.ts +0 -30
  134. package/lib/oauthProxy/errors.ts +0 -128
  135. package/lib/oauthProxy/generators.ts +0 -494
  136. package/lib/oauthProxy/index.ts +0 -28
  137. package/lib/oauthProxy/prompts.ts +0 -123
  138. package/lib/oauthProxy/references.ts +0 -45
  139. package/lib/oauthProxy/runtime.ts +0 -115
  140. package/lib/oauthProxy/streams.ts +0 -232
  141. package/lib/oauthProxy/types.ts +0 -9
  142. package/lib/oauthProxy.ts +0 -3
  143. package/lib/openDirectory.ts +0 -47
  144. package/lib/pngInfo.ts +0 -26
  145. package/lib/promptBuilder/attachments.ts +0 -74
  146. package/lib/promptBuilder/client.ts +0 -130
  147. package/lib/promptBuilder/constants.ts +0 -9
  148. package/lib/promptBuilder/context.ts +0 -36
  149. package/lib/promptBuilder/errors.ts +0 -12
  150. package/lib/promptBuilder/requestSchema.ts +0 -56
  151. package/lib/promptBuilder/responseParser.ts +0 -219
  152. package/lib/promptBuilder/systemPrompt.ts +0 -135
  153. package/lib/promptBuilder/transport.ts +0 -94
  154. package/lib/promptBuilder/types.ts +0 -109
  155. package/lib/promptImport/curatedSources.ts +0 -141
  156. package/lib/promptImport/discoveryRegistry.ts +0 -329
  157. package/lib/promptImport/errors.ts +0 -18
  158. package/lib/promptImport/githubDiscovery.ts +0 -309
  159. package/lib/promptImport/githubFolder.ts +0 -397
  160. package/lib/promptImport/githubSource.ts +0 -257
  161. package/lib/promptImport/gptImageHints.ts +0 -70
  162. package/lib/promptImport/parsePromptCandidates.ts +0 -179
  163. package/lib/promptImport/promptIndex.ts +0 -326
  164. package/lib/promptImport/rankPromptCandidates.ts +0 -65
  165. package/lib/promptImport/types.ts +0 -103
  166. package/lib/promptSafetyPolicy.ts +0 -5
  167. package/lib/providerOptions.ts +0 -56
  168. package/lib/referenceImageCompress.ts +0 -84
  169. package/lib/refs.ts +0 -133
  170. package/lib/requestLogger.ts +0 -49
  171. package/lib/responsesDoctor.ts +0 -456
  172. package/lib/responsesErrors.ts +0 -83
  173. package/lib/responsesFallback.ts +0 -114
  174. package/lib/responsesImageAdapter.ts +0 -466
  175. package/lib/responsesParse.ts +0 -452
  176. package/lib/responsesTools.ts +0 -28
  177. package/lib/runtimeContext.ts +0 -146
  178. package/lib/runtimePorts.ts +0 -105
  179. package/lib/sessionStore.ts +0 -308
  180. package/lib/storageMigration.ts +0 -310
  181. package/lib/styleSheet.ts +0 -139
  182. package/lib/systemTrash.ts +0 -20
  183. package/lib/videoContinuity.ts +0 -180
  184. package/lib/videoFrameExtract.ts +0 -78
  185. package/lib/videoSeriesChain.ts +0 -29
  186. package/lib/visibleTextLanguagePolicy.ts +0 -7
  187. package/routes/agent.ts +0 -308
  188. package/routes/annotations.ts +0 -118
  189. package/routes/canvasVersions.ts +0 -69
  190. package/routes/capabilities.ts +0 -18
  191. package/routes/cardNews.ts +0 -211
  192. package/routes/comfy.ts +0 -43
  193. package/routes/edit.ts +0 -352
  194. package/routes/generate.ts +0 -492
  195. package/routes/grok.ts +0 -24
  196. package/routes/health.ts +0 -123
  197. package/routes/history.ts +0 -221
  198. package/routes/imageImport.ts +0 -37
  199. package/routes/index.ts +0 -52
  200. package/routes/metadata.ts +0 -77
  201. package/routes/multimode.ts +0 -499
  202. package/routes/nodes.ts +0 -578
  203. package/routes/promptBuilder.ts +0 -37
  204. package/routes/promptImport.ts +0 -379
  205. package/routes/prompts.ts +0 -428
  206. package/routes/quota.ts +0 -89
  207. package/routes/sessions.ts +0 -317
  208. package/routes/storage.ts +0 -47
  209. package/routes/video.ts +0 -300
  210. package/routes/videoExtended.ts +0 -284
  211. package/server.ts +0 -293
  212. package/ui/dist/assets/SettingsWorkspace-PiaVnsdA.js +0 -1
  213. package/ui/dist/assets/index-CjgnNtgt.css +0 -1
  214. 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
- }