@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,4 +1,4 @@
1
- import { ThreadMessage } from "../../types/message.js";
1
+ import { ThreadMessage, ToolCallMessagePart } from "../../types/message.js";
2
2
  import { Tool, ToolModelContentPart } from "assistant-stream";
3
3
  import { ReadonlyJSONValue } from "assistant-stream/utils";
4
4
  //#region src/runtimes/tool-invocations/ToolInvocationTracker.d.ts
@@ -48,9 +48,17 @@ type AddToolResultCommand = {
48
48
  declare class ToolInvocationTracker {
49
49
  private readonly _getTools;
50
50
  private readonly _callbacks;
51
+ private readonly _isClientToolCall;
51
52
  private readonly _entries;
52
53
  private readonly _humanInput;
53
54
  private readonly _executing;
55
+ /**
56
+ * Tool calls whose turn ended before they reached the executor. Held here
57
+ * rather than on the entry because an entry is rebuilt whenever a snapshot
58
+ * re-creates the call, and this is the one reason to skip that no later
59
+ * snapshot carries.
60
+ */
61
+ private readonly _discardedToolCallIds;
54
62
  private readonly _settledResolvers;
55
63
  private _statuses;
56
64
  private _ac;
@@ -62,14 +70,16 @@ declare class ToolInvocationTracker {
62
70
  /**
63
71
  * Set when the assistant-stream pipeline has died (errored out via
64
72
  * `.pipeTo(...).catch(...)`). The next `setState` re-initializes the
65
- * pipeline and demotes all active entries to restored so they survive
66
- * across the restart without re-firing `streamCall` (preserves the
67
- * "exactly once" contract). Capped at a single auto-restart per session
68
- * — repeated failures keep the tracker dead with a more visible error.
73
+ * pipeline and demotes each active entry that reached the executor to
74
+ * restored, so it survives the restart without re-firing `streamCall`.
75
+ * A restart is an execution boundary like `reset()`: an entry that had
76
+ * not reached it starts over and fires once there (F.4). Capped at a
77
+ * single auto-restart per session — repeated failures keep the tracker
78
+ * dead with a more visible error.
69
79
  */
70
80
  private _pipelineDead;
71
81
  private _pipelineRestartUsed;
72
- constructor(getTools: () => Record<string, Tool> | undefined, callbacks: ToolInvocationTracker.Callbacks);
82
+ constructor(getTools: () => Record<string, Tool> | undefined, callbacks: ToolInvocationTracker.Callbacks, isClientToolCall?: (toolCall: ToolCallMessagePart) => boolean | undefined);
73
83
  /**
74
84
  * Build the assistant-stream pipeline. Called once from the constructor
75
85
  * and at most once again if `_pipelineDead` is set (see F.4 in
@@ -90,8 +100,15 @@ declare class ToolInvocationTracker {
90
100
  /**
91
101
  * Abort any in-flight `execute()` invocations. Resolves once all of them
92
102
  * have settled (or immediately if none are running).
103
+ *
104
+ * `discardPending` additionally kills the calls that never reached the
105
+ * executor, for a caller ending the turn rather than interrupting it. The
106
+ * signal cannot reach those: they are waiting on the run to settle (A.10),
107
+ * and the settled snapshot arrives after this installs a fresh controller.
93
108
  */
94
- abort(): Promise<void>;
109
+ abort(options?: {
110
+ discardPending?: boolean;
111
+ }): Promise<void>;
95
112
  /**
96
113
  * Resolve a pending human-input request for the given tool call. Returns
97
114
  * `true` if a pending request was resumed, `false` if the tracker has no
@@ -116,7 +133,13 @@ declare class ToolInvocationTracker {
116
133
  private _invokeOnStatusesChange;
117
134
  private _setStatus;
118
135
  private _deleteStatus;
119
- private _hasExecutableTool;
136
+ private _warnProviderOwnedSkip;
137
+ /**
138
+ * Closing the args stream hands the call to the client executor, so it may
139
+ * only happen once the provider can no longer speak about that call. The run
140
+ * ending is the only universal signal for that; an adapter that reports the
141
+ * call as client-owned has said it earlier, per call.
142
+ */
120
143
  private _shouldCloseArgsStream;
121
144
  private _startActiveEntry;
122
145
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"ToolInvocationTracker.d.ts","names":[],"sources":["../../../src/runtimes/tool-invocations/ToolInvocationTracker.ts"],"mappings":";;;;;;;KAuBY;EACN;;EAEA;EACA;IAAW;IAAe;;;KAGpB;WACD;WACA;WACA;WACA,QAAQ;WACR;WACA,WAAW;WACX,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;cA8EtB;mBACM;mBACA;mBAEA;mBACA;mBAQA;mBACA;UAET;UAEA;UACA;;UAGA;UACA;UAEA;;;;;;;;;UAUA;UACA;EAGN,YAAA,gBAAgB,eAAe,mBAC/B,WAAW,sBAAsB;;;;;;UAa3B;;;;;EAsDD,SAAS,UAAU,sBAAsB;;;;;;EAmEzC;;;;;EAwBA,SAAS;;;;;;;EAkCT,OAAO,oBAAoB;;;;;;;EAoB3B,eAAe,oBAAoB;UAMlC;UA6CA;UAaA;UAmCA;UAYA;UA0BA;UAiCA;UAWA;UAaA;UAOA;UAUA;UAKA;UAgBA;;;;;;;;UA4BA;UAWA;UA0GA;;kBAiFO;OACH,kBAAkB;OAElB;aACD,mBAAmB;;aAEnB;;;;;;aAMA;;OAGC;;;;;IAKV,WAAW,SAAS;;;;;;IAMpB,mBACE,UAAU,oBAAoB"}
1
+ {"version":3,"file":"ToolInvocationTracker.d.ts","names":[],"sources":["../../../src/runtimes/tool-invocations/ToolInvocationTracker.ts"],"mappings":";;;;;;;KAwBY;EACN;;EAEA;EACA;IAAW;IAAe;;;KAGpB;WACD;WACA;WACA;WACA,QAAQ;WACR;WACA,WAAW;WACX,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;cA+EtB;mBACM;mBACA;mBACA;mBAIA;mBACA;mBAQA;;;;;;;mBAOA;mBACA;UAET;UAEA;UACA;;UAGA;UACA;UAEA;;;;;;;;;;;UAYA;UACA;EAGN,YAAA,gBAAgB,eAAe,mBAC/B,WAAW,sBAAsB,WACjC,oBAAoB,UAAU;;;;;;UAcxB;;;;;EAsDD,SAAS,UAAU,sBAAsB;;;;;;EAmEzC;;;;;;;;;;EA8BA,MAAM;IAAY;MAA6B;;;;;;;EA2C/C,OAAO,oBAAoB;;;;;;;EAoB3B,eAAe,oBAAoB;UAMlC;UA6CA;UAaA;UAmCA;UAcA;UA0BA;UAkCA;UAWA;UAaA;UAOA;UAUA;;;;;;;UAeA;UAcA;;;;;;;;UA8BA;UAqBA;UA0GA;;kBAmFO;OACH,kBAAkB;OAElB;aACD,mBAAmB;;aAEnB;;;;;;aAMA;;OAGC;;;;;IAKV,WAAW,SAAS;;;;;;IAMpB,mBACE,UAAU,oBAAoB"}
@@ -1,4 +1,5 @@
1
1
  import { isJSONValueEqual } from "../../utils/json/is-json-equal.js";
2
+ import { walkToolCallTree } from "../../runtime/utils/tool-call-tree.js";
2
3
  import { ToolResponse, createAssistantStreamController, unstable_toolResultStream } from "assistant-stream";
3
4
  import { AssistantMetaTransformStream } from "assistant-stream/utils";
4
5
  //#region src/runtimes/tool-invocations/ToolInvocationTracker.ts
@@ -50,9 +51,17 @@ const getToolExecutionId = (value) => value[TOOL_EXECUTION_ID];
50
51
  var ToolInvocationTracker = class {
51
52
  _getTools;
52
53
  _callbacks;
54
+ _isClientToolCall;
53
55
  _entries = /* @__PURE__ */ new Map();
54
56
  _humanInput = /* @__PURE__ */ new Map();
55
57
  _executing = /* @__PURE__ */ new Set();
58
+ /**
59
+ * Tool calls whose turn ended before they reached the executor. Held here
60
+ * rather than on the entry because an entry is rebuilt whenever a snapshot
61
+ * re-creates the call, and this is the one reason to skip that no later
62
+ * snapshot carries.
63
+ */
64
+ _discardedToolCallIds = /* @__PURE__ */ new Set();
56
65
  _settledResolvers = [];
57
66
  _statuses = /* @__PURE__ */ new Map();
58
67
  _ac = new AbortController();
@@ -64,16 +73,19 @@ var ToolInvocationTracker = class {
64
73
  /**
65
74
  * Set when the assistant-stream pipeline has died (errored out via
66
75
  * `.pipeTo(...).catch(...)`). The next `setState` re-initializes the
67
- * pipeline and demotes all active entries to restored so they survive
68
- * across the restart without re-firing `streamCall` (preserves the
69
- * "exactly once" contract). Capped at a single auto-restart per session
70
- * — repeated failures keep the tracker dead with a more visible error.
76
+ * pipeline and demotes each active entry that reached the executor to
77
+ * restored, so it survives the restart without re-firing `streamCall`.
78
+ * A restart is an execution boundary like `reset()`: an entry that had
79
+ * not reached it starts over and fires once there (F.4). Capped at a
80
+ * single auto-restart per session — repeated failures keep the tracker
81
+ * dead with a more visible error.
71
82
  */
72
83
  _pipelineDead = false;
73
84
  _pipelineRestartUsed = false;
74
- constructor(getTools, callbacks) {
85
+ constructor(getTools, callbacks, isClientToolCall) {
75
86
  this._getTools = getTools;
76
87
  this._callbacks = callbacks;
88
+ this._isClientToolCall = isClientToolCall;
77
89
  this._initPipeline();
78
90
  }
79
91
  /**
@@ -141,6 +153,7 @@ var ToolInvocationTracker = class {
141
153
  try {
142
154
  this._pendingRestore = true;
143
155
  this._entries.clear();
156
+ this._discardedToolCallIds.clear();
144
157
  this._lastSnapshot = null;
145
158
  this.abort();
146
159
  if (this._statuses.size > 0) {
@@ -154,8 +167,13 @@ var ToolInvocationTracker = class {
154
167
  /**
155
168
  * Abort any in-flight `execute()` invocations. Resolves once all of them
156
169
  * have settled (or immediately if none are running).
170
+ *
171
+ * `discardPending` additionally kills the calls that never reached the
172
+ * executor, for a caller ending the turn rather than interrupting it. The
173
+ * signal cannot reach those: they are waiting on the run to settle (A.10),
174
+ * and the settled snapshot arrives after this installs a fresh controller.
157
175
  */
158
- abort() {
176
+ abort(options) {
159
177
  try {
160
178
  this._humanInput.forEach(({ reject }) => {
161
179
  try {
@@ -163,6 +181,12 @@ var ToolInvocationTracker = class {
163
181
  } catch {}
164
182
  });
165
183
  this._humanInput.clear();
184
+ if (options?.discardPending) for (const [toolCallId, entry] of this._entries) {
185
+ if (!entry.controller) continue;
186
+ if (entry.argsComplete || entry.hasResult) continue;
187
+ this._discardedToolCallIds.add(toolCallId);
188
+ entry.skipExecute = true;
189
+ }
166
190
  this._ac.abort();
167
191
  this._ac = new AbortController();
168
192
  if (this._executing.size === 0) return Promise.resolve();
@@ -265,6 +289,7 @@ var ToolInvocationTracker = class {
265
289
  if (!this._captureExecution(toolCallId, executionId)) return;
266
290
  if (this._entries.get(toolCallId).skipExecute) return;
267
291
  this._executing.add(executionId);
292
+ if (this._humanInput.get(toolCallId)?.executionId === executionId) return;
268
293
  this._setStatus(toolCallId, { type: "executing" });
269
294
  }
270
295
  _onExecutionEnd(toolCallId, executionId) {
@@ -292,6 +317,7 @@ var ToolInvocationTracker = class {
292
317
  const entry = this._entries.get(toolCallId);
293
318
  if (!entry || entry.executionId !== executionId) return;
294
319
  if (entry?.hasResult) return;
320
+ if (entry.skipExecute) return;
295
321
  this._invokeOnResult({
296
322
  type: "add-tool-result",
297
323
  toolCallId,
@@ -329,16 +355,26 @@ var ToolInvocationTracker = class {
329
355
  this._statuses = next;
330
356
  this._invokeOnStatusesChange();
331
357
  }
332
- _hasExecutableTool(toolName) {
333
- const tool = this._getTools()?.[toolName];
334
- return tool?.execute !== void 0 || tool?.streamCall !== void 0;
358
+ _warnProviderOwnedSkip(toolName, toolCallId) {
359
+ if (process.env.NODE_ENV === "production") return;
360
+ if (this._getTools()?.[toolName]?.execute === void 0) return;
361
+ console.warn("[ToolInvocationTracker] the runtime reports this tool call as provider-owned, so the registered execute is skipped; the provider has to hand the call to the client for it to run (see EDGE_CASES.md A.9)", {
362
+ toolCallId,
363
+ toolName
364
+ });
335
365
  }
336
- _shouldCloseArgsStream({ toolName, argsText, hasResult }) {
366
+ /**
367
+ * Closing the args stream hands the call to the client executor, so it may
368
+ * only happen once the provider can no longer speak about that call. The run
369
+ * ending is the only universal signal for that; an adapter that reports the
370
+ * call as client-owned has said it earlier, per call.
371
+ */
372
+ _shouldCloseArgsStream({ argsText, hasResult, clientOwned }) {
337
373
  if (hasResult) return true;
338
- if (!this._hasExecutableTool(toolName)) return !this._isRunning && isArgsTextComplete(argsText);
339
- return isArgsTextComplete(argsText);
374
+ if (!isArgsTextComplete(argsText)) return false;
375
+ return clientOwned || !this._isRunning;
340
376
  }
341
- _startActiveEntry(toolCallId, toolName, skipExecute) {
377
+ _startActiveEntry(toolCallId, toolName, skipExecute, clientOwned) {
342
378
  const entry = {
343
379
  toolName,
344
380
  controller: this._controller.addToolCallPart({
@@ -348,7 +384,8 @@ var ToolInvocationTracker = class {
348
384
  argsText: "",
349
385
  hasResult: false,
350
386
  skipExecute,
351
- argsComplete: false
387
+ argsComplete: false,
388
+ clientOwned
352
389
  };
353
390
  this._entries.set(toolCallId, entry);
354
391
  return entry;
@@ -363,6 +400,10 @@ var ToolInvocationTracker = class {
363
400
  _demoteEntriesToRestored() {
364
401
  for (const [toolCallId, entry] of this._entries) {
365
402
  if (!entry.controller) continue;
403
+ if (!entry.argsComplete && !entry.hasResult) {
404
+ this._entries.delete(toolCallId);
405
+ continue;
406
+ }
366
407
  this._entries.set(toolCallId, {
367
408
  toolName: entry.toolName,
368
409
  argsText: entry.argsText,
@@ -390,9 +431,9 @@ var ToolInvocationTracker = class {
390
431
  } else if (!content.argsText.startsWith(entry.argsText)) {
391
432
  if (isArgsTextComplete(entry.argsText) && isArgsTextComplete(content.argsText) && isEquivalentCompleteArgsText(entry.argsText, content.argsText)) {
392
433
  const shouldClose = this._shouldCloseArgsStream({
393
- toolName: content.toolName,
394
434
  argsText: content.argsText,
395
- hasResult
435
+ hasResult,
436
+ clientOwned: entry.clientOwned
396
437
  });
397
438
  if (shouldClose) entry.controller.argsText.close();
398
439
  entry.argsText = content.argsText;
@@ -411,9 +452,9 @@ var ToolInvocationTracker = class {
411
452
  const delta = content.argsText.slice(entry.argsText.length);
412
453
  entry.controller.argsText.append(delta);
413
454
  const shouldClose = this._shouldCloseArgsStream({
414
- toolName: content.toolName,
415
455
  argsText: content.argsText,
416
- hasResult
456
+ hasResult,
457
+ clientOwned: entry.clientOwned
417
458
  });
418
459
  if (shouldClose) entry.controller.argsText.close();
419
460
  entry.argsText = content.argsText;
@@ -422,9 +463,9 @@ var ToolInvocationTracker = class {
422
463
  }
423
464
  if (!entry.argsComplete && entry.controller) {
424
465
  if (this._shouldCloseArgsStream({
425
- toolName: content.toolName,
426
466
  argsText: entry.argsText,
427
- hasResult
467
+ hasResult,
468
+ clientOwned: entry.clientOwned
428
469
  })) {
429
470
  entry.controller.argsText.close();
430
471
  entry.argsComplete = true;
@@ -433,45 +474,43 @@ var ToolInvocationTracker = class {
433
474
  }
434
475
  _processMessages(messages) {
435
476
  const isRestore = this._pendingRestore;
436
- for (const message of messages) {
437
- if (!message || !Array.isArray(message.content)) continue;
438
- for (const content of message.content) {
439
- if (!content || content.type !== "tool-call") continue;
440
- const existing = this._entries.get(content.toolCallId);
441
- if (isRestore) {
442
- if (!existing?.controller) this._entries.set(content.toolCallId, {
443
- toolName: content.toolName,
444
- argsText: content.argsText,
445
- hasResult: content.result !== void 0
446
- });
447
- if (content.messages) this._processMessages(content.messages);
448
- continue;
449
- }
450
- let entry = existing;
451
- if (entry && !entry.controller) {
452
- if (!(content.argsText !== entry.argsText || content.result !== void 0 !== entry.hasResult)) {
453
- if (content.messages) this._processMessages(content.messages);
454
- continue;
455
- }
456
- this._entries.delete(content.toolCallId);
457
- entry = void 0;
458
- }
459
- if (!entry) entry = this._startActiveEntry(content.toolCallId, content.toolName, content.result !== void 0);
460
- this._processArgsText(entry, content);
461
- if (content.result !== void 0 && !entry.hasResult) {
462
- const { controller: activeController } = entry;
463
- if (!activeController) continue;
464
- entry.hasResult = true;
465
- entry.argsComplete = true;
466
- activeController.setResponse(new ToolResponse({
467
- result: content.result,
468
- artifact: content.artifact,
469
- isError: content.isError,
470
- ...content.modelContent !== void 0 ? { modelContent: content.modelContent } : {}
471
- }));
472
- activeController.close();
473
- }
474
- if (content.messages) this._processMessages(content.messages);
477
+ for (const { part: content } of walkToolCallTree(messages)) {
478
+ const existing = this._entries.get(content.toolCallId);
479
+ if (isRestore) {
480
+ if (!existing?.controller) this._entries.set(content.toolCallId, {
481
+ toolName: content.toolName,
482
+ argsText: content.argsText,
483
+ hasResult: content.result !== void 0
484
+ });
485
+ continue;
486
+ }
487
+ let entry = existing;
488
+ if (content.result !== void 0) this._discardedToolCallIds.delete(content.toolCallId);
489
+ if (entry && !entry.controller) {
490
+ if (!(content.argsText !== entry.argsText || content.result !== void 0 !== entry.hasResult)) continue;
491
+ this._entries.delete(content.toolCallId);
492
+ entry = void 0;
493
+ }
494
+ if (!entry) {
495
+ const ownership = this._isClientToolCall?.(content);
496
+ const providerOwned = content.result === void 0 && ownership === false;
497
+ if (providerOwned) this._warnProviderOwnedSkip(content.toolName, content.toolCallId);
498
+ entry = this._startActiveEntry(content.toolCallId, content.toolName, content.result !== void 0 || providerOwned || this._discardedToolCallIds.has(content.toolCallId), ownership === true);
499
+ }
500
+ if (content.approval !== void 0) entry.skipExecute = true;
501
+ this._processArgsText(entry, content);
502
+ if (content.result !== void 0 && !entry.hasResult) {
503
+ const { controller: activeController } = entry;
504
+ if (!activeController) continue;
505
+ entry.hasResult = true;
506
+ entry.argsComplete = true;
507
+ activeController.setResponse(new ToolResponse({
508
+ result: content.result,
509
+ artifact: content.artifact,
510
+ isError: content.isError,
511
+ ...content.modelContent !== void 0 ? { modelContent: content.modelContent } : {}
512
+ }));
513
+ activeController.close();
475
514
  }
476
515
  }
477
516
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ToolInvocationTracker.js","names":["process","env","NODE_ENV","createAssistantStreamController","ToolCallStreamController","ToolResponse","unstable_toolResultStream","Tool","ToolModelContentPart","ToolResultStreamOptions","AssistantMetaTransformStream","ReadonlyJSONValue","isJSONValueEqual","ThreadMessage","TOOL_EXECUTION_ID","Symbol","for","ToolExecutionStatus","type","payload","AddToolResultCommand","toolCallId","toolName","result","isError","artifact","modelContent","ToolCallEntry","argsText","hasResult","executionId","skipExecute","controller","argsComplete","SettledResolver","executionIds","ReadonlySet","resolve","isArgsTextComplete","JSON","parse","parseArgsText","undefined","isEquivalentCompleteArgsText","previous","next","previousValue","nextValue","getToolExecutionId","value","Record","PropertyKey","ToolInvocationTracker","_getTools","_callbacks","Callbacks","_entries","Map","_humanInput","reject","reason","_executing","Set","_settledResolvers","_statuses","_ac","AbortController","_pendingRestore","_lastSnapshot","Snapshot","_isRunning","_controller","ReturnType","_pipelineDead","_pipelineRestartUsed","constructor","getTools","callbacks","_initPipeline","stream","human","_onHumanInput","transform","_getWrappedTools","signal","onExecutionStart","id","_name","_onExecutionStart","onExecutionEnd","_onExecutionEnd","pipeThrough","pipeTo","WritableStream","write","chunk","_handleResultChunk","err","console","error","catch","setState","snapshot","_demoteEntriesToRestored","clear","messages","isRunning","isLoading","restoreFromLoading","previousIsRunning","_processMessages","reset","abort","size","_invokeOnStatusesChange","Promise","forEach","Error","push","resume","handlers","get","delete","_setStatus","getStatuses","ReadonlyMap","tools","Object","fromEntries","entries","map","name","tool","execute","streamCall","wrappedTool","args","context","Parameters","entry","_captureExecution","reader","set","add","_deleteStatus","pending","some","has","length","meta","_invokeOnResult","command","onResult","onStatusesChange","status","_hasExecutableTool","_shouldCloseArgsStream","_startActiveEntry","toolCallController","addToolCallPart","_processArgsText","content","shouldWriteArgsText","warn","startsWith","shouldClose","close","delta","slice","append","isRestore","message","Array","isArray","existing","signatureChanged","activeController","setResponse","ExecutionStatus","statuses"],"sources":["../../../src/runtimes/tool-invocations/ToolInvocationTracker.ts"],"sourcesContent":["declare const process: { env: { NODE_ENV?: string } };\n\nimport {\n createAssistantStreamController,\n type ToolCallStreamController,\n ToolResponse,\n unstable_toolResultStream,\n type Tool,\n type ToolModelContentPart,\n type ToolResultStreamOptions,\n} from \"assistant-stream\";\nimport {\n AssistantMetaTransformStream,\n type ReadonlyJSONValue,\n} from \"assistant-stream/utils\";\nimport { isJSONValueEqual } from \"../../utils/json/is-json-equal\";\nimport type { ThreadMessage } from \"../../types/message\";\n\nconst TOOL_EXECUTION_ID = Symbol.for(\"assistant-stream.tool-execution-id\");\n\n/**\n * Streaming execution state for a frontend tool.\n */\nexport type ToolExecutionStatus =\n | { type: \"executing\" }\n | {\n type: \"interrupt\";\n payload: { type: \"human\"; payload: unknown };\n };\n\nexport type AddToolResultCommand = {\n readonly type: \"add-tool-result\";\n readonly toolCallId: string;\n readonly toolName: string;\n readonly result: ReadonlyJSONValue;\n readonly isError: boolean;\n readonly artifact?: ReadonlyJSONValue;\n readonly modelContent?: readonly ToolModelContentPart[];\n};\n\ntype ToolCallEntry = {\n toolName: string;\n argsText: string;\n hasResult: boolean;\n executionId?: symbol;\n skipExecute?: boolean;\n} & (\n | {\n /** Restored phase — observed during a history-load snapshot. */\n controller?: undefined;\n argsComplete?: undefined;\n }\n | {\n /** Active phase — chunks are flowing through `controller`. */\n controller: ToolCallStreamController;\n argsComplete: boolean;\n }\n);\n\ntype SettledResolver = {\n executionIds: ReadonlySet<symbol>;\n resolve: () => void;\n};\n\nconst isArgsTextComplete = (argsText: string) => {\n try {\n JSON.parse(argsText);\n return true;\n } catch {\n return false;\n }\n};\n\nconst parseArgsText = (argsText: string) => {\n try {\n return JSON.parse(argsText);\n } catch {\n return undefined;\n }\n};\n\nconst isEquivalentCompleteArgsText = (previous: string, next: string) => {\n const previousValue = parseArgsText(previous);\n const nextValue = parseArgsText(next);\n if (previousValue === undefined || nextValue === undefined) return false;\n return isJSONValueEqual(previousValue, nextValue);\n};\n\nconst getToolExecutionId = (value: object): symbol | undefined =>\n (value as Record<PropertyKey, unknown>)[TOOL_EXECUTION_ID] as\n | symbol\n | undefined;\n\n/**\n * Plain-class port of the former `useToolInvocations` React hook. Owns the\n * assistant-stream pipeline that drives client-side `streamCall` / `execute`\n * for tool-call parts surfaced by a thread runtime, plus the per-tool-call\n * status map that consumers render against.\n *\n * **Contract**: `streamCall` (and `execute`) fires exactly once per logical\n * `toolCallId`. Args mutations after first completion, result replacement,\n * and result clearing are *not* surfaced through additional `streamCall`\n * invocations — by design — so hosts cannot observe spurious re-fires of\n * side effects. The follow-up `reader.events()` API will expose those\n * post-completion transitions to consumers that opt in.\n *\n * State-transition safety: every public method that observes runtime state\n * (`setState`, `reset`, `abort`, `resume`) wraps its work in try/catch and\n * logs to `console.error` rather than throwing. The tracker is built into\n * the hot message-processing path, so a malformed snapshot must never crash\n * the host runtime. See ./EDGE_CASES.md for the known non-trivial state\n * transitions and what each does today.\n *\n * @deprecated Internal — for framework bindings; not a public API. May change without notice.\n */\nexport class ToolInvocationTracker {\n private readonly _getTools: () => Record<string, Tool> | undefined;\n private readonly _callbacks: ToolInvocationTracker.Callbacks;\n\n private readonly _entries = new Map<string, ToolCallEntry>();\n private readonly _humanInput = new Map<\n string,\n {\n executionId: symbol;\n resolve: (payload: unknown) => void;\n reject: (reason: unknown) => void;\n }\n >();\n private readonly _executing = new Set<symbol>();\n private readonly _settledResolvers: SettledResolver[] = [];\n\n private _statuses = new Map<string, ToolExecutionStatus>();\n\n private _ac: AbortController = new AbortController();\n private _pendingRestore = true;\n\n /** Cached last snapshot, used to skip processing on identical re-renders. */\n private _lastSnapshot: ToolInvocationTracker.Snapshot | null = null;\n private _isRunning = false;\n\n private _controller!: ReturnType<typeof createAssistantStreamController>[1];\n\n /**\n * Set when the assistant-stream pipeline has died (errored out via\n * `.pipeTo(...).catch(...)`). The next `setState` re-initializes the\n * pipeline and demotes all active entries to restored so they survive\n * across the restart without re-firing `streamCall` (preserves the\n * \"exactly once\" contract). Capped at a single auto-restart per session\n * — repeated failures keep the tracker dead with a more visible error.\n */\n private _pipelineDead = false;\n private _pipelineRestartUsed = false;\n\n constructor(\n getTools: () => Record<string, Tool> | undefined,\n callbacks: ToolInvocationTracker.Callbacks,\n ) {\n this._getTools = getTools;\n this._callbacks = callbacks;\n\n this._initPipeline();\n }\n\n /**\n * Build the assistant-stream pipeline. Called once from the constructor\n * and at most once again if `_pipelineDead` is set (see F.4 in\n * EDGE_CASES.md).\n */\n private _initPipeline(): void {\n const [stream, controller] = createAssistantStreamController();\n this._controller = controller;\n\n const human = (\n toolCallId: string,\n payload: unknown,\n executionId?: symbol,\n ) => this._onHumanInput(toolCallId, payload, executionId);\n const transform = unstable_toolResultStream(\n () => this._getWrappedTools(),\n () => this._ac.signal,\n human,\n {\n onExecutionStart: (id: string, _name: string, executionId?: symbol) =>\n this._onExecutionStart(id, executionId),\n onExecutionEnd: (id: string, _name: string, executionId?: symbol) =>\n this._onExecutionEnd(id, executionId),\n } as ToolResultStreamOptions,\n );\n\n stream\n .pipeThrough(transform)\n .pipeThrough(new AssistantMetaTransformStream())\n .pipeTo(\n new WritableStream({\n write: (chunk) => {\n try {\n if (chunk.type !== \"result\") return;\n this._handleResultChunk(chunk);\n } catch (err) {\n console.error(\n \"[ToolInvocationTracker] result chunk handling failed\",\n err,\n );\n }\n },\n }),\n )\n .catch((err) => {\n console.error(\n \"[ToolInvocationTracker] stream pipeline failed; will attempt single restart on next setState\",\n err,\n );\n this._pipelineDead = true;\n });\n }\n\n // ───────────────────────── public API ─────────────────────────\n\n /**\n * Feed the next observed snapshot into the tracker. Called from the host\n * runtime whenever its message list / running state changes.\n */\n public setState(snapshot: ToolInvocationTracker.Snapshot): void {\n try {\n // Recover from a dead pipeline before processing anything. We demote\n // all active entries to \"restored\" so the rebuilt pipeline does not\n // re-fire `streamCall` for tool calls that already fired pre-death;\n // preserves the \"exactly once per toolCallId\" contract.\n if (this._pipelineDead) {\n if (this._pipelineRestartUsed) {\n // Already retried once and failed again. Stay dead.\n return;\n }\n this._pipelineRestartUsed = true;\n this._pipelineDead = false;\n this._demoteEntriesToRestored();\n this._executing.clear();\n this._ac = new AbortController();\n this._initPipeline();\n // Fall through and process the snapshot against the fresh pipeline.\n }\n\n // Identical snapshot — skip processing entirely. Note: external-store\n // runtimes rebuild the messages array on every adapter update, so this\n // fast-path rarely triggers there; it's primarily for the React-hook\n // shim where state references are stable.\n if (\n this._lastSnapshot &&\n this._lastSnapshot.messages === snapshot.messages &&\n this._lastSnapshot.isRunning === snapshot.isRunning &&\n this._lastSnapshot.isLoading === snapshot.isLoading\n ) {\n return;\n }\n\n // While the host is still loading initial state, treat every snapshot\n // as historical: tool calls are recorded so the next live snapshot can\n // diff against them, but `streamCall` / `execute` do not fire.\n const restoreFromLoading = snapshot.isLoading === true;\n if (restoreFromLoading) {\n this._pendingRestore = true;\n }\n\n // E.4 / AF3 — only mark `_lastSnapshot`/`_isRunning` as observed after\n // processing succeeds. If `_processMessages` throws, the next snapshot\n // (even if identical) gets re-processed against the recovered state.\n const previousIsRunning = this._isRunning;\n this._isRunning = snapshot.isRunning;\n try {\n this._processMessages(snapshot.messages);\n } catch (err) {\n this._isRunning = previousIsRunning;\n throw err;\n }\n this._lastSnapshot = snapshot;\n this._pendingRestore = false;\n } catch (err) {\n console.error(\n \"[ToolInvocationTracker] setState failed; snapshot dropped\",\n err,\n );\n }\n }\n\n /**\n * Reset the tracker so the next observed snapshot is treated as historical.\n * Clears entries and aborts any in-flight executions. Used by callers like\n * `importExternalState` to mark a freshly loaded state as restored.\n */\n public reset(): void {\n try {\n this._pendingRestore = true;\n this._entries.clear();\n this._lastSnapshot = null;\n void this.abort();\n // Statuses are cleared synchronously: discarded executions may never\n // settle (aborting hands the signal to the tool, it does not force\n // settlement), and a late settlement of one sibling must not republish\n // the others. `_deleteStatus` no-ops for cleared ids, so post-reset\n // settlements stay silent.\n if (this._statuses.size > 0) {\n this._statuses = new Map();\n this._invokeOnStatusesChange();\n }\n } catch (err) {\n console.error(\"[ToolInvocationTracker] reset failed\", err);\n }\n }\n\n /**\n * Abort any in-flight `execute()` invocations. Resolves once all of them\n * have settled (or immediately if none are running).\n */\n public abort(): Promise<void> {\n try {\n this._humanInput.forEach(({ reject }) => {\n try {\n reject(new Error(\"Tool execution aborted\"));\n } catch {\n // host rejection handler threw — already in the abort path,\n // swallow so we continue cleaning up.\n }\n });\n this._humanInput.clear();\n\n this._ac.abort();\n this._ac = new AbortController();\n\n if (this._executing.size === 0) {\n return Promise.resolve();\n }\n const executionIds = new Set(this._executing);\n return new Promise<void>((resolve) => {\n this._settledResolvers.push({ executionIds, resolve });\n });\n } catch (err) {\n console.error(\"[ToolInvocationTracker] abort failed\", err);\n return Promise.resolve();\n }\n }\n\n /**\n * Resolve a pending human-input request for the given tool call. Returns\n * `true` if a pending request was resumed, `false` if the tracker has no\n * outstanding request for that id (the caller should fall back to its own\n * dispatch path).\n */\n public resume(toolCallId: string, payload: unknown): boolean {\n try {\n const handlers = this._humanInput.get(toolCallId);\n if (!handlers) return false;\n this._humanInput.delete(toolCallId);\n this._setStatus(toolCallId, { type: \"executing\" });\n handlers.resolve(payload);\n return true;\n } catch (err) {\n console.error(\"[ToolInvocationTracker] resume failed\", err);\n return false;\n }\n }\n\n /**\n * Returns the current tool execution status map. The returned `Map` is\n * the tracker's internal store — do not mutate it. Treat the reference\n * as a snapshot that may be replaced wholesale on the next status\n * transition.\n */\n public getStatuses(): ReadonlyMap<string, ToolExecutionStatus> {\n return this._statuses;\n }\n\n // ───────────────────── internal: tool wrapping ─────────────────────\n\n private _getWrappedTools(): Record<string, Tool> | undefined {\n const tools = this._getTools();\n if (!tools) return undefined;\n\n return Object.fromEntries(\n Object.entries(tools).map(([name, tool]) => {\n const execute = tool.execute;\n const streamCall = tool.streamCall;\n if (execute === undefined && streamCall === undefined)\n return [name, tool];\n\n const wrappedTool = {\n ...tool,\n ...(execute !== undefined && {\n execute: (...[args, context]: Parameters<typeof execute>) => {\n const executionId = getToolExecutionId(context);\n const entry = this._captureExecution(\n context.toolCallId,\n executionId,\n );\n if (!entry || entry.skipExecute) {\n return new Promise(() => {}) as never;\n }\n return execute(args, context);\n },\n }),\n ...(streamCall !== undefined && {\n streamCall: (\n ...[reader, context]: Parameters<typeof streamCall>\n ) => {\n const executionId = getToolExecutionId(context);\n const entry = this._captureExecution(\n context.toolCallId,\n executionId,\n );\n if (!entry) return;\n return streamCall(reader, context);\n },\n }),\n } as Tool;\n return [name, wrappedTool];\n }),\n ) as Record<string, Tool>;\n }\n\n private _captureExecution(\n toolCallId: string,\n executionId: symbol | undefined,\n ): ToolCallEntry | undefined {\n if (executionId === undefined) return undefined;\n const entry = this._entries.get(toolCallId);\n if (!entry?.controller) return undefined;\n if (entry.executionId === undefined) entry.executionId = executionId;\n return entry.executionId === executionId ? entry : undefined;\n }\n\n // ──────────────── internal: execution lifecycle callbacks ────────────────\n\n private _onHumanInput(\n toolCallId: string,\n payload: unknown,\n executionId?: symbol,\n ): Promise<unknown> {\n return new Promise<unknown>((resolve, reject) => {\n // A discarded execution must not resurrect a status entry or park an\n // unanswerable request after its id has been reused.\n const entry = this._entries.get(toolCallId);\n if (!entry?.controller || entry.executionId !== executionId) {\n reject(new Error(\"Tool execution aborted\"));\n return;\n }\n const previous = this._humanInput.get(toolCallId);\n if (previous) {\n try {\n previous.reject(\n new Error(\"Human input request was superseded by a new request\"),\n );\n } catch {\n // host rejection handler threw; ignore and proceed\n }\n }\n this._humanInput.set(toolCallId, {\n executionId: executionId!,\n resolve,\n reject,\n });\n this._setStatus(toolCallId, {\n type: \"interrupt\",\n payload: { type: \"human\", payload },\n });\n });\n }\n\n private _onExecutionStart(\n toolCallId: string,\n executionId: symbol | undefined,\n ): void {\n if (!this._captureExecution(toolCallId, executionId)) return;\n const entry = this._entries.get(toolCallId)!;\n if (entry.skipExecute) return;\n\n this._executing.add(executionId!);\n this._setStatus(toolCallId, { type: \"executing\" });\n }\n\n private _onExecutionEnd(\n toolCallId: string,\n executionId: symbol | undefined,\n ): void {\n if (executionId === undefined || !this._executing.delete(executionId))\n return;\n\n const entry = this._entries.get(toolCallId);\n if (entry?.executionId === executionId) this._deleteStatus(toolCallId);\n\n const pending: SettledResolver[] = [];\n this._settledResolvers.forEach(({ executionIds, resolve }) => {\n if ([...executionIds].some((id) => this._executing.has(id))) {\n pending.push({ executionIds, resolve });\n return;\n }\n try {\n resolve();\n } catch {\n // ignore — settled-resolver consumer threw\n }\n });\n this._settledResolvers.length = 0;\n this._settledResolvers.push(...pending);\n }\n\n private _handleResultChunk(chunk: {\n type: \"result\";\n result: ReadonlyJSONValue;\n isError: boolean;\n artifact?: ReadonlyJSONValue;\n modelContent?: readonly ToolModelContentPart[];\n meta: { toolCallId: string; toolName: string };\n }): void {\n const toolCallId = chunk.meta.toolCallId;\n const executionId = getToolExecutionId(chunk);\n const entry = this._entries.get(toolCallId);\n\n if (!entry || entry.executionId !== executionId) return;\n\n // The host already set the result (via the live snapshot's\n // `setResponse` path). Suppress the executor's redundant emit.\n if (entry?.hasResult) return;\n\n this._invokeOnResult({\n type: \"add-tool-result\",\n toolCallId,\n toolName: chunk.meta.toolName,\n result: chunk.result,\n isError: chunk.isError,\n ...(chunk.artifact !== undefined && { artifact: chunk.artifact }),\n ...(chunk.modelContent !== undefined && {\n modelContent: chunk.modelContent,\n }),\n });\n }\n\n // ──────────────── internal: callback invocation (AF1/AF2) ────────────────\n\n private _invokeOnResult(command: AddToolResultCommand): void {\n try {\n this._callbacks.onResult(command);\n } catch (err) {\n console.error(\n \"[ToolInvocationTracker] onResult callback threw; result dropped\",\n err,\n );\n }\n }\n\n private _invokeOnStatusesChange(): void {\n try {\n this._callbacks.onStatusesChange(this._statuses);\n } catch (err) {\n console.error(\n \"[ToolInvocationTracker] onStatusesChange callback threw; status change not propagated\",\n err,\n );\n }\n }\n\n // ──────────────── internal: status map mutations ────────────────\n\n private _setStatus(toolCallId: string, status: ToolExecutionStatus): void {\n const next = new Map(this._statuses);\n next.set(toolCallId, status);\n this._statuses = next;\n this._invokeOnStatusesChange();\n }\n\n private _deleteStatus(toolCallId: string): void {\n if (!this._statuses.has(toolCallId)) return;\n const next = new Map(this._statuses);\n next.delete(toolCallId);\n this._statuses = next;\n this._invokeOnStatusesChange();\n }\n\n // ──────────────── internal: snapshot processing ────────────────\n\n private _hasExecutableTool(toolName: string): boolean {\n const tool = this._getTools()?.[toolName];\n return tool?.execute !== undefined || tool?.streamCall !== undefined;\n }\n\n private _shouldCloseArgsStream({\n toolName,\n argsText,\n hasResult,\n }: {\n toolName: string;\n argsText: string;\n hasResult: boolean;\n }): boolean {\n if (hasResult) return true;\n if (!this._hasExecutableTool(toolName)) {\n return !this._isRunning && isArgsTextComplete(argsText);\n }\n return isArgsTextComplete(argsText);\n }\n\n private _startActiveEntry(\n toolCallId: string,\n toolName: string,\n skipExecute: boolean,\n ): ToolCallEntry {\n const toolCallController = this._controller.addToolCallPart({\n toolName,\n toolCallId,\n });\n const entry: ToolCallEntry = {\n toolName,\n controller: toolCallController,\n argsText: \"\",\n hasResult: false,\n skipExecute,\n argsComplete: false,\n };\n this._entries.set(toolCallId, entry);\n return entry;\n }\n\n /**\n * Demote every active entry back to the restored phase. Used by the\n * pipeline-restart path so that, after a fresh pipeline is built, the\n * next observed snapshot does not re-fire `streamCall` for tool calls\n * that already fired pre-death. Args / hasResult tracking is preserved\n * so signature comparisons still work.\n */\n private _demoteEntriesToRestored(): void {\n for (const [toolCallId, entry] of this._entries) {\n if (!entry.controller) continue;\n this._entries.set(toolCallId, {\n toolName: entry.toolName,\n argsText: entry.argsText,\n hasResult: entry.hasResult,\n });\n }\n }\n\n private _processArgsText(\n entry: ToolCallEntry,\n content: {\n toolCallId: string;\n toolName: string;\n argsText: string;\n result?: unknown;\n },\n ): void {\n if (!entry.controller) return;\n const hasResult = content.result !== undefined;\n\n if (content.argsText !== entry.argsText) {\n let shouldWriteArgsText = true;\n\n if (entry.argsComplete) {\n if (isEquivalentCompleteArgsText(entry.argsText, content.argsText)) {\n // A.3 — key reorder. Track new text, no re-fire needed.\n entry.argsText = content.argsText;\n shouldWriteArgsText = false;\n } else {\n // A.4 — args changed after first completion. Under the\n // \"exactly once per toolCallId\" contract we do not restart the\n // stream. The host's existing `streamCall` keeps its original\n // args view; the snapshot's new text is recorded for diffing\n // but not surfaced. Events API in a follow-up will expose this\n // to consumers that opt in.\n if (process.env.NODE_ENV !== \"production\") {\n console.warn(\n \"[ToolInvocationTracker] argsText changed after first completion; not re-firing streamCall (see EDGE_CASES.md A.4)\",\n {\n previous: entry.argsText,\n next: content.argsText,\n toolCallId: content.toolCallId,\n },\n );\n }\n shouldWriteArgsText = false;\n }\n } else if (!content.argsText.startsWith(entry.argsText)) {\n if (\n isArgsTextComplete(entry.argsText) &&\n isArgsTextComplete(content.argsText) &&\n isEquivalentCompleteArgsText(entry.argsText, content.argsText)\n ) {\n const shouldClose = this._shouldCloseArgsStream({\n toolName: content.toolName,\n argsText: content.argsText,\n hasResult,\n });\n if (shouldClose) entry.controller.argsText.close();\n entry.argsText = content.argsText;\n entry.argsComplete = shouldClose;\n shouldWriteArgsText = false;\n } else {\n // A.2 — args regressed mid-stream. Under the \"exactly once\"\n // contract we do not restart. The controller keeps whatever\n // prefix we already streamed; subsequent prefix-respecting\n // updates can still flow against it. Snapshots that never\n // re-converge to a prefix will leave the controller's args\n // view stale relative to the snapshot. Events API in a\n // follow-up will expose this to consumers that opt in.\n if (process.env.NODE_ENV !== \"production\") {\n console.warn(\n \"[ToolInvocationTracker] argsText regressed mid-stream; not restarting (see EDGE_CASES.md A.2)\",\n {\n previous: entry.argsText,\n next: content.argsText,\n toolCallId: content.toolCallId,\n },\n );\n }\n shouldWriteArgsText = false;\n }\n }\n\n if (shouldWriteArgsText && entry.controller) {\n const delta = content.argsText.slice(entry.argsText.length);\n entry.controller.argsText.append(delta);\n const shouldClose = this._shouldCloseArgsStream({\n toolName: content.toolName,\n argsText: content.argsText,\n hasResult,\n });\n if (shouldClose) entry.controller.argsText.close();\n entry.argsText = content.argsText;\n entry.argsComplete = shouldClose;\n }\n }\n\n if (!entry.argsComplete && entry.controller) {\n // ToolExecutionStream parses the streamed prefix on close, so the close\n // gates on the streamed content; a divergent snapshot (A.2) can be\n // complete while the controller still holds an incomplete stale prefix.\n const shouldClose = this._shouldCloseArgsStream({\n toolName: content.toolName,\n argsText: entry.argsText,\n hasResult,\n });\n if (shouldClose) {\n entry.controller.argsText.close();\n entry.argsComplete = true;\n }\n }\n }\n\n private _processMessages(messages: readonly ThreadMessage[]): void {\n const isRestore = this._pendingRestore;\n\n for (const message of messages) {\n if (!message || !Array.isArray((message as ThreadMessage).content)) {\n continue;\n }\n for (const content of message.content as readonly ThreadMessage[\"content\"][number][]) {\n if (!content || content.type !== \"tool-call\") continue;\n\n const existing = this._entries.get(content.toolCallId);\n\n if (isRestore) {\n // Don't overwrite an already-active entry (e.g. live tool-call\n // observed before this restore snapshot landed). Restore can\n // only seed entries the runtime has never seen.\n if (!existing?.controller) {\n this._entries.set(content.toolCallId, {\n toolName: content.toolName,\n argsText: content.argsText,\n hasResult: content.result !== undefined,\n });\n }\n if (content.messages) this._processMessages(content.messages);\n continue;\n }\n\n // Live snapshot.\n let entry = existing;\n\n if (entry && !entry.controller) {\n // Restored entry observed in a live snapshot. Promote if its\n // signature has changed; otherwise treat as still-historical.\n const signatureChanged =\n content.argsText !== entry.argsText ||\n (content.result !== undefined) !== entry.hasResult;\n if (!signatureChanged) {\n if (content.messages) this._processMessages(content.messages);\n continue;\n }\n this._entries.delete(content.toolCallId);\n entry = undefined;\n }\n\n if (!entry) {\n entry = this._startActiveEntry(\n content.toolCallId,\n content.toolName,\n content.result !== undefined,\n );\n }\n\n this._processArgsText(entry, content);\n\n if (content.result !== undefined && !entry.hasResult) {\n // `entry` is in active phase from this point — either just\n // created by `_startActiveEntry`, or pre-existing with a live\n // controller. Narrow once instead of asserting at every use.\n const { controller: activeController } = entry;\n if (!activeController) continue;\n entry.hasResult = true;\n entry.argsComplete = true;\n activeController.setResponse(\n new ToolResponse({\n result: content.result as ReadonlyJSONValue,\n artifact: content.artifact as ReadonlyJSONValue | undefined,\n isError: content.isError,\n ...(content.modelContent !== undefined\n ? { modelContent: content.modelContent }\n : {}),\n }),\n );\n activeController.close();\n }\n\n if (content.messages) this._processMessages(content.messages);\n }\n }\n }\n}\n\nexport namespace ToolInvocationTracker {\n export type ExecutionStatus = ToolExecutionStatus;\n\n export type Snapshot = {\n readonly messages: readonly ThreadMessage[];\n /** Whether the producing runtime is currently streaming new output. */\n readonly isRunning: boolean;\n /**\n * Whether the producing runtime is still loading historical state.\n * When `true`, every snapshot is treated as historical (no `streamCall` /\n * `execute` fires). When `false`, processing resumes as live.\n */\n readonly isLoading?: boolean;\n };\n\n export type Callbacks = {\n /**\n * Invoked when a client-side `execute()` returns a result and the runtime\n * needs to feed it back into the conversation.\n */\n onResult: (command: AddToolResultCommand) => void;\n /**\n * Invoked whenever the per-tool-call status map changes (executing /\n * interrupt / cleared). The callback receives a fresh map; mutating the\n * argument is not supported.\n */\n onStatusesChange: (\n statuses: ReadonlyMap<string, ToolExecutionStatus>,\n ) => void;\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ToolInvocationTracker.js","names":["process","env","NODE_ENV","createAssistantStreamController","ToolCallStreamController","ToolResponse","unstable_toolResultStream","Tool","ToolModelContentPart","ToolResultStreamOptions","AssistantMetaTransformStream","ReadonlyJSONValue","isJSONValueEqual","ThreadMessage","ToolCallMessagePart","walkToolCallTree","TOOL_EXECUTION_ID","Symbol","for","ToolExecutionStatus","type","payload","AddToolResultCommand","toolCallId","toolName","result","isError","artifact","modelContent","ToolCallEntry","argsText","hasResult","executionId","skipExecute","controller","argsComplete","clientOwned","SettledResolver","executionIds","ReadonlySet","resolve","isArgsTextComplete","JSON","parse","parseArgsText","undefined","isEquivalentCompleteArgsText","previous","next","previousValue","nextValue","getToolExecutionId","value","Record","PropertyKey","ToolInvocationTracker","_getTools","_callbacks","Callbacks","_isClientToolCall","toolCall","_entries","Map","_humanInput","reject","reason","_executing","Set","_discardedToolCallIds","_settledResolvers","_statuses","_ac","AbortController","_pendingRestore","_lastSnapshot","Snapshot","_isRunning","_controller","ReturnType","_pipelineDead","_pipelineRestartUsed","constructor","getTools","callbacks","isClientToolCall","_initPipeline","stream","human","_onHumanInput","transform","_getWrappedTools","signal","onExecutionStart","id","_name","_onExecutionStart","onExecutionEnd","_onExecutionEnd","pipeThrough","pipeTo","WritableStream","write","chunk","_handleResultChunk","err","console","error","catch","setState","snapshot","_demoteEntriesToRestored","clear","messages","isRunning","isLoading","restoreFromLoading","previousIsRunning","_processMessages","reset","abort","size","_invokeOnStatusesChange","options","discardPending","Promise","forEach","Error","entry","add","push","resume","handlers","get","delete","_setStatus","getStatuses","ReadonlyMap","tools","Object","fromEntries","entries","map","name","tool","execute","streamCall","wrappedTool","args","context","Parameters","_captureExecution","reader","set","_deleteStatus","pending","some","has","length","meta","_invokeOnResult","command","onResult","onStatusesChange","status","_warnProviderOwnedSkip","warn","_shouldCloseArgsStream","_startActiveEntry","toolCallController","addToolCallPart","_processArgsText","content","shouldWriteArgsText","startsWith","shouldClose","close","delta","slice","append","isRestore","part","existing","signatureChanged","ownership","providerOwned","approval","activeController","setResponse","ExecutionStatus","statuses"],"sources":["../../../src/runtimes/tool-invocations/ToolInvocationTracker.ts"],"sourcesContent":["declare const process: { env: { NODE_ENV?: string } };\n\nimport {\n createAssistantStreamController,\n type ToolCallStreamController,\n ToolResponse,\n unstable_toolResultStream,\n type Tool,\n type ToolModelContentPart,\n type ToolResultStreamOptions,\n} from \"assistant-stream\";\nimport {\n AssistantMetaTransformStream,\n type ReadonlyJSONValue,\n} from \"assistant-stream/utils\";\nimport { isJSONValueEqual } from \"../../utils/json/is-json-equal\";\nimport type { ThreadMessage, ToolCallMessagePart } from \"../../types/message\";\nimport { walkToolCallTree } from \"../../runtime/utils/tool-call-tree\";\n\nconst TOOL_EXECUTION_ID = Symbol.for(\"assistant-stream.tool-execution-id\");\n\n/**\n * Streaming execution state for a frontend tool.\n */\nexport type ToolExecutionStatus =\n | { type: \"executing\" }\n | {\n type: \"interrupt\";\n payload: { type: \"human\"; payload: unknown };\n };\n\nexport type AddToolResultCommand = {\n readonly type: \"add-tool-result\";\n readonly toolCallId: string;\n readonly toolName: string;\n readonly result: ReadonlyJSONValue;\n readonly isError: boolean;\n readonly artifact?: ReadonlyJSONValue;\n readonly modelContent?: readonly ToolModelContentPart[];\n};\n\ntype ToolCallEntry = {\n toolName: string;\n argsText: string;\n hasResult: boolean;\n executionId?: symbol;\n skipExecute?: boolean;\n} & (\n | {\n /** Restored phase — observed during a history-load snapshot. */\n controller?: undefined;\n argsComplete?: undefined;\n }\n | {\n /** Active phase — chunks are flowing through `controller`. */\n controller: ToolCallStreamController;\n argsComplete: boolean;\n clientOwned: boolean;\n }\n);\n\ntype SettledResolver = {\n executionIds: ReadonlySet<symbol>;\n resolve: () => void;\n};\n\nconst isArgsTextComplete = (argsText: string) => {\n try {\n JSON.parse(argsText);\n return true;\n } catch {\n return false;\n }\n};\n\nconst parseArgsText = (argsText: string) => {\n try {\n return JSON.parse(argsText);\n } catch {\n return undefined;\n }\n};\n\nconst isEquivalentCompleteArgsText = (previous: string, next: string) => {\n const previousValue = parseArgsText(previous);\n const nextValue = parseArgsText(next);\n if (previousValue === undefined || nextValue === undefined) return false;\n return isJSONValueEqual(previousValue, nextValue);\n};\n\nconst getToolExecutionId = (value: object): symbol | undefined =>\n (value as Record<PropertyKey, unknown>)[TOOL_EXECUTION_ID] as\n | symbol\n | undefined;\n\n/**\n * Plain-class port of the former `useToolInvocations` React hook. Owns the\n * assistant-stream pipeline that drives client-side `streamCall` / `execute`\n * for tool-call parts surfaced by a thread runtime, plus the per-tool-call\n * status map that consumers render against.\n *\n * **Contract**: `streamCall` (and `execute`) fires exactly once per logical\n * `toolCallId`. Args mutations after first completion, result replacement,\n * and result clearing are *not* surfaced through additional `streamCall`\n * invocations — by design — so hosts cannot observe spurious re-fires of\n * side effects. The follow-up `reader.events()` API will expose those\n * post-completion transitions to consumers that opt in.\n *\n * State-transition safety: every public method that observes runtime state\n * (`setState`, `reset`, `abort`, `resume`) wraps its work in try/catch and\n * logs to `console.error` rather than throwing. The tracker is built into\n * the hot message-processing path, so a malformed snapshot must never crash\n * the host runtime. See ./EDGE_CASES.md for the known non-trivial state\n * transitions and what each does today.\n *\n * @deprecated Internal — for framework bindings; not a public API. May change without notice.\n */\nexport class ToolInvocationTracker {\n private readonly _getTools: () => Record<string, Tool> | undefined;\n private readonly _callbacks: ToolInvocationTracker.Callbacks;\n private readonly _isClientToolCall:\n | ((toolCall: ToolCallMessagePart) => boolean | undefined)\n | undefined;\n\n private readonly _entries = new Map<string, ToolCallEntry>();\n private readonly _humanInput = new Map<\n string,\n {\n executionId: symbol;\n resolve: (payload: unknown) => void;\n reject: (reason: unknown) => void;\n }\n >();\n private readonly _executing = new Set<symbol>();\n /**\n * Tool calls whose turn ended before they reached the executor. Held here\n * rather than on the entry because an entry is rebuilt whenever a snapshot\n * re-creates the call, and this is the one reason to skip that no later\n * snapshot carries.\n */\n private readonly _discardedToolCallIds = new Set<string>();\n private readonly _settledResolvers: SettledResolver[] = [];\n\n private _statuses = new Map<string, ToolExecutionStatus>();\n\n private _ac: AbortController = new AbortController();\n private _pendingRestore = true;\n\n /** Cached last snapshot, used to skip processing on identical re-renders. */\n private _lastSnapshot: ToolInvocationTracker.Snapshot | null = null;\n private _isRunning = false;\n\n private _controller!: ReturnType<typeof createAssistantStreamController>[1];\n\n /**\n * Set when the assistant-stream pipeline has died (errored out via\n * `.pipeTo(...).catch(...)`). The next `setState` re-initializes the\n * pipeline and demotes each active entry that reached the executor to\n * restored, so it survives the restart without re-firing `streamCall`.\n * A restart is an execution boundary like `reset()`: an entry that had\n * not reached it starts over and fires once there (F.4). Capped at a\n * single auto-restart per session — repeated failures keep the tracker\n * dead with a more visible error.\n */\n private _pipelineDead = false;\n private _pipelineRestartUsed = false;\n\n constructor(\n getTools: () => Record<string, Tool> | undefined,\n callbacks: ToolInvocationTracker.Callbacks,\n isClientToolCall?: (toolCall: ToolCallMessagePart) => boolean | undefined,\n ) {\n this._getTools = getTools;\n this._callbacks = callbacks;\n this._isClientToolCall = isClientToolCall;\n\n this._initPipeline();\n }\n\n /**\n * Build the assistant-stream pipeline. Called once from the constructor\n * and at most once again if `_pipelineDead` is set (see F.4 in\n * EDGE_CASES.md).\n */\n private _initPipeline(): void {\n const [stream, controller] = createAssistantStreamController();\n this._controller = controller;\n\n const human = (\n toolCallId: string,\n payload: unknown,\n executionId?: symbol,\n ) => this._onHumanInput(toolCallId, payload, executionId);\n const transform = unstable_toolResultStream(\n () => this._getWrappedTools(),\n () => this._ac.signal,\n human,\n {\n onExecutionStart: (id: string, _name: string, executionId?: symbol) =>\n this._onExecutionStart(id, executionId),\n onExecutionEnd: (id: string, _name: string, executionId?: symbol) =>\n this._onExecutionEnd(id, executionId),\n } as ToolResultStreamOptions,\n );\n\n stream\n .pipeThrough(transform)\n .pipeThrough(new AssistantMetaTransformStream())\n .pipeTo(\n new WritableStream({\n write: (chunk) => {\n try {\n if (chunk.type !== \"result\") return;\n this._handleResultChunk(chunk);\n } catch (err) {\n console.error(\n \"[ToolInvocationTracker] result chunk handling failed\",\n err,\n );\n }\n },\n }),\n )\n .catch((err) => {\n console.error(\n \"[ToolInvocationTracker] stream pipeline failed; will attempt single restart on next setState\",\n err,\n );\n this._pipelineDead = true;\n });\n }\n\n // ───────────────────────── public API ─────────────────────────\n\n /**\n * Feed the next observed snapshot into the tracker. Called from the host\n * runtime whenever its message list / running state changes.\n */\n public setState(snapshot: ToolInvocationTracker.Snapshot): void {\n try {\n // Recover from a dead pipeline before processing anything. Entries\n // that reached the executor are demoted to \"restored\" so the rebuilt\n // pipeline does not re-fire `streamCall` for them; the rest start over\n // across the boundary the restart opens (F.4).\n if (this._pipelineDead) {\n if (this._pipelineRestartUsed) {\n // Already retried once and failed again. Stay dead.\n return;\n }\n this._pipelineRestartUsed = true;\n this._pipelineDead = false;\n this._demoteEntriesToRestored();\n this._executing.clear();\n this._ac = new AbortController();\n this._initPipeline();\n // Fall through and process the snapshot against the fresh pipeline.\n }\n\n // Identical snapshot — skip processing entirely. Note: external-store\n // runtimes rebuild the messages array on every adapter update, so this\n // fast-path rarely triggers there; it's primarily for the React-hook\n // shim where state references are stable.\n if (\n this._lastSnapshot &&\n this._lastSnapshot.messages === snapshot.messages &&\n this._lastSnapshot.isRunning === snapshot.isRunning &&\n this._lastSnapshot.isLoading === snapshot.isLoading\n ) {\n return;\n }\n\n // While the host is still loading initial state, treat every snapshot\n // as historical: tool calls are recorded so the next live snapshot can\n // diff against them, but `streamCall` / `execute` do not fire.\n const restoreFromLoading = snapshot.isLoading === true;\n if (restoreFromLoading) {\n this._pendingRestore = true;\n }\n\n // E.4 / AF3 — only mark `_lastSnapshot`/`_isRunning` as observed after\n // processing succeeds. If `_processMessages` throws, the next snapshot\n // (even if identical) gets re-processed against the recovered state.\n const previousIsRunning = this._isRunning;\n this._isRunning = snapshot.isRunning;\n try {\n this._processMessages(snapshot.messages);\n } catch (err) {\n this._isRunning = previousIsRunning;\n throw err;\n }\n this._lastSnapshot = snapshot;\n this._pendingRestore = false;\n } catch (err) {\n console.error(\n \"[ToolInvocationTracker] setState failed; snapshot dropped\",\n err,\n );\n }\n }\n\n /**\n * Reset the tracker so the next observed snapshot is treated as historical.\n * Clears entries and aborts any in-flight executions. Used by callers like\n * `importExternalState` to mark a freshly loaded state as restored.\n */\n public reset(): void {\n try {\n this._pendingRestore = true;\n this._entries.clear();\n this._discardedToolCallIds.clear();\n this._lastSnapshot = null;\n void this.abort();\n // Statuses are cleared synchronously: discarded executions may never\n // settle (aborting hands the signal to the tool, it does not force\n // settlement), and a late settlement of one sibling must not republish\n // the others. `_deleteStatus` no-ops for cleared ids, so post-reset\n // settlements stay silent.\n if (this._statuses.size > 0) {\n this._statuses = new Map();\n this._invokeOnStatusesChange();\n }\n } catch (err) {\n console.error(\"[ToolInvocationTracker] reset failed\", err);\n }\n }\n\n /**\n * Abort any in-flight `execute()` invocations. Resolves once all of them\n * have settled (or immediately if none are running).\n *\n * `discardPending` additionally kills the calls that never reached the\n * executor, for a caller ending the turn rather than interrupting it. The\n * signal cannot reach those: they are waiting on the run to settle (A.10),\n * and the settled snapshot arrives after this installs a fresh controller.\n */\n public abort(options?: { discardPending?: boolean }): Promise<void> {\n try {\n this._humanInput.forEach(({ reject }) => {\n try {\n reject(new Error(\"Tool execution aborted\"));\n } catch {\n // host rejection handler threw — already in the abort path,\n // swallow so we continue cleaning up.\n }\n });\n this._humanInput.clear();\n\n if (options?.discardPending) {\n for (const [toolCallId, entry] of this._entries) {\n if (!entry.controller) continue;\n if (entry.argsComplete || entry.hasResult) continue;\n this._discardedToolCallIds.add(toolCallId);\n entry.skipExecute = true;\n }\n }\n\n this._ac.abort();\n this._ac = new AbortController();\n\n if (this._executing.size === 0) {\n return Promise.resolve();\n }\n const executionIds = new Set(this._executing);\n return new Promise<void>((resolve) => {\n this._settledResolvers.push({ executionIds, resolve });\n });\n } catch (err) {\n console.error(\"[ToolInvocationTracker] abort failed\", err);\n return Promise.resolve();\n }\n }\n\n /**\n * Resolve a pending human-input request for the given tool call. Returns\n * `true` if a pending request was resumed, `false` if the tracker has no\n * outstanding request for that id (the caller should fall back to its own\n * dispatch path).\n */\n public resume(toolCallId: string, payload: unknown): boolean {\n try {\n const handlers = this._humanInput.get(toolCallId);\n if (!handlers) return false;\n this._humanInput.delete(toolCallId);\n this._setStatus(toolCallId, { type: \"executing\" });\n handlers.resolve(payload);\n return true;\n } catch (err) {\n console.error(\"[ToolInvocationTracker] resume failed\", err);\n return false;\n }\n }\n\n /**\n * Returns the current tool execution status map. The returned `Map` is\n * the tracker's internal store — do not mutate it. Treat the reference\n * as a snapshot that may be replaced wholesale on the next status\n * transition.\n */\n public getStatuses(): ReadonlyMap<string, ToolExecutionStatus> {\n return this._statuses;\n }\n\n // ───────────────────── internal: tool wrapping ─────────────────────\n\n private _getWrappedTools(): Record<string, Tool> | undefined {\n const tools = this._getTools();\n if (!tools) return undefined;\n\n return Object.fromEntries(\n Object.entries(tools).map(([name, tool]) => {\n const execute = tool.execute;\n const streamCall = tool.streamCall;\n if (execute === undefined && streamCall === undefined)\n return [name, tool];\n\n const wrappedTool = {\n ...tool,\n ...(execute !== undefined && {\n execute: (...[args, context]: Parameters<typeof execute>) => {\n const executionId = getToolExecutionId(context);\n const entry = this._captureExecution(\n context.toolCallId,\n executionId,\n );\n if (!entry || entry.skipExecute) {\n return new Promise(() => {}) as never;\n }\n return execute(args, context);\n },\n }),\n ...(streamCall !== undefined && {\n streamCall: (\n ...[reader, context]: Parameters<typeof streamCall>\n ) => {\n const executionId = getToolExecutionId(context);\n const entry = this._captureExecution(\n context.toolCallId,\n executionId,\n );\n if (!entry) return;\n return streamCall(reader, context);\n },\n }),\n } as Tool;\n return [name, wrappedTool];\n }),\n ) as Record<string, Tool>;\n }\n\n private _captureExecution(\n toolCallId: string,\n executionId: symbol | undefined,\n ): ToolCallEntry | undefined {\n if (executionId === undefined) return undefined;\n const entry = this._entries.get(toolCallId);\n if (!entry?.controller) return undefined;\n if (entry.executionId === undefined) entry.executionId = executionId;\n return entry.executionId === executionId ? entry : undefined;\n }\n\n // ──────────────── internal: execution lifecycle callbacks ────────────────\n\n private _onHumanInput(\n toolCallId: string,\n payload: unknown,\n executionId?: symbol,\n ): Promise<unknown> {\n return new Promise<unknown>((resolve, reject) => {\n // A discarded execution must not resurrect a status entry or park an\n // unanswerable request after its id has been reused.\n const entry = this._entries.get(toolCallId);\n if (!entry?.controller || entry.executionId !== executionId) {\n reject(new Error(\"Tool execution aborted\"));\n return;\n }\n const previous = this._humanInput.get(toolCallId);\n if (previous) {\n try {\n previous.reject(\n new Error(\"Human input request was superseded by a new request\"),\n );\n } catch {\n // host rejection handler threw; ignore and proceed\n }\n }\n this._humanInput.set(toolCallId, {\n executionId: executionId!,\n resolve,\n reject,\n });\n this._setStatus(toolCallId, {\n type: \"interrupt\",\n payload: { type: \"human\", payload },\n });\n });\n }\n\n private _onExecutionStart(\n toolCallId: string,\n executionId: symbol | undefined,\n ): void {\n if (!this._captureExecution(toolCallId, executionId)) return;\n const entry = this._entries.get(toolCallId)!;\n if (entry.skipExecute) return;\n\n this._executing.add(executionId!);\n // execute can park human() before onExecutionStart; preserve this execution's interrupt.\n if (this._humanInput.get(toolCallId)?.executionId === executionId) return;\n this._setStatus(toolCallId, { type: \"executing\" });\n }\n\n private _onExecutionEnd(\n toolCallId: string,\n executionId: symbol | undefined,\n ): void {\n if (executionId === undefined || !this._executing.delete(executionId))\n return;\n\n const entry = this._entries.get(toolCallId);\n if (entry?.executionId === executionId) this._deleteStatus(toolCallId);\n\n const pending: SettledResolver[] = [];\n this._settledResolvers.forEach(({ executionIds, resolve }) => {\n if ([...executionIds].some((id) => this._executing.has(id))) {\n pending.push({ executionIds, resolve });\n return;\n }\n try {\n resolve();\n } catch {\n // ignore — settled-resolver consumer threw\n }\n });\n this._settledResolvers.length = 0;\n this._settledResolvers.push(...pending);\n }\n\n private _handleResultChunk(chunk: {\n type: \"result\";\n result: ReadonlyJSONValue;\n isError: boolean;\n artifact?: ReadonlyJSONValue;\n modelContent?: readonly ToolModelContentPart[];\n meta: { toolCallId: string; toolName: string };\n }): void {\n const toolCallId = chunk.meta.toolCallId;\n const executionId = getToolExecutionId(chunk);\n const entry = this._entries.get(toolCallId);\n\n if (!entry || entry.executionId !== executionId) return;\n\n // The host already set the result (via the live snapshot's\n // `setResponse` path). Suppress the executor's redundant emit.\n if (entry?.hasResult) return;\n if (entry.skipExecute) return;\n\n this._invokeOnResult({\n type: \"add-tool-result\",\n toolCallId,\n toolName: chunk.meta.toolName,\n result: chunk.result,\n isError: chunk.isError,\n ...(chunk.artifact !== undefined && { artifact: chunk.artifact }),\n ...(chunk.modelContent !== undefined && {\n modelContent: chunk.modelContent,\n }),\n });\n }\n\n // ──────────────── internal: callback invocation (AF1/AF2) ────────────────\n\n private _invokeOnResult(command: AddToolResultCommand): void {\n try {\n this._callbacks.onResult(command);\n } catch (err) {\n console.error(\n \"[ToolInvocationTracker] onResult callback threw; result dropped\",\n err,\n );\n }\n }\n\n private _invokeOnStatusesChange(): void {\n try {\n this._callbacks.onStatusesChange(this._statuses);\n } catch (err) {\n console.error(\n \"[ToolInvocationTracker] onStatusesChange callback threw; status change not propagated\",\n err,\n );\n }\n }\n\n // ──────────────── internal: status map mutations ────────────────\n\n private _setStatus(toolCallId: string, status: ToolExecutionStatus): void {\n const next = new Map(this._statuses);\n next.set(toolCallId, status);\n this._statuses = next;\n this._invokeOnStatusesChange();\n }\n\n private _deleteStatus(toolCallId: string): void {\n if (!this._statuses.has(toolCallId)) return;\n const next = new Map(this._statuses);\n next.delete(toolCallId);\n this._statuses = next;\n this._invokeOnStatusesChange();\n }\n\n // ──────────────── internal: snapshot processing ────────────────\n\n private _warnProviderOwnedSkip(toolName: string, toolCallId: string): void {\n if (process.env.NODE_ENV === \"production\") return;\n if (this._getTools()?.[toolName]?.execute === undefined) return;\n console.warn(\n \"[ToolInvocationTracker] the runtime reports this tool call as provider-owned, so the registered execute is skipped; the provider has to hand the call to the client for it to run (see EDGE_CASES.md A.9)\",\n { toolCallId, toolName },\n );\n }\n\n /**\n * Closing the args stream hands the call to the client executor, so it may\n * only happen once the provider can no longer speak about that call. The run\n * ending is the only universal signal for that; an adapter that reports the\n * call as client-owned has said it earlier, per call.\n */\n private _shouldCloseArgsStream({\n argsText,\n hasResult,\n clientOwned,\n }: {\n argsText: string;\n hasResult: boolean;\n clientOwned: boolean;\n }): boolean {\n if (hasResult) return true;\n if (!isArgsTextComplete(argsText)) return false;\n return clientOwned || !this._isRunning;\n }\n\n private _startActiveEntry(\n toolCallId: string,\n toolName: string,\n skipExecute: boolean,\n clientOwned: boolean,\n ): ToolCallEntry {\n const toolCallController = this._controller.addToolCallPart({\n toolName,\n toolCallId,\n });\n const entry: ToolCallEntry = {\n toolName,\n controller: toolCallController,\n argsText: \"\",\n hasResult: false,\n skipExecute,\n argsComplete: false,\n clientOwned,\n };\n this._entries.set(toolCallId, entry);\n return entry;\n }\n\n /**\n * Demote every active entry back to the restored phase. Used by the\n * pipeline-restart path so that, after a fresh pipeline is built, the\n * next observed snapshot does not re-fire `streamCall` for tool calls\n * that already fired pre-death. Args / hasResult tracking is preserved\n * so signature comparisons still work.\n */\n private _demoteEntriesToRestored(): void {\n for (const [toolCallId, entry] of this._entries) {\n if (!entry.controller) continue;\n if (!entry.argsComplete && !entry.hasResult) {\n // The call never reached the executor. A restored entry is promoted\n // only when its signature changes, and a call waiting on the run to\n // settle already holds its final args, so demoting it would strand it\n // unexecuted. Dropping it lets the next snapshot start it over; a call\n // whose turn was discarded is held by `_discardedToolCallIds`, not by\n // the entry, so starting over does not revive it.\n this._entries.delete(toolCallId);\n continue;\n }\n this._entries.set(toolCallId, {\n toolName: entry.toolName,\n argsText: entry.argsText,\n hasResult: entry.hasResult,\n });\n }\n }\n\n private _processArgsText(\n entry: ToolCallEntry,\n content: {\n toolCallId: string;\n toolName: string;\n argsText: string;\n result?: unknown;\n },\n ): void {\n if (!entry.controller) return;\n const hasResult = content.result !== undefined;\n\n if (content.argsText !== entry.argsText) {\n let shouldWriteArgsText = true;\n\n if (entry.argsComplete) {\n if (isEquivalentCompleteArgsText(entry.argsText, content.argsText)) {\n // A.3 — key reorder. Track new text, no re-fire needed.\n entry.argsText = content.argsText;\n shouldWriteArgsText = false;\n } else {\n // A.4 — args changed after first completion. Under the\n // \"exactly once per toolCallId\" contract we do not restart the\n // stream. The host's existing `streamCall` keeps its original\n // args view; the snapshot's new text is recorded for diffing\n // but not surfaced. Events API in a follow-up will expose this\n // to consumers that opt in.\n if (process.env.NODE_ENV !== \"production\") {\n console.warn(\n \"[ToolInvocationTracker] argsText changed after first completion; not re-firing streamCall (see EDGE_CASES.md A.4)\",\n {\n previous: entry.argsText,\n next: content.argsText,\n toolCallId: content.toolCallId,\n },\n );\n }\n shouldWriteArgsText = false;\n }\n } else if (!content.argsText.startsWith(entry.argsText)) {\n if (\n isArgsTextComplete(entry.argsText) &&\n isArgsTextComplete(content.argsText) &&\n isEquivalentCompleteArgsText(entry.argsText, content.argsText)\n ) {\n const shouldClose = this._shouldCloseArgsStream({\n argsText: content.argsText,\n hasResult,\n clientOwned: entry.clientOwned,\n });\n if (shouldClose) entry.controller.argsText.close();\n entry.argsText = content.argsText;\n entry.argsComplete = shouldClose;\n shouldWriteArgsText = false;\n } else {\n // A.2 — args regressed mid-stream. Under the \"exactly once\"\n // contract we do not restart. The controller keeps whatever\n // prefix we already streamed; subsequent prefix-respecting\n // updates can still flow against it. Snapshots that never\n // re-converge to a prefix will leave the controller's args\n // view stale relative to the snapshot. Events API in a\n // follow-up will expose this to consumers that opt in.\n if (process.env.NODE_ENV !== \"production\") {\n console.warn(\n \"[ToolInvocationTracker] argsText regressed mid-stream; not restarting (see EDGE_CASES.md A.2)\",\n {\n previous: entry.argsText,\n next: content.argsText,\n toolCallId: content.toolCallId,\n },\n );\n }\n shouldWriteArgsText = false;\n }\n }\n\n if (shouldWriteArgsText && entry.controller) {\n const delta = content.argsText.slice(entry.argsText.length);\n entry.controller.argsText.append(delta);\n const shouldClose = this._shouldCloseArgsStream({\n argsText: content.argsText,\n hasResult,\n clientOwned: entry.clientOwned,\n });\n if (shouldClose) entry.controller.argsText.close();\n entry.argsText = content.argsText;\n entry.argsComplete = shouldClose;\n }\n }\n\n if (!entry.argsComplete && entry.controller) {\n // ToolExecutionStream parses the streamed prefix on close, so the close\n // gates on the streamed content; a divergent snapshot (A.2) can be\n // complete while the controller still holds an incomplete stale prefix.\n const shouldClose = this._shouldCloseArgsStream({\n argsText: entry.argsText,\n hasResult,\n clientOwned: entry.clientOwned,\n });\n if (shouldClose) {\n entry.controller.argsText.close();\n entry.argsComplete = true;\n }\n }\n }\n\n private _processMessages(messages: readonly ThreadMessage[]): void {\n const isRestore = this._pendingRestore;\n\n for (const { part: content } of walkToolCallTree(messages)) {\n const existing = this._entries.get(content.toolCallId);\n\n if (isRestore) {\n // Don't overwrite an already-active entry (e.g. live tool-call\n // observed before this restore snapshot landed). Restore can\n // only seed entries the runtime has never seen.\n if (!existing?.controller) {\n this._entries.set(content.toolCallId, {\n toolName: content.toolName,\n argsText: content.argsText,\n hasResult: content.result !== undefined,\n });\n }\n continue;\n }\n\n // Live snapshot.\n let entry = existing;\n\n // A discarded id is remembered only until the call is answered, which\n // bounds the set to the open calls of a discarded turn.\n if (content.result !== undefined)\n this._discardedToolCallIds.delete(content.toolCallId);\n\n if (entry && !entry.controller) {\n // Restored entry observed in a live snapshot. Promote if its\n // signature has changed; otherwise treat as still-historical.\n const signatureChanged =\n content.argsText !== entry.argsText ||\n (content.result !== undefined) !== entry.hasResult;\n if (!signatureChanged) continue;\n this._entries.delete(content.toolCallId);\n entry = undefined;\n }\n\n if (!entry) {\n const ownership = this._isClientToolCall?.(content);\n const providerOwned =\n content.result === undefined && ownership === false;\n if (providerOwned)\n this._warnProviderOwnedSkip(content.toolName, content.toolCallId);\n entry = this._startActiveEntry(\n content.toolCallId,\n content.toolName,\n content.result !== undefined ||\n providerOwned ||\n this._discardedToolCallIds.has(content.toolCallId),\n ownership === true,\n );\n }\n\n if (content.approval !== undefined) entry.skipExecute = true;\n\n this._processArgsText(entry, content);\n\n if (content.result !== undefined && !entry.hasResult) {\n // `entry` is in active phase from this point — either just\n // created by `_startActiveEntry`, or pre-existing with a live\n // controller. Narrow once instead of asserting at every use.\n const { controller: activeController } = entry;\n if (!activeController) continue;\n entry.hasResult = true;\n entry.argsComplete = true;\n activeController.setResponse(\n new ToolResponse({\n result: content.result as ReadonlyJSONValue,\n artifact: content.artifact as ReadonlyJSONValue | undefined,\n isError: content.isError,\n ...(content.modelContent !== undefined\n ? { modelContent: content.modelContent }\n : {}),\n }),\n );\n activeController.close();\n }\n }\n }\n}\n\nexport namespace ToolInvocationTracker {\n export type ExecutionStatus = ToolExecutionStatus;\n\n export type Snapshot = {\n readonly messages: readonly ThreadMessage[];\n /** Whether the producing runtime is currently streaming new output. */\n readonly isRunning: boolean;\n /**\n * Whether the producing runtime is still loading historical state.\n * When `true`, every snapshot is treated as historical (no `streamCall` /\n * `execute` fires). When `false`, processing resumes as live.\n */\n readonly isLoading?: boolean;\n };\n\n export type Callbacks = {\n /**\n * Invoked when a client-side `execute()` returns a result and the runtime\n * needs to feed it back into the conversation.\n */\n onResult: (command: AddToolResultCommand) => void;\n /**\n * Invoked whenever the per-tool-call status map changes (executing /\n * interrupt / cleared). The callback receives a fresh map; mutating the\n * argument is not supported.\n */\n onStatusesChange: (\n statuses: ReadonlyMap<string, ToolExecutionStatus>,\n ) => void;\n };\n}\n"],"mappings":"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"}
@@ -53,7 +53,7 @@ type ExternalThreadProps = {
53
53
  /** Branch adapter for runtimes that track sibling variants of messages. */
54
54
  branches?: ExternalThreadBranchAdapter;
55
55
  /** Callback for tool approval decisions. Absent: responding to an approval throws a capability error. */
56
- onRespondToToolApproval?: (options: RespondToToolApprovalOptions) => void;
56
+ onRespondToToolApproval?: (options: RespondToToolApprovalOptions) => void | Promise<void>;
57
57
  };
58
58
  declare const ExternalThread: import("@assistant-ui/tap").Resource<ClientOutput<"thread">, [ExternalThreadProps]>;
59
59
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"external-thread.d.ts","names":[],"sources":["../../../src/store/clients/external-thread.ts"],"mappings":";;;;;;;;;;KAyDY,wBAAwB;EAClC;;KAgBU;EACV,mBAAmB;EACnB;EACA;EACA,QAAQ;EACR;;;;;;;EAOA;;;;;EAKA,SAAS,SAAS;EAClB,UAAU,SAAS;EACnB,YAAY;EACZ;EACA;EACA;;;;;;;EAOA,yBAAyB;EACzB,oBAAoB,SAAS;;EAE7B,qBAAqB,SAAS;EAC9B,wBAAwB;EACxB,oBAAoB;EACpB,kBAAkB;EAClB,gBAAgB;;EAEhB,QAAQ;;EAER,WAAW;;EAEX,2BAA2B,SAAS;;cAqkCzB,4CAAc,SAAA,yBAAA"}
1
+ {"version":3,"file":"external-thread.d.ts","names":[],"sources":["../../../src/store/clients/external-thread.ts"],"mappings":";;;;;;;;;;KA8DY,wBAAwB;EAClC;;KAgBU;EACV,mBAAmB;EACnB;EACA;EACA,QAAQ;EACR;;;;;;;EAOA;;;;;EAKA,SAAS,SAAS;EAClB,UAAU,SAAS;EACnB,YAAY;EACZ;EACA;EACA;;;;;;;EAOA,yBAAyB;EACzB,oBAAoB,SAAS;;EAE7B,qBAAqB,SAAS;EAC9B,wBAAwB;EACxB,oBAAoB;EACpB,kBAAkB;EAClB,gBAAgB;;EAEhB,QAAQ;;EAER,WAAW;;EAEX,2BACE,SAAS,wCACC;;cAuhCD,4CAAc,SAAA,yBAAA"}