openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
317 lines (316 loc) • 12.9 kB
JavaScript
import { r as __exportAll } from "./rolldown-runtime-Dr7-SnC6.mjs";
import { o as normalizeLowercaseStringOrEmpty } from "./string-coerce-1VuiLaaR.mjs";
import { i as asOptionalObjectRecord } from "./record-coerce-TIsquoVR.mjs";
import { _ as normalizeUniqueTrimmedStringList } from "./string-normalization-CECOqf64.mjs";
import { a as resolveOpenAIThinkingApi } from "./model-catalog-types-BUOf2O4u.mjs";
import { _ as runtimeContextContentToText, f as hasRuntimeContextMarker, p as isRuntimeContextMessage } from "./types-CQc6JNG4.mjs";
import { n as validateToolCall, t as validateToolArguments } from "./validation-Rta7w8wz.mjs";
import { r as resolveEnvNodeProxyUrlForTarget, t as createFixedNodeProxyAgentPair } from "./node-proxy-agent-D_aqMs2B.mjs";
import { i as streamSimple, n as completeSimple, r as stream, t as complete } from "./stream-noSN8e3M.mjs";
import { adjustMaxTokensForThinking, buildBaseOptions, clampReasoning, transformMessages } from "@openclaw/ai/internal/shared";
import { calculateCost, clampThinkingLevel as clampThinkingLevel$1, createToolArgumentPreviewSchedule as createToolArgumentPreviewSchedule$1, getApiProvider, getApiProviders, getEnvApiKey, parseStreamingJson as parseStreamingJson$1, sanitizeSurrogates as sanitizeSurrogates$1 } from "@openclaw/ai/internal/runtime";
//#region packages/llm-core/src/utils/event-stream.ts
const thinkingAppends = /* @__PURE__ */ new WeakMap();
const eventStreamCompletions = /* @__PURE__ */ new WeakMap();
/** Generic async-iterable event stream with a separately awaited final result. */
var EventStream = class {
constructor(isComplete, extractResult) {
this.queue = [];
this.queueHead = 0;
this.waiting = [];
this.done = false;
this.resultSettled = false;
this.isComplete = isComplete;
this.extractResult = extractResult;
this.finalResultPromise = new Promise((resolve, reject) => {
this.resolveFinalResult = resolve;
this.rejectFinalResult = reject;
});
eventStreamCompletions.set(this, this.finalResultPromise);
}
push(event) {
if (this.done) return;
if (this.isComplete(event)) {
this.done = true;
this.resultSettled = true;
this.resolveFinalResult(this.extractResult(event));
}
const waiter = this.waiting.shift();
if (waiter) waiter({
value: event,
done: false
});
else this.queue.push(event);
}
end(result) {
this.done = true;
if (result !== void 0) {
this.resultSettled = true;
this.resolveFinalResult(result);
} else if (!this.resultSettled) {
this.resultSettled = true;
this.finalResultPromise.catch(() => {});
this.rejectFinalResult(/* @__PURE__ */ new Error("event stream ended without a terminal event or final result"));
}
while (this.waiting.length > 0) {
const waiter = this.waiting.shift();
if (!waiter) break;
waiter({
value: void 0,
done: true
});
}
}
async *[Symbol.asyncIterator]() {
while (true) if (this.queueHead < this.queue.length) {
const event = this.queue[this.queueHead];
this.queue[this.queueHead] = void 0;
this.queueHead += 1;
if (this.queueHead >= 1024 && this.queueHead * 2 >= this.queue.length) {
this.queue = this.queue.slice(this.queueHead);
this.queueHead = 0;
}
yield event;
} else if (this.done) return;
else {
const result = await new Promise((resolve) => {
this.waiting.push(resolve);
});
if (result.done) return;
yield result.value;
}
}
result() {
return this.finalResultPromise;
}
};
/** Assistant-message event stream that resolves on done/error terminal events. */
var AssistantMessageEventStream = class extends EventStream {
push(event) {
if (!this.done && event.type === "text_delta" && !event.partial) {
const previous = this.queue[this.queue.length - 1];
if (previous?.type === "text_delta" && !previous.partial && previous.contentIndex === event.contentIndex) {
this.queue[this.queue.length - 1] = {
...event,
delta: previous.delta + event.delta
};
return;
}
}
if (event.type === "thinking_delta" || event.type === "thinking_end") {
const block = event.partial.content[event.contentIndex];
if (block?.type === "thinking") {
if (this.done || event.type === "thinking_end") {
thinkingAppends.delete(block);
this.activeThinkingBlocks?.delete(block);
} else if (thinkingAppends.has(block)) (this.activeThinkingBlocks ??= /* @__PURE__ */ new Set()).add(block);
}
}
if (event.type === "done" || event.type === "error") this.clearThinkingAppends(event.type === "done" ? event.message : event.error);
super.push(event);
}
end(result) {
this.clearThinkingAppends(result);
super.end(result);
}
clearThinkingAppends(message) {
for (const block of message?.content ?? []) if (block.type === "thinking") thinkingAppends.delete(block);
for (const block of this.activeThinkingBlocks ?? []) thinkingAppends.delete(block);
this.activeThinkingBlocks = void 0;
}
constructor() {
super((event) => event.type === "done" || event.type === "error", (event) => {
if (event.type === "done") return event.message;
else if (event.type === "error") return event.error;
throw new Error("Unexpected event type for final result");
});
}
};
/** Creates an assistant-message stream for provider and plugin adapters. */
function createAssistantMessageEventStream() {
return new AssistantMessageEventStream();
}
//#endregion
//#region packages/ai/src/provider-types.ts
const PROVIDER_CONTEXT_HANDOFF = Symbol("providerContextHandoff");
/** Resolves provider-only context without widening the canonical call contract. */
async function resolveProviderContext(context, options) {
return options?.[PROVIDER_CONTEXT_HANDOFF]?.() ?? context;
}
//#endregion
//#region packages/ai/src/providers/openai-reasoning-effort.ts
/**
* OpenAI-compatible reasoning-effort normalization. Different GPT families
* expose different accepted effort enums, so callers map requested values here
* before constructing provider payloads.
*/
const ENABLED_REASONING_EFFORTS = [
"minimal",
"low",
"medium",
"high",
"xhigh",
"max"
];
const GPT_5_REASONING_EFFORTS = [
"minimal",
"low",
"medium",
"high"
];
const GPT_51_REASONING_EFFORTS = [
"none",
"low",
"medium",
"high"
];
const GPT_52_REASONING_EFFORTS = [
"none",
"low",
"medium",
"high",
"xhigh"
];
const GPT_56_REASONING_EFFORTS = [
"none",
"low",
"medium",
"high",
"xhigh",
"max"
];
const GPT_6_MANDATORY_REASONING_EFFORTS = [
"low",
"medium",
"high",
"xhigh",
"max"
];
const GPT_CODEX_REASONING_EFFORTS = [
"low",
"medium",
"high",
"xhigh"
];
const GPT_PRO_REASONING_EFFORTS = [
"medium",
"high",
"xhigh"
];
const GPT_5_PRO_REASONING_EFFORTS = ["high"];
const GPT_51_CODEX_MAX_REASONING_EFFORTS = [
"none",
"medium",
"high",
"xhigh"
];
const GPT_51_CODEX_MINI_REASONING_EFFORTS = ["medium"];
const CANONICAL_REASONING_EFFORTS = /* @__PURE__ */ new Set([
"none",
...ENABLED_REASONING_EFFORTS,
"off"
]);
function normalizeModelId(id) {
return normalizeLowercaseStringOrEmpty(id ?? "").replace(/-\d{4}-\d{2}-\d{2}$/u, "");
}
/** Return whether a model has a known GPT-6 reasoning and sampling contract. */
function isOpenAIGpt6Model(model) {
const id = normalizeModelId(typeof model.id === "string" ? model.id : void 0);
return id === "gpt-6-astra" || id === "gpt-6-sol" || id === "gpt-6-luna" || id === "gpt-6.1-sol";
}
/** Normalize user-facing reasoning effort names to API effort names. */
function normalizeOpenAIReasoningEffort(effort) {
const trimmed = effort.trim();
const folded = trimmed.toLowerCase();
return CANONICAL_REASONING_EFFORTS.has(folded) ? folded : trimmed;
}
function readCompatReasoningEfforts(compat) {
if (!compat || typeof compat !== "object") return;
if (compat.supportsReasoningEffort === false) return [];
const raw = compat.supportedReasoningEfforts;
if (!Array.isArray(raw)) return;
return normalizeUniqueTrimmedStringList(raw);
}
/** Read a declared or known model contract, leaving unknown compatible models unspecified. */
function resolveOpenAIModelReasoningEfforts(model) {
const compatEfforts = readCompatReasoningEfforts(model.compat);
if (compatEfforts) return compatEfforts;
const id = normalizeModelId(typeof model.id === "string" ? model.id : void 0);
const api = resolveOpenAIThinkingApi(model.api);
const supportsMax = api !== "openai-completions";
if (isOpenAIGpt6Model(model) && api !== "azure-openai-responses") {
if (id === "gpt-6-astra" || id === "gpt-6.1-sol") return supportsMax ? GPT_6_MANDATORY_REASONING_EFFORTS : GPT_CODEX_REASONING_EFFORTS;
return supportsMax ? GPT_56_REASONING_EFFORTS : GPT_52_REASONING_EFFORTS;
}
if (/^gpt-5\.6(?:-|$)/u.test(id)) return supportsMax ? GPT_56_REASONING_EFFORTS : GPT_52_REASONING_EFFORTS;
if (id === "gpt-5.1-codex-mini") return GPT_51_CODEX_MINI_REASONING_EFFORTS;
if (id === "gpt-5.1-codex-max") return GPT_51_CODEX_MAX_REASONING_EFFORTS;
if (/^gpt-5(?:\.\d+)?-codex(?:-|$)/u.test(id)) return GPT_CODEX_REASONING_EFFORTS;
if (id === "gpt-5-pro") return GPT_5_PRO_REASONING_EFFORTS;
if (/^gpt-5\.[2-9](?:\.\d+)?-pro(?:-|$)/u.test(id)) return GPT_PRO_REASONING_EFFORTS;
if (/^gpt-5\.[2-9](?:\.\d+)?(?:-|$)/u.test(id)) return GPT_52_REASONING_EFFORTS;
if (/^gpt-5\.1(?:-|$)/u.test(id)) return GPT_51_REASONING_EFFORTS;
if (/^gpt-5(?:-|$)/u.test(id)) return GPT_5_REASONING_EFFORTS;
}
/** Read provider mappings without folding provider-native labels. */
function resolveOpenAIReasoningEffortMapping(effort, mapping) {
const requested = normalizeOpenAIReasoningEffort(effort);
return mapping?.[requested] ?? (mapping && CANONICAL_REASONING_EFFORTS.has(requested) ? Object.entries(mapping).find(([key]) => normalizeOpenAIReasoningEffort(key) === requested)?.[1] : void 0);
}
//#endregion
//#region packages/ai/src/transports/openai-reasoning-compat.ts
/** Explicit model reasoning-effort compatibility metadata. */
function readCompatReasoningEffortMap(compat) {
const rawMap = asOptionalObjectRecord(asOptionalObjectRecord(compat)?.reasoningEffortMap);
if (!rawMap) return {};
return Object.fromEntries(Object.entries(rawMap).filter((entry) => typeof entry[1] === "string"));
}
/** Resolves the reasoning effort remap for an OpenAI-compatible model. */
function resolveOpenAIReasoningEffortMap(model, fallbackMap = {}) {
return {
...fallbackMap,
...readCompatReasoningEffortMap(model.compat)
};
}
//#endregion
//#region src/llm/utils/node-http-proxy.ts
/** Builds fixed HTTP and HTTPS proxy agents for a target URL, when env proxy config applies. */
function createHttpProxyAgentsForTarget(targetUrl) {
const proxyUrl = resolveEnvNodeProxyUrlForTarget(targetUrl);
if (!proxyUrl) return;
return createFixedNodeProxyAgentPair(proxyUrl);
}
//#endregion
//#region src/plugin-sdk/llm.ts
var llm_exports = /* @__PURE__ */ __exportAll({
AssistantMessageEventStream: () => AssistantMessageEventStream,
adjustMaxTokensForThinking: () => adjustMaxTokensForThinking,
buildBaseOptions: () => buildBaseOptions,
calculateCost: () => calculateCost,
clampReasoning: () => clampReasoning,
clampThinkingLevel: () => clampThinkingLevel$1,
complete: () => complete,
completeSimple: () => completeSimple,
createAssistantMessageEventStream: () => createAssistantMessageEventStream,
createHttpProxyAgentsForTarget: () => createHttpProxyAgentsForTarget,
createToolArgumentPreviewSchedule: () => createToolArgumentPreviewSchedule$1,
getApiProvider: () => getApiProvider,
getApiProviders: () => getApiProviders,
getEnvApiKey: () => getEnvApiKey,
hasRuntimeContextMarker: () => hasRuntimeContextMarker,
isRuntimeContextMessage: () => isRuntimeContextMessage,
parseStreamingJson: () => parseStreamingJson$1,
resolveOpenAIModelReasoningEfforts: () => resolveOpenAIModelReasoningEfforts,
resolveOpenAIReasoningEffortMap: () => resolveOpenAIReasoningEffortMap,
resolveOpenAIReasoningEffortMapping: () => resolveOpenAIReasoningEffortMapping,
resolveProviderContext: () => resolveProviderContext,
runtimeContextContentToText: () => runtimeContextContentToText,
sanitizeSurrogates: () => sanitizeSurrogates$1,
stream: () => stream,
streamSimple: () => streamSimple,
transformMessages: () => transformMessages,
validateToolArguments: () => validateToolArguments,
validateToolCall: () => validateToolCall
});
//#endregion
export { resolveOpenAIReasoningEffortMapping as _, clampThinkingLevel$1 as a, AssistantMessageEventStream as b, getApiProviders as c, parseStreamingJson$1 as d, sanitizeSurrogates$1 as f, resolveOpenAIModelReasoningEfforts as g, resolveOpenAIReasoningEffortMap as h, clampReasoning as i, getEnvApiKey as l, createHttpProxyAgentsForTarget as m, buildBaseOptions as n, createToolArgumentPreviewSchedule$1 as o, transformMessages as p, calculateCost as r, getApiProvider as s, adjustMaxTokensForThinking as t, llm_exports as u, PROVIDER_CONTEXT_HANDOFF as v, createAssistantMessageEventStream as x, resolveProviderContext as y };