@ai-sdk/vue 2.0.0-canary.21 → 2.0.0-canary.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # @ai-sdk/vue
2
2
 
3
+ ## 2.0.0-canary.23
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [bedb239]
8
+ - Updated dependencies [507ac1d]
9
+ - Updated dependencies [2b9bbcd]
10
+ - Updated dependencies [f7e8bf4]
11
+ - Updated dependencies [cda32ba]
12
+ - Updated dependencies [50f0362]
13
+ - Updated dependencies [ed675de]
14
+ - Updated dependencies [faf8446]
15
+ - Updated dependencies [64f6d64]
16
+ - ai@5.0.0-canary.24
17
+ - @ai-sdk/provider-utils@3.0.0-canary.19
18
+
19
+ ## 2.0.0-canary.22
20
+
21
+ ### Major Changes
22
+
23
+ - 40acf9b: feat (ui): introduce ChatStore and ChatTransport
24
+
25
+ ### Patch Changes
26
+
27
+ - Updated dependencies [40acf9b]
28
+ - @ai-sdk/provider-utils@3.0.0-canary.18
29
+ - ai@5.0.0-canary.23
30
+
3
31
  ## 2.0.0-canary.21
4
32
 
5
33
  ### Patch Changes
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { UIMessage, CreateUIMessage, ChatRequestOptions, FileUIPart, UseChatOptions, JSONValue, CompletionRequestOptions, UseCompletionOptions } from 'ai';
1
+ import { UIMessage, CreateUIMessage, ChatRequestOptions, FileUIPart, OriginalUseChatOptions, JSONValue, CompletionRequestOptions, UseCompletionOptions } from 'ai';
2
2
  export { CreateUIMessage, UIMessage, UseChatOptions, UseCompletionOptions } from 'ai';
3
3
  import { Ref } from 'vue';
4
4
 
@@ -52,7 +52,7 @@ type UseChatHelpers<MESSAGE_METADATA> = {
52
52
  /** The id of the chat */
53
53
  id: string;
54
54
  };
55
- declare function useChat<MESSAGE_METADATA = unknown>({ api, id, initialMessages, initialInput, streamProtocol, onFinish, onError, credentials, headers: metadataHeaders, body: metadataBody, generateId, onToolCall, fetch, maxSteps, experimental_prepareRequestBody, messageMetadataSchema, }?: UseChatOptions<MESSAGE_METADATA> & {
55
+ declare function useChat<MESSAGE_METADATA = unknown>({ api, id, initialMessages, initialInput, streamProtocol, onFinish, onError, credentials, headers: metadataHeaders, body: metadataBody, generateId, onToolCall, fetch, maxSteps, experimental_prepareRequestBody, messageMetadataSchema, }?: OriginalUseChatOptions<MESSAGE_METADATA> & {
56
56
  /**
57
57
  * Experimental (Vue only). When a function is provided, it will be used
58
58
  * to prepare the request body for the chat API. This can be useful for
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { UIMessage, CreateUIMessage, ChatRequestOptions, FileUIPart, UseChatOptions, JSONValue, CompletionRequestOptions, UseCompletionOptions } from 'ai';
1
+ import { UIMessage, CreateUIMessage, ChatRequestOptions, FileUIPart, OriginalUseChatOptions, JSONValue, CompletionRequestOptions, UseCompletionOptions } from 'ai';
2
2
  export { CreateUIMessage, UIMessage, UseChatOptions, UseCompletionOptions } from 'ai';
3
3
  import { Ref } from 'vue';
4
4
 
@@ -52,7 +52,7 @@ type UseChatHelpers<MESSAGE_METADATA> = {
52
52
  /** The id of the chat */
53
53
  id: string;
54
54
  };
55
- declare function useChat<MESSAGE_METADATA = unknown>({ api, id, initialMessages, initialInput, streamProtocol, onFinish, onError, credentials, headers: metadataHeaders, body: metadataBody, generateId, onToolCall, fetch, maxSteps, experimental_prepareRequestBody, messageMetadataSchema, }?: UseChatOptions<MESSAGE_METADATA> & {
55
+ declare function useChat<MESSAGE_METADATA = unknown>({ api, id, initialMessages, initialInput, streamProtocol, onFinish, onError, credentials, headers: metadataHeaders, body: metadataBody, generateId, onToolCall, fetch, maxSteps, experimental_prepareRequestBody, messageMetadataSchema, }?: OriginalUseChatOptions<MESSAGE_METADATA> & {
56
56
  /**
57
57
  * Experimental (Vue only). When a function is provided, it will be used
58
58
  * to prepare the request body for the chat API. This can be useful for
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/use-chat.ts","../src/use-completion.ts"],"sourcesContent":["export * from './use-chat';\nexport * from './use-completion';\n","import type {\n ChatRequestOptions,\n CreateUIMessage,\n FileUIPart,\n JSONValue,\n UIMessage,\n UseChatOptions,\n} from 'ai';\nimport {\n callChatApi,\n convertFileListToFileUIParts,\n extractMaxToolInvocationStep,\n generateId as generateIdFunc,\n getToolInvocations,\n isAssistantMessageWithCompletedToolCalls,\n shouldResubmitMessages,\n updateToolCallResult,\n} from 'ai';\nimport swrv from 'swrv';\nimport type { Ref } from 'vue';\nimport { ref, unref } from 'vue';\n\nexport type { CreateUIMessage, UIMessage, UseChatOptions };\n\nexport type UseChatHelpers<MESSAGE_METADATA> = {\n /** Current messages in the chat */\n messages: Ref<UIMessage<MESSAGE_METADATA>[]>;\n /** The error object of the API request */\n error: Ref<undefined | Error>;\n /**\n * Append a user message to the chat list. This triggers the API call to fetch\n * the assistant's response.\n */\n append: (\n message: UIMessage<MESSAGE_METADATA> | CreateUIMessage<MESSAGE_METADATA>,\n chatRequestOptions?: ChatRequestOptions,\n ) => Promise<string | null | undefined>;\n /**\n * Reload the last AI chat response for the given chat history. If the last\n * message isn't from the assistant, it will request the API to generate a\n * new response.\n */\n reload: (\n chatRequestOptions?: ChatRequestOptions,\n ) => Promise<string | null | undefined>;\n /**\n * Abort the current request immediately, keep the generated tokens if any.\n */\n stop: () => void;\n /**\n * Update the `messages` state locally. This is useful when you want to\n * edit the messages on the client, and then trigger the `reload` method\n * manually to regenerate the AI response.\n */\n setMessages: (\n messages:\n | UIMessage<MESSAGE_METADATA>[]\n | ((\n messages: UIMessage<MESSAGE_METADATA>[],\n ) => UIMessage<MESSAGE_METADATA>[]),\n ) => void;\n /** The current value of the input */\n input: Ref<string>;\n /** Form submission handler to automatically reset input and append a user message */\n handleSubmit: (\n event?: { preventDefault?: () => void },\n chatRequestOptions?: ChatRequestOptions & {\n files?: FileList | FileUIPart[];\n },\n ) => void;\n\n /**\n * Hook status:\n *\n * - `submitted`: The message has been sent to the API and we're awaiting the start of the response stream.\n * - `streaming`: The response is actively streaming in from the API, receiving chunks of data.\n * - `ready`: The full response has been received and processed; a new user message can be submitted.\n * - `error`: An error occurred during the API request, preventing successful completion.\n */\n status: Ref<'submitted' | 'streaming' | 'ready' | 'error'>;\n\n addToolResult: ({\n toolCallId,\n result,\n }: {\n toolCallId: string;\n result: any;\n }) => void;\n\n /** The id of the chat */\n id: string;\n};\n\n// @ts-expect-error - some issues with the default export of useSWRV\nconst useSWRV = (swrv.default as (typeof import('swrv'))['default']) || swrv;\nconst store: Record<string, UIMessage<any>[] | undefined> = {};\nconst statusStore: Record<\n string,\n Ref<'submitted' | 'streaming' | 'ready' | 'error'>\n> = {};\n\nexport function useChat<MESSAGE_METADATA = unknown>(\n {\n api = '/api/chat',\n id,\n initialMessages = [],\n initialInput = '',\n streamProtocol = 'ui-message',\n onFinish,\n onError,\n credentials,\n headers: metadataHeaders,\n body: metadataBody,\n generateId = generateIdFunc,\n onToolCall,\n fetch,\n maxSteps = 1,\n experimental_prepareRequestBody,\n messageMetadataSchema,\n }: UseChatOptions<MESSAGE_METADATA> & {\n /**\n * Experimental (Vue only). When a function is provided, it will be used\n * to prepare the request body for the chat API. This can be useful for\n * customizing the request body based on the messages and data in the chat.\n *\n * @param id The chat ID\n * @param messages The current messages in the chat\n * @param requestData The data object passed in the chat request\n * @param requestBody The request body object passed in the chat request\n */\n experimental_prepareRequestBody?: (options: {\n id: string;\n messages: UIMessage<MESSAGE_METADATA>[];\n requestData?: JSONValue;\n requestBody?: object;\n }) => unknown;\n } = {\n maxSteps: 1,\n },\n): UseChatHelpers<MESSAGE_METADATA> {\n // Generate a unique ID for the chat if not provided.\n const chatId = id ?? generateId();\n\n const key = `${api}|${chatId}`;\n const { data: messagesData, mutate: originalMutate } = useSWRV<\n UIMessage<MESSAGE_METADATA>[]\n >(key, () => store[key] ?? initialMessages);\n\n const status =\n statusStore[chatId] ??\n (statusStore[chatId] = ref<'submitted' | 'streaming' | 'ready' | 'error'>(\n 'ready',\n ));\n\n // Force the `data` to be `initialMessages` if it's `undefined`.\n messagesData.value ??= initialMessages;\n\n const mutate = (data?: UIMessage<MESSAGE_METADATA>[]) => {\n store[key] = data;\n return originalMutate();\n };\n\n // Because of the `initialData` option, the `data` will never be `undefined`.\n const messages = messagesData as Ref<UIMessage<MESSAGE_METADATA>[]>;\n\n const error = ref<undefined | Error>(undefined);\n\n let abortController: AbortController | null = null;\n\n async function triggerRequest(\n messagesSnapshot: UIMessage<MESSAGE_METADATA>[],\n { headers, body }: ChatRequestOptions = {},\n ) {\n error.value = undefined;\n status.value = 'submitted';\n\n const messageCount = messages.value.length;\n const lastMessage = messages.value.at(-1);\n const maxStep =\n lastMessage != null\n ? extractMaxToolInvocationStep(getToolInvocations(lastMessage))\n : 0;\n\n try {\n abortController = new AbortController();\n\n // Do an optimistic update to show the updated messages immediately:\n mutate(messagesSnapshot);\n\n await callChatApi({\n api,\n body: experimental_prepareRequestBody?.({\n id: chatId,\n messages: messagesSnapshot,\n requestBody: body,\n }) ?? {\n id: chatId,\n messages: messagesSnapshot,\n ...unref(metadataBody), // Use unref to unwrap the ref value\n ...body,\n },\n streamProtocol,\n headers: {\n ...metadataHeaders,\n ...headers,\n },\n abortController: () => abortController,\n credentials,\n onUpdate({ message }) {\n status.value = 'streaming';\n\n const replaceLastMessage =\n message.id === messagesSnapshot[messagesSnapshot.length - 1].id;\n\n mutate([\n ...(replaceLastMessage\n ? messagesSnapshot.slice(0, messagesSnapshot.length - 1)\n : messagesSnapshot),\n message,\n ]);\n },\n onFinish,\n generateId,\n onToolCall,\n fetch,\n // enabled use of structured clone in processChatResponse:\n lastMessage: recursiveToRaw(\n messagesSnapshot[messagesSnapshot.length - 1],\n ),\n messageMetadataSchema,\n });\n\n status.value = 'ready';\n } catch (err) {\n // Ignore abort errors as they are expected.\n if ((err as any).name === 'AbortError') {\n abortController = null;\n status.value = 'ready';\n return null;\n }\n\n if (onError && err instanceof Error) {\n onError(err);\n }\n\n error.value = err as Error;\n status.value = 'error';\n } finally {\n abortController = null;\n }\n\n // auto-submit when all tool calls in the last assistant message have results:\n if (\n shouldResubmitMessages({\n originalMaxToolInvocationStep: maxStep,\n originalMessageCount: messageCount,\n maxSteps,\n messages: messages.value,\n })\n ) {\n await triggerRequest(messages.value);\n }\n }\n\n const append: UseChatHelpers<MESSAGE_METADATA>['append'] = async (\n message,\n options,\n ) => {\n return triggerRequest(\n messages.value.concat({\n ...message,\n id: message.id ?? generateId(),\n parts: message.parts,\n }),\n options,\n );\n };\n\n const reload: UseChatHelpers<MESSAGE_METADATA>['reload'] = async options => {\n const messagesSnapshot = messages.value;\n if (messagesSnapshot.length === 0) return null;\n\n const lastMessage = messagesSnapshot[messagesSnapshot.length - 1];\n if (lastMessage.role === 'assistant') {\n return triggerRequest(messagesSnapshot.slice(0, -1), options);\n }\n\n return triggerRequest(messagesSnapshot, options);\n };\n\n const stop = () => {\n if (abortController) {\n abortController.abort();\n abortController = null;\n }\n };\n\n const setMessages = (\n messagesArg:\n | UIMessage<MESSAGE_METADATA>[]\n | ((\n messages: UIMessage<MESSAGE_METADATA>[],\n ) => UIMessage<MESSAGE_METADATA>[]),\n ) => {\n if (typeof messagesArg === 'function') {\n messagesArg = messagesArg(messages.value);\n }\n\n mutate(messagesArg);\n };\n\n const input = ref(initialInput);\n\n const handleSubmit = async (\n event?: { preventDefault?: () => void },\n options: ChatRequestOptions & { files?: FileList | FileUIPart[] } = {},\n ) => {\n event?.preventDefault?.();\n\n const inputValue = input.value;\n\n const fileParts = Array.isArray(options?.files)\n ? options.files\n : await convertFileListToFileUIParts(options?.files);\n\n if (!inputValue && fileParts.length === 0) return;\n\n triggerRequest(\n messages.value.concat({\n id: generateId(),\n role: 'user',\n parts: [...fileParts, { type: 'text', text: inputValue }],\n }),\n options,\n );\n\n input.value = '';\n };\n\n const addToolResult = ({\n toolCallId,\n result,\n }: {\n toolCallId: string;\n result: unknown;\n }) => {\n const currentMessages = messages.value;\n\n updateToolCallResult({\n messages: currentMessages,\n toolCallId,\n toolResult: result,\n });\n\n mutate(currentMessages);\n\n // when the request is ongoing, the auto-submit will be triggered after the request is finished\n if (status.value === 'submitted' || status.value === 'streaming') {\n return;\n }\n\n // auto-submit when all tool calls in the last assistant message have results:\n const lastMessage = currentMessages[currentMessages.length - 1];\n if (isAssistantMessageWithCompletedToolCalls(lastMessage)) {\n triggerRequest(currentMessages);\n }\n };\n\n return {\n id: chatId,\n messages,\n append,\n error,\n reload,\n stop,\n setMessages,\n input,\n handleSubmit,\n status: status as Ref<'submitted' | 'streaming' | 'ready' | 'error'>,\n addToolResult,\n };\n}\n\n// required for use of structured clone\nfunction recursiveToRaw<T>(inputValue: T): T {\n if (Array.isArray(inputValue)) {\n return [...inputValue.map(recursiveToRaw)] as T;\n } else if (typeof inputValue === 'object' && inputValue !== null) {\n const clone: any = {};\n for (const [key, value] of Object.entries(inputValue)) {\n clone[key] = recursiveToRaw(value);\n }\n return clone;\n } else {\n return inputValue;\n }\n}\n","import type { CompletionRequestOptions, UseCompletionOptions } from 'ai';\nimport { callCompletionApi } from 'ai';\nimport swrv from 'swrv';\nimport type { Ref } from 'vue';\nimport { ref, unref } from 'vue';\n\nexport type { UseCompletionOptions };\n\nexport type UseCompletionHelpers = {\n /** The current completion result */\n completion: Ref<string>;\n /** The error object of the API request */\n error: Ref<undefined | Error>;\n /**\n * Send a new prompt to the API endpoint and update the completion state.\n */\n complete: (\n prompt: string,\n options?: CompletionRequestOptions,\n ) => Promise<string | null | undefined>;\n /**\n * Abort the current API request but keep the generated tokens.\n */\n stop: () => void;\n /**\n * Update the `completion` state locally.\n */\n setCompletion: (completion: string) => void;\n /** The current value of the input */\n input: Ref<string>;\n /**\n * Form submission handler to automatically reset input and append a user message\n * @example\n * ```jsx\n * <form @submit=\"handleSubmit\">\n * <input @change=\"handleInputChange\" v-model=\"input\" />\n * </form>\n * ```\n */\n handleSubmit: (event?: { preventDefault?: () => void }) => void;\n /** Whether the API request is in progress */\n isLoading: Ref<boolean | undefined>;\n};\n\nlet uniqueId = 0;\n\n// @ts-expect-error - some issues with the default export of useSWRV\nconst useSWRV = (swrv.default as (typeof import('swrv'))['default']) || swrv;\nconst store: Record<string, any> = {};\n\nexport function useCompletion({\n api = '/api/completion',\n id,\n initialCompletion = '',\n initialInput = '',\n credentials,\n headers,\n body,\n streamProtocol,\n onFinish,\n onError,\n fetch,\n}: UseCompletionOptions = {}): UseCompletionHelpers {\n // Generate an unique id for the completion if not provided.\n const completionId = id || `completion-${uniqueId++}`;\n\n const key = `${api}|${completionId}`;\n const { data, mutate: originalMutate } = useSWRV<string>(\n key,\n () => store[key] || initialCompletion,\n );\n\n const { data: isLoading, mutate: mutateLoading } = useSWRV<boolean>(\n `${completionId}-loading`,\n null,\n );\n\n isLoading.value ??= false;\n\n // Force the `data` to be `initialCompletion` if it's `undefined`.\n data.value ||= initialCompletion;\n\n const mutate = (data: string) => {\n store[key] = data;\n return originalMutate();\n };\n\n // Because of the `initialData` option, the `data` will never be `undefined`.\n const completion = data as Ref<string>;\n\n const error = ref<undefined | Error>(undefined);\n\n let abortController: AbortController | null = null;\n\n async function triggerRequest(\n prompt: string,\n options?: CompletionRequestOptions,\n ) {\n return callCompletionApi({\n api,\n prompt,\n credentials,\n headers: {\n ...headers,\n ...options?.headers,\n },\n body: {\n ...unref(body),\n ...options?.body,\n },\n streamProtocol,\n setCompletion: mutate,\n setLoading: loading => mutateLoading(() => loading),\n setError: err => {\n error.value = err;\n },\n setAbortController: controller => {\n abortController = controller;\n },\n onFinish,\n onError,\n fetch,\n });\n }\n\n const complete: UseCompletionHelpers['complete'] = async (\n prompt,\n options,\n ) => {\n return triggerRequest(prompt, options);\n };\n\n const stop = () => {\n if (abortController) {\n abortController.abort();\n abortController = null;\n }\n };\n\n const setCompletion = (completion: string) => {\n mutate(completion);\n };\n\n const input = ref(initialInput);\n\n const handleSubmit = (event?: { preventDefault?: () => void }) => {\n event?.preventDefault?.();\n const inputValue = input.value;\n return inputValue ? complete(inputValue) : undefined;\n };\n\n return {\n completion,\n complete,\n error,\n stop,\n setCompletion,\n input,\n handleSubmit,\n isLoading,\n };\n}\n"],"mappings":"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","names":["swrv","generateIdFunc","_a","import_ai","import_swrv","import_vue","useSWRV","swrv","store","data","completion","_a"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/use-chat.ts","../src/use-completion.ts"],"sourcesContent":["export * from './use-chat';\nexport * from './use-completion';\n","import type {\n ChatRequestOptions,\n CreateUIMessage,\n FileUIPart,\n JSONValue,\n OriginalUseChatOptions,\n UIMessage,\n UseChatOptions,\n} from 'ai';\nimport {\n callChatApi,\n convertFileListToFileUIParts,\n extractMaxToolInvocationStep,\n generateId as generateIdFunc,\n getToolInvocations,\n isAssistantMessageWithCompletedToolCalls,\n shouldResubmitMessages,\n updateToolCallResult,\n} from 'ai';\nimport swrv from 'swrv';\nimport type { Ref } from 'vue';\nimport { ref, unref } from 'vue';\n\nexport type { CreateUIMessage, UIMessage, UseChatOptions };\n\nexport type UseChatHelpers<MESSAGE_METADATA> = {\n /** Current messages in the chat */\n messages: Ref<UIMessage<MESSAGE_METADATA>[]>;\n /** The error object of the API request */\n error: Ref<undefined | Error>;\n /**\n * Append a user message to the chat list. This triggers the API call to fetch\n * the assistant's response.\n */\n append: (\n message: UIMessage<MESSAGE_METADATA> | CreateUIMessage<MESSAGE_METADATA>,\n chatRequestOptions?: ChatRequestOptions,\n ) => Promise<string | null | undefined>;\n /**\n * Reload the last AI chat response for the given chat history. If the last\n * message isn't from the assistant, it will request the API to generate a\n * new response.\n */\n reload: (\n chatRequestOptions?: ChatRequestOptions,\n ) => Promise<string | null | undefined>;\n /**\n * Abort the current request immediately, keep the generated tokens if any.\n */\n stop: () => void;\n /**\n * Update the `messages` state locally. This is useful when you want to\n * edit the messages on the client, and then trigger the `reload` method\n * manually to regenerate the AI response.\n */\n setMessages: (\n messages:\n | UIMessage<MESSAGE_METADATA>[]\n | ((\n messages: UIMessage<MESSAGE_METADATA>[],\n ) => UIMessage<MESSAGE_METADATA>[]),\n ) => void;\n /** The current value of the input */\n input: Ref<string>;\n /** Form submission handler to automatically reset input and append a user message */\n handleSubmit: (\n event?: { preventDefault?: () => void },\n chatRequestOptions?: ChatRequestOptions & {\n files?: FileList | FileUIPart[];\n },\n ) => void;\n\n /**\n * Hook status:\n *\n * - `submitted`: The message has been sent to the API and we're awaiting the start of the response stream.\n * - `streaming`: The response is actively streaming in from the API, receiving chunks of data.\n * - `ready`: The full response has been received and processed; a new user message can be submitted.\n * - `error`: An error occurred during the API request, preventing successful completion.\n */\n status: Ref<'submitted' | 'streaming' | 'ready' | 'error'>;\n\n addToolResult: ({\n toolCallId,\n result,\n }: {\n toolCallId: string;\n result: any;\n }) => void;\n\n /** The id of the chat */\n id: string;\n};\n\n// @ts-expect-error - some issues with the default export of useSWRV\nconst useSWRV = (swrv.default as (typeof import('swrv'))['default']) || swrv;\nconst store: Record<string, UIMessage<any>[] | undefined> = {};\nconst statusStore: Record<\n string,\n Ref<'submitted' | 'streaming' | 'ready' | 'error'>\n> = {};\n\nexport function useChat<MESSAGE_METADATA = unknown>(\n {\n api = '/api/chat',\n id,\n initialMessages = [],\n initialInput = '',\n streamProtocol = 'ui-message',\n onFinish,\n onError,\n credentials,\n headers: metadataHeaders,\n body: metadataBody,\n generateId = generateIdFunc,\n onToolCall,\n fetch,\n maxSteps = 1,\n experimental_prepareRequestBody,\n messageMetadataSchema,\n }: OriginalUseChatOptions<MESSAGE_METADATA> & {\n /**\n * Experimental (Vue only). When a function is provided, it will be used\n * to prepare the request body for the chat API. This can be useful for\n * customizing the request body based on the messages and data in the chat.\n *\n * @param id The chat ID\n * @param messages The current messages in the chat\n * @param requestData The data object passed in the chat request\n * @param requestBody The request body object passed in the chat request\n */\n experimental_prepareRequestBody?: (options: {\n id: string;\n messages: UIMessage<MESSAGE_METADATA>[];\n requestData?: JSONValue;\n requestBody?: object;\n }) => unknown;\n } = {\n maxSteps: 1,\n },\n): UseChatHelpers<MESSAGE_METADATA> {\n // Generate a unique ID for the chat if not provided.\n const chatId = id ?? generateId();\n\n const key = `${api}|${chatId}`;\n const { data: messagesData, mutate: originalMutate } = useSWRV<\n UIMessage<MESSAGE_METADATA>[]\n >(key, () => store[key] ?? initialMessages);\n\n const status =\n statusStore[chatId] ??\n (statusStore[chatId] = ref<'submitted' | 'streaming' | 'ready' | 'error'>(\n 'ready',\n ));\n\n // Force the `data` to be `initialMessages` if it's `undefined`.\n messagesData.value ??= initialMessages;\n\n const mutate = (data?: UIMessage<MESSAGE_METADATA>[]) => {\n store[key] = data;\n return originalMutate();\n };\n\n // Because of the `initialData` option, the `data` will never be `undefined`.\n const messages = messagesData as Ref<UIMessage<MESSAGE_METADATA>[]>;\n\n const error = ref<undefined | Error>(undefined);\n\n let abortController: AbortController | null = null;\n\n async function triggerRequest(\n messagesSnapshot: UIMessage<MESSAGE_METADATA>[],\n { headers, body }: ChatRequestOptions = {},\n ) {\n error.value = undefined;\n status.value = 'submitted';\n\n const messageCount = messages.value.length;\n const lastMessage = messages.value.at(-1);\n const maxStep =\n lastMessage != null\n ? extractMaxToolInvocationStep(getToolInvocations(lastMessage))\n : 0;\n\n try {\n abortController = new AbortController();\n\n // Do an optimistic update to show the updated messages immediately:\n mutate(messagesSnapshot);\n\n await callChatApi({\n api,\n body: experimental_prepareRequestBody?.({\n id: chatId,\n messages: messagesSnapshot,\n requestBody: body,\n }) ?? {\n id: chatId,\n messages: messagesSnapshot,\n ...unref(metadataBody), // Use unref to unwrap the ref value\n ...body,\n },\n streamProtocol,\n headers: {\n ...metadataHeaders,\n ...headers,\n },\n abortController: () => abortController,\n credentials,\n onUpdate({ message }) {\n status.value = 'streaming';\n\n const replaceLastMessage =\n message.id === messagesSnapshot[messagesSnapshot.length - 1].id;\n\n mutate([\n ...(replaceLastMessage\n ? messagesSnapshot.slice(0, messagesSnapshot.length - 1)\n : messagesSnapshot),\n message,\n ]);\n },\n onFinish,\n generateId,\n onToolCall,\n fetch,\n // enabled use of structured clone in processChatResponse:\n lastMessage: recursiveToRaw(\n messagesSnapshot[messagesSnapshot.length - 1],\n ),\n messageMetadataSchema,\n });\n\n status.value = 'ready';\n } catch (err) {\n // Ignore abort errors as they are expected.\n if ((err as any).name === 'AbortError') {\n abortController = null;\n status.value = 'ready';\n return null;\n }\n\n if (onError && err instanceof Error) {\n onError(err);\n }\n\n error.value = err as Error;\n status.value = 'error';\n } finally {\n abortController = null;\n }\n\n // auto-submit when all tool calls in the last assistant message have results:\n if (\n shouldResubmitMessages({\n originalMaxToolInvocationStep: maxStep,\n originalMessageCount: messageCount,\n maxSteps,\n messages: messages.value,\n })\n ) {\n await triggerRequest(messages.value);\n }\n }\n\n const append: UseChatHelpers<MESSAGE_METADATA>['append'] = async (\n message,\n options,\n ) => {\n return triggerRequest(\n messages.value.concat({\n ...message,\n id: message.id ?? generateId(),\n parts: message.parts,\n }),\n options,\n );\n };\n\n const reload: UseChatHelpers<MESSAGE_METADATA>['reload'] = async options => {\n const messagesSnapshot = messages.value;\n if (messagesSnapshot.length === 0) return null;\n\n const lastMessage = messagesSnapshot[messagesSnapshot.length - 1];\n if (lastMessage.role === 'assistant') {\n return triggerRequest(messagesSnapshot.slice(0, -1), options);\n }\n\n return triggerRequest(messagesSnapshot, options);\n };\n\n const stop = () => {\n if (abortController) {\n abortController.abort();\n abortController = null;\n }\n };\n\n const setMessages = (\n messagesArg:\n | UIMessage<MESSAGE_METADATA>[]\n | ((\n messages: UIMessage<MESSAGE_METADATA>[],\n ) => UIMessage<MESSAGE_METADATA>[]),\n ) => {\n if (typeof messagesArg === 'function') {\n messagesArg = messagesArg(messages.value);\n }\n\n mutate(messagesArg);\n };\n\n const input = ref(initialInput);\n\n const handleSubmit = async (\n event?: { preventDefault?: () => void },\n options: ChatRequestOptions & { files?: FileList | FileUIPart[] } = {},\n ) => {\n event?.preventDefault?.();\n\n const inputValue = input.value;\n\n const fileParts = Array.isArray(options?.files)\n ? options.files\n : await convertFileListToFileUIParts(options?.files);\n\n if (!inputValue && fileParts.length === 0) return;\n\n triggerRequest(\n messages.value.concat({\n id: generateId(),\n role: 'user',\n parts: [...fileParts, { type: 'text', text: inputValue }],\n }),\n options,\n );\n\n input.value = '';\n };\n\n const addToolResult = ({\n toolCallId,\n result,\n }: {\n toolCallId: string;\n result: unknown;\n }) => {\n const currentMessages = messages.value;\n\n updateToolCallResult({\n messages: currentMessages,\n toolCallId,\n toolResult: result,\n });\n\n mutate(currentMessages);\n\n // when the request is ongoing, the auto-submit will be triggered after the request is finished\n if (status.value === 'submitted' || status.value === 'streaming') {\n return;\n }\n\n // auto-submit when all tool calls in the last assistant message have results:\n const lastMessage = currentMessages[currentMessages.length - 1];\n if (isAssistantMessageWithCompletedToolCalls(lastMessage)) {\n triggerRequest(currentMessages);\n }\n };\n\n return {\n id: chatId,\n messages,\n append,\n error,\n reload,\n stop,\n setMessages,\n input,\n handleSubmit,\n status: status as Ref<'submitted' | 'streaming' | 'ready' | 'error'>,\n addToolResult,\n };\n}\n\n// required for use of structured clone\nfunction recursiveToRaw<T>(inputValue: T): T {\n if (Array.isArray(inputValue)) {\n return [...inputValue.map(recursiveToRaw)] as T;\n } else if (typeof inputValue === 'object' && inputValue !== null) {\n const clone: any = {};\n for (const [key, value] of Object.entries(inputValue)) {\n clone[key] = recursiveToRaw(value);\n }\n return clone;\n } else {\n return inputValue;\n }\n}\n","import type { CompletionRequestOptions, UseCompletionOptions } from 'ai';\nimport { callCompletionApi } from 'ai';\nimport swrv from 'swrv';\nimport type { Ref } from 'vue';\nimport { ref, unref } from 'vue';\n\nexport type { UseCompletionOptions };\n\nexport type UseCompletionHelpers = {\n /** The current completion result */\n completion: Ref<string>;\n /** The error object of the API request */\n error: Ref<undefined | Error>;\n /**\n * Send a new prompt to the API endpoint and update the completion state.\n */\n complete: (\n prompt: string,\n options?: CompletionRequestOptions,\n ) => Promise<string | null | undefined>;\n /**\n * Abort the current API request but keep the generated tokens.\n */\n stop: () => void;\n /**\n * Update the `completion` state locally.\n */\n setCompletion: (completion: string) => void;\n /** The current value of the input */\n input: Ref<string>;\n /**\n * Form submission handler to automatically reset input and append a user message\n * @example\n * ```jsx\n * <form @submit=\"handleSubmit\">\n * <input @change=\"handleInputChange\" v-model=\"input\" />\n * </form>\n * ```\n */\n handleSubmit: (event?: { preventDefault?: () => void }) => void;\n /** Whether the API request is in progress */\n isLoading: Ref<boolean | undefined>;\n};\n\nlet uniqueId = 0;\n\n// @ts-expect-error - some issues with the default export of useSWRV\nconst useSWRV = (swrv.default as (typeof import('swrv'))['default']) || swrv;\nconst store: Record<string, any> = {};\n\nexport function useCompletion({\n api = '/api/completion',\n id,\n initialCompletion = '',\n initialInput = '',\n credentials,\n headers,\n body,\n streamProtocol,\n onFinish,\n onError,\n fetch,\n}: UseCompletionOptions = {}): UseCompletionHelpers {\n // Generate an unique id for the completion if not provided.\n const completionId = id || `completion-${uniqueId++}`;\n\n const key = `${api}|${completionId}`;\n const { data, mutate: originalMutate } = useSWRV<string>(\n key,\n () => store[key] || initialCompletion,\n );\n\n const { data: isLoading, mutate: mutateLoading } = useSWRV<boolean>(\n `${completionId}-loading`,\n null,\n );\n\n isLoading.value ??= false;\n\n // Force the `data` to be `initialCompletion` if it's `undefined`.\n data.value ||= initialCompletion;\n\n const mutate = (data: string) => {\n store[key] = data;\n return originalMutate();\n };\n\n // Because of the `initialData` option, the `data` will never be `undefined`.\n const completion = data as Ref<string>;\n\n const error = ref<undefined | Error>(undefined);\n\n let abortController: AbortController | null = null;\n\n async function triggerRequest(\n prompt: string,\n options?: CompletionRequestOptions,\n ) {\n return callCompletionApi({\n api,\n prompt,\n credentials,\n headers: {\n ...headers,\n ...options?.headers,\n },\n body: {\n ...unref(body),\n ...options?.body,\n },\n streamProtocol,\n setCompletion: mutate,\n setLoading: loading => mutateLoading(() => loading),\n setError: err => {\n error.value = err;\n },\n setAbortController: controller => {\n abortController = controller;\n },\n onFinish,\n onError,\n fetch,\n });\n }\n\n const complete: UseCompletionHelpers['complete'] = async (\n prompt,\n options,\n ) => {\n return triggerRequest(prompt, options);\n };\n\n const stop = () => {\n if (abortController) {\n abortController.abort();\n abortController = null;\n }\n };\n\n const setCompletion = (completion: string) => {\n mutate(completion);\n };\n\n const input = ref(initialInput);\n\n const handleSubmit = (event?: { preventDefault?: () => void }) => {\n event?.preventDefault?.();\n const inputValue = input.value;\n return inputValue ? complete(inputValue) : undefined;\n };\n\n return {\n completion,\n complete,\n error,\n stop,\n setCompletion,\n input,\n handleSubmit,\n isLoading,\n };\n}\n"],"mappings":"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","names":["swrv","generateIdFunc","_a","import_ai","import_swrv","import_vue","useSWRV","swrv","store","data","completion","_a"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/use-chat.ts","../src/use-completion.ts"],"sourcesContent":["import type {\n ChatRequestOptions,\n CreateUIMessage,\n FileUIPart,\n JSONValue,\n UIMessage,\n UseChatOptions,\n} from 'ai';\nimport {\n callChatApi,\n convertFileListToFileUIParts,\n extractMaxToolInvocationStep,\n generateId as generateIdFunc,\n getToolInvocations,\n isAssistantMessageWithCompletedToolCalls,\n shouldResubmitMessages,\n updateToolCallResult,\n} from 'ai';\nimport swrv from 'swrv';\nimport type { Ref } from 'vue';\nimport { ref, unref } from 'vue';\n\nexport type { CreateUIMessage, UIMessage, UseChatOptions };\n\nexport type UseChatHelpers<MESSAGE_METADATA> = {\n /** Current messages in the chat */\n messages: Ref<UIMessage<MESSAGE_METADATA>[]>;\n /** The error object of the API request */\n error: Ref<undefined | Error>;\n /**\n * Append a user message to the chat list. This triggers the API call to fetch\n * the assistant's response.\n */\n append: (\n message: UIMessage<MESSAGE_METADATA> | CreateUIMessage<MESSAGE_METADATA>,\n chatRequestOptions?: ChatRequestOptions,\n ) => Promise<string | null | undefined>;\n /**\n * Reload the last AI chat response for the given chat history. If the last\n * message isn't from the assistant, it will request the API to generate a\n * new response.\n */\n reload: (\n chatRequestOptions?: ChatRequestOptions,\n ) => Promise<string | null | undefined>;\n /**\n * Abort the current request immediately, keep the generated tokens if any.\n */\n stop: () => void;\n /**\n * Update the `messages` state locally. This is useful when you want to\n * edit the messages on the client, and then trigger the `reload` method\n * manually to regenerate the AI response.\n */\n setMessages: (\n messages:\n | UIMessage<MESSAGE_METADATA>[]\n | ((\n messages: UIMessage<MESSAGE_METADATA>[],\n ) => UIMessage<MESSAGE_METADATA>[]),\n ) => void;\n /** The current value of the input */\n input: Ref<string>;\n /** Form submission handler to automatically reset input and append a user message */\n handleSubmit: (\n event?: { preventDefault?: () => void },\n chatRequestOptions?: ChatRequestOptions & {\n files?: FileList | FileUIPart[];\n },\n ) => void;\n\n /**\n * Hook status:\n *\n * - `submitted`: The message has been sent to the API and we're awaiting the start of the response stream.\n * - `streaming`: The response is actively streaming in from the API, receiving chunks of data.\n * - `ready`: The full response has been received and processed; a new user message can be submitted.\n * - `error`: An error occurred during the API request, preventing successful completion.\n */\n status: Ref<'submitted' | 'streaming' | 'ready' | 'error'>;\n\n addToolResult: ({\n toolCallId,\n result,\n }: {\n toolCallId: string;\n result: any;\n }) => void;\n\n /** The id of the chat */\n id: string;\n};\n\n// @ts-expect-error - some issues with the default export of useSWRV\nconst useSWRV = (swrv.default as (typeof import('swrv'))['default']) || swrv;\nconst store: Record<string, UIMessage<any>[] | undefined> = {};\nconst statusStore: Record<\n string,\n Ref<'submitted' | 'streaming' | 'ready' | 'error'>\n> = {};\n\nexport function useChat<MESSAGE_METADATA = unknown>(\n {\n api = '/api/chat',\n id,\n initialMessages = [],\n initialInput = '',\n streamProtocol = 'ui-message',\n onFinish,\n onError,\n credentials,\n headers: metadataHeaders,\n body: metadataBody,\n generateId = generateIdFunc,\n onToolCall,\n fetch,\n maxSteps = 1,\n experimental_prepareRequestBody,\n messageMetadataSchema,\n }: UseChatOptions<MESSAGE_METADATA> & {\n /**\n * Experimental (Vue only). When a function is provided, it will be used\n * to prepare the request body for the chat API. This can be useful for\n * customizing the request body based on the messages and data in the chat.\n *\n * @param id The chat ID\n * @param messages The current messages in the chat\n * @param requestData The data object passed in the chat request\n * @param requestBody The request body object passed in the chat request\n */\n experimental_prepareRequestBody?: (options: {\n id: string;\n messages: UIMessage<MESSAGE_METADATA>[];\n requestData?: JSONValue;\n requestBody?: object;\n }) => unknown;\n } = {\n maxSteps: 1,\n },\n): UseChatHelpers<MESSAGE_METADATA> {\n // Generate a unique ID for the chat if not provided.\n const chatId = id ?? generateId();\n\n const key = `${api}|${chatId}`;\n const { data: messagesData, mutate: originalMutate } = useSWRV<\n UIMessage<MESSAGE_METADATA>[]\n >(key, () => store[key] ?? initialMessages);\n\n const status =\n statusStore[chatId] ??\n (statusStore[chatId] = ref<'submitted' | 'streaming' | 'ready' | 'error'>(\n 'ready',\n ));\n\n // Force the `data` to be `initialMessages` if it's `undefined`.\n messagesData.value ??= initialMessages;\n\n const mutate = (data?: UIMessage<MESSAGE_METADATA>[]) => {\n store[key] = data;\n return originalMutate();\n };\n\n // Because of the `initialData` option, the `data` will never be `undefined`.\n const messages = messagesData as Ref<UIMessage<MESSAGE_METADATA>[]>;\n\n const error = ref<undefined | Error>(undefined);\n\n let abortController: AbortController | null = null;\n\n async function triggerRequest(\n messagesSnapshot: UIMessage<MESSAGE_METADATA>[],\n { headers, body }: ChatRequestOptions = {},\n ) {\n error.value = undefined;\n status.value = 'submitted';\n\n const messageCount = messages.value.length;\n const lastMessage = messages.value.at(-1);\n const maxStep =\n lastMessage != null\n ? extractMaxToolInvocationStep(getToolInvocations(lastMessage))\n : 0;\n\n try {\n abortController = new AbortController();\n\n // Do an optimistic update to show the updated messages immediately:\n mutate(messagesSnapshot);\n\n await callChatApi({\n api,\n body: experimental_prepareRequestBody?.({\n id: chatId,\n messages: messagesSnapshot,\n requestBody: body,\n }) ?? {\n id: chatId,\n messages: messagesSnapshot,\n ...unref(metadataBody), // Use unref to unwrap the ref value\n ...body,\n },\n streamProtocol,\n headers: {\n ...metadataHeaders,\n ...headers,\n },\n abortController: () => abortController,\n credentials,\n onUpdate({ message }) {\n status.value = 'streaming';\n\n const replaceLastMessage =\n message.id === messagesSnapshot[messagesSnapshot.length - 1].id;\n\n mutate([\n ...(replaceLastMessage\n ? messagesSnapshot.slice(0, messagesSnapshot.length - 1)\n : messagesSnapshot),\n message,\n ]);\n },\n onFinish,\n generateId,\n onToolCall,\n fetch,\n // enabled use of structured clone in processChatResponse:\n lastMessage: recursiveToRaw(\n messagesSnapshot[messagesSnapshot.length - 1],\n ),\n messageMetadataSchema,\n });\n\n status.value = 'ready';\n } catch (err) {\n // Ignore abort errors as they are expected.\n if ((err as any).name === 'AbortError') {\n abortController = null;\n status.value = 'ready';\n return null;\n }\n\n if (onError && err instanceof Error) {\n onError(err);\n }\n\n error.value = err as Error;\n status.value = 'error';\n } finally {\n abortController = null;\n }\n\n // auto-submit when all tool calls in the last assistant message have results:\n if (\n shouldResubmitMessages({\n originalMaxToolInvocationStep: maxStep,\n originalMessageCount: messageCount,\n maxSteps,\n messages: messages.value,\n })\n ) {\n await triggerRequest(messages.value);\n }\n }\n\n const append: UseChatHelpers<MESSAGE_METADATA>['append'] = async (\n message,\n options,\n ) => {\n return triggerRequest(\n messages.value.concat({\n ...message,\n id: message.id ?? generateId(),\n parts: message.parts,\n }),\n options,\n );\n };\n\n const reload: UseChatHelpers<MESSAGE_METADATA>['reload'] = async options => {\n const messagesSnapshot = messages.value;\n if (messagesSnapshot.length === 0) return null;\n\n const lastMessage = messagesSnapshot[messagesSnapshot.length - 1];\n if (lastMessage.role === 'assistant') {\n return triggerRequest(messagesSnapshot.slice(0, -1), options);\n }\n\n return triggerRequest(messagesSnapshot, options);\n };\n\n const stop = () => {\n if (abortController) {\n abortController.abort();\n abortController = null;\n }\n };\n\n const setMessages = (\n messagesArg:\n | UIMessage<MESSAGE_METADATA>[]\n | ((\n messages: UIMessage<MESSAGE_METADATA>[],\n ) => UIMessage<MESSAGE_METADATA>[]),\n ) => {\n if (typeof messagesArg === 'function') {\n messagesArg = messagesArg(messages.value);\n }\n\n mutate(messagesArg);\n };\n\n const input = ref(initialInput);\n\n const handleSubmit = async (\n event?: { preventDefault?: () => void },\n options: ChatRequestOptions & { files?: FileList | FileUIPart[] } = {},\n ) => {\n event?.preventDefault?.();\n\n const inputValue = input.value;\n\n const fileParts = Array.isArray(options?.files)\n ? options.files\n : await convertFileListToFileUIParts(options?.files);\n\n if (!inputValue && fileParts.length === 0) return;\n\n triggerRequest(\n messages.value.concat({\n id: generateId(),\n role: 'user',\n parts: [...fileParts, { type: 'text', text: inputValue }],\n }),\n options,\n );\n\n input.value = '';\n };\n\n const addToolResult = ({\n toolCallId,\n result,\n }: {\n toolCallId: string;\n result: unknown;\n }) => {\n const currentMessages = messages.value;\n\n updateToolCallResult({\n messages: currentMessages,\n toolCallId,\n toolResult: result,\n });\n\n mutate(currentMessages);\n\n // when the request is ongoing, the auto-submit will be triggered after the request is finished\n if (status.value === 'submitted' || status.value === 'streaming') {\n return;\n }\n\n // auto-submit when all tool calls in the last assistant message have results:\n const lastMessage = currentMessages[currentMessages.length - 1];\n if (isAssistantMessageWithCompletedToolCalls(lastMessage)) {\n triggerRequest(currentMessages);\n }\n };\n\n return {\n id: chatId,\n messages,\n append,\n error,\n reload,\n stop,\n setMessages,\n input,\n handleSubmit,\n status: status as Ref<'submitted' | 'streaming' | 'ready' | 'error'>,\n addToolResult,\n };\n}\n\n// required for use of structured clone\nfunction recursiveToRaw<T>(inputValue: T): T {\n if (Array.isArray(inputValue)) {\n return [...inputValue.map(recursiveToRaw)] as T;\n } else if (typeof inputValue === 'object' && inputValue !== null) {\n const clone: any = {};\n for (const [key, value] of Object.entries(inputValue)) {\n clone[key] = recursiveToRaw(value);\n }\n return clone;\n } else {\n return inputValue;\n }\n}\n","import type { CompletionRequestOptions, UseCompletionOptions } from 'ai';\nimport { callCompletionApi } from 'ai';\nimport swrv from 'swrv';\nimport type { Ref } from 'vue';\nimport { ref, unref } from 'vue';\n\nexport type { UseCompletionOptions };\n\nexport type UseCompletionHelpers = {\n /** The current completion result */\n completion: Ref<string>;\n /** The error object of the API request */\n error: Ref<undefined | Error>;\n /**\n * Send a new prompt to the API endpoint and update the completion state.\n */\n complete: (\n prompt: string,\n options?: CompletionRequestOptions,\n ) => Promise<string | null | undefined>;\n /**\n * Abort the current API request but keep the generated tokens.\n */\n stop: () => void;\n /**\n * Update the `completion` state locally.\n */\n setCompletion: (completion: string) => void;\n /** The current value of the input */\n input: Ref<string>;\n /**\n * Form submission handler to automatically reset input and append a user message\n * @example\n * ```jsx\n * <form @submit=\"handleSubmit\">\n * <input @change=\"handleInputChange\" v-model=\"input\" />\n * </form>\n * ```\n */\n handleSubmit: (event?: { preventDefault?: () => void }) => void;\n /** Whether the API request is in progress */\n isLoading: Ref<boolean | undefined>;\n};\n\nlet uniqueId = 0;\n\n// @ts-expect-error - some issues with the default export of useSWRV\nconst useSWRV = (swrv.default as (typeof import('swrv'))['default']) || swrv;\nconst store: Record<string, any> = {};\n\nexport function useCompletion({\n api = '/api/completion',\n id,\n initialCompletion = '',\n initialInput = '',\n credentials,\n headers,\n body,\n streamProtocol,\n onFinish,\n onError,\n fetch,\n}: UseCompletionOptions = {}): UseCompletionHelpers {\n // Generate an unique id for the completion if not provided.\n const completionId = id || `completion-${uniqueId++}`;\n\n const key = `${api}|${completionId}`;\n const { data, mutate: originalMutate } = useSWRV<string>(\n key,\n () => store[key] || initialCompletion,\n );\n\n const { data: isLoading, mutate: mutateLoading } = useSWRV<boolean>(\n `${completionId}-loading`,\n null,\n );\n\n isLoading.value ??= false;\n\n // Force the `data` to be `initialCompletion` if it's `undefined`.\n data.value ||= initialCompletion;\n\n const mutate = (data: string) => {\n store[key] = data;\n return originalMutate();\n };\n\n // Because of the `initialData` option, the `data` will never be `undefined`.\n const completion = data as Ref<string>;\n\n const error = ref<undefined | Error>(undefined);\n\n let abortController: AbortController | null = null;\n\n async function triggerRequest(\n prompt: string,\n options?: CompletionRequestOptions,\n ) {\n return callCompletionApi({\n api,\n prompt,\n credentials,\n headers: {\n ...headers,\n ...options?.headers,\n },\n body: {\n ...unref(body),\n ...options?.body,\n },\n streamProtocol,\n setCompletion: mutate,\n setLoading: loading => mutateLoading(() => loading),\n setError: err => {\n error.value = err;\n },\n setAbortController: controller => {\n abortController = controller;\n },\n onFinish,\n onError,\n fetch,\n });\n }\n\n const complete: UseCompletionHelpers['complete'] = async (\n prompt,\n options,\n ) => {\n return triggerRequest(prompt, options);\n };\n\n const stop = () => {\n if (abortController) {\n abortController.abort();\n abortController = null;\n }\n };\n\n const setCompletion = (completion: string) => {\n mutate(completion);\n };\n\n const input = ref(initialInput);\n\n const handleSubmit = (event?: { preventDefault?: () => void }) => {\n event?.preventDefault?.();\n const inputValue = input.value;\n return inputValue ? complete(inputValue) : undefined;\n };\n\n return {\n completion,\n complete,\n error,\n stop,\n setCompletion,\n input,\n handleSubmit,\n isLoading,\n };\n}\n"],"mappings":"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","names":["_a","swrv","ref","unref","useSWRV","store","data","completion","_a"]}
1
+ {"version":3,"sources":["../src/use-chat.ts","../src/use-completion.ts"],"sourcesContent":["import type {\n ChatRequestOptions,\n CreateUIMessage,\n FileUIPart,\n JSONValue,\n OriginalUseChatOptions,\n UIMessage,\n UseChatOptions,\n} from 'ai';\nimport {\n callChatApi,\n convertFileListToFileUIParts,\n extractMaxToolInvocationStep,\n generateId as generateIdFunc,\n getToolInvocations,\n isAssistantMessageWithCompletedToolCalls,\n shouldResubmitMessages,\n updateToolCallResult,\n} from 'ai';\nimport swrv from 'swrv';\nimport type { Ref } from 'vue';\nimport { ref, unref } from 'vue';\n\nexport type { CreateUIMessage, UIMessage, UseChatOptions };\n\nexport type UseChatHelpers<MESSAGE_METADATA> = {\n /** Current messages in the chat */\n messages: Ref<UIMessage<MESSAGE_METADATA>[]>;\n /** The error object of the API request */\n error: Ref<undefined | Error>;\n /**\n * Append a user message to the chat list. This triggers the API call to fetch\n * the assistant's response.\n */\n append: (\n message: UIMessage<MESSAGE_METADATA> | CreateUIMessage<MESSAGE_METADATA>,\n chatRequestOptions?: ChatRequestOptions,\n ) => Promise<string | null | undefined>;\n /**\n * Reload the last AI chat response for the given chat history. If the last\n * message isn't from the assistant, it will request the API to generate a\n * new response.\n */\n reload: (\n chatRequestOptions?: ChatRequestOptions,\n ) => Promise<string | null | undefined>;\n /**\n * Abort the current request immediately, keep the generated tokens if any.\n */\n stop: () => void;\n /**\n * Update the `messages` state locally. This is useful when you want to\n * edit the messages on the client, and then trigger the `reload` method\n * manually to regenerate the AI response.\n */\n setMessages: (\n messages:\n | UIMessage<MESSAGE_METADATA>[]\n | ((\n messages: UIMessage<MESSAGE_METADATA>[],\n ) => UIMessage<MESSAGE_METADATA>[]),\n ) => void;\n /** The current value of the input */\n input: Ref<string>;\n /** Form submission handler to automatically reset input and append a user message */\n handleSubmit: (\n event?: { preventDefault?: () => void },\n chatRequestOptions?: ChatRequestOptions & {\n files?: FileList | FileUIPart[];\n },\n ) => void;\n\n /**\n * Hook status:\n *\n * - `submitted`: The message has been sent to the API and we're awaiting the start of the response stream.\n * - `streaming`: The response is actively streaming in from the API, receiving chunks of data.\n * - `ready`: The full response has been received and processed; a new user message can be submitted.\n * - `error`: An error occurred during the API request, preventing successful completion.\n */\n status: Ref<'submitted' | 'streaming' | 'ready' | 'error'>;\n\n addToolResult: ({\n toolCallId,\n result,\n }: {\n toolCallId: string;\n result: any;\n }) => void;\n\n /** The id of the chat */\n id: string;\n};\n\n// @ts-expect-error - some issues with the default export of useSWRV\nconst useSWRV = (swrv.default as (typeof import('swrv'))['default']) || swrv;\nconst store: Record<string, UIMessage<any>[] | undefined> = {};\nconst statusStore: Record<\n string,\n Ref<'submitted' | 'streaming' | 'ready' | 'error'>\n> = {};\n\nexport function useChat<MESSAGE_METADATA = unknown>(\n {\n api = '/api/chat',\n id,\n initialMessages = [],\n initialInput = '',\n streamProtocol = 'ui-message',\n onFinish,\n onError,\n credentials,\n headers: metadataHeaders,\n body: metadataBody,\n generateId = generateIdFunc,\n onToolCall,\n fetch,\n maxSteps = 1,\n experimental_prepareRequestBody,\n messageMetadataSchema,\n }: OriginalUseChatOptions<MESSAGE_METADATA> & {\n /**\n * Experimental (Vue only). When a function is provided, it will be used\n * to prepare the request body for the chat API. This can be useful for\n * customizing the request body based on the messages and data in the chat.\n *\n * @param id The chat ID\n * @param messages The current messages in the chat\n * @param requestData The data object passed in the chat request\n * @param requestBody The request body object passed in the chat request\n */\n experimental_prepareRequestBody?: (options: {\n id: string;\n messages: UIMessage<MESSAGE_METADATA>[];\n requestData?: JSONValue;\n requestBody?: object;\n }) => unknown;\n } = {\n maxSteps: 1,\n },\n): UseChatHelpers<MESSAGE_METADATA> {\n // Generate a unique ID for the chat if not provided.\n const chatId = id ?? generateId();\n\n const key = `${api}|${chatId}`;\n const { data: messagesData, mutate: originalMutate } = useSWRV<\n UIMessage<MESSAGE_METADATA>[]\n >(key, () => store[key] ?? initialMessages);\n\n const status =\n statusStore[chatId] ??\n (statusStore[chatId] = ref<'submitted' | 'streaming' | 'ready' | 'error'>(\n 'ready',\n ));\n\n // Force the `data` to be `initialMessages` if it's `undefined`.\n messagesData.value ??= initialMessages;\n\n const mutate = (data?: UIMessage<MESSAGE_METADATA>[]) => {\n store[key] = data;\n return originalMutate();\n };\n\n // Because of the `initialData` option, the `data` will never be `undefined`.\n const messages = messagesData as Ref<UIMessage<MESSAGE_METADATA>[]>;\n\n const error = ref<undefined | Error>(undefined);\n\n let abortController: AbortController | null = null;\n\n async function triggerRequest(\n messagesSnapshot: UIMessage<MESSAGE_METADATA>[],\n { headers, body }: ChatRequestOptions = {},\n ) {\n error.value = undefined;\n status.value = 'submitted';\n\n const messageCount = messages.value.length;\n const lastMessage = messages.value.at(-1);\n const maxStep =\n lastMessage != null\n ? extractMaxToolInvocationStep(getToolInvocations(lastMessage))\n : 0;\n\n try {\n abortController = new AbortController();\n\n // Do an optimistic update to show the updated messages immediately:\n mutate(messagesSnapshot);\n\n await callChatApi({\n api,\n body: experimental_prepareRequestBody?.({\n id: chatId,\n messages: messagesSnapshot,\n requestBody: body,\n }) ?? {\n id: chatId,\n messages: messagesSnapshot,\n ...unref(metadataBody), // Use unref to unwrap the ref value\n ...body,\n },\n streamProtocol,\n headers: {\n ...metadataHeaders,\n ...headers,\n },\n abortController: () => abortController,\n credentials,\n onUpdate({ message }) {\n status.value = 'streaming';\n\n const replaceLastMessage =\n message.id === messagesSnapshot[messagesSnapshot.length - 1].id;\n\n mutate([\n ...(replaceLastMessage\n ? messagesSnapshot.slice(0, messagesSnapshot.length - 1)\n : messagesSnapshot),\n message,\n ]);\n },\n onFinish,\n generateId,\n onToolCall,\n fetch,\n // enabled use of structured clone in processChatResponse:\n lastMessage: recursiveToRaw(\n messagesSnapshot[messagesSnapshot.length - 1],\n ),\n messageMetadataSchema,\n });\n\n status.value = 'ready';\n } catch (err) {\n // Ignore abort errors as they are expected.\n if ((err as any).name === 'AbortError') {\n abortController = null;\n status.value = 'ready';\n return null;\n }\n\n if (onError && err instanceof Error) {\n onError(err);\n }\n\n error.value = err as Error;\n status.value = 'error';\n } finally {\n abortController = null;\n }\n\n // auto-submit when all tool calls in the last assistant message have results:\n if (\n shouldResubmitMessages({\n originalMaxToolInvocationStep: maxStep,\n originalMessageCount: messageCount,\n maxSteps,\n messages: messages.value,\n })\n ) {\n await triggerRequest(messages.value);\n }\n }\n\n const append: UseChatHelpers<MESSAGE_METADATA>['append'] = async (\n message,\n options,\n ) => {\n return triggerRequest(\n messages.value.concat({\n ...message,\n id: message.id ?? generateId(),\n parts: message.parts,\n }),\n options,\n );\n };\n\n const reload: UseChatHelpers<MESSAGE_METADATA>['reload'] = async options => {\n const messagesSnapshot = messages.value;\n if (messagesSnapshot.length === 0) return null;\n\n const lastMessage = messagesSnapshot[messagesSnapshot.length - 1];\n if (lastMessage.role === 'assistant') {\n return triggerRequest(messagesSnapshot.slice(0, -1), options);\n }\n\n return triggerRequest(messagesSnapshot, options);\n };\n\n const stop = () => {\n if (abortController) {\n abortController.abort();\n abortController = null;\n }\n };\n\n const setMessages = (\n messagesArg:\n | UIMessage<MESSAGE_METADATA>[]\n | ((\n messages: UIMessage<MESSAGE_METADATA>[],\n ) => UIMessage<MESSAGE_METADATA>[]),\n ) => {\n if (typeof messagesArg === 'function') {\n messagesArg = messagesArg(messages.value);\n }\n\n mutate(messagesArg);\n };\n\n const input = ref(initialInput);\n\n const handleSubmit = async (\n event?: { preventDefault?: () => void },\n options: ChatRequestOptions & { files?: FileList | FileUIPart[] } = {},\n ) => {\n event?.preventDefault?.();\n\n const inputValue = input.value;\n\n const fileParts = Array.isArray(options?.files)\n ? options.files\n : await convertFileListToFileUIParts(options?.files);\n\n if (!inputValue && fileParts.length === 0) return;\n\n triggerRequest(\n messages.value.concat({\n id: generateId(),\n role: 'user',\n parts: [...fileParts, { type: 'text', text: inputValue }],\n }),\n options,\n );\n\n input.value = '';\n };\n\n const addToolResult = ({\n toolCallId,\n result,\n }: {\n toolCallId: string;\n result: unknown;\n }) => {\n const currentMessages = messages.value;\n\n updateToolCallResult({\n messages: currentMessages,\n toolCallId,\n toolResult: result,\n });\n\n mutate(currentMessages);\n\n // when the request is ongoing, the auto-submit will be triggered after the request is finished\n if (status.value === 'submitted' || status.value === 'streaming') {\n return;\n }\n\n // auto-submit when all tool calls in the last assistant message have results:\n const lastMessage = currentMessages[currentMessages.length - 1];\n if (isAssistantMessageWithCompletedToolCalls(lastMessage)) {\n triggerRequest(currentMessages);\n }\n };\n\n return {\n id: chatId,\n messages,\n append,\n error,\n reload,\n stop,\n setMessages,\n input,\n handleSubmit,\n status: status as Ref<'submitted' | 'streaming' | 'ready' | 'error'>,\n addToolResult,\n };\n}\n\n// required for use of structured clone\nfunction recursiveToRaw<T>(inputValue: T): T {\n if (Array.isArray(inputValue)) {\n return [...inputValue.map(recursiveToRaw)] as T;\n } else if (typeof inputValue === 'object' && inputValue !== null) {\n const clone: any = {};\n for (const [key, value] of Object.entries(inputValue)) {\n clone[key] = recursiveToRaw(value);\n }\n return clone;\n } else {\n return inputValue;\n }\n}\n","import type { CompletionRequestOptions, UseCompletionOptions } from 'ai';\nimport { callCompletionApi } from 'ai';\nimport swrv from 'swrv';\nimport type { Ref } from 'vue';\nimport { ref, unref } from 'vue';\n\nexport type { UseCompletionOptions };\n\nexport type UseCompletionHelpers = {\n /** The current completion result */\n completion: Ref<string>;\n /** The error object of the API request */\n error: Ref<undefined | Error>;\n /**\n * Send a new prompt to the API endpoint and update the completion state.\n */\n complete: (\n prompt: string,\n options?: CompletionRequestOptions,\n ) => Promise<string | null | undefined>;\n /**\n * Abort the current API request but keep the generated tokens.\n */\n stop: () => void;\n /**\n * Update the `completion` state locally.\n */\n setCompletion: (completion: string) => void;\n /** The current value of the input */\n input: Ref<string>;\n /**\n * Form submission handler to automatically reset input and append a user message\n * @example\n * ```jsx\n * <form @submit=\"handleSubmit\">\n * <input @change=\"handleInputChange\" v-model=\"input\" />\n * </form>\n * ```\n */\n handleSubmit: (event?: { preventDefault?: () => void }) => void;\n /** Whether the API request is in progress */\n isLoading: Ref<boolean | undefined>;\n};\n\nlet uniqueId = 0;\n\n// @ts-expect-error - some issues with the default export of useSWRV\nconst useSWRV = (swrv.default as (typeof import('swrv'))['default']) || swrv;\nconst store: Record<string, any> = {};\n\nexport function useCompletion({\n api = '/api/completion',\n id,\n initialCompletion = '',\n initialInput = '',\n credentials,\n headers,\n body,\n streamProtocol,\n onFinish,\n onError,\n fetch,\n}: UseCompletionOptions = {}): UseCompletionHelpers {\n // Generate an unique id for the completion if not provided.\n const completionId = id || `completion-${uniqueId++}`;\n\n const key = `${api}|${completionId}`;\n const { data, mutate: originalMutate } = useSWRV<string>(\n key,\n () => store[key] || initialCompletion,\n );\n\n const { data: isLoading, mutate: mutateLoading } = useSWRV<boolean>(\n `${completionId}-loading`,\n null,\n );\n\n isLoading.value ??= false;\n\n // Force the `data` to be `initialCompletion` if it's `undefined`.\n data.value ||= initialCompletion;\n\n const mutate = (data: string) => {\n store[key] = data;\n return originalMutate();\n };\n\n // Because of the `initialData` option, the `data` will never be `undefined`.\n const completion = data as Ref<string>;\n\n const error = ref<undefined | Error>(undefined);\n\n let abortController: AbortController | null = null;\n\n async function triggerRequest(\n prompt: string,\n options?: CompletionRequestOptions,\n ) {\n return callCompletionApi({\n api,\n prompt,\n credentials,\n headers: {\n ...headers,\n ...options?.headers,\n },\n body: {\n ...unref(body),\n ...options?.body,\n },\n streamProtocol,\n setCompletion: mutate,\n setLoading: loading => mutateLoading(() => loading),\n setError: err => {\n error.value = err;\n },\n setAbortController: controller => {\n abortController = controller;\n },\n onFinish,\n onError,\n fetch,\n });\n }\n\n const complete: UseCompletionHelpers['complete'] = async (\n prompt,\n options,\n ) => {\n return triggerRequest(prompt, options);\n };\n\n const stop = () => {\n if (abortController) {\n abortController.abort();\n abortController = null;\n }\n };\n\n const setCompletion = (completion: string) => {\n mutate(completion);\n };\n\n const input = ref(initialInput);\n\n const handleSubmit = (event?: { preventDefault?: () => void }) => {\n event?.preventDefault?.();\n const inputValue = input.value;\n return inputValue ? complete(inputValue) : undefined;\n };\n\n return {\n completion,\n complete,\n error,\n stop,\n setCompletion,\n input,\n handleSubmit,\n isLoading,\n };\n}\n"],"mappings":"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","names":["_a","swrv","ref","unref","useSWRV","store","data","completion","_a"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-sdk/vue",
3
- "version": "2.0.0-canary.21",
3
+ "version": "2.0.0-canary.23",
4
4
  "license": "Apache-2.0",
5
5
  "sideEffects": false,
6
6
  "main": "./dist/index.js",
@@ -20,8 +20,8 @@
20
20
  ],
21
21
  "dependencies": {
22
22
  "swrv": "^1.0.4",
23
- "ai": "5.0.0-canary.22",
24
- "@ai-sdk/provider-utils": "3.0.0-canary.17"
23
+ "ai": "5.0.0-canary.24",
24
+ "@ai-sdk/provider-utils": "3.0.0-canary.19"
25
25
  },
26
26
  "devDependencies": {
27
27
  "@testing-library/jest-dom": "^6.6.3",