@assistant-ui/react 0.12.21 → 0.12.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.
Files changed (253) hide show
  1. package/dist/client/ExternalThread.d.ts.map +1 -1
  2. package/dist/client/ExternalThread.js +8 -2
  3. package/dist/client/ExternalThread.js.map +1 -1
  4. package/dist/client/InMemoryThreadList.d.ts.map +1 -1
  5. package/dist/client/InMemoryThreadList.js +2 -0
  6. package/dist/client/InMemoryThreadList.js.map +1 -1
  7. package/dist/client/SingleThreadList.d.ts.map +1 -1
  8. package/dist/client/SingleThreadList.js +2 -0
  9. package/dist/client/SingleThreadList.js.map +1 -1
  10. package/dist/index.d.ts +5 -1
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +3 -1
  13. package/dist/index.js.map +1 -1
  14. package/dist/legacy-runtime/runtime-cores/assistant-transport/types.d.ts +3 -1
  15. package/dist/legacy-runtime/runtime-cores/assistant-transport/types.d.ts.map +1 -1
  16. package/dist/legacy-runtime/runtime-cores/assistant-transport/types.js.map +1 -1
  17. package/dist/legacy-runtime/runtime-cores/assistant-transport/useAssistantTransportRuntime.d.ts.map +1 -1
  18. package/dist/legacy-runtime/runtime-cores/assistant-transport/useAssistantTransportRuntime.js +4 -0
  19. package/dist/legacy-runtime/runtime-cores/assistant-transport/useAssistantTransportRuntime.js.map +1 -1
  20. package/dist/primitives/actionBar/ActionBarCopy.d.ts +3 -1
  21. package/dist/primitives/actionBar/ActionBarCopy.d.ts.map +1 -1
  22. package/dist/primitives/actionBar/ActionBarCopy.js +1 -1
  23. package/dist/primitives/actionBar/ActionBarCopy.js.map +1 -1
  24. package/dist/primitives/actionBar/ActionBarEdit.d.ts +4 -2
  25. package/dist/primitives/actionBar/ActionBarEdit.d.ts.map +1 -1
  26. package/dist/primitives/actionBar/ActionBarExportMarkdown.d.ts +3 -1
  27. package/dist/primitives/actionBar/ActionBarExportMarkdown.d.ts.map +1 -1
  28. package/dist/primitives/actionBar/ActionBarExportMarkdown.js +1 -1
  29. package/dist/primitives/actionBar/ActionBarExportMarkdown.js.map +1 -1
  30. package/dist/primitives/actionBar/ActionBarFeedbackNegative.d.ts +4 -2
  31. package/dist/primitives/actionBar/ActionBarFeedbackNegative.d.ts.map +1 -1
  32. package/dist/primitives/actionBar/ActionBarFeedbackNegative.js +1 -1
  33. package/dist/primitives/actionBar/ActionBarFeedbackNegative.js.map +1 -1
  34. package/dist/primitives/actionBar/ActionBarFeedbackPositive.d.ts +4 -2
  35. package/dist/primitives/actionBar/ActionBarFeedbackPositive.d.ts.map +1 -1
  36. package/dist/primitives/actionBar/ActionBarFeedbackPositive.js +1 -1
  37. package/dist/primitives/actionBar/ActionBarFeedbackPositive.js.map +1 -1
  38. package/dist/primitives/actionBar/ActionBarReload.d.ts +4 -2
  39. package/dist/primitives/actionBar/ActionBarReload.d.ts.map +1 -1
  40. package/dist/primitives/actionBar/ActionBarRoot.d.ts +4 -2
  41. package/dist/primitives/actionBar/ActionBarRoot.d.ts.map +1 -1
  42. package/dist/primitives/actionBar/ActionBarRoot.js +1 -1
  43. package/dist/primitives/actionBar/ActionBarRoot.js.map +1 -1
  44. package/dist/primitives/actionBar/ActionBarSpeak.d.ts +4 -2
  45. package/dist/primitives/actionBar/ActionBarSpeak.d.ts.map +1 -1
  46. package/dist/primitives/actionBar/ActionBarStopSpeaking.d.ts +4 -2
  47. package/dist/primitives/actionBar/ActionBarStopSpeaking.d.ts.map +1 -1
  48. package/dist/primitives/actionBar/ActionBarStopSpeaking.js +1 -1
  49. package/dist/primitives/actionBar/ActionBarStopSpeaking.js.map +1 -1
  50. package/dist/primitives/attachment/AttachmentRemove.d.ts +4 -2
  51. package/dist/primitives/attachment/AttachmentRemove.d.ts.map +1 -1
  52. package/dist/primitives/attachment/AttachmentRoot.d.ts +5 -3
  53. package/dist/primitives/attachment/AttachmentRoot.d.ts.map +1 -1
  54. package/dist/primitives/attachment/AttachmentRoot.js +1 -1
  55. package/dist/primitives/attachment/AttachmentRoot.js.map +1 -1
  56. package/dist/primitives/attachment/AttachmentThumb.d.ts +5 -3
  57. package/dist/primitives/attachment/AttachmentThumb.d.ts.map +1 -1
  58. package/dist/primitives/attachment/AttachmentThumb.js +1 -1
  59. package/dist/primitives/attachment/AttachmentThumb.js.map +1 -1
  60. package/dist/primitives/branchPicker/BranchPickerNext.d.ts +4 -2
  61. package/dist/primitives/branchPicker/BranchPickerNext.d.ts.map +1 -1
  62. package/dist/primitives/branchPicker/BranchPickerPrevious.d.ts +4 -2
  63. package/dist/primitives/branchPicker/BranchPickerPrevious.d.ts.map +1 -1
  64. package/dist/primitives/branchPicker/BranchPickerRoot.d.ts +4 -2
  65. package/dist/primitives/branchPicker/BranchPickerRoot.d.ts.map +1 -1
  66. package/dist/primitives/branchPicker/BranchPickerRoot.js +1 -1
  67. package/dist/primitives/branchPicker/BranchPickerRoot.js.map +1 -1
  68. package/dist/primitives/chainOfThought/ChainOfThoughtAccordionTrigger.d.ts +4 -2
  69. package/dist/primitives/chainOfThought/ChainOfThoughtAccordionTrigger.d.ts.map +1 -1
  70. package/dist/primitives/chainOfThought/ChainOfThoughtRoot.d.ts +5 -3
  71. package/dist/primitives/chainOfThought/ChainOfThoughtRoot.d.ts.map +1 -1
  72. package/dist/primitives/chainOfThought/ChainOfThoughtRoot.js +1 -1
  73. package/dist/primitives/chainOfThought/ChainOfThoughtRoot.js.map +1 -1
  74. package/dist/primitives/composer/ComposerAddAttachment.d.ts +3 -1
  75. package/dist/primitives/composer/ComposerAddAttachment.d.ts.map +1 -1
  76. package/dist/primitives/composer/ComposerAttachmentDropzone.d.ts +3 -0
  77. package/dist/primitives/composer/ComposerAttachmentDropzone.d.ts.map +1 -1
  78. package/dist/primitives/composer/ComposerAttachmentDropzone.js +18 -8
  79. package/dist/primitives/composer/ComposerAttachmentDropzone.js.map +1 -1
  80. package/dist/primitives/composer/ComposerCancel.d.ts +4 -2
  81. package/dist/primitives/composer/ComposerCancel.d.ts.map +1 -1
  82. package/dist/primitives/composer/ComposerDictate.d.ts +4 -2
  83. package/dist/primitives/composer/ComposerDictate.d.ts.map +1 -1
  84. package/dist/primitives/composer/ComposerDictationTranscript.d.ts +5 -3
  85. package/dist/primitives/composer/ComposerDictationTranscript.d.ts.map +1 -1
  86. package/dist/primitives/composer/ComposerDictationTranscript.js +1 -1
  87. package/dist/primitives/composer/ComposerDictationTranscript.js.map +1 -1
  88. package/dist/primitives/composer/ComposerInput.d.ts +5 -0
  89. package/dist/primitives/composer/ComposerInput.d.ts.map +1 -1
  90. package/dist/primitives/composer/ComposerInput.js +23 -6
  91. package/dist/primitives/composer/ComposerInput.js.map +1 -1
  92. package/dist/primitives/composer/ComposerQuote.d.ts +13 -7
  93. package/dist/primitives/composer/ComposerQuote.d.ts.map +1 -1
  94. package/dist/primitives/composer/ComposerQuote.js +1 -1
  95. package/dist/primitives/composer/ComposerQuote.js.map +1 -1
  96. package/dist/primitives/composer/ComposerRoot.d.ts +5 -3
  97. package/dist/primitives/composer/ComposerRoot.d.ts.map +1 -1
  98. package/dist/primitives/composer/ComposerRoot.js +1 -1
  99. package/dist/primitives/composer/ComposerRoot.js.map +1 -1
  100. package/dist/primitives/composer/ComposerSend.d.ts +4 -2
  101. package/dist/primitives/composer/ComposerSend.d.ts.map +1 -1
  102. package/dist/primitives/composer/ComposerStopDictation.d.ts +4 -2
  103. package/dist/primitives/composer/ComposerStopDictation.d.ts.map +1 -1
  104. package/dist/primitives/composer/mention/ComposerMentionBack.d.ts +5 -3
  105. package/dist/primitives/composer/mention/ComposerMentionBack.d.ts.map +1 -1
  106. package/dist/primitives/composer/mention/ComposerMentionBack.js +1 -1
  107. package/dist/primitives/composer/mention/ComposerMentionBack.js.map +1 -1
  108. package/dist/primitives/composer/mention/ComposerMentionCategories.d.ts +8 -4
  109. package/dist/primitives/composer/mention/ComposerMentionCategories.d.ts.map +1 -1
  110. package/dist/primitives/composer/mention/ComposerMentionCategories.js +1 -1
  111. package/dist/primitives/composer/mention/ComposerMentionCategories.js.map +1 -1
  112. package/dist/primitives/composer/mention/ComposerMentionItems.d.ts +8 -4
  113. package/dist/primitives/composer/mention/ComposerMentionItems.d.ts.map +1 -1
  114. package/dist/primitives/composer/mention/ComposerMentionItems.js +1 -1
  115. package/dist/primitives/composer/mention/ComposerMentionItems.js.map +1 -1
  116. package/dist/primitives/composer/mention/ComposerMentionPopover.d.ts +5 -3
  117. package/dist/primitives/composer/mention/ComposerMentionPopover.d.ts.map +1 -1
  118. package/dist/primitives/composer/mention/ComposerMentionPopover.js +1 -1
  119. package/dist/primitives/composer/mention/ComposerMentionPopover.js.map +1 -1
  120. package/dist/primitives/error/ErrorMessage.d.ts +5 -3
  121. package/dist/primitives/error/ErrorMessage.d.ts.map +1 -1
  122. package/dist/primitives/error/ErrorMessage.js +1 -1
  123. package/dist/primitives/error/ErrorMessage.js.map +1 -1
  124. package/dist/primitives/error/ErrorRoot.d.ts +5 -3
  125. package/dist/primitives/error/ErrorRoot.d.ts.map +1 -1
  126. package/dist/primitives/error/ErrorRoot.js +1 -1
  127. package/dist/primitives/error/ErrorRoot.js.map +1 -1
  128. package/dist/primitives/message/MessageRoot.d.ts +5 -3
  129. package/dist/primitives/message/MessageRoot.d.ts.map +1 -1
  130. package/dist/primitives/message/MessageRoot.js +1 -1
  131. package/dist/primitives/message/MessageRoot.js.map +1 -1
  132. package/dist/primitives/messagePart/MessagePartImage.d.ts +5 -3
  133. package/dist/primitives/messagePart/MessagePartImage.d.ts.map +1 -1
  134. package/dist/primitives/messagePart/MessagePartImage.js +1 -1
  135. package/dist/primitives/messagePart/MessagePartImage.js.map +1 -1
  136. package/dist/primitives/messagePart/MessagePartText.d.ts +5 -3
  137. package/dist/primitives/messagePart/MessagePartText.d.ts.map +1 -1
  138. package/dist/primitives/queueItem/QueueItemRemove.d.ts +4 -2
  139. package/dist/primitives/queueItem/QueueItemRemove.d.ts.map +1 -1
  140. package/dist/primitives/queueItem/QueueItemSteer.d.ts +4 -2
  141. package/dist/primitives/queueItem/QueueItemSteer.d.ts.map +1 -1
  142. package/dist/primitives/queueItem/QueueItemText.d.ts +5 -3
  143. package/dist/primitives/queueItem/QueueItemText.d.ts.map +1 -1
  144. package/dist/primitives/queueItem/QueueItemText.js +1 -1
  145. package/dist/primitives/queueItem/QueueItemText.js.map +1 -1
  146. package/dist/primitives/selectionToolbar/SelectionToolbarQuote.d.ts +5 -3
  147. package/dist/primitives/selectionToolbar/SelectionToolbarQuote.d.ts.map +1 -1
  148. package/dist/primitives/selectionToolbar/SelectionToolbarQuote.js +1 -1
  149. package/dist/primitives/selectionToolbar/SelectionToolbarQuote.js.map +1 -1
  150. package/dist/primitives/selectionToolbar/SelectionToolbarRoot.d.ts +5 -3
  151. package/dist/primitives/selectionToolbar/SelectionToolbarRoot.d.ts.map +1 -1
  152. package/dist/primitives/selectionToolbar/SelectionToolbarRoot.js +1 -1
  153. package/dist/primitives/selectionToolbar/SelectionToolbarRoot.js.map +1 -1
  154. package/dist/primitives/suggestion/SuggestionDescription.d.ts +5 -3
  155. package/dist/primitives/suggestion/SuggestionDescription.d.ts.map +1 -1
  156. package/dist/primitives/suggestion/SuggestionDescription.js +1 -1
  157. package/dist/primitives/suggestion/SuggestionDescription.js.map +1 -1
  158. package/dist/primitives/suggestion/SuggestionTitle.d.ts +5 -3
  159. package/dist/primitives/suggestion/SuggestionTitle.d.ts.map +1 -1
  160. package/dist/primitives/suggestion/SuggestionTitle.js +1 -1
  161. package/dist/primitives/suggestion/SuggestionTitle.js.map +1 -1
  162. package/dist/primitives/suggestion/SuggestionTrigger.d.ts +3 -1
  163. package/dist/primitives/suggestion/SuggestionTrigger.d.ts.map +1 -1
  164. package/dist/primitives/thread/ThreadRoot.d.ts +5 -3
  165. package/dist/primitives/thread/ThreadRoot.d.ts.map +1 -1
  166. package/dist/primitives/thread/ThreadRoot.js +1 -1
  167. package/dist/primitives/thread/ThreadRoot.js.map +1 -1
  168. package/dist/primitives/thread/ThreadScrollToBottom.d.ts +4 -2
  169. package/dist/primitives/thread/ThreadScrollToBottom.d.ts.map +1 -1
  170. package/dist/primitives/thread/ThreadSuggestion.d.ts +3 -1
  171. package/dist/primitives/thread/ThreadSuggestion.d.ts.map +1 -1
  172. package/dist/primitives/thread/ThreadViewport.d.ts +4 -2
  173. package/dist/primitives/thread/ThreadViewport.d.ts.map +1 -1
  174. package/dist/primitives/thread/ThreadViewport.js +1 -1
  175. package/dist/primitives/thread/ThreadViewport.js.map +1 -1
  176. package/dist/primitives/thread/ThreadViewportFooter.d.ts +5 -3
  177. package/dist/primitives/thread/ThreadViewportFooter.d.ts.map +1 -1
  178. package/dist/primitives/thread/ThreadViewportFooter.js +1 -1
  179. package/dist/primitives/thread/ThreadViewportFooter.js.map +1 -1
  180. package/dist/primitives/threadList/ThreadListNew.d.ts +4 -2
  181. package/dist/primitives/threadList/ThreadListNew.d.ts.map +1 -1
  182. package/dist/primitives/threadList/ThreadListNew.js +1 -1
  183. package/dist/primitives/threadList/ThreadListNew.js.map +1 -1
  184. package/dist/primitives/threadList/ThreadListRoot.d.ts +5 -3
  185. package/dist/primitives/threadList/ThreadListRoot.d.ts.map +1 -1
  186. package/dist/primitives/threadList/ThreadListRoot.js +1 -1
  187. package/dist/primitives/threadList/ThreadListRoot.js.map +1 -1
  188. package/dist/primitives/threadListItem/ThreadListItemArchive.d.ts +4 -2
  189. package/dist/primitives/threadListItem/ThreadListItemArchive.d.ts.map +1 -1
  190. package/dist/primitives/threadListItem/ThreadListItemDelete.d.ts +4 -2
  191. package/dist/primitives/threadListItem/ThreadListItemDelete.d.ts.map +1 -1
  192. package/dist/primitives/threadListItem/ThreadListItemRoot.d.ts +5 -3
  193. package/dist/primitives/threadListItem/ThreadListItemRoot.d.ts.map +1 -1
  194. package/dist/primitives/threadListItem/ThreadListItemRoot.js +1 -1
  195. package/dist/primitives/threadListItem/ThreadListItemRoot.js.map +1 -1
  196. package/dist/primitives/threadListItem/ThreadListItemTrigger.d.ts +4 -2
  197. package/dist/primitives/threadListItem/ThreadListItemTrigger.d.ts.map +1 -1
  198. package/dist/primitives/threadListItem/ThreadListItemUnarchive.d.ts +4 -2
  199. package/dist/primitives/threadListItem/ThreadListItemUnarchive.d.ts.map +1 -1
  200. package/dist/utils/Primitive.d.ts +106 -0
  201. package/dist/utils/Primitive.d.ts.map +1 -0
  202. package/dist/utils/Primitive.js +54 -0
  203. package/dist/utils/Primitive.js.map +1 -0
  204. package/dist/utils/createActionButton.d.ts +5 -3
  205. package/dist/utils/createActionButton.d.ts.map +1 -1
  206. package/dist/utils/createActionButton.js +1 -1
  207. package/dist/utils/createActionButton.js.map +1 -1
  208. package/package.json +7 -8
  209. package/src/client/ExternalThread.ts +8 -2
  210. package/src/client/InMemoryThreadList.ts +3 -0
  211. package/src/client/SingleThreadList.ts +2 -0
  212. package/src/index.ts +21 -6
  213. package/src/legacy-runtime/runtime-cores/assistant-transport/types.ts +7 -0
  214. package/src/legacy-runtime/runtime-cores/assistant-transport/useAssistantTransportRuntime.ts +4 -0
  215. package/src/legacy-runtime/runtime-cores/assistant-transport/useToolInvocations.test.ts +186 -3
  216. package/src/primitives/actionBar/ActionBarCopy.tsx +1 -1
  217. package/src/primitives/actionBar/ActionBarExportMarkdown.tsx +1 -1
  218. package/src/primitives/actionBar/ActionBarFeedbackNegative.tsx +1 -1
  219. package/src/primitives/actionBar/ActionBarFeedbackPositive.tsx +1 -1
  220. package/src/primitives/actionBar/ActionBarRoot.tsx +1 -1
  221. package/src/primitives/actionBar/ActionBarStopSpeaking.tsx +1 -1
  222. package/src/primitives/attachment/AttachmentRoot.tsx +1 -1
  223. package/src/primitives/attachment/AttachmentThumb.tsx +1 -1
  224. package/src/primitives/branchPicker/BranchPickerRoot.tsx +1 -1
  225. package/src/primitives/chainOfThought/ChainOfThoughtRoot.tsx +1 -1
  226. package/src/primitives/composer/ComposerAttachmentDropzone.tsx +41 -18
  227. package/src/primitives/composer/ComposerDictationTranscript.tsx +1 -1
  228. package/src/primitives/composer/ComposerInput.tsx +43 -17
  229. package/src/primitives/composer/ComposerQuote.tsx +1 -1
  230. package/src/primitives/composer/ComposerRoot.tsx +1 -1
  231. package/src/primitives/composer/mention/ComposerMentionBack.tsx +1 -1
  232. package/src/primitives/composer/mention/ComposerMentionCategories.tsx +1 -1
  233. package/src/primitives/composer/mention/ComposerMentionItems.tsx +1 -1
  234. package/src/primitives/composer/mention/ComposerMentionPopover.tsx +1 -1
  235. package/src/primitives/error/ErrorMessage.tsx +1 -1
  236. package/src/primitives/error/ErrorRoot.tsx +1 -1
  237. package/src/primitives/message/MessageRoot.tsx +1 -1
  238. package/src/primitives/messagePart/MessagePartImage.tsx +1 -1
  239. package/src/primitives/messagePart/MessagePartText.tsx +1 -1
  240. package/src/primitives/queueItem/QueueItemText.tsx +1 -1
  241. package/src/primitives/selectionToolbar/SelectionToolbarQuote.tsx +1 -1
  242. package/src/primitives/selectionToolbar/SelectionToolbarRoot.tsx +1 -1
  243. package/src/primitives/suggestion/SuggestionDescription.tsx +1 -1
  244. package/src/primitives/suggestion/SuggestionTitle.tsx +1 -1
  245. package/src/primitives/thread/ThreadRoot.tsx +1 -1
  246. package/src/primitives/thread/ThreadViewport.tsx +1 -1
  247. package/src/primitives/thread/ThreadViewportFooter.tsx +1 -1
  248. package/src/primitives/threadList/ThreadListNew.tsx +1 -1
  249. package/src/primitives/threadList/ThreadListRoot.tsx +1 -1
  250. package/src/primitives/threadListItem/ThreadListItemRoot.tsx +1 -1
  251. package/src/utils/Primitive.test.tsx +99 -0
  252. package/src/utils/Primitive.tsx +100 -0
  253. package/src/utils/createActionButton.tsx +1 -1
@@ -147,6 +147,10 @@ const useAssistantTransportThreadRuntime = <T>(
147
147
  ...(parentIdRef.current !== undefined && {
148
148
  parentId: parentIdRef.current,
149
149
  }),
150
+ // nested (new format, aligned with AssistantChatTransport)
151
+ callSettings: context.callSettings,
152
+ config: context.config,
153
+ // @deprecated spread at top level — use nested `callSettings`/`config` instead. Will be removed in a future version.
150
154
  ...context.callSettings,
151
155
  ...context.config,
152
156
  ...(bodyValue ?? {}),
@@ -19,7 +19,13 @@ const createState = (
19
19
  const createAssistantMessage = (
20
20
  argsText: string,
21
21
  args: Record<string, unknown>,
22
- options?: { result?: ReadonlyJSONValue; isError?: boolean },
22
+ options?: {
23
+ result?: ReadonlyJSONValue;
24
+ isError?: boolean;
25
+ toolCallId?: string;
26
+ toolName?: string;
27
+ nestedMessages?: ThreadAssistantMessage[];
28
+ },
23
29
  ): ThreadAssistantMessage => ({
24
30
  id: "m-1",
25
31
  role: "assistant",
@@ -35,12 +41,13 @@ const createAssistantMessage = (
35
41
  content: [
36
42
  {
37
43
  type: "tool-call",
38
- toolCallId: "tool-1",
39
- toolName: "weatherSearch",
44
+ toolCallId: options?.toolCallId ?? "tool-1",
45
+ toolName: options?.toolName ?? "weatherSearch",
40
46
  args: args as ReadonlyJSONObject,
41
47
  argsText,
42
48
  ...(options?.result !== undefined && { result: options.result }),
43
49
  ...(options?.isError !== undefined && { isError: options.isError }),
50
+ ...(options?.nestedMessages && { messages: options.nestedMessages }),
44
51
  },
45
52
  ],
46
53
  });
@@ -228,6 +235,182 @@ describe("useToolInvocations", () => {
228
235
  expect(Object.keys(statuses)).not.toContain("tool-1:rewrite:0");
229
236
  });
230
237
 
238
+ it("does not execute tool calls loaded asynchronously with existing results", async () => {
239
+ const execute = vi.fn(async () => ({ forecast: "ok" }));
240
+ const getTools = () => ({
241
+ weatherSearch: {
242
+ parameters: { type: "object", properties: {} },
243
+ execute,
244
+ } satisfies Tool,
245
+ });
246
+ const onResult = vi.fn();
247
+ const setToolStatuses = vi.fn();
248
+
249
+ const { rerender } = renderHook(
250
+ ({ state }: { state: AssistantTransportState }) =>
251
+ useToolInvocations({
252
+ state,
253
+ getTools,
254
+ onResult,
255
+ setToolStatuses,
256
+ }),
257
+ {
258
+ initialProps: {
259
+ state: createState([]),
260
+ },
261
+ },
262
+ );
263
+
264
+ act(() => {
265
+ rerender({
266
+ state: createState([
267
+ createAssistantMessage(
268
+ '{"query":"London"}',
269
+ { query: "London" },
270
+ { result: { source: "history" } },
271
+ ),
272
+ ]),
273
+ });
274
+ });
275
+
276
+ await waitFor(() => {
277
+ expect(execute).not.toHaveBeenCalled();
278
+ expect(onResult).not.toHaveBeenCalled();
279
+ });
280
+ });
281
+
282
+ it("does not re-execute asynchronously loaded resolved tool calls after reset", async () => {
283
+ const execute = vi.fn(async () => ({ forecast: "ok" }));
284
+ const getTools = () => ({
285
+ weatherSearch: {
286
+ parameters: { type: "object", properties: {} },
287
+ execute,
288
+ } satisfies Tool,
289
+ });
290
+ const onResult = vi.fn();
291
+ const setToolStatuses = vi.fn();
292
+
293
+ const { result, rerender } = renderHook(
294
+ ({ state }: { state: AssistantTransportState }) =>
295
+ useToolInvocations({
296
+ state,
297
+ getTools,
298
+ onResult,
299
+ setToolStatuses,
300
+ }),
301
+ {
302
+ initialProps: {
303
+ state: createState([]),
304
+ },
305
+ },
306
+ );
307
+
308
+ act(() => {
309
+ rerender({
310
+ state: createState([
311
+ createAssistantMessage('{"query":"London"}', { query: "London" }),
312
+ ]),
313
+ });
314
+ });
315
+
316
+ await waitFor(() => {
317
+ expect(execute).toHaveBeenCalledTimes(1);
318
+ });
319
+
320
+ act(() => {
321
+ result.current.reset();
322
+ });
323
+
324
+ await act(async () => {
325
+ await Promise.resolve();
326
+ });
327
+
328
+ act(() => {
329
+ rerender({
330
+ state: createState([]),
331
+ });
332
+ });
333
+
334
+ act(() => {
335
+ rerender({
336
+ state: createState([
337
+ createAssistantMessage(
338
+ '{"query":"London"}',
339
+ { query: "London" },
340
+ { result: { source: "history" } },
341
+ ),
342
+ ]),
343
+ });
344
+ });
345
+
346
+ await waitFor(() => {
347
+ expect(execute).toHaveBeenCalledTimes(1);
348
+ expect(onResult).toHaveBeenCalledTimes(1);
349
+ });
350
+ });
351
+
352
+ it("still processes nested unresolved tool calls when the parent tool call is already resolved", async () => {
353
+ const executeParent = vi.fn(async () => ({ scope: "parent" }));
354
+ const executeChild = vi.fn(async () => ({ scope: "child" }));
355
+ const getTools = () => ({
356
+ resolvedOnly: {
357
+ parameters: { type: "object", properties: {} },
358
+ execute: executeParent,
359
+ } satisfies Tool,
360
+ childTool: {
361
+ parameters: { type: "object", properties: {} },
362
+ execute: executeChild,
363
+ } satisfies Tool,
364
+ });
365
+ const onResult = vi.fn();
366
+ const setToolStatuses = vi.fn();
367
+
368
+ const nestedMessage = createAssistantMessage(
369
+ '{"query":"nested"}',
370
+ { query: "nested" },
371
+ {
372
+ toolCallId: "tool-child",
373
+ toolName: "childTool",
374
+ },
375
+ );
376
+
377
+ const { rerender } = renderHook(
378
+ ({ state }: { state: AssistantTransportState }) =>
379
+ useToolInvocations({
380
+ state,
381
+ getTools,
382
+ onResult,
383
+ setToolStatuses,
384
+ }),
385
+ {
386
+ initialProps: {
387
+ state: createState([]),
388
+ },
389
+ },
390
+ );
391
+
392
+ act(() => {
393
+ rerender({
394
+ state: createState([
395
+ createAssistantMessage(
396
+ '{"query":"parent"}',
397
+ { query: "parent" },
398
+ {
399
+ result: { source: "history" },
400
+ toolName: "resolvedOnly",
401
+ nestedMessages: [nestedMessage],
402
+ },
403
+ ),
404
+ ]),
405
+ });
406
+ });
407
+
408
+ await waitFor(() => {
409
+ expect(executeParent).not.toHaveBeenCalled();
410
+ expect(executeChild).toHaveBeenCalledTimes(1);
411
+ });
412
+ });
413
+
231
414
  it("does not close args stream early for non-executable tool snapshots", () => {
232
415
  const getTools = () => ({
233
416
  weatherSearch: {
@@ -3,7 +3,7 @@
3
3
  import { forwardRef } from "react";
4
4
  import { ActionButtonProps } from "../../utils/createActionButton";
5
5
  import { composeEventHandlers } from "@radix-ui/primitive";
6
- import { Primitive } from "@radix-ui/react-primitive";
6
+ import { Primitive } from "../../utils/Primitive";
7
7
  import { useActionBarCopy } from "@assistant-ui/core/react";
8
8
  import { useAuiState } from "@assistant-ui/store";
9
9
 
@@ -3,7 +3,7 @@
3
3
  import { forwardRef, useCallback } from "react";
4
4
  import { ActionButtonProps } from "../../utils/createActionButton";
5
5
  import { composeEventHandlers } from "@radix-ui/primitive";
6
- import { Primitive } from "@radix-ui/react-primitive";
6
+ import { Primitive } from "../../utils/Primitive";
7
7
  import { useAuiState, useAui } from "@assistant-ui/store";
8
8
 
9
9
  const useActionBarExportMarkdown = ({
@@ -3,7 +3,7 @@
3
3
  import { forwardRef } from "react";
4
4
  import { ActionButtonProps } from "../../utils/createActionButton";
5
5
  import { composeEventHandlers } from "@radix-ui/primitive";
6
- import { Primitive } from "@radix-ui/react-primitive";
6
+ import { Primitive } from "../../utils/Primitive";
7
7
  import { useAuiState } from "@assistant-ui/store";
8
8
  import { useActionBarFeedbackNegative as useActionBarFeedbackNegativeBehavior } from "@assistant-ui/core/react";
9
9
 
@@ -4,7 +4,7 @@ import { forwardRef } from "react";
4
4
  import { ActionButtonProps } from "../../utils/createActionButton";
5
5
  import { composeEventHandlers } from "@radix-ui/primitive";
6
6
  import { useAuiState } from "@assistant-ui/store";
7
- import { Primitive } from "@radix-ui/react-primitive";
7
+ import { Primitive } from "../../utils/Primitive";
8
8
  import { useActionBarFeedbackPositive as useActionBarFeedbackPositiveBehavior } from "@assistant-ui/core/react";
9
9
 
10
10
  const useActionBarFeedbackPositive = () => {
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
 
3
- import { Primitive } from "@radix-ui/react-primitive";
3
+ import { Primitive } from "../../utils/Primitive";
4
4
  import {
5
5
  type ComponentRef,
6
6
  forwardRef,
@@ -3,7 +3,7 @@
3
3
  import { forwardRef } from "react";
4
4
  import { ActionButtonProps } from "../../utils/createActionButton";
5
5
  import { useEscapeKeydown } from "@radix-ui/react-use-escape-keydown";
6
- import { Primitive } from "@radix-ui/react-primitive";
6
+ import { Primitive } from "../../utils/Primitive";
7
7
  import { composeEventHandlers } from "@radix-ui/primitive";
8
8
  import { useActionBarStopSpeaking as useActionBarStopSpeakingBehavior } from "@assistant-ui/core/react";
9
9
 
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
 
3
- import { Primitive } from "@radix-ui/react-primitive";
3
+ import { Primitive } from "../../utils/Primitive";
4
4
  import { ComponentPropsWithoutRef, ComponentRef, forwardRef } from "react";
5
5
 
6
6
  type PrimitiveDivProps = ComponentPropsWithoutRef<typeof Primitive.div>;
@@ -2,7 +2,7 @@
2
2
 
3
3
  import { ComponentPropsWithoutRef, forwardRef, type ComponentRef } from "react";
4
4
  import { useAuiState } from "@assistant-ui/store";
5
- import { Primitive } from "@radix-ui/react-primitive";
5
+ import { Primitive } from "../../utils/Primitive";
6
6
 
7
7
  type PrimitiveDivProps = ComponentPropsWithoutRef<typeof Primitive.div>;
8
8
 
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
 
3
- import { Primitive } from "@radix-ui/react-primitive";
3
+ import { Primitive } from "../../utils/Primitive";
4
4
  import { type ComponentRef, forwardRef, ComponentPropsWithoutRef } from "react";
5
5
  import { MessagePrimitiveIf as If } from "../message/MessageIf";
6
6
 
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
 
3
- import { Primitive } from "@radix-ui/react-primitive";
3
+ import { Primitive } from "../../utils/Primitive";
4
4
  import { type ComponentRef, forwardRef, ComponentPropsWithoutRef } from "react";
5
5
 
6
6
  type PrimitiveDivProps = ComponentPropsWithoutRef<typeof Primitive.div>;
@@ -1,7 +1,15 @@
1
1
  "use client";
2
2
 
3
- import { forwardRef, useCallback, useState } from "react";
3
+ import {
4
+ forwardRef,
5
+ useCallback,
6
+ useState,
7
+ type ReactElement,
8
+ cloneElement,
9
+ isValidElement,
10
+ } from "react";
4
11
 
12
+ import { composeEventHandlers } from "@radix-ui/primitive";
5
13
  import { Slot } from "radix-ui";
6
14
  import React from "react";
7
15
  import { useAui } from "@assistant-ui/store";
@@ -10,6 +18,7 @@ export namespace ComposerPrimitiveAttachmentDropzone {
10
18
  export type Element = HTMLDivElement;
11
19
  export type Props = React.HTMLAttributes<HTMLDivElement> & {
12
20
  asChild?: boolean | undefined;
21
+ render?: ReactElement | undefined;
13
22
  disabled?: boolean | undefined;
14
23
  };
15
24
  }
@@ -17,7 +26,7 @@ export namespace ComposerPrimitiveAttachmentDropzone {
17
26
  export const ComposerPrimitiveAttachmentDropzone = forwardRef<
18
27
  HTMLDivElement,
19
28
  ComposerPrimitiveAttachmentDropzone.Props
20
- >(({ disabled, asChild = false, children, ...rest }, ref) => {
29
+ >(({ disabled, asChild = false, render, children, ...rest }, ref) => {
21
30
  const [isDragging, setIsDragging] = useState(false);
22
31
  const aui = useAui();
23
32
 
@@ -68,25 +77,39 @@ export const ComposerPrimitiveAttachmentDropzone = forwardRef<
68
77
  [disabled, aui],
69
78
  );
70
79
 
71
- const dragProps = {
72
- onDragEnterCapture: handleDragEnterCapture,
73
- onDragOverCapture: handleDragOverCapture,
74
- onDragLeaveCapture: handleDragLeaveCapture,
75
- onDropCapture: handleDrop,
80
+ const mergedProps = {
81
+ ...(isDragging ? { "data-dragging": "true" } : null),
82
+ ...rest,
83
+ onDragEnterCapture: composeEventHandlers(
84
+ rest.onDragEnterCapture,
85
+ handleDragEnterCapture,
86
+ ),
87
+ onDragOverCapture: composeEventHandlers(
88
+ rest.onDragOverCapture,
89
+ handleDragOverCapture,
90
+ ),
91
+ onDragLeaveCapture: composeEventHandlers(
92
+ rest.onDragLeaveCapture,
93
+ handleDragLeaveCapture,
94
+ ),
95
+ onDropCapture: composeEventHandlers(rest.onDropCapture, handleDrop),
96
+ ref,
76
97
  };
77
98
 
78
- const Comp = asChild ? Slot.Root : "div";
99
+ if (render && isValidElement(render)) {
100
+ const renderChildren =
101
+ children !== undefined
102
+ ? children
103
+ : (render.props as Record<string, unknown>).children;
104
+ return (
105
+ <Slot.Root {...mergedProps}>
106
+ {cloneElement(render, undefined, renderChildren as React.ReactNode)}
107
+ </Slot.Root>
108
+ );
109
+ }
79
110
 
80
- return (
81
- <Comp
82
- {...(isDragging ? { "data-dragging": "true" } : null)}
83
- ref={ref}
84
- {...dragProps}
85
- {...rest}
86
- >
87
- {children}
88
- </Comp>
89
- );
111
+ const Comp = asChild ? Slot.Root : "div";
112
+ return <Comp {...mergedProps}>{children}</Comp>;
90
113
  });
91
114
 
92
115
  ComposerPrimitiveAttachmentDropzone.displayName =
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
 
3
- import { Primitive } from "@radix-ui/react-primitive";
3
+ import { Primitive } from "../../utils/Primitive";
4
4
  import { type ComponentRef, forwardRef, ComponentPropsWithoutRef } from "react";
5
5
  import { useAuiState } from "@assistant-ui/store";
6
6
 
@@ -6,10 +6,14 @@ import { Slot } from "radix-ui";
6
6
  import {
7
7
  ClipboardEvent,
8
8
  type KeyboardEvent,
9
+ type ReactElement,
10
+ type ReactNode,
9
11
  forwardRef,
10
12
  useCallback,
11
13
  useEffect,
12
14
  useRef,
15
+ cloneElement,
16
+ isValidElement,
13
17
  } from "react";
14
18
  import TextareaAutosize, {
15
19
  type TextareaAutosizeProps,
@@ -32,6 +36,10 @@ export namespace ComposerPrimitiveInput {
32
36
  * When true, the component will merge its props with its child.
33
37
  */
34
38
  asChild?: boolean | undefined;
39
+ /**
40
+ * A React element to use as the input container, with props merged in.
41
+ */
42
+ render?: ReactElement | undefined;
35
43
  /**
36
44
  * Whether to cancel message composition when Escape is pressed.
37
45
  * @default true
@@ -118,6 +126,7 @@ export const ComposerPrimitiveInput = forwardRef<
118
126
  {
119
127
  autoFocus = false,
120
128
  asChild,
129
+ render,
121
130
  disabled: disabledProp,
122
131
  onChange,
123
132
  onKeyDown,
@@ -146,8 +155,6 @@ export const ComposerPrimitiveInput = forwardRef<
146
155
  return s.composer.text;
147
156
  });
148
157
 
149
- const Component = asChild ? Slot.Root : TextareaAutosize;
150
-
151
158
  const isDisabled =
152
159
  useAuiState(
153
160
  (s) => s.thread.isDisabled || s.composer.dictation?.inputDisabled,
@@ -277,14 +284,15 @@ export const ComposerPrimitiveInput = forwardRef<
277
284
  return aui.on("threadListItem.switchedTo", focus);
278
285
  }, [unstable_focusOnThreadSwitched, focus, aui]);
279
286
 
280
- return (
281
- <Component
282
- name="input"
283
- value={value}
284
- {...rest}
285
- ref={ref as React.ForwardedRef<HTMLTextAreaElement>}
286
- disabled={isDisabled}
287
- onChange={composeEventHandlers(onChange, (e) => {
287
+ const inputProps = {
288
+ name: "input" as const,
289
+ value,
290
+ ...rest,
291
+ ref: ref as React.ForwardedRef<HTMLTextAreaElement>,
292
+ disabled: isDisabled,
293
+ onChange: composeEventHandlers(
294
+ onChange,
295
+ (e: React.ChangeEvent<HTMLTextAreaElement>) => {
288
296
  if (!aui.composer().getState().isEditing) return;
289
297
  flushResourcesSync(() => {
290
298
  aui.composer().setText(e.target.value);
@@ -292,17 +300,35 @@ export const ComposerPrimitiveInput = forwardRef<
292
300
  mentionInternalContext?.setCursorPosition(
293
301
  e.target.selectionStart ?? e.target.value.length,
294
302
  );
295
- })}
296
- onKeyDown={composeEventHandlers(onKeyDown, handleKeyPress)}
297
- onSelect={composeEventHandlers(onSelect, (e) => {
303
+ },
304
+ ),
305
+ onKeyDown: composeEventHandlers(onKeyDown, handleKeyPress),
306
+ onSelect: composeEventHandlers(
307
+ onSelect,
308
+ (e: React.SyntheticEvent<HTMLTextAreaElement>) => {
298
309
  const target = e.target as HTMLTextAreaElement;
299
310
  mentionInternalContext?.setCursorPosition(
300
311
  target.selectionStart ?? target.value.length,
301
312
  );
302
- })}
303
- onPaste={composeEventHandlers(onPaste, handlePaste)}
304
- />
305
- );
313
+ },
314
+ ),
315
+ onPaste: composeEventHandlers(onPaste, handlePaste),
316
+ };
317
+
318
+ if (render && isValidElement(render)) {
319
+ const renderChildren =
320
+ (rest as any).children !== undefined
321
+ ? ((rest as any).children as ReactNode)
322
+ : ((render.props as Record<string, unknown>).children as ReactNode);
323
+ return (
324
+ <Slot.Root {...inputProps}>
325
+ {cloneElement(render, undefined, renderChildren)}
326
+ </Slot.Root>
327
+ );
328
+ }
329
+
330
+ const Component = asChild ? Slot.Root : TextareaAutosize;
331
+ return <Component {...inputProps} />;
306
332
  },
307
333
  );
308
334
 
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
 
3
- import { Primitive } from "@radix-ui/react-primitive";
3
+ import { Primitive } from "../../utils/Primitive";
4
4
  import {
5
5
  type ComponentRef,
6
6
  type ComponentPropsWithoutRef,
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
 
3
3
  import { composeEventHandlers } from "@radix-ui/primitive";
4
- import { Primitive } from "@radix-ui/react-primitive";
4
+ import { Primitive } from "../../utils/Primitive";
5
5
  import {
6
6
  type ComponentRef,
7
7
  type FormEvent,
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
 
3
- import { Primitive } from "@radix-ui/react-primitive";
3
+ import { Primitive } from "../../../utils/Primitive";
4
4
  import {
5
5
  type ComponentRef,
6
6
  type ComponentPropsWithoutRef,
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
 
3
- import { Primitive } from "@radix-ui/react-primitive";
3
+ import { Primitive } from "../../../utils/Primitive";
4
4
  import {
5
5
  type ComponentRef,
6
6
  type ComponentPropsWithoutRef,
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
 
3
- import { Primitive } from "@radix-ui/react-primitive";
3
+ import { Primitive } from "../../../utils/Primitive";
4
4
  import {
5
5
  type ComponentRef,
6
6
  type ComponentPropsWithoutRef,
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
 
3
- import { Primitive } from "@radix-ui/react-primitive";
3
+ import { Primitive } from "../../../utils/Primitive";
4
4
  import {
5
5
  type ComponentRef,
6
6
  type ComponentPropsWithoutRef,
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
 
3
- import { Primitive } from "@radix-ui/react-primitive";
3
+ import { Primitive } from "../../utils/Primitive";
4
4
  import { type ComponentRef, forwardRef, ComponentPropsWithoutRef } from "react";
5
5
  import { useMessageError } from "@assistant-ui/core/react";
6
6
 
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
 
3
- import { Primitive } from "@radix-ui/react-primitive";
3
+ import { Primitive } from "../../utils/Primitive";
4
4
  import { type ComponentRef, forwardRef, ComponentPropsWithoutRef } from "react";
5
5
 
6
6
  export namespace ErrorPrimitiveRoot {
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
 
3
- import { Primitive } from "@radix-ui/react-primitive";
3
+ import { Primitive } from "../../utils/Primitive";
4
4
  import {
5
5
  type ComponentRef,
6
6
  forwardRef,
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
 
3
- import { Primitive } from "@radix-ui/react-primitive";
3
+ import { Primitive } from "../../utils/Primitive";
4
4
  import { type ComponentRef, forwardRef, ComponentPropsWithoutRef } from "react";
5
5
  import { useMessagePartImage } from "./useMessagePartImage";
6
6
 
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
 
3
- import { Primitive } from "@radix-ui/react-primitive";
3
+ import { Primitive } from "../../utils/Primitive";
4
4
  import {
5
5
  type ComponentRef,
6
6
  forwardRef,
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
 
3
- import { Primitive } from "@radix-ui/react-primitive";
3
+ import { Primitive } from "../../utils/Primitive";
4
4
  import {
5
5
  type ComponentRef,
6
6
  type ComponentPropsWithoutRef,
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
 
3
- import { Primitive } from "@radix-ui/react-primitive";
3
+ import { Primitive } from "../../utils/Primitive";
4
4
  import { composeEventHandlers } from "@radix-ui/primitive";
5
5
  import {
6
6
  type ComponentPropsWithoutRef,
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
 
3
- import { Primitive } from "@radix-ui/react-primitive";
3
+ import { Primitive } from "../../utils/Primitive";
4
4
  import {
5
5
  type ComponentPropsWithoutRef,
6
6
  type ComponentRef,
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
 
3
- import { Primitive } from "@radix-ui/react-primitive";
3
+ import { Primitive } from "../../utils/Primitive";
4
4
  import { type ElementRef, forwardRef, ComponentPropsWithoutRef } from "react";
5
5
  import { useAuiState } from "@assistant-ui/store";
6
6