@assistant-ui/core 0.3.17 → 0.3.19

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 (470) hide show
  1. package/dist/adapters/attachment.d.ts.map +1 -1
  2. package/dist/adapters/attachment.js +5 -4
  3. package/dist/adapters/attachment.js.map +1 -1
  4. package/dist/adapters/speech.d.ts.map +1 -1
  5. package/dist/adapters/speech.js +13 -3
  6. package/dist/adapters/speech.js.map +1 -1
  7. package/dist/adapters/thread-history.d.ts +4 -0
  8. package/dist/adapters/thread-history.d.ts.map +1 -1
  9. package/dist/index.d.ts +3 -3
  10. package/dist/index.js.map +1 -1
  11. package/dist/internal.d.ts +4 -3
  12. package/dist/internal.js +3 -2
  13. package/dist/model-context/frame/host.d.ts.map +1 -1
  14. package/dist/model-context/frame/host.js +35 -14
  15. package/dist/model-context/frame/host.js.map +1 -1
  16. package/dist/model-context/frame/provider.d.ts +2 -0
  17. package/dist/model-context/frame/provider.d.ts.map +1 -1
  18. package/dist/model-context/frame/provider.js +30 -7
  19. package/dist/model-context/frame/provider.js.map +1 -1
  20. package/dist/model-context/interactable-composer-metadata.d.ts.map +1 -1
  21. package/dist/model-context/interactable-composer-metadata.js +27 -18
  22. package/dist/model-context/interactable-composer-metadata.js.map +1 -1
  23. package/dist/model-context/registry.d.ts.map +1 -1
  24. package/dist/model-context/registry.js +3 -5
  25. package/dist/model-context/registry.js.map +1 -1
  26. package/dist/model-context/types.d.ts.map +1 -1
  27. package/dist/model-context/types.js +5 -4
  28. package/dist/model-context/types.js.map +1 -1
  29. package/dist/react/adapters/LocalStorageThreadListAdapter.d.ts.map +1 -1
  30. package/dist/react/adapters/LocalStorageThreadListAdapter.js +45 -7
  31. package/dist/react/adapters/LocalStorageThreadListAdapter.js.map +1 -1
  32. package/dist/react/client/DataRenderers.d.ts.map +1 -1
  33. package/dist/react/client/DataRenderers.js +20 -15
  34. package/dist/react/client/DataRenderers.js.map +1 -1
  35. package/dist/react/client/InMemoryThreadList.d.ts.map +1 -1
  36. package/dist/react/client/InMemoryThreadList.js +62 -56
  37. package/dist/react/client/InMemoryThreadList.js.map +1 -1
  38. package/dist/react/client/Interactables.d.ts.map +1 -1
  39. package/dist/react/client/Interactables.js +35 -32
  40. package/dist/react/client/Interactables.js.map +1 -1
  41. package/dist/react/client/RemoteThreadList.d.ts +1 -0
  42. package/dist/react/client/RemoteThreadList.d.ts.map +1 -1
  43. package/dist/react/client/RemoteThreadList.js +154 -143
  44. package/dist/react/client/RemoteThreadList.js.map +1 -1
  45. package/dist/react/client/Tools.d.ts.map +1 -1
  46. package/dist/react/client/Tools.js +18 -16
  47. package/dist/react/client/Tools.js.map +1 -1
  48. package/dist/react/client/interactable-model-context.d.ts.map +1 -1
  49. package/dist/react/client/interactable-model-context.js +3 -2
  50. package/dist/react/client/interactable-model-context.js.map +1 -1
  51. package/dist/react/index.d.ts +2 -2
  52. package/dist/react/index.js +2 -2
  53. package/dist/react/interactables-legacy/Interactables.js +242 -121
  54. package/dist/react/interactables-legacy/Interactables.js.map +1 -1
  55. package/dist/react/interactables-legacy/useAssistantInteractable.d.ts.map +1 -1
  56. package/dist/react/interactables-legacy/useAssistantInteractable.js +3 -0
  57. package/dist/react/interactables-legacy/useAssistantInteractable.js.map +1 -1
  58. package/dist/react/interactables-shared/useInteractablePersistenceQueue.d.ts.map +1 -1
  59. package/dist/react/interactables-shared/useInteractablePersistenceQueue.js +11 -9
  60. package/dist/react/interactables-shared/useInteractablePersistenceQueue.js.map +1 -1
  61. package/dist/react/model-context/makeAssistantTool.d.ts +2 -2
  62. package/dist/react/model-context/makeAssistantTool.js +1 -1
  63. package/dist/react/model-context/makeAssistantTool.js.map +1 -1
  64. package/dist/react/model-context/useAssistantTool.d.ts +2 -2
  65. package/dist/react/model-context/useAssistantTool.js +1 -1
  66. package/dist/react/model-context/useAssistantTool.js.map +1 -1
  67. package/dist/react/model-context/useInteractable.d.ts.map +1 -1
  68. package/dist/react/model-context/useInteractable.js +4 -1
  69. package/dist/react/model-context/useInteractable.js.map +1 -1
  70. package/dist/react/model-context/useInteractableVersions.js +1 -1
  71. package/dist/react/model-context/useToolArgsStatus.d.ts.map +1 -1
  72. package/dist/react/model-context/useToolArgsStatus.js +2 -1
  73. package/dist/react/model-context/useToolArgsStatus.js.map +1 -1
  74. package/dist/react/primitives/message/MessageGroupedParts.d.ts +11 -2
  75. package/dist/react/primitives/message/MessageGroupedParts.d.ts.map +1 -1
  76. package/dist/react/primitives/message/MessageGroupedParts.js +3 -2
  77. package/dist/react/primitives/message/MessageGroupedParts.js.map +1 -1
  78. package/dist/react/primitives/part/PartMessages.d.ts +1 -0
  79. package/dist/react/primitives/part/PartMessages.d.ts.map +1 -1
  80. package/dist/react/primitives/part/PartMessages.js +1 -0
  81. package/dist/react/primitives/part/PartMessages.js.map +1 -1
  82. package/dist/react/primitives/thread/ThreadMessages.d.ts.map +1 -1
  83. package/dist/react/primitives/thread/ThreadMessages.js +6 -5
  84. package/dist/react/primitives/thread/ThreadMessages.js.map +1 -1
  85. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts.map +1 -1
  86. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js +16 -8
  87. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js.map +1 -1
  88. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts +5 -1
  89. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts.map +1 -1
  90. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js +105 -104
  91. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js.map +1 -1
  92. package/dist/react/runtimes/RemoteThreadResource.d.ts +1 -0
  93. package/dist/react/runtimes/RemoteThreadResource.d.ts.map +1 -1
  94. package/dist/react/runtimes/RemoteThreadResource.js +13 -11
  95. package/dist/react/runtimes/RemoteThreadResource.js.map +1 -1
  96. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts +5 -24
  97. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts.map +1 -1
  98. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js +354 -226
  99. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js.map +1 -1
  100. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.d.ts +1 -0
  101. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.d.ts.map +1 -1
  102. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.js +22 -2
  103. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.js.map +1 -1
  104. package/dist/react/runtimes/cloud/auiV0.d.ts +40 -15
  105. package/dist/react/runtimes/cloud/auiV0.d.ts.map +1 -1
  106. package/dist/react/runtimes/cloud/auiV0.js +62 -15
  107. package/dist/react/runtimes/cloud/auiV0.js.map +1 -1
  108. package/dist/react/runtimes/cloud/createCloudThreadListAdapter.d.ts +2 -1
  109. package/dist/react/runtimes/cloud/createCloudThreadListAdapter.d.ts.map +1 -1
  110. package/dist/react/runtimes/cloud/createCloudThreadListAdapter.js +6 -1
  111. package/dist/react/runtimes/cloud/createCloudThreadListAdapter.js.map +1 -1
  112. package/dist/react/runtimes/cloud/sdkIdentity.d.ts +6 -0
  113. package/dist/react/runtimes/cloud/sdkIdentity.d.ts.map +1 -0
  114. package/dist/react/runtimes/cloud/sdkIdentity.js +9 -0
  115. package/dist/react/runtimes/cloud/sdkIdentity.js.map +1 -0
  116. package/dist/react/runtimes/external-message-converter.d.ts +12 -2
  117. package/dist/react/runtimes/external-message-converter.d.ts.map +1 -1
  118. package/dist/react/runtimes/external-message-converter.js +26 -61
  119. package/dist/react/runtimes/external-message-converter.js.map +1 -1
  120. package/dist/react/runtimes/useExternalStoreRuntime.js +75 -46
  121. package/dist/react/runtimes/useExternalStoreRuntime.js.map +1 -1
  122. package/dist/react/runtimes/useRemoteThreadListRuntime.d.ts.map +1 -1
  123. package/dist/react/runtimes/useRemoteThreadListRuntime.js +64 -24
  124. package/dist/react/runtimes/useRemoteThreadListRuntime.js.map +1 -1
  125. package/dist/react/utils/groupParts.d.ts +6 -1
  126. package/dist/react/utils/groupParts.d.ts.map +1 -1
  127. package/dist/react/utils/groupParts.js +6 -0
  128. package/dist/react/utils/groupParts.js.map +1 -1
  129. package/dist/react/utils/useJSONEqual.d.ts +3 -1
  130. package/dist/react/utils/useJSONEqual.d.ts.map +1 -1
  131. package/dist/react/utils/useJSONEqual.js +6 -1
  132. package/dist/react/utils/useJSONEqual.js.map +1 -1
  133. package/dist/react/utils/useJSONSchemaDependency.d.ts +7 -0
  134. package/dist/react/utils/useJSONSchemaDependency.d.ts.map +1 -0
  135. package/dist/react/utils/useJSONSchemaDependency.js +20 -0
  136. package/dist/react/utils/useJSONSchemaDependency.js.map +1 -0
  137. package/dist/runtime/api/thread-list-item-runtime.d.ts +7 -3
  138. package/dist/runtime/api/thread-list-item-runtime.d.ts.map +1 -1
  139. package/dist/runtime/api/thread-list-item-runtime.js +2 -2
  140. package/dist/runtime/api/thread-list-item-runtime.js.map +1 -1
  141. package/dist/runtime/api/thread-list-runtime.d.ts +3 -0
  142. package/dist/runtime/api/thread-list-runtime.d.ts.map +1 -1
  143. package/dist/runtime/api/thread-list-runtime.js +18 -14
  144. package/dist/runtime/api/thread-list-runtime.js.map +1 -1
  145. package/dist/runtime/api/thread-runtime.d.ts +4 -0
  146. package/dist/runtime/api/thread-runtime.d.ts.map +1 -1
  147. package/dist/runtime/api/thread-runtime.js +3 -6
  148. package/dist/runtime/api/thread-runtime.js.map +1 -1
  149. package/dist/runtime/base/base-composer-runtime-core.d.ts +1 -0
  150. package/dist/runtime/base/base-composer-runtime-core.d.ts.map +1 -1
  151. package/dist/runtime/base/base-composer-runtime-core.js +62 -22
  152. package/dist/runtime/base/base-composer-runtime-core.js.map +1 -1
  153. package/dist/runtime/base/base-thread-runtime-core.d.ts +2 -0
  154. package/dist/runtime/base/base-thread-runtime-core.d.ts.map +1 -1
  155. package/dist/runtime/base/base-thread-runtime-core.js +161 -69
  156. package/dist/runtime/base/base-thread-runtime-core.js.map +1 -1
  157. package/dist/runtime/interfaces/composer-runtime-core.d.ts +12 -5
  158. package/dist/runtime/interfaces/composer-runtime-core.d.ts.map +1 -1
  159. package/dist/runtime/interfaces/thread-list-runtime-core.d.ts +4 -1
  160. package/dist/runtime/interfaces/thread-list-runtime-core.d.ts.map +1 -1
  161. package/dist/runtime/interfaces/thread-runtime-core.d.ts +6 -0
  162. package/dist/runtime/interfaces/thread-runtime-core.d.ts.map +1 -1
  163. package/dist/runtime/queue/message-queue.d.ts +5 -0
  164. package/dist/runtime/queue/message-queue.d.ts.map +1 -1
  165. package/dist/runtime/queue/message-queue.js +61 -6
  166. package/dist/runtime/queue/message-queue.js.map +1 -1
  167. package/dist/runtime/utils/auto-status.d.ts +6 -2
  168. package/dist/runtime/utils/auto-status.d.ts.map +1 -1
  169. package/dist/runtime/utils/auto-status.js +12 -4
  170. package/dist/runtime/utils/auto-status.js.map +1 -1
  171. package/dist/runtime/utils/external-message-conversion.d.ts +16 -4
  172. package/dist/runtime/utils/external-message-conversion.d.ts.map +1 -1
  173. package/dist/runtime/utils/external-message-conversion.js +49 -13
  174. package/dist/runtime/utils/external-message-conversion.js.map +1 -1
  175. package/dist/runtime/utils/message-repository.d.ts +1 -0
  176. package/dist/runtime/utils/message-repository.d.ts.map +1 -1
  177. package/dist/runtime/utils/message-repository.js +18 -9
  178. package/dist/runtime/utils/message-repository.js.map +1 -1
  179. package/dist/runtime/utils/thread-message-like.d.ts +2 -1
  180. package/dist/runtime/utils/thread-message-like.d.ts.map +1 -1
  181. package/dist/runtime/utils/thread-message-like.js +5 -3
  182. package/dist/runtime/utils/thread-message-like.js.map +1 -1
  183. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.d.ts.map +1 -1
  184. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js +21 -27
  185. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js.map +1 -1
  186. package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts.map +1 -1
  187. package/dist/runtimes/external-store/external-store-thread-runtime-core.js +8 -1
  188. package/dist/runtimes/external-store/external-store-thread-runtime-core.js.map +1 -1
  189. package/dist/runtimes/internal.d.ts +3 -3
  190. package/dist/runtimes/internal.js +2 -2
  191. package/dist/runtimes/local/local-thread-runtime-core.d.ts +1 -1
  192. package/dist/runtimes/local/local-thread-runtime-core.d.ts.map +1 -1
  193. package/dist/runtimes/local/local-thread-runtime-core.js +4 -1
  194. package/dist/runtimes/local/local-thread-runtime-core.js.map +1 -1
  195. package/dist/runtimes/remote-thread-list/remote-thread-state.d.ts +18 -1
  196. package/dist/runtimes/remote-thread-list/remote-thread-state.d.ts.map +1 -1
  197. package/dist/runtimes/remote-thread-list/remote-thread-state.js +130 -42
  198. package/dist/runtimes/remote-thread-list/remote-thread-state.js.map +1 -1
  199. package/dist/runtimes/remote-thread-list/title-generation.d.ts +49 -0
  200. package/dist/runtimes/remote-thread-list/title-generation.d.ts.map +1 -0
  201. package/dist/runtimes/remote-thread-list/title-generation.js +197 -0
  202. package/dist/runtimes/remote-thread-list/title-generation.js.map +1 -0
  203. package/dist/runtimes/remote-thread-list/title.d.ts +3 -1
  204. package/dist/runtimes/remote-thread-list/title.d.ts.map +1 -1
  205. package/dist/runtimes/remote-thread-list/title.js +9 -1
  206. package/dist/runtimes/remote-thread-list/title.js.map +1 -1
  207. package/dist/runtimes/remote-thread-list/types.d.ts +10 -0
  208. package/dist/runtimes/remote-thread-list/types.d.ts.map +1 -1
  209. package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts.map +1 -1
  210. package/dist/runtimes/tool-invocations/ToolInvocationTracker.js +2 -1
  211. package/dist/runtimes/tool-invocations/ToolInvocationTracker.js.map +1 -1
  212. package/dist/store/clients/external-thread.d.ts.map +1 -1
  213. package/dist/store/clients/external-thread.js +260 -203
  214. package/dist/store/clients/external-thread.js.map +1 -1
  215. package/dist/store/clients/model-context-client.d.ts.map +1 -1
  216. package/dist/store/clients/model-context-client.js +2 -1
  217. package/dist/store/clients/model-context-client.js.map +1 -1
  218. package/dist/store/clients/single-thread-list.d.ts.map +1 -1
  219. package/dist/store/clients/single-thread-list.js +1 -0
  220. package/dist/store/clients/single-thread-list.js.map +1 -1
  221. package/dist/store/clients/suggestions.d.ts.map +1 -1
  222. package/dist/store/clients/suggestions.js +5 -4
  223. package/dist/store/clients/suggestions.js.map +1 -1
  224. package/dist/store/clients/thread-tasks.d.ts +13 -0
  225. package/dist/store/clients/thread-tasks.d.ts.map +1 -0
  226. package/dist/store/clients/thread-tasks.js +69 -0
  227. package/dist/store/clients/thread-tasks.js.map +1 -0
  228. package/dist/store/index.d.ts +3 -2
  229. package/dist/store/index.js +3 -3
  230. package/dist/store/primitive-predicates.d.ts.map +1 -1
  231. package/dist/store/primitive-predicates.js +4 -4
  232. package/dist/store/primitive-predicates.js.map +1 -1
  233. package/dist/store/runtime-clients/composer-runtime-client.d.ts +1 -0
  234. package/dist/store/runtime-clients/composer-runtime-client.d.ts.map +1 -1
  235. package/dist/store/runtime-clients/composer-runtime-client.js +97 -61
  236. package/dist/store/runtime-clients/composer-runtime-client.js.map +1 -1
  237. package/dist/store/runtime-clients/message-runtime-client.d.ts +1 -0
  238. package/dist/store/runtime-clients/message-runtime-client.d.ts.map +1 -1
  239. package/dist/store/runtime-clients/message-runtime-client.js +221 -144
  240. package/dist/store/runtime-clients/message-runtime-client.js.map +1 -1
  241. package/dist/store/runtime-clients/thread-list-item-runtime-client.d.ts.map +1 -1
  242. package/dist/store/runtime-clients/thread-list-item-runtime-client.js +1 -1
  243. package/dist/store/runtime-clients/thread-list-item-runtime-client.js.map +1 -1
  244. package/dist/store/runtime-clients/thread-list-runtime-client.d.ts.map +1 -1
  245. package/dist/store/runtime-clients/thread-list-runtime-client.js +54 -52
  246. package/dist/store/runtime-clients/thread-list-runtime-client.js.map +1 -1
  247. package/dist/store/runtime-clients/thread-runtime-client.d.ts.map +1 -1
  248. package/dist/store/runtime-clients/thread-runtime-client.js +246 -126
  249. package/dist/store/runtime-clients/thread-runtime-client.js.map +1 -1
  250. package/dist/store/scope-registration.d.ts +2 -0
  251. package/dist/store/scope-registration.d.ts.map +1 -1
  252. package/dist/store/scopes/composer.d.ts +10 -2
  253. package/dist/store/scopes/composer.d.ts.map +1 -1
  254. package/dist/store/scopes/message.d.ts +30 -1
  255. package/dist/store/scopes/message.d.ts.map +1 -1
  256. package/dist/store/scopes/task.d.ts +36 -0
  257. package/dist/store/scopes/task.d.ts.map +1 -0
  258. package/dist/store/scopes/task.js +0 -0
  259. package/dist/store/scopes/thread-list-item.d.ts +2 -2
  260. package/dist/store/scopes/thread-list-item.d.ts.map +1 -1
  261. package/dist/store/scopes/thread.d.ts +28 -0
  262. package/dist/store/scopes/thread.d.ts.map +1 -1
  263. package/dist/store/scopes/threads.d.ts +1 -0
  264. package/dist/store/scopes/threads.d.ts.map +1 -1
  265. package/dist/subscribable/subscribable.d.ts +2 -1
  266. package/dist/subscribable/subscribable.d.ts.map +1 -1
  267. package/dist/subscribable/subscribable.js +23 -15
  268. package/dist/subscribable/subscribable.js.map +1 -1
  269. package/dist/types/attachment.d.ts +2 -1
  270. package/dist/types/attachment.d.ts.map +1 -1
  271. package/dist/types/attachment.js +2 -1
  272. package/dist/types/attachment.js.map +1 -1
  273. package/dist/types/index.d.ts +2 -2
  274. package/dist/types/message.d.ts +8 -1
  275. package/dist/types/message.d.ts.map +1 -1
  276. package/dist/types/message.js.map +1 -1
  277. package/dist/utils/abortable-iterable.d.ts +19 -0
  278. package/dist/utils/abortable-iterable.d.ts.map +1 -0
  279. package/dist/utils/abortable-iterable.js +88 -0
  280. package/dist/utils/abortable-iterable.js.map +1 -0
  281. package/dist/utils/composite-context-provider.d.ts.map +1 -1
  282. package/dist/utils/composite-context-provider.js +20 -2
  283. package/dist/utils/composite-context-provider.js.map +1 -1
  284. package/dist/utils/getGroupStatus.d.ts +18 -2
  285. package/dist/utils/getGroupStatus.d.ts.map +1 -1
  286. package/dist/utils/getGroupStatus.js +32 -7
  287. package/dist/utils/getGroupStatus.js.map +1 -1
  288. package/dist/utils/record.d.ts +11 -0
  289. package/dist/utils/record.d.ts.map +1 -0
  290. package/dist/utils/record.js +12 -0
  291. package/dist/utils/record.js.map +1 -0
  292. package/dist/utils/wire-media.d.ts.map +1 -1
  293. package/dist/utils/wire-media.js +2 -2
  294. package/dist/utils/wire-media.js.map +1 -1
  295. package/package.json +11 -11
  296. package/src/adapters/attachment.test.ts +50 -1
  297. package/src/adapters/attachment.ts +7 -4
  298. package/src/adapters/speech.test.ts +236 -0
  299. package/src/adapters/speech.ts +17 -10
  300. package/src/adapters/thread-history.ts +3 -0
  301. package/src/index.ts +2 -0
  302. package/src/internal.ts +4 -0
  303. package/src/model-context/frame/host.test.ts +137 -1
  304. package/src/model-context/frame/host.ts +49 -16
  305. package/src/model-context/frame/provider.test.ts +71 -0
  306. package/src/model-context/frame/provider.ts +37 -7
  307. package/src/model-context/interactable-composer-metadata.test.ts +58 -0
  308. package/src/model-context/interactable-composer-metadata.ts +19 -13
  309. package/src/model-context/registry.test.ts +12 -0
  310. package/src/model-context/registry.ts +3 -2
  311. package/src/model-context/types.test.ts +25 -0
  312. package/src/model-context/types.ts +9 -4
  313. package/src/react/RuntimeAdapter.test.ts +34 -0
  314. package/src/react/adapters/LocalStorageThreadListAdapter.test.ts +244 -0
  315. package/src/react/adapters/LocalStorageThreadListAdapter.tsx +104 -7
  316. package/src/react/client/DataRenderers.test.tsx +45 -0
  317. package/src/react/client/DataRenderers.ts +13 -9
  318. package/src/react/client/InMemoryThreadList.ts +1 -0
  319. package/src/react/client/Interactables.test.ts +72 -1
  320. package/src/react/client/Interactables.ts +22 -14
  321. package/src/react/client/RemoteThreadList.background.test.ts +148 -6
  322. package/src/react/client/RemoteThreadList.concurrent.test.tsx +42 -1
  323. package/src/react/client/RemoteThreadList.test.ts +386 -4
  324. package/src/react/client/RemoteThreadList.ts +181 -112
  325. package/src/react/client/Tools.ts +22 -11
  326. package/src/react/client/interactable-model-context.test.ts +44 -0
  327. package/src/react/client/interactable-model-context.ts +3 -2
  328. package/src/react/index.ts +5 -1
  329. package/src/react/interactables-legacy/Interactables.ts +16 -16
  330. package/src/react/interactables-legacy/useAssistantInteractable.test.tsx +132 -0
  331. package/src/react/interactables-legacy/useAssistantInteractable.ts +10 -1
  332. package/src/react/interactables-shared/useInteractablePersistenceQueue.ts +9 -10
  333. package/src/react/model-context/makeAssistantTool.ts +2 -2
  334. package/src/react/model-context/useAssistantTool.ts +2 -2
  335. package/src/react/model-context/useInteractable.test.tsx +177 -0
  336. package/src/react/model-context/useInteractable.ts +3 -0
  337. package/src/react/model-context/useToolArgsStatus.test.tsx +30 -0
  338. package/src/react/model-context/useToolArgsStatus.ts +2 -1
  339. package/src/react/primitive-hooks/useActionBarCopy.test.ts +0 -1
  340. package/src/react/primitive-hooks/useSuggestionTrigger.test.ts +0 -1
  341. package/src/react/primitives/message/MessageGroupedParts.test.tsx +96 -0
  342. package/src/react/primitives/message/MessageGroupedParts.tsx +15 -4
  343. package/src/react/primitives/part/PartMessages.test.tsx +104 -1
  344. package/src/react/primitives/part/PartMessages.tsx +1 -0
  345. package/src/react/primitives/thread/ThreadMessages.test.tsx +142 -0
  346. package/src/react/primitives/thread/ThreadMessages.tsx +8 -5
  347. package/src/react/providers/ReadonlyThreadProvider.test.tsx +56 -0
  348. package/src/react/runtimes/RemoteThreadListHookInstanceManager.destroy.test.tsx +172 -0
  349. package/src/react/runtimes/RemoteThreadListHookInstanceManager.running.test.tsx +33 -0
  350. package/src/react/runtimes/RemoteThreadListHookInstanceManager.test.tsx +7 -1
  351. package/src/react/runtimes/RemoteThreadListHookInstanceManager.tsx +28 -5
  352. package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.load-error.test.ts +132 -0
  353. package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.switch-delete.test.ts +105 -0
  354. package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.tsx +143 -112
  355. package/src/react/runtimes/RemoteThreadResource.test.ts +9 -0
  356. package/src/react/runtimes/RemoteThreadResource.ts +19 -12
  357. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.test.ts +20 -14
  358. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.test.tsx +703 -6
  359. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.ts +492 -402
  360. package/src/react/runtimes/cloud/CloudFileAttachmentAdapter.test.ts +77 -0
  361. package/src/react/runtimes/cloud/CloudFileAttachmentAdapter.ts +27 -1
  362. package/src/react/runtimes/cloud/auiV0.ts +160 -25
  363. package/src/react/runtimes/cloud/createCloudThreadListAdapter.test.ts +36 -0
  364. package/src/react/runtimes/cloud/createCloudThreadListAdapter.ts +8 -1
  365. package/src/react/runtimes/cloud/sdkIdentity.ts +9 -0
  366. package/src/react/runtimes/cloud/useCloudThreadListAdapter.test.tsx +18 -4
  367. package/src/react/runtimes/external-message-converter.test.ts +136 -1
  368. package/src/react/runtimes/external-message-converter.ts +39 -93
  369. package/src/react/runtimes/useExternalStoreRuntime.lifecycle.test.tsx +41 -0
  370. package/src/react/runtimes/useExternalStoreRuntime.ts +10 -4
  371. package/src/react/runtimes/useLocalRuntime.test.tsx +20 -0
  372. package/src/react/runtimes/useRemoteThreadListRuntime.load-error.test.tsx +108 -0
  373. package/src/react/runtimes/useRemoteThreadListRuntime.ts +34 -1
  374. package/src/react/utils/groupParts.ts +12 -1
  375. package/src/react/utils/useJSONEqual.ts +9 -0
  376. package/src/react/utils/useJSONSchemaDependency.ts +22 -0
  377. package/src/runtime/api/message-runtime.test.ts +75 -0
  378. package/src/runtime/api/thread-list-item-runtime.ts +10 -3
  379. package/src/runtime/api/thread-list-runtime.ts +21 -11
  380. package/src/runtime/api/thread-runtime.test.ts +136 -0
  381. package/src/runtime/api/thread-runtime.ts +10 -5
  382. package/src/runtime/base/base-composer-runtime-core.ts +105 -24
  383. package/src/runtime/base/base-thread-runtime-core.test.ts +1063 -2
  384. package/src/runtime/base/base-thread-runtime-core.ts +228 -87
  385. package/src/runtime/interfaces/composer-runtime-core.ts +10 -5
  386. package/src/runtime/interfaces/thread-list-runtime-core.ts +5 -1
  387. package/src/runtime/interfaces/thread-runtime-core.ts +6 -0
  388. package/src/runtime/queue/message-queue.ts +68 -6
  389. package/src/runtime/utils/auto-status.test.ts +112 -1
  390. package/src/runtime/utils/auto-status.ts +31 -5
  391. package/src/runtime/utils/external-message-conversion.test.ts +202 -0
  392. package/src/runtime/utils/external-message-conversion.ts +123 -32
  393. package/src/runtime/utils/message-repository.test.ts +49 -0
  394. package/src/runtime/utils/message-repository.ts +32 -20
  395. package/src/runtime/utils/thread-message-like.test.ts +52 -0
  396. package/src/runtime/utils/thread-message-like.ts +5 -1
  397. package/src/runtimes/external-store/external-store-thread-list-runtime-core.ts +18 -13
  398. package/src/runtimes/external-store/external-store-thread-runtime-core.ts +31 -1
  399. package/src/runtimes/internal.ts +1 -0
  400. package/src/runtimes/local/local-thread-runtime-core.test.ts +21 -0
  401. package/src/runtimes/local/local-thread-runtime-core.ts +11 -1
  402. package/src/runtimes/remote-thread-list/remote-thread-state.test.ts +128 -2
  403. package/src/runtimes/remote-thread-list/remote-thread-state.ts +182 -42
  404. package/src/runtimes/remote-thread-list/title-generation.test.ts +602 -0
  405. package/src/runtimes/remote-thread-list/title-generation.ts +329 -0
  406. package/src/runtimes/remote-thread-list/title.test.ts +62 -0
  407. package/src/runtimes/remote-thread-list/title.ts +13 -0
  408. package/src/runtimes/remote-thread-list/types.ts +10 -0
  409. package/src/runtimes/tool-invocations/EDGE_CASES.md +2 -6
  410. package/src/runtimes/tool-invocations/ToolInvocationTracker.test.ts +133 -0
  411. package/src/runtimes/tool-invocations/ToolInvocationTracker.ts +10 -6
  412. package/src/store/clients/external-thread.ts +67 -4
  413. package/src/store/clients/model-context-client.ts +5 -1
  414. package/src/store/clients/single-thread-list.ts +1 -0
  415. package/src/store/clients/suggestions.test.ts +40 -0
  416. package/src/store/clients/suggestions.ts +13 -10
  417. package/src/store/clients/thread-tasks.test.ts +274 -0
  418. package/src/store/clients/thread-tasks.ts +138 -0
  419. package/src/store/index.ts +8 -0
  420. package/src/store/primitive-predicates.test.ts +48 -5
  421. package/src/store/primitive-predicates.ts +7 -2
  422. package/src/store/runtime-clients/composer-runtime-client.ts +42 -9
  423. package/src/store/runtime-clients/message-runtime-client.ts +54 -6
  424. package/src/store/runtime-clients/thread-list-item-runtime-client.ts +4 -2
  425. package/src/store/runtime-clients/thread-list-runtime-client.ts +1 -0
  426. package/src/store/runtime-clients/thread-runtime-client.ts +89 -11
  427. package/src/store/scope-registration.ts +2 -0
  428. package/src/store/scopes/composer.ts +16 -4
  429. package/src/store/scopes/message.ts +14 -0
  430. package/src/store/scopes/task.ts +34 -0
  431. package/src/store/scopes/thread-list-item.ts +5 -2
  432. package/src/store/scopes/thread.ts +20 -0
  433. package/src/store/scopes/threads.ts +1 -0
  434. package/src/store/thread-tasks.test.tsx +209 -0
  435. package/src/subscribable/subscribable.test.ts +156 -1
  436. package/src/subscribable/subscribable.ts +25 -15
  437. package/src/tests/MessageRepository.test.ts +117 -5
  438. package/src/tests/OptimisticState-list-race.test.ts +1 -0
  439. package/src/tests/RemoteThreadListThreadListRuntimeCore-initialize-adapter-change.test.ts +38 -0
  440. package/src/tests/RemoteThreadListThreadListRuntimeCore-load-race.test.ts +47 -0
  441. package/src/tests/RemoteThreadListThreadListRuntimeCore-title-race.test.ts +89 -0
  442. package/src/tests/attachment-adapters.test.ts +14 -0
  443. package/src/tests/auiV0Encode.test.ts +300 -0
  444. package/src/tests/base-composer-runtime-core-send.test.ts +51 -0
  445. package/src/tests/base-composer-runtime-core.test.ts +353 -2
  446. package/src/tests/external-store-thread-list-runtime-core.test.ts +83 -0
  447. package/src/tests/external-store-thread-runtime-core-adapter.test.ts +178 -18
  448. package/src/tests/external-thread-attachments.test.tsx +208 -0
  449. package/src/tests/external-thread-parity.test.tsx +57 -0
  450. package/src/tests/groupParts.test.ts +71 -0
  451. package/src/tests/message-queue.test.ts +253 -0
  452. package/src/tests/remote-thread-list-isLoading.test.ts +1 -0
  453. package/src/tests/remote-thread-list-reactive-threadId.test.ts +51 -0
  454. package/src/tests/thread-list-runtime-getLoadThreadsPromise.test.ts +1 -0
  455. package/src/tests/thread-switch-events.test.tsx +78 -0
  456. package/src/tests/tools-scope-migration.test.tsx +28 -0
  457. package/src/tests/useRemoteThreadListRuntime-controlled.test.tsx +43 -0
  458. package/src/types/attachment.ts +4 -0
  459. package/src/types/index.ts +1 -0
  460. package/src/types/message.ts +8 -0
  461. package/src/utils/abortable-iterable.test.ts +328 -0
  462. package/src/utils/abortable-iterable.ts +104 -0
  463. package/src/utils/composite-context-provider.test.ts +25 -0
  464. package/src/utils/composite-context-provider.ts +23 -2
  465. package/src/utils/getGroupStatus.test.ts +70 -4
  466. package/src/utils/getGroupStatus.ts +35 -12
  467. package/src/utils/record.test.ts +48 -0
  468. package/src/utils/record.ts +11 -0
  469. package/src/utils/wire-media.test.ts +10 -0
  470. package/src/utils/wire-media.ts +6 -2
@@ -7,6 +7,7 @@ import {
7
7
  WritableSubscribable,
8
8
  } from "../../subscribable/subscribable";
9
9
  import { useSubscribable } from "../../store/runtime-clients/useSubscribable";
10
+ import { nullProtoRecord } from "../../utils/record";
10
11
  import { OptimisticState } from "../../runtimes/remote-thread-list/optimistic-state";
11
12
  import { EMPTY_THREAD_CORE } from "../../runtimes/remote-thread-list/empty-thread-core";
12
13
  import type {
@@ -20,6 +21,8 @@ import {
20
21
  createThreadMappingId,
21
22
  getThreadData,
22
23
  normalizeCursor,
24
+ reconcileInitializedThread,
25
+ promoteNewThreadReducer,
23
26
  updateStatusReducer,
24
27
  preserveMidLoadTransitions,
25
28
  seedNewThread,
@@ -32,7 +35,17 @@ import type {
32
35
  } from "../../runtimes/remote-thread-list/types";
33
36
  import { ThreadListAdapterChangedError } from "../../runtimes/remote-thread-list/adapter-changed";
34
37
  import { RemoteThreadListHookInstanceManager } from "./RemoteThreadListHookInstanceManager";
35
- import { isTitleSourceMessage } from "../../runtimes/remote-thread-list/title";
38
+ import {
39
+ applyTitleStream,
40
+ isTitleSourceMessage,
41
+ } from "../../runtimes/remote-thread-list/title";
42
+ import {
43
+ clearThreadTitleState,
44
+ finishThreadTitleRename,
45
+ runThreadTitleGeneration,
46
+ startThreadTitleRename,
47
+ type ThreadTitleState,
48
+ } from "../../runtimes/remote-thread-list/title-generation";
36
49
  import {
37
50
  type ComponentType,
38
51
  type FC,
@@ -42,10 +55,10 @@ import {
42
55
  useId,
43
56
  } from "react";
44
57
  import { useAui } from "@assistant-ui/store";
45
- import { AssistantMessageStream } from "assistant-stream";
46
58
  import type { ModelContextProvider } from "../../model-context/types";
47
59
  import { RuntimeAdapterProvider } from "./RuntimeAdapterProvider";
48
60
  import { useStableRuntimeAdapters } from "./useRuntimeAdapters";
61
+ import { invokeUserCallback } from "../../utils/invoke-user-callback";
49
62
 
50
63
  const threadNotFoundError = (threadIdOrRemoteId: string, action: string) =>
51
64
  new Error(`Thread "${threadIdOrRemoteId}" not found while ${action}.`);
@@ -77,6 +90,7 @@ export class RemoteThreadListThreadListRuntimeCore
77
90
  private _staleThreadIdsOnReplace: ReadonlySet<string> | undefined;
78
91
  private _switchGeneration = 0;
79
92
  private _switchTask: Promise<void> | undefined;
93
+ private readonly _titleStates = new Map<string, ThreadTitleState>();
80
94
 
81
95
  private _mainThreadId!: string;
82
96
  private readonly _state = new OptimisticState<RemoteThreadState>(
@@ -137,6 +151,7 @@ export class RemoteThreadListThreadListRuntimeCore
137
151
  return {
138
152
  ...state,
139
153
  isLoading: true,
154
+ loadError: undefined,
140
155
  };
141
156
  },
142
157
  then: (state, l) => {
@@ -146,7 +161,7 @@ export class RemoteThreadListThreadListRuntimeCore
146
161
  this._replaceListOnNextLoad = false;
147
162
  replacedList = true;
148
163
  return this._replaceWithThreads(
149
- state,
164
+ { ...state, loadError: undefined },
150
165
  l.threads,
151
166
  normalizeCursor(l.nextCursor),
152
167
  );
@@ -161,6 +176,7 @@ export class RemoteThreadListThreadListRuntimeCore
161
176
  const merged = {
162
177
  ...state,
163
178
  isLoading: false,
179
+ loadError: undefined,
164
180
  cursor: normalizeCursor(l.nextCursor),
165
181
  threadIds: fresh.threadIds,
166
182
  archivedThreadIds: fresh.archivedThreadIds,
@@ -178,13 +194,18 @@ export class RemoteThreadListThreadListRuntimeCore
178
194
  this._state.update({
179
195
  ...this._state.baseValue,
180
196
  isLoading: false,
197
+ loadError: error,
181
198
  });
182
199
  return;
183
200
  }
184
201
  this._replaceListOnNextLoad = false;
185
202
  replacedList = true;
186
203
  this._state.update(
187
- this._replaceWithThreads(this._state.baseValue, [], undefined),
204
+ this._replaceWithThreads(
205
+ { ...this._state.baseValue, loadError: error },
206
+ [],
207
+ undefined,
208
+ ),
188
209
  );
189
210
  })
190
211
  .then(() => {
@@ -320,7 +341,9 @@ export class RemoteThreadListThreadListRuntimeCore
320
341
  this._state.update({
321
342
  ...this._state.baseValue,
322
343
  cursor: undefined,
344
+ loadError: undefined,
323
345
  });
346
+ this._titleStates.clear();
324
347
  }
325
348
 
326
349
  if (controlledThreadIdChanged) {
@@ -347,8 +370,13 @@ export class RemoteThreadListThreadListRuntimeCore
347
370
  ): RemoteThreadState {
348
371
  const carried: RemoteThreadData[] = [];
349
372
  if (state.newThreadId) {
350
- const mappingId = state.threadIdMap[state.newThreadId];
351
- const draft = mappingId ? state.threadData[mappingId] : undefined;
373
+ const mappingId = Object.hasOwn(state.threadIdMap, state.newThreadId)
374
+ ? state.threadIdMap[state.newThreadId]
375
+ : undefined;
376
+ const draft =
377
+ mappingId && Object.hasOwn(state.threadData, mappingId)
378
+ ? state.threadData[mappingId]
379
+ : undefined;
352
380
  if (draft?.status === "new") carried.push(draft);
353
381
  }
354
382
 
@@ -365,12 +393,12 @@ export class RemoteThreadListThreadListRuntimeCore
365
393
  const seed: ClassifyAccumulator = {
366
394
  threadIds: [],
367
395
  archivedThreadIds: [],
368
- threadIdMap: {},
369
- threadData: {},
396
+ threadIdMap: nullProtoRecord(),
397
+ threadData: nullProtoRecord(),
370
398
  };
371
399
  for (const item of carried) {
372
400
  const mappingId = createThreadMappingId(item.id);
373
- if (seed.threadData[mappingId]) continue;
401
+ if (Object.hasOwn(seed.threadData, mappingId)) continue;
374
402
  seed.threadIdMap[item.id] = mappingId;
375
403
  if (item.remoteId !== undefined) {
376
404
  seed.threadIdMap[item.remoteId] = mappingId;
@@ -383,7 +411,10 @@ export class RemoteThreadListThreadListRuntimeCore
383
411
 
384
412
  for (const item of carried) {
385
413
  if (item.remoteId === undefined) continue;
386
- const current = threadData[createThreadMappingId(item.id)];
414
+ const currentMappingId = createThreadMappingId(item.id);
415
+ const current = Object.hasOwn(threadData, currentMappingId)
416
+ ? threadData[currentMappingId]
417
+ : undefined;
387
418
  if (current === undefined) continue;
388
419
  if (current.status === "regular" && !threadIds.includes(current.id)) {
389
420
  threadIds.push(current.id);
@@ -405,7 +436,7 @@ export class RemoteThreadListThreadListRuntimeCore
405
436
  threadData,
406
437
  newThreadId:
407
438
  state.newThreadId !== undefined &&
408
- threadIdMap[state.newThreadId] === undefined
439
+ !Object.hasOwn(threadIdMap, state.newThreadId)
409
440
  ? undefined
410
441
  : state.newThreadId,
411
442
  };
@@ -501,6 +532,10 @@ export class RemoteThreadListThreadListRuntimeCore
501
532
  return this._state.value.isLoading;
502
533
  }
503
534
 
535
+ public get loadError() {
536
+ return this._state.value.loadError;
537
+ }
538
+
504
539
  public get isLoadingMore() {
505
540
  return this._state.value.isLoadingMore;
506
541
  }
@@ -539,7 +574,12 @@ export class RemoteThreadListThreadListRuntimeCore
539
574
  if (this._lastNotifiedThreadId === threadId) return;
540
575
  this._lastNotifiedThreadId = threadId;
541
576
  if (emit) {
542
- this._options.onThreadIdChange?.(threadId);
577
+ invokeUserCallback(
578
+ "assistant-ui",
579
+ "onThreadIdChange",
580
+ this._options.onThreadIdChange,
581
+ threadId,
582
+ );
543
583
  }
544
584
  }
545
585
 
@@ -778,71 +818,40 @@ export class RemoteThreadListThreadListRuntimeCore
778
818
  return { remoteId, externalId };
779
819
  }
780
820
 
821
+ this._requireAdapterGeneration(adapterGeneration);
822
+ const initializeTask = adapter.initialize(threadId);
823
+ let removedMappingId: string | undefined;
781
824
  const { remoteId, externalId } = await this._state.optimisticUpdate({
782
- execute: () => {
783
- this._requireAdapterGeneration(adapterGeneration);
784
- return adapter.initialize(threadId);
785
- },
786
- optimistic: (state) => {
787
- return updateStatusReducer(state, threadId, "regular");
788
- },
789
- loading: (state, task) => {
790
- const mappingId = createThreadMappingId(threadId);
791
- return {
792
- ...state,
793
- threadData: {
794
- ...state.threadData,
795
- [mappingId]: {
796
- ...state.threadData[mappingId],
797
- initializeTask: task,
798
- },
799
- },
800
- };
801
- },
825
+ execute: () => initializeTask,
826
+ optimistic: (state) =>
827
+ promoteNewThreadReducer(state, threadId, initializeTask),
802
828
  then: (state, { remoteId, externalId }) => {
803
829
  if (adapterGeneration !== this._adapterGeneration) return state;
804
- const data = getThreadData(state, threadId);
805
- if (!data) return state;
806
-
807
- const mappingId = createThreadMappingId(threadId);
808
- // A list() response that landed while this initialize was in flight
809
- // could not know the remote id yet, so it may have minted its own slot
810
- // for it; that slot collapses into this one.
811
- const listedMappingId = state.threadIdMap[remoteId];
812
- const orphan =
813
- listedMappingId !== undefined && listedMappingId !== mappingId
814
- ? state.threadData[listedMappingId]
815
- : undefined;
816
-
817
- const threadData = { ...state.threadData };
818
- if (orphan !== undefined) delete threadData[listedMappingId!];
819
- threadData[mappingId] = {
820
- ...data,
821
- initializeTask: Promise.resolve({ remoteId, externalId }),
830
+ const reconciliation = reconcileInitializedThread(
831
+ state,
832
+ threadId,
822
833
  remoteId,
823
834
  externalId,
824
- } as RemoteThreadData;
825
-
826
- const rewire = (ids: readonly string[]) =>
827
- orphan === undefined ? ids : ids.filter((id) => id !== orphan.id);
828
-
829
- return {
830
- ...state,
831
- threadIds: rewire(state.threadIds),
832
- archivedThreadIds: rewire(state.archivedThreadIds),
833
- threadIdMap: {
834
- ...state.threadIdMap,
835
- [remoteId]: mappingId,
836
- },
837
- threadData,
838
- };
835
+ threadId,
836
+ );
837
+ removedMappingId = reconciliation.removedMappingId;
838
+ if (removedMappingId === this._mainThreadId) {
839
+ this._mainThreadId = reconciliation.survivorMappingId;
840
+ }
841
+ return reconciliation.state;
839
842
  },
840
843
  });
841
844
  this._requireAdapterGeneration(adapterGeneration);
845
+ if (removedMappingId !== undefined) {
846
+ this._hookManager.stopThreadRuntime(removedMappingId);
847
+ }
842
848
  return { remoteId, externalId };
843
849
  };
844
850
 
845
- public generateTitle = async (threadId: string) => {
851
+ public generateTitle = async (
852
+ threadId: string,
853
+ options?: { automatic?: boolean },
854
+ ) => {
846
855
  this._requireAdapterSettled();
847
856
  const adapter = this._options.adapter;
848
857
  const adapterGeneration = this._adapterGeneration;
@@ -861,30 +870,40 @@ export class RemoteThreadListThreadListRuntimeCore
861
870
  // would make the payload race-dependent; the title reads settled
862
871
  // messages only, matching the trigger's readiness gate.
863
872
  const messages = runtimeCore.messages.filter(isTitleSourceMessage);
864
- const stream = await adapter.generateTitle(remoteId, messages);
865
- const messageStream = AssistantMessageStream.fromAssistantStream(stream);
866
- for await (const result of messageStream) {
867
- if (adapterGeneration !== this._adapterGeneration) return;
868
- const newTitle = result.parts.filter((c) => c.type === "text")[0]?.text;
869
- await this._state.optimisticUpdate({
870
- execute: async () => {},
871
- optimistic: (state) => {
872
- if (adapterGeneration !== this._adapterGeneration) return state;
873
- const currentData = getThreadData(state, data.id);
874
- if (!currentData) return state;
875
- return {
876
- ...state,
877
- threadData: {
878
- ...state.threadData,
879
- [currentData.id]: {
880
- ...currentData,
881
- title: newTitle,
873
+ await runThreadTitleGeneration({
874
+ states: this._titleStates,
875
+ threadId: data.id,
876
+ automatic: options?.automatic === true,
877
+ generate: async (onTitle) => {
878
+ const stream = await adapter.generateTitle(remoteId, messages);
879
+ this._requireAdapterGeneration(adapterGeneration);
880
+ await applyTitleStream(stream, onTitle);
881
+ },
882
+ rename: async (title) => {
883
+ this._requireAdapterGeneration(adapterGeneration);
884
+ await adapter.rename(remoteId, title);
885
+ },
886
+ applyTitle: async (title) => {
887
+ await this._state.optimisticUpdate({
888
+ execute: async () => {},
889
+ optimistic: (state) => {
890
+ if (adapterGeneration !== this._adapterGeneration) return state;
891
+ const currentData = getThreadData(state, data.id);
892
+ if (!currentData) return state;
893
+ return {
894
+ ...state,
895
+ threadData: {
896
+ ...state.threadData,
897
+ [currentData.id]: {
898
+ ...currentData,
899
+ title,
900
+ },
882
901
  },
883
- },
884
- };
885
- },
886
- });
887
- }
902
+ };
903
+ },
904
+ });
905
+ },
906
+ });
888
907
  };
889
908
 
890
909
  public async rename(
@@ -899,28 +918,36 @@ export class RemoteThreadListThreadListRuntimeCore
899
918
  if (data.status === "new")
900
919
  throw threadStatusError(threadIdOrRemoteId, data.status, "be renamed");
901
920
 
902
- return this._state.optimisticUpdate({
903
- execute: async () => {
904
- const { remoteId } = await data.initializeTask;
905
- this._requireAdapterGeneration(adapterGeneration);
906
- return adapter.rename(remoteId, newTitle);
907
- },
908
- optimistic: (state) => {
909
- const data = getThreadData(state, threadIdOrRemoteId);
910
- if (!data) return state;
921
+ const claim = startThreadTitleRename(this._titleStates, data.id, newTitle);
922
+ try {
923
+ const result = await this._state.optimisticUpdate({
924
+ execute: async () => {
925
+ const { remoteId } = await data.initializeTask;
926
+ this._requireAdapterGeneration(adapterGeneration);
927
+ return adapter.rename(remoteId, newTitle);
928
+ },
929
+ optimistic: (state) => {
930
+ const currentData = getThreadData(state, threadIdOrRemoteId);
931
+ if (!currentData) return state;
911
932
 
912
- return {
913
- ...state,
914
- threadData: {
915
- ...state.threadData,
916
- [data.id]: {
917
- ...data,
918
- title: newTitle,
933
+ return {
934
+ ...state,
935
+ threadData: {
936
+ ...state.threadData,
937
+ [currentData.id]: {
938
+ ...currentData,
939
+ title: newTitle,
940
+ },
919
941
  },
920
- },
921
- };
922
- },
923
- });
942
+ };
943
+ },
944
+ });
945
+ finishThreadTitleRename(this._titleStates, data.id, claim, true);
946
+ return result;
947
+ } catch (error) {
948
+ finishThreadTitleRename(this._titleStates, data.id, claim, false);
949
+ throw error;
950
+ }
924
951
  }
925
952
 
926
953
  public async updateCustom(
@@ -1063,9 +1090,7 @@ export class RemoteThreadListThreadListRuntimeCore
1063
1090
 
1064
1091
  await this._ensureThreadIsNotMain(data.id);
1065
1092
  this._requireAdapterGeneration(adapterGeneration);
1066
- this._hookManager.stopThreadRuntime(data.id);
1067
-
1068
- return this._state.optimisticUpdate({
1093
+ const result = await this._state.optimisticUpdate({
1069
1094
  execute: async () => {
1070
1095
  const { remoteId } = await data.initializeTask;
1071
1096
  this._requireAdapterGeneration(adapterGeneration);
@@ -1075,6 +1100,12 @@ export class RemoteThreadListThreadListRuntimeCore
1075
1100
  return updateStatusReducer(state, data.id, "deleted");
1076
1101
  },
1077
1102
  });
1103
+ // The optimistic layer survives an adapter swap, so a resolved deletion has
1104
+ // dropped the slot from `threadData`, where `_replaceWithThreads` would
1105
+ // otherwise have found it to stop.
1106
+ this._hookManager.stopThreadRuntime(data.id);
1107
+ clearThreadTitleState(this._titleStates, data.id);
1108
+ return result;
1078
1109
  }
1079
1110
 
1080
1111
  public __internal_dispose() {
@@ -53,6 +53,9 @@ describe("subscribeToTitleGeneration", () => {
53
53
 
54
54
  await vi.waitFor(() => {
55
55
  expect(itemRuntime.generateTitle).toHaveBeenCalledOnce();
56
+ expect(itemRuntime.generateTitle).toHaveBeenCalledWith({
57
+ automatic: true,
58
+ });
56
59
  expect(consoleError).toHaveBeenCalledWith(
57
60
  "[assistant-ui] Thread title generation failed",
58
61
  error,
@@ -97,6 +100,9 @@ describe("subscribeToTitleGeneration", () => {
97
100
 
98
101
  await vi.waitFor(() => {
99
102
  expect(itemRuntime.generateTitle).toHaveBeenCalledOnce();
103
+ expect(itemRuntime.generateTitle).toHaveBeenCalledWith({
104
+ automatic: true,
105
+ });
100
106
  });
101
107
  });
102
108
 
@@ -136,6 +142,9 @@ describe("subscribeToTitleGeneration", () => {
136
142
 
137
143
  await vi.waitFor(() => {
138
144
  expect(itemRuntime.generateTitle).toHaveBeenCalledOnce();
145
+ expect(itemRuntime.generateTitle).toHaveBeenCalledWith({
146
+ automatic: true,
147
+ });
139
148
  });
140
149
  });
141
150
  });
@@ -3,6 +3,7 @@ import { resource } from "@assistant-ui/tap";
3
3
  import {
4
4
  useAssistantContextProvider,
5
5
  useConfiguredAui,
6
+ useDestroySignalProvider,
6
7
  } from "@assistant-ui/store/client";
7
8
  import { ThreadListItemClient } from "../../store/internal";
8
9
  import type { AssistantRuntime } from "../../runtime/api/assistant-runtime";
@@ -38,6 +39,7 @@ export type RemoteThreadResourceProps = {
38
39
  runtime: ThreadRuntimeCore,
39
40
  generation: number,
40
41
  ) => void;
42
+ destroySignal: AbortSignal;
41
43
  };
42
44
 
43
45
  export const subscribeToTitleGeneration = (
@@ -45,10 +47,12 @@ export const subscribeToTitleGeneration = (
45
47
  itemRuntime: ThreadListItemRuntime,
46
48
  ) => {
47
49
  const generate = () =>
48
- void itemRuntime.generateTitle().catch((error: unknown) => {
49
- if (isSilentRuntimeAction(error)) return;
50
- console.error("[assistant-ui] Thread title generation failed", error);
51
- });
50
+ void itemRuntime
51
+ .generateTitle({ automatic: true })
52
+ .catch((error: unknown) => {
53
+ if (isSilentRuntimeAction(error)) return;
54
+ console.error("[assistant-ui] Thread title generation failed", error);
55
+ });
52
56
 
53
57
  const hasTitleSource = () =>
54
58
  threadRuntime.getState().messages.some(isTitleSourceMessage);
@@ -178,6 +182,7 @@ const useRemoteThreadResource = ({
178
182
  parentClient,
179
183
  adapters,
180
184
  publish,
185
+ destroySignal,
181
186
  }: RemoteThreadResourceProps) => {
182
187
  const itemRuntime = useMemo(
183
188
  () =>
@@ -214,14 +219,16 @@ const useRemoteThreadResource = ({
214
219
  threadListItem: ThreadListItemClient({ runtime: itemRuntime }),
215
220
  });
216
221
 
217
- return useAssistantContextProvider(client, function useThreadClient() {
218
- return useRuntimeAdaptersProvider(adapters, function useBoundRuntime() {
219
- return useRemoteThreadBinder({
220
- threadId,
221
- generation,
222
- runtimeHook,
223
- publish,
224
- itemRuntime,
222
+ return useDestroySignalProvider(destroySignal, function useOwnedThread() {
223
+ return useAssistantContextProvider(client, function useThreadClient() {
224
+ return useRuntimeAdaptersProvider(adapters, function useBoundRuntime() {
225
+ return useRemoteThreadBinder({
226
+ threadId,
227
+ generation,
228
+ runtimeHook,
229
+ publish,
230
+ itemRuntime,
231
+ });
225
232
  });
226
233
  });
227
234
  });
@@ -28,8 +28,8 @@ describe("extractAuiV0", () => {
28
28
  it("reports a terminal message once with its usage", () => {
29
29
  const result = extractAuiV0(auiV0Message({ type: "complete" }));
30
30
  expect(result?.status).toBe("completed");
31
- expect(result?.inputTokens).toBe(1);
32
- expect(result?.outputTokens).toBe(2);
31
+ expect(result?.usage?.inputTokens).toBe(1);
32
+ expect(result?.usage?.outputTokens).toBe(2);
33
33
  });
34
34
 
35
35
  it("sums step usage reported under the AI SDK v7 token details", () => {
@@ -57,22 +57,28 @@ describe("extractAuiV0", () => {
57
57
  },
58
58
  });
59
59
 
60
- expect(result?.inputTokens).toBe(15);
61
- expect(result?.outputTokens).toBe(6);
62
- expect(result?.cachedInputTokens).toBe(9);
63
- expect(result?.reasoningTokens).toBe(2);
60
+ expect(result?.usage).toEqual({
61
+ inputTokens: 15,
62
+ outputTokens: 6,
63
+ cachedInputTokens: 9,
64
+ reasoningTokens: 2,
65
+ });
64
66
  expect(result?.steps).toEqual([
65
67
  {
66
- input_tokens: 10,
67
- output_tokens: 4,
68
- reasoning_tokens: 1,
69
- cached_input_tokens: 6,
68
+ usage: {
69
+ inputTokens: 10,
70
+ outputTokens: 4,
71
+ inputTokenDetails: { cacheReadTokens: 6 },
72
+ outputTokenDetails: { reasoningTokens: 1 },
73
+ },
70
74
  },
71
75
  {
72
- input_tokens: 5,
73
- output_tokens: 2,
74
- reasoning_tokens: 1,
75
- cached_input_tokens: 3,
76
+ usage: {
77
+ inputTokens: 5,
78
+ outputTokens: 2,
79
+ inputTokenDetails: { cacheReadTokens: 3 },
80
+ outputTokenDetails: { reasoningTokens: 1 },
81
+ },
76
82
  },
77
83
  ]);
78
84
  });