@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,9 +1,10 @@
1
1
  import i18next from 'i18next';
2
- import { USAGE_PROVIDERS } from '@adecore/agent-contracts';
2
+ import { evenPace, USAGE_PROVIDERS } from '@adecore/agent-contracts';
3
3
  import { limitsAccountId } from '../agents/account-limits.js';
4
4
  import { accountName, accountsOfKind, accountStatusLine } from '../agents/accounts.js';
5
5
  import { formatDuration } from '@adecore/ui/format';
6
6
  import { PROVIDER_LABELS } from './format.js';
7
+ export { evenPace } from '@adecore/agent-contracts';
7
8
  const MINUTE = 60_000;
8
9
  /*
9
10
  * The plan numbers per CLI, one row per account. The machine only reads an account that is signed in,
@@ -12,80 +13,97 @@ const MINUTE = 60_000;
12
13
  * A CLI the machine reads no plan of at all has no group, whatever accounts it has.
13
14
  */
14
15
  export function limitGroups(snapshot, accounts) {
15
- return USAGE_PROVIDERS.flatMap((kind) => {
16
- if (!snapshot.providers.some((entry) => entry.kind === kind)) {
17
- return [];
18
- }
19
- const known = accountsOfKind(accounts, kind);
20
- const read = snapshot.providers
21
- .filter((entry) => entry.kind === kind)
22
- .map((entry) => {
23
- const id = limitsAccountId(entry);
24
- const account = known.find((each) => each.id === id);
25
- return {
26
- id,
27
- kind,
28
- name: account === undefined ? (entry.account?.label ?? PROVIDER_LABELS[kind]) : accountName(account, PROVIDER_LABELS[kind]),
29
- color: account === undefined ? entry.account?.color : account.account.color,
30
- entry,
31
- status: account?.status ?? null
32
- };
33
- });
34
- const unread = known
35
- .filter((account) => account.account.enabled !== false && !read.some((row) => row.id === account.id))
36
- .map((account) => ({
37
- id: account.id,
38
- kind,
39
- name: accountName(account, PROVIDER_LABELS[kind]),
40
- color: account.account.color,
41
- entry: null,
42
- status: account.status
43
- }));
44
- const rows = [...read, ...unread];
45
- return rows.length === 0 ? [] : [{ kind, accounts: rows }];
16
+ return USAGE_PROVIDERS.flatMap(kind => {
17
+ if (!snapshot.providers.some(entry => entry.kind === kind)) {
18
+ return [];
19
+ }
20
+ const known = accountsOfKind(accounts, kind);
21
+ const read = snapshot.providers.filter(entry => entry.kind === kind).map(entry => {
22
+ const id = limitsAccountId(entry);
23
+ const account = known.find(each => each.id === id);
24
+ return {
25
+ id,
26
+ kind,
27
+ name: account === undefined ? entry.account?.label ?? PROVIDER_LABELS[kind] : accountName(account, PROVIDER_LABELS[kind]),
28
+ color: account === undefined ? entry.account?.color : account.account.color,
29
+ entry,
30
+ status: account?.status ?? null
31
+ };
46
32
  });
33
+ const unread = known.filter(account => account.account.enabled !== false && !read.some(row => row.id === account.id)).map(account => ({
34
+ id: account.id,
35
+ kind,
36
+ name: accountName(account, PROVIDER_LABELS[kind]),
37
+ color: account.account.color,
38
+ entry: null,
39
+ status: account.status
40
+ }));
41
+ const rows = [...read, ...unread];
42
+ return rows.length === 0 ? [] : [{
43
+ kind,
44
+ accounts: rows
45
+ }];
46
+ });
47
47
  }
48
48
  /* Whether any CLI has more than one account, which is when the limits name the account of every row. */
49
49
  export function hasSeveralAccounts(groups) {
50
- return groups.some((group) => group.accounts.length > 1);
50
+ return groups.some(group => group.accounts.length > 1);
51
51
  }
52
52
  export function isSignedOut(account) {
53
- return account.status?.state === 'signed-out';
53
+ return account.status?.state === 'signed-out';
54
54
  }
55
55
  /* The window that resets first from now, the one reset a line per window has no room to repeat. */
56
56
  export function nextReset(windows, now) {
57
- let next = null;
58
- for (const window of windows) {
59
- if (window.resetsAt !== null && window.resetsAt > now && (next === null || window.resetsAt < next.resetsAt)) {
60
- next = { ...window, resetsAt: window.resetsAt };
61
- }
57
+ let next = null;
58
+ for (const window of windows) {
59
+ if (window.resetsAt !== null && window.resetsAt > now && (next === null || window.resetsAt < next.resetsAt)) {
60
+ next = {
61
+ ...window,
62
+ resetsAt: window.resetsAt
63
+ };
62
64
  }
63
- return next;
65
+ }
66
+ return next;
67
+ }
68
+ /* The bar as words for whoever cannot see the mark: how much is used and how that stands against an even pace. */
69
+ export function paceText(window, now) {
70
+ const percent = Math.round(window.used * 100);
71
+ const pace = evenPace(window, now);
72
+ return pace === null ? i18next.t('agent-usage:limits.used', {
73
+ percent
74
+ }) : i18next.t(`agent-usage:limits.pace.${pace.standing}`, {
75
+ percent,
76
+ pace: pace.percent
77
+ });
64
78
  }
65
79
  /* When the numbers came in and from where: a read of the machine's own, or a turn that reported them. Null before the first read. */
66
80
  export function checkedLabel(entry, now) {
67
- if (entry.checkedAt <= 0) {
68
- return null;
69
- }
70
- const past = now - entry.checkedAt;
71
- const when = past < MINUTE ? i18next.t('agent-usage:limits.checked.now') : i18next.t('agent-usage:limits.checked.ago', { duration: formatDuration(past) });
72
- return entry.source === 'event' ? i18next.t('agent-usage:limits.checked.fromTurn', { when }) : when;
81
+ if (entry.checkedAt <= 0) {
82
+ return null;
83
+ }
84
+ const past = now - entry.checkedAt;
85
+ const when = past < MINUTE ? i18next.t('agent-usage:limits.checked.now') : i18next.t('agent-usage:limits.checked.ago', {
86
+ duration: formatDuration(past)
87
+ });
88
+ return entry.source === 'event' ? i18next.t('agent-usage:limits.checked.fromTurn', {
89
+ when
90
+ }) : when;
73
91
  }
74
92
  /* Why a read account has no bars, or null when it has them. */
75
93
  export function explain(provider) {
76
- if (provider.unavailable === null) {
77
- return provider.windows.length === 0 ? i18next.t('agent-usage:limits.none') : null;
78
- }
79
- if (provider.unavailable.reason === 'not-installed') {
80
- return i18next.t('agent-usage:limits.notInstalled');
81
- }
82
- if (provider.unavailable.reason === 'no-subscription') {
83
- // A provider that knows why it has no plan says so; the rest are accounts on an API key.
84
- return provider.unavailable.message ?? i18next.t('agent-usage:limits.noSubscription');
85
- }
86
- return provider.unavailable.message ?? i18next.t('agent-usage:limits.unreachable');
94
+ if (provider.unavailable === null) {
95
+ return provider.windows.length === 0 ? i18next.t('agent-usage:limits.none') : null;
96
+ }
97
+ if (provider.unavailable.reason === 'not-installed') {
98
+ return i18next.t('agent-usage:limits.notInstalled');
99
+ }
100
+ if (provider.unavailable.reason === 'no-subscription') {
101
+ // A provider that knows why it has no plan says so; the rest are accounts on an API key.
102
+ return provider.unavailable.message ?? i18next.t('agent-usage:limits.noSubscription');
103
+ }
104
+ return provider.unavailable.message ?? i18next.t('agent-usage:limits.unreachable');
87
105
  }
88
106
  /* Why an account has no bars, or null when it has them. An account the machine does not read says what its login is doing. */
89
107
  export function accountNote(account) {
90
- return account.entry === null ? accountStatusLine(account.status, true).text : explain(account.entry);
91
- }
108
+ return account.entry === null ? accountStatusLine(account.status, true).text : explain(account.entry);
109
+ }
@@ -1,4 +1,5 @@
1
- import { useEffect, useMemo } from 'react';
1
+ import { c as _c } from "react/compiler-runtime";
2
+ import { useEffect } from 'react';
2
3
  import { useChatScope } from '../scope.js';
3
4
  import { useProviderAccountsStore } from '../state/provider-accounts.js';
4
5
  import { useUsage, useUsageStore } from '../state/usage.js';
@@ -7,52 +8,86 @@ import { limitGroups } from './limit-groups.js';
7
8
  const holds = new Map();
8
9
  /* On the scope's transport as it stands: reading the windows never makes the host connect, so they fill once it is connected for another reason. */
9
10
  function hold(scope) {
10
- const link = scope.transport;
11
- const scopeId = scope.id;
12
- const ask = () => {
13
- link.request('usage.limits', {})
14
- .then((snapshot) => useUsageStore.getState().setLimits(scopeId, snapshot))
15
- .catch(() => undefined);
16
- };
17
- if (link.status === 'open') {
18
- ask();
11
+ const link = scope.transport;
12
+ const scopeId = scope.id;
13
+ const ask = () => {
14
+ link.request('usage.limits', {}).then(snapshot => useUsageStore.getState().setLimits(scopeId, snapshot)).catch(() => undefined);
15
+ };
16
+ if (link.status === 'open') {
17
+ ask();
18
+ }
19
+ // A running turn reports its own numbers, which is what keeps a bar moving between reads.
20
+ const offChanged = link.on('usage.limitsChanged', snapshot => useUsageStore.getState().setLimits(scopeId, snapshot));
21
+ const offStatus = link.subscribeStatus(status => {
22
+ if (status === 'open') {
23
+ ask();
19
24
  }
20
- // A running turn reports its own numbers, which is what keeps a bar moving between reads.
21
- const offChanged = link.on('usage.limitsChanged', (snapshot) => useUsageStore.getState().setLimits(scopeId, snapshot));
22
- const offStatus = link.subscribeStatus((status) => {
23
- if (status === 'open') {
24
- ask();
25
- }
26
- });
27
- return {
28
- readers: 0,
29
- release: () => {
30
- offChanged();
31
- offStatus();
32
- }
33
- };
25
+ });
26
+ return {
27
+ readers: 0,
28
+ release: () => {
29
+ offChanged();
30
+ offStatus();
31
+ }
32
+ };
34
33
  }
35
34
  /* The snapshot of the host in scope, kept fresh for as long as anything shows it. */
36
35
  export function useUsageLimits() {
37
- const limits = useUsage((s) => s.limits);
38
- const scope = useChatScope();
39
- useEffect(() => {
40
- const held = holds.get(scope.id) ?? hold(scope);
41
- held.readers += 1;
42
- holds.set(scope.id, held);
43
- return () => {
44
- held.readers -= 1;
45
- if (held.readers === 0) {
46
- held.release();
47
- holds.delete(scope.id);
48
- }
49
- };
50
- }, [scope]);
51
- return limits;
36
+ const $ = _c(3);
37
+ const limits = useUsage(_temp);
38
+ const scope = useChatScope();
39
+ let t0;
40
+ let t1;
41
+ if ($[0] !== scope) {
42
+ t0 = () => {
43
+ const held = holds.get(scope.id) ?? hold(scope);
44
+ held.readers = held.readers + 1;
45
+ holds.set(scope.id, held);
46
+ return () => {
47
+ held.readers = held.readers - 1;
48
+ if (held.readers === 0) {
49
+ held.release();
50
+ holds.delete(scope.id);
51
+ }
52
+ };
53
+ };
54
+ t1 = [scope];
55
+ $[0] = scope;
56
+ $[1] = t0;
57
+ $[2] = t1;
58
+ } else {
59
+ t0 = $[1];
60
+ t1 = $[2];
61
+ }
62
+ useEffect(t0, t1);
63
+ return limits;
52
64
  }
53
65
  /* The snapshot per CLI and account, with the accounts of the same host it is read from. */
54
- export function useLimitGroups(limits) {
55
- const { id } = useChatScope();
56
- const accounts = useProviderAccountsStore((s) => s.byScope[id]?.accounts ?? null);
57
- return useMemo(() => (limits === null ? [] : limitGroups(limits, accounts)), [limits, accounts]);
66
+ function _temp(s) {
67
+ return s.limits;
58
68
  }
69
+ export function useLimitGroups(limits) {
70
+ const $ = _c(5);
71
+ const {
72
+ id
73
+ } = useChatScope();
74
+ let t0;
75
+ if ($[0] !== id) {
76
+ t0 = s => s.byScope[id]?.accounts ?? null;
77
+ $[0] = id;
78
+ $[1] = t0;
79
+ } else {
80
+ t0 = $[1];
81
+ }
82
+ const accounts = useProviderAccountsStore(t0);
83
+ let t1;
84
+ if ($[2] !== accounts || $[3] !== limits) {
85
+ t1 = limits === null ? [] : limitGroups(limits, accounts);
86
+ $[2] = accounts;
87
+ $[3] = limits;
88
+ $[4] = t1;
89
+ } else {
90
+ t1 = $[4];
91
+ }
92
+ return t1;
93
+ }
@@ -1,9 +1,25 @@
1
- import { useMemo } from 'react';
1
+ import { c as _c } from "react/compiler-runtime";
2
2
  import { useUsage } from '../state/usage.js';
3
3
  import { moneyFormat } from './format.js';
4
4
  /* The formatter every amount on the page goes through: the chosen currency, at the rate the summary on screen carries. */
5
5
  export function useMoney() {
6
- const currency = useUsage((s) => s.currency);
7
- const rate = useUsage((s) => s.summary?.rate ?? null);
8
- return useMemo(() => moneyFormat(currency, rate), [currency, rate]);
6
+ const $ = _c(3);
7
+ const currency = useUsage(_temp);
8
+ const rate = useUsage(_temp2);
9
+ let t0;
10
+ if ($[0] !== currency || $[1] !== rate) {
11
+ t0 = moneyFormat(currency, rate);
12
+ $[0] = currency;
13
+ $[1] = rate;
14
+ $[2] = t0;
15
+ } else {
16
+ t0 = $[2];
17
+ }
18
+ return t0;
9
19
  }
20
+ function _temp2(s_0) {
21
+ return s_0.summary?.rate ?? null;
22
+ }
23
+ function _temp(s) {
24
+ return s.currency;
25
+ }
@@ -1,92 +1,113 @@
1
1
  import { EMPTY_TOTALS, USAGE_PROVIDERS, addTotals, totalTokensOf } from '@adecore/agent-contracts';
2
2
  /* Three or four round numbers up the side. The one piece of arithmetic a chart library would bring. */
3
3
  export function niceScale(max, ticks = 4) {
4
- if (!Number.isFinite(max) || max <= 0) {
5
- return { max: 1, step: 1 };
6
- }
7
- const rough = max / ticks;
8
- const magnitude = 10 ** Math.floor(Math.log10(rough));
9
- const normalized = rough / magnitude;
10
- const step = (normalized <= 1 ? 1 : normalized <= 2 ? 2 : normalized <= 5 ? 5 : 10) * magnitude;
11
- return { max: Math.ceil(max / step) * step, step };
4
+ if (!Number.isFinite(max) || max <= 0) {
5
+ return {
6
+ max: 1,
7
+ step: 1
8
+ };
9
+ }
10
+ const rough = max / ticks;
11
+ const magnitude = 10 ** Math.floor(Math.log10(rough));
12
+ const normalized = rough / magnitude;
13
+ const step = (normalized <= 1 ? 1 : normalized <= 2 ? 2 : normalized <= 5 ? 5 : 10) * magnitude;
14
+ return {
15
+ max: Math.ceil(max / step) * step,
16
+ step
17
+ };
12
18
  }
13
19
  function pad(value) {
14
- return String(value).padStart(2, '0');
20
+ return String(value).padStart(2, '0');
15
21
  }
16
22
  /*
17
23
  * Every slot the period has, whether anything happened in it or not: an empty day keeps its place on
18
24
  * the axis, so a gap in the work reads as a gap and not as a shorter week.
19
25
  */
20
26
  export function enumerateSlots(summary) {
21
- if (summary.resolution === 'hour') {
22
- return Array.from({ length: 24 }, (_, hour) => `${summary.to}T${pad(hour)}`);
23
- }
24
- const slots = [];
25
- const at = new Date(`${summary.from}T00:00:00`);
26
- const end = new Date(`${summary.to}T00:00:00`);
27
- // A calendar loop rather than adding milliseconds, since a day is 23 or 25 hours long twice a year.
28
- while (at <= end && slots.length < 400) {
29
- slots.push(`${at.getFullYear()}-${pad(at.getMonth() + 1)}-${pad(at.getDate())}`);
30
- at.setDate(at.getDate() + 1);
31
- }
32
- return slots;
27
+ if (summary.resolution === 'hour') {
28
+ return Array.from({
29
+ length: 24
30
+ }, (_, hour) => `${summary.to}T${pad(hour)}`);
31
+ }
32
+ const slots = [];
33
+ const at = new Date(`${summary.from}T00:00:00`);
34
+ const end = new Date(`${summary.to}T00:00:00`);
35
+ // A calendar loop rather than adding milliseconds, since a day is 23 or 25 hours long twice a year.
36
+ while (at <= end && slots.length < 400) {
37
+ slots.push(`${at.getFullYear()}-${pad(at.getMonth() + 1)}-${pad(at.getDate())}`);
38
+ at.setDate(at.getDate() + 1);
39
+ }
40
+ return slots;
33
41
  }
34
42
  /* How often an x label fits: every third hour, every day, every week, every fortnight. */
35
43
  export function labelEveryFor(slots) {
36
- return slots <= 10 ? 1 : slots <= 24 ? 3 : slots <= 31 ? 7 : 15;
44
+ return slots <= 10 ? 1 : slots <= 24 ? 3 : slots <= 31 ? 7 : 15;
37
45
  }
38
46
  /*
39
47
  * The buckets folded into what the page draws. The daemon sends one bucket per slot, provider and
40
48
  * model, which is the smallest thing every part of the page can be summed out of.
41
49
  */
42
50
  export function deriveUsage(summary, metric) {
43
- const bySlot = new Map();
44
- for (const slot of enumerateSlots(summary)) {
45
- bySlot.set(slot, { slot, byProvider: {}, total: 0 });
51
+ const bySlot = new Map();
52
+ for (const slot of enumerateSlots(summary)) {
53
+ bySlot.set(slot, {
54
+ slot,
55
+ byProvider: {},
56
+ total: 0
57
+ });
58
+ }
59
+ const byProvider = new Map();
60
+ let totals = EMPTY_TOTALS;
61
+ let costUsd = 0;
62
+ let cacheSavingsUsd = 0;
63
+ for (const bucket of summary.buckets) {
64
+ const value = metric === 'cost' ? bucket.costUsd ?? 0 : totalTokensOf(bucket.totals);
65
+ const slot = bySlot.get(bucket.slot);
66
+ if (slot !== undefined) {
67
+ slot.byProvider[bucket.provider] = (slot.byProvider[bucket.provider] ?? 0) + value;
68
+ slot.total += value;
46
69
  }
47
- const byProvider = new Map();
48
- let totals = EMPTY_TOTALS;
49
- let costUsd = 0;
50
- let cacheSavingsUsd = 0;
51
- for (const bucket of summary.buckets) {
52
- const value = metric === 'cost' ? (bucket.costUsd ?? 0) : totalTokensOf(bucket.totals);
53
- const slot = bySlot.get(bucket.slot);
54
- if (slot !== undefined) {
55
- slot.byProvider[bucket.provider] = (slot.byProvider[bucket.provider] ?? 0) + value;
56
- slot.total += value;
57
- }
58
- const provider = byProvider.get(bucket.provider) ?? { provider: bucket.provider, costUsd: 0, totals: EMPTY_TOTALS };
59
- provider.costUsd += bucket.costUsd ?? 0;
60
- provider.totals = addTotals(provider.totals, bucket.totals);
61
- byProvider.set(bucket.provider, provider);
62
- totals = addTotals(totals, bucket.totals);
63
- costUsd += bucket.costUsd ?? 0;
64
- cacheSavingsUsd += bucket.cacheSavingsUsd;
65
- }
66
- const providers = [...byProvider.values()].sort((a, b) => b.costUsd - a.costUsd);
67
- return {
68
- slots: [...bySlot.values()],
69
- providers,
70
- active: USAGE_PROVIDERS.filter((provider) => byProvider.has(provider)),
71
- totals,
72
- costUsd,
73
- cacheSavingsUsd
70
+ const provider = byProvider.get(bucket.provider) ?? {
71
+ provider: bucket.provider,
72
+ costUsd: 0,
73
+ totals: EMPTY_TOTALS
74
74
  };
75
+ provider.costUsd += bucket.costUsd ?? 0;
76
+ provider.totals = addTotals(provider.totals, bucket.totals);
77
+ byProvider.set(bucket.provider, provider);
78
+ totals = addTotals(totals, bucket.totals);
79
+ costUsd += bucket.costUsd ?? 0;
80
+ cacheSavingsUsd += bucket.cacheSavingsUsd;
81
+ }
82
+ const providers = [...byProvider.values()].sort((a, b) => b.costUsd - a.costUsd);
83
+ return {
84
+ slots: [...bySlot.values()],
85
+ providers,
86
+ active: USAGE_PROVIDERS.filter(provider => byProvider.has(provider)),
87
+ totals,
88
+ costUsd,
89
+ cacheSavingsUsd
90
+ };
75
91
  }
76
92
  /*
77
93
  * The chart's buckets as a table of calendar days, newest first; an hour slot folds onto the date it
78
94
  * names. A day nothing happened in is left out, since the chart already shows the gap.
79
95
  */
80
96
  export function deriveDays(summary) {
81
- const rows = new Map();
82
- for (const bucket of summary.buckets) {
83
- const day = bucket.slot.slice(0, 10);
84
- const row = rows.get(day) ?? { slot: day, costByProvider: {}, costUsd: 0, tokens: 0 };
85
- const cost = bucket.costUsd ?? 0;
86
- row.costByProvider[bucket.provider] = (row.costByProvider[bucket.provider] ?? 0) + cost;
87
- row.costUsd += cost;
88
- row.tokens += totalTokensOf(bucket.totals);
89
- rows.set(day, row);
90
- }
91
- return [...rows.values()].sort((a, b) => b.slot.localeCompare(a.slot));
92
- }
97
+ const rows = new Map();
98
+ for (const bucket of summary.buckets) {
99
+ const day = bucket.slot.slice(0, 10);
100
+ const row = rows.get(day) ?? {
101
+ slot: day,
102
+ costByProvider: {},
103
+ costUsd: 0,
104
+ tokens: 0
105
+ };
106
+ const cost = bucket.costUsd ?? 0;
107
+ row.costByProvider[bucket.provider] = (row.costByProvider[bucket.provider] ?? 0) + cost;
108
+ row.costUsd += cost;
109
+ row.tokens += totalTokensOf(bucket.totals);
110
+ rows.set(day, row);
111
+ }
112
+ return [...rows.values()].sort((a, b) => b.slot.localeCompare(a.slot));
113
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adecore/agents-react",
3
- "version": "0.31.11",
3
+ "version": "0.32.0",
4
4
  "description": "React agent chat threads, composers, approvals, provider accounts and usage views.",
5
5
  "type": "module",
6
6
  "exports": {
@@ -67,11 +67,11 @@
67
67
  "test:visuals": "bun --config=integration.bunfig.toml --conditions=source test ./src/chat/visual-viewport.integration.test.ts"
68
68
  },
69
69
  "dependencies": {
70
- "@adecore/agent-contracts": "0.31.11",
71
- "@adecore/editor": "0.31.11",
72
- "@adecore/editor-react": "0.31.11",
73
- "@adecore/intelligent-ui": "0.31.11",
74
- "@adecore/merge": "0.31.11",
70
+ "@adecore/agent-contracts": "0.32.0",
71
+ "@adecore/editor": "0.32.0",
72
+ "@adecore/editor-react": "0.32.0",
73
+ "@adecore/intelligent-ui": "0.32.0",
74
+ "@adecore/merge": "0.32.0",
75
75
  "@codemirror/commands": "^6.11.1",
76
76
  "@codemirror/language": "^6.12.4",
77
77
  "@codemirror/state": "^6.7.6",
@@ -94,14 +94,14 @@
94
94
  "zustand": "^5.0.15"
95
95
  },
96
96
  "peerDependencies": {
97
- "@adecore/ui": "^0.31.11",
97
+ "@adecore/ui": "^0.32.0",
98
98
  "i18next": "^26.4.2",
99
99
  "react": "^19.3.0",
100
100
  "react-dom": "^19.3.0",
101
101
  "react-i18next": "^17.0.15"
102
102
  },
103
103
  "devDependencies": {
104
- "@adecore/ui": "0.31.11",
104
+ "@adecore/ui": "0.32.0",
105
105
  "@types/bun": "^1.4.2",
106
106
  "@types/react": "^19.3.0",
107
107
  "@types/react-dom": "^19.3.0",
@@ -1,6 +1,7 @@
1
1
  import type { ModelOptionDescriptor, ModelSelection } from '@adecore/agent-contracts';
2
2
  import { Segmented, Switch, Select } from '@adecore/ui';
3
3
  import { optionValue } from './model-options';
4
+ import { localizedOption } from './option-words';
4
5
 
5
6
  // Up to this many choices read at a glance side by side; more go into a menu.
6
7
  const MAX_SEGMENTS = 3;
@@ -26,7 +27,8 @@ type ModelOptionControlProps = {
26
27
  * descriptors as menu items (`RunSettings`), since there they sit in a menu.
27
28
  */
28
29
  export function ModelOptionControl(props: ModelOptionControlProps) {
29
- const { option, options, layout = 'compact', disabled } = props;
30
+ const { options, layout = 'compact', disabled } = props;
31
+ const option = localizedOption(props.option);
30
32
  if (option.type === 'boolean') {
31
33
  return <Switch checked={optionValue(option, options) === true} label={option.label} disabled={disabled} onCheckedChange={props.onChange} />;
32
34
  }
@@ -0,0 +1,27 @@
1
+ import i18next from 'i18next';
2
+ import type { ModelOptionDescriptor } from '@adecore/agent-contracts';
3
+
4
+ /*
5
+ * The model catalogs write a model's knobs in English. Those words read in the person's language; a word
6
+ * that differs from the catalog's is an agent's own and stays as the agent wrote it.
7
+ */
8
+ function catalogWord(key: string, written: string): string {
9
+ return i18next.t(key, { lng: 'en', defaultValue: '' }) === written ? i18next.t(key) : written;
10
+ }
11
+
12
+ export function optionWord(option: ModelOptionDescriptor): string {
13
+ return catalogWord(`agent-chat:modelOptions.${option.id}.label`, option.label);
14
+ }
15
+
16
+ export function choiceWord(optionId: string, choice: { id: string; label: string }): string {
17
+ return catalogWord(`agent-chat:modelOptions.${optionId}.choices.${choice.id}`, choice.label);
18
+ }
19
+
20
+ /* The option with the words a person reads, for a surface that draws its labels and choices. */
21
+ export function localizedOption(option: ModelOptionDescriptor): ModelOptionDescriptor {
22
+ const label = optionWord(option);
23
+ if (option.type !== 'select') {
24
+ return { ...option, label };
25
+ }
26
+ return { ...option, label, choices: option.choices.map((choice) => ({ ...choice, label: choiceWord(option.id, choice) })) };
27
+ }
@@ -1,7 +1,7 @@
1
1
  import { useMemo } from 'react';
2
2
  import type { AgentKind, ProviderAccounts } from '@adecore/agent-contracts';
3
3
  import { accountName, accountsOfKind, hasAccountChoice, offeredAccounts, type AccountEntry } from '../agents/accounts';
4
- import { useProviderAccounts } from '../state/provider-accounts';
4
+ import { useProviderAccounts, type ProviderAccountsRow } from '../state/provider-accounts';
5
5
  import { useProviders } from '../state/providers';
6
6
 
7
7
  export interface AccountChoice {
@@ -42,3 +42,43 @@ export function useAccountChoice(kind: AgentKind | null, account: string | undef
42
42
  };
43
43
  }, [accounts, kind, account, providerName]);
44
44
  }
45
+
46
+ /*
47
+ * The accounts a new chat or agent of a CLI may start under. `loading` until the machine answered, and
48
+ * while no CLI is picked yet; `unsupported` for a machine that keeps no accounts for the CLI, which
49
+ * then starts under its own login. `offered` holds only the accounts that are on, also when that is
50
+ * one or none: nothing runs under a new chat yet, so a turned-off account has no reason to stay.
51
+ */
52
+ export type NewAccountChoice =
53
+ | { status: 'loading' }
54
+ | { status: 'unsupported' }
55
+ | { status: 'ready'; offered: AccountEntry[]; providerName: string; nameOf(entry: AccountEntry): string };
56
+
57
+ // One object each, so a render that changes nothing hands back the same answer.
58
+ const LOADING: NewAccountChoice = { status: 'loading' };
59
+ const UNSUPPORTED: NewAccountChoice = { status: 'unsupported' };
60
+
61
+ /* `useNewAccountChoice` without React, for its tests. */
62
+ export function newAccountChoiceOf(row: ProviderAccountsRow, kind: AgentKind | null, providerName: string): NewAccountChoice {
63
+ if (kind === null || !row.loaded) {
64
+ return LOADING;
65
+ }
66
+ const entries = accountsOfKind(row.accounts, kind);
67
+ // An older machine lists no accounts at all, or none of a CLI it does not know.
68
+ if (entries.length === 0) {
69
+ return UNSUPPORTED;
70
+ }
71
+ return {
72
+ status: 'ready',
73
+ offered: offeredAccounts(entries, undefined),
74
+ providerName,
75
+ nameOf: (entry: AccountEntry) => accountName(entry, providerName)
76
+ };
77
+ }
78
+
79
+ /* The accounts a new chat or agent of this CLI may start under on the machine in scope. */
80
+ export function useNewAccountChoice(kind: AgentKind | null): NewAccountChoice {
81
+ const row = useProviderAccounts((entry) => entry);
82
+ const providerName = useProviders((entry) => entry.providers.find((provider) => provider.kind === kind)?.name) ?? kind ?? '';
83
+ return newAccountChoiceOf(row, kind, providerName);
84
+ }