@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
@@ -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
+ });
@@ -0,0 +1,43 @@
1
+ import type { AssistantState } from "@assistant-ui/store";
2
+
3
+ /**
4
+ * Disabled predicates shared by every binding's primitive layer. Each binding
5
+ * consumes these as state selectors so the disabled semantics of a primitive
6
+ * cannot drift between frameworks.
7
+ */
8
+
9
+ export const composerSendDisabled = (s: AssistantState): boolean =>
10
+ !s.composer.canSend || (s.thread.isRunning && !s.thread.capabilities.queue);
11
+
12
+ export const composerCancelDisabled = (s: AssistantState): boolean =>
13
+ !s.composer.canCancel;
14
+
15
+ export const composerInputDisabled = (s: AssistantState): boolean =>
16
+ s.thread.isDisabled || s.composer.dictation?.inputDisabled === true;
17
+
18
+ export const actionBarEditDisabled = (s: AssistantState): boolean =>
19
+ s.composer.isEditing;
20
+
21
+ export const actionBarReloadDisabled = (s: AssistantState): boolean =>
22
+ s.thread.isRunning || s.thread.isDisabled || s.message.role !== "assistant";
23
+
24
+ export const actionBarCopyDisabled = (s: AssistantState): boolean =>
25
+ !(
26
+ (s.message.role !== "assistant" || s.message.status?.type !== "running") &&
27
+ s.message.parts.some((part) => part.type === "text" && part.text.length > 0)
28
+ );
29
+
30
+ export const branchPickerPreviousDisabled = (s: AssistantState): boolean =>
31
+ s.message.branchNumber <= 1 ||
32
+ (s.thread.isRunning && !s.thread.capabilities.switchBranchDuringRun);
33
+
34
+ export const branchPickerNextDisabled = (s: AssistantState): boolean =>
35
+ s.message.branchNumber >= s.message.branchCount ||
36
+ (s.thread.isRunning && !s.thread.capabilities.switchBranchDuringRun);
37
+
38
+ export const suggestionTriggerDisabled = (
39
+ s: AssistantState,
40
+ send: boolean,
41
+ ): boolean =>
42
+ s.thread.isDisabled ||
43
+ (send && s.thread.isRunning && !s.thread.capabilities.queue);
@@ -0,0 +1,41 @@
1
+ import { createTapRoot, useResource } from "@assistant-ui/tap";
2
+ import { afterEach, describe, expect, it, vi } from "vitest";
3
+ import type { AttachmentRuntime } from "../../runtime/api/attachment-runtime";
4
+ import { AttachmentRuntimeClient } from "./attachment-runtime-client";
5
+
6
+ describe("AttachmentRuntimeClient", () => {
7
+ afterEach(() => {
8
+ vi.restoreAllMocks();
9
+ });
10
+
11
+ it("reports attachment removal failures", async () => {
12
+ const error = new Error("storage unavailable");
13
+ const consoleError = vi
14
+ .spyOn(console, "error")
15
+ .mockImplementation(() => {});
16
+ const state = {
17
+ id: "attachment-1",
18
+ type: "file",
19
+ name: "notes.txt",
20
+ status: { type: "complete" },
21
+ content: [],
22
+ source: "thread-composer",
23
+ };
24
+ const runtime = {
25
+ getState: () => state,
26
+ subscribe: () => () => {},
27
+ remove: () => Promise.reject(error),
28
+ } as unknown as AttachmentRuntime;
29
+ const root = createTapRoot(function AttachmentClientRoot() {
30
+ return useResource(AttachmentRuntimeClient({ runtime }));
31
+ });
32
+
33
+ await expect(root.getValue().remove()).rejects.toBe(error);
34
+
35
+ expect(consoleError).toHaveBeenCalledWith(
36
+ "[assistant-ui] attachment remove failed:",
37
+ error,
38
+ );
39
+ root.unmount();
40
+ });
41
+ });
@@ -1,6 +1,7 @@
1
1
  import { resource } from "@assistant-ui/tap";
2
2
  import type { ClientOutput } from "@assistant-ui/store";
3
3
  import type { AttachmentRuntime } from "../../runtime/api/attachment-runtime";
4
+ import { handleRuntimeAction } from "./handle-runtime-action";
4
5
  import { useSubscribable } from "./useSubscribable";
5
6
 
6
7
  const useAttachmentRuntimeClient = ({
@@ -12,7 +13,7 @@ const useAttachmentRuntimeClient = ({
12
13
 
13
14
  return {
14
15
  getState: () => state,
15
- remove: runtime.remove,
16
+ remove: () => handleRuntimeAction("attachment remove", runtime.remove),
16
17
  __internal_getRuntime: () => runtime,
17
18
  };
18
19
  };
@@ -0,0 +1,11 @@
1
+ export const handleRuntimeAction = (
2
+ label: string,
3
+ execute: () => Promise<void>,
4
+ ): Promise<void> => {
5
+ const task = execute();
6
+
7
+ void task.catch((error: unknown) => {
8
+ console.error(`[assistant-ui] ${label} failed:`, error);
9
+ });
10
+ return task;
11
+ };
@@ -0,0 +1,69 @@
1
+ import { afterEach, describe, expect, it, vi } from "vitest";
2
+ import { handleThreadListAction } from "./handle-thread-list-action";
3
+
4
+ describe("handleThreadListAction", () => {
5
+ afterEach(() => {
6
+ vi.restoreAllMocks();
7
+ });
8
+
9
+ it("reports a rejected task", async () => {
10
+ const error = new Error("unavailable");
11
+ const task = Promise.reject(error);
12
+ const consoleError = vi
13
+ .spyOn(console, "error")
14
+ .mockImplementation(() => {});
15
+
16
+ const result = handleThreadListAction("delete", () => task);
17
+
18
+ expect(result).toBe(task);
19
+ await expect(result).rejects.toBe(error);
20
+ expect(consoleError).toHaveBeenCalledWith(
21
+ "[assistant-ui] thread list delete failed:",
22
+ error,
23
+ );
24
+ });
25
+
26
+ it("preserves synchronous failures", () => {
27
+ const error = new Error("invalid thread");
28
+ const consoleError = vi
29
+ .spyOn(console, "error")
30
+ .mockImplementation(() => {});
31
+
32
+ expect(() =>
33
+ handleThreadListAction("switch", () => {
34
+ throw error;
35
+ }),
36
+ ).toThrow(error);
37
+ expect(consoleError).not.toHaveBeenCalled();
38
+ });
39
+
40
+ it("does not leak an ignored action as an unhandled rejection", async () => {
41
+ const error = new Error("delete failed");
42
+ const consoleError = vi
43
+ .spyOn(console, "error")
44
+ .mockImplementation(() => {});
45
+ const rejections: unknown[] = [];
46
+ const onUnhandledRejection = (reason: unknown) => {
47
+ rejections.push(reason);
48
+ };
49
+ const priorListeners = process.listeners("unhandledRejection");
50
+ process.removeAllListeners("unhandledRejection");
51
+ process.on("unhandledRejection", onUnhandledRejection);
52
+
53
+ try {
54
+ handleThreadListAction("delete", () => Promise.reject(error));
55
+ await new Promise((resolve) => setTimeout(resolve, 20));
56
+ } finally {
57
+ process.removeListener("unhandledRejection", onUnhandledRejection);
58
+ for (const listener of priorListeners) {
59
+ process.on("unhandledRejection", listener);
60
+ }
61
+ }
62
+
63
+ expect(rejections).toEqual([]);
64
+ expect(consoleError).toHaveBeenCalledWith(
65
+ "[assistant-ui] thread list delete failed:",
66
+ error,
67
+ );
68
+ });
69
+ });
@@ -0,0 +1,6 @@
1
+ import { handleRuntimeAction } from "./handle-runtime-action";
2
+
3
+ export const handleThreadListAction = (
4
+ action: string,
5
+ execute: () => Promise<void>,
6
+ ): Promise<void> => handleRuntimeAction(`thread list ${action}`, execute);
@@ -4,6 +4,7 @@ import type { ClientOutput } from "@assistant-ui/store";
4
4
  import { useAssistantEmit } from "@assistant-ui/store/client";
5
5
  import type { ThreadListItemRuntime } from "../../runtime/api/thread-list-item-runtime";
6
6
  import { useSubscribable } from "./useSubscribable";
7
+ import { handleThreadListAction } from "./handle-thread-list-action";
7
8
 
8
9
  const useThreadListItemClient = ({
9
10
  runtime,
@@ -39,13 +40,20 @@ const useThreadListItemClient = ({
39
40
 
40
41
  return {
41
42
  getState: () => state,
42
- switchTo: runtime.switchTo,
43
- rename: runtime.rename,
44
- updateCustom: runtime.updateCustom,
45
- archive: runtime.archive,
46
- unarchive: runtime.unarchive,
47
- delete: runtime.delete,
48
- generateTitle: runtime.generateTitle,
43
+ switchTo: (options) =>
44
+ handleThreadListAction("switch", () => runtime.switchTo(options)),
45
+ rename: (newTitle) =>
46
+ handleThreadListAction("rename", () => runtime.rename(newTitle)),
47
+ updateCustom: (custom) =>
48
+ handleThreadListAction("update custom metadata", () =>
49
+ runtime.updateCustom(custom),
50
+ ),
51
+ archive: () => handleThreadListAction("archive", () => runtime.archive()),
52
+ unarchive: () =>
53
+ handleThreadListAction("unarchive", () => runtime.unarchive()),
54
+ delete: () => handleThreadListAction("delete", () => runtime.delete()),
55
+ generateTitle: () =>
56
+ handleThreadListAction("generate title", () => runtime.generateTitle()),
49
57
  initialize: runtime.initialize,
50
58
  detach: runtime.detach,
51
59
  __internal_getRuntime: () => runtime,
@@ -2,12 +2,14 @@ import { useMemo } from "react";
2
2
  import { useResource, withKey, resource } from "@assistant-ui/tap";
3
3
  import type { ClientOutput } from "@assistant-ui/store";
4
4
  import { useClientLookup, useClientResource } from "@assistant-ui/store/client";
5
+ import { useThreadSelectionEvents } from "../clients/thread-selection-events";
5
6
  import type { ThreadListRuntime } from "../../runtime/api/thread-list-runtime";
6
7
  import type { AssistantRuntime } from "../../runtime/api/assistant-runtime";
7
8
  import { useSubscribable } from "./useSubscribable";
8
9
  import { ThreadListItemClient } from "./thread-list-item-runtime-client";
9
10
  import { ThreadClient } from "./thread-runtime-client";
10
11
  import type { ThreadsState } from "../scopes/threads";
12
+ import { handleThreadListAction } from "./handle-thread-list-action";
11
13
 
12
14
  const useThreadListItemClientById = ({
13
15
  runtime,
@@ -40,6 +42,7 @@ const useThreadListClient = ({
40
42
  __internal_assistantRuntime: AssistantRuntime;
41
43
  }): ClientOutput<"threads"> => {
42
44
  const runtimeState = useSubscribable(runtime);
45
+ useThreadSelectionEvents(runtimeState.mainThreadId);
43
46
 
44
47
  const main = useClientResource(
45
48
  ThreadClient({
@@ -93,12 +96,12 @@ const useThreadListClient = ({
93
96
  : state.threadIds[index]!;
94
97
  return threadItems.get({ key: id });
95
98
  },
96
- switchToThread: async (threadId, options) => {
97
- await runtime.switchToThread(threadId, options);
98
- },
99
- switchToNewThread: async () => {
100
- await runtime.switchToNewThread();
101
- },
99
+ switchToThread: (threadId, options) =>
100
+ handleThreadListAction("switch", () =>
101
+ runtime.switchToThread(threadId, options),
102
+ ),
103
+ switchToNewThread: () =>
104
+ handleThreadListAction("create", () => runtime.switchToNewThread()),
102
105
  getLoadThreadsPromise: () => runtime.getLoadThreadsPromise(),
103
106
  reload: () => runtime.reload(),
104
107
  reloadMainThread: () => runtime.reloadMainThread(),
@@ -27,6 +27,11 @@ export type ComposerState = {
27
27
  readonly attachments: readonly Attachment[];
28
28
  readonly runConfig: RunConfig;
29
29
  readonly isEditing: boolean;
30
+ /**
31
+ * Whether the composer can cancel the current run. `true` when the runtime
32
+ * supports cancel and a run is in flight, not merely when cancel is a
33
+ * capability.
34
+ */
30
35
  readonly canCancel: boolean;
31
36
  /**
32
37
  * Whether the composer is currently willing to send. `true` when the
@@ -104,13 +109,13 @@ export type ComposerMeta = {
104
109
 
105
110
  export type ComposerEvents = {
106
111
  /**
107
- * @deprecated State-derivable. Observe composer `text` clearing via
108
- * `useAuiState` instead. Kept for backward compatibility.
112
+ * The user sent the composer contents. `messageId` is set when the send
113
+ * came from an edit composer.
109
114
  */
110
115
  "composer.send": { threadId: string; messageId?: string };
111
116
  /**
112
- * @deprecated State-derivable. Observe composer `attachments` via
113
- * `useAuiState` instead. Kept for backward compatibility.
117
+ * An attachment was added to the composer. `messageId` is set when the
118
+ * attachment was added to an edit composer.
114
119
  */
115
120
  "composer.attachmentAdd": { threadId: string; messageId?: string };
116
121
  "composer.attachmentAddError": {
@@ -42,15 +42,16 @@ export type ThreadListItemMeta = {
42
42
 
43
43
  export type ThreadListItemEvents = {
44
44
  /**
45
- * @deprecated State-derivable. Compare `s.threads.mainThreadId` against the
46
- * item's `s.threadListItem.id` via `useAuiState` instead. Kept for backward
47
- * compatibility.
45
+ * @deprecated Use `threads.selectionChanged` instead; its `threadId` is the
46
+ * newly selected thread. Inside a per-item `threadListItem` scope, filter by
47
+ * `threadId === threadListItem.id` to reproduce the per-item delivery. Kept
48
+ * for backward compatibility.
48
49
  */
49
50
  "threadListItem.switchedTo": { threadId: string };
50
51
  /**
51
- * @deprecated State-derivable. Compare `s.threads.mainThreadId` against the
52
- * item's `s.threadListItem.id` via `useAuiState` instead. Kept for backward
53
- * compatibility.
52
+ * @deprecated Use `threads.selectionChanged` instead; its
53
+ * `previousThreadId` is the thread that was switched away from. Kept for
54
+ * backward compatibility.
54
55
  */
55
56
  "threadListItem.switchedAway": { threadId: string };
56
57
  };
@@ -145,19 +145,20 @@ export type ThreadMeta = {
145
145
 
146
146
  export type ThreadEvents = {
147
147
  /**
148
- * @deprecated State-derivable. Observe `isRunning` flipping to `true` via
149
- * `useAuiState` instead. Kept for backward compatibility.
148
+ * A run started on this thread. Also observable as `isRunning` flipping to
149
+ * `true` in thread state.
150
150
  */
151
151
  "thread.runStart": { threadId: string };
152
152
  /**
153
- * @deprecated State-derivable. Observe `isRunning` flipping to `false` via
154
- * `useAuiState` instead. Kept for backward compatibility.
153
+ * A run on this thread ended, whether it completed, errored, or was
154
+ * cancelled. Also observable as `isRunning` flipping to `false` in thread
155
+ * state.
155
156
  */
156
157
  "thread.runEnd": { threadId: string };
157
158
  /**
158
- * @deprecated State-derivable. This event fires before the first message is
159
- * added; observe `messages` becoming non-empty via `useAuiState` instead of
160
- * reading state inside this event handler. Kept for backward compatibility.
159
+ * The thread transitioned from new to initialized. Fires before the first
160
+ * message is added, so read thread state via `useAuiState` rather than
161
+ * inside this event handler.
161
162
  */
162
163
  "thread.initialize": { threadId: string };
163
164
  /**
@@ -35,6 +35,20 @@ export type ThreadsMethods = {
35
35
  __internal_getAssistantRuntime?(): AssistantRuntime;
36
36
  };
37
37
 
38
+ export type ThreadsEvents = {
39
+ /**
40
+ * The main thread selection changed. Fires once per switch with the newly
41
+ * selected thread and the thread that was selected before. Does not fire
42
+ * for the initially selected thread on mount. Runtimes that resolve a
43
+ * deep-linked `threadId`/`initialThreadId` after mount (such as
44
+ * `useRemoteThreadListRuntime`) start on a placeholder new thread, so the
45
+ * deep link's resolution fires this event with the placeholder as
46
+ * `previousThreadId`.
47
+ */
48
+ "threads.selectionChanged": { threadId: string; previousThreadId: string };
49
+ };
50
+
38
51
  export type ThreadsClientSchema = {
39
52
  methods: ThreadsMethods;
53
+ events: ThreadsEvents;
40
54
  };