@agent-native/core 0.149.0 → 0.149.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/corpus/README.md +1 -1
- package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +2 -0
- package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +150 -46
- package/corpus/templates/analytics/app/global.css +1 -1
- package/corpus/templates/analytics/app/i18n-data.ts +37 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/PanelEditorDialog.tsx +1 -1
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +32 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/types.ts +2 -0
- package/corpus/templates/analytics/changelog/2026-08-10-dashboard-tables-can-be-copied-and-sorted-by-multiple-column.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
- package/corpus/templates/assets/app/global.css +1 -1
- package/corpus/templates/assets/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
- package/corpus/templates/brain/app/global.css +1 -1
- package/corpus/templates/brain/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
- package/corpus/templates/chat/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-10-clips-desktop-sign-in-now-starts-with-magic-links-and-google.md +6 -0
- package/corpus/templates/clips/chrome-extension/src/overlay.css +1 -0
- package/corpus/templates/clips/desktop/src/app.tsx +274 -137
- package/corpus/templates/clips/desktop/src/styles.css +35 -0
- package/corpus/templates/content/app/global.css +1 -0
- package/corpus/templates/crm/app/global.css +1 -1
- package/corpus/templates/crm/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
- package/corpus/templates/dispatch/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
- package/corpus/templates/factory/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
- package/corpus/templates/forms/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
- package/corpus/templates/plan/app/global.css +1 -0
- package/corpus/templates/plan/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
- package/corpus/templates/plan/server/ui-plan-html.ts +4 -1
- package/corpus/templates/slides/AGENTS.md +11 -10
- package/corpus/templates/slides/actions/add-deck.ts +2 -0
- package/corpus/templates/slides/actions/add-slide.ts +15 -1
- package/corpus/templates/slides/actions/create-deck.ts +18 -6
- package/corpus/templates/slides/actions/get-deck.ts +29 -1
- package/corpus/templates/slides/actions/patch-deck.ts +139 -10
- package/corpus/templates/slides/actions/save-deck.ts +24 -1
- package/corpus/templates/slides/app/components/deck/SlideRenderer.tsx +46 -0
- package/corpus/templates/slides/app/components/editor/BlockBubbleMenu.tsx +194 -3
- package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +10 -1
- package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +134 -618
- package/corpus/templates/slides/app/components/editor/ExportMenu.tsx +74 -63
- package/corpus/templates/slides/app/components/editor/GeneratingSlidePreview.tsx +1 -1
- package/corpus/templates/slides/app/components/editor/GoogleDriveConnectionCta.tsx +13 -1
- package/corpus/templates/slides/app/components/editor/NewDeckReferenceStep.tsx +56 -174
- package/corpus/templates/slides/app/components/editor/PromptDialog.tsx +239 -116
- package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +29 -7
- package/corpus/templates/slides/app/components/editor/slide-object-interactions.ts +45 -0
- package/corpus/templates/slides/app/components/layout/AgentWorkIndicator.tsx +1 -1
- package/corpus/templates/slides/app/components/layout/Layout.tsx +34 -35
- package/corpus/templates/slides/app/components/layout/layout-route-policy.ts +2 -5
- package/corpus/templates/slides/app/components/onboarding/FirstDeckOnboardingFlow.tsx +45 -40
- package/corpus/templates/slides/app/components/presentation/PresentationView.tsx +63 -16
- package/corpus/templates/slides/app/hooks/use-generating-slide-preview.ts +25 -3
- package/corpus/templates/slides/app/i18n/en-US.ts +1 -0
- package/corpus/templates/slides/app/lib/create-deck-generation.ts +5 -4
- package/corpus/templates/slides/app/lib/export-pdf-client.ts +84 -25
- package/corpus/templates/slides/app/lib/import-uploaded-deck.ts +11 -0
- package/corpus/templates/slides/app/lib/recent-references.ts +23 -1
- package/corpus/templates/slides/app/lib/slide-animation-elements.ts +41 -3
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +16 -27
- package/corpus/templates/slides/app/pages/Index.tsx +256 -98
- package/corpus/templates/slides/changelog/2026-08-08-google-slides-export-now-tells-you-why-a-deck-fell-back-to-a.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-09-delete-key-now-removes-a-selected-image.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-09-editing-a-slide-in-an-imported-deck-no-longer-fails-to-save.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-09-fixed-pdf-and-custom-size-powerpoint-imports-rendering-with-.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-09-images-from-sites-without-cors-no-longer-export-blank.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-09-imported-pdf-headings-no-longer-lose-the-space-between-color.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-09-imported-slide-text-no-longer-renders-too-large-for-its-box.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-09-large-decks-no-longer-render-slowly-or-glitch-in-the-editor.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-09-revise-highlighted-slide-text-with-ai.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-09-the-deck-editor-no-longer-stays-dimmed-after-the-window-narro.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-10-ai-editing-avatar-badge.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-10-generated-decks-keep-a-clear-human-readable-title.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-10-new-deck-creation-now-shows-progress-opens-the-editor-direct.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-10-presentation-reveals-now-follow-valid-targets.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-10-slides-editing-controls-are-consolidated-into-one-focused-me.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-10-slides-now-verify-and-restyle-every-imported-slide-in-one-pa.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-10-slides-only-suggests-a-google-connection-for-relevant-reques.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-10-the-google-slides-import-option-is-now-labeled-slides.md +6 -0
- package/corpus/templates/slides/server/handlers/import/html-converter.ts +115 -22
- package/corpus/templates/slides/server/handlers/import/pdf-fidelity-parser.ts +11 -2
- package/corpus/templates/slides/server/lib/chat-attachments.ts +1 -1
- package/corpus/templates/slides/server/lib/fetch-remote-image.ts +192 -0
- package/corpus/templates/slides/server/lib/image-proxy-url.ts +192 -0
- package/corpus/templates/slides/server/plugins/agent-chat.ts +5 -3
- package/corpus/templates/slides/server/routes/api/image-proxy.get.ts +65 -0
- package/corpus/templates/slides/shared/api.ts +2 -1
- package/corpus/templates/slides/shared/deck-title.ts +135 -0
- package/corpus/templates/tasks/app/components/tasks/TaskListRow.tsx +4 -1
- package/dist/agent/engine/ai-sdk-engine.js +1 -1
- package/dist/agent/production-agent.d.ts +21 -1
- package/dist/agent/production-agent.js +129 -10
- package/dist/agent/tool-approval-store.d.ts +18 -0
- package/dist/agent/tool-approval-store.js +122 -0
- package/dist/agent/types.d.ts +1 -1
- package/dist/cli/code-agent-executor.js +11 -2
- package/dist/client/AgentPanel.js +31 -6
- package/dist/client/AssistantChat.d.ts +3 -2
- package/dist/client/AssistantChat.js +7 -20
- package/dist/client/agent-chat/index.d.ts +1 -1
- package/dist/client/agent-chat-adapter.js +11 -0
- package/dist/client/agent-chat.d.ts +1 -1
- package/dist/client/chat/markdown-renderer.js +14 -2
- package/dist/client/chat/message-components.d.ts +6 -2
- package/dist/client/chat/message-components.js +25 -47
- package/dist/client/chat/tool-call-display.d.ts +3 -5
- package/dist/client/chat/tool-call-display.js +7 -212
- package/dist/client/chat-first/apps-rail.js +3 -3
- package/dist/client/chat-first/browser-pane.js +4 -1
- package/dist/client/chat-first/chat-history.d.ts +3 -1
- package/dist/client/chat-first/chat-history.js +2 -2
- package/dist/client/chat-first/surface-tabs.d.ts +1 -1
- package/dist/client/chat-first/surface-tabs.js +52 -41
- package/dist/client/chat-first/types.d.ts +3 -0
- package/dist/client/chat-first.d.ts +10 -0
- package/dist/client/chat-first.js +37 -2
- package/dist/client/components/ui/message-scroller.js +4 -1
- package/dist/client/i18n.js +3 -1
- package/dist/client/progress/RunsTray.js +14 -1
- package/dist/client/resources/McpConnectionSuggestion.js +9 -1
- package/dist/client/sse-event-processor.js +10 -0
- package/dist/client/use-chat-models.js +156 -80
- package/dist/integrations/webhook-handler.js +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +1 -1
- package/dist/secrets/routes.d.ts +6 -6
- package/dist/server/auth.js +262 -31
- package/dist/server/onboarding-html.js +56 -9
- package/dist/shared/reasoning-effort.d.ts +8 -8
- package/dist/shared/reasoning-effort.js +10 -10
- package/dist/shared/streaming-text-smoothing.js +41 -11
- package/dist/styles/agent-native.css +19 -32
- package/dist/templates/chat/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
- package/docs/content/template-chat.mdx +1 -1
- package/package.json +2 -2
- package/src/templates/chat/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
|
@@ -49,15 +49,19 @@ export declare function shouldOfferRestore(args: {
|
|
|
49
49
|
* messages put it at `metadata.runId`.
|
|
50
50
|
*/
|
|
51
51
|
export declare function assistantMessageRunId(message: unknown): string | undefined;
|
|
52
|
+
export declare function resolveAssistantRequestId(message: unknown, activeRun: {
|
|
53
|
+
threadId: string;
|
|
54
|
+
runId: string;
|
|
55
|
+
} | null, threadId: string): string | undefined;
|
|
52
56
|
export declare function MessageBranchPicker(): React.JSX.Element;
|
|
53
|
-
export declare function MessageActionsMenu({ showRevert, onRevert, }?: {
|
|
57
|
+
export declare function MessageActionsMenu({ showRevert, onRevert, threadId, }?: {
|
|
54
58
|
showRevert?: boolean;
|
|
55
59
|
onRevert?: () => void;
|
|
60
|
+
threadId?: string;
|
|
56
61
|
}): React.JSX.Element;
|
|
57
62
|
export declare function UserMessage(): React.JSX.Element | null;
|
|
58
63
|
export declare function messageTextFromContent(content: unknown): string;
|
|
59
64
|
export declare function isMissingFinalResponseWarningText(text: string): boolean;
|
|
60
|
-
export declare function completedAssistantToolNamesAfterLastText(content: readonly ContentPart[]): string[];
|
|
61
65
|
export declare function latestUserMessageText(messages: readonly unknown[]): string;
|
|
62
66
|
export declare function userMessageTextBeforeAssistant(messages: readonly unknown[], assistantMessageId: string): string;
|
|
63
67
|
export declare function assistantMessageHasUnresolvedTool(content: unknown): boolean;
|
|
@@ -14,7 +14,7 @@ import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel,
|
|
|
14
14
|
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from "../components/ui/tooltip.js";
|
|
15
15
|
import { ThumbsFeedback } from "../observability/ThumbsFeedback.js";
|
|
16
16
|
import { McpConnectionSuggestion } from "../resources/McpConnectionSuggestion.js";
|
|
17
|
-
import {
|
|
17
|
+
import { isCallAgentToolCallShadowed, shadowedCallAgentToolCallIds, } from "../tool-display.js";
|
|
18
18
|
import { cn } from "../utils.js";
|
|
19
19
|
import { MarkdownText, renderMarkdownToClipboardHtml, SmoothMarkdownText, } from "./markdown-renderer.js";
|
|
20
20
|
import { getAssistantRunDurationMs } from "./repo-helpers.js";
|
|
@@ -172,6 +172,10 @@ export function assistantMessageRunId(message) {
|
|
|
172
172
|
? metadata.runId
|
|
173
173
|
: undefined;
|
|
174
174
|
}
|
|
175
|
+
export function resolveAssistantRequestId(message, activeRun, threadId) {
|
|
176
|
+
return (assistantMessageRunId(message) ||
|
|
177
|
+
(activeRun?.threadId === threadId ? activeRun.runId : undefined));
|
|
178
|
+
}
|
|
175
179
|
// ─── MessageBranchPicker ──────────────────────────────────────────────────────
|
|
176
180
|
export function MessageBranchPicker() {
|
|
177
181
|
return (_jsxs(BranchPickerPrimitive.Root, { hideWhenSingleBranch: true, className: "flex items-center gap-0.5 text-[11px] text-muted-foreground", children: [_jsx(BranchPickerPrimitive.Previous, { asChild: true, children: _jsx("button", { type: "button", "aria-label": "Previous branch", className: "flex h-6 w-6 cursor-pointer items-center justify-center rounded-md text-muted-foreground/70 transition-colors duration-150 hover:bg-accent hover:text-foreground disabled:cursor-not-allowed disabled:opacity-40", children: _jsx(IconChevronLeft, { className: "h-3.5 w-3.5" }) }) }), _jsxs("span", { className: "tabular-nums select-none", children: [_jsx(BranchPickerPrimitive.Number, {}), "/", _jsx(BranchPickerPrimitive.Count, {})] }), _jsx(BranchPickerPrimitive.Next, { asChild: true, children: _jsx("button", { type: "button", "aria-label": "Next branch", className: "flex h-6 w-6 cursor-pointer items-center justify-center rounded-md text-muted-foreground/70 transition-colors duration-150 hover:bg-accent hover:text-foreground disabled:cursor-not-allowed disabled:opacity-40", children: _jsx(IconChevronRight, { className: "h-3.5 w-3.5" }) }) })] }));
|
|
@@ -284,7 +288,7 @@ function UserMessageEditComposer() {
|
|
|
284
288
|
return (_jsxs(ComposerPrimitive.Root, { className: "flex flex-col gap-2 rounded-lg border border-border bg-background px-3 py-2 shadow-sm", children: [_jsx(ComposerPrimitive.Input, { className: "w-full resize-none bg-transparent text-sm leading-relaxed text-foreground placeholder:text-muted-foreground focus:outline-none", rows: 1, submitMode: "enter" }), _jsxs("div", { className: "flex justify-end gap-2", children: [_jsx(ComposerPrimitive.Cancel, { asChild: true, children: _jsx("button", { type: "button", className: "cursor-pointer rounded-md px-2 py-1 text-xs font-medium text-muted-foreground hover:bg-accent hover:text-foreground", children: "Cancel" }) }), _jsx(ComposerPrimitive.Send, { asChild: true, children: _jsx("button", { type: "submit", className: "cursor-pointer rounded-md bg-foreground px-2 py-1 text-xs font-medium text-background hover:opacity-90 disabled:opacity-50", children: "Save" }) })] })] }));
|
|
285
289
|
}
|
|
286
290
|
// ─── MessageActionsMenu ────────────────────────────────────────────────────────
|
|
287
|
-
export function MessageActionsMenu({ showRevert, onRevert, } = {}) {
|
|
291
|
+
export function MessageActionsMenu({ showRevert, onRevert, threadId = "", } = {}) {
|
|
288
292
|
const [open, setOpen] = useState(false);
|
|
289
293
|
const [copied, setCopied] = useState(null);
|
|
290
294
|
const messageRuntime = useMessageRuntime();
|
|
@@ -311,24 +315,23 @@ export function MessageActionsMenu({ showRevert, onRevert, } = {}) {
|
|
|
311
315
|
}, [messageRuntime]);
|
|
312
316
|
const handleCopyRequestId = useCallback(() => {
|
|
313
317
|
const m = messageRuntime.getState();
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
(typeof window !== "undefined" ? getActiveRun()?.runId : null) ||
|
|
320
|
-
m.id ||
|
|
321
|
-
"";
|
|
318
|
+
const runId = resolveAssistantRequestId(m, getActiveRun(), threadId);
|
|
319
|
+
if (!runId) {
|
|
320
|
+
setCopied("id-unavailable");
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
322
323
|
void writeClipboardText(runId).then((ok) => {
|
|
323
|
-
if (!ok)
|
|
324
|
+
if (!ok) {
|
|
325
|
+
setCopied("id-failed");
|
|
324
326
|
return;
|
|
327
|
+
}
|
|
325
328
|
setCopied("id");
|
|
326
329
|
setTimeout(() => {
|
|
327
330
|
setCopied(null);
|
|
328
331
|
setOpen(false);
|
|
329
332
|
}, 1000);
|
|
330
333
|
});
|
|
331
|
-
}, [messageRuntime]);
|
|
334
|
+
}, [messageRuntime, threadId]);
|
|
332
335
|
const handleForkChat = useCallback(() => {
|
|
333
336
|
setOpen(false);
|
|
334
337
|
actionsCtx?.onForkChat?.();
|
|
@@ -343,7 +346,13 @@ export function MessageActionsMenu({ showRevert, onRevert, } = {}) {
|
|
|
343
346
|
}, children: [copied === "message" ? (_jsx(IconCheck, { className: "h-3.5 w-3.5" })) : (_jsx(IconCopy, { className: "h-3.5 w-3.5" })), copied === "message" ? "Copied!" : "Copy Message"] }), _jsxs(DropdownMenuItem, { onSelect: (e) => {
|
|
344
347
|
e.preventDefault();
|
|
345
348
|
handleCopyRequestId();
|
|
346
|
-
}, children: [copied === "id" ? (_jsx(IconCheck, { className: "h-3.5 w-3.5" })) : (_jsx(IconId, { className: "h-3.5 w-3.5" })), copied === "id"
|
|
349
|
+
}, children: [copied === "id" ? (_jsx(IconCheck, { className: "h-3.5 w-3.5" })) : (_jsx(IconId, { className: "h-3.5 w-3.5" })), copied === "id"
|
|
350
|
+
? "Copied!"
|
|
351
|
+
: copied === "id-unavailable"
|
|
352
|
+
? "Request ID unavailable"
|
|
353
|
+
: copied === "id-failed"
|
|
354
|
+
? "Copy failed"
|
|
355
|
+
: "Copy Request ID"] }), showRevert && (_jsxs(DropdownMenuItem, { onSelect: handleRevert, children: [_jsx(IconArrowBackUp, { className: "h-3.5 w-3.5" }), "Revert to here"] })), timestamp && (_jsxs(_Fragment, { children: [_jsx(DropdownMenuSeparator, {}), _jsxs(DropdownMenuLabel, { className: "px-2 py-1 text-[11px] font-normal text-muted-foreground", children: ["Sent ", timestamp.short] })] }))] })] }));
|
|
347
356
|
}
|
|
348
357
|
// ─── UserMessage ──────────────────────────────────────────────────────────────
|
|
349
358
|
export function UserMessage() {
|
|
@@ -481,29 +490,6 @@ function missingFinalResponseWarningText(content) {
|
|
|
481
490
|
}
|
|
482
491
|
return null;
|
|
483
492
|
}
|
|
484
|
-
export function completedAssistantToolNamesAfterLastText(content) {
|
|
485
|
-
let lastTextIndex = -1;
|
|
486
|
-
for (let index = content.length - 1; index >= 0; index -= 1) {
|
|
487
|
-
if (content[index]?.type === "text") {
|
|
488
|
-
lastTextIndex = index;
|
|
489
|
-
break;
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
const names = new Set();
|
|
493
|
-
for (let index = lastTextIndex + 1; index < content.length; index += 1) {
|
|
494
|
-
const part = content[index];
|
|
495
|
-
if (part?.type !== "tool-call" ||
|
|
496
|
-
part.activity === true ||
|
|
497
|
-
part.result === undefined ||
|
|
498
|
-
part.isError === true ||
|
|
499
|
-
part.outcome === "unknown" ||
|
|
500
|
-
isCallAgentToolCallShadowed(content, index)) {
|
|
501
|
-
continue;
|
|
502
|
-
}
|
|
503
|
-
names.add(humanizeToolName(part.toolName));
|
|
504
|
-
}
|
|
505
|
-
return [...names];
|
|
506
|
-
}
|
|
507
493
|
export function latestUserMessageText(messages) {
|
|
508
494
|
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
509
495
|
const message = messages[index];
|
|
@@ -781,11 +767,6 @@ export function InlineRunErrorNotice({ info, durationMs, onRetry, }) {
|
|
|
781
767
|
: headline;
|
|
782
768
|
return (_jsxs("div", { className: "my-1 w-full", children: [_jsxs("button", { type: "button", onClick: () => setOpen((v) => !v), "aria-expanded": open, className: "flex cursor-pointer items-center gap-1.5 py-0.5 text-[13px] text-muted-foreground transition-colors hover:text-foreground", children: [_jsx(IconAlertTriangle, { className: "size-3.5 shrink-0 text-amber-500" }), _jsx("span", { className: "truncate", children: label }), _jsx(IconChevronRight, { className: cn("size-3.5 shrink-0 transition-transform", open && "rotate-90") })] }), open && (_jsxs("div", { className: "mt-1 rounded-md border border-border/60 bg-background/70 p-2 text-[11px] leading-relaxed text-muted-foreground", children: [_jsx("p", { className: "whitespace-pre-wrap break-words", children: info.message }), info.errorCode && (_jsxs("div", { className: "mt-1 font-mono", children: ["code: ", info.errorCode] })), info.runId && _jsxs("div", { className: "font-mono", children: ["run: ", info.runId] }), info.details && (_jsx("pre", { className: "mt-1 max-h-28 overflow-auto whitespace-pre-wrap break-words font-mono", children: info.details })), onRetry && (_jsxs("button", { type: "button", onClick: onRetry, className: "mt-2 inline-flex h-7 cursor-pointer items-center gap-1.5 rounded-md border border-border bg-background px-2.5 text-[11px] font-medium text-foreground hover:bg-accent", children: [_jsx(IconRefresh, { className: "size-3" }), "Retry"] }))] }))] }));
|
|
783
769
|
}
|
|
784
|
-
function AssistantCompletionProgress({ messageId, toolNames, }) {
|
|
785
|
-
if (toolNames.length === 0)
|
|
786
|
-
return null;
|
|
787
|
-
return (_jsx("div", { className: "my-1 w-full text-[13px] text-muted-foreground", role: "status", "aria-live": "polite", "data-testid": "assistant-completion-progress", children: _jsx(SmoothMarkdownText, { text: `The agent completed these actions: ${toolNames.join(", ")}`, streaming: true, resetKey: `assistant-completion-progress:${messageId}`, statusType: "running" }) }));
|
|
788
|
-
}
|
|
789
770
|
function MissingFinalResponseNotice({ messageId, text, animate, onRevealComplete, }) {
|
|
790
771
|
return (_jsx("div", { className: "my-1 w-full text-muted-foreground", role: "status", "aria-live": "polite", "data-testid": "missing-final-response", children: _jsx(SmoothMarkdownText, { text: text, streaming: animate, resetKey: `missing-final-response:${messageId}`, statusType: animate ? "running" : "complete", onRevealComplete: animate ? onRevealComplete : undefined }) }));
|
|
791
772
|
}
|
|
@@ -849,9 +830,6 @@ export function AssistantMessage() {
|
|
|
849
830
|
return;
|
|
850
831
|
setRevealedMissingFinalResponseKey(missingFinalResponseAnimationKey);
|
|
851
832
|
}, [missingFinalResponseAnimationKey]);
|
|
852
|
-
const completedToolNames = isLast && chatRunning && !hasCompletedCustomUi && Array.isArray(msg.content)
|
|
853
|
-
? completedAssistantToolNamesAfterLastText(msg.content)
|
|
854
|
-
: [];
|
|
855
833
|
const shouldHoldCompletionFooter = isLast &&
|
|
856
834
|
((missingFinalResponseCandidate && !showMissingFinalResponse) ||
|
|
857
835
|
(animateMissingFinalResponse && !missingFinalResponseRevealed));
|
|
@@ -1004,15 +982,15 @@ export function AssistantMessage() {
|
|
|
1004
982
|
case "tool-call":
|
|
1005
983
|
if (shadowedToolCallIds.has(part.toolCallId))
|
|
1006
984
|
return null;
|
|
1007
|
-
return part.toolUI ? (_jsx(ToolActivityPresentation, { toolName: part.toolName, isRunning: part.status?.type === "running",
|
|
985
|
+
return part.toolUI ? (_jsx(ToolActivityPresentation, { toolName: part.toolName, isRunning: part.status?.type === "running", toolCallId: part.toolCallId, children: part.toolUI })) : (_jsx(ToolCallFallback, { ...part, isActiveTail: part.toolCallId === activeTailToolCallId }));
|
|
1008
986
|
default:
|
|
1009
987
|
return null;
|
|
1010
988
|
}
|
|
1011
|
-
} }) }),
|
|
989
|
+
} }) }), showInlineRunError && messageRunError && (_jsx(InlineRunErrorNotice, { info: messageRunError, durationMs: capturedDurationMs ?? persistedDurationMs, onRetry: isLast && messageRunError.recoverable
|
|
1012
990
|
? messageActions?.onRetryRunError
|
|
1013
991
|
: undefined })), missingWarningText == null &&
|
|
1014
992
|
missingFinalResponseNoticeText != null &&
|
|
1015
|
-
!showInlineRunError && (_jsx(MissingFinalResponseNotice, { messageId: msg.id, text: missingFinalResponseNoticeText, animate: animateMissingFinalResponse, onRevealComplete: handleMissingFinalResponseReveal })), isComplete && hasCodeAgentTools && msgContent && (_jsx(FilesChangedSummary, { parts: msgContent })), isComplete && (_jsx(McpConnectionSuggestion, { text: responseConnectionText, contextText: responseConnectionContext, variant: "response" }))] }), isComplete && (_jsxs("div", { className: "mt-1 flex items-center justify-between", children: [_jsxs("div", { className: "flex min-w-0 items-center gap-1", children: [_jsx(MessageActionsMenu, { showRevert: showRestore && restoreState === "idle", onRevert: handleRestore }), isLast && (_jsx(TooltipProvider, { delayDuration: 400, children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(ActionBarPrimitive.Reload, { asChild: true, children: _jsx("button", { type: "button", "aria-label": "Regenerate response", className: `flex h-6 w-6 cursor-pointer items-center justify-center rounded-md text-muted-foreground/70 hover:bg-accent hover:text-foreground ${messageFooterFadeClassName} disabled:cursor-not-allowed disabled:opacity-40`, children: _jsx(IconRefresh, { className: "h-3.5 w-3.5" }) }) }) }), _jsx(TooltipContent, { side: "top", className: "text-xs", children: "Regenerate response" })] }) })), _jsx(MessageBranchPicker, {}), timestamp && (_jsx(MessageTimestamp, { timestamp: timestamp, className: messageFooterFadeClassName }))] }), showRestore && restoreState === "confirming" ? (_jsxs("div", { className: "flex items-center gap-1 text-xs", children: [_jsx("button", { onClick: handleRestore, className: "rounded-md bg-destructive px-1.5 py-0.5 text-destructive-foreground hover:bg-destructive/90", children: "Restore to here?" }), _jsx("button", { onClick: cancelRestore, className: "rounded-md px-1.5 py-0.5 text-muted-foreground hover:bg-accent", children: "Cancel" })] })) : showRestore && restoreState === "restoring" ? (_jsxs("span", { className: "flex items-center gap-1 text-xs text-muted-foreground", children: [_jsx(IconLoader2, { className: "h-3 w-3 animate-spin" }), "Restoring..."] })) : restoreState === "error" ? (_jsxs("span", { className: "flex items-center gap-1 text-xs text-destructive", children: [_jsx(IconAlertTriangle, { className: "h-3 w-3 shrink-0" }), _jsx("span", { className: "truncate", children: restoreError }), _jsx("button", { onClick: cancelRestore, className: "cursor-pointer rounded-md px-1.5 py-0.5 text-muted-foreground hover:bg-accent", children: "Dismiss" })] })) : (_jsx(ThumbsFeedback, { threadId: cpCtx?.threadId ?? "", runId: messageRunId ?? "", messageSeq: thread.messages.findIndex((m) => m.id === msg.id) }))] }))] }));
|
|
993
|
+
!showInlineRunError && (_jsx(MissingFinalResponseNotice, { messageId: msg.id, text: missingFinalResponseNoticeText, animate: animateMissingFinalResponse, onRevealComplete: handleMissingFinalResponseReveal })), isComplete && hasCodeAgentTools && msgContent && (_jsx(FilesChangedSummary, { parts: msgContent })), isComplete && (_jsx(McpConnectionSuggestion, { text: responseConnectionText, contextText: responseConnectionContext, variant: "response" }))] }), isComplete && (_jsxs("div", { className: "mt-1 flex items-center justify-between", children: [_jsxs("div", { className: "flex min-w-0 items-center gap-1", children: [_jsx(MessageActionsMenu, { showRevert: showRestore && restoreState === "idle", onRevert: handleRestore, threadId: cpCtx?.threadId ?? "" }), isLast && (_jsx(TooltipProvider, { delayDuration: 400, children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(ActionBarPrimitive.Reload, { asChild: true, children: _jsx("button", { type: "button", "aria-label": "Regenerate response", className: `flex h-6 w-6 cursor-pointer items-center justify-center rounded-md text-muted-foreground/70 hover:bg-accent hover:text-foreground ${messageFooterFadeClassName} disabled:cursor-not-allowed disabled:opacity-40`, children: _jsx(IconRefresh, { className: "h-3.5 w-3.5" }) }) }) }), _jsx(TooltipContent, { side: "top", className: "text-xs", children: "Regenerate response" })] }) })), _jsx(MessageBranchPicker, {}), timestamp && (_jsx(MessageTimestamp, { timestamp: timestamp, className: messageFooterFadeClassName }))] }), showRestore && restoreState === "confirming" ? (_jsxs("div", { className: "flex items-center gap-1 text-xs", children: [_jsx("button", { onClick: handleRestore, className: "rounded-md bg-destructive px-1.5 py-0.5 text-destructive-foreground hover:bg-destructive/90", children: "Restore to here?" }), _jsx("button", { onClick: cancelRestore, className: "rounded-md px-1.5 py-0.5 text-muted-foreground hover:bg-accent", children: "Cancel" })] })) : showRestore && restoreState === "restoring" ? (_jsxs("span", { className: "flex items-center gap-1 text-xs text-muted-foreground", children: [_jsx(IconLoader2, { className: "h-3 w-3 animate-spin" }), "Restoring..."] })) : restoreState === "error" ? (_jsxs("span", { className: "flex items-center gap-1 text-xs text-destructive", children: [_jsx(IconAlertTriangle, { className: "h-3 w-3 shrink-0" }), _jsx("span", { className: "truncate", children: restoreError }), _jsx("button", { onClick: cancelRestore, className: "cursor-pointer rounded-md px-1.5 py-0.5 text-muted-foreground hover:bg-accent", children: "Dismiss" })] })) : (_jsx(ThumbsFeedback, { threadId: cpCtx?.threadId ?? "", runId: messageRunId ?? "", messageSeq: thread.messages.findIndex((m) => m.id === msg.id) }))] }))] }));
|
|
1016
994
|
}
|
|
1017
995
|
// ─── RunningActivityStatus / ThinkingIndicator ────────────────────────────────
|
|
1018
996
|
export function RunningActivityStatus({ label }) {
|
|
@@ -8,9 +8,8 @@ export declare const ChatRunningContext: React.Context<boolean>;
|
|
|
8
8
|
export declare const ChatRunDurationContext: React.Context<number | null>;
|
|
9
9
|
export declare const ASSISTANT_VISIBLE_TOOL_CALL_LIMIT = 3;
|
|
10
10
|
/**
|
|
11
|
-
* Keeps the
|
|
12
|
-
*
|
|
13
|
-
* untouched; this only animates the DOM's before/after positions.
|
|
11
|
+
* Keeps the tool-call stack layout-transparent. Tool-entry motion is disabled
|
|
12
|
+
* until it can stay stable while streaming calls are added and summarized.
|
|
14
13
|
*/
|
|
15
14
|
export declare function ToolCallStackMotion({ children, className, }: {
|
|
16
15
|
children: React.ReactNode;
|
|
@@ -55,10 +54,9 @@ export declare function toolCallHasPendingApproval(part: {
|
|
|
55
54
|
} | null;
|
|
56
55
|
}): boolean;
|
|
57
56
|
export declare const TOOL_LONG_RUNNING_HINT_DELAY_MS = 45000;
|
|
58
|
-
export declare function ToolActivityPresentation({ toolName, isRunning,
|
|
57
|
+
export declare function ToolActivityPresentation({ toolName, isRunning, toolCallId, suppressLongRunningHint, children, }: {
|
|
59
58
|
toolName: string;
|
|
60
59
|
isRunning: boolean;
|
|
61
|
-
isActiveTail: boolean;
|
|
62
60
|
toolCallId?: string;
|
|
63
61
|
suppressLongRunningHint?: boolean;
|
|
64
62
|
children: React.ReactNode;
|
|
@@ -20,207 +20,12 @@ import { isBuiltinDataWidgetActionRenderer, resolveBuiltinActionChatRenderer, re
|
|
|
20
20
|
export const ChatRunningContext = React.createContext(false);
|
|
21
21
|
export const ChatRunDurationContext = React.createContext(null);
|
|
22
22
|
export const ASSISTANT_VISIBLE_TOOL_CALL_LIMIT = 3;
|
|
23
|
-
const TOOL_CALL_ENTRY_DURATION_MS = 220;
|
|
24
|
-
const TOOL_CALL_STACK_MOTION_DURATION_MS = 220;
|
|
25
|
-
const TOOL_CALL_STACK_EASING = "cubic-bezier(0.23, 1, 0.32, 1)";
|
|
26
|
-
function toolStackMotionKey(element, index) {
|
|
27
|
-
const toolCallId = element.dataset.agentToolCallId;
|
|
28
|
-
if (toolCallId)
|
|
29
|
-
return `tool:${toolCallId}`;
|
|
30
|
-
const summaryId = element.dataset.agentToolSummary;
|
|
31
|
-
if (summaryId)
|
|
32
|
-
return `summary:${summaryId}`;
|
|
33
|
-
return `anonymous:${index}`;
|
|
34
|
-
}
|
|
35
|
-
function prefersReducedMotionForToolStack() {
|
|
36
|
-
return (typeof window !== "undefined" &&
|
|
37
|
-
typeof window.matchMedia === "function" &&
|
|
38
|
-
window.matchMedia("(prefers-reduced-motion: reduce)").matches);
|
|
39
|
-
}
|
|
40
|
-
function startToolStackAnimation(element, keyframes) {
|
|
41
|
-
if (typeof element.animate !== "function")
|
|
42
|
-
return null;
|
|
43
|
-
return element.animate(keyframes, {
|
|
44
|
-
duration: TOOL_CALL_STACK_MOTION_DURATION_MS,
|
|
45
|
-
easing: TOOL_CALL_STACK_EASING,
|
|
46
|
-
fill: "both",
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
function prepareToolStackExitClone(clone, snapshot) {
|
|
50
|
-
clone.classList.remove("agent-tool-call--entering", "agent-tool-call--stack-entering");
|
|
51
|
-
clone
|
|
52
|
-
.querySelectorAll(".agent-tool-call--entering, .agent-tool-call--stack-entering")
|
|
53
|
-
.forEach((element) => {
|
|
54
|
-
element.classList.remove("agent-tool-call--entering", "agent-tool-call--stack-entering");
|
|
55
|
-
});
|
|
56
|
-
clone.classList.add("agent-tool-call-stack__exit");
|
|
57
|
-
clone.setAttribute("aria-hidden", "true");
|
|
58
|
-
clone.removeAttribute("data-agent-tool-call-id");
|
|
59
|
-
clone.removeAttribute("data-agent-tool-summary");
|
|
60
|
-
clone.removeAttribute("data-agent-tool-motion-token");
|
|
61
|
-
clone.style.left = `${snapshot.left}px`;
|
|
62
|
-
clone.style.top = `${snapshot.top}px`;
|
|
63
|
-
clone.style.width = `${snapshot.width}px`;
|
|
64
|
-
clone.style.height = `${snapshot.height}px`;
|
|
65
|
-
clone.style.transform = "translate3d(0, 0, 0)";
|
|
66
|
-
clone.style.transition = "none";
|
|
67
|
-
clone.style.animation = "none";
|
|
68
|
-
clone.style.opacity = "1";
|
|
69
|
-
}
|
|
70
23
|
/**
|
|
71
|
-
* Keeps the
|
|
72
|
-
*
|
|
73
|
-
* untouched; this only animates the DOM's before/after positions.
|
|
24
|
+
* Keeps the tool-call stack layout-transparent. Tool-entry motion is disabled
|
|
25
|
+
* until it can stay stable while streaming calls are added and summarized.
|
|
74
26
|
*/
|
|
75
27
|
export function ToolCallStackMotion({ children, className, }) {
|
|
76
|
-
|
|
77
|
-
const previousRef = useRef(new Map());
|
|
78
|
-
const previousStructureRef = useRef([]);
|
|
79
|
-
const activeMotionsRef = useRef(new Map());
|
|
80
|
-
const exitAnimationsRef = useRef(new Map());
|
|
81
|
-
useLayoutEffect(() => {
|
|
82
|
-
const stack = stackRef.current;
|
|
83
|
-
if (!stack)
|
|
84
|
-
return;
|
|
85
|
-
const previous = previousRef.current;
|
|
86
|
-
const visualPrevious = new Map(previous);
|
|
87
|
-
for (const [key, activeMotion] of activeMotionsRef.current) {
|
|
88
|
-
if (stack.contains(activeMotion.element)) {
|
|
89
|
-
const previousSnapshot = previous.get(key);
|
|
90
|
-
if (previousSnapshot) {
|
|
91
|
-
const rect = activeMotion.element.getBoundingClientRect();
|
|
92
|
-
visualPrevious.set(key, {
|
|
93
|
-
...previousSnapshot,
|
|
94
|
-
top: rect.top,
|
|
95
|
-
left: rect.left,
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
activeMotion.animation.cancel();
|
|
100
|
-
}
|
|
101
|
-
activeMotionsRef.current.clear();
|
|
102
|
-
for (const [ghost, animation] of exitAnimationsRef.current) {
|
|
103
|
-
animation.cancel();
|
|
104
|
-
ghost.remove();
|
|
105
|
-
}
|
|
106
|
-
exitAnimationsRef.current.clear();
|
|
107
|
-
const elements = Array.from(stack.querySelectorAll("[data-agent-tool-call-id], [data-agent-tool-summary]"));
|
|
108
|
-
const structure = elements.map((element, index) => toolStackMotionKey(element, index));
|
|
109
|
-
const previousStructure = previousStructureRef.current;
|
|
110
|
-
const structureChanged = structure.length !== previousStructure.length ||
|
|
111
|
-
structure.some((key, index) => key !== previousStructure[index]);
|
|
112
|
-
previousStructureRef.current = structure;
|
|
113
|
-
const current = new Map();
|
|
114
|
-
for (const [index, element] of elements.entries()) {
|
|
115
|
-
const rect = element.getBoundingClientRect();
|
|
116
|
-
current.set(toolStackMotionKey(element, index), {
|
|
117
|
-
top: rect.top,
|
|
118
|
-
left: rect.left,
|
|
119
|
-
width: rect.width,
|
|
120
|
-
height: rect.height,
|
|
121
|
-
clone: element.cloneNode(true),
|
|
122
|
-
});
|
|
123
|
-
}
|
|
124
|
-
previousRef.current = current;
|
|
125
|
-
// Entry motion changes the measured transform without changing the stack
|
|
126
|
-
// structure. Do not turn that animation's cleanup into a second FLIP pass.
|
|
127
|
-
if (previous.size === 0 ||
|
|
128
|
-
!structureChanged ||
|
|
129
|
-
prefersReducedMotionForToolStack())
|
|
130
|
-
return;
|
|
131
|
-
const summary = elements.find((element) => element.dataset.agentToolSummary !== undefined);
|
|
132
|
-
const summaryRect = summary?.getBoundingClientRect();
|
|
133
|
-
const elementsByKey = new Map(elements.map((element, index) => [
|
|
134
|
-
toolStackMotionKey(element, index),
|
|
135
|
-
element,
|
|
136
|
-
]));
|
|
137
|
-
for (const [key, after] of current.entries()) {
|
|
138
|
-
const before = visualPrevious.get(key);
|
|
139
|
-
if (!before) {
|
|
140
|
-
const node = elementsByKey.get(key);
|
|
141
|
-
if (!node)
|
|
142
|
-
continue;
|
|
143
|
-
if (node.dataset.agentToolSummary !== undefined)
|
|
144
|
-
continue;
|
|
145
|
-
if (node.dataset.agentToolCallId !== undefined &&
|
|
146
|
-
!node.classList.contains("agent-tool-call--entering")) {
|
|
147
|
-
node.classList.add("agent-tool-call--stack-entering");
|
|
148
|
-
window.setTimeout(() => {
|
|
149
|
-
node.classList.remove("agent-tool-call--stack-entering");
|
|
150
|
-
}, TOOL_CALL_ENTRY_DURATION_MS);
|
|
151
|
-
}
|
|
152
|
-
continue;
|
|
153
|
-
}
|
|
154
|
-
const dx = before.left - after.left;
|
|
155
|
-
const dy = before.top - after.top;
|
|
156
|
-
if (Math.abs(dx) < 0.5 && Math.abs(dy) < 0.5)
|
|
157
|
-
continue;
|
|
158
|
-
const node = elementsByKey.get(key);
|
|
159
|
-
if (!node)
|
|
160
|
-
continue;
|
|
161
|
-
if (node.dataset.agentToolSummary !== undefined)
|
|
162
|
-
continue;
|
|
163
|
-
const animation = startToolStackAnimation(node, [
|
|
164
|
-
{ transform: `translate3d(${dx}px, ${dy}px, 0)` },
|
|
165
|
-
{ transform: "translate3d(0, 0, 0)" },
|
|
166
|
-
]);
|
|
167
|
-
if (!animation)
|
|
168
|
-
continue;
|
|
169
|
-
activeMotionsRef.current.set(key, { element: node, animation });
|
|
170
|
-
const clearMotion = () => {
|
|
171
|
-
if (activeMotionsRef.current.get(key)?.animation === animation) {
|
|
172
|
-
activeMotionsRef.current.delete(key);
|
|
173
|
-
}
|
|
174
|
-
};
|
|
175
|
-
animation.onfinish = clearMotion;
|
|
176
|
-
animation.oncancel = clearMotion;
|
|
177
|
-
}
|
|
178
|
-
for (const [key, before] of visualPrevious.entries()) {
|
|
179
|
-
if (current.has(key) || !key.startsWith("tool:"))
|
|
180
|
-
continue;
|
|
181
|
-
const ghost = before.clone;
|
|
182
|
-
prepareToolStackExitClone(ghost, before);
|
|
183
|
-
document.body?.appendChild(ghost);
|
|
184
|
-
if (!ghost.isConnected)
|
|
185
|
-
continue;
|
|
186
|
-
const targetTop = summaryRect?.top ?? before.top - 8;
|
|
187
|
-
const targetLeft = summaryRect?.left ?? before.left;
|
|
188
|
-
const animation = startToolStackAnimation(ghost, [
|
|
189
|
-
{ transform: "translate3d(0, 0, 0)", opacity: 1 },
|
|
190
|
-
{
|
|
191
|
-
transform: `translate3d(${targetLeft - before.left}px, ${targetTop - before.top}px, 0)`,
|
|
192
|
-
opacity: 0,
|
|
193
|
-
},
|
|
194
|
-
]);
|
|
195
|
-
if (!animation) {
|
|
196
|
-
ghost.remove();
|
|
197
|
-
continue;
|
|
198
|
-
}
|
|
199
|
-
exitAnimationsRef.current.set(ghost, animation);
|
|
200
|
-
const clearExit = () => {
|
|
201
|
-
if (exitAnimationsRef.current.get(ghost) === animation) {
|
|
202
|
-
exitAnimationsRef.current.delete(ghost);
|
|
203
|
-
}
|
|
204
|
-
ghost.remove();
|
|
205
|
-
};
|
|
206
|
-
animation.onfinish = clearExit;
|
|
207
|
-
animation.oncancel = clearExit;
|
|
208
|
-
}
|
|
209
|
-
});
|
|
210
|
-
useEffect(() => {
|
|
211
|
-
return () => {
|
|
212
|
-
for (const { animation } of activeMotionsRef.current.values()) {
|
|
213
|
-
animation.cancel();
|
|
214
|
-
}
|
|
215
|
-
activeMotionsRef.current.clear();
|
|
216
|
-
for (const [ghost, animation] of exitAnimationsRef.current) {
|
|
217
|
-
animation.cancel();
|
|
218
|
-
ghost.remove();
|
|
219
|
-
}
|
|
220
|
-
exitAnimationsRef.current.clear();
|
|
221
|
-
};
|
|
222
|
-
}, []);
|
|
223
|
-
return (_jsx("div", { ref: stackRef, className: cn("agent-tool-call-stack", className), children: children }));
|
|
28
|
+
return (_jsx("div", { className: cn("agent-tool-call-stack", className), children: children }));
|
|
224
29
|
}
|
|
225
30
|
export const ApprovalContext = React.createContext(null);
|
|
226
31
|
/** Pending human-in-the-loop gate still waiting for Approve/Deny. */
|
|
@@ -231,18 +36,8 @@ export function toolCallHasPendingApproval(part) {
|
|
|
231
36
|
approval.dismissed !== true);
|
|
232
37
|
}
|
|
233
38
|
export const TOOL_LONG_RUNNING_HINT_DELAY_MS = 45_000;
|
|
234
|
-
export function ToolActivityPresentation({ toolName, isRunning,
|
|
39
|
+
export function ToolActivityPresentation({ toolName, isRunning, toolCallId, suppressLongRunningHint = false, children, }) {
|
|
235
40
|
const [showLongRunningHint, setShowLongRunningHint] = useState(false);
|
|
236
|
-
// A batched update can first reveal a tool with its result already attached.
|
|
237
|
-
// Presentation follows the active chat tail rather than execution state so
|
|
238
|
-
// that newly revealed completed tools still get their entrance motion.
|
|
239
|
-
const [animateEntry, setAnimateEntry] = useState(isActiveTail);
|
|
240
|
-
useEffect(() => {
|
|
241
|
-
if (!animateEntry)
|
|
242
|
-
return;
|
|
243
|
-
const timeout = window.setTimeout(() => setAnimateEntry(false), TOOL_CALL_ENTRY_DURATION_MS);
|
|
244
|
-
return () => window.clearTimeout(timeout);
|
|
245
|
-
}, [animateEntry]);
|
|
246
41
|
useEffect(() => {
|
|
247
42
|
if (!isRunning || suppressLongRunningHint) {
|
|
248
43
|
setShowLongRunningHint(false);
|
|
@@ -254,7 +49,7 @@ export function ToolActivityPresentation({ toolName, isRunning, isActiveTail, to
|
|
|
254
49
|
}, TOOL_LONG_RUNNING_HINT_DELAY_MS);
|
|
255
50
|
return () => window.clearTimeout(timeout);
|
|
256
51
|
}, [isRunning, suppressLongRunningHint, toolName]);
|
|
257
|
-
return (_jsx("div", { className:
|
|
52
|
+
return (_jsx("div", { className: "agent-tool-call", "data-agent-tool-call-id": toolCallId, "data-running": isRunning ? "true" : undefined, children: _jsxs("div", { className: "agent-tool-call__content", children: [children, isRunning && showLongRunningHint && (_jsx("div", { className: "mt-0.5 px-2.5 pb-2 text-[11px] leading-snug text-muted-foreground/80", children: "Still working. Large updates can take a minute or two." }))] }) }));
|
|
258
53
|
}
|
|
259
54
|
function stringifyToolValue(value, pretty = false) {
|
|
260
55
|
if (typeof value === "string")
|
|
@@ -480,7 +275,7 @@ export function ToolCallDisplay({ toolName, toolCallId, argsText, args, result,
|
|
|
480
275
|
// These must be separate components so hook order in ToolCallDisplayGeneric
|
|
481
276
|
// is always stable (no conditional hook calls).
|
|
482
277
|
const toolKind = structuredMeta?.toolKind;
|
|
483
|
-
const wrapToolDisplay = (children) => (_jsx(ToolActivityPresentation, { toolName: toolName, isRunning: isRunning,
|
|
278
|
+
const wrapToolDisplay = (children) => (_jsx(ToolActivityPresentation, { toolName: toolName, isRunning: isRunning, toolCallId: toolCallId, suppressLongRunningHint: toolName === "call-agent" || toolName.startsWith("agent:"), children: children }));
|
|
484
279
|
if (toolKind === "bash") {
|
|
485
280
|
return wrapToolDisplay(_jsx(BashCell, { meta: structuredMeta, output: result, isRunning: isRunning }));
|
|
486
281
|
}
|
|
@@ -642,7 +437,7 @@ function AgentCallCell({ agentName, activity, progress, responseText, isRunning,
|
|
|
642
437
|
function AgentActivityToolCallRow({ tool, isActiveTail, }) {
|
|
643
438
|
const isRunning = tool.status === "running";
|
|
644
439
|
const ToolIcon = resolveToolIcon(tool.name);
|
|
645
|
-
return (_jsx(ToolActivityPresentation, { toolName: tool.name, isRunning: isRunning,
|
|
440
|
+
return (_jsx(ToolActivityPresentation, { toolName: tool.name, isRunning: isRunning, toolCallId: tool.id, suppressLongRunningHint: true, children: _jsxs("div", { className: "my-0.5 flex w-full items-center gap-1.5 rounded-md py-0.5 text-left text-[13px] text-muted-foreground", children: [_jsx("span", { className: "flex size-4 shrink-0 items-center justify-center", children: isRunning ? (_jsx(IconLoader2, { className: "size-3.5 animate-spin" })) : (_jsx(ToolIcon, { className: "size-3.5" })) }), _jsx("span", { className: cn("min-w-0 truncate font-normal", isActiveTail && "agent-running-shimmer"), children: humanizeToolName(tool.name) })] }) }));
|
|
646
441
|
}
|
|
647
442
|
// ─── ToolCallFallback ──────────────────────────────────────────────────────────
|
|
648
443
|
export function ToolCallFallback({ toolName, toolCallId, args, argsText, result, ...rest }) {
|
|
@@ -15,12 +15,12 @@ function AppRows({ apps, activeAppId, layout, onDragStart, onDrop, onDragEnd, on
|
|
|
15
15
|
const active = activeAppId === app.id;
|
|
16
16
|
const pinned = layout.pinnedIds.includes(app.id);
|
|
17
17
|
const index = orderedApps.indexOf(app);
|
|
18
|
-
return (_jsxs(ContextMenu, { children: [_jsx(ContextMenuTrigger, { asChild: true, children: _jsxs("li", { draggable: true, "data-chat-first-app": true, "data-app-id": app.id, className: cn("group flex h-8 w-full min-w-0 items-center gap-1 rounded-md px-
|
|
18
|
+
return (_jsxs(ContextMenu, { children: [_jsx(ContextMenuTrigger, { asChild: true, children: _jsxs("li", { draggable: true, "data-chat-first-app": true, "data-app-id": app.id, className: cn("group flex h-8 w-full min-w-0 items-center gap-1 rounded-md px-0 text-sm", active
|
|
19
19
|
? "bg-sidebar-accent font-medium text-sidebar-accent-foreground"
|
|
20
20
|
: "text-sidebar-foreground/75 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground"), onDragStart: (event) => {
|
|
21
21
|
event.dataTransfer.effectAllowed = "move";
|
|
22
22
|
onDragStart(app.id);
|
|
23
|
-
}, onDragOver: (event) => event.preventDefault(), onDrop: () => onDrop(app.id), onDragEnd: onDragEnd, children: [_jsxs("button", { type: "button", className: "flex h-full min-w-0 flex-1 items-center gap-2 px-
|
|
23
|
+
}, onDragOver: (event) => event.preventDefault(), onDrop: () => onDrop(app.id), onDragEnd: onDragEnd, children: [_jsxs("button", { type: "button", className: "flex h-full min-w-0 flex-1 items-center gap-2 px-2 text-start", onClick: () => onOpenApp(app), onKeyDown: (event) => {
|
|
24
24
|
if (!event.altKey)
|
|
25
25
|
return;
|
|
26
26
|
if (event.key === "ArrowUp") {
|
|
@@ -99,5 +99,5 @@ export const ChatFirstAppsRail = memo(function ChatFirstAppsRail({ apps, activeA
|
|
|
99
99
|
? "bg-sidebar-accent text-sidebar-accent-foreground"
|
|
100
100
|
: "text-sidebar-foreground/70 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground"), onClick: () => onOpenApp(app), "aria-label": copy("openApp", { name: app.name }), title: app.name, children: renderIcon(app) }, app.id))), onOpenAllApps ? (_jsx("button", { type: "button", "data-chat-first-all-apps": true, className: "flex size-9 items-center justify-center rounded-md text-sidebar-foreground/70 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground", onClick: onOpenAllApps, "aria-label": copy("allApps"), title: copy("allApps"), children: _jsx(IconApps, { size: 16, "aria-hidden": "true" }) })) : null, error ? (_jsx("span", { className: "size-1.5 rounded-full bg-destructive", title: error, "aria-label": error })) : null] }));
|
|
101
101
|
}
|
|
102
|
-
return (_jsxs("section", { "data-chat-first-apps-rail": true, className: "mt-3 px-
|
|
102
|
+
return (_jsxs("section", { "data-chat-first-apps-rail": true, className: "mt-3 px-0 pb-2 pt-2", "aria-label": copy("workspaceApps"), children: [_jsxs("div", { className: "mb-1 flex items-center gap-1.5 px-2 text-[11px] font-medium text-sidebar-foreground/50", children: [_jsx("span", { children: copy("workspaceApps") }), _jsx("span", { className: "ml-auto", children: createTrigger })] }), loading && apps.length === 0 ? (_jsx("div", { className: "space-y-0.5 px-2", children: [0, 1, 2].map((index) => (_jsx(Skeleton, { className: "h-8 w-full rounded-md" }, index))) })) : apps.length === 0 ? (_jsxs("div", { className: "px-2", children: [_jsx("p", { className: "text-xs text-sidebar-foreground/55", children: copy("noWorkspaceApps") }), createAppTrigger ? (createTrigger) : onCreateApp ? (_jsxs("button", { type: "button", className: "mt-1 inline-flex h-6 items-center gap-1.5 rounded-md border border-sidebar-border px-2 text-xs text-sidebar-foreground/75 hover:bg-sidebar-accent hover:text-sidebar-foreground", onClick: onCreateApp, children: [_jsx(IconPlus, { size: 13, "aria-hidden": "true" }), copy("createApp")] })) : (createTrigger)] })) : (_jsx(AppRows, { apps: visibleApps, activeAppId: activeAppId, layout: layout, onDragStart: setDraggedAppId, onDrop: reorderApps, onDragEnd: () => setDraggedAppId(null), onOpenApp: onOpenApp, onTogglePinned: togglePinned, onMove: moveApp, renderIcon: renderIcon, copy: copy })), hasMoreApps || showAllApps ? (_jsxs("button", { type: "button", className: "mt-0.5 flex h-8 w-full items-center gap-2 rounded-md px-2 text-xs text-sidebar-foreground/50 hover:bg-sidebar-accent hover:text-sidebar-foreground", onClick: () => setShowAllApps((value) => !value), children: [showAllApps ? (_jsx(IconChevronUp, { size: 14, "aria-hidden": "true" })) : (_jsx(IconChevronDown, { size: 14, "aria-hidden": "true" })), showAllApps ? copy("showLess") : copy("showMore")] })) : null, onOpenAllApps ? (_jsx("div", { className: "mt-1 border-t border-sidebar-border/60 pt-1", children: _jsxs("button", { type: "button", "data-chat-first-all-apps": true, className: "flex h-8 w-full items-center gap-2 rounded-md px-2 text-xs text-sidebar-foreground/55 hover:bg-sidebar-accent hover:text-sidebar-foreground", onClick: onOpenAllApps, children: [_jsx(IconApps, { size: 14, "aria-hidden": "true" }), _jsx("span", { children: copy("allApps") })] }) })) : null, error ? (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("button", { type: "button", className: "mt-1 flex items-center gap-1 px-2 text-[10px] text-destructive/80", onClick: onRetry, "aria-label": error, children: [_jsx("span", { className: "size-1.5 rounded-full bg-destructive" }), onRetry ? copy("retry") : copy("appsLoadError")] }) }), _jsx(TooltipContent, { side: "right", children: error })] })) : null] }));
|
|
103
103
|
});
|
|
@@ -17,6 +17,9 @@ export function ChatFirstBrowserPane({ url, title, status, statusMessage, onClos
|
|
|
17
17
|
setHistoryIndex(0);
|
|
18
18
|
setNavigationError(null);
|
|
19
19
|
}, [url]);
|
|
20
|
+
const currentTarget = resolveChatFirstBrowserTarget({ url: currentUrl });
|
|
21
|
+
const isExternalOnly = currentTarget.status === "ready" &&
|
|
22
|
+
currentTarget.target.openExternally === true;
|
|
20
23
|
function navigate(event) {
|
|
21
24
|
event.preventDefault();
|
|
22
25
|
const target = resolveChatFirstBrowserTarget({ url: draftUrl });
|
|
@@ -56,7 +59,7 @@ export function ChatFirstBrowserPane({ url, title, status, statusMessage, onClos
|
|
|
56
59
|
}
|
|
57
60
|
return (_jsxs("section", { "data-chat-first-browser-pane": true, className: "flex h-full min-h-0 w-full flex-col overflow-hidden bg-background", "aria-label": copy("surface.browser.label"), children: [_jsxs("header", { className: "flex h-12 shrink-0 items-center gap-1.5 border-b border-border bg-card px-2", children: [_jsxs("div", { className: "flex shrink-0 items-center gap-0.5", children: [_jsx("button", { type: "button", disabled: historyIndex <= 0, onClick: goBack, "aria-label": copy("browserBack"), title: copy("browserBack"), className: "flex size-7 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground disabled:opacity-35", children: _jsx(IconArrowLeft, { size: 15 }) }), _jsx("button", { type: "button", disabled: historyIndex >= history.length - 1, onClick: goForward, "aria-label": copy("browserForward"), title: copy("browserForward"), className: "flex size-7 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground disabled:opacity-35", children: _jsx(IconArrowRight, { size: 15 }) }), _jsx("button", { type: "button", onClick: () => setReloadKey((key) => key + 1), "aria-label": copy("browserReload"), title: copy("browserReload"), className: "flex size-7 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground", children: _jsx(IconRefresh, { size: 15 }) })] }), _jsxs("form", { className: "flex min-w-0 flex-1 items-center gap-1.5 rounded-md border border-input bg-background px-2", onSubmit: navigate, children: [_jsx(IconWorld, { size: 13, className: "shrink-0 text-muted-foreground", "aria-hidden": "true" }), _jsx("input", { value: draftUrl, onChange: (event) => setDraftUrl(event.target.value), "aria-label": copy("browserAddress"), spellCheck: false, className: "h-7 min-w-0 flex-1 bg-transparent text-xs text-foreground outline-none placeholder:text-muted-foreground" })] }), _jsxs("div", { className: "flex shrink-0 items-center gap-0.5", children: [title ? (_jsx("span", { className: "hidden max-w-28 truncate px-1 text-xs text-muted-foreground xl:block", title: title, children: title })) : null, _jsx("button", { type: "button", onClick: () => window.open(currentUrl, "_blank", "noopener,noreferrer"), "aria-label": copy("browserOpenExternal"), title: copy("browserOpenExternal"), className: "flex size-7 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground", children: _jsx(IconExternalLink, { size: 15 }) }), _jsx("button", { type: "button", onClick: onClose, "aria-label": copy("browserClose"), title: copy("browserClose"), className: "flex size-7 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground", children: _jsx(IconX, { size: 15 }) })] })] }), navigationError ? (_jsx("p", { className: "border-b border-destructive/30 bg-destructive/10 px-3 py-1.5 text-xs text-destructive", role: "alert", children: navigationError })) : null, _jsx("div", { className: "relative min-h-0 flex-1 overflow-hidden", children: status === "starting" || status === "error" ? (_jsx("div", { className: "flex h-full items-center justify-center px-6 text-center", role: status === "error" ? "alert" : "status", "aria-live": "polite", children: _jsxs("div", { className: "max-w-xs space-y-1", children: [_jsx("p", { className: "text-sm font-medium text-foreground", children: status === "starting"
|
|
58
61
|
? copy("browserPreviewStarting")
|
|
59
|
-
: copy("browserPreviewError") }), statusMessage ? (_jsx("p", { className: "text-xs text-muted-foreground", children: statusMessage })) : null] }) })) : (renderEmbed({
|
|
62
|
+
: copy("browserPreviewError") }), statusMessage ? (_jsx("p", { className: "text-xs text-muted-foreground", children: statusMessage })) : null] }) })) : isExternalOnly ? (_jsx("div", { className: "flex h-full items-center justify-center p-6 text-center", children: _jsxs("div", { className: "max-w-sm space-y-3", children: [_jsx("p", { className: "text-sm text-muted-foreground", children: copy("browserPreviewError") }), _jsxs("a", { href: currentUrl, target: "_blank", rel: "noopener noreferrer", className: "inline-flex items-center gap-1.5 rounded-md border border-border px-3 py-1.5 text-xs font-medium text-foreground hover:bg-accent", children: [_jsx(IconExternalLink, { size: 14, "aria-hidden": "true" }), copy("browserOpenExternal")] })] }) })) : (renderEmbed({
|
|
60
63
|
url: currentUrl,
|
|
61
64
|
title: title || copy("browserPage"),
|
|
62
65
|
key: `${currentUrl}:${reloadKey}`,
|
|
@@ -3,10 +3,12 @@ import { type ChatHistoryItem, type ChatHistoryListProps } from "../chat/ChatHis
|
|
|
3
3
|
export interface ChatFirstChatHistoryProps extends Omit<ChatHistoryListProps, "items" | "sections" | "variant"> {
|
|
4
4
|
items: ChatHistoryItem[];
|
|
5
5
|
label?: ReactNode;
|
|
6
|
+
/** Optional contextual actions for the Chats section header. */
|
|
7
|
+
headerAction?: ReactNode;
|
|
6
8
|
}
|
|
7
9
|
/**
|
|
8
10
|
* The single chat-list presentation used by the chat-first rail on every
|
|
9
11
|
* host. Hosts still own thread fetching and actions, but row rhythm and the
|
|
10
12
|
* Chats section treatment stay identical.
|
|
11
13
|
*/
|
|
12
|
-
export declare function ChatFirstChatHistory({ items, label, className, ...props }: ChatFirstChatHistoryProps): import("react").JSX.Element | null;
|
|
14
|
+
export declare function ChatFirstChatHistory({ items, label, headerAction, className, ...props }: ChatFirstChatHistoryProps): import("react").JSX.Element | null;
|
|
@@ -5,8 +5,8 @@ import { ChatHistoryList, } from "../chat/ChatHistoryList.js";
|
|
|
5
5
|
* host. Hosts still own thread fetching and actions, but row rhythm and the
|
|
6
6
|
* Chats section treatment stay identical.
|
|
7
7
|
*/
|
|
8
|
-
export function ChatFirstChatHistory({ items, label = "Chats", className, ...props }) {
|
|
8
|
+
export function ChatFirstChatHistory({ items, label = "Chats", headerAction, className, ...props }) {
|
|
9
9
|
if (items.length === 0)
|
|
10
10
|
return null;
|
|
11
|
-
return (_jsxs("section", { "data-chat-first-chat-history": true, className: ["min-h-0 min-w-0", className].filter(Boolean).join(" "), children: [
|
|
11
|
+
return (_jsxs("section", { "data-chat-first-chat-history": true, className: ["min-h-0 min-w-0", className].filter(Boolean).join(" "), children: [_jsxs("div", { "data-chat-first-chat-history-header": true, className: "group mb-1 flex min-h-6 items-center justify-between gap-2 px-2", children: [_jsx("p", { className: "min-w-0 text-[11px] font-medium text-sidebar-foreground/50", children: label }), headerAction ? (_jsx("div", { className: "shrink-0 opacity-0 transition-opacity duration-100 group-hover:opacity-100 group-focus-within:opacity-100", children: headerAction })) : null] }), _jsx(ChatHistoryList, { ...props, items: items, variant: "rail", className: "min-w-0" })] }));
|
|
12
12
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
2
|
import { type ChatFirstSurfaceTab } from "../chat-first.js";
|
|
3
3
|
import type { ChatFirstSurfaceTabsProps } from "./types.js";
|
|
4
|
-
export declare function ChatFirstSurfaceTabs({ tabs, activeTabId, onActivate, onClose, onCloseOthers, onCloseToRight, onCloseAll, onOpenSurface, copy, }: ChatFirstSurfaceTabsProps): import("react").JSX.Element;
|
|
4
|
+
export declare function ChatFirstSurfaceTabs({ tabs, activeTabId, onActivate, onClose, onCloseOthers, onCloseToRight, onCloseAll, onOpenSurface, apps, onOpenApp, renderAppIcon, copy, }: ChatFirstSurfaceTabsProps): import("react").JSX.Element;
|
|
5
5
|
export declare function ChatFirstSurfaceContent({ tabs, activeTabId, renderTab, }: {
|
|
6
6
|
tabs: readonly ChatFirstSurfaceTab[];
|
|
7
7
|
activeTabId: string | null;
|