@adecore/agents-react 0.31.12 → 0.33.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 (409) hide show
  1. package/README.md +1 -1
  2. package/dist/agents/AccountDot.js +57 -6
  3. package/dist/agents/AgentIcon.js +88 -12
  4. package/dist/agents/ModelOptionControl.js +153 -18
  5. package/dist/agents/ProviderLogo.js +49 -4
  6. package/dist/agents/account-limits.js +17 -14
  7. package/dist/agents/accounts.js +99 -67
  8. package/dist/agents/agent-marks.js +5 -3
  9. package/dist/agents/model-name.js +42 -31
  10. package/dist/agents/model-options.js +8 -8
  11. package/dist/agents/model-requirement.js +17 -14
  12. package/dist/agents/option-words.d.ts +7 -0
  13. package/dist/agents/option-words.js +35 -0
  14. package/dist/agents/provider-paths.js +6 -6
  15. package/dist/agents/status-look.js +32 -12
  16. package/dist/chat/account-choice.d.ts +13 -0
  17. package/dist/chat/account-choice.js +90 -20
  18. package/dist/chat/actions.js +126 -59
  19. package/dist/chat/activity.js +5 -5
  20. package/dist/chat/attachments.js +74 -53
  21. package/dist/chat/bookmarks.js +58 -48
  22. package/dist/chat/chat-client.js +344 -263
  23. package/dist/chat/chat-references.js +3 -3
  24. package/dist/chat/composer-effort.d.ts +5 -0
  25. package/dist/chat/composer-effort.js +26 -0
  26. package/dist/chat/composer-send.js +13 -13
  27. package/dist/chat/drafts.js +115 -79
  28. package/dist/chat/forks.js +81 -24
  29. package/dist/chat/guards.js +15 -43
  30. package/dist/chat/index.d.ts +3 -1
  31. package/dist/chat/index.js +3 -2
  32. package/dist/chat/logic/ansi.js +170 -167
  33. package/dist/chat/logic/answers.js +2 -2
  34. package/dist/chat/logic/bookmarks.js +19 -19
  35. package/dist/chat/logic/command-looks.js +138 -96
  36. package/dist/chat/logic/context-usage.js +13 -9
  37. package/dist/chat/logic/continue-after-stop.js +15 -19
  38. package/dist/chat/logic/effort.d.ts +14 -0
  39. package/dist/chat/logic/effort.js +34 -0
  40. package/dist/chat/logic/embedded-code.js +387 -326
  41. package/dist/chat/logic/fork.js +134 -110
  42. package/dist/chat/logic/generated-image.js +54 -23
  43. package/dist/chat/logic/goal.js +28 -20
  44. package/dist/chat/logic/handback.js +6 -6
  45. package/dist/chat/logic/json.js +2 -2
  46. package/dist/chat/logic/limit.js +46 -30
  47. package/dist/chat/logic/picker-entries.d.ts +5 -3
  48. package/dist/chat/logic/picker-entries.js +83 -43
  49. package/dist/chat/logic/resume-compaction.d.ts +14 -1
  50. package/dist/chat/logic/resume-compaction.js +93 -24
  51. package/dist/chat/logic/scrubber.js +188 -136
  52. package/dist/chat/logic/thought.js +13 -16
  53. package/dist/chat/logic/thread-cards.js +60 -48
  54. package/dist/chat/logic/timeline-copy.js +30 -38
  55. package/dist/chat/logic/timeline-target.js +92 -63
  56. package/dist/chat/logic/timeline.js +499 -355
  57. package/dist/chat/logic/tool-catalog.js +54 -34
  58. package/dist/chat/logic/tools.js +106 -82
  59. package/dist/chat/logic/visual-height.js +18 -18
  60. package/dist/chat/logic/visual-viewport.js +6 -3
  61. package/dist/chat/logic/welcome.js +9 -9
  62. package/dist/chat/logic/workflow.d.ts +10 -0
  63. package/dist/chat/logic/workflow.js +130 -32
  64. package/dist/chat/mentions.js +149 -109
  65. package/dist/chat/persisted-json.js +51 -54
  66. package/dist/chat/preferences.d.ts +4 -0
  67. package/dist/chat/preferences.js +162 -84
  68. package/dist/chat/prompt-hold.js +9 -9
  69. package/dist/chat/quote.js +21 -30
  70. package/dist/chat/reading-width.js +12 -10
  71. package/dist/chat/recent-messages.js +34 -21
  72. package/dist/chat/resume-compaction-dismissals.js +25 -5
  73. package/dist/chat/runtime-modes.js +3 -3
  74. package/dist/chat/send-key.js +11 -7
  75. package/dist/chat/stash.js +89 -69
  76. package/dist/chat/subagent-conversation.js +181 -139
  77. package/dist/chat/subagent-list.js +65 -67
  78. package/dist/chat/subagent-support.js +12 -7
  79. package/dist/chat/subagent-view.js +132 -44
  80. package/dist/chat/thumbnails.js +88 -60
  81. package/dist/chat/timeline-flash.js +24 -12
  82. package/dist/chat/timeline-scroll.js +116 -86
  83. package/dist/chat/ui/AccountPill.js +126 -15
  84. package/dist/chat/ui/AnsiOutput.js +62 -6
  85. package/dist/chat/ui/BookmarkMarker.js +231 -41
  86. package/dist/chat/ui/BookmarkSubmenu.js +165 -18
  87. package/dist/chat/ui/ChatActivity.js +649 -70
  88. package/dist/chat/ui/ChatReferenceChip.js +104 -9
  89. package/dist/chat/ui/CodeBlock.js +132 -58
  90. package/dist/chat/ui/Composer.js +866 -132
  91. package/dist/chat/ui/ComposerInput.js +309 -120
  92. package/dist/chat/ui/DiffPool.js +75 -14
  93. package/dist/chat/ui/EditDiff.js +160 -21
  94. package/dist/chat/ui/FadingWords.js +32 -3
  95. package/dist/chat/ui/GoalDock.js +235 -42
  96. package/dist/chat/ui/ImageView.js +617 -61
  97. package/dist/chat/ui/LimitState.js +446 -72
  98. package/dist/chat/ui/Markdown.js +991 -173
  99. package/dist/chat/ui/MermaidBlock.js +285 -79
  100. package/dist/chat/ui/MessageActions.js +251 -39
  101. package/dist/chat/ui/ModelMarks.js +55 -5
  102. package/dist/chat/ui/Pickers.js +664 -113
  103. package/dist/chat/ui/PromptComposer.js +281 -51
  104. package/dist/chat/ui/QuoteButton.js +151 -57
  105. package/dist/chat/ui/ResumeCompactionDock.d.ts +6 -2
  106. package/dist/chat/ui/ResumeCompactionDock.js +141 -6
  107. package/dist/chat/ui/RowTime.js +59 -5
  108. package/dist/chat/ui/RunSettings.js +1744 -154
  109. package/dist/chat/ui/Scrubber.js +517 -88
  110. package/dist/chat/ui/ShellCommand.js +183 -107
  111. package/dist/chat/ui/SubagentControls.js +212 -24
  112. package/dist/chat/ui/SubagentInfo.js +170 -13
  113. package/dist/chat/ui/SubagentStopButton.js +115 -24
  114. package/dist/chat/ui/SubagentTimeline.js +357 -91
  115. package/dist/chat/ui/Timeline.js +988 -476
  116. package/dist/chat/ui/TimelineMenu.js +552 -37
  117. package/dist/chat/ui/UnifiedDiff.js +234 -27
  118. package/dist/chat/ui/UploadThumb.js +37 -7
  119. package/dist/chat/ui/VisualDialogs.js +251 -20
  120. package/dist/chat/ui/VisualFrame.js +321 -95
  121. package/dist/chat/ui/Welcome.js +72 -7
  122. package/dist/chat/ui/chips.js +1 -1
  123. package/dist/chat/ui/code-lines.js +36 -36
  124. package/dist/chat/ui/code-streaming.js +1 -1
  125. package/dist/chat/ui/code-theme.js +7 -7
  126. package/dist/chat/ui/composer/ComposerControls.js +329 -21
  127. package/dist/chat/ui/composer/ComposerMenu.js +358 -30
  128. package/dist/chat/ui/composer/DraftParts.js +185 -11
  129. package/dist/chat/ui/composer/QueuedMessages.js +138 -13
  130. package/dist/chat/ui/composer/chips.js +29 -19
  131. package/dist/chat/ui/composer/editor.js +79 -63
  132. package/dist/chat/ui/composer/insert.js +26 -12
  133. package/dist/chat/ui/composer/key-handler.js +180 -127
  134. package/dist/chat/ui/composer/keys.js +90 -73
  135. package/dist/chat/ui/composer/menu-aria.js +18 -9
  136. package/dist/chat/ui/composer/placeholder.js +78 -31
  137. package/dist/chat/ui/composer/surface.js +13 -37
  138. package/dist/chat/ui/composer/use-chat-controls.js +230 -90
  139. package/dist/chat/ui/composer/use-compaction-offer.js +50 -18
  140. package/dist/chat/ui/composer/use-composer-draft.js +65 -34
  141. package/dist/chat/ui/composer/use-composer-menus.js +478 -193
  142. package/dist/chat/ui/composer/use-composer-submit.js +251 -109
  143. package/dist/chat/ui/composer/use-continuable-turn.js +33 -6
  144. package/dist/chat/ui/composer/use-draft-files.js +245 -93
  145. package/dist/chat/ui/composer/use-effort-stepper.d.ts +13 -0
  146. package/dist/chat/ui/composer/use-effort-stepper.js +88 -0
  147. package/dist/chat/ui/composer/use-notice.js +61 -16
  148. package/dist/chat/ui/composer/use-pending-requests.js +38 -17
  149. package/dist/chat/ui/composer/use-prompt-history.js +117 -45
  150. package/dist/chat/ui/composer/use-prompt-hold.js +119 -35
  151. package/dist/chat/ui/composer/use-take-back.js +94 -72
  152. package/dist/chat/ui/diff/ApprovalReview.js +101 -23
  153. package/dist/chat/ui/diff/DiffFallbackBoundary.js +21 -13
  154. package/dist/chat/ui/diff/DiffOmitted.js +56 -6
  155. package/dist/chat/ui/diff/DiffStack.js +92 -8
  156. package/dist/chat/ui/diff/DiffUnavailable.js +56 -6
  157. package/dist/chat/ui/diff/EditorEditDiff.js +263 -51
  158. package/dist/chat/ui/diff/EditorPatchDiff.js +39 -14
  159. package/dist/chat/ui/diff/LegacyDiffPool.js +27 -10
  160. package/dist/chat/ui/diff/LegacyEditDiff.js +97 -20
  161. package/dist/chat/ui/diff/LegacyUnifiedDiff.js +172 -42
  162. package/dist/chat/ui/diff/RawDiff.js +65 -5
  163. package/dist/chat/ui/diff/ReviewDiff.js +77 -5
  164. package/dist/chat/ui/diff/diff-props.js +1 -1
  165. package/dist/chat/ui/diff/diff-source-budget.js +46 -35
  166. package/dist/chat/ui/diff/editor-edit-model.js +18 -14
  167. package/dist/chat/ui/diff/review-plan.js +63 -40
  168. package/dist/chat/ui/diff/review-settle.js +24 -9
  169. package/dist/chat/ui/diff/syntax-runtime.js +236 -201
  170. package/dist/chat/ui/diff/use-review-stack.js +146 -25
  171. package/dist/chat/ui/diff-syntax.js +70 -58
  172. package/dist/chat/ui/diff-theme.js +31 -12
  173. package/dist/chat/ui/file-links.js +39 -10
  174. package/dist/chat/ui/find-reveal.js +29 -8
  175. package/dist/chat/ui/full-diff.js +17 -12
  176. package/dist/chat/ui/highlighter.js +143 -113
  177. package/dist/chat/ui/icons.js +16 -7
  178. package/dist/chat/ui/index.js +1 -1
  179. package/dist/chat/ui/intelligent-ui/UiBlockFrame.js +556 -82
  180. package/dist/chat/ui/intelligent-ui/UiFallbackPart.js +73 -5
  181. package/dist/chat/ui/intelligent-ui/UiReply.js +666 -262
  182. package/dist/chat/ui/intelligent-ui/block-local.js +59 -31
  183. package/dist/chat/ui/intelligent-ui/chart-data.js +77 -67
  184. package/dist/chat/ui/intelligent-ui/node-text.js +77 -91
  185. package/dist/chat/ui/intelligent-ui/registry.js +46 -46
  186. package/dist/chat/ui/intelligent-ui/render-context.js +1 -1
  187. package/dist/chat/ui/intelligent-ui/renderers/base-land.js +1 -1
  188. package/dist/chat/ui/intelligent-ui/renderers/binding.js +3 -3
  189. package/dist/chat/ui/intelligent-ui/renderers/chart.js +1223 -123
  190. package/dist/chat/ui/intelligent-ui/renderers/choices.js +312 -34
  191. package/dist/chat/ui/intelligent-ui/renderers/content.js +1241 -86
  192. package/dist/chat/ui/intelligent-ui/renderers/data.js +619 -54
  193. package/dist/chat/ui/intelligent-ui/renderers/inputs.js +868 -67
  194. package/dist/chat/ui/intelligent-ui/renderers/links.js +366 -62
  195. package/dist/chat/ui/intelligent-ui/renderers/map-slots.js +118 -60
  196. package/dist/chat/ui/intelligent-ui/renderers/map-style.js +85 -78
  197. package/dist/chat/ui/intelligent-ui/renderers/map-view.js +282 -217
  198. package/dist/chat/ui/intelligent-ui/renderers/map.js +621 -69
  199. package/dist/chat/ui/intelligent-ui/renderers/place-point.js +15 -8
  200. package/dist/chat/ui/intelligent-ui/renderers/structure.js +262 -20
  201. package/dist/chat/ui/intelligent-ui/renderers/text.js +674 -49
  202. package/dist/chat/ui/intelligent-ui/reply-parts.js +24 -15
  203. package/dist/chat/ui/intelligent-ui/table-data.js +97 -57
  204. package/dist/chat/ui/intelligent-ui/tones.js +31 -31
  205. package/dist/chat/ui/intelligent-ui/use-in-view.js +30 -12
  206. package/dist/chat/ui/intelligent-ui/use-later.js +28 -13
  207. package/dist/chat/ui/intelligent-ui/use-truncated.js +45 -21
  208. package/dist/chat/ui/intelligent-ui/use-ui-links.js +296 -109
  209. package/dist/chat/ui/intelligent-ui/use-ui-queries.js +256 -246
  210. package/dist/chat/ui/markdown-blocks.js +296 -262
  211. package/dist/chat/ui/mermaid.d.ts +8 -20
  212. package/dist/chat/ui/mermaid.js +47 -84
  213. package/dist/chat/ui/quote-selection.js +32 -29
  214. package/dist/chat/ui/rehype-chips.js +35 -23
  215. package/dist/chat/ui/rehype-fade.js +28 -17
  216. package/dist/chat/ui/remark-html-as-text.js +22 -15
  217. package/dist/chat/ui/reply-context.js +1 -1
  218. package/dist/chat/ui/reveal.js +161 -72
  219. package/dist/chat/ui/rows/ForksRow.js +226 -24
  220. package/dist/chat/ui/rows/GeneratedImageRow.js +541 -87
  221. package/dist/chat/ui/rows/MessageRows.js +1706 -159
  222. package/dist/chat/ui/rows/RowContainer.js +57 -7
  223. package/dist/chat/ui/rows/Rows.js +463 -54
  224. package/dist/chat/ui/rows/SubagentRow.js +577 -60
  225. package/dist/chat/ui/rows/TaskRow.js +359 -40
  226. package/dist/chat/ui/rows/VisualRow.js +233 -11
  227. package/dist/chat/ui/rows/WorkRows.d.ts +3 -0
  228. package/dist/chat/ui/rows/WorkRows.js +1945 -164
  229. package/dist/chat/ui/rows/WorkflowRow.js +756 -37
  230. package/dist/chat/ui/rows/row-rhythm.js +27 -17
  231. package/dist/chat/ui/theme-watch.js +26 -23
  232. package/dist/chat/ui/timestamp-format.js +4 -1
  233. package/dist/chat/ui/use-diff-source-tokens.js +70 -34
  234. package/dist/chat/ui/useToggleSet.js +51 -19
  235. package/dist/chat/ui/visual-theme.js +153 -128
  236. package/dist/chat/visual-bridge.js +123 -123
  237. package/dist/chat/visual-viewport.js +94 -83
  238. package/dist/chat/visuals.js +13 -5
  239. package/dist/host-hooks.d.ts +29 -0
  240. package/dist/host-hooks.js +78 -0
  241. package/dist/host.js +120 -48
  242. package/dist/index.js +1 -1
  243. package/dist/lazy.js +38 -32
  244. package/dist/locales/en/agent-chat.d.ts +42 -0
  245. package/dist/locales/en/agent-chat.js +755 -713
  246. package/dist/locales/en/agent-prompts.js +42 -42
  247. package/dist/locales/en/agent-providers.d.ts +1 -0
  248. package/dist/locales/en/agent-providers.js +166 -165
  249. package/dist/locales/en/agent-usage.d.ts +6 -0
  250. package/dist/locales/en/agent-usage.js +129 -123
  251. package/dist/locales/nl/agent-chat.d.ts +42 -0
  252. package/dist/locales/nl/agent-chat.js +755 -713
  253. package/dist/locales/nl/agent-prompts.js +42 -42
  254. package/dist/locales/nl/agent-providers.d.ts +1 -0
  255. package/dist/locales/nl/agent-providers.js +166 -165
  256. package/dist/locales/nl/agent-usage.d.ts +6 -0
  257. package/dist/locales/nl/agent-usage.js +129 -123
  258. package/dist/locales.js +14 -14
  259. package/dist/mounted-registry.js +31 -30
  260. package/dist/port-transport.js +122 -111
  261. package/dist/prompts/index.js +1 -1
  262. package/dist/prompts/logic/focus.js +15 -14
  263. package/dist/prompts/logic/keys.js +93 -59
  264. package/dist/prompts/logic/prompts.js +27 -14
  265. package/dist/prompts/logic/subjects.js +60 -46
  266. package/dist/prompts/logic/useFocusAfterAnswer.js +60 -20
  267. package/dist/prompts/logic/usePromptSession.js +88 -77
  268. package/dist/prompts/ui/ApprovalBody.js +246 -27
  269. package/dist/prompts/ui/PromptActions.js +215 -9
  270. package/dist/prompts/ui/PromptCard.js +215 -36
  271. package/dist/prompts/ui/PromptView.js +372 -34
  272. package/dist/prompts/ui/QuestionBody.js +269 -73
  273. package/dist/providers/AccountColors.js +36 -5
  274. package/dist/providers/AccountDetail.js +683 -50
  275. package/dist/providers/AccountVariables.js +139 -32
  276. package/dist/providers/AddAccountForm.js +125 -38
  277. package/dist/providers/CliDetail.js +343 -36
  278. package/dist/providers/InstallPage.js +644 -59
  279. package/dist/providers/ProviderList.d.ts +2 -1
  280. package/dist/providers/ProviderList.js +215 -23
  281. package/dist/providers/ProvidersPane.d.ts +4 -2
  282. package/dist/providers/ProvidersPane.js +244 -64
  283. package/dist/providers/account-actions.js +54 -30
  284. package/dist/providers/index.js +1 -1
  285. package/dist/providers/install-steps.js +12 -9
  286. package/dist/providers/pane-target.d.ts +3 -0
  287. package/dist/providers/pane-target.js +34 -13
  288. package/dist/providers/parts.js +62 -12
  289. package/dist/providers/provider-abilities.js +5 -5
  290. package/dist/providers/provider-groups.js +75 -40
  291. package/dist/providers/variables.js +73 -39
  292. package/dist/scope.js +6 -6
  293. package/dist/settings/sections.js +18 -18
  294. package/dist/state/chats.js +404 -192
  295. package/dist/state/index.js +1 -1
  296. package/dist/state/provider-accounts.js +70 -47
  297. package/dist/state/providers.js +45 -16
  298. package/dist/state/usage.js +154 -77
  299. package/dist/storage.js +69 -68
  300. package/dist/testing/index.js +1 -1
  301. package/dist/testing/prompts.js +105 -67
  302. package/dist/transport.js +10 -10
  303. package/dist/ui/PlainTextarea.js +27 -3
  304. package/dist/usage/LimitsList.js +646 -40
  305. package/dist/usage/UsageBreakdown.js +879 -38
  306. package/dist/usage/UsageChart.js +311 -32
  307. package/dist/usage/UsageDialog.js +46 -4
  308. package/dist/usage/UsageLimits.js +467 -34
  309. package/dist/usage/UsageLimitsCard.js +95 -11
  310. package/dist/usage/UsagePage.js +817 -96
  311. package/dist/usage/UsagePane.js +164 -10
  312. package/dist/usage/UsageSummary.js +151 -6
  313. package/dist/usage/UsageTiles.js +164 -14
  314. package/dist/usage/format.js +32 -32
  315. package/dist/usage/index.d.ts +1 -1
  316. package/dist/usage/index.js +2 -1
  317. package/dist/usage/limit-groups.d.ts +2 -0
  318. package/dist/usage/limit-groups.js +77 -59
  319. package/dist/usage/limits.js +78 -43
  320. package/dist/usage/money.js +20 -4
  321. package/dist/usage/summary.js +85 -64
  322. package/package.json +9 -9
  323. package/src/agents/ModelOptionControl.tsx +3 -1
  324. package/src/agents/option-words.ts +27 -0
  325. package/src/chat/account-choice.ts +41 -1
  326. package/src/chat/composer-effort.ts +32 -0
  327. package/src/chat/forks.ts +4 -5
  328. package/src/chat/index.ts +3 -1
  329. package/src/chat/logic/effort.ts +32 -0
  330. package/src/chat/logic/picker-entries.ts +45 -10
  331. package/src/chat/logic/resume-compaction.ts +95 -17
  332. package/src/chat/logic/timeline.ts +11 -3
  333. package/src/chat/logic/workflow.ts +86 -4
  334. package/src/chat/preferences.ts +35 -0
  335. package/src/chat/subagent-view.ts +2 -3
  336. package/src/chat/ui/AnsiOutput.tsx +1 -2
  337. package/src/chat/ui/BookmarkSubmenu.tsx +3 -3
  338. package/src/chat/ui/ChatActivity.tsx +14 -22
  339. package/src/chat/ui/ChatReferenceChip.tsx +2 -3
  340. package/src/chat/ui/Composer.tsx +15 -7
  341. package/src/chat/ui/EditDiff.tsx +2 -3
  342. package/src/chat/ui/LimitState.tsx +2 -2
  343. package/src/chat/ui/Markdown.tsx +10 -8
  344. package/src/chat/ui/MermaidBlock.tsx +57 -49
  345. package/src/chat/ui/Pickers.tsx +49 -29
  346. package/src/chat/ui/PromptComposer.tsx +7 -9
  347. package/src/chat/ui/ResumeCompactionDock.tsx +16 -4
  348. package/src/chat/ui/RunSettings.tsx +67 -28
  349. package/src/chat/ui/Scrubber.tsx +3 -3
  350. package/src/chat/ui/ShellCommand.tsx +2 -0
  351. package/src/chat/ui/SubagentInfo.tsx +2 -3
  352. package/src/chat/ui/SubagentTimeline.tsx +12 -16
  353. package/src/chat/ui/Timeline.tsx +6 -6
  354. package/src/chat/ui/UnifiedDiff.tsx +3 -4
  355. package/src/chat/ui/VisualFrame.tsx +5 -8
  356. package/src/chat/ui/code-theme.ts +4 -4
  357. package/src/chat/ui/composer/placeholder.ts +2 -2
  358. package/src/chat/ui/composer/use-compaction-offer.ts +36 -16
  359. package/src/chat/ui/composer/use-composer-menus.ts +4 -9
  360. package/src/chat/ui/composer/use-composer-submit.ts +2 -1
  361. package/src/chat/ui/composer/use-effort-stepper.ts +56 -0
  362. package/src/chat/ui/composer/use-notice.ts +2 -2
  363. package/src/chat/ui/diff/EditorEditDiff.tsx +9 -13
  364. package/src/chat/ui/diff/LegacyEditDiff.tsx +12 -17
  365. package/src/chat/ui/diff/LegacyUnifiedDiff.tsx +13 -21
  366. package/src/chat/ui/diff/use-review-stack.ts +4 -4
  367. package/src/chat/ui/diff-theme.ts +3 -3
  368. package/src/chat/ui/file-links.ts +2 -2
  369. package/src/chat/ui/intelligent-ui/UiReply.tsx +2 -0
  370. package/src/chat/ui/intelligent-ui/renderers/chart.tsx +3 -3
  371. package/src/chat/ui/intelligent-ui/renderers/content.tsx +5 -6
  372. package/src/chat/ui/intelligent-ui/renderers/map-view.tsx +2 -1
  373. package/src/chat/ui/intelligent-ui/renderers/map.tsx +2 -1
  374. package/src/chat/ui/intelligent-ui/use-truncated.ts +16 -19
  375. package/src/chat/ui/intelligent-ui/use-ui-links.ts +3 -3
  376. package/src/chat/ui/mermaid.ts +52 -96
  377. package/src/chat/ui/rows/ForksRow.tsx +3 -5
  378. package/src/chat/ui/rows/GeneratedImageRow.tsx +2 -1
  379. package/src/chat/ui/rows/MessageRows.tsx +12 -21
  380. package/src/chat/ui/rows/SubagentRow.tsx +3 -3
  381. package/src/chat/ui/rows/TaskRow.tsx +1 -1
  382. package/src/chat/ui/rows/WorkRows.tsx +11 -6
  383. package/src/chat/ui/rows/WorkflowRow.tsx +144 -54
  384. package/src/chat/ui/useToggleSet.ts +15 -18
  385. package/src/chat/ui/visual-theme.ts +2 -3
  386. package/src/host-hooks.ts +113 -0
  387. package/src/lazy.tsx +2 -0
  388. package/src/locales/en/agent-chat.ts +142 -108
  389. package/src/locales/en/agent-prompts.ts +7 -7
  390. package/src/locales/en/agent-providers.ts +35 -34
  391. package/src/locales/en/agent-usage.ts +26 -20
  392. package/src/locales/nl/agent-chat.ts +134 -100
  393. package/src/locales/nl/agent-prompts.ts +5 -5
  394. package/src/locales/nl/agent-providers.ts +33 -32
  395. package/src/locales/nl/agent-usage.ts +25 -20
  396. package/src/providers/CliDetail.tsx +2 -1
  397. package/src/providers/InstallPage.tsx +2 -4
  398. package/src/providers/ProviderList.tsx +12 -2
  399. package/src/providers/ProvidersPane.tsx +45 -15
  400. package/src/providers/pane-target.ts +20 -4
  401. package/src/state/chats.ts +2 -2
  402. package/src/usage/LimitsList.tsx +12 -13
  403. package/src/usage/UsageBreakdown.tsx +17 -6
  404. package/src/usage/UsageLimits.tsx +2 -1
  405. package/src/usage/UsagePage.tsx +3 -3
  406. package/src/usage/index.ts +1 -1
  407. package/src/usage/limit-groups.ts +12 -0
  408. package/src/usage/limits.ts +2 -2
  409. package/src/usage/money.ts +1 -2
@@ -2,104 +2,102 @@ import i18next from 'i18next';
2
2
  import { activeSubagents } from '@adecore/agent-contracts';
3
3
  import { formatMoment, formatElapsedShort, formatTokens } from '@adecore/ui/format';
4
4
  export function subagentTitle(item) {
5
- return item.description || item.summary || item.subagentType || i18next.t('agent-chat:rows.subagent.label');
5
+ return item.description || item.summary || item.subagentType || i18next.t('agent-chat:rows.subagent.label');
6
6
  }
7
7
  /* What the bar over a sub-agent's conversation says of it beside its state and its time; the model is named by the caller, which has the catalog. */
8
8
  export function subagentFacts(item, modelName) {
9
- return [
10
- modelName,
11
- item.subagentType,
12
- item.background ? i18next.t('agent-chat:rows.subagent.background') : null,
13
- item.usage !== null && item.usage.totalTokens > 0
14
- ? i18next.t('agent-chat:subagents.info.tokens', { tokens: formatTokens(item.usage.totalTokens) })
15
- : null,
16
- item.usage !== null && item.usage.toolUses > 0 ? i18next.t('agent-chat:group.toolCalls', { count: item.usage.toolUses }) : null
17
- ].filter((fact) => fact !== null && fact !== '');
9
+ return [modelName, item.subagentType, item.background ? i18next.t('agent-chat:rows.subagent.background') : null, item.usage !== null && item.usage.totalTokens > 0 ? i18next.t('agent-chat:subagents.info.tokens', {
10
+ tokens: formatTokens(item.usage.totalTokens)
11
+ }) : null, item.usage !== null && item.usage.toolUses > 0 ? i18next.t('agent-chat:group.toolCalls', {
12
+ count: item.usage.toolUses
13
+ }) : null].filter(fact => fact !== null && fact !== '');
18
14
  }
19
15
  /* The task a row stands for, whose id the host wrote into the row's own. */
20
16
  export function taskIdOf(item) {
21
- return item.origin === 'ruimte' && item.id.startsWith('task-') ? item.id.slice(5) : null;
17
+ return item.origin === 'ruimte' && item.id.startsWith('task-') ? item.id.slice(5) : null;
22
18
  }
23
19
  /* A cancelled task is a failed row on the wire and a paused one a running row, and only the task itself still says which it is. */
24
20
  export function statusWordOf(item, task) {
25
- if (item.status === 'failed' && task?.status === 'cancelled') {
26
- return 'cancelled';
27
- }
28
- if (item.status === 'running' && task?.status === 'open' && task.paused !== undefined) {
29
- return 'paused';
30
- }
31
- return item.status;
21
+ if (item.status === 'failed' && task?.status === 'cancelled') {
22
+ return 'cancelled';
23
+ }
24
+ if (item.status === 'running' && task?.status === 'open' && task.paused !== undefined) {
25
+ return 'paused';
26
+ }
27
+ return item.status;
32
28
  }
33
29
  export function taskRowStateOf(item, task, child) {
34
- const word = statusWordOf(item, task);
35
- if (word === 'running' && (child?.status === 'needs-you' || (child?.requests?.length ?? 0) > 0)) {
36
- return 'waiting';
37
- }
38
- return word;
30
+ const word = statusWordOf(item, task);
31
+ if (word === 'running' && (child?.status === 'needs-you' || (child?.requests?.length ?? 0) > 0)) {
32
+ return 'waiting';
33
+ }
34
+ return word;
39
35
  }
40
36
  /* How far delegated work is: what settled as done, what still runs or waits, and how many of those wait on a person. */
41
37
  export function progressOf(states) {
42
- return {
43
- done: states.filter((state) => state === 'done').length,
44
- total: states.length,
45
- waiting: states.filter((state) => state === 'waiting').length,
46
- active: states.filter((state) => state === 'running' || state === 'paused' || state === 'waiting').length
47
- };
38
+ return {
39
+ done: states.filter(state => state === 'done').length,
40
+ total: states.length,
41
+ waiting: states.filter(state => state === 'waiting').length,
42
+ active: states.filter(state => state === 'running' || state === 'paused' || state === 'waiting').length
43
+ };
48
44
  }
49
45
  /* What the flyout over the composer lists (`activeSubagents`); `order` puts the rows from before the page first. */
50
46
  export function flyoutSubagents(order, structure) {
51
- return activeSubagents(order.flatMap((id) => {
52
- const item = structure[id];
53
- return item === undefined ? [] : [item];
54
- }));
47
+ return activeSubagents(order.flatMap(id => {
48
+ const item = structure[id];
49
+ return item === undefined ? [] : [item];
50
+ }));
55
51
  }
56
52
  /* The one state the badge shows for all of them: work in progress first, then work held up, then whatever went wrong. */
57
53
  export function summaryWordOf(words) {
58
- return ['running', 'paused', 'failed', 'cancelled'].find((word) => words.includes(word)) ?? 'done';
54
+ return ['running', 'paused', 'failed', 'cancelled'].find(word => words.includes(word)) ?? 'done';
59
55
  }
60
56
  /* The number on the badge: the ones still at work, a paused one included, and all of them once none is. */
61
57
  export function badgeCountOf(words) {
62
- const active = words.filter((word) => word === 'running' || word === 'paused').length;
63
- return active > 0 ? active : words.length;
58
+ const active = words.filter(word => word === 'running' || word === 'paused').length;
59
+ return active > 0 ? active : words.length;
64
60
  }
65
61
  /* The time on the right of an entry: how long it has run so far, or how long it took once it settled. */
66
62
  export function entryTimeOf(item, task, now) {
67
- // A task's own record says when it was given and settled; the row copies those, but may lag behind it.
68
- const startedAt = task?.createdAt ?? item.startedAt;
69
- const finishedAt = task === null ? item.finishedAt : (task.settledAt ?? item.finishedAt);
70
- const word = statusWordOf(item, task);
71
- if (word === 'paused') {
72
- const until = task?.paused?.until;
73
- return until === undefined
74
- ? i18next.t('agent-chat:common.status.paused')
75
- : i18next.t('agent-chat:activity.pausedUntil', { time: formatMoment(until, now) });
76
- }
77
- if (item.status === 'running') {
78
- return startedAt > 0 ? formatElapsedShort(now - startedAt) : '';
79
- }
80
- if (startedAt <= 0 || finishedAt === null || finishedAt < startedAt) {
81
- return i18next.t(`agent-chat:common.status.${word}`);
82
- }
83
- return i18next.t(`agent-chat:activity.took.${word}`, { duration: formatElapsedShort(finishedAt - startedAt) });
63
+ // A task's own record says when it was given and settled; the row copies those, but may lag behind it.
64
+ const startedAt = task?.createdAt ?? item.startedAt;
65
+ const finishedAt = task === null ? item.finishedAt : task.settledAt ?? item.finishedAt;
66
+ const word = statusWordOf(item, task);
67
+ if (word === 'paused') {
68
+ const until = task?.paused?.until;
69
+ return until === undefined ? i18next.t('agent-chat:common.status.paused') : i18next.t('agent-chat:activity.pausedUntil', {
70
+ time: formatMoment(until, now)
71
+ });
72
+ }
73
+ if (item.status === 'running') {
74
+ return startedAt > 0 ? formatElapsedShort(now - startedAt) : '';
75
+ }
76
+ if (startedAt <= 0 || finishedAt === null || finishedAt < startedAt) {
77
+ return i18next.t(`agent-chat:common.status.${word}`);
78
+ }
79
+ return i18next.t(`agent-chat:activity.took.${word}`, {
80
+ duration: formatElapsedShort(finishedAt - startedAt)
81
+ });
84
82
  }
85
83
  export function stopOf(item, turnRunning) {
86
- if (item.status !== 'running') {
87
- return null;
88
- }
89
- if (item.origin === 'ruimte') {
90
- return item.childId === undefined ? null : 'task';
91
- }
92
- if (item.native?.agentId) {
93
- return 'native';
94
- }
95
- return turnRunning ? null : 'mark';
84
+ if (item.status !== 'running') {
85
+ return null;
86
+ }
87
+ if (item.origin === 'ruimte') {
88
+ return item.childId === undefined ? null : 'task';
89
+ }
90
+ if (item.native?.agentId) {
91
+ return 'native';
92
+ }
93
+ return turnRunning ? null : 'mark';
96
94
  }
97
95
  export function stopLabel(stop) {
98
- return i18next.t(`agent-chat:subagents.stop.${stop}`);
96
+ return i18next.t(`agent-chat:subagents.stop.${stop}`);
99
97
  }
100
98
  export function composerStopOf(shiftKey) {
101
- return shiftKey ? 'turn-and-subagents' : 'turn';
99
+ return shiftKey ? 'turn-and-subagents' : 'turn';
102
100
  }
103
101
  export function composerStopLabel() {
104
- return i18next.t('agent-chat:composer.stop');
105
- }
102
+ return i18next.t('agent-chat:composer.stop');
103
+ }
@@ -4,11 +4,16 @@ import { create } from 'zustand';
4
4
  * version: the first refusal hides the button on that host's rows that carry no pointer of their own.
5
5
  */
6
6
  export const useSubagentSupport = create((set, get) => ({
7
- unsupported: {},
8
- markUnsupported(scopeId) {
9
- if (get().unsupported[scopeId]) {
10
- return;
11
- }
12
- set({ unsupported: { ...get().unsupported, [scopeId]: true } });
7
+ unsupported: {},
8
+ markUnsupported(scopeId) {
9
+ if (get().unsupported[scopeId]) {
10
+ return;
13
11
  }
14
- }));
12
+ set({
13
+ unsupported: {
14
+ ...get().unsupported,
15
+ [scopeId]: true
16
+ }
17
+ });
18
+ }
19
+ }));
@@ -1,5 +1,5 @@
1
+ import { c as _c } from "react/compiler-runtime";
1
2
  import i18next from 'i18next';
2
- import { useMemo } from 'react';
3
3
  import { create } from 'zustand';
4
4
  import { useChatScope } from '../scope.js';
5
5
  import { useChatRow } from '../state/chats.js';
@@ -7,90 +7,178 @@ import { useSubagentSupport } from './subagent-support.js';
7
7
  export const MAIN_AGENT = [];
8
8
  const NO_ITEMS = [];
9
9
  export function crumbOf(item) {
10
- return { toolUseId: item.toolUseId, description: item.description };
10
+ return {
11
+ toolUseId: item.toolUseId,
12
+ description: item.description
13
+ };
11
14
  }
12
15
  function stepLabel(step) {
13
- return step.description || i18next.t('agent-chat:rows.subagent.label');
16
+ return step.description || i18next.t('agent-chat:rows.subagent.label');
14
17
  }
15
18
  /* A row in the main agent's thread or an entry of the flyout opens its conversation straight away. */
16
19
  export function openFromMain(step) {
17
- return [step];
20
+ return [step];
18
21
  }
19
22
  export function openBelow(trail, step) {
20
- return [...trail, step];
23
+ return [...trail, step];
21
24
  }
22
25
  export function trailTo(trail, depth) {
23
- return depth <= 0 ? MAIN_AGENT : trail.slice(0, depth);
26
+ return depth <= 0 ? MAIN_AGENT : trail.slice(0, depth);
24
27
  }
25
28
  export function stepBack(trail) {
26
- return trailTo(trail, trail.length - 1);
29
+ return trailTo(trail, trail.length - 1);
27
30
  }
28
31
  /*
29
32
  * A sub-agent's conversation is read back, so there is nobody to write to. The composer stays, since
30
33
  * the chat's own approvals and questions are answered there.
31
34
  */
32
35
  export function composerWrites(trail) {
33
- return trail.length === 0;
36
+ return trail.length === 0;
34
37
  }
35
38
  /* The crumbs after the chat's own title, which the bar draws as the first crumb and the way back. */
36
39
  export function breadcrumbOf(trail) {
37
- return trail.map((step, index) => ({ label: stepLabel(step), depth: index + 1, current: index === trail.length - 1 }));
40
+ return trail.map((step, index) => ({
41
+ label: stepLabel(step),
42
+ depth: index + 1,
43
+ current: index === trail.length - 1
44
+ }));
38
45
  }
39
46
  /* A row without a pointer of its own can only be opened by a machine that answers `chat.subagent` for it. */
40
47
  export function canOpenSubagent(item, machineRefused) {
41
- return item.native !== undefined || !machineRefused;
48
+ return item.native !== undefined || !machineRefused;
42
49
  }
43
50
  /* The row of the call that opened a conversation, a nested one included, since its row is in the thread too. */
44
51
  export function subagentOf(structure, toolUseId) {
45
- return Object.values(structure).find((item) => item.kind === 'subagent' && item.toolUseId === toolUseId) ?? null;
52
+ return Object.values(structure).find(item => item.kind === 'subagent' && item.toolUseId === toolUseId) ?? null;
46
53
  }
47
54
  /* The subagents a chat can open, in the order the thread has them. */
48
55
  export function openableSubagents(order, structure, machineRefused) {
49
- return order.flatMap((id) => {
50
- const item = structure[id];
51
- return item?.kind === 'subagent' && canOpenSubagent(item, machineRefused) ? [item] : [];
52
- });
56
+ return order.flatMap(id => {
57
+ const item = structure[id];
58
+ return item?.kind === 'subagent' && canOpenSubagent(item, machineRefused) ? [item] : [];
59
+ });
53
60
  }
54
61
  /*
55
62
  * What a chat shows in its place, for this page's life only: a look into a subagent is a moment
56
63
  * rather than a place, so it is never written to the project or to the host.
57
64
  */
58
65
  export const useSubagentView = create((set, get) => ({
59
- trails: {},
60
- show(key, trail) {
61
- const trails = { ...get().trails };
62
- if (trail.length === 0) {
63
- delete trails[key];
64
- }
65
- else {
66
- trails[key] = trail;
67
- }
68
- set({ trails });
69
- },
70
- back(key) {
71
- const trail = get().trails[key];
72
- if (trail === undefined || trail.length === 0) {
73
- return false;
74
- }
75
- get().show(key, stepBack(trail));
76
- return true;
66
+ trails: {},
67
+ show(key, trail) {
68
+ const trails = {
69
+ ...get().trails
70
+ };
71
+ if (trail.length === 0) {
72
+ delete trails[key];
73
+ } else {
74
+ trails[key] = trail;
75
+ }
76
+ set({
77
+ trails
78
+ });
79
+ },
80
+ back(key) {
81
+ const trail = get().trails[key];
82
+ if (trail === undefined || trail.length === 0) {
83
+ return false;
77
84
  }
85
+ get().show(key, stepBack(trail));
86
+ return true;
87
+ }
78
88
  }));
79
89
  /* The trail of a chat in the scope this is rendered in, and a way to set it. */
80
90
  export function useSubagentTrail(chatId) {
81
- const key = useChatScope().keyOf(chatId);
82
- const trail = useSubagentView((s) => s.trails[key] ?? MAIN_AGENT);
83
- return { trail, show: (next) => useSubagentView.getState().show(key, next) };
91
+ const $ = _c(10);
92
+ const t0 = useChatScope();
93
+ let t1;
94
+ if ($[0] !== chatId || $[1] !== t0) {
95
+ t1 = t0.keyOf(chatId);
96
+ $[0] = chatId;
97
+ $[1] = t0;
98
+ $[2] = t1;
99
+ } else {
100
+ t1 = $[2];
101
+ }
102
+ const key = t1;
103
+ let t2;
104
+ if ($[3] !== key) {
105
+ t2 = s => s.trails[key] ?? MAIN_AGENT;
106
+ $[3] = key;
107
+ $[4] = t2;
108
+ } else {
109
+ t2 = $[4];
110
+ }
111
+ const trail = useSubagentView(t2);
112
+ let t3;
113
+ if ($[5] !== key) {
114
+ t3 = next => useSubagentView.getState().show(key, next);
115
+ $[5] = key;
116
+ $[6] = t3;
117
+ } else {
118
+ t3 = $[6];
119
+ }
120
+ let t4;
121
+ if ($[7] !== t3 || $[8] !== trail) {
122
+ t4 = {
123
+ trail,
124
+ show: t3
125
+ };
126
+ $[7] = t3;
127
+ $[8] = trail;
128
+ $[9] = t4;
129
+ } else {
130
+ t4 = $[9];
131
+ }
132
+ return t4;
84
133
  }
85
134
  export function useOpenableSubagents(chatId) {
86
- const { id } = useChatScope();
87
- const refused = useSubagentSupport((s) => s.unsupported[id] === true);
88
- // The structure and not the items, so a delta growing a reply does not walk the thread again.
89
- const order = useChatRow(chatId, (row) => row?.order);
90
- const structure = useChatRow(chatId, (row) => row?.structure);
91
- return useMemo(() => (structure === undefined ? [] : openableSubagents(order ?? NO_ITEMS, structure, refused)), [order, structure, refused]);
135
+ const $ = _c(6);
136
+ const {
137
+ id
138
+ } = useChatScope();
139
+ let t0;
140
+ if ($[0] !== id) {
141
+ t0 = s => s.unsupported[id] === true;
142
+ $[0] = id;
143
+ $[1] = t0;
144
+ } else {
145
+ t0 = $[1];
146
+ }
147
+ const refused = useSubagentSupport(t0);
148
+ const order = useChatRow(chatId, _temp);
149
+ const structure = useChatRow(chatId, _temp2);
150
+ let t1;
151
+ if ($[2] !== order || $[3] !== refused || $[4] !== structure) {
152
+ t1 = structure === undefined ? [] : openableSubagents(order ?? NO_ITEMS, structure, refused);
153
+ $[2] = order;
154
+ $[3] = refused;
155
+ $[4] = structure;
156
+ $[5] = t1;
157
+ } else {
158
+ t1 = $[5];
159
+ }
160
+ return t1;
161
+ }
162
+ function _temp2(row_0) {
163
+ return row_0?.structure;
164
+ }
165
+ function _temp(row) {
166
+ return row?.order;
92
167
  }
93
168
  export function useSubagentItem(chatId, toolUseId) {
94
- const structure = useChatRow(chatId, (row) => row?.structure);
95
- return useMemo(() => (structure === undefined ? null : subagentOf(structure, toolUseId)), [structure, toolUseId]);
169
+ const $ = _c(3);
170
+ const structure = useChatRow(chatId, _temp3);
171
+ let t0;
172
+ if ($[0] !== structure || $[1] !== toolUseId) {
173
+ t0 = structure === undefined ? null : subagentOf(structure, toolUseId);
174
+ $[0] = structure;
175
+ $[1] = toolUseId;
176
+ $[2] = t0;
177
+ } else {
178
+ t0 = $[2];
179
+ }
180
+ return t0;
96
181
  }
182
+ function _temp3(row) {
183
+ return row?.structure;
184
+ }
@@ -1,3 +1,4 @@
1
+ import { c as _c } from "react/compiler-runtime";
1
2
  import i18next from 'i18next';
2
3
  import { useEffect, useState } from 'react';
3
4
  import { uploadPreviewUrl } from './attachments.js';
@@ -5,29 +6,29 @@ import { uploadPreviewUrl } from './attachments.js';
5
6
  export const THUMBNAIL_PX = 256;
6
7
  /* The square in the middle of an image that a thumbnail shows, the same part `object-cover` would. */
7
8
  export function thumbnailCrop(width, height, max = THUMBNAIL_PX) {
8
- const size = Math.max(1, Math.min(width, height));
9
- return {
10
- sx: Math.max(0, Math.floor((width - size) / 2)),
11
- sy: Math.max(0, Math.floor((height - size) / 2)),
12
- size,
13
- out: Math.min(max, size)
14
- };
9
+ const size = Math.max(1, Math.min(width, height));
10
+ return {
11
+ sx: Math.max(0, Math.floor((width - size) / 2)),
12
+ sy: Math.max(0, Math.floor((height - size) / 2)),
13
+ size,
14
+ out: Math.min(max, size)
15
+ };
15
16
  }
16
17
  function bytesOf(base64) {
17
- const binary = atob(base64);
18
- const bytes = new Uint8Array(new ArrayBuffer(binary.length));
19
- for (let i = 0; i < binary.length; i++) {
20
- bytes[i] = binary.charCodeAt(i);
21
- }
22
- return bytes;
18
+ const binary = atob(base64);
19
+ const bytes = new Uint8Array(new ArrayBuffer(binary.length));
20
+ for (let i = 0; i < binary.length; i++) {
21
+ bytes[i] = binary.charCodeAt(i);
22
+ }
23
+ return bytes;
23
24
  }
24
25
  function dataUrlOf(blob) {
25
- return new Promise((resolve, reject) => {
26
- const reader = new FileReader();
27
- reader.onerror = () => reject(reader.error ?? new Error(i18next.t('agent-chat:attachments.unreadableThumbnail')));
28
- reader.onload = () => resolve(String(reader.result));
29
- reader.readAsDataURL(blob);
30
- });
26
+ return new Promise((resolve, reject) => {
27
+ const reader = new FileReader();
28
+ reader.onerror = () => reject(reader.error ?? new Error(i18next.t('agent-chat:attachments.unreadableThumbnail')));
29
+ reader.onload = () => resolve(String(reader.result));
30
+ reader.readAsDataURL(blob);
31
+ });
31
32
  }
32
33
  /*
33
34
  * A still of the middle of an image, decoded once: a browser decodes a full data URL again on every
@@ -35,54 +36,81 @@ function dataUrlOf(blob) {
35
36
  * cannot be decoded this way (an SVG, a browser without `OffscreenCanvas`) falls back to the image.
36
37
  */
37
38
  async function makeThumbnail(upload) {
38
- try {
39
- const bitmap = await createImageBitmap(new Blob([bytesOf(upload.data)], { type: upload.mime }));
40
- const crop = thumbnailCrop(bitmap.width, bitmap.height);
41
- const canvas = new OffscreenCanvas(crop.out, crop.out);
42
- const context = canvas.getContext('2d');
43
- if (!context) {
44
- bitmap.close();
45
- return uploadPreviewUrl(upload);
46
- }
47
- context.drawImage(bitmap, crop.sx, crop.sy, crop.size, crop.size, 0, 0, crop.out, crop.out);
48
- bitmap.close();
49
- return await dataUrlOf(await canvas.convertToBlob({ type: 'image/png' }));
50
- }
51
- catch {
52
- return uploadPreviewUrl(upload);
39
+ try {
40
+ const bitmap = await createImageBitmap(new Blob([bytesOf(upload.data)], {
41
+ type: upload.mime
42
+ }));
43
+ const crop = thumbnailCrop(bitmap.width, bitmap.height);
44
+ const canvas = new OffscreenCanvas(crop.out, crop.out);
45
+ const context = canvas.getContext('2d');
46
+ if (!context) {
47
+ bitmap.close();
48
+ return uploadPreviewUrl(upload);
53
49
  }
50
+ context.drawImage(bitmap, crop.sx, crop.sy, crop.size, crop.size, 0, 0, crop.out, crop.out);
51
+ bitmap.close();
52
+ return await dataUrlOf(await canvas.convertToBlob({
53
+ type: 'image/png'
54
+ }));
55
+ } catch {
56
+ return uploadPreviewUrl(upload);
57
+ }
54
58
  }
55
59
  // Keyed by the upload itself, so a composer that mounts again finds it and a removed file lets it go.
56
60
  const made = new WeakMap();
57
61
  const making = new WeakMap();
58
62
  function thumbnailOf(upload) {
59
- let promise = making.get(upload);
60
- if (!promise) {
61
- promise = makeThumbnail(upload).then((url) => {
62
- made.set(upload, url);
63
- return url;
64
- });
65
- making.set(upload, promise);
66
- }
67
- return promise;
63
+ let promise = making.get(upload);
64
+ if (!promise) {
65
+ promise = makeThumbnail(upload).then(url => {
66
+ made.set(upload, url);
67
+ return url;
68
+ });
69
+ making.set(upload, promise);
70
+ }
71
+ return promise;
68
72
  }
69
73
  /* The thumbnail of an image the composer holds, or null while it is being made. */
70
74
  export function useUploadThumbnail(upload) {
71
- const [ready, setReady] = useState(null);
72
- const cached = made.get(upload);
73
- useEffect(() => {
74
- if (made.has(upload)) {
75
- return;
75
+ const $ = _c(5);
76
+ const [ready, setReady] = useState(null);
77
+ let t0;
78
+ if ($[0] !== upload) {
79
+ t0 = made.get(upload);
80
+ $[0] = upload;
81
+ $[1] = t0;
82
+ } else {
83
+ t0 = $[1];
84
+ }
85
+ const cached = t0;
86
+ let t1;
87
+ let t2;
88
+ if ($[2] !== upload) {
89
+ t1 = () => {
90
+ if (made.has(upload)) {
91
+ return;
92
+ }
93
+ let cancelled = false;
94
+ thumbnailOf(upload).then(url => {
95
+ if (!cancelled) {
96
+ setReady({
97
+ upload,
98
+ url
99
+ });
76
100
  }
77
- let cancelled = false;
78
- void thumbnailOf(upload).then((url) => {
79
- if (!cancelled) {
80
- setReady({ upload, url });
81
- }
82
- });
83
- return () => {
84
- cancelled = true;
85
- };
86
- }, [upload]);
87
- return cached ?? (ready?.upload === upload ? ready.url : null);
88
- }
101
+ });
102
+ return () => {
103
+ cancelled = true;
104
+ };
105
+ };
106
+ t2 = [upload];
107
+ $[2] = upload;
108
+ $[3] = t1;
109
+ $[4] = t2;
110
+ } else {
111
+ t1 = $[3];
112
+ t2 = $[4];
113
+ }
114
+ useEffect(t1, t2);
115
+ return cached ?? (ready?.upload === upload ? ready.url : null);
116
+ }
@@ -2,15 +2,27 @@ import { create } from 'zustand';
2
2
  /* A little longer than the animation of `.chat-flash`, so a row that scrolls into view again later is neither lit nor opened a second time. */
3
3
  const FLASH_MS = 2000;
4
4
  export const useTimelineFlash = create((set, get) => ({
5
- target: null,
6
- flash(key, rowId, opens, block) {
7
- const nonce = (get().target?.nonce ?? 0) + 1;
8
- set({ target: { key, rowId, opens, nonce, ...(block ? { block } : {}) } });
9
- const timer = setTimeout(() => {
10
- if (get().target?.nonce === nonce) {
11
- set({ target: null });
12
- }
13
- }, FLASH_MS);
14
- timer.unref?.();
15
- }
16
- }));
5
+ target: null,
6
+ flash(key, rowId, opens, block) {
7
+ const nonce = (get().target?.nonce ?? 0) + 1;
8
+ set({
9
+ target: {
10
+ key,
11
+ rowId,
12
+ opens,
13
+ nonce,
14
+ ...(block ? {
15
+ block
16
+ } : {})
17
+ }
18
+ });
19
+ const timer = setTimeout(() => {
20
+ if (get().target?.nonce === nonce) {
21
+ set({
22
+ target: null
23
+ });
24
+ }
25
+ }, FLASH_MS);
26
+ timer.unref?.();
27
+ }
28
+ }));