openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
125 lines (124 loc) • 5.49 kB
JavaScript
import { g as readStringValue } from "./string-coerce-CIXf7egm.js";
import { a as redactModelVisibleSecrets, h as redactToolPayloadText, l as redactSecrets } from "./redact-BtvPPfTi.js";
import { t as createSubsystemLogger } from "./subsystem-Dy2tqXOS.js";
import { u as swapSecretSentinelsInText } from "./sentinel-ZgmfESkJ.js";
import { d as normalizeMimeType, n as detectMime } from "./mime-CVpcq9ju.js";
import { r as resolveProviderRequestCapabilities } from "./provider-attribution-CDS-94hQ.js";
import { a as getModelProviderRequestRouteFacts } from "./provider-request-config-DIOYidiO.js";
import { n as resolveModelRequestTimeoutMs, t as buildGuardedModelFetch } from "./provider-transport-fetch-DGSx4u4m.js";
import { n as estimateBase64DecodedBytes, t as canonicalizeBase64 } from "./base64-Vw7DZYSc.js";
import { a as convertImageToJpeg, o as convertImageToPng } from "./image-ops-DU1SIRgh.js";
import { configureProviderErrorRedactor } from "@openclaw/ai/diagnostics";
import { configureAiTransportHost } from "@openclaw/ai";
//#region src/agents/openai-strict-tool-setting.ts
/**
* Strict tool-schema default resolution for native OpenAI-compatible routes.
*
* Compatible providers can support strict schemas without inheriting OpenAI's required default.
*/
function resolvesToNativeOpenAIStrictTools(model, transport) {
const capabilities = getModelProviderRequestRouteFacts(model)?.capabilities ?? resolveProviderRequestCapabilities({
provider: readStringValue(model.provider),
api: readStringValue(model.api),
baseUrl: readStringValue(model.baseUrl),
capability: "llm",
transport,
modelId: readStringValue(model.id),
compat: model.compat
});
if (!capabilities.usesKnownNativeOpenAIRoute) return false;
return capabilities.provider === "openai" || capabilities.provider === "azure-openai" || capabilities.provider === "azure-openai-responses";
}
/** Resolve the strict-tool setting for one OpenAI-compatible model/transport. */
function resolveOpenAIStrictToolSetting(model, options) {
if (resolvesToNativeOpenAIStrictTools(model, options?.transport ?? "stream")) return true;
if (options?.supportsStrictMode) return false;
}
//#endregion
//#region src/media/anthropic-inline-images.ts
const ANTHROPIC_SUPPORTED_IMAGE_MIMES = [
"image/jpeg",
"image/png",
"image/gif",
"image/webp"
];
const ANTHROPIC_INLINE_IMAGE_DECODE_SAFETY_BYTES = 10485760;
const ANTHROPIC_SUPPORTED_IMAGE_MIME_SET = new Set(ANTHROPIC_SUPPORTED_IMAGE_MIMES);
function isAnthropicSupportedImageMime(value) {
return typeof value === "string" && ANTHROPIC_SUPPORTED_IMAGE_MIME_SET.has(value);
}
async function normalizeAnthropicInlineImage(block) {
const canonicalData = canonicalizeBase64(block.data) ?? block.data.trim();
const buffer = Buffer.from(canonicalData, "base64");
const declaredMime = normalizeMimeType(block.mimeType);
const detectedMime = normalizeMimeType(await detectMime({ buffer }));
if (isAnthropicSupportedImageMime(detectedMime)) return {
data: canonicalData,
mimeType: detectedMime
};
if (!detectedMime && isAnthropicSupportedImageMime(declaredMime)) return {
data: canonicalData,
mimeType: declaredMime
};
const convertToPng = detectedMime === "image/bmp";
const normalizedBuffer = convertToPng ? await convertImageToPng(buffer) : await convertImageToJpeg(buffer);
if (normalizedBuffer.byteLength > ANTHROPIC_INLINE_IMAGE_DECODE_SAFETY_BYTES) throw new Error("Normalized Anthropic inline image exceeds the 10 MB decoded safety limit.");
return {
data: normalizedBuffer.toString("base64"),
mimeType: convertToPng ? "image/png" : "image/jpeg"
};
}
async function normalizeAnthropicInlineContentBlocks(content) {
for (const block of content) {
if (block.type !== "image") continue;
if (estimateBase64DecodedBytes(block.data) > ANTHROPIC_INLINE_IMAGE_DECODE_SAFETY_BYTES) throw new Error("Anthropic inline image exceeds the 10 MB decoded safety limit.");
}
const normalized = [];
for (const block of content) {
if (block.type !== "image") {
normalized.push(block);
continue;
}
normalized.push({
...block,
...await normalizeAnthropicInlineImage(block)
});
}
return normalized;
}
//#endregion
//#region src/llm/ai-transport-host.ts
const transportLogBySubsystem = /* @__PURE__ */ new Map();
configureProviderErrorRedactor(redactSecrets);
function transportLog(subsystem) {
let log = transportLogBySubsystem.get(subsystem);
if (!log) {
log = createSubsystemLogger(subsystem);
transportLogBySubsystem.set(subsystem, log);
}
return log;
}
configureAiTransportHost({
buildModelFetch: buildGuardedModelFetch,
resolveSecretSentinel: (value) => {
const swapped = swapSecretSentinelsInText(value);
const unknown = swapped.unknown[0];
if (unknown) throw new Error(`Secret sentinel ${unknown} is not registered in this process; refusing to construct provider client`);
return swapped.text;
},
redactModelVisibleSecrets,
redactToolPayloadText,
normalizeAnthropicInlineContentBlocks,
resolveOpenAIStrictToolSetting,
resolveModelRequestTimeoutMs: (model) => resolveModelRequestTimeoutMs(model, void 0),
logDebug: (subsystem, build) => {
const log = transportLog(subsystem);
if (!log.isEnabled("debug", "any")) return;
const entry = build();
if (entry) log.debug(entry.message, entry.data);
},
logInfo: (subsystem, message, data) => transportLog(subsystem).info(message, data),
logWarn: (subsystem, message, data) => transportLog(subsystem).warn(message, data)
});
//#endregion
export {};