openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
136 lines (135 loc) • 6.56 kB
JavaScript
import { r as truncateUtf16Safe } from "../../utf16-slice-D_ngcYKd.mjs";
import { n as sanitizeTerminalText } from "../../safe-text-SY_CvCi3.mjs";
import { Fn as object, Jn as string, Nt as array, sr as unknown } from "../../schemas-BOYIvvln.mjs";
import { i as readResponseWithLimit } from "../../http-response-body-umfRGZ-E.mjs";
import { t as canonicalizeBase64 } from "../../base64-CU53EX1R.mjs";
import "../../text-utility-runtime-BDs7x8Fk.mjs";
import "../../response-limit-runtime-CpfmMF5T.mjs";
import "../../text-chunking-D9rERslX.mjs";
//#region extensions/openai/image-generation-codex-response.ts
const MAX_CODEX_IMAGE_SSE_BYTES = 67108864;
const MAX_CODEX_IMAGE_SSE_EVENTS = 512;
const MAX_CODEX_IMAGE_BASE64_CHARS = 67108864;
const OPENAI_MAX_IMAGE_RESULTS = 4;
const DIAGNOSTIC_MAX_CHARS = 256;
const contentSchema = object({
type: string().nullish(),
text: string().nullish(),
refusal: string().nullish()
});
const itemSchema = contentSchema.extend({
result: string().nullish(),
revised_prompt: string().nullish(),
status: string().nullish(),
content: array(contentSchema).nullish()
});
const errorSchema = object({
code: string().nullish(),
message: string().nullish()
});
const eventSchema = object({
type: string().nullish(),
item: itemSchema.nullish(),
response: object({
error: errorSchema.nullish(),
incomplete_details: object({ reason: string().nullish() }).nullish(),
output: array(itemSchema).nullish(),
usage: unknown().optional(),
tool_usage: unknown().optional()
}).nullish(),
error: errorSchema.nullish(),
message: string().nullish()
});
function parseCodexImageGenerationEvents(body) {
const events = [];
for (const frame of body.replace(/\r\n?/g, "\n").split("\n\n")) {
const data = frame.split("\n").filter((line) => line.startsWith("data:")).map((line) => line.slice(5).replace(/^ /, "")).join("\n").trim();
if (!data || data === "[DONE]") continue;
let decoded;
try {
decoded = JSON.parse(data);
} catch {
continue;
}
const event = eventSchema.safeParse(decoded);
if (!event.success) throw new Error("OpenAI Codex image generation returned a malformed stream event");
events.push(event.data);
if (events.length > MAX_CODEX_IMAGE_SSE_EVENTS) throw new Error("OpenAI Codex image generation response exceeded event limit");
}
return events;
}
function decodeCodexImagePayload(payload) {
if (payload.length > MAX_CODEX_IMAGE_BASE64_CHARS) throw new Error("OpenAI Codex image generation result exceeded size limit");
const trimmedPayload = payload.replace(/^\p{White_Space}+|\p{White_Space}+$/gu, "");
const canonicalPayload = canonicalizeBase64(trimmedPayload);
if (!canonicalPayload || canonicalPayload !== trimmedPayload) throw new Error("OpenAI Codex image generation returned malformed base64 image data");
return Buffer.from(canonicalPayload, "base64");
}
function extractCodexImageDiagnostic(completed, streamed) {
for (const output of [completed ?? [], streamed]) {
let providerText;
for (const entry of output) {
const parts = entry.type === "message" ? entry.content ?? [] : [entry];
for (const part of parts) {
const raw = part.type === "refusal" ? part.refusal ?? part.text : part.type === "output_text" ? part.text : void 0;
if (typeof raw !== "string") continue;
const cleaned = sanitizeTerminalText(raw.replace(/safety_violations=\[[^\]]*\]/gi, " ")).replace(/[\u200e\u200f\u202a-\u202e\u2066-\u2069]/gi, "").replace(/\s+/g, " ").trim();
if (!cleaned) continue;
const text = cleaned.length > DIAGNOSTIC_MAX_CHARS ? `${truncateUtf16Safe(cleaned, DIAGNOSTIC_MAX_CHARS)}...` : cleaned;
if (part.type === "refusal") return `OpenAI Codex image generation refused by provider: "${text}"`;
providerText ??= `OpenAI Codex image generation returned text instead of an image: "${text}"`;
}
}
if (providerText) return providerText;
}
}
async function readCodexImageGenerationResponse(response, params) {
const body = await readResponseWithLimit(response, MAX_CODEX_IMAGE_SSE_BYTES, { onOverflow: () => /* @__PURE__ */ new Error("OpenAI Codex image generation response exceeded size limit") });
const events = parseCodexImageGenerationEvents(new TextDecoder().decode(body));
const outputItems = [];
let completedResponse;
for (const event of events) {
if (event.type === "response.failed" || event.type === "error") {
const error = event.response?.error ?? event.error;
const message = error?.message ?? event.message ?? (error?.code ? `OpenAI Codex image generation failed (${error.code})` : "");
throw new Error(message || "OpenAI Codex image generation failed");
}
if (event.type === "response.incomplete") {
const reason = event.response?.incomplete_details?.reason ?? "unknown";
throw new Error(`OpenAI Codex image generation response incomplete: ${reason}`);
}
if (event.type === "response.completed") {
completedResponse = event.response;
break;
}
if (event.type === "response.output_item.done" && event.item) outputItems.push(event.item);
}
if (!completedResponse) throw new Error("OpenAI Codex image generation stream closed before response.completed");
const completedOutputItems = (completedResponse.output ?? []).filter((entry) => entry.type === "image_generation_call");
const selectedOutputItems = (completedOutputItems.length > 0 ? completedOutputItems : outputItems.filter((entry) => entry.type === "image_generation_call")).slice(0, OPENAI_MAX_IMAGE_RESULTS);
const images = [];
for (const [index, item] of selectedOutputItems.entries()) {
if (item.status && item.status !== "completed") {
const diagnostic = extractCodexImageDiagnostic(completedResponse.output, outputItems);
throw new Error(diagnostic ? `${diagnostic} (image call did not complete (${item.status}))` : `OpenAI Codex image generation image call did not complete (${item.status})`);
}
if (typeof item.result !== "string" || item.result.length === 0) continue;
images.push({
buffer: decodeCodexImagePayload(item.result),
mimeType: params.mimeType,
fileName: `image-${index + 1}.${params.extension}`,
...item.revised_prompt ? { revisedPrompt: item.revised_prompt } : {}
});
}
if (images.length === 0) throw new Error(extractCodexImageDiagnostic(completedResponse.output, outputItems) ?? "OpenAI Codex image generation completed but did not produce an image");
return {
images,
model: params.model,
metadata: {
usage: completedResponse.usage,
toolUsage: completedResponse.tool_usage
}
};
}
//#endregion
export { readCodexImageGenerationResponse };