@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
@@ -344,6 +344,149 @@ describe("convertExternalMessages", () => {
344
344
  });
345
345
  });
346
346
 
347
+ describe("metadata merging across joined messages", () => {
348
+ it("keeps the final assistant message's metadata after a tool call", () => {
349
+ const messages = [
350
+ {
351
+ id: "a1",
352
+ role: "assistant" as const,
353
+ content: [
354
+ {
355
+ type: "tool-call" as const,
356
+ toolCallId: "t1",
357
+ toolName: "search",
358
+ args: {},
359
+ },
360
+ ],
361
+ },
362
+ {
363
+ role: "tool" as const,
364
+ toolCallId: "t1",
365
+ toolName: "search",
366
+ result: { ok: true },
367
+ },
368
+ {
369
+ id: "a2",
370
+ role: "assistant" as const,
371
+ content: [{ type: "text" as const, text: "final answer" }],
372
+ metadata: {
373
+ unstable_annotations: [{ note: "final" }],
374
+ steps: [{ usage: { promptTokens: 1, completionTokens: 2 } }],
375
+ },
376
+ },
377
+ ];
378
+
379
+ const callback: useExternalMessageConverter.Callback<
380
+ (typeof messages)[number]
381
+ > = (msg) => msg as useExternalMessageConverter.Message;
382
+
383
+ const result = convertExternalMessages(messages, callback, false, {});
384
+
385
+ expect(result).toHaveLength(1);
386
+ const metadata = result[0]!.metadata as any;
387
+ expect(metadata.unstable_annotations).toEqual([{ note: "final" }]);
388
+ expect(metadata.steps).toEqual([
389
+ { usage: { promptTokens: 1, completionTokens: 2 } },
390
+ ]);
391
+ });
392
+
393
+ it("accumulates annotations and data from every joined assistant message", () => {
394
+ const messages = [
395
+ {
396
+ id: "a1",
397
+ role: "assistant" as const,
398
+ content: [{ type: "text" as const, text: "first" }],
399
+ metadata: {
400
+ unstable_annotations: [{ a: 1 }],
401
+ unstable_data: [{ d: 1 }],
402
+ },
403
+ },
404
+ {
405
+ id: "a2",
406
+ role: "assistant" as const,
407
+ content: [{ type: "text" as const, text: "second" }],
408
+ metadata: {
409
+ unstable_annotations: [{ a: 2 }],
410
+ unstable_data: [{ d: 2 }],
411
+ },
412
+ },
413
+ ];
414
+
415
+ const callback: useExternalMessageConverter.Callback<
416
+ (typeof messages)[number]
417
+ > = (msg) => msg as useExternalMessageConverter.Message;
418
+
419
+ const result = convertExternalMessages(messages, callback, false, {});
420
+
421
+ expect(result).toHaveLength(1);
422
+ const metadata = result[0]!.metadata as any;
423
+ expect(metadata.unstable_annotations).toEqual([{ a: 1 }, { a: 2 }]);
424
+ expect(metadata.unstable_data).toEqual([{ d: 1 }, { d: 2 }]);
425
+ });
426
+
427
+ it("keeps the last joined output's timing, dropping earlier timing", () => {
428
+ const messages = [
429
+ {
430
+ id: "a1",
431
+ role: "assistant" as const,
432
+ content: [{ type: "text" as const, text: "first" }],
433
+ metadata: {
434
+ timing: { streamStartTime: 1 },
435
+ },
436
+ },
437
+ {
438
+ id: "a2",
439
+ role: "assistant" as const,
440
+ content: [{ type: "text" as const, text: "second" }],
441
+ metadata: {
442
+ timing: { streamStartTime: 2 },
443
+ },
444
+ },
445
+ ];
446
+
447
+ const callback: useExternalMessageConverter.Callback<
448
+ (typeof messages)[number]
449
+ > = (msg) => msg as useExternalMessageConverter.Message;
450
+
451
+ const result = convertExternalMessages(messages, callback, false, {});
452
+
453
+ expect(result).toHaveLength(1);
454
+ const metadata = result[0]!.metadata as any;
455
+ expect(metadata.timing).toEqual({ streamStartTime: 2 });
456
+ });
457
+
458
+ it("merges custom across joined outputs, with later keys overwriting earlier ones", () => {
459
+ const messages = [
460
+ {
461
+ id: "a1",
462
+ role: "assistant" as const,
463
+ content: [{ type: "text" as const, text: "first" }],
464
+ metadata: {
465
+ custom: { author: "agent-a", branch: "main" },
466
+ },
467
+ },
468
+ {
469
+ id: "a2",
470
+ role: "assistant" as const,
471
+ content: [{ type: "text" as const, text: "second" }],
472
+ metadata: {
473
+ custom: { author: "agent-b" },
474
+ },
475
+ },
476
+ ];
477
+
478
+ const callback: useExternalMessageConverter.Callback<
479
+ (typeof messages)[number]
480
+ > = (msg) => msg as useExternalMessageConverter.Message;
481
+
482
+ const result = convertExternalMessages(messages, callback, false, {});
483
+
484
+ expect(result).toHaveLength(1);
485
+ const metadata = result[0]!.metadata as any;
486
+ expect(metadata.custom).toEqual({ author: "agent-b", branch: "main" });
487
+ });
488
+ });
489
+
347
490
  describe("invalid converter output", () => {
348
491
  it("throws a descriptive error when the callback returns undefined", () => {
349
492
  const messages = [{ id: "m1", type: "remove" }];
@@ -200,52 +200,52 @@ const joinExternalMessages = (
200
200
  ...output.attachments,
201
201
  ];
202
202
  }
203
+ }
203
204
 
204
- if (output.metadata) {
205
- assistantMessage.metadata ??= {};
206
- if (output.metadata.unstable_state !== undefined) {
207
- assistantMessage.metadata.unstable_state =
208
- output.metadata.unstable_state;
209
- }
210
- if (output.metadata.unstable_annotations) {
211
- assistantMessage.metadata.unstable_annotations = [
212
- ...(assistantMessage.metadata.unstable_annotations ?? []),
213
- ...output.metadata.unstable_annotations,
214
- ];
215
- }
216
- if (output.metadata.unstable_data) {
217
- assistantMessage.metadata.unstable_data = [
218
- ...(assistantMessage.metadata.unstable_data ?? []),
219
- ...output.metadata.unstable_data,
220
- ];
221
- }
222
- if (output.metadata.steps) {
223
- assistantMessage.metadata.steps = [
224
- ...(assistantMessage.metadata.steps ?? []),
225
- ...output.metadata.steps,
226
- ];
227
- }
228
- if (output.metadata.custom) {
229
- assistantMessage.metadata.custom = {
230
- ...(assistantMessage.metadata.custom ?? {}),
231
- ...output.metadata.custom,
232
- };
233
- }
205
+ if (output.metadata) {
206
+ assistantMessage.metadata ??= {};
207
+ if (output.metadata.unstable_state !== undefined) {
208
+ assistantMessage.metadata.unstable_state =
209
+ output.metadata.unstable_state;
210
+ }
211
+ if (output.metadata.unstable_annotations) {
212
+ assistantMessage.metadata.unstable_annotations = [
213
+ ...(assistantMessage.metadata.unstable_annotations ?? []),
214
+ ...output.metadata.unstable_annotations,
215
+ ];
216
+ }
217
+ if (output.metadata.unstable_data) {
218
+ assistantMessage.metadata.unstable_data = [
219
+ ...(assistantMessage.metadata.unstable_data ?? []),
220
+ ...output.metadata.unstable_data,
221
+ ];
222
+ }
223
+ if (output.metadata.steps) {
224
+ assistantMessage.metadata.steps = [
225
+ ...(assistantMessage.metadata.steps ?? []),
226
+ ...output.metadata.steps,
227
+ ];
228
+ }
229
+ if (output.metadata.custom) {
230
+ assistantMessage.metadata.custom = {
231
+ ...(assistantMessage.metadata.custom ?? {}),
232
+ ...output.metadata.custom,
233
+ };
234
+ }
234
235
 
235
- if (output.metadata.timing) {
236
- assistantMessage.metadata.timing = output.metadata.timing;
237
- }
236
+ if (output.metadata.timing) {
237
+ assistantMessage.metadata.timing = output.metadata.timing;
238
+ }
238
239
 
239
- if (output.metadata.submittedFeedback) {
240
- assistantMessage.metadata.submittedFeedback =
241
- output.metadata.submittedFeedback;
242
- }
240
+ if (output.metadata.submittedFeedback) {
241
+ assistantMessage.metadata.submittedFeedback =
242
+ output.metadata.submittedFeedback;
243
+ }
243
244
 
244
- if (output.metadata.isOptimistic) {
245
- assistantMessage.metadata.isOptimistic = true;
246
- }
245
+ if (output.metadata.isOptimistic) {
246
+ assistantMessage.metadata.isOptimistic = true;
247
247
  }
248
- // TODO keep this in sync
248
+ // TODO keep this in sync with ThreadMessageLike["metadata"] / fromThreadMessageLike
249
249
  }
250
250
 
251
251
  // Add content parts, merging reasoning parts with same parentId
@@ -0,0 +1,58 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import {
3
+ createTapRoot,
4
+ resource,
5
+ useResources,
6
+ withKey,
7
+ } from "@assistant-ui/tap";
8
+ import { useExternalStoreRuntime } from "./useExternalStoreRuntime";
9
+ import type { AssistantRuntime } from "../../runtime/api/assistant-runtime";
10
+
11
+ const EMPTY_MESSAGES: readonly never[] = [];
12
+
13
+ const useTestThreadRuntime = () =>
14
+ useExternalStoreRuntime({
15
+ messages: EMPTY_MESSAGES,
16
+ isRunning: false,
17
+ onNew: async () => {},
18
+ });
19
+
20
+ const TestThread = resource(useTestThreadRuntime);
21
+
22
+ describe("runtimeHook hosted under one tap root", () => {
23
+ it("starts N independent threads as keyed resources", () => {
24
+ const ids = ["a", "b", "c"] as const;
25
+ const root = createTapRoot(function RemoteThreadListHost() {
26
+ return useResources(ids.map((id) => withKey(id, TestThread(), [id])));
27
+ });
28
+
29
+ try {
30
+ const runtimes = root.getValue();
31
+ expect(runtimes).toHaveLength(3);
32
+ for (const runtime of runtimes) {
33
+ expect(runtime.thread.getState().messages).toEqual([]);
34
+ expect(runtime.thread.getState().isRunning).toBe(false);
35
+ }
36
+ expect(new Set(runtimes).size).toBe(3);
37
+ } finally {
38
+ root.unmount();
39
+ }
40
+ });
41
+
42
+ it("keeps a sibling resource after another key is removed", () => {
43
+ let ids = ["first", "second"];
44
+ const root = createTapRoot(function RemoteThreadListHost() {
45
+ return useResources(ids.map((id) => withKey(id, TestThread(), [id])));
46
+ });
47
+
48
+ try {
49
+ const [kept] = root.getValue() as [AssistantRuntime, AssistantRuntime];
50
+ ids = ["first"];
51
+ root.getValue();
52
+ expect(root.getValue()[0]).toBe(kept);
53
+ expect(kept.thread.getState().messages).toEqual([]);
54
+ } finally {
55
+ root.unmount();
56
+ }
57
+ });
58
+ });
@@ -0,0 +1,83 @@
1
+ // @vitest-environment jsdom
2
+
3
+ import { StrictMode } from "react";
4
+ import { act, render } from "@testing-library/react";
5
+ import { describe, expect, it, vi } from "vitest";
6
+ import { useExternalStoreRuntime } from "./useExternalStoreRuntime";
7
+ import type { AssistantRuntime } from "../../runtime/api/assistant-runtime";
8
+
9
+ describe("useExternalStoreRuntime lifecycle", () => {
10
+ it("keeps dispatching appends after StrictMode's simulated remount", async () => {
11
+ const onNew = vi.fn(async () => {});
12
+ const capture: { runtime: AssistantRuntime | null } = { runtime: null };
13
+ const App = () => {
14
+ const runtime = useExternalStoreRuntime({ messages: [], onNew });
15
+ capture.runtime = runtime;
16
+ return null;
17
+ };
18
+ render(
19
+ <StrictMode>
20
+ <App />
21
+ </StrictMode>,
22
+ );
23
+ expect(capture.runtime).not.toBeNull();
24
+
25
+ await act(async () => {
26
+ await capture.runtime!.thread.append({
27
+ role: "user",
28
+ content: [{ type: "text", text: "hello" }],
29
+ });
30
+ });
31
+
32
+ expect(onNew).toHaveBeenCalledTimes(1);
33
+ });
34
+
35
+ it("dispatches an append before unmount", async () => {
36
+ let resolveInitialization!: () => void;
37
+ const initialization = new Promise<void>((resolve) => {
38
+ resolveInitialization = resolve;
39
+ });
40
+ const onNew = vi.fn(async () => {});
41
+ const capture: { runtime: AssistantRuntime | null } = { runtime: null };
42
+ const App = () => {
43
+ const runtime = useExternalStoreRuntime({ messages: [], onNew });
44
+ capture.runtime = runtime;
45
+ return null;
46
+ };
47
+ const view = render(<App />);
48
+ expect(capture.runtime).not.toBeNull();
49
+ const core = (
50
+ capture.runtime!.thread as unknown as {
51
+ __internal_threadBinding: {
52
+ getState(): {
53
+ __internal_setGetInitializePromise(
54
+ getPromise: () => Promise<unknown> | undefined,
55
+ ): void;
56
+ append(message: unknown): Promise<void>;
57
+ };
58
+ };
59
+ }
60
+ ).__internal_threadBinding.getState();
61
+ core.__internal_setGetInitializePromise(() => initialization);
62
+
63
+ const appendPromise = core.append({
64
+ parentId: null,
65
+ sourceId: null,
66
+ runConfig: {},
67
+ role: "user",
68
+ content: [{ type: "text", text: "hello" }],
69
+ attachments: [],
70
+ metadata: { custom: {} },
71
+ createdAt: new Date(0),
72
+ });
73
+ await Promise.resolve();
74
+
75
+ expect(onNew).toHaveBeenCalledTimes(1);
76
+
77
+ view.unmount();
78
+ resolveInitialization();
79
+
80
+ await appendPromise;
81
+ expect(onNew).toHaveBeenCalledTimes(1);
82
+ });
83
+ });
@@ -52,20 +52,30 @@ afterEach(() => {
52
52
  describe("useExternalStoreRuntime suggestions scope", () => {
53
53
  it("exposes runtime suggestions on the suggestions scope", () => {
54
54
  render(
55
- <App suggestions={[{ prompt: "Tell me a joke" }, { prompt: "Help" }]} />,
55
+ <App
56
+ suggestions={[
57
+ { title: "Weather", label: "in SF", prompt: "What's the weather?" },
58
+ { prompt: "Help" },
59
+ ]}
60
+ />,
56
61
  );
57
62
 
58
63
  expect(scopeSuggestions).toEqual([
59
- { title: "Tell me a joke", label: "", prompt: "Tell me a joke" },
64
+ { title: "Weather", label: "in SF", prompt: "What's the weather?" },
60
65
  { title: "Help", label: "", prompt: "Help" },
61
66
  ]);
67
+ expect(aui.suggestions.suggestion({ index: 0 }).getState()).toEqual({
68
+ title: "Weather",
69
+ label: "in SF",
70
+ prompt: "What's the weather?",
71
+ });
62
72
  expect(aui.suggestions.suggestion({ index: 1 }).getState()).toEqual({
63
73
  title: "Help",
64
74
  label: "",
65
75
  prompt: "Help",
66
76
  });
67
77
  expect(aui.thread.getState().suggestions).toEqual([
68
- { prompt: "Tell me a joke" },
78
+ { title: "Weather", label: "in SF", prompt: "What's the weather?" },
69
79
  { prompt: "Help" },
70
80
  ]);
71
81
  });
@@ -5,6 +5,7 @@ import { ExternalStoreRuntimeCore } from "../../runtimes/internal";
5
5
  import type { ExternalStoreAdapter } from "../../runtimes/external-store/external-store-adapter";
6
6
  import type { AssistantRuntime } from "../../runtime/api/assistant-runtime";
7
7
  import { AssistantRuntimeImpl } from "../../runtime/internal";
8
+ import { invalidateThreadRuntime } from "../../runtime/utils/thread-runtime-lifecycle";
8
9
  import { useRuntimeAdapters } from "./RuntimeAdapterProvider";
9
10
 
10
11
  export const useExternalStoreRuntime = <T>(
@@ -12,6 +13,12 @@ export const useExternalStoreRuntime = <T>(
12
13
  ): AssistantRuntime => {
13
14
  const [runtime] = useState(() => new ExternalStoreRuntimeCore(store));
14
15
 
16
+ useEffect(() => {
17
+ return () => {
18
+ invalidateThreadRuntime(runtime.threads.getMainThreadRuntimeCore());
19
+ };
20
+ }, [runtime]);
21
+
15
22
  useEffect(() => {
16
23
  runtime.setAdapter(store);
17
24
  });
@@ -16,7 +16,9 @@ export const useExternalStoreSharedOptions = (
16
16
  unstable_capabilities,
17
17
  suggestions,
18
18
  }) satisfies {
19
- [K in keyof Required<ExternalStoreSharedOptions>]: ExternalStoreSharedOptions[K];
19
+ [
20
+ K in keyof Required<ExternalStoreSharedOptions>
21
+ ]: ExternalStoreSharedOptions[K];
20
22
  },
21
23
  [isDisabled, isSendDisabled, unstable_capabilities, suggestions],
22
24
  );
@@ -1,9 +1,10 @@
1
1
  // @vitest-environment jsdom
2
2
 
3
- import { render, waitFor } from "@testing-library/react";
4
- import { StrictMode } from "react";
3
+ import { act, render, waitFor } from "@testing-library/react";
4
+ import { type FC, StrictMode } from "react";
5
5
  import { afterEach, describe, expect, it, vi } from "vitest";
6
6
  import type { AssistantCloud } from "assistant-cloud";
7
+ import { useAui, useAuiState } from "@assistant-ui/store";
7
8
  import type { ChatModelAdapter } from "../../runtime/utils/chat-model-adapter";
8
9
  import { AssistantRuntimeProvider } from "../AssistantRuntimeProvider";
9
10
  import { useLocalRuntime } from "./useLocalRuntime";
@@ -17,13 +18,49 @@ const makeCloud = () =>
17
18
  threads: {
18
19
  list: vi.fn().mockResolvedValue({ threads: [] }),
19
20
  },
21
+ files: {
22
+ generatePresignedUploadUrl: vi.fn().mockResolvedValue({
23
+ signedUrl: "https://storage.example/upload",
24
+ publicUrl: "https://cdn.example/file.txt",
25
+ }),
26
+ },
20
27
  }) as unknown as AssistantCloud;
21
28
 
22
29
  afterEach(() => {
30
+ vi.unstubAllGlobals();
23
31
  vi.restoreAllMocks();
24
32
  });
25
33
 
26
34
  describe("useLocalRuntime", () => {
35
+ it("surfaces the live thread after mount without user input", async () => {
36
+ const auiRef: { current: ReturnType<typeof useAui> | null } = {
37
+ current: null,
38
+ };
39
+ const loadingRef = { current: true };
40
+ const Capture: FC = () => {
41
+ auiRef.current = useAui();
42
+ loadingRef.current = useAuiState((s) => s.thread.isLoading);
43
+ return null;
44
+ };
45
+
46
+ const App = () => {
47
+ const runtime = useLocalRuntime(chatModel, {
48
+ unstable_enableMessageQueue: true,
49
+ });
50
+ return (
51
+ <AssistantRuntimeProvider runtime={runtime}>
52
+ <Capture />
53
+ </AssistantRuntimeProvider>
54
+ );
55
+ };
56
+
57
+ render(<App />);
58
+ await waitFor(() => {
59
+ expect(loadingRef.current).toBe(false);
60
+ expect(auiRef.current!.thread.getState().capabilities.queue).toBe(true);
61
+ });
62
+ });
63
+
27
64
  it("keeps the Cloud thread list loaded across unrelated rerenders", async () => {
28
65
  const firstCloud = makeCloud();
29
66
  const secondCloud = makeCloud();
@@ -46,17 +83,58 @@ describe("useLocalRuntime", () => {
46
83
  const { rerender } = render(<App cloud={firstCloud} label="first" />);
47
84
 
48
85
  await waitFor(() => {
49
- expect(firstCloud.threads.list).toHaveBeenCalledOnce();
86
+ expect(firstCloud.threads.list).toHaveBeenCalledTimes(2);
50
87
  });
51
88
 
52
89
  rerender(<App cloud={firstCloud} label="second" />);
53
- expect(firstCloud.threads.list).toHaveBeenCalledOnce();
90
+ expect(firstCloud.threads.list).toHaveBeenCalledTimes(2);
54
91
 
55
92
  rerender(<App cloud={secondCloud} label="third" />);
56
93
  await waitFor(() => {
57
- expect(secondCloud.threads.list).toHaveBeenCalledOnce();
94
+ expect(secondCloud.threads.list).toHaveBeenCalledTimes(2);
95
+ });
96
+ expect(firstCloud.threads.list).toHaveBeenCalledTimes(2);
97
+ });
98
+
99
+ it("uses the current Cloud client for attachment uploads", async () => {
100
+ vi.stubGlobal("fetch", vi.fn().mockResolvedValue({ ok: true }));
101
+ const firstCloud = makeCloud();
102
+ const secondCloud = makeCloud();
103
+ let addAttachment: ((file: File) => Promise<void>) | undefined;
104
+ let getAttachmentStatus: (() => unknown) | undefined;
105
+
106
+ const App = ({ cloud }: { cloud: AssistantCloud }) => {
107
+ const runtime = useLocalRuntime(chatModel, { cloud });
108
+ addAttachment = (file) => runtime.thread.composer.addAttachment(file);
109
+ getAttachmentStatus = () =>
110
+ runtime.thread.composer.getState().attachments[0]?.status;
111
+ return (
112
+ <AssistantRuntimeProvider runtime={runtime}>
113
+ <div />
114
+ </AssistantRuntimeProvider>
115
+ );
116
+ };
117
+
118
+ const { rerender } = render(<App cloud={firstCloud} />);
119
+
120
+ await waitFor(() => {
121
+ expect(firstCloud.threads.list).toHaveBeenCalledTimes(2);
122
+ });
123
+
124
+ rerender(<App cloud={secondCloud} />);
125
+
126
+ await act(async () => {
127
+ await addAttachment!(
128
+ new File(["hello"], "notes.txt", { type: "text/plain" }),
129
+ );
130
+ });
131
+
132
+ expect(firstCloud.files.generatePresignedUploadUrl).not.toHaveBeenCalled();
133
+ expect(secondCloud.files.generatePresignedUploadUrl).toHaveBeenCalledOnce();
134
+ expect(getAttachmentStatus!()).toEqual({
135
+ type: "requires-action",
136
+ reason: "composer-send",
58
137
  });
59
- expect(firstCloud.threads.list).toHaveBeenCalledOnce();
60
138
  });
61
139
 
62
140
  it("handles rejected history loads", async () => {
@@ -92,8 +170,56 @@ describe("useLocalRuntime", () => {
92
170
  );
93
171
  });
94
172
 
173
+ const loadsAfterMount = history.load.mock.calls.length;
174
+ const errorsAfterMount = consoleError.mock.calls.length;
175
+ expect(loadsAfterMount).toBeGreaterThan(0);
95
176
  rerender(renderApp());
96
- expect(history.load).toHaveBeenCalledTimes(1);
97
- expect(consoleError).toHaveBeenCalledTimes(1);
177
+ expect(history.load).toHaveBeenCalledTimes(loadsAfterMount);
178
+ expect(consoleError).toHaveBeenCalledTimes(errorsAfterMount);
179
+ });
180
+
181
+ it("exposes composer.canCancel while a run started after initial messages is in flight", async () => {
182
+ const hangingModel: ChatModelAdapter = {
183
+ async *run({ abortSignal }) {
184
+ await new Promise<void>((resolve) => {
185
+ if (abortSignal.aborted) {
186
+ resolve();
187
+ return;
188
+ }
189
+ abortSignal.addEventListener("abort", () => resolve(), {
190
+ once: true,
191
+ });
192
+ });
193
+ },
194
+ };
195
+ let runtime: ReturnType<typeof useLocalRuntime> | null = null;
196
+ const App = () => {
197
+ runtime = useLocalRuntime(hangingModel, {
198
+ initialMessages: [
199
+ {
200
+ role: "assistant",
201
+ content: [{ type: "text", text: "Hello" }],
202
+ status: { type: "complete", reason: "stop" },
203
+ },
204
+ ],
205
+ });
206
+ return (
207
+ <AssistantRuntimeProvider runtime={runtime}>
208
+ <div />
209
+ </AssistantRuntimeProvider>
210
+ );
211
+ };
212
+
213
+ render(<App />);
214
+ act(() => {
215
+ runtime!.thread.append("Run");
216
+ });
217
+ await waitFor(() => {
218
+ expect(runtime!.thread.getState().isRunning).toBe(true);
219
+ expect(runtime!.thread.composer.getState().canCancel).toBe(true);
220
+ });
221
+ act(() => {
222
+ runtime!.thread.cancelRun();
223
+ });
98
224
  });
99
225
  });