fix: Stabilize subagent lifecycle and polish subagent live display [LET-7764] (#1391)
This commit is contained in:
@@ -680,6 +680,12 @@ async function executeSubagent(
|
||||
},
|
||||
});
|
||||
|
||||
// Consider execution "running" once the child process has successfully spawned.
|
||||
// This avoids waiting on subagent init events (e.g. agentURL) to reflect progress.
|
||||
proc.once("spawn", () => {
|
||||
updateSubagent(subagentId, { status: "running" });
|
||||
});
|
||||
|
||||
// Set up abort handler to kill the child process
|
||||
let wasAborted = false;
|
||||
const abortHandler = () => {
|
||||
@@ -708,6 +714,14 @@ async function executeSubagent(
|
||||
crlfDelay: Number.POSITIVE_INFINITY,
|
||||
});
|
||||
|
||||
let rlClosed = false;
|
||||
const rlClosedPromise = new Promise<void>((resolve) => {
|
||||
rl.once("close", () => {
|
||||
rlClosed = true;
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
rl.on("line", (line: string) => {
|
||||
stdoutChunks.push(Buffer.from(`${line}\n`));
|
||||
processStreamEvent(line, state, subagentId);
|
||||
@@ -723,6 +737,13 @@ async function executeSubagent(
|
||||
proc.on("error", () => resolve(null));
|
||||
});
|
||||
|
||||
// Ensure all stdout lines have been processed before completing.
|
||||
// Without this, late tool events can be dropped before Task marks completion.
|
||||
if (!rlClosed) {
|
||||
rl.close();
|
||||
}
|
||||
await rlClosedPromise;
|
||||
|
||||
// Clean up abort listener
|
||||
signal?.removeEventListener("abort", abortHandler);
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ import {
|
||||
} from "../helpers/subagentDisplay.js";
|
||||
import {
|
||||
getSnapshot,
|
||||
getSubagentToolCount,
|
||||
type SubagentState,
|
||||
subscribe,
|
||||
toggleExpanded,
|
||||
@@ -71,20 +72,22 @@ interface AgentRowProps {
|
||||
const AgentRow = memo(
|
||||
({ agent, isLast, expanded, condensed = false }: AgentRowProps) => {
|
||||
const { treeChar, continueChar } = getTreeChars(isLast);
|
||||
const rowIndent = " ";
|
||||
const statusIndent = " ";
|
||||
const expandedToolIndent = " ";
|
||||
const columns = useTerminalWidth();
|
||||
const gutterWidth = 8; // indent (3) + continueChar (2) + status indent (3)
|
||||
const gutterWidth =
|
||||
rowIndent.length + continueChar.length + statusIndent.length;
|
||||
const contentWidth = Math.max(0, columns - gutterWidth);
|
||||
|
||||
const isRunning = agent.status === "pending" || agent.status === "running";
|
||||
const toolCount = getSubagentToolCount(agent);
|
||||
const shouldDim = isRunning && !agent.isBackground;
|
||||
const showStats = !(agent.isBackground && isRunning);
|
||||
const showStats =
|
||||
!(agent.isBackground && isRunning) && !(isRunning && toolCount === 0);
|
||||
const hideBackgroundStatusLine =
|
||||
agent.isBackground && isRunning && !agent.agentURL;
|
||||
const stats = formatStats(
|
||||
agent.toolCalls.length,
|
||||
agent.totalTokens,
|
||||
isRunning,
|
||||
);
|
||||
const stats = formatStats(toolCount, agent.totalTokens);
|
||||
const modelDisplay = getSubagentModelDisplay(agent.model);
|
||||
const lastTool = agent.toolCalls[agent.toolCalls.length - 1];
|
||||
|
||||
@@ -98,9 +101,9 @@ const AgentRow = memo(
|
||||
<Box flexDirection="column">
|
||||
{/* Main row: tree char + description + type + model (no stats) */}
|
||||
<Box flexDirection="row">
|
||||
<Text>
|
||||
<Text wrap="truncate-end">
|
||||
<Text color={colors.subagent.treeChar}>
|
||||
{" "}
|
||||
{rowIndent}
|
||||
{treeChar}{" "}
|
||||
</Text>
|
||||
<Text bold={!shouldDim} dimColor={shouldDim}>
|
||||
@@ -131,19 +134,37 @@ const AgentRow = memo(
|
||||
{/* Simple status line */}
|
||||
{!hideBackgroundStatusLine && (
|
||||
<Box flexDirection="row">
|
||||
<Text color={colors.subagent.treeChar}>
|
||||
{" "}
|
||||
{continueChar}
|
||||
</Text>
|
||||
<Text dimColor>{" "}</Text>
|
||||
{agent.status === "error" ? (
|
||||
<Text color={colors.subagent.error}>Error</Text>
|
||||
) : isComplete ? (
|
||||
<Text dimColor>Done</Text>
|
||||
) : agent.isBackground ? (
|
||||
<Text dimColor>Running in the background</Text>
|
||||
{!agent.agentURL &&
|
||||
!lastTool &&
|
||||
!isComplete &&
|
||||
agent.status !== "error" &&
|
||||
!agent.isBackground ? (
|
||||
<>
|
||||
<Text color={colors.subagent.treeChar}>
|
||||
{rowIndent}
|
||||
{continueChar} ⎿{" "}
|
||||
</Text>
|
||||
<Text dimColor>Launching...</Text>
|
||||
</>
|
||||
) : (
|
||||
<Text dimColor>Running...</Text>
|
||||
<>
|
||||
<Text color={colors.subagent.treeChar}>
|
||||
{rowIndent}
|
||||
{continueChar}
|
||||
</Text>
|
||||
<Text dimColor>{statusIndent}</Text>
|
||||
{agent.status === "error" ? (
|
||||
<Text color={colors.subagent.error}>Error</Text>
|
||||
) : isComplete ? (
|
||||
<Text dimColor>Done</Text>
|
||||
) : agent.isBackground ? (
|
||||
<Text dimColor>Running in the background</Text>
|
||||
) : lastTool ? (
|
||||
<Text dimColor>Running...</Text>
|
||||
) : (
|
||||
<Text dimColor>Thinking</Text>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Box>
|
||||
)}
|
||||
@@ -156,9 +177,9 @@ const AgentRow = memo(
|
||||
<Box flexDirection="column">
|
||||
{/* Main row: tree char + description + type + model + stats */}
|
||||
<Box flexDirection="row">
|
||||
<Text>
|
||||
<Text wrap="truncate-end">
|
||||
<Text color={colors.subagent.treeChar}>
|
||||
{" "}
|
||||
{rowIndent}
|
||||
{treeChar}{" "}
|
||||
</Text>
|
||||
<Text bold={!shouldDim} dimColor={shouldDim}>
|
||||
@@ -195,7 +216,7 @@ const AgentRow = memo(
|
||||
{agent.agentURL && (
|
||||
<Box flexDirection="row">
|
||||
<Text color={colors.subagent.treeChar}>
|
||||
{" "}
|
||||
{rowIndent}
|
||||
{continueChar} ⎿{" "}
|
||||
</Text>
|
||||
<Text dimColor>{"Subagent: "}</Text>
|
||||
@@ -210,11 +231,11 @@ const AgentRow = memo(
|
||||
return (
|
||||
<Box key={tc.id} flexDirection="row">
|
||||
<Text color={colors.subagent.treeChar}>
|
||||
{" "}
|
||||
{rowIndent}
|
||||
{continueChar}
|
||||
</Text>
|
||||
<Text dimColor>
|
||||
{" "}
|
||||
{expandedToolIndent}
|
||||
{tc.name}({formattedArgs})
|
||||
</Text>
|
||||
</Box>
|
||||
@@ -224,23 +245,15 @@ const AgentRow = memo(
|
||||
{/* Status line */}
|
||||
{!hideBackgroundStatusLine && (
|
||||
<Box flexDirection="row">
|
||||
{agent.status === "completed" ? (
|
||||
<>
|
||||
<Text color={colors.subagent.treeChar}>
|
||||
{" "}
|
||||
{continueChar}
|
||||
</Text>
|
||||
<Text dimColor>{" Done"}</Text>
|
||||
</>
|
||||
) : agent.status === "error" ? (
|
||||
{agent.status === "error" ? (
|
||||
<>
|
||||
<Box width={gutterWidth} flexShrink={0}>
|
||||
<Text>
|
||||
<Text color={colors.subagent.treeChar}>
|
||||
{" "}
|
||||
{rowIndent}
|
||||
{continueChar}
|
||||
</Text>
|
||||
<Text dimColor>{" "}</Text>
|
||||
<Text dimColor>{statusIndent}</Text>
|
||||
</Text>
|
||||
</Box>
|
||||
<Box flexGrow={1} width={contentWidth}>
|
||||
@@ -249,32 +262,33 @@ const AgentRow = memo(
|
||||
</Text>
|
||||
</Box>
|
||||
</>
|
||||
) : agent.isBackground ? (
|
||||
<Text>
|
||||
<Text color={colors.subagent.treeChar}>
|
||||
{" "}
|
||||
{continueChar}
|
||||
</Text>
|
||||
<Text dimColor>{" Running in the background"}</Text>
|
||||
</Text>
|
||||
) : lastTool ? (
|
||||
) : !agent.agentURL &&
|
||||
!lastTool &&
|
||||
agent.status !== "completed" &&
|
||||
!agent.isBackground ? (
|
||||
<>
|
||||
<Text color={colors.subagent.treeChar}>
|
||||
{" "}
|
||||
{continueChar}
|
||||
</Text>
|
||||
<Text dimColor>
|
||||
{" "}
|
||||
{lastTool.name}
|
||||
{rowIndent}
|
||||
{continueChar} ⎿{" "}
|
||||
</Text>
|
||||
<Text dimColor>Launching...</Text>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Text color={colors.subagent.treeChar}>
|
||||
{" "}
|
||||
{rowIndent}
|
||||
{continueChar}
|
||||
</Text>
|
||||
<Text dimColor>{" Starting..."}</Text>
|
||||
<Text dimColor>
|
||||
{statusIndent}
|
||||
{agent.status === "completed"
|
||||
? "Done"
|
||||
: agent.isBackground
|
||||
? "Running in the background"
|
||||
: lastTool
|
||||
? lastTool.name
|
||||
: "Thinking"}
|
||||
</Text>
|
||||
</>
|
||||
)}
|
||||
</Box>
|
||||
|
||||
@@ -56,8 +56,11 @@ interface AgentRowProps {
|
||||
|
||||
const AgentRow = memo(({ agent, isLast }: AgentRowProps) => {
|
||||
const { treeChar, continueChar } = getTreeChars(isLast);
|
||||
const rowIndent = " ";
|
||||
const statusIndent = " ";
|
||||
const columns = useTerminalWidth();
|
||||
const gutterWidth = 8; // indent (3) + continueChar (2) + status indent (3)
|
||||
const gutterWidth =
|
||||
rowIndent.length + continueChar.length + statusIndent.length;
|
||||
const contentWidth = Math.max(0, columns - gutterWidth);
|
||||
|
||||
const isRunning = agent.status === "running";
|
||||
@@ -65,16 +68,16 @@ const AgentRow = memo(({ agent, isLast }: AgentRowProps) => {
|
||||
const showStats = !(agent.isBackground && isRunning);
|
||||
const hideBackgroundStatusLine =
|
||||
agent.isBackground && isRunning && !agent.agentURL;
|
||||
const stats = formatStats(agent.toolCount, agent.totalTokens, isRunning);
|
||||
const stats = formatStats(agent.toolCount, agent.totalTokens);
|
||||
const modelDisplay = getSubagentModelDisplay(agent.model);
|
||||
|
||||
return (
|
||||
<Box flexDirection="column">
|
||||
{/* Main row: tree char + description + type + model + stats */}
|
||||
<Box flexDirection="row">
|
||||
<Text>
|
||||
<Text wrap="truncate-end">
|
||||
<Text color={colors.subagent.treeChar}>
|
||||
{" "}
|
||||
{rowIndent}
|
||||
{treeChar}{" "}
|
||||
</Text>
|
||||
<Text bold={!shouldDim} dimColor={shouldDim}>
|
||||
@@ -111,7 +114,7 @@ const AgentRow = memo(({ agent, isLast }: AgentRowProps) => {
|
||||
{agent.agentURL && (
|
||||
<Box flexDirection="row">
|
||||
<Text color={colors.subagent.treeChar}>
|
||||
{" "}
|
||||
{rowIndent}
|
||||
{continueChar} ⎿{" "}
|
||||
</Text>
|
||||
<Text dimColor>{"Subagent: "}</Text>
|
||||
@@ -122,23 +125,15 @@ const AgentRow = memo(({ agent, isLast }: AgentRowProps) => {
|
||||
{/* Status line */}
|
||||
{!hideBackgroundStatusLine && (
|
||||
<Box flexDirection="row">
|
||||
{agent.status === "completed" && !agent.isBackground ? (
|
||||
<>
|
||||
<Text color={colors.subagent.treeChar}>
|
||||
{" "}
|
||||
{continueChar}
|
||||
</Text>
|
||||
<Text dimColor>{" Done"}</Text>
|
||||
</>
|
||||
) : agent.status === "error" ? (
|
||||
{agent.status === "error" ? (
|
||||
<>
|
||||
<Box width={gutterWidth} flexShrink={0}>
|
||||
<Text>
|
||||
<Text color={colors.subagent.treeChar}>
|
||||
{" "}
|
||||
{rowIndent}
|
||||
{continueChar}
|
||||
</Text>
|
||||
<Text dimColor>{" "}</Text>
|
||||
<Text dimColor>{statusIndent}</Text>
|
||||
</Text>
|
||||
</Box>
|
||||
<Box flexGrow={1} width={contentWidth}>
|
||||
@@ -150,10 +145,15 @@ const AgentRow = memo(({ agent, isLast }: AgentRowProps) => {
|
||||
) : (
|
||||
<>
|
||||
<Text color={colors.subagent.treeChar}>
|
||||
{" "}
|
||||
{rowIndent}
|
||||
{continueChar}
|
||||
</Text>
|
||||
<Text dimColor>{" Running in the background"}</Text>
|
||||
<Text dimColor>
|
||||
{statusIndent}
|
||||
{agent.status === "completed" && !agent.isBackground
|
||||
? "Done"
|
||||
: "Running in the background"}
|
||||
</Text>
|
||||
</>
|
||||
)}
|
||||
</Box>
|
||||
|
||||
@@ -5,7 +5,11 @@
|
||||
|
||||
import type { StaticSubagent } from "../components/SubagentGroupStatic.js";
|
||||
import type { Line } from "./accumulator.js";
|
||||
import { getSubagentByToolCallId, getSubagents } from "./subagentState.js";
|
||||
import {
|
||||
getSubagentByToolCallId,
|
||||
getSubagents,
|
||||
getSubagentToolCount,
|
||||
} from "./subagentState.js";
|
||||
import { isTaskTool } from "./toolNameMapping.js";
|
||||
|
||||
/**
|
||||
@@ -133,7 +137,7 @@ export function createSubagentGroupItem(
|
||||
status: subagent.isBackground
|
||||
? "running"
|
||||
: (subagent.status as "completed" | "error"),
|
||||
toolCount: subagent.toolCalls.length,
|
||||
toolCount: getSubagentToolCount(subagent),
|
||||
totalTokens: subagent.totalTokens,
|
||||
agentURL: subagent.agentURL,
|
||||
error: subagent.error,
|
||||
|
||||
@@ -12,22 +12,15 @@ import { formatCompact } from "./format";
|
||||
*
|
||||
* @param toolCount - Number of tool calls
|
||||
* @param totalTokens - Total tokens used (0 or undefined means no data available)
|
||||
* @param isRunning - If true, shows "—" for tokens (since usage is only available at end)
|
||||
*/
|
||||
export function formatStats(
|
||||
toolCount: number,
|
||||
totalTokens: number,
|
||||
isRunning = false,
|
||||
): string {
|
||||
export function formatStats(toolCount: number, totalTokens: number): string {
|
||||
const toolStr = `${toolCount} tool use${toolCount !== 1 ? "s" : ""}`;
|
||||
|
||||
// Only show token count if we have actual data (not running and totalTokens > 0)
|
||||
const hasTokenData = !isRunning && totalTokens > 0;
|
||||
if (!hasTokenData) {
|
||||
return toolStr;
|
||||
if (totalTokens > 0) {
|
||||
return `${toolStr} · ${formatCompact(totalTokens)} tokens`;
|
||||
}
|
||||
|
||||
return `${toolStr} · ${formatCompact(totalTokens)} tokens`;
|
||||
return toolStr;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -23,6 +23,8 @@ export interface SubagentState {
|
||||
status: "pending" | "running" | "completed" | "error";
|
||||
agentURL: string | null;
|
||||
toolCalls: ToolCall[];
|
||||
// Monotonic counter to avoid transient regressions in rendered tool usage.
|
||||
maxToolCallsSeen: number;
|
||||
totalTokens: number;
|
||||
durationMs: number;
|
||||
error?: string;
|
||||
@@ -121,6 +123,7 @@ export function registerSubagent(
|
||||
status: "pending",
|
||||
agentURL: null,
|
||||
toolCalls: [],
|
||||
maxToolCallsSeen: 0,
|
||||
totalTokens: 0,
|
||||
durationMs: 0,
|
||||
startTime: Date.now(),
|
||||
@@ -148,8 +151,22 @@ export function updateSubagent(
|
||||
updates.status = "running";
|
||||
}
|
||||
|
||||
const nextToolCalls = updates.toolCalls ?? agent.toolCalls;
|
||||
const nextMax = Math.max(
|
||||
agent.maxToolCallsSeen,
|
||||
nextToolCalls.length,
|
||||
updates.maxToolCallsSeen ?? 0,
|
||||
);
|
||||
|
||||
// Skip no-op updates to avoid unnecessary re-renders
|
||||
const keys = Object.keys(updates) as (keyof typeof updates)[];
|
||||
const isNoop =
|
||||
keys.every((k) => agent[k] === updates[k]) &&
|
||||
nextMax === agent.maxToolCallsSeen;
|
||||
if (isNoop) return;
|
||||
|
||||
// Create a new object to ensure React.memo detects the change
|
||||
const updatedAgent = { ...agent, ...updates };
|
||||
const updatedAgent = { ...agent, ...updates, maxToolCallsSeen: nextMax };
|
||||
store.agents.set(id, updatedAgent);
|
||||
notifyListeners();
|
||||
}
|
||||
@@ -176,6 +193,10 @@ export function addToolCall(
|
||||
...agent.toolCalls,
|
||||
{ id: toolCallId, name: toolName, args: toolArgs },
|
||||
],
|
||||
maxToolCallsSeen: Math.max(
|
||||
agent.maxToolCallsSeen,
|
||||
agent.toolCalls.length + 1,
|
||||
),
|
||||
};
|
||||
store.agents.set(subagentId, updatedAgent);
|
||||
notifyListeners();
|
||||
@@ -198,11 +219,18 @@ export function completeSubagent(
|
||||
error: result.error,
|
||||
durationMs: Date.now() - agent.startTime,
|
||||
totalTokens: result.totalTokens ?? agent.totalTokens,
|
||||
maxToolCallsSeen: Math.max(agent.maxToolCallsSeen, agent.toolCalls.length),
|
||||
} as SubagentState;
|
||||
store.agents.set(id, updatedAgent);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
export function getSubagentToolCount(
|
||||
agent: Pick<SubagentState, "toolCalls" | "maxToolCallsSeen">,
|
||||
): number {
|
||||
return Math.max(agent.toolCalls.length, agent.maxToolCallsSeen);
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle expanded/collapsed state
|
||||
*/
|
||||
|
||||
96
src/tests/cli/subagent-tool-count.test.ts
Normal file
96
src/tests/cli/subagent-tool-count.test.ts
Normal file
@@ -0,0 +1,96 @@
|
||||
import { beforeEach, describe, expect, test } from "bun:test";
|
||||
import type { Line } from "../../cli/helpers/accumulator";
|
||||
import {
|
||||
collectFinishedTaskToolCalls,
|
||||
createSubagentGroupItem,
|
||||
} from "../../cli/helpers/subagentAggregation";
|
||||
import {
|
||||
addToolCall,
|
||||
clearAllSubagents,
|
||||
completeSubagent,
|
||||
getSubagentByToolCallId,
|
||||
getSubagentToolCount,
|
||||
registerSubagent,
|
||||
updateSubagent,
|
||||
} from "../../cli/helpers/subagentState";
|
||||
|
||||
describe("subagent tool count stability", () => {
|
||||
beforeEach(() => {
|
||||
clearAllSubagents();
|
||||
});
|
||||
|
||||
test("tool count remains monotonic even if toolCalls array is overwritten with fewer entries", () => {
|
||||
registerSubagent("sub-1", "explore", "Find symbols", "tc-task", false);
|
||||
addToolCall("sub-1", "tc-read", "Read", "{}");
|
||||
addToolCall("sub-1", "tc-grep", "Grep", "{}");
|
||||
|
||||
const before = getSubagentByToolCallId("tc-task");
|
||||
if (!before) {
|
||||
throw new Error("Expected subagent for tc-task");
|
||||
}
|
||||
expect(getSubagentToolCount(before)).toBe(2);
|
||||
|
||||
// Simulate a stale overwrite (should not reduce displayed count).
|
||||
updateSubagent("sub-1", {
|
||||
toolCalls: before.toolCalls.slice(0, 1),
|
||||
});
|
||||
|
||||
const after = getSubagentByToolCallId("tc-task");
|
||||
if (!after) {
|
||||
throw new Error("Expected updated subagent for tc-task");
|
||||
}
|
||||
expect(after.toolCalls.length).toBe(1);
|
||||
expect(getSubagentToolCount(after)).toBe(2);
|
||||
|
||||
completeSubagent("sub-1", { success: true });
|
||||
const completed = getSubagentByToolCallId("tc-task");
|
||||
if (!completed) {
|
||||
throw new Error("Expected completed subagent for tc-task");
|
||||
}
|
||||
expect(getSubagentToolCount(completed)).toBe(2);
|
||||
});
|
||||
|
||||
test("static subagent grouping uses monotonic tool count", () => {
|
||||
registerSubagent("sub-1", "explore", "Find symbols", "tc-task", false);
|
||||
addToolCall("sub-1", "tc-read", "Read", "{}");
|
||||
addToolCall("sub-1", "tc-grep", "Grep", "{}");
|
||||
completeSubagent("sub-1", { success: true, totalTokens: 42 });
|
||||
|
||||
const subagent = getSubagentByToolCallId("tc-task");
|
||||
if (!subagent) {
|
||||
throw new Error("Expected subagent for tc-task before grouping");
|
||||
}
|
||||
|
||||
// Simulate stale reduction right before grouping.
|
||||
updateSubagent("sub-1", {
|
||||
toolCalls: subagent.toolCalls.slice(0, 1),
|
||||
});
|
||||
|
||||
const order = ["line-task"];
|
||||
const byId = new Map<string, Line>([
|
||||
[
|
||||
"line-task",
|
||||
{
|
||||
kind: "tool_call",
|
||||
id: "line-task",
|
||||
name: "Task",
|
||||
phase: "finished",
|
||||
toolCallId: "tc-task",
|
||||
resultOk: true,
|
||||
},
|
||||
],
|
||||
]);
|
||||
|
||||
const finished = collectFinishedTaskToolCalls(
|
||||
order,
|
||||
byId,
|
||||
new Set<string>(),
|
||||
false,
|
||||
);
|
||||
expect(finished.length).toBe(1);
|
||||
|
||||
const group = createSubagentGroupItem(finished);
|
||||
expect(group.agents.length).toBe(1);
|
||||
expect(group.agents[0]?.toolCount).toBe(2);
|
||||
});
|
||||
});
|
||||
@@ -46,6 +46,7 @@ describe("spawnBackgroundSubagentTask", () => {
|
||||
{ id: "tc-1", name: "Read", args: "{}" },
|
||||
{ id: "tc-2", name: "Edit", args: "{}" },
|
||||
],
|
||||
maxToolCallsSeen: 2,
|
||||
totalTokens: 0,
|
||||
durationMs: 0,
|
||||
startTime: Date.now(),
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
completeSubagent,
|
||||
generateSubagentId,
|
||||
getSnapshot as getSubagentSnapshot,
|
||||
getSubagentToolCount,
|
||||
registerSubagent,
|
||||
} from "../../cli/helpers/subagentState.js";
|
||||
import { formatTaskNotification } from "../../cli/helpers/taskNotifications.js";
|
||||
@@ -293,9 +294,9 @@ export function spawnBackgroundSubagentTask(
|
||||
|
||||
if (!silentCompletion) {
|
||||
const subagentSnapshot = getSubagentSnapshotFn();
|
||||
const toolUses = subagentSnapshot.agents.find(
|
||||
const subagentEntry = subagentSnapshot.agents.find(
|
||||
(agent) => agent.id === subagentId,
|
||||
)?.toolCalls.length;
|
||||
);
|
||||
const durationMs = Math.max(0, Date.now() - bgTask.startTime.getTime());
|
||||
|
||||
const fullResult = result.success
|
||||
@@ -317,7 +318,10 @@ export function spawnBackgroundSubagentTask(
|
||||
outputFile,
|
||||
usage: {
|
||||
totalTokens: result.totalTokens,
|
||||
toolUses,
|
||||
toolUses:
|
||||
subagentEntry === undefined
|
||||
? undefined
|
||||
: getSubagentToolCount(subagentEntry),
|
||||
durationMs,
|
||||
},
|
||||
});
|
||||
@@ -361,9 +365,9 @@ export function spawnBackgroundSubagentTask(
|
||||
|
||||
if (!silentCompletion) {
|
||||
const subagentSnapshot = getSubagentSnapshotFn();
|
||||
const toolUses = subagentSnapshot.agents.find(
|
||||
const subagentEntry = subagentSnapshot.agents.find(
|
||||
(agent) => agent.id === subagentId,
|
||||
)?.toolCalls.length;
|
||||
);
|
||||
const durationMs = Math.max(0, Date.now() - bgTask.startTime.getTime());
|
||||
const notificationXml = formatTaskNotificationFn({
|
||||
taskId,
|
||||
@@ -372,7 +376,10 @@ export function spawnBackgroundSubagentTask(
|
||||
result: errorMessage,
|
||||
outputFile,
|
||||
usage: {
|
||||
toolUses,
|
||||
toolUses:
|
||||
subagentEntry === undefined
|
||||
? undefined
|
||||
: getSubagentToolCount(subagentEntry),
|
||||
durationMs,
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user