@assistant-ui/core 0.3.12 → 0.3.14

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 (452) 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 +27 -15
  8. package/dist/adapters/voice.js.map +1 -1
  9. package/dist/index.d.ts +3 -3
  10. package/dist/index.js +2 -2
  11. package/dist/index.js.map +1 -1
  12. package/dist/internal.d.ts +1 -1
  13. package/dist/internal.js +6 -6
  14. package/dist/model-context/frame/host.d.ts.map +1 -1
  15. package/dist/model-context/frame/host.js +2 -1
  16. package/dist/model-context/frame/host.js.map +1 -1
  17. package/dist/model-context/registry.d.ts.map +1 -1
  18. package/dist/model-context/registry.js +16 -4
  19. package/dist/model-context/registry.js.map +1 -1
  20. package/dist/react/RuntimeAdapter.d.ts +8 -1
  21. package/dist/react/RuntimeAdapter.d.ts.map +1 -1
  22. package/dist/react/RuntimeAdapter.js +23 -18
  23. package/dist/react/RuntimeAdapter.js.map +1 -1
  24. package/dist/react/adapters/LocalStorageThreadListAdapter.d.ts.map +1 -1
  25. package/dist/react/adapters/LocalStorageThreadListAdapter.js +28 -12
  26. package/dist/react/adapters/LocalStorageThreadListAdapter.js.map +1 -1
  27. package/dist/react/client/AdaptedRemoteThread.d.ts +11 -0
  28. package/dist/react/client/AdaptedRemoteThread.d.ts.map +1 -0
  29. package/dist/react/client/AdaptedRemoteThread.js +27 -0
  30. package/dist/react/client/AdaptedRemoteThread.js.map +1 -0
  31. package/dist/react/client/InMemoryThreadList.d.ts +19 -0
  32. package/dist/react/client/InMemoryThreadList.d.ts.map +1 -0
  33. package/dist/react/client/InMemoryThreadList.js +418 -0
  34. package/dist/react/client/InMemoryThreadList.js.map +1 -0
  35. package/dist/react/client/Interactables.d.ts.map +1 -1
  36. package/dist/react/client/Interactables.js +159 -102
  37. package/dist/react/client/Interactables.js.map +1 -1
  38. package/dist/react/client/RemoteThreadList.d.ts +34 -0
  39. package/dist/react/client/RemoteThreadList.d.ts.map +1 -0
  40. package/dist/react/client/RemoteThreadList.js +826 -0
  41. package/dist/react/client/RemoteThreadList.js.map +1 -0
  42. package/dist/react/client/Tools.d.ts.map +1 -1
  43. package/dist/react/client/Tools.js +38 -27
  44. package/dist/react/client/Tools.js.map +1 -1
  45. package/dist/react/client/interactable-model-context.d.ts.map +1 -1
  46. package/dist/react/client/interactable-model-context.js +5 -1
  47. package/dist/react/client/interactable-model-context.js.map +1 -1
  48. package/dist/react/index.d.ts +7 -2
  49. package/dist/react/index.js +5 -2
  50. package/dist/react/interactables-legacy/Interactables.d.ts.map +1 -1
  51. package/dist/react/interactables-legacy/Interactables.js +145 -110
  52. package/dist/react/interactables-legacy/Interactables.js.map +1 -1
  53. package/dist/react/primitive-hooks/useActionBarCopy.d.ts.map +1 -1
  54. package/dist/react/primitive-hooks/useActionBarCopy.js +13 -18
  55. package/dist/react/primitive-hooks/useActionBarCopy.js.map +1 -1
  56. package/dist/react/primitive-hooks/useActionBarEdit.d.ts.map +1 -1
  57. package/dist/react/primitive-hooks/useActionBarEdit.js +2 -4
  58. package/dist/react/primitive-hooks/useActionBarEdit.js.map +1 -1
  59. package/dist/react/primitive-hooks/useActionBarReload.d.ts.map +1 -1
  60. package/dist/react/primitive-hooks/useActionBarReload.js +2 -4
  61. package/dist/react/primitive-hooks/useActionBarReload.js.map +1 -1
  62. package/dist/react/primitive-hooks/useBranchPickerNext.d.ts.map +1 -1
  63. package/dist/react/primitive-hooks/useBranchPickerNext.js +2 -6
  64. package/dist/react/primitive-hooks/useBranchPickerNext.js.map +1 -1
  65. package/dist/react/primitive-hooks/useBranchPickerPrevious.d.ts.map +1 -1
  66. package/dist/react/primitive-hooks/useBranchPickerPrevious.js +2 -6
  67. package/dist/react/primitive-hooks/useBranchPickerPrevious.js.map +1 -1
  68. package/dist/react/primitive-hooks/useComposerCancel.d.ts.map +1 -1
  69. package/dist/react/primitive-hooks/useComposerCancel.js +2 -4
  70. package/dist/react/primitive-hooks/useComposerCancel.js.map +1 -1
  71. package/dist/react/primitive-hooks/useComposerSend.d.ts.map +1 -1
  72. package/dist/react/primitive-hooks/useComposerSend.js +2 -4
  73. package/dist/react/primitive-hooks/useComposerSend.js.map +1 -1
  74. package/dist/react/primitive-hooks/useSuggestionTrigger.d.ts.map +1 -1
  75. package/dist/react/primitive-hooks/useSuggestionTrigger.js +6 -2
  76. package/dist/react/primitive-hooks/useSuggestionTrigger.js.map +1 -1
  77. package/dist/react/primitives/message/MessageParts.d.ts +13 -0
  78. package/dist/react/primitives/message/MessageParts.d.ts.map +1 -1
  79. package/dist/react/primitives/message/MessageParts.js.map +1 -1
  80. package/dist/react/primitives/thread/ThreadMessages.d.ts.map +1 -1
  81. package/dist/react/primitives/thread/ThreadMessages.js +1 -1
  82. package/dist/react/primitives/thread/ThreadMessages.js.map +1 -1
  83. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts +22 -10
  84. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts.map +1 -1
  85. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js +109 -71
  86. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js.map +1 -1
  87. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts +8 -2
  88. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts.map +1 -1
  89. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js +40 -13
  90. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js.map +1 -1
  91. package/dist/react/runtimes/RemoteThreadResource.d.ts +30 -0
  92. package/dist/react/runtimes/RemoteThreadResource.d.ts.map +1 -0
  93. package/dist/react/runtimes/RemoteThreadResource.js +134 -0
  94. package/dist/react/runtimes/RemoteThreadResource.js.map +1 -0
  95. package/dist/react/runtimes/RuntimeAdapterProvider.d.ts +3 -10
  96. package/dist/react/runtimes/RuntimeAdapterProvider.d.ts.map +1 -1
  97. package/dist/react/runtimes/RuntimeAdapterProvider.js +3 -6
  98. package/dist/react/runtimes/RuntimeAdapterProvider.js.map +1 -1
  99. package/dist/react/runtimes/assistant-transport/commandQueue.d.ts +17 -0
  100. package/dist/react/runtimes/assistant-transport/commandQueue.d.ts.map +1 -0
  101. package/dist/react/runtimes/assistant-transport/commandQueue.js +55 -0
  102. package/dist/react/runtimes/assistant-transport/commandQueue.js.map +1 -0
  103. package/dist/react/runtimes/assistant-transport/replayBoundaryStream.d.ts +11 -0
  104. package/dist/react/runtimes/assistant-transport/replayBoundaryStream.d.ts.map +1 -0
  105. package/dist/react/runtimes/assistant-transport/replayBoundaryStream.js +165 -0
  106. package/dist/react/runtimes/assistant-transport/replayBoundaryStream.js.map +1 -0
  107. package/dist/react/runtimes/assistant-transport/runManager.d.ts +15 -0
  108. package/dist/react/runtimes/assistant-transport/runManager.d.ts.map +1 -0
  109. package/dist/react/runtimes/assistant-transport/runManager.js +86 -0
  110. package/dist/react/runtimes/assistant-transport/runManager.js.map +1 -0
  111. package/dist/react/runtimes/assistant-transport/types.d.ts +130 -0
  112. package/dist/react/runtimes/assistant-transport/types.d.ts.map +1 -0
  113. package/dist/react/runtimes/assistant-transport/types.js +0 -0
  114. package/dist/react/runtimes/assistant-transport/useAssistantTransportRuntime.d.ts +14 -0
  115. package/dist/react/runtimes/assistant-transport/useAssistantTransportRuntime.d.ts.map +1 -0
  116. package/dist/react/runtimes/assistant-transport/useAssistantTransportRuntime.js +296 -0
  117. package/dist/react/runtimes/assistant-transport/useAssistantTransportRuntime.js.map +1 -0
  118. package/dist/react/runtimes/assistant-transport/useConvertedState.d.ts +7 -0
  119. package/dist/react/runtimes/assistant-transport/useConvertedState.d.ts.map +1 -0
  120. package/dist/react/runtimes/assistant-transport/useConvertedState.js +25 -0
  121. package/dist/react/runtimes/assistant-transport/useConvertedState.js.map +1 -0
  122. package/dist/react/runtimes/assistant-transport/useLatestRef.d.ts +7 -0
  123. package/dist/react/runtimes/assistant-transport/useLatestRef.d.ts.map +1 -0
  124. package/dist/react/runtimes/assistant-transport/useLatestRef.js +27 -0
  125. package/dist/react/runtimes/assistant-transport/useLatestRef.js.map +1 -0
  126. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts.map +1 -1
  127. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js +39 -13
  128. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js.map +1 -1
  129. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.d.ts +2 -1
  130. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.d.ts.map +1 -1
  131. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.js +3 -3
  132. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.js.map +1 -1
  133. package/dist/react/runtimes/cloud/auiV0.d.ts +4 -0
  134. package/dist/react/runtimes/cloud/auiV0.d.ts.map +1 -1
  135. package/dist/react/runtimes/cloud/auiV0.js +7 -0
  136. package/dist/react/runtimes/cloud/auiV0.js.map +1 -1
  137. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.d.ts.map +1 -1
  138. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js +22 -12
  139. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js.map +1 -1
  140. package/dist/react/runtimes/cloud/useCloudThreadListRuntime.d.ts +16 -0
  141. package/dist/react/runtimes/cloud/useCloudThreadListRuntime.d.ts.map +1 -0
  142. package/dist/react/runtimes/cloud/useCloudThreadListRuntime.js +36 -0
  143. package/dist/react/runtimes/cloud/useCloudThreadListRuntime.js.map +1 -0
  144. package/dist/react/runtimes/external-message-converter.js +14 -14
  145. package/dist/react/runtimes/external-message-converter.js.map +1 -1
  146. package/dist/react/runtimes/useExternalStoreRuntime.d.ts.map +1 -1
  147. package/dist/react/runtimes/useExternalStoreRuntime.js +44 -28
  148. package/dist/react/runtimes/useExternalStoreRuntime.js.map +1 -1
  149. package/dist/react/runtimes/useExternalStoreSharedOptions.js.map +1 -1
  150. package/dist/react/runtimes/useLocalRuntime.js +1 -1
  151. package/dist/react/runtimes/useRuntimeAdapters.d.ts +9 -0
  152. package/dist/react/runtimes/useRuntimeAdapters.d.ts.map +1 -0
  153. package/dist/react/runtimes/useRuntimeAdapters.js +20 -0
  154. package/dist/react/runtimes/useRuntimeAdapters.js.map +1 -0
  155. package/dist/runtime/api/composer-runtime.d.ts +5 -0
  156. package/dist/runtime/api/composer-runtime.d.ts.map +1 -1
  157. package/dist/runtime/api/composer-runtime.js.map +1 -1
  158. package/dist/runtime/api/message-runtime.js +1 -1
  159. package/dist/runtime/api/thread-list-runtime.d.ts +1 -0
  160. package/dist/runtime/api/thread-list-runtime.d.ts.map +1 -1
  161. package/dist/runtime/api/thread-list-runtime.js +4 -2
  162. package/dist/runtime/api/thread-list-runtime.js.map +1 -1
  163. package/dist/runtime/api/thread-runtime.d.ts +12 -2
  164. package/dist/runtime/api/thread-runtime.d.ts.map +1 -1
  165. package/dist/runtime/api/thread-runtime.js +13 -3
  166. package/dist/runtime/api/thread-runtime.js.map +1 -1
  167. package/dist/runtime/base/base-composer-runtime-core.d.ts +25 -0
  168. package/dist/runtime/base/base-composer-runtime-core.d.ts.map +1 -1
  169. package/dist/runtime/base/base-composer-runtime-core.js +72 -18
  170. package/dist/runtime/base/base-composer-runtime-core.js.map +1 -1
  171. package/dist/runtime/base/base-thread-runtime-core.d.ts +15 -0
  172. package/dist/runtime/base/base-thread-runtime-core.d.ts.map +1 -1
  173. package/dist/runtime/base/base-thread-runtime-core.js +34 -3
  174. package/dist/runtime/base/base-thread-runtime-core.js.map +1 -1
  175. package/dist/runtime/base/default-edit-composer-runtime-core.d.ts.map +1 -1
  176. package/dist/runtime/base/default-edit-composer-runtime-core.js +1 -6
  177. package/dist/runtime/base/default-edit-composer-runtime-core.js.map +1 -1
  178. package/dist/runtime/base/default-thread-composer-runtime-core.d.ts +0 -1
  179. package/dist/runtime/base/default-thread-composer-runtime-core.d.ts.map +1 -1
  180. package/dist/runtime/base/default-thread-composer-runtime-core.js +11 -8
  181. package/dist/runtime/base/default-thread-composer-runtime-core.js.map +1 -1
  182. package/dist/runtime/interfaces/thread-runtime-core.d.ts +6 -0
  183. package/dist/runtime/interfaces/thread-runtime-core.d.ts.map +1 -1
  184. package/dist/runtime/internal.js +5 -5
  185. package/dist/runtime/queue/external-thread-queue-adapter.d.ts +15 -0
  186. package/dist/runtime/queue/external-thread-queue-adapter.d.ts.map +1 -1
  187. package/dist/runtime/queue/message-queue.d.ts.map +1 -1
  188. package/dist/runtime/queue/message-queue.js +25 -11
  189. package/dist/runtime/queue/message-queue.js.map +1 -1
  190. package/dist/runtime/utils/thread-runtime-lifecycle.d.ts +8 -0
  191. package/dist/runtime/utils/thread-runtime-lifecycle.d.ts.map +1 -0
  192. package/dist/runtime/utils/thread-runtime-lifecycle.js +11 -0
  193. package/dist/runtime/utils/thread-runtime-lifecycle.js.map +1 -0
  194. package/dist/runtimes/external-store/external-store-adapter.d.ts +7 -0
  195. package/dist/runtimes/external-store/external-store-adapter.d.ts.map +1 -1
  196. package/dist/runtimes/external-store/external-store-shared-options.js.map +1 -1
  197. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.d.ts.map +1 -1
  198. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js +4 -1
  199. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js.map +1 -1
  200. package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts +11 -1
  201. package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts.map +1 -1
  202. package/dist/runtimes/external-store/external-store-thread-runtime-core.js +78 -20
  203. package/dist/runtimes/external-store/external-store-thread-runtime-core.js.map +1 -1
  204. package/dist/runtimes/internal.d.ts +1 -1
  205. package/dist/runtimes/local/local-thread-runtime-core.d.ts +3 -0
  206. package/dist/runtimes/local/local-thread-runtime-core.d.ts.map +1 -1
  207. package/dist/runtimes/local/local-thread-runtime-core.js +55 -14
  208. package/dist/runtimes/local/local-thread-runtime-core.js.map +1 -1
  209. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.d.ts +1 -0
  210. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.d.ts.map +1 -1
  211. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.js +3 -0
  212. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.js.map +1 -1
  213. package/dist/runtimes/remote-thread-list/empty-thread-core.js +3 -0
  214. package/dist/runtimes/remote-thread-list/empty-thread-core.js.map +1 -1
  215. package/dist/runtimes/remote-thread-list/types.d.ts +29 -1
  216. package/dist/runtimes/remote-thread-list/types.d.ts.map +1 -1
  217. package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts +1 -12
  218. package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts.map +1 -1
  219. package/dist/runtimes/tool-invocations/ToolInvocationTracker.js +67 -38
  220. package/dist/runtimes/tool-invocations/ToolInvocationTracker.js.map +1 -1
  221. package/dist/store/clients/external-thread.d.ts +7 -0
  222. package/dist/store/clients/external-thread.d.ts.map +1 -1
  223. package/dist/store/clients/external-thread.js +460 -369
  224. package/dist/store/clients/external-thread.js.map +1 -1
  225. package/dist/store/clients/runtime-adapter.d.ts.map +1 -1
  226. package/dist/store/clients/runtime-adapter.js +5 -2
  227. package/dist/store/clients/runtime-adapter.js.map +1 -1
  228. package/dist/store/clients/single-thread-list.d.ts.map +1 -1
  229. package/dist/store/clients/single-thread-list.js +31 -27
  230. package/dist/store/clients/single-thread-list.js.map +1 -1
  231. package/dist/store/clients/suggestions.d.ts +3 -1
  232. package/dist/store/clients/suggestions.d.ts.map +1 -1
  233. package/dist/store/clients/suggestions.js +65 -37
  234. package/dist/store/clients/suggestions.js.map +1 -1
  235. package/dist/store/clients/thread-selection-events.d.ts +10 -0
  236. package/dist/store/clients/thread-selection-events.d.ts.map +1 -0
  237. package/dist/store/clients/thread-selection-events.js +40 -0
  238. package/dist/store/clients/thread-selection-events.js.map +1 -0
  239. package/dist/store/env.d.ts +5 -0
  240. package/dist/store/env.d.ts.map +1 -0
  241. package/dist/store/env.js +12 -0
  242. package/dist/store/env.js.map +1 -0
  243. package/dist/store/index.d.ts +6 -4
  244. package/dist/store/index.js +5 -3
  245. package/dist/store/internal.d.ts +4 -1
  246. package/dist/store/internal.js +4 -1
  247. package/dist/store/primitive-predicates.d.ts +19 -0
  248. package/dist/store/primitive-predicates.d.ts.map +1 -0
  249. package/dist/store/primitive-predicates.js +19 -0
  250. package/dist/store/primitive-predicates.js.map +1 -0
  251. package/dist/store/runtime-clients/attachment-runtime-client.d.ts.map +1 -1
  252. package/dist/store/runtime-clients/attachment-runtime-client.js +18 -11
  253. package/dist/store/runtime-clients/attachment-runtime-client.js.map +1 -1
  254. package/dist/store/runtime-clients/handle-runtime-action.d.ts +5 -0
  255. package/dist/store/runtime-clients/handle-runtime-action.d.ts.map +1 -0
  256. package/dist/store/runtime-clients/handle-runtime-action.js +12 -0
  257. package/dist/store/runtime-clients/handle-runtime-action.js.map +1 -0
  258. package/dist/store/runtime-clients/handle-thread-list-action.d.ts +5 -0
  259. package/dist/store/runtime-clients/handle-thread-list-action.d.ts.map +1 -0
  260. package/dist/store/runtime-clients/handle-thread-list-action.js +7 -0
  261. package/dist/store/runtime-clients/handle-thread-list-action.js.map +1 -0
  262. package/dist/store/runtime-clients/thread-list-item-runtime-client.d.ts.map +1 -1
  263. package/dist/store/runtime-clients/thread-list-item-runtime-client.js +104 -57
  264. package/dist/store/runtime-clients/thread-list-item-runtime-client.js.map +1 -1
  265. package/dist/store/runtime-clients/thread-list-runtime-client.d.ts.map +1 -1
  266. package/dist/store/runtime-clients/thread-list-runtime-client.js +5 -6
  267. package/dist/store/runtime-clients/thread-list-runtime-client.js.map +1 -1
  268. package/dist/store/runtime-clients/thread-runtime-client.d.ts.map +1 -1
  269. package/dist/store/runtime-clients/thread-runtime-client.js +98 -82
  270. package/dist/store/runtime-clients/thread-runtime-client.js.map +1 -1
  271. package/dist/store/scope-registration.d.ts +2 -2
  272. package/dist/store/scopes/composer.d.ts +9 -4
  273. package/dist/store/scopes/composer.d.ts.map +1 -1
  274. package/dist/store/scopes/suggestions.d.ts +6 -1
  275. package/dist/store/scopes/suggestions.d.ts.map +1 -1
  276. package/dist/store/scopes/thread-list-item.d.ts +7 -6
  277. package/dist/store/scopes/thread-list-item.d.ts.map +1 -1
  278. package/dist/store/scopes/thread.d.ts +25 -7
  279. package/dist/store/scopes/thread.d.ts.map +1 -1
  280. package/dist/store/scopes/threads.d.ts +17 -1
  281. package/dist/store/scopes/threads.d.ts.map +1 -1
  282. package/dist/subscribable/subscribable.d.ts +2 -1
  283. package/dist/subscribable/subscribable.d.ts.map +1 -1
  284. package/dist/subscribable/subscribable.js +23 -18
  285. package/dist/subscribable/subscribable.js.map +1 -1
  286. package/dist/types/error.d.ts +15 -1
  287. package/dist/types/error.d.ts.map +1 -1
  288. package/dist/types/error.js +18 -1
  289. package/dist/types/error.js.map +1 -1
  290. package/dist/types/message.d.ts +2 -0
  291. package/dist/types/message.d.ts.map +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/package.json +7 -7
  302. package/src/adapters/speech.test.ts +118 -1
  303. package/src/adapters/speech.ts +21 -22
  304. package/src/adapters/thread-history.ts +2 -0
  305. package/src/adapters/voice.test.ts +69 -0
  306. package/src/adapters/voice.ts +27 -27
  307. package/src/index.ts +2 -0
  308. package/src/model-context/frame/host.test.ts +23 -0
  309. package/src/model-context/frame/host.ts +2 -1
  310. package/src/model-context/registry.test.ts +131 -0
  311. package/src/model-context/registry.ts +16 -6
  312. package/src/react/RuntimeAdapter.test.ts +2 -0
  313. package/src/react/RuntimeAdapter.ts +20 -8
  314. package/src/react/adapters/LocalStorageThreadListAdapter.tsx +34 -17
  315. package/src/react/client/AdaptedRemoteThread.ts +41 -0
  316. package/src/react/client/InMemoryThreadList.test.tsx +148 -0
  317. package/src/react/client/InMemoryThreadList.ts +290 -0
  318. package/src/react/client/Interactables.test.ts +326 -2
  319. package/src/react/client/Interactables.ts +227 -110
  320. package/src/react/client/RemoteThreadList.test.ts +1026 -0
  321. package/src/react/client/RemoteThreadList.ts +1067 -0
  322. package/src/react/client/Tools.ts +36 -29
  323. package/src/react/client/interactable-model-context.ts +6 -1
  324. package/src/react/index.ts +13 -0
  325. package/src/react/interactables-legacy/Interactables.test.ts +317 -0
  326. package/src/react/interactables-legacy/Interactables.ts +204 -128
  327. package/src/react/primitive-hooks/useActionBarCopy.ts +2 -7
  328. package/src/react/primitive-hooks/useActionBarEdit.ts +2 -1
  329. package/src/react/primitive-hooks/useActionBarReload.ts +2 -6
  330. package/src/react/primitive-hooks/useBranchPickerNext.ts +2 -7
  331. package/src/react/primitive-hooks/useBranchPickerPrevious.ts +2 -7
  332. package/src/react/primitive-hooks/useComposerCancel.ts +2 -1
  333. package/src/react/primitive-hooks/useComposerSend.ts +2 -5
  334. package/src/react/primitive-hooks/useSuggestionTrigger.test.ts +11 -0
  335. package/src/react/primitive-hooks/useSuggestionTrigger.ts +4 -5
  336. package/src/react/primitives/message/MessageParts.tsx +0 -1
  337. package/src/react/primitives/thread/ThreadMessages.tsx +2 -1
  338. package/src/react/runtimes/RemoteThreadListHookInstanceManager.retry.test.tsx +116 -0
  339. package/src/react/runtimes/RemoteThreadListHookInstanceManager.running.test.tsx +1 -1
  340. package/src/react/runtimes/RemoteThreadListHookInstanceManager.test.tsx +57 -6
  341. package/src/react/runtimes/RemoteThreadListHookInstanceManager.title.test.tsx +272 -0
  342. package/src/react/runtimes/RemoteThreadListHookInstanceManager.tsx +159 -124
  343. package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.tsx +59 -20
  344. package/src/react/runtimes/RemoteThreadResource.test.ts +141 -0
  345. package/src/react/runtimes/RemoteThreadResource.ts +231 -0
  346. package/src/react/runtimes/RuntimeAdapterProvider.tsx +8 -20
  347. package/src/react/runtimes/assistant-transport/commandQueue.ts +68 -0
  348. package/src/react/runtimes/assistant-transport/replayBoundaryStream.test.ts +455 -0
  349. package/src/react/runtimes/assistant-transport/replayBoundaryStream.ts +172 -0
  350. package/src/react/runtimes/assistant-transport/runManager.ts +124 -0
  351. package/src/react/runtimes/assistant-transport/transport-delivery.test.tsx +79 -0
  352. package/src/react/runtimes/assistant-transport/transport-parentid.test.tsx +97 -0
  353. package/src/react/runtimes/assistant-transport/transport-scheduling.test.ts +414 -0
  354. package/src/react/runtimes/assistant-transport/types.ts +170 -0
  355. package/src/react/runtimes/assistant-transport/useAssistantTransport.spec.md +141 -0
  356. package/src/react/runtimes/assistant-transport/useAssistantTransportRuntime.test.tsx +625 -0
  357. package/src/react/runtimes/assistant-transport/useAssistantTransportRuntime.ts +481 -0
  358. package/src/react/runtimes/assistant-transport/useConvertedState.ts +20 -0
  359. package/src/react/runtimes/assistant-transport/useLatestRef.ts +9 -0
  360. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.test.tsx +131 -6
  361. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.ts +61 -15
  362. package/src/react/runtimes/cloud/CloudFileAttachmentAdapter.ts +6 -4
  363. package/src/react/runtimes/cloud/auiV0.ts +17 -1
  364. package/src/react/runtimes/cloud/useCloudThreadListAdapter.tsx +36 -21
  365. package/src/react/runtimes/cloud/useCloudThreadListRuntime.test.tsx +56 -0
  366. package/src/react/runtimes/cloud/useCloudThreadListRuntime.ts +31 -0
  367. package/src/react/runtimes/external-message-converter.test.ts +143 -0
  368. package/src/react/runtimes/external-message-converter.ts +41 -41
  369. package/src/react/runtimes/remote-thread-hook-on-tap.test.ts +58 -0
  370. package/src/react/runtimes/useExternalStoreRuntime.lifecycle.test.tsx +83 -0
  371. package/src/react/runtimes/useExternalStoreRuntime.suggestions.test.tsx +124 -0
  372. package/src/react/runtimes/useExternalStoreRuntime.ts +7 -0
  373. package/src/react/runtimes/useExternalStoreSharedOptions.ts +3 -1
  374. package/src/react/runtimes/useLocalRuntime.test.tsx +130 -4
  375. package/src/react/runtimes/useRuntimeAdapters.test.tsx +62 -0
  376. package/src/react/runtimes/useRuntimeAdapters.ts +28 -0
  377. package/src/runtime/api/composer-runtime.ts +5 -0
  378. package/src/runtime/api/thread-list-runtime.ts +3 -1
  379. package/src/runtime/api/thread-runtime.ts +28 -3
  380. package/src/runtime/base/base-composer-runtime-core.ts +106 -13
  381. package/src/runtime/base/base-thread-runtime-core.test.ts +191 -0
  382. package/src/runtime/base/base-thread-runtime-core.ts +47 -2
  383. package/src/runtime/base/default-edit-composer-runtime-core.ts +1 -15
  384. package/src/runtime/base/default-thread-composer-runtime-core.ts +13 -15
  385. package/src/runtime/interfaces/thread-runtime-core.ts +6 -0
  386. package/src/runtime/queue/external-thread-queue-adapter.ts +17 -0
  387. package/src/runtime/queue/message-queue.ts +28 -10
  388. package/src/runtime/utils/thread-runtime-lifecycle.ts +18 -0
  389. package/src/runtimes/external-store/external-store-adapter.ts +7 -0
  390. package/src/runtimes/external-store/external-store-shared-options.ts +3 -1
  391. package/src/runtimes/external-store/external-store-thread-list-runtime-core.ts +4 -1
  392. package/src/runtimes/external-store/external-store-thread-runtime-core.ts +187 -48
  393. package/src/runtimes/local/local-thread-runtime-core.test.ts +373 -4
  394. package/src/runtimes/local/local-thread-runtime-core.ts +83 -15
  395. package/src/runtimes/readonly/ReadonlyThreadRuntimeCore.ts +4 -0
  396. package/src/runtimes/remote-thread-list/empty-thread-core.ts +4 -0
  397. package/src/runtimes/remote-thread-list/types.ts +30 -0
  398. package/src/runtimes/tool-invocations/EDGE_CASES.md +17 -6
  399. package/src/runtimes/tool-invocations/ToolInvocationTracker.test.ts +243 -0
  400. package/src/runtimes/tool-invocations/ToolInvocationTracker.ts +127 -61
  401. package/src/store/clients/external-thread.ts +119 -16
  402. package/src/store/clients/model-context-client.test.ts +16 -8
  403. package/src/store/clients/runtime-adapter.ts +5 -2
  404. package/src/store/clients/single-thread-list.ts +2 -1
  405. package/src/store/clients/suggestions.ts +39 -13
  406. package/src/store/clients/thread-selection-events.ts +21 -0
  407. package/src/store/env.ts +11 -0
  408. package/src/store/index.ts +14 -1
  409. package/src/store/internal.ts +13 -0
  410. package/src/store/primitive-predicates.test.ts +184 -0
  411. package/src/store/primitive-predicates.ts +43 -0
  412. package/src/store/runtime-clients/attachment-runtime-client.test.ts +41 -0
  413. package/src/store/runtime-clients/attachment-runtime-client.ts +2 -1
  414. package/src/store/runtime-clients/handle-runtime-action.ts +11 -0
  415. package/src/store/runtime-clients/handle-thread-list-action.test.ts +69 -0
  416. package/src/store/runtime-clients/handle-thread-list-action.ts +6 -0
  417. package/src/store/runtime-clients/thread-list-item-runtime-client.ts +28 -35
  418. package/src/store/runtime-clients/thread-list-runtime-client.ts +9 -6
  419. package/src/store/runtime-clients/thread-runtime-client.ts +5 -0
  420. package/src/store/scopes/composer.ts +9 -4
  421. package/src/store/scopes/suggestions.ts +6 -0
  422. package/src/store/scopes/thread-list-item.ts +7 -6
  423. package/src/store/scopes/thread.ts +25 -7
  424. package/src/store/scopes/threads.ts +14 -0
  425. package/src/subscribable/subscribable.test.ts +77 -1
  426. package/src/subscribable/subscribable.ts +38 -23
  427. package/src/tests/RemoteThreadListThreadListRuntimeCore-switchToThread-unarchive.test.ts +25 -0
  428. package/src/tests/append-interactable-snapshots.test.ts +350 -0
  429. package/src/tests/auiV0Encode.test.ts +66 -0
  430. package/src/tests/base-composer-runtime-core-send.test.ts +156 -0
  431. package/src/tests/base-composer-runtime-core.test.ts +136 -1
  432. package/src/tests/composer-can-cancel.test.ts +101 -0
  433. package/src/tests/default-edit-composer-runtime-core.test.ts +0 -68
  434. package/src/tests/external-store-thread-list-runtime-core.test.ts +101 -0
  435. package/src/tests/external-store-thread-runtime-core-adapter.test.ts +491 -1
  436. package/src/tests/external-store-thread-runtime-core.test.ts +124 -0
  437. package/src/tests/external-thread-attachments.test.tsx +214 -0
  438. package/src/tests/external-thread-parity.test.tsx +54 -0
  439. package/src/tests/external-thread-refetch.test.tsx +117 -0
  440. package/src/tests/external-thread-suggestions.test.tsx +59 -0
  441. package/src/tests/interactables-toolui-migration.test.tsx +66 -0
  442. package/src/tests/message-queue.test.ts +54 -0
  443. package/src/tests/session-reset-notification.test.ts +145 -0
  444. package/src/tests/thread-message-like.test.ts +39 -0
  445. package/src/tests/thread-switch-events.test.tsx +234 -0
  446. package/src/tests/tools-scope-migration.test.tsx +58 -0
  447. package/src/types/error.ts +24 -0
  448. package/src/types/message.ts +2 -0
  449. package/src/utils/composite-context-provider.test.ts +139 -0
  450. package/src/utils/composite-context-provider.ts +26 -8
  451. package/src/utils/notify-event-listeners.ts +10 -5
  452. package/src/tests/default-thread-composer-runtime-core.test.ts +0 -82
@@ -0,0 +1,145 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import { ExternalStoreRuntimeCore } from "../runtimes/external-store/external-store-runtime-core";
3
+ import { LocalRuntimeCore } from "../runtimes/local/local-runtime-core";
4
+ import type { ChatModelAdapter } from "../runtime/utils/chat-model-adapter";
5
+ import type { ThreadMessage } from "../types/message";
6
+
7
+ async function waitFor(
8
+ predicate: () => unknown,
9
+ timeoutMs = 500,
10
+ ): Promise<void> {
11
+ const start = Date.now();
12
+ while (Date.now() - start < timeoutMs) {
13
+ try {
14
+ await predicate();
15
+ return;
16
+ } catch {
17
+ // retry
18
+ }
19
+ await new Promise((r) => setTimeout(r, 5));
20
+ }
21
+ await predicate();
22
+ }
23
+
24
+ const trailingUserMessage = {
25
+ id: "u1",
26
+ role: "user",
27
+ createdAt: new Date(),
28
+ content: [{ type: "text", text: "draft in flight" }],
29
+ attachments: [],
30
+ metadata: { custom: {} },
31
+ } as ThreadMessage;
32
+
33
+ const toolCallMessage = {
34
+ id: "a1",
35
+ role: "assistant",
36
+ createdAt: new Date(),
37
+ status: { type: "requires-action", reason: "tool-calls" },
38
+ metadata: {
39
+ unstable_state: null,
40
+ unstable_annotations: [],
41
+ unstable_data: [],
42
+ steps: [],
43
+ custom: {},
44
+ },
45
+ content: [
46
+ {
47
+ type: "tool-call",
48
+ toolCallId: "tool-1",
49
+ toolName: "send_email",
50
+ args: { to: "dev@example.com" },
51
+ argsText: '{"to":"dev@example.com"}',
52
+ },
53
+ ],
54
+ } as unknown as ThreadMessage;
55
+
56
+ const externalThread = () => {
57
+ const setToolStatuses = vi.fn();
58
+ const setMessages = vi.fn();
59
+ const onCancel = vi.fn();
60
+ const notifyCancelled = vi.fn();
61
+ const store = {
62
+ messages: [trailingUserMessage] as ThreadMessage[],
63
+ onNew: vi.fn(async () => {}),
64
+ onCancel,
65
+ setMessages,
66
+ unstable_enableToolInvocations: true,
67
+ setToolStatuses,
68
+ queue: {
69
+ __internal_notifyCancelled: notifyCancelled,
70
+ } as never,
71
+ };
72
+ const core = new ExternalStoreRuntimeCore(store);
73
+ core.registerModelContextProvider({
74
+ getModelContext: () => ({
75
+ tools: {
76
+ send_email: {
77
+ parameters: { type: "object", properties: {} },
78
+ execute: vi.fn(() => new Promise(() => {})),
79
+ },
80
+ },
81
+ }),
82
+ });
83
+ return {
84
+ core,
85
+ store,
86
+ thread: core.threads.getMainThreadRuntimeCore(),
87
+ setToolStatuses,
88
+ setMessages,
89
+ onCancel,
90
+ notifyCancelled,
91
+ };
92
+ };
93
+
94
+ const driveExecutingTool = async (
95
+ harness: ReturnType<typeof externalThread>,
96
+ ) => {
97
+ harness.core.setAdapter({
98
+ ...harness.store,
99
+ messages: [trailingUserMessage, toolCallMessage],
100
+ });
101
+ await waitFor(() => {
102
+ const statuses = harness.setToolStatuses.mock.lastCall?.[0] as
103
+ | Record<string, { type: string }>
104
+ | undefined;
105
+ expect(statuses?.["tool-1"]?.type).toBe("executing");
106
+ });
107
+ };
108
+
109
+ describe("unstable_notifySessionReset", () => {
110
+ it("clears session-scoped tool state once and parks queued work", async () => {
111
+ const harness = externalThread();
112
+ await driveExecutingTool(harness);
113
+
114
+ harness.setToolStatuses.mockClear();
115
+ harness.thread.unstable_notifySessionReset();
116
+
117
+ expect(harness.setToolStatuses).toHaveBeenCalledTimes(1);
118
+ expect(harness.setToolStatuses).toHaveBeenLastCalledWith({});
119
+ expect(harness.notifyCancelled).toHaveBeenCalledTimes(1);
120
+ });
121
+
122
+ it("carries no run-cancel semantics", async () => {
123
+ const harness = externalThread();
124
+ await driveExecutingTool(harness);
125
+
126
+ harness.thread.unstable_notifySessionReset();
127
+
128
+ expect(harness.onCancel).not.toHaveBeenCalled();
129
+ expect(harness.setMessages).not.toHaveBeenCalled();
130
+ expect(harness.thread.messages.at(-1)?.id).toBe("a1");
131
+ });
132
+
133
+ it("throws on runtimes without a backing session", () => {
134
+ const local = new LocalRuntimeCore(
135
+ {
136
+ adapters: { chatModel: { async *run() {} } satisfies ChatModelAdapter },
137
+ },
138
+ undefined,
139
+ );
140
+
141
+ expect(() =>
142
+ local.threads.getMainThreadRuntimeCore().unstable_notifySessionReset(),
143
+ ).toThrow("Runtime does not support resetting sessions.");
144
+ });
145
+ });
@@ -382,3 +382,42 @@ describe("fromThreadMessageLike", () => {
382
382
  });
383
383
  });
384
384
  });
385
+
386
+ describe("fromThreadMessageLike provider metadata", () => {
387
+ it("keeps it on image and file parts", () => {
388
+ const result = fromThreadMessageLike(
389
+ {
390
+ role: "user",
391
+ content: [
392
+ {
393
+ type: "image",
394
+ image: "https://example.com/cat.png",
395
+ providerMetadata: { agui: { file_id: "f_1" } },
396
+ },
397
+ {
398
+ type: "file",
399
+ data: "https://example.com/spec.pdf",
400
+ mimeType: "application/pdf",
401
+ providerMetadata: { agui: { file_id: "f_2" } },
402
+ },
403
+ ],
404
+ },
405
+ fallbackId,
406
+ fallbackStatus,
407
+ );
408
+
409
+ expect(result.content).toEqual([
410
+ {
411
+ type: "image",
412
+ image: "https://example.com/cat.png",
413
+ providerMetadata: { agui: { file_id: "f_1" } },
414
+ },
415
+ {
416
+ type: "file",
417
+ data: "https://example.com/spec.pdf",
418
+ mimeType: "application/pdf",
419
+ providerMetadata: { agui: { file_id: "f_2" } },
420
+ },
421
+ ]);
422
+ });
423
+ });
@@ -0,0 +1,234 @@
1
+ // @vitest-environment jsdom
2
+
3
+ import { act, render, waitFor } from "@testing-library/react";
4
+ import { describe, expect, it, vi } from "vitest";
5
+ import { AuiProvider, useAui, useAuiEvent } from "@assistant-ui/store";
6
+ import { AssistantRuntimeProvider } from "../react/AssistantRuntimeProvider";
7
+ import { useExternalStoreRuntime } from "../react/runtimes/useExternalStoreRuntime";
8
+ import { useRemoteThreadListRuntime } from "../react/runtimes/useRemoteThreadListRuntime";
9
+ import { makeAdapter } from "./remote-thread-list-test-helpers";
10
+ import { RuntimeAdapter } from "../react/RuntimeAdapter";
11
+ import { AssistantRuntimeImpl } from "../runtime/api/assistant-runtime";
12
+ import { ExternalStoreRuntimeCore } from "../runtimes/external-store/external-store-runtime-core";
13
+ import type { ExternalStoreAdapter } from "../runtimes/external-store/external-store-adapter";
14
+
15
+ type DemoMessage = { id: string; role: "user" | "assistant"; text: string };
16
+
17
+ const EMPTY_MESSAGES: readonly never[] = [];
18
+
19
+ const useTestThreadRuntime = () =>
20
+ useExternalStoreRuntime({
21
+ messages: EMPTY_MESSAGES,
22
+ isRunning: false,
23
+ onNew: async () => {},
24
+ });
25
+
26
+ const createRuntime = () => {
27
+ const threads = [
28
+ {
29
+ id: "t1",
30
+ title: "one",
31
+ messages: [{ id: "m1", role: "user" as const, text: "a" }],
32
+ },
33
+ {
34
+ id: "t2",
35
+ title: "two",
36
+ messages: [{ id: "m2", role: "user" as const, text: "b" }],
37
+ },
38
+ ];
39
+ let currentId = "t1";
40
+ const makeAdapter = (): ExternalStoreAdapter<DemoMessage> => ({
41
+ messages: threads.find((t) => t.id === currentId)!.messages,
42
+ convertMessage: (m) => ({
43
+ id: m.id,
44
+ role: m.role,
45
+ content: [{ type: "text", text: m.text }],
46
+ }),
47
+ onNew: async () => {},
48
+ adapters: {
49
+ threadList: {
50
+ threadId: currentId,
51
+ threads: threads.map((t) => ({
52
+ status: "regular" as const,
53
+ id: t.id,
54
+ title: t.title,
55
+ })),
56
+ onSwitchToThread: (threadId: string) => {
57
+ currentId = threadId;
58
+ sync();
59
+ },
60
+ onSwitchToNewThread: () => {},
61
+ },
62
+ },
63
+ });
64
+ const core = new ExternalStoreRuntimeCore(makeAdapter());
65
+ const runtime = new AssistantRuntimeImpl(core);
66
+ const sync = () => core.setAdapter(makeAdapter());
67
+ return runtime;
68
+ };
69
+
70
+ describe("thread switch events", () => {
71
+ it("delivers switchedTo to default-scope, star-scope, and aui.on listeners", async () => {
72
+ const runtime = createRuntime();
73
+ const defaultScope = vi.fn();
74
+ const starScope = vi.fn();
75
+ const auiOn = vi.fn();
76
+ const switchedAwayStar = vi.fn();
77
+ let aui!: ReturnType<typeof useAui>;
78
+ const Consumer = () => {
79
+ useAuiEvent("threadListItem.switchedTo" as never, defaultScope as never);
80
+ useAuiEvent(
81
+ { scope: "*", event: "threadListItem.switchedTo" } as never,
82
+ starScope as never,
83
+ );
84
+ useAuiEvent(
85
+ { scope: "*", event: "threadListItem.switchedAway" } as never,
86
+ switchedAwayStar as never,
87
+ );
88
+ return null;
89
+ };
90
+ const Harness = () => {
91
+ aui = useAui({ threads: RuntimeAdapter(runtime) } as never);
92
+ return (
93
+ <AuiProvider value={aui}>
94
+ <Consumer />
95
+ </AuiProvider>
96
+ );
97
+ };
98
+ render(<Harness />);
99
+ await act(async () => {});
100
+
101
+ aui.on("threadListItem.switchedTo" as never, auiOn as never);
102
+
103
+ await act(async () => {
104
+ aui.threads.item({ index: 1 }).switchTo();
105
+ });
106
+ await act(async () => {});
107
+
108
+ expect(defaultScope).toHaveBeenCalledExactlyOnceWith({ threadId: "t2" });
109
+ expect(starScope).toHaveBeenCalledExactlyOnceWith({ threadId: "t2" });
110
+ expect(auiOn).toHaveBeenCalledExactlyOnceWith({ threadId: "t2" });
111
+ expect(switchedAwayStar).toHaveBeenCalledExactlyOnceWith({
112
+ threadId: "t1",
113
+ });
114
+
115
+ await act(async () => {
116
+ aui.threads.item({ index: 0 }).switchTo();
117
+ });
118
+ await act(async () => {});
119
+
120
+ expect(defaultScope).toHaveBeenCalledTimes(2);
121
+ expect(defaultScope).toHaveBeenLastCalledWith({ threadId: "t1" });
122
+ expect(switchedAwayStar).toHaveBeenCalledTimes(2);
123
+ expect(switchedAwayStar).toHaveBeenLastCalledWith({ threadId: "t2" });
124
+ });
125
+
126
+ it("delivers threads.selectionChanged with the new and previous thread ids", async () => {
127
+ const runtime = createRuntime();
128
+ const selectionChanged = vi.fn();
129
+ const auiOn = vi.fn();
130
+ let aui!: ReturnType<typeof useAui>;
131
+ const Consumer = () => {
132
+ useAuiEvent(
133
+ "threads.selectionChanged" as never,
134
+ selectionChanged as never,
135
+ );
136
+ return null;
137
+ };
138
+ const Harness = () => {
139
+ aui = useAui({ threads: RuntimeAdapter(runtime) } as never);
140
+ return (
141
+ <AuiProvider value={aui}>
142
+ <Consumer />
143
+ </AuiProvider>
144
+ );
145
+ };
146
+ render(<Harness />);
147
+ await act(async () => {});
148
+
149
+ aui.on("threads.selectionChanged" as never, auiOn as never);
150
+
151
+ await act(async () => {
152
+ aui.threads.item({ index: 1 }).switchTo();
153
+ });
154
+ await act(async () => {});
155
+
156
+ expect(selectionChanged).toHaveBeenCalledExactlyOnceWith({
157
+ threadId: "t2",
158
+ previousThreadId: "t1",
159
+ });
160
+ expect(auiOn).toHaveBeenCalledExactlyOnceWith({
161
+ threadId: "t2",
162
+ previousThreadId: "t1",
163
+ });
164
+
165
+ await act(async () => {
166
+ aui.threads.item({ index: 0 }).switchTo();
167
+ });
168
+ await act(async () => {});
169
+
170
+ expect(selectionChanged).toHaveBeenCalledTimes(2);
171
+ expect(selectionChanged).toHaveBeenLastCalledWith({
172
+ threadId: "t1",
173
+ previousThreadId: "t2",
174
+ });
175
+ });
176
+
177
+ it("does not emit for the initially selected thread on mount", async () => {
178
+ const runtime = createRuntime();
179
+ const anySwitch = vi.fn();
180
+ const Consumer = () => {
181
+ useAuiEvent(
182
+ { scope: "*", event: "threadListItem.switchedTo" } as never,
183
+ anySwitch as never,
184
+ );
185
+ useAuiEvent(
186
+ { scope: "*", event: "threads.selectionChanged" } as never,
187
+ anySwitch as never,
188
+ );
189
+ return null;
190
+ };
191
+ const Harness = () => {
192
+ const aui = useAui({ threads: RuntimeAdapter(runtime) } as never);
193
+ return (
194
+ <AuiProvider value={aui}>
195
+ <Consumer />
196
+ </AuiProvider>
197
+ );
198
+ };
199
+ render(<Harness />);
200
+ await act(async () => {});
201
+
202
+ expect(anySwitch).not.toHaveBeenCalled();
203
+ });
204
+
205
+ it("emits when a deep-linked initial thread resolves after mount", async () => {
206
+ const adapter = makeAdapter();
207
+ const selectionChanged = vi.fn();
208
+ const Listener = () => {
209
+ useAuiEvent("threads.selectionChanged", selectionChanged);
210
+ return null;
211
+ };
212
+ const Harness = () => {
213
+ const runtime = useRemoteThreadListRuntime({
214
+ adapter,
215
+ initialThreadId: "thread-a",
216
+ runtimeHook: useTestThreadRuntime,
217
+ });
218
+ return (
219
+ <AssistantRuntimeProvider runtime={runtime}>
220
+ <Listener />
221
+ </AssistantRuntimeProvider>
222
+ );
223
+ };
224
+ render(<Harness />);
225
+
226
+ await waitFor(() => expect(selectionChanged).toHaveBeenCalledTimes(1));
227
+ const payload = selectionChanged.mock.calls[0]![0] as {
228
+ threadId: string;
229
+ previousThreadId: string;
230
+ };
231
+ expect(payload.threadId).toBe("thread-a");
232
+ expect(payload.previousThreadId).toMatch(/^__LOCALID_/);
233
+ });
234
+ });
@@ -0,0 +1,58 @@
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 { ModelContext } from "../store/clients/model-context-client";
9
+ import type { Toolkit } from "../react/model-context/toolbox";
10
+
11
+ type AnyClient = Record<string, any>;
12
+
13
+ const toolkit = {
14
+ lookup: {
15
+ description: "look something up",
16
+ parameters: { type: "object", properties: {} },
17
+ execute: async () => "ok",
18
+ },
19
+ } as unknown as Toolkit;
20
+
21
+ afterEach(() => {
22
+ cleanup();
23
+ });
24
+
25
+ describe("Tools model-context registration", () => {
26
+ it("migrates to a structurally replaced modelContext scope", async () => {
27
+ let aui!: AnyClient;
28
+ const Harness = ({ generation }: { generation: number }) => {
29
+ aui = useAui({
30
+ tools: Tools({ toolkit }),
31
+ modelContext: withKey(String(generation), ModelContext()),
32
+ } as never);
33
+ return null;
34
+ };
35
+ const view = render(<Harness generation={0} />);
36
+
37
+ expect(
38
+ Object.keys(aui.modelContext().getModelContext().tools ?? {}),
39
+ ).toContain("lookup");
40
+
41
+ // A rerender inside an outer act would not land until that act exits,
42
+ // so the swap happens first and only the scheduler wait is wrapped
43
+ view.rerender(<Harness generation={1} />);
44
+
45
+ // The registration lands one scheduler macrotask after the swap: the
46
+ // mount-time register marks the tap scheduler dirty, which defers the
47
+ // structural publish to the scheduler's drain. The remounted scope
48
+ // starts from fresh state, so the tools reappearing proves the
49
+ // registration migrated to the replacement instance.
50
+ await act(async () => {
51
+ await vi.waitFor(() =>
52
+ expect(
53
+ Object.keys(aui.modelContext().getModelContext().tools ?? {}),
54
+ ).toContain("lookup"),
55
+ );
56
+ });
57
+ });
58
+ });
@@ -52,6 +52,30 @@ export const isAssistantError = (value: unknown): value is AssistantError => {
52
52
  return true;
53
53
  };
54
54
 
55
+ const MESSAGE_NOT_SENT = Symbol.for("assistant-ui.message-not-sent");
56
+
57
+ /**
58
+ * Rejection reason for a send that never reached the backend, so nothing ran
59
+ * and nothing is recoverable from the thread. A runtime adapter throws it from
60
+ * `onNew` to hand the message back to the thread composer, which restores the
61
+ * draft it cleared at dispatch time when nothing has claimed the composer
62
+ * since. An edit composer closes at dispatch, so a rejected edit is not
63
+ * restored.
64
+ */
65
+ export class MessageNotSentError extends Error {
66
+ readonly [MESSAGE_NOT_SENT] = true;
67
+
68
+ constructor(message = "The message was not sent.") {
69
+ super(message);
70
+ this.name = "MessageNotSentError";
71
+ }
72
+ }
73
+
74
+ export const isMessageNotSentError = (
75
+ error: unknown,
76
+ ): error is MessageNotSentError =>
77
+ typeof error === "object" && error !== null && MESSAGE_NOT_SENT in error;
78
+
55
79
  export const toAssistantError = (error: unknown): AssistantError => {
56
80
  if (isAssistantError(error)) return error;
57
81
  if (error instanceof Error) {
@@ -56,6 +56,7 @@ export type ImageMessagePart = {
56
56
  readonly type: "image";
57
57
  readonly image: string;
58
58
  readonly filename?: string;
59
+ readonly providerMetadata?: PartProviderMetadata;
59
60
  };
60
61
 
61
62
  export type FileMessagePart = {
@@ -65,6 +66,7 @@ export type FileMessagePart = {
65
66
  readonly mimeType: string;
66
67
  /** How `data` goes on the wire: a url or id reference; omitted = inferred (http(s) → url, else base64). "url" is honored by the LangChain-family, A2A, AG-UI, and Google ADK runtimes; "id" by the LangChain family only. */
67
68
  readonly sourceType?: "url" | "id";
69
+ readonly providerMetadata?: PartProviderMetadata;
68
70
  readonly parentId?: string;
69
71
  };
70
72
 
@@ -0,0 +1,139 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import { CompositeContextProvider } from "./composite-context-provider";
3
+
4
+ describe("CompositeContextProvider", () => {
5
+ it("notifies every subscriber and rethrows when a registration subscriber throws", () => {
6
+ const composite = new CompositeContextProvider();
7
+ const error = new Error("subscriber failed");
8
+ const laterSubscriber = vi.fn();
9
+
10
+ composite.subscribe(() => {
11
+ throw error;
12
+ });
13
+ composite.subscribe(laterSubscriber);
14
+
15
+ expect(() =>
16
+ composite.registerModelContextProvider({
17
+ getModelContext: () => ({ system: "provider instructions" }),
18
+ }),
19
+ ).toThrow(error);
20
+
21
+ expect(composite.getModelContext().system).toBe("provider instructions");
22
+ expect(laterSubscriber).toHaveBeenCalledTimes(1);
23
+ });
24
+
25
+ it("rolls back providers that fail to subscribe", () => {
26
+ const composite = new CompositeContextProvider();
27
+ const error = new Error("subscription failed");
28
+ const observedSystems: Array<string | undefined> = [];
29
+
30
+ composite.subscribe(() => {
31
+ observedSystems.push(composite.getModelContext().system);
32
+ });
33
+
34
+ expect(() =>
35
+ composite.registerModelContextProvider({
36
+ getModelContext: () => ({ system: "provider instructions" }),
37
+ subscribe: (callback) => {
38
+ callback();
39
+ throw error;
40
+ },
41
+ }),
42
+ ).toThrow(error);
43
+
44
+ expect(composite.getModelContext().system).toBeUndefined();
45
+ expect(observedSystems).toEqual(["provider instructions", undefined]);
46
+ });
47
+
48
+ it("rethrows the provider subscription failure when a rollback subscriber throws", () => {
49
+ const composite = new CompositeContextProvider();
50
+ const subscriptionError = new Error("subscription failed");
51
+ const subscriberError = new Error("subscriber failed");
52
+ const consoleError = vi
53
+ .spyOn(console, "error")
54
+ .mockImplementation(() => {});
55
+
56
+ composite.subscribe(() => {
57
+ throw subscriberError;
58
+ });
59
+
60
+ try {
61
+ expect(() =>
62
+ composite.registerModelContextProvider({
63
+ getModelContext: () => ({ system: "provider instructions" }),
64
+ subscribe: () => {
65
+ throw subscriptionError;
66
+ },
67
+ }),
68
+ ).toThrow(subscriptionError);
69
+
70
+ expect(composite.getModelContext().system).toBeUndefined();
71
+ expect(consoleError).toHaveBeenCalledWith(subscriberError);
72
+ } finally {
73
+ consoleError.mockRestore();
74
+ }
75
+ });
76
+
77
+ it("preserves an earlier registration when a duplicate fails to subscribe", () => {
78
+ const composite = new CompositeContextProvider();
79
+ const error = new Error("subscription failed");
80
+ let subscriptionCount = 0;
81
+ const provider = {
82
+ getModelContext: () => ({ system: "provider instructions" }),
83
+ subscribe: () => {
84
+ subscriptionCount++;
85
+ if (subscriptionCount === 2) throw error;
86
+ return () => {};
87
+ },
88
+ };
89
+
90
+ const unregister = composite.registerModelContextProvider(provider);
91
+
92
+ expect(() => composite.registerModelContextProvider(provider)).toThrow(
93
+ error,
94
+ );
95
+ expect(composite.getModelContext().system).toBe("provider instructions");
96
+
97
+ unregister();
98
+ expect(composite.getModelContext().system).toBeUndefined();
99
+ });
100
+
101
+ it("keeps duplicate registrations independent", () => {
102
+ const composite = new CompositeContextProvider();
103
+ const provider = {
104
+ getModelContext: () => ({ system: "provider instructions" }),
105
+ };
106
+
107
+ const unregisterFirst = composite.registerModelContextProvider(provider);
108
+ const unregisterSecond = composite.registerModelContextProvider(provider);
109
+
110
+ unregisterFirst();
111
+ expect(composite.getModelContext().system).toBe("provider instructions");
112
+
113
+ unregisterSecond();
114
+ expect(composite.getModelContext().system).toBeUndefined();
115
+ });
116
+
117
+ it("notifies every subscriber and rethrows on provider updates", () => {
118
+ const composite = new CompositeContextProvider();
119
+ const error = new Error("subscriber failed");
120
+ const laterSubscriber = vi.fn();
121
+ let publishUpdate = () => {};
122
+
123
+ composite.registerModelContextProvider({
124
+ getModelContext: () => ({ system: "provider instructions" }),
125
+ subscribe: (callback) => {
126
+ publishUpdate = callback;
127
+ return () => {};
128
+ },
129
+ });
130
+
131
+ composite.subscribe(() => {
132
+ throw error;
133
+ });
134
+ composite.subscribe(laterSubscriber);
135
+
136
+ expect(() => publishUpdate()).toThrow(error);
137
+ expect(laterSubscriber).toHaveBeenCalledTimes(1);
138
+ });
139
+ });