@assistant-ui/core 0.3.13 → 0.3.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (463) hide show
  1. package/dist/adapters/speech.d.ts.map +1 -1
  2. package/dist/adapters/speech.js +9 -15
  3. package/dist/adapters/speech.js.map +1 -1
  4. package/dist/adapters/thread-history.d.ts +2 -0
  5. package/dist/adapters/thread-history.d.ts.map +1 -1
  6. package/dist/adapters/voice.d.ts.map +1 -1
  7. package/dist/adapters/voice.js +38 -15
  8. package/dist/adapters/voice.js.map +1 -1
  9. package/dist/index.d.ts +2 -2
  10. package/dist/index.js +1 -1
  11. package/dist/index.js.map +1 -1
  12. package/dist/internal.d.ts +3 -2
  13. package/dist/internal.js +8 -7
  14. package/dist/model-context/frame/host.d.ts +1 -1
  15. package/dist/model-context/frame/host.d.ts.map +1 -1
  16. package/dist/model-context/frame/host.js +19 -4
  17. package/dist/model-context/frame/host.js.map +1 -1
  18. package/dist/model-context/frame/provider.d.ts +4 -0
  19. package/dist/model-context/frame/provider.d.ts.map +1 -1
  20. package/dist/model-context/frame/provider.js +50 -3
  21. package/dist/model-context/frame/provider.js.map +1 -1
  22. package/dist/model-context/frame/types.d.ts +4 -1
  23. package/dist/model-context/frame/types.d.ts.map +1 -1
  24. package/dist/model-context/frame/types.js.map +1 -1
  25. package/dist/model-context/registry.d.ts.map +1 -1
  26. package/dist/model-context/registry.js +16 -4
  27. package/dist/model-context/registry.js.map +1 -1
  28. package/dist/react/RuntimeAdapter.d.ts +8 -1
  29. package/dist/react/RuntimeAdapter.d.ts.map +1 -1
  30. package/dist/react/RuntimeAdapter.js +23 -18
  31. package/dist/react/RuntimeAdapter.js.map +1 -1
  32. package/dist/react/adapters/LocalStorageThreadListAdapter.d.ts.map +1 -1
  33. package/dist/react/adapters/LocalStorageThreadListAdapter.js +28 -12
  34. package/dist/react/adapters/LocalStorageThreadListAdapter.js.map +1 -1
  35. package/dist/react/client/AdaptedRemoteThread.d.ts +11 -0
  36. package/dist/react/client/AdaptedRemoteThread.d.ts.map +1 -0
  37. package/dist/react/client/AdaptedRemoteThread.js +27 -0
  38. package/dist/react/client/AdaptedRemoteThread.js.map +1 -0
  39. package/dist/react/client/InMemoryThreadList.d.ts +19 -0
  40. package/dist/react/client/InMemoryThreadList.d.ts.map +1 -0
  41. package/dist/react/client/InMemoryThreadList.js +418 -0
  42. package/dist/react/client/InMemoryThreadList.js.map +1 -0
  43. package/dist/react/client/Interactables.d.ts.map +1 -1
  44. package/dist/react/client/Interactables.js +159 -102
  45. package/dist/react/client/Interactables.js.map +1 -1
  46. package/dist/react/client/RemoteThreadList.d.ts +34 -0
  47. package/dist/react/client/RemoteThreadList.d.ts.map +1 -0
  48. package/dist/react/client/RemoteThreadList.js +898 -0
  49. package/dist/react/client/RemoteThreadList.js.map +1 -0
  50. package/dist/react/client/Tools.d.ts.map +1 -1
  51. package/dist/react/client/Tools.js +38 -27
  52. package/dist/react/client/Tools.js.map +1 -1
  53. package/dist/react/index.d.ts +7 -2
  54. package/dist/react/index.js +5 -2
  55. package/dist/react/interactables-legacy/Interactables.d.ts.map +1 -1
  56. package/dist/react/interactables-legacy/Interactables.js +145 -110
  57. package/dist/react/interactables-legacy/Interactables.js.map +1 -1
  58. package/dist/react/primitive-hooks/useActionBarCopy.d.ts.map +1 -1
  59. package/dist/react/primitive-hooks/useActionBarCopy.js +20 -19
  60. package/dist/react/primitive-hooks/useActionBarCopy.js.map +1 -1
  61. package/dist/react/primitive-hooks/useActionBarEdit.d.ts.map +1 -1
  62. package/dist/react/primitive-hooks/useActionBarEdit.js +2 -4
  63. package/dist/react/primitive-hooks/useActionBarEdit.js.map +1 -1
  64. package/dist/react/primitive-hooks/useActionBarReload.d.ts.map +1 -1
  65. package/dist/react/primitive-hooks/useActionBarReload.js +2 -4
  66. package/dist/react/primitive-hooks/useActionBarReload.js.map +1 -1
  67. package/dist/react/primitive-hooks/useBranchPickerNext.d.ts.map +1 -1
  68. package/dist/react/primitive-hooks/useBranchPickerNext.js +2 -6
  69. package/dist/react/primitive-hooks/useBranchPickerNext.js.map +1 -1
  70. package/dist/react/primitive-hooks/useBranchPickerPrevious.d.ts.map +1 -1
  71. package/dist/react/primitive-hooks/useBranchPickerPrevious.js +2 -6
  72. package/dist/react/primitive-hooks/useBranchPickerPrevious.js.map +1 -1
  73. package/dist/react/primitive-hooks/useComposerCancel.d.ts.map +1 -1
  74. package/dist/react/primitive-hooks/useComposerCancel.js +2 -4
  75. package/dist/react/primitive-hooks/useComposerCancel.js.map +1 -1
  76. package/dist/react/primitive-hooks/useComposerSend.d.ts.map +1 -1
  77. package/dist/react/primitive-hooks/useComposerSend.js +2 -4
  78. package/dist/react/primitive-hooks/useComposerSend.js.map +1 -1
  79. package/dist/react/primitive-hooks/useSuggestionTrigger.d.ts.map +1 -1
  80. package/dist/react/primitive-hooks/useSuggestionTrigger.js +6 -2
  81. package/dist/react/primitive-hooks/useSuggestionTrigger.js.map +1 -1
  82. package/dist/react/primitive-hooks/useThreadIsEmpty.d.ts +3 -0
  83. package/dist/react/primitive-hooks/useThreadIsEmpty.d.ts.map +1 -1
  84. package/dist/react/primitive-hooks/useThreadIsEmpty.js +3 -0
  85. package/dist/react/primitive-hooks/useThreadIsEmpty.js.map +1 -1
  86. package/dist/react/primitive-hooks/useThreadIsRunning.d.ts +3 -0
  87. package/dist/react/primitive-hooks/useThreadIsRunning.d.ts.map +1 -1
  88. package/dist/react/primitive-hooks/useThreadIsRunning.js +3 -0
  89. package/dist/react/primitive-hooks/useThreadIsRunning.js.map +1 -1
  90. package/dist/react/primitives/message/MessageParts.d.ts +13 -0
  91. package/dist/react/primitives/message/MessageParts.d.ts.map +1 -1
  92. package/dist/react/primitives/message/MessageParts.js.map +1 -1
  93. package/dist/react/primitives/thread/ThreadMessages.d.ts.map +1 -1
  94. package/dist/react/primitives/thread/ThreadMessages.js +1 -1
  95. package/dist/react/primitives/thread/ThreadMessages.js.map +1 -1
  96. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts +24 -10
  97. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts.map +1 -1
  98. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js +115 -71
  99. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js.map +1 -1
  100. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts +14 -2
  101. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts.map +1 -1
  102. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js +232 -63
  103. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js.map +1 -1
  104. package/dist/react/runtimes/RemoteThreadResource.d.ts +30 -0
  105. package/dist/react/runtimes/RemoteThreadResource.d.ts.map +1 -0
  106. package/dist/react/runtimes/RemoteThreadResource.js +136 -0
  107. package/dist/react/runtimes/RemoteThreadResource.js.map +1 -0
  108. package/dist/react/runtimes/RuntimeAdapterProvider.d.ts +3 -10
  109. package/dist/react/runtimes/RuntimeAdapterProvider.d.ts.map +1 -1
  110. package/dist/react/runtimes/RuntimeAdapterProvider.js +3 -6
  111. package/dist/react/runtimes/RuntimeAdapterProvider.js.map +1 -1
  112. package/dist/react/runtimes/assistant-transport/commandQueue.d.ts +17 -0
  113. package/dist/react/runtimes/assistant-transport/commandQueue.d.ts.map +1 -0
  114. package/dist/react/runtimes/assistant-transport/commandQueue.js +55 -0
  115. package/dist/react/runtimes/assistant-transport/commandQueue.js.map +1 -0
  116. package/dist/react/runtimes/assistant-transport/replayBoundaryStream.d.ts +11 -0
  117. package/dist/react/runtimes/assistant-transport/replayBoundaryStream.d.ts.map +1 -0
  118. package/dist/react/runtimes/assistant-transport/replayBoundaryStream.js +165 -0
  119. package/dist/react/runtimes/assistant-transport/replayBoundaryStream.js.map +1 -0
  120. package/dist/react/runtimes/assistant-transport/runManager.d.ts +15 -0
  121. package/dist/react/runtimes/assistant-transport/runManager.d.ts.map +1 -0
  122. package/dist/react/runtimes/assistant-transport/runManager.js +86 -0
  123. package/dist/react/runtimes/assistant-transport/runManager.js.map +1 -0
  124. package/dist/react/runtimes/assistant-transport/types.d.ts +130 -0
  125. package/dist/react/runtimes/assistant-transport/types.d.ts.map +1 -0
  126. package/dist/react/runtimes/assistant-transport/types.js +0 -0
  127. package/dist/react/runtimes/assistant-transport/useAssistantTransportRuntime.d.ts +14 -0
  128. package/dist/react/runtimes/assistant-transport/useAssistantTransportRuntime.d.ts.map +1 -0
  129. package/dist/react/runtimes/assistant-transport/useAssistantTransportRuntime.js +296 -0
  130. package/dist/react/runtimes/assistant-transport/useAssistantTransportRuntime.js.map +1 -0
  131. package/dist/react/runtimes/assistant-transport/useConvertedState.d.ts +7 -0
  132. package/dist/react/runtimes/assistant-transport/useConvertedState.d.ts.map +1 -0
  133. package/dist/react/runtimes/assistant-transport/useConvertedState.js +25 -0
  134. package/dist/react/runtimes/assistant-transport/useConvertedState.js.map +1 -0
  135. package/dist/react/runtimes/assistant-transport/useLatestRef.d.ts +7 -0
  136. package/dist/react/runtimes/assistant-transport/useLatestRef.d.ts.map +1 -0
  137. package/dist/react/runtimes/assistant-transport/useLatestRef.js +27 -0
  138. package/dist/react/runtimes/assistant-transport/useLatestRef.js.map +1 -0
  139. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts.map +1 -1
  140. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js +39 -13
  141. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js.map +1 -1
  142. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.d.ts +2 -1
  143. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.d.ts.map +1 -1
  144. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.js +3 -3
  145. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.js.map +1 -1
  146. package/dist/react/runtimes/cloud/auiV0.d.ts +4 -0
  147. package/dist/react/runtimes/cloud/auiV0.d.ts.map +1 -1
  148. package/dist/react/runtimes/cloud/auiV0.js +7 -0
  149. package/dist/react/runtimes/cloud/auiV0.js.map +1 -1
  150. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.d.ts.map +1 -1
  151. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js +60 -17
  152. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js.map +1 -1
  153. package/dist/react/runtimes/cloud/useCloudThreadListRuntime.d.ts +16 -0
  154. package/dist/react/runtimes/cloud/useCloudThreadListRuntime.d.ts.map +1 -0
  155. package/dist/react/runtimes/cloud/useCloudThreadListRuntime.js +36 -0
  156. package/dist/react/runtimes/cloud/useCloudThreadListRuntime.js.map +1 -0
  157. package/dist/react/runtimes/external-message-converter.js +14 -14
  158. package/dist/react/runtimes/external-message-converter.js.map +1 -1
  159. package/dist/react/runtimes/useExternalStoreRuntime.d.ts.map +1 -1
  160. package/dist/react/runtimes/useExternalStoreRuntime.js +44 -28
  161. package/dist/react/runtimes/useExternalStoreRuntime.js.map +1 -1
  162. package/dist/react/runtimes/useExternalStoreSharedOptions.js.map +1 -1
  163. package/dist/react/runtimes/useLocalRuntime.js +1 -1
  164. package/dist/react/runtimes/useRuntimeAdapters.d.ts +9 -0
  165. package/dist/react/runtimes/useRuntimeAdapters.d.ts.map +1 -0
  166. package/dist/react/runtimes/useRuntimeAdapters.js +20 -0
  167. package/dist/react/runtimes/useRuntimeAdapters.js.map +1 -0
  168. package/dist/runtime/api/composer-runtime.d.ts +5 -0
  169. package/dist/runtime/api/composer-runtime.d.ts.map +1 -1
  170. package/dist/runtime/api/composer-runtime.js.map +1 -1
  171. package/dist/runtime/api/message-runtime.js +1 -1
  172. package/dist/runtime/api/thread-list-runtime.d.ts +1 -0
  173. package/dist/runtime/api/thread-list-runtime.d.ts.map +1 -1
  174. package/dist/runtime/api/thread-list-runtime.js +4 -2
  175. package/dist/runtime/api/thread-list-runtime.js.map +1 -1
  176. package/dist/runtime/api/thread-runtime.d.ts +12 -2
  177. package/dist/runtime/api/thread-runtime.d.ts.map +1 -1
  178. package/dist/runtime/api/thread-runtime.js +8 -2
  179. package/dist/runtime/api/thread-runtime.js.map +1 -1
  180. package/dist/runtime/base/base-composer-runtime-core.d.ts.map +1 -1
  181. package/dist/runtime/base/base-composer-runtime-core.js +8 -7
  182. package/dist/runtime/base/base-composer-runtime-core.js.map +1 -1
  183. package/dist/runtime/base/base-thread-runtime-core.d.ts +1 -0
  184. package/dist/runtime/base/base-thread-runtime-core.d.ts.map +1 -1
  185. package/dist/runtime/base/base-thread-runtime-core.js +3 -3
  186. package/dist/runtime/base/base-thread-runtime-core.js.map +1 -1
  187. package/dist/runtime/base/default-thread-composer-runtime-core.d.ts +0 -1
  188. package/dist/runtime/base/default-thread-composer-runtime-core.d.ts.map +1 -1
  189. package/dist/runtime/base/default-thread-composer-runtime-core.js +10 -4
  190. package/dist/runtime/base/default-thread-composer-runtime-core.js.map +1 -1
  191. package/dist/runtime/interfaces/thread-runtime-core.d.ts +6 -0
  192. package/dist/runtime/interfaces/thread-runtime-core.d.ts.map +1 -1
  193. package/dist/runtime/internal.js +5 -5
  194. package/dist/runtime/queue/message-queue.d.ts.map +1 -1
  195. package/dist/runtime/queue/message-queue.js +2 -1
  196. package/dist/runtime/queue/message-queue.js.map +1 -1
  197. package/dist/runtime/utils/message-repository.d.ts.map +1 -1
  198. package/dist/runtime/utils/message-repository.js +27 -18
  199. package/dist/runtime/utils/message-repository.js.map +1 -1
  200. package/dist/runtime/utils/thread-runtime-lifecycle.d.ts +8 -0
  201. package/dist/runtime/utils/thread-runtime-lifecycle.d.ts.map +1 -0
  202. package/dist/runtime/utils/thread-runtime-lifecycle.js +11 -0
  203. package/dist/runtime/utils/thread-runtime-lifecycle.js.map +1 -0
  204. package/dist/runtimes/external-store/external-store-shared-options.js.map +1 -1
  205. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.d.ts.map +1 -1
  206. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js +4 -1
  207. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js.map +1 -1
  208. package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts +8 -0
  209. package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts.map +1 -1
  210. package/dist/runtimes/external-store/external-store-thread-runtime-core.js +37 -13
  211. package/dist/runtimes/external-store/external-store-thread-runtime-core.js.map +1 -1
  212. package/dist/runtimes/inert/InertThreadRuntimeCore.d.ts +102 -0
  213. package/dist/runtimes/inert/InertThreadRuntimeCore.d.ts.map +1 -0
  214. package/dist/runtimes/inert/InertThreadRuntimeCore.js +156 -0
  215. package/dist/runtimes/inert/InertThreadRuntimeCore.js.map +1 -0
  216. package/dist/runtimes/internal.d.ts +1 -1
  217. package/dist/runtimes/local/local-thread-runtime-core.d.ts +3 -0
  218. package/dist/runtimes/local/local-thread-runtime-core.d.ts.map +1 -1
  219. package/dist/runtimes/local/local-thread-runtime-core.js +78 -19
  220. package/dist/runtimes/local/local-thread-runtime-core.js.map +1 -1
  221. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.d.ts +12 -59
  222. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.d.ts.map +1 -1
  223. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.js +10 -142
  224. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.js.map +1 -1
  225. package/dist/runtimes/remote-thread-list/adapter-changed.d.ts +9 -0
  226. package/dist/runtimes/remote-thread-list/adapter-changed.d.ts.map +1 -0
  227. package/dist/runtimes/remote-thread-list/adapter-changed.js +13 -0
  228. package/dist/runtimes/remote-thread-list/adapter-changed.js.map +1 -0
  229. package/dist/runtimes/remote-thread-list/empty-thread-core.d.ts.map +1 -1
  230. package/dist/runtimes/remote-thread-list/empty-thread-core.js +16 -152
  231. package/dist/runtimes/remote-thread-list/empty-thread-core.js.map +1 -1
  232. package/dist/runtimes/remote-thread-list/optimistic-state.d.ts +2 -0
  233. package/dist/runtimes/remote-thread-list/optimistic-state.d.ts.map +1 -1
  234. package/dist/runtimes/remote-thread-list/optimistic-state.js +11 -0
  235. package/dist/runtimes/remote-thread-list/optimistic-state.js.map +1 -1
  236. package/dist/runtimes/remote-thread-list/types.d.ts +32 -1
  237. package/dist/runtimes/remote-thread-list/types.d.ts.map +1 -1
  238. package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts +1 -12
  239. package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts.map +1 -1
  240. package/dist/runtimes/tool-invocations/ToolInvocationTracker.js +67 -38
  241. package/dist/runtimes/tool-invocations/ToolInvocationTracker.js.map +1 -1
  242. package/dist/store/clients/external-thread.js +1 -1
  243. package/dist/store/clients/external-thread.js.map +1 -1
  244. package/dist/store/clients/suggestions.js +2 -2
  245. package/dist/store/clients/suggestions.js.map +1 -1
  246. package/dist/store/clients/thread-selection-events.d.ts +10 -0
  247. package/dist/store/clients/thread-selection-events.d.ts.map +1 -0
  248. package/dist/store/clients/thread-selection-events.js +40 -0
  249. package/dist/store/clients/thread-selection-events.js.map +1 -0
  250. package/dist/store/env.d.ts +5 -0
  251. package/dist/store/env.d.ts.map +1 -0
  252. package/dist/store/env.js +12 -0
  253. package/dist/store/env.js.map +1 -0
  254. package/dist/store/index.d.ts +5 -3
  255. package/dist/store/index.js +4 -2
  256. package/dist/store/internal.d.ts +4 -1
  257. package/dist/store/internal.js +4 -1
  258. package/dist/store/primitive-predicates.d.ts +19 -0
  259. package/dist/store/primitive-predicates.d.ts.map +1 -0
  260. package/dist/store/primitive-predicates.js +19 -0
  261. package/dist/store/primitive-predicates.js.map +1 -0
  262. package/dist/store/runtime-clients/attachment-runtime-client.d.ts.map +1 -1
  263. package/dist/store/runtime-clients/attachment-runtime-client.js +18 -11
  264. package/dist/store/runtime-clients/attachment-runtime-client.js.map +1 -1
  265. package/dist/store/runtime-clients/handle-runtime-action.d.ts +5 -0
  266. package/dist/store/runtime-clients/handle-runtime-action.d.ts.map +1 -0
  267. package/dist/store/runtime-clients/handle-runtime-action.js +14 -0
  268. package/dist/store/runtime-clients/handle-runtime-action.js.map +1 -0
  269. package/dist/store/runtime-clients/handle-thread-list-action.d.ts +5 -0
  270. package/dist/store/runtime-clients/handle-thread-list-action.d.ts.map +1 -0
  271. package/dist/store/runtime-clients/handle-thread-list-action.js +7 -0
  272. package/dist/store/runtime-clients/handle-thread-list-action.js.map +1 -0
  273. package/dist/store/runtime-clients/thread-list-item-runtime-client.d.ts.map +1 -1
  274. package/dist/store/runtime-clients/thread-list-item-runtime-client.js +62 -29
  275. package/dist/store/runtime-clients/thread-list-item-runtime-client.js.map +1 -1
  276. package/dist/store/runtime-clients/thread-list-runtime-client.d.ts.map +1 -1
  277. package/dist/store/runtime-clients/thread-list-runtime-client.js +5 -6
  278. package/dist/store/runtime-clients/thread-list-runtime-client.js.map +1 -1
  279. package/dist/store/scopes/composer.d.ts +9 -4
  280. package/dist/store/scopes/composer.d.ts.map +1 -1
  281. package/dist/store/scopes/thread-list-item.d.ts +7 -6
  282. package/dist/store/scopes/thread-list-item.d.ts.map +1 -1
  283. package/dist/store/scopes/thread.d.ts +8 -7
  284. package/dist/store/scopes/thread.d.ts.map +1 -1
  285. package/dist/store/scopes/threads.d.ts +17 -1
  286. package/dist/store/scopes/threads.d.ts.map +1 -1
  287. package/dist/subscribable/subscribable.d.ts +2 -1
  288. package/dist/subscribable/subscribable.d.ts.map +1 -1
  289. package/dist/subscribable/subscribable.js +23 -18
  290. package/dist/subscribable/subscribable.js.map +1 -1
  291. package/dist/types/message.d.ts +1 -1
  292. package/dist/types/message.js.map +1 -1
  293. package/dist/utils/composite-context-provider.d.ts +1 -0
  294. package/dist/utils/composite-context-provider.d.ts.map +1 -1
  295. package/dist/utils/composite-context-provider.js +25 -9
  296. package/dist/utils/composite-context-provider.js.map +1 -1
  297. package/dist/utils/notify-event-listeners.d.ts +2 -2
  298. package/dist/utils/notify-event-listeners.d.ts.map +1 -1
  299. package/dist/utils/notify-event-listeners.js +2 -2
  300. package/dist/utils/notify-event-listeners.js.map +1 -1
  301. package/dist/utils/silent-runtime-action.d.ts +6 -0
  302. package/dist/utils/silent-runtime-action.d.ts.map +1 -0
  303. package/dist/utils/silent-runtime-action.js +7 -0
  304. package/dist/utils/silent-runtime-action.js.map +1 -0
  305. package/package.json +8 -8
  306. package/src/adapters/speech.test.ts +118 -1
  307. package/src/adapters/speech.ts +21 -22
  308. package/src/adapters/thread-history.ts +2 -0
  309. package/src/adapters/voice.test.ts +134 -0
  310. package/src/adapters/voice.ts +35 -27
  311. package/src/index.ts +1 -0
  312. package/src/internal.ts +1 -0
  313. package/src/model-context/frame/host.test.ts +87 -5
  314. package/src/model-context/frame/host.ts +18 -4
  315. package/src/model-context/frame/provider.test.ts +347 -20
  316. package/src/model-context/frame/provider.ts +58 -2
  317. package/src/model-context/frame/types.ts +5 -0
  318. package/src/model-context/registry.test.ts +131 -0
  319. package/src/model-context/registry.ts +16 -6
  320. package/src/react/RuntimeAdapter.test.ts +2 -0
  321. package/src/react/RuntimeAdapter.ts +20 -8
  322. package/src/react/adapters/LocalStorageThreadListAdapter.tsx +34 -17
  323. package/src/react/client/AdaptedRemoteThread.ts +41 -0
  324. package/src/react/client/InMemoryThreadList.test.tsx +148 -0
  325. package/src/react/client/InMemoryThreadList.ts +290 -0
  326. package/src/react/client/Interactables.test.ts +326 -2
  327. package/src/react/client/Interactables.ts +227 -110
  328. package/src/react/client/RemoteThreadList.test.ts +1222 -0
  329. package/src/react/client/RemoteThreadList.ts +1136 -0
  330. package/src/react/client/Tools.ts +36 -29
  331. package/src/react/index.ts +13 -0
  332. package/src/react/interactables-legacy/Interactables.test.ts +317 -0
  333. package/src/react/interactables-legacy/Interactables.ts +204 -128
  334. package/src/react/primitive-hooks/useActionBarCopy.test.ts +15 -0
  335. package/src/react/primitive-hooks/useActionBarCopy.ts +15 -10
  336. package/src/react/primitive-hooks/useActionBarEdit.ts +2 -1
  337. package/src/react/primitive-hooks/useActionBarReload.ts +2 -6
  338. package/src/react/primitive-hooks/useBranchPickerNext.ts +2 -7
  339. package/src/react/primitive-hooks/useBranchPickerPrevious.ts +2 -7
  340. package/src/react/primitive-hooks/useComposerCancel.ts +2 -1
  341. package/src/react/primitive-hooks/useComposerSend.ts +2 -5
  342. package/src/react/primitive-hooks/useSuggestionTrigger.test.ts +11 -0
  343. package/src/react/primitive-hooks/useSuggestionTrigger.ts +4 -5
  344. package/src/react/primitive-hooks/useThreadIsEmpty.ts +3 -0
  345. package/src/react/primitive-hooks/useThreadIsRunning.ts +3 -0
  346. package/src/react/primitives/message/MessageParts.tsx +0 -1
  347. package/src/react/primitives/thread/ThreadMessages.tsx +2 -1
  348. package/src/react/runtimes/RemoteThreadListHookInstanceManager.retry.test.tsx +116 -0
  349. package/src/react/runtimes/RemoteThreadListHookInstanceManager.running.test.tsx +1 -1
  350. package/src/react/runtimes/RemoteThreadListHookInstanceManager.test.tsx +57 -6
  351. package/src/react/runtimes/RemoteThreadListHookInstanceManager.title.test.tsx +272 -0
  352. package/src/react/runtimes/RemoteThreadListHookInstanceManager.tsx +171 -124
  353. package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.republish.test.ts +87 -0
  354. package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.tsx +327 -83
  355. package/src/react/runtimes/RemoteThreadResource.test.ts +141 -0
  356. package/src/react/runtimes/RemoteThreadResource.ts +233 -0
  357. package/src/react/runtimes/RuntimeAdapterProvider.tsx +8 -20
  358. package/src/react/runtimes/assistant-transport/commandQueue.ts +68 -0
  359. package/src/react/runtimes/assistant-transport/replayBoundaryStream.test.ts +455 -0
  360. package/src/react/runtimes/assistant-transport/replayBoundaryStream.ts +172 -0
  361. package/src/react/runtimes/assistant-transport/runManager.ts +124 -0
  362. package/src/react/runtimes/assistant-transport/transport-delivery.test.tsx +79 -0
  363. package/src/react/runtimes/assistant-transport/transport-parentid.test.tsx +97 -0
  364. package/src/react/runtimes/assistant-transport/transport-scheduling.test.ts +414 -0
  365. package/src/react/runtimes/assistant-transport/types.ts +170 -0
  366. package/src/react/runtimes/assistant-transport/useAssistantTransport.spec.md +141 -0
  367. package/src/react/runtimes/assistant-transport/useAssistantTransportRuntime.test.tsx +683 -0
  368. package/src/react/runtimes/assistant-transport/useAssistantTransportRuntime.ts +483 -0
  369. package/src/react/runtimes/assistant-transport/useConvertedState.ts +20 -0
  370. package/src/react/runtimes/assistant-transport/useLatestRef.ts +9 -0
  371. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.test.tsx +131 -6
  372. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.ts +61 -15
  373. package/src/react/runtimes/cloud/CloudFileAttachmentAdapter.ts +6 -4
  374. package/src/react/runtimes/cloud/auiV0.ts +17 -1
  375. package/src/react/runtimes/cloud/useCloudThreadListAdapter.test.tsx +98 -3
  376. package/src/react/runtimes/cloud/useCloudThreadListAdapter.tsx +104 -27
  377. package/src/react/runtimes/cloud/useCloudThreadListRuntime.test.tsx +56 -0
  378. package/src/react/runtimes/cloud/useCloudThreadListRuntime.ts +31 -0
  379. package/src/react/runtimes/external-message-converter.test.ts +143 -0
  380. package/src/react/runtimes/external-message-converter.ts +41 -41
  381. package/src/react/runtimes/remote-thread-hook-on-tap.test.ts +58 -0
  382. package/src/react/runtimes/useExternalStoreRuntime.lifecycle.test.tsx +83 -0
  383. package/src/react/runtimes/useExternalStoreRuntime.suggestions.test.tsx +13 -3
  384. package/src/react/runtimes/useExternalStoreRuntime.ts +7 -0
  385. package/src/react/runtimes/useExternalStoreSharedOptions.ts +3 -1
  386. package/src/react/runtimes/useLocalRuntime.test.tsx +134 -8
  387. package/src/react/runtimes/useRuntimeAdapters.test.tsx +62 -0
  388. package/src/react/runtimes/useRuntimeAdapters.ts +28 -0
  389. package/src/runtime/api/composer-runtime.ts +5 -0
  390. package/src/runtime/api/thread-list-runtime.ts +3 -1
  391. package/src/runtime/api/thread-runtime.ts +20 -2
  392. package/src/runtime/base/base-composer-runtime-core.ts +6 -5
  393. package/src/runtime/base/base-thread-runtime-core.test.ts +191 -0
  394. package/src/runtime/base/base-thread-runtime-core.ts +11 -2
  395. package/src/runtime/base/default-thread-composer-runtime-core.ts +12 -4
  396. package/src/runtime/interfaces/thread-runtime-core.ts +6 -0
  397. package/src/runtime/queue/message-queue.ts +2 -1
  398. package/src/runtime/utils/message-repository.ts +26 -18
  399. package/src/runtime/utils/thread-runtime-lifecycle.ts +18 -0
  400. package/src/runtimes/external-store/external-store-shared-options.ts +3 -1
  401. package/src/runtimes/external-store/external-store-thread-list-runtime-core.ts +4 -1
  402. package/src/runtimes/external-store/external-store-thread-runtime-core.ts +103 -34
  403. package/src/runtimes/inert/InertThreadRuntimeCore.test.ts +253 -0
  404. package/src/runtimes/inert/InertThreadRuntimeCore.ts +232 -0
  405. package/src/runtimes/local/local-thread-runtime-core.test.ts +692 -4
  406. package/src/runtimes/local/local-thread-runtime-core.ts +117 -22
  407. package/src/runtimes/readonly/ReadonlyThreadRuntimeCore.ts +17 -205
  408. package/src/runtimes/remote-thread-list/adapter-changed.ts +10 -0
  409. package/src/runtimes/remote-thread-list/empty-thread-core.ts +28 -217
  410. package/src/runtimes/remote-thread-list/optimistic-state.test.ts +18 -0
  411. package/src/runtimes/remote-thread-list/optimistic-state.ts +13 -0
  412. package/src/runtimes/remote-thread-list/types.ts +34 -0
  413. package/src/runtimes/tool-invocations/EDGE_CASES.md +17 -6
  414. package/src/runtimes/tool-invocations/ToolInvocationTracker.test.ts +243 -0
  415. package/src/runtimes/tool-invocations/ToolInvocationTracker.ts +127 -61
  416. package/src/store/clients/external-thread.ts +1 -1
  417. package/src/store/clients/model-context-client.test.ts +16 -8
  418. package/src/store/clients/suggestions.ts +2 -2
  419. package/src/store/clients/thread-selection-events.ts +21 -0
  420. package/src/store/env.ts +11 -0
  421. package/src/store/index.ts +14 -1
  422. package/src/store/internal.ts +13 -0
  423. package/src/store/primitive-predicates.test.ts +184 -0
  424. package/src/store/primitive-predicates.ts +43 -0
  425. package/src/store/runtime-clients/attachment-runtime-client.test.ts +41 -0
  426. package/src/store/runtime-clients/attachment-runtime-client.ts +2 -1
  427. package/src/store/runtime-clients/handle-runtime-action.test.ts +40 -0
  428. package/src/store/runtime-clients/handle-runtime-action.ts +14 -0
  429. package/src/store/runtime-clients/handle-thread-list-action.test.ts +69 -0
  430. package/src/store/runtime-clients/handle-thread-list-action.ts +6 -0
  431. package/src/store/runtime-clients/thread-list-item-runtime-client.ts +15 -7
  432. package/src/store/runtime-clients/thread-list-runtime-client.ts +9 -6
  433. package/src/store/scopes/composer.ts +9 -4
  434. package/src/store/scopes/thread-list-item.ts +7 -6
  435. package/src/store/scopes/thread.ts +8 -7
  436. package/src/store/scopes/threads.ts +14 -0
  437. package/src/subscribable/subscribable.test.ts +77 -1
  438. package/src/subscribable/subscribable.ts +38 -23
  439. package/src/tests/MessageRepository.test.ts +48 -0
  440. package/src/tests/RemoteThreadListThreadListRuntimeCore-errors.test.ts +2 -2
  441. package/src/tests/RemoteThreadListThreadListRuntimeCore-loadMore.test.ts +8 -6
  442. package/src/tests/RemoteThreadListThreadListRuntimeCore-switchToThread-unarchive.test.ts +25 -0
  443. package/src/tests/auiV0Encode.test.ts +66 -0
  444. package/src/tests/base-composer-runtime-core-send.test.ts +30 -0
  445. package/src/tests/base-composer-runtime-core.test.ts +28 -0
  446. package/src/tests/composer-can-cancel.test.ts +101 -0
  447. package/src/tests/empty-thread-core.test.ts +6 -0
  448. package/src/tests/external-store-thread-list-runtime-core.test.ts +101 -0
  449. package/src/tests/external-store-thread-runtime-core-adapter.test.ts +211 -1
  450. package/src/tests/external-store-thread-runtime-core.test.ts +124 -0
  451. package/src/tests/external-thread-isEmpty.test.tsx +100 -0
  452. package/src/tests/interactables-toolui-migration.test.tsx +66 -0
  453. package/src/tests/message-queue.test.ts +28 -0
  454. package/src/tests/remote-thread-list-adapter-switch.test.ts +383 -0
  455. package/src/tests/session-reset-notification.test.ts +145 -0
  456. package/src/tests/thread-switch-events.test.tsx +99 -1
  457. package/src/tests/tools-scope-migration.test.tsx +58 -0
  458. package/src/tests/useRemoteThreadListRuntime-controlled.test.tsx +67 -0
  459. package/src/types/message.ts +1 -1
  460. package/src/utils/composite-context-provider.test.ts +139 -0
  461. package/src/utils/composite-context-provider.ts +26 -8
  462. package/src/utils/notify-event-listeners.ts +10 -5
  463. package/src/utils/silent-runtime-action.ts +6 -0
@@ -1,4 +1,5 @@
1
1
  import type { Unsubscribe } from "../types/unsubscribe";
2
+ import { notifyEventListeners } from "../utils/notify-event-listeners";
2
3
 
3
4
  export namespace SpeechSynthesisAdapter {
4
5
  export type Status =
@@ -22,21 +23,6 @@ export type SpeechSynthesisAdapter = {
22
23
  speak: (text: string) => SpeechSynthesisAdapter.Utterance;
23
24
  };
24
25
 
25
- const notifySpeechSynthesisListeners = (
26
- listeners: Iterable<() => void>,
27
- ): void => {
28
- for (const listener of listeners) {
29
- try {
30
- listener();
31
- } catch (error) {
32
- console.error(
33
- "[assistant-ui] Speech synthesis listener threw an error",
34
- error,
35
- );
36
- }
37
- }
38
- };
39
-
40
26
  export namespace DictationAdapter {
41
27
  export type Status =
42
28
  | {
@@ -79,7 +65,7 @@ export class WebSpeechSynthesisAdapter implements SpeechSynthesisAdapter {
79
65
  if (res.status.type === "ended") return;
80
66
 
81
67
  res.status = { type: "ended", reason, error };
82
- notifySpeechSynthesisListeners(subscribers);
68
+ notifyEventListeners(subscribers, undefined, "Speech synthesis");
83
69
  };
84
70
 
85
71
  utterance.addEventListener("end", () => handleEnd("finished"));
@@ -97,7 +83,9 @@ export class WebSpeechSynthesisAdapter implements SpeechSynthesisAdapter {
97
83
  if (res.status.type === "ended") {
98
84
  let cancelled = false;
99
85
  queueMicrotask(() => {
100
- if (!cancelled) notifySpeechSynthesisListeners([callback]);
86
+ if (!cancelled) {
87
+ notifyEventListeners([callback], undefined, "Speech synthesis");
88
+ }
101
89
  });
102
90
  return () => {
103
91
  cancelled = true;
@@ -270,7 +258,7 @@ export class WebSpeechDictationAdapter implements DictationAdapter {
270
258
  };
271
259
 
272
260
  recognition.addEventListener("speechstart", () => {
273
- for (const cb of speechStartCallbacks) cb();
261
+ notifyEventListeners(speechStartCallbacks, undefined, "Dictation");
274
262
  });
275
263
 
276
264
  recognition.addEventListener("start", () => {
@@ -292,9 +280,17 @@ export class WebSpeechDictationAdapter implements DictationAdapter {
292
280
 
293
281
  if (result.isFinal) {
294
282
  finalTranscript += transcript;
295
- for (const cb of speechCallbacks) cb({ transcript, isFinal: true });
283
+ notifyEventListeners(
284
+ speechCallbacks,
285
+ () => ({ transcript, isFinal: true }),
286
+ "Dictation",
287
+ );
296
288
  } else {
297
- for (const cb of speechCallbacks) cb({ transcript, isFinal: false });
289
+ notifyEventListeners(
290
+ speechCallbacks,
291
+ () => ({ transcript, isFinal: false }),
292
+ "Dictation",
293
+ );
298
294
  }
299
295
  }
300
296
  });
@@ -309,8 +305,11 @@ export class WebSpeechDictationAdapter implements DictationAdapter {
309
305
  updateStatus({ type: "ended", reason: "stopped" });
310
306
  }
311
307
  if (finalTranscript) {
312
- for (const cb of speechEndCallbacks)
313
- cb({ transcript: finalTranscript });
308
+ notifyEventListeners(
309
+ speechEndCallbacks,
310
+ () => ({ transcript: finalTranscript }),
311
+ "Dictation",
312
+ );
314
313
  finalTranscript = "";
315
314
  }
316
315
  });
@@ -39,6 +39,8 @@ export interface MessageFormatAdapter<
39
39
 
40
40
  export type GenericThreadHistoryAdapter<TMessage> = {
41
41
  load(): Promise<MessageFormatRepository<TMessage>>;
42
+ /** Snapshot the current thread so later writes survive a switch. */
43
+ pin?(): void;
42
44
  append(item: MessageFormatItem<TMessage>): Promise<void>;
43
45
  update?(
44
46
  item: MessageFormatItem<TMessage>,
@@ -73,6 +73,140 @@ describe("createVoiceSession", () => {
73
73
  expect(controls.mute).not.toHaveBeenCalled();
74
74
  });
75
75
 
76
+ it("disconnects immediately when created with an already-aborted signal", async () => {
77
+ const abortController = new AbortController();
78
+ abortController.abort();
79
+ const setup = vi.fn(async () => ({
80
+ disconnect: vi.fn(),
81
+ mute: vi.fn(),
82
+ unmute: vi.fn(),
83
+ }));
84
+
85
+ const session = createVoiceSession(
86
+ { abortSignal: abortController.signal },
87
+ setup,
88
+ );
89
+ await Promise.resolve();
90
+
91
+ expect(setup).not.toHaveBeenCalled();
92
+ expect(session.status).toEqual({ type: "ended", reason: "cancelled" });
93
+ });
94
+
95
+ it("removes the abort listener after disconnecting", async () => {
96
+ const abortController = new AbortController();
97
+ const controls = {
98
+ disconnect: vi.fn(),
99
+ mute: vi.fn(),
100
+ unmute: vi.fn(),
101
+ };
102
+ const session = createVoiceSession(
103
+ { abortSignal: abortController.signal },
104
+ async () => controls,
105
+ );
106
+ await Promise.resolve();
107
+ const statusListener = vi.fn();
108
+ session.onStatusChange(statusListener);
109
+
110
+ session.disconnect();
111
+ session.disconnect();
112
+ abortController.abort();
113
+
114
+ expect(session.status).toEqual({ type: "ended", reason: "cancelled" });
115
+ expect(statusListener).toHaveBeenCalledOnce();
116
+ expect(statusListener).toHaveBeenCalledWith({
117
+ type: "ended",
118
+ reason: "cancelled",
119
+ });
120
+ expect(controls.disconnect).toHaveBeenCalledOnce();
121
+ });
122
+
123
+ it("ends a running session when the abort signal fires", async () => {
124
+ const abortController = new AbortController();
125
+ const controls = {
126
+ disconnect: vi.fn(),
127
+ mute: vi.fn(),
128
+ unmute: vi.fn(),
129
+ };
130
+ let helpers: VoiceSessionHelpers | undefined;
131
+ const session = createVoiceSession(
132
+ { abortSignal: abortController.signal },
133
+ async (sessionHelpers) => {
134
+ helpers = sessionHelpers;
135
+ return controls;
136
+ },
137
+ );
138
+ await Promise.resolve();
139
+ if (!helpers) throw new Error("Voice session setup did not start");
140
+
141
+ helpers.setStatus({ type: "running" });
142
+ const statusListener = vi.fn();
143
+ session.onStatusChange(statusListener);
144
+
145
+ abortController.abort();
146
+
147
+ expect(session.status).toEqual({ type: "ended", reason: "cancelled" });
148
+ expect(statusListener).toHaveBeenCalledOnce();
149
+ expect(statusListener).toHaveBeenCalledWith({
150
+ type: "ended",
151
+ reason: "cancelled",
152
+ });
153
+ expect(controls.disconnect).toHaveBeenCalledOnce();
154
+ });
155
+
156
+ it("keeps abort teardown available after the session ends", async () => {
157
+ const abortController = new AbortController();
158
+ const controls = {
159
+ disconnect: vi.fn(),
160
+ mute: vi.fn(),
161
+ unmute: vi.fn(),
162
+ };
163
+ let helpers: VoiceSessionHelpers | undefined;
164
+ const session = createVoiceSession(
165
+ { abortSignal: abortController.signal },
166
+ async (sessionHelpers) => {
167
+ helpers = sessionHelpers;
168
+ return controls;
169
+ },
170
+ );
171
+ await Promise.resolve();
172
+ if (!helpers) throw new Error("Voice session setup did not start");
173
+
174
+ helpers.end("error");
175
+ abortController.abort();
176
+
177
+ expect(session.status).toEqual({
178
+ type: "ended",
179
+ reason: "error",
180
+ error: undefined,
181
+ });
182
+ expect(controls.disconnect).toHaveBeenCalledOnce();
183
+ });
184
+
185
+ it("cleans up when the adapter disconnect throws", async () => {
186
+ const disconnectError = new Error("disconnect failed");
187
+ let helpers: VoiceSessionHelpers | undefined;
188
+ const session = createVoiceSession({}, async (sessionHelpers) => {
189
+ helpers = sessionHelpers;
190
+ return {
191
+ disconnect: () => {
192
+ throw disconnectError;
193
+ },
194
+ mute: vi.fn(),
195
+ unmute: vi.fn(),
196
+ };
197
+ });
198
+ await Promise.resolve();
199
+ if (!helpers) throw new Error("Voice session setup did not start");
200
+ const transcriptListener = vi.fn();
201
+ session.onTranscript(transcriptListener);
202
+
203
+ expect(() => session.disconnect()).toThrow(disconnectError);
204
+ expect(helpers.isDisposed()).toBe(true);
205
+
206
+ helpers.emitTranscript({ role: "assistant", text: "stale" });
207
+ expect(transcriptListener).not.toHaveBeenCalled();
208
+ });
209
+
76
210
  it("continues notifying listeners when one throws", () => {
77
211
  const listenerError = new Error("listener failed");
78
212
  const consoleError = vi
@@ -1,4 +1,5 @@
1
1
  import type { Unsubscribe } from "../types/unsubscribe";
2
+ import { notifyEventListeners } from "../utils/notify-event-listeners";
2
3
 
3
4
  export namespace RealtimeVoiceAdapter {
4
5
  export type Status =
@@ -57,22 +58,6 @@ export type VoiceSessionHelpers = {
57
58
  isDisposed: () => boolean;
58
59
  };
59
60
 
60
- const notifyListeners = <T>(
61
- listeners: ReadonlySet<(value: T) => void>,
62
- value: T,
63
- ) => {
64
- for (const listener of listeners) {
65
- try {
66
- listener(value);
67
- } catch (error) {
68
- console.error(
69
- "[assistant-ui] Voice session listener threw an error",
70
- error,
71
- );
72
- }
73
- }
74
- };
75
-
76
61
  export function createVoiceSession(
77
62
  options: { abortSignal?: AbortSignal },
78
63
  setup: (helpers: VoiceSessionHelpers) => Promise<VoiceSessionControls>,
@@ -87,7 +72,17 @@ export function createVoiceSession(
87
72
  let currentStatus: RealtimeVoiceAdapter.Status = { type: "starting" };
88
73
  let isMuted = false;
89
74
  let disposed = false;
75
+ let disconnected = false;
90
76
  let controls: VoiceSessionControls | null = null;
77
+ const abortSignal = options.abortSignal;
78
+ let abortHandler: (() => void) | undefined;
79
+
80
+ const detachAbortHandler = () => {
81
+ if (abortHandler) {
82
+ abortSignal?.removeEventListener("abort", abortHandler);
83
+ abortHandler = undefined;
84
+ }
85
+ };
91
86
 
92
87
  const cleanup = () => {
93
88
  disposed = true;
@@ -101,25 +96,25 @@ export function createVoiceSession(
101
96
  setStatus: (status) => {
102
97
  if (disposed) return;
103
98
  currentStatus = status;
104
- notifyListeners(statusCbs, status);
99
+ notifyEventListeners(statusCbs, status, "Voice session");
105
100
  },
106
101
  end: (reason, error?) => {
107
102
  if (disposed) return;
108
103
  currentStatus = { type: "ended", reason, error };
109
- notifyListeners(statusCbs, currentStatus);
104
+ notifyEventListeners(statusCbs, currentStatus, "Voice session");
110
105
  cleanup();
111
106
  },
112
107
  emitTranscript: (item) => {
113
108
  if (disposed) return;
114
- notifyListeners(transcriptCbs, item);
109
+ notifyEventListeners(transcriptCbs, item, "Voice session");
115
110
  },
116
111
  emitMode: (mode) => {
117
112
  if (disposed) return;
118
- notifyListeners(modeCbs, mode);
113
+ notifyEventListeners(modeCbs, mode, "Voice session");
119
114
  },
120
115
  emitVolume: (volume) => {
121
116
  if (disposed) return;
122
- notifyListeners(volumeCbs, volume);
117
+ notifyEventListeners(volumeCbs, volume, "Voice session");
123
118
  },
124
119
  isDisposed: () => disposed,
125
120
  };
@@ -132,8 +127,18 @@ export function createVoiceSession(
132
127
  return isMuted;
133
128
  },
134
129
  disconnect: () => {
135
- controls?.disconnect();
136
- cleanup();
130
+ if (disconnected) return;
131
+ disconnected = true;
132
+ detachAbortHandler();
133
+ if (currentStatus.type !== "ended") {
134
+ currentStatus = { type: "ended", reason: "cancelled" };
135
+ notifyEventListeners(statusCbs, currentStatus, "Voice session");
136
+ }
137
+ try {
138
+ controls?.disconnect();
139
+ } finally {
140
+ cleanup();
141
+ }
137
142
  },
138
143
  mute: () => {
139
144
  controls?.mute();
@@ -161,10 +166,13 @@ export function createVoiceSession(
161
166
  },
162
167
  };
163
168
 
164
- if (options.abortSignal) {
165
- options.abortSignal.addEventListener("abort", () => session.disconnect(), {
166
- once: true,
167
- });
169
+ if (abortSignal) {
170
+ abortHandler = () => session.disconnect();
171
+ abortSignal.addEventListener("abort", abortHandler, { once: true });
172
+ if (abortSignal.aborted) {
173
+ session.disconnect();
174
+ return session;
175
+ }
168
176
  }
169
177
 
170
178
  const doSetup = async () => {
package/src/index.ts CHANGED
@@ -347,6 +347,7 @@ export {
347
347
  // Remote Thread List (user-facing)
348
348
  export type {
349
349
  RemoteThreadListAdapter,
350
+ RuntimeAdapters,
350
351
  RemoteThreadListOptions,
351
352
  RemoteThreadListProviderComponent,
352
353
  RemoteThreadInitializeResponse,
package/src/internal.ts CHANGED
@@ -33,6 +33,7 @@ export {
33
33
  // Message utilities
34
34
  export { getThreadMessageText } from "./utils/text";
35
35
  export { toMessagePartStatus } from "./utils/normalizePartStatus";
36
+ export { notifyEventListeners } from "./utils/notify-event-listeners";
36
37
  export { resolveToolApprovalResponse } from "./runtime/utils/resolveToolApprovalResponse";
37
38
  export { consumeSuggestionResult } from "./adapters/suggestion";
38
39
 
@@ -46,7 +46,15 @@ const createHost = () => {
46
46
  const execute = host.getModelContext().tools?.search?.execute;
47
47
  if (!execute) throw new Error("Expected the search tool to be available");
48
48
 
49
- return { dispatchMessage, execute, host, postMessage };
49
+ const getToolCallId = () => {
50
+ const call = postMessage.mock.calls.find(
51
+ ([data]) => data.message.type === "tool-call",
52
+ );
53
+ if (!call) throw new Error("Expected a tool call to be posted");
54
+ return call[0].message.id as string;
55
+ };
56
+
57
+ return { dispatchMessage, execute, getToolCallId, host, postMessage };
50
58
  };
51
59
 
52
60
  beforeEach(() => {
@@ -60,14 +68,14 @@ afterEach(() => {
60
68
 
61
69
  describe("AssistantFrameHost", () => {
62
70
  it("resolves tool calls from frame results", async () => {
63
- const { dispatchMessage, execute, host } = createHost();
71
+ const { dispatchMessage, execute, getToolCallId, host } = createHost();
64
72
  const result = Promise.resolve(
65
73
  execute({ query: "weather" }, executionContext),
66
74
  );
67
75
 
68
76
  dispatchMessage({
69
77
  type: "tool-result",
70
- id: "tool-0",
78
+ id: getToolCallId(),
71
79
  result: "sunny",
72
80
  });
73
81
 
@@ -77,19 +85,27 @@ describe("AssistantFrameHost", () => {
77
85
  });
78
86
 
79
87
  it("rejects pending tool calls when disposed", async () => {
80
- const { execute, host } = createHost();
88
+ const { execute, getToolCallId, host, postMessage } = createHost();
81
89
  const result = Promise.resolve(execute({}, executionContext));
90
+ const toolCallId = getToolCallId();
82
91
 
83
92
  host.dispose();
84
93
 
85
94
  await expect(result).rejects.toThrow(
86
95
  "AssistantFrameHost has been disposed",
87
96
  );
97
+ expect(postMessage).toHaveBeenLastCalledWith(
98
+ {
99
+ channel: FRAME_MESSAGE_CHANNEL,
100
+ message: { type: "tool-cancel", id: toolCallId },
101
+ },
102
+ "*",
103
+ );
88
104
  expect(vi.getTimerCount()).toBe(0);
89
105
  });
90
106
 
91
107
  it("rejects pending tool calls when execution is aborted", async () => {
92
- const { execute, host } = createHost();
108
+ const { execute, getToolCallId, host, postMessage } = createHost();
93
109
  const abortController = new AbortController();
94
110
  const abortError = new Error("Run cancelled");
95
111
  abortError.name = "AbortError";
@@ -104,15 +120,58 @@ describe("AssistantFrameHost", () => {
104
120
  );
105
121
  const onRejected = vi.fn();
106
122
  void result.catch(onRejected);
123
+ const toolCallId = getToolCallId();
107
124
 
108
125
  abortController.abort(abortError);
109
126
  await Promise.resolve();
110
127
 
111
128
  expect(onRejected).toHaveBeenCalledWith(abortError);
129
+ expect(postMessage).toHaveBeenLastCalledWith(
130
+ {
131
+ channel: FRAME_MESSAGE_CHANNEL,
132
+ message: { type: "tool-cancel", id: toolCallId },
133
+ },
134
+ "*",
135
+ );
136
+ expect(vi.getTimerCount()).toBe(0);
137
+ host.dispose();
138
+ });
139
+
140
+ it("cancels tool calls when they time out", async () => {
141
+ const { execute, getToolCallId, host, postMessage } = createHost();
142
+ const result = Promise.resolve(execute({}, executionContext));
143
+ const toolCallId = getToolCallId();
144
+ const rejection = expect(result).rejects.toThrow(
145
+ 'Tool call "search" timed out',
146
+ );
147
+
148
+ await vi.advanceTimersByTimeAsync(30000);
149
+
150
+ await rejection;
151
+ expect(postMessage).toHaveBeenLastCalledWith(
152
+ {
153
+ channel: FRAME_MESSAGE_CHANNEL,
154
+ message: { type: "tool-cancel", id: toolCallId },
155
+ },
156
+ "*",
157
+ );
112
158
  expect(vi.getTimerCount()).toBe(0);
113
159
  host.dispose();
114
160
  });
115
161
 
162
+ it("uses unique tool IDs across host instances", () => {
163
+ const first = createHost();
164
+ const second = createHost();
165
+
166
+ void first.execute({}, executionContext).catch(() => undefined);
167
+ void second.execute({}, executionContext).catch(() => undefined);
168
+
169
+ expect(first.getToolCallId()).not.toBe(second.getToolCallId());
170
+
171
+ first.host.dispose();
172
+ second.host.dispose();
173
+ });
174
+
116
175
  it("does not post tool calls when execution is already aborted", async () => {
117
176
  const { execute, host, postMessage } = createHost();
118
177
  const abortController = new AbortController();
@@ -144,4 +203,27 @@ describe("AssistantFrameHost", () => {
144
203
  );
145
204
  expect(postMessage).toHaveBeenCalledOnce();
146
205
  });
206
+
207
+ it("isolates subscriber errors while applying context updates", () => {
208
+ const { dispatchMessage, host } = createHost();
209
+ const error = new Error("subscriber failed");
210
+ const laterSubscriber = vi.fn();
211
+
212
+ host.subscribe(() => {
213
+ throw error;
214
+ });
215
+ host.subscribe(laterSubscriber);
216
+
217
+ expect(() =>
218
+ dispatchMessage({
219
+ type: "model-context-update",
220
+ context: { system: "frame instructions" },
221
+ }),
222
+ ).toThrow(error);
223
+
224
+ expect(host.getModelContext().system).toBe("frame instructions");
225
+ expect(laterSubscriber).toHaveBeenCalledOnce();
226
+
227
+ host.dispose();
228
+ });
147
229
  });
@@ -1,6 +1,8 @@
1
1
  import type { ModelContextProvider, ModelContext } from "../types";
2
2
  import type { Unsubscribe } from "../../types/unsubscribe";
3
3
  import type { Tool } from "assistant-stream";
4
+ import { notifySubscribers as notifyStateSubscribers } from "../../subscribable/subscribable";
5
+ import { generateId } from "../../utils/id";
4
6
  import {
5
7
  type FrameMessage,
6
8
  FRAME_MESSAGE_CHANNEL,
@@ -57,7 +59,6 @@ export class AssistantFrameHost implements ModelContextProvider {
57
59
  reject: (error: any) => void;
58
60
  }
59
61
  >();
60
- private _requestCounter = 0;
61
62
  private _iframeWindow: Window;
62
63
  private _targetOrigin: string;
63
64
  private _disposed = false;
@@ -129,7 +130,7 @@ export class AssistantFrameHost implements ModelContextProvider {
129
130
  return this.sendRequest(
130
131
  {
131
132
  type: "tool-call",
132
- id: `tool-${this._requestCounter++}`,
133
+ id: `tool-${generateId()}`,
133
134
  toolName,
134
135
  args,
135
136
  },
@@ -158,6 +159,7 @@ export class AssistantFrameHost implements ModelContextProvider {
158
159
  if (!abortSignal) return;
159
160
  const pending = this._pendingRequests.get(message.id);
160
161
  if (pending) {
162
+ this.cancelToolCall(message.id);
161
163
  pending.reject(getAbortReason(abortSignal));
162
164
  this._pendingRequests.delete(message.id);
163
165
  }
@@ -181,6 +183,7 @@ export class AssistantFrameHost implements ModelContextProvider {
181
183
  timeoutId = setTimeout(() => {
182
184
  const pending = this._pendingRequests.get(message.id);
183
185
  if (pending) {
186
+ this.cancelToolCall(message.id);
184
187
  pending.reject(new Error(timeoutMessage));
185
188
  this._pendingRequests.delete(message.id);
186
189
  }
@@ -194,6 +197,16 @@ export class AssistantFrameHost implements ModelContextProvider {
194
197
  });
195
198
  }
196
199
 
200
+ private cancelToolCall(id: string) {
201
+ this._iframeWindow.postMessage(
202
+ {
203
+ channel: FRAME_MESSAGE_CHANNEL,
204
+ message: { type: "tool-cancel", id } satisfies FrameMessage,
205
+ },
206
+ this._targetOrigin,
207
+ );
208
+ }
209
+
197
210
  private requestContext() {
198
211
  this._iframeWindow.postMessage(
199
212
  {
@@ -207,7 +220,7 @@ export class AssistantFrameHost implements ModelContextProvider {
207
220
  }
208
221
 
209
222
  private notifySubscribers() {
210
- this._subscribers.forEach((callback) => callback());
223
+ notifyStateSubscribers(this._subscribers);
211
224
  }
212
225
 
213
226
  getModelContext(): ModelContext {
@@ -224,7 +237,8 @@ export class AssistantFrameHost implements ModelContextProvider {
224
237
  window.removeEventListener("message", this.handleMessage);
225
238
  this._subscribers.clear();
226
239
  const error = new Error("AssistantFrameHost has been disposed");
227
- for (const pending of this._pendingRequests.values()) {
240
+ for (const [id, pending] of this._pendingRequests) {
241
+ this.cancelToolCall(id);
228
242
  pending.reject(error);
229
243
  }
230
244
  this._pendingRequests.clear();