@ai-sdk/svelte 3.0.0-canary.9 → 3.0.1

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.
Files changed (35) hide show
  1. package/CHANGELOG.md +929 -0
  2. package/README.md +5 -5
  3. package/dist/chat.svelte.d.ts +4 -73
  4. package/dist/chat.svelte.d.ts.map +1 -1
  5. package/dist/chat.svelte.js +23 -243
  6. package/dist/completion.svelte.d.ts +2 -9
  7. package/dist/completion.svelte.d.ts.map +1 -1
  8. package/dist/completion.svelte.js +4 -22
  9. package/dist/context-provider.d.ts.map +1 -1
  10. package/dist/context-provider.js +0 -3
  11. package/dist/index.d.ts +2 -2
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +2 -2
  14. package/dist/structured-object.svelte.d.ts +11 -6
  15. package/dist/structured-object.svelte.d.ts.map +1 -1
  16. package/dist/structured-object.svelte.js +17 -7
  17. package/dist/tests/structured-object-synchronization.svelte.d.ts +2 -2
  18. package/dist/utils.svelte.js +1 -1
  19. package/package.json +8 -8
  20. package/src/chat.svelte.ts +32 -331
  21. package/src/completion.svelte.ts +10 -27
  22. package/src/context-provider.ts +0 -4
  23. package/src/index.ts +3 -12
  24. package/src/structured-object.svelte.ts +36 -13
  25. package/src/utils.svelte.ts +1 -1
  26. package/dist/chat-context.svelte.d.ts +0 -14
  27. package/dist/chat-context.svelte.d.ts.map +0 -1
  28. package/dist/chat-context.svelte.js +0 -13
  29. package/dist/completion-context.svelte.d.ts +0 -15
  30. package/dist/completion-context.svelte.d.ts.map +0 -1
  31. package/dist/tests/chat-synchronization.svelte +0 -12
  32. package/dist/tests/chat-synchronization.svelte.d.ts +0 -11
  33. package/dist/tests/chat-synchronization.svelte.d.ts.map +0 -1
  34. package/src/chat-context.svelte.ts +0 -23
  35. package/src/tests/chat-synchronization.svelte +0 -12
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-sdk/svelte",
3
- "version": "3.0.0-canary.9",
3
+ "version": "3.0.1",
4
4
  "license": "Apache-2.0",
5
5
  "files": [
6
6
  "dist",
@@ -27,8 +27,8 @@
27
27
  "access": "public"
28
28
  },
29
29
  "peerDependencies": {
30
- "svelte": "^5.0.0",
31
- "zod": "^3.23.8"
30
+ "svelte": "^5.31.0",
31
+ "zod": "^3.25.76 || ^4"
32
32
  },
33
33
  "peerDependenciesMeta": {
34
34
  "zod": {
@@ -36,8 +36,8 @@
36
36
  }
37
37
  },
38
38
  "dependencies": {
39
- "ai": "5.0.0-canary.10",
40
- "@ai-sdk/provider-utils": "3.0.0-canary.8"
39
+ "ai": "5.0.1",
40
+ "@ai-sdk/provider-utils": "3.0.0"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@types/node": "20.17.24",
@@ -52,16 +52,16 @@
52
52
  "globals": "^16.0.0",
53
53
  "jsdom": "^26.0.0",
54
54
  "publint": "^0.3.2",
55
- "svelte": "^5.0.0",
55
+ "svelte": "^5.31.0",
56
56
  "svelte-check": "^4.0.0",
57
57
  "typescript": "^5.0.0",
58
58
  "typescript-eslint": "^8.20.0",
59
59
  "vite": "^6.0.0",
60
60
  "vitest": "^3.0.0",
61
- "zod": "3.23.8",
61
+ "zod": "3.25.76",
62
62
  "@vercel/ai-tsconfig": "0.0.0"
63
63
  },
64
- "homepage": "https://sdk.vercel.ai/docs",
64
+ "homepage": "https://ai-sdk.dev/docs",
65
65
  "repository": {
66
66
  "type": "git",
67
67
  "url": "git+https://github.com/vercel/ai.git",
@@ -1,350 +1,51 @@
1
1
  import {
2
- fillMessageParts,
3
- generateId,
2
+ AbstractChat,
3
+ type ChatInit,
4
+ type ChatState,
5
+ type ChatStatus,
6
+ type CreateUIMessage,
4
7
  type UIMessage,
5
- type UseChatOptions,
6
- type JSONValue,
7
- type ChatRequest,
8
- extractMaxToolInvocationStep,
9
- callChatApi,
10
- shouldResubmitMessages,
11
- type Message,
12
- type CreateMessage,
13
- type ChatRequestOptions,
14
- prepareAttachmentsForRequest,
15
- getMessageParts,
16
- updateToolCallResult,
17
- isAssistantMessageWithCompletedToolCalls,
18
8
  } from 'ai';
19
- import { isAbortError } from '@ai-sdk/provider-utils';
20
- import {
21
- KeyedChatStore,
22
- getChatContext,
23
- hasChatContext,
24
- } from './chat-context.svelte.js';
25
- import { untrack } from 'svelte';
26
-
27
- export type ChatOptions = Readonly<
28
- Omit<UseChatOptions, 'keepLastMessageOnError'> & {
29
- /**
30
- * Maximum number of sequential LLM calls (steps), e.g. when you use tool calls.
31
- * Must be at least 1.
32
- * A maximum number is required to prevent infinite loops in the case of misconfigured tools.
33
- * By default, it's set to 1, which means that only a single LLM call is made.
34
- * @default 1
35
- */
36
- maxSteps?: number;
37
- }
38
- >;
39
9
 
40
- export type { CreateMessage, Message, UIMessage };
41
-
42
- export class Chat {
43
- readonly #options: ChatOptions = {};
44
- readonly #api = $derived(this.#options.api ?? '/api/chat');
45
- readonly #generateId = $derived(this.#options.generateId ?? generateId);
46
- readonly #maxSteps = $derived(this.#options.maxSteps ?? 1);
47
- readonly #streamProtocol = $derived(this.#options.streamProtocol ?? 'data');
48
- readonly #keyedStore = $state<KeyedChatStore>()!;
49
- /**
50
- * The id of the chat. If not provided through the constructor, a random ID will be generated
51
- * using the provided `generateId` function, or a built-in function if not provided.
52
- */
53
- readonly id = $derived(this.#options.id ?? this.#generateId());
54
- readonly #store = $derived(this.#keyedStore.get(this.id));
55
- #abortController: AbortController | undefined;
56
-
57
- /**
58
- * Additional data added on the server via StreamData.
59
- *
60
- * This is writable, so you can use it to transform or clear the chat data.
61
- */
62
- get data() {
63
- return this.#store.data;
64
- }
65
- set data(value: JSONValue[] | undefined) {
66
- this.#store.data = value;
67
- }
68
-
69
- /**
70
- * Hook status:
71
- *
72
- * - `submitted`: The message has been sent to the API and we're awaiting the start of the response stream.
73
- * - `streaming`: The response is actively streaming in from the API, receiving chunks of data.
74
- * - `ready`: The full response has been received and processed; a new user message can be submitted.
75
- * - `error`: An error occurred during the API request, preventing successful completion.
76
- */
77
- get status() {
78
- return this.#store.status;
79
- }
80
-
81
- /** The error object of the API request */
82
- get error() {
83
- return this.#store.error;
84
- }
10
+ export type { CreateUIMessage, UIMessage };
85
11
 
86
- /** The current value of the input. Writable, so it can be bound to form inputs. */
87
- input = $state<string>()!;
88
-
89
- /**
90
- * Current messages in the chat.
91
- *
92
- * This is writable, which is useful when you want to edit the messages on the client, and then
93
- * trigger {@link reload} to regenerate the AI response.
94
- */
95
- get messages(): UIMessage[] {
96
- return this.#store.messages;
97
- }
98
- set messages(value: Message[]) {
99
- untrack(() => (this.#store.messages = fillMessageParts(value)));
12
+ export class Chat<
13
+ UI_MESSAGE extends UIMessage = UIMessage,
14
+ > extends AbstractChat<UI_MESSAGE> {
15
+ constructor(init: ChatInit<UI_MESSAGE>) {
16
+ super({
17
+ ...init,
18
+ state: new SvelteChatState(init.messages),
19
+ });
100
20
  }
21
+ }
101
22
 
102
- constructor(options: ChatOptions = {}) {
103
- if (hasChatContext()) {
104
- this.#keyedStore = getChatContext();
105
- } else {
106
- this.#keyedStore = new KeyedChatStore();
107
- }
23
+ class SvelteChatState<UI_MESSAGE extends UIMessage>
24
+ implements ChatState<UI_MESSAGE>
25
+ {
26
+ messages: UI_MESSAGE[];
27
+ status = $state<ChatStatus>('ready');
28
+ error = $state<Error | undefined>(undefined);
108
29
 
109
- this.#options = options;
110
- this.messages = options.initialMessages ?? [];
111
- this.input = options.initialInput ?? '';
30
+ constructor(messages: UI_MESSAGE[] = []) {
31
+ this.messages = $state(messages);
112
32
  }
113
33
 
114
- /**
115
- * Append a user message to the chat list. This triggers the API call to fetch
116
- * the assistant's response.
117
- * @param message The message to append
118
- * @param options Additional options to pass to the API call
119
- */
120
- append = async (
121
- message: Message | CreateMessage,
122
- { data, headers, body, experimental_attachments }: ChatRequestOptions = {},
123
- ) => {
124
- const attachmentsForRequest = await prepareAttachmentsForRequest(
125
- experimental_attachments,
126
- );
127
-
128
- const messages = this.messages.concat({
129
- ...message,
130
- id: message.id ?? this.#generateId(),
131
- createdAt: message.createdAt ?? new Date(),
132
- experimental_attachments:
133
- attachmentsForRequest.length > 0 ? attachmentsForRequest : undefined,
134
- parts: getMessageParts(message),
135
- });
136
-
137
- return this.#triggerRequest({ messages, headers, body, data });
138
- };
139
-
140
- /**
141
- * Reload the last AI chat response for the given chat history. If the last
142
- * message isn't from the assistant, it will request the API to generate a
143
- * new response.
144
- */
145
- reload = async ({ data, headers, body }: ChatRequestOptions = {}) => {
146
- if (this.messages.length === 0) {
147
- return;
148
- }
149
-
150
- const lastMessage = this.messages[this.messages.length - 1];
151
- await this.#triggerRequest({
152
- messages:
153
- lastMessage.role === 'assistant'
154
- ? this.messages.slice(0, -1)
155
- : this.messages,
156
- headers,
157
- body,
158
- data,
159
- });
34
+ setMessages = (messages: UI_MESSAGE[]) => {
35
+ this.messages = messages;
160
36
  };
161
37
 
162
- /**
163
- * Abort the current request immediately, keep the generated tokens if any.
164
- */
165
- stop = () => {
166
- try {
167
- this.#abortController?.abort();
168
- } catch {
169
- // ignore
170
- } finally {
171
- this.#store.status = 'ready';
172
- this.#abortController = undefined;
173
- }
38
+ pushMessage = (message: UI_MESSAGE) => {
39
+ this.messages.push(message);
174
40
  };
175
41
 
176
- /** Form submission handler to automatically reset input and append a user message */
177
- handleSubmit = async (
178
- event?: { preventDefault?: () => void },
179
- options: ChatRequestOptions = {},
180
- ) => {
181
- event?.preventDefault?.();
182
- if (!this.input && !options.allowEmptySubmit) return;
183
-
184
- const attachmentsForRequest = await prepareAttachmentsForRequest(
185
- options.experimental_attachments,
186
- );
187
-
188
- const messages = this.messages.concat({
189
- id: this.#generateId(),
190
- createdAt: new Date(),
191
- role: 'user',
192
- content: this.input,
193
- experimental_attachments:
194
- attachmentsForRequest.length > 0 ? attachmentsForRequest : undefined,
195
- parts: [{ type: 'text', text: this.input }],
196
- });
197
-
198
- const chatRequest: ChatRequest = {
199
- messages,
200
- headers: options.headers,
201
- body: options.body,
202
- data: options.data,
203
- };
204
-
205
- const request = this.#triggerRequest(chatRequest);
206
- this.input = '';
207
- await request;
42
+ popMessage = () => {
43
+ this.messages.pop();
208
44
  };
209
45
 
210
- addToolResult = async ({
211
- toolCallId,
212
- result,
213
- }: {
214
- toolCallId: string;
215
- result: unknown;
216
- }) => {
217
- updateToolCallResult({
218
- messages: this.messages,
219
- toolCallId,
220
- toolResult: result,
221
- });
222
-
223
- // when the request is ongoing, the auto-submit will be triggered after the request is finished
224
- if (
225
- this.#store.status === 'submitted' ||
226
- this.#store.status === 'streaming'
227
- ) {
228
- return;
229
- }
230
-
231
- const lastMessage = this.messages[this.messages.length - 1];
232
- if (isAssistantMessageWithCompletedToolCalls(lastMessage)) {
233
- await this.#triggerRequest({ messages: this.messages });
234
- }
46
+ replaceMessage = (index: number, message: UI_MESSAGE) => {
47
+ this.messages[index] = message;
235
48
  };
236
49
 
237
- #triggerRequest = async (chatRequest: ChatRequest) => {
238
- this.#store.status = 'submitted';
239
- this.#store.error = undefined;
240
-
241
- const messages = fillMessageParts(chatRequest.messages);
242
- const messageCount = messages.length;
243
- const maxStep = extractMaxToolInvocationStep(
244
- messages[messages.length - 1]?.toolInvocations,
245
- );
246
-
247
- try {
248
- const abortController = new AbortController();
249
- this.#abortController = abortController;
250
-
251
- // Optimistically update messages
252
- this.messages = messages;
253
-
254
- const constructedMessagesPayload = this.#options.sendExtraMessageFields
255
- ? messages
256
- : messages.map(
257
- ({
258
- role,
259
- content,
260
- experimental_attachments,
261
- data,
262
- annotations,
263
- toolInvocations,
264
- parts,
265
- }) => ({
266
- role,
267
- content,
268
- ...(experimental_attachments !== undefined && {
269
- experimental_attachments,
270
- }),
271
- ...(data !== undefined && { data }),
272
- ...(annotations !== undefined && { annotations }),
273
- ...(toolInvocations !== undefined && { toolInvocations }),
274
- ...(parts !== undefined && { parts }),
275
- }),
276
- );
277
-
278
- const existingData = this.data ?? [];
279
- await callChatApi({
280
- api: this.#api,
281
- body: {
282
- id: this.id,
283
- messages: constructedMessagesPayload,
284
- data: chatRequest.data,
285
- ...$state.snapshot(this.#options.body),
286
- ...chatRequest.body,
287
- },
288
- streamProtocol: this.#streamProtocol,
289
- credentials: this.#options.credentials,
290
- headers: {
291
- ...this.#options.headers,
292
- ...chatRequest.headers,
293
- },
294
- abortController: () => abortController,
295
- restoreMessagesOnFailure: () => {},
296
- onResponse: this.#options.onResponse,
297
- onUpdate: ({ message, data, replaceLastMessage }) => {
298
- this.#store.status = 'streaming';
299
-
300
- this.messages = messages;
301
- if (replaceLastMessage) {
302
- this.messages[this.messages.length - 1] = message;
303
- } else {
304
- this.messages.push(message);
305
- }
306
-
307
- if (data?.length) {
308
- this.data = existingData;
309
- this.data.push(...data);
310
- }
311
- },
312
- onToolCall: this.#options.onToolCall,
313
- onFinish: this.#options.onFinish,
314
- generateId: this.#generateId,
315
- fetch: this.#options.fetch,
316
- // callChatApi calls structuredClone on the message
317
- lastMessage: $state.snapshot(this.messages[this.messages.length - 1]),
318
- });
319
-
320
- this.#abortController = undefined;
321
- this.#store.status = 'ready';
322
- } catch (error) {
323
- if (isAbortError(error)) {
324
- return;
325
- }
326
-
327
- const coalescedError =
328
- error instanceof Error ? error : new Error(String(error));
329
- if (this.#options.onError) {
330
- this.#options.onError(coalescedError);
331
- }
332
-
333
- this.#store.status = 'error';
334
- this.#store.error = coalescedError;
335
- }
336
-
337
- // auto-submit when all tool calls in the last assistant message have results
338
- // and assistant has not answered yet
339
- if (
340
- shouldResubmitMessages({
341
- originalMaxToolInvocationStep: maxStep,
342
- originalMessageCount: messageCount,
343
- maxSteps: this.#maxSteps,
344
- messages: this.messages,
345
- })
346
- ) {
347
- await this.#triggerRequest({ messages: this.messages });
348
- }
349
- };
50
+ snapshot = <T>(thing: T): T => $state.snapshot(thing) as T;
350
51
  }
@@ -1,9 +1,8 @@
1
1
  import {
2
+ callCompletionApi,
2
3
  generateId,
4
+ type CompletionRequestOptions,
3
5
  type UseCompletionOptions,
4
- type JSONValue,
5
- type RequestOptions,
6
- callCompletionApi,
7
6
  } from 'ai';
8
7
  import {
9
8
  KeyedCompletionStore,
@@ -30,18 +29,6 @@ export class Completion {
30
29
  this.#store.completions.set(this.#id, value);
31
30
  }
32
31
 
33
- /**
34
- * Additional data added on the server via StreamData.
35
- *
36
- * This is writable, so you can use it to transform or clear the chat data.
37
- */
38
- get data() {
39
- return this.#store.data;
40
- }
41
- set data(value: JSONValue[]) {
42
- this.#store.data = value;
43
- }
44
-
45
32
  /** The error object of the API request */
46
33
  get error() {
47
34
  return this.#store.error;
@@ -58,12 +45,9 @@ export class Completion {
58
45
  }
59
46
 
60
47
  constructor(options: CompletionOptions = {}) {
61
- if (hasCompletionContext()) {
62
- this.#keyedStore = getCompletionContext();
63
- } else {
64
- this.#keyedStore = new KeyedCompletionStore();
65
- }
66
-
48
+ this.#keyedStore = hasCompletionContext()
49
+ ? getCompletionContext()
50
+ : new KeyedCompletionStore();
67
51
  this.#options = options;
68
52
  this.completion = options.initialCompletion ?? '';
69
53
  this.input = options.initialInput ?? '';
@@ -86,7 +70,7 @@ export class Completion {
86
70
  /**
87
71
  * Send a new prompt to the API endpoint and update the completion state.
88
72
  */
89
- complete = async (prompt: string, options?: RequestOptions) =>
73
+ complete = async (prompt: string, options?: CompletionRequestOptions) =>
90
74
  this.#triggerRequest(prompt, options);
91
75
 
92
76
  /** Form submission handler to automatically reset input and call the completion API */
@@ -97,7 +81,10 @@ export class Completion {
97
81
  }
98
82
  };
99
83
 
100
- #triggerRequest = async (prompt: string, options?: RequestOptions) => {
84
+ #triggerRequest = async (
85
+ prompt: string,
86
+ options?: CompletionRequestOptions,
87
+ ) => {
101
88
  return callCompletionApi({
102
89
  api: this.#api,
103
90
  prompt,
@@ -113,9 +100,6 @@ export class Completion {
113
100
  setCompletion: completion => {
114
101
  this.completion = completion;
115
102
  },
116
- onData: data => {
117
- this.data.push(...data);
118
- },
119
103
  setLoading: loading => {
120
104
  this.#store.loading = loading;
121
105
  },
@@ -125,7 +109,6 @@ export class Completion {
125
109
  setAbortController: abortController => {
126
110
  this.#abortController = abortController ?? undefined;
127
111
  },
128
- onResponse: this.#options.onResponse,
129
112
  onFinish: this.#options.onFinish,
130
113
  onError: this.#options.onError,
131
114
  });
@@ -1,4 +1,3 @@
1
- import { KeyedChatStore, setChatContext } from './chat-context.svelte.js';
2
1
  import {
3
2
  KeyedCompletionStore,
4
3
  setCompletionContext,
@@ -9,9 +8,6 @@ import {
9
8
  } from './structured-object-context.svelte.js';
10
9
 
11
10
  export function createAIContext() {
12
- const chatStore = new KeyedChatStore();
13
- setChatContext(chatStore);
14
-
15
11
  const completionStore = new KeyedCompletionStore();
16
12
  setCompletionContext(completionStore);
17
13
 
package/src/index.ts CHANGED
@@ -1,16 +1,7 @@
1
- export {
2
- Chat,
3
- type ChatOptions,
4
- type CreateMessage,
5
- type Message,
6
- type UIMessage,
7
- } from './chat.svelte.js';
8
-
1
+ export { Chat, type CreateUIMessage, type UIMessage } from './chat.svelte.js';
2
+ export { Completion, type CompletionOptions } from './completion.svelte.js';
3
+ export { createAIContext } from './context-provider.js';
9
4
  export {
10
5
  StructuredObject as Experimental_StructuredObject,
11
6
  type Experimental_StructuredObjectOptions,
12
7
  } from './structured-object.svelte.js';
13
-
14
- export { Completion, type CompletionOptions } from './completion.svelte.js';
15
-
16
- export { createAIContext } from './context-provider.js';
@@ -3,6 +3,7 @@ import {
3
3
  isAbortError,
4
4
  safeValidateTypes,
5
5
  type FetchFunction,
6
+ type InferSchema,
6
7
  } from '@ai-sdk/provider-utils';
7
8
  import {
8
9
  asSchema,
@@ -11,7 +12,8 @@ import {
11
12
  type DeepPartial,
12
13
  type Schema,
13
14
  } from 'ai';
14
- import { type z } from 'zod';
15
+ import type * as z3 from 'zod/v3';
16
+ import type * as z4 from 'zod/v4';
15
17
  import {
16
18
  getStructuredObjectContext,
17
19
  hasStructuredObjectContext,
@@ -19,7 +21,10 @@ import {
19
21
  type StructuredObjectStore,
20
22
  } from './structured-object-context.svelte.js';
21
23
 
22
- export type Experimental_StructuredObjectOptions<RESULT> = {
24
+ export type Experimental_StructuredObjectOptions<
25
+ SCHEMA extends z3.Schema | z4.core.$ZodType | Schema,
26
+ RESULT = InferSchema<SCHEMA>,
27
+ > = {
23
28
  /**
24
29
  * The API endpoint. It should stream JSON that matches the schema as chunked text.
25
30
  */
@@ -28,7 +33,7 @@ export type Experimental_StructuredObjectOptions<RESULT> = {
28
33
  /**
29
34
  * A Zod schema that defines the shape of the complete object.
30
35
  */
31
- schema: z.Schema<RESULT, z.ZodTypeDef, unknown> | Schema<RESULT>;
36
+ schema: SCHEMA;
32
37
 
33
38
  /**
34
39
  * An unique identifier. If not provided, a random one will be
@@ -82,9 +87,13 @@ export type Experimental_StructuredObjectOptions<RESULT> = {
82
87
  credentials?: RequestCredentials;
83
88
  };
84
89
 
85
- export class StructuredObject<RESULT, INPUT = unknown> {
86
- #options: Experimental_StructuredObjectOptions<RESULT> =
87
- {} as Experimental_StructuredObjectOptions<RESULT>;
90
+ export class StructuredObject<
91
+ SCHEMA extends z3.Schema | z4.core.$ZodType | Schema,
92
+ RESULT = InferSchema<SCHEMA>,
93
+ INPUT = unknown,
94
+ > {
95
+ #options: Experimental_StructuredObjectOptions<SCHEMA, RESULT> =
96
+ {} as Experimental_StructuredObjectOptions<SCHEMA, RESULT>;
88
97
  readonly #id = $derived(this.#options.id ?? generateId());
89
98
  readonly #keyedStore = $state<KeyedStructuredObjectStore>()!;
90
99
  readonly #store = $derived(
@@ -114,7 +123,7 @@ export class StructuredObject<RESULT, INPUT = unknown> {
114
123
  return this.#store.loading;
115
124
  }
116
125
 
117
- constructor(options: Experimental_StructuredObjectOptions<RESULT>) {
126
+ constructor(options: Experimental_StructuredObjectOptions<SCHEMA, RESULT>) {
118
127
  if (hasStructuredObjectContext()) {
119
128
  this.#keyedStore = getStructuredObjectContext();
120
129
  } else {
@@ -143,9 +152,9 @@ export class StructuredObject<RESULT, INPUT = unknown> {
143
152
  */
144
153
  submit = async (input: INPUT) => {
145
154
  try {
146
- this.#store.object = undefined; // reset the data
155
+ this.#clearObject();
156
+
147
157
  this.#store.loading = true;
148
- this.#store.error = undefined;
149
158
 
150
159
  const abortController = new AbortController();
151
160
  this.#abortController = abortController;
@@ -177,13 +186,13 @@ export class StructuredObject<RESULT, INPUT = unknown> {
177
186
 
178
187
  await response.body.pipeThrough(new TextDecoderStream()).pipeTo(
179
188
  new WritableStream<string>({
180
- write: chunk => {
189
+ write: async chunk => {
181
190
  if (abortController?.signal.aborted) {
182
191
  throw new DOMException('Stream aborted', 'AbortError');
183
192
  }
184
193
  accumulatedText += chunk;
185
194
 
186
- const { value } = parsePartialJson(accumulatedText);
195
+ const { value } = await parsePartialJson(accumulatedText);
187
196
  const currentObject = value as DeepPartial<RESULT>;
188
197
 
189
198
  if (!isDeepEqualData(latestObject, currentObject)) {
@@ -193,12 +202,12 @@ export class StructuredObject<RESULT, INPUT = unknown> {
193
202
  }
194
203
  },
195
204
 
196
- close: () => {
205
+ close: async () => {
197
206
  this.#store.loading = false;
198
207
  this.#abortController = undefined;
199
208
 
200
209
  if (this.#options.onFinish != null) {
201
- const validationResult = safeValidateTypes({
210
+ const validationResult = await safeValidateTypes({
202
211
  value: latestObject,
203
212
  schema: asSchema(this.#options.schema),
204
213
  });
@@ -227,4 +236,18 @@ export class StructuredObject<RESULT, INPUT = unknown> {
227
236
  this.#store.error = coalescedError;
228
237
  }
229
238
  };
239
+
240
+ /**
241
+ * Clears the object state.
242
+ */
243
+ clear = () => {
244
+ this.stop();
245
+ this.#clearObject();
246
+ };
247
+
248
+ #clearObject = () => {
249
+ this.#store.object = undefined;
250
+ this.#store.error = undefined;
251
+ this.#store.loading = false;
252
+ };
230
253
  }
@@ -1,4 +1,4 @@
1
- import { hasContext, getContext, setContext, untrack } from 'svelte';
1
+ import { getContext, hasContext, setContext, untrack } from 'svelte';
2
2
  import { SvelteMap } from 'svelte/reactivity';
3
3
 
4
4
  export function createContext<T>(name: string) {
@@ -1,14 +0,0 @@
1
- import type { JSONValue, UIMessage } from 'ai';
2
- import { KeyedStore } from './utils.svelte.js';
3
- declare class ChatStore {
4
- messages: UIMessage[];
5
- data: JSONValue[] | undefined;
6
- status: "submitted" | "streaming" | "ready" | "error";
7
- error: Error | undefined;
8
- }
9
- export declare class KeyedChatStore extends KeyedStore<ChatStore> {
10
- constructor(value?: Iterable<readonly [string, ChatStore]> | null | undefined);
11
- }
12
- export declare const hasChatContext: () => boolean, getChatContext: () => KeyedChatStore, setChatContext: (value: KeyedChatStore) => KeyedChatStore;
13
- export {};
14
- //# sourceMappingURL=chat-context.svelte.d.ts.map