@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
@@ -14,6 +14,12 @@ import {
14
14
  } from "assistant-cloud";
15
15
  import { auiV0Decode, auiV0Encode } from "./auiV0";
16
16
  import { type AssistantClient, getClientId, useAui } from "@assistant-ui/store";
17
+ import type { ThreadListItemMethods } from "../../../store/scopes/thread-list-item";
18
+
19
+ type CloudThreadListItem = Pick<
20
+ ThreadListItemMethods,
21
+ "getState" | "initialize"
22
+ >;
17
23
 
18
24
  const globalPersistence = new WeakMap<
19
25
  getClientId.ClientId,
@@ -36,8 +42,10 @@ class AssistantCloudThreadHistoryAdapter implements ThreadHistoryAdapter {
36
42
  return this.getAui();
37
43
  }
38
44
 
39
- private get _persistence(): CloudMessagePersistence {
40
- const key = getClientId(this.aui.threadListItem);
45
+ private getPersistence(
46
+ threadListItem: CloudThreadListItem = this.aui.threadListItem,
47
+ ): CloudMessagePersistence {
48
+ const key = getClientId(threadListItem);
41
49
  if (!globalPersistence.has(key)) {
42
50
  globalPersistence.set(
43
51
  key,
@@ -47,24 +55,57 @@ class AssistantCloudThreadHistoryAdapter implements ThreadHistoryAdapter {
47
55
  return globalPersistence.get(key)!;
48
56
  }
49
57
 
58
+ private get _persistence(): CloudMessagePersistence {
59
+ return this.getPersistence();
60
+ }
61
+
62
+ private tryGetKeyedThreadListItem(): CloudThreadListItem | undefined {
63
+ const live = this.aui.threadListItem;
64
+ if (!live.source) return undefined;
65
+ const id = live.getState().id;
66
+ if (id === undefined) return undefined;
67
+ return this.aui.threads.item({ id });
68
+ }
69
+
50
70
  withFormat<TMessage, TStorageFormat extends Record<string, unknown>>(
51
71
  formatAdapter: MessageFormatAdapter<TMessage, TStorageFormat>,
52
72
  ): GenericThreadHistoryAdapter<TMessage> {
53
73
  const adapter = this;
54
- const formatted = createFormattedPersistence(
55
- this._persistence,
56
- formatAdapter,
57
- );
74
+ let threadListItem: CloudThreadListItem | undefined;
75
+ const pinCurrent = () => {
76
+ const next = adapter.tryGetKeyedThreadListItem();
77
+ if (next) threadListItem = next;
78
+ return threadListItem;
79
+ };
80
+ const resolvePinned = () => threadListItem ?? pinCurrent();
81
+ const getFormatted = () =>
82
+ createFormattedPersistence(adapter._persistence, formatAdapter);
83
+ const getTargetFormatted = (item: CloudThreadListItem) =>
84
+ createFormattedPersistence(adapter.getPersistence(item), formatAdapter);
58
85
  return {
59
- // Note: callers must also call reportTelemetry() for run tracking
86
+ pin() {
87
+ pinCurrent();
88
+ },
60
89
  async append(item: MessageFormatItem<TMessage>) {
61
- const { remoteId } = await adapter.aui.threadListItem.initialize();
62
- await formatted.append(remoteId, item);
90
+ const pinned = resolvePinned();
91
+ if (!pinned) {
92
+ throw new Error(
93
+ "Cannot persist cloud history without a thread list item.",
94
+ );
95
+ }
96
+ const remoteId =
97
+ pinned.getState().remoteId ?? (await pinned.initialize()).remoteId;
98
+ await getTargetFormatted(pinned).append(remoteId, item);
63
99
  },
64
100
  async update(item: MessageFormatItem<TMessage>, localMessageId: string) {
65
- const remoteId = adapter.aui.threadListItem.getState().remoteId;
66
- if (!remoteId) return;
67
- await formatted.update?.(remoteId, item, localMessageId);
101
+ const pinned = resolvePinned();
102
+ const remoteId = pinned?.getState().remoteId;
103
+ if (!remoteId || !pinned) return;
104
+ await getTargetFormatted(pinned).update?.(
105
+ remoteId,
106
+ item,
107
+ localMessageId,
108
+ );
68
109
  },
69
110
  async delete() {
70
111
  throw new Error(
@@ -85,12 +126,15 @@ class AssistantCloudThreadHistoryAdapter implements ThreadHistoryAdapter {
85
126
  formatAdapter.format,
86
127
  encodedRunMessages,
87
128
  options,
129
+ resolvePinned(),
88
130
  );
89
131
  },
90
132
  async load(): Promise<MessageFormatRepository<TMessage>> {
91
- const remoteId = adapter.aui.threadListItem.getState().remoteId;
133
+ pinCurrent();
134
+ const live = adapter.aui.threadListItem;
135
+ const remoteId = live.source ? live.getState().remoteId : undefined;
92
136
  if (!remoteId) return { messages: [] };
93
- return formatted.load(remoteId);
137
+ return getFormatted().load(remoteId);
94
138
  },
95
139
  };
96
140
  }
@@ -153,10 +197,12 @@ class AssistantCloudThreadHistoryAdapter implements ThreadHistoryAdapter {
153
197
  durationMs?: number;
154
198
  stepTimestamps?: StepTimestamp[];
155
199
  },
200
+ threadListItem?: CloudThreadListItem,
156
201
  ) {
157
202
  if (!this.cloudRef.current.telemetry.enabled) return;
158
203
 
159
- const remoteId = this.aui.threadListItem.getState().remoteId;
204
+ const remoteId = (threadListItem ?? this.aui.threadListItem).getState()
205
+ .remoteId;
160
206
  if (!remoteId) return;
161
207
 
162
208
  const extracted = extractRunTelemetry(format, runMessages);
@@ -19,10 +19,12 @@ const guessAttachmentType = (
19
19
  export class CloudFileAttachmentAdapter implements AttachmentAdapter {
20
20
  public accept = "*";
21
21
 
22
- private cloud: AssistantCloud;
22
+ private getCloud: () => AssistantCloud;
23
23
 
24
- constructor(cloud: AssistantCloud) {
25
- this.cloud = cloud;
24
+ constructor(cloud: AssistantCloud);
25
+ constructor(getCloud: () => AssistantCloud);
26
+ constructor(cloud: AssistantCloud | (() => AssistantCloud)) {
27
+ this.getCloud = typeof cloud === "function" ? cloud : () => cloud;
26
28
  }
27
29
 
28
30
  private uploadedUrls = new Map<string, string>();
@@ -46,7 +48,7 @@ export class CloudFileAttachmentAdapter implements AttachmentAdapter {
46
48
 
47
49
  try {
48
50
  const { signedUrl, publicUrl } =
49
- await this.cloud.files.generatePresignedUploadUrl({
51
+ await this.getCloud().files.generatePresignedUploadUrl({
50
52
  filename: file.name,
51
53
  });
52
54
  const res = await fetch(signedUrl, {
@@ -79,6 +79,11 @@ type AuiV0MessagePart =
79
79
  readonly mimeType: string;
80
80
  readonly filename?: string;
81
81
  readonly sourceType?: "url" | "id";
82
+ }
83
+ | {
84
+ readonly type: "data";
85
+ readonly name: string;
86
+ readonly data: ReadonlyJSONValue;
82
87
  };
83
88
 
84
89
  type AuiV0AttachmentPart =
@@ -296,8 +301,19 @@ export function auiV0Encode(message: ThreadMessage): AuiV0Message {
296
301
  ...(part.sourceType ? { sourceType: part.sourceType } : undefined),
297
302
  };
298
303
 
304
+ case "data": {
305
+ if (!isJSONValue(part.data)) {
306
+ console.warn(`data part is not JSON! ${JSON.stringify(part)}`);
307
+ }
308
+ return {
309
+ type: "data",
310
+ name: part.name,
311
+ data: part.data as ReadonlyJSONValue,
312
+ };
313
+ }
314
+
299
315
  default: {
300
- const unhandledType: "audio" | "data" | "generative-ui" = type;
316
+ const unhandledType: "audio" | "generative-ui" = type;
301
317
  throw new Error(
302
318
  `Message part type not supported by aui/v0: ${unhandledType}`,
303
319
  );
@@ -3,16 +3,21 @@ declare const process: { env: Record<string, string | undefined> };
3
3
  import {
4
4
  type FC,
5
5
  type PropsWithChildren,
6
+ type RefObject,
6
7
  useCallback,
7
8
  useEffect,
8
9
  useMemo,
9
10
  useRef,
11
+ useState,
10
12
  } from "react";
11
13
  import { AssistantCloud } from "assistant-cloud";
12
14
  import type { RemoteThreadListAdapter } from "../../../runtimes/remote-thread-list/types";
13
15
  import { InMemoryThreadListAdapter } from "../../../runtimes/remote-thread-list/adapter/in-memory";
14
16
  import { useAssistantCloudThreadHistoryAdapter } from "./AssistantCloudThreadHistoryAdapter";
15
- import { RuntimeAdapterProvider } from "../RuntimeAdapterProvider";
17
+ import {
18
+ RuntimeAdapterProvider,
19
+ type RuntimeAdapters,
20
+ } from "../RuntimeAdapterProvider";
16
21
  import { CloudFileAttachmentAdapter } from "./CloudFileAttachmentAdapter";
17
22
  import { isRecord } from "../../../utils/json/is-json";
18
23
 
@@ -39,6 +44,29 @@ const autoCloud = baseUrl
39
44
 
40
45
  const CLOUD_THREAD_PAGE_SIZE = 20;
41
46
 
47
+ const useCloudThreadListAdapters = (
48
+ adapterRef: RefObject<CloudThreadListAdapterOptions>,
49
+ ): RuntimeAdapters => {
50
+ const history = useAssistantCloudThreadHistoryAdapter({
51
+ get current() {
52
+ return adapterRef.current.cloud ?? autoCloud!;
53
+ },
54
+ });
55
+ const [attachments] = useState(
56
+ () =>
57
+ new CloudFileAttachmentAdapter(
58
+ () => adapterRef.current.cloud ?? autoCloud!,
59
+ ),
60
+ );
61
+ return useMemo(
62
+ () => ({
63
+ history,
64
+ attachments,
65
+ }),
66
+ [history, attachments],
67
+ );
68
+ };
69
+
42
70
  export const useCloudThreadListAdapter = (
43
71
  adapter: CloudThreadListAdapterOptions,
44
72
  ): RemoteThreadListAdapter => {
@@ -47,27 +75,13 @@ export const useCloudThreadListAdapter = (
47
75
  adapterRef.current = adapter;
48
76
  }, [adapter]);
49
77
 
78
+ const unstable_useAdapters = useCallback(function useCloudAdapters() {
79
+ return useCloudThreadListAdapters(adapterRef);
80
+ }, []);
81
+
50
82
  const unstable_Provider = useCallback<FC<PropsWithChildren>>(
51
83
  function Provider({ children }) {
52
- const history = useAssistantCloudThreadHistoryAdapter({
53
- get current() {
54
- return adapterRef.current.cloud ?? autoCloud!;
55
- },
56
- });
57
- const cloudInstance = adapterRef.current.cloud ?? autoCloud!;
58
- const attachments = useMemo(
59
- () => new CloudFileAttachmentAdapter(cloudInstance),
60
- [cloudInstance],
61
- );
62
-
63
- const adapters = useMemo(
64
- () => ({
65
- history,
66
- attachments,
67
- }),
68
- [history, attachments],
69
- );
70
-
84
+ const adapters = useCloudThreadListAdapters(adapterRef);
71
85
  return (
72
86
  <RuntimeAdapterProvider adapters={adapters}>
73
87
  {children}
@@ -175,6 +189,7 @@ export const useCloudThreadListAdapter = (
175
189
  },
176
190
 
177
191
  unstable_Provider,
192
+ unstable_useAdapters,
178
193
  };
179
- }, [cloud, unstable_Provider]);
194
+ }, [cloud, unstable_Provider, unstable_useAdapters]);
180
195
  };
@@ -0,0 +1,56 @@
1
+ // @vitest-environment jsdom
2
+
3
+ import { renderHook } from "@testing-library/react";
4
+ import type { AssistantCloud } from "assistant-cloud";
5
+ import { describe, expect, it, vi } from "vitest";
6
+ import type { AssistantRuntime } from "../../../runtime/api/assistant-runtime";
7
+ import { useCloudThreadListRuntime } from "./useCloudThreadListRuntime";
8
+
9
+ const mocks = vi.hoisted(() => ({
10
+ useCloudThreadListAdapter: vi.fn(),
11
+ useRemoteThreadListRuntime: vi.fn(),
12
+ }));
13
+
14
+ vi.mock("./useCloudThreadListAdapter", async (importOriginal) => ({
15
+ ...(await importOriginal<typeof import("./useCloudThreadListAdapter")>()),
16
+ useCloudThreadListAdapter: mocks.useCloudThreadListAdapter,
17
+ }));
18
+
19
+ vi.mock("../useRemoteThreadListRuntime", async (importOriginal) => ({
20
+ ...(await importOriginal<typeof import("../useRemoteThreadListRuntime")>()),
21
+ useRemoteThreadListRuntime: mocks.useRemoteThreadListRuntime,
22
+ }));
23
+
24
+ describe("useCloudThreadListRuntime", () => {
25
+ it("forwards cloud options to the adapter and nests the runtime hook", () => {
26
+ const cloud = { threads: {} } as AssistantCloud;
27
+ const runtimeHook = () => ({}) as AssistantRuntime;
28
+ const create = vi.fn();
29
+ const del = vi.fn();
30
+ const adapter = { list: vi.fn() };
31
+ const runtime = { kind: "runtime" };
32
+ mocks.useCloudThreadListAdapter.mockReturnValue(adapter);
33
+ mocks.useRemoteThreadListRuntime.mockReturnValue(runtime);
34
+
35
+ const { result } = renderHook(() =>
36
+ useCloudThreadListRuntime({
37
+ cloud,
38
+ runtimeHook,
39
+ create,
40
+ delete: del,
41
+ }),
42
+ );
43
+
44
+ expect(mocks.useCloudThreadListAdapter).toHaveBeenCalledWith({
45
+ cloud,
46
+ create,
47
+ delete: del,
48
+ });
49
+ expect(mocks.useRemoteThreadListRuntime).toHaveBeenCalledWith({
50
+ runtimeHook,
51
+ adapter,
52
+ allowNesting: true,
53
+ });
54
+ expect(result.current).toBe(runtime);
55
+ });
56
+ });
@@ -0,0 +1,31 @@
1
+ "use client";
2
+
3
+ import type { AssistantCloud } from "assistant-cloud";
4
+ import type { AssistantRuntime } from "../../../runtime/api/assistant-runtime";
5
+ import { useRemoteThreadListRuntime } from "../useRemoteThreadListRuntime";
6
+ import { useCloudThreadListAdapter } from "./useCloudThreadListAdapter";
7
+
8
+ type ThreadData = {
9
+ externalId: string;
10
+ };
11
+
12
+ type CloudThreadListAdapter = {
13
+ cloud: AssistantCloud;
14
+
15
+ runtimeHook: () => AssistantRuntime;
16
+
17
+ create?(): Promise<ThreadData>;
18
+ delete?(threadId: string): Promise<void>;
19
+ };
20
+
21
+ export function useCloudThreadListRuntime({
22
+ runtimeHook,
23
+ ...adapterOptions
24
+ }: CloudThreadListAdapter) {
25
+ const adapter = useCloudThreadListAdapter(adapterOptions);
26
+ return useRemoteThreadListRuntime({
27
+ runtimeHook,
28
+ adapter,
29
+ allowNesting: true,
30
+ });
31
+ }
@@ -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
+ });