Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
654 lines
23 KiB
TypeScript
654 lines
23 KiB
TypeScript
import { memo, useCallback, useMemo, useRef } from "react";
|
|
import { createWorkspaceUserProjectI18nRuntime } from "@tutti-os/workspace-user-project/i18n";
|
|
import { createWorkspaceFileManagerI18nRuntime } from "@tutti-os/workspace-file-manager";
|
|
import type { WorkspaceFileReference } from "@tutti-os/workspace-file-reference/contracts";
|
|
import { useTranslation } from "../../i18n/index";
|
|
import type { WorkspaceLinkAction } from "../../actions/workspaceLinkActions";
|
|
import type { AgentGUIAgentTarget, AgentGUINodeData } from "../../types";
|
|
import { resolveCanonicalNodeMinSize } from "../../utils/workspaceNodeSizing";
|
|
import { WorkspaceNodeWindow } from "../shared/WorkspaceNodeWindow";
|
|
import { CanvasNodeGhostIconButton } from "../shared/CanvasNodeGhostIconButton";
|
|
import { CanvasNodePanelLinedIcon } from "../shared/canvasNodeChromeIcons";
|
|
import { useAgentGUINodeController } from "./controller/useAgentGUINodeController";
|
|
import { useAgentGUIStatus } from "./controller/useAgentGUIStatus";
|
|
import { agentTargetForConversation } from "./controller/agentGuiController.providerHelpers";
|
|
import { AgentGUINodeView } from "./AgentGUINodeView";
|
|
import {
|
|
normalizeAgentGUIProviderIdentity,
|
|
resolveAgentGUIProviderDisplayLabel
|
|
} from "./model/agentGuiProviderIdentity";
|
|
import { AgentProbeInfoPopover } from "../workspaceDesktop/view/AgentProbeInfoPopover";
|
|
import styles from "./AgentGUINode.styles";
|
|
import {
|
|
AGENT_GUI_COLLAPSED_MIN_WIDTH_PX,
|
|
AGENT_GUI_CONVERSATION_RAIL_MIN_WIDTH_PX,
|
|
AGENT_GUI_DETAIL_MIN_WIDTH_PX,
|
|
clampAgentGUIConversationRailWidthPx,
|
|
resolveAgentGUIConversationRailPresentation,
|
|
resolveAgentGUIExpandedWindowFrame,
|
|
resolveNextAgentGUIConversationRailWidthPx,
|
|
resolveAgentGUIConversationRailMaxWidthPx
|
|
} from "./model/agentGuiRailLayout";
|
|
import type {
|
|
AgentGUIAgentConfigMenuContext,
|
|
AgentGUINodeProps
|
|
} from "./AgentGUINode.types";
|
|
import { areAgentGUINodePropsEqual } from "./AgentGUINode.types";
|
|
import { AgentGUIMentionServiceBoundary } from "./AgentGUIMentionServiceBoundary";
|
|
import {
|
|
useAgentGUIViewLabels,
|
|
useAgentGUIConversationRailLabels,
|
|
useAgentGUIWorkspaceFileReferenceCopy
|
|
} from "./AgentGUINode.labels";
|
|
import { useAgentMentionProvenanceFilters } from "./composer/useAgentMentionProvenanceFilters";
|
|
|
|
export type { AgentGUINodeProps } from "./AgentGUINode.types";
|
|
|
|
export const AgentGUINode = memo(function AgentGUINode({
|
|
identity,
|
|
workspace,
|
|
frame,
|
|
state,
|
|
runtimeRequests,
|
|
hostCapabilities,
|
|
hostActions,
|
|
renderSlots
|
|
}: AgentGUINodeProps): React.JSX.Element {
|
|
"use memo";
|
|
const { nodeId, workspaceId, currentUserId, title } = identity;
|
|
const {
|
|
path: workspacePath,
|
|
fileReferenceAdapter: workspaceFileReferenceAdapter = null,
|
|
onRequestGitBranches = null,
|
|
selectProjectDirectory,
|
|
resolveExternalPromptEntries = null,
|
|
prepareExternalPromptFiles = null,
|
|
resolvePastedPath = null,
|
|
promptAssetLimit = null,
|
|
projectDirectorySourceAggregator = null,
|
|
referenceSourceAggregator = null,
|
|
resolveReferenceContentErrorAction:
|
|
resolveWorkspaceReferenceContentErrorAction,
|
|
resolveReferenceEntryIconUrl: resolveWorkspaceReferenceEntryIconUrl,
|
|
resolveMentionReferenceTarget = null,
|
|
resolveReferenceInitialTarget:
|
|
resolveWorkspaceReferenceInitialTarget = null,
|
|
onFileReferencesAdded: onWorkspaceFileReferencesAdded,
|
|
agentSettings
|
|
} = workspace;
|
|
const {
|
|
position,
|
|
width,
|
|
height,
|
|
desktopSize,
|
|
isMaximized = false,
|
|
isActive,
|
|
isVisible = true,
|
|
embedded = false
|
|
} = frame;
|
|
const widthRef = useRef(width);
|
|
widthRef.current = width;
|
|
const {
|
|
composerAppend: composerAppendRequest = null,
|
|
composerFocusSequence: composerFocusRequestSequence = null,
|
|
workbench: workbenchCommandBridge = null,
|
|
openSession: openSessionRequest = null,
|
|
prefillPrompt: prefillPromptRequest = null,
|
|
agentStatusController
|
|
} = runtimeRequests;
|
|
const {
|
|
capabilityMenuState,
|
|
capabilityControlsReadOnly = false,
|
|
agentTargets,
|
|
agentTargetsLoading = false,
|
|
mentionAgentTargets,
|
|
handoffAgentTargets,
|
|
handoffAgentTargetsLoading = false,
|
|
showHandoffTargetOwnershipLabels = false,
|
|
providerRailAllPresentation = null,
|
|
providerRailMode = "catalog",
|
|
comingSoonProviders,
|
|
providerReadinessGates = null,
|
|
accountUsageRefreshInline = false,
|
|
targetConnectionSource = null,
|
|
interactionReadinessSource = null,
|
|
observationGapSource = null,
|
|
defaultAgentTargetId = null,
|
|
providerAuthAccountLabels,
|
|
mentionService,
|
|
workspaceAppIcons,
|
|
hiddenMentionFilterIds,
|
|
disabledHomeSuggestions,
|
|
referenceProvenanceFilterCatalog: injectedReferenceProvenanceFilterCatalog,
|
|
referenceProvenanceFilterEnabled = false,
|
|
sessionInputHistoryEnabled = false,
|
|
sideConversationEnabled = false,
|
|
sideConversationPresentation = null,
|
|
sessionWorktreeEnabled = false,
|
|
sessionLaunchModesByProjectSectionKey,
|
|
codexSaverModeEntryEnabled = false,
|
|
rtkSaverModeEntryEnabled = false
|
|
} = hostCapabilities;
|
|
const referenceProvenanceFilters = useAgentMentionProvenanceFilters({
|
|
agentTargets,
|
|
injectedCatalog: injectedReferenceProvenanceFilterCatalog,
|
|
legacyAgentFilterEnabled: referenceProvenanceFilterEnabled
|
|
});
|
|
const {
|
|
onComposerAppendHandled,
|
|
onLinkAction,
|
|
onHandoffConversation,
|
|
onCapabilitySettingsRequest,
|
|
onAgentProviderLogin,
|
|
onAgentEnvPanelOpen,
|
|
onAgentConfigMenuOpen: onHostAgentConfigMenuOpen,
|
|
onOpenConversationWindow,
|
|
onClose,
|
|
onResize,
|
|
onUpdateNode,
|
|
onRememberComposerDefaults,
|
|
onSessionLaunchModePreferenceChange,
|
|
isMuted = false,
|
|
onMinimize,
|
|
onToggleMaximize,
|
|
onShowMessage,
|
|
onEngagementEvent,
|
|
onConversationRailLayoutChange
|
|
} = hostActions;
|
|
const {
|
|
agentConfigAccount: renderAgentConfigAccount,
|
|
agentConfigSystemActions: renderAgentConfigSystemActions,
|
|
agentTargetInfo: renderAgentTargetInfo,
|
|
composerFooterAccessory: renderComposerFooterAccessory,
|
|
projectDirectoryPickerHeaderActions:
|
|
renderProjectDirectoryPickerHeaderActions,
|
|
projectSelectOptions,
|
|
referencePickerSidebarActions: renderReferencePickerSidebarActions,
|
|
providerRailEmpty: renderProviderRailEmpty,
|
|
sidebarFooter: renderSidebarFooter
|
|
} = renderSlots;
|
|
const { i18n, locale, t } = useTranslation();
|
|
const workspaceUserProjectI18n = useMemo(
|
|
() => createWorkspaceUserProjectI18nRuntime(i18n),
|
|
[i18n]
|
|
);
|
|
const workspaceFileManagerI18n = useMemo(
|
|
() =>
|
|
typeof i18n?.t === "function"
|
|
? createWorkspaceFileManagerI18nRuntime(i18n)
|
|
: null,
|
|
[i18n]
|
|
);
|
|
const handleLinkAction = useCallback(
|
|
(action: WorkspaceLinkAction) => {
|
|
onLinkAction?.(action);
|
|
},
|
|
[onLinkAction]
|
|
);
|
|
const handleAgentProviderLogin = useCallback(
|
|
(provider?: string | null) => {
|
|
const resolvedProvider = normalizeAgentGUIProviderIdentity(provider);
|
|
onAgentProviderLogin?.(
|
|
resolvedProvider === "unknown" ? state.provider : resolvedProvider
|
|
);
|
|
},
|
|
[onAgentProviderLogin, state.provider]
|
|
);
|
|
const handleWorkspaceFileReferencesAdded = useCallback(
|
|
(references: readonly WorkspaceFileReference[]) => {
|
|
onWorkspaceFileReferencesAdded?.({
|
|
provider: state.provider,
|
|
references
|
|
});
|
|
},
|
|
[onWorkspaceFileReferencesAdded, state.provider]
|
|
);
|
|
const handleDataChange = useCallback(
|
|
(updater: (current: AgentGUINodeData) => AgentGUINodeData) => {
|
|
onUpdateNode(updater);
|
|
},
|
|
[onUpdateNode]
|
|
);
|
|
const handleConversationRailWidthChanged = useCallback(
|
|
(widthPx: number) => {
|
|
onUpdateNode((current) => {
|
|
const nextWidthPx = resolveNextAgentGUIConversationRailWidthPx({
|
|
currentWidthPx: current.conversationRailWidthPx,
|
|
requestedWidthPx: widthPx,
|
|
containerWidthPx: widthRef.current
|
|
});
|
|
|
|
if (current.conversationRailWidthPx === nextWidthPx) {
|
|
return current;
|
|
}
|
|
return {
|
|
...current,
|
|
conversationRailWidthPx: nextWidthPx
|
|
};
|
|
});
|
|
},
|
|
[onUpdateNode]
|
|
);
|
|
const conversationRailPresentation =
|
|
resolveAgentGUIConversationRailPresentation({
|
|
autoCollapseMode: frame.conversationRailAutoCollapseMode,
|
|
containerWidthPx: width,
|
|
conversationRailCollapsed: state.conversationRailCollapsed,
|
|
conversationRailWidthPx: state.conversationRailWidthPx
|
|
});
|
|
const isConversationRailAutoCollapsed =
|
|
conversationRailPresentation.isAutoCollapsed;
|
|
const isConversationRailCollapsed = conversationRailPresentation.isCollapsed;
|
|
const minSize = useMemo(
|
|
() => ({
|
|
...resolveCanonicalNodeMinSize("agentGui"),
|
|
width: AGENT_GUI_COLLAPSED_MIN_WIDTH_PX
|
|
}),
|
|
[]
|
|
);
|
|
const toggleConversationRailCollapsed = useCallback(() => {
|
|
onUpdateNode((current) => ({
|
|
...current,
|
|
conversationRailCollapsed: current.conversationRailCollapsed !== true
|
|
}));
|
|
}, [onUpdateNode]);
|
|
const handleConversationRailToggle = useCallback(() => {
|
|
if (!isConversationRailAutoCollapsed) {
|
|
toggleConversationRailCollapsed();
|
|
return;
|
|
}
|
|
|
|
onResize(
|
|
resolveAgentGUIExpandedWindowFrame({
|
|
position,
|
|
width,
|
|
height,
|
|
desktopSize,
|
|
conversationRailWidthPx: state.conversationRailWidthPx
|
|
})
|
|
);
|
|
onUpdateNode((current) => {
|
|
if (current.conversationRailCollapsed !== true) {
|
|
return current;
|
|
}
|
|
return {
|
|
...current,
|
|
conversationRailCollapsed: false
|
|
};
|
|
});
|
|
}, [
|
|
desktopSize,
|
|
height,
|
|
isConversationRailAutoCollapsed,
|
|
onResize,
|
|
onUpdateNode,
|
|
position,
|
|
state.conversationRailWidthPx,
|
|
toggleConversationRailCollapsed,
|
|
width
|
|
]);
|
|
const { viewModel, actions } = useAgentGUINodeController({
|
|
nodeId,
|
|
isSurfaceActive: isActive,
|
|
isSurfaceVisible: isVisible,
|
|
workspaceId,
|
|
currentUserId,
|
|
workspacePath,
|
|
avoidGroupingEdits: agentSettings.avoidGroupingEdits,
|
|
data: state,
|
|
composerAppendRequest,
|
|
openSessionRequest,
|
|
prefillPromptRequest,
|
|
codexSaverModeEntryEnabled,
|
|
rtkSaverModeEntryEnabled,
|
|
agentTargets,
|
|
agentTargetsLoading,
|
|
handoffAgentTargets,
|
|
handoffAgentTargetsLoading,
|
|
providerRailMode,
|
|
comingSoonProviders,
|
|
providerReadinessGates,
|
|
targetConnectionSource,
|
|
interactionReadinessSource,
|
|
observationGapSource,
|
|
defaultAgentTargetId,
|
|
onDataChange: handleDataChange,
|
|
onComposerAppendHandled,
|
|
onRememberComposerDefaults,
|
|
onShowMessage
|
|
});
|
|
const handleCreateConversation = useCallback(
|
|
(...args: Parameters<typeof actions.createConversation>) => {
|
|
{
|
|
onUpdateNode((current) =>
|
|
current.lastActiveAgentSessionId === null
|
|
? current
|
|
: {
|
|
...current,
|
|
lastActiveAgentSessionId: null
|
|
}
|
|
);
|
|
}
|
|
actions.createConversation(...args);
|
|
},
|
|
[actions, onUpdateNode]
|
|
);
|
|
const viewActions = useMemo(
|
|
() => ({
|
|
...actions,
|
|
createConversation: handleCreateConversation
|
|
}),
|
|
[actions, handleCreateConversation]
|
|
);
|
|
|
|
const fallbackAgentTitle = t("sidebar.fallbackAgentLabel");
|
|
const activeProvider =
|
|
viewModel.rail.activeConversation?.provider ?? state.provider;
|
|
const activeConversationAgentTarget = agentTargetForConversation(
|
|
viewModel.rail.activeConversation,
|
|
viewModel.rail.agentTargets
|
|
);
|
|
const displayProviderLabel = resolveAgentGUIProviderDisplayLabel(
|
|
activeProvider,
|
|
fallbackAgentTitle,
|
|
viewModel.rail.activeConversation
|
|
? activeConversationAgentTarget?.label
|
|
: viewModel.rail.selectedAgentTarget?.label
|
|
);
|
|
const conversationRailLabels = useAgentGUIConversationRailLabels(t);
|
|
const labels = useAgentGUIViewLabels({
|
|
disabledHomeSuggestions,
|
|
displayProviderLabel,
|
|
fallbackAgentTitle,
|
|
t,
|
|
workspaceAppIcons: workspaceAppIcons ?? [],
|
|
workspaceId
|
|
});
|
|
const workspaceFileReferenceCopy = useAgentGUIWorkspaceFileReferenceCopy(t);
|
|
const windowTitle = title;
|
|
const {
|
|
agentProbeLines,
|
|
controllerRailStatus,
|
|
handleAgentConfigMenuClose,
|
|
handleAgentConfigMenuOpen: handleStatusAgentConfigMenuOpen,
|
|
handleAgentProbeInfoClose,
|
|
handleAgentProbeInfoOpen,
|
|
handleAgentUsageRefresh,
|
|
handleSlashStatusClose,
|
|
handleSlashStatusOpen,
|
|
handleSlashStatusRefresh,
|
|
railStatusProvider,
|
|
slashStatusLimits,
|
|
slashStatusLimitsUnavailable,
|
|
slashStatusOverride
|
|
} = useAgentGUIStatus({
|
|
activeProvider,
|
|
agentStatusController,
|
|
t,
|
|
viewModel
|
|
});
|
|
const effectiveProviderAuthAccountLabels = projectProviderAccountLabel(
|
|
providerAuthAccountLabels,
|
|
railStatusProvider,
|
|
controllerRailStatus?.accountLabel
|
|
);
|
|
const agentConfigMenuContext =
|
|
viewModel.rail.conversationFilter.kind === "all"
|
|
? null
|
|
: resolveAgentConfigMenuContext(viewModel.rail.selectedAgentTarget);
|
|
const handleAgentConfigMenuOpen = () => {
|
|
handleStatusAgentConfigMenuOpen();
|
|
if (agentConfigMenuContext) {
|
|
onHostAgentConfigMenuOpen?.(agentConfigMenuContext);
|
|
}
|
|
};
|
|
const agentConfigAccountContent = agentConfigMenuContext
|
|
? (renderAgentConfigAccount?.(agentConfigMenuContext) ?? null)
|
|
: null;
|
|
const agentConfigSystemActionsContent =
|
|
renderAgentConfigSystemActions?.({ presentation: "menu" }) ?? null;
|
|
|
|
return (
|
|
<AgentGUIMentionServiceBoundary
|
|
service={mentionService}
|
|
observationGapSource={observationGapSource}
|
|
>
|
|
<WorkspaceNodeWindow
|
|
nodeId={nodeId}
|
|
kind="agentGui"
|
|
title={windowTitle}
|
|
titleIcon={null}
|
|
position={position}
|
|
width={width}
|
|
height={height}
|
|
desktopSize={desktopSize}
|
|
minSize={minSize}
|
|
appearance={embedded ? "embedded" : "window"}
|
|
className="size-full bg-transparent"
|
|
bodyClassName={`${styles.shell} nodrag size-full min-h-0 min-w-0 !bg-transparent p-0`}
|
|
hideHeader={embedded}
|
|
titleAccessory={
|
|
<span className="inline-flex flex-none items-center gap-1">
|
|
<AgentProbeInfoPopover
|
|
lines={agentProbeLines}
|
|
testId="agent-gui-window-agent-info"
|
|
className={styles.windowAgentInfo}
|
|
onOpen={handleAgentProbeInfoOpen}
|
|
onClose={handleAgentProbeInfoClose}
|
|
/>
|
|
<CanvasNodeGhostIconButton
|
|
aria-label={
|
|
isConversationRailCollapsed
|
|
? t("agentHost.agentGui.expandConversationRail")
|
|
: t("agentHost.agentGui.collapseConversationRail")
|
|
}
|
|
title={
|
|
isConversationRailCollapsed
|
|
? t("agentHost.agentGui.expandConversationRail")
|
|
: t("agentHost.agentGui.collapseConversationRail")
|
|
}
|
|
data-testid="agent-gui-toggle-conversation-rail"
|
|
data-agent-gui-conversation-rail-collapsed={
|
|
isConversationRailCollapsed ? "true" : "false"
|
|
}
|
|
data-agent-gui-conversation-rail-auto-collapsed={
|
|
isConversationRailAutoCollapsed ? "true" : "false"
|
|
}
|
|
onClick={(event) => {
|
|
event.stopPropagation();
|
|
handleConversationRailToggle();
|
|
}}
|
|
>
|
|
<CanvasNodePanelLinedIcon
|
|
width={18}
|
|
height={18}
|
|
aria-hidden="true"
|
|
/>
|
|
</CanvasNodeGhostIconButton>
|
|
</span>
|
|
}
|
|
onClose={onClose}
|
|
onResize={onResize}
|
|
isMaximized={isMaximized}
|
|
isMuted={isMuted}
|
|
hideMaximizeButton
|
|
onMinimize={onMinimize}
|
|
onToggleMaximize={onToggleMaximize}
|
|
>
|
|
{(renderFrame) => {
|
|
const renderedWidth = renderFrame.size.width;
|
|
const isRenderedConversationRailCollapsed =
|
|
isConversationRailCollapsed ||
|
|
resolveAgentGUIConversationRailPresentation({
|
|
autoCollapseMode: frame.conversationRailAutoCollapseMode,
|
|
containerWidthPx: renderedWidth,
|
|
conversationRailCollapsed: state.conversationRailCollapsed,
|
|
conversationRailWidthPx: state.conversationRailWidthPx
|
|
}).isCollapsed;
|
|
|
|
return (
|
|
<AgentGUINodeView
|
|
viewModel={viewModel}
|
|
mentionAgentTargets={mentionAgentTargets}
|
|
hiddenMentionFilterIds={hiddenMentionFilterIds}
|
|
renderAgentTargetInfo={renderAgentTargetInfo}
|
|
renderSidebarFooter={renderSidebarFooter}
|
|
renderProviderRailEmpty={renderProviderRailEmpty}
|
|
providerRailAllPresentation={providerRailAllPresentation}
|
|
actions={viewActions}
|
|
isActive={isActive}
|
|
isVisible={isVisible}
|
|
onEngagementEvent={onEngagementEvent}
|
|
composerFocusRequestSequence={composerFocusRequestSequence}
|
|
workbenchCommandBridge={workbenchCommandBridge}
|
|
slashStatusLimits={slashStatusLimits}
|
|
slashStatusLimitsLoading={controllerRailStatus?.loading ?? false}
|
|
slashStatusLimitsUnavailable={slashStatusLimitsUnavailable}
|
|
slashStatusOverride={slashStatusOverride}
|
|
railConfigProvider={railStatusProvider}
|
|
railSlashStatusLimits={controllerRailStatus?.limits ?? []}
|
|
slashStatusUsageCapturedAtUnixMs={
|
|
controllerRailStatus?.capturedAtUnixMs ?? null
|
|
}
|
|
slashStatusUsageDidFail={controllerRailStatus?.didFail ?? false}
|
|
slashStatusUsageErrorMessage={
|
|
controllerRailStatus?.errorMessage ?? null
|
|
}
|
|
slashStatusUsageAttempted={
|
|
controllerRailStatus?.attempted ?? false
|
|
}
|
|
slashStatusLimitsResolvedEmpty={
|
|
controllerRailStatus?.resolvedEmpty ?? false
|
|
}
|
|
agentConfigAccountContent={agentConfigAccountContent}
|
|
agentConfigSystemActionsContent={agentConfigSystemActionsContent}
|
|
providerAuthAccountLabels={effectiveProviderAuthAccountLabels}
|
|
onAgentConfigMenuClose={handleAgentConfigMenuClose}
|
|
onAgentConfigMenuOpen={handleAgentConfigMenuOpen}
|
|
onAgentUsageRefresh={handleAgentUsageRefresh}
|
|
accountUsageRefreshInline={accountUsageRefreshInline}
|
|
onSlashStatusOpen={handleSlashStatusOpen}
|
|
onSlashStatusClose={handleSlashStatusClose}
|
|
onSlashStatusRefresh={handleSlashStatusRefresh}
|
|
onLinkAction={handleLinkAction}
|
|
onHandoffConversation={onHandoffConversation}
|
|
showHandoffTargetOwnershipLabels={
|
|
showHandoffTargetOwnershipLabels
|
|
}
|
|
capabilityMenuState={capabilityMenuState}
|
|
capabilityControlsReadOnly={capabilityControlsReadOnly}
|
|
onCapabilitySettingsRequest={onCapabilitySettingsRequest}
|
|
onAgentProviderLogin={
|
|
onAgentProviderLogin ? handleAgentProviderLogin : undefined
|
|
}
|
|
onAgentEnvPanelOpen={onAgentEnvPanelOpen}
|
|
conversationRailCollapsed={isRenderedConversationRailCollapsed}
|
|
conversationRailWidthPx={clampAgentGUIConversationRailWidthPx(
|
|
state.conversationRailWidthPx,
|
|
renderedWidth
|
|
)}
|
|
conversationRailMinWidthPx={
|
|
AGENT_GUI_CONVERSATION_RAIL_MIN_WIDTH_PX
|
|
}
|
|
conversationRailMaxWidthPx={resolveAgentGUIConversationRailMaxWidthPx(
|
|
renderedWidth
|
|
)}
|
|
detailMinWidthPx={AGENT_GUI_DETAIL_MIN_WIDTH_PX}
|
|
uiLanguage={locale}
|
|
onWorkspaceFileReferencesAdded={
|
|
onWorkspaceFileReferencesAdded
|
|
? handleWorkspaceFileReferencesAdded
|
|
: undefined
|
|
}
|
|
resolveExternalPromptEntries={resolveExternalPromptEntries}
|
|
prepareExternalPromptFiles={prepareExternalPromptFiles}
|
|
resolvePastedPath={resolvePastedPath}
|
|
promptAssetLimit={promptAssetLimit}
|
|
onConversationRailWidthChanged={
|
|
handleConversationRailWidthChanged
|
|
}
|
|
onConversationRailLayoutChange={onConversationRailLayoutChange}
|
|
labels={labels}
|
|
conversationRailLabels={conversationRailLabels}
|
|
workspaceUserProjectI18n={workspaceUserProjectI18n}
|
|
workspaceFileManagerCopy={workspaceFileManagerI18n}
|
|
workspaceFileReferenceAdapter={workspaceFileReferenceAdapter}
|
|
onOpenConversationWindow={onOpenConversationWindow}
|
|
onRequestGitBranches={onRequestGitBranches}
|
|
selectProjectDirectory={selectProjectDirectory}
|
|
projectDirectorySourceAggregator={
|
|
projectDirectorySourceAggregator
|
|
}
|
|
referenceSourceAggregator={referenceSourceAggregator}
|
|
resolveReferenceContentErrorAction={
|
|
resolveWorkspaceReferenceContentErrorAction
|
|
}
|
|
resolveWorkspaceReferenceEntryIconUrl={
|
|
resolveWorkspaceReferenceEntryIconUrl
|
|
}
|
|
resolveMentionReferenceTarget={resolveMentionReferenceTarget}
|
|
resolveWorkspaceReferenceInitialTarget={
|
|
resolveWorkspaceReferenceInitialTarget
|
|
}
|
|
workspaceFileReferenceCopy={workspaceFileReferenceCopy}
|
|
workspaceAppIcons={workspaceAppIcons}
|
|
referenceProvenanceFilters={referenceProvenanceFilters}
|
|
sessionInputHistoryEnabled={sessionInputHistoryEnabled}
|
|
sideConversationEnabled={sideConversationEnabled}
|
|
sideConversationPresentation={sideConversationPresentation}
|
|
sessionWorktreeEnabled={sessionWorktreeEnabled}
|
|
sessionLaunchModesByProjectSectionKey={
|
|
sessionLaunchModesByProjectSectionKey
|
|
}
|
|
onSessionLaunchModePreferenceChange={
|
|
onSessionLaunchModePreferenceChange
|
|
}
|
|
renderProjectDirectoryPickerHeaderActions={
|
|
renderProjectDirectoryPickerHeaderActions
|
|
}
|
|
projectSelectOptions={projectSelectOptions}
|
|
renderReferencePickerSidebarActions={
|
|
renderReferencePickerSidebarActions
|
|
}
|
|
renderComposerFooterAccessory={renderComposerFooterAccessory}
|
|
/>
|
|
);
|
|
}}
|
|
</WorkspaceNodeWindow>
|
|
</AgentGUIMentionServiceBoundary>
|
|
);
|
|
}, areAgentGUINodePropsEqual);
|
|
|
|
function projectProviderAccountLabel(
|
|
labels: Partial<Record<string, string>> | undefined,
|
|
providerValue: string | null | undefined,
|
|
accountLabelValue: string | null | undefined
|
|
): Partial<Record<string, string>> | undefined {
|
|
const provider = providerValue?.trim();
|
|
const accountLabel = accountLabelValue?.trim();
|
|
if (!provider || !accountLabel || labels?.[provider]?.trim()) {
|
|
return labels;
|
|
}
|
|
return {
|
|
...labels,
|
|
[provider]: accountLabel
|
|
};
|
|
}
|
|
|
|
function resolveAgentConfigMenuContext(
|
|
target: AgentGUIAgentTarget
|
|
): AgentGUIAgentConfigMenuContext | null {
|
|
const agentTargetId = target.agentTargetId?.trim() || target.targetId.trim();
|
|
const provider = target.provider.trim();
|
|
if (!agentTargetId || !provider) {
|
|
return null;
|
|
}
|
|
return {
|
|
agentTargetId,
|
|
provider,
|
|
label: target.label,
|
|
presentation: "menu",
|
|
...(target.ownership ? { ownership: target.ownership } : {})
|
|
};
|
|
}
|