// src/use-chat.ts import { callChatApi, extractMaxToolInvocationStep, fillMessageParts, generateId as generateIdFunc, getMessageParts, isAssistantMessageWithCompletedToolCalls, prepareAttachmentsForRequest, shouldResubmitMessages, updateToolCallResult } from "@ai-sdk/ui-utils"; import swrv from "swrv"; import { computed, ref, unref } from "vue"; var useSWRV = swrv.default || swrv; var store = {}; var statusStore = {}; function useChat({ api = "/api/chat", id, initialMessages = [], initialInput = "", sendExtraMessageFields, streamProtocol = "data", onResponse, onFinish, onError, credentials, headers: metadataHeaders, body: metadataBody, generateId: generateId2 = generateIdFunc, onToolCall, fetch: fetch2, keepLastMessageOnError = true, maxSteps = 1, experimental_prepareRequestBody } = { maxSteps: 1 }) { var _a, _b; const chatId = id != null ? id : generateId2(); const key = `${api}|${chatId}`; const { data: messagesData, mutate: originalMutate } = useSWRV( key, () => { var _a2; return (_a2 = store[key]) != null ? _a2 : fillMessageParts(initialMessages); } ); const status = (_a = statusStore[chatId]) != null ? _a : statusStore[chatId] = ref( "ready" ); (_b = messagesData.value) != null ? _b : messagesData.value = fillMessageParts(initialMessages); const mutate = (data) => { store[key] = data; return originalMutate(); }; const messages = messagesData; const error = ref(void 0); const streamData = ref(void 0); let abortController = null; async function triggerRequest(messagesSnapshot, { data, headers, body } = {}) { var _a2, _b2, _c; error.value = void 0; status.value = "submitted"; const messageCount = messages.value.length; const maxStep = extractMaxToolInvocationStep( (_a2 = messages.value[messages.value.length - 1]) == null ? void 0 : _a2.toolInvocations ); try { abortController = new AbortController(); const previousMessages = fillMessageParts(messagesSnapshot); const chatMessages = previousMessages; mutate(chatMessages); const existingData = (_b2 = streamData.value) != null ? _b2 : []; const constructedMessagesPayload = sendExtraMessageFields ? chatMessages : chatMessages.map( ({ role, content, experimental_attachments, data: data2, annotations, toolInvocations, parts }) => ({ role, content, ...experimental_attachments !== void 0 && { experimental_attachments }, ...data2 !== void 0 && { data: data2 }, ...annotations !== void 0 && { annotations }, ...toolInvocations !== void 0 && { toolInvocations }, ...parts !== void 0 && { parts } }) ); await callChatApi({ api, body: (_c = experimental_prepareRequestBody == null ? void 0 : experimental_prepareRequestBody({ id: chatId, messages: chatMessages, requestData: data, requestBody: body })) != null ? _c : { id: chatId, messages: constructedMessagesPayload, data, ...unref(metadataBody), // Use unref to unwrap the ref value ...body }, streamProtocol, headers: { ...metadataHeaders, ...headers }, abortController: () => abortController, credentials, onResponse, onUpdate({ message, data: data2, replaceLastMessage }) { status.value = "streaming"; mutate([ ...replaceLastMessage ? chatMessages.slice(0, chatMessages.length - 1) : chatMessages, message ]); if (data2 == null ? void 0 : data2.length) { streamData.value = [...existingData, ...data2]; } }, onFinish, restoreMessagesOnFailure() { if (!keepLastMessageOnError) { mutate(previousMessages); } }, generateId: generateId2, onToolCall, fetch: fetch2, // enabled use of structured clone in processChatResponse: lastMessage: recursiveToRaw(chatMessages[chatMessages.length - 1]) }); status.value = "ready"; } catch (err) { if (err.name === "AbortError") { abortController = null; status.value = "ready"; return null; } if (onError && err instanceof Error) { onError(err); } error.value = err; status.value = "error"; } finally { abortController = null; } if (shouldResubmitMessages({ originalMaxToolInvocationStep: maxStep, originalMessageCount: messageCount, maxSteps, messages: messages.value })) { await triggerRequest(messages.value); } } const append = async (message, options) => { var _a2, _b2, _c; const attachmentsForRequest = await prepareAttachmentsForRequest( (_a2 = options == null ? void 0 : options.experimental_attachments) != null ? _a2 : message.experimental_attachments ); return triggerRequest( messages.value.concat({ ...message, id: (_b2 = message.id) != null ? _b2 : generateId2(), createdAt: (_c = message.createdAt) != null ? _c : /* @__PURE__ */ new Date(), experimental_attachments: attachmentsForRequest.length > 0 ? attachmentsForRequest : void 0, parts: getMessageParts(message) }), options ); }; const reload = async (options) => { const messagesSnapshot = messages.value; if (messagesSnapshot.length === 0) return null; const lastMessage = messagesSnapshot[messagesSnapshot.length - 1]; if (lastMessage.role === "assistant") { return triggerRequest(messagesSnapshot.slice(0, -1), options); } return triggerRequest(messagesSnapshot, options); }; const stop = () => { if (abortController) { abortController.abort(); abortController = null; } }; const setMessages = (messagesArg) => { if (typeof messagesArg === "function") { messagesArg = messagesArg(messages.value); } mutate(fillMessageParts(messagesArg)); }; const setData = (dataArg) => { if (typeof dataArg === "function") { dataArg = dataArg(streamData.value); } streamData.value = dataArg; }; const input = ref(initialInput); const handleSubmit = async (event, options = {}) => { var _a2; (_a2 = event == null ? void 0 : event.preventDefault) == null ? void 0 : _a2.call(event); const inputValue = input.value; if (!inputValue && !options.allowEmptySubmit) return; const attachmentsForRequest = await prepareAttachmentsForRequest( options.experimental_attachments ); triggerRequest( messages.value.concat({ id: generateId2(), createdAt: /* @__PURE__ */ new Date(), content: inputValue, role: "user", experimental_attachments: attachmentsForRequest.length > 0 ? attachmentsForRequest : void 0, parts: [{ type: "text", text: inputValue }] }), options ); input.value = ""; }; const addToolResult = ({ toolCallId, result }) => { const currentMessages = messages.value; updateToolCallResult({ messages: currentMessages, toolCallId, toolResult: result }); mutate(currentMessages); if (status.value === "submitted" || status.value === "streaming") { return; } const lastMessage = currentMessages[currentMessages.length - 1]; if (isAssistantMessageWithCompletedToolCalls(lastMessage)) { triggerRequest(currentMessages); } }; return { id: chatId, messages, append, error, reload, stop, setMessages, input, handleSubmit, isLoading: computed( () => status.value === "submitted" || status.value === "streaming" ), status, data: streamData, setData, addToolResult }; } function recursiveToRaw(inputValue) { if (Array.isArray(inputValue)) { return [...inputValue.map(recursiveToRaw)]; } else if (typeof inputValue === "object" && inputValue !== null) { const clone = {}; for (const [key, value] of Object.entries(inputValue)) { clone[key] = recursiveToRaw(value); } return clone; } else { return inputValue; } } // src/use-completion.ts import { callCompletionApi } from "@ai-sdk/ui-utils"; import swrv2 from "swrv"; import { ref as ref2, unref as unref2 } from "vue"; var uniqueId = 0; var useSWRV2 = swrv2.default || swrv2; var store2 = {}; function useCompletion({ api = "/api/completion", id, initialCompletion = "", initialInput = "", credentials, headers, body, streamProtocol, onResponse, onFinish, onError, fetch: fetch2 } = {}) { var _a; const completionId = id || `completion-${uniqueId++}`; const key = `${api}|${completionId}`; const { data, mutate: originalMutate } = useSWRV2( key, () => store2[key] || initialCompletion ); const { data: isLoading, mutate: mutateLoading } = useSWRV2( `${completionId}-loading`, null ); (_a = isLoading.value) != null ? _a : isLoading.value = false; const { data: streamData, mutate: mutateStreamData } = useSWRV2(`${completionId}-data`, null); data.value || (data.value = initialCompletion); const mutate = (data2) => { store2[key] = data2; return originalMutate(); }; const completion = data; const error = ref2(void 0); let abortController = null; async function triggerRequest(prompt, options) { var _a2; const existingData = (_a2 = streamData.value) != null ? _a2 : []; return callCompletionApi({ api, prompt, credentials, headers: { ...headers, ...options == null ? void 0 : options.headers }, body: { ...unref2(body), ...options == null ? void 0 : options.body }, streamProtocol, setCompletion: mutate, setLoading: (loading) => mutateLoading(() => loading), setError: (err) => { error.value = err; }, setAbortController: (controller) => { abortController = controller; }, onResponse, onFinish, onError, onData: (data2) => { mutateStreamData(() => [...existingData, ...data2 != null ? data2 : []]); }, fetch: fetch2 }); } const complete = async (prompt, options) => { return triggerRequest(prompt, options); }; const stop = () => { if (abortController) { abortController.abort(); abortController = null; } }; const setCompletion = (completion2) => { mutate(completion2); }; const input = ref2(initialInput); const handleSubmit = (event) => { var _a2; (_a2 = event == null ? void 0 : event.preventDefault) == null ? void 0 : _a2.call(event); const inputValue = input.value; return inputValue ? complete(inputValue) : void 0; }; return { completion, complete, error, stop, setCompletion, input, handleSubmit, isLoading, data: streamData }; } // src/use-assistant.ts import { isAbortError } from "@ai-sdk/provider-utils"; import { generateId, processAssistantStream } from "@ai-sdk/ui-utils"; import { computed as computed2, readonly, ref as ref3 } from "vue"; function useAssistant({ api, threadId: threadIdParam, credentials, headers, body, onError }) { const messages = ref3([]); const input = ref3(""); const currentThreadId = ref3(void 0); const status = ref3("awaiting_message"); const error = ref3(void 0); const setMessages = (messageFactory) => { messages.value = messageFactory(messages.value); }; const setCurrentThreadId = (newThreadId) => { currentThreadId.value = newThreadId; messages.value = []; }; const handleInputChange = (event) => { var _a; input.value = (_a = event == null ? void 0 : event.target) == null ? void 0 : _a.value; }; const isSending = computed2(() => status.value === "in_progress"); const abortController = ref3(null); const stop = computed2(() => { return () => { if (abortController.value) { abortController.value.abort(); abortController.value = null; } }; }); const append = async (message, requestOptions) => { var _a, _b, _c, _d; status.value = "in_progress"; const newMessage = { ...message, id: (_a = message.id) != null ? _a : generateId() }; setMessages((messages2) => [...messages2, newMessage]); input.value = ""; const controller = new AbortController(); try { abortController.value = controller; const response = await fetch(api, { method: "POST", headers: { "Content-Type": "application/json", ...headers }, body: JSON.stringify({ ...body, // Message Content message: message.content, // Always Use User Provided Thread ID When Available threadId: (_b = threadIdParam != null ? threadIdParam : currentThreadId.value) != null ? _b : null, // Optional Request Data ...(requestOptions == null ? void 0 : requestOptions.data) && { data: requestOptions == null ? void 0 : requestOptions.data } }), signal: controller.signal, credentials }); if (!response.ok) { throw new Error( (_c = response.statusText) != null ? _c : "An error occurred while sending the message" ); } if (!response.body) { throw new Error("The response body is empty"); } await processAssistantStream({ stream: response.body, onAssistantMessagePart(value) { messages.value = [ ...messages.value, { id: value.id, content: value.content[0].text.value, role: value.role, parts: [] } ]; }, onTextPart(value) { setMessages((messages2) => { const lastMessage = messages2[messages2.length - 1]; lastMessage.content += value; return [...messages2.slice(0, -1), lastMessage]; }); }, onAssistantControlDataPart(value) { if (value.threadId) { currentThreadId.value = value.threadId; } setMessages((messages2) => { const lastMessage = messages2[messages2.length - 1]; lastMessage.id = value.messageId; return [...messages2.slice(0, -1), lastMessage]; }); }, onDataMessagePart(value) { setMessages((messages2) => { var _a2; return [ ...messages2, { id: (_a2 = value.id) != null ? _a2 : generateId(), role: "data", content: "", data: value.data, parts: [] } ]; }); }, onErrorPart(value) { error.value = new Error(value); } }); } catch (err) { if (isAbortError(err) && ((_d = abortController.value) == null ? void 0 : _d.signal.aborted)) { abortController.value = null; return; } if (onError && err instanceof Error) { onError(err); } error.value = err; } finally { abortController.value = null; status.value = "awaiting_message"; } }; const submitMessage = async (event, requestOptions) => { var _a; (_a = event == null ? void 0 : event.preventDefault) == null ? void 0 : _a.call(event); if (!input.value) return; append( { role: "user", content: input.value, parts: [] }, requestOptions ); }; return { append, messages, setMessages, threadId: readonly(currentThreadId), setThreadId: setCurrentThreadId, input, handleInputChange, handleSubmit: submitMessage, isSending, status, error, stop }; } export { useAssistant, useChat, useCompletion }; //# sourceMappingURL=index.mjs.map