@agent-native/core 0.172.10 → 0.173.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/README.md +1 -1
- package/corpus/templates/calendar/actions/view-screen.ts +0 -5
- package/corpus/templates/calendar/app/components/calendar/CommandPalette.tsx +1 -1
- package/corpus/templates/clips/app/components/player/video-player.tsx +3 -1
- package/corpus/templates/clips/changelog/2026-08-24-shared-clips-now-expose-agent-readable-transcript-and-frame-metadata-from-public-links.md +6 -0
- package/corpus/templates/clips/server/routes/[...page].get.ts +172 -3
- package/corpus/templates/plan/app/components/layout/Header.tsx +1 -1
- package/corpus/templates/plan/app/components/layout/Layout.tsx +19 -3
- package/corpus/templates/plan/app/components/layout/Sidebar.tsx +11 -10
- package/corpus/templates/plan/app/hooks/use-navigation-state.ts +10 -9
- package/corpus/templates/plan/app/pages/PlansPage.tsx +1 -1
- package/corpus/templates/plan/app/root.tsx +9 -8
- package/corpus/templates/plan/app/routes/_index.tsx +6 -30
- package/corpus/templates/plan/app/routes/chat.tsx +34 -0
- package/corpus/templates/plan/server/plugins/auth.ts +1 -0
- package/dist/client/AgentPanel.d.ts +3 -1
- package/dist/client/AgentPanel.js +67 -46
- package/dist/client/AssistantChat.d.ts +8 -0
- package/dist/client/AssistantChat.js +2 -1
- package/dist/client/agent-chat/index.d.ts +2 -0
- package/dist/client/agent-chat/index.js +2 -0
- package/dist/client/chat/index.d.ts +2 -0
- package/dist/client/chat/index.js +2 -0
- package/dist/client/chat/message-components.d.ts +5 -14
- package/dist/client/chat/message-components.js +15 -8
- package/dist/client/chat/tool-call-display.js +24 -11
- package/dist/client/thinking-display.d.ts +23 -0
- package/dist/client/thinking-display.js +86 -0
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/localization/core-messages/ar-SA.js +4 -0
- package/dist/localization/core-messages/de-DE.js +4 -0
- package/dist/localization/core-messages/en-US.d.ts +4 -0
- package/dist/localization/core-messages/en-US.js +4 -0
- package/dist/localization/core-messages/es-ES.js +4 -0
- package/dist/localization/core-messages/fr-FR.js +4 -0
- package/dist/localization/core-messages/hi-IN.js +4 -0
- package/dist/localization/core-messages/ja-JP.js +4 -0
- package/dist/localization/core-messages/ko-KR.js +4 -0
- package/dist/localization/core-messages/pt-BR.js +4 -0
- package/dist/localization/core-messages/zh-CN.js +4 -0
- package/dist/localization/core-messages/zh-TW.js +4 -0
- package/dist/localization/core-messages.d.ts +4 -0
- package/dist/observability/posthog-ai.d.ts +6 -0
- package/dist/observability/posthog-ai.js +6 -0
- package/dist/observability/routes.d.ts +3 -3
- package/dist/provider-api/actions/custom-provider-registration.d.ts +4 -4
- package/dist/provider-api/actions/provider-api.d.ts +8 -8
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/secrets/routes.d.ts +6 -6
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/shared/thinking-display.d.ts +23 -0
- package/dist/shared/thinking-display.js +31 -0
- package/dist/tracking/providers.js +22 -1
- package/package.json +3 -3
|
@@ -22,16 +22,17 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
|
|
|
22
22
|
* <AgentChatSurface mode="page" className="h-screen" />
|
|
23
23
|
*/
|
|
24
24
|
import { Tooltip as DesignSystemTooltip } from "@agent-native/toolkit/design-system";
|
|
25
|
-
import { IconMessageCircle, IconMessageDots, IconTerminal2, IconSettings, IconLayoutSidebarRightCollapse, IconLayoutGrid, IconCheck, IconPlus, IconX, IconDotsVertical, IconHistory, IconArrowsHorizontal, IconArrowsMaximize, IconExternalLink, IconShare3, } from "@tabler/icons-react";
|
|
25
|
+
import { IconMessageCircle, IconMessageDots, IconTerminal2, IconSettings, IconLayoutSidebarRightCollapse, IconLayoutGrid, IconCheck, IconPlus, IconX, IconDotsVertical, IconHistory, IconArrowsHorizontal, IconArrowsMaximize, IconExternalLink, IconShare3, IconBulb, } from "@tabler/icons-react";
|
|
26
26
|
import React, { useState, useEffect, useRef, useCallback, useMemo, lazy, Suspense, startTransition, } from "react";
|
|
27
27
|
import { flushSync } from "react-dom";
|
|
28
28
|
import { hostedHarnessAgentOption, isHostedHarnessConfigured, isHostedHarnessRuntime, normalizeHostedHarnessRuntimes, } from "../agent/harness/hosted.js";
|
|
29
|
-
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuTrigger, } from "./components/ui/dropdown-menu.js";
|
|
29
|
+
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, } from "./components/ui/dropdown-menu.js";
|
|
30
30
|
import { normalizeTooltipText } from "./components/ui/tooltip.js";
|
|
31
31
|
import { ErrorReportActions } from "./ErrorReportActions.js";
|
|
32
32
|
import { FeedbackButton, resolveFeedbackUrl } from "./FeedbackButton.js";
|
|
33
33
|
import { RunsTrayMenuItem } from "./progress/RunsTray.js";
|
|
34
34
|
import { ShareButton } from "./sharing/ShareButton.js";
|
|
35
|
+
import { ThinkingDisplayProvider, useThinkingDisplayControl, } from "./thinking-display.js";
|
|
35
36
|
// Lazy-load the full assistant-ui chat stack (tiptap composer + react-markdown +
|
|
36
37
|
// assistant-ui + zod block schemas) so it is NOT in the static import closure of
|
|
37
38
|
// every page. The header/tab chrome renders immediately; chat streams in once the
|
|
@@ -184,6 +185,26 @@ export function consumeAgentPanelOverlayFocusRestore(pendingOverlayRef, event) {
|
|
|
184
185
|
pendingOverlayRef.current = false;
|
|
185
186
|
event.preventDefault();
|
|
186
187
|
}
|
|
188
|
+
/**
|
|
189
|
+
* Reasoning visibility for this browser. Absent when a host pinned the mode
|
|
190
|
+
* through `thinkingDisplay`, so the menu never offers a control that cannot
|
|
191
|
+
* change anything.
|
|
192
|
+
*/
|
|
193
|
+
function ThinkingDisplayMenuItem() {
|
|
194
|
+
const t = useT();
|
|
195
|
+
const { mode, setMode, pinned } = useThinkingDisplayControl();
|
|
196
|
+
if (pinned)
|
|
197
|
+
return null;
|
|
198
|
+
return (_jsxs(DropdownMenuSub, { children: [_jsxs(DropdownMenuSubTrigger, { children: [_jsx(IconBulb, { size: 14, className: "shrink-0" }), t("agentChat.thinking.display")] }), _jsx(DropdownMenuSubContent, { children: _jsxs(DropdownMenuRadioGroup, { value: mode, onValueChange: (next) => {
|
|
199
|
+
// The radio group hands back a bare string; anything that is not a
|
|
200
|
+
// known mode would silently persist and read back as the default.
|
|
201
|
+
if (next === "expanded" ||
|
|
202
|
+
next === "collapsed" ||
|
|
203
|
+
next === "hidden") {
|
|
204
|
+
setMode(next);
|
|
205
|
+
}
|
|
206
|
+
}, children: [_jsx(DropdownMenuRadioItem, { value: "expanded", children: t("agentChat.thinking.expanded") }), _jsx(DropdownMenuRadioItem, { value: "collapsed", children: t("agentChat.thinking.collapsed") }), _jsx(DropdownMenuRadioItem, { value: "hidden", children: t("agentChat.thinking.hidden") })] }) })] }));
|
|
207
|
+
}
|
|
187
208
|
function useAvailableClis() {
|
|
188
209
|
const [clis, setClis] = useState([]);
|
|
189
210
|
useEffect(() => {
|
|
@@ -763,7 +784,7 @@ function AgentPanelInner({ defaultMode = "chat", className, style, apiUrl, empty
|
|
|
763
784
|
? t("agentPanel.hideChats")
|
|
764
785
|
: t("agentPanel.allChats")] })), mode === "chat" && (_jsx(RunsTrayMenuItem, { pollMs: 0, limit: 12, showRecent: true, onOpenThread: openRunThread })), mode === "chat" && _jsx(DropdownMenuSeparator, {}), mode === "cli" && availableClis.length > 0 && (_jsxs(_Fragment, { children: [availableClis.map((cli) => (_jsxs(DropdownMenuItem, { onSelect: () => selectCli(cli.command), className: cn(cli.command === selectedCli
|
|
765
786
|
? "font-medium"
|
|
766
|
-
: "text-muted-foreground"), children: [cli.command === selectedCli ? (_jsx(IconCheck, { size: 12, className: "shrink-0" })) : (_jsx("span", { className: "w-3" })), cli.label] }, cli.command))), _jsx(DropdownMenuSeparator, {})] })), allowSettingsMode && (_jsxs(DropdownMenuItem, { onSelect: () => switchMode("settings"), className: cn(mode === "settings" ? "font-medium" : "text-muted-foreground"), children: [_jsx(IconSettings, { size: 14, className: "shrink-0" }), t("agentPanel.settings")] })), feedbackEnabled ? (_jsxs(DropdownMenuItem, { onSelect: (event) => deferAgentPanelOverlayOpen(event, closeHeaderMenuForOverlay, () => setFeedbackOpen(true)), children: [_jsx(IconMessageDots, { size: 14, className: "shrink-0" }), t("agentPanel.feedback")] })) : null, ((mode === "chat" && activeTabId) ||
|
|
787
|
+
: "text-muted-foreground"), children: [cli.command === selectedCli ? (_jsx(IconCheck, { size: 12, className: "shrink-0" })) : (_jsx("span", { className: "w-3" })), cli.label] }, cli.command))), _jsx(DropdownMenuSeparator, {})] })), mode === "chat" && _jsx(ThinkingDisplayMenuItem, {}), allowSettingsMode && (_jsxs(DropdownMenuItem, { onSelect: () => switchMode("settings"), className: cn(mode === "settings" ? "font-medium" : "text-muted-foreground"), children: [_jsx(IconSettings, { size: 14, className: "shrink-0" }), t("agentPanel.settings")] })), feedbackEnabled ? (_jsxs(DropdownMenuItem, { onSelect: (event) => deferAgentPanelOverlayOpen(event, closeHeaderMenuForOverlay, () => setFeedbackOpen(true)), children: [_jsx(IconMessageDots, { size: 14, className: "shrink-0" }), t("agentPanel.feedback")] })) : null, ((mode === "chat" && activeTabId) ||
|
|
767
788
|
(mode === "cli" && canUseCodeTools && activeCliTab)) && (_jsxs(_Fragment, { children: [_jsx(DropdownMenuSeparator, {}), mode === "chat" ? (shouldShowAgentPanelChatTabBar(tabs, activeTabId) ? (_jsxs(_Fragment, { children: [_jsxs(DropdownMenuItem, { onSelect: () => closeTab(activeTabId), children: [_jsx(IconX, { size: 14, className: "shrink-0" }), t("agentPanel.closeTab"), _jsx(DropdownMenuShortcut, { children: closeTabHint })] }), _jsx(DropdownMenuItem, { onSelect: () => closeOtherTabs(activeTabId), children: t("agentPanel.closeOtherTabs") }), _jsxs(DropdownMenuItem, { onSelect: () => closeAllTabs(), children: [t("agentPanel.closeAllTabs"), _jsx(DropdownMenuShortcut, { children: closeAllTabsHint })] })] })) : (_jsxs(DropdownMenuItem, { onSelect: clearActiveTab, children: [_jsx(IconX, { size: 14, className: "shrink-0" }), t("agentPanel.clearChat")] }))) : (_jsxs(_Fragment, { children: [_jsxs(DropdownMenuItem, { onSelect: () => closeCliTab(activeCliTab), children: [_jsx(IconX, { size: 14, className: "shrink-0" }), t("agentPanel.closeTab"), _jsx(DropdownMenuShortcut, { children: closeTabHint })] }), _jsx(DropdownMenuItem, { onSelect: () => closeOtherCliTabs(activeCliTab), children: t("agentPanel.closeOtherTabs") }), _jsxs(DropdownMenuItem, { onSelect: () => closeAllCliTabs(), children: [t("agentPanel.closeAllTabs"), _jsx(DropdownMenuShortcut, { children: closeAllTabsHint })] })] }))] }))] })] }), onCollapse && (_jsx(IconTooltip, { content: t("agentPanel.collapseSidebar"), children: _jsx("button", { type: "button", onClick: onCollapse, "aria-label": t("agentPanel.collapseSidebar"), className: "flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:text-foreground hover:bg-accent/50", children: _jsx(IconX, { size: 14 }) }) }))] })), [
|
|
768
789
|
activeCliTab,
|
|
769
790
|
addCliTab,
|
|
@@ -961,47 +982,47 @@ function AgentPanelInner({ defaultMode = "chat", className, style, apiUrl, empty
|
|
|
961
982
|
closeCliTab,
|
|
962
983
|
t,
|
|
963
984
|
]);
|
|
964
|
-
return (_jsxs("div", { className: cn("agent-panel-root flex flex-1 flex-col min-h-0 h-full text-[13px] leading-[1.2] antialiased", className), style: {
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
985
|
+
return (_jsx(ThinkingDisplayProvider, { value: assistantChatProps.thinkingDisplay, children: _jsxs("div", { className: cn("agent-panel-root flex flex-1 flex-col min-h-0 h-full text-[13px] leading-[1.2] antialiased", className), style: {
|
|
986
|
+
...AGENT_PANEL_ROOT_STYLE,
|
|
987
|
+
...style,
|
|
988
|
+
// The chat view-transition container otherwise traps fixed onboarding
|
|
989
|
+
// chrome below the app's own header instead of the viewport edge.
|
|
990
|
+
...(isFirstRunOnboardingSurface ? { contain: "none" } : {}),
|
|
991
|
+
}, "data-agent-fullscreen": isFullscreen ? "true" : undefined, children: [_jsx("style", { dangerouslySetInnerHTML: {
|
|
992
|
+
__html: "@media (hover:hover) and (pointer:fine){" +
|
|
993
|
+
".agent-sidebar-chat-header[data-agent-sidebar-chat-header]{opacity:0;pointer-events:none;transition:opacity 150ms ease-out;}" +
|
|
994
|
+
".agent-panel-root:hover .agent-sidebar-chat-header[data-agent-sidebar-chat-header],.agent-panel-root:focus-within .agent-sidebar-chat-header[data-agent-sidebar-chat-header],.agent-sidebar-chat-header[data-agent-sidebar-chat-header][data-agent-sidebar-chat-header-active]{opacity:1;pointer-events:auto;}" +
|
|
995
|
+
".agent-sidebar-panel[data-agent-sidebar-per-app-chat='true'] .agent-sidebar-chat-header[data-agent-sidebar-chat-header]{opacity:1;pointer-events:auto;transition:none;}" +
|
|
996
|
+
"}" +
|
|
997
|
+
".agent-tab-close{opacity:0}.agent-tab:hover .agent-tab-close{opacity:1}" +
|
|
998
|
+
".agent-tabs-scroll{scrollbar-width:none;-ms-overflow-style:none;}" +
|
|
999
|
+
".agent-tabs-scroll::-webkit-scrollbar{display:none;}" +
|
|
1000
|
+
`[data-agent-fullscreen='true'] .agent-thread-content,` +
|
|
1001
|
+
`[data-agent-fullscreen='true'] .agent-running-activity{` +
|
|
1002
|
+
`max-width:${FULLSCREEN_CHAT_COLUMN_MAX_PX}px;` +
|
|
1003
|
+
`margin-left:auto;margin-right:auto;width:100%;}` +
|
|
1004
|
+
`[data-agent-fullscreen='true'] .agent-composer-area,` +
|
|
1005
|
+
`[data-agent-fullscreen='true'] .agent-plan-mode-callout{` +
|
|
1006
|
+
`max-width:${FULLSCREEN_CHAT_COLUMN_MAX_PX}px;` +
|
|
1007
|
+
`margin-left:auto;margin-right:auto;width:100%;}` +
|
|
1008
|
+
`[data-agent-fullscreen='true'] .agent-composer-area:not(.agent-composer-area--compact){` +
|
|
1009
|
+
`padding-left:0;padding-right:0;}` +
|
|
1010
|
+
`[data-agent-fullscreen='true'] .agent-mcp-connection-suggestion--composer,` +
|
|
1011
|
+
`[data-agent-fullscreen='true'] .agent-mcp-connection-suggestion-error--composer{` +
|
|
1012
|
+
`max-width:${FULLSCREEN_CHAT_COLUMN_MAX_PX}px;` +
|
|
1013
|
+
`margin-left:auto;margin-right:auto;width:100%;}`,
|
|
1014
|
+
} }), SHOW_ONBOARDING && mounted && (_jsx(Suspense, { fallback: null, children: _jsx(OnboardingPanel, {}) })), showFirstRunOnboarding && mounted && !insideAgentSidebar && (_jsx(Suspense, { fallback: null, children: _jsx(FirstRunOnboarding, {}) })), _jsx("div", { className: cn("flex flex-col min-h-0", mode === "chat" ? "flex-1" : "shrink-0"), children: mounted && (_jsx(Suspense, { fallback: _jsx(ChatLoadingSkeleton, { renderHeader: showHeader ? renderChatHeader : undefined, centerComposerWhenEmpty: assistantChatProps.centerComposerWhenEmpty, composerSlot: assistantChatProps.composerSlot, composerAreaClassName: assistantChatProps.composerAreaClassName, composerLayoutVariant: assistantChatProps.composerLayoutVariant }), children: _jsx(MultiTabAssistantChatLazy, { ...assistantChatProps, agentChatSurface: effectiveAgentChatSurface, apiUrl: apiUrl, showHeader: false, renderHeader: showHeader ? renderChatHeader : undefined, showTabBar: showTabBar, renderOverlay: showPageNewChatButton && !showHeader
|
|
1015
|
+
? renderPageChatOverlay
|
|
1016
|
+
: undefined, contentHidden: mode !== "chat", emptyStateText: emptyStateText, emptyStateAddon: emptyStateAddon, suggestions: suggestions, dynamicSuggestions: dynamicSuggestions, onSwitchToCli: () => switchMode("cli"), execMode: execMode, onExecModeChange: switchExecMode, storageKey: storageKey, restoreActiveThread: restoreActiveThread, scope: scope, isolateHistoryByScope: isolateHistoryByScope, showScopeBadge: showScopeBadge, browserTabId: browserTabId, threadUrlSync: threadUrlSync }) })) }), canUseCodeTools
|
|
1017
|
+
? mode === "cli" &&
|
|
1018
|
+
cliTabs.map((id) => (_jsx("div", { className: "min-h-0 relative flex-1", style: {
|
|
1019
|
+
display: id === activeCliTab ? undefined : "none",
|
|
1020
|
+
}, children: _jsx(Suspense, { fallback: _jsx("div", { className: "flex items-center justify-center h-full text-muted-foreground text-sm", children: t("agentPanel.loadingTerminal") }), children: _jsx(AgentTerminal, { command: selectedCli, hideInFrame: false, className: "h-full", style: { background: "transparent" } }) }) }, id)))
|
|
1021
|
+
: mode === "cli" && (_jsx("div", { className: "flex flex-1 flex-col items-center justify-center min-h-0 px-6 gap-3", children: _jsx(CodeAccessUnavailablePanel, { title: codeAccessEnabled
|
|
1022
|
+
? t("agentPanel.cliRequiresDevMode")
|
|
1023
|
+
: codeUnavailableTitle, description: codeAccessEnabled
|
|
1024
|
+
? t("agentPanel.cliRequiresDevModeDescription")
|
|
1025
|
+
: codeUnavailableDescription, ctaLabel: codeUnavailableCtaLabel, ctaHref: codeAccessEnabled ? undefined : codeUnavailableCtaHref, secondaryCtaLabel: codeUnavailableSecondaryCtaLabel, secondaryCtaHref: codeUnavailableSecondaryCtaHref }) })), mode === "resources" && (_jsx("div", { className: "flex flex-1 flex-col min-h-0", children: _jsx(Suspense, { fallback: _jsx("div", { className: "flex h-full flex-col min-h-0", children: _jsx("div", { className: "flex shrink-0 items-center justify-between border-b border-border px-2 py-1.5", children: _jsxs("div", { className: "flex items-center gap-1", children: [_jsx("div", { className: "h-5 w-16 rounded bg-muted animate-pulse" }), _jsx("div", { className: "h-5 w-14 rounded bg-muted animate-pulse" })] }) }) }), children: _jsx(ResourcesPanel, {}) }) })), mode === "settings" && (_jsx("div", { className: "flex flex-col flex-1 min-h-0", children: _jsx(Suspense, { fallback: _jsxs("div", { className: "p-3 space-y-2", children: [_jsx("div", { className: "h-10 w-full rounded-lg bg-muted animate-pulse" }), _jsx("div", { className: "h-10 w-full rounded-lg bg-muted animate-pulse" }), _jsx("div", { className: "h-10 w-full rounded-lg bg-muted animate-pulse" })] }), children: _jsx(SettingsPanel, { isDevMode: isDevMode, onToggleDevMode: () => setDevMode(!isDevMode), showDevToggle: showDevToggle, devAppUrl: devAppUrl, initialSection: settingsSection.section, sectionRequestKey: settingsSection.requestKey }) }) }))] }) }));
|
|
1005
1026
|
}
|
|
1006
1027
|
// ─── Resize handle ──────────────────────────────────────────────────────────
|
|
1007
1028
|
const SIDEBAR_STORAGE_KEY = "agent-native-sidebar-width";
|
|
@@ -1429,7 +1450,7 @@ export function AgentChatSurface({ mode = "panel", className, defaultMode = "cha
|
|
|
1429
1450
|
* Wraps app content with a toggleable agent sidebar.
|
|
1430
1451
|
* Use AgentToggleButton in your header to open/close it.
|
|
1431
1452
|
*/
|
|
1432
|
-
export function AgentSidebar({ children, enabled = true, emptyStateText = "How can I help you?", suggestions, dynamicSuggestions, composerToolbarSlot, composerSlot, onComposerTextChange, imageModelMenu, availableAgents, availableModels, modelListLoading, selectedAgent, onAgentChange, onConnectLocalRuntime, onConnectProvider, runtime, adapterReloadKey, threadFooterSlot, defaultSidebarWidth, sidebarWidth, position = "right", defaultOpen = false, animateMobile = true, animateDesktop = true, chatViewTransition = false, chatViewTransitionHandoff = false, storageKey, openStorageKey, restoreActiveThread = true, apiUrl, agentChatSurface, desktopIdentityUnauthenticated, desktopIdentityAuthenticated, showTabBar = true, suppressInlineOpenApp, composerPlaceholder, openOnChatRunning = false, onFullscreenRequest, scope, toggleScopeId, isolateHistoryByScope = false, showScopeBadge, browserTabId, threadUrlSync, agentPageHref, suppressFirstRunOnboarding = false, }) {
|
|
1453
|
+
export function AgentSidebar({ children, enabled = true, emptyStateText = "How can I help you?", suggestions, dynamicSuggestions, composerToolbarSlot, composerSlot, onComposerTextChange, imageModelMenu, availableAgents, availableModels, modelListLoading, selectedAgent, onAgentChange, onConnectLocalRuntime, onConnectProvider, runtime, adapterReloadKey, threadFooterSlot, defaultSidebarWidth, sidebarWidth, position = "right", defaultOpen = false, animateMobile = true, animateDesktop = true, chatViewTransition = false, chatViewTransitionHandoff = false, storageKey, openStorageKey, restoreActiveThread = true, apiUrl, agentChatSurface, desktopIdentityUnauthenticated, desktopIdentityAuthenticated, showTabBar = true, suppressInlineOpenApp, composerPlaceholder, openOnChatRunning = false, onFullscreenRequest, scope, toggleScopeId, isolateHistoryByScope = false, showScopeBadge, browserTabId, threadUrlSync, agentPageHref, suppressFirstRunOnboarding = false, thinkingDisplay, }) {
|
|
1433
1454
|
const staticHostedHarnessEnabled = isHostedHarnessConfigured(injectedAgentNativeConfig().harness);
|
|
1434
1455
|
const hostedHarnessQuery = useActionQuery("get-hosted-harness-config", undefined, { enabled: staticHostedHarnessEnabled });
|
|
1435
1456
|
const hostedHarnessStatus = hostedHarnessQuery.data;
|
|
@@ -2075,7 +2096,7 @@ export function AgentSidebar({ children, enabled = true, emptyStateText = "How c
|
|
|
2075
2096
|
? "desktop"
|
|
2076
2097
|
: undefined, "data-agent-sidebar-layout": panelLayout, "data-agent-sidebar-position": effectivePosition, "data-agent-native-hosted-harness-ui": hostedHarnessUi ? "desktop" : undefined, "data-agent-sidebar-state": panelOpen ? "open" : "closed", "data-agent-sidebar-per-app-chat": isPerAppChatSidebar ? "true" : undefined, "data-agent-sidebar-resizing": isResizing ? "true" : undefined, "data-agent-sidebar-chat-handoff": chatViewTransitionHandoff ? "true" : undefined, style: chatViewTransition
|
|
2077
2098
|
? getAgentChatViewTransitionStyle(panelStyle)
|
|
2078
|
-
: panelStyle, inert: sidebarAnimationEnabled && !panelOpen ? true : undefined, "aria-hidden": sidebarAnimationEnabled && !panelOpen ? true : undefined, children: _jsx("div", { className: "agent-sidebar-panel-inner flex min-h-0 flex-1 flex-col", children: _jsx(AgentPanel, { emptyStateText: emptyStateText, suggestions: suggestions, dynamicSuggestions: dynamicSuggestions, composerToolbarSlot: composerToolbarSlot, composerSlot: composerSlot, onComposerTextChange: onComposerTextChange, imageModelMenu: imageModelMenu, availableAgents: effectiveAvailableAgents, availableModels: availableModels, modelListLoading: modelListLoading, selectedAgent: effectiveSelectedAgent, onAgentChange: effectiveOnAgentChange, hostedHarness: hostedHarnessEnabled, onConnectProvider: onConnectProvider, onConnectLocalRuntime: onConnectLocalRuntime, runtime: runtime, adapterReloadKey: adapterReloadKey, threadFooterSlot: threadFooterSlot, apiUrl: apiUrl, agentChatSurface: agentChatSurface, desktopIdentityUnauthenticated: desktopIdentityUnauthenticated, desktopIdentityAuthenticated: desktopIdentityAuthenticated, showTabBar: effectiveShowTabBar, suppressInlineOpenApp: suppressInlineOpenApp, composerPlaceholder: composerPlaceholder, missingApiKeySetupLayout: "sidebar", onCollapse: () => setOpenPersisted(false), onSnapTo75Percent: isMobile ? undefined : snapTo75Percent, isWideDrawer: isMobile ? false : isWideDrawer, onExitWideDrawer: isMobile ? undefined : exitWideDrawer, onFullViewRequest: onFullscreenRequest, storageKey: storageKey, restoreActiveThread: restoreActiveThread, scope: scope, isolateHistoryByScope: isolateHistoryByScope, showScopeBadge: showScopeBadge, browserTabId: browserTabId, threadUrlSync: threadUrlSync, agentPageHref: agentPageHref, allowSettingsMode: false, chatOnly: true }) }) }), showResizeHandle && isLeft && (_jsx(ResizeHandle, { position: effectivePosition, onDrag: handleDrag, onResizeStart: handleResizeStart, onResizeEnd: handleResizeEnd }))] })) : null;
|
|
2099
|
+
: panelStyle, inert: sidebarAnimationEnabled && !panelOpen ? true : undefined, "aria-hidden": sidebarAnimationEnabled && !panelOpen ? true : undefined, children: _jsx("div", { className: "agent-sidebar-panel-inner flex min-h-0 flex-1 flex-col", children: _jsx(AgentPanel, { emptyStateText: emptyStateText, suggestions: suggestions, dynamicSuggestions: dynamicSuggestions, composerToolbarSlot: composerToolbarSlot, composerSlot: composerSlot, onComposerTextChange: onComposerTextChange, imageModelMenu: imageModelMenu, availableAgents: effectiveAvailableAgents, availableModels: availableModels, modelListLoading: modelListLoading, selectedAgent: effectiveSelectedAgent, onAgentChange: effectiveOnAgentChange, hostedHarness: hostedHarnessEnabled, onConnectProvider: onConnectProvider, onConnectLocalRuntime: onConnectLocalRuntime, runtime: runtime, adapterReloadKey: adapterReloadKey, threadFooterSlot: threadFooterSlot, apiUrl: apiUrl, agentChatSurface: agentChatSurface, desktopIdentityUnauthenticated: desktopIdentityUnauthenticated, desktopIdentityAuthenticated: desktopIdentityAuthenticated, showTabBar: effectiveShowTabBar, suppressInlineOpenApp: suppressInlineOpenApp, composerPlaceholder: composerPlaceholder, missingApiKeySetupLayout: "sidebar", onCollapse: () => setOpenPersisted(false), onSnapTo75Percent: isMobile ? undefined : snapTo75Percent, isWideDrawer: isMobile ? false : isWideDrawer, onExitWideDrawer: isMobile ? undefined : exitWideDrawer, onFullViewRequest: onFullscreenRequest, storageKey: storageKey, restoreActiveThread: restoreActiveThread, scope: scope, isolateHistoryByScope: isolateHistoryByScope, showScopeBadge: showScopeBadge, browserTabId: browserTabId, threadUrlSync: threadUrlSync, agentPageHref: agentPageHref, thinkingDisplay: thinkingDisplay, allowSettingsMode: false, chatOnly: true }) }) }), showResizeHandle && isLeft && (_jsx(ResizeHandle, { position: effectivePosition, onDrag: handleDrag, onResizeStart: handleResizeStart, onResizeEnd: handleResizeEnd }))] })) : null;
|
|
2079
2100
|
const drawerPlaceholder = wideDrawerEnabled && !presentationMode && panelOpen ? (_jsx("div", { "aria-hidden": "true", className: "agent-sidebar-drawer-placeholder shrink-0", "data-agent-sidebar-placeholder": "true", style: { width: drawerPlaceholderWidth + 1 } })) : null;
|
|
2080
2101
|
return (_jsx(AgentSidebarOnboardingContext.Provider, { value: true, children: _jsxs(RealtimeVoiceModeProvider, { browserTabId: browserTabId, children: [showFirstRunOnboarding && (_jsx(Suspense, { fallback: null, children: _jsx(FirstRunOnboarding, {}) })), _jsxs("div", { className: "agent-sidebar-shell flex min-w-0 flex-1 h-screen overflow-hidden", "data-agent-sidebar-position": effectivePosition, "data-agent-native-hosted-harness-ui": hostedHarnessUi ? "desktop" : undefined, "data-agent-native-hosted-chat": isPerAppChatHosted ? "true" : undefined, "data-agent-sidebar-resizing": isResizing ? "true" : undefined, children: [isMobile &&
|
|
2081
2102
|
!isPerAppChatHosted &&
|
|
@@ -2,6 +2,7 @@ import type { ComposerAgentOption, ComposerImageModelMenu } from "@agent-native/
|
|
|
2
2
|
import type { ChatModelAdapter, ExportedMessageRepository } from "@assistant-ui/react";
|
|
3
3
|
import React from "react";
|
|
4
4
|
import type { ReasoningEffort } from "../shared/reasoning-effort.js";
|
|
5
|
+
import type { ThinkingDisplay } from "../shared/thinking-display.js";
|
|
5
6
|
import { type AgentChatSurfaceKind } from "./agent-chat-adapter.js";
|
|
6
7
|
import { type AgentChatContextItem } from "./agent-chat.js";
|
|
7
8
|
import { type QueuedAttachment } from "./chat/attachment-adapters.js";
|
|
@@ -447,6 +448,13 @@ export interface AssistantChatProps {
|
|
|
447
448
|
onAlwaysAllow?: (approvalKey: string, toolName: string) => void | Promise<void>;
|
|
448
449
|
alwaysAllowScope?: "action" | "exact-command";
|
|
449
450
|
};
|
|
451
|
+
/**
|
|
452
|
+
* Pin how much model reasoning this chat shows: "expanded" opens the live
|
|
453
|
+
* cell, "collapsed" keeps it one click away, "hidden" renders none. Omit to
|
|
454
|
+
* let the reader's own preference apply, which is what surfaces the in-chat
|
|
455
|
+
* control — a pinned mode hides it rather than leaving a dead menu item.
|
|
456
|
+
*/
|
|
457
|
+
thinkingDisplay?: ThinkingDisplay;
|
|
450
458
|
}
|
|
451
459
|
export declare function shouldShowAssistantChatModelSelector(showModelSelector: boolean | undefined): boolean;
|
|
452
460
|
export declare const CHAT_STORAGE_PREFIX = "agent-chat:";
|
|
@@ -38,6 +38,7 @@ import { addMcpConnectionCompleteListener, consumeMcpConnectionResume, } from ".
|
|
|
38
38
|
import { McpConnectionSuggestion } from "./resources/McpConnectionSuggestion.js";
|
|
39
39
|
import { claimRunStream, createRunStreamToken, ownsRunStream, releaseRunStream, } from "./run-stream-ownership.js";
|
|
40
40
|
import { AgentAutoContinueSignal, readSSEStreamRaw, settleInterruptedToolCalls, } from "./sse-event-processor.js";
|
|
41
|
+
import { ThinkingDisplayProvider } from "./thinking-display.js";
|
|
41
42
|
import { callAction } from "./use-action.js";
|
|
42
43
|
import { useAgentEngineConfigured } from "./use-agent-engine-configured.js";
|
|
43
44
|
import { appendChatThreadScopeParams, } from "./use-chat-threads.js";
|
|
@@ -4519,5 +4520,5 @@ export const AssistantChat = forwardRef(function AssistantChat({ apiUrl = agentN
|
|
|
4519
4520
|
const runtime = useLocalRuntime(adapter, {
|
|
4520
4521
|
adapters: { attachments: attachmentAdapter },
|
|
4521
4522
|
});
|
|
4522
|
-
return (_jsx(AssistantRuntimeProvider, { runtime: runtime, children: _jsx(TooltipProvider, { delayDuration: 200, children: _jsx(ThreadPrimitive.Root, { className: "flex flex-1 flex-col h-full min-h-0 overflow-x-hidden", children: _jsx(AssistantUiStaleIndexErrorBoundary, { resetKey: `${tabId ?? ""}:${threadId ?? ""}`, componentName: "AssistantChat", children: _jsx(AssistantChatInner, { ref: ref, ...props, browserTabId: browserTabId, contextScope: contextScope, contextNamespace: contextNamespace, isActiveComposer: isActiveComposer, apiUrl: apiUrl, tabId: tabId, threadId: threadId }) }) }) }) }));
|
|
4523
|
+
return (_jsx(AssistantRuntimeProvider, { runtime: runtime, children: _jsx(ThinkingDisplayProvider, { value: props.thinkingDisplay, children: _jsx(TooltipProvider, { delayDuration: 200, children: _jsx(ThreadPrimitive.Root, { className: "flex flex-1 flex-col h-full min-h-0 overflow-x-hidden", children: _jsx(AssistantUiStaleIndexErrorBoundary, { resetKey: `${tabId ?? ""}:${threadId ?? ""}`, componentName: "AssistantChat", children: _jsx(AssistantChatInner, { ref: ref, ...props, browserTabId: browserTabId, contextScope: contextScope, contextNamespace: contextNamespace, isActiveComposer: isActiveComposer, apiUrl: apiUrl, tabId: tabId, threadId: threadId }) }) }) }) }) }));
|
|
4523
4524
|
});
|
|
@@ -42,3 +42,5 @@ export { clearReservedToolRenderersForTests, clearToolRenderersForTests, registe
|
|
|
42
42
|
export * from "../chat/connectors.js";
|
|
43
43
|
export * from "../chat/runtime.js";
|
|
44
44
|
export { CHAT_FIRST_APP_LAYOUT_STORAGE_KEY, CHAT_FIRST_DEFAULT_APP_IDS, CHAT_FIRST_SURFACE_TABS_STORAGE_KEY, CHAT_FIRST_SURFACE_PANEL_STORAGE_KEY, CHAT_FIRST_SURFACE_WIDTH_DEFAULT, CHAT_FIRST_SURFACE_WIDTH_MIN, clampChatFirstSurfaceWidth, CHAT_FIRST_MODE_STORAGE_KEY, CHAT_FIRST_MODE_CHANGED_EVENT, CHAT_FIRST_OPEN_APP_EVENT, CHAT_FIRST_OPEN_BROWSER_EVENT, CHAT_FIRST_WATCH_SESSION_EVENT, CHAT_FIRST_SURFACE_CATALOG, chatFirstSurfaceTabId, closeChatFirstSessionWatch, emitChatFirstOpenApp, emitChatFirstOpenBrowser, emitChatFirstSessionWatch, getChatFirstSessionWatchStore, getChatFirstSurfaceTabsStore, getChatFirstSurfacePanelStore, orderChatFirstAppIds, readChatFirstAppLayout, resolveChatFirstAppTarget, resolveChatFirstBrowserTarget, resolveChatFirstSessionId, normalizeChatFirstSessionReference, readChatFirstMode, readChatFirstModeState, readChatFirstSurfaceWidth, subscribeChatFirstOpenApp, subscribeChatFirstOpenBrowser, subscribeChatFirstSessionWatch, useChatFirstSessionWatch, useChatFirstSurfaceResize, useChatFirstSurfacePanel, useChatFirstSurfaceTabs, writeChatFirstAppLayout, writeChatFirstMode, writeChatFirstSurfaceWidth, type ChatFirstAppLayoutPreference, type ChatFirstModeReadResult, type ChatFirstAppRegistration, type ChatFirstAppResolution, type ChatFirstAppTarget, type ChatFirstAppSurfacePlacement, type ChatFirstAgentActivity, type ChatFirstAgentActivityStatus, type ChatFirstOpenAppDelivery, type ChatFirstOpenAppDetail, type ChatFirstOpenBrowserDetail, type ChatFirstBrowserResolution, type ChatFirstSessionKind, type ChatFirstSessionReference, type ChatFirstSessionWatchDelivery, type ChatFirstSessionWatchState, type ChatFirstSessionWatchStore, type ChatFirstSurfaceKind, type ChatFirstSurfaceTab, type ChatFirstSurfacePanelState, type ChatFirstSurfacePanelStore, type ChatFirstSurfaceTabsState, type ChatFirstSurfaceTabsStore, } from "../chat-first.js";
|
|
45
|
+
export { ThinkingDisplayProvider, getBrowserThinkingDisplay, setBrowserThinkingDisplay, subscribeToBrowserThinkingDisplay, useThinkingDisplay, useThinkingDisplayControl, } from "../thinking-display.js";
|
|
46
|
+
export { DEFAULT_THINKING_DISPLAY, THINKING_DISPLAY_MODES, isThinkingDisplay, type ThinkingDisplay, } from "../../shared/thinking-display.js";
|
|
@@ -41,3 +41,5 @@ export { clearReservedToolRenderersForTests, clearToolRenderersForTests, registe
|
|
|
41
41
|
export * from "../chat/connectors.js";
|
|
42
42
|
export * from "../chat/runtime.js";
|
|
43
43
|
export { CHAT_FIRST_APP_LAYOUT_STORAGE_KEY, CHAT_FIRST_DEFAULT_APP_IDS, CHAT_FIRST_SURFACE_TABS_STORAGE_KEY, CHAT_FIRST_SURFACE_PANEL_STORAGE_KEY, CHAT_FIRST_SURFACE_WIDTH_DEFAULT, CHAT_FIRST_SURFACE_WIDTH_MIN, clampChatFirstSurfaceWidth, CHAT_FIRST_MODE_STORAGE_KEY, CHAT_FIRST_MODE_CHANGED_EVENT, CHAT_FIRST_OPEN_APP_EVENT, CHAT_FIRST_OPEN_BROWSER_EVENT, CHAT_FIRST_WATCH_SESSION_EVENT, CHAT_FIRST_SURFACE_CATALOG, chatFirstSurfaceTabId, closeChatFirstSessionWatch, emitChatFirstOpenApp, emitChatFirstOpenBrowser, emitChatFirstSessionWatch, getChatFirstSessionWatchStore, getChatFirstSurfaceTabsStore, getChatFirstSurfacePanelStore, orderChatFirstAppIds, readChatFirstAppLayout, resolveChatFirstAppTarget, resolveChatFirstBrowserTarget, resolveChatFirstSessionId, normalizeChatFirstSessionReference, readChatFirstMode, readChatFirstModeState, readChatFirstSurfaceWidth, subscribeChatFirstOpenApp, subscribeChatFirstOpenBrowser, subscribeChatFirstSessionWatch, useChatFirstSessionWatch, useChatFirstSurfaceResize, useChatFirstSurfacePanel, useChatFirstSurfaceTabs, writeChatFirstAppLayout, writeChatFirstMode, writeChatFirstSurfaceWidth, } from "../chat-first.js";
|
|
44
|
+
export { ThinkingDisplayProvider, getBrowserThinkingDisplay, setBrowserThinkingDisplay, subscribeToBrowserThinkingDisplay, useThinkingDisplay, useThinkingDisplayControl, } from "../thinking-display.js";
|
|
45
|
+
export { DEFAULT_THINKING_DISPLAY, THINKING_DISPLAY_MODES, isThinkingDisplay, } from "../../shared/thinking-display.js";
|
|
@@ -20,3 +20,5 @@ export { useChatModels, type UseChatModelsResult, type EngineModelGroup, } from
|
|
|
20
20
|
export { useChatThreads, type ChatThreadScope, type ChatThreadSnapshot, type ChatThreadSummary, type ChatThreadData, type ChatThreadShareLink, type ChatThreadShareState, type UseChatThreadsOptions, } from "../use-chat-threads.js";
|
|
21
21
|
export { ChatHistoryList, type ChatHistoryItem, type ChatHistorySection, type ChatHistoryListProps, } from "./ChatHistoryList.js";
|
|
22
22
|
export * from "../conversation/index.js";
|
|
23
|
+
export { ThinkingDisplayProvider, getBrowserThinkingDisplay, setBrowserThinkingDisplay, subscribeToBrowserThinkingDisplay, useThinkingDisplay, useThinkingDisplayControl, } from "../thinking-display.js";
|
|
24
|
+
export { DEFAULT_THINKING_DISPLAY, THINKING_DISPLAY_MODES, isThinkingDisplay, type ThinkingDisplay, } from "../../shared/thinking-display.js";
|
|
@@ -20,3 +20,5 @@ export { useChatModels, } from "../use-chat-models.js";
|
|
|
20
20
|
export { useChatThreads, } from "../use-chat-threads.js";
|
|
21
21
|
export { ChatHistoryList, } from "./ChatHistoryList.js";
|
|
22
22
|
export * from "../conversation/index.js";
|
|
23
|
+
export { ThinkingDisplayProvider, getBrowserThinkingDisplay, setBrowserThinkingDisplay, subscribeToBrowserThinkingDisplay, useThinkingDisplay, useThinkingDisplayControl, } from "../thinking-display.js";
|
|
24
|
+
export { DEFAULT_THINKING_DISPLAY, THINKING_DISPLAY_MODES, isThinkingDisplay, } from "../../shared/thinking-display.js";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
+
import { type ThinkingDisplay } from "../../shared/thinking-display.js";
|
|
2
3
|
import type { ContentPart } from "../sse-event-processor.js";
|
|
3
4
|
import { type RunErrorInfo } from "./run-recovery.js";
|
|
4
5
|
import { toolCallHasPendingApproval } from "./tool-call-display.js";
|
|
@@ -145,7 +146,7 @@ export declare function isCollapsibleAssistantWorkPart(part: {
|
|
|
145
146
|
approvalKey?: string;
|
|
146
147
|
dismissed?: boolean;
|
|
147
148
|
};
|
|
148
|
-
}): boolean;
|
|
149
|
+
}, thinkingDisplay?: ThinkingDisplay): boolean;
|
|
149
150
|
export declare function getAssistantToolSummaryInfo(parts: readonly {
|
|
150
151
|
type?: string;
|
|
151
152
|
toolCallId?: string;
|
|
@@ -161,18 +162,7 @@ export declare function getAssistantToolSummaryInfo(parts: readonly {
|
|
|
161
162
|
startIndex: number;
|
|
162
163
|
hiddenToolCount: number;
|
|
163
164
|
};
|
|
164
|
-
export
|
|
165
|
-
type?: string;
|
|
166
|
-
toolCallId?: string;
|
|
167
|
-
toolName?: string;
|
|
168
|
-
args?: Record<string, unknown>;
|
|
169
|
-
chatUI?: unknown;
|
|
170
|
-
mcpApp?: unknown;
|
|
171
|
-
approval?: {
|
|
172
|
-
approvalKey?: string;
|
|
173
|
-
dismissed?: boolean;
|
|
174
|
-
};
|
|
175
|
-
}, index: number, parts: readonly {
|
|
165
|
+
export interface AssistantWorkPart {
|
|
176
166
|
type?: string;
|
|
177
167
|
toolCallId?: string;
|
|
178
168
|
toolName?: string;
|
|
@@ -183,7 +173,8 @@ export declare function groupAssistantWorkParts(part: {
|
|
|
183
173
|
approvalKey?: string;
|
|
184
174
|
dismissed?: boolean;
|
|
185
175
|
};
|
|
186
|
-
}
|
|
176
|
+
}
|
|
177
|
+
export declare function groupAssistantWorkParts(part: AssistantWorkPart, index: number, parts: readonly AssistantWorkPart[], thinkingDisplay?: ThinkingDisplay): ["group-work"] | null;
|
|
187
178
|
export declare function shouldShowInlineRunError({ runError, bannerRunErrorKey, }: {
|
|
188
179
|
runError: RunErrorInfo | null;
|
|
189
180
|
bannerRunErrorKey: string | null | undefined;
|
|
@@ -8,6 +8,7 @@ import { PastedTextChip } from "@agent-native/toolkit/composer/PastedTextChip";
|
|
|
8
8
|
import { useThreadRuntime, useMessageRuntime, useComposer, MessagePrimitive, ActionBarPrimitive, BranchPickerPrimitive, ComposerPrimitive, useMessagePartReasoning, useMessagePartRuntime, useAuiState, } from "@assistant-ui/react";
|
|
9
9
|
import { IconX, IconCheck, IconCopy, IconChevronDown, IconChevronLeft, IconChevronRight, IconDots, IconGitFork, IconId, IconQuote, IconRefresh, IconArrowBackUp, IconFile, IconFolder, IconFileText, IconCheckbox, IconMail, IconUser, IconPresentation, IconStack2, IconMessageChatbot, IconPencil, IconAlertTriangle, IconLoader2, } from "@tabler/icons-react";
|
|
10
10
|
import React, { useState, useEffect, useCallback, useRef } from "react";
|
|
11
|
+
import { DEFAULT_THINKING_DISPLAY, } from "../../shared/thinking-display.js";
|
|
11
12
|
import { getActiveRun } from "../active-run-state.js";
|
|
12
13
|
import { agentNativePath } from "../api-path.js";
|
|
13
14
|
import { writeClipboardText } from "../clipboard.js";
|
|
@@ -18,6 +19,7 @@ import { localizeKnownChatErrorText } from "../error-format.js";
|
|
|
18
19
|
import { DEFAULT_LOCALE, useFormatters, useOptionalLocale, useT, } from "../i18n.js";
|
|
19
20
|
import { ThumbsFeedback } from "../observability/ThumbsFeedback.js";
|
|
20
21
|
import { McpConnectionSuggestion } from "../resources/McpConnectionSuggestion.js";
|
|
22
|
+
import { useThinkingDisplay } from "../thinking-display.js";
|
|
21
23
|
import { isCallAgentToolCallShadowed, isToolCallActive, shadowedCallAgentToolCallIds, } from "../tool-display.js";
|
|
22
24
|
import { cn } from "../utils.js";
|
|
23
25
|
import { MarkdownText, renderMarkdownToClipboardHtml, SmoothMarkdownText, } from "./markdown-renderer.js";
|
|
@@ -795,9 +797,11 @@ export function isAlwaysVisibleAssistantTool(part) {
|
|
|
795
797
|
typeof part.toolName === "string" &&
|
|
796
798
|
ALWAYS_VISIBLE_ASSISTANT_TOOLS.has(part.toolName));
|
|
797
799
|
}
|
|
798
|
-
export function isCollapsibleAssistantWorkPart(part) {
|
|
800
|
+
export function isCollapsibleAssistantWorkPart(part, thinkingDisplay = DEFAULT_THINKING_DISPLAY) {
|
|
801
|
+
// Hidden reasoning renders nothing, so counting it as work would wrap a
|
|
802
|
+
// reasoning-only turn in an empty "Worked for…" disclosure.
|
|
799
803
|
if (part.type === "reasoning")
|
|
800
|
-
return
|
|
804
|
+
return thinkingDisplay !== "hidden";
|
|
801
805
|
return (part.type === "tool-call" &&
|
|
802
806
|
!isAlwaysVisibleAssistantTool(part) &&
|
|
803
807
|
part.chatUI === undefined &&
|
|
@@ -825,16 +829,17 @@ export function getAssistantToolSummaryInfo(parts) {
|
|
|
825
829
|
hiddenToolCount: toolCallIndices.length - ASSISTANT_VISIBLE_TOOL_CALL_LIMIT,
|
|
826
830
|
};
|
|
827
831
|
}
|
|
828
|
-
export function groupAssistantWorkParts(part, index, parts) {
|
|
832
|
+
export function groupAssistantWorkParts(part, index, parts, thinkingDisplay = DEFAULT_THINKING_DISPLAY) {
|
|
829
833
|
if (isCallAgentToolCallShadowed(parts, index)) {
|
|
830
834
|
const previousPart = parts[index - 1];
|
|
831
835
|
const previousPartIsInWorkGroup = previousPart != null &&
|
|
832
|
-
(isCollapsibleAssistantWorkPart(previousPart) ||
|
|
836
|
+
(isCollapsibleAssistantWorkPart(previousPart, thinkingDisplay) ||
|
|
833
837
|
isCallAgentToolCallShadowed(parts, index - 1));
|
|
834
838
|
return previousPartIsInWorkGroup ? ["group-work"] : null;
|
|
835
839
|
}
|
|
836
|
-
if (isCollapsibleAssistantWorkPart(part))
|
|
840
|
+
if (isCollapsibleAssistantWorkPart(part, thinkingDisplay)) {
|
|
837
841
|
return ["group-work"];
|
|
842
|
+
}
|
|
838
843
|
return null;
|
|
839
844
|
}
|
|
840
845
|
export function shouldShowInlineRunError({ runError, bannerRunErrorKey, }) {
|
|
@@ -882,6 +887,8 @@ export function AssistantMessage() {
|
|
|
882
887
|
const messageTurnId = assistantMessageTurnId(msg);
|
|
883
888
|
const userStoppedRun = React.useContext(UserStoppedRunContext);
|
|
884
889
|
const isUserStoppedRun = assistantMessageWasUserStopped(msg) || userStoppedRun(messageRunId);
|
|
890
|
+
const thinkingDisplay = useThinkingDisplay();
|
|
891
|
+
const groupWorkParts = useCallback((part, index, parts) => groupAssistantWorkParts(part, index, parts, thinkingDisplay), [thinkingDisplay]);
|
|
885
892
|
const hasRenderableContent = assistantMessageHasRenderableContent(msg);
|
|
886
893
|
const hasUnresolvedTool = assistantMessageHasUnresolvedTool(msg.content);
|
|
887
894
|
const hasActiveTool = assistantMessageHasActiveTool(msg.content);
|
|
@@ -1066,11 +1073,11 @@ export function AssistantMessage() {
|
|
|
1066
1073
|
const hasCollapsibleWork = Array.isArray(msgContent) &&
|
|
1067
1074
|
msgContent.some((p, index) => !isCallAgentToolCallShadowed(msgContent, index) &&
|
|
1068
1075
|
(p.type !== "tool-call" || p.activity !== true) &&
|
|
1069
|
-
isCollapsibleAssistantWorkPart(p));
|
|
1076
|
+
isCollapsibleAssistantWorkPart(p, thinkingDisplay));
|
|
1070
1077
|
const firstWorkPartIndex = Array.isArray(msgContent)
|
|
1071
1078
|
? msgContent.findIndex((p, index) => !isCallAgentToolCallShadowed(msgContent, index) &&
|
|
1072
1079
|
(p.type !== "tool-call" || p.activity !== true) &&
|
|
1073
|
-
isCollapsibleAssistantWorkPart(p))
|
|
1080
|
+
isCollapsibleAssistantWorkPart(p, thinkingDisplay))
|
|
1074
1081
|
: -1;
|
|
1075
1082
|
const shadowedToolCallIds = Array.isArray(msgContent)
|
|
1076
1083
|
? shadowedCallAgentToolCallIds(msgContent)
|
|
@@ -1081,7 +1088,7 @@ export function AssistantMessage() {
|
|
|
1081
1088
|
});
|
|
1082
1089
|
if (!hasRenderableContent || isMissingCredential)
|
|
1083
1090
|
return null;
|
|
1084
|
-
return (_jsxs("div", { className: "group relative", style: { contentVisibility: isComplete ? "auto" : "visible" }, children: [_jsxs("div", { className: "w-full max-w-[95%] text-sm leading-relaxed text-foreground", children: [isComplete && (_jsx(McpConnectionSuggestion, { text: responseConnectionText, contextText: responseConnectionContext, variant: "response" })), _jsx(ToolCallStackMotion, { children: _jsx(MessagePrimitive.GroupedParts, { groupBy:
|
|
1091
|
+
return (_jsxs("div", { className: "group relative", style: { contentVisibility: isComplete ? "auto" : "visible" }, children: [_jsxs("div", { className: "w-full max-w-[95%] text-sm leading-relaxed text-foreground", children: [isComplete && (_jsx(McpConnectionSuggestion, { text: responseConnectionText, contextText: responseConnectionContext, variant: "response" })), _jsx(ToolCallStackMotion, { children: _jsx(MessagePrimitive.GroupedParts, { groupBy: groupWorkParts, children: ({ part, children }) => {
|
|
1085
1092
|
switch (part.type) {
|
|
1086
1093
|
case "group-work": {
|
|
1087
1094
|
const showSummary = shouldShowAssistantWorkSummary({
|
|
@@ -12,6 +12,7 @@ import { useOptionalLocale, useT } from "../i18n.js";
|
|
|
12
12
|
import { McpAppRenderer } from "../mcp-apps/McpAppRenderer.js";
|
|
13
13
|
import { findMcpIntegrationForToolName } from "../resources/mcp-integration-catalog.js";
|
|
14
14
|
import { McpIntegrationLogo } from "../resources/McpIntegrationLogo.js";
|
|
15
|
+
import { useThinkingDisplay } from "../thinking-display.js";
|
|
15
16
|
import { BashCell, EditCell, WriteCell, FilesChangedSummary, } from "../tool-cells/index.js";
|
|
16
17
|
import { humanizeToolName, isCallAgentToolCallShadowed, isToolCallActive, } from "../tool-display.js";
|
|
17
18
|
import { useAgentChatContext } from "../use-agent-chat-context.js";
|
|
@@ -644,22 +645,26 @@ function isReconnectToolSummaryPart(content, index, startIndex) {
|
|
|
644
645
|
// ─── Reasoning / Thinking cell ────────────────────────────────────────────────
|
|
645
646
|
/**
|
|
646
647
|
* Completed reasoning and tool calls share one outer "Worked for…"
|
|
647
|
-
* disclosure.
|
|
648
|
-
*
|
|
648
|
+
* disclosure. Inside it a reasoning cell keeps its own disclosure — the tool
|
|
649
|
+
* calls it sits between are collapsible there, and reasoning that could not be
|
|
650
|
+
* collapsed was the longest thing in an opened summary by far.
|
|
649
651
|
*/
|
|
650
652
|
const WorkSummaryContentContext = React.createContext(false);
|
|
651
653
|
export function ReasoningCell({ text, isStreaming = false, defaultOpen, autoCollapse = false, collapseWhenReplaced = false, durationMs, }) {
|
|
652
654
|
const t = useT();
|
|
653
655
|
const formatDuration = useLocalizedWorkedDuration();
|
|
656
|
+
const display = useThinkingDisplay();
|
|
654
657
|
const embeddedInWorkSummary = React.useContext(WorkSummaryContentContext);
|
|
655
|
-
|
|
658
|
+
// Only "expanded" honours a caller's request to start open. "collapsed"
|
|
659
|
+
// keeps every cell shut until the reader asks for it, which is the point of
|
|
660
|
+
// the mode — a live cell that opens itself is what pushes the answer off
|
|
661
|
+
// screen mid-turn.
|
|
662
|
+
const startOpen = display === "expanded" ? (defaultOpen ?? true) : false;
|
|
663
|
+
const [open, setOpen] = useState(startOpen);
|
|
656
664
|
const wasStreamingRef = useRef(isStreaming);
|
|
657
665
|
const wasReplacedRef = useRef(collapseWhenReplaced);
|
|
666
|
+
const previousDisplayRef = useRef(display);
|
|
658
667
|
const trimmed = text.trim();
|
|
659
|
-
// Reasoning is already a compact live status surface. Rendering the latest
|
|
660
|
-
// chunk directly avoids a second character-level queue that can lag behind
|
|
661
|
-
// the model and make the surrounding chat look like it is jumping.
|
|
662
|
-
const visibleText = trimmed;
|
|
663
668
|
useEffect(() => {
|
|
664
669
|
if (autoCollapse && wasStreamingRef.current && !isStreaming) {
|
|
665
670
|
setOpen(false);
|
|
@@ -672,11 +677,19 @@ export function ReasoningCell({ text, isStreaming = false, defaultOpen, autoColl
|
|
|
672
677
|
}
|
|
673
678
|
wasReplacedRef.current = collapseWhenReplaced;
|
|
674
679
|
}, [collapseWhenReplaced]);
|
|
680
|
+
// Switching the preference re-applies it to cells already on screen, so the
|
|
681
|
+
// change is visible on the turn the reader is looking at rather than only on
|
|
682
|
+
// the next one.
|
|
683
|
+
useEffect(() => {
|
|
684
|
+
if (previousDisplayRef.current === display)
|
|
685
|
+
return;
|
|
686
|
+
previousDisplayRef.current = display;
|
|
687
|
+
setOpen(startOpen);
|
|
688
|
+
}, [display, startOpen]);
|
|
689
|
+
if (display === "hidden")
|
|
690
|
+
return null;
|
|
675
691
|
if (!trimmed && !isStreaming)
|
|
676
692
|
return null;
|
|
677
|
-
if (embeddedInWorkSummary) {
|
|
678
|
-
return (_jsx("div", { className: "pb-1 pl-5 text-[13px] leading-relaxed text-muted-foreground whitespace-pre-wrap", children: visibleText || (isStreaming ? "…" : "") }));
|
|
679
|
-
}
|
|
680
693
|
const label = isStreaming
|
|
681
694
|
? t("agentChat.status.thinking")
|
|
682
695
|
: durationMs != null
|
|
@@ -687,7 +700,7 @@ export function ReasoningCell({ text, isStreaming = false, defaultOpen, autoColl
|
|
|
687
700
|
// Only clamp to a scroll-free "tail" view while actively streaming and
|
|
688
701
|
// expanded — once the run finishes the full text is shown, unclamped.
|
|
689
702
|
const showTail = isStreaming && open;
|
|
690
|
-
return (_jsxs("div", { className: "my-0.5
|
|
703
|
+
return (_jsxs("div", { className: cn("w-full", embeddedInWorkSummary ? "my-0" : "my-0.5"), 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("ps-5 pb-1", showTail && "reasoning-cell-tail"), children: trimmed ? (_jsx("div", { className: "agent-reasoning-markdown text-[13px] leading-relaxed text-muted-foreground", children: _jsx(SmoothMarkdownText, { text: trimmed, streaming: isStreaming, animateStreaming: false, resetKey: "reasoning", statusType: isStreaming ? "running" : "complete" }) })) : (_jsx("div", { className: "text-[13px] leading-relaxed text-muted-foreground", children: isStreaming ? "…" : "" })) }) })] }));
|
|
691
704
|
}
|
|
692
705
|
// ─── Worked-for duration helpers ──────────────────────────────────────────────
|
|
693
706
|
export function formatWorkedDuration(ms, options = {}) {
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** Browser-local reasoning-visibility preference for the chat surface.
|
|
2
|
+
*
|
|
3
|
+
* Presentation only, and deliberately device-local: it must not reach the
|
|
4
|
+
* agent, application state, or the engine's reasoning-effort request.
|
|
5
|
+
*/
|
|
6
|
+
import type { ReactNode } from "react";
|
|
7
|
+
import { type ThinkingDisplay } from "../shared/thinking-display.js";
|
|
8
|
+
export declare const THINKING_DISPLAY_STORAGE_KEY = "agent-native:thinking-display";
|
|
9
|
+
export declare function getBrowserThinkingDisplay(): ThinkingDisplay;
|
|
10
|
+
export declare function setBrowserThinkingDisplay(mode: ThinkingDisplay): void;
|
|
11
|
+
export declare function subscribeToBrowserThinkingDisplay(callback: () => void): () => void;
|
|
12
|
+
export declare function ThinkingDisplayProvider({ value, children, }: {
|
|
13
|
+
value?: ThinkingDisplay;
|
|
14
|
+
children: ReactNode;
|
|
15
|
+
}): import("react").JSX.Element;
|
|
16
|
+
export declare function useThinkingDisplay(): ThinkingDisplay;
|
|
17
|
+
/** Reads and writes the preference for the in-chat control. */
|
|
18
|
+
export declare function useThinkingDisplayControl(): {
|
|
19
|
+
mode: ThinkingDisplay;
|
|
20
|
+
setMode: (mode: ThinkingDisplay) => void;
|
|
21
|
+
/** True when a host prop pins the mode, so no control should be offered. */
|
|
22
|
+
pinned: boolean;
|
|
23
|
+
};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/** Browser-local reasoning-visibility preference for the chat surface.
|
|
3
|
+
*
|
|
4
|
+
* Presentation only, and deliberately device-local: it must not reach the
|
|
5
|
+
* agent, application state, or the engine's reasoning-effort request.
|
|
6
|
+
*/
|
|
7
|
+
import { createContext, useCallback, useContext, useSyncExternalStore, } from "react";
|
|
8
|
+
import { DEFAULT_THINKING_DISPLAY, parseThinkingDisplay, } from "../shared/thinking-display.js";
|
|
9
|
+
export const THINKING_DISPLAY_STORAGE_KEY = "agent-native:thinking-display";
|
|
10
|
+
const THINKING_DISPLAY_CHANGE_EVENT = "agent-native:thinking-display-change";
|
|
11
|
+
export function getBrowserThinkingDisplay() {
|
|
12
|
+
if (typeof window === "undefined")
|
|
13
|
+
return DEFAULT_THINKING_DISPLAY;
|
|
14
|
+
try {
|
|
15
|
+
return (parseThinkingDisplay(window.localStorage.getItem(THINKING_DISPLAY_STORAGE_KEY)) ?? DEFAULT_THINKING_DISPLAY);
|
|
16
|
+
// A blocked or unavailable localStorage means "no stored preference",
|
|
17
|
+
// which is exactly the default. Nothing downstream can act on the
|
|
18
|
+
// difference, and throwing would break the whole chat header.
|
|
19
|
+
// coercion-ok: absent and unreadable are the same answer for this key.
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return DEFAULT_THINKING_DISPLAY;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export function setBrowserThinkingDisplay(mode) {
|
|
26
|
+
if (typeof window === "undefined")
|
|
27
|
+
return;
|
|
28
|
+
try {
|
|
29
|
+
if (mode === DEFAULT_THINKING_DISPLAY) {
|
|
30
|
+
window.localStorage.removeItem(THINKING_DISPLAY_STORAGE_KEY);
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
window.localStorage.setItem(THINKING_DISPLAY_STORAGE_KEY, mode);
|
|
34
|
+
}
|
|
35
|
+
// A failed write leaves the in-memory listeners correct for this tab,
|
|
36
|
+
// which is the whole visible effect of the change.
|
|
37
|
+
// coercion-ok: an unwritable localStorage is not a preference failure.
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
// Intentionally empty: the change event below still updates this tab.
|
|
41
|
+
}
|
|
42
|
+
window.dispatchEvent(new Event(THINKING_DISPLAY_CHANGE_EVENT));
|
|
43
|
+
}
|
|
44
|
+
export function subscribeToBrowserThinkingDisplay(callback) {
|
|
45
|
+
if (typeof window === "undefined")
|
|
46
|
+
return () => undefined;
|
|
47
|
+
const onStorage = (event) => {
|
|
48
|
+
if (event.key === THINKING_DISPLAY_STORAGE_KEY || event.key === null) {
|
|
49
|
+
callback();
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
const onChange = () => callback();
|
|
53
|
+
window.addEventListener("storage", onStorage);
|
|
54
|
+
window.addEventListener(THINKING_DISPLAY_CHANGE_EVENT, onChange);
|
|
55
|
+
return () => {
|
|
56
|
+
window.removeEventListener("storage", onStorage);
|
|
57
|
+
window.removeEventListener(THINKING_DISPLAY_CHANGE_EVENT, onChange);
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* A host-supplied mode. When set it wins over the stored preference and the
|
|
62
|
+
* in-chat control disappears, so a host that pins the mode does not leave a
|
|
63
|
+
* menu item that silently does nothing.
|
|
64
|
+
*/
|
|
65
|
+
const ThinkingDisplayContext = createContext(undefined);
|
|
66
|
+
export function ThinkingDisplayProvider({ value, children, }) {
|
|
67
|
+
// Inherit rather than clear: a chat surface nested inside a host that pinned
|
|
68
|
+
// the mode renders this provider too, and passing its own absent prop
|
|
69
|
+
// straight through would silently un-pin the host's choice.
|
|
70
|
+
const inherited = useContext(ThinkingDisplayContext);
|
|
71
|
+
return (_jsx(ThinkingDisplayContext.Provider, { value: value ?? inherited, children: children }));
|
|
72
|
+
}
|
|
73
|
+
export function useThinkingDisplay() {
|
|
74
|
+
const pinned = useContext(ThinkingDisplayContext);
|
|
75
|
+
const stored = useSyncExternalStore(subscribeToBrowserThinkingDisplay, getBrowserThinkingDisplay, () => DEFAULT_THINKING_DISPLAY);
|
|
76
|
+
return pinned ?? stored;
|
|
77
|
+
}
|
|
78
|
+
/** Reads and writes the preference for the in-chat control. */
|
|
79
|
+
export function useThinkingDisplayControl() {
|
|
80
|
+
const pinned = useContext(ThinkingDisplayContext);
|
|
81
|
+
const mode = useThinkingDisplay();
|
|
82
|
+
const setMode = useCallback((next) => {
|
|
83
|
+
setBrowserThinkingDisplay(next);
|
|
84
|
+
}, []);
|
|
85
|
+
return { mode, setMode, pinned: pinned !== undefined };
|
|
86
|
+
}
|