@adecore/agents-react 0.0.1 → 0.17.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (513) hide show
  1. package/LICENSE +110 -0
  2. package/README.md +61 -0
  3. package/dist/agents/AccountDot.d.ts +4 -0
  4. package/dist/agents/AccountDot.js +8 -0
  5. package/dist/agents/AgentIcon.d.ts +6 -0
  6. package/dist/agents/AgentIcon.js +20 -0
  7. package/dist/agents/ModelOptionControl.d.ts +15 -0
  8. package/dist/agents/ModelOptionControl.js +33 -0
  9. package/dist/agents/ProviderLogo.d.ts +8 -0
  10. package/dist/agents/ProviderLogo.js +8 -0
  11. package/dist/agents/account-limits.d.ts +7 -0
  12. package/dist/agents/account-limits.js +40 -0
  13. package/dist/agents/accounts.d.ts +22 -0
  14. package/dist/agents/accounts.js +113 -0
  15. package/dist/agents/model-name.d.ts +12 -0
  16. package/dist/agents/model-name.js +56 -0
  17. package/dist/agents/model-options.d.ts +5 -0
  18. package/dist/agents/model-options.js +15 -0
  19. package/dist/agents/provider-paths.d.ts +2 -0
  20. package/dist/agents/provider-paths.js +8 -0
  21. package/dist/agents/status-look.d.ts +13 -0
  22. package/dist/agents/status-look.js +24 -0
  23. package/dist/chat/account-choice.d.ts +11 -0
  24. package/dist/chat/account-choice.js +30 -0
  25. package/dist/chat/actions.d.ts +6 -0
  26. package/dist/chat/actions.js +68 -0
  27. package/dist/chat/activity.d.ts +5 -0
  28. package/dist/chat/activity.js +6 -0
  29. package/dist/chat/attachments.d.ts +23 -0
  30. package/dist/chat/attachments.js +86 -0
  31. package/dist/chat/bookmarks.d.ts +14 -0
  32. package/dist/chat/bookmarks.js +73 -0
  33. package/dist/chat/chat-client.d.ts +55 -0
  34. package/dist/chat/chat-client.js +279 -0
  35. package/dist/chat/chat-references.d.ts +5 -0
  36. package/dist/chat/chat-references.js +5 -0
  37. package/dist/chat/drafts.d.ts +29 -0
  38. package/dist/chat/drafts.js +116 -0
  39. package/dist/chat/forks.d.ts +2 -0
  40. package/dist/chat/forks.js +28 -0
  41. package/dist/chat/guards.d.ts +12 -0
  42. package/dist/chat/guards.js +69 -0
  43. package/dist/chat/logic/ansi.d.ts +13 -0
  44. package/dist/chat/logic/ansi.js +185 -0
  45. package/dist/chat/logic/answers.d.ts +1 -0
  46. package/dist/chat/logic/answers.js +8 -0
  47. package/dist/chat/logic/bookmarks.d.ts +5 -0
  48. package/dist/chat/logic/bookmarks.js +33 -0
  49. package/dist/chat/logic/context-usage.d.ts +12 -0
  50. package/dist/chat/logic/context-usage.js +21 -0
  51. package/dist/chat/logic/fork.d.ts +45 -0
  52. package/dist/chat/logic/fork.js +148 -0
  53. package/dist/chat/logic/handback.d.ts +2 -0
  54. package/dist/chat/logic/handback.js +8 -0
  55. package/dist/chat/logic/json.d.ts +1 -0
  56. package/dist/chat/logic/json.js +4 -0
  57. package/dist/chat/logic/limit.d.ts +7 -0
  58. package/dist/chat/logic/limit.js +34 -0
  59. package/dist/chat/logic/resume-compaction.d.ts +14 -0
  60. package/dist/chat/logic/resume-compaction.js +47 -0
  61. package/dist/chat/logic/scrubber.d.ts +50 -0
  62. package/dist/chat/logic/scrubber.js +220 -0
  63. package/dist/chat/logic/thread-cards.d.ts +3 -0
  64. package/dist/chat/logic/thread-cards.js +59 -0
  65. package/dist/chat/logic/timeline-copy.d.ts +4 -0
  66. package/dist/chat/logic/timeline-copy.js +59 -0
  67. package/dist/chat/logic/timeline-target.d.ts +12 -0
  68. package/dist/chat/logic/timeline-target.js +34 -0
  69. package/dist/chat/logic/timeline.d.ts +115 -0
  70. package/dist/chat/logic/timeline.js +343 -0
  71. package/dist/chat/logic/tool-catalog.d.ts +10 -0
  72. package/dist/chat/logic/tool-catalog.js +44 -0
  73. package/dist/chat/logic/tools.d.ts +15 -0
  74. package/dist/chat/logic/tools.js +82 -0
  75. package/dist/chat/logic/welcome.d.ts +2 -0
  76. package/dist/chat/logic/welcome.js +10 -0
  77. package/dist/chat/logic/workflow.d.ts +14 -0
  78. package/dist/chat/logic/workflow.js +47 -0
  79. package/dist/chat/mentions.d.ts +65 -0
  80. package/dist/chat/mentions.js +184 -0
  81. package/dist/chat/persisted-json.d.ts +5 -0
  82. package/dist/chat/persisted-json.js +58 -0
  83. package/dist/chat/preferences.d.ts +27 -0
  84. package/dist/chat/preferences.js +139 -0
  85. package/dist/chat/quote.d.ts +2 -0
  86. package/dist/chat/quote.js +25 -0
  87. package/dist/chat/recent-messages.d.ts +17 -0
  88. package/dist/chat/recent-messages.js +36 -0
  89. package/dist/chat/resume-compaction-dismissals.d.ts +3 -0
  90. package/dist/chat/resume-compaction-dismissals.js +14 -0
  91. package/dist/chat/runtime-modes.d.ts +4 -0
  92. package/dist/chat/runtime-modes.js +15 -0
  93. package/dist/chat/stash.d.ts +24 -0
  94. package/dist/chat/stash.js +91 -0
  95. package/dist/chat/subagent-conversation.d.ts +41 -0
  96. package/dist/chat/subagent-conversation.js +167 -0
  97. package/dist/chat/subagent-list.d.ts +19 -0
  98. package/dist/chat/subagent-list.js +106 -0
  99. package/dist/chat/subagent-support.d.ts +6 -0
  100. package/dist/chat/subagent-support.js +14 -0
  101. package/dist/chat/subagent-view.d.ts +35 -0
  102. package/dist/chat/subagent-view.js +96 -0
  103. package/dist/chat/thumbnails.d.ts +10 -0
  104. package/dist/chat/thumbnails.js +89 -0
  105. package/dist/chat/timeline-flash.d.ts +12 -0
  106. package/dist/chat/timeline-flash.js +16 -0
  107. package/dist/chat/timeline-scroll.d.ts +27 -0
  108. package/dist/chat/timeline-scroll.js +152 -0
  109. package/dist/chat/ui/AccountPill.d.ts +3 -0
  110. package/dist/chat/ui/AccountPill.js +23 -0
  111. package/dist/chat/ui/AnsiOutput.d.ts +5 -0
  112. package/dist/chat/ui/AnsiOutput.js +9 -0
  113. package/dist/chat/ui/BookmarkMarker.d.ts +8 -0
  114. package/dist/chat/ui/BookmarkMarker.js +57 -0
  115. package/dist/chat/ui/BookmarkSubmenu.d.ts +3 -0
  116. package/dist/chat/ui/BookmarkSubmenu.js +33 -0
  117. package/dist/chat/ui/ChatActivity.d.ts +7 -0
  118. package/dist/chat/ui/ChatActivity.js +84 -0
  119. package/dist/chat/ui/ChatReferenceChip.d.ts +4 -0
  120. package/dist/chat/ui/ChatReferenceChip.js +16 -0
  121. package/dist/chat/ui/CodeBlock.d.ts +4 -0
  122. package/dist/chat/ui/CodeBlock.js +132 -0
  123. package/dist/chat/ui/Composer.d.ts +15 -0
  124. package/dist/chat/ui/Composer.js +856 -0
  125. package/dist/chat/ui/ComposerInput.d.ts +29 -0
  126. package/dist/chat/ui/ComposerInput.js +127 -0
  127. package/dist/chat/ui/DiffPool.d.ts +5 -0
  128. package/dist/chat/ui/DiffPool.js +26 -0
  129. package/dist/chat/ui/EditDiff.d.ts +4 -0
  130. package/dist/chat/ui/EditDiff.js +21 -0
  131. package/dist/chat/ui/FadingWords.d.ts +3 -0
  132. package/dist/chat/ui/FadingWords.js +5 -0
  133. package/dist/chat/ui/ImageView.d.ts +6 -0
  134. package/dist/chat/ui/ImageView.js +81 -0
  135. package/dist/chat/ui/LimitState.d.ts +8 -0
  136. package/dist/chat/ui/LimitState.js +112 -0
  137. package/dist/chat/ui/Markdown.d.ts +18 -0
  138. package/dist/chat/ui/Markdown.js +159 -0
  139. package/dist/chat/ui/MessageActions.d.ts +9 -0
  140. package/dist/chat/ui/MessageActions.js +53 -0
  141. package/dist/chat/ui/Pickers.d.ts +21 -0
  142. package/dist/chat/ui/Pickers.js +111 -0
  143. package/dist/chat/ui/PromptComposer.d.ts +13 -0
  144. package/dist/chat/ui/PromptComposer.js +56 -0
  145. package/dist/chat/ui/QuoteButton.d.ts +7 -0
  146. package/dist/chat/ui/QuoteButton.js +74 -0
  147. package/dist/chat/ui/ResumeCompactionDock.d.ts +5 -0
  148. package/dist/chat/ui/ResumeCompactionDock.js +14 -0
  149. package/dist/chat/ui/RunSettings.d.ts +28 -0
  150. package/dist/chat/ui/RunSettings.js +153 -0
  151. package/dist/chat/ui/Scrubber.d.ts +17 -0
  152. package/dist/chat/ui/Scrubber.js +118 -0
  153. package/dist/chat/ui/SubagentControls.d.ts +11 -0
  154. package/dist/chat/ui/SubagentControls.js +36 -0
  155. package/dist/chat/ui/SubagentInfo.d.ts +4 -0
  156. package/dist/chat/ui/SubagentInfo.js +34 -0
  157. package/dist/chat/ui/SubagentStopButton.d.ts +7 -0
  158. package/dist/chat/ui/SubagentStopButton.js +34 -0
  159. package/dist/chat/ui/SubagentTimeline.d.ts +4 -0
  160. package/dist/chat/ui/SubagentTimeline.js +107 -0
  161. package/dist/chat/ui/Timeline.d.ts +6 -0
  162. package/dist/chat/ui/Timeline.js +424 -0
  163. package/dist/chat/ui/TimelineMenu.d.ts +12 -0
  164. package/dist/chat/ui/TimelineMenu.js +54 -0
  165. package/dist/chat/ui/UnifiedDiff.d.ts +11 -0
  166. package/dist/chat/ui/UnifiedDiff.js +66 -0
  167. package/dist/chat/ui/UploadThumb.d.ts +4 -0
  168. package/dist/chat/ui/UploadThumb.js +11 -0
  169. package/dist/chat/ui/Welcome.d.ts +4 -0
  170. package/dist/chat/ui/Welcome.js +16 -0
  171. package/dist/chat/ui/chips.d.ts +4 -0
  172. package/dist/chat/ui/chips.js +11 -0
  173. package/dist/chat/ui/code-lines.d.ts +18 -0
  174. package/dist/chat/ui/code-lines.js +46 -0
  175. package/dist/chat/ui/code-streaming.d.ts +1 -0
  176. package/dist/chat/ui/code-streaming.js +3 -0
  177. package/dist/chat/ui/code-theme.d.ts +3 -0
  178. package/dist/chat/ui/code-theme.js +12 -0
  179. package/dist/chat/ui/composer/chips.d.ts +6 -0
  180. package/dist/chat/ui/composer/chips.js +31 -0
  181. package/dist/chat/ui/composer/editor.d.ts +11 -0
  182. package/dist/chat/ui/composer/editor.js +98 -0
  183. package/dist/chat/ui/composer/insert.d.ts +2 -0
  184. package/dist/chat/ui/composer/insert.js +19 -0
  185. package/dist/chat/ui/composer/keys.d.ts +30 -0
  186. package/dist/chat/ui/composer/keys.js +100 -0
  187. package/dist/chat/ui/diff-theme.d.ts +2 -0
  188. package/dist/chat/ui/diff-theme.js +20 -0
  189. package/dist/chat/ui/file-links.d.ts +5 -0
  190. package/dist/chat/ui/file-links.js +20 -0
  191. package/dist/chat/ui/find-reveal.d.ts +7 -0
  192. package/dist/chat/ui/find-reveal.js +13 -0
  193. package/dist/chat/ui/full-diff.d.ts +6 -0
  194. package/dist/chat/ui/full-diff.js +19 -0
  195. package/dist/chat/ui/icons.d.ts +4 -0
  196. package/dist/chat/ui/icons.js +20 -0
  197. package/dist/chat/ui/markdown-blocks.d.ts +6 -0
  198. package/dist/chat/ui/markdown-blocks.js +103 -0
  199. package/dist/chat/ui/quote-selection.d.ts +3 -0
  200. package/dist/chat/ui/quote-selection.js +46 -0
  201. package/dist/chat/ui/rehype-chips.d.ts +23 -0
  202. package/dist/chat/ui/rehype-chips.js +32 -0
  203. package/dist/chat/ui/rehype-fade.d.ts +23 -0
  204. package/dist/chat/ui/rehype-fade.js +36 -0
  205. package/dist/chat/ui/remark-html-as-text.d.ts +8 -0
  206. package/dist/chat/ui/remark-html-as-text.js +26 -0
  207. package/dist/chat/ui/reply-context.d.ts +5 -0
  208. package/dist/chat/ui/reply-context.js +2 -0
  209. package/dist/chat/ui/reveal.d.ts +13 -0
  210. package/dist/chat/ui/reveal.js +114 -0
  211. package/dist/chat/ui/rows/ForksRow.d.ts +4 -0
  212. package/dist/chat/ui/rows/ForksRow.js +38 -0
  213. package/dist/chat/ui/rows/MessageRows.d.ts +40 -0
  214. package/dist/chat/ui/rows/MessageRows.js +204 -0
  215. package/dist/chat/ui/rows/Rows.d.ts +12 -0
  216. package/dist/chat/ui/rows/Rows.js +61 -0
  217. package/dist/chat/ui/rows/SubagentRow.d.ts +17 -0
  218. package/dist/chat/ui/rows/SubagentRow.js +101 -0
  219. package/dist/chat/ui/rows/TaskRow.d.ts +8 -0
  220. package/dist/chat/ui/rows/TaskRow.js +63 -0
  221. package/dist/chat/ui/rows/WorkRows.d.ts +47 -0
  222. package/dist/chat/ui/rows/WorkRows.js +168 -0
  223. package/dist/chat/ui/rows/WorkflowRow.d.ts +8 -0
  224. package/dist/chat/ui/rows/WorkflowRow.js +48 -0
  225. package/dist/chat/ui/rows/row-rhythm.d.ts +6 -0
  226. package/dist/chat/ui/rows/row-rhythm.js +34 -0
  227. package/dist/chat/ui/useToggleSet.d.ts +6 -0
  228. package/dist/chat/ui/useToggleSet.js +25 -0
  229. package/dist/host.d.ts +195 -0
  230. package/dist/host.js +55 -0
  231. package/dist/lazy.d.ts +6 -0
  232. package/dist/lazy.js +57 -0
  233. package/dist/locales/en/agent-chat.json +446 -0
  234. package/dist/locales/en/agent-prompts.json +42 -0
  235. package/dist/locales/en/agent-providers.json +131 -0
  236. package/dist/locales/en/agent-usage.json +131 -0
  237. package/dist/locales/nl/agent-chat.json +446 -0
  238. package/dist/locales/nl/agent-prompts.json +42 -0
  239. package/dist/locales/nl/agent-providers.json +131 -0
  240. package/dist/locales/nl/agent-usage.json +131 -0
  241. package/dist/locales.d.ts +5 -0
  242. package/dist/locales.js +20 -0
  243. package/dist/mounted-registry.d.ts +7 -0
  244. package/dist/mounted-registry.js +39 -0
  245. package/dist/port-transport.d.ts +6 -0
  246. package/dist/port-transport.js +129 -0
  247. package/dist/prompts/logic/focus.d.ts +2 -0
  248. package/dist/prompts/logic/focus.js +23 -0
  249. package/dist/prompts/logic/keys.d.ts +42 -0
  250. package/dist/prompts/logic/keys.js +94 -0
  251. package/dist/prompts/logic/prompts.d.ts +34 -0
  252. package/dist/prompts/logic/prompts.fixtures.d.ts +5 -0
  253. package/dist/prompts/logic/prompts.fixtures.js +79 -0
  254. package/dist/prompts/logic/prompts.js +32 -0
  255. package/dist/prompts/logic/subjects.d.ts +50 -0
  256. package/dist/prompts/logic/subjects.js +63 -0
  257. package/dist/prompts/logic/useFocusAfterAnswer.d.ts +6 -0
  258. package/dist/prompts/logic/useFocusAfterAnswer.js +28 -0
  259. package/dist/prompts/logic/usePromptSession.d.ts +24 -0
  260. package/dist/prompts/logic/usePromptSession.js +87 -0
  261. package/dist/prompts/ui/ApprovalBody.d.ts +13 -0
  262. package/dist/prompts/ui/ApprovalBody.js +34 -0
  263. package/dist/prompts/ui/PromptActions.d.ts +27 -0
  264. package/dist/prompts/ui/PromptActions.js +18 -0
  265. package/dist/prompts/ui/PromptCard.d.ts +16 -0
  266. package/dist/prompts/ui/PromptCard.js +50 -0
  267. package/dist/prompts/ui/PromptView.d.ts +2 -0
  268. package/dist/prompts/ui/PromptView.js +47 -0
  269. package/dist/prompts/ui/QuestionBody.d.ts +9 -0
  270. package/dist/prompts/ui/QuestionBody.js +87 -0
  271. package/dist/providers/AccountColors.d.ts +5 -0
  272. package/dist/providers/AccountColors.js +8 -0
  273. package/dist/providers/AccountDetail.d.ts +12 -0
  274. package/dist/providers/AccountDetail.js +69 -0
  275. package/dist/providers/AccountVariables.d.ts +8 -0
  276. package/dist/providers/AccountVariables.js +43 -0
  277. package/dist/providers/AddAccountForm.d.ts +10 -0
  278. package/dist/providers/AddAccountForm.js +54 -0
  279. package/dist/providers/CliDetail.d.ts +12 -0
  280. package/dist/providers/CliDetail.js +54 -0
  281. package/dist/providers/ProvidersPane.d.ts +9 -0
  282. package/dist/providers/ProvidersPane.js +86 -0
  283. package/dist/providers/account-actions.d.ts +7 -0
  284. package/dist/providers/account-actions.js +57 -0
  285. package/dist/providers/parts.d.ts +9 -0
  286. package/dist/providers/parts.js +18 -0
  287. package/dist/providers/provider-abilities.d.ts +2 -0
  288. package/dist/providers/provider-abilities.js +7 -0
  289. package/dist/providers/variables.d.ts +13 -0
  290. package/dist/providers/variables.js +63 -0
  291. package/dist/scope.d.ts +11 -0
  292. package/dist/scope.js +10 -0
  293. package/dist/settings/sections.d.ts +13 -0
  294. package/dist/settings/sections.js +32 -0
  295. package/dist/state/chats.d.ts +44 -0
  296. package/dist/state/chats.js +199 -0
  297. package/dist/state/provider-accounts.d.ts +17 -0
  298. package/dist/state/provider-accounts.js +67 -0
  299. package/dist/state/providers.d.ts +17 -0
  300. package/dist/state/providers.js +33 -0
  301. package/dist/state/usage.d.ts +44 -0
  302. package/dist/state/usage.js +121 -0
  303. package/dist/storage.d.ts +20 -0
  304. package/dist/storage.js +89 -0
  305. package/dist/theme.css +212 -0
  306. package/dist/transport.d.ts +24 -0
  307. package/dist/transport.js +18 -0
  308. package/dist/ui/PlainTextarea.d.ts +2 -0
  309. package/dist/ui/PlainTextarea.js +5 -0
  310. package/dist/usage/LimitsList.d.ts +18 -0
  311. package/dist/usage/LimitsList.js +73 -0
  312. package/dist/usage/UsageBreakdown.d.ts +9 -0
  313. package/dist/usage/UsageBreakdown.js +67 -0
  314. package/dist/usage/UsageChart.d.ts +10 -0
  315. package/dist/usage/UsageChart.js +47 -0
  316. package/dist/usage/UsageDialog.d.ts +6 -0
  317. package/dist/usage/UsageDialog.js +12 -0
  318. package/dist/usage/UsageLimits.d.ts +1 -0
  319. package/dist/usage/UsageLimits.js +57 -0
  320. package/dist/usage/UsageLimitsCard.d.ts +4 -0
  321. package/dist/usage/UsageLimitsCard.js +26 -0
  322. package/dist/usage/UsagePage.d.ts +7 -0
  323. package/dist/usage/UsagePage.js +154 -0
  324. package/dist/usage/UsagePane.d.ts +3 -0
  325. package/dist/usage/UsagePane.js +21 -0
  326. package/dist/usage/UsageSummary.d.ts +12 -0
  327. package/dist/usage/UsageSummary.js +15 -0
  328. package/dist/usage/UsageTiles.d.ts +7 -0
  329. package/dist/usage/UsageTiles.js +19 -0
  330. package/dist/usage/format.d.ts +13 -0
  331. package/dist/usage/format.js +55 -0
  332. package/dist/usage/limit-groups.d.ts +22 -0
  333. package/dist/usage/limit-groups.js +86 -0
  334. package/dist/usage/limits.d.ts +4 -0
  335. package/dist/usage/limits.js +58 -0
  336. package/dist/usage/money.d.ts +1 -0
  337. package/dist/usage/money.js +13 -0
  338. package/dist/usage/summary.d.ts +34 -0
  339. package/dist/usage/summary.js +94 -0
  340. package/package.json +895 -3
  341. package/src/agents/AccountDot.tsx +14 -0
  342. package/src/agents/AgentIcon.tsx +26 -0
  343. package/src/agents/ModelOptionControl.tsx +68 -0
  344. package/src/agents/ProviderLogo.tsx +20 -0
  345. package/src/agents/account-limits.ts +61 -0
  346. package/src/agents/accounts.ts +137 -0
  347. package/src/agents/model-name.ts +70 -0
  348. package/src/agents/model-options.ts +21 -0
  349. package/src/agents/provider-paths.ts +10 -0
  350. package/src/agents/status-look.ts +43 -0
  351. package/src/chat/account-choice.ts +44 -0
  352. package/src/chat/actions.ts +72 -0
  353. package/src/chat/activity.ts +8 -0
  354. package/src/chat/attachments.ts +118 -0
  355. package/src/chat/bookmarks.ts +87 -0
  356. package/src/chat/chat-client.ts +345 -0
  357. package/src/chat/chat-references.ts +11 -0
  358. package/src/chat/drafts.ts +165 -0
  359. package/src/chat/forks.ts +33 -0
  360. package/src/chat/guards.ts +84 -0
  361. package/src/chat/logic/ansi.ts +206 -0
  362. package/src/chat/logic/answers.ts +8 -0
  363. package/src/chat/logic/bookmarks.ts +42 -0
  364. package/src/chat/logic/context-usage.ts +36 -0
  365. package/src/chat/logic/fork.ts +200 -0
  366. package/src/chat/logic/handback.ts +10 -0
  367. package/src/chat/logic/json.ts +4 -0
  368. package/src/chat/logic/limit.ts +46 -0
  369. package/src/chat/logic/resume-compaction.ts +71 -0
  370. package/src/chat/logic/scrubber.ts +289 -0
  371. package/src/chat/logic/thread-cards.ts +64 -0
  372. package/src/chat/logic/timeline-copy.ts +65 -0
  373. package/src/chat/logic/timeline-target.ts +52 -0
  374. package/src/chat/logic/timeline.ts +419 -0
  375. package/src/chat/logic/tool-catalog.ts +62 -0
  376. package/src/chat/logic/tools.ts +102 -0
  377. package/src/chat/logic/welcome.ts +13 -0
  378. package/src/chat/logic/workflow.ts +66 -0
  379. package/src/chat/mentions.ts +232 -0
  380. package/src/chat/persisted-json.ts +67 -0
  381. package/src/chat/preferences.ts +179 -0
  382. package/src/chat/quote.ts +26 -0
  383. package/src/chat/recent-messages.ts +59 -0
  384. package/src/chat/resume-compaction-dismissals.ts +17 -0
  385. package/src/chat/runtime-modes.ts +18 -0
  386. package/src/chat/stash.ts +122 -0
  387. package/src/chat/subagent-conversation.ts +203 -0
  388. package/src/chat/subagent-list.ts +141 -0
  389. package/src/chat/subagent-support.ts +21 -0
  390. package/src/chat/subagent-view.ts +137 -0
  391. package/src/chat/thumbnails.ts +108 -0
  392. package/src/chat/timeline-flash.ts +33 -0
  393. package/src/chat/timeline-scroll.ts +199 -0
  394. package/src/chat/ui/AccountPill.tsx +31 -0
  395. package/src/chat/ui/AnsiOutput.tsx +18 -0
  396. package/src/chat/ui/BookmarkMarker.tsx +108 -0
  397. package/src/chat/ui/BookmarkSubmenu.tsx +53 -0
  398. package/src/chat/ui/ChatActivity.tsx +198 -0
  399. package/src/chat/ui/ChatReferenceChip.tsx +28 -0
  400. package/src/chat/ui/CodeBlock.tsx +175 -0
  401. package/src/chat/ui/Composer.tsx +1326 -0
  402. package/src/chat/ui/ComposerInput.tsx +187 -0
  403. package/src/chat/ui/DiffPool.tsx +36 -0
  404. package/src/chat/ui/EditDiff.tsx +30 -0
  405. package/src/chat/ui/FadingWords.tsx +18 -0
  406. package/src/chat/ui/ImageView.tsx +159 -0
  407. package/src/chat/ui/LimitState.tsx +165 -0
  408. package/src/chat/ui/Markdown.tsx +258 -0
  409. package/src/chat/ui/MessageActions.tsx +88 -0
  410. package/src/chat/ui/Pickers.tsx +272 -0
  411. package/src/chat/ui/PromptComposer.tsx +119 -0
  412. package/src/chat/ui/QuoteButton.tsx +103 -0
  413. package/src/chat/ui/ResumeCompactionDock.tsx +28 -0
  414. package/src/chat/ui/RunSettings.tsx +546 -0
  415. package/src/chat/ui/Scrubber.tsx +262 -0
  416. package/src/chat/ui/SubagentControls.tsx +66 -0
  417. package/src/chat/ui/SubagentInfo.tsx +67 -0
  418. package/src/chat/ui/SubagentStopButton.tsx +45 -0
  419. package/src/chat/ui/SubagentTimeline.tsx +170 -0
  420. package/src/chat/ui/Timeline.tsx +628 -0
  421. package/src/chat/ui/TimelineMenu.tsx +124 -0
  422. package/src/chat/ui/UnifiedDiff.tsx +99 -0
  423. package/src/chat/ui/UploadThumb.tsx +13 -0
  424. package/src/chat/ui/Welcome.tsx +22 -0
  425. package/src/chat/ui/chips.ts +15 -0
  426. package/src/chat/ui/code-lines.ts +60 -0
  427. package/src/chat/ui/code-streaming.ts +4 -0
  428. package/src/chat/ui/code-theme.ts +15 -0
  429. package/src/chat/ui/composer/chips.ts +43 -0
  430. package/src/chat/ui/composer/editor.ts +118 -0
  431. package/src/chat/ui/composer/insert.ts +22 -0
  432. package/src/chat/ui/composer/keys.ts +144 -0
  433. package/src/chat/ui/diff-theme.ts +23 -0
  434. package/src/chat/ui/file-links.ts +24 -0
  435. package/src/chat/ui/find-reveal.ts +23 -0
  436. package/src/chat/ui/full-diff.ts +25 -0
  437. package/src/chat/ui/icons.tsx +24 -0
  438. package/src/chat/ui/markdown-blocks.ts +123 -0
  439. package/src/chat/ui/quote-selection.ts +53 -0
  440. package/src/chat/ui/rehype-chips.ts +62 -0
  441. package/src/chat/ui/rehype-fade.ts +64 -0
  442. package/src/chat/ui/remark-html-as-text.ts +36 -0
  443. package/src/chat/ui/reply-context.ts +4 -0
  444. package/src/chat/ui/reveal.ts +135 -0
  445. package/src/chat/ui/rows/ForksRow.tsx +79 -0
  446. package/src/chat/ui/rows/MessageRows.tsx +415 -0
  447. package/src/chat/ui/rows/Rows.tsx +81 -0
  448. package/src/chat/ui/rows/SubagentRow.tsx +209 -0
  449. package/src/chat/ui/rows/TaskRow.tsx +91 -0
  450. package/src/chat/ui/rows/WorkRows.tsx +445 -0
  451. package/src/chat/ui/rows/WorkflowRow.tsx +120 -0
  452. package/src/chat/ui/rows/row-rhythm.ts +37 -0
  453. package/src/chat/ui/useToggleSet.ts +39 -0
  454. package/src/host.ts +324 -0
  455. package/src/lazy.tsx +64 -0
  456. package/src/locales/en/agent-chat.json +446 -0
  457. package/src/locales/en/agent-prompts.json +42 -0
  458. package/src/locales/en/agent-providers.json +131 -0
  459. package/src/locales/en/agent-usage.json +131 -0
  460. package/src/locales/nl/agent-chat.json +446 -0
  461. package/src/locales/nl/agent-prompts.json +42 -0
  462. package/src/locales/nl/agent-providers.json +131 -0
  463. package/src/locales/nl/agent-usage.json +131 -0
  464. package/src/locales.ts +33 -0
  465. package/src/mounted-registry.ts +45 -0
  466. package/src/port-transport.ts +146 -0
  467. package/src/prompts/logic/focus.ts +25 -0
  468. package/src/prompts/logic/keys.ts +116 -0
  469. package/src/prompts/logic/prompts.fixtures.ts +84 -0
  470. package/src/prompts/logic/prompts.ts +58 -0
  471. package/src/prompts/logic/subjects.ts +122 -0
  472. package/src/prompts/logic/useFocusAfterAnswer.ts +38 -0
  473. package/src/prompts/logic/usePromptSession.ts +114 -0
  474. package/src/prompts/ui/ApprovalBody.tsx +109 -0
  475. package/src/prompts/ui/PromptActions.tsx +109 -0
  476. package/src/prompts/ui/PromptCard.tsx +101 -0
  477. package/src/prompts/ui/PromptView.tsx +111 -0
  478. package/src/prompts/ui/QuestionBody.tsx +174 -0
  479. package/src/providers/AccountColors.tsx +8 -0
  480. package/src/providers/AccountDetail.tsx +209 -0
  481. package/src/providers/AccountVariables.tsx +126 -0
  482. package/src/providers/AddAccountForm.tsx +121 -0
  483. package/src/providers/CliDetail.tsx +157 -0
  484. package/src/providers/ProvidersPane.tsx +236 -0
  485. package/src/providers/account-actions.ts +67 -0
  486. package/src/providers/parts.tsx +25 -0
  487. package/src/providers/provider-abilities.ts +9 -0
  488. package/src/providers/variables.ts +87 -0
  489. package/src/scope.ts +30 -0
  490. package/src/settings/sections.ts +47 -0
  491. package/src/state/chats.ts +279 -0
  492. package/src/state/provider-accounts.ts +87 -0
  493. package/src/state/providers.ts +50 -0
  494. package/src/state/usage.ts +196 -0
  495. package/src/storage.ts +113 -0
  496. package/src/theme.css +212 -0
  497. package/src/transport.ts +50 -0
  498. package/src/ui/PlainTextarea.tsx +6 -0
  499. package/src/usage/LimitsList.tsx +232 -0
  500. package/src/usage/UsageBreakdown.tsx +210 -0
  501. package/src/usage/UsageChart.tsx +113 -0
  502. package/src/usage/UsageDialog.tsx +20 -0
  503. package/src/usage/UsageLimits.tsx +145 -0
  504. package/src/usage/UsageLimitsCard.tsx +36 -0
  505. package/src/usage/UsagePage.tsx +276 -0
  506. package/src/usage/UsagePane.tsx +52 -0
  507. package/src/usage/UsageSummary.tsx +50 -0
  508. package/src/usage/UsageTiles.tsx +34 -0
  509. package/src/usage/format.ts +71 -0
  510. package/src/usage/limit-groups.ts +119 -0
  511. package/src/usage/limits.ts +71 -0
  512. package/src/usage/money.ts +14 -0
  513. package/src/usage/summary.ts +137 -0
@@ -0,0 +1,445 @@
1
+ import { Suspense, useEffect, useState } from 'react';
2
+ import clsx from 'clsx';
3
+ import i18next from 'i18next';
4
+ import { useTranslation } from 'react-i18next';
5
+ import { ChevronRight, FileDiff, X } from 'lucide-react';
6
+ import type { ChatCheckpointDiff, ChatCheckpointFile, ChatFileChange, ChatToolItem, ChatTurnItem } from '@adecore/agent-contracts';
7
+ import { fileChanges, liveOutput, readImagePath, toolStartedAt, toolSummary, unifiedChanges, type FileChange } from '../../logic/tools';
8
+ import { useOpenForFind } from '../find-reveal';
9
+ import { chatHost } from '../../../host';
10
+ import { lazyNamed } from '../../../lazy';
11
+ import { useChatActions } from '../../actions';
12
+ import { useChatScope } from '../../../scope';
13
+ import { useCurrentItem } from '../../../state/chats';
14
+ import { useTimelineFlash } from '../../timeline-flash';
15
+ import { formatClockDuration, formatElapsedShort } from '@adecore/ui/format';
16
+ import { Icon, Spinner, useTickingText } from '@adecore/ui';
17
+ import { ROW_GUTTER, toolIcon } from '../icons';
18
+ import { AnsiOutput } from '../AnsiOutput';
19
+
20
+ // The diff renderers carry shiki; they only load once a thread shows a file change.
21
+ const EditDiff = lazyNamed(() => import('../EditDiff'), 'default');
22
+ const UnifiedDiff = lazyNamed(() => import('../UnifiedDiff'), 'default');
23
+
24
+ const OUTPUT_LIMIT = 4000;
25
+
26
+ function clip(text: string): string {
27
+ return text.length > OUTPUT_LIMIT
28
+ ? `${text.slice(0, OUTPUT_LIMIT)}\n${i18next.t('agent-chat:work.moreCharacters', { count: text.length - OUTPUT_LIMIT })}`
29
+ : text;
30
+ }
31
+
32
+ export function ToggleLine({
33
+ icon,
34
+ label,
35
+ detail,
36
+ open,
37
+ onToggle,
38
+ failed,
39
+ live,
40
+ trailing,
41
+ className
42
+ }: {
43
+ icon: React.ReactNode;
44
+ label: string;
45
+ detail?: string;
46
+ open: boolean;
47
+ onToggle(): void;
48
+ failed?: boolean;
49
+ live?: boolean;
50
+ trailing?: React.ReactNode;
51
+ className?: string;
52
+ }) {
53
+ return (
54
+ <button
55
+ className={clsx(
56
+ // Fix the width so long commands reach the truncation inside the negative margins.
57
+ '-mx-1 mb-0.5 flex h-7 w-[calc(100%+8px)] items-center gap-2 rounded-md px-1 text-left text-xs text-text-muted hover:bg-surface-hover',
58
+ failed && 'text-status-error',
59
+ className
60
+ )}
61
+ onClick={onToggle}
62
+ >
63
+ <span className={clsx(ROW_GUTTER, live && 'text-accent')}>{icon}</span>
64
+ <span className={clsx('shrink-0', live && 'chat-live-text')}>{label}</span>
65
+ {detail && (
66
+ <span data-find-field="summary" className="min-w-0 truncate font-mono text-text-faint">
67
+ {detail}
68
+ </span>
69
+ )}
70
+ <span className="grow" />
71
+ {trailing}
72
+ {failed && <Icon icon={X} size={12} className="shrink-0" />}
73
+ <Icon icon={ChevronRight} size={12} className={clsx('shrink-0 text-text-faint transition-transform', open && 'rotate-90')} />
74
+ </button>
75
+ );
76
+ }
77
+
78
+ function ToolBody({ tool }: { tool: ChatToolItem }) {
79
+ const { t } = useTranslation('agent-chat');
80
+ const patches = unifiedChanges(tool);
81
+ const changes = patches.length > 0 ? [] : fileChanges(tool.name, tool.input);
82
+ return (
83
+ <div className="mt-1.5 mb-2 ml-6 overflow-hidden rounded-md border border-border bg-surface-raised">
84
+ {patches.length > 0 ? (
85
+ <Suspense fallback={<div className="px-3 py-2 text-xs text-text-faint">{t('work.loadingDiff')}</div>}>
86
+ {patches.map((change, index) => (
87
+ <UnifiedDiff key={index} change={change} />
88
+ ))}
89
+ </Suspense>
90
+ ) : changes.length > 0 ? (
91
+ <Suspense fallback={<div className="px-3 py-2 text-xs text-text-faint">{t('work.loadingDiff')}</div>}>
92
+ {changes.map((change, index) => (
93
+ <EditDiff key={index} change={change} />
94
+ ))}
95
+ </Suspense>
96
+ ) : (
97
+ <pre className="max-h-64 overflow-auto px-3 py-2 font-mono text-code text-text-muted select-text">
98
+ {clip(JSON.stringify(tool.input, null, 2) ?? '')}
99
+ </pre>
100
+ )}
101
+ {tool.output !== null && tool.output !== '' && patches.length === 0 && (
102
+ <pre
103
+ data-find-field="output"
104
+ className={clsx(
105
+ 'max-h-64 overflow-auto whitespace-pre-wrap border-t border-border px-3 py-2 font-mono text-code select-text',
106
+ tool.state === 'error' ? 'text-chat-removed' : 'text-chat-output'
107
+ )}
108
+ >
109
+ <AnsiOutput text={tool.output} limit={OUTPUT_LIMIT} />
110
+ </pre>
111
+ )}
112
+ </div>
113
+ );
114
+ }
115
+
116
+ /* One settled tool call: a line, and its input and output behind it. An image the call looked at
117
+ is drawn under the line, because a picture says more about that read than its path does. */
118
+ export function WorkRow({ tool, nested, detail }: { tool: ChatToolItem; nested?: boolean; detail?: string }) {
119
+ const [open, setOpen] = useState(false);
120
+ const image = tool.state === 'done' ? readImagePath(tool.name, tool.input) : null;
121
+ const { ReadImage } = chatHost();
122
+ useOpenForFind(tool.id, 'output', setOpen);
123
+ return (
124
+ <div data-find-item={tool.id} className={nested ? 'ml-6' : undefined}>
125
+ <ToggleLine
126
+ icon={toolIcon(tool.name)}
127
+ label={tool.name}
128
+ detail={detail ?? toolSummary(tool.name, tool.input)}
129
+ open={open}
130
+ onToggle={() => setOpen((o) => !o)}
131
+ failed={tool.state === 'error'}
132
+ />
133
+ {image !== null && ReadImage !== null && <ReadImage path={image} />}
134
+ {open && <ToolBody tool={tool} />}
135
+ </div>
136
+ );
137
+ }
138
+
139
+ /* "running for 12s" next to a live call. */
140
+ export function RunningFor({ startedAt }: { startedAt: number }) {
141
+ const { t } = useTranslation('agent-chat');
142
+ const ref = useTickingText(() => t('work.runningFor', { elapsed: formatElapsedShort(Date.now() - startedAt) }));
143
+ return <span ref={ref} className="shrink-0 text-xs text-text-faint tabular-nums" />;
144
+ }
145
+
146
+ /* A call still running: its timer on the line, and for a provider that streams output, the last lines under it. */
147
+ export function WorkLiveRow({ chatId, tool: derived }: { chatId: string; tool: ChatToolItem }) {
148
+ const [open, setOpen] = useState(false);
149
+ const tool = useCurrentItem(chatId, derived);
150
+ const tail = liveOutput(tool);
151
+ return (
152
+ <div>
153
+ <ToggleLine
154
+ icon={toolIcon(tool.name)}
155
+ label={tool.name}
156
+ detail={toolSummary(tool.name, tool.input) || tool.progress?.description || ''}
157
+ open={open}
158
+ onToggle={() => setOpen((o) => !o)}
159
+ trailing={<RunningFor startedAt={toolStartedAt(tool)} />}
160
+ live
161
+ />
162
+ {open && <ToolBody tool={tool} />}
163
+ {tail !== null && !open && (
164
+ <pre className="mt-1.5 mb-2 ml-6 max-h-48 overflow-auto rounded-md border border-border bg-surface-raised px-3 py-2 font-mono text-code whitespace-pre-wrap text-chat-output select-text">
165
+ <AnsiOutput text={tail} tailLines={12} />
166
+ </pre>
167
+ )}
168
+ </div>
169
+ );
170
+ }
171
+
172
+ /* A run of tool calls as one line ("Read 4 files"); opening it lists every call. */
173
+ export function WorkGroupRow({ tools, summary, expanded, onToggle }: { tools: ChatToolItem[]; summary: string; expanded: boolean; onToggle(): void }) {
174
+ const failed = tools.some((tool) => tool.state === 'error');
175
+ return (
176
+ <div>
177
+ <ToggleLine icon={toolIcon(tools[0]!.name)} label={summary} open={expanded} onToggle={onToggle} failed={failed} />
178
+ </div>
179
+ );
180
+ }
181
+
182
+ /*
183
+ * A settled turn folded behind how long it took and what it did. A line and not a button, like the
184
+ * tool lines it hides; the work reads fainter than the time so the eye lands on the time first.
185
+ */
186
+ export function TurnFoldRow({
187
+ turn,
188
+ label,
189
+ work,
190
+ expanded,
191
+ onToggle
192
+ }: {
193
+ turn: ChatTurnItem;
194
+ label: string;
195
+ work: readonly string[];
196
+ expanded: boolean;
197
+ onToggle(): void;
198
+ }) {
199
+ return (
200
+ <button
201
+ className={clsx(
202
+ 'group -mx-1 mb-2 flex h-7 w-[calc(100%+8px)] min-w-0 items-center gap-2 rounded-md px-1 text-left text-xs text-text-muted hover:bg-surface-hover',
203
+ turn.state === 'error' && 'text-status-error'
204
+ )}
205
+ aria-expanded={expanded}
206
+ onClick={onToggle}
207
+ >
208
+ <span className={ROW_GUTTER}>
209
+ <Icon icon={ChevronRight} size={12} className={clsx('transition-transform', expanded && 'rotate-90')} />
210
+ </span>
211
+ <span className="shrink-0 group-hover:text-text">{label}</span>
212
+ {work.length > 0 && <span className="min-w-0 truncate text-text-faint">{work.map((part) => ` · ${part}`).join('')}</span>}
213
+ </button>
214
+ );
215
+ }
216
+
217
+ function omittedLabel(reason: 'binary' | 'too-large'): string {
218
+ return reason === 'binary' ? i18next.t('agent-chat:work.omitted.binary') : i18next.t('agent-chat:work.omitted.tooLarge');
219
+ }
220
+
221
+ /* One file of a turn's checkpoint diff: its patch, or the reason there is none. */
222
+ function CheckpointFileBody({ file }: { file: ChatCheckpointFile }) {
223
+ const { t } = useTranslation('agent-chat');
224
+ if (file.omitted) {
225
+ return <div className="px-3 py-2 text-xs text-text-faint">{omittedLabel(file.omitted)}</div>;
226
+ }
227
+ return (
228
+ <Suspense fallback={<div className="px-3 py-2 text-xs text-text-faint">{t('work.loadingDiff')}</div>}>
229
+ <UnifiedDiff change={file} />
230
+ </Suspense>
231
+ );
232
+ }
233
+
234
+ /* The frame of a changed files card: a header that folds the list of files away. */
235
+ function ChangedFilesCard({
236
+ count,
237
+ truncated,
238
+ added,
239
+ deleted,
240
+ revealNonce = 0,
241
+ children
242
+ }: {
243
+ count: number;
244
+ truncated?: boolean;
245
+ added?: number;
246
+ deleted?: number;
247
+ /* A jump from outside the chat that asked for this card; each new one opens it. */
248
+ revealNonce?: number;
249
+ children: React.ReactNode;
250
+ }) {
251
+ const { t } = useTranslation('agent-chat');
252
+ const [expanded, setExpanded] = useState(false);
253
+ // A jump from outside opens the card, also when the jump put the row on screen and so mounted it; the flash is gone by the time the row is scrolled to again.
254
+ const [seenReveal, setSeenReveal] = useState(0);
255
+ if (revealNonce > 0 && revealNonce !== seenReveal) {
256
+ setSeenReveal(revealNonce);
257
+ setExpanded(true);
258
+ }
259
+ return (
260
+ <div className="mb-3 overflow-hidden rounded-lg border border-border bg-surface-raised">
261
+ <button
262
+ className="flex w-full items-center gap-2 px-3 py-2 text-left text-xs text-text-muted hover:bg-surface-hover"
263
+ aria-expanded={expanded}
264
+ onClick={() => setExpanded((value) => !value)}
265
+ >
266
+ <Icon icon={FileDiff} size={12} className="shrink-0" />
267
+ <span className="shrink-0 font-medium text-text">{t('work.changedFiles', { count })}</span>
268
+ {truncated && <span className="min-w-0 truncate text-text-faint">{t('work.andMore')}</span>}
269
+ <span className="grow" />
270
+ {added !== undefined && <span className="text-chat-added tabular-nums">+{added}</span>}
271
+ {deleted !== undefined && <span className="text-chat-removed tabular-nums">-{deleted}</span>}
272
+ <Icon icon={ChevronRight} size={12} className={clsx('shrink-0 text-text-faint transition-transform', expanded && 'rotate-90')} />
273
+ </button>
274
+ {expanded && children}
275
+ </div>
276
+ );
277
+ }
278
+
279
+ /*
280
+ * The files a settled turn changed, as a card; each file opens its diff in place. The host's
281
+ * checkpoint diff comes first (the working tree against the tree the turn started from), then the
282
+ * unified diffs the CLI reported, then the before and after of its own edits. A turn that has a
283
+ * checkpoint but no stored diff asks the host for one, which is also how a running turn gets it.
284
+ */
285
+ export function ChangedFilesRow({
286
+ tools,
287
+ diff,
288
+ checkpoint,
289
+ chatId,
290
+ turnId
291
+ }: {
292
+ tools: ChatToolItem[];
293
+ diff: ChatCheckpointDiff | null;
294
+ checkpoint: boolean;
295
+ chatId: string;
296
+ turnId: string;
297
+ }) {
298
+ const [open, setOpen] = useState<Record<string, boolean>>({});
299
+ const [fetched, setFetched] = useState<ChatCheckpointDiff | null>(null);
300
+ const actions = useChatActions();
301
+ useEffect(() => {
302
+ if (diff !== null || !checkpoint) {
303
+ return;
304
+ }
305
+ let alive = true;
306
+ void actions
307
+ .turnDiff(chatId, turnId)
308
+ .then((answer) => {
309
+ if (alive) {
310
+ setFetched(answer);
311
+ }
312
+ })
313
+ .catch(() => undefined);
314
+ return () => {
315
+ alive = false;
316
+ };
317
+ }, [actions, chatId, turnId, diff, checkpoint]);
318
+ const checkpointDiff = diff ?? fetched;
319
+ const { keyOf } = useChatScope();
320
+ const flash = useTimelineFlash((s) => s.target);
321
+ const revealNonce = flash !== null && flash.opens && flash.key === keyOf(chatId) && flash.rowId === `files-${turnId}` ? flash.nonce : 0;
322
+ if (checkpointDiff !== null && checkpointDiff.files.length > 0) {
323
+ const files = checkpointDiff.files;
324
+ return (
325
+ <ChangedFilesCard
326
+ revealNonce={revealNonce}
327
+ count={files.length}
328
+ truncated={checkpointDiff.truncated}
329
+ added={files.reduce((sum, file) => sum + file.added, 0)}
330
+ deleted={files.reduce((sum, file) => sum + file.deleted, 0)}
331
+ >
332
+ {files.map((file) => (
333
+ <div key={file.path} className="border-t border-border">
334
+ <button
335
+ className="flex w-full items-center gap-2 px-3 py-1.5 text-left text-xs text-text-muted hover:bg-surface-hover"
336
+ data-file-path={file.path}
337
+ onClick={() => setOpen((o) => ({ ...o, [file.path]: !o[file.path] }))}
338
+ >
339
+ <Icon
340
+ icon={ChevronRight}
341
+ size={12}
342
+ className={clsx('shrink-0 text-text-faint transition-transform', open[file.path] && 'rotate-90')}
343
+ />
344
+ <span className="min-w-0 truncate font-mono text-text">{file.path}</span>
345
+ <span className="grow" />
346
+ <span className="text-chat-added tabular-nums">+{file.added}</span>
347
+ <span className="text-chat-removed tabular-nums">-{file.deleted}</span>
348
+ </button>
349
+ {open[file.path] && (
350
+ <div className="border-t border-border">
351
+ <CheckpointFileBody file={file} />
352
+ </div>
353
+ )}
354
+ </div>
355
+ ))}
356
+ </ChangedFilesCard>
357
+ );
358
+ }
359
+ return <ProviderChangedFiles tools={tools} open={open} setOpen={setOpen} revealNonce={revealNonce} />;
360
+ }
361
+
362
+ /* The fallback card, built from what the CLI itself reported about its edits. */
363
+ function ProviderChangedFiles({
364
+ tools,
365
+ open,
366
+ setOpen,
367
+ revealNonce
368
+ }: {
369
+ tools: ChatToolItem[];
370
+ open: Record<string, boolean>;
371
+ revealNonce: number;
372
+ setOpen: React.Dispatch<React.SetStateAction<Record<string, boolean>>>;
373
+ }) {
374
+ const { t } = useTranslation('agent-chat');
375
+ const byPath = new Map<string, { edits: FileChange[]; patches: ChatFileChange[] }>();
376
+ const entryFor = (path: string) => {
377
+ const existing = byPath.get(path);
378
+ if (existing) {
379
+ return existing;
380
+ }
381
+ const created = { edits: [] as FileChange[], patches: [] as ChatFileChange[] };
382
+ byPath.set(path, created);
383
+ return created;
384
+ };
385
+ for (const tool of tools) {
386
+ const patches = unifiedChanges(tool);
387
+ if (patches.length > 0) {
388
+ for (const patch of patches) {
389
+ entryFor(patch.path).patches.push(patch);
390
+ }
391
+ continue;
392
+ }
393
+ for (const change of fileChanges(tool.name, tool.input)) {
394
+ entryFor(change.path || tool.id).edits.push(change);
395
+ }
396
+ }
397
+ return (
398
+ <ChangedFilesCard count={byPath.size} revealNonce={revealNonce}>
399
+ {[...byPath].map(([path, entry]) => {
400
+ const count = entry.edits.length + entry.patches.length;
401
+ return (
402
+ <div key={path} className="border-t border-border">
403
+ <button
404
+ className="flex w-full items-center gap-2 px-3 py-1.5 text-left text-xs text-text-muted hover:bg-surface-hover"
405
+ data-file-path={path}
406
+ onClick={() => setOpen((o) => ({ ...o, [path]: !o[path] }))}
407
+ >
408
+ <Icon icon={ChevronRight} size={12} className={clsx('shrink-0 text-text-faint transition-transform', open[path] && 'rotate-90')} />
409
+ <span className="min-w-0 truncate font-mono text-text">{path}</span>
410
+ <span className="grow" />
411
+ <span className="text-text-faint">{t('work.edits', { count })}</span>
412
+ </button>
413
+ {open[path] && (
414
+ <div className="border-t border-border">
415
+ <Suspense fallback={<div className="px-3 py-2 text-xs text-text-faint">{t('work.loadingDiff')}</div>}>
416
+ {entry.patches.map((change, index) => (
417
+ <UnifiedDiff key={`patch-${index}`} change={change} />
418
+ ))}
419
+ {entry.edits.map((change, index) => (
420
+ <EditDiff key={`edit-${index}`} change={change} />
421
+ ))}
422
+ </Suspense>
423
+ </div>
424
+ )}
425
+ </div>
426
+ );
427
+ })}
428
+ </ChangedFilesCard>
429
+ );
430
+ }
431
+
432
+ /* "Working for 00:14". */
433
+ export function WorkingRow({ startedAt }: { startedAt: number }) {
434
+ const { t } = useTranslation('agent-chat');
435
+ const ref = useTickingText(() => formatClockDuration(Date.now() - startedAt));
436
+ return (
437
+ <div className="-mx-1 mb-0.5 flex h-7 items-center gap-2 px-1 text-xs text-text-muted">
438
+ <span className={`${ROW_GUTTER} text-status-running`}>
439
+ <Spinner size={12} />
440
+ </span>
441
+ <span className="chat-live-text">{t('work.workingFor')}</span>
442
+ <span ref={ref} className="tabular-nums" />
443
+ </div>
444
+ );
445
+ }
@@ -0,0 +1,120 @@
1
+ import { useTranslation } from 'react-i18next';
2
+ import { Bot, ListTree, TriangleAlert, Square } from 'lucide-react';
3
+ import { workflowAgentRef, type ChatToolItem, type ChatWorkflow } from '@adecore/agent-contracts';
4
+ import { workflowAgentTime, workflowPhases, type WorkflowAgentView, type WorkflowPhaseView } from '../../logic/workflow';
5
+ import { useSubagentSupport } from '../../subagent-support';
6
+ import type { SubagentStep } from '../../subagent-view';
7
+ import { ROW_GUTTER } from '../icons';
8
+ import { RunningFor, ToggleLine, WorkLiveRow, WorkRow } from './WorkRows';
9
+ import { useChatScope } from '../../../scope';
10
+ import { Icon, IconButton } from '@adecore/ui';
11
+ import { useChatActions } from '../../actions';
12
+ import { chatHost } from '../../../host';
13
+
14
+ function AgentLine({ view, onOpen }: { view: WorkflowAgentView; onOpen?(step: SubagentStep): void }) {
15
+ const { agent, state } = view;
16
+ const time = workflowAgentTime(view);
17
+ const running = state === 'running';
18
+ const agentId = agent.agentId;
19
+ // One still waiting has no transcript yet.
20
+ const open = onOpen !== undefined && agentId !== null ? () => onOpen({ toolUseId: workflowAgentRef(agentId), description: agent.label }) : () => undefined;
21
+ return (
22
+ <ToggleLine
23
+ icon={<Icon icon={Bot} size={12} />}
24
+ label={agent.label}
25
+ detail={running ? (agent.lastTool ?? undefined) : undefined}
26
+ open={false}
27
+ onToggle={open}
28
+ failed={state === 'failed'}
29
+ live={running}
30
+ trailing={
31
+ running && agent.startedAt !== null ? (
32
+ <RunningFor startedAt={agent.startedAt} />
33
+ ) : (
34
+ <span className="shrink-0 text-xs text-text-faint tabular-nums">{time}</span>
35
+ )
36
+ }
37
+ />
38
+ );
39
+ }
40
+
41
+ function PhaseBlock({ phase, onOpen }: { phase: WorkflowPhaseView; onOpen?(step: SubagentStep): void }) {
42
+ const { t } = useTranslation('agent-chat');
43
+ return (
44
+ <div>
45
+ {phase.title !== null && (
46
+ <div className="mb-0.5 flex h-7 min-w-0 items-center gap-2 text-xs text-text-muted">
47
+ <span className={ROW_GUTTER}>
48
+ <Icon icon={ListTree} size={12} />
49
+ </span>
50
+ <span className="min-w-0 truncate">{phase.title}</span>
51
+ <span className="grow" />
52
+ {phase.agents.length === 0 && <span className="shrink-0 text-text-faint">{t('rows.workflow.notStarted')}</span>}
53
+ </div>
54
+ )}
55
+ {phase.agents.length > 0 && (
56
+ <div className={phase.title === null ? undefined : 'ml-6'}>
57
+ {phase.agents.map((view) => (
58
+ <AgentLine key={view.agent.index} view={view} onOpen={onOpen} />
59
+ ))}
60
+ </div>
61
+ )}
62
+ </div>
63
+ );
64
+ }
65
+
66
+ // Keep background progress visible after the launcher turn ends.
67
+ export function WorkflowRow({
68
+ tool,
69
+ workflow,
70
+ chatId,
71
+ onOpenAgent
72
+ }: {
73
+ tool: ChatToolItem;
74
+ workflow: ChatWorkflow;
75
+ chatId?: string;
76
+ onOpenAgent?(step: SubagentStep): void;
77
+ }) {
78
+ const { t } = useTranslation('agent-chat');
79
+ const { id } = useChatScope();
80
+ // A host that does not answer `chat.subagent` has no conversation to open for anyone.
81
+ const refused = useSubagentSupport((s) => s.unsupported[id] === true);
82
+ const running = tool.state === 'running';
83
+ const phases = workflowPhases(workflow, running);
84
+ const onOpen = refused ? undefined : onOpenAgent;
85
+ const actions = useChatActions();
86
+ const stop = (): void => {
87
+ if (chatId && workflow.taskId) {
88
+ void actions.stopTask(chatId, workflow.taskId).catch((error: unknown) => {
89
+ chatHost().notify({
90
+ kind: 'error',
91
+ title: t('activity.stopFailed'),
92
+ description: error instanceof Error ? error.message : t('subagents.noAnswer')
93
+ });
94
+ });
95
+ }
96
+ };
97
+ return (
98
+ <div>
99
+ <div className="flex items-center gap-1">
100
+ <div className="min-w-0 grow">
101
+ {running ? <WorkLiveRow chatId={chatId ?? ''} tool={tool} /> : <WorkRow tool={tool} detail={workflow.name ?? undefined} />}
102
+ </div>
103
+ {running && chatId && workflow.taskId && <IconButton icon={Square} size="xs" label={t('activity.stop')} onClick={stop} />}
104
+ </div>
105
+ {running && workflow.stalledAt !== undefined && (
106
+ <p role="status" className="ml-6 mb-1 flex items-start gap-1.5 text-xs text-text-muted">
107
+ <Icon icon={TriangleAlert} size={12} className="mt-0.5 shrink-0 text-status-needs-you" />
108
+ <span>{t('rows.workflow.stalled')}</span>
109
+ </p>
110
+ )}
111
+ {phases.length > 0 && (
112
+ <div className="ml-6">
113
+ {phases.map((phase) => (
114
+ <PhaseBlock key={phase.key} phase={phase} onOpen={onOpen} />
115
+ ))}
116
+ </div>
117
+ )}
118
+ </div>
119
+ );
120
+ }
@@ -0,0 +1,37 @@
1
+ import clsx from 'clsx';
2
+ import { isBlock, type TimelineRow } from '../../logic/timeline';
3
+
4
+ /* Below this distance from the bottom a thread follows what the agent writes; above it the reader scrolled back on purpose. */
5
+ export const FOLLOW_THRESHOLD_PX = 40;
6
+
7
+ /*
8
+ * The gaps a row wears for where it sits: a question is followed by its answer gap, and a seam where
9
+ * the list rhythm of tool lines meets the block rhythm of prose gets the block gap. A question
10
+ * already carries the gap before it, and the row after one is the answer, so neither takes a seam.
11
+ */
12
+ export function rowRhythm(row: TimelineRow, previous: TimelineRow | null): string {
13
+ const question = row.kind === 'user';
14
+ const seam = !question && previous !== null && previous.kind !== 'user' && isBlock(row) !== isBlock(previous);
15
+ return clsx(question && 'pb-(--chat-answer-gap)', seam && 'pt-(--chat-block-gap)');
16
+ }
17
+
18
+ /*
19
+ * Whether a reply's header goes over this row, and the time it shows: the first row after the question
20
+ * or the agent's own turn opener, whatever row that is, dated when that turn began. A thread that
21
+ * starts halfway through a reply has no time to show.
22
+ */
23
+ export function replyHeader(row: TimelineRow, previous: TimelineRow | null): { at: number | null } | null {
24
+ if (row.kind === 'user' || row.kind === 'turn-start') {
25
+ return null;
26
+ }
27
+ if (previous === null) {
28
+ return { at: null };
29
+ }
30
+ if (previous.kind === 'user') {
31
+ return { at: previous.item.createdAt };
32
+ }
33
+ if (previous.kind === 'turn-start') {
34
+ return { at: previous.turn.createdAt };
35
+ }
36
+ return null;
37
+ }
@@ -0,0 +1,39 @@
1
+ import { useCallback, useState } from 'react';
2
+
3
+ export interface ToggleSet {
4
+ ids: ReadonlySet<string>;
5
+ /* Opens what is closed and closes what is open, and tells `onToggle` a person did it. */
6
+ toggle(id: string): void;
7
+ /* Opens one without saying a person asked, for a jump that opens what it lands on. */
8
+ add(id: string): void;
9
+ }
10
+
11
+ /*
12
+ * The ids of the folds a thread has open. `onToggle` is what a thread does about a person opening
13
+ * one, which is to stop following the end: a fold is a deliberate look back, not a reason to jump.
14
+ */
15
+ export function useToggleSet(onToggle?: () => void): ToggleSet {
16
+ const [ids, setIds] = useState<ReadonlySet<string>>(() => new Set());
17
+
18
+ const toggle = useCallback(
19
+ (id: string): void => {
20
+ setIds((current) => {
21
+ const next = new Set(current);
22
+ if (next.has(id)) {
23
+ next.delete(id);
24
+ } else {
25
+ next.add(id);
26
+ }
27
+ return next;
28
+ });
29
+ onToggle?.();
30
+ },
31
+ [onToggle]
32
+ );
33
+
34
+ const add = useCallback((id: string): void => {
35
+ setIds((current) => new Set(current).add(id));
36
+ }, []);
37
+
38
+ return { ids, toggle, add };
39
+ }