@adecore/agents-react 0.0.1 → 0.17.0-beta.2
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/LICENSE +110 -0
- package/README.md +61 -0
- package/dist/agents/AccountDot.d.ts +4 -0
- package/dist/agents/AccountDot.js +8 -0
- package/dist/agents/AgentIcon.d.ts +6 -0
- package/dist/agents/AgentIcon.js +20 -0
- package/dist/agents/ModelOptionControl.d.ts +15 -0
- package/dist/agents/ModelOptionControl.js +33 -0
- package/dist/agents/ProviderLogo.d.ts +8 -0
- package/dist/agents/ProviderLogo.js +8 -0
- package/dist/agents/account-limits.d.ts +7 -0
- package/dist/agents/account-limits.js +40 -0
- package/dist/agents/accounts.d.ts +22 -0
- package/dist/agents/accounts.js +113 -0
- package/dist/agents/model-name.d.ts +12 -0
- package/dist/agents/model-name.js +56 -0
- package/dist/agents/model-options.d.ts +5 -0
- package/dist/agents/model-options.js +15 -0
- package/dist/agents/provider-paths.d.ts +2 -0
- package/dist/agents/provider-paths.js +8 -0
- package/dist/agents/status-look.d.ts +13 -0
- package/dist/agents/status-look.js +24 -0
- package/dist/chat/account-choice.d.ts +11 -0
- package/dist/chat/account-choice.js +30 -0
- package/dist/chat/actions.d.ts +6 -0
- package/dist/chat/actions.js +68 -0
- package/dist/chat/activity.d.ts +5 -0
- package/dist/chat/activity.js +6 -0
- package/dist/chat/attachments.d.ts +23 -0
- package/dist/chat/attachments.js +86 -0
- package/dist/chat/bookmarks.d.ts +14 -0
- package/dist/chat/bookmarks.js +73 -0
- package/dist/chat/chat-client.d.ts +55 -0
- package/dist/chat/chat-client.js +279 -0
- package/dist/chat/chat-references.d.ts +5 -0
- package/dist/chat/chat-references.js +5 -0
- package/dist/chat/drafts.d.ts +29 -0
- package/dist/chat/drafts.js +116 -0
- package/dist/chat/forks.d.ts +2 -0
- package/dist/chat/forks.js +28 -0
- package/dist/chat/guards.d.ts +12 -0
- package/dist/chat/guards.js +69 -0
- package/dist/chat/logic/ansi.d.ts +13 -0
- package/dist/chat/logic/ansi.js +185 -0
- package/dist/chat/logic/answers.d.ts +1 -0
- package/dist/chat/logic/answers.js +8 -0
- package/dist/chat/logic/bookmarks.d.ts +5 -0
- package/dist/chat/logic/bookmarks.js +33 -0
- package/dist/chat/logic/context-usage.d.ts +12 -0
- package/dist/chat/logic/context-usage.js +21 -0
- package/dist/chat/logic/fork.d.ts +45 -0
- package/dist/chat/logic/fork.js +148 -0
- package/dist/chat/logic/handback.d.ts +2 -0
- package/dist/chat/logic/handback.js +8 -0
- package/dist/chat/logic/json.d.ts +1 -0
- package/dist/chat/logic/json.js +4 -0
- package/dist/chat/logic/limit.d.ts +7 -0
- package/dist/chat/logic/limit.js +34 -0
- package/dist/chat/logic/resume-compaction.d.ts +14 -0
- package/dist/chat/logic/resume-compaction.js +47 -0
- package/dist/chat/logic/scrubber.d.ts +50 -0
- package/dist/chat/logic/scrubber.js +220 -0
- package/dist/chat/logic/thread-cards.d.ts +3 -0
- package/dist/chat/logic/thread-cards.js +59 -0
- package/dist/chat/logic/timeline-copy.d.ts +4 -0
- package/dist/chat/logic/timeline-copy.js +59 -0
- package/dist/chat/logic/timeline-target.d.ts +12 -0
- package/dist/chat/logic/timeline-target.js +34 -0
- package/dist/chat/logic/timeline.d.ts +115 -0
- package/dist/chat/logic/timeline.js +343 -0
- package/dist/chat/logic/tool-catalog.d.ts +10 -0
- package/dist/chat/logic/tool-catalog.js +44 -0
- package/dist/chat/logic/tools.d.ts +15 -0
- package/dist/chat/logic/tools.js +82 -0
- package/dist/chat/logic/welcome.d.ts +2 -0
- package/dist/chat/logic/welcome.js +10 -0
- package/dist/chat/logic/workflow.d.ts +14 -0
- package/dist/chat/logic/workflow.js +47 -0
- package/dist/chat/mentions.d.ts +65 -0
- package/dist/chat/mentions.js +184 -0
- package/dist/chat/persisted-json.d.ts +5 -0
- package/dist/chat/persisted-json.js +58 -0
- package/dist/chat/preferences.d.ts +27 -0
- package/dist/chat/preferences.js +139 -0
- package/dist/chat/quote.d.ts +2 -0
- package/dist/chat/quote.js +25 -0
- package/dist/chat/recent-messages.d.ts +17 -0
- package/dist/chat/recent-messages.js +36 -0
- package/dist/chat/resume-compaction-dismissals.d.ts +3 -0
- package/dist/chat/resume-compaction-dismissals.js +14 -0
- package/dist/chat/runtime-modes.d.ts +4 -0
- package/dist/chat/runtime-modes.js +15 -0
- package/dist/chat/stash.d.ts +24 -0
- package/dist/chat/stash.js +91 -0
- package/dist/chat/subagent-conversation.d.ts +41 -0
- package/dist/chat/subagent-conversation.js +167 -0
- package/dist/chat/subagent-list.d.ts +19 -0
- package/dist/chat/subagent-list.js +106 -0
- package/dist/chat/subagent-support.d.ts +6 -0
- package/dist/chat/subagent-support.js +14 -0
- package/dist/chat/subagent-view.d.ts +35 -0
- package/dist/chat/subagent-view.js +96 -0
- package/dist/chat/thumbnails.d.ts +10 -0
- package/dist/chat/thumbnails.js +89 -0
- package/dist/chat/timeline-flash.d.ts +12 -0
- package/dist/chat/timeline-flash.js +16 -0
- package/dist/chat/timeline-scroll.d.ts +27 -0
- package/dist/chat/timeline-scroll.js +152 -0
- package/dist/chat/ui/AccountPill.d.ts +3 -0
- package/dist/chat/ui/AccountPill.js +23 -0
- package/dist/chat/ui/AnsiOutput.d.ts +5 -0
- package/dist/chat/ui/AnsiOutput.js +9 -0
- package/dist/chat/ui/BookmarkMarker.d.ts +8 -0
- package/dist/chat/ui/BookmarkMarker.js +57 -0
- package/dist/chat/ui/BookmarkSubmenu.d.ts +3 -0
- package/dist/chat/ui/BookmarkSubmenu.js +33 -0
- package/dist/chat/ui/ChatActivity.d.ts +7 -0
- package/dist/chat/ui/ChatActivity.js +84 -0
- package/dist/chat/ui/ChatReferenceChip.d.ts +4 -0
- package/dist/chat/ui/ChatReferenceChip.js +16 -0
- package/dist/chat/ui/CodeBlock.d.ts +4 -0
- package/dist/chat/ui/CodeBlock.js +132 -0
- package/dist/chat/ui/Composer.d.ts +15 -0
- package/dist/chat/ui/Composer.js +856 -0
- package/dist/chat/ui/ComposerInput.d.ts +29 -0
- package/dist/chat/ui/ComposerInput.js +127 -0
- package/dist/chat/ui/DiffPool.d.ts +5 -0
- package/dist/chat/ui/DiffPool.js +26 -0
- package/dist/chat/ui/EditDiff.d.ts +4 -0
- package/dist/chat/ui/EditDiff.js +21 -0
- package/dist/chat/ui/FadingWords.d.ts +3 -0
- package/dist/chat/ui/FadingWords.js +5 -0
- package/dist/chat/ui/ImageView.d.ts +6 -0
- package/dist/chat/ui/ImageView.js +81 -0
- package/dist/chat/ui/LimitState.d.ts +8 -0
- package/dist/chat/ui/LimitState.js +112 -0
- package/dist/chat/ui/Markdown.d.ts +18 -0
- package/dist/chat/ui/Markdown.js +159 -0
- package/dist/chat/ui/MessageActions.d.ts +9 -0
- package/dist/chat/ui/MessageActions.js +53 -0
- package/dist/chat/ui/Pickers.d.ts +21 -0
- package/dist/chat/ui/Pickers.js +111 -0
- package/dist/chat/ui/PromptComposer.d.ts +13 -0
- package/dist/chat/ui/PromptComposer.js +56 -0
- package/dist/chat/ui/QuoteButton.d.ts +7 -0
- package/dist/chat/ui/QuoteButton.js +74 -0
- package/dist/chat/ui/ResumeCompactionDock.d.ts +5 -0
- package/dist/chat/ui/ResumeCompactionDock.js +14 -0
- package/dist/chat/ui/RunSettings.d.ts +28 -0
- package/dist/chat/ui/RunSettings.js +153 -0
- package/dist/chat/ui/Scrubber.d.ts +17 -0
- package/dist/chat/ui/Scrubber.js +118 -0
- package/dist/chat/ui/SubagentControls.d.ts +11 -0
- package/dist/chat/ui/SubagentControls.js +36 -0
- package/dist/chat/ui/SubagentInfo.d.ts +4 -0
- package/dist/chat/ui/SubagentInfo.js +34 -0
- package/dist/chat/ui/SubagentStopButton.d.ts +7 -0
- package/dist/chat/ui/SubagentStopButton.js +34 -0
- package/dist/chat/ui/SubagentTimeline.d.ts +4 -0
- package/dist/chat/ui/SubagentTimeline.js +107 -0
- package/dist/chat/ui/Timeline.d.ts +6 -0
- package/dist/chat/ui/Timeline.js +424 -0
- package/dist/chat/ui/TimelineMenu.d.ts +12 -0
- package/dist/chat/ui/TimelineMenu.js +54 -0
- package/dist/chat/ui/UnifiedDiff.d.ts +11 -0
- package/dist/chat/ui/UnifiedDiff.js +66 -0
- package/dist/chat/ui/UploadThumb.d.ts +4 -0
- package/dist/chat/ui/UploadThumb.js +11 -0
- package/dist/chat/ui/Welcome.d.ts +4 -0
- package/dist/chat/ui/Welcome.js +16 -0
- package/dist/chat/ui/chips.d.ts +4 -0
- package/dist/chat/ui/chips.js +11 -0
- package/dist/chat/ui/code-lines.d.ts +18 -0
- package/dist/chat/ui/code-lines.js +46 -0
- package/dist/chat/ui/code-streaming.d.ts +1 -0
- package/dist/chat/ui/code-streaming.js +3 -0
- package/dist/chat/ui/code-theme.d.ts +3 -0
- package/dist/chat/ui/code-theme.js +12 -0
- package/dist/chat/ui/composer/chips.d.ts +6 -0
- package/dist/chat/ui/composer/chips.js +31 -0
- package/dist/chat/ui/composer/editor.d.ts +11 -0
- package/dist/chat/ui/composer/editor.js +98 -0
- package/dist/chat/ui/composer/insert.d.ts +2 -0
- package/dist/chat/ui/composer/insert.js +19 -0
- package/dist/chat/ui/composer/keys.d.ts +30 -0
- package/dist/chat/ui/composer/keys.js +100 -0
- package/dist/chat/ui/diff-theme.d.ts +2 -0
- package/dist/chat/ui/diff-theme.js +20 -0
- package/dist/chat/ui/file-links.d.ts +5 -0
- package/dist/chat/ui/file-links.js +20 -0
- package/dist/chat/ui/find-reveal.d.ts +7 -0
- package/dist/chat/ui/find-reveal.js +13 -0
- package/dist/chat/ui/full-diff.d.ts +6 -0
- package/dist/chat/ui/full-diff.js +19 -0
- package/dist/chat/ui/icons.d.ts +4 -0
- package/dist/chat/ui/icons.js +20 -0
- package/dist/chat/ui/markdown-blocks.d.ts +6 -0
- package/dist/chat/ui/markdown-blocks.js +103 -0
- package/dist/chat/ui/quote-selection.d.ts +3 -0
- package/dist/chat/ui/quote-selection.js +46 -0
- package/dist/chat/ui/rehype-chips.d.ts +23 -0
- package/dist/chat/ui/rehype-chips.js +32 -0
- package/dist/chat/ui/rehype-fade.d.ts +23 -0
- package/dist/chat/ui/rehype-fade.js +36 -0
- package/dist/chat/ui/remark-html-as-text.d.ts +8 -0
- package/dist/chat/ui/remark-html-as-text.js +26 -0
- package/dist/chat/ui/reply-context.d.ts +5 -0
- package/dist/chat/ui/reply-context.js +2 -0
- package/dist/chat/ui/reveal.d.ts +13 -0
- package/dist/chat/ui/reveal.js +114 -0
- package/dist/chat/ui/rows/ForksRow.d.ts +4 -0
- package/dist/chat/ui/rows/ForksRow.js +38 -0
- package/dist/chat/ui/rows/MessageRows.d.ts +40 -0
- package/dist/chat/ui/rows/MessageRows.js +204 -0
- package/dist/chat/ui/rows/Rows.d.ts +12 -0
- package/dist/chat/ui/rows/Rows.js +61 -0
- package/dist/chat/ui/rows/SubagentRow.d.ts +17 -0
- package/dist/chat/ui/rows/SubagentRow.js +101 -0
- package/dist/chat/ui/rows/TaskRow.d.ts +8 -0
- package/dist/chat/ui/rows/TaskRow.js +63 -0
- package/dist/chat/ui/rows/WorkRows.d.ts +47 -0
- package/dist/chat/ui/rows/WorkRows.js +168 -0
- package/dist/chat/ui/rows/WorkflowRow.d.ts +8 -0
- package/dist/chat/ui/rows/WorkflowRow.js +48 -0
- package/dist/chat/ui/rows/row-rhythm.d.ts +6 -0
- package/dist/chat/ui/rows/row-rhythm.js +34 -0
- package/dist/chat/ui/useToggleSet.d.ts +6 -0
- package/dist/chat/ui/useToggleSet.js +25 -0
- package/dist/host.d.ts +195 -0
- package/dist/host.js +55 -0
- package/dist/lazy.d.ts +6 -0
- package/dist/lazy.js +57 -0
- package/dist/locales/en/agent-chat.json +446 -0
- package/dist/locales/en/agent-prompts.json +42 -0
- package/dist/locales/en/agent-providers.json +131 -0
- package/dist/locales/en/agent-usage.json +131 -0
- package/dist/locales/nl/agent-chat.json +446 -0
- package/dist/locales/nl/agent-prompts.json +42 -0
- package/dist/locales/nl/agent-providers.json +131 -0
- package/dist/locales/nl/agent-usage.json +131 -0
- package/dist/locales.d.ts +5 -0
- package/dist/locales.js +20 -0
- package/dist/mounted-registry.d.ts +7 -0
- package/dist/mounted-registry.js +39 -0
- package/dist/port-transport.d.ts +6 -0
- package/dist/port-transport.js +129 -0
- package/dist/prompts/logic/focus.d.ts +2 -0
- package/dist/prompts/logic/focus.js +23 -0
- package/dist/prompts/logic/keys.d.ts +42 -0
- package/dist/prompts/logic/keys.js +94 -0
- package/dist/prompts/logic/prompts.d.ts +34 -0
- package/dist/prompts/logic/prompts.fixtures.d.ts +5 -0
- package/dist/prompts/logic/prompts.fixtures.js +79 -0
- package/dist/prompts/logic/prompts.js +32 -0
- package/dist/prompts/logic/subjects.d.ts +50 -0
- package/dist/prompts/logic/subjects.js +63 -0
- package/dist/prompts/logic/useFocusAfterAnswer.d.ts +6 -0
- package/dist/prompts/logic/useFocusAfterAnswer.js +28 -0
- package/dist/prompts/logic/usePromptSession.d.ts +24 -0
- package/dist/prompts/logic/usePromptSession.js +87 -0
- package/dist/prompts/ui/ApprovalBody.d.ts +13 -0
- package/dist/prompts/ui/ApprovalBody.js +34 -0
- package/dist/prompts/ui/PromptActions.d.ts +27 -0
- package/dist/prompts/ui/PromptActions.js +18 -0
- package/dist/prompts/ui/PromptCard.d.ts +16 -0
- package/dist/prompts/ui/PromptCard.js +50 -0
- package/dist/prompts/ui/PromptView.d.ts +2 -0
- package/dist/prompts/ui/PromptView.js +47 -0
- package/dist/prompts/ui/QuestionBody.d.ts +9 -0
- package/dist/prompts/ui/QuestionBody.js +87 -0
- package/dist/providers/AccountColors.d.ts +5 -0
- package/dist/providers/AccountColors.js +8 -0
- package/dist/providers/AccountDetail.d.ts +12 -0
- package/dist/providers/AccountDetail.js +69 -0
- package/dist/providers/AccountVariables.d.ts +8 -0
- package/dist/providers/AccountVariables.js +43 -0
- package/dist/providers/AddAccountForm.d.ts +10 -0
- package/dist/providers/AddAccountForm.js +54 -0
- package/dist/providers/CliDetail.d.ts +12 -0
- package/dist/providers/CliDetail.js +54 -0
- package/dist/providers/ProvidersPane.d.ts +9 -0
- package/dist/providers/ProvidersPane.js +86 -0
- package/dist/providers/account-actions.d.ts +7 -0
- package/dist/providers/account-actions.js +57 -0
- package/dist/providers/parts.d.ts +9 -0
- package/dist/providers/parts.js +18 -0
- package/dist/providers/provider-abilities.d.ts +2 -0
- package/dist/providers/provider-abilities.js +7 -0
- package/dist/providers/variables.d.ts +13 -0
- package/dist/providers/variables.js +63 -0
- package/dist/scope.d.ts +11 -0
- package/dist/scope.js +10 -0
- package/dist/settings/sections.d.ts +13 -0
- package/dist/settings/sections.js +32 -0
- package/dist/state/chats.d.ts +44 -0
- package/dist/state/chats.js +199 -0
- package/dist/state/provider-accounts.d.ts +17 -0
- package/dist/state/provider-accounts.js +67 -0
- package/dist/state/providers.d.ts +17 -0
- package/dist/state/providers.js +33 -0
- package/dist/state/usage.d.ts +44 -0
- package/dist/state/usage.js +121 -0
- package/dist/storage.d.ts +20 -0
- package/dist/storage.js +89 -0
- package/dist/theme.css +212 -0
- package/dist/transport.d.ts +24 -0
- package/dist/transport.js +18 -0
- package/dist/ui/PlainTextarea.d.ts +2 -0
- package/dist/ui/PlainTextarea.js +5 -0
- package/dist/usage/LimitsList.d.ts +18 -0
- package/dist/usage/LimitsList.js +73 -0
- package/dist/usage/UsageBreakdown.d.ts +9 -0
- package/dist/usage/UsageBreakdown.js +67 -0
- package/dist/usage/UsageChart.d.ts +10 -0
- package/dist/usage/UsageChart.js +47 -0
- package/dist/usage/UsageDialog.d.ts +6 -0
- package/dist/usage/UsageDialog.js +12 -0
- package/dist/usage/UsageLimits.d.ts +1 -0
- package/dist/usage/UsageLimits.js +57 -0
- package/dist/usage/UsageLimitsCard.d.ts +4 -0
- package/dist/usage/UsageLimitsCard.js +26 -0
- package/dist/usage/UsagePage.d.ts +7 -0
- package/dist/usage/UsagePage.js +154 -0
- package/dist/usage/UsagePane.d.ts +3 -0
- package/dist/usage/UsagePane.js +21 -0
- package/dist/usage/UsageSummary.d.ts +12 -0
- package/dist/usage/UsageSummary.js +15 -0
- package/dist/usage/UsageTiles.d.ts +7 -0
- package/dist/usage/UsageTiles.js +19 -0
- package/dist/usage/format.d.ts +13 -0
- package/dist/usage/format.js +55 -0
- package/dist/usage/limit-groups.d.ts +22 -0
- package/dist/usage/limit-groups.js +86 -0
- package/dist/usage/limits.d.ts +4 -0
- package/dist/usage/limits.js +58 -0
- package/dist/usage/money.d.ts +1 -0
- package/dist/usage/money.js +13 -0
- package/dist/usage/summary.d.ts +34 -0
- package/dist/usage/summary.js +94 -0
- package/package.json +895 -3
- package/src/agents/AccountDot.tsx +14 -0
- package/src/agents/AgentIcon.tsx +26 -0
- package/src/agents/ModelOptionControl.tsx +68 -0
- package/src/agents/ProviderLogo.tsx +20 -0
- package/src/agents/account-limits.ts +61 -0
- package/src/agents/accounts.ts +137 -0
- package/src/agents/model-name.ts +70 -0
- package/src/agents/model-options.ts +21 -0
- package/src/agents/provider-paths.ts +10 -0
- package/src/agents/status-look.ts +43 -0
- package/src/chat/account-choice.ts +44 -0
- package/src/chat/actions.ts +72 -0
- package/src/chat/activity.ts +8 -0
- package/src/chat/attachments.ts +118 -0
- package/src/chat/bookmarks.ts +87 -0
- package/src/chat/chat-client.ts +345 -0
- package/src/chat/chat-references.ts +11 -0
- package/src/chat/drafts.ts +165 -0
- package/src/chat/forks.ts +33 -0
- package/src/chat/guards.ts +84 -0
- package/src/chat/logic/ansi.ts +206 -0
- package/src/chat/logic/answers.ts +8 -0
- package/src/chat/logic/bookmarks.ts +42 -0
- package/src/chat/logic/context-usage.ts +36 -0
- package/src/chat/logic/fork.ts +200 -0
- package/src/chat/logic/handback.ts +10 -0
- package/src/chat/logic/json.ts +4 -0
- package/src/chat/logic/limit.ts +46 -0
- package/src/chat/logic/resume-compaction.ts +71 -0
- package/src/chat/logic/scrubber.ts +289 -0
- package/src/chat/logic/thread-cards.ts +64 -0
- package/src/chat/logic/timeline-copy.ts +65 -0
- package/src/chat/logic/timeline-target.ts +52 -0
- package/src/chat/logic/timeline.ts +419 -0
- package/src/chat/logic/tool-catalog.ts +62 -0
- package/src/chat/logic/tools.ts +102 -0
- package/src/chat/logic/welcome.ts +13 -0
- package/src/chat/logic/workflow.ts +66 -0
- package/src/chat/mentions.ts +232 -0
- package/src/chat/persisted-json.ts +67 -0
- package/src/chat/preferences.ts +179 -0
- package/src/chat/quote.ts +26 -0
- package/src/chat/recent-messages.ts +59 -0
- package/src/chat/resume-compaction-dismissals.ts +17 -0
- package/src/chat/runtime-modes.ts +18 -0
- package/src/chat/stash.ts +122 -0
- package/src/chat/subagent-conversation.ts +203 -0
- package/src/chat/subagent-list.ts +141 -0
- package/src/chat/subagent-support.ts +21 -0
- package/src/chat/subagent-view.ts +137 -0
- package/src/chat/thumbnails.ts +108 -0
- package/src/chat/timeline-flash.ts +33 -0
- package/src/chat/timeline-scroll.ts +199 -0
- package/src/chat/ui/AccountPill.tsx +31 -0
- package/src/chat/ui/AnsiOutput.tsx +18 -0
- package/src/chat/ui/BookmarkMarker.tsx +108 -0
- package/src/chat/ui/BookmarkSubmenu.tsx +53 -0
- package/src/chat/ui/ChatActivity.tsx +198 -0
- package/src/chat/ui/ChatReferenceChip.tsx +28 -0
- package/src/chat/ui/CodeBlock.tsx +175 -0
- package/src/chat/ui/Composer.tsx +1326 -0
- package/src/chat/ui/ComposerInput.tsx +187 -0
- package/src/chat/ui/DiffPool.tsx +36 -0
- package/src/chat/ui/EditDiff.tsx +30 -0
- package/src/chat/ui/FadingWords.tsx +18 -0
- package/src/chat/ui/ImageView.tsx +159 -0
- package/src/chat/ui/LimitState.tsx +165 -0
- package/src/chat/ui/Markdown.tsx +258 -0
- package/src/chat/ui/MessageActions.tsx +88 -0
- package/src/chat/ui/Pickers.tsx +272 -0
- package/src/chat/ui/PromptComposer.tsx +119 -0
- package/src/chat/ui/QuoteButton.tsx +103 -0
- package/src/chat/ui/ResumeCompactionDock.tsx +28 -0
- package/src/chat/ui/RunSettings.tsx +546 -0
- package/src/chat/ui/Scrubber.tsx +262 -0
- package/src/chat/ui/SubagentControls.tsx +66 -0
- package/src/chat/ui/SubagentInfo.tsx +67 -0
- package/src/chat/ui/SubagentStopButton.tsx +45 -0
- package/src/chat/ui/SubagentTimeline.tsx +170 -0
- package/src/chat/ui/Timeline.tsx +628 -0
- package/src/chat/ui/TimelineMenu.tsx +124 -0
- package/src/chat/ui/UnifiedDiff.tsx +99 -0
- package/src/chat/ui/UploadThumb.tsx +13 -0
- package/src/chat/ui/Welcome.tsx +22 -0
- package/src/chat/ui/chips.ts +15 -0
- package/src/chat/ui/code-lines.ts +60 -0
- package/src/chat/ui/code-streaming.ts +4 -0
- package/src/chat/ui/code-theme.ts +15 -0
- package/src/chat/ui/composer/chips.ts +43 -0
- package/src/chat/ui/composer/editor.ts +118 -0
- package/src/chat/ui/composer/insert.ts +22 -0
- package/src/chat/ui/composer/keys.ts +144 -0
- package/src/chat/ui/diff-theme.ts +23 -0
- package/src/chat/ui/file-links.ts +24 -0
- package/src/chat/ui/find-reveal.ts +23 -0
- package/src/chat/ui/full-diff.ts +25 -0
- package/src/chat/ui/icons.tsx +24 -0
- package/src/chat/ui/markdown-blocks.ts +123 -0
- package/src/chat/ui/quote-selection.ts +53 -0
- package/src/chat/ui/rehype-chips.ts +62 -0
- package/src/chat/ui/rehype-fade.ts +64 -0
- package/src/chat/ui/remark-html-as-text.ts +36 -0
- package/src/chat/ui/reply-context.ts +4 -0
- package/src/chat/ui/reveal.ts +135 -0
- package/src/chat/ui/rows/ForksRow.tsx +79 -0
- package/src/chat/ui/rows/MessageRows.tsx +415 -0
- package/src/chat/ui/rows/Rows.tsx +81 -0
- package/src/chat/ui/rows/SubagentRow.tsx +209 -0
- package/src/chat/ui/rows/TaskRow.tsx +91 -0
- package/src/chat/ui/rows/WorkRows.tsx +445 -0
- package/src/chat/ui/rows/WorkflowRow.tsx +120 -0
- package/src/chat/ui/rows/row-rhythm.ts +37 -0
- package/src/chat/ui/useToggleSet.ts +39 -0
- package/src/host.ts +324 -0
- package/src/lazy.tsx +64 -0
- package/src/locales/en/agent-chat.json +446 -0
- package/src/locales/en/agent-prompts.json +42 -0
- package/src/locales/en/agent-providers.json +131 -0
- package/src/locales/en/agent-usage.json +131 -0
- package/src/locales/nl/agent-chat.json +446 -0
- package/src/locales/nl/agent-prompts.json +42 -0
- package/src/locales/nl/agent-providers.json +131 -0
- package/src/locales/nl/agent-usage.json +131 -0
- package/src/locales.ts +33 -0
- package/src/mounted-registry.ts +45 -0
- package/src/port-transport.ts +146 -0
- package/src/prompts/logic/focus.ts +25 -0
- package/src/prompts/logic/keys.ts +116 -0
- package/src/prompts/logic/prompts.fixtures.ts +84 -0
- package/src/prompts/logic/prompts.ts +58 -0
- package/src/prompts/logic/subjects.ts +122 -0
- package/src/prompts/logic/useFocusAfterAnswer.ts +38 -0
- package/src/prompts/logic/usePromptSession.ts +114 -0
- package/src/prompts/ui/ApprovalBody.tsx +109 -0
- package/src/prompts/ui/PromptActions.tsx +109 -0
- package/src/prompts/ui/PromptCard.tsx +101 -0
- package/src/prompts/ui/PromptView.tsx +111 -0
- package/src/prompts/ui/QuestionBody.tsx +174 -0
- package/src/providers/AccountColors.tsx +8 -0
- package/src/providers/AccountDetail.tsx +209 -0
- package/src/providers/AccountVariables.tsx +126 -0
- package/src/providers/AddAccountForm.tsx +121 -0
- package/src/providers/CliDetail.tsx +157 -0
- package/src/providers/ProvidersPane.tsx +236 -0
- package/src/providers/account-actions.ts +67 -0
- package/src/providers/parts.tsx +25 -0
- package/src/providers/provider-abilities.ts +9 -0
- package/src/providers/variables.ts +87 -0
- package/src/scope.ts +30 -0
- package/src/settings/sections.ts +47 -0
- package/src/state/chats.ts +279 -0
- package/src/state/provider-accounts.ts +87 -0
- package/src/state/providers.ts +50 -0
- package/src/state/usage.ts +196 -0
- package/src/storage.ts +113 -0
- package/src/theme.css +212 -0
- package/src/transport.ts +50 -0
- package/src/ui/PlainTextarea.tsx +6 -0
- package/src/usage/LimitsList.tsx +232 -0
- package/src/usage/UsageBreakdown.tsx +210 -0
- package/src/usage/UsageChart.tsx +113 -0
- package/src/usage/UsageDialog.tsx +20 -0
- package/src/usage/UsageLimits.tsx +145 -0
- package/src/usage/UsageLimitsCard.tsx +36 -0
- package/src/usage/UsagePage.tsx +276 -0
- package/src/usage/UsagePane.tsx +52 -0
- package/src/usage/UsageSummary.tsx +50 -0
- package/src/usage/UsageTiles.tsx +34 -0
- package/src/usage/format.ts +71 -0
- package/src/usage/limit-groups.ts +119 -0
- package/src/usage/limits.ts +71 -0
- package/src/usage/money.ts +14 -0
- package/src/usage/summary.ts +137 -0
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { useImperativeHandle, useLayoutEffect, useRef, useState, type Ref } from 'react';
|
|
2
|
+
import { Compartment, EditorState, Prec, Transaction, type Extension } from '@codemirror/state';
|
|
3
|
+
import { EditorView, placeholder as placeholderText } from '@codemirror/view';
|
|
4
|
+
import { chatHost } from '../../host';
|
|
5
|
+
import { composerEditorExtensions, externalChange } from './composer/editor';
|
|
6
|
+
import { insertAtSelection } from './composer/insert';
|
|
7
|
+
|
|
8
|
+
export interface ComposerInputHandle {
|
|
9
|
+
focus(): void;
|
|
10
|
+
/* Puts the caret at `pos`, clamped to the text, and gives the editor the focus. */
|
|
11
|
+
setCaret(pos: number): void;
|
|
12
|
+
/* Types text in over the selection (`insertAtSelection`) and gives the editor the focus. */
|
|
13
|
+
insert(text: string): void;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface InputSelection {
|
|
17
|
+
from: number;
|
|
18
|
+
to: number;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface ComposerInputProps {
|
|
22
|
+
ref?: Ref<ComposerInputHandle>;
|
|
23
|
+
dictationToolbar?: HTMLElement | null;
|
|
24
|
+
value: string;
|
|
25
|
+
/* An element for a placeholder with markup of its own; keep its reference stable, as with `extensions`. */
|
|
26
|
+
placeholder: string | HTMLElement;
|
|
27
|
+
disabled: boolean;
|
|
28
|
+
tabbable: boolean;
|
|
29
|
+
className?: string;
|
|
30
|
+
/* Keep the reference stable. A new one reconfigures the editor. */
|
|
31
|
+
extensions?: Extension;
|
|
32
|
+
onChange(text: string, selection: InputSelection, state: EditorState): void;
|
|
33
|
+
onSelectionChange?(text: string, selection: InputSelection, state: EditorState): void;
|
|
34
|
+
onBlur?(): void;
|
|
35
|
+
/* Runs before the editor's own keymap; true means the key is handled and its default prevented. */
|
|
36
|
+
onKeyDown?(event: KeyboardEvent, view: EditorView): boolean;
|
|
37
|
+
/* Runs before the editor pastes the plain text itself; true means the paste is handled. */
|
|
38
|
+
onPaste?(event: ClipboardEvent, view: EditorView): boolean;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const NO_EXTENSIONS: Extension = [];
|
|
42
|
+
|
|
43
|
+
/*
|
|
44
|
+
* A multi-line text field on CodeMirror, controlled by a plain string. The editor draws the text
|
|
45
|
+
* itself, so a decoration may change a font or add padding without walking the caret off its
|
|
46
|
+
* character, which a textarea with a painted layer behind it could not.
|
|
47
|
+
*/
|
|
48
|
+
export function ComposerInput({
|
|
49
|
+
ref,
|
|
50
|
+
value,
|
|
51
|
+
placeholder,
|
|
52
|
+
disabled,
|
|
53
|
+
tabbable,
|
|
54
|
+
className,
|
|
55
|
+
dictationToolbar,
|
|
56
|
+
extensions = NO_EXTENSIONS,
|
|
57
|
+
...handlers
|
|
58
|
+
}: ComposerInputProps) {
|
|
59
|
+
const hostRef = useRef<HTMLDivElement>(null);
|
|
60
|
+
const targetRef = useRef<HTMLDivElement>(null);
|
|
61
|
+
const viewRef = useRef<EditorView | null>(null);
|
|
62
|
+
const [compartments] = useState(() => ({
|
|
63
|
+
attributes: new Compartment(),
|
|
64
|
+
editable: new Compartment(),
|
|
65
|
+
placeholder: new Compartment(),
|
|
66
|
+
extensions: new Compartment()
|
|
67
|
+
}));
|
|
68
|
+
const latest = useRef({ value, handlers });
|
|
69
|
+
// What the editor last reported. The parent handing that back is catching up, not setting a value of its own.
|
|
70
|
+
const reported = useRef(value);
|
|
71
|
+
|
|
72
|
+
useLayoutEffect(() => {
|
|
73
|
+
latest.current = { value, handlers };
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
useLayoutEffect(() => {
|
|
77
|
+
const host = hostRef.current;
|
|
78
|
+
if (!host) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const initial = latest.current.value;
|
|
82
|
+
const view = new EditorView({
|
|
83
|
+
parent: host,
|
|
84
|
+
state: EditorState.create({
|
|
85
|
+
doc: initial,
|
|
86
|
+
selection: { anchor: initial.length },
|
|
87
|
+
extensions: [
|
|
88
|
+
composerEditorExtensions(),
|
|
89
|
+
chatHost().dictation.composer?.extensions ?? [],
|
|
90
|
+
compartments.attributes.of([]),
|
|
91
|
+
compartments.editable.of([]),
|
|
92
|
+
compartments.placeholder.of([]),
|
|
93
|
+
compartments.extensions.of([]),
|
|
94
|
+
Prec.highest(
|
|
95
|
+
EditorView.domEventHandlers({
|
|
96
|
+
keydown: (event, target) => latest.current.handlers.onKeyDown?.(event, target) ?? false,
|
|
97
|
+
paste: (event, target) => latest.current.handlers.onPaste?.(event, target) ?? false
|
|
98
|
+
})
|
|
99
|
+
),
|
|
100
|
+
EditorView.updateListener.of((update) => {
|
|
101
|
+
const current = latest.current.handlers;
|
|
102
|
+
if (update.focusChanged && !update.view.hasFocus) {
|
|
103
|
+
current.onBlur?.();
|
|
104
|
+
}
|
|
105
|
+
if ((!update.docChanged && !update.selectionSet) || update.transactions.some((tr) => tr.annotation(externalChange))) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
const text = update.state.doc.toString();
|
|
109
|
+
const { from, to } = update.state.selection.main;
|
|
110
|
+
if (update.docChanged) {
|
|
111
|
+
reported.current = text;
|
|
112
|
+
current.onChange(text, { from, to }, update.state);
|
|
113
|
+
} else {
|
|
114
|
+
current.onSelectionChange?.(text, { from, to }, update.state);
|
|
115
|
+
}
|
|
116
|
+
})
|
|
117
|
+
]
|
|
118
|
+
})
|
|
119
|
+
});
|
|
120
|
+
viewRef.current = view;
|
|
121
|
+
return () => {
|
|
122
|
+
view.destroy();
|
|
123
|
+
viewRef.current = null;
|
|
124
|
+
};
|
|
125
|
+
}, [compartments]);
|
|
126
|
+
|
|
127
|
+
useLayoutEffect(() => {
|
|
128
|
+
viewRef.current?.dispatch({
|
|
129
|
+
effects: [
|
|
130
|
+
// Spellcheck stays on, as it was on the textarea this editor replaced.
|
|
131
|
+
compartments.attributes.reconfigure(EditorView.contentAttributes.of({ spellcheck: 'true', tabindex: tabbable ? '0' : '-1' })),
|
|
132
|
+
compartments.editable.reconfigure([EditorView.editable.of(!disabled), EditorState.readOnly.of(disabled)]),
|
|
133
|
+
compartments.placeholder.reconfigure(placeholderText(placeholder)),
|
|
134
|
+
compartments.extensions.reconfigure(extensions)
|
|
135
|
+
]
|
|
136
|
+
});
|
|
137
|
+
}, [compartments, tabbable, disabled, placeholder, extensions]);
|
|
138
|
+
|
|
139
|
+
useLayoutEffect(() => {
|
|
140
|
+
const view = viewRef.current;
|
|
141
|
+
if (!view || value === reported.current) {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
reported.current = value;
|
|
145
|
+
const doc = view.state.doc.toString();
|
|
146
|
+
if (value === doc) {
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
view.dispatch({
|
|
150
|
+
changes: { from: 0, to: doc.length, insert: value },
|
|
151
|
+
selection: { anchor: value.length },
|
|
152
|
+
annotations: [externalChange.of(true), Transaction.addToHistory.of(false)]
|
|
153
|
+
});
|
|
154
|
+
}, [value]);
|
|
155
|
+
|
|
156
|
+
useImperativeHandle(
|
|
157
|
+
ref,
|
|
158
|
+
() => ({
|
|
159
|
+
focus: () => viewRef.current?.focus(),
|
|
160
|
+
setCaret: (pos: number) => {
|
|
161
|
+
const view = viewRef.current;
|
|
162
|
+
if (!view) {
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
view.dispatch({ selection: { anchor: Math.min(pos, view.state.doc.length) }, scrollIntoView: true });
|
|
166
|
+
view.focus();
|
|
167
|
+
},
|
|
168
|
+
insert: (text: string) => {
|
|
169
|
+
const view = viewRef.current;
|
|
170
|
+
if (!view) {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
view.dispatch(insertAtSelection(view.state, text));
|
|
174
|
+
view.focus();
|
|
175
|
+
}
|
|
176
|
+
}),
|
|
177
|
+
[]
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
const Dictation = chatHost().dictation.composer?.Control;
|
|
181
|
+
return (
|
|
182
|
+
<div ref={targetRef} className="min-w-0">
|
|
183
|
+
<div ref={hostRef} className={className} />
|
|
184
|
+
{Dictation && <Dictation buttonContainer={dictationToolbar} targetRef={targetRef} disabled={disabled} editor={() => viewRef.current} />}
|
|
185
|
+
</div>
|
|
186
|
+
);
|
|
187
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { useEffect, type ReactNode } from 'react';
|
|
2
|
+
import { useWorkerPool, WorkerPoolContextProvider } from '@pierre/diffs/react';
|
|
3
|
+
import { useDiffTheme } from './diff-theme';
|
|
4
|
+
|
|
5
|
+
// Two workers keep highlighting off the main thread without holding a shiki instance per chat node.
|
|
6
|
+
const POOL_SIZE = 2;
|
|
7
|
+
|
|
8
|
+
/* The pool reads its highlighter options once, when the singleton is made, and its theme wins over a diff's own. */
|
|
9
|
+
function ThemeSync() {
|
|
10
|
+
const pool = useWorkerPool();
|
|
11
|
+
const theme = useDiffTheme();
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
void pool?.setRenderOptions({ theme });
|
|
14
|
+
}, [pool, theme]);
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/*
|
|
19
|
+
* Shares one highlighter pool between every diff under it; the provider keeps a singleton behind the
|
|
20
|
+
* scenes. How a worker of `@pierre/diffs/worker` is made is the bundler's business, so the app says.
|
|
21
|
+
*/
|
|
22
|
+
export default function DiffPool({ workerFactory, children }: { workerFactory: () => Worker; children: ReactNode }) {
|
|
23
|
+
const theme = useDiffTheme();
|
|
24
|
+
return (
|
|
25
|
+
<WorkerPoolContextProvider
|
|
26
|
+
poolOptions={{
|
|
27
|
+
poolSize: POOL_SIZE,
|
|
28
|
+
workerFactory
|
|
29
|
+
}}
|
|
30
|
+
highlighterOptions={{ theme }}
|
|
31
|
+
>
|
|
32
|
+
<ThemeSync />
|
|
33
|
+
{children}
|
|
34
|
+
</WorkerPoolContextProvider>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
|
+
import { MultiFileDiff } from '@pierre/diffs/react';
|
|
3
|
+
import { chatHost } from '../../host';
|
|
4
|
+
import { useDiffTheme } from './diff-theme';
|
|
5
|
+
|
|
6
|
+
import type { FileChange } from '../logic/tools';
|
|
7
|
+
|
|
8
|
+
/* One hunk of a file edit, highlighted in a worker. The header is ours, so the library's is off. */
|
|
9
|
+
export default function EditDiff({ change }: { change: FileChange }) {
|
|
10
|
+
const resolved = chatHost().code.useMode();
|
|
11
|
+
const theme = useDiffTheme();
|
|
12
|
+
const oldFile = useMemo(() => ({ name: change.path, contents: change.before }), [change.path, change.before]);
|
|
13
|
+
const newFile = useMemo(() => ({ name: change.path, contents: change.after }), [change.path, change.after]);
|
|
14
|
+
const options = useMemo(
|
|
15
|
+
() => ({
|
|
16
|
+
diffStyle: 'unified' as const,
|
|
17
|
+
theme,
|
|
18
|
+
themeType: resolved,
|
|
19
|
+
disableFileHeader: true,
|
|
20
|
+
overflow: 'wrap' as const,
|
|
21
|
+
hunkSeparators: 'simple' as const
|
|
22
|
+
}),
|
|
23
|
+
[theme, resolved]
|
|
24
|
+
);
|
|
25
|
+
return (
|
|
26
|
+
<div className="chat-diff select-text">
|
|
27
|
+
<MultiFileDiff oldFile={oldFile} newFile={newFile} options={options} />
|
|
28
|
+
</div>
|
|
29
|
+
);
|
|
30
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { FADE_CLASS, isWhitespace, wordSegments } from './rehype-fade';
|
|
2
|
+
|
|
3
|
+
export function FadingWords({ text }: { text: string }) {
|
|
4
|
+
return (
|
|
5
|
+
<>
|
|
6
|
+
{wordSegments(text).map((segment, index) =>
|
|
7
|
+
isWhitespace(segment) ? (
|
|
8
|
+
segment
|
|
9
|
+
) : (
|
|
10
|
+
// Streaming appends words, so the index keeps existing fades from restarting.
|
|
11
|
+
<span key={index} className={FADE_CLASS}>
|
|
12
|
+
{segment}
|
|
13
|
+
</span>
|
|
14
|
+
)
|
|
15
|
+
)}
|
|
16
|
+
</>
|
|
17
|
+
);
|
|
18
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { useRef, useState } from 'react';
|
|
2
|
+
import { useTranslation } from 'react-i18next';
|
|
3
|
+
import clsx from 'clsx';
|
|
4
|
+
import { ImageOff, Minus, Plus, RotateCcw } from 'lucide-react';
|
|
5
|
+
import type { ResourceUrl } from '../../host';
|
|
6
|
+
import { ButtonGroup, CloseButton, Dialog, Icon, IconButton, Tooltip } from '@adecore/ui';
|
|
7
|
+
|
|
8
|
+
const MIN_SCALE = 1;
|
|
9
|
+
const MAX_SCALE = 8;
|
|
10
|
+
// One wheel notch, small enough that a trackpad flick does not jump past the detail it aimed at.
|
|
11
|
+
const WHEEL_STEP = 1.0015;
|
|
12
|
+
const BUTTON_STEP = 1.5;
|
|
13
|
+
|
|
14
|
+
interface View {
|
|
15
|
+
scale: number;
|
|
16
|
+
x: number;
|
|
17
|
+
y: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const START: View = { scale: 1, x: 0, y: 0 };
|
|
21
|
+
|
|
22
|
+
/*
|
|
23
|
+
* Zooms around a point, which is what makes a wheel over a detail feel like a magnifier instead of
|
|
24
|
+
* a slider. The pixel under the pointer stays where it is while everything else moves away from it.
|
|
25
|
+
* `x` and `y` are offsets from the middle of the frame, so a scale of 1 is always centered.
|
|
26
|
+
*/
|
|
27
|
+
function zoomed(view: View, factor: number, pointX: number, pointY: number): View {
|
|
28
|
+
const scale = Math.min(MAX_SCALE, Math.max(MIN_SCALE, view.scale * factor));
|
|
29
|
+
if (scale === MIN_SCALE) {
|
|
30
|
+
return START;
|
|
31
|
+
}
|
|
32
|
+
const ratio = scale / view.scale;
|
|
33
|
+
return { scale, x: pointX - (pointX - view.x) * ratio, y: pointY - (pointY - view.y) * ratio };
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/* An image on its own, large: the wheel and the buttons zoom, dragging pans, Escape closes. */
|
|
37
|
+
function Lightbox({ src, alt, open, onOpenChange }: { src: string; alt: string; open: boolean; onOpenChange(open: boolean): void }) {
|
|
38
|
+
const { t } = useTranslation('agent-chat');
|
|
39
|
+
const [view, setView] = useState<View>(START);
|
|
40
|
+
// The alt of an image an agent read is its path; the header shows the file and keeps the path on a tooltip.
|
|
41
|
+
const name = alt.slice(alt.lastIndexOf('/') + 1);
|
|
42
|
+
const title = <span className="min-w-0 truncate text-xs text-text">{name}</span>;
|
|
43
|
+
const frameRef = useRef<HTMLDivElement>(null);
|
|
44
|
+
const dragRef = useRef<{ pointerId: number; x: number; y: number } | null>(null);
|
|
45
|
+
|
|
46
|
+
if (!open && view !== START) {
|
|
47
|
+
setView(START);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/* Where the pointer sits against the middle of the frame, which is what the transform counts from. */
|
|
51
|
+
const pointIn = (event: { clientX: number; clientY: number }): { x: number; y: number } => {
|
|
52
|
+
const rect = frameRef.current?.getBoundingClientRect();
|
|
53
|
+
if (!rect) {
|
|
54
|
+
return { x: 0, y: 0 };
|
|
55
|
+
}
|
|
56
|
+
return { x: event.clientX - rect.left - rect.width / 2, y: event.clientY - rect.top - rect.height / 2 };
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const zoomButton = (factor: number): void => setView((current) => zoomed(current, factor, 0, 0));
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<Dialog.Root open={open} onOpenChange={onOpenChange}>
|
|
63
|
+
{/* Nothing here sets a size. The picture takes the room `.lightbox-frame` allows it, and the popup follows. */}
|
|
64
|
+
<Dialog.Popup backdropClassName="lightbox-backdrop" className="flex min-w-72 flex-col">
|
|
65
|
+
<Dialog.Title className="sr-only">{alt}</Dialog.Title>
|
|
66
|
+
<div className="flex h-11 shrink-0 items-center gap-2 border-b border-border pr-2 pl-3">
|
|
67
|
+
{name === alt ? title : <Tooltip label={alt}>{title}</Tooltip>}
|
|
68
|
+
<span className="grow" />
|
|
69
|
+
<span className="tabular-nums text-xs text-text-faint">{Math.round(view.scale * 100)}%</span>
|
|
70
|
+
<ButtonGroup render={<span />}>
|
|
71
|
+
<IconButton
|
|
72
|
+
icon={Minus}
|
|
73
|
+
size="sm"
|
|
74
|
+
label={t('image.zoomOut')}
|
|
75
|
+
disabled={view.scale <= MIN_SCALE}
|
|
76
|
+
onClick={() => zoomButton(1 / BUTTON_STEP)}
|
|
77
|
+
/>
|
|
78
|
+
<IconButton
|
|
79
|
+
icon={Plus}
|
|
80
|
+
size="sm"
|
|
81
|
+
label={t('image.zoomIn')}
|
|
82
|
+
disabled={view.scale >= MAX_SCALE}
|
|
83
|
+
onClick={() => zoomButton(BUTTON_STEP)}
|
|
84
|
+
/>
|
|
85
|
+
<IconButton icon={RotateCcw} size="sm" label={t('image.reset')} disabled={view.scale === MIN_SCALE} onClick={() => setView(START)} />
|
|
86
|
+
</ButtonGroup>
|
|
87
|
+
<CloseButton label={t('common.action.close')} kbd="esc" className="ml-1" dialog />
|
|
88
|
+
</div>
|
|
89
|
+
<div
|
|
90
|
+
ref={frameRef}
|
|
91
|
+
className={clsx('lightbox-frame grid place-items-center overflow-hidden bg-surface-sunken', view.scale > MIN_SCALE && 'cursor-grab')}
|
|
92
|
+
onWheel={(e) => {
|
|
93
|
+
const point = pointIn(e);
|
|
94
|
+
setView((current) => zoomed(current, WHEEL_STEP ** -e.deltaY, point.x, point.y));
|
|
95
|
+
}}
|
|
96
|
+
onDoubleClick={(e) => {
|
|
97
|
+
const point = pointIn(e);
|
|
98
|
+
setView((current) => (current.scale > MIN_SCALE ? START : zoomed(current, 2, point.x, point.y)));
|
|
99
|
+
}}
|
|
100
|
+
onPointerDown={(e) => {
|
|
101
|
+
if (view.scale <= MIN_SCALE) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
e.currentTarget.setPointerCapture(e.pointerId);
|
|
105
|
+
dragRef.current = { pointerId: e.pointerId, x: e.clientX - view.x, y: e.clientY - view.y };
|
|
106
|
+
}}
|
|
107
|
+
onPointerMove={(e) => {
|
|
108
|
+
const drag = dragRef.current;
|
|
109
|
+
if (drag?.pointerId === e.pointerId) {
|
|
110
|
+
setView((current) => ({ ...current, x: e.clientX - drag.x, y: e.clientY - drag.y }));
|
|
111
|
+
}
|
|
112
|
+
}}
|
|
113
|
+
onPointerUp={() => {
|
|
114
|
+
dragRef.current = null;
|
|
115
|
+
}}
|
|
116
|
+
onPointerCancel={() => {
|
|
117
|
+
dragRef.current = null;
|
|
118
|
+
}}
|
|
119
|
+
>
|
|
120
|
+
<img
|
|
121
|
+
src={src}
|
|
122
|
+
alt={alt}
|
|
123
|
+
draggable={false}
|
|
124
|
+
className="select-none"
|
|
125
|
+
style={{ transform: `translate(${Math.round(view.x)}px, ${Math.round(view.y)}px) scale(${view.scale})` }}
|
|
126
|
+
/>
|
|
127
|
+
</div>
|
|
128
|
+
</Dialog.Popup>
|
|
129
|
+
</Dialog.Root>
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/*
|
|
134
|
+
* A thumbnail that opens the same image large. The button is the picture, so there is nothing to aim at.
|
|
135
|
+
* The image is bytes where the host keeps them; until they are here a quiet square stands in for it.
|
|
136
|
+
*/
|
|
137
|
+
export function ImageThumb({ source, alt, className }: { source: ResourceUrl; alt: string; className?: string }) {
|
|
138
|
+
const [open, setOpen] = useState(false);
|
|
139
|
+
const { url: src, failure } = source;
|
|
140
|
+
if (src === null) {
|
|
141
|
+
return (
|
|
142
|
+
<span className="grid size-16 place-items-center rounded-lg border border-border bg-surface-sunken text-text-faint">
|
|
143
|
+
{failure !== null && (
|
|
144
|
+
<Tooltip label={failure}>
|
|
145
|
+
<Icon icon={ImageOff} size={14} />
|
|
146
|
+
</Tooltip>
|
|
147
|
+
)}
|
|
148
|
+
</span>
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
return (
|
|
152
|
+
<>
|
|
153
|
+
<button className="block overflow-hidden rounded-lg border border-border" onClick={() => setOpen(true)}>
|
|
154
|
+
<img src={src} alt={alt} className={className} />
|
|
155
|
+
</button>
|
|
156
|
+
<Lightbox src={src} alt={alt} open={open} onOpenChange={setOpen} />
|
|
157
|
+
</>
|
|
158
|
+
);
|
|
159
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
import { useTranslation } from 'react-i18next';
|
|
3
|
+
import { Hourglass } from 'lucide-react';
|
|
4
|
+
import type { ChatInfo } from '@adecore/agent-contracts';
|
|
5
|
+
import { AccountDot } from '../../agents/AccountDot';
|
|
6
|
+
import { continueTarget, hasUnreadAccount } from '../../agents/account-limits';
|
|
7
|
+
import { useAccountChoice, type AccountChoice } from '../account-choice';
|
|
8
|
+
import { limitView } from '../logic/limit';
|
|
9
|
+
import { useFormatLocale } from '@adecore/ui/format';
|
|
10
|
+
import { Switch, Button, Icon, Pill, Tooltip, useNow } from '@adecore/ui';
|
|
11
|
+
import { useUsageLimits } from '../../usage/limits';
|
|
12
|
+
import { useChats } from '../../state/chats';
|
|
13
|
+
import { chatHost } from '../../host';
|
|
14
|
+
import { useChatScope, type ChatScope } from '../../scope';
|
|
15
|
+
import { useChatActions } from '../actions';
|
|
16
|
+
import { useUsageStore } from '../../state/usage';
|
|
17
|
+
|
|
18
|
+
// A time a limit names reads as a clock today and with its day after that, so the words follow the minute.
|
|
19
|
+
const MINUTE_MS = 60_000;
|
|
20
|
+
|
|
21
|
+
// Reading an account's plan starts its CLI, so an account nobody used yet is read at most this often per host.
|
|
22
|
+
const UNREAD_REFRESH_MS = 5 * MINUTE_MS;
|
|
23
|
+
const refreshedAt = new Map<string, number>();
|
|
24
|
+
|
|
25
|
+
/*
|
|
26
|
+
* The host reads the plan of an account other than a CLI's default one only while it is in use, so
|
|
27
|
+
* an account that could take the chat over may have no numbers yet. The dock asks for them.
|
|
28
|
+
*/
|
|
29
|
+
function readUnreadAccounts(scope: ChatScope): void {
|
|
30
|
+
const last = refreshedAt.get(scope.id);
|
|
31
|
+
if (last !== undefined && Date.now() - last < UNREAD_REFRESH_MS) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
refreshedAt.set(scope.id, Date.now());
|
|
35
|
+
void scope.transport
|
|
36
|
+
.request('usage.refreshLimits', {})
|
|
37
|
+
.then((snapshot) => useUsageStore.getState().setLimits(scope.id, snapshot))
|
|
38
|
+
.catch(() => undefined);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/*
|
|
42
|
+
* The chat's own "Resume at reset". It only counts while the host allows it, so with the host's
|
|
43
|
+
* switch off it stands off and says where that switch is.
|
|
44
|
+
*/
|
|
45
|
+
function ResumeAtResetToggle({ chatId, info }: { chatId: string; info: ChatInfo }) {
|
|
46
|
+
const { t } = useTranslation('agent-chat');
|
|
47
|
+
const { id } = useChatScope();
|
|
48
|
+
const actions = useChatActions();
|
|
49
|
+
const machineAllows = chatHost().useResumeAtReset(id);
|
|
50
|
+
const set = (on: boolean): void => {
|
|
51
|
+
void actions.configure(chatId, { resumeAtReset: on }).catch(() => undefined);
|
|
52
|
+
};
|
|
53
|
+
return (
|
|
54
|
+
<Tooltip label={machineAllows ? t('limit.toggle') : t('limit.machineOff')}>
|
|
55
|
+
{/* A disabled switch does not take the pointer, so the tooltip hangs on a wrapper. */}
|
|
56
|
+
<span className="inline-flex shrink-0">
|
|
57
|
+
<Switch checked={machineAllows && info.resumeAtReset !== false} onCheckedChange={set} label={t('limit.toggle')} disabled={!machineAllows} />
|
|
58
|
+
</span>
|
|
59
|
+
</Tooltip>
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/*
|
|
64
|
+
* Another account of the chat's CLI that has room: the one with the least of its session spent. Only
|
|
65
|
+
* ever offered, since going on there spends someone's other plan. An account that reads the chat's
|
|
66
|
+
* conversation takes it over; any other goes on in a fork, which then opens the way a fork does.
|
|
67
|
+
*/
|
|
68
|
+
function ContinueOn({ chatId, info, choice }: { chatId: string; info: ChatInfo; choice: AccountChoice }) {
|
|
69
|
+
const { t } = useTranslation('agent-chat');
|
|
70
|
+
const scope = useChatScope();
|
|
71
|
+
const actions = useChatActions();
|
|
72
|
+
const limits = useUsageLimits();
|
|
73
|
+
const [busy, setBusy] = useState(false);
|
|
74
|
+
const target = continueTarget(choice.accounts, limits, info.provider, info.account);
|
|
75
|
+
const unread = limits !== null && hasUnreadAccount(choice.accounts, limits, info.provider, info.account);
|
|
76
|
+
|
|
77
|
+
useEffect(() => {
|
|
78
|
+
if (unread) {
|
|
79
|
+
readUnreadAccounts(scope);
|
|
80
|
+
}
|
|
81
|
+
}, [scope, unread]);
|
|
82
|
+
|
|
83
|
+
if (target === null) {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
const name = choice.nameOf(target);
|
|
87
|
+
const go = (): void => {
|
|
88
|
+
setBusy(true);
|
|
89
|
+
actions
|
|
90
|
+
.continueOn(chatId, target.id)
|
|
91
|
+
.catch((e: unknown) =>
|
|
92
|
+
chatHost().notify({
|
|
93
|
+
kind: 'error',
|
|
94
|
+
title: t('limit.continueFailed', { account: name }),
|
|
95
|
+
description: e instanceof Error ? e.message : String(e)
|
|
96
|
+
})
|
|
97
|
+
)
|
|
98
|
+
.finally(() => setBusy(false));
|
|
99
|
+
};
|
|
100
|
+
return (
|
|
101
|
+
<Tooltip label={t('limit.continueOnTip', { account: name })}>
|
|
102
|
+
<Button
|
|
103
|
+
variant="secondary"
|
|
104
|
+
size="sm"
|
|
105
|
+
className="shrink-0 gap-1.5 whitespace-nowrap"
|
|
106
|
+
disabled={busy}
|
|
107
|
+
aria-label={t('limit.continueOnAria', { account: name })}
|
|
108
|
+
onClick={go}
|
|
109
|
+
>
|
|
110
|
+
{t('limit.continueOn')}
|
|
111
|
+
<AccountDot color={target.account.color} className="size-1.75" />
|
|
112
|
+
{name}
|
|
113
|
+
</Button>
|
|
114
|
+
</Tooltip>
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/* At the top of the composer while the last turn stopped on a limit: what stopped it, when it goes on, and the switch. */
|
|
119
|
+
export function LimitDock({ chatId, info }: { chatId: string; info: ChatInfo }) {
|
|
120
|
+
const { t } = useTranslation('agent-chat');
|
|
121
|
+
useFormatLocale();
|
|
122
|
+
const now = useNow(MINUTE_MS, info.limit !== undefined);
|
|
123
|
+
const choice = useAccountChoice(info.provider, info.account);
|
|
124
|
+
const view = limitView(info, now);
|
|
125
|
+
if (view === null) {
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
// With a choice of accounts the line names the one that ran into the limit.
|
|
129
|
+
const account = choice === null ? null : choice.current === null ? choice.currentId : choice.nameOf(choice.current);
|
|
130
|
+
const detail = account === null ? view.detail : view.detail === null ? account : `${account} · ${view.detail}`;
|
|
131
|
+
return (
|
|
132
|
+
<div className="flex items-center gap-2 border-b border-border px-3.5 py-2.5">
|
|
133
|
+
<Icon icon={Hourglass} size={16} className="shrink-0 text-text-faint" />
|
|
134
|
+
<span className="flex min-w-0 grow flex-col">
|
|
135
|
+
<span className="truncate text-sm text-text">{view.title}</span>
|
|
136
|
+
{detail !== null && <span className="truncate text-xs tabular-nums text-text-faint">{detail}</span>}
|
|
137
|
+
</span>
|
|
138
|
+
{choice !== null && info.limit?.kind === 'usage' && <ContinueOn chatId={chatId} info={info} choice={choice} />}
|
|
139
|
+
<span className="shrink-0 text-xs text-text-muted">{t('limit.toggle')}</span>
|
|
140
|
+
<ResumeAtResetToggle chatId={chatId} info={info} />
|
|
141
|
+
</div>
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/* The same state in a chat node's header, read from the status every client gets, so a node nobody opened says it too. */
|
|
146
|
+
export function LimitPill({ chatId }: { chatId: string }) {
|
|
147
|
+
const { keyOf } = useChatScope();
|
|
148
|
+
const info = useChats((s) => s.statusByKey[keyOf(chatId)]?.info);
|
|
149
|
+
useFormatLocale();
|
|
150
|
+
const now = useNow(MINUTE_MS, info?.limit !== undefined);
|
|
151
|
+
const view = info === undefined ? null : limitView(info, now);
|
|
152
|
+
if (info === undefined || view === null) {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
return (
|
|
156
|
+
<>
|
|
157
|
+
<Tooltip label={view.detail === null ? view.title : `${view.title}. ${view.detail}`}>
|
|
158
|
+
<Pill className="tabular-nums" icon={<Icon icon={Hourglass} size={12} />}>
|
|
159
|
+
{view.pill}
|
|
160
|
+
</Pill>
|
|
161
|
+
</Tooltip>
|
|
162
|
+
<ResumeAtResetToggle chatId={chatId} info={info} />
|
|
163
|
+
</>
|
|
164
|
+
);
|
|
165
|
+
}
|