UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

99 lines (98 loc) • 5.22 kB
import { c as isRecord } from "./record-coerce-TIsquoVR.mjs"; import { t as createStreamIteratorWrapper } from "./stream-iterator-wrapper-BKsGhmOL.mjs"; //#region src/agents/plugin-text-transforms.ts /** Merge multiple plugin text-transform sets. */ function mergePluginTextTransforms(...transforms) { const input = transforms.flatMap((entry) => entry?.input ?? []); const output = transforms.flatMap((entry) => entry?.output ?? []); if (input.length === 0 && output.length === 0) return; return { ...input.length > 0 ? { input } : {}, ...output.length > 0 ? { output } : {} }; } /** Apply sequential plugin text replacements to one string. */ function applyPluginTextReplacements(text, replacements) { if (!replacements || replacements.length === 0 || !text) return text; let next = text; for (const replacement of replacements) next = next.replace(replacement.from, replacement.to); return next; } function transformContentText(content, replacements) { if (typeof content === "string") return applyPluginTextReplacements(content, replacements); if (Array.isArray(content)) return content.map((entry) => transformContentText(entry, replacements)); if (!isRecord(content)) return content; const next = { ...content }; if (typeof next.text === "string") next.text = applyPluginTextReplacements(next.text, replacements); if (Object.hasOwn(next, "content")) next.content = transformContentText(next.content, replacements); if (next.type === "toolCall" && Object.hasOwn(next, "arguments")) next.arguments = transformToolCallArgumentText(next.arguments, replacements); return next; } function transformMessageText(message, replacements) { if (!isRecord(message)) return message; const next = { ...message }; if (Object.hasOwn(next, "content")) next.content = transformContentText(next.content, replacements); if (typeof next.errorMessage === "string") next.errorMessage = applyPluginTextReplacements(next.errorMessage, replacements); return next; } function transformToolCallArgumentText(value, replacements) { if (typeof value === "string") return applyPluginTextReplacements(value, replacements); if (Array.isArray(value)) return value.map((entry) => transformToolCallArgumentText(entry, replacements)); if (!isRecord(value)) return value; return Object.fromEntries(Object.entries(value).map(([key, entry]) => [key, transformToolCallArgumentText(entry, replacements)])); } /** Apply input text replacements to a stream context. */ function transformStreamContextText(context, replacements, options) { if (!replacements || replacements.length === 0) return context; return { ...context, systemPrompt: options?.systemPrompt !== false && typeof context.systemPrompt === "string" ? applyPluginTextReplacements(context.systemPrompt, replacements) : context.systemPrompt, messages: Array.isArray(context.messages) ? context.messages.map((message) => transformMessageText(message, replacements)) : context.messages }; } function transformAssistantEventText(event, replacements) { if (!isRecord(event) || !replacements || replacements.length === 0) return event; const next = { ...event }; if (next.type === "text_delta" && typeof next.delta === "string") next.delta = applyPluginTextReplacements(next.delta, replacements); if (next.type === "text_end" && typeof next.content === "string") next.content = applyPluginTextReplacements(next.content, replacements); if (next.type === "toolcall_end" && isRecord(next.toolCall) && Object.hasOwn(next.toolCall, "arguments")) next.toolCall = { ...next.toolCall, arguments: transformToolCallArgumentText(next.toolCall.arguments, replacements) }; for (const field of [ "partial", "message", "error" ]) if (Object.hasOwn(next, field)) next[field] = transformMessageText(next[field], replacements); return next; } function wrapStreamTextTransforms(stream, replacements) { if (!replacements || replacements.length === 0) return stream; const originalResult = stream.result.bind(stream); stream.result = async () => transformMessageText(await originalResult(), replacements); const originalAsyncIterator = stream[Symbol.asyncIterator].bind(stream); stream[Symbol.asyncIterator] = function() { return createStreamIteratorWrapper({ iterator: originalAsyncIterator(), next: async (streamIterator) => { const result = await streamIterator.next(); return result.done ? result : { done: false, value: transformAssistantEventText(result.value, replacements) }; } }); }; return stream; } /** Wrap a stream function with plugin input/output text transforms. */ function wrapStreamFnTextTransforms(params) { return (model, context, options) => { const nextContext = transformStreamContextText(context, params.input, { systemPrompt: params.transformSystemPrompt }); const maybeStream = params.streamFn(model, nextContext, options); if (maybeStream && typeof maybeStream === "object" && "then" in maybeStream) return Promise.resolve(maybeStream).then((stream) => wrapStreamTextTransforms(stream, params.output)); return wrapStreamTextTransforms(maybeStream, params.output); }; } //#endregion export { mergePluginTextTransforms as n, wrapStreamFnTextTransforms as r, applyPluginTextReplacements as t };