@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
@@ -26,7 +26,6 @@ interface KeyHandlerInput {
26
26
  history: PromptHistory;
27
27
  noteKey(e: KeyboardEvent): void;
28
28
  toggleStash(): void;
29
- setText(next: string): void;
30
29
  submit(how: ComposerSend): void;
31
30
  }
32
31
 
@@ -35,9 +34,11 @@ function indentInFence(e: KeyboardEvent, view: EditorView): boolean {
35
34
  const { state } = view;
36
35
  const { from, to, head } = state.selection.main;
37
36
  const tree = ensureSyntaxTree(state, state.doc.length, 50) ?? syntaxTree(state);
37
+
38
38
  if (!inFenceBody(tree, state.doc.toString(), head)) {
39
39
  return false;
40
40
  }
41
+
41
42
  // Handled even when there is nothing to outdent, so Shift+Tab never throws the focus out of a block.
42
43
  if (e.shiftKey) {
43
44
  indentLess(view);
@@ -46,53 +47,62 @@ function indentInFence(e: KeyboardEvent, view: EditorView): boolean {
46
47
  } else {
47
48
  view.dispatch(state.replaceSelection(tabSpaces(head - state.doc.lineAt(head).from)), { scrollIntoView: true, userEvent: 'input' });
48
49
  }
50
+
49
51
  return true;
50
52
  }
51
53
 
52
54
  /* The keys an open picker takes: the arrows walk it, and Tab (or Enter, outside the commands) picks. */
53
- function pickInMenu(e: KeyboardEvent, { menus, setText }: KeyHandlerInput): boolean {
55
+ export function pickInMenu(e: KeyboardEvent, menus: ComposerMenus): boolean {
54
56
  const { activeIndex } = menus;
57
+
55
58
  if (menus.commandMenuOpen) {
56
59
  if (menus.moveInMenu(e.key, menus.commands.length)) {
57
60
  return true;
58
61
  }
62
+
59
63
  if (e.key === 'Tab') {
60
- const chosen = menus.commands[activeIndex]!;
61
- if (chosen.skill) {
62
- menus.chooseSkill(chosen.name);
63
- } else {
64
- setText(`/${chosen.name} `);
65
- }
64
+ menus.completeCommand(menus.commands[activeIndex]!);
65
+
66
66
  return true;
67
67
  }
68
68
  }
69
+
69
70
  if (menus.skillMenuOpen) {
70
71
  if (menus.moveInMenu(e.key, menus.skillMatches.length)) {
71
72
  return true;
72
73
  }
74
+
73
75
  if (e.key === 'Tab' || e.key === 'Enter') {
74
76
  menus.chooseSkill((menus.skillMatches[activeIndex] ?? menus.skillMatches[0]!).name);
77
+
75
78
  return true;
76
79
  }
77
80
  }
81
+
78
82
  if (menus.mentionMenuOpen && menus.mentionCount > 0) {
79
83
  if (menus.moveInMenu(e.key, menus.mentionCount)) {
80
84
  return true;
81
85
  }
86
+
82
87
  if (e.key === 'Tab' || e.key === 'Enter') {
83
88
  menus.chooseMentionAt(activeIndex);
89
+
84
90
  return true;
85
91
  }
86
92
  }
93
+
87
94
  if (menus.referenceMenuOpen && menus.referenceMatches.length > 0) {
88
95
  if (menus.moveInMenu(e.key, menus.referenceMatches.length)) {
89
96
  return true;
90
97
  }
98
+
91
99
  if (e.key === 'Tab' || e.key === 'Enter') {
92
100
  menus.chooseReferenceAt(activeIndex);
101
+
93
102
  return true;
94
103
  }
95
104
  }
105
+
96
106
  return false;
97
107
  }
98
108
 
@@ -104,6 +114,7 @@ function enter(e: KeyboardEvent, view: EditorView, { host, sendKey, submit }: Ke
104
114
  const tree = ensureSyntaxTree(state, state.doc.length, 50) ?? syntaxTree(state);
105
115
  const line = state.doc.lineAt(head);
106
116
  const list = from === to && !inCode(tree, state.doc.toString(), head) ? listItemAt(line.text) : null;
117
+
107
118
  const action = enterAction(
108
119
  { shift: e.shiftKey, mod: isModHeld(e, host.isApplePlatform()), alt: e.altKey },
109
120
  {
@@ -115,9 +126,11 @@ function enter(e: KeyboardEvent, view: EditorView, { host, sendKey, submit }: Ke
115
126
  startsNewChat: host.openNewChat !== null
116
127
  }
117
128
  );
129
+
118
130
  if (action === 'newline') {
119
131
  return insertNewline(view);
120
132
  }
133
+
121
134
  if (action === 'continue-list') {
122
135
  if (list) {
123
136
  view.dispatch({
@@ -127,57 +140,77 @@ function enter(e: KeyboardEvent, view: EditorView, { host, sendKey, submit }: Ke
127
140
  userEvent: 'input'
128
141
  });
129
142
  }
143
+
130
144
  return true;
131
145
  }
146
+
132
147
  if (action === 'leave-list') {
133
148
  view.dispatch({ changes: { from: line.from, to: line.to }, selection: { anchor: line.from }, userEvent: 'delete' });
149
+
134
150
  return true;
135
151
  }
152
+
136
153
  submit(SEND_HOW[action]);
154
+
137
155
  return true;
138
156
  }
139
157
 
140
158
  /* Runs before the editor's own keymap; true means the key is handled and its default prevented. */
141
159
  export function composerKeyHandler(input: KeyHandlerInput): (e: KeyboardEvent, view: EditorView) => boolean {
142
160
  const { chatId, host, text, history } = input;
161
+
143
162
  return (e, view) => {
144
163
  input.noteKey(e);
164
+
145
165
  // Escape leaves the node, unless it first has a recalled prompt to put back.
146
166
  if (e.key === 'Escape' && !e.isComposing) {
147
167
  if (!history.leave()) {
148
168
  return false;
149
169
  }
170
+
150
171
  e.stopPropagation();
172
+
151
173
  return true;
152
174
  }
175
+
153
176
  // The app's own shortcuts stay the app's while you type: Mod+Shift+Enter would otherwise send as well.
154
177
  if (host.isAppShortcut(e)) {
155
178
  return false;
156
179
  }
180
+
157
181
  e.stopPropagation();
182
+
158
183
  // A key inside an IME composition belongs to the composition, Enter and the arrows included.
159
184
  if (e.isComposing) {
160
185
  return false;
161
186
  }
187
+
162
188
  // Reading back through a long answer should not mean leaving the box you are typing in.
163
189
  if (e.key === 'PageUp' || e.key === 'PageDown') {
164
190
  return pageTimeline(chatId, e.key === 'PageUp' ? -1 : 1);
165
191
  }
192
+
166
193
  if (matchesShortcut(STASH_SHORTCUT, e, host.isApplePlatform())) {
167
194
  input.toggleStash();
195
+
168
196
  return true;
169
197
  }
170
- if (pickInMenu(e, input)) {
198
+
199
+ if (pickInMenu(e, input.menus)) {
171
200
  return true;
172
201
  }
202
+
173
203
  if (e.key === 'Tab' && !e.altKey && !e.metaKey && !e.ctrlKey && indentInFence(e, view)) {
174
204
  return true;
175
205
  }
206
+
176
207
  if (e.key === 'Enter') {
177
208
  return enter(e, view, input);
178
209
  }
210
+
179
211
  const { from, to } = view.state.selection.main;
180
212
  const direction = recallDirection({ key: e.key, text, from, to, recalled: history.recalled(text) });
213
+
181
214
  return direction !== null && history.recall(direction);
182
215
  };
183
216
  }
@@ -40,11 +40,14 @@ const LIST_ITEM = /^([ \t]*)(?:([-*+])|(\d{1,9})([.)]))([ \t]+)(\[[ xX]\](?:[ \t
40
40
  /* The list item a line starts, if it starts one. */
41
41
  export function listItemAt(line: string): ListItem | null {
42
42
  const match = LIST_ITEM.exec(line);
43
+
43
44
  if (match === null) {
44
45
  return null;
45
46
  }
47
+
46
48
  const [prefix, indent, bullet, number, delimiter, space, task] = match;
47
49
  const marker = bullet ?? `${Number(number) + 1}${delimiter}`;
50
+
48
51
  return { prefix, next: `${indent}${marker}${space}${task ? '[ ] ' : ''}`, empty: line.slice(prefix.length).trim() === '' };
49
52
  }
50
53
 
@@ -60,25 +63,32 @@ export function enterAction(
60
63
  { inOpenFence, list, column, sendKey = 'enter', multiline = false, startsNewChat = false }: EnterContext
61
64
  ): EnterAction {
62
65
  const modOnly = modSends(sendKey, multiline);
66
+
63
67
  if (keys.mod) {
64
68
  if (keys.alt && startsNewChat) {
65
69
  return 'send-and-new';
66
70
  }
71
+
67
72
  return keys.alt || (modOnly && keys.shift) ? 'send-alternate' : 'send';
68
73
  }
74
+
69
75
  if (keys.shift || inOpenFence) {
70
76
  return 'newline';
71
77
  }
78
+
72
79
  if (list !== null) {
73
80
  // A caret in front of the marker moves the item down rather than splitting its marker.
74
81
  if (column < list.prefix.length) {
75
82
  return 'newline';
76
83
  }
84
+
77
85
  return list.empty ? 'leave-list' : 'continue-list';
78
86
  }
87
+
79
88
  if (keys.alt) {
80
89
  return 'send-alternate';
81
90
  }
91
+
82
92
  return modOnly ? 'newline' : 'send';
83
93
  }
84
94
 
@@ -89,6 +99,7 @@ function enclosingFence(tree: Tree, pos: number): SyntaxNode | null {
89
99
  return node;
90
100
  }
91
101
  }
102
+
92
103
  return null;
93
104
  }
94
105
 
@@ -100,16 +111,20 @@ function isOpenFence(fence: SyntaxNode): boolean {
100
111
  /* Whether `pos` sits inside a fenced code block that has an opening fence and no closing one yet. */
101
112
  export function inOpenFence(tree: Tree, pos: number): boolean {
102
113
  const fence = enclosingFence(tree, pos);
114
+
103
115
  return fence !== null && pos > fence.from && isOpenFence(fence);
104
116
  }
105
117
 
106
118
  /* Whether `pos` sits in the body of a fenced code block, open or closed: below its opening line and before its end. */
107
119
  export function inFenceBody(tree: Tree, text: string, pos: number): boolean {
108
120
  const fence = enclosingFence(tree, pos);
121
+
109
122
  if (fence === null) {
110
123
  return false;
111
124
  }
125
+
112
126
  const openingEnd = text.indexOf('\n', fence.from);
127
+
113
128
  return openingEnd !== -1 && pos > openingEnd && (pos < fence.to || isOpenFence(fence));
114
129
  }
115
130
 
@@ -127,18 +142,23 @@ const INLINE_BLOCK = /^(Paragraph|ATXHeading\d|SetextHeading\d)$/;
127
142
  */
128
143
  export function inCode(tree: Tree, text: string, pos: number): boolean {
129
144
  let blockFrom: number | null = null;
145
+
130
146
  for (let node: SyntaxNode | null = tree.resolveInner(pos, -1); node !== null; node = node.parent) {
131
147
  if (node.name === 'FencedCode') {
132
148
  return pos > node.from && (pos < node.to || isOpenFence(node));
133
149
  }
150
+
134
151
  if (node.name === 'InlineCode' && pos > node.from && pos < node.to) {
135
152
  return true;
136
153
  }
154
+
137
155
  if (blockFrom === null && INLINE_BLOCK.test(node.name)) {
138
156
  blockFrom = node.from;
139
157
  }
140
158
  }
159
+
141
160
  let from = blockFrom ?? text.lastIndexOf('\n', pos - 1) + 1;
161
+
142
162
  tree.iterate({
143
163
  from,
144
164
  to: pos,
@@ -148,6 +168,7 @@ export function inCode(tree: Tree, text: string, pos: number): boolean {
148
168
  }
149
169
  }
150
170
  });
171
+
151
172
  return /(^|[^\\])`/.test(text.slice(from, pos));
152
173
  }
153
174
 
@@ -169,8 +190,10 @@ export function recallDirection({ key, text, from, to, recalled }: RecallContext
169
190
  if (key === 'ArrowUp' && (text === '' || (recalled && from === 0))) {
170
191
  return -1;
171
192
  }
193
+
172
194
  if (key === 'ArrowDown' && recalled && to === text.length) {
173
195
  return 1;
174
196
  }
197
+
175
198
  return null;
176
199
  }
@@ -10,12 +10,15 @@ function hintedPlaceholder(lead: string, joiner: string, hints: ReadonlyArray<{
10
10
  const extra = document.createElement('span');
11
11
  extra.className = 'composer-hints-extra';
12
12
  extra.append(joiner);
13
+
13
14
  for (const hint of hints) {
14
15
  const cap = document.createElement('kbd');
15
16
  cap.textContent = hint.key;
16
17
  extra.append(cap, hint.label);
17
18
  }
19
+
18
20
  root.append(lead, extra);
21
+
19
22
  return root;
20
23
  }
21
24
 
@@ -32,13 +35,16 @@ export function useHintedPlaceholder({ chatId, disabled, readOnly, mentionable,
32
35
  const { t } = useTranslation('agent-chat');
33
36
  const scope = useChatScope();
34
37
  const lead = useHostComposerPlaceholder(scope.id, chatId);
38
+
35
39
  return useMemo(() => {
36
40
  if (disabled) {
37
41
  return t('composer.placeholder.disconnected');
38
42
  }
43
+
39
44
  if (readOnly) {
40
45
  return t('composer.placeholder.readOnly');
41
46
  }
47
+
42
48
  return hintedPlaceholder(lead ?? t('composer.placeholder.lead'), t('composer.placeholder.joiner'), [
43
49
  { key: '/', label: t('composer.placeholder.commands') },
44
50
  ...(mentionable ? [{ key: '@', label: t('composer.placeholder.files') }] : []),
@@ -0,0 +1,18 @@
1
+ import type { ChatSendExtras } from '../../chat-client';
2
+ import { referenceTokens, type Referables } from '../../chat-references';
3
+ import { presentMentions, presentReferences, presentSkills } from '../../mentions';
4
+ import type { PromptDraft } from './use-prompt-menus';
5
+
6
+ /* What a prompt still holds of what was picked in it, as a send of the composer carries it. */
7
+ export function promptPicks(value: PromptDraft, referables: Referables): Pick<ChatSendExtras, 'mentions' | 'skills' | 'chats' | 'references'> {
8
+ const text = value.text.trim();
9
+ const tokens = referenceTokens([...value.chats, ...value.references], referables.items, value.referenceNames);
10
+
11
+ return {
12
+ mentions: presentMentions(text, value.mentions),
13
+ skills: presentSkills(text, value.skills),
14
+ chats: presentReferences(text, value.chats, tokens),
15
+ // A machine that resolves only chats would drop the rest.
16
+ references: referables.chatsOnly ? [] : presentReferences(text, value.references, tokens)
17
+ };
18
+ }
@@ -33,13 +33,18 @@ const ACTIONS = [
33
33
  export function surfacePartOf(target: EventTarget | null, surface: Element): 'input' | 'action' | 'surface' {
34
34
  // Not `instanceof Element`, which fails for an element of another window.
35
35
  const element = target as Element | null;
36
+
36
37
  if (typeof element?.closest !== 'function' || !surface.contains(element)) {
37
38
  return 'action';
38
39
  }
40
+
39
41
  const input = element.closest('.cm-editor');
42
+
40
43
  if (input !== null && surface.contains(input)) {
41
44
  return 'input';
42
45
  }
46
+
43
47
  const action = element.closest(ACTIONS);
48
+
44
49
  return action !== null && surface.contains(action) ? 'action' : 'surface';
45
50
  }
@@ -32,8 +32,10 @@ export function useChatControls({ chatId, info, notice: { setNotice, showError }
32
32
  if (configuring.current) {
33
33
  return;
34
34
  }
35
+
35
36
  configuring.current = true;
36
37
  setConfigurationPending(true);
38
+
37
39
  void work()
38
40
  .catch(showError)
39
41
  .finally(() => {
@@ -49,6 +51,7 @@ export function useChatControls({ chatId, info, notice: { setNotice, showError }
49
51
  if (patch.selection) {
50
52
  rememberChatSelection(info.provider, patch.selection);
51
53
  }
54
+
52
55
  if (patch.account) {
53
56
  rememberChatAccount(scope.id, info.provider, patch.account);
54
57
  }
@@ -59,18 +62,23 @@ export function useChatControls({ chatId, info, notice: { setNotice, showError }
59
62
  /* A model of another CLI re-points the whole chat; one of this CLI's own is a configure. */
60
63
  const chooseModel = (provider: AgentKind, slug: string): void => {
61
64
  const selection: ModelSelection = { model: slug, options: {} };
65
+
62
66
  if (provider !== info.provider) {
63
67
  runConfiguration(() => onRetarget(provider, selection).then(() => rememberChatSelection(provider, selection)));
68
+
64
69
  return;
65
70
  }
71
+
66
72
  configure({ selection });
67
73
  };
68
74
 
69
75
  const stop = (shiftKey: boolean): void => {
70
76
  if (composerStopOf(shiftKey) === 'turn') {
71
77
  void actions.stopTurn(chatId, false).catch(showError);
78
+
72
79
  return;
73
80
  }
81
+
74
82
  host.confirm.stopSubagents(scope.id, chatId, () => void actions.stopTurn(chatId, true).catch(showError));
75
83
  };
76
84
 
@@ -81,8 +89,10 @@ export function useChatControls({ chatId, info, notice: { setNotice, showError }
81
89
  } catch (e) {
82
90
  if (errorCode(e) === 'chat-busy') {
83
91
  setConfirmClear(true);
92
+
84
93
  return;
85
94
  }
95
+
86
96
  setNotice(t('composer.notice.clearFailed'));
87
97
  }
88
98
  };
@@ -101,12 +111,15 @@ export function useChatControls({ chatId, info, notice: { setNotice, showError }
101
111
  switch (name) {
102
112
  case 'model':
103
113
  setModelPickerOpen(true);
114
+
104
115
  return true;
105
116
  case 'compact':
106
117
  void actions.compact(chatId).catch(() => undefined);
118
+
107
119
  return true;
108
120
  case 'clear':
109
121
  void clearThread();
122
+
110
123
  return true;
111
124
  default:
112
125
  return false;
@@ -12,8 +12,10 @@ const PAGE_CLOCK: DueClock = {
12
12
  if (typeof window === 'undefined') {
13
13
  return () => {};
14
14
  }
15
+
15
16
  window.addEventListener('focus', wake);
16
17
  document.addEventListener('visibilitychange', wake);
18
+
17
19
  return () => {
18
20
  window.removeEventListener('focus', wake);
19
21
  document.removeEventListener('visibilitychange', wake);
@@ -38,6 +40,7 @@ export function useCompactionOffer(chatId: string, info: ChatInfo, compaction: P
38
40
  if (dueAt === null) {
39
41
  return;
40
42
  }
43
+
41
44
  return watchDueAt(dueAt, setNow, PAGE_CLOCK);
42
45
  }, [dueAt]);
43
46