@assistant-ui/ai-sdk 0.0.6 → 0.0.8

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 (107) hide show
  1. package/README.md +1 -1
  2. package/dist/adapters/aiSDKFormatAdapter.d.ts +2 -2
  3. package/dist/adapters/aiSDKFormatAdapter.d.ts.map +1 -0
  4. package/dist/adapters/vercelAttachmentAdapter.d.ts +2 -5
  5. package/dist/adapters/vercelAttachmentAdapter.d.ts.map +1 -1
  6. package/dist/adapters/vercelAttachmentAdapter.js +3 -3
  7. package/dist/adapters/vercelAttachmentAdapter.js.map +1 -1
  8. package/dist/aiSDKExtras.d.ts +6 -9
  9. package/dist/aiSDKExtras.d.ts.map +1 -1
  10. package/dist/converters/convertMessage.d.ts +34 -25
  11. package/dist/converters/convertMessage.d.ts.map +1 -1
  12. package/dist/converters/convertMessage.js +78 -8
  13. package/dist/converters/convertMessage.js.map +1 -1
  14. package/dist/converters/modelContentEnvelope.d.ts +10 -12
  15. package/dist/converters/modelContentEnvelope.d.ts.map +1 -1
  16. package/dist/converters/toCreateMessage.d.ts +3 -6
  17. package/dist/converters/toCreateMessage.d.ts.map +1 -1
  18. package/dist/converters/toolOutputConversion.d.ts +22 -25
  19. package/dist/converters/toolOutputConversion.d.ts.map +1 -1
  20. package/dist/hooks.d.ts +4 -7
  21. package/dist/hooks.d.ts.map +1 -1
  22. package/dist/index.d.ts +17 -14
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.native.d.ts +15 -12
  25. package/dist/index.native.d.ts.map +1 -0
  26. package/dist/model-context/injectInteractableContext.d.ts +3 -6
  27. package/dist/model-context/injectInteractableContext.d.ts.map +1 -1
  28. package/dist/model-context/injectQuoteContext.d.ts +2 -5
  29. package/dist/model-context/injectQuoteContext.d.ts.map +1 -1
  30. package/dist/runtime/AISDKChat.d.ts +4 -7
  31. package/dist/runtime/AISDKChat.d.ts.map +1 -1
  32. package/dist/runtime/AISDKChat.js +1 -1
  33. package/dist/runtime/AISDKThreads.d.ts +29 -32
  34. package/dist/runtime/AISDKThreads.d.ts.map +1 -1
  35. package/dist/runtime/AISDKThreads.js +26 -33
  36. package/dist/runtime/AISDKThreads.js.map +1 -1
  37. package/dist/runtime/sdkIdentity.d.ts +2 -5
  38. package/dist/runtime/sdkIdentity.d.ts.map +1 -1
  39. package/dist/runtime/sdkIdentity.js +1 -1
  40. package/dist/runtime/useAISDKRuntime.d.ts +72 -61
  41. package/dist/runtime/useAISDKRuntime.d.ts.map +1 -1
  42. package/dist/runtime/useAISDKRuntime.js +170 -56
  43. package/dist/runtime/useAISDKRuntime.js.map +1 -1
  44. package/dist/runtime/useChatRuntime.d.ts +8 -11
  45. package/dist/runtime/useChatRuntime.d.ts.map +1 -1
  46. package/dist/runtime/useChatRuntime.js +14 -10
  47. package/dist/runtime/useChatRuntime.js.map +1 -1
  48. package/dist/runtime/useChatThread.d.ts +100 -81
  49. package/dist/runtime/useChatThread.d.ts.map +1 -1
  50. package/dist/runtime/useChatThread.js +33 -13
  51. package/dist/runtime/useChatThread.js.map +1 -1
  52. package/dist/runtime/useExternalHistory.d.ts +8 -9
  53. package/dist/runtime/useExternalHistory.d.ts.map +1 -1
  54. package/dist/runtime/useExternalHistory.js +236 -58
  55. package/dist/runtime/useExternalHistory.js.map +1 -1
  56. package/dist/runtime/useResourceCleanup.d.ts +1 -4
  57. package/dist/runtime/useResourceCleanup.d.ts.map +1 -1
  58. package/dist/runtime/useResourceCleanup.js +38 -14
  59. package/dist/runtime/useResourceCleanup.js.map +1 -1
  60. package/dist/runtime/useStreamingTiming.d.ts +5 -8
  61. package/dist/runtime/useStreamingTiming.d.ts.map +1 -1
  62. package/dist/runtime/useStreamingTiming.js +1 -1
  63. package/dist/tools/frontendTools.d.ts +24 -27
  64. package/dist/tools/frontendTools.d.ts.map +1 -1
  65. package/dist/tools/generativeTools.d.ts +29 -32
  66. package/dist/tools/generativeTools.d.ts.map +1 -1
  67. package/dist/tools/mcp-stdio.node.d.ts +2 -2
  68. package/dist/tools/mcp-stdio.node.d.ts.map +1 -0
  69. package/dist/tools/mcp-stdio.unsupported.d.ts +2 -5
  70. package/dist/tools/mcp-stdio.unsupported.d.ts.map +1 -1
  71. package/dist/transport/AssistantChatTransport.d.ts +17 -20
  72. package/dist/transport/AssistantChatTransport.d.ts.map +1 -1
  73. package/dist/transport/resumable.d.ts +29 -32
  74. package/dist/transport/resumable.d.ts.map +1 -1
  75. package/dist/usage.d.ts +12 -15
  76. package/dist/usage.d.ts.map +1 -1
  77. package/dist/usage.js.map +1 -1
  78. package/dist/utils/getVercelAIMessages.d.ts +3 -6
  79. package/dist/utils/getVercelAIMessages.d.ts.map +1 -1
  80. package/dist/utils/sliceMessagesUntil.d.ts +2 -5
  81. package/dist/utils/sliceMessagesUntil.d.ts.map +1 -1
  82. package/package.json +16 -14
  83. package/src/adapters/vercelAttachmentAdapter.test.ts +23 -0
  84. package/src/adapters/vercelAttachmentAdapter.ts +2 -2
  85. package/src/converters/convertMessage.test.ts +616 -3
  86. package/src/converters/convertMessage.ts +187 -12
  87. package/src/index.native.ts +1 -1
  88. package/src/index.ts +1 -1
  89. package/src/runtime/AISDKChat.test.ts +4 -5
  90. package/src/runtime/AISDKThreads.cloud.test.ts +60 -2
  91. package/src/runtime/AISDKThreads.test.ts +88 -51
  92. package/src/runtime/AISDKThreads.ts +4 -13
  93. package/src/runtime/useAISDKRuntime.approval.integration.test.tsx +338 -0
  94. package/src/runtime/useAISDKRuntime.approval.test.tsx +476 -4
  95. package/src/runtime/useAISDKRuntime.test.ts +282 -8
  96. package/src/runtime/useAISDKRuntime.ts +274 -46
  97. package/src/runtime/useAISDKRuntime.voice.test.tsx +319 -0
  98. package/src/runtime/useChatRuntime.integration.test.tsx +56 -0
  99. package/src/runtime/useChatRuntime.test.ts +77 -5
  100. package/src/runtime/useChatRuntime.ts +6 -2
  101. package/src/runtime/useChatThread.transport.test.tsx +149 -0
  102. package/src/runtime/useChatThread.ts +77 -10
  103. package/src/runtime/useExternalHistory.test.ts +989 -3
  104. package/src/runtime/useExternalHistory.ts +390 -24
  105. package/src/runtime/useResourceCleanup.ts +41 -15
  106. package/src/tools/generativeTools.test.ts +7 -1
  107. package/src/usage.ts +1 -1
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
 
3
- import { useChat, type Chat, type UIMessage } from "@ai-sdk/react";
3
+ import { Chat, useChat, type UIMessage } from "@ai-sdk/react";
4
4
  import type { MessageRepository } from "@assistant-ui/core/internal";
5
5
  import {
6
6
  pickExternalStoreSharedOptions,
@@ -26,6 +26,7 @@ import {
26
26
  useEffect,
27
27
  useMemo,
28
28
  useRef,
29
+ useState,
29
30
  useSyncExternalStore,
30
31
  } from "react";
31
32
  import { useResourceCleanup } from "./useResourceCleanup";
@@ -38,6 +39,7 @@ export type ChatThreadOptions<UI_MESSAGE extends UIMessage = UIMessage> =
38
39
  toCreateMessage?: CustomToCreateMessageFunction;
39
40
  onResume?: AISDKRuntimeAdapter["onResume"];
40
41
  onResumeToolCall?: AISDKRuntimeAdapter["onResumeToolCall"];
42
+ onRespondToToolApproval?: AISDKRuntimeAdapter["onRespondToToolApproval"];
41
43
  /**
42
44
  * Called when an automatic resumable stream reconnect fails. Use this to
43
45
  * surface a toast, report telemetry, or mark the thread as needing a
@@ -55,6 +57,12 @@ export type ChatThreadEnvironment<UI_MESSAGE extends UIMessage = UIMessage> = {
55
57
  isMainThread: boolean;
56
58
  getThreadListItem: () => InitializableThreadListItem | undefined;
57
59
  stopOnClientDestroy?: boolean;
60
+ /**
61
+ * Aborts when the React component hosting the runtime is deleted. A nested
62
+ * runtime resolves the destroy signal of the provider above it, which
63
+ * outlives the nested component, so this stops the chat on its own unmount.
64
+ */
65
+ hostDestroySignal?: AbortSignal | undefined;
58
66
  /**
59
67
  * An externally owned chat instance. State lives on the instance, so it
60
68
  * survives the hosting resource unmounting; construction options are read
@@ -140,6 +148,7 @@ export const splitChatThreadOptions = <UI_MESSAGE extends UIMessage>(
140
148
  suggestions: _suggestions,
141
149
  onResume,
142
150
  onResumeToolCall,
151
+ onRespondToToolApproval,
143
152
  onResumeError,
144
153
  joinStrategy,
145
154
  messageRepository,
@@ -158,6 +167,7 @@ export const splitChatThreadOptions = <UI_MESSAGE extends UIMessage>(
158
167
  toCreateMessage,
159
168
  onResume,
160
169
  onResumeToolCall,
170
+ onRespondToToolApproval,
161
171
  onResumeError,
162
172
  joinStrategy,
163
173
  messageRepository,
@@ -166,6 +176,30 @@ export const splitChatThreadOptions = <UI_MESSAGE extends UIMessage>(
166
176
  };
167
177
  };
168
178
 
179
+ type ChatCallbacks<UI_MESSAGE extends UIMessage> = Pick<
180
+ ChatInit<UI_MESSAGE>,
181
+ "onToolCall" | "onData" | "onFinish" | "onError" | "sendAutomaticallyWhen"
182
+ >;
183
+
184
+ /**
185
+ * Constructs a `Chat` whose callbacks read the latest options through
186
+ * `callbacksRef`, the forwarding `useChat` applies only to a chat it
187
+ * constructs itself.
188
+ */
189
+ export const createChat = <UI_MESSAGE extends UIMessage>(
190
+ init: ChatInit<UI_MESSAGE>,
191
+ callbacksRef: { readonly current: ChatCallbacks<UI_MESSAGE> | undefined },
192
+ ): Chat<UI_MESSAGE> =>
193
+ new Chat<UI_MESSAGE>({
194
+ ...init,
195
+ onToolCall: (arg) => callbacksRef.current?.onToolCall?.(arg),
196
+ onData: (arg) => callbacksRef.current?.onData?.(arg),
197
+ onFinish: (arg) => callbacksRef.current?.onFinish?.(arg),
198
+ onError: (arg) => callbacksRef.current?.onError?.(arg),
199
+ sendAutomaticallyWhen: (arg) =>
200
+ callbacksRef.current?.sendAutomaticallyWhen?.(arg) ?? false,
201
+ });
202
+
169
203
  export const useChatThread = <UI_MESSAGE extends UIMessage = UIMessage>(
170
204
  options: ChatThreadOptions<UI_MESSAGE> | undefined,
171
205
  env: ChatThreadEnvironment<UI_MESSAGE>,
@@ -177,6 +211,7 @@ export const useChatThread = <UI_MESSAGE extends UIMessage = UIMessage>(
177
211
  toCreateMessage,
178
212
  onResume,
179
213
  onResumeToolCall,
214
+ onRespondToToolApproval,
180
215
  onResumeError,
181
216
  joinStrategy,
182
217
  messageRepository,
@@ -189,25 +224,51 @@ export const useChatThread = <UI_MESSAGE extends UIMessage = UIMessage>(
189
224
  isMainThread,
190
225
  getThreadListItem,
191
226
  stopOnClientDestroy = true,
227
+ hostDestroySignal,
192
228
  chat: externalChat,
193
229
  messageRepositoryInstance,
194
230
  } = env;
195
231
 
196
- const defaultTransport = useMemo(() => new AssistantChatTransport(), []);
197
- const sourceTransport = transportOptions ?? defaultTransport;
232
+ // Wiring below is per thread and mutated on the instance, so a transport
233
+ // shared across simultaneously mounted threads is last-writer-wins. A
234
+ // caller-owned chat is already bound to its own clone, so cloning again
235
+ // here would wire a copy the chat never sends through.
236
+ const sourceTransport = useMemo(
237
+ () =>
238
+ transportOptions === undefined
239
+ ? new AssistantChatTransport()
240
+ : externalChat === undefined &&
241
+ transportOptions instanceof AssistantChatTransport
242
+ ? transportOptions.__internal_clone()
243
+ : transportOptions,
244
+ [transportOptions, externalChat],
245
+ );
198
246
  const transport = useDynamicChatTransport(sourceTransport);
199
247
 
248
+ const latestChatOptionsRef = useRef(chatOptions);
249
+ useEffect(() => {
250
+ latestChatOptionsRef.current = chatOptions;
251
+ });
252
+ // `useChat` stops a chat it constructs whenever it unmounts, and a
253
+ // resource's soft unmount runs that cleanup, so the thread owns its chat.
254
+ const [ownedChat] = useState(
255
+ () =>
256
+ externalChat ??
257
+ createChat({ ...chatOptions, id, transport }, latestChatOptionsRef),
258
+ );
259
+
200
260
  const chat = useChat({
201
- ...chatOptions,
202
- id,
203
- transport,
261
+ chat: externalChat ?? ownedChat,
204
262
  ...(throttle !== undefined && { throttle }),
205
- ...(externalChat !== undefined && { chat: externalChat }),
206
263
  });
207
264
 
208
- useResourceCleanup(stopOnClientDestroy, () => {
209
- void chat.stop().catch(() => {});
210
- });
265
+ useResourceCleanup(
266
+ stopOnClientDestroy,
267
+ () => {
268
+ void chat.stop().catch(() => {});
269
+ },
270
+ hostDestroySignal,
271
+ );
211
272
 
212
273
  const runtime = useAISDKRuntime(chat, {
213
274
  adapters,
@@ -215,6 +276,7 @@ export const useChatThread = <UI_MESSAGE extends UIMessage = UIMessage>(
215
276
  ...(toCreateMessage && { toCreateMessage }),
216
277
  ...(onResume && { onResume }),
217
278
  ...(onResumeToolCall && { onResumeToolCall }),
279
+ ...(onRespondToToolApproval && { onRespondToToolApproval }),
218
280
  ...(joinStrategy && { joinStrategy }),
219
281
  ...(messageRepository && { messageRepository }),
220
282
  ...(messageRepositoryInstance && {
@@ -223,6 +285,11 @@ export const useChatThread = <UI_MESSAGE extends UIMessage = UIMessage>(
223
285
  ...(unstable_onBranchChange && { unstable_onBranchChange }),
224
286
  });
225
287
 
288
+ // Wire in render, not an effect: a send from a descendant's mount effect
289
+ // runs before this hook's effect would (effects fire child-first), and must
290
+ // see a wired transport. The clone is per thread, so a discarded render's
291
+ // wiring is discarded with it and the committed render re-wires the same
292
+ // instance.
226
293
  if (sourceTransport instanceof AssistantChatTransport) {
227
294
  sourceTransport.setRuntime(runtime);
228
295
  sourceTransport.__internal_setGetThreadListItem(getThreadListItem);