diff --git a/site/src/pages/AgentsPage/components/ChatConversation/StreamingOutput.tsx b/site/src/pages/AgentsPage/components/ChatConversation/StreamingOutput.tsx index 56cb79014d..ba894a3eb0 100644 --- a/site/src/pages/AgentsPage/components/ChatConversation/StreamingOutput.tsx +++ b/site/src/pages/AgentsPage/components/ChatConversation/StreamingOutput.tsx @@ -23,7 +23,7 @@ const LiveActivitySlot: FC = () => ( data-testid="live-activity-slot" className="flex h-6 items-center gap-2 text-content-secondary" > - + Thinking diff --git a/site/src/pages/AgentsPage/components/ChatConversation/messageParsing.test.ts b/site/src/pages/AgentsPage/components/ChatConversation/messageParsing.test.ts index 7d3fa92bd8..53356484d7 100644 --- a/site/src/pages/AgentsPage/components/ChatConversation/messageParsing.test.ts +++ b/site/src/pages/AgentsPage/components/ChatConversation/messageParsing.test.ts @@ -1151,30 +1151,4 @@ describe("getSubagentDescriptor", () => { }); } }); - - it("renders list_agents with a fixed generic affordance", () => { - const descriptor = getSubagentDescriptor({ - name: "list_agents", - args: {}, - result: { - agents: [ - { chat_id: "agent-1", type: "explore", status: "completed" }, - { chat_id: "agent-2", type: "computer_use", status: "running" }, - ], - total: 2, - returned: 2, - offset: 0, - has_more: false, - }, - }); - - // The list result has no single top-level type, so the descriptor - // must not derive a variant from per-agent types. - expect(descriptor).toMatchObject({ - action: "list", - variant: "general", - iconKind: "bot", - supportsDesktopAffordance: false, - }); - }); }); diff --git a/site/src/pages/AgentsPage/components/ChatElements/tools/CreateWorkspaceTool.tsx b/site/src/pages/AgentsPage/components/ChatElements/tools/CreateWorkspaceTool.tsx index 970ed61de2..ece7f4ff17 100644 --- a/site/src/pages/AgentsPage/components/ChatElements/tools/CreateWorkspaceTool.tsx +++ b/site/src/pages/AgentsPage/components/ChatElements/tools/CreateWorkspaceTool.tsx @@ -2,7 +2,7 @@ import { ExternalLinkIcon } from "lucide-react"; import type React from "react"; import { Link } from "react-router"; import { ToolCall } from "./ToolCall"; -import { asRecord, asString, type ToolStatus } from "./utils"; +import { asString, parseArgs, type ToolStatus } from "./utils"; import { WorkspaceBuildLogSection } from "./WorkspaceBuildLogSection"; /** @@ -32,15 +32,7 @@ export const CreateWorkspaceTool: React.FC<{ labelOverride, }) => { const isRunning = status === "running"; - let rec: Record | null = null; - if (resultJson) { - try { - const parsed = JSON.parse(resultJson); - rec = asRecord(parsed); - } catch { - rec = asRecord(resultJson); - } - } + const rec = parseArgs(resultJson); const ownerName = rec ? asString(rec.owner_name) : ""; const wsName = rec ? asString(rec.workspace_name) : workspaceName; const workspaceLink = ownerName && wsName ? `/@${ownerName}/${wsName}` : null; diff --git a/site/src/pages/AgentsPage/components/ChatElements/tools/ExecuteTool.stories.tsx b/site/src/pages/AgentsPage/components/ChatElements/tools/ExecuteTool.stories.tsx index f30e469874..bae1044512 100644 --- a/site/src/pages/AgentsPage/components/ChatElements/tools/ExecuteTool.stories.tsx +++ b/site/src/pages/AgentsPage/components/ChatElements/tools/ExecuteTool.stories.tsx @@ -35,14 +35,6 @@ export const ShortCommand: Story = { }, }; -export const RunningWithoutCommand: Story = { - args: { - command: "", - status: "running", - transcriptBlocks: [], - }, -}; - export const LongCommand: Story = { decorators: [ (Story) => ( diff --git a/site/src/pages/AgentsPage/components/ChatElements/tools/ExecuteTool.tsx b/site/src/pages/AgentsPage/components/ChatElements/tools/ExecuteTool.tsx index 329773e056..2e6add7289 100644 --- a/site/src/pages/AgentsPage/components/ChatElements/tools/ExecuteTool.tsx +++ b/site/src/pages/AgentsPage/components/ChatElements/tools/ExecuteTool.tsx @@ -56,7 +56,6 @@ export const ExecuteTool: React.FC = ({ parsedCommands, shellToolDisplayMode, }) => { - const hasCommand = command.trim().length > 0; const hasTranscriptBlocks = transcriptBlocks.length > 0; const autoDisplayState: AgentDisplayState = hasTranscriptBlocks || @@ -78,10 +77,6 @@ export const ExecuteTool: React.FC = ({ autoDisplayState, ); - if (!hasCommand) { - return null; - } - return ( { - const Renderer = - isSubagentToolName(name) && name !== "list_agents" - ? SubagentRenderer - : (toolRenderers[name] ?? GenericToolRenderer); + const Renderer = isSubagentToolName(name) + ? SubagentRenderer + : (toolRenderers[name] ?? GenericToolRenderer); const isShellTool = name === "execute" || name === "process_output"; if (!shouldRenderTool({ name, status, args, result })) { return null; diff --git a/site/src/pages/AgentsPage/components/ChatElements/tools/ToolCall.tsx b/site/src/pages/AgentsPage/components/ChatElements/tools/ToolCall.tsx index cd51f618b0..d9023d6f87 100644 --- a/site/src/pages/AgentsPage/components/ChatElements/tools/ToolCall.tsx +++ b/site/src/pages/AgentsPage/components/ChatElements/tools/ToolCall.tsx @@ -15,7 +15,6 @@ import { import { cn } from "#/utils/cn"; import { Shimmer } from "../Shimmer"; import { TranscriptRow } from "../TranscriptRow"; -import type { SubagentIconKind } from "./subagentDescriptor"; import { ToolIcon } from "./ToolIcon"; import type { ToolStatus } from "./utils"; @@ -208,7 +207,6 @@ type ToolCallLeadingIconProps = { children?: ReactNode; iconUrl?: string; serverName?: string; - subagentIconKind?: SubagentIconKind; }; const LeadingIcon: FC = ({ @@ -216,9 +214,8 @@ const LeadingIcon: FC = ({ children, iconUrl, serverName, - subagentIconKind, }) => { - const { active, failed } = useToolCallContext(); + const { active } = useToolCallContext(); if (children) { return <>{children}; } @@ -229,11 +226,9 @@ const LeadingIcon: FC = ({ return ( ); }; @@ -267,16 +262,11 @@ const Label: FC = ({ type ToolCallStatusProps = { className?: string; - errorMessage?: string; }; -const Status: FC = ({ className, errorMessage }) => { - const { - active, - errorMessage: contextErrorMessage, - failed, - } = useToolCallContext(); - const message = errorMessage || contextErrorMessage || "Tool call failed"; +const Status: FC = ({ className }) => { + const { active, errorMessage, failed } = useToolCallContext(); + const message = errorMessage || "Tool call failed"; return ( <> {active && ( @@ -367,7 +357,6 @@ type ToolCallHeaderProps = { label: ReactNode; iconUrl?: string; serverName?: string; - subagentIconKind?: SubagentIconKind; secondaryLabel?: ReactNode; trailing?: ReactNode; showStatus?: boolean; @@ -388,7 +377,6 @@ const Header: FC = ({ label, iconUrl, serverName, - subagentIconKind, secondaryLabel, trailing, showStatus = true, @@ -396,12 +384,7 @@ const Header: FC = ({ }) => { return ( - + {secondaryLabel} {showStatus && } diff --git a/site/src/pages/AgentsPage/components/ChatElements/tools/ToolIcon.tsx b/site/src/pages/AgentsPage/components/ChatElements/tools/ToolIcon.tsx index c2ff74debb..6db7eb5604 100644 --- a/site/src/pages/AgentsPage/components/ChatElements/tools/ToolIcon.tsx +++ b/site/src/pages/AgentsPage/components/ChatElements/tools/ToolIcon.tsx @@ -22,19 +22,13 @@ import { TooltipTrigger, } from "#/components/Tooltip/Tooltip"; import { cn } from "#/utils/cn"; -import { - isSubagentToolName, - type SubagentIconKind, -} from "./subagentDescriptor"; export const ToolIcon: React.FC<{ name: string; - isError: boolean; iconUrl?: string; isRunning?: boolean; serverName?: string; - subagentIconKind?: SubagentIconKind; -}> = ({ name, iconUrl, isRunning, serverName, subagentIconKind }) => { +}> = ({ name, iconUrl, isRunning, serverName }) => { const [imgError, setImgError] = useState(false); const color = "text-current"; const base = cn( @@ -80,20 +74,6 @@ export const ToolIcon: React.FC<{ return img; } - if (isSubagentToolName(name)) { - // This name-based fallback only exists for legacy callers that do - // not pass a descriptor. The descriptor path should provide - // subagentIconKind for new subagent types instead of extending it. - const iconKind = - subagentIconKind || - (name === "spawn_computer_use_agent" ? "monitor" : "bot"); - return iconKind === "monitor" ? ( - - ) : ( - - ); - } - switch (name) { case "execute": case "process_output": @@ -116,6 +96,7 @@ export const ToolIcon: React.FC<{ case "start_workspace": return ; case "chat_summarized": + case "list_agents": return ; case "thinking": return ; diff --git a/site/src/pages/AgentsPage/components/ChatElements/tools/ToolLabel.tsx b/site/src/pages/AgentsPage/components/ChatElements/tools/ToolLabel.tsx index b8babecf7a..078aa5d9ae 100644 --- a/site/src/pages/AgentsPage/components/ChatElements/tools/ToolLabel.tsx +++ b/site/src/pages/AgentsPage/components/ChatElements/tools/ToolLabel.tsx @@ -1,58 +1,7 @@ import type React from "react"; import { getPathBasename } from "../../../utils/path"; -import { - getProvidedSubagentTitle, - getSubagentDescriptor, -} from "./subagentDescriptor"; import { asRecord, asString, humanizeMCPToolName, parseArgs } from "./utils"; -const renderSubagentLabel = ( - name: string, - args: unknown, - result: unknown, -): React.ReactNode | null => { - const descriptor = getSubagentDescriptor({ name, args, result }); - if (!descriptor) { - return null; - } - - const providedTitle = getProvidedSubagentTitle({ args, result }); - const fallbackTitle = descriptor.fallbackTitle; - const text = (() => { - switch (descriptor.action) { - case "spawn": - if (providedTitle) { - return `Spawning ${providedTitle}`; - } - if (descriptor.variant === "explore") { - return "Spawning Explore agent…"; - } - if (descriptor.variant === "computer_use") { - return "Spawning computer use sub-agent…"; - } - return `Spawning ${fallbackTitle}…`; - case "wait": - return providedTitle - ? `Waiting for ${providedTitle}` - : `Waiting for ${fallbackTitle}…`; - case "message": - return providedTitle - ? `Messaging ${providedTitle}` - : `Messaging ${fallbackTitle}…`; - case "interrupt": - return providedTitle - ? `Interrupting ${providedTitle}` - : `Interrupting ${fallbackTitle}`; - case "list": - return providedTitle - ? `Listing ${providedTitle}` - : `Listing ${fallbackTitle}`; - } - })(); - - return {text}; -}; - export const ToolLabel: React.FC<{ name: string; args: unknown; @@ -61,14 +10,6 @@ export const ToolLabel: React.FC<{ }> = ({ name, args, result, mcpSlug }) => { const parsed = parseArgs(args); const parsedResult = asRecord(result); - const subagentLabel = renderSubagentLabel( - name, - parsed ?? args, - parsedResult ?? result, - ); - if (subagentLabel) { - return subagentLabel; - } switch (name) { case "execute": { diff --git a/site/src/pages/AgentsPage/components/ChatElements/tools/subagentDescriptor.ts b/site/src/pages/AgentsPage/components/ChatElements/tools/subagentDescriptor.ts index 8011c4a642..8d954b830a 100644 --- a/site/src/pages/AgentsPage/components/ChatElements/tools/subagentDescriptor.ts +++ b/site/src/pages/AgentsPage/components/ChatElements/tools/subagentDescriptor.ts @@ -1,14 +1,9 @@ import { asString } from "../runtimeTypeUtils"; import { parseArgs } from "./utils"; -export type SubagentAction = - | "spawn" - | "wait" - | "message" - | "interrupt" - | "list"; +export type SubagentAction = "spawn" | "wait" | "message" | "interrupt"; export type SubagentVariant = "general" | "explore" | "computer_use"; -export type SubagentIconKind = "bot" | "monitor"; +type SubagentIconKind = "bot" | "monitor"; export type SubagentDescriptor = { action: SubagentAction; @@ -59,11 +54,6 @@ const actionByToolName: Record = { // Legacy persisted tool name kept so old chat histories still render. close_agent: "interrupt", interrupt_agent: "interrupt", - // list_agents is a subagent tool but renders through - // ListAgentsRenderer, not SubagentRenderer. The "list" action - // exists for isSubagentToolName classification and ToolIcon - // dispatch, not for the SubagentRenderer label machinery. - list_agents: "list", }; const variantBySpawnToolName: Record = { diff --git a/site/src/pages/AgentsPage/components/ChatElements/tools/toolVisibility.test.ts b/site/src/pages/AgentsPage/components/ChatElements/tools/toolVisibility.test.ts index 31f68826e0..077a626468 100644 --- a/site/src/pages/AgentsPage/components/ChatElements/tools/toolVisibility.test.ts +++ b/site/src/pages/AgentsPage/components/ChatElements/tools/toolVisibility.test.ts @@ -136,7 +136,7 @@ describe("toolVisibility", () => { ).toBe(false); }); - it("renders list_agents rows even without a chat_id", () => { + it("renders list_agents rows regardless of chat_id", () => { expect( shouldRenderTool({ name: "list_agents",