import { memo, useCallback, type ReactElement } from "react"; import { WorkspaceDiffStatPill } from "@/composer/diff-stat-pill"; import { useWorkspaceHasDiffStat } from "@/composer/workspace-diff-stat"; import { AgentTaskList } from "@/composer/task-list"; import { ComposerTrackBar } from "@/composer/tracks"; import { supportsDesktopPaneSplits, useIsCompactFormFactor } from "@/constants/layout"; import { usePaneContext } from "@/panels/pane-context"; import { useSettings } from "@/hooks/use-settings"; import { useSessionStore } from "@/stores/session-store"; import { type ArchiveFinishedStatus, useArchiveSubagent, useDetachSubagent, type SubagentRow, } from "@/subagents"; import { SubagentsTrack } from "@/subagents/track"; import type { TodoEntry } from "@/types/stream"; import { navigateToAgent } from "@/utils/navigate-to-agent"; import { buildWorkspaceTabPersistenceKey } from "@/workspace-tabs/model"; import { openSupportingTab, toggleSupportingTab } from "@/workspace-tabs/side-panel"; /** * The pane's ambient context — workspace changes, subagents, and tasks — as a row of pills above * the composer. * * The row shares the composer's keyboard transform and owns the space between itself and the * transcript. Each pill owns its action while tab placement stays behind the workspace boundary. */ export const AgentTracks = memo(function AgentTracks({ serverId, workspaceId, subagentRows, tasks, archiveFinishedStatus, onArchiveFinished, }: { serverId: string; workspaceId: string; subagentRows: SubagentRow[]; tasks: TodoEntry[] | undefined; archiveFinishedStatus: ArchiveFinishedStatus; onArchiveFinished: () => void; }): ReactElement | null { const { tabId, openTab } = usePaneContext(); const hasWorkspaceDiffStat = useWorkspaceHasDiffStat(serverId, workspaceId); const isCompact = useIsCompactFormFactor(); const canSplit = supportsDesktopPaneSplits() && !isCompact; const openInSidePanelByDefault = useSettings( (settings) => settings.openSupportingTabsInSidePanel, ); const workspaceKey = buildWorkspaceTabPersistenceKey({ serverId, workspaceId }); const canDetachSubagents = useSessionStore( (state) => state.sessions[serverId]?.serverInfo?.features?.agentDetach === true, ); const archiveSubagent = useArchiveSubagent({ serverId }); const detachSubagent = useDetachSubagent({ serverId }); const handleOpenSubagent = useCallback( (subagentId: string) => { const session = useSessionStore.getState().sessions[serverId]; const agent = session?.agents.get(subagentId) ?? session?.agentDetails.get(subagentId); if (agent?.workspaceId && agent.workspaceId !== workspaceId) { navigateToAgent({ serverId, agentId: subagentId }); return; } if (canSplit && workspaceKey) { openSupportingTab({ isCompact, workspaceKey, target: { kind: "agent", agentId: subagentId }, openInSidePanelByDefault, parentTabId: tabId, }); return; } navigateToAgent({ serverId, agentId: subagentId }); }, [canSplit, isCompact, openInSidePanelByDefault, serverId, tabId, workspaceId, workspaceKey], ); const handleOpenProviderSubagent = useCallback( (parentAgentId: string, subagentId: string) => { if (canSplit && workspaceKey) { openSupportingTab({ isCompact, workspaceKey, target: { kind: "provider_subagent", parentAgentId, subagentId }, openInSidePanelByDefault, parentTabId: tabId, }); return; } openTab({ kind: "provider_subagent", parentAgentId, subagentId }); }, [canSplit, isCompact, openInSidePanelByDefault, openTab, tabId, workspaceKey], ); const handleOpenChanges = useCallback(() => { if (!workspaceKey) { return; } toggleSupportingTab({ isCompact, workspaceKey, target: { kind: "working_diff" }, openInSidePanelByDefault, }); }, [isCompact, openInSidePanelByDefault, workspaceKey]); if (!hasWorkspaceDiffStat && !hasAgentTracks({ subagentRows, tasks, archiveFinishedStatus })) { return null; } return ( ); }); export function hasAgentTracks({ subagentRows, tasks, archiveFinishedStatus, }: { subagentRows: readonly SubagentRow[]; tasks: readonly TodoEntry[] | undefined; archiveFinishedStatus: ArchiveFinishedStatus; }): boolean { return subagentRows.length > 0 || Boolean(tasks?.length) || archiveFinishedStatus.kind !== "idle"; }