@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
@@ -0,0 +1,1136 @@
1
+ import {
2
+ useCallback,
3
+ useEffect,
4
+ useMemo,
5
+ useState,
6
+ useSyncExternalStore,
7
+ } from "react";
8
+ import { resource, withKey } from "@assistant-ui/tap";
9
+ import type { ClientOutput } from "@assistant-ui/store";
10
+ import {
11
+ attachTransformScopes,
12
+ useClientLookup,
13
+ useClientResource,
14
+ } from "@assistant-ui/store/client";
15
+ import { isDevelopment, useThreadSelectionEvents } from "../../store/internal";
16
+ import { generateId } from "../../utils/id";
17
+ import { OptimisticState } from "../../runtimes/remote-thread-list/optimistic-state";
18
+ import {
19
+ classifyThreads,
20
+ createThreadMappingId,
21
+ getThreadData,
22
+ normalizeCursor,
23
+ updateStatusReducer,
24
+ type RemoteThreadData,
25
+ type RemoteThreadState,
26
+ } from "../../runtimes/remote-thread-list/remote-thread-state";
27
+ import type {
28
+ RemoteThreadInitializeResponse,
29
+ RemoteThreadListAdapter,
30
+ } from "../../runtimes/remote-thread-list/types";
31
+ import { ThreadListAdapterChangedError } from "../../runtimes/remote-thread-list/adapter-changed";
32
+ import type { ThreadMessage } from "../../types/message";
33
+ import { AssistantMessageStream } from "assistant-stream";
34
+ import { handleThreadListAction } from "../../store/runtime-clients/handle-thread-list-action";
35
+ import {
36
+ inMemoryThreadListTransformScopes,
37
+ type InMemoryThreadListProps,
38
+ } from "./InMemoryThreadList";
39
+ import { AdaptedRemoteThread } from "./AdaptedRemoteThread";
40
+
41
+ const RESOLVED_PROMISE = Promise.resolve();
42
+
43
+ const EMPTY_LIST: RemoteThreadState = {
44
+ isLoading: true,
45
+ isLoadingMore: false,
46
+ cursor: undefined,
47
+ newThreadId: undefined,
48
+ threadIds: [],
49
+ archivedThreadIds: [],
50
+ threadIdMap: {},
51
+ threadData: {},
52
+ };
53
+
54
+ export type RemoteThreadListProps = {
55
+ /**
56
+ * Swapping this to a different backing store does not reload the list. Call `reload()` after a genuine swap. A recreated object for the same store is a no-op. `reload()` after a different adapter instance resets selection and cached records before loading.
57
+ */
58
+ adapter: RemoteThreadListAdapter;
59
+ /**
60
+ * Factory for the visible thread. Per-thread history reload requires a
61
+ * resource keyed by thread id (`withKey(id, thread(...))`). An unkeyed
62
+ * factory keeps one instance across switches, so a mount-once history
63
+ * loader will not fetch the next thread.
64
+ */
65
+ thread: InMemoryThreadListProps["thread"];
66
+ threadId?: string | undefined;
67
+ onThreadIdChange?: ((threadId: string | undefined) => void) | undefined;
68
+ onSwitchToThread?: ((threadId: string) => void) | undefined;
69
+ onSwitchToNewThread?: (() => void) | undefined;
70
+ onDelete?: ((threadId: string) => void) | undefined;
71
+ };
72
+
73
+ const threadNotFoundError = (threadIdOrRemoteId: string, action: string) =>
74
+ new Error(`Thread "${threadIdOrRemoteId}" was not found while ${action}.`);
75
+
76
+ const threadStatusError = (
77
+ threadIdOrRemoteId: string,
78
+ status: RemoteThreadData["status"],
79
+ action: string,
80
+ ) =>
81
+ new Error(
82
+ `Thread "${threadIdOrRemoteId}" has status "${status}", so it cannot ${action}.`,
83
+ );
84
+
85
+ const toInitializeResult = (
86
+ result: RemoteThreadInitializeResponse,
87
+ ): { remoteId: string; externalId: string | undefined } => ({
88
+ remoteId: result.remoteId,
89
+ externalId: result.externalId,
90
+ });
91
+
92
+ const applyTitleStream = async (
93
+ stream: Parameters<typeof AssistantMessageStream.fromAssistantStream>[0],
94
+ onTitle: (title: string | undefined) => void,
95
+ ) => {
96
+ const messageStream = AssistantMessageStream.fromAssistantStream(stream);
97
+ for await (const result of messageStream) {
98
+ onTitle(result.parts.filter((part) => part.type === "text")[0]?.text);
99
+ }
100
+ };
101
+
102
+ const seedNewThread = (
103
+ state: RemoteThreadState,
104
+ ): { id: string; state: RemoteThreadState } => {
105
+ let id: string;
106
+ do {
107
+ id = `__LOCALID_${generateId()}`;
108
+ } while (state.threadIdMap[id]);
109
+ const mappingId = createThreadMappingId(id);
110
+ return {
111
+ id,
112
+ state: {
113
+ ...state,
114
+ newThreadId: id,
115
+ threadIdMap: {
116
+ ...state.threadIdMap,
117
+ [id]: mappingId,
118
+ },
119
+ threadData: {
120
+ ...state.threadData,
121
+ [mappingId]: {
122
+ status: "new",
123
+ id,
124
+ remoteId: undefined,
125
+ externalId: undefined,
126
+ title: undefined,
127
+ custom: undefined,
128
+ },
129
+ },
130
+ },
131
+ };
132
+ };
133
+
134
+ const useThreadListItemClient = (props: {
135
+ data: RemoteThreadData;
136
+ isRunning: boolean;
137
+ onSwitchTo: (options?: { unarchive?: boolean }) => void;
138
+ onRename: (title: string) => void;
139
+ onUpdateCustom: (custom: Record<string, unknown> | undefined) => void;
140
+ onArchive: () => void;
141
+ onUnarchive: () => void;
142
+ onDelete: () => void;
143
+ onGenerateTitle: () => void;
144
+ onInitialize: () => Promise<{
145
+ remoteId: string;
146
+ externalId: string | undefined;
147
+ }>;
148
+ onDetach: () => void;
149
+ }): ClientOutput<"threadListItem"> => {
150
+ const {
151
+ data,
152
+ isRunning,
153
+ onSwitchTo,
154
+ onRename,
155
+ onUpdateCustom,
156
+ onArchive,
157
+ onUnarchive,
158
+ onDelete,
159
+ onGenerateTitle,
160
+ onInitialize,
161
+ onDetach,
162
+ } = props;
163
+ const state = useMemo(
164
+ () => ({
165
+ id: data.id,
166
+ remoteId: data.remoteId,
167
+ externalId: data.externalId,
168
+ title: data.title,
169
+ lastMessageAt: "lastMessageAt" in data ? data.lastMessageAt : undefined,
170
+ status: data.status,
171
+ custom: data.custom,
172
+ isRunning,
173
+ }),
174
+ [data, isRunning],
175
+ );
176
+
177
+ return {
178
+ getState: () => state,
179
+ switchTo: onSwitchTo,
180
+ rename: onRename,
181
+ updateCustom: onUpdateCustom,
182
+ archive: onArchive,
183
+ unarchive: onUnarchive,
184
+ delete: onDelete,
185
+ generateTitle: onGenerateTitle,
186
+ initialize: onInitialize,
187
+ detach: onDetach,
188
+ };
189
+ };
190
+
191
+ const ThreadListItemClient = resource(useThreadListItemClient);
192
+
193
+ const collectItemOrder = (
194
+ listState: RemoteThreadState,
195
+ mainThreadId: string,
196
+ ): RemoteThreadData[] => {
197
+ const ids = [
198
+ listState.newThreadId,
199
+ ...listState.threadIds,
200
+ ...listState.archivedThreadIds,
201
+ mainThreadId,
202
+ ].filter((id): id is string => id !== undefined);
203
+ const seenIds = new Set<string>();
204
+ const seenRemoteIds = new Set<string>();
205
+ const items: RemoteThreadData[] = [];
206
+ for (const id of ids) {
207
+ const data = getThreadData(listState, id);
208
+ if (!data || seenIds.has(data.id)) continue;
209
+ if (data.remoteId !== undefined && seenRemoteIds.has(data.remoteId)) {
210
+ continue;
211
+ }
212
+ seenIds.add(data.id);
213
+ if (data.remoteId !== undefined) seenRemoteIds.add(data.remoteId);
214
+ items.push(data);
215
+ }
216
+ return items;
217
+ };
218
+
219
+ const itemMatchesId = (
220
+ item: RemoteThreadData,
221
+ listState: RemoteThreadState,
222
+ id: string,
223
+ ) => {
224
+ const data = getThreadData(listState, id);
225
+ return (
226
+ item.id === id ||
227
+ item.id === data?.id ||
228
+ (data?.remoteId !== undefined &&
229
+ (item.id === data.remoteId || item.remoteId === data.remoteId))
230
+ );
231
+ };
232
+
233
+ const isSameThread = (
234
+ listState: RemoteThreadState,
235
+ left: string,
236
+ right: string,
237
+ ) => {
238
+ if (left === right) return true;
239
+ const data = getThreadData(listState, left);
240
+ return data !== undefined && itemMatchesId(data, listState, right);
241
+ };
242
+
243
+ const useRemoteThreadListView = ({
244
+ listState,
245
+ mainThreadId,
246
+ threadFactory,
247
+ useAdapters,
248
+ onSwitchTo,
249
+ onRename,
250
+ onUpdateCustom,
251
+ onArchive,
252
+ onUnarchive,
253
+ onDelete,
254
+ onGenerateTitle,
255
+ onInitialize,
256
+ onDetach,
257
+ }: {
258
+ listState: RemoteThreadState;
259
+ mainThreadId: string;
260
+ threadFactory: RemoteThreadListProps["thread"];
261
+ useAdapters: RemoteThreadListAdapter["unstable_useAdapters"];
262
+ onSwitchTo: (
263
+ threadId: string,
264
+ options?: { unarchive?: boolean },
265
+ ) => Promise<void>;
266
+ onRename: (threadId: string, title: string) => Promise<void>;
267
+ onUpdateCustom: (
268
+ threadId: string,
269
+ custom: Record<string, unknown> | undefined,
270
+ ) => Promise<void>;
271
+ onArchive: (threadId: string) => Promise<void>;
272
+ onUnarchive: (threadId: string) => Promise<void>;
273
+ onDelete: (threadId: string) => Promise<void>;
274
+ onGenerateTitle: (
275
+ threadId: string,
276
+ messages: readonly ThreadMessage[] | undefined,
277
+ ) => Promise<void>;
278
+ onInitialize: (threadId: string) => Promise<{
279
+ remoteId: string;
280
+ externalId: string | undefined;
281
+ }>;
282
+ onDetach: (threadId: string) => Promise<void>;
283
+ }) => {
284
+ const thread = threadFactory(mainThreadId);
285
+ const wrapped =
286
+ useAdapters === undefined
287
+ ? thread
288
+ : AdaptedRemoteThread({
289
+ useAdapters,
290
+ thread,
291
+ });
292
+ const mainThreadClient = useClientResource(
293
+ thread.key === undefined ? wrapped : withKey(thread.key, wrapped),
294
+ );
295
+ const itemOrder = useMemo(
296
+ () => collectItemOrder(listState, mainThreadId),
297
+ [listState, mainThreadId],
298
+ );
299
+ const threadListItems = useClientLookup(
300
+ itemOrder.map((data) =>
301
+ withKey(
302
+ data.id,
303
+ ThreadListItemClient({
304
+ data,
305
+ isRunning:
306
+ itemMatchesId(data, listState, mainThreadId) &&
307
+ mainThreadClient.state.isRunning,
308
+ onSwitchTo: (options) =>
309
+ handleThreadListAction("switch", () =>
310
+ onSwitchTo(data.id, options),
311
+ ),
312
+ onRename: (title) =>
313
+ handleThreadListAction("rename", () => onRename(data.id, title)),
314
+ onUpdateCustom: (custom) =>
315
+ handleThreadListAction("update custom metadata", () =>
316
+ onUpdateCustom(data.id, custom),
317
+ ),
318
+ onArchive: () =>
319
+ handleThreadListAction("archive", () => onArchive(data.id)),
320
+ onUnarchive: () =>
321
+ handleThreadListAction("unarchive", () => onUnarchive(data.id)),
322
+ onDelete: () =>
323
+ handleThreadListAction("delete", () => onDelete(data.id)),
324
+ onGenerateTitle: () =>
325
+ handleThreadListAction("generate title", () =>
326
+ onGenerateTitle(
327
+ data.id,
328
+ mainThreadClient.state.messages as
329
+ | readonly ThreadMessage[]
330
+ | undefined,
331
+ ),
332
+ ),
333
+ onInitialize: () => onInitialize(data.id),
334
+ onDetach: () =>
335
+ handleThreadListAction("detach", () => onDetach(data.id)),
336
+ }),
337
+ ),
338
+ ),
339
+ );
340
+ return { mainThreadClient, itemOrder, threadListItems };
341
+ };
342
+
343
+ const useRemoteThreadList = (
344
+ props: RemoteThreadListProps,
345
+ ): ClientOutput<"threads"> => {
346
+ const {
347
+ adapter,
348
+ thread: threadFactory,
349
+ threadId,
350
+ onThreadIdChange,
351
+ onSwitchToThread,
352
+ onSwitchToNewThread,
353
+ onDelete,
354
+ } = props;
355
+
356
+ const [{ store, initialMainId, session }] = useState(() => {
357
+ const seeded = seedNewThread(EMPTY_LIST);
358
+ return {
359
+ store: new OptimisticState(seeded.state),
360
+ initialMainId: seeded.id,
361
+ session: {
362
+ adapter,
363
+ adapterAtLoad: adapter,
364
+ adapterGeneration: 0,
365
+ loadGeneration: 0,
366
+ switchGeneration: 0,
367
+ loadPromise: undefined as Promise<void> | undefined,
368
+ loadMorePromise: undefined as Promise<void> | undefined,
369
+ lastNotifiedRemoteId: undefined as string | undefined,
370
+ lastControlledThreadId: undefined as string | undefined,
371
+ switchTask: undefined as Promise<void> | undefined,
372
+ mainThreadId: seeded.id,
373
+ isFirstThreadIdEffect: true,
374
+ onThreadIdChange,
375
+ onSwitchToThread,
376
+ onSwitchToNewThread,
377
+ },
378
+ };
379
+ });
380
+
381
+ // Config updates can invoke `reload()` in the same turn as the re-render, before the effect below runs.
382
+ session.adapter = adapter;
383
+
384
+ const listState = useSyncExternalStore(
385
+ (onStoreChange) => store.subscribe(onStoreChange),
386
+ () => store.value,
387
+ () => store.value,
388
+ );
389
+
390
+ const [mainThreadId, setMainThreadId] = useState(initialMainId);
391
+ const assignMainThreadId = useCallback(
392
+ (id: string) => {
393
+ session.mainThreadId = id;
394
+ setMainThreadId(id);
395
+ },
396
+ [session],
397
+ );
398
+ useThreadSelectionEvents(mainThreadId);
399
+ useEffect(() => {
400
+ session.adapter = adapter;
401
+ session.mainThreadId = mainThreadId;
402
+ session.onThreadIdChange = onThreadIdChange;
403
+ session.onSwitchToThread = onSwitchToThread;
404
+ session.onSwitchToNewThread = onSwitchToNewThread;
405
+ }, [
406
+ adapter,
407
+ mainThreadId,
408
+ onSwitchToNewThread,
409
+ onSwitchToThread,
410
+ onThreadIdChange,
411
+ session,
412
+ ]);
413
+
414
+ const notifyRemoteId = useCallback(
415
+ (remoteId: string | undefined, emit: boolean) => {
416
+ if (session.lastNotifiedRemoteId === remoteId) return;
417
+ session.lastNotifiedRemoteId = remoteId;
418
+ if (emit) session.onThreadIdChange?.(remoteId);
419
+ },
420
+ [session],
421
+ );
422
+
423
+ const getLoadThreadsPromise = useCallback(() => {
424
+ if (session.loadPromise) return session.loadPromise;
425
+ const generation = session.loadGeneration;
426
+ const adapter = session.adapter;
427
+ session.loadPromise = store
428
+ .optimisticUpdate({
429
+ execute: () => adapter.list(),
430
+ loading: (state) => ({ ...state, isLoading: true }),
431
+ then: (state, page) => {
432
+ if (generation !== session.loadGeneration) return state;
433
+ session.adapterAtLoad = adapter;
434
+ const fresh = classifyThreads(page.threads, {
435
+ threadIds: [],
436
+ archivedThreadIds: [],
437
+ threadIdMap: {},
438
+ threadData: {},
439
+ });
440
+ return {
441
+ ...state,
442
+ isLoading: false,
443
+ cursor: normalizeCursor(page.nextCursor),
444
+ threadIds: fresh.threadIds,
445
+ archivedThreadIds: fresh.archivedThreadIds,
446
+ threadIdMap: {
447
+ ...state.threadIdMap,
448
+ ...fresh.threadIdMap,
449
+ },
450
+ threadData: {
451
+ ...state.threadData,
452
+ ...fresh.threadData,
453
+ },
454
+ };
455
+ },
456
+ })
457
+ .catch((error: unknown) => {
458
+ if (generation !== session.loadGeneration) return;
459
+ console.error("[assistant-ui] thread list load failed:", error);
460
+ session.loadPromise = undefined;
461
+ store.update({
462
+ ...store.baseValue,
463
+ isLoading: false,
464
+ });
465
+ })
466
+ .then(() => {});
467
+ return session.loadPromise;
468
+ }, [session, store]);
469
+
470
+ const reload = useCallback(() => {
471
+ const adapterChanged = adapter !== session.adapterAtLoad;
472
+ session.loadGeneration++;
473
+ session.loadPromise = undefined;
474
+ session.loadMorePromise = undefined;
475
+ if (adapterChanged) {
476
+ session.adapterGeneration++;
477
+ session.switchGeneration++;
478
+ session.switchTask = undefined;
479
+ session.adapterAtLoad = adapter;
480
+ const seeded = seedNewThread(EMPTY_LIST);
481
+ store.reset({ ...seeded.state, isLoading: true });
482
+ assignMainThreadId(seeded.id);
483
+ notifyRemoteId(undefined, true);
484
+ } else {
485
+ store.update({
486
+ ...store.baseValue,
487
+ cursor: undefined,
488
+ });
489
+ }
490
+ return getLoadThreadsPromise();
491
+ }, [
492
+ adapter,
493
+ assignMainThreadId,
494
+ getLoadThreadsPromise,
495
+ notifyRemoteId,
496
+ session,
497
+ store,
498
+ ]);
499
+
500
+ useEffect(() => {
501
+ void getLoadThreadsPromise();
502
+ }, [getLoadThreadsPromise]);
503
+
504
+ useEffect(() => {
505
+ if (!isDevelopment) return;
506
+ if (adapter.unstable_useAdapters !== undefined) return;
507
+ if (adapter.unstable_Provider === undefined) return;
508
+ console.warn(
509
+ "[assistant-ui] RemoteThreadList ignores RemoteThreadListAdapter.unstable_Provider. Expose unstable_useAdapters so per-thread history loads on this entry. useRemoteThreadListRuntime still honors unstable_Provider.",
510
+ );
511
+ }, [adapter]);
512
+
513
+ const loadMore = useCallback(() => {
514
+ if (session.loadMorePromise) return session.loadMorePromise;
515
+ const snapshot = store.value;
516
+ if (snapshot.cursor === undefined || snapshot.isLoading) {
517
+ return RESOLVED_PROMISE;
518
+ }
519
+ const generation = session.loadGeneration;
520
+ const cursor = snapshot.cursor;
521
+ const currentAdapter = session.adapter;
522
+ const task = store
523
+ .optimisticUpdate({
524
+ execute: () => currentAdapter.list({ after: cursor }),
525
+ loading: (state) => ({ ...state, isLoadingMore: true }),
526
+ then: (state, page) => {
527
+ if (generation !== session.loadGeneration) return state;
528
+ const appended = classifyThreads(page.threads, {
529
+ threadIds: [...state.threadIds],
530
+ archivedThreadIds: [...state.archivedThreadIds],
531
+ threadIdMap: { ...state.threadIdMap },
532
+ threadData: { ...state.threadData },
533
+ });
534
+ return {
535
+ ...state,
536
+ isLoadingMore: false,
537
+ cursor: normalizeCursor(page.nextCursor),
538
+ threadIds: appended.threadIds,
539
+ archivedThreadIds: appended.archivedThreadIds,
540
+ threadIdMap: appended.threadIdMap,
541
+ threadData: appended.threadData,
542
+ };
543
+ },
544
+ })
545
+ .catch((error: unknown) => {
546
+ if (generation !== session.loadGeneration) return;
547
+ console.error("[assistant-ui] thread list loadMore failed:", error);
548
+ })
549
+ .then(() => {
550
+ if (session.loadMorePromise === task) {
551
+ session.loadMorePromise = undefined;
552
+ }
553
+ });
554
+ session.loadMorePromise = task;
555
+ return task;
556
+ }, [session, store]);
557
+
558
+ const startSwitch = useCallback(
559
+ (run: (generation: number) => Promise<void>) => {
560
+ const generation = ++session.switchGeneration;
561
+ let settle!: (error?: unknown) => void;
562
+ const task = new Promise<void>((resolve, reject) => {
563
+ settle = (error) => {
564
+ if (error === undefined) resolve();
565
+ else reject(error);
566
+ };
567
+ });
568
+ session.switchTask = task;
569
+ void run(generation).then(
570
+ () => settle(),
571
+ (error: unknown) => settle(error),
572
+ );
573
+ return task;
574
+ },
575
+ [session],
576
+ );
577
+
578
+ const switchToThread = useCallback(
579
+ (
580
+ threadIdOrRemoteId: string,
581
+ options?: { unarchive?: boolean },
582
+ emitThreadIdChange = true,
583
+ ) =>
584
+ startSwitch(async (generation) => {
585
+ let data = getThreadData(store.value, threadIdOrRemoteId);
586
+ if (!data) {
587
+ const remoteMetadata =
588
+ await session.adapter.fetch(threadIdOrRemoteId);
589
+ if (generation !== session.switchGeneration) return;
590
+ const state = store.value;
591
+ const mappingId = createThreadMappingId(remoteMetadata.remoteId);
592
+ const wasInTarget =
593
+ remoteMetadata.status === "regular"
594
+ ? state.threadIds.includes(remoteMetadata.remoteId)
595
+ : state.archivedThreadIds.includes(remoteMetadata.remoteId);
596
+ const threadIdsWithoutRemote = state.threadIds.filter(
597
+ (id) => id !== remoteMetadata.remoteId,
598
+ );
599
+ const archivedThreadIdsWithoutRemote = state.archivedThreadIds.filter(
600
+ (id) => id !== remoteMetadata.remoteId,
601
+ );
602
+ store.update({
603
+ ...state,
604
+ threadIds:
605
+ remoteMetadata.status === "regular"
606
+ ? wasInTarget
607
+ ? state.threadIds
608
+ : [...threadIdsWithoutRemote, remoteMetadata.remoteId]
609
+ : threadIdsWithoutRemote,
610
+ archivedThreadIds:
611
+ remoteMetadata.status === "archived"
612
+ ? wasInTarget
613
+ ? state.archivedThreadIds
614
+ : [...archivedThreadIdsWithoutRemote, remoteMetadata.remoteId]
615
+ : archivedThreadIdsWithoutRemote,
616
+ threadIdMap: {
617
+ ...state.threadIdMap,
618
+ [remoteMetadata.remoteId]: mappingId,
619
+ },
620
+ threadData: {
621
+ ...state.threadData,
622
+ [mappingId]: {
623
+ id: mappingId,
624
+ initializeTask: Promise.resolve({
625
+ remoteId: remoteMetadata.remoteId,
626
+ externalId: remoteMetadata.externalId,
627
+ }),
628
+ remoteId: remoteMetadata.remoteId,
629
+ externalId: remoteMetadata.externalId,
630
+ status: remoteMetadata.status,
631
+ title: remoteMetadata.title,
632
+ lastMessageAt: remoteMetadata.lastMessageAt,
633
+ custom: remoteMetadata.custom,
634
+ },
635
+ },
636
+ });
637
+ data = getThreadData(store.value, threadIdOrRemoteId);
638
+ }
639
+ if (!data) {
640
+ throw threadNotFoundError(threadIdOrRemoteId, "switching to it");
641
+ }
642
+ if (isSameThread(store.value, data.id, session.mainThreadId)) return;
643
+ if (data.status === "archived" && options?.unarchive !== false) {
644
+ const current = data;
645
+ const { remoteId } = await current.initializeTask;
646
+ if (generation !== session.switchGeneration) return;
647
+ await store.optimisticUpdate({
648
+ execute: () => session.adapter.unarchive(remoteId),
649
+ optimistic: (state) =>
650
+ updateStatusReducer(state, current.id, "regular"),
651
+ });
652
+ if (generation !== session.switchGeneration) return;
653
+ data = getThreadData(store.value, current.id) ?? current;
654
+ }
655
+ if (generation !== session.switchGeneration) return;
656
+ assignMainThreadId(data.id);
657
+ notifyRemoteId(data.remoteId, emitThreadIdChange);
658
+ session.onSwitchToThread?.(data.id);
659
+ }),
660
+ [assignMainThreadId, notifyRemoteId, session, startSwitch, store],
661
+ );
662
+
663
+ const switchToNewThread = useCallback(
664
+ (emitThreadIdChange = true) =>
665
+ startSwitch(async (generation) => {
666
+ while (
667
+ store.baseValue.newThreadId !== undefined &&
668
+ store.value.newThreadId === undefined
669
+ ) {
670
+ await store.waitForUpdate();
671
+ if (generation !== session.switchGeneration) return;
672
+ }
673
+ const existing = store.value.newThreadId;
674
+ if (existing !== undefined) {
675
+ const existingId =
676
+ getThreadData(store.value, existing)?.id ?? existing;
677
+ if (isSameThread(store.value, existingId, session.mainThreadId)) {
678
+ return;
679
+ }
680
+ assignMainThreadId(existingId);
681
+ notifyRemoteId(undefined, emitThreadIdChange);
682
+ session.onSwitchToNewThread?.();
683
+ return;
684
+ }
685
+ const seeded = seedNewThread(store.baseValue);
686
+ store.update(seeded.state);
687
+ if (generation !== session.switchGeneration) return;
688
+ assignMainThreadId(seeded.id);
689
+ notifyRemoteId(undefined, emitThreadIdChange);
690
+ session.onSwitchToNewThread?.();
691
+ }),
692
+ [assignMainThreadId, notifyRemoteId, session, startSwitch, store],
693
+ );
694
+
695
+ const ensureNotMain = useCallback(
696
+ async (threadId: string) => {
697
+ if (threadId === store.value.newThreadId) {
698
+ throw new Error("Cannot ensure new thread is not main");
699
+ }
700
+ let lastAwaitedTask: Promise<void> | undefined;
701
+ while (isSameThread(store.value, threadId, session.mainThreadId)) {
702
+ let switchTask = session.switchTask;
703
+ const startedFallback = !switchTask || switchTask === lastAwaitedTask;
704
+ if (startedFallback) {
705
+ switchTask = switchToNewThread();
706
+ }
707
+ lastAwaitedTask = switchTask;
708
+ try {
709
+ await switchTask;
710
+ } catch (error) {
711
+ if (startedFallback && session.switchTask === switchTask) {
712
+ throw error;
713
+ }
714
+ }
715
+ }
716
+ },
717
+ [session, store, switchToNewThread],
718
+ );
719
+
720
+ const requireAdapterGeneration = useCallback(
721
+ (generation: number) => {
722
+ if (generation !== session.adapterGeneration) {
723
+ throw new ThreadListAdapterChangedError();
724
+ }
725
+ },
726
+ [session],
727
+ );
728
+
729
+ const initialize = useCallback(
730
+ async (threadId: string) => {
731
+ const currentAdapter = session.adapter;
732
+ const adapterGeneration = session.adapterGeneration;
733
+ if (store.value.newThreadId !== threadId) {
734
+ const data = getThreadData(store.value, threadId);
735
+ if (!data) throw threadNotFoundError(threadId, "initializing it");
736
+ if (data.status === "new") {
737
+ throw threadStatusError(threadId, data.status, "be initialized here");
738
+ }
739
+ const result = toInitializeResult(await data.initializeTask);
740
+ requireAdapterGeneration(adapterGeneration);
741
+ return result;
742
+ }
743
+ const result = await store.optimisticUpdate({
744
+ execute: () => {
745
+ requireAdapterGeneration(adapterGeneration);
746
+ return currentAdapter.initialize(threadId);
747
+ },
748
+ optimistic: (state) => updateStatusReducer(state, threadId, "regular"),
749
+ loading: (state, task) => {
750
+ const mappingId = createThreadMappingId(threadId);
751
+ return {
752
+ ...state,
753
+ threadData: {
754
+ ...state.threadData,
755
+ [mappingId]: {
756
+ ...state.threadData[mappingId],
757
+ initializeTask: task,
758
+ },
759
+ },
760
+ };
761
+ },
762
+ then: (state, { remoteId, externalId }) => {
763
+ if (adapterGeneration !== session.adapterGeneration) return state;
764
+ const data = getThreadData(state, threadId);
765
+ if (!data) return state;
766
+ const mappingId = createThreadMappingId(threadId);
767
+ return {
768
+ ...state,
769
+ threadIdMap: {
770
+ ...state.threadIdMap,
771
+ [remoteId]: mappingId,
772
+ },
773
+ threadData: {
774
+ ...state.threadData,
775
+ [mappingId]: {
776
+ ...data,
777
+ initializeTask: Promise.resolve({ remoteId, externalId }),
778
+ remoteId,
779
+ externalId,
780
+ },
781
+ },
782
+ };
783
+ },
784
+ });
785
+ requireAdapterGeneration(adapterGeneration);
786
+ if (threadId === session.mainThreadId) {
787
+ notifyRemoteId(result.remoteId, true);
788
+ }
789
+ return toInitializeResult(result);
790
+ },
791
+ [notifyRemoteId, requireAdapterGeneration, session, store],
792
+ );
793
+
794
+ const rename = useCallback(
795
+ (threadIdOrRemoteId: string, newTitle: string) => {
796
+ const currentAdapter = session.adapter;
797
+ const adapterGeneration = session.adapterGeneration;
798
+ const data = getThreadData(store.value, threadIdOrRemoteId);
799
+ if (!data) throw threadNotFoundError(threadIdOrRemoteId, "renaming it");
800
+ if (data.status === "new") {
801
+ throw threadStatusError(threadIdOrRemoteId, data.status, "be renamed");
802
+ }
803
+ return store.optimisticUpdate({
804
+ execute: async () => {
805
+ const { remoteId } = await data.initializeTask;
806
+ requireAdapterGeneration(adapterGeneration);
807
+ return currentAdapter.rename(remoteId, newTitle);
808
+ },
809
+ optimistic: (state) => {
810
+ const current = getThreadData(state, threadIdOrRemoteId);
811
+ if (!current) return state;
812
+ return {
813
+ ...state,
814
+ threadData: {
815
+ ...state.threadData,
816
+ [current.id]: {
817
+ ...current,
818
+ title: newTitle,
819
+ },
820
+ },
821
+ };
822
+ },
823
+ });
824
+ },
825
+ [requireAdapterGeneration, session, store],
826
+ );
827
+
828
+ const updateCustom = useCallback(
829
+ (
830
+ threadIdOrRemoteId: string,
831
+ custom: Record<string, unknown> | undefined,
832
+ ) => {
833
+ const currentAdapter = session.adapter;
834
+ const adapterGeneration = session.adapterGeneration;
835
+ const data = getThreadData(store.value, threadIdOrRemoteId);
836
+ if (!data) {
837
+ throw threadNotFoundError(
838
+ threadIdOrRemoteId,
839
+ "updating its custom metadata",
840
+ );
841
+ }
842
+ if (data.status === "new") {
843
+ throw threadStatusError(
844
+ threadIdOrRemoteId,
845
+ data.status,
846
+ "update custom metadata",
847
+ );
848
+ }
849
+ if (!currentAdapter.updateCustom) {
850
+ throw new Error(
851
+ "Remote thread list adapter does not support updating custom metadata",
852
+ );
853
+ }
854
+ return store.optimisticUpdate({
855
+ execute: async () => {
856
+ const { remoteId } = await data.initializeTask;
857
+ requireAdapterGeneration(adapterGeneration);
858
+ if (!currentAdapter.updateCustom) {
859
+ throw new Error(
860
+ "Remote thread list adapter does not support updating custom metadata",
861
+ );
862
+ }
863
+ return currentAdapter.updateCustom(remoteId, custom);
864
+ },
865
+ optimistic: (state) => {
866
+ const current = getThreadData(state, threadIdOrRemoteId);
867
+ if (!current) return state;
868
+ return {
869
+ ...state,
870
+ threadData: {
871
+ ...state.threadData,
872
+ [current.id]: {
873
+ ...current,
874
+ custom,
875
+ },
876
+ },
877
+ };
878
+ },
879
+ });
880
+ },
881
+ [requireAdapterGeneration, session, store],
882
+ );
883
+
884
+ const archive = useCallback(
885
+ async (threadIdOrRemoteId: string) => {
886
+ const currentAdapter = session.adapter;
887
+ const adapterGeneration = session.adapterGeneration;
888
+ const data = getThreadData(store.value, threadIdOrRemoteId);
889
+ if (!data) throw threadNotFoundError(threadIdOrRemoteId, "archiving it");
890
+ if (data.status !== "regular") {
891
+ throw threadStatusError(threadIdOrRemoteId, data.status, "be archived");
892
+ }
893
+ await ensureNotMain(data.id);
894
+ requireAdapterGeneration(adapterGeneration);
895
+ return store.optimisticUpdate({
896
+ execute: async () => {
897
+ const { remoteId } = await data.initializeTask;
898
+ requireAdapterGeneration(adapterGeneration);
899
+ return currentAdapter.archive(remoteId);
900
+ },
901
+ optimistic: (state) => updateStatusReducer(state, data.id, "archived"),
902
+ });
903
+ },
904
+ [ensureNotMain, requireAdapterGeneration, session, store],
905
+ );
906
+
907
+ const unarchive = useCallback(
908
+ (threadIdOrRemoteId: string) => {
909
+ const currentAdapter = session.adapter;
910
+ const adapterGeneration = session.adapterGeneration;
911
+ const data = getThreadData(store.value, threadIdOrRemoteId);
912
+ if (!data)
913
+ throw threadNotFoundError(threadIdOrRemoteId, "unarchiving it");
914
+ if (data.status !== "archived") {
915
+ throw threadStatusError(
916
+ threadIdOrRemoteId,
917
+ data.status,
918
+ "be unarchived",
919
+ );
920
+ }
921
+ return store.optimisticUpdate({
922
+ execute: async () => {
923
+ try {
924
+ const { remoteId } = await data.initializeTask;
925
+ requireAdapterGeneration(adapterGeneration);
926
+ return await currentAdapter.unarchive(remoteId);
927
+ } catch (error) {
928
+ if (adapterGeneration === session.adapterGeneration) {
929
+ await ensureNotMain(data.id);
930
+ }
931
+ throw error;
932
+ }
933
+ },
934
+ optimistic: (state) => updateStatusReducer(state, data.id, "regular"),
935
+ });
936
+ },
937
+ [ensureNotMain, requireAdapterGeneration, session, store],
938
+ );
939
+
940
+ const deleteThread = useCallback(
941
+ async (threadIdOrRemoteId: string) => {
942
+ const currentAdapter = session.adapter;
943
+ const adapterGeneration = session.adapterGeneration;
944
+ const data = getThreadData(store.value, threadIdOrRemoteId);
945
+ if (!data) throw threadNotFoundError(threadIdOrRemoteId, "deleting it");
946
+ if (data.status !== "regular" && data.status !== "archived") {
947
+ throw threadStatusError(threadIdOrRemoteId, data.status, "be deleted");
948
+ }
949
+ await ensureNotMain(data.id);
950
+ requireAdapterGeneration(adapterGeneration);
951
+ onDelete?.(data.id);
952
+ return store.optimisticUpdate({
953
+ execute: async () => {
954
+ const { remoteId } = await data.initializeTask;
955
+ requireAdapterGeneration(adapterGeneration);
956
+ return currentAdapter.delete(remoteId);
957
+ },
958
+ optimistic: (state) => updateStatusReducer(state, data.id, "deleted"),
959
+ });
960
+ },
961
+ [ensureNotMain, onDelete, requireAdapterGeneration, session, store],
962
+ );
963
+
964
+ const generateTitle = useCallback(
965
+ async (
966
+ threadIdOrRemoteId: string,
967
+ messages: readonly ThreadMessage[] | undefined,
968
+ ) => {
969
+ const currentAdapter = session.adapter;
970
+ const adapterGeneration = session.adapterGeneration;
971
+ const data = getThreadData(store.value, threadIdOrRemoteId);
972
+ if (!data) {
973
+ throw threadNotFoundError(threadIdOrRemoteId, "generating its title");
974
+ }
975
+ if (data.status === "new") {
976
+ throw threadStatusError(
977
+ threadIdOrRemoteId,
978
+ data.status,
979
+ "generate a title",
980
+ );
981
+ }
982
+ const { remoteId } = await data.initializeTask;
983
+ requireAdapterGeneration(adapterGeneration);
984
+ if (!isSameThread(store.value, data.id, session.mainThreadId)) return;
985
+ if (!messages) return;
986
+ const stream = await currentAdapter.generateTitle(remoteId, messages);
987
+ requireAdapterGeneration(adapterGeneration);
988
+ await applyTitleStream(stream, (newTitle) => {
989
+ if (adapterGeneration !== session.adapterGeneration) return;
990
+ const state = store.baseValue;
991
+ const current = getThreadData(state, data.id);
992
+ if (!current) return;
993
+ store.update({
994
+ ...state,
995
+ threadData: {
996
+ ...state.threadData,
997
+ [current.id]: {
998
+ ...current,
999
+ title: newTitle,
1000
+ },
1001
+ },
1002
+ });
1003
+ });
1004
+ },
1005
+ [requireAdapterGeneration, session, store],
1006
+ );
1007
+
1008
+ const { mainThreadClient, itemOrder, threadListItems } =
1009
+ useRemoteThreadListView({
1010
+ listState,
1011
+ mainThreadId,
1012
+ threadFactory,
1013
+ useAdapters: adapter.unstable_useAdapters,
1014
+ onSwitchTo: (id, options) => switchToThread(id, options),
1015
+ onRename: (id, title) => rename(id, title),
1016
+ onUpdateCustom: (id, custom) => updateCustom(id, custom),
1017
+ onArchive: (id) => archive(id),
1018
+ onUnarchive: (id) => unarchive(id),
1019
+ onDelete: (id) => deleteThread(id),
1020
+ onGenerateTitle: (id, messages) => generateTitle(id, messages),
1021
+ onInitialize: async (id) => toInitializeResult(await initialize(id)),
1022
+ onDetach: (id) => ensureNotMain(id),
1023
+ });
1024
+
1025
+ const mainRemoteId = getThreadData(listState, mainThreadId)?.remoteId;
1026
+ useEffect(() => {
1027
+ if (session.lastNotifiedRemoteId === mainRemoteId) return;
1028
+ session.lastNotifiedRemoteId = mainRemoteId;
1029
+ onThreadIdChange?.(mainRemoteId);
1030
+ }, [mainRemoteId, onThreadIdChange, session]);
1031
+
1032
+ useEffect(() => {
1033
+ if (session.isFirstThreadIdEffect) {
1034
+ session.isFirstThreadIdEffect = false;
1035
+ session.lastControlledThreadId = threadId;
1036
+ if (threadId === undefined) return;
1037
+ handleThreadListAction("switch", () =>
1038
+ switchToThread(threadId, undefined, false),
1039
+ );
1040
+ return;
1041
+ }
1042
+ if (Object.is(session.lastControlledThreadId, threadId)) return;
1043
+ session.lastControlledThreadId = threadId;
1044
+ if (threadId === undefined) {
1045
+ handleThreadListAction("create", () => switchToNewThread(false));
1046
+ return;
1047
+ }
1048
+ handleThreadListAction("switch", () =>
1049
+ switchToThread(threadId, undefined, false),
1050
+ );
1051
+ }, [session, switchToNewThread, switchToThread, threadId]);
1052
+
1053
+ const state = useMemo(
1054
+ () => ({
1055
+ mainThreadId,
1056
+ newThreadId: listState.newThreadId ?? null,
1057
+ isLoading: listState.isLoading,
1058
+ isLoadingMore: listState.isLoadingMore,
1059
+ hasMore: listState.cursor !== undefined,
1060
+ threadIds: listState.threadIds,
1061
+ archivedThreadIds: listState.archivedThreadIds,
1062
+ threadItems: threadListItems.state,
1063
+ main: mainThreadClient.state,
1064
+ }),
1065
+ [
1066
+ listState.archivedThreadIds,
1067
+ listState.cursor,
1068
+ listState.isLoading,
1069
+ listState.isLoadingMore,
1070
+ listState.newThreadId,
1071
+ listState.threadIds,
1072
+ mainThreadClient.state,
1073
+ mainThreadId,
1074
+ threadListItems.state,
1075
+ ],
1076
+ );
1077
+
1078
+ return {
1079
+ getState: () => state,
1080
+ switchToThread: (id, options) => {
1081
+ handleThreadListAction("switch", () => switchToThread(id, options));
1082
+ },
1083
+ switchToNewThread: () => {
1084
+ handleThreadListAction("create", () => switchToNewThread());
1085
+ },
1086
+ getLoadThreadsPromise,
1087
+ reload,
1088
+ reloadMainThread: () => {
1089
+ if (getThreadData(store.value, mainThreadId)?.status === "new") {
1090
+ return RESOLVED_PROMISE;
1091
+ }
1092
+ return (
1093
+ mainThreadClient.methods.unstable_refetchThread?.() ?? RESOLVED_PROMISE
1094
+ );
1095
+ },
1096
+ loadMore,
1097
+ item: (selector) => {
1098
+ if (selector === "main") {
1099
+ const index = itemOrder.findIndex((item) =>
1100
+ itemMatchesId(item, listState, mainThreadId),
1101
+ );
1102
+ return threadListItems.get({ index });
1103
+ }
1104
+ if ("id" in selector) {
1105
+ const index = itemOrder.findIndex((item) =>
1106
+ itemMatchesId(item, listState, selector.id),
1107
+ );
1108
+ return threadListItems.get({ index });
1109
+ }
1110
+ const ids = selector.archived
1111
+ ? listState.archivedThreadIds
1112
+ : listState.threadIds;
1113
+ const id = ids[selector.index];
1114
+ if (id === undefined) {
1115
+ return threadListItems.get({ index: -1 });
1116
+ }
1117
+ const index = itemOrder.findIndex((item) =>
1118
+ itemMatchesId(item, listState, id),
1119
+ );
1120
+ return threadListItems.get({ index });
1121
+ },
1122
+ thread: () => mainThreadClient.methods,
1123
+ };
1124
+ };
1125
+
1126
+ /**
1127
+ * `AuiConfig` `threads` entry backed by a `RemoteThreadListAdapter`. Thread
1128
+ * bodies are born from the `thread` factory inside the client tree, so any
1129
+ * `AssistantClient` host can run a remote or cloud list. Per-thread history
1130
+ * and attachments come from `unstable_useAdapters`. `useRemoteThreadListRuntime`
1131
+ * uses the same hook when `unstable_Provider` is omitted. Key the factory
1132
+ * with `withKey` so history reloads when the visible thread changes.
1133
+ */
1134
+ export const RemoteThreadList = resource(useRemoteThreadList);
1135
+
1136
+ attachTransformScopes(useRemoteThreadList, inMemoryThreadListTransformScopes);