@assistant-ui/core 0.3.13 → 0.3.15

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 (463) hide show
  1. package/dist/adapters/speech.d.ts.map +1 -1
  2. package/dist/adapters/speech.js +9 -15
  3. package/dist/adapters/speech.js.map +1 -1
  4. package/dist/adapters/thread-history.d.ts +2 -0
  5. package/dist/adapters/thread-history.d.ts.map +1 -1
  6. package/dist/adapters/voice.d.ts.map +1 -1
  7. package/dist/adapters/voice.js +38 -15
  8. package/dist/adapters/voice.js.map +1 -1
  9. package/dist/index.d.ts +2 -2
  10. package/dist/index.js +1 -1
  11. package/dist/index.js.map +1 -1
  12. package/dist/internal.d.ts +3 -2
  13. package/dist/internal.js +8 -7
  14. package/dist/model-context/frame/host.d.ts +1 -1
  15. package/dist/model-context/frame/host.d.ts.map +1 -1
  16. package/dist/model-context/frame/host.js +19 -4
  17. package/dist/model-context/frame/host.js.map +1 -1
  18. package/dist/model-context/frame/provider.d.ts +4 -0
  19. package/dist/model-context/frame/provider.d.ts.map +1 -1
  20. package/dist/model-context/frame/provider.js +50 -3
  21. package/dist/model-context/frame/provider.js.map +1 -1
  22. package/dist/model-context/frame/types.d.ts +4 -1
  23. package/dist/model-context/frame/types.d.ts.map +1 -1
  24. package/dist/model-context/frame/types.js.map +1 -1
  25. package/dist/model-context/registry.d.ts.map +1 -1
  26. package/dist/model-context/registry.js +16 -4
  27. package/dist/model-context/registry.js.map +1 -1
  28. package/dist/react/RuntimeAdapter.d.ts +8 -1
  29. package/dist/react/RuntimeAdapter.d.ts.map +1 -1
  30. package/dist/react/RuntimeAdapter.js +23 -18
  31. package/dist/react/RuntimeAdapter.js.map +1 -1
  32. package/dist/react/adapters/LocalStorageThreadListAdapter.d.ts.map +1 -1
  33. package/dist/react/adapters/LocalStorageThreadListAdapter.js +28 -12
  34. package/dist/react/adapters/LocalStorageThreadListAdapter.js.map +1 -1
  35. package/dist/react/client/AdaptedRemoteThread.d.ts +11 -0
  36. package/dist/react/client/AdaptedRemoteThread.d.ts.map +1 -0
  37. package/dist/react/client/AdaptedRemoteThread.js +27 -0
  38. package/dist/react/client/AdaptedRemoteThread.js.map +1 -0
  39. package/dist/react/client/InMemoryThreadList.d.ts +19 -0
  40. package/dist/react/client/InMemoryThreadList.d.ts.map +1 -0
  41. package/dist/react/client/InMemoryThreadList.js +418 -0
  42. package/dist/react/client/InMemoryThreadList.js.map +1 -0
  43. package/dist/react/client/Interactables.d.ts.map +1 -1
  44. package/dist/react/client/Interactables.js +159 -102
  45. package/dist/react/client/Interactables.js.map +1 -1
  46. package/dist/react/client/RemoteThreadList.d.ts +34 -0
  47. package/dist/react/client/RemoteThreadList.d.ts.map +1 -0
  48. package/dist/react/client/RemoteThreadList.js +898 -0
  49. package/dist/react/client/RemoteThreadList.js.map +1 -0
  50. package/dist/react/client/Tools.d.ts.map +1 -1
  51. package/dist/react/client/Tools.js +38 -27
  52. package/dist/react/client/Tools.js.map +1 -1
  53. package/dist/react/index.d.ts +7 -2
  54. package/dist/react/index.js +5 -2
  55. package/dist/react/interactables-legacy/Interactables.d.ts.map +1 -1
  56. package/dist/react/interactables-legacy/Interactables.js +145 -110
  57. package/dist/react/interactables-legacy/Interactables.js.map +1 -1
  58. package/dist/react/primitive-hooks/useActionBarCopy.d.ts.map +1 -1
  59. package/dist/react/primitive-hooks/useActionBarCopy.js +20 -19
  60. package/dist/react/primitive-hooks/useActionBarCopy.js.map +1 -1
  61. package/dist/react/primitive-hooks/useActionBarEdit.d.ts.map +1 -1
  62. package/dist/react/primitive-hooks/useActionBarEdit.js +2 -4
  63. package/dist/react/primitive-hooks/useActionBarEdit.js.map +1 -1
  64. package/dist/react/primitive-hooks/useActionBarReload.d.ts.map +1 -1
  65. package/dist/react/primitive-hooks/useActionBarReload.js +2 -4
  66. package/dist/react/primitive-hooks/useActionBarReload.js.map +1 -1
  67. package/dist/react/primitive-hooks/useBranchPickerNext.d.ts.map +1 -1
  68. package/dist/react/primitive-hooks/useBranchPickerNext.js +2 -6
  69. package/dist/react/primitive-hooks/useBranchPickerNext.js.map +1 -1
  70. package/dist/react/primitive-hooks/useBranchPickerPrevious.d.ts.map +1 -1
  71. package/dist/react/primitive-hooks/useBranchPickerPrevious.js +2 -6
  72. package/dist/react/primitive-hooks/useBranchPickerPrevious.js.map +1 -1
  73. package/dist/react/primitive-hooks/useComposerCancel.d.ts.map +1 -1
  74. package/dist/react/primitive-hooks/useComposerCancel.js +2 -4
  75. package/dist/react/primitive-hooks/useComposerCancel.js.map +1 -1
  76. package/dist/react/primitive-hooks/useComposerSend.d.ts.map +1 -1
  77. package/dist/react/primitive-hooks/useComposerSend.js +2 -4
  78. package/dist/react/primitive-hooks/useComposerSend.js.map +1 -1
  79. package/dist/react/primitive-hooks/useSuggestionTrigger.d.ts.map +1 -1
  80. package/dist/react/primitive-hooks/useSuggestionTrigger.js +6 -2
  81. package/dist/react/primitive-hooks/useSuggestionTrigger.js.map +1 -1
  82. package/dist/react/primitive-hooks/useThreadIsEmpty.d.ts +3 -0
  83. package/dist/react/primitive-hooks/useThreadIsEmpty.d.ts.map +1 -1
  84. package/dist/react/primitive-hooks/useThreadIsEmpty.js +3 -0
  85. package/dist/react/primitive-hooks/useThreadIsEmpty.js.map +1 -1
  86. package/dist/react/primitive-hooks/useThreadIsRunning.d.ts +3 -0
  87. package/dist/react/primitive-hooks/useThreadIsRunning.d.ts.map +1 -1
  88. package/dist/react/primitive-hooks/useThreadIsRunning.js +3 -0
  89. package/dist/react/primitive-hooks/useThreadIsRunning.js.map +1 -1
  90. package/dist/react/primitives/message/MessageParts.d.ts +13 -0
  91. package/dist/react/primitives/message/MessageParts.d.ts.map +1 -1
  92. package/dist/react/primitives/message/MessageParts.js.map +1 -1
  93. package/dist/react/primitives/thread/ThreadMessages.d.ts.map +1 -1
  94. package/dist/react/primitives/thread/ThreadMessages.js +1 -1
  95. package/dist/react/primitives/thread/ThreadMessages.js.map +1 -1
  96. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts +24 -10
  97. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts.map +1 -1
  98. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js +115 -71
  99. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js.map +1 -1
  100. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts +14 -2
  101. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts.map +1 -1
  102. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js +232 -63
  103. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js.map +1 -1
  104. package/dist/react/runtimes/RemoteThreadResource.d.ts +30 -0
  105. package/dist/react/runtimes/RemoteThreadResource.d.ts.map +1 -0
  106. package/dist/react/runtimes/RemoteThreadResource.js +136 -0
  107. package/dist/react/runtimes/RemoteThreadResource.js.map +1 -0
  108. package/dist/react/runtimes/RuntimeAdapterProvider.d.ts +3 -10
  109. package/dist/react/runtimes/RuntimeAdapterProvider.d.ts.map +1 -1
  110. package/dist/react/runtimes/RuntimeAdapterProvider.js +3 -6
  111. package/dist/react/runtimes/RuntimeAdapterProvider.js.map +1 -1
  112. package/dist/react/runtimes/assistant-transport/commandQueue.d.ts +17 -0
  113. package/dist/react/runtimes/assistant-transport/commandQueue.d.ts.map +1 -0
  114. package/dist/react/runtimes/assistant-transport/commandQueue.js +55 -0
  115. package/dist/react/runtimes/assistant-transport/commandQueue.js.map +1 -0
  116. package/dist/react/runtimes/assistant-transport/replayBoundaryStream.d.ts +11 -0
  117. package/dist/react/runtimes/assistant-transport/replayBoundaryStream.d.ts.map +1 -0
  118. package/dist/react/runtimes/assistant-transport/replayBoundaryStream.js +165 -0
  119. package/dist/react/runtimes/assistant-transport/replayBoundaryStream.js.map +1 -0
  120. package/dist/react/runtimes/assistant-transport/runManager.d.ts +15 -0
  121. package/dist/react/runtimes/assistant-transport/runManager.d.ts.map +1 -0
  122. package/dist/react/runtimes/assistant-transport/runManager.js +86 -0
  123. package/dist/react/runtimes/assistant-transport/runManager.js.map +1 -0
  124. package/dist/react/runtimes/assistant-transport/types.d.ts +130 -0
  125. package/dist/react/runtimes/assistant-transport/types.d.ts.map +1 -0
  126. package/dist/react/runtimes/assistant-transport/types.js +0 -0
  127. package/dist/react/runtimes/assistant-transport/useAssistantTransportRuntime.d.ts +14 -0
  128. package/dist/react/runtimes/assistant-transport/useAssistantTransportRuntime.d.ts.map +1 -0
  129. package/dist/react/runtimes/assistant-transport/useAssistantTransportRuntime.js +296 -0
  130. package/dist/react/runtimes/assistant-transport/useAssistantTransportRuntime.js.map +1 -0
  131. package/dist/react/runtimes/assistant-transport/useConvertedState.d.ts +7 -0
  132. package/dist/react/runtimes/assistant-transport/useConvertedState.d.ts.map +1 -0
  133. package/dist/react/runtimes/assistant-transport/useConvertedState.js +25 -0
  134. package/dist/react/runtimes/assistant-transport/useConvertedState.js.map +1 -0
  135. package/dist/react/runtimes/assistant-transport/useLatestRef.d.ts +7 -0
  136. package/dist/react/runtimes/assistant-transport/useLatestRef.d.ts.map +1 -0
  137. package/dist/react/runtimes/assistant-transport/useLatestRef.js +27 -0
  138. package/dist/react/runtimes/assistant-transport/useLatestRef.js.map +1 -0
  139. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts.map +1 -1
  140. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js +39 -13
  141. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js.map +1 -1
  142. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.d.ts +2 -1
  143. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.d.ts.map +1 -1
  144. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.js +3 -3
  145. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.js.map +1 -1
  146. package/dist/react/runtimes/cloud/auiV0.d.ts +4 -0
  147. package/dist/react/runtimes/cloud/auiV0.d.ts.map +1 -1
  148. package/dist/react/runtimes/cloud/auiV0.js +7 -0
  149. package/dist/react/runtimes/cloud/auiV0.js.map +1 -1
  150. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.d.ts.map +1 -1
  151. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js +60 -17
  152. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js.map +1 -1
  153. package/dist/react/runtimes/cloud/useCloudThreadListRuntime.d.ts +16 -0
  154. package/dist/react/runtimes/cloud/useCloudThreadListRuntime.d.ts.map +1 -0
  155. package/dist/react/runtimes/cloud/useCloudThreadListRuntime.js +36 -0
  156. package/dist/react/runtimes/cloud/useCloudThreadListRuntime.js.map +1 -0
  157. package/dist/react/runtimes/external-message-converter.js +14 -14
  158. package/dist/react/runtimes/external-message-converter.js.map +1 -1
  159. package/dist/react/runtimes/useExternalStoreRuntime.d.ts.map +1 -1
  160. package/dist/react/runtimes/useExternalStoreRuntime.js +44 -28
  161. package/dist/react/runtimes/useExternalStoreRuntime.js.map +1 -1
  162. package/dist/react/runtimes/useExternalStoreSharedOptions.js.map +1 -1
  163. package/dist/react/runtimes/useLocalRuntime.js +1 -1
  164. package/dist/react/runtimes/useRuntimeAdapters.d.ts +9 -0
  165. package/dist/react/runtimes/useRuntimeAdapters.d.ts.map +1 -0
  166. package/dist/react/runtimes/useRuntimeAdapters.js +20 -0
  167. package/dist/react/runtimes/useRuntimeAdapters.js.map +1 -0
  168. package/dist/runtime/api/composer-runtime.d.ts +5 -0
  169. package/dist/runtime/api/composer-runtime.d.ts.map +1 -1
  170. package/dist/runtime/api/composer-runtime.js.map +1 -1
  171. package/dist/runtime/api/message-runtime.js +1 -1
  172. package/dist/runtime/api/thread-list-runtime.d.ts +1 -0
  173. package/dist/runtime/api/thread-list-runtime.d.ts.map +1 -1
  174. package/dist/runtime/api/thread-list-runtime.js +4 -2
  175. package/dist/runtime/api/thread-list-runtime.js.map +1 -1
  176. package/dist/runtime/api/thread-runtime.d.ts +12 -2
  177. package/dist/runtime/api/thread-runtime.d.ts.map +1 -1
  178. package/dist/runtime/api/thread-runtime.js +8 -2
  179. package/dist/runtime/api/thread-runtime.js.map +1 -1
  180. package/dist/runtime/base/base-composer-runtime-core.d.ts.map +1 -1
  181. package/dist/runtime/base/base-composer-runtime-core.js +8 -7
  182. package/dist/runtime/base/base-composer-runtime-core.js.map +1 -1
  183. package/dist/runtime/base/base-thread-runtime-core.d.ts +1 -0
  184. package/dist/runtime/base/base-thread-runtime-core.d.ts.map +1 -1
  185. package/dist/runtime/base/base-thread-runtime-core.js +3 -3
  186. package/dist/runtime/base/base-thread-runtime-core.js.map +1 -1
  187. package/dist/runtime/base/default-thread-composer-runtime-core.d.ts +0 -1
  188. package/dist/runtime/base/default-thread-composer-runtime-core.d.ts.map +1 -1
  189. package/dist/runtime/base/default-thread-composer-runtime-core.js +10 -4
  190. package/dist/runtime/base/default-thread-composer-runtime-core.js.map +1 -1
  191. package/dist/runtime/interfaces/thread-runtime-core.d.ts +6 -0
  192. package/dist/runtime/interfaces/thread-runtime-core.d.ts.map +1 -1
  193. package/dist/runtime/internal.js +5 -5
  194. package/dist/runtime/queue/message-queue.d.ts.map +1 -1
  195. package/dist/runtime/queue/message-queue.js +2 -1
  196. package/dist/runtime/queue/message-queue.js.map +1 -1
  197. package/dist/runtime/utils/message-repository.d.ts.map +1 -1
  198. package/dist/runtime/utils/message-repository.js +27 -18
  199. package/dist/runtime/utils/message-repository.js.map +1 -1
  200. package/dist/runtime/utils/thread-runtime-lifecycle.d.ts +8 -0
  201. package/dist/runtime/utils/thread-runtime-lifecycle.d.ts.map +1 -0
  202. package/dist/runtime/utils/thread-runtime-lifecycle.js +11 -0
  203. package/dist/runtime/utils/thread-runtime-lifecycle.js.map +1 -0
  204. package/dist/runtimes/external-store/external-store-shared-options.js.map +1 -1
  205. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.d.ts.map +1 -1
  206. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js +4 -1
  207. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js.map +1 -1
  208. package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts +8 -0
  209. package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts.map +1 -1
  210. package/dist/runtimes/external-store/external-store-thread-runtime-core.js +37 -13
  211. package/dist/runtimes/external-store/external-store-thread-runtime-core.js.map +1 -1
  212. package/dist/runtimes/inert/InertThreadRuntimeCore.d.ts +102 -0
  213. package/dist/runtimes/inert/InertThreadRuntimeCore.d.ts.map +1 -0
  214. package/dist/runtimes/inert/InertThreadRuntimeCore.js +156 -0
  215. package/dist/runtimes/inert/InertThreadRuntimeCore.js.map +1 -0
  216. package/dist/runtimes/internal.d.ts +1 -1
  217. package/dist/runtimes/local/local-thread-runtime-core.d.ts +3 -0
  218. package/dist/runtimes/local/local-thread-runtime-core.d.ts.map +1 -1
  219. package/dist/runtimes/local/local-thread-runtime-core.js +78 -19
  220. package/dist/runtimes/local/local-thread-runtime-core.js.map +1 -1
  221. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.d.ts +12 -59
  222. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.d.ts.map +1 -1
  223. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.js +10 -142
  224. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.js.map +1 -1
  225. package/dist/runtimes/remote-thread-list/adapter-changed.d.ts +9 -0
  226. package/dist/runtimes/remote-thread-list/adapter-changed.d.ts.map +1 -0
  227. package/dist/runtimes/remote-thread-list/adapter-changed.js +13 -0
  228. package/dist/runtimes/remote-thread-list/adapter-changed.js.map +1 -0
  229. package/dist/runtimes/remote-thread-list/empty-thread-core.d.ts.map +1 -1
  230. package/dist/runtimes/remote-thread-list/empty-thread-core.js +16 -152
  231. package/dist/runtimes/remote-thread-list/empty-thread-core.js.map +1 -1
  232. package/dist/runtimes/remote-thread-list/optimistic-state.d.ts +2 -0
  233. package/dist/runtimes/remote-thread-list/optimistic-state.d.ts.map +1 -1
  234. package/dist/runtimes/remote-thread-list/optimistic-state.js +11 -0
  235. package/dist/runtimes/remote-thread-list/optimistic-state.js.map +1 -1
  236. package/dist/runtimes/remote-thread-list/types.d.ts +32 -1
  237. package/dist/runtimes/remote-thread-list/types.d.ts.map +1 -1
  238. package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts +1 -12
  239. package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts.map +1 -1
  240. package/dist/runtimes/tool-invocations/ToolInvocationTracker.js +67 -38
  241. package/dist/runtimes/tool-invocations/ToolInvocationTracker.js.map +1 -1
  242. package/dist/store/clients/external-thread.js +1 -1
  243. package/dist/store/clients/external-thread.js.map +1 -1
  244. package/dist/store/clients/suggestions.js +2 -2
  245. package/dist/store/clients/suggestions.js.map +1 -1
  246. package/dist/store/clients/thread-selection-events.d.ts +10 -0
  247. package/dist/store/clients/thread-selection-events.d.ts.map +1 -0
  248. package/dist/store/clients/thread-selection-events.js +40 -0
  249. package/dist/store/clients/thread-selection-events.js.map +1 -0
  250. package/dist/store/env.d.ts +5 -0
  251. package/dist/store/env.d.ts.map +1 -0
  252. package/dist/store/env.js +12 -0
  253. package/dist/store/env.js.map +1 -0
  254. package/dist/store/index.d.ts +5 -3
  255. package/dist/store/index.js +4 -2
  256. package/dist/store/internal.d.ts +4 -1
  257. package/dist/store/internal.js +4 -1
  258. package/dist/store/primitive-predicates.d.ts +19 -0
  259. package/dist/store/primitive-predicates.d.ts.map +1 -0
  260. package/dist/store/primitive-predicates.js +19 -0
  261. package/dist/store/primitive-predicates.js.map +1 -0
  262. package/dist/store/runtime-clients/attachment-runtime-client.d.ts.map +1 -1
  263. package/dist/store/runtime-clients/attachment-runtime-client.js +18 -11
  264. package/dist/store/runtime-clients/attachment-runtime-client.js.map +1 -1
  265. package/dist/store/runtime-clients/handle-runtime-action.d.ts +5 -0
  266. package/dist/store/runtime-clients/handle-runtime-action.d.ts.map +1 -0
  267. package/dist/store/runtime-clients/handle-runtime-action.js +14 -0
  268. package/dist/store/runtime-clients/handle-runtime-action.js.map +1 -0
  269. package/dist/store/runtime-clients/handle-thread-list-action.d.ts +5 -0
  270. package/dist/store/runtime-clients/handle-thread-list-action.d.ts.map +1 -0
  271. package/dist/store/runtime-clients/handle-thread-list-action.js +7 -0
  272. package/dist/store/runtime-clients/handle-thread-list-action.js.map +1 -0
  273. package/dist/store/runtime-clients/thread-list-item-runtime-client.d.ts.map +1 -1
  274. package/dist/store/runtime-clients/thread-list-item-runtime-client.js +62 -29
  275. package/dist/store/runtime-clients/thread-list-item-runtime-client.js.map +1 -1
  276. package/dist/store/runtime-clients/thread-list-runtime-client.d.ts.map +1 -1
  277. package/dist/store/runtime-clients/thread-list-runtime-client.js +5 -6
  278. package/dist/store/runtime-clients/thread-list-runtime-client.js.map +1 -1
  279. package/dist/store/scopes/composer.d.ts +9 -4
  280. package/dist/store/scopes/composer.d.ts.map +1 -1
  281. package/dist/store/scopes/thread-list-item.d.ts +7 -6
  282. package/dist/store/scopes/thread-list-item.d.ts.map +1 -1
  283. package/dist/store/scopes/thread.d.ts +8 -7
  284. package/dist/store/scopes/thread.d.ts.map +1 -1
  285. package/dist/store/scopes/threads.d.ts +17 -1
  286. package/dist/store/scopes/threads.d.ts.map +1 -1
  287. package/dist/subscribable/subscribable.d.ts +2 -1
  288. package/dist/subscribable/subscribable.d.ts.map +1 -1
  289. package/dist/subscribable/subscribable.js +23 -18
  290. package/dist/subscribable/subscribable.js.map +1 -1
  291. package/dist/types/message.d.ts +1 -1
  292. package/dist/types/message.js.map +1 -1
  293. package/dist/utils/composite-context-provider.d.ts +1 -0
  294. package/dist/utils/composite-context-provider.d.ts.map +1 -1
  295. package/dist/utils/composite-context-provider.js +25 -9
  296. package/dist/utils/composite-context-provider.js.map +1 -1
  297. package/dist/utils/notify-event-listeners.d.ts +2 -2
  298. package/dist/utils/notify-event-listeners.d.ts.map +1 -1
  299. package/dist/utils/notify-event-listeners.js +2 -2
  300. package/dist/utils/notify-event-listeners.js.map +1 -1
  301. package/dist/utils/silent-runtime-action.d.ts +6 -0
  302. package/dist/utils/silent-runtime-action.d.ts.map +1 -0
  303. package/dist/utils/silent-runtime-action.js +7 -0
  304. package/dist/utils/silent-runtime-action.js.map +1 -0
  305. package/package.json +8 -8
  306. package/src/adapters/speech.test.ts +118 -1
  307. package/src/adapters/speech.ts +21 -22
  308. package/src/adapters/thread-history.ts +2 -0
  309. package/src/adapters/voice.test.ts +134 -0
  310. package/src/adapters/voice.ts +35 -27
  311. package/src/index.ts +1 -0
  312. package/src/internal.ts +1 -0
  313. package/src/model-context/frame/host.test.ts +87 -5
  314. package/src/model-context/frame/host.ts +18 -4
  315. package/src/model-context/frame/provider.test.ts +347 -20
  316. package/src/model-context/frame/provider.ts +58 -2
  317. package/src/model-context/frame/types.ts +5 -0
  318. package/src/model-context/registry.test.ts +131 -0
  319. package/src/model-context/registry.ts +16 -6
  320. package/src/react/RuntimeAdapter.test.ts +2 -0
  321. package/src/react/RuntimeAdapter.ts +20 -8
  322. package/src/react/adapters/LocalStorageThreadListAdapter.tsx +34 -17
  323. package/src/react/client/AdaptedRemoteThread.ts +41 -0
  324. package/src/react/client/InMemoryThreadList.test.tsx +148 -0
  325. package/src/react/client/InMemoryThreadList.ts +290 -0
  326. package/src/react/client/Interactables.test.ts +326 -2
  327. package/src/react/client/Interactables.ts +227 -110
  328. package/src/react/client/RemoteThreadList.test.ts +1222 -0
  329. package/src/react/client/RemoteThreadList.ts +1136 -0
  330. package/src/react/client/Tools.ts +36 -29
  331. package/src/react/index.ts +13 -0
  332. package/src/react/interactables-legacy/Interactables.test.ts +317 -0
  333. package/src/react/interactables-legacy/Interactables.ts +204 -128
  334. package/src/react/primitive-hooks/useActionBarCopy.test.ts +15 -0
  335. package/src/react/primitive-hooks/useActionBarCopy.ts +15 -10
  336. package/src/react/primitive-hooks/useActionBarEdit.ts +2 -1
  337. package/src/react/primitive-hooks/useActionBarReload.ts +2 -6
  338. package/src/react/primitive-hooks/useBranchPickerNext.ts +2 -7
  339. package/src/react/primitive-hooks/useBranchPickerPrevious.ts +2 -7
  340. package/src/react/primitive-hooks/useComposerCancel.ts +2 -1
  341. package/src/react/primitive-hooks/useComposerSend.ts +2 -5
  342. package/src/react/primitive-hooks/useSuggestionTrigger.test.ts +11 -0
  343. package/src/react/primitive-hooks/useSuggestionTrigger.ts +4 -5
  344. package/src/react/primitive-hooks/useThreadIsEmpty.ts +3 -0
  345. package/src/react/primitive-hooks/useThreadIsRunning.ts +3 -0
  346. package/src/react/primitives/message/MessageParts.tsx +0 -1
  347. package/src/react/primitives/thread/ThreadMessages.tsx +2 -1
  348. package/src/react/runtimes/RemoteThreadListHookInstanceManager.retry.test.tsx +116 -0
  349. package/src/react/runtimes/RemoteThreadListHookInstanceManager.running.test.tsx +1 -1
  350. package/src/react/runtimes/RemoteThreadListHookInstanceManager.test.tsx +57 -6
  351. package/src/react/runtimes/RemoteThreadListHookInstanceManager.title.test.tsx +272 -0
  352. package/src/react/runtimes/RemoteThreadListHookInstanceManager.tsx +171 -124
  353. package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.republish.test.ts +87 -0
  354. package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.tsx +327 -83
  355. package/src/react/runtimes/RemoteThreadResource.test.ts +141 -0
  356. package/src/react/runtimes/RemoteThreadResource.ts +233 -0
  357. package/src/react/runtimes/RuntimeAdapterProvider.tsx +8 -20
  358. package/src/react/runtimes/assistant-transport/commandQueue.ts +68 -0
  359. package/src/react/runtimes/assistant-transport/replayBoundaryStream.test.ts +455 -0
  360. package/src/react/runtimes/assistant-transport/replayBoundaryStream.ts +172 -0
  361. package/src/react/runtimes/assistant-transport/runManager.ts +124 -0
  362. package/src/react/runtimes/assistant-transport/transport-delivery.test.tsx +79 -0
  363. package/src/react/runtimes/assistant-transport/transport-parentid.test.tsx +97 -0
  364. package/src/react/runtimes/assistant-transport/transport-scheduling.test.ts +414 -0
  365. package/src/react/runtimes/assistant-transport/types.ts +170 -0
  366. package/src/react/runtimes/assistant-transport/useAssistantTransport.spec.md +141 -0
  367. package/src/react/runtimes/assistant-transport/useAssistantTransportRuntime.test.tsx +683 -0
  368. package/src/react/runtimes/assistant-transport/useAssistantTransportRuntime.ts +483 -0
  369. package/src/react/runtimes/assistant-transport/useConvertedState.ts +20 -0
  370. package/src/react/runtimes/assistant-transport/useLatestRef.ts +9 -0
  371. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.test.tsx +131 -6
  372. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.ts +61 -15
  373. package/src/react/runtimes/cloud/CloudFileAttachmentAdapter.ts +6 -4
  374. package/src/react/runtimes/cloud/auiV0.ts +17 -1
  375. package/src/react/runtimes/cloud/useCloudThreadListAdapter.test.tsx +98 -3
  376. package/src/react/runtimes/cloud/useCloudThreadListAdapter.tsx +104 -27
  377. package/src/react/runtimes/cloud/useCloudThreadListRuntime.test.tsx +56 -0
  378. package/src/react/runtimes/cloud/useCloudThreadListRuntime.ts +31 -0
  379. package/src/react/runtimes/external-message-converter.test.ts +143 -0
  380. package/src/react/runtimes/external-message-converter.ts +41 -41
  381. package/src/react/runtimes/remote-thread-hook-on-tap.test.ts +58 -0
  382. package/src/react/runtimes/useExternalStoreRuntime.lifecycle.test.tsx +83 -0
  383. package/src/react/runtimes/useExternalStoreRuntime.suggestions.test.tsx +13 -3
  384. package/src/react/runtimes/useExternalStoreRuntime.ts +7 -0
  385. package/src/react/runtimes/useExternalStoreSharedOptions.ts +3 -1
  386. package/src/react/runtimes/useLocalRuntime.test.tsx +134 -8
  387. package/src/react/runtimes/useRuntimeAdapters.test.tsx +62 -0
  388. package/src/react/runtimes/useRuntimeAdapters.ts +28 -0
  389. package/src/runtime/api/composer-runtime.ts +5 -0
  390. package/src/runtime/api/thread-list-runtime.ts +3 -1
  391. package/src/runtime/api/thread-runtime.ts +20 -2
  392. package/src/runtime/base/base-composer-runtime-core.ts +6 -5
  393. package/src/runtime/base/base-thread-runtime-core.test.ts +191 -0
  394. package/src/runtime/base/base-thread-runtime-core.ts +11 -2
  395. package/src/runtime/base/default-thread-composer-runtime-core.ts +12 -4
  396. package/src/runtime/interfaces/thread-runtime-core.ts +6 -0
  397. package/src/runtime/queue/message-queue.ts +2 -1
  398. package/src/runtime/utils/message-repository.ts +26 -18
  399. package/src/runtime/utils/thread-runtime-lifecycle.ts +18 -0
  400. package/src/runtimes/external-store/external-store-shared-options.ts +3 -1
  401. package/src/runtimes/external-store/external-store-thread-list-runtime-core.ts +4 -1
  402. package/src/runtimes/external-store/external-store-thread-runtime-core.ts +103 -34
  403. package/src/runtimes/inert/InertThreadRuntimeCore.test.ts +253 -0
  404. package/src/runtimes/inert/InertThreadRuntimeCore.ts +232 -0
  405. package/src/runtimes/local/local-thread-runtime-core.test.ts +692 -4
  406. package/src/runtimes/local/local-thread-runtime-core.ts +117 -22
  407. package/src/runtimes/readonly/ReadonlyThreadRuntimeCore.ts +17 -205
  408. package/src/runtimes/remote-thread-list/adapter-changed.ts +10 -0
  409. package/src/runtimes/remote-thread-list/empty-thread-core.ts +28 -217
  410. package/src/runtimes/remote-thread-list/optimistic-state.test.ts +18 -0
  411. package/src/runtimes/remote-thread-list/optimistic-state.ts +13 -0
  412. package/src/runtimes/remote-thread-list/types.ts +34 -0
  413. package/src/runtimes/tool-invocations/EDGE_CASES.md +17 -6
  414. package/src/runtimes/tool-invocations/ToolInvocationTracker.test.ts +243 -0
  415. package/src/runtimes/tool-invocations/ToolInvocationTracker.ts +127 -61
  416. package/src/store/clients/external-thread.ts +1 -1
  417. package/src/store/clients/model-context-client.test.ts +16 -8
  418. package/src/store/clients/suggestions.ts +2 -2
  419. package/src/store/clients/thread-selection-events.ts +21 -0
  420. package/src/store/env.ts +11 -0
  421. package/src/store/index.ts +14 -1
  422. package/src/store/internal.ts +13 -0
  423. package/src/store/primitive-predicates.test.ts +184 -0
  424. package/src/store/primitive-predicates.ts +43 -0
  425. package/src/store/runtime-clients/attachment-runtime-client.test.ts +41 -0
  426. package/src/store/runtime-clients/attachment-runtime-client.ts +2 -1
  427. package/src/store/runtime-clients/handle-runtime-action.test.ts +40 -0
  428. package/src/store/runtime-clients/handle-runtime-action.ts +14 -0
  429. package/src/store/runtime-clients/handle-thread-list-action.test.ts +69 -0
  430. package/src/store/runtime-clients/handle-thread-list-action.ts +6 -0
  431. package/src/store/runtime-clients/thread-list-item-runtime-client.ts +15 -7
  432. package/src/store/runtime-clients/thread-list-runtime-client.ts +9 -6
  433. package/src/store/scopes/composer.ts +9 -4
  434. package/src/store/scopes/thread-list-item.ts +7 -6
  435. package/src/store/scopes/thread.ts +8 -7
  436. package/src/store/scopes/threads.ts +14 -0
  437. package/src/subscribable/subscribable.test.ts +77 -1
  438. package/src/subscribable/subscribable.ts +38 -23
  439. package/src/tests/MessageRepository.test.ts +48 -0
  440. package/src/tests/RemoteThreadListThreadListRuntimeCore-errors.test.ts +2 -2
  441. package/src/tests/RemoteThreadListThreadListRuntimeCore-loadMore.test.ts +8 -6
  442. package/src/tests/RemoteThreadListThreadListRuntimeCore-switchToThread-unarchive.test.ts +25 -0
  443. package/src/tests/auiV0Encode.test.ts +66 -0
  444. package/src/tests/base-composer-runtime-core-send.test.ts +30 -0
  445. package/src/tests/base-composer-runtime-core.test.ts +28 -0
  446. package/src/tests/composer-can-cancel.test.ts +101 -0
  447. package/src/tests/empty-thread-core.test.ts +6 -0
  448. package/src/tests/external-store-thread-list-runtime-core.test.ts +101 -0
  449. package/src/tests/external-store-thread-runtime-core-adapter.test.ts +211 -1
  450. package/src/tests/external-store-thread-runtime-core.test.ts +124 -0
  451. package/src/tests/external-thread-isEmpty.test.tsx +100 -0
  452. package/src/tests/interactables-toolui-migration.test.tsx +66 -0
  453. package/src/tests/message-queue.test.ts +28 -0
  454. package/src/tests/remote-thread-list-adapter-switch.test.ts +383 -0
  455. package/src/tests/session-reset-notification.test.ts +145 -0
  456. package/src/tests/thread-switch-events.test.tsx +99 -1
  457. package/src/tests/tools-scope-migration.test.tsx +58 -0
  458. package/src/tests/useRemoteThreadListRuntime-controlled.test.tsx +67 -0
  459. package/src/types/message.ts +1 -1
  460. package/src/utils/composite-context-provider.test.ts +139 -0
  461. package/src/utils/composite-context-provider.ts +26 -8
  462. package/src/utils/notify-event-listeners.ts +10 -5
  463. package/src/utils/silent-runtime-action.ts +6 -0
@@ -1,4 +1,4 @@
1
- import { describe, it, expect, beforeEach, vi } from "vitest";
1
+ import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
2
2
  import {
3
3
  ExternalStoreThreadRuntimeCore,
4
4
  hasUpcomingMessage,
@@ -8,6 +8,7 @@ import type { ModelContextProvider } from "../model-context/types";
8
8
  import type { AppendMessage, ThreadMessage } from "../types/message";
9
9
  import { createMessageQueue } from "../runtime/queue/message-queue";
10
10
  import { getThreadMessageText } from "../utils/text";
11
+ import { invalidateThreadRuntime } from "../runtime/utils/thread-runtime-lifecycle";
11
12
 
12
13
  const createContextProvider = (): ModelContextProvider => ({
13
14
  getModelContext: () => ({}),
@@ -49,6 +50,23 @@ const createBaseAdapter = (
49
50
  ...overrides,
50
51
  });
51
52
 
53
+ const captureUnhandledRejections = async (
54
+ run: () => Promise<void>,
55
+ ): Promise<unknown[]> => {
56
+ const rejections: unknown[] = [];
57
+ const onUnhandledRejection = (reason: unknown) => {
58
+ rejections.push(reason);
59
+ };
60
+ process.on("unhandledRejection", onUnhandledRejection);
61
+ try {
62
+ await run();
63
+ await new Promise((resolve) => setImmediate(resolve));
64
+ } finally {
65
+ process.removeListener("unhandledRejection", onUnhandledRejection);
66
+ }
67
+ return rejections;
68
+ };
69
+
52
70
  describe("ExternalStoreThreadRuntimeCore adapter contract", () => {
53
71
  let contextProvider: ModelContextProvider;
54
72
 
@@ -56,6 +74,10 @@ describe("ExternalStoreThreadRuntimeCore adapter contract", () => {
56
74
  contextProvider = createContextProvider();
57
75
  });
58
76
 
77
+ afterEach(() => {
78
+ vi.restoreAllMocks();
79
+ });
80
+
59
81
  it("hasUpcomingMessage is true only while running without an assistant tail", () => {
60
82
  expect(hasUpcomingMessage(true, [createUserMessage("u1")])).toBe(true);
61
83
  expect(hasUpcomingMessage(true, [createAssistantMessage("a1")])).toBe(
@@ -283,6 +305,25 @@ describe("ExternalStoreThreadRuntimeCore adapter contract", () => {
283
305
  expect(texts).not.toContain("partial answer");
284
306
  });
285
307
 
308
+ it("does not resync after the runtime is invalidated", async () => {
309
+ const setMessages = vi.fn();
310
+ const core = new ExternalStoreThreadRuntimeCore(
311
+ contextProvider,
312
+ createBaseAdapter({
313
+ messages: [createAssistantMessage("a1", "partial answer")],
314
+ isRunning: true,
315
+ onCancel: vi.fn(),
316
+ setMessages,
317
+ }),
318
+ );
319
+
320
+ core.cancelRun();
321
+ invalidateThreadRuntime(core);
322
+
323
+ await new Promise((resolve) => setTimeout(resolve, 0));
324
+ expect(setMessages).not.toHaveBeenCalled();
325
+ });
326
+
286
327
  it("re-applies the user leaf rollback when the store updates before the flush", async () => {
287
328
  const messages = [createUserMessage("u1", "cancel me")];
288
329
  const setMessages = vi.fn();
@@ -760,6 +801,175 @@ describe("ExternalStoreThreadRuntimeCore adapter contract", () => {
760
801
  });
761
802
  });
762
803
 
804
+ describe("tool callbacks", () => {
805
+ it("handles rejected automatic tool result callbacks", async () => {
806
+ const error = new Error("tool result failed");
807
+ const consoleError = vi
808
+ .spyOn(console, "error")
809
+ .mockImplementation(() => {});
810
+ const execute = vi.fn(async () => ({ forecast: "sunny" }));
811
+ let callbackCalls = 0;
812
+ const onAddToolResult = () => {
813
+ callbackCalls += 1;
814
+ return Promise.reject(error);
815
+ };
816
+ const core = new ExternalStoreThreadRuntimeCore(
817
+ {
818
+ getModelContext: () => ({
819
+ tools: {
820
+ weatherSearch: {
821
+ parameters: { type: "object", properties: {} },
822
+ execute,
823
+ },
824
+ },
825
+ }),
826
+ },
827
+ createBaseAdapter({
828
+ unstable_enableToolInvocations: true,
829
+ onAddToolResult,
830
+ }),
831
+ );
832
+
833
+ const rejections = await captureUnhandledRejections(async () => {
834
+ core.__internal_setAdapter(
835
+ createBaseAdapter({
836
+ unstable_enableToolInvocations: true,
837
+ isRunning: true,
838
+ messages: [
839
+ {
840
+ ...createAssistantMessage("a1"),
841
+ status: { type: "requires-action", reason: "tool-calls" },
842
+ content: [
843
+ {
844
+ type: "tool-call",
845
+ toolCallId: "tc1",
846
+ toolName: "weatherSearch",
847
+ args: { city: "London" },
848
+ argsText: '{"city":"London"}',
849
+ },
850
+ ],
851
+ },
852
+ ],
853
+ onAddToolResult,
854
+ }),
855
+ );
856
+
857
+ await vi.waitFor(() =>
858
+ expect(consoleError).toHaveBeenCalledWith(
859
+ "[ExternalStoreThreadRuntimeCore] onAddToolResult callback rejected",
860
+ error,
861
+ ),
862
+ );
863
+ });
864
+
865
+ expect(execute).toHaveBeenCalledOnce();
866
+ expect(callbackCalls).toBe(1);
867
+ expect(rejections).toEqual([]);
868
+ });
869
+
870
+ it("handles rejected direct tool result callbacks", async () => {
871
+ const error = new Error("tool result failed");
872
+ const consoleError = vi
873
+ .spyOn(console, "error")
874
+ .mockImplementation(() => {});
875
+ let callbackCalls = 0;
876
+ const core = new ExternalStoreThreadRuntimeCore(
877
+ contextProvider,
878
+ createBaseAdapter({
879
+ onAddToolResult: () => {
880
+ callbackCalls += 1;
881
+ return Promise.reject(error);
882
+ },
883
+ }),
884
+ );
885
+
886
+ const rejections = await captureUnhandledRejections(async () => {
887
+ core.addToolResult({
888
+ messageId: "m1",
889
+ toolName: "weatherSearch",
890
+ toolCallId: "tc1",
891
+ result: { forecast: "sunny" },
892
+ isError: false,
893
+ });
894
+
895
+ await vi.waitFor(() =>
896
+ expect(consoleError).toHaveBeenCalledWith(
897
+ "[ExternalStoreThreadRuntimeCore] onAddToolResult callback rejected",
898
+ error,
899
+ ),
900
+ );
901
+ });
902
+
903
+ expect(callbackCalls).toBe(1);
904
+ expect(rejections).toEqual([]);
905
+ });
906
+
907
+ it("handles rejected onRespondToToolApproval callbacks", async () => {
908
+ const error = new Error("approval failed");
909
+ const consoleError = vi
910
+ .spyOn(console, "error")
911
+ .mockImplementation(() => {});
912
+ let callbackCalls = 0;
913
+ const core = new ExternalStoreThreadRuntimeCore(
914
+ contextProvider,
915
+ createBaseAdapter({
916
+ onRespondToToolApproval: () => {
917
+ callbackCalls += 1;
918
+ return Promise.reject(error);
919
+ },
920
+ }),
921
+ );
922
+
923
+ const rejections = await captureUnhandledRejections(async () => {
924
+ core.respondToToolApproval({
925
+ approvalId: "approval-1",
926
+ approved: true,
927
+ });
928
+
929
+ await vi.waitFor(() =>
930
+ expect(consoleError).toHaveBeenCalledWith(
931
+ "[ExternalStoreThreadRuntimeCore] onRespondToToolApproval callback rejected",
932
+ error,
933
+ ),
934
+ );
935
+ });
936
+
937
+ expect(callbackCalls).toBe(1);
938
+ expect(rejections).toEqual([]);
939
+ });
940
+
941
+ it("handles rejected onCancel callbacks", async () => {
942
+ const error = new Error("cancel failed");
943
+ const consoleError = vi
944
+ .spyOn(console, "error")
945
+ .mockImplementation(() => {});
946
+ let callbackCalls = 0;
947
+ const core = new ExternalStoreThreadRuntimeCore(
948
+ contextProvider,
949
+ createBaseAdapter({
950
+ onCancel: () => {
951
+ callbackCalls += 1;
952
+ return Promise.reject(error);
953
+ },
954
+ }),
955
+ );
956
+
957
+ const rejections = await captureUnhandledRejections(async () => {
958
+ core.cancelRun();
959
+
960
+ await vi.waitFor(() =>
961
+ expect(consoleError).toHaveBeenCalledWith(
962
+ "[ExternalStoreThreadRuntimeCore] onCancel callback rejected",
963
+ error,
964
+ ),
965
+ );
966
+ });
967
+
968
+ expect(callbackCalls).toBe(1);
969
+ expect(rejections).toEqual([]);
970
+ });
971
+ });
972
+
763
973
  describe("messageRepository incremental sync", () => {
764
974
  const u1 = createUserMessage("u1");
765
975
  const a1 = createAssistantMessage("a1");
@@ -4,6 +4,7 @@ import type { ExternalStoreAdapter } from "../runtimes/external-store/external-s
4
4
  import type { ModelContextProvider } from "../model-context/types";
5
5
  import type { ThreadMessageLike } from "../runtime/utils/thread-message-like";
6
6
  import type { AppendMessage } from "../types/message";
7
+ import { invalidateThreadRuntime } from "../runtime/utils/thread-runtime-lifecycle";
7
8
 
8
9
  const mockContextProvider: ModelContextProvider = {
9
10
  getModelContext: () => ({}),
@@ -868,6 +869,129 @@ describe("ExternalStoreThreadRuntimeCore - message queue", () => {
868
869
  expect(withoutQueue.capabilities.queue).toBe(false);
869
870
  });
870
871
 
872
+ it("waits for thread initialization before enqueueing into the queue adapter", async () => {
873
+ let resolveInitialization!: () => void;
874
+ const initialization = new Promise<void>((resolve) => {
875
+ resolveInitialization = resolve;
876
+ });
877
+ const queue = makeQueue();
878
+ const onNew = vi.fn(async () => {});
879
+ const runtime = new ExternalStoreThreadRuntimeCore(
880
+ mockContextProvider,
881
+ makeStore({ onNew, queue }),
882
+ );
883
+ runtime.__internal_setGetInitializePromise(() => initialization);
884
+
885
+ const appendPromise = runtime.append(appendMessage());
886
+ await Promise.resolve();
887
+
888
+ expect(queue.enqueue).not.toHaveBeenCalled();
889
+
890
+ resolveInitialization();
891
+ await appendPromise;
892
+
893
+ expect(queue.enqueue).toHaveBeenCalledTimes(1);
894
+ expect(onNew).not.toHaveBeenCalled();
895
+ });
896
+
897
+ it("does not enqueue when the thread is invalidated during initialization", async () => {
898
+ let resolveInitialization!: () => void;
899
+ const initialization = new Promise<void>((resolve) => {
900
+ resolveInitialization = resolve;
901
+ });
902
+ const queue = makeQueue();
903
+ const runtime = new ExternalStoreThreadRuntimeCore(
904
+ mockContextProvider,
905
+ makeStore({ onNew: vi.fn(), queue }),
906
+ );
907
+ runtime.__internal_setGetInitializePromise(() => initialization);
908
+
909
+ const appendPromise = runtime.append(appendMessage());
910
+ await Promise.resolve();
911
+ invalidateThreadRuntime(runtime);
912
+ resolveInitialization();
913
+
914
+ await appendPromise;
915
+ expect(queue.enqueue).not.toHaveBeenCalled();
916
+ expect(queue.steer).not.toHaveBeenCalled();
917
+ });
918
+
919
+ it("dispatches an append without waiting for thread initialization", async () => {
920
+ const initialization = new Promise<void>(() => {});
921
+ const getInitializePromise = vi.fn(() => initialization);
922
+ const onNew = vi.fn(async () => {});
923
+ const runtime = new ExternalStoreThreadRuntimeCore(
924
+ mockContextProvider,
925
+ makeStore({ onNew }),
926
+ );
927
+ runtime.__internal_setGetInitializePromise(getInitializePromise);
928
+
929
+ await runtime.append(appendMessage());
930
+
931
+ expect(onNew).toHaveBeenCalledTimes(1);
932
+ expect(getInitializePromise).toHaveBeenCalledTimes(1);
933
+ });
934
+
935
+ it("dispatches concurrent appends without waiting for initialization", async () => {
936
+ const initialization = new Promise<void>(() => {});
937
+ const onNew = vi.fn(async () => {});
938
+ const runtime = new ExternalStoreThreadRuntimeCore(
939
+ mockContextProvider,
940
+ makeStore({ onNew }),
941
+ );
942
+ runtime.__internal_setGetInitializePromise(() => initialization);
943
+
944
+ await Promise.all([
945
+ runtime.append(appendMessage()),
946
+ runtime.append(appendMessage()),
947
+ ]);
948
+
949
+ expect(onNew).toHaveBeenCalledTimes(2);
950
+ });
951
+
952
+ it("does not fail the append when thread initialization rejects", async () => {
953
+ const initialization = Promise.reject(new Error("initialization failed"));
954
+ const onNew = vi.fn(async () => {});
955
+ const runtime = new ExternalStoreThreadRuntimeCore(
956
+ mockContextProvider,
957
+ makeStore({ onNew }),
958
+ );
959
+ runtime.__internal_setGetInitializePromise(() => initialization);
960
+
961
+ await runtime.append(appendMessage());
962
+
963
+ expect(onNew).toHaveBeenCalledTimes(1);
964
+ });
965
+
966
+ it("drops an append disposed while aborting client-side tools", async () => {
967
+ let resolveAbort!: () => void;
968
+ const abortPromise = new Promise<void>((resolve) => {
969
+ resolveAbort = resolve;
970
+ });
971
+ const onNew = vi.fn(async () => {});
972
+ const runtime = new ExternalStoreThreadRuntimeCore(
973
+ mockContextProvider,
974
+ makeStore({ onNew }),
975
+ );
976
+ runtime.__internal_setGetInitializePromise(() => Promise.resolve());
977
+ const abort = vi.fn(() => abortPromise);
978
+ (
979
+ runtime as unknown as { _toolInvocations: { abort: typeof abort } }
980
+ )._toolInvocations = {
981
+ abort,
982
+ };
983
+
984
+ const appendPromise = runtime.append(appendMessage());
985
+ await Promise.resolve();
986
+ expect(abort).toHaveBeenCalledOnce();
987
+
988
+ invalidateThreadRuntime(runtime);
989
+ resolveAbort();
990
+
991
+ await appendPromise;
992
+ expect(onNew).not.toHaveBeenCalled();
993
+ });
994
+
871
995
  it("routes a tail append through the queue adapter instead of onNew", async () => {
872
996
  const queue = makeQueue();
873
997
  const onNew = vi.fn();
@@ -0,0 +1,100 @@
1
+ // @vitest-environment jsdom
2
+
3
+ import { render } from "@testing-library/react";
4
+ import type { FC } from "react";
5
+ import { describe, it, expect } from "vitest";
6
+ import { AuiIf, useAui, AuiProvider } from "@assistant-ui/store";
7
+ import {
8
+ ExternalThread,
9
+ type ExternalThreadProps,
10
+ } from "../store/clients/external-thread";
11
+ import { useThreadIsEmpty } from "../react/primitive-hooks/useThreadIsEmpty";
12
+
13
+ const HookProbe: FC = () => (
14
+ <div data-testid="hook">{useThreadIsEmpty() ? "empty" : "not-empty"}</div>
15
+ );
16
+
17
+ const renderThread = (props: ExternalThreadProps) => {
18
+ const captured: { aui?: ReturnType<typeof useAui> } = {};
19
+ const Capture: FC = () => {
20
+ captured.aui = useAui();
21
+ return null;
22
+ };
23
+ const App: FC<{ threadProps: ExternalThreadProps }> = ({ threadProps }) => {
24
+ const aui = useAui({ thread: ExternalThread(threadProps) });
25
+ return (
26
+ <AuiProvider value={aui}>
27
+ <Capture />
28
+ <HookProbe />
29
+ <AuiIf condition={(s) => s.thread.isEmpty}>
30
+ <div data-testid="aui-if">empty</div>
31
+ </AuiIf>
32
+ </AuiProvider>
33
+ );
34
+ };
35
+ const utils = render(<App threadProps={props} />);
36
+ return {
37
+ state: () => captured.aui!.thread.getState(),
38
+ hookSaysEmpty: () => utils.getByTestId("hook").textContent === "empty",
39
+ auiIfRendered: () => utils.queryByTestId("aui-if") !== null,
40
+ rerender: (next: ExternalThreadProps) =>
41
+ utils.rerender(<App threadProps={next} />),
42
+ };
43
+ };
44
+
45
+ const userMessage = (id: string) =>
46
+ ({
47
+ id,
48
+ role: "user",
49
+ content: [{ type: "text", text: "hi" }],
50
+ createdAt: new Date(0),
51
+ metadata: { custom: {} },
52
+ }) as unknown as ExternalThreadProps["messages"][number];
53
+
54
+ describe("ExternalThread isEmpty", () => {
55
+ it("is empty when there are no messages and nothing is loading", () => {
56
+ const t = renderThread({ messages: [] });
57
+ expect(t.state().isEmpty).toBe(true);
58
+ expect(t.hookSaysEmpty()).toBe(true);
59
+ expect(t.auiIfRendered()).toBe(true);
60
+ });
61
+
62
+ it("is not empty while the adapter is still loading", () => {
63
+ const t = renderThread({ messages: [], isLoading: true });
64
+ expect(t.state().isEmpty).toBe(false);
65
+ });
66
+
67
+ it("does not render empty-state consumers while loading", () => {
68
+ const t = renderThread({ messages: [], isLoading: true });
69
+ expect(t.hookSaysEmpty()).toBe(false);
70
+ expect(t.auiIfRendered()).toBe(false);
71
+ });
72
+
73
+ it("is not empty once messages arrive", () => {
74
+ const t = renderThread({ messages: [userMessage("m1")] });
75
+ expect(t.state().isEmpty).toBe(false);
76
+ });
77
+
78
+ it("becomes empty when loading finishes with no messages", () => {
79
+ const t = renderThread({ messages: [], isLoading: true });
80
+ expect(t.state().isEmpty).toBe(false);
81
+ expect(t.auiIfRendered()).toBe(false);
82
+
83
+ t.rerender({ messages: [], isLoading: false });
84
+
85
+ expect(t.state().isEmpty).toBe(true);
86
+ expect(t.hookSaysEmpty()).toBe(true);
87
+ expect(t.auiIfRendered()).toBe(true);
88
+ });
89
+
90
+ it("stays non-empty when loading finishes with messages", () => {
91
+ const t = renderThread({ messages: [], isLoading: true });
92
+ expect(t.state().isEmpty).toBe(false);
93
+
94
+ t.rerender({ messages: [userMessage("m1")], isLoading: false });
95
+
96
+ expect(t.state().isEmpty).toBe(false);
97
+ expect(t.hookSaysEmpty()).toBe(false);
98
+ expect(t.auiIfRendered()).toBe(false);
99
+ });
100
+ });
@@ -0,0 +1,66 @@
1
+ // @vitest-environment jsdom
2
+
3
+ import { act, cleanup, render } from "@testing-library/react";
4
+ import { afterEach, describe, expect, it, vi } from "vitest";
5
+ import { withKey } from "@assistant-ui/tap";
6
+ import { useAui } from "@assistant-ui/store";
7
+ import { Tools } from "../react/client/Tools";
8
+ import { unstable_Interactables } from "../react/client/Interactables";
9
+
10
+ type AnyClient = Record<string, any>;
11
+
12
+ afterEach(() => {
13
+ cleanup();
14
+ });
15
+
16
+ describe("interactables update-tool UI registration", () => {
17
+ it("migrates to a structurally replaced tools scope", async () => {
18
+ let aui!: AnyClient;
19
+ const Harness = ({ generation }: { generation: number }) => {
20
+ aui = useAui({
21
+ tools: withKey(String(generation), Tools({})),
22
+ unstable_interactables: unstable_Interactables({}),
23
+ } as never);
24
+ return null;
25
+ };
26
+ const view = render(<Harness generation={0} />);
27
+
28
+ const toolUIs = () =>
29
+ (aui.tools().getState().toolUIs ?? {}) as Record<string, unknown[]>;
30
+ // setToolUI lands after the tap scheduler drains its macrotask
31
+ await act(async () => {
32
+ aui.unstable_interactables.register({
33
+ id: "call-1",
34
+ name: "note",
35
+ description: "a note",
36
+ stateSchema: { type: "object", properties: {} },
37
+ initialState: {},
38
+ updateRender: () => null,
39
+ });
40
+ await vi.waitFor(() => expect(Object.keys(toolUIs())).toHaveLength(1));
41
+ });
42
+ const [toolName] = Object.keys(toolUIs());
43
+ const firstRegistration = toolUIs()[toolName!]![0];
44
+
45
+ // A rerender inside an outer act would not land until that act exits,
46
+ // so the swap happens first and only the scheduler wait is wrapped
47
+ view.rerender(<Harness generation={1} />);
48
+
49
+ // The remounted tools scope starts from fresh state; a registration
50
+ // object distinct from the pre-swap one proves the retained entry was
51
+ // re-applied on the replacement instance rather than read stale. It
52
+ // lands one scheduler macrotask after the swap, once the tap scheduler
53
+ // drains.
54
+ await act(async () => {
55
+ await vi.waitFor(() => {
56
+ const registration = toolUIs()[toolName!]?.[0];
57
+ expect(registration).toBeDefined();
58
+ expect(registration).not.toBe(firstRegistration);
59
+ });
60
+ });
61
+
62
+ // Post-settle cardinality: a duplicate re-apply would leave a second
63
+ // registration whose disposer was dropped
64
+ expect(toolUIs()[toolName!]).toHaveLength(1);
65
+ });
66
+ });
@@ -612,6 +612,34 @@ describe("createMessageQueue", () => {
612
612
  expect(cb).toHaveBeenCalled();
613
613
  });
614
614
 
615
+ it("isolates subscriber errors while enqueueing", () => {
616
+ const run = vi.fn();
617
+ const { adapter, subscribe } = createMessageQueue({ run });
618
+ const error = new Error("subscriber failed");
619
+ const laterSubscriber = vi.fn();
620
+ const consoleError = vi
621
+ .spyOn(console, "error")
622
+ .mockImplementation(() => {});
623
+
624
+ subscribe(() => {
625
+ throw error;
626
+ });
627
+ subscribe(laterSubscriber);
628
+
629
+ try {
630
+ expect(() => adapter.enqueue(msg("a"), { steer: false })).not.toThrow();
631
+ expect(run).toHaveBeenCalledTimes(1);
632
+ expect(adapter.items).toHaveLength(0);
633
+ expect(laterSubscriber).toHaveBeenCalledTimes(2);
634
+ expect(consoleError).toHaveBeenCalledWith(
635
+ "[assistant-ui] Message queue listener threw an error",
636
+ error,
637
+ );
638
+ } finally {
639
+ consoleError.mockRestore();
640
+ }
641
+ });
642
+
615
643
  it("buffers when a run started outside the queue is marked busy", () => {
616
644
  const run = vi.fn();
617
645
  const { adapter, notifyBusy, notifyIdle } = createMessageQueue({ run });