@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.
- package/README.md +1 -1
- package/dist/agents/AccountDot.js +57 -6
- package/dist/agents/AgentIcon.js +88 -12
- package/dist/agents/ModelOptionControl.js +153 -18
- package/dist/agents/ProviderLogo.js +49 -4
- package/dist/agents/account-limits.js +17 -14
- package/dist/agents/accounts.js +99 -67
- package/dist/agents/agent-marks.js +5 -3
- package/dist/agents/model-name.js +42 -31
- package/dist/agents/model-options.js +8 -8
- package/dist/agents/model-requirement.js +17 -14
- package/dist/agents/option-words.d.ts +7 -0
- package/dist/agents/option-words.js +35 -0
- package/dist/agents/provider-paths.js +6 -6
- package/dist/agents/status-look.js +32 -12
- package/dist/chat/account-choice.d.ts +13 -0
- package/dist/chat/account-choice.js +90 -20
- package/dist/chat/actions.js +126 -59
- package/dist/chat/activity.js +5 -5
- package/dist/chat/attachments.js +74 -53
- package/dist/chat/bookmarks.js +58 -48
- package/dist/chat/chat-client.js +344 -263
- package/dist/chat/chat-references.js +3 -3
- package/dist/chat/composer-effort.d.ts +5 -0
- package/dist/chat/composer-effort.js +26 -0
- package/dist/chat/composer-send.js +13 -13
- package/dist/chat/drafts.js +115 -79
- package/dist/chat/forks.js +81 -24
- package/dist/chat/guards.js +15 -43
- package/dist/chat/index.d.ts +3 -1
- package/dist/chat/index.js +3 -2
- package/dist/chat/logic/ansi.js +170 -167
- package/dist/chat/logic/answers.js +2 -2
- package/dist/chat/logic/bookmarks.js +19 -19
- package/dist/chat/logic/command-looks.js +138 -96
- package/dist/chat/logic/context-usage.js +13 -9
- package/dist/chat/logic/continue-after-stop.js +15 -19
- package/dist/chat/logic/effort.d.ts +14 -0
- package/dist/chat/logic/effort.js +34 -0
- package/dist/chat/logic/embedded-code.js +387 -326
- package/dist/chat/logic/fork.js +134 -110
- package/dist/chat/logic/generated-image.js +54 -23
- package/dist/chat/logic/goal.js +28 -20
- package/dist/chat/logic/handback.js +6 -6
- package/dist/chat/logic/json.js +2 -2
- package/dist/chat/logic/limit.js +46 -30
- package/dist/chat/logic/picker-entries.d.ts +5 -3
- package/dist/chat/logic/picker-entries.js +83 -43
- package/dist/chat/logic/resume-compaction.d.ts +14 -1
- package/dist/chat/logic/resume-compaction.js +93 -24
- package/dist/chat/logic/scrubber.js +188 -136
- package/dist/chat/logic/thought.js +13 -16
- package/dist/chat/logic/thread-cards.js +60 -48
- package/dist/chat/logic/timeline-copy.js +30 -38
- package/dist/chat/logic/timeline-target.js +92 -63
- package/dist/chat/logic/timeline.js +499 -355
- package/dist/chat/logic/tool-catalog.js +54 -34
- package/dist/chat/logic/tools.js +106 -82
- package/dist/chat/logic/visual-height.js +18 -18
- package/dist/chat/logic/visual-viewport.js +6 -3
- package/dist/chat/logic/welcome.js +9 -9
- package/dist/chat/logic/workflow.d.ts +10 -0
- package/dist/chat/logic/workflow.js +130 -32
- package/dist/chat/mentions.js +149 -109
- package/dist/chat/persisted-json.js +51 -54
- package/dist/chat/preferences.d.ts +4 -0
- package/dist/chat/preferences.js +162 -84
- package/dist/chat/prompt-hold.js +9 -9
- package/dist/chat/quote.js +21 -30
- package/dist/chat/reading-width.js +12 -10
- package/dist/chat/recent-messages.js +34 -21
- package/dist/chat/resume-compaction-dismissals.js +25 -5
- package/dist/chat/runtime-modes.js +3 -3
- package/dist/chat/send-key.js +11 -7
- package/dist/chat/stash.js +89 -69
- package/dist/chat/subagent-conversation.js +181 -139
- package/dist/chat/subagent-list.js +65 -67
- package/dist/chat/subagent-support.js +12 -7
- package/dist/chat/subagent-view.js +132 -44
- package/dist/chat/thumbnails.js +88 -60
- package/dist/chat/timeline-flash.js +24 -12
- package/dist/chat/timeline-scroll.js +116 -86
- package/dist/chat/ui/AccountPill.js +126 -15
- package/dist/chat/ui/AnsiOutput.js +62 -6
- package/dist/chat/ui/BookmarkMarker.js +231 -41
- package/dist/chat/ui/BookmarkSubmenu.js +165 -18
- package/dist/chat/ui/ChatActivity.js +649 -70
- package/dist/chat/ui/ChatReferenceChip.js +104 -9
- package/dist/chat/ui/CodeBlock.js +132 -58
- package/dist/chat/ui/Composer.js +866 -132
- package/dist/chat/ui/ComposerInput.js +309 -120
- package/dist/chat/ui/DiffPool.js +75 -14
- package/dist/chat/ui/EditDiff.js +160 -21
- package/dist/chat/ui/FadingWords.js +32 -3
- package/dist/chat/ui/GoalDock.js +235 -42
- package/dist/chat/ui/ImageView.js +617 -61
- package/dist/chat/ui/LimitState.js +446 -72
- package/dist/chat/ui/Markdown.js +991 -173
- package/dist/chat/ui/MermaidBlock.js +285 -79
- package/dist/chat/ui/MessageActions.js +251 -39
- package/dist/chat/ui/ModelMarks.js +55 -5
- package/dist/chat/ui/Pickers.js +664 -113
- package/dist/chat/ui/PromptComposer.js +281 -51
- package/dist/chat/ui/QuoteButton.js +151 -57
- package/dist/chat/ui/ResumeCompactionDock.d.ts +6 -2
- package/dist/chat/ui/ResumeCompactionDock.js +141 -6
- package/dist/chat/ui/RowTime.js +59 -5
- package/dist/chat/ui/RunSettings.js +1744 -154
- package/dist/chat/ui/Scrubber.js +517 -88
- package/dist/chat/ui/ShellCommand.js +183 -107
- package/dist/chat/ui/SubagentControls.js +212 -24
- package/dist/chat/ui/SubagentInfo.js +170 -13
- package/dist/chat/ui/SubagentStopButton.js +115 -24
- package/dist/chat/ui/SubagentTimeline.js +357 -91
- package/dist/chat/ui/Timeline.js +988 -476
- package/dist/chat/ui/TimelineMenu.js +552 -37
- package/dist/chat/ui/UnifiedDiff.js +234 -27
- package/dist/chat/ui/UploadThumb.js +37 -7
- package/dist/chat/ui/VisualDialogs.js +251 -20
- package/dist/chat/ui/VisualFrame.js +321 -95
- package/dist/chat/ui/Welcome.js +72 -7
- package/dist/chat/ui/chips.js +1 -1
- package/dist/chat/ui/code-lines.js +36 -36
- package/dist/chat/ui/code-streaming.js +1 -1
- package/dist/chat/ui/code-theme.js +7 -7
- package/dist/chat/ui/composer/ComposerControls.js +329 -21
- package/dist/chat/ui/composer/ComposerMenu.js +358 -30
- package/dist/chat/ui/composer/DraftParts.js +185 -11
- package/dist/chat/ui/composer/QueuedMessages.js +138 -13
- package/dist/chat/ui/composer/chips.js +29 -19
- package/dist/chat/ui/composer/editor.js +79 -63
- package/dist/chat/ui/composer/insert.js +26 -12
- package/dist/chat/ui/composer/key-handler.js +180 -127
- package/dist/chat/ui/composer/keys.js +90 -73
- package/dist/chat/ui/composer/menu-aria.js +18 -9
- package/dist/chat/ui/composer/placeholder.js +78 -31
- package/dist/chat/ui/composer/surface.js +13 -37
- package/dist/chat/ui/composer/use-chat-controls.js +230 -90
- package/dist/chat/ui/composer/use-compaction-offer.js +50 -18
- package/dist/chat/ui/composer/use-composer-draft.js +65 -34
- package/dist/chat/ui/composer/use-composer-menus.js +478 -193
- package/dist/chat/ui/composer/use-composer-submit.js +251 -109
- package/dist/chat/ui/composer/use-continuable-turn.js +33 -6
- package/dist/chat/ui/composer/use-draft-files.js +245 -93
- package/dist/chat/ui/composer/use-effort-stepper.d.ts +13 -0
- package/dist/chat/ui/composer/use-effort-stepper.js +88 -0
- package/dist/chat/ui/composer/use-notice.js +61 -16
- package/dist/chat/ui/composer/use-pending-requests.js +38 -17
- package/dist/chat/ui/composer/use-prompt-history.js +117 -45
- package/dist/chat/ui/composer/use-prompt-hold.js +119 -35
- package/dist/chat/ui/composer/use-take-back.js +94 -72
- package/dist/chat/ui/diff/ApprovalReview.js +101 -23
- package/dist/chat/ui/diff/DiffFallbackBoundary.js +21 -13
- package/dist/chat/ui/diff/DiffOmitted.js +56 -6
- package/dist/chat/ui/diff/DiffStack.js +92 -8
- package/dist/chat/ui/diff/DiffUnavailable.js +56 -6
- package/dist/chat/ui/diff/EditorEditDiff.js +263 -51
- package/dist/chat/ui/diff/EditorPatchDiff.js +39 -14
- package/dist/chat/ui/diff/LegacyDiffPool.js +27 -10
- package/dist/chat/ui/diff/LegacyEditDiff.js +97 -20
- package/dist/chat/ui/diff/LegacyUnifiedDiff.js +172 -42
- package/dist/chat/ui/diff/RawDiff.js +65 -5
- package/dist/chat/ui/diff/ReviewDiff.js +77 -5
- package/dist/chat/ui/diff/diff-props.js +1 -1
- package/dist/chat/ui/diff/diff-source-budget.js +46 -35
- package/dist/chat/ui/diff/editor-edit-model.js +18 -14
- package/dist/chat/ui/diff/review-plan.js +63 -40
- package/dist/chat/ui/diff/review-settle.js +24 -9
- package/dist/chat/ui/diff/syntax-runtime.js +236 -201
- package/dist/chat/ui/diff/use-review-stack.js +146 -25
- package/dist/chat/ui/diff-syntax.js +70 -58
- package/dist/chat/ui/diff-theme.js +31 -12
- package/dist/chat/ui/file-links.js +39 -10
- package/dist/chat/ui/find-reveal.js +29 -8
- package/dist/chat/ui/full-diff.js +17 -12
- package/dist/chat/ui/highlighter.js +143 -113
- package/dist/chat/ui/icons.js +16 -7
- package/dist/chat/ui/index.js +1 -1
- package/dist/chat/ui/intelligent-ui/UiBlockFrame.js +556 -82
- package/dist/chat/ui/intelligent-ui/UiFallbackPart.js +73 -5
- package/dist/chat/ui/intelligent-ui/UiReply.js +666 -262
- package/dist/chat/ui/intelligent-ui/block-local.js +59 -31
- package/dist/chat/ui/intelligent-ui/chart-data.js +77 -67
- package/dist/chat/ui/intelligent-ui/node-text.js +77 -91
- package/dist/chat/ui/intelligent-ui/registry.js +46 -46
- package/dist/chat/ui/intelligent-ui/render-context.js +1 -1
- package/dist/chat/ui/intelligent-ui/renderers/base-land.js +1 -1
- package/dist/chat/ui/intelligent-ui/renderers/binding.js +3 -3
- package/dist/chat/ui/intelligent-ui/renderers/chart.js +1223 -123
- package/dist/chat/ui/intelligent-ui/renderers/choices.js +312 -34
- package/dist/chat/ui/intelligent-ui/renderers/content.js +1241 -86
- package/dist/chat/ui/intelligent-ui/renderers/data.js +619 -54
- package/dist/chat/ui/intelligent-ui/renderers/inputs.js +868 -67
- package/dist/chat/ui/intelligent-ui/renderers/links.js +366 -62
- package/dist/chat/ui/intelligent-ui/renderers/map-slots.js +118 -60
- package/dist/chat/ui/intelligent-ui/renderers/map-style.js +85 -78
- package/dist/chat/ui/intelligent-ui/renderers/map-view.js +282 -217
- package/dist/chat/ui/intelligent-ui/renderers/map.js +621 -69
- package/dist/chat/ui/intelligent-ui/renderers/place-point.js +15 -8
- package/dist/chat/ui/intelligent-ui/renderers/structure.js +262 -20
- package/dist/chat/ui/intelligent-ui/renderers/text.js +674 -49
- package/dist/chat/ui/intelligent-ui/reply-parts.js +24 -15
- package/dist/chat/ui/intelligent-ui/table-data.js +97 -57
- package/dist/chat/ui/intelligent-ui/tones.js +31 -31
- package/dist/chat/ui/intelligent-ui/use-in-view.js +30 -12
- package/dist/chat/ui/intelligent-ui/use-later.js +28 -13
- package/dist/chat/ui/intelligent-ui/use-truncated.js +45 -21
- package/dist/chat/ui/intelligent-ui/use-ui-links.js +296 -109
- package/dist/chat/ui/intelligent-ui/use-ui-queries.js +256 -246
- package/dist/chat/ui/markdown-blocks.js +296 -262
- package/dist/chat/ui/mermaid.d.ts +8 -20
- package/dist/chat/ui/mermaid.js +47 -84
- package/dist/chat/ui/quote-selection.js +32 -29
- package/dist/chat/ui/rehype-chips.js +35 -23
- package/dist/chat/ui/rehype-fade.js +28 -17
- package/dist/chat/ui/remark-html-as-text.js +22 -15
- package/dist/chat/ui/reply-context.js +1 -1
- package/dist/chat/ui/reveal.js +161 -72
- package/dist/chat/ui/rows/ForksRow.js +226 -24
- package/dist/chat/ui/rows/GeneratedImageRow.js +541 -87
- package/dist/chat/ui/rows/MessageRows.js +1706 -159
- package/dist/chat/ui/rows/RowContainer.js +57 -7
- package/dist/chat/ui/rows/Rows.js +463 -54
- package/dist/chat/ui/rows/SubagentRow.js +577 -60
- package/dist/chat/ui/rows/TaskRow.js +359 -40
- package/dist/chat/ui/rows/VisualRow.js +233 -11
- package/dist/chat/ui/rows/WorkRows.d.ts +3 -0
- package/dist/chat/ui/rows/WorkRows.js +1945 -164
- package/dist/chat/ui/rows/WorkflowRow.js +756 -37
- package/dist/chat/ui/rows/row-rhythm.js +27 -17
- package/dist/chat/ui/theme-watch.js +26 -23
- package/dist/chat/ui/timestamp-format.js +4 -1
- package/dist/chat/ui/use-diff-source-tokens.js +70 -34
- package/dist/chat/ui/useToggleSet.js +51 -19
- package/dist/chat/ui/visual-theme.js +153 -128
- package/dist/chat/visual-bridge.js +123 -123
- package/dist/chat/visual-viewport.js +94 -83
- package/dist/chat/visuals.js +13 -5
- package/dist/host-hooks.d.ts +29 -0
- package/dist/host-hooks.js +78 -0
- package/dist/host.js +120 -48
- package/dist/index.js +1 -1
- package/dist/lazy.js +38 -32
- package/dist/locales/en/agent-chat.d.ts +42 -0
- package/dist/locales/en/agent-chat.js +755 -713
- package/dist/locales/en/agent-prompts.js +42 -42
- package/dist/locales/en/agent-providers.d.ts +1 -0
- package/dist/locales/en/agent-providers.js +166 -165
- package/dist/locales/en/agent-usage.d.ts +6 -0
- package/dist/locales/en/agent-usage.js +129 -123
- package/dist/locales/nl/agent-chat.d.ts +42 -0
- package/dist/locales/nl/agent-chat.js +755 -713
- package/dist/locales/nl/agent-prompts.js +42 -42
- package/dist/locales/nl/agent-providers.d.ts +1 -0
- package/dist/locales/nl/agent-providers.js +166 -165
- package/dist/locales/nl/agent-usage.d.ts +6 -0
- package/dist/locales/nl/agent-usage.js +129 -123
- package/dist/locales.js +14 -14
- package/dist/mounted-registry.js +31 -30
- package/dist/port-transport.js +122 -111
- package/dist/prompts/index.js +1 -1
- package/dist/prompts/logic/focus.js +15 -14
- package/dist/prompts/logic/keys.js +93 -59
- package/dist/prompts/logic/prompts.js +27 -14
- package/dist/prompts/logic/subjects.js +60 -46
- package/dist/prompts/logic/useFocusAfterAnswer.js +60 -20
- package/dist/prompts/logic/usePromptSession.js +88 -77
- package/dist/prompts/ui/ApprovalBody.js +246 -27
- package/dist/prompts/ui/PromptActions.js +215 -9
- package/dist/prompts/ui/PromptCard.js +215 -36
- package/dist/prompts/ui/PromptView.js +372 -34
- package/dist/prompts/ui/QuestionBody.js +269 -73
- package/dist/providers/AccountColors.js +36 -5
- package/dist/providers/AccountDetail.js +683 -50
- package/dist/providers/AccountVariables.js +139 -32
- package/dist/providers/AddAccountForm.js +125 -38
- package/dist/providers/CliDetail.js +343 -36
- package/dist/providers/InstallPage.js +644 -59
- package/dist/providers/ProviderList.d.ts +2 -1
- package/dist/providers/ProviderList.js +215 -23
- package/dist/providers/ProvidersPane.d.ts +4 -2
- package/dist/providers/ProvidersPane.js +244 -64
- package/dist/providers/account-actions.js +54 -30
- package/dist/providers/index.js +1 -1
- package/dist/providers/install-steps.js +12 -9
- package/dist/providers/pane-target.d.ts +3 -0
- package/dist/providers/pane-target.js +34 -13
- package/dist/providers/parts.js +62 -12
- package/dist/providers/provider-abilities.js +5 -5
- package/dist/providers/provider-groups.js +75 -40
- package/dist/providers/variables.js +73 -39
- package/dist/scope.js +6 -6
- package/dist/settings/sections.js +18 -18
- package/dist/state/chats.js +404 -192
- package/dist/state/index.js +1 -1
- package/dist/state/provider-accounts.js +70 -47
- package/dist/state/providers.js +45 -16
- package/dist/state/usage.js +154 -77
- package/dist/storage.js +69 -68
- package/dist/testing/index.js +1 -1
- package/dist/testing/prompts.js +105 -67
- package/dist/transport.js +10 -10
- package/dist/ui/PlainTextarea.js +27 -3
- package/dist/usage/LimitsList.js +646 -40
- package/dist/usage/UsageBreakdown.js +879 -38
- package/dist/usage/UsageChart.js +311 -32
- package/dist/usage/UsageDialog.js +46 -4
- package/dist/usage/UsageLimits.js +467 -34
- package/dist/usage/UsageLimitsCard.js +95 -11
- package/dist/usage/UsagePage.js +817 -96
- package/dist/usage/UsagePane.js +164 -10
- package/dist/usage/UsageSummary.js +151 -6
- package/dist/usage/UsageTiles.js +164 -14
- package/dist/usage/format.js +32 -32
- package/dist/usage/index.d.ts +1 -1
- package/dist/usage/index.js +2 -1
- package/dist/usage/limit-groups.d.ts +2 -0
- package/dist/usage/limit-groups.js +77 -59
- package/dist/usage/limits.js +78 -43
- package/dist/usage/money.js +20 -4
- package/dist/usage/summary.js +85 -64
- package/package.json +9 -9
- package/src/agents/ModelOptionControl.tsx +3 -1
- package/src/agents/option-words.ts +27 -0
- package/src/chat/account-choice.ts +41 -1
- package/src/chat/composer-effort.ts +32 -0
- package/src/chat/forks.ts +4 -5
- package/src/chat/index.ts +3 -1
- package/src/chat/logic/effort.ts +32 -0
- package/src/chat/logic/picker-entries.ts +45 -10
- package/src/chat/logic/resume-compaction.ts +95 -17
- package/src/chat/logic/timeline.ts +11 -3
- package/src/chat/logic/workflow.ts +86 -4
- package/src/chat/preferences.ts +35 -0
- package/src/chat/subagent-view.ts +2 -3
- package/src/chat/ui/AnsiOutput.tsx +1 -2
- package/src/chat/ui/BookmarkSubmenu.tsx +3 -3
- package/src/chat/ui/ChatActivity.tsx +14 -22
- package/src/chat/ui/ChatReferenceChip.tsx +2 -3
- package/src/chat/ui/Composer.tsx +15 -7
- package/src/chat/ui/EditDiff.tsx +2 -3
- package/src/chat/ui/LimitState.tsx +2 -2
- package/src/chat/ui/Markdown.tsx +10 -8
- package/src/chat/ui/MermaidBlock.tsx +57 -49
- package/src/chat/ui/Pickers.tsx +49 -29
- package/src/chat/ui/PromptComposer.tsx +7 -9
- package/src/chat/ui/ResumeCompactionDock.tsx +16 -4
- package/src/chat/ui/RunSettings.tsx +67 -28
- package/src/chat/ui/Scrubber.tsx +3 -3
- package/src/chat/ui/ShellCommand.tsx +2 -0
- package/src/chat/ui/SubagentInfo.tsx +2 -3
- package/src/chat/ui/SubagentTimeline.tsx +12 -16
- package/src/chat/ui/Timeline.tsx +6 -6
- package/src/chat/ui/UnifiedDiff.tsx +3 -4
- package/src/chat/ui/VisualFrame.tsx +5 -8
- package/src/chat/ui/code-theme.ts +4 -4
- package/src/chat/ui/composer/placeholder.ts +2 -2
- package/src/chat/ui/composer/use-compaction-offer.ts +36 -16
- package/src/chat/ui/composer/use-composer-menus.ts +4 -9
- package/src/chat/ui/composer/use-composer-submit.ts +2 -1
- package/src/chat/ui/composer/use-effort-stepper.ts +56 -0
- package/src/chat/ui/composer/use-notice.ts +2 -2
- package/src/chat/ui/diff/EditorEditDiff.tsx +9 -13
- package/src/chat/ui/diff/LegacyEditDiff.tsx +12 -17
- package/src/chat/ui/diff/LegacyUnifiedDiff.tsx +13 -21
- package/src/chat/ui/diff/use-review-stack.ts +4 -4
- package/src/chat/ui/diff-theme.ts +3 -3
- package/src/chat/ui/file-links.ts +2 -2
- package/src/chat/ui/intelligent-ui/UiReply.tsx +2 -0
- package/src/chat/ui/intelligent-ui/renderers/chart.tsx +3 -3
- package/src/chat/ui/intelligent-ui/renderers/content.tsx +5 -6
- package/src/chat/ui/intelligent-ui/renderers/map-view.tsx +2 -1
- package/src/chat/ui/intelligent-ui/renderers/map.tsx +2 -1
- package/src/chat/ui/intelligent-ui/use-truncated.ts +16 -19
- package/src/chat/ui/intelligent-ui/use-ui-links.ts +3 -3
- package/src/chat/ui/mermaid.ts +52 -96
- package/src/chat/ui/rows/ForksRow.tsx +3 -5
- package/src/chat/ui/rows/GeneratedImageRow.tsx +2 -1
- package/src/chat/ui/rows/MessageRows.tsx +12 -21
- package/src/chat/ui/rows/SubagentRow.tsx +3 -3
- package/src/chat/ui/rows/TaskRow.tsx +1 -1
- package/src/chat/ui/rows/WorkRows.tsx +11 -6
- package/src/chat/ui/rows/WorkflowRow.tsx +144 -54
- package/src/chat/ui/useToggleSet.ts +15 -18
- package/src/chat/ui/visual-theme.ts +2 -3
- package/src/host-hooks.ts +113 -0
- package/src/lazy.tsx +2 -0
- package/src/locales/en/agent-chat.ts +142 -108
- package/src/locales/en/agent-prompts.ts +7 -7
- package/src/locales/en/agent-providers.ts +35 -34
- package/src/locales/en/agent-usage.ts +26 -20
- package/src/locales/nl/agent-chat.ts +134 -100
- package/src/locales/nl/agent-prompts.ts +5 -5
- package/src/locales/nl/agent-providers.ts +33 -32
- package/src/locales/nl/agent-usage.ts +25 -20
- package/src/providers/CliDetail.tsx +2 -1
- package/src/providers/InstallPage.tsx +2 -4
- package/src/providers/ProviderList.tsx +12 -2
- package/src/providers/ProvidersPane.tsx +45 -15
- package/src/providers/pane-target.ts +20 -4
- package/src/state/chats.ts +2 -2
- package/src/usage/LimitsList.tsx +12 -13
- package/src/usage/UsageBreakdown.tsx +17 -6
- package/src/usage/UsageLimits.tsx +2 -1
- package/src/usage/UsagePage.tsx +3 -3
- package/src/usage/index.ts +1 -1
- package/src/usage/limit-groups.ts +12 -0
- package/src/usage/limits.ts +2 -2
- package/src/usage/money.ts +1 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
2
|
import clsx from 'clsx';
|
|
3
3
|
import { useShallow } from 'zustand/shallow';
|
|
4
4
|
import { useTranslation } from 'react-i18next';
|
|
@@ -16,6 +16,7 @@ import { useChatHost } from '../../host';
|
|
|
16
16
|
import { useChatScope } from '../../scope';
|
|
17
17
|
import { useChatActions } from '../actions';
|
|
18
18
|
import { statusLookOf, type StatusWord } from '../../agents/status-look';
|
|
19
|
+
import { useHostTask, useHostTasks } from '../../host-hooks';
|
|
19
20
|
|
|
20
21
|
const NO_TASKS: readonly ChatBackgroundTask[] = [];
|
|
21
22
|
|
|
@@ -30,29 +31,21 @@ export function ChatActivity({ chatId }: { chatId: string }) {
|
|
|
30
31
|
const order = useChatRow(chatId, (row) => row?.order) ?? NO_ITEMS;
|
|
31
32
|
const before = useChatRow(chatId, (row) => row?.subagentsBefore) ?? NO_ITEMS;
|
|
32
33
|
const structure = useChatRow(chatId, (row) => row?.structure);
|
|
33
|
-
const subagents =
|
|
34
|
+
const subagents = structure === undefined ? [] : flyoutSubagents([...before, ...order], structure);
|
|
34
35
|
const { id, keyOf } = useChatScope();
|
|
35
|
-
const tasks =
|
|
36
|
+
const tasks = useHostTasks(id);
|
|
36
37
|
// The infos of these sub-agents' own chats, so the info of any other chat changing does not draw this again.
|
|
37
38
|
const children = useChats(useShallow((s) => subagents.map((item) => (item.childId === undefined ? undefined : s.statusByKey[keyOf(item.childId)]?.info))));
|
|
38
|
-
const progress =
|
|
39
|
-
() =>
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
return taskRowStateOf(item, taskId === null ? null : (tasks?.[taskId] ?? null), children[index]);
|
|
44
|
-
})
|
|
45
|
-
),
|
|
46
|
-
[subagents, tasks, children]
|
|
47
|
-
);
|
|
48
|
-
const words = useMemo(
|
|
49
|
-
() =>
|
|
50
|
-
subagents.map((item) => {
|
|
51
|
-
const taskId = taskIdOf(item);
|
|
52
|
-
return statusWordOf(item, taskId === null ? null : (tasks?.[taskId] ?? null));
|
|
53
|
-
}),
|
|
54
|
-
[subagents, tasks]
|
|
39
|
+
const progress = progressOf(
|
|
40
|
+
subagents.map((item, index) => {
|
|
41
|
+
const taskId = taskIdOf(item);
|
|
42
|
+
return taskRowStateOf(item, taskId === null ? null : (tasks?.[taskId] ?? null), children[index]);
|
|
43
|
+
})
|
|
55
44
|
);
|
|
45
|
+
const words = subagents.map((item) => {
|
|
46
|
+
const taskId = taskIdOf(item);
|
|
47
|
+
return statusWordOf(item, taskId === null ? null : (tasks?.[taskId] ?? null));
|
|
48
|
+
});
|
|
56
49
|
const background = useChatRow(chatId, (row) => row?.info.background) ?? NO_TASKS;
|
|
57
50
|
if (subagents.length === 0 && background.length === 0) {
|
|
58
51
|
return null;
|
|
@@ -174,11 +167,10 @@ function SubagentRows({ chatId, items }: { chatId: string; items: readonly ChatS
|
|
|
174
167
|
}
|
|
175
168
|
|
|
176
169
|
function SubagentEntry({ chatId, item, now }: { chatId: string; item: ChatSubagentItem; now: number }) {
|
|
177
|
-
const host = useChatHost();
|
|
178
170
|
const { t } = useTranslation('agent-chat');
|
|
179
171
|
const { id, keyOf } = useChatScope();
|
|
180
172
|
const refused = useSubagentSupport((s) => s.unsupported[id] === true);
|
|
181
|
-
const task =
|
|
173
|
+
const task = useHostTask(id, taskIdOf(item));
|
|
182
174
|
const { show } = useSubagentTrail(chatId);
|
|
183
175
|
const child = useChats((s) => (item.childId === undefined ? undefined : s.statusByKey[keyOf(item.childId)]?.info));
|
|
184
176
|
const word = statusWordOf(item, task);
|
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
import clsx from 'clsx';
|
|
2
2
|
import { useTranslation } from 'react-i18next';
|
|
3
3
|
import { MessageSquare, X } from 'lucide-react';
|
|
4
|
-
import { useChatHost } from '../../host';
|
|
5
4
|
import { CHIP_IN_MESSAGE, MENTION_TONE } from './chips';
|
|
6
5
|
import { Icon, Tooltip } from '@adecore/ui';
|
|
6
|
+
import { useHostReferableChats } from '../../host-hooks';
|
|
7
7
|
|
|
8
8
|
/* A chat attached to a message, under the title it has now rather than the one it had when it was attached. */
|
|
9
9
|
export function ChatReferenceChip({ chatId, onRemove }: { chatId: string; onRemove?: () => void }) {
|
|
10
|
-
const host = useChatHost();
|
|
11
10
|
const { t } = useTranslation('agent-chat');
|
|
12
|
-
const chat =
|
|
11
|
+
const chat = useHostReferableChats().find((candidate) => candidate.id === chatId);
|
|
13
12
|
const title = chat === undefined ? t('chatReference.gone') : chat.title || t('chatReference.untitled');
|
|
14
13
|
return (
|
|
15
14
|
<span className={clsx(MENTION_TONE, CHIP_IN_MESSAGE)}>
|
package/src/chat/ui/Composer.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useEffect,
|
|
1
|
+
import { useEffect, useRef, useState, useSyncExternalStore, type MouseEvent, type PointerEvent } from 'react';
|
|
2
2
|
import { useTranslation } from 'react-i18next';
|
|
3
3
|
import clsx from 'clsx';
|
|
4
4
|
import { ChevronDown } from 'lucide-react';
|
|
@@ -35,6 +35,7 @@ import { useCompactionOffer } from './composer/use-compaction-offer';
|
|
|
35
35
|
import { useComposerDraft } from './composer/use-composer-draft';
|
|
36
36
|
import { useComposerMenus } from './composer/use-composer-menus';
|
|
37
37
|
import { useComposerSubmit } from './composer/use-composer-submit';
|
|
38
|
+
import { useEffortStepper } from './composer/use-effort-stepper';
|
|
38
39
|
import { LEAVE_DROPS_TO_THE_CARD, useDraftFiles } from './composer/use-draft-files';
|
|
39
40
|
import { useContinuableTurn } from './composer/use-continuable-turn';
|
|
40
41
|
import { useNotice } from './composer/use-notice';
|
|
@@ -43,6 +44,7 @@ import { usePromptHistory } from './composer/use-prompt-history';
|
|
|
43
44
|
import { usePromptHold } from './composer/use-prompt-hold';
|
|
44
45
|
import { surfacePartOf } from './composer/surface';
|
|
45
46
|
import { useTakeBack } from './composer/use-take-back';
|
|
47
|
+
import { useHostExtraPrompts, useHostSendDelivery } from '../../host-hooks';
|
|
46
48
|
|
|
47
49
|
interface ComposerProps {
|
|
48
50
|
chatId: string;
|
|
@@ -78,7 +80,7 @@ export function Composer({ chatId, info, focused, answerPromptsElsewhere, disabl
|
|
|
78
80
|
const { t } = useTranslation('agent-chat');
|
|
79
81
|
const host = useChatHost();
|
|
80
82
|
const scope = useChatScope();
|
|
81
|
-
const sendDelivery =
|
|
83
|
+
const sendDelivery = useHostSendDelivery();
|
|
82
84
|
const sendKey = useChatPreferences((preferences) => preferences.sendKey);
|
|
83
85
|
const provider = useProviders((row) => row.providers.find((entry) => entry.kind === info.provider));
|
|
84
86
|
// Absent until the host answered `provider.list`, so only an explicit false hides anything.
|
|
@@ -96,11 +98,19 @@ export function Composer({ chatId, info, focused, answerPromptsElsewhere, disabl
|
|
|
96
98
|
const menus = useComposerMenus({ chatId, info, capabilities, providerName: provider?.name, draft: box, inputRef });
|
|
97
99
|
const files = useDraftFiles({ capabilities, providerName: provider?.name, writable, draft: box, inputRef, setNotice: notice.setNotice });
|
|
98
100
|
const controls = useChatControls({ chatId, info, notice, onRetarget });
|
|
101
|
+
useEffortStepper({
|
|
102
|
+
chatId,
|
|
103
|
+
info,
|
|
104
|
+
model: provider?.models.find((entry) => entry.slug === info.selection.model),
|
|
105
|
+
writable,
|
|
106
|
+
controls,
|
|
107
|
+
setNotice: notice.setNotice
|
|
108
|
+
});
|
|
99
109
|
const guard = promptGuard(withQuote(draft.quote, draft.text));
|
|
100
110
|
const continuable = useContinuableTurn(chatId, info);
|
|
101
111
|
// The stopped turn something went out for, since the chat takes a moment to answer and Continue must not stand there meanwhile.
|
|
102
112
|
const [sentFor, setSentFor] = useState<string | null>(null);
|
|
103
|
-
const extraPrompts =
|
|
113
|
+
const extraPrompts = useHostExtraPrompts(scope.id, chatId);
|
|
104
114
|
const { submit, continueTurn, restoreStashed, toggleStash } = useComposerSubmit({
|
|
105
115
|
chatId,
|
|
106
116
|
writable,
|
|
@@ -144,10 +154,7 @@ export function Composer({ chatId, info, focused, answerPromptsElsewhere, disabl
|
|
|
144
154
|
const pending = usePendingRequests(chatId);
|
|
145
155
|
const compactionOffer = useCompactionOffer(chatId, info, capabilities?.compaction);
|
|
146
156
|
const placeholder = useHintedPlaceholder({ chatId, disabled, readOnly, mentionable: capabilities?.mentions !== false, hasSkills: menus.hasSkills });
|
|
147
|
-
const editorExtensions =
|
|
148
|
-
() => [chipDecorations({ mentions: draft.mentions, skills: draft.skills }), LEAVE_DROPS_TO_THE_CARD],
|
|
149
|
-
[draft.mentions, draft.skills]
|
|
150
|
-
);
|
|
157
|
+
const editorExtensions = [chipDecorations({ mentions: draft.mentions, skills: draft.skills }), LEAVE_DROPS_TO_THE_CARD];
|
|
151
158
|
/* The timeline owns the scroller; this is the one bit of it the composer needs to know. */
|
|
152
159
|
const atEnd = useSyncExternalStore(
|
|
153
160
|
subscribeTimelineEnd,
|
|
@@ -232,6 +239,7 @@ export function Composer({ chatId, info, focused, answerPromptsElsewhere, disabl
|
|
|
232
239
|
{compactionOffer && (
|
|
233
240
|
<ResumeCompactionDock
|
|
234
241
|
tokens={compactionOffer.tokens}
|
|
242
|
+
reason={compactionOffer.reason}
|
|
235
243
|
onCompact={controls.compact}
|
|
236
244
|
onDismiss={() => dismissResumeCompaction(scope, chatId, compactionOffer.turnId)}
|
|
237
245
|
/>
|
package/src/chat/ui/EditDiff.tsx
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { useMemo } from 'react';
|
|
2
1
|
import { LazyBoundary } from '@adecore/ui';
|
|
3
2
|
import { useTranslation } from 'react-i18next';
|
|
4
3
|
import { lazyNamed } from '../../lazy';
|
|
@@ -17,9 +16,9 @@ export default function EditDiff({ change, allowEditor = true, maxHeight }: { ch
|
|
|
17
16
|
const host = useChatHost();
|
|
18
17
|
const { t } = useTranslation('agent-chat');
|
|
19
18
|
const loadEngine = host.code.editor;
|
|
20
|
-
const sourceAllowed =
|
|
19
|
+
const sourceAllowed = diffSourceBudget(change.before, change.after);
|
|
21
20
|
const legacyMode = !allowEditor || loadEngine === undefined;
|
|
22
|
-
const legacyAllowed =
|
|
21
|
+
const legacyAllowed = legacyMode && legacyDiffBudget(change.before, change.after);
|
|
23
22
|
const omitted = <DiffOmitted path={change.path} />;
|
|
24
23
|
const fallback = legacyAllowed ? (
|
|
25
24
|
<DiffFallbackBoundary fallback={omitted} resetKeys={[change.path, change.before, change.after]}>
|
|
@@ -14,6 +14,7 @@ import { useChatHost } from '../../host';
|
|
|
14
14
|
import { useChatScope, type ChatScope } from '../../scope';
|
|
15
15
|
import { useChatActions } from '../actions';
|
|
16
16
|
import { useUsageStore } from '../../state/usage';
|
|
17
|
+
import { useHostResumeAtReset } from '../../host-hooks';
|
|
17
18
|
|
|
18
19
|
// A time a limit names reads as a clock today and with its day after that, so the words follow the minute.
|
|
19
20
|
const MINUTE_MS = 60_000;
|
|
@@ -43,11 +44,10 @@ function readUnreadAccounts(scope: ChatScope): void {
|
|
|
43
44
|
* switch off it stands off and says where that switch is.
|
|
44
45
|
*/
|
|
45
46
|
function ResumeAtResetToggle({ chatId, info }: { chatId: string; info: ChatInfo }) {
|
|
46
|
-
const host = useChatHost();
|
|
47
47
|
const { t } = useTranslation('agent-chat');
|
|
48
48
|
const { id } = useChatScope();
|
|
49
49
|
const actions = useChatActions();
|
|
50
|
-
const machineAllows =
|
|
50
|
+
const machineAllows = useHostResumeAtReset(id);
|
|
51
51
|
const set = (on: boolean): void => {
|
|
52
52
|
void actions.configure(chatId, { resumeAtReset: on }).catch(() => undefined);
|
|
53
53
|
};
|
package/src/chat/ui/Markdown.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createContext, memo, useContext,
|
|
1
|
+
import { createContext, memo, useContext, type ReactNode } from 'react';
|
|
2
2
|
import clsx from 'clsx';
|
|
3
3
|
import { Zap } from 'lucide-react';
|
|
4
4
|
import ReactMarkdown, { type Components, type ExtraProps, type Options } from 'react-markdown';
|
|
@@ -85,7 +85,7 @@ function languageOf(className: string | undefined): string {
|
|
|
85
85
|
return /language-([\w-]+)/.exec(className ?? '')?.[1] ?? 'text';
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
const INLINE_CODE = 'rounded-sm bg-surface-sunken px-1 py-px font-mono text-code';
|
|
88
|
+
const INLINE_CODE = 'rounded-sm bg-surface-sunken px-1 py-px font-mono text-code box-decoration-clone';
|
|
89
89
|
|
|
90
90
|
/*
|
|
91
91
|
* A path an agent wrote down. It keeps the shape of the code chip it would otherwise be, so a sentence
|
|
@@ -99,7 +99,7 @@ function FileLink({ target, className, children }: { target: FileRef; className?
|
|
|
99
99
|
// A button is not selectable on its own, and a thread is copied as often as it is clicked.
|
|
100
100
|
<button
|
|
101
101
|
type="button"
|
|
102
|
-
className={clsx('cursor-pointer select-text', className)}
|
|
102
|
+
className={clsx('cursor-pointer select-text text-left', className)}
|
|
103
103
|
data-file-path={target.path}
|
|
104
104
|
data-file-line={target.line}
|
|
105
105
|
data-file-column={target.column}
|
|
@@ -121,8 +121,10 @@ function InlineCode({ text }: { text: string }) {
|
|
|
121
121
|
return <code className={INLINE_CODE}>{text}</code>;
|
|
122
122
|
}
|
|
123
123
|
return (
|
|
124
|
-
|
|
125
|
-
|
|
124
|
+
// The chip sits on a code inside the button, since a button is always a box of its own and its
|
|
125
|
+
// background would fill the whole box once a long path wraps.
|
|
126
|
+
<FileLink target={target} className="text-accent">
|
|
127
|
+
<code className={clsx(INLINE_CODE, 'hover:underline')}>{text}</code>
|
|
126
128
|
</FileLink>
|
|
127
129
|
);
|
|
128
130
|
}
|
|
@@ -393,7 +395,7 @@ export const ReplyMarkdown = memo(function ReplyMarkdown({
|
|
|
393
395
|
arriving?: boolean;
|
|
394
396
|
reply?: ShellCodeBlockReply;
|
|
395
397
|
}) {
|
|
396
|
-
const blocks =
|
|
398
|
+
const blocks = splitMarkdownBlocks(text);
|
|
397
399
|
return (
|
|
398
400
|
<div className="chat-markdown prose prose-sm max-w-none text-sm" data-arriving={arriving || undefined}>
|
|
399
401
|
{blocks.map((block, index) =>
|
|
@@ -420,7 +422,7 @@ export const ReplyMarkdown = memo(function ReplyMarkdown({
|
|
|
420
422
|
* it was, and the files and skills picked in the composer are chips again.
|
|
421
423
|
*/
|
|
422
424
|
export const MessageMarkdown = memo(function MessageMarkdown({ text, mentions, skills }: { text: string; mentions?: string[]; skills?: string[] }) {
|
|
423
|
-
const rehypePlugins
|
|
425
|
+
const rehypePlugins: [typeof rehypeChips, ChipOptions][] = [[rehypeChips, { mentions, skills }]];
|
|
424
426
|
return (
|
|
425
427
|
<div className="chat-markdown prose prose-sm max-w-none text-sm">
|
|
426
428
|
<ReactMarkdown remarkPlugins={MESSAGE_PLUGINS} rehypePlugins={rehypePlugins} components={messageComponents}>
|
|
@@ -449,7 +451,7 @@ export const Markdown = memo(function Markdown({
|
|
|
449
451
|
rehypePlugins?: Options['rehypePlugins'];
|
|
450
452
|
componentOverrides?: Components;
|
|
451
453
|
}) {
|
|
452
|
-
const renderComponents =
|
|
454
|
+
const renderComponents = { ...(fileLinks ? components : plainComponents), ...componentOverrides };
|
|
453
455
|
return (
|
|
454
456
|
<div className="chat-markdown prose prose-sm max-w-none text-sm" data-muted={muted || undefined}>
|
|
455
457
|
<ReactMarkdown remarkPlugins={breaks ? PLUGINS_WITH_BREAKS : PLUGINS} rehypePlugins={rehypePlugins} components={renderComponents}>
|
|
@@ -2,20 +2,23 @@ import { useContext, useEffect, useId, useRef, useState } from 'react';
|
|
|
2
2
|
import { useTranslation } from 'react-i18next';
|
|
3
3
|
import { Code, Workflow } from 'lucide-react';
|
|
4
4
|
import { IconButton } from '@adecore/ui';
|
|
5
|
-
import { useChatHost } from '../../host';
|
|
6
5
|
import { CodeBlock } from './CodeBlock';
|
|
7
6
|
import { CodeStreamingContext } from './code-streaming';
|
|
8
|
-
import {
|
|
7
|
+
import { DIAGRAM_TOKENS, GROUND_TOKEN, renderOptions, svgDataUrl, themedSvg, type DiagramFont } from './mermaid';
|
|
9
8
|
import { watchTheme } from './theme-watch';
|
|
9
|
+
import { useHostCodeMode } from '../../host-hooks';
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
interface LaidOut {
|
|
12
|
+
svg: string;
|
|
13
|
+
width: number;
|
|
14
|
+
height: number;
|
|
15
|
+
}
|
|
12
16
|
|
|
13
|
-
|
|
14
|
-
let queue: Promise<unknown> = Promise.resolve();
|
|
17
|
+
type Drawing = { state: 'drawing' } | { state: 'drawn'; image: LaidOut } | { state: 'failed' };
|
|
15
18
|
|
|
16
19
|
let probeCanvas: HTMLCanvasElement | null = null;
|
|
17
20
|
|
|
18
|
-
/* A token as an opaque `#rrggbb` over `ground`,
|
|
21
|
+
/* A token as an opaque `#rrggbb` over `ground`, so a border with an alpha mixes with the ground and not with what is under the image. */
|
|
19
22
|
function resolveColor(element: HTMLElement, token: string, ground: string): string {
|
|
20
23
|
probeCanvas ??= document.createElement('canvas');
|
|
21
24
|
probeCanvas.width = 1;
|
|
@@ -33,47 +36,58 @@ function resolveColor(element: HTMLElement, token: string, ground: string): stri
|
|
|
33
36
|
return `#${[red, green, blue].map((channel) => channel!.toString(16).padStart(2, '0')).join('')}`;
|
|
34
37
|
}
|
|
35
38
|
|
|
36
|
-
function themeColors(element: HTMLElement): MermaidColors {
|
|
37
|
-
const ground = resolveColor(element, MERMAID_TOKENS.ground, '#808080');
|
|
38
|
-
const entries = Object.entries(MERMAID_TOKENS).map(([name, token]) => [name, name === 'ground' ? ground : resolveColor(element, token, ground)]);
|
|
39
|
-
return Object.fromEntries(entries) as unknown as MermaidColors;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
39
|
/* What a diagram reads of the theme where it stands. */
|
|
43
40
|
interface DiagramLook {
|
|
44
|
-
colors:
|
|
45
|
-
font:
|
|
41
|
+
colors: Record<string, string>;
|
|
42
|
+
font: DiagramFont;
|
|
46
43
|
}
|
|
47
44
|
|
|
48
45
|
function diagramLook(element: HTMLElement): DiagramLook {
|
|
49
46
|
const style = getComputedStyle(element);
|
|
50
|
-
|
|
47
|
+
const ground = resolveColor(element, GROUND_TOKEN, '#808080');
|
|
48
|
+
const colors = Object.fromEntries(
|
|
49
|
+
Object.entries(DIAGRAM_TOKENS).map(([name, token]) => [name, token === GROUND_TOKEN ? ground : resolveColor(element, token, ground)])
|
|
50
|
+
);
|
|
51
|
+
const font = {
|
|
52
|
+
family: style.fontFamily,
|
|
53
|
+
mono: style.getPropertyValue('--font-mono').trim() || 'monospace',
|
|
54
|
+
size: Number.parseFloat(style.fontSize) || 14
|
|
55
|
+
};
|
|
56
|
+
return { colors, font };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/* Keeps the look on screen when nothing of it changed, so a change of the root that leaves every color alone draws nothing again. */
|
|
60
|
+
function keepingSame(next: DiagramLook) {
|
|
61
|
+
return (current: DiagramLook | null) => (current !== null && JSON.stringify(current) === JSON.stringify(next) ? current : next);
|
|
51
62
|
}
|
|
52
63
|
|
|
53
|
-
async function
|
|
54
|
-
const {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
return sizedSvg(svg);
|
|
64
|
+
async function layOut(id: string, source: string, font: DiagramFont): Promise<LaidOut> {
|
|
65
|
+
const { renderAsync } = await import('pele/lazy');
|
|
66
|
+
const { svg, width, height } = await renderAsync(source, renderOptions(font, id));
|
|
67
|
+
return { svg, width: Math.ceil(width), height: Math.ceil(height) };
|
|
58
68
|
}
|
|
59
69
|
|
|
60
70
|
/*
|
|
61
|
-
* A ```mermaid fence, drawn as the diagram once the fence is closed.
|
|
62
|
-
*
|
|
63
|
-
* draw, it is the code block it would otherwise be.
|
|
71
|
+
* A ```mermaid fence, drawn as the diagram once the fence is closed. Pele loads on the first diagram of the
|
|
72
|
+
* page, and then only what a diagram of that kind needs. While the fence grows, and when the text is no diagram
|
|
73
|
+
* Pele can draw, it is the code block it would otherwise be.
|
|
64
74
|
*/
|
|
65
75
|
export function MermaidBlock({ code }: { code: string }) {
|
|
66
|
-
const host = useChatHost();
|
|
67
76
|
const { t } = useTranslation('agent-chat');
|
|
68
77
|
const streaming = useContext(CodeStreamingContext);
|
|
69
|
-
const dark =
|
|
78
|
+
const dark = useHostCodeMode() === 'dark';
|
|
70
79
|
const id = `mermaid-${useId().replace(/[^\w-]/g, '')}`;
|
|
71
80
|
const frame = useRef<HTMLDivElement>(null);
|
|
72
81
|
const [source, setSource] = useState(false);
|
|
73
82
|
const [drawing, setDrawing] = useState<Drawing>({ state: 'drawing' });
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
83
|
+
const [look, setLook] = useState<DiagramLook | null>(null);
|
|
84
|
+
|
|
85
|
+
useEffect(() => {
|
|
86
|
+
const element = frame.current;
|
|
87
|
+
if (element !== null) {
|
|
88
|
+
setLook(keepingSame(diagramLook(element)));
|
|
89
|
+
}
|
|
90
|
+
}, [dark]);
|
|
77
91
|
|
|
78
92
|
// An app may change its colors without turning light or dark, which only the root of the page tells.
|
|
79
93
|
useEffect(() => {
|
|
@@ -81,34 +95,28 @@ export function MermaidBlock({ code }: { code: string }) {
|
|
|
81
95
|
if (element === null) {
|
|
82
96
|
return;
|
|
83
97
|
}
|
|
84
|
-
return watchTheme(element.ownerDocument, () =>
|
|
85
|
-
if (drawnLook.current !== null && JSON.stringify(diagramLook(element)) !== drawnLook.current) {
|
|
86
|
-
setThemeRevision((revision) => revision + 1);
|
|
87
|
-
}
|
|
88
|
-
});
|
|
98
|
+
return watchTheme(element.ownerDocument, () => setLook(keepingSame(diagramLook(element))));
|
|
89
99
|
}, []);
|
|
90
100
|
|
|
101
|
+
const fontFamily = look?.font.family;
|
|
102
|
+
const fontMono = look?.font.mono;
|
|
103
|
+
const fontSize = look?.font.size;
|
|
91
104
|
useEffect(() => {
|
|
92
|
-
|
|
93
|
-
if (streaming || element === null) {
|
|
105
|
+
if (streaming || fontFamily === undefined || fontMono === undefined || fontSize === undefined) {
|
|
94
106
|
return;
|
|
95
107
|
}
|
|
96
108
|
let cancelled = false;
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
setDrawing((current) => (current.state === 'drawn' ? current : { state: 'drawing' }));
|
|
101
|
-
const drawn = queue.then(() => (cancelled ? null : drawDiagram(id, code, look, dark)));
|
|
102
|
-
queue = drawn.catch(() => undefined);
|
|
103
|
-
drawn.then(
|
|
104
|
-
(image) => !cancelled && setDrawing(image === null ? { state: 'failed' } : { state: 'drawn', image }),
|
|
109
|
+
// A diagram already drawn stays until the next one is there, so it does not blink.
|
|
110
|
+
layOut(id, code, { family: fontFamily, mono: fontMono, size: fontSize }).then(
|
|
111
|
+
(image) => !cancelled && setDrawing({ state: 'drawn', image }),
|
|
105
112
|
() => !cancelled && setDrawing({ state: 'failed' })
|
|
106
113
|
);
|
|
107
114
|
return () => {
|
|
108
115
|
cancelled = true;
|
|
109
116
|
};
|
|
110
|
-
}, [code,
|
|
117
|
+
}, [code, fontFamily, fontMono, fontSize, id, streaming]);
|
|
111
118
|
|
|
119
|
+
const image = drawing.state === 'drawn' && look !== null ? { ...drawing.image, svg: themedSvg(drawing.image.svg, look.colors) } : null;
|
|
112
120
|
const showsDiagram = !streaming && !source && drawing.state !== 'failed';
|
|
113
121
|
const toggle =
|
|
114
122
|
streaming || drawing.state === 'failed' ? undefined : (
|
|
@@ -128,12 +136,12 @@ export function MermaidBlock({ code }: { code: string }) {
|
|
|
128
136
|
actions={toggle}
|
|
129
137
|
view={
|
|
130
138
|
showsDiagram ? (
|
|
131
|
-
<div className="overflow-x-auto p-3" aria-busy={
|
|
132
|
-
{
|
|
139
|
+
<div className="overflow-x-auto p-3" aria-busy={image === null || undefined}>
|
|
140
|
+
{image !== null && (
|
|
133
141
|
<img
|
|
134
|
-
src={svgDataUrl(
|
|
135
|
-
width={
|
|
136
|
-
height={
|
|
142
|
+
src={svgDataUrl(image.svg)}
|
|
143
|
+
width={image.width}
|
|
144
|
+
height={image.height}
|
|
137
145
|
alt={t('code.mermaid.diagram')}
|
|
138
146
|
className="m-0 max-w-none"
|
|
139
147
|
draggable={false}
|
package/src/chat/ui/Pickers.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { useContext, useEffect,
|
|
1
|
+
import { useContext, useEffect, useRef, useState, type ReactNode, type RefObject } from 'react';
|
|
2
2
|
import { useTranslation } from 'react-i18next';
|
|
3
|
-
import { Bookmark, ChevronDown, ChevronRight, Search, Trash2 } from 'lucide-react';
|
|
3
|
+
import { Bookmark, ChevronDown, ChevronRight, Search, Star, Trash2 } from 'lucide-react';
|
|
4
4
|
import type { AgentKind, ModelSelection, ProviderInfo, UsageProvider } from '@adecore/agent-contracts';
|
|
5
5
|
import { AgentIcon } from '../../agents/AgentIcon';
|
|
6
6
|
import { ProviderLogo } from '../../agents/ProviderLogo';
|
|
@@ -11,8 +11,10 @@ import { ChatScopeContext } from '../../scope';
|
|
|
11
11
|
import { useReportedModels } from '../../state/chats';
|
|
12
12
|
import { ModelMarks } from './ModelMarks';
|
|
13
13
|
import { pickerEntriesOf, type PickerEntry } from '../logic/picker-entries';
|
|
14
|
+
import { favoriteModelsOf, toggleFavoriteModel, useChatPreferences } from '../preferences';
|
|
14
15
|
import { forgetStashed, STASH_SHORTCUT, useStash, type StashedPrompt } from '../stash';
|
|
15
16
|
import { Icon, IconButton, Menu, Popover, Tooltip } from '@adecore/ui';
|
|
17
|
+
import { useHostMachineLabel } from '../../host-hooks';
|
|
16
18
|
|
|
17
19
|
const triggerClass =
|
|
18
20
|
'flex h-7 shrink-0 items-center gap-1 whitespace-nowrap rounded-md px-2 text-xs text-text-muted hover:bg-surface-hover hover:text-text data-[popup-open]:bg-surface-active data-[popup-open]:text-text';
|
|
@@ -74,12 +76,13 @@ export function ModelPicker({
|
|
|
74
76
|
const grouped = providers.length > 1;
|
|
75
77
|
const trimmed = query.trim().toLowerCase();
|
|
76
78
|
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
|
|
79
|
+
const favorites = useChatPreferences((preferences) => preferences.favoriteModels);
|
|
80
|
+
const starredHere = (row: PickerEntry | undefined): boolean => row?.kind === 'model' && favorites[row.provider.kind]?.includes(row.model.slug) === true;
|
|
81
|
+
const entries = pickerEntriesOf(providers, trimmed, legacyOpen, expanded, { provider, model: selection.model }, (kind) =>
|
|
82
|
+
favoriteModelsOf(favorites, kind)
|
|
80
83
|
);
|
|
81
84
|
const scope = useContext(ChatScopeContext);
|
|
82
|
-
const machine =
|
|
85
|
+
const machine = useHostMachineLabel(scope?.id ?? '');
|
|
83
86
|
const reported = useReportedModels(provider);
|
|
84
87
|
const requirementOf = (entry: PickerEntry & { kind: 'model' }) => modelRequirementOf(entry.model, entry.provider, reported);
|
|
85
88
|
// A CLI that is too old blocks all its models; one way to its settings under the group says it once.
|
|
@@ -226,17 +229,21 @@ export function ModelPicker({
|
|
|
226
229
|
const first = grouped && (previous === undefined || previous.kind === 'legacy' || previous.provider.kind !== entry.provider.kind);
|
|
227
230
|
// The makers read as groups only where the whole list is shown, so a short list is not cut by labels.
|
|
228
231
|
const vendorOpen = trimmed !== '' || expanded.has(entry.provider.kind);
|
|
232
|
+
// The starred rows lead their CLI without a maker's label; the makers start after them.
|
|
229
233
|
const vendorFirst =
|
|
230
234
|
vendorOpen &&
|
|
231
235
|
entry.model.vendor !== undefined &&
|
|
236
|
+
!starredHere(entry) &&
|
|
232
237
|
(previous === undefined ||
|
|
233
238
|
previous.kind !== 'model' ||
|
|
234
239
|
previous.provider.kind !== entry.provider.kind ||
|
|
240
|
+
starredHere(previous) ||
|
|
235
241
|
previous.model.vendor !== entry.model.vendor);
|
|
236
242
|
const requirement = requirementOf(entry);
|
|
237
243
|
const next = entries[i + 1];
|
|
238
244
|
const lastOfGroup = next === undefined || next.kind !== 'model' || next.provider.kind !== entry.provider.kind;
|
|
239
245
|
const chosen = entry.provider.kind === provider && entry.model.slug === selection.model;
|
|
246
|
+
const starred = starredHere(entry);
|
|
240
247
|
return (
|
|
241
248
|
<div key={`${entry.provider.kind}/${entry.model.slug}`}>
|
|
242
249
|
{first && (
|
|
@@ -246,30 +253,43 @@ export function ModelPicker({
|
|
|
246
253
|
</Menu.Label>
|
|
247
254
|
)}
|
|
248
255
|
{vendorFirst && <Menu.Label>{entry.model.vendor}</Menu.Label>}
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
<span className="
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
{machine === null
|
|
268
|
-
? t('pickers.model.requiresHere', { cli: requirement.cli, version: requirement.minVersion })
|
|
269
|
-
: t('pickers.model.requires', { cli: requirement.cli, version: requirement.minVersion, machine })}
|
|
256
|
+
{/* The star sits beside the option rather than in it, since a button holds no other button. */}
|
|
257
|
+
<div className="flex items-start gap-0.5">
|
|
258
|
+
<button
|
|
259
|
+
role="option"
|
|
260
|
+
aria-selected={chosen}
|
|
261
|
+
aria-disabled={requirement !== null || undefined}
|
|
262
|
+
data-active={i === index}
|
|
263
|
+
className={`cursor-row flex min-w-0 grow flex-col items-stretch gap-0.5 rounded-md px-2.5 py-1.5 text-left text-sm ${requirement === null ? 'text-text-muted' : 'text-text-faint'}`}
|
|
264
|
+
onMouseEnter={() => setIndex(i)}
|
|
265
|
+
onClick={() => choose(entry)}
|
|
266
|
+
>
|
|
267
|
+
<span className="flex w-full items-center gap-2">
|
|
268
|
+
<Menu.Check kind="radio" checked={chosen} />
|
|
269
|
+
{/* Wrapped rather than cut, so a long name a provider gives is read whole. */}
|
|
270
|
+
<span className="min-w-0 break-words">{entry.model.name}</span>
|
|
271
|
+
<ModelMarks model={entry.model} />
|
|
272
|
+
<span className="grow" />
|
|
273
|
+
{entry.model.legacy && <span className="text-xs text-text-faint">{t('pickers.model.legacy')}</span>}
|
|
270
274
|
</span>
|
|
271
|
-
|
|
272
|
-
|
|
275
|
+
{requirement !== null && (
|
|
276
|
+
<span className="pl-6 text-xs text-text-faint">
|
|
277
|
+
{machine === null
|
|
278
|
+
? t('pickers.model.requiresHere', { cli: requirement.cli, version: requirement.minVersion })
|
|
279
|
+
: t('pickers.model.requires', { cli: requirement.cli, version: requirement.minVersion, machine })}
|
|
280
|
+
</span>
|
|
281
|
+
)}
|
|
282
|
+
</button>
|
|
283
|
+
<IconButton
|
|
284
|
+
icon={Star}
|
|
285
|
+
size="sm"
|
|
286
|
+
label={starred ? t('pickers.model.unstar') : t('pickers.model.star')}
|
|
287
|
+
aria-pressed={starred}
|
|
288
|
+
iconClassName={starred ? 'fill-current text-accent' : undefined}
|
|
289
|
+
className="mt-0.5 shrink-0"
|
|
290
|
+
onClick={() => toggleFavoriteModel(entry.provider.kind, entry.model.slug)}
|
|
291
|
+
/>
|
|
292
|
+
</div>
|
|
273
293
|
{lastOfGroup && blockedKinds.has(entry.provider.kind) && (
|
|
274
294
|
<button
|
|
275
295
|
type="button"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useEffect,
|
|
1
|
+
import { useEffect, useRef, type ReactNode } from 'react';
|
|
2
2
|
import { useTranslation } from 'react-i18next';
|
|
3
3
|
import { ArrowDown, Hand, MessageCircleQuestionMark } from 'lucide-react';
|
|
4
4
|
import type { HoldRelease } from '../prompt-hold';
|
|
@@ -12,6 +12,7 @@ import { useChatHost } from '../../host';
|
|
|
12
12
|
import { useChatScope } from '../../scope';
|
|
13
13
|
import { useChatActions } from '../actions';
|
|
14
14
|
import { Button, Icon } from '@adecore/ui';
|
|
15
|
+
import { useHostExtraPrompts } from '../../host-hooks';
|
|
15
16
|
|
|
16
17
|
/* Keeps a prompt card behind the draft while the person types; `released` says what lifted the hold last. */
|
|
17
18
|
export interface PromptHold {
|
|
@@ -57,14 +58,11 @@ export function PromptComposer({
|
|
|
57
58
|
const actions = useChatActions();
|
|
58
59
|
const elsewhere = onShowElsewhere !== undefined;
|
|
59
60
|
// A card the app raises itself waits in the chat beside the CLI's own requests.
|
|
60
|
-
const extra =
|
|
61
|
-
const subjects =
|
|
62
|
-
(): PromptSubject
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
],
|
|
66
|
-
[pending, extra, chatId]
|
|
67
|
-
);
|
|
61
|
+
const extra = useHostExtraPrompts(id, chatId);
|
|
62
|
+
const subjects: PromptSubject[] = [
|
|
63
|
+
...pending.map((item): PromptSubject => ({ kind: 'chat', nodeId: chatId, item })),
|
|
64
|
+
...extra.map((prompt): PromptSubject => ({ kind: 'host', nodeId: chatId, prompt }))
|
|
65
|
+
];
|
|
68
66
|
const session = usePromptSession({ prompts: subjects, idOf: promptIdOf, pick: pickSubject, disabled });
|
|
69
67
|
const ref = useRef<HTMLDivElement>(null);
|
|
70
68
|
const { active, activeId: activeKey } = session;
|