@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
|
@@ -51,6 +51,7 @@ function useReplyAuthor(chatId: string) {
|
|
|
51
51
|
const { id } = useChatScope();
|
|
52
52
|
const context = useContext(ReplyContext);
|
|
53
53
|
const author = useHostReplyAuthor(id, context?.chatId ?? chatId);
|
|
54
|
+
|
|
54
55
|
return context !== null && context.chatId === undefined ? null : author;
|
|
55
56
|
}
|
|
56
57
|
|
|
@@ -62,6 +63,7 @@ function AttachmentLink({ chatId, attachment }: { chatId: string; attachment: Ch
|
|
|
62
63
|
const { id } = useChatScope();
|
|
63
64
|
const { url } = useHostAttachmentUrl(id, chatId, attachment.id);
|
|
64
65
|
const badge = fileBadge(attachment.name);
|
|
66
|
+
|
|
65
67
|
return (
|
|
66
68
|
<Tooltip label={attachment.name}>
|
|
67
69
|
<a
|
|
@@ -86,6 +88,7 @@ function AttachmentLink({ chatId, attachment }: { chatId: string; attachment: Ch
|
|
|
86
88
|
function AttachmentThumb({ chatId, attachment }: { chatId: string; attachment: ChatAttachment }) {
|
|
87
89
|
const { id } = useChatScope();
|
|
88
90
|
const source = useHostAttachmentUrl(id, chatId, attachment.id);
|
|
91
|
+
|
|
89
92
|
return <ImageThumb source={source} alt={attachment.name} className="max-h-32 max-w-48 object-cover" />;
|
|
90
93
|
}
|
|
91
94
|
|
|
@@ -113,6 +116,7 @@ export function UserRow({ chatId, item }: { chatId: string; item: ChatUserItem }
|
|
|
113
116
|
jumpToTimelineItem(keyOf(chatId), source, { flash: true, onMissing: () => setMissing(true) });
|
|
114
117
|
}
|
|
115
118
|
}
|
|
119
|
+
|
|
116
120
|
return (
|
|
117
121
|
<ReferenceLookupContext value={lookup}>
|
|
118
122
|
<div data-find-item={item.id} className="flex flex-col items-end" onCopy={(e) => copySelectionWithChips(e.nativeEvent)}>
|
|
@@ -189,6 +193,7 @@ function ChoiceLine({ chatId, choice }: { chatId: string; choice: ChatUiChoiceOr
|
|
|
189
193
|
const inherited = useContext(UiReplyNavigationContext);
|
|
190
194
|
const navigation = inherited?.chatId === chatId ? inherited : null;
|
|
191
195
|
const Tag = navigation ? 'button' : 'div';
|
|
196
|
+
|
|
192
197
|
return (
|
|
193
198
|
<Tag
|
|
194
199
|
type={navigation ? 'button' : undefined}
|
|
@@ -220,6 +225,7 @@ function MessageHeading({ children }: { children: ReactNode }) {
|
|
|
220
225
|
/* The report a subagent handed back, drawn as a reply under a label of its own. */
|
|
221
226
|
export function ReportRow({ id, text }: { id: string; text: string }) {
|
|
222
227
|
const { t } = useTranslation('agent-chat');
|
|
228
|
+
|
|
223
229
|
return (
|
|
224
230
|
<div data-find-item={id} className="-mx-1 px-1 pb-2">
|
|
225
231
|
<MessageHeading>{t('rows.report.heading')}</MessageHeading>
|
|
@@ -240,6 +246,7 @@ function ReplyHeading({ chatId }: { chatId: string }) {
|
|
|
240
246
|
const author = useReplyAuthor(chatId);
|
|
241
247
|
const kind = useChatRow(chatId, (row) => row?.info.provider);
|
|
242
248
|
const name = useProviders((s) => s.providers.find((provider) => provider.kind === (context?.provider ?? kind))?.name);
|
|
249
|
+
|
|
243
250
|
return <MessageHeading>{author?.name ?? name ?? t('rows.reply.agent')}</MessageHeading>;
|
|
244
251
|
}
|
|
245
252
|
|
|
@@ -249,9 +256,11 @@ function ReplyHeading({ chatId }: { chatId: string }) {
|
|
|
249
256
|
*/
|
|
250
257
|
export function ReplyHeader({ chatId, at }: { chatId: string; at: number | null }) {
|
|
251
258
|
const author = useReplyAuthor(chatId);
|
|
259
|
+
|
|
252
260
|
if (author === null) {
|
|
253
261
|
return null;
|
|
254
262
|
}
|
|
263
|
+
|
|
255
264
|
return (
|
|
256
265
|
<div aria-hidden className="mb-1 flex h-6 items-center gap-2 text-sm font-medium text-text select-none">
|
|
257
266
|
{author.mark}
|
|
@@ -263,21 +272,20 @@ export function ReplyHeader({ chatId, at }: { chatId: string; at: number | null
|
|
|
263
272
|
|
|
264
273
|
function ReplyAge({ at }: { at: number }) {
|
|
265
274
|
const ref = useTickingText(() => formatAgo(Date.now() - at), 30_000);
|
|
275
|
+
|
|
266
276
|
return <span ref={ref} className="shrink-0 font-normal text-text-faint" />;
|
|
267
277
|
}
|
|
268
278
|
|
|
269
279
|
/* The line that stands where the next words will land; a component, so the word is read at render and not at import. */
|
|
270
280
|
function Writing() {
|
|
271
281
|
const { t } = useTranslation('agent-chat');
|
|
282
|
+
|
|
272
283
|
return <span className="chat-live-text text-sm">{t('rows.reply.writing')}</span>;
|
|
273
284
|
}
|
|
274
285
|
|
|
275
286
|
/*
|
|
276
|
-
* A reply
|
|
277
|
-
*
|
|
278
|
-
* it says it is being written and fades in once it is done. Only a row that saw the reply being
|
|
279
|
-
* written fades anything: an old reply scrolled back into view just stands there. A `#Name` it
|
|
280
|
-
* spells for a view, node or chat of the project is a chip that opens it.
|
|
287
|
+
* A reply, streamed a word, a block or the whole of it at a time. Only a row that saw the reply being
|
|
288
|
+
* written fades anything in: an old reply scrolled back into view just stands there.
|
|
281
289
|
*/
|
|
282
290
|
export function AssistantRow({ chatId, item: derived }: { chatId: string; item: ChatAssistantItem }) {
|
|
283
291
|
const item = useCurrentItem(chatId, derived);
|
|
@@ -310,6 +318,7 @@ export function AssistantRow({ chatId, item: derived }: { chatId: string; item:
|
|
|
310
318
|
|
|
311
319
|
if (mode === 'blocks') {
|
|
312
320
|
const settled = item.streaming ? settledBlocksText(item.text) : item.text;
|
|
321
|
+
|
|
313
322
|
return (
|
|
314
323
|
<div data-find-item={item.id} className="-mx-1 px-1 pb-2" onCopy={(e) => copySelectionWithChips(e.nativeEvent)}>
|
|
315
324
|
<ReplyHeading chatId={chatId} />
|
|
@@ -324,6 +333,7 @@ export function AssistantRow({ chatId, item: derived }: { chatId: string; item:
|
|
|
324
333
|
</div>
|
|
325
334
|
);
|
|
326
335
|
}
|
|
336
|
+
|
|
327
337
|
if (mode === 'whole' && item.streaming) {
|
|
328
338
|
return (
|
|
329
339
|
<div className="-mx-1 px-1 pb-2">
|
|
@@ -332,6 +342,7 @@ export function AssistantRow({ chatId, item: derived }: { chatId: string; item:
|
|
|
332
342
|
</div>
|
|
333
343
|
);
|
|
334
344
|
}
|
|
345
|
+
|
|
335
346
|
return (
|
|
336
347
|
<div
|
|
337
348
|
data-find-item={item.id}
|
|
@@ -369,6 +380,7 @@ export function ThinkingRow({ chatId, item: derived }: { chatId: string; item: C
|
|
|
369
380
|
const preview = item.streaming ? '' : thoughtPreview(item.text);
|
|
370
381
|
const duration = formatElapsedShort((item.endedAt ?? item.createdAt) - item.createdAt);
|
|
371
382
|
useOpenForFind(item.id, 'text', setOpen);
|
|
383
|
+
|
|
372
384
|
return (
|
|
373
385
|
<div data-find-item={item.id} className="-mx-1 px-1 pb-2">
|
|
374
386
|
<button
|
|
@@ -418,9 +430,11 @@ export function ThinkingRow({ chatId, item: derived }: { chatId: string; item: C
|
|
|
418
430
|
export function LiveThoughtRow({ chatId, item: derived }: { chatId: string; item: ChatThinkingItem }) {
|
|
419
431
|
const item = useCurrentItem(chatId, derived);
|
|
420
432
|
const line = thoughtLine(item.text);
|
|
433
|
+
|
|
421
434
|
if (line === '') {
|
|
422
435
|
return null;
|
|
423
436
|
}
|
|
437
|
+
|
|
424
438
|
return (
|
|
425
439
|
<div className="-mx-1 mb-0.5 flex min-h-7 items-start gap-2 px-1 py-1 text-xs text-text-muted">
|
|
426
440
|
<span className={ROW_GUTTER}>
|
|
@@ -448,6 +462,7 @@ export function NoteRow({ id, level, text, from }: { id: string; level: 'info' |
|
|
|
448
462
|
const head = breakAt === -1 ? text : text.slice(0, breakAt);
|
|
449
463
|
const rest = breakAt === -1 ? '' : text.slice(breakAt + 1).trim();
|
|
450
464
|
useOpenForFind(id, 'output', setOpen);
|
|
465
|
+
|
|
451
466
|
return (
|
|
452
467
|
<div
|
|
453
468
|
data-find-item={id}
|
|
@@ -483,9 +498,11 @@ export function NoteRow({ id, level, text, from }: { id: string; level: 'info' |
|
|
|
483
498
|
function OpenChatButton({ chatId, label }: { chatId: string; label: 'openFork' | 'openWaiting' }) {
|
|
484
499
|
const { t } = useTranslation('agent-chat');
|
|
485
500
|
const place = useHostChatPlace(chatId);
|
|
501
|
+
|
|
486
502
|
if (place.title === null) {
|
|
487
503
|
return null;
|
|
488
504
|
}
|
|
505
|
+
|
|
489
506
|
return (
|
|
490
507
|
<button className="text-text-muted hover:text-text" onClick={place.go}>
|
|
491
508
|
{t(`rows.note.${label}`)}
|
|
@@ -499,6 +516,7 @@ function OpenChatButton({ chatId, label }: { chatId: string; label: 'openFork' |
|
|
|
499
516
|
*/
|
|
500
517
|
export function AgentTurnRow({ label, onOpen }: { label: string; onOpen?: () => void }) {
|
|
501
518
|
const line = 'mb-0.5 flex h-7 w-full items-center gap-2 text-left text-xs text-text-muted';
|
|
519
|
+
|
|
502
520
|
// A header with nowhere to go is text to read and copy; one that opens a row is a button.
|
|
503
521
|
const content = (
|
|
504
522
|
<>
|
|
@@ -508,9 +526,11 @@ export function AgentTurnRow({ label, onOpen }: { label: string; onOpen?: () =>
|
|
|
508
526
|
<span className={clsx('min-w-0 truncate', onOpen === undefined && 'select-text')}>{label}</span>
|
|
509
527
|
</>
|
|
510
528
|
);
|
|
529
|
+
|
|
511
530
|
if (onOpen === undefined) {
|
|
512
531
|
return <div className={line}>{content}</div>;
|
|
513
532
|
}
|
|
533
|
+
|
|
514
534
|
return (
|
|
515
535
|
<button className={clsx(line, 'hover:text-text')} onClick={onOpen}>
|
|
516
536
|
{content}
|
|
@@ -521,6 +541,7 @@ export function AgentTurnRow({ label, onOpen }: { label: string; onOpen?: () =>
|
|
|
521
541
|
/* A dashed line, since what stands above it is still there for the reader but only a summary to the agent. */
|
|
522
542
|
export function CompactionRow({ preTokens }: { preTokens: number | null }) {
|
|
523
543
|
const { t } = useTranslation('agent-chat');
|
|
544
|
+
|
|
524
545
|
return (
|
|
525
546
|
<div className="flex items-center gap-3 pb-3 text-xs text-text-faint">
|
|
526
547
|
<span className="grow border-t border-dashed border-border" />
|
|
@@ -542,9 +563,11 @@ const DECISION_ICON: Record<Exclude<ChatApprovalItem['decision'], 'pending'>, Re
|
|
|
542
563
|
/* The outcome of a permission request, one quiet line; the request itself lived on the composer. */
|
|
543
564
|
export function ApprovalHistoryRow({ item }: { item: ChatApprovalItem }) {
|
|
544
565
|
const { t } = useTranslation('agent-chat');
|
|
566
|
+
|
|
545
567
|
if (item.decision === 'pending') {
|
|
546
568
|
return null;
|
|
547
569
|
}
|
|
570
|
+
|
|
548
571
|
return (
|
|
549
572
|
<div className="-mx-1 mb-0.5 flex h-7 items-center gap-2 px-1 text-xs text-text-faint">
|
|
550
573
|
<span className={clsx(ROW_GUTTER, item.decision === 'deny' && 'text-status-error')}>{DECISION_ICON[item.decision]}</span>
|
|
@@ -563,6 +586,7 @@ export function ApprovalHistoryRow({ item }: { item: ChatApprovalItem }) {
|
|
|
563
586
|
|
|
564
587
|
export function QuestionHistoryRow({ item }: { item: ChatQuestionItem }) {
|
|
565
588
|
const { t } = useTranslation('agent-chat');
|
|
589
|
+
|
|
566
590
|
return (
|
|
567
591
|
<div>
|
|
568
592
|
{item.questions.map((question) => (
|
|
@@ -41,6 +41,7 @@ function AppCardBody({ card }: { card: ThreadCard }) {
|
|
|
41
41
|
|
|
42
42
|
function AppCardRow({ card }: { card: ThreadCard }) {
|
|
43
43
|
const { t } = useTranslation('agent-chat');
|
|
44
|
+
|
|
44
45
|
return (
|
|
45
46
|
<ErrorBoundary label={t('timeline.cardFailed')} resetKeys={[card]} compact className="relative rounded-lg">
|
|
46
47
|
<AppCardBody card={card} />
|
|
@@ -55,6 +56,7 @@ export function Row({ row, chatId, toggleGroup, toggleTurn, toggleSubagent, open
|
|
|
55
56
|
return <UserRow chatId={chatId} item={row.item} />;
|
|
56
57
|
case 'turn-start': {
|
|
57
58
|
const toolUseId = row.turn.taskToolUseId;
|
|
59
|
+
|
|
58
60
|
return <AgentTurnRow label={row.label} onOpen={toolUseId ? () => openSubagent(toolUseId) : undefined} />;
|
|
59
61
|
}
|
|
60
62
|
case 'assistant':
|
|
@@ -33,16 +33,20 @@ function ChildRow({ chatId, item }: { chatId: string; item: ChatItem }) {
|
|
|
33
33
|
if (isImageGeneration(item)) {
|
|
34
34
|
return <GeneratedImageRow chatId={chatId} tool={item} />;
|
|
35
35
|
}
|
|
36
|
+
|
|
36
37
|
return item.state === 'running' ? <WorkLiveRow chatId={chatId} tool={item} /> : <WorkRow chatId={chatId} tool={item} />;
|
|
37
38
|
}
|
|
39
|
+
|
|
38
40
|
if (item.kind === 'assistant') {
|
|
39
41
|
return <ChildText chatId={chatId} item={item} />;
|
|
40
42
|
}
|
|
43
|
+
|
|
41
44
|
return null;
|
|
42
45
|
}
|
|
43
46
|
|
|
44
47
|
function ChildText({ chatId, item: derived }: { chatId: string; item: ChatAssistantItem }) {
|
|
45
48
|
const item = useCurrentItem(chatId, derived);
|
|
49
|
+
|
|
46
50
|
return (
|
|
47
51
|
<div className="-mx-1 px-1 pb-2 text-xs text-text-muted select-text">
|
|
48
52
|
<Markdown text={item.text} />
|
|
@@ -54,15 +58,19 @@ function StatusPill({ item, task }: { item: ChatSubagentItem; task: SubagentTask
|
|
|
54
58
|
const { t } = useTranslation('agent-chat');
|
|
55
59
|
const paused = statusWordOf(item, task) === 'paused';
|
|
56
60
|
const now = useNow(60_000, paused);
|
|
61
|
+
|
|
57
62
|
if (paused) {
|
|
58
63
|
return <span className="shrink-0 text-xs text-text-faint tabular-nums">{entryTimeOf(item, task, now)}</span>;
|
|
59
64
|
}
|
|
65
|
+
|
|
60
66
|
if (item.status === 'running') {
|
|
61
67
|
return <RunningFor startedAt={item.startedAt} />;
|
|
62
68
|
}
|
|
69
|
+
|
|
63
70
|
const failed = item.status === 'failed';
|
|
64
71
|
const duration = item.finishedAt === null ? null : formatElapsedShort(item.finishedAt - item.startedAt);
|
|
65
72
|
const outcome = failed ? 'failed' : 'done';
|
|
73
|
+
|
|
66
74
|
return (
|
|
67
75
|
<span className={clsx('shrink-0 text-xs tabular-nums', failed ? 'text-status-error' : 'text-text-faint')}>
|
|
68
76
|
{duration === null ? t(`common.status.${outcome}`) : t(`rows.subagent.${outcome}In`, { duration })}
|
|
@@ -75,16 +83,19 @@ function SubagentWork({ chatId, item, work }: { chatId: string; item: ChatSubage
|
|
|
75
83
|
const { t } = useTranslation('agent-chat');
|
|
76
84
|
const scroller = useRef<HTMLDivElement>(null);
|
|
77
85
|
const running = item.status === 'running';
|
|
86
|
+
|
|
78
87
|
useLayoutEffect(() => {
|
|
79
88
|
// While it works, the newest line is the one worth seeing.
|
|
80
89
|
if (running && scroller.current) {
|
|
81
90
|
scroller.current.scrollTop = scroller.current.scrollHeight;
|
|
82
91
|
}
|
|
83
92
|
}, [work.length, running]);
|
|
93
|
+
|
|
84
94
|
if (work.length === 0) {
|
|
85
95
|
// A line inside a chat row, where the centered block of an EmptyState would outweigh the row itself.
|
|
86
96
|
return <div className="ml-6 pb-1 text-xs text-text-faint">{t('rows.subagent.nothingYet')}</div>;
|
|
87
97
|
}
|
|
98
|
+
|
|
88
99
|
return (
|
|
89
100
|
<div ref={scroller} className="ml-6 overflow-y-auto" style={{ maxHeight: CHILDREN_MAX_PX }}>
|
|
90
101
|
{item.itemsTruncated && <div className="pb-1 text-xs text-text-faint">{t('rows.subagent.truncated')}</div>}
|
|
@@ -100,6 +111,7 @@ function SubagentResult({ itemId, result }: { itemId: string; result: string })
|
|
|
100
111
|
const { t } = useTranslation('agent-chat');
|
|
101
112
|
const [open, setOpen] = useState(false);
|
|
102
113
|
useOpenForFind(itemId, 'output', setOpen);
|
|
114
|
+
|
|
103
115
|
return (
|
|
104
116
|
<div className="ml-6 pb-1">
|
|
105
117
|
<button className="flex items-center gap-1.5 text-xs text-text-muted hover:text-text" onClick={() => setOpen((o) => !o)}>
|
|
@@ -146,6 +158,7 @@ export function SubagentRow({
|
|
|
146
158
|
// A row that carries no pointer on a host that already said no has nothing to open.
|
|
147
159
|
const refused = useSubagentSupport((s) => s.unsupported[id] === true);
|
|
148
160
|
const press = onOpenConversation !== undefined && canOpenSubagent(item, refused) ? onOpenConversation : onToggle;
|
|
161
|
+
|
|
149
162
|
return (
|
|
150
163
|
<div data-find-item={item.id}>
|
|
151
164
|
{item.origin === 'ruimte' ? (
|
|
@@ -33,6 +33,7 @@ const STATE_TONE: Record<TaskRowState, string> = {
|
|
|
33
33
|
|
|
34
34
|
function Elapsed({ startedAt }: { startedAt: number }) {
|
|
35
35
|
const ref = useTickingText(() => formatElapsedShort(Date.now() - startedAt));
|
|
36
|
+
|
|
36
37
|
return <span ref={ref} className="shrink-0 text-xs text-text-faint tabular-nums" />;
|
|
37
38
|
}
|
|
38
39
|
|
|
@@ -40,6 +41,7 @@ function StateLine({ state, task }: { state: TaskRowState; task: SubagentTask |
|
|
|
40
41
|
const { t } = useTranslation('agent-chat');
|
|
41
42
|
const until = state === 'paused' ? task?.paused?.until : undefined;
|
|
42
43
|
const now = useNow(60_000, until !== undefined);
|
|
44
|
+
|
|
43
45
|
return (
|
|
44
46
|
<span className={clsx('truncate text-2xs', STATE_TONE[state])}>
|
|
45
47
|
{until === undefined ? t(`rows.task.${state}`) : t('rows.task.pausedUntil', { time: formatMoment(until, now) })}
|
|
@@ -58,18 +60,23 @@ export function TaskRow({ item, task, open, onPress }: { item: ChatSubagentItem;
|
|
|
58
60
|
const child = useChats((s) => (item.childId === undefined ? undefined : s.statusByKey[keyOf(item.childId)]?.info));
|
|
59
61
|
const provider = child?.provider;
|
|
60
62
|
const slug = child?.model ?? child?.selection.model ?? null;
|
|
63
|
+
|
|
61
64
|
const model = useProviders((s) => {
|
|
62
65
|
if (slug === null) {
|
|
63
66
|
return null;
|
|
64
67
|
}
|
|
68
|
+
|
|
65
69
|
const models = s.providers.find((entry) => entry.kind === provider)?.models;
|
|
70
|
+
|
|
66
71
|
return shortModelName(modelName(slug, models), models);
|
|
67
72
|
});
|
|
73
|
+
|
|
68
74
|
const state = taskRowStateOf(item, task, child);
|
|
69
75
|
const title = item.description || t('rows.subagent.task');
|
|
70
76
|
const startedAt = task?.createdAt ?? item.startedAt;
|
|
71
77
|
const finishedAt = task === null ? item.finishedAt : (task.settledAt ?? item.finishedAt);
|
|
72
78
|
const settled = state === 'done' || state === 'failed' || state === 'cancelled';
|
|
79
|
+
|
|
73
80
|
return (
|
|
74
81
|
<button className="-mx-1 mb-0.5 flex w-[calc(100%+8px)] items-start gap-2 rounded-md px-1 py-1 text-left hover:bg-surface-hover" onClick={onPress}>
|
|
75
82
|
<span className={clsx(ROW_GUTTER, 'relative text-text')}>
|
|
@@ -18,11 +18,15 @@ export function VisualRow({ chatId, visual }: { chatId: string; visual: ChatVisu
|
|
|
18
18
|
const host = useChatHost();
|
|
19
19
|
const { t } = useTranslation('agent-chat');
|
|
20
20
|
const { id: scopeId, keyOf } = useChatScope();
|
|
21
|
+
|
|
21
22
|
if (host.visuals === null) {
|
|
22
23
|
return null;
|
|
23
24
|
}
|
|
25
|
+
|
|
24
26
|
const extra = host.visuals.actions?.(scopeId, chatId, visual) ?? [];
|
|
27
|
+
|
|
25
28
|
const open = (kind: 'expand' | 'remove'): void => useVisualDialog.getState().open(keyOf(chatId), visual.id, kind);
|
|
29
|
+
|
|
26
30
|
return (
|
|
27
31
|
<ErrorBoundary label={t('visuals.renderFailed')} resetKeys={[visual]} compact className="relative rounded-lg">
|
|
28
32
|
<div className="group/visual relative">
|
|
@@ -59,6 +59,7 @@ const BRAND = 'font-semibold';
|
|
|
59
59
|
function withBrand(text: string, brands: readonly string[]): ReactNode {
|
|
60
60
|
for (const brand of brands) {
|
|
61
61
|
const at = brand === '' ? -1 : text.indexOf(brand);
|
|
62
|
+
|
|
62
63
|
if (at !== -1) {
|
|
63
64
|
return (
|
|
64
65
|
<>
|
|
@@ -69,6 +70,7 @@ function withBrand(text: string, brands: readonly string[]): ReactNode {
|
|
|
69
70
|
);
|
|
70
71
|
}
|
|
71
72
|
}
|
|
73
|
+
|
|
72
74
|
return text;
|
|
73
75
|
}
|
|
74
76
|
|
|
@@ -80,18 +82,23 @@ function hasNames(look: CommandLook): look is CommandLook & Required<Pick<Comman
|
|
|
80
82
|
function NamedLookDetail({ run, chatId, look }: { run: CommandLookRun; chatId: string; look: Required<Pick<CommandLook, 'useNames'>> }) {
|
|
81
83
|
const scope = useContext(ChatScopeContext);
|
|
82
84
|
const nameOf = useCommandNames(look, scope?.id ?? '', chatId);
|
|
85
|
+
|
|
83
86
|
const names = run.words.flatMap((word): NamedWord[] => {
|
|
84
87
|
const name = nameOf(word.text, word.option);
|
|
88
|
+
|
|
85
89
|
return name === null ? [] : [{ start: word.start, end: word.end, word: word.text, name }];
|
|
86
90
|
});
|
|
91
|
+
|
|
87
92
|
return <ShellCommand command={run.detail} code={run.code} names={names} />;
|
|
88
93
|
}
|
|
89
94
|
|
|
90
95
|
function LookDetail({ run, chatId }: { run: CommandLookRun; chatId: string }) {
|
|
91
96
|
const { look } = run;
|
|
97
|
+
|
|
92
98
|
if (!hasNames(look)) {
|
|
93
99
|
return <ShellCommand command={run.detail} code={run.code} />;
|
|
94
100
|
}
|
|
101
|
+
|
|
95
102
|
// Keyed by the look, so a row whose command turns into another look's starts its hooks again.
|
|
96
103
|
return <NamedLookDetail key={look.program} run={run} chatId={chatId} look={look} />;
|
|
97
104
|
}
|
|
@@ -102,6 +109,7 @@ const TAG = 'shrink-0 rounded bg-surface-hover px-1.5 text-text-faint';
|
|
|
102
109
|
function LookTags({ run }: { run: CommandLookRun }) {
|
|
103
110
|
const { t } = useTranslation('agent-chat');
|
|
104
111
|
const also = run.heredoc ? [...run.others, t('work.heredoc')] : run.others;
|
|
112
|
+
|
|
105
113
|
return (
|
|
106
114
|
<>
|
|
107
115
|
{also.length > 0 && <span className={TAG}>{t('work.alsoRan', { programs: also.join(', ') })}</span>}
|
|
@@ -156,6 +164,7 @@ export function ToggleLine({
|
|
|
156
164
|
failed && 'text-status-error',
|
|
157
165
|
className
|
|
158
166
|
);
|
|
167
|
+
|
|
159
168
|
const content = (
|
|
160
169
|
<>
|
|
161
170
|
<span className={clsx(ROW_GUTTER, live && 'text-accent')}>{icon}</span>
|
|
@@ -192,9 +201,11 @@ export function ToggleLine({
|
|
|
192
201
|
)}
|
|
193
202
|
</>
|
|
194
203
|
);
|
|
204
|
+
|
|
195
205
|
if (onToggle === undefined) {
|
|
196
206
|
return <div className={classes}>{content}</div>;
|
|
197
207
|
}
|
|
208
|
+
|
|
198
209
|
return (
|
|
199
210
|
<button className={classes} onClick={onToggle}>
|
|
200
211
|
{content}
|
|
@@ -205,6 +216,7 @@ export function ToggleLine({
|
|
|
205
216
|
/* The diff renderers load lazily, so a diff waits on them under a line that says so. */
|
|
206
217
|
function DiffSuspense({ children }: { children: ReactNode }) {
|
|
207
218
|
const { t } = useTranslation('agent-chat');
|
|
219
|
+
|
|
208
220
|
return <LazyBoundary fallback={<div className="px-3 py-2 text-xs text-text-faint">{t('work.loadingDiff')}</div>}>{children}</LazyBoundary>;
|
|
209
221
|
}
|
|
210
222
|
|
|
@@ -262,11 +274,14 @@ function DiffBody({ tool, entries, patched }: { tool: ChatToolItem; entries: rea
|
|
|
262
274
|
/* What a call answered, muted under the call; a failure in the error color, or its exit code when the tool names one. */
|
|
263
275
|
function ToolOutput({ tool }: { tool: ChatToolItem }) {
|
|
264
276
|
const { t } = useTranslation('agent-chat');
|
|
277
|
+
|
|
265
278
|
if (!hasOutput(tool.output)) {
|
|
266
279
|
return null;
|
|
267
280
|
}
|
|
281
|
+
|
|
268
282
|
const failed = tool.state === 'error';
|
|
269
283
|
const { code, rest } = failed ? exitCodeOf(tool.output) : { code: null, rest: tool.output };
|
|
284
|
+
|
|
270
285
|
return (
|
|
271
286
|
<>
|
|
272
287
|
{hasOutput(rest) && (
|
|
@@ -286,10 +301,13 @@ function ToolOutput({ tool }: { tool: ChatToolItem }) {
|
|
|
286
301
|
export function ToolBody({ tool }: { tool: ChatToolItem }) {
|
|
287
302
|
const patches = unifiedChanges(tool);
|
|
288
303
|
const changes = patches.length > 0 ? [] : fileChanges(tool.name, tool.input);
|
|
304
|
+
|
|
289
305
|
if (patches.length + changes.length > 0) {
|
|
290
306
|
return <DiffBody tool={tool} entries={reviewEntries(patches, changes)} patched={patches.length > 0} />;
|
|
291
307
|
}
|
|
308
|
+
|
|
292
309
|
const lines = toolCallLines(tool.name, tool.input);
|
|
310
|
+
|
|
293
311
|
return (
|
|
294
312
|
<div className="mt-0.5 mb-2 ml-6 flex flex-col gap-1.5 font-mono text-code select-text">
|
|
295
313
|
{lines.command !== null && (
|
|
@@ -345,6 +363,7 @@ export function WorkRow({
|
|
|
345
363
|
const opens = hasToolBody(tool);
|
|
346
364
|
const shell = shellCommand(tool.name, tool.input);
|
|
347
365
|
const run = detail === undefined && icon === undefined && label === undefined && shell !== null ? matchCommandLook(shell, host.commandLooks) : null;
|
|
366
|
+
|
|
348
367
|
return (
|
|
349
368
|
<div data-find-item={tool.id} className={nested ? 'ml-6' : undefined}>
|
|
350
369
|
<ToggleLine
|
|
@@ -370,6 +389,7 @@ export function WorkRow({
|
|
|
370
389
|
export function RunningFor({ startedAt }: { startedAt: number }) {
|
|
371
390
|
const { t } = useTranslation('agent-chat');
|
|
372
391
|
const ref = useTickingText(() => t('work.runningFor', { elapsed: formatElapsedShort(Date.now() - startedAt) }));
|
|
392
|
+
|
|
373
393
|
return <span ref={ref} className="shrink-0 text-xs text-text-faint tabular-nums" />;
|
|
374
394
|
}
|
|
375
395
|
|
|
@@ -385,6 +405,7 @@ export function WorkLiveRow({ chatId, tool: derived }: { chatId: string; tool: C
|
|
|
385
405
|
const run = shell === null ? null : matchCommandLook(shell, commandLooks);
|
|
386
406
|
const awaiting = useAwaitsApproval(chatId, tool.toolUseId);
|
|
387
407
|
const { t } = useTranslation('agent-chat');
|
|
408
|
+
|
|
388
409
|
return (
|
|
389
410
|
<div>
|
|
390
411
|
<ToggleLine
|
|
@@ -431,6 +452,7 @@ export function WorkGroupRow({
|
|
|
431
452
|
onToggle(): void;
|
|
432
453
|
}) {
|
|
433
454
|
const failed = tools.some((tool) => tool.state === 'error');
|
|
455
|
+
|
|
434
456
|
return (
|
|
435
457
|
<div>
|
|
436
458
|
<ToggleLine
|
|
@@ -464,6 +486,7 @@ export function TurnFoldRow({
|
|
|
464
486
|
}) {
|
|
465
487
|
const { commandLooks } = useChatHost();
|
|
466
488
|
const brands = commandLooks?.flatMap(({ brand }) => (brand === undefined ? [] : [brand])) ?? [];
|
|
489
|
+
|
|
467
490
|
return (
|
|
468
491
|
<button
|
|
469
492
|
className={clsx(
|
|
@@ -502,6 +525,7 @@ function CheckpointFileBody({ file }: { file: ChatCheckpointFile }) {
|
|
|
502
525
|
if (file.omitted) {
|
|
503
526
|
return <div className="px-3 py-2 text-xs text-text-faint">{omittedLabel(file.omitted)}</div>;
|
|
504
527
|
}
|
|
528
|
+
|
|
505
529
|
return (
|
|
506
530
|
<DiffSuspense>
|
|
507
531
|
<UnifiedDiff change={file} />
|
|
@@ -533,10 +557,12 @@ function ChangedFilesCard({
|
|
|
533
557
|
const [expanded, setExpanded] = useState(false);
|
|
534
558
|
// A jump opens the card, also one that mounted it by scrolling it on screen; the flash is gone by the next visit.
|
|
535
559
|
const [seenReveal, setSeenReveal] = useState(0);
|
|
560
|
+
|
|
536
561
|
if (revealNonce > 0 && revealNonce !== seenReveal) {
|
|
537
562
|
setSeenReveal(revealNonce);
|
|
538
563
|
setExpanded(true);
|
|
539
564
|
}
|
|
565
|
+
|
|
540
566
|
return (
|
|
541
567
|
<div className="mb-3 overflow-hidden rounded-lg border border-border bg-surface-raised">
|
|
542
568
|
<button
|
|
@@ -588,11 +614,14 @@ export function ChangedFilesRow({
|
|
|
588
614
|
const [open, setOpen] = useState<Record<string, boolean>>({});
|
|
589
615
|
const [fetched, setFetched] = useState<ChatCheckpointDiff | null>(null);
|
|
590
616
|
const actions = useChatActions();
|
|
617
|
+
|
|
591
618
|
useEffect(() => {
|
|
592
619
|
if (diff !== null || !checkpoint) {
|
|
593
620
|
return;
|
|
594
621
|
}
|
|
622
|
+
|
|
595
623
|
let alive = true;
|
|
624
|
+
|
|
596
625
|
void actions
|
|
597
626
|
.turnDiff(chatId, turnId)
|
|
598
627
|
.then((answer) => {
|
|
@@ -601,16 +630,20 @@ export function ChangedFilesRow({
|
|
|
601
630
|
}
|
|
602
631
|
})
|
|
603
632
|
.catch(() => undefined);
|
|
633
|
+
|
|
604
634
|
return () => {
|
|
605
635
|
alive = false;
|
|
606
636
|
};
|
|
607
637
|
}, [actions, chatId, turnId, diff, checkpoint]);
|
|
638
|
+
|
|
608
639
|
const checkpointDiff = diff ?? fetched;
|
|
609
640
|
const { keyOf } = useChatScope();
|
|
610
641
|
const flash = useTimelineFlash((s) => s.target);
|
|
611
642
|
const revealNonce = flash !== null && flash.opens && flash.key === keyOf(chatId) && flash.rowId === `files-${turnId}` ? flash.nonce : 0;
|
|
643
|
+
|
|
612
644
|
if (checkpointDiff !== null && checkpointDiff.files.length > 0) {
|
|
613
645
|
const files = checkpointDiff.files;
|
|
646
|
+
|
|
614
647
|
return (
|
|
615
648
|
<ChangedFilesCard
|
|
616
649
|
revealNonce={revealNonce}
|
|
@@ -639,6 +672,7 @@ export function ChangedFilesRow({
|
|
|
639
672
|
</ChangedFilesCard>
|
|
640
673
|
);
|
|
641
674
|
}
|
|
675
|
+
|
|
642
676
|
return <ProviderChangedFiles tools={tools} open={open} setOpen={setOpen} revealNonce={revealNonce} />;
|
|
643
677
|
}
|
|
644
678
|
|
|
@@ -659,6 +693,7 @@ function ProviderReviewFiles({
|
|
|
659
693
|
}) {
|
|
660
694
|
const { t } = useTranslation('agent-chat');
|
|
661
695
|
const stack = useReviewStack(reviews.filter(({ path }) => open[path] === true).flatMap(({ reviews }) => reviews));
|
|
696
|
+
|
|
662
697
|
return reviews.map(({ path, count, reviews }) => (
|
|
663
698
|
<ChangedFileLine
|
|
664
699
|
key={path}
|
|
@@ -685,32 +720,42 @@ function ProviderChangedFiles({
|
|
|
685
720
|
setOpen: Dispatch<SetStateAction<Record<string, boolean>>>;
|
|
686
721
|
}) {
|
|
687
722
|
const byPath = new Map<string, { edits: FileChange[]; patches: ChatFileChange[] }>();
|
|
723
|
+
|
|
688
724
|
const entryFor = (path: string) => {
|
|
689
725
|
const existing = byPath.get(path);
|
|
726
|
+
|
|
690
727
|
if (existing) {
|
|
691
728
|
return existing;
|
|
692
729
|
}
|
|
730
|
+
|
|
693
731
|
const created = { edits: [] as FileChange[], patches: [] as ChatFileChange[] };
|
|
694
732
|
byPath.set(path, created);
|
|
733
|
+
|
|
695
734
|
return created;
|
|
696
735
|
};
|
|
736
|
+
|
|
697
737
|
for (const tool of tools) {
|
|
698
738
|
const patches = unifiedChanges(tool);
|
|
739
|
+
|
|
699
740
|
if (patches.length > 0) {
|
|
700
741
|
for (const patch of patches) {
|
|
701
742
|
entryFor(patch.path).patches.push(patch);
|
|
702
743
|
}
|
|
744
|
+
|
|
703
745
|
continue;
|
|
704
746
|
}
|
|
747
|
+
|
|
705
748
|
for (const change of fileChanges(tool.name, tool.input)) {
|
|
706
749
|
entryFor(change.path || tool.id).edits.push(change);
|
|
707
750
|
}
|
|
708
751
|
}
|
|
752
|
+
|
|
709
753
|
const reviews = [...byPath].map(([path, entry]) => ({
|
|
710
754
|
path,
|
|
711
755
|
count: entry.patches.length + entry.edits.length,
|
|
712
756
|
reviews: reviewEntries(entry.patches, entry.edits)
|
|
713
757
|
}));
|
|
758
|
+
|
|
714
759
|
return (
|
|
715
760
|
<ChangedFilesCard count={byPath.size} revealNonce={revealNonce}>
|
|
716
761
|
<ProviderReviewFiles reviews={reviews} open={open} setOpen={setOpen} />
|
|
@@ -722,6 +767,7 @@ function ProviderChangedFiles({
|
|
|
722
767
|
export function WorkingRow({ startedAt }: { startedAt: number }) {
|
|
723
768
|
const { t } = useTranslation('agent-chat');
|
|
724
769
|
const ref = useTickingText(() => formatClockDuration(Date.now() - startedAt));
|
|
770
|
+
|
|
725
771
|
return (
|
|
726
772
|
<div className="-mx-1 mb-0.5 flex h-7 items-center gap-2 px-1 text-xs text-text-muted">
|
|
727
773
|
<span className={`${ROW_GUTTER} text-status-running`}>
|