@assistant-ui/core 0.3.13 → 0.3.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (463) hide show
  1. package/dist/adapters/speech.d.ts.map +1 -1
  2. package/dist/adapters/speech.js +9 -15
  3. package/dist/adapters/speech.js.map +1 -1
  4. package/dist/adapters/thread-history.d.ts +2 -0
  5. package/dist/adapters/thread-history.d.ts.map +1 -1
  6. package/dist/adapters/voice.d.ts.map +1 -1
  7. package/dist/adapters/voice.js +38 -15
  8. package/dist/adapters/voice.js.map +1 -1
  9. package/dist/index.d.ts +2 -2
  10. package/dist/index.js +1 -1
  11. package/dist/index.js.map +1 -1
  12. package/dist/internal.d.ts +3 -2
  13. package/dist/internal.js +8 -7
  14. package/dist/model-context/frame/host.d.ts +1 -1
  15. package/dist/model-context/frame/host.d.ts.map +1 -1
  16. package/dist/model-context/frame/host.js +19 -4
  17. package/dist/model-context/frame/host.js.map +1 -1
  18. package/dist/model-context/frame/provider.d.ts +4 -0
  19. package/dist/model-context/frame/provider.d.ts.map +1 -1
  20. package/dist/model-context/frame/provider.js +50 -3
  21. package/dist/model-context/frame/provider.js.map +1 -1
  22. package/dist/model-context/frame/types.d.ts +4 -1
  23. package/dist/model-context/frame/types.d.ts.map +1 -1
  24. package/dist/model-context/frame/types.js.map +1 -1
  25. package/dist/model-context/registry.d.ts.map +1 -1
  26. package/dist/model-context/registry.js +16 -4
  27. package/dist/model-context/registry.js.map +1 -1
  28. package/dist/react/RuntimeAdapter.d.ts +8 -1
  29. package/dist/react/RuntimeAdapter.d.ts.map +1 -1
  30. package/dist/react/RuntimeAdapter.js +23 -18
  31. package/dist/react/RuntimeAdapter.js.map +1 -1
  32. package/dist/react/adapters/LocalStorageThreadListAdapter.d.ts.map +1 -1
  33. package/dist/react/adapters/LocalStorageThreadListAdapter.js +28 -12
  34. package/dist/react/adapters/LocalStorageThreadListAdapter.js.map +1 -1
  35. package/dist/react/client/AdaptedRemoteThread.d.ts +11 -0
  36. package/dist/react/client/AdaptedRemoteThread.d.ts.map +1 -0
  37. package/dist/react/client/AdaptedRemoteThread.js +27 -0
  38. package/dist/react/client/AdaptedRemoteThread.js.map +1 -0
  39. package/dist/react/client/InMemoryThreadList.d.ts +19 -0
  40. package/dist/react/client/InMemoryThreadList.d.ts.map +1 -0
  41. package/dist/react/client/InMemoryThreadList.js +418 -0
  42. package/dist/react/client/InMemoryThreadList.js.map +1 -0
  43. package/dist/react/client/Interactables.d.ts.map +1 -1
  44. package/dist/react/client/Interactables.js +159 -102
  45. package/dist/react/client/Interactables.js.map +1 -1
  46. package/dist/react/client/RemoteThreadList.d.ts +34 -0
  47. package/dist/react/client/RemoteThreadList.d.ts.map +1 -0
  48. package/dist/react/client/RemoteThreadList.js +898 -0
  49. package/dist/react/client/RemoteThreadList.js.map +1 -0
  50. package/dist/react/client/Tools.d.ts.map +1 -1
  51. package/dist/react/client/Tools.js +38 -27
  52. package/dist/react/client/Tools.js.map +1 -1
  53. package/dist/react/index.d.ts +7 -2
  54. package/dist/react/index.js +5 -2
  55. package/dist/react/interactables-legacy/Interactables.d.ts.map +1 -1
  56. package/dist/react/interactables-legacy/Interactables.js +145 -110
  57. package/dist/react/interactables-legacy/Interactables.js.map +1 -1
  58. package/dist/react/primitive-hooks/useActionBarCopy.d.ts.map +1 -1
  59. package/dist/react/primitive-hooks/useActionBarCopy.js +20 -19
  60. package/dist/react/primitive-hooks/useActionBarCopy.js.map +1 -1
  61. package/dist/react/primitive-hooks/useActionBarEdit.d.ts.map +1 -1
  62. package/dist/react/primitive-hooks/useActionBarEdit.js +2 -4
  63. package/dist/react/primitive-hooks/useActionBarEdit.js.map +1 -1
  64. package/dist/react/primitive-hooks/useActionBarReload.d.ts.map +1 -1
  65. package/dist/react/primitive-hooks/useActionBarReload.js +2 -4
  66. package/dist/react/primitive-hooks/useActionBarReload.js.map +1 -1
  67. package/dist/react/primitive-hooks/useBranchPickerNext.d.ts.map +1 -1
  68. package/dist/react/primitive-hooks/useBranchPickerNext.js +2 -6
  69. package/dist/react/primitive-hooks/useBranchPickerNext.js.map +1 -1
  70. package/dist/react/primitive-hooks/useBranchPickerPrevious.d.ts.map +1 -1
  71. package/dist/react/primitive-hooks/useBranchPickerPrevious.js +2 -6
  72. package/dist/react/primitive-hooks/useBranchPickerPrevious.js.map +1 -1
  73. package/dist/react/primitive-hooks/useComposerCancel.d.ts.map +1 -1
  74. package/dist/react/primitive-hooks/useComposerCancel.js +2 -4
  75. package/dist/react/primitive-hooks/useComposerCancel.js.map +1 -1
  76. package/dist/react/primitive-hooks/useComposerSend.d.ts.map +1 -1
  77. package/dist/react/primitive-hooks/useComposerSend.js +2 -4
  78. package/dist/react/primitive-hooks/useComposerSend.js.map +1 -1
  79. package/dist/react/primitive-hooks/useSuggestionTrigger.d.ts.map +1 -1
  80. package/dist/react/primitive-hooks/useSuggestionTrigger.js +6 -2
  81. package/dist/react/primitive-hooks/useSuggestionTrigger.js.map +1 -1
  82. package/dist/react/primitive-hooks/useThreadIsEmpty.d.ts +3 -0
  83. package/dist/react/primitive-hooks/useThreadIsEmpty.d.ts.map +1 -1
  84. package/dist/react/primitive-hooks/useThreadIsEmpty.js +3 -0
  85. package/dist/react/primitive-hooks/useThreadIsEmpty.js.map +1 -1
  86. package/dist/react/primitive-hooks/useThreadIsRunning.d.ts +3 -0
  87. package/dist/react/primitive-hooks/useThreadIsRunning.d.ts.map +1 -1
  88. package/dist/react/primitive-hooks/useThreadIsRunning.js +3 -0
  89. package/dist/react/primitive-hooks/useThreadIsRunning.js.map +1 -1
  90. package/dist/react/primitives/message/MessageParts.d.ts +13 -0
  91. package/dist/react/primitives/message/MessageParts.d.ts.map +1 -1
  92. package/dist/react/primitives/message/MessageParts.js.map +1 -1
  93. package/dist/react/primitives/thread/ThreadMessages.d.ts.map +1 -1
  94. package/dist/react/primitives/thread/ThreadMessages.js +1 -1
  95. package/dist/react/primitives/thread/ThreadMessages.js.map +1 -1
  96. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts +24 -10
  97. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts.map +1 -1
  98. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js +115 -71
  99. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js.map +1 -1
  100. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts +14 -2
  101. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts.map +1 -1
  102. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js +232 -63
  103. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js.map +1 -1
  104. package/dist/react/runtimes/RemoteThreadResource.d.ts +30 -0
  105. package/dist/react/runtimes/RemoteThreadResource.d.ts.map +1 -0
  106. package/dist/react/runtimes/RemoteThreadResource.js +136 -0
  107. package/dist/react/runtimes/RemoteThreadResource.js.map +1 -0
  108. package/dist/react/runtimes/RuntimeAdapterProvider.d.ts +3 -10
  109. package/dist/react/runtimes/RuntimeAdapterProvider.d.ts.map +1 -1
  110. package/dist/react/runtimes/RuntimeAdapterProvider.js +3 -6
  111. package/dist/react/runtimes/RuntimeAdapterProvider.js.map +1 -1
  112. package/dist/react/runtimes/assistant-transport/commandQueue.d.ts +17 -0
  113. package/dist/react/runtimes/assistant-transport/commandQueue.d.ts.map +1 -0
  114. package/dist/react/runtimes/assistant-transport/commandQueue.js +55 -0
  115. package/dist/react/runtimes/assistant-transport/commandQueue.js.map +1 -0
  116. package/dist/react/runtimes/assistant-transport/replayBoundaryStream.d.ts +11 -0
  117. package/dist/react/runtimes/assistant-transport/replayBoundaryStream.d.ts.map +1 -0
  118. package/dist/react/runtimes/assistant-transport/replayBoundaryStream.js +165 -0
  119. package/dist/react/runtimes/assistant-transport/replayBoundaryStream.js.map +1 -0
  120. package/dist/react/runtimes/assistant-transport/runManager.d.ts +15 -0
  121. package/dist/react/runtimes/assistant-transport/runManager.d.ts.map +1 -0
  122. package/dist/react/runtimes/assistant-transport/runManager.js +86 -0
  123. package/dist/react/runtimes/assistant-transport/runManager.js.map +1 -0
  124. package/dist/react/runtimes/assistant-transport/types.d.ts +130 -0
  125. package/dist/react/runtimes/assistant-transport/types.d.ts.map +1 -0
  126. package/dist/react/runtimes/assistant-transport/types.js +0 -0
  127. package/dist/react/runtimes/assistant-transport/useAssistantTransportRuntime.d.ts +14 -0
  128. package/dist/react/runtimes/assistant-transport/useAssistantTransportRuntime.d.ts.map +1 -0
  129. package/dist/react/runtimes/assistant-transport/useAssistantTransportRuntime.js +296 -0
  130. package/dist/react/runtimes/assistant-transport/useAssistantTransportRuntime.js.map +1 -0
  131. package/dist/react/runtimes/assistant-transport/useConvertedState.d.ts +7 -0
  132. package/dist/react/runtimes/assistant-transport/useConvertedState.d.ts.map +1 -0
  133. package/dist/react/runtimes/assistant-transport/useConvertedState.js +25 -0
  134. package/dist/react/runtimes/assistant-transport/useConvertedState.js.map +1 -0
  135. package/dist/react/runtimes/assistant-transport/useLatestRef.d.ts +7 -0
  136. package/dist/react/runtimes/assistant-transport/useLatestRef.d.ts.map +1 -0
  137. package/dist/react/runtimes/assistant-transport/useLatestRef.js +27 -0
  138. package/dist/react/runtimes/assistant-transport/useLatestRef.js.map +1 -0
  139. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts.map +1 -1
  140. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js +39 -13
  141. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js.map +1 -1
  142. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.d.ts +2 -1
  143. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.d.ts.map +1 -1
  144. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.js +3 -3
  145. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.js.map +1 -1
  146. package/dist/react/runtimes/cloud/auiV0.d.ts +4 -0
  147. package/dist/react/runtimes/cloud/auiV0.d.ts.map +1 -1
  148. package/dist/react/runtimes/cloud/auiV0.js +7 -0
  149. package/dist/react/runtimes/cloud/auiV0.js.map +1 -1
  150. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.d.ts.map +1 -1
  151. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js +60 -17
  152. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js.map +1 -1
  153. package/dist/react/runtimes/cloud/useCloudThreadListRuntime.d.ts +16 -0
  154. package/dist/react/runtimes/cloud/useCloudThreadListRuntime.d.ts.map +1 -0
  155. package/dist/react/runtimes/cloud/useCloudThreadListRuntime.js +36 -0
  156. package/dist/react/runtimes/cloud/useCloudThreadListRuntime.js.map +1 -0
  157. package/dist/react/runtimes/external-message-converter.js +14 -14
  158. package/dist/react/runtimes/external-message-converter.js.map +1 -1
  159. package/dist/react/runtimes/useExternalStoreRuntime.d.ts.map +1 -1
  160. package/dist/react/runtimes/useExternalStoreRuntime.js +44 -28
  161. package/dist/react/runtimes/useExternalStoreRuntime.js.map +1 -1
  162. package/dist/react/runtimes/useExternalStoreSharedOptions.js.map +1 -1
  163. package/dist/react/runtimes/useLocalRuntime.js +1 -1
  164. package/dist/react/runtimes/useRuntimeAdapters.d.ts +9 -0
  165. package/dist/react/runtimes/useRuntimeAdapters.d.ts.map +1 -0
  166. package/dist/react/runtimes/useRuntimeAdapters.js +20 -0
  167. package/dist/react/runtimes/useRuntimeAdapters.js.map +1 -0
  168. package/dist/runtime/api/composer-runtime.d.ts +5 -0
  169. package/dist/runtime/api/composer-runtime.d.ts.map +1 -1
  170. package/dist/runtime/api/composer-runtime.js.map +1 -1
  171. package/dist/runtime/api/message-runtime.js +1 -1
  172. package/dist/runtime/api/thread-list-runtime.d.ts +1 -0
  173. package/dist/runtime/api/thread-list-runtime.d.ts.map +1 -1
  174. package/dist/runtime/api/thread-list-runtime.js +4 -2
  175. package/dist/runtime/api/thread-list-runtime.js.map +1 -1
  176. package/dist/runtime/api/thread-runtime.d.ts +12 -2
  177. package/dist/runtime/api/thread-runtime.d.ts.map +1 -1
  178. package/dist/runtime/api/thread-runtime.js +8 -2
  179. package/dist/runtime/api/thread-runtime.js.map +1 -1
  180. package/dist/runtime/base/base-composer-runtime-core.d.ts.map +1 -1
  181. package/dist/runtime/base/base-composer-runtime-core.js +8 -7
  182. package/dist/runtime/base/base-composer-runtime-core.js.map +1 -1
  183. package/dist/runtime/base/base-thread-runtime-core.d.ts +1 -0
  184. package/dist/runtime/base/base-thread-runtime-core.d.ts.map +1 -1
  185. package/dist/runtime/base/base-thread-runtime-core.js +3 -3
  186. package/dist/runtime/base/base-thread-runtime-core.js.map +1 -1
  187. package/dist/runtime/base/default-thread-composer-runtime-core.d.ts +0 -1
  188. package/dist/runtime/base/default-thread-composer-runtime-core.d.ts.map +1 -1
  189. package/dist/runtime/base/default-thread-composer-runtime-core.js +10 -4
  190. package/dist/runtime/base/default-thread-composer-runtime-core.js.map +1 -1
  191. package/dist/runtime/interfaces/thread-runtime-core.d.ts +6 -0
  192. package/dist/runtime/interfaces/thread-runtime-core.d.ts.map +1 -1
  193. package/dist/runtime/internal.js +5 -5
  194. package/dist/runtime/queue/message-queue.d.ts.map +1 -1
  195. package/dist/runtime/queue/message-queue.js +2 -1
  196. package/dist/runtime/queue/message-queue.js.map +1 -1
  197. package/dist/runtime/utils/message-repository.d.ts.map +1 -1
  198. package/dist/runtime/utils/message-repository.js +27 -18
  199. package/dist/runtime/utils/message-repository.js.map +1 -1
  200. package/dist/runtime/utils/thread-runtime-lifecycle.d.ts +8 -0
  201. package/dist/runtime/utils/thread-runtime-lifecycle.d.ts.map +1 -0
  202. package/dist/runtime/utils/thread-runtime-lifecycle.js +11 -0
  203. package/dist/runtime/utils/thread-runtime-lifecycle.js.map +1 -0
  204. package/dist/runtimes/external-store/external-store-shared-options.js.map +1 -1
  205. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.d.ts.map +1 -1
  206. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js +4 -1
  207. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js.map +1 -1
  208. package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts +8 -0
  209. package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts.map +1 -1
  210. package/dist/runtimes/external-store/external-store-thread-runtime-core.js +37 -13
  211. package/dist/runtimes/external-store/external-store-thread-runtime-core.js.map +1 -1
  212. package/dist/runtimes/inert/InertThreadRuntimeCore.d.ts +102 -0
  213. package/dist/runtimes/inert/InertThreadRuntimeCore.d.ts.map +1 -0
  214. package/dist/runtimes/inert/InertThreadRuntimeCore.js +156 -0
  215. package/dist/runtimes/inert/InertThreadRuntimeCore.js.map +1 -0
  216. package/dist/runtimes/internal.d.ts +1 -1
  217. package/dist/runtimes/local/local-thread-runtime-core.d.ts +3 -0
  218. package/dist/runtimes/local/local-thread-runtime-core.d.ts.map +1 -1
  219. package/dist/runtimes/local/local-thread-runtime-core.js +78 -19
  220. package/dist/runtimes/local/local-thread-runtime-core.js.map +1 -1
  221. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.d.ts +12 -59
  222. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.d.ts.map +1 -1
  223. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.js +10 -142
  224. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.js.map +1 -1
  225. package/dist/runtimes/remote-thread-list/adapter-changed.d.ts +9 -0
  226. package/dist/runtimes/remote-thread-list/adapter-changed.d.ts.map +1 -0
  227. package/dist/runtimes/remote-thread-list/adapter-changed.js +13 -0
  228. package/dist/runtimes/remote-thread-list/adapter-changed.js.map +1 -0
  229. package/dist/runtimes/remote-thread-list/empty-thread-core.d.ts.map +1 -1
  230. package/dist/runtimes/remote-thread-list/empty-thread-core.js +16 -152
  231. package/dist/runtimes/remote-thread-list/empty-thread-core.js.map +1 -1
  232. package/dist/runtimes/remote-thread-list/optimistic-state.d.ts +2 -0
  233. package/dist/runtimes/remote-thread-list/optimistic-state.d.ts.map +1 -1
  234. package/dist/runtimes/remote-thread-list/optimistic-state.js +11 -0
  235. package/dist/runtimes/remote-thread-list/optimistic-state.js.map +1 -1
  236. package/dist/runtimes/remote-thread-list/types.d.ts +32 -1
  237. package/dist/runtimes/remote-thread-list/types.d.ts.map +1 -1
  238. package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts +1 -12
  239. package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts.map +1 -1
  240. package/dist/runtimes/tool-invocations/ToolInvocationTracker.js +67 -38
  241. package/dist/runtimes/tool-invocations/ToolInvocationTracker.js.map +1 -1
  242. package/dist/store/clients/external-thread.js +1 -1
  243. package/dist/store/clients/external-thread.js.map +1 -1
  244. package/dist/store/clients/suggestions.js +2 -2
  245. package/dist/store/clients/suggestions.js.map +1 -1
  246. package/dist/store/clients/thread-selection-events.d.ts +10 -0
  247. package/dist/store/clients/thread-selection-events.d.ts.map +1 -0
  248. package/dist/store/clients/thread-selection-events.js +40 -0
  249. package/dist/store/clients/thread-selection-events.js.map +1 -0
  250. package/dist/store/env.d.ts +5 -0
  251. package/dist/store/env.d.ts.map +1 -0
  252. package/dist/store/env.js +12 -0
  253. package/dist/store/env.js.map +1 -0
  254. package/dist/store/index.d.ts +5 -3
  255. package/dist/store/index.js +4 -2
  256. package/dist/store/internal.d.ts +4 -1
  257. package/dist/store/internal.js +4 -1
  258. package/dist/store/primitive-predicates.d.ts +19 -0
  259. package/dist/store/primitive-predicates.d.ts.map +1 -0
  260. package/dist/store/primitive-predicates.js +19 -0
  261. package/dist/store/primitive-predicates.js.map +1 -0
  262. package/dist/store/runtime-clients/attachment-runtime-client.d.ts.map +1 -1
  263. package/dist/store/runtime-clients/attachment-runtime-client.js +18 -11
  264. package/dist/store/runtime-clients/attachment-runtime-client.js.map +1 -1
  265. package/dist/store/runtime-clients/handle-runtime-action.d.ts +5 -0
  266. package/dist/store/runtime-clients/handle-runtime-action.d.ts.map +1 -0
  267. package/dist/store/runtime-clients/handle-runtime-action.js +14 -0
  268. package/dist/store/runtime-clients/handle-runtime-action.js.map +1 -0
  269. package/dist/store/runtime-clients/handle-thread-list-action.d.ts +5 -0
  270. package/dist/store/runtime-clients/handle-thread-list-action.d.ts.map +1 -0
  271. package/dist/store/runtime-clients/handle-thread-list-action.js +7 -0
  272. package/dist/store/runtime-clients/handle-thread-list-action.js.map +1 -0
  273. package/dist/store/runtime-clients/thread-list-item-runtime-client.d.ts.map +1 -1
  274. package/dist/store/runtime-clients/thread-list-item-runtime-client.js +62 -29
  275. package/dist/store/runtime-clients/thread-list-item-runtime-client.js.map +1 -1
  276. package/dist/store/runtime-clients/thread-list-runtime-client.d.ts.map +1 -1
  277. package/dist/store/runtime-clients/thread-list-runtime-client.js +5 -6
  278. package/dist/store/runtime-clients/thread-list-runtime-client.js.map +1 -1
  279. package/dist/store/scopes/composer.d.ts +9 -4
  280. package/dist/store/scopes/composer.d.ts.map +1 -1
  281. package/dist/store/scopes/thread-list-item.d.ts +7 -6
  282. package/dist/store/scopes/thread-list-item.d.ts.map +1 -1
  283. package/dist/store/scopes/thread.d.ts +8 -7
  284. package/dist/store/scopes/thread.d.ts.map +1 -1
  285. package/dist/store/scopes/threads.d.ts +17 -1
  286. package/dist/store/scopes/threads.d.ts.map +1 -1
  287. package/dist/subscribable/subscribable.d.ts +2 -1
  288. package/dist/subscribable/subscribable.d.ts.map +1 -1
  289. package/dist/subscribable/subscribable.js +23 -18
  290. package/dist/subscribable/subscribable.js.map +1 -1
  291. package/dist/types/message.d.ts +1 -1
  292. package/dist/types/message.js.map +1 -1
  293. package/dist/utils/composite-context-provider.d.ts +1 -0
  294. package/dist/utils/composite-context-provider.d.ts.map +1 -1
  295. package/dist/utils/composite-context-provider.js +25 -9
  296. package/dist/utils/composite-context-provider.js.map +1 -1
  297. package/dist/utils/notify-event-listeners.d.ts +2 -2
  298. package/dist/utils/notify-event-listeners.d.ts.map +1 -1
  299. package/dist/utils/notify-event-listeners.js +2 -2
  300. package/dist/utils/notify-event-listeners.js.map +1 -1
  301. package/dist/utils/silent-runtime-action.d.ts +6 -0
  302. package/dist/utils/silent-runtime-action.d.ts.map +1 -0
  303. package/dist/utils/silent-runtime-action.js +7 -0
  304. package/dist/utils/silent-runtime-action.js.map +1 -0
  305. package/package.json +8 -8
  306. package/src/adapters/speech.test.ts +118 -1
  307. package/src/adapters/speech.ts +21 -22
  308. package/src/adapters/thread-history.ts +2 -0
  309. package/src/adapters/voice.test.ts +134 -0
  310. package/src/adapters/voice.ts +35 -27
  311. package/src/index.ts +1 -0
  312. package/src/internal.ts +1 -0
  313. package/src/model-context/frame/host.test.ts +87 -5
  314. package/src/model-context/frame/host.ts +18 -4
  315. package/src/model-context/frame/provider.test.ts +347 -20
  316. package/src/model-context/frame/provider.ts +58 -2
  317. package/src/model-context/frame/types.ts +5 -0
  318. package/src/model-context/registry.test.ts +131 -0
  319. package/src/model-context/registry.ts +16 -6
  320. package/src/react/RuntimeAdapter.test.ts +2 -0
  321. package/src/react/RuntimeAdapter.ts +20 -8
  322. package/src/react/adapters/LocalStorageThreadListAdapter.tsx +34 -17
  323. package/src/react/client/AdaptedRemoteThread.ts +41 -0
  324. package/src/react/client/InMemoryThreadList.test.tsx +148 -0
  325. package/src/react/client/InMemoryThreadList.ts +290 -0
  326. package/src/react/client/Interactables.test.ts +326 -2
  327. package/src/react/client/Interactables.ts +227 -110
  328. package/src/react/client/RemoteThreadList.test.ts +1222 -0
  329. package/src/react/client/RemoteThreadList.ts +1136 -0
  330. package/src/react/client/Tools.ts +36 -29
  331. package/src/react/index.ts +13 -0
  332. package/src/react/interactables-legacy/Interactables.test.ts +317 -0
  333. package/src/react/interactables-legacy/Interactables.ts +204 -128
  334. package/src/react/primitive-hooks/useActionBarCopy.test.ts +15 -0
  335. package/src/react/primitive-hooks/useActionBarCopy.ts +15 -10
  336. package/src/react/primitive-hooks/useActionBarEdit.ts +2 -1
  337. package/src/react/primitive-hooks/useActionBarReload.ts +2 -6
  338. package/src/react/primitive-hooks/useBranchPickerNext.ts +2 -7
  339. package/src/react/primitive-hooks/useBranchPickerPrevious.ts +2 -7
  340. package/src/react/primitive-hooks/useComposerCancel.ts +2 -1
  341. package/src/react/primitive-hooks/useComposerSend.ts +2 -5
  342. package/src/react/primitive-hooks/useSuggestionTrigger.test.ts +11 -0
  343. package/src/react/primitive-hooks/useSuggestionTrigger.ts +4 -5
  344. package/src/react/primitive-hooks/useThreadIsEmpty.ts +3 -0
  345. package/src/react/primitive-hooks/useThreadIsRunning.ts +3 -0
  346. package/src/react/primitives/message/MessageParts.tsx +0 -1
  347. package/src/react/primitives/thread/ThreadMessages.tsx +2 -1
  348. package/src/react/runtimes/RemoteThreadListHookInstanceManager.retry.test.tsx +116 -0
  349. package/src/react/runtimes/RemoteThreadListHookInstanceManager.running.test.tsx +1 -1
  350. package/src/react/runtimes/RemoteThreadListHookInstanceManager.test.tsx +57 -6
  351. package/src/react/runtimes/RemoteThreadListHookInstanceManager.title.test.tsx +272 -0
  352. package/src/react/runtimes/RemoteThreadListHookInstanceManager.tsx +171 -124
  353. package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.republish.test.ts +87 -0
  354. package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.tsx +327 -83
  355. package/src/react/runtimes/RemoteThreadResource.test.ts +141 -0
  356. package/src/react/runtimes/RemoteThreadResource.ts +233 -0
  357. package/src/react/runtimes/RuntimeAdapterProvider.tsx +8 -20
  358. package/src/react/runtimes/assistant-transport/commandQueue.ts +68 -0
  359. package/src/react/runtimes/assistant-transport/replayBoundaryStream.test.ts +455 -0
  360. package/src/react/runtimes/assistant-transport/replayBoundaryStream.ts +172 -0
  361. package/src/react/runtimes/assistant-transport/runManager.ts +124 -0
  362. package/src/react/runtimes/assistant-transport/transport-delivery.test.tsx +79 -0
  363. package/src/react/runtimes/assistant-transport/transport-parentid.test.tsx +97 -0
  364. package/src/react/runtimes/assistant-transport/transport-scheduling.test.ts +414 -0
  365. package/src/react/runtimes/assistant-transport/types.ts +170 -0
  366. package/src/react/runtimes/assistant-transport/useAssistantTransport.spec.md +141 -0
  367. package/src/react/runtimes/assistant-transport/useAssistantTransportRuntime.test.tsx +683 -0
  368. package/src/react/runtimes/assistant-transport/useAssistantTransportRuntime.ts +483 -0
  369. package/src/react/runtimes/assistant-transport/useConvertedState.ts +20 -0
  370. package/src/react/runtimes/assistant-transport/useLatestRef.ts +9 -0
  371. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.test.tsx +131 -6
  372. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.ts +61 -15
  373. package/src/react/runtimes/cloud/CloudFileAttachmentAdapter.ts +6 -4
  374. package/src/react/runtimes/cloud/auiV0.ts +17 -1
  375. package/src/react/runtimes/cloud/useCloudThreadListAdapter.test.tsx +98 -3
  376. package/src/react/runtimes/cloud/useCloudThreadListAdapter.tsx +104 -27
  377. package/src/react/runtimes/cloud/useCloudThreadListRuntime.test.tsx +56 -0
  378. package/src/react/runtimes/cloud/useCloudThreadListRuntime.ts +31 -0
  379. package/src/react/runtimes/external-message-converter.test.ts +143 -0
  380. package/src/react/runtimes/external-message-converter.ts +41 -41
  381. package/src/react/runtimes/remote-thread-hook-on-tap.test.ts +58 -0
  382. package/src/react/runtimes/useExternalStoreRuntime.lifecycle.test.tsx +83 -0
  383. package/src/react/runtimes/useExternalStoreRuntime.suggestions.test.tsx +13 -3
  384. package/src/react/runtimes/useExternalStoreRuntime.ts +7 -0
  385. package/src/react/runtimes/useExternalStoreSharedOptions.ts +3 -1
  386. package/src/react/runtimes/useLocalRuntime.test.tsx +134 -8
  387. package/src/react/runtimes/useRuntimeAdapters.test.tsx +62 -0
  388. package/src/react/runtimes/useRuntimeAdapters.ts +28 -0
  389. package/src/runtime/api/composer-runtime.ts +5 -0
  390. package/src/runtime/api/thread-list-runtime.ts +3 -1
  391. package/src/runtime/api/thread-runtime.ts +20 -2
  392. package/src/runtime/base/base-composer-runtime-core.ts +6 -5
  393. package/src/runtime/base/base-thread-runtime-core.test.ts +191 -0
  394. package/src/runtime/base/base-thread-runtime-core.ts +11 -2
  395. package/src/runtime/base/default-thread-composer-runtime-core.ts +12 -4
  396. package/src/runtime/interfaces/thread-runtime-core.ts +6 -0
  397. package/src/runtime/queue/message-queue.ts +2 -1
  398. package/src/runtime/utils/message-repository.ts +26 -18
  399. package/src/runtime/utils/thread-runtime-lifecycle.ts +18 -0
  400. package/src/runtimes/external-store/external-store-shared-options.ts +3 -1
  401. package/src/runtimes/external-store/external-store-thread-list-runtime-core.ts +4 -1
  402. package/src/runtimes/external-store/external-store-thread-runtime-core.ts +103 -34
  403. package/src/runtimes/inert/InertThreadRuntimeCore.test.ts +253 -0
  404. package/src/runtimes/inert/InertThreadRuntimeCore.ts +232 -0
  405. package/src/runtimes/local/local-thread-runtime-core.test.ts +692 -4
  406. package/src/runtimes/local/local-thread-runtime-core.ts +117 -22
  407. package/src/runtimes/readonly/ReadonlyThreadRuntimeCore.ts +17 -205
  408. package/src/runtimes/remote-thread-list/adapter-changed.ts +10 -0
  409. package/src/runtimes/remote-thread-list/empty-thread-core.ts +28 -217
  410. package/src/runtimes/remote-thread-list/optimistic-state.test.ts +18 -0
  411. package/src/runtimes/remote-thread-list/optimistic-state.ts +13 -0
  412. package/src/runtimes/remote-thread-list/types.ts +34 -0
  413. package/src/runtimes/tool-invocations/EDGE_CASES.md +17 -6
  414. package/src/runtimes/tool-invocations/ToolInvocationTracker.test.ts +243 -0
  415. package/src/runtimes/tool-invocations/ToolInvocationTracker.ts +127 -61
  416. package/src/store/clients/external-thread.ts +1 -1
  417. package/src/store/clients/model-context-client.test.ts +16 -8
  418. package/src/store/clients/suggestions.ts +2 -2
  419. package/src/store/clients/thread-selection-events.ts +21 -0
  420. package/src/store/env.ts +11 -0
  421. package/src/store/index.ts +14 -1
  422. package/src/store/internal.ts +13 -0
  423. package/src/store/primitive-predicates.test.ts +184 -0
  424. package/src/store/primitive-predicates.ts +43 -0
  425. package/src/store/runtime-clients/attachment-runtime-client.test.ts +41 -0
  426. package/src/store/runtime-clients/attachment-runtime-client.ts +2 -1
  427. package/src/store/runtime-clients/handle-runtime-action.test.ts +40 -0
  428. package/src/store/runtime-clients/handle-runtime-action.ts +14 -0
  429. package/src/store/runtime-clients/handle-thread-list-action.test.ts +69 -0
  430. package/src/store/runtime-clients/handle-thread-list-action.ts +6 -0
  431. package/src/store/runtime-clients/thread-list-item-runtime-client.ts +15 -7
  432. package/src/store/runtime-clients/thread-list-runtime-client.ts +9 -6
  433. package/src/store/scopes/composer.ts +9 -4
  434. package/src/store/scopes/thread-list-item.ts +7 -6
  435. package/src/store/scopes/thread.ts +8 -7
  436. package/src/store/scopes/threads.ts +14 -0
  437. package/src/subscribable/subscribable.test.ts +77 -1
  438. package/src/subscribable/subscribable.ts +38 -23
  439. package/src/tests/MessageRepository.test.ts +48 -0
  440. package/src/tests/RemoteThreadListThreadListRuntimeCore-errors.test.ts +2 -2
  441. package/src/tests/RemoteThreadListThreadListRuntimeCore-loadMore.test.ts +8 -6
  442. package/src/tests/RemoteThreadListThreadListRuntimeCore-switchToThread-unarchive.test.ts +25 -0
  443. package/src/tests/auiV0Encode.test.ts +66 -0
  444. package/src/tests/base-composer-runtime-core-send.test.ts +30 -0
  445. package/src/tests/base-composer-runtime-core.test.ts +28 -0
  446. package/src/tests/composer-can-cancel.test.ts +101 -0
  447. package/src/tests/empty-thread-core.test.ts +6 -0
  448. package/src/tests/external-store-thread-list-runtime-core.test.ts +101 -0
  449. package/src/tests/external-store-thread-runtime-core-adapter.test.ts +211 -1
  450. package/src/tests/external-store-thread-runtime-core.test.ts +124 -0
  451. package/src/tests/external-thread-isEmpty.test.tsx +100 -0
  452. package/src/tests/interactables-toolui-migration.test.tsx +66 -0
  453. package/src/tests/message-queue.test.ts +28 -0
  454. package/src/tests/remote-thread-list-adapter-switch.test.ts +383 -0
  455. package/src/tests/session-reset-notification.test.ts +145 -0
  456. package/src/tests/thread-switch-events.test.tsx +99 -1
  457. package/src/tests/tools-scope-migration.test.tsx +58 -0
  458. package/src/tests/useRemoteThreadListRuntime-controlled.test.tsx +67 -0
  459. package/src/types/message.ts +1 -1
  460. package/src/utils/composite-context-provider.test.ts +139 -0
  461. package/src/utils/composite-context-provider.ts +26 -8
  462. package/src/utils/notify-event-listeners.ts +10 -5
  463. package/src/utils/silent-runtime-action.ts +6 -0
@@ -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 {
@@ -82,6 +82,21 @@ describe("useActionBarCopy", () => {
82
82
  expect(mocks.setIsCopied).not.toHaveBeenCalled();
83
83
  });
84
84
 
85
+ it("does not report copy success when the clipboard handler throws synchronously", async () => {
86
+ const copyToClipboard = vi.fn(() => {
87
+ throw new TypeError(
88
+ "Cannot read properties of undefined (reading 'writeText')",
89
+ );
90
+ });
91
+ const { result } = renderHook(() => useActionBarCopy({ copyToClipboard }));
92
+
93
+ expect(() => result.current.copy()).not.toThrow();
94
+ await Promise.resolve();
95
+
96
+ expect(copyToClipboard).toHaveBeenCalledWith("Hello");
97
+ expect(mocks.setIsCopied).not.toHaveBeenCalled();
98
+ });
99
+
85
100
  it("keeps copy success visible for the full duration after copying again", async () => {
86
101
  vi.useFakeTimers();
87
102
  const copyToClipboard = vi.fn();
@@ -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);
@@ -45,9 +40,19 @@ export const useActionBarCopy = ({
45
40
  if (!valueToCopy) return;
46
41
  const scopeGeneration = scopeGenerationRef.current;
47
42
 
48
- // The rejection handler swallows clipboard write failures (permission denied,
49
- // API unavailable) so they don't surface as unhandled promise rejections.
50
- Promise.resolve(copyToClipboard(valueToCopy)).then(
43
+ // The writer runs synchronously inside the press so the user-gesture gating
44
+ // of navigator.clipboard survives (WebKit scopes it to the stack); the try
45
+ // contains a synchronously throwing caller-supplied writer, and the rejection
46
+ // handler swallows clipboard failures (permission denied, API unavailable) so
47
+ // they don't surface as unhandled rejections.
48
+ let write: void | Promise<void>;
49
+ try {
50
+ write = copyToClipboard(valueToCopy);
51
+ } catch {
52
+ return;
53
+ }
54
+
55
+ Promise.resolve(write).then(
51
56
  () => {
52
57
  if (scopeGeneration !== scopeGenerationRef.current) return;
53
58
 
@@ -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
  }
@@ -1,5 +1,8 @@
1
1
  import { useAuiState } from "@assistant-ui/store";
2
2
 
3
+ /**
4
+ * @deprecated Use `useAuiState((s) => s.thread.isEmpty)` instead.
5
+ */
3
6
  export const useThreadIsEmpty = (): boolean => {
4
7
  return useAuiState((s) => s.thread.isEmpty);
5
8
  };