@assistant-ui/core 0.3.13 → 0.3.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (396) hide show
  1. package/dist/adapters/speech.d.ts.map +1 -1
  2. package/dist/adapters/speech.js +9 -15
  3. package/dist/adapters/speech.js.map +1 -1
  4. package/dist/adapters/thread-history.d.ts +2 -0
  5. package/dist/adapters/thread-history.d.ts.map +1 -1
  6. package/dist/adapters/voice.d.ts.map +1 -1
  7. package/dist/adapters/voice.js +27 -15
  8. package/dist/adapters/voice.js.map +1 -1
  9. package/dist/index.d.ts +2 -2
  10. package/dist/index.js.map +1 -1
  11. package/dist/internal.d.ts +1 -1
  12. package/dist/internal.js +6 -6
  13. package/dist/model-context/frame/host.d.ts.map +1 -1
  14. package/dist/model-context/frame/host.js +2 -1
  15. package/dist/model-context/frame/host.js.map +1 -1
  16. package/dist/model-context/registry.d.ts.map +1 -1
  17. package/dist/model-context/registry.js +16 -4
  18. package/dist/model-context/registry.js.map +1 -1
  19. package/dist/react/RuntimeAdapter.d.ts +8 -1
  20. package/dist/react/RuntimeAdapter.d.ts.map +1 -1
  21. package/dist/react/RuntimeAdapter.js +23 -18
  22. package/dist/react/RuntimeAdapter.js.map +1 -1
  23. package/dist/react/adapters/LocalStorageThreadListAdapter.d.ts.map +1 -1
  24. package/dist/react/adapters/LocalStorageThreadListAdapter.js +28 -12
  25. package/dist/react/adapters/LocalStorageThreadListAdapter.js.map +1 -1
  26. package/dist/react/client/AdaptedRemoteThread.d.ts +11 -0
  27. package/dist/react/client/AdaptedRemoteThread.d.ts.map +1 -0
  28. package/dist/react/client/AdaptedRemoteThread.js +27 -0
  29. package/dist/react/client/AdaptedRemoteThread.js.map +1 -0
  30. package/dist/react/client/InMemoryThreadList.d.ts +19 -0
  31. package/dist/react/client/InMemoryThreadList.d.ts.map +1 -0
  32. package/dist/react/client/InMemoryThreadList.js +418 -0
  33. package/dist/react/client/InMemoryThreadList.js.map +1 -0
  34. package/dist/react/client/Interactables.d.ts.map +1 -1
  35. package/dist/react/client/Interactables.js +159 -102
  36. package/dist/react/client/Interactables.js.map +1 -1
  37. package/dist/react/client/RemoteThreadList.d.ts +34 -0
  38. package/dist/react/client/RemoteThreadList.d.ts.map +1 -0
  39. package/dist/react/client/RemoteThreadList.js +826 -0
  40. package/dist/react/client/RemoteThreadList.js.map +1 -0
  41. package/dist/react/client/Tools.d.ts.map +1 -1
  42. package/dist/react/client/Tools.js +38 -27
  43. package/dist/react/client/Tools.js.map +1 -1
  44. package/dist/react/index.d.ts +7 -2
  45. package/dist/react/index.js +5 -2
  46. package/dist/react/interactables-legacy/Interactables.d.ts.map +1 -1
  47. package/dist/react/interactables-legacy/Interactables.js +145 -110
  48. package/dist/react/interactables-legacy/Interactables.js.map +1 -1
  49. package/dist/react/primitive-hooks/useActionBarCopy.d.ts.map +1 -1
  50. package/dist/react/primitive-hooks/useActionBarCopy.js +13 -18
  51. package/dist/react/primitive-hooks/useActionBarCopy.js.map +1 -1
  52. package/dist/react/primitive-hooks/useActionBarEdit.d.ts.map +1 -1
  53. package/dist/react/primitive-hooks/useActionBarEdit.js +2 -4
  54. package/dist/react/primitive-hooks/useActionBarEdit.js.map +1 -1
  55. package/dist/react/primitive-hooks/useActionBarReload.d.ts.map +1 -1
  56. package/dist/react/primitive-hooks/useActionBarReload.js +2 -4
  57. package/dist/react/primitive-hooks/useActionBarReload.js.map +1 -1
  58. package/dist/react/primitive-hooks/useBranchPickerNext.d.ts.map +1 -1
  59. package/dist/react/primitive-hooks/useBranchPickerNext.js +2 -6
  60. package/dist/react/primitive-hooks/useBranchPickerNext.js.map +1 -1
  61. package/dist/react/primitive-hooks/useBranchPickerPrevious.d.ts.map +1 -1
  62. package/dist/react/primitive-hooks/useBranchPickerPrevious.js +2 -6
  63. package/dist/react/primitive-hooks/useBranchPickerPrevious.js.map +1 -1
  64. package/dist/react/primitive-hooks/useComposerCancel.d.ts.map +1 -1
  65. package/dist/react/primitive-hooks/useComposerCancel.js +2 -4
  66. package/dist/react/primitive-hooks/useComposerCancel.js.map +1 -1
  67. package/dist/react/primitive-hooks/useComposerSend.d.ts.map +1 -1
  68. package/dist/react/primitive-hooks/useComposerSend.js +2 -4
  69. package/dist/react/primitive-hooks/useComposerSend.js.map +1 -1
  70. package/dist/react/primitive-hooks/useSuggestionTrigger.d.ts.map +1 -1
  71. package/dist/react/primitive-hooks/useSuggestionTrigger.js +6 -2
  72. package/dist/react/primitive-hooks/useSuggestionTrigger.js.map +1 -1
  73. package/dist/react/primitives/message/MessageParts.d.ts +13 -0
  74. package/dist/react/primitives/message/MessageParts.d.ts.map +1 -1
  75. package/dist/react/primitives/message/MessageParts.js.map +1 -1
  76. package/dist/react/primitives/thread/ThreadMessages.d.ts.map +1 -1
  77. package/dist/react/primitives/thread/ThreadMessages.js +1 -1
  78. package/dist/react/primitives/thread/ThreadMessages.js.map +1 -1
  79. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts +22 -10
  80. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts.map +1 -1
  81. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js +109 -71
  82. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js.map +1 -1
  83. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts +8 -2
  84. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts.map +1 -1
  85. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js +40 -13
  86. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js.map +1 -1
  87. package/dist/react/runtimes/RemoteThreadResource.d.ts +30 -0
  88. package/dist/react/runtimes/RemoteThreadResource.d.ts.map +1 -0
  89. package/dist/react/runtimes/RemoteThreadResource.js +134 -0
  90. package/dist/react/runtimes/RemoteThreadResource.js.map +1 -0
  91. package/dist/react/runtimes/RuntimeAdapterProvider.d.ts +3 -10
  92. package/dist/react/runtimes/RuntimeAdapterProvider.d.ts.map +1 -1
  93. package/dist/react/runtimes/RuntimeAdapterProvider.js +3 -6
  94. package/dist/react/runtimes/RuntimeAdapterProvider.js.map +1 -1
  95. package/dist/react/runtimes/assistant-transport/commandQueue.d.ts +17 -0
  96. package/dist/react/runtimes/assistant-transport/commandQueue.d.ts.map +1 -0
  97. package/dist/react/runtimes/assistant-transport/commandQueue.js +55 -0
  98. package/dist/react/runtimes/assistant-transport/commandQueue.js.map +1 -0
  99. package/dist/react/runtimes/assistant-transport/replayBoundaryStream.d.ts +11 -0
  100. package/dist/react/runtimes/assistant-transport/replayBoundaryStream.d.ts.map +1 -0
  101. package/dist/react/runtimes/assistant-transport/replayBoundaryStream.js +165 -0
  102. package/dist/react/runtimes/assistant-transport/replayBoundaryStream.js.map +1 -0
  103. package/dist/react/runtimes/assistant-transport/runManager.d.ts +15 -0
  104. package/dist/react/runtimes/assistant-transport/runManager.d.ts.map +1 -0
  105. package/dist/react/runtimes/assistant-transport/runManager.js +86 -0
  106. package/dist/react/runtimes/assistant-transport/runManager.js.map +1 -0
  107. package/dist/react/runtimes/assistant-transport/types.d.ts +130 -0
  108. package/dist/react/runtimes/assistant-transport/types.d.ts.map +1 -0
  109. package/dist/react/runtimes/assistant-transport/types.js +0 -0
  110. package/dist/react/runtimes/assistant-transport/useAssistantTransportRuntime.d.ts +14 -0
  111. package/dist/react/runtimes/assistant-transport/useAssistantTransportRuntime.d.ts.map +1 -0
  112. package/dist/react/runtimes/assistant-transport/useAssistantTransportRuntime.js +296 -0
  113. package/dist/react/runtimes/assistant-transport/useAssistantTransportRuntime.js.map +1 -0
  114. package/dist/react/runtimes/assistant-transport/useConvertedState.d.ts +7 -0
  115. package/dist/react/runtimes/assistant-transport/useConvertedState.d.ts.map +1 -0
  116. package/dist/react/runtimes/assistant-transport/useConvertedState.js +25 -0
  117. package/dist/react/runtimes/assistant-transport/useConvertedState.js.map +1 -0
  118. package/dist/react/runtimes/assistant-transport/useLatestRef.d.ts +7 -0
  119. package/dist/react/runtimes/assistant-transport/useLatestRef.d.ts.map +1 -0
  120. package/dist/react/runtimes/assistant-transport/useLatestRef.js +27 -0
  121. package/dist/react/runtimes/assistant-transport/useLatestRef.js.map +1 -0
  122. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts.map +1 -1
  123. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js +39 -13
  124. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js.map +1 -1
  125. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.d.ts +2 -1
  126. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.d.ts.map +1 -1
  127. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.js +3 -3
  128. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.js.map +1 -1
  129. package/dist/react/runtimes/cloud/auiV0.d.ts +4 -0
  130. package/dist/react/runtimes/cloud/auiV0.d.ts.map +1 -1
  131. package/dist/react/runtimes/cloud/auiV0.js +7 -0
  132. package/dist/react/runtimes/cloud/auiV0.js.map +1 -1
  133. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.d.ts.map +1 -1
  134. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js +22 -12
  135. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js.map +1 -1
  136. package/dist/react/runtimes/cloud/useCloudThreadListRuntime.d.ts +16 -0
  137. package/dist/react/runtimes/cloud/useCloudThreadListRuntime.d.ts.map +1 -0
  138. package/dist/react/runtimes/cloud/useCloudThreadListRuntime.js +36 -0
  139. package/dist/react/runtimes/cloud/useCloudThreadListRuntime.js.map +1 -0
  140. package/dist/react/runtimes/external-message-converter.js +14 -14
  141. package/dist/react/runtimes/external-message-converter.js.map +1 -1
  142. package/dist/react/runtimes/useExternalStoreRuntime.d.ts.map +1 -1
  143. package/dist/react/runtimes/useExternalStoreRuntime.js +44 -28
  144. package/dist/react/runtimes/useExternalStoreRuntime.js.map +1 -1
  145. package/dist/react/runtimes/useExternalStoreSharedOptions.js.map +1 -1
  146. package/dist/react/runtimes/useLocalRuntime.js +1 -1
  147. package/dist/react/runtimes/useRuntimeAdapters.d.ts +9 -0
  148. package/dist/react/runtimes/useRuntimeAdapters.d.ts.map +1 -0
  149. package/dist/react/runtimes/useRuntimeAdapters.js +20 -0
  150. package/dist/react/runtimes/useRuntimeAdapters.js.map +1 -0
  151. package/dist/runtime/api/composer-runtime.d.ts +5 -0
  152. package/dist/runtime/api/composer-runtime.d.ts.map +1 -1
  153. package/dist/runtime/api/composer-runtime.js.map +1 -1
  154. package/dist/runtime/api/message-runtime.js +1 -1
  155. package/dist/runtime/api/thread-list-runtime.d.ts +1 -0
  156. package/dist/runtime/api/thread-list-runtime.d.ts.map +1 -1
  157. package/dist/runtime/api/thread-list-runtime.js +4 -2
  158. package/dist/runtime/api/thread-list-runtime.js.map +1 -1
  159. package/dist/runtime/api/thread-runtime.d.ts +12 -2
  160. package/dist/runtime/api/thread-runtime.d.ts.map +1 -1
  161. package/dist/runtime/api/thread-runtime.js +8 -2
  162. package/dist/runtime/api/thread-runtime.js.map +1 -1
  163. package/dist/runtime/base/base-composer-runtime-core.d.ts.map +1 -1
  164. package/dist/runtime/base/base-composer-runtime-core.js +8 -7
  165. package/dist/runtime/base/base-composer-runtime-core.js.map +1 -1
  166. package/dist/runtime/base/base-thread-runtime-core.d.ts +1 -0
  167. package/dist/runtime/base/base-thread-runtime-core.d.ts.map +1 -1
  168. package/dist/runtime/base/base-thread-runtime-core.js +3 -3
  169. package/dist/runtime/base/base-thread-runtime-core.js.map +1 -1
  170. package/dist/runtime/base/default-thread-composer-runtime-core.d.ts +0 -1
  171. package/dist/runtime/base/default-thread-composer-runtime-core.d.ts.map +1 -1
  172. package/dist/runtime/base/default-thread-composer-runtime-core.js +10 -4
  173. package/dist/runtime/base/default-thread-composer-runtime-core.js.map +1 -1
  174. package/dist/runtime/interfaces/thread-runtime-core.d.ts +6 -0
  175. package/dist/runtime/interfaces/thread-runtime-core.d.ts.map +1 -1
  176. package/dist/runtime/internal.js +5 -5
  177. package/dist/runtime/queue/message-queue.d.ts.map +1 -1
  178. package/dist/runtime/queue/message-queue.js +2 -1
  179. package/dist/runtime/queue/message-queue.js.map +1 -1
  180. package/dist/runtime/utils/thread-runtime-lifecycle.d.ts +8 -0
  181. package/dist/runtime/utils/thread-runtime-lifecycle.d.ts.map +1 -0
  182. package/dist/runtime/utils/thread-runtime-lifecycle.js +11 -0
  183. package/dist/runtime/utils/thread-runtime-lifecycle.js.map +1 -0
  184. package/dist/runtimes/external-store/external-store-shared-options.js.map +1 -1
  185. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.d.ts.map +1 -1
  186. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js +4 -1
  187. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js.map +1 -1
  188. package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts +8 -0
  189. package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts.map +1 -1
  190. package/dist/runtimes/external-store/external-store-thread-runtime-core.js +35 -13
  191. package/dist/runtimes/external-store/external-store-thread-runtime-core.js.map +1 -1
  192. package/dist/runtimes/internal.d.ts +1 -1
  193. package/dist/runtimes/local/local-thread-runtime-core.d.ts +3 -0
  194. package/dist/runtimes/local/local-thread-runtime-core.d.ts.map +1 -1
  195. package/dist/runtimes/local/local-thread-runtime-core.js +53 -13
  196. package/dist/runtimes/local/local-thread-runtime-core.js.map +1 -1
  197. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.d.ts +1 -0
  198. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.d.ts.map +1 -1
  199. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.js +3 -0
  200. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.js.map +1 -1
  201. package/dist/runtimes/remote-thread-list/empty-thread-core.js +3 -0
  202. package/dist/runtimes/remote-thread-list/empty-thread-core.js.map +1 -1
  203. package/dist/runtimes/remote-thread-list/types.d.ts +29 -1
  204. package/dist/runtimes/remote-thread-list/types.d.ts.map +1 -1
  205. package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts +1 -12
  206. package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts.map +1 -1
  207. package/dist/runtimes/tool-invocations/ToolInvocationTracker.js +67 -38
  208. package/dist/runtimes/tool-invocations/ToolInvocationTracker.js.map +1 -1
  209. package/dist/store/clients/suggestions.js +2 -2
  210. package/dist/store/clients/suggestions.js.map +1 -1
  211. package/dist/store/clients/thread-selection-events.d.ts +10 -0
  212. package/dist/store/clients/thread-selection-events.d.ts.map +1 -0
  213. package/dist/store/clients/thread-selection-events.js +40 -0
  214. package/dist/store/clients/thread-selection-events.js.map +1 -0
  215. package/dist/store/env.d.ts +5 -0
  216. package/dist/store/env.d.ts.map +1 -0
  217. package/dist/store/env.js +12 -0
  218. package/dist/store/env.js.map +1 -0
  219. package/dist/store/index.d.ts +5 -3
  220. package/dist/store/index.js +4 -2
  221. package/dist/store/internal.d.ts +4 -1
  222. package/dist/store/internal.js +4 -1
  223. package/dist/store/primitive-predicates.d.ts +19 -0
  224. package/dist/store/primitive-predicates.d.ts.map +1 -0
  225. package/dist/store/primitive-predicates.js +19 -0
  226. package/dist/store/primitive-predicates.js.map +1 -0
  227. package/dist/store/runtime-clients/attachment-runtime-client.d.ts.map +1 -1
  228. package/dist/store/runtime-clients/attachment-runtime-client.js +18 -11
  229. package/dist/store/runtime-clients/attachment-runtime-client.js.map +1 -1
  230. package/dist/store/runtime-clients/handle-runtime-action.d.ts +5 -0
  231. package/dist/store/runtime-clients/handle-runtime-action.d.ts.map +1 -0
  232. package/dist/store/runtime-clients/handle-runtime-action.js +12 -0
  233. package/dist/store/runtime-clients/handle-runtime-action.js.map +1 -0
  234. package/dist/store/runtime-clients/handle-thread-list-action.d.ts +5 -0
  235. package/dist/store/runtime-clients/handle-thread-list-action.d.ts.map +1 -0
  236. package/dist/store/runtime-clients/handle-thread-list-action.js +7 -0
  237. package/dist/store/runtime-clients/handle-thread-list-action.js.map +1 -0
  238. package/dist/store/runtime-clients/thread-list-item-runtime-client.d.ts.map +1 -1
  239. package/dist/store/runtime-clients/thread-list-item-runtime-client.js +62 -29
  240. package/dist/store/runtime-clients/thread-list-item-runtime-client.js.map +1 -1
  241. package/dist/store/runtime-clients/thread-list-runtime-client.d.ts.map +1 -1
  242. package/dist/store/runtime-clients/thread-list-runtime-client.js +5 -6
  243. package/dist/store/runtime-clients/thread-list-runtime-client.js.map +1 -1
  244. package/dist/store/scopes/composer.d.ts +9 -4
  245. package/dist/store/scopes/composer.d.ts.map +1 -1
  246. package/dist/store/scopes/thread-list-item.d.ts +7 -6
  247. package/dist/store/scopes/thread-list-item.d.ts.map +1 -1
  248. package/dist/store/scopes/thread.d.ts +8 -7
  249. package/dist/store/scopes/thread.d.ts.map +1 -1
  250. package/dist/store/scopes/threads.d.ts +17 -1
  251. package/dist/store/scopes/threads.d.ts.map +1 -1
  252. package/dist/subscribable/subscribable.d.ts +2 -1
  253. package/dist/subscribable/subscribable.d.ts.map +1 -1
  254. package/dist/subscribable/subscribable.js +23 -18
  255. package/dist/subscribable/subscribable.js.map +1 -1
  256. package/dist/utils/composite-context-provider.d.ts +1 -0
  257. package/dist/utils/composite-context-provider.d.ts.map +1 -1
  258. package/dist/utils/composite-context-provider.js +25 -9
  259. package/dist/utils/composite-context-provider.js.map +1 -1
  260. package/dist/utils/notify-event-listeners.d.ts +2 -2
  261. package/dist/utils/notify-event-listeners.d.ts.map +1 -1
  262. package/dist/utils/notify-event-listeners.js +2 -2
  263. package/dist/utils/notify-event-listeners.js.map +1 -1
  264. package/package.json +7 -7
  265. package/src/adapters/speech.test.ts +118 -1
  266. package/src/adapters/speech.ts +21 -22
  267. package/src/adapters/thread-history.ts +2 -0
  268. package/src/adapters/voice.test.ts +69 -0
  269. package/src/adapters/voice.ts +27 -27
  270. package/src/index.ts +1 -0
  271. package/src/model-context/frame/host.test.ts +23 -0
  272. package/src/model-context/frame/host.ts +2 -1
  273. package/src/model-context/registry.test.ts +131 -0
  274. package/src/model-context/registry.ts +16 -6
  275. package/src/react/RuntimeAdapter.test.ts +2 -0
  276. package/src/react/RuntimeAdapter.ts +20 -8
  277. package/src/react/adapters/LocalStorageThreadListAdapter.tsx +34 -17
  278. package/src/react/client/AdaptedRemoteThread.ts +41 -0
  279. package/src/react/client/InMemoryThreadList.test.tsx +148 -0
  280. package/src/react/client/InMemoryThreadList.ts +290 -0
  281. package/src/react/client/Interactables.test.ts +326 -2
  282. package/src/react/client/Interactables.ts +227 -110
  283. package/src/react/client/RemoteThreadList.test.ts +1026 -0
  284. package/src/react/client/RemoteThreadList.ts +1067 -0
  285. package/src/react/client/Tools.ts +36 -29
  286. package/src/react/index.ts +13 -0
  287. package/src/react/interactables-legacy/Interactables.test.ts +317 -0
  288. package/src/react/interactables-legacy/Interactables.ts +204 -128
  289. package/src/react/primitive-hooks/useActionBarCopy.ts +2 -7
  290. package/src/react/primitive-hooks/useActionBarEdit.ts +2 -1
  291. package/src/react/primitive-hooks/useActionBarReload.ts +2 -6
  292. package/src/react/primitive-hooks/useBranchPickerNext.ts +2 -7
  293. package/src/react/primitive-hooks/useBranchPickerPrevious.ts +2 -7
  294. package/src/react/primitive-hooks/useComposerCancel.ts +2 -1
  295. package/src/react/primitive-hooks/useComposerSend.ts +2 -5
  296. package/src/react/primitive-hooks/useSuggestionTrigger.test.ts +11 -0
  297. package/src/react/primitive-hooks/useSuggestionTrigger.ts +4 -5
  298. package/src/react/primitives/message/MessageParts.tsx +0 -1
  299. package/src/react/primitives/thread/ThreadMessages.tsx +2 -1
  300. package/src/react/runtimes/RemoteThreadListHookInstanceManager.retry.test.tsx +116 -0
  301. package/src/react/runtimes/RemoteThreadListHookInstanceManager.running.test.tsx +1 -1
  302. package/src/react/runtimes/RemoteThreadListHookInstanceManager.test.tsx +57 -6
  303. package/src/react/runtimes/RemoteThreadListHookInstanceManager.title.test.tsx +272 -0
  304. package/src/react/runtimes/RemoteThreadListHookInstanceManager.tsx +159 -124
  305. package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.tsx +59 -20
  306. package/src/react/runtimes/RemoteThreadResource.test.ts +141 -0
  307. package/src/react/runtimes/RemoteThreadResource.ts +231 -0
  308. package/src/react/runtimes/RuntimeAdapterProvider.tsx +8 -20
  309. package/src/react/runtimes/assistant-transport/commandQueue.ts +68 -0
  310. package/src/react/runtimes/assistant-transport/replayBoundaryStream.test.ts +455 -0
  311. package/src/react/runtimes/assistant-transport/replayBoundaryStream.ts +172 -0
  312. package/src/react/runtimes/assistant-transport/runManager.ts +124 -0
  313. package/src/react/runtimes/assistant-transport/transport-delivery.test.tsx +79 -0
  314. package/src/react/runtimes/assistant-transport/transport-parentid.test.tsx +97 -0
  315. package/src/react/runtimes/assistant-transport/transport-scheduling.test.ts +414 -0
  316. package/src/react/runtimes/assistant-transport/types.ts +170 -0
  317. package/src/react/runtimes/assistant-transport/useAssistantTransport.spec.md +141 -0
  318. package/src/react/runtimes/assistant-transport/useAssistantTransportRuntime.test.tsx +625 -0
  319. package/src/react/runtimes/assistant-transport/useAssistantTransportRuntime.ts +481 -0
  320. package/src/react/runtimes/assistant-transport/useConvertedState.ts +20 -0
  321. package/src/react/runtimes/assistant-transport/useLatestRef.ts +9 -0
  322. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.test.tsx +131 -6
  323. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.ts +61 -15
  324. package/src/react/runtimes/cloud/CloudFileAttachmentAdapter.ts +6 -4
  325. package/src/react/runtimes/cloud/auiV0.ts +17 -1
  326. package/src/react/runtimes/cloud/useCloudThreadListAdapter.tsx +36 -21
  327. package/src/react/runtimes/cloud/useCloudThreadListRuntime.test.tsx +56 -0
  328. package/src/react/runtimes/cloud/useCloudThreadListRuntime.ts +31 -0
  329. package/src/react/runtimes/external-message-converter.test.ts +143 -0
  330. package/src/react/runtimes/external-message-converter.ts +41 -41
  331. package/src/react/runtimes/remote-thread-hook-on-tap.test.ts +58 -0
  332. package/src/react/runtimes/useExternalStoreRuntime.lifecycle.test.tsx +83 -0
  333. package/src/react/runtimes/useExternalStoreRuntime.suggestions.test.tsx +13 -3
  334. package/src/react/runtimes/useExternalStoreRuntime.ts +7 -0
  335. package/src/react/runtimes/useExternalStoreSharedOptions.ts +3 -1
  336. package/src/react/runtimes/useLocalRuntime.test.tsx +130 -4
  337. package/src/react/runtimes/useRuntimeAdapters.test.tsx +62 -0
  338. package/src/react/runtimes/useRuntimeAdapters.ts +28 -0
  339. package/src/runtime/api/composer-runtime.ts +5 -0
  340. package/src/runtime/api/thread-list-runtime.ts +3 -1
  341. package/src/runtime/api/thread-runtime.ts +20 -2
  342. package/src/runtime/base/base-composer-runtime-core.ts +6 -5
  343. package/src/runtime/base/base-thread-runtime-core.test.ts +191 -0
  344. package/src/runtime/base/base-thread-runtime-core.ts +11 -2
  345. package/src/runtime/base/default-thread-composer-runtime-core.ts +12 -4
  346. package/src/runtime/interfaces/thread-runtime-core.ts +6 -0
  347. package/src/runtime/queue/message-queue.ts +2 -1
  348. package/src/runtime/utils/thread-runtime-lifecycle.ts +18 -0
  349. package/src/runtimes/external-store/external-store-shared-options.ts +3 -1
  350. package/src/runtimes/external-store/external-store-thread-list-runtime-core.ts +4 -1
  351. package/src/runtimes/external-store/external-store-thread-runtime-core.ts +99 -34
  352. package/src/runtimes/local/local-thread-runtime-core.test.ts +373 -4
  353. package/src/runtimes/local/local-thread-runtime-core.ts +79 -14
  354. package/src/runtimes/readonly/ReadonlyThreadRuntimeCore.ts +4 -0
  355. package/src/runtimes/remote-thread-list/empty-thread-core.ts +4 -0
  356. package/src/runtimes/remote-thread-list/types.ts +30 -0
  357. package/src/runtimes/tool-invocations/EDGE_CASES.md +17 -6
  358. package/src/runtimes/tool-invocations/ToolInvocationTracker.test.ts +243 -0
  359. package/src/runtimes/tool-invocations/ToolInvocationTracker.ts +127 -61
  360. package/src/store/clients/model-context-client.test.ts +16 -8
  361. package/src/store/clients/suggestions.ts +2 -2
  362. package/src/store/clients/thread-selection-events.ts +21 -0
  363. package/src/store/env.ts +11 -0
  364. package/src/store/index.ts +14 -1
  365. package/src/store/internal.ts +13 -0
  366. package/src/store/primitive-predicates.test.ts +184 -0
  367. package/src/store/primitive-predicates.ts +43 -0
  368. package/src/store/runtime-clients/attachment-runtime-client.test.ts +41 -0
  369. package/src/store/runtime-clients/attachment-runtime-client.ts +2 -1
  370. package/src/store/runtime-clients/handle-runtime-action.ts +11 -0
  371. package/src/store/runtime-clients/handle-thread-list-action.test.ts +69 -0
  372. package/src/store/runtime-clients/handle-thread-list-action.ts +6 -0
  373. package/src/store/runtime-clients/thread-list-item-runtime-client.ts +15 -7
  374. package/src/store/runtime-clients/thread-list-runtime-client.ts +9 -6
  375. package/src/store/scopes/composer.ts +9 -4
  376. package/src/store/scopes/thread-list-item.ts +7 -6
  377. package/src/store/scopes/thread.ts +8 -7
  378. package/src/store/scopes/threads.ts +14 -0
  379. package/src/subscribable/subscribable.test.ts +77 -1
  380. package/src/subscribable/subscribable.ts +38 -23
  381. package/src/tests/RemoteThreadListThreadListRuntimeCore-switchToThread-unarchive.test.ts +25 -0
  382. package/src/tests/auiV0Encode.test.ts +66 -0
  383. package/src/tests/base-composer-runtime-core-send.test.ts +30 -0
  384. package/src/tests/base-composer-runtime-core.test.ts +28 -0
  385. package/src/tests/composer-can-cancel.test.ts +101 -0
  386. package/src/tests/external-store-thread-list-runtime-core.test.ts +101 -0
  387. package/src/tests/external-store-thread-runtime-core-adapter.test.ts +191 -1
  388. package/src/tests/external-store-thread-runtime-core.test.ts +124 -0
  389. package/src/tests/interactables-toolui-migration.test.tsx +66 -0
  390. package/src/tests/message-queue.test.ts +28 -0
  391. package/src/tests/session-reset-notification.test.ts +145 -0
  392. package/src/tests/thread-switch-events.test.tsx +99 -1
  393. package/src/tests/tools-scope-migration.test.tsx +58 -0
  394. package/src/utils/composite-context-provider.test.ts +139 -0
  395. package/src/utils/composite-context-provider.ts +26 -8
  396. package/src/utils/notify-event-listeners.ts +10 -5
@@ -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[]>) => {
@@ -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
  }
@@ -42,9 +42,25 @@ import { generateId } from "../../utils/id";
42
42
  import { ToolInvocationTracker } from "../tool-invocations/ToolInvocationTracker";
43
43
  import { EMPTY_QUEUE_ITEMS } from "../../store/scopes/queue-item";
44
44
  import type { QuoteInfo } from "../../types/quote";
45
+ import {
46
+ captureThreadRuntimeGeneration,
47
+ isThreadRuntimeGenerationCurrent,
48
+ } from "../../runtime/utils/thread-runtime-lifecycle";
45
49
 
46
50
  const EMPTY_ARRAY: readonly ThreadSuggestion[] = Object.freeze([]);
47
51
 
52
+ const observeAdapterCallback = (
53
+ name: "onAddToolResult" | "onRespondToToolApproval" | "onCancel",
54
+ result: Promise<void> | void,
55
+ ) => {
56
+ void Promise.resolve(result).catch((error) => {
57
+ console.error(
58
+ `[ExternalStoreThreadRuntimeCore] ${name} callback rejected`,
59
+ error,
60
+ );
61
+ });
62
+ };
63
+
48
64
  const shallowEqual = (a: object, b: object): boolean => {
49
65
  const aKeys = Object.keys(a);
50
66
  if (aKeys.length !== Object.keys(b).length) return false;
@@ -122,6 +138,14 @@ export class ExternalStoreThreadRuntimeCore
122
138
 
123
139
  private _store!: ExternalStoreAdapter<any>;
124
140
 
141
+ private _getInitializePromise?: () => Promise<unknown> | undefined;
142
+
143
+ public __internal_setGetInitializePromise(
144
+ getPromise: () => Promise<unknown> | undefined,
145
+ ) {
146
+ this._getInitializePromise = getPromise;
147
+ }
148
+
125
149
  private _transformedQueue: ExternalThreadQueueAdapter | undefined;
126
150
 
127
151
  /**
@@ -375,19 +399,22 @@ export class ExternalStoreThreadRuntimeCore
375
399
  // rolled back). Drop the result.
376
400
  return;
377
401
  }
378
- this._store.onAddToolResult?.({
379
- messageId,
380
- toolCallId: command.toolCallId,
381
- toolName: command.toolName,
382
- result: command.result,
383
- isError: command.isError,
384
- ...(command.artifact !== undefined && {
385
- artifact: command.artifact,
386
- }),
387
- ...(command.modelContent !== undefined && {
388
- modelContent: command.modelContent,
402
+ observeAdapterCallback(
403
+ "onAddToolResult",
404
+ this._store.onAddToolResult?.({
405
+ messageId,
406
+ toolCallId: command.toolCallId,
407
+ toolName: command.toolName,
408
+ result: command.result,
409
+ isError: command.isError,
410
+ ...(command.artifact !== undefined && {
411
+ artifact: command.artifact,
412
+ }),
413
+ ...(command.modelContent !== undefined && {
414
+ modelContent: command.modelContent,
415
+ }),
389
416
  }),
390
- });
417
+ );
391
418
  } catch (err) {
392
419
  console.error(
393
420
  "[ExternalStoreThreadRuntimeCore] onAddToolResult dispatch failed",
@@ -492,22 +519,46 @@ export class ExternalStoreThreadRuntimeCore
492
519
  rawMessage.sourceId != null ||
493
520
  rawMessage.parentId !== (this.messages.at(-1)?.id ?? null);
494
521
 
495
- // Buffering does not start a run, so the tool-abort below must wait until
496
- // the queue flushes. By then the prior run (and its tools) has settled.
522
+ // A transformed-queue send is stamped at flush; any other queue's
523
+ // transform would gate against its own thread's messages, so those stamp
524
+ // at send.
525
+ const message =
526
+ !isEdit &&
527
+ this._store.queue &&
528
+ this._store.queue === this._transformedQueue
529
+ ? rawMessage
530
+ : this.enrichAppendMetadata(rawMessage);
531
+
532
+ const generation = captureThreadRuntimeGeneration(this);
533
+ this.ensureInitialized();
534
+
535
+ // The getter call is what starts thread initialization.
536
+ const initPromise = this._getInitializePromise?.();
537
+
538
+ // The queue driver dispatches through the host adapter, outside this
539
+ // core, so the initialization barrier must run before a message can
540
+ // enter the queue.
497
541
  if (!isEdit && this._store.queue) {
498
- // Skip only for the queue this core actually installed on: another
499
- // core's transform would gate against its own thread's messages.
500
- const queued =
501
- this._store.queue === this._transformedQueue
502
- ? rawMessage
503
- : this.enrichAppendMetadata(rawMessage);
504
- if (queued.steer ?? this._store.isRunning ?? false)
505
- this._store.queue.steer(queued);
506
- else this._store.queue.enqueue(queued);
542
+ if (initPromise) {
543
+ await initPromise;
544
+ }
545
+ if (!isThreadRuntimeGenerationCurrent(this, generation)) return;
546
+
547
+ // Buffering does not start a run, so the tool-abort below must wait
548
+ // until the queue flushes. By then the prior run (and its tools) has
549
+ // settled.
550
+ if (message.steer ?? this._store.isRunning ?? false)
551
+ this._store.queue.steer(message);
552
+ else this._store.queue.enqueue(message);
507
553
  return;
508
554
  }
509
555
 
510
- const message = this.enrichAppendMetadata(rawMessage);
556
+ // The optimistic insert lives inside the adapter's dispatch, so holding
557
+ // `onNew` on initialization would keep the message off screen for the
558
+ // whole roundtrip. Seams that need the remote identity await
559
+ // `threadListItem.initialize()` themselves, and a rejection surfaces
560
+ // there.
561
+ void initPromise?.catch(() => {});
511
562
 
512
563
  // Auto-abort in-flight client-side tool executions when a new run is
513
564
  // about to start. Without this, a tool that finishes after the new turn
@@ -518,6 +569,7 @@ export class ExternalStoreThreadRuntimeCore
518
569
  if (message.startRun ?? message.role === "user") {
519
570
  await this._toolInvocations?.abort();
520
571
  }
572
+ if (!isThreadRuntimeGenerationCurrent(this, generation)) return;
521
573
 
522
574
  if (isEdit) {
523
575
  if (!this._store.onEdit)
@@ -600,17 +652,24 @@ export class ExternalStoreThreadRuntimeCore
600
652
  // imported state) is treated as historical — no streamCall/execute
601
653
  // fires for the loaded tool calls. The adapter is expected to update
602
654
  // its messages in response to onLoadExternalState; that update flows
603
- // back here via __internal_setAdapter. We only clear adapter-side
604
- // tool statuses when the tracker is the source of truth — otherwise
605
- // we'd wipe statuses the adapter is managing on its own.
606
- if (this._toolInvocations) {
607
- this._toolInvocations.reset();
608
- this._store.setToolStatuses?.({});
609
- }
655
+ // back here via __internal_setAdapter. The tracker publishes the
656
+ // cleared status map itself, so adapter-side statuses reset only when
657
+ // the tracker is the source of truth.
658
+ this._toolInvocations?.reset();
610
659
 
611
660
  this._store.onLoadExternalState(state);
612
661
  }
613
662
 
663
+ /**
664
+ * Adapter-facing notification that the backing session was discarded.
665
+ * Clears session-scoped tool-invocation state and parks queued work,
666
+ * without run-cancel semantics (`onCancel`, composer draft restoration).
667
+ */
668
+ public unstable_notifySessionReset(): void {
669
+ this._toolInvocations?.reset();
670
+ this._store.queue?.__internal_notifyCancelled?.();
671
+ }
672
+
614
673
  public cancelRun(): void {
615
674
  if (!this._store.onCancel)
616
675
  throw new Error("Runtime does not support cancelling runs.");
@@ -625,7 +684,7 @@ export class ExternalStoreThreadRuntimeCore
625
684
  // stopped.
626
685
  this._store.queue?.__internal_notifyCancelled?.();
627
686
 
628
- this._store.onCancel();
687
+ observeAdapterCallback("onCancel", this._store.onCancel());
629
688
 
630
689
  this.dropEmptyOptimisticHead();
631
690
 
@@ -700,7 +759,10 @@ export class ExternalStoreThreadRuntimeCore
700
759
  public addToolResult(options: AddToolResultOptions) {
701
760
  if (!this._store.onAddToolResult)
702
761
  throw new Error("Runtime does not support tool results.");
703
- this._store.onAddToolResult?.(options);
762
+ observeAdapterCallback(
763
+ "onAddToolResult",
764
+ this._store.onAddToolResult(options),
765
+ );
704
766
  }
705
767
 
706
768
  public resumeToolCall(options: ResumeToolCallOptions) {
@@ -726,7 +788,10 @@ export class ExternalStoreThreadRuntimeCore
726
788
  public respondToToolApproval(options: RespondToToolApprovalOptions) {
727
789
  if (!this._store.onRespondToToolApproval)
728
790
  throw new Error("Runtime does not support tool approvals.");
729
- this._store.onRespondToToolApproval(options);
791
+ observeAdapterCallback(
792
+ "onRespondToToolApproval",
793
+ this._store.onRespondToToolApproval(options),
794
+ );
730
795
  }
731
796
 
732
797
  public override reset(initialMessages?: readonly ThreadMessageLike[]) {