@ai-sdk/svelte 0.0.43 → 0.0.45

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,19 @@
1
1
  # @ai-sdk/svelte
2
2
 
3
+ ## 0.0.45
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [aa2dc58]
8
+ - @ai-sdk/ui-utils@0.0.40
9
+
10
+ ## 0.0.44
11
+
12
+ ### Patch Changes
13
+
14
+ - @ai-sdk/provider-utils@1.0.17
15
+ - @ai-sdk/ui-utils@0.0.39
16
+
3
17
  ## 0.0.43
4
18
 
5
19
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-sdk/svelte",
3
- "version": "0.0.43",
3
+ "version": "0.0.45",
4
4
  "license": "Apache-2.0",
5
5
  "sideEffects": false,
6
6
  "main": "./dist/index.js",
@@ -14,9 +14,13 @@
14
14
  "require": "./dist/index.js"
15
15
  }
16
16
  },
17
+ "files": [
18
+ "dist/**/*",
19
+ "CHANGELOG.md"
20
+ ],
17
21
  "dependencies": {
18
- "@ai-sdk/provider-utils": "1.0.16",
19
- "@ai-sdk/ui-utils": "0.0.38",
22
+ "@ai-sdk/provider-utils": "1.0.17",
23
+ "@ai-sdk/ui-utils": "0.0.40",
20
24
  "sswr": "2.1.0"
21
25
  },
22
26
  "devDependencies": {
package/.eslintrc.js DELETED
@@ -1,4 +0,0 @@
1
- module.exports = {
2
- root: true,
3
- extends: ['vercel-ai'],
4
- };
@@ -1,21 +0,0 @@
1
-
2
- > @ai-sdk/svelte@0.0.43 build /home/runner/work/ai/ai/packages/svelte
3
- > tsup
4
-
5
- CLI Building entry: src/index.ts
6
- CLI Using tsconfig: tsconfig.json
7
- CLI tsup v7.2.0
8
- CLI Using tsup config: /home/runner/work/ai/ai/packages/svelte/tsup.config.ts
9
- CLI Target: es2018
10
- CJS Build start
11
- ESM Build start
12
- CJS dist/index.js 19.63 KB
13
- CJS dist/index.js.map 39.25 KB
14
- CJS ⚡️ Build success in 40ms
15
- ESM dist/index.mjs 17.87 KB
16
- ESM dist/index.mjs.map 39.11 KB
17
- ESM ⚡️ Build success in 52ms
18
- DTS Build start
19
- DTS ⚡️ Build success in 4881ms
20
- DTS dist/index.d.ts 6.53 KB
21
- DTS dist/index.d.mts 6.53 KB
@@ -1,4 +0,0 @@
1
-
2
- > @ai-sdk/svelte@0.0.43 clean /home/runner/work/ai/ai/packages/svelte
3
- > rm -rf dist
4
-
package/src/index.ts DELETED
@@ -1,3 +0,0 @@
1
- export * from './use-chat';
2
- export * from './use-completion';
3
- export * from './use-assistant';
package/src/package.json DELETED
@@ -1,10 +0,0 @@
1
- {
2
- "main": "./dist/index.js",
3
- "module": "./dist/index.mjs",
4
- "types": "./dist/index.d.ts",
5
- "exports": "./dist/index.mjs",
6
- "private": true,
7
- "peerDependencies": {
8
- "svelte": "*"
9
- }
10
- }
@@ -1,262 +0,0 @@
1
- import { isAbortError } from '@ai-sdk/provider-utils';
2
- import type {
3
- AssistantStatus,
4
- CreateMessage,
5
- Message,
6
- UseAssistantOptions,
7
- } from '@ai-sdk/ui-utils';
8
- import { generateId, readDataStream } from '@ai-sdk/ui-utils';
9
- import { Readable, Writable, get, writable } from 'svelte/store';
10
-
11
- // use function to allow for mocking in tests:
12
- const getOriginalFetch = () => fetch;
13
-
14
- let uniqueId = 0;
15
-
16
- const store: Record<string, any> = {};
17
-
18
- export type UseAssistantHelpers = {
19
- /**
20
- * The current array of chat messages.
21
- */
22
- messages: Readable<Message[]>;
23
-
24
- /**
25
- * Update the message store with a new array of messages.
26
- */
27
- setMessages: (messages: Message[]) => void;
28
-
29
- /**
30
- * The current thread ID.
31
- */
32
- threadId: Readable<string | undefined>;
33
-
34
- /**
35
- * The current value of the input field.
36
- */
37
- input: Writable<string>;
38
-
39
- /**
40
- * Append a user message to the chat list. This triggers the API call to fetch
41
- * the assistant's response.
42
- * @param message The message to append
43
- * @param requestOptions Additional options to pass to the API call
44
- */
45
- append: (
46
- message: Message | CreateMessage,
47
- requestOptions?: { data?: Record<string, string> },
48
- ) => Promise<void>;
49
-
50
- /**
51
- Abort the current request immediately, keep the generated tokens if any.
52
- */
53
- stop: () => void;
54
-
55
- /**
56
- * Form submission handler that automatically resets the input field and appends a user message.
57
- */
58
- submitMessage: (
59
- event?: { preventDefault?: () => void },
60
- requestOptions?: { data?: Record<string, string> },
61
- ) => Promise<void>;
62
-
63
- /**
64
- * The current status of the assistant. This can be used to show a loading indicator.
65
- */
66
- status: Readable<AssistantStatus>;
67
-
68
- /**
69
- * The error thrown during the assistant message processing, if any.
70
- */
71
- error: Readable<undefined | Error>;
72
- };
73
-
74
- export function useAssistant({
75
- api,
76
- threadId: threadIdParam,
77
- credentials,
78
- headers,
79
- body,
80
- onError,
81
- fetch,
82
- }: UseAssistantOptions): UseAssistantHelpers {
83
- // Generate a unique thread ID
84
- const threadIdStore = writable<string | undefined>(threadIdParam);
85
-
86
- // Initialize message, input, status, and error stores
87
- const key = `${api}|${threadIdParam ?? `completion-${uniqueId++}`}`;
88
- const messages = writable<Message[]>(store[key] || []);
89
- const input = writable('');
90
- const status = writable<AssistantStatus>('awaiting_message');
91
- const error = writable<undefined | Error>(undefined);
92
-
93
- // To manage aborting the current fetch request
94
- let abortController: AbortController | null = null;
95
-
96
- // Update the message store
97
- const mutateMessages = (newMessages: Message[]) => {
98
- store[key] = newMessages;
99
- messages.set(newMessages);
100
- };
101
-
102
- // Function to handle API calls and state management
103
- async function append(
104
- message: Message | CreateMessage,
105
- requestOptions?: { data?: Record<string, string> },
106
- ) {
107
- status.set('in_progress');
108
- abortController = new AbortController(); // Initialize a new AbortController
109
-
110
- // Add the new message to the existing array
111
- mutateMessages([
112
- ...get(messages),
113
- { ...message, id: message.id ?? generateId() },
114
- ]);
115
-
116
- input.set('');
117
-
118
- try {
119
- const actualFetch = fetch ?? getOriginalFetch();
120
- const response = await actualFetch(api, {
121
- method: 'POST',
122
- credentials,
123
- signal: abortController.signal,
124
- headers: { 'Content-Type': 'application/json', ...headers },
125
- body: JSON.stringify({
126
- ...body,
127
- // always use user-provided threadId when available:
128
- threadId: threadIdParam ?? get(threadIdStore) ?? null,
129
- message: message.content,
130
-
131
- // optional request data:
132
- data: requestOptions?.data,
133
- }),
134
- });
135
-
136
- if (!response.ok) {
137
- throw new Error(
138
- (await response.text()) ?? 'Failed to fetch the assistant response.',
139
- );
140
- }
141
-
142
- if (response.body == null) {
143
- throw new Error('The response body is empty.');
144
- }
145
-
146
- // Read the streamed response data
147
- for await (const { type, value } of readDataStream(
148
- response.body.getReader(),
149
- )) {
150
- switch (type) {
151
- case 'assistant_message': {
152
- mutateMessages([
153
- ...get(messages),
154
- {
155
- id: value.id,
156
- role: value.role,
157
- content: value.content[0].text.value,
158
- },
159
- ]);
160
- break;
161
- }
162
-
163
- case 'text': {
164
- // text delta - add to last message:
165
- mutateMessages(
166
- get(messages).map((msg, index, array) => {
167
- if (index === array.length - 1) {
168
- return { ...msg, content: msg.content + value };
169
- }
170
- return msg;
171
- }),
172
- );
173
- break;
174
- }
175
-
176
- case 'data_message': {
177
- mutateMessages([
178
- ...get(messages),
179
- {
180
- id: value.id ?? generateId(),
181
- role: 'data',
182
- content: '',
183
- data: value.data,
184
- },
185
- ]);
186
- break;
187
- }
188
-
189
- case 'assistant_control_data': {
190
- threadIdStore.set(value.threadId);
191
-
192
- mutateMessages(
193
- get(messages).map((msg, index, array) => {
194
- if (index === array.length - 1) {
195
- return { ...msg, id: value.messageId };
196
- }
197
- return msg;
198
- }),
199
- );
200
-
201
- break;
202
- }
203
-
204
- case 'error': {
205
- error.set(new Error(value));
206
- break;
207
- }
208
- }
209
- }
210
- } catch (err) {
211
- // Ignore abort errors as they are expected when the user cancels the request:
212
- if (isAbortError(error) && abortController?.signal?.aborted) {
213
- abortController = null;
214
- return;
215
- }
216
-
217
- if (onError && err instanceof Error) {
218
- onError(err);
219
- }
220
-
221
- error.set(err as Error);
222
- } finally {
223
- abortController = null;
224
- status.set('awaiting_message');
225
- }
226
- }
227
-
228
- function setMessages(messages: Message[]) {
229
- mutateMessages(messages);
230
- }
231
-
232
- function stop() {
233
- if (abortController) {
234
- abortController.abort();
235
- abortController = null;
236
- }
237
- }
238
-
239
- // Function to handle form submission
240
- async function submitMessage(
241
- event?: { preventDefault?: () => void },
242
- requestOptions?: { data?: Record<string, string> },
243
- ) {
244
- event?.preventDefault?.();
245
- const inputValue = get(input);
246
- if (!inputValue) return;
247
-
248
- await append({ role: 'user', content: inputValue }, requestOptions);
249
- }
250
-
251
- return {
252
- messages,
253
- error,
254
- threadId: threadIdStore,
255
- input,
256
- append,
257
- submitMessage,
258
- status,
259
- setMessages,
260
- stop,
261
- };
262
- }
package/src/use-chat.ts DELETED
@@ -1,574 +0,0 @@
1
- import { FetchFunction } from '@ai-sdk/provider-utils';
2
- import type {
3
- ChatRequest,
4
- ChatRequestOptions,
5
- CreateMessage,
6
- IdGenerator,
7
- JSONValue,
8
- Message,
9
- UseChatOptions as SharedUseChatOptions,
10
- } from '@ai-sdk/ui-utils';
11
- import {
12
- callChatApi,
13
- generateId as generateIdFunc,
14
- processChatStream,
15
- } from '@ai-sdk/ui-utils';
16
- import { useSWR } from 'sswr';
17
- import { Readable, Writable, derived, get, writable } from 'svelte/store';
18
- export type { CreateMessage, Message };
19
-
20
- export type UseChatOptions = SharedUseChatOptions & {
21
- /**
22
- Maximal number of automatic roundtrips for tool calls.
23
-
24
- An automatic tool call roundtrip is a call to the server with the
25
- tool call results when all tool calls in the last assistant
26
- message have results.
27
-
28
- A maximum number is required to prevent infinite loops in the
29
- case of misconfigured tools.
30
-
31
- By default, it's set to 0, which will disable the feature.
32
- */
33
- maxToolRoundtrips?: number;
34
- };
35
-
36
- export type UseChatHelpers = {
37
- /** Current messages in the chat */
38
- messages: Readable<Message[]>;
39
- /** The error object of the API request */
40
- error: Readable<undefined | Error>;
41
- /**
42
- * Append a user message to the chat list. This triggers the API call to fetch
43
- * the assistant's response.
44
- * @param message The message to append
45
- * @param chatRequestOptions Additional options to pass to the API call
46
- */
47
- append: (
48
- message: Message | CreateMessage,
49
- chatRequestOptions?: ChatRequestOptions,
50
- ) => Promise<string | null | undefined>;
51
- /**
52
- * Reload the last AI chat response for the given chat history. If the last
53
- * message isn't from the assistant, it will request the API to generate a
54
- * new response.
55
- */
56
- reload: (
57
- chatRequestOptions?: ChatRequestOptions,
58
- ) => Promise<string | null | undefined>;
59
- /**
60
- * Abort the current request immediately, keep the generated tokens if any.
61
- */
62
- stop: () => void;
63
- /**
64
- * Update the `messages` state locally. This is useful when you want to
65
- * edit the messages on the client, and then trigger the `reload` method
66
- * manually to regenerate the AI response.
67
- */
68
- setMessages: (
69
- messages: Message[] | ((messages: Message[]) => Message[]),
70
- ) => void;
71
-
72
- /** The current value of the input */
73
- input: Writable<string>;
74
- /** Form submission handler to automatically reset input and append a user message */
75
- handleSubmit: (
76
- event?: { preventDefault?: () => void },
77
- chatRequestOptions?: ChatRequestOptions,
78
- ) => void;
79
- metadata?: Object;
80
- /** Whether the API request is in progress */
81
- isLoading: Readable<boolean | undefined>;
82
-
83
- /** Additional data added on the server via StreamData */
84
- data: Readable<JSONValue[] | undefined>;
85
- /**
86
- Maximal number of automatic roundtrips for tool calls.
87
-
88
- An automatic tool call roundtrip is a call to the server with the
89
- tool call results when all tool calls in the last assistant
90
- message have results.
91
-
92
- A maximum number is required to prevent infinite loops in the
93
- case of misconfigured tools.
94
-
95
- By default, it's set to 0, which will disable the feature.
96
- */
97
- maxToolRoundtrips?: number;
98
- };
99
-
100
- const getStreamedResponse = async (
101
- api: string,
102
- chatRequest: ChatRequest,
103
- mutate: (messages: Message[]) => void,
104
- mutateStreamData: (data: JSONValue[] | undefined) => void,
105
- existingData: JSONValue[] | undefined,
106
- extraMetadata: {
107
- credentials?: RequestCredentials;
108
- headers?: Record<string, string> | Headers;
109
- body?: any;
110
- },
111
- previousMessages: Message[],
112
- abortControllerRef: AbortController | null,
113
- generateId: IdGenerator,
114
- streamProtocol: UseChatOptions['streamProtocol'],
115
- onFinish: UseChatOptions['onFinish'],
116
- onResponse: ((response: Response) => void | Promise<void>) | undefined,
117
- onToolCall: UseChatOptions['onToolCall'] | undefined,
118
- sendExtraMessageFields: boolean | undefined,
119
- fetch: FetchFunction | undefined,
120
- keepLastMessageOnError: boolean | undefined,
121
- ) => {
122
- // Do an optimistic update to the chat state to show the updated messages
123
- // immediately.
124
- mutate(chatRequest.messages);
125
-
126
- const constructedMessagesPayload = sendExtraMessageFields
127
- ? chatRequest.messages
128
- : chatRequest.messages.map(
129
- ({
130
- role,
131
- content,
132
- name,
133
- data,
134
- annotations,
135
- function_call,
136
- tool_calls,
137
- tool_call_id,
138
- toolInvocations,
139
- }) => ({
140
- role,
141
- content,
142
- ...(name !== undefined && { name }),
143
- ...(data !== undefined && { data }),
144
- ...(annotations !== undefined && { annotations }),
145
- ...(toolInvocations !== undefined && { toolInvocations }),
146
- // outdated function/tool call handling (TODO deprecate):
147
- tool_call_id,
148
- ...(function_call !== undefined && { function_call }),
149
- ...(tool_calls !== undefined && { tool_calls }),
150
- }),
151
- );
152
-
153
- return await callChatApi({
154
- api,
155
- body: {
156
- messages: constructedMessagesPayload,
157
- data: chatRequest.data,
158
- ...extraMetadata.body,
159
- ...chatRequest.body,
160
- ...(chatRequest.functions !== undefined && {
161
- functions: chatRequest.functions,
162
- }),
163
- ...(chatRequest.function_call !== undefined && {
164
- function_call: chatRequest.function_call,
165
- }),
166
- ...(chatRequest.tools !== undefined && {
167
- tools: chatRequest.tools,
168
- }),
169
- ...(chatRequest.tool_choice !== undefined && {
170
- tool_choice: chatRequest.tool_choice,
171
- }),
172
- },
173
- streamProtocol,
174
- credentials: extraMetadata.credentials,
175
- headers: {
176
- ...extraMetadata.headers,
177
- ...chatRequest.headers,
178
- },
179
- abortController: () => abortControllerRef,
180
- restoreMessagesOnFailure() {
181
- if (!keepLastMessageOnError) {
182
- mutate(previousMessages);
183
- }
184
- },
185
- onResponse,
186
- onUpdate(merged, data) {
187
- mutate([...chatRequest.messages, ...merged]);
188
- mutateStreamData([...(existingData || []), ...(data || [])]);
189
- },
190
- onFinish,
191
- generateId,
192
- onToolCall,
193
- fetch,
194
- });
195
- };
196
-
197
- let uniqueId = 0;
198
-
199
- const store: Record<string, Message[] | undefined> = {};
200
-
201
- /**
202
- Check if the message is an assistant message with completed tool calls.
203
- The message must have at least one tool invocation and all tool invocations
204
- must have a result.
205
- */
206
- function isAssistantMessageWithCompletedToolCalls(message: Message) {
207
- return (
208
- message.role === 'assistant' &&
209
- message.toolInvocations &&
210
- message.toolInvocations.length > 0 &&
211
- message.toolInvocations.every(toolInvocation => 'result' in toolInvocation)
212
- );
213
- }
214
-
215
- /**
216
- Returns the number of trailing assistant messages in the array.
217
- */
218
- function countTrailingAssistantMessages(messages: Message[]) {
219
- let count = 0;
220
- for (let i = messages.length - 1; i >= 0; i--) {
221
- if (messages[i].role === 'assistant') {
222
- count++;
223
- } else {
224
- break;
225
- }
226
- }
227
-
228
- return count;
229
- }
230
-
231
- export function useChat({
232
- api = '/api/chat',
233
- id,
234
- initialMessages = [],
235
- initialInput = '',
236
- sendExtraMessageFields,
237
- experimental_onFunctionCall,
238
- experimental_onToolCall,
239
- streamMode,
240
- streamProtocol,
241
- onResponse,
242
- onFinish,
243
- onError,
244
- onToolCall,
245
- credentials,
246
- headers,
247
- body,
248
- generateId = generateIdFunc,
249
- fetch,
250
- keepLastMessageOnError = false,
251
- maxToolRoundtrips = 0,
252
- }: UseChatOptions = {}): UseChatHelpers & {
253
- addToolResult: ({
254
- toolCallId,
255
- result,
256
- }: {
257
- toolCallId: string;
258
- result: any;
259
- }) => void;
260
- } {
261
- // streamMode is deprecated, use streamProtocol instead.
262
- if (streamMode) {
263
- streamProtocol ??= streamMode === 'text' ? 'text' : undefined;
264
- }
265
-
266
- // Generate a unique id for the chat if not provided.
267
- const chatId = id || `chat-${uniqueId++}`;
268
-
269
- const key = `${api}|${chatId}`;
270
- const {
271
- data,
272
- mutate: originalMutate,
273
- isLoading: isSWRLoading,
274
- } = useSWR<Message[]>(key, {
275
- fetcher: () => store[key] || initialMessages,
276
- fallbackData: initialMessages,
277
- });
278
-
279
- const streamData = writable<JSONValue[] | undefined>(undefined);
280
-
281
- const loading = writable<boolean>(false);
282
-
283
- // Force the `data` to be `initialMessages` if it's `undefined`.
284
- data.set(initialMessages);
285
-
286
- const mutate = (data: Message[]) => {
287
- store[key] = data;
288
- return originalMutate(data);
289
- };
290
-
291
- // Because of the `fallbackData` option, the `data` will never be `undefined`.
292
- const messages = data as Writable<Message[]>;
293
-
294
- // Abort controller to cancel the current API call.
295
- let abortController: AbortController | null = null;
296
-
297
- const extraMetadata = {
298
- credentials,
299
- headers,
300
- body,
301
- };
302
-
303
- const error = writable<undefined | Error>(undefined);
304
-
305
- // Actual mutation hook to send messages to the API endpoint and update the
306
- // chat state.
307
- async function triggerRequest(chatRequest: ChatRequest) {
308
- const messagesSnapshot = get(messages);
309
- const messageCount = messagesSnapshot.length;
310
-
311
- try {
312
- error.set(undefined);
313
- loading.set(true);
314
- abortController = new AbortController();
315
-
316
- await processChatStream({
317
- getStreamedResponse: () =>
318
- getStreamedResponse(
319
- api,
320
- chatRequest,
321
- mutate,
322
- data => {
323
- streamData.set(data);
324
- },
325
- get(streamData),
326
- extraMetadata,
327
- get(messages),
328
- abortController,
329
- generateId,
330
- streamProtocol,
331
- onFinish,
332
- onResponse,
333
- onToolCall,
334
- sendExtraMessageFields,
335
- fetch,
336
- keepLastMessageOnError,
337
- ),
338
- experimental_onFunctionCall,
339
- experimental_onToolCall,
340
- updateChatRequest: chatRequestParam => {
341
- chatRequest = chatRequestParam;
342
- },
343
- getCurrentMessages: () => get(messages),
344
- });
345
-
346
- abortController = null;
347
- } catch (err) {
348
- // Ignore abort errors as they are expected.
349
- if ((err as any).name === 'AbortError') {
350
- abortController = null;
351
- return null;
352
- }
353
-
354
- if (onError && err instanceof Error) {
355
- onError(err);
356
- }
357
-
358
- error.set(err as Error);
359
- } finally {
360
- loading.set(false);
361
- }
362
-
363
- // auto-submit when all tool calls in the last assistant message have results:
364
- const newMessagesSnapshot = get(messages);
365
- const lastMessage = newMessagesSnapshot[newMessagesSnapshot.length - 1];
366
-
367
- if (
368
- // ensure we actually have new messages (to prevent infinite loops in case of errors):
369
- newMessagesSnapshot.length > messageCount &&
370
- // ensure there is a last message:
371
- lastMessage != null &&
372
- // check if the feature is enabled:
373
- maxToolRoundtrips > 0 &&
374
- // check that roundtrip is possible:
375
- isAssistantMessageWithCompletedToolCalls(lastMessage) &&
376
- // limit the number of automatic roundtrips:
377
- countTrailingAssistantMessages(newMessagesSnapshot) <= maxToolRoundtrips
378
- ) {
379
- await triggerRequest({ messages: newMessagesSnapshot });
380
- }
381
- }
382
-
383
- const append: UseChatHelpers['append'] = async (
384
- message: Message | CreateMessage,
385
- {
386
- options,
387
- functions,
388
- function_call,
389
- tools,
390
- tool_choice,
391
- data,
392
- headers,
393
- body,
394
- }: ChatRequestOptions = {},
395
- ) => {
396
- if (!message.id) {
397
- message.id = generateId();
398
- }
399
-
400
- const requestOptions = {
401
- headers: headers ?? options?.headers,
402
- body: body ?? options?.body,
403
- };
404
-
405
- const chatRequest: ChatRequest = {
406
- messages: get(messages).concat(message as Message),
407
- options: requestOptions,
408
- headers: requestOptions.headers,
409
- body: requestOptions.body,
410
- data,
411
- ...(functions !== undefined && { functions }),
412
- ...(function_call !== undefined && { function_call }),
413
- ...(tools !== undefined && { tools }),
414
- ...(tool_choice !== undefined && { tool_choice }),
415
- };
416
- return triggerRequest(chatRequest);
417
- };
418
-
419
- const reload: UseChatHelpers['reload'] = async ({
420
- options,
421
- functions,
422
- function_call,
423
- tools,
424
- tool_choice,
425
- data,
426
- headers,
427
- body,
428
- }: ChatRequestOptions = {}) => {
429
- const messagesSnapshot = get(messages);
430
- if (messagesSnapshot.length === 0) return null;
431
-
432
- const requestOptions = {
433
- headers: headers ?? options?.headers,
434
- body: body ?? options?.body,
435
- };
436
-
437
- // Remove last assistant message and retry last user message.
438
- const lastMessage = messagesSnapshot.at(-1);
439
- if (lastMessage?.role === 'assistant') {
440
- const chatRequest: ChatRequest = {
441
- messages: messagesSnapshot.slice(0, -1),
442
- options: requestOptions,
443
- headers: requestOptions.headers,
444
- body: requestOptions.body,
445
- data,
446
- ...(functions !== undefined && { functions }),
447
- ...(function_call !== undefined && { function_call }),
448
- ...(tools !== undefined && { tools }),
449
- ...(tool_choice !== undefined && { tool_choice }),
450
- };
451
-
452
- return triggerRequest(chatRequest);
453
- }
454
-
455
- const chatRequest: ChatRequest = {
456
- messages: messagesSnapshot,
457
- options: requestOptions,
458
- headers: requestOptions.headers,
459
- body: requestOptions.body,
460
- data,
461
- };
462
-
463
- return triggerRequest(chatRequest);
464
- };
465
-
466
- const stop = () => {
467
- if (abortController) {
468
- abortController.abort();
469
- abortController = null;
470
- }
471
- };
472
-
473
- const setMessages = (
474
- messagesArg: Message[] | ((messages: Message[]) => Message[]),
475
- ) => {
476
- if (typeof messagesArg === 'function') {
477
- messagesArg = messagesArg(get(messages));
478
- }
479
-
480
- mutate(messagesArg);
481
- };
482
-
483
- const input = writable(initialInput);
484
-
485
- const handleSubmit = (
486
- event?: { preventDefault?: () => void },
487
- options: ChatRequestOptions = {},
488
- ) => {
489
- event?.preventDefault?.();
490
- const inputValue = get(input);
491
-
492
- if (!inputValue && !options.allowEmptySubmit) return;
493
-
494
- const requestOptions = {
495
- headers: options.headers ?? options.options?.headers,
496
- body: options.body ?? options.options?.body,
497
- };
498
-
499
- const chatRequest: ChatRequest = {
500
- messages:
501
- !inputValue && options.allowEmptySubmit
502
- ? get(messages)
503
- : get(messages).concat({
504
- id: generateId(),
505
- content: inputValue,
506
- role: 'user',
507
- createdAt: new Date(),
508
- } as Message),
509
- options: requestOptions,
510
- body: requestOptions.body,
511
- headers: requestOptions.headers,
512
- data: options.data,
513
- };
514
-
515
- triggerRequest(chatRequest);
516
-
517
- input.set('');
518
- };
519
-
520
- const isLoading = derived(
521
- [isSWRLoading, loading],
522
- ([$isSWRLoading, $loading]) => {
523
- return $isSWRLoading || $loading;
524
- },
525
- );
526
-
527
- const addToolResult = ({
528
- toolCallId,
529
- result,
530
- }: {
531
- toolCallId: string;
532
- result: any;
533
- }) => {
534
- const messagesSnapshot = get(messages) ?? [];
535
- const updatedMessages = messagesSnapshot.map((message, index, arr) =>
536
- // update the tool calls in the last assistant message:
537
- index === arr.length - 1 &&
538
- message.role === 'assistant' &&
539
- message.toolInvocations
540
- ? {
541
- ...message,
542
- toolInvocations: message.toolInvocations.map(toolInvocation =>
543
- toolInvocation.toolCallId === toolCallId
544
- ? { ...toolInvocation, result }
545
- : toolInvocation,
546
- ),
547
- }
548
- : message,
549
- );
550
-
551
- messages.set(updatedMessages);
552
-
553
- // auto-submit when all tool calls in the last assistant message have results:
554
- const lastMessage = updatedMessages[updatedMessages.length - 1];
555
-
556
- if (isAssistantMessageWithCompletedToolCalls(lastMessage)) {
557
- triggerRequest({ messages: updatedMessages });
558
- }
559
- };
560
-
561
- return {
562
- messages,
563
- error,
564
- append,
565
- reload,
566
- stop,
567
- setMessages,
568
- input,
569
- handleSubmit,
570
- isLoading,
571
- data: streamData,
572
- addToolResult,
573
- };
574
- }
@@ -1,179 +0,0 @@
1
- import type {
2
- JSONValue,
3
- RequestOptions,
4
- UseCompletionOptions,
5
- } from '@ai-sdk/ui-utils';
6
- import { callCompletionApi } from '@ai-sdk/ui-utils';
7
- import { useSWR } from 'sswr';
8
- import { Readable, Writable, derived, get, writable } from 'svelte/store';
9
-
10
- export type { UseCompletionOptions };
11
-
12
- export type UseCompletionHelpers = {
13
- /** The current completion result */
14
- completion: Readable<string>;
15
- /** The error object of the API request */
16
- error: Readable<undefined | Error>;
17
- /**
18
- * Send a new prompt to the API endpoint and update the completion state.
19
- */
20
- complete: (
21
- prompt: string,
22
- options?: RequestOptions,
23
- ) => Promise<string | null | undefined>;
24
- /**
25
- * Abort the current API request but keep the generated tokens.
26
- */
27
- stop: () => void;
28
- /**
29
- * Update the `completion` state locally.
30
- */
31
- setCompletion: (completion: string) => void;
32
- /** The current value of the input */
33
- input: Writable<string>;
34
- /**
35
- * Form submission handler to automatically reset input and append a user message
36
- * @example
37
- * ```jsx
38
- * <form onSubmit={handleSubmit}>
39
- * <input onChange={handleInputChange} value={input} />
40
- * </form>
41
- * ```
42
- */
43
- handleSubmit: (event?: { preventDefault?: () => void }) => void;
44
- /** Whether the API request is in progress */
45
- isLoading: Readable<boolean | undefined>;
46
-
47
- /** Additional data added on the server via StreamData */
48
- data: Readable<JSONValue[] | undefined>;
49
- };
50
-
51
- let uniqueId = 0;
52
-
53
- const store: Record<string, any> = {};
54
-
55
- export function useCompletion({
56
- api = '/api/completion',
57
- id,
58
- initialCompletion = '',
59
- initialInput = '',
60
- credentials,
61
- headers,
62
- body,
63
- streamMode,
64
- streamProtocol,
65
- onResponse,
66
- onFinish,
67
- onError,
68
- fetch,
69
- }: UseCompletionOptions = {}): UseCompletionHelpers {
70
- // streamMode is deprecated, use streamProtocol instead.
71
- if (streamMode) {
72
- streamProtocol ??= streamMode === 'text' ? 'text' : undefined;
73
- }
74
-
75
- // Generate an unique id for the completion if not provided.
76
- const completionId = id || `completion-${uniqueId++}`;
77
-
78
- const key = `${api}|${completionId}`;
79
- const {
80
- data,
81
- mutate: originalMutate,
82
- isLoading: isSWRLoading,
83
- } = useSWR<string>(key, {
84
- fetcher: () => store[key] || initialCompletion,
85
- fallbackData: initialCompletion,
86
- });
87
-
88
- const streamData = writable<JSONValue[] | undefined>(undefined);
89
-
90
- const loading = writable<boolean>(false);
91
-
92
- // Force the `data` to be `initialCompletion` if it's `undefined`.
93
- data.set(initialCompletion);
94
-
95
- const mutate = (data: string) => {
96
- store[key] = data;
97
- return originalMutate(data);
98
- };
99
-
100
- // Because of the `fallbackData` option, the `data` will never be `undefined`.
101
- const completion = data as Writable<string>;
102
-
103
- const error = writable<undefined | Error>(undefined);
104
-
105
- let abortController: AbortController | null = null;
106
-
107
- const complete: UseCompletionHelpers['complete'] = async (
108
- prompt: string,
109
- options?: RequestOptions,
110
- ) => {
111
- const existingData = get(streamData);
112
- return callCompletionApi({
113
- api,
114
- prompt,
115
- credentials,
116
- headers: {
117
- ...headers,
118
- ...options?.headers,
119
- },
120
- body: {
121
- ...body,
122
- ...options?.body,
123
- },
124
- streamProtocol,
125
- setCompletion: mutate,
126
- setLoading: loadingState => loading.set(loadingState),
127
- setError: err => error.set(err),
128
- setAbortController: controller => {
129
- abortController = controller;
130
- },
131
- onResponse,
132
- onFinish,
133
- onError,
134
- onData(data) {
135
- streamData.set([...(existingData || []), ...(data || [])]);
136
- },
137
- fetch,
138
- });
139
- };
140
-
141
- const stop = () => {
142
- if (abortController) {
143
- abortController.abort();
144
- abortController = null;
145
- }
146
- };
147
-
148
- const setCompletion = (completion: string) => {
149
- mutate(completion);
150
- };
151
-
152
- const input = writable(initialInput);
153
-
154
- const handleSubmit = (event?: { preventDefault?: () => void }) => {
155
- event?.preventDefault?.();
156
-
157
- const inputValue = get(input);
158
- return inputValue ? complete(inputValue) : undefined;
159
- };
160
-
161
- const isLoading = derived(
162
- [isSWRLoading, loading],
163
- ([$isSWRLoading, $loading]) => {
164
- return $isSWRLoading || $loading;
165
- },
166
- );
167
-
168
- return {
169
- completion,
170
- complete,
171
- error,
172
- stop,
173
- setCompletion,
174
- input,
175
- handleSubmit,
176
- isLoading,
177
- data: streamData,
178
- };
179
- }
package/tsconfig.json DELETED
@@ -1,9 +0,0 @@
1
- {
2
- "extends": "./node_modules/@vercel/ai-tsconfig/react-library.json",
3
- "compilerOptions": {
4
- "target": "ES2018",
5
- "stripInternal": true
6
- },
7
- "include": ["."],
8
- "exclude": ["*/dist", "dist", "build", "node_modules"]
9
- }
package/tsup.config.ts DELETED
@@ -1,13 +0,0 @@
1
- import { defineConfig } from 'tsup';
2
-
3
- export default defineConfig([
4
- {
5
- entry: ['src/index.ts'],
6
- outDir: 'dist',
7
- banner: {},
8
- format: ['cjs', 'esm'],
9
- external: ['vue'],
10
- dts: true,
11
- sourcemap: true,
12
- },
13
- ]);
package/turbo.json DELETED
@@ -1,8 +0,0 @@
1
- {
2
- "extends": ["//"],
3
- "pipeline": {
4
- "build": {
5
- "outputs": ["**/dist/**"]
6
- }
7
- }
8
- }