@assistant-ui/core 0.3.15 → 0.3.17

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 (455) hide show
  1. package/dist/index.d.ts +2 -2
  2. package/dist/index.js +2 -2
  3. package/dist/index.js.map +1 -1
  4. package/dist/internal.d.ts +8 -2
  5. package/dist/internal.js +9 -3
  6. package/dist/model-context/frame/host.d.ts.map +1 -1
  7. package/dist/model-context/frame/host.js +3 -2
  8. package/dist/model-context/frame/host.js.map +1 -1
  9. package/dist/model-context/frame/provider.d.ts +5 -0
  10. package/dist/model-context/frame/provider.d.ts.map +1 -1
  11. package/dist/model-context/frame/provider.js +141 -28
  12. package/dist/model-context/frame/provider.js.map +1 -1
  13. package/dist/model-context/interactable-composer-metadata.d.ts +1 -1
  14. package/dist/model-context/interactable-composer-metadata.js +1 -1
  15. package/dist/model-context/interactable-composer-metadata.js.map +1 -1
  16. package/dist/model-context/registry.d.ts +2 -2
  17. package/dist/model-context/registry.d.ts.map +1 -1
  18. package/dist/model-context/registry.js +9 -28
  19. package/dist/model-context/registry.js.map +1 -1
  20. package/dist/model-context/tool-call-text.d.ts +26 -0
  21. package/dist/model-context/tool-call-text.d.ts.map +1 -0
  22. package/dist/model-context/tool-call-text.js +18 -0
  23. package/dist/model-context/tool-call-text.js.map +1 -0
  24. package/dist/react/RuntimeAdapter.js +1 -1
  25. package/dist/react/adapters/LocalStorageThreadListAdapter.d.ts.map +1 -1
  26. package/dist/react/adapters/LocalStorageThreadListAdapter.js +1 -1
  27. package/dist/react/adapters/LocalStorageThreadListAdapter.js.map +1 -1
  28. package/dist/react/client/AdaptedRemoteThread.js +1 -1
  29. package/dist/react/client/InMemoryThreadList.d.ts.map +1 -1
  30. package/dist/react/client/InMemoryThreadList.js +25 -21
  31. package/dist/react/client/InMemoryThreadList.js.map +1 -1
  32. package/dist/react/client/Interactables.d.ts.map +1 -1
  33. package/dist/react/client/Interactables.js +60 -178
  34. package/dist/react/client/Interactables.js.map +1 -1
  35. package/dist/react/client/RemoteThreadList.d.ts +15 -0
  36. package/dist/react/client/RemoteThreadList.d.ts.map +1 -1
  37. package/dist/react/client/RemoteThreadList.js +263 -194
  38. package/dist/react/client/RemoteThreadList.js.map +1 -1
  39. package/dist/react/client/Tools.d.ts.map +1 -1
  40. package/dist/react/client/Tools.js +6 -2
  41. package/dist/react/client/Tools.js.map +1 -1
  42. package/dist/react/index.d.ts +4 -2
  43. package/dist/react/index.js +2 -1
  44. package/dist/react/interactables-legacy/Interactables.d.ts.map +1 -1
  45. package/dist/react/interactables-legacy/Interactables.js +60 -178
  46. package/dist/react/interactables-legacy/Interactables.js.map +1 -1
  47. package/dist/react/interactables-shared/useInteractablePersistenceQueue.d.ts +24 -0
  48. package/dist/react/interactables-shared/useInteractablePersistenceQueue.d.ts.map +1 -0
  49. package/dist/react/interactables-shared/useInteractablePersistenceQueue.js +138 -0
  50. package/dist/react/interactables-shared/useInteractablePersistenceQueue.js.map +1 -0
  51. package/dist/react/model-context/toolbox.d.ts +2 -14
  52. package/dist/react/model-context/toolbox.d.ts.map +1 -1
  53. package/dist/react/model-context/toolbox.js +1 -13
  54. package/dist/react/model-context/toolbox.js.map +1 -1
  55. package/dist/react/model-context/useAssistantContext.js +37 -7
  56. package/dist/react/model-context/useAssistantContext.js.map +1 -1
  57. package/dist/react/model-context/useAuiToolOverrides.js +31 -5
  58. package/dist/react/model-context/useAuiToolOverrides.js.map +1 -1
  59. package/dist/react/model-context/useInlineRender.d.ts.map +1 -1
  60. package/dist/react/model-context/useInlineRender.js +10 -36
  61. package/dist/react/model-context/useInlineRender.js.map +1 -1
  62. package/dist/react/primitive-hooks/useMessageError.d.ts.map +1 -1
  63. package/dist/react/primitive-hooks/useMessageError.js +2 -8
  64. package/dist/react/primitive-hooks/useMessageError.js.map +1 -1
  65. package/dist/react/primitive-hooks/useThreadListLoadMore.d.ts.map +1 -1
  66. package/dist/react/primitive-hooks/useThreadListLoadMore.js +2 -4
  67. package/dist/react/primitive-hooks/useThreadListLoadMore.js.map +1 -1
  68. package/dist/react/primitives/composer/ComposerAttachments.d.ts.map +1 -1
  69. package/dist/react/primitives/composer/ComposerAttachments.js +4 -3
  70. package/dist/react/primitives/composer/ComposerAttachments.js.map +1 -1
  71. package/dist/react/primitives/composer/ComposerIf.js.map +1 -1
  72. package/dist/react/primitives/composer/ComposerQueue.d.ts +2 -1
  73. package/dist/react/primitives/composer/ComposerQueue.d.ts.map +1 -1
  74. package/dist/react/primitives/composer/ComposerQueue.js +4 -3
  75. package/dist/react/primitives/composer/ComposerQueue.js.map +1 -1
  76. package/dist/react/primitives/message/MessageAttachments.d.ts.map +1 -1
  77. package/dist/react/primitives/message/MessageAttachments.js +7 -6
  78. package/dist/react/primitives/message/MessageAttachments.js.map +1 -1
  79. package/dist/react/primitives/message/MessageGroupedParts.js +2 -2
  80. package/dist/react/primitives/message/MessageGroupedParts.js.map +1 -1
  81. package/dist/react/primitives/message/MessageParts.js +3 -3
  82. package/dist/react/primitives/message/MessageParts.js.map +1 -1
  83. package/dist/react/primitives/threadList/ThreadListItems.d.ts.map +1 -1
  84. package/dist/react/primitives/threadList/ThreadListItems.js +5 -4
  85. package/dist/react/primitives/threadList/ThreadListItems.js.map +1 -1
  86. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts +7 -5
  87. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts.map +1 -1
  88. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js +44 -22
  89. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js.map +1 -1
  90. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts +7 -6
  91. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts.map +1 -1
  92. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js +102 -117
  93. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js.map +1 -1
  94. package/dist/react/runtimes/RemoteThreadResource.d.ts +1 -6
  95. package/dist/react/runtimes/RemoteThreadResource.d.ts.map +1 -1
  96. package/dist/react/runtimes/RemoteThreadResource.js +3 -3
  97. package/dist/react/runtimes/RemoteThreadResource.js.map +1 -1
  98. package/dist/react/runtimes/assistant-transport/runManager.d.ts.map +1 -1
  99. package/dist/react/runtimes/assistant-transport/runManager.js +2 -12
  100. package/dist/react/runtimes/assistant-transport/runManager.js.map +1 -1
  101. package/dist/react/runtimes/assistant-transport/useLatestRef.js +2 -2
  102. package/dist/react/runtimes/assistant-transport/useLatestRef.js.map +1 -1
  103. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts +3 -10
  104. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts.map +1 -1
  105. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js +43 -85
  106. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js.map +1 -1
  107. package/dist/react/runtimes/cloud/auiV0.d.ts +5 -1
  108. package/dist/react/runtimes/cloud/auiV0.d.ts.map +1 -1
  109. package/dist/react/runtimes/cloud/auiV0.js.map +1 -1
  110. package/dist/react/runtimes/cloud/createCloudThreadListAdapter.d.ts +29 -0
  111. package/dist/react/runtimes/cloud/createCloudThreadListAdapter.d.ts.map +1 -0
  112. package/dist/react/runtimes/cloud/createCloudThreadListAdapter.js +159 -0
  113. package/dist/react/runtimes/cloud/createCloudThreadListAdapter.js.map +1 -0
  114. package/dist/react/runtimes/cloud/createCloudThreadListAdapterCreateFallback.d.ts +12 -0
  115. package/dist/react/runtimes/cloud/createCloudThreadListAdapterCreateFallback.d.ts.map +1 -0
  116. package/dist/react/runtimes/cloud/createCloudThreadListAdapterCreateFallback.js +10 -0
  117. package/dist/react/runtimes/cloud/createCloudThreadListAdapterCreateFallback.js.map +1 -0
  118. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.d.ts +1 -9
  119. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.d.ts.map +1 -1
  120. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js +16 -153
  121. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js.map +1 -1
  122. package/dist/react/runtimes/cloud/useCloudThreadListRuntime.js.map +1 -1
  123. package/dist/react/runtimes/createMessageConverter.d.ts +2 -1
  124. package/dist/react/runtimes/createMessageConverter.d.ts.map +1 -1
  125. package/dist/react/runtimes/external-message-converter.d.ts +6 -25
  126. package/dist/react/runtimes/external-message-converter.d.ts.map +1 -1
  127. package/dist/react/runtimes/external-message-converter.js +33 -233
  128. package/dist/react/runtimes/external-message-converter.js.map +1 -1
  129. package/dist/react/runtimes/useRemoteThreadListRuntime.d.ts.map +1 -1
  130. package/dist/react/runtimes/useRemoteThreadListRuntime.js +14 -6
  131. package/dist/react/runtimes/useRemoteThreadListRuntime.js.map +1 -1
  132. package/dist/react/types/MessagePartComponentTypes.d.ts +7 -3
  133. package/dist/react/types/MessagePartComponentTypes.d.ts.map +1 -1
  134. package/dist/react/types/scopes/tools.d.ts +2 -0
  135. package/dist/react/types/scopes/tools.d.ts.map +1 -1
  136. package/dist/runtime/api/composer-runtime.d.ts +1 -1
  137. package/dist/runtime/api/composer-runtime.js.map +1 -1
  138. package/dist/runtime/api/message-part-runtime.d.ts +2 -2
  139. package/dist/runtime/api/message-part-runtime.d.ts.map +1 -1
  140. package/dist/runtime/api/message-part-runtime.js +1 -1
  141. package/dist/runtime/api/message-part-runtime.js.map +1 -1
  142. package/dist/runtime/api/thread-list-runtime.d.ts +9 -1
  143. package/dist/runtime/api/thread-list-runtime.d.ts.map +1 -1
  144. package/dist/runtime/api/thread-list-runtime.js +5 -0
  145. package/dist/runtime/api/thread-list-runtime.js.map +1 -1
  146. package/dist/runtime/api/thread-runtime.d.ts +2 -3
  147. package/dist/runtime/api/thread-runtime.d.ts.map +1 -1
  148. package/dist/runtime/base/base-composer-runtime-core.d.ts +1 -1
  149. package/dist/runtime/base/base-composer-runtime-core.d.ts.map +1 -1
  150. package/dist/runtime/base/base-composer-runtime-core.js +14 -29
  151. package/dist/runtime/base/base-composer-runtime-core.js.map +1 -1
  152. package/dist/runtime/base/base-thread-runtime-core.d.ts +4 -6
  153. package/dist/runtime/base/base-thread-runtime-core.d.ts.map +1 -1
  154. package/dist/runtime/base/base-thread-runtime-core.js +5 -11
  155. package/dist/runtime/base/base-thread-runtime-core.js.map +1 -1
  156. package/dist/runtime/base/default-thread-composer-runtime-core.d.ts +1 -1
  157. package/dist/runtime/base/default-thread-composer-runtime-core.d.ts.map +1 -1
  158. package/dist/runtime/base/default-thread-composer-runtime-core.js +1 -1
  159. package/dist/runtime/base/default-thread-composer-runtime-core.js.map +1 -1
  160. package/dist/runtime/interfaces/composer-runtime-core.d.ts +1 -1
  161. package/dist/runtime/interfaces/thread-list-runtime-core.d.ts +14 -2
  162. package/dist/runtime/interfaces/thread-list-runtime-core.d.ts.map +1 -1
  163. package/dist/runtime/interfaces/thread-runtime-core.d.ts +16 -2
  164. package/dist/runtime/interfaces/thread-runtime-core.d.ts.map +1 -1
  165. package/dist/runtime/internal.d.ts +2 -1
  166. package/dist/runtime/internal.js +2 -1
  167. package/dist/runtime/queue/external-thread-queue-adapter.d.ts +1 -1
  168. package/dist/runtime/queue/message-queue.d.ts.map +1 -1
  169. package/dist/runtime/queue/message-queue.js +1 -1
  170. package/dist/runtime/queue/message-queue.js.map +1 -1
  171. package/dist/runtime/queue/queue-item.d.ts +12 -0
  172. package/dist/runtime/queue/queue-item.d.ts.map +1 -0
  173. package/dist/runtime/queue/queue-item.js +6 -0
  174. package/dist/runtime/queue/queue-item.js.map +1 -0
  175. package/dist/runtime/utils/abortable-thread-load.d.ts +15 -0
  176. package/dist/runtime/utils/abortable-thread-load.d.ts.map +1 -0
  177. package/dist/runtime/utils/abortable-thread-load.js +35 -0
  178. package/dist/runtime/utils/abortable-thread-load.js.map +1 -0
  179. package/dist/runtime/utils/attachment-add-operations.d.ts +18 -0
  180. package/dist/runtime/utils/attachment-add-operations.d.ts.map +1 -0
  181. package/dist/runtime/utils/attachment-add-operations.js +43 -0
  182. package/dist/runtime/utils/attachment-add-operations.js.map +1 -0
  183. package/dist/runtime/utils/auto-status.d.ts +7 -2
  184. package/dist/runtime/utils/auto-status.d.ts.map +1 -1
  185. package/dist/runtime/utils/auto-status.js +13 -3
  186. package/dist/runtime/utils/auto-status.js.map +1 -1
  187. package/dist/runtime/utils/external-message-conversion.d.ts +48 -0
  188. package/dist/runtime/utils/external-message-conversion.d.ts.map +1 -0
  189. package/dist/runtime/utils/external-message-conversion.js +222 -0
  190. package/dist/runtime/utils/external-message-conversion.js.map +1 -0
  191. package/dist/runtime/utils/external-store-message.d.ts +2 -1
  192. package/dist/runtime/utils/external-store-message.d.ts.map +1 -1
  193. package/dist/runtime/utils/external-store-message.js +2 -1
  194. package/dist/runtime/utils/external-store-message.js.map +1 -1
  195. package/dist/runtime/utils/message-repository-session.d.ts +30 -0
  196. package/dist/runtime/utils/message-repository-session.d.ts.map +1 -0
  197. package/dist/runtime/utils/message-repository-session.js +130 -0
  198. package/dist/runtime/utils/message-repository-session.js.map +1 -0
  199. package/dist/runtime/utils/message-repository.d.ts.map +1 -1
  200. package/dist/runtime/utils/message-repository.js +3 -4
  201. package/dist/runtime/utils/message-repository.js.map +1 -1
  202. package/dist/runtime/utils/pending-tool-calls.d.ts +20 -0
  203. package/dist/runtime/utils/pending-tool-calls.d.ts.map +1 -0
  204. package/dist/runtime/utils/pending-tool-calls.js +22 -0
  205. package/dist/runtime/utils/pending-tool-calls.js.map +1 -0
  206. package/dist/runtime/utils/resolveToolApprovalResponse.d.ts +6 -3
  207. package/dist/runtime/utils/resolveToolApprovalResponse.d.ts.map +1 -1
  208. package/dist/runtime/utils/resolveToolApprovalResponse.js +12 -3
  209. package/dist/runtime/utils/resolveToolApprovalResponse.js.map +1 -1
  210. package/dist/runtime/utils/thread-message-like.d.ts +3 -10
  211. package/dist/runtime/utils/thread-message-like.d.ts.map +1 -1
  212. package/dist/runtime/utils/thread-message-like.js.map +1 -1
  213. package/dist/runtime/utils/tool-call-tree.d.ts +39 -0
  214. package/dist/runtime/utils/tool-call-tree.d.ts.map +1 -0
  215. package/dist/runtime/utils/tool-call-tree.js +85 -0
  216. package/dist/runtime/utils/tool-call-tree.js.map +1 -0
  217. package/dist/runtimes/external-store/external-store-adapter.d.ts +29 -2
  218. package/dist/runtimes/external-store/external-store-adapter.d.ts.map +1 -1
  219. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.d.ts +2 -5
  220. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.d.ts.map +1 -1
  221. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js +3 -10
  222. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js.map +1 -1
  223. package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts +21 -2
  224. package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts.map +1 -1
  225. package/dist/runtimes/external-store/external-store-thread-runtime-core.js +154 -46
  226. package/dist/runtimes/external-store/external-store-thread-runtime-core.js.map +1 -1
  227. package/dist/runtimes/inert/InertThreadRuntimeCore.d.ts +1 -1
  228. package/dist/runtimes/inert/InertThreadRuntimeCore.d.ts.map +1 -1
  229. package/dist/runtimes/inert/InertThreadRuntimeCore.js.map +1 -1
  230. package/dist/runtimes/local/local-thread-runtime-core.d.ts +4 -2
  231. package/dist/runtimes/local/local-thread-runtime-core.d.ts.map +1 -1
  232. package/dist/runtimes/local/local-thread-runtime-core.js +23 -3
  233. package/dist/runtimes/local/local-thread-runtime-core.js.map +1 -1
  234. package/dist/runtimes/remote-thread-list/remote-thread-state.d.ts +12 -1
  235. package/dist/runtimes/remote-thread-list/remote-thread-state.d.ts.map +1 -1
  236. package/dist/runtimes/remote-thread-list/remote-thread-state.js +107 -14
  237. package/dist/runtimes/remote-thread-list/remote-thread-state.js.map +1 -1
  238. package/dist/runtimes/remote-thread-list/title.d.ts +9 -0
  239. package/dist/runtimes/remote-thread-list/title.d.ts.map +1 -0
  240. package/dist/runtimes/remote-thread-list/title.js +6 -0
  241. package/dist/runtimes/remote-thread-list/title.js.map +1 -0
  242. package/dist/runtimes/remote-thread-list/types.d.ts +6 -5
  243. package/dist/runtimes/remote-thread-list/types.d.ts.map +1 -1
  244. package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts +31 -8
  245. package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts.map +1 -1
  246. package/dist/runtimes/tool-invocations/ToolInvocationTracker.js +98 -59
  247. package/dist/runtimes/tool-invocations/ToolInvocationTracker.js.map +1 -1
  248. package/dist/store/clients/external-thread.d.ts +1 -1
  249. package/dist/store/clients/external-thread.d.ts.map +1 -1
  250. package/dist/store/clients/external-thread.js +85 -103
  251. package/dist/store/clients/external-thread.js.map +1 -1
  252. package/dist/store/clients/single-thread-list.d.ts.map +1 -1
  253. package/dist/store/clients/single-thread-list.js +2 -2
  254. package/dist/store/clients/single-thread-list.js.map +1 -1
  255. package/dist/store/clients/suggestions.d.ts.map +1 -1
  256. package/dist/store/clients/suggestions.js +33 -12
  257. package/dist/store/clients/suggestions.js.map +1 -1
  258. package/dist/store/clients/thread-message-client.js +1 -1
  259. package/dist/store/clients/thread-selection-events.js +1 -1
  260. package/dist/store/index.d.ts +6 -3
  261. package/dist/store/index.js +2 -1
  262. package/dist/store/internal.d.ts +2 -2
  263. package/dist/store/internal.js +2 -2
  264. package/dist/store/primitive-predicates.d.ts +4 -1
  265. package/dist/store/primitive-predicates.d.ts.map +1 -1
  266. package/dist/store/primitive-predicates.js +9 -1
  267. package/dist/store/primitive-predicates.js.map +1 -1
  268. package/dist/store/runtime-clients/composer-runtime-client.js +1 -1
  269. package/dist/store/runtime-clients/message-runtime-client.js +1 -1
  270. package/dist/store/runtime-clients/thread-list-item-runtime-client.js +1 -1
  271. package/dist/store/runtime-clients/thread-list-runtime-client.d.ts.map +1 -1
  272. package/dist/store/runtime-clients/thread-list-runtime-client.js +124 -105
  273. package/dist/store/runtime-clients/thread-list-runtime-client.js.map +1 -1
  274. package/dist/store/runtime-clients/thread-runtime-client.js +1 -1
  275. package/dist/store/runtime-clients/useSubscribable.d.ts +3 -1
  276. package/dist/store/runtime-clients/useSubscribable.d.ts.map +1 -1
  277. package/dist/store/runtime-clients/useSubscribable.js +1 -1
  278. package/dist/store/runtime-clients/useSubscribable.js.map +1 -1
  279. package/dist/store/scope-registration.d.ts +1 -1
  280. package/dist/store/scopes/composer.d.ts +2 -1
  281. package/dist/store/scopes/composer.d.ts.map +1 -1
  282. package/dist/store/scopes/message.d.ts +1 -1
  283. package/dist/store/scopes/part.d.ts +6 -3
  284. package/dist/store/scopes/part.d.ts.map +1 -1
  285. package/dist/store/scopes/queue-item.d.ts +2 -9
  286. package/dist/store/scopes/queue-item.d.ts.map +1 -1
  287. package/dist/store/scopes/queue-item.js +0 -6
  288. package/dist/subscribable/subscribable.d.ts +8 -1
  289. package/dist/subscribable/subscribable.d.ts.map +1 -1
  290. package/dist/subscribable/subscribable.js +24 -16
  291. package/dist/subscribable/subscribable.js.map +1 -1
  292. package/dist/types/message.d.ts +47 -4
  293. package/dist/types/message.d.ts.map +1 -1
  294. package/dist/types/message.js +7 -1
  295. package/dist/types/message.js.map +1 -1
  296. package/dist/utils/data-url.d.ts +14 -1
  297. package/dist/utils/data-url.d.ts.map +1 -1
  298. package/dist/utils/data-url.js +13 -1
  299. package/dist/utils/data-url.js.map +1 -1
  300. package/dist/utils/invoke-user-callback.d.ts +5 -0
  301. package/dist/utils/invoke-user-callback.d.ts.map +1 -0
  302. package/dist/utils/invoke-user-callback.js +19 -0
  303. package/dist/utils/invoke-user-callback.js.map +1 -0
  304. package/dist/utils/normalizePartStatus.js.map +1 -1
  305. package/package.json +12 -17
  306. package/src/index.ts +6 -1
  307. package/src/internal.ts +20 -0
  308. package/src/model-context/frame/host.test.ts +91 -7
  309. package/src/model-context/frame/host.ts +7 -2
  310. package/src/model-context/frame/provider.test.ts +484 -13
  311. package/src/model-context/frame/provider.ts +205 -35
  312. package/src/model-context/interactable-composer-metadata.ts +1 -1
  313. package/src/model-context/registry.test.ts +44 -0
  314. package/src/model-context/registry.ts +13 -35
  315. package/src/model-context/tool-call-text.test.ts +67 -0
  316. package/src/model-context/tool-call-text.ts +67 -0
  317. package/src/react/AssistantRuntimeProvider.test.tsx +66 -2
  318. package/src/react/adapters/LocalStorageThreadListAdapter.tsx +1 -3
  319. package/src/react/client/InMemoryThreadList.test.tsx +49 -0
  320. package/src/react/client/InMemoryThreadList.ts +7 -1
  321. package/src/react/client/Interactables.ts +19 -178
  322. package/src/react/client/RemoteThreadList.background.test.ts +384 -0
  323. package/src/react/client/RemoteThreadList.concurrent.test.tsx +274 -0
  324. package/src/react/client/RemoteThreadList.test.ts +369 -1
  325. package/src/react/client/RemoteThreadList.ts +320 -142
  326. package/src/react/client/Tools.ts +7 -1
  327. package/src/react/index.ts +4 -0
  328. package/src/react/interactables-legacy/Interactables.ts +20 -177
  329. package/src/react/interactables-shared/useInteractablePersistenceQueue.test.tsx +161 -0
  330. package/src/react/interactables-shared/useInteractablePersistenceQueue.ts +206 -0
  331. package/src/react/model-context/modelContextHooks.test.tsx +131 -0
  332. package/src/react/model-context/toolbox.test.ts +9 -9
  333. package/src/react/model-context/toolbox.ts +9 -36
  334. package/src/react/model-context/useAssistantContext.ts +4 -2
  335. package/src/react/model-context/useAuiToolOverrides.ts +4 -2
  336. package/src/react/model-context/useInlineRender.test.tsx +48 -0
  337. package/src/react/model-context/useInlineRender.ts +14 -10
  338. package/src/react/primitive-hooks/useMessageError.ts +2 -19
  339. package/src/react/primitive-hooks/useThreadListLoadMore.ts +2 -3
  340. package/src/react/primitives/composer/ComposerAttachments.test.tsx +76 -0
  341. package/src/react/primitives/composer/ComposerAttachments.tsx +9 -4
  342. package/src/react/primitives/composer/ComposerQueue.test.tsx +72 -0
  343. package/src/react/primitives/composer/ComposerQueue.tsx +7 -4
  344. package/src/react/primitives/message/MessageAttachments.test.tsx +107 -37
  345. package/src/react/primitives/message/MessageAttachments.tsx +10 -7
  346. package/src/react/primitives/message/MessageGroupedParts.tsx +2 -2
  347. package/src/react/primitives/message/MessageParts.tsx +3 -3
  348. package/src/react/primitives/threadList/ThreadListItems.test.tsx +99 -0
  349. package/src/react/primitives/threadList/ThreadListItems.tsx +8 -5
  350. package/src/react/runtimes/RemoteThreadListHookInstanceManager.running.test.tsx +94 -1
  351. package/src/react/runtimes/RemoteThreadListHookInstanceManager.tsx +72 -31
  352. package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.switch-delete.test.ts +169 -0
  353. package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.tsx +140 -124
  354. package/src/react/runtimes/RemoteThreadResource.ts +1 -4
  355. package/src/react/runtimes/assistant-transport/runManager.ts +4 -17
  356. package/src/react/runtimes/assistant-transport/transport-scheduling.test.ts +51 -2
  357. package/src/react/runtimes/assistant-transport/useLatestRef.ts +2 -2
  358. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.test.ts +45 -0
  359. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.test.tsx +157 -1
  360. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.ts +82 -176
  361. package/src/react/runtimes/cloud/auiV0.ts +5 -0
  362. package/src/react/runtimes/cloud/createCloudThreadListAdapter.test.ts +88 -0
  363. package/src/react/runtimes/cloud/createCloudThreadListAdapter.ts +236 -0
  364. package/src/react/runtimes/cloud/createCloudThreadListAdapterCreateFallback.test.ts +37 -0
  365. package/src/react/runtimes/cloud/createCloudThreadListAdapterCreateFallback.ts +18 -0
  366. package/src/react/runtimes/cloud/useCloudThreadListAdapter.test.tsx +90 -1
  367. package/src/react/runtimes/cloud/useCloudThreadListAdapter.tsx +33 -238
  368. package/src/react/runtimes/external-message-converter.test.ts +0 -14
  369. package/src/react/runtimes/external-message-converter.test.tsx +77 -0
  370. package/src/react/runtimes/external-message-converter.ts +59 -481
  371. package/src/react/runtimes/useRemoteThreadListRuntime.concurrent.test.tsx +216 -0
  372. package/src/react/runtimes/useRemoteThreadListRuntime.ts +24 -6
  373. package/src/react/types/MessagePartComponentTypes.ts +7 -3
  374. package/src/react/types/scopes/tools.ts +2 -0
  375. package/src/runtime/api/composer-runtime.ts +1 -1
  376. package/src/runtime/api/message-part-runtime.ts +3 -3
  377. package/src/runtime/api/message-runtime.test.ts +28 -1
  378. package/src/runtime/api/thread-list-runtime.ts +25 -1
  379. package/src/runtime/base/base-composer-runtime-core.ts +20 -40
  380. package/src/runtime/base/base-thread-runtime-core.test.ts +110 -3
  381. package/src/runtime/base/base-thread-runtime-core.ts +16 -15
  382. package/src/runtime/base/default-thread-composer-runtime-core.ts +1 -4
  383. package/src/runtime/interfaces/composer-runtime-core.ts +1 -1
  384. package/src/runtime/interfaces/thread-list-runtime-core.ts +20 -1
  385. package/src/runtime/interfaces/thread-runtime-core.ts +18 -2
  386. package/src/runtime/internal.ts +5 -0
  387. package/src/runtime/queue/external-thread-queue-adapter.ts +1 -1
  388. package/src/runtime/queue/message-queue.ts +1 -4
  389. package/src/runtime/queue/queue-item.ts +10 -0
  390. package/src/runtime/utils/abortable-thread-load.test.ts +87 -0
  391. package/src/runtime/utils/abortable-thread-load.ts +53 -0
  392. package/src/runtime/utils/attachment-add-operations.ts +59 -0
  393. package/src/runtime/utils/auto-status.test.ts +57 -0
  394. package/src/runtime/utils/auto-status.ts +46 -1
  395. package/src/runtime/utils/external-message-conversion.test.ts +210 -0
  396. package/src/runtime/utils/external-message-conversion.ts +510 -0
  397. package/src/runtime/utils/external-store-message.ts +2 -0
  398. package/src/runtime/utils/message-repository-session.test.ts +195 -0
  399. package/src/runtime/utils/message-repository-session.ts +176 -0
  400. package/src/runtime/utils/message-repository.ts +7 -4
  401. package/src/runtime/utils/pending-tool-calls.test.ts +57 -0
  402. package/src/runtime/utils/pending-tool-calls.ts +35 -0
  403. package/src/runtime/utils/resolveToolApprovalResponse.test.ts +73 -0
  404. package/src/runtime/utils/resolveToolApprovalResponse.ts +27 -6
  405. package/src/runtime/utils/thread-message-like.ts +4 -10
  406. package/src/runtime/utils/tool-call-tree.test.ts +191 -0
  407. package/src/runtime/utils/tool-call-tree.ts +97 -0
  408. package/src/runtimes/external-store/external-store-adapter.ts +38 -2
  409. package/src/runtimes/external-store/external-store-thread-list-runtime-core.ts +6 -14
  410. package/src/runtimes/external-store/external-store-thread-runtime-core.ts +231 -61
  411. package/src/runtimes/inert/InertThreadRuntimeCore.ts +1 -1
  412. package/src/runtimes/local/local-thread-runtime-core.test.ts +201 -4
  413. package/src/runtimes/local/local-thread-runtime-core.ts +53 -4
  414. package/src/runtimes/remote-thread-list/remote-thread-state.test.ts +149 -0
  415. package/src/runtimes/remote-thread-list/remote-thread-state.ts +178 -16
  416. package/src/runtimes/remote-thread-list/title.ts +3 -0
  417. package/src/runtimes/remote-thread-list/types.ts +6 -5
  418. package/src/runtimes/tool-invocations/EDGE_CASES.md +125 -3
  419. package/src/runtimes/tool-invocations/ToolInvocationTracker.test.ts +856 -102
  420. package/src/runtimes/tool-invocations/ToolInvocationTracker.ts +145 -89
  421. package/src/store/clients/external-thread.ts +30 -69
  422. package/src/store/clients/single-thread-list.ts +4 -1
  423. package/src/store/clients/suggestions.test.ts +185 -0
  424. package/src/store/clients/suggestions.ts +42 -35
  425. package/src/store/index.ts +4 -0
  426. package/src/store/internal.ts +2 -0
  427. package/src/store/primitive-predicates.ts +35 -0
  428. package/src/store/runtime-clients/thread-list-runtime-client.ts +16 -2
  429. package/src/store/runtime-clients/useSubscribable.ts +8 -2
  430. package/src/store/scopes/message.ts +1 -1
  431. package/src/store/scopes/part.ts +6 -3
  432. package/src/store/scopes/queue-item.ts +2 -9
  433. package/src/subscribable/subscribable.test.ts +50 -0
  434. package/src/subscribable/subscribable.ts +33 -21
  435. package/src/tests/MessageRepository.test.ts +77 -0
  436. package/src/tests/RemoteThreadListThreadListRuntimeCore-load-race.test.ts +305 -0
  437. package/src/tests/RemoteThreadListThreadListRuntimeCore-loadMore.test.ts +78 -0
  438. package/src/tests/RemoteThreadListThreadListRuntimeCore-reload.test.ts +52 -0
  439. package/src/tests/RemoteThreadListThreadListRuntimeCore-title-race.test.ts +158 -0
  440. package/src/tests/external-store-optimistic-id.test.ts +79 -0
  441. package/src/tests/external-store-repository-instance.test.ts +166 -0
  442. package/src/tests/external-store-thread-runtime-core-adapter.test.ts +186 -16
  443. package/src/tests/external-store-thread-runtime-core.test.ts +642 -0
  444. package/src/tests/external-thread-attachments.test.tsx +258 -1
  445. package/src/tests/remote-thread-list-adapter-switch.test.ts +66 -1
  446. package/src/tests/single-thread-list-item.test.tsx +47 -0
  447. package/src/tests/thread-message-like.test.ts +39 -1
  448. package/src/tests/thread-switch-events.test.tsx +397 -2
  449. package/src/types/message.ts +58 -5
  450. package/src/utils/data-url.test.ts +52 -1
  451. package/src/utils/data-url.ts +21 -0
  452. package/src/utils/invoke-user-callback.test.ts +82 -0
  453. package/src/utils/invoke-user-callback.ts +31 -0
  454. package/src/utils/normalizePartStatus.ts +1 -1
  455. package/dist/store/scopes/queue-item.js.map +0 -1
@@ -1,3 +1,4 @@
1
+ import { shallowEqual } from "@assistant-ui/store/client";
1
2
  import type { AppendMessage, ThreadMessage } from "../../types/message";
2
3
  import type { Attachment } from "../../types/attachment";
3
4
  import type {
@@ -16,14 +17,19 @@ import type {
16
17
  import {
17
18
  getExternalStoreMessages,
18
19
  bindExternalStoreMessage,
20
+ FALLBACK_ID_PREFIX,
19
21
  } from "../../runtime/utils/external-store-message";
20
22
  import { ThreadMessageConverter } from "./thread-message-converter";
21
- import { getAutoStatus, isAutoStatus } from "../../runtime/utils/auto-status";
23
+ import {
24
+ getContentAutoStatus,
25
+ isAutoStatus,
26
+ } from "../../runtime/utils/auto-status";
22
27
  import {
23
28
  fromThreadMessageLike,
24
29
  type ThreadMessageLike,
25
30
  } from "../../runtime/utils/thread-message-like";
26
31
  import { getThreadMessageText } from "../../utils/text";
32
+ import { shallowArrayEqual } from "../../runtime/utils/external-message-conversion";
27
33
  import type {
28
34
  RuntimeCapabilities,
29
35
  ThreadRuntimeCore,
@@ -39,8 +45,12 @@ import {
39
45
  MessageRepository,
40
46
  } from "../../runtime/utils/message-repository";
41
47
  import { generateId } from "../../utils/id";
42
- import { ToolInvocationTracker } from "../tool-invocations/ToolInvocationTracker";
43
- import { EMPTY_QUEUE_ITEMS } from "../../store/scopes/queue-item";
48
+ import { walkToolCallTree } from "../../runtime/utils/tool-call-tree";
49
+ import {
50
+ ToolInvocationTracker,
51
+ type ToolExecutionStatus,
52
+ } from "../tool-invocations/ToolInvocationTracker";
53
+ import { EMPTY_QUEUE_ITEMS } from "../../runtime/queue/queue-item";
44
54
  import type { QuoteInfo } from "../../types/quote";
45
55
  import {
46
56
  captureThreadRuntimeGeneration,
@@ -50,7 +60,7 @@ import {
50
60
  const EMPTY_ARRAY: readonly ThreadSuggestion[] = Object.freeze([]);
51
61
 
52
62
  const observeAdapterCallback = (
53
- name: "onAddToolResult" | "onRespondToToolApproval" | "onCancel",
63
+ name: "onAddToolResult" | "onCancel",
54
64
  result: Promise<void> | void,
55
65
  ) => {
56
66
  void Promise.resolve(result).catch((error) => {
@@ -61,15 +71,6 @@ const observeAdapterCallback = (
61
71
  });
62
72
  };
63
73
 
64
- const shallowEqual = (a: object, b: object): boolean => {
65
- const aKeys = Object.keys(a);
66
- if (aKeys.length !== Object.keys(b).length) return false;
67
- for (const key of aKeys) {
68
- if ((a as any)[key] !== (b as any)[key]) return false;
69
- }
70
- return true;
71
- };
72
-
73
74
  export const hasUpcomingMessage = (
74
75
  isRunning: boolean,
75
76
  messages: readonly ThreadMessage[],
@@ -110,6 +111,7 @@ export class ExternalStoreThreadRuntimeCore
110
111
  }
111
112
  // Unlike `isLoading`: pass `undefined` through to preserve the `getThreadState` fallback.
112
113
  public get isRunning(): boolean | undefined {
114
+ if (this._hasExecutingTools(this._store)) return true;
113
115
  return this._store.isRunning;
114
116
  }
115
117
 
@@ -136,6 +138,21 @@ export class ExternalStoreThreadRuntimeCore
136
138
 
137
139
  private _converter = new ThreadMessageConverter();
138
140
 
141
+ // Ids the host was asked to delete via onDelete. The snapshot pass evicts
142
+ // them from the repository once the host's array no longer carries them;
143
+ // an id the host kept is dropped from the set without eviction.
144
+ // Branch-changing mutations (edit, branch switch, reload) invalidate the
145
+ // set, because after them the incoming array omits off-branch ids for
146
+ // reasons unrelated to deletion. Plain tail sends do not clear: a tail
147
+ // append cannot make a visible id absent, so id-absence stays unambiguous
148
+ // and a delete whose confirmation races a send keeps its eviction.
149
+ private _pendingDeleteEvictions = new Set<string>();
150
+
151
+ // Placeholder id for the upcoming assistant message, reused across snapshot
152
+ // passes while the same tail message awaits its response so the placeholder
153
+ // keeps one identity per response.
154
+ private _optimistic: { id: string; parentId: string | null } | null = null;
155
+
139
156
  private _store!: ExternalStoreAdapter<any>;
140
157
 
141
158
  private _getInitializePromise?: () => Promise<unknown> | undefined;
@@ -153,6 +170,51 @@ export class ExternalStoreThreadRuntimeCore
153
170
  * snapshot — only when `adapter.unstable_enableToolInvocations === true`.
154
171
  */
155
172
  private _toolInvocations: ToolInvocationTracker | null = null;
173
+ private _toolStatuses: ReadonlyMap<string, ToolExecutionStatus> = new Map();
174
+ private _effectiveIsRunning = false;
175
+ private _inTrackerUpdate = false;
176
+ private _pendingRunningRefresh = false;
177
+
178
+ /**
179
+ * Tracker mutations initiated by this class (setState, reset) can publish
180
+ * status changes synchronously. Re-entering the snapshot pipeline from
181
+ * inside them would feed the tracker a stale snapshot and consume the
182
+ * restore arming a reset just installed, so the running refresh is
183
+ * deferred until the mutation returns and stays off the tracker.
184
+ */
185
+ private _runTrackerUpdate(fn: () => void): void {
186
+ this._inTrackerUpdate = true;
187
+ try {
188
+ fn();
189
+ } finally {
190
+ this._inTrackerUpdate = false;
191
+ }
192
+ if (this._pendingRunningRefresh) {
193
+ this._pendingRunningRefresh = false;
194
+ this._refreshEffectiveIsRunning();
195
+ }
196
+ }
197
+
198
+ private _refreshEffectiveIsRunning(): void {
199
+ const isRunning = this._getEffectiveIsRunning(this._store);
200
+ if (this._effectiveIsRunning === isRunning) return;
201
+ this._effectiveIsRunning = isRunning;
202
+ this._notifyEventSubscribers(isRunning ? "runStart" : "runEnd", {});
203
+ this._notifySubscribers();
204
+ }
205
+
206
+ private _hasExecutingTools(store: ExternalStoreAdapter<any>): boolean {
207
+ if (store.unstable_enableToolInvocations !== true) return false;
208
+ if (this._toolInvocations === null) return false;
209
+ for (const status of this._toolStatuses.values()) {
210
+ if (status.type === "executing") return true;
211
+ }
212
+ return false;
213
+ }
214
+
215
+ private _getEffectiveIsRunning(store: ExternalStoreAdapter<any>): boolean {
216
+ return (store.isRunning ?? false) || this._hasExecutingTools(store);
217
+ }
156
218
 
157
219
  public override beginEdit(messageId: string) {
158
220
  if (!this._store.onEdit)
@@ -172,12 +234,25 @@ export class ExternalStoreThreadRuntimeCore
172
234
  public __internal_setAdapter(store: ExternalStoreAdapter<any>) {
173
235
  if (this._store === store) return;
174
236
 
175
- const isRunning = store.isRunning ?? false;
237
+ this._updateStoreSnapshot(store);
238
+ }
239
+
240
+ private _updateStoreSnapshot(store: ExternalStoreAdapter<any>) {
241
+ const previousIsRunning = this._effectiveIsRunning;
176
242
  this.isDisabled = store.isDisabled ?? false;
177
243
  this.isSendDisabled = store.isSendDisabled ?? false;
178
244
 
179
245
  const oldStore = this._store as ExternalStoreAdapter<any> | undefined;
180
246
  this._store = store;
247
+ const isRunning = this._getEffectiveIsRunning(store);
248
+ const repositoryInstance = store.unstable_messageRepositoryInstance;
249
+ const repositoryChanged =
250
+ repositoryInstance !== undefined &&
251
+ repositoryInstance !== this.repository;
252
+ if (repositoryChanged) {
253
+ this.repository = repositoryInstance;
254
+ this._pendingDeleteEvictions.clear();
255
+ }
181
256
  if (oldStore?.queue !== store.queue) {
182
257
  this._transformedQueue = undefined;
183
258
  store.queue?.__internal_setDispatchTransform?.((message) => {
@@ -228,8 +303,10 @@ export class ExternalStoreThreadRuntimeCore
228
303
  // Handle messageRepository
229
304
  if (
230
305
  oldStore &&
306
+ !repositoryChanged &&
231
307
  oldStore.isRunning === store.isRunning &&
232
- oldStore.messageRepository === store.messageRepository
308
+ oldStore.messageRepository === store.messageRepository &&
309
+ previousIsRunning === isRunning
233
310
  ) {
234
311
  this._notifySubscribers();
235
312
  return;
@@ -239,7 +316,11 @@ export class ExternalStoreThreadRuntimeCore
239
316
  const headId =
240
317
  store.messageRepository.headId ?? incoming.at(-1)?.message.id ?? null;
241
318
 
242
- if (oldStore && oldStore.messageRepository === store.messageRepository) {
319
+ if (
320
+ oldStore &&
321
+ !repositoryChanged &&
322
+ oldStore.messageRepository === store.messageRepository
323
+ ) {
243
324
  this.repository.resetHead(headId);
244
325
  messages = this.repository.getMessages();
245
326
  } else {
@@ -252,6 +333,7 @@ export class ExternalStoreThreadRuntimeCore
252
333
  this.repository.deleteMessage(message.id);
253
334
  }
254
335
  }
336
+ this._pendingDeleteEvictions.clear();
255
337
  this.repository.resetHead(headId);
256
338
  messages = this.repository.getMessages();
257
339
  }
@@ -263,8 +345,10 @@ export class ExternalStoreThreadRuntimeCore
263
345
  if (oldStore.convertMessage !== store.convertMessage) {
264
346
  this._converter = new ThreadMessageConverter();
265
347
  } else if (
348
+ !repositoryChanged &&
266
349
  oldStore.isRunning === store.isRunning &&
267
- oldStore.messages === store.messages
350
+ oldStore.messages === store.messages &&
351
+ previousIsRunning === isRunning
268
352
  ) {
269
353
  this._notifySubscribers();
270
354
  // no conversion update
@@ -278,27 +362,31 @@ export class ExternalStoreThreadRuntimeCore
278
362
  if (!store.convertMessage) return m;
279
363
 
280
364
  const isLast = idx === (store.messages?.length ?? 0) - 1;
281
- const autoStatus = getAutoStatus(
282
- isLast,
283
- isRunning,
284
- false,
285
- false,
286
- undefined,
287
- );
365
+ const fallbackId = `${FALLBACK_ID_PREFIX}${idx}`;
288
366
 
289
367
  if (
290
368
  cache &&
291
369
  (cache.role !== "assistant" ||
292
370
  !isAutoStatus(cache.status) ||
293
- cache.status === autoStatus)
294
- )
371
+ cache.status ===
372
+ getContentAutoStatus(cache.content, isLast, isRunning))
373
+ ) {
374
+ if (
375
+ cache.id.startsWith(FALLBACK_ID_PREFIX) &&
376
+ cache.id !== fallbackId
377
+ ) {
378
+ const updated = { ...cache, id: fallbackId };
379
+ bindExternalStoreMessage(updated, m);
380
+ return updated;
381
+ }
295
382
  return cache;
383
+ }
296
384
 
297
385
  const messageLike = store.convertMessage(m, idx);
298
386
  const newMessage = fromThreadMessageLike(
299
387
  messageLike,
300
- idx.toString(),
301
- autoStatus,
388
+ fallbackId,
389
+ getContentAutoStatus(messageLike.content, isLast, isRunning),
302
390
  );
303
391
  bindExternalStoreMessage(newMessage, m);
304
392
  return newMessage;
@@ -324,6 +412,20 @@ export class ExternalStoreThreadRuntimeCore
324
412
  const parent = messages[i - 1];
325
413
  this.repository.addOrUpdateMessage(parent?.id ?? null, message);
326
414
  }
415
+
416
+ if (this._pendingDeleteEvictions.size > 0) {
417
+ const incomingIds = new Set(messages.map((m) => m.id));
418
+ for (const id of this._pendingDeleteEvictions) {
419
+ this._pendingDeleteEvictions.delete(id);
420
+ if (incomingIds.has(id)) continue;
421
+ try {
422
+ this.repository.getMessage(id);
423
+ } catch {
424
+ continue;
425
+ }
426
+ this.repository.deleteMessage(id);
427
+ }
428
+ }
327
429
  } else {
328
430
  throw new Error(
329
431
  "ExternalStoreAdapter must provide either 'messages' or 'messageRepository'",
@@ -333,8 +435,9 @@ export class ExternalStoreThreadRuntimeCore
333
435
  // Common logic for both paths
334
436
  if (messages.length > 0) this.ensureInitialized();
335
437
 
336
- if ((oldStore?.isRunning ?? false) !== (store.isRunning ?? false)) {
337
- if (store.isRunning) {
438
+ this._effectiveIsRunning = isRunning;
439
+ if (previousIsRunning !== isRunning) {
440
+ if (isRunning) {
338
441
  this._notifyEventSubscribers("runStart", {});
339
442
  } else {
340
443
  this._notifyEventSubscribers("runEnd", {});
@@ -346,9 +449,13 @@ export class ExternalStoreThreadRuntimeCore
346
449
  // (prior placeholders, mid-run id-swap siblings); export() never persists them.
347
450
  let optimisticId: string | null = null;
348
451
  if (hasUpcomingMessage(isRunning, messages)) {
349
- optimisticId = generateId();
452
+ const parentId = messages.at(-1)?.id ?? null;
453
+ if (this._optimistic?.parentId !== parentId) {
454
+ this._optimistic = { id: generateId(), parentId };
455
+ }
456
+ optimisticId = this._optimistic.id;
350
457
  this.repository.addOrUpdateMessage(
351
- messages.at(-1)?.id ?? null,
458
+ parentId,
352
459
  fromThreadMessageLike(
353
460
  { role: "assistant", content: [], metadata: { isOptimistic: true } },
354
461
  optimisticId,
@@ -357,11 +464,21 @@ export class ExternalStoreThreadRuntimeCore
357
464
  );
358
465
  }
359
466
 
467
+ if (optimisticId === null) this._optimistic = null;
360
468
  this.repository.resetHead(optimisticId ?? messages.at(-1)?.id ?? null);
361
469
 
362
- this._messages = this.repository.getMessages();
470
+ const messagesSnapshot = this.repository.getMessages();
471
+ if (
472
+ !this._messages ||
473
+ !shallowArrayEqual(this._messages, messagesSnapshot)
474
+ ) {
475
+ this._messages = messagesSnapshot;
476
+ }
363
477
 
364
- this._driveToolInvocations();
478
+ if (repositoryChanged) {
479
+ this._runTrackerUpdate(() => this._toolInvocations?.reset());
480
+ }
481
+ this._runTrackerUpdate(() => this._driveToolInvocations());
365
482
 
366
483
  this._notifySubscribers();
367
484
  }
@@ -380,6 +497,7 @@ export class ExternalStoreThreadRuntimeCore
380
497
  if (this._toolInvocations) {
381
498
  this._toolInvocations.reset();
382
499
  this._toolInvocations = null;
500
+ this._toolStatuses = new Map();
383
501
  this._store.setToolStatuses?.({});
384
502
  }
385
503
  return;
@@ -423,15 +541,28 @@ export class ExternalStoreThreadRuntimeCore
423
541
  }
424
542
  },
425
543
  onStatusesChange: (statuses) => {
426
- this._store.setToolStatuses?.(Object.fromEntries(statuses));
544
+ const hadExecutingTools = this._hasExecutingTools(this._store);
545
+ this._toolStatuses = statuses;
546
+ try {
547
+ this._store.setToolStatuses?.(Object.fromEntries(statuses));
548
+ } finally {
549
+ if (hadExecutingTools !== this._hasExecutingTools(this._store)) {
550
+ if (this._inTrackerUpdate) {
551
+ this._pendingRunningRefresh = true;
552
+ } else {
553
+ this._updateStoreSnapshot(this._store);
554
+ }
555
+ }
556
+ }
427
557
  },
428
558
  },
559
+ (toolCall) => this._store.unstable_isClientToolCall?.(toolCall),
429
560
  );
430
561
  }
431
562
 
432
563
  this._toolInvocations.setState({
433
564
  messages: this._messages,
434
- isRunning: this._store.isRunning ?? false,
565
+ isRunning: this._getEffectiveIsRunning(this._store),
435
566
  ...(this._store.isLoading !== undefined && {
436
567
  isLoading: this._store.isLoading,
437
568
  }),
@@ -454,17 +585,9 @@ export class ExternalStoreThreadRuntimeCore
454
585
  private _findMessageIdForToolCall(toolCallId: string): string | undefined {
455
586
  if (this._messagesForToolCallIndex !== this._messages) {
456
587
  this._toolCallToMessageId.clear();
457
- const visit = (messages: readonly ThreadMessage[]): void => {
458
- for (const message of messages) {
459
- if (!Array.isArray(message.content)) continue;
460
- for (const part of message.content) {
461
- if (!part || part.type !== "tool-call") continue;
462
- this._toolCallToMessageId.set(part.toolCallId, message.id);
463
- if (part.messages) visit(part.messages);
464
- }
465
- }
466
- };
467
- visit(this._messages);
588
+ for (const { part, messageId } of walkToolCallTree(this._messages)) {
589
+ this._toolCallToMessageId.set(part.toolCallId, messageId);
590
+ }
468
591
  this._messagesForToolCallIndex = this._messages;
469
592
  }
470
593
  return this._toolCallToMessageId.get(toolCallId);
@@ -475,7 +598,7 @@ export class ExternalStoreThreadRuntimeCore
475
598
  throw new Error("Runtime does not support switching branches.");
476
599
 
477
600
  // Silently ignore branch switches while running
478
- if (this._store.isRunning) {
601
+ if (this._getEffectiveIsRunning(this._store)) {
479
602
  return;
480
603
  }
481
604
 
@@ -485,6 +608,7 @@ export class ExternalStoreThreadRuntimeCore
485
608
  : null;
486
609
 
487
610
  this.repository.switchToBranch(branchId);
611
+ this._pendingDeleteEvictions.clear();
488
612
  this.updateMessages(this.repository.getMessages());
489
613
  if (onBranchChange) {
490
614
  this._notifyBranchChange(previousHeadId, onBranchChange);
@@ -547,7 +671,7 @@ export class ExternalStoreThreadRuntimeCore
547
671
  // Buffering does not start a run, so the tool-abort below must wait
548
672
  // until the queue flushes. By then the prior run (and its tools) has
549
673
  // settled.
550
- if (message.steer ?? this._store.isRunning ?? false)
674
+ if (message.steer ?? this._getEffectiveIsRunning(this._store))
551
675
  this._store.queue.steer(message);
552
676
  else this._store.queue.enqueue(message);
553
677
  return;
@@ -567,13 +691,14 @@ export class ExternalStoreThreadRuntimeCore
567
691
  // user messages — matches the satellites' historical opt-in cancel
568
692
  // behavior, which is now built in.
569
693
  if (message.startRun ?? message.role === "user") {
570
- await this._toolInvocations?.abort();
694
+ await this._toolInvocations?.abort({ discardPending: true });
571
695
  }
572
696
  if (!isThreadRuntimeGenerationCurrent(this, generation)) return;
573
697
 
574
698
  if (isEdit) {
575
699
  if (!this._store.onEdit)
576
700
  throw new Error("Runtime does not support editing messages.");
701
+ this._pendingDeleteEvictions.clear();
577
702
  await this._store.onEdit(message);
578
703
  } else {
579
704
  await this._store.onNew(message);
@@ -582,14 +707,29 @@ export class ExternalStoreThreadRuntimeCore
582
707
 
583
708
  public async deleteMessage(messageId: string): Promise<void> {
584
709
  if (this._store.onDelete) {
585
- await this._store.onDelete(messageId);
710
+ // The host owns deletion here, and it may decline (fail a server call,
711
+ // cancel a confirm dialog, ignore an off-branch id). The eviction is
712
+ // therefore deferred to the snapshot pass, which evicts only once the
713
+ // host's own array no longer carries the id. Registered before the
714
+ // callback because an optimistic host publishes that snapshot while
715
+ // the callback is still awaited.
716
+ const wasVisible = this.repository
717
+ .getMessages()
718
+ .some((m) => m.id === messageId);
719
+ if (wasVisible) this._pendingDeleteEvictions.add(messageId);
720
+ try {
721
+ await this._store.onDelete(messageId);
722
+ } catch (error) {
723
+ this._pendingDeleteEvictions.delete(messageId);
724
+ throw error;
725
+ }
586
726
  return;
587
727
  }
588
728
 
589
729
  if (!this._store.setMessages)
590
730
  throw new Error("Runtime does not support deleting messages.");
591
731
 
592
- if (this._store.isRunning) {
732
+ if (this._getEffectiveIsRunning(this._store)) {
593
733
  await this._toolInvocations?.abort();
594
734
  }
595
735
 
@@ -597,7 +737,32 @@ export class ExternalStoreThreadRuntimeCore
597
737
  const messageIndex = messages.findIndex((m) => m.id === messageId);
598
738
  if (messageIndex === -1) throw new Error("Message not found.");
599
739
 
740
+ this._pendingDeleteEvictions.clear();
600
741
  this.updateMessages(messages.filter((message) => message.id !== messageId));
742
+ this._evictDeletedMessage(messageId);
743
+ }
744
+
745
+ // The snapshot pass only relinks incoming messages; it never evicts, so
746
+ // without this the deleted message survives as a sibling branch that the
747
+ // branch picker can resurrect into the host store. `_messages` is refreshed
748
+ // before notifying so `messages` and the branch graph agree at notify time,
749
+ // mirroring the end of the snapshot pass.
750
+ private _evictDeletedMessage(messageId: string) {
751
+ // Positional fallback ids are remapped in the snapshot pass; evicting
752
+ // them first leaves the pre-renumber node as a sibling of the new head.
753
+ if (messageId.startsWith(FALLBACK_ID_PREFIX)) return;
754
+ // A synchronous host update (e.g. a setMessages that re-entered the
755
+ // snapshot pass) may have evicted the message already; only that case is
756
+ // skipped, so genuine repository errors still propagate.
757
+ try {
758
+ this.repository.getMessage(messageId);
759
+ } catch {
760
+ return;
761
+ }
762
+
763
+ this.repository.deleteMessage(messageId);
764
+ this._messages = this.repository.getMessages();
765
+ this._notifySubscribers();
601
766
  }
602
767
 
603
768
  public getQueueItems() {
@@ -622,10 +787,12 @@ export class ExternalStoreThreadRuntimeCore
622
787
  if (!this._store.onReload)
623
788
  throw new Error("Runtime does not support reloading messages.");
624
789
 
790
+ this._pendingDeleteEvictions.clear();
791
+
625
792
  // Auto-abort in-flight client-side tool executions when a run reloads;
626
793
  // any results that land afterward would target a turn that no longer
627
794
  // exists. See `append` above for full rationale.
628
- await this._toolInvocations?.abort();
795
+ await this._toolInvocations?.abort({ discardPending: true });
629
796
 
630
797
  await this._store.onReload(config.parentId, config);
631
798
  }
@@ -655,7 +822,7 @@ export class ExternalStoreThreadRuntimeCore
655
822
  // back here via __internal_setAdapter. The tracker publishes the
656
823
  // cleared status map itself, so adapter-side statuses reset only when
657
824
  // the tracker is the source of truth.
658
- this._toolInvocations?.reset();
825
+ this._runTrackerUpdate(() => this._toolInvocations?.reset());
659
826
 
660
827
  this._store.onLoadExternalState(state);
661
828
  }
@@ -666,7 +833,7 @@ export class ExternalStoreThreadRuntimeCore
666
833
  * without run-cancel semantics (`onCancel`, composer draft restoration).
667
834
  */
668
835
  public unstable_notifySessionReset(): void {
669
- this._toolInvocations?.reset();
836
+ this._runTrackerUpdate(() => this._toolInvocations?.reset());
670
837
  this._store.queue?.__internal_notifyCancelled?.();
671
838
  }
672
839
 
@@ -679,7 +846,7 @@ export class ExternalStoreThreadRuntimeCore
679
846
  // Abort any in-flight client-side tool executions. Fire-and-forget —
680
847
  // the abort resolves once executions settle, but we don't gate the
681
848
  // cancel on it.
682
- void this._toolInvocations?.abort();
849
+ void this._toolInvocations?.abort({ discardPending: true });
683
850
 
684
851
  // Before the run is aborted, so the settle it produces keeps the pending
685
852
  // items instead of dispatching the next one at the moment the user
@@ -789,13 +956,16 @@ export class ExternalStoreThreadRuntimeCore
789
956
  );
790
957
  }
791
958
 
792
- public respondToToolApproval(options: RespondToToolApprovalOptions) {
959
+ public respondToToolApproval(
960
+ options: RespondToToolApprovalOptions,
961
+ ): Promise<void> {
793
962
  if (!this._store.onRespondToToolApproval)
794
963
  throw new Error("Runtime does not support tool approvals.");
795
- observeAdapterCallback(
796
- "onRespondToToolApproval",
797
- this._store.onRespondToToolApproval(options),
798
- );
964
+ try {
965
+ return Promise.resolve(this._store.onRespondToToolApproval(options));
966
+ } catch (error) {
967
+ return Promise.reject(error);
968
+ }
799
969
  }
800
970
 
801
971
  public override reset(initialMessages?: readonly ThreadMessageLike[]) {
@@ -136,7 +136,7 @@ export abstract class InertThreadRuntimeCore
136
136
  throw this.error;
137
137
  }
138
138
 
139
- respondToToolApproval(): void {
139
+ respondToToolApproval(): Promise<void> {
140
140
  throw this.error;
141
141
  }
142
142