openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
138 lines (137 loc) • 4.82 kB
JavaScript
import { n as validateJsonSchemaValue } from "../../schema-validator-fW6S83H8.mjs";
import { x as createAssistantMessageEventStream } from "../../llm-CJ3KKVO3.mjs";
import { t as buildAssistantMessage } from "../../stream-message-shared-CYuIJ_XF.mjs";
import "../../json-schema-runtime-B4A5hjgp.mjs";
import { r as quoteUnsafeIntegerLiterals } from "../../json-unsafe-integers-BeeNmB5X.mjs";
import { d as failTransportStream, o as createEmptyTransportUsage } from "../../provider-transport-runtime-DtxA52dc.mjs";
//#region extensions/apple-fm/stream.ts
/** Native tools propose calls; the OpenClaw agent loop validates and executes them. */
function createAppleFmStream(native) {
return (model, context, options) => {
const stream = createAssistantMessageEventStream();
const message = buildAssistantMessage({
model,
content: [],
usage: createEmptyTransportUsage(),
stopReason: "stop"
});
stream.push({
type: "start",
partial: message
});
(async () => {
try {
options?.signal?.throwIfAborted();
const responseFormat = options?.responseFormat ? structuredClone(options.responseFormat) : void 0;
const request = {
systemPrompt: context.systemPrompt,
messages: context.messages,
tools: context.tools ?? [],
maxTokens: options?.maxTokens ?? model.maxTokens,
temperature: options?.temperature,
responseFormat: responseFormat ? structuredClone(responseFormat) : void 0
};
const payload = await options?.onPayload?.(request, model) ?? request;
if (!payload || typeof payload !== "object") throw new Error("Apple Foundation Models requires an object request.");
options?.signal?.throwIfAborted();
const result = await native.run(payload, { signal: options?.signal });
options?.signal?.throwIfAborted();
if (responseFormat && result.toolCalls.length === 0) {
const unsafeNumberMessage = "Apple Foundation Models returned an invalid structured response: an unsafe numeric value cannot be validated without losing precision.";
if (quoteUnsafeIntegerLiterals(result.text) !== result.text) throw new Error(unsafeNumberMessage);
let value;
try {
value = JSON.parse(result.text, (_key, parsedValue) => {
if (typeof parsedValue === "number" && (!Number.isFinite(parsedValue) || Number.isInteger(parsedValue) && !Number.isSafeInteger(parsedValue))) throw new Error(unsafeNumberMessage);
return parsedValue;
});
} catch (error) {
if (!(error instanceof SyntaxError)) throw error;
}
if (value === void 0) throw new Error("Apple Foundation Models returned an invalid structured response: malformed JSON.");
const validation = validateJsonSchemaValue({
schema: responseFormat,
cacheKey: "apple-fm.structured-response",
value,
applyDefaults: false
});
if (!validation.ok) throw new Error(`Apple Foundation Models returned an invalid structured response at ${validation.errors.map((error) => error.path).join(", ")}.`);
}
message.usage.input = result.inputTokens;
message.usage.output = result.outputTokens;
message.usage.totalTokens = result.inputTokens + result.outputTokens;
message.usage.cacheTelemetry = { state: "unavailable" };
message.usage.contextUsage = {
state: "available",
promptTokens: result.inputTokens,
totalTokens: message.usage.totalTokens
};
if (result.text) {
message.content.push({
type: "text",
text: result.text
});
stream.push({
type: "text_start",
contentIndex: 0,
partial: message
});
stream.push({
type: "text_delta",
contentIndex: 0,
delta: result.text,
partial: message
});
stream.push({
type: "text_end",
contentIndex: 0,
content: result.text,
partial: message
});
}
for (const call of result.toolCalls) {
const toolCall = {
type: "toolCall",
...call
};
const contentIndex = message.content.length;
message.content.push(toolCall);
stream.push({
type: "toolcall_start",
contentIndex,
partial: message
});
stream.push({
type: "toolcall_delta",
contentIndex,
delta: JSON.stringify(call.arguments),
partial: message
});
stream.push({
type: "toolcall_end",
contentIndex,
toolCall,
partial: message
});
}
message.stopReason = result.toolCalls.length ? "toolUse" : "stop";
stream.push({
type: "done",
reason: message.stopReason,
message
});
stream.end(message);
} catch (error) {
failTransportStream({
stream,
output: message,
error,
signal: options?.signal
});
}
})();
return stream;
};
}
//#endregion
export { createAppleFmStream };