@agent-native/toolkit 0.228.0-nightly-20261111212500 → 0.228.0

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 (361) hide show
  1. package/agent-native.eject.json +2 -0
  2. package/dist/app/agentkit/react/approval-card.d.ts.map +1 -1
  3. package/dist/app/agentkit/react/approval-card.js +5 -3
  4. package/dist/app/agentkit/react/approval-card.js.map +1 -1
  5. package/dist/app/agentkit/react/code-block.d.ts +32 -0
  6. package/dist/app/agentkit/react/code-block.d.ts.map +1 -0
  7. package/dist/app/agentkit/react/code-block.js +125 -0
  8. package/dist/app/agentkit/react/code-block.js.map +1 -0
  9. package/dist/app/agentkit/react/components.d.ts +33 -14
  10. package/dist/app/agentkit/react/components.d.ts.map +1 -1
  11. package/dist/app/agentkit/react/components.js +843 -168
  12. package/dist/app/agentkit/react/components.js.map +1 -1
  13. package/dist/app/agentkit/react/context-usage.d.ts +45 -0
  14. package/dist/app/agentkit/react/context-usage.d.ts.map +1 -0
  15. package/dist/app/agentkit/react/context-usage.js +93 -0
  16. package/dist/app/agentkit/react/context-usage.js.map +1 -0
  17. package/dist/app/agentkit/react/context.d.ts +42 -3
  18. package/dist/app/agentkit/react/context.d.ts.map +1 -1
  19. package/dist/app/agentkit/react/context.js +46 -1
  20. package/dist/app/agentkit/react/context.js.map +1 -1
  21. package/dist/app/agentkit/react/disclosure-content.d.ts +12 -0
  22. package/dist/app/agentkit/react/disclosure-content.d.ts.map +1 -0
  23. package/dist/app/agentkit/react/disclosure-content.js +33 -0
  24. package/dist/app/agentkit/react/disclosure-content.js.map +1 -0
  25. package/dist/app/agentkit/react/duration.d.ts +6 -0
  26. package/dist/app/agentkit/react/duration.d.ts.map +1 -0
  27. package/dist/app/agentkit/react/duration.js +21 -0
  28. package/dist/app/agentkit/react/duration.js.map +1 -0
  29. package/dist/app/agentkit/react/file-change.d.ts +33 -0
  30. package/dist/app/agentkit/react/file-change.d.ts.map +1 -0
  31. package/dist/app/agentkit/react/file-change.js +83 -0
  32. package/dist/app/agentkit/react/file-change.js.map +1 -0
  33. package/dist/app/agentkit/react/file-diff.d.ts +17 -0
  34. package/dist/app/agentkit/react/file-diff.d.ts.map +1 -0
  35. package/dist/app/agentkit/react/file-diff.js +94 -0
  36. package/dist/app/agentkit/react/file-diff.js.map +1 -0
  37. package/dist/app/agentkit/react/index.d.ts +7 -0
  38. package/dist/app/agentkit/react/index.d.ts.map +1 -1
  39. package/dist/app/agentkit/react/index.js +7 -0
  40. package/dist/app/agentkit/react/index.js.map +1 -1
  41. package/dist/app/agentkit/react/question-card.d.ts +67 -0
  42. package/dist/app/agentkit/react/question-card.d.ts.map +1 -0
  43. package/dist/app/agentkit/react/question-card.js +198 -0
  44. package/dist/app/agentkit/react/question-card.js.map +1 -0
  45. package/dist/app/agentkit/react/root.d.ts +3 -2
  46. package/dist/app/agentkit/react/root.d.ts.map +1 -1
  47. package/dist/app/agentkit/react/root.js +2 -2
  48. package/dist/app/agentkit/react/root.js.map +1 -1
  49. package/dist/app/agentkit/react/roving-focus.d.ts +4 -0
  50. package/dist/app/agentkit/react/roving-focus.d.ts.map +1 -0
  51. package/dist/app/agentkit/react/roving-focus.js +75 -0
  52. package/dist/app/agentkit/react/roving-focus.js.map +1 -0
  53. package/dist/app/agentkit/react/stack-trace.d.ts +34 -0
  54. package/dist/app/agentkit/react/stack-trace.d.ts.map +1 -0
  55. package/dist/app/agentkit/react/stack-trace.js +121 -0
  56. package/dist/app/agentkit/react/stack-trace.js.map +1 -0
  57. package/dist/app/agentkit/react/stop-button.d.ts.map +1 -1
  58. package/dist/app/agentkit/react/stop-button.js +22 -6
  59. package/dist/app/agentkit/react/stop-button.js.map +1 -1
  60. package/dist/app/agentkit/react/styles.css +1306 -395
  61. package/dist/app/agentkit/react/terminal.d.ts +28 -0
  62. package/dist/app/agentkit/react/terminal.d.ts.map +1 -0
  63. package/dist/app/agentkit/react/terminal.js +84 -0
  64. package/dist/app/agentkit/react/terminal.js.map +1 -0
  65. package/dist/app/agentkit/react/trace.d.ts +31 -0
  66. package/dist/app/agentkit/react/trace.d.ts.map +1 -0
  67. package/dist/app/agentkit/react/trace.js +73 -0
  68. package/dist/app/agentkit/react/trace.js.map +1 -0
  69. package/dist/app/blocks/library/HighlightedCode.d.ts +2 -1
  70. package/dist/app/blocks/library/HighlightedCode.d.ts.map +1 -1
  71. package/dist/app/blocks/library/HighlightedCode.js +8 -111
  72. package/dist/app/blocks/library/HighlightedCode.js.map +1 -1
  73. package/dist/app/chat/AgentKitAssistantChat.d.ts.map +1 -1
  74. package/dist/app/chat/AgentKitAssistantChat.js +23 -245
  75. package/dist/app/chat/AgentKitAssistantChat.js.map +1 -1
  76. package/dist/app/chat/agentkit-chat/guided-questions.d.ts +15 -1
  77. package/dist/app/chat/agentkit-chat/guided-questions.d.ts.map +1 -1
  78. package/dist/app/chat/agentkit-chat/guided-questions.js +142 -2
  79. package/dist/app/chat/agentkit-chat/guided-questions.js.map +1 -1
  80. package/dist/app/chat/agentkit-chat/history.js +1 -1
  81. package/dist/app/chat/agentkit-chat/history.js.map +1 -1
  82. package/dist/app/chat/agentkit-chat/index.d.ts +1 -1
  83. package/dist/app/chat/agentkit-chat/index.d.ts.map +1 -1
  84. package/dist/app/chat/agentkit-chat/index.js +1 -1
  85. package/dist/app/chat/agentkit-chat/index.js.map +1 -1
  86. package/dist/app/chat/agentkit-chat/labels.d.ts +5 -0
  87. package/dist/app/chat/agentkit-chat/labels.d.ts.map +1 -0
  88. package/dist/app/chat/agentkit-chat/labels.js +245 -0
  89. package/dist/app/chat/agentkit-chat/labels.js.map +1 -0
  90. package/dist/app/chat/agentkit-chat/questions.d.ts +1 -1
  91. package/dist/app/chat/agentkit-chat/questions.d.ts.map +1 -1
  92. package/dist/app/chat/agentkit-chat/questions.js +1 -1
  93. package/dist/app/chat/agentkit-chat/questions.js.map +1 -1
  94. package/dist/app/chat/agentkit-chat/root.d.ts.map +1 -1
  95. package/dist/app/chat/agentkit-chat/root.js +5 -64
  96. package/dist/app/chat/agentkit-chat/root.js.map +1 -1
  97. package/dist/app/chat/agentkit-chat/work-step-labels.d.ts +2 -0
  98. package/dist/app/chat/agentkit-chat/work-step-labels.d.ts.map +1 -1
  99. package/dist/app/chat/agentkit-chat/work-step-labels.js +31 -0
  100. package/dist/app/chat/agentkit-chat/work-step-labels.js.map +1 -1
  101. package/dist/app/chat/chat/markdown-renderer.d.ts +2 -12
  102. package/dist/app/chat/chat/markdown-renderer.d.ts.map +1 -1
  103. package/dist/app/chat/chat/markdown-renderer.js +2 -41
  104. package/dist/app/chat/chat/markdown-renderer.js.map +1 -1
  105. package/dist/app/chat/chat/tool-call-display.d.ts.map +1 -1
  106. package/dist/app/chat/chat/tool-call-display.js +2 -2
  107. package/dist/app/chat/chat/tool-call-display.js.map +1 -1
  108. package/dist/app/chat/conversation/AgentConversation.d.ts.map +1 -1
  109. package/dist/app/chat/conversation/AgentConversation.js +2 -37
  110. package/dist/app/chat/conversation/AgentConversation.js.map +1 -1
  111. package/dist/app/chat/tool-cells/BashCell.d.ts +3 -1
  112. package/dist/app/chat/tool-cells/BashCell.d.ts.map +1 -1
  113. package/dist/app/chat/tool-cells/BashCell.js +4 -40
  114. package/dist/app/chat/tool-cells/BashCell.js.map +1 -1
  115. package/dist/app/chat/tool-cells/EditCell.d.ts.map +1 -1
  116. package/dist/app/chat/tool-cells/EditCell.js +5 -108
  117. package/dist/app/chat/tool-cells/EditCell.js.map +1 -1
  118. package/dist/app/chat/tool-cells/FilesChangedSummary.d.ts.map +1 -1
  119. package/dist/app/chat/tool-cells/FilesChangedSummary.js +23 -81
  120. package/dist/app/chat/tool-cells/FilesChangedSummary.js.map +1 -1
  121. package/dist/app/chat/tool-cells/WriteCell.d.ts.map +1 -1
  122. package/dist/app/chat/tool-cells/WriteCell.js +5 -24
  123. package/dist/app/chat/tool-cells/WriteCell.js.map +1 -1
  124. package/dist/app/code-highlighter.d.ts +11 -0
  125. package/dist/app/code-highlighter.d.ts.map +1 -0
  126. package/dist/app/code-highlighter.js +122 -0
  127. package/dist/app/code-highlighter.js.map +1 -0
  128. package/dist/app/context-xray/ThreadContextRing.js +3 -3
  129. package/dist/app/context-xray/ThreadContextRing.js.map +1 -1
  130. package/dist/app/i18n/catalogs/ar-SA.d.ts.map +1 -1
  131. package/dist/app/i18n/catalogs/ar-SA.js +22 -0
  132. package/dist/app/i18n/catalogs/ar-SA.js.map +1 -1
  133. package/dist/app/i18n/catalogs/de-DE.d.ts.map +1 -1
  134. package/dist/app/i18n/catalogs/de-DE.js +22 -0
  135. package/dist/app/i18n/catalogs/de-DE.js.map +1 -1
  136. package/dist/app/i18n/catalogs/en-US.d.ts +22 -0
  137. package/dist/app/i18n/catalogs/en-US.d.ts.map +1 -1
  138. package/dist/app/i18n/catalogs/en-US.js +22 -0
  139. package/dist/app/i18n/catalogs/en-US.js.map +1 -1
  140. package/dist/app/i18n/catalogs/es-ES.d.ts.map +1 -1
  141. package/dist/app/i18n/catalogs/es-ES.js +22 -0
  142. package/dist/app/i18n/catalogs/es-ES.js.map +1 -1
  143. package/dist/app/i18n/catalogs/fr-FR.d.ts.map +1 -1
  144. package/dist/app/i18n/catalogs/fr-FR.js +22 -0
  145. package/dist/app/i18n/catalogs/fr-FR.js.map +1 -1
  146. package/dist/app/i18n/catalogs/hi-IN.d.ts.map +1 -1
  147. package/dist/app/i18n/catalogs/hi-IN.js +22 -0
  148. package/dist/app/i18n/catalogs/hi-IN.js.map +1 -1
  149. package/dist/app/i18n/catalogs/ja-JP.d.ts.map +1 -1
  150. package/dist/app/i18n/catalogs/ja-JP.js +22 -0
  151. package/dist/app/i18n/catalogs/ja-JP.js.map +1 -1
  152. package/dist/app/i18n/catalogs/ko-KR.d.ts.map +1 -1
  153. package/dist/app/i18n/catalogs/ko-KR.js +22 -0
  154. package/dist/app/i18n/catalogs/ko-KR.js.map +1 -1
  155. package/dist/app/i18n/catalogs/pt-BR.d.ts.map +1 -1
  156. package/dist/app/i18n/catalogs/pt-BR.js +22 -0
  157. package/dist/app/i18n/catalogs/pt-BR.js.map +1 -1
  158. package/dist/app/i18n/catalogs/zh-CN.d.ts.map +1 -1
  159. package/dist/app/i18n/catalogs/zh-CN.js +22 -0
  160. package/dist/app/i18n/catalogs/zh-CN.js.map +1 -1
  161. package/dist/app/i18n/catalogs/zh-TW.d.ts.map +1 -1
  162. package/dist/app/i18n/catalogs/zh-TW.js +22 -0
  163. package/dist/app/i18n/catalogs/zh-TW.js.map +1 -1
  164. package/dist/app/onboarding/first-run-first-paint.d.ts +10 -0
  165. package/dist/app/onboarding/first-run-first-paint.d.ts.map +1 -0
  166. package/dist/app/onboarding/first-run-first-paint.js +22 -0
  167. package/dist/app/onboarding/first-run-first-paint.js.map +1 -0
  168. package/dist/app/onboarding/first-run-startup-gate.d.ts +3 -1
  169. package/dist/app/onboarding/first-run-startup-gate.d.ts.map +1 -1
  170. package/dist/app/onboarding/first-run-startup-gate.js +30 -6
  171. package/dist/app/onboarding/first-run-startup-gate.js.map +1 -1
  172. package/dist/app/providers/AppProviders.d.ts.map +1 -1
  173. package/dist/app/providers/AppProviders.js +9 -2
  174. package/dist/app/providers/AppProviders.js.map +1 -1
  175. package/dist/app/providers/BuilderSignupActivation.d.ts +2 -1
  176. package/dist/app/providers/BuilderSignupActivation.d.ts.map +1 -1
  177. package/dist/app/providers/BuilderSignupActivation.js +6 -3
  178. package/dist/app/providers/BuilderSignupActivation.js.map +1 -1
  179. package/dist/app/shared/AppShellSkeleton.d.ts.map +1 -1
  180. package/dist/app/shared/AppShellSkeleton.js +11 -1
  181. package/dist/app/shared/AppShellSkeleton.js.map +1 -1
  182. package/dist/app/styles/agent-native.css +2 -2
  183. package/dist/app/styles/tokens/agent-kit.css +20 -3
  184. package/dist/composer/AgentSuggestionBar.d.ts.map +1 -1
  185. package/dist/composer/AgentSuggestionBar.js +2 -2
  186. package/dist/composer/AgentSuggestionBar.js.map +1 -1
  187. package/dist/composer/ComposerContextMenu.js +4 -4
  188. package/dist/composer/ComposerContextMenu.js.map +1 -1
  189. package/dist/composer/ComposerContextPicker.d.ts.map +1 -1
  190. package/dist/composer/ComposerContextPicker.js +2 -2
  191. package/dist/composer/ComposerContextPicker.js.map +1 -1
  192. package/dist/composer/ComposerContextPickerDialog.d.ts.map +1 -1
  193. package/dist/composer/ComposerContextPickerDialog.js +2 -2
  194. package/dist/composer/ComposerContextPickerDialog.js.map +1 -1
  195. package/dist/composer/ComposerModePicker.d.ts.map +1 -1
  196. package/dist/composer/ComposerModePicker.js +2 -1
  197. package/dist/composer/ComposerModePicker.js.map +1 -1
  198. package/dist/composer/ComposerPlusMenu.js +1 -1
  199. package/dist/composer/ComposerPlusMenu.js.map +1 -1
  200. package/dist/composer/MentionChip.js +1 -1
  201. package/dist/composer/MentionChip.js.map +1 -1
  202. package/dist/composer/MentionPopover.d.ts +3 -0
  203. package/dist/composer/MentionPopover.d.ts.map +1 -1
  204. package/dist/composer/MentionPopover.js +34 -15
  205. package/dist/composer/MentionPopover.js.map +1 -1
  206. package/dist/composer/MessageQueueDrawer.d.ts.map +1 -1
  207. package/dist/composer/MessageQueueDrawer.js +14 -9
  208. package/dist/composer/MessageQueueDrawer.js.map +1 -1
  209. package/dist/composer/PastedTextChip.d.ts.map +1 -1
  210. package/dist/composer/PastedTextChip.js +14 -18
  211. package/dist/composer/PastedTextChip.js.map +1 -1
  212. package/dist/composer/PromptBar.js +1 -1
  213. package/dist/composer/PromptBar.js.map +1 -1
  214. package/dist/composer/PromptComposer.d.ts.map +1 -1
  215. package/dist/composer/PromptComposer.js +11 -9
  216. package/dist/composer/PromptComposer.js.map +1 -1
  217. package/dist/composer/RealtimeVoiceMode.js +2 -2
  218. package/dist/composer/RealtimeVoiceMode.js.map +1 -1
  219. package/dist/composer/TiptapComposer.d.ts.map +1 -1
  220. package/dist/composer/TiptapComposer.js +52 -89
  221. package/dist/composer/TiptapComposer.js.map +1 -1
  222. package/dist/composer/VoiceButton.d.ts +3 -1
  223. package/dist/composer/VoiceButton.d.ts.map +1 -1
  224. package/dist/composer/VoiceButton.js +10 -8
  225. package/dist/composer/VoiceButton.js.map +1 -1
  226. package/dist/composer/composer-notice.js +3 -3
  227. package/dist/composer/composer-notice.js.map +1 -1
  228. package/dist/composer/extensions/FileReference.js +1 -1
  229. package/dist/composer/extensions/FileReference.js.map +1 -1
  230. package/dist/composer/extensions/SkillReference.js +1 -1
  231. package/dist/composer/extensions/SkillReference.js.map +1 -1
  232. package/dist/composer/popover-surface.d.ts +1 -1
  233. package/dist/composer/popover-surface.d.ts.map +1 -1
  234. package/dist/composer/popover-surface.js +1 -1
  235. package/dist/composer/popover-surface.js.map +1 -1
  236. package/dist/context-ui/ContextUsageRing.d.ts +1 -45
  237. package/dist/context-ui/ContextUsageRing.d.ts.map +1 -1
  238. package/dist/context-ui/ContextUsageRing.js +2 -87
  239. package/dist/context-ui/ContextUsageRing.js.map +1 -1
  240. package/dist/context-ui/index.d.ts +2 -2
  241. package/dist/context-ui/index.d.ts.map +1 -1
  242. package/dist/context-ui/index.js +2 -2
  243. package/dist/context-ui/index.js.map +1 -1
  244. package/package.json +4 -4
  245. package/src/app/agentkit/react/approval-card.tsx +14 -2
  246. package/src/app/agentkit/react/code-block.spec.tsx +154 -0
  247. package/src/app/agentkit/react/code-block.tsx +317 -0
  248. package/src/app/agentkit/react/components.interaction.spec.tsx +7 -0
  249. package/src/app/agentkit/react/components.papercuts.spec.tsx +143 -2
  250. package/src/app/agentkit/react/components.spec.tsx +40 -47
  251. package/src/app/agentkit/react/components.tsx +1533 -413
  252. package/src/app/agentkit/react/composer-context.spec.tsx +35 -0
  253. package/src/app/agentkit/react/context-usage.tsx +353 -0
  254. package/src/app/agentkit/react/context.tsx +93 -1
  255. package/src/app/agentkit/react/disclosure-content.ts +42 -0
  256. package/src/app/agentkit/react/disclosures.spec.tsx +62 -4
  257. package/src/app/agentkit/react/duration.ts +22 -0
  258. package/src/app/agentkit/react/file-change.spec.tsx +124 -0
  259. package/src/app/agentkit/react/file-change.tsx +228 -0
  260. package/src/app/agentkit/react/file-diff.ts +110 -0
  261. package/src/app/agentkit/react/index.ts +7 -0
  262. package/src/app/agentkit/react/lifecycle.spec.tsx +565 -20
  263. package/src/app/agentkit/react/markdown.spec.tsx +18 -8
  264. package/src/app/agentkit/react/message-actions.spec.tsx +55 -1
  265. package/src/app/agentkit/react/notices.spec.tsx +4 -4
  266. package/src/app/agentkit/react/optimistic-send.spec.tsx +43 -0
  267. package/src/app/agentkit/react/question-card.spec.tsx +276 -0
  268. package/src/app/agentkit/react/question-card.tsx +533 -0
  269. package/src/app/agentkit/react/root.tsx +4 -0
  270. package/src/app/agentkit/react/roving-focus.spec.tsx +114 -0
  271. package/src/app/agentkit/react/roving-focus.ts +82 -0
  272. package/src/app/agentkit/react/stack-trace.spec.tsx +177 -0
  273. package/src/app/agentkit/react/stack-trace.tsx +281 -0
  274. package/src/app/agentkit/react/stop-button.spec.tsx +40 -0
  275. package/src/app/agentkit/react/stop-button.tsx +22 -5
  276. package/src/app/agentkit/react/styles.css +1306 -395
  277. package/src/app/agentkit/react/subagent-step.spec.tsx +554 -0
  278. package/src/app/agentkit/react/terminal.spec.tsx +228 -0
  279. package/src/app/agentkit/react/terminal.tsx +228 -0
  280. package/src/app/agentkit/react/trace.spec.tsx +120 -0
  281. package/src/app/agentkit/react/trace.tsx +239 -0
  282. package/src/app/blocks/library/HighlightedCode.tsx +14 -126
  283. package/src/app/chat/AgentKitAssistantChat.spec.tsx +28 -12
  284. package/src/app/chat/AgentKitAssistantChat.tsx +27 -253
  285. package/src/app/chat/agentkit-chat/approval-card.spec.tsx +1 -0
  286. package/src/app/chat/agentkit-chat/guided-questions.flow.spec.tsx +381 -0
  287. package/src/app/chat/agentkit-chat/guided-questions.tsx +236 -3
  288. package/src/app/chat/agentkit-chat/history.tsx +1 -1
  289. package/src/app/chat/agentkit-chat/index.ts +2 -0
  290. package/src/app/chat/agentkit-chat/labels.ts +259 -0
  291. package/src/app/chat/agentkit-chat/questions.ts +2 -0
  292. package/src/app/chat/agentkit-chat/root.spec.tsx +18 -0
  293. package/src/app/chat/agentkit-chat/root.tsx +5 -64
  294. package/src/app/chat/agentkit-chat/work-step-labels.ts +42 -0
  295. package/src/app/chat/chat/markdown-renderer.tsx +2 -59
  296. package/src/app/chat/chat/tool-call-display.spec.tsx +26 -14
  297. package/src/app/chat/chat/tool-call-display.tsx +2 -1
  298. package/src/app/chat/conversation/AgentConversation.tsx +2 -50
  299. package/src/app/chat/tool-cells/BashCell.tsx +14 -136
  300. package/src/app/chat/tool-cells/EditCell.tsx +11 -248
  301. package/src/app/chat/tool-cells/FilesChangedSummary.spec.tsx +62 -5
  302. package/src/app/chat/tool-cells/FilesChangedSummary.tsx +31 -162
  303. package/src/app/chat/tool-cells/WriteCell.tsx +11 -121
  304. package/src/app/code-highlighter.ts +131 -0
  305. package/src/app/context-xray/ThreadContextRing.tsx +7 -7
  306. package/src/app/i18n/catalogs/ar-SA.ts +22 -0
  307. package/src/app/i18n/catalogs/de-DE.ts +22 -0
  308. package/src/app/i18n/catalogs/en-US.ts +22 -0
  309. package/src/app/i18n/catalogs/es-ES.ts +22 -0
  310. package/src/app/i18n/catalogs/fr-FR.ts +22 -0
  311. package/src/app/i18n/catalogs/hi-IN.ts +22 -0
  312. package/src/app/i18n/catalogs/ja-JP.ts +22 -0
  313. package/src/app/i18n/catalogs/ko-KR.ts +22 -0
  314. package/src/app/i18n/catalogs/pt-BR.ts +22 -0
  315. package/src/app/i18n/catalogs/zh-CN.ts +22 -0
  316. package/src/app/i18n/catalogs/zh-TW.ts +22 -0
  317. package/src/app/onboarding/first-run-first-paint.spec.ts +39 -0
  318. package/src/app/onboarding/first-run-first-paint.ts +24 -0
  319. package/src/app/onboarding/first-run-startup-gate.spec.tsx +125 -13
  320. package/src/app/onboarding/first-run-startup-gate.tsx +48 -5
  321. package/src/app/providers/AppProviders.tsx +18 -0
  322. package/src/app/providers/BuilderSignupActivation.tsx +8 -2
  323. package/src/app/shared/AppShellSkeleton.spec.tsx +60 -1
  324. package/src/app/shared/AppShellSkeleton.tsx +31 -1
  325. package/src/app/styles/agent-native.css +2 -2
  326. package/src/app/styles/agent-native.spec.ts +2 -2
  327. package/src/app/styles/tokens/agent-kit.css +20 -3
  328. package/src/composer/AgentSuggestionBar.spec.tsx +3 -1
  329. package/src/composer/AgentSuggestionBar.tsx +5 -2
  330. package/src/composer/ComposerContextMenu.tsx +4 -4
  331. package/src/composer/ComposerContextPicker.tsx +8 -2
  332. package/src/composer/ComposerContextPickerDialog.tsx +5 -2
  333. package/src/composer/ComposerModePicker.tsx +2 -1
  334. package/src/composer/ComposerPlusMenu.tsx +1 -1
  335. package/src/composer/MentionChip.tsx +1 -1
  336. package/src/composer/MentionPopover.spec.tsx +108 -2
  337. package/src/composer/MentionPopover.tsx +93 -17
  338. package/src/composer/MessageQueueDrawer.spec.tsx +5 -5
  339. package/src/composer/MessageQueueDrawer.tsx +19 -12
  340. package/src/composer/PastedTextChip.spec.tsx +36 -0
  341. package/src/composer/PastedTextChip.tsx +52 -58
  342. package/src/composer/PromptBar.tsx +1 -1
  343. package/src/composer/PromptComposer.context.spec.tsx +2 -2
  344. package/src/composer/PromptComposer.submission.spec.tsx +27 -0
  345. package/src/composer/PromptComposer.tsx +17 -9
  346. package/src/composer/RealtimeVoiceMode.tsx +2 -2
  347. package/src/composer/TiptapComposer.model-picker.spec.tsx +23 -82
  348. package/src/composer/TiptapComposer.tsx +68 -145
  349. package/src/composer/VoiceButton.tsx +12 -7
  350. package/src/composer/composer-notice.tsx +3 -3
  351. package/src/composer/extensions/FileReference.tsx +1 -1
  352. package/src/composer/extensions/SkillReference.tsx +1 -1
  353. package/src/composer/popover-surface.ts +1 -1
  354. package/src/context-ui/ContextUsageRing.spec.tsx +33 -8
  355. package/src/context-ui/ContextUsageRing.tsx +13 -348
  356. package/src/context-ui/index.ts +7 -1
  357. package/dist/composer/ModelPickerParts.d.ts +0 -20
  358. package/dist/composer/ModelPickerParts.d.ts.map +0 -1
  359. package/dist/composer/ModelPickerParts.js +0 -77
  360. package/dist/composer/ModelPickerParts.js.map +0 -1
  361. package/src/composer/ModelPickerParts.tsx +0 -188
@@ -1,5 +1,5 @@
1
1
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { IconId, IconThumbUpFilled, IconThumbUp, IconThumbDownFilled, IconThumbDown, IconActivity, IconAlertCircle, IconAlertTriangle, IconArrowDown, IconArrowFork, IconBook2, IconBrain, IconCheck, IconChevronLeft, IconChevronRight, IconCircle, IconCircleCheck, IconClock, IconCode, IconCopy, IconDots, IconFile, IconFolder, IconFileText, IconCheckbox, IconMail, IconUser, IconPresentation, IconStack2, IconMessageChatbot, IconGitBranch, IconLoader2, IconMessage, IconMessageQuestion, IconPlugConnected, IconPlayerPause, IconPlayerPlay, IconPencil, IconRefresh, IconSearch, IconTerminal2, IconChecklist, IconBolt, IconPointFilled, IconTool, IconWorld, IconWorldDownload, IconX, } from "@tabler/icons-react";
2
+ import { IconId, IconThumbUpFilled, IconThumbUp, IconThumbDownFilled, IconThumbDown, IconActivity, IconAlertTriangle, IconArrowDown, IconArrowFork, IconBook2, IconBrain, IconChevronLeft, IconChevronRight, IconCircle, IconCircleCheck, IconClock, IconCode, IconCopy, IconDots, IconFile, IconFolder, IconFileText, IconCheckbox, IconMail, IconUser, IconPresentation, IconStack2, IconMessageChatbot, IconGitBranch, IconLoader2, IconMessage, IconMessageQuestion, IconPlugConnected, IconPlayerPause, IconPlayerPlay, IconPencil, IconRefresh, IconSearch, IconTerminal2, IconChecklist, IconBolt, IconPointFilled, IconTool, IconWorld, IconWorldDownload, IconX, } from "@tabler/icons-react";
3
3
  import { createContext, createElement, Component, Fragment, isValidElement, memo, useCallback, useContext, useEffect, useId, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore, } from "react";
4
4
  import { createPortal } from "react-dom";
5
5
  import ReactMarkdown from "react-markdown";
@@ -13,15 +13,25 @@ import { Skeleton } from "../../../ui/skeleton.js";
13
13
  import { ApprovalCard, approvalOptionDecision, approvalRequestKind, } from "./approval-card.js";
14
14
  import { createAgentKitComposerSubmission, snapshotComposerValue, } from "./composer-submission.js";
15
15
  import { CoreFileStorageSetupContext } from "./core-file-storage.js";
16
+ import { AgentKitDeferClosedContentContext, useUntilFoundContent, } from "./disclosure-content.js";
16
17
  import { splitAgentKitMessageContext } from "@agent-native/agentkit";
17
18
  import { AgentKitCapabilityError, AgentKitUploadError, hasActiveAgentRuns, isCurrentAgentSuggestion, selectAgentSuggestions, } from "@agent-native/agentkit/client";
18
19
  import { inferAgentActivityKind, } from "@agent-native/agentkit/protocol";
20
+ import { prettyLanguageName } from "../../code-highlighter.js";
21
+ import { CodeBlock, CodeBlockActions, CodeBlockContent, CodeBlockCopyButton, CodeBlockFooter, CodeBlockHeader, CodeBlockTitle, } from "./code-block.js";
19
22
  import { defaultAgentKitLabels, useAgentCapability, useAgentConnection, useAgentKit, useAgentKitBeginPendingSubmission, useAgentKitControl, useAgentKitMutation, useAgentKitPendingSubmissions, useAgentKitSelector, useAgentKitSubmissionStarting, useAgentThread, useAgentThreadLoadStatus, } from "./context.js";
23
+ import { formatAgentKitDuration } from "./duration.js";
24
+ import { FileChange } from "./file-change.js";
20
25
  import { scheduleIdleMount } from "./idle-mount.js";
21
26
  import { orderMessageContent } from "./message-content-order.js";
22
27
  import { AGENTKIT_CLIENT_REQUEST_ID_METADATA_KEY, agentKitTurnInProgress, pendingSubmissionFiles, } from "./pending-submissions.js";
28
+ import { parseStackTrace, StackTrace } from "./stack-trace.js";
29
+ import { Terminal } from "./terminal.js";
30
+ export { formatAgentKitDuration };
31
+ import { useRovingFocus } from "./roving-focus.js";
23
32
  import { useAgentKitStopButton } from "./stop-button.js";
24
33
  import { AgentStreamingText, usePrefersReducedMotion, useStreamingRevealOrigin, } from "./streaming-text.js";
34
+ import { Trace, TraceCollapsible, TraceCollapsibleContent, TraceCollapsibleTrigger, TraceDescription, TraceIcon, TraceLine, TraceTitle, } from "./trace.js";
25
35
  import { TranscriptGlide } from "./transcript-glide.js";
26
36
  import { workedForRowChevronStyle, workedForRowSummaryStyle, } from "./transcript-layout.js";
27
37
  import { registerChatThreadView } from "./viewed-threads.js";
@@ -93,7 +103,7 @@ function sameRenderedNode(previous, next) {
93
103
  }
94
104
  const AgentKitSurfaceBoundary = memo(function AgentKitSurfaceBoundary({ surface, resetKey, children, }) {
95
105
  const { labels, onRenderError, threadId } = useAgentKit();
96
- return (_jsx(AgentKitErrorBoundary, { resetKey: resetKey, fallback: _jsxs("div", { className: "agentkit-error", "data-render-surface": surface, role: "alert", children: [_jsx(IconAlertCircle, { "aria-hidden": "true", className: "agentkit-icon" }), _jsx("span", { children: labels.renderError })] }), onError: (error, info) => onRenderError?.({
106
+ return (_jsx(AgentKitErrorBoundary, { resetKey: resetKey, fallback: _jsxs("div", { className: "agentkit-error", "data-render-surface": surface, role: "alert", children: [_jsx(IconAlertTriangle, { "aria-hidden": "true", className: "agentkit-icon" }), _jsx("span", { children: labels.renderError })] }), onError: (error, info) => onRenderError?.({
97
107
  error,
98
108
  surface,
99
109
  threadId,
@@ -157,14 +167,28 @@ function AgentLink({ href, children, }) {
157
167
  const safeHref = safeAgentHref(href);
158
168
  return safeHref ? (_jsx("a", { href: safeHref, ...agentLinkTargetProps(safeHref, origin), children: children })) : (_jsx("span", { children: children }));
159
169
  }
160
- function codeBlockLanguage(children) {
170
+ function fencedCode(children) {
161
171
  const code = Array.isArray(children) ? children[0] : children;
162
- if (!code || typeof code !== "object" || !("props" in code))
163
- return undefined;
172
+ if (!isValidElement(code)) {
173
+ return { text: nodeText(children), language: undefined };
174
+ }
164
175
  const className = code.props.className;
165
- if (typeof className !== "string")
166
- return undefined;
167
- return /(?:^|\s)language-([\w+#.-]+)/.exec(className)?.[1];
176
+ return {
177
+ text: nodeText(code.props.children),
178
+ language: typeof className === "string"
179
+ ? /(?:^|\s)language-([\w+#.-]+)/.exec(className)?.[1]
180
+ : undefined,
181
+ };
182
+ }
183
+ function nodeText(node) {
184
+ if (typeof node === "string" || typeof node === "number")
185
+ return `${node}`;
186
+ if (Array.isArray(node))
187
+ return node.map(nodeText).join("");
188
+ if (isValidElement(node)) {
189
+ return nodeText(node.props.children);
190
+ }
191
+ return "";
168
192
  }
169
193
  function AgentMarkdownCodeBlock({ children, node: _node, className, ...props }) {
170
194
  // The header belongs to the block, so it fades in with the code.
@@ -174,34 +198,19 @@ function AgentMarkdownCodeBlock({ children, node: _node, className, ...props })
174
198
  .filter((name) => name && name !== STREAMING_REVEAL_BLOCK_CLASS)
175
199
  .join(" ") || undefined;
176
200
  const { labels } = useAgentKit();
177
- const preRef = useRef(null);
178
- const [copied, setCopied] = useState(false);
179
- const copiedTimer = useRef(null);
180
- useEffect(() => () => {
181
- if (copiedTimer.current)
182
- clearTimeout(copiedTimer.current);
183
- }, []);
184
- const language = codeBlockLanguage(children);
185
- const copy = async () => {
186
- const text = preRef.current?.textContent ?? "";
187
- if (!(await writeClipboardText(text)))
188
- return;
189
- setCopied(true);
190
- if (copiedTimer.current)
191
- clearTimeout(copiedTimer.current);
192
- copiedTimer.current = setTimeout(() => setCopied(false), 2_000);
193
- };
194
- return (_jsxs("figure", { className: revealsAsBlock
195
- ? `agentkit-code-block ${STREAMING_REVEAL_BLOCK_CLASS}`
196
- : "agentkit-code-block", children: [_jsxs("div", { className: "agentkit-code-block-header", children: [_jsx("span", { className: "agentkit-code-block-language", "aria-hidden": "true", children: language }), _jsx(IconButton, { label: copied ? labels.codeCopied : labels.copyCode, icon: copied ? (_jsx(IconCheck, { "aria-hidden": "true", size: 16 })) : (_jsx(IconCopy, { "aria-hidden": "true", size: 16 })), size: "compact", className: "size-6", onPress: () => void copy() })] }), _jsx("pre", { ...props, className: preClassName, ref: preRef, tabIndex: 0, role: "region", "aria-label": language
197
- ? labels.codeBlockLanguage.replace("{{language}}", () => language)
198
- : labels.codeBlock, children: children })] }));
201
+ const { text, language } = fencedCode(children);
202
+ const languageName = prettyLanguageName(language);
203
+ return (_jsxs(CodeBlock, { className: revealsAsBlock ? STREAMING_REVEAL_BLOCK_CLASS : undefined, children: [_jsxs(CodeBlockHeader, { children: [_jsx(CodeBlockTitle, { "aria-hidden": "true", children: languageName }), _jsx(CodeBlockActions, { children: _jsx(CodeBlockCopyButton, { value: text }) })] }), _jsx(CodeBlockContent, { ...props, className: preClassName, language: language,
204
+ // A group, not a region: a landmark per code block buries the real ones.
205
+ role: "group", "aria-label": languageName
206
+ ? labels.codeBlockLanguage.replace("{{language}}", () => languageName)
207
+ : labels.codeBlock, children: text })] }));
199
208
  }
200
209
  function AgentMarkdownTable({ node: _node, ...props }) {
201
210
  const { labels } = useAgentKit();
202
211
  const table = useRef(null);
203
212
  useTableColumnGlide(table);
204
- return (_jsx("div", { className: "agentkit-markdown-table", tabIndex: 0, role: "region", "aria-label": labels.table, children: _jsx("table", { ref: table, ...props }) }));
213
+ return (_jsx("div", { className: "agentkit-markdown-table", tabIndex: 0, role: "group", "aria-label": labels.table, children: _jsx("table", { ref: table, ...props }) }));
205
214
  }
206
215
  function AgentMarkdownImage({ node: _node, src, alt, ...props }) {
207
216
  const [loaded, setLoaded] = useState(false);
@@ -331,12 +340,12 @@ function activityIcon(kind) {
331
340
  }
332
341
  }
333
342
  const DISCLOSURE_ROW_INTERACTIVE = "button, a, input, textarea, select, [role='button'], [contenteditable='true']";
334
- /** One summary row for every AgentKit disclosure: icon, label, then chevron. */
335
- export function AgentKitDisclosureSummary({ open, onToggle, label, icon, expandable = true, as = "button", controls, meta, className, rowClassName, style, chevronStyle, children, }) {
336
- const content = children ?? (_jsxs(_Fragment, { children: [icon !== undefined ? (_jsx("span", { className: "agentkit-disclosure-icon-slot", "aria-hidden": "true", children: icon })) : null, _jsx("span", { className: "agentkit-disclosure-label", children: label }), expandable && as === "button" ? (_jsx(IconChevronRight, { "aria-hidden": "true", className: "agentkit-icon agentkit-disclosure-chevron", "data-open": open ? "true" : "false", style: chevronStyle })) : null] }));
343
+ /** The label keeps its own styling; `TraceTitle` is for host rows. */
344
+ export function AgentKitDisclosureSummary({ open, onToggle, label, icon, expandable = true, as = "button", controls, meta, className, rowClassName, style, chevronStyle, status, children, }) {
345
+ const content = children ?? (_jsxs(_Fragment, { children: [_jsxs(TraceLine, { status: status, children: [icon !== undefined ? _jsx(TraceIcon, { children: icon }) : null, _jsx("span", { "data-slot": "trace-title", className: "agentkit-disclosure-label", children: label })] }), expandable && as === "button" ? (_jsx(IconChevronRight, { "aria-hidden": "true", className: "agentkit-icon agentkit-disclosure-chevron", "data-open": open ? "true" : "false", style: chevronStyle })) : null] }));
337
346
  const trigger = as === "static" ? (_jsx("span", { className: ["agentkit-disclosure-summary", className]
338
347
  .filter(Boolean)
339
- .join(" "), "data-expandable": "false", style: style, children: content })) : (_jsx("button", { type: "button", className: ["agentkit-disclosure-summary", className]
348
+ .join(" "), "data-expandable": "false", style: style, children: content })) : (_jsx("button", { type: "button", "data-slot": expandable ? "trace-collapsible-trigger" : undefined, className: ["agentkit-disclosure-summary", className]
340
349
  .filter(Boolean)
341
350
  .join(" "), "data-expandable": expandable ? "true" : "false", "aria-expanded": expandable ? open : undefined, "aria-controls": expandable ? controls : undefined, "aria-disabled": expandable ? undefined : true, tabIndex: expandable ? undefined : -1, style: style, onClick: () => {
342
351
  if (expandable)
@@ -361,36 +370,10 @@ export function AgentKitDisclosureSummary({ open, onToggle, label, icon, expanda
361
370
  }
362
371
  : undefined, children: [trigger, meta] }));
363
372
  }
364
- /** True while a long thread opens, so closed rows can mount later. */
365
- const AgentKitDeferClosedContentContext = createContext(false);
366
- /**
367
- * Mounted while closed, like <details>, so find-in-page can reveal it. In a
368
- * long thread, closed content mounts in the next idle period rather than with
369
- * the transcript, so the history paints before every collapsed step renders.
370
- */
373
+ /** Mounted while closed, like <details>, so find-in-page can reveal it. */
371
374
  export function AgentKitDisclosureContent({ id, open, onReveal, children, }) {
372
- const ref = useRef(null);
373
- const revealRef = useRef(onReveal);
374
- revealRef.current = onReveal;
375
- const deferClosed = useContext(AgentKitDeferClosedContentContext);
376
- const [contentMounted, setContentMounted] = useState(open || !deferClosed);
377
- if (open && !contentMounted)
378
- setContentMounted(true);
379
- useEffect(() => {
380
- if (contentMounted)
381
- return;
382
- return scheduleIdleMount(() => setContentMounted(true));
383
- }, [contentMounted]);
384
- useEffect(() => {
385
- const element = ref.current;
386
- if (!element || open)
387
- return;
388
- element.setAttribute("hidden", "until-found");
389
- const reveal = () => revealRef.current?.();
390
- element.addEventListener("beforematch", reveal);
391
- return () => element.removeEventListener("beforematch", reveal);
392
- }, [open]);
393
- return (_jsx("div", { ref: ref, id: id, className: "agentkit-disclosure-content", hidden: !open, children: contentMounted || open ? children : null }));
375
+ const { ref, mounted } = useUntilFoundContent(open, onReveal);
376
+ return (_jsx("div", { ref: ref, id: id, "data-slot": "trace-collapsible-content", "data-state": open ? "open" : "closed", className: "agentkit-disclosure-content", hidden: !open, children: mounted ? children : null }));
394
377
  }
395
378
  function interactionIcon(kind) {
396
379
  const props = { "aria-hidden": true, className: "agentkit-icon" };
@@ -407,7 +390,7 @@ function interactionIcon(kind) {
407
390
  case "completed":
408
391
  return _jsx(IconCircleCheck, { ...props });
409
392
  case "failed":
410
- return _jsx(IconAlertCircle, { ...props });
393
+ return _jsx(IconAlertTriangle, { ...props });
411
394
  case "closed":
412
395
  return _jsx(IconX, { ...props });
413
396
  default:
@@ -769,6 +752,54 @@ function formatActivityToolValue(value, labels = {}) {
769
752
  const contentLimit = Math.max(0, ACTIVITY_TOOL_VALUE_LIMIT - omissionMarker.length - 1);
770
753
  return `${formatted.slice(0, contentLimit).trimEnd()}…${omissionMarker}`;
771
754
  }
755
+ /** Fields whose string is the program a tool runs, with its grammar. */
756
+ const ACTIVITY_TOOL_SOURCE_FIELDS = {
757
+ command: "bash",
758
+ script: undefined,
759
+ code: undefined,
760
+ };
761
+ function formatActivityToolInput(value, labels = {}) {
762
+ const source = activityToolSource(value);
763
+ if (!source) {
764
+ const text = formatActivityToolValue(value, labels);
765
+ return text ? { text } : undefined;
766
+ }
767
+ const text = formatActivityToolValue(source.text, labels);
768
+ if (!text)
769
+ return undefined;
770
+ const options = Object.entries(source.rest).flatMap(([key, option]) => {
771
+ const formatted = formatActivityToolValue(option, labels);
772
+ return formatted ? [[key, formatted.replace(/\s+/g, " ")]] : [];
773
+ });
774
+ return {
775
+ text,
776
+ language: source.language,
777
+ ...(options.length ? { options } : {}),
778
+ };
779
+ }
780
+ function activityToolSource(value) {
781
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
782
+ return undefined;
783
+ }
784
+ const input = value;
785
+ const field = Object.keys(ACTIVITY_TOOL_SOURCE_FIELDS).find((key) => {
786
+ const text = input[key];
787
+ // `code` also names short values such as a country or a promo code.
788
+ return (typeof text === "string" &&
789
+ (key === "command" ? text.trim() !== "" : /\n|.{40}/.test(text)));
790
+ });
791
+ if (!field)
792
+ return undefined;
793
+ const languageField = ["language", "lang"].find((key) => typeof input[key] === "string");
794
+ const rest = Object.fromEntries(Object.entries(input).filter(([key, option]) => key !== field && key !== languageField && option !== undefined));
795
+ return {
796
+ text: input[field],
797
+ language: languageField
798
+ ? input[languageField]
799
+ : ACTIVITY_TOOL_SOURCE_FIELDS[field],
800
+ rest,
801
+ };
802
+ }
772
803
  function activityLabel(activity, workingLabel) {
773
804
  const label = readableText(activity.label);
774
805
  if (label.toLowerCase() === "processing")
@@ -778,7 +809,16 @@ function activityLabel(activity, workingLabel) {
778
809
  workingLabel);
779
810
  }
780
811
  function AgentIdentityChip({ id, name, fallbackName = "Agent", kind, status, }) {
781
- return (_jsx("span", { className: "agentkit-agent", "data-agent-id": id, "data-agent-kind": kind, "data-status": status, children: _jsx("span", { className: "agentkit-agent-name", children: readableText(name) || fallbackName }) }));
812
+ const { labels } = useAgentKit();
813
+ // The chip's tint and shimmer carry the state, so it is said in words too.
814
+ const statusLabel = status === "working"
815
+ ? labels.taskStatusRunning
816
+ : status === "failed"
817
+ ? labels.taskStatusFailed
818
+ : status === "waiting"
819
+ ? labels.taskStatusAwaitingInput
820
+ : undefined;
821
+ return (_jsxs("span", { className: "agentkit-agent", "data-agent-id": id, "data-agent-kind": kind, "data-status": status, children: [status === "failed" ? (_jsx(IconAlertTriangle, { "aria-hidden": "true", className: "agentkit-icon" })) : null, _jsx("span", { className: "agentkit-agent-name", children: readableText(name) || fallbackName }), statusLabel ? (_jsx("span", { className: "agentkit-visually-hidden", children: statusLabel })) : null] }));
782
822
  }
783
823
  function defaultInteractionLabel(interaction, labels) {
784
824
  if (interaction.label)
@@ -805,8 +845,9 @@ function defaultInteractionLabel(interaction, labels) {
805
845
  }
806
846
  }
807
847
  export function AgentInteractionItem({ value: interaction, threadId, }) {
808
- const { slots, registry, labels } = useAgentKit();
848
+ const { slots, registry, labels, formatAgentInteractionDetail } = useAgentKit();
809
849
  const thread = useAgentThreadSlice(sameAgents, threadId);
850
+ const showAgent = useContext(AgentSubagentStepContext) !== interaction.agentId;
810
851
  const agent = thread.agents[interaction.agentId];
811
852
  const target = interaction.targetAgentId
812
853
  ? thread.agents[interaction.targetAgentId]
@@ -832,8 +873,8 @@ export function AgentInteractionItem({ value: interaction, threadId, }) {
832
873
  const label = readableText(interaction.label);
833
874
  const visibleLabel = humanizeAgentLabel(label) ||
834
875
  defaultInteractionLabel({ ...interaction, label: undefined }, labels);
835
- const detail = readableText(interaction.detail);
836
- return (_jsxs("div", { className: "agentkit-agent-interaction", "data-kind": interaction.kind, "data-scope": interaction.scope, children: [_jsxs("span", { className: "agentkit-agent-interaction-head", children: [interactionIcon(interaction.kind), agent && AgentRenderer ? (_jsx(AgentRenderer, { value: agent, threadId: threadId })) : (_jsx(AgentIdentityChip, { id: interaction.agentId, name: agentName, fallbackName: labels.assistant })), _jsx("span", { className: "agentkit-agent-interaction-label", children: visibleLabel }), target && TargetRenderer ? (_jsx(TargetRenderer, { value: target, threadId: threadId })) : interaction.targetAgentId ? (_jsx(AgentIdentityChip, { id: interaction.targetAgentId, name: targetName, fallbackName: labels.assistant })) : null, object ? _jsx(ObjectRenderer, { value: object, threadId: threadId }) : null] }), detail && (!object || interaction.kind === "failed") ? (_jsx("span", { ...(interaction.kind === "failed"
876
+ const detail = readableText(formatAgentInteractionDetail?.(interaction) ?? interaction.detail);
877
+ return (_jsxs("div", { className: "agentkit-agent-interaction", "data-kind": interaction.kind, "data-scope": interaction.scope, children: [_jsxs(TraceLine, { className: "agentkit-agent-interaction-head", status: interaction.kind === "failed" ? "error" : undefined, children: [_jsx(TraceIcon, { children: interactionIcon(interaction.kind) }), !showAgent ? null : AgentRenderer ? (_jsx(AgentRenderer, { value: agent, threadId: threadId })) : (_jsx(AgentIdentityChip, { id: interaction.agentId, name: agentName, fallbackName: labels.assistant })), _jsx("span", { "data-slot": "trace-title", className: "agentkit-agent-interaction-label", children: visibleLabel }), target && TargetRenderer ? (_jsx(TargetRenderer, { value: target, threadId: threadId })) : interaction.targetAgentId ? (_jsx(AgentIdentityChip, { id: interaction.targetAgentId, name: targetName, fallbackName: labels.assistant })) : null, object ? _jsx(ObjectRenderer, { value: object, threadId: threadId }) : null] }), detail && (!object || interaction.kind === "failed") ? (_jsx("span", { ...(interaction.kind === "failed"
837
878
  ? SESSION_REPLAY_MASK_PROPS
838
879
  : { title: detail }), className: "agentkit-agent-interaction-detail", children: detail })) : null] }));
839
880
  }
@@ -860,11 +901,27 @@ export function AgentActivityItem({ value: activity, threadId, }) {
860
901
  const thread = useAgentThreadSlice((previous, next) => previous.agents === next.agents &&
861
902
  previous.tools[activity.id] === next.tools[activity.id]);
862
903
  const [open, setOpen] = useState(false);
904
+ const showAgent = useContext(AgentSubagentStepContext) !== activity.agentId;
863
905
  const agent = activity.agentId ? thread.agents[activity.agentId] : undefined;
864
906
  const agentName = resolveAgentName(thread, activity.agentId, [activity.source, activity.object], labels.assistant);
865
907
  const tool = thread.tools[activity.id];
866
- const toolInput = useMemo(() => (tool ? formatActivityToolValue(tool.input, labels) : undefined), [labels, tool]);
908
+ const toolInput = useMemo(() => (tool ? formatActivityToolInput(tool.input, labels) : undefined), [labels, tool]);
867
909
  const toolResult = useMemo(() => (tool ? formatActivityToolValue(tool.output, labels) : undefined), [labels, tool]);
910
+ const stackTrace = useMemo(() => {
911
+ if (!tool)
912
+ return undefined;
913
+ const sources = [
914
+ toolResult,
915
+ formatActivityToolValue(tool.error?.details, labels),
916
+ formatActivityToolValue(tool.error?.message, labels),
917
+ ];
918
+ for (const source of sources) {
919
+ const parsed = source ? parseStackTrace(source) : undefined;
920
+ if (parsed)
921
+ return { parsed, fromResult: source === toolResult };
922
+ }
923
+ return undefined;
924
+ }, [labels, tool, toolResult]);
868
925
  const toolInputLabel = labels.toolInput;
869
926
  const toolResultLabel = labels.toolResult;
870
927
  const expandable = Boolean(activity.summary?.length || toolInput || toolResult);
@@ -877,6 +934,13 @@ export function AgentActivityItem({ value: activity, threadId, }) {
877
934
  const object = activity.object ??
878
935
  sourceObjectUnlessRepresented(activity.source, thread, [activity.agentId]);
879
936
  const failed = activity.status === "failed";
937
+ const statusWords = activity.status === "running"
938
+ ? labels.taskStatusRunning
939
+ : failed
940
+ ? labels.taskStatusFailed
941
+ : activity.status === "cancelled"
942
+ ? labels.runStopped
943
+ : undefined;
880
944
  const errorPreview = activityErrorPreview(activity, tool, labels);
881
945
  // A tool call names what it acted on, so rows in a group tell apart.
882
946
  const toolObject = tool && !object
@@ -885,8 +949,41 @@ export function AgentActivityItem({ value: activity, threadId, }) {
885
949
  const detail = tool || failed
886
950
  ? readableText(toolObject?.text)
887
951
  : readableText(activity.detail);
888
- const summaryId = useId();
889
- return (_jsxs("div", { className: "agentkit-activity-item", "data-activity-kind": activity.kind, "data-status": activity.status, "data-open": expandable && open ? "true" : "false", children: [_jsx(AgentKitDisclosureSummary, { rowClassName: "agentkit-activity-row", open: open, onToggle: () => setOpen((current) => !current), expandable: expandable, as: expandable ? "button" : "static", controls: open ? summaryId : undefined, icon: failed ? (_jsx(IconAlertTriangle, { "aria-hidden": "true", className: "agentkit-icon" })) : (_jsx(ActivitySourceIcon, { activity: activity, threadId: threadId })), label: _jsxs(_Fragment, { children: [agent && AgentRenderer ? (_jsx(AgentRenderer, { value: agent, threadId: threadId })) : activity.agentId ? (_jsx(AgentIdentityChip, { id: activity.agentId, name: agentName, fallbackName: labels.assistant })) : null, _jsx("span", { className: "agentkit-activity-label", children: activityLabel(activity, labels.working) })] }), meta: object || detail ? (_jsxs(_Fragment, { children: [object ? (_jsx(ObjectRenderer, { value: object, threadId: threadId })) : null, detail ? (_jsx("span", { ...(toolObject ? SESSION_REPLAY_MASK_PROPS : {}), title: toolObject ? undefined : detail, className: "agentkit-activity-detail", "data-kind": toolObject?.kind, children: detail })) : null] })) : null }), errorPreview ? (_jsx("span", { ...SESSION_REPLAY_MASK_PROPS, className: "agentkit-activity-error", children: errorPreview })) : null, open ? (_jsxs("div", { ...(activity.status === "failed" ? SESSION_REPLAY_BLOCK_PROPS : {}), id: summaryId, className: "agentkit-activity-summary", children: [activity.summary?.map((part, index) => {
952
+ const line = (_jsxs(TraceLine, { status: traceStatus(activity.status), children: [_jsx(TraceIcon, { children: failed ? (_jsx(IconAlertTriangle, { "aria-hidden": "true", className: "agentkit-icon" })) : (_jsx(ActivitySourceIcon, { activity: activity, threadId: threadId })) }), _jsxs("span", { className: "agentkit-disclosure-label", children: [!showAgent ? null : agent && AgentRenderer ? (_jsx(AgentRenderer, { value: agent, threadId: threadId })) : activity.agentId ? (_jsx(AgentIdentityChip, { id: activity.agentId, name: agentName, fallbackName: labels.assistant })) : null, _jsx(TraceTitle, { className: "agentkit-activity-label", children: activityLabel(activity, labels.working) }), statusWords ? (_jsx("span", { className: "agentkit-visually-hidden", children: statusWords })) : null] })] }));
953
+ const meta = (_jsxs(_Fragment, { children: [object ? _jsx(ObjectRenderer, { value: object, threadId: threadId }) : null, detail ? (_jsx(TraceDescription, { ...(toolObject ? SESSION_REPLAY_MASK_PROPS : {}), title: toolObject ? undefined : detail, className: "agentkit-activity-detail", "data-kind": toolObject?.kind, children: detail })) : null] }));
954
+ const errorLine = errorPreview ? (_jsx("span", { ...SESSION_REPLAY_MASK_PROPS, className: "agentkit-activity-error", children: errorPreview })) : null;
955
+ const rootProps = {
956
+ className: "agentkit-activity-item",
957
+ "data-activity-kind": activity.kind,
958
+ "data-status": activity.status,
959
+ "data-open": expandable && open ? "true" : "false",
960
+ };
961
+ const fileChange = tool ? fileChangeTool(tool) : undefined;
962
+ if (fileChange) {
963
+ return (_jsxs("div", { ...rootProps, children: [_jsx(FileChange, { change: fileChange, running: activity.status === "running" }), errorLine] }));
964
+ }
965
+ const terminal = tool ? terminalTool(tool) : undefined;
966
+ if (terminal) {
967
+ return (_jsx("div", { ...rootProps, children: _jsx(Terminal, { command: terminal.command, output: typeof tool?.output === "string" ? tool.output : toolResult, running: activity.status === "running", exitCode: terminal.exitCode, durationMs: terminal.durationMs, timedOut: terminal.timedOut, failed: failed }) }));
968
+ }
969
+ if (!expandable) {
970
+ return (_jsxs("div", { ...rootProps, children: [_jsxs("div", { className: "agentkit-disclosure-row agentkit-activity-row", children: [_jsx("span", { className: "agentkit-disclosure-summary", "data-expandable": "false", children: line }), meta] }), errorLine] }));
971
+ }
972
+ return (_jsxs(TraceCollapsible, { ...rootProps, open: open, onOpenChange: setOpen, children: [_jsxs("div", { className: "agentkit-disclosure-row agentkit-activity-row", "data-expandable": "true", onClick: (event) => {
973
+ // Meta controls handle their own clicks; a text-selecting drag is no toggle.
974
+ const target = event.target;
975
+ if (target instanceof Element &&
976
+ target.closest(DISCLOSURE_ROW_INTERACTIVE))
977
+ return;
978
+ if (globalThis.getSelection()?.toString())
979
+ return;
980
+ setOpen((current) => !current);
981
+ }, children: [_jsx(TraceCollapsibleTrigger, { children: line }), meta] }), errorLine, _jsxs(TraceCollapsibleContent
982
+ // A fresh node on each toggle: the recorder can drop a block marker
983
+ // changed on a node it has recorded, and the closed body stays mounted.
984
+ , { keepMounted: true, ...(activity.status === "failed" || !open
985
+ ? SESSION_REPLAY_BLOCK_PROPS
986
+ : {}), className: "agentkit-activity-summary", children: [activity.summary?.map((part, index) => {
890
987
  const safePart = part.type === "text"
891
988
  ? {
892
989
  ...part,
@@ -896,7 +993,95 @@ export function AgentActivityItem({ value: activity, threadId, }) {
896
993
  }
897
994
  : part;
898
995
  return safePart.type === "text" && !safePart.text ? null : (_jsx(AgentMessagePartView, { value: safePart, threadId: threadId }, `${activity.id}-summary-${index}`));
899
- }), toolInput ? (_jsxs("div", { className: "agentkit-activity-summary-section", children: [_jsx("div", { className: "agentkit-activity-summary-label", children: toolInputLabel }), _jsx("pre", { role: "region", "aria-label": toolInputLabel, tabIndex: 0, className: "agentkit-activity-summary-value", children: toolInput })] })) : null, toolResult ? (_jsxs("div", { className: "agentkit-activity-summary-section", children: [_jsx("div", { className: "agentkit-activity-summary-label", children: toolResultLabel }), _jsx("pre", { role: "region", "aria-label": toolResultLabel, tabIndex: 0, className: "agentkit-activity-summary-value", children: toolResult })] })) : null] })) : null] }));
996
+ }), toolInput ? (_jsx(ActivityToolValue, { label: toolInputLabel, value: toolInput.text, language: toolInput.language, options: toolInput.options })) : null, stackTrace ? (_jsx(StackTrace, { trace: stackTrace.parsed, defaultOpen: true })) : null, toolResult && !(stackTrace?.fromResult && stackTrace.parsed.whole) ? (_jsx(ActivityToolValue, { label: toolResultLabel, value: toolResult })) : null] }, open ? "open" : "closed")] }));
997
+ }
998
+ function terminalTool(tool) {
999
+ const metadata = tool.metadata;
1000
+ if (metadata?.toolKind !== "bash" || typeof metadata.command !== "string") {
1001
+ return undefined;
1002
+ }
1003
+ return {
1004
+ command: metadata.command,
1005
+ exitCode: typeof metadata.exitCode === "number" || metadata.exitCode === null
1006
+ ? metadata.exitCode
1007
+ : undefined,
1008
+ durationMs: typeof metadata.durationMs === "number" ? metadata.durationMs : undefined,
1009
+ timedOut: metadata.timedOut === true ? true : undefined,
1010
+ };
1011
+ }
1012
+ function fileChangeTool(tool) {
1013
+ const metadata = tool.metadata;
1014
+ const kind = metadata?.toolKind;
1015
+ if ((kind !== "edit" && kind !== "write") ||
1016
+ typeof metadata?.filePath !== "string") {
1017
+ return undefined;
1018
+ }
1019
+ const text = (value) => typeof value === "string" ? value : undefined;
1020
+ return {
1021
+ filePath: metadata.filePath,
1022
+ kind,
1023
+ oldText: text(metadata.oldText),
1024
+ newText: text(metadata.newText),
1025
+ content: text(metadata.content),
1026
+ lineCount: typeof metadata.lineCount === "number" ? metadata.lineCount : undefined,
1027
+ truncated: metadata.truncated === true,
1028
+ };
1029
+ }
1030
+ function ActivityToolValue({ label, value, language: sourceLanguage, options, }) {
1031
+ const language = useMemo(() => sourceLanguage ?? (isJsonText(value) ? "json" : undefined), [sourceLanguage, value]);
1032
+ return (_jsxs(CodeBlock, { size: "sm", className: "agentkit-activity-summary-section", children: [_jsxs(CodeBlockHeader, { children: [_jsx(CodeBlockTitle, { children: label }), _jsx(CodeBlockActions, { children: _jsx(CodeBlockCopyButton, { value: value }) })] }), _jsx(CodeBlockContent, { wrap: true, language: language, role: "group", "aria-label": label, className: "agentkit-activity-summary-value", children: value }), options ? (_jsx(CodeBlockFooter, { children: _jsx("dl", { className: "agentkit-activity-tool-options", children: options.map(([key, option]) => (_jsxs("div", { children: [_jsx("dt", { children: key }), _jsx("dd", { children: option })] }, key))) }) })) : null] }));
1033
+ }
1034
+ function isJsonText(text) {
1035
+ const start = text.trimStart()[0];
1036
+ if (start !== "{" && start !== "[")
1037
+ return false;
1038
+ try {
1039
+ JSON.parse(text);
1040
+ return true;
1041
+ // coercion-ok: text that does not parse is the predicate's false answer.
1042
+ }
1043
+ catch {
1044
+ return false;
1045
+ }
1046
+ }
1047
+ /** The same page cited twice counts as one source. */
1048
+ export function AgentSources({ citations }) {
1049
+ const { labels } = useAgentKit();
1050
+ const sources = useMemo(() => {
1051
+ const seen = new Set();
1052
+ return citations.filter((citation) => {
1053
+ const key = safeAgentHref(citation.url) ?? `title:${citation.title}`;
1054
+ if (seen.has(key))
1055
+ return false;
1056
+ seen.add(key);
1057
+ return true;
1058
+ });
1059
+ }, [citations]);
1060
+ const label = (sources.length === 1
1061
+ ? labels.workStepSourcesOne
1062
+ : labels.workStepSourcesOther).replace("{{count}}", () => `${sources.length}`);
1063
+ return (_jsx(Trace, { className: "agentkit-sources", children: _jsxs(TraceCollapsible, { children: [_jsx(TraceCollapsibleTrigger, { children: _jsxs(TraceLine, { children: [_jsx(TraceIcon, { children: _jsx(IconWorld, { "aria-hidden": "true", className: "agentkit-icon" }) }), _jsx("span", { className: "agentkit-disclosure-label", children: label })] }) }), _jsx(TraceCollapsibleContent, { keepMounted: true, children: _jsx("ul", { className: "agentkit-sources-list", children: sources.map((source, index) => (_jsx("li", { children: _jsx(AgentLink, { href: source.url, children: _jsxs(TraceLine, { children: [_jsx(TraceIcon, { children: _jsx(IconWorld, { "aria-hidden": "true", className: "agentkit-icon" }) }), _jsx(TraceTitle, { children: sourceTitle(source) })] }) }) }, `${index}:${source.url ?? source.title}`))) }) })] }) }));
1064
+ }
1065
+ function sourceTitle(source) {
1066
+ const title = readableText(source.title);
1067
+ if (title)
1068
+ return title;
1069
+ const href = safeAgentHref(source.url);
1070
+ if (!href)
1071
+ return source.title;
1072
+ try {
1073
+ return new URL(href).hostname;
1074
+ }
1075
+ catch {
1076
+ return href;
1077
+ }
1078
+ }
1079
+ function traceStatus(status) {
1080
+ return status === "running"
1081
+ ? "running"
1082
+ : status === "failed"
1083
+ ? "error"
1084
+ : undefined;
900
1085
  }
901
1086
  function ActivitySourceIcon({ activity, threadId, compact = false, }) {
902
1087
  const { registry } = useAgentKit();
@@ -981,26 +1166,6 @@ function workedSummaryLabel(durationMs, labels, formatDuration) {
981
1166
  ? labels.workedFor.replace("{{duration}}", () => formatDuration(durationMs))
982
1167
  : labels.worked;
983
1168
  }
984
- export function formatAgentKitDuration(ms, units = {}) {
985
- const hour = units.hour ?? "h";
986
- const minute = units.minute ?? "m";
987
- const second = units.second ?? "s";
988
- const totalSeconds = Math.max(0, Math.round(ms / 1_000));
989
- if (totalSeconds < 60)
990
- return `${Math.max(1, totalSeconds)}${second}`;
991
- const minutes = Math.floor(totalSeconds / 60);
992
- const seconds = totalSeconds % 60;
993
- if (minutes < 60) {
994
- return seconds === 0
995
- ? `${minutes}${minute}`
996
- : `${minutes}${minute} ${seconds}${second}`;
997
- }
998
- const hours = Math.floor(minutes / 60);
999
- const remainingMinutes = minutes % 60;
1000
- return remainingMinutes === 0
1001
- ? `${hours}${hour}`
1002
- : `${hours}${hour} ${remainingMinutes}${minute}`;
1003
- }
1004
1169
  function isVisibleReasoningPart(part) {
1005
1170
  return (part.type === "reasoning" &&
1006
1171
  part.visibility !== "hidden" &&
@@ -1527,7 +1692,7 @@ export const AgentActivityGroup = memo(function AgentActivityGroup({ runId, afte
1527
1692
  AgentActivityItem;
1528
1693
  return _jsx(Renderer, { value: call.activity, threadId: threadId }, call.id);
1529
1694
  };
1530
- return (_jsxs(_Fragment, { children: [resultCards, hasExpandableActivity || activelyWorking ? (_jsx(AgentWorkDisclosure, { label: baseSummaryLabel, failedCount: failedCount, icon: summaryIcon, running: visiblyRunning, expandable: hasExpandableActivity, runId: runId, messageId: messageId, current: currentActivity ? (_jsxs("span", { className: "agentkit-activities-current", "data-running": "true", "data-agentkit-current-activity": "true", children: [_jsx(ActivitySourceIcon, { activity: currentActivity, threadId: threadId, compact: true }), _jsx("span", { className: "agentkit-activities-current-label agent-running-shimmer", children: currentActivityLabel })] })) : null, currentLabel: currentActivity ? (_jsx("span", { className: "agentkit-activities-current", "data-running": "true", "data-agentkit-current-activity": "true", children: _jsx("span", { className: "agentkit-activities-current-label agent-running-shimmer", children: currentActivityLabel }) })) : null, children: _jsx(AgentWorkStepList, { steps: steps, threadId: threadId, running: activelyWorking, renderCall: renderCall }) })) : (_jsx("div", { className: "agentkit-activities-static", children: summaryLabel || currentActivity ? (_jsx(AgentKitDisclosureSummary, { as: "static", className: "agentkit-activities-summary", open: false, onToggle: () => { }, expandable: false, icon: summaryIcon, label: summaryLabel ? (_jsx("span", { className: "agentkit-activities-label", children: summaryLabel })) : (_jsx("span", { className: "agentkit-activities-current", "data-running": "true", "data-agentkit-current-activity": "true", children: _jsx("span", { className: "agentkit-activities-current-label agent-running-shimmer", children: currentActivityLabel }) })) })) : null }))] }));
1695
+ return (_jsxs(_Fragment, { children: [resultCards, hasExpandableActivity || activelyWorking ? (_jsx(AgentWorkDisclosure, { label: baseSummaryLabel, failedCount: failedCount, icon: summaryIcon, running: visiblyRunning, expandable: hasExpandableActivity, runId: runId, messageId: messageId, current: currentActivity ? (_jsxs("span", { className: "agentkit-activities-current", "data-running": "true", "data-agentkit-current-activity": "true", children: [_jsx(ActivitySourceIcon, { activity: currentActivity, threadId: threadId, compact: true }), _jsx("span", { className: "agentkit-activities-current-label agent-running-shimmer", children: currentActivityLabel })] })) : null, currentLabel: currentActivity ? (_jsx("span", { className: "agentkit-activities-current", "data-running": "true", "data-agentkit-current-activity": "true", children: _jsx("span", { className: "agentkit-activities-current-label agent-running-shimmer", children: currentActivityLabel }) })) : null, children: _jsx(AgentWorkStepList, { steps: steps, threadId: threadId, running: activelyWorking, renderCall: renderCall }) })) : (_jsx("div", { className: "agentkit-activities-static", children: summaryLabel || currentActivity ? (_jsx(AgentKitDisclosureSummary, { as: "static", className: "agentkit-activities-summary", open: false, onToggle: () => { }, expandable: false, status: summaryLabel ? undefined : "running", icon: summaryIcon, label: summaryLabel ? (_jsx("span", { className: "agentkit-activities-label", children: summaryLabel })) : (_jsx("span", { className: "agentkit-activities-current", "data-running": "true", "data-agentkit-current-activity": "true", children: _jsx("span", { className: "agentkit-activities-current-label agent-running-shimmer", children: currentActivityLabel }) })) })) : null }))] }));
1531
1696
  });
1532
1697
  const WORK_STEP_PREVIEW_COUNT = 6;
1533
1698
  const WORK_GROUP_PREVIEW_COUNT = 4;
@@ -1642,7 +1807,7 @@ function AgentWorkGroupRow({ group, threadId, renderCall, }) {
1642
1807
  ]))
1643
1808
  : undefined;
1644
1809
  const reason = group.reason ? readableText(group.reason) : "";
1645
- return (_jsxs("div", { className: "agentkit-work-group", "data-verb": group.verb, "data-failed": group.failed ? "true" : undefined, "data-running": group.running ? "true" : undefined, "data-open": open ? "true" : "false", children: [_jsx(AgentKitDisclosureSummary, { rowClassName: "agentkit-activity-row agentkit-work-group-row", open: open, onToggle: () => setOpen((current) => !current), controls: contentId, icon: group.failed ? (_jsx(IconAlertTriangle, { "aria-hidden": "true", className: "agentkit-icon" })) : ((source?.icon ??
1810
+ return (_jsxs("div", { className: "agentkit-work-group", "data-verb": group.verb, "data-failed": group.failed ? "true" : undefined, "data-running": group.running ? "true" : undefined, "data-open": open ? "true" : "false", children: [_jsx(AgentKitDisclosureSummary, { rowClassName: "agentkit-activity-row agentkit-work-group-row", open: open, onToggle: () => setOpen((current) => !current), controls: contentId, status: group.failed ? "error" : group.running ? "running" : undefined, icon: group.failed ? (_jsx(IconAlertTriangle, { "aria-hidden": "true", className: "agentkit-icon" })) : ((source?.icon ??
1646
1811
  workVerbIcon(group.verb) ??
1647
1812
  activityIcon(activity.kind))), label: _jsxs(_Fragment, { children: [agent && AgentRenderer ? (_jsx(AgentRenderer, { value: agent, threadId: threadId })) : activity.agentId ? (_jsx(AgentIdentityChip, { id: activity.agentId, name: resolveAgentName(thread, activity.agentId, [activity.source, activity.object], labels.assistant), fallbackName: labels.assistant })) : null, _jsx("span", { className: "agentkit-activity-label agentkit-work-group-label", children: label }), group.verb === "used" && !group.failed && count > 1 ? (_jsxs("span", { className: "agentkit-activity-cluster-count", children: ["\u00D7", count] })) : null] }), meta: reason || group.objects.length || reference ? (_jsxs("span", { className: "agentkit-work-group-meta", children: [reason ? (_jsx("span", { ...SESSION_REPLAY_MASK_PROPS, className: "agentkit-work-failure-reason", children: reason })) : null, _jsx(AgentWorkObjects, { objects: group.objects }), reference ? (_jsx(ObjectRenderer, { value: reference, threadId: threadId })) : null] })) : null }), _jsx(AgentKitDisclosureContent, { id: contentId, open: open, onReveal: () => setOpen(true), children: _jsx("div", { className: "agentkit-activity-cluster-items", children: group.calls.map(renderCall) }) })] }));
1648
1813
  }
@@ -1691,7 +1856,7 @@ function AgentWorkStepItem({ step, plain, threadId, renderCall, }) {
1691
1856
  ? step.groups
1692
1857
  : step.groups.filter((group, index) => index < WORK_GROUP_PREVIEW_COUNT || group.failed);
1693
1858
  const hiddenGroups = step.groups.length - groups.length;
1694
- return (_jsxs("li", { className: "agentkit-work-step", "data-running": step.running ? "true" : undefined, "data-untitled": step.title ? undefined : "true", "data-open": open ? "true" : "false", children: [plain ? null : (_jsx("span", { className: "agentkit-work-step-marker", "aria-hidden": "true", children: _jsx(IconPointFilled, { className: "agentkit-icon" }) })), _jsxs("div", { className: "agentkit-work-step-content", children: [title ? (_jsx(AgentKitDisclosureSummary, { className: "agentkit-work-step-title", open: open, onToggle: () => setOpen((current) => !current), expandable: hasBody, as: hasBody ? "button" : "static", controls: hasBody ? bodyId : undefined, label: _jsx("span", { className: "agentkit-work-step-label", "data-active": step.active ? "true" : undefined, children: title }) })) : null, hasBody ? (_jsx(AgentKitDisclosureContent, { id: bodyId, open: open, onReveal: () => setOpen(true), children: _jsx("div", { className: "agentkit-reasoning-content agentkit-work-step-body", children: ReasoningRenderer ? (_jsx(AgentKitWorkStepBodyContext.Provider, { value: true, children: _jsx(ReasoningRenderer, { value: { type: "reasoning", text: step.reasoning ?? "" }, threadId: threadId, active: step.active, resetKey: `${threadId}:${step.key}` }) })) : (_jsx(AgentMarkdown, { text: step.body, streaming: step.active })) }) })) : null, step.groups.length ? (_jsxs("ul", { ref: groupsRef, className: "agentkit-work-groups", role: "list", children: [groups.map((group) => (_jsx("li", { children: group.standalone ||
1859
+ return (_jsxs("li", { className: "agentkit-work-step", "data-running": step.running ? "true" : undefined, "data-untitled": step.title ? undefined : "true", "data-open": open ? "true" : "false", children: [plain ? null : (_jsx("span", { className: "agentkit-work-step-marker", "aria-hidden": "true", children: _jsx(IconPointFilled, { className: "agentkit-icon" }) })), _jsxs("div", { className: "agentkit-work-step-content", children: [title ? (_jsx(AgentKitDisclosureSummary, { className: "agentkit-work-step-title", open: open, onToggle: () => setOpen((current) => !current), status: step.active ? "running" : undefined, expandable: hasBody, as: hasBody ? "button" : "static", controls: hasBody ? bodyId : undefined, label: _jsx("span", { className: "agentkit-work-step-label", "data-active": step.active ? "true" : undefined, children: title }) })) : null, hasBody ? (_jsx(AgentKitDisclosureContent, { id: bodyId, open: open, onReveal: () => setOpen(true), children: _jsx("div", { className: "agentkit-reasoning-content agentkit-work-step-body", children: ReasoningRenderer ? (_jsx(AgentKitWorkStepBodyContext.Provider, { value: true, children: _jsx(ReasoningRenderer, { value: { type: "reasoning", text: step.reasoning ?? "" }, threadId: threadId, active: step.active, resetKey: `${threadId}:${step.key}` }) })) : (_jsx(AgentMarkdown, { text: step.body, streaming: step.active })) }) })) : null, step.groups.length ? (_jsxs("ul", { ref: groupsRef, className: "agentkit-work-groups", role: "list", children: [groups.map((group) => (_jsx("li", { children: group.standalone ||
1695
1860
  (group.verb === "used" &&
1696
1861
  !group.failed &&
1697
1862
  group.calls.length === 1) ? (group.calls.map(renderCall)) : (_jsx(AgentWorkGroupRow, { group: group, threadId: threadId, renderCall: renderCall })) }, group.key))), hiddenGroups ? (_jsx("li", { children: _jsxs("button", { type: "button", className: "agentkit-disclosure-summary agentkit-work-more", onClick: () => {
@@ -1756,7 +1921,7 @@ function AgentWorkDisclosure({ label, failedCount = 0, icon, running, expandable
1756
1921
  // The row stays one mounted trigger from "Thinking" through the first
1757
1922
  // activity, so it never flickers; until then it is not a tab stop. Finished
1758
1923
  // work with nothing to expand is text, not a disabled button.
1759
- const disclosure = (_jsxs("div", { className: "agentkit-activities", "data-running": running ? "true" : undefined, "data-expandable": expandable ? "true" : "false", "data-open": open ? "true" : "false", children: [_jsx(AgentKitDisclosureSummary, { as: expandable || running ? "button" : "static", className: "agentkit-activities-summary", rowClassName: "agentkit-activities-row", open: open, onToggle: () => setOpen((value) => !value), expandable: expandable, controls: contentId, style: workedForRowSummaryStyle(workedForRowLayout), chevronStyle: workedForRowChevronStyle(workedForRowLayout), icon: icon, label: summaryLabel, children: summaryContent }), _jsxs(AgentKitDisclosureContent, { id: contentId, open: open, onReveal: expandable ? () => setOpen(true) : undefined, children: [runId && expandable && !running ? (_jsx(AgentRunDetails, { runId: runId, messageId: messageId, open: open })) : null, children] })] }));
1924
+ const disclosure = (_jsxs("div", { className: "agentkit-activities", "data-running": running ? "true" : undefined, "data-expandable": expandable ? "true" : "false", "data-open": open ? "true" : "false", children: [_jsx(AgentKitDisclosureSummary, { as: expandable || running ? "button" : "static", className: "agentkit-activities-summary", rowClassName: "agentkit-activities-row", open: open, onToggle: () => setOpen((value) => !value), status: running ? "running" : undefined, expandable: expandable, controls: contentId, style: workedForRowSummaryStyle(workedForRowLayout), chevronStyle: workedForRowChevronStyle(workedForRowLayout), icon: icon, label: summaryLabel, children: summaryContent }), _jsxs(AgentKitDisclosureContent, { id: contentId, open: open, onReveal: expandable ? () => setOpen(true) : undefined, children: [runId && expandable && !running ? (_jsx(AgentRunDetails, { runId: runId, messageId: messageId, open: open })) : null, children] })] }));
1760
1925
  // A reply's work sits on its footer line, live or finished, so the finish
1761
1926
  // never moves it.
1762
1927
  return footerHost ? createPortal(disclosure, footerHost) : disclosure;
@@ -1764,7 +1929,7 @@ function AgentWorkDisclosure({ label, failedCount = 0, icon, running, expandable
1764
1929
  function AgentReasoningPartDisclosure({ label, text, active, resetKey, }) {
1765
1930
  const [open, setOpen] = useState(false);
1766
1931
  const contentId = useId();
1767
- return (_jsxs("div", { className: "agentkit-reasoning", "data-active": active ? "true" : undefined, "data-open": open ? "true" : "false", children: [_jsx(AgentKitDisclosureSummary, { className: "agentkit-reasoning-summary", open: open, onToggle: () => setOpen((value) => !value), controls: contentId, icon: activityIcon("reasoning"), label: _jsx("span", { className: "agentkit-reasoning-label", children: label }) }), _jsx(AgentKitDisclosureContent, { id: contentId, open: open, onReveal: () => setOpen(true), children: _jsx("div", { className: "agentkit-reasoning-content", children: _jsx(AgentStreamingText, { text: text, active: active, resetKey: resetKey, children: (visibleText) => (_jsx(AgentMarkdown, { text: visibleText, streaming: active || visibleText !== text })) }) }) })] }));
1932
+ return (_jsxs("div", { className: "agentkit-reasoning", "data-active": active ? "true" : undefined, "data-open": open ? "true" : "false", children: [_jsx(AgentKitDisclosureSummary, { className: "agentkit-reasoning-summary", open: open, onToggle: () => setOpen((value) => !value), controls: contentId, status: active ? "running" : undefined, icon: activityIcon("reasoning"), label: _jsx("span", { className: "agentkit-reasoning-label", children: label }) }), _jsx(AgentKitDisclosureContent, { id: contentId, open: open, onReveal: () => setOpen(true), children: _jsx("div", { className: "agentkit-reasoning-content", children: _jsx(AgentStreamingText, { text: text, active: active, resetKey: resetKey, children: (visibleText) => (_jsx(AgentMarkdown, { text: visibleText, streaming: active || visibleText !== text })) }) }) })] }));
1768
1933
  }
1769
1934
  /** A reply's own reasoning as work steps, as a turn with tool calls lists it. */
1770
1935
  function AgentReasoningSteps({ message, threadId, active, }) {
@@ -1781,12 +1946,28 @@ function AgentReasoningSteps({ message, threadId, active, }) {
1781
1946
  : [])), [active, message]);
1782
1947
  return (_jsx(AgentWorkStepList, { steps: steps, threadId: threadId, running: active, renderCall: () => null }));
1783
1948
  }
1784
- export function AgentCollaborationFeed({ runId, afterSequence, throughSequence, }) {
1785
- const { threadId, slots, registry, labels } = useAgentKit();
1786
- const thread = useAgentThreadSlice((previous, next) => sameRunWork(previous, next, runId));
1787
- const runEvents = agentRunEvents(thread, runId);
1949
+ function collaborationSubjectId(entry, thread) {
1950
+ const isPrimary = (id) => id !== undefined && thread.agents[id]?.kind === "primary";
1951
+ if (entry.type === "activity") {
1952
+ const id = entry.value.agentId;
1953
+ return id && !isPrimary(id) ? id : undefined;
1954
+ }
1955
+ const { agentId, targetAgentId } = entry.value;
1956
+ if (isPrimary(agentId)) {
1957
+ return targetAgentId && !isPrimary(targetAgentId)
1958
+ ? targetAgentId
1959
+ : undefined;
1960
+ }
1961
+ return agentId;
1962
+ }
1963
+ /** Each delegated agent's entries fold into one item where it first appears. */
1964
+ function agentCollaborationItems(thread, runEvents, labels, range) {
1788
1965
  const entries = new Map();
1966
+ const firstSequence = new Map();
1967
+ const order = [];
1789
1968
  const delegatedAgentIds = new Map();
1969
+ // A delegated agent's own tool calls leave the parent's work for its step.
1970
+ const delegatedToolAgentIds = new Map();
1790
1971
  for (const event of runEvents) {
1791
1972
  if (event.type === "activity.started" ||
1792
1973
  event.type === "activity.updated" ||
@@ -1796,15 +1977,18 @@ export function AgentCollaborationFeed({ runId, afterSequence, throughSequence,
1796
1977
  if (agentId)
1797
1978
  delegatedAgentIds.set(event.activity.id, agentId);
1798
1979
  }
1980
+ if (event.type === "tool.started" || event.type === "tool.updated") {
1981
+ const agentId = event.toolCall.agentId ?? thread.tools[event.toolCall.id]?.agentId;
1982
+ if (agentId)
1983
+ delegatedToolAgentIds.set(event.toolCall.id, agentId);
1984
+ }
1799
1985
  }
1800
- const firstSequence = new Map();
1801
- const order = [];
1802
1986
  const remember = (key, sequence, entry) => {
1803
1987
  if (!entries.has(key)) {
1804
1988
  order.push(key);
1805
1989
  firstSequence.set(key, sequence);
1806
1990
  }
1807
- entries.set(key, entry);
1991
+ entries.set(key, { ...entry, sequence });
1808
1992
  };
1809
1993
  for (const event of runEvents) {
1810
1994
  if (event.type === "agent.interaction") {
@@ -1825,18 +2009,341 @@ export function AgentCollaborationFeed({ runId, afterSequence, throughSequence,
1825
2009
  value: { ...activity, agentId },
1826
2010
  });
1827
2011
  }
2012
+ const toolId = event.type === "tool.started" || event.type === "tool.updated"
2013
+ ? event.toolCall.id
2014
+ : event.type === "tool.delta"
2015
+ ? event.toolCallId
2016
+ : undefined;
2017
+ const toolAgentId = toolId ? delegatedToolAgentIds.get(toolId) : undefined;
2018
+ if (toolId && toolAgentId) {
2019
+ const tool = toolId in thread.tools
2020
+ ? thread.tools[toolId]
2021
+ : event.type === "tool.started" || event.type === "tool.updated"
2022
+ ? event.toolCall
2023
+ : undefined;
2024
+ if (tool) {
2025
+ remember(`tool:${toolId}`, event.sequence, {
2026
+ type: "activity",
2027
+ value: { ...toolToActivity(tool, labels), agentId: toolAgentId },
2028
+ });
2029
+ }
2030
+ }
1828
2031
  }
1829
- const selectedOrder = order.filter((key) => {
2032
+ const items = [];
2033
+ const subagents = new Map();
2034
+ for (const key of order) {
1830
2035
  const sequence = firstSequence.get(key);
1831
- return (sequence !== undefined &&
1832
- sequenceInRange(sequence, { afterSequence, throughSequence }));
2036
+ const entry = entries.get(key);
2037
+ if (!entry || sequence === undefined || !sequenceInRange(sequence, range)) {
2038
+ continue;
2039
+ }
2040
+ const agentId = collaborationSubjectId(entry, thread);
2041
+ if (!agentId) {
2042
+ items.push({ type: "entry", key, entry });
2043
+ continue;
2044
+ }
2045
+ const grouped = subagents.get(agentId);
2046
+ if (grouped) {
2047
+ grouped.push(entry);
2048
+ continue;
2049
+ }
2050
+ const created = [entry];
2051
+ subagents.set(agentId, created);
2052
+ items.push({
2053
+ type: "subagent",
2054
+ key: `subagent:${agentId}`,
2055
+ agentId,
2056
+ entries: created,
2057
+ });
2058
+ }
2059
+ return items;
2060
+ }
2061
+ /** The one task a Subagent step shows: the agent's active task, else its first. */
2062
+ function subagentStepTask(thread, agentId) {
2063
+ const agent = agentId in thread.agents ? thread.agents[agentId] : undefined;
2064
+ return Object.values(thread.tasks).find((candidate) => candidate.assignedAgentId === agentId &&
2065
+ (agent?.activeTaskId === undefined ||
2066
+ candidate.id === agent.activeTaskId));
2067
+ }
2068
+ /** Tasks the Subagent steps in this range of a run show. */
2069
+ function subagentStepTaskIds(thread, runId, labels, range) {
2070
+ const ids = new Set();
2071
+ for (const item of agentCollaborationItems(thread, agentRunEvents(thread, runId), labels, range)) {
2072
+ if (item.type !== "subagent")
2073
+ continue;
2074
+ const task = subagentStepTask(thread, item.agentId);
2075
+ if (task)
2076
+ ids.add(task.id);
2077
+ }
2078
+ return ids;
2079
+ }
2080
+ /** Set inside a Subagent step, so its rows do not repeat the agent's chip. */
2081
+ const AgentSubagentStepContext = createContext(undefined);
2082
+ const SUBAGENT_LIFECYCLE_KINDS = new Set([
2083
+ "started",
2084
+ "resumed",
2085
+ "delegated",
2086
+ "paused",
2087
+ "completed",
2088
+ "failed",
2089
+ "closed",
2090
+ ]);
2091
+ function subagentState(agent, entries) {
2092
+ switch (agent?.status) {
2093
+ case "waiting":
2094
+ case "paused":
2095
+ return "paused";
2096
+ case "completed":
2097
+ return "completed";
2098
+ case "failed":
2099
+ return "failed";
2100
+ case "closed":
2101
+ return "closed";
2102
+ case "idle":
2103
+ case "working":
2104
+ case undefined:
2105
+ break;
2106
+ }
2107
+ // Status can stay "working" past its last event; a finished call is not a finished agent.
2108
+ const newestFirst = [...entries].sort((a, b) => b.sequence - a.sequence);
2109
+ for (const entry of newestFirst) {
2110
+ if (entry.type === "activity") {
2111
+ if (entry.value.status === "running")
2112
+ return "running";
2113
+ continue;
2114
+ }
2115
+ switch (entry.value.kind) {
2116
+ case "completed":
2117
+ return "completed";
2118
+ case "failed":
2119
+ return "failed";
2120
+ case "paused":
2121
+ return "paused";
2122
+ case "closed":
2123
+ return "closed";
2124
+ case "started":
2125
+ case "resumed":
2126
+ case "delegated":
2127
+ return "running";
2128
+ case "messaged":
2129
+ default:
2130
+ break;
2131
+ }
2132
+ }
2133
+ if (agent?.status === "working")
2134
+ return "running";
2135
+ const latest = newestFirst.at(0);
2136
+ return latest?.type === "activity" && latest.value.status === "failed"
2137
+ ? "failed"
2138
+ : latest?.type === "activity" && latest.value.status === "completed"
2139
+ ? "completed"
2140
+ : "running";
2141
+ }
2142
+ function metadataDurationMs(metadata) {
2143
+ const value = metadata?.durationMs;
2144
+ return typeof value === "number" && Number.isFinite(value) && value >= 0
2145
+ ? value
2146
+ : undefined;
2147
+ }
2148
+ function subagentDurationMs(agent, entries) {
2149
+ const fromAgent = metadataDurationMs(agent?.metadata);
2150
+ if (fromAgent !== undefined)
2151
+ return fromAgent;
2152
+ for (const entry of [...entries].sort((a, b) => b.sequence - a.sequence)) {
2153
+ const fromEntry = metadataDurationMs(entry.value.metadata);
2154
+ if (fromEntry !== undefined)
2155
+ return fromEntry;
2156
+ }
2157
+ const started = agent?.startedAt ? Date.parse(agent.startedAt) : Number.NaN;
2158
+ const completed = agent?.completedAt
2159
+ ? Date.parse(agent.completedAt)
2160
+ : Number.NaN;
2161
+ return Number.isFinite(started) &&
2162
+ Number.isFinite(completed) &&
2163
+ completed >= started
2164
+ ? completed - started
2165
+ : undefined;
2166
+ }
2167
+ /** One row per delegated agent, with its own calls and its result inside. */
2168
+ export function AgentSubagentStep({ agentId, entries, runId, threadId, }) {
2169
+ const { slots, registry, labels, formatWorkedForDuration, formatAgentInteractionDetail, } = useAgentKit();
2170
+ const thread = useAgentThreadSlice((previous, next) => sameAgentsAndTasks(previous, next) &&
2171
+ previous.tools === next.tools &&
2172
+ previous.runs === next.runs);
2173
+ const [open, setOpen] = useState(false);
2174
+ const agent = agentId in thread.agents ? thread.agents[agentId] : undefined;
2175
+ const AgentRenderer = agent
2176
+ ? (registry.agents?.[agent.kind ?? ""] ??
2177
+ slots.agent ??
2178
+ AgentParticipantView)
2179
+ : undefined;
2180
+ const name = resolveAgentName(thread, agentId, entries.map((entry) => entry.value.source), labels.assistant);
2181
+ const runStatus = runId === undefined ? undefined : thread.runs[runId]?.status;
2182
+ const liveState = subagentState(agent, entries);
2183
+ // Agents can outlive their run, so one still "working" after it settled has stopped.
2184
+ const settledStatus = liveState !== "running"
2185
+ ? undefined
2186
+ : runStatus === "completed"
2187
+ ? "completed"
2188
+ : runStatus === "failed"
2189
+ ? "failed"
2190
+ : runStatus === "cancelled"
2191
+ ? "closed"
2192
+ : undefined;
2193
+ const state = settledStatus ?? liveState;
2194
+ const durationMs = state === "running" ? undefined : subagentDurationMs(agent, entries);
2195
+ const duration = durationMs === undefined
2196
+ ? undefined
2197
+ : (formatWorkedForDuration?.(durationMs) ??
2198
+ formatAgentKitDuration(durationMs, {
2199
+ hour: labels.durationHourShort,
2200
+ minute: labels.durationMinuteShort,
2201
+ second: labels.durationSecondShort,
2202
+ }));
2203
+ const task = subagentStepTask(thread, agentId);
2204
+ const taskTitle = task ? humanizeAgentLabel(task.title) : "";
2205
+ const shownTaskTitle = taskTitle && taskTitle.toLocaleLowerCase() !== name.toLocaleLowerCase()
2206
+ ? taskTitle
2207
+ : "";
2208
+ const newestFirst = [...entries].sort((a, b) => b.sequence - a.sequence);
2209
+ const latest = (pick) => {
2210
+ for (const entry of newestFirst) {
2211
+ const value = pick(entry);
2212
+ if (value !== undefined)
2213
+ return value;
2214
+ }
2215
+ return undefined;
2216
+ };
2217
+ // A call's detail is its output, which is no headline.
2218
+ const progress = state === "running"
2219
+ ? latest((entry) => entry.type === "activity" &&
2220
+ entry.value.status === "running" &&
2221
+ !(entry.value.id in thread.tools) &&
2222
+ readableText(entry.value.detail)
2223
+ ? entry.value
2224
+ : undefined)
2225
+ : undefined;
2226
+ const progressDetail = progress ? readableText(progress.detail) : "";
2227
+ const failureDetail = state === "failed"
2228
+ ? latest((entry) => entry.type === "interaction" && entry.value.kind === "failed"
2229
+ ? readableText(formatAgentInteractionDetail?.(entry.value) ??
2230
+ entry.value.detail) || undefined
2231
+ : entry.type === "activity" && entry.value.status === "failed"
2232
+ ? readableText(entry.value.detail) || undefined
2233
+ : undefined)
2234
+ : undefined;
2235
+ const status = state === "running"
2236
+ ? labels.agentWorking
2237
+ : state === "failed"
2238
+ ? labels.agentFailed
2239
+ : state === "paused"
2240
+ ? labels.agentPaused
2241
+ : state === "closed"
2242
+ ? labels.agentClosed
2243
+ : duration
2244
+ ? labels.agentWorkedFor.replace("{{duration}}", () => duration)
2245
+ : labels.agentCompleted;
2246
+ const content = entries.flatMap((entry) => {
2247
+ const key = `${entry.type}:${entry.value.id}`;
2248
+ if (entry.type === "interaction") {
2249
+ const interaction = entry.value;
2250
+ const Custom = registry.agentInteractions?.[interaction.kind] ??
2251
+ slots.agentInteraction;
2252
+ if (Custom) {
2253
+ return [_jsx(Custom, { value: interaction, threadId: threadId }, key)];
2254
+ }
2255
+ // The row's own status, duration and error line already say these.
2256
+ if (SUBAGENT_LIFECYCLE_KINDS.has(interaction.kind) &&
2257
+ (interaction.kind === "failed" ||
2258
+ !(interaction.label ||
2259
+ interaction.detail ||
2260
+ interaction.object ||
2261
+ interaction.targetAgentId))) {
2262
+ return [];
2263
+ }
2264
+ return [
2265
+ _jsx(AgentInteractionItem, { value: interaction, threadId: threadId }, key),
2266
+ ];
2267
+ }
2268
+ const activity = entry.value;
2269
+ const Custom = registry.activities?.[activity.kind] ?? slots.activity;
2270
+ if (Custom) {
2271
+ return [_jsx(Custom, { value: activity, threadId: threadId }, key)];
2272
+ }
2273
+ if (activity.id in thread.tools) {
2274
+ return [
2275
+ _jsx(AgentActivityItem, { value: activity, threadId: threadId }, key),
2276
+ ];
2277
+ }
2278
+ // The agent's report is the step's result, so it shows in place.
2279
+ const summary = (activity.summary ?? []).flatMap((part, partIndex) => {
2280
+ const safePart = part.type === "text"
2281
+ ? {
2282
+ ...part,
2283
+ text: part.text.trim()
2284
+ ? formatActivityText(part.text, labels)
2285
+ : "",
2286
+ }
2287
+ : part;
2288
+ return safePart.type === "text" && !safePart.text
2289
+ ? []
2290
+ : [
2291
+ _jsx(AgentMessagePartView, { value: safePart, threadId: threadId }, `${key}:summary:${partIndex}`),
2292
+ ];
2293
+ });
2294
+ if (summary.length)
2295
+ return summary;
2296
+ // A summary-less "agent" activity is the status line the header carries.
2297
+ if (activity === progress || activity.kind === "agent")
2298
+ return [];
2299
+ return [
2300
+ _jsx(AgentActivityItem, { value: activity, threadId: threadId }, key),
2301
+ ];
1833
2302
  });
1834
- if (selectedOrder.length === 0)
2303
+ const failed = state === "failed";
2304
+ const line = (_jsxs(TraceLine, { status: state === "running" ? "running" : failed ? "error" : undefined, children: [_jsx(TraceIcon, { children: _jsx(IconArrowFork, { "aria-hidden": "true", className: "agentkit-icon" }) }), _jsxs("span", { className: "agentkit-disclosure-label", children: [agent && AgentRenderer ? (_jsx(AgentRenderer, { value: settledStatus ? { ...agent, status: settledStatus } : agent, threadId: threadId })) : (_jsx(AgentIdentityChip, { id: agentId, name: name, fallbackName: labels.assistant, ...(failed
2305
+ ? { status: "failed" }
2306
+ : state === "running"
2307
+ ? { status: "working" }
2308
+ : {}) })), _jsx(TraceTitle, { className: "agentkit-activity-label", children: status })] })] }));
2309
+ const detail = shownTaskTitle || progressDetail;
2310
+ const ObjectRenderer = slots.object ?? AgentObjectReferenceView;
2311
+ const taskObject = task
2312
+ ? (task.object ??
2313
+ sourceObjectUnlessRepresented(task.source, thread, [agentId]))
2314
+ : undefined;
2315
+ const meta = detail || taskObject ? (_jsxs(_Fragment, { children: [taskObject ? (_jsx(ObjectRenderer, { value: taskObject, threadId: threadId })) : null, detail ? (_jsx(TraceDescription, { ...SESSION_REPLAY_MASK_PROPS, className: "agentkit-activity-detail", children: detail })) : null] })) : null;
2316
+ const errorLine = failureDetail ? (_jsx("span", { ...SESSION_REPLAY_MASK_PROPS, className: "agentkit-activity-error", children: failureDetail })) : null;
2317
+ const rootProps = {
2318
+ className: "agentkit-subagent-step",
2319
+ "data-agent-id": agentId,
2320
+ // Not data-state: the collapsible keeps its open state there.
2321
+ "data-status": state,
2322
+ };
2323
+ if (!content.length) {
2324
+ return (_jsxs("div", { ...rootProps, children: [_jsxs("div", { className: "agentkit-disclosure-row agentkit-activity-row", children: [_jsx("span", { className: "agentkit-disclosure-summary", "data-expandable": "false", children: line }), meta] }), errorLine] }));
2325
+ }
2326
+ return (_jsxs(TraceCollapsible, { ...rootProps, open: open, onOpenChange: setOpen, children: [_jsxs("div", { className: "agentkit-disclosure-row agentkit-activity-row", "data-expandable": "true", onClick: (event) => {
2327
+ const target = event.target;
2328
+ if (target instanceof Element &&
2329
+ target.closest(DISCLOSURE_ROW_INTERACTIVE))
2330
+ return;
2331
+ if (globalThis.getSelection()?.toString())
2332
+ return;
2333
+ setOpen((current) => !current);
2334
+ }, children: [_jsx(TraceCollapsibleTrigger, { children: line }), meta] }), errorLine, _jsx(TraceCollapsibleContent, { keepMounted: true, ...(failed || !open ? SESSION_REPLAY_BLOCK_PROPS : {}), className: "agentkit-subagent-content", children: _jsx(AgentSubagentStepContext.Provider, { value: agentId, children: content }) }, open ? "open" : "closed")] }));
2335
+ }
2336
+ export function AgentCollaborationFeed({ runId, afterSequence, throughSequence, }) {
2337
+ const { threadId, slots, registry, labels } = useAgentKit();
2338
+ const thread = useAgentThreadSlice((previous, next) => sameRunWork(previous, next, runId));
2339
+ const items = agentCollaborationItems(thread, agentRunEvents(thread, runId), labels, { afterSequence, throughSequence });
2340
+ if (items.length === 0)
1835
2341
  return null;
1836
- return (_jsx("section", { className: "agentkit-agent-feed", "aria-label": labels.agents, "data-agent-collaboration-feed": "true", children: selectedOrder.map((key) => {
1837
- const entry = entries.get(key);
1838
- if (!entry)
1839
- return null;
2342
+ return (_jsx("section", { className: "agentkit-agent-feed", "aria-label": labels.agents, "data-agent-collaboration-feed": "true", children: items.map((item) => {
2343
+ if (item.type === "subagent") {
2344
+ return (_jsx(AgentSubagentStep, { agentId: item.agentId, entries: item.entries, runId: runId, threadId: threadId }, item.key));
2345
+ }
2346
+ const { entry, key } = item;
1840
2347
  if (entry.type === "interaction") {
1841
2348
  const Renderer = registry.agentInteractions?.[entry.value.kind] ??
1842
2349
  slots.agentInteraction ??
@@ -1898,8 +2405,11 @@ export function AgentTaskItem({ value: task, threadId, }) {
1898
2405
  slots.agent ??
1899
2406
  AgentParticipantView)
1900
2407
  : undefined;
1901
- const progress = task.progress
1902
- ? `${task.progress.completed}/${task.progress.total}`
2408
+ const taskProgress = task.progress;
2409
+ const progress = taskProgress
2410
+ ? labels.tasksProgress
2411
+ .replace("{{completed}}", () => String(taskProgress.completed))
2412
+ .replace("{{total}}", () => String(taskProgress.total))
1903
2413
  : undefined;
1904
2414
  const title = humanizeAgentLabel(task.title) ||
1905
2415
  (task.assignedAgentId ? agentName : labels.untitledTask);
@@ -1909,7 +2419,11 @@ export function AgentTaskItem({ value: task, threadId, }) {
1909
2419
  const showAgent = task.assignedAgentId &&
1910
2420
  title.toLocaleLowerCase() !== agentName.toLocaleLowerCase();
1911
2421
  const status = taskStatusPresentation(task.status, labels);
1912
- return (_jsxs("div", { className: "agentkit-task-row", "data-status": task.status, children: [status.icon, _jsx("span", { className: "agentkit-visually-hidden", children: status.label }), showAgent && agent && AgentRenderer ? (_jsx(AgentRenderer, { value: agent, threadId: threadId })) : showAgent && task.assignedAgentId ? (_jsx(AgentIdentityChip, { id: task.assignedAgentId, name: agentName, fallbackName: labels.assistant })) : null, _jsx("span", { className: "agentkit-task-title", children: title }), object ? _jsx(ObjectRenderer, { value: object, threadId: threadId }) : null, detail ? (_jsx("span", { className: "agentkit-task-detail", title: detail, children: detail })) : null, progress ? (_jsx("span", { className: "agentkit-task-progress", children: progress })) : null] }));
2422
+ return (_jsxs(TraceLine, { className: "agentkit-task-row", "data-status": task.status, status: task.status === "running"
2423
+ ? "running"
2424
+ : task.status === "failed"
2425
+ ? "error"
2426
+ : undefined, children: [_jsx(TraceIcon, { children: status.icon }), _jsx("span", { className: "agentkit-visually-hidden", children: status.label }), showAgent && agent && AgentRenderer ? (_jsx(AgentRenderer, { value: agent, threadId: threadId })) : showAgent && task.assignedAgentId ? (_jsx(AgentIdentityChip, { id: task.assignedAgentId, name: agentName, fallbackName: labels.assistant })) : null, _jsx(TraceTitle, { className: "agentkit-task-title", children: title }), object ? _jsx(ObjectRenderer, { value: object, threadId: threadId }) : null, detail ? (_jsx("span", { className: "agentkit-task-detail", title: detail, children: detail })) : null, progress ? (_jsx(TraceDescription, { className: "agentkit-task-progress", children: progress })) : null] }));
1913
2427
  }
1914
2428
  export function AgentTaskGroup({ runId, afterSequence, throughSequence, }) {
1915
2429
  const { threadId, slots, registry, labels } = useAgentKit();
@@ -1931,14 +2445,23 @@ export function AgentTaskGroup({ runId, afterSequence, throughSequence, }) {
1931
2445
  }
1932
2446
  tasks.set(event.task.id, thread.tasks[event.task.id] ?? event.task);
1933
2447
  }
2448
+ // Only the task a Subagent step shows moves out of this list.
2449
+ const stepTaskIds = subagentStepTaskIds(thread, runId, labels, {
2450
+ afterSequence,
2451
+ throughSequence,
2452
+ });
1934
2453
  const selectedIds = ids.filter((id) => {
1935
2454
  const sequence = firstSequence.get(id);
1936
2455
  return (sequence !== undefined &&
1937
- sequenceInRange(sequence, { afterSequence, throughSequence }));
2456
+ sequenceInRange(sequence, { afterSequence, throughSequence }) &&
2457
+ !stepTaskIds.has(id));
1938
2458
  });
1939
2459
  if (selectedIds.length === 0)
1940
2460
  return null;
1941
- return (_jsxs("div", { className: "agentkit-tasks", "data-open": open ? "true" : "false", children: [_jsx(AgentKitDisclosureSummary, { className: "agentkit-tasks-summary", open: open, onToggle: () => setOpen((value) => !value), controls: listId, icon: _jsx(IconChecklist, { "aria-hidden": "true", className: "agentkit-icon" }), label: _jsxs(_Fragment, { children: [_jsx("span", { children: labels.tasks }), _jsx("span", { className: "agentkit-tasks-count", children: selectedIds.length })] }) }), _jsx(AgentKitDisclosureContent, { id: listId, open: open, onReveal: () => setOpen(true), children: _jsx("div", { className: "agentkit-tasks-list", children: selectedIds.map((id) => {
2461
+ const completedCount = selectedIds.filter((id) => tasks.get(id)?.status === "completed").length;
2462
+ return (_jsxs("div", { className: "agentkit-tasks", "data-open": open ? "true" : "false", children: [_jsx(AgentKitDisclosureSummary, { className: "agentkit-tasks-summary", open: open, onToggle: () => setOpen((value) => !value), controls: listId, icon: _jsx(IconChecklist, { "aria-hidden": "true", className: "agentkit-icon" }), label: _jsxs(_Fragment, { children: [_jsx("span", { children: labels.tasks }), _jsx("span", { className: "agentkit-tasks-count", children: labels.tasksProgress
2463
+ .replace("{{completed}}", () => String(completedCount))
2464
+ .replace("{{total}}", () => String(selectedIds.length)) })] }) }), _jsx(AgentKitDisclosureContent, { id: listId, open: open, onReveal: () => setOpen(true), children: _jsx("div", { className: "agentkit-tasks-list", children: selectedIds.map((id) => {
1942
2465
  const task = tasks.get(id);
1943
2466
  if (!task)
1944
2467
  return null;
@@ -2168,11 +2691,11 @@ export function AgentConnectionRequestCard({ request, runId, providerLabel, retr
2168
2691
  : labels.connectionConnectProvider.replace("{{provider}}", () => providerName);
2169
2692
  const description = request.detail?.trim() ||
2170
2693
  (adminRequired && !terminal ? labels.connectionAdminRequired : undefined);
2171
- return (_jsxs(Surface, { as: "section", className: "agentkit-connection-request shadow-(--agent-kit-control-elevation)", elevation: "low", padding: "none", "data-status": request.status, "aria-labelledby": `${request.id}-title`, children: [_jsxs("div", { className: "agentkit-connection-request-copy", children: [_jsx(IconPlugConnected, { "aria-hidden": "true", className: "agentkit-icon" }), _jsxs("div", { children: [_jsx("h3", { id: `${request.id}-title`, children: title }), description ? _jsx("p", { children: description }) : null] })] }), !terminal && request.reason !== "admin_required" ? (_jsxs("div", { className: "agentkit-connection-request-actions", children: [_jsx(ActionButton, { emphasis: "outline", size: "compact", disabled: resolution.pending, onPress: () => resolve("decline"), children: labels.connectionNotNow }), _jsx(ActionButton, { className: "agentkit-primary-button", intent: "primary", size: "compact", disabled: resolution.pending || (!onConnectionRequest && !onConnect), pending: resolution.pending, onPress: () => resolve("connect"), children: resolution.pending
2694
+ return (_jsxs(Surface, { as: "section", className: "agentkit-connection-request", elevation: "none", padding: "none", "data-status": request.status, "aria-labelledby": `${request.id}-title`, children: [_jsxs("div", { className: "agentkit-connection-request-copy", children: [_jsx(IconPlugConnected, { "aria-hidden": "true", className: "agentkit-icon" }), _jsxs("div", { children: [_jsx("h3", { id: `${request.id}-title`, children: title }), description ? _jsx("p", { children: description }) : null] })] }), !terminal && request.reason !== "admin_required" ? (_jsxs("div", { className: "agentkit-connection-request-actions", children: [_jsx(ActionButton, { emphasis: "outline", size: "compact", disabled: resolution.pending, onPress: () => resolve("decline"), children: labels.connectionNotNow }), _jsx(ActionButton, { className: "agentkit-primary-button", intent: "primary", size: "compact", disabled: resolution.pending || (!onConnectionRequest && !onConnect), pending: resolution.pending, onPress: () => resolve("connect"), children: resolution.pending
2172
2695
  ? labels.connectionConnecting
2173
2696
  : retry
2174
2697
  ? labels.connectionRetry
2175
- : labels.connectionConnect })] })) : request.status === "failed" && (onConnectionRequest || onConnect) ? (_jsx("div", { className: "agentkit-connection-request-actions", children: _jsx(ActionButton, { emphasis: "outline", size: "compact", disabled: resolution.pending, pending: resolution.pending, onPress: () => resolve("connect"), children: labels.connectionRetry }) })) : null, resolution.error ? (_jsxs("div", { className: "agentkit-command-error", role: "alert", children: [_jsx(IconAlertCircle, { "aria-hidden": "true", className: "agentkit-icon" }), _jsx("span", { ...SESSION_REPLAY_MASK_PROPS, children: resolution.error.message })] })) : null] }));
2698
+ : labels.connectionConnect })] })) : request.status === "failed" && (onConnectionRequest || onConnect) ? (_jsx("div", { className: "agentkit-connection-request-actions", children: _jsx(ActionButton, { emphasis: "outline", size: "compact", disabled: resolution.pending, pending: resolution.pending, onPress: () => resolve("connect"), children: labels.connectionRetry }) })) : null, resolution.error ? (_jsxs("div", { className: "agentkit-command-error", role: "alert", children: [_jsx(IconAlertTriangle, { "aria-hidden": "true", className: "agentkit-icon" }), _jsx("span", { ...SESSION_REPLAY_MASK_PROPS, children: resolution.error.message })] })) : null] }));
2176
2699
  }
2177
2700
  function AgentWidgetActionButton({ widget, action, threadId, }) {
2178
2701
  const control = useAgentKitControl(threadId);
@@ -2716,20 +3239,52 @@ function AgentMessageTimestamp({ createdAt, format, }) {
2716
3239
  const fallback = formatAgentMessageTimestamp(createdAt);
2717
3240
  return (_jsx("time", { dateTime: createdAt, title: fallback.title, children: format?.(createdAt) ?? fallback.text }));
2718
3241
  }
3242
+ /** Enter and Space fire a click with no pointer detail. */
3243
+ function pressedByKeyboard(event) {
3244
+ return event?.detail === 0;
3245
+ }
3246
+ /** Keyboard presses only: focusing the composer on touch opens the on-screen keyboard. */
3247
+ function useRescueFocusToComposer(threadId) {
3248
+ const { requestComposerFocus } = useAgentKit();
3249
+ return useCallback(() => {
3250
+ requestAnimationFrame(() => {
3251
+ const active = document.activeElement;
3252
+ if (!active || active === document.body)
3253
+ requestComposerFocus(threadId);
3254
+ });
3255
+ }, [requestComposerFocus, threadId]);
3256
+ }
2719
3257
  /**
2720
3258
  * Names an icon-only message action on hover and keyboard focus. Below the
2721
3259
  * button, so it never covers the message it acts on.
2722
3260
  */
2723
- function MessageActionButton({ title, ...props }) {
2724
- // A disabled button gets no pointer events, so only a native title can
2725
- // explain it; an enabled one shows the reason in its tooltip instead, so a
2726
- // degraded action never opens both.
2727
- const inactive = Boolean(props.disabled || props.pending);
3261
+ function MessageActionButton({ title, busy = false, unavailable = false, icon, onPress, className, ...props }) {
3262
+ // Only a native title explains a disabled button, never also the tooltip. An
3263
+ // unavailable one stays focusable and a press opens its tooltip: taps never hover.
3264
+ const inactive = Boolean(props.disabled || props.pending || busy);
2728
3265
  const reason = inactive ? undefined : title;
2729
- return (_jsx(Tooltip, { content: reason ? (_jsxs(_Fragment, { children: [props.label, _jsx("span", { className: "block text-muted-foreground", children: reason })] })) : (props.label), placement: "bottom", trigger: _jsx(IconButton, { ...props, ...(inactive && title !== undefined ? { title } : {}) }) }));
3266
+ const reasonId = useId();
3267
+ const [tooltipOpen, setTooltipOpen] = useState(false);
3268
+ return (_jsxs(_Fragment, { children: [_jsx(Tooltip, { open: tooltipOpen, onOpenChange: setTooltipOpen, content: reason ? (_jsxs(_Fragment, { children: [props.label, _jsx("span", { className: "block text-muted-foreground", children: reason })] })) : (props.label), placement: "bottom", trigger: _jsx(IconButton, { ...props, icon: busy ? (_jsx(IconLoader2, { "aria-hidden": "true", className: "animate-spin" })) : (icon), ...(unavailable
3269
+ ? {
3270
+ className: `${className ?? ""} aria-disabled:cursor-default aria-disabled:opacity-50`,
3271
+ }
3272
+ : className
3273
+ ? { className }
3274
+ : {}), ...(busy ? { "aria-busy": true } : {}), ...(unavailable ? { "aria-disabled": true } : {}), ...(reason ? { "aria-describedby": reasonId } : {}), onPress: (event) => {
3275
+ if (unavailable) {
3276
+ if (reason)
3277
+ setTooltipOpen(true);
3278
+ return;
3279
+ }
3280
+ if (busy)
3281
+ return;
3282
+ onPress?.(event);
3283
+ }, ...(inactive && title !== undefined ? { title } : {}) }) }), reason ? (_jsx("span", { id: reasonId, hidden: true, children: reason })) : null] }));
2730
3284
  }
2731
3285
  export const AgentMessageActions = memo(function AgentMessageActions({ value: message, threadId, }) {
2732
3286
  const { controller, labels, slots, onThreadForked, onCopyMessage, branchNavigation, } = useAgentKit();
3287
+ const rescueFocusToComposer = useRescueFocusToComposer(threadId);
2733
3288
  const feedbackCapability = useAgentCapability("feedback");
2734
3289
  const forkingCapability = useAgentCapability("threadForking");
2735
3290
  const control = useAgentKitControl(threadId);
@@ -2773,6 +3328,10 @@ export const AgentMessageActions = memo(function AgentMessageActions({ value: me
2773
3328
  const feedbackConfirmedTimer = useRef(null);
2774
3329
  const requestIdCopiedTimer = useRef(null);
2775
3330
  const toolbarRef = useRef(null);
3331
+ const actionsRef = useRef(null);
3332
+ // One tab stop per message: the toolbar for a reply, the row for a sent message.
3333
+ useRovingFocus(toolbarRef, isAssistant);
3334
+ useRovingFocus(actionsRef, !isAssistant);
2776
3335
  const moreToggleRef = useRef(null);
2777
3336
  const secondaryActionsRef = useRef(null);
2778
3337
  const pendingFocusRef = useRef(null);
@@ -2903,22 +3462,21 @@ export const AgentMessageActions = memo(function AgentMessageActions({ value: me
2903
3462
  forkAction.error ??
2904
3463
  regenerateAction.error;
2905
3464
  const placement = isAssistant ? "inline" : undefined;
2906
- const copyButton = (_jsx(MessageActionButton, { label: copied ? labels.copied : labels.copy, icon: copyAction.pending ? (_jsx(IconLoader2, { "aria-hidden": "true", className: "animate-spin" })) : copied ? (_jsx(IconCircleCheck, { "aria-hidden": "true" })) : (_jsx(IconCopy, { "aria-hidden": "true" })), size: "compact", className: "size-6", "aria-busy": copyAction.pending || undefined, onPress: () => {
3465
+ const copyButton = (_jsx(MessageActionButton, { label: copied ? labels.copied : labels.copy, icon: copyAction.pending ? (_jsx(IconLoader2, { "aria-hidden": "true", className: "animate-spin" })) : copied ? (_jsx(IconCircleCheck, { "aria-hidden": "true" })) : (_jsx(IconCopy, { "aria-hidden": "true" })), size: "compact", className: "size-6 rounded-[var(--agent-kit-radius-xs,0.25rem)]", "aria-busy": copyAction.pending || undefined, onPress: () => {
2907
3466
  if (copyAction.pending)
2908
3467
  return;
2909
3468
  void copyAction.execute().catch(() => undefined);
2910
3469
  } }));
2911
3470
  const branchControls = branchNavigation && branchNavigation.count > 1 ? (_jsxs("div", { className: "agentkit-branch-navigation", role: "group", "aria-label": labels.branchPositionLabel
2912
3471
  .replace("{{index}}", String(branchNavigation.index))
2913
- .replace("{{count}}", String(branchNavigation.count)), children: [_jsx(MessageActionButton, { label: labels.previousBranch, icon: _jsx(IconChevronLeft, { "aria-hidden": "true" }), size: "compact", className: "size-6", disabled: branchNavigation.index <= 1 || branchNavigationAction.pending, pending: branchNavigationAction.pending, onPress: () => void branchNavigationAction
3472
+ .replace("{{count}}", String(branchNavigation.count)), children: [_jsx(MessageActionButton, { label: labels.previousBranch, icon: _jsx(IconChevronLeft, { "aria-hidden": "true" }), size: "compact", className: "size-6 rounded-[var(--agent-kit-radius-xs,0.25rem)]", unavailable: branchNavigation.index <= 1, busy: branchNavigationAction.pending, onPress: () => void branchNavigationAction
2914
3473
  .execute("previous")
2915
3474
  .catch(() => undefined) }), _jsx("span", { "aria-hidden": "true", children: labels.branchPosition
2916
3475
  .replace("{{index}}", String(branchNavigation.index))
2917
3476
  .replace("{{count}}", String(branchNavigation.count)) }), _jsx("span", { className: "agentkit-visually-hidden", "aria-live": "polite", children: labels.branchPositionLabel
2918
3477
  .replace("{{index}}", String(branchNavigation.index))
2919
- .replace("{{count}}", String(branchNavigation.count)) }), _jsx(MessageActionButton, { label: labels.nextBranch, icon: _jsx(IconChevronRight, { "aria-hidden": "true" }), size: "compact", className: "size-6", disabled: branchNavigation.index >= branchNavigation.count ||
2920
- branchNavigationAction.pending, pending: branchNavigationAction.pending, onPress: () => void branchNavigationAction.execute("next").catch(() => undefined) })] })) : null;
2921
- const toolbar = isAssistant ? (_jsxs("div", { ref: toolbarRef, className: "agentkit-message-toolbar", role: "group", "aria-label": labels.messageActions, "data-placement": placement, "data-latest": isLastAssistantMessage ? "true" : undefined, "data-streaming": message.status === "streaming" ? "true" : undefined, "data-expanded": moreActionsOpen ? "true" : undefined, onKeyDown: (event) => {
3478
+ .replace("{{count}}", String(branchNavigation.count)) }), _jsx(MessageActionButton, { label: labels.nextBranch, icon: _jsx(IconChevronRight, { "aria-hidden": "true" }), size: "compact", className: "size-6 rounded-[var(--agent-kit-radius-xs,0.25rem)]", unavailable: branchNavigation.index >= branchNavigation.count, busy: branchNavigationAction.pending, onPress: () => void branchNavigationAction.execute("next").catch(() => undefined) })] })) : null;
3479
+ const toolbar = isAssistant ? (_jsxs("div", { ref: toolbarRef, className: "agentkit-message-toolbar", role: "toolbar", "aria-label": labels.messageActions, "data-placement": placement, "data-latest": isLastAssistantMessage ? "true" : undefined, "data-streaming": message.status === "streaming" ? "true" : undefined, "data-expanded": moreActionsOpen ? "true" : undefined, onKeyDown: (event) => {
2922
3480
  if (event.key !== "Escape" || !moreActionsOpen)
2923
3481
  return;
2924
3482
  event.preventDefault();
@@ -2949,7 +3507,7 @@ export const AgentMessageActions = memo(function AgentMessageActions({ value: me
2949
3507
  const chosen = feedback === value;
2950
3508
  const renderFeedbackButton = (toggle, open, contentId) => (_jsx(MessageActionButton, { label: value === "positive"
2951
3509
  ? labels.feedbackGood
2952
- : labels.feedbackBad, icon: value === "positive" ? (chosen ? (_jsx(IconThumbUpFilled, { "aria-hidden": "true" })) : (_jsx(IconThumbUp, { "aria-hidden": "true" }))) : chosen ? (_jsx(IconThumbDownFilled, { "aria-hidden": "true" })) : (_jsx(IconThumbDown, { "aria-hidden": "true" })), size: "compact", className: "size-6", "data-message-action": `feedback-${value}`, "aria-pressed": chosen, "aria-haspopup": toggle ? "dialog" : undefined, "aria-expanded": toggle ? open : undefined, "aria-controls": toggle && open ? contentId : undefined, disabled: !feedbackCapability.enabled || feedbackAction.pending, ...(feedbackCapability.reason === undefined
3510
+ : labels.feedbackBad, icon: value === "positive" ? (chosen ? (_jsx(IconThumbUpFilled, { "aria-hidden": "true" })) : (_jsx(IconThumbUp, { "aria-hidden": "true" }))) : chosen ? (_jsx(IconThumbDownFilled, { "aria-hidden": "true" })) : (_jsx(IconThumbDown, { "aria-hidden": "true" })), size: "compact", className: "size-6 rounded-[var(--agent-kit-radius-xs,0.25rem)]", "data-message-action": `feedback-${value}`, "aria-pressed": chosen, "aria-haspopup": toggle ? "dialog" : undefined, "aria-expanded": toggle ? open : undefined, "aria-controls": toggle && open ? contentId : undefined, unavailable: !feedbackCapability.enabled, busy: feedbackAction.pending, ...(feedbackCapability.reason === undefined
2953
3511
  ? {}
2954
3512
  : { title: feedbackCapability.reason }), onPress: () => {
2955
3513
  toggle?.();
@@ -2958,30 +3516,40 @@ export const AgentMessageActions = memo(function AgentMessageActions({ value: me
2958
3516
  } }, value));
2959
3517
  return value === "negative" && slots.feedbackNote ? (_jsx(slots.feedbackNote, { threadId: threadId, ...(runId ? { runId } : {}), ...(messageSeq >= 0 ? { messageSeq } : {}), renderTrigger: renderFeedbackButton }, value)) : (renderFeedbackButton());
2960
3518
  })
2961
- : null] }), hasSecondaryActions ? (_jsxs("div", { ref: secondaryActionsRef, id: secondaryActionsId, className: "agentkit-message-actions-set", "data-set": "secondary", "data-active": moreActionsOpen ? "true" : "false", inert: !moreActionsOpen, children: [showRetry ? (_jsx(MessageActionButton, { label: labels.regenerateResponse, icon: _jsx(IconRefresh, { "aria-hidden": "true" }), size: "compact", className: "size-6", "data-message-action": "retry", pending: regenerateAction.pending, disabled: regenerateAction.pending ||
2962
- position.active ||
2963
- !forkingCapability.enabled, ...(forkingCapability.reason === undefined
3519
+ : null] }), hasSecondaryActions ? (_jsxs("div", { ref: secondaryActionsRef, id: secondaryActionsId, className: "agentkit-message-actions-set", "data-set": "secondary", "data-active": moreActionsOpen ? "true" : "false", inert: !moreActionsOpen, children: [showRetry ? (_jsx(MessageActionButton, { label: labels.regenerateResponse, icon: _jsx(IconRefresh, { "aria-hidden": "true" }), size: "compact", className: "size-6 rounded-[var(--agent-kit-radius-xs,0.25rem)]", "data-message-action": "retry", busy: regenerateAction.pending, unavailable: position.active || !forkingCapability.enabled, ...(forkingCapability.reason === undefined
2964
3520
  ? {}
2965
- : { title: forkingCapability.reason }), onPress: () => void regenerateAction.execute().catch(() => undefined) })) : null, showFork ? (_jsx(MessageActionButton, { label: labels.forkFromHere, icon: _jsx(IconArrowFork, { "aria-hidden": "true" }), size: "compact", className: "size-6", "data-message-action": "fork", pending: forkAction.pending, disabled: !forkingCapability.enabled || forkAction.pending, ...(forkingCapability.reason === undefined
3521
+ : { title: forkingCapability.reason }), onPress: (event) => {
3522
+ const keyboard = pressedByKeyboard(event);
3523
+ void regenerateAction
3524
+ .execute()
3525
+ .catch(() => undefined)
3526
+ // The new response replaces this toolbar.
3527
+ .finally(() => {
3528
+ if (keyboard)
3529
+ rescueFocusToComposer();
3530
+ });
3531
+ } })) : null, showFork ? (_jsx(MessageActionButton, { label: labels.forkFromHere, icon: _jsx(IconArrowFork, { "aria-hidden": "true" }), size: "compact", className: "size-6 rounded-[var(--agent-kit-radius-xs,0.25rem)]", "data-message-action": "fork", busy: forkAction.pending, unavailable: !forkingCapability.enabled, ...(forkingCapability.reason === undefined
2966
3532
  ? {}
2967
- : { title: forkingCapability.reason }), onPress: () => void forkAction.execute().catch(() => undefined) })) : null, requestId ? (_jsx(MessageActionButton, { label: requestIdCopied ? labels.copied : labels.copyRequestId, icon: requestIdAction.pending ? (_jsx(IconLoader2, { "aria-hidden": "true", className: "animate-spin" })) : requestIdCopied ? (_jsx(IconCircleCheck, { "aria-hidden": "true" })) : (_jsx(IconId, { "aria-hidden": "true" })), size: "compact", className: "size-6", "data-message-action": "request-id", "aria-busy": requestIdAction.pending || undefined, onPress: () => {
3533
+ : { title: forkingCapability.reason }), onPress: () => void forkAction.execute().catch(() => undefined) })) : null, requestId ? (_jsx(MessageActionButton, { label: requestIdCopied ? labels.copied : labels.copyRequestId, icon: requestIdAction.pending ? (_jsx(IconLoader2, { "aria-hidden": "true", className: "animate-spin" })) : requestIdCopied ? (_jsx(IconCircleCheck, { "aria-hidden": "true" })) : (_jsx(IconId, { "aria-hidden": "true" })), size: "compact", className: "size-6 rounded-[var(--agent-kit-radius-xs,0.25rem)]", "data-message-action": "request-id", "aria-busy": requestIdAction.pending || undefined, onPress: () => {
2968
3534
  if (requestIdAction.pending)
2969
3535
  return;
2970
3536
  void requestIdAction.execute().catch(() => undefined);
2971
3537
  } })) : null] })) : null] }), hasSecondaryActions ? (_jsx(MessageActionButton, { elementRef: moreToggleRef, label: labels.moreMessageActions, icon: _jsx(IconDots, { "aria-hidden": "true" }), size: "compact",
2972
3538
  // Hover is lighter than open, the toolkit's menu-trigger pattern,
2973
3539
  // so pressing it reads as a change while the pointer is still on it.
2974
- className: "agentkit-message-actions-toggle size-6 hover:bg-accent/60 aria-expanded:bg-accent aria-expanded:text-foreground", "data-message-actions-toggle": "", "aria-expanded": moreActionsOpen, "aria-controls": secondaryActionsId, onPress: () => setMoreActions(!moreActionsOpen, moreActionsOpen ? "toggle" : "secondary") })) : null, _jsx("span", { className: "agentkit-visually-hidden", "aria-live": "polite", children: feedbackConfirmed
3540
+ className: "agentkit-message-actions-toggle size-6 rounded-[var(--agent-kit-radius-xs,0.25rem)] hover:bg-accent/60 aria-expanded:bg-accent aria-expanded:text-foreground", "data-message-actions-toggle": "", "aria-expanded": moreActionsOpen, "aria-controls": secondaryActionsId, onPress: () => setMoreActions(!moreActionsOpen, moreActionsOpen ? "toggle" : "secondary") })) : null, _jsx("span", { className: "agentkit-visually-hidden", "aria-live": "polite", children: feedbackConfirmed
2975
3541
  ? labels.feedbackSubmitted
2976
- : requestIdCopied
3542
+ : requestIdCopied || copied
2977
3543
  ? labels.copied
2978
3544
  : "" })] })) : null;
2979
- return (_jsxs("div", { className: "agentkit-message-actions", "data-role": message.role, "data-placement": placement, "data-latest": isLastAssistantMessage ? "true" : undefined, "data-streaming": message.status === "streaming" ? "true" : undefined, "data-expanded": moreActionsOpen ? "true" : undefined, "data-has-error": footerError ? "true" : undefined, children: [isAssistant ? (_jsxs(_Fragment, { children: [_jsx("div", { ref: workHostRef, className: "agentkit-message-work-host" }), toolbar] })) : (_jsxs(_Fragment, { children: [_jsxs("div", { className: "agentkit-message-actions-leading", children: [copyButton, editContext?.enabled &&
3545
+ return (_jsxs("div", { ref: actionsRef, className: "agentkit-message-actions", "data-role": message.role, "data-placement": placement, "data-latest": isLastAssistantMessage ? "true" : undefined, "data-streaming": message.status === "streaming" ? "true" : undefined, "data-expanded": moreActionsOpen ? "true" : undefined, "data-has-error": footerError ? "true" : undefined, ...(isAssistant
3546
+ ? {}
3547
+ : { role: "toolbar", "aria-label": labels.messageActions }), children: [isAssistant ? (_jsxs(_Fragment, { children: [_jsx("div", { ref: workHostRef, className: "agentkit-message-work-host" }), toolbar] })) : (_jsxs(_Fragment, { children: [_jsxs("div", { className: "agentkit-message-actions-leading", children: [copyButton, editContext?.enabled &&
2980
3548
  message.metadata?.pendingSubmission !== true &&
2981
3549
  forkingCapability.visible &&
2982
- text.trim() ? (_jsx(MessageActionButton, { label: labels.editMessage, icon: _jsx(IconPencil, { "aria-hidden": "true" }), size: "compact", className: "size-6", disabled: position.active || !forkingCapability.enabled, ...(forkingCapability.reason === undefined
3550
+ text.trim() ? (_jsx(MessageActionButton, { label: labels.editMessage, icon: _jsx(IconPencil, { "aria-hidden": "true" }), size: "compact", className: "size-6 rounded-[var(--agent-kit-radius-xs,0.25rem)]", unavailable: position.active || !forkingCapability.enabled, ...(forkingCapability.reason === undefined
2983
3551
  ? {}
2984
- : { title: forkingCapability.reason }), "aria-pressed": editContext.message?.id === message.id, onPress: () => editContext.setMessage(message) })) : null] }), _jsx("div", { className: "agentkit-message-actions-trailing", children: message.createdAt ? (_jsx(AgentMessageTimestamp, { createdAt: message.createdAt, format: labels.formatTimestamp })) : null })] })), footerError ? (_jsx("span", { ...SESSION_REPLAY_MASK_PROPS, className: "agentkit-command-error", role: "alert", children: footerError.message })) : null] }));
3552
+ : { title: forkingCapability.reason }), "aria-pressed": editContext.message?.id === message.id, onPress: () => editContext.setMessage(message) })) : null] }), _jsx("div", { className: "agentkit-message-actions-trailing", children: message.createdAt ? (_jsx(AgentMessageTimestamp, { createdAt: message.createdAt, format: labels.formatTimestamp })) : null }), _jsx("span", { className: "agentkit-visually-hidden", "aria-live": "polite", children: copied ? labels.copied : "" })] })), footerError ? (_jsx("span", { ...SESSION_REPLAY_MASK_PROPS, className: "agentkit-command-error", role: "alert", children: footerError.message })) : null] }));
2985
3553
  });
2986
3554
  const AgentKitPostWidgetTextContext = createContext(undefined);
2987
3555
  function shallowEqualArrays(previous, next) {
@@ -3030,12 +3598,16 @@ export const AgentMessageView = memo(function AgentMessageView({ value: message,
3030
3598
  let hasSeenWidget = false;
3031
3599
  const renderedContent = [];
3032
3600
  let citationRun = [];
3601
+ let citationParts = [];
3033
3602
  let citationRunKey = "";
3034
3603
  const flushCitations = () => {
3035
3604
  if (!citationRun.length)
3036
3605
  return;
3037
- renderedContent.push(_jsx("span", { className: "agentkit-citations", children: citationRun }, `citations:${citationRunKey}`));
3606
+ renderedContent.push(
3607
+ // A host citation renderer keeps the inline run it was written for.
3608
+ slots.citation || registry.messageParts?.citation ? (_jsx("span", { className: "agentkit-citations", children: citationRun }, `citations:${citationRunKey}`)) : (_jsx(AgentSources, { citations: citationParts }, `citations:${citationRunKey}`)));
3038
3609
  citationRun = [];
3610
+ citationParts = [];
3039
3611
  };
3040
3612
  orderedContent.forEach((item, index) => {
3041
3613
  const isWidget = item.type === "widget" || item.part.type === "widget";
@@ -3053,13 +3625,14 @@ export const AgentMessageView = memo(function AgentMessageView({ value: message,
3053
3625
  if (!citationRun.length)
3054
3626
  citationRunKey = item.key;
3055
3627
  citationRun.push(_jsx(Fragment, { children: content }, item.key));
3628
+ citationParts.push(item.part);
3056
3629
  return;
3057
3630
  }
3058
3631
  flushCitations();
3059
3632
  renderedContent.push(followsWidget ? (_jsx("div", { "data-post-widget-text": "true", children: content }, item.key)) : (_jsx(Fragment, { children: content }, item.key)));
3060
3633
  });
3061
3634
  flushCitations();
3062
- return (_jsxs("article", { className: "agentkit-message", "data-role": message.role, "data-message-id": message.id, "data-pending": message.metadata?.pendingSubmission === true ? "true" : undefined, "data-editing": editing ? "true" : undefined, "aria-label": message.role === "user" ? labels.you : labels.assistant, "aria-busy": message.status === "streaming", children: [_jsxs("div", { className: "agentkit-message-content", children: [renderedContent, attachedAnnotations.length ? (_jsx("div", { className: "agentkit-annotations", children: attachedAnnotations.map((annotation) => (_jsx(AgentMessagePartView, { value: { type: "annotation", annotation }, threadId: threadId }, annotation.id))) })) : null, Supplement ? (_jsx(Supplement, { value: visibleMessage, threadId: threadId })) : null] }), _jsx(Actions, { value: slots.messageActions ? visibleMessage : message, threadId: threadId })] }));
3635
+ return (_jsxs("article", { className: "agentkit-message", "data-role": message.role, "data-message-id": message.id, "data-pending": message.metadata?.pendingSubmission === true ? "true" : undefined, "data-editing": editing ? "true" : undefined, "aria-label": message.role === "user" ? labels.you : labels.assistant, "aria-busy": message.status === "streaming", children: [_jsx("h2", { className: "agentkit-visually-hidden", children: message.role === "user" ? labels.you : labels.assistant }), _jsxs("div", { className: "agentkit-message-content", children: [renderedContent, attachedAnnotations.length ? (_jsx("div", { className: "agentkit-annotations", children: attachedAnnotations.map((annotation) => (_jsx(AgentMessagePartView, { value: { type: "annotation", annotation }, threadId: threadId }, annotation.id))) })) : null, Supplement ? (_jsx(Supplement, { value: visibleMessage, threadId: threadId })) : null] }), _jsx(Actions, { value: slots.messageActions ? visibleMessage : message, threadId: threadId })] }));
3063
3636
  });
3064
3637
  function stripAgentMessageContext(message) {
3065
3638
  const metadata = stripAgentContextMetadata(message.metadata);
@@ -3107,14 +3680,12 @@ export function AgentRunFailure({ error, runId, threadId, }) {
3107
3680
  setContinueFailed(true);
3108
3681
  });
3109
3682
  };
3110
- // A failure the user can recover from is a warning; red means it is final.
3111
- const tone = error.retryable === true ? "warning" : "danger";
3112
- const ToneIcon = tone === "warning" ? IconAlertTriangle : IconAlertCircle;
3113
- return (_jsxs("div", { className: "agentkit-run-failure", "data-tone": tone, "data-error-code": error.code, "data-run-id": runId, "data-thread-id": threadId, role: !superseded && latestFailure ? "alert" : undefined, children: [_jsx(ToneIcon, { "aria-hidden": "true", className: "agentkit-icon" }), _jsxs("div", { className: "agentkit-run-failure-copy", children: [_jsx("strong", { children: labels.runFailed }), _jsx("span", { ...SESSION_REPLAY_MASK_PROPS, children: error.message }), canContinue ? (_jsx("div", { className: "agentkit-error-actions", children: _jsx(ActionButton, { emphasis: "outline", size: "compact", pending: continuing, onPress: continueRun, children: labels.continueRun }) })) : null, continueFailed && !superseded ? (_jsx("span", { className: "agentkit-command-error", role: "alert", children: labels.continueRunUnavailable })) : null] })] }));
3683
+ // Amber, not red, even when not retryable: a failed run destroys nothing.
3684
+ return (_jsxs("div", { className: "agentkit-run-failure", "data-tone": "warning", "data-error-code": error.code, "data-run-id": runId, "data-thread-id": threadId, role: !superseded && latestFailure ? "alert" : undefined, children: [_jsx(IconAlertTriangle, { "aria-hidden": "true", className: "agentkit-icon" }), _jsxs("div", { className: "agentkit-run-failure-copy", children: [_jsx("strong", { children: labels.runFailed }), _jsx("span", { ...SESSION_REPLAY_MASK_PROPS, children: error.message }), canContinue ? (_jsx("div", { className: "agentkit-error-actions", children: _jsx(ActionButton, { emphasis: "outline", size: "compact", pending: continuing, onPress: continueRun, children: labels.continueRun }) })) : null, continueFailed && !superseded ? (_jsx("span", { className: "agentkit-command-error", role: "alert", children: labels.continueRunUnavailable })) : null] })] }));
3114
3685
  }
3115
3686
  export function AgentConnectionErrorView({ error, threadId, recover, recovering, recoveryError, dismiss, }) {
3116
3687
  const { labels } = useAgentKit();
3117
- return (_jsxs(ComposerNotice, { tone: error.retryable ? "warning" : "danger", role: "alert", noticeId: "connection-error", className: "agentkit-connection-notice", rootProps: { "data-error-code": error.code, "data-thread-id": threadId }, onDismiss: dismiss, dismissLabel: labels.dismissNotice, actions: error.retryable ? (_jsx(ActionButton, { emphasis: "outline", size: "compact", className: "h-6 px-2 text-xs", pending: recovering, onPress: () => void recover().catch(() => undefined), children: labels.reconnect })) : undefined, children: [_jsx("span", { ...SESSION_REPLAY_MASK_PROPS, children: error.message }), recoveryError ? (_jsx("span", { ...SESSION_REPLAY_MASK_PROPS, className: "block", children: recoveryError.message })) : null] }));
3688
+ return (_jsxs(ComposerNotice, { tone: "warning", role: "alert", noticeId: "connection-error", className: "agentkit-connection-notice", rootProps: { "data-error-code": error.code, "data-thread-id": threadId }, onDismiss: dismiss, dismissLabel: labels.dismissNotice, actions: error.retryable ? (_jsx(ActionButton, { emphasis: "outline", size: "compact", className: "h-6 px-2 text-xs", pending: recovering, onPress: () => void recover().catch(() => undefined), children: labels.reconnect })) : undefined, children: [_jsx("span", { ...SESSION_REPLAY_MASK_PROPS, children: error.message }), recoveryError ? (_jsx("span", { ...SESSION_REPLAY_MASK_PROPS, className: "block", children: recoveryError.message })) : null] }));
3118
3689
  }
3119
3690
  function hasActiveRuns(thread) {
3120
3691
  return threadHasActiveRuns(thread);
@@ -3390,7 +3961,7 @@ inlineTextAttachments = false, beforeSend, }) {
3390
3961
  editContext?.setMessage(null);
3391
3962
  focusComposer();
3392
3963
  }, [editContext, focusComposer, initialText]);
3393
- const editingRow = editingMessage ? (_jsxs("div", { role: "group", "aria-labelledby": editingLabelId, className: "agentkit-editing-row flex h-6 min-w-0 items-center gap-2 text-xs text-muted-foreground", "data-agentkit-editing-row": "true", children: [_jsx(Tooltip, { placement: "top", align: "start", trigger: _jsxs("span", { tabIndex: 0, className: "inline-flex min-w-0 items-center gap-2 rounded-sm outline-none focus-visible:ring-2 focus-visible:ring-ring", children: [_jsx(IconPencil, { "aria-hidden": "true", className: "size-4 shrink-0" }), _jsx("span", { id: editingLabelId, className: "truncate", children: labels.editingMessage })] }), content: labels.editingMessageHint }), _jsx(ActionButton, { emphasis: "ghost", size: "compact", className: "-me-2 ms-auto h-6 shrink-0 px-2 text-xs", onPress: cancelEditing, children: labels.cancelEditing })] })) : null;
3964
+ const editingRow = editingMessage ? (_jsxs("div", { role: "group", "aria-labelledby": editingLabelId, className: "agentkit-editing-row flex h-6 min-w-0 items-center gap-2 text-xs text-muted-foreground", "data-agentkit-editing-row": "true", children: [_jsx(Tooltip, { placement: "top", align: "start", trigger: _jsxs("span", { tabIndex: 0, className: "inline-flex min-w-0 items-center gap-2 rounded-[var(--agent-kit-radius-xs,0.25rem)] outline-none focus-visible:ring-2 focus-visible:ring-ring", children: [_jsx(IconPencil, { "aria-hidden": "true", className: "size-4 shrink-0" }), _jsx("span", { id: editingLabelId, className: "truncate", children: labels.editingMessage })] }), content: labels.editingMessageHint }), _jsx(ActionButton, { emphasis: "ghost", size: "compact", className: "-me-2 ms-auto h-6 shrink-0 px-2 text-xs", onPress: cancelEditing, children: labels.cancelEditing })] })) : null;
3394
3965
  useEffect(() => registerComposerFocus(threadId, focusComposer), [focusComposer, registerComposerFocus, threadId]);
3395
3966
  // i18n-ignore: These type-level callback property names are not visible copy.
3396
3967
  const submitMessage = async (text, files, references, // i18n-ignore: Type-only callback tuple, not rendered copy.
@@ -3518,6 +4089,9 @@ inlineTextAttachments = false, beforeSend, }) {
3518
4089
  threadId: forkedThread.id,
3519
4090
  text: payload.text,
3520
4091
  attachments: [...payload.attachments],
4092
+ ...(payload.references.length
4093
+ ? { references: [...payload.references] }
4094
+ : {}),
3521
4095
  options: payload.options,
3522
4096
  metadata: sendMetadata,
3523
4097
  onLocalSubmit,
@@ -3559,6 +4133,9 @@ inlineTextAttachments = false, beforeSend, }) {
3559
4133
  const message = {
3560
4134
  text: payload.text,
3561
4135
  attachments: [...payload.attachments],
4136
+ ...(payload.references.length
4137
+ ? { references: [...payload.references] }
4138
+ : {}),
3562
4139
  options: payload.options,
3563
4140
  metadata: sendMetadata,
3564
4141
  queueWhileRunning,
@@ -3857,6 +4434,8 @@ const AGENTKIT_HISTORY_ROW_CHUNK = 16;
3857
4434
  const AGENTKIT_TRANSCRIPT_SCROLLBAR_IDLE_MS = 900;
3858
4435
  /** Outlasts the reveal's bounded drain after a run ends. */
3859
4436
  const AGENTKIT_TRANSCRIPT_GLIDE_AFTER_RUN_MS = 2_000;
4437
+ /** How much of the previous turn shows above an anchored message. */
4438
+ const AGENTKIT_TURN_ANCHOR_PEEK_PX = 32;
3860
4439
  const AGENTKIT_TRANSCRIPT_SCROLL_KEYS = new Set([
3861
4440
  "ArrowDown",
3862
4441
  "ArrowUp",
@@ -3866,13 +4445,14 @@ const AGENTKIT_TRANSCRIPT_SCROLL_KEYS = new Set([
3866
4445
  "PageUp",
3867
4446
  " ",
3868
4447
  ]);
3869
- const AGENTKIT_ACTIVITY_ANNOUNCE_INTERVAL_MS = 2_000;
4448
+ // Long enough for a screen reader to finish speaking between step names.
4449
+ const AGENTKIT_ACTIVITY_ANNOUNCE_INTERVAL_MS = 10_000;
3870
4450
  export function isAgentKitTranscriptNearBottom(element, threshold = AGENTKIT_TRANSCRIPT_BOTTOM_THRESHOLD) {
3871
4451
  return (element.scrollHeight - element.clientHeight - element.scrollTop <= threshold);
3872
4452
  }
3873
4453
  /** Layout-matching placeholder for a conversation whose history is loading. */
3874
4454
  export function AgentKitTranscriptSkeleton({ label = defaultAgentKitLabels.loadingConversation, className, }) {
3875
- return (_jsxs("div", { className: `agentkit-transcript-skeleton ${className ?? ""}`, role: "status", "aria-busy": "true", children: [_jsx("span", { className: "agentkit-visually-hidden", children: label }), _jsx("div", { className: "agentkit-transcript-skeleton-user", "aria-hidden": "true", children: _jsx(Skeleton, { className: "agentkit-transcript-skeleton-bubble ms-auto h-10 w-2/5 rounded-2xl" }) }), _jsxs("div", { className: "agentkit-transcript-skeleton-assistant", "aria-hidden": "true", children: [_jsx(Skeleton, { className: "agentkit-transcript-skeleton-line h-4 w-full" }), _jsx(Skeleton, { className: "agentkit-transcript-skeleton-line h-4 w-11/12" }), _jsx(Skeleton, { className: "agentkit-transcript-skeleton-line h-4 w-3/5" })] })] }));
4455
+ return (_jsxs("div", { className: `agentkit-transcript-skeleton ${className ?? ""}`, role: "status", "aria-busy": "true", children: [_jsx("span", { className: "agentkit-visually-hidden", children: label }), _jsx("div", { className: "agentkit-transcript-skeleton-user", "aria-hidden": "true", children: _jsx(Skeleton, { className: "agentkit-transcript-skeleton-bubble ms-auto h-11 w-2/5 rounded-[var(--agent-kit-radius-sm,0.5rem)]" }) }), _jsxs("div", { className: "agentkit-transcript-skeleton-assistant", "aria-hidden": "true", children: [_jsx(Skeleton, { className: "agentkit-transcript-skeleton-line h-4 w-full" }), _jsx(Skeleton, { className: "agentkit-transcript-skeleton-line h-4 w-11/12" }), _jsx(Skeleton, { className: "agentkit-transcript-skeleton-line h-4 w-3/5" })] })] }));
3876
4456
  }
3877
4457
  function AgentThreadUnavailable({ onStartNewChat, }) {
3878
4458
  const { labels } = useAgentKit();
@@ -3914,6 +4494,14 @@ function currentRunActivityLabel(thread, runId, labels) {
3914
4494
  }
3915
4495
  return labels.working;
3916
4496
  }
4497
+ // A run that stops to wait on the user is as much news as one that ends.
4498
+ const RUN_STATUS_ANNOUNCEMENTS = {
4499
+ completed: "responseReady",
4500
+ failed: "responseFailed",
4501
+ cancelled: "runStopped",
4502
+ awaiting_approval: "waitingForApproval",
4503
+ awaiting_input: "waitingForInput",
4504
+ };
3917
4505
  /**
3918
4506
  * One polite status region for the whole chat. The transcript itself stays
3919
4507
  * aria-live="off": streamed text would otherwise be read token by token.
@@ -3924,6 +4512,8 @@ function AgentKitLiveStatus({ threadId }) {
3924
4512
  const runId = latestRunId(thread);
3925
4513
  const run = runId ? thread.runs[runId] : undefined;
3926
4514
  const status = run?.status;
4515
+ // A failure with an error has its own alert; announcing it here reads it twice.
4516
+ const failureHasAlert = status === "failed" && Boolean(run?.error);
3927
4517
  const running = status === "running";
3928
4518
  const activityText = running && runId ? currentRunActivityLabel(thread, runId, labels) : "";
3929
4519
  const [announcement, setAnnouncement] = useState("");
@@ -3940,14 +4530,16 @@ function AgentKitLiveStatus({ threadId }) {
3940
4530
  if (!runId || previous.runId !== runId || previous.status === status) {
3941
4531
  return;
3942
4532
  }
3943
- if (status === "completed" || status === "failed") {
3944
- if (pendingTimerRef.current)
3945
- clearTimeout(pendingTimerRef.current);
3946
- pendingTimerRef.current = undefined;
3947
- lastAnnouncedAtRef.current = Date.now();
3948
- setAnnouncement(status === "completed" ? labels.responseReady : labels.responseFailed);
3949
- }
3950
- }, [labels.responseFailed, labels.responseReady, runId, status]);
4533
+ const announced = status ? RUN_STATUS_ANNOUNCEMENTS[status] : undefined;
4534
+ if (!announced)
4535
+ return;
4536
+ if (pendingTimerRef.current)
4537
+ clearTimeout(pendingTimerRef.current);
4538
+ pendingTimerRef.current = undefined;
4539
+ lastAnnouncedAtRef.current = Date.now();
4540
+ // Cleared rather than left on the last step name, which is stale now.
4541
+ setAnnouncement(failureHasAlert ? "" : labels[announced]);
4542
+ }, [failureHasAlert, labels, runId, status]);
3951
4543
  useEffect(() => {
3952
4544
  if (!activityText)
3953
4545
  return;
@@ -3975,8 +4567,8 @@ function isTerminalRunStatus(status) {
3975
4567
  export function AgentKitEmptyState({ text, children, className, }) {
3976
4568
  return (_jsxs("div", { className: `agentkit-empty-state ${className ?? ""}`, "data-agentkit-empty-state": "true", children: [_jsx("p", { className: "agentkit-empty-state-greeting", children: text }), children] }));
3977
4569
  }
3978
- export function AgentKitChat({ title, toolbar, composer = true, composerProps, hasRenderedMessages = false, emptyComposerPlacement = "center", autoScroll = true, transcriptLayout, expectExistingThread, onStartNewChat, className, }) {
3979
- const { controller, threadId, slots, registry, labels, onThreadForked, threadLoad, formatWorkedForDuration, } = useAgentKit();
4570
+ export function AgentKitChat({ title, toolbar, composer = true, composerProps, hasRenderedMessages = false, emptyComposerPlacement = "center", autoScroll = true, anchorTurns = true, transcriptLayout, expectExistingThread, onStartNewChat, className, }) {
4571
+ const { controller, threadId, slots, registry, labels, onThreadForked, threadLoad, formatWorkedForDuration, requestComposerFocus, } = useAgentKit();
3980
4572
  const formatReasoningDuration = (ms) => formatWorkedForDuration?.(ms) ??
3981
4573
  formatAgentKitDuration(ms, {
3982
4574
  hour: labels.durationHourShort,
@@ -4045,6 +4637,9 @@ export function AgentKitChat({ title, toolbar, composer = true, composerProps, h
4045
4637
  }, [threadId]);
4046
4638
  useRealtimeVoiceTranscripts(controller, threadId, hasActiveRuns(thread));
4047
4639
  const transcriptContentRef = useRef(null);
4640
+ const turnSpacerRef = useRef(null);
4641
+ // Set by a message sent in this thread; a thread that opens has no anchor.
4642
+ const turnAnchoredRef = useRef(false);
4048
4643
  const fileDragDepthRef = useRef(0);
4049
4644
  const followsTranscriptRef = useRef(true);
4050
4645
  const programmaticScrollTopRef = useRef(undefined);
@@ -4212,7 +4807,35 @@ export function AgentKitChat({ title, toolbar, composer = true, composerProps, h
4212
4807
  setTranscriptScrollbarVisible(true);
4213
4808
  scheduleTranscriptScrollbarHide();
4214
4809
  }, [scheduleTranscriptScrollbarHide]);
4810
+ // The spacer pads what the reply has not filled, so following the bottom holds
4811
+ // the sent message near the top. Sized imperatively so streaming never re-renders.
4812
+ const updateTurnSpacer = useCallback(() => {
4813
+ const transcript = transcriptRef.current;
4814
+ const content = transcriptContentRef.current;
4815
+ const spacer = turnSpacerRef.current;
4816
+ if (!transcript || !content || !spacer)
4817
+ return;
4818
+ // No stylesheet may size the spacer: its inline height is read back as-is.
4819
+ const current = Number.parseFloat(spacer.style.blockSize) || 0;
4820
+ const rows = content.querySelectorAll('.agentkit-message[data-role="user"]');
4821
+ const row = rows.length ? rows[rows.length - 1] : undefined;
4822
+ if (!anchorTurns || !turnAnchoredRef.current || !row) {
4823
+ if (current)
4824
+ spacer.style.blockSize = "";
4825
+ return;
4826
+ }
4827
+ const rowTop = row.getBoundingClientRect().top -
4828
+ transcript.getBoundingClientRect().top +
4829
+ transcript.scrollTop;
4830
+ const anchorTop = Math.max(0, rowTop - AGENTKIT_TURN_ANCHOR_PEEK_PX);
4831
+ const next = Math.max(0, Math.ceil(anchorTop +
4832
+ transcript.clientHeight -
4833
+ (transcript.scrollHeight - current)));
4834
+ if (next !== current)
4835
+ spacer.style.blockSize = next ? `${next}px` : "";
4836
+ }, [anchorTurns]);
4215
4837
  const scrollTranscriptToBottom = useCallback(() => {
4838
+ updateTurnSpacer();
4216
4839
  const transcript = transcriptRef.current;
4217
4840
  if (!autoScroll || !transcript || !followsTranscriptRef.current)
4218
4841
  return;
@@ -4220,13 +4843,14 @@ export function AgentKitChat({ title, toolbar, composer = true, composerProps, h
4220
4843
  if (Math.abs(transcript.scrollTop - nextScrollTop) <= 1)
4221
4844
  return;
4222
4845
  writeTranscriptScrollTop(transcript, nextScrollTop);
4223
- }, [autoScroll, writeTranscriptScrollTop]);
4846
+ }, [autoScroll, updateTurnSpacer, writeTranscriptScrollTop]);
4224
4847
  const stopTranscriptGlide = useCallback(() => {
4225
4848
  transcriptGlideRef.current?.glide.stop();
4226
4849
  }, []);
4227
4850
  // Streamed growth glides to the new bottom; anything else (opening a
4228
4851
  // thread, a long jump) lands there at once instead of gliding through it.
4229
4852
  const followTranscriptToBottom = useCallback(() => {
4853
+ updateTurnSpacer();
4230
4854
  const transcript = transcriptRef.current;
4231
4855
  if (!autoScroll || !transcript || !followsTranscriptRef.current)
4232
4856
  return;
@@ -4244,7 +4868,22 @@ export function AgentKitChat({ title, toolbar, composer = true, composerProps, h
4244
4868
  transcriptGlideRef.current = {
4245
4869
  element: transcript,
4246
4870
  glide: new TranscriptGlide({
4247
- element: transcript,
4871
+ // Size the spacer first so an anchored message holds still as the reply grows.
4872
+ element: {
4873
+ get scrollTop() {
4874
+ return transcript.scrollTop;
4875
+ },
4876
+ set scrollTop(value) {
4877
+ transcript.scrollTop = value;
4878
+ },
4879
+ get scrollHeight() {
4880
+ updateTurnSpacer();
4881
+ return transcript.scrollHeight;
4882
+ },
4883
+ get clientHeight() {
4884
+ return transcript.clientHeight;
4885
+ },
4886
+ },
4248
4887
  write: (scrollTop) => writeTranscriptScrollTop(transcript, scrollTop),
4249
4888
  following: () => followsTranscriptRef.current,
4250
4889
  }),
@@ -4255,6 +4894,7 @@ export function AgentKitChat({ title, toolbar, composer = true, composerProps, h
4255
4894
  autoScroll,
4256
4895
  scrollTranscriptToBottom,
4257
4896
  stopTranscriptGlide,
4897
+ updateTurnSpacer,
4258
4898
  writeTranscriptScrollTop,
4259
4899
  ]);
4260
4900
  useEffect(() => {
@@ -4340,6 +4980,7 @@ export function AgentKitChat({ title, toolbar, composer = true, composerProps, h
4340
4980
  if (transcriptThreadIdRef.current !== threadId) {
4341
4981
  transcriptThreadIdRef.current = threadId;
4342
4982
  previousLastMessageIdRef.current = undefined;
4983
+ turnAnchoredRef.current = false;
4343
4984
  transcriptGlidesUntilRef.current = 0;
4344
4985
  jumps = true;
4345
4986
  setTranscriptFollow(true);
@@ -4353,6 +4994,9 @@ export function AgentKitChat({ title, toolbar, composer = true, composerProps, h
4353
4994
  if (lastMessage?.role === "user" &&
4354
4995
  lastMessage.id !== previousLastMessageId) {
4355
4996
  jumps = true;
4997
+ // Only a send anchors: the first render of an opened thread is not one.
4998
+ if (previousLastMessageId !== undefined)
4999
+ turnAnchoredRef.current = true;
4356
5000
  setTranscriptFollow(true);
4357
5001
  hideTranscriptScrollbar();
4358
5002
  }
@@ -4375,6 +5019,28 @@ export function AgentKitChat({ title, toolbar, composer = true, composerProps, h
4375
5019
  stopTranscriptGlide,
4376
5020
  threadId,
4377
5021
  ]);
5022
+ // Anchor from the pending submission so the message never lands at the bottom first.
5023
+ const newestPendingSubmissionId = pendingSubmissions.at(-1)?.id;
5024
+ const previousPendingSubmissionIdRef = useRef(newestPendingSubmissionId);
5025
+ useLayoutEffect(() => {
5026
+ const previous = previousPendingSubmissionIdRef.current;
5027
+ previousPendingSubmissionIdRef.current = newestPendingSubmissionId;
5028
+ if (!autoScroll ||
5029
+ !newestPendingSubmissionId ||
5030
+ newestPendingSubmissionId === previous) {
5031
+ return;
5032
+ }
5033
+ turnAnchoredRef.current = true;
5034
+ setTranscriptFollow(true);
5035
+ stopTranscriptGlide();
5036
+ scrollTranscriptToBottom();
5037
+ }, [
5038
+ autoScroll,
5039
+ newestPendingSubmissionId,
5040
+ scrollTranscriptToBottom,
5041
+ setTranscriptFollow,
5042
+ stopTranscriptGlide,
5043
+ ]);
4378
5044
  useLayoutEffect(() => {
4379
5045
  const transcript = transcriptRef.current;
4380
5046
  const content = transcriptContentRef.current;
@@ -5021,10 +5687,19 @@ export function AgentKitChat({ title, toolbar, composer = true, composerProps, h
5021
5687
  observer.disconnect();
5022
5688
  };
5023
5689
  }, [hiddenHistoryRows, writeTranscriptScrollTop]);
5024
- return (_jsx(ComposerNoticeScope, { children: _jsx(AgentMessageEditContext.Provider, { value: messageEditContext, children: _jsx(AgentMessageWorkHostsContext.Provider, { value: messageWorkHosts, children: _jsx(AgentKitTranscriptFollowContext.Provider, { value: followTranscriptOnSubmit, children: _jsxs("section", { "aria-label": typeof title === "string" ? title : undefined, className: `agentkit-chat ${className ?? ""}`, "data-empty": showEmptyState, "data-has-header": hasHeader, "data-empty-composer-placement": showEmptyState ? emptyComposerPlacement : "bottom", style: chatLaneStyle(transcriptLayout), onDragEnter: handleFileDragEnter, onDragOver: handleFileDragOver, onDragLeave: handleFileDragLeave, onDropCapture: handleFileDropCapture, onDrop: handleFileDrop, children: [fileDragActive ? (_jsx("div", { className: "agentkit-file-drop-overlay", role: "status", children: labels.dropFilesToAttach })) : null, hasHeader ? (_jsx(AgentKitSurfaceBoundary, { surface: "header", resetKey: threadId, children: _jsx(AgentKitRegionSlot, { slot: Header, threadId: threadId, children: _jsxs("header", { className: "agentkit-chat-header", "data-agentkit-region": "header", "data-agentkit-chat-header": "true", "data-has-title": showTitle, children: [showTitle ? (_jsx("div", { className: "agentkit-chat-title", children: title })) : null, toolbar ? (_jsx(AgentKitRegionSlot, { slot: Toolbar, threadId: threadId, children: _jsx("div", { className: "agentkit-chat-toolbar", children: toolbar }) })) : null] }) }) })) : null, _jsx("div", { ref: transcriptRef, className: "agentkit-transcript", role: "region", "aria-label": labels.conversation, "aria-live": "off", tabIndex: 0, "data-follow": "true", "data-scrollbar-visible": transcriptScrollbarVisible, onKeyDown: handleTranscriptKeyDown, onPointerDown: handleTranscriptPointerDown, onScroll: handleTranscriptScroll, onTouchMove: revealTranscriptScrollbar, onWheel: revealTranscriptScrollbar, children: _jsx("div", { ref: transcriptContentRef, className: "agentkit-transcript-content", "data-lane-offset-mode": transcriptLayout?.messageLaneOffsetMode ?? "clamped", style: transcriptContentStyle(transcriptLayout), children: _jsxs(AgentKitRegionSlot, { slot: Transcript, threadId: threadId, children: [threadLoading ? (_jsx(AgentKitTranscriptSkeleton, { label: labels.loadingConversation })) : threadMissing ? (ThreadUnavailable ? (_jsx(ThreadUnavailable, { threadId: threadId })) : (_jsx(AgentThreadUnavailable, { onStartNewChat: onStartNewChat }))) : threadLoadFailed ? (_jsx(AgentThreadLoadFailed, { retry: hostLoadRetry ??
5025
- (() => void recovery.execute().catch(() => undefined)), retrying: hostLoadRetry ? false : recovery.pending, retryError: hostLoadRetry ? undefined : recovery.error })) : showEmptyState ? (EmptyState ? (_jsx(EmptyState, { threadId: threadId })) : (_jsx(AgentKitEmptyState, { text: labels.emptyStateText }))) : null, _jsx(AgentKitPostWidgetTextContext.Provider, { value: transcriptLayout?.postWidgetText, children: _jsx(AgentKitDeferClosedContentContext.Provider, { value: longHistory, children: renderedTranscriptItems }) }), approvalEntries.map(([approvalId, request]) => (_jsx(AgentKitSurfaceBoundary, { surface: "approval", resetKey: `${approvalId}:${runRevision(thread.approvalRunIds[approvalId] ?? "")}`, children: Approval ? (_jsx(Approval, { value: request, threadId: threadId, runId: thread.approvalRunIds[approvalId] ?? "" })) : (_jsx(AgentApprovalPrompt, { request: request, runId: thread.approvalRunIds[approvalId] ?? "" })) }, `${threadId}:${approvalId}`))), connectionRequestEntries.map(([requestId, request]) => (_jsx(AgentKitSurfaceBoundary, { surface: "connection-request", resetKey: `${requestId}:${request.status}`, children: ConnectionRequest ? (_jsx(ConnectionRequest, { value: request, threadId: threadId, runId: thread.connectionRequestRunIds[requestId] ?? "" })) : (_jsx(AgentConnectionRequestCard, { request: request, runId: thread.connectionRequestRunIds[requestId] ?? "" })) }, `${threadId}:${requestId}`))), visibleConnectionError ? (_jsx(AgentKitSurfaceBoundary, { surface: "connection-error", resetKey: `${threadId}:${visibleConnectionError.code}`, children: _jsx(ErrorState, { error: visibleConnectionError, threadId: threadId, recover: recovery.execute, recovering: recovery.pending, ...(recovery.error === undefined
5026
- ? {}
5027
- : { recoveryError: recovery.error }), dismiss: clearConnectionNotice }) })) : null] }) }) }), _jsx("div", { className: "agentkit-scroll-to-bottom-control", "data-visible": transcriptAwayFromBottom ? "true" : "false", "aria-hidden": transcriptAwayFromBottom ? undefined : true, inert: !transcriptAwayFromBottom, children: _jsx(IconButton, { label: labels.scrollToBottom, icon: _jsx(IconArrowDown, { "aria-hidden": "true" }), size: "compact", className: "rounded-full border border-[color:var(--agentkit-border)] bg-(--agentkit-surface) text-[color:var(--agentkit-text)] shadow-(--agent-kit-overlay-elevation) hover:bg-(--agentkit-subtle) hover:text-[color:var(--agentkit-text)]", onPress: returnTranscriptToBottom }) }), _jsx(AgentKitLiveStatus, { threadId: threadId }), composer ? (_jsx("footer", { className: "agentkit-chat-footer", children: _jsx(AgentKitSurfaceBoundary, { surface: "composer", resetKey: threadId, children: _jsx(AgentKitRegionSlot, { slot: Footer, threadId: threadId, children: slots.composer ? (_jsx(Composer, { threadId: threadId })) : (_jsx(AgentKitComposer, { ...composerProps, threadId: threadId })) }) }) })) : null] }) }) }) }) }));
5690
+ return (_jsx(ComposerNoticeScope, { children: _jsx(AgentMessageEditContext.Provider, { value: messageEditContext, children: _jsx(AgentMessageWorkHostsContext.Provider, { value: messageWorkHosts, children: _jsx(AgentKitTranscriptFollowContext.Provider, { value: followTranscriptOnSubmit, children: _jsxs("section", { "aria-label": typeof title === "string" ? title : undefined, className: `agentkit-chat ${className ?? ""}`, "data-empty": showEmptyState, "data-has-header": hasHeader, "data-empty-composer-placement": showEmptyState ? emptyComposerPlacement : "bottom", style: chatLaneStyle(transcriptLayout), onDragEnter: handleFileDragEnter, onDragOver: handleFileDragOver, onDragLeave: handleFileDragLeave, onDropCapture: handleFileDropCapture, onDrop: handleFileDrop, children: [fileDragActive ? (_jsx("div", { className: "agentkit-file-drop-overlay", role: "status", children: labels.dropFilesToAttach })) : null, hasHeader ? (_jsx(AgentKitSurfaceBoundary, { surface: "header", resetKey: threadId, children: _jsx(AgentKitRegionSlot, { slot: Header, threadId: threadId, children: _jsxs("header", { className: "agentkit-chat-header", "data-agentkit-region": "header", "data-agentkit-chat-header": "true", "data-has-title": showTitle, children: [showTitle ? (_jsx("div", { className: "agentkit-chat-title", children: title })) : null, toolbar ? (_jsx(AgentKitRegionSlot, { slot: Toolbar, threadId: threadId, children: _jsx("div", {
5691
+ // Host buttons carry the primitive's own radius
5692
+ // utility, which beats layered CSS.
5693
+ className: "agentkit-chat-toolbar [&_:is(button,[role=button])]:rounded-[var(--agentkit-radius-xs)]", children: toolbar }) })) : null] }) }) })) : null, composer && !showEmptyState ? (_jsx("button", { type: "button", className: "agentkit-skip-link", "data-agentkit-skip-link": "composer", onClick: () => requestComposerFocus(threadId), children: labels.skipToComposer })) : null, _jsx("div", { ref: transcriptRef, className: "agentkit-transcript", role: "region", "aria-label": labels.conversation, "aria-live": "off", tabIndex: 0, "data-follow": "true", "data-scrollbar-visible": transcriptScrollbarVisible, onKeyDown: handleTranscriptKeyDown, onPointerDown: handleTranscriptPointerDown, onScroll: handleTranscriptScroll, onTouchMove: revealTranscriptScrollbar, onWheel: revealTranscriptScrollbar, children: _jsxs("div", { ref: transcriptContentRef, className: "agentkit-transcript-content", "data-lane-offset-mode": transcriptLayout?.messageLaneOffsetMode ?? "clamped", style: transcriptContentStyle(transcriptLayout), children: [_jsxs(AgentKitRegionSlot, { slot: Transcript, threadId: threadId, children: [threadLoading ? (_jsx(AgentKitTranscriptSkeleton, { label: labels.loadingConversation })) : threadMissing ? (ThreadUnavailable ? (_jsx(ThreadUnavailable, { threadId: threadId })) : (_jsx(AgentThreadUnavailable, { onStartNewChat: onStartNewChat }))) : threadLoadFailed ? (_jsx(AgentThreadLoadFailed, { retry: hostLoadRetry ??
5694
+ (() => void recovery.execute().catch(() => undefined)), retrying: hostLoadRetry ? false : recovery.pending, retryError: hostLoadRetry ? undefined : recovery.error })) : showEmptyState ? (EmptyState ? (_jsx(EmptyState, { threadId: threadId })) : (_jsx(AgentKitEmptyState, { text: labels.emptyStateText }))) : null, _jsx(AgentKitPostWidgetTextContext.Provider, { value: transcriptLayout?.postWidgetText, children: _jsx(AgentKitDeferClosedContentContext.Provider, { value: longHistory, children: renderedTranscriptItems }) }), approvalEntries.map(([approvalId, request]) => (_jsx(AgentKitSurfaceBoundary, { surface: "approval", resetKey: `${approvalId}:${runRevision(thread.approvalRunIds[approvalId] ?? "")}`, children: Approval ? (_jsx(Approval, { value: request, threadId: threadId, runId: thread.approvalRunIds[approvalId] ?? "" })) : (_jsx(AgentApprovalPrompt, { request: request, runId: thread.approvalRunIds[approvalId] ?? "" })) }, `${threadId}:${approvalId}`))), connectionRequestEntries.map(([requestId, request]) => (_jsx(AgentKitSurfaceBoundary, { surface: "connection-request", resetKey: `${requestId}:${request.status}`, children: ConnectionRequest ? (_jsx(ConnectionRequest, { value: request, threadId: threadId, runId: thread.connectionRequestRunIds[requestId] ?? "" })) : (_jsx(AgentConnectionRequestCard, { request: request, runId: thread.connectionRequestRunIds[requestId] ?? "" })) }, `${threadId}:${requestId}`))), visibleConnectionError ? (_jsx(AgentKitSurfaceBoundary, { surface: "connection-error", resetKey: `${threadId}:${visibleConnectionError.code}`, children: _jsx(ErrorState, { error: visibleConnectionError, threadId: threadId, recover: recovery.execute, recovering: recovery.pending, ...(recovery.error === undefined
5695
+ ? {}
5696
+ : { recoveryError: recovery.error }), dismiss: clearConnectionNotice }) })) : null] }), _jsx("div", { ref: turnSpacerRef, className: "agentkit-turn-spacer", "aria-hidden": "true" })] }) }), _jsx("div", { className: "agentkit-scroll-to-bottom-control", "data-visible": transcriptAwayFromBottom ? "true" : "false", "aria-hidden": transcriptAwayFromBottom ? undefined : true, inert: !transcriptAwayFromBottom, children: _jsx(IconButton, { label: labels.scrollToBottom, icon: _jsx(IconArrowDown, { "aria-hidden": "true" }), size: "compact", className: "rounded-[var(--agent-kit-radius-sm,0.5rem)] border border-[color:var(--agentkit-border)] bg-(--agentkit-surface) text-[color:var(--agentkit-text)] shadow-(--agent-kit-overlay-elevation) hover:bg-(--agentkit-subtle) hover:text-[color:var(--agentkit-text)]", onPress: (event) => {
5697
+ returnTranscriptToBottom();
5698
+ // The control goes inert at the bottom, which would drop
5699
+ // a keyboard user's focus to the page.
5700
+ if (pressedByKeyboard(event))
5701
+ requestComposerFocus(threadId);
5702
+ } }) }), _jsx(AgentKitLiveStatus, { threadId: threadId }), composer ? (_jsx("footer", { className: "agentkit-chat-footer", children: _jsx(AgentKitSurfaceBoundary, { surface: "composer", resetKey: threadId, children: _jsx(AgentKitRegionSlot, { slot: Footer, threadId: threadId, children: slots.composer ? (_jsx(Composer, { threadId: threadId })) : (_jsx(AgentKitComposer, { ...composerProps, threadId: threadId })) }) }) })) : null] }) }) }) }) }));
5028
5703
  }
5029
5704
  export { useAgentKitStopButton } from "./stop-button.js";
5030
5705
  //# sourceMappingURL=components.js.map