@adecore/agents-react 0.38.0 → 0.40.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 (351) hide show
  1. package/dist/agents/AgentModelLabel.d.ts +10 -0
  2. package/dist/agents/AgentModelLabel.js +98 -0
  3. package/dist/agents/model-name.js +2 -1
  4. package/dist/agents/provider-paths.d.ts +2 -1
  5. package/dist/agents/provider-paths.js +7 -3
  6. package/dist/chat/account-choice.js +57 -28
  7. package/dist/chat/bookmarks.js +2 -1
  8. package/dist/chat/drafts.d.ts +0 -1
  9. package/dist/chat/drafts.js +9 -28
  10. package/dist/chat/logic/picker-entries.js +2 -8
  11. package/dist/chat/logic/resume-compaction.js +2 -5
  12. package/dist/chat/logic/timeline-copy.js +2 -8
  13. package/dist/chat/logic/timeline.js +9 -10
  14. package/dist/chat/logic/workflow.js +2 -4
  15. package/dist/chat/subagent-conversation.js +2 -1
  16. package/dist/chat/ui/Composer.js +385 -360
  17. package/dist/chat/ui/GoalDock.js +2 -1
  18. package/dist/chat/ui/LimitState.js +4 -6
  19. package/dist/chat/ui/Pickers.d.ts +2 -1
  20. package/dist/chat/ui/Pickers.js +126 -123
  21. package/dist/chat/ui/PromptEditor.d.ts +19 -0
  22. package/dist/chat/ui/PromptEditor.js +115 -0
  23. package/dist/chat/ui/Timeline.d.ts +2 -1
  24. package/dist/chat/ui/Timeline.js +13 -1
  25. package/dist/chat/ui/composer/ComposerControls.d.ts +3 -0
  26. package/dist/chat/ui/composer/ComposerControls.js +235 -38
  27. package/dist/chat/ui/composer/key-handler.d.ts +1 -1
  28. package/dist/chat/ui/composer/key-handler.js +3 -11
  29. package/dist/chat/ui/composer/prompt-picks.d.ts +4 -0
  30. package/dist/chat/ui/composer/prompt-picks.js +14 -0
  31. package/dist/chat/ui/composer/use-composer-menus.d.ts +4 -49
  32. package/dist/chat/ui/composer/use-composer-menus.js +65 -519
  33. package/dist/chat/ui/composer/use-continuable-turn.js +0 -1
  34. package/dist/chat/ui/composer/use-notice.js +2 -1
  35. package/dist/chat/ui/composer/use-prompt-history.js +1 -1
  36. package/dist/chat/ui/composer/use-prompt-menus.d.ts +73 -0
  37. package/dist/chat/ui/composer/use-prompt-menus.js +499 -0
  38. package/dist/chat/ui/composer/use-take-back.js +2 -2
  39. package/dist/chat/ui/diff/ApprovalReview.js +1 -1
  40. package/dist/chat/ui/highlighter.d.ts +0 -6
  41. package/dist/chat/ui/highlighter.js +0 -12
  42. package/dist/chat/ui/icons.d.ts +0 -1
  43. package/dist/chat/ui/icons.js +0 -3
  44. package/dist/chat/ui/index.d.ts +3 -0
  45. package/dist/chat/ui/index.js +2 -0
  46. package/dist/chat/ui/rows/MessageRows.js +2 -5
  47. package/dist/chat/ui/rows/row-rhythm.js +2 -5
  48. package/dist/chat/ui/theme-watch.js +3 -7
  49. package/dist/host-hooks.d.ts +2 -1
  50. package/dist/host-hooks.js +6 -0
  51. package/dist/host.d.ts +17 -1
  52. package/dist/index.d.ts +1 -1
  53. package/dist/locales/en/agent-chat.d.ts +1 -0
  54. package/dist/locales/en/agent-chat.js +1 -0
  55. package/dist/locales/nl/agent-chat.d.ts +1 -0
  56. package/dist/locales/nl/agent-chat.js +1 -0
  57. package/dist/prompts/logic/usePromptSession.js +2 -1
  58. package/dist/providers/AddAccountForm.js +2 -1
  59. package/dist/providers/CliDetail.js +104 -130
  60. package/dist/providers/account-actions.js +6 -9
  61. package/dist/providers/index.d.ts +1 -0
  62. package/dist/providers/index.js +1 -0
  63. package/dist/state/chats.d.ts +1 -0
  64. package/dist/state/chats.js +6 -11
  65. package/dist/state/provider-accounts.d.ts +1 -1
  66. package/dist/state/provider-accounts.js +2 -8
  67. package/dist/theme.css +3 -0
  68. package/dist/transport.d.ts +2 -0
  69. package/dist/transport.js +14 -0
  70. package/dist/usage/ChartLogo.d.ts +5 -0
  71. package/dist/usage/ChartLogo.js +48 -0
  72. package/dist/usage/LimitsList.js +6 -16
  73. package/dist/usage/UsageBreakdown.js +17 -40
  74. package/dist/usage/UsageLimits.js +183 -211
  75. package/dist/usage/UsagePage.js +3 -17
  76. package/dist/usage/UsageSummary.js +4 -9
  77. package/dist/usage/limits.js +16 -31
  78. package/dist/usage/summary.d.ts +1 -1
  79. package/dist/usage/summary.js +3 -5
  80. package/package.json +26 -26
  81. package/src/agents/AccountDot.tsx +1 -0
  82. package/src/agents/AgentIcon.tsx +2 -0
  83. package/src/agents/AgentModelLabel.tsx +38 -0
  84. package/src/agents/ModelOptionControl.tsx +8 -0
  85. package/src/agents/account-limits.ts +3 -0
  86. package/src/agents/accounts.ts +12 -0
  87. package/src/agents/model-name.ts +13 -1
  88. package/src/agents/model-options.ts +2 -0
  89. package/src/agents/model-requirement.ts +4 -0
  90. package/src/agents/option-words.ts +2 -0
  91. package/src/agents/provider-paths.ts +8 -3
  92. package/src/agents/status-look.ts +1 -0
  93. package/src/chat/account-choice.ts +25 -19
  94. package/src/chat/actions.ts +5 -0
  95. package/src/chat/attachments.ts +8 -0
  96. package/src/chat/bookmarks.ts +13 -1
  97. package/src/chat/chat-client.ts +63 -0
  98. package/src/chat/chat-references.ts +3 -0
  99. package/src/chat/composer-effort.ts +5 -0
  100. package/src/chat/composer-send.ts +4 -0
  101. package/src/chat/drafts.ts +21 -17
  102. package/src/chat/forks.ts +4 -0
  103. package/src/chat/guards.ts +2 -0
  104. package/src/chat/index.ts +7 -0
  105. package/src/chat/logic/ansi.ts +47 -0
  106. package/src/chat/logic/bookmarks.ts +7 -0
  107. package/src/chat/logic/command-looks.ts +29 -0
  108. package/src/chat/logic/context-usage.ts +3 -0
  109. package/src/chat/logic/continue-after-stop.ts +5 -0
  110. package/src/chat/logic/effort.ts +4 -0
  111. package/src/chat/logic/embedded-code.ts +63 -0
  112. package/src/chat/logic/fork.ts +22 -0
  113. package/src/chat/logic/generated-image.ts +7 -0
  114. package/src/chat/logic/goal.ts +7 -0
  115. package/src/chat/logic/handback.ts +2 -0
  116. package/src/chat/logic/limit.ts +8 -0
  117. package/src/chat/logic/picker-entries.ts +16 -4
  118. package/src/chat/logic/resume-compaction.ts +22 -5
  119. package/src/chat/logic/scrubber.ts +38 -5
  120. package/src/chat/logic/thought.ts +5 -0
  121. package/src/chat/logic/thread-cards.ts +6 -0
  122. package/src/chat/logic/timeline-copy.ts +4 -9
  123. package/src/chat/logic/timeline-target.ts +15 -0
  124. package/src/chat/logic/timeline.ts +113 -10
  125. package/src/chat/logic/tools.ts +30 -0
  126. package/src/chat/logic/visual-height.ts +5 -0
  127. package/src/chat/logic/visual-viewport.ts +1 -0
  128. package/src/chat/logic/welcome.ts +3 -0
  129. package/src/chat/logic/workflow.ts +26 -7
  130. package/src/chat/mentions.ts +56 -0
  131. package/src/chat/pending-prompts.ts +16 -0
  132. package/src/chat/persisted-json.ts +15 -0
  133. package/src/chat/preferences.ts +16 -0
  134. package/src/chat/prompt-hold.ts +2 -0
  135. package/src/chat/quote.ts +7 -0
  136. package/src/chat/reading-width.ts +1 -0
  137. package/src/chat/recent-messages.ts +5 -0
  138. package/src/chat/resume-compaction-dismissals.ts +1 -0
  139. package/src/chat/stash.ts +12 -0
  140. package/src/chat/subagent-conversation.ts +24 -4
  141. package/src/chat/subagent-list.ts +14 -0
  142. package/src/chat/subagent-support.ts +1 -0
  143. package/src/chat/subagent-view.ts +9 -0
  144. package/src/chat/thumbnails.ts +14 -0
  145. package/src/chat/timeline-flash.ts +2 -0
  146. package/src/chat/timeline-scroll.ts +23 -0
  147. package/src/chat/ui/AccountPill.tsx +4 -0
  148. package/src/chat/ui/AnsiOutput.tsx +1 -0
  149. package/src/chat/ui/BookmarkMarker.tsx +5 -0
  150. package/src/chat/ui/BookmarkSubmenu.tsx +1 -0
  151. package/src/chat/ui/ChatActivity.tsx +13 -0
  152. package/src/chat/ui/CodeBlock.tsx +8 -0
  153. package/src/chat/ui/Composer.tsx +27 -3
  154. package/src/chat/ui/ComposerInput.tsx +22 -0
  155. package/src/chat/ui/DiffPool.tsx +3 -0
  156. package/src/chat/ui/EditDiff.tsx +5 -0
  157. package/src/chat/ui/GoalDock.tsx +13 -1
  158. package/src/chat/ui/ImageView.tsx +11 -0
  159. package/src/chat/ui/LimitState.tsx +23 -6
  160. package/src/chat/ui/Markdown.tsx +41 -0
  161. package/src/chat/ui/MermaidBlock.tsx +16 -0
  162. package/src/chat/ui/MessageActions.tsx +8 -0
  163. package/src/chat/ui/ModelMarks.tsx +1 -0
  164. package/src/chat/ui/Pickers.tsx +30 -1
  165. package/src/chat/ui/PromptComposer.tsx +2 -0
  166. package/src/chat/ui/PromptEditor.tsx +136 -0
  167. package/src/chat/ui/QuoteButton.tsx +12 -0
  168. package/src/chat/ui/ReferenceChip.tsx +3 -0
  169. package/src/chat/ui/ResumeCompactionDock.tsx +1 -0
  170. package/src/chat/ui/RowTime.tsx +1 -0
  171. package/src/chat/ui/RunSettings.tsx +38 -0
  172. package/src/chat/ui/Scrubber.tsx +14 -0
  173. package/src/chat/ui/SessionLine.tsx +1 -0
  174. package/src/chat/ui/ShellCommand.tsx +32 -0
  175. package/src/chat/ui/SubagentControls.tsx +7 -0
  176. package/src/chat/ui/SubagentInfo.tsx +1 -0
  177. package/src/chat/ui/SubagentStopButton.tsx +6 -0
  178. package/src/chat/ui/SubagentTimeline.tsx +10 -0
  179. package/src/chat/ui/Timeline.tsx +141 -1
  180. package/src/chat/ui/TimelineMenu.tsx +5 -0
  181. package/src/chat/ui/UnifiedDiff.tsx +6 -0
  182. package/src/chat/ui/UploadThumb.tsx +2 -0
  183. package/src/chat/ui/VisualDialogs.tsx +3 -0
  184. package/src/chat/ui/VisualFrame.tsx +15 -0
  185. package/src/chat/ui/Welcome.tsx +1 -0
  186. package/src/chat/ui/chip-clipboard.ts +20 -0
  187. package/src/chat/ui/code-lines.ts +14 -0
  188. package/src/chat/ui/code-theme.ts +1 -0
  189. package/src/chat/ui/composer/ComposerControls.tsx +70 -15
  190. package/src/chat/ui/composer/ComposerMenu.tsx +12 -0
  191. package/src/chat/ui/composer/DraftParts.tsx +2 -0
  192. package/src/chat/ui/composer/QueuedMessages.tsx +4 -0
  193. package/src/chat/ui/composer/chip-paste.ts +16 -0
  194. package/src/chat/ui/composer/chips.ts +6 -0
  195. package/src/chat/ui/composer/editor.ts +9 -0
  196. package/src/chat/ui/composer/insert.ts +2 -0
  197. package/src/chat/ui/composer/key-handler.ts +42 -9
  198. package/src/chat/ui/composer/keys.ts +23 -0
  199. package/src/chat/ui/composer/placeholder.ts +6 -0
  200. package/src/chat/ui/composer/prompt-picks.ts +18 -0
  201. package/src/chat/ui/composer/surface.ts +5 -0
  202. package/src/chat/ui/composer/use-chat-controls.ts +13 -0
  203. package/src/chat/ui/composer/use-compaction-offer.ts +3 -0
  204. package/src/chat/ui/composer/use-composer-menus.ts +20 -275
  205. package/src/chat/ui/composer/use-composer-submit.ts +27 -0
  206. package/src/chat/ui/composer/use-continuable-turn.ts +3 -5
  207. package/src/chat/ui/composer/use-draft-files.ts +24 -0
  208. package/src/chat/ui/composer/use-effort-stepper.ts +8 -0
  209. package/src/chat/ui/composer/use-notice.ts +4 -1
  210. package/src/chat/ui/composer/use-pending-requests.ts +3 -0
  211. package/src/chat/ui/composer/use-prompt-history.ts +20 -11
  212. package/src/chat/ui/composer/use-prompt-hold.ts +3 -0
  213. package/src/chat/ui/composer/use-prompt-menus.ts +361 -0
  214. package/src/chat/ui/composer/use-take-back.ts +20 -2
  215. package/src/chat/ui/diff/ApprovalReview.tsx +18 -15
  216. package/src/chat/ui/diff/DiffFallbackBoundary.tsx +1 -0
  217. package/src/chat/ui/diff/DiffOmitted.tsx +1 -0
  218. package/src/chat/ui/diff/DiffStack.tsx +2 -0
  219. package/src/chat/ui/diff/DiffUnavailable.tsx +1 -0
  220. package/src/chat/ui/diff/EditorEditDiff.tsx +13 -0
  221. package/src/chat/ui/diff/EditorPatchDiff.tsx +4 -0
  222. package/src/chat/ui/diff/LegacyDiffPool.tsx +2 -0
  223. package/src/chat/ui/diff/LegacyEditDiff.tsx +2 -0
  224. package/src/chat/ui/diff/LegacyUnifiedDiff.tsx +8 -0
  225. package/src/chat/ui/diff/RawDiff.tsx +1 -0
  226. package/src/chat/ui/diff/ReviewDiff.tsx +1 -0
  227. package/src/chat/ui/diff/diff-source-budget.ts +8 -0
  228. package/src/chat/ui/diff/editor-edit-model.ts +4 -0
  229. package/src/chat/ui/diff/review-plan.ts +9 -0
  230. package/src/chat/ui/diff/review-settle.ts +1 -0
  231. package/src/chat/ui/diff/syntax-runtime.ts +52 -0
  232. package/src/chat/ui/diff/use-review-stack.ts +9 -0
  233. package/src/chat/ui/diff-syntax.ts +12 -0
  234. package/src/chat/ui/diff-theme.ts +2 -0
  235. package/src/chat/ui/file-links.ts +2 -0
  236. package/src/chat/ui/find-reveal.ts +1 -0
  237. package/src/chat/ui/full-diff.ts +1 -0
  238. package/src/chat/ui/highlighter.ts +29 -15
  239. package/src/chat/ui/icons.tsx +2 -4
  240. package/src/chat/ui/index.ts +7 -0
  241. package/src/chat/ui/intelligent-ui/UiBlockFrame.tsx +25 -0
  242. package/src/chat/ui/intelligent-ui/UiFallbackPart.tsx +1 -0
  243. package/src/chat/ui/intelligent-ui/UiReply.tsx +63 -0
  244. package/src/chat/ui/intelligent-ui/block-local.ts +5 -0
  245. package/src/chat/ui/intelligent-ui/chart-data.ts +15 -0
  246. package/src/chat/ui/intelligent-ui/node-text.ts +17 -0
  247. package/src/chat/ui/intelligent-ui/renderers/binding.ts +1 -0
  248. package/src/chat/ui/intelligent-ui/renderers/chart.tsx +31 -0
  249. package/src/chat/ui/intelligent-ui/renderers/choices.tsx +4 -0
  250. package/src/chat/ui/intelligent-ui/renderers/content.tsx +18 -0
  251. package/src/chat/ui/intelligent-ui/renderers/data.tsx +11 -0
  252. package/src/chat/ui/intelligent-ui/renderers/inputs.tsx +13 -0
  253. package/src/chat/ui/intelligent-ui/renderers/links.tsx +9 -0
  254. package/src/chat/ui/intelligent-ui/renderers/map-slots.ts +15 -0
  255. package/src/chat/ui/intelligent-ui/renderers/map-style.ts +15 -0
  256. package/src/chat/ui/intelligent-ui/renderers/map-view.tsx +48 -0
  257. package/src/chat/ui/intelligent-ui/renderers/map.tsx +20 -0
  258. package/src/chat/ui/intelligent-ui/renderers/place-point.ts +3 -0
  259. package/src/chat/ui/intelligent-ui/renderers/structure.tsx +3 -0
  260. package/src/chat/ui/intelligent-ui/renderers/text.tsx +8 -0
  261. package/src/chat/ui/intelligent-ui/reply-parts.ts +5 -0
  262. package/src/chat/ui/intelligent-ui/table-data.ts +17 -0
  263. package/src/chat/ui/intelligent-ui/use-in-view.ts +4 -0
  264. package/src/chat/ui/intelligent-ui/use-later.ts +4 -0
  265. package/src/chat/ui/intelligent-ui/use-truncated.ts +5 -0
  266. package/src/chat/ui/intelligent-ui/use-ui-links.ts +29 -0
  267. package/src/chat/ui/intelligent-ui/use-ui-queries.ts +60 -0
  268. package/src/chat/ui/markdown-blocks.ts +64 -0
  269. package/src/chat/ui/mermaid.ts +4 -0
  270. package/src/chat/ui/quote-selection.ts +10 -0
  271. package/src/chat/ui/rehype-chips.ts +5 -0
  272. package/src/chat/ui/rehype-fade.ts +2 -0
  273. package/src/chat/ui/remark-html-as-text.ts +5 -0
  274. package/src/chat/ui/reveal.ts +18 -0
  275. package/src/chat/ui/rows/ForksRow.tsx +5 -0
  276. package/src/chat/ui/rows/GeneratedImageRow.tsx +10 -0
  277. package/src/chat/ui/rows/MessageRows.tsx +29 -5
  278. package/src/chat/ui/rows/RowContainer.tsx +1 -0
  279. package/src/chat/ui/rows/Rows.tsx +2 -0
  280. package/src/chat/ui/rows/SubagentRow.tsx +13 -0
  281. package/src/chat/ui/rows/TaskRow.tsx +7 -0
  282. package/src/chat/ui/rows/VisualRow.tsx +4 -0
  283. package/src/chat/ui/rows/WorkRows.tsx +46 -0
  284. package/src/chat/ui/rows/WorkflowRow.tsx +10 -0
  285. package/src/chat/ui/rows/row-rhythm.ts +7 -5
  286. package/src/chat/ui/theme-watch.ts +8 -7
  287. package/src/chat/ui/thread-references.ts +7 -0
  288. package/src/chat/ui/use-diff-source-tokens.ts +8 -0
  289. package/src/chat/ui/useToggleSet.ts +3 -0
  290. package/src/chat/ui/visual-theme.ts +30 -0
  291. package/src/chat/visual-bridge.ts +23 -0
  292. package/src/chat/visual-viewport.ts +12 -0
  293. package/src/host-hooks.ts +15 -5
  294. package/src/host.ts +29 -1
  295. package/src/index.ts +5 -0
  296. package/src/lazy.tsx +9 -0
  297. package/src/locales/en/agent-chat.ts +1 -0
  298. package/src/locales/nl/agent-chat.ts +1 -0
  299. package/src/mounted-registry.ts +4 -0
  300. package/src/port-transport.ts +32 -0
  301. package/src/prompts/index.ts +2 -0
  302. package/src/prompts/logic/focus.ts +5 -0
  303. package/src/prompts/logic/keys.ts +12 -0
  304. package/src/prompts/logic/prompts.ts +8 -0
  305. package/src/prompts/logic/subjects.ts +8 -0
  306. package/src/prompts/logic/useFocusAfterAnswer.ts +2 -0
  307. package/src/prompts/logic/usePromptSession.ts +13 -1
  308. package/src/prompts/ui/ApprovalBody.tsx +2 -0
  309. package/src/prompts/ui/PromptActions.tsx +2 -0
  310. package/src/prompts/ui/PromptCard.tsx +6 -0
  311. package/src/prompts/ui/PromptView.tsx +6 -0
  312. package/src/prompts/ui/QuestionBody.tsx +11 -0
  313. package/src/providers/AccountColors.tsx +1 -0
  314. package/src/providers/AccountDetail.tsx +7 -0
  315. package/src/providers/AccountVariables.tsx +2 -0
  316. package/src/providers/AddAccountForm.tsx +5 -1
  317. package/src/providers/CliDetail.tsx +6 -5
  318. package/src/providers/InstallPage.tsx +11 -0
  319. package/src/providers/ProviderList.tsx +3 -0
  320. package/src/providers/ProvidersPane.tsx +18 -0
  321. package/src/providers/account-actions.ts +10 -8
  322. package/src/providers/index.ts +1 -0
  323. package/src/providers/install-steps.ts +3 -0
  324. package/src/providers/pane-target.ts +5 -0
  325. package/src/providers/provider-abilities.ts +1 -0
  326. package/src/providers/provider-groups.ts +6 -0
  327. package/src/providers/variables.ts +12 -0
  328. package/src/scope.ts +2 -0
  329. package/src/state/chats.ts +61 -14
  330. package/src/state/index.ts +2 -0
  331. package/src/state/provider-accounts.ts +7 -9
  332. package/src/state/providers.ts +1 -0
  333. package/src/state/usage.ts +6 -0
  334. package/src/storage.ts +18 -0
  335. package/src/testing/prompts.ts +5 -0
  336. package/src/theme.css +3 -0
  337. package/src/transport.ts +18 -0
  338. package/src/usage/ChartLogo.tsx +12 -0
  339. package/src/usage/LimitsList.tsx +7 -8
  340. package/src/usage/UsageBreakdown.tsx +11 -4
  341. package/src/usage/UsageChart.tsx +5 -0
  342. package/src/usage/UsageLimits.tsx +10 -7
  343. package/src/usage/UsageLimitsCard.tsx +2 -0
  344. package/src/usage/UsagePage.tsx +16 -19
  345. package/src/usage/UsageSummary.tsx +4 -5
  346. package/src/usage/UsageTiles.tsx +2 -0
  347. package/src/usage/format.ts +7 -0
  348. package/src/usage/limit-groups.ts +14 -0
  349. package/src/usage/limits.ts +11 -13
  350. package/src/usage/money.ts +1 -0
  351. package/src/usage/summary.ts +15 -7
@@ -39,6 +39,7 @@ export function BookmarkMarker({ chatId, itemId, bookmark }: BookmarkMarkerProps
39
39
  initial={bookmark?.name ?? ''}
40
40
  onDone={(name) => {
41
41
  useBookmarkNaming.getState().close();
42
+
42
43
  if (name !== null) {
43
44
  void nameBookmark(scope, host, chatId, itemId, name, bookmark?.name);
44
45
  }
@@ -73,6 +74,7 @@ function NameField({ initial, onDone }: { initial: string; onDone: (name: string
73
74
  useEffect(() => {
74
75
  ref.current?.focus();
75
76
  const frame = requestAnimationFrame(() => ref.current?.focus());
77
+
76
78
  return () => cancelAnimationFrame(frame);
77
79
  }, []);
78
80
 
@@ -80,6 +82,7 @@ function NameField({ initial, onDone }: { initial: string; onDone: (name: string
80
82
  if (settled.current) {
81
83
  return;
82
84
  }
85
+
83
86
  settled.current = true;
84
87
  onDone(name);
85
88
  };
@@ -98,9 +101,11 @@ function NameField({ initial, onDone }: { initial: string; onDone: (name: string
98
101
  onBlur={(e) => settle(e.currentTarget.value)}
99
102
  onKeyDown={(e) => {
100
103
  e.stopPropagation();
104
+
101
105
  if (e.key === 'Enter') {
102
106
  settle(e.currentTarget.value);
103
107
  }
108
+
104
109
  if (e.key === 'Escape') {
105
110
  settle(null);
106
111
  }
@@ -18,6 +18,7 @@ export function BookmarkSubmenu({ chatId }: { chatId: string }) {
18
18
  const host = useChatHost();
19
19
  const place = useHostChatPlace(chatId);
20
20
  const sorted = bookmarksInThreadOrder(bookmarks ?? [], order ?? []);
21
+
21
22
  if (sorted.length === 0) {
22
23
  return null;
23
24
  }
@@ -36,28 +36,37 @@ export function ChatActivity({ chatId }: { chatId: string }) {
36
36
  const tasks = useHostTasks(id);
37
37
  // The infos of these sub-agents' own chats, so the info of any other chat changing does not draw this again.
38
38
  const children = useChats(useShallow((s) => subagents.map((item) => (item.childId === undefined ? undefined : s.statusByKey[keyOf(item.childId)]?.info))));
39
+
39
40
  const progress = progressOf(
40
41
  subagents.map((item, index) => {
41
42
  const taskId = taskIdOf(item);
43
+
42
44
  return taskRowStateOf(item, taskId === null ? null : (tasks?.[taskId] ?? null), children[index]);
43
45
  })
44
46
  );
47
+
45
48
  const words = subagents.map((item) => {
46
49
  const taskId = taskIdOf(item);
50
+
47
51
  return statusWordOf(item, taskId === null ? null : (tasks?.[taskId] ?? null));
48
52
  });
53
+
49
54
  const background = useChatRow(chatId, (row) => row?.info.background) ?? NO_TASKS;
55
+
50
56
  if (subagents.length === 0 && background.length === 0) {
51
57
  return null;
52
58
  }
59
+
53
60
  const { shells, monitors } = backgroundCounts(background);
54
61
  const Slot = host.SubagentSlot;
55
62
  const counting = progress.active > 0 && progress.total > 1;
63
+
56
64
  const label = counting
57
65
  ? [t('activity.progress', { done: progress.done, total: progress.total }), progress.waiting > 0 && t('activity.needsYou', { count: progress.waiting })]
58
66
  .filter(Boolean)
59
67
  .join(', ')
60
68
  : t('activity.subagents', { count: badgeCountOf(words) });
69
+
61
70
  return (
62
71
  <div className="mb-3 flex flex-wrap items-center gap-2">
63
72
  {subagents.length > 0 &&
@@ -94,6 +103,7 @@ export function ChatActivity({ chatId }: { chatId: string }) {
94
103
 
95
104
  export function StatusIcon({ word }: { word: StatusWord }) {
96
105
  const look = statusLookOf(word);
106
+
97
107
  return <Icon icon={look.icon} size={14} className={clsx('shrink-0', look.tone, look.spins && 'animate-spin')} />;
98
108
  }
99
109
 
@@ -142,6 +152,7 @@ function ActivityRow({
142
152
  {time !== '' && <span className="shrink-0 text-xs text-text-faint tabular-nums">{time}</span>}
143
153
  </>
144
154
  );
155
+
145
156
  // The stop is a button of its own beside the line, since a button cannot hold another.
146
157
  return (
147
158
  <div className={clsx('flex items-center gap-1 rounded-md', onOpen && 'hover:bg-surface-hover')}>
@@ -163,6 +174,7 @@ function SubagentRows({ chatId, items }: { chatId: string; items: readonly ChatS
163
174
  1000,
164
175
  items.some((item) => item.status === 'running')
165
176
  );
177
+
166
178
  return items.map((item) => <SubagentEntry key={item.id} chatId={chatId} item={item} now={now} />);
167
179
  }
168
180
 
@@ -175,6 +187,7 @@ function SubagentEntry({ chatId, item, now }: { chatId: string; item: ChatSubage
175
187
  const child = useChats((s) => (item.childId === undefined ? undefined : s.statusByKey[keyOf(item.childId)]?.info));
176
188
  const word = statusWordOf(item, task);
177
189
  const state = taskRowStateOf(item, task, child);
190
+
178
191
  return (
179
192
  <ActivityRow
180
193
  icon={<StatusIcon word={word} />}
@@ -51,7 +51,9 @@ export function CodeBlock({ code, lang, actions, view }: { code: string; lang: s
51
51
  if (copyState !== 'copied') {
52
52
  return;
53
53
  }
54
+
54
55
  const timer = setTimeout(() => setCopyState('idle'), COPIED_MS);
56
+
55
57
  return () => clearTimeout(timer);
56
58
  }, [copyState]);
57
59
 
@@ -59,8 +61,10 @@ export function CodeBlock({ code, lang, actions, view }: { code: string; lang: s
59
61
  if (copying.current) {
60
62
  return;
61
63
  }
64
+
62
65
  copying.current = true;
63
66
  setCopyState('copying');
67
+
64
68
  try {
65
69
  // The best-effort clipboard helper cannot distinguish a refusal from success.
66
70
  await navigator.clipboard.writeText(code);
@@ -76,16 +80,20 @@ export function CodeBlock({ code, lang, actions, view }: { code: string; lang: s
76
80
  if (tokenizer !== null) {
77
81
  return;
78
82
  }
83
+
79
84
  let cancelled = false;
85
+
80
86
  Promise.all([highlighter.loadLanguage(lang), highlighter.loadTheme(theme, custom)])
81
87
  .then(() => !cancelled && setLoaded(`${lang}:${theme}`))
82
88
  .catch(() => !cancelled && setLoaded('failed'));
89
+
83
90
  return () => {
84
91
  cancelled = true;
85
92
  };
86
93
  }, [highlighter, lang, theme, custom, tokenizer]);
87
94
 
88
95
  const pending = (tokenizer === null || tokens === null) && loaded !== 'failed';
96
+
89
97
  return (
90
98
  <div className="chat-code" data-copy-state={copyState}>
91
99
  {view ?? (
@@ -44,7 +44,7 @@ import { usePromptHistory } from './composer/use-prompt-history';
44
44
  import { usePromptHold } from './composer/use-prompt-hold';
45
45
  import { surfacePartOf } from './composer/surface';
46
46
  import { useTakeBack } from './composer/use-take-back';
47
- import { useHostExtraPrompts, useHostSendDelivery } from '../../host-hooks';
47
+ import { useHostComposerSendActions, useHostExtraPrompts, useHostSendDelivery } from '../../host-hooks';
48
48
 
49
49
  interface ComposerProps {
50
50
  chatId: string;
@@ -70,9 +70,11 @@ function sendLabelKey(busy: boolean, steerable: boolean, delivery: 'queue' | 'st
70
70
  if (!busy) {
71
71
  return 'composer.send';
72
72
  }
73
+
73
74
  if (!steerable) {
74
75
  return 'composer.queueButton';
75
76
  }
77
+
76
78
  return delivery === 'steer' ? 'composer.steerButton' : 'composer.queueWithSteerButton';
77
79
  }
78
80
 
@@ -96,6 +98,7 @@ export function Composer({ chatId, info, focused, answerPromptsElsewhere, disabl
96
98
  const notice = useNotice();
97
99
  const history = usePromptHistory(chatId, box.setText);
98
100
  const menus = useComposerMenus({ chatId, info, capabilities, providerName: provider?.name, draft: box, inputRef });
101
+
99
102
  const files = useDraftFiles({
100
103
  capabilities,
101
104
  providerName: provider?.name,
@@ -107,7 +110,9 @@ export function Composer({ chatId, info, focused, answerPromptsElsewhere, disabl
107
110
  referables: menus.referables.chatsOnly ? menus.referables.items.filter((item) => item.kind === 'chat') : menus.referables.items,
108
111
  referenceChips: menus.referenceChips
109
112
  });
113
+
110
114
  const controls = useChatControls({ chatId, info, notice, onRetarget });
115
+
111
116
  useEffortStepper({
112
117
  chatId,
113
118
  info,
@@ -116,11 +121,14 @@ export function Composer({ chatId, info, focused, answerPromptsElsewhere, disabl
116
121
  controls,
117
122
  setNotice: notice.setNotice
118
123
  });
124
+
119
125
  const guard = promptGuard(withQuote(draft.quote, draft.text));
120
126
  const continuable = useContinuableTurn(chatId, info);
121
127
  // The stopped turn something went out for, since the chat takes a moment to answer and Continue must not stand there meanwhile.
122
128
  const [sentFor, setSentFor] = useState<string | null>(null);
123
129
  const extraPrompts = useHostExtraPrompts(scope.id, chatId);
130
+ const sendActions = useHostComposerSendActions(scope.id, chatId);
131
+
124
132
  const { submit, continueTurn, restoreStashed, toggleStash } = useComposerSubmit({
125
133
  chatId,
126
134
  writable,
@@ -137,6 +145,7 @@ export function Composer({ chatId, info, focused, answerPromptsElsewhere, disabl
137
145
  onSend: (text, extras) => {
138
146
  setSentFor(continuable);
139
147
  const sent = onSend(text, extras);
148
+
140
149
  // A send the host did not take leaves Continue where it was; the original promise still reaches its caller.
141
150
  void Promise.resolve(sent).then(
142
151
  (taken) => {
@@ -146,12 +155,15 @@ export function Composer({ chatId, info, focused, answerPromptsElsewhere, disabl
146
155
  },
147
156
  (error: unknown) => {
148
157
  setSentFor(null);
158
+
149
159
  throw error;
150
160
  }
151
161
  );
162
+
152
163
  return sent;
153
164
  }
154
165
  });
166
+
155
167
  const { takingBack, takeBack } = useTakeBack({
156
168
  chatId,
157
169
  draft: box,
@@ -161,16 +173,19 @@ export function Composer({ chatId, info, focused, answerPromptsElsewhere, disabl
161
173
  inputRef.current?.focus();
162
174
  }
163
175
  });
176
+
164
177
  const pending = usePendingRequests(chatId);
165
178
  const compactionOffer = useCompactionOffer(chatId, info, capabilities?.compaction);
166
179
  const placeholder = useHintedPlaceholder({ chatId, disabled, readOnly, mentionable: capabilities?.mentions !== false, hasSkills: menus.hasSkills });
167
180
  const editorExtensions = [chipDecorations({ mentions: draft.mentions, skills: draft.skills, references: menus.referenceChips }), LEAVE_DROPS_TO_THE_CARD];
181
+
168
182
  /* The timeline owns the scroller; this is the one bit of it the composer needs to know. */
169
183
  const atEnd = useSyncExternalStore(
170
184
  subscribeTimelineEnd,
171
185
  () => timelineAtEnd(chatId),
172
186
  () => true
173
187
  );
188
+
174
189
  const queue = info.queue ?? [];
175
190
  const empty = isEmptyDraft(draft);
176
191
 
@@ -189,7 +204,6 @@ export function Composer({ chatId, info, focused, answerPromptsElsewhere, disabl
189
204
  history,
190
205
  noteKey: files.noteKey,
191
206
  toggleStash,
192
- setText: (next) => box.setText(next),
193
207
  submit
194
208
  });
195
209
 
@@ -201,6 +215,7 @@ export function Composer({ chatId, info, focused, answerPromptsElsewhere, disabl
201
215
  if (!writable || event.button !== 0 || event.defaultPrevented || surfacePartOf(event.target, event.currentTarget) !== 'surface') {
202
216
  return;
203
217
  }
218
+
204
219
  // Nothing around the field selects, so the default would only blur it on the way, closing its picker and lifting a held prompt card.
205
220
  event.preventDefault();
206
221
  inputRef.current?.setCaret(Infinity);
@@ -336,7 +351,16 @@ export function Composer({ chatId, info, focused, answerPromptsElsewhere, disabl
336
351
  onContinue:
337
352
  continuable !== null && continuable !== sentFor && empty && writable && pending.length === 0 && extraPrompts.length === 0
338
353
  ? continueTurn
339
- : null
354
+ : null,
355
+ actions: sendActions,
356
+ draft: {
357
+ scopeId: scope.id,
358
+ chatId,
359
+ text: withQuote(draft.quote, draft.text.trim()),
360
+ provider: info.provider,
361
+ selection: info.selection,
362
+ runtimeMode: info.runtimeMode
363
+ }
340
364
  }}
341
365
  dictationToolbar={setDictationToolbar}
342
366
  onFiles={(picked) => {
@@ -69,12 +69,14 @@ export function ComposerInput({
69
69
  const hostRef = useRef<HTMLDivElement>(null);
70
70
  const targetRef = useRef<HTMLDivElement>(null);
71
71
  const viewRef = useRef<EditorView | null>(null);
72
+
72
73
  const [compartments] = useState(() => ({
73
74
  attributes: new Compartment(),
74
75
  editable: new Compartment(),
75
76
  placeholder: new Compartment(),
76
77
  extensions: new Compartment()
77
78
  }));
79
+
78
80
  const latest = useRef({ value, handlers });
79
81
  // What the editor last reported. The parent handing that back is catching up, not setting a value of its own.
80
82
  const reported = useRef(value);
@@ -85,10 +87,13 @@ export function ComposerInput({
85
87
 
86
88
  useLayoutEffect(() => {
87
89
  const host = hostRef.current;
90
+
88
91
  if (!host) {
89
92
  return;
90
93
  }
94
+
91
95
  const initial = latest.current.value;
96
+
92
97
  const view = new EditorView({
93
98
  parent: host,
94
99
  state: EditorState.create({
@@ -109,24 +114,30 @@ export function ComposerInput({
109
114
  cut: (event, target) => latest.current.handlers.onCopy?.(event, target) ?? false,
110
115
  compositionstart: () => {
111
116
  latest.current.handlers.onComposing?.(true);
117
+
112
118
  return false;
113
119
  },
114
120
  compositionend: () => {
115
121
  latest.current.handlers.onComposing?.(false);
122
+
116
123
  return false;
117
124
  }
118
125
  })
119
126
  ),
120
127
  EditorView.updateListener.of((update) => {
121
128
  const current = latest.current.handlers;
129
+
122
130
  if (update.focusChanged && !update.view.hasFocus) {
123
131
  current.onBlur?.();
124
132
  }
133
+
125
134
  if ((!update.docChanged && !update.selectionSet) || update.transactions.some((tr) => tr.annotation(externalChange))) {
126
135
  return;
127
136
  }
137
+
128
138
  const text = update.state.doc.toString();
129
139
  const { from, to } = update.state.selection.main;
140
+
130
141
  if (update.docChanged) {
131
142
  reported.current = text;
132
143
  current.onChange(text, { from, to }, update.state);
@@ -137,7 +148,9 @@ export function ComposerInput({
137
148
  ]
138
149
  })
139
150
  });
151
+
140
152
  viewRef.current = view;
153
+
141
154
  return () => {
142
155
  view.destroy();
143
156
  viewRef.current = null;
@@ -158,14 +171,18 @@ export function ComposerInput({
158
171
 
159
172
  useLayoutEffect(() => {
160
173
  const view = viewRef.current;
174
+
161
175
  if (!view || value === reported.current) {
162
176
  return;
163
177
  }
178
+
164
179
  reported.current = value;
165
180
  const doc = view.state.doc.toString();
181
+
166
182
  if (value === doc) {
167
183
  return;
168
184
  }
185
+
169
186
  view.dispatch({
170
187
  changes: { from: 0, to: doc.length, insert: value },
171
188
  selection: { anchor: value.length },
@@ -179,17 +196,21 @@ export function ComposerInput({
179
196
  focus: () => viewRef.current?.focus(),
180
197
  setCaret: (pos: number) => {
181
198
  const view = viewRef.current;
199
+
182
200
  if (!view) {
183
201
  return;
184
202
  }
203
+
185
204
  view.dispatch({ selection: { anchor: Math.min(pos, view.state.doc.length) }, scrollIntoView: true });
186
205
  view.focus();
187
206
  },
188
207
  insert: (text: string) => {
189
208
  const view = viewRef.current;
209
+
190
210
  if (!view) {
191
211
  return;
192
212
  }
213
+
193
214
  view.dispatch(insertAtSelection(view.state, text));
194
215
  view.focus();
195
216
  }
@@ -198,6 +219,7 @@ export function ComposerInput({
198
219
  );
199
220
 
200
221
  const Dictation = dictation.composer?.Control;
222
+
201
223
  return (
202
224
  <div ref={targetRef} className="min-w-0">
203
225
  <div ref={hostRef} className={className} />
@@ -9,9 +9,11 @@ const POOL_SIZE = 2;
9
9
  function ThemeSync() {
10
10
  const pool = useWorkerPool();
11
11
  const theme = useDiffTheme();
12
+
12
13
  useEffect(() => {
13
14
  void pool?.setRenderOptions({ theme });
14
15
  }, [pool, theme]);
16
+
15
17
  return null;
16
18
  }
17
19
 
@@ -21,6 +23,7 @@ function ThemeSync() {
21
23
  */
22
24
  export default function DiffPool({ workerFactory, children }: { workerFactory: () => Worker; children: ReactNode }) {
23
25
  const theme = useDiffTheme();
26
+
24
27
  return (
25
28
  <WorkerPoolContextProvider
26
29
  poolOptions={{
@@ -20,6 +20,7 @@ export default function EditDiff({ change, allowEditor = true, maxHeight }: { ch
20
20
  const legacyMode = !allowEditor || loadEngine === undefined;
21
21
  const legacyAllowed = legacyMode && legacyDiffBudget(change.before, change.after);
22
22
  const omitted = <DiffOmitted path={change.path} />;
23
+
23
24
  const fallback = legacyAllowed ? (
24
25
  <DiffFallbackBoundary fallback={omitted} resetKeys={[change.path, change.before, change.after]}>
25
26
  <LazyBoundary fallback={<div className="px-3 py-2 text-xs text-text-faint">{t('work.loadingDiff')}</div>}>
@@ -29,13 +30,17 @@ export default function EditDiff({ change, allowEditor = true, maxHeight }: { ch
29
30
  ) : (
30
31
  omitted
31
32
  );
33
+
32
34
  if (!sourceAllowed) {
33
35
  return omitted;
34
36
  }
37
+
35
38
  if (legacyMode) {
36
39
  return fallback;
37
40
  }
41
+
38
42
  const unavailable = <DiffUnavailable path={change.path} />;
43
+
39
44
  return (
40
45
  <DiffFallbackBoundary fallback={unavailable} resetKeys={[change.path, change.before, change.after, loadEngine]}>
41
46
  <LazyBoundary fallback={<div className="px-3 py-2 text-xs text-text-faint">{t('work.loadingDiff')}</div>}>
@@ -11,13 +11,16 @@ import { useChatScope } from '../../scope';
11
11
  import { useChats } from '../../state/chats';
12
12
  import { useChatActions } from '../actions';
13
13
  import { goalView } from '../logic/goal';
14
+ import { errorMessage } from '../../transport';
14
15
 
15
16
  /* How far the goal got, in what its CLI counts: the checks that sent the agent on, or the tokens it spent. */
16
17
  function progressOf(goal: ChatGoal, t: TFunction<'agent-chat'>): string | null {
17
18
  const parts: string[] = [];
19
+
18
20
  if (goal.checks !== undefined && goal.checks > 0) {
19
21
  parts.push(t('goal.checks', { count: goal.checks }));
20
22
  }
23
+
21
24
  if (goal.tokensUsed !== undefined && (goal.tokensUsed > 0 || goal.tokenBudget !== undefined)) {
22
25
  parts.push(
23
26
  goal.tokenBudget === undefined
@@ -25,6 +28,7 @@ function progressOf(goal: ChatGoal, t: TFunction<'agent-chat'>): string | null {
25
28
  : t('goal.budget', { tokens: formatTokens(goal.tokensUsed), budget: formatTokens(goal.tokenBudget) })
26
29
  );
27
30
  }
31
+
28
32
  return parts.length === 0 ? null : parts.join(' · ');
29
33
  }
30
34
 
@@ -39,21 +43,27 @@ export function GoalDock({ chatId, info, goals }: { chatId: string; info: ChatIn
39
43
  const actions = useChatActions();
40
44
  const [changing, setChanging] = useState(false);
41
45
  const view = goalView(info, goals, actions.goal !== undefined);
46
+
42
47
  if (view === null) {
43
48
  return null;
44
49
  }
50
+
45
51
  const { goal } = view;
46
52
  const progress = progressOf(goal, t);
53
+
47
54
  const act = (action: ChatGoalAction): void => {
48
55
  if (!actions.goal) {
49
56
  return;
50
57
  }
58
+
51
59
  setChanging(true);
60
+
52
61
  actions
53
62
  .goal(chatId, action)
54
- .catch((e: unknown) => host.notify({ kind: 'error', title: t('goal.failed'), description: e instanceof Error ? e.message : String(e) }))
63
+ .catch((e: unknown) => host.notify({ kind: 'error', title: t('goal.failed'), description: errorMessage(e) }))
55
64
  .finally(() => setChanging(false));
56
65
  };
66
+
57
67
  return (
58
68
  <div className="flex items-center gap-2 border-b border-border px-3.5 py-2.5">
59
69
  <Icon icon={Target} size={16} className={clsx('shrink-0', goal.status === 'active' ? 'text-accent' : 'text-text-faint')} />
@@ -91,9 +101,11 @@ export function GoalPill({ chatId }: { chatId: string }) {
91
101
  const { t } = useTranslation('agent-chat');
92
102
  const { keyOf } = useChatScope();
93
103
  const goal = useChats((s) => s.statusByKey[keyOf(chatId)]?.info.goal);
104
+
94
105
  if (goal?.status !== 'active') {
95
106
  return null;
96
107
  }
108
+
97
109
  return (
98
110
  <Tooltip label={`${t('goal.status.active')}: ${goal.objective}`}>
99
111
  <Pill tone="accent" icon={<Icon icon={Target} size={12} />}>
@@ -26,10 +26,13 @@ const START: View = { scale: 1, x: 0, y: 0 };
26
26
  */
27
27
  function zoomed(view: View, factor: number, pointX: number, pointY: number): View {
28
28
  const scale = Math.min(MAX_SCALE, Math.max(MIN_SCALE, view.scale * factor));
29
+
29
30
  if (scale === MIN_SCALE) {
30
31
  return START;
31
32
  }
33
+
32
34
  const ratio = scale / view.scale;
35
+
33
36
  return { scale, x: pointX - (pointX - view.x) * ratio, y: pointY - (pointY - view.y) * ratio };
34
37
  }
35
38
 
@@ -62,9 +65,11 @@ function Lightbox({
62
65
  /* Where the pointer sits against the middle of the frame, which is what the transform counts from. */
63
66
  const pointIn = (event: { clientX: number; clientY: number }): { x: number; y: number } => {
64
67
  const rect = frameRef.current?.getBoundingClientRect();
68
+
65
69
  if (!rect) {
66
70
  return { x: 0, y: 0 };
67
71
  }
72
+
68
73
  return { x: event.clientX - rect.left - rect.width / 2, y: event.clientY - rect.top - rect.height / 2 };
69
74
  };
70
75
 
@@ -114,11 +119,13 @@ function Lightbox({
114
119
  if (view.scale <= MIN_SCALE) {
115
120
  return;
116
121
  }
122
+
117
123
  e.currentTarget.setPointerCapture(e.pointerId);
118
124
  dragRef.current = { pointerId: e.pointerId, x: e.clientX - view.x, y: e.clientY - view.y };
119
125
  }}
120
126
  onPointerMove={(e) => {
121
127
  const drag = dragRef.current;
128
+
122
129
  if (drag?.pointerId === e.pointerId) {
123
130
  setView((current) => ({ ...current, x: e.clientX - drag.x, y: e.clientY - drag.y }));
124
131
  }
@@ -163,12 +170,15 @@ export interface ImageThumbProps {
163
170
  export function ImageThumb({ source, alt, className, aspect, actions, open: openProp, onOpenChange }: ImageThumbProps) {
164
171
  const [ownOpen, setOwnOpen] = useState(false);
165
172
  const open = openProp ?? ownOpen;
173
+
166
174
  const setOpen = (next: boolean): void => {
167
175
  setOwnOpen(next);
168
176
  onOpenChange?.(next);
169
177
  };
178
+
170
179
  const { url: src, failure } = source;
171
180
  const ratio = aspect === undefined ? undefined : { aspectRatio: aspect };
181
+
172
182
  if (src === null) {
173
183
  return (
174
184
  <span
@@ -186,6 +196,7 @@ export function ImageThumb({ source, alt, className, aspect, actions, open: open
186
196
  </span>
187
197
  );
188
198
  }
199
+
189
200
  return (
190
201
  <>
191
202
  <button