@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
@@ -12,6 +12,7 @@ import { ImageThumb } from '../../ImageView';
12
12
  import { uiChildrenOf, uiNodeLabel, uiNodeText, uiUrlDomain } from '../node-text';
13
13
  import type { UiRendererProps } from '../render-context';
14
14
  import { useTruncated } from '../use-truncated';
15
+ import { useHostAttachmentUrl } from '../../../../host-hooks';
15
16
 
16
17
  // The number of every source by its node id, which the list counts in its own order.
17
18
  const SourceNumbers = createContext<ReadonlyMap<string, number>>(new Map());
@@ -55,8 +56,7 @@ function AttachedImage({
55
56
  cell: boolean;
56
57
  unnamed: boolean;
57
58
  }) {
58
- const host = useChatHost();
59
- const source = host.attachments.useUrl(scopeId, chatId, attachmentId);
59
+ const source = useHostAttachmentUrl(scopeId, chatId, attachmentId);
60
60
  if (!cell) {
61
61
  return <ImageThumb source={source} alt={alt} className="max-h-70 max-w-full rounded-xl object-contain" />;
62
62
  }
@@ -117,12 +117,11 @@ const COMPARE_MAX_HEIGHT = 384;
117
117
  */
118
118
  export function CompareRenderer({ node, children, context }: UiRendererProps<UiProps<'Compare'>>) {
119
119
  const { t } = useTranslation('agent-chat');
120
- const host = useChatHost();
121
120
  const { before, after } = node.props;
122
121
  const beforeLabel = node.props.beforeLabel || t('blocks.compare.before');
123
122
  const afterLabel = node.props.afterLabel || t('blocks.compare.after');
124
- const first = host.attachments.useUrl(context.scopeId, context.chatId, before);
125
- const second = host.attachments.useUrl(context.scopeId, context.chatId, after);
123
+ const first = useHostAttachmentUrl(context.scopeId, context.chatId, before);
124
+ const second = useHostAttachmentUrl(context.scopeId, context.chatId, after);
126
125
  const [split, setSplit] = useState(0.5);
127
126
  const [aspect, setAspect] = useState(COMPARE_ASPECT);
128
127
  const caption = uiNodeLabel(node);
@@ -205,7 +204,7 @@ export function ModelRenderer({ node, children, context }: UiRendererProps<UiPro
205
204
  const { t } = useTranslation('agent-chat');
206
205
  const host = useChatHost();
207
206
  const { attachment, alt } = node.props;
208
- const source = host.attachments.useUrl(context.scopeId, context.chatId, attachment);
207
+ const source = useHostAttachmentUrl(context.scopeId, context.chatId, attachment);
209
208
  const caption = uiNodeLabel(node);
210
209
  const label = alt ?? (caption === '' ? t('blocks.model.label') : caption);
211
210
  const View = host.ModelView;
@@ -7,6 +7,7 @@ import { ButtonGroup, IconButton } from '@adecore/ui';
7
7
  import { useChatHost, type UiMapSource } from '../../../../host';
8
8
  import { watchTheme } from '../../theme-watch';
9
9
  import { baseMapStyle, boundsOf, localizedTextField, mapFitOptions, spreadOverlaps, type MapColors, type MapPoint } from './map-style';
10
+ import { useHostCodeMode } from '../../../../host-hooks';
10
11
 
11
12
  /*
12
13
  * What the view is drawing: `base` by the source's choice, `offline` and `unavailable` as a fallback from tiles that
@@ -63,7 +64,7 @@ function readColors(element: HTMLElement): MapColors {
63
64
  export function MapView({ markers, source, selected, onPick, onStatus }: MapViewProps) {
64
65
  const { t, i18n } = useTranslation('agent-chat');
65
66
  const host = useChatHost();
66
- const mode = host.code.useMode();
67
+ const mode = useHostCodeMode();
67
68
  const workerUrl = host.maps?.workerUrl;
68
69
  const element = useRef<HTMLDivElement>(null);
69
70
  const [map, setMap] = useState<MapLibreMap | null>(null);
@@ -5,6 +5,7 @@ import { useTranslation } from 'react-i18next';
5
5
  import type { UiProps, UiViewNode } from '@adecore/intelligent-ui';
6
6
  import { Button, LazyBoundary, Spinner } from '@adecore/ui';
7
7
  import { useChatHost, type UiMapSource } from '../../../../host';
8
+ import { useHostMapSource } from '../../../../host-hooks';
8
9
  import { lazyNamed } from '../../../../lazy';
9
10
  import { DiffFallbackBoundary } from '../../diff/DiffFallbackBoundary';
10
11
  import { uiChildrenOf, uiNodeLabel } from '../node-text';
@@ -170,7 +171,7 @@ function MapFrame({ markers, source, selected, onPick }: FrameProps) {
170
171
 
171
172
  /* Asks the host for its tiles in a component of its own, since a host that offers none has no hook to call. */
172
173
  function HostedFrame({ maps, scopeId, ...frame }: Omit<FrameProps, 'source'> & { maps: NonNullable<ReturnType<typeof useChatHost>['maps']>; scopeId: string }) {
173
- return <MapFrame {...frame} source={maps.useSource(scopeId)} />;
174
+ return <MapFrame {...frame} source={useHostMapSource(maps, scopeId)} />;
174
175
  }
175
176
 
176
177
  /*
@@ -1,4 +1,4 @@
1
- import { useCallback, useState } from 'react';
1
+ import { useState } from 'react';
2
2
 
3
3
  function cut(element: HTMLElement): boolean {
4
4
  return element.scrollWidth > element.clientWidth + 1;
@@ -11,23 +11,20 @@ function cut(element: HTMLElement): boolean {
11
11
  */
12
12
  export function useTruncated<T extends HTMLElement>(within = false): [(element: T | null) => (() => void) | undefined, boolean] {
13
13
  const [truncated, setTruncated] = useState(false);
14
- const measure = useCallback(
15
- (element: T | null) => {
16
- if (element === null || typeof ResizeObserver === 'undefined') {
17
- return undefined;
18
- }
19
- const check = () => setTruncated(within ? [...element.querySelectorAll<HTMLElement>('.truncate')].some(cut) : cut(element));
20
- check();
21
- const resize = new ResizeObserver(check);
22
- resize.observe(element);
23
- const text = new MutationObserver(check);
24
- text.observe(element, { characterData: true, childList: true, subtree: true });
25
- return () => {
26
- resize.disconnect();
27
- text.disconnect();
28
- };
29
- },
30
- [within]
31
- );
14
+ const measure = (element: T | null) => {
15
+ if (element === null || typeof ResizeObserver === 'undefined') {
16
+ return undefined;
17
+ }
18
+ const check = () => setTruncated(within ? [...element.querySelectorAll<HTMLElement>('.truncate')].some(cut) : cut(element));
19
+ check();
20
+ const resize = new ResizeObserver(check);
21
+ resize.observe(element);
22
+ const text = new MutationObserver(check);
23
+ text.observe(element, { characterData: true, childList: true, subtree: true });
24
+ return () => {
25
+ resize.disconnect();
26
+ text.disconnect();
27
+ };
28
+ };
32
29
  return [measure, truncated];
33
30
  }
@@ -1,4 +1,4 @@
1
- import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
1
+ import { useEffect, useRef, useState } from 'react';
2
2
  import type { ChatUiLinkReading, ChatUiQueryState } from '@adecore/agent-contracts';
3
3
  import { uiLinkTargets, type UiLinkTarget } from '@adecore/intelligent-ui/links';
4
4
  import { uiInputValues, UI_HOST_LIMITS, type UiBlock, UiState } from '@adecore/intelligent-ui';
@@ -40,7 +40,7 @@ export function useUiLinks(
40
40
  const signature = JSON.stringify(targets);
41
41
  const input = JSON.stringify(values);
42
42
  const tickets = JSON.stringify(reads);
43
- const defaultInput = useMemo(() => JSON.stringify(uiInputValues(block, new UiState(block))), [block]);
43
+ const defaultInput = JSON.stringify(uiInputValues(block, new UiState(block)));
44
44
  const link = host?.link;
45
45
  useEffect(() => {
46
46
  asked.current.clear();
@@ -134,7 +134,7 @@ export function useUiLinks(
134
134
  });
135
135
  };
136
136
  const hostOpenUrl = host?.openUrl;
137
- const openUrl = useCallback((url: string) => hostOpenUrl?.(context.scopeId, url), [hostOpenUrl, context.scopeId]);
137
+ const openUrl = (url: string) => hostOpenUrl?.(context.scopeId, url);
138
138
  return {
139
139
  link: link ? resolution : undefined,
140
140
  openLink: link && host?.openLink ? open : undefined,
@@ -2,8 +2,8 @@ import { useTranslation } from 'react-i18next';
2
2
  import { ChevronRight, GitFork } from 'lucide-react';
3
3
  import { useForkIdsAfter } from '../../forks';
4
4
  import { ROW_GUTTER } from '../icons';
5
- import { useChatHost } from '../../../host';
6
5
  import { Icon, Menu } from '@adecore/ui';
6
+ import { useHostChatPlace } from '../../../host-hooks';
7
7
 
8
8
  const LINE = '-mx-1 mb-0.5 flex h-7 items-center gap-2 rounded-md px-1 text-xs text-text-muted';
9
9
  const LINK = `${LINE} hover:bg-surface-hover hover:text-text data-[popup-open]:bg-surface-hover data-[popup-open]:text-text`;
@@ -52,8 +52,7 @@ function ForksLabel({ label, link = true }: { label: string; link?: boolean }) {
52
52
 
53
53
  // A fork no longer in this project has nowhere to lead, so it only says it is there.
54
54
  function OneFork({ forkId, label }: { forkId: string; label: string }) {
55
- const host = useChatHost();
56
- const place = host.useChatPlace(forkId);
55
+ const place = useHostChatPlace(forkId);
57
56
  return (
58
57
  <div className="flex">
59
58
  {place.title === null ? (
@@ -70,9 +69,8 @@ function OneFork({ forkId, label }: { forkId: string; label: string }) {
70
69
  }
71
70
 
72
71
  function ForkItem({ forkId }: { forkId: string }) {
73
- const host = useChatHost();
74
72
  const { t } = useTranslation('agent-chat');
75
- const place = host.useChatPlace(forkId);
73
+ const place = useHostChatPlace(forkId);
76
74
  return (
77
75
  <Menu.Item disabled={place.title === null} onClick={place.go}>
78
76
  <Icon icon={GitFork} size={14} /> <span className="truncate">{place.title ?? t('fork.pill.label')}</span>
@@ -16,6 +16,7 @@ import { useFileLinkCwd, useOpenFileLink } from '../file-links';
16
16
  import { ImageThumb } from '../ImageView';
17
17
  import { ROW_GUTTER } from '../icons';
18
18
  import { RunningFor, WorkRow } from './WorkRows';
19
+ import { useHostAttachmentUrl } from '../../../host-hooks';
19
20
 
20
21
  const SAVED_FLASH_MS = 2000;
21
22
 
@@ -94,7 +95,7 @@ function ReadyImage({ chatId, attachment, prompt, transparent }: { chatId: strin
94
95
  const { t } = useTranslation('agent-chat');
95
96
  const { id: scopeId } = useChatScope();
96
97
  const { attachments } = useChatHost();
97
- const source = attachments.useUrl(scopeId, chatId, attachment.id);
98
+ const source = useHostAttachmentUrl(scopeId, chatId, attachment.id);
98
99
  const savedKey = `${scopeId}\n${chatId}\n${attachment.id}`;
99
100
  const [lightbox, setLightbox] = useState(false);
100
101
  const [saving, setSaving] = useState(false);
@@ -1,4 +1,4 @@
1
- import { useContext, useMemo, useState, type ReactNode } from 'react';
1
+ import { useContext, useState, type ReactNode } from 'react';
2
2
  import clsx from 'clsx';
3
3
  import { useTranslation } from 'react-i18next';
4
4
  import { Bot, Brain, Check, ChevronDown, CircleAlert, File, Info, MessageCircleQuestionMark, Reply, TriangleAlert, X } from 'lucide-react';
@@ -14,7 +14,6 @@ import type {
14
14
  import { WAITING_NOTE_PREFIX } from '@adecore/agent-contracts';
15
15
  import { fileBadge, formatBytes, isImageAttachment } from '../../attachments';
16
16
  import { useChatRow, useCurrentItem } from '../../../state/chats';
17
- import { useChatHost } from '../../../host';
18
17
  import { useChatScope } from '../../../scope';
19
18
  import { splitQuote } from '../../quote';
20
19
  import { jumpToTimelineItem } from '../../timeline-scroll';
@@ -34,6 +33,7 @@ import { ROW_GUTTER } from '../icons';
34
33
  import { useOpenForFind } from '../find-reveal';
35
34
  import { ReplyContext, UiReplyNavigationContext } from '../reply-context';
36
35
  import { UiReply } from '../intelligent-ui/UiReply';
36
+ import { useHostAttachmentUrl, useHostChatPlace, useHostReplyAuthor, useHostStreaming } from '../../../host-hooks';
37
37
 
38
38
  // A long prompt folds so the answer stays in view; the reader can open it.
39
39
  const USER_FOLD_LINES = 8;
@@ -43,10 +43,9 @@ const USER_FOLD_CHARS = 600;
43
43
  const FOLD = 'max-h-[10em] overflow-hidden [mask-image:linear-gradient(to_bottom,black_70%,transparent)]';
44
44
 
45
45
  function useReplyAuthor(chatId: string) {
46
- const host = useChatHost();
47
46
  const { id } = useChatScope();
48
47
  const context = useContext(ReplyContext);
49
- const author = host.useReplyAuthor(id, context?.chatId ?? chatId);
48
+ const author = useHostReplyAuthor(id, context?.chatId ?? chatId);
50
49
  return context !== null && context.chatId === undefined ? null : author;
51
50
  }
52
51
 
@@ -55,9 +54,8 @@ function useReplyAuthor(chatId: string) {
55
54
  * hands a link that opens a window to the system browser, which cannot reach a blob of this page.
56
55
  */
57
56
  function AttachmentLink({ chatId, attachment }: { chatId: string; attachment: ChatAttachment }) {
58
- const host = useChatHost();
59
57
  const { id } = useChatScope();
60
- const { url } = host.attachments.useUrl(id, chatId, attachment.id);
58
+ const { url } = useHostAttachmentUrl(id, chatId, attachment.id);
61
59
  const badge = fileBadge(attachment.name);
62
60
  return (
63
61
  <Tooltip label={attachment.name}>
@@ -81,9 +79,8 @@ function AttachmentLink({ chatId, attachment }: { chatId: string; attachment: Ch
81
79
 
82
80
  /* A picture attached to a message, which opens large. */
83
81
  function AttachmentThumb({ chatId, attachment }: { chatId: string; attachment: ChatAttachment }) {
84
- const host = useChatHost();
85
82
  const { id } = useChatScope();
86
- const source = host.attachments.useUrl(id, chatId, attachment.id);
83
+ const source = useHostAttachmentUrl(id, chatId, attachment.id);
87
84
  return <ImageThumb source={source} alt={attachment.name} className="max-h-32 max-w-48 object-cover" />;
88
85
  }
89
86
 
@@ -268,15 +265,11 @@ function Writing() {
268
265
  * written fades anything: an old reply scrolled back into view just stands there.
269
266
  */
270
267
  export function AssistantRow({ chatId, item: derived }: { chatId: string; item: ChatAssistantItem }) {
271
- const host = useChatHost();
272
268
  const item = useCurrentItem(chatId, derived);
273
269
  const scope = useChatScope();
274
270
  const context = useContext(ReplyContext);
275
- const reply = useMemo(
276
- () => (context === null && !item.parentToolUseId ? { scopeId: scope.id, chatId, itemId: item.id, streaming: item.streaming } : undefined),
277
- [context, item.parentToolUseId, scope.id, chatId, item.id, item.streaming]
278
- );
279
- const mode = host.useStreaming();
271
+ const reply = context === null && !item.parentToolUseId ? { scopeId: scope.id, chatId, itemId: item.id, streaming: item.streaming } : undefined;
272
+ const mode = useHostStreaming();
280
273
  const [sawWriting] = useState(item.streaming);
281
274
  const live = mode === 'words' && item.streaming;
282
275
  const reveal = useRevealedText(item.text, live);
@@ -338,10 +331,9 @@ export function AssistantRow({ chatId, item: derived }: { chatId: string; item:
338
331
  * folded, it shows the heading it opens with or itself on one line, and opened, it reads as Markdown.
339
332
  */
340
333
  export function ThinkingRow({ chatId, item: derived }: { chatId: string; item: ChatThinkingItem }) {
341
- const host = useChatHost();
342
334
  const { t } = useTranslation('agent-chat');
343
335
  const item = useCurrentItem(chatId, derived);
344
- const mode = host.useStreaming();
336
+ const mode = useHostStreaming();
345
337
  const [open, setOpen] = useState(false);
346
338
  const reveal = useRevealedText(item.text, mode === 'words' && item.streaming);
347
339
  // A block at a time, the paragraphs of the thought that closed are shown as they land.
@@ -349,8 +341,8 @@ export function ThinkingRow({ chatId, item: derived }: { chatId: string; item: C
349
341
  // Whole, the thought stays behind "Thinking…" until it is done and then folds like any other.
350
342
  const shown = open || reveal.active || (settled !== null && settled !== '');
351
343
  const text = settled ?? reveal.text;
352
- const live = useMemo(() => (item.streaming && mode !== 'whole' ? thoughtLine(text) : ''), [item.streaming, mode, text]);
353
- const preview = useMemo(() => (item.streaming ? '' : thoughtPreview(item.text)), [item.streaming, item.text]);
344
+ const live = item.streaming && mode !== 'whole' ? thoughtLine(text) : '';
345
+ const preview = item.streaming ? '' : thoughtPreview(item.text);
354
346
  const duration = formatElapsedShort((item.endedAt ?? item.createdAt) - item.createdAt);
355
347
  useOpenForFind(item.id, 'text', setOpen);
356
348
  return (
@@ -401,7 +393,7 @@ export function ThinkingRow({ chatId, item: derived }: { chatId: string; item: C
401
393
  */
402
394
  export function LiveThoughtRow({ chatId, item: derived }: { chatId: string; item: ChatThinkingItem }) {
403
395
  const item = useCurrentItem(chatId, derived);
404
- const line = useMemo(() => thoughtLine(item.text), [item.text]);
396
+ const line = thoughtLine(item.text);
405
397
  if (line === '') {
406
398
  return null;
407
399
  }
@@ -465,9 +457,8 @@ export function NoteRow({ id, level, text, from }: { id: string; level: 'info' |
465
457
 
466
458
  /* "Open fork" on a note a fork sent, or "Open to answer" on one about a waiting child, while that chat is still in the project. */
467
459
  function OpenChatButton({ chatId, label }: { chatId: string; label: 'openFork' | 'openWaiting' }) {
468
- const host = useChatHost();
469
460
  const { t } = useTranslation('agent-chat');
470
- const place = host.useChatPlace(chatId);
461
+ const place = useHostChatPlace(chatId);
471
462
  if (place.title === null) {
472
463
  return null;
473
464
  }
@@ -15,9 +15,10 @@ import { RunningFor, ToggleLine, WorkLiveRow, WorkRow } from './WorkRows';
15
15
  import { entryTimeOf, statusWordOf, taskIdOf } from '../../subagent-list';
16
16
  import { useSubagentSupport } from '../../subagent-support';
17
17
  import { canOpenSubagent, crumbOf, type SubagentStep } from '../../subagent-view';
18
- import { useChatHost, type SubagentTask } from '../../../host';
18
+ import { type SubagentTask } from '../../../host';
19
19
  import { useChatScope } from '../../../scope';
20
20
  import { useCurrentItem } from '../../../state/chats';
21
+ import { useHostTask } from '../../../host-hooks';
21
22
 
22
23
  // The work of a long-running agent scrolls inside its row instead of pushing the thread away.
23
24
  const CHILDREN_MAX_PX = 320;
@@ -135,11 +136,10 @@ export function SubagentRow({
135
136
  /* Opens everything it did in the thread's place, for a surface that has somewhere to open it. */
136
137
  onOpenConversation?(): void;
137
138
  }) {
138
- const host = useChatHost();
139
139
  const { t } = useTranslation('agent-chat');
140
140
  const { id } = useChatScope();
141
141
  const taskId = taskIdOf(item);
142
- const task = host.tasks.useTask(id, taskId);
142
+ const task = useHostTask(id, taskId);
143
143
  // A task paused on its child's limit is still a running row on the wire, but nothing is at work.
144
144
  const running = item.status === 'running' && statusWordOf(item, task) !== 'paused';
145
145
  const detail = item.description || item.summary || item.subagentType || '';
@@ -39,7 +39,7 @@ function Elapsed({ startedAt }: { startedAt: number }) {
39
39
  function StateLine({ state, task }: { state: TaskRowState; task: SubagentTask | null }) {
40
40
  const { t } = useTranslation('agent-chat');
41
41
  const until = state === 'paused' ? task?.paused?.until : undefined;
42
- const now = useNow(60_000, until === undefined);
42
+ const now = useNow(60_000, until !== undefined);
43
43
  return (
44
44
  <span className={clsx('truncate text-2xs', STATE_TONE[state])}>
45
45
  {until === undefined ? t(`rows.task.${state}`) : t('rows.task.pausedUntil', { time: formatMoment(until, now) })}
@@ -23,10 +23,11 @@ import {
23
23
  } from '../../logic/tools';
24
24
  import { useOpenForFind } from '../find-reveal';
25
25
  import { useChatHost, type CommandLook } from '../../../host';
26
+ import { useCommandNames } from '../../../host-hooks';
26
27
  import { lazyNamed } from '../../../lazy';
27
28
  import { useChatActions } from '../../actions';
28
29
  import { ChatScopeContext, useChatScope } from '../../../scope';
29
- import { useCurrentItem } from '../../../state/chats';
30
+ import { useAwaitsApproval, useCurrentItem } from '../../../state/chats';
30
31
  import { useTimelineFlash } from '../../timeline-flash';
31
32
  import { formatClockDuration, formatElapsedShort } from '@adecore/ui/format';
32
33
  import { Icon, LazyBoundary, MiddleTruncate, Spinner, useTickingText } from '@adecore/ui';
@@ -71,10 +72,14 @@ function withBrand(text: string, brands: readonly string[]): ReactNode {
71
72
  return text;
72
73
  }
73
74
 
75
+ function hasNames(look: CommandLook): look is CommandLook & Required<Pick<CommandLook, 'useNames'>> {
76
+ return look.useNames !== undefined;
77
+ }
78
+
74
79
  /* The detail of a look's run, with the words its host names drawn as those names. */
75
- function NamedLookDetail({ run, chatId, useNames }: { run: CommandLookRun; chatId: string; useNames: NonNullable<CommandLook['useNames']> }) {
80
+ function NamedLookDetail({ run, chatId, look }: { run: CommandLookRun; chatId: string; look: Required<Pick<CommandLook, 'useNames'>> }) {
76
81
  const scope = useContext(ChatScopeContext);
77
- const nameOf = useNames(scope?.id ?? '', chatId);
82
+ const nameOf = useCommandNames(look, scope?.id ?? '', chatId);
78
83
  const names = run.words.flatMap((word): NamedWord[] => {
79
84
  const name = nameOf(word.text, word.option);
80
85
  return name === null ? [] : [{ start: word.start, end: word.end, word: word.text, name }];
@@ -83,12 +88,12 @@ function NamedLookDetail({ run, chatId, useNames }: { run: CommandLookRun; chatI
83
88
  }
84
89
 
85
90
  function LookDetail({ run, chatId }: { run: CommandLookRun; chatId: string }) {
86
- const { useNames } = run.look;
87
- if (useNames === undefined) {
91
+ const { look } = run;
92
+ if (!hasNames(look)) {
88
93
  return <ShellCommand command={run.detail} code={run.code} />;
89
94
  }
90
95
  // Keyed by the look, so a row whose command turns into another look's starts its hooks again.
91
- return <NamedLookDetail key={run.look.program} run={run} chatId={chatId} useNames={useNames} />;
96
+ return <NamedLookDetail key={look.program} run={run} chatId={chatId} look={look} />;
92
97
  }
93
98
 
94
99
  const TAG = 'shrink-0 rounded bg-surface-hover px-1.5 text-text-faint';
@@ -378,6 +383,8 @@ export function WorkLiveRow({ chatId, tool: derived }: { chatId: string; tool: C
378
383
  const shell = shellCommand(tool.name, tool.input);
379
384
  const { commandLooks } = useChatHost();
380
385
  const run = shell === null ? null : matchCommandLook(shell, commandLooks);
386
+ const awaiting = useAwaitsApproval(chatId, tool.toolUseId);
387
+ const { t } = useTranslation('agent-chat');
381
388
  return (
382
389
  <div>
383
390
  <ToggleLine
@@ -390,7 +397,13 @@ export function WorkLiveRow({ chatId, tool: derived }: { chatId: string; tool: C
390
397
  path={summary !== '' && toolSummaryIsPath(tool.name, tool.input)}
391
398
  open={open && opens}
392
399
  onToggle={opens ? () => setOpen((o) => !o) : undefined}
393
- trailing={<RunningFor startedAt={toolStartedAt(tool)} />}
400
+ trailing={
401
+ awaiting ? (
402
+ <span className="shrink-0 text-xs text-text-faint">{t('work.awaitingApproval')}</span>
403
+ ) : (
404
+ <RunningFor startedAt={toolStartedAt(tool)} />
405
+ )
406
+ }
394
407
  live
395
408
  />
396
409
  {open && opens && <ToolBody tool={tool} />}
@@ -1,4 +1,4 @@
1
- import { useCallback, useState } from 'react';
1
+ import { useState } from 'react';
2
2
 
3
3
  export interface ToggleSet {
4
4
  ids: ReadonlySet<string>;
@@ -15,25 +15,22 @@ export interface ToggleSet {
15
15
  export function useToggleSet(onToggle?: () => void): ToggleSet {
16
16
  const [ids, setIds] = useState<ReadonlySet<string>>(() => new Set());
17
17
 
18
- const toggle = useCallback(
19
- (id: string): void => {
20
- setIds((current) => {
21
- const next = new Set(current);
22
- if (next.has(id)) {
23
- next.delete(id);
24
- } else {
25
- next.add(id);
26
- }
27
- return next;
28
- });
29
- onToggle?.();
30
- },
31
- [onToggle]
32
- );
18
+ const toggle = (id: string): void => {
19
+ setIds((current) => {
20
+ const next = new Set(current);
21
+ if (next.has(id)) {
22
+ next.delete(id);
23
+ } else {
24
+ next.add(id);
25
+ }
26
+ return next;
27
+ });
28
+ onToggle?.();
29
+ };
33
30
 
34
- const add = useCallback((id: string): void => {
31
+ const add = (id: string): void => {
35
32
  setIds((current) => new Set(current).add(id));
36
- }, []);
33
+ };
37
34
 
38
35
  return { ids, toggle, add };
39
36
  }
@@ -1,7 +1,7 @@
1
1
  import { useLayoutEffect, useState, type RefObject } from 'react';
2
2
  import { cleanVisualVariables, type VisualAppearance, type VisualTheme, type VisualThemeVariable } from '@adecore/agent-contracts/visual';
3
- import { useChatHost } from '../../host';
4
3
  import { watchTheme } from './theme-watch';
4
+ import { useHostCodeMode } from '../../host-hooks';
5
5
 
6
6
  /* The tokens of the app's theme where a frame stands; each answers '' for a token the theme lacks. */
7
7
  export interface VisualTokens {
@@ -165,8 +165,7 @@ function readTheme(element: HTMLElement, mode: VisualAppearance): VisualTheme {
165
165
  * accent or a font a person picks reaches every frame as well.
166
166
  */
167
167
  export function useVisualTheme(ref: RefObject<HTMLElement | null>): VisualTheme | null {
168
- const host = useChatHost();
169
- const mode = host.code.useMode();
168
+ const mode = useHostCodeMode();
170
169
  const [theme, setTheme] = useState<VisualTheme | null>(null);
171
170
  useLayoutEffect(() => {
172
171
  const element = ref.current;
@@ -0,0 +1,113 @@
1
+ 'use no memo';
2
+ /*
3
+ * The hooks a host hands the views, each called through a hook of its own here. To the React Compiler a
4
+ * hook read from a context may be another function on the next render, so it leaves a component that
5
+ * calls one as written. `ChatHostProvider` pins its host and a command look's hooks stay with its row's
6
+ * key, so they never change under a mounted view; only these wrappers go uncompiled for it.
7
+ */
8
+ import type { ProviderPlatform } from '@adecore/agent-contracts';
9
+ import { useChatHost, type ChatHost, type CommandLook } from './host';
10
+
11
+ export function useHostCodeMode(): 'light' | 'dark' {
12
+ return useChatHost().code.useMode();
13
+ }
14
+
15
+ export function useHostCodeThemes(): { light: string; dark: string } {
16
+ return useChatHost().code.useThemes();
17
+ }
18
+
19
+ export function useHostAttachmentUrl(...args: Parameters<ChatHost['attachments']['useUrl']>): ReturnType<ChatHost['attachments']['useUrl']> {
20
+ return useChatHost().attachments.useUrl(...args);
21
+ }
22
+
23
+ export function useHostTasks(...args: Parameters<ChatHost['tasks']['useTasks']>): ReturnType<ChatHost['tasks']['useTasks']> {
24
+ return useChatHost().tasks.useTasks(...args);
25
+ }
26
+
27
+ export function useHostTask(...args: Parameters<ChatHost['tasks']['useTask']>): ReturnType<ChatHost['tasks']['useTask']> {
28
+ return useChatHost().tasks.useTask(...args);
29
+ }
30
+
31
+ export function useHostExtraPrompts(...args: Parameters<ChatHost['prompts']['useExtra']>): ReturnType<ChatHost['prompts']['useExtra']> {
32
+ return useChatHost().prompts.useExtra(...args);
33
+ }
34
+
35
+ export function useHostStreaming(): ReturnType<ChatHost['useStreaming']> {
36
+ return useChatHost().useStreaming();
37
+ }
38
+
39
+ export function useHostSendDelivery(): ReturnType<ChatHost['useSendDelivery']> {
40
+ return useChatHost().useSendDelivery();
41
+ }
42
+
43
+ export function useHostTimelineFind(...args: Parameters<ChatHost['useTimelineFind']>): ReturnType<ChatHost['useTimelineFind']> {
44
+ return useChatHost().useTimelineFind(...args);
45
+ }
46
+
47
+ export function useHostReferableChats(): ReturnType<ChatHost['useReferableChats']> {
48
+ return useChatHost().useReferableChats();
49
+ }
50
+
51
+ export function useHostLoginBlocked(...args: Parameters<ChatHost['useLoginBlocked']>): ReturnType<ChatHost['useLoginBlocked']> {
52
+ return useChatHost().useLoginBlocked(...args);
53
+ }
54
+
55
+ const noPlatform = (): ProviderPlatform | null => null;
56
+
57
+ /* Null where the host does not say, as it need not. */
58
+ export function useHostMachinePlatform(scopeId: string): ProviderPlatform | null {
59
+ const useMachinePlatform = useChatHost().useMachinePlatform ?? noPlatform;
60
+ return useMachinePlatform(scopeId);
61
+ }
62
+
63
+ export function useHostProjectLook(...args: Parameters<ChatHost['useProjectLook']>): ReturnType<ChatHost['useProjectLook']> {
64
+ return useChatHost().useProjectLook(...args);
65
+ }
66
+
67
+ export function useHostMachineLabel(...args: Parameters<ChatHost['useMachineLabel']>): ReturnType<ChatHost['useMachineLabel']> {
68
+ return useChatHost().useMachineLabel(...args);
69
+ }
70
+
71
+ export function useHostChatPlace(...args: Parameters<ChatHost['useChatPlace']>): ReturnType<ChatHost['useChatPlace']> {
72
+ return useChatHost().useChatPlace(...args);
73
+ }
74
+
75
+ export function useHostContextSources(...args: Parameters<ChatHost['useContextSources']>): ReturnType<ChatHost['useContextSources']> {
76
+ return useChatHost().useContextSources(...args);
77
+ }
78
+
79
+ export function useHostHidesFolder(...args: Parameters<ChatHost['useHidesFolder']>): ReturnType<ChatHost['useHidesFolder']> {
80
+ return useChatHost().useHidesFolder(...args);
81
+ }
82
+
83
+ export function useHostWelcome(...args: Parameters<ChatHost['useWelcome']>): ReturnType<ChatHost['useWelcome']> {
84
+ return useChatHost().useWelcome(...args);
85
+ }
86
+
87
+ export function useHostResumeAtReset(...args: Parameters<ChatHost['useResumeAtReset']>): ReturnType<ChatHost['useResumeAtReset']> {
88
+ return useChatHost().useResumeAtReset(...args);
89
+ }
90
+
91
+ export function useHostComposerPlaceholder(...args: Parameters<ChatHost['useComposerPlaceholder']>): ReturnType<ChatHost['useComposerPlaceholder']> {
92
+ return useChatHost().useComposerPlaceholder(...args);
93
+ }
94
+
95
+ export function useHostThreadCards(...args: Parameters<ChatHost['useThreadCards']>): ReturnType<ChatHost['useThreadCards']> {
96
+ return useChatHost().useThreadCards(...args);
97
+ }
98
+
99
+ export function useHostReplyAuthor(...args: Parameters<ChatHost['useReplyAuthor']>): ReturnType<ChatHost['useReplyAuthor']> {
100
+ return useChatHost().useReplyAuthor(...args);
101
+ }
102
+
103
+ export function useHostMapSource(maps: NonNullable<ChatHost['maps']>, scopeId: string): ReturnType<NonNullable<ChatHost['maps']>['useSource']> {
104
+ return maps.useSource(scopeId);
105
+ }
106
+
107
+ export function useCommandNames(
108
+ look: Required<Pick<CommandLook, 'useNames'>>,
109
+ scopeId: string,
110
+ chatId: string
111
+ ): ReturnType<NonNullable<CommandLook['useNames']>> {
112
+ return look.useNames(scopeId, chatId);
113
+ }
package/src/lazy.tsx CHANGED
@@ -58,6 +58,8 @@ export function lazyNamed<Module extends Record<Name, ComponentType<any>>, Name
58
58
  }
59
59
  });
60
60
  const LazyNamed = (props: ComponentProps<Module[Name]>) => {
61
+ // `loaded` fills in place; compiled, the element drawn before the module landed would stay.
62
+ 'use no memo';
61
63
  const Component: ComponentType<any> = loaded.current ?? Lazy;
62
64
  return <Component {...props} />;
63
65
  };