@adecore/agents-react 0.31.12 → 0.33.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 (409) hide show
  1. package/README.md +1 -1
  2. package/dist/agents/AccountDot.js +57 -6
  3. package/dist/agents/AgentIcon.js +88 -12
  4. package/dist/agents/ModelOptionControl.js +153 -18
  5. package/dist/agents/ProviderLogo.js +49 -4
  6. package/dist/agents/account-limits.js +17 -14
  7. package/dist/agents/accounts.js +99 -67
  8. package/dist/agents/agent-marks.js +5 -3
  9. package/dist/agents/model-name.js +42 -31
  10. package/dist/agents/model-options.js +8 -8
  11. package/dist/agents/model-requirement.js +17 -14
  12. package/dist/agents/option-words.d.ts +7 -0
  13. package/dist/agents/option-words.js +35 -0
  14. package/dist/agents/provider-paths.js +6 -6
  15. package/dist/agents/status-look.js +32 -12
  16. package/dist/chat/account-choice.d.ts +13 -0
  17. package/dist/chat/account-choice.js +90 -20
  18. package/dist/chat/actions.js +126 -59
  19. package/dist/chat/activity.js +5 -5
  20. package/dist/chat/attachments.js +74 -53
  21. package/dist/chat/bookmarks.js +58 -48
  22. package/dist/chat/chat-client.js +344 -263
  23. package/dist/chat/chat-references.js +3 -3
  24. package/dist/chat/composer-effort.d.ts +5 -0
  25. package/dist/chat/composer-effort.js +26 -0
  26. package/dist/chat/composer-send.js +13 -13
  27. package/dist/chat/drafts.js +115 -79
  28. package/dist/chat/forks.js +81 -24
  29. package/dist/chat/guards.js +15 -43
  30. package/dist/chat/index.d.ts +3 -1
  31. package/dist/chat/index.js +3 -2
  32. package/dist/chat/logic/ansi.js +170 -167
  33. package/dist/chat/logic/answers.js +2 -2
  34. package/dist/chat/logic/bookmarks.js +19 -19
  35. package/dist/chat/logic/command-looks.js +138 -96
  36. package/dist/chat/logic/context-usage.js +13 -9
  37. package/dist/chat/logic/continue-after-stop.js +15 -19
  38. package/dist/chat/logic/effort.d.ts +14 -0
  39. package/dist/chat/logic/effort.js +34 -0
  40. package/dist/chat/logic/embedded-code.js +387 -326
  41. package/dist/chat/logic/fork.js +134 -110
  42. package/dist/chat/logic/generated-image.js +54 -23
  43. package/dist/chat/logic/goal.js +28 -20
  44. package/dist/chat/logic/handback.js +6 -6
  45. package/dist/chat/logic/json.js +2 -2
  46. package/dist/chat/logic/limit.js +46 -30
  47. package/dist/chat/logic/picker-entries.d.ts +5 -3
  48. package/dist/chat/logic/picker-entries.js +83 -43
  49. package/dist/chat/logic/resume-compaction.d.ts +14 -1
  50. package/dist/chat/logic/resume-compaction.js +93 -24
  51. package/dist/chat/logic/scrubber.js +188 -136
  52. package/dist/chat/logic/thought.js +13 -16
  53. package/dist/chat/logic/thread-cards.js +60 -48
  54. package/dist/chat/logic/timeline-copy.js +30 -38
  55. package/dist/chat/logic/timeline-target.js +92 -63
  56. package/dist/chat/logic/timeline.js +499 -355
  57. package/dist/chat/logic/tool-catalog.js +54 -34
  58. package/dist/chat/logic/tools.js +106 -82
  59. package/dist/chat/logic/visual-height.js +18 -18
  60. package/dist/chat/logic/visual-viewport.js +6 -3
  61. package/dist/chat/logic/welcome.js +9 -9
  62. package/dist/chat/logic/workflow.d.ts +10 -0
  63. package/dist/chat/logic/workflow.js +130 -32
  64. package/dist/chat/mentions.js +149 -109
  65. package/dist/chat/persisted-json.js +51 -54
  66. package/dist/chat/preferences.d.ts +4 -0
  67. package/dist/chat/preferences.js +162 -84
  68. package/dist/chat/prompt-hold.js +9 -9
  69. package/dist/chat/quote.js +21 -30
  70. package/dist/chat/reading-width.js +12 -10
  71. package/dist/chat/recent-messages.js +34 -21
  72. package/dist/chat/resume-compaction-dismissals.js +25 -5
  73. package/dist/chat/runtime-modes.js +3 -3
  74. package/dist/chat/send-key.js +11 -7
  75. package/dist/chat/stash.js +89 -69
  76. package/dist/chat/subagent-conversation.js +181 -139
  77. package/dist/chat/subagent-list.js +65 -67
  78. package/dist/chat/subagent-support.js +12 -7
  79. package/dist/chat/subagent-view.js +132 -44
  80. package/dist/chat/thumbnails.js +88 -60
  81. package/dist/chat/timeline-flash.js +24 -12
  82. package/dist/chat/timeline-scroll.js +116 -86
  83. package/dist/chat/ui/AccountPill.js +126 -15
  84. package/dist/chat/ui/AnsiOutput.js +62 -6
  85. package/dist/chat/ui/BookmarkMarker.js +231 -41
  86. package/dist/chat/ui/BookmarkSubmenu.js +165 -18
  87. package/dist/chat/ui/ChatActivity.js +649 -70
  88. package/dist/chat/ui/ChatReferenceChip.js +104 -9
  89. package/dist/chat/ui/CodeBlock.js +132 -58
  90. package/dist/chat/ui/Composer.js +866 -132
  91. package/dist/chat/ui/ComposerInput.js +309 -120
  92. package/dist/chat/ui/DiffPool.js +75 -14
  93. package/dist/chat/ui/EditDiff.js +160 -21
  94. package/dist/chat/ui/FadingWords.js +32 -3
  95. package/dist/chat/ui/GoalDock.js +235 -42
  96. package/dist/chat/ui/ImageView.js +617 -61
  97. package/dist/chat/ui/LimitState.js +446 -72
  98. package/dist/chat/ui/Markdown.js +991 -173
  99. package/dist/chat/ui/MermaidBlock.js +285 -79
  100. package/dist/chat/ui/MessageActions.js +251 -39
  101. package/dist/chat/ui/ModelMarks.js +55 -5
  102. package/dist/chat/ui/Pickers.js +664 -113
  103. package/dist/chat/ui/PromptComposer.js +281 -51
  104. package/dist/chat/ui/QuoteButton.js +151 -57
  105. package/dist/chat/ui/ResumeCompactionDock.d.ts +6 -2
  106. package/dist/chat/ui/ResumeCompactionDock.js +141 -6
  107. package/dist/chat/ui/RowTime.js +59 -5
  108. package/dist/chat/ui/RunSettings.js +1744 -154
  109. package/dist/chat/ui/Scrubber.js +517 -88
  110. package/dist/chat/ui/ShellCommand.js +183 -107
  111. package/dist/chat/ui/SubagentControls.js +212 -24
  112. package/dist/chat/ui/SubagentInfo.js +170 -13
  113. package/dist/chat/ui/SubagentStopButton.js +115 -24
  114. package/dist/chat/ui/SubagentTimeline.js +357 -91
  115. package/dist/chat/ui/Timeline.js +988 -476
  116. package/dist/chat/ui/TimelineMenu.js +552 -37
  117. package/dist/chat/ui/UnifiedDiff.js +234 -27
  118. package/dist/chat/ui/UploadThumb.js +37 -7
  119. package/dist/chat/ui/VisualDialogs.js +251 -20
  120. package/dist/chat/ui/VisualFrame.js +321 -95
  121. package/dist/chat/ui/Welcome.js +72 -7
  122. package/dist/chat/ui/chips.js +1 -1
  123. package/dist/chat/ui/code-lines.js +36 -36
  124. package/dist/chat/ui/code-streaming.js +1 -1
  125. package/dist/chat/ui/code-theme.js +7 -7
  126. package/dist/chat/ui/composer/ComposerControls.js +329 -21
  127. package/dist/chat/ui/composer/ComposerMenu.js +358 -30
  128. package/dist/chat/ui/composer/DraftParts.js +185 -11
  129. package/dist/chat/ui/composer/QueuedMessages.js +138 -13
  130. package/dist/chat/ui/composer/chips.js +29 -19
  131. package/dist/chat/ui/composer/editor.js +79 -63
  132. package/dist/chat/ui/composer/insert.js +26 -12
  133. package/dist/chat/ui/composer/key-handler.js +180 -127
  134. package/dist/chat/ui/composer/keys.js +90 -73
  135. package/dist/chat/ui/composer/menu-aria.js +18 -9
  136. package/dist/chat/ui/composer/placeholder.js +78 -31
  137. package/dist/chat/ui/composer/surface.js +13 -37
  138. package/dist/chat/ui/composer/use-chat-controls.js +230 -90
  139. package/dist/chat/ui/composer/use-compaction-offer.js +50 -18
  140. package/dist/chat/ui/composer/use-composer-draft.js +65 -34
  141. package/dist/chat/ui/composer/use-composer-menus.js +478 -193
  142. package/dist/chat/ui/composer/use-composer-submit.js +251 -109
  143. package/dist/chat/ui/composer/use-continuable-turn.js +33 -6
  144. package/dist/chat/ui/composer/use-draft-files.js +245 -93
  145. package/dist/chat/ui/composer/use-effort-stepper.d.ts +13 -0
  146. package/dist/chat/ui/composer/use-effort-stepper.js +88 -0
  147. package/dist/chat/ui/composer/use-notice.js +61 -16
  148. package/dist/chat/ui/composer/use-pending-requests.js +38 -17
  149. package/dist/chat/ui/composer/use-prompt-history.js +117 -45
  150. package/dist/chat/ui/composer/use-prompt-hold.js +119 -35
  151. package/dist/chat/ui/composer/use-take-back.js +94 -72
  152. package/dist/chat/ui/diff/ApprovalReview.js +101 -23
  153. package/dist/chat/ui/diff/DiffFallbackBoundary.js +21 -13
  154. package/dist/chat/ui/diff/DiffOmitted.js +56 -6
  155. package/dist/chat/ui/diff/DiffStack.js +92 -8
  156. package/dist/chat/ui/diff/DiffUnavailable.js +56 -6
  157. package/dist/chat/ui/diff/EditorEditDiff.js +263 -51
  158. package/dist/chat/ui/diff/EditorPatchDiff.js +39 -14
  159. package/dist/chat/ui/diff/LegacyDiffPool.js +27 -10
  160. package/dist/chat/ui/diff/LegacyEditDiff.js +97 -20
  161. package/dist/chat/ui/diff/LegacyUnifiedDiff.js +172 -42
  162. package/dist/chat/ui/diff/RawDiff.js +65 -5
  163. package/dist/chat/ui/diff/ReviewDiff.js +77 -5
  164. package/dist/chat/ui/diff/diff-props.js +1 -1
  165. package/dist/chat/ui/diff/diff-source-budget.js +46 -35
  166. package/dist/chat/ui/diff/editor-edit-model.js +18 -14
  167. package/dist/chat/ui/diff/review-plan.js +63 -40
  168. package/dist/chat/ui/diff/review-settle.js +24 -9
  169. package/dist/chat/ui/diff/syntax-runtime.js +236 -201
  170. package/dist/chat/ui/diff/use-review-stack.js +146 -25
  171. package/dist/chat/ui/diff-syntax.js +70 -58
  172. package/dist/chat/ui/diff-theme.js +31 -12
  173. package/dist/chat/ui/file-links.js +39 -10
  174. package/dist/chat/ui/find-reveal.js +29 -8
  175. package/dist/chat/ui/full-diff.js +17 -12
  176. package/dist/chat/ui/highlighter.js +143 -113
  177. package/dist/chat/ui/icons.js +16 -7
  178. package/dist/chat/ui/index.js +1 -1
  179. package/dist/chat/ui/intelligent-ui/UiBlockFrame.js +556 -82
  180. package/dist/chat/ui/intelligent-ui/UiFallbackPart.js +73 -5
  181. package/dist/chat/ui/intelligent-ui/UiReply.js +666 -262
  182. package/dist/chat/ui/intelligent-ui/block-local.js +59 -31
  183. package/dist/chat/ui/intelligent-ui/chart-data.js +77 -67
  184. package/dist/chat/ui/intelligent-ui/node-text.js +77 -91
  185. package/dist/chat/ui/intelligent-ui/registry.js +46 -46
  186. package/dist/chat/ui/intelligent-ui/render-context.js +1 -1
  187. package/dist/chat/ui/intelligent-ui/renderers/base-land.js +1 -1
  188. package/dist/chat/ui/intelligent-ui/renderers/binding.js +3 -3
  189. package/dist/chat/ui/intelligent-ui/renderers/chart.js +1223 -123
  190. package/dist/chat/ui/intelligent-ui/renderers/choices.js +312 -34
  191. package/dist/chat/ui/intelligent-ui/renderers/content.js +1241 -86
  192. package/dist/chat/ui/intelligent-ui/renderers/data.js +619 -54
  193. package/dist/chat/ui/intelligent-ui/renderers/inputs.js +868 -67
  194. package/dist/chat/ui/intelligent-ui/renderers/links.js +366 -62
  195. package/dist/chat/ui/intelligent-ui/renderers/map-slots.js +118 -60
  196. package/dist/chat/ui/intelligent-ui/renderers/map-style.js +85 -78
  197. package/dist/chat/ui/intelligent-ui/renderers/map-view.js +282 -217
  198. package/dist/chat/ui/intelligent-ui/renderers/map.js +621 -69
  199. package/dist/chat/ui/intelligent-ui/renderers/place-point.js +15 -8
  200. package/dist/chat/ui/intelligent-ui/renderers/structure.js +262 -20
  201. package/dist/chat/ui/intelligent-ui/renderers/text.js +674 -49
  202. package/dist/chat/ui/intelligent-ui/reply-parts.js +24 -15
  203. package/dist/chat/ui/intelligent-ui/table-data.js +97 -57
  204. package/dist/chat/ui/intelligent-ui/tones.js +31 -31
  205. package/dist/chat/ui/intelligent-ui/use-in-view.js +30 -12
  206. package/dist/chat/ui/intelligent-ui/use-later.js +28 -13
  207. package/dist/chat/ui/intelligent-ui/use-truncated.js +45 -21
  208. package/dist/chat/ui/intelligent-ui/use-ui-links.js +296 -109
  209. package/dist/chat/ui/intelligent-ui/use-ui-queries.js +256 -246
  210. package/dist/chat/ui/markdown-blocks.js +296 -262
  211. package/dist/chat/ui/mermaid.d.ts +8 -20
  212. package/dist/chat/ui/mermaid.js +47 -84
  213. package/dist/chat/ui/quote-selection.js +32 -29
  214. package/dist/chat/ui/rehype-chips.js +35 -23
  215. package/dist/chat/ui/rehype-fade.js +28 -17
  216. package/dist/chat/ui/remark-html-as-text.js +22 -15
  217. package/dist/chat/ui/reply-context.js +1 -1
  218. package/dist/chat/ui/reveal.js +161 -72
  219. package/dist/chat/ui/rows/ForksRow.js +226 -24
  220. package/dist/chat/ui/rows/GeneratedImageRow.js +541 -87
  221. package/dist/chat/ui/rows/MessageRows.js +1706 -159
  222. package/dist/chat/ui/rows/RowContainer.js +57 -7
  223. package/dist/chat/ui/rows/Rows.js +463 -54
  224. package/dist/chat/ui/rows/SubagentRow.js +577 -60
  225. package/dist/chat/ui/rows/TaskRow.js +359 -40
  226. package/dist/chat/ui/rows/VisualRow.js +233 -11
  227. package/dist/chat/ui/rows/WorkRows.d.ts +3 -0
  228. package/dist/chat/ui/rows/WorkRows.js +1945 -164
  229. package/dist/chat/ui/rows/WorkflowRow.js +756 -37
  230. package/dist/chat/ui/rows/row-rhythm.js +27 -17
  231. package/dist/chat/ui/theme-watch.js +26 -23
  232. package/dist/chat/ui/timestamp-format.js +4 -1
  233. package/dist/chat/ui/use-diff-source-tokens.js +70 -34
  234. package/dist/chat/ui/useToggleSet.js +51 -19
  235. package/dist/chat/ui/visual-theme.js +153 -128
  236. package/dist/chat/visual-bridge.js +123 -123
  237. package/dist/chat/visual-viewport.js +94 -83
  238. package/dist/chat/visuals.js +13 -5
  239. package/dist/host-hooks.d.ts +29 -0
  240. package/dist/host-hooks.js +78 -0
  241. package/dist/host.js +120 -48
  242. package/dist/index.js +1 -1
  243. package/dist/lazy.js +38 -32
  244. package/dist/locales/en/agent-chat.d.ts +42 -0
  245. package/dist/locales/en/agent-chat.js +755 -713
  246. package/dist/locales/en/agent-prompts.js +42 -42
  247. package/dist/locales/en/agent-providers.d.ts +1 -0
  248. package/dist/locales/en/agent-providers.js +166 -165
  249. package/dist/locales/en/agent-usage.d.ts +6 -0
  250. package/dist/locales/en/agent-usage.js +129 -123
  251. package/dist/locales/nl/agent-chat.d.ts +42 -0
  252. package/dist/locales/nl/agent-chat.js +755 -713
  253. package/dist/locales/nl/agent-prompts.js +42 -42
  254. package/dist/locales/nl/agent-providers.d.ts +1 -0
  255. package/dist/locales/nl/agent-providers.js +166 -165
  256. package/dist/locales/nl/agent-usage.d.ts +6 -0
  257. package/dist/locales/nl/agent-usage.js +129 -123
  258. package/dist/locales.js +14 -14
  259. package/dist/mounted-registry.js +31 -30
  260. package/dist/port-transport.js +122 -111
  261. package/dist/prompts/index.js +1 -1
  262. package/dist/prompts/logic/focus.js +15 -14
  263. package/dist/prompts/logic/keys.js +93 -59
  264. package/dist/prompts/logic/prompts.js +27 -14
  265. package/dist/prompts/logic/subjects.js +60 -46
  266. package/dist/prompts/logic/useFocusAfterAnswer.js +60 -20
  267. package/dist/prompts/logic/usePromptSession.js +88 -77
  268. package/dist/prompts/ui/ApprovalBody.js +246 -27
  269. package/dist/prompts/ui/PromptActions.js +215 -9
  270. package/dist/prompts/ui/PromptCard.js +215 -36
  271. package/dist/prompts/ui/PromptView.js +372 -34
  272. package/dist/prompts/ui/QuestionBody.js +269 -73
  273. package/dist/providers/AccountColors.js +36 -5
  274. package/dist/providers/AccountDetail.js +683 -50
  275. package/dist/providers/AccountVariables.js +139 -32
  276. package/dist/providers/AddAccountForm.js +125 -38
  277. package/dist/providers/CliDetail.js +343 -36
  278. package/dist/providers/InstallPage.js +644 -59
  279. package/dist/providers/ProviderList.d.ts +2 -1
  280. package/dist/providers/ProviderList.js +215 -23
  281. package/dist/providers/ProvidersPane.d.ts +4 -2
  282. package/dist/providers/ProvidersPane.js +244 -64
  283. package/dist/providers/account-actions.js +54 -30
  284. package/dist/providers/index.js +1 -1
  285. package/dist/providers/install-steps.js +12 -9
  286. package/dist/providers/pane-target.d.ts +3 -0
  287. package/dist/providers/pane-target.js +34 -13
  288. package/dist/providers/parts.js +62 -12
  289. package/dist/providers/provider-abilities.js +5 -5
  290. package/dist/providers/provider-groups.js +75 -40
  291. package/dist/providers/variables.js +73 -39
  292. package/dist/scope.js +6 -6
  293. package/dist/settings/sections.js +18 -18
  294. package/dist/state/chats.js +404 -192
  295. package/dist/state/index.js +1 -1
  296. package/dist/state/provider-accounts.js +70 -47
  297. package/dist/state/providers.js +45 -16
  298. package/dist/state/usage.js +154 -77
  299. package/dist/storage.js +69 -68
  300. package/dist/testing/index.js +1 -1
  301. package/dist/testing/prompts.js +105 -67
  302. package/dist/transport.js +10 -10
  303. package/dist/ui/PlainTextarea.js +27 -3
  304. package/dist/usage/LimitsList.js +646 -40
  305. package/dist/usage/UsageBreakdown.js +879 -38
  306. package/dist/usage/UsageChart.js +311 -32
  307. package/dist/usage/UsageDialog.js +46 -4
  308. package/dist/usage/UsageLimits.js +467 -34
  309. package/dist/usage/UsageLimitsCard.js +95 -11
  310. package/dist/usage/UsagePage.js +817 -96
  311. package/dist/usage/UsagePane.js +164 -10
  312. package/dist/usage/UsageSummary.js +151 -6
  313. package/dist/usage/UsageTiles.js +164 -14
  314. package/dist/usage/format.js +32 -32
  315. package/dist/usage/index.d.ts +1 -1
  316. package/dist/usage/index.js +2 -1
  317. package/dist/usage/limit-groups.d.ts +2 -0
  318. package/dist/usage/limit-groups.js +77 -59
  319. package/dist/usage/limits.js +78 -43
  320. package/dist/usage/money.js +20 -4
  321. package/dist/usage/summary.js +85 -64
  322. package/package.json +9 -9
  323. package/src/agents/ModelOptionControl.tsx +3 -1
  324. package/src/agents/option-words.ts +27 -0
  325. package/src/chat/account-choice.ts +41 -1
  326. package/src/chat/composer-effort.ts +32 -0
  327. package/src/chat/forks.ts +4 -5
  328. package/src/chat/index.ts +3 -1
  329. package/src/chat/logic/effort.ts +32 -0
  330. package/src/chat/logic/picker-entries.ts +45 -10
  331. package/src/chat/logic/resume-compaction.ts +95 -17
  332. package/src/chat/logic/timeline.ts +11 -3
  333. package/src/chat/logic/workflow.ts +86 -4
  334. package/src/chat/preferences.ts +35 -0
  335. package/src/chat/subagent-view.ts +2 -3
  336. package/src/chat/ui/AnsiOutput.tsx +1 -2
  337. package/src/chat/ui/BookmarkSubmenu.tsx +3 -3
  338. package/src/chat/ui/ChatActivity.tsx +14 -22
  339. package/src/chat/ui/ChatReferenceChip.tsx +2 -3
  340. package/src/chat/ui/Composer.tsx +15 -7
  341. package/src/chat/ui/EditDiff.tsx +2 -3
  342. package/src/chat/ui/LimitState.tsx +2 -2
  343. package/src/chat/ui/Markdown.tsx +10 -8
  344. package/src/chat/ui/MermaidBlock.tsx +57 -49
  345. package/src/chat/ui/Pickers.tsx +49 -29
  346. package/src/chat/ui/PromptComposer.tsx +7 -9
  347. package/src/chat/ui/ResumeCompactionDock.tsx +16 -4
  348. package/src/chat/ui/RunSettings.tsx +67 -28
  349. package/src/chat/ui/Scrubber.tsx +3 -3
  350. package/src/chat/ui/ShellCommand.tsx +2 -0
  351. package/src/chat/ui/SubagentInfo.tsx +2 -3
  352. package/src/chat/ui/SubagentTimeline.tsx +12 -16
  353. package/src/chat/ui/Timeline.tsx +6 -6
  354. package/src/chat/ui/UnifiedDiff.tsx +3 -4
  355. package/src/chat/ui/VisualFrame.tsx +5 -8
  356. package/src/chat/ui/code-theme.ts +4 -4
  357. package/src/chat/ui/composer/placeholder.ts +2 -2
  358. package/src/chat/ui/composer/use-compaction-offer.ts +36 -16
  359. package/src/chat/ui/composer/use-composer-menus.ts +4 -9
  360. package/src/chat/ui/composer/use-composer-submit.ts +2 -1
  361. package/src/chat/ui/composer/use-effort-stepper.ts +56 -0
  362. package/src/chat/ui/composer/use-notice.ts +2 -2
  363. package/src/chat/ui/diff/EditorEditDiff.tsx +9 -13
  364. package/src/chat/ui/diff/LegacyEditDiff.tsx +12 -17
  365. package/src/chat/ui/diff/LegacyUnifiedDiff.tsx +13 -21
  366. package/src/chat/ui/diff/use-review-stack.ts +4 -4
  367. package/src/chat/ui/diff-theme.ts +3 -3
  368. package/src/chat/ui/file-links.ts +2 -2
  369. package/src/chat/ui/intelligent-ui/UiReply.tsx +2 -0
  370. package/src/chat/ui/intelligent-ui/renderers/chart.tsx +3 -3
  371. package/src/chat/ui/intelligent-ui/renderers/content.tsx +5 -6
  372. package/src/chat/ui/intelligent-ui/renderers/map-view.tsx +2 -1
  373. package/src/chat/ui/intelligent-ui/renderers/map.tsx +2 -1
  374. package/src/chat/ui/intelligent-ui/use-truncated.ts +16 -19
  375. package/src/chat/ui/intelligent-ui/use-ui-links.ts +3 -3
  376. package/src/chat/ui/mermaid.ts +52 -96
  377. package/src/chat/ui/rows/ForksRow.tsx +3 -5
  378. package/src/chat/ui/rows/GeneratedImageRow.tsx +2 -1
  379. package/src/chat/ui/rows/MessageRows.tsx +12 -21
  380. package/src/chat/ui/rows/SubagentRow.tsx +3 -3
  381. package/src/chat/ui/rows/TaskRow.tsx +1 -1
  382. package/src/chat/ui/rows/WorkRows.tsx +11 -6
  383. package/src/chat/ui/rows/WorkflowRow.tsx +144 -54
  384. package/src/chat/ui/useToggleSet.ts +15 -18
  385. package/src/chat/ui/visual-theme.ts +2 -3
  386. package/src/host-hooks.ts +113 -0
  387. package/src/lazy.tsx +2 -0
  388. package/src/locales/en/agent-chat.ts +142 -108
  389. package/src/locales/en/agent-prompts.ts +7 -7
  390. package/src/locales/en/agent-providers.ts +35 -34
  391. package/src/locales/en/agent-usage.ts +26 -20
  392. package/src/locales/nl/agent-chat.ts +134 -100
  393. package/src/locales/nl/agent-prompts.ts +5 -5
  394. package/src/locales/nl/agent-providers.ts +33 -32
  395. package/src/locales/nl/agent-usage.ts +25 -20
  396. package/src/providers/CliDetail.tsx +2 -1
  397. package/src/providers/InstallPage.tsx +2 -4
  398. package/src/providers/ProviderList.tsx +12 -2
  399. package/src/providers/ProvidersPane.tsx +45 -15
  400. package/src/providers/pane-target.ts +20 -4
  401. package/src/state/chats.ts +2 -2
  402. package/src/usage/LimitsList.tsx +12 -13
  403. package/src/usage/UsageBreakdown.tsx +17 -6
  404. package/src/usage/UsageLimits.tsx +2 -1
  405. package/src/usage/UsagePage.tsx +3 -3
  406. package/src/usage/index.ts +1 -1
  407. package/src/usage/limit-groups.ts +12 -0
  408. package/src/usage/limits.ts +2 -2
  409. package/src/usage/money.ts +1 -2
@@ -1,14 +1,14 @@
1
1
  import { Bot, Eye, FolderSearch, Globe, ListTodo, Search, SquarePen, Terminal, Workflow, Zap } from 'lucide-react';
2
2
  function entry(icon, summary, rest = {}) {
3
- return {
4
- icon,
5
- summary,
6
- grouped: true,
7
- changesFiles: false,
8
- readsImage: false,
9
- shell: false,
10
- ...rest
11
- };
3
+ return {
4
+ icon,
5
+ summary,
6
+ grouped: true,
7
+ changesFiles: false,
8
+ readsImage: false,
9
+ shell: false,
10
+ ...rest
11
+ };
12
12
  }
13
13
  /*
14
14
  * Every tool the thread has a word for, in one table so a new name is never missing from a lookup. A
@@ -16,30 +16,50 @@ function entry(icon, summary, rest = {}) {
16
16
  * string of its input.
17
17
  */
18
18
  export const TOOL_CATALOG = {
19
- Read: entry(Eye, ['file_path'], { readsImage: true }),
20
- // Only `readImagePath` ever had this one, which is why it has no sentence of its own yet.
21
- NotebookRead: entry(Eye, ['file_path', 'notebook_path'], { grouped: false, readsImage: true }),
22
- // These three read as "Edited 3 files" through `changesFiles`, so they carry no copy of that sentence.
23
- Edit: entry(SquarePen, ['file_path'], { grouped: false, changesFiles: true }),
24
- Write: entry(SquarePen, ['file_path'], { changesFiles: true }),
25
- MultiEdit: entry(SquarePen, ['file_path'], { grouped: false, changesFiles: true }),
26
- NotebookEdit: entry(SquarePen, ['file_path', 'notebook_path']),
27
- // Codex reports a patch as the paths it touches; its own input carries no path of its own.
28
- ApplyPatch: entry(SquarePen, ['summary'], { grouped: false, changesFiles: true }),
29
- // Codex's command executions arrive under this name too.
30
- Bash: entry(Terminal, ['description', 'command'], { shell: true }),
31
- Grep: entry(Search, ['pattern']),
32
- Glob: entry(FolderSearch, ['pattern']),
33
- WebFetch: entry(Globe, ['url', 'query']),
34
- WebSearch: entry(Globe, ['url', 'query']),
35
- Task: entry(Bot, ['description']),
36
- Agent: entry(Bot, ['description']),
37
- Skill: entry(Zap, ['skill']),
38
- // A plan is a list of objects, so there is no line to lift out of it.
39
- TodoWrite: entry(ListTodo, []),
40
- // Its input is the whole script; the line takes what the CLI says the workflow is about instead.
41
- Workflow: entry(Workflow, [], { grouped: false })
19
+ Read: entry(Eye, ['file_path'], {
20
+ readsImage: true
21
+ }),
22
+ // Only `readImagePath` ever had this one, which is why it has no sentence of its own yet.
23
+ NotebookRead: entry(Eye, ['file_path', 'notebook_path'], {
24
+ grouped: false,
25
+ readsImage: true
26
+ }),
27
+ // These three read as "Edited 3 files" through `changesFiles`, so they carry no copy of that sentence.
28
+ Edit: entry(SquarePen, ['file_path'], {
29
+ grouped: false,
30
+ changesFiles: true
31
+ }),
32
+ Write: entry(SquarePen, ['file_path'], {
33
+ changesFiles: true
34
+ }),
35
+ MultiEdit: entry(SquarePen, ['file_path'], {
36
+ grouped: false,
37
+ changesFiles: true
38
+ }),
39
+ NotebookEdit: entry(SquarePen, ['file_path', 'notebook_path']),
40
+ // Codex reports a patch as the paths it touches; its own input carries no path of its own.
41
+ ApplyPatch: entry(SquarePen, ['summary'], {
42
+ grouped: false,
43
+ changesFiles: true
44
+ }),
45
+ // Codex's command executions arrive under this name too.
46
+ Bash: entry(Terminal, ['description', 'command'], {
47
+ shell: true
48
+ }),
49
+ Grep: entry(Search, ['pattern']),
50
+ Glob: entry(FolderSearch, ['pattern']),
51
+ WebFetch: entry(Globe, ['url', 'query']),
52
+ WebSearch: entry(Globe, ['url', 'query']),
53
+ Task: entry(Bot, ['description']),
54
+ Agent: entry(Bot, ['description']),
55
+ Skill: entry(Zap, ['skill']),
56
+ // A plan is a list of objects, so there is no line to lift out of it.
57
+ TodoWrite: entry(ListTodo, []),
58
+ // Its input is the whole script; the line takes what the CLI says the workflow is about instead.
59
+ Workflow: entry(Workflow, [], {
60
+ grouped: false
61
+ })
42
62
  };
43
63
  export function toolEntry(name) {
44
- return TOOL_CATALOG[name];
45
- }
64
+ return TOOL_CATALOG[name];
65
+ }
@@ -1,139 +1,163 @@
1
1
  import { isRecord } from './json.js';
2
2
  import { toolEntry } from './tool-catalog.js';
3
3
  function str(value) {
4
- return typeof value === 'string' ? value : null;
4
+ return typeof value === 'string' ? value : null;
5
5
  }
6
6
  /* The one line that says what a tool call is about: the command, the file, the pattern. */
7
7
  export function toolSummary(name, input) {
8
- if (!isRecord(input)) {
9
- return '';
10
- }
11
- const known = toolEntry(name);
12
- if (known === undefined) {
13
- // A tool nobody wrote down, an MCP one above all, gets its best guess from the first string it was given.
14
- const first = Object.values(input).find((value) => typeof value === 'string');
15
- return typeof first === 'string' ? first : '';
16
- }
17
- for (const key of known.summary) {
18
- const value = str(input[key]);
19
- if (value !== null) {
20
- return value;
21
- }
22
- }
8
+ if (!isRecord(input)) {
23
9
  return '';
10
+ }
11
+ const known = toolEntry(name);
12
+ if (known === undefined) {
13
+ // A tool nobody wrote down, an MCP one above all, gets its best guess from the first string it was given.
14
+ const first = Object.values(input).find(value => typeof value === 'string');
15
+ return typeof first === 'string' ? first : '';
16
+ }
17
+ for (const key of known.summary) {
18
+ const value = str(input[key]);
19
+ if (value !== null) {
20
+ return value;
21
+ }
22
+ }
23
+ return '';
24
24
  }
25
25
  // The input keys whose value is a file a call is about.
26
26
  const PATH_KEYS = new Set(['file_path', 'notebook_path']);
27
27
  /* Whether the one line of a call is the path of a file, which a row cuts in the middle so the name stays. */
28
28
  export function toolSummaryIsPath(name, input) {
29
- const known = toolEntry(name);
30
- if (known === undefined || !isRecord(input)) {
31
- return false;
32
- }
33
- const key = known.summary.find((candidate) => str(input[candidate]) !== null);
34
- return key !== undefined && PATH_KEYS.has(key);
29
+ const known = toolEntry(name);
30
+ if (known === undefined || !isRecord(input)) {
31
+ return false;
32
+ }
33
+ const key = known.summary.find(candidate => str(input[candidate]) !== null);
34
+ return key !== undefined && PATH_KEYS.has(key);
35
35
  }
36
36
  /* The command of a shell call, as it was run; null for any other call or one without a command. */
37
37
  export function shellCommand(name, input) {
38
- if (toolEntry(name)?.shell !== true || !isRecord(input)) {
39
- return null;
40
- }
41
- const command = str(input.command);
42
- return command === null || command.trim() === '' ? null : command;
38
+ if (toolEntry(name)?.shell !== true || !isRecord(input)) {
39
+ return null;
40
+ }
41
+ const command = str(input.command);
42
+ return command === null || command.trim() === '' ? null : command;
43
43
  }
44
44
  // A shell call's description is already the detail of its row.
45
45
  const SHELL_SHOWN = new Set(['command', 'description']);
46
46
  function valueText(value) {
47
- // An empty string can be the point of a call (clearing a field), so it shows as one.
48
- return typeof value === 'string' && value !== '' ? value : (JSON.stringify(value) ?? String(value));
47
+ // An empty string can be the point of a call (clearing a field), so it shows as one.
48
+ return typeof value === 'string' && value !== '' ? value : JSON.stringify(value) ?? String(value);
49
49
  }
50
50
  /* The input of a call as lines: a shell command as itself, every other key as `key value`, null included. */
51
51
  export function toolCallLines(name, input) {
52
- if (!isRecord(input)) {
53
- const text = input === null || input === undefined || input === '' ? null : valueText(input);
54
- return { command: null, args: [], text };
55
- }
56
- const command = shellCommand(name, input);
57
- const args = Object.entries(input)
58
- .filter(([key, value]) => value !== undefined && !(command !== null && SHELL_SHOWN.has(key)))
59
- .map(([key, value]) => [key, valueText(value)]);
60
- return { command, args, text: null };
52
+ if (!isRecord(input)) {
53
+ const text = input === null || input === undefined || input === '' ? null : valueText(input);
54
+ return {
55
+ command: null,
56
+ args: [],
57
+ text
58
+ };
59
+ }
60
+ const command = shellCommand(name, input);
61
+ const args = Object.entries(input).filter(([key, value]) => value !== undefined && !(command !== null && SHELL_SHOWN.has(key))).map(([key, value]) => [key, valueText(value)]);
62
+ return {
63
+ command,
64
+ args,
65
+ text: null
66
+ };
61
67
  }
62
68
  /* A failed call's output with the exit code its tool put on the first line ("Exit code 1"), as Claude Code's shell does. */
63
69
  export function exitCodeOf(output) {
64
- const match = /^Exit code (-?\d+)[ \t]*(?:\r?\n|$)/.exec(output);
65
- if (match === null || Number(match[1]) === 0) {
66
- return { code: null, rest: output };
67
- }
68
- return { code: Number(match[1]), rest: output.slice(match[0].length) };
70
+ const match = /^Exit code (-?\d+)[ \t]*(?:\r?\n|$)/.exec(output);
71
+ if (match === null || Number(match[1]) === 0) {
72
+ return {
73
+ code: null,
74
+ rest: output
75
+ };
76
+ }
77
+ return {
78
+ code: Number(match[1]),
79
+ rest: output.slice(match[0].length)
80
+ };
69
81
  }
70
82
  /* Whether an output says anything; whitespace alone does not. */
71
83
  export function hasOutput(output) {
72
- return output !== null && output.trim() !== '';
84
+ return output !== null && output.trim() !== '';
73
85
  }
74
86
  /* Whether opening a call shows anything: a diff, the input it was given or what it answered. */
75
87
  export function hasToolBody(tool) {
76
- if (hasFileChanges(tool) || hasOutput(tool.output)) {
77
- return true;
78
- }
79
- const lines = toolCallLines(tool.name, tool.input);
80
- return lines.command !== null || lines.args.length > 0 || lines.text !== null;
88
+ if (hasFileChanges(tool) || hasOutput(tool.output)) {
89
+ return true;
90
+ }
91
+ const lines = toolCallLines(tool.name, tool.input);
92
+ return lines.command !== null || lines.args.length > 0 || lines.text !== null;
81
93
  }
82
94
  // What `GET /fs/file` will serve; a path with another suffix is not worth asking the host about.
83
95
  const IMAGE_SUFFIXES = ['.png', '.jpg', '.jpeg', '.gif', '.webp', '.svg'];
84
96
  /* The image file a tool call looked at, so the row can draw it; null for every other call. */
85
97
  export function readImagePath(name, input) {
86
- if (toolEntry(name)?.readsImage !== true) {
87
- return null;
88
- }
89
- const path = isRecord(input) ? str(input.file_path) : null;
90
- if (path === null) {
91
- return null;
92
- }
93
- const lowered = path.toLowerCase();
94
- return IMAGE_SUFFIXES.some((suffix) => lowered.endsWith(suffix)) ? path : null;
98
+ if (toolEntry(name)?.readsImage !== true) {
99
+ return null;
100
+ }
101
+ const path = isRecord(input) ? str(input.file_path) : null;
102
+ if (path === null) {
103
+ return null;
104
+ }
105
+ const lowered = path.toLowerCase();
106
+ return IMAGE_SUFFIXES.some(suffix => lowered.endsWith(suffix)) ? path : null;
95
107
  }
96
108
  /* The before and after text of a file-changing tool call, so the thread can show it as a diff. */
97
109
  export function fileChanges(name, input) {
98
- if (!isRecord(input)) {
99
- return [];
100
- }
101
- const path = str(input.file_path) ?? '';
102
- if (name === 'Edit') {
103
- return [{ path, before: str(input.old_string) ?? '', after: str(input.new_string) ?? '' }];
104
- }
105
- if (name === 'Write') {
106
- return [{ path, before: '', after: str(input.content) ?? '' }];
107
- }
108
- if (name === 'MultiEdit' && Array.isArray(input.edits)) {
109
- return input.edits.filter(isRecord).map((edit) => ({ path, before: str(edit.old_string) ?? '', after: str(edit.new_string) ?? '' }));
110
- }
110
+ if (!isRecord(input)) {
111
111
  return [];
112
+ }
113
+ const path = str(input.file_path) ?? '';
114
+ if (name === 'Edit') {
115
+ return [{
116
+ path,
117
+ before: str(input.old_string) ?? '',
118
+ after: str(input.new_string) ?? ''
119
+ }];
120
+ }
121
+ if (name === 'Write') {
122
+ return [{
123
+ path,
124
+ before: '',
125
+ after: str(input.content) ?? ''
126
+ }];
127
+ }
128
+ if (name === 'MultiEdit' && Array.isArray(input.edits)) {
129
+ return input.edits.filter(isRecord).map(edit => ({
130
+ path,
131
+ before: str(edit.old_string) ?? '',
132
+ after: str(edit.new_string) ?? ''
133
+ }));
134
+ }
135
+ return [];
112
136
  }
113
137
  export function isFileChange(name) {
114
- return toolEntry(name)?.changesFiles === true;
138
+ return toolEntry(name)?.changesFiles === true;
115
139
  }
116
140
  /* The unified diffs a provider put next to a tool call; empty for one that reports before and after. */
117
141
  export function unifiedChanges(tool) {
118
- return (tool.changes ?? []).filter((change) => change.diff !== '');
142
+ return (tool.changes ?? []).filter(change => change.diff !== '');
119
143
  }
120
144
  /* The same, for the copy an approval carries so the person can read what they are approving. */
121
145
  export function approvalChanges(input) {
122
- const changes = isRecord(input) ? input.changes : null;
123
- if (!Array.isArray(changes)) {
124
- return [];
125
- }
126
- return changes.filter((change) => isRecord(change) && typeof change.path === 'string' && typeof change.diff === 'string' && change.diff !== '');
146
+ const changes = isRecord(input) ? input.changes : null;
147
+ if (!Array.isArray(changes)) {
148
+ return [];
149
+ }
150
+ return changes.filter(change => isRecord(change) && typeof change.path === 'string' && typeof change.diff === 'string' && change.diff !== '');
127
151
  }
128
152
  /* Whether a settled call is worth a row in the turn's changed files card. */
129
153
  export function hasFileChanges(tool) {
130
- return unifiedChanges(tool).length > 0 || fileChanges(tool.name, tool.input).length > 0;
154
+ return unifiedChanges(tool).length > 0 || fileChanges(tool.name, tool.input).length > 0;
131
155
  }
132
156
  /* When a running call started: what the CLI reported, or the moment the call appeared. */
133
157
  export function toolStartedAt(tool) {
134
- return tool.progress?.startedAt ?? tool.createdAt;
158
+ return tool.progress?.startedAt ?? tool.createdAt;
135
159
  }
136
160
  // Keep the full buffer so the renderer can carry ANSI state into the visible tail.
137
161
  export function liveOutput(tool) {
138
- return tool.progress?.output || null;
139
- }
162
+ return tool.progress?.output || null;
163
+ }
@@ -11,36 +11,36 @@ const MAX_CONTENT_HEIGHT_PX = 10_000_000;
11
11
  */
12
12
  const remembered = new Map();
13
13
  function keyOf(visualId, width) {
14
- return `${visualId}@${Math.round(width)}`;
14
+ return `${visualId}@${Math.round(width)}`;
15
15
  }
16
16
  /* A height a page reported, held to the visual's own maximum and the limits, in whole pixels. */
17
17
  export function clampVisualHeight(visual, height) {
18
- return Math.min(Math.max(Math.ceil(Math.min(height, visual.maxHeight)), VISUAL_LIMITS.minHeight), VISUAL_LIMITS.maxHeight);
18
+ return Math.min(Math.max(Math.ceil(Math.min(height, visual.maxHeight)), VISUAL_LIMITS.minHeight), VISUAL_LIMITS.maxHeight);
19
19
  }
20
20
  export function visualContentHeight(height) {
21
- return Math.min(MAX_CONTENT_HEIGHT_PX, Math.max(VISUAL_LIMITS.minHeight, Math.ceil(height)));
21
+ return Math.min(MAX_CONTENT_HEIGHT_PX, Math.max(VISUAL_LIMITS.minHeight, Math.ceil(height)));
22
22
  }
23
23
  export function initialVisualContentHeight(visual, width) {
24
- const cached = remembered.get(keyOf(visual.id, width));
25
- if (cached !== undefined) {
26
- return cached;
27
- }
28
- const below = visual.heights?.filter(([measured]) => measured <= width).sort((left, right) => right[0] - left[0])[0];
29
- const above = visual.heights?.filter(([measured]) => measured >= width).sort((left, right) => left[0] - right[0])[0];
30
- return below || above ? visualContentHeight(Math.max(below?.[1] ?? 0, above?.[1] ?? 0)) : DEFAULT_HEIGHT_PX;
24
+ const cached = remembered.get(keyOf(visual.id, width));
25
+ if (cached !== undefined) {
26
+ return cached;
27
+ }
28
+ const below = visual.heights?.filter(([measured]) => measured <= width).sort((left, right) => right[0] - left[0])[0];
29
+ const above = visual.heights?.filter(([measured]) => measured >= width).sort((left, right) => left[0] - right[0])[0];
30
+ return below || above ? visualContentHeight(Math.max(below?.[1] ?? 0, above?.[1] ?? 0)) : DEFAULT_HEIGHT_PX;
31
31
  }
32
32
  /*
33
33
  * The height a frame `width` CSS pixels wide starts at: what the page reported in a frame that wide
34
34
  * before, else what the host measured, else a modest default.
35
35
  */
36
36
  export function initialVisualHeight(visual, width) {
37
- return remembered.get(keyOf(visual.id, width)) ?? visualFrameHeight(visual, width) ?? clampVisualHeight(visual, DEFAULT_HEIGHT_PX);
37
+ return remembered.get(keyOf(visual.id, width)) ?? visualFrameHeight(visual, width) ?? clampVisualHeight(visual, DEFAULT_HEIGHT_PX);
38
38
  }
39
39
  export function rememberVisualHeight(visualId, width, height) {
40
- const key = keyOf(visualId, width);
41
- remembered.delete(key);
42
- remembered.set(key, height);
43
- if (remembered.size > REMEMBERED_HEIGHTS) {
44
- remembered.delete(remembered.keys().next().value);
45
- }
46
- }
40
+ const key = keyOf(visualId, width);
41
+ remembered.delete(key);
42
+ remembered.set(key, height);
43
+ if (remembered.size > REMEMBERED_HEIGHTS) {
44
+ remembered.delete(remembered.keys().next().value);
45
+ }
46
+ }
@@ -1,4 +1,7 @@
1
1
  export function visualViewportGeometry(contentHeight, availableHeight, top) {
2
- const height = Math.max(1, Math.min(contentHeight, availableHeight));
3
- return { height, top: Math.max(0, Math.min(-top, contentHeight - height)) };
4
- }
2
+ const height = Math.max(1, Math.min(contentHeight, availableHeight));
3
+ return {
4
+ height,
5
+ top: Math.max(0, Math.min(-top, contentHeight - height))
6
+ };
7
+ }
@@ -1,10 +1,10 @@
1
1
  export function dayPartOf(now) {
2
- const hour = now.getHours();
3
- if (hour < 5) {
4
- return 'night';
5
- }
6
- if (hour < 12) {
7
- return 'morning';
8
- }
9
- return hour < 18 ? 'afternoon' : 'evening';
10
- }
2
+ const hour = now.getHours();
3
+ if (hour < 5) {
4
+ return 'night';
5
+ }
6
+ if (hour < 12) {
7
+ return 'morning';
8
+ }
9
+ return hour < 18 ? 'afternoon' : 'evening';
10
+ }
@@ -12,3 +12,13 @@ export interface WorkflowPhaseView {
12
12
  export declare function workflowAgentState(agent: ChatWorkflowAgent, workflowRunning: boolean): WorkflowAgentState;
13
13
  export declare function workflowPhases(workflow: ChatWorkflow, workflowRunning: boolean): WorkflowPhaseView[];
14
14
  export declare function workflowAgentTime(view: WorkflowAgentView): string | null;
15
+ export interface WorkflowAgentPreview {
16
+ tool: string | null;
17
+ text: string | null;
18
+ }
19
+ export declare function workflowAgentPreview(view: WorkflowAgentView): WorkflowAgentPreview;
20
+ export type WorkflowCounts = Record<WorkflowAgentState, number> & {
21
+ total: number;
22
+ };
23
+ export declare function workflowCounts(phases: WorkflowPhaseView[]): WorkflowCounts;
24
+ export declare function workflowDescription(input: unknown): string | null;
@@ -1,47 +1,145 @@
1
1
  import i18next from 'i18next';
2
2
  import { formatElapsedShort } from '@adecore/ui/format';
3
3
  export function workflowAgentState(agent, workflowRunning) {
4
- if (agent.status !== 'running') {
5
- return agent.status;
6
- }
7
- if (!workflowRunning) {
8
- return 'stopped';
9
- }
10
- return agent.startedAt === null ? 'waiting' : 'running';
4
+ if (agent.status !== 'running') {
5
+ return agent.status;
6
+ }
7
+ if (!workflowRunning) {
8
+ return 'stopped';
9
+ }
10
+ return agent.startedAt === null ? 'waiting' : 'running';
11
11
  }
12
12
  /*
13
13
  * The phases in the order the script announced them, each with the agents it started in it. A phase
14
14
  * announced ahead of its agents is there without any, and agents of no known phase come first, untitled.
15
15
  */
16
16
  export function workflowPhases(workflow, workflowRunning) {
17
- const known = new Map(workflow.phases.map((phase) => [phase.index, phase]));
18
- const loose = [];
19
- const byPhase = new Map();
20
- for (const agent of workflow.agents) {
21
- const view = { agent, state: workflowAgentState(agent, workflowRunning) };
22
- if (agent.phaseIndex === null || !known.has(agent.phaseIndex)) {
23
- loose.push(view);
24
- continue;
25
- }
26
- byPhase.set(agent.phaseIndex, [...(byPhase.get(agent.phaseIndex) ?? []), view]);
17
+ const known = new Map(workflow.phases.map(phase => [phase.index, phase]));
18
+ const loose = [];
19
+ const byPhase = new Map();
20
+ for (const agent of workflow.agents) {
21
+ const view = {
22
+ agent,
23
+ state: workflowAgentState(agent, workflowRunning)
24
+ };
25
+ if (agent.phaseIndex === null || !known.has(agent.phaseIndex)) {
26
+ loose.push(view);
27
+ continue;
27
28
  }
28
- const phases = workflow.phases.map((phase) => ({ key: `phase-${phase.index}`, title: phase.title, agents: byPhase.get(phase.index) ?? [] }));
29
- return loose.length > 0 ? [{ key: 'loose', title: null, agents: loose }, ...phases] : phases;
29
+ byPhase.set(agent.phaseIndex, [...(byPhase.get(agent.phaseIndex) ?? []), view]);
30
+ }
31
+ const phases = workflow.phases.map(phase => ({
32
+ key: `phase-${phase.index}`,
33
+ title: phase.title,
34
+ agents: byPhase.get(phase.index) ?? []
35
+ }));
36
+ return loose.length > 0 ? [{
37
+ key: 'loose',
38
+ title: null,
39
+ agents: loose
40
+ }, ...phases] : phases;
30
41
  }
31
42
  /* What the line of an agent that is not at work says about its time; one at work counts on by itself. */
32
43
  export function workflowAgentTime(view) {
33
- const duration = view.agent.durationMs === null ? null : formatElapsedShort(view.agent.durationMs);
34
- switch (view.state) {
35
- case 'running':
36
- return null;
37
- case 'waiting':
38
- return i18next.t('agent-chat:rows.workflow.waiting');
39
- case 'stopped':
40
- return i18next.t('agent-chat:rows.workflow.stopped');
41
- case 'done':
42
- case 'failed':
43
- return duration === null
44
- ? i18next.t(`agent-chat:common.status.${view.state}`)
45
- : i18next.t(`agent-chat:rows.subagent.${view.state}In`, { duration });
44
+ switch (view.state) {
45
+ case 'running':
46
+ return null;
47
+ case 'waiting':
48
+ return i18next.t('agent-chat:rows.workflow.waiting');
49
+ case 'stopped':
50
+ return i18next.t('agent-chat:rows.workflow.stopped');
51
+ case 'done':
52
+ case 'failed':
53
+ return view.agent.durationMs === null ? null : formatElapsedShort(view.agent.durationMs);
54
+ }
55
+ }
56
+ /* The CLI's previews start with a markdown heading as often as not, which says nothing on one line. */
57
+ function firstLine(text) {
58
+ const line = text?.split('\n').map(part => part.replace(/^#+\s*/, '').trim()).find(part => part !== '');
59
+ return line === undefined ? null : line;
60
+ }
61
+ /* The second line of an agent: what it does while at work, what it answered once it stopped, what it was asked before. */
62
+ export function workflowAgentPreview(view) {
63
+ const {
64
+ agent
65
+ } = view;
66
+ switch (view.state) {
67
+ case 'running':
68
+ return agent.lastTool === null ? {
69
+ tool: null,
70
+ text: firstLine(agent.promptPreview)
71
+ } : {
72
+ tool: agent.lastTool,
73
+ text: firstLine(agent.lastToolSummary)
74
+ };
75
+ case 'waiting':
76
+ return {
77
+ tool: null,
78
+ text: firstLine(agent.promptPreview)
79
+ };
80
+ case 'failed':
81
+ return {
82
+ tool: null,
83
+ text: firstLine(agent.error) ?? firstLine(agent.resultPreview)
84
+ };
85
+ case 'done':
86
+ case 'stopped':
87
+ return {
88
+ tool: null,
89
+ text: firstLine(agent.resultPreview) ?? firstLine(agent.promptPreview)
90
+ };
91
+ }
92
+ }
93
+ export function workflowCounts(phases) {
94
+ const counts = {
95
+ total: 0,
96
+ running: 0,
97
+ waiting: 0,
98
+ stopped: 0,
99
+ done: 0,
100
+ failed: 0
101
+ };
102
+ for (const view of phases.flatMap(phase => phase.agents)) {
103
+ counts.total += 1;
104
+ counts[view.state] += 1;
105
+ }
106
+ return counts;
107
+ }
108
+ const META_START = /export\s+const\s+meta\s*=\s*\{/;
109
+ const DESCRIPTION = /\bdescription\s*:\s*(['"`])((?:\\.|(?!\1)[^\\])*)\1/;
110
+ /* The literal from its opening brace to the one that closes it, skipping braces inside strings. */
111
+ function metaLiteral(script) {
112
+ const start = META_START.exec(script);
113
+ if (start === null) {
114
+ return null;
115
+ }
116
+ const from = start.index + start[0].length - 1;
117
+ let depth = 0;
118
+ let quote = null;
119
+ for (let i = from; i < script.length; i++) {
120
+ const char = script[i];
121
+ if (quote !== null) {
122
+ if (char === '\\') {
123
+ i++;
124
+ } else if (char === quote) {
125
+ quote = null;
126
+ }
127
+ continue;
128
+ }
129
+ if (char === "'" || char === '"' || char === '`') {
130
+ quote = char;
131
+ } else if (char === '{') {
132
+ depth++;
133
+ } else if (char === '}' && --depth === 0) {
134
+ return script.slice(from, i + 1);
46
135
  }
136
+ }
137
+ return null;
47
138
  }
139
+ /* The script's `meta` is a pure literal by the CLI's own rule, so its description reads without running anything. A saved workflow called by name has no script here. */
140
+ export function workflowDescription(input) {
141
+ const script = typeof input === 'object' && input !== null && 'script' in input ? input.script : undefined;
142
+ const meta = typeof script === 'string' ? metaLiteral(script) : null;
143
+ const found = meta === null ? undefined : DESCRIPTION.exec(meta)?.[2]?.replace(/\\(.)/g, '$1').trim();
144
+ return found ? found : null;
145
+ }