UNPKG

@assistant-ui/react

Version:

React components for AI chat.

156 lines 4.88 kB
// src/runtimes/external-store/external-message-converter.tsx import { useMemo } from "react"; import { ThreadMessageConverter } from "./ThreadMessageConverter.mjs"; import { getExternalStoreMessage, symbolInnerMessage } from "./getExternalStoreMessage.mjs"; import { fromThreadMessageLike } from "./ThreadMessageLike.mjs"; import { getAutoStatus, isAutoStatus } from "./auto-status.mjs"; var joinExternalMessages = (messages) => { const assistantMessage = { role: "assistant", content: [] }; for (const output of messages) { if (output.role === "tool") { const toolCallIdx = assistantMessage.content.findIndex( (c) => c.type === "tool-call" && c.toolCallId === output.toolCallId ); if (toolCallIdx !== -1) { const toolCall = assistantMessage.content[toolCallIdx]; if (output.toolName) { if (toolCall.toolName !== output.toolName) throw new Error( `Tool call name ${output.toolCallId} ${output.toolName} does not match existing tool call ${toolCall.toolName}` ); } assistantMessage.content[toolCallIdx] = { ...toolCall, result: output.result }; } else { throw new Error( `Tool call ${output.toolCallId} ${output.toolName} not found in assistant message` ); } } else { const role = output.role; switch (role) { case "system": case "user": return output; case "assistant": if (assistantMessage.content.length === 0) { assistantMessage.id = output.id; assistantMessage.createdAt ??= output.createdAt; assistantMessage.status ??= output.status; } assistantMessage.content.push(...output.content); break; default: { const unsupportedRole = role; throw new Error(`Unknown message role: ${unsupportedRole}`); } } } } return assistantMessage; }; var chunkExternalMessages = (callbackResults) => { const results = []; let isAssistant = false; let inputs = []; let outputs = []; const flush = () => { if (outputs.length) { results.push({ inputs, outputs }); } inputs = []; outputs = []; }; for (const callbackResult of callbackResults) { for (const output of callbackResult.outputs) { if (!isAssistant || output.role === "user" || output.role === "system") { flush(); } isAssistant = output.role === "assistant" || output.role === "tool"; if (inputs.at(-1) !== callbackResult.input) { inputs.push(callbackResult.input); } outputs.push(output); } } flush(); return results; }; var useExternalMessageConverter = ({ callback, messages, isRunning }) => { const state = useMemo( () => ({ callback, callbackCache: /* @__PURE__ */ new WeakMap(), chunkCache: /* @__PURE__ */ new WeakMap(), converterCache: new ThreadMessageConverter() }), [callback] ); return useMemo(() => { const callbackResults = []; for (const message of messages) { let result = state.callbackCache.get(message); if (!result) { const output = state.callback(message); const outputs = Array.isArray(output) ? output : [output]; result = { input: message, outputs }; state.callbackCache.set(message, result); } callbackResults.push(result); } const chunks = chunkExternalMessages(callbackResults).map((m) => { const key = m.outputs[0]; if (!key) return m; const cached = state.chunkCache.get(key); if (cached && shallowArrayEqual(cached.outputs, m.outputs)) return cached; state.chunkCache.set(key, m); return m; }); return state.converterCache.convertMessages( chunks, (cache, message, idx) => { const isLast = idx === chunks.length - 1; const autoStatus = getAutoStatus(isLast, isRunning); if (cache && (cache.role !== "assistant" || !isAutoStatus(cache.status) || cache.status === autoStatus)) { const inputs = getExternalStoreMessage(cache); if (shallowArrayEqual(inputs, message.inputs)) { return cache; } } const newMessage = fromThreadMessageLike( joinExternalMessages(message.outputs), idx.toString(), autoStatus ); newMessage[symbolInnerMessage] = message.inputs; return newMessage; } ); }, [state, messages, isRunning]); }; var shallowArrayEqual = (a, b) => { if (a.length !== b.length) return false; for (let i = 0; i < a.length; i++) { if (a[i] !== b[i]) return false; } return true; }; export { useExternalMessageConverter }; //# sourceMappingURL=external-message-converter.mjs.map