@adecore/agents-react 0.31.11 → 0.32.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 (404) hide show
  1. package/dist/agents/AccountDot.js +57 -6
  2. package/dist/agents/AgentIcon.js +88 -12
  3. package/dist/agents/ModelOptionControl.js +153 -18
  4. package/dist/agents/ProviderLogo.js +49 -4
  5. package/dist/agents/account-limits.js +17 -14
  6. package/dist/agents/accounts.js +99 -67
  7. package/dist/agents/agent-marks.js +5 -3
  8. package/dist/agents/model-name.js +42 -31
  9. package/dist/agents/model-options.js +8 -8
  10. package/dist/agents/model-requirement.js +17 -14
  11. package/dist/agents/option-words.d.ts +7 -0
  12. package/dist/agents/option-words.js +35 -0
  13. package/dist/agents/provider-paths.js +6 -6
  14. package/dist/agents/status-look.js +32 -12
  15. package/dist/chat/account-choice.d.ts +13 -0
  16. package/dist/chat/account-choice.js +90 -20
  17. package/dist/chat/actions.js +126 -59
  18. package/dist/chat/activity.js +5 -5
  19. package/dist/chat/attachments.js +74 -53
  20. package/dist/chat/bookmarks.js +58 -48
  21. package/dist/chat/chat-client.js +344 -263
  22. package/dist/chat/chat-references.js +3 -3
  23. package/dist/chat/composer-effort.d.ts +5 -0
  24. package/dist/chat/composer-effort.js +26 -0
  25. package/dist/chat/composer-send.js +13 -13
  26. package/dist/chat/drafts.js +115 -79
  27. package/dist/chat/forks.js +81 -24
  28. package/dist/chat/guards.js +15 -43
  29. package/dist/chat/index.d.ts +3 -1
  30. package/dist/chat/index.js +3 -2
  31. package/dist/chat/logic/ansi.js +170 -167
  32. package/dist/chat/logic/answers.js +2 -2
  33. package/dist/chat/logic/bookmarks.js +19 -19
  34. package/dist/chat/logic/command-looks.js +138 -96
  35. package/dist/chat/logic/context-usage.js +13 -9
  36. package/dist/chat/logic/continue-after-stop.js +15 -19
  37. package/dist/chat/logic/effort.d.ts +14 -0
  38. package/dist/chat/logic/effort.js +34 -0
  39. package/dist/chat/logic/embedded-code.js +387 -326
  40. package/dist/chat/logic/fork.js +134 -110
  41. package/dist/chat/logic/generated-image.js +54 -23
  42. package/dist/chat/logic/goal.js +28 -20
  43. package/dist/chat/logic/handback.js +6 -6
  44. package/dist/chat/logic/json.js +2 -2
  45. package/dist/chat/logic/limit.js +46 -30
  46. package/dist/chat/logic/picker-entries.d.ts +5 -3
  47. package/dist/chat/logic/picker-entries.js +83 -43
  48. package/dist/chat/logic/resume-compaction.d.ts +14 -1
  49. package/dist/chat/logic/resume-compaction.js +93 -24
  50. package/dist/chat/logic/scrubber.js +188 -136
  51. package/dist/chat/logic/thought.js +13 -16
  52. package/dist/chat/logic/thread-cards.js +60 -48
  53. package/dist/chat/logic/timeline-copy.js +30 -38
  54. package/dist/chat/logic/timeline-target.js +92 -63
  55. package/dist/chat/logic/timeline.js +499 -355
  56. package/dist/chat/logic/tool-catalog.js +54 -34
  57. package/dist/chat/logic/tools.js +106 -82
  58. package/dist/chat/logic/visual-height.js +18 -18
  59. package/dist/chat/logic/visual-viewport.js +6 -3
  60. package/dist/chat/logic/welcome.js +9 -9
  61. package/dist/chat/logic/workflow.js +45 -34
  62. package/dist/chat/mentions.js +149 -109
  63. package/dist/chat/persisted-json.js +51 -54
  64. package/dist/chat/preferences.d.ts +4 -0
  65. package/dist/chat/preferences.js +162 -84
  66. package/dist/chat/prompt-hold.js +9 -9
  67. package/dist/chat/quote.js +21 -30
  68. package/dist/chat/reading-width.js +12 -10
  69. package/dist/chat/recent-messages.js +34 -21
  70. package/dist/chat/resume-compaction-dismissals.js +25 -5
  71. package/dist/chat/runtime-modes.js +3 -3
  72. package/dist/chat/send-key.js +11 -7
  73. package/dist/chat/stash.js +89 -69
  74. package/dist/chat/subagent-conversation.js +181 -139
  75. package/dist/chat/subagent-list.js +65 -67
  76. package/dist/chat/subagent-support.js +12 -7
  77. package/dist/chat/subagent-view.js +132 -44
  78. package/dist/chat/thumbnails.js +88 -60
  79. package/dist/chat/timeline-flash.js +24 -12
  80. package/dist/chat/timeline-scroll.js +116 -86
  81. package/dist/chat/ui/AccountPill.js +126 -15
  82. package/dist/chat/ui/AnsiOutput.js +62 -6
  83. package/dist/chat/ui/BookmarkMarker.js +231 -41
  84. package/dist/chat/ui/BookmarkSubmenu.js +165 -18
  85. package/dist/chat/ui/ChatActivity.js +649 -70
  86. package/dist/chat/ui/ChatReferenceChip.js +104 -9
  87. package/dist/chat/ui/CodeBlock.js +132 -58
  88. package/dist/chat/ui/Composer.js +866 -132
  89. package/dist/chat/ui/ComposerInput.js +309 -120
  90. package/dist/chat/ui/DiffPool.js +75 -14
  91. package/dist/chat/ui/EditDiff.js +160 -21
  92. package/dist/chat/ui/FadingWords.js +32 -3
  93. package/dist/chat/ui/GoalDock.js +235 -42
  94. package/dist/chat/ui/ImageView.js +617 -61
  95. package/dist/chat/ui/LimitState.js +446 -72
  96. package/dist/chat/ui/Markdown.js +991 -173
  97. package/dist/chat/ui/MermaidBlock.js +238 -68
  98. package/dist/chat/ui/MessageActions.js +251 -39
  99. package/dist/chat/ui/ModelMarks.js +55 -5
  100. package/dist/chat/ui/Pickers.js +664 -113
  101. package/dist/chat/ui/PromptComposer.js +281 -51
  102. package/dist/chat/ui/QuoteButton.js +151 -57
  103. package/dist/chat/ui/ResumeCompactionDock.d.ts +6 -2
  104. package/dist/chat/ui/ResumeCompactionDock.js +141 -6
  105. package/dist/chat/ui/RowTime.js +59 -5
  106. package/dist/chat/ui/RunSettings.js +1744 -154
  107. package/dist/chat/ui/Scrubber.js +517 -88
  108. package/dist/chat/ui/ShellCommand.js +183 -107
  109. package/dist/chat/ui/SubagentControls.js +212 -24
  110. package/dist/chat/ui/SubagentInfo.js +170 -13
  111. package/dist/chat/ui/SubagentStopButton.js +115 -24
  112. package/dist/chat/ui/SubagentTimeline.js +357 -91
  113. package/dist/chat/ui/Timeline.js +988 -476
  114. package/dist/chat/ui/TimelineMenu.js +552 -37
  115. package/dist/chat/ui/UnifiedDiff.js +234 -27
  116. package/dist/chat/ui/UploadThumb.js +37 -7
  117. package/dist/chat/ui/VisualDialogs.js +251 -20
  118. package/dist/chat/ui/VisualFrame.js +321 -95
  119. package/dist/chat/ui/Welcome.js +72 -7
  120. package/dist/chat/ui/chips.js +1 -1
  121. package/dist/chat/ui/code-lines.js +36 -36
  122. package/dist/chat/ui/code-streaming.js +1 -1
  123. package/dist/chat/ui/code-theme.js +7 -7
  124. package/dist/chat/ui/composer/ComposerControls.js +329 -21
  125. package/dist/chat/ui/composer/ComposerMenu.js +358 -30
  126. package/dist/chat/ui/composer/DraftParts.js +185 -11
  127. package/dist/chat/ui/composer/QueuedMessages.js +138 -13
  128. package/dist/chat/ui/composer/chips.js +29 -19
  129. package/dist/chat/ui/composer/editor.js +79 -63
  130. package/dist/chat/ui/composer/insert.js +26 -12
  131. package/dist/chat/ui/composer/key-handler.js +180 -127
  132. package/dist/chat/ui/composer/keys.js +90 -73
  133. package/dist/chat/ui/composer/menu-aria.js +18 -9
  134. package/dist/chat/ui/composer/placeholder.js +78 -31
  135. package/dist/chat/ui/composer/surface.js +13 -37
  136. package/dist/chat/ui/composer/use-chat-controls.js +230 -90
  137. package/dist/chat/ui/composer/use-compaction-offer.js +50 -18
  138. package/dist/chat/ui/composer/use-composer-draft.js +65 -34
  139. package/dist/chat/ui/composer/use-composer-menus.js +478 -193
  140. package/dist/chat/ui/composer/use-composer-submit.js +251 -109
  141. package/dist/chat/ui/composer/use-continuable-turn.js +33 -6
  142. package/dist/chat/ui/composer/use-draft-files.js +245 -93
  143. package/dist/chat/ui/composer/use-effort-stepper.d.ts +13 -0
  144. package/dist/chat/ui/composer/use-effort-stepper.js +88 -0
  145. package/dist/chat/ui/composer/use-notice.js +61 -16
  146. package/dist/chat/ui/composer/use-pending-requests.js +38 -17
  147. package/dist/chat/ui/composer/use-prompt-history.js +117 -45
  148. package/dist/chat/ui/composer/use-prompt-hold.js +119 -35
  149. package/dist/chat/ui/composer/use-take-back.js +94 -72
  150. package/dist/chat/ui/diff/ApprovalReview.js +101 -23
  151. package/dist/chat/ui/diff/DiffFallbackBoundary.js +21 -13
  152. package/dist/chat/ui/diff/DiffOmitted.js +56 -6
  153. package/dist/chat/ui/diff/DiffStack.js +92 -8
  154. package/dist/chat/ui/diff/DiffUnavailable.js +56 -6
  155. package/dist/chat/ui/diff/EditorEditDiff.js +263 -51
  156. package/dist/chat/ui/diff/EditorPatchDiff.js +39 -14
  157. package/dist/chat/ui/diff/LegacyDiffPool.js +27 -10
  158. package/dist/chat/ui/diff/LegacyEditDiff.js +97 -20
  159. package/dist/chat/ui/diff/LegacyUnifiedDiff.js +172 -42
  160. package/dist/chat/ui/diff/RawDiff.js +65 -5
  161. package/dist/chat/ui/diff/ReviewDiff.js +77 -5
  162. package/dist/chat/ui/diff/diff-props.js +1 -1
  163. package/dist/chat/ui/diff/diff-source-budget.js +46 -35
  164. package/dist/chat/ui/diff/editor-edit-model.js +18 -14
  165. package/dist/chat/ui/diff/review-plan.js +63 -40
  166. package/dist/chat/ui/diff/review-settle.js +24 -9
  167. package/dist/chat/ui/diff/syntax-runtime.js +236 -201
  168. package/dist/chat/ui/diff/use-review-stack.js +146 -25
  169. package/dist/chat/ui/diff-syntax.js +70 -58
  170. package/dist/chat/ui/diff-theme.js +31 -12
  171. package/dist/chat/ui/file-links.js +39 -10
  172. package/dist/chat/ui/find-reveal.js +29 -8
  173. package/dist/chat/ui/full-diff.js +17 -12
  174. package/dist/chat/ui/highlighter.js +143 -113
  175. package/dist/chat/ui/icons.js +16 -7
  176. package/dist/chat/ui/index.js +1 -1
  177. package/dist/chat/ui/intelligent-ui/UiBlockFrame.js +556 -82
  178. package/dist/chat/ui/intelligent-ui/UiFallbackPart.js +73 -5
  179. package/dist/chat/ui/intelligent-ui/UiReply.js +666 -262
  180. package/dist/chat/ui/intelligent-ui/block-local.js +59 -31
  181. package/dist/chat/ui/intelligent-ui/chart-data.js +77 -67
  182. package/dist/chat/ui/intelligent-ui/node-text.js +77 -91
  183. package/dist/chat/ui/intelligent-ui/registry.js +46 -46
  184. package/dist/chat/ui/intelligent-ui/render-context.js +1 -1
  185. package/dist/chat/ui/intelligent-ui/renderers/base-land.js +1 -1
  186. package/dist/chat/ui/intelligent-ui/renderers/binding.js +3 -3
  187. package/dist/chat/ui/intelligent-ui/renderers/chart.js +1223 -123
  188. package/dist/chat/ui/intelligent-ui/renderers/choices.js +312 -34
  189. package/dist/chat/ui/intelligent-ui/renderers/content.js +1241 -86
  190. package/dist/chat/ui/intelligent-ui/renderers/data.js +619 -54
  191. package/dist/chat/ui/intelligent-ui/renderers/inputs.js +868 -67
  192. package/dist/chat/ui/intelligent-ui/renderers/links.js +366 -62
  193. package/dist/chat/ui/intelligent-ui/renderers/map-slots.js +118 -60
  194. package/dist/chat/ui/intelligent-ui/renderers/map-style.js +85 -78
  195. package/dist/chat/ui/intelligent-ui/renderers/map-view.js +282 -217
  196. package/dist/chat/ui/intelligent-ui/renderers/map.js +621 -69
  197. package/dist/chat/ui/intelligent-ui/renderers/place-point.js +15 -8
  198. package/dist/chat/ui/intelligent-ui/renderers/structure.js +262 -20
  199. package/dist/chat/ui/intelligent-ui/renderers/text.js +674 -49
  200. package/dist/chat/ui/intelligent-ui/reply-parts.js +24 -15
  201. package/dist/chat/ui/intelligent-ui/table-data.js +97 -57
  202. package/dist/chat/ui/intelligent-ui/tones.js +31 -31
  203. package/dist/chat/ui/intelligent-ui/use-in-view.js +30 -12
  204. package/dist/chat/ui/intelligent-ui/use-later.js +28 -13
  205. package/dist/chat/ui/intelligent-ui/use-truncated.js +45 -21
  206. package/dist/chat/ui/intelligent-ui/use-ui-links.js +296 -109
  207. package/dist/chat/ui/intelligent-ui/use-ui-queries.js +256 -246
  208. package/dist/chat/ui/markdown-blocks.js +296 -262
  209. package/dist/chat/ui/mermaid.js +60 -72
  210. package/dist/chat/ui/quote-selection.js +32 -29
  211. package/dist/chat/ui/rehype-chips.js +35 -23
  212. package/dist/chat/ui/rehype-fade.js +28 -17
  213. package/dist/chat/ui/remark-html-as-text.js +22 -15
  214. package/dist/chat/ui/reply-context.js +1 -1
  215. package/dist/chat/ui/reveal.js +161 -72
  216. package/dist/chat/ui/rows/ForksRow.js +226 -24
  217. package/dist/chat/ui/rows/GeneratedImageRow.js +541 -87
  218. package/dist/chat/ui/rows/MessageRows.js +1706 -159
  219. package/dist/chat/ui/rows/RowContainer.js +57 -7
  220. package/dist/chat/ui/rows/Rows.js +463 -54
  221. package/dist/chat/ui/rows/SubagentRow.js +577 -60
  222. package/dist/chat/ui/rows/TaskRow.js +359 -40
  223. package/dist/chat/ui/rows/VisualRow.js +233 -11
  224. package/dist/chat/ui/rows/WorkRows.js +1946 -163
  225. package/dist/chat/ui/rows/WorkflowRow.js +293 -34
  226. package/dist/chat/ui/rows/row-rhythm.js +27 -17
  227. package/dist/chat/ui/theme-watch.js +26 -23
  228. package/dist/chat/ui/timestamp-format.js +4 -1
  229. package/dist/chat/ui/use-diff-source-tokens.js +70 -34
  230. package/dist/chat/ui/useToggleSet.js +51 -19
  231. package/dist/chat/ui/visual-theme.js +153 -128
  232. package/dist/chat/visual-bridge.js +123 -123
  233. package/dist/chat/visual-viewport.js +94 -83
  234. package/dist/chat/visuals.js +13 -5
  235. package/dist/host-hooks.d.ts +29 -0
  236. package/dist/host-hooks.js +78 -0
  237. package/dist/host.js +120 -48
  238. package/dist/index.js +1 -1
  239. package/dist/lazy.js +38 -32
  240. package/dist/locales/en/agent-chat.d.ts +35 -0
  241. package/dist/locales/en/agent-chat.js +747 -712
  242. package/dist/locales/en/agent-prompts.js +42 -42
  243. package/dist/locales/en/agent-providers.d.ts +1 -0
  244. package/dist/locales/en/agent-providers.js +166 -165
  245. package/dist/locales/en/agent-usage.d.ts +6 -0
  246. package/dist/locales/en/agent-usage.js +129 -123
  247. package/dist/locales/nl/agent-chat.d.ts +35 -0
  248. package/dist/locales/nl/agent-chat.js +747 -712
  249. package/dist/locales/nl/agent-prompts.js +42 -42
  250. package/dist/locales/nl/agent-providers.d.ts +1 -0
  251. package/dist/locales/nl/agent-providers.js +166 -165
  252. package/dist/locales/nl/agent-usage.d.ts +6 -0
  253. package/dist/locales/nl/agent-usage.js +129 -123
  254. package/dist/locales.js +14 -14
  255. package/dist/mounted-registry.js +31 -30
  256. package/dist/port-transport.js +122 -111
  257. package/dist/prompts/index.js +1 -1
  258. package/dist/prompts/logic/focus.js +15 -14
  259. package/dist/prompts/logic/keys.js +93 -59
  260. package/dist/prompts/logic/prompts.js +27 -14
  261. package/dist/prompts/logic/subjects.js +60 -46
  262. package/dist/prompts/logic/useFocusAfterAnswer.js +60 -20
  263. package/dist/prompts/logic/usePromptSession.js +88 -77
  264. package/dist/prompts/ui/ApprovalBody.js +246 -25
  265. package/dist/prompts/ui/PromptActions.js +215 -9
  266. package/dist/prompts/ui/PromptCard.js +215 -36
  267. package/dist/prompts/ui/PromptView.js +372 -34
  268. package/dist/prompts/ui/QuestionBody.js +269 -73
  269. package/dist/providers/AccountColors.js +36 -5
  270. package/dist/providers/AccountDetail.js +683 -50
  271. package/dist/providers/AccountVariables.js +139 -32
  272. package/dist/providers/AddAccountForm.js +125 -38
  273. package/dist/providers/CliDetail.js +343 -36
  274. package/dist/providers/InstallPage.js +644 -59
  275. package/dist/providers/ProviderList.d.ts +2 -1
  276. package/dist/providers/ProviderList.js +215 -23
  277. package/dist/providers/ProvidersPane.d.ts +4 -2
  278. package/dist/providers/ProvidersPane.js +244 -64
  279. package/dist/providers/account-actions.js +54 -30
  280. package/dist/providers/index.js +1 -1
  281. package/dist/providers/install-steps.js +12 -9
  282. package/dist/providers/pane-target.d.ts +3 -0
  283. package/dist/providers/pane-target.js +34 -13
  284. package/dist/providers/parts.js +62 -12
  285. package/dist/providers/provider-abilities.js +5 -5
  286. package/dist/providers/provider-groups.js +75 -40
  287. package/dist/providers/variables.js +73 -39
  288. package/dist/scope.js +6 -6
  289. package/dist/settings/sections.js +18 -18
  290. package/dist/state/chats.d.ts +1 -0
  291. package/dist/state/chats.js +408 -192
  292. package/dist/state/index.js +1 -1
  293. package/dist/state/provider-accounts.js +70 -47
  294. package/dist/state/providers.js +45 -16
  295. package/dist/state/usage.js +154 -77
  296. package/dist/storage.js +69 -68
  297. package/dist/testing/index.js +1 -1
  298. package/dist/testing/prompts.js +105 -67
  299. package/dist/transport.js +10 -10
  300. package/dist/ui/PlainTextarea.js +27 -3
  301. package/dist/usage/LimitsList.js +646 -40
  302. package/dist/usage/UsageBreakdown.js +879 -38
  303. package/dist/usage/UsageChart.js +311 -32
  304. package/dist/usage/UsageDialog.js +46 -4
  305. package/dist/usage/UsageLimits.js +467 -34
  306. package/dist/usage/UsageLimitsCard.js +95 -11
  307. package/dist/usage/UsagePage.js +817 -96
  308. package/dist/usage/UsagePane.js +164 -10
  309. package/dist/usage/UsageSummary.js +151 -6
  310. package/dist/usage/UsageTiles.js +164 -14
  311. package/dist/usage/format.js +32 -32
  312. package/dist/usage/index.d.ts +1 -1
  313. package/dist/usage/index.js +2 -1
  314. package/dist/usage/limit-groups.d.ts +2 -0
  315. package/dist/usage/limit-groups.js +77 -59
  316. package/dist/usage/limits.js +78 -43
  317. package/dist/usage/money.js +20 -4
  318. package/dist/usage/summary.js +85 -64
  319. package/package.json +8 -8
  320. package/src/agents/ModelOptionControl.tsx +3 -1
  321. package/src/agents/option-words.ts +27 -0
  322. package/src/chat/account-choice.ts +41 -1
  323. package/src/chat/composer-effort.ts +32 -0
  324. package/src/chat/forks.ts +4 -5
  325. package/src/chat/index.ts +3 -1
  326. package/src/chat/logic/effort.ts +32 -0
  327. package/src/chat/logic/picker-entries.ts +45 -10
  328. package/src/chat/logic/resume-compaction.ts +95 -17
  329. package/src/chat/logic/timeline.ts +11 -3
  330. package/src/chat/preferences.ts +35 -0
  331. package/src/chat/subagent-view.ts +2 -3
  332. package/src/chat/ui/AnsiOutput.tsx +1 -2
  333. package/src/chat/ui/BookmarkSubmenu.tsx +3 -3
  334. package/src/chat/ui/ChatActivity.tsx +14 -22
  335. package/src/chat/ui/ChatReferenceChip.tsx +2 -3
  336. package/src/chat/ui/Composer.tsx +15 -7
  337. package/src/chat/ui/EditDiff.tsx +2 -3
  338. package/src/chat/ui/LimitState.tsx +2 -2
  339. package/src/chat/ui/Markdown.tsx +10 -8
  340. package/src/chat/ui/MermaidBlock.tsx +2 -3
  341. package/src/chat/ui/Pickers.tsx +49 -29
  342. package/src/chat/ui/PromptComposer.tsx +7 -9
  343. package/src/chat/ui/ResumeCompactionDock.tsx +16 -4
  344. package/src/chat/ui/RunSettings.tsx +67 -28
  345. package/src/chat/ui/Scrubber.tsx +3 -3
  346. package/src/chat/ui/ShellCommand.tsx +2 -0
  347. package/src/chat/ui/SubagentInfo.tsx +2 -3
  348. package/src/chat/ui/SubagentTimeline.tsx +12 -16
  349. package/src/chat/ui/Timeline.tsx +6 -6
  350. package/src/chat/ui/UnifiedDiff.tsx +3 -4
  351. package/src/chat/ui/VisualFrame.tsx +5 -8
  352. package/src/chat/ui/code-theme.ts +4 -4
  353. package/src/chat/ui/composer/placeholder.ts +2 -2
  354. package/src/chat/ui/composer/use-compaction-offer.ts +36 -16
  355. package/src/chat/ui/composer/use-composer-menus.ts +4 -9
  356. package/src/chat/ui/composer/use-composer-submit.ts +2 -1
  357. package/src/chat/ui/composer/use-effort-stepper.ts +56 -0
  358. package/src/chat/ui/composer/use-notice.ts +2 -2
  359. package/src/chat/ui/diff/EditorEditDiff.tsx +9 -13
  360. package/src/chat/ui/diff/LegacyEditDiff.tsx +12 -17
  361. package/src/chat/ui/diff/LegacyUnifiedDiff.tsx +13 -21
  362. package/src/chat/ui/diff/use-review-stack.ts +4 -4
  363. package/src/chat/ui/diff-theme.ts +3 -3
  364. package/src/chat/ui/file-links.ts +2 -2
  365. package/src/chat/ui/intelligent-ui/UiReply.tsx +2 -0
  366. package/src/chat/ui/intelligent-ui/renderers/chart.tsx +3 -3
  367. package/src/chat/ui/intelligent-ui/renderers/content.tsx +5 -6
  368. package/src/chat/ui/intelligent-ui/renderers/map-view.tsx +2 -1
  369. package/src/chat/ui/intelligent-ui/renderers/map.tsx +2 -1
  370. package/src/chat/ui/intelligent-ui/use-truncated.ts +16 -19
  371. package/src/chat/ui/intelligent-ui/use-ui-links.ts +3 -3
  372. package/src/chat/ui/rows/ForksRow.tsx +3 -5
  373. package/src/chat/ui/rows/GeneratedImageRow.tsx +2 -1
  374. package/src/chat/ui/rows/MessageRows.tsx +12 -21
  375. package/src/chat/ui/rows/SubagentRow.tsx +3 -3
  376. package/src/chat/ui/rows/TaskRow.tsx +1 -1
  377. package/src/chat/ui/rows/WorkRows.tsx +20 -7
  378. package/src/chat/ui/useToggleSet.ts +15 -18
  379. package/src/chat/ui/visual-theme.ts +2 -3
  380. package/src/host-hooks.ts +113 -0
  381. package/src/lazy.tsx +2 -0
  382. package/src/locales/en/agent-chat.ts +135 -108
  383. package/src/locales/en/agent-prompts.ts +7 -7
  384. package/src/locales/en/agent-providers.ts +35 -34
  385. package/src/locales/en/agent-usage.ts +26 -20
  386. package/src/locales/nl/agent-chat.ts +127 -100
  387. package/src/locales/nl/agent-prompts.ts +5 -5
  388. package/src/locales/nl/agent-providers.ts +33 -32
  389. package/src/locales/nl/agent-usage.ts +25 -20
  390. package/src/prompts/ui/ApprovalBody.tsx +3 -1
  391. package/src/providers/CliDetail.tsx +2 -1
  392. package/src/providers/InstallPage.tsx +2 -4
  393. package/src/providers/ProviderList.tsx +12 -2
  394. package/src/providers/ProvidersPane.tsx +45 -15
  395. package/src/providers/pane-target.ts +20 -4
  396. package/src/state/chats.ts +7 -2
  397. package/src/usage/LimitsList.tsx +12 -13
  398. package/src/usage/UsageBreakdown.tsx +17 -6
  399. package/src/usage/UsageLimits.tsx +2 -1
  400. package/src/usage/UsagePage.tsx +3 -3
  401. package/src/usage/index.ts +1 -1
  402. package/src/usage/limit-groups.ts +12 -0
  403. package/src/usage/limits.ts +2 -2
  404. package/src/usage/money.ts +1 -2
@@ -1,7 +1,7 @@
1
1
  export default {
2
2
  status: {
3
3
  checking: 'Controleren',
4
- disabled: 'Uitgezet',
4
+ disabled: 'Uit',
5
5
  notFound: 'CLI niet gevonden',
6
6
  signedOut: 'Niet ingelogd',
7
7
  ready: 'Ingelogd',
@@ -11,23 +11,24 @@ export default {
11
11
  unavailable: 'Niet beschikbaar',
12
12
  failed: 'Controle mislukt'
13
13
  },
14
- failed: 'De instellingen van de providers konden niet worden getekend',
14
+ failed: 'Kon de providerinstellingen niet tonen',
15
15
  list: {
16
- label: "Agent-CLI's en hun accounts",
16
+ label: 'Agents en hun accounts',
17
17
  default: 'Standaard',
18
18
  ready: 'Klaar',
19
19
  needsSetup: 'Nog instellen',
20
- signedOut: 'Uitgelogd',
21
- addAccount: 'Een {{provider}}-account toevoegen',
20
+ signedOut: 'Niet ingelogd',
21
+ addAccount: '{{provider}}-account toevoegen',
22
+ addProvider: 'Provider toevoegen',
22
23
  notInstalled: 'Niet geïnstalleerd',
23
24
  missing: 'Ontbreekt',
24
- notInstalledNote: 'Installeer er een op deze machine om hem hier te gebruiken.',
25
- none: "Geen agent-CLI's gevonden op deze machine.",
26
- noAccounts: 'Deze machine houdt nog geen accounts bij. Werk Ruimte daar bij om er een toe te voegen.'
25
+ notInstalledNote: 'Installeer om hem hier te gebruiken.',
26
+ none: 'Geen agents gevonden op deze machine.',
27
+ noAccounts: 'Werk Ruimte op deze machine bij om accounts toe te voegen.'
27
28
  },
28
29
  install: {
29
30
  notInstalled: 'Niet geïnstalleerd',
30
- steps: '{{provider}} instellen in stappen',
31
+ steps: '{{provider}} instellen',
31
32
  platform: 'Systeem',
32
33
  platforms: {
33
34
  darwin: 'macOS',
@@ -40,38 +41,38 @@ export default {
40
41
  guide: 'Installatiegids',
41
42
  install: {
42
43
  title: 'Installeer de CLI',
43
- none: 'Er is geen installatiecommando voor dit systeem.',
44
+ none: 'Geen installatiecommando voor dit systeem.',
44
45
  done: 'Geïnstalleerd, versie {{version}}.',
45
46
  doneNoVersion: 'Geïnstalleerd.'
46
47
  },
47
48
  signIn: {
48
49
  title: 'Log in',
49
- command: 'Voer dit uit in een terminal en volg de stappen:',
50
+ command: 'Voer dit uit in een terminal:',
50
51
  env: 'Zet <code>{{variable}}</code> in de omgeving waarin de CLI start.',
51
52
  chat: 'De eerste chat vraagt je om in te loggen.',
52
53
  or: 'Of',
53
- unknown: 'De CLI vraagt je om in te loggen als hij voor het eerst draait.'
54
+ unknown: 'Vraagt bij de eerste start om in te loggen.'
54
55
  },
55
56
  start: {
56
57
  title: 'Aan de slag',
57
58
  description: 'Kies {{provider}} voor je volgende chat of terminal.'
58
59
  },
59
60
  footer: {
60
- missing: 'Nog niet gevonden op deze machine. Er wordt opnieuw gekeken als je terugkomt in dit venster.',
61
+ missing: 'Nog niet gevonden. Ruimte kijkt opnieuw als je terugkomt in dit venster.',
61
62
  found: 'Gevonden op deze machine.'
62
63
  },
63
- fallback: 'Installeer {{provider}} op deze machine om hem hier te gebruiken.'
64
+ fallback: 'Installeer {{provider}} om hem hier te gebruiken.'
64
65
  },
65
66
  abilities: {
66
67
  version: 'Versie {{version}}.',
67
68
  chatAndTerminal: 'Chat en terminal.',
68
69
  terminalOnly: 'Alleen terminal.',
69
- reportsStatus: 'Meldt de agentstatus.',
70
- noStatus: 'Meldt geen agentstatus.'
70
+ reportsStatus: 'Laat zien wanneer hij je nodig heeft.',
71
+ noStatus: 'Laat niet zien wanneer hij je nodig heeft.'
71
72
  },
72
73
  cli: {
73
74
  addAccount: 'Account toevoegen',
74
- onlyDefault: '{{provider}} heeft geen instelling voor zijn configuratiemap, dus alleen zijn standaardaccount.',
75
+ onlyDefault: '{{provider}} kent alleen zijn standaardaccount.',
75
76
  defaults: {
76
77
  title: 'Standaarden voor nieuwe chats',
77
78
  description: 'Een model of account kiezen in een chat verandert hier ook de standaard.',
@@ -90,7 +91,7 @@ export default {
90
91
  kind: '{{provider}}-account',
91
92
  enabled: {
92
93
  label: 'Dit account gebruiken',
93
- description: 'Uitgezet wordt het niet aangeboden voor nieuwe chats en agents.'
94
+ description: 'Staat het uit, dan zien nieuwe chats en agents het niet.'
94
95
  },
95
96
  showFolder: 'Map tonen',
96
97
  folderCopied: 'Pad van de map gekopieerd',
@@ -100,14 +101,14 @@ export default {
100
101
  title: 'Login',
101
102
  signedInAs: 'Ingelogd als {{email}}',
102
103
  signedIn: 'Ingelogd',
103
- planDetail: '{{plan}}-abonnement. Opnieuw inloggen opent een terminal met de login van de CLI zelf.',
104
- detail: 'Opnieuw inloggen opent een terminal met de login van de CLI zelf.',
104
+ planDetail: '{{plan}}-abonnement. Opnieuw inloggen opent een terminal.',
105
+ detail: 'Opnieuw inloggen opent een terminal.',
105
106
  signedOut: 'Niet ingelogd',
106
- signedOutDetail: 'Opent een terminal die de login van de CLI met deze map draait.',
107
+ signedOutDetail: 'Opent een terminal waarin je inlogt op dit account.',
107
108
  logIn: 'Inloggen',
108
109
  logInAgain: 'Opnieuw inloggen',
109
110
  inChat: 'Logt in vanuit een chat',
110
- inChatDetail: 'De eerste chat op dit account vraagt je in te loggen, en de CLI bewaart die login in deze map.'
111
+ inChatDetail: 'De eerste chat op dit account vraagt je in te loggen.'
111
112
  },
112
113
  folder: {
113
114
  label: 'Map',
@@ -116,14 +117,14 @@ export default {
116
117
  },
117
118
  variables: {
118
119
  title: 'Variabelen',
119
- description: 'Extra omgeving voor alleen dit account. Gevoelige waarden blijven in de sleutelhanger.',
120
+ description: 'Extra omgeving voor dit account. Geheimen blijven in de sleutelhanger.',
120
121
  add: 'Variabele toevoegen',
121
122
  name: 'Naam van variabele {{index}}',
122
123
  value: 'Waarde van {{name}}',
123
124
  kept: 'Bewaard in de sleutelhanger',
124
125
  lock: '{{name}} in de sleutelhanger bewaren',
125
126
  unlock: '{{name}} als platte tekst bewaren',
126
- noKeychain: 'Deze machine heeft geen sleutelhanger, dus een waarde kan niet geheim blijven.',
127
+ noKeychain: 'Geen sleutelhanger op deze machine, dus waarden blijven leesbaar.',
127
128
  remove: '{{name}} verwijderen',
128
129
  none: 'Geen variabelen',
129
130
  discard: 'Weggooien',
@@ -137,25 +138,25 @@ export default {
137
138
  remove: {
138
139
  label: 'Account verwijderen',
139
140
  description: 'Chats die het gebruiken vragen bij hun volgende turn om een ander account. De map blijft op de schijf.',
140
- defaultNote: 'Het standaardaccount gebruikt de eigen map van de CLI en kan niet weg. Zet het in plaats daarvan hierboven uit.',
141
+ defaultNote: 'Het standaardaccount kan niet weg. Zet het hierboven uit.',
141
142
  button: 'Verwijderen',
142
143
  confirmTitle: '{{account}} verwijderen?',
143
- confirmDescription: 'Ruimte vergeet dit account. De map blijft op de schijf staan op {{folder}}, met de login erin.',
144
+ confirmDescription: 'De map en de login blijven in {{folder}}.',
144
145
  confirm: 'Account verwijderen'
145
146
  },
146
147
  saveFailed: 'Kon het account niet opslaan'
147
148
  },
148
149
  add: {
149
- title: 'Een {{provider}}-account toevoegen',
150
- description: 'Ruimte maakt er een map voor op de machine en opent dan een terminal waarin je inlogt.',
151
- chatDescription: 'Er komt een map voor op de machine. De eerste chat erop vraagt je in te loggen.',
150
+ title: '{{provider}}-account toevoegen',
151
+ description: 'Maakt een map en opent een terminal om in te loggen.',
152
+ chatDescription: 'Maakt een map. De eerste chat vraagt je in te loggen.',
152
153
  name: 'Naam',
153
154
  namePlaceholder: 'Werk',
154
155
  color: 'Kleur',
155
156
  advanced: 'Geavanceerd',
156
157
  link: {
157
158
  label: 'Een bestaande map koppelen',
158
- description: 'Gebruik een configuratiemap die al op de machine staat in plaats van een nieuwe. Ruimte verplaatst of verwijdert hem nooit.',
159
+ description: 'Gebruik een bestaande configuratiemap. Ruimte verplaatst of verwijdert hem nooit.',
159
160
  placeholder: 'Pad op de machine'
160
161
  },
161
162
  create: 'Account toevoegen',
@@ -164,9 +165,9 @@ export default {
164
165
  },
165
166
  section: {
166
167
  label: 'Providers',
167
- description: "De agent-CLI's op deze machine en de accounts waarmee ze inloggen."
168
+ description: 'Agents op deze machine en hun accounts.'
168
169
  },
169
- notAnswering: 'Geeft geen antwoord. Pas dit aan zodra de machine terug is.',
170
+ notAnswering: 'De machine geeft geen antwoord. Probeer het opnieuw zodra hij terug is.',
170
171
  common: {
171
172
  save: 'Opslaan',
172
173
  cancel: 'Annuleren'
@@ -1,22 +1,27 @@
1
1
  export default {
2
2
  limits: {
3
3
  title: 'Limieten',
4
- explain:
5
- 'Het streepje op een balk laat zien hoeveel van het venster voorbij is. Een balk voorbij dat streepje verbruikt sneller dan het venster teruggeeft.',
4
+ explain: 'De markering toont waar het verbruik bij een gelijk tempo zou staan. Voorbij de markering verbruik je sneller dan het weer vrijkomt.',
6
5
  loading: 'Limieten laden…',
7
6
  used: '{{percent}}% gebruikt',
8
7
  bar: '{{window}}, {{percent}}% gebruikt',
9
8
  windowPassed: '{{percent}}% van het venster voorbij',
10
- faster: 'Verbruikt sneller dan het venster teruggeeft.',
11
- slower: 'Verbruikt langzamer dan het venster teruggeeft.',
9
+ faster: 'Sneller verbruikt dan het weer vrijkomt.',
10
+ slower: 'Langzamer verbruikt dan het weer vrijkomt.',
11
+ pace: {
12
+ ahead: '{{percent}}% gebruikt, voor op een gelijkmatig tempo van {{pace}}%',
13
+ behind: '{{percent}}% gebruikt, achter op een gelijkmatig tempo van {{pace}}%',
14
+ even: '{{percent}}% gebruikt, op een gelijkmatig tempo'
15
+ },
16
+ even: 'Even snel verbruikt als het vrijkomt.',
12
17
  resets: 'Reset {{at}}',
13
18
  none: 'Nog geen limieten gemeld.',
14
19
  notInstalled: 'Niet geïnstalleerd op deze machine.',
15
- noSubscription: 'Dit account gebruikt een API-sleutel en kent geen abonnementslimieten.',
16
- unreachable: 'De CLI was niet bereikbaar.',
17
- filter: 'Accounts waarvan je de limieten ziet',
20
+ noSubscription: 'API-sleutel, geen abonnementslimieten.',
21
+ unreachable: 'Kon de limieten niet ophalen.',
22
+ filter: 'Getoonde accounts',
18
23
  signedOut: 'Niet ingelogd',
19
- signedOutDetail: 'Niet ingelogd. Log in om de limieten te zien.',
24
+ signedOutDetail: 'Niet ingelogd. Log in om limieten te zien.',
20
25
  logIn: 'Inloggen',
21
26
  nextReset: '{{window}} reset {{at}}',
22
27
  checked: {
@@ -29,8 +34,8 @@ export default {
29
34
  currency: {
30
35
  label: 'Valuta',
31
36
  dollars: 'Prijzen zoals gepubliceerd, in dollars.',
32
- noRate: 'Nog geen wisselkoers. De pagina toont dollars zolang die er niet is.',
33
- converted: 'Omgerekend met de ECB-referentiekoers van {{date}}.',
37
+ noRate: 'Nog geen wisselkoers. Bedragen in dollars.',
38
+ converted: 'Omgerekend met de ECB-koers van {{date}}.',
34
39
  options: {
35
40
  USD: 'Dollars',
36
41
  EUR: "Euro's"
@@ -44,7 +49,7 @@ export default {
44
49
  },
45
50
  section: {
46
51
  label: 'Verbruik',
47
- description: 'De valuta van de verbruikspagina.'
52
+ description: 'Valuta van de verbruikspagina.'
48
53
  },
49
54
  dialog: {
50
55
  title: 'Verbruik',
@@ -53,7 +58,7 @@ export default {
53
58
  rescan: 'Opnieuw scannen',
54
59
  period: 'Periode',
55
60
  metric: 'Eenheid',
56
- failed: 'Verbruik kon niet worden getekend',
61
+ failed: 'Kon het verbruik niet tonen',
57
62
  periods: {
58
63
  today: 'Vandaag',
59
64
  '7d': '7 dagen',
@@ -70,20 +75,20 @@ export default {
70
75
  }
71
76
  },
72
77
  empty: {
73
- noTranscripts: 'Geen transcripts van Claude of Codex gevonden. De machine leest ~/.claude/projects en ~/.codex/sessions.',
74
- noUsage: 'Nog geen verbruik op deze machine.'
78
+ noTranscripts: 'Nog geen chats van Claude of Codex gevonden op deze machine.',
79
+ noUsage: 'Nog geen verbruik.'
75
80
  },
76
81
  agents: {
77
- none: 'Op deze machine staat geen agent-CLI.',
78
- installed: 'Deze machine heeft {{list}}.',
82
+ none: 'Geen agent-CLI geïnstalleerd.',
83
+ installed: 'Geïnstalleerd: {{list}}.',
79
84
  settings: 'Agent-instellingen'
80
85
  },
81
86
  provenance: {
82
- failed: 'Kon de transcripts niet lezen. Dit is de laatste scan die wel lukte.',
87
+ failed: 'Kon het laatste verbruik niet lezen. Dit zijn de vorige resultaten.',
83
88
  scanned_one: 'Gescand om {{time}}, {{files}} bestand',
84
89
  scanned_other: 'Gescand om {{time}}, {{files}} bestanden',
85
- bundledPrices: 'Prijzen uit de meegeleverde tabel',
86
- fetchedPrices: 'Prijzen van LiteLLM, {{date}}',
90
+ bundledPrices: 'Ingebouwde prijzen',
91
+ fetchedPrices: 'Prijzen van {{date}}',
87
92
  rate: '{{currency}} tegen de ECB-koers van {{date}}'
88
93
  },
89
94
  summary: {
@@ -120,7 +125,7 @@ export default {
120
125
  cost: 'Kosten',
121
126
  share: 'Aandeel',
122
127
  pricedAs: 'Geprijsd als {{model}}',
123
- noPrice: 'Geen prijs bekend voor dit model'
128
+ noPrice: 'Geen prijs bekend'
124
129
  },
125
130
  days: {
126
131
  day: 'Dag',
@@ -30,9 +30,11 @@ function ApprovalDetails({ item }: { item: ChatApprovalItem }) {
30
30
  const editorPreview = host.code.editor !== undefined;
31
31
  const maxHeight = expanded ? 480 : 176;
32
32
  const input = typeof item.input === 'object' && item.input !== null ? (item.input as Record<string, unknown>) : {};
33
+ // Some agents describe a command by the command itself, which the box under it already shows.
34
+ const describes = item.description && item.description.trim() !== (typeof input.command === 'string' ? input.command.trim() : null);
33
35
  return (
34
36
  <>
35
- {item.description && <p className="text-sm text-text-muted">{item.description}</p>}
37
+ {describes && <p className="text-sm text-text-muted">{item.description}</p>}
36
38
  {patches.length + edits.length > 1 && (
37
39
  <p className="text-xs text-text-muted">{t('approval.allChanges', { count: patches.length + edits.length })}</p>
38
40
  )}
@@ -4,6 +4,7 @@ import type { AgentKind, ModelInfo, ProviderInfo } from '@adecore/agent-contract
4
4
  import { AccountDot } from '../agents/AccountDot';
5
5
  import { ModelOptionControl } from '../agents/ModelOptionControl';
6
6
  import { carryOptions } from '../agents/model-options';
7
+ import { optionWord } from '../agents/option-words';
7
8
  import { ACCOUNT_TONE_CLASSES, accountName, accountStatusLine, type AccountEntry, type AccountLogin } from '../agents/accounts';
8
9
  import { accountFor, forgetChatSelection, rememberChatAccount, rememberChatSelection, selectionFor, useChatPreferences } from '../chat/preferences';
9
10
  import { useChatScope } from '../scope';
@@ -27,7 +28,7 @@ function ModelOptionRows({ provider, model, options }: { provider: AgentKind; mo
27
28
  key={option.id}
28
29
  indent
29
30
  muted
30
- label={option.label}
31
+ label={optionWord(option)}
31
32
  control={<ModelOptionControl option={option} options={options} layout="row" onChange={(value) => setOption(option.id, value)} />}
32
33
  />
33
34
  ))}
@@ -5,12 +5,11 @@ import { Check, Copy, ExternalLink, SquareTerminal } from 'lucide-react';
5
5
  import type { ProviderInfo, ProviderPlatform, ProviderSignIn } from '@adecore/agent-contracts';
6
6
  import { Button, copyText, Icon, Pill, Segmented } from '@adecore/ui';
7
7
  import { useChatHost } from '../host';
8
+ import { useHostMachinePlatform } from '../host-hooks';
8
9
  import { useChatScope } from '../scope';
9
10
  import { installPlatforms, installStepStates, pagePlatform, type InstallStepState, type ProviderInstallStep } from './install-steps';
10
11
  import { CliMark } from './parts';
11
12
 
12
- const noPlatform = (): ProviderPlatform | null => null;
13
-
14
13
  function CommandBlock({ command }: { command: string }) {
15
14
  const { t } = useTranslation('agent-providers');
16
15
  const [copied, setCopied] = useState<string | null>(null);
@@ -104,8 +103,7 @@ export function InstallPage({ provider, signedIn, extra }: InstallPageProps) {
104
103
  const { t } = useTranslation('agent-providers');
105
104
  const { id: scopeId } = useChatScope();
106
105
  const host = useChatHost();
107
- const useMachinePlatform = host.useMachinePlatform ?? noPlatform;
108
- const machine = useMachinePlatform(scopeId) ?? pagePlatform();
106
+ const machine = useHostMachinePlatform(scopeId) ?? pagePlatform();
109
107
  const { offered, initial } = installPlatforms(provider, machine);
110
108
  // Only a person's pick is kept, so a machine whose system arrives late still opens on its own.
111
109
  const [chosen, setPlatform] = useState<ProviderPlatform | null>(null);
@@ -5,7 +5,7 @@ import { Plus } from 'lucide-react';
5
5
  import type { AgentKind } from '@adecore/agent-contracts';
6
6
  import { AccountDot } from '../agents/AccountDot';
7
7
  import { accountName } from '../agents/accounts';
8
- import { IconButton, SectionLabel } from '@adecore/ui';
8
+ import { Icon, IconButton, SectionLabel } from '@adecore/ui';
9
9
  import type { Picked } from './pane-target';
10
10
  import { CliMark } from './parts';
11
11
  import { accountNote, type ProviderGroups, type ProviderRow, type ProviderSetupStatus } from './provider-groups';
@@ -55,11 +55,13 @@ interface ProviderListProps {
55
55
  groups: ProviderGroups;
56
56
  current: Picked | null;
57
57
  canAddAccount(kind: AgentKind): boolean;
58
+ /* Whether the list ends in a row that opens the host's page to add a provider. */
59
+ canAddProvider?: boolean;
58
60
  onPick(picked: Picked): void;
59
61
  }
60
62
 
61
63
  /* The providers by whether they are ready, need setup or are not installed; a group without providers is left out. */
62
- export function ProviderList({ groups, current, canAddAccount, onPick }: ProviderListProps) {
64
+ export function ProviderList({ groups, current, canAddAccount, canAddProvider = false, onPick }: ProviderListProps) {
63
65
  const { t } = useTranslation('agent-providers');
64
66
  const picksCli = (kind: AgentKind): boolean => (current?.kind === 'cli' || current?.kind === 'install') && current.cli === kind;
65
67
  const picksAccount = (id: string): boolean => current?.kind === 'account' && current.id === id;
@@ -139,6 +141,14 @@ export function ProviderList({ groups, current, canAddAccount, onPick }: Provide
139
141
  )}
140
142
  </>
141
143
  )}
144
+ {canAddProvider && (
145
+ <ListRow selected={current?.kind === 'catalog'} onSelect={() => onPick({ kind: 'catalog' })} className="py-2">
146
+ <span className="grid w-3.5 shrink-0 place-items-center text-text-muted">
147
+ <Icon icon={Plus} size={14} />
148
+ </span>
149
+ <span className="min-w-0 grow truncate text-sm text-text-muted">{t('list.addProvider')}</span>
150
+ </ListRow>
151
+ )}
142
152
  </>
143
153
  );
144
154
  }
@@ -11,11 +11,12 @@ import { AddAccountForm } from './AddAccountForm';
11
11
  import { CliDetail } from './CliDetail';
12
12
  import { InstallPage } from './InstallPage';
13
13
  import type { ProviderInstallStep } from './install-steps';
14
- import { pickOfTarget, type Picked } from './pane-target';
14
+ import { pickOfCli, pickOfTarget, type Picked } from './pane-target';
15
15
  import { groupProviders, type ProviderSetupStatus } from './provider-groups';
16
16
  import { ProviderList } from './ProviderList';
17
17
  import { useProviderAccounts } from '../state/provider-accounts';
18
18
  import { useProviders } from '../state/providers';
19
+ import { useHostLoginBlocked } from '../host-hooks';
19
20
 
20
21
  interface ProvidersPaneProps {
21
22
  /* The row a search result leads to, by its `searchId`; the pane opens on the CLI it belongs to. `providers.install.<kind>` opens on that CLI's install page, or on its detail once it is installed. */
@@ -28,10 +29,14 @@ interface ProvidersPaneProps {
28
29
  installStepOf?(provider: ProviderInfo): ProviderInstallStep | null;
29
30
  /* Why a provider is not usable yet when the app knows better than its accounts, such as one turned off in its own detail; null leaves it to the accounts. */
30
31
  setupStatusOf?(provider: ProviderInfo): ProviderSetupStatus | null;
32
+ /* Sections of the app's own under a CLI's usual detail, such as its version and an update; null adds none. */
33
+ sectionsOf?(provider: ProviderInfo): ReactNode | null;
34
+ /* A page of the app's own to add a provider from, such as a catalog to install one; the list then ends in a row that opens it. `added` picks the provider it added. */
35
+ addPage?(added: (kind: AgentKind) => void): ReactNode;
31
36
  }
32
37
 
33
38
  /* The agent CLIs of the host in scope, each with its accounts, beside the detail of what is picked. */
34
- export function ProvidersPane({ target = null, detailOf, defaults = true, installStepOf, setupStatusOf }: ProvidersPaneProps) {
39
+ export function ProvidersPane({ target = null, detailOf, defaults = true, installStepOf, setupStatusOf, sectionsOf, addPage }: ProvidersPaneProps) {
35
40
  const { t } = useTranslation('agent-providers');
36
41
  const { id: scopeId } = useChatScope();
37
42
  const providers = useProviders((s) => s.providers);
@@ -39,7 +44,7 @@ export function ProvidersPane({ target = null, detailOf, defaults = true, instal
39
44
  const accounts = useProviderAccounts((s) => s.accounts);
40
45
  const host = useChatHost();
41
46
  const { openLogin } = host;
42
- const loginBlocked = host.useLoginBlocked(scopeId);
47
+ const loginBlocked = useHostLoginBlocked(scopeId);
43
48
  const [picked, setPicked] = useState<Picked | null>(() => pickOfTarget(target, providers));
44
49
 
45
50
  const groups = groupProviders(providers, accounts, setupStatusOf);
@@ -49,10 +54,23 @@ export function ProvidersPane({ target = null, detailOf, defaults = true, instal
49
54
 
50
55
  // What was picked may be gone since (an account removed elsewhere); the first CLI stands in for it.
51
56
  const pickedEntry = picked?.kind === 'account' ? (Object.hasOwn(accounts?.accounts ?? {}, picked.id) ? picked.id : null) : null;
52
- const current: Picked | null =
53
- picked !== null && (picked.kind !== 'account' || pickedEntry !== null) ? picked : installed[0] ? { kind: 'cli', cli: installed[0].kind } : null;
57
+ // A CLI taken off the host since it was picked makes way too, so the detail never stays empty.
58
+ const keeps = (entry: Picked): boolean => {
59
+ switch (entry.kind) {
60
+ case 'account':
61
+ return pickedEntry !== null;
62
+ case 'catalog':
63
+ return addPage !== undefined;
64
+ case 'cli':
65
+ return !loaded || installed.some((provider) => provider.kind === entry.cli);
66
+ default:
67
+ return true;
68
+ }
69
+ };
70
+ const current: Picked | null = picked !== null && keeps(picked) ? picked : installed[0] ? { kind: 'cli', cli: installed[0].kind } : null;
54
71
  const currentAccount = current?.kind === 'account' ? accounts?.accounts[current.id] : undefined;
55
- const currentCli = current === null ? null : current.kind === 'account' ? (currentAccount?.kind as AgentKind | undefined) : current.cli;
72
+ const currentCli =
73
+ current === null || current.kind === 'catalog' ? null : current.kind === 'account' ? (currentAccount?.kind as AgentKind | undefined) : current.cli;
56
74
  const provider = (current?.kind === 'install' ? providers : installed).find((entry) => entry.kind === currentCli) ?? null;
57
75
 
58
76
  // A search result lands on a row of a CLI's detail, so a picked account makes way for its CLI.
@@ -80,10 +98,19 @@ export function ProvidersPane({ target = null, detailOf, defaults = true, instal
80
98
  <Skeleton className="w-40" />
81
99
  </div>
82
100
  ) : (
83
- <ProviderList groups={groups} current={current} canAddAccount={(kind) => loginOf(kind) !== null} onPick={setPicked} />
101
+ <ProviderList
102
+ groups={groups}
103
+ current={current}
104
+ canAddAccount={(kind) => loginOf(kind) !== null}
105
+ canAddProvider={addPage !== undefined}
106
+ onPick={setPicked}
107
+ />
84
108
  );
85
109
 
86
110
  const detail = (): ReactNode => {
111
+ if (current?.kind === 'catalog') {
112
+ return addPage?.((kind) => setPicked(pickOfCli(kind, providers))) ?? null;
113
+ }
87
114
  if (current === null || provider === null) {
88
115
  return null;
89
116
  }
@@ -130,14 +157,17 @@ export function ProvidersPane({ target = null, detailOf, defaults = true, instal
130
157
  );
131
158
  }
132
159
  return (
133
- <CliDetail
134
- provider={provider}
135
- entries={accounts === null ? null : entriesOf(provider.kind)}
136
- defaults={defaults}
137
- login={loginOf(provider.kind)}
138
- onAddAccount={() => setPicked({ kind: 'add', cli: provider.kind })}
139
- onPickAccount={(id) => setPicked({ kind: 'account', id })}
140
- />
160
+ <>
161
+ <CliDetail
162
+ provider={provider}
163
+ entries={accounts === null ? null : entriesOf(provider.kind)}
164
+ defaults={defaults}
165
+ login={loginOf(provider.kind)}
166
+ onAddAccount={() => setPicked({ kind: 'add', cli: provider.kind })}
167
+ onPickAccount={(id) => setPicked({ kind: 'account', id })}
168
+ />
169
+ {sectionsOf?.(provider) ?? null}
170
+ </>
141
171
  );
142
172
  };
143
173
 
@@ -1,21 +1,37 @@
1
1
  import type { AgentKind, ProviderInfo } from '@adecore/agent-contracts';
2
2
 
3
- // `install` is a CLI picked while it was missing: its install page stays until it is installed and signed in.
4
- export type Picked = { kind: 'cli'; cli: AgentKind } | { kind: 'install'; cli: AgentKind } | { kind: 'account'; id: string } | { kind: 'add'; cli: AgentKind };
3
+ // `install` is a CLI picked while it was missing: its install page stays until it is installed and signed in. `catalog` is the host's page to add a provider from.
4
+ export type Picked =
5
+ | { kind: 'cli'; cli: AgentKind }
6
+ | { kind: 'install'; cli: AgentKind }
7
+ | { kind: 'account'; id: string }
8
+ | { kind: 'add'; cli: AgentKind }
9
+ | { kind: 'catalog' };
5
10
 
6
11
  const INSTALL_TARGET = 'providers.install.';
12
+ const ADD_TARGET = 'providers.add';
7
13
 
8
14
  /* What a target opens on its own, before any CLI is picked; null for a target that only lands on a row of the CLI already shown. */
9
15
  export function pickOfTarget(target: string | null, providers: ProviderInfo[]): Picked | null {
10
16
  if (target === 'providers.apple') {
11
17
  return { kind: 'cli', cli: 'apple' };
12
18
  }
19
+ if (target === ADD_TARGET) {
20
+ return { kind: 'catalog' };
21
+ }
13
22
  if (!target?.startsWith(INSTALL_TARGET) || target.length === INSTALL_TARGET.length) {
14
23
  return null;
15
24
  }
16
- const cli = target.slice(INSTALL_TARGET.length) as AgentKind;
25
+ return pickOfCli(target.slice(INSTALL_TARGET.length) as AgentKind, providers);
26
+ }
27
+
28
+ /*
29
+ * A CLI opened by name, from a target or from the host's page that just added it: its detail once it is there, its
30
+ * install page while it is missing. A CLI the host has not reported yet is taken as missing, so the pick holds until
31
+ * the next list names it; once it is installed and signed in, its install page gives way to its detail.
32
+ */
33
+ export function pickOfCli(cli: AgentKind, providers: ProviderInfo[]): Picked {
17
34
  const provider = providers.find((entry) => entry.kind === cli);
18
- // A CLI the host has not reported yet is taken as missing; once it is installed and signed in, its install page gives way to its detail.
19
35
  if (provider !== undefined && (provider.installed || !provider.capabilities.terminal)) {
20
36
  return { kind: 'cli', cli };
21
37
  }
@@ -1,4 +1,4 @@
1
- import { useContext, useMemo } from 'react';
1
+ import { useContext } from 'react';
2
2
  import { create } from 'zustand';
3
3
  import type {
4
4
  AgentKind,
@@ -344,7 +344,12 @@ export function useReportedModels(provider: AgentKind): ReadonlySet<string> {
344
344
  }
345
345
  return [...names].sort().join('\n');
346
346
  });
347
- return useMemo(() => new Set(joined === '' ? [] : joined.split('\n')), [joined]);
347
+ return new Set(joined === '' ? [] : joined.split('\n'));
348
+ }
349
+
350
+ /* Whether a call still waits on the person's answer to an approval of it, when its clock is not running yet. */
351
+ export function useAwaitsApproval(chatId: string, toolUseId: string): boolean {
352
+ return useChatRow(chatId, (row) => waitingRequestsOf(row).some((request) => request.kind === 'approval' && request.toolUseId === toolUseId));
348
353
  }
349
354
 
350
355
  /* The item as the thread holds it now, for a row derived from the structure, which a delta leaves alone. */
@@ -8,7 +8,7 @@ import { Tooltip } from '@adecore/ui';
8
8
  import { formatClock, formatWeekdayClock, isSameDay, formatCountdown, formatPercent } from '@adecore/ui/format';
9
9
  import { ProviderLogo } from '../agents/ProviderLogo';
10
10
  import { PROVIDER_COLORS, PROVIDER_LABELS } from './format';
11
- import { accountNote, explain, isSignedOut, nextReset, type LimitAccount, type LimitGroup } from './limit-groups';
11
+ import { accountNote, evenPace, explain, isSignedOut, nextReset, paceText, type LimitAccount, type LimitGroup, type PaceStanding } from './limit-groups';
12
12
 
13
13
  /* Red where a window is nearly spent, amber where it is worth knowing; room to spare is not news and takes the text color. */
14
14
  function toneOf(used: number): string {
@@ -25,20 +25,18 @@ function resetInLabel(resetsAt: number, now: number): string | null {
25
25
  return resetsAt <= now ? null : formatCountdown(resetsAt - now);
26
26
  }
27
27
 
28
- /* How much of the window has run, or null when the provider named neither a reset nor a length. */
29
- function elapsedShare(window: UsageWindow, now: number): number | null {
30
- if (window.resetsAt === null || window.durationMs === null || window.durationMs <= 0) {
31
- return null;
32
- }
33
- return Math.min(1, Math.max(0, 1 - (window.resetsAt - now) / window.durationMs));
34
- }
28
+ const PACE_LINES: Record<PaceStanding, string> = {
29
+ ahead: 'limits.faster',
30
+ behind: 'limits.slower',
31
+ even: 'limits.even'
32
+ };
35
33
 
36
34
  export function WindowBar({ window, now, compact }: { window: UsageWindow; now: number; compact: boolean }) {
37
35
  const { t } = useTranslation('agent-usage');
38
36
  const percent = Math.round(window.used * 100);
39
- const elapsed = elapsedShare(window, now);
40
37
  // The bar fills as the quota is spent, so the mark beside it is how much of the window has run.
41
- const mark = elapsed === null ? null : Math.round(elapsed * 100);
38
+ const pace = evenPace(window, now);
39
+ const mark = pace?.percent ?? null;
42
40
  const resetsAt = window.resetsAt === null ? null : resetAtLabel(window.resetsAt, now);
43
41
  const resetsIn = window.resetsAt === null ? null : resetInLabel(window.resetsAt, now);
44
42
 
@@ -47,6 +45,7 @@ export function WindowBar({ window, now, compact }: { window: UsageWindow; now:
47
45
  role="progressbar"
48
46
  aria-label={t('limits.bar', { window: window.label, percent })}
49
47
  aria-valuenow={percent}
48
+ aria-valuetext={paceText(window, now)}
50
49
  aria-valuemin={0}
51
50
  aria-valuemax={100}
52
51
  className={clsx('relative cursor-default', compact ? 'h-4' : 'h-6')}
@@ -85,7 +84,7 @@ export function WindowBar({ window, now, compact }: { window: UsageWindow; now:
85
84
  {t('limits.used', { percent })}
86
85
  {mark !== null && ` · ${t('limits.windowPassed', { percent: mark })}`}
87
86
  </span>
88
- {mark !== null && <span className="text-text-muted">{mark <= percent ? t('limits.faster') : t('limits.slower')}</span>}
87
+ {pace !== null && <span className="text-text-muted">{t(PACE_LINES[pace.standing])}</span>}
89
88
  </span>
90
89
  }
91
90
  >
@@ -145,8 +144,7 @@ export function LimitsList({ limits, now, compact = false }: LimitsListProps) {
145
144
  function WindowLine({ window, now }: { window: UsageWindow; now: number }) {
146
145
  const { t } = useTranslation('agent-usage');
147
146
  const percent = Math.round(window.used * 100);
148
- const elapsed = elapsedShare(window, now);
149
- const mark = elapsed === null ? null : Math.round(elapsed * 100);
147
+ const mark = evenPace(window, now)?.percent ?? null;
150
148
  return (
151
149
  <>
152
150
  <span className="text-text-muted">{window.label}</span>
@@ -154,6 +152,7 @@ function WindowLine({ window, now }: { window: UsageWindow; now: number }) {
154
152
  role="progressbar"
155
153
  aria-label={t('limits.bar', { window: window.label, percent })}
156
154
  aria-valuenow={percent}
155
+ aria-valuetext={paceText(window, now)}
157
156
  aria-valuemin={0}
158
157
  aria-valuemax={100}
159
158
  className="relative h-1.5 rounded-full bg-surface-sunken"