@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
@@ -7,6 +7,7 @@ import {
7
7
  unstable_toolResultStream,
8
8
  type Tool,
9
9
  type ToolModelContentPart,
10
+ type ToolResultStreamOptions,
10
11
  } from "assistant-stream";
11
12
  import {
12
13
  AssistantMetaTransformStream,
@@ -15,6 +16,8 @@ import {
15
16
  import { isJSONValueEqual } from "../../utils/json/is-json-equal";
16
17
  import type { ThreadMessage } from "../../types/message";
17
18
 
19
+ const TOOL_EXECUTION_ID = Symbol.for("assistant-stream.tool-execution-id");
20
+
18
21
  /**
19
22
  * Streaming execution state for a frontend tool.
20
23
  */
@@ -39,6 +42,8 @@ type ToolCallEntry = {
39
42
  toolName: string;
40
43
  argsText: string;
41
44
  hasResult: boolean;
45
+ executionId?: symbol;
46
+ skipExecute?: boolean;
42
47
  } & (
43
48
  | {
44
49
  /** Restored phase — observed during a history-load snapshot. */
@@ -52,6 +57,11 @@ type ToolCallEntry = {
52
57
  }
53
58
  );
54
59
 
60
+ type SettledResolver = {
61
+ executionIds: ReadonlySet<symbol>;
62
+ resolve: () => void;
63
+ };
64
+
55
65
  const isArgsTextComplete = (argsText: string) => {
56
66
  try {
57
67
  JSON.parse(argsText);
@@ -76,6 +86,11 @@ const isEquivalentCompleteArgsText = (previous: string, next: string) => {
76
86
  return isJSONValueEqual(previousValue, nextValue);
77
87
  };
78
88
 
89
+ const getToolExecutionId = (value: object): symbol | undefined =>
90
+ (value as Record<PropertyKey, unknown>)[TOOL_EXECUTION_ID] as
91
+ | symbol
92
+ | undefined;
93
+
79
94
  /**
80
95
  * Plain-class port of the former `useToolInvocations` React hook. Owns the
81
96
  * assistant-stream pipeline that drives client-side `streamCall` / `execute`
@@ -103,27 +118,16 @@ export class ToolInvocationTracker {
103
118
  private readonly _callbacks: ToolInvocationTracker.Callbacks;
104
119
 
105
120
  private readonly _entries = new Map<string, ToolCallEntry>();
106
- /**
107
- * Tool call ids whose `execute` should be short-circuited in the wrapper.
108
- * Populated when an entry is created with a result already attached
109
- * (history reload, mid-run resume, etc.) — `execute` is suppressed so
110
- * client-side side effects don't double-run. Membership outlives the
111
- * entry: `reset()` deliberately does *not* clear this so post-abort
112
- * cancellation `result` chunks for pre-resolved entries can still be
113
- * recognized and dropped. Growth is bounded by the number of pre-resolved
114
- * tool calls observed in the session.
115
- */
116
- private readonly _skipExecuteStreamIds = new Set<string>();
117
121
  private readonly _humanInput = new Map<
118
122
  string,
119
123
  {
124
+ executionId: symbol;
120
125
  resolve: (payload: unknown) => void;
121
126
  reject: (reason: unknown) => void;
122
127
  }
123
128
  >();
124
- /** In-flight `execute` invocations keyed by tool call id. */
125
- private readonly _executing = new Set<string>();
126
- private readonly _settledResolvers: Array<() => void> = [];
129
+ private readonly _executing = new Set<symbol>();
130
+ private readonly _settledResolvers: SettledResolver[] = [];
127
131
 
128
132
  private _statuses = new Map<string, ToolExecutionStatus>();
129
133
 
@@ -166,14 +170,21 @@ export class ToolInvocationTracker {
166
170
  const [stream, controller] = createAssistantStreamController();
167
171
  this._controller = controller;
168
172
 
173
+ const human = (
174
+ toolCallId: string,
175
+ payload: unknown,
176
+ executionId?: symbol,
177
+ ) => this._onHumanInput(toolCallId, payload, executionId);
169
178
  const transform = unstable_toolResultStream(
170
179
  () => this._getWrappedTools(),
171
180
  () => this._ac.signal,
172
- (toolCallId, payload) => this._onHumanInput(toolCallId, payload),
181
+ human,
173
182
  {
174
- onExecutionStart: (id) => this._onExecutionStart(id),
175
- onExecutionEnd: (id) => this._onExecutionEnd(id),
176
- },
183
+ onExecutionStart: (id: string, _name: string, executionId?: symbol) =>
184
+ this._onExecutionStart(id, executionId),
185
+ onExecutionEnd: (id: string, _name: string, executionId?: symbol) =>
186
+ this._onExecutionEnd(id, executionId),
187
+ } as ToolResultStreamOptions,
177
188
  );
178
189
 
179
190
  stream
@@ -281,10 +292,16 @@ export class ToolInvocationTracker {
281
292
  this._pendingRestore = true;
282
293
  this._entries.clear();
283
294
  this._lastSnapshot = null;
284
- // `_skipExecuteStreamIds` is intentionally not cleared — see field doc.
285
- void this.abort().finally(() => {
286
- this._executing.clear();
287
- });
295
+ void this.abort();
296
+ // Statuses are cleared synchronously: discarded executions may never
297
+ // settle (aborting hands the signal to the tool, it does not force
298
+ // settlement), and a late settlement of one sibling must not republish
299
+ // the others. `_deleteStatus` no-ops for cleared ids, so post-reset
300
+ // settlements stay silent.
301
+ if (this._statuses.size > 0) {
302
+ this._statuses = new Map();
303
+ this._invokeOnStatusesChange();
304
+ }
288
305
  } catch (err) {
289
306
  console.error("[ToolInvocationTracker] reset failed", err);
290
307
  }
@@ -312,8 +329,9 @@ export class ToolInvocationTracker {
312
329
  if (this._executing.size === 0) {
313
330
  return Promise.resolve();
314
331
  }
332
+ const executionIds = new Set(this._executing);
315
333
  return new Promise<void>((resolve) => {
316
- this._settledResolvers.push(resolve);
334
+ this._settledResolvers.push({ executionIds, resolve });
317
335
  });
318
336
  } catch (err) {
319
337
  console.error("[ToolInvocationTracker] abort failed", err);
@@ -360,34 +378,70 @@ export class ToolInvocationTracker {
360
378
  return Object.fromEntries(
361
379
  Object.entries(tools).map(([name, tool]) => {
362
380
  const execute = tool.execute;
363
- if (execute === undefined) return [name, tool];
381
+ const streamCall = tool.streamCall;
382
+ if (execute === undefined && streamCall === undefined)
383
+ return [name, tool];
364
384
 
365
385
  const wrappedTool = {
366
386
  ...tool,
367
- execute: (
368
- ...[args, context]: Parameters<NonNullable<typeof execute>>
369
- ) => {
370
- if (this._skipExecuteStreamIds.has(context.toolCallId)) {
371
- // Pre-resolved tool call: never invoke the host's execute.
372
- // Returning a never-settling Promise keeps the executor's
373
- // pending entry alive but enqueues nothing.
374
- return new Promise(() => {}) as never;
375
- }
376
- return execute(args, context);
377
- },
387
+ ...(execute !== undefined && {
388
+ execute: (...[args, context]: Parameters<typeof execute>) => {
389
+ const executionId = getToolExecutionId(context);
390
+ const entry = this._captureExecution(
391
+ context.toolCallId,
392
+ executionId,
393
+ );
394
+ if (!entry || entry.skipExecute) {
395
+ return new Promise(() => {}) as never;
396
+ }
397
+ return execute(args, context);
398
+ },
399
+ }),
400
+ ...(streamCall !== undefined && {
401
+ streamCall: (
402
+ ...[reader, context]: Parameters<typeof streamCall>
403
+ ) => {
404
+ const executionId = getToolExecutionId(context);
405
+ const entry = this._captureExecution(
406
+ context.toolCallId,
407
+ executionId,
408
+ );
409
+ if (!entry) return;
410
+ return streamCall(reader, context);
411
+ },
412
+ }),
378
413
  } as Tool;
379
414
  return [name, wrappedTool];
380
415
  }),
381
416
  ) as Record<string, Tool>;
382
417
  }
383
418
 
419
+ private _captureExecution(
420
+ toolCallId: string,
421
+ executionId: symbol | undefined,
422
+ ): ToolCallEntry | undefined {
423
+ if (executionId === undefined) return undefined;
424
+ const entry = this._entries.get(toolCallId);
425
+ if (!entry?.controller) return undefined;
426
+ if (entry.executionId === undefined) entry.executionId = executionId;
427
+ return entry.executionId === executionId ? entry : undefined;
428
+ }
429
+
384
430
  // ──────────────── internal: execution lifecycle callbacks ────────────────
385
431
 
386
432
  private _onHumanInput(
387
433
  toolCallId: string,
388
434
  payload: unknown,
435
+ executionId?: symbol,
389
436
  ): Promise<unknown> {
390
437
  return new Promise<unknown>((resolve, reject) => {
438
+ // A discarded execution must not resurrect a status entry or park an
439
+ // unanswerable request after its id has been reused.
440
+ const entry = this._entries.get(toolCallId);
441
+ if (!entry?.controller || entry.executionId !== executionId) {
442
+ reject(new Error("Tool execution aborted"));
443
+ return;
444
+ }
391
445
  const previous = this._humanInput.get(toolCallId);
392
446
  if (previous) {
393
447
  try {
@@ -398,7 +452,11 @@ export class ToolInvocationTracker {
398
452
  // host rejection handler threw; ignore and proceed
399
453
  }
400
454
  }
401
- this._humanInput.set(toolCallId, { resolve, reject });
455
+ this._humanInput.set(toolCallId, {
456
+ executionId: executionId!,
457
+ resolve,
458
+ reject,
459
+ });
402
460
  this._setStatus(toolCallId, {
403
461
  type: "interrupt",
404
462
  payload: { type: "human", payload },
@@ -406,28 +464,42 @@ export class ToolInvocationTracker {
406
464
  });
407
465
  }
408
466
 
409
- private _onExecutionStart(toolCallId: string): void {
410
- if (this._skipExecuteStreamIds.has(toolCallId)) return;
467
+ private _onExecutionStart(
468
+ toolCallId: string,
469
+ executionId: symbol | undefined,
470
+ ): void {
471
+ if (!this._captureExecution(toolCallId, executionId)) return;
472
+ const entry = this._entries.get(toolCallId)!;
473
+ if (entry.skipExecute) return;
411
474
 
412
- this._executing.add(toolCallId);
475
+ this._executing.add(executionId!);
413
476
  this._setStatus(toolCallId, { type: "executing" });
414
477
  }
415
478
 
416
- private _onExecutionEnd(toolCallId: string): void {
417
- if (!this._executing.delete(toolCallId)) return;
479
+ private _onExecutionEnd(
480
+ toolCallId: string,
481
+ executionId: symbol | undefined,
482
+ ): void {
483
+ if (executionId === undefined || !this._executing.delete(executionId))
484
+ return;
418
485
 
419
- this._deleteStatus(toolCallId);
486
+ const entry = this._entries.get(toolCallId);
487
+ if (entry?.executionId === executionId) this._deleteStatus(toolCallId);
420
488
 
421
- if (this._executing.size === 0) {
422
- const resolvers = this._settledResolvers.splice(0);
423
- resolvers.forEach((resolve) => {
424
- try {
425
- resolve();
426
- } catch {
427
- // ignore — settled-resolver consumer threw
428
- }
429
- });
430
- }
489
+ const pending: SettledResolver[] = [];
490
+ this._settledResolvers.forEach(({ executionIds, resolve }) => {
491
+ if ([...executionIds].some((id) => this._executing.has(id))) {
492
+ pending.push({ executionIds, resolve });
493
+ return;
494
+ }
495
+ try {
496
+ resolve();
497
+ } catch {
498
+ // ignore — settled-resolver consumer threw
499
+ }
500
+ });
501
+ this._settledResolvers.length = 0;
502
+ this._settledResolvers.push(...pending);
431
503
  }
432
504
 
433
505
  private _handleResultChunk(chunk: {
@@ -439,14 +511,10 @@ export class ToolInvocationTracker {
439
511
  meta: { toolCallId: string; toolName: string };
440
512
  }): void {
441
513
  const toolCallId = chunk.meta.toolCallId;
514
+ const executionId = getToolExecutionId(chunk);
442
515
  const entry = this._entries.get(toolCallId);
443
516
 
444
- // Pre-resolved tool call whose entry has been cleared by `reset()`.
445
- // The post-abort cancellation chunk lands here after the entry is
446
- // gone; suppress via the long-lived skip-execute marker.
447
- if (!entry && this._skipExecuteStreamIds.has(toolCallId)) {
448
- return;
449
- }
517
+ if (!entry || entry.executionId !== executionId) return;
450
518
 
451
519
  // The host already set the result (via the live snapshot's
452
520
  // `setResponse` path). Suppress the executor's redundant emit.
@@ -538,14 +606,12 @@ export class ToolInvocationTracker {
538
606
  toolName,
539
607
  toolCallId,
540
608
  });
541
- if (skipExecute) {
542
- this._skipExecuteStreamIds.add(toolCallId);
543
- }
544
609
  const entry: ToolCallEntry = {
545
610
  toolName,
546
611
  controller: toolCallController,
547
612
  argsText: "",
548
613
  hasResult: false,
614
+ skipExecute,
549
615
  argsComplete: false,
550
616
  };
551
617
  this._entries.set(toolCallId, entry);
@@ -1085,7 +1085,7 @@ const useExternalThread = ({
1085
1085
  }));
1086
1086
 
1087
1087
  return {
1088
- isEmpty: messages.length === 0,
1088
+ isEmpty: messages.length === 0 && !isLoading,
1089
1089
  isDisabled: false,
1090
1090
  isLoading,
1091
1091
  isRunning,
@@ -39,10 +39,12 @@ describe("ModelContext", () => {
39
39
  it("reflects modelName from a registered provider", async () => {
40
40
  const { sub, unmount } = render();
41
41
  try {
42
- sub.getValue().register(provider({ config: { modelName: "gpt-4" } }));
42
+ sub
43
+ .getValue()
44
+ .register(provider({ config: { modelName: "gpt-5.6-luna" } }));
43
45
  await tick();
44
46
 
45
- expect(sub.getValue().getState().modelName).toBe("gpt-4");
47
+ expect(sub.getValue().getState().modelName).toBe("gpt-5.6-luna");
46
48
  } finally {
47
49
  unmount();
48
50
  }
@@ -67,11 +69,15 @@ describe("ModelContext", () => {
67
69
  it("keeps the same state reference when an extra provider does not change the merged values", async () => {
68
70
  const { sub, unmount } = render();
69
71
  try {
70
- sub.getValue().register(provider({ config: { modelName: "gpt-4" } }));
72
+ sub
73
+ .getValue()
74
+ .register(provider({ config: { modelName: "gpt-5.6-luna" } }));
71
75
  await tick();
72
76
  const before = sub.getValue().getState();
73
77
 
74
- sub.getValue().register(provider({ config: { modelName: "gpt-4" } }));
78
+ sub
79
+ .getValue()
80
+ .register(provider({ config: { modelName: "gpt-5.6-luna" } }));
75
81
  await tick();
76
82
  const after = sub.getValue().getState();
77
83
 
@@ -86,9 +92,9 @@ describe("ModelContext", () => {
86
92
  try {
87
93
  const unsubscribe = sub
88
94
  .getValue()
89
- .register(provider({ config: { modelName: "gpt-4" } }));
95
+ .register(provider({ config: { modelName: "gpt-5.6-luna" } }));
90
96
  await tick();
91
- expect(sub.getValue().getState().modelName).toBe("gpt-4");
97
+ expect(sub.getValue().getState().modelName).toBe("gpt-5.6-luna");
92
98
 
93
99
  unsubscribe();
94
100
  await tick();
@@ -102,9 +108,11 @@ describe("ModelContext", () => {
102
108
  it("reflects modelName synchronously after register without awaiting", () => {
103
109
  const { sub, unmount } = render();
104
110
  try {
105
- sub.getValue().register(provider({ config: { modelName: "gpt-4" } }));
111
+ sub
112
+ .getValue()
113
+ .register(provider({ config: { modelName: "gpt-5.6-luna" } }));
106
114
 
107
- expect(sub.getValue().getState().modelName).toBe("gpt-4");
115
+ expect(sub.getValue().getState().modelName).toBe("gpt-5.6-luna");
108
116
  } finally {
109
117
  unmount();
110
118
  }
@@ -72,8 +72,8 @@ const useThreadSuggestions = (
72
72
  const state = useMemo<SuggestionsState>(
73
73
  () => ({
74
74
  suggestions: suggestions.map((s) => ({
75
- title: s.prompt,
76
- label: "",
75
+ title: s.title ?? s.prompt,
76
+ label: s.label ?? "",
77
77
  prompt: s.prompt,
78
78
  })),
79
79
  }),
@@ -0,0 +1,21 @@
1
+ import { useEffect, useRef } from "react";
2
+ import { useAssistantEmit } from "@assistant-ui/store/client";
3
+
4
+ /**
5
+ * Emits `threads.selectionChanged` whenever the main thread selection changes.
6
+ * Does not emit for the initially selected thread on mount. Every `threads`
7
+ * client whose selection can change calls this with its current main thread id.
8
+ */
9
+ export const useThreadSelectionEvents = (mainThreadId: string) => {
10
+ const emit = useAssistantEmit();
11
+ const previousMainThreadIdRef = useRef(mainThreadId);
12
+ useEffect(() => {
13
+ const previousThreadId = previousMainThreadIdRef.current;
14
+ if (previousThreadId === mainThreadId) return;
15
+ previousMainThreadIdRef.current = mainThreadId;
16
+ emit("threads.selectionChanged", {
17
+ threadId: mainThreadId,
18
+ previousThreadId,
19
+ });
20
+ }, [mainThreadId, emit]);
21
+ };
@@ -0,0 +1,11 @@
1
+ // Bundlers replace the process.env.NODE_ENV literal statically (Vite, webpack,
2
+ // Metro); the try covers hosts where no process binding exists at runtime.
3
+ export const isDevelopment = (() => {
4
+ try {
5
+ return (
6
+ process.env.NODE_ENV === "development" || process.env.NODE_ENV === "test"
7
+ );
8
+ } catch {
9
+ return false;
10
+ }
11
+ })();
@@ -5,6 +5,7 @@
5
5
  export type {
6
6
  ThreadsState,
7
7
  ThreadsMethods,
8
+ ThreadsEvents,
8
9
  ThreadsClientSchema,
9
10
  } from "./scopes/threads";
10
11
  export type {
@@ -79,7 +80,19 @@ export type {
79
80
  } from "./scopes/chain-of-thought";
80
81
 
81
82
  // runtime wiring
82
- export { RuntimeAdapter } from "../react/RuntimeAdapter";
83
+ export {
84
+ RuntimeAdapter,
85
+ runtimeAdapterTransformScopes,
86
+ } from "../react/RuntimeAdapter";
87
+ export {
88
+ InMemoryThreadList,
89
+ inMemoryThreadListTransformScopes,
90
+ type InMemoryThreadListProps,
91
+ } from "../react/client/InMemoryThreadList";
92
+ export {
93
+ RemoteThreadList,
94
+ type RemoteThreadListProps,
95
+ } from "../react/client/RemoteThreadList";
83
96
  export {
84
97
  useExternalMessageConverter,
85
98
  convertExternalMessages,
@@ -6,3 +6,16 @@ export { ThreadClient } from "./runtime-clients/thread-runtime-client";
6
6
  export { ThreadListItemClient } from "./runtime-clients/thread-list-item-runtime-client";
7
7
  export { ThreadListClient } from "./runtime-clients/thread-list-runtime-client";
8
8
  export { baseRuntimeAdapterTransformScopes } from "./clients/runtime-adapter";
9
+ export {
10
+ actionBarCopyDisabled,
11
+ actionBarEditDisabled,
12
+ actionBarReloadDisabled,
13
+ branchPickerNextDisabled,
14
+ branchPickerPreviousDisabled,
15
+ composerCancelDisabled,
16
+ composerInputDisabled,
17
+ composerSendDisabled,
18
+ suggestionTriggerDisabled,
19
+ } from "./primitive-predicates";
20
+ export { isDevelopment } from "./env";
21
+ export { useThreadSelectionEvents } from "./clients/thread-selection-events";
@@ -0,0 +1,184 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import {
3
+ actionBarCopyDisabled,
4
+ actionBarEditDisabled,
5
+ actionBarReloadDisabled,
6
+ branchPickerNextDisabled,
7
+ branchPickerPreviousDisabled,
8
+ composerCancelDisabled,
9
+ composerInputDisabled,
10
+ composerSendDisabled,
11
+ suggestionTriggerDisabled,
12
+ } from "./primitive-predicates";
13
+
14
+ const state = (partial: Record<string, unknown>) => partial as never;
15
+
16
+ describe("primitive predicates", () => {
17
+ it("composerSendDisabled requires canSend and either an idle thread or a queue", () => {
18
+ const composer = { canSend: true };
19
+ expect(
20
+ composerSendDisabled(
21
+ state({
22
+ composer,
23
+ thread: { isRunning: false, capabilities: { queue: false } },
24
+ }),
25
+ ),
26
+ ).toBe(false);
27
+ expect(
28
+ composerSendDisabled(
29
+ state({
30
+ composer,
31
+ thread: { isRunning: true, capabilities: { queue: true } },
32
+ }),
33
+ ),
34
+ ).toBe(false);
35
+ expect(
36
+ composerSendDisabled(
37
+ state({
38
+ composer,
39
+ thread: { isRunning: true, capabilities: { queue: false } },
40
+ }),
41
+ ),
42
+ ).toBe(true);
43
+ expect(
44
+ composerSendDisabled(
45
+ state({
46
+ composer: { canSend: false },
47
+ thread: { isRunning: false, capabilities: { queue: false } },
48
+ }),
49
+ ),
50
+ ).toBe(true);
51
+ });
52
+
53
+ it("actionBarReloadDisabled rejects user messages and busy threads", () => {
54
+ const thread = { isRunning: false, isDisabled: false };
55
+ expect(
56
+ actionBarReloadDisabled(
57
+ state({ thread, message: { role: "assistant" } }),
58
+ ),
59
+ ).toBe(false);
60
+ expect(
61
+ actionBarReloadDisabled(state({ thread, message: { role: "user" } })),
62
+ ).toBe(true);
63
+ expect(
64
+ actionBarReloadDisabled(
65
+ state({
66
+ thread: { ...thread, isRunning: true },
67
+ message: { role: "assistant" },
68
+ }),
69
+ ),
70
+ ).toBe(true);
71
+ });
72
+
73
+ it("actionBarCopyDisabled requires settled content with non-empty text", () => {
74
+ expect(
75
+ actionBarCopyDisabled(
76
+ state({
77
+ message: {
78
+ role: "assistant",
79
+ status: { type: "complete" },
80
+ parts: [{ type: "text", text: "hi" }],
81
+ },
82
+ }),
83
+ ),
84
+ ).toBe(false);
85
+ expect(
86
+ actionBarCopyDisabled(
87
+ state({
88
+ message: {
89
+ role: "assistant",
90
+ status: { type: "running" },
91
+ parts: [{ type: "text", text: "hi" }],
92
+ },
93
+ }),
94
+ ),
95
+ ).toBe(true);
96
+ expect(
97
+ actionBarCopyDisabled(
98
+ state({
99
+ message: {
100
+ role: "user",
101
+ status: undefined,
102
+ parts: [{ type: "text", text: "" }],
103
+ },
104
+ }),
105
+ ),
106
+ ).toBe(true);
107
+ });
108
+
109
+ it("branch picker predicates respect bounds and run capabilities", () => {
110
+ const thread = {
111
+ isRunning: false,
112
+ capabilities: { switchBranchDuringRun: false },
113
+ };
114
+ const message = { branchNumber: 2, branchCount: 3 };
115
+ expect(branchPickerPreviousDisabled(state({ thread, message }))).toBe(
116
+ false,
117
+ );
118
+ expect(branchPickerNextDisabled(state({ thread, message }))).toBe(false);
119
+ expect(
120
+ branchPickerPreviousDisabled(
121
+ state({ thread, message: { ...message, branchNumber: 1 } }),
122
+ ),
123
+ ).toBe(true);
124
+ expect(
125
+ branchPickerNextDisabled(
126
+ state({ thread, message: { ...message, branchNumber: 3 } }),
127
+ ),
128
+ ).toBe(true);
129
+ expect(
130
+ branchPickerNextDisabled(
131
+ state({ thread: { ...thread, isRunning: true }, message }),
132
+ ),
133
+ ).toBe(true);
134
+ });
135
+
136
+ it("suggestionTriggerDisabled gates on send only for queueless runs", () => {
137
+ const thread = {
138
+ isDisabled: false,
139
+ isRunning: true,
140
+ capabilities: { queue: false },
141
+ };
142
+ expect(suggestionTriggerDisabled(state({ thread }), false)).toBe(false);
143
+ expect(suggestionTriggerDisabled(state({ thread }), true)).toBe(true);
144
+ expect(
145
+ suggestionTriggerDisabled(
146
+ state({ thread: { ...thread, capabilities: { queue: true } } }),
147
+ true,
148
+ ),
149
+ ).toBe(false);
150
+ });
151
+ it("composerCancelDisabled, composerInputDisabled, and actionBarEditDisabled mirror their fields", () => {
152
+ expect(
153
+ composerCancelDisabled(state({ composer: { canCancel: true } })),
154
+ ).toBe(false);
155
+ expect(
156
+ composerCancelDisabled(state({ composer: { canCancel: false } })),
157
+ ).toBe(true);
158
+
159
+ const enabledThread = { isDisabled: false };
160
+ expect(
161
+ composerInputDisabled(state({ thread: enabledThread, composer: {} })),
162
+ ).toBe(false);
163
+ expect(
164
+ composerInputDisabled(
165
+ state({
166
+ thread: enabledThread,
167
+ composer: { dictation: { inputDisabled: true } },
168
+ }),
169
+ ),
170
+ ).toBe(true);
171
+ expect(
172
+ composerInputDisabled(
173
+ state({ thread: { isDisabled: true }, composer: {} }),
174
+ ),
175
+ ).toBe(true);
176
+
177
+ expect(
178
+ actionBarEditDisabled(state({ composer: { isEditing: false } })),
179
+ ).toBe(false);
180
+ expect(
181
+ actionBarEditDisabled(state({ composer: { isEditing: true } })),
182
+ ).toBe(true);
183
+ });
184
+ });