@assistant-ui/core 0.3.13 → 0.3.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (396) hide show
  1. package/dist/adapters/speech.d.ts.map +1 -1
  2. package/dist/adapters/speech.js +9 -15
  3. package/dist/adapters/speech.js.map +1 -1
  4. package/dist/adapters/thread-history.d.ts +2 -0
  5. package/dist/adapters/thread-history.d.ts.map +1 -1
  6. package/dist/adapters/voice.d.ts.map +1 -1
  7. package/dist/adapters/voice.js +27 -15
  8. package/dist/adapters/voice.js.map +1 -1
  9. package/dist/index.d.ts +2 -2
  10. package/dist/index.js.map +1 -1
  11. package/dist/internal.d.ts +1 -1
  12. package/dist/internal.js +6 -6
  13. package/dist/model-context/frame/host.d.ts.map +1 -1
  14. package/dist/model-context/frame/host.js +2 -1
  15. package/dist/model-context/frame/host.js.map +1 -1
  16. package/dist/model-context/registry.d.ts.map +1 -1
  17. package/dist/model-context/registry.js +16 -4
  18. package/dist/model-context/registry.js.map +1 -1
  19. package/dist/react/RuntimeAdapter.d.ts +8 -1
  20. package/dist/react/RuntimeAdapter.d.ts.map +1 -1
  21. package/dist/react/RuntimeAdapter.js +23 -18
  22. package/dist/react/RuntimeAdapter.js.map +1 -1
  23. package/dist/react/adapters/LocalStorageThreadListAdapter.d.ts.map +1 -1
  24. package/dist/react/adapters/LocalStorageThreadListAdapter.js +28 -12
  25. package/dist/react/adapters/LocalStorageThreadListAdapter.js.map +1 -1
  26. package/dist/react/client/AdaptedRemoteThread.d.ts +11 -0
  27. package/dist/react/client/AdaptedRemoteThread.d.ts.map +1 -0
  28. package/dist/react/client/AdaptedRemoteThread.js +27 -0
  29. package/dist/react/client/AdaptedRemoteThread.js.map +1 -0
  30. package/dist/react/client/InMemoryThreadList.d.ts +19 -0
  31. package/dist/react/client/InMemoryThreadList.d.ts.map +1 -0
  32. package/dist/react/client/InMemoryThreadList.js +418 -0
  33. package/dist/react/client/InMemoryThreadList.js.map +1 -0
  34. package/dist/react/client/Interactables.d.ts.map +1 -1
  35. package/dist/react/client/Interactables.js +159 -102
  36. package/dist/react/client/Interactables.js.map +1 -1
  37. package/dist/react/client/RemoteThreadList.d.ts +34 -0
  38. package/dist/react/client/RemoteThreadList.d.ts.map +1 -0
  39. package/dist/react/client/RemoteThreadList.js +826 -0
  40. package/dist/react/client/RemoteThreadList.js.map +1 -0
  41. package/dist/react/client/Tools.d.ts.map +1 -1
  42. package/dist/react/client/Tools.js +38 -27
  43. package/dist/react/client/Tools.js.map +1 -1
  44. package/dist/react/index.d.ts +7 -2
  45. package/dist/react/index.js +5 -2
  46. package/dist/react/interactables-legacy/Interactables.d.ts.map +1 -1
  47. package/dist/react/interactables-legacy/Interactables.js +145 -110
  48. package/dist/react/interactables-legacy/Interactables.js.map +1 -1
  49. package/dist/react/primitive-hooks/useActionBarCopy.d.ts.map +1 -1
  50. package/dist/react/primitive-hooks/useActionBarCopy.js +13 -18
  51. package/dist/react/primitive-hooks/useActionBarCopy.js.map +1 -1
  52. package/dist/react/primitive-hooks/useActionBarEdit.d.ts.map +1 -1
  53. package/dist/react/primitive-hooks/useActionBarEdit.js +2 -4
  54. package/dist/react/primitive-hooks/useActionBarEdit.js.map +1 -1
  55. package/dist/react/primitive-hooks/useActionBarReload.d.ts.map +1 -1
  56. package/dist/react/primitive-hooks/useActionBarReload.js +2 -4
  57. package/dist/react/primitive-hooks/useActionBarReload.js.map +1 -1
  58. package/dist/react/primitive-hooks/useBranchPickerNext.d.ts.map +1 -1
  59. package/dist/react/primitive-hooks/useBranchPickerNext.js +2 -6
  60. package/dist/react/primitive-hooks/useBranchPickerNext.js.map +1 -1
  61. package/dist/react/primitive-hooks/useBranchPickerPrevious.d.ts.map +1 -1
  62. package/dist/react/primitive-hooks/useBranchPickerPrevious.js +2 -6
  63. package/dist/react/primitive-hooks/useBranchPickerPrevious.js.map +1 -1
  64. package/dist/react/primitive-hooks/useComposerCancel.d.ts.map +1 -1
  65. package/dist/react/primitive-hooks/useComposerCancel.js +2 -4
  66. package/dist/react/primitive-hooks/useComposerCancel.js.map +1 -1
  67. package/dist/react/primitive-hooks/useComposerSend.d.ts.map +1 -1
  68. package/dist/react/primitive-hooks/useComposerSend.js +2 -4
  69. package/dist/react/primitive-hooks/useComposerSend.js.map +1 -1
  70. package/dist/react/primitive-hooks/useSuggestionTrigger.d.ts.map +1 -1
  71. package/dist/react/primitive-hooks/useSuggestionTrigger.js +6 -2
  72. package/dist/react/primitive-hooks/useSuggestionTrigger.js.map +1 -1
  73. package/dist/react/primitives/message/MessageParts.d.ts +13 -0
  74. package/dist/react/primitives/message/MessageParts.d.ts.map +1 -1
  75. package/dist/react/primitives/message/MessageParts.js.map +1 -1
  76. package/dist/react/primitives/thread/ThreadMessages.d.ts.map +1 -1
  77. package/dist/react/primitives/thread/ThreadMessages.js +1 -1
  78. package/dist/react/primitives/thread/ThreadMessages.js.map +1 -1
  79. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts +22 -10
  80. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts.map +1 -1
  81. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js +109 -71
  82. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js.map +1 -1
  83. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts +8 -2
  84. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts.map +1 -1
  85. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js +40 -13
  86. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js.map +1 -1
  87. package/dist/react/runtimes/RemoteThreadResource.d.ts +30 -0
  88. package/dist/react/runtimes/RemoteThreadResource.d.ts.map +1 -0
  89. package/dist/react/runtimes/RemoteThreadResource.js +134 -0
  90. package/dist/react/runtimes/RemoteThreadResource.js.map +1 -0
  91. package/dist/react/runtimes/RuntimeAdapterProvider.d.ts +3 -10
  92. package/dist/react/runtimes/RuntimeAdapterProvider.d.ts.map +1 -1
  93. package/dist/react/runtimes/RuntimeAdapterProvider.js +3 -6
  94. package/dist/react/runtimes/RuntimeAdapterProvider.js.map +1 -1
  95. package/dist/react/runtimes/assistant-transport/commandQueue.d.ts +17 -0
  96. package/dist/react/runtimes/assistant-transport/commandQueue.d.ts.map +1 -0
  97. package/dist/react/runtimes/assistant-transport/commandQueue.js +55 -0
  98. package/dist/react/runtimes/assistant-transport/commandQueue.js.map +1 -0
  99. package/dist/react/runtimes/assistant-transport/replayBoundaryStream.d.ts +11 -0
  100. package/dist/react/runtimes/assistant-transport/replayBoundaryStream.d.ts.map +1 -0
  101. package/dist/react/runtimes/assistant-transport/replayBoundaryStream.js +165 -0
  102. package/dist/react/runtimes/assistant-transport/replayBoundaryStream.js.map +1 -0
  103. package/dist/react/runtimes/assistant-transport/runManager.d.ts +15 -0
  104. package/dist/react/runtimes/assistant-transport/runManager.d.ts.map +1 -0
  105. package/dist/react/runtimes/assistant-transport/runManager.js +86 -0
  106. package/dist/react/runtimes/assistant-transport/runManager.js.map +1 -0
  107. package/dist/react/runtimes/assistant-transport/types.d.ts +130 -0
  108. package/dist/react/runtimes/assistant-transport/types.d.ts.map +1 -0
  109. package/dist/react/runtimes/assistant-transport/types.js +0 -0
  110. package/dist/react/runtimes/assistant-transport/useAssistantTransportRuntime.d.ts +14 -0
  111. package/dist/react/runtimes/assistant-transport/useAssistantTransportRuntime.d.ts.map +1 -0
  112. package/dist/react/runtimes/assistant-transport/useAssistantTransportRuntime.js +296 -0
  113. package/dist/react/runtimes/assistant-transport/useAssistantTransportRuntime.js.map +1 -0
  114. package/dist/react/runtimes/assistant-transport/useConvertedState.d.ts +7 -0
  115. package/dist/react/runtimes/assistant-transport/useConvertedState.d.ts.map +1 -0
  116. package/dist/react/runtimes/assistant-transport/useConvertedState.js +25 -0
  117. package/dist/react/runtimes/assistant-transport/useConvertedState.js.map +1 -0
  118. package/dist/react/runtimes/assistant-transport/useLatestRef.d.ts +7 -0
  119. package/dist/react/runtimes/assistant-transport/useLatestRef.d.ts.map +1 -0
  120. package/dist/react/runtimes/assistant-transport/useLatestRef.js +27 -0
  121. package/dist/react/runtimes/assistant-transport/useLatestRef.js.map +1 -0
  122. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts.map +1 -1
  123. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js +39 -13
  124. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js.map +1 -1
  125. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.d.ts +2 -1
  126. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.d.ts.map +1 -1
  127. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.js +3 -3
  128. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.js.map +1 -1
  129. package/dist/react/runtimes/cloud/auiV0.d.ts +4 -0
  130. package/dist/react/runtimes/cloud/auiV0.d.ts.map +1 -1
  131. package/dist/react/runtimes/cloud/auiV0.js +7 -0
  132. package/dist/react/runtimes/cloud/auiV0.js.map +1 -1
  133. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.d.ts.map +1 -1
  134. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js +22 -12
  135. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js.map +1 -1
  136. package/dist/react/runtimes/cloud/useCloudThreadListRuntime.d.ts +16 -0
  137. package/dist/react/runtimes/cloud/useCloudThreadListRuntime.d.ts.map +1 -0
  138. package/dist/react/runtimes/cloud/useCloudThreadListRuntime.js +36 -0
  139. package/dist/react/runtimes/cloud/useCloudThreadListRuntime.js.map +1 -0
  140. package/dist/react/runtimes/external-message-converter.js +14 -14
  141. package/dist/react/runtimes/external-message-converter.js.map +1 -1
  142. package/dist/react/runtimes/useExternalStoreRuntime.d.ts.map +1 -1
  143. package/dist/react/runtimes/useExternalStoreRuntime.js +44 -28
  144. package/dist/react/runtimes/useExternalStoreRuntime.js.map +1 -1
  145. package/dist/react/runtimes/useExternalStoreSharedOptions.js.map +1 -1
  146. package/dist/react/runtimes/useLocalRuntime.js +1 -1
  147. package/dist/react/runtimes/useRuntimeAdapters.d.ts +9 -0
  148. package/dist/react/runtimes/useRuntimeAdapters.d.ts.map +1 -0
  149. package/dist/react/runtimes/useRuntimeAdapters.js +20 -0
  150. package/dist/react/runtimes/useRuntimeAdapters.js.map +1 -0
  151. package/dist/runtime/api/composer-runtime.d.ts +5 -0
  152. package/dist/runtime/api/composer-runtime.d.ts.map +1 -1
  153. package/dist/runtime/api/composer-runtime.js.map +1 -1
  154. package/dist/runtime/api/message-runtime.js +1 -1
  155. package/dist/runtime/api/thread-list-runtime.d.ts +1 -0
  156. package/dist/runtime/api/thread-list-runtime.d.ts.map +1 -1
  157. package/dist/runtime/api/thread-list-runtime.js +4 -2
  158. package/dist/runtime/api/thread-list-runtime.js.map +1 -1
  159. package/dist/runtime/api/thread-runtime.d.ts +12 -2
  160. package/dist/runtime/api/thread-runtime.d.ts.map +1 -1
  161. package/dist/runtime/api/thread-runtime.js +8 -2
  162. package/dist/runtime/api/thread-runtime.js.map +1 -1
  163. package/dist/runtime/base/base-composer-runtime-core.d.ts.map +1 -1
  164. package/dist/runtime/base/base-composer-runtime-core.js +8 -7
  165. package/dist/runtime/base/base-composer-runtime-core.js.map +1 -1
  166. package/dist/runtime/base/base-thread-runtime-core.d.ts +1 -0
  167. package/dist/runtime/base/base-thread-runtime-core.d.ts.map +1 -1
  168. package/dist/runtime/base/base-thread-runtime-core.js +3 -3
  169. package/dist/runtime/base/base-thread-runtime-core.js.map +1 -1
  170. package/dist/runtime/base/default-thread-composer-runtime-core.d.ts +0 -1
  171. package/dist/runtime/base/default-thread-composer-runtime-core.d.ts.map +1 -1
  172. package/dist/runtime/base/default-thread-composer-runtime-core.js +10 -4
  173. package/dist/runtime/base/default-thread-composer-runtime-core.js.map +1 -1
  174. package/dist/runtime/interfaces/thread-runtime-core.d.ts +6 -0
  175. package/dist/runtime/interfaces/thread-runtime-core.d.ts.map +1 -1
  176. package/dist/runtime/internal.js +5 -5
  177. package/dist/runtime/queue/message-queue.d.ts.map +1 -1
  178. package/dist/runtime/queue/message-queue.js +2 -1
  179. package/dist/runtime/queue/message-queue.js.map +1 -1
  180. package/dist/runtime/utils/thread-runtime-lifecycle.d.ts +8 -0
  181. package/dist/runtime/utils/thread-runtime-lifecycle.d.ts.map +1 -0
  182. package/dist/runtime/utils/thread-runtime-lifecycle.js +11 -0
  183. package/dist/runtime/utils/thread-runtime-lifecycle.js.map +1 -0
  184. package/dist/runtimes/external-store/external-store-shared-options.js.map +1 -1
  185. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.d.ts.map +1 -1
  186. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js +4 -1
  187. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js.map +1 -1
  188. package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts +8 -0
  189. package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts.map +1 -1
  190. package/dist/runtimes/external-store/external-store-thread-runtime-core.js +35 -13
  191. package/dist/runtimes/external-store/external-store-thread-runtime-core.js.map +1 -1
  192. package/dist/runtimes/internal.d.ts +1 -1
  193. package/dist/runtimes/local/local-thread-runtime-core.d.ts +3 -0
  194. package/dist/runtimes/local/local-thread-runtime-core.d.ts.map +1 -1
  195. package/dist/runtimes/local/local-thread-runtime-core.js +53 -13
  196. package/dist/runtimes/local/local-thread-runtime-core.js.map +1 -1
  197. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.d.ts +1 -0
  198. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.d.ts.map +1 -1
  199. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.js +3 -0
  200. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.js.map +1 -1
  201. package/dist/runtimes/remote-thread-list/empty-thread-core.js +3 -0
  202. package/dist/runtimes/remote-thread-list/empty-thread-core.js.map +1 -1
  203. package/dist/runtimes/remote-thread-list/types.d.ts +29 -1
  204. package/dist/runtimes/remote-thread-list/types.d.ts.map +1 -1
  205. package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts +1 -12
  206. package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts.map +1 -1
  207. package/dist/runtimes/tool-invocations/ToolInvocationTracker.js +67 -38
  208. package/dist/runtimes/tool-invocations/ToolInvocationTracker.js.map +1 -1
  209. package/dist/store/clients/suggestions.js +2 -2
  210. package/dist/store/clients/suggestions.js.map +1 -1
  211. package/dist/store/clients/thread-selection-events.d.ts +10 -0
  212. package/dist/store/clients/thread-selection-events.d.ts.map +1 -0
  213. package/dist/store/clients/thread-selection-events.js +40 -0
  214. package/dist/store/clients/thread-selection-events.js.map +1 -0
  215. package/dist/store/env.d.ts +5 -0
  216. package/dist/store/env.d.ts.map +1 -0
  217. package/dist/store/env.js +12 -0
  218. package/dist/store/env.js.map +1 -0
  219. package/dist/store/index.d.ts +5 -3
  220. package/dist/store/index.js +4 -2
  221. package/dist/store/internal.d.ts +4 -1
  222. package/dist/store/internal.js +4 -1
  223. package/dist/store/primitive-predicates.d.ts +19 -0
  224. package/dist/store/primitive-predicates.d.ts.map +1 -0
  225. package/dist/store/primitive-predicates.js +19 -0
  226. package/dist/store/primitive-predicates.js.map +1 -0
  227. package/dist/store/runtime-clients/attachment-runtime-client.d.ts.map +1 -1
  228. package/dist/store/runtime-clients/attachment-runtime-client.js +18 -11
  229. package/dist/store/runtime-clients/attachment-runtime-client.js.map +1 -1
  230. package/dist/store/runtime-clients/handle-runtime-action.d.ts +5 -0
  231. package/dist/store/runtime-clients/handle-runtime-action.d.ts.map +1 -0
  232. package/dist/store/runtime-clients/handle-runtime-action.js +12 -0
  233. package/dist/store/runtime-clients/handle-runtime-action.js.map +1 -0
  234. package/dist/store/runtime-clients/handle-thread-list-action.d.ts +5 -0
  235. package/dist/store/runtime-clients/handle-thread-list-action.d.ts.map +1 -0
  236. package/dist/store/runtime-clients/handle-thread-list-action.js +7 -0
  237. package/dist/store/runtime-clients/handle-thread-list-action.js.map +1 -0
  238. package/dist/store/runtime-clients/thread-list-item-runtime-client.d.ts.map +1 -1
  239. package/dist/store/runtime-clients/thread-list-item-runtime-client.js +62 -29
  240. package/dist/store/runtime-clients/thread-list-item-runtime-client.js.map +1 -1
  241. package/dist/store/runtime-clients/thread-list-runtime-client.d.ts.map +1 -1
  242. package/dist/store/runtime-clients/thread-list-runtime-client.js +5 -6
  243. package/dist/store/runtime-clients/thread-list-runtime-client.js.map +1 -1
  244. package/dist/store/scopes/composer.d.ts +9 -4
  245. package/dist/store/scopes/composer.d.ts.map +1 -1
  246. package/dist/store/scopes/thread-list-item.d.ts +7 -6
  247. package/dist/store/scopes/thread-list-item.d.ts.map +1 -1
  248. package/dist/store/scopes/thread.d.ts +8 -7
  249. package/dist/store/scopes/thread.d.ts.map +1 -1
  250. package/dist/store/scopes/threads.d.ts +17 -1
  251. package/dist/store/scopes/threads.d.ts.map +1 -1
  252. package/dist/subscribable/subscribable.d.ts +2 -1
  253. package/dist/subscribable/subscribable.d.ts.map +1 -1
  254. package/dist/subscribable/subscribable.js +23 -18
  255. package/dist/subscribable/subscribable.js.map +1 -1
  256. package/dist/utils/composite-context-provider.d.ts +1 -0
  257. package/dist/utils/composite-context-provider.d.ts.map +1 -1
  258. package/dist/utils/composite-context-provider.js +25 -9
  259. package/dist/utils/composite-context-provider.js.map +1 -1
  260. package/dist/utils/notify-event-listeners.d.ts +2 -2
  261. package/dist/utils/notify-event-listeners.d.ts.map +1 -1
  262. package/dist/utils/notify-event-listeners.js +2 -2
  263. package/dist/utils/notify-event-listeners.js.map +1 -1
  264. package/package.json +7 -7
  265. package/src/adapters/speech.test.ts +118 -1
  266. package/src/adapters/speech.ts +21 -22
  267. package/src/adapters/thread-history.ts +2 -0
  268. package/src/adapters/voice.test.ts +69 -0
  269. package/src/adapters/voice.ts +27 -27
  270. package/src/index.ts +1 -0
  271. package/src/model-context/frame/host.test.ts +23 -0
  272. package/src/model-context/frame/host.ts +2 -1
  273. package/src/model-context/registry.test.ts +131 -0
  274. package/src/model-context/registry.ts +16 -6
  275. package/src/react/RuntimeAdapter.test.ts +2 -0
  276. package/src/react/RuntimeAdapter.ts +20 -8
  277. package/src/react/adapters/LocalStorageThreadListAdapter.tsx +34 -17
  278. package/src/react/client/AdaptedRemoteThread.ts +41 -0
  279. package/src/react/client/InMemoryThreadList.test.tsx +148 -0
  280. package/src/react/client/InMemoryThreadList.ts +290 -0
  281. package/src/react/client/Interactables.test.ts +326 -2
  282. package/src/react/client/Interactables.ts +227 -110
  283. package/src/react/client/RemoteThreadList.test.ts +1026 -0
  284. package/src/react/client/RemoteThreadList.ts +1067 -0
  285. package/src/react/client/Tools.ts +36 -29
  286. package/src/react/index.ts +13 -0
  287. package/src/react/interactables-legacy/Interactables.test.ts +317 -0
  288. package/src/react/interactables-legacy/Interactables.ts +204 -128
  289. package/src/react/primitive-hooks/useActionBarCopy.ts +2 -7
  290. package/src/react/primitive-hooks/useActionBarEdit.ts +2 -1
  291. package/src/react/primitive-hooks/useActionBarReload.ts +2 -6
  292. package/src/react/primitive-hooks/useBranchPickerNext.ts +2 -7
  293. package/src/react/primitive-hooks/useBranchPickerPrevious.ts +2 -7
  294. package/src/react/primitive-hooks/useComposerCancel.ts +2 -1
  295. package/src/react/primitive-hooks/useComposerSend.ts +2 -5
  296. package/src/react/primitive-hooks/useSuggestionTrigger.test.ts +11 -0
  297. package/src/react/primitive-hooks/useSuggestionTrigger.ts +4 -5
  298. package/src/react/primitives/message/MessageParts.tsx +0 -1
  299. package/src/react/primitives/thread/ThreadMessages.tsx +2 -1
  300. package/src/react/runtimes/RemoteThreadListHookInstanceManager.retry.test.tsx +116 -0
  301. package/src/react/runtimes/RemoteThreadListHookInstanceManager.running.test.tsx +1 -1
  302. package/src/react/runtimes/RemoteThreadListHookInstanceManager.test.tsx +57 -6
  303. package/src/react/runtimes/RemoteThreadListHookInstanceManager.title.test.tsx +272 -0
  304. package/src/react/runtimes/RemoteThreadListHookInstanceManager.tsx +159 -124
  305. package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.tsx +59 -20
  306. package/src/react/runtimes/RemoteThreadResource.test.ts +141 -0
  307. package/src/react/runtimes/RemoteThreadResource.ts +231 -0
  308. package/src/react/runtimes/RuntimeAdapterProvider.tsx +8 -20
  309. package/src/react/runtimes/assistant-transport/commandQueue.ts +68 -0
  310. package/src/react/runtimes/assistant-transport/replayBoundaryStream.test.ts +455 -0
  311. package/src/react/runtimes/assistant-transport/replayBoundaryStream.ts +172 -0
  312. package/src/react/runtimes/assistant-transport/runManager.ts +124 -0
  313. package/src/react/runtimes/assistant-transport/transport-delivery.test.tsx +79 -0
  314. package/src/react/runtimes/assistant-transport/transport-parentid.test.tsx +97 -0
  315. package/src/react/runtimes/assistant-transport/transport-scheduling.test.ts +414 -0
  316. package/src/react/runtimes/assistant-transport/types.ts +170 -0
  317. package/src/react/runtimes/assistant-transport/useAssistantTransport.spec.md +141 -0
  318. package/src/react/runtimes/assistant-transport/useAssistantTransportRuntime.test.tsx +625 -0
  319. package/src/react/runtimes/assistant-transport/useAssistantTransportRuntime.ts +481 -0
  320. package/src/react/runtimes/assistant-transport/useConvertedState.ts +20 -0
  321. package/src/react/runtimes/assistant-transport/useLatestRef.ts +9 -0
  322. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.test.tsx +131 -6
  323. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.ts +61 -15
  324. package/src/react/runtimes/cloud/CloudFileAttachmentAdapter.ts +6 -4
  325. package/src/react/runtimes/cloud/auiV0.ts +17 -1
  326. package/src/react/runtimes/cloud/useCloudThreadListAdapter.tsx +36 -21
  327. package/src/react/runtimes/cloud/useCloudThreadListRuntime.test.tsx +56 -0
  328. package/src/react/runtimes/cloud/useCloudThreadListRuntime.ts +31 -0
  329. package/src/react/runtimes/external-message-converter.test.ts +143 -0
  330. package/src/react/runtimes/external-message-converter.ts +41 -41
  331. package/src/react/runtimes/remote-thread-hook-on-tap.test.ts +58 -0
  332. package/src/react/runtimes/useExternalStoreRuntime.lifecycle.test.tsx +83 -0
  333. package/src/react/runtimes/useExternalStoreRuntime.suggestions.test.tsx +13 -3
  334. package/src/react/runtimes/useExternalStoreRuntime.ts +7 -0
  335. package/src/react/runtimes/useExternalStoreSharedOptions.ts +3 -1
  336. package/src/react/runtimes/useLocalRuntime.test.tsx +130 -4
  337. package/src/react/runtimes/useRuntimeAdapters.test.tsx +62 -0
  338. package/src/react/runtimes/useRuntimeAdapters.ts +28 -0
  339. package/src/runtime/api/composer-runtime.ts +5 -0
  340. package/src/runtime/api/thread-list-runtime.ts +3 -1
  341. package/src/runtime/api/thread-runtime.ts +20 -2
  342. package/src/runtime/base/base-composer-runtime-core.ts +6 -5
  343. package/src/runtime/base/base-thread-runtime-core.test.ts +191 -0
  344. package/src/runtime/base/base-thread-runtime-core.ts +11 -2
  345. package/src/runtime/base/default-thread-composer-runtime-core.ts +12 -4
  346. package/src/runtime/interfaces/thread-runtime-core.ts +6 -0
  347. package/src/runtime/queue/message-queue.ts +2 -1
  348. package/src/runtime/utils/thread-runtime-lifecycle.ts +18 -0
  349. package/src/runtimes/external-store/external-store-shared-options.ts +3 -1
  350. package/src/runtimes/external-store/external-store-thread-list-runtime-core.ts +4 -1
  351. package/src/runtimes/external-store/external-store-thread-runtime-core.ts +99 -34
  352. package/src/runtimes/local/local-thread-runtime-core.test.ts +373 -4
  353. package/src/runtimes/local/local-thread-runtime-core.ts +79 -14
  354. package/src/runtimes/readonly/ReadonlyThreadRuntimeCore.ts +4 -0
  355. package/src/runtimes/remote-thread-list/empty-thread-core.ts +4 -0
  356. package/src/runtimes/remote-thread-list/types.ts +30 -0
  357. package/src/runtimes/tool-invocations/EDGE_CASES.md +17 -6
  358. package/src/runtimes/tool-invocations/ToolInvocationTracker.test.ts +243 -0
  359. package/src/runtimes/tool-invocations/ToolInvocationTracker.ts +127 -61
  360. package/src/store/clients/model-context-client.test.ts +16 -8
  361. package/src/store/clients/suggestions.ts +2 -2
  362. package/src/store/clients/thread-selection-events.ts +21 -0
  363. package/src/store/env.ts +11 -0
  364. package/src/store/index.ts +14 -1
  365. package/src/store/internal.ts +13 -0
  366. package/src/store/primitive-predicates.test.ts +184 -0
  367. package/src/store/primitive-predicates.ts +43 -0
  368. package/src/store/runtime-clients/attachment-runtime-client.test.ts +41 -0
  369. package/src/store/runtime-clients/attachment-runtime-client.ts +2 -1
  370. package/src/store/runtime-clients/handle-runtime-action.ts +11 -0
  371. package/src/store/runtime-clients/handle-thread-list-action.test.ts +69 -0
  372. package/src/store/runtime-clients/handle-thread-list-action.ts +6 -0
  373. package/src/store/runtime-clients/thread-list-item-runtime-client.ts +15 -7
  374. package/src/store/runtime-clients/thread-list-runtime-client.ts +9 -6
  375. package/src/store/scopes/composer.ts +9 -4
  376. package/src/store/scopes/thread-list-item.ts +7 -6
  377. package/src/store/scopes/thread.ts +8 -7
  378. package/src/store/scopes/threads.ts +14 -0
  379. package/src/subscribable/subscribable.test.ts +77 -1
  380. package/src/subscribable/subscribable.ts +38 -23
  381. package/src/tests/RemoteThreadListThreadListRuntimeCore-switchToThread-unarchive.test.ts +25 -0
  382. package/src/tests/auiV0Encode.test.ts +66 -0
  383. package/src/tests/base-composer-runtime-core-send.test.ts +30 -0
  384. package/src/tests/base-composer-runtime-core.test.ts +28 -0
  385. package/src/tests/composer-can-cancel.test.ts +101 -0
  386. package/src/tests/external-store-thread-list-runtime-core.test.ts +101 -0
  387. package/src/tests/external-store-thread-runtime-core-adapter.test.ts +191 -1
  388. package/src/tests/external-store-thread-runtime-core.test.ts +124 -0
  389. package/src/tests/interactables-toolui-migration.test.tsx +66 -0
  390. package/src/tests/message-queue.test.ts +28 -0
  391. package/src/tests/session-reset-notification.test.ts +145 -0
  392. package/src/tests/thread-switch-events.test.tsx +99 -1
  393. package/src/tests/tools-scope-migration.test.tsx +58 -0
  394. package/src/utils/composite-context-provider.test.ts +139 -0
  395. package/src/utils/composite-context-provider.ts +26 -8
  396. package/src/utils/notify-event-listeners.ts +10 -5
@@ -0,0 +1,141 @@
1
+ import { afterEach, describe, expect, it, vi } from "vitest";
2
+ import { AssistantRuntimeImpl } from "../../runtime/api/assistant-runtime";
3
+ import type { ThreadListItemRuntime } from "../../runtime/api/thread-list-item-runtime";
4
+ import { LocalRuntimeCore } from "../../runtimes/local/local-runtime-core";
5
+ import type { AppendMessage } from "../../types/message";
6
+ import { subscribeToTitleGeneration } from "./RemoteThreadResource";
7
+
8
+ afterEach(() => {
9
+ vi.restoreAllMocks();
10
+ });
11
+
12
+ describe("subscribeToTitleGeneration", () => {
13
+ it("reports title generation failures", async () => {
14
+ const error = new Error("title unavailable");
15
+ const core = new LocalRuntimeCore(
16
+ {
17
+ adapters: {
18
+ chatModel: {
19
+ async run() {
20
+ return { content: [{ type: "text", text: "done" }] };
21
+ },
22
+ },
23
+ },
24
+ unstable_humanToolNames: [],
25
+ },
26
+ undefined,
27
+ );
28
+ const runtime = new AssistantRuntimeImpl(core);
29
+ const itemRuntime = {
30
+ generateTitle: vi.fn(async () => {
31
+ throw error;
32
+ }),
33
+ } as unknown as ThreadListItemRuntime;
34
+ const consoleError = vi
35
+ .spyOn(console, "error")
36
+ .mockImplementation(() => undefined);
37
+
38
+ subscribeToTitleGeneration(runtime.thread, itemRuntime);
39
+ const message: AppendMessage = {
40
+ parentId: null,
41
+ sourceId: null,
42
+ runConfig: {},
43
+ role: "user",
44
+ content: [{ type: "text", text: "hello" }],
45
+ attachments: [],
46
+ metadata: { custom: {} },
47
+ createdAt: new Date(),
48
+ };
49
+
50
+ await expect(
51
+ core.threads.getMainThreadRuntimeCore().append(message),
52
+ ).resolves.toBeUndefined();
53
+
54
+ await vi.waitFor(() => {
55
+ expect(itemRuntime.generateTitle).toHaveBeenCalledOnce();
56
+ expect(consoleError).toHaveBeenCalledWith(
57
+ "[assistant-ui] Thread title generation failed",
58
+ error,
59
+ );
60
+ });
61
+ });
62
+
63
+ it("waits for the first message before generating", async () => {
64
+ const core = new LocalRuntimeCore(
65
+ {
66
+ adapters: {
67
+ chatModel: {
68
+ async run() {
69
+ return { content: [{ type: "text", text: "done" }] };
70
+ },
71
+ },
72
+ },
73
+ unstable_humanToolNames: [],
74
+ },
75
+ undefined,
76
+ );
77
+ const runtime = new AssistantRuntimeImpl(core);
78
+ const itemRuntime = {
79
+ generateTitle: vi.fn(async () => {}),
80
+ } as unknown as ThreadListItemRuntime;
81
+
82
+ subscribeToTitleGeneration(runtime.thread, itemRuntime);
83
+ expect(itemRuntime.generateTitle).not.toHaveBeenCalled();
84
+
85
+ const message: AppendMessage = {
86
+ parentId: null,
87
+ sourceId: null,
88
+ runConfig: {},
89
+ role: "user",
90
+ content: [{ type: "text", text: "hello" }],
91
+ attachments: [],
92
+ metadata: { custom: {} },
93
+ createdAt: new Date(),
94
+ startRun: false,
95
+ };
96
+ await core.threads.getMainThreadRuntimeCore().append(message);
97
+
98
+ await vi.waitFor(() => {
99
+ expect(itemRuntime.generateTitle).toHaveBeenCalledOnce();
100
+ });
101
+ });
102
+
103
+ it("generates immediately when a message already exists", async () => {
104
+ const core = new LocalRuntimeCore(
105
+ {
106
+ adapters: {
107
+ chatModel: {
108
+ async run() {
109
+ return { content: [{ type: "text", text: "done" }] };
110
+ },
111
+ },
112
+ },
113
+ unstable_humanToolNames: [],
114
+ },
115
+ undefined,
116
+ );
117
+ const runtime = new AssistantRuntimeImpl(core);
118
+ const itemRuntime = {
119
+ generateTitle: vi.fn(async () => {}),
120
+ } as unknown as ThreadListItemRuntime;
121
+
122
+ const message: AppendMessage = {
123
+ parentId: null,
124
+ sourceId: null,
125
+ runConfig: {},
126
+ role: "user",
127
+ content: [{ type: "text", text: "hello" }],
128
+ attachments: [],
129
+ metadata: { custom: {} },
130
+ createdAt: new Date(),
131
+ startRun: false,
132
+ };
133
+ await core.threads.getMainThreadRuntimeCore().append(message);
134
+
135
+ subscribeToTitleGeneration(runtime.thread, itemRuntime);
136
+
137
+ await vi.waitFor(() => {
138
+ expect(itemRuntime.generateTitle).toHaveBeenCalledOnce();
139
+ });
140
+ });
141
+ });
@@ -0,0 +1,231 @@
1
+ import { useCallback, useEffect, useEffectEvent, useMemo, useRef } from "react";
2
+ import { resource } from "@assistant-ui/tap";
3
+ import {
4
+ useAssistantContextProvider,
5
+ useConfiguredAui,
6
+ } from "@assistant-ui/store/client";
7
+ import { ThreadListItemClient } from "../../store/internal";
8
+ import type { AssistantRuntime } from "../../runtime/api/assistant-runtime";
9
+ import type { ThreadListRuntimeCore } from "../../runtime/interfaces/thread-list-runtime-core";
10
+ import type { ThreadRuntimeCore } from "../../runtime/interfaces/thread-runtime-core";
11
+ import type { ThreadRuntimeImpl } from "../../runtime/api/thread-runtime";
12
+ import {
13
+ ThreadListItemRuntimeImpl,
14
+ type ThreadListItemRuntime,
15
+ } from "../../runtime/api/thread-list-item-runtime";
16
+ import {
17
+ SKIP_UPDATE,
18
+ ShallowMemoizeSubject,
19
+ } from "../../subscribable/subscribable";
20
+ import {
21
+ useRuntimeAdaptersProvider,
22
+ type RuntimeAdapters,
23
+ } from "./RuntimeAdapterProvider";
24
+
25
+ export type RemoteThreadListHook = () => AssistantRuntime;
26
+
27
+ export type RemoteThreadResourceProps = {
28
+ threadId: string;
29
+ generation: number;
30
+ parentList: ThreadListRuntimeCore;
31
+ runtimeHook: RemoteThreadListHook;
32
+ parentClient: Parameters<typeof useConfiguredAui>[0];
33
+ adapters: RuntimeAdapters | null;
34
+ publish: (
35
+ threadId: string,
36
+ runtime: ThreadRuntimeCore,
37
+ generation: number,
38
+ ) => void;
39
+ };
40
+
41
+ export const isTitleSourceMessage = (message: {
42
+ status?: { type: string } | undefined;
43
+ }) => message.status?.type !== "running";
44
+
45
+ export const subscribeToTitleGeneration = (
46
+ threadRuntime: AssistantRuntime["thread"],
47
+ itemRuntime: ThreadListItemRuntime,
48
+ ) => {
49
+ const generate = () =>
50
+ void itemRuntime.generateTitle().catch((error: unknown) => {
51
+ console.error("[assistant-ui] Thread title generation failed", error);
52
+ });
53
+
54
+ const hasTitleSource = () =>
55
+ threadRuntime.getState().messages.some(isTitleSourceMessage);
56
+
57
+ if (hasTitleSource()) {
58
+ generate();
59
+ return () => {};
60
+ }
61
+
62
+ const unsubscribe = threadRuntime.subscribe(() => {
63
+ if (!hasTitleSource()) return;
64
+ unsubscribe();
65
+ generate();
66
+ });
67
+ return unsubscribe;
68
+ };
69
+
70
+ const useRemoteThreadBinder = ({
71
+ threadId,
72
+ generation,
73
+ runtimeHook,
74
+ publish,
75
+ itemRuntime,
76
+ }: {
77
+ threadId: string;
78
+ generation: number;
79
+ runtimeHook: RemoteThreadListHook;
80
+ publish: RemoteThreadResourceProps["publish"];
81
+ itemRuntime: ThreadListItemRuntime;
82
+ }) => {
83
+ const runtime = runtimeHook();
84
+ const threadBinding = (runtime?.thread as ThreadRuntimeImpl | undefined)
85
+ ?.__internal_threadBinding;
86
+
87
+ const updateRuntime = useCallback(() => {
88
+ if (!threadBinding) return;
89
+ publish(threadId, threadBinding.getState(), generation);
90
+ }, [threadId, generation, threadBinding, publish]);
91
+
92
+ const isMounted = useRef(false);
93
+ if (!isMounted.current) {
94
+ updateRuntime();
95
+ }
96
+
97
+ useEffect(() => {
98
+ if (!threadBinding) return undefined;
99
+ isMounted.current = true;
100
+ updateRuntime();
101
+ return threadBinding.outerSubscribe(updateRuntime);
102
+ }, [threadBinding, updateRuntime]);
103
+
104
+ const initPromiseRef = useRef<Promise<unknown> | undefined>(undefined);
105
+ const hasInitializedRef = useRef(false);
106
+ const titleDisposeRef = useRef<(() => void) | undefined>(undefined);
107
+ const titleAliveRef = useRef(false);
108
+
109
+ const handleInitialize = useEffectEvent(() => {
110
+ if (hasInitializedRef.current) return;
111
+
112
+ const state = itemRuntime.getState();
113
+ if (state.status !== "new") return;
114
+ hasInitializedRef.current = true;
115
+
116
+ const initPromise = itemRuntime.initialize();
117
+ initPromiseRef.current = initPromise;
118
+
119
+ // The title needs the thread to exist and its first message, so it arms
120
+ // when initialization resolves rather than at the first runEnd; waiting
121
+ // for the run would leave the thread on "New Chat" for the whole
122
+ // response, and forever when the run never completes.
123
+ void initPromise.then(
124
+ () => {
125
+ if (!titleAliveRef.current) return;
126
+ titleDisposeRef.current?.();
127
+ titleDisposeRef.current = subscribeToTitleGeneration(
128
+ runtime.thread,
129
+ itemRuntime,
130
+ );
131
+ },
132
+ () => {
133
+ if (initPromiseRef.current === initPromise) {
134
+ initPromiseRef.current = undefined;
135
+ hasInitializedRef.current = false;
136
+ }
137
+ },
138
+ );
139
+ });
140
+
141
+ const getInitializePromise = useEffectEvent(() => {
142
+ handleInitialize();
143
+ return initPromiseRef.current;
144
+ });
145
+
146
+ useEffect(() => {
147
+ if (!threadBinding) return;
148
+ const runtimeCore = threadBinding.getState();
149
+ const setGetInitializePromise = (runtimeCore as Record<string, unknown>)
150
+ .__internal_setGetInitializePromise;
151
+ if (typeof setGetInitializePromise === "function") {
152
+ setGetInitializePromise.call(runtimeCore, getInitializePromise);
153
+ }
154
+ }, [threadBinding]);
155
+ useEffect(() => {
156
+ if (!runtime?.threads?.main) return undefined;
157
+ hasInitializedRef.current = false;
158
+ titleAliveRef.current = true;
159
+ const unsubscribe = runtime.threads.main.unstable_on(
160
+ "initialize",
161
+ handleInitialize,
162
+ );
163
+ return () => {
164
+ titleAliveRef.current = false;
165
+ unsubscribe();
166
+ titleDisposeRef.current?.();
167
+ titleDisposeRef.current = undefined;
168
+ };
169
+ }, [runtime]);
170
+
171
+ return runtime;
172
+ };
173
+
174
+ const useRemoteThreadResource = ({
175
+ threadId,
176
+ generation,
177
+ parentList,
178
+ runtimeHook,
179
+ parentClient,
180
+ adapters,
181
+ publish,
182
+ }: RemoteThreadResourceProps) => {
183
+ const itemRuntime = useMemo(
184
+ () =>
185
+ new ThreadListItemRuntimeImpl(
186
+ new ShallowMemoizeSubject({
187
+ path: {
188
+ ref: `threadItems[threadId=${threadId}]`,
189
+ threadSelector: { type: "threadId", threadId },
190
+ },
191
+ getState: () => {
192
+ const data = parentList.getItemById(threadId);
193
+ if (!data) return SKIP_UPDATE;
194
+ return {
195
+ id: data.id,
196
+ remoteId: data.remoteId,
197
+ externalId: data.externalId,
198
+ title: data.title,
199
+ lastMessageAt: data.lastMessageAt,
200
+ custom: data.custom,
201
+ status: data.status,
202
+ isMain: data.id === parentList.mainThreadId,
203
+ isRunning:
204
+ parentList.unstable_isThreadRunning?.(data.id) ?? false,
205
+ };
206
+ },
207
+ subscribe: (callback) => parentList.subscribe(callback),
208
+ }),
209
+ parentList,
210
+ ),
211
+ [parentList, threadId],
212
+ );
213
+
214
+ const { client } = useConfiguredAui(parentClient, {
215
+ threadListItem: ThreadListItemClient({ runtime: itemRuntime }),
216
+ });
217
+
218
+ return useAssistantContextProvider(client, function useThreadClient() {
219
+ return useRuntimeAdaptersProvider(adapters, function useBoundRuntime() {
220
+ return useRemoteThreadBinder({
221
+ threadId,
222
+ generation,
223
+ runtimeHook,
224
+ publish,
225
+ itemRuntime,
226
+ });
227
+ });
228
+ });
229
+ };
230
+
231
+ export const RemoteThreadResource = resource(useRemoteThreadResource);
@@ -1,21 +1,13 @@
1
+ import { type FC, type ReactNode, useContext, useMemo } from "react";
2
+ import type { RuntimeAdapters } from "../../runtimes/remote-thread-list/types";
1
3
  import {
2
- createContext,
3
- type FC,
4
- type ReactNode,
5
- useContext,
6
- useMemo,
7
- } from "react";
8
- import type { ThreadHistoryAdapter } from "../../adapters/thread-history";
9
- import type { AttachmentAdapter } from "../../adapters/attachment";
10
- import type { ModelContextProvider } from "../../model-context/types";
4
+ RuntimeAdaptersContext,
5
+ useRuntimeAdapters,
6
+ useRuntimeAdaptersProvider,
7
+ } from "./useRuntimeAdapters";
11
8
 
12
- export type RuntimeAdapters = {
13
- modelContext?: ModelContextProvider | undefined;
14
- history?: ThreadHistoryAdapter | undefined;
15
- attachments?: AttachmentAdapter | undefined;
16
- };
17
-
18
- const RuntimeAdaptersContext = createContext<RuntimeAdapters | null>(null);
9
+ export type { RuntimeAdapters };
10
+ export { useRuntimeAdapters, useRuntimeAdaptersProvider };
19
11
 
20
12
  export namespace RuntimeAdapterProvider {
21
13
  export type Props = {
@@ -39,7 +31,3 @@ export const RuntimeAdapterProvider: FC<RuntimeAdapterProvider.Props> = ({
39
31
  </RuntimeAdaptersContext.Provider>
40
32
  );
41
33
  };
42
-
43
- export const useRuntimeAdapters = () => {
44
- return useContext(RuntimeAdaptersContext);
45
- };
@@ -0,0 +1,68 @@
1
+ import { useState, useCallback, useRef, useEffect } from "react";
2
+ import type {
3
+ AssistantTransportCommand,
4
+ CommandQueueState,
5
+ QueuedCommand,
6
+ } from "./types";
7
+
8
+ export const createInitialQueueState = (): CommandQueueState => ({
9
+ queued: [],
10
+ inTransit: [],
11
+ });
12
+
13
+ export const useCommandQueue = (opts: { onQueue: () => void }) => {
14
+ const onQueueRef = useRef(opts.onQueue);
15
+ useEffect(() => {
16
+ onQueueRef.current = opts.onQueue;
17
+ });
18
+
19
+ const [, rerender] = useState(0);
20
+ const queueStateRef = useRef<CommandQueueState>(createInitialQueueState());
21
+
22
+ const enqueue = (
23
+ command: AssistantTransportCommand,
24
+ options?: { schedule?: boolean },
25
+ ) => {
26
+ queueStateRef.current = {
27
+ queued: [...queueStateRef.current.queued, command],
28
+ inTransit: queueStateRef.current.inTransit,
29
+ };
30
+ rerender((prev) => prev + 1);
31
+
32
+ if (options?.schedule !== false) onQueueRef.current();
33
+ };
34
+
35
+ const flush = (): QueuedCommand[] => {
36
+ if (queueStateRef.current.queued.length === 0) return [];
37
+
38
+ const queued = queueStateRef.current.queued;
39
+ queueStateRef.current = {
40
+ queued: [],
41
+ inTransit: [...queueStateRef.current.inTransit, ...queued],
42
+ };
43
+ rerender((prev) => prev + 1);
44
+
45
+ return queued;
46
+ };
47
+
48
+ const markDelivered = () => {
49
+ queueStateRef.current = { ...queueStateRef.current, inTransit: [] };
50
+ rerender((prev) => prev + 1);
51
+ };
52
+
53
+ const reset = useCallback(() => {
54
+ queueStateRef.current = createInitialQueueState();
55
+ rerender((prev) => prev + 1);
56
+ }, []);
57
+
58
+ return {
59
+ // live getter — callbacks firing between renders must not see a stale snapshot
60
+ get state() {
61
+ return queueStateRef.current;
62
+ },
63
+ enqueue,
64
+ flush,
65
+ markDelivered,
66
+ reset,
67
+ };
68
+ };