@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,4 +1,4 @@
1
- import { useContext, useMemo, useState, type ReactNode } from 'react';
1
+ import { useContext, useState, type ReactNode } from 'react';
2
2
  import clsx from 'clsx';
3
3
  import { useTranslation } from 'react-i18next';
4
4
  import { Bot, Brain, Check, ChevronDown, CircleAlert, File, Info, MessageCircleQuestionMark, Reply, TriangleAlert, X } from 'lucide-react';
@@ -14,7 +14,6 @@ import type {
14
14
  import { WAITING_NOTE_PREFIX } from '@adecore/agent-contracts';
15
15
  import { fileBadge, formatBytes, isImageAttachment } from '../../attachments';
16
16
  import { useChatRow, useCurrentItem } from '../../../state/chats';
17
- import { useChatHost } from '../../../host';
18
17
  import { useChatScope } from '../../../scope';
19
18
  import { splitQuote } from '../../quote';
20
19
  import { jumpToTimelineItem } from '../../timeline-scroll';
@@ -34,6 +33,7 @@ import { ROW_GUTTER } from '../icons';
34
33
  import { useOpenForFind } from '../find-reveal';
35
34
  import { ReplyContext, UiReplyNavigationContext } from '../reply-context';
36
35
  import { UiReply } from '../intelligent-ui/UiReply';
36
+ import { useHostAttachmentUrl, useHostChatPlace, useHostReplyAuthor, useHostStreaming } from '../../../host-hooks';
37
37
 
38
38
  // A long prompt folds so the answer stays in view; the reader can open it.
39
39
  const USER_FOLD_LINES = 8;
@@ -43,10 +43,9 @@ const USER_FOLD_CHARS = 600;
43
43
  const FOLD = 'max-h-[10em] overflow-hidden [mask-image:linear-gradient(to_bottom,black_70%,transparent)]';
44
44
 
45
45
  function useReplyAuthor(chatId: string) {
46
- const host = useChatHost();
47
46
  const { id } = useChatScope();
48
47
  const context = useContext(ReplyContext);
49
- const author = host.useReplyAuthor(id, context?.chatId ?? chatId);
48
+ const author = useHostReplyAuthor(id, context?.chatId ?? chatId);
50
49
  return context !== null && context.chatId === undefined ? null : author;
51
50
  }
52
51
 
@@ -55,9 +54,8 @@ function useReplyAuthor(chatId: string) {
55
54
  * hands a link that opens a window to the system browser, which cannot reach a blob of this page.
56
55
  */
57
56
  function AttachmentLink({ chatId, attachment }: { chatId: string; attachment: ChatAttachment }) {
58
- const host = useChatHost();
59
57
  const { id } = useChatScope();
60
- const { url } = host.attachments.useUrl(id, chatId, attachment.id);
58
+ const { url } = useHostAttachmentUrl(id, chatId, attachment.id);
61
59
  const badge = fileBadge(attachment.name);
62
60
  return (
63
61
  <Tooltip label={attachment.name}>
@@ -81,9 +79,8 @@ function AttachmentLink({ chatId, attachment }: { chatId: string; attachment: Ch
81
79
 
82
80
  /* A picture attached to a message, which opens large. */
83
81
  function AttachmentThumb({ chatId, attachment }: { chatId: string; attachment: ChatAttachment }) {
84
- const host = useChatHost();
85
82
  const { id } = useChatScope();
86
- const source = host.attachments.useUrl(id, chatId, attachment.id);
83
+ const source = useHostAttachmentUrl(id, chatId, attachment.id);
87
84
  return <ImageThumb source={source} alt={attachment.name} className="max-h-32 max-w-48 object-cover" />;
88
85
  }
89
86
 
@@ -268,15 +265,11 @@ function Writing() {
268
265
  * written fades anything: an old reply scrolled back into view just stands there.
269
266
  */
270
267
  export function AssistantRow({ chatId, item: derived }: { chatId: string; item: ChatAssistantItem }) {
271
- const host = useChatHost();
272
268
  const item = useCurrentItem(chatId, derived);
273
269
  const scope = useChatScope();
274
270
  const context = useContext(ReplyContext);
275
- const reply = useMemo(
276
- () => (context === null && !item.parentToolUseId ? { scopeId: scope.id, chatId, itemId: item.id, streaming: item.streaming } : undefined),
277
- [context, item.parentToolUseId, scope.id, chatId, item.id, item.streaming]
278
- );
279
- const mode = host.useStreaming();
271
+ const reply = context === null && !item.parentToolUseId ? { scopeId: scope.id, chatId, itemId: item.id, streaming: item.streaming } : undefined;
272
+ const mode = useHostStreaming();
280
273
  const [sawWriting] = useState(item.streaming);
281
274
  const live = mode === 'words' && item.streaming;
282
275
  const reveal = useRevealedText(item.text, live);
@@ -338,10 +331,9 @@ export function AssistantRow({ chatId, item: derived }: { chatId: string; item:
338
331
  * folded, it shows the heading it opens with or itself on one line, and opened, it reads as Markdown.
339
332
  */
340
333
  export function ThinkingRow({ chatId, item: derived }: { chatId: string; item: ChatThinkingItem }) {
341
- const host = useChatHost();
342
334
  const { t } = useTranslation('agent-chat');
343
335
  const item = useCurrentItem(chatId, derived);
344
- const mode = host.useStreaming();
336
+ const mode = useHostStreaming();
345
337
  const [open, setOpen] = useState(false);
346
338
  const reveal = useRevealedText(item.text, mode === 'words' && item.streaming);
347
339
  // A block at a time, the paragraphs of the thought that closed are shown as they land.
@@ -349,8 +341,8 @@ export function ThinkingRow({ chatId, item: derived }: { chatId: string; item: C
349
341
  // Whole, the thought stays behind "Thinking…" until it is done and then folds like any other.
350
342
  const shown = open || reveal.active || (settled !== null && settled !== '');
351
343
  const text = settled ?? reveal.text;
352
- const live = useMemo(() => (item.streaming && mode !== 'whole' ? thoughtLine(text) : ''), [item.streaming, mode, text]);
353
- const preview = useMemo(() => (item.streaming ? '' : thoughtPreview(item.text)), [item.streaming, item.text]);
344
+ const live = item.streaming && mode !== 'whole' ? thoughtLine(text) : '';
345
+ const preview = item.streaming ? '' : thoughtPreview(item.text);
354
346
  const duration = formatElapsedShort((item.endedAt ?? item.createdAt) - item.createdAt);
355
347
  useOpenForFind(item.id, 'text', setOpen);
356
348
  return (
@@ -401,7 +393,7 @@ export function ThinkingRow({ chatId, item: derived }: { chatId: string; item: C
401
393
  */
402
394
  export function LiveThoughtRow({ chatId, item: derived }: { chatId: string; item: ChatThinkingItem }) {
403
395
  const item = useCurrentItem(chatId, derived);
404
- const line = useMemo(() => thoughtLine(item.text), [item.text]);
396
+ const line = thoughtLine(item.text);
405
397
  if (line === '') {
406
398
  return null;
407
399
  }
@@ -465,9 +457,8 @@ export function NoteRow({ id, level, text, from }: { id: string; level: 'info' |
465
457
 
466
458
  /* "Open fork" on a note a fork sent, or "Open to answer" on one about a waiting child, while that chat is still in the project. */
467
459
  function OpenChatButton({ chatId, label }: { chatId: string; label: 'openFork' | 'openWaiting' }) {
468
- const host = useChatHost();
469
460
  const { t } = useTranslation('agent-chat');
470
- const place = host.useChatPlace(chatId);
461
+ const place = useHostChatPlace(chatId);
471
462
  if (place.title === null) {
472
463
  return null;
473
464
  }
@@ -15,9 +15,10 @@ import { RunningFor, ToggleLine, WorkLiveRow, WorkRow } from './WorkRows';
15
15
  import { entryTimeOf, statusWordOf, taskIdOf } from '../../subagent-list';
16
16
  import { useSubagentSupport } from '../../subagent-support';
17
17
  import { canOpenSubagent, crumbOf, type SubagentStep } from '../../subagent-view';
18
- import { useChatHost, type SubagentTask } from '../../../host';
18
+ import { type SubagentTask } from '../../../host';
19
19
  import { useChatScope } from '../../../scope';
20
20
  import { useCurrentItem } from '../../../state/chats';
21
+ import { useHostTask } from '../../../host-hooks';
21
22
 
22
23
  // The work of a long-running agent scrolls inside its row instead of pushing the thread away.
23
24
  const CHILDREN_MAX_PX = 320;
@@ -135,11 +136,10 @@ export function SubagentRow({
135
136
  /* Opens everything it did in the thread's place, for a surface that has somewhere to open it. */
136
137
  onOpenConversation?(): void;
137
138
  }) {
138
- const host = useChatHost();
139
139
  const { t } = useTranslation('agent-chat');
140
140
  const { id } = useChatScope();
141
141
  const taskId = taskIdOf(item);
142
- const task = host.tasks.useTask(id, taskId);
142
+ const task = useHostTask(id, taskId);
143
143
  // A task paused on its child's limit is still a running row on the wire, but nothing is at work.
144
144
  const running = item.status === 'running' && statusWordOf(item, task) !== 'paused';
145
145
  const detail = item.description || item.summary || item.subagentType || '';
@@ -39,7 +39,7 @@ function Elapsed({ startedAt }: { startedAt: number }) {
39
39
  function StateLine({ state, task }: { state: TaskRowState; task: SubagentTask | null }) {
40
40
  const { t } = useTranslation('agent-chat');
41
41
  const until = state === 'paused' ? task?.paused?.until : undefined;
42
- const now = useNow(60_000, until === undefined);
42
+ const now = useNow(60_000, until !== undefined);
43
43
  return (
44
44
  <span className={clsx('truncate text-2xs', STATE_TONE[state])}>
45
45
  {until === undefined ? t(`rows.task.${state}`) : t('rows.task.pausedUntil', { time: formatMoment(until, now) })}
@@ -23,6 +23,7 @@ import {
23
23
  } from '../../logic/tools';
24
24
  import { useOpenForFind } from '../find-reveal';
25
25
  import { useChatHost, type CommandLook } from '../../../host';
26
+ import { useCommandNames } from '../../../host-hooks';
26
27
  import { lazyNamed } from '../../../lazy';
27
28
  import { useChatActions } from '../../actions';
28
29
  import { ChatScopeContext, useChatScope } from '../../../scope';
@@ -71,10 +72,14 @@ function withBrand(text: string, brands: readonly string[]): ReactNode {
71
72
  return text;
72
73
  }
73
74
 
75
+ function hasNames(look: CommandLook): look is CommandLook & Required<Pick<CommandLook, 'useNames'>> {
76
+ return look.useNames !== undefined;
77
+ }
78
+
74
79
  /* The detail of a look's run, with the words its host names drawn as those names. */
75
- function NamedLookDetail({ run, chatId, useNames }: { run: CommandLookRun; chatId: string; useNames: NonNullable<CommandLook['useNames']> }) {
80
+ function NamedLookDetail({ run, chatId, look }: { run: CommandLookRun; chatId: string; look: Required<Pick<CommandLook, 'useNames'>> }) {
76
81
  const scope = useContext(ChatScopeContext);
77
- const nameOf = useNames(scope?.id ?? '', chatId);
82
+ const nameOf = useCommandNames(look, scope?.id ?? '', chatId);
78
83
  const names = run.words.flatMap((word): NamedWord[] => {
79
84
  const name = nameOf(word.text, word.option);
80
85
  return name === null ? [] : [{ start: word.start, end: word.end, word: word.text, name }];
@@ -83,12 +88,12 @@ function NamedLookDetail({ run, chatId, useNames }: { run: CommandLookRun; chatI
83
88
  }
84
89
 
85
90
  function LookDetail({ run, chatId }: { run: CommandLookRun; chatId: string }) {
86
- const { useNames } = run.look;
87
- if (useNames === undefined) {
91
+ const { look } = run;
92
+ if (!hasNames(look)) {
88
93
  return <ShellCommand command={run.detail} code={run.code} />;
89
94
  }
90
95
  // Keyed by the look, so a row whose command turns into another look's starts its hooks again.
91
- return <NamedLookDetail key={run.look.program} run={run} chatId={chatId} useNames={useNames} />;
96
+ return <NamedLookDetail key={look.program} run={run} chatId={chatId} look={look} />;
92
97
  }
93
98
 
94
99
  const TAG = 'shrink-0 rounded bg-surface-hover px-1.5 text-text-faint';
@@ -278,7 +283,7 @@ function ToolOutput({ tool }: { tool: ChatToolItem }) {
278
283
  }
279
284
 
280
285
  /* An opened call without a card: what it was asked in the foreground, what it answered muted below. */
281
- function ToolBody({ tool }: { tool: ChatToolItem }) {
286
+ export function ToolBody({ tool }: { tool: ChatToolItem }) {
282
287
  const patches = unifiedChanges(tool);
283
288
  const changes = patches.length > 0 ? [] : fileChanges(tool.name, tool.input);
284
289
  if (patches.length + changes.length > 0) {
@@ -1,68 +1,129 @@
1
+ import { useState } from 'react';
2
+ import clsx from 'clsx';
1
3
  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';
4
+ import { Bot, ChevronRight, Square, TriangleAlert, Workflow, X } from 'lucide-react';
5
+ import { workflowAgentRef, type AgentKind, type ChatToolItem, type ChatWorkflow } from '@adecore/agent-contracts';
6
+ import { formatElapsedShort } from '@adecore/ui/format';
7
+ import { Icon, IconButton, useTickingText } from '@adecore/ui';
8
+ import { AgentIcon } from '../../../agents/AgentIcon';
9
+ import {
10
+ workflowAgentPreview,
11
+ workflowAgentTime,
12
+ workflowCounts,
13
+ workflowDescription,
14
+ workflowPhases,
15
+ type WorkflowAgentState,
16
+ type WorkflowAgentView,
17
+ type WorkflowCounts,
18
+ type WorkflowPhaseView
19
+ } from '../../logic/workflow';
20
+ import { hasToolBody } from '../../logic/tools';
5
21
  import { useSubagentSupport } from '../../subagent-support';
6
22
  import type { SubagentStep } from '../../subagent-view';
7
23
  import { ROW_GUTTER } from '../icons';
8
- import { RunningFor, ToggleLine, WorkLiveRow, WorkRow } from './WorkRows';
24
+ import { ToolBody } from './WorkRows';
9
25
  import { useChatScope } from '../../../scope';
10
- import { Icon, IconButton } from '@adecore/ui';
26
+ import { useChats } from '../../../state/chats';
11
27
  import { useChatActions } from '../../actions';
12
28
  import { useChatHost } from '../../../host';
13
29
 
14
- function AgentLine({ view, onOpen }: { view: WorkflowAgentView; onOpen?(step: SubagentStep): void }) {
30
+ const DOT: Record<WorkflowAgentState, string> = {
31
+ running: 'bg-status-running',
32
+ waiting: 'bg-text-faint',
33
+ stopped: 'bg-text-faint',
34
+ done: 'bg-status-idle',
35
+ failed: 'bg-status-error'
36
+ };
37
+
38
+ const TIME = 'shrink-0 text-xs text-text-faint tabular-nums';
39
+
40
+ function Elapsed({ startedAt }: { startedAt: number }) {
41
+ const ref = useTickingText(() => formatElapsedShort(Date.now() - startedAt));
42
+ return <span ref={ref} className={TIME} />;
43
+ }
44
+
45
+ function AgentLine({ view, provider, onOpen }: { view: WorkflowAgentView; provider: AgentKind | undefined; onOpen?(step: SubagentStep): void }) {
15
46
  const { agent, state } = view;
16
47
  const time = workflowAgentTime(view);
17
- const running = state === 'running';
48
+ const preview = workflowAgentPreview(view);
18
49
  const agentId = agent.agentId;
19
50
  // One still waiting has no transcript yet.
20
- const open = onOpen !== undefined && agentId !== null ? () => onOpen({ toolUseId: workflowAgentRef(agentId), description: agent.label }) : () => undefined;
51
+ const open = onOpen !== undefined && agentId !== null ? () => onOpen({ toolUseId: workflowAgentRef(agentId), description: agent.label }) : undefined;
21
52
  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} />
53
+ <button
54
+ className="-mx-1 mb-0.5 flex w-[calc(100%+8px)] items-start gap-2 rounded-md px-1 py-1 text-left enabled:hover:bg-surface-hover"
55
+ disabled={open === undefined}
56
+ onClick={open}
57
+ >
58
+ <span className={clsx(ROW_GUTTER, 'relative text-text')}>
59
+ {provider === undefined ? <Icon icon={Bot} size={14} /> : <AgentIcon kind={provider} size={14} />}
60
+ <span className={clsx('absolute -right-0.75 bottom-0 size-2 rounded-full ring-2 ring-surface', DOT[state])} />
61
+ </span>
62
+ <span className="flex min-w-0 grow flex-col">
63
+ <span data-find-field="summary" className={clsx('truncate text-xs font-medium', state === 'failed' ? 'text-status-error' : 'text-text')}>
64
+ {agent.label}
65
+ </span>
66
+ {(preview.tool !== null || preview.text !== null) && (
67
+ <span className="truncate text-2xs text-text-muted">
68
+ {preview.tool !== null && <span className="font-mono text-code">{preview.tool}</span>}
69
+ {preview.tool !== null && preview.text !== null && ' · '}
70
+ {preview.text}
71
+ </span>
72
+ )}
73
+ </span>
74
+ <span className="flex h-5 shrink-0 items-center gap-2">
75
+ {state === 'running' && agent.startedAt !== null ? (
76
+ <Elapsed startedAt={agent.startedAt} />
33
77
  ) : (
34
- <span className="shrink-0 text-xs text-text-faint tabular-nums">{time}</span>
35
- )
36
- }
37
- />
78
+ time !== null && <span className={TIME}>{time}</span>
79
+ )}
80
+ {state === 'failed' && <Icon icon={X} size={12} className="shrink-0 text-status-error" />}
81
+ <Icon icon={ChevronRight} size={12} className={clsx('shrink-0 text-text-faint', open === undefined && 'invisible')} />
82
+ </span>
83
+ </button>
38
84
  );
39
85
  }
40
86
 
41
- function PhaseBlock({ phase, onOpen }: { phase: WorkflowPhaseView; onOpen?(step: SubagentStep): void }) {
87
+ function PhaseBlock({ phase, provider, onOpen }: { phase: WorkflowPhaseView; provider: AgentKind | undefined; onOpen?(step: SubagentStep): void }) {
42
88
  const { t } = useTranslation('agent-chat');
89
+ const settled = phase.agents.filter((view) => view.state === 'done' || view.state === 'failed').length;
43
90
  return (
44
- <div>
91
+ <div className="mt-3">
45
92
  {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} />
93
+ <div className="flex h-7 min-w-0 items-center gap-2 text-xs">
94
+ <span className="min-w-0 truncate font-medium text-text">{phase.title}</span>
95
+ <span className="shrink-0 text-text-faint tabular-nums">
96
+ {phase.agents.length === 0 ? t('rows.workflow.notStarted') : `${settled}/${phase.agents.length}`}
49
97
  </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
98
  </div>
61
99
  )}
100
+ {phase.agents.map((view) => (
101
+ <AgentLine key={view.agent.index} view={view} provider={provider} onOpen={onOpen} />
102
+ ))}
62
103
  </div>
63
104
  );
64
105
  }
65
106
 
107
+ function Counts({ counts }: { counts: WorkflowCounts }) {
108
+ const { t } = useTranslation('agent-chat');
109
+ const parts = [
110
+ { key: 'working', count: counts.running, tone: 'text-status-running' },
111
+ { key: 'finished', count: counts.done, tone: 'text-status-idle' },
112
+ { key: 'failedCount', count: counts.failed, tone: 'text-status-error' }
113
+ ].filter((part) => part.count > 0);
114
+ return (
115
+ <span className="shrink-0 truncate text-xs text-text-faint tabular-nums">
116
+ {t('rows.workflow.agents', { count: counts.total })}
117
+ {parts.map((part) => (
118
+ <span key={part.key}>
119
+ {' · '}
120
+ <span className={part.tone}>{t(`rows.workflow.${part.key}`, { count: part.count })}</span>
121
+ </span>
122
+ ))}
123
+ </span>
124
+ );
125
+ }
126
+
66
127
  // Keep background progress visible after the launcher turn ends.
67
128
  export function WorkflowRow({
68
129
  tool,
@@ -77,11 +138,16 @@ export function WorkflowRow({
77
138
  }) {
78
139
  const host = useChatHost();
79
140
  const { t } = useTranslation('agent-chat');
80
- const { id } = useChatScope();
141
+ const { id, keyOf } = useChatScope();
142
+ const [open, setOpen] = useState(false);
81
143
  // A host that does not answer `chat.subagent` has no conversation to open for anyone.
82
144
  const refused = useSubagentSupport((s) => s.unsupported[id] === true);
145
+ const provider = useChats((s) => (chatId === undefined ? undefined : s.statusByKey[keyOf(chatId)]?.info?.provider));
83
146
  const running = tool.state === 'running';
84
147
  const phases = workflowPhases(workflow, running);
148
+ const counts = workflowCounts(phases);
149
+ const description = workflowDescription(tool.input);
150
+ const opens = hasToolBody(tool);
85
151
  const onOpen = refused ? undefined : onOpenAgent;
86
152
  const actions = useChatActions();
87
153
  const stop = (): void => {
@@ -95,27 +161,51 @@ export function WorkflowRow({
95
161
  });
96
162
  }
97
163
  };
164
+ const failed = tool.state === 'error';
165
+ const header = (
166
+ <>
167
+ <span className={clsx(ROW_GUTTER, running && 'text-accent')}>
168
+ <Icon icon={Workflow} size={12} />
169
+ </span>
170
+ <span className={clsx('shrink-0', running && 'chat-live-text')}>{t(`rows.workflow.${running ? 'running' : failed ? 'failed' : 'done'}`)}</span>
171
+ <span className="grow" />
172
+ {counts.total > 0 && <Counts counts={counts} />}
173
+ {opens && <Icon icon={ChevronRight} size={12} className={clsx('shrink-0 text-text-faint transition-transform', open && 'rotate-90')} />}
174
+ </>
175
+ );
176
+ const headerClasses = clsx(
177
+ '-mx-1 flex h-7 w-[calc(100%+8px)] min-w-0 items-center gap-2 rounded-md px-1 text-left text-xs',
178
+ failed ? 'text-status-error' : 'text-text-muted',
179
+ opens && 'hover:bg-surface-hover'
180
+ );
98
181
  return (
99
- <div>
182
+ <div data-find-item={tool.id} className="mb-1">
100
183
  <div className="flex items-center gap-1">
101
184
  <div className="min-w-0 grow">
102
- {running ? <WorkLiveRow chatId={chatId ?? ''} tool={tool} /> : <WorkRow chatId={chatId} tool={tool} detail={workflow.name ?? undefined} />}
185
+ {opens ? (
186
+ <button className={headerClasses} onClick={() => setOpen((value) => !value)}>
187
+ {header}
188
+ </button>
189
+ ) : (
190
+ <div className={headerClasses}>{header}</div>
191
+ )}
103
192
  </div>
104
193
  {running && chatId && workflow.taskId && <IconButton icon={Square} size="xs" label={t('activity.stop')} onClick={stop} />}
105
194
  </div>
106
- {running && workflow.stalledAt !== undefined && (
107
- <p role="status" className="ml-6 mb-1 flex items-start gap-1.5 text-xs text-text-muted">
108
- <Icon icon={TriangleAlert} size={12} className="mt-0.5 shrink-0 text-status-needs-you" />
109
- <span>{t('rows.workflow.stalled')}</span>
110
- </p>
111
- )}
112
- {phases.length > 0 && (
113
- <div className="ml-6">
114
- {phases.map((phase) => (
115
- <PhaseBlock key={phase.key} phase={phase} onOpen={onOpen} />
116
- ))}
117
- </div>
118
- )}
195
+ {open && opens && <ToolBody tool={tool} />}
196
+ <div className="mt-1.5 ml-6">
197
+ {workflow.name !== null && <div className="truncate text-sm font-medium text-text">{workflow.name}</div>}
198
+ {description !== null && <p className="mt-0.5 line-clamp-2 text-xs text-text-muted">{description}</p>}
199
+ {running && workflow.stalledAt !== undefined && (
200
+ <p role="status" className="mt-1 flex items-start gap-1.5 text-xs text-text-muted">
201
+ <Icon icon={TriangleAlert} size={12} className="mt-0.5 shrink-0 text-status-needs-you" />
202
+ <span>{t('rows.workflow.stalled')}</span>
203
+ </p>
204
+ )}
205
+ {phases.map((phase) => (
206
+ <PhaseBlock key={phase.key} phase={phase} provider={provider} onOpen={onOpen} />
207
+ ))}
208
+ </div>
119
209
  </div>
120
210
  );
121
211
  }
@@ -1,4 +1,4 @@
1
- import { useCallback, useState } from 'react';
1
+ import { useState } from 'react';
2
2
 
3
3
  export interface ToggleSet {
4
4
  ids: ReadonlySet<string>;
@@ -15,25 +15,22 @@ export interface ToggleSet {
15
15
  export function useToggleSet(onToggle?: () => void): ToggleSet {
16
16
  const [ids, setIds] = useState<ReadonlySet<string>>(() => new Set());
17
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
- );
18
+ const toggle = (id: string): void => {
19
+ setIds((current) => {
20
+ const next = new Set(current);
21
+ if (next.has(id)) {
22
+ next.delete(id);
23
+ } else {
24
+ next.add(id);
25
+ }
26
+ return next;
27
+ });
28
+ onToggle?.();
29
+ };
33
30
 
34
- const add = useCallback((id: string): void => {
31
+ const add = (id: string): void => {
35
32
  setIds((current) => new Set(current).add(id));
36
- }, []);
33
+ };
37
34
 
38
35
  return { ids, toggle, add };
39
36
  }
@@ -1,7 +1,7 @@
1
1
  import { useLayoutEffect, useState, type RefObject } from 'react';
2
2
  import { cleanVisualVariables, type VisualAppearance, type VisualTheme, type VisualThemeVariable } from '@adecore/agent-contracts/visual';
3
- import { useChatHost } from '../../host';
4
3
  import { watchTheme } from './theme-watch';
4
+ import { useHostCodeMode } from '../../host-hooks';
5
5
 
6
6
  /* The tokens of the app's theme where a frame stands; each answers '' for a token the theme lacks. */
7
7
  export interface VisualTokens {
@@ -165,8 +165,7 @@ function readTheme(element: HTMLElement, mode: VisualAppearance): VisualTheme {
165
165
  * accent or a font a person picks reaches every frame as well.
166
166
  */
167
167
  export function useVisualTheme(ref: RefObject<HTMLElement | null>): VisualTheme | null {
168
- const host = useChatHost();
169
- const mode = host.code.useMode();
168
+ const mode = useHostCodeMode();
170
169
  const [theme, setTheme] = useState<VisualTheme | null>(null);
171
170
  useLayoutEffect(() => {
172
171
  const element = ref.current;
@@ -0,0 +1,113 @@
1
+ 'use no memo';
2
+ /*
3
+ * The hooks a host hands the views, each called through a hook of its own here. To the React Compiler a
4
+ * hook read from a context may be another function on the next render, so it leaves a component that
5
+ * calls one as written. `ChatHostProvider` pins its host and a command look's hooks stay with its row's
6
+ * key, so they never change under a mounted view; only these wrappers go uncompiled for it.
7
+ */
8
+ import type { ProviderPlatform } from '@adecore/agent-contracts';
9
+ import { useChatHost, type ChatHost, type CommandLook } from './host';
10
+
11
+ export function useHostCodeMode(): 'light' | 'dark' {
12
+ return useChatHost().code.useMode();
13
+ }
14
+
15
+ export function useHostCodeThemes(): { light: string; dark: string } {
16
+ return useChatHost().code.useThemes();
17
+ }
18
+
19
+ export function useHostAttachmentUrl(...args: Parameters<ChatHost['attachments']['useUrl']>): ReturnType<ChatHost['attachments']['useUrl']> {
20
+ return useChatHost().attachments.useUrl(...args);
21
+ }
22
+
23
+ export function useHostTasks(...args: Parameters<ChatHost['tasks']['useTasks']>): ReturnType<ChatHost['tasks']['useTasks']> {
24
+ return useChatHost().tasks.useTasks(...args);
25
+ }
26
+
27
+ export function useHostTask(...args: Parameters<ChatHost['tasks']['useTask']>): ReturnType<ChatHost['tasks']['useTask']> {
28
+ return useChatHost().tasks.useTask(...args);
29
+ }
30
+
31
+ export function useHostExtraPrompts(...args: Parameters<ChatHost['prompts']['useExtra']>): ReturnType<ChatHost['prompts']['useExtra']> {
32
+ return useChatHost().prompts.useExtra(...args);
33
+ }
34
+
35
+ export function useHostStreaming(): ReturnType<ChatHost['useStreaming']> {
36
+ return useChatHost().useStreaming();
37
+ }
38
+
39
+ export function useHostSendDelivery(): ReturnType<ChatHost['useSendDelivery']> {
40
+ return useChatHost().useSendDelivery();
41
+ }
42
+
43
+ export function useHostTimelineFind(...args: Parameters<ChatHost['useTimelineFind']>): ReturnType<ChatHost['useTimelineFind']> {
44
+ return useChatHost().useTimelineFind(...args);
45
+ }
46
+
47
+ export function useHostReferableChats(): ReturnType<ChatHost['useReferableChats']> {
48
+ return useChatHost().useReferableChats();
49
+ }
50
+
51
+ export function useHostLoginBlocked(...args: Parameters<ChatHost['useLoginBlocked']>): ReturnType<ChatHost['useLoginBlocked']> {
52
+ return useChatHost().useLoginBlocked(...args);
53
+ }
54
+
55
+ const noPlatform = (): ProviderPlatform | null => null;
56
+
57
+ /* Null where the host does not say, as it need not. */
58
+ export function useHostMachinePlatform(scopeId: string): ProviderPlatform | null {
59
+ const useMachinePlatform = useChatHost().useMachinePlatform ?? noPlatform;
60
+ return useMachinePlatform(scopeId);
61
+ }
62
+
63
+ export function useHostProjectLook(...args: Parameters<ChatHost['useProjectLook']>): ReturnType<ChatHost['useProjectLook']> {
64
+ return useChatHost().useProjectLook(...args);
65
+ }
66
+
67
+ export function useHostMachineLabel(...args: Parameters<ChatHost['useMachineLabel']>): ReturnType<ChatHost['useMachineLabel']> {
68
+ return useChatHost().useMachineLabel(...args);
69
+ }
70
+
71
+ export function useHostChatPlace(...args: Parameters<ChatHost['useChatPlace']>): ReturnType<ChatHost['useChatPlace']> {
72
+ return useChatHost().useChatPlace(...args);
73
+ }
74
+
75
+ export function useHostContextSources(...args: Parameters<ChatHost['useContextSources']>): ReturnType<ChatHost['useContextSources']> {
76
+ return useChatHost().useContextSources(...args);
77
+ }
78
+
79
+ export function useHostHidesFolder(...args: Parameters<ChatHost['useHidesFolder']>): ReturnType<ChatHost['useHidesFolder']> {
80
+ return useChatHost().useHidesFolder(...args);
81
+ }
82
+
83
+ export function useHostWelcome(...args: Parameters<ChatHost['useWelcome']>): ReturnType<ChatHost['useWelcome']> {
84
+ return useChatHost().useWelcome(...args);
85
+ }
86
+
87
+ export function useHostResumeAtReset(...args: Parameters<ChatHost['useResumeAtReset']>): ReturnType<ChatHost['useResumeAtReset']> {
88
+ return useChatHost().useResumeAtReset(...args);
89
+ }
90
+
91
+ export function useHostComposerPlaceholder(...args: Parameters<ChatHost['useComposerPlaceholder']>): ReturnType<ChatHost['useComposerPlaceholder']> {
92
+ return useChatHost().useComposerPlaceholder(...args);
93
+ }
94
+
95
+ export function useHostThreadCards(...args: Parameters<ChatHost['useThreadCards']>): ReturnType<ChatHost['useThreadCards']> {
96
+ return useChatHost().useThreadCards(...args);
97
+ }
98
+
99
+ export function useHostReplyAuthor(...args: Parameters<ChatHost['useReplyAuthor']>): ReturnType<ChatHost['useReplyAuthor']> {
100
+ return useChatHost().useReplyAuthor(...args);
101
+ }
102
+
103
+ export function useHostMapSource(maps: NonNullable<ChatHost['maps']>, scopeId: string): ReturnType<NonNullable<ChatHost['maps']>['useSource']> {
104
+ return maps.useSource(scopeId);
105
+ }
106
+
107
+ export function useCommandNames(
108
+ look: Required<Pick<CommandLook, 'useNames'>>,
109
+ scopeId: string,
110
+ chatId: string
111
+ ): ReturnType<NonNullable<CommandLook['useNames']>> {
112
+ return look.useNames(scopeId, chatId);
113
+ }
package/src/lazy.tsx CHANGED
@@ -58,6 +58,8 @@ export function lazyNamed<Module extends Record<Name, ComponentType<any>>, Name
58
58
  }
59
59
  });
60
60
  const LazyNamed = (props: ComponentProps<Module[Name]>) => {
61
+ // `loaded` fills in place; compiled, the element drawn before the module landed would stay.
62
+ 'use no memo';
61
63
  const Component: ComponentType<any> = loaded.current ?? Lazy;
62
64
  return <Component {...props} />;
63
65
  };