@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
@@ -2,6 +2,7 @@ import type {
2
2
  RemoteThreadInitializeResponse,
3
3
  RemoteThreadMetadata,
4
4
  } from "./types";
5
+ import { generateId } from "../../utils/id";
5
6
 
6
7
  export type RemoteThreadData =
7
8
  | {
@@ -11,6 +12,7 @@ export type RemoteThreadData =
11
12
  readonly status: "new";
12
13
  readonly title: undefined;
13
14
  readonly custom: undefined;
15
+ readonly localOrigin?: true;
14
16
  }
15
17
  | {
16
18
  readonly id: string;
@@ -20,6 +22,7 @@ export type RemoteThreadData =
20
22
  readonly status: "regular" | "archived";
21
23
  readonly title?: string | undefined;
22
24
  readonly custom: undefined;
25
+ readonly localOrigin?: true;
23
26
  }
24
27
  | {
25
28
  readonly id: string;
@@ -30,6 +33,7 @@ export type RemoteThreadData =
30
33
  readonly title?: string | undefined;
31
34
  readonly lastMessageAt?: Date | undefined;
32
35
  readonly custom?: Record<string, unknown> | undefined;
36
+ readonly localOrigin?: true;
33
37
  };
34
38
 
35
39
  export type THREAD_MAPPING_ID = string & { __brand: "THREAD_MAPPING_ID" };
@@ -38,29 +42,34 @@ export function createThreadMappingId(id: string): THREAD_MAPPING_ID {
38
42
  return id as THREAD_MAPPING_ID;
39
43
  }
40
44
 
45
+ export const LOCAL_THREAD_ID_PREFIX = "__LOCALID_";
46
+
41
47
  export const normalizeCursor = (c: string | undefined): string | undefined =>
42
48
  c || undefined;
43
49
 
44
- type ClassifyAccumulator = {
50
+ export type ClassifyAccumulator = {
45
51
  threadIds: string[];
46
52
  archivedThreadIds: string[];
47
53
  threadIdMap: Record<string, THREAD_MAPPING_ID>;
48
54
  threadData: Record<THREAD_MAPPING_ID, RemoteThreadData>;
49
55
  };
50
56
 
57
+ // A slot's `id` is fixed when it is minted: the hook instance manager keys live
58
+ // thread runtimes by it, so renaming a slot would detach the runtime the user is
59
+ // chatting in. A listed thread whose `remoteId` already maps to a slot therefore
60
+ // refreshes that slot instead of minting a second one, and a slot minted by a
61
+ // list() that raced ahead of the remote id collapses when `initialize()` settles.
62
+ // `threadIds`/`archivedThreadIds` carry slot ids, never remote ids.
51
63
  export const classifyThreads = (
52
64
  threads: readonly RemoteThreadMetadata[],
53
65
  acc: ClassifyAccumulator,
54
66
  ): ClassifyAccumulator => {
55
- for (const thread of threads) {
56
- if (acc.threadIdMap[thread.remoteId] !== undefined) continue;
67
+ const listed = new Set([...acc.threadIds, ...acc.archivedThreadIds]);
57
68
 
69
+ for (const thread of threads) {
58
70
  switch (thread.status) {
59
71
  case "regular":
60
- acc.threadIds.push(thread.remoteId);
61
- break;
62
72
  case "archived":
63
- acc.archivedThreadIds.push(thread.remoteId);
64
73
  break;
65
74
  default: {
66
75
  const _exhaustiveCheck: never = thread.status;
@@ -68,20 +77,52 @@ export const classifyThreads = (
68
77
  }
69
78
  }
70
79
 
71
- const mappingId = createThreadMappingId(thread.remoteId);
80
+ const existingMappingId = acc.threadIdMap[thread.remoteId];
81
+ const existing =
82
+ existingMappingId !== undefined
83
+ ? acc.threadData[existingMappingId]
84
+ : undefined;
85
+ const id = existing?.id ?? thread.remoteId;
86
+ const mappingId = existingMappingId ?? createThreadMappingId(id);
87
+ const existingTask =
88
+ existing !== undefined && existing.status !== "new"
89
+ ? existing.initializeTask
90
+ : undefined;
91
+
92
+ if (!listed.has(id)) {
93
+ listed.add(id);
94
+ if (thread.status === "regular") {
95
+ acc.threadIds.push(id);
96
+ } else {
97
+ acc.archivedThreadIds.push(id);
98
+ }
99
+ } else if (existing !== undefined && existing.status !== thread.status) {
100
+ if (thread.status === "regular") {
101
+ acc.archivedThreadIds = acc.archivedThreadIds.filter((t) => t !== id);
102
+ acc.threadIds.push(id);
103
+ } else {
104
+ acc.threadIds = acc.threadIds.filter((t) => t !== id);
105
+ acc.archivedThreadIds.push(id);
106
+ }
107
+ }
108
+
109
+ acc.threadIdMap[id] = mappingId;
72
110
  acc.threadIdMap[thread.remoteId] = mappingId;
73
111
  acc.threadData[mappingId] = {
74
- id: thread.remoteId,
112
+ ...(existing?.localOrigin === true ? { localOrigin: true as const } : {}),
113
+ id,
75
114
  remoteId: thread.remoteId,
76
115
  externalId: thread.externalId,
77
116
  status: thread.status,
78
117
  title: thread.title,
79
118
  lastMessageAt: thread.lastMessageAt,
80
119
  custom: thread.custom,
81
- initializeTask: Promise.resolve({
82
- remoteId: thread.remoteId,
83
- externalId: thread.externalId,
84
- }),
120
+ initializeTask:
121
+ existingTask ??
122
+ Promise.resolve({
123
+ remoteId: thread.remoteId,
124
+ externalId: thread.externalId,
125
+ }),
85
126
  };
86
127
  }
87
128
  return acc;
@@ -98,6 +139,123 @@ export type RemoteThreadState = {
98
139
  readonly threadData: Readonly<Record<THREAD_MAPPING_ID, RemoteThreadData>>;
99
140
  };
100
141
 
142
+ export const createEmptyRemoteThreadState = (): RemoteThreadState => ({
143
+ isLoading: true,
144
+ isLoadingMore: false,
145
+ cursor: undefined,
146
+ newThreadId: undefined,
147
+ threadIds: [],
148
+ archivedThreadIds: [],
149
+ threadIdMap: {},
150
+ threadData: {},
151
+ });
152
+
153
+ export const seedNewThread = (
154
+ state: RemoteThreadState,
155
+ ): { id: string; state: RemoteThreadState } => {
156
+ let id: string;
157
+ do {
158
+ id = `${LOCAL_THREAD_ID_PREFIX}${generateId()}`;
159
+ } while (state.threadIdMap[id]);
160
+ const mappingId = createThreadMappingId(id);
161
+ return {
162
+ id,
163
+ state: {
164
+ ...state,
165
+ newThreadId: id,
166
+ threadIdMap: {
167
+ ...state.threadIdMap,
168
+ [id]: mappingId,
169
+ },
170
+ threadData: {
171
+ ...state.threadData,
172
+ [mappingId]: {
173
+ status: "new",
174
+ id,
175
+ remoteId: undefined,
176
+ externalId: undefined,
177
+ title: undefined,
178
+ custom: undefined,
179
+ localOrigin: true,
180
+ } satisfies RemoteThreadData,
181
+ },
182
+ },
183
+ };
184
+ };
185
+
186
+ // A list() response predating a mid-flight local transition (a thread
187
+ // initialized while the request was running) omits that thread, and the
188
+ // completed-optimistic replay cannot re-add it because the merged threadData
189
+ // already carries the final status. Threads whose status moved from new (or
190
+ // nonexistent) at request time to regular/archived are re-inserted at the
191
+ // top, in the order the pre-response lists carried them: updateStatusReducer
192
+ // prepends as transitions happen, so the pre-response lists hold newest
193
+ // first, which threadData insertion order need not match. Threads the server already knew stay governed by the response, so
194
+ // a server-side deletion is not resurrected — and a thread unknown to the
195
+ // snapshot is only rescued when it carries the localOrigin marker stamped at
196
+ // draft creation, so a deep-linked thread the fetch path deliberately
197
+ // appended at the tail is not hoisted, whatever its remote id looks like.
198
+ export const preserveMidLoadTransitions = (
199
+ state: RemoteThreadState,
200
+ priorOrder: Pick<RemoteThreadState, "threadIds" | "archivedThreadIds">,
201
+ statusAtRequest: ReadonlyMap<string, RemoteThreadData["status"]>,
202
+ ): RemoteThreadState => {
203
+ const regular = new Set(state.threadIds);
204
+ const archived = new Set(state.archivedThreadIds);
205
+ const rescuedRegular: RemoteThreadData[] = [];
206
+ const rescuedArchived: RemoteThreadData[] = [];
207
+
208
+ const contains = (ids: ReadonlySet<string>, data: RemoteThreadData) =>
209
+ ids.has(data.id) || (data.remoteId !== undefined && ids.has(data.remoteId));
210
+
211
+ for (const data of Object.values(state.threadData)) {
212
+ const before = statusAtRequest.get(data.id);
213
+ if (before !== undefined && before !== "new") continue;
214
+ if (before === undefined && data.localOrigin !== true) continue;
215
+
216
+ if (data.status === "regular" && !contains(regular, data)) {
217
+ rescuedRegular.push(data);
218
+ regular.add(data.id);
219
+ } else if (data.status === "archived" && !contains(archived, data)) {
220
+ rescuedArchived.push(data);
221
+ archived.add(data.id);
222
+ }
223
+ }
224
+
225
+ if (rescuedRegular.length === 0 && rescuedArchived.length === 0) return state;
226
+
227
+ const position = (ids: readonly string[], data: RemoteThreadData) => {
228
+ const byId = ids.indexOf(data.id);
229
+ if (byId !== -1) return byId;
230
+ const byRemoteId =
231
+ data.remoteId !== undefined ? ids.indexOf(data.remoteId) : -1;
232
+ return byRemoteId !== -1 ? byRemoteId : Number.MAX_SAFE_INTEGER;
233
+ };
234
+ rescuedRegular.sort(
235
+ (a, b) =>
236
+ position(priorOrder.threadIds, a) - position(priorOrder.threadIds, b),
237
+ );
238
+ rescuedArchived.sort(
239
+ (a, b) =>
240
+ position(priorOrder.archivedThreadIds, a) -
241
+ position(priorOrder.archivedThreadIds, b),
242
+ );
243
+
244
+ return {
245
+ ...state,
246
+ threadIds: [...rescuedRegular.map((d) => d.id), ...state.threadIds],
247
+ archivedThreadIds: [
248
+ ...rescuedArchived.map((d) => d.id),
249
+ ...state.archivedThreadIds,
250
+ ],
251
+ };
252
+ };
253
+
254
+ export const statusSnapshot = (
255
+ state: RemoteThreadState,
256
+ ): ReadonlyMap<string, RemoteThreadData["status"]> =>
257
+ new Map(Object.values(state.threadData).map((d) => [d.id, d.status]));
258
+
101
259
  export const getThreadData = (
102
260
  state: RemoteThreadState,
103
261
  threadIdOrRemoteId: string,
@@ -115,7 +273,7 @@ export const updateStatusReducer = (
115
273
  const data = getThreadData(state, threadIdOrRemoteId);
116
274
  if (!data) return state;
117
275
 
118
- const { id, remoteId, status: lastStatus } = data;
276
+ const { id, status: lastStatus } = data;
119
277
  if (lastStatus === newStatus) return state;
120
278
 
121
279
  const newState = { ...state };
@@ -150,16 +308,20 @@ export const updateStatusReducer = (
150
308
  newState.archivedThreadIds = [id, ...newState.archivedThreadIds];
151
309
  break;
152
310
 
153
- case "deleted":
311
+ case "deleted": {
312
+ const mappingId = state.threadIdMap[threadIdOrRemoteId]!;
154
313
  newState.threadData = Object.fromEntries(
155
- Object.entries(newState.threadData).filter(([key]) => key !== id),
314
+ Object.entries(newState.threadData).filter(
315
+ ([key]) => key !== mappingId,
316
+ ),
156
317
  );
157
318
  newState.threadIdMap = Object.fromEntries(
158
319
  Object.entries(newState.threadIdMap).filter(
159
- ([key]) => key !== id && key !== remoteId,
320
+ ([, value]) => value !== mappingId,
160
321
  ),
161
322
  );
162
323
  break;
324
+ }
163
325
 
164
326
  default: {
165
327
  const _exhaustiveCheck: never = newStatus;
@@ -0,0 +1,3 @@
1
+ export const isTitleSourceMessage = (message: {
2
+ status?: { type: string } | undefined;
3
+ }) => message.status?.type !== "running";
@@ -78,11 +78,12 @@ export type RemoteThreadListAdapter = {
78
78
  unstable_Provider?: RemoteThreadListProviderComponent | undefined;
79
79
 
80
80
  /**
81
- * Hook the `RemoteThreadList` store entry calls once for the main-thread
82
- * slot, then provides to the `thread` factory. This is not mounted per
83
- * listed thread. `useRemoteThreadListRuntime` also calls it when
84
- * `unstable_Provider` is omitted. Resolve `threadListItem` lazily on each
85
- * adapter call; do not capture it at hook mount. The hook must keep a
81
+ * Hook the `RemoteThreadList` store entry calls once per mounted thread
82
+ * body (the main-thread slot by default; every started thread with
83
+ * `backgroundThreads`), then provides to the `thread` factory. This is not
84
+ * mounted per listed thread. `useRemoteThreadListRuntime` also calls it
85
+ * when `unstable_Provider` is omitted. Resolve `threadListItem` lazily on
86
+ * each adapter call; do not capture it at hook mount. The hook must keep a
86
87
  * stable hook count across adapter swaps; a different count throws.
87
88
  * Memoize the returned object.
88
89
  *
@@ -11,8 +11,9 @@ observe via `setState(snapshot)` and what the current behavior is.
11
11
  > result is replaced, result is cleared, key order shuffles — the tracker
12
12
  > never invokes the host's tool callback a second time.
13
13
  >
14
- > `reset()` starts a new execution boundary. A reused `toolCallId` in the
15
- > next boundary gets a new execution identity and may fire once there.
14
+ > `reset()` starts a new execution boundary, and so does the single
15
+ > pipeline restart after a stream failure (F.4). A reused `toolCallId` in
16
+ > the next boundary gets a new execution identity and may fire once there.
16
17
 
17
18
  This guarantees host-side side effects (the typical reason `streamCall` /
18
19
  `execute` exists at all) can't double-run. The cost: post-completion
@@ -78,6 +79,117 @@ sees only the first result.
78
79
  ### A.7. Previously-resolved tool loses its `result` (back to undefined)
79
80
  Silently ignored. The entry stays in the resolved phase internally.
80
81
 
82
+ ### A.8. Tool call carries a provider `approval`
83
+ The entry is marked `skipExecute`, exactly like a call observed with
84
+ a `result`, whether the gate is present when the call is first observed
85
+ or lands on an already-active entry. A gate belongs to the provider:
86
+ `approved === true` means the provider is producing the result, `false`
87
+ means it records the denial, so the frontend `execute` never fires for
88
+ that `toolCallId` once the gate is present. `streamCall` still fires
89
+ once and the backend result flows through A.5 when it lands.
90
+
91
+ If the gate lands after the args stream has closed but before an
92
+ in-flight `execute` resolves, the execute runs to completion (its side
93
+ effects happen) but its result chunk is dropped: `onResult` never fires,
94
+ and the `executing` status, plus any `human()` interrupt the execution
95
+ parked, stays up until the promise settles. Only a gate that lands after
96
+ the result chunk has already been emitted is fully too late.
97
+
98
+ A call the adapter reports as client-owned reaches that window while the
99
+ run is still open; a call whose ownership is unknown reaches it when the
100
+ run settles before the gate arrives (A.10). Either way the client was
101
+ meant to run it, so nothing but the gate's arrival says otherwise and the
102
+ gate is late by construction.
103
+
104
+ ### A.9. Adapter reports the tool call as provider-owned
105
+ The entry is marked `skipExecute` at creation, exactly like a call
106
+ observed with a `result`. `unstable_isClientToolCall` is read once, when
107
+ the call is first observed live, and never re-read: ownership is fixed
108
+ when the provider emits the call, so a later snapshot cannot revoke it
109
+ and drop the result of an execute already in flight. `streamCall` still
110
+ fires once, as under A.8; only the wrapped `execute` and its result
111
+ chunk are withheld.
112
+
113
+ Outside production, a provider-owned call whose name resolves to a tool
114
+ with an `execute` logs a `console.warn`. The two together are a
115
+ misconfiguration: the provider answers the call, so the registered
116
+ `execute` would never run and the skip is otherwise silent.
117
+
118
+ The predicate is also what licenses running a frontend tool before the
119
+ provider's run ends, so an adapter that supplies it keeps the overlap
120
+ between a client tool's work and the run tail (A.10).
121
+
122
+ ### A.10. Args complete while the provider's run is still open
123
+ Closing the args stream hands the call to the client executor, so it may
124
+ only happen once the provider can no longer speak about that call. A
125
+ provider may still answer the call (A.5) or gate it (A.8) one or more
126
+ snapshots after its arguments complete, and a protocol can carry the
127
+ outcome no earlier: AG-UI projects an interrupt only from `RUN_FINISHED`.
128
+ The run ending is the only universal signal, so a call whose ownership is
129
+ unknown closes when the snapshot's `isRunning` goes false.
130
+
131
+ `ExternalStoreThreadRuntimeCore` feeds the tracker
132
+ `store.isRunning || _hasExecutingTools(store)`, so that condition also covers
133
+ a client tool mid-`execute`. That defers an unknown-ownership sibling only
134
+ while a client-owned call is actually executing, which no shipped adapter
135
+ produces: every entry pending in a snapshot closes in the same
136
+ `_processMessages` pass, an adapter that supplies the predicate classifies
137
+ every call, and an execution parked on `human()` reports `interrupt` rather
138
+ than `executing`, which `_hasExecutingTools` does not count.
139
+
140
+ That holds even when `execute` opens with `await human()`. The stream
141
+ fires `onExecutionStart` only after `execute` returns, because until then
142
+ it cannot tell a frontend tool from one without an `execute`, so by the
143
+ time the callback runs the body has already parked its resolver and set
144
+ `interrupt`. `_onExecutionStart` still registers the execution for
145
+ `_onExecutionEnd` but leaves the status alone when this execution's own
146
+ request is pending. The check is keyed on the request's execution id,
147
+ not on the status map: a pipeline restart (F.4) clears `_executing` but
148
+ keeps the status map, and a stale `interrupt` must not stop the fresh
149
+ execution from reporting `executing` (#6763).
150
+
151
+ A call the adapter reports as client-owned (A.9) closes as soon as its
152
+ arguments parse, because the adapter has already said the provider will
153
+ not answer it. Ownership says who answers a call, not whether it is
154
+ gated, so a gate on such a call is still late and A.8 governs it
155
+ (#6677).
156
+
157
+ ### A.11. The turn is discarded while a call waits on the run
158
+ `abort({ discardPending: true })` records every active entry that has
159
+ neither closed its args stream nor holds a result in
160
+ `_discardedToolCallIds`, and marks it `skipExecute`.
161
+
162
+ The abort signal alone does not cover these. A call waiting on the run to
163
+ settle (A.10) has not reached the executor, so there is nothing to signal,
164
+ and `abort()` installs a fresh `AbortController` before the settled
165
+ snapshot arrives; without the record, cancelling a run would be what
166
+ starts the call it was meant to stop.
167
+
168
+ `discardPending` is the caller's claim that the turn is over, not that it
169
+ is being interrupted, so only the three callers that end it pass it: a new
170
+ turn starting, a reload, and `cancelRun`. `deleteMessage` does not: its
171
+ `setMessages` fallback aborts while the provider run continues, and
172
+ discarding there would strand that run's remaining calls result-less,
173
+ while its `onDelete` path never aborts at all. `reset()` is unaffected
174
+ either way: it clears `_entries` and the recorded ids before aborting,
175
+ because it opens a new execution boundary.
176
+
177
+ An id is forgotten once a live snapshot observes the call with a result,
178
+ which bounds the set to the open calls of a discarded turn. That is all
179
+ it does: an id re-emitted inside the same execution boundary keeps its
180
+ existing entry, so A.4 and A.7 govern it rather than this set, and a new
181
+ boundary clears the set outright. The residual is a call that is
182
+ discarded, answered, and then loses its result (A.7) across a pipeline
183
+ restart; it is left to A.7 rather than pinned here, because holding the
184
+ id past the answer would trade a five-step chain for a set that grows for
185
+ the life of the tracker.
186
+
187
+ The record lives on the tracker rather than the entry because it is the one
188
+ reason to skip that no later snapshot carries: an `approval` is re-read at
189
+ each snapshot and provider ownership is recomputed, while a rebuilt entry
190
+ would otherwise come back clean. That is what lets F.4 drop a waiting entry
191
+ without a special case.
192
+
81
193
  ## B. Tool call disappears from snapshot
82
194
 
83
195
  ### B.1. Tool call removed entirely (rollback, branch switch)
@@ -176,7 +288,17 @@ The `.pipeTo(...).catch(...)` handler logs and flips `_pipelineDead`.
176
288
  The next `setState` call recreates the pipeline once per tracker
177
289
  lifetime: existing active entries are *demoted to restored* (so the
178
290
  rebuilt pipeline does not re-fire `streamCall` for them) and the
179
- snapshot is processed against the fresh pipeline. Repeated failures
291
+ snapshot is processed against the fresh pipeline. An active entry that
292
+ neither closed its args stream nor holds a result is dropped instead of
293
+ demoted: a restored entry is promoted only when its signature changes,
294
+ and a call waiting on the run to settle (A.10) already holds its final
295
+ args, so demoting it would strand it unexecuted.
296
+
297
+ Starting it over re-fires `streamCall`, which the restart path already
298
+ does for any demoted entry whose signature later changes. The rebuilt
299
+ pipeline holds no part for the call, so nothing can reach the executor
300
+ without adding one; a restart is an execution boundary in the same sense
301
+ `reset()` is. Repeated failures
180
302
  keep the tracker dead with a visible error to avoid restart loops.
181
303
 
182
304
  ### F.5. Reset followed by same-id reuse