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.
- package/README.md +44 -7
- package/bin/commands/video.js +14 -0
- package/bin/ima2.js +14 -4
- package/bin/lib/platform.js +34 -5
- package/docs/README.ko.md +43 -2
- package/lib/agentQueueWorker.js +6 -0
- package/lib/agentRuntime.js +3 -2
- package/lib/atomicWrite.js +14 -0
- package/lib/grokImageAdapter.js +6 -0
- package/lib/grokProxyLauncher.js +5 -3
- package/lib/grokVideoAdapter.js +1 -1
- package/lib/grokVideoPlannerPrompt.js +10 -0
- package/lib/inflight.js +1 -1
- package/lib/oauthLauncher.js +5 -0
- package/lib/videoFrameExtract.js +3 -3
- package/package.json +5 -7
- package/routes/capabilities.js +13 -0
- package/routes/edit.js +2 -1
- package/routes/generate.js +32 -6
- package/routes/health.js +4 -3
- package/routes/multimode.js +2 -1
- package/routes/video.js +35 -3
- package/server.js +29 -2
- package/skills/ima2/SKILL.md +48 -6
- package/ui/dist/.vite/manifest.json +12 -12
- package/ui/dist/assets/{AgentWorkspace-B_hq9CLg.js → AgentWorkspace-C21zqdTZ.js} +1 -1
- package/ui/dist/assets/{CardNewsWorkspace-wD12J7qk.js → CardNewsWorkspace-BN-ga1lG.js} +1 -1
- package/ui/dist/assets/{NodeCanvas-CI_wuPMf.js → NodeCanvas-BbMa4IhI.js} +1 -1
- package/ui/dist/assets/{PromptBuilderPanel-CUTujJUV.js → PromptBuilderPanel-DRwBJRDQ.js} +1 -1
- package/ui/dist/assets/{PromptImportDialog-CUi66jPK.js → PromptImportDialog-Dp85kHCq.js} +2 -2
- package/ui/dist/assets/{PromptImportDiscoverySection-Cm3vrjY4.js → PromptImportDiscoverySection-BE8Q8MLD.js} +1 -1
- package/ui/dist/assets/{PromptImportFolderSection-DOtWTD9n.js → PromptImportFolderSection-PtH5x0sc.js} +1 -1
- package/ui/dist/assets/{PromptLibraryPanel-BMjQegRa.js → PromptLibraryPanel-FnM9tHI9.js} +2 -2
- package/ui/dist/assets/SettingsWorkspace-MARPGyBL.js +1 -0
- package/ui/dist/assets/index-BAFI6htx.js +42 -0
- package/ui/dist/assets/{index-31uVIdt4.js → index-BSXxr_Bt.js} +1 -1
- package/ui/dist/assets/index-DS-ADE7U.css +1 -0
- package/ui/dist/index.html +2 -2
- package/bin/commands/annotate.ts +0 -119
- package/bin/commands/cancel.ts +0 -48
- package/bin/commands/canvas-versions.ts +0 -80
- package/bin/commands/capabilities.ts +0 -110
- package/bin/commands/cardnews.ts +0 -249
- package/bin/commands/comfy.ts +0 -54
- package/bin/commands/config.ts +0 -186
- package/bin/commands/defaults.ts +0 -192
- package/bin/commands/doctor.ts +0 -202
- package/bin/commands/edit.ts +0 -150
- package/bin/commands/gen.ts +0 -214
- package/bin/commands/grok.ts +0 -90
- package/bin/commands/history.ts +0 -146
- package/bin/commands/ls.ts +0 -64
- package/bin/commands/metadata.ts +0 -39
- package/bin/commands/multimode.ts +0 -196
- package/bin/commands/node.ts +0 -166
- package/bin/commands/observability.ts +0 -176
- package/bin/commands/ping.ts +0 -31
- package/bin/commands/prompt-sub/build.ts +0 -101
- package/bin/commands/prompt.ts +0 -492
- package/bin/commands/ps.ts +0 -81
- package/bin/commands/session.ts +0 -266
- package/bin/commands/show.ts +0 -72
- package/bin/commands/skill.ts +0 -70
- package/bin/commands/video.ts +0 -442
- package/bin/ima2.ts +0 -430
- package/bin/lib/args.ts +0 -92
- package/bin/lib/browser-id.ts +0 -16
- package/bin/lib/client.ts +0 -122
- package/bin/lib/config-store.ts +0 -120
- package/bin/lib/destructive-confirm.ts +0 -19
- package/bin/lib/doctor-checks.ts +0 -91
- package/bin/lib/error-hints.ts +0 -23
- package/bin/lib/files.ts +0 -39
- package/bin/lib/output.ts +0 -73
- package/bin/lib/platform.ts +0 -99
- package/bin/lib/recover-output.ts +0 -139
- package/bin/lib/sse.ts +0 -73
- package/bin/lib/star-prompt.ts +0 -97
- package/bin/lib/storage-doctor.ts +0 -39
- package/bin/lib/ui-build.ts +0 -85
- package/config.ts +0 -354
- package/lib/agentCommandParser.ts +0 -69
- package/lib/agentGenerationPlanner.ts +0 -273
- package/lib/agentQuestionResponder.ts +0 -266
- package/lib/agentQueueStore.ts +0 -270
- package/lib/agentQueueWorker.ts +0 -89
- package/lib/agentRuntime.ts +0 -604
- package/lib/agentSettings.ts +0 -72
- package/lib/agentStore.ts +0 -422
- package/lib/agentStoreRows.ts +0 -136
- package/lib/agentTypes.ts +0 -154
- package/lib/apiCachePolicy.ts +0 -11
- package/lib/assetLifecycle.ts +0 -146
- package/lib/canvasVersionStore.ts +0 -223
- package/lib/capabilities.ts +0 -126
- package/lib/cardNewsGenerator.ts +0 -271
- package/lib/cardNewsJobStore.ts +0 -142
- package/lib/cardNewsManifestStore.ts +0 -154
- package/lib/cardNewsPlanner.ts +0 -236
- package/lib/cardNewsPlannerClient.ts +0 -155
- package/lib/cardNewsPlannerPrompt.ts +0 -62
- package/lib/cardNewsPlannerSchema.ts +0 -321
- package/lib/cardNewsRoleTemplateStore.ts +0 -47
- package/lib/cardNewsTemplateStore.ts +0 -252
- package/lib/codexDetect.ts +0 -71
- package/lib/comfyBridge.ts +0 -235
- package/lib/composerSnapshot.ts +0 -33
- package/lib/configKeys.ts +0 -62
- package/lib/db.ts +0 -295
- package/lib/errInfo.ts +0 -43
- package/lib/errorClassify.ts +0 -100
- package/lib/generationCancel.ts +0 -28
- package/lib/generationErrors.ts +0 -238
- package/lib/grokImageAdapter.ts +0 -513
- package/lib/grokMultimodeAdapter.ts +0 -84
- package/lib/grokProxyLauncher.ts +0 -153
- package/lib/grokRuntime.ts +0 -23
- package/lib/grokSizeMapper.ts +0 -71
- package/lib/grokVideoAdapter.ts +0 -458
- package/lib/grokVideoCanvas.ts +0 -26
- package/lib/grokVideoDownload.ts +0 -59
- package/lib/grokVideoPlannerPrompt.ts +0 -67
- package/lib/historyIndex.ts +0 -51
- package/lib/historyList.ts +0 -181
- package/lib/imageMetadata.ts +0 -113
- package/lib/imageMetadataStore.ts +0 -67
- package/lib/imageModels.ts +0 -165
- package/lib/inflight.ts +0 -281
- package/lib/localImportStore.ts +0 -114
- package/lib/logger.ts +0 -161
- package/lib/nodeStore.ts +0 -91
- package/lib/oauthLauncher.ts +0 -94
- package/lib/oauthNormalize.ts +0 -30
- package/lib/oauthProxy/errors.ts +0 -128
- package/lib/oauthProxy/generators.ts +0 -494
- package/lib/oauthProxy/index.ts +0 -28
- package/lib/oauthProxy/prompts.ts +0 -123
- package/lib/oauthProxy/references.ts +0 -45
- package/lib/oauthProxy/runtime.ts +0 -115
- package/lib/oauthProxy/streams.ts +0 -232
- package/lib/oauthProxy/types.ts +0 -9
- package/lib/oauthProxy.ts +0 -3
- package/lib/openDirectory.ts +0 -47
- package/lib/pngInfo.ts +0 -26
- package/lib/promptBuilder/attachments.ts +0 -74
- package/lib/promptBuilder/client.ts +0 -130
- package/lib/promptBuilder/constants.ts +0 -9
- package/lib/promptBuilder/context.ts +0 -36
- package/lib/promptBuilder/errors.ts +0 -12
- package/lib/promptBuilder/requestSchema.ts +0 -56
- package/lib/promptBuilder/responseParser.ts +0 -219
- package/lib/promptBuilder/systemPrompt.ts +0 -135
- package/lib/promptBuilder/transport.ts +0 -94
- package/lib/promptBuilder/types.ts +0 -109
- package/lib/promptImport/curatedSources.ts +0 -141
- package/lib/promptImport/discoveryRegistry.ts +0 -329
- package/lib/promptImport/errors.ts +0 -18
- package/lib/promptImport/githubDiscovery.ts +0 -309
- package/lib/promptImport/githubFolder.ts +0 -397
- package/lib/promptImport/githubSource.ts +0 -257
- package/lib/promptImport/gptImageHints.ts +0 -70
- package/lib/promptImport/parsePromptCandidates.ts +0 -179
- package/lib/promptImport/promptIndex.ts +0 -326
- package/lib/promptImport/rankPromptCandidates.ts +0 -65
- package/lib/promptImport/types.ts +0 -103
- package/lib/promptSafetyPolicy.ts +0 -5
- package/lib/providerOptions.ts +0 -56
- package/lib/referenceImageCompress.ts +0 -84
- package/lib/refs.ts +0 -133
- package/lib/requestLogger.ts +0 -49
- package/lib/responsesDoctor.ts +0 -456
- package/lib/responsesErrors.ts +0 -83
- package/lib/responsesFallback.ts +0 -114
- package/lib/responsesImageAdapter.ts +0 -466
- package/lib/responsesParse.ts +0 -452
- package/lib/responsesTools.ts +0 -28
- package/lib/runtimeContext.ts +0 -146
- package/lib/runtimePorts.ts +0 -105
- package/lib/sessionStore.ts +0 -308
- package/lib/storageMigration.ts +0 -310
- package/lib/styleSheet.ts +0 -139
- package/lib/systemTrash.ts +0 -20
- package/lib/videoContinuity.ts +0 -180
- package/lib/videoFrameExtract.ts +0 -78
- package/lib/videoSeriesChain.ts +0 -29
- package/lib/visibleTextLanguagePolicy.ts +0 -7
- package/routes/agent.ts +0 -308
- package/routes/annotations.ts +0 -118
- package/routes/canvasVersions.ts +0 -69
- package/routes/capabilities.ts +0 -18
- package/routes/cardNews.ts +0 -211
- package/routes/comfy.ts +0 -43
- package/routes/edit.ts +0 -352
- package/routes/generate.ts +0 -492
- package/routes/grok.ts +0 -24
- package/routes/health.ts +0 -123
- package/routes/history.ts +0 -221
- package/routes/imageImport.ts +0 -37
- package/routes/index.ts +0 -52
- package/routes/metadata.ts +0 -77
- package/routes/multimode.ts +0 -499
- package/routes/nodes.ts +0 -578
- package/routes/promptBuilder.ts +0 -37
- package/routes/promptImport.ts +0 -379
- package/routes/prompts.ts +0 -428
- package/routes/quota.ts +0 -89
- package/routes/sessions.ts +0 -317
- package/routes/storage.ts +0 -47
- package/routes/video.ts +0 -300
- package/routes/videoExtended.ts +0 -284
- package/server.ts +0 -293
- package/ui/dist/assets/SettingsWorkspace-PiaVnsdA.js +0 -1
- package/ui/dist/assets/index-CjgnNtgt.css +0 -1
- 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
|
-
}
|
package/lib/oauthProxy/types.ts
DELETED
|
@@ -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
package/lib/openDirectory.ts
DELETED
|
@@ -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
|
-
}
|