@assistant-ui/react 0.15.19 → 0.15.21

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 (359) hide show
  1. package/dist/assistant-transport.d.ts +10 -10
  2. package/dist/assistant-transport.d.ts.map +1 -1
  3. package/dist/augmentations.d.ts +3 -4
  4. package/dist/augmentations.d.ts.map +1 -1
  5. package/dist/context/ReadonlyStore.d.ts +2 -3
  6. package/dist/context/ReadonlyStore.d.ts.map +1 -1
  7. package/dist/context/providers/MessageProvider.d.ts +1 -2
  8. package/dist/context/providers/MessageProvider.d.ts.map +1 -1
  9. package/dist/context/providers/ThreadViewportProvider.d.ts +2 -3
  10. package/dist/context/providers/ThreadViewportProvider.d.ts.map +1 -1
  11. package/dist/context/react/ThreadViewportContext.d.ts +3 -4
  12. package/dist/context/react/ThreadViewportContext.d.ts.map +1 -1
  13. package/dist/context/react/utils/createContextHook.d.ts +1 -2
  14. package/dist/context/react/utils/createContextHook.d.ts.map +1 -1
  15. package/dist/context/react/utils/createContextStoreHook.d.ts +1 -2
  16. package/dist/context/react/utils/createContextStoreHook.d.ts.map +1 -1
  17. package/dist/context/stores/ThreadViewport.d.ts +4 -5
  18. package/dist/context/stores/ThreadViewport.d.ts.map +1 -1
  19. package/dist/context/stores/ThreadViewport.js +2 -1
  20. package/dist/context/stores/ThreadViewport.js.map +1 -1
  21. package/dist/devtools/DevToolsHooks.d.ts +3 -4
  22. package/dist/devtools/DevToolsHooks.d.ts.map +1 -1
  23. package/dist/hooks/useMessageQuote.d.ts +1 -2
  24. package/dist/hooks/useMessageQuote.d.ts.map +1 -1
  25. package/dist/hooks/useMessageTiming.d.ts +1 -2
  26. package/dist/hooks/useMessageTiming.d.ts.map +1 -1
  27. package/dist/hooks/useToolCallElapsed.d.ts +1 -2
  28. package/dist/hooks/useToolCallElapsed.d.ts.map +1 -1
  29. package/dist/index.d.ts +4 -4
  30. package/dist/index.js +2 -2
  31. package/dist/legacy-runtime/AssistantRuntimeProvider.d.ts +3 -4
  32. package/dist/legacy-runtime/AssistantRuntimeProvider.d.ts.map +1 -1
  33. package/dist/legacy-runtime/runtime-cores/external-store/external-message-converter.d.ts +2 -2
  34. package/dist/legacy-runtime/runtime-cores/external-store/external-message-converter.js +2 -2
  35. package/dist/mcp-apps/McpAppRenderer.d.ts +3 -4
  36. package/dist/mcp-apps/McpAppRenderer.d.ts.map +1 -1
  37. package/dist/mcp-apps/McpAppRenderer.js +1 -1
  38. package/dist/mcp-apps/McpAppsRemoteHost.d.ts +1 -2
  39. package/dist/mcp-apps/McpAppsRemoteHost.d.ts.map +1 -1
  40. package/dist/mcp-apps/app-frame.d.ts +1 -2
  41. package/dist/mcp-apps/app-frame.d.ts.map +1 -1
  42. package/dist/mcp-apps/app-frame.js +1 -1
  43. package/dist/mcp-apps/bridge.d.ts +4 -5
  44. package/dist/mcp-apps/bridge.d.ts.map +1 -1
  45. package/dist/mcp-apps/types.d.ts +20 -20
  46. package/dist/mcp-apps/types.d.ts.map +1 -1
  47. package/dist/mcp-apps/utils.d.ts +1 -2
  48. package/dist/mcp-apps/utils.d.ts.map +1 -1
  49. package/dist/model-context/frame/useAssistantFrameHost.d.ts +1 -2
  50. package/dist/model-context/frame/useAssistantFrameHost.d.ts.map +1 -1
  51. package/dist/model-context/frame/useAssistantFrameHost.js +20 -2
  52. package/dist/model-context/frame/useAssistantFrameHost.js.map +1 -1
  53. package/dist/model-context/makeAssistantVisible.d.ts +2 -2
  54. package/dist/model-context/makeAssistantVisible.d.ts.map +1 -1
  55. package/dist/primitives/actionBar/ActionBarCopy.d.ts +2 -3
  56. package/dist/primitives/actionBar/ActionBarCopy.d.ts.map +1 -1
  57. package/dist/primitives/actionBar/ActionBarEdit.d.ts +2 -3
  58. package/dist/primitives/actionBar/ActionBarEdit.d.ts.map +1 -1
  59. package/dist/primitives/actionBar/ActionBarExportMarkdown.d.ts +2 -3
  60. package/dist/primitives/actionBar/ActionBarExportMarkdown.d.ts.map +1 -1
  61. package/dist/primitives/actionBar/ActionBarFeedbackNegative.d.ts +2 -3
  62. package/dist/primitives/actionBar/ActionBarFeedbackNegative.d.ts.map +1 -1
  63. package/dist/primitives/actionBar/ActionBarFeedbackPositive.d.ts +2 -3
  64. package/dist/primitives/actionBar/ActionBarFeedbackPositive.d.ts.map +1 -1
  65. package/dist/primitives/actionBar/ActionBarInteractionContext.d.ts +3 -4
  66. package/dist/primitives/actionBar/ActionBarInteractionContext.d.ts.map +1 -1
  67. package/dist/primitives/actionBar/ActionBarReload.d.ts +2 -3
  68. package/dist/primitives/actionBar/ActionBarReload.d.ts.map +1 -1
  69. package/dist/primitives/actionBar/ActionBarRoot.d.ts +2 -3
  70. package/dist/primitives/actionBar/ActionBarRoot.d.ts.map +1 -1
  71. package/dist/primitives/actionBar/ActionBarSpeak.d.ts +2 -3
  72. package/dist/primitives/actionBar/ActionBarSpeak.d.ts.map +1 -1
  73. package/dist/primitives/actionBar/ActionBarStopSpeaking.d.ts +2 -3
  74. package/dist/primitives/actionBar/ActionBarStopSpeaking.d.ts.map +1 -1
  75. package/dist/primitives/actionBar/useActionBarFloatStatus.d.ts +4 -5
  76. package/dist/primitives/actionBar/useActionBarFloatStatus.d.ts.map +1 -1
  77. package/dist/primitives/actionBarMore/ActionBarMoreContent.d.ts +2 -3
  78. package/dist/primitives/actionBarMore/ActionBarMoreContent.d.ts.map +1 -1
  79. package/dist/primitives/actionBarMore/ActionBarMoreItem.d.ts +2 -3
  80. package/dist/primitives/actionBarMore/ActionBarMoreItem.d.ts.map +1 -1
  81. package/dist/primitives/actionBarMore/ActionBarMoreRoot.d.ts +2 -3
  82. package/dist/primitives/actionBarMore/ActionBarMoreRoot.d.ts.map +1 -1
  83. package/dist/primitives/actionBarMore/ActionBarMoreSeparator.d.ts +2 -3
  84. package/dist/primitives/actionBarMore/ActionBarMoreSeparator.d.ts.map +1 -1
  85. package/dist/primitives/actionBarMore/ActionBarMoreTrigger.d.ts +2 -3
  86. package/dist/primitives/actionBarMore/ActionBarMoreTrigger.d.ts.map +1 -1
  87. package/dist/primitives/actionBarMore/scope.d.ts +2 -3
  88. package/dist/primitives/actionBarMore/scope.d.ts.map +1 -1
  89. package/dist/primitives/assistantModal/AssistantModalAnchor.d.ts +2 -3
  90. package/dist/primitives/assistantModal/AssistantModalAnchor.d.ts.map +1 -1
  91. package/dist/primitives/assistantModal/AssistantModalContent.d.ts +2 -3
  92. package/dist/primitives/assistantModal/AssistantModalContent.d.ts.map +1 -1
  93. package/dist/primitives/assistantModal/AssistantModalRoot.d.ts +2 -3
  94. package/dist/primitives/assistantModal/AssistantModalRoot.d.ts.map +1 -1
  95. package/dist/primitives/assistantModal/AssistantModalTrigger.d.ts +2 -3
  96. package/dist/primitives/assistantModal/AssistantModalTrigger.d.ts.map +1 -1
  97. package/dist/primitives/assistantModal/popoverRenderPrimitives.d.ts +3 -4
  98. package/dist/primitives/assistantModal/popoverRenderPrimitives.d.ts.map +1 -1
  99. package/dist/primitives/assistantModal/scope.d.ts +2 -3
  100. package/dist/primitives/assistantModal/scope.d.ts.map +1 -1
  101. package/dist/primitives/attachment/AttachmentName.d.ts +2 -3
  102. package/dist/primitives/attachment/AttachmentName.d.ts.map +1 -1
  103. package/dist/primitives/attachment/AttachmentRemove.d.ts +2 -3
  104. package/dist/primitives/attachment/AttachmentRemove.d.ts.map +1 -1
  105. package/dist/primitives/attachment/AttachmentRoot.d.ts +2 -3
  106. package/dist/primitives/attachment/AttachmentRoot.d.ts.map +1 -1
  107. package/dist/primitives/attachment/AttachmentThumb.d.ts +2 -3
  108. package/dist/primitives/attachment/AttachmentThumb.d.ts.map +1 -1
  109. package/dist/primitives/branchPicker/BranchPickerCount.d.ts +2 -3
  110. package/dist/primitives/branchPicker/BranchPickerCount.d.ts.map +1 -1
  111. package/dist/primitives/branchPicker/BranchPickerNext.d.ts +2 -3
  112. package/dist/primitives/branchPicker/BranchPickerNext.d.ts.map +1 -1
  113. package/dist/primitives/branchPicker/BranchPickerNumber.d.ts +2 -3
  114. package/dist/primitives/branchPicker/BranchPickerNumber.d.ts.map +1 -1
  115. package/dist/primitives/branchPicker/BranchPickerPrevious.d.ts +2 -3
  116. package/dist/primitives/branchPicker/BranchPickerPrevious.d.ts.map +1 -1
  117. package/dist/primitives/branchPicker/BranchPickerRoot.d.ts +2 -3
  118. package/dist/primitives/branchPicker/BranchPickerRoot.d.ts.map +1 -1
  119. package/dist/primitives/chainOfThought/ChainOfThoughtAccordionTrigger.d.ts +2 -3
  120. package/dist/primitives/chainOfThought/ChainOfThoughtAccordionTrigger.d.ts.map +1 -1
  121. package/dist/primitives/chainOfThought/ChainOfThoughtRoot.d.ts +2 -3
  122. package/dist/primitives/chainOfThought/ChainOfThoughtRoot.d.ts.map +1 -1
  123. package/dist/primitives/composer/ComposerAddAttachment.d.ts +2 -3
  124. package/dist/primitives/composer/ComposerAddAttachment.d.ts.map +1 -1
  125. package/dist/primitives/composer/ComposerAttachmentDropzone.d.ts +2 -3
  126. package/dist/primitives/composer/ComposerAttachmentDropzone.d.ts.map +1 -1
  127. package/dist/primitives/composer/ComposerCancel.d.ts +2 -3
  128. package/dist/primitives/composer/ComposerCancel.d.ts.map +1 -1
  129. package/dist/primitives/composer/ComposerCompactContext.d.ts +3 -4
  130. package/dist/primitives/composer/ComposerCompactContext.d.ts.map +1 -1
  131. package/dist/primitives/composer/ComposerDictate.d.ts +2 -3
  132. package/dist/primitives/composer/ComposerDictate.d.ts.map +1 -1
  133. package/dist/primitives/composer/ComposerDictationTranscript.d.ts +2 -3
  134. package/dist/primitives/composer/ComposerDictationTranscript.d.ts.map +1 -1
  135. package/dist/primitives/composer/ComposerInput.d.ts +2 -3
  136. package/dist/primitives/composer/ComposerInput.d.ts.map +1 -1
  137. package/dist/primitives/composer/ComposerInputPluginContext.d.ts +5 -6
  138. package/dist/primitives/composer/ComposerInputPluginContext.d.ts.map +1 -1
  139. package/dist/primitives/composer/ComposerQuote.d.ts +6 -7
  140. package/dist/primitives/composer/ComposerQuote.d.ts.map +1 -1
  141. package/dist/primitives/composer/ComposerRoot.d.ts +2 -3
  142. package/dist/primitives/composer/ComposerRoot.d.ts.map +1 -1
  143. package/dist/primitives/composer/ComposerSend.d.ts +3 -4
  144. package/dist/primitives/composer/ComposerSend.d.ts.map +1 -1
  145. package/dist/primitives/composer/ComposerStopDictation.d.ts +2 -3
  146. package/dist/primitives/composer/ComposerStopDictation.d.ts.map +1 -1
  147. package/dist/primitives/composer/trigger/TriggerPopover.d.ts +6 -7
  148. package/dist/primitives/composer/trigger/TriggerPopover.d.ts.map +1 -1
  149. package/dist/primitives/composer/trigger/TriggerPopoverAction.d.ts +2 -3
  150. package/dist/primitives/composer/trigger/TriggerPopoverAction.d.ts.map +1 -1
  151. package/dist/primitives/composer/trigger/TriggerPopoverBack.d.ts +2 -3
  152. package/dist/primitives/composer/trigger/TriggerPopoverBack.d.ts.map +1 -1
  153. package/dist/primitives/composer/trigger/TriggerPopoverCategories.d.ts +4 -5
  154. package/dist/primitives/composer/trigger/TriggerPopoverCategories.d.ts.map +1 -1
  155. package/dist/primitives/composer/trigger/TriggerPopoverDirective.d.ts +2 -3
  156. package/dist/primitives/composer/trigger/TriggerPopoverDirective.d.ts.map +1 -1
  157. package/dist/primitives/composer/trigger/TriggerPopoverItems.d.ts +4 -5
  158. package/dist/primitives/composer/trigger/TriggerPopoverItems.d.ts.map +1 -1
  159. package/dist/primitives/composer/trigger/TriggerPopoverResource.d.ts +4 -4
  160. package/dist/primitives/composer/trigger/TriggerPopoverResource.d.ts.map +1 -1
  161. package/dist/primitives/composer/trigger/TriggerPopoverRootContext.d.ts +12 -13
  162. package/dist/primitives/composer/trigger/TriggerPopoverRootContext.d.ts.map +1 -1
  163. package/dist/primitives/composer/trigger/detectTrigger.d.ts +3 -4
  164. package/dist/primitives/composer/trigger/detectTrigger.d.ts.map +1 -1
  165. package/dist/primitives/composer/trigger/index.d.ts +2 -2
  166. package/dist/primitives/composer/trigger/index.d.ts.map +1 -1
  167. package/dist/primitives/composer/trigger/matchesTriggerItemQuery.d.ts +1 -2
  168. package/dist/primitives/composer/trigger/matchesTriggerItemQuery.d.ts.map +1 -1
  169. package/dist/primitives/composer/trigger/triggerDetectionResource.d.ts +3 -4
  170. package/dist/primitives/composer/trigger/triggerDetectionResource.d.ts.map +1 -1
  171. package/dist/primitives/composer/trigger/triggerKeyboardResource.d.ts +3 -4
  172. package/dist/primitives/composer/trigger/triggerKeyboardResource.d.ts.map +1 -1
  173. package/dist/primitives/composer/trigger/triggerNavigationResource.d.ts +2 -3
  174. package/dist/primitives/composer/trigger/triggerNavigationResource.d.ts.map +1 -1
  175. package/dist/primitives/composer/trigger/triggerSelectionResource.d.ts +4 -5
  176. package/dist/primitives/composer/trigger/triggerSelectionResource.d.ts.map +1 -1
  177. package/dist/primitives/composer/useComposerInputState.d.ts +4 -5
  178. package/dist/primitives/composer/useComposerInputState.d.ts.map +1 -1
  179. package/dist/primitives/dropdownMenuRenderPrimitives.d.ts +4 -5
  180. package/dist/primitives/dropdownMenuRenderPrimitives.d.ts.map +1 -1
  181. package/dist/primitives/error/ErrorMessage.d.ts +2 -3
  182. package/dist/primitives/error/ErrorMessage.d.ts.map +1 -1
  183. package/dist/primitives/error/ErrorRoot.d.ts +2 -3
  184. package/dist/primitives/error/ErrorRoot.d.ts.map +1 -1
  185. package/dist/primitives/message/MessageError.d.ts +1 -2
  186. package/dist/primitives/message/MessageError.d.ts.map +1 -1
  187. package/dist/primitives/message/MessageIf.d.ts +2 -3
  188. package/dist/primitives/message/MessageIf.d.ts.map +1 -1
  189. package/dist/primitives/message/MessageParts.d.ts +3 -3
  190. package/dist/primitives/message/MessageParts.d.ts.map +1 -1
  191. package/dist/primitives/message/MessagePartsGrouped.d.ts +4 -5
  192. package/dist/primitives/message/MessagePartsGrouped.d.ts.map +1 -1
  193. package/dist/primitives/message/MessageRoot.d.ts +2 -3
  194. package/dist/primitives/message/MessageRoot.d.ts.map +1 -1
  195. package/dist/primitives/messagePart/MessagePartImage.d.ts +2 -3
  196. package/dist/primitives/messagePart/MessagePartImage.d.ts.map +1 -1
  197. package/dist/primitives/messagePart/MessagePartText.d.ts +3 -4
  198. package/dist/primitives/messagePart/MessagePartText.d.ts.map +1 -1
  199. package/dist/primitives/messagePart/useMessagePartData.d.ts +1 -2
  200. package/dist/primitives/messagePart/useMessagePartData.d.ts.map +1 -1
  201. package/dist/primitives/messagePart/useMessagePartFile.d.ts +1 -2
  202. package/dist/primitives/messagePart/useMessagePartFile.d.ts.map +1 -1
  203. package/dist/primitives/messagePart/useMessagePartImage.d.ts +1 -2
  204. package/dist/primitives/messagePart/useMessagePartImage.d.ts.map +1 -1
  205. package/dist/primitives/messagePart/useMessagePartReasoning.d.ts +1 -2
  206. package/dist/primitives/messagePart/useMessagePartReasoning.d.ts.map +1 -1
  207. package/dist/primitives/messagePart/useMessagePartSource.d.ts +1 -2
  208. package/dist/primitives/messagePart/useMessagePartSource.d.ts.map +1 -1
  209. package/dist/primitives/messagePart/useMessagePartText.d.ts +1 -2
  210. package/dist/primitives/messagePart/useMessagePartText.d.ts.map +1 -1
  211. package/dist/primitives/queueItem/QueueItemRemove.d.ts +2 -3
  212. package/dist/primitives/queueItem/QueueItemRemove.d.ts.map +1 -1
  213. package/dist/primitives/queueItem/QueueItemSteer.d.ts +2 -3
  214. package/dist/primitives/queueItem/QueueItemSteer.d.ts.map +1 -1
  215. package/dist/primitives/queueItem/QueueItemText.d.ts +2 -3
  216. package/dist/primitives/queueItem/QueueItemText.d.ts.map +1 -1
  217. package/dist/primitives/reasoning/useScrollLock.d.ts +1 -2
  218. package/dist/primitives/reasoning/useScrollLock.d.ts.map +1 -1
  219. package/dist/primitives/selectionToolbar/SelectionToolbarQuote.d.ts +2 -3
  220. package/dist/primitives/selectionToolbar/SelectionToolbarQuote.d.ts.map +1 -1
  221. package/dist/primitives/selectionToolbar/SelectionToolbarRoot.d.ts +3 -4
  222. package/dist/primitives/selectionToolbar/SelectionToolbarRoot.d.ts.map +1 -1
  223. package/dist/primitives/selectionToolbar/SelectionToolbarRoot.js +5 -1
  224. package/dist/primitives/selectionToolbar/SelectionToolbarRoot.js.map +1 -1
  225. package/dist/primitives/suggestion/SuggestionDescription.d.ts +2 -3
  226. package/dist/primitives/suggestion/SuggestionDescription.d.ts.map +1 -1
  227. package/dist/primitives/suggestion/SuggestionTitle.d.ts +2 -3
  228. package/dist/primitives/suggestion/SuggestionTitle.d.ts.map +1 -1
  229. package/dist/primitives/suggestion/SuggestionTrigger.d.ts +2 -3
  230. package/dist/primitives/suggestion/SuggestionTrigger.d.ts.map +1 -1
  231. package/dist/primitives/thread/ThreadEmpty.d.ts +2 -3
  232. package/dist/primitives/thread/ThreadEmpty.d.ts.map +1 -1
  233. package/dist/primitives/thread/ThreadIf.d.ts +2 -3
  234. package/dist/primitives/thread/ThreadIf.d.ts.map +1 -1
  235. package/dist/primitives/thread/ThreadRoot.d.ts +2 -3
  236. package/dist/primitives/thread/ThreadRoot.d.ts.map +1 -1
  237. package/dist/primitives/thread/ThreadScrollToBottom.d.ts +3 -3
  238. package/dist/primitives/thread/ThreadScrollToBottom.d.ts.map +1 -1
  239. package/dist/primitives/thread/ThreadSuggestion.d.ts +2 -3
  240. package/dist/primitives/thread/ThreadSuggestion.d.ts.map +1 -1
  241. package/dist/primitives/thread/ThreadViewport.d.ts +2 -3
  242. package/dist/primitives/thread/ThreadViewport.d.ts.map +1 -1
  243. package/dist/primitives/thread/ThreadViewportFooter.d.ts +2 -3
  244. package/dist/primitives/thread/ThreadViewportFooter.d.ts.map +1 -1
  245. package/dist/primitives/thread/topAnchor/computeTopAnchorSlack.d.ts +4 -5
  246. package/dist/primitives/thread/topAnchor/computeTopAnchorSlack.d.ts.map +1 -1
  247. package/dist/primitives/thread/topAnchor/createReserveObservers.d.ts +1 -2
  248. package/dist/primitives/thread/topAnchor/createReserveObservers.d.ts.map +1 -1
  249. package/dist/primitives/thread/topAnchor/mountTopAnchorReserve.d.ts +2 -3
  250. package/dist/primitives/thread/topAnchor/mountTopAnchorReserve.d.ts.map +1 -1
  251. package/dist/primitives/thread/topAnchor/topAnchorTurn.d.ts +5 -6
  252. package/dist/primitives/thread/topAnchor/topAnchorTurn.d.ts.map +1 -1
  253. package/dist/primitives/thread/topAnchor/topAnchorUtils.d.ts +5 -6
  254. package/dist/primitives/thread/topAnchor/topAnchorUtils.d.ts.map +1 -1
  255. package/dist/primitives/thread/topAnchor/useTopAnchorReserve.d.ts +1 -2
  256. package/dist/primitives/thread/topAnchor/useTopAnchorReserve.d.ts.map +1 -1
  257. package/dist/primitives/thread/useThreadViewportAutoScroll.d.ts +2 -3
  258. package/dist/primitives/thread/useThreadViewportAutoScroll.d.ts.map +1 -1
  259. package/dist/primitives/thread/useThreadViewportAutoScroll.js +23 -15
  260. package/dist/primitives/thread/useThreadViewportAutoScroll.js.map +1 -1
  261. package/dist/primitives/threadList/ThreadListLoadMore.d.ts +2 -3
  262. package/dist/primitives/threadList/ThreadListLoadMore.d.ts.map +1 -1
  263. package/dist/primitives/threadList/ThreadListNew.d.ts +2 -3
  264. package/dist/primitives/threadList/ThreadListNew.d.ts.map +1 -1
  265. package/dist/primitives/threadList/ThreadListRoot.d.ts +2 -3
  266. package/dist/primitives/threadList/ThreadListRoot.d.ts.map +1 -1
  267. package/dist/primitives/threadListFocusGroup.d.ts +4 -4
  268. package/dist/primitives/threadListFocusGroup.d.ts.map +1 -1
  269. package/dist/primitives/threadListItem/ThreadListItemArchive.d.ts +2 -3
  270. package/dist/primitives/threadListItem/ThreadListItemArchive.d.ts.map +1 -1
  271. package/dist/primitives/threadListItem/ThreadListItemDelete.d.ts +2 -3
  272. package/dist/primitives/threadListItem/ThreadListItemDelete.d.ts.map +1 -1
  273. package/dist/primitives/threadListItem/ThreadListItemRoot.d.ts +2 -3
  274. package/dist/primitives/threadListItem/ThreadListItemRoot.d.ts.map +1 -1
  275. package/dist/primitives/threadListItem/ThreadListItemTrigger.d.ts +2 -3
  276. package/dist/primitives/threadListItem/ThreadListItemTrigger.d.ts.map +1 -1
  277. package/dist/primitives/threadListItem/ThreadListItemUnarchive.d.ts +2 -3
  278. package/dist/primitives/threadListItem/ThreadListItemUnarchive.d.ts.map +1 -1
  279. package/dist/primitives/threadListItemMore/ThreadListItemMoreContent.d.ts +2 -3
  280. package/dist/primitives/threadListItemMore/ThreadListItemMoreContent.d.ts.map +1 -1
  281. package/dist/primitives/threadListItemMore/ThreadListItemMoreItem.d.ts +2 -3
  282. package/dist/primitives/threadListItemMore/ThreadListItemMoreItem.d.ts.map +1 -1
  283. package/dist/primitives/threadListItemMore/ThreadListItemMoreRoot.d.ts +4 -5
  284. package/dist/primitives/threadListItemMore/ThreadListItemMoreRoot.d.ts.map +1 -1
  285. package/dist/primitives/threadListItemMore/ThreadListItemMoreSeparator.d.ts +2 -3
  286. package/dist/primitives/threadListItemMore/ThreadListItemMoreSeparator.d.ts.map +1 -1
  287. package/dist/primitives/threadListItemMore/ThreadListItemMoreTrigger.d.ts +2 -3
  288. package/dist/primitives/threadListItemMore/ThreadListItemMoreTrigger.d.ts.map +1 -1
  289. package/dist/primitives/threadListItemMore/scope.d.ts +2 -3
  290. package/dist/primitives/threadListItemMore/scope.d.ts.map +1 -1
  291. package/dist/sandbox-host/SandboxHost.d.ts +8 -9
  292. package/dist/sandbox-host/SandboxHost.d.ts.map +1 -1
  293. package/dist/sandbox-host/SandboxHost.js +1 -1
  294. package/dist/tests/remote-thread-list-test-helpers.d.ts +1 -2
  295. package/dist/tests/remote-thread-list-test-helpers.d.ts.map +1 -1
  296. package/dist/unstable/useComposerInput.d.ts +5 -6
  297. package/dist/unstable/useComposerInput.d.ts.map +1 -1
  298. package/dist/unstable/useComposerInputHistory.d.ts +2 -3
  299. package/dist/unstable/useComposerInputHistory.d.ts.map +1 -1
  300. package/dist/unstable/useLiveCompletionAdapter.d.ts +2 -3
  301. package/dist/unstable/useLiveCompletionAdapter.d.ts.map +1 -1
  302. package/dist/unstable/useMentionAdapter.d.ts +7 -8
  303. package/dist/unstable/useMentionAdapter.d.ts.map +1 -1
  304. package/dist/unstable/useMessageStallDetection.d.ts +3 -4
  305. package/dist/unstable/useMessageStallDetection.d.ts.map +1 -1
  306. package/dist/unstable/useModelContextSnapshot.d.ts +3 -4
  307. package/dist/unstable/useModelContextSnapshot.d.ts.map +1 -1
  308. package/dist/unstable/useSlashCommandAdapter.d.ts +4 -5
  309. package/dist/unstable/useSlashCommandAdapter.d.ts.map +1 -1
  310. package/dist/unstable/webmcp/WebMcpRegistrationResource.d.ts +2 -3
  311. package/dist/unstable/webmcp/WebMcpRegistrationResource.d.ts.map +1 -1
  312. package/dist/unstable/webmcp/convertTools.d.ts +4 -5
  313. package/dist/unstable/webmcp/convertTools.d.ts.map +1 -1
  314. package/dist/unstable/webmcp/useWebMcpProvider.d.ts +3 -4
  315. package/dist/unstable/webmcp/useWebMcpProvider.d.ts.map +1 -1
  316. package/dist/unstable/webmcp/webmcp-host.d.ts +6 -7
  317. package/dist/unstable/webmcp/webmcp-host.d.ts.map +1 -1
  318. package/dist/utils/Primitive.d.ts +4 -4
  319. package/dist/utils/RequireAtLeastOne.d.ts +1 -2
  320. package/dist/utils/RequireAtLeastOne.d.ts.map +1 -1
  321. package/dist/utils/createActionButton.d.ts +3 -4
  322. package/dist/utils/createActionButton.d.ts.map +1 -1
  323. package/dist/utils/getSelectionMessageId.d.ts +1 -2
  324. package/dist/utils/getSelectionMessageId.d.ts.map +1 -1
  325. package/dist/utils/hooks/useManagedRef.d.ts +1 -2
  326. package/dist/utils/hooks/useManagedRef.d.ts.map +1 -1
  327. package/dist/utils/hooks/useMediaQuery.d.ts +1 -2
  328. package/dist/utils/hooks/useMediaQuery.d.ts.map +1 -1
  329. package/dist/utils/hooks/useOnResizeContent.d.ts +1 -2
  330. package/dist/utils/hooks/useOnResizeContent.d.ts.map +1 -1
  331. package/dist/utils/hooks/useOnScrollToBottom.d.ts +1 -2
  332. package/dist/utils/hooks/useOnScrollToBottom.d.ts.map +1 -1
  333. package/dist/utils/hooks/useSizeHandle.d.ts +1 -2
  334. package/dist/utils/hooks/useSizeHandle.d.ts.map +1 -1
  335. package/dist/utils/smooth/SmoothContext.d.ts +3 -4
  336. package/dist/utils/smooth/SmoothContext.d.ts.map +1 -1
  337. package/dist/utils/smooth/useSmooth.d.ts +2 -3
  338. package/dist/utils/smooth/useSmooth.d.ts.map +1 -1
  339. package/package.json +17 -16
  340. package/src/context/stores/ThreadViewport.test.ts +29 -0
  341. package/src/context/stores/ThreadViewport.ts +6 -3
  342. package/src/index.ts +5 -0
  343. package/src/legacy-runtime/runtime-cores/external-store/external-message-converter.ts +2 -0
  344. package/src/mcp-apps/McpAppRenderer.test.tsx +1 -2
  345. package/src/mcp-apps/app-frame.test.tsx +0 -1
  346. package/src/model-context/frame/useAssistantFrameHost.test.tsx +42 -0
  347. package/src/model-context/frame/useAssistantFrameHost.ts +25 -2
  348. package/src/primitives/composer/ComposerAddAttachment.test.tsx +7 -5
  349. package/src/primitives/composer/ComposerRoot.test.tsx +5 -3
  350. package/src/primitives/selectionToolbar/SelectionToolbarRoot.test.tsx +44 -0
  351. package/src/primitives/selectionToolbar/SelectionToolbarRoot.tsx +7 -1
  352. package/src/primitives/thread/useThreadViewportAutoScroll.test.tsx +95 -0
  353. package/src/primitives/thread/useThreadViewportAutoScroll.ts +10 -0
  354. package/src/tests/RemoteThreadListRuntime.reloadMainThread.test.tsx +2 -4
  355. package/src/tests/threadListItemIsRunning.test.tsx +3 -2
  356. package/src/unstable/useMentionAdapter.test.tsx +15 -21
  357. package/src/unstable/useModelContextSnapshot.test.tsx +3 -2
  358. package/src/unstable/webmcp/convertTools.test.ts +59 -37
  359. package/src/unstable/webmcp/useWebMcpProvider.test.tsx +12 -3
@@ -1 +1 @@
1
- {"version":3,"file":"useManagedRef.d.ts","names":[],"sources":["../../../src/utils/hooks/useManagedRef.ts"],"mappings":";cAEa,gBAAiB,OAC5B,WAAW,MAAM,wCAAkC,IAK5C"}
1
+ {"version":3,"file":"useManagedRef.d.ts","names":[],"sources":["../../../src/utils/hooks/useManagedRef.ts"],"mappings":";qBAEa,gBAAiB,OAC5B,WAAW,MAAM,wCAAkC,IAK5C"}
@@ -1,5 +1,4 @@
1
1
  //#region src/utils/hooks/useMediaQuery.d.ts
2
- declare const useMediaQuery: (query: string | null) => boolean;
2
+ export declare const useMediaQuery: (query: string | null) => boolean;
3
3
  //#endregion
4
- export { useMediaQuery };
5
4
  //# sourceMappingURL=useMediaQuery.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useMediaQuery.d.ts","names":[],"sources":["../../../src/utils/hooks/useMediaQuery.ts"],"mappings":";cAOa,gBAAiB"}
1
+ {"version":3,"file":"useMediaQuery.d.ts","names":[],"sources":["../../../src/utils/hooks/useMediaQuery.ts"],"mappings":";qBAOa,gBAAiB"}
@@ -1,5 +1,4 @@
1
1
  //#region src/utils/hooks/useOnResizeContent.d.ts
2
- declare const useOnResizeContent: (callback: () => void) => (el: HTMLElement | null) => void;
2
+ export declare const useOnResizeContent: (callback: () => void) => (el: HTMLElement | null) => void;
3
3
  //#endregion
4
- export { useOnResizeContent };
5
4
  //# sourceMappingURL=useOnResizeContent.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useOnResizeContent.d.ts","names":[],"sources":["../../../src/utils/hooks/useOnResizeContent.ts"],"mappings":";cAIa,qBAAsB,0BAAoB,IAAA"}
1
+ {"version":3,"file":"useOnResizeContent.d.ts","names":[],"sources":["../../../src/utils/hooks/useOnResizeContent.ts"],"mappings":";qBAIa,qBAAsB,0BAAoB,IAAA"}
@@ -1,7 +1,6 @@
1
1
  //#region src/utils/hooks/useOnScrollToBottom.d.ts
2
- declare const useOnScrollToBottom: (callback: (config: {
2
+ export declare const useOnScrollToBottom: (callback: (config: {
3
3
  behavior: ScrollBehavior;
4
4
  }) => void) => void;
5
5
  //#endregion
6
- export { useOnScrollToBottom };
7
6
  //# sourceMappingURL=useOnScrollToBottom.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useOnScrollToBottom.d.ts","names":[],"sources":["../../../src/utils/hooks/useOnScrollToBottom.ts"],"mappings":";cAMa,sBACX,WAAW;EAAU,UAAU"}
1
+ {"version":3,"file":"useOnScrollToBottom.d.ts","names":[],"sources":["../../../src/utils/hooks/useOnScrollToBottom.ts"],"mappings":";qBAMa,sBACX,WAAW;EAAU,UAAU"}
@@ -8,7 +8,6 @@ import { SizeHandle } from "../../context/stores/ThreadViewport.js";
8
8
  * @param getHeight - Optional function to compute height (defaults to el.offsetHeight)
9
9
  * @returns A ref callback to attach to the element
10
10
  */
11
- declare const useSizeHandle: (register: (() => SizeHandle) | null | undefined, getHeight?: (el: HTMLElement) => number) => (el: HTMLElement | null) => void;
11
+ export declare const useSizeHandle: (register: (() => SizeHandle) | null | undefined, getHeight?: (el: HTMLElement) => number) => (el: HTMLElement | null) => void;
12
12
  //#endregion
13
- export { useSizeHandle };
14
13
  //# sourceMappingURL=useSizeHandle.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useSizeHandle.d.ts","names":[],"sources":["../../../src/utils/hooks/useSizeHandle.ts"],"mappings":";;;;;;;;;;cAca,gBACX,iBAAiB,gCACjB,aAAa,IAAI,4BAAsB,IAAA"}
1
+ {"version":3,"file":"useSizeHandle.d.ts","names":[],"sources":["../../../src/utils/hooks/useSizeHandle.ts"],"mappings":";;;;;;;;;;qBAca,gBACX,iBAAiB,gCACjB,aAAa,IAAI,4BAAsB,IAAA"}
@@ -1,9 +1,9 @@
1
1
  import { ReadonlyStore } from "../../context/ReadonlyStore.js";
2
2
  import { ComponentType, FC, PropsWithChildren } from "react";
3
3
  //#region src/utils/smooth/SmoothContext.d.ts
4
- declare const SmoothContextProvider: FC<PropsWithChildren>;
5
- declare const withSmoothContextProvider: <C extends ComponentType<any>>(Component: C) => C;
6
- declare const useSmoothStatus: {
4
+ export declare const SmoothContextProvider: FC<PropsWithChildren>;
5
+ export declare const withSmoothContextProvider: <C extends ComponentType<any>>(Component: C) => C;
6
+ export declare const useSmoothStatus: {
7
7
  (): {
8
8
  readonly type: "running";
9
9
  } | {
@@ -110,5 +110,4 @@ declare const useSmoothStatus: {
110
110
  }> | null;
111
111
  };
112
112
  //#endregion
113
- export { SmoothContextProvider, useSmoothStatus, useSmoothStatusStore, withSmoothContextProvider };
114
113
  //# sourceMappingURL=SmoothContext.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"SmoothContext.d.ts","names":[],"sources":["../../../src/utils/smooth/SmoothContext.tsx"],"mappings":";;;cAmCa,uBAAuB,GAAG;cAgB1B,4BAA6B,UAAU,oBAClD,WAAW,MACV;cA2BY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAAiB"}
1
+ {"version":3,"file":"SmoothContext.d.ts","names":[],"sources":["../../../src/utils/smooth/SmoothContext.tsx"],"mappings":";;;qBAmCa,uBAAuB,GAAG;qBAgB1B,4BAA6B,UAAU,oBAClD,WAAW,MACV;qBA2BY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAAiB"}
@@ -3,7 +3,7 @@ import { MessagePartState, ReasoningMessagePart, TextMessagePart } from "@assist
3
3
  /**
4
4
  * Tuning options for the smooth text streaming animation.
5
5
  */
6
- type SmoothOptions = {
6
+ export type SmoothOptions = {
7
7
  /**
8
8
  * Target time in milliseconds to drain the backlog of unrevealed
9
9
  * characters. Larger values reveal long backlogs more gradually.
@@ -53,7 +53,6 @@ type SmoothOptions = {
53
53
  * });
54
54
  * ```
55
55
  */
56
- declare const useSmooth: (state: MessagePartState & (TextMessagePart | ReasoningMessagePart), smooth?: boolean | SmoothOptions) => MessagePartState & (TextMessagePart | ReasoningMessagePart);
56
+ export declare const useSmooth: (state: MessagePartState & (TextMessagePart | ReasoningMessagePart), smooth?: boolean | SmoothOptions) => MessagePartState & (TextMessagePart | ReasoningMessagePart);
57
57
  //#endregion
58
- export { SmoothOptions, useSmooth };
59
58
  //# sourceMappingURL=useSmooth.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useSmooth.d.ts","names":[],"sources":["../../../src/utils/smooth/useSmooth.ts"],"mappings":";;;;;KAkBY;;;;;;EAMV;;;;;;EAMA;;;;;EAKA;;;;;;;;EAQA;;;;;;;;;;;;;;;;;;;;;;;;;cAgHW,YACX,OAAO,oBAAoB,kBAAkB,uBAC7C,mBAAkB,kBACjB,oBAAoB,kBAAkB"}
1
+ {"version":3,"file":"useSmooth.d.ts","names":[],"sources":["../../../src/utils/smooth/useSmooth.ts"],"mappings":";;;;;YAkBY;;;;;;EAMV;;;;;;EAMA;;;;;EAKA;;;;;;;;EAQA;;;;;;;;;;;;;;;;;;;;;;;;;qBAgHW,YACX,OAAO,oBAAoB,kBAAkB,uBAC7C,mBAAkB,kBACjB,oBAAoB,kBAAkB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@assistant-ui/react",
3
- "version": "0.15.19",
3
+ "version": "0.15.21",
4
4
  "description": "Open-source TypeScript/React library for building production-grade AI chat experiences",
5
5
  "keywords": [
6
6
  "ai",
@@ -55,15 +55,15 @@
55
55
  ],
56
56
  "sideEffects": false,
57
57
  "dependencies": {
58
- "@assistant-ui/core": "^0.3.18",
59
- "@assistant-ui/store": "^0.3.13",
60
- "@assistant-ui/tap": "^0.9.17",
61
- "assistant-cloud": "^0.2.0",
62
- "assistant-stream": "^0.3.42",
58
+ "@assistant-ui/core": "^0.3.20",
59
+ "@assistant-ui/store": "^0.3.14",
60
+ "@assistant-ui/tap": "^0.9.18",
61
+ "assistant-cloud": "^0.2.2",
62
+ "assistant-stream": "^0.3.44",
63
63
  "radix-ui": "^1.6.7",
64
64
  "react-textarea-autosize": "^8.5.9",
65
- "safe-content-frame": "^0.0.30",
66
- "zod": "^4.5.4",
65
+ "safe-content-frame": "^0.0.31",
66
+ "zod": "^4.6.5",
67
67
  "zustand": "^5.0.15"
68
68
  },
69
69
  "peerDependencies": {
@@ -81,17 +81,17 @@
81
81
  }
82
82
  },
83
83
  "devDependencies": {
84
- "@assistant-ui/vite": "0.0.17",
85
- "@assistant-ui/x-buildutils": "0.0.26",
84
+ "@assistant-ui/vite": "0.0.18",
85
+ "@assistant-ui/x-buildutils": "0.0.28",
86
86
  "@testing-library/react": "^16.3.3",
87
87
  "@types/json-schema": "^7.0.15",
88
- "@types/node": "^26.4.1",
89
- "@types/react": "^19.2.18",
90
- "@types/react-dom": "^19.2.7",
88
+ "@types/node": "^26.5.1",
89
+ "@types/react": "^19.3.0",
90
+ "@types/react-dom": "^19.3.0",
91
91
  "jsdom": "^30.0.1",
92
- "react": "^19.2.8",
93
- "react-dom": "^19.2.8",
94
- "vitest": "^4.1.11"
92
+ "react": "^19.3.0",
93
+ "react-dom": "^19.3.0",
94
+ "vitest": "^5.0.1"
95
95
  },
96
96
  "publishConfig": {
97
97
  "access": "public",
@@ -109,6 +109,7 @@
109
109
  "scripts": {
110
110
  "build": "aui-build",
111
111
  "test": "vitest run",
112
+ "typecheck": "tsc --noEmit",
112
113
  "test:watch": "vitest"
113
114
  }
114
115
  }
@@ -0,0 +1,29 @@
1
+ import { describe, expect, it, onTestFinished, vi } from "vitest";
2
+ import { makeThreadViewportStore } from "./ThreadViewport";
3
+
4
+ describe("makeThreadViewportStore", () => {
5
+ it("notifies every scroll listener when one throws", () => {
6
+ const store = makeThreadViewportStore();
7
+ const listenerError = new Error("scroll listener failed");
8
+ const consoleError = vi
9
+ .spyOn(console, "error")
10
+ .mockImplementation(() => {});
11
+ onTestFinished(() => consoleError.mockRestore());
12
+ const laterListener = vi.fn();
13
+
14
+ store.getState().onScrollToBottom(() => {
15
+ throw listenerError;
16
+ });
17
+ store.getState().onScrollToBottom((config) => {
18
+ config.behavior = "smooth";
19
+ });
20
+ store.getState().onScrollToBottom(laterListener);
21
+
22
+ expect(() => store.getState().scrollToBottom()).not.toThrow();
23
+ expect(laterListener).toHaveBeenCalledWith({ behavior: "auto" });
24
+ expect(consoleError).toHaveBeenCalledWith(
25
+ expect.stringContaining("Thread viewport"),
26
+ listenerError,
27
+ );
28
+ });
29
+ });
@@ -2,6 +2,7 @@
2
2
 
3
3
  import { create } from "zustand";
4
4
  import type { Unsubscribe } from "@assistant-ui/core";
5
+ import { notifyEventListeners } from "@assistant-ui/core/internal";
5
6
 
6
7
  export type SizeHandle = {
7
8
  /** Update the height */
@@ -184,9 +185,11 @@ export const makeThreadViewportStore = (
184
185
  const store = create<ThreadViewportState>(() => ({
185
186
  isAtBottom: true,
186
187
  scrollToBottom: ({ behavior = "auto" } = {}) => {
187
- for (const listener of scrollToBottomListeners) {
188
- listener({ behavior });
189
- }
188
+ notifyEventListeners(
189
+ scrollToBottomListeners,
190
+ () => ({ behavior }),
191
+ "Thread viewport",
192
+ );
190
193
  },
191
194
  onScrollToBottom: (callback) => {
192
195
  scrollToBottomListeners.add(callback);
package/src/index.ts CHANGED
@@ -159,6 +159,8 @@ export { useExternalStoreSharedOptions } from "@assistant-ui/core/react";
159
159
  export {
160
160
  useExternalMessageConverter,
161
161
  convertExternalMessages as unstable_convertExternalMessages,
162
+ createExternalMessageConversionCache as unstable_createExternalMessageConversionCache,
163
+ type ExternalMessageConversionCache as Unstable_ExternalMessageConversionCache,
162
164
  } from "./legacy-runtime/runtime-cores/external-store/external-message-converter";
163
165
  export { createMessageConverter as unstable_createMessageConverter } from "./legacy-runtime/runtime-cores/external-store/createMessageConverter";
164
166
 
@@ -278,6 +280,8 @@ export { tool } from "@assistant-ui/core";
278
280
  export { Suggestions, type SuggestionConfig } from "@assistant-ui/core/store";
279
281
  export type {
280
282
  QueueItemState,
283
+ TaskState,
284
+ TaskMethods,
281
285
  QueueItemMethods,
282
286
  } from "@assistant-ui/core/store";
283
287
  export type { ComposerSendOptions } from "@assistant-ui/core/store";
@@ -374,6 +378,7 @@ export type {
374
378
  MessagePartStreamStatus,
375
379
  ToolCallMessagePartStatus,
376
380
  MessageTiming,
381
+ MessageModality,
377
382
  ThreadUserMessagePart,
378
383
  ThreadAssistantMessagePart,
379
384
  ThreadSystemMessage,
@@ -2,4 +2,6 @@
2
2
  export {
3
3
  useExternalMessageConverter,
4
4
  convertExternalMessages,
5
+ createExternalMessageConversionCache,
6
+ type ExternalMessageConversionCache,
5
7
  } from "@assistant-ui/core/react";
@@ -70,8 +70,7 @@ const createPart = (
70
70
  });
71
71
 
72
72
  const createPartWithoutApp = (): ToolCallMessagePartProps => {
73
- const part = createPart();
74
- delete part.mcp;
73
+ const { mcp: _mcp, ...part } = createPart();
75
74
  return part;
76
75
  };
77
76
 
@@ -29,7 +29,6 @@ import { McpAppFrame } from "./app-frame";
29
29
  describe("McpAppFrame", () => {
30
30
  afterEach(() => {
31
31
  cleanup();
32
- vi.clearAllMocks();
33
32
  });
34
33
 
35
34
  it("keeps bridge options scoped to committed renders", async () => {
@@ -0,0 +1,42 @@
1
+ // @vitest-environment jsdom
2
+
3
+ import { renderHook } from "@testing-library/react";
4
+ import { AssistantFrameHost } from "@assistant-ui/core";
5
+ import { afterEach, describe, expect, it, vi } from "vitest";
6
+ import { useAssistantFrameHost } from "./useAssistantFrameHost";
7
+
8
+ afterEach(() => {
9
+ vi.restoreAllMocks();
10
+ });
11
+
12
+ describe("useAssistantFrameHost", () => {
13
+ it("unregisters the host when disposal throws", () => {
14
+ const disposalError = new Error("tool cancellation failed");
15
+ const unregistrationError = new Error("unregistration failed");
16
+ vi.spyOn(AssistantFrameHost.prototype, "dispose").mockImplementation(() => {
17
+ throw disposalError;
18
+ });
19
+ const consoleError = vi
20
+ .spyOn(console, "error")
21
+ .mockImplementation(() => undefined);
22
+ const unsubscribe = vi.fn(() => {
23
+ throw unregistrationError;
24
+ });
25
+ const register = vi.fn(() => unsubscribe);
26
+ const iframeRef = {
27
+ current: {
28
+ contentWindow: { postMessage: vi.fn() } as unknown as Window,
29
+ } as HTMLIFrameElement,
30
+ };
31
+ const { unmount } = renderHook(() =>
32
+ useAssistantFrameHost({ iframeRef, register }),
33
+ );
34
+
35
+ expect(() => unmount()).toThrow(disposalError);
36
+ expect(unsubscribe).toHaveBeenCalledOnce();
37
+ expect(consoleError).toHaveBeenCalledWith(
38
+ "[assistant-ui] AssistantFrameHost unregistration failed.",
39
+ unregistrationError,
40
+ );
41
+ });
42
+ });
@@ -41,8 +41,31 @@ export const useAssistantFrameHost = ({
41
41
  const unsubscribe = register(frameHost);
42
42
 
43
43
  return () => {
44
- frameHost.dispose();
45
- unsubscribe();
44
+ let cleanupFailed = false;
45
+ let cleanupError: unknown;
46
+
47
+ try {
48
+ frameHost.dispose();
49
+ } catch (error) {
50
+ cleanupFailed = true;
51
+ cleanupError = error;
52
+ }
53
+
54
+ try {
55
+ unsubscribe();
56
+ } catch (error) {
57
+ if (cleanupFailed) {
58
+ console.error(
59
+ "[assistant-ui] AssistantFrameHost unregistration failed.",
60
+ error,
61
+ );
62
+ } else {
63
+ cleanupFailed = true;
64
+ cleanupError = error;
65
+ }
66
+ }
67
+
68
+ if (cleanupFailed) throw cleanupError;
46
69
  };
47
70
  }, [iframeRef, targetOrigin, register]);
48
71
  };
@@ -78,14 +78,16 @@ describe("ComposerPrimitiveAddAttachment", () => {
78
78
 
79
79
  const button = container.querySelector("button");
80
80
  expect(button).not.toBeNull();
81
+ if (!button) throw new Error("Attachment button was not rendered");
81
82
 
82
83
  await act(async () => {
83
- button!.click();
84
+ button.click();
84
85
  });
85
86
 
86
87
  const input =
87
88
  document.querySelector<HTMLInputElement>('input[type="file"]');
88
89
  expect(input).not.toBeNull();
90
+ if (!input) throw new Error("File input was not rendered");
89
91
 
90
92
  const files = [
91
93
  new File(["a"], "unsupported.bin"),
@@ -96,13 +98,13 @@ describe("ComposerPrimitiveAddAttachment", () => {
96
98
  value: files,
97
99
  });
98
100
 
99
- const result = input!.onchange?.call(input, {
100
- target: input,
101
- } as unknown as Event);
101
+ const event = new Event("change");
102
+ Object.defineProperty(event, "target", { value: input });
103
+ const result = input.onchange?.call(input, event);
102
104
 
103
105
  await expect(Promise.resolve(result)).resolves.toBeUndefined();
104
106
  expect(addAttachment).toHaveBeenCalledTimes(2);
105
107
  expect(errorSpy).not.toHaveBeenCalled();
106
- expect(input!.isConnected).toBe(false);
108
+ expect(input.isConnected).toBe(false);
107
109
  });
108
110
  });
@@ -354,9 +354,11 @@ describe("ComposerPrimitiveRoot compact mode", () => {
354
354
  );
355
355
 
356
356
  it("updates compact mode when the compact context multiline latch changes", async () => {
357
- let compactContext: ComposerCompactContextValue | null = null;
357
+ const compactContext: { current: ComposerCompactContextValue | null } = {
358
+ current: null,
359
+ };
358
360
  const Probe = () => {
359
- compactContext = useComposerCompactContextOptional();
361
+ compactContext.current = useComposerCompactContextOptional();
360
362
  return null;
361
363
  };
362
364
 
@@ -364,7 +366,7 @@ describe("ComposerPrimitiveRoot compact mode", () => {
364
366
  compact: true,
365
367
  children: <Probe />,
366
368
  });
367
- const context = compactContext;
369
+ const context = compactContext.current;
368
370
  expect(context).not.toBeNull();
369
371
  if (!context) throw new Error("Composer compact context was not provided");
370
372
  expect(form.hasAttribute("data-compact")).toBe(true);
@@ -72,3 +72,47 @@ describe("SelectionToolbarPrimitiveRoot onMouseDown composition", () => {
72
72
  expect(notPrevented).toBe(false);
73
73
  });
74
74
  });
75
+
76
+ describe("SelectionToolbarPrimitiveRoot frame cleanup", () => {
77
+ // Defer the frame instead of running it inline, so the window between the
78
+ // selection event and the frame is observable.
79
+ const deferFrames = () => {
80
+ const frames: FrameRequestCallback[] = [];
81
+ let nextHandle = 1;
82
+ vi.spyOn(window, "requestAnimationFrame").mockImplementation((cb) => {
83
+ frames.push(cb);
84
+ return nextHandle++;
85
+ });
86
+ const cancelAnimationFrame = vi
87
+ .spyOn(window, "cancelAnimationFrame")
88
+ .mockImplementation(() => {});
89
+ return { frames, cancelAnimationFrame };
90
+ };
91
+
92
+ it("cancels a queued selection frame when the toolbar unmounts", () => {
93
+ const { frames, cancelAnimationFrame } = deferFrames();
94
+ const { unmount } = render(<SelectionToolbarPrimitiveRoot />);
95
+
96
+ fireEvent.mouseUp(document);
97
+ expect(frames).toHaveLength(1);
98
+
99
+ unmount();
100
+
101
+ expect(cancelAnimationFrame).toHaveBeenCalledWith(1);
102
+ });
103
+
104
+ it("cancels the previous frame when another selection event arrives", () => {
105
+ const { frames, cancelAnimationFrame } = deferFrames();
106
+ const { unmount } = render(<SelectionToolbarPrimitiveRoot />);
107
+
108
+ fireEvent.mouseUp(document);
109
+ fireEvent.keyUp(document);
110
+ expect(frames).toHaveLength(2);
111
+ expect(cancelAnimationFrame).toHaveBeenCalledWith(1);
112
+
113
+ unmount();
114
+
115
+ expect(cancelAnimationFrame).toHaveBeenCalledTimes(2);
116
+ expect(cancelAnimationFrame).toHaveBeenLastCalledWith(2);
117
+ });
118
+ });
@@ -51,8 +51,13 @@ export const SelectionToolbarPrimitiveRoot = forwardRef<
51
51
  const [info, setInfo] = useState<SelectionInfo | null>(null);
52
52
 
53
53
  useEffect(() => {
54
+ // Read the selection on the next frame so the browser has settled it.
55
+ let pendingFrame: number | null = null;
56
+
54
57
  const checkSelection = () => {
55
- requestAnimationFrame(() => {
58
+ if (pendingFrame !== null) cancelAnimationFrame(pendingFrame);
59
+ pendingFrame = requestAnimationFrame(() => {
60
+ pendingFrame = null;
56
61
  const sel = window.getSelection();
57
62
  if (!sel || sel.isCollapsed) {
58
63
  setInfo(null);
@@ -94,6 +99,7 @@ export const SelectionToolbarPrimitiveRoot = forwardRef<
94
99
  document.addEventListener("scroll", handleScroll, true);
95
100
 
96
101
  return () => {
102
+ if (pendingFrame !== null) cancelAnimationFrame(pendingFrame);
97
103
  document.removeEventListener("mouseup", checkSelection);
98
104
  document.removeEventListener("keyup", checkSelection);
99
105
  document.removeEventListener("selectionchange", handleSelectionCollapse);
@@ -498,6 +498,101 @@ describe("useThreadViewportAutoScroll", () => {
498
498
  expect(screen.getByTestId("is-at-bottom").textContent).toBe("false");
499
499
  });
500
500
 
501
+ it("starts following when auto-scroll is enabled at the bottom", async () => {
502
+ const view = render(
503
+ <SyncRuntimeProvider>
504
+ <Thread autoScroll={false} scrollToBottomOnInitialize={false} />
505
+ </SyncRuntimeProvider>,
506
+ );
507
+
508
+ const viewport = getViewport();
509
+ await waitFor(() => {
510
+ expect(screen.getAllByTestId("thread-message")).toHaveLength(
511
+ messages.length,
512
+ );
513
+ });
514
+
515
+ act(() => {
516
+ viewport.scrollTop = getMaxScrollTop(viewport);
517
+ viewport.dispatchEvent(new Event("scroll"));
518
+ });
519
+
520
+ view.rerender(
521
+ <SyncRuntimeProvider>
522
+ <Thread autoScroll scrollToBottomOnInitialize={false} />
523
+ </SyncRuntimeProvider>,
524
+ );
525
+
526
+ viewportMeasurementOffset += 200;
527
+ act(notifyResizeObservers);
528
+
529
+ expect(viewport.scrollTop).toBe(getMaxScrollTop(viewport));
530
+ });
531
+
532
+ it("preserves bottom follow on initial mount when initialize scrolling is disabled", async () => {
533
+ render(
534
+ <SyncRuntimeProvider>
535
+ <ThreadPrimitiveRoot>
536
+ <ThreadPrimitiveViewport
537
+ autoScroll
538
+ data-testid="viewport"
539
+ scrollToBottomOnInitialize={false}
540
+ turnAnchor="top"
541
+ >
542
+ {messages.map((_, index) => (
543
+ <div key={index} data-testid="thread-message" />
544
+ ))}
545
+ </ThreadPrimitiveViewport>
546
+ </ThreadPrimitiveRoot>
547
+ </SyncRuntimeProvider>,
548
+ );
549
+
550
+ const viewport = getViewport();
551
+ await waitFor(() => {
552
+ expect(screen.getAllByTestId("thread-message")).toHaveLength(
553
+ messages.length,
554
+ );
555
+ });
556
+
557
+ viewportMeasurementOffset += 200;
558
+ act(notifyResizeObservers);
559
+
560
+ expect(viewport.scrollTop).toBe(getMaxScrollTop(viewport));
561
+ });
562
+
563
+ it("does not jump down when auto-scroll is enabled away from the bottom", async () => {
564
+ const view = render(
565
+ <SyncRuntimeProvider>
566
+ <Thread autoScroll={false} scrollToBottomOnInitialize={false} />
567
+ </SyncRuntimeProvider>,
568
+ );
569
+
570
+ const viewport = getViewport();
571
+ await waitFor(() => {
572
+ expect(screen.getAllByTestId("thread-message")).toHaveLength(
573
+ messages.length,
574
+ );
575
+ });
576
+
577
+ act(() => {
578
+ viewport.scrollTop = getMaxScrollTop(viewport) - 80;
579
+ viewport.dispatchEvent(new Event("scroll"));
580
+ });
581
+ const scrollTopBeforeEnable = viewport.scrollTop;
582
+
583
+ view.rerender(
584
+ <SyncRuntimeProvider>
585
+ <Thread autoScroll scrollToBottomOnInitialize={false} />
586
+ </SyncRuntimeProvider>,
587
+ );
588
+
589
+ viewportMeasurementOffset += 200;
590
+ act(notifyResizeObservers);
591
+
592
+ expect(viewport.scrollTop).toBe(scrollTopBeforeEnable);
593
+ expect(viewport.scrollTop).toBeLessThan(getMaxScrollTop(viewport));
594
+ });
595
+
501
596
  it("defers auto-scroll to an active top anchor only while the run is active", async () => {
502
597
  let releaseRun!: () => void;
503
598
  const runGate = new Promise<void>((resolve) => {
@@ -74,6 +74,16 @@ export const useThreadViewportAutoScroll = <TElement extends HTMLElement>({
74
74
  // user actively scrolls up while content size is stable.
75
75
  const scrollingToBottomBehaviorRef = useRef<ScrollBehavior | null>(null);
76
76
  const followBottomRef = useRef(autoScroll);
77
+ const previousAutoScrollRef = useRef(autoScroll);
78
+
79
+ useLayoutEffect(() => {
80
+ const previousAutoScroll = previousAutoScrollRef.current;
81
+ previousAutoScrollRef.current = autoScroll;
82
+ if (previousAutoScroll || !autoScroll) return;
83
+
84
+ const div = divRef.current;
85
+ followBottomRef.current = div !== null && isViewportAtBottom(div);
86
+ }, [autoScroll]);
77
87
 
78
88
  const scrollToBottom = useCallback((behavior: ScrollBehavior) => {
79
89
  const div = divRef.current;
@@ -3,10 +3,8 @@
3
3
  import { act, render, waitFor } from "@testing-library/react";
4
4
  import { type FC, useEffect } from "react";
5
5
  import { describe, expect, it } from "vitest";
6
- import {
7
- useRemoteThreadListRuntime,
8
- type AssistantRuntime,
9
- } from "@assistant-ui/core/react";
6
+ import type { AssistantRuntime } from "@assistant-ui/core";
7
+ import { useRemoteThreadListRuntime } from "@assistant-ui/core/react";
10
8
  import { makeAdapter } from "./remote-thread-list-test-helpers";
11
9
  import { useLocalRuntime } from "../legacy-runtime/runtime-cores/local/useLocalRuntime";
12
10
  import { AssistantRuntimeProvider } from "../context";
@@ -3,6 +3,7 @@
3
3
  import { act, render, screen, waitFor } from "@testing-library/react";
4
4
  import { type FC, useEffect, useReducer } from "react";
5
5
  import { describe, expect, it } from "vitest";
6
+ import type { ThreadMessage } from "@assistant-ui/core";
6
7
  import { useRemoteThreadListRuntime } from "@assistant-ui/core/react";
7
8
  import { makeAdapter } from "./remote-thread-list-test-helpers";
8
9
  import { AssistantRuntimeProvider } from "../context";
@@ -79,7 +80,7 @@ describe("threadListItem.isRunning", () => {
79
80
 
80
81
  it("reports the run of a single-thread runtime that cannot observe background threads", async () => {
81
82
  const Inner: FC<{ isRunning: boolean }> = ({ isRunning }) => {
82
- const runtime = useExternalStoreRuntime({
83
+ const runtime = useExternalStoreRuntime<ThreadMessage>({
83
84
  messages: [],
84
85
  isRunning,
85
86
  onNew: async () => {},
@@ -126,7 +127,7 @@ describe("threadListItem.isRunning", () => {
126
127
  };
127
128
  }, []);
128
129
 
129
- return useExternalStoreRuntime({
130
+ return useExternalStoreRuntime<ThreadMessage>({
130
131
  messages: [],
131
132
  isRunning: running.get(threadId) ?? false,
132
133
  onNew: async () => {},