@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
@@ -5,6 +5,7 @@ import {
5
5
  type ClientOutput,
6
6
  attachTransformScopes,
7
7
  } from "@assistant-ui/store";
8
+ import { useAssistantScopeEffect } from "@assistant-ui/store/client";
8
9
  import type {
9
10
  InteractablesState,
10
11
  InteractableRegistration,
@@ -15,6 +16,7 @@ import type {
15
16
  import { toJSONSchema, toPartialJSONSchema } from "assistant-stream";
16
17
  import { ModelContext } from "../../store";
17
18
  import { buildInteractableModelContext } from "./interactable-model-context";
19
+ import { notifySubscribers as notifyStateSubscribers } from "../../subscribable/subscribable";
18
20
 
19
21
  const PERSISTENCE_DEBOUNCE_MS = 500;
20
22
 
@@ -27,9 +29,15 @@ const useInteractables = (): ClientOutput<"interactables"> => {
27
29
  const clientRef = useAssistantClientRef();
28
30
 
29
31
  const stateRef = useRef(state);
30
- useEffect(() => {
31
- stateRef.current = state;
32
- }, [state]);
32
+
33
+ const setStateAndRef = useCallback(
34
+ (updater: (prev: InteractablesState) => InteractablesState) => {
35
+ const next = updater(stateRef.current);
36
+ stateRef.current = next;
37
+ setState(next);
38
+ },
39
+ [],
40
+ );
33
41
 
34
42
  const subscribersRef = useRef(new Set<() => void>());
35
43
  const partialSchemaCacheRef = useRef(
@@ -44,75 +52,142 @@ const useInteractables = (): ClientOutput<"interactables"> => {
44
52
  undefined,
45
53
  );
46
54
  const syncSeqRef = useRef(0);
47
- const hasPendingLocalChangeRef = useRef(false);
55
+ const latestSyncSeqByIdRef = useRef(new Map<string, number>());
56
+ const inFlightPersistenceRef = useRef(0);
48
57
  const flushResolversRef = useRef<Array<() => void>>([]);
49
58
  const dirtyIdsRef = useRef(new Set<string>());
50
59
 
51
- const runPersistence = useCallback(async () => {
52
- const adapter = adapterRef.current;
53
- if (!adapter) {
54
- for (const resolve of flushResolversRef.current) resolve();
55
- flushResolversRef.current = [];
56
- return;
57
- }
60
+ type PersistenceBatch = {
61
+ adapter: InteractablePersistenceAdapter;
62
+ payload: InteractablePersistedState;
63
+ dirtyIds: Set<string>;
64
+ seq: number;
65
+ };
58
66
 
59
- const seq = ++syncSeqRef.current;
60
- const dirtyIds = new Set(dirtyIdsRef.current);
61
- dirtyIdsRef.current.clear();
62
- hasPendingLocalChangeRef.current = true;
67
+ const outgoingQueueRef = useRef<PersistenceBatch[]>([]);
68
+ const runPersistenceRef = useRef<(batch?: PersistenceBatch) => void>(
69
+ () => {},
70
+ );
63
71
 
64
- // Snapshot before any await so unregistered definitions are still included.
65
- const exported = stateRef.current.definitions;
66
- const payload: InteractablePersistedState = {};
67
- for (const [id, def] of Object.entries(exported)) {
68
- payload[id] = { name: def.name, state: def.state };
72
+ const exportState = useCallback((): InteractablePersistedState => {
73
+ const result: InteractablePersistedState = {};
74
+ for (const [id, def] of Object.entries(stateRef.current.definitions)) {
75
+ result[id] = { name: def.name, state: def.state };
69
76
  }
77
+ return result;
78
+ }, []);
70
79
 
71
- setState((prev) => ({
72
- ...prev,
73
- persistence: {
74
- ...prev.persistence,
75
- ...Object.fromEntries(
76
- [...dirtyIds].map((id) => [
77
- id,
78
- { isPending: true, error: undefined },
79
- ]),
80
- ),
81
- },
82
- }));
80
+ const takeDirtyBatch = useCallback(
81
+ (adapter: InteractablePersistenceAdapter): PersistenceBatch | undefined => {
82
+ if (dirtyIdsRef.current.size === 0) return;
83
+ const dirtyIds = new Set(dirtyIdsRef.current);
84
+ dirtyIdsRef.current.clear();
85
+ const seq = ++syncSeqRef.current;
86
+ for (const id of dirtyIds) latestSyncSeqByIdRef.current.set(id, seq);
87
+ return { adapter, payload: exportState(), dirtyIds, seq };
88
+ },
89
+ [exportState],
90
+ );
83
91
 
84
- try {
85
- await adapter.save(payload);
86
- if (syncSeqRef.current === seq) {
87
- hasPendingLocalChangeRef.current = false;
88
- setState((prev) => {
89
- const persistence = { ...prev.persistence };
90
- for (const id of dirtyIds) delete persistence[id];
91
- return { ...prev, persistence };
92
- });
92
+ const enqueuePersistence = useCallback(
93
+ (adapter: InteractablePersistenceAdapter) => {
94
+ const batch = takeDirtyBatch(adapter);
95
+ if (!batch) return;
96
+ if (inFlightPersistenceRef.current === 0) {
97
+ runPersistenceRef.current(batch);
98
+ } else {
99
+ outgoingQueueRef.current.push(batch);
93
100
  }
94
- } catch (e) {
95
- if (syncSeqRef.current === seq) {
96
- hasPendingLocalChangeRef.current = false;
97
- setState((prev) => ({
98
- ...prev,
99
- persistence: {
100
- ...prev.persistence,
101
- ...Object.fromEntries(
102
- [...dirtyIds].map((id) => [id, { isPending: false, error: e }]),
103
- ),
104
- },
105
- }));
101
+ },
102
+ [takeDirtyBatch],
103
+ );
104
+
105
+ const runPersistence = useCallback(
106
+ async (batch?: PersistenceBatch) => {
107
+ const resolved =
108
+ batch ??
109
+ (adapterRef.current ? takeDirtyBatch(adapterRef.current) : undefined);
110
+ if (!resolved) {
111
+ if (inFlightPersistenceRef.current === 0) {
112
+ for (const resolve of flushResolversRef.current) resolve();
113
+ flushResolversRef.current = [];
114
+ }
115
+ return;
106
116
  }
107
- } finally {
108
- if (dirtyIdsRef.current.size > 0 && adapterRef.current) {
109
- runPersistence();
110
- } else {
111
- for (const resolve of flushResolversRef.current) resolve();
112
- flushResolversRef.current = [];
117
+
118
+ const { adapter, payload, dirtyIds, seq } = resolved;
119
+ inFlightPersistenceRef.current += 1;
120
+
121
+ setStateAndRef((prev) => ({
122
+ ...prev,
123
+ persistence: {
124
+ ...prev.persistence,
125
+ ...Object.fromEntries(
126
+ [...dirtyIds].map((id) => [
127
+ id,
128
+ { isPending: true, error: undefined },
129
+ ]),
130
+ ),
131
+ },
132
+ }));
133
+
134
+ try {
135
+ await adapter.save(payload);
136
+ setStateAndRef((prev) => {
137
+ let changed = false;
138
+ const persistence = { ...prev.persistence };
139
+ for (const id of dirtyIds) {
140
+ if (
141
+ latestSyncSeqByIdRef.current.get(id) !== seq ||
142
+ dirtyIdsRef.current.has(id)
143
+ )
144
+ continue;
145
+ latestSyncSeqByIdRef.current.delete(id);
146
+ delete persistence[id];
147
+ changed = true;
148
+ }
149
+ return changed ? { ...prev, persistence } : prev;
150
+ });
151
+ } catch (e) {
152
+ setStateAndRef((prev) => {
153
+ let changed = false;
154
+ const persistence = { ...prev.persistence };
155
+ for (const id of dirtyIds) {
156
+ if (
157
+ latestSyncSeqByIdRef.current.get(id) !== seq ||
158
+ dirtyIdsRef.current.has(id)
159
+ )
160
+ continue;
161
+ latestSyncSeqByIdRef.current.delete(id);
162
+ persistence[id] = { isPending: false, error: e };
163
+ changed = true;
164
+ }
165
+ return changed ? { ...prev, persistence } : prev;
166
+ });
167
+ } finally {
168
+ inFlightPersistenceRef.current -= 1;
169
+ const next =
170
+ outgoingQueueRef.current.shift() ??
171
+ (adapterRef.current && dirtyIdsRef.current.size > 0
172
+ ? takeDirtyBatch(adapterRef.current)
173
+ : undefined);
174
+ if (next) {
175
+ if (debounceTimerRef.current !== undefined) {
176
+ clearTimeout(debounceTimerRef.current);
177
+ debounceTimerRef.current = undefined;
178
+ }
179
+ runPersistenceRef.current(next);
180
+ } else if (inFlightPersistenceRef.current === 0) {
181
+ for (const resolve of flushResolversRef.current) resolve();
182
+ flushResolversRef.current = [];
183
+ }
113
184
  }
114
- }
115
- }, []);
185
+ },
186
+ [setStateAndRef, takeDirtyBatch],
187
+ );
188
+ runPersistenceRef.current = (nextBatch) => {
189
+ void runPersistence(nextBatch);
190
+ };
116
191
 
117
192
  const schedulePersistence = useCallback(
118
193
  (id: string) => {
@@ -123,79 +198,75 @@ const useInteractables = (): ClientOutput<"interactables"> => {
123
198
  }
124
199
  debounceTimerRef.current = setTimeout(() => {
125
200
  debounceTimerRef.current = undefined;
126
- if (!hasPendingLocalChangeRef.current) {
127
- runPersistence();
201
+ if (inFlightPersistenceRef.current === 0 && adapterRef.current) {
202
+ enqueuePersistence(adapterRef.current);
128
203
  } else {
129
204
  debounceTimerRef.current = setTimeout(() => {
130
205
  debounceTimerRef.current = undefined;
131
- runPersistence();
206
+ if (adapterRef.current) enqueuePersistence(adapterRef.current);
132
207
  }, PERSISTENCE_DEBOUNCE_MS);
133
208
  }
134
209
  }, PERSISTENCE_DEBOUNCE_MS);
135
210
  },
136
- [runPersistence],
211
+ [enqueuePersistence],
137
212
  );
138
213
 
139
- const exportState = useCallback((): InteractablePersistedState => {
140
- const result: InteractablePersistedState = {};
141
- for (const [id, def] of Object.entries(stateRef.current.definitions)) {
142
- result[id] = { name: def.name, state: def.state };
143
- }
144
- return result;
145
- }, []);
146
-
147
- const importState = useCallback((saved: InteractablePersistedState) => {
148
- for (const [id, entry] of Object.entries(saved)) {
149
- detachedStateRef.current.set(id, entry.state);
150
- }
151
- setState((prev) => {
152
- let changed = false;
153
- const definitions = { ...prev.definitions };
214
+ const importState = useCallback(
215
+ (saved: InteractablePersistedState) => {
154
216
  for (const [id, entry] of Object.entries(saved)) {
155
- if (definitions[id]) {
156
- definitions[id] = { ...definitions[id], state: entry.state };
157
- changed = true;
158
- }
217
+ detachedStateRef.current.set(id, entry.state);
159
218
  }
160
- return changed ? { ...prev, definitions } : prev;
161
- });
162
- }, []);
163
-
164
- const setPersistenceAdapter = useCallback(
165
- (adapter: InteractablePersistenceAdapter | undefined) => {
166
- adapterRef.current = adapter;
219
+ setStateAndRef((prev) => {
220
+ let changed = false;
221
+ const definitions = { ...prev.definitions };
222
+ for (const [id, entry] of Object.entries(saved)) {
223
+ if (definitions[id]) {
224
+ definitions[id] = { ...definitions[id], state: entry.state };
225
+ changed = true;
226
+ }
227
+ }
228
+ return changed ? { ...prev, definitions } : prev;
229
+ });
167
230
  },
168
- [],
231
+ [setStateAndRef],
169
232
  );
170
233
 
234
+ const flushIfPending = useCallback(() => {
235
+ if (debounceTimerRef.current !== undefined) {
236
+ clearTimeout(debounceTimerRef.current);
237
+ debounceTimerRef.current = undefined;
238
+ }
239
+ if (adapterRef.current) enqueuePersistence(adapterRef.current);
240
+ }, [enqueuePersistence]);
241
+
171
242
  const flush = useCallback(async () => {
172
243
  if (debounceTimerRef.current !== undefined) {
173
244
  clearTimeout(debounceTimerRef.current);
174
245
  debounceTimerRef.current = undefined;
175
246
  }
176
- if (!adapterRef.current) return;
177
- if (!hasPendingLocalChangeRef.current && dirtyIdsRef.current.size === 0)
178
- return;
247
+ const hasWork =
248
+ inFlightPersistenceRef.current > 0 ||
249
+ dirtyIdsRef.current.size > 0 ||
250
+ outgoingQueueRef.current.length > 0;
251
+ if (!hasWork) return;
179
252
  const p = new Promise<void>((resolve) => {
180
253
  flushResolversRef.current.push(resolve);
181
254
  });
182
- if (!hasPendingLocalChangeRef.current) {
183
- runPersistence();
184
- }
255
+ if (adapterRef.current) enqueuePersistence(adapterRef.current);
185
256
  return p;
186
- }, [runPersistence]);
257
+ }, [enqueuePersistence]);
187
258
 
188
- const flushIfPending = useCallback(() => {
189
- if (adapterRef.current && debounceTimerRef.current !== undefined) {
190
- clearTimeout(debounceTimerRef.current);
191
- debounceTimerRef.current = undefined;
192
- runPersistence();
193
- }
194
- }, [runPersistence]);
259
+ const setPersistenceAdapter = useCallback(
260
+ (adapter: InteractablePersistenceAdapter | undefined) => {
261
+ if (adapterRef.current !== adapter) flushIfPending();
262
+ adapterRef.current = adapter;
263
+ },
264
+ [flushIfPending],
265
+ );
195
266
 
196
267
  const setDefState = useCallback(
197
268
  (id: string, updater: (prev: unknown) => unknown) => {
198
- setState((prev) => {
269
+ setStateAndRef((prev) => {
199
270
  const existing = prev.definitions[id];
200
271
  if (!existing) return prev;
201
272
  return {
@@ -208,22 +279,25 @@ const useInteractables = (): ClientOutput<"interactables"> => {
208
279
  });
209
280
  if (stateRef.current.definitions[id]) schedulePersistence(id);
210
281
  },
211
- [schedulePersistence],
282
+ [schedulePersistence, setStateAndRef],
212
283
  );
213
284
 
214
- const setDefSelected = useCallback((id: string, selected: boolean) => {
215
- setState((prev) => {
216
- const existing = prev.definitions[id];
217
- if (!existing) return prev;
218
- return {
219
- ...prev,
220
- definitions: {
221
- ...prev.definitions,
222
- [id]: { ...existing, selected },
223
- },
224
- };
225
- });
226
- }, []);
285
+ const setDefSelected = useCallback(
286
+ (id: string, selected: boolean) => {
287
+ setStateAndRef((prev) => {
288
+ const existing = prev.definitions[id];
289
+ if (!existing) return prev;
290
+ return {
291
+ ...prev,
292
+ definitions: {
293
+ ...prev.definitions,
294
+ [id]: { ...existing, selected },
295
+ },
296
+ };
297
+ });
298
+ },
299
+ [setStateAndRef],
300
+ );
227
301
 
228
302
  const provider = useMemo(
229
303
  () => ({
@@ -248,12 +322,14 @@ const useInteractables = (): ClientOutput<"interactables"> => {
248
322
  );
249
323
 
250
324
  useEffect(() => {
251
- for (const cb of subscribersRef.current) cb();
325
+ notifyStateSubscribers(subscribersRef.current);
252
326
  }, [state]);
253
327
 
254
- useEffect(() => {
255
- return clientRef.current!.modelContext().register(provider);
256
- }, [clientRef, provider]);
328
+ useAssistantScopeEffect(
329
+ "modelContext",
330
+ () => clientRef.current!.modelContext().register(provider),
331
+ [provider],
332
+ );
257
333
 
258
334
  const register = useCallback(
259
335
  (def: InteractableRegistration) => {
@@ -273,7 +349,7 @@ const useInteractables = (): ClientOutput<"interactables"> => {
273
349
  const detached = detachedStateRef.current.get(def.id);
274
350
  detachedStateRef.current.delete(def.id);
275
351
 
276
- setState((prev) => ({
352
+ setStateAndRef((prev) => ({
277
353
  ...prev,
278
354
  definitions: {
279
355
  ...prev.definitions,
@@ -291,7 +367,7 @@ const useInteractables = (): ClientOutput<"interactables"> => {
291
367
 
292
368
  return () => {
293
369
  flushIfPending();
294
- setState((prev) => {
370
+ setStateAndRef((prev) => {
295
371
  const existing = prev.definitions[def.id];
296
372
  if (existing) {
297
373
  detachedStateRef.current.set(def.id, existing.state);
@@ -303,7 +379,7 @@ const useInteractables = (): ClientOutput<"interactables"> => {
303
379
  });
304
380
  };
305
381
  },
306
- [flushIfPending],
382
+ [flushIfPending, setStateAndRef],
307
383
  );
308
384
 
309
385
  return {
@@ -1,5 +1,6 @@
1
1
  import { useCallback, useEffect, useRef } from "react";
2
2
  import { useAui, useAuiState } from "@assistant-ui/store";
3
+ import { actionBarCopyDisabled } from "../../store/primitive-predicates";
3
4
 
4
5
  export type UseActionBarCopyOptions = {
5
6
  copiedDuration?: number | undefined;
@@ -11,13 +12,7 @@ export const useActionBarCopy = ({
11
12
  copyToClipboard,
12
13
  }: UseActionBarCopyOptions = {}) => {
13
14
  const aui = useAui();
14
- const disabled = useAuiState((s) => {
15
- return !(
16
- (s.message.role !== "assistant" ||
17
- s.message.status?.type !== "running") &&
18
- s.message.parts.some((c) => c.type === "text" && c.text.length > 0)
19
- );
20
- });
15
+ const disabled = useAuiState(actionBarCopyDisabled);
21
16
  const isCopied = useAuiState((s) => s.message.isCopied);
22
17
  const isEditing = useAuiState((s) => s.composer.isEditing);
23
18
  const composerValue = useAuiState((s) => s.composer.text);
@@ -1,9 +1,10 @@
1
1
  import { useCallback } from "react";
2
2
  import { useAui, useAuiState } from "@assistant-ui/store";
3
+ import { actionBarEditDisabled } from "../../store/primitive-predicates";
3
4
 
4
5
  export const useActionBarEdit = () => {
5
6
  const aui = useAui();
6
- const disabled = useAuiState((s) => s.composer.isEditing);
7
+ const disabled = useAuiState(actionBarEditDisabled);
7
8
 
8
9
  const edit = useCallback(() => {
9
10
  aui.composer.beginEdit();
@@ -1,14 +1,10 @@
1
1
  import { useCallback } from "react";
2
2
  import { useAui, useAuiState } from "@assistant-ui/store";
3
+ import { actionBarReloadDisabled } from "../../store/primitive-predicates";
3
4
 
4
5
  export const useActionBarReload = () => {
5
6
  const aui = useAui();
6
- const disabled = useAuiState(
7
- (s) =>
8
- s.thread.isRunning ||
9
- s.thread.isDisabled ||
10
- s.message.role !== "assistant",
11
- );
7
+ const disabled = useAuiState(actionBarReloadDisabled);
12
8
 
13
9
  const reload = useCallback(() => {
14
10
  aui.message.reload();
@@ -1,15 +1,10 @@
1
1
  import { useCallback } from "react";
2
2
  import { useAui, useAuiState } from "@assistant-ui/store";
3
+ import { branchPickerNextDisabled } from "../../store/primitive-predicates";
3
4
 
4
5
  export const useBranchPickerNext = () => {
5
6
  const aui = useAui();
6
- const disabled = useAuiState((s) => {
7
- if (s.message.branchNumber >= s.message.branchCount) return true;
8
- if (s.thread.isRunning && !s.thread.capabilities.switchBranchDuringRun) {
9
- return true;
10
- }
11
- return false;
12
- });
7
+ const disabled = useAuiState(branchPickerNextDisabled);
13
8
 
14
9
  const next = useCallback(() => {
15
10
  aui.message.switchToBranch({ position: "next" });
@@ -1,15 +1,10 @@
1
1
  import { useCallback } from "react";
2
2
  import { useAui, useAuiState } from "@assistant-ui/store";
3
+ import { branchPickerPreviousDisabled } from "../../store/primitive-predicates";
3
4
 
4
5
  export const useBranchPickerPrevious = () => {
5
6
  const aui = useAui();
6
- const disabled = useAuiState((s) => {
7
- if (s.message.branchNumber <= 1) return true;
8
- if (s.thread.isRunning && !s.thread.capabilities.switchBranchDuringRun) {
9
- return true;
10
- }
11
- return false;
12
- });
7
+ const disabled = useAuiState(branchPickerPreviousDisabled);
13
8
 
14
9
  const previous = useCallback(() => {
15
10
  aui.message.switchToBranch({ position: "previous" });
@@ -1,9 +1,10 @@
1
1
  import { useCallback } from "react";
2
2
  import { useAui, useAuiState } from "@assistant-ui/store";
3
+ import { composerCancelDisabled } from "../../store/primitive-predicates";
3
4
 
4
5
  export const useComposerCancel = () => {
5
6
  const aui = useAui();
6
- const disabled = useAuiState((s) => !s.composer.canCancel);
7
+ const disabled = useAuiState(composerCancelDisabled);
7
8
 
8
9
  const cancel = useCallback(() => {
9
10
  aui.composer.cancel();
@@ -1,14 +1,11 @@
1
1
  import { useCallback } from "react";
2
2
  import { useAui, useAuiState } from "@assistant-ui/store";
3
+ import { composerSendDisabled } from "../../store/primitive-predicates";
3
4
  import type { ComposerSendOptions } from "../../store/scopes/composer";
4
5
 
5
6
  export const useComposerSend = () => {
6
7
  const aui = useAui();
7
- const disabled = useAuiState(
8
- (s) =>
9
- !s.composer.canSend ||
10
- (s.thread.isRunning && !s.thread.capabilities.queue),
11
- );
8
+ const disabled = useAuiState(composerSendDisabled);
12
9
 
13
10
  const send = useCallback(
14
11
  (opts?: ComposerSendOptions) => {
@@ -127,6 +127,17 @@ describe("useSuggestionTrigger", () => {
127
127
  expect(mocks.setText).toHaveBeenCalledWith("my draft Hello");
128
128
  });
129
129
 
130
+ it("does not add a separator for an empty prompt", () => {
131
+ mocks.composerState.text = "my draft";
132
+ const { result } = renderHook(() =>
133
+ useSuggestionTrigger({ prompt: "", clearComposer: false }),
134
+ );
135
+
136
+ result.current.trigger();
137
+
138
+ expect(mocks.setText).toHaveBeenCalledWith("my draft");
139
+ });
140
+
130
141
  it("inserts the prompt alone when the composer is empty and clearComposer is false", () => {
131
142
  const { result } = renderHook(() =>
132
143
  useSuggestionTrigger({ prompt: "Hello", clearComposer: false }),
@@ -1,5 +1,6 @@
1
1
  import { useCallback } from "react";
2
2
  import { useAui, useAuiState } from "@assistant-ui/store";
3
+ import { suggestionTriggerDisabled } from "../../store/primitive-predicates";
3
4
 
4
5
  export type UseSuggestionTriggerOptions = {
5
6
  prompt: string;
@@ -14,10 +15,8 @@ export const useSuggestionTrigger = ({
14
15
  }: UseSuggestionTriggerOptions) => {
15
16
  const aui = useAui();
16
17
  const resolvedSend = send ?? false;
17
- const disabled = useAuiState(
18
- (s) =>
19
- s.thread.isDisabled ||
20
- (resolvedSend && s.thread.isRunning && !s.thread.capabilities.queue),
18
+ const disabled = useAuiState((s) =>
19
+ suggestionTriggerDisabled(s, resolvedSend),
21
20
  );
22
21
 
23
22
  const trigger = useCallback(() => {
@@ -39,7 +38,7 @@ export const useSuggestionTrigger = ({
39
38
  } else {
40
39
  const currentText = aui.composer.getState().text;
41
40
  aui.composer.setText(
42
- currentText.trim() ? `${currentText} ${prompt}` : prompt,
41
+ [currentText, prompt].filter((part) => part.trim()).join(" "),
43
42
  );
44
43
  }
45
44
  }
@@ -726,7 +726,6 @@ const EMPTY_RUNNING_TEXT_PART: Extract<EnrichedPartState, { type: "text" }> =
726
726
  });
727
727
 
728
728
  /**
729
- * @internal
730
729
  * Renders a single part by index, calling `children` with the
731
730
  * {@link EnrichedPartState} (tool/data UI enrichments + addResult/resume
732
731
  * for tool calls). Shared between `<MessagePrimitive.Parts>` and
@@ -130,7 +130,8 @@ const getComponent = (
130
130
  components.SystemEditComposer ??
131
131
  components.EditComposer ??
132
132
  components.SystemMessage ??
133
- (components.Message as ComponentType)
133
+ (components.Message as ComponentType) ??
134
+ DEFAULT_SYSTEM_MESSAGE
134
135
  );
135
136
  } else {
136
137
  return (