@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,84 @@
|
|
|
1
|
+
import type { ChatQuestion, ChatQuestionItem, ChatApprovalItem } from '@adecore/agent-contracts';
|
|
2
|
+
import type { PendingPrompt } from './prompts';
|
|
3
|
+
|
|
4
|
+
const endpoints: ChatQuestion = {
|
|
5
|
+
id: 'endpoints',
|
|
6
|
+
header: 'Shared backoff',
|
|
7
|
+
question: 'Which endpoints should share the backoff?',
|
|
8
|
+
multiSelect: false,
|
|
9
|
+
choices: [
|
|
10
|
+
{ label: 'All three', description: 'Chat, files and terminal' },
|
|
11
|
+
{ label: 'Only chat and files', description: 'Keep terminal retries separate' }
|
|
12
|
+
]
|
|
13
|
+
};
|
|
14
|
+
const checks: ChatQuestion = {
|
|
15
|
+
id: 'checks',
|
|
16
|
+
header: 'Validation',
|
|
17
|
+
question: 'Which checks should run before the change is ready?',
|
|
18
|
+
multiSelect: true,
|
|
19
|
+
choices: [
|
|
20
|
+
{ label: 'Type check', description: 'Check all workspaces' },
|
|
21
|
+
{ label: 'Unit tests', description: 'Run the targeted tests' },
|
|
22
|
+
{ label: 'Build', description: 'Verify the production bundle' }
|
|
23
|
+
]
|
|
24
|
+
};
|
|
25
|
+
const notes: ChatQuestion = { id: 'notes', header: 'Instructions', question: 'What else should the agent keep in mind?', multiSelect: false, choices: [] };
|
|
26
|
+
function base(id: string) {
|
|
27
|
+
return { id: `preview-${id}`, requestId: `preview-${id}`, createdAt: 0, turnId: null };
|
|
28
|
+
}
|
|
29
|
+
function question(id: string, questions: ChatQuestion[], async = false): ChatQuestionItem {
|
|
30
|
+
return {
|
|
31
|
+
...base(id),
|
|
32
|
+
kind: 'question',
|
|
33
|
+
questions,
|
|
34
|
+
answers: null,
|
|
35
|
+
state: 'pending',
|
|
36
|
+
async
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function approval(long = false): ChatApprovalItem {
|
|
40
|
+
return {
|
|
41
|
+
...base(long ? 'long' : 'edit'),
|
|
42
|
+
kind: 'approval',
|
|
43
|
+
toolUseId: null,
|
|
44
|
+
toolName: 'Edit',
|
|
45
|
+
description: 'Replace the reconnect loop with the shared backoff and export it for the three endpoints.',
|
|
46
|
+
input: {
|
|
47
|
+
file_path: 'src/transport/pool.ts',
|
|
48
|
+
old_string: 'const retries = 10;',
|
|
49
|
+
new_string:
|
|
50
|
+
'const retries = 5;\nexport const backoff = createBackoff({ max: retries });' +
|
|
51
|
+
(long ? '\n' + Array.from({ length: 90 }, (_, i) => `// Context line ${i + 1}`).join('\n') : '')
|
|
52
|
+
},
|
|
53
|
+
canAllowAlways: false,
|
|
54
|
+
decision: 'pending'
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// These never enter the chat store or the transport; the preview owns their lifetime.
|
|
59
|
+
export const PROMPT_SAMPLES: Array<{ label: string; items: PendingPrompt[] }> = [
|
|
60
|
+
{ label: 'Permission · File edit', items: [approval()] },
|
|
61
|
+
{
|
|
62
|
+
label: 'Permission · Command',
|
|
63
|
+
items: [
|
|
64
|
+
{
|
|
65
|
+
...base('command'),
|
|
66
|
+
kind: 'approval',
|
|
67
|
+
toolName: 'Bash',
|
|
68
|
+
toolUseId: null,
|
|
69
|
+
input: { command: 'bun run check && bun test', cwd: '/projects/ruimte' },
|
|
70
|
+
description: "Run the project's validation checks before continuing.",
|
|
71
|
+
canAllowAlways: true,
|
|
72
|
+
allowAlways: { label: 'Allow for this session', description: 'Allow commands in this session until it ends.' },
|
|
73
|
+
decision: 'pending'
|
|
74
|
+
}
|
|
75
|
+
]
|
|
76
|
+
},
|
|
77
|
+
{ label: 'Permission · Long diff', items: [approval(true)] },
|
|
78
|
+
{ label: 'Question · Single choice', items: [question('single', [endpoints])] },
|
|
79
|
+
{ label: 'Question · Multiple choices', items: [question('multiple', [checks])] },
|
|
80
|
+
{ label: 'Question · Written answer', items: [question('written', [notes])] },
|
|
81
|
+
{ label: 'Question · Three questions', items: [question('questions', [endpoints, checks, notes])] },
|
|
82
|
+
{ label: 'Question · Optional', items: [question('optional', [endpoints], true)] },
|
|
83
|
+
{ label: 'Several requests', items: [question('optional', [endpoints], true), approval(), question('single', [endpoints])] }
|
|
84
|
+
];
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { ChatApprovalItem, ChatQuestionItem, ChatQuestion } from '@adecore/agent-contracts';
|
|
2
|
+
import { toggleChoice } from '../../chat/logic/answers';
|
|
3
|
+
|
|
4
|
+
export type PendingPrompt = ChatApprovalItem | ChatQuestionItem;
|
|
5
|
+
export type PromptAction =
|
|
6
|
+
| { kind: 'approve'; decision: 'allow' | 'allow-always' | 'deny'; message?: string }
|
|
7
|
+
| { kind: 'answer'; answers: Record<string, string> }
|
|
8
|
+
| { kind: 'dismiss' }
|
|
9
|
+
// A terminal's permission request, answered with one of the choices the host offered.
|
|
10
|
+
| { kind: 'choose'; choiceId: string };
|
|
11
|
+
export interface PromptAnswer {
|
|
12
|
+
choices: string[];
|
|
13
|
+
text: string;
|
|
14
|
+
custom: boolean;
|
|
15
|
+
}
|
|
16
|
+
export interface PromptDraft {
|
|
17
|
+
index: number;
|
|
18
|
+
answers: Record<string, PromptAnswer>;
|
|
19
|
+
reason: string;
|
|
20
|
+
showReason: boolean;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function emptyPromptDraft(): PromptDraft {
|
|
24
|
+
return { index: 0, answers: {}, reason: '', showReason: false };
|
|
25
|
+
}
|
|
26
|
+
export function answerValue(answer: PromptAnswer): string {
|
|
27
|
+
return answer.custom ? answer.text.trim() : answer.choices.join(', ');
|
|
28
|
+
}
|
|
29
|
+
export function questionAnswer(draft: PromptDraft, question: ChatQuestion): PromptAnswer {
|
|
30
|
+
return draft.answers[question.id] ?? { choices: [], text: '', custom: question.choices.length === 0 };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function pickPromptChoice(answer: PromptAnswer, question: ChatQuestion, label: string): PromptAnswer {
|
|
34
|
+
return { ...answer, custom: false, choices: question.multiSelect ? toggleChoice(answer.choices, label) : [label] };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/* An optional question never stands in front of a request that holds the agent up. */
|
|
38
|
+
export function isBlockingPrompt(item: PendingPrompt): boolean {
|
|
39
|
+
return item.kind === 'approval' || !item.async;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/* Blocking prompts first and optional ones after, each oldest first. The chat and a canvas's stack both follow it. */
|
|
43
|
+
export function orderPrompts<T>(prompts: readonly T[], blocking: (prompt: T) => boolean, createdAt: (prompt: T) => number): T[] {
|
|
44
|
+
return [...prompts].sort((a, b) => Number(blocking(b)) - Number(blocking(a)) || createdAt(a) - createdAt(b));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function nextPrompt(items: readonly PendingPrompt[], activeId: string | null): PendingPrompt | null {
|
|
48
|
+
const active = items.find((item) => item.requestId === activeId);
|
|
49
|
+
if (active) {
|
|
50
|
+
return active;
|
|
51
|
+
}
|
|
52
|
+
return orderPrompts(items, isBlockingPrompt, (item) => item.createdAt)[0] ?? null;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function promptAnswers(item: ChatQuestionItem, draft: PromptDraft): Record<string, string> | null {
|
|
56
|
+
const answers = Object.fromEntries(item.questions.map((question) => [question.id, answerValue(questionAnswer(draft, question))]));
|
|
57
|
+
return Object.values(answers).every((answer) => answer !== '') ? answers : null;
|
|
58
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import i18next from 'i18next';
|
|
2
|
+
import type { ReactNode } from 'react';
|
|
3
|
+
import { chatHost } from '../../host';
|
|
4
|
+
import { isBlockingPrompt, type PendingPrompt, type PromptAction, type PromptDraft } from './prompts';
|
|
5
|
+
|
|
6
|
+
/*
|
|
7
|
+
* A prompt the app raises beside a chat's own requests, such as its own approval to operate
|
|
8
|
+
* something. The app draws it and answers it (`ChatHost.prompts`); the chat only orders it among the
|
|
9
|
+
* rest and keeps its draft.
|
|
10
|
+
*/
|
|
11
|
+
export interface HostPrompt {
|
|
12
|
+
/* Unique across the prompts of a surface, and stable while the prompt waits. */
|
|
13
|
+
id: string;
|
|
14
|
+
createdAt: number;
|
|
15
|
+
blocking: boolean;
|
|
16
|
+
/* The mark a pointer to it wears: a hand for a request, a question mark for anything else. */
|
|
17
|
+
asks: 'approval' | 'question';
|
|
18
|
+
/* What the app knows about it, for its own drawing and answering; the same object while nothing about it changed. */
|
|
19
|
+
data: unknown;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/* What a prompt card draws, whatever asked it. The chat's items pass through unchanged. */
|
|
23
|
+
export type PromptSubject = { kind: 'chat'; nodeId: string; item: PendingPrompt } | { kind: 'host'; nodeId: string; prompt: HostPrompt };
|
|
24
|
+
|
|
25
|
+
/* The requests a chat's own prompts are answered with. */
|
|
26
|
+
export interface ChatPromptClients {
|
|
27
|
+
approve(chatId: string, requestId: string, decision: 'allow' | 'allow-always' | 'deny', message?: string): Promise<void>;
|
|
28
|
+
answer(chatId: string, requestId: string, answers: Record<string, string>): Promise<void>;
|
|
29
|
+
dismiss(chatId: string, itemId: string): Promise<void>;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/* What a card is given to draw, the chat's and the app's alike. */
|
|
33
|
+
export interface PromptViewProps {
|
|
34
|
+
subject: PromptSubject;
|
|
35
|
+
draft: PromptDraft;
|
|
36
|
+
onDraft(draft: PromptDraft): void;
|
|
37
|
+
onAction(action: PromptAction): void;
|
|
38
|
+
more: number;
|
|
39
|
+
hasDraft: boolean;
|
|
40
|
+
denyReason: boolean;
|
|
41
|
+
disabled: boolean;
|
|
42
|
+
sending: boolean;
|
|
43
|
+
error: string | null;
|
|
44
|
+
top?: ReactNode;
|
|
45
|
+
/* Takes the person to whatever an app's own card is about. */
|
|
46
|
+
onReveal?: () => void;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface ApprovalButtonSpec {
|
|
50
|
+
id: string;
|
|
51
|
+
label: string;
|
|
52
|
+
description?: string;
|
|
53
|
+
primary: boolean;
|
|
54
|
+
/* Grants beyond this one request, so the keyboard never starts on it. */
|
|
55
|
+
lasting?: boolean;
|
|
56
|
+
action: PromptAction;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/* Unique across the chats of a surface and the app's own prompts, and stable while the prompt waits. */
|
|
60
|
+
export function promptIdOf(subject: PromptSubject): string {
|
|
61
|
+
return subject.kind === 'chat' ? `agent-chat:${subject.nodeId}:${subject.item.requestId}` : subject.prompt.id;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function promptCreatedAt(subject: PromptSubject): number {
|
|
65
|
+
return subject.kind === 'chat' ? subject.item.createdAt : subject.prompt.createdAt;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/* Only a chat's optional question does not hold anything up; the app says so of its own. */
|
|
69
|
+
export function isBlockingSubject(subject: PromptSubject): boolean {
|
|
70
|
+
return subject.kind === 'chat' ? isBlockingPrompt(subject.item) : subject.prompt.blocking;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/* The buttons of a chat's permission request in the order it draws them: a remembered rule, Deny, then Allow as the primary. */
|
|
74
|
+
export function approvalButtons(subject: PromptSubject, reason: string): ApprovalButtonSpec[] {
|
|
75
|
+
if (subject.kind !== 'chat' || subject.item.kind !== 'approval') {
|
|
76
|
+
return [];
|
|
77
|
+
}
|
|
78
|
+
const { item } = subject;
|
|
79
|
+
const message = reason.trim();
|
|
80
|
+
return [
|
|
81
|
+
...(item.canAllowAlways && item.allowAlways
|
|
82
|
+
? [
|
|
83
|
+
{
|
|
84
|
+
id: 'allow-always',
|
|
85
|
+
label: item.allowAlways.label,
|
|
86
|
+
description: item.allowAlways.description,
|
|
87
|
+
primary: false,
|
|
88
|
+
lasting: true,
|
|
89
|
+
action: { kind: 'approve', decision: 'allow-always' } as const
|
|
90
|
+
}
|
|
91
|
+
]
|
|
92
|
+
: []),
|
|
93
|
+
{
|
|
94
|
+
id: 'deny',
|
|
95
|
+
label: i18next.t('agent-prompts:approval.deny'),
|
|
96
|
+
primary: false,
|
|
97
|
+
action: { kind: 'approve', decision: 'deny', ...(message ? { message } : {}) }
|
|
98
|
+
},
|
|
99
|
+
{ id: 'allow', label: i18next.t('agent-prompts:approval.allow'), primary: true, action: { kind: 'approve', decision: 'allow' } }
|
|
100
|
+
];
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/* Sends a card's action as the request its subject is answered with. A refusal comes back as an error for the card to show. */
|
|
104
|
+
export async function answerPrompt(subject: PromptSubject, action: PromptAction, chat: ChatPromptClients | null): Promise<void> {
|
|
105
|
+
if (subject.kind === 'host') {
|
|
106
|
+
return chatHost().prompts.answer(subject.prompt, action);
|
|
107
|
+
}
|
|
108
|
+
if (chat === null) {
|
|
109
|
+
throw new Error(i18next.t('agent-prompts:error.notConnected'));
|
|
110
|
+
}
|
|
111
|
+
const { item, nodeId } = subject;
|
|
112
|
+
if (action.kind === 'approve') {
|
|
113
|
+
return chat.approve(nodeId, item.requestId, action.decision, action.message);
|
|
114
|
+
}
|
|
115
|
+
if (action.kind === 'answer') {
|
|
116
|
+
return chat.answer(nodeId, item.requestId, action.answers);
|
|
117
|
+
}
|
|
118
|
+
if (action.kind === 'dismiss') {
|
|
119
|
+
return chat.dismiss(nodeId, item.id);
|
|
120
|
+
}
|
|
121
|
+
throw new Error(i18next.t('agent-prompts:error.noChoices'));
|
|
122
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { useEffect, useRef, type RefObject } from 'react';
|
|
2
|
+
import { focusPromptStart } from './focus';
|
|
3
|
+
|
|
4
|
+
export interface FocusAfterAnswer {
|
|
5
|
+
/* Called before the front card changes, to remember whether the keyboard is in it, since the card is gone by the time the next one shows. */
|
|
6
|
+
hold(): void;
|
|
7
|
+
/* The card stays after all, as when its answer failed. */
|
|
8
|
+
release(): void;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/*
|
|
12
|
+
* The keyboard stays with the prompts it was answering: on where the card that comes next is answered, or
|
|
13
|
+
* wherever `onEmpty` puts it once none is left. A card answered with the keyboard elsewhere takes nothing.
|
|
14
|
+
*/
|
|
15
|
+
export function useFocusAfterAnswer(activeId: string | null, container: RefObject<HTMLElement | null>, onEmpty: () => void): FocusAfterAnswer {
|
|
16
|
+
const pending = useRef(false);
|
|
17
|
+
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
if (!pending.current) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
pending.current = false;
|
|
23
|
+
if (!focusPromptStart(container.current)) {
|
|
24
|
+
onEmpty();
|
|
25
|
+
}
|
|
26
|
+
// Only a change of the front card is news; a new `onEmpty` each render is not.
|
|
27
|
+
// oxlint-disable-next-line react-hooks/exhaustive-deps
|
|
28
|
+
}, [activeId]);
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
hold: () => {
|
|
32
|
+
pending.current = container.current?.contains(document.activeElement) === true;
|
|
33
|
+
},
|
|
34
|
+
release: () => {
|
|
35
|
+
pending.current = false;
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { useRef, useState, type MouseEvent } from 'react';
|
|
2
|
+
import { emptyPromptDraft, type PromptDraft } from './prompts';
|
|
3
|
+
|
|
4
|
+
interface PromptSessionOptions<T> {
|
|
5
|
+
prompts: readonly T[];
|
|
6
|
+
idOf(prompt: T): string;
|
|
7
|
+
/* Which waiting prompt is in front, given the one that was and where it stood; a new prompt never takes the place of the one being read. */
|
|
8
|
+
pick(waiting: readonly T[], activeId: string | null, activeIndex: number): T | null;
|
|
9
|
+
disabled: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface PromptSession<T> {
|
|
13
|
+
active: T | null;
|
|
14
|
+
activeId: string | null;
|
|
15
|
+
/* Where the active prompt stands among the waiting ones. */
|
|
16
|
+
index: number;
|
|
17
|
+
/* The prompts not answered yet from this card, in the order they came in. */
|
|
18
|
+
waiting: readonly T[];
|
|
19
|
+
setActive(id: string): void;
|
|
20
|
+
draftOf(id: string): PromptDraft;
|
|
21
|
+
setDraft(id: string, draft: PromptDraft): void;
|
|
22
|
+
sending: boolean;
|
|
23
|
+
errorOf(id: string): string | null;
|
|
24
|
+
/* `busy` when another answer is still on its way, so this one was never sent. */
|
|
25
|
+
act(prompt: T, send: () => Promise<void>): Promise<'sent' | 'failed' | 'busy'>;
|
|
26
|
+
onPointerDownCapture(): void;
|
|
27
|
+
onClickCapture(event: MouseEvent): void;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/*
|
|
31
|
+
* What answering a row of prompts needs besides the prompts: a draft per request that survives
|
|
32
|
+
* paging, one send at a time, the error of the request that failed, and the requests answered here
|
|
33
|
+
* that the machine has not taken off yet.
|
|
34
|
+
*/
|
|
35
|
+
export function usePromptSession<T>({ prompts, idOf, pick, disabled }: PromptSessionOptions<T>): PromptSession<T> {
|
|
36
|
+
const [activeId, setActiveId] = useState<string | null>(null);
|
|
37
|
+
const [activeIndex, setActiveIndex] = useState(0);
|
|
38
|
+
const [completed, setCompleted] = useState<string[]>([]);
|
|
39
|
+
const [drafts, setDrafts] = useState<Record<string, PromptDraft>>({});
|
|
40
|
+
const [sending, setSending] = useState(false);
|
|
41
|
+
const [error, setError] = useState<{ id: string; message: string } | null>(null);
|
|
42
|
+
const busy = useRef(false);
|
|
43
|
+
const pressedRequest = useRef<string | null>(null);
|
|
44
|
+
const stillCompleted = completed.filter((id) => prompts.some((prompt) => idOf(prompt) === id));
|
|
45
|
+
if (stillCompleted.length !== completed.length) {
|
|
46
|
+
setCompleted(stillCompleted);
|
|
47
|
+
}
|
|
48
|
+
const waiting = prompts.filter((prompt) => !completed.includes(idOf(prompt)));
|
|
49
|
+
const active = pick(waiting, activeId, activeIndex);
|
|
50
|
+
const activeKey = active === null ? null : idOf(active);
|
|
51
|
+
const index = active === null ? 0 : waiting.indexOf(active);
|
|
52
|
+
if (index !== activeIndex) {
|
|
53
|
+
setActiveIndex(index);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (activeKey !== activeId) {
|
|
57
|
+
setActiveId(activeKey);
|
|
58
|
+
setError(null);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const finish = (id: string) => {
|
|
62
|
+
setCompleted((current) => [...current, id]);
|
|
63
|
+
setDrafts((current) => {
|
|
64
|
+
const next = { ...current };
|
|
65
|
+
delete next[id];
|
|
66
|
+
return next;
|
|
67
|
+
});
|
|
68
|
+
};
|
|
69
|
+
const act = async (prompt: T, send: () => Promise<void>): Promise<'sent' | 'failed' | 'busy'> => {
|
|
70
|
+
if (busy.current || disabled) {
|
|
71
|
+
return 'busy';
|
|
72
|
+
}
|
|
73
|
+
const id = idOf(prompt);
|
|
74
|
+
busy.current = true;
|
|
75
|
+
setSending(true);
|
|
76
|
+
setError(null);
|
|
77
|
+
try {
|
|
78
|
+
await send();
|
|
79
|
+
finish(id);
|
|
80
|
+
return 'sent';
|
|
81
|
+
} catch (cause) {
|
|
82
|
+
setError({ id, message: cause instanceof Error ? cause.message : String(cause) });
|
|
83
|
+
return 'failed';
|
|
84
|
+
} finally {
|
|
85
|
+
busy.current = false;
|
|
86
|
+
setSending(false);
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
return {
|
|
90
|
+
active,
|
|
91
|
+
activeId: activeKey,
|
|
92
|
+
index,
|
|
93
|
+
waiting,
|
|
94
|
+
setActive: (id) => {
|
|
95
|
+
setActiveId(id);
|
|
96
|
+
setError(null);
|
|
97
|
+
},
|
|
98
|
+
draftOf: (id) => drafts[id] ?? emptyPromptDraft(),
|
|
99
|
+
setDraft: (id, draft) => setDrafts((current) => ({ ...current, [id]: draft })),
|
|
100
|
+
sending,
|
|
101
|
+
errorOf: (id) => (error?.id === id ? error.message : null),
|
|
102
|
+
act,
|
|
103
|
+
onPointerDownCapture: () => {
|
|
104
|
+
pressedRequest.current = activeKey;
|
|
105
|
+
},
|
|
106
|
+
onClickCapture: (event) => {
|
|
107
|
+
// A press that began on Send cannot become Allow when a request arrives underneath it.
|
|
108
|
+
if (event.detail > 0 && (event.target as HTMLElement).closest('.prompt-card') && pressedRequest.current !== activeKey) {
|
|
109
|
+
event.preventDefault();
|
|
110
|
+
event.stopPropagation();
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { Suspense, useState } from 'react';
|
|
2
|
+
import clsx from 'clsx';
|
|
3
|
+
import { useTranslation } from 'react-i18next';
|
|
4
|
+
import type { ChatApprovalItem } from '@adecore/agent-contracts';
|
|
5
|
+
import { approvalChanges, fileChanges } from '../../chat/logic/tools';
|
|
6
|
+
import { chatHost } from '../../host';
|
|
7
|
+
import { lazyNamed } from '../../lazy';
|
|
8
|
+
import { isPrimaryKey } from '../logic/keys';
|
|
9
|
+
import type { PromptDraft } from '../logic/prompts';
|
|
10
|
+
import { Button, TextMenu } from '@adecore/ui';
|
|
11
|
+
|
|
12
|
+
const EditDiff = lazyNamed(() => import('../../chat/ui/EditDiff'), 'default');
|
|
13
|
+
const UnifiedDiff = lazyNamed(() => import('../../chat/ui/UnifiedDiff'), 'default');
|
|
14
|
+
|
|
15
|
+
/* A command in the sunken box a person reads before allowing it, with the folder it runs in when that is known. */
|
|
16
|
+
export function CommandBox({ command, cwd }: { command: string; cwd?: string }) {
|
|
17
|
+
return (
|
|
18
|
+
<TextMenu className="rounded-xl bg-surface-sunken p-3">
|
|
19
|
+
{cwd !== undefined && <p className="mb-2 break-all font-mono text-xs text-text-muted select-text">{cwd}</p>}
|
|
20
|
+
<pre className="whitespace-pre-wrap break-words font-mono text-code text-text select-text">{command}</pre>
|
|
21
|
+
</TextMenu>
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function ApprovalDetails({ item }: { item: ChatApprovalItem }) {
|
|
26
|
+
const { t } = useTranslation('agent-prompts');
|
|
27
|
+
const [expanded, setExpanded] = useState(false);
|
|
28
|
+
const patches = approvalChanges(item.input);
|
|
29
|
+
const edits = patches.length ? [] : fileChanges(item.toolName, item.input);
|
|
30
|
+
const input = typeof item.input === 'object' && item.input !== null ? (item.input as Record<string, unknown>) : {};
|
|
31
|
+
return (
|
|
32
|
+
<>
|
|
33
|
+
{item.description && <p className="text-sm text-text-muted">{item.description}</p>}
|
|
34
|
+
{patches.length + edits.length > 1 && (
|
|
35
|
+
<p className="text-xs text-text-muted">{t('approval.allChanges', { count: patches.length + edits.length })}</p>
|
|
36
|
+
)}
|
|
37
|
+
{patches.length + edits.length > 0 ? (
|
|
38
|
+
<div className="overflow-hidden rounded-xl bg-surface-sunken">
|
|
39
|
+
<div className={clsx('overflow-auto', !expanded && 'max-h-44')}>
|
|
40
|
+
<Suspense fallback={<p className="p-3 text-xs text-text-muted">{t('approval.loadingDiff')}</p>}>
|
|
41
|
+
{patches.map((change, i) => (
|
|
42
|
+
<UnifiedDiff key={i} change={change} />
|
|
43
|
+
))}
|
|
44
|
+
{edits.map((change, i) => (
|
|
45
|
+
<EditDiff key={i} change={change} />
|
|
46
|
+
))}
|
|
47
|
+
</Suspense>
|
|
48
|
+
</div>
|
|
49
|
+
<div className="flex items-center border-t border-border p-1">
|
|
50
|
+
<Button size="sm" aria-expanded={expanded} onClick={() => setExpanded(!expanded)}>
|
|
51
|
+
{expanded ? t('approval.collapseDiff') : t('approval.viewDiff')}
|
|
52
|
+
</Button>
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
) : typeof input.command === 'string' ? (
|
|
56
|
+
<CommandBox command={input.command} cwd={typeof input.cwd === 'string' ? input.cwd : undefined} />
|
|
57
|
+
) : (
|
|
58
|
+
<details>
|
|
59
|
+
<summary className="flex h-7 cursor-pointer items-center text-xs text-text-muted">{t('approval.details')}</summary>
|
|
60
|
+
<TextMenu>
|
|
61
|
+
<pre className="max-h-64 overflow-auto whitespace-pre-wrap break-words rounded-xl bg-surface-sunken p-3 font-mono text-code text-text select-text">
|
|
62
|
+
{JSON.stringify(item.input, null, 2)}
|
|
63
|
+
</pre>
|
|
64
|
+
</TextMenu>
|
|
65
|
+
</details>
|
|
66
|
+
)}
|
|
67
|
+
</>
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/* A chat's permission request: the diff, the command or the raw input, and the reason a Deny may carry. */
|
|
72
|
+
export function ApprovalBody({
|
|
73
|
+
item,
|
|
74
|
+
draft,
|
|
75
|
+
onDraft,
|
|
76
|
+
denyReason,
|
|
77
|
+
locked
|
|
78
|
+
}: {
|
|
79
|
+
item: ChatApprovalItem;
|
|
80
|
+
draft: PromptDraft;
|
|
81
|
+
onDraft(draft: PromptDraft): void;
|
|
82
|
+
denyReason: boolean;
|
|
83
|
+
locked: boolean;
|
|
84
|
+
}) {
|
|
85
|
+
const { t } = useTranslation('agent-prompts');
|
|
86
|
+
const AnswerField = chatHost().dictation.Textarea;
|
|
87
|
+
return (
|
|
88
|
+
<>
|
|
89
|
+
<ApprovalDetails item={item} />
|
|
90
|
+
{denyReason && draft.showReason && (
|
|
91
|
+
<AnswerField
|
|
92
|
+
className="field min-h-16 text-sm"
|
|
93
|
+
autoFocus
|
|
94
|
+
aria-label={t('approval.reasonLabel')}
|
|
95
|
+
placeholder={t('approval.reasonPlaceholder')}
|
|
96
|
+
disabled={locked}
|
|
97
|
+
value={draft.reason}
|
|
98
|
+
onChange={(e) => onDraft({ ...draft, reason: e.target.value })}
|
|
99
|
+
onKeyDown={(e) => {
|
|
100
|
+
// Mod+Enter presses Allow everywhere else in the card, which is the opposite of what a reason for declining is typed for.
|
|
101
|
+
if (isPrimaryKey(e.nativeEvent, chatHost().isApplePlatform())) {
|
|
102
|
+
e.preventDefault();
|
|
103
|
+
}
|
|
104
|
+
}}
|
|
105
|
+
/>
|
|
106
|
+
)}
|
|
107
|
+
</>
|
|
108
|
+
);
|
|
109
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import type { ButtonHTMLAttributes } from 'react';
|
|
2
|
+
import { useTranslation } from 'react-i18next';
|
|
3
|
+
import { ArrowUp, CircleCheck } from 'lucide-react';
|
|
4
|
+
import { Button, Icon } from '@adecore/ui';
|
|
5
|
+
|
|
6
|
+
/* The one button Mod+Enter presses and ArrowDown from the heading lands on, when the body has nothing to choose. */
|
|
7
|
+
export function PromptPrimary(props: ButtonHTMLAttributes<HTMLButtonElement>) {
|
|
8
|
+
return <Button variant="inverse" size="sm" data-prompt-primary {...props} />;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface ApprovalButton {
|
|
12
|
+
id: string;
|
|
13
|
+
label: string;
|
|
14
|
+
description?: string;
|
|
15
|
+
/* The Allow: drawn last, filled, and the one that says it is sending. */
|
|
16
|
+
primary: boolean;
|
|
17
|
+
lasting?: boolean;
|
|
18
|
+
onPress(): void;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/* The buttons of a permission request, in the order a chat draws them: the quieter ones first, Allow last. */
|
|
22
|
+
export function ApprovalActions({
|
|
23
|
+
buttons,
|
|
24
|
+
onAddReason,
|
|
25
|
+
locked,
|
|
26
|
+
sending
|
|
27
|
+
}: {
|
|
28
|
+
buttons: readonly ApprovalButton[];
|
|
29
|
+
/* Only where a Deny can carry a reason, and only until the field is open. */
|
|
30
|
+
onAddReason?: () => void;
|
|
31
|
+
locked: boolean;
|
|
32
|
+
sending: boolean;
|
|
33
|
+
}) {
|
|
34
|
+
const { t } = useTranslation('agent-prompts');
|
|
35
|
+
return (
|
|
36
|
+
<>
|
|
37
|
+
{onAddReason && (
|
|
38
|
+
<Button size="sm" disabled={locked} onClick={onAddReason}>
|
|
39
|
+
{t('approval.addReason')}
|
|
40
|
+
</Button>
|
|
41
|
+
)}
|
|
42
|
+
<div className="ml-auto flex flex-wrap items-center justify-end gap-1.5">
|
|
43
|
+
{buttons.map((button) =>
|
|
44
|
+
button.primary ? (
|
|
45
|
+
<PromptPrimary key={button.id} disabled={locked} onClick={button.onPress}>
|
|
46
|
+
<Icon icon={CircleCheck} size={16} />
|
|
47
|
+
{sending ? t('sending') : button.label}
|
|
48
|
+
</PromptPrimary>
|
|
49
|
+
) : (
|
|
50
|
+
<Button
|
|
51
|
+
key={button.id}
|
|
52
|
+
size="sm"
|
|
53
|
+
disabled={locked}
|
|
54
|
+
aria-description={button.description}
|
|
55
|
+
data-prompt-lasting={button.lasting ? '' : undefined}
|
|
56
|
+
onClick={button.onPress}
|
|
57
|
+
>
|
|
58
|
+
{button.label}
|
|
59
|
+
</Button>
|
|
60
|
+
)
|
|
61
|
+
)}
|
|
62
|
+
</div>
|
|
63
|
+
</>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/* The buttons of a question: back through its questions, dismissing an optional one, and Next until the last becomes Answer. */
|
|
68
|
+
export function QuestionActions({
|
|
69
|
+
index,
|
|
70
|
+
dismissable,
|
|
71
|
+
last,
|
|
72
|
+
ready,
|
|
73
|
+
locked,
|
|
74
|
+
sending,
|
|
75
|
+
onPrevious,
|
|
76
|
+
onDismiss,
|
|
77
|
+
onCommit
|
|
78
|
+
}: {
|
|
79
|
+
index: number;
|
|
80
|
+
dismissable: boolean;
|
|
81
|
+
last: boolean;
|
|
82
|
+
ready: boolean;
|
|
83
|
+
locked: boolean;
|
|
84
|
+
sending: boolean;
|
|
85
|
+
onPrevious(): void;
|
|
86
|
+
onDismiss(): void;
|
|
87
|
+
onCommit(): void;
|
|
88
|
+
}) {
|
|
89
|
+
const { t } = useTranslation(['agent-prompts', 'agent-chat']);
|
|
90
|
+
return (
|
|
91
|
+
<>
|
|
92
|
+
{index > 0 && (
|
|
93
|
+
<Button size="sm" disabled={sending} onClick={onPrevious}>
|
|
94
|
+
{t('question.previous')}
|
|
95
|
+
</Button>
|
|
96
|
+
)}
|
|
97
|
+
{dismissable && index === 0 && (
|
|
98
|
+
<Button size="sm" disabled={locked} onClick={onDismiss}>
|
|
99
|
+
{t('agent-chat:common.action.dismiss')}
|
|
100
|
+
</Button>
|
|
101
|
+
)}
|
|
102
|
+
<span className="grow" />
|
|
103
|
+
<PromptPrimary disabled={locked || !ready} onClick={onCommit}>
|
|
104
|
+
{sending ? t('sending') : last ? t('question.answer') : t('question.next')}
|
|
105
|
+
<Icon icon={ArrowUp} size={16} />
|
|
106
|
+
</PromptPrimary>
|
|
107
|
+
</>
|
|
108
|
+
);
|
|
109
|
+
}
|