@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,50 @@
|
|
|
1
|
+
import { create } from 'zustand';
|
|
2
|
+
import type { ProviderInfo } from '@adecore/agent-contracts';
|
|
3
|
+
import { useChatScope } from '../scope';
|
|
4
|
+
|
|
5
|
+
export interface ProvidersRow {
|
|
6
|
+
providers: ProviderInfo[];
|
|
7
|
+
loaded: boolean;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/* One object for a host that has not answered yet, so a selector gets a stable snapshot. */
|
|
11
|
+
const NONE: ProvidersRow = { providers: [], loaded: false };
|
|
12
|
+
|
|
13
|
+
interface ProvidersStore {
|
|
14
|
+
byScope: Record<string, ProvidersRow>;
|
|
15
|
+
setProviders(scopeId: string, providers: ProviderInfo[]): void;
|
|
16
|
+
forget(scopeId: string): void;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/* Which agent CLIs each host reports, and their models; filled once per connection. */
|
|
20
|
+
export const useProvidersStore = create<ProvidersStore>((set, get) => ({
|
|
21
|
+
byScope: {},
|
|
22
|
+
setProviders(scopeId, providers) {
|
|
23
|
+
set({ byScope: { ...get().byScope, [scopeId]: { providers, loaded: true } } });
|
|
24
|
+
},
|
|
25
|
+
forget(scopeId) {
|
|
26
|
+
const { [scopeId]: _gone, ...rest } = get().byScope;
|
|
27
|
+
set({ byScope: rest });
|
|
28
|
+
}
|
|
29
|
+
}));
|
|
30
|
+
|
|
31
|
+
/*
|
|
32
|
+
* The CLIs of the host in scope. An agent menu has to offer what the host the chat will run on has
|
|
33
|
+
* installed, never what another host answered.
|
|
34
|
+
*/
|
|
35
|
+
export function useProviders<T>(select: (row: ProvidersRow) => T): T {
|
|
36
|
+
const { id } = useChatScope();
|
|
37
|
+
return useProvidersStore((s) => select(s.byScope[id] ?? NONE));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/* The same answer outside a render. */
|
|
41
|
+
export function providersOf(scopeId: string): ProvidersRow {
|
|
42
|
+
return useProvidersStore.getState().byScope[scopeId] ?? NONE;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/* What one host's chat client fills in; it knows its own host and nothing of the others. */
|
|
46
|
+
export function providerSinkFor(scopeId: string): { setProviders(providers: ProviderInfo[]): void } {
|
|
47
|
+
return {
|
|
48
|
+
setProviders: (providers) => useProvidersStore.getState().setProviders(scopeId, providers)
|
|
49
|
+
};
|
|
50
|
+
}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import type { UsageLimitsSnapshot, UsageSummaryPayload, UsageSummaryResult } from '@adecore/agent-contracts';
|
|
2
|
+
import { chatStorageKey, chatStorageLegacyKeys, createChatStore, onChatStorageConfiguration } from '../storage';
|
|
3
|
+
import { persistedJson } from '../chat/persisted-json';
|
|
4
|
+
import { localTimeZone } from '@adecore/ui/format';
|
|
5
|
+
import { useChatScope } from '../scope';
|
|
6
|
+
import type { UsageCurrency } from '../usage/format';
|
|
7
|
+
|
|
8
|
+
export type UsagePeriod = 'today' | '7d' | '30d' | '90d';
|
|
9
|
+
export type UsageMetric = 'cost' | 'tokens';
|
|
10
|
+
|
|
11
|
+
/* Only the id and the length. A store has no words, so the page names a period in its own language. */
|
|
12
|
+
export const USAGE_PERIODS: readonly { id: UsagePeriod; days: number }[] = [
|
|
13
|
+
{ id: 'today', days: 1 },
|
|
14
|
+
{ id: '7d', days: 7 },
|
|
15
|
+
{ id: '30d', days: 30 },
|
|
16
|
+
{ id: '90d', days: 90 }
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
const storageKey = (): string => chatStorageKey('usage');
|
|
20
|
+
|
|
21
|
+
export let USAGE_PREFERENCES_KEY = storageKey();
|
|
22
|
+
onChatStorageConfiguration(() => {
|
|
23
|
+
USAGE_PREFERENCES_KEY = storageKey();
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
export function usagePreferencesKey(): string {
|
|
27
|
+
return storageKey();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface Preferences {
|
|
31
|
+
period: UsagePeriod;
|
|
32
|
+
metric: UsageMetric;
|
|
33
|
+
/* Dollars until someone asks for euros; it is the viewer's setting, not the project's. */
|
|
34
|
+
currency: UsageCurrency;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const DEFAULTS: Preferences = { period: '7d', metric: 'cost', currency: 'USD' };
|
|
38
|
+
|
|
39
|
+
function parsePreferences(raw: string | null): Preferences {
|
|
40
|
+
try {
|
|
41
|
+
const stored = JSON.parse(raw ?? '{}') as Partial<Preferences>;
|
|
42
|
+
return {
|
|
43
|
+
period: USAGE_PERIODS.some((period) => period.id === stored.period) ? stored.period! : DEFAULTS.period,
|
|
44
|
+
metric: stored.metric === 'tokens' || stored.metric === 'cost' ? stored.metric : DEFAULTS.metric,
|
|
45
|
+
currency: stored.currency === 'EUR' ? 'EUR' : DEFAULTS.currency
|
|
46
|
+
};
|
|
47
|
+
} catch {
|
|
48
|
+
return DEFAULTS;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const storage = persistedJson(storageKey, parsePreferences, DEFAULTS, () => chatStorageLegacyKeys('usage'));
|
|
53
|
+
|
|
54
|
+
function readPreferences(): Preferences {
|
|
55
|
+
return storage.read();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function persist(preferences: Preferences): void {
|
|
59
|
+
storage.write(preferences);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/* The three stored choices out of the store, so a setter writes the other two back unchanged. */
|
|
63
|
+
function chosen(state: Preferences): Preferences {
|
|
64
|
+
return { period: state.period, metric: state.metric, currency: state.currency };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function pad(value: number): string {
|
|
68
|
+
return String(value).padStart(2, '0');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/* The viewer's own calendar day; the host may stand in another zone and buckets in this one. */
|
|
72
|
+
export function dayOf(date: Date): string {
|
|
73
|
+
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/*
|
|
77
|
+
* What a period asks for. Today counts from local midnight in hours, the way the commit log already
|
|
78
|
+
* groups days, so every other period reads as one bar per calendar day.
|
|
79
|
+
*/
|
|
80
|
+
export function windowFor(period: UsagePeriod, now = new Date()): UsageSummaryPayload {
|
|
81
|
+
const days = USAGE_PERIODS.find((entry) => entry.id === period)?.days ?? 7;
|
|
82
|
+
const from = new Date(now.getFullYear(), now.getMonth(), now.getDate() - (days - 1));
|
|
83
|
+
return {
|
|
84
|
+
from: dayOf(from),
|
|
85
|
+
to: dayOf(now),
|
|
86
|
+
resolution: period === 'today' ? 'hour' : 'day',
|
|
87
|
+
timeZone: localTimeZone() ?? 'UTC'
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/* A period, and only the usage of one account when one is picked; null is every account. */
|
|
92
|
+
export function summaryPayload(period: UsagePeriod, account: string | null, now = new Date()): UsageSummaryPayload {
|
|
93
|
+
return account === null ? windowFor(period, now) : { ...windowFor(period, now), accounts: [account] };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/* What was asked, so an answer to the question before this one is never drawn over a newer one. */
|
|
97
|
+
export function askedKey(payload: UsageSummaryPayload): string {
|
|
98
|
+
return `${payload.from}\0${payload.to}\0${payload.resolution}\0${payload.timeZone}\0${payload.accounts?.join(',') ?? ''}`;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/* The numbers of one host: its transcripts, priced by it. */
|
|
102
|
+
interface UsageRow {
|
|
103
|
+
/* The question the summary on screen answers, or null while nothing has come back yet. */
|
|
104
|
+
asked: string | null;
|
|
105
|
+
summary: UsageSummaryResult | null;
|
|
106
|
+
/* True while the host has not answered the question that is being asked now. */
|
|
107
|
+
loading: boolean;
|
|
108
|
+
/* The last request failed; the summary before it stays on screen under a red line. */
|
|
109
|
+
failed: boolean;
|
|
110
|
+
limits: UsageLimitsSnapshot | null;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/* One object for a host nothing was read from yet, so a selector gets a stable snapshot. */
|
|
114
|
+
const EMPTY: UsageRow = { asked: null, summary: null, loading: false, failed: false, limits: null };
|
|
115
|
+
|
|
116
|
+
interface UsageStore extends Preferences {
|
|
117
|
+
byScope: Record<string, UsageRow>;
|
|
118
|
+
/*
|
|
119
|
+
* The host the usage page is showing, by scope id, or null for the one its surroundings are on.
|
|
120
|
+
* Deliberately not in `Preferences`, so it is not written to storage: a remembered host outlives
|
|
121
|
+
* this client's knowledge of it, and the numbers worth opening on are those of the host you work
|
|
122
|
+
* on. It does survive closing the page, which is what makes browsing two hosts bearable.
|
|
123
|
+
*/
|
|
124
|
+
chosen: string | null;
|
|
125
|
+
/* Which host's numbers the page shows; null hands it back to the one around it. */
|
|
126
|
+
choose(scopeId: string | null): void;
|
|
127
|
+
setPeriod(period: UsagePeriod): void;
|
|
128
|
+
setMetric(metric: UsageMetric): void;
|
|
129
|
+
setCurrency(currency: UsageCurrency): void;
|
|
130
|
+
setLoading(scopeId: string, loading: boolean): void;
|
|
131
|
+
receive(scopeId: string, asked: string, summary: UsageSummaryResult): void;
|
|
132
|
+
fail(scopeId: string): void;
|
|
133
|
+
setLimits(scopeId: string, limits: UsageLimitsSnapshot): void;
|
|
134
|
+
/* A host that is forgotten takes its numbers with it; the three preferences are the viewer's and stay. */
|
|
135
|
+
forget(scopeId: string): void;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/* Reads the period, metric and currency again, once another window of the same origin wrote them. */
|
|
139
|
+
export function reloadUsagePreferences(): void {
|
|
140
|
+
useUsageStore.setState(readPreferences());
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export const useUsageStore = createChatStore<UsageStore>(
|
|
144
|
+
(set, get) => ({
|
|
145
|
+
...DEFAULTS,
|
|
146
|
+
byScope: {},
|
|
147
|
+
chosen: null,
|
|
148
|
+
choose(scopeId) {
|
|
149
|
+
set({ chosen: scopeId });
|
|
150
|
+
},
|
|
151
|
+
setPeriod(period) {
|
|
152
|
+
persist({ ...chosen(get()), period });
|
|
153
|
+
set({ period });
|
|
154
|
+
},
|
|
155
|
+
setMetric(metric) {
|
|
156
|
+
persist({ ...chosen(get()), metric });
|
|
157
|
+
set({ metric });
|
|
158
|
+
},
|
|
159
|
+
setCurrency(currency) {
|
|
160
|
+
persist({ ...chosen(get()), currency });
|
|
161
|
+
set({ currency });
|
|
162
|
+
},
|
|
163
|
+
setLoading(scopeId, loading) {
|
|
164
|
+
set({ byScope: { ...get().byScope, [scopeId]: { ...(get().byScope[scopeId] ?? EMPTY), loading } } });
|
|
165
|
+
},
|
|
166
|
+
receive(scopeId, asked, summary) {
|
|
167
|
+
set({
|
|
168
|
+
byScope: { ...get().byScope, [scopeId]: { ...(get().byScope[scopeId] ?? EMPTY), asked, summary, loading: false, failed: false } }
|
|
169
|
+
});
|
|
170
|
+
},
|
|
171
|
+
fail(scopeId) {
|
|
172
|
+
set({ byScope: { ...get().byScope, [scopeId]: { ...(get().byScope[scopeId] ?? EMPTY), loading: false, failed: true } } });
|
|
173
|
+
},
|
|
174
|
+
setLimits(scopeId, limits) {
|
|
175
|
+
set({ byScope: { ...get().byScope, [scopeId]: { ...(get().byScope[scopeId] ?? EMPTY), limits } } });
|
|
176
|
+
},
|
|
177
|
+
forget(scopeId) {
|
|
178
|
+
const { [scopeId]: _gone, ...rest } = get().byScope;
|
|
179
|
+
set({ byScope: rest });
|
|
180
|
+
}
|
|
181
|
+
}),
|
|
182
|
+
(store) => store.setState(readPreferences())
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
/*
|
|
186
|
+
* The preferences of the viewer over the numbers of the host in scope, as one thing to select from.
|
|
187
|
+
* The usage page renders the host its picker is on as a scope of its own; everything outside it (the
|
|
188
|
+
* limit bars beside the work) reads the host around it, so browsing another host's spend never
|
|
189
|
+
* moves the bars that say how much of the plan the agents beside you have left.
|
|
190
|
+
*/
|
|
191
|
+
export type UsageView = Preferences & UsageRow;
|
|
192
|
+
|
|
193
|
+
export function useUsage<T>(select: (view: UsageView) => T): T {
|
|
194
|
+
const { id } = useChatScope();
|
|
195
|
+
return useUsageStore((s) => select({ period: s.period, metric: s.metric, currency: s.currency, ...(s.byScope[id] ?? EMPTY) }));
|
|
196
|
+
}
|
package/src/storage.ts
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { create, type StateCreator, type StoreApi, type UseBoundStore } from 'zustand';
|
|
2
|
+
|
|
3
|
+
export type ChatStorageRecord = 'drafts' | 'preferences' | 'stash' | 'usage';
|
|
4
|
+
|
|
5
|
+
export interface ChatStorageAdapter {
|
|
6
|
+
getItem(key: string): string | null;
|
|
7
|
+
setItem(key: string, value: string): void;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface ChatStorageOptions {
|
|
11
|
+
namespace?: string;
|
|
12
|
+
keys?: Partial<Record<ChatStorageRecord, string>>;
|
|
13
|
+
legacyNamespaces?: readonly string[];
|
|
14
|
+
legacyKeys?: Partial<Record<ChatStorageRecord, readonly string[]>>;
|
|
15
|
+
/* Null keeps values in memory; an omitted adapter uses browser storage on first use. */
|
|
16
|
+
storage?: ChatStorageAdapter | null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const SUFFIXES: Record<ChatStorageRecord, string> = {
|
|
20
|
+
drafts: 'chat.drafts',
|
|
21
|
+
preferences: 'chat.preferences',
|
|
22
|
+
stash: 'chat.stash',
|
|
23
|
+
usage: 'usage'
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
let options: ChatStorageOptions = {};
|
|
27
|
+
let hydrated = false;
|
|
28
|
+
const hydrators: Array<() => void> = [];
|
|
29
|
+
const configurationListeners: Array<() => void> = [];
|
|
30
|
+
|
|
31
|
+
export function onChatStorageConfiguration(listener: () => void): void {
|
|
32
|
+
configurationListeners.push(listener);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/* Configure once before using a store, so an imported component cannot read another host's records. */
|
|
36
|
+
export function configureChatStorage(configuration: ChatStorageOptions): void {
|
|
37
|
+
if (hydrated) {
|
|
38
|
+
throw new Error('Configure chat storage before using chat stores');
|
|
39
|
+
}
|
|
40
|
+
options = {
|
|
41
|
+
...configuration,
|
|
42
|
+
keys: { ...configuration.keys },
|
|
43
|
+
legacyNamespaces: [...(configuration.legacyNamespaces ?? [])],
|
|
44
|
+
legacyKeys: Object.fromEntries(Object.entries(configuration.legacyKeys ?? {}).map(([key, values]) => [key, [...values]]))
|
|
45
|
+
};
|
|
46
|
+
for (const listener of configurationListeners) {
|
|
47
|
+
listener();
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function chatStorageKey(record: ChatStorageRecord): string {
|
|
52
|
+
return options.keys?.[record] ?? `${options.namespace ?? 'adecore'}.${SUFFIXES[record]}`;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function chatStorageLegacyKeys(record: ChatStorageRecord): readonly string[] {
|
|
56
|
+
return [...(options.legacyKeys?.[record] ?? []), ...(options.legacyNamespaces ?? []).map((namespace) => `${namespace}.${SUFFIXES[record]}`)];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function chatStorageAdapter(): ChatStorageAdapter | null {
|
|
60
|
+
if (options.storage !== undefined) {
|
|
61
|
+
return options.storage;
|
|
62
|
+
}
|
|
63
|
+
try {
|
|
64
|
+
return globalThis.localStorage;
|
|
65
|
+
} catch {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function hydrateChatStorage(): void {
|
|
71
|
+
if (hydrated) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
hydrated = true;
|
|
75
|
+
for (const hydrate of hydrators) {
|
|
76
|
+
hydrate();
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function createChatStore<T>(initial: StateCreator<T>, hydrate: (store: StoreApi<T>) => void): UseBoundStore<StoreApi<T>> {
|
|
81
|
+
const store = create<T>(initial);
|
|
82
|
+
let initialized = false;
|
|
83
|
+
const hydrateOnce = (): void => {
|
|
84
|
+
if (initialized) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
initialized = true;
|
|
88
|
+
hydrate(store);
|
|
89
|
+
};
|
|
90
|
+
hydrators.push(hydrateOnce);
|
|
91
|
+
const useStore = ((...args: Parameters<typeof store>) => {
|
|
92
|
+
hydrateChatStorage();
|
|
93
|
+
hydrateOnce();
|
|
94
|
+
return store(...args);
|
|
95
|
+
}) as typeof store;
|
|
96
|
+
Object.assign(useStore, store);
|
|
97
|
+
useStore.getState = () => {
|
|
98
|
+
hydrateChatStorage();
|
|
99
|
+
hydrateOnce();
|
|
100
|
+
return store.getState();
|
|
101
|
+
};
|
|
102
|
+
useStore.subscribe = (...args) => {
|
|
103
|
+
hydrateChatStorage();
|
|
104
|
+
hydrateOnce();
|
|
105
|
+
return store.subscribe(...args);
|
|
106
|
+
};
|
|
107
|
+
useStore.setState = ((...args: Parameters<typeof store.setState>) => {
|
|
108
|
+
hydrateChatStorage();
|
|
109
|
+
hydrateOnce();
|
|
110
|
+
store.setState(...args);
|
|
111
|
+
}) as typeof store.setState;
|
|
112
|
+
return useStore;
|
|
113
|
+
}
|
package/src/theme.css
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* The chat of @adecore/agents-react, its providers and its usage: the tokens only they read and the
|
|
3
|
+
* rules they draw with. Imported right after `@adecore/ui/theme.css`; the app scans the package with
|
|
4
|
+
* `@source` and loads `@tailwindcss/typography`, which the markdown of a thread builds on.
|
|
5
|
+
*/
|
|
6
|
+
:root, [data-theme="light"] {
|
|
7
|
+
/* Skills read as a second kind of token next to a file mention, so they get their own hue. */
|
|
8
|
+
--skill: #9333ea;
|
|
9
|
+
--skill-soft: #f7eeff;
|
|
10
|
+
/* One color per agent CLI, so a bar, a dot and a legend row all name the same provider. Apple's
|
|
11
|
+
system orange and teal; Gemini and Copilot are reserved for the day their transcripts are read. */
|
|
12
|
+
--chart-claude: #ff9500;
|
|
13
|
+
--chart-codex: #30b0c7;
|
|
14
|
+
--chart-gemini: #3b82f6;
|
|
15
|
+
--chart-copilot: #64748b;
|
|
16
|
+
/* What a chat's context holds, one color per part; the rest is the system's and stays gray. */
|
|
17
|
+
--chart-context-tools: #4d7ce6;
|
|
18
|
+
--chart-context-files: #9a63e0;
|
|
19
|
+
--chart-context-conversation: #2f9e5a;
|
|
20
|
+
--chart-context-system: var(--text-faint);
|
|
21
|
+
/* The current hit of a find, which has to stand out from the accent of a bookmark next to it. */
|
|
22
|
+
--chat-find: #facc15;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
[data-theme="dark"] {
|
|
26
|
+
--skill: #c084fc;
|
|
27
|
+
--skill-soft: #2f2350;
|
|
28
|
+
--chart-claude: #ff9f0a;
|
|
29
|
+
--chart-codex: #40c8e0;
|
|
30
|
+
--chart-gemini: #60a5fa;
|
|
31
|
+
--chart-copilot: #94a3b8;
|
|
32
|
+
--chart-context-tools: #8aa7f5;
|
|
33
|
+
--chart-context-files: #b98af3;
|
|
34
|
+
--chart-context-conversation: #6dd08b;
|
|
35
|
+
--chart-context-system: var(--text-faint);
|
|
36
|
+
--chat-find: #f5c542;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/* Output and diffs take the terminal's colors when the app loads `@adecore/terminal/terminal.css`,
|
|
40
|
+
and the base theme's otherwise. Declared on every themed element, so a nested theme resolves its own. */
|
|
41
|
+
:root, [data-theme] {
|
|
42
|
+
--chat-code-bg: var(--term-bg, var(--surface-sunken));
|
|
43
|
+
--chat-output: var(--term-fg, var(--text));
|
|
44
|
+
--chat-added: var(--term-ansi-green, var(--positive));
|
|
45
|
+
--chat-removed: var(--term-ansi-red, var(--status-error));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
@theme inline {
|
|
49
|
+
--color-skill: var(--skill);
|
|
50
|
+
--color-skill-soft: var(--skill-soft);
|
|
51
|
+
--color-chart-claude: var(--chart-claude);
|
|
52
|
+
--color-chart-codex: var(--chart-codex);
|
|
53
|
+
--color-chart-gemini: var(--chart-gemini);
|
|
54
|
+
--color-chart-copilot: var(--chart-copilot);
|
|
55
|
+
--color-chart-context-tools: var(--chart-context-tools);
|
|
56
|
+
--color-chart-context-files: var(--chart-context-files);
|
|
57
|
+
--color-chart-context-conversation: var(--chart-context-conversation);
|
|
58
|
+
--color-chart-context-system: var(--chart-context-system);
|
|
59
|
+
--color-chat-find: var(--chat-find);
|
|
60
|
+
--color-chat-output: var(--chat-output);
|
|
61
|
+
--color-chat-added: var(--chat-added);
|
|
62
|
+
--color-chat-removed: var(--chat-removed);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
@layer components {
|
|
66
|
+
/* ---------------------------------------------------------------- Chat */
|
|
67
|
+
|
|
68
|
+
/* Text in a chat is there to be read and copied, so the thread selects even though the app does
|
|
69
|
+
not. Its chrome stays out of it: a drag on a fold header or a chip would select the row.
|
|
70
|
+
The pretty wrap from `body` would be recomputed on the growing paragraph every frame a reply
|
|
71
|
+
streams, so the thread wraps the plain way.
|
|
72
|
+
The gaps are the air a thread needs to read as turns: the step from a question to its answer,
|
|
73
|
+
and the wider step from the end of one turn to the next question. A view of its own gets more
|
|
74
|
+
of both, the way its type does. The block gap is the step inside a turn, where a run of tool
|
|
75
|
+
lines meets prose or a card. */
|
|
76
|
+
.chat-thread { user-select: text; text-wrap-style: auto; --chat-answer-gap: 16px; --chat-turn-gap: 24px; --chat-block-gap: 12px; }
|
|
77
|
+
.chat-column .chat-thread { --chat-answer-gap: 20px; --chat-turn-gap: 32px; --chat-block-gap: 16px; }
|
|
78
|
+
.chat-thread button, .chat-thread kbd { user-select: none; }
|
|
79
|
+
|
|
80
|
+
/*
|
|
81
|
+
* A chat that is a view of its own reads in a column. The scroller keeps the full width of the
|
|
82
|
+
* main column, so its scrollbar sits at that column's right edge and nothing jumps when the
|
|
83
|
+
* thread grows past a screenful; only the rows and the composer inside it are centered.
|
|
84
|
+
*/
|
|
85
|
+
.chat-column .chat-column-content { margin-inline: auto; max-width: 768px; }
|
|
86
|
+
/* Wider by the input's inset (`.composer-input .cm-content` padding plus the card's border), so what is typed lines up with the thread. */
|
|
87
|
+
.chat-column .chat-composer-content { margin-inline: auto; max-width: calc(768px + 2 * 21px); }
|
|
88
|
+
|
|
89
|
+
/* A diff inside a chat tool block; the library paints its own colors inside a shadow root and
|
|
90
|
+
takes the face it draws them in through these variables. */
|
|
91
|
+
.chat-diff { font-size: var(--text-code); --diffs-font-size: var(--text-code); --diffs-font-family: var(--font-mono); }
|
|
92
|
+
.chat-diff + .chat-diff { border-top: 1px solid var(--border); }
|
|
93
|
+
|
|
94
|
+
/* Live tool rows shine once across; a paused animation costs nothing. */
|
|
95
|
+
.chat-live-text {
|
|
96
|
+
background: linear-gradient(90deg, var(--text-muted) 0%, var(--text) 50%, var(--text-muted) 100%);
|
|
97
|
+
background-size: 200% 100%;
|
|
98
|
+
-webkit-background-clip: text;
|
|
99
|
+
background-clip: text;
|
|
100
|
+
color: transparent;
|
|
101
|
+
animation: chat-shine 1.6s linear infinite;
|
|
102
|
+
}
|
|
103
|
+
@keyframes chat-shine { from { background-position: 200% 0; } to { background-position: -200% 0; } }
|
|
104
|
+
|
|
105
|
+
/* A word of a reply that just arrived. The duration is REVEAL_FADE_MS in chat/ui/reveal.ts, which
|
|
106
|
+
keeps the spans until it is over; ease-in-out, because ease-out jumps up and then trails. */
|
|
107
|
+
.chat-fade { animation: chat-fade 300ms ease-in-out both; }
|
|
108
|
+
/* A whole reply that was written out of sight. */
|
|
109
|
+
.chat-fade-whole { animation: chat-fade 220ms ease-out both; }
|
|
110
|
+
/* A block of a reply streamed a block at a time, faded in when it is inserted and never when a
|
|
111
|
+
finished thread opens, which carries no `data-arriving`. */
|
|
112
|
+
.chat-markdown[data-arriving] > * {
|
|
113
|
+
transition: opacity 300ms ease-in-out;
|
|
114
|
+
@starting-style { opacity: 0; }
|
|
115
|
+
}
|
|
116
|
+
@keyframes chat-fade { from { opacity: 0; } to { opacity: 1; } }
|
|
117
|
+
|
|
118
|
+
/* The row a jump from outside the chat (the card of a change in a file) landed on. */
|
|
119
|
+
.chat-flash { animation: chat-flash 1600ms ease-out both; }
|
|
120
|
+
@keyframes chat-flash {
|
|
121
|
+
from { background: color-mix(in srgb, var(--accent) 18%, transparent); }
|
|
122
|
+
to { background: transparent; }
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/*
|
|
127
|
+
* Markdown, outside every layer on purpose. The typography plugin registers `.prose` as a utility,
|
|
128
|
+
* and a later layer beats an earlier one whatever the specificity, so a rule that has to outrank
|
|
129
|
+
* prose cannot live in `components`. Unlayered styles win over every layer, which is the one
|
|
130
|
+
* place the app's tokens and scale are sure to land on top of the plugin's.
|
|
131
|
+
*/
|
|
132
|
+
/*
|
|
133
|
+
* Markdown anywhere in the app: the chat timeline, a note node and the file preview all render
|
|
134
|
+
* the same `Markdown` component, which carries `prose prose-sm max-w-none text-sm` next to this
|
|
135
|
+
* class. Prose brings the rhythm; everything here is what the app decides instead of the plugin.
|
|
136
|
+
* The semantic tokens flip with the theme on their own, so the prose variables read from them
|
|
137
|
+
* and `prose-invert` is a second source of truth the app does not need. The size comes from the
|
|
138
|
+
* `text-sm` utility, which a node, a view and the file preview each move.
|
|
139
|
+
*/
|
|
140
|
+
.prose.chat-markdown {
|
|
141
|
+
--tw-prose-body: var(--text);
|
|
142
|
+
--tw-prose-headings: var(--text);
|
|
143
|
+
--tw-prose-lead: var(--text-muted);
|
|
144
|
+
--tw-prose-links: var(--accent);
|
|
145
|
+
--tw-prose-bold: var(--text);
|
|
146
|
+
--tw-prose-counters: var(--text-faint);
|
|
147
|
+
--tw-prose-bullets: var(--text-faint);
|
|
148
|
+
--tw-prose-hr: var(--border);
|
|
149
|
+
--tw-prose-quotes: var(--text);
|
|
150
|
+
--tw-prose-quote-borders: var(--border);
|
|
151
|
+
--tw-prose-captions: var(--text-muted);
|
|
152
|
+
--tw-prose-kbd: var(--text);
|
|
153
|
+
--tw-prose-code: var(--text);
|
|
154
|
+
--tw-prose-pre-code: var(--text);
|
|
155
|
+
--tw-prose-pre-bg: var(--surface-sunken);
|
|
156
|
+
--tw-prose-th-borders: var(--border);
|
|
157
|
+
--tw-prose-td-borders: var(--border);
|
|
158
|
+
}
|
|
159
|
+
/* Headings stay on the app's scale, which is flatter than the one prose brings. */
|
|
160
|
+
.chat-markdown :is(h1, h2, h3, h4) { font-weight: 600; line-height: round(1.3em, 1px); }
|
|
161
|
+
.chat-markdown h1 { font-size: var(--text-lg); }
|
|
162
|
+
.chat-markdown h2 { font-size: var(--text-base); }
|
|
163
|
+
.chat-markdown :is(h3, h4) { font-size: var(--text-sm); }
|
|
164
|
+
.chat-markdown a { text-underline-offset: 2px; }
|
|
165
|
+
/* Code is the app's own: `--text-code` at every depth, and none of the quotes prose puts around
|
|
166
|
+
inline code, since the chip the component draws already says what it is. */
|
|
167
|
+
.chat-markdown code { font-size: var(--text-code); font-weight: 400; }
|
|
168
|
+
.chat-markdown code::before, .chat-markdown code::after { content: none; }
|
|
169
|
+
/* A checked box is the marker; prose would put a bullet next to it. */
|
|
170
|
+
.chat-markdown li:has(> input[type="checkbox"]) { list-style: none; }
|
|
171
|
+
.chat-markdown input[type="checkbox"] { margin-right: 6px; accent-color: var(--accent); }
|
|
172
|
+
/* A wide table scrolls in its own wrapper instead of stretching the column it sits in. The
|
|
173
|
+
wrapper is a scroll container, so the air around the table has to sit on it, not inside it. */
|
|
174
|
+
.chat-table { overflow-x: auto; margin-block: 2em; }
|
|
175
|
+
.chat-markdown table { margin: 0; border-collapse: collapse; font-size: var(--text-xs); }
|
|
176
|
+
.chat-markdown :is(th, td) { border: 1px solid var(--tw-prose-td-borders); padding: 4px 8px; text-align: left; }
|
|
177
|
+
|
|
178
|
+
/* A code block is shiki's own `<pre>`, which brings a background of its own to override. */
|
|
179
|
+
.chat-code { border-radius: 8px; border: 1px solid var(--border); background: var(--chat-code-bg); overflow: auto; }
|
|
180
|
+
.chat-code pre { margin: 0; padding: round(0.625rem, 1px) round(0.75rem, 1px); background: transparent !important; font-family: var(--font-mono); font-size: var(--text-code); line-height: var(--text-code--line-height); }
|
|
181
|
+
.chat-code code { font-family: inherit; }
|
|
182
|
+
|
|
183
|
+
/* The chat composer is a CodeMirror editor, whose base theme lands in an unlayered style tag at
|
|
184
|
+
mount. These rules stay unlayered too, and carry one class more than the theme's selectors. */
|
|
185
|
+
.composer-input .cm-editor { max-height: 200px; }
|
|
186
|
+
.composer-input .cm-editor.cm-focused { outline: none; }
|
|
187
|
+
.composer-input .cm-editor .cm-scroller { overflow: auto; font-family: inherit; line-height: inherit; }
|
|
188
|
+
.composer-input .cm-editor .cm-scroller .cm-content { padding: 18px 14px 6px 20px; caret-color: var(--text); }
|
|
189
|
+
.composer-input .cm-scroller .cm-content .cm-line { padding: 0; }
|
|
190
|
+
.composer-input .cm-scroller .cm-content .cm-placeholder { color: var(--text-faint); }
|
|
191
|
+
.composer-hints, .composer-hints-extra { display: inline-flex; align-items: center; gap: 8px; white-space: nowrap; }
|
|
192
|
+
/* The joiner starts with its own comma, so it sits against the lead without the gap. */
|
|
193
|
+
.composer-hints-extra { margin-left: -8px; }
|
|
194
|
+
.composer-hints kbd { padding: 0 6px; border-radius: 5px; background: var(--surface-active); color: var(--text-muted); font-family: var(--font-mono); font-size: var(--text-code); line-height: var(--text-code--line-height); }
|
|
195
|
+
/* The widths of Tailwind's `@md` container variant, which the rest of the composer narrows at. */
|
|
196
|
+
@container composer (width < 28rem) {
|
|
197
|
+
.composer-input .cm-editor .cm-scroller .cm-content { padding: 14px 12px 4px 14px; }
|
|
198
|
+
}
|
|
199
|
+
/* The hints stay on the line of the lead or go; wrapped, they would start left of the text. */
|
|
200
|
+
@container composer (width < 36rem) {
|
|
201
|
+
.composer-hints-extra { display: none; }
|
|
202
|
+
}
|
|
203
|
+
/* Markdown stays source while you type: the markers stay put and dim, and what they wrap takes its look. */
|
|
204
|
+
.composer-input .cm-md-mark { color: var(--text-faint); }
|
|
205
|
+
.composer-input .cm-md-strong, .composer-input .cm-md-heading { font-weight: 600; }
|
|
206
|
+
.composer-input .cm-md-emphasis { font-style: italic; }
|
|
207
|
+
.composer-input .cm-md-strike { text-decoration: line-through; }
|
|
208
|
+
.composer-input .cm-md-link { color: var(--accent); text-decoration: underline; }
|
|
209
|
+
.composer-input .cm-md-code { padding: 1px 2px; border-radius: 4px; background: var(--surface-sunken); font-family: var(--font-mono); font-size: var(--text-code); }
|
|
210
|
+
.composer-input .cm-content .cm-line.cm-md-fence { padding: 0 8px; background: var(--surface-sunken); font-family: var(--font-mono); font-size: var(--text-code); }
|
|
211
|
+
.composer-input .cm-content .cm-line.cm-md-fence-start { padding-top: 4px; border-top-left-radius: 6px; border-top-right-radius: 6px; }
|
|
212
|
+
.composer-input .cm-content .cm-line.cm-md-fence-end { padding-bottom: 4px; border-bottom-left-radius: 6px; border-bottom-right-radius: 6px; }
|
package/src/transport.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { z } from 'zod';
|
|
2
|
+
import type { AGENT_EVENT_SCHEMAS, AGENT_REQUEST_SCHEMAS, AgentEventType, AgentRequestType } from '@adecore/agent-contracts/protocol';
|
|
3
|
+
|
|
4
|
+
export type ChatRequestMap = {
|
|
5
|
+
[T in AgentRequestType]: {
|
|
6
|
+
payload: z.infer<(typeof AGENT_REQUEST_SCHEMAS)[T]['payload']>;
|
|
7
|
+
result: z.infer<(typeof AGENT_REQUEST_SCHEMAS)[T]['result']>;
|
|
8
|
+
};
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type ChatEventMap = {
|
|
12
|
+
[E in AgentEventType]: z.infer<(typeof AGENT_EVENT_SCHEMAS)[E]>;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export type ChatTransportStatus = 'connecting' | 'open' | 'closed';
|
|
16
|
+
|
|
17
|
+
/*
|
|
18
|
+
* What the chat, its providers and their usage need of whatever runs the chats: a request with its
|
|
19
|
+
* typed answer, the events, and whether the link is up. A link that comes back is a fresh one to the
|
|
20
|
+
* host, so everything that holds state there says it again when the status turns `open`. An app that
|
|
21
|
+
* talks to several hosts has one of these per host; nothing here assumes there is only one.
|
|
22
|
+
*/
|
|
23
|
+
export interface ChatTransport {
|
|
24
|
+
request<T extends AgentRequestType>(type: T, payload: ChatRequestMap[T]['payload']): Promise<ChatRequestMap[T]['result']>;
|
|
25
|
+
on<E extends AgentEventType>(event: E, handler: (payload: ChatEventMap[E]) => void): () => void;
|
|
26
|
+
readonly status: ChatTransportStatus;
|
|
27
|
+
subscribeStatus(handler: (status: ChatTransportStatus) => void): () => void;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/* A refused request always carries a code, so a caller branches on it instead of on the message. */
|
|
31
|
+
export class ChatTransportError extends Error {
|
|
32
|
+
readonly code: string;
|
|
33
|
+
|
|
34
|
+
constructor(code: string, message: string) {
|
|
35
|
+
super(message);
|
|
36
|
+
this.name = 'ChatTransportError';
|
|
37
|
+
this.code = code;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/* The code of a refusal from any transport, this package's or the app's own: every one of them carries it the same way. */
|
|
42
|
+
export function errorCode(error: unknown): string | null {
|
|
43
|
+
return typeof error === 'object' && error !== null && 'code' in error && typeof error.code === 'string' ? error.code : null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/* Whether a request failed because the link was down rather than because the host refused it; the reconnect asks again. */
|
|
47
|
+
export function isConnectionError(error: unknown): boolean {
|
|
48
|
+
const code = errorCode(error);
|
|
49
|
+
return code === 'not-connected' || code === 'disconnected';
|
|
50
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { TextareaProps } from '../host';
|
|
2
|
+
|
|
3
|
+
/* The field a written answer goes in when the app brings no dictation of its own. */
|
|
4
|
+
export function PlainTextarea({ buttonClassName: _buttonClassName, ...props }: TextareaProps) {
|
|
5
|
+
return <textarea {...props} />;
|
|
6
|
+
}
|