@adecore/agents-react 0.38.0 → 0.40.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/AgentModelLabel.d.ts +10 -0
- package/dist/agents/AgentModelLabel.js +98 -0
- package/dist/agents/model-name.js +2 -1
- package/dist/agents/provider-paths.d.ts +2 -1
- package/dist/agents/provider-paths.js +7 -3
- package/dist/chat/account-choice.js +57 -28
- package/dist/chat/bookmarks.js +2 -1
- package/dist/chat/drafts.d.ts +0 -1
- package/dist/chat/drafts.js +9 -28
- package/dist/chat/logic/picker-entries.js +2 -8
- package/dist/chat/logic/resume-compaction.js +2 -5
- package/dist/chat/logic/timeline-copy.js +2 -8
- package/dist/chat/logic/timeline.js +9 -10
- package/dist/chat/logic/workflow.js +2 -4
- package/dist/chat/subagent-conversation.js +2 -1
- package/dist/chat/ui/Composer.js +385 -360
- package/dist/chat/ui/GoalDock.js +2 -1
- package/dist/chat/ui/LimitState.js +4 -6
- package/dist/chat/ui/Pickers.d.ts +2 -1
- package/dist/chat/ui/Pickers.js +126 -123
- package/dist/chat/ui/PromptEditor.d.ts +19 -0
- package/dist/chat/ui/PromptEditor.js +115 -0
- package/dist/chat/ui/Timeline.d.ts +2 -1
- package/dist/chat/ui/Timeline.js +13 -1
- package/dist/chat/ui/composer/ComposerControls.d.ts +3 -0
- package/dist/chat/ui/composer/ComposerControls.js +235 -38
- package/dist/chat/ui/composer/key-handler.d.ts +1 -1
- package/dist/chat/ui/composer/key-handler.js +3 -11
- package/dist/chat/ui/composer/prompt-picks.d.ts +4 -0
- package/dist/chat/ui/composer/prompt-picks.js +14 -0
- package/dist/chat/ui/composer/use-composer-menus.d.ts +4 -49
- package/dist/chat/ui/composer/use-composer-menus.js +65 -519
- package/dist/chat/ui/composer/use-continuable-turn.js +0 -1
- package/dist/chat/ui/composer/use-notice.js +2 -1
- package/dist/chat/ui/composer/use-prompt-history.js +1 -1
- package/dist/chat/ui/composer/use-prompt-menus.d.ts +73 -0
- package/dist/chat/ui/composer/use-prompt-menus.js +499 -0
- package/dist/chat/ui/composer/use-take-back.js +2 -2
- package/dist/chat/ui/diff/ApprovalReview.js +1 -1
- package/dist/chat/ui/highlighter.d.ts +0 -6
- package/dist/chat/ui/highlighter.js +0 -12
- package/dist/chat/ui/icons.d.ts +0 -1
- package/dist/chat/ui/icons.js +0 -3
- package/dist/chat/ui/index.d.ts +3 -0
- package/dist/chat/ui/index.js +2 -0
- package/dist/chat/ui/rows/MessageRows.js +2 -5
- package/dist/chat/ui/rows/row-rhythm.js +2 -5
- package/dist/chat/ui/theme-watch.js +3 -7
- package/dist/host-hooks.d.ts +2 -1
- package/dist/host-hooks.js +6 -0
- package/dist/host.d.ts +17 -1
- package/dist/index.d.ts +1 -1
- package/dist/locales/en/agent-chat.d.ts +1 -0
- package/dist/locales/en/agent-chat.js +1 -0
- package/dist/locales/nl/agent-chat.d.ts +1 -0
- package/dist/locales/nl/agent-chat.js +1 -0
- package/dist/prompts/logic/usePromptSession.js +2 -1
- package/dist/providers/AddAccountForm.js +2 -1
- package/dist/providers/CliDetail.js +104 -130
- package/dist/providers/account-actions.js +6 -9
- package/dist/providers/index.d.ts +1 -0
- package/dist/providers/index.js +1 -0
- package/dist/state/chats.d.ts +1 -0
- package/dist/state/chats.js +6 -11
- package/dist/state/provider-accounts.d.ts +1 -1
- package/dist/state/provider-accounts.js +2 -8
- package/dist/theme.css +3 -0
- package/dist/transport.d.ts +2 -0
- package/dist/transport.js +14 -0
- package/dist/usage/ChartLogo.d.ts +5 -0
- package/dist/usage/ChartLogo.js +48 -0
- package/dist/usage/LimitsList.js +6 -16
- package/dist/usage/UsageBreakdown.js +17 -40
- package/dist/usage/UsageLimits.js +183 -211
- package/dist/usage/UsagePage.js +3 -17
- package/dist/usage/UsageSummary.js +4 -9
- package/dist/usage/limits.js +16 -31
- package/dist/usage/summary.d.ts +1 -1
- package/dist/usage/summary.js +3 -5
- package/package.json +26 -26
- package/src/agents/AccountDot.tsx +1 -0
- package/src/agents/AgentIcon.tsx +2 -0
- package/src/agents/AgentModelLabel.tsx +38 -0
- package/src/agents/ModelOptionControl.tsx +8 -0
- package/src/agents/account-limits.ts +3 -0
- package/src/agents/accounts.ts +12 -0
- package/src/agents/model-name.ts +13 -1
- package/src/agents/model-options.ts +2 -0
- package/src/agents/model-requirement.ts +4 -0
- package/src/agents/option-words.ts +2 -0
- package/src/agents/provider-paths.ts +8 -3
- package/src/agents/status-look.ts +1 -0
- package/src/chat/account-choice.ts +25 -19
- package/src/chat/actions.ts +5 -0
- package/src/chat/attachments.ts +8 -0
- package/src/chat/bookmarks.ts +13 -1
- package/src/chat/chat-client.ts +63 -0
- package/src/chat/chat-references.ts +3 -0
- package/src/chat/composer-effort.ts +5 -0
- package/src/chat/composer-send.ts +4 -0
- package/src/chat/drafts.ts +21 -17
- package/src/chat/forks.ts +4 -0
- package/src/chat/guards.ts +2 -0
- package/src/chat/index.ts +7 -0
- package/src/chat/logic/ansi.ts +47 -0
- package/src/chat/logic/bookmarks.ts +7 -0
- package/src/chat/logic/command-looks.ts +29 -0
- package/src/chat/logic/context-usage.ts +3 -0
- package/src/chat/logic/continue-after-stop.ts +5 -0
- package/src/chat/logic/effort.ts +4 -0
- package/src/chat/logic/embedded-code.ts +63 -0
- package/src/chat/logic/fork.ts +22 -0
- package/src/chat/logic/generated-image.ts +7 -0
- package/src/chat/logic/goal.ts +7 -0
- package/src/chat/logic/handback.ts +2 -0
- package/src/chat/logic/limit.ts +8 -0
- package/src/chat/logic/picker-entries.ts +16 -4
- package/src/chat/logic/resume-compaction.ts +22 -5
- package/src/chat/logic/scrubber.ts +38 -5
- package/src/chat/logic/thought.ts +5 -0
- package/src/chat/logic/thread-cards.ts +6 -0
- package/src/chat/logic/timeline-copy.ts +4 -9
- package/src/chat/logic/timeline-target.ts +15 -0
- package/src/chat/logic/timeline.ts +113 -10
- package/src/chat/logic/tools.ts +30 -0
- package/src/chat/logic/visual-height.ts +5 -0
- package/src/chat/logic/visual-viewport.ts +1 -0
- package/src/chat/logic/welcome.ts +3 -0
- package/src/chat/logic/workflow.ts +26 -7
- package/src/chat/mentions.ts +56 -0
- package/src/chat/pending-prompts.ts +16 -0
- package/src/chat/persisted-json.ts +15 -0
- package/src/chat/preferences.ts +16 -0
- package/src/chat/prompt-hold.ts +2 -0
- package/src/chat/quote.ts +7 -0
- package/src/chat/reading-width.ts +1 -0
- package/src/chat/recent-messages.ts +5 -0
- package/src/chat/resume-compaction-dismissals.ts +1 -0
- package/src/chat/stash.ts +12 -0
- package/src/chat/subagent-conversation.ts +24 -4
- package/src/chat/subagent-list.ts +14 -0
- package/src/chat/subagent-support.ts +1 -0
- package/src/chat/subagent-view.ts +9 -0
- package/src/chat/thumbnails.ts +14 -0
- package/src/chat/timeline-flash.ts +2 -0
- package/src/chat/timeline-scroll.ts +23 -0
- package/src/chat/ui/AccountPill.tsx +4 -0
- package/src/chat/ui/AnsiOutput.tsx +1 -0
- package/src/chat/ui/BookmarkMarker.tsx +5 -0
- package/src/chat/ui/BookmarkSubmenu.tsx +1 -0
- package/src/chat/ui/ChatActivity.tsx +13 -0
- package/src/chat/ui/CodeBlock.tsx +8 -0
- package/src/chat/ui/Composer.tsx +27 -3
- package/src/chat/ui/ComposerInput.tsx +22 -0
- package/src/chat/ui/DiffPool.tsx +3 -0
- package/src/chat/ui/EditDiff.tsx +5 -0
- package/src/chat/ui/GoalDock.tsx +13 -1
- package/src/chat/ui/ImageView.tsx +11 -0
- package/src/chat/ui/LimitState.tsx +23 -6
- package/src/chat/ui/Markdown.tsx +41 -0
- package/src/chat/ui/MermaidBlock.tsx +16 -0
- package/src/chat/ui/MessageActions.tsx +8 -0
- package/src/chat/ui/ModelMarks.tsx +1 -0
- package/src/chat/ui/Pickers.tsx +30 -1
- package/src/chat/ui/PromptComposer.tsx +2 -0
- package/src/chat/ui/PromptEditor.tsx +136 -0
- package/src/chat/ui/QuoteButton.tsx +12 -0
- package/src/chat/ui/ReferenceChip.tsx +3 -0
- package/src/chat/ui/ResumeCompactionDock.tsx +1 -0
- package/src/chat/ui/RowTime.tsx +1 -0
- package/src/chat/ui/RunSettings.tsx +38 -0
- package/src/chat/ui/Scrubber.tsx +14 -0
- package/src/chat/ui/SessionLine.tsx +1 -0
- package/src/chat/ui/ShellCommand.tsx +32 -0
- package/src/chat/ui/SubagentControls.tsx +7 -0
- package/src/chat/ui/SubagentInfo.tsx +1 -0
- package/src/chat/ui/SubagentStopButton.tsx +6 -0
- package/src/chat/ui/SubagentTimeline.tsx +10 -0
- package/src/chat/ui/Timeline.tsx +141 -1
- package/src/chat/ui/TimelineMenu.tsx +5 -0
- package/src/chat/ui/UnifiedDiff.tsx +6 -0
- package/src/chat/ui/UploadThumb.tsx +2 -0
- package/src/chat/ui/VisualDialogs.tsx +3 -0
- package/src/chat/ui/VisualFrame.tsx +15 -0
- package/src/chat/ui/Welcome.tsx +1 -0
- package/src/chat/ui/chip-clipboard.ts +20 -0
- package/src/chat/ui/code-lines.ts +14 -0
- package/src/chat/ui/code-theme.ts +1 -0
- package/src/chat/ui/composer/ComposerControls.tsx +70 -15
- package/src/chat/ui/composer/ComposerMenu.tsx +12 -0
- package/src/chat/ui/composer/DraftParts.tsx +2 -0
- package/src/chat/ui/composer/QueuedMessages.tsx +4 -0
- package/src/chat/ui/composer/chip-paste.ts +16 -0
- package/src/chat/ui/composer/chips.ts +6 -0
- package/src/chat/ui/composer/editor.ts +9 -0
- package/src/chat/ui/composer/insert.ts +2 -0
- package/src/chat/ui/composer/key-handler.ts +42 -9
- package/src/chat/ui/composer/keys.ts +23 -0
- package/src/chat/ui/composer/placeholder.ts +6 -0
- package/src/chat/ui/composer/prompt-picks.ts +18 -0
- package/src/chat/ui/composer/surface.ts +5 -0
- package/src/chat/ui/composer/use-chat-controls.ts +13 -0
- package/src/chat/ui/composer/use-compaction-offer.ts +3 -0
- package/src/chat/ui/composer/use-composer-menus.ts +20 -275
- package/src/chat/ui/composer/use-composer-submit.ts +27 -0
- package/src/chat/ui/composer/use-continuable-turn.ts +3 -5
- package/src/chat/ui/composer/use-draft-files.ts +24 -0
- package/src/chat/ui/composer/use-effort-stepper.ts +8 -0
- package/src/chat/ui/composer/use-notice.ts +4 -1
- package/src/chat/ui/composer/use-pending-requests.ts +3 -0
- package/src/chat/ui/composer/use-prompt-history.ts +20 -11
- package/src/chat/ui/composer/use-prompt-hold.ts +3 -0
- package/src/chat/ui/composer/use-prompt-menus.ts +361 -0
- package/src/chat/ui/composer/use-take-back.ts +20 -2
- package/src/chat/ui/diff/ApprovalReview.tsx +18 -15
- package/src/chat/ui/diff/DiffFallbackBoundary.tsx +1 -0
- package/src/chat/ui/diff/DiffOmitted.tsx +1 -0
- package/src/chat/ui/diff/DiffStack.tsx +2 -0
- package/src/chat/ui/diff/DiffUnavailable.tsx +1 -0
- package/src/chat/ui/diff/EditorEditDiff.tsx +13 -0
- package/src/chat/ui/diff/EditorPatchDiff.tsx +4 -0
- package/src/chat/ui/diff/LegacyDiffPool.tsx +2 -0
- package/src/chat/ui/diff/LegacyEditDiff.tsx +2 -0
- package/src/chat/ui/diff/LegacyUnifiedDiff.tsx +8 -0
- package/src/chat/ui/diff/RawDiff.tsx +1 -0
- package/src/chat/ui/diff/ReviewDiff.tsx +1 -0
- package/src/chat/ui/diff/diff-source-budget.ts +8 -0
- package/src/chat/ui/diff/editor-edit-model.ts +4 -0
- package/src/chat/ui/diff/review-plan.ts +9 -0
- package/src/chat/ui/diff/review-settle.ts +1 -0
- package/src/chat/ui/diff/syntax-runtime.ts +52 -0
- package/src/chat/ui/diff/use-review-stack.ts +9 -0
- package/src/chat/ui/diff-syntax.ts +12 -0
- package/src/chat/ui/diff-theme.ts +2 -0
- package/src/chat/ui/file-links.ts +2 -0
- package/src/chat/ui/find-reveal.ts +1 -0
- package/src/chat/ui/full-diff.ts +1 -0
- package/src/chat/ui/highlighter.ts +29 -15
- package/src/chat/ui/icons.tsx +2 -4
- package/src/chat/ui/index.ts +7 -0
- package/src/chat/ui/intelligent-ui/UiBlockFrame.tsx +25 -0
- package/src/chat/ui/intelligent-ui/UiFallbackPart.tsx +1 -0
- package/src/chat/ui/intelligent-ui/UiReply.tsx +63 -0
- package/src/chat/ui/intelligent-ui/block-local.ts +5 -0
- package/src/chat/ui/intelligent-ui/chart-data.ts +15 -0
- package/src/chat/ui/intelligent-ui/node-text.ts +17 -0
- package/src/chat/ui/intelligent-ui/renderers/binding.ts +1 -0
- package/src/chat/ui/intelligent-ui/renderers/chart.tsx +31 -0
- package/src/chat/ui/intelligent-ui/renderers/choices.tsx +4 -0
- package/src/chat/ui/intelligent-ui/renderers/content.tsx +18 -0
- package/src/chat/ui/intelligent-ui/renderers/data.tsx +11 -0
- package/src/chat/ui/intelligent-ui/renderers/inputs.tsx +13 -0
- package/src/chat/ui/intelligent-ui/renderers/links.tsx +9 -0
- package/src/chat/ui/intelligent-ui/renderers/map-slots.ts +15 -0
- package/src/chat/ui/intelligent-ui/renderers/map-style.ts +15 -0
- package/src/chat/ui/intelligent-ui/renderers/map-view.tsx +48 -0
- package/src/chat/ui/intelligent-ui/renderers/map.tsx +20 -0
- package/src/chat/ui/intelligent-ui/renderers/place-point.ts +3 -0
- package/src/chat/ui/intelligent-ui/renderers/structure.tsx +3 -0
- package/src/chat/ui/intelligent-ui/renderers/text.tsx +8 -0
- package/src/chat/ui/intelligent-ui/reply-parts.ts +5 -0
- package/src/chat/ui/intelligent-ui/table-data.ts +17 -0
- package/src/chat/ui/intelligent-ui/use-in-view.ts +4 -0
- package/src/chat/ui/intelligent-ui/use-later.ts +4 -0
- package/src/chat/ui/intelligent-ui/use-truncated.ts +5 -0
- package/src/chat/ui/intelligent-ui/use-ui-links.ts +29 -0
- package/src/chat/ui/intelligent-ui/use-ui-queries.ts +60 -0
- package/src/chat/ui/markdown-blocks.ts +64 -0
- package/src/chat/ui/mermaid.ts +4 -0
- package/src/chat/ui/quote-selection.ts +10 -0
- package/src/chat/ui/rehype-chips.ts +5 -0
- package/src/chat/ui/rehype-fade.ts +2 -0
- package/src/chat/ui/remark-html-as-text.ts +5 -0
- package/src/chat/ui/reveal.ts +18 -0
- package/src/chat/ui/rows/ForksRow.tsx +5 -0
- package/src/chat/ui/rows/GeneratedImageRow.tsx +10 -0
- package/src/chat/ui/rows/MessageRows.tsx +29 -5
- package/src/chat/ui/rows/RowContainer.tsx +1 -0
- package/src/chat/ui/rows/Rows.tsx +2 -0
- package/src/chat/ui/rows/SubagentRow.tsx +13 -0
- package/src/chat/ui/rows/TaskRow.tsx +7 -0
- package/src/chat/ui/rows/VisualRow.tsx +4 -0
- package/src/chat/ui/rows/WorkRows.tsx +46 -0
- package/src/chat/ui/rows/WorkflowRow.tsx +10 -0
- package/src/chat/ui/rows/row-rhythm.ts +7 -5
- package/src/chat/ui/theme-watch.ts +8 -7
- package/src/chat/ui/thread-references.ts +7 -0
- package/src/chat/ui/use-diff-source-tokens.ts +8 -0
- package/src/chat/ui/useToggleSet.ts +3 -0
- package/src/chat/ui/visual-theme.ts +30 -0
- package/src/chat/visual-bridge.ts +23 -0
- package/src/chat/visual-viewport.ts +12 -0
- package/src/host-hooks.ts +15 -5
- package/src/host.ts +29 -1
- package/src/index.ts +5 -0
- package/src/lazy.tsx +9 -0
- package/src/locales/en/agent-chat.ts +1 -0
- package/src/locales/nl/agent-chat.ts +1 -0
- package/src/mounted-registry.ts +4 -0
- package/src/port-transport.ts +32 -0
- package/src/prompts/index.ts +2 -0
- package/src/prompts/logic/focus.ts +5 -0
- package/src/prompts/logic/keys.ts +12 -0
- package/src/prompts/logic/prompts.ts +8 -0
- package/src/prompts/logic/subjects.ts +8 -0
- package/src/prompts/logic/useFocusAfterAnswer.ts +2 -0
- package/src/prompts/logic/usePromptSession.ts +13 -1
- package/src/prompts/ui/ApprovalBody.tsx +2 -0
- package/src/prompts/ui/PromptActions.tsx +2 -0
- package/src/prompts/ui/PromptCard.tsx +6 -0
- package/src/prompts/ui/PromptView.tsx +6 -0
- package/src/prompts/ui/QuestionBody.tsx +11 -0
- package/src/providers/AccountColors.tsx +1 -0
- package/src/providers/AccountDetail.tsx +7 -0
- package/src/providers/AccountVariables.tsx +2 -0
- package/src/providers/AddAccountForm.tsx +5 -1
- package/src/providers/CliDetail.tsx +6 -5
- package/src/providers/InstallPage.tsx +11 -0
- package/src/providers/ProviderList.tsx +3 -0
- package/src/providers/ProvidersPane.tsx +18 -0
- package/src/providers/account-actions.ts +10 -8
- package/src/providers/index.ts +1 -0
- package/src/providers/install-steps.ts +3 -0
- package/src/providers/pane-target.ts +5 -0
- package/src/providers/provider-abilities.ts +1 -0
- package/src/providers/provider-groups.ts +6 -0
- package/src/providers/variables.ts +12 -0
- package/src/scope.ts +2 -0
- package/src/state/chats.ts +61 -14
- package/src/state/index.ts +2 -0
- package/src/state/provider-accounts.ts +7 -9
- package/src/state/providers.ts +1 -0
- package/src/state/usage.ts +6 -0
- package/src/storage.ts +18 -0
- package/src/testing/prompts.ts +5 -0
- package/src/theme.css +3 -0
- package/src/transport.ts +18 -0
- package/src/usage/ChartLogo.tsx +12 -0
- package/src/usage/LimitsList.tsx +7 -8
- package/src/usage/UsageBreakdown.tsx +11 -4
- package/src/usage/UsageChart.tsx +5 -0
- package/src/usage/UsageLimits.tsx +10 -7
- package/src/usage/UsageLimitsCard.tsx +2 -0
- package/src/usage/UsagePage.tsx +16 -19
- package/src/usage/UsageSummary.tsx +4 -5
- package/src/usage/UsageTiles.tsx +2 -0
- package/src/usage/format.ts +7 -0
- package/src/usage/limit-groups.ts +14 -0
- package/src/usage/limits.ts +11 -13
- package/src/usage/money.ts +1 -0
- package/src/usage/summary.ts +15 -7
package/src/host.ts
CHANGED
|
@@ -18,7 +18,9 @@ import type {
|
|
|
18
18
|
ChatUiLinkPayload,
|
|
19
19
|
ChatUiLinkReading,
|
|
20
20
|
ChatVisual,
|
|
21
|
-
|
|
21
|
+
ModelSelection,
|
|
22
|
+
ProviderPlatform,
|
|
23
|
+
RuntimeMode
|
|
22
24
|
} from '@adecore/agent-contracts';
|
|
23
25
|
import { isApplePlatform } from '@adecore/ui';
|
|
24
26
|
import type { Referables } from './chat/chat-references';
|
|
@@ -168,6 +170,28 @@ export interface ComposerSlotProps {
|
|
|
168
170
|
insert(text: string): void;
|
|
169
171
|
}
|
|
170
172
|
|
|
173
|
+
/* What a send action of the app's gets: the message as it stands when a person picks the action. */
|
|
174
|
+
export interface ComposerSendDraft {
|
|
175
|
+
scopeId: string;
|
|
176
|
+
chatId: string;
|
|
177
|
+
/* The draft as Send would send it, trimmed and with its quote; empty when nothing is written. */
|
|
178
|
+
text: string;
|
|
179
|
+
provider: AgentKind;
|
|
180
|
+
selection: ModelSelection;
|
|
181
|
+
runtimeMode: RuntimeMode;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/* An action of the app's own in the menu beside the composer's send button, such as sending the draft later. */
|
|
185
|
+
export interface ComposerSendAction {
|
|
186
|
+
/* Unique among the actions of one composer. */
|
|
187
|
+
id: string;
|
|
188
|
+
label: string;
|
|
189
|
+
icon?: LucideIcon;
|
|
190
|
+
disabled?: boolean;
|
|
191
|
+
/* Runs once a person picks it; the draft stays in the box, and the host shows a failure itself. */
|
|
192
|
+
run(draft: ComposerSendDraft): void;
|
|
193
|
+
}
|
|
194
|
+
|
|
171
195
|
/* What an app's own chips for a chat's sub-agents get, in place of the one flyout over the composer. */
|
|
172
196
|
export interface SubagentSlotProps {
|
|
173
197
|
chatId: string;
|
|
@@ -453,6 +477,8 @@ export interface ChatHost {
|
|
|
453
477
|
useComposerPlaceholder(scopeId: string, chatId: string): string | null;
|
|
454
478
|
/* The app's own control in the composer's row, after the pickers; null draws none. */
|
|
455
479
|
ComposerSlot: ComponentType<ComposerSlotProps> | null;
|
|
480
|
+
/* Actions of the app's own behind a chevron on the send button, in the order given; left out, or none, Send stands alone. */
|
|
481
|
+
useComposerSendActions?(scopeId: string, chatId: string): readonly ComposerSendAction[];
|
|
456
482
|
/* The app's own chips for a chat's sub-agents over the composer; null draws the one flyout. */
|
|
457
483
|
SubagentSlot: ComponentType<SubagentSlotProps> | null;
|
|
458
484
|
/* Cards of the app's own in a thread, in any order. Hand back the same array while none changed, or the thread lays out its rows again on every render. */
|
|
@@ -525,9 +551,11 @@ const ChatHostContext = createContext<ChatHost>(DEFAULT_HOST);
|
|
|
525
551
|
export function ChatHostProvider({ host, children }: { host: Partial<ChatHost>; children?: ReactNode }) {
|
|
526
552
|
const parent = useContext(ChatHostContext);
|
|
527
553
|
const [pinned] = useState(() => ({ host, value: { ...parent, ...host } }));
|
|
554
|
+
|
|
528
555
|
if (pinned.host !== host) {
|
|
529
556
|
throw new Error('A ChatHostProvider reads its host once: hand it the same object on every render, or a new key to mount it with another');
|
|
530
557
|
}
|
|
558
|
+
|
|
531
559
|
return createElement(ChatHostContext.Provider, { value: pinned.value }, children);
|
|
532
560
|
}
|
|
533
561
|
|
package/src/index.ts
CHANGED
|
@@ -9,6 +9,8 @@ export {
|
|
|
9
9
|
type TimelineFind,
|
|
10
10
|
type ComposerDictationProps,
|
|
11
11
|
type ComposerSlotProps,
|
|
12
|
+
type ComposerSendAction,
|
|
13
|
+
type ComposerSendDraft,
|
|
12
14
|
type SubagentSlotProps,
|
|
13
15
|
type ThreadCard,
|
|
14
16
|
type VisualHost,
|
|
@@ -27,7 +29,9 @@ export {
|
|
|
27
29
|
type TextareaProps,
|
|
28
30
|
type ResourceUrl
|
|
29
31
|
} from './host';
|
|
32
|
+
|
|
30
33
|
export { type ChatScope, ChatScopeContext, useChatScope } from './scope';
|
|
34
|
+
|
|
31
35
|
export {
|
|
32
36
|
type ChatRequestMap,
|
|
33
37
|
type ChatEventMap,
|
|
@@ -37,6 +41,7 @@ export {
|
|
|
37
41
|
errorCode,
|
|
38
42
|
isConnectionError
|
|
39
43
|
} from './transport';
|
|
44
|
+
|
|
40
45
|
export { portTransport, type PortTransport } from './port-transport';
|
|
41
46
|
export { configureAgentMarks, type AgentMark } from './agents/agent-marks';
|
|
42
47
|
export { configureChatStorage, type ChatStorageRecord, type ChatStorageAdapter, type ChatStorageOptions } from './storage';
|
package/src/lazy.tsx
CHANGED
|
@@ -13,6 +13,7 @@ const openErrorListeners = new Set<(error: unknown) => void>();
|
|
|
13
13
|
*/
|
|
14
14
|
export function setLazyPrefetch(next: (load: Loader) => void): void {
|
|
15
15
|
register = next;
|
|
16
|
+
|
|
16
17
|
for (const load of loaders) {
|
|
17
18
|
next(load);
|
|
18
19
|
}
|
|
@@ -24,6 +25,7 @@ export function setLazyPrefetch(next: (load: Loader) => void): void {
|
|
|
24
25
|
*/
|
|
25
26
|
export function onLazyOpenError(listener: (error: unknown) => void): () => void {
|
|
26
27
|
openErrorListeners.add(listener);
|
|
28
|
+
|
|
27
29
|
return () => {
|
|
28
30
|
openErrorListeners.delete(listener);
|
|
29
31
|
};
|
|
@@ -41,11 +43,14 @@ export function lazyNamed<Module extends Record<Name, ComponentType<any>>, Name
|
|
|
41
43
|
): ComponentType<ComponentProps<Module[Name]>> {
|
|
42
44
|
// Through `LoadedComponent`, so a `LazyBoundary` around it draws the moment the module lands.
|
|
43
45
|
const loaded = new LoadedComponent<ComponentType<any>>(async () => (await load())[name]);
|
|
46
|
+
|
|
44
47
|
const open = (): Promise<ComponentType<any>> => loaded.load();
|
|
48
|
+
|
|
45
49
|
if (options?.prefetch !== false) {
|
|
46
50
|
loaders.push(open);
|
|
47
51
|
register?.(open);
|
|
48
52
|
}
|
|
53
|
+
|
|
49
54
|
// Only a render loads through here; a prefetch calls `open` itself, so its failures report nothing.
|
|
50
55
|
const Lazy = lazy(async () => {
|
|
51
56
|
try {
|
|
@@ -54,14 +59,18 @@ export function lazyNamed<Module extends Record<Name, ComponentType<any>>, Name
|
|
|
54
59
|
for (const listener of openErrorListeners) {
|
|
55
60
|
listener(error);
|
|
56
61
|
}
|
|
62
|
+
|
|
57
63
|
throw error;
|
|
58
64
|
}
|
|
59
65
|
});
|
|
66
|
+
|
|
60
67
|
const LazyNamed = (props: ComponentProps<Module[Name]>) => {
|
|
61
68
|
// `loaded` fills in place; compiled, the element drawn before the module landed would stay.
|
|
62
69
|
'use no memo';
|
|
63
70
|
const Component: ComponentType<any> = loaded.current ?? Lazy;
|
|
71
|
+
|
|
64
72
|
return <Component {...props} />;
|
|
65
73
|
};
|
|
74
|
+
|
|
66
75
|
return LazyNamed;
|
|
67
76
|
}
|
package/src/mounted-registry.ts
CHANGED
|
@@ -27,12 +27,15 @@ export class MountedRegistry<T extends MountedEntry> extends Map<string, T> {
|
|
|
27
27
|
*/
|
|
28
28
|
async reattachAll(reattach: (id: string, entry: T) => Promise<void>): Promise<void> {
|
|
29
29
|
const queue = [...this];
|
|
30
|
+
|
|
30
31
|
const work = async (): Promise<void> => {
|
|
31
32
|
for (let next = queue.shift(); next !== undefined; next = queue.shift()) {
|
|
32
33
|
const [id, entry] = next;
|
|
34
|
+
|
|
33
35
|
if (entry.attached || this.get(id) !== entry) {
|
|
34
36
|
continue;
|
|
35
37
|
}
|
|
38
|
+
|
|
36
39
|
try {
|
|
37
40
|
await reattach(id, entry);
|
|
38
41
|
} catch {
|
|
@@ -40,6 +43,7 @@ export class MountedRegistry<T extends MountedEntry> extends Map<string, T> {
|
|
|
40
43
|
}
|
|
41
44
|
}
|
|
42
45
|
};
|
|
46
|
+
|
|
43
47
|
await Promise.all(Array.from({ length: REATTACH_CONCURRENCY }, work));
|
|
44
48
|
}
|
|
45
49
|
}
|
package/src/port-transport.ts
CHANGED
|
@@ -34,32 +34,45 @@ export function portTransport(port: FramePort): PortTransport {
|
|
|
34
34
|
|
|
35
35
|
const answer = (id: string, frame: { ok: true; result: unknown } | { ok: false; error: { code: string; message: string } }): void => {
|
|
36
36
|
const entry = pending.get(id);
|
|
37
|
+
|
|
37
38
|
if (!entry) {
|
|
38
39
|
return;
|
|
39
40
|
}
|
|
41
|
+
|
|
40
42
|
pending.delete(id);
|
|
43
|
+
|
|
41
44
|
if (!frame.ok) {
|
|
42
45
|
entry.reject(new ChatTransportError(frame.error.code, frame.error.message));
|
|
46
|
+
|
|
43
47
|
return;
|
|
44
48
|
}
|
|
49
|
+
|
|
45
50
|
const result = AGENT_REQUEST_SCHEMAS[entry.type].result.safeParse(frame.result);
|
|
51
|
+
|
|
46
52
|
if (!result.success) {
|
|
47
53
|
entry.reject(new ChatTransportError('bad-reply', i18next.t('agent-chat:transport.badReply', { type: entry.type })));
|
|
54
|
+
|
|
48
55
|
return;
|
|
49
56
|
}
|
|
57
|
+
|
|
50
58
|
entry.resolve(result.data);
|
|
51
59
|
};
|
|
52
60
|
|
|
53
61
|
const dispatch = (event: string, payload: unknown): void => {
|
|
54
62
|
if (!isEventType(event)) {
|
|
55
63
|
console.warn('Dropped an unknown event', event);
|
|
64
|
+
|
|
56
65
|
return;
|
|
57
66
|
}
|
|
67
|
+
|
|
58
68
|
const parsed = AGENT_EVENT_SCHEMAS[event].safeParse(payload);
|
|
69
|
+
|
|
59
70
|
if (!parsed.success) {
|
|
60
71
|
console.warn(`Dropped a malformed ${event} event`);
|
|
72
|
+
|
|
61
73
|
return;
|
|
62
74
|
}
|
|
75
|
+
|
|
63
76
|
// A copy, so a handler that unsubscribes while it runs does not change the set being walked.
|
|
64
77
|
for (const handler of [...(eventHandlers.get(event) ?? [])]) {
|
|
65
78
|
(handler as (payload: unknown) => void)(parsed.data);
|
|
@@ -70,21 +83,30 @@ export function portTransport(port: FramePort): PortTransport {
|
|
|
70
83
|
if (status === 'closed') {
|
|
71
84
|
return;
|
|
72
85
|
}
|
|
86
|
+
|
|
73
87
|
const parsed = parseServerFrame(raw);
|
|
88
|
+
|
|
74
89
|
if (!parsed.ok) {
|
|
75
90
|
console.warn('Dropped a malformed frame', parsed.message);
|
|
91
|
+
|
|
76
92
|
return;
|
|
77
93
|
}
|
|
94
|
+
|
|
78
95
|
const frame = parsed.value;
|
|
96
|
+
|
|
79
97
|
if ('event' in frame) {
|
|
80
98
|
dispatch(frame.event, frame.payload);
|
|
99
|
+
|
|
81
100
|
return;
|
|
82
101
|
}
|
|
102
|
+
|
|
83
103
|
if (frame.id === null) {
|
|
84
104
|
// An answer without an id is about a frame the host could not read; nothing waits for it.
|
|
85
105
|
console.warn('The chat host refused a frame', frame);
|
|
106
|
+
|
|
86
107
|
return;
|
|
87
108
|
}
|
|
109
|
+
|
|
88
110
|
answer(frame.id, frame);
|
|
89
111
|
});
|
|
90
112
|
|
|
@@ -96,29 +118,36 @@ export function portTransport(port: FramePort): PortTransport {
|
|
|
96
118
|
if (status !== 'open') {
|
|
97
119
|
return Promise.reject(new ChatTransportError('not-connected', i18next.t('agent-chat:transport.notConnected')));
|
|
98
120
|
}
|
|
121
|
+
|
|
99
122
|
const id = String(nextId++);
|
|
123
|
+
|
|
100
124
|
const promise = new Promise<ChatRequestMap[T]['result']>((resolve, reject) => {
|
|
101
125
|
pending.set(id, { type, resolve: resolve as (result: unknown) => void, reject });
|
|
102
126
|
});
|
|
127
|
+
|
|
103
128
|
try {
|
|
104
129
|
port.send({ id, type, payload });
|
|
105
130
|
} catch {
|
|
106
131
|
// A payload the port cannot clone throws here, and the caller only listens to the promise.
|
|
107
132
|
pending.delete(id);
|
|
133
|
+
|
|
108
134
|
return Promise.reject(new ChatTransportError('not-sent', i18next.t('agent-chat:transport.notSent', { type })));
|
|
109
135
|
}
|
|
136
|
+
|
|
110
137
|
return promise;
|
|
111
138
|
},
|
|
112
139
|
on<E extends AgentEventType>(event: E, handler: (payload: ChatEventMap[E]) => void): () => void {
|
|
113
140
|
const handlers = eventHandlers.get(event) ?? new Set();
|
|
114
141
|
eventHandlers.set(event, handlers);
|
|
115
142
|
handlers.add(handler);
|
|
143
|
+
|
|
116
144
|
return () => {
|
|
117
145
|
handlers.delete(handler);
|
|
118
146
|
};
|
|
119
147
|
},
|
|
120
148
|
subscribeStatus(handler: (status: ChatTransportStatus) => void): () => void {
|
|
121
149
|
statusHandlers.add(handler);
|
|
150
|
+
|
|
122
151
|
return () => {
|
|
123
152
|
statusHandlers.delete(handler);
|
|
124
153
|
};
|
|
@@ -127,13 +156,16 @@ export function portTransport(port: FramePort): PortTransport {
|
|
|
127
156
|
if (status === 'closed') {
|
|
128
157
|
return;
|
|
129
158
|
}
|
|
159
|
+
|
|
130
160
|
status = 'closed';
|
|
131
161
|
stopListening();
|
|
132
162
|
const waiting = [...pending.values()];
|
|
133
163
|
pending.clear();
|
|
164
|
+
|
|
134
165
|
for (const entry of waiting) {
|
|
135
166
|
entry.reject(new ChatTransportError('disconnected', i18next.t('agent-chat:transport.closedBeforeAnswer')));
|
|
136
167
|
}
|
|
168
|
+
|
|
137
169
|
for (const handler of [...statusHandlers]) {
|
|
138
170
|
handler(status);
|
|
139
171
|
}
|
package/src/prompts/index.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
export { focusPromptStart } from './logic/focus';
|
|
3
3
|
export { PROMPT_SHORTCUTS, pageKey, type PromptKeyEvent } from './logic/keys';
|
|
4
4
|
export { type PendingPrompt, type PromptAction, emptyPromptDraft, orderPrompts, type PromptAnswer, type PromptDraft } from './logic/prompts';
|
|
5
|
+
|
|
5
6
|
export {
|
|
6
7
|
type HostPrompt,
|
|
7
8
|
type PromptSubject,
|
|
@@ -13,6 +14,7 @@ export {
|
|
|
13
14
|
isBlockingSubject,
|
|
14
15
|
answerPrompt
|
|
15
16
|
} from './logic/subjects';
|
|
17
|
+
|
|
16
18
|
export { useFocusAfterAnswer, type FocusAfterAnswer } from './logic/useFocusAfterAnswer';
|
|
17
19
|
export { usePromptSession, type PromptSession } from './logic/usePromptSession';
|
|
18
20
|
export { PromptPrimary, ApprovalActions, type ApprovalButton } from './ui/PromptActions';
|
|
@@ -5,15 +5,19 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export function focusPromptStart(root: ParentNode | null | undefined): boolean {
|
|
7
7
|
const card = root?.querySelector<HTMLElement>('.prompt-card');
|
|
8
|
+
|
|
8
9
|
if (!card) {
|
|
9
10
|
return false;
|
|
10
11
|
}
|
|
12
|
+
|
|
11
13
|
const start =
|
|
12
14
|
card.querySelector<HTMLElement>('[data-prompt-entry]:not(:disabled)') ??
|
|
13
15
|
card.querySelector<HTMLElement>('[role="toolbar"] button:not(:disabled):not([data-prompt-primary]):not([data-prompt-lasting])') ??
|
|
14
16
|
card.querySelector<HTMLElement>('[data-prompt-primary]:not(:disabled)') ??
|
|
15
17
|
card.querySelector<HTMLElement>('.prompt-heading');
|
|
18
|
+
|
|
16
19
|
start?.focus({ preventScroll: true });
|
|
20
|
+
|
|
17
21
|
return start !== null;
|
|
18
22
|
}
|
|
19
23
|
|
|
@@ -21,5 +25,6 @@ export function focusPromptStart(root: ParentNode | null | undefined): boolean {
|
|
|
21
25
|
export function focusPromptHeading(root: ParentNode | null | undefined): boolean {
|
|
22
26
|
const heading = root?.querySelector<HTMLElement>('.prompt-card .prompt-heading');
|
|
23
27
|
heading?.focus({ preventScroll: true });
|
|
28
|
+
|
|
24
29
|
return !!heading;
|
|
25
30
|
}
|
|
@@ -30,6 +30,7 @@ export function stepIndex(index: number, count: number, to: ListStep): number {
|
|
|
30
30
|
if (count === 0) {
|
|
31
31
|
return -1;
|
|
32
32
|
}
|
|
33
|
+
|
|
33
34
|
switch (to) {
|
|
34
35
|
case 'first':
|
|
35
36
|
return 0;
|
|
@@ -50,19 +51,25 @@ export function choiceKey(event: PromptKeyEvent, { multiSelect, anyChosen }: { m
|
|
|
50
51
|
if (!isPlain(event)) {
|
|
51
52
|
return null;
|
|
52
53
|
}
|
|
54
|
+
|
|
53
55
|
const step = LIST_KEYS[event.key];
|
|
56
|
+
|
|
54
57
|
if (step) {
|
|
55
58
|
return { kind: 'move', to: step };
|
|
56
59
|
}
|
|
60
|
+
|
|
57
61
|
if (event.code === 'Space') {
|
|
58
62
|
return { kind: 'pick' };
|
|
59
63
|
}
|
|
64
|
+
|
|
60
65
|
if (event.key === 'Enter') {
|
|
61
66
|
if (!multiSelect) {
|
|
62
67
|
return { kind: 'pick-and-commit' };
|
|
63
68
|
}
|
|
69
|
+
|
|
64
70
|
return anyChosen ? { kind: 'commit' } : { kind: 'pick' };
|
|
65
71
|
}
|
|
72
|
+
|
|
66
73
|
return null;
|
|
67
74
|
}
|
|
68
75
|
|
|
@@ -74,13 +81,16 @@ export function answerFieldKey(
|
|
|
74
81
|
if (!isPlain(event)) {
|
|
75
82
|
return null;
|
|
76
83
|
}
|
|
84
|
+
|
|
77
85
|
if (event.key === 'ArrowUp' && belowChoices && caretAtStart) {
|
|
78
86
|
return { kind: 'to-last-choice' };
|
|
79
87
|
}
|
|
88
|
+
|
|
80
89
|
if (event.key === 'Enter') {
|
|
81
90
|
// An empty answer is not sent, and an empty line in front of the answer is never what Enter meant.
|
|
82
91
|
return hasText ? { kind: 'commit' } : { kind: 'ignore' };
|
|
83
92
|
}
|
|
93
|
+
|
|
84
94
|
return null;
|
|
85
95
|
}
|
|
86
96
|
|
|
@@ -101,9 +111,11 @@ export function pageKey(event: PromptKeyEvent, apple: boolean, typing: boolean):
|
|
|
101
111
|
if (typing || event.isComposing) {
|
|
102
112
|
return null;
|
|
103
113
|
}
|
|
114
|
+
|
|
104
115
|
if (matchesShortcut(PROMPT_SHORTCUTS.previousPrompt, event, apple)) {
|
|
105
116
|
return -1;
|
|
106
117
|
}
|
|
118
|
+
|
|
107
119
|
return matchesShortcut(PROMPT_SHORTCUTS.nextPrompt, event, apple) ? 1 : null;
|
|
108
120
|
}
|
|
109
121
|
|
|
@@ -2,17 +2,20 @@ import type { ChatApprovalItem, ChatQuestionItem, ChatQuestion } from '@adecore/
|
|
|
2
2
|
import { toggleChoice } from '../../chat/logic/answers';
|
|
3
3
|
|
|
4
4
|
export type PendingPrompt = ChatApprovalItem | ChatQuestionItem;
|
|
5
|
+
|
|
5
6
|
export type PromptAction =
|
|
6
7
|
| { kind: 'approve'; decision: 'allow' | 'allow-always' | 'deny'; message?: string }
|
|
7
8
|
| { kind: 'answer'; answers: Record<string, string> }
|
|
8
9
|
| { kind: 'dismiss' }
|
|
9
10
|
// A terminal's permission request, answered with one of the choices the host offered.
|
|
10
11
|
| { kind: 'choose'; choiceId: string };
|
|
12
|
+
|
|
11
13
|
export interface PromptAnswer {
|
|
12
14
|
choices: string[];
|
|
13
15
|
text: string;
|
|
14
16
|
custom: boolean;
|
|
15
17
|
}
|
|
18
|
+
|
|
16
19
|
export interface PromptDraft {
|
|
17
20
|
index: number;
|
|
18
21
|
answers: Record<string, PromptAnswer>;
|
|
@@ -23,9 +26,11 @@ export interface PromptDraft {
|
|
|
23
26
|
export function emptyPromptDraft(): PromptDraft {
|
|
24
27
|
return { index: 0, answers: {}, reason: '', showReason: false };
|
|
25
28
|
}
|
|
29
|
+
|
|
26
30
|
export function answerValue(answer: PromptAnswer): string {
|
|
27
31
|
return answer.custom ? answer.text.trim() : answer.choices.join(', ');
|
|
28
32
|
}
|
|
33
|
+
|
|
29
34
|
export function questionAnswer(draft: PromptDraft, question: ChatQuestion): PromptAnswer {
|
|
30
35
|
return draft.answers[question.id] ?? { choices: [], text: '', custom: question.choices.length === 0 };
|
|
31
36
|
}
|
|
@@ -46,13 +51,16 @@ export function orderPrompts<T>(prompts: readonly T[], blocking: (prompt: T) =>
|
|
|
46
51
|
|
|
47
52
|
export function nextPrompt(items: readonly PendingPrompt[], activeId: string | null): PendingPrompt | null {
|
|
48
53
|
const active = items.find((item) => item.requestId === activeId);
|
|
54
|
+
|
|
49
55
|
if (active) {
|
|
50
56
|
return active;
|
|
51
57
|
}
|
|
58
|
+
|
|
52
59
|
return orderPrompts(items, isBlockingPrompt, (item) => item.createdAt)[0] ?? null;
|
|
53
60
|
}
|
|
54
61
|
|
|
55
62
|
export function promptAnswers(item: ChatQuestionItem, draft: PromptDraft): Record<string, string> | null {
|
|
56
63
|
const answers = Object.fromEntries(item.questions.map((question) => [question.id, answerValue(questionAnswer(draft, question))]));
|
|
64
|
+
|
|
57
65
|
return Object.values(answers).every((answer) => answer !== '') ? answers : null;
|
|
58
66
|
}
|
|
@@ -78,8 +78,10 @@ export function approvalButtons(subject: PromptSubject, reason: string): Approva
|
|
|
78
78
|
if (subject.kind !== 'chat' || subject.item.kind !== 'approval') {
|
|
79
79
|
return [];
|
|
80
80
|
}
|
|
81
|
+
|
|
81
82
|
const { item } = subject;
|
|
82
83
|
const message = reason.trim();
|
|
84
|
+
|
|
83
85
|
return [
|
|
84
86
|
...(item.canAllowAlways && item.allowAlways
|
|
85
87
|
? [
|
|
@@ -116,18 +118,24 @@ export async function answerPrompt(
|
|
|
116
118
|
if (subject.kind === 'host') {
|
|
117
119
|
return host.prompts.answer(subject.prompt, action);
|
|
118
120
|
}
|
|
121
|
+
|
|
119
122
|
if (chat === null) {
|
|
120
123
|
throw new Error(i18next.t('agent-prompts:error.notConnected'));
|
|
121
124
|
}
|
|
125
|
+
|
|
122
126
|
const { item, nodeId } = subject;
|
|
127
|
+
|
|
123
128
|
if (action.kind === 'approve') {
|
|
124
129
|
return chat.approve(nodeId, item.requestId, action.decision, action.message);
|
|
125
130
|
}
|
|
131
|
+
|
|
126
132
|
if (action.kind === 'answer') {
|
|
127
133
|
return chat.answer(nodeId, item.requestId, action.answers);
|
|
128
134
|
}
|
|
135
|
+
|
|
129
136
|
if (action.kind === 'dismiss') {
|
|
130
137
|
return chat.dismiss(nodeId, item.id);
|
|
131
138
|
}
|
|
139
|
+
|
|
132
140
|
throw new Error(i18next.t('agent-prompts:error.noChoices'));
|
|
133
141
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useRef, useState, type MouseEvent } from 'react';
|
|
2
|
+
import { errorMessage } from '../../transport';
|
|
2
3
|
import { emptyPromptDraft, type PromptDraft } from './prompts';
|
|
3
4
|
|
|
4
5
|
interface PromptSessionOptions<T> {
|
|
@@ -42,13 +43,16 @@ export function usePromptSession<T>({ prompts, idOf, pick, disabled }: PromptSes
|
|
|
42
43
|
const busy = useRef(false);
|
|
43
44
|
const pressedRequest = useRef<string | null>(null);
|
|
44
45
|
const stillCompleted = completed.filter((id) => prompts.some((prompt) => idOf(prompt) === id));
|
|
46
|
+
|
|
45
47
|
if (stillCompleted.length !== completed.length) {
|
|
46
48
|
setCompleted(stillCompleted);
|
|
47
49
|
}
|
|
50
|
+
|
|
48
51
|
const waiting = prompts.filter((prompt) => !completed.includes(idOf(prompt)));
|
|
49
52
|
const active = pick(waiting, activeId, activeIndex);
|
|
50
53
|
const activeKey = active === null ? null : idOf(active);
|
|
51
54
|
const index = active === null ? 0 : waiting.indexOf(active);
|
|
55
|
+
|
|
52
56
|
if (index !== activeIndex) {
|
|
53
57
|
setActiveIndex(index);
|
|
54
58
|
}
|
|
@@ -60,32 +64,40 @@ export function usePromptSession<T>({ prompts, idOf, pick, disabled }: PromptSes
|
|
|
60
64
|
|
|
61
65
|
const finish = (id: string) => {
|
|
62
66
|
setCompleted((current) => [...current, id]);
|
|
67
|
+
|
|
63
68
|
setDrafts((current) => {
|
|
64
69
|
const next = { ...current };
|
|
65
70
|
delete next[id];
|
|
71
|
+
|
|
66
72
|
return next;
|
|
67
73
|
});
|
|
68
74
|
};
|
|
75
|
+
|
|
69
76
|
const act = async (prompt: T, send: () => Promise<void>): Promise<'sent' | 'failed' | 'busy'> => {
|
|
70
77
|
if (busy.current || disabled) {
|
|
71
78
|
return 'busy';
|
|
72
79
|
}
|
|
80
|
+
|
|
73
81
|
const id = idOf(prompt);
|
|
74
82
|
busy.current = true;
|
|
75
83
|
setSending(true);
|
|
76
84
|
setError(null);
|
|
85
|
+
|
|
77
86
|
try {
|
|
78
87
|
await send();
|
|
79
88
|
finish(id);
|
|
89
|
+
|
|
80
90
|
return 'sent';
|
|
81
91
|
} catch (cause) {
|
|
82
|
-
setError({ id, message:
|
|
92
|
+
setError({ id, message: errorMessage(cause) });
|
|
93
|
+
|
|
83
94
|
return 'failed';
|
|
84
95
|
} finally {
|
|
85
96
|
busy.current = false;
|
|
86
97
|
setSending(false);
|
|
87
98
|
}
|
|
88
99
|
};
|
|
100
|
+
|
|
89
101
|
return {
|
|
90
102
|
active,
|
|
91
103
|
activeId: activeKey,
|
|
@@ -32,6 +32,7 @@ function ApprovalDetails({ item }: { item: ChatApprovalItem }) {
|
|
|
32
32
|
const input = typeof item.input === 'object' && item.input !== null ? (item.input as Record<string, unknown>) : {};
|
|
33
33
|
// Some agents describe a command by the command itself, which the box under it already shows.
|
|
34
34
|
const describes = item.description && item.description.trim() !== (typeof input.command === 'string' ? input.command.trim() : null);
|
|
35
|
+
|
|
35
36
|
return (
|
|
36
37
|
<>
|
|
37
38
|
{describes && <p className="text-sm text-text-muted">{item.description}</p>}
|
|
@@ -82,6 +83,7 @@ export function ApprovalBody({
|
|
|
82
83
|
const host = useChatHost();
|
|
83
84
|
const { t } = useTranslation('agent-prompts');
|
|
84
85
|
const AnswerField = host.dictation.Textarea;
|
|
86
|
+
|
|
85
87
|
return (
|
|
86
88
|
<>
|
|
87
89
|
<ApprovalDetails item={item} />
|
|
@@ -32,6 +32,7 @@ export function ApprovalActions({
|
|
|
32
32
|
sending: boolean;
|
|
33
33
|
}) {
|
|
34
34
|
const { t } = useTranslation('agent-prompts');
|
|
35
|
+
|
|
35
36
|
return (
|
|
36
37
|
<>
|
|
37
38
|
{onAddReason && (
|
|
@@ -87,6 +88,7 @@ export function QuestionActions({
|
|
|
87
88
|
onCommit(): void;
|
|
88
89
|
}) {
|
|
89
90
|
const { t } = useTranslation(['agent-prompts', 'agent-chat']);
|
|
91
|
+
|
|
90
92
|
return (
|
|
91
93
|
<>
|
|
92
94
|
{index > 0 && (
|
|
@@ -35,6 +35,7 @@ interface PromptCardProps {
|
|
|
35
35
|
function onCardKeyDown(event: KeyboardEvent<HTMLDivElement>, apple: boolean) {
|
|
36
36
|
const card = event.currentTarget;
|
|
37
37
|
const target = event.target instanceof HTMLElement ? event.target : null;
|
|
38
|
+
|
|
38
39
|
if (!event.defaultPrevented) {
|
|
39
40
|
if (isPrimaryKey(event.nativeEvent, apple)) {
|
|
40
41
|
event.preventDefault();
|
|
@@ -46,6 +47,7 @@ function onCardKeyDown(event: KeyboardEvent<HTMLDivElement>, apple: boolean) {
|
|
|
46
47
|
} else {
|
|
47
48
|
const toolbar = target?.closest('[role="toolbar"]');
|
|
48
49
|
const step = toolbar ? toolbarKey(event.nativeEvent) : null;
|
|
50
|
+
|
|
49
51
|
if (toolbar && step !== null) {
|
|
50
52
|
event.preventDefault();
|
|
51
53
|
const buttons = [...toolbar.querySelectorAll<HTMLButtonElement>('button:not(:disabled)')];
|
|
@@ -54,6 +56,7 @@ function onCardKeyDown(event: KeyboardEvent<HTMLDivElement>, apple: boolean) {
|
|
|
54
56
|
}
|
|
55
57
|
}
|
|
56
58
|
}
|
|
59
|
+
|
|
57
60
|
if (event.defaultPrevented || staysInCard(event.nativeEvent)) {
|
|
58
61
|
event.stopPropagation();
|
|
59
62
|
}
|
|
@@ -63,6 +66,7 @@ function onCardKeyDown(event: KeyboardEvent<HTMLDivElement>, apple: boolean) {
|
|
|
63
66
|
export function PromptCard({ kind, heading, meta, top, actions, busy, notice, error, children }: PromptCardProps) {
|
|
64
67
|
const { t } = useTranslation('agent-prompts');
|
|
65
68
|
const { isApplePlatform } = useChatHost();
|
|
69
|
+
|
|
66
70
|
const card = (
|
|
67
71
|
<div
|
|
68
72
|
className="prompt-card flex min-h-0 flex-col gap-2 p-3"
|
|
@@ -96,9 +100,11 @@ export function PromptCard({ kind, heading, meta, top, actions, busy, notice, er
|
|
|
96
100
|
</div>
|
|
97
101
|
</div>
|
|
98
102
|
);
|
|
103
|
+
|
|
99
104
|
if (top === undefined) {
|
|
100
105
|
return card;
|
|
101
106
|
}
|
|
107
|
+
|
|
102
108
|
return (
|
|
103
109
|
<div className="flex min-h-0 flex-col">
|
|
104
110
|
{top}
|