openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
612 lines (611 loc) • 28.5 kB
JavaScript
import { o as normalizeLowercaseStringOrEmpty } from "./string-coerce-6kR-86XC.mjs";
import { i as asOptionalObjectRecord } from "./record-coerce-TIsquoVR.mjs";
import { r as findCodeRegions } from "./code-regions-CjBR1D_6.mjs";
import { a as projectScrubbedPlainTextToolCallMessage, i as normalizePlainTextToolCallStreamEvents, n as createPromotedPlainTextToolCallEvents, r as projectStandalonePlainTextToolCallMessage, t as createPromotedPlainTextToolCallBlock } from "./src-CuGBxcbS.mjs";
import { t as event_stream_exports } from "./event-stream-xGBL9CyU.mjs";
import { i as streamSimple } from "./stream-DfRba3vu.mjs";
import { t as streamWithPayloadPatch } from "./stream-payload-utils-BoUixBWV.mjs";
import "./moonshot-thinking-DKZUWN-7.mjs";
import { projectCopilotRequestFacts as projectCopilotRequestFacts$1 } from "@openclaw/ai/internal/shared";
import { createDeferredEventBuffer, notifyLlmRequestActivity as notifyLlmRequestActivity$1, onLlmRequestActivity as onLlmRequestActivity$1 } from "@openclaw/ai/internal/runtime";
import { applyAnthropicEphemeralCacheControlMarkers, applyAnthropicPayloadPolicyToParams, applyCompletionsAnthropicCacheControl as applyCompletionsAnthropicCacheControl$1, createEmptyTransportUsage, googleFlashSupportsMinimalThinking, resolveAnthropicEphemeralCacheControl, resolveAnthropicPayloadPolicy, resolveOpenAIReasoningEffortMap } from "@openclaw/ai/transports";
import { resolveOpenAIReasoningEffortForModel } from "@openclaw/ai/internal/openai";
import { applyAnthropicRefusal, isAnthropicOAuthApiKey, resolveAnthropicServerCompactionPlan as resolveAnthropicServerCompactionPlan$1, resolveAnthropicThinkingEffort } from "@openclaw/ai/internal/anthropic";
import { isGoogleGemini3FlashModel, isGoogleGemini3FlashModel as isGoogleGemini3FlashModel$1, isGoogleGemini3ProModel, isGoogleGemini3ProModel as isGoogleGemini3ProModel$1, isGoogleGemini3ThinkingLevelModel, isGoogleGemini3ThinkingLevelModel as isGoogleGemini3ThinkingLevelModel$1 } from "@openclaw/ai/internal/google-model-family";
//#region src/llm/providers/stream-wrappers/reasoning-effort-utils.ts
/** Maps OpenClaw thinking levels onto provider reasoning-effort labels. */
function mapThinkingLevelToReasoningEffort(thinkingLevel) {
if (thinkingLevel === "off") return "none";
if (thinkingLevel === "adaptive") return "medium";
if (thinkingLevel === "max" || thinkingLevel === "ultra") return "xhigh";
return thinkingLevel;
}
//#endregion
//#region src/llm/providers/stream-wrappers/google-thinking-payload.ts
/** @deprecated Google provider-owned stream helper; do not use from third-party plugins. */
function isGoogleThinkingRequiredModel(modelId) {
return normalizeLowercaseStringOrEmpty(modelId).includes("gemini-2.5-pro");
}
/** @deprecated Google provider-owned stream helper; do not use from third-party plugins. */
function isGoogleGemini25ThinkingBudgetModel(modelId) {
return /(?:^|\/)gemini-2\.5-/.test(normalizeLowercaseStringOrEmpty(modelId));
}
/**
* Maps legacy numeric/semantic thinking input onto Gemini 3's provider enum.
* @deprecated Google provider-owned stream helper; do not use from third-party plugins.
*/
function resolveGoogleGemini3ThinkingLevel(params) {
if (typeof params.modelId !== "string") return;
if (isGoogleGemini3ProModel(params.modelId)) {
switch (params.thinkingLevel) {
case "off":
case "minimal":
case "low": return "LOW";
case "medium":
case "high":
case "max":
case "xhigh": return "HIGH";
case "adaptive": return;
case void 0:
}
if (typeof params.thinkingBudget === "number") {
if (params.thinkingBudget < 0) return;
return params.thinkingBudget <= 2048 ? "LOW" : "HIGH";
}
return;
}
if (!isGoogleGemini3FlashModel(params.modelId)) return;
const minimalLevel = googleFlashSupportsMinimalThinking(params.modelId) ? "MINIMAL" : "LOW";
switch (params.thinkingLevel) {
case "off":
case "minimal": return minimalLevel;
case "low": return "LOW";
case "medium": return "MEDIUM";
case "high":
case "max":
case "xhigh": return "HIGH";
case "adaptive": return;
case void 0:
}
if (typeof params.thinkingBudget !== "number") return;
if (params.thinkingBudget < 0) return;
if (params.thinkingBudget <= 0) return minimalLevel;
if (params.thinkingBudget <= 2048) return "LOW";
if (params.thinkingBudget <= 8192) return "MEDIUM";
return "HIGH";
}
/**
* Removes `thinkingBudget=0` only for Gemini models that reject disabled thinking.
* @deprecated Google provider-owned stream helper; do not use from third-party plugins.
*/
function stripInvalidGoogleThinkingBudget(params) {
if (params.thinkingConfig.thinkingBudget !== 0 || typeof params.modelId !== "string" || !isGoogleThinkingRequiredModel(params.modelId)) return false;
delete params.thinkingConfig.thinkingBudget;
return true;
}
function isGemma4Model(modelId) {
return normalizeLowercaseStringOrEmpty(modelId).startsWith("gemma-4");
}
function mapThinkLevelToGemma4ThinkingLevel(thinkingLevel) {
switch (thinkingLevel) {
case "off": return;
case "minimal":
case "low": return "MINIMAL";
case "medium":
case "adaptive":
case "high":
case "max":
case "xhigh": return "HIGH";
default: return;
}
}
function normalizeGemma4ThinkingLevel(value) {
if (typeof value !== "string") return;
switch (value.trim().toUpperCase()) {
case "MINIMAL":
case "LOW": return "MINIMAL";
case "MEDIUM":
case "HIGH": return "HIGH";
default: return;
}
}
/**
* Normalizes Google thinking config across SDK payload shapes before provider transport.
* @deprecated Google provider-owned stream helper; do not use from third-party plugins.
*/
function sanitizeGoogleThinkingPayload(params) {
if (!params.payload || typeof params.payload !== "object") return;
const payloadObj = params.payload;
sanitizeGoogleThinkingConfigContainer({
container: payloadObj.config,
modelId: params.modelId,
thinkingLevel: params.thinkingLevel
});
sanitizeGoogleThinkingConfigContainer({
container: payloadObj.generationConfig,
modelId: params.modelId,
thinkingLevel: params.thinkingLevel
});
}
function sanitizeGoogleThinkingConfigContainer(params) {
if (!params.container || typeof params.container !== "object") return;
const configObj = params.container;
const thinkingConfig = configObj.thinkingConfig;
if (!thinkingConfig || typeof thinkingConfig !== "object") return;
const thinkingConfigObj = thinkingConfig;
if (typeof params.modelId === "string" && isGemma4Model(params.modelId)) {
const normalizedThinkingLevel = normalizeGemma4ThinkingLevel(thinkingConfigObj.thinkingLevel);
const explicitMappedLevel = mapThinkLevelToGemma4ThinkingLevel(params.thinkingLevel);
const disabledViaBudget = typeof thinkingConfigObj.thinkingBudget === "number" && thinkingConfigObj.thinkingBudget <= 0;
const hadThinkingBudget = thinkingConfigObj.thinkingBudget !== void 0;
delete thinkingConfigObj.thinkingBudget;
if (params.thinkingLevel === "off" || disabledViaBudget && explicitMappedLevel === void 0 && !normalizedThinkingLevel) {
delete thinkingConfigObj.thinkingLevel;
if (Object.keys(thinkingConfigObj).length === 0) delete configObj.thinkingConfig;
return;
}
const mappedLevel = explicitMappedLevel ?? normalizedThinkingLevel ?? (hadThinkingBudget ? "MINIMAL" : void 0);
if (mappedLevel) thinkingConfigObj.thinkingLevel = mappedLevel;
return;
}
const thinkingBudget = thinkingConfigObj.thinkingBudget;
if (params.thinkingLevel === "adaptive" && typeof params.modelId === "string" && isGoogleGemini25ThinkingBudgetModel(params.modelId)) {
delete thinkingConfigObj.thinkingLevel;
thinkingConfigObj.thinkingBudget = -1;
return;
}
if (params.thinkingLevel === "adaptive" && typeof params.modelId === "string" && isGoogleGemini3ThinkingLevelModel(params.modelId)) {
delete thinkingConfigObj.thinkingBudget;
delete thinkingConfigObj.thinkingLevel;
if (Object.keys(thinkingConfigObj).length === 0) delete configObj.thinkingConfig;
return;
}
if (typeof params.modelId === "string" && isGoogleGemini3ThinkingLevelModel(params.modelId)) {
const mappedLevel = resolveGoogleGemini3ThinkingLevel({
modelId: params.modelId,
thinkingLevel: params.thinkingLevel,
thinkingBudget: typeof thinkingBudget === "number" ? thinkingBudget : void 0
});
delete thinkingConfigObj.thinkingBudget;
if (mappedLevel) thinkingConfigObj.thinkingLevel = mappedLevel;
if (Object.keys(thinkingConfigObj).length === 0) delete configObj.thinkingConfig;
return;
}
if (stripInvalidGoogleThinkingBudget({
thinkingConfig: thinkingConfigObj,
modelId: params.modelId
})) {
if (Object.keys(thinkingConfigObj).length === 0) delete configObj.thinkingConfig;
return;
}
if (typeof thinkingBudget !== "number" || thinkingBudget >= 0) return;
delete thinkingConfigObj.thinkingBudget;
if (Object.keys(thinkingConfigObj).length === 0) delete configObj.thinkingConfig;
}
//#endregion
//#region src/plugin-sdk/provider-stream-event-normalization.ts
const STREAM_EVENT_TYPE_RE = /^(?:start|(?:text|thinking|toolcall)_(?:start|delta|end)|done|error)$/;
const STOP_REASON_RE = /^(?:stop|length|toolUse|error|aborted)$/;
function materializeMessage(value, model, stopReason) {
const message = asOptionalObjectRecord(value);
if (message?.role !== "assistant" || !Array.isArray(message.content)) throw new Error("Plain-text tool-call normalization produced an invalid stream event");
message.api = typeof message.api === "string" ? message.api : model.api;
message.provider = typeof message.provider === "string" ? message.provider : model.provider;
message.model = typeof message.model === "string" ? message.model : model.id;
message.usage ??= createEmptyTransportUsage();
message.stopReason = STOP_REASON_RE.test(String(message.stopReason)) ? message.stopReason : stopReason;
message.timestamp = typeof message.timestamp === "number" ? message.timestamp : Date.now();
}
function assertProviderStreamEvent(value, model) {
const event = asOptionalObjectRecord(value);
if (!event || typeof event.type !== "string" || !STREAM_EVENT_TYPE_RE.test(event.type)) throw new Error("Plain-text tool-call normalization produced an invalid stream event");
if (event.type === "done") {
const reason = event.reason === "length" || event.reason === "toolUse" ? event.reason : "stop";
event.reason = reason;
materializeMessage(event.message, model, reason);
return;
}
if (event.type === "error") {
const reason = event.reason === "aborted" ? "aborted" : "error";
event.reason = reason;
materializeMessage(event.error, model, reason);
return;
}
if (event.type === "text_delta" && event.partial === void 0) {
event.contentIndex ??= 0;
return;
}
event.contentIndex ??= 0;
event.partial ??= {
role: "assistant",
content: []
};
materializeMessage(event.partial, model, "stop");
}
//#endregion
//#region src/llm/providers/stream-wrappers/zai.ts
/**
* Inject `tool_stream=true` so tool-call deltas stream in real time.
* Providers can disable this by setting `params.tool_stream=false`.
*
* @deprecated Provider-owned stream helper; do not use from third-party plugins.
*/
function createToolStreamWrapper(baseStreamFn, enabled) {
const underlying = baseStreamFn ?? streamSimple;
return (model, context, options) => {
if (!enabled) return underlying(model, context, options);
return streamWithPayloadPatch(underlying, model, context, options, (payloadObj) => {
payloadObj.tool_stream = true;
});
};
}
//#endregion
//#region src/plugin-sdk/provider-stream-shared.ts
/** Compose stream wrapper factories from left to right around a base stream function. */
function composeProviderStreamWrappers(baseStreamFn, ...wrappers) {
return wrappers.reduce((streamFn, wrapper) => wrapper ? wrapper(streamFn) : streamFn, baseStreamFn);
}
function resolveContextToolNames(context) {
const tools = context.tools;
if (!Array.isArray(tools)) return /* @__PURE__ */ new Set();
const names = tools.map((tool) => {
const record = asOptionalObjectRecord(tool);
return typeof record?.name === "string" && record.name.trim() ? record.name : void 0;
}).filter((name) => Boolean(name));
return new Set(names);
}
function promotePlainTextToolCalls(message, toolNames) {
const messageRecord = asOptionalObjectRecord(message);
if (Array.isArray(messageRecord?.content) && messageRecord.content.some((block) => asOptionalObjectRecord(block)?.type === "toolCall")) return;
return projectStandalonePlainTextToolCallMessage({
allowedToolNames: toolNames,
createToolCallBlock: createPromotedPlainTextToolCallBlock,
isRetainableNonTextBlock: () => true,
message,
resolveProtectedRanges: findCodeRegions
});
}
function createProviderToolNameMatcher(toolNames) {
return {
hasExactName: (name) => toolNames.has(name),
hasNamePrefix: (prefix) => {
for (const toolName of toolNames) if (toolName.startsWith(prefix)) return true;
return false;
}
};
}
function normalizeProviderDoneMessage(message, allowPromotion, toolNames, matcher, preserveEmptyTextBlocks = false) {
const scrubbedMessage = scrubProviderTerminalMessage(message, matcher, preserveEmptyTextBlocks);
if (scrubbedMessage) return {
kind: "scrubbed",
...scrubbedMessage
};
if (!allowPromotion) return;
const promotedMessage = promotePlainTextToolCalls(message, toolNames);
return promotedMessage ? {
kind: "promoted",
...promotedMessage
} : void 0;
}
function scrubProviderTerminalMessage(message, matcher, preserveEmptyTextBlocks = false, forceKnownCandidates = false) {
return projectScrubbedPlainTextToolCallMessage({
forceKnownCandidates,
matcher,
message,
preserveEmptyTextBlocks,
resolveProtectedRanges: findCodeRegions
});
}
function wrapPlainTextToolCallStream(source, context, model) {
const toolNames = resolveContextToolNames(context);
if (toolNames.size === 0) return source;
const matcher = createProviderToolNameMatcher(toolNames);
const output = (0, event_stream_exports.createAssistantMessageEventStream)();
(async () => {
try {
const normalizedEvents = normalizePlainTextToolCallStreamEvents(source, {
createPromotedToolCallEvents: createPromotedPlainTextToolCallEvents,
matcher,
normalizeTerminalMessage: ({ allowPromotion, message, preserveEmptyTextBlocks }) => normalizeProviderDoneMessage(message, allowPromotion, toolNames, matcher, preserveEmptyTextBlocks),
protectedRangesFenceCompatible: true,
resolveProtectedRanges: findCodeRegions,
stopAfterDone: true
});
for await (const normalizedEvent of normalizedEvents) {
assertProviderStreamEvent(normalizedEvent, model);
output.push(normalizedEvent);
}
} catch (error) {
output.push({
type: "error",
reason: "error",
error: {
role: "assistant",
content: [],
api: model.api,
provider: model.provider,
model: model.id,
usage: createEmptyTransportUsage(),
stopReason: "error",
errorMessage: error instanceof Error ? error.message : String(error),
timestamp: Date.now()
}
});
} finally {
output.end();
}
})();
return output;
}
/**
* Provider stream wrapper for local/proxy providers that sometimes emit a
* standalone textual tool-call block even when native tool calling is enabled.
*/
function createPlainTextToolCallCompatWrapper(baseStreamFn) {
const underlying = baseStreamFn ?? streamSimple;
return (model, context, options) => {
const maybeStream = underlying(model, context, options);
if (maybeStream && typeof maybeStream === "object" && "then" in maybeStream) return Promise.resolve(maybeStream).then((stream) => wrapPlainTextToolCallStream(stream, context, model));
return wrapPlainTextToolCallStream(maybeStream, context, model);
};
}
/** @deprecated Bundled provider stream helper; do not use from third-party plugins. */
function defaultToolStreamExtraParams(extraParams) {
if (extraParams?.tool_stream !== void 0) return extraParams;
return {
...extraParams,
tool_stream: true
};
}
/** Wrap a provider stream so callers can patch the outbound provider payload once. */
function createPayloadPatchStreamWrapper(baseStreamFn, patchPayload, wrapperOptions) {
const underlying = baseStreamFn ?? streamSimple;
return (model, context, options) => {
if (wrapperOptions?.shouldPatch && !wrapperOptions.shouldPatch({
model,
context,
options
})) return underlying(model, context, options);
return streamWithPayloadPatch(underlying, model, context, options, (payload) => patchPayload({
payload,
model,
context,
options
}));
};
}
/**
* Applies explicit disabled-thinking intent to OpenAI-compatible Chat
* Completions payloads without changing enabled reasoning levels.
*/
function createOpenAICompatibleCompletionsThinkingOffWrapper(baseStreamFn, thinkingLevel, sourceApi) {
const underlying = baseStreamFn ?? streamSimple;
return (model, context, options) => {
if ((options?.reasoning ?? thinkingLevel) !== "off" || (sourceApi ?? model.api) !== "openai-completions") return underlying(model, context, options);
return streamWithPayloadPatch(underlying, model, context, options, (payload) => {
if (!("reasoning_effort" in payload)) return;
const disabled = resolveOpenAIReasoningEffortForModel({
model,
effort: "off",
fallbackMap: resolveOpenAIReasoningEffortMap({
provider: model.provider,
id: model.id,
compat: model.compat
})
});
if (disabled) payload.reasoning_effort = disabled;
else delete payload.reasoning_effort;
});
};
}
function isAnthropicThinkingEnabled(payload) {
const thinking = payload.thinking;
if (!thinking || typeof thinking !== "object") return false;
return thinking.type !== "disabled";
}
function assistantMessageHasAnthropicToolUse(message) {
if (Array.isArray(message.tool_calls) && message.tool_calls.length > 0) return true;
const content = message.content;
if (!Array.isArray(content)) return false;
return content.some((block) => block && typeof block === "object" && (block.type === "tool_use" || block.type === "toolCall"));
}
/** Removes trailing assistant prefills while preserving assistant tool calls. */
function stripTrailingAssistantPrefillMessages(payload) {
if (!Array.isArray(payload.messages)) return 0;
let stripped = 0;
while (payload.messages.length > 0) {
const finalMessage = payload.messages[payload.messages.length - 1];
if (!finalMessage || typeof finalMessage !== "object") break;
const message = finalMessage;
if (message.role !== "assistant" || assistantMessageHasAnthropicToolUse(message)) break;
payload.messages.pop();
stripped += 1;
}
return stripped;
}
/** @deprecated Anthropic-family provider stream helper; do not use from third-party plugins. */
function stripTrailingAnthropicAssistantPrefillWhenThinking(payload) {
if (!isAnthropicThinkingEnabled(payload)) return 0;
return stripTrailingAssistantPrefillMessages(payload);
}
/** @deprecated Anthropic-family provider stream helper; do not use from third-party plugins. */
function createAnthropicThinkingPrefillPayloadWrapper(baseStreamFn, onStripped, wrapperOptions) {
return createPayloadPatchStreamWrapper(baseStreamFn, ({ payload }) => {
const stripped = stripTrailingAnthropicAssistantPrefillWhenThinking(payload);
if (stripped > 0) onStripped?.(stripped);
}, wrapperOptions);
}
/** @deprecated OpenAI-compatible provider stream helper; do not use from third-party plugins. */
function isOpenAICompatibleThinkingEnabled(params) {
const options = params.options ?? {};
const raw = options.reasoningEffort ?? options.reasoning ?? params.thinkingLevel ?? "high";
if (typeof raw !== "string") return true;
const normalized = raw.trim().toLowerCase();
return normalized !== "off" && normalized !== "none";
}
/** Applies the shared reasoning payload policy used by OpenAI-compatible proxy providers. */
function normalizeOpenAICompatibleReasoningPayload(payload, thinkingLevel) {
delete payload.reasoning_effort;
if (!thinkingLevel || thinkingLevel === "off") return;
const existingReasoning = payload.reasoning;
if (existingReasoning && typeof existingReasoning === "object" && !Array.isArray(existingReasoning)) {
const reasoning = existingReasoning;
if (!("max_tokens" in reasoning) && !("effort" in reasoning)) reasoning.effort = mapThinkingLevelToReasoningEffort(thinkingLevel);
} else if (!existingReasoning) payload.reasoning = { effort: mapThinkingLevelToReasoningEffort(thinkingLevel) };
}
/** Applies Qwen chat-template thinking flags without discarding provider-specific kwargs. */
function setQwenChatTemplateThinking(payload, enabled) {
const existing = payload.chat_template_kwargs;
if (existing && typeof existing === "object" && !Array.isArray(existing)) {
const next = {
...existing,
enable_thinking: enabled
};
if (!Object.hasOwn(next, "preserve_thinking")) next.preserve_thinking = true;
payload.chat_template_kwargs = next;
return;
}
payload.chat_template_kwargs = {
enable_thinking: enabled,
preserve_thinking: true
};
}
function isDisabledDeepSeekV4ThinkingLevel(thinkingLevel) {
const normalized = typeof thinkingLevel === "string" ? thinkingLevel.toLowerCase() : "";
return normalized === "off" || normalized === "none";
}
function resolveDeepSeekV4ReasoningEffort(thinkingLevel) {
return thinkingLevel === "xhigh" || thinkingLevel === "max" ? "max" : "high";
}
/** Normalizes assistant reasoning replay shared by OpenAI-compatible provider families. */
function normalizeOpenAICompatibleReasoningReplay(payload, params) {
if (!Array.isArray(payload.messages)) return;
for (const message of payload.messages) {
if (!message || typeof message !== "object") continue;
const record = message;
if (!params.thinkingEnabled) {
if (!params.stripAssistantMessagesOnly || record.role === "assistant") delete record.reasoning_content;
continue;
}
if (record.role !== "assistant" || params.shouldBackfillAssistantMessage && !params.shouldBackfillAssistantMessage(record)) continue;
if (!("reasoning_content" in record) || params.replaceNullReasoningContent && record.reasoning_content == null) record.reasoning_content = "";
}
}
/** @deprecated DeepSeek provider stream helper; do not use from third-party plugins. */
function createDeepSeekV4OpenAICompatibleThinkingWrapper(params) {
if (!params.baseStreamFn) return;
const underlying = params.baseStreamFn;
const resolveReasoningEffort = params.resolveReasoningEffort ?? resolveDeepSeekV4ReasoningEffort;
return (model, context, options) => {
if (!params.shouldPatchModel(model)) return underlying(model, context, options);
const thinkingLevel = options?.reasoning ?? params.thinkingLevel;
return streamWithPayloadPatch(underlying, model, context, options, (payload) => {
if (isDisabledDeepSeekV4ThinkingLevel(thinkingLevel)) {
payload.thinking = { type: "disabled" };
delete payload.reasoning_effort;
delete payload.reasoning;
normalizeOpenAICompatibleReasoningReplay(payload, { thinkingEnabled: false });
return;
}
payload.thinking = { type: "enabled" };
payload.reasoning_effort = resolveReasoningEffort(thinkingLevel);
normalizeOpenAICompatibleReasoningReplay(payload, {
thinkingEnabled: true,
shouldBackfillAssistantMessage: params.shouldBackfillAssistantReasoningContent
});
});
};
}
function promoteThinkingOnlyFinalOutputToText(message) {
if (!message || typeof message !== "object") return;
const record = message;
if (record.stopReason !== "stop" && record.stopReason !== "length") return;
if (!Array.isArray(record.content) || record.content.length === 0) return;
let hasVisibleText = false;
let hasToolCall = false;
let hasVisibleThinking = false;
for (const block of record.content) {
if (!block || typeof block !== "object") continue;
const typedBlock = block;
if (typedBlock.type === "text" && typeof typedBlock.text === "string" && typedBlock.text.trim()) hasVisibleText = true;
if (typedBlock.type === "toolCall" || typedBlock.type === "tool_use") hasToolCall = true;
if (typedBlock.type === "thinking" && typeof typedBlock.thinking === "string" && typedBlock.thinking.trim()) hasVisibleThinking = true;
}
if (hasVisibleText || hasToolCall || !hasVisibleThinking) return;
record.content = record.content.map((block) => {
if (!block || typeof block !== "object") return block;
const typedBlock = block;
if (typedBlock.type !== "thinking" || typeof typedBlock.thinking !== "string" || !typedBlock.thinking.trim()) return block;
return {
type: "text",
text: typedBlock.thinking
};
});
}
/** Mutate streamed and final message objects without replacing or buffering events. */
function transformProviderStreamMessages(stream, transformMessage) {
const originalResult = stream.result.bind(stream);
stream.result = async () => {
const message = await originalResult();
transformMessage(message);
return message;
};
const originalAsyncIterator = stream[Symbol.asyncIterator].bind(stream);
stream[Symbol.asyncIterator] = function() {
const iterator = originalAsyncIterator();
return {
async next() {
const result = await iterator.next();
if (!result.done && result.value && typeof result.value === "object") {
const event = result.value;
transformMessage(event.partial);
transformMessage(event.message);
}
return result;
},
async return(value) {
return iterator.return?.(value) ?? {
done: true,
value: void 0
};
},
async throw(error) {
return iterator.throw?.(error) ?? {
done: true,
value: void 0
};
},
[Symbol.asyncIterator]() {
return this;
}
};
};
return stream;
}
/** @deprecated OpenAI-compatible provider stream helper; do not use from third-party plugins. */
function createThinkingOnlyFinalTextWrapper(params) {
if (!params.baseStreamFn) return;
const underlying = params.baseStreamFn;
return (model, context, options) => {
const maybeStream = underlying(model, context, options);
if (!params.shouldPatchModel(model)) return maybeStream;
if (maybeStream && typeof maybeStream === "object" && "then" in maybeStream) return Promise.resolve(maybeStream).then((stream) => transformProviderStreamMessages(stream, promoteThinkingOnlyFinalOutputToText));
return transformProviderStreamMessages(maybeStream, promoteThinkingOnlyFinalOutputToText);
};
}
/** @deprecated Google provider-owned stream helper; do not use from third-party plugins. */
function createGoogleThinkingPayloadWrapper(baseStreamFn, thinkingLevel) {
return createPayloadPatchStreamWrapper(baseStreamFn, ({ payload, model }) => {
if (model.api === "google-generative-ai") sanitizeGoogleThinkingPayload({
payload,
modelId: model.id,
thinkingLevel
});
});
}
/** @deprecated Google provider-owned stream helper; do not use from third-party plugins. */
function createGoogleThinkingStreamWrapper(ctx) {
return createGoogleThinkingPayloadWrapper(ctx.streamFn, ctx.thinkingLevel);
}
//#endregion
export { stripTrailingAssistantPrefillMessages as A, mapThinkingLevelToReasoningEffort as B, onLlmRequestActivity$1 as C, resolveAnthropicThinkingEffort as D, resolveAnthropicServerCompactionPlan$1 as E, isGoogleGemini25ThinkingBudgetModel as F, isGoogleThinkingRequiredModel as I, resolveGoogleGemini3ThinkingLevel as L, createToolStreamWrapper as M, applyAnthropicEphemeralCacheControlMarkers as N, setQwenChatTemplateThinking as O, resolveAnthropicEphemeralCacheControl as P, sanitizeGoogleThinkingPayload as R, notifyLlmRequestActivity$1 as S, resolveAnthropicPayloadPolicy as T, isGoogleGemini3ProModel$1 as _, createAnthropicThinkingPrefillPayloadWrapper as a, normalizeOpenAICompatibleReasoningPayload as b, createGoogleThinkingPayloadWrapper as c, createPayloadPatchStreamWrapper as d, createPlainTextToolCallCompatWrapper as f, isGoogleGemini3FlashModel$1 as g, isAnthropicOAuthApiKey as h, composeProviderStreamWrappers as i, transformProviderStreamMessages as j, stripTrailingAnthropicAssistantPrefillWhenThinking as k, createGoogleThinkingStreamWrapper as l, defaultToolStreamExtraParams as m, applyAnthropicRefusal as n, createDeepSeekV4OpenAICompatibleThinkingWrapper as o, createThinkingOnlyFinalTextWrapper as p, applyCompletionsAnthropicCacheControl$1 as r, createDeferredEventBuffer as s, applyAnthropicPayloadPolicyToParams as t, createOpenAICompatibleCompletionsThinkingOffWrapper as u, isGoogleGemini3ThinkingLevelModel$1 as v, projectCopilotRequestFacts$1 as w, normalizeOpenAICompatibleReasoningReplay as x, isOpenAICompatibleThinkingEnabled as y, stripInvalidGoogleThinkingBudget as z };