authorgravatar for 154429365+Rishet11@users.noreply.github.comRishet11 <154429365+Rishet11@users.noreply.github.com> 2026-08-15 17:30:51+05:30
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-08-15 12:00:51+00:00
log9bdd91293316038d6a50f8bb19afcd73c25ad102
treea10a9c9d061a149af2c1124a672b36db9728794a
parent4db50757c0b618293997a7f81bcfe30b68356969
signature Signed by PGP key B5690EEEBB952194

fix(web): stop counting a workflow coordinator as a working agent (#6672)


2 files changed, 45 insertions(+), 8 deletions(-)

packages/client-runtime/src/state/subagentRuntime.test.ts+39-3
...@@ -383,13 +383,49 @@ describe("deriveAgentPanelModel", () => {...@@ -383,13 +383,49 @@ describe("deriveAgentPanelModel", () => {
383 it("counts idle deliberately and waiting as active", () => {383 it("counts idle deliberately and waiting as active", () => {
384 const model = deriveAgentPanelModel({ agents: roster });384 const model = deriveAgentPanelModel({ agents: roster });
385 expect(model.idleCount).toBe(1);385 expect(model.idleCount).toBe(1);
386 // wf-1 coordinator + member 1 running.386 // Member 1 is running; the wf-1 coordinator is a container, not a worker.
387 expect(model.runningCount).toBeGreaterThanOrEqual(1);387 expect(model.runningCount).toBe(1);
388 // Every agent lands in exactly one bucket, except coordinators that stand
389 // in for their members.
388 expect(model.idleCount + model.runningCount + model.waitingCount + model.settledCount).toBe(390 expect(model.idleCount + model.runningCount + model.waitingCount + model.settledCount).toBe(
389 roster.length,391 roster.length - 1,
390 );392 );
391 });393 });
392394
395 it("omits a workflow coordinator from the working-agent count", () => {
396 const model = deriveAgentPanelModel({ agents: roster });
397 // One member still running plus one idle direct spawn. The coordinator
398 // reports running for the whole workflow and must not inflate the banner.
399 expect(model.liveCount).toBe(1);
400 });
401
402 it("omits a finished workflow coordinator from the settled count", () => {
403 const finished = fold([
404 activity("task.started", { taskId: "wf-2", taskType: "local_workflow", title: "sweep" }),
405 activity("task.progress", {
406 taskId: "wf-2:wf:0",
407 title: "sweep:a",
408 status: "completed",
409 parentAgentId: "wf-2",
410 agentIndex: 0,
411 phaseIndex: 0,
412 }),
413 activity("task.completed", {
414 taskId: "wf-2:wf:0",
415 status: "completed",
416 parentAgentId: "wf-2",
417 }),
418 activity("task.completed", { taskId: "wf-2", status: "completed" }),
419 ]);
420
421 const model = deriveAgentPanelModel({ agents: finished });
422
423 // Only the member settled. The coordinator stands in for it, so counting
424 // both would report two finished agents where one ran.
425 expect(model.settledCount).toBe(1);
426 expect(model.liveCount).toBe(0);
427 });
428
393 it("keeps direct spawns in first-seen order as their activity changes", () => {429 it("keeps direct spawns in first-seen order as their activity changes", () => {
394 const directRoster = fold([430 const directRoster = fold([
395 activity("task.started", { taskId: "direct-a", title: "First" }, "2026-08-01T11:00:00.000Z"),431 activity("task.started", { taskId: "direct-a", title: "First" }, "2026-08-01T11:00:00.000Z"),
packages/client-runtime/src/state/subagentRuntime.ts+6-5
...@@ -826,15 +826,16 @@ export function deriveAgentPanelModel({...@@ -826,15 +826,16 @@ export function deriveAgentPanelModel({
826 let settledCount = 0;826 let settledCount = 0;
827 let totalTokens = 0;827 let totalTokens = 0;
828 for (const agent of source) {828 for (const agent of source) {
829 // A workflow coordinator with members is a container for those members, not
830 // work of its own: it reports running for the whole run and aggregates their
831 // usage upstream in some providers. Counting it would report one more agent
832 // working than there are, and double count tokens.
833 if (agent.kind === "workflow" && (members.get(agent.id) ?? []).length > 0) continue;
829 if (agent.status === "running" || agent.status === "pending") runningCount += 1;834 if (agent.status === "running" || agent.status === "pending") runningCount += 1;
830 else if (agent.status === "waiting") waitingCount += 1;835 else if (agent.status === "waiting") waitingCount += 1;
831 else if (agent.status === "idle") idleCount += 1;836 else if (agent.status === "idle") idleCount += 1;
832 else settledCount += 1;837 else settledCount += 1;
833 // Workflow coordinators aggregate member usage upstream in some providers;838 totalTokens += agent.usage?.totalTokens ?? 0;
834 // avoid double counting by only summing leaf agents when members exist.
835 if (agent.kind !== "workflow" || (members.get(agent.id) ?? []).length === 0) {
836 totalTokens += agent.usage?.totalTokens ?? 0;
837 }
838 }839 }
839840
840 return {841 return {