@ai-sdk/react 2.0.0-canary.20 → 2.0.0-canary.22

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/dist/index.mjs CHANGED
@@ -1,306 +1,154 @@
1
1
  // src/use-chat.ts
2
2
  import {
3
- callChatApi,
4
3
  convertFileListToFileUIParts,
5
- extractMaxToolInvocationStep,
6
- generateId as generateIdFunc,
7
- getToolInvocations,
8
- isAssistantMessageWithCompletedToolCalls,
9
- shouldResubmitMessages,
10
- updateToolCallResult
4
+ defaultChatStore,
5
+ generateId as generateIdFunc
11
6
  } from "ai";
12
- import { useCallback, useEffect as useEffect2, useMemo, useRef, useState as useState2 } from "react";
13
- import useSWR from "swr";
14
-
15
- // src/throttle.ts
16
- import throttleFunction from "throttleit";
17
- function throttle(fn, waitMs) {
18
- return waitMs != null ? throttleFunction(fn, waitMs) : fn;
19
- }
20
-
21
- // src/util/use-stable-value.ts
22
- import { isDeepEqualData } from "ai";
23
- import { useEffect, useState } from "react";
24
- function useStableValue(latestValue) {
25
- const [value, setValue] = useState(latestValue);
26
- useEffect(() => {
27
- if (!isDeepEqualData(latestValue, value)) {
28
- setValue(latestValue);
29
- }
30
- }, [latestValue, value]);
31
- return value;
32
- }
33
-
34
- // src/use-chat.ts
7
+ import { useCallback, useRef, useState, useSyncExternalStore } from "react";
35
8
  function useChat({
36
- api = "/api/chat",
37
9
  id,
38
- initialMessages,
39
10
  initialInput = "",
40
11
  onToolCall,
41
- experimental_prepareRequestBody,
42
- maxSteps = 1,
43
- streamProtocol = "data",
44
- onResponse,
45
12
  onFinish,
46
13
  onError,
47
- credentials,
48
- headers,
49
- body,
50
14
  generateId = generateIdFunc,
51
- fetch: fetch2,
52
15
  experimental_throttle: throttleWaitMs,
53
- messageMetadataSchema
16
+ chatStore: chatStoreArg
54
17
  } = {}) {
55
- const [hookId] = useState2(generateId);
18
+ const [hookId] = useState(generateId);
56
19
  const chatId = id != null ? id : hookId;
57
- const chatKey = typeof api === "string" ? [api, chatId] : chatId;
58
- const stableInitialMessages = useStableValue(initialMessages != null ? initialMessages : []);
59
- const processedInitialMessages = useMemo(
60
- () => stableInitialMessages,
61
- [stableInitialMessages]
62
- );
63
- const { data: messages, mutate } = useSWR(
64
- [chatKey, "messages"],
65
- null,
66
- { fallbackData: processedInitialMessages }
20
+ const chatStore = useRef(
21
+ chatStoreArg != null ? chatStoreArg : defaultChatStore({
22
+ api: "/api/chat",
23
+ generateId
24
+ })
67
25
  );
68
- const messagesRef = useRef(messages || []);
69
- useEffect2(() => {
70
- messagesRef.current = messages || [];
71
- }, [messages]);
72
- const { data: status = "ready", mutate: mutateStatus } = useSWR([chatKey, "status"], null);
73
- const { data: error = void 0, mutate: setError } = useSWR([chatKey, "error"], null);
74
- const abortControllerRef = useRef(null);
75
- const extraMetadataRef = useRef({
76
- credentials,
77
- headers,
78
- body
79
- });
80
- useEffect2(() => {
81
- extraMetadataRef.current = {
82
- credentials,
83
- headers,
84
- body
85
- };
86
- }, [credentials, headers, body]);
87
- const triggerRequest = useCallback(
88
- async (chatRequest, requestType = "generate") => {
89
- var _a;
90
- mutateStatus("submitted");
91
- setError(void 0);
92
- const chatMessages = chatRequest.messages;
93
- const messageCount = chatMessages.length;
94
- const maxStep = extractMaxToolInvocationStep(
95
- getToolInvocations(chatMessages[chatMessages.length - 1])
96
- );
97
- try {
98
- const abortController = new AbortController();
99
- abortControllerRef.current = abortController;
100
- const throttledMutate = throttle(mutate, throttleWaitMs);
101
- throttledMutate(chatMessages, false);
102
- await callChatApi({
103
- api,
104
- body: (_a = experimental_prepareRequestBody == null ? void 0 : experimental_prepareRequestBody({
105
- id: chatId,
106
- messages: chatMessages,
107
- requestData: chatRequest.data,
108
- requestBody: chatRequest.body
109
- })) != null ? _a : {
110
- id: chatId,
111
- messages: chatMessages,
112
- data: chatRequest.data,
113
- ...extraMetadataRef.current.body,
114
- ...chatRequest.body
115
- },
116
- streamProtocol,
117
- credentials: extraMetadataRef.current.credentials,
118
- headers: {
119
- ...extraMetadataRef.current.headers,
120
- ...chatRequest.headers
121
- },
122
- abortController: () => abortControllerRef.current,
123
- onResponse,
124
- onUpdate({ message }) {
125
- mutateStatus("streaming");
126
- const replaceLastMessage = message.id === chatMessages[chatMessages.length - 1].id;
127
- throttledMutate(
128
- [
129
- ...replaceLastMessage ? chatMessages.slice(0, chatMessages.length - 1) : chatMessages,
130
- message
131
- ],
132
- false
133
- );
134
- },
135
- onToolCall,
136
- onFinish,
137
- generateId,
138
- fetch: fetch2,
139
- lastMessage: chatMessages[chatMessages.length - 1],
140
- requestType,
141
- messageMetadataSchema
142
- });
143
- abortControllerRef.current = null;
144
- mutateStatus("ready");
145
- } catch (err) {
146
- if (err.name === "AbortError") {
147
- abortControllerRef.current = null;
148
- mutateStatus("ready");
149
- return null;
150
- }
151
- if (onError && err instanceof Error) {
152
- onError(err);
26
+ if (!chatStore.current.hasChat(chatId)) {
27
+ chatStore.current.addChat(chatId, []);
28
+ }
29
+ const subscribe = useCallback(
30
+ ({
31
+ onStoreChange,
32
+ eventType
33
+ }) => {
34
+ return chatStore.current.subscribe({
35
+ onChatChanged: (event) => {
36
+ if (event.chatId !== chatId || event.type !== eventType) {
37
+ return;
38
+ }
39
+ onStoreChange();
153
40
  }
154
- setError(err);
155
- mutateStatus("error");
156
- }
157
- const messages2 = messagesRef.current;
158
- if (shouldResubmitMessages({
159
- originalMaxToolInvocationStep: maxStep,
160
- originalMessageCount: messageCount,
161
- maxSteps,
162
- messages: messages2
163
- })) {
164
- await triggerRequest({ messages: messages2 });
165
- }
41
+ });
166
42
  },
167
- [
168
- mutate,
169
- mutateStatus,
170
- api,
171
- extraMetadataRef,
172
- onResponse,
173
- onFinish,
174
- onError,
175
- setError,
176
- streamProtocol,
177
- experimental_prepareRequestBody,
178
- onToolCall,
179
- maxSteps,
180
- messagesRef,
181
- abortControllerRef,
182
- generateId,
183
- fetch2,
184
- throttleWaitMs,
185
- chatId,
186
- messageMetadataSchema
187
- ]
43
+ [chatStore, chatId]
188
44
  );
189
- const append = useCallback(
190
- (message, { data, headers: headers2, body: body2 } = {}) => {
191
- var _a;
192
- return triggerRequest({
193
- messages: messagesRef.current.concat({
194
- ...message,
195
- id: (_a = message.id) != null ? _a : generateId()
196
- }),
197
- headers: headers2,
198
- body: body2,
199
- data
45
+ const addToolResult = useCallback(
46
+ (options) => chatStore.current.addToolResult({ chatId, ...options }),
47
+ [chatStore, chatId]
48
+ );
49
+ const stopStream = useCallback(() => {
50
+ chatStore.current.stopStream({ chatId });
51
+ }, [chatStore, chatId]);
52
+ const error = useSyncExternalStore(
53
+ (callback) => subscribe({
54
+ onStoreChange: callback,
55
+ eventType: "chat-status-changed"
56
+ }),
57
+ () => chatStore.current.getError(chatId),
58
+ () => chatStore.current.getError(chatId)
59
+ );
60
+ const status = useSyncExternalStore(
61
+ (callback) => subscribe({
62
+ onStoreChange: callback,
63
+ eventType: "chat-status-changed"
64
+ }),
65
+ () => chatStore.current.getStatus(chatId),
66
+ () => chatStore.current.getStatus(chatId)
67
+ );
68
+ const messages = useSyncExternalStore(
69
+ (callback) => {
70
+ return subscribe({
71
+ onStoreChange: callback,
72
+ eventType: "chat-messages-changed"
200
73
  });
201
74
  },
202
- [triggerRequest, generateId]
75
+ () => chatStore.current.getMessages(chatId),
76
+ () => chatStore.current.getMessages(chatId)
77
+ );
78
+ const append = useCallback(
79
+ (message, { headers, body } = {}) => chatStore.current.submitMessage({
80
+ chatId,
81
+ message,
82
+ headers,
83
+ body,
84
+ onError,
85
+ onToolCall,
86
+ onFinish
87
+ }),
88
+ [chatStore, chatId, onError, onToolCall, onFinish]
203
89
  );
204
90
  const reload = useCallback(
205
- async ({ data, headers: headers2, body: body2 } = {}) => {
206
- const messages2 = messagesRef.current;
207
- if (messages2.length === 0) {
208
- return null;
209
- }
210
- const lastMessage = messages2[messages2.length - 1];
211
- return triggerRequest({
212
- messages: lastMessage.role === "assistant" ? messages2.slice(0, -1) : messages2,
213
- headers: headers2,
214
- body: body2,
215
- data
216
- });
217
- },
218
- [triggerRequest]
91
+ async ({ headers, body } = {}) => chatStore.current.resubmitLastUserMessage({
92
+ chatId,
93
+ headers,
94
+ body,
95
+ onError,
96
+ onToolCall,
97
+ onFinish
98
+ }),
99
+ [chatStore, chatId, onError, onToolCall, onFinish]
100
+ );
101
+ const stop = useCallback(() => stopStream(), [stopStream]);
102
+ const experimental_resume = useCallback(
103
+ async () => chatStore.current.resumeStream({
104
+ chatId,
105
+ onError,
106
+ onToolCall,
107
+ onFinish
108
+ }),
109
+ [chatStore, chatId, onError, onToolCall, onFinish]
219
110
  );
220
- const stop = useCallback(() => {
221
- if (abortControllerRef.current) {
222
- abortControllerRef.current.abort();
223
- abortControllerRef.current = null;
224
- }
225
- }, []);
226
- const experimental_resume = useCallback(async () => {
227
- const messages2 = messagesRef.current;
228
- triggerRequest({ messages: messages2 }, "resume");
229
- }, [triggerRequest]);
230
111
  const setMessages = useCallback(
231
- (messages2) => {
232
- if (typeof messages2 === "function") {
233
- messages2 = messages2(messagesRef.current);
112
+ (messagesParam) => {
113
+ if (typeof messagesParam === "function") {
114
+ messagesParam = messagesParam(messages);
234
115
  }
235
- mutate(messages2, false);
236
- messagesRef.current = messages2;
116
+ chatStore.current.setMessages({
117
+ id: chatId,
118
+ messages: messagesParam
119
+ });
237
120
  },
238
- [mutate]
121
+ [chatId, messages]
239
122
  );
240
- const [input, setInput] = useState2(initialInput);
123
+ const [input, setInput] = useState(initialInput);
241
124
  const handleSubmit = useCallback(
242
- async (event, options = {}, metadata) => {
125
+ async (event, options = {}) => {
243
126
  var _a;
244
127
  (_a = event == null ? void 0 : event.preventDefault) == null ? void 0 : _a.call(event);
245
- if (!input && !options.allowEmptySubmit)
246
- return;
247
- if (metadata) {
248
- extraMetadataRef.current = {
249
- ...extraMetadataRef.current,
250
- ...metadata
251
- };
252
- }
253
128
  const fileParts = Array.isArray(options == null ? void 0 : options.files) ? options.files : await convertFileListToFileUIParts(options == null ? void 0 : options.files);
254
- triggerRequest({
255
- messages: messagesRef.current.concat({
129
+ if (!input && fileParts.length === 0)
130
+ return;
131
+ append(
132
+ {
256
133
  id: generateId(),
257
134
  role: "user",
258
135
  metadata: void 0,
259
136
  parts: [...fileParts, { type: "text", text: input }]
260
- }),
261
- headers: options.headers,
262
- body: options.body,
263
- data: options.data
264
- });
137
+ },
138
+ {
139
+ headers: options.headers,
140
+ body: options.body
141
+ }
142
+ );
265
143
  setInput("");
266
144
  },
267
- [input, generateId, triggerRequest]
145
+ [input, generateId, append, messages]
268
146
  );
269
147
  const handleInputChange = (e) => {
270
148
  setInput(e.target.value);
271
149
  };
272
- const addToolResult = useCallback(
273
- ({ toolCallId, result }) => {
274
- const currentMessages = messagesRef.current;
275
- updateToolCallResult({
276
- messages: currentMessages,
277
- toolCallId,
278
- toolResult: result
279
- });
280
- mutate(
281
- [
282
- ...currentMessages.slice(0, currentMessages.length - 1),
283
- {
284
- ...currentMessages[currentMessages.length - 1],
285
- // @ts-ignore
286
- // update the revisionId to trigger a re-render
287
- revisionId: generateId()
288
- }
289
- ],
290
- false
291
- );
292
- if (status === "submitted" || status === "streaming") {
293
- return;
294
- }
295
- const lastMessage = currentMessages[currentMessages.length - 1];
296
- if (isAssistantMessageWithCompletedToolCalls(lastMessage)) {
297
- triggerRequest({ messages: currentMessages });
298
- }
299
- },
300
- [mutate, status, triggerRequest, generateId]
301
- );
302
150
  return {
303
- messages: messages != null ? messages : [],
151
+ messages,
304
152
  id: chatId,
305
153
  setMessages,
306
154
  error,
@@ -312,7 +160,6 @@ function useChat({
312
160
  setInput,
313
161
  handleInputChange,
314
162
  handleSubmit,
315
- isLoading: status === "submitted" || status === "streaming",
316
163
  status,
317
164
  addToolResult
318
165
  };
@@ -322,8 +169,16 @@ function useChat({
322
169
  import {
323
170
  callCompletionApi
324
171
  } from "ai";
325
- import { useCallback as useCallback2, useEffect as useEffect3, useId, useRef as useRef2, useState as useState3 } from "react";
326
- import useSWR2 from "swr";
172
+ import { useCallback as useCallback2, useEffect, useId, useRef as useRef2, useState as useState2 } from "react";
173
+ import useSWR from "swr";
174
+
175
+ // src/throttle.ts
176
+ import throttleFunction from "throttleit";
177
+ function throttle(fn, waitMs) {
178
+ return waitMs != null ? throttleFunction(fn, waitMs) : fn;
179
+ }
180
+
181
+ // src/use-completion.ts
327
182
  function useCompletion({
328
183
  api = "/api/completion",
329
184
  id,
@@ -334,29 +189,28 @@ function useCompletion({
334
189
  body,
335
190
  streamProtocol = "data",
336
191
  fetch: fetch2,
337
- onResponse,
338
192
  onFinish,
339
193
  onError,
340
194
  experimental_throttle: throttleWaitMs
341
195
  } = {}) {
342
196
  const hookId = useId();
343
197
  const completionId = id || hookId;
344
- const { data, mutate } = useSWR2([api, completionId], null, {
198
+ const { data, mutate } = useSWR([api, completionId], null, {
345
199
  fallbackData: initialCompletion
346
200
  });
347
- const { data: isLoading = false, mutate: mutateLoading } = useSWR2(
201
+ const { data: isLoading = false, mutate: mutateLoading } = useSWR(
348
202
  [completionId, "loading"],
349
203
  null
350
204
  );
351
- const [error, setError] = useState3(void 0);
205
+ const [error, setError] = useState2(void 0);
352
206
  const completion = data;
353
- const [abortController, setAbortController] = useState3(null);
207
+ const [abortController, setAbortController] = useState2(null);
354
208
  const extraMetadataRef = useRef2({
355
209
  credentials,
356
210
  headers,
357
211
  body
358
212
  });
359
- useEffect3(() => {
213
+ useEffect(() => {
360
214
  extraMetadataRef.current = {
361
215
  credentials,
362
216
  headers,
@@ -383,7 +237,6 @@ function useCompletion({
383
237
  setLoading: mutateLoading,
384
238
  setError,
385
239
  setAbortController,
386
- onResponse,
387
240
  onFinish,
388
241
  onError
389
242
  }),
@@ -393,7 +246,6 @@ function useCompletion({
393
246
  api,
394
247
  extraMetadataRef,
395
248
  setAbortController,
396
- onResponse,
397
249
  onFinish,
398
250
  onError,
399
251
  setError,
@@ -420,7 +272,7 @@ function useCompletion({
420
272
  },
421
273
  [triggerRequest]
422
274
  );
423
- const [input, setInput] = useState3(initialInput);
275
+ const [input, setInput] = useState2(initialInput);
424
276
  const handleSubmit = useCallback2(
425
277
  (event) => {
426
278
  var _a;
@@ -456,11 +308,11 @@ import {
456
308
  } from "@ai-sdk/provider-utils";
457
309
  import {
458
310
  asSchema,
459
- isDeepEqualData as isDeepEqualData2,
311
+ isDeepEqualData,
460
312
  parsePartialJson
461
313
  } from "ai";
462
- import { useCallback as useCallback3, useId as useId2, useRef as useRef3, useState as useState4 } from "react";
463
- import useSWR3 from "swr";
314
+ import { useCallback as useCallback3, useId as useId2, useRef as useRef3, useState as useState3 } from "react";
315
+ import useSWR2 from "swr";
464
316
  var getOriginalFetch = () => fetch;
465
317
  function useObject({
466
318
  api,
@@ -476,13 +328,13 @@ function useObject({
476
328
  }) {
477
329
  const hookId = useId2();
478
330
  const completionId = id != null ? id : hookId;
479
- const { data, mutate } = useSWR3(
331
+ const { data, mutate } = useSWR2(
480
332
  [api, completionId],
481
333
  null,
482
334
  { fallbackData: initialValue }
483
335
  );
484
- const [error, setError] = useState4(void 0);
485
- const [isLoading, setIsLoading] = useState4(false);
336
+ const [error, setError] = useState3(void 0);
337
+ const [isLoading, setIsLoading] = useState3(false);
486
338
  const abortControllerRef = useRef3(null);
487
339
  const stop = useCallback3(() => {
488
340
  var _a;
@@ -529,7 +381,7 @@ function useObject({
529
381
  accumulatedText += chunk;
530
382
  const { value } = await parsePartialJson(accumulatedText);
531
383
  const currentObject = value;
532
- if (!isDeepEqualData2(latestObject, currentObject)) {
384
+ if (!isDeepEqualData(latestObject, currentObject)) {
533
385
  latestObject = currentObject;
534
386
  mutate(currentObject);
535
387
  }