@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
@@ -540,6 +540,175 @@ describe("AgentChat lifecycle", () => {
540
540
  expect(transcript.getAttribute("data-scrollbar-visible")).toBe("false");
541
541
  });
542
542
 
543
+ it.each([
544
+ { anchorTurns: true, sentTop: 1_178, partialTop: 1_178 },
545
+ { anchorTurns: false, sentTop: 960, partialTop: 1_100 },
546
+ ])(
547
+ "holds a sent message near the top until its reply fills the view (anchorTurns: $anchorTurns)",
548
+ async ({ anchorTurns, sentTop, partialTop }) => {
549
+ const threadId = `thread-anchor-${anchorTurns}`;
550
+ const earlier = {
551
+ id: "assistant-1",
552
+ role: "assistant" as const,
553
+ status: "complete" as const,
554
+ parts: [{ type: "text" as const, text: "Earlier answer" }],
555
+ };
556
+ const initialThread = {
557
+ ...createAgentThreadState(threadId),
558
+ messages: [earlier],
559
+ };
560
+ const resized: ResizeObserverCallback[] = [];
561
+ vi.stubGlobal(
562
+ "ResizeObserver",
563
+ class {
564
+ public constructor(callback: ResizeObserverCallback) {
565
+ resized.push(callback);
566
+ }
567
+ public observe() {}
568
+ public disconnect() {}
569
+ },
570
+ );
571
+ vi.stubGlobal(
572
+ "requestAnimationFrame",
573
+ (callback: FrameRequestCallback) => {
574
+ callback(performance.now());
575
+ return 0;
576
+ },
577
+ );
578
+ const observable = observableController({
579
+ connection: "connected",
580
+ capabilities: {},
581
+ capabilitiesStatus: "ready",
582
+ threads: { [threadId]: initialThread },
583
+ revision: 0,
584
+ });
585
+ const tree = mount();
586
+ await tree.render(
587
+ <AgentKitProvider
588
+ controller={observable.controller}
589
+ threadId={threadId}
590
+ >
591
+ <AgentKitChat composer={false} anchorTurns={anchorTurns} />
592
+ </AgentKitProvider>,
593
+ );
594
+ const transcript = tree.container.querySelector(
595
+ ".agentkit-transcript",
596
+ ) as HTMLDivElement;
597
+ const spacer = tree.container.querySelector(
598
+ ".agentkit-turn-spacer",
599
+ ) as HTMLDivElement;
600
+ // The sent message starts 1,210px down the content.
601
+ let contentHeight = 1_200;
602
+ let scrollTop = 0;
603
+ const spacerHeight = () => Number.parseFloat(spacer.style.blockSize) || 0;
604
+ Object.defineProperties(transcript, {
605
+ clientHeight: { configurable: true, get: () => 300 },
606
+ scrollHeight: {
607
+ configurable: true,
608
+ get: () => contentHeight + spacerHeight(),
609
+ },
610
+ scrollTop: {
611
+ configurable: true,
612
+ get: () => scrollTop,
613
+ set: (value: number) => {
614
+ scrollTop = Math.min(value, contentHeight + spacerHeight() - 300);
615
+ },
616
+ },
617
+ });
618
+ const rect = vi
619
+ .spyOn(HTMLElement.prototype, "getBoundingClientRect")
620
+ .mockImplementation(function (this: HTMLElement) {
621
+ const top =
622
+ this.dataset.messageId === "user-2" ? 1_210 - scrollTop : 0;
623
+ return { top, bottom: top, left: 0, right: 0 } as DOMRect;
624
+ });
625
+ const update = (
626
+ revision: number,
627
+ messages: AgentMessage[],
628
+ height: number,
629
+ ) => {
630
+ contentHeight = height;
631
+ observable.update({
632
+ connection: "connected",
633
+ capabilities: {},
634
+ capabilitiesStatus: "ready",
635
+ threads: { [threadId]: { ...initialThread, messages } },
636
+ revision,
637
+ });
638
+ };
639
+ const sent = {
640
+ id: "user-2",
641
+ role: "user" as const,
642
+ status: "complete" as const,
643
+ parts: [{ type: "text" as const, text: "And then?" }],
644
+ };
645
+ const reply = (text: string) => ({
646
+ id: "assistant-2",
647
+ role: "assistant" as const,
648
+ status: "streaming" as const,
649
+ parts: [{ type: "text" as const, text }],
650
+ });
651
+ try {
652
+ update(1, [earlier, sent], 1_260);
653
+ await flush();
654
+ // Anchored 32px below the top, a sliver of the earlier answer above.
655
+ expect(scrollTop).toBe(sentTop);
656
+
657
+ update(2, [earlier, sent, reply("The reply")], 1_400);
658
+ await flush();
659
+ expect(scrollTop).toBe(partialTop);
660
+
661
+ // Filled: the spacer is gone and following moves on with the reply.
662
+ update(3, [earlier, sent, reply("The reply, at length")], 1_600);
663
+ await flush();
664
+ await act(async () => {
665
+ for (const callback of resized) callback([], {} as ResizeObserver);
666
+ });
667
+ expect(spacerHeight()).toBe(0);
668
+ expect(scrollTop).toBe(1_300);
669
+ } finally {
670
+ rect.mockRestore();
671
+ vi.unstubAllGlobals();
672
+ await tree.unmount();
673
+ }
674
+ },
675
+ );
676
+
677
+ it("does not anchor the last message of a thread that opens", async () => {
678
+ const threadId = "thread-anchor-open";
679
+ const observable = observableController({
680
+ connection: "connected",
681
+ capabilities: {},
682
+ capabilitiesStatus: "ready",
683
+ threads: {
684
+ [threadId]: {
685
+ ...createAgentThreadState(threadId),
686
+ messages: [
687
+ {
688
+ id: "user-1",
689
+ role: "user" as const,
690
+ status: "complete" as const,
691
+ parts: [{ type: "text" as const, text: "Waiting" }],
692
+ },
693
+ ],
694
+ },
695
+ },
696
+ revision: 0,
697
+ });
698
+ const tree = mount();
699
+ await tree.render(
700
+ <AgentKitProvider controller={observable.controller} threadId={threadId}>
701
+ <AgentKitChat composer={false} />
702
+ </AgentKitProvider>,
703
+ );
704
+ await flush();
705
+ expect(
706
+ (tree.container.querySelector(".agentkit-turn-spacer") as HTMLElement)
707
+ .style.blockSize,
708
+ ).toBe("");
709
+ await tree.unmount();
710
+ });
711
+
543
712
  it("follows buffered layout growth without feeding updates back into React", async () => {
544
713
  const resizeObservers: Array<{
545
714
  callback: ResizeObserverCallback;
@@ -2566,9 +2735,11 @@ describe("AgentChat lifecycle", () => {
2566
2735
  row.querySelector(".agentkit-activity-label")?.textContent ===
2567
2736
  "Update slide",
2568
2737
  );
2569
- expect(failedToolRow?.textContent).not.toContain(
2570
- "slide_content_edit_failed",
2571
- );
2738
+ expect(
2739
+ failedToolRow
2740
+ ?.querySelector(".agentkit-activity-summary")
2741
+ ?.getAttribute("hidden"),
2742
+ ).toBe("until-found");
2572
2743
  await act(async () => {
2573
2744
  failedToolRow
2574
2745
  ?.querySelector<HTMLElement>(
@@ -2939,12 +3110,12 @@ describe("AgentChat lifecycle", () => {
2939
3110
  it("shares integration badges between current work and history without mixing providers", async () => {
2940
3111
  const threadId = "thread-tool-sources";
2941
3112
  const runId = "run-tool-sources";
2942
- const tools: AgentToolCall[] = ["slack", "slack", "gong", "figma"].map(
3113
+ const tools: AgentToolCall[] = ["slack", "slack", "gong", "files"].map(
2943
3114
  (provider, index) => ({
2944
3115
  id: `tool-${index}`,
2945
3116
  name: "provider-api-request",
2946
3117
  input: { provider },
2947
- status: provider === "figma" ? "running" : "completed",
3118
+ status: provider === "files" ? "running" : "completed",
2948
3119
  }),
2949
3120
  );
2950
3121
  const thread = {
@@ -2999,7 +3170,7 @@ describe("AgentChat lifecycle", () => {
2999
3170
  expect(work?.dataset.open).toBe("false");
3000
3171
  expect(
3001
3172
  work?.querySelector(
3002
- '.agentkit-activities-summary > .agentkit-disclosure-icon-slot [data-source-id="figma"]',
3173
+ '.agentkit-activities-summary > .agentkit-trace-line > .agentkit-disclosure-icon-slot [data-source-id="files"]',
3003
3174
  ),
3004
3175
  ).not.toBeNull();
3005
3176
  const clusters = work?.querySelectorAll(".agentkit-work-group");
@@ -3145,9 +3316,19 @@ describe("AgentChat lifecycle", () => {
3145
3316
  )?.textContent,
3146
3317
  ).toBe("Source Agent");
3147
3318
 
3148
- const interactionRow = tree.container.querySelector(
3149
- ".agentkit-agent-interaction",
3319
+ const step = tree.container.querySelector<HTMLElement>(
3320
+ '.agentkit-subagent-step[data-agent-id="actor-agent"]',
3150
3321
  );
3322
+ expect(
3323
+ step?.querySelector(
3324
+ ":scope > .agentkit-activity-row > .agentkit-object .agentkit-object-label",
3325
+ )?.textContent,
3326
+ ).toBe("Source Agent");
3327
+ expect(tree.container.querySelector(".agentkit-task-row")).toBeNull();
3328
+ await act(async () =>
3329
+ step?.querySelector<HTMLElement>(".agentkit-disclosure-summary")?.click(),
3330
+ );
3331
+ const interactionRow = step?.querySelector(".agentkit-agent-interaction");
3151
3332
  expect(
3152
3333
  interactionRow?.querySelector(".agentkit-agent-interaction-label")
3153
3334
  ?.textContent,
@@ -3155,11 +3336,6 @@ describe("AgentChat lifecycle", () => {
3155
3336
  expect(
3156
3337
  interactionRow?.querySelector(".agentkit-object-label")?.textContent,
3157
3338
  ).toBe("Source Agent");
3158
-
3159
- expect(
3160
- tree.container.querySelector(".agentkit-task-row .agentkit-object-label")
3161
- ?.textContent,
3162
- ).toBe("Source Agent");
3163
3339
  const uuidActivity = Array.from(
3164
3340
  tree.container.querySelectorAll<HTMLElement>(".agentkit-activity-item"),
3165
3341
  ).find((item) => item.dataset.activityKind === internalId);
@@ -3314,7 +3490,9 @@ describe("AgentChat lifecycle", () => {
3314
3490
  );
3315
3491
  expect(tree.container.querySelector(".agentkit-run-failure")).toBeNull();
3316
3492
  expect(work?.dataset.open).toBe("false");
3317
- expect(work?.querySelector(".agentkit-activity-summary")).toBeNull();
3493
+ expect(
3494
+ work?.querySelector(".agentkit-activity-summary")?.getAttribute("hidden"),
3495
+ ).toBe("until-found");
3318
3496
  await act(async () =>
3319
3497
  work?.querySelector<HTMLElement>(".agentkit-disclosure-summary")?.click(),
3320
3498
  );
@@ -3322,9 +3500,11 @@ describe("AgentChat lifecycle", () => {
3322
3500
  const failedTool = work?.querySelector(
3323
3501
  '.agentkit-activity-item[data-status="failed"]',
3324
3502
  );
3325
- expect(failedTool?.textContent).not.toContain(
3326
- "The file could not be saved.",
3327
- );
3503
+ expect(
3504
+ failedTool
3505
+ ?.querySelector(".agentkit-activity-summary")
3506
+ ?.getAttribute("hidden"),
3507
+ ).toBe("until-found");
3328
3508
  await act(async () => failedTool?.querySelector("button")?.click());
3329
3509
  expect(
3330
3510
  failedTool?.querySelector(".agentkit-activity-summary")?.textContent,
@@ -3402,7 +3582,7 @@ describe("AgentChat lifecycle", () => {
3402
3582
  "Result",
3403
3583
  ]);
3404
3584
  expect(
3405
- details.every((detail) => detail.getAttribute("role") === "region"),
3585
+ details.every((detail) => detail.getAttribute("role") === "group"),
3406
3586
  ).toBe(true);
3407
3587
  expect(details.every((detail) => detail.tabIndex === 0)).toBe(true);
3408
3588
  expect(details[0]?.textContent).toContain("[Identifier hidden]");
@@ -3418,6 +3598,286 @@ describe("AgentChat lifecycle", () => {
3418
3598
  await tree.unmount();
3419
3599
  });
3420
3600
 
3601
+ it("shows a code tool's source as code and its other arguments beside it", async () => {
3602
+ const threadId = "thread-tool-source";
3603
+ const runId = "run-tool-source";
3604
+ const internalId = "550e8400-e29b-41d4-a716-446655440000";
3605
+ const code = `const id = "${internalId}";\nconsole.log(id);`;
3606
+ const thread = reduceAgentEvent(createAgentThreadState(threadId), {
3607
+ id: "event-run-code",
3608
+ threadId,
3609
+ runId,
3610
+ sequence: 1,
3611
+ occurredAt: "2026-10-01T00:00:00.000Z",
3612
+ type: "tool.updated",
3613
+ toolCall: {
3614
+ id: "tool-run-code",
3615
+ name: "run-code",
3616
+ status: "completed",
3617
+ input: { code, timeoutMs: 120_000, background: false },
3618
+ output: "stdout:\nok",
3619
+ },
3620
+ });
3621
+ const { controller } = observableController({
3622
+ connection: "connected",
3623
+ capabilities: {},
3624
+ capabilitiesStatus: "ready",
3625
+ threads: { [threadId]: thread },
3626
+ revision: 0,
3627
+ });
3628
+ const tree = mount();
3629
+ await tree.render(
3630
+ <AgentKitProvider controller={controller} threadId={threadId}>
3631
+ <AgentActivityGroup runId={runId} />
3632
+ </AgentKitProvider>,
3633
+ );
3634
+ const work = tree.container.querySelector<HTMLElement>(
3635
+ ".agentkit-activities",
3636
+ );
3637
+ await act(async () =>
3638
+ work?.querySelector<HTMLElement>(".agentkit-disclosure-summary")?.click(),
3639
+ );
3640
+ const row = work?.querySelector<HTMLElement>(".agentkit-activity-item");
3641
+ await act(async () => row?.querySelector("button")?.click());
3642
+
3643
+ const input = row?.querySelector<HTMLPreElement>(
3644
+ ".agentkit-activity-summary-value[aria-label='Input']",
3645
+ );
3646
+ expect(input?.textContent).toBe('const id = "";\nconsole.log(id);');
3647
+ const options = Array.from(
3648
+ row?.querySelectorAll(".agentkit-activity-tool-options > div") ?? [],
3649
+ (option) => option.textContent,
3650
+ );
3651
+ expect(options).toEqual(["timeoutMs120000", "backgroundfalse"]);
3652
+ await tree.unmount();
3653
+ });
3654
+
3655
+ it("keeps a short code argument in the JSON input", async () => {
3656
+ const threadId = "thread-tool-short-code";
3657
+ const runId = "run-tool-short-code";
3658
+ const thread = reduceAgentEvent(createAgentThreadState(threadId), {
3659
+ id: "event-lookup",
3660
+ threadId,
3661
+ runId,
3662
+ sequence: 1,
3663
+ occurredAt: "2026-10-01T00:00:00.000Z",
3664
+ type: "tool.updated",
3665
+ toolCall: {
3666
+ id: "tool-lookup",
3667
+ name: "lookup-country",
3668
+ status: "completed",
3669
+ input: { code: "US" },
3670
+ output: "United States",
3671
+ },
3672
+ });
3673
+ const { controller } = observableController({
3674
+ connection: "connected",
3675
+ capabilities: {},
3676
+ capabilitiesStatus: "ready",
3677
+ threads: { [threadId]: thread },
3678
+ revision: 0,
3679
+ });
3680
+ const tree = mount();
3681
+ await tree.render(
3682
+ <AgentKitProvider controller={controller} threadId={threadId}>
3683
+ <AgentActivityGroup runId={runId} />
3684
+ </AgentKitProvider>,
3685
+ );
3686
+ const work = tree.container.querySelector<HTMLElement>(
3687
+ ".agentkit-activities",
3688
+ );
3689
+ await act(async () =>
3690
+ work?.querySelector<HTMLElement>(".agentkit-disclosure-summary")?.click(),
3691
+ );
3692
+ const row = work?.querySelector<HTMLElement>(".agentkit-activity-item");
3693
+ await act(async () => row?.querySelector("button")?.click());
3694
+ expect(
3695
+ row?.querySelector(".agentkit-activity-summary-value[aria-label='Input']")
3696
+ ?.textContent,
3697
+ ).toContain('"code": "US"');
3698
+ await tree.unmount();
3699
+ });
3700
+
3701
+ it.each([
3702
+ {
3703
+ name: "a result that is only a stack replaces the raw result",
3704
+ output: "TypeError: boom\n at run (/work/app.js:3:9)",
3705
+ keepsResult: false,
3706
+ },
3707
+ {
3708
+ name: "a stack inside other output sits above the raw result",
3709
+ output:
3710
+ "stdout:\nstarting\n\nstderr:\nTypeError: boom\n at run (/work/app.js:3:9)",
3711
+ keepsResult: true,
3712
+ },
3713
+ ])("$name", async ({ output, keepsResult }) => {
3714
+ const threadId = "thread-tool-stack";
3715
+ const runId = "run-tool-stack";
3716
+ const thread = reduceAgentEvent(createAgentThreadState(threadId), {
3717
+ id: "event-run-code-stack",
3718
+ threadId,
3719
+ runId,
3720
+ sequence: 1,
3721
+ occurredAt: "2026-10-01T00:00:00.000Z",
3722
+ type: "tool.updated",
3723
+ toolCall: {
3724
+ id: "tool-run-code-stack",
3725
+ name: "run-code",
3726
+ status: "completed",
3727
+ input: { code: "run();" },
3728
+ output,
3729
+ },
3730
+ });
3731
+ const { controller } = observableController({
3732
+ connection: "connected",
3733
+ capabilities: {},
3734
+ capabilitiesStatus: "ready",
3735
+ threads: { [threadId]: thread },
3736
+ revision: 0,
3737
+ });
3738
+ const tree = mount();
3739
+ await tree.render(
3740
+ <AgentKitProvider controller={controller} threadId={threadId}>
3741
+ <AgentActivityGroup runId={runId} />
3742
+ </AgentKitProvider>,
3743
+ );
3744
+ const work = tree.container.querySelector<HTMLElement>(
3745
+ ".agentkit-activities",
3746
+ );
3747
+ await act(async () =>
3748
+ work?.querySelector<HTMLElement>(".agentkit-disclosure-summary")?.click(),
3749
+ );
3750
+ const row = work?.querySelector<HTMLElement>(".agentkit-activity-item");
3751
+ await act(async () => row?.querySelector("button")?.click());
3752
+
3753
+ const stack = row?.querySelector(".agentkit-stack-trace");
3754
+ expect(stack?.querySelector(".agentkit-trace-title")?.textContent).toBe(
3755
+ "TypeError: boom",
3756
+ );
3757
+ expect(
3758
+ stack
3759
+ ?.querySelector("button.agentkit-disclosure-summary")
3760
+ ?.getAttribute("aria-expanded"),
3761
+ ).toBe("true");
3762
+ expect(
3763
+ row?.querySelector(
3764
+ ".agentkit-activity-summary-value[aria-label='Result']",
3765
+ ) !== null,
3766
+ ).toBe(keepsResult);
3767
+ await tree.unmount();
3768
+ });
3769
+
3770
+ it("renders a coding tool's file edit as a file change", async () => {
3771
+ const threadId = "thread-edit";
3772
+ const runId = "run-edit";
3773
+ const thread = reduceAgentEvent(createAgentThreadState(threadId), {
3774
+ id: "event-edit",
3775
+ threadId,
3776
+ runId,
3777
+ sequence: 1,
3778
+ occurredAt: "2026-10-01T00:00:00.000Z",
3779
+ type: "tool.updated",
3780
+ toolCall: {
3781
+ id: "tool-edit",
3782
+ name: "edit",
3783
+ status: "completed",
3784
+ input: { filePath: "src/app.ts" },
3785
+ output: "Edited src/app.ts",
3786
+ metadata: {
3787
+ toolKind: "edit",
3788
+ filePath: "src/app.ts",
3789
+ oldText: "a",
3790
+ newText: "b",
3791
+ },
3792
+ },
3793
+ });
3794
+ const { controller } = observableController({
3795
+ connection: "connected",
3796
+ capabilities: {},
3797
+ capabilitiesStatus: "ready",
3798
+ threads: { [threadId]: thread },
3799
+ revision: 0,
3800
+ });
3801
+ const tree = mount();
3802
+ await tree.render(
3803
+ <AgentKitProvider controller={controller} threadId={threadId}>
3804
+ <AgentActivityGroup runId={runId} />
3805
+ </AgentKitProvider>,
3806
+ );
3807
+ const work = tree.container.querySelector<HTMLElement>(
3808
+ ".agentkit-activities",
3809
+ );
3810
+ await act(async () =>
3811
+ work?.querySelector<HTMLElement>(".agentkit-disclosure-summary")?.click(),
3812
+ );
3813
+ const change = work?.querySelector<HTMLElement>(
3814
+ ".agentkit-activity-item > .agentkit-file-change",
3815
+ );
3816
+ expect(
3817
+ change?.querySelector("[data-agent-file-change-path]")?.textContent,
3818
+ ).toBe("src/app.ts");
3819
+ expect(
3820
+ change?.querySelector("[data-agent-file-change-stats]")?.textContent,
3821
+ ).toBe("+1−1");
3822
+ await tree.unmount();
3823
+ });
3824
+
3825
+ it("renders a shell command call as a terminal with its streamed output", async () => {
3826
+ const threadId = "thread-bash";
3827
+ const runId = "run-bash";
3828
+ const thread = reduceAgentEvent(createAgentThreadState(threadId), {
3829
+ id: "event-bash",
3830
+ threadId,
3831
+ runId,
3832
+ sequence: 1,
3833
+ occurredAt: "2026-10-01T00:00:00.000Z",
3834
+ type: "tool.updated",
3835
+ toolCall: {
3836
+ id: "tool-bash",
3837
+ name: "bash",
3838
+ status: "completed",
3839
+ input: { command: "pnpm test" },
3840
+ output: "x".repeat(3_000),
3841
+ metadata: {
3842
+ toolKind: "bash",
3843
+ command: "pnpm test",
3844
+ cwd: "/work",
3845
+ exitCode: 1,
3846
+ },
3847
+ },
3848
+ });
3849
+ const { controller } = observableController({
3850
+ connection: "connected",
3851
+ capabilities: {},
3852
+ capabilitiesStatus: "ready",
3853
+ threads: { [threadId]: thread },
3854
+ revision: 0,
3855
+ });
3856
+ const tree = mount();
3857
+ await tree.render(
3858
+ <AgentKitProvider controller={controller} threadId={threadId}>
3859
+ <AgentActivityGroup runId={runId} />
3860
+ </AgentKitProvider>,
3861
+ );
3862
+ const work = tree.container.querySelector<HTMLElement>(
3863
+ ".agentkit-activities",
3864
+ );
3865
+ await act(async () =>
3866
+ work?.querySelector<HTMLElement>(".agentkit-disclosure-summary")?.click(),
3867
+ );
3868
+ const terminal = work?.querySelector<HTMLElement>(
3869
+ ".agentkit-activity-item > .agentkit-terminal",
3870
+ );
3871
+ expect(terminal?.dataset.status).toBe("failed");
3872
+ expect(
3873
+ terminal?.querySelector(".agentkit-terminal-command")?.textContent,
3874
+ ).toBe("pnpm test");
3875
+ await act(async () => terminal?.querySelector("button")?.click());
3876
+ // Command output is not cut at the 2,000-character tool preview.
3877
+ expect(terminal?.querySelector("pre")?.textContent).toHaveLength(3_000);
3878
+ await tree.unmount();
3879
+ });
3880
+
3421
3881
  it("keeps the omission marker visible when formatted tool output expands", async () => {
3422
3882
  const threadId = "thread-expanded-tool-output";
3423
3883
  const runId = "run-expanded-tool-output";
@@ -5214,7 +5674,84 @@ describe("AgentKit subscriptions and recovery", () => {
5214
5674
  },
5215
5675
  });
5216
5676
  await flush();
5217
- expect(retries()[0]?.disabled).toBe(true);
5677
+ // Unavailable but still focusable, so a keyboard user keeps their place.
5678
+ expect(retries()[0]?.getAttribute("aria-disabled")).toBe("true");
5679
+ } finally {
5680
+ await tree.unmount();
5681
+ }
5682
+ });
5683
+
5684
+ it("says why an unavailable action can't run, on focus and on press", async () => {
5685
+ const thread = createAgentThreadState("thread-unavailable-reason");
5686
+ thread.messages = [
5687
+ { id: "u1", role: "user", parts: [{ type: "text", text: "Hi" }] },
5688
+ {
5689
+ id: "a1",
5690
+ role: "assistant",
5691
+ parts: [{ type: "text", text: "Hello." }],
5692
+ },
5693
+ ];
5694
+ const reason = "Branching is paused while the workspace syncs.";
5695
+ const store = observableController({
5696
+ connection: "connected",
5697
+ capabilities: { threadForking: true },
5698
+ capabilityDiscovery: {
5699
+ protocol: {
5700
+ status: "compatible",
5701
+ selectedVersion: 1,
5702
+ localVersions: [1],
5703
+ peerVersions: [1],
5704
+ },
5705
+ discoveredAt: "2026-11-11T00:00:00.000Z",
5706
+ capabilities: [
5707
+ {
5708
+ id: "threadForking",
5709
+ state: "unavailable",
5710
+ error: {
5711
+ code: "capability_unavailable",
5712
+ message: reason,
5713
+ capability: "threadForking",
5714
+ retryable: true,
5715
+ },
5716
+ },
5717
+ ],
5718
+ },
5719
+ capabilitiesStatus: "ready",
5720
+ threads: { [thread.id]: thread },
5721
+ revision: 0,
5722
+ });
5723
+ const tree = mount();
5724
+
5725
+ try {
5726
+ await tree.render(
5727
+ <AgentKitProvider
5728
+ controller={store.controller}
5729
+ threadId={thread.id}
5730
+ onThreadForked={() => undefined}
5731
+ >
5732
+ <AgentMessageActions
5733
+ threadId={thread.id}
5734
+ value={thread.messages[1]!}
5735
+ />
5736
+ </AgentKitProvider>,
5737
+ );
5738
+ const retry = tree.container.querySelector<HTMLButtonElement>(
5739
+ 'button[aria-label="Retry"]',
5740
+ );
5741
+ expect(retry?.getAttribute("aria-disabled")).toBe("true");
5742
+ const describedBy = retry?.getAttribute("aria-describedby");
5743
+ expect(
5744
+ describedBy ? document.getElementById(describedBy)?.textContent : "",
5745
+ ).toBe(reason);
5746
+
5747
+ // A tap never hovers, so pressing it shows the reason.
5748
+ await act(async () => retry?.click());
5749
+ await flush();
5750
+ expect(
5751
+ Array.from(document.querySelectorAll('[role="tooltip"]')).some((tip) =>
5752
+ tip.textContent?.includes(reason),
5753
+ ),
5754
+ ).toBe(true);
5218
5755
  } finally {
5219
5756
  await tree.unmount();
5220
5757
  }
@@ -6204,9 +6741,17 @@ describe("AgentKit subscriptions and recovery", () => {
6204
6741
  const feed = tree.container.querySelector(
6205
6742
  "[data-agent-collaboration-feed='true']",
6206
6743
  );
6744
+ const step = feed?.querySelector<HTMLElement>(
6745
+ '.agentkit-subagent-step[data-agent-id="subagent-1"]',
6746
+ );
6747
+ await act(async () =>
6748
+ step?.querySelector<HTMLElement>(".agentkit-disclosure-summary")?.click(),
6749
+ );
6207
6750
  expect(
6208
- feed?.querySelector("[data-status='completed']")?.textContent,
6751
+ step?.querySelector(".agentkit-activity-item[data-status='completed']")
6752
+ ?.textContent,
6209
6753
  ).toContain("Reading delegated files");
6754
+ // The call it made later belongs to a later segment.
6210
6755
  expect(tree.container.textContent).not.toContain("read-delegated-files");
6211
6756
  await tree.unmount();
6212
6757
  });