@agent-native/core 0.155.0 → 0.157.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/corpus/templates/assets/app/components/asset/AssetPreviewDialog.tsx +3 -1
- package/corpus/templates/assets/app/i18n-data.ts +21 -1
- package/corpus/templates/assets/app/routes/brand-kits.$id.tsx +17 -13
- package/corpus/templates/clips/app/components/player/share-dialog.tsx +102 -59
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +15 -1
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +16 -2
- package/corpus/templates/slides/app/components/editor/AddSlidePopover.tsx +98 -29
- package/corpus/templates/slides/app/components/editor/EditorActionCluster.tsx +45 -91
- package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +94 -2
- package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +17 -29
- package/corpus/templates/slides/app/components/editor/SlideContextToolbar.tsx +1 -1
- package/corpus/templates/slides/app/context/DeckContext.tsx +42 -2
- package/corpus/templates/slides/app/global.css +7 -40
- package/corpus/templates/slides/app/i18n/en-US.ts +4 -0
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +130 -45
- package/dist/agent/index.d.ts +1 -1
- package/dist/agent/production-agent.d.ts +30 -0
- package/dist/agent/production-agent.js +100 -8
- package/dist/agent/types.d.ts +9 -0
- package/dist/client/AgentPanel.js +12 -9
- package/dist/client/AssistantChat.d.ts +15 -1
- package/dist/client/AssistantChat.js +110 -43
- package/dist/client/MultiTabAssistantChat.js +44 -27
- package/dist/client/chat/markdown-renderer.js +4 -2
- package/dist/client/chat/message-components.d.ts +2 -2
- package/dist/client/chat/message-components.js +69 -35
- package/dist/client/chat/run-recovery.d.ts +4 -1
- package/dist/client/chat/run-recovery.js +62 -30
- package/dist/client/chat/tool-call-display.d.ts +12 -3
- package/dist/client/chat/tool-call-display.js +79 -40
- package/dist/client/chat/widgets/DataChartRenderer.js +3 -1
- package/dist/client/chat/widgets/DataChartWidget.js +8 -2
- package/dist/client/chat/widgets/DataInsightsWidget.js +3 -1
- package/dist/client/chat/widgets/DataTableWidget.js +23 -9
- package/dist/client/chat/widgets/builtin-tool-renderers.js +3 -1
- package/dist/client/components/ui/message-scroller.d.ts +1 -1
- package/dist/client/components/ui/message-scroller.js +7 -3
- package/dist/client/composer/runtime-adapters.js +3 -2
- package/dist/client/context-xray/ContextMeter.js +5 -1
- package/dist/client/context-xray/ContextXRayPanel.js +5 -5
- package/dist/client/error-format.d.ts +4 -0
- package/dist/client/error-format.js +93 -5
- package/dist/client/i18n.js +83 -17
- package/dist/client/observability/ThumbsFeedback.js +10 -8
- package/dist/client/sharing/ShareButton.js +160 -54
- package/dist/coding-tools/run-code.js +2 -1
- package/dist/coding-tools/sandbox/background.d.ts +1 -0
- package/dist/coding-tools/sandbox/background.js +8 -1
- package/dist/coding-tools/sandbox/executions-store.d.ts +2 -0
- package/dist/coding-tools/sandbox/executions-store.js +41 -3
- package/dist/collab/routes.d.ts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/localization/core-messages/ar-SA.d.ts +3 -0
- package/dist/localization/core-messages/ar-SA.js +541 -0
- package/dist/localization/core-messages/de-DE.d.ts +3 -0
- package/dist/localization/core-messages/de-DE.js +513 -0
- package/dist/localization/core-messages/en-US.d.ts +513 -0
- package/dist/localization/core-messages/en-US.js +513 -0
- package/dist/localization/core-messages/es-ES.d.ts +3 -0
- package/dist/localization/core-messages/es-ES.js +520 -0
- package/dist/localization/core-messages/fr-FR.d.ts +3 -0
- package/dist/localization/core-messages/fr-FR.js +520 -0
- package/dist/localization/core-messages/hi-IN.d.ts +3 -0
- package/dist/localization/core-messages/hi-IN.js +513 -0
- package/dist/localization/core-messages/ja-JP.d.ts +3 -0
- package/dist/localization/core-messages/ja-JP.js +506 -0
- package/dist/localization/core-messages/ko-KR.d.ts +3 -0
- package/dist/localization/core-messages/ko-KR.js +506 -0
- package/dist/localization/core-messages/pt-BR.d.ts +3 -0
- package/dist/localization/core-messages/pt-BR.js +520 -0
- package/dist/localization/core-messages/zh-CN.d.ts +3 -0
- package/dist/localization/core-messages/zh-CN.js +506 -0
- package/dist/localization/core-messages/zh-TW.d.ts +3 -0
- package/dist/localization/core-messages/zh-TW.js +506 -0
- package/dist/localization/core-messages.d.ts +524 -0
- package/dist/localization/core-messages.js +124 -0
- package/dist/localization/default-messages.d.ts +2 -0
- package/dist/localization/default-messages.js +2 -0
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/observability/routes.d.ts +5 -5
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/agent-chat/plugin-options.d.ts +7 -2
- package/dist/server/agent-chat-plugin.d.ts +10 -0
- package/dist/server/agent-chat-plugin.js +144 -41
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/agent-run-context.d.ts +7 -1
- package/dist/server/agent-run-context.js +9 -2
- package/dist/server/agent-teams-run-queue.d.ts +3 -0
- package/dist/server/agent-teams.js +38 -9
- package/dist/server/index.d.ts +1 -1
- package/dist/server/request-context.d.ts +7 -0
- package/dist/server/request-context.js +15 -0
- package/docs/content/agent-surfaces.mdx +30 -0
- package/package.json +2 -2
|
@@ -7,8 +7,8 @@ import { IconLoader2, IconCheck, IconCopy, IconX, IconChevronDown, IconGitFork,
|
|
|
7
7
|
import { useState, useEffect, useCallback, useRef } from "react";
|
|
8
8
|
import { agentNativePath } from "../api-path.js";
|
|
9
9
|
import { writeClipboardText } from "../clipboard.js";
|
|
10
|
-
import { isProviderAuthenticationError } from "../error-format.js";
|
|
11
|
-
import { useT } from "../i18n.js";
|
|
10
|
+
import { isProviderAuthenticationError, localizeKnownChatErrorText, } from "../error-format.js";
|
|
11
|
+
import { useFormatters, useT } from "../i18n.js";
|
|
12
12
|
import { AgentProviderSetupForm } from "../settings/ProviderSetupForm.js";
|
|
13
13
|
import { useBuilderConnectFlow } from "../settings/useBuilderStatus.js";
|
|
14
14
|
import { cn } from "../utils.js";
|
|
@@ -66,10 +66,11 @@ export function getRunErrorMetadata(message) {
|
|
|
66
66
|
export function runErrorKey(info) {
|
|
67
67
|
return `${info.runId ?? ""}:${info.errorCode ?? ""}:${info.message}`;
|
|
68
68
|
}
|
|
69
|
-
export function runErrorHeadline(info
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
69
|
+
export function runErrorHeadline(info, labels = {
|
|
70
|
+
recoverable: "The agent stopped before finishing",
|
|
71
|
+
terminal: "The agent hit an error",
|
|
72
|
+
}) {
|
|
73
|
+
return info.recoverable === true ? labels.recoverable : labels.terminal;
|
|
73
74
|
}
|
|
74
75
|
export function getRequestModeMetadata(message) {
|
|
75
76
|
const meta = message?.metadata;
|
|
@@ -123,21 +124,28 @@ function isConnectionRecoveryRunError(info) {
|
|
|
123
124
|
// which opens the flow in an Electron BrowserWindow that shares the webview's
|
|
124
125
|
// session. See packages/desktop-app/src/main/index.ts.
|
|
125
126
|
export function BuilderConnectCta({ variant = "primary", onConnected, }) {
|
|
127
|
+
const t = useT();
|
|
126
128
|
const { configured, orgName, connecting, error, start } = useBuilderConnectFlow({
|
|
127
129
|
trackingSource: "assistant_chat_builder_cta",
|
|
128
130
|
onConnected,
|
|
129
131
|
});
|
|
130
132
|
if (variant === "compact") {
|
|
131
133
|
if (configured) {
|
|
132
|
-
return (_jsxs("span", { className: "agent-builder-setup-card__builder-button inline-flex h-8 items-center gap-1.5 whitespace-nowrap rounded-md border border-border bg-background px-2.5 text-[11px] font-medium text-foreground", children: [_jsx(IconCheck, { size: 11, className: "text-emerald-500" }), orgName
|
|
134
|
+
return (_jsxs("span", { className: "agent-builder-setup-card__builder-button inline-flex h-8 items-center gap-1.5 whitespace-nowrap rounded-md border border-border bg-background px-2.5 text-[11px] font-medium text-foreground", children: [_jsx(IconCheck, { size: 11, className: "text-emerald-500" }), orgName
|
|
135
|
+
? t("agentChat.setup.connectedTo", { organization: orgName })
|
|
136
|
+
: t("agentChat.setup.connected")] }));
|
|
133
137
|
}
|
|
134
|
-
return (_jsxs("div", { className: "agent-builder-setup-card__builder-cta flex min-w-0 flex-col items-start gap-1 sm:items-end", children: [_jsx("button", { type: "button", onClick: () => start(), disabled: connecting, className: "agent-builder-setup-card__builder-button inline-flex h-8 shrink-0 items-center gap-1 whitespace-nowrap rounded-md bg-foreground px-3 text-[11px] font-medium text-background hover:opacity-90 disabled:cursor-wait disabled:opacity-60", "aria-busy": connecting, children: connecting ? (_jsxs(_Fragment, { children: [_jsx(IconLoader2, { size: 10, className: "animate-spin" }), "
|
|
138
|
+
return (_jsxs("div", { className: "agent-builder-setup-card__builder-cta flex min-w-0 flex-col items-start gap-1 sm:items-end", children: [_jsx("button", { type: "button", onClick: () => start(), disabled: connecting, className: "agent-builder-setup-card__builder-button inline-flex h-8 shrink-0 items-center gap-1 whitespace-nowrap rounded-md bg-foreground px-3 text-[11px] font-medium text-background hover:opacity-90 disabled:cursor-wait disabled:opacity-60", "aria-busy": connecting, children: connecting ? (_jsxs(_Fragment, { children: [_jsx(IconLoader2, { size: 10, className: "animate-spin" }), t("agentChat.common.waiting")] })) : (t("agentChat.setup.connectBuilder")) }), error && (_jsx("p", { className: "max-w-[13rem] text-[10px] leading-snug text-destructive sm:text-end", children: error }))] }));
|
|
135
139
|
}
|
|
136
140
|
const containerClass = "flex items-center gap-3 rounded-md border border-border px-3 py-3";
|
|
137
141
|
if (configured) {
|
|
138
|
-
return (_jsxs("div", { className: containerClass, children: [_jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: "text-xs font-medium text-foreground", children: "Builder.io" }), _jsx("p", { className: "text-[11px] text-muted-foreground mt-0.5", children: orgName
|
|
142
|
+
return (_jsxs("div", { className: containerClass, children: [_jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: "text-xs font-medium text-foreground", children: "Builder.io" }), _jsx("p", { className: "text-[11px] text-muted-foreground mt-0.5", children: orgName
|
|
143
|
+
? t("agentChat.setup.connectedOrganization", {
|
|
144
|
+
organization: orgName,
|
|
145
|
+
})
|
|
146
|
+
: t("agentChat.setup.connected") })] }), _jsxs("span", { className: "ms-auto inline-flex items-center gap-1 shrink-0 rounded-md bg-emerald-500/10 px-2 py-0.5 text-[10px] font-medium text-emerald-500", children: [_jsx(IconCheck, { size: 10 }), t("agentChat.setup.connected")] })] }));
|
|
139
147
|
}
|
|
140
|
-
return (_jsxs("div", { className: containerClass, children: [_jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: "text-xs font-medium text-foreground", children: "
|
|
148
|
+
return (_jsxs("div", { className: containerClass, children: [_jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: "text-xs font-medium text-foreground", children: t("agentChat.setup.connectBuilder") }), _jsx("p", { className: "text-[11px] text-muted-foreground mt-0.5 max-w-[220px]", children: t("agentChat.setup.freeCredits") }), error && _jsx("p", { className: "mt-1 text-[10px] text-destructive", children: error })] }), _jsx("button", { type: "button", onClick: () => start(), disabled: connecting, className: "ms-auto inline-flex items-center gap-1 shrink-0 rounded-md bg-foreground px-3 py-1.5 text-[11px] font-medium no-underline text-background hover:opacity-90 disabled:opacity-60 disabled:cursor-wait", "aria-busy": connecting, children: connecting ? (_jsxs(_Fragment, { children: [_jsx(IconLoader2, { size: 10, className: "animate-spin" }), t("agentChat.common.waiting")] })) : (t("agentChat.common.connect")) })] }));
|
|
141
149
|
}
|
|
142
150
|
// ─── ApiKeyConnect ────────────────────────────────────────────────────────────
|
|
143
151
|
export function ApiKeyConnect({ onConnected }) {
|
|
@@ -181,6 +189,7 @@ export function BuilderSetupCard({ onConnected, bouncePulse, fullWidth, layout =
|
|
|
181
189
|
}
|
|
182
190
|
// ─── RunErrorRecoveryCard ─────────────────────────────────────────────────────
|
|
183
191
|
export function RunErrorRecoveryCard({ info, onContinue, onRetry, onFork, onDismiss, onProviderConnected, }) {
|
|
192
|
+
const t = useT();
|
|
184
193
|
const [detailsOpen, setDetailsOpen] = useState(false);
|
|
185
194
|
const [copyState, setCopyState] = useState("idle");
|
|
186
195
|
const [forking, setForking] = useState(false);
|
|
@@ -201,7 +210,9 @@ export function RunErrorRecoveryCard({ info, onContinue, onRetry, onFork, onDism
|
|
|
201
210
|
builderReconnect.configured;
|
|
202
211
|
const isQueryError = isProviderQueryRunError(info);
|
|
203
212
|
const isConnectionRecoveryError = isConnectionRecoveryRunError(info);
|
|
204
|
-
const copyLabel = info.runId || info.errorCode || info.details
|
|
213
|
+
const copyLabel = info.runId || info.errorCode || info.details
|
|
214
|
+
? t("agentChat.recovery.copyDebug")
|
|
215
|
+
: t("agentChat.common.copy");
|
|
205
216
|
const copyDetails = useCallback(() => {
|
|
206
217
|
const text = [
|
|
207
218
|
info.message,
|
|
@@ -237,31 +248,40 @@ export function RunErrorRecoveryCard({ info, onContinue, onRetry, onFork, onDism
|
|
|
237
248
|
try {
|
|
238
249
|
const result = await onFork();
|
|
239
250
|
if (result === false) {
|
|
240
|
-
setForkError("
|
|
251
|
+
setForkError(t("agentChat.recovery.forkFailed"));
|
|
241
252
|
}
|
|
242
253
|
}
|
|
243
254
|
catch {
|
|
244
|
-
setForkError("
|
|
255
|
+
setForkError(t("agentChat.recovery.forkFailed"));
|
|
245
256
|
}
|
|
246
257
|
finally {
|
|
247
258
|
setForking(false);
|
|
248
259
|
}
|
|
249
|
-
}, [forking, onFork]);
|
|
260
|
+
}, [forking, onFork, t]);
|
|
250
261
|
useEffect(() => {
|
|
251
262
|
if (builderReconnectResolved) {
|
|
252
263
|
onDismiss();
|
|
253
264
|
}
|
|
254
265
|
}, [builderReconnectResolved, onDismiss]);
|
|
255
|
-
return (_jsxs("div", { className: "rounded-lg border border-amber-500/25 bg-amber-500/[0.06] p-3 text-sm", children: [_jsxs("div", { className: "flex items-start gap-2", children: [_jsx("span", { className: "mt-0.5 flex h-6 w-6 shrink-0 items-center justify-center rounded-md bg-amber-500/10 text-amber-700 dark:text-amber-300", children: _jsx(IconAlertTriangle, { size: 14 }) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: "font-medium text-foreground", children: runErrorHeadline(info
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
266
|
+
return (_jsxs("div", { className: "rounded-lg border border-amber-500/25 bg-amber-500/[0.06] p-3 text-sm", children: [_jsxs("div", { className: "flex items-start gap-2", children: [_jsx("span", { className: "mt-0.5 flex h-6 w-6 shrink-0 items-center justify-center rounded-md bg-amber-500/10 text-amber-700 dark:text-amber-300", children: _jsx(IconAlertTriangle, { size: 14 }) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: "font-medium text-foreground", children: runErrorHeadline(info, {
|
|
267
|
+
recoverable: t("agentChat.error.stopped"),
|
|
268
|
+
terminal: t("agentChat.error.failed"),
|
|
269
|
+
}) }), _jsx("p", { className: "mt-1 text-xs leading-relaxed text-muted-foreground", children: localizeKnownChatErrorText(info.message, t) }), isProviderAuthError && (_jsx("div", { className: "mt-3 rounded-md border border-border/70 bg-background/60 p-2.5", children: _jsx(BuilderSetupContent, { layout: "sidebar", onConnected: handleProviderConnected }) })), shouldShowBuilderReconnect && !builderReconnectResolved && (_jsx("p", { className: "mt-2 text-xs leading-relaxed text-muted-foreground", children: t("agentChat.recovery.credentialRejected") })), isConnectionRecoveryError && (_jsx("p", { className: "mt-2 text-xs leading-relaxed text-muted-foreground", children: t("agentChat.recovery.newChatHint") })), (info.runId || info.errorCode || info.details) && (_jsxs("button", { type: "button", onClick: () => setDetailsOpen((v) => !v), className: "mt-2 inline-flex items-center gap-1 text-[11px] font-medium text-muted-foreground hover:text-foreground", children: [_jsx(IconChevronDown, { size: 12, className: cn("transition-transform", detailsOpen && "rotate-180") }), t("agentChat.common.details")] })), detailsOpen && (_jsxs("div", { className: "mt-2 rounded-md border border-border/60 bg-background/70 p-2 font-mono text-[11px] leading-relaxed text-muted-foreground", children: [info.runId && _jsxs("div", { children: ["run: ", info.runId] }), info.errorCode && _jsxs("div", { children: ["code: ", info.errorCode] }), info.details && (_jsx("pre", { className: "mt-2 max-h-28 overflow-auto whitespace-pre-wrap break-words font-mono", children: info.details }))] }))] }), _jsx("button", { type: "button", onClick: onDismiss, "aria-label": t("agentChat.common.dismiss"), className: "flex h-6 w-6 shrink-0 items-center justify-center rounded-md text-muted-foreground hover:bg-background/80 hover:text-foreground", children: _jsx(IconX, { size: 14 }) })] }), _jsxs("div", { className: "mt-3 flex flex-wrap items-center gap-2", children: [shouldShowBuilderReconnect && !builderReconnectResolved && (_jsxs("button", { type: "button", onClick: () => builderReconnect.start(), disabled: builderReconnect.connecting, className: "inline-flex h-8 items-center gap-1.5 rounded-md bg-foreground px-3 text-xs font-medium text-background hover:opacity-90 disabled:cursor-wait disabled:opacity-70", children: [builderReconnect.connecting ? (_jsx(IconLoader2, { size: 13, className: "animate-spin" })) : null, builderReconnect.connecting
|
|
270
|
+
? t("agentChat.recovery.connectingBuilder")
|
|
271
|
+
: t("agentChat.recovery.reconnectBuilder")] })), canRecover && (_jsx(_Fragment, { children: _jsxs("button", { type: "button", onClick: onContinue, className: "inline-flex h-8 items-center gap-1.5 rounded-md bg-foreground px-3 text-xs font-medium text-background hover:opacity-90", children: [_jsx(IconPlayerPlay, { size: 13 }), t("agentChat.common.continue")] }) })), canRetry && (_jsxs("button", { type: "button", onClick: onRetry, className: "inline-flex h-8 items-center gap-1.5 rounded-md border border-border bg-background px-3 text-xs font-medium text-foreground hover:bg-accent", children: [_jsx(IconRefresh, { size: 13 }), isQueryError
|
|
272
|
+
? t("agentChat.recovery.diagnoseRetry")
|
|
273
|
+
: t("agentChat.common.retry")] })), canRecover && isConnectionRecoveryError && (_jsxs("button", { type: "button", onClick: startNewChat, className: "inline-flex h-8 items-center gap-1.5 rounded-md border border-border bg-background px-3 text-xs font-medium text-foreground hover:bg-accent", children: [_jsx(IconPlus, { size: 13 }), t("agentChat.tabs.newChat")] })), canRecover && onFork && !isConnectionRecoveryError && (_jsxs("button", { type: "button", onClick: handleFork, disabled: forking, title: t("agentChat.recovery.forkDescription"), "aria-label": t("agentChat.recovery.forkDescription"), className: "inline-flex h-8 items-center gap-1.5 rounded-md border border-border bg-background px-3 text-xs font-medium text-foreground hover:bg-accent disabled:cursor-wait disabled:opacity-70", children: [forking ? (_jsx(IconLoader2, { size: 13, className: "animate-spin" })) : (_jsx(IconGitFork, { size: 13 })), forking
|
|
274
|
+
? t("agentChat.recovery.forking")
|
|
275
|
+
: t("agentChat.message.forkChat")] })), _jsxs("button", { type: "button", onClick: copyDetails, className: "ms-auto inline-flex h-8 items-center gap-1.5 rounded-md px-2.5 text-xs font-medium text-muted-foreground hover:bg-background/80 hover:text-foreground", children: [copyState === "copied" ? (_jsx(IconCheck, { size: 13 })) : copyState === "failed" ? (_jsx(IconX, { size: 13 })) : (_jsx(IconCopy, { size: 13 })), _jsx("span", { "aria-live": "polite", children: copyState === "copied"
|
|
276
|
+
? t("agentChat.common.copied")
|
|
259
277
|
: copyState === "failed"
|
|
260
|
-
? "
|
|
278
|
+
? t("agentChat.recovery.copyFailed")
|
|
261
279
|
: copyLabel })] })] }), shouldShowBuilderReconnect && builderReconnect.error && (_jsx("p", { className: "mt-2 text-xs leading-relaxed text-red-500", children: builderReconnect.error })), forkError && (_jsx("p", { className: "mt-2 text-xs leading-relaxed text-red-500", children: forkError }))] }));
|
|
262
280
|
}
|
|
263
281
|
// ─── LoopLimitContinueCard ────────────────────────────────────────────────────
|
|
264
282
|
export function LoopLimitContinueCard({ info, onContinue, }) {
|
|
283
|
+
const t = useT();
|
|
284
|
+
const { formatNumber } = useFormatters();
|
|
265
285
|
const [settings, setSettings] = useState(null);
|
|
266
286
|
const [value, setValue] = useState("");
|
|
267
287
|
const [saving, setSaving] = useState(false);
|
|
@@ -294,9 +314,11 @@ export function LoopLimitContinueCard({ info, onContinue, }) {
|
|
|
294
314
|
numericValue !== settings.maxIterations;
|
|
295
315
|
const scopeLabel = settings?.scope === "org"
|
|
296
316
|
? settings.orgName
|
|
297
|
-
?
|
|
298
|
-
|
|
299
|
-
|
|
317
|
+
? t("agentChat.limit.namedOrganization", {
|
|
318
|
+
organization: settings.orgName,
|
|
319
|
+
})
|
|
320
|
+
: t("agentChat.limit.organization")
|
|
321
|
+
: t("agentChat.limit.account");
|
|
300
322
|
const saveLimit = useCallback(async () => {
|
|
301
323
|
if (!settings?.canUpdate)
|
|
302
324
|
return false;
|
|
@@ -311,7 +333,8 @@ export function LoopLimitContinueCard({ info, onContinue, }) {
|
|
|
311
333
|
});
|
|
312
334
|
const body = await res.json().catch(() => ({}));
|
|
313
335
|
if (!res.ok) {
|
|
314
|
-
throw new Error(body?.error ??
|
|
336
|
+
throw new Error(body?.error ??
|
|
337
|
+
t("agentChat.common.saveFailedStatus", { status: res.status }));
|
|
315
338
|
}
|
|
316
339
|
setSettings(body);
|
|
317
340
|
setValue(String(body.maxIterations));
|
|
@@ -321,13 +344,13 @@ export function LoopLimitContinueCard({ info, onContinue, }) {
|
|
|
321
344
|
return true;
|
|
322
345
|
}
|
|
323
346
|
catch (err) {
|
|
324
|
-
setError(err instanceof Error ? err.message : "
|
|
347
|
+
setError(err instanceof Error ? err.message : t("agentChat.common.saveFailed"));
|
|
325
348
|
return false;
|
|
326
349
|
}
|
|
327
350
|
finally {
|
|
328
351
|
setSaving(false);
|
|
329
352
|
}
|
|
330
|
-
}, [numericValue, settings?.canUpdate]);
|
|
353
|
+
}, [numericValue, settings?.canUpdate, t]);
|
|
331
354
|
const handleContinue = useCallback(async () => {
|
|
332
355
|
if (hasPendingChange) {
|
|
333
356
|
const ok = await saveLimit();
|
|
@@ -343,12 +366,18 @@ export function LoopLimitContinueCard({ info, onContinue, }) {
|
|
|
343
366
|
catch { }
|
|
344
367
|
window.dispatchEvent(new CustomEvent("agent-panel:open-settings"));
|
|
345
368
|
}, []);
|
|
346
|
-
return (_jsxs("div", { className: "rounded-lg border border-amber-500/25 bg-amber-500/[0.06] px-3 py-3 shadow-sm", children: [_jsxs("div", { className: "flex items-start gap-2.5", children: [_jsx("span", { className: "mt-0.5 flex h-6 w-6 shrink-0 items-center justify-center rounded-md bg-amber-500/10 text-amber-600 dark:text-amber-400", children: _jsx(IconGauge, { size: 14 }) }), _jsxs("div", { className: "min-w-0", children: [_jsx("p", { className: "text-sm font-medium text-foreground", children: "
|
|
347
|
-
|
|
348
|
-
:
|
|
369
|
+
return (_jsxs("div", { className: "rounded-lg border border-amber-500/25 bg-amber-500/[0.06] px-3 py-3 shadow-sm", children: [_jsxs("div", { className: "flex items-start gap-2.5", children: [_jsx("span", { className: "mt-0.5 flex h-6 w-6 shrink-0 items-center justify-center rounded-md bg-amber-500/10 text-amber-600 dark:text-amber-400", children: _jsx(IconGauge, { size: 14 }) }), _jsxs("div", { className: "min-w-0", children: [_jsx("p", { className: "text-sm font-medium text-foreground", children: t("agentChat.limit.reached") }), _jsx("p", { className: "mt-0.5 text-xs leading-relaxed text-muted-foreground", children: currentLimit
|
|
370
|
+
? t("agentChat.limit.descriptionWithCount", {
|
|
371
|
+
count: currentLimit,
|
|
372
|
+
formattedCount: formatNumber(currentLimit),
|
|
373
|
+
scope: scopeLabel,
|
|
374
|
+
})
|
|
375
|
+
: t("agentChat.limit.descriptionAll", { scope: scopeLabel }) })] })] }), _jsxs("div", { className: "mt-3 flex flex-wrap items-end gap-2", children: [_jsxs("label", { className: "min-w-[116px] flex-1 space-y-1", children: [_jsx("span", { className: "text-[10px] font-medium uppercase tracking-wide text-muted-foreground", children: t("agentChat.limit.maxSteps") }), _jsx("input", { type: "number", min: settings?.minMaxIterations ?? 1, max: settings?.maxMaxIterations ?? 1000, value: value, disabled: !settings?.canUpdate || saving, onChange: (e) => {
|
|
349
376
|
setValue(e.target.value);
|
|
350
377
|
setError(null);
|
|
351
|
-
}, className: "h-8 w-full rounded-md border border-border bg-background px-2 text-xs text-foreground outline-none focus:ring-1 focus:ring-ring disabled:opacity-60" })] }), _jsx("button", { type: "button", onClick: saveLimit, disabled: !hasPendingChange || saving, className: "inline-flex h-8 items-center gap-1 rounded-md border border-border px-2.5 text-xs font-medium text-foreground hover:bg-accent disabled:opacity-50", children: saving ? (_jsx(IconLoader2, { size: 12, className: "animate-spin" })) : saved ? (_jsx(IconCheck, { size: 12 })) : ("
|
|
378
|
+
}, className: "h-8 w-full rounded-md border border-border bg-background px-2 text-xs text-foreground outline-none focus:ring-1 focus:ring-ring disabled:opacity-60" })] }), _jsx("button", { type: "button", onClick: saveLimit, disabled: !hasPendingChange || saving, className: "inline-flex h-8 items-center gap-1 rounded-md border border-border px-2.5 text-xs font-medium text-foreground hover:bg-accent disabled:opacity-50", children: saving ? (_jsx(IconLoader2, { size: 12, className: "animate-spin" })) : saved ? (_jsx(IconCheck, { size: 12 })) : (t("agentChat.common.save")) }), _jsxs("button", { type: "button", onClick: openSettings, className: "inline-flex h-8 items-center gap-1 rounded-md border border-border px-2.5 text-xs font-medium text-muted-foreground hover:bg-accent hover:text-foreground", children: [_jsx(IconSettings, { size: 12 }), t("agentChat.common.settings")] }), _jsxs("button", { type: "button", onClick: handleContinue, disabled: saving, className: "ms-auto inline-flex h-8 items-center gap-1 rounded-md bg-foreground px-3 text-xs font-medium text-background hover:opacity-90 disabled:opacity-60", children: [hasPendingChange
|
|
379
|
+
? t("agentChat.limit.saveAndContinue")
|
|
380
|
+
: t("agentChat.limit.keepGoing"), _jsx(IconArrowRight, { size: 12 })] })] }), settings && !settings.canUpdate && (_jsx("p", { className: "mt-2 text-[11px] text-muted-foreground", children: t("agentChat.limit.ownerOnly") })), error && _jsx("p", { className: "mt-2 text-[11px] text-destructive", children: error })] }));
|
|
352
381
|
}
|
|
353
382
|
// ─── PlanModeCallout ──────────────────────────────────────────────────────────
|
|
354
383
|
//
|
|
@@ -358,5 +387,8 @@ export function LoopLimitContinueCard({ info, onContinue, }) {
|
|
|
358
387
|
// narrow sidebar chats and wide/centered page layouts, instead of floating
|
|
359
388
|
// against the full pane width.
|
|
360
389
|
export function PlanModeCallout({ canImplementPlan, onImplementPlan, onSwitchToAct, }) {
|
|
361
|
-
|
|
390
|
+
const t = useT();
|
|
391
|
+
return (_jsx("div", { className: "agent-plan-mode-callout shrink-0 px-3", children: _jsxs("div", { className: "ms-auto flex w-fit max-w-full items-center gap-2 rounded-full border border-border/70 bg-background/95 px-2 py-1.5 text-xs text-muted-foreground shadow-sm", children: [_jsx(IconClipboardList, { size: 13, className: "shrink-0" }), _jsx("span", { className: "min-w-0 truncate", children: canImplementPlan
|
|
392
|
+
? t("agentChat.plan.ready")
|
|
393
|
+
: t("agentChat.plan.mode") }), canImplementPlan ? (_jsxs("button", { type: "button", onClick: onImplementPlan, className: "inline-flex h-6 shrink-0 items-center gap-1 rounded-full bg-foreground px-2.5 text-[11px] font-medium text-background hover:opacity-90", children: [_jsx(IconPlayerPlay, { size: 12 }), t("agentChat.plan.implement")] })) : (_jsxs("button", { type: "button", onClick: onSwitchToAct, className: "inline-flex h-6 shrink-0 items-center gap-1 rounded-full border border-border bg-background px-2.5 text-[11px] font-medium text-foreground hover:bg-accent", "aria-label": t("agentChat.plan.switchToAct"), children: [t("agentChat.plan.act"), _jsx(IconArrowRight, { size: 12 })] }))] }) }));
|
|
362
394
|
}
|
|
@@ -72,8 +72,11 @@ export type ToolDetailPayload = {
|
|
|
72
72
|
copyText: string;
|
|
73
73
|
lang: string;
|
|
74
74
|
};
|
|
75
|
-
export declare function toolInputPayload(toolName: string, args: Record<string, unknown
|
|
76
|
-
|
|
75
|
+
export declare function toolInputPayload(toolName: string, args: Record<string, unknown>, labels?: {
|
|
76
|
+
input: string;
|
|
77
|
+
inputWithLabel: (label: string) => string;
|
|
78
|
+
}): ToolDetailPayload | null;
|
|
79
|
+
export declare function toolResultPayload(result: string | undefined, title?: string): ToolDetailPayload | null;
|
|
77
80
|
export declare function AnimatedCollapse({ open, children, }: {
|
|
78
81
|
open: boolean;
|
|
79
82
|
children: React.ReactNode;
|
|
@@ -138,7 +141,13 @@ export declare function ReasoningCell({ text, isStreaming, defaultOpen, autoColl
|
|
|
138
141
|
*/
|
|
139
142
|
durationMs?: number | null;
|
|
140
143
|
}): React.JSX.Element | null;
|
|
141
|
-
export declare function formatWorkedDuration(ms: number
|
|
144
|
+
export declare function formatWorkedDuration(ms: number, options?: {
|
|
145
|
+
locale?: string;
|
|
146
|
+
hour?: string;
|
|
147
|
+
minute?: string;
|
|
148
|
+
second?: string;
|
|
149
|
+
}): string;
|
|
150
|
+
export declare function useLocalizedWorkedDuration(): (ms: number) => string;
|
|
142
151
|
export declare function WorkedForSummary({ durationMs, defaultOpen, autoCollapse, children, }: {
|
|
143
152
|
durationMs?: number | null;
|
|
144
153
|
/** Keep completed work visible when the turn contains interactive UI. */
|
|
@@ -6,7 +6,7 @@ import { writeClipboardText } from "../clipboard.js";
|
|
|
6
6
|
import { Popover, PopoverContent, PopoverTrigger, } from "../components/ui/popover.js";
|
|
7
7
|
import { ConnectBuilderCard } from "../ConnectBuilderCard.js";
|
|
8
8
|
import { FileStorageSetupCard } from "../FileStorageSetupCard.js";
|
|
9
|
-
import { useT } from "../i18n.js";
|
|
9
|
+
import { useOptionalLocale, useT } from "../i18n.js";
|
|
10
10
|
import { McpAppRenderer } from "../mcp-apps/McpAppRenderer.js";
|
|
11
11
|
import { findMcpIntegrationForToolName } from "../resources/mcp-integration-catalog.js";
|
|
12
12
|
import { McpIntegrationLogo } from "../resources/McpIntegrationLogo.js";
|
|
@@ -41,6 +41,7 @@ export function toolCallHasPendingApproval(part) {
|
|
|
41
41
|
}
|
|
42
42
|
export const TOOL_LONG_RUNNING_HINT_DELAY_MS = 45_000;
|
|
43
43
|
export function ToolActivityPresentation({ toolName, isRunning, toolCallId, suppressLongRunningHint = false, children, }) {
|
|
44
|
+
const t = useT();
|
|
44
45
|
const [showLongRunningHint, setShowLongRunningHint] = useState(false);
|
|
45
46
|
useEffect(() => {
|
|
46
47
|
if (!isRunning || suppressLongRunningHint) {
|
|
@@ -53,7 +54,7 @@ export function ToolActivityPresentation({ toolName, isRunning, toolCallId, supp
|
|
|
53
54
|
}, TOOL_LONG_RUNNING_HINT_DELAY_MS);
|
|
54
55
|
return () => window.clearTimeout(timeout);
|
|
55
56
|
}, [isRunning, suppressLongRunningHint, toolName]);
|
|
56
|
-
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: "
|
|
57
|
+
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: t("agentChat.tool.longRunning") }))] }) }));
|
|
57
58
|
}
|
|
58
59
|
function stringifyToolValue(value, pretty = false) {
|
|
59
60
|
if (typeof value === "string")
|
|
@@ -109,7 +110,10 @@ function formatToolTextValue(value, key, toolName) {
|
|
|
109
110
|
}
|
|
110
111
|
return { text: stringifyToolValue(value, true), lang: "json" };
|
|
111
112
|
}
|
|
112
|
-
export function toolInputPayload(toolName, args
|
|
113
|
+
export function toolInputPayload(toolName, args, labels = {
|
|
114
|
+
input: "Input",
|
|
115
|
+
inputWithLabel: (label) => `Input - ${label}`,
|
|
116
|
+
}) {
|
|
113
117
|
const entries = Object.entries(args);
|
|
114
118
|
if (entries.length === 0)
|
|
115
119
|
return null;
|
|
@@ -120,7 +124,7 @@ export function toolInputPayload(toolName, args) {
|
|
|
120
124
|
const keyLabel = normalizedKey === "sql" || normalizedKey.endsWith("sql") ? "SQL" : key;
|
|
121
125
|
return {
|
|
122
126
|
section: "input",
|
|
123
|
-
title:
|
|
127
|
+
title: labels.inputWithLabel(keyLabel),
|
|
124
128
|
text: formatted.text,
|
|
125
129
|
copyText: typeof value === "string" ? value : stringifyToolValue(value, true),
|
|
126
130
|
lang: formatted.lang,
|
|
@@ -128,19 +132,19 @@ export function toolInputPayload(toolName, args) {
|
|
|
128
132
|
}
|
|
129
133
|
return {
|
|
130
134
|
section: "input",
|
|
131
|
-
title:
|
|
135
|
+
title: labels.input,
|
|
132
136
|
text: JSON.stringify(args, null, 2),
|
|
133
137
|
copyText: JSON.stringify(args, null, 2),
|
|
134
138
|
lang: "json",
|
|
135
139
|
};
|
|
136
140
|
}
|
|
137
|
-
export function toolResultPayload(result) {
|
|
141
|
+
export function toolResultPayload(result, title = "Result") {
|
|
138
142
|
if (result === undefined)
|
|
139
143
|
return null;
|
|
140
144
|
const formatted = formatToolTextValue(result);
|
|
141
145
|
return {
|
|
142
146
|
section: "result",
|
|
143
|
-
title
|
|
147
|
+
title,
|
|
144
148
|
text: formatted.text,
|
|
145
149
|
copyText: result,
|
|
146
150
|
lang: formatted.lang,
|
|
@@ -195,6 +199,7 @@ function SimpleCodeViewer({ text, lang, className, maxHeightClass = "max-h-56",
|
|
|
195
199
|
return (_jsxs("div", { className: cn("agent-tool-code overflow-auto rounded-md bg-muted/70 font-mono text-[11px] leading-relaxed text-foreground", maxHeightClass, className), children: [lang !== "text" && (_jsx("div", { className: "sticky top-0 z-[1] flex items-center justify-between border-b border-border/40 bg-muted/90 px-2.5 py-1", children: _jsx("span", { className: "font-mono text-[10px] uppercase tracking-wide text-muted-foreground/80", children: lang }) })), _jsx(HighlightedCodeBlock, { code: text, lang: lang })] }));
|
|
196
200
|
}
|
|
197
201
|
function ToolOutputPopover({ open, onOpenChange, title, payload, children, }) {
|
|
202
|
+
const t = useT();
|
|
198
203
|
const [copied, setCopied] = useState(false);
|
|
199
204
|
const copyResetRef = useRef(null);
|
|
200
205
|
useEffect(() => {
|
|
@@ -216,7 +221,7 @@ function ToolOutputPopover({ open, onOpenChange, title, payload, children, }) {
|
|
|
216
221
|
// Clipboard failures should not interrupt chat rendering.
|
|
217
222
|
}
|
|
218
223
|
}, [payload.copyText]);
|
|
219
|
-
return (_jsxs(Popover, { open: open, onOpenChange: onOpenChange, children: [_jsx(PopoverTrigger, { asChild: true, children: children }), _jsxs(PopoverContent, { align: "start", side: "bottom", sideOffset: 6, collisionPadding: 12, className: "flex max-h-[min(calc(100vh-2rem),var(--radix-popover-content-available-height,75vh))] w-[min(calc(100vw-2rem),var(--radix-popover-content-available-width,760px),760px)] flex-col gap-0 overflow-hidden p-0", children: [_jsxs("div", { className: "flex shrink-0 items-center justify-between gap-3 border-b border-border px-4 py-3", children: [_jsx("div", { className: "truncate text-sm font-medium", children: title }), _jsxs("button", { type: "button", onClick: copyValue, className: "inline-flex h-7 items-center gap-1.5 rounded-md px-2 text-xs text-muted-foreground hover:bg-accent hover:text-foreground", children: [copied ? _jsx(IconCheck, { size: 13 }) : _jsx(IconCopy, { size: 13 }), copied ? "
|
|
224
|
+
return (_jsxs(Popover, { open: open, onOpenChange: onOpenChange, children: [_jsx(PopoverTrigger, { asChild: true, children: children }), _jsxs(PopoverContent, { align: "start", side: "bottom", sideOffset: 6, collisionPadding: 12, className: "flex max-h-[min(calc(100vh-2rem),var(--radix-popover-content-available-height,75vh))] w-[min(calc(100vw-2rem),var(--radix-popover-content-available-width,760px),760px)] flex-col gap-0 overflow-hidden p-0", children: [_jsxs("div", { className: "flex shrink-0 items-center justify-between gap-3 border-b border-border px-4 py-3", children: [_jsx("div", { className: "truncate text-sm font-medium", children: title }), _jsxs("button", { type: "button", onClick: copyValue, className: "inline-flex h-7 items-center gap-1.5 rounded-md px-2 text-xs text-muted-foreground hover:bg-accent hover:text-foreground", children: [copied ? _jsx(IconCheck, { size: 13 }) : _jsx(IconCopy, { size: 13 }), copied ? t("agentChat.common.copied") : t("agentChat.common.copy")] })] }), _jsx("div", { className: "min-h-0 flex-1 overflow-hidden p-3", children: _jsx(SimpleCodeViewer, { text: payload.text, lang: payload.lang, maxHeightClass: "max-h-[min(70vh,calc(var(--radix-popover-content-available-height,75vh)-4.5rem))]" }) })] })] }));
|
|
220
225
|
}
|
|
221
226
|
// ─── Collapsible height animation ─────────────────────────────────────────────
|
|
222
227
|
export function AnimatedCollapse({ open, children, }) {
|
|
@@ -241,6 +246,7 @@ export function AnimatedCollapse({ open, children, }) {
|
|
|
241
246
|
* the prompt locally (the action stays un-run).
|
|
242
247
|
*/
|
|
243
248
|
function ApprovalAffordance({ toolName, toolCallId, approval, }) {
|
|
249
|
+
const t = useT();
|
|
244
250
|
const ctx = React.useContext(ApprovalContext);
|
|
245
251
|
const [localResolution, setLocalResolution] = useState(null);
|
|
246
252
|
const retainedResolution = ctx?.getApprovalResolution?.(approval.approvalKey, toolCallId) ?? null;
|
|
@@ -250,27 +256,27 @@ function ApprovalAffordance({ toolName, toolCallId, approval, }) {
|
|
|
250
256
|
// Once resolved, collapse to a quiet note so a repository refresh cannot
|
|
251
257
|
// restore the action buttons while the continuation is running.
|
|
252
258
|
if (resolution === "approved") {
|
|
253
|
-
return (
|
|
259
|
+
return (_jsx("div", { className: "mt-1.5 text-xs text-muted-foreground", children: t("agentChat.approval.approved", { tool: toolName }) }));
|
|
254
260
|
}
|
|
255
261
|
// Deny defaults to local-only (the action simply stays un-run). When the
|
|
256
262
|
// host also provided `onDeny` (e.g. a Code session resolving its own
|
|
257
263
|
// pending approval), it fires alongside the local state.
|
|
258
264
|
if (resolution === "denied") {
|
|
259
|
-
return (
|
|
265
|
+
return (_jsx("div", { className: "mt-1.5 text-xs text-muted-foreground", children: t("agentChat.approval.denied", { tool: toolName }) }));
|
|
260
266
|
}
|
|
261
|
-
return (_jsxs("div", { className: "mt-1.5 flex min-w-0 flex-wrap items-center gap-2 rounded-md border border-border bg-muted/40 px-2.5 py-1.5", children: [_jsx(IconShieldCheck, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
|
|
267
|
+
return (_jsxs("div", { className: "mt-1.5 flex min-w-0 flex-wrap items-center gap-2 rounded-md border border-border bg-muted/40 px-2.5 py-1.5", children: [_jsx(IconShieldCheck, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }), _jsx("span", { className: "min-w-0 flex-1 text-xs text-muted-foreground", children: t("agentChat.approval.question", { tool: toolName }) }), ctx && (_jsxs("button", { type: "button", onClick: () => {
|
|
262
268
|
setLocalResolution("approved");
|
|
263
269
|
ctx.onApprovalResolved?.(approval.approvalKey, "approved", toolCallId);
|
|
264
270
|
ctx.onApprove(approval.approvalKey);
|
|
265
|
-
}, className: cn("inline-flex shrink-0 items-center gap-1 rounded-md px-2.5 py-1 text-xs font-medium transition-colors", "bg-foreground text-background hover:bg-foreground/90"), children: [_jsx(IconCheck, { className: "h-3.5 w-3.5" }), "
|
|
271
|
+
}, className: cn("inline-flex shrink-0 items-center gap-1 rounded-md px-2.5 py-1 text-xs font-medium transition-colors", "bg-foreground text-background hover:bg-foreground/90"), children: [_jsx(IconCheck, { className: "h-3.5 w-3.5" }), t("agentChat.approval.approve")] })), ctx?.onAlwaysAllow && (_jsxs("button", { type: "button", onClick: () => {
|
|
266
272
|
setLocalResolution("approved");
|
|
267
273
|
ctx.onApprovalResolved?.(approval.approvalKey, "approved", toolCallId);
|
|
268
274
|
ctx.onAlwaysAllow?.(approval.approvalKey);
|
|
269
|
-
}, title: "
|
|
275
|
+
}, title: t("agentChat.approval.alwaysAllowHint"), className: cn("inline-flex shrink-0 items-center gap-1 rounded-md border border-border px-2.5 py-1 text-xs font-medium transition-colors", "text-foreground hover:bg-muted"), children: [_jsx(IconShieldCheck, { className: "h-3.5 w-3.5" }), t("agentChat.approval.alwaysAllow")] })), _jsxs("button", { type: "button", onClick: () => {
|
|
270
276
|
setLocalResolution("denied");
|
|
271
277
|
ctx?.onApprovalResolved?.(approval.approvalKey, "denied", toolCallId);
|
|
272
278
|
ctx?.onDeny?.(approval.approvalKey);
|
|
273
|
-
}, className: cn("inline-flex shrink-0 items-center gap-1 rounded-md border border-border px-2.5 py-1 text-xs font-medium transition-colors", "text-foreground hover:bg-muted"), children: [_jsx(IconX, { className: "h-3.5 w-3.5" }), "
|
|
279
|
+
}, className: cn("inline-flex shrink-0 items-center gap-1 rounded-md border border-border px-2.5 py-1 text-xs font-medium transition-colors", "text-foreground hover:bg-muted"), children: [_jsx(IconX, { className: "h-3.5 w-3.5" }), t("agentChat.approval.deny")] })] }));
|
|
274
280
|
}
|
|
275
281
|
// ─── ToolCallDisplay ──────────────────────────────────────────────────────────
|
|
276
282
|
export function ToolCallDisplay({ toolName, toolCallId, argsText, args, result, mcpApp, chatUI, isRunning, outcome, structuredMeta, activity, approval, repeatCount, isLatestRunning = isRunning, isActiveTail, }) {
|
|
@@ -303,6 +309,7 @@ export function ToolCallDisplay({ toolName, toolCallId, argsText, args, result,
|
|
|
303
309
|
return wrapToolDisplay(_jsx(ToolCallDisplayGeneric, { toolName: toolName, toolCallId: toolCallId, argsText: argsText, args: args, result: result, mcpApp: mcpApp, chatUI: chatUI, isRunning: effectiveIsRunning, outcome: outcome, isActiveTail: showActiveTail, structuredMeta: structuredMeta, approval: approval, repeatCount: repeatCount }));
|
|
304
310
|
}
|
|
305
311
|
function ToolCallDisplayGeneric({ toolName, toolCallId, argsText, args, result, mcpApp, chatUI, isRunning, outcome, isActiveTail, structuredMeta, approval, repeatCount, }) {
|
|
312
|
+
const t = useT();
|
|
306
313
|
const suppressInlineOpenApp = React.useContext(SuppressInlineOpenAppContext);
|
|
307
314
|
const isRawCallAgent = toolName === "call-agent";
|
|
308
315
|
const isAgentCall = toolName.startsWith("agent:") || isRawCallAgent;
|
|
@@ -362,7 +369,7 @@ function ToolCallDisplayGeneric({ toolName, toolCallId, argsText, args, result,
|
|
|
362
369
|
if (parsed.taskId && parsed.threadId) {
|
|
363
370
|
return (_jsx(AgentTaskCard, { taskId: parsed.taskId, threadId: parsed.threadId, description: parsed.description ||
|
|
364
371
|
args?.task ||
|
|
365
|
-
"
|
|
372
|
+
t("agentChat.tool.subAgentTask"), onOpen: (tid) => {
|
|
366
373
|
window.dispatchEvent(new CustomEvent("agent-task-open", {
|
|
367
374
|
detail: {
|
|
368
375
|
threadId: tid,
|
|
@@ -398,30 +405,38 @@ function ToolCallDisplayGeneric({ toolName, toolCallId, argsText, args, result,
|
|
|
398
405
|
if (NativeToolRenderer) {
|
|
399
406
|
return (_jsx(ActionChatUiSurface, { context: nativeToolContext, isBuiltinDataWidget: isBuiltinDataWidgetActionRenderer(nativeToolContext), children: _jsx(NativeToolRenderer, { context: nativeToolContext }) }));
|
|
400
407
|
}
|
|
401
|
-
const inputPayload = hasArgs
|
|
402
|
-
|
|
408
|
+
const inputPayload = hasArgs
|
|
409
|
+
? toolInputPayload(toolName, args, {
|
|
410
|
+
input: t("agentChat.tool.input"),
|
|
411
|
+
inputWithLabel: (label) => t("agentChat.tool.inputWithLabel", { label }),
|
|
412
|
+
})
|
|
413
|
+
: null;
|
|
414
|
+
const resultPayload = toolResultPayload(result, t("agentChat.tool.result"));
|
|
403
415
|
const displayName = isAgentCall
|
|
404
416
|
? isRunning
|
|
405
|
-
?
|
|
417
|
+
? t("agentChat.tool.askingAgent", { agent: agentName })
|
|
406
418
|
: isAgentError
|
|
407
|
-
?
|
|
408
|
-
:
|
|
419
|
+
? t("agentChat.tool.askingAgentFailed", { agent: agentName })
|
|
420
|
+
: t("agentChat.tool.askedAgent", { agent: agentName })
|
|
409
421
|
: humanizeToolName(toolName);
|
|
410
422
|
const canExpand = isAgentCall
|
|
411
423
|
? hasStreamText
|
|
412
424
|
: hasArgs || result !== undefined;
|
|
413
425
|
const isExpanded = isAgentCall ? hasStreamText && expanded : expanded;
|
|
414
426
|
const ToolIcon = resolveToolIcon(toolName);
|
|
415
|
-
const outputTitle =
|
|
427
|
+
const outputTitle = t("agentChat.tool.rawOutput", { tool: toolName });
|
|
416
428
|
if (isAgentCall) {
|
|
417
|
-
return (_jsx(AgentCallCell, { agentName: agentName ?? "agent", activity: agentActivity, progress: agentProgress, responseText: agentStreamText, isRunning: isRunning, isError: isAgentError, durationMs: typeof structuredMeta?.agentDurationMs === "number"
|
|
429
|
+
return (_jsx(AgentCallCell, { agentName: agentName ?? t("agentChat.common.agent"), activity: agentActivity, progress: agentProgress, responseText: agentStreamText, isRunning: isRunning, isError: isAgentError, durationMs: typeof structuredMeta?.agentDurationMs === "number"
|
|
418
430
|
? structuredMeta.agentDurationMs
|
|
419
431
|
: agentActivity?.durationMs }));
|
|
420
432
|
}
|
|
421
|
-
return (_jsxs("div", { className: "group/tool my-0.5 w-full overflow-hidden", children: [mcpApp && !(suppressInlineOpenApp && toolName === "open_app") && (_jsx(McpAppRenderer, { app: mcpApp, className: "mb-1.5" })), _jsxs("button", { type: "button", onClick: () => canExpand && setExpanded(!isExpanded), "aria-expanded": canExpand ? isExpanded : undefined, className: cn("flex w-full items-center gap-1.5 rounded-md py-0.5 text-left text-[13px] text-muted-foreground transition-colors", canExpand && "hover:text-foreground", isRunning && "text-muted-foreground"), children: [_jsx("span", { className: "relative flex size-4 shrink-0 items-center justify-center", children: isRunning ? (_jsx(IconLoader2, { className: "size-3.5 animate-spin" })) : isAgentError ? (_jsx(IconCircleX, { className: "size-3.5 text-destructive" })) : isUnknownOutcome ? (_jsx(IconAlertTriangle, { className: "size-3.5 text-muted-foreground" })) : (_jsxs(_Fragment, { children: [_jsx(ToolIcon, { className: cn("size-3.5 transition-opacity", canExpand && "group-hover/tool:opacity-0") }), canExpand && (_jsx(IconChevronRight, { className: cn("absolute size-3.5 opacity-0 transition-[opacity,transform] group-hover/tool:opacity-100", isExpanded && "rotate-90") }))] })) }), _jsx("span", { className: cn("min-w-0 truncate font-normal", isActiveTail && "agent-running-shimmer"), children: displayName }), repeatCount && repeatCount > 1 && (_jsxs("span", { className: "shrink-0 rounded border border-border/60 px-1.5 py-0.5 text-[10px] leading-none text-muted-foreground", title:
|
|
433
|
+
return (_jsxs("div", { className: "group/tool my-0.5 w-full overflow-hidden", children: [mcpApp && !(suppressInlineOpenApp && toolName === "open_app") && (_jsx(McpAppRenderer, { app: mcpApp, className: "mb-1.5" })), _jsxs("button", { type: "button", onClick: () => canExpand && setExpanded(!isExpanded), "aria-expanded": canExpand ? isExpanded : undefined, className: cn("flex w-full items-center gap-1.5 rounded-md py-0.5 text-left text-[13px] text-muted-foreground transition-colors", canExpand && "hover:text-foreground", isRunning && "text-muted-foreground"), children: [_jsx("span", { className: "relative flex size-4 shrink-0 items-center justify-center", children: isRunning ? (_jsx(IconLoader2, { className: "size-3.5 animate-spin" })) : isAgentError ? (_jsx(IconCircleX, { className: "size-3.5 text-destructive" })) : isUnknownOutcome ? (_jsx(IconAlertTriangle, { className: "size-3.5 text-muted-foreground" })) : (_jsxs(_Fragment, { children: [_jsx(ToolIcon, { className: cn("size-3.5 transition-opacity", canExpand && "group-hover/tool:opacity-0") }), canExpand && (_jsx(IconChevronRight, { className: cn("absolute size-3.5 opacity-0 transition-[opacity,transform] group-hover/tool:opacity-100", isExpanded && "rotate-90") }))] })) }), _jsx("span", { className: cn("min-w-0 truncate font-normal", isActiveTail && "agent-running-shimmer"), children: displayName }), repeatCount && repeatCount > 1 && (_jsxs("span", { className: "shrink-0 rounded border border-border/60 px-1.5 py-0.5 text-[10px] leading-none text-muted-foreground", title: t("agentChat.tool.repeated", { count: repeatCount }), children: [repeatCount, "x"] }))] }), _jsx(AnimatedCollapse, { open: isExpanded && !isAgentCall && (hasArgs || result !== undefined), children: _jsxs("div", { className: "mt-1 space-y-2 pl-5", children: [inputPayload && (_jsx(SimpleCodeViewer, { text: inputPayload.text, lang: inputPayload.lang })), resultPayload && (_jsx(ToolOutputPopover, { open: outputOpen, onOpenChange: setOutputOpen, title: outputTitle, payload: resultPayload, children: _jsx("button", { type: "button", "aria-label": t("agentChat.tool.viewOutput", {
|
|
434
|
+
tool: toolName,
|
|
435
|
+
}), className: "inline-flex size-6 items-center justify-center rounded-md text-muted-foreground/70 transition-colors hover:bg-accent hover:text-foreground", children: _jsx(IconCode, { className: "size-3.5" }) }) }))] }) }), isUnknownOutcome && (_jsx("p", { role: "status", className: "ps-5 text-xs text-muted-foreground", children: t("agentChat.tool.interrupted") })), approval && (_jsx(ApprovalAffordance, { toolName: toolName, toolCallId: toolCallId, approval: approval }))] }));
|
|
422
436
|
}
|
|
423
437
|
function AgentCallCell({ agentName, activity, progress, responseText, isRunning, isError, durationMs, }) {
|
|
424
438
|
const t = useT();
|
|
439
|
+
const formatDuration = useLocalizedWorkedDuration();
|
|
425
440
|
const [open, setOpen] = useState(true);
|
|
426
441
|
const toolCount = activity?.toolCalls?.length ?? 0;
|
|
427
442
|
// Response segments are ordered against the tool calls that preceded them, so
|
|
@@ -434,10 +449,10 @@ function AgentCallCell({ agentName, activity, progress, responseText, isRunning,
|
|
|
434
449
|
const work = activity?.reasoning?.length || toolCount || inlineSegments.length;
|
|
435
450
|
const workItemCount = Math.max(activity?.reasoning?.length ?? 0, toolCount, inlineSegments.length);
|
|
436
451
|
const label = isRunning
|
|
437
|
-
? t("
|
|
452
|
+
? t("agentChat.tool.askingAgent", { agent: agentName })
|
|
438
453
|
: isError
|
|
439
|
-
? t("
|
|
440
|
-
: t("
|
|
454
|
+
? t("agentChat.tool.askingAgentFailed", { agent: agentName })
|
|
455
|
+
: t("agentChat.tool.askedAgent", { agent: agentName });
|
|
441
456
|
const workContent = work ? (_jsx("div", { className: "space-y-1 ps-5", children: Array.from({ length: workItemCount }, (_, index) => {
|
|
442
457
|
const reasoningText = activity?.reasoning?.[index];
|
|
443
458
|
const segment = inlineSegments[index];
|
|
@@ -452,8 +467,8 @@ function AgentCallCell({ agentName, activity, progress, responseText, isRunning,
|
|
|
452
467
|
const progressText = isRunning && !activity && progress && progressState
|
|
453
468
|
? [
|
|
454
469
|
progressState.charAt(0).toUpperCase() + progressState.slice(1),
|
|
455
|
-
t("
|
|
456
|
-
duration:
|
|
470
|
+
t("agentChat.tool.elapsed", {
|
|
471
|
+
duration: formatDuration(progress.elapsedSeconds * 1000),
|
|
457
472
|
}),
|
|
458
473
|
progress.detail,
|
|
459
474
|
]
|
|
@@ -603,6 +618,8 @@ function isReconnectToolSummaryPart(content, index, startIndex) {
|
|
|
603
618
|
*/
|
|
604
619
|
const WorkSummaryContentContext = React.createContext(false);
|
|
605
620
|
export function ReasoningCell({ text, isStreaming = false, defaultOpen, autoCollapse = false, collapseWhenReplaced = false, durationMs, }) {
|
|
621
|
+
const t = useT();
|
|
622
|
+
const formatDuration = useLocalizedWorkedDuration();
|
|
606
623
|
const embeddedInWorkSummary = React.useContext(WorkSummaryContentContext);
|
|
607
624
|
const [open, setOpen] = useState(defaultOpen ?? true);
|
|
608
625
|
const wasStreamingRef = useRef(isStreaming);
|
|
@@ -630,35 +647,54 @@ export function ReasoningCell({ text, isStreaming = false, defaultOpen, autoColl
|
|
|
630
647
|
return (_jsx("div", { className: "pb-1 pl-5 text-[13px] leading-relaxed text-muted-foreground whitespace-pre-wrap", children: visibleText || (isStreaming ? "…" : "") }));
|
|
631
648
|
}
|
|
632
649
|
const label = isStreaming
|
|
633
|
-
? "
|
|
650
|
+
? t("agentChat.status.thinking")
|
|
634
651
|
: durationMs != null
|
|
635
|
-
?
|
|
636
|
-
|
|
652
|
+
? t("agentChat.tool.thoughtFor", {
|
|
653
|
+
duration: formatDuration(durationMs),
|
|
654
|
+
})
|
|
655
|
+
: t("agentChat.tool.thought");
|
|
637
656
|
// Only clamp to a scroll-free "tail" view while actively streaming and
|
|
638
657
|
// expanded — once the run finishes the full text is shown, unclamped.
|
|
639
658
|
const showTail = isStreaming && open;
|
|
640
659
|
return (_jsxs("div", { className: "my-0.5 w-full", children: [_jsxs("button", { type: "button", onClick: () => setOpen((v) => !v), "aria-expanded": open, className: "flex items-center gap-1.5 py-0.5 text-[13px] text-muted-foreground transition-colors hover:text-foreground", children: [_jsx(IconChevronRight, { className: cn("size-3.5 shrink-0 transition-transform", open && "rotate-90") }), isStreaming ? (_jsx("span", { className: "agent-thinking-indicator__text", children: label })) : (_jsx("span", { children: label }))] }), _jsx(AnimatedCollapse, { open: open, children: _jsx("div", { className: cn("pl-5 pb-1", showTail && "reasoning-cell-tail"), children: _jsx("div", { className: "text-[13px] leading-relaxed text-muted-foreground whitespace-pre-wrap", children: visibleText || (isStreaming ? "…" : "") }) }) })] }));
|
|
641
660
|
}
|
|
642
661
|
// ─── Worked-for duration helpers ──────────────────────────────────────────────
|
|
643
|
-
export function formatWorkedDuration(ms) {
|
|
662
|
+
export function formatWorkedDuration(ms, options = {}) {
|
|
663
|
+
const number = new Intl.NumberFormat(options.locale ?? "en-US");
|
|
664
|
+
const hour = options.hour ?? "h";
|
|
665
|
+
const minute = options.minute ?? "m";
|
|
666
|
+
const second = options.second ?? "s";
|
|
667
|
+
const part = (value, unit) => `${number.format(value)}${unit}`;
|
|
644
668
|
const totalSeconds = Math.max(0, Math.round(ms / 1000));
|
|
645
669
|
if (totalSeconds < 60) {
|
|
646
|
-
return
|
|
670
|
+
return part(Math.max(1, totalSeconds), second);
|
|
647
671
|
}
|
|
648
672
|
const minutes = Math.floor(totalSeconds / 60);
|
|
649
673
|
const seconds = totalSeconds % 60;
|
|
650
674
|
if (minutes < 60) {
|
|
651
675
|
if (seconds === 0)
|
|
652
|
-
return
|
|
653
|
-
return `${minutes}
|
|
676
|
+
return part(minutes, minute);
|
|
677
|
+
return `${part(minutes, minute)} ${part(seconds, second)}`;
|
|
654
678
|
}
|
|
655
679
|
const hours = Math.floor(minutes / 60);
|
|
656
680
|
const remMinutes = minutes % 60;
|
|
657
681
|
if (remMinutes === 0)
|
|
658
|
-
return
|
|
659
|
-
return `${hours}
|
|
682
|
+
return part(hours, hour);
|
|
683
|
+
return `${part(hours, hour)} ${part(remMinutes, minute)}`;
|
|
684
|
+
}
|
|
685
|
+
export function useLocalizedWorkedDuration() {
|
|
686
|
+
const t = useT();
|
|
687
|
+
const locale = useOptionalLocale()?.locale ?? "en-US";
|
|
688
|
+
return useCallback((ms) => formatWorkedDuration(ms, {
|
|
689
|
+
locale,
|
|
690
|
+
hour: t("agentChat.duration.hourShort"),
|
|
691
|
+
minute: t("agentChat.duration.minuteShort"),
|
|
692
|
+
second: t("agentChat.duration.secondShort"),
|
|
693
|
+
}), [locale, t]);
|
|
660
694
|
}
|
|
661
695
|
export function WorkedForSummary({ durationMs, defaultOpen = false, autoCollapse = false, children, }) {
|
|
696
|
+
const t = useT();
|
|
697
|
+
const formatDuration = useLocalizedWorkedDuration();
|
|
662
698
|
// Ordinary completed work starts closed so a remount never flashes details
|
|
663
699
|
// while auto-collapse settles. Interactive UI opts into an open summary.
|
|
664
700
|
const [open, setOpen] = useState(defaultOpen);
|
|
@@ -671,13 +707,16 @@ export function WorkedForSummary({ durationMs, defaultOpen = false, autoCollapse
|
|
|
671
707
|
}
|
|
672
708
|
}, [autoCollapse, defaultOpen]);
|
|
673
709
|
const label = durationMs != null && durationMs >= 1000
|
|
674
|
-
?
|
|
675
|
-
|
|
710
|
+
? t("agentChat.tool.workedFor", {
|
|
711
|
+
duration: formatDuration(durationMs),
|
|
712
|
+
})
|
|
713
|
+
: t("agentChat.tool.worked");
|
|
676
714
|
return (_jsxs("div", { className: "my-1 w-full", children: [_jsxs("button", { type: "button", onClick: () => setOpen((v) => !v), "aria-expanded": open, className: "flex items-center gap-1.5 py-0.5 text-[13px] text-muted-foreground transition-colors hover:text-foreground", children: [_jsx("span", { children: label }), _jsx(IconChevronRight, { className: cn("size-3.5 shrink-0 transition-transform", open && "rotate-90") })] }), _jsx(AnimatedCollapse, { open: open, children: _jsx(WorkSummaryContentContext.Provider, { value: true, children: _jsx("div", { className: "pt-1", children: children }) }) })] }));
|
|
677
715
|
}
|
|
678
716
|
export function RanToolsSummary({ toolCount, motionKey = "summary", children, }) {
|
|
717
|
+
const t = useT();
|
|
679
718
|
const [open, setOpen] = useState(false);
|
|
680
|
-
const label =
|
|
719
|
+
const label = t("agentChat.tool.ranTools", { count: toolCount });
|
|
681
720
|
return (_jsxs("div", { className: "agent-tool-summary my-1 w-full", "data-agent-tool-summary": motionKey, children: [_jsxs("button", { type: "button", onClick: () => setOpen((v) => !v), "aria-expanded": open, className: "flex items-center gap-1.5 py-0.5 text-[13px] text-muted-foreground transition-colors hover:text-foreground", children: [_jsx("span", { className: "agent-tool-summary__label", children: label }), _jsx(IconChevronRight, { className: cn("size-3.5 shrink-0 transition-transform", open && "rotate-90") })] }), _jsx(AnimatedCollapse, { open: open, children: _jsx("div", { className: "pt-1", children: children }) })] }));
|
|
682
721
|
}
|
|
683
722
|
// ─── Re-export for AssistantMessage ───────────────────────────────────────────
|