@athenaintel/react 0.41.3 → 0.42.2

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 (479) hide show
  1. package/README.md +132 -10
  2. package/dist/agent-runtime/src/asset-attachment.d.ts +98 -0
  3. package/dist/agent-runtime/src/athena-asset-drag.d.ts +32 -0
  4. package/dist/agent-runtime/src/auth-denial.d.ts +29 -0
  5. package/dist/agent-runtime/src/chat-outbox-attachments.cjs +41 -0
  6. package/dist/agent-runtime/src/chat-outbox-attachments.cjs.map +1 -0
  7. package/dist/agent-runtime/src/chat-outbox-attachments.d.ts +38 -0
  8. package/dist/agent-runtime/src/chat-outbox-attachments.js +41 -0
  9. package/dist/agent-runtime/src/chat-outbox-attachments.js.map +1 -0
  10. package/dist/agent-runtime/src/chat-outbox-signals.cjs +63 -0
  11. package/dist/agent-runtime/src/chat-outbox-signals.cjs.map +1 -0
  12. package/dist/agent-runtime/src/chat-outbox-signals.d.ts +12 -0
  13. package/dist/agent-runtime/src/chat-outbox-signals.js +63 -0
  14. package/dist/agent-runtime/src/chat-outbox-signals.js.map +1 -0
  15. package/dist/agent-runtime/src/chat-outbox-store.cjs +509 -0
  16. package/dist/agent-runtime/src/chat-outbox-store.cjs.map +1 -0
  17. package/dist/agent-runtime/src/chat-outbox-store.d.ts +203 -0
  18. package/dist/agent-runtime/src/chat-outbox-store.js +509 -0
  19. package/dist/agent-runtime/src/chat-outbox-store.js.map +1 -0
  20. package/dist/agent-runtime/src/chat-outbox-thread.cjs +136 -0
  21. package/dist/agent-runtime/src/chat-outbox-thread.cjs.map +1 -0
  22. package/dist/agent-runtime/src/chat-outbox-thread.d.ts +118 -0
  23. package/dist/agent-runtime/src/chat-outbox-thread.js +136 -0
  24. package/dist/agent-runtime/src/chat-outbox-thread.js.map +1 -0
  25. package/dist/agent-runtime/src/chat-outbox.cjs +696 -0
  26. package/dist/agent-runtime/src/chat-outbox.cjs.map +1 -0
  27. package/dist/agent-runtime/src/chat-outbox.d.ts +285 -0
  28. package/dist/agent-runtime/src/chat-outbox.js +696 -0
  29. package/dist/agent-runtime/src/chat-outbox.js.map +1 -0
  30. package/dist/agent-runtime/src/chat-socket-reachability.d.ts +45 -0
  31. package/dist/agent-runtime/src/client-tool-bridge.d.ts +152 -0
  32. package/dist/agent-runtime/src/client-tools.d.ts +133 -0
  33. package/dist/agent-runtime/src/composer-markdown.cjs +10 -0
  34. package/dist/agent-runtime/src/composer-markdown.cjs.map +1 -1
  35. package/dist/agent-runtime/src/composer-markdown.d.ts +108 -0
  36. package/dist/agent-runtime/src/composer-markdown.js +10 -0
  37. package/dist/agent-runtime/src/composer-markdown.js.map +1 -1
  38. package/dist/agent-runtime/src/config-mutations.d.ts +51 -0
  39. package/dist/agent-runtime/src/conversation-index.d.ts +110 -0
  40. package/dist/agent-runtime/src/conversation-list.d.ts +343 -0
  41. package/dist/agent-runtime/src/deep-agent-transport-recipe.cjs +3 -2
  42. package/dist/agent-runtime/src/deep-agent-transport-recipe.cjs.map +1 -1
  43. package/dist/agent-runtime/src/deep-agent-transport-recipe.d.ts +166 -0
  44. package/dist/agent-runtime/src/deep-agent-transport-recipe.js +3 -2
  45. package/dist/agent-runtime/src/deep-agent-transport-recipe.js.map +1 -1
  46. package/dist/agent-runtime/src/desktop-handoff.d.ts +139 -0
  47. package/dist/agent-runtime/src/durable-thread-snapshot-cache.d.ts +60 -0
  48. package/dist/agent-runtime/src/edit-command.d.ts +156 -0
  49. package/dist/agent-runtime/src/errors.d.ts +174 -0
  50. package/dist/agent-runtime/src/execute-output.d.ts +31 -0
  51. package/dist/agent-runtime/src/generated/runconfig-contract.cjs +16 -2
  52. package/dist/agent-runtime/src/generated/runconfig-contract.cjs.map +1 -1
  53. package/dist/agent-runtime/src/generated/runconfig-contract.d.ts +202 -0
  54. package/dist/agent-runtime/src/generated/runconfig-contract.js +16 -2
  55. package/dist/agent-runtime/src/generated/runconfig-contract.js.map +1 -1
  56. package/dist/agent-runtime/src/github-wake-event.d.ts +77 -0
  57. package/dist/agent-runtime/src/index.d.ts +74 -0
  58. package/dist/agent-runtime/src/interrupts.cjs +17 -0
  59. package/dist/agent-runtime/src/interrupts.cjs.map +1 -1
  60. package/dist/agent-runtime/src/interrupts.d.ts +348 -0
  61. package/dist/agent-runtime/src/interrupts.js +17 -0
  62. package/dist/agent-runtime/src/interrupts.js.map +1 -1
  63. package/dist/agent-runtime/src/lane-follow.d.ts +121 -0
  64. package/dist/agent-runtime/src/lane-history.cjs +209 -0
  65. package/dist/agent-runtime/src/lane-history.cjs.map +1 -0
  66. package/dist/agent-runtime/src/lane-history.d.ts +175 -0
  67. package/dist/agent-runtime/src/lane-history.js +209 -0
  68. package/dist/agent-runtime/src/lane-history.js.map +1 -0
  69. package/dist/agent-runtime/src/lane-images.d.ts +184 -0
  70. package/dist/agent-runtime/src/message-author.d.ts +43 -0
  71. package/dist/agent-runtime/src/message-text.cjs +15 -0
  72. package/dist/agent-runtime/src/message-text.cjs.map +1 -0
  73. package/dist/agent-runtime/src/message-text.d.ts +47 -0
  74. package/dist/agent-runtime/src/message-text.js +15 -0
  75. package/dist/agent-runtime/src/message-text.js.map +1 -0
  76. package/dist/agent-runtime/src/message-window.cjs +15 -1
  77. package/dist/agent-runtime/src/message-window.cjs.map +1 -1
  78. package/dist/agent-runtime/src/message-window.d.ts +159 -0
  79. package/dist/agent-runtime/src/message-window.js +16 -2
  80. package/dist/agent-runtime/src/message-window.js.map +1 -1
  81. package/dist/agent-runtime/src/messages.cjs +123 -8
  82. package/dist/agent-runtime/src/messages.cjs.map +1 -1
  83. package/dist/agent-runtime/src/messages.d.ts +621 -0
  84. package/dist/agent-runtime/src/messages.js +123 -8
  85. package/dist/agent-runtime/src/messages.js.map +1 -1
  86. package/dist/agent-runtime/src/model-context.d.ts +22 -0
  87. package/dist/agent-runtime/src/offline-status.d.ts +157 -0
  88. package/dist/agent-runtime/src/optimistic-content.d.ts +21 -0
  89. package/dist/agent-runtime/src/protocol.cjs +12 -4
  90. package/dist/agent-runtime/src/protocol.cjs.map +1 -1
  91. package/dist/agent-runtime/src/protocol.d.ts +119 -0
  92. package/dist/agent-runtime/src/protocol.js +13 -5
  93. package/dist/agent-runtime/src/protocol.js.map +1 -1
  94. package/dist/agent-runtime/src/ptc-subcalls.d.ts +51 -0
  95. package/dist/agent-runtime/src/queue.d.ts +138 -0
  96. package/dist/agent-runtime/src/quota-safe-local-storage-session.cjs +10 -0
  97. package/dist/agent-runtime/src/quota-safe-local-storage-session.cjs.map +1 -1
  98. package/dist/agent-runtime/src/quota-safe-local-storage-session.d.ts +161 -0
  99. package/dist/agent-runtime/src/quota-safe-local-storage-session.js +10 -0
  100. package/dist/agent-runtime/src/quota-safe-local-storage-session.js.map +1 -1
  101. package/dist/agent-runtime/src/running-tool-placeholder.cjs +11 -0
  102. package/dist/agent-runtime/src/running-tool-placeholder.cjs.map +1 -0
  103. package/dist/agent-runtime/src/running-tool-placeholder.d.ts +25 -0
  104. package/dist/agent-runtime/src/running-tool-placeholder.js +11 -0
  105. package/dist/agent-runtime/src/running-tool-placeholder.js.map +1 -0
  106. package/dist/agent-runtime/src/runtime-messages.d.ts +104 -0
  107. package/dist/agent-runtime/src/screen-point.d.ts +151 -0
  108. package/dist/agent-runtime/src/sealed-idb.cjs +112 -0
  109. package/dist/agent-runtime/src/sealed-idb.cjs.map +1 -0
  110. package/dist/agent-runtime/src/sealed-idb.d.ts +106 -0
  111. package/dist/agent-runtime/src/sealed-idb.js +112 -0
  112. package/dist/agent-runtime/src/sealed-idb.js.map +1 -0
  113. package/dist/agent-runtime/src/send-recovery.d.ts +40 -0
  114. package/dist/agent-runtime/src/session-lane-scope.cjs +25 -0
  115. package/dist/agent-runtime/src/session-lane-scope.cjs.map +1 -0
  116. package/dist/agent-runtime/src/session-lane-scope.d.ts +59 -0
  117. package/dist/agent-runtime/src/session-lane-scope.js +25 -0
  118. package/dist/agent-runtime/src/session-lane-scope.js.map +1 -0
  119. package/dist/agent-runtime/src/statewire-attach-observer.d.ts +194 -0
  120. package/dist/agent-runtime/src/statewire-diagnostics.d.ts +74 -0
  121. package/dist/agent-runtime/src/statewire-state.d.ts +29 -0
  122. package/dist/agent-runtime/src/statewire-suspended.cjs.map +1 -1
  123. package/dist/agent-runtime/src/statewire-suspended.d.ts +27 -0
  124. package/dist/agent-runtime/src/statewire-suspended.js.map +1 -1
  125. package/dist/agent-runtime/src/statewire-transport.d.ts +40 -0
  126. package/dist/agent-runtime/src/streaming-markdown.d.ts +46 -0
  127. package/dist/agent-runtime/src/subagent-transcripts.cjs +209 -0
  128. package/dist/agent-runtime/src/subagent-transcripts.cjs.map +1 -0
  129. package/dist/agent-runtime/src/subagent-transcripts.d.ts +71 -0
  130. package/dist/agent-runtime/src/subagent-transcripts.js +209 -0
  131. package/dist/agent-runtime/src/subagent-transcripts.js.map +1 -0
  132. package/dist/agent-runtime/src/subagents.cjs +253 -0
  133. package/dist/agent-runtime/src/subagents.cjs.map +1 -0
  134. package/dist/agent-runtime/src/subagents.d.ts +311 -0
  135. package/dist/agent-runtime/src/subagents.js +253 -0
  136. package/dist/agent-runtime/src/subagents.js.map +1 -0
  137. package/dist/agent-runtime/src/subscription-wake-event.d.ts +111 -0
  138. package/dist/agent-runtime/src/thread-extras.d.ts +43 -0
  139. package/dist/agent-runtime/src/thread-handoff.d.ts +364 -0
  140. package/dist/agent-runtime/src/thread-prewarm-controller.d.ts +76 -0
  141. package/dist/agent-runtime/src/thread-prewarm.d.ts +118 -0
  142. package/dist/agent-runtime/src/thread-snapshot-cache.d.ts +99 -0
  143. package/dist/agent-runtime/src/thread-snapshot-mirror.cjs +46 -117
  144. package/dist/agent-runtime/src/thread-snapshot-mirror.cjs.map +1 -1
  145. package/dist/agent-runtime/src/thread-snapshot-mirror.d.ts +101 -0
  146. package/dist/agent-runtime/src/thread-snapshot-mirror.js +17 -88
  147. package/dist/agent-runtime/src/thread-snapshot-mirror.js.map +1 -1
  148. package/dist/agent-runtime/src/thread-status.d.ts +53 -0
  149. package/dist/agent-runtime/src/tool-metadata.d.ts +146 -0
  150. package/dist/agent-runtime/src/tool-names.cjs +71 -0
  151. package/dist/agent-runtime/src/tool-names.cjs.map +1 -1
  152. package/dist/agent-runtime/src/tool-names.d.ts +67 -0
  153. package/dist/agent-runtime/src/tool-names.js +72 -1
  154. package/dist/agent-runtime/src/tool-names.js.map +1 -1
  155. package/dist/agent-runtime/src/tool-outputs.d.ts +35 -0
  156. package/dist/agent-runtime/src/tool-result.cjs +1 -0
  157. package/dist/agent-runtime/src/tool-result.cjs.map +1 -1
  158. package/dist/agent-runtime/src/tool-result.d.ts +126 -0
  159. package/dist/agent-runtime/src/tool-result.js +1 -0
  160. package/dist/agent-runtime/src/tool-result.js.map +1 -1
  161. package/dist/agent-runtime/src/types.d.ts +159 -0
  162. package/dist/agent-runtime/src/use-conversation-list.d.ts +76 -0
  163. package/dist/agent-runtime/src/use-deep-agent-chat-outbox.cjs +136 -0
  164. package/dist/agent-runtime/src/use-deep-agent-chat-outbox.cjs.map +1 -0
  165. package/dist/agent-runtime/src/use-deep-agent-chat-outbox.d.ts +64 -0
  166. package/dist/agent-runtime/src/use-deep-agent-chat-outbox.js +136 -0
  167. package/dist/agent-runtime/src/use-deep-agent-chat-outbox.js.map +1 -0
  168. package/dist/agent-runtime/src/use-deep-agent-config.d.ts +169 -0
  169. package/dist/agent-runtime/src/use-deep-agent-edit-submit.cjs +13 -0
  170. package/dist/agent-runtime/src/use-deep-agent-edit-submit.cjs.map +1 -1
  171. package/dist/agent-runtime/src/use-deep-agent-edit-submit.d.ts +22 -0
  172. package/dist/agent-runtime/src/use-deep-agent-edit-submit.js +13 -0
  173. package/dist/agent-runtime/src/use-deep-agent-edit-submit.js.map +1 -1
  174. package/dist/agent-runtime/src/use-deep-agent-runtime.cjs +37 -2
  175. package/dist/agent-runtime/src/use-deep-agent-runtime.cjs.map +1 -1
  176. package/dist/agent-runtime/src/use-deep-agent-runtime.d.ts +177 -0
  177. package/dist/agent-runtime/src/use-deep-agent-runtime.js +38 -3
  178. package/dist/agent-runtime/src/use-deep-agent-runtime.js.map +1 -1
  179. package/dist/agent-runtime/src/use-deep-agent-thread.cjs +39 -13
  180. package/dist/agent-runtime/src/use-deep-agent-thread.cjs.map +1 -1
  181. package/dist/agent-runtime/src/use-deep-agent-thread.d.ts +352 -0
  182. package/dist/agent-runtime/src/use-deep-agent-thread.js +39 -13
  183. package/dist/agent-runtime/src/use-deep-agent-thread.js.map +1 -1
  184. package/dist/agent-runtime/src/use-deep-agent-voice.cjs +1019 -0
  185. package/dist/agent-runtime/src/use-deep-agent-voice.cjs.map +1 -0
  186. package/dist/agent-runtime/src/use-deep-agent-voice.d.ts +409 -0
  187. package/dist/agent-runtime/src/use-deep-agent-voice.js +1019 -0
  188. package/dist/agent-runtime/src/use-deep-agent-voice.js.map +1 -0
  189. package/dist/agent-runtime/src/use-deep-agent-window-sync.d.ts +102 -0
  190. package/dist/agent-runtime/src/use-historical-edit-attachments.d.ts +2 -0
  191. package/dist/agent-runtime/src/use-thread-handoff-flow.d.ts +84 -0
  192. package/dist/agent-runtime/src/voice-presentation.cjs +2 -0
  193. package/dist/agent-runtime/src/voice-presentation.cjs.map +1 -1
  194. package/dist/agent-runtime/src/voice-presentation.d.ts +80 -0
  195. package/dist/agent-runtime/src/voice-presentation.js +2 -0
  196. package/dist/agent-runtime/src/voice-presentation.js.map +1 -1
  197. package/dist/agent-runtime/src/voice-turn-grouping.d.ts +28 -0
  198. package/dist/agent-runtime/src/voice-wire-types.d.ts +15 -0
  199. package/dist/agent-runtime/src/withdrawn-turns.d.ts +97 -0
  200. package/dist/catalog/runtime-catalog.js +1 -1
  201. package/dist/chat/AthenaChat.cjs +192 -103
  202. package/dist/chat/AthenaChat.cjs.map +1 -1
  203. package/dist/chat/AthenaChat.d.ts +9 -0
  204. package/dist/chat/AthenaChat.js +194 -105
  205. package/dist/chat/AthenaChat.js.map +1 -1
  206. package/dist/chat/StatewireApprovalCard.d.ts +1 -1
  207. package/dist/chat/StatewireClientToolBridge.d.ts +1 -1
  208. package/dist/chat/StatewireQueuedMessages.cjs +11 -4
  209. package/dist/chat/StatewireQueuedMessages.cjs.map +1 -1
  210. package/dist/chat/StatewireQueuedMessages.d.ts +1 -1
  211. package/dist/chat/StatewireQueuedMessages.js +11 -4
  212. package/dist/chat/StatewireQueuedMessages.js.map +1 -1
  213. package/dist/chat/chat-outbox-rows.cjs +223 -0
  214. package/dist/chat/chat-outbox-rows.cjs.map +1 -0
  215. package/dist/chat/chat-outbox-rows.d.ts +29 -0
  216. package/dist/chat/chat-outbox-rows.js +223 -0
  217. package/dist/chat/chat-outbox-rows.js.map +1 -0
  218. package/dist/chat/chat-voice-controls.cjs +128 -0
  219. package/dist/chat/chat-voice-controls.cjs.map +1 -0
  220. package/dist/chat/chat-voice-controls.d.ts +19 -0
  221. package/dist/chat/chat-voice-controls.js +128 -0
  222. package/dist/chat/chat-voice-controls.js.map +1 -0
  223. package/dist/chat/statewire-approval.d.ts +1 -1
  224. package/dist/chat/statewire-client-tools.d.ts +1 -1
  225. package/dist/chat/super-grouping/SuperGroupingCard.cjs +3 -1
  226. package/dist/chat/super-grouping/SuperGroupingCard.cjs.map +1 -1
  227. package/dist/chat/super-grouping/SuperGroupingCard.d.ts +7 -1
  228. package/dist/chat/super-grouping/SuperGroupingCard.js +3 -1
  229. package/dist/chat/super-grouping/SuperGroupingCard.js.map +1 -1
  230. package/dist/chat/super-grouping/SuperGroupingTranscript.cjs +7 -2
  231. package/dist/chat/super-grouping/SuperGroupingTranscript.cjs.map +1 -1
  232. package/dist/chat/super-grouping/SuperGroupingTranscript.d.ts +2 -2
  233. package/dist/chat/super-grouping/SuperGroupingTranscript.js +7 -2
  234. package/dist/chat/super-grouping/SuperGroupingTranscript.js.map +1 -1
  235. package/dist/chat/super-grouping/activity-timeline.cjs +15 -8
  236. package/dist/chat/super-grouping/activity-timeline.cjs.map +1 -1
  237. package/dist/chat/super-grouping/activity-timeline.d.ts +18 -8
  238. package/dist/chat/super-grouping/activity-timeline.js +15 -8
  239. package/dist/chat/super-grouping/activity-timeline.js.map +1 -1
  240. package/dist/chat/use-statewire-approval-request.cjs +36 -0
  241. package/dist/chat/use-statewire-approval-request.cjs.map +1 -1
  242. package/dist/chat/use-statewire-approval-request.d.ts +49 -1
  243. package/dist/chat/use-statewire-approval-request.js +39 -3
  244. package/dist/chat/use-statewire-approval-request.js.map +1 -1
  245. package/dist/chat-ui/composer/tiptap-composer.cjs +133 -14
  246. package/dist/chat-ui/composer/tiptap-composer.cjs.map +1 -1
  247. package/dist/chat-ui/composer/tiptap-composer.d.ts +33 -1
  248. package/dist/chat-ui/composer/tiptap-composer.js +135 -16
  249. package/dist/chat-ui/composer/tiptap-composer.js.map +1 -1
  250. package/dist/chat-ui/header/conversation-history-panel.d.ts +1 -1
  251. package/dist/chat-ui/index.d.ts +1 -1
  252. package/dist/chat-ui/mentions/suggestions/data/api-client.cjs +2 -1
  253. package/dist/chat-ui/mentions/suggestions/data/api-client.cjs.map +1 -1
  254. package/dist/chat-ui/mentions/suggestions/data/api-client.d.ts +3 -1
  255. package/dist/chat-ui/mentions/suggestions/data/api-client.js +2 -1
  256. package/dist/chat-ui/mentions/suggestions/data/api-client.js.map +1 -1
  257. package/dist/chat-ui/mentions/use-account-workspace-id.cjs +29 -51
  258. package/dist/chat-ui/mentions/use-account-workspace-id.cjs.map +1 -1
  259. package/dist/chat-ui/mentions/use-account-workspace-id.d.ts +2 -2
  260. package/dist/chat-ui/mentions/use-account-workspace-id.js +30 -52
  261. package/dist/chat-ui/mentions/use-account-workspace-id.js.map +1 -1
  262. package/dist/chat-ui/messages/message-components.cjs +15 -0
  263. package/dist/chat-ui/messages/message-components.cjs.map +1 -1
  264. package/dist/chat-ui/messages/message-components.js +15 -0
  265. package/dist/chat-ui/messages/message-components.js.map +1 -1
  266. package/dist/chat-ui/messages/runtime-message.d.ts +1 -1
  267. package/dist/chat-ui/messages/statewire-continue-run.d.ts +1 -1
  268. package/dist/chat-ui/messages/user-edit-composer.cjs +15 -2
  269. package/dist/chat-ui/messages/user-edit-composer.cjs.map +1 -1
  270. package/dist/chat-ui/messages/user-edit-composer.d.ts +4 -2
  271. package/dist/chat-ui/messages/user-edit-composer.js +15 -2
  272. package/dist/chat-ui/messages/user-edit-composer.js.map +1 -1
  273. package/dist/chat-ui/messages/wake-marker.d.ts +1 -1
  274. package/dist/chat-ui/rich-text/chat-text-schema.cjs +1 -0
  275. package/dist/chat-ui/rich-text/chat-text-schema.cjs.map +1 -1
  276. package/dist/chat-ui/rich-text/chat-text-schema.d.ts +3 -0
  277. package/dist/chat-ui/rich-text/chat-text-schema.js +1 -0
  278. package/dist/chat-ui/rich-text/chat-text-schema.js.map +1 -1
  279. package/dist/chat-ui/statewire.cjs +1 -0
  280. package/dist/chat-ui/statewire.cjs.map +1 -1
  281. package/dist/chat-ui/statewire.d.ts +2 -2
  282. package/dist/chat-ui/statewire.js +2 -1
  283. package/dist/chat-ui/thread/composer-send-or-stop.cjs +2 -1
  284. package/dist/chat-ui/thread/composer-send-or-stop.cjs.map +1 -1
  285. package/dist/chat-ui/thread/composer-send-or-stop.d.ts +2 -0
  286. package/dist/chat-ui/thread/composer-send-or-stop.js +2 -1
  287. package/dist/chat-ui/thread/composer-send-or-stop.js.map +1 -1
  288. package/dist/chat-ui/thread/statewire-history-edge.d.ts +1 -1
  289. package/dist/composer/AttachmentContext.cjs +8 -4
  290. package/dist/composer/AttachmentContext.cjs.map +1 -1
  291. package/dist/composer/AttachmentContext.d.ts +7 -0
  292. package/dist/composer/AttachmentContext.js +8 -4
  293. package/dist/composer/AttachmentContext.js.map +1 -1
  294. package/dist/composer/build-composed-message.cjs +34 -0
  295. package/dist/composer/build-composed-message.cjs.map +1 -1
  296. package/dist/composer/build-composed-message.d.ts +20 -0
  297. package/dist/composer/build-composed-message.js +35 -1
  298. package/dist/composer/build-composed-message.js.map +1 -1
  299. package/dist/composer/composer-handoff.cjs +39 -2
  300. package/dist/composer/composer-handoff.cjs.map +1 -1
  301. package/dist/composer/composer-handoff.d.ts +28 -3
  302. package/dist/composer/composer-handoff.js +39 -2
  303. package/dist/composer/composer-handoff.js.map +1 -1
  304. package/dist/composer/useAttachFiles.cjs +15 -2
  305. package/dist/composer/useAttachFiles.cjs.map +1 -1
  306. package/dist/composer/useAttachFiles.d.ts +11 -0
  307. package/dist/composer/useAttachFiles.js +15 -2
  308. package/dist/composer/useAttachFiles.js.map +1 -1
  309. package/dist/composer/useSendMessage.cjs.map +1 -1
  310. package/dist/composer/useSendMessage.d.ts +4 -3
  311. package/dist/composer/useSendMessage.js.map +1 -1
  312. package/dist/diagnostics/athena-diagnostics.cjs.map +1 -1
  313. package/dist/diagnostics/athena-diagnostics.d.ts +3 -1
  314. package/dist/diagnostics/athena-diagnostics.js.map +1 -1
  315. package/dist/index.cjs +13 -0
  316. package/dist/index.cjs.map +1 -1
  317. package/dist/index.d.ts +14 -7
  318. package/dist/index.js +14 -1
  319. package/dist/index.js.map +1 -1
  320. package/dist/offline/chat-outbox.cjs +57 -0
  321. package/dist/offline/chat-outbox.cjs.map +1 -0
  322. package/dist/offline/chat-outbox.d.ts +80 -0
  323. package/dist/offline/chat-outbox.js +57 -0
  324. package/dist/offline/chat-outbox.js.map +1 -0
  325. package/dist/offline/offline-history.d.ts +1 -1
  326. package/dist/provider/AthenaProvider.cjs +162 -8
  327. package/dist/provider/AthenaProvider.cjs.map +1 -1
  328. package/dist/provider/AthenaProvider.d.ts +15 -1
  329. package/dist/provider/AthenaProvider.js +163 -9
  330. package/dist/provider/AthenaProvider.js.map +1 -1
  331. package/dist/provider/statewire-window-context.d.ts +1 -1
  332. package/dist/react/package.json.cjs +1 -1
  333. package/dist/react/package.json.js +1 -1
  334. package/dist/references/src/anchors/file-line-range.d.ts +58 -0
  335. package/dist/references/src/anchors/format.d.ts +21 -0
  336. package/dist/references/src/anchors/message-anchors.d.ts +71 -0
  337. package/dist/references/src/anchors/parse.d.ts +8 -0
  338. package/dist/references/src/anchors/registry-contract.d.ts +24 -0
  339. package/dist/references/src/anchors/registry.d.ts +19 -0
  340. package/dist/references/src/anchors/schemas.d.ts +194 -0
  341. package/dist/references/src/anchors/serialize.d.ts +8 -0
  342. package/dist/references/src/anchors/time.d.ts +78 -0
  343. package/dist/references/src/anchors/types.d.ts +474 -0
  344. package/dist/references/src/asset-bounds.d.ts +27 -0
  345. package/dist/references/src/asset-links.d.ts +23 -0
  346. package/dist/references/src/asset-reference.d.ts +16 -0
  347. package/dist/references/src/formats/format-catalog.d.ts +79 -0
  348. package/dist/references/src/formats/markdown/parse-reference-markdown.d.ts +28 -0
  349. package/dist/references/src/formats/markdown/reference-display-name.d.ts +6 -0
  350. package/dist/references/src/formats/object/asset-object.d.ts +9 -0
  351. package/dist/references/src/formats/object/callable-object.d.ts +6 -0
  352. package/dist/references/src/formats/object/decode-reference-object-payload.d.ts +3 -0
  353. package/dist/references/src/formats/object/external-url-object.d.ts +9 -0
  354. package/dist/references/src/formats/object/group-object.d.ts +9 -0
  355. package/dist/references/src/formats/object/navigation-object.d.ts +9 -0
  356. package/dist/references/src/formats/object/parse-reference-object.d.ts +11 -0
  357. package/dist/references/src/formats/object/person-object.d.ts +9 -0
  358. package/dist/references/src/formats/uri/asset-mention-uri.d.ts +9 -0
  359. package/dist/references/src/formats/uri/asset-spaces-url.d.ts +9 -0
  360. package/dist/references/src/formats/uri/callable-mention-uris.d.ts +9 -0
  361. package/dist/references/src/formats/uri/detect-uri-wire.d.ts +9 -0
  362. package/dist/references/src/formats/uri/group-mention-uri.d.ts +12 -0
  363. package/dist/references/src/formats/uri/navigation-spaces-url.d.ts +14 -0
  364. package/dist/references/src/formats/uri/parse-reference-uri.d.ts +20 -0
  365. package/dist/references/src/formats/uri/person-mention-uri.d.ts +9 -0
  366. package/dist/references/src/formats/uri/template-placeholder.d.ts +12 -0
  367. package/dist/references/src/index.d.ts +47 -0
  368. package/dist/references/src/legacy/index.d.ts +14 -0
  369. package/dist/references/src/legacy/pre-reference-asset-url.d.ts +57 -0
  370. package/dist/references/src/legacy/pre-reference-citation-bridge.d.ts +22 -0
  371. package/dist/references/src/legacy/pre-reference-citation.d.ts +138 -0
  372. package/dist/references/src/legacy/pre-reference-external-url.d.ts +31 -0
  373. package/dist/references/src/legacy/pre-reference-format.d.ts +8 -0
  374. package/dist/references/src/legacy/pre-reference-mention.d.ts +27 -0
  375. package/dist/references/src/legacy/pre-reference-object.d.ts +8 -0
  376. package/dist/references/src/legacy/pre-reference-uri.d.ts +12 -0
  377. package/dist/references/src/legacy.d.ts +2 -0
  378. package/dist/references/src/mention-href-patterns.d.ts +19 -0
  379. package/dist/references/src/mention-node/index.d.ts +5 -0
  380. package/dist/references/src/mention-node/mention-node.d.ts +31 -0
  381. package/dist/references/src/mention-node/resolve-node-attrs.d.ts +27 -0
  382. package/dist/references/src/parse-reference.d.ts +23 -0
  383. package/dist/references/src/schemas.d.ts +463 -0
  384. package/dist/references/src/serialize-reference.d.ts +50 -0
  385. package/dist/references/src/sheet-name.d.ts +10 -0
  386. package/dist/references/src/tool-option-schemas.d.ts +597 -0
  387. package/dist/references/src/types.d.ts +125 -0
  388. package/dist/references/src/version-ref.d.ts +30 -0
  389. package/dist/runtime/statewire-lifecycle.d.ts +1 -1
  390. package/dist/runtime/statewire-model-lane.d.ts +1 -1
  391. package/dist/runtime/statewire-server-lane-context.d.ts +1 -1
  392. package/dist/runtime/statewire-session-key.cjs +7 -0
  393. package/dist/runtime/statewire-session-key.cjs.map +1 -1
  394. package/dist/runtime/statewire-session-key.d.ts +19 -0
  395. package/dist/runtime/statewire-session-key.js +8 -1
  396. package/dist/runtime/statewire-session-key.js.map +1 -1
  397. package/dist/runtime/statewire-session-lane.cjs +48 -0
  398. package/dist/runtime/statewire-session-lane.cjs.map +1 -0
  399. package/dist/runtime/statewire-session-lane.d.ts +29 -0
  400. package/dist/runtime/statewire-session-lane.js +48 -0
  401. package/dist/runtime/statewire-session-lane.js.map +1 -0
  402. package/dist/runtime/statewire-thread-config-lane.d.ts +1 -1
  403. package/dist/runtime/useAthenaStatewireRuntime.cjs +19 -5
  404. package/dist/runtime/useAthenaStatewireRuntime.cjs.map +1 -1
  405. package/dist/runtime/useAthenaStatewireRuntime.d.ts +15 -1
  406. package/dist/runtime/useAthenaStatewireRuntime.js +20 -6
  407. package/dist/runtime/useAthenaStatewireRuntime.js.map +1 -1
  408. package/dist/styles.css +1 -1
  409. package/dist/threads/api.d.ts +1 -1
  410. package/dist/threads/conversation-list-fetcher.d.ts +1 -1
  411. package/dist/threads/index-triggered-refresh.cjs +164 -0
  412. package/dist/threads/index-triggered-refresh.cjs.map +1 -0
  413. package/dist/threads/index-triggered-refresh.d.ts +70 -0
  414. package/dist/threads/index-triggered-refresh.js +164 -0
  415. package/dist/threads/index-triggered-refresh.js.map +1 -0
  416. package/dist/threads/offline-session-list.d.ts +1 -1
  417. package/dist/threads/pull-request-display.d.ts +1 -1
  418. package/dist/threads/session-list-model.d.ts +1 -1
  419. package/dist/threads/session-list-tab-share.cjs +150 -0
  420. package/dist/threads/session-list-tab-share.cjs.map +1 -0
  421. package/dist/threads/session-list-tab-share.d.ts +73 -0
  422. package/dist/threads/session-list-tab-share.js +150 -0
  423. package/dist/threads/session-list-tab-share.js.map +1 -0
  424. package/dist/threads/session-row-parts.d.ts +1 -1
  425. package/dist/threads/sessions-query.d.ts +1 -1
  426. package/dist/threads/statewire-thread-list.cjs +42 -16
  427. package/dist/threads/statewire-thread-list.cjs.map +1 -1
  428. package/dist/threads/statewire-thread-list.d.ts +11 -2
  429. package/dist/threads/statewire-thread-list.js +43 -17
  430. package/dist/threads/statewire-thread-list.js.map +1 -1
  431. package/dist/threads/thread-prefetcher.d.ts +1 -1
  432. package/dist/threads/use-athena-session-attention.d.ts +1 -1
  433. package/dist/threads/use-athena-sessions.cjs +32 -22
  434. package/dist/threads/use-athena-sessions.cjs.map +1 -1
  435. package/dist/threads/use-athena-sessions.js +33 -23
  436. package/dist/threads/use-athena-sessions.js.map +1 -1
  437. package/dist/threads/use-rest-conversation-history.d.ts +1 -1
  438. package/dist/threads/use-statewire-conversation-history.d.ts +5 -5
  439. package/dist/tiptap-markdown-table/src/markdown-table-serializer.d.ts +56 -0
  440. package/dist/tools/NestedPtcMessages.cjs +14 -9
  441. package/dist/tools/NestedPtcMessages.cjs.map +1 -1
  442. package/dist/tools/NestedPtcMessages.d.ts +9 -0
  443. package/dist/tools/NestedPtcMessages.js +6 -1
  444. package/dist/tools/NestedPtcMessages.js.map +1 -1
  445. package/dist/tools/index.d.ts +1 -1
  446. package/dist/tools/primitives.d.ts +1 -1
  447. package/dist/tools/subagent-task-tool-ui.cjs +494 -0
  448. package/dist/tools/subagent-task-tool-ui.cjs.map +1 -0
  449. package/dist/tools/subagent-task-tool-ui.d.ts +109 -0
  450. package/dist/tools/subagent-task-tool-ui.js +494 -0
  451. package/dist/tools/subagent-task-tool-ui.js.map +1 -0
  452. package/dist/tools/tool-fallback.d.ts +1 -1
  453. package/dist/tools/tool-icons.d.ts +1 -1
  454. package/dist/tools/tool-summary.d.ts +1 -1
  455. package/dist/tools/tool-uis.cjs +4 -0
  456. package/dist/tools/tool-uis.cjs.map +1 -1
  457. package/dist/tools/tool-uis.js +4 -0
  458. package/dist/tools/tool-uis.js.map +1 -1
  459. package/dist/voice/chat.cjs +6 -0
  460. package/dist/voice/chat.cjs.map +1 -0
  461. package/dist/voice/chat.d.ts +2 -0
  462. package/dist/voice/chat.js +6 -0
  463. package/dist/voice/chat.js.map +1 -0
  464. package/dist/voice/livekit-join.cjs +119 -0
  465. package/dist/voice/livekit-join.cjs.map +1 -0
  466. package/dist/voice/livekit-join.d.ts +8 -0
  467. package/dist/voice/livekit-join.js +119 -0
  468. package/dist/voice/livekit-join.js.map +1 -0
  469. package/dist/voice/livekit.cjs +32 -0
  470. package/dist/voice/livekit.cjs.map +1 -0
  471. package/dist/voice/livekit.d.ts +80 -0
  472. package/dist/voice/livekit.js +32 -0
  473. package/dist/voice/livekit.js.map +1 -0
  474. package/dist/voice/use-chat-voice-enabled.cjs +43 -0
  475. package/dist/voice/use-chat-voice-enabled.cjs.map +1 -0
  476. package/dist/voice/use-chat-voice-enabled.d.ts +9 -0
  477. package/dist/voice/use-chat-voice-enabled.js +43 -0
  478. package/dist/voice/use-chat-voice-enabled.js.map +1 -0
  479. package/package.json +22 -16
@@ -1 +1 @@
1
- {"version":3,"file":"activity-timeline.cjs","sources":["../../../src/chat/super-grouping/activity-timeline.ts"],"sourcesContent":["/**\n * The assistant turn's activity timeline — the one derivation of \"what did\n * this turn do, and how did each step end\" behind the collapsed view\n * (previously called the conversational view) on every surface: the SDK's\n * `AthenaChat`, Olympus's Spaces chat, and the Chrome extension. Pure\n * functions over assistant-ui message parts; `SuperGroupingCard` renders them.\n *\n * Step states come from the shared classifier (`classifyToolResult`) plus the\n * approval outcomes a part carries (`approval`, `interrupt`, a rejection\n * result), so a call that reads as failed, paused, or rejected on one surface\n * cannot read as a green check on another. Copy comes from the shared tool\n * summary registry (`summarizeToolCall`), itself built on the display\n * registry.\n */\nimport type {\n MessageStatus,\n ThreadAssistantMessagePart,\n ToolCallMessagePartStatus,\n} from '@assistant-ui/react';\nimport {\n classifyToolResult,\n isSpokenTurnTextPart,\n readRejectedToolResult,\n type ToolStatusLabelState,\n} from '@athenaintel/agent-runtime';\nimport { summarizeToolCall, type ToolCallSummary } from '../../tools/tool-summary';\nimport type { GroupablePart, GroupingFunction } from './grouping-function';\n\nexport type ActivityToolState = ToolStatusLabelState;\n\nexport type ActivityItem =\n | {\n kind: 'reasoning';\n id?: string;\n /** Position of the part in the message's content. */\n partIndex?: number;\n text: string;\n state: 'running' | 'complete';\n }\n | {\n kind: 'tool';\n id?: string;\n /** Position of the part in the message's content. */\n partIndex?: number;\n toolName: string;\n args?: ToolCallPart['args'];\n /** The tool's real result; absent while it runs or holds only the streaming placeholder. */\n result?: unknown;\n state: ActivityToolState;\n };\n\n/** The turn as a whole: still working, parked on the person, ended in error, or done. */\nexport type ActivityPhase = 'running' | 'waiting' | 'complete' | 'error';\n\ntype ToolCallPart = Extract<ThreadAssistantMessagePart, { type: 'tool-call' }>;\n\nexport interface ActivityTimelineOptions {\n /**\n * Tools whose unresolved call means the turn is waiting on the person even\n * without an interrupt or approval on the part (the Chrome extension's\n * device plan approval, which the tool UI itself collects).\n */\n waitingTools?: ReadonlySet<string>;\n /**\n * Tools whose result is an application payload relayed verbatim (the Chrome\n * extension's page JavaScript), so a `success: false` flag counts only with\n * an error detail — see `classifyToolResult`'s `passThroughPayload`.\n */\n passThroughTools?: ReadonlySet<string>;\n}\n\nconst NO_TOOLS: ReadonlySet<string> = new Set();\n\n/**\n * Whether a tool-call part still holds the backend's streaming placeholder\n * result rather than the tool's real output. Long-running tools (task\n * subagents, studio and Python execution, deep research) append a ToolMessage\n * the moment they start so their card can fill in live; it carries\n * `additional_kwargs.streaming`, which the runtime converter lifts into\n * `artifact._tool_message_metadata`. The real ToolMessage that replaces it\n * has no such flag, so a defined `result` alone does not mean the tool is done.\n */\nexport function isStreamingToolPlaceholder(part: Pick<ToolCallPart, 'artifact'>): boolean {\n const artifact: unknown = part.artifact;\n if (typeof artifact !== 'object' || artifact === null) return false;\n const metadata: unknown = (artifact as { _tool_message_metadata?: unknown })\n ._tool_message_metadata;\n if (typeof metadata !== 'object' || metadata === null) return false;\n return (metadata as { streaming?: unknown }).streaming === true;\n}\n\n/** The tool's real result: undefined while it has none or only the streaming placeholder. */\nfunction finalResult(part: ToolCallPart): unknown {\n return isStreamingToolPlaceholder(part) ? undefined : part.result;\n}\n\nfunction toolCallStatus(\n part: ToolCallPart,\n messageStatus: MessageStatus | undefined,\n): ToolCallMessagePartStatus | undefined {\n if (finalResult(part) !== undefined) return { type: 'complete' };\n if (messageStatus?.type === 'incomplete') {\n return {\n type: 'incomplete',\n reason: messageStatus.reason === 'tool-calls' ? 'other' : messageStatus.reason,\n error: messageStatus.error,\n };\n }\n if (messageStatus?.type === 'complete') return { type: 'complete' };\n if (messageStatus?.type === 'requires-action') {\n return { type: 'requires-action', reason: messageStatus.reason };\n }\n if (messageStatus?.type === 'running') return { type: 'running' };\n return undefined;\n}\n\n/** How one tool call ended (or is going), reading the approval fields before the result. */\nexport function getActivityToolState(\n part: ToolCallPart,\n messageStatus: MessageStatus | undefined,\n { waitingTools = NO_TOOLS, passThroughTools = NO_TOOLS }: ActivityTimelineOptions = {},\n): ActivityToolState {\n if (part.approval?.approved === false || readRejectedToolResult(part.result) !== null) {\n return 'rejected';\n }\n if (part.approval?.resolution === 'cancelled' || part.approval?.resolution === 'expired') {\n return 'cancelled';\n }\n const result = finalResult(part);\n const unresolved = result === undefined;\n const messageIsActive =\n messageStatus === undefined ||\n messageStatus.type === 'running' ||\n messageStatus.type === 'requires-action';\n if (\n unresolved &&\n (part.interrupt?.type === 'human' ||\n (part.approval !== undefined &&\n part.approval.approved === undefined &&\n part.approval.resolution === undefined) ||\n (waitingTools.has(part.toolName) && messageIsActive))\n ) {\n return 'waiting';\n }\n\n const classification = classifyToolResult({\n status: toolCallStatus(part, messageStatus),\n result,\n isError: part.isError,\n passThroughPayload: passThroughTools.has(part.toolName),\n });\n if (classification.state === 'requires-action') return 'waiting';\n return classification.state;\n}\n\n/**\n * The compact reasoning/tool timeline in the order the parts streamed.\n *\n * A reasoning part is still streaming only while it is the final part of a\n * running message — once any later part appears, the thought has settled.\n * Settled reasoning parts with no text are dropped so the list never shows an\n * empty thinking row.\n */\nexport function buildActivityTimeline(\n content: readonly ThreadAssistantMessagePart[] | undefined,\n messageStatus: MessageStatus | undefined,\n options: ActivityTimelineOptions = {},\n): ActivityItem[] {\n if (!content?.length) return [];\n\n const lastPartIndex = content.length - 1;\n const timeline: ActivityItem[] = [];\n for (let index = 0; index < content.length; index += 1) {\n const part = content[index];\n if (part.type === 'tool-call') {\n const result = finalResult(part);\n timeline.push({\n kind: 'tool',\n id: part.toolCallId,\n partIndex: index,\n args: part.args,\n ...(result !== undefined ? { result } : {}),\n toolName: part.toolName,\n state: getActivityToolState(part, messageStatus, options),\n });\n continue;\n }\n if (part.type !== 'reasoning') continue;\n\n const text = typeof part.text === 'string' ? part.text : '';\n const stillStreaming = messageStatus?.type === 'running' && index === lastPartIndex;\n if (!stillStreaming && text.trim() === '') continue;\n timeline.push({\n kind: 'reasoning',\n id: `reasoning-${index}`,\n partIndex: index,\n text,\n state: stillStreaming ? 'running' : 'complete',\n });\n }\n return timeline;\n}\n\n/** Number of tool calls in the timeline. */\nexport function countActivityTools(timeline: readonly ActivityItem[]): number {\n return timeline.reduce((count, item) => (item.kind === 'tool' ? count + 1 : count), 0);\n}\n\n/**\n * The turn's phase. Waiting on the person wins over everything — a\n * `requires-action` status, a waiting tool, or a host's own `waitingForInput`\n * assertion (no in-repo host passes one) — then the message's own status.\n */\nexport function resolveActivityPhase(\n status: MessageStatus | undefined,\n timeline: readonly ActivityItem[],\n { waitingForInput = false }: { waitingForInput?: boolean } = {},\n): ActivityPhase {\n if (\n waitingForInput ||\n status?.type === 'requires-action' ||\n timeline.some((item) => item.kind === 'tool' && item.state === 'waiting')\n ) {\n return 'waiting';\n }\n if (status?.type === 'running') return 'running';\n if (status?.type === 'incomplete') return 'error';\n return 'complete';\n}\n\n/**\n * A settled thought's row: the heading a reasoning summary opens with\n * (\"**Checking the workstation**\" → \"Checking the workstation\"), else the\n * generic wording. The thought itself stays in the run's details.\n */\nexport function getReasoningLabel(text: string, state: 'running' | 'complete'): string {\n if (state === 'running') return 'Thinking';\n const heading = /^\\s*\\*\\*([^*\\n]{3,80}?)\\*\\*/.exec(text)?.[1]?.trim();\n return heading ? heading.replace(/[.:]+$/, '') : 'Thought through the next step';\n}\n\n/**\n * The status-row copy for one step: the call's own summary from the shared\n * summary registry (`summarizeToolCall`: \"Ran git status\", \"Read config.ts\").\n * `resolveToolDisplayName` lets a host with a richer tool catalog name tools\n * neither registry has an entry for; `assetTitles` names the machine or\n * document a call targeted by id when an earlier result in the turn did.\n */\nexport function getActivityItemLabel(\n item: ActivityItem,\n resolveToolDisplayName?: (toolName: string) => string | undefined,\n assetTitles?: ReadonlyMap<string, string>,\n): string {\n if (item.kind === 'reasoning') return getReasoningLabel(item.text, item.state);\n return summarizeActivityTool(item, resolveToolDisplayName, assetTitles).label;\n}\n\n/** The summary of one tool step (see {@link getActivityItemLabel}). */\nexport function summarizeActivityTool(\n item: Extract<ActivityItem, { kind: 'tool' }>,\n resolveToolDisplayName?: (toolName: string) => string | undefined,\n assetTitles?: ReadonlyMap<string, string>,\n): ToolCallSummary {\n return summarizeToolCall({\n toolName: item.toolName,\n args: item.args,\n result: item.result,\n status: item.state,\n ...(assetTitles ? { assetTitles } : {}),\n ...(resolveToolDisplayName ? { displayName: resolveToolDisplayName(item.toolName) } : {}),\n });\n}\n\n/**\n * The collapsed-card summary of a finished turn. \"Completed with issues\" means\n * the turn ended on a problem: a call the person refused, or a failed call\n * that no later call completed after. A failed command the agent then got past\n * (a search that found nothing, a retry that worked) is ordinary work, so a\n * long turn that recovered from it reads as the tools it used.\n */\nexport function getActivitySummary(timeline: readonly ActivityItem[]): string {\n const toolCount = countActivityTools(timeline);\n const tools = timeline.filter((item) => item.kind === 'tool');\n const lastFailure = tools.findLastIndex((item) => item.state === 'error');\n const endedOnFailure =\n lastFailure >= 0 && !tools.slice(lastFailure + 1).some((item) => item.state === 'complete');\n const hasIssue = endedOnFailure || tools.some((item) => item.state === 'rejected');\n if (hasIssue) return 'Completed with issues';\n if (timeline.some((item) => item.kind === 'tool' && item.state === 'cancelled')) {\n return 'Action cancelled';\n }\n if (timeline.some((item) => item.kind === 'tool' && item.state === 'paused')) {\n return 'Paused during tool use';\n }\n if (toolCount > 0) return `Used ${toolCount} ${toolCount === 1 ? 'tool' : 'tools'}`;\n return 'Reasoning complete';\n}\n\n/** The part shape the final-text read needs; any message role's parts satisfy it. */\nexport type FinalTextPart = { readonly type: string; readonly text?: string };\n\n/**\n * Whether a text part shows below the card instead of in the details panel:\n * it comes after the final tool call, or it holds a spoken voice turn's words\n * (a live turn heard during a delegated run lands between the run's tool\n * calls, see `isSpokenTurnTextPart`; it is the conversation, not narration).\n */\nfunction isAnswerTextPart(\n part: { readonly type: string } | undefined,\n index: number,\n lastToolIndex: number,\n): boolean {\n return part?.type === 'text' && (index > lastToolIndex || isSpokenTurnTextPart(part));\n}\n\n/**\n * The visible answer of a grouped turn: the text after the final tool call\n * (all of it when the turn never called a tool), plus the words of every\n * spoken voice turn in the message, in order. Other intermediate text (before\n * or between tool calls) stays available in the details panel.\n */\nexport function getFinalText(content: readonly FinalTextPart[] | undefined): string | null {\n const parts = getFinalTextParts(content);\n return parts.length > 0 ? parts.map((part) => part.text).join('\\n\\n') : null;\n}\n\n/** One text part of the visible answer, with its index in the message content. */\nexport interface FinalTextSegment {\n index: number;\n text: string;\n}\n\n/**\n * The parts `getFinalText` joins, each kept separate with its content index.\n * A spoken turn and the run's own reply can stream at the same time, so the\n * earlier part may grow while a later one exists: rendered as one joined\n * string, that text changes in the middle rather than at its end, and the\n * streaming reveal restarts from an empty bubble on every word.\n */\nexport function getFinalTextParts(content: readonly FinalTextPart[] | undefined): FinalTextSegment[] {\n if (!content?.length) return [];\n\n const lastToolIndex = content.findLastIndex((part) => part?.type === 'tool-call');\n const parts: FinalTextSegment[] = [];\n content.forEach((part, index) => {\n if (part.text && isAnswerTextPart(part, index, lastToolIndex)) parts.push({ index, text: part.text });\n });\n return parts;\n}\n\n/**\n * Keep the answer out of the details panel: it renders below the card\n * (`SuperGroupingFinalText`), so the details grouping drops every text part\n * `getFinalText` shows and any group that becomes empty.\n */\nexport function excludeFinalTextFromGroups(grouping: GroupingFunction): GroupingFunction {\n return (parts) => {\n const lastToolIndex = parts.findLastIndex((part) => part?.type === 'tool-call');\n return grouping(parts)\n .map((group) => ({\n ...group,\n indices: group.indices.filter((index) => !isAnswerTextPart(parts[index], index, lastToolIndex)),\n }))\n .filter((group) => group.indices.length > 0);\n };\n}\n\n/**\n * Drop the parts `exclude` matches from every group, and any group left\n * empty: `SuperGroupingCard` renders inline tool calls outside the details,\n * so they must not render a second time inside it.\n */\nexport function excludePartsFromGroups(\n grouping: GroupingFunction,\n exclude: (part: GroupablePart) => boolean,\n): GroupingFunction {\n return (parts) =>\n grouping(parts)\n .map((group) => ({\n ...group,\n indices: group.indices.filter((index) => {\n const part = parts[index];\n return part === undefined || !exclude(part);\n }),\n }))\n .filter((group) => group.indices.length > 0);\n}\n"],"names":["readRejectedToolResult","classifyToolResult","summarizeToolCall","isSpokenTurnTextPart"],"mappings":"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"}
1
+ {"version":3,"file":"activity-timeline.cjs","sources":["../../../src/chat/super-grouping/activity-timeline.ts"],"sourcesContent":["/**\n * The assistant turn's activity timeline — the one derivation of \"what did\n * this turn do, and how did each step end\" behind the collapsed view\n * (previously called the conversational view) on every surface: the SDK's\n * `AthenaChat`, Olympus's Spaces chat, and the Chrome extension. Pure\n * functions over assistant-ui message parts; `SuperGroupingCard` renders them.\n *\n * Step states come from the shared classifier (`classifyToolResult`) plus the\n * approval outcomes a part carries (`approval`, `interrupt`, a rejection\n * result), so a call that reads as failed, paused, or rejected on one surface\n * cannot read as a green check on another. Copy comes from the shared tool\n * summary registry (`summarizeToolCall`), itself built on the display\n * registry.\n */\nimport type {\n MessageStatus,\n ThreadAssistantMessagePart,\n ToolCallMessagePartStatus,\n} from '@assistant-ui/react';\nimport {\n classifyToolResult,\n isRunningToolPlaceholderArtifact,\n isSpokenTurnTextPart,\n readRejectedToolResult,\n type ToolStatusLabelState,\n} from '@athenaintel/agent-runtime';\nimport { summarizeToolCall, type ToolCallSummary } from '../../tools/tool-summary';\nimport type { GroupablePart, GroupingFunction } from './grouping-function';\n\nexport type ActivityToolState = ToolStatusLabelState;\n\nexport type ActivityItem =\n | {\n kind: 'reasoning';\n id?: string;\n /** Position of the part in the message's content. */\n partIndex?: number;\n text: string;\n state: 'running' | 'complete';\n }\n | {\n kind: 'tool';\n id?: string;\n /** Position of the part in the message's content. */\n partIndex?: number;\n toolName: string;\n args?: ToolCallPart['args'];\n /** The tool's real result; absent while it runs or holds only the streaming placeholder. */\n result?: unknown;\n state: ActivityToolState;\n };\n\n/** The turn as a whole: still working, parked on the person, ended in error, or done. */\nexport type ActivityPhase = 'running' | 'waiting' | 'complete' | 'error';\n\ntype ToolCallPart = Extract<ThreadAssistantMessagePart, { type: 'tool-call' }>;\n\nexport interface ActivityTimelineOptions {\n /**\n * Tools whose unresolved call means the turn is waiting on the person even\n * without an interrupt or approval on the part (the Chrome extension's\n * device plan approval, which the tool UI itself collects).\n */\n waitingTools?: ReadonlySet<string>;\n /**\n * Calls the run is parked on, by tool-call id, as the host reads them off\n * its pending approval: a gated call, or (in Olympus) a `task` call whose\n * subagent waits on an approval. Any of them still without its real result\n * reads as waiting.\n */\n waitingToolCallIds?: ReadonlySet<string>;\n /**\n * Tools whose result is an application payload relayed verbatim (the Chrome\n * extension's page JavaScript), so a `success: false` flag counts only with\n * an error detail — see `classifyToolResult`'s `passThroughPayload`.\n */\n passThroughTools?: ReadonlySet<string>;\n}\n\nconst NO_TOOLS: ReadonlySet<string> = new Set();\nconst NO_TOOL_CALLS: ReadonlySet<string> = new Set();\n\n/**\n * Whether a tool-call part still holds the backend's running-tool placeholder\n * result rather than the tool's real output. Long-running tools (task\n * subagents, studio and Python execution, deep research) append a ToolMessage\n * the moment they start so their card can fill in live; its marker reaches the\n * part's artifact (`isRunningToolPlaceholderArtifact`). The real ToolMessage\n * that replaces it has no such marker, so a defined `result` alone does not\n * mean the tool is done.\n */\nexport function isStreamingToolPlaceholder(part: Pick<ToolCallPart, 'artifact'>): boolean {\n return isRunningToolPlaceholderArtifact(part.artifact);\n}\n\n/** The tool's real result: undefined while it has none or only the streaming placeholder. */\nfunction finalResult(part: ToolCallPart): unknown {\n return isStreamingToolPlaceholder(part) ? undefined : part.result;\n}\n\nfunction toolCallStatus(\n part: ToolCallPart,\n messageStatus: MessageStatus | undefined,\n): ToolCallMessagePartStatus | undefined {\n if (finalResult(part) !== undefined) return { type: 'complete' };\n if (messageStatus?.type === 'incomplete') {\n return {\n type: 'incomplete',\n reason: messageStatus.reason === 'tool-calls' ? 'other' : messageStatus.reason,\n error: messageStatus.error,\n };\n }\n if (messageStatus?.type === 'complete') {\n // The placeholder is the backend's word that the call is still in flight.\n // A turn reads `complete` whenever nothing streams (a run parked on an\n // approval inside a subagent, the gap before a drained run resumes), and\n // assistant-ui counts the placeholder as the call's result when it settles\n // that status, so the turn's status cannot finish the call.\n return isStreamingToolPlaceholder(part) ? { type: 'running' } : { type: 'complete' };\n }\n if (messageStatus?.type === 'requires-action') {\n return { type: 'requires-action', reason: messageStatus.reason };\n }\n if (messageStatus?.type === 'running') return { type: 'running' };\n return undefined;\n}\n\n/** How one tool call ended (or is going), reading the approval fields before the result. */\nexport function getActivityToolState(\n part: ToolCallPart,\n messageStatus: MessageStatus | undefined,\n {\n waitingTools = NO_TOOLS,\n waitingToolCallIds = NO_TOOL_CALLS,\n passThroughTools = NO_TOOLS,\n }: ActivityTimelineOptions = {},\n): ActivityToolState {\n if (part.approval?.approved === false || readRejectedToolResult(part.result) !== null) {\n return 'rejected';\n }\n if (part.approval?.resolution === 'cancelled' || part.approval?.resolution === 'expired') {\n return 'cancelled';\n }\n const result = finalResult(part);\n const unresolved = result === undefined;\n const messageIsActive =\n messageStatus === undefined ||\n messageStatus.type === 'running' ||\n messageStatus.type === 'requires-action';\n if (\n unresolved &&\n (part.interrupt?.type === 'human' ||\n (part.approval !== undefined &&\n part.approval.approved === undefined &&\n part.approval.resolution === undefined) ||\n waitingToolCallIds.has(part.toolCallId) ||\n (waitingTools.has(part.toolName) && messageIsActive))\n ) {\n return 'waiting';\n }\n\n const classification = classifyToolResult({\n status: toolCallStatus(part, messageStatus),\n result,\n isError: part.isError,\n passThroughPayload: passThroughTools.has(part.toolName),\n });\n if (classification.state === 'requires-action') return 'waiting';\n return classification.state;\n}\n\n/**\n * The compact reasoning/tool timeline in the order the parts streamed.\n *\n * A reasoning part is still streaming only while it is the final part of a\n * running message — once any later part appears, the thought has settled.\n * Settled reasoning parts with no text are dropped so the list never shows an\n * empty thinking row.\n */\nexport function buildActivityTimeline(\n content: readonly ThreadAssistantMessagePart[] | undefined,\n messageStatus: MessageStatus | undefined,\n options: ActivityTimelineOptions = {},\n): ActivityItem[] {\n if (!content?.length) return [];\n\n const lastPartIndex = content.length - 1;\n const timeline: ActivityItem[] = [];\n for (let index = 0; index < content.length; index += 1) {\n const part = content[index];\n if (part.type === 'tool-call') {\n const result = finalResult(part);\n timeline.push({\n kind: 'tool',\n id: part.toolCallId,\n partIndex: index,\n args: part.args,\n ...(result !== undefined ? { result } : {}),\n toolName: part.toolName,\n state: getActivityToolState(part, messageStatus, options),\n });\n continue;\n }\n if (part.type !== 'reasoning') continue;\n\n const text = typeof part.text === 'string' ? part.text : '';\n const stillStreaming = messageStatus?.type === 'running' && index === lastPartIndex;\n if (!stillStreaming && text.trim() === '') continue;\n timeline.push({\n kind: 'reasoning',\n id: `reasoning-${index}`,\n partIndex: index,\n text,\n state: stillStreaming ? 'running' : 'complete',\n });\n }\n return timeline;\n}\n\n/** Number of tool calls in the timeline. */\nexport function countActivityTools(timeline: readonly ActivityItem[]): number {\n return timeline.reduce((count, item) => (item.kind === 'tool' ? count + 1 : count), 0);\n}\n\n/**\n * The turn's phase. Waiting on the person wins over everything — a\n * `requires-action` status, a waiting tool, or a host's own `waitingForInput`\n * assertion (no in-repo host passes one) — then the message's own status. A\n * complete turn with a step still running is running: only a step holding the\n * backend's running placeholder reads so once nothing streams (a run parked on\n * an approval inside a subagent, the gap before a drained run resumes).\n */\nexport function resolveActivityPhase(\n status: MessageStatus | undefined,\n timeline: readonly ActivityItem[],\n { waitingForInput = false }: { waitingForInput?: boolean } = {},\n): ActivityPhase {\n if (\n waitingForInput ||\n status?.type === 'requires-action' ||\n timeline.some((item) => item.kind === 'tool' && item.state === 'waiting')\n ) {\n return 'waiting';\n }\n if (status?.type === 'running') return 'running';\n if (status?.type === 'incomplete') return 'error';\n if (\n status?.type === 'complete' &&\n timeline.some((item) => item.kind === 'tool' && item.state === 'running')\n ) {\n return 'running';\n }\n return 'complete';\n}\n\n/**\n * A settled thought's row: the heading a reasoning summary opens with\n * (\"**Checking the workstation**\" → \"Checking the workstation\"), else the\n * generic wording. The thought itself stays in the run's details.\n */\nexport function getReasoningLabel(text: string, state: 'running' | 'complete'): string {\n if (state === 'running') return 'Thinking';\n const heading = /^\\s*\\*\\*([^*\\n]{3,80}?)\\*\\*/.exec(text)?.[1]?.trim();\n return heading ? heading.replace(/[.:]+$/, '') : 'Thought through the next step';\n}\n\n/**\n * The status-row copy for one step: the call's own summary from the shared\n * summary registry (`summarizeToolCall`: \"Ran git status\", \"Read config.ts\").\n * `resolveToolDisplayName` lets a host with a richer tool catalog name tools\n * neither registry has an entry for; `assetTitles` names the machine or\n * document a call targeted by id when an earlier result in the turn did.\n */\nexport function getActivityItemLabel(\n item: ActivityItem,\n resolveToolDisplayName?: (toolName: string) => string | undefined,\n assetTitles?: ReadonlyMap<string, string>,\n): string {\n if (item.kind === 'reasoning') return getReasoningLabel(item.text, item.state);\n return summarizeActivityTool(item, resolveToolDisplayName, assetTitles).label;\n}\n\n/** The summary of one tool step (see {@link getActivityItemLabel}). */\nexport function summarizeActivityTool(\n item: Extract<ActivityItem, { kind: 'tool' }>,\n resolveToolDisplayName?: (toolName: string) => string | undefined,\n assetTitles?: ReadonlyMap<string, string>,\n): ToolCallSummary {\n return summarizeToolCall({\n toolName: item.toolName,\n args: item.args,\n result: item.result,\n status: item.state,\n ...(assetTitles ? { assetTitles } : {}),\n ...(resolveToolDisplayName ? { displayName: resolveToolDisplayName(item.toolName) } : {}),\n });\n}\n\n/**\n * The collapsed-card summary of a finished turn. \"Completed with issues\" means\n * the turn ended on a problem: a call the person refused, or a failed call\n * that no later call completed after. A failed command the agent then got past\n * (a search that found nothing, a retry that worked) is ordinary work, so a\n * long turn that recovered from it reads as the tools it used.\n */\nexport function getActivitySummary(timeline: readonly ActivityItem[]): string {\n const toolCount = countActivityTools(timeline);\n const tools = timeline.filter((item) => item.kind === 'tool');\n const lastFailure = tools.findLastIndex((item) => item.state === 'error');\n const endedOnFailure =\n lastFailure >= 0 && !tools.slice(lastFailure + 1).some((item) => item.state === 'complete');\n const hasIssue = endedOnFailure || tools.some((item) => item.state === 'rejected');\n if (hasIssue) return 'Completed with issues';\n if (timeline.some((item) => item.kind === 'tool' && item.state === 'cancelled')) {\n return 'Action cancelled';\n }\n if (timeline.some((item) => item.kind === 'tool' && item.state === 'paused')) {\n return 'Paused during tool use';\n }\n if (toolCount > 0) return `Used ${toolCount} ${toolCount === 1 ? 'tool' : 'tools'}`;\n return 'Reasoning complete';\n}\n\n/** The part shape the final-text read needs; any message role's parts satisfy it. */\nexport type FinalTextPart = { readonly type: string; readonly text?: string };\n\n/**\n * Whether a text part shows below the card instead of in the details panel:\n * it comes after the final tool call, or it holds a spoken voice turn's words\n * (a live turn heard during a delegated run lands between the run's tool\n * calls, see `isSpokenTurnTextPart`; it is the conversation, not narration).\n */\nfunction isAnswerTextPart(\n part: { readonly type: string } | undefined,\n index: number,\n lastToolIndex: number,\n): boolean {\n return part?.type === 'text' && (index > lastToolIndex || isSpokenTurnTextPart(part));\n}\n\n/**\n * The visible answer of a grouped turn: the text after the final tool call\n * (all of it when the turn never called a tool), plus the words of every\n * spoken voice turn in the message, in order. Other intermediate text (before\n * or between tool calls) stays available in the details panel.\n */\nexport function getFinalText(content: readonly FinalTextPart[] | undefined): string | null {\n const parts = getFinalTextParts(content);\n return parts.length > 0 ? parts.map((part) => part.text).join('\\n\\n') : null;\n}\n\n/** One text part of the visible answer, with its index in the message content. */\nexport interface FinalTextSegment {\n index: number;\n text: string;\n}\n\n/**\n * The parts `getFinalText` joins, each kept separate with its content index.\n * A spoken turn and the run's own reply can stream at the same time, so the\n * earlier part may grow while a later one exists: rendered as one joined\n * string, that text changes in the middle rather than at its end, and the\n * streaming reveal restarts from an empty bubble on every word.\n */\nexport function getFinalTextParts(content: readonly FinalTextPart[] | undefined): FinalTextSegment[] {\n if (!content?.length) return [];\n\n const lastToolIndex = content.findLastIndex((part) => part?.type === 'tool-call');\n const parts: FinalTextSegment[] = [];\n content.forEach((part, index) => {\n if (part.text && isAnswerTextPart(part, index, lastToolIndex)) parts.push({ index, text: part.text });\n });\n return parts;\n}\n\n/**\n * Keep the answer out of the details panel: it renders below the card\n * (`SuperGroupingFinalText`), so the details grouping drops every text part\n * `getFinalText` shows and any group that becomes empty.\n */\nexport function excludeFinalTextFromGroups(grouping: GroupingFunction): GroupingFunction {\n return (parts) => {\n const lastToolIndex = parts.findLastIndex((part) => part?.type === 'tool-call');\n return grouping(parts)\n .map((group) => ({\n ...group,\n indices: group.indices.filter((index) => !isAnswerTextPart(parts[index], index, lastToolIndex)),\n }))\n .filter((group) => group.indices.length > 0);\n };\n}\n\n/**\n * Drop the parts `exclude` matches from every group, and any group left\n * empty: `SuperGroupingCard` renders inline tool calls outside the details,\n * so they must not render a second time inside it.\n */\nexport function excludePartsFromGroups(\n grouping: GroupingFunction,\n exclude: (part: GroupablePart) => boolean,\n): GroupingFunction {\n return (parts) =>\n grouping(parts)\n .map((group) => ({\n ...group,\n indices: group.indices.filter((index) => {\n const part = parts[index];\n return part === undefined || !exclude(part);\n }),\n }))\n .filter((group) => group.indices.length > 0);\n}\n"],"names":["isRunningToolPlaceholderArtifact","readRejectedToolResult","classifyToolResult","summarizeToolCall","isSpokenTurnTextPart"],"mappings":"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"}
@@ -13,7 +13,7 @@
13
13
  * registry.
14
14
  */
15
15
  import type { MessageStatus, ThreadAssistantMessagePart } from '@assistant-ui/react';
16
- import { type ToolStatusLabelState } from '@athenaintel/agent-runtime';
16
+ import { type ToolStatusLabelState } from '../../agent-runtime/src/index';
17
17
  import { type ToolCallSummary } from '../../tools/tool-summary';
18
18
  import type { GroupablePart, GroupingFunction } from './grouping-function';
19
19
  export type ActivityToolState = ToolStatusLabelState;
@@ -47,6 +47,13 @@ export interface ActivityTimelineOptions {
47
47
  * device plan approval, which the tool UI itself collects).
48
48
  */
49
49
  waitingTools?: ReadonlySet<string>;
50
+ /**
51
+ * Calls the run is parked on, by tool-call id, as the host reads them off
52
+ * its pending approval: a gated call, or (in Olympus) a `task` call whose
53
+ * subagent waits on an approval. Any of them still without its real result
54
+ * reads as waiting.
55
+ */
56
+ waitingToolCallIds?: ReadonlySet<string>;
50
57
  /**
51
58
  * Tools whose result is an application payload relayed verbatim (the Chrome
52
59
  * extension's page JavaScript), so a `success: false` flag counts only with
@@ -55,17 +62,17 @@ export interface ActivityTimelineOptions {
55
62
  passThroughTools?: ReadonlySet<string>;
56
63
  }
57
64
  /**
58
- * Whether a tool-call part still holds the backend's streaming placeholder
65
+ * Whether a tool-call part still holds the backend's running-tool placeholder
59
66
  * result rather than the tool's real output. Long-running tools (task
60
67
  * subagents, studio and Python execution, deep research) append a ToolMessage
61
- * the moment they start so their card can fill in live; it carries
62
- * `additional_kwargs.streaming`, which the runtime converter lifts into
63
- * `artifact._tool_message_metadata`. The real ToolMessage that replaces it
64
- * has no such flag, so a defined `result` alone does not mean the tool is done.
68
+ * the moment they start so their card can fill in live; its marker reaches the
69
+ * part's artifact (`isRunningToolPlaceholderArtifact`). The real ToolMessage
70
+ * that replaces it has no such marker, so a defined `result` alone does not
71
+ * mean the tool is done.
65
72
  */
66
73
  export declare function isStreamingToolPlaceholder(part: Pick<ToolCallPart, 'artifact'>): boolean;
67
74
  /** How one tool call ended (or is going), reading the approval fields before the result. */
68
- export declare function getActivityToolState(part: ToolCallPart, messageStatus: MessageStatus | undefined, { waitingTools, passThroughTools }?: ActivityTimelineOptions): ActivityToolState;
75
+ export declare function getActivityToolState(part: ToolCallPart, messageStatus: MessageStatus | undefined, { waitingTools, waitingToolCallIds, passThroughTools, }?: ActivityTimelineOptions): ActivityToolState;
69
76
  /**
70
77
  * The compact reasoning/tool timeline in the order the parts streamed.
71
78
  *
@@ -80,7 +87,10 @@ export declare function countActivityTools(timeline: readonly ActivityItem[]): n
80
87
  /**
81
88
  * The turn's phase. Waiting on the person wins over everything — a
82
89
  * `requires-action` status, a waiting tool, or a host's own `waitingForInput`
83
- * assertion (no in-repo host passes one) — then the message's own status.
90
+ * assertion (no in-repo host passes one) — then the message's own status. A
91
+ * complete turn with a step still running is running: only a step holding the
92
+ * backend's running placeholder reads so once nothing streams (a run parked on
93
+ * an approval inside a subagent, the gap before a drained run resumes).
84
94
  */
85
95
  export declare function resolveActivityPhase(status: MessageStatus | undefined, timeline: readonly ActivityItem[], { waitingForInput }?: {
86
96
  waitingForInput?: boolean;
@@ -1,13 +1,11 @@
1
1
  import { summarizeToolCall } from "../../tools/tool-summary.js";
2
2
  import { readRejectedToolResult, classifyToolResult } from "../../agent-runtime/src/tool-result.js";
3
+ import { isRunningToolPlaceholderArtifact } from "../../agent-runtime/src/running-tool-placeholder.js";
3
4
  import { isSpokenTurnTextPart } from "../../agent-runtime/src/voice-presentation.js";
4
5
  const NO_TOOLS = /* @__PURE__ */ new Set();
6
+ const NO_TOOL_CALLS = /* @__PURE__ */ new Set();
5
7
  function isStreamingToolPlaceholder(part) {
6
- const artifact = part.artifact;
7
- if (typeof artifact !== "object" || artifact === null) return false;
8
- const metadata = artifact._tool_message_metadata;
9
- if (typeof metadata !== "object" || metadata === null) return false;
10
- return metadata.streaming === true;
8
+ return isRunningToolPlaceholderArtifact(part.artifact);
11
9
  }
12
10
  function finalResult(part) {
13
11
  return isStreamingToolPlaceholder(part) ? void 0 : part.result;
@@ -21,14 +19,20 @@ function toolCallStatus(part, messageStatus) {
21
19
  error: messageStatus.error
22
20
  };
23
21
  }
24
- if ((messageStatus == null ? void 0 : messageStatus.type) === "complete") return { type: "complete" };
22
+ if ((messageStatus == null ? void 0 : messageStatus.type) === "complete") {
23
+ return isStreamingToolPlaceholder(part) ? { type: "running" } : { type: "complete" };
24
+ }
25
25
  if ((messageStatus == null ? void 0 : messageStatus.type) === "requires-action") {
26
26
  return { type: "requires-action", reason: messageStatus.reason };
27
27
  }
28
28
  if ((messageStatus == null ? void 0 : messageStatus.type) === "running") return { type: "running" };
29
29
  return void 0;
30
30
  }
31
- function getActivityToolState(part, messageStatus, { waitingTools = NO_TOOLS, passThroughTools = NO_TOOLS } = {}) {
31
+ function getActivityToolState(part, messageStatus, {
32
+ waitingTools = NO_TOOLS,
33
+ waitingToolCallIds = NO_TOOL_CALLS,
34
+ passThroughTools = NO_TOOLS
35
+ } = {}) {
32
36
  var _a, _b, _c, _d;
33
37
  if (((_a = part.approval) == null ? void 0 : _a.approved) === false || readRejectedToolResult(part.result) !== null) {
34
38
  return "rejected";
@@ -39,7 +43,7 @@ function getActivityToolState(part, messageStatus, { waitingTools = NO_TOOLS, pa
39
43
  const result = finalResult(part);
40
44
  const unresolved = result === void 0;
41
45
  const messageIsActive = messageStatus === void 0 || messageStatus.type === "running" || messageStatus.type === "requires-action";
42
- if (unresolved && (((_d = part.interrupt) == null ? void 0 : _d.type) === "human" || part.approval !== void 0 && part.approval.approved === void 0 && part.approval.resolution === void 0 || waitingTools.has(part.toolName) && messageIsActive)) {
46
+ if (unresolved && (((_d = part.interrupt) == null ? void 0 : _d.type) === "human" || part.approval !== void 0 && part.approval.approved === void 0 && part.approval.resolution === void 0 || waitingToolCallIds.has(part.toolCallId) || waitingTools.has(part.toolName) && messageIsActive)) {
43
47
  return "waiting";
44
48
  }
45
49
  const classification = classifyToolResult({
@@ -93,6 +97,9 @@ function resolveActivityPhase(status, timeline, { waitingForInput = false } = {}
93
97
  }
94
98
  if ((status == null ? void 0 : status.type) === "running") return "running";
95
99
  if ((status == null ? void 0 : status.type) === "incomplete") return "error";
100
+ if ((status == null ? void 0 : status.type) === "complete" && timeline.some((item) => item.kind === "tool" && item.state === "running")) {
101
+ return "running";
102
+ }
96
103
  return "complete";
97
104
  }
98
105
  function getReasoningLabel(text, state) {
@@ -1 +1 @@
1
- {"version":3,"file":"activity-timeline.js","sources":["../../../src/chat/super-grouping/activity-timeline.ts"],"sourcesContent":["/**\n * The assistant turn's activity timeline — the one derivation of \"what did\n * this turn do, and how did each step end\" behind the collapsed view\n * (previously called the conversational view) on every surface: the SDK's\n * `AthenaChat`, Olympus's Spaces chat, and the Chrome extension. Pure\n * functions over assistant-ui message parts; `SuperGroupingCard` renders them.\n *\n * Step states come from the shared classifier (`classifyToolResult`) plus the\n * approval outcomes a part carries (`approval`, `interrupt`, a rejection\n * result), so a call that reads as failed, paused, or rejected on one surface\n * cannot read as a green check on another. Copy comes from the shared tool\n * summary registry (`summarizeToolCall`), itself built on the display\n * registry.\n */\nimport type {\n MessageStatus,\n ThreadAssistantMessagePart,\n ToolCallMessagePartStatus,\n} from '@assistant-ui/react';\nimport {\n classifyToolResult,\n isSpokenTurnTextPart,\n readRejectedToolResult,\n type ToolStatusLabelState,\n} from '@athenaintel/agent-runtime';\nimport { summarizeToolCall, type ToolCallSummary } from '../../tools/tool-summary';\nimport type { GroupablePart, GroupingFunction } from './grouping-function';\n\nexport type ActivityToolState = ToolStatusLabelState;\n\nexport type ActivityItem =\n | {\n kind: 'reasoning';\n id?: string;\n /** Position of the part in the message's content. */\n partIndex?: number;\n text: string;\n state: 'running' | 'complete';\n }\n | {\n kind: 'tool';\n id?: string;\n /** Position of the part in the message's content. */\n partIndex?: number;\n toolName: string;\n args?: ToolCallPart['args'];\n /** The tool's real result; absent while it runs or holds only the streaming placeholder. */\n result?: unknown;\n state: ActivityToolState;\n };\n\n/** The turn as a whole: still working, parked on the person, ended in error, or done. */\nexport type ActivityPhase = 'running' | 'waiting' | 'complete' | 'error';\n\ntype ToolCallPart = Extract<ThreadAssistantMessagePart, { type: 'tool-call' }>;\n\nexport interface ActivityTimelineOptions {\n /**\n * Tools whose unresolved call means the turn is waiting on the person even\n * without an interrupt or approval on the part (the Chrome extension's\n * device plan approval, which the tool UI itself collects).\n */\n waitingTools?: ReadonlySet<string>;\n /**\n * Tools whose result is an application payload relayed verbatim (the Chrome\n * extension's page JavaScript), so a `success: false` flag counts only with\n * an error detail — see `classifyToolResult`'s `passThroughPayload`.\n */\n passThroughTools?: ReadonlySet<string>;\n}\n\nconst NO_TOOLS: ReadonlySet<string> = new Set();\n\n/**\n * Whether a tool-call part still holds the backend's streaming placeholder\n * result rather than the tool's real output. Long-running tools (task\n * subagents, studio and Python execution, deep research) append a ToolMessage\n * the moment they start so their card can fill in live; it carries\n * `additional_kwargs.streaming`, which the runtime converter lifts into\n * `artifact._tool_message_metadata`. The real ToolMessage that replaces it\n * has no such flag, so a defined `result` alone does not mean the tool is done.\n */\nexport function isStreamingToolPlaceholder(part: Pick<ToolCallPart, 'artifact'>): boolean {\n const artifact: unknown = part.artifact;\n if (typeof artifact !== 'object' || artifact === null) return false;\n const metadata: unknown = (artifact as { _tool_message_metadata?: unknown })\n ._tool_message_metadata;\n if (typeof metadata !== 'object' || metadata === null) return false;\n return (metadata as { streaming?: unknown }).streaming === true;\n}\n\n/** The tool's real result: undefined while it has none or only the streaming placeholder. */\nfunction finalResult(part: ToolCallPart): unknown {\n return isStreamingToolPlaceholder(part) ? undefined : part.result;\n}\n\nfunction toolCallStatus(\n part: ToolCallPart,\n messageStatus: MessageStatus | undefined,\n): ToolCallMessagePartStatus | undefined {\n if (finalResult(part) !== undefined) return { type: 'complete' };\n if (messageStatus?.type === 'incomplete') {\n return {\n type: 'incomplete',\n reason: messageStatus.reason === 'tool-calls' ? 'other' : messageStatus.reason,\n error: messageStatus.error,\n };\n }\n if (messageStatus?.type === 'complete') return { type: 'complete' };\n if (messageStatus?.type === 'requires-action') {\n return { type: 'requires-action', reason: messageStatus.reason };\n }\n if (messageStatus?.type === 'running') return { type: 'running' };\n return undefined;\n}\n\n/** How one tool call ended (or is going), reading the approval fields before the result. */\nexport function getActivityToolState(\n part: ToolCallPart,\n messageStatus: MessageStatus | undefined,\n { waitingTools = NO_TOOLS, passThroughTools = NO_TOOLS }: ActivityTimelineOptions = {},\n): ActivityToolState {\n if (part.approval?.approved === false || readRejectedToolResult(part.result) !== null) {\n return 'rejected';\n }\n if (part.approval?.resolution === 'cancelled' || part.approval?.resolution === 'expired') {\n return 'cancelled';\n }\n const result = finalResult(part);\n const unresolved = result === undefined;\n const messageIsActive =\n messageStatus === undefined ||\n messageStatus.type === 'running' ||\n messageStatus.type === 'requires-action';\n if (\n unresolved &&\n (part.interrupt?.type === 'human' ||\n (part.approval !== undefined &&\n part.approval.approved === undefined &&\n part.approval.resolution === undefined) ||\n (waitingTools.has(part.toolName) && messageIsActive))\n ) {\n return 'waiting';\n }\n\n const classification = classifyToolResult({\n status: toolCallStatus(part, messageStatus),\n result,\n isError: part.isError,\n passThroughPayload: passThroughTools.has(part.toolName),\n });\n if (classification.state === 'requires-action') return 'waiting';\n return classification.state;\n}\n\n/**\n * The compact reasoning/tool timeline in the order the parts streamed.\n *\n * A reasoning part is still streaming only while it is the final part of a\n * running message — once any later part appears, the thought has settled.\n * Settled reasoning parts with no text are dropped so the list never shows an\n * empty thinking row.\n */\nexport function buildActivityTimeline(\n content: readonly ThreadAssistantMessagePart[] | undefined,\n messageStatus: MessageStatus | undefined,\n options: ActivityTimelineOptions = {},\n): ActivityItem[] {\n if (!content?.length) return [];\n\n const lastPartIndex = content.length - 1;\n const timeline: ActivityItem[] = [];\n for (let index = 0; index < content.length; index += 1) {\n const part = content[index];\n if (part.type === 'tool-call') {\n const result = finalResult(part);\n timeline.push({\n kind: 'tool',\n id: part.toolCallId,\n partIndex: index,\n args: part.args,\n ...(result !== undefined ? { result } : {}),\n toolName: part.toolName,\n state: getActivityToolState(part, messageStatus, options),\n });\n continue;\n }\n if (part.type !== 'reasoning') continue;\n\n const text = typeof part.text === 'string' ? part.text : '';\n const stillStreaming = messageStatus?.type === 'running' && index === lastPartIndex;\n if (!stillStreaming && text.trim() === '') continue;\n timeline.push({\n kind: 'reasoning',\n id: `reasoning-${index}`,\n partIndex: index,\n text,\n state: stillStreaming ? 'running' : 'complete',\n });\n }\n return timeline;\n}\n\n/** Number of tool calls in the timeline. */\nexport function countActivityTools(timeline: readonly ActivityItem[]): number {\n return timeline.reduce((count, item) => (item.kind === 'tool' ? count + 1 : count), 0);\n}\n\n/**\n * The turn's phase. Waiting on the person wins over everything — a\n * `requires-action` status, a waiting tool, or a host's own `waitingForInput`\n * assertion (no in-repo host passes one) — then the message's own status.\n */\nexport function resolveActivityPhase(\n status: MessageStatus | undefined,\n timeline: readonly ActivityItem[],\n { waitingForInput = false }: { waitingForInput?: boolean } = {},\n): ActivityPhase {\n if (\n waitingForInput ||\n status?.type === 'requires-action' ||\n timeline.some((item) => item.kind === 'tool' && item.state === 'waiting')\n ) {\n return 'waiting';\n }\n if (status?.type === 'running') return 'running';\n if (status?.type === 'incomplete') return 'error';\n return 'complete';\n}\n\n/**\n * A settled thought's row: the heading a reasoning summary opens with\n * (\"**Checking the workstation**\" → \"Checking the workstation\"), else the\n * generic wording. The thought itself stays in the run's details.\n */\nexport function getReasoningLabel(text: string, state: 'running' | 'complete'): string {\n if (state === 'running') return 'Thinking';\n const heading = /^\\s*\\*\\*([^*\\n]{3,80}?)\\*\\*/.exec(text)?.[1]?.trim();\n return heading ? heading.replace(/[.:]+$/, '') : 'Thought through the next step';\n}\n\n/**\n * The status-row copy for one step: the call's own summary from the shared\n * summary registry (`summarizeToolCall`: \"Ran git status\", \"Read config.ts\").\n * `resolveToolDisplayName` lets a host with a richer tool catalog name tools\n * neither registry has an entry for; `assetTitles` names the machine or\n * document a call targeted by id when an earlier result in the turn did.\n */\nexport function getActivityItemLabel(\n item: ActivityItem,\n resolveToolDisplayName?: (toolName: string) => string | undefined,\n assetTitles?: ReadonlyMap<string, string>,\n): string {\n if (item.kind === 'reasoning') return getReasoningLabel(item.text, item.state);\n return summarizeActivityTool(item, resolveToolDisplayName, assetTitles).label;\n}\n\n/** The summary of one tool step (see {@link getActivityItemLabel}). */\nexport function summarizeActivityTool(\n item: Extract<ActivityItem, { kind: 'tool' }>,\n resolveToolDisplayName?: (toolName: string) => string | undefined,\n assetTitles?: ReadonlyMap<string, string>,\n): ToolCallSummary {\n return summarizeToolCall({\n toolName: item.toolName,\n args: item.args,\n result: item.result,\n status: item.state,\n ...(assetTitles ? { assetTitles } : {}),\n ...(resolveToolDisplayName ? { displayName: resolveToolDisplayName(item.toolName) } : {}),\n });\n}\n\n/**\n * The collapsed-card summary of a finished turn. \"Completed with issues\" means\n * the turn ended on a problem: a call the person refused, or a failed call\n * that no later call completed after. A failed command the agent then got past\n * (a search that found nothing, a retry that worked) is ordinary work, so a\n * long turn that recovered from it reads as the tools it used.\n */\nexport function getActivitySummary(timeline: readonly ActivityItem[]): string {\n const toolCount = countActivityTools(timeline);\n const tools = timeline.filter((item) => item.kind === 'tool');\n const lastFailure = tools.findLastIndex((item) => item.state === 'error');\n const endedOnFailure =\n lastFailure >= 0 && !tools.slice(lastFailure + 1).some((item) => item.state === 'complete');\n const hasIssue = endedOnFailure || tools.some((item) => item.state === 'rejected');\n if (hasIssue) return 'Completed with issues';\n if (timeline.some((item) => item.kind === 'tool' && item.state === 'cancelled')) {\n return 'Action cancelled';\n }\n if (timeline.some((item) => item.kind === 'tool' && item.state === 'paused')) {\n return 'Paused during tool use';\n }\n if (toolCount > 0) return `Used ${toolCount} ${toolCount === 1 ? 'tool' : 'tools'}`;\n return 'Reasoning complete';\n}\n\n/** The part shape the final-text read needs; any message role's parts satisfy it. */\nexport type FinalTextPart = { readonly type: string; readonly text?: string };\n\n/**\n * Whether a text part shows below the card instead of in the details panel:\n * it comes after the final tool call, or it holds a spoken voice turn's words\n * (a live turn heard during a delegated run lands between the run's tool\n * calls, see `isSpokenTurnTextPart`; it is the conversation, not narration).\n */\nfunction isAnswerTextPart(\n part: { readonly type: string } | undefined,\n index: number,\n lastToolIndex: number,\n): boolean {\n return part?.type === 'text' && (index > lastToolIndex || isSpokenTurnTextPart(part));\n}\n\n/**\n * The visible answer of a grouped turn: the text after the final tool call\n * (all of it when the turn never called a tool), plus the words of every\n * spoken voice turn in the message, in order. Other intermediate text (before\n * or between tool calls) stays available in the details panel.\n */\nexport function getFinalText(content: readonly FinalTextPart[] | undefined): string | null {\n const parts = getFinalTextParts(content);\n return parts.length > 0 ? parts.map((part) => part.text).join('\\n\\n') : null;\n}\n\n/** One text part of the visible answer, with its index in the message content. */\nexport interface FinalTextSegment {\n index: number;\n text: string;\n}\n\n/**\n * The parts `getFinalText` joins, each kept separate with its content index.\n * A spoken turn and the run's own reply can stream at the same time, so the\n * earlier part may grow while a later one exists: rendered as one joined\n * string, that text changes in the middle rather than at its end, and the\n * streaming reveal restarts from an empty bubble on every word.\n */\nexport function getFinalTextParts(content: readonly FinalTextPart[] | undefined): FinalTextSegment[] {\n if (!content?.length) return [];\n\n const lastToolIndex = content.findLastIndex((part) => part?.type === 'tool-call');\n const parts: FinalTextSegment[] = [];\n content.forEach((part, index) => {\n if (part.text && isAnswerTextPart(part, index, lastToolIndex)) parts.push({ index, text: part.text });\n });\n return parts;\n}\n\n/**\n * Keep the answer out of the details panel: it renders below the card\n * (`SuperGroupingFinalText`), so the details grouping drops every text part\n * `getFinalText` shows and any group that becomes empty.\n */\nexport function excludeFinalTextFromGroups(grouping: GroupingFunction): GroupingFunction {\n return (parts) => {\n const lastToolIndex = parts.findLastIndex((part) => part?.type === 'tool-call');\n return grouping(parts)\n .map((group) => ({\n ...group,\n indices: group.indices.filter((index) => !isAnswerTextPart(parts[index], index, lastToolIndex)),\n }))\n .filter((group) => group.indices.length > 0);\n };\n}\n\n/**\n * Drop the parts `exclude` matches from every group, and any group left\n * empty: `SuperGroupingCard` renders inline tool calls outside the details,\n * so they must not render a second time inside it.\n */\nexport function excludePartsFromGroups(\n grouping: GroupingFunction,\n exclude: (part: GroupablePart) => boolean,\n): GroupingFunction {\n return (parts) =>\n grouping(parts)\n .map((group) => ({\n ...group,\n indices: group.indices.filter((index) => {\n const part = parts[index];\n return part === undefined || !exclude(part);\n }),\n }))\n .filter((group) => group.indices.length > 0);\n}\n"],"names":[],"mappings":";;;AAuEA,MAAM,+BAAoC,IAAA;AAWnC,SAAS,2BAA2B,MAA+C;AACxF,QAAM,WAAoB,KAAK;AAC/B,MAAI,OAAO,aAAa,YAAY,aAAa,KAAM,QAAO;AAC9D,QAAM,WAAqB,SACxB;AACH,MAAI,OAAO,aAAa,YAAY,aAAa,KAAM,QAAO;AAC9D,SAAQ,SAAqC,cAAc;AAC7D;AAGA,SAAS,YAAY,MAA6B;AAChD,SAAO,2BAA2B,IAAI,IAAI,SAAY,KAAK;AAC7D;AAEA,SAAS,eACP,MACA,eACuC;AACvC,MAAI,YAAY,IAAI,MAAM,OAAW,QAAO,EAAE,MAAM,WAAA;AACpD,OAAI,+CAAe,UAAS,cAAc;AACxC,WAAO;AAAA,MACL,MAAM;AAAA,MACN,QAAQ,cAAc,WAAW,eAAe,UAAU,cAAc;AAAA,MACxE,OAAO,cAAc;AAAA,IAAA;AAAA,EAEzB;AACA,OAAI,+CAAe,UAAS,WAAY,QAAO,EAAE,MAAM,WAAA;AACvD,OAAI,+CAAe,UAAS,mBAAmB;AAC7C,WAAO,EAAE,MAAM,mBAAmB,QAAQ,cAAc,OAAA;AAAA,EAC1D;AACA,OAAI,+CAAe,UAAS,UAAW,QAAO,EAAE,MAAM,UAAA;AACtD,SAAO;AACT;AAGO,SAAS,qBACd,MACA,eACA,EAAE,eAAe,UAAU,mBAAmB,SAAA,IAAsC,IACjE;;AACnB,QAAI,UAAK,aAAL,mBAAe,cAAa,SAAS,uBAAuB,KAAK,MAAM,MAAM,MAAM;AACrF,WAAO;AAAA,EACT;AACA,QAAI,UAAK,aAAL,mBAAe,gBAAe,iBAAe,UAAK,aAAL,mBAAe,gBAAe,WAAW;AACxF,WAAO;AAAA,EACT;AACA,QAAM,SAAS,YAAY,IAAI;AAC/B,QAAM,aAAa,WAAW;AAC9B,QAAM,kBACJ,kBAAkB,UAClB,cAAc,SAAS,aACvB,cAAc,SAAS;AACzB,MACE,iBACC,UAAK,cAAL,mBAAgB,UAAS,WACvB,KAAK,aAAa,UACjB,KAAK,SAAS,aAAa,UAC3B,KAAK,SAAS,eAAe,UAC9B,aAAa,IAAI,KAAK,QAAQ,KAAK,kBACtC;AACA,WAAO;AAAA,EACT;AAEA,QAAM,iBAAiB,mBAAmB;AAAA,IACxC,QAAQ,eAAe,MAAM,aAAa;AAAA,IAC1C;AAAA,IACA,SAAS,KAAK;AAAA,IACd,oBAAoB,iBAAiB,IAAI,KAAK,QAAQ;AAAA,EAAA,CACvD;AACD,MAAI,eAAe,UAAU,kBAAmB,QAAO;AACvD,SAAO,eAAe;AACxB;AAUO,SAAS,sBACd,SACA,eACA,UAAmC,CAAA,GACnB;AAChB,MAAI,EAAC,mCAAS,QAAQ,QAAO,CAAA;AAE7B,QAAM,gBAAgB,QAAQ,SAAS;AACvC,QAAM,WAA2B,CAAA;AACjC,WAAS,QAAQ,GAAG,QAAQ,QAAQ,QAAQ,SAAS,GAAG;AACtD,UAAM,OAAO,QAAQ,KAAK;AAC1B,QAAI,KAAK,SAAS,aAAa;AAC7B,YAAM,SAAS,YAAY,IAAI;AAC/B,eAAS,KAAK;AAAA,QACZ,MAAM;AAAA,QACN,IAAI,KAAK;AAAA,QACT,WAAW;AAAA,QACX,MAAM,KAAK;AAAA,QACX,GAAI,WAAW,SAAY,EAAE,OAAA,IAAW,CAAA;AAAA,QACxC,UAAU,KAAK;AAAA,QACf,OAAO,qBAAqB,MAAM,eAAe,OAAO;AAAA,MAAA,CACzD;AACD;AAAA,IACF;AACA,QAAI,KAAK,SAAS,YAAa;AAE/B,UAAM,OAAO,OAAO,KAAK,SAAS,WAAW,KAAK,OAAO;AACzD,UAAM,kBAAiB,+CAAe,UAAS,aAAa,UAAU;AACtE,QAAI,CAAC,kBAAkB,KAAK,KAAA,MAAW,GAAI;AAC3C,aAAS,KAAK;AAAA,MACZ,MAAM;AAAA,MACN,IAAI,aAAa,KAAK;AAAA,MACtB,WAAW;AAAA,MACX;AAAA,MACA,OAAO,iBAAiB,YAAY;AAAA,IAAA,CACrC;AAAA,EACH;AACA,SAAO;AACT;AAGO,SAAS,mBAAmB,UAA2C;AAC5E,SAAO,SAAS,OAAO,CAAC,OAAO,SAAU,KAAK,SAAS,SAAS,QAAQ,IAAI,OAAQ,CAAC;AACvF;AAOO,SAAS,qBACd,QACA,UACA,EAAE,kBAAkB,MAAA,IAAyC,IAC9C;AACf,MACE,oBACA,iCAAQ,UAAS,qBACjB,SAAS,KAAK,CAAC,SAAS,KAAK,SAAS,UAAU,KAAK,UAAU,SAAS,GACxE;AACA,WAAO;AAAA,EACT;AACA,OAAI,iCAAQ,UAAS,UAAW,QAAO;AACvC,OAAI,iCAAQ,UAAS,aAAc,QAAO;AAC1C,SAAO;AACT;AAOO,SAAS,kBAAkB,MAAc,OAAuC;;AACrF,MAAI,UAAU,UAAW,QAAO;AAChC,QAAM,WAAU,yCAA8B,KAAK,IAAI,MAAvC,mBAA2C,OAA3C,mBAA+C;AAC/D,SAAO,UAAU,QAAQ,QAAQ,UAAU,EAAE,IAAI;AACnD;AASO,SAAS,qBACd,MACA,wBACA,aACQ;AACR,MAAI,KAAK,SAAS,YAAa,QAAO,kBAAkB,KAAK,MAAM,KAAK,KAAK;AAC7E,SAAO,sBAAsB,MAAM,wBAAwB,WAAW,EAAE;AAC1E;AAGO,SAAS,sBACd,MACA,wBACA,aACiB;AACjB,SAAO,kBAAkB;AAAA,IACvB,UAAU,KAAK;AAAA,IACf,MAAM,KAAK;AAAA,IACX,QAAQ,KAAK;AAAA,IACb,QAAQ,KAAK;AAAA,IACb,GAAI,cAAc,EAAE,YAAA,IAAgB,CAAA;AAAA,IACpC,GAAI,yBAAyB,EAAE,aAAa,uBAAuB,KAAK,QAAQ,MAAM,CAAA;AAAA,EAAC,CACxF;AACH;AASO,SAAS,mBAAmB,UAA2C;AAC5E,QAAM,YAAY,mBAAmB,QAAQ;AAC7C,QAAM,QAAQ,SAAS,OAAO,CAAC,SAAS,KAAK,SAAS,MAAM;AAC5D,QAAM,cAAc,MAAM,cAAc,CAAC,SAAS,KAAK,UAAU,OAAO;AACxE,QAAM,iBACJ,eAAe,KAAK,CAAC,MAAM,MAAM,cAAc,CAAC,EAAE,KAAK,CAAC,SAAS,KAAK,UAAU,UAAU;AAC5F,QAAM,WAAW,kBAAkB,MAAM,KAAK,CAAC,SAAS,KAAK,UAAU,UAAU;AACjF,MAAI,SAAU,QAAO;AACrB,MAAI,SAAS,KAAK,CAAC,SAAS,KAAK,SAAS,UAAU,KAAK,UAAU,WAAW,GAAG;AAC/E,WAAO;AAAA,EACT;AACA,MAAI,SAAS,KAAK,CAAC,SAAS,KAAK,SAAS,UAAU,KAAK,UAAU,QAAQ,GAAG;AAC5E,WAAO;AAAA,EACT;AACA,MAAI,YAAY,EAAG,QAAO,QAAQ,SAAS,IAAI,cAAc,IAAI,SAAS,OAAO;AACjF,SAAO;AACT;AAWA,SAAS,iBACP,MACA,OACA,eACS;AACT,UAAO,6BAAM,UAAS,WAAW,QAAQ,iBAAiB,qBAAqB,IAAI;AACrF;AAQO,SAAS,aAAa,SAA8D;AACzF,QAAM,QAAQ,kBAAkB,OAAO;AACvC,SAAO,MAAM,SAAS,IAAI,MAAM,IAAI,CAAC,SAAS,KAAK,IAAI,EAAE,KAAK,MAAM,IAAI;AAC1E;AAeO,SAAS,kBAAkB,SAAmE;AACnG,MAAI,EAAC,mCAAS,QAAQ,QAAO,CAAA;AAE7B,QAAM,gBAAgB,QAAQ,cAAc,CAAC,UAAS,6BAAM,UAAS,WAAW;AAChF,QAAM,QAA4B,CAAA;AAClC,UAAQ,QAAQ,CAAC,MAAM,UAAU;AAC/B,QAAI,KAAK,QAAQ,iBAAiB,MAAM,OAAO,aAAa,EAAG,OAAM,KAAK,EAAE,OAAO,MAAM,KAAK,MAAM;AAAA,EACtG,CAAC;AACD,SAAO;AACT;AAOO,SAAS,2BAA2B,UAA8C;AACvF,SAAO,CAAC,UAAU;AAChB,UAAM,gBAAgB,MAAM,cAAc,CAAC,UAAS,6BAAM,UAAS,WAAW;AAC9E,WAAO,SAAS,KAAK,EAClB,IAAI,CAAC,WAAW;AAAA,MACf,GAAG;AAAA,MACH,SAAS,MAAM,QAAQ,OAAO,CAAC,UAAU,CAAC,iBAAiB,MAAM,KAAK,GAAG,OAAO,aAAa,CAAC;AAAA,IAAA,EAC9F,EACD,OAAO,CAAC,UAAU,MAAM,QAAQ,SAAS,CAAC;AAAA,EAC/C;AACF;AAOO,SAAS,uBACd,UACA,SACkB;AAClB,SAAO,CAAC,UACN,SAAS,KAAK,EACX,IAAI,CAAC,WAAW;AAAA,IACf,GAAG;AAAA,IACH,SAAS,MAAM,QAAQ,OAAO,CAAC,UAAU;AACvC,YAAM,OAAO,MAAM,KAAK;AACxB,aAAO,SAAS,UAAa,CAAC,QAAQ,IAAI;AAAA,IAC5C,CAAC;AAAA,EAAA,EACD,EACD,OAAO,CAAC,UAAU,MAAM,QAAQ,SAAS,CAAC;AACjD;"}
1
+ {"version":3,"file":"activity-timeline.js","sources":["../../../src/chat/super-grouping/activity-timeline.ts"],"sourcesContent":["/**\n * The assistant turn's activity timeline — the one derivation of \"what did\n * this turn do, and how did each step end\" behind the collapsed view\n * (previously called the conversational view) on every surface: the SDK's\n * `AthenaChat`, Olympus's Spaces chat, and the Chrome extension. Pure\n * functions over assistant-ui message parts; `SuperGroupingCard` renders them.\n *\n * Step states come from the shared classifier (`classifyToolResult`) plus the\n * approval outcomes a part carries (`approval`, `interrupt`, a rejection\n * result), so a call that reads as failed, paused, or rejected on one surface\n * cannot read as a green check on another. Copy comes from the shared tool\n * summary registry (`summarizeToolCall`), itself built on the display\n * registry.\n */\nimport type {\n MessageStatus,\n ThreadAssistantMessagePart,\n ToolCallMessagePartStatus,\n} from '@assistant-ui/react';\nimport {\n classifyToolResult,\n isRunningToolPlaceholderArtifact,\n isSpokenTurnTextPart,\n readRejectedToolResult,\n type ToolStatusLabelState,\n} from '@athenaintel/agent-runtime';\nimport { summarizeToolCall, type ToolCallSummary } from '../../tools/tool-summary';\nimport type { GroupablePart, GroupingFunction } from './grouping-function';\n\nexport type ActivityToolState = ToolStatusLabelState;\n\nexport type ActivityItem =\n | {\n kind: 'reasoning';\n id?: string;\n /** Position of the part in the message's content. */\n partIndex?: number;\n text: string;\n state: 'running' | 'complete';\n }\n | {\n kind: 'tool';\n id?: string;\n /** Position of the part in the message's content. */\n partIndex?: number;\n toolName: string;\n args?: ToolCallPart['args'];\n /** The tool's real result; absent while it runs or holds only the streaming placeholder. */\n result?: unknown;\n state: ActivityToolState;\n };\n\n/** The turn as a whole: still working, parked on the person, ended in error, or done. */\nexport type ActivityPhase = 'running' | 'waiting' | 'complete' | 'error';\n\ntype ToolCallPart = Extract<ThreadAssistantMessagePart, { type: 'tool-call' }>;\n\nexport interface ActivityTimelineOptions {\n /**\n * Tools whose unresolved call means the turn is waiting on the person even\n * without an interrupt or approval on the part (the Chrome extension's\n * device plan approval, which the tool UI itself collects).\n */\n waitingTools?: ReadonlySet<string>;\n /**\n * Calls the run is parked on, by tool-call id, as the host reads them off\n * its pending approval: a gated call, or (in Olympus) a `task` call whose\n * subagent waits on an approval. Any of them still without its real result\n * reads as waiting.\n */\n waitingToolCallIds?: ReadonlySet<string>;\n /**\n * Tools whose result is an application payload relayed verbatim (the Chrome\n * extension's page JavaScript), so a `success: false` flag counts only with\n * an error detail — see `classifyToolResult`'s `passThroughPayload`.\n */\n passThroughTools?: ReadonlySet<string>;\n}\n\nconst NO_TOOLS: ReadonlySet<string> = new Set();\nconst NO_TOOL_CALLS: ReadonlySet<string> = new Set();\n\n/**\n * Whether a tool-call part still holds the backend's running-tool placeholder\n * result rather than the tool's real output. Long-running tools (task\n * subagents, studio and Python execution, deep research) append a ToolMessage\n * the moment they start so their card can fill in live; its marker reaches the\n * part's artifact (`isRunningToolPlaceholderArtifact`). The real ToolMessage\n * that replaces it has no such marker, so a defined `result` alone does not\n * mean the tool is done.\n */\nexport function isStreamingToolPlaceholder(part: Pick<ToolCallPart, 'artifact'>): boolean {\n return isRunningToolPlaceholderArtifact(part.artifact);\n}\n\n/** The tool's real result: undefined while it has none or only the streaming placeholder. */\nfunction finalResult(part: ToolCallPart): unknown {\n return isStreamingToolPlaceholder(part) ? undefined : part.result;\n}\n\nfunction toolCallStatus(\n part: ToolCallPart,\n messageStatus: MessageStatus | undefined,\n): ToolCallMessagePartStatus | undefined {\n if (finalResult(part) !== undefined) return { type: 'complete' };\n if (messageStatus?.type === 'incomplete') {\n return {\n type: 'incomplete',\n reason: messageStatus.reason === 'tool-calls' ? 'other' : messageStatus.reason,\n error: messageStatus.error,\n };\n }\n if (messageStatus?.type === 'complete') {\n // The placeholder is the backend's word that the call is still in flight.\n // A turn reads `complete` whenever nothing streams (a run parked on an\n // approval inside a subagent, the gap before a drained run resumes), and\n // assistant-ui counts the placeholder as the call's result when it settles\n // that status, so the turn's status cannot finish the call.\n return isStreamingToolPlaceholder(part) ? { type: 'running' } : { type: 'complete' };\n }\n if (messageStatus?.type === 'requires-action') {\n return { type: 'requires-action', reason: messageStatus.reason };\n }\n if (messageStatus?.type === 'running') return { type: 'running' };\n return undefined;\n}\n\n/** How one tool call ended (or is going), reading the approval fields before the result. */\nexport function getActivityToolState(\n part: ToolCallPart,\n messageStatus: MessageStatus | undefined,\n {\n waitingTools = NO_TOOLS,\n waitingToolCallIds = NO_TOOL_CALLS,\n passThroughTools = NO_TOOLS,\n }: ActivityTimelineOptions = {},\n): ActivityToolState {\n if (part.approval?.approved === false || readRejectedToolResult(part.result) !== null) {\n return 'rejected';\n }\n if (part.approval?.resolution === 'cancelled' || part.approval?.resolution === 'expired') {\n return 'cancelled';\n }\n const result = finalResult(part);\n const unresolved = result === undefined;\n const messageIsActive =\n messageStatus === undefined ||\n messageStatus.type === 'running' ||\n messageStatus.type === 'requires-action';\n if (\n unresolved &&\n (part.interrupt?.type === 'human' ||\n (part.approval !== undefined &&\n part.approval.approved === undefined &&\n part.approval.resolution === undefined) ||\n waitingToolCallIds.has(part.toolCallId) ||\n (waitingTools.has(part.toolName) && messageIsActive))\n ) {\n return 'waiting';\n }\n\n const classification = classifyToolResult({\n status: toolCallStatus(part, messageStatus),\n result,\n isError: part.isError,\n passThroughPayload: passThroughTools.has(part.toolName),\n });\n if (classification.state === 'requires-action') return 'waiting';\n return classification.state;\n}\n\n/**\n * The compact reasoning/tool timeline in the order the parts streamed.\n *\n * A reasoning part is still streaming only while it is the final part of a\n * running message — once any later part appears, the thought has settled.\n * Settled reasoning parts with no text are dropped so the list never shows an\n * empty thinking row.\n */\nexport function buildActivityTimeline(\n content: readonly ThreadAssistantMessagePart[] | undefined,\n messageStatus: MessageStatus | undefined,\n options: ActivityTimelineOptions = {},\n): ActivityItem[] {\n if (!content?.length) return [];\n\n const lastPartIndex = content.length - 1;\n const timeline: ActivityItem[] = [];\n for (let index = 0; index < content.length; index += 1) {\n const part = content[index];\n if (part.type === 'tool-call') {\n const result = finalResult(part);\n timeline.push({\n kind: 'tool',\n id: part.toolCallId,\n partIndex: index,\n args: part.args,\n ...(result !== undefined ? { result } : {}),\n toolName: part.toolName,\n state: getActivityToolState(part, messageStatus, options),\n });\n continue;\n }\n if (part.type !== 'reasoning') continue;\n\n const text = typeof part.text === 'string' ? part.text : '';\n const stillStreaming = messageStatus?.type === 'running' && index === lastPartIndex;\n if (!stillStreaming && text.trim() === '') continue;\n timeline.push({\n kind: 'reasoning',\n id: `reasoning-${index}`,\n partIndex: index,\n text,\n state: stillStreaming ? 'running' : 'complete',\n });\n }\n return timeline;\n}\n\n/** Number of tool calls in the timeline. */\nexport function countActivityTools(timeline: readonly ActivityItem[]): number {\n return timeline.reduce((count, item) => (item.kind === 'tool' ? count + 1 : count), 0);\n}\n\n/**\n * The turn's phase. Waiting on the person wins over everything — a\n * `requires-action` status, a waiting tool, or a host's own `waitingForInput`\n * assertion (no in-repo host passes one) — then the message's own status. A\n * complete turn with a step still running is running: only a step holding the\n * backend's running placeholder reads so once nothing streams (a run parked on\n * an approval inside a subagent, the gap before a drained run resumes).\n */\nexport function resolveActivityPhase(\n status: MessageStatus | undefined,\n timeline: readonly ActivityItem[],\n { waitingForInput = false }: { waitingForInput?: boolean } = {},\n): ActivityPhase {\n if (\n waitingForInput ||\n status?.type === 'requires-action' ||\n timeline.some((item) => item.kind === 'tool' && item.state === 'waiting')\n ) {\n return 'waiting';\n }\n if (status?.type === 'running') return 'running';\n if (status?.type === 'incomplete') return 'error';\n if (\n status?.type === 'complete' &&\n timeline.some((item) => item.kind === 'tool' && item.state === 'running')\n ) {\n return 'running';\n }\n return 'complete';\n}\n\n/**\n * A settled thought's row: the heading a reasoning summary opens with\n * (\"**Checking the workstation**\" → \"Checking the workstation\"), else the\n * generic wording. The thought itself stays in the run's details.\n */\nexport function getReasoningLabel(text: string, state: 'running' | 'complete'): string {\n if (state === 'running') return 'Thinking';\n const heading = /^\\s*\\*\\*([^*\\n]{3,80}?)\\*\\*/.exec(text)?.[1]?.trim();\n return heading ? heading.replace(/[.:]+$/, '') : 'Thought through the next step';\n}\n\n/**\n * The status-row copy for one step: the call's own summary from the shared\n * summary registry (`summarizeToolCall`: \"Ran git status\", \"Read config.ts\").\n * `resolveToolDisplayName` lets a host with a richer tool catalog name tools\n * neither registry has an entry for; `assetTitles` names the machine or\n * document a call targeted by id when an earlier result in the turn did.\n */\nexport function getActivityItemLabel(\n item: ActivityItem,\n resolveToolDisplayName?: (toolName: string) => string | undefined,\n assetTitles?: ReadonlyMap<string, string>,\n): string {\n if (item.kind === 'reasoning') return getReasoningLabel(item.text, item.state);\n return summarizeActivityTool(item, resolveToolDisplayName, assetTitles).label;\n}\n\n/** The summary of one tool step (see {@link getActivityItemLabel}). */\nexport function summarizeActivityTool(\n item: Extract<ActivityItem, { kind: 'tool' }>,\n resolveToolDisplayName?: (toolName: string) => string | undefined,\n assetTitles?: ReadonlyMap<string, string>,\n): ToolCallSummary {\n return summarizeToolCall({\n toolName: item.toolName,\n args: item.args,\n result: item.result,\n status: item.state,\n ...(assetTitles ? { assetTitles } : {}),\n ...(resolveToolDisplayName ? { displayName: resolveToolDisplayName(item.toolName) } : {}),\n });\n}\n\n/**\n * The collapsed-card summary of a finished turn. \"Completed with issues\" means\n * the turn ended on a problem: a call the person refused, or a failed call\n * that no later call completed after. A failed command the agent then got past\n * (a search that found nothing, a retry that worked) is ordinary work, so a\n * long turn that recovered from it reads as the tools it used.\n */\nexport function getActivitySummary(timeline: readonly ActivityItem[]): string {\n const toolCount = countActivityTools(timeline);\n const tools = timeline.filter((item) => item.kind === 'tool');\n const lastFailure = tools.findLastIndex((item) => item.state === 'error');\n const endedOnFailure =\n lastFailure >= 0 && !tools.slice(lastFailure + 1).some((item) => item.state === 'complete');\n const hasIssue = endedOnFailure || tools.some((item) => item.state === 'rejected');\n if (hasIssue) return 'Completed with issues';\n if (timeline.some((item) => item.kind === 'tool' && item.state === 'cancelled')) {\n return 'Action cancelled';\n }\n if (timeline.some((item) => item.kind === 'tool' && item.state === 'paused')) {\n return 'Paused during tool use';\n }\n if (toolCount > 0) return `Used ${toolCount} ${toolCount === 1 ? 'tool' : 'tools'}`;\n return 'Reasoning complete';\n}\n\n/** The part shape the final-text read needs; any message role's parts satisfy it. */\nexport type FinalTextPart = { readonly type: string; readonly text?: string };\n\n/**\n * Whether a text part shows below the card instead of in the details panel:\n * it comes after the final tool call, or it holds a spoken voice turn's words\n * (a live turn heard during a delegated run lands between the run's tool\n * calls, see `isSpokenTurnTextPart`; it is the conversation, not narration).\n */\nfunction isAnswerTextPart(\n part: { readonly type: string } | undefined,\n index: number,\n lastToolIndex: number,\n): boolean {\n return part?.type === 'text' && (index > lastToolIndex || isSpokenTurnTextPart(part));\n}\n\n/**\n * The visible answer of a grouped turn: the text after the final tool call\n * (all of it when the turn never called a tool), plus the words of every\n * spoken voice turn in the message, in order. Other intermediate text (before\n * or between tool calls) stays available in the details panel.\n */\nexport function getFinalText(content: readonly FinalTextPart[] | undefined): string | null {\n const parts = getFinalTextParts(content);\n return parts.length > 0 ? parts.map((part) => part.text).join('\\n\\n') : null;\n}\n\n/** One text part of the visible answer, with its index in the message content. */\nexport interface FinalTextSegment {\n index: number;\n text: string;\n}\n\n/**\n * The parts `getFinalText` joins, each kept separate with its content index.\n * A spoken turn and the run's own reply can stream at the same time, so the\n * earlier part may grow while a later one exists: rendered as one joined\n * string, that text changes in the middle rather than at its end, and the\n * streaming reveal restarts from an empty bubble on every word.\n */\nexport function getFinalTextParts(content: readonly FinalTextPart[] | undefined): FinalTextSegment[] {\n if (!content?.length) return [];\n\n const lastToolIndex = content.findLastIndex((part) => part?.type === 'tool-call');\n const parts: FinalTextSegment[] = [];\n content.forEach((part, index) => {\n if (part.text && isAnswerTextPart(part, index, lastToolIndex)) parts.push({ index, text: part.text });\n });\n return parts;\n}\n\n/**\n * Keep the answer out of the details panel: it renders below the card\n * (`SuperGroupingFinalText`), so the details grouping drops every text part\n * `getFinalText` shows and any group that becomes empty.\n */\nexport function excludeFinalTextFromGroups(grouping: GroupingFunction): GroupingFunction {\n return (parts) => {\n const lastToolIndex = parts.findLastIndex((part) => part?.type === 'tool-call');\n return grouping(parts)\n .map((group) => ({\n ...group,\n indices: group.indices.filter((index) => !isAnswerTextPart(parts[index], index, lastToolIndex)),\n }))\n .filter((group) => group.indices.length > 0);\n };\n}\n\n/**\n * Drop the parts `exclude` matches from every group, and any group left\n * empty: `SuperGroupingCard` renders inline tool calls outside the details,\n * so they must not render a second time inside it.\n */\nexport function excludePartsFromGroups(\n grouping: GroupingFunction,\n exclude: (part: GroupablePart) => boolean,\n): GroupingFunction {\n return (parts) =>\n grouping(parts)\n .map((group) => ({\n ...group,\n indices: group.indices.filter((index) => {\n const part = parts[index];\n return part === undefined || !exclude(part);\n }),\n }))\n .filter((group) => group.indices.length > 0);\n}\n"],"names":[],"mappings":"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"}
@@ -131,5 +131,41 @@ function useStatewireApprovalRequest(options = {}) {
131
131
  replayQueuedLanes
132
132
  };
133
133
  }
134
+ const NO_WAITING_TOOL_CALL_IDS = /* @__PURE__ */ new Set();
135
+ const NOTHING_WAITS = {
136
+ toolCallIds: NO_WAITING_TOOL_CALL_IDS,
137
+ runParked: false
138
+ };
139
+ const TOOL_CALL_ID_SEPARATOR = "\n";
140
+ function toolCallIdSet(key) {
141
+ return key === "" ? NO_WAITING_TOOL_CALL_IDS : new Set(key.split(TOOL_CALL_ID_SEPARATOR));
142
+ }
143
+ function useStatewireApprovalWait() {
144
+ const { requestId, actionRequests, liveActionRequests, queuedLaneDecisions } = useStatewireApprovalRequest();
145
+ const runParked = requestId !== void 0;
146
+ const ids = interrupts.toolCallIdsAwaitingApproval({
147
+ actionRequests: runParked ? actionRequests : liveActionRequests,
148
+ queuedLaneDecisions
149
+ });
150
+ const key = [...ids].sort().join(TOOL_CALL_ID_SEPARATOR);
151
+ return react.useMemo(
152
+ () => key === "" && !runParked ? NOTHING_WAITS : { toolCallIds: toolCallIdSet(key), runParked },
153
+ [key, runParked]
154
+ );
155
+ }
156
+ const StatewireApprovalWaitContext = react.createContext(NOTHING_WAITS);
157
+ function StatewireApprovalWaitProvider({ children }) {
158
+ return react.createElement(
159
+ StatewireApprovalWaitContext.Provider,
160
+ { value: useStatewireApprovalWait() },
161
+ children
162
+ );
163
+ }
164
+ function useApprovalWaitInScope() {
165
+ return react.useContext(StatewireApprovalWaitContext);
166
+ }
167
+ exports.StatewireApprovalWaitProvider = StatewireApprovalWaitProvider;
168
+ exports.useApprovalWaitInScope = useApprovalWaitInScope;
134
169
  exports.useStatewireApprovalRequest = useStatewireApprovalRequest;
170
+ exports.useStatewireApprovalWait = useStatewireApprovalWait;
135
171
  //# sourceMappingURL=use-statewire-approval-request.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-statewire-approval-request.cjs","sources":["../../src/chat/use-statewire-approval-request.ts"],"sourcesContent":["import type { StatewireThread } from '@assistant-ui/react-statewire';\nimport {\n useStatewireRuns,\n useStatewireSendCommand,\n useStatewireState,\n} from '@assistant-ui/react-statewire';\nimport {\n type AbandonedInputRequest,\n asHitlApproval,\n findAbandonedInterrupt,\n HITL_PENDING_RESUME_GRACE_MS,\n type HitlApprovalPayload,\n interruptMirrorPayload,\n isApprovalCardInterrupt,\n laneInterruptIds,\n type PendingActionRequest,\n pendingActionRequests,\n readAbandonedInputRequests,\n readInterruptMirror,\n readQueuedLaneDecisions,\n useApprovalResumeLock,\n} from '@athenaintel/agent-runtime';\nimport { useCallback, useEffect, useMemo, useRef, useSyncExternalStore } from 'react';\nimport { useAthenaRunLive } from './use-athena-run-live';\n\ndeclare module '@assistant-ui/core' {\n namespace Assistant {\n interface Commands {\n /**\n * Decide per-dispatch subagent lanes while the parent run is still\n * streaming (`DeepAgentThread.run_lane_input`). Keys are the lanes'\n * langgraph interrupt ids; the host matches them against the lanes its\n * mirrored interrupt currently parks, answers at once when the run is\n * already parked, and otherwise holds them until it parks — stale or\n * unknown ids are ignored, never carried to a later interrupt.\n */\n runLaneInput: {\n readonly type: 'run/lane-input';\n readonly laneDecisions: Readonly<Record<string, StatewireThread.InputResponse>>;\n };\n /**\n * Re-send the lane decisions the host still holds queued as their\n * approver's resume of the parked request (`DeepAgentThread.run_lane_replay`).\n * The host resumes under the meta the approver's `run/lane-input`\n * recorded and refuses any other caller — every attached client reads\n * the same queue, and only the one that queued it may turn it into a\n * resume. Carries no decisions: the host replays what it recorded.\n */\n runLaneReplay: {\n readonly type: 'run/lane-replay';\n readonly requestId: string;\n };\n }\n }\n}\n\nconst NO_QUEUED_LANE_DECISIONS: Readonly<Record<string, unknown>> = Object.freeze({});\nconst NO_ACTION_REQUESTS: PendingActionRequest[] = [];\n\n/**\n * Lane ids of the parked requests this client resumed, keyed by request id\n * and shared by every hook instance on the page (approval card,\n * waiting-on-you banner, host editors) so all of them treat a lingering\n * mirror the same way. Request ids are unique per parked interrupt, so an\n * instance only ever consults the record of the request it saw parked: two\n * chats mounted side by side cannot suppress or clear each other's. A record\n * is retired once the host drops that request's mirror (the resume run\n * started), the surface sees a different request park, or it unmounts.\n */\nconst answeredRequests = new Map<string, readonly string[]>();\nconst answeredListeners = new Set<() => void>();\nlet answeredVersion = 0;\nfunction notifyAnswered(): void {\n answeredVersion += 1;\n for (const listener of answeredListeners) listener();\n}\nfunction recordAnswered(requestId: string, laneIds: readonly string[]): void {\n answeredRequests.set(requestId, laneIds);\n notifyAnswered();\n}\nfunction forgetAnswered(requestId: string): void {\n if (answeredRequests.delete(requestId)) notifyAnswered();\n}\nfunction subscribeAnswered(listener: () => void): () => void {\n answeredListeners.add(listener);\n return () => {\n answeredListeners.delete(listener);\n };\n}\nconst readAnsweredVersion = (): number => answeredVersion;\n\n/**\n * The lanes a resume of the parked request settles: every lane of the request\n * (a resume answers the whole park — lanes already queued through\n * `run/lane-input` ride along) plus any lane named in the `lane_decisions` map.\n */\nfunction answeredLaneIds(value: unknown, actionRequests: readonly PendingActionRequest[]): string[] {\n const ids = laneInterruptIds(actionRequests) ?? [];\n if (typeof value === 'object' && value !== null && 'lane_decisions' in value) {\n const lanes = (value as { lane_decisions: unknown }).lane_decisions;\n if (typeof lanes === 'object' && lanes !== null) {\n for (const id of Object.keys(lanes)) if (!ids.includes(id)) ids.push(id);\n }\n }\n return ids;\n}\n\n/**\n * Whether the host's mirror still shows an interrupt this client already\n * answered. After `run/input` the host drops the parked request at once but\n * keeps `__interrupt__` until the resume run starts and clears it (seconds on\n * a cold checkpoint); without this check the card would re-offer the SAME\n * approval from the mirror, buttons live, and then fold it away again.\n */\nfunction mirrorAlreadyAnswered(\n answeredLanes: readonly string[] | undefined,\n liveActionRequests: readonly PendingActionRequest[],\n): boolean {\n if (answeredLanes === undefined) return false;\n const ids = laneInterruptIds(liveActionRequests);\n if (ids === null) return false;\n return ids.every((id) => answeredLanes.includes(id));\n}\n\n/** Selects which pending interrupt an approval surface answers. */\nexport type StatewireInterruptPredicate = (\n request: StatewireThread.InputRequestState,\n) => request is StatewireThread.CustomInputRequest;\n\nexport interface UseStatewireApprovalRequestOptions {\n /**\n * Which pending interrupt to answer. Defaults to `isApprovalCardInterrupt`\n * (client-tool parks excluded — the client-tool bridge owns those, and a\n * generic resume would corrupt the parked tool call).\n */\n interruptPredicate?: StatewireInterruptPredicate;\n /**\n * How long a sent decision keeps the actions locked when no resume run ever\n * starts. Defaults to {@link HITL_PENDING_RESUME_GRACE_MS}.\n */\n pendingResumeGraceMs?: number;\n /**\n * The host refused the `run/input` (or the transport lost it): the\n * optimistic fold rolls back, the request is on screen again with its\n * actions re-enabled, and this is the surface's one chance to say why.\n */\n onResumeRejected?: (error: unknown, requestId: string) => void;\n /** See {@link UseApprovalResumeLockOptions.onResumeRetry}. */\n onResumeRetry?: (error: unknown, requestId: string, attempt: number) => void;\n}\n\nexport interface StatewireApprovalRequest<TValue> {\n /** The pending interrupt this surface answers, if any. */\n request: StatewireThread.CustomInputRequest | undefined;\n requestId: string | undefined;\n /** The payload narrowed to the Athena HITL approval shape, or `null`. */\n hitl: HitlApprovalPayload | null;\n /** Every gated call the approval covers, in decision order (empty for non-HITL parks). */\n actionRequests: PendingActionRequest[];\n /** An interrupt a non-resume dispatch dropped — the \"approval was cancelled\" notice. */\n abandonedInterrupt: AbandonedInputRequest | undefined;\n /**\n * The mirrored interrupt's HITL payload while the run is still live and no\n * input request is answerable: per-dispatch `task` lanes parked on their\n * gates while sibling lanes stream. `null` once the run parks (the same\n * lanes are then `hitl` / `actionRequests`) and when nothing is parked.\n */\n liveHitl: HitlApprovalPayload | null;\n /** Every gated call `liveHitl` covers (empty when it is `null`). */\n liveActionRequests: PendingActionRequest[];\n /**\n * The decisions the host already holds from a `run/lane-input`, keyed by\n * langgraph interrupt id, to be answered when the run parks — a queued lane\n * reads as decided on every attached client, not just the one that sent it.\n */\n queuedLaneDecisions: Readonly<Record<string, unknown>>;\n /** True after a resume until the request identity changes (or recovery fires). */\n pending: boolean;\n /**\n * Answer the request with `{ type: 'run/input', requestId, response: { type: 'resume', value } }`.\n * Returns the dispatch promise (settles when the host accepts, rejects when\n * it refuses), or `undefined` when the lock dropped the send.\n */\n resume: (value: TValue) => Promise<unknown> | undefined;\n /**\n * Decide per-dispatch lanes by langgraph interrupt id. With a pending\n * request this is the native `lane_decisions` resume through the lock;\n * without one (the run is still streaming siblings) it is `run/lane-input`,\n * which the host queues and answers on the park. Returns the dispatch\n * promise, or `undefined` when the lock dropped a resume.\n */\n sendLaneDecisions: (\n lanes: Readonly<Record<string, StatewireThread.InputResponse>>,\n ) => Promise<unknown> | undefined;\n /**\n * Ask the host to resume the parked `requestId` with the lane decisions it\n * still holds queued, as their approver (`run/lane-replay`). For the card\n * that queued them, after the host's own answerer has stayed silent past\n * its budget; the host refuses every other caller. Settles when the host\n * accepts, rejects when it refuses.\n */\n replayQueuedLanes: (requestId: string) => Promise<unknown>;\n}\n\n/**\n * The headless half of every statewire approval surface: selects the pending\n * interrupt from the runs projection, narrows its payload, reads the\n * host-published abandoned interrupts, and wires the shared optimistic resume\n * lock to the thread's `run/input` command. `StatewireApprovalCard` renders\n * over it; hosts with their own decision UI (per-lane subagent cards) build\n * on it directly so the selection and lock semantics cannot drift.\n *\n * Requires a statewire aui scope (throws outside one, like every\n * `useStatewire*` hook) — gate the mount with `hasStatewireThreadExtras`.\n */\nexport function useStatewireApprovalRequest<\n TValue extends StatewireThread.InputResponse = Record<string, string>,\n>(options: UseStatewireApprovalRequestOptions = {}): StatewireApprovalRequest<TValue> {\n const {\n interruptPredicate = isApprovalCardInterrupt,\n pendingResumeGraceMs = HITL_PENDING_RESUME_GRACE_MS,\n onResumeRejected,\n onResumeRetry,\n } = options;\n const sendCommand = useStatewireSendCommand();\n // The runs projection is memoized by the lib, so this derivation is\n // reference-stable between state updates.\n const request = useStatewireRuns().inputRequests?.find(interruptPredicate);\n const requestId = request?.id;\n\n // The host publishes the interrupts a non-resume dispatch dropped. Select\n // the raw array reference (pre-stream-safe) and derive inline; a `.find`\n // selector would return a fresh object every update.\n const abandoned = useStatewireState(readAbandonedInputRequests);\n const abandonedInterrupt = findAbandonedInterrupt(abandoned);\n\n const hitl = asHitlApproval(request?.payload);\n const actionRequests = useMemo(() => pendingActionRequests(hitl), [hitl]);\n\n const isRunning = useAthenaRunLive();\n // The host mirrors the interrupt into state as soon as a lane parks — while\n // the run manager still reports `running` (siblings streaming) and has no\n // request to answer. Raw reference selectors; derive inline.\n const mirror = useStatewireState(readInterruptMirror);\n const mirrorHitl =\n request === undefined && isRunning ? asHitlApproval(interruptMirrorPayload(mirror)) : null;\n const mirrorActionRequests = useMemo(() => pendingActionRequests(mirrorHitl), [mirrorHitl]);\n\n // The request this surface last saw parked: the only record it may read\n // or retire (the mirror it watches is the one that request's resume clears).\n const lastRequestIdRef = useRef<string>(undefined);\n if (requestId !== undefined) lastRequestIdRef.current = requestId;\n useSyncExternalStore(subscribeAnswered, readAnsweredVersion, readAnsweredVersion);\n const answeredLanes =\n lastRequestIdRef.current === undefined ? undefined : answeredRequests.get(lastRequestIdRef.current);\n const mirrorCleared = interruptMirrorPayload(mirror) === undefined;\n useEffect(() => {\n if (requestId === undefined) return;\n return () => {\n // A different request parks next (or this one unparks for good): the\n // record of this one is stale once it is not the one on screen.\n if (lastRequestIdRef.current !== requestId) forgetAnswered(requestId);\n };\n }, [requestId]);\n useEffect(() => {\n if (mirrorCleared && lastRequestIdRef.current !== undefined) forgetAnswered(lastRequestIdRef.current);\n }, [mirrorCleared]);\n useEffect(\n () => () => {\n if (lastRequestIdRef.current !== undefined) forgetAnswered(lastRequestIdRef.current);\n },\n [],\n );\n const liveHitl = mirrorAlreadyAnswered(answeredLanes, mirrorActionRequests) ? null : mirrorHitl;\n const liveActionRequests = liveHitl === mirrorHitl ? mirrorActionRequests : NO_ACTION_REQUESTS;\n const queuedLaneDecisions =\n useStatewireState(readQueuedLaneDecisions) ?? NO_QUEUED_LANE_DECISIONS;\n\n const { pending, resume: resumeLocked } = useApprovalResumeLock<TValue>({\n requestId,\n isRunning,\n pendingResumeGraceMs,\n onResumeRejected,\n onResumeRetry,\n // The dispatch promise is handed to the lock: a refusal releases it and\n // reaches `onResumeRejected`.\n sendResume: (id, value) =>\n sendCommand({\n type: 'run/input',\n requestId: id,\n response: { type: 'resume', value },\n }),\n });\n\n const resume = useCallback(\n (value: TValue) => {\n if (requestId !== undefined) {\n recordAnswered(requestId, answeredLaneIds(value, actionRequests));\n }\n return resumeLocked(value);\n },\n [requestId, actionRequests, resumeLocked],\n );\n\n const sendLaneDecisions = useCallback(\n (lanes: Readonly<Record<string, StatewireThread.InputResponse>>) =>\n requestId !== undefined\n ? resume({ lane_decisions: lanes } as unknown as TValue)\n : sendCommand({ type: 'run/lane-input', laneDecisions: lanes }),\n [requestId, resume, sendCommand],\n );\n\n const replayQueuedLanes = useCallback(\n (id: string) => sendCommand({ type: 'run/lane-replay', requestId: id }),\n [sendCommand],\n );\n\n return {\n request,\n requestId,\n hitl,\n actionRequests,\n liveHitl,\n liveActionRequests,\n queuedLaneDecisions,\n abandonedInterrupt,\n pending,\n resume,\n sendLaneDecisions,\n replayQueuedLanes,\n };\n}\n"],"names":["laneInterruptIds","isApprovalCardInterrupt","HITL_PENDING_RESUME_GRACE_MS","useStatewireSendCommand","useStatewireRuns","useStatewireState","readAbandonedInputRequests","findAbandonedInterrupt","asHitlApproval","useMemo","pendingActionRequests","useAthenaRunLive","readInterruptMirror","interruptMirrorPayload","useRef","useSyncExternalStore","useEffect","readQueuedLaneDecisions","useApprovalResumeLock","useCallback"],"mappings":";;;;;;AAwDA,MAAM,2BAA8D,OAAO,OAAO,EAAE;AACpF,MAAM,qBAA6C,CAAA;AAYnD,MAAM,uCAAuB,IAAA;AAC7B,MAAM,wCAAwB,IAAA;AAC9B,IAAI,kBAAkB;AACtB,SAAS,iBAAuB;AAC9B,qBAAmB;AACnB,aAAW,YAAY,kBAAmB,UAAA;AAC5C;AACA,SAAS,eAAe,WAAmB,SAAkC;AAC3E,mBAAiB,IAAI,WAAW,OAAO;AACvC,iBAAA;AACF;AACA,SAAS,eAAe,WAAyB;AAC/C,MAAI,iBAAiB,OAAO,SAAS,EAAG,gBAAA;AAC1C;AACA,SAAS,kBAAkB,UAAkC;AAC3D,oBAAkB,IAAI,QAAQ;AAC9B,SAAO,MAAM;AACX,sBAAkB,OAAO,QAAQ;AAAA,EACnC;AACF;AACA,MAAM,sBAAsB,MAAc;AAO1C,SAAS,gBAAgB,OAAgB,gBAA2D;AAClG,QAAM,MAAMA,WAAAA,iBAAiB,cAAc,KAAK,CAAA;AAChD,MAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,oBAAoB,OAAO;AAC5E,UAAM,QAAS,MAAsC;AACrD,QAAI,OAAO,UAAU,YAAY,UAAU,MAAM;AAC/C,iBAAW,MAAM,OAAO,KAAK,KAAK,EAAG,KAAI,CAAC,IAAI,SAAS,EAAE,EAAG,KAAI,KAAK,EAAE;AAAA,IACzE;AAAA,EACF;AACA,SAAO;AACT;AASA,SAAS,sBACP,eACA,oBACS;AACT,MAAI,kBAAkB,OAAW,QAAO;AACxC,QAAM,MAAMA,WAAAA,iBAAiB,kBAAkB;AAC/C,MAAI,QAAQ,KAAM,QAAO;AACzB,SAAO,IAAI,MAAM,CAAC,OAAO,cAAc,SAAS,EAAE,CAAC;AACrD;AA6FO,SAAS,4BAEd,UAA8C,IAAsC;;AACpF,QAAM;AAAA,IACJ,qBAAqBC,WAAAA;AAAAA,IACrB,uBAAuBC,WAAAA;AAAAA,IACvB;AAAA,IACA;AAAA,EAAA,IACE;AACJ,QAAM,cAAcC,eAAAA,wBAAA;AAGpB,QAAM,WAAUC,oBAAAA,iBAAA,EAAmB,kBAAnBA,mBAAkC,KAAK;AACvD,QAAM,YAAY,mCAAS;AAK3B,QAAM,YAAYC,eAAAA,kBAAkBC,qCAA0B;AAC9D,QAAM,qBAAqBC,WAAAA,uBAAuB,SAAS;AAE3D,QAAM,OAAOC,WAAAA,eAAe,mCAAS,OAAO;AAC5C,QAAM,iBAAiBC,MAAAA,QAAQ,MAAMC,WAAAA,sBAAsB,IAAI,GAAG,CAAC,IAAI,CAAC;AAExE,QAAM,YAAYC,iBAAAA,iBAAA;AAIlB,QAAM,SAASN,eAAAA,kBAAkBO,8BAAmB;AACpD,QAAM,aACJ,YAAY,UAAa,YAAYJ,WAAAA,eAAeK,WAAAA,uBAAuB,MAAM,CAAC,IAAI;AACxF,QAAM,uBAAuBJ,MAAAA,QAAQ,MAAMC,WAAAA,sBAAsB,UAAU,GAAG,CAAC,UAAU,CAAC;AAI1F,QAAM,mBAAmBI,MAAAA,OAAe,MAAS;AACjD,MAAI,cAAc,OAAW,kBAAiB,UAAU;AACxDC,6BAAqB,mBAAmB,qBAAqB,mBAAmB;AAChF,QAAM,gBACJ,iBAAiB,YAAY,SAAY,SAAY,iBAAiB,IAAI,iBAAiB,OAAO;AACpG,QAAM,gBAAgBF,WAAAA,uBAAuB,MAAM,MAAM;AACzDG,QAAAA,UAAU,MAAM;AACd,QAAI,cAAc,OAAW;AAC7B,WAAO,MAAM;AAGX,UAAI,iBAAiB,YAAY,UAAW,gBAAe,SAAS;AAAA,IACtE;AAAA,EACF,GAAG,CAAC,SAAS,CAAC;AACdA,QAAAA,UAAU,MAAM;AACd,QAAI,iBAAiB,iBAAiB,YAAY,OAAW,gBAAe,iBAAiB,OAAO;AAAA,EACtG,GAAG,CAAC,aAAa,CAAC;AAClBA,QAAAA;AAAAA,IACE,MAAM,MAAM;AACV,UAAI,iBAAiB,YAAY,OAAW,gBAAe,iBAAiB,OAAO;AAAA,IACrF;AAAA,IACA,CAAA;AAAA,EAAC;AAEH,QAAM,WAAW,sBAAsB,eAAe,oBAAoB,IAAI,OAAO;AACrF,QAAM,qBAAqB,aAAa,aAAa,uBAAuB;AAC5E,QAAM,sBACJX,eAAAA,kBAAkBY,WAAAA,uBAAuB,KAAK;AAEhD,QAAM,EAAE,SAAS,QAAQ,aAAA,IAAiBC,WAAAA,sBAA8B;AAAA,IACtE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAAA;AAAA,IAGA,YAAY,CAAC,IAAI,UACf,YAAY;AAAA,MACV,MAAM;AAAA,MACN,WAAW;AAAA,MACX,UAAU,EAAE,MAAM,UAAU,MAAA;AAAA,IAAM,CACnC;AAAA,EAAA,CACJ;AAED,QAAM,SAASC,MAAAA;AAAAA,IACb,CAAC,UAAkB;AACjB,UAAI,cAAc,QAAW;AAC3B,uBAAe,WAAW,gBAAgB,OAAO,cAAc,CAAC;AAAA,MAClE;AACA,aAAO,aAAa,KAAK;AAAA,IAC3B;AAAA,IACA,CAAC,WAAW,gBAAgB,YAAY;AAAA,EAAA;AAG1C,QAAM,oBAAoBA,MAAAA;AAAAA,IACxB,CAAC,UACC,cAAc,SACV,OAAO,EAAE,gBAAgB,MAAA,CAA4B,IACrD,YAAY,EAAE,MAAM,kBAAkB,eAAe,OAAO;AAAA,IAClE,CAAC,WAAW,QAAQ,WAAW;AAAA,EAAA;AAGjC,QAAM,oBAAoBA,MAAAA;AAAAA,IACxB,CAAC,OAAe,YAAY,EAAE,MAAM,mBAAmB,WAAW,IAAI;AAAA,IACtE,CAAC,WAAW;AAAA,EAAA;AAGd,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAEJ;;"}
1
+ {"version":3,"file":"use-statewire-approval-request.cjs","sources":["../../src/chat/use-statewire-approval-request.ts"],"sourcesContent":["import type { StatewireThread } from '@assistant-ui/react-statewire';\nimport {\n useStatewireRuns,\n useStatewireSendCommand,\n useStatewireState,\n} from '@assistant-ui/react-statewire';\nimport {\n type AbandonedInputRequest,\n asHitlApproval,\n findAbandonedInterrupt,\n HITL_PENDING_RESUME_GRACE_MS,\n type HitlApprovalPayload,\n interruptMirrorPayload,\n isApprovalCardInterrupt,\n laneInterruptIds,\n type PendingActionRequest,\n pendingActionRequests,\n readAbandonedInputRequests,\n readInterruptMirror,\n readQueuedLaneDecisions,\n toolCallIdsAwaitingApproval,\n useApprovalResumeLock,\n} from '@athenaintel/agent-runtime';\nimport {\n createContext,\n createElement,\n type ReactNode,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useSyncExternalStore,\n} from 'react';\nimport { useAthenaRunLive } from './use-athena-run-live';\n\ndeclare module '@assistant-ui/core' {\n namespace Assistant {\n interface Commands {\n /**\n * Decide per-dispatch subagent lanes while the parent run is still\n * streaming (`DeepAgentThread.run_lane_input`). Keys are the lanes'\n * langgraph interrupt ids; the host matches them against the lanes its\n * mirrored interrupt currently parks, answers at once when the run is\n * already parked, and otherwise holds them until it parks — stale or\n * unknown ids are ignored, never carried to a later interrupt.\n */\n runLaneInput: {\n readonly type: 'run/lane-input';\n readonly laneDecisions: Readonly<Record<string, StatewireThread.InputResponse>>;\n };\n /**\n * Re-send the lane decisions the host still holds queued as their\n * approver's resume of the parked request (`DeepAgentThread.run_lane_replay`).\n * The host resumes under the meta the approver's `run/lane-input`\n * recorded and refuses any other caller — every attached client reads\n * the same queue, and only the one that queued it may turn it into a\n * resume. Carries no decisions: the host replays what it recorded.\n */\n runLaneReplay: {\n readonly type: 'run/lane-replay';\n readonly requestId: string;\n };\n }\n }\n}\n\nconst NO_QUEUED_LANE_DECISIONS: Readonly<Record<string, unknown>> = Object.freeze({});\nconst NO_ACTION_REQUESTS: PendingActionRequest[] = [];\n\n/**\n * Lane ids of the parked requests this client resumed, keyed by request id\n * and shared by every hook instance on the page (approval card,\n * waiting-on-you banner, host editors) so all of them treat a lingering\n * mirror the same way. Request ids are unique per parked interrupt, so an\n * instance only ever consults the record of the request it saw parked: two\n * chats mounted side by side cannot suppress or clear each other's. A record\n * is retired once the host drops that request's mirror (the resume run\n * started), the surface sees a different request park, or it unmounts.\n */\nconst answeredRequests = new Map<string, readonly string[]>();\nconst answeredListeners = new Set<() => void>();\nlet answeredVersion = 0;\nfunction notifyAnswered(): void {\n answeredVersion += 1;\n for (const listener of answeredListeners) listener();\n}\nfunction recordAnswered(requestId: string, laneIds: readonly string[]): void {\n answeredRequests.set(requestId, laneIds);\n notifyAnswered();\n}\nfunction forgetAnswered(requestId: string): void {\n if (answeredRequests.delete(requestId)) notifyAnswered();\n}\nfunction subscribeAnswered(listener: () => void): () => void {\n answeredListeners.add(listener);\n return () => {\n answeredListeners.delete(listener);\n };\n}\nconst readAnsweredVersion = (): number => answeredVersion;\n\n/**\n * The lanes a resume of the parked request settles: every lane of the request\n * (a resume answers the whole park — lanes already queued through\n * `run/lane-input` ride along) plus any lane named in the `lane_decisions` map.\n */\nfunction answeredLaneIds(value: unknown, actionRequests: readonly PendingActionRequest[]): string[] {\n const ids = laneInterruptIds(actionRequests) ?? [];\n if (typeof value === 'object' && value !== null && 'lane_decisions' in value) {\n const lanes = (value as { lane_decisions: unknown }).lane_decisions;\n if (typeof lanes === 'object' && lanes !== null) {\n for (const id of Object.keys(lanes)) if (!ids.includes(id)) ids.push(id);\n }\n }\n return ids;\n}\n\n/**\n * Whether the host's mirror still shows an interrupt this client already\n * answered. After `run/input` the host drops the parked request at once but\n * keeps `__interrupt__` until the resume run starts and clears it (seconds on\n * a cold checkpoint); without this check the card would re-offer the SAME\n * approval from the mirror, buttons live, and then fold it away again.\n */\nfunction mirrorAlreadyAnswered(\n answeredLanes: readonly string[] | undefined,\n liveActionRequests: readonly PendingActionRequest[],\n): boolean {\n if (answeredLanes === undefined) return false;\n const ids = laneInterruptIds(liveActionRequests);\n if (ids === null) return false;\n return ids.every((id) => answeredLanes.includes(id));\n}\n\n/** Selects which pending interrupt an approval surface answers. */\nexport type StatewireInterruptPredicate = (\n request: StatewireThread.InputRequestState,\n) => request is StatewireThread.CustomInputRequest;\n\nexport interface UseStatewireApprovalRequestOptions {\n /**\n * Which pending interrupt to answer. Defaults to `isApprovalCardInterrupt`\n * (client-tool parks excluded — the client-tool bridge owns those, and a\n * generic resume would corrupt the parked tool call).\n */\n interruptPredicate?: StatewireInterruptPredicate;\n /**\n * How long a sent decision keeps the actions locked when no resume run ever\n * starts. Defaults to {@link HITL_PENDING_RESUME_GRACE_MS}.\n */\n pendingResumeGraceMs?: number;\n /**\n * The host refused the `run/input` (or the transport lost it): the\n * optimistic fold rolls back, the request is on screen again with its\n * actions re-enabled, and this is the surface's one chance to say why.\n */\n onResumeRejected?: (error: unknown, requestId: string) => void;\n /** See {@link UseApprovalResumeLockOptions.onResumeRetry}. */\n onResumeRetry?: (error: unknown, requestId: string, attempt: number) => void;\n}\n\nexport interface StatewireApprovalRequest<TValue> {\n /** The pending interrupt this surface answers, if any. */\n request: StatewireThread.CustomInputRequest | undefined;\n requestId: string | undefined;\n /** The payload narrowed to the Athena HITL approval shape, or `null`. */\n hitl: HitlApprovalPayload | null;\n /** Every gated call the approval covers, in decision order (empty for non-HITL parks). */\n actionRequests: PendingActionRequest[];\n /** An interrupt a non-resume dispatch dropped — the \"approval was cancelled\" notice. */\n abandonedInterrupt: AbandonedInputRequest | undefined;\n /**\n * The mirrored interrupt's HITL payload while the run is still live and no\n * input request is answerable: per-dispatch `task` lanes parked on their\n * gates while sibling lanes stream. `null` once the run parks (the same\n * lanes are then `hitl` / `actionRequests`) and when nothing is parked.\n */\n liveHitl: HitlApprovalPayload | null;\n /** Every gated call `liveHitl` covers (empty when it is `null`). */\n liveActionRequests: PendingActionRequest[];\n /**\n * The decisions the host already holds from a `run/lane-input`, keyed by\n * langgraph interrupt id, to be answered when the run parks — a queued lane\n * reads as decided on every attached client, not just the one that sent it.\n */\n queuedLaneDecisions: Readonly<Record<string, unknown>>;\n /** True after a resume until the request identity changes (or recovery fires). */\n pending: boolean;\n /**\n * Answer the request with `{ type: 'run/input', requestId, response: { type: 'resume', value } }`.\n * Returns the dispatch promise (settles when the host accepts, rejects when\n * it refuses), or `undefined` when the lock dropped the send.\n */\n resume: (value: TValue) => Promise<unknown> | undefined;\n /**\n * Decide per-dispatch lanes by langgraph interrupt id. With a pending\n * request this is the native `lane_decisions` resume through the lock;\n * without one (the run is still streaming siblings) it is `run/lane-input`,\n * which the host queues and answers on the park. Returns the dispatch\n * promise, or `undefined` when the lock dropped a resume.\n */\n sendLaneDecisions: (\n lanes: Readonly<Record<string, StatewireThread.InputResponse>>,\n ) => Promise<unknown> | undefined;\n /**\n * Ask the host to resume the parked `requestId` with the lane decisions it\n * still holds queued, as their approver (`run/lane-replay`). For the card\n * that queued them, after the host's own answerer has stayed silent past\n * its budget; the host refuses every other caller. Settles when the host\n * accepts, rejects when it refuses.\n */\n replayQueuedLanes: (requestId: string) => Promise<unknown>;\n}\n\n/**\n * The headless half of every statewire approval surface: selects the pending\n * interrupt from the runs projection, narrows its payload, reads the\n * host-published abandoned interrupts, and wires the shared optimistic resume\n * lock to the thread's `run/input` command. `StatewireApprovalCard` renders\n * over it; hosts with their own decision UI (per-lane subagent cards) build\n * on it directly so the selection and lock semantics cannot drift.\n *\n * Requires a statewire aui scope (throws outside one, like every\n * `useStatewire*` hook) — gate the mount with `hasStatewireThreadExtras`.\n */\nexport function useStatewireApprovalRequest<\n TValue extends StatewireThread.InputResponse = Record<string, string>,\n>(options: UseStatewireApprovalRequestOptions = {}): StatewireApprovalRequest<TValue> {\n const {\n interruptPredicate = isApprovalCardInterrupt,\n pendingResumeGraceMs = HITL_PENDING_RESUME_GRACE_MS,\n onResumeRejected,\n onResumeRetry,\n } = options;\n const sendCommand = useStatewireSendCommand();\n // The runs projection is memoized by the lib, so this derivation is\n // reference-stable between state updates.\n const request = useStatewireRuns().inputRequests?.find(interruptPredicate);\n const requestId = request?.id;\n\n // The host publishes the interrupts a non-resume dispatch dropped. Select\n // the raw array reference (pre-stream-safe) and derive inline; a `.find`\n // selector would return a fresh object every update.\n const abandoned = useStatewireState(readAbandonedInputRequests);\n const abandonedInterrupt = findAbandonedInterrupt(abandoned);\n\n const hitl = asHitlApproval(request?.payload);\n const actionRequests = useMemo(() => pendingActionRequests(hitl), [hitl]);\n\n const isRunning = useAthenaRunLive();\n // The host mirrors the interrupt into state as soon as a lane parks — while\n // the run manager still reports `running` (siblings streaming) and has no\n // request to answer. Raw reference selectors; derive inline.\n const mirror = useStatewireState(readInterruptMirror);\n const mirrorHitl =\n request === undefined && isRunning ? asHitlApproval(interruptMirrorPayload(mirror)) : null;\n const mirrorActionRequests = useMemo(() => pendingActionRequests(mirrorHitl), [mirrorHitl]);\n\n // The request this surface last saw parked: the only record it may read\n // or retire (the mirror it watches is the one that request's resume clears).\n const lastRequestIdRef = useRef<string>(undefined);\n if (requestId !== undefined) lastRequestIdRef.current = requestId;\n useSyncExternalStore(subscribeAnswered, readAnsweredVersion, readAnsweredVersion);\n const answeredLanes =\n lastRequestIdRef.current === undefined ? undefined : answeredRequests.get(lastRequestIdRef.current);\n const mirrorCleared = interruptMirrorPayload(mirror) === undefined;\n useEffect(() => {\n if (requestId === undefined) return;\n return () => {\n // A different request parks next (or this one unparks for good): the\n // record of this one is stale once it is not the one on screen.\n if (lastRequestIdRef.current !== requestId) forgetAnswered(requestId);\n };\n }, [requestId]);\n useEffect(() => {\n if (mirrorCleared && lastRequestIdRef.current !== undefined) forgetAnswered(lastRequestIdRef.current);\n }, [mirrorCleared]);\n useEffect(\n () => () => {\n if (lastRequestIdRef.current !== undefined) forgetAnswered(lastRequestIdRef.current);\n },\n [],\n );\n const liveHitl = mirrorAlreadyAnswered(answeredLanes, mirrorActionRequests) ? null : mirrorHitl;\n const liveActionRequests = liveHitl === mirrorHitl ? mirrorActionRequests : NO_ACTION_REQUESTS;\n const queuedLaneDecisions =\n useStatewireState(readQueuedLaneDecisions) ?? NO_QUEUED_LANE_DECISIONS;\n\n const { pending, resume: resumeLocked } = useApprovalResumeLock<TValue>({\n requestId,\n isRunning,\n pendingResumeGraceMs,\n onResumeRejected,\n onResumeRetry,\n // The dispatch promise is handed to the lock: a refusal releases it and\n // reaches `onResumeRejected`.\n sendResume: (id, value) =>\n sendCommand({\n type: 'run/input',\n requestId: id,\n response: { type: 'resume', value },\n }),\n });\n\n const resume = useCallback(\n (value: TValue) => {\n if (requestId !== undefined) {\n recordAnswered(requestId, answeredLaneIds(value, actionRequests));\n }\n return resumeLocked(value);\n },\n [requestId, actionRequests, resumeLocked],\n );\n\n const sendLaneDecisions = useCallback(\n (lanes: Readonly<Record<string, StatewireThread.InputResponse>>) =>\n requestId !== undefined\n ? resume({ lane_decisions: lanes } as unknown as TValue)\n : sendCommand({ type: 'run/lane-input', laneDecisions: lanes }),\n [requestId, resume, sendCommand],\n );\n\n const replayQueuedLanes = useCallback(\n (id: string) => sendCommand({ type: 'run/lane-replay', requestId: id }),\n [sendCommand],\n );\n\n return {\n request,\n requestId,\n hitl,\n actionRequests,\n liveHitl,\n liveActionRequests,\n queuedLaneDecisions,\n abandonedInterrupt,\n pending,\n resume,\n sendLaneDecisions,\n replayQueuedLanes,\n };\n}\n\n/**\n * What the run waits on a person's approval for: the one read every surface\n * that shows a parked step makes (the SDK chat's turns and subagent cards,\n * Olympus's lane cards and step lists), so they all agree with the approval\n * card. The join from an approval to the calls, lanes and steps it gates is\n * agent-runtime's (`toolCallIdsAwaitingApproval`, `subagentAwaitingApproval`,\n * `useTurnToolCallsAwaitingApproval`). Read-only: nothing here sends a command.\n */\nexport interface StatewireApprovalWait {\n /**\n * The gated calls still waiting on a decision, by `tool_call_id`: a step\n * holding one waits for approval, and so does a subagent lane whose own\n * dispatch, or a call it made, is one. Keeps its identity while its ids are\n * unchanged.\n */\n toolCallIds: ReadonlySet<string>;\n /**\n * The run is parked on a request a person answers (an approval, a\n * question): nothing runs until someone answers it, so no step's silence is\n * a stall.\n */\n runParked: boolean;\n}\n\nconst NO_WAITING_TOOL_CALL_IDS: ReadonlySet<string> = new Set();\n\n/** Nothing waits on a person. */\nconst NOTHING_WAITS: StatewireApprovalWait = {\n toolCallIds: NO_WAITING_TOOL_CALL_IDS,\n runParked: false,\n};\n\n/** Joins call ids into one selector value; an id never holds it. */\nconst TOOL_CALL_ID_SEPARATOR = '\\n';\n\nfunction toolCallIdSet(key: string): ReadonlySet<string> {\n return key === '' ? NO_WAITING_TOOL_CALL_IDS : new Set(key.split(TOOL_CALL_ID_SEPARATOR));\n}\n\n/**\n * The run's approval wait: the gated calls of the approval on screen (the\n * parked request's, else the host's mirror of a lane parked while its\n * siblings still stream) that nobody has answered, less the lanes whose\n * decision the host already holds (`queuedLaneDecisions`: a lane decided live\n * waits for the run to park, not for anyone), and whether the run is parked.\n * It clears the moment the approval is answered.\n *\n * Requires a statewire aui scope (throws outside one), like\n * {@link useStatewireApprovalRequest}.\n */\nexport function useStatewireApprovalWait(): StatewireApprovalWait {\n const { requestId, actionRequests, liveActionRequests, queuedLaneDecisions } =\n useStatewireApprovalRequest();\n const runParked = requestId !== undefined;\n const ids = toolCallIdsAwaitingApproval({\n actionRequests: runParked ? actionRequests : liveActionRequests,\n queuedLaneDecisions,\n });\n // A fresh set per state update: key it, so a reader re-renders only when the ids change.\n const key = [...ids].sort().join(TOOL_CALL_ID_SEPARATOR);\n return useMemo(\n () => (key === '' && !runParked ? NOTHING_WAITS : { toolCallIds: toolCallIdSet(key), runParked }),\n [key, runParked],\n );\n}\n\nconst StatewireApprovalWaitContext = createContext<StatewireApprovalWait>(NOTHING_WAITS);\n\n/**\n * Reads the run's approval wait once for everything below it: `AthenaChat`'s\n * turns and subagent cards. Needs a statewire aui scope.\n */\nexport function StatewireApprovalWaitProvider({ children }: { children?: ReactNode }) {\n return createElement(\n StatewireApprovalWaitContext.Provider,\n { value: useStatewireApprovalWait() },\n children,\n );\n}\n\n/**\n * The nearest {@link StatewireApprovalWaitProvider}'s wait. Without one (a\n * host's own thread), nothing waits, as before the SDK read it.\n */\nexport function useApprovalWaitInScope(): StatewireApprovalWait {\n return useContext(StatewireApprovalWaitContext);\n}\n"],"names":["laneInterruptIds","isApprovalCardInterrupt","HITL_PENDING_RESUME_GRACE_MS","useStatewireSendCommand","useStatewireRuns","useStatewireState","readAbandonedInputRequests","findAbandonedInterrupt","asHitlApproval","useMemo","pendingActionRequests","useAthenaRunLive","readInterruptMirror","interruptMirrorPayload","useRef","useSyncExternalStore","useEffect","readQueuedLaneDecisions","useApprovalResumeLock","useCallback","toolCallIdsAwaitingApproval","createContext","createElement","useContext"],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  import type { StatewireThread } from '@assistant-ui/react-statewire';
2
- import { type AbandonedInputRequest, type HitlApprovalPayload, type PendingActionRequest } from '@athenaintel/agent-runtime';
2
+ import { type AbandonedInputRequest, type HitlApprovalPayload, type PendingActionRequest } from '../agent-runtime/src/index';
3
+ import { type ReactNode } from 'react';
3
4
  declare module '@assistant-ui/core' {
4
5
  namespace Assistant {
5
6
  interface Commands {
@@ -115,3 +116,50 @@ export interface StatewireApprovalRequest<TValue> {
115
116
  * `useStatewire*` hook) — gate the mount with `hasStatewireThreadExtras`.
116
117
  */
117
118
  export declare function useStatewireApprovalRequest<TValue extends StatewireThread.InputResponse = Record<string, string>>(options?: UseStatewireApprovalRequestOptions): StatewireApprovalRequest<TValue>;
119
+ /**
120
+ * What the run waits on a person's approval for: the one read every surface
121
+ * that shows a parked step makes (the SDK chat's turns and subagent cards,
122
+ * Olympus's lane cards and step lists), so they all agree with the approval
123
+ * card. The join from an approval to the calls, lanes and steps it gates is
124
+ * agent-runtime's (`toolCallIdsAwaitingApproval`, `subagentAwaitingApproval`,
125
+ * `useTurnToolCallsAwaitingApproval`). Read-only: nothing here sends a command.
126
+ */
127
+ export interface StatewireApprovalWait {
128
+ /**
129
+ * The gated calls still waiting on a decision, by `tool_call_id`: a step
130
+ * holding one waits for approval, and so does a subagent lane whose own
131
+ * dispatch, or a call it made, is one. Keeps its identity while its ids are
132
+ * unchanged.
133
+ */
134
+ toolCallIds: ReadonlySet<string>;
135
+ /**
136
+ * The run is parked on a request a person answers (an approval, a
137
+ * question): nothing runs until someone answers it, so no step's silence is
138
+ * a stall.
139
+ */
140
+ runParked: boolean;
141
+ }
142
+ /**
143
+ * The run's approval wait: the gated calls of the approval on screen (the
144
+ * parked request's, else the host's mirror of a lane parked while its
145
+ * siblings still stream) that nobody has answered, less the lanes whose
146
+ * decision the host already holds (`queuedLaneDecisions`: a lane decided live
147
+ * waits for the run to park, not for anyone), and whether the run is parked.
148
+ * It clears the moment the approval is answered.
149
+ *
150
+ * Requires a statewire aui scope (throws outside one), like
151
+ * {@link useStatewireApprovalRequest}.
152
+ */
153
+ export declare function useStatewireApprovalWait(): StatewireApprovalWait;
154
+ /**
155
+ * Reads the run's approval wait once for everything below it: `AthenaChat`'s
156
+ * turns and subagent cards. Needs a statewire aui scope.
157
+ */
158
+ export declare function StatewireApprovalWaitProvider({ children }: {
159
+ children?: ReactNode;
160
+ }): import("react").FunctionComponentElement<import("react").ProviderProps<StatewireApprovalWait>>;
161
+ /**
162
+ * The nearest {@link StatewireApprovalWaitProvider}'s wait. Without one (a
163
+ * host's own thread), nothing waits, as before the SDK read it.
164
+ */
165
+ export declare function useApprovalWaitInScope(): StatewireApprovalWait;
@@ -1,7 +1,7 @@
1
1
  import { useStatewireSendCommand, useStatewireRuns, useStatewireState } from "@assistant-ui/react-statewire";
2
- import { useMemo, useRef, useSyncExternalStore, useEffect, useCallback } from "react";
2
+ import { useMemo, useRef, useSyncExternalStore, useEffect, useCallback, useContext, createContext, createElement } from "react";
3
3
  import { useAthenaRunLive } from "./use-athena-run-live.js";
4
- import { isApprovalCardInterrupt, HITL_PENDING_RESUME_GRACE_MS, readAbandonedInputRequests, findAbandonedInterrupt, asHitlApproval, pendingActionRequests, readInterruptMirror, interruptMirrorPayload, readQueuedLaneDecisions, useApprovalResumeLock, laneInterruptIds } from "../agent-runtime/src/interrupts.js";
4
+ import { isApprovalCardInterrupt, HITL_PENDING_RESUME_GRACE_MS, readAbandonedInputRequests, findAbandonedInterrupt, asHitlApproval, pendingActionRequests, readInterruptMirror, interruptMirrorPayload, readQueuedLaneDecisions, useApprovalResumeLock, toolCallIdsAwaitingApproval, laneInterruptIds } from "../agent-runtime/src/interrupts.js";
5
5
  const NO_QUEUED_LANE_DECISIONS = Object.freeze({});
6
6
  const NO_ACTION_REQUESTS = [];
7
7
  const answeredRequests = /* @__PURE__ */ new Map();
@@ -129,7 +129,43 @@ function useStatewireApprovalRequest(options = {}) {
129
129
  replayQueuedLanes
130
130
  };
131
131
  }
132
+ const NO_WAITING_TOOL_CALL_IDS = /* @__PURE__ */ new Set();
133
+ const NOTHING_WAITS = {
134
+ toolCallIds: NO_WAITING_TOOL_CALL_IDS,
135
+ runParked: false
136
+ };
137
+ const TOOL_CALL_ID_SEPARATOR = "\n";
138
+ function toolCallIdSet(key) {
139
+ return key === "" ? NO_WAITING_TOOL_CALL_IDS : new Set(key.split(TOOL_CALL_ID_SEPARATOR));
140
+ }
141
+ function useStatewireApprovalWait() {
142
+ const { requestId, actionRequests, liveActionRequests, queuedLaneDecisions } = useStatewireApprovalRequest();
143
+ const runParked = requestId !== void 0;
144
+ const ids = toolCallIdsAwaitingApproval({
145
+ actionRequests: runParked ? actionRequests : liveActionRequests,
146
+ queuedLaneDecisions
147
+ });
148
+ const key = [...ids].sort().join(TOOL_CALL_ID_SEPARATOR);
149
+ return useMemo(
150
+ () => key === "" && !runParked ? NOTHING_WAITS : { toolCallIds: toolCallIdSet(key), runParked },
151
+ [key, runParked]
152
+ );
153
+ }
154
+ const StatewireApprovalWaitContext = createContext(NOTHING_WAITS);
155
+ function StatewireApprovalWaitProvider({ children }) {
156
+ return createElement(
157
+ StatewireApprovalWaitContext.Provider,
158
+ { value: useStatewireApprovalWait() },
159
+ children
160
+ );
161
+ }
162
+ function useApprovalWaitInScope() {
163
+ return useContext(StatewireApprovalWaitContext);
164
+ }
132
165
  export {
133
- useStatewireApprovalRequest
166
+ StatewireApprovalWaitProvider,
167
+ useApprovalWaitInScope,
168
+ useStatewireApprovalRequest,
169
+ useStatewireApprovalWait
134
170
  };
135
171
  //# sourceMappingURL=use-statewire-approval-request.js.map