openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
135 lines (134 loc) • 5.49 kB
JavaScript
import { i as streamSimple } from "./stream-4H1GSjKe.js";
import "./llm-B2byLsni.js";
import { b as createToolStreamWrapper, s as createPlainTextToolCallCompatWrapper, t as composeProviderStreamWrappers } from "./provider-stream-shared-BIV_zuwB.js";
//#region extensions/xai/stream.ts
const XAI_FAST_MODEL_IDS = new Map([
["grok-3", "grok-3-fast"],
["grok-3-mini", "grok-3-mini-fast"],
["grok-4", "grok-4-fast"],
["grok-4-0709", "grok-4-fast"]
]);
function resolveXaiFastModelId(modelId) {
if (typeof modelId !== "string") return;
return XAI_FAST_MODEL_IDS.get(modelId.trim());
}
function stripUnsupportedStrictFlag(tool) {
if (!tool || typeof tool !== "object") return tool;
const toolObj = tool;
const fn = toolObj.function;
if (!fn || typeof fn !== "object") return tool;
const fnObj = fn;
if (typeof fnObj.strict !== "boolean") return tool;
const nextFunction = { ...fnObj };
delete nextFunction.strict;
return {
...toolObj,
function: nextFunction
};
}
function supportsExplicitImageInput(model) {
return Array.isArray(model.input) && model.input.includes("image");
}
function supportsReasoningControls(model) {
const compat = model.compat && typeof model.compat === "object" ? model.compat : void 0;
return model.reasoning === true && compat?.supportsReasoningEffort !== false;
}
const TOOL_RESULT_IMAGE_REPLAY_TEXT = "Attached image(s) from tool result:";
function isReplayableInputImagePart(part) {
if (part.type !== "input_image") return false;
if (typeof part.image_url === "string") return true;
if (!part.source || typeof part.source !== "object") return false;
const source = part.source;
if (source.type === "url") return typeof source.url === "string";
return source.type === "base64" && typeof source.media_type === "string" && typeof source.data === "string";
}
function normalizeXaiResponsesFunctionCallOutput(item, includeImages) {
if (!item || typeof item !== "object") return {
normalizedItem: item,
imageParts: []
};
const itemObj = item;
if (itemObj.type !== "function_call_output" || !Array.isArray(itemObj.output)) return {
normalizedItem: itemObj,
imageParts: []
};
const outputParts = itemObj.output;
const textOutput = outputParts.filter((part) => part.type === "input_text" && typeof part.text === "string").map((part) => part.text).join("");
const imageParts = includeImages ? outputParts.filter((part) => isReplayableInputImagePart(part)) : [];
const hadNonTextParts = outputParts.some((part) => part.type !== "input_text");
return {
normalizedItem: {
...itemObj,
output: textOutput || (hadNonTextParts ? "(see attached image)" : "")
},
imageParts
};
}
function normalizeXaiResponsesToolResultPayload(payloadObj, model) {
if (model.api !== "openai-responses" || !Array.isArray(payloadObj.input)) return;
const includeImages = supportsExplicitImageInput(model);
const normalizedInput = [];
const collectedImageParts = [];
for (const item of payloadObj.input) {
const normalized = normalizeXaiResponsesFunctionCallOutput(item, includeImages);
normalizedInput.push(normalized.normalizedItem);
collectedImageParts.push(...normalized.imageParts);
}
if (collectedImageParts.length > 0) normalizedInput.push({
type: "message",
role: "user",
content: [{
type: "input_text",
text: TOOL_RESULT_IMAGE_REPLAY_TEXT
}, ...collectedImageParts]
});
payloadObj.input = normalizedInput;
}
function createXaiToolPayloadCompatibilityWrapper(baseStreamFn) {
const underlying = baseStreamFn ?? streamSimple;
return (model, context, options) => {
const originalOnPayload = options?.onPayload;
return underlying(model, context, {
...options,
onPayload: (payload) => {
if (payload && typeof payload === "object") {
const payloadObj = payload;
if (Array.isArray(payloadObj.tools)) payloadObj.tools = payloadObj.tools.map((tool) => stripUnsupportedStrictFlag(tool));
normalizeXaiResponsesToolResultPayload(payloadObj, model);
if (!supportsReasoningControls(model)) {
delete payloadObj.reasoning;
delete payloadObj.reasoningEffort;
delete payloadObj.reasoning_effort;
}
}
return originalOnPayload?.(payload, model);
}
});
};
}
function createXaiFastModeWrapper(baseStreamFn, fastMode) {
const underlying = baseStreamFn ?? streamSimple;
return (model, context, options) => {
const supportsFastAliasTransport = model.api === "openai-completions" || model.api === "openai-responses";
if (!fastMode || !supportsFastAliasTransport || model.provider !== "xai") return underlying(model, context, options);
const fastModelId = resolveXaiFastModelId(model.id);
if (!fastModelId) return underlying(model, context, options);
return underlying({
...model,
id: fastModelId
}, context, options);
};
}
function wrapXaiProviderStream(ctx) {
const extraParams = ctx.extraParams;
const fastMode = extraParams?.fastMode;
const toolStreamEnabled = extraParams?.tool_stream !== false;
return composeProviderStreamWrappers(ctx.streamFn, (streamFn) => {
let wrappedStreamFn = createXaiToolPayloadCompatibilityWrapper(streamFn);
if (typeof fastMode === "boolean") wrappedStreamFn = createXaiFastModeWrapper(wrappedStreamFn, fastMode);
wrappedStreamFn = createPlainTextToolCallCompatWrapper(wrappedStreamFn);
return createToolStreamWrapper(wrappedStreamFn, toolStreamEnabled);
});
}
//#endregion
export { createXaiToolPayloadCompatibilityWrapper as n, wrapXaiProviderStream as r, createXaiFastModeWrapper as t };