Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,9 @@ function ActiveSubAgentRow({
const isRunning = item?.state !== "completed" || payload?.status === "running" || workflowIsLive;
if (registrationOnly || !item || !payload?.name) return null;

const display = deriveToolDisplay(payload);
// The dock groups rows under kind headers (Subagents/Crossagents), so the
// per-row "Agent:"/"Crossagent:" prefix would just repeat the header.
const display = deriveToolDisplay(payload, { bareAgentTitle: true });
const args =
payload.args && typeof payload.args === "object" && !Array.isArray(payload.args)
? (payload.args as Record<string, unknown>)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,9 @@ describe("SubAgentContent", () => {
expect(screen.queryByText("Background tasks")).not.toBeInTheDocument();
expect(screen.getByRole("button", { name: "Close subagents panel" })).toBeInTheDocument();
expect(screen.getByRole("button", { name: "Close Crossagents panel" })).toBeInTheDocument();
// Rows sit under the kind header, so they keep the bare label.
expect(screen.getByText("Codex · GPT-5.5")).toBeInTheDocument();
expect(screen.queryByText(/^Crossagent:/)).not.toBeInTheDocument();
});

it("renders child messages through the main timeline parser", async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,33 @@ describe("deriveToolDisplay", () => {
);
});

it("drops the kind prefix from bare agent titles used by grouped docks", () => {
const crossagent = makePayload({
name: "Drive collection closures — Factory Droid · DeepSeek V4 Flash 0731 (Droid Core) - High",
isCrossagent: true,
});
expect(deriveToolDisplay(crossagent).title).toBe(
"Crossagent: Drive collection closures — Factory Droid · DeepSeek V4 Flash 0731 (Droid Core) - High",
);
expect(deriveToolDisplay(crossagent, { bareAgentTitle: true }).title).toBe(
"Drive collection closures — Factory Droid · DeepSeek V4 Flash 0731 (Droid Core) - High",
);

const subagent = makePayload({
name: "probe worker alpha",
isSubAgent: true,
args: { subagent_type: "general-purpose" },
});
expect(deriveToolDisplay(subagent, { bareAgentTitle: true }).title).toBe("probe worker alpha");

const claudeTask = makePayload({
name: "Task",
isSubAgent: true,
args: { subagent_type: "general-purpose" },
});
expect(deriveToolDisplay(claudeTask, { bareAgentTitle: true }).title).toBe("general-purpose");
});

it("recognizes Claude Workflow tool calls as background work", () => {
const payload = makePayload({
name: "Workflow",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,19 @@ export {
} from "@/shared/toolCallClassification";
export { isWorkflowTool };

export function deriveToolDisplay(payload: ToolCallPayload): ToolDisplay {
export interface ToolDisplayOptions {
/**
* Omit the "Agent:"/"Crossagent:" kind prefix from delegated-agent titles —
* rows already grouped under a kind header (e.g. the Crossagents dock)
* would just repeat the header on every item.
*/
bareAgentTitle?: boolean;
}

export function deriveToolDisplay(
payload: ToolCallPayload,
options?: ToolDisplayOptions,
): ToolDisplay {
const args = readArgsObject(payload);

const mcp = parseMcpName(payload);
Expand All @@ -118,7 +130,7 @@ export function deriveToolDisplay(payload: ToolCallPayload): ToolDisplay {
};
}

const claude = mapClaudeRawTool(payload.name, args);
const claude = mapClaudeRawTool(payload.name, args, options);
if (claude) return claude;

if (payload.isSubAgent === true || payload.isCrossagent === true) {
Expand All @@ -127,6 +139,7 @@ export function deriveToolDisplay(payload: ToolCallPayload): ToolDisplay {
preferFallback: payload.title !== undefined,
isCrossagent: payload.isCrossagent === true,
isResume: payload.isSubAgentResume === true,
...(options?.bareAgentTitle ? { bare: true } : {}),
...(payload.subAgentType ? { subAgentType: payload.subAgentType } : {}),
}),
Icon: Bot,
Expand All @@ -142,6 +155,7 @@ export function deriveToolDisplay(payload: ToolCallPayload): ToolDisplay {
function mapClaudeRawTool(
name: string,
args: Record<string, unknown> | undefined,
options?: ToolDisplayOptions,
): ToolDisplay | null {
switch (name) {
case "Read":
Expand All @@ -156,7 +170,14 @@ function mapClaudeRawTool(
return withPath("List", args, ["path"], FolderSearch);
case "Task":
case "Agent":
return { title: formatAgentTitle(args), Icon: Bot };
return {
title: formatAgentTitle(
args,
undefined,
options?.bareAgentTitle ? { bare: true } : undefined,
),
Icon: Bot,
};
case "BashOutput":
return { title: titleWithValue(i18n._(msg`Bash output`), args, "bash_id"), Icon: Terminal };
case "KillBash":
Expand Down Expand Up @@ -339,6 +360,7 @@ function formatAgentTitle(
preferFallback?: boolean;
isCrossagent?: boolean;
isResume?: boolean;
bare?: boolean;
subAgentType?: string;
},
): string {
Expand All @@ -357,6 +379,10 @@ function formatAgentTitle(
}
return subagent ? i18n._(msg`Agent Resume: ${subagent}`) : i18n._(msg`Agent Resume`);
}
if (options?.bare) {
if (description) return description;
return subagent ?? (options.isCrossagent ? i18n._(msg`Crossagent`) : i18n._(msg`Agent`));
}
if (options?.isCrossagent) {
if (description) {
return subagent
Expand Down