@assistant-ui/react 0.14.16 → 0.14.19

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 (380) hide show
  1. package/dist/client/ExternalThread.d.ts +5 -3
  2. package/dist/client/ExternalThread.d.ts.map +1 -1
  3. package/dist/client/ExternalThread.js +745 -255
  4. package/dist/client/ExternalThread.js.map +1 -1
  5. package/dist/client/InMemoryThreadList.d.ts +1 -1
  6. package/dist/client/InMemoryThreadList.d.ts.map +1 -1
  7. package/dist/client/InMemoryThreadList.js +299 -113
  8. package/dist/client/InMemoryThreadList.js.map +1 -1
  9. package/dist/client/SingleThreadList.d.ts +1 -6
  10. package/dist/client/SingleThreadList.d.ts.map +1 -1
  11. package/dist/client/SingleThreadList.js +143 -55
  12. package/dist/client/SingleThreadList.js.map +1 -1
  13. package/dist/context/ReadonlyStore.js.map +1 -1
  14. package/dist/context/providers/MessageProvider.js +38 -5
  15. package/dist/context/providers/MessageProvider.js.map +1 -1
  16. package/dist/context/providers/ThreadViewportProvider.js +76 -20
  17. package/dist/context/providers/ThreadViewportProvider.js.map +1 -1
  18. package/dist/context/react/ThreadViewportContext.js.map +1 -1
  19. package/dist/context/react/utils/createContextHook.js.map +1 -1
  20. package/dist/context/react/utils/createContextStoreHook.js +17 -2
  21. package/dist/context/react/utils/createContextStoreHook.js.map +1 -1
  22. package/dist/context/react/utils/createStateHookForRuntime.js.map +1 -1
  23. package/dist/context/react/utils/ensureBinding.js.map +1 -1
  24. package/dist/context/react/utils/useRuntimeState.js +18 -2
  25. package/dist/context/react/utils/useRuntimeState.js.map +1 -1
  26. package/dist/context/stores/ThreadViewport.js.map +1 -1
  27. package/dist/devtools/DevToolsHooks.js.map +1 -1
  28. package/dist/hooks/useMessageQuote.js.map +1 -1
  29. package/dist/hooks/useMessageTiming.js +4 -1
  30. package/dist/hooks/useMessageTiming.js.map +1 -1
  31. package/dist/hooks/useToolCallElapsed.d.ts +23 -0
  32. package/dist/hooks/useToolCallElapsed.d.ts.map +1 -0
  33. package/dist/hooks/useToolCallElapsed.js +72 -0
  34. package/dist/hooks/useToolCallElapsed.js.map +1 -0
  35. package/dist/index.d.ts +6 -2
  36. package/dist/index.js +5 -1
  37. package/dist/internal.js.map +1 -1
  38. package/dist/legacy-runtime/AssistantRuntimeProvider.js +46 -10
  39. package/dist/legacy-runtime/AssistantRuntimeProvider.js.map +1 -1
  40. package/dist/legacy-runtime/cloud/auiV0.js.map +1 -1
  41. package/dist/legacy-runtime/cloud/useCloudThreadListRuntime.js +27 -6
  42. package/dist/legacy-runtime/cloud/useCloudThreadListRuntime.js.map +1 -1
  43. package/dist/legacy-runtime/hooks/AssistantContext.js +13 -2
  44. package/dist/legacy-runtime/hooks/AssistantContext.js.map +1 -1
  45. package/dist/legacy-runtime/hooks/AttachmentContext.js +9 -1
  46. package/dist/legacy-runtime/hooks/AttachmentContext.js.map +1 -1
  47. package/dist/legacy-runtime/hooks/ComposerContext.js +9 -1
  48. package/dist/legacy-runtime/hooks/ComposerContext.js.map +1 -1
  49. package/dist/legacy-runtime/hooks/MessageContext.js +12 -2
  50. package/dist/legacy-runtime/hooks/MessageContext.js.map +1 -1
  51. package/dist/legacy-runtime/hooks/MessagePartContext.js +9 -1
  52. package/dist/legacy-runtime/hooks/MessagePartContext.js.map +1 -1
  53. package/dist/legacy-runtime/hooks/ThreadContext.js +33 -5
  54. package/dist/legacy-runtime/hooks/ThreadContext.js.map +1 -1
  55. package/dist/legacy-runtime/hooks/ThreadListItemContext.js +9 -1
  56. package/dist/legacy-runtime/hooks/ThreadListItemContext.js.map +1 -1
  57. package/dist/legacy-runtime/runtime-cores/assistant-transport/commandQueue.js +3 -3
  58. package/dist/legacy-runtime/runtime-cores/assistant-transport/commandQueue.js.map +1 -1
  59. package/dist/legacy-runtime/runtime-cores/assistant-transport/replayBoundaryStream.js +71 -31
  60. package/dist/legacy-runtime/runtime-cores/assistant-transport/replayBoundaryStream.js.map +1 -1
  61. package/dist/legacy-runtime/runtime-cores/assistant-transport/runManager.js.map +1 -1
  62. package/dist/legacy-runtime/runtime-cores/assistant-transport/useAssistantTransportRuntime.js +24 -16
  63. package/dist/legacy-runtime/runtime-cores/assistant-transport/useAssistantTransportRuntime.js.map +1 -1
  64. package/dist/legacy-runtime/runtime-cores/assistant-transport/useConvertedState.js +17 -12
  65. package/dist/legacy-runtime/runtime-cores/assistant-transport/useConvertedState.js.map +1 -1
  66. package/dist/legacy-runtime/runtime-cores/assistant-transport/useLatestRef.js +17 -3
  67. package/dist/legacy-runtime/runtime-cores/assistant-transport/useLatestRef.js.map +1 -1
  68. package/dist/mcp-apps/McpAppRenderer.d.ts +2 -10
  69. package/dist/mcp-apps/McpAppRenderer.d.ts.map +1 -1
  70. package/dist/mcp-apps/McpAppRenderer.js +9 -8
  71. package/dist/mcp-apps/McpAppRenderer.js.map +1 -1
  72. package/dist/mcp-apps/McpAppsRemoteHost.d.ts +1 -8
  73. package/dist/mcp-apps/McpAppsRemoteHost.d.ts.map +1 -1
  74. package/dist/mcp-apps/McpAppsRemoteHost.js +6 -5
  75. package/dist/mcp-apps/McpAppsRemoteHost.js.map +1 -1
  76. package/dist/mcp-apps/app-frame.js +33 -14
  77. package/dist/mcp-apps/app-frame.js.map +1 -1
  78. package/dist/mcp-apps/bridge.js.map +1 -1
  79. package/dist/mcp-apps/types.js.map +1 -1
  80. package/dist/mcp-apps/utils.js.map +1 -1
  81. package/dist/model-context/frame/useAssistantFrameHost.js +32 -14
  82. package/dist/model-context/frame/useAssistantFrameHost.js.map +1 -1
  83. package/dist/model-context/makeAssistantVisible.js +64 -26
  84. package/dist/model-context/makeAssistantVisible.js.map +1 -1
  85. package/dist/primitives/actionBar/ActionBarCopy.js +94 -20
  86. package/dist/primitives/actionBar/ActionBarCopy.js.map +1 -1
  87. package/dist/primitives/actionBar/ActionBarEdit.js.map +1 -1
  88. package/dist/primitives/actionBar/ActionBarExportMarkdown.js +105 -37
  89. package/dist/primitives/actionBar/ActionBarExportMarkdown.js.map +1 -1
  90. package/dist/primitives/actionBar/ActionBarFeedbackNegative.js +60 -11
  91. package/dist/primitives/actionBar/ActionBarFeedbackNegative.js.map +1 -1
  92. package/dist/primitives/actionBar/ActionBarFeedbackPositive.js +60 -11
  93. package/dist/primitives/actionBar/ActionBarFeedbackPositive.js.map +1 -1
  94. package/dist/primitives/actionBar/ActionBarInteractionContext.js +3 -1
  95. package/dist/primitives/actionBar/ActionBarInteractionContext.js.map +1 -1
  96. package/dist/primitives/actionBar/ActionBarReload.js.map +1 -1
  97. package/dist/primitives/actionBar/ActionBarRoot.js +84 -25
  98. package/dist/primitives/actionBar/ActionBarRoot.js.map +1 -1
  99. package/dist/primitives/actionBar/ActionBarSpeak.js.map +1 -1
  100. package/dist/primitives/actionBar/ActionBarStopSpeaking.js +45 -14
  101. package/dist/primitives/actionBar/ActionBarStopSpeaking.js.map +1 -1
  102. package/dist/primitives/actionBar/useActionBarFloatStatus.js +22 -10
  103. package/dist/primitives/actionBar/useActionBarFloatStatus.js.map +1 -1
  104. package/dist/primitives/actionBar.js.map +1 -1
  105. package/dist/primitives/actionBarMore/ActionBarMoreContent.js +44 -7
  106. package/dist/primitives/actionBarMore/ActionBarMoreContent.js.map +1 -1
  107. package/dist/primitives/actionBarMore/ActionBarMoreItem.js +28 -6
  108. package/dist/primitives/actionBarMore/ActionBarMoreItem.js.map +1 -1
  109. package/dist/primitives/actionBarMore/ActionBarMoreRoot.js +103 -36
  110. package/dist/primitives/actionBarMore/ActionBarMoreRoot.js.map +1 -1
  111. package/dist/primitives/actionBarMore/ActionBarMoreSeparator.js +28 -6
  112. package/dist/primitives/actionBarMore/ActionBarMoreSeparator.js.map +1 -1
  113. package/dist/primitives/actionBarMore/ActionBarMoreTrigger.js +28 -6
  114. package/dist/primitives/actionBarMore/ActionBarMoreTrigger.js.map +1 -1
  115. package/dist/primitives/actionBarMore/scope.js.map +1 -1
  116. package/dist/primitives/actionBarMore.js.map +1 -1
  117. package/dist/primitives/assistantModal/AssistantModalAnchor.js +27 -6
  118. package/dist/primitives/assistantModal/AssistantModalAnchor.js.map +1 -1
  119. package/dist/primitives/assistantModal/AssistantModalContent.js +71 -10
  120. package/dist/primitives/assistantModal/AssistantModalContent.js.map +1 -1
  121. package/dist/primitives/assistantModal/AssistantModalRoot.js +93 -26
  122. package/dist/primitives/assistantModal/AssistantModalRoot.js.map +1 -1
  123. package/dist/primitives/assistantModal/AssistantModalTrigger.js +27 -6
  124. package/dist/primitives/assistantModal/AssistantModalTrigger.js.map +1 -1
  125. package/dist/primitives/assistantModal/scope.js.map +1 -1
  126. package/dist/primitives/assistantModal.js.map +1 -1
  127. package/dist/primitives/attachment/AttachmentName.js +13 -1
  128. package/dist/primitives/attachment/AttachmentName.js.map +1 -1
  129. package/dist/primitives/attachment/AttachmentRemove.js +11 -4
  130. package/dist/primitives/attachment/AttachmentRemove.js.map +1 -1
  131. package/dist/primitives/attachment/AttachmentRoot.js +13 -4
  132. package/dist/primitives/attachment/AttachmentRoot.js.map +1 -1
  133. package/dist/primitives/attachment/AttachmentThumb.js +20 -9
  134. package/dist/primitives/attachment/AttachmentThumb.js.map +1 -1
  135. package/dist/primitives/attachment.js.map +1 -1
  136. package/dist/primitives/branchPicker/BranchPickerCount.js +14 -2
  137. package/dist/primitives/branchPicker/BranchPickerCount.js.map +1 -1
  138. package/dist/primitives/branchPicker/BranchPickerNext.js.map +1 -1
  139. package/dist/primitives/branchPicker/BranchPickerNumber.js +14 -2
  140. package/dist/primitives/branchPicker/BranchPickerNumber.js.map +1 -1
  141. package/dist/primitives/branchPicker/BranchPickerPrevious.js.map +1 -1
  142. package/dist/primitives/branchPicker/BranchPickerRoot.js +34 -6
  143. package/dist/primitives/branchPicker/BranchPickerRoot.js.map +1 -1
  144. package/dist/primitives/branchPicker.js.map +1 -1
  145. package/dist/primitives/chainOfThought/ChainOfThoughtAccordionTrigger.js +16 -5
  146. package/dist/primitives/chainOfThought/ChainOfThoughtAccordionTrigger.js.map +1 -1
  147. package/dist/primitives/chainOfThought/ChainOfThoughtRoot.js +13 -4
  148. package/dist/primitives/chainOfThought/ChainOfThoughtRoot.js.map +1 -1
  149. package/dist/primitives/chainOfThought.js.map +1 -1
  150. package/dist/primitives/composer/ComposerAddAttachment.js +37 -24
  151. package/dist/primitives/composer/ComposerAddAttachment.js.map +1 -1
  152. package/dist/primitives/composer/ComposerAttachmentDropzone.js +124 -49
  153. package/dist/primitives/composer/ComposerAttachmentDropzone.js.map +1 -1
  154. package/dist/primitives/composer/ComposerCancel.js.map +1 -1
  155. package/dist/primitives/composer/ComposerDictate.js.map +1 -1
  156. package/dist/primitives/composer/ComposerDictationTranscript.js +32 -7
  157. package/dist/primitives/composer/ComposerDictationTranscript.js.map +1 -1
  158. package/dist/primitives/composer/ComposerInput.js +29 -29
  159. package/dist/primitives/composer/ComposerInput.js.map +1 -1
  160. package/dist/primitives/composer/ComposerInputPluginContext.js +71 -25
  161. package/dist/primitives/composer/ComposerInputPluginContext.js.map +1 -1
  162. package/dist/primitives/composer/ComposerQuote.js +92 -23
  163. package/dist/primitives/composer/ComposerQuote.js.map +1 -1
  164. package/dist/primitives/composer/ComposerRoot.js +45 -11
  165. package/dist/primitives/composer/ComposerRoot.js.map +1 -1
  166. package/dist/primitives/composer/ComposerSend.js +9 -2
  167. package/dist/primitives/composer/ComposerSend.js.map +1 -1
  168. package/dist/primitives/composer/ComposerStopDictation.js +15 -5
  169. package/dist/primitives/composer/ComposerStopDictation.js.map +1 -1
  170. package/dist/primitives/composer/trigger/TriggerPopover.d.ts.map +1 -1
  171. package/dist/primitives/composer/trigger/TriggerPopover.js +215 -75
  172. package/dist/primitives/composer/trigger/TriggerPopover.js.map +1 -1
  173. package/dist/primitives/composer/trigger/TriggerPopoverAction.js.map +1 -1
  174. package/dist/primitives/composer/trigger/TriggerPopoverBack.js +35 -7
  175. package/dist/primitives/composer/trigger/TriggerPopoverBack.js.map +1 -1
  176. package/dist/primitives/composer/trigger/TriggerPopoverCategories.js +134 -28
  177. package/dist/primitives/composer/trigger/TriggerPopoverCategories.js.map +1 -1
  178. package/dist/primitives/composer/trigger/TriggerPopoverDirective.js.map +1 -1
  179. package/dist/primitives/composer/trigger/TriggerPopoverItems.js +132 -28
  180. package/dist/primitives/composer/trigger/TriggerPopoverItems.js.map +1 -1
  181. package/dist/primitives/composer/trigger/TriggerPopoverResource.d.ts +2 -10
  182. package/dist/primitives/composer/trigger/TriggerPopoverResource.d.ts.map +1 -1
  183. package/dist/primitives/composer/trigger/TriggerPopoverResource.js +126 -53
  184. package/dist/primitives/composer/trigger/TriggerPopoverResource.js.map +1 -1
  185. package/dist/primitives/composer/trigger/TriggerPopoverRootContext.js +181 -78
  186. package/dist/primitives/composer/trigger/TriggerPopoverRootContext.js.map +1 -1
  187. package/dist/primitives/composer/trigger/detectTrigger.js.map +1 -1
  188. package/dist/primitives/composer/trigger/index.js.map +1 -1
  189. package/dist/primitives/composer/trigger/triggerDetectionResource.d.ts +2 -6
  190. package/dist/primitives/composer/trigger/triggerDetectionResource.d.ts.map +1 -1
  191. package/dist/primitives/composer/trigger/triggerDetectionResource.js +30 -15
  192. package/dist/primitives/composer/trigger/triggerDetectionResource.js.map +1 -1
  193. package/dist/primitives/composer/trigger/triggerKeyboardResource.d.ts +2 -17
  194. package/dist/primitives/composer/trigger/triggerKeyboardResource.d.ts.map +1 -1
  195. package/dist/primitives/composer/trigger/triggerKeyboardResource.js +117 -59
  196. package/dist/primitives/composer/trigger/triggerKeyboardResource.js.map +1 -1
  197. package/dist/primitives/composer/trigger/triggerNavigationResource.d.ts +2 -10
  198. package/dist/primitives/composer/trigger/triggerNavigationResource.d.ts.map +1 -1
  199. package/dist/primitives/composer/trigger/triggerNavigationResource.js +204 -71
  200. package/dist/primitives/composer/trigger/triggerNavigationResource.js.map +1 -1
  201. package/dist/primitives/composer/trigger/triggerSelectionResource.d.ts +2 -10
  202. package/dist/primitives/composer/trigger/triggerSelectionResource.d.ts.map +1 -1
  203. package/dist/primitives/composer/trigger/triggerSelectionResource.js +51 -14
  204. package/dist/primitives/composer/trigger/triggerSelectionResource.js.map +1 -1
  205. package/dist/primitives/composer.js.map +1 -1
  206. package/dist/primitives/dropdownMenuRenderPrimitives.js.map +1 -1
  207. package/dist/primitives/error/ErrorMessage.js +28 -6
  208. package/dist/primitives/error/ErrorMessage.js.map +1 -1
  209. package/dist/primitives/error/ErrorRoot.js +14 -5
  210. package/dist/primitives/error/ErrorRoot.js.map +1 -1
  211. package/dist/primitives/error.js.map +1 -1
  212. package/dist/primitives/message/MessageError.js +2 -1
  213. package/dist/primitives/message/MessageError.js.map +1 -1
  214. package/dist/primitives/message/MessageIf.js +50 -20
  215. package/dist/primitives/message/MessageIf.js.map +1 -1
  216. package/dist/primitives/message/MessageParts.js +41 -7
  217. package/dist/primitives/message/MessageParts.js.map +1 -1
  218. package/dist/primitives/message/MessagePartsGrouped.js +399 -94
  219. package/dist/primitives/message/MessagePartsGrouped.js.map +1 -1
  220. package/dist/primitives/message/MessageRoot.js +197 -65
  221. package/dist/primitives/message/MessageRoot.js.map +1 -1
  222. package/dist/primitives/message.js.map +1 -1
  223. package/dist/primitives/messagePart/MessagePartImage.js +15 -5
  224. package/dist/primitives/messagePart/MessagePartImage.js.map +1 -1
  225. package/dist/primitives/messagePart/MessagePartText.d.ts +5 -2
  226. package/dist/primitives/messagePart/MessagePartText.d.ts.map +1 -1
  227. package/dist/primitives/messagePart/MessagePartText.js +35 -7
  228. package/dist/primitives/messagePart/MessagePartText.js.map +1 -1
  229. package/dist/primitives/messagePart/useMessagePartData.js +5 -4
  230. package/dist/primitives/messagePart/useMessagePartData.js.map +1 -1
  231. package/dist/primitives/messagePart/useMessagePartFile.js +5 -4
  232. package/dist/primitives/messagePart/useMessagePartFile.js.map +1 -1
  233. package/dist/primitives/messagePart/useMessagePartImage.js +5 -4
  234. package/dist/primitives/messagePart/useMessagePartImage.js.map +1 -1
  235. package/dist/primitives/messagePart/useMessagePartReasoning.js +5 -4
  236. package/dist/primitives/messagePart/useMessagePartReasoning.js.map +1 -1
  237. package/dist/primitives/messagePart/useMessagePartSource.js +5 -4
  238. package/dist/primitives/messagePart/useMessagePartSource.js.map +1 -1
  239. package/dist/primitives/messagePart/useMessagePartText.js +5 -4
  240. package/dist/primitives/messagePart/useMessagePartText.js.map +1 -1
  241. package/dist/primitives/messagePart.js.map +1 -1
  242. package/dist/primitives/queueItem/QueueItemRemove.js +11 -4
  243. package/dist/primitives/queueItem/QueueItemRemove.js.map +1 -1
  244. package/dist/primitives/queueItem/QueueItemSteer.js +11 -4
  245. package/dist/primitives/queueItem/QueueItemSteer.js.map +1 -1
  246. package/dist/primitives/queueItem/QueueItemText.js +20 -6
  247. package/dist/primitives/queueItem/QueueItemText.js.map +1 -1
  248. package/dist/primitives/queueItem.js.map +1 -1
  249. package/dist/primitives/reasoning/useScrollLock.js +61 -34
  250. package/dist/primitives/reasoning/useScrollLock.js.map +1 -1
  251. package/dist/primitives/selectionToolbar/SelectionToolbarQuote.js +56 -16
  252. package/dist/primitives/selectionToolbar/SelectionToolbarQuote.js.map +1 -1
  253. package/dist/primitives/selectionToolbar/SelectionToolbarRoot.js +120 -59
  254. package/dist/primitives/selectionToolbar/SelectionToolbarRoot.js.map +1 -1
  255. package/dist/primitives/selectionToolbar.js.map +1 -1
  256. package/dist/primitives/suggestion/SuggestionDescription.js +20 -6
  257. package/dist/primitives/suggestion/SuggestionDescription.js.map +1 -1
  258. package/dist/primitives/suggestion/SuggestionTitle.js +20 -6
  259. package/dist/primitives/suggestion/SuggestionTitle.js.map +1 -1
  260. package/dist/primitives/suggestion/SuggestionTrigger.js +39 -26
  261. package/dist/primitives/suggestion/SuggestionTrigger.js.map +1 -1
  262. package/dist/primitives/suggestion.js.map +1 -1
  263. package/dist/primitives/thread/ThreadEmpty.js +6 -2
  264. package/dist/primitives/thread/ThreadEmpty.js.map +1 -1
  265. package/dist/primitives/thread/ThreadIf.js +32 -10
  266. package/dist/primitives/thread/ThreadIf.js.map +1 -1
  267. package/dist/primitives/thread/ThreadRoot.js +13 -4
  268. package/dist/primitives/thread/ThreadRoot.js.map +1 -1
  269. package/dist/primitives/thread/ThreadScrollToBottom.js +24 -6
  270. package/dist/primitives/thread/ThreadScrollToBottom.js.map +1 -1
  271. package/dist/primitives/thread/ThreadSuggestion.js +18 -6
  272. package/dist/primitives/thread/ThreadSuggestion.js.map +1 -1
  273. package/dist/primitives/thread/ThreadViewport.js +185 -47
  274. package/dist/primitives/thread/ThreadViewport.js.map +1 -1
  275. package/dist/primitives/thread/ThreadViewportFooter.js +22 -9
  276. package/dist/primitives/thread/ThreadViewportFooter.js.map +1 -1
  277. package/dist/primitives/thread/topAnchor/computeTopAnchorSlack.js.map +1 -1
  278. package/dist/primitives/thread/topAnchor/createReserveObservers.js.map +1 -1
  279. package/dist/primitives/thread/topAnchor/mountTopAnchorReserve.js.map +1 -1
  280. package/dist/primitives/thread/topAnchor/topAnchorTurn.js.map +1 -1
  281. package/dist/primitives/thread/topAnchor/topAnchorUtils.js.map +1 -1
  282. package/dist/primitives/thread/topAnchor/useTopAnchorReserve.js +19 -4
  283. package/dist/primitives/thread/topAnchor/useTopAnchorReserve.js.map +1 -1
  284. package/dist/primitives/thread/useThreadViewportAutoScroll.d.ts.map +1 -1
  285. package/dist/primitives/thread/useThreadViewportAutoScroll.js +21 -16
  286. package/dist/primitives/thread/useThreadViewportAutoScroll.js.map +1 -1
  287. package/dist/primitives/thread.js.map +1 -1
  288. package/dist/primitives/threadList/ThreadListLoadMore.js.map +1 -1
  289. package/dist/primitives/threadList/ThreadListNew.js +53 -11
  290. package/dist/primitives/threadList/ThreadListNew.js.map +1 -1
  291. package/dist/primitives/threadList/ThreadListRoot.js +13 -4
  292. package/dist/primitives/threadList/ThreadListRoot.js.map +1 -1
  293. package/dist/primitives/threadList.js.map +1 -1
  294. package/dist/primitives/threadListItem/ThreadListItemArchive.js.map +1 -1
  295. package/dist/primitives/threadListItem/ThreadListItemDelete.js.map +1 -1
  296. package/dist/primitives/threadListItem/ThreadListItemRoot.js +26 -7
  297. package/dist/primitives/threadListItem/ThreadListItemRoot.js.map +1 -1
  298. package/dist/primitives/threadListItem/ThreadListItemTrigger.js.map +1 -1
  299. package/dist/primitives/threadListItem/ThreadListItemUnarchive.js.map +1 -1
  300. package/dist/primitives/threadListItem.js.map +1 -1
  301. package/dist/primitives/threadListItemMore/ThreadListItemMoreContent.js +44 -7
  302. package/dist/primitives/threadListItemMore/ThreadListItemMoreContent.js.map +1 -1
  303. package/dist/primitives/threadListItemMore/ThreadListItemMoreItem.js +28 -6
  304. package/dist/primitives/threadListItemMore/ThreadListItemMoreItem.js.map +1 -1
  305. package/dist/primitives/threadListItemMore/ThreadListItemMoreRoot.js +25 -5
  306. package/dist/primitives/threadListItemMore/ThreadListItemMoreRoot.js.map +1 -1
  307. package/dist/primitives/threadListItemMore/ThreadListItemMoreSeparator.js +28 -6
  308. package/dist/primitives/threadListItemMore/ThreadListItemMoreSeparator.js.map +1 -1
  309. package/dist/primitives/threadListItemMore/ThreadListItemMoreTrigger.js +28 -6
  310. package/dist/primitives/threadListItemMore/ThreadListItemMoreTrigger.js.map +1 -1
  311. package/dist/primitives/threadListItemMore/scope.js.map +1 -1
  312. package/dist/primitives/threadListItemMore.js.map +1 -1
  313. package/dist/sandbox-host/SandboxHost.js.map +1 -1
  314. package/dist/tests/remote-thread-list-test-helpers.js.map +1 -1
  315. package/dist/tests/setup.js.map +1 -1
  316. package/dist/unstable/useComposerInputHistory.d.ts +30 -0
  317. package/dist/unstable/useComposerInputHistory.d.ts.map +1 -0
  318. package/dist/unstable/useComposerInputHistory.js +117 -0
  319. package/dist/unstable/useComposerInputHistory.js.map +1 -0
  320. package/dist/unstable/useMentionAdapter.js.map +1 -1
  321. package/dist/unstable/useMessageStallDetection.d.ts +29 -0
  322. package/dist/unstable/useMessageStallDetection.d.ts.map +1 -0
  323. package/dist/unstable/useMessageStallDetection.js +69 -0
  324. package/dist/unstable/useMessageStallDetection.js.map +1 -0
  325. package/dist/unstable/useSlashCommandAdapter.js.map +1 -1
  326. package/dist/utils/Primitive.js +57 -12
  327. package/dist/utils/Primitive.js.map +1 -1
  328. package/dist/utils/createActionButton.js +23 -7
  329. package/dist/utils/createActionButton.js.map +1 -1
  330. package/dist/utils/getSelectionMessageId.js.map +1 -1
  331. package/dist/utils/hooks/useManagedRef.js +16 -8
  332. package/dist/utils/hooks/useManagedRef.js.map +1 -1
  333. package/dist/utils/hooks/useMediaQuery.js +25 -10
  334. package/dist/utils/hooks/useMediaQuery.js.map +1 -1
  335. package/dist/utils/hooks/useOnResizeContent.js +29 -19
  336. package/dist/utils/hooks/useOnResizeContent.js.map +1 -1
  337. package/dist/utils/hooks/useOnScrollToBottom.js +20 -4
  338. package/dist/utils/hooks/useOnScrollToBottom.js.map +1 -1
  339. package/dist/utils/hooks/useSizeHandle.js +23 -15
  340. package/dist/utils/hooks/useSizeHandle.js.map +1 -1
  341. package/dist/utils/json/is-json-equal.js.map +1 -1
  342. package/dist/utils/json/is-json.js.map +1 -1
  343. package/dist/utils/smooth/SmoothContext.js +41 -11
  344. package/dist/utils/smooth/SmoothContext.js.map +1 -1
  345. package/dist/utils/smooth/useSmooth.d.ts +40 -2
  346. package/dist/utils/smooth/useSmooth.d.ts.map +1 -1
  347. package/dist/utils/smooth/useSmooth.js +52 -13
  348. package/dist/utils/smooth/useSmooth.js.map +1 -1
  349. package/dist/utils/useToolArgsFieldStatus.d.ts +2 -2
  350. package/dist/utils/useToolArgsFieldStatus.d.ts.map +1 -1
  351. package/dist/utils/useToolArgsFieldStatus.js +13 -5
  352. package/dist/utils/useToolArgsFieldStatus.js.map +1 -1
  353. package/package.json +6 -6
  354. package/src/client/ExternalThread.ts +146 -74
  355. package/src/client/InMemoryThreadList.ts +23 -21
  356. package/src/client/SingleThreadList.ts +29 -27
  357. package/src/hooks/useToolCallElapsed.ts +52 -0
  358. package/src/index.ts +19 -0
  359. package/src/mcp-apps/McpAppRenderer.tsx +5 -3
  360. package/src/mcp-apps/McpAppsRemoteHost.ts +5 -3
  361. package/src/primitives/composer/ComposerInput.test.tsx +1 -1
  362. package/src/primitives/composer/ComposerInput.tsx +3 -3
  363. package/src/primitives/composer/trigger/TriggerPopover.tsx +4 -5
  364. package/src/primitives/composer/trigger/TriggerPopoverResource.ts +5 -3
  365. package/src/primitives/composer/trigger/triggerDetectionResource.ts +21 -21
  366. package/src/primitives/composer/trigger/triggerKeyboardResource.test.ts +5 -4
  367. package/src/primitives/composer/trigger/triggerKeyboardResource.ts +99 -101
  368. package/src/primitives/composer/trigger/triggerNavigationResource.ts +92 -98
  369. package/src/primitives/composer/trigger/triggerSelectionResource.ts +76 -76
  370. package/src/primitives/messagePart/MessagePartText.tsx +3 -2
  371. package/src/primitives/reasoning/useScrollLock.ts +25 -2
  372. package/src/primitives/thread/useThreadViewportAutoScroll.ts +8 -0
  373. package/src/tests/external-thread-branches.test.tsx +160 -0
  374. package/src/tests/shouldContinue.test.ts +33 -0
  375. package/src/tests/toolCallTiming.test.tsx +221 -0
  376. package/src/unstable/useComposerInputHistory.test.tsx +201 -0
  377. package/src/unstable/useComposerInputHistory.ts +160 -0
  378. package/src/unstable/useMessageStallDetection.ts +91 -0
  379. package/src/utils/smooth/useSmooth.test.tsx +95 -0
  380. package/src/utils/smooth/useSmooth.ts +82 -10
@@ -1 +1 @@
1
- {"version":3,"file":"useOnScrollToBottom.js","names":[],"sources":["../../../src/utils/hooks/useOnScrollToBottom.ts"],"sourcesContent":["\"use client\";\n\nimport { useCallbackRef } from \"@radix-ui/react-use-callback-ref\";\nimport { useEffect } from \"react\";\nimport { useThreadViewport } from \"../../context/react/ThreadViewportContext\";\n\nexport const useOnScrollToBottom = (\n callback: (config: { behavior: ScrollBehavior }) => void,\n) => {\n const callbackRef = useCallbackRef(callback);\n const onScrollToBottom = useThreadViewport((vp) => vp.onScrollToBottom);\n\n useEffect(() => {\n return onScrollToBottom(callbackRef);\n }, [onScrollToBottom, callbackRef]);\n};\n"],"mappings":";;;;;AAMA,MAAa,uBACX,aACG;CACH,MAAM,cAAc,eAAe,QAAQ;CAC3C,MAAM,mBAAmB,mBAAmB,OAAO,GAAG,gBAAgB;CAEtE,gBAAgB;EACd,OAAO,iBAAiB,WAAW;CACrC,GAAG,CAAC,kBAAkB,WAAW,CAAC;AACpC"}
1
+ {"version":3,"file":"useOnScrollToBottom.js","names":["c","_c","useCallbackRef","useEffect","useThreadViewport","useOnScrollToBottom","callback","$","callbackRef","onScrollToBottom","_temp","t0","t1","vp"],"sources":["../../../src/utils/hooks/useOnScrollToBottom.ts"],"sourcesContent":["\"use client\";\n\nimport { useCallbackRef } from \"@radix-ui/react-use-callback-ref\";\nimport { useEffect } from \"react\";\nimport { useThreadViewport } from \"../../context/react/ThreadViewportContext\";\n\nexport const useOnScrollToBottom = (\n callback: (config: { behavior: ScrollBehavior }) => void,\n) => {\n const callbackRef = useCallbackRef(callback);\n const onScrollToBottom = useThreadViewport((vp) => vp.onScrollToBottom);\n\n useEffect(() => {\n return onScrollToBottom(callbackRef);\n }, [onScrollToBottom, callbackRef]);\n};\n"],"mappings":";;;;;;AAMA,MAAaK,uBAAsBC,aAAA;CAAA,MAAAC,IAAAN,EAAA,CAAA;CAGjC,MAAAO,cAAoBN,eAAeI,QAAQ;CAC3C,MAAAG,mBAAyBL,kBAAkBM,KAA2B;CAAE,IAAAC;CAAA,IAAAC;CAAA,IAAAL,EAAA,OAAAC,eAAAD,EAAA,OAAAE,kBAAA;EAE9DE,WACDF,iBAAiBD,WAAW;EAClCI,KAAA,CAACH,kBAAkBD,WAAW;EAACD,EAAA,KAAAC;EAAAD,EAAA,KAAAE;EAAAF,EAAA,KAAAI;EAAAJ,EAAA,KAAAK;CAAA,OAAA;EAAAD,KAAAJ,EAAA;EAAAK,KAAAL,EAAA;CAAA;CAFlCJ,UAAUQ,IAEPC,EAA+B;AAAC;AARF,SAAAF,MAAAG,IAAA;CAAA,OAIkBA,GAAEJ;AAAiB"}
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import { useManagedRef } from "./useManagedRef.js";
3
- import { useCallback } from "@assistant-ui/tap/react-shim";
3
+ import { c } from "@assistant-ui/tap/react-shim/compiler-runtime";
4
4
  //#region src/utils/hooks/useSizeHandle.ts
5
5
  /**
6
6
  * Hook that creates a ref for tracking element size via a SizeHandle.
@@ -11,21 +11,29 @@ import { useCallback } from "@assistant-ui/tap/react-shim";
11
11
  * @returns A ref callback to attach to the element
12
12
  */
13
13
  const useSizeHandle = (register, getHeight) => {
14
- return useManagedRef(useCallback((el) => {
15
- if (!register) return;
16
- const sizeHandle = register();
17
- const updateHeight = () => {
18
- const height = getHeight ? getHeight(el) : el.offsetHeight;
19
- sizeHandle.setHeight(height);
14
+ const $ = c(3);
15
+ let t0;
16
+ if ($[0] !== getHeight || $[1] !== register) {
17
+ t0 = (el) => {
18
+ if (!register) return;
19
+ const sizeHandle = register();
20
+ const updateHeight = () => {
21
+ const height = getHeight ? getHeight(el) : el.offsetHeight;
22
+ sizeHandle.setHeight(height);
23
+ };
24
+ const ro = new ResizeObserver(updateHeight);
25
+ ro.observe(el);
26
+ updateHeight();
27
+ return () => {
28
+ ro.disconnect();
29
+ sizeHandle.unregister();
30
+ };
20
31
  };
21
- const ro = new ResizeObserver(updateHeight);
22
- ro.observe(el);
23
- updateHeight();
24
- return () => {
25
- ro.disconnect();
26
- sizeHandle.unregister();
27
- };
28
- }, [register, getHeight]));
32
+ $[0] = getHeight;
33
+ $[1] = register;
34
+ $[2] = t0;
35
+ } else t0 = $[2];
36
+ return useManagedRef(t0);
29
37
  };
30
38
  //#endregion
31
39
  export { useSizeHandle };
@@ -1 +1 @@
1
- {"version":3,"file":"useSizeHandle.js","names":[],"sources":["../../../src/utils/hooks/useSizeHandle.ts"],"sourcesContent":["\"use client\";\n\nimport { useCallback } from \"react\";\nimport { useManagedRef } from \"./useManagedRef\";\nimport type { SizeHandle } from \"../../context/stores/ThreadViewport\";\n\n/**\n * Hook that creates a ref for tracking element size via a SizeHandle.\n * Automatically sets up ResizeObserver and reports height changes.\n *\n * @param register - Function that returns a SizeHandle (e.g., registerContentInset)\n * @param getHeight - Optional function to compute height (defaults to el.offsetHeight)\n * @returns A ref callback to attach to the element\n */\nexport const useSizeHandle = (\n register: (() => SizeHandle) | null | undefined,\n getHeight?: (el: HTMLElement) => number,\n) => {\n const callbackRef = useCallback(\n (el: HTMLElement) => {\n if (!register) return;\n\n const sizeHandle = register();\n\n const updateHeight = () => {\n const height = getHeight ? getHeight(el) : el.offsetHeight;\n sizeHandle.setHeight(height);\n };\n\n const ro = new ResizeObserver(updateHeight);\n ro.observe(el);\n updateHeight();\n\n return () => {\n ro.disconnect();\n sizeHandle.unregister();\n };\n },\n [register, getHeight],\n );\n\n return useManagedRef(callbackRef);\n};\n"],"mappings":";;;;;;;;;;;;AAcA,MAAa,iBACX,UACA,cACG;CAwBH,OAAO,cAvBa,aACjB,OAAoB;EACnB,IAAI,CAAC,UAAU;EAEf,MAAM,aAAa,SAAS;EAE5B,MAAM,qBAAqB;GACzB,MAAM,SAAS,YAAY,UAAU,EAAE,IAAI,GAAG;GAC9C,WAAW,UAAU,MAAM;EAC7B;EAEA,MAAM,KAAK,IAAI,eAAe,YAAY;EAC1C,GAAG,QAAQ,EAAE;EACb,aAAa;EAEb,aAAa;GACX,GAAG,WAAW;GACd,WAAW,WAAW;EACxB;CACF,GACA,CAAC,UAAU,SAAS,CAGS,CAAC;AAClC"}
1
+ {"version":3,"file":"useSizeHandle.js","names":["c","_c","useCallback","useManagedRef","SizeHandle","useSizeHandle","register","getHeight","$","t0","el","sizeHandle","updateHeight","height","offsetHeight","setHeight","ro","ResizeObserver","observe","disconnect","unregister","callbackRef"],"sources":["../../../src/utils/hooks/useSizeHandle.ts"],"sourcesContent":["\"use client\";\n\nimport { useCallback } from \"react\";\nimport { useManagedRef } from \"./useManagedRef\";\nimport type { SizeHandle } from \"../../context/stores/ThreadViewport\";\n\n/**\n * Hook that creates a ref for tracking element size via a SizeHandle.\n * Automatically sets up ResizeObserver and reports height changes.\n *\n * @param register - Function that returns a SizeHandle (e.g., registerContentInset)\n * @param getHeight - Optional function to compute height (defaults to el.offsetHeight)\n * @returns A ref callback to attach to the element\n */\nexport const useSizeHandle = (\n register: (() => SizeHandle) | null | undefined,\n getHeight?: (el: HTMLElement) => number,\n) => {\n const callbackRef = useCallback(\n (el: HTMLElement) => {\n if (!register) return;\n\n const sizeHandle = register();\n\n const updateHeight = () => {\n const height = getHeight ? getHeight(el) : el.offsetHeight;\n sizeHandle.setHeight(height);\n };\n\n const ro = new ResizeObserver(updateHeight);\n ro.observe(el);\n updateHeight();\n\n return () => {\n ro.disconnect();\n sizeHandle.unregister();\n };\n },\n [register, getHeight],\n );\n\n return useManagedRef(callbackRef);\n};\n"],"mappings":";;;;;;;;;;;;AAcA,MAAaK,iBAAgBC,UAAAC,cAAA;CAAA,MAAAC,IAAAP,EAAA,CAAA;CAAA,IAAAQ;CAAA,IAAAD,EAAA,OAAAD,aAAAC,EAAA,OAAAF,UAAA;EAKzBG,MAAAC,OAAA;GACE,IAAI,CAACJ,UAAQ;GAEb,MAAAK,aAAmBL,SAAS;GAE5B,MAAAM,qBAAqB;IACnB,MAAAC,SAAeN,YAAYA,UAAUG,EAAoB,IAAdA,GAAEI;IAC7CH,WAAUI,UAAWF,MAAM;GAAC;GAG9B,MAAAG,KAAW,IAAIC,eAAeL,YAAY;GAC1CI,GAAEE,QAASR,EAAE;GACbE,aAAa;GAAC,aAEP;IACLI,GAAEG,WAAY;IACdR,WAAUS,WAAY;GAAC;EACxB;EACFZ,EAAA,KAAAD;EAAAC,EAAA,KAAAF;EAAAE,EAAA,KAAAC;CAAA,OAAAA,KAAAD,EAAA;CAED,OAEKL,cAAckB,EAAW;AAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"is-json-equal.js","names":[],"sources":["../../../src/utils/json/is-json-equal.ts"],"sourcesContent":["import type { ReadonlyJSONValue } from \"assistant-stream/utils\";\nimport { isJSONValue, isRecord } from \"./is-json\";\n\nconst MAX_JSON_DEPTH = 100;\n\nconst isJSONValueEqualAtDepth = (\n a: ReadonlyJSONValue,\n b: ReadonlyJSONValue,\n currentDepth: number,\n): boolean => {\n if (a === b) return true;\n if (currentDepth > MAX_JSON_DEPTH) return false;\n\n if (a == null || b == null) return false;\n\n if (Array.isArray(a)) {\n if (!Array.isArray(b) || a.length !== b.length) return false;\n return a.every((item, index) =>\n isJSONValueEqualAtDepth(\n item,\n b[index] as ReadonlyJSONValue,\n currentDepth + 1,\n ),\n );\n }\n\n if (Array.isArray(b)) return false;\n if (!isRecord(a) || !isRecord(b)) return false;\n\n const aKeys = Object.keys(a);\n const bKeys = Object.keys(b);\n if (aKeys.length !== bKeys.length) return false;\n\n return aKeys.every(\n (key) =>\n Object.hasOwn(b, key) &&\n isJSONValueEqualAtDepth(\n a[key] as ReadonlyJSONValue,\n b[key] as ReadonlyJSONValue,\n currentDepth + 1,\n ),\n );\n};\n\nexport const isJSONValueEqual = (a: unknown, b: unknown): boolean => {\n if (!isJSONValue(a) || !isJSONValue(b)) return false;\n return isJSONValueEqualAtDepth(a, b, 0);\n};\n"],"mappings":";;AAGA,MAAM,iBAAiB;AAEvB,MAAM,2BACJ,GACA,GACA,iBACY;CACZ,IAAI,MAAM,GAAG,OAAO;CACpB,IAAI,eAAe,gBAAgB,OAAO;CAE1C,IAAI,KAAK,QAAQ,KAAK,MAAM,OAAO;CAEnC,IAAI,MAAM,QAAQ,CAAC,GAAG;EACpB,IAAI,CAAC,MAAM,QAAQ,CAAC,KAAK,EAAE,WAAW,EAAE,QAAQ,OAAO;EACvD,OAAO,EAAE,OAAO,MAAM,UACpB,wBACE,MACA,EAAE,QACF,eAAe,CACjB,CACF;CACF;CAEA,IAAI,MAAM,QAAQ,CAAC,GAAG,OAAO;CAC7B,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,OAAO;CAEzC,MAAM,QAAQ,OAAO,KAAK,CAAC;CAC3B,MAAM,QAAQ,OAAO,KAAK,CAAC;CAC3B,IAAI,MAAM,WAAW,MAAM,QAAQ,OAAO;CAE1C,OAAO,MAAM,OACV,QACC,OAAO,OAAO,GAAG,GAAG,KACpB,wBACE,EAAE,MACF,EAAE,MACF,eAAe,CACjB,CACJ;AACF;AAEA,MAAa,oBAAoB,GAAY,MAAwB;CACnE,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,OAAO;CAC/C,OAAO,wBAAwB,GAAG,GAAG,CAAC;AACxC"}
1
+ {"version":3,"file":"is-json-equal.js","names":["ReadonlyJSONValue","isJSONValue","isRecord","MAX_JSON_DEPTH","isJSONValueEqualAtDepth","a","b","currentDepth","Array","isArray","length","every","item","index","aKeys","Object","keys","bKeys","key","hasOwn","isJSONValueEqual"],"sources":["../../../src/utils/json/is-json-equal.ts"],"sourcesContent":["import type { ReadonlyJSONValue } from \"assistant-stream/utils\";\nimport { isJSONValue, isRecord } from \"./is-json\";\n\nconst MAX_JSON_DEPTH = 100;\n\nconst isJSONValueEqualAtDepth = (\n a: ReadonlyJSONValue,\n b: ReadonlyJSONValue,\n currentDepth: number,\n): boolean => {\n if (a === b) return true;\n if (currentDepth > MAX_JSON_DEPTH) return false;\n\n if (a == null || b == null) return false;\n\n if (Array.isArray(a)) {\n if (!Array.isArray(b) || a.length !== b.length) return false;\n return a.every((item, index) =>\n isJSONValueEqualAtDepth(\n item,\n b[index] as ReadonlyJSONValue,\n currentDepth + 1,\n ),\n );\n }\n\n if (Array.isArray(b)) return false;\n if (!isRecord(a) || !isRecord(b)) return false;\n\n const aKeys = Object.keys(a);\n const bKeys = Object.keys(b);\n if (aKeys.length !== bKeys.length) return false;\n\n return aKeys.every(\n (key) =>\n Object.hasOwn(b, key) &&\n isJSONValueEqualAtDepth(\n a[key] as ReadonlyJSONValue,\n b[key] as ReadonlyJSONValue,\n currentDepth + 1,\n ),\n );\n};\n\nexport const isJSONValueEqual = (a: unknown, b: unknown): boolean => {\n if (!isJSONValue(a) || !isJSONValue(b)) return false;\n return isJSONValueEqualAtDepth(a, b, 0);\n};\n"],"mappings":";;AAGA,MAAMG,iBAAiB;AAEvB,MAAMC,2BACJC,GACAC,GACAC,iBACY;CACZ,IAAIF,MAAMC,GAAG,OAAO;CACpB,IAAIC,eAAeJ,gBAAgB,OAAO;CAE1C,IAAIE,KAAK,QAAQC,KAAK,MAAM,OAAO;CAEnC,IAAIE,MAAMC,QAAQJ,CAAC,GAAG;EACpB,IAAI,CAACG,MAAMC,QAAQH,CAAC,KAAKD,EAAEK,WAAWJ,EAAEI,QAAQ,OAAO;EACvD,OAAOL,EAAEM,OAAOC,MAAMC,UACpBT,wBACEQ,MACAN,EAAEO,QACFN,eAAe,CACjB,CACF;CACF;CAEA,IAAIC,MAAMC,QAAQH,CAAC,GAAG,OAAO;CAC7B,IAAI,CAACJ,SAASG,CAAC,KAAK,CAACH,SAASI,CAAC,GAAG,OAAO;CAEzC,MAAMQ,QAAQC,OAAOC,KAAKX,CAAC;CAC3B,MAAMY,QAAQF,OAAOC,KAAKV,CAAC;CAC3B,IAAIQ,MAAMJ,WAAWO,MAAMP,QAAQ,OAAO;CAE1C,OAAOI,MAAMH,OACVO,QACCH,OAAOI,OAAOb,GAAGY,GAAG,KACpBd,wBACEC,EAAEa,MACFZ,EAAEY,MACFX,eAAe,CACjB,CACJ;AACF;AAEA,MAAaa,oBAAoBf,GAAYC,MAAwB;CACnE,IAAI,CAACL,YAAYI,CAAC,KAAK,CAACJ,YAAYK,CAAC,GAAG,OAAO;CAC/C,OAAOF,wBAAwBC,GAAGC,GAAG,CAAC;AACxC"}
@@ -1 +1 @@
1
- {"version":3,"file":"is-json.js","names":[],"sources":["../../../src/utils/json/is-json.ts"],"sourcesContent":["import type {\n ReadonlyJSONArray,\n ReadonlyJSONObject,\n ReadonlyJSONValue,\n} from \"assistant-stream/utils\";\n\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return value != null && typeof value === \"object\" && !Array.isArray(value);\n}\n\nexport function isJSONValue(\n value: unknown,\n currentDepth: number = 0,\n): value is ReadonlyJSONValue {\n // Protect against too deep recursion\n if (currentDepth > 100) {\n return false;\n }\n\n if (\n value === null ||\n typeof value === \"string\" ||\n typeof value === \"boolean\"\n ) {\n return true;\n }\n\n // Handle special number cases\n if (typeof value === \"number\") {\n return !Number.isNaN(value) && Number.isFinite(value);\n }\n\n if (Array.isArray(value)) {\n return value.every((item) => isJSONValue(item, currentDepth + 1));\n }\n\n if (isRecord(value)) {\n return Object.entries(value).every(\n ([key, val]) =>\n typeof key === \"string\" && isJSONValue(val, currentDepth + 1),\n );\n }\n\n return false;\n}\n\nexport function isJSONArray(value: unknown): value is ReadonlyJSONArray {\n return Array.isArray(value) && value.every(isJSONValue);\n}\n\nexport function isJSONObject(value: unknown): value is ReadonlyJSONObject {\n return (\n isRecord(value) &&\n Object.entries(value).every(\n ([key, val]) => typeof key === \"string\" && isJSONValue(val),\n )\n );\n}\n"],"mappings":";AAMA,SAAgB,SAAS,OAAkD;CACzE,OAAO,SAAS,QAAQ,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK;AAC3E;AAEA,SAAgB,YACd,OACA,eAAuB,GACK;CAE5B,IAAI,eAAe,KACjB,OAAO;CAGT,IACE,UAAU,QACV,OAAO,UAAU,YACjB,OAAO,UAAU,WAEjB,OAAO;CAIT,IAAI,OAAO,UAAU,UACnB,OAAO,CAAC,OAAO,MAAM,KAAK,KAAK,OAAO,SAAS,KAAK;CAGtD,IAAI,MAAM,QAAQ,KAAK,GACrB,OAAO,MAAM,OAAO,SAAS,YAAY,MAAM,eAAe,CAAC,CAAC;CAGlE,IAAI,SAAS,KAAK,GAChB,OAAO,OAAO,QAAQ,KAAK,CAAC,CAAC,OAC1B,CAAC,KAAK,SACL,OAAO,QAAQ,YAAY,YAAY,KAAK,eAAe,CAAC,CAChE;CAGF,OAAO;AACT;AAEA,SAAgB,YAAY,OAA4C;CACtE,OAAO,MAAM,QAAQ,KAAK,KAAK,MAAM,MAAM,WAAW;AACxD;AAEA,SAAgB,aAAa,OAA6C;CACxE,OACE,SAAS,KAAK,KACd,OAAO,QAAQ,KAAK,CAAC,CAAC,OACnB,CAAC,KAAK,SAAS,OAAO,QAAQ,YAAY,YAAY,GAAG,CAC5D;AAEJ"}
1
+ {"version":3,"file":"is-json.js","names":["ReadonlyJSONArray","ReadonlyJSONObject","ReadonlyJSONValue","isRecord","value","Record","Array","isArray","isJSONValue","currentDepth","Number","isNaN","isFinite","every","item","Object","entries","key","val","isJSONArray","isJSONObject"],"sources":["../../../src/utils/json/is-json.ts"],"sourcesContent":["import type {\n ReadonlyJSONArray,\n ReadonlyJSONObject,\n ReadonlyJSONValue,\n} from \"assistant-stream/utils\";\n\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return value != null && typeof value === \"object\" && !Array.isArray(value);\n}\n\nexport function isJSONValue(\n value: unknown,\n currentDepth: number = 0,\n): value is ReadonlyJSONValue {\n // Protect against too deep recursion\n if (currentDepth > 100) {\n return false;\n }\n\n if (\n value === null ||\n typeof value === \"string\" ||\n typeof value === \"boolean\"\n ) {\n return true;\n }\n\n // Handle special number cases\n if (typeof value === \"number\") {\n return !Number.isNaN(value) && Number.isFinite(value);\n }\n\n if (Array.isArray(value)) {\n return value.every((item) => isJSONValue(item, currentDepth + 1));\n }\n\n if (isRecord(value)) {\n return Object.entries(value).every(\n ([key, val]) =>\n typeof key === \"string\" && isJSONValue(val, currentDepth + 1),\n );\n }\n\n return false;\n}\n\nexport function isJSONArray(value: unknown): value is ReadonlyJSONArray {\n return Array.isArray(value) && value.every(isJSONValue);\n}\n\nexport function isJSONObject(value: unknown): value is ReadonlyJSONObject {\n return (\n isRecord(value) &&\n Object.entries(value).every(\n ([key, val]) => typeof key === \"string\" && isJSONValue(val),\n )\n );\n}\n"],"mappings":";AAMA,SAAgBG,SAASC,OAAkD;CACzE,OAAOA,SAAS,QAAQ,OAAOA,UAAU,YAAY,CAACE,MAAMC,QAAQH,KAAK;AAC3E;AAEA,SAAgBI,YACdJ,OACAK,eAAuB,GACK;CAE5B,IAAIA,eAAe,KACjB,OAAO;CAGT,IACEL,UAAU,QACV,OAAOA,UAAU,YACjB,OAAOA,UAAU,WAEjB,OAAO;CAIT,IAAI,OAAOA,UAAU,UACnB,OAAO,CAACM,OAAOC,MAAMP,KAAK,KAAKM,OAAOE,SAASR,KAAK;CAGtD,IAAIE,MAAMC,QAAQH,KAAK,GACrB,OAAOA,MAAMS,OAAOC,SAASN,YAAYM,MAAML,eAAe,CAAC,CAAC;CAGlE,IAAIN,SAASC,KAAK,GAChB,OAAOW,OAAOC,QAAQZ,KAAK,CAAC,CAACS,OAC1B,CAACI,KAAKC,SACL,OAAOD,QAAQ,YAAYT,YAAYU,KAAKT,eAAe,CAAC,CAChE;CAGF,OAAO;AACT;AAEA,SAAgBU,YAAYf,OAA4C;CACtE,OAAOE,MAAMC,QAAQH,KAAK,KAAKA,MAAMS,MAAML,WAAW;AACxD;AAEA,SAAgBY,aAAahB,OAA6C;CACxE,OACED,SAASC,KAAK,KACdW,OAAOC,QAAQZ,KAAK,CAAC,CAACS,OACnB,CAACI,KAAKC,SAAS,OAAOD,QAAQ,YAAYT,YAAYU,GAAG,CAC5D;AAEJ"}
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
  import { createContextStoreHook } from "../../context/react/utils/createContextStoreHook.js";
3
3
  import { useAui } from "@assistant-ui/store";
4
+ import { c } from "@assistant-ui/tap/react-shim/compiler-runtime";
4
5
  import { createContext, forwardRef, useContext, useState } from "@assistant-ui/tap/react-shim";
5
6
  import { create } from "zustand";
6
7
  import { jsx } from "react/jsx-runtime";
@@ -9,22 +10,51 @@ const SmoothContext = createContext(null);
9
10
  const makeSmoothContext = (initialState) => {
10
11
  return { useSmoothStatus: create(() => initialState) };
11
12
  };
12
- const SmoothContextProvider = ({ children }) => {
13
- const outer = useSmoothContext({ optional: true });
13
+ const SmoothContextProvider = (t0) => {
14
+ const $ = c(6);
15
+ const { children } = t0;
16
+ let t1;
17
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
18
+ t1 = { optional: true };
19
+ $[0] = t1;
20
+ } else t1 = $[0];
21
+ const outer = useSmoothContext(t1);
14
22
  const aui = useAui();
15
- const [context] = useState(() => makeSmoothContext(aui.part().getState().status));
23
+ let t2;
24
+ if ($[1] !== aui) {
25
+ t2 = () => makeSmoothContext(aui.part().getState().status);
26
+ $[1] = aui;
27
+ $[2] = t2;
28
+ } else t2 = $[2];
29
+ const [context] = useState(t2);
16
30
  if (outer) return children;
17
- return /* @__PURE__ */ jsx(SmoothContext.Provider, {
18
- value: context,
19
- children
20
- });
31
+ let t3;
32
+ if ($[3] !== children || $[4] !== context) {
33
+ t3 = /* @__PURE__ */ jsx(SmoothContext.Provider, {
34
+ value: context,
35
+ children
36
+ });
37
+ $[3] = children;
38
+ $[4] = context;
39
+ $[5] = t3;
40
+ } else t3 = $[5];
41
+ return t3;
21
42
  };
22
43
  const withSmoothContextProvider = (Component) => {
23
44
  const Wrapped = forwardRef((props, ref) => {
24
- return /* @__PURE__ */ jsx(SmoothContextProvider, { children: /* @__PURE__ */ jsx(Component, {
25
- ...props,
26
- ref
27
- }) });
45
+ const $ = c(3);
46
+ const t0 = props;
47
+ let t1;
48
+ if ($[0] !== ref || $[1] !== t0) {
49
+ t1 = /* @__PURE__ */ jsx(SmoothContextProvider, { children: /* @__PURE__ */ jsx(Component, {
50
+ ...t0,
51
+ ref
52
+ }) });
53
+ $[0] = ref;
54
+ $[1] = t0;
55
+ $[2] = t1;
56
+ } else t1 = $[2];
57
+ return t1;
28
58
  });
29
59
  Wrapped.displayName = Component.displayName;
30
60
  return Wrapped;
@@ -1 +1 @@
1
- {"version":3,"file":"SmoothContext.js","names":[],"sources":["../../../src/utils/smooth/SmoothContext.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n type ComponentType,\n createContext,\n type FC,\n forwardRef,\n type PropsWithChildren,\n useContext,\n useState,\n} from \"react\";\nimport type { ReadonlyStore } from \"../../context/ReadonlyStore\";\nimport { create, type UseBoundStore } from \"zustand\";\nimport type {\n MessagePartStatus,\n ToolCallMessagePartStatus,\n} from \"@assistant-ui/core\";\nimport { useAui } from \"@assistant-ui/store\";\nimport { createContextStoreHook } from \"../../context/react/utils/createContextStoreHook\";\n\ntype SmoothContextValue = {\n useSmoothStatus: UseBoundStore<\n ReadonlyStore<MessagePartStatus | ToolCallMessagePartStatus>\n >;\n};\n\nconst SmoothContext = createContext<SmoothContextValue | null>(null);\n\nconst makeSmoothContext = (\n initialState: MessagePartStatus | ToolCallMessagePartStatus,\n) => {\n const useSmoothStatus = create(() => initialState);\n return { useSmoothStatus };\n};\n\nexport const SmoothContextProvider: FC<PropsWithChildren> = ({ children }) => {\n const outer = useSmoothContext({ optional: true });\n const aui = useAui();\n\n const [context] = useState(() =>\n makeSmoothContext(aui.part().getState().status),\n );\n\n // do not wrap if there is an outer SmoothContextProvider\n if (outer) return children;\n\n return (\n <SmoothContext.Provider value={context}>{children}</SmoothContext.Provider>\n );\n};\n\nexport const withSmoothContextProvider = <C extends ComponentType<any>>(\n Component: C,\n): C => {\n const Wrapped = forwardRef((props, ref) => {\n return (\n <SmoothContextProvider>\n <Component {...(props as any)} ref={ref} />\n </SmoothContextProvider>\n );\n });\n Wrapped.displayName = Component.displayName;\n return Wrapped as any;\n};\n\nfunction useSmoothContext(options?: {\n optional?: false | undefined;\n}): SmoothContextValue;\nfunction useSmoothContext(options?: {\n optional?: boolean | undefined;\n}): SmoothContextValue | null;\nfunction useSmoothContext(options?: { optional?: boolean | undefined }) {\n const context = useContext(SmoothContext);\n if (!options?.optional && !context)\n throw new Error(\n \"This component must be used within a SmoothContextProvider.\",\n );\n return context;\n}\n\nexport const { useSmoothStatus, useSmoothStatusStore } = createContextStoreHook(\n useSmoothContext,\n \"useSmoothStatus\",\n);\n"],"mappings":";;;;;;;AA0BA,MAAM,gBAAgB,cAAyC,IAAI;AAEnE,MAAM,qBACJ,iBACG;CAEH,OAAO,EAAE,iBADe,aAAa,YACd,EAAE;AAC3B;AAEA,MAAa,yBAAgD,EAAE,eAAe;CAC5E,MAAM,QAAQ,iBAAiB,EAAE,UAAU,KAAK,CAAC;CACjD,MAAM,MAAM,OAAO;CAEnB,MAAM,CAAC,WAAW,eAChB,kBAAkB,IAAI,KAAK,CAAC,CAAC,SAAS,CAAC,CAAC,MAAM,CAChD;CAGA,IAAI,OAAO,OAAO;CAElB,OACE,oBAAC,cAAc,UAAf;EAAwB,OAAO;EAAU;CAAiC,CAAA;AAE9E;AAEA,MAAa,6BACX,cACM;CACN,MAAM,UAAU,YAAY,OAAO,QAAQ;EACzC,OACE,oBAAC,uBAAD,EAAA,UACE,oBAAC,WAAD;GAAW,GAAK;GAAoB;EAAM,CAAA,EACrB,CAAA;CAE3B,CAAC;CACD,QAAQ,cAAc,UAAU;CAChC,OAAO;AACT;AAQA,SAAS,iBAAiB,SAA8C;CACtE,MAAM,UAAU,WAAW,aAAa;CACxC,IAAI,CAAC,SAAS,YAAY,CAAC,SACzB,MAAM,IAAI,MACR,6DACF;CACF,OAAO;AACT;AAEA,MAAa,EAAE,iBAAiB,yBAAyB,uBACvD,kBACA,iBACF"}
1
+ {"version":3,"file":"SmoothContext.js","names":["c","_c","ComponentType","createContext","FC","forwardRef","PropsWithChildren","useContext","useState","ReadonlyStore","create","UseBoundStore","MessagePartStatus","ToolCallMessagePartStatus","useAui","createContextStoreHook","SmoothContextValue","useSmoothStatus","SmoothContext","makeSmoothContext","initialState","SmoothContextProvider","t0","$","children","t1","Symbol","for","optional","outer","useSmoothContext","aui","t2","part","getState","status","context","t3","withSmoothContextProvider","Component","C","Wrapped","props","ref","displayName","options","Error","useSmoothStatusStore"],"sources":["../../../src/utils/smooth/SmoothContext.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n type ComponentType,\n createContext,\n type FC,\n forwardRef,\n type PropsWithChildren,\n useContext,\n useState,\n} from \"react\";\nimport type { ReadonlyStore } from \"../../context/ReadonlyStore\";\nimport { create, type UseBoundStore } from \"zustand\";\nimport type {\n MessagePartStatus,\n ToolCallMessagePartStatus,\n} from \"@assistant-ui/core\";\nimport { useAui } from \"@assistant-ui/store\";\nimport { createContextStoreHook } from \"../../context/react/utils/createContextStoreHook\";\n\ntype SmoothContextValue = {\n useSmoothStatus: UseBoundStore<\n ReadonlyStore<MessagePartStatus | ToolCallMessagePartStatus>\n >;\n};\n\nconst SmoothContext = createContext<SmoothContextValue | null>(null);\n\nconst makeSmoothContext = (\n initialState: MessagePartStatus | ToolCallMessagePartStatus,\n) => {\n const useSmoothStatus = create(() => initialState);\n return { useSmoothStatus };\n};\n\nexport const SmoothContextProvider: FC<PropsWithChildren> = ({ children }) => {\n const outer = useSmoothContext({ optional: true });\n const aui = useAui();\n\n const [context] = useState(() =>\n makeSmoothContext(aui.part().getState().status),\n );\n\n // do not wrap if there is an outer SmoothContextProvider\n if (outer) return children;\n\n return (\n <SmoothContext.Provider value={context}>{children}</SmoothContext.Provider>\n );\n};\n\nexport const withSmoothContextProvider = <C extends ComponentType<any>>(\n Component: C,\n): C => {\n const Wrapped = forwardRef((props, ref) => {\n return (\n <SmoothContextProvider>\n <Component {...(props as any)} ref={ref} />\n </SmoothContextProvider>\n );\n });\n Wrapped.displayName = Component.displayName;\n return Wrapped as any;\n};\n\nfunction useSmoothContext(options?: {\n optional?: false | undefined;\n}): SmoothContextValue;\nfunction useSmoothContext(options?: {\n optional?: boolean | undefined;\n}): SmoothContextValue | null;\nfunction useSmoothContext(options?: { optional?: boolean | undefined }) {\n const context = useContext(SmoothContext);\n if (!options?.optional && !context)\n throw new Error(\n \"This component must be used within a SmoothContextProvider.\",\n );\n return context;\n}\n\nexport const { useSmoothStatus, useSmoothStatusStore } = createContextStoreHook(\n useSmoothContext,\n \"useSmoothStatus\",\n);\n"],"mappings":";;;;;;;;AA0BA,MAAMkB,gBAAgBf,cAAyC,IAAI;AAEnE,MAAMgB,qBACJC,iBACG;CAEH,OAAO,EAAEH,iBADeP,aAAaU,YAC5BH,EAAgB;AAC3B;AAEA,MAAaI,yBAA+CC,OAAA;CAAA,MAAAC,IAAAtB,EAAA,CAAA;CAAC,MAAA,EAAAuB,aAAAF;CAAY,IAAAG;CAAA,IAAAF,EAAA,OAAAG,OAAAC,IAAA,2BAAA,GAAA;EACxCF,KAAA,EAAAG,UAAY,KAAK;EAACL,EAAA,KAAAE;CAAA,OAAAA,KAAAF,EAAA;CAAjD,MAAAM,QAAcC,iBAAiBL,EAAkB;CACjD,MAAAM,MAAYjB,OAAO;CAAE,IAAAkB;CAAA,IAAAT,EAAA,OAAAQ,KAAA;EAEMC,WACzBb,kBAAkBY,IAAGE,KAAM,CAAC,CAAAC,SAAU,CAAC,CAAAC,MAAO;EAACZ,EAAA,KAAAQ;EAAAR,EAAA,KAAAS;CAAA,OAAAA,KAAAT,EAAA;CADjD,MAAA,CAAAa,WAAkB5B,SAASwB,EAE3B;CAGA,IAAIH,OAAK,OAASL;CAAS,IAAAa;CAAA,IAAAd,EAAA,OAAAC,YAAAD,EAAA,OAAAa,SAAA;EAGzBC,KAAA,oBAAA,cAAA,UAAA;GAA+BD,OAAAA;GAAUZ;EAAS,CAAA;EAAyBD,EAAA,KAAAC;EAAAD,EAAA,KAAAa;EAAAb,EAAA,KAAAc;CAAA,OAAAA,KAAAd,EAAA;CAAA,OAA3Ec;AAA2E;AAI/E,MAAaC,6BACXC,cACM;CACN,MAAME,UAAUpC,YAAWqC,OAAAC,QAAA;EAAA,MAAApB,IAAAtB,EAAA,CAAA;EAGL,MAAAqB,KAAAoB;EAAY,IAAAjB;EAAA,IAAAF,EAAA,OAAAoB,OAAApB,EAAA,OAAAD,IAAA;GAD9BG,KAAA,oBAAC,uBAAD,EAAA,UACE,oBAAC,WAAD;IAAU,GAAMH;IAAoBqB;GAAG,CAAA,EADnB,CAAA;GAEEpB,EAAA,KAAAoB;GAAApB,EAAA,KAAAD;GAAAC,EAAA,KAAAE;EAAA,OAAAA,KAAAF,EAAA;EAAA,OAFxBE;CAEwB,CAE3B;CACDgB,QAAQG,cAAcL,UAAUK;CAChC,OAAOH;AACT;AAQA,SAAAX,iBAAAe,SAAA;CACE,MAAAT,UAAgB7B,WAAWW,aAAa;CACxC,IAAI,CAAC2B,SAAOjB,YAAR,CAAuBQ,SACzB,MAAM,IAAIU,MACR,6DACF;CAAE,OACGV;AAAO;AAGhB,MAAa,EAAEnB,iBAAiB8B,yBAAyBhC,uBACvDe,kBACA,iBACF"}
@@ -1,7 +1,45 @@
1
1
  import { MessagePartState, ReasoningMessagePart, TextMessagePart } from "@assistant-ui/core";
2
2
 
3
3
  //#region src/utils/smooth/useSmooth.d.ts
4
- declare const useSmooth: (state: MessagePartState & (TextMessagePart | ReasoningMessagePart), smooth?: boolean) => MessagePartState & (TextMessagePart | ReasoningMessagePart);
4
+ /**
5
+ * Tuning options for the smooth text streaming animation.
6
+ */
7
+ type SmoothOptions = {
8
+ /**
9
+ * Target time in milliseconds to drain the backlog of unrevealed
10
+ * characters. Larger values reveal long backlogs more gradually.
11
+ * @default 250
12
+ */
13
+ drainMs?: number | undefined;
14
+ /**
15
+ * Maximum time in milliseconds between revealed characters, i.e. the
16
+ * slowest reveal rate when the backlog is short.
17
+ * @default 5
18
+ */
19
+ maxCharIntervalMs?: number | undefined;
20
+ /**
21
+ * Maximum number of characters revealed per animation frame.
22
+ * @default Infinity
23
+ */
24
+ maxCharsPerFrame?: number | undefined;
25
+ };
26
+ /**
27
+ * Animates streamed message part text with a typewriter-style reveal.
28
+ *
29
+ * Takes the current part state and a `smooth` argument: `false` disables,
30
+ * `true` uses the default rate, and a {@link SmoothOptions} object tunes
31
+ * the reveal. Returns the part state with `text` replaced by the revealed
32
+ * prefix and `status` reporting `running` until the reveal catches up.
33
+ *
34
+ * @example
35
+ * ```tsx
36
+ * const { text, status } = useSmooth(useMessagePartText(), {
37
+ * drainMs: 500,
38
+ * maxCharsPerFrame: 30,
39
+ * });
40
+ * ```
41
+ */
42
+ declare const useSmooth: (state: MessagePartState & (TextMessagePart | ReasoningMessagePart), smooth?: boolean | SmoothOptions) => MessagePartState & (TextMessagePart | ReasoningMessagePart);
5
43
  //#endregion
6
- export { useSmooth };
44
+ export { SmoothOptions, useSmooth };
7
45
  //# sourceMappingURL=useSmooth.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useSmooth.d.ts","names":[],"sources":["../../../src/utils/smooth/useSmooth.ts"],"mappings":";;;cAwEa,SAAA,GACX,KAAA,EAAO,gBAAA,IAAoB,eAAA,GAAkB,oBAAA,GAC7C,MAAA,eACC,gBAAA,IAAoB,eAAA,GAAkB,oBAAA"}
1
+ {"version":3,"file":"useSmooth.d.ts","names":[],"sources":["../../../src/utils/smooth/useSmooth.ts"],"mappings":";;;;;AAiBA;KAAY,aAAA;;;;;;EAMV,OAAA;EAWgB;AA+FlB;;;;EApGE,iBAAA;EAqG6C;;;;EAhG7C,gBAAA;AAAA;;;;;;;;;;;;AAkG2D;;;;;cAHhD,SAAA,GACX,KAAA,EAAO,gBAAA,IAAoB,eAAA,GAAkB,oBAAA,GAC7C,MAAA,aAAkB,aAAA,KACjB,gBAAA,IAAoB,eAAA,GAAkB,oBAAA"}
@@ -5,12 +5,17 @@ import { useAui, useAuiState } from "@assistant-ui/store";
5
5
  import { useEffect, useMemo, useRef, useState } from "@assistant-ui/tap/react-shim";
6
6
  import { useCallbackRef } from "@radix-ui/react-use-callback-ref";
7
7
  //#region src/utils/smooth/useSmooth.ts
8
+ const DEFAULT_DRAIN_MS = 250;
9
+ const DEFAULT_MAX_CHAR_INTERVAL_MS = 5;
8
10
  var TextStreamAnimator = class {
9
11
  currentText;
10
12
  setText;
11
13
  animationFrameId = null;
12
14
  lastUpdateTime = Date.now();
13
15
  targetText = "";
16
+ drainMs = DEFAULT_DRAIN_MS;
17
+ maxCharIntervalMs = DEFAULT_MAX_CHAR_INTERVAL_MS;
18
+ maxCharsPerFrame = Infinity;
14
19
  constructor(currentText, setText) {
15
20
  this.currentText = currentText;
16
21
  this.setText = setText;
@@ -30,12 +35,14 @@ var TextStreamAnimator = class {
30
35
  const currentTime = Date.now();
31
36
  let timeToConsume = currentTime - this.lastUpdateTime;
32
37
  const remainingChars = this.targetText.length - this.currentText.length;
33
- const baseTimePerChar = Math.min(5, 250 / remainingChars);
38
+ const baseTimePerChar = Math.min(this.maxCharIntervalMs, this.drainMs / remainingChars);
39
+ const frameLimit = Math.min(remainingChars, this.maxCharsPerFrame);
34
40
  let charsToAdd = 0;
35
- while (timeToConsume >= baseTimePerChar && charsToAdd < remainingChars) {
41
+ while (timeToConsume >= baseTimePerChar && charsToAdd < frameLimit) {
36
42
  charsToAdd++;
37
43
  timeToConsume -= baseTimePerChar;
38
44
  }
45
+ if (charsToAdd === frameLimit && frameLimit === this.maxCharsPerFrame) timeToConsume = 0;
39
46
  if (charsToAdd !== remainingChars) this.animationFrameId = requestAnimationFrame(this.animate);
40
47
  else this.animationFrameId = null;
41
48
  if (charsToAdd === 0) return;
@@ -45,8 +52,30 @@ var TextStreamAnimator = class {
45
52
  };
46
53
  };
47
54
  const SMOOTH_STATUS = Object.freeze({ type: "running" });
55
+ const positiveOr = (value, fallback) => value !== void 0 && value > 0 ? value : fallback;
56
+ /**
57
+ * Animates streamed message part text with a typewriter-style reveal.
58
+ *
59
+ * Takes the current part state and a `smooth` argument: `false` disables,
60
+ * `true` uses the default rate, and a {@link SmoothOptions} object tunes
61
+ * the reveal. Returns the part state with `text` replaced by the revealed
62
+ * prefix and `status` reporting `running` until the reveal catches up.
63
+ *
64
+ * @example
65
+ * ```tsx
66
+ * const { text, status } = useSmooth(useMessagePartText(), {
67
+ * drainMs: 500,
68
+ * maxCharsPerFrame: 30,
69
+ * });
70
+ * ```
71
+ */
48
72
  const useSmooth = (state, smooth = false) => {
49
73
  const { text } = state;
74
+ const options = typeof smooth === "object" && smooth !== null ? smooth : void 0;
75
+ const enabled = smooth !== false && smooth !== null;
76
+ const drainMs = positiveOr(options?.drainMs, DEFAULT_DRAIN_MS);
77
+ const maxCharIntervalMs = positiveOr(options?.maxCharIntervalMs, DEFAULT_MAX_CHAR_INTERVAL_MS);
78
+ const maxCharsPerFrame = positiveOr(options?.maxCharsPerFrame, Infinity);
50
79
  const [displayedText, setDisplayedText] = useState(state.status.type === "running" ? "" : text);
51
80
  const aui = useAui();
52
81
  const part = useAuiState(() => aui.part());
@@ -56,29 +85,39 @@ const useSmooth = (state, smooth = false) => {
56
85
  setDisplayedText(state.status.type === "running" ? "" : text);
57
86
  }
58
87
  const smoothStatusStore = useSmoothStatusStore({ optional: true });
59
- const setText = useCallbackRef((text) => {
60
- setDisplayedText(text);
88
+ const setText = useCallbackRef((text_0) => {
89
+ setDisplayedText(text_0);
61
90
  if (smoothStatusStore) {
62
- const target = displayedText !== text || state.status.type === "running" ? SMOOTH_STATUS : state.status;
91
+ const target = displayedText !== text_0 || state.status.type === "running" ? SMOOTH_STATUS : state.status;
63
92
  writableStore(smoothStatusStore).setState(target, true);
64
93
  }
65
94
  });
66
95
  useEffect(() => {
67
96
  if (smoothStatusStore) {
68
- const target = smooth && (displayedText !== text || state.status.type === "running") ? SMOOTH_STATUS : state.status;
69
- writableStore(smoothStatusStore).setState(target, true);
97
+ const target_0 = enabled && (displayedText !== text || state.status.type === "running") ? SMOOTH_STATUS : state.status;
98
+ writableStore(smoothStatusStore).setState(target_0, true);
70
99
  }
71
100
  }, [
72
101
  smoothStatusStore,
73
- smooth,
102
+ enabled,
74
103
  text,
75
104
  displayedText,
76
105
  state.status
77
106
  ]);
78
107
  const [animatorRef] = useState(new TextStreamAnimator(displayedText, setText));
108
+ useEffect(() => {
109
+ animatorRef.drainMs = drainMs;
110
+ animatorRef.maxCharIntervalMs = maxCharIntervalMs;
111
+ animatorRef.maxCharsPerFrame = maxCharsPerFrame;
112
+ }, [
113
+ animatorRef,
114
+ drainMs,
115
+ maxCharIntervalMs,
116
+ maxCharsPerFrame
117
+ ]);
79
118
  const animatorPartRef = useRef(part);
80
119
  useEffect(() => {
81
- if (!smooth) {
120
+ if (!enabled) {
82
121
  animatorRef.stop();
83
122
  return;
84
123
  }
@@ -100,7 +139,7 @@ const useSmooth = (state, smooth = false) => {
100
139
  animatorRef.start();
101
140
  }, [
102
141
  animatorRef,
103
- smooth,
142
+ enabled,
104
143
  text,
105
144
  state.status.type,
106
145
  part
@@ -110,12 +149,12 @@ const useSmooth = (state, smooth = false) => {
110
149
  animatorRef.stop();
111
150
  };
112
151
  }, [animatorRef]);
113
- return useMemo(() => smooth ? {
114
- type: "text",
152
+ return useMemo(() => enabled ? {
153
+ ...state,
115
154
  text: displayedText,
116
155
  status: text === displayedText ? state.status : SMOOTH_STATUS
117
156
  } : state, [
118
- smooth,
157
+ enabled,
119
158
  displayedText,
120
159
  state,
121
160
  text
@@ -1 +1 @@
1
- {"version":3,"file":"useSmooth.js","names":[],"sources":["../../../src/utils/smooth/useSmooth.ts"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport { useAui, useAuiState } from \"@assistant-ui/store\";\nimport type {\n MessagePartStatus,\n ReasoningMessagePart,\n TextMessagePart,\n MessagePartState,\n} from \"@assistant-ui/core\";\nimport { useCallbackRef } from \"@radix-ui/react-use-callback-ref\";\nimport { useSmoothStatusStore } from \"./SmoothContext\";\nimport { writableStore } from \"../../context/ReadonlyStore\";\n\nclass TextStreamAnimator {\n private animationFrameId: number | null = null;\n private lastUpdateTime: number = Date.now();\n\n public targetText: string = \"\";\n\n constructor(\n public currentText: string,\n private setText: (newText: string) => void,\n ) {}\n\n start() {\n if (this.animationFrameId !== null) return;\n this.lastUpdateTime = Date.now();\n this.animate();\n }\n\n stop() {\n if (this.animationFrameId !== null) {\n cancelAnimationFrame(this.animationFrameId);\n this.animationFrameId = null;\n }\n }\n\n private animate = () => {\n const currentTime = Date.now();\n const deltaTime = currentTime - this.lastUpdateTime;\n let timeToConsume = deltaTime;\n\n const remainingChars = this.targetText.length - this.currentText.length;\n const baseTimePerChar = Math.min(5, 250 / remainingChars);\n\n let charsToAdd = 0;\n while (timeToConsume >= baseTimePerChar && charsToAdd < remainingChars) {\n charsToAdd++;\n timeToConsume -= baseTimePerChar;\n }\n\n if (charsToAdd !== remainingChars) {\n this.animationFrameId = requestAnimationFrame(this.animate);\n } else {\n this.animationFrameId = null;\n }\n if (charsToAdd === 0) return;\n\n this.currentText = this.targetText.slice(\n 0,\n this.currentText.length + charsToAdd,\n );\n this.lastUpdateTime = currentTime - timeToConsume;\n this.setText(this.currentText);\n };\n}\n\nconst SMOOTH_STATUS: MessagePartStatus = Object.freeze({\n type: \"running\",\n});\n\nexport const useSmooth = (\n state: MessagePartState & (TextMessagePart | ReasoningMessagePart),\n smooth: boolean = false,\n): MessagePartState & (TextMessagePart | ReasoningMessagePart) => {\n const { text } = state;\n\n const [displayedText, setDisplayedText] = useState(\n state.status.type === \"running\" ? \"\" : text,\n );\n\n // Render-phase resync on part flip or text discontinuity, so the\n // first paint after a thread switch never shows the previous\n // part's text (#4051). `displayedText` is already a prefix of\n // `text` during normal streaming, so use it as the previous-text\n // reference instead of carrying separate state — avoids the\n // double render per streaming token. Read part identity through\n // `useAuiState` so we actually subscribe to its changes instead\n // of relying on a render-time proxy reference that may be stable\n // across thread swaps.\n const aui = useAui();\n const part = useAuiState(() => aui.part());\n const [prevPart, setPrevPart] = useState(part);\n if (part !== prevPart || !text.startsWith(displayedText)) {\n setPrevPart(part);\n setDisplayedText(state.status.type === \"running\" ? \"\" : text);\n }\n\n const smoothStatusStore = useSmoothStatusStore({ optional: true });\n const setText = useCallbackRef((text: string) => {\n setDisplayedText(text);\n if (smoothStatusStore) {\n const target =\n displayedText !== text || state.status.type === \"running\"\n ? SMOOTH_STATUS\n : state.status;\n writableStore(smoothStatusStore).setState(target, true);\n }\n });\n\n // TODO this is hacky\n useEffect(() => {\n if (smoothStatusStore) {\n const target =\n smooth && (displayedText !== text || state.status.type === \"running\")\n ? SMOOTH_STATUS\n : state.status;\n writableStore(smoothStatusStore).setState(target, true);\n }\n }, [smoothStatusStore, smooth, text, displayedText, state.status]);\n\n const [animatorRef] = useState<TextStreamAnimator>(\n new TextStreamAnimator(displayedText, setText),\n );\n\n const animatorPartRef = useRef(part);\n useEffect(() => {\n if (!smooth) {\n animatorRef.stop();\n return;\n }\n\n // Discontinuity: part flipped, or new text breaks continuation\n // of the animator's current target. Either case requires\n // resetting the cursor — without the part check, a new part\n // whose text happens to share a prefix with the previous target\n // would keep the stale cursor and flicker.\n const partChanged = animatorPartRef.current !== part;\n animatorPartRef.current = part;\n if (partChanged || !text.startsWith(animatorRef.targetText)) {\n if (state.status.type === \"running\") {\n animatorRef.currentText = \"\";\n animatorRef.targetText = text;\n animatorRef.start();\n } else {\n animatorRef.currentText = text;\n animatorRef.targetText = text;\n animatorRef.stop();\n }\n return;\n }\n\n animatorRef.targetText = text;\n animatorRef.start();\n }, [animatorRef, smooth, text, state.status.type, part]);\n\n useEffect(() => {\n return () => {\n animatorRef.stop();\n };\n }, [animatorRef]);\n\n return useMemo(\n () =>\n smooth\n ? {\n type: \"text\",\n text: displayedText,\n status: text === displayedText ? state.status : SMOOTH_STATUS,\n }\n : state,\n [smooth, displayedText, state, text],\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"useSmooth.js","names":["useEffect","useMemo","useRef","useState","useAui","useAuiState","MessagePartStatus","ReasoningMessagePart","TextMessagePart","MessagePartState","useCallbackRef","useSmoothStatusStore","writableStore","SmoothOptions","drainMs","maxCharIntervalMs","maxCharsPerFrame","DEFAULT_DRAIN_MS","DEFAULT_MAX_CHAR_INTERVAL_MS","TextStreamAnimator","animationFrameId","lastUpdateTime","Date","now","targetText","Infinity","constructor","currentText","setText","newText","start","animate","stop","cancelAnimationFrame","currentTime","deltaTime","timeToConsume","remainingChars","length","baseTimePerChar","Math","min","frameLimit","charsToAdd","requestAnimationFrame","slice","SMOOTH_STATUS","Object","freeze","type","positiveOr","value","fallback","undefined","useSmooth","state","smooth","text","options","enabled","displayedText","setDisplayedText","status","aui","part","prevPart","setPrevPart","startsWith","smoothStatusStore","optional","target","setState","animatorRef","animatorPartRef","partChanged","current"],"sources":["../../../src/utils/smooth/useSmooth.ts"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport { useAui, useAuiState } from \"@assistant-ui/store\";\nimport type {\n MessagePartStatus,\n ReasoningMessagePart,\n TextMessagePart,\n MessagePartState,\n} from \"@assistant-ui/core\";\nimport { useCallbackRef } from \"@radix-ui/react-use-callback-ref\";\nimport { useSmoothStatusStore } from \"./SmoothContext\";\nimport { writableStore } from \"../../context/ReadonlyStore\";\n\n/**\n * Tuning options for the smooth text streaming animation.\n */\nexport type SmoothOptions = {\n /**\n * Target time in milliseconds to drain the backlog of unrevealed\n * characters. Larger values reveal long backlogs more gradually.\n * @default 250\n */\n drainMs?: number | undefined;\n /**\n * Maximum time in milliseconds between revealed characters, i.e. the\n * slowest reveal rate when the backlog is short.\n * @default 5\n */\n maxCharIntervalMs?: number | undefined;\n /**\n * Maximum number of characters revealed per animation frame.\n * @default Infinity\n */\n maxCharsPerFrame?: number | undefined;\n};\n\nconst DEFAULT_DRAIN_MS = 250;\nconst DEFAULT_MAX_CHAR_INTERVAL_MS = 5;\n\nclass TextStreamAnimator {\n private animationFrameId: number | null = null;\n private lastUpdateTime: number = Date.now();\n\n public targetText: string = \"\";\n public drainMs: number = DEFAULT_DRAIN_MS;\n public maxCharIntervalMs: number = DEFAULT_MAX_CHAR_INTERVAL_MS;\n public maxCharsPerFrame: number = Infinity;\n\n constructor(\n public currentText: string,\n private setText: (newText: string) => void,\n ) {}\n\n start() {\n if (this.animationFrameId !== null) return;\n this.lastUpdateTime = Date.now();\n this.animate();\n }\n\n stop() {\n if (this.animationFrameId !== null) {\n cancelAnimationFrame(this.animationFrameId);\n this.animationFrameId = null;\n }\n }\n\n private animate = () => {\n const currentTime = Date.now();\n const deltaTime = currentTime - this.lastUpdateTime;\n let timeToConsume = deltaTime;\n\n const remainingChars = this.targetText.length - this.currentText.length;\n const baseTimePerChar = Math.min(\n this.maxCharIntervalMs,\n this.drainMs / remainingChars,\n );\n\n const frameLimit = Math.min(remainingChars, this.maxCharsPerFrame);\n let charsToAdd = 0;\n while (timeToConsume >= baseTimePerChar && charsToAdd < frameLimit) {\n charsToAdd++;\n timeToConsume -= baseTimePerChar;\n }\n // A cap-limited frame must not bank its surplus time, or the next\n // frame would burst past the cap.\n if (charsToAdd === frameLimit && frameLimit === this.maxCharsPerFrame) {\n timeToConsume = 0;\n }\n\n if (charsToAdd !== remainingChars) {\n this.animationFrameId = requestAnimationFrame(this.animate);\n } else {\n this.animationFrameId = null;\n }\n if (charsToAdd === 0) return;\n\n this.currentText = this.targetText.slice(\n 0,\n this.currentText.length + charsToAdd,\n );\n this.lastUpdateTime = currentTime - timeToConsume;\n this.setText(this.currentText);\n };\n}\n\nconst SMOOTH_STATUS: MessagePartStatus = Object.freeze({\n type: \"running\",\n});\n\nconst positiveOr = (value: number | undefined, fallback: number): number =>\n value !== undefined && value > 0 ? value : fallback;\n\n/**\n * Animates streamed message part text with a typewriter-style reveal.\n *\n * Takes the current part state and a `smooth` argument: `false` disables,\n * `true` uses the default rate, and a {@link SmoothOptions} object tunes\n * the reveal. Returns the part state with `text` replaced by the revealed\n * prefix and `status` reporting `running` until the reveal catches up.\n *\n * @example\n * ```tsx\n * const { text, status } = useSmooth(useMessagePartText(), {\n * drainMs: 500,\n * maxCharsPerFrame: 30,\n * });\n * ```\n */\nexport const useSmooth = (\n state: MessagePartState & (TextMessagePart | ReasoningMessagePart),\n smooth: boolean | SmoothOptions = false,\n): MessagePartState & (TextMessagePart | ReasoningMessagePart) => {\n const { text } = state;\n const options =\n typeof smooth === \"object\" && smooth !== null ? smooth : undefined;\n const enabled = smooth !== false && smooth !== null;\n const drainMs = positiveOr(options?.drainMs, DEFAULT_DRAIN_MS);\n const maxCharIntervalMs = positiveOr(\n options?.maxCharIntervalMs,\n DEFAULT_MAX_CHAR_INTERVAL_MS,\n );\n const maxCharsPerFrame = positiveOr(options?.maxCharsPerFrame, Infinity);\n\n const [displayedText, setDisplayedText] = useState(\n state.status.type === \"running\" ? \"\" : text,\n );\n\n // Render-phase resync on part flip or text discontinuity, so the\n // first paint after a thread switch never shows the previous\n // part's text (#4051). `displayedText` is already a prefix of\n // `text` during normal streaming, so use it as the previous-text\n // reference instead of carrying separate state — avoids the\n // double render per streaming token. Read part identity through\n // `useAuiState` so we actually subscribe to its changes instead\n // of relying on a render-time proxy reference that may be stable\n // across thread swaps.\n const aui = useAui();\n const part = useAuiState(() => aui.part());\n const [prevPart, setPrevPart] = useState(part);\n if (part !== prevPart || !text.startsWith(displayedText)) {\n setPrevPart(part);\n setDisplayedText(state.status.type === \"running\" ? \"\" : text);\n }\n\n const smoothStatusStore = useSmoothStatusStore({ optional: true });\n const setText = useCallbackRef((text: string) => {\n setDisplayedText(text);\n if (smoothStatusStore) {\n const target =\n displayedText !== text || state.status.type === \"running\"\n ? SMOOTH_STATUS\n : state.status;\n writableStore(smoothStatusStore).setState(target, true);\n }\n });\n\n // TODO this is hacky\n useEffect(() => {\n if (smoothStatusStore) {\n const target =\n enabled && (displayedText !== text || state.status.type === \"running\")\n ? SMOOTH_STATUS\n : state.status;\n writableStore(smoothStatusStore).setState(target, true);\n }\n }, [smoothStatusStore, enabled, text, displayedText, state.status]);\n\n const [animatorRef] = useState<TextStreamAnimator>(\n new TextStreamAnimator(displayedText, setText),\n );\n\n useEffect(() => {\n animatorRef.drainMs = drainMs;\n animatorRef.maxCharIntervalMs = maxCharIntervalMs;\n animatorRef.maxCharsPerFrame = maxCharsPerFrame;\n }, [animatorRef, drainMs, maxCharIntervalMs, maxCharsPerFrame]);\n\n const animatorPartRef = useRef(part);\n useEffect(() => {\n if (!enabled) {\n animatorRef.stop();\n return;\n }\n\n // Discontinuity: part flipped, or new text breaks continuation\n // of the animator's current target. Either case requires\n // resetting the cursor — without the part check, a new part\n // whose text happens to share a prefix with the previous target\n // would keep the stale cursor and flicker.\n const partChanged = animatorPartRef.current !== part;\n animatorPartRef.current = part;\n if (partChanged || !text.startsWith(animatorRef.targetText)) {\n if (state.status.type === \"running\") {\n animatorRef.currentText = \"\";\n animatorRef.targetText = text;\n animatorRef.start();\n } else {\n animatorRef.currentText = text;\n animatorRef.targetText = text;\n animatorRef.stop();\n }\n return;\n }\n\n animatorRef.targetText = text;\n animatorRef.start();\n }, [animatorRef, enabled, text, state.status.type, part]);\n\n useEffect(() => {\n return () => {\n animatorRef.stop();\n };\n }, [animatorRef]);\n\n return useMemo(\n () =>\n enabled\n ? {\n ...state,\n text: displayedText,\n status: text === displayedText ? state.status : SMOOTH_STATUS,\n }\n : state,\n [enabled, displayedText, state, text],\n );\n};\n"],"mappings":"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"}
@@ -1,5 +1,7 @@
1
1
  //#region src/utils/useToolArgsFieldStatus.d.ts
2
2
  declare const useToolArgsFieldStatus: (fieldPath: (string | number)[]) => {
3
+ type: string;
4
+ } | {
3
5
  readonly type: "running";
4
6
  } | {
5
7
  readonly type: "complete";
@@ -7,8 +9,6 @@ declare const useToolArgsFieldStatus: (fieldPath: (string | number)[]) => {
7
9
  readonly type: "incomplete";
8
10
  readonly reason: "cancelled" | "length" | "content-filter" | "other" | "error";
9
11
  readonly error?: unknown;
10
- } | {
11
- type: string;
12
12
  };
13
13
  //#endregion
14
14
  export { useToolArgsFieldStatus };
@@ -1 +1 @@
1
- {"version":3,"file":"useToolArgsFieldStatus.d.ts","names":[],"sources":["../../src/utils/useToolArgsFieldStatus.ts"],"mappings":";cAKa,sBAAA,GAA0B,SAAA;EAAA"}
1
+ {"version":3,"file":"useToolArgsFieldStatus.d.ts","names":[],"sources":["../../src/utils/useToolArgsFieldStatus.ts"],"mappings":";cAKa,sBAAA,GAA0B,SAAA"}
@@ -1,13 +1,21 @@
1
1
  import { useAuiState } from "@assistant-ui/store";
2
+ import { c } from "@assistant-ui/tap/react-shim/compiler-runtime";
2
3
  import { getPartialJsonObjectFieldState } from "assistant-stream/utils";
3
4
  //#region src/utils/useToolArgsFieldStatus.ts
4
5
  const COMPLETE_STATUS = { type: "complete" };
5
6
  const useToolArgsFieldStatus = (fieldPath) => {
6
- return useAuiState((s) => {
7
- if (s.part.type !== "tool-call") throw new Error("useToolArgsFieldStatus can only be used inside tool-call message parts");
8
- if (getPartialJsonObjectFieldState(s.part.args, fieldPath) === "complete" || s.part.status?.type === "requires-action") return COMPLETE_STATUS;
9
- return s.part.status;
10
- });
7
+ const $ = c(2);
8
+ let t0;
9
+ if ($[0] !== fieldPath) {
10
+ t0 = (s) => {
11
+ if (s.part.type !== "tool-call") throw new Error("useToolArgsFieldStatus can only be used inside tool-call message parts");
12
+ if (getPartialJsonObjectFieldState(s.part.args, fieldPath) === "complete" || s.part.status?.type === "requires-action") return COMPLETE_STATUS;
13
+ return s.part.status;
14
+ };
15
+ $[0] = fieldPath;
16
+ $[1] = t0;
17
+ } else t0 = $[1];
18
+ return useAuiState(t0);
11
19
  };
12
20
  //#endregion
13
21
  export { useToolArgsFieldStatus };
@@ -1 +1 @@
1
- {"version":3,"file":"useToolArgsFieldStatus.js","names":[],"sources":["../../src/utils/useToolArgsFieldStatus.ts"],"sourcesContent":["import { getPartialJsonObjectFieldState } from \"assistant-stream/utils\";\nimport { useAuiState } from \"@assistant-ui/store\";\n\nconst COMPLETE_STATUS = { type: \"complete\" };\n\nexport const useToolArgsFieldStatus = (fieldPath: (string | number)[]) => {\n return useAuiState((s) => {\n if (s.part.type !== \"tool-call\")\n throw new Error(\n \"useToolArgsFieldStatus can only be used inside tool-call message parts\",\n );\n\n const state = getPartialJsonObjectFieldState(s.part.args, fieldPath);\n if (state === \"complete\" || s.part.status?.type === \"requires-action\")\n return COMPLETE_STATUS;\n return s.part.status;\n });\n};\n"],"mappings":";;;AAGA,MAAM,kBAAkB,EAAE,MAAM,WAAW;AAE3C,MAAa,0BAA0B,cAAmC;CACxE,OAAO,aAAa,MAAM;EACxB,IAAI,EAAE,KAAK,SAAS,aAClB,MAAM,IAAI,MACR,wEACF;EAGF,IADc,+BAA+B,EAAE,KAAK,MAAM,SAClD,MAAM,cAAc,EAAE,KAAK,QAAQ,SAAS,mBAClD,OAAO;EACT,OAAO,EAAE,KAAK;CAChB,CAAC;AACH"}
1
+ {"version":3,"file":"useToolArgsFieldStatus.js","names":["getPartialJsonObjectFieldState","useAuiState","COMPLETE_STATUS","type","useToolArgsFieldStatus","fieldPath","$","_c","t0","s","part","Error","state","args","status"],"sources":["../../src/utils/useToolArgsFieldStatus.ts"],"sourcesContent":["import { getPartialJsonObjectFieldState } from \"assistant-stream/utils\";\nimport { useAuiState } from \"@assistant-ui/store\";\n\nconst COMPLETE_STATUS = { type: \"complete\" };\n\nexport const useToolArgsFieldStatus = (fieldPath: (string | number)[]) => {\n return useAuiState((s) => {\n if (s.part.type !== \"tool-call\")\n throw new Error(\n \"useToolArgsFieldStatus can only be used inside tool-call message parts\",\n );\n\n const state = getPartialJsonObjectFieldState(s.part.args, fieldPath);\n if (state === \"complete\" || s.part.status?.type === \"requires-action\")\n return COMPLETE_STATUS;\n return s.part.status;\n });\n};\n"],"mappings":";;;;AAGA,MAAME,kBAAkB,EAAEC,MAAM,WAAW;AAE3C,MAAaC,0BAAyBC,cAAA;CAAA,MAAAC,IAAAC,EAAA,CAAA;CAAA,IAAAC;CAAA,IAAAF,EAAA,OAAAD,WAAA;EACjBG,MAAAC,MAAA;GACjB,IAAIA,EAACC,KAAKP,SAAU,aAClB,MAAM,IAAIQ,MACR,wEACF;GAGF,IADcX,+BAA+BS,EAACC,KAAKG,MAAOR,SACtDO,MAAU,cAAcH,EAACC,KAAKI,QAAaX,SAAK,mBAAiB,OAC5DD;GAAgB,OAClBO,EAACC,KAAKI;EAAO;EACrBR,EAAA,KAAAD;EAAAC,EAAA,KAAAE;CAAA,OAAAA,KAAAF,EAAA;CAAA,OAVML,YAAYO,EAUlB;AAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@assistant-ui/react",
3
- "version": "0.14.16",
3
+ "version": "0.14.19",
4
4
  "description": "Open-source TypeScript/React library for building production-grade AI chat experiences",
5
5
  "keywords": [
6
6
  "ai",
@@ -55,9 +55,9 @@
55
55
  ],
56
56
  "sideEffects": false,
57
57
  "dependencies": {
58
- "@assistant-ui/core": "^0.2.12",
59
- "@assistant-ui/store": "^0.2.14",
60
- "@assistant-ui/tap": "^0.6.1",
58
+ "@assistant-ui/core": "^0.2.15",
59
+ "@assistant-ui/store": "^0.2.17",
60
+ "@assistant-ui/tap": "^0.8.1",
61
61
  "@radix-ui/primitive": "^1.1.4",
62
62
  "@radix-ui/react-compose-refs": "^1.1.3",
63
63
  "@radix-ui/react-context": "^1.1.4",
@@ -65,7 +65,7 @@
65
65
  "@radix-ui/react-use-callback-ref": "^1.1.2",
66
66
  "@radix-ui/react-use-escape-keydown": "^1.1.2",
67
67
  "assistant-cloud": "^0.1.32",
68
- "assistant-stream": "^0.3.21",
68
+ "assistant-stream": "^0.3.22",
69
69
  "nanoid": "^5.1.11",
70
70
  "radix-ui": "^1.5.0",
71
71
  "react-textarea-autosize": "^8.5.9",
@@ -98,7 +98,7 @@
98
98
  "react-dom": "^19.2.7",
99
99
  "vitest": "^4.1.8",
100
100
  "@assistant-ui/vite": "0.0.4",
101
- "@assistant-ui/x-buildutils": "0.0.12"
101
+ "@assistant-ui/x-buildutils": "0.0.13"
102
102
  },
103
103
  "publishConfig": {
104
104
  "access": "public",