@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
@@ -0,0 +1,62 @@
1
+ // @vitest-environment jsdom
2
+
3
+ import { renderHook } from "@testing-library/react";
4
+ import { describe, expect, it } from "vitest";
5
+ import { useStableRuntimeAdapters } from "./useRuntimeAdapters";
6
+ import type { RuntimeAdapters } from "../../runtimes/remote-thread-list/types";
7
+ import type { ThreadHistoryAdapter } from "../../adapters/thread-history";
8
+
9
+ const makeHistory = (): ThreadHistoryAdapter => ({
10
+ load: async () => ({ messages: [] }),
11
+ append: async () => {},
12
+ });
13
+
14
+ describe("useStableRuntimeAdapters", () => {
15
+ it("keeps the previous bag when a fresh literal is shallow-equal", () => {
16
+ const history = makeHistory();
17
+ const { result, rerender } = renderHook(
18
+ ({ adapters }: { adapters: RuntimeAdapters | null }) =>
19
+ useStableRuntimeAdapters(adapters),
20
+ { initialProps: { adapters: { history } } },
21
+ );
22
+ const first = result.current;
23
+
24
+ rerender({ adapters: { history } });
25
+
26
+ expect(result.current).toBe(first);
27
+ });
28
+
29
+ it("adopts the new bag when a field changes", () => {
30
+ const first = makeHistory();
31
+ const second = makeHistory();
32
+ const { result, rerender } = renderHook(
33
+ ({ adapters }: { adapters: RuntimeAdapters | null }) =>
34
+ useStableRuntimeAdapters(adapters),
35
+ { initialProps: { adapters: { history: first } } },
36
+ );
37
+
38
+ rerender({ adapters: { history: second } });
39
+
40
+ expect(result.current?.history).toBe(second);
41
+ });
42
+
43
+ it("moves between null and a bag", () => {
44
+ const history = makeHistory();
45
+ const { result, rerender } = renderHook(
46
+ ({ adapters }: { adapters: RuntimeAdapters | null }) =>
47
+ useStableRuntimeAdapters(adapters),
48
+ { initialProps: { adapters: null as RuntimeAdapters | null } },
49
+ );
50
+ expect(result.current).toBeNull();
51
+
52
+ rerender({ adapters: { history } });
53
+ expect(result.current?.history).toBe(history);
54
+
55
+ rerender({ adapters: null });
56
+ expect(result.current).toBeNull();
57
+
58
+ rerender({ adapters: {} });
59
+ expect(result.current).not.toBeNull();
60
+ expect(result.current).toEqual({});
61
+ });
62
+ });
@@ -0,0 +1,28 @@
1
+ import { createContext, useContext } from "react";
2
+ import { useContextProvider } from "@assistant-ui/tap";
3
+ import { useShallowStable } from "@assistant-ui/store/internal";
4
+ import type { RuntimeAdapters } from "../../runtimes/remote-thread-list/types";
5
+
6
+ const RuntimeAdaptersContext = createContext<RuntimeAdapters | null>(null);
7
+
8
+ export const useRuntimeAdaptersProvider = <T>(
9
+ adapters: RuntimeAdapters | null,
10
+ fn: () => T,
11
+ ): T => useContextProvider(RuntimeAdaptersContext, adapters, fn);
12
+
13
+ export const useRuntimeAdapters = () => {
14
+ return useContext(RuntimeAdaptersContext);
15
+ };
16
+
17
+ const NO_ADAPTERS: RuntimeAdapters = {};
18
+
19
+ // Both adapter faces absorb a fresh but shallow-equal bag from
20
+ // `unstable_useAdapters`, so a per-render literal does not churn the context.
21
+ export const useStableRuntimeAdapters = (
22
+ adapters: RuntimeAdapters | null | undefined,
23
+ ): RuntimeAdapters | null => {
24
+ const stable = useShallowStable(adapters ?? NO_ADAPTERS);
25
+ return adapters == null ? null : stable;
26
+ };
27
+
28
+ export { RuntimeAdaptersContext };
@@ -42,6 +42,11 @@ export type {
42
42
  };
43
43
 
44
44
  type BaseComposerState = {
45
+ /**
46
+ * Whether the composer can cancel the current run. `true` when the runtime
47
+ * supports cancel and a run is in flight, not merely when cancel is a
48
+ * capability.
49
+ */
45
50
  readonly canCancel: boolean;
46
51
  readonly canSend: boolean;
47
52
  readonly isEditing: boolean;
@@ -114,6 +114,7 @@ export type ThreadListRuntimeCoreBinding = ThreadListRuntimeCore;
114
114
 
115
115
  export class ThreadListRuntimeImpl implements ThreadListRuntime {
116
116
  private _getState;
117
+ private _stateBinding: LazyMemoizeSubject<ThreadListState, object>;
117
118
  private _core: ThreadListRuntimeCoreBinding;
118
119
  private _runtimeFactory: new (
119
120
  binding: ThreadRuntimeCoreBinding,
@@ -136,6 +137,7 @@ export class ThreadListRuntimeImpl implements ThreadListRuntime {
136
137
  });
137
138
 
138
139
  this._getState = stateBinding.getState.bind(stateBinding);
140
+ this._stateBinding = stateBinding;
139
141
 
140
142
  this._mainThreadListItemRuntime = new ThreadListItemRuntimeImpl(
141
143
  new ShallowMemoizeSubject({
@@ -213,7 +215,7 @@ export class ThreadListRuntimeImpl implements ThreadListRuntime {
213
215
  }
214
216
 
215
217
  public subscribe(callback: () => void): Unsubscribe {
216
- return this._core.subscribe(callback);
218
+ return this._stateBinding.subscribe(callback);
217
219
  }
218
220
 
219
221
  private _mainThreadListItemRuntime;
@@ -199,7 +199,7 @@ export type ThreadState = {
199
199
  * reports it directly; the rest fall back to the trailing assistant message.
200
200
  */
201
201
  export const getThreadRuntimeCoreIsRunning = (
202
- runtime: ThreadRuntimeCore,
202
+ runtime: Pick<ThreadRuntimeCore, "isRunning" | "messages">,
203
203
  ): boolean => {
204
204
  if (runtime.isRunning !== undefined) return runtime.isRunning;
205
205
  const lastMessage = runtime.messages.at(-1);
@@ -294,6 +294,13 @@ export type ThreadRuntime = {
294
294
 
295
295
  subscribe(callback: () => void): Unsubscribe;
296
296
  cancelRun(): void;
297
+ /**
298
+ * Notifies the runtime that the adapter discarded its backing session.
299
+ * Clears session-scoped tool-invocation state without run-cancel side
300
+ * effects such as composer draft restoration. Internal API for
301
+ * external-store adapter authors.
302
+ */
303
+ unstable_notifySessionReset(): void;
297
304
  getModelContext(): ModelContext;
298
305
 
299
306
  export(): ExportedMessageRepository;
@@ -339,6 +346,10 @@ export class ThreadRuntimeImpl implements ThreadRuntime {
339
346
  private readonly _threadBinding: ThreadRuntimeCoreBinding & {
340
347
  getStateState(): ThreadState;
341
348
  };
349
+ private readonly _stateBinding: ShallowMemoizeSubject<
350
+ ThreadState,
351
+ ThreadRuntimePath
352
+ >;
342
353
 
343
354
  constructor(
344
355
  threadBinding: ThreadRuntimeCoreBinding,
@@ -361,6 +372,7 @@ export class ThreadRuntimeImpl implements ThreadRuntime {
361
372
  },
362
373
  });
363
374
 
375
+ this._stateBinding = stateBinding;
364
376
  this._threadBinding = {
365
377
  path: threadBinding.path,
366
378
  getState: () => threadBinding.getState(),
@@ -392,6 +404,8 @@ export class ThreadRuntimeImpl implements ThreadRuntime {
392
404
  this.exportExternalState = this.exportExternalState.bind(this);
393
405
  this.startRun = this.startRun.bind(this);
394
406
  this.cancelRun = this.cancelRun.bind(this);
407
+ this.unstable_notifySessionReset =
408
+ this.unstable_notifySessionReset.bind(this);
395
409
  this.stopSpeaking = this.stopSpeaking.bind(this);
396
410
  this.connectVoice = this.connectVoice.bind(this);
397
411
  this.disconnectVoice = this.disconnectVoice.bind(this);
@@ -435,7 +449,7 @@ export class ThreadRuntimeImpl implements ThreadRuntime {
435
449
  }
436
450
 
437
451
  public subscribe(callback: () => void) {
438
- return this._threadBinding.subscribe(callback);
452
+ return this._stateBinding.subscribe(callback);
439
453
  }
440
454
 
441
455
  public getModelContext() {
@@ -462,6 +476,10 @@ export class ThreadRuntimeImpl implements ThreadRuntime {
462
476
  this._threadBinding.getState().cancelRun();
463
477
  }
464
478
 
479
+ public unstable_notifySessionReset() {
480
+ this._threadBinding.getState().unstable_notifySessionReset();
481
+ }
482
+
465
483
  public stopSpeaking() {
466
484
  return this._threadBinding.getState().stopSpeaking();
467
485
  }
@@ -240,6 +240,8 @@ export abstract class BaseComposerRuntimeCore
240
240
  const originalAttachments = this.attachments;
241
241
  const text = this.text;
242
242
  const quote = this._quote;
243
+ const role = this.role;
244
+ const runConfig = this.runConfig;
243
245
  this._quote = undefined;
244
246
  this._text = "";
245
247
  this._isSending = true;
@@ -291,10 +293,10 @@ export abstract class BaseComposerRuntimeCore
291
293
 
292
294
  const message: Omit<AppendMessage, "parentId" | "sourceId"> = {
293
295
  createdAt: new Date(),
294
- role: this.role,
296
+ role,
295
297
  content: text ? [{ type: "text", text }] : [],
296
298
  attachments: finalAttachments,
297
- runConfig: this.runConfig,
299
+ runConfig,
298
300
  metadata: { custom: { ...(quote ? { quote } : {}) } },
299
301
  };
300
302
 
@@ -718,9 +720,8 @@ export abstract class BaseComposerRuntimeCore
718
720
 
719
721
  const session = this._dictationSession;
720
722
  const sessionId = this._activeDictationSessionId;
721
- session.stop().finally(() => {
722
- this._cleanupDictation({ sessionId });
723
- });
723
+ const cleanup = () => this._cleanupDictation({ sessionId });
724
+ void session.stop().then(cleanup, cleanup);
724
725
  }
725
726
 
726
727
  private _cleanupDictation(options?: { sessionId: number | undefined }): void {
@@ -0,0 +1,191 @@
1
+ import { afterEach, describe, expect, it, vi } from "vitest";
2
+ import type { RealtimeVoiceAdapter } from "../../adapters/voice";
3
+ import type { AppendMessage } from "../../types/message";
4
+ import type {
5
+ AddToolResultOptions,
6
+ ResumeRunConfig,
7
+ ResumeToolCallOptions,
8
+ RespondToToolApprovalOptions,
9
+ RuntimeCapabilities,
10
+ StartRunConfig,
11
+ ThreadSuggestion,
12
+ } from "../interfaces/thread-runtime-core";
13
+ import { BaseThreadRuntimeCore } from "./base-thread-runtime-core";
14
+
15
+ const createVoiceAdapter = () => {
16
+ let volumeCallback: ((volume: number) => void) | undefined;
17
+ const session: RealtimeVoiceAdapter.Session = {
18
+ status: { type: "running" },
19
+ isMuted: false,
20
+ disconnect: vi.fn(),
21
+ mute: vi.fn(),
22
+ unmute: vi.fn(),
23
+ onStatusChange: () => () => {},
24
+ onTranscript: () => () => {},
25
+ onModeChange: () => () => {},
26
+ onVolumeChange: (callback) => {
27
+ volumeCallback = callback;
28
+ return () => {
29
+ volumeCallback = undefined;
30
+ };
31
+ },
32
+ };
33
+
34
+ return {
35
+ adapter: { connect: () => session },
36
+ emitVolume: (volume: number) => volumeCallback?.(volume),
37
+ session,
38
+ } satisfies {
39
+ adapter: RealtimeVoiceAdapter;
40
+ emitVolume: (volume: number) => void;
41
+ session: RealtimeVoiceAdapter.Session;
42
+ };
43
+ };
44
+
45
+ class TestRuntime extends BaseThreadRuntimeCore {
46
+ private readonly voiceAdapter: ReturnType<typeof createVoiceAdapter>;
47
+
48
+ constructor(voiceAdapter: ReturnType<typeof createVoiceAdapter>) {
49
+ super({ getModelContext: () => ({}) });
50
+ this.voiceAdapter = voiceAdapter;
51
+ }
52
+
53
+ get adapters() {
54
+ return { voice: this.voiceAdapter.adapter };
55
+ }
56
+
57
+ get isDisabled() {
58
+ return false;
59
+ }
60
+
61
+ get isSendDisabled() {
62
+ return false;
63
+ }
64
+
65
+ get isLoading() {
66
+ return false;
67
+ }
68
+
69
+ get suggestions(): readonly ThreadSuggestion[] {
70
+ return [];
71
+ }
72
+
73
+ get extras() {
74
+ return undefined;
75
+ }
76
+
77
+ get capabilities(): RuntimeCapabilities {
78
+ return {
79
+ switchToBranch: false,
80
+ switchBranchDuringRun: false,
81
+ edit: false,
82
+ delete: false,
83
+ reload: false,
84
+ refetchThread: false,
85
+ cancel: false,
86
+ unstable_copy: false,
87
+ speech: false,
88
+ dictation: false,
89
+ voice: true,
90
+ attachments: false,
91
+ feedback: false,
92
+ queue: false,
93
+ };
94
+ }
95
+
96
+ append(_message: AppendMessage) {}
97
+ deleteMessage(_messageId: string) {}
98
+ startRun(_config: StartRunConfig) {}
99
+ resumeRun(_config: ResumeRunConfig) {}
100
+ addToolResult(_options: AddToolResultOptions) {}
101
+ resumeToolCall(_options: ResumeToolCallOptions) {}
102
+ respondToToolApproval(_options: RespondToToolApprovalOptions) {}
103
+ cancelRun() {}
104
+ exportExternalState() {
105
+ return {};
106
+ }
107
+ importExternalState(_state: unknown) {}
108
+ unstable_notifySessionReset() {}
109
+ }
110
+
111
+ afterEach(() => {
112
+ vi.restoreAllMocks();
113
+ });
114
+
115
+ describe("BaseThreadRuntimeCore voice volume subscriptions", () => {
116
+ it("continues notifying subscribers when one throws", () => {
117
+ const consoleError = vi
118
+ .spyOn(console, "error")
119
+ .mockImplementation(() => {});
120
+ const voice = createVoiceAdapter();
121
+ const runtime = new TestRuntime(voice);
122
+ runtime.connectVoice();
123
+
124
+ const listenerError = new Error("listener failed");
125
+ const laterListener = vi.fn();
126
+ runtime.subscribeVoiceVolume(() => {
127
+ throw listenerError;
128
+ });
129
+ runtime.subscribeVoiceVolume(laterListener);
130
+
131
+ expect(() => voice.emitVolume(0.5)).not.toThrow();
132
+ expect(laterListener).toHaveBeenCalledOnce();
133
+ expect(runtime.getVoiceVolume()).toBe(0.5);
134
+ expect(consoleError).toHaveBeenCalledWith(
135
+ "[assistant-ui] Voice volume listener threw an error",
136
+ listenerError,
137
+ );
138
+ });
139
+
140
+ it("continues disconnect cleanup when a subscriber throws", () => {
141
+ const consoleError = vi
142
+ .spyOn(console, "error")
143
+ .mockImplementation(() => {});
144
+ const voice = createVoiceAdapter();
145
+ const runtime = new TestRuntime(voice);
146
+ runtime.connectVoice();
147
+
148
+ const listenerError = new Error("disconnect listener failed");
149
+ const laterListener = vi.fn();
150
+ runtime.subscribeVoiceVolume(() => {
151
+ throw listenerError;
152
+ });
153
+ runtime.subscribeVoiceVolume(laterListener);
154
+
155
+ expect(() => runtime.disconnectVoice()).not.toThrow();
156
+ expect(laterListener).toHaveBeenCalledOnce();
157
+ expect(runtime.getVoiceVolume()).toBe(0);
158
+ expect(runtime.voice).toBeUndefined();
159
+ expect(voice.session.disconnect).toHaveBeenCalledOnce();
160
+ expect(consoleError).toHaveBeenCalledWith(
161
+ "[assistant-ui] Voice volume listener threw an error",
162
+ listenerError,
163
+ );
164
+ });
165
+
166
+ it("reports rejected subscriber thenables", async () => {
167
+ const consoleError = vi
168
+ .spyOn(console, "error")
169
+ .mockImplementation(() => {});
170
+ const voice = createVoiceAdapter();
171
+ const runtime = new TestRuntime(voice);
172
+ runtime.connectVoice();
173
+
174
+ const listenerError = new Error("async listener failed");
175
+ const laterListener = vi.fn();
176
+ runtime.subscribeVoiceVolume(async () => {
177
+ throw listenerError;
178
+ });
179
+ runtime.subscribeVoiceVolume(laterListener);
180
+
181
+ voice.emitVolume(0.5);
182
+
183
+ await vi.waitFor(() => {
184
+ expect(laterListener).toHaveBeenCalledOnce();
185
+ expect(consoleError).toHaveBeenCalledWith(
186
+ "[assistant-ui] Voice volume listener threw an error",
187
+ listenerError,
188
+ );
189
+ });
190
+ });
191
+ });
@@ -69,6 +69,7 @@ export abstract class BaseThreadRuntimeCore implements ThreadRuntimeCore {
69
69
  public abstract cancelRun(): void;
70
70
  public abstract exportExternalState(): any;
71
71
  public abstract importExternalState(state: any): void;
72
+ public abstract unstable_notifySessionReset(): void;
72
73
 
73
74
  protected _voiceMessages: ThreadMessage[] = [];
74
75
  protected _voiceGeneration = 0;
@@ -355,7 +356,11 @@ export abstract class BaseThreadRuntimeCore implements ThreadRuntimeCore {
355
356
  unsubs.push(
356
357
  session.onVolumeChange((volume) => {
357
358
  this._voiceVolume = volume;
358
- for (const cb of this._voiceVolumeSubscribers) cb();
359
+ notifyEventListeners(
360
+ this._voiceVolumeSubscribers,
361
+ undefined,
362
+ "Voice volume",
363
+ );
359
364
  }),
360
365
  );
361
366
 
@@ -454,7 +459,11 @@ export abstract class BaseThreadRuntimeCore implements ThreadRuntimeCore {
454
459
  this._voiceSession = undefined;
455
460
  this.voice = undefined;
456
461
  this._voiceVolume = 0;
457
- for (const cb of this._voiceVolumeSubscribers) cb();
462
+ notifyEventListeners(
463
+ this._voiceVolumeSubscribers,
464
+ undefined,
465
+ "Voice volume",
466
+ );
458
467
  this._voiceMessages = [];
459
468
  this._markVoiceMessagesDirty();
460
469
  this._notifySubscribers();
@@ -6,6 +6,7 @@ import type {
6
6
  ThreadComposerRuntimeCore,
7
7
  } from "../interfaces/composer-runtime-core";
8
8
  import type { ThreadRuntimeCore } from "../interfaces/thread-runtime-core";
9
+ import { getThreadRuntimeCoreIsRunning } from "../api/thread-runtime";
9
10
  import type { QueuePlacement } from "../queue/external-thread-queue-adapter";
10
11
  import {
11
12
  EMPTY_QUEUE_ITEMS,
@@ -13,13 +14,18 @@ import {
13
14
  } from "../../store/scopes/queue-item";
14
15
  import { BaseComposerRuntimeCore } from "./base-composer-runtime-core";
15
16
 
17
+ const isCancelable = (runtime: Omit<ThreadRuntimeCore, "composer">) => {
18
+ // capabilities is a subclass field assigned after this composer is constructed
19
+ if (!runtime.capabilities?.cancel) return false;
20
+ return getThreadRuntimeCoreIsRunning(runtime);
21
+ };
22
+
16
23
  export class DefaultThreadComposerRuntimeCore
17
24
  extends BaseComposerRuntimeCore
18
25
  implements ThreadComposerRuntimeCore
19
26
  {
20
- private _canCancel = false;
21
27
  public get canCancel() {
22
- return this._canCancel;
28
+ return isCancelable(this.runtime);
23
29
  }
24
30
 
25
31
  public get canSend() {
@@ -94,12 +100,14 @@ export class DefaultThreadComposerRuntimeCore
94
100
  }
95
101
 
96
102
  public connect() {
103
+ let lastCanCancel = false;
97
104
  let lastIsSendDisabled = this.runtime.isSendDisabled;
98
105
  let lastQueue = this.queue;
99
106
  return this.runtime.subscribe(() => {
100
107
  let changed = false;
101
- if (this.canCancel !== this.runtime.capabilities.cancel) {
102
- this._canCancel = this.runtime.capabilities.cancel;
108
+ const nextCanCancel = this.canCancel;
109
+ if (lastCanCancel !== nextCanCancel) {
110
+ lastCanCancel = nextCanCancel;
103
111
  changed = true;
104
112
  }
105
113
  if (lastIsSendDisabled !== this.runtime.isSendDisabled) {
@@ -72,6 +72,11 @@ export type SubmitFeedbackOptions = {
72
72
  };
73
73
 
74
74
  export type ThreadSuggestion = {
75
+ /** Display heading for the suggestion. Falls back to the prompt when absent. */
76
+ title?: string;
77
+ /** Secondary display text shown alongside the title. */
78
+ label?: string;
79
+ /** The message text sent when the suggestion is selected. */
75
80
  prompt: string;
76
81
  };
77
82
 
@@ -156,6 +161,7 @@ export type ThreadRuntimeCore = Readonly<{
156
161
  startRun: (config: StartRunConfig) => void;
157
162
  resumeRun: (config: ResumeRunConfig) => void;
158
163
  cancelRun: () => void;
164
+ unstable_notifySessionReset: () => void;
159
165
 
160
166
  addToolResult: (options: AddToolResultOptions) => void;
161
167
  resumeToolCall: (options: ResumeToolCallOptions) => void;
@@ -8,6 +8,7 @@ import {
8
8
  type QueueItemState,
9
9
  } from "../../store/scopes/queue-item";
10
10
  import { generateId } from "../../utils/id";
11
+ import { notifyEventListeners } from "../../utils/notify-event-listeners";
11
12
  import { getThreadMessageText } from "../../utils/text";
12
13
  import type {
13
14
  ExternalThreadQueueAdapter,
@@ -87,7 +88,7 @@ export const createMessageQueue = (
87
88
  let interrupting = false;
88
89
 
89
90
  const notify = () => {
90
- for (const callback of subscribers) callback();
91
+ notifyEventListeners(subscribers, undefined, "Message queue");
91
92
  };
92
93
 
93
94
  const setLanes = (next: Record<Lane, readonly QueueItemState[]>) => {
@@ -81,9 +81,9 @@ type RepositoryMessage = RepositoryParent & {
81
81
  const findHead = (
82
82
  message: RepositoryMessage | RepositoryParent,
83
83
  ): RepositoryMessage | null => {
84
- if (message.next) return findHead(message.next);
85
- if ("current" in message) return message;
86
- return null;
84
+ let current = message;
85
+ while (current.next) current = current.next;
86
+ return "current" in current ? current : null;
87
87
  };
88
88
 
89
89
  class CachedValue<T> {
@@ -116,11 +116,17 @@ export class MessageRepository {
116
116
  };
117
117
 
118
118
  private updateLevels(message: RepositoryMessage, newLevel: number) {
119
- message.level = newLevel;
120
- for (const childId of message.children) {
121
- const childMessage = this.messages.get(childId);
122
- if (childMessage) {
123
- this.updateLevels(childMessage, newLevel + 1);
119
+ const pending = [{ message, level: newLevel }];
120
+
121
+ while (pending.length > 0) {
122
+ const current = pending.pop()!;
123
+ current.message.level = current.level;
124
+
125
+ for (const childId of current.message.children) {
126
+ const childMessage = this.messages.get(childId);
127
+ if (childMessage) {
128
+ pending.push({ message: childMessage, level: current.level + 1 });
129
+ }
124
130
  }
125
131
  }
126
132
  }
@@ -135,7 +141,8 @@ export class MessageRepository {
135
141
 
136
142
  if (operation === "relink" && parentOrRoot === newParentOrRoot) return;
137
143
 
138
- if (operation !== "cut") {
144
+ // `link` receives a fresh ID from `addOrUpdateMessage`; only `relink` can introduce a cycle.
145
+ if (operation === "relink") {
139
146
  for (
140
147
  let current: RepositoryMessage | null = newParent;
141
148
  current;
@@ -143,7 +150,7 @@ export class MessageRepository {
143
150
  ) {
144
151
  if (current.current.id === child.current.id) {
145
152
  throw new Error(
146
- "MessageRepository(performOp/link): A message with the same id already exists in the parent tree. This error occurs if the same message id is found multiple times. This is likely an internal bug in assistant-ui.",
153
+ "MessageRepository(performOp/relink): A message with the same id already exists in the parent tree. This error occurs if the same message id is found multiple times. This is likely an internal bug in assistant-ui.",
147
154
  );
148
155
  }
149
156
  }
@@ -396,16 +403,17 @@ export class MessageRepository {
396
403
  const previousHead = this.head;
397
404
 
398
405
  if (message.children.length > 0) {
399
- const deleteDescendants = (msg: RepositoryMessage) => {
400
- for (const childId of msg.children) {
401
- const childMessage = this.messages.get(childId);
402
- if (childMessage) {
403
- deleteDescendants(childMessage);
404
- this.messages.delete(childId);
406
+ const pending = [...message.children];
407
+ while (pending.length > 0) {
408
+ const childId = pending.pop()!;
409
+ const childMessage = this.messages.get(childId);
410
+ if (childMessage) {
411
+ for (const descendantId of childMessage.children) {
412
+ pending.push(descendantId);
405
413
  }
414
+ this.messages.delete(childId);
406
415
  }
407
- };
408
- deleteDescendants(message);
416
+ }
409
417
 
410
418
  message.children = [];
411
419
  message.next = null;
@@ -0,0 +1,18 @@
1
+ import type { ThreadRuntimeCore } from "../interfaces/thread-runtime-core";
2
+
3
+ // Invalidation must stay re-entrant: StrictMode's simulated unmount runs the
4
+ // effect cleanup while the runtime object survives into the next mount, so a
5
+ // permanent disposed mark would swallow every later append.
6
+ const generations = new WeakMap<ThreadRuntimeCore, number>();
7
+
8
+ export const captureThreadRuntimeGeneration = (runtime: ThreadRuntimeCore) =>
9
+ generations.get(runtime) ?? 0;
10
+
11
+ export const isThreadRuntimeGenerationCurrent = (
12
+ runtime: ThreadRuntimeCore,
13
+ generation: number,
14
+ ) => captureThreadRuntimeGeneration(runtime) === generation;
15
+
16
+ export const invalidateThreadRuntime = (runtime: ThreadRuntimeCore) => {
17
+ generations.set(runtime, captureThreadRuntimeGeneration(runtime) + 1);
18
+ };
@@ -14,5 +14,7 @@ export const pickExternalStoreSharedOptions = (
14
14
  unstable_capabilities: options.unstable_capabilities,
15
15
  suggestions: options.suggestions,
16
16
  }) satisfies {
17
- [K in keyof Required<ExternalStoreSharedOptions>]: ExternalStoreSharedOptions[K];
17
+ [
18
+ K in keyof Required<ExternalStoreSharedOptions>
19
+ ]: ExternalStoreSharedOptions[K];
18
20
  };
@@ -5,6 +5,8 @@ import type {
5
5
  ThreadListRuntimeCore,
6
6
  } from "../../runtime/interfaces/thread-list-runtime-core";
7
7
  import type { ExternalStoreThreadListAdapter } from "./external-store-adapter";
8
+ import { invalidateThreadRuntime } from "../../runtime/utils/thread-runtime-lifecycle";
9
+ import { notifySubscribers } from "../../subscribable/subscribable";
8
10
 
9
11
  export type ExternalStoreThreadFactory = () => ExternalStoreThreadRuntimeCore;
10
12
 
@@ -150,6 +152,7 @@ export class ExternalStoreThreadListRuntimeCore implements ThreadListRuntimeCore
150
152
 
151
153
  // `initialLoad ||`: `_mainThread!` must be assigned on construction.
152
154
  if (initialLoad || previousThreadId !== newThreadId) {
155
+ if (!initialLoad) invalidateThreadRuntime(this._mainThread);
153
156
  this._mainThreadId = newThreadId;
154
157
  this._mainThread = this.threadFactory();
155
158
  }
@@ -268,6 +271,6 @@ export class ExternalStoreThreadListRuntimeCore implements ThreadListRuntimeCore
268
271
  }
269
272
 
270
273
  private _notifySubscribers() {
271
- for (const callback of this._subscriptions) callback();
274
+ notifySubscribers(this._subscriptions);
272
275
  }
273
276
  }