import { describe, expect, it } from "vite-plus/test";import { classifyTaskAgentKind, type OrchestrationThreadActivity } from "@t3tools/contracts";import { deriveAgentPanelModel, foldSubagentActivities, formatSubagentModelLabel, formatSubagentTokenCount,} from "./subagentRuntime.ts"; let sequence = 0;/** * Fixtures model POST-INGESTION rows: ingestion stamps agentKind on every * task.* payload, so the helper stamps too (same classifier). Pass an * explicit agentKind (or agentKind: undefined via legacy()) to override. */function activity( kind: string, payload: Record<string, unknown>, at = `2026-08-01T10:00:${String(sequence).padStart(2, "0")}.000Z`,): OrchestrationThreadActivity { sequence += 1; const stamped = kind.startsWith("task.") && !("agentKind" in payload) ? { ...payload, agentKind: classifyTaskAgentKind({ taskType: typeof payload.taskType === "string" ? payload.taskType : undefined, agentId: typeof payload.agentId === "string" ? payload.agentId : undefined, }), } : payload; return { id: `activity-${sequence}`, tone: "info", kind, summary: kind, payload: stamped, turnId: null, createdAt: at, } as unknown as OrchestrationThreadActivity;} /** A pre-stamp row (legacy thread / old server): no agentKind at all. */function legacyActivity( kind: string, payload: Record<string, unknown>,): OrchestrationThreadActivity { sequence += 1; return { id: `activity-${sequence}`, tone: "info", kind, summary: kind, payload, turnId: null, createdAt: `2026-08-01T10:00:${String(sequence).padStart(2, "0")}.000Z`, } as unknown as OrchestrationThreadActivity;} function fold(rows: ReadonlyArray<OrchestrationThreadActivity>) { return foldSubagentActivities(rows);} describe("foldSubagentActivities", () => { it("shows the batch status limit after its parent turn ends without claiming a result", () => { const running = activity("task.progress", { taskId: "batch-1", taskType: "subagent_batch", title: "Antigravity subagent batch", status: "running", summary: "Launch readers", }); const agents = fold([ running, activity("task.updated", { taskId: "batch-1", taskType: "subagent_batch", status: "idle", detail: "Turn ended. Individual agent status is unavailable.", timelineBypass: true, }), ]); expect(agents).toHaveLength(1); expect(agents[0]).toMatchObject({ title: "Antigravity subagent batch", kind: "subagent_batch", status: "idle", progress: "Turn ended. Individual agent status is unavailable.", result: null, error: null, }); }); it("learns batch identity from a later update and retains it on sparse updates", () => { const agents = fold([ activity("task.progress", { taskId: "batch-1", taskType: "subagent", status: "running" }), activity("task.updated", { taskId: "batch-1", taskType: "subagent_batch", status: "idle" }), activity("task.updated", { taskId: "batch-1", status: "idle" }), ]); expect(agents).toHaveLength(1); expect(agents[0]).toMatchObject({ kind: "subagent_batch", status: "idle" }); }); it("builds an agent from start → progress → completion", () => { const agents = fold([ activity("task.started", { taskId: "task-1", title: "Audit auth flow", role: "explorer", }), activity("task.progress", { taskId: "task-1", lastToolName: "Read", typedUsage: { totalTokens: 1200, toolUses: 3 }, }), activity("task.completed", { taskId: "task-1", status: "completed", summary: "Found 2 issues", typedUsage: { totalTokens: 5000, toolUses: 9 }, }), ]); expect(agents).toHaveLength(1); const agent = agents[0]!; expect(agent.title).toBe("Audit auth flow"); expect(agent.role).toBe("explorer"); expect(agent.status).toBe("completed"); expect(agent.result).toBe("Found 2 issues"); expect(agent.usage?.totalTokens).toBe(5000); expect(agent.activationCount).toBe(1); expect(agent.completedAt).not.toBeNull(); }); it("progress can create an agent when its start row aged out of retention", () => { const agents = fold([ activity("task.progress", { taskId: "task-orphan", title: "Recovered agent", role: "verifier", typedUsage: { totalTokens: 100 }, }), ]); expect(agents).toHaveLength(1); expect(agents[0]!.title).toBe("Recovered agent"); expect(agents[0]!.status).toBe("running"); }); it("completion before start stays terminal; a late start only fills metadata", () => { const agents = fold([ activity("task.completed", { taskId: "task-2", status: "failed", summary: "boom", role: "fixer", }), activity("task.started", { taskId: "task-2", title: "Late metadata", role: "fixer" }), ]); expect(agents).toHaveLength(1); const agent = agents[0]!; expect(agent.title).toBe("Late metadata"); expect(agent.role).toBe("fixer"); // The late start must NOT reopen the terminal activation as a new run. expect(agent.status).toBe("failed"); expect(agent.error).toBe("boom"); }); it("duplicate terminal events are idempotent (timestamps do not slide)", () => { const agents = fold([ activity("task.started", { taskId: "task-3", taskType: "local_agent" }), activity( "task.completed", { taskId: "task-3", status: "completed" }, "2026-08-01T11:00:00.000Z", ), activity( "task.completed", { taskId: "task-3", status: "completed" }, "2026-08-01T12:00:00.000Z", ), ]); expect(agents[0]!.completedAt).toBe("2026-08-01T11:00:00.000Z"); }); it("reactivation increments the run count and clears result/error", () => { const agents = fold([ activity("task.started", { taskId: "task-4", taskType: "local_agent" }), activity("task.completed", { taskId: "task-4", status: "completed", summary: "run 1 done" }), activity("task.updated", { taskId: "task-4", status: "running" }), ]); const agent = agents[0]!; expect(agent.activationCount).toBe(2); expect(agent.result).toBeNull(); expect(agent.completedAt).toBeNull(); expect(agent.status).toBe("running"); }); it("idle is nonterminal: an idle agent resumes without losing identity", () => { const agents = fold([ activity("task.started", { taskId: "codex-child-1", title: "Marlow", role: "explorer" }), activity("task.updated", { taskId: "codex-child-1", status: "idle" }), activity("task.updated", { taskId: "codex-child-1", status: "running" }), ]); expect(agents).toHaveLength(1); expect(agents[0]!.activationCount).toBe(2); expect(agents[0]!.status).toBe("running"); }); it("cumulative usage max-merges: duplicate and late frames never shrink or double-count", () => { const agents = fold([ activity("task.started", { taskId: "task-5", taskType: "local_agent" }), activity("task.progress", { taskId: "task-5", typedUsage: { totalTokens: 900, inputTokens: 700 }, }), activity("task.progress", { taskId: "task-5", typedUsage: { totalTokens: 900, inputTokens: 700 }, }), activity("task.progress", { taskId: "task-5", typedUsage: { totalTokens: 500 } }), ]); expect(agents[0]!.usage).toEqual({ totalTokens: 900, inputTokens: 700 }); }); it("usage snapshots enrich an existing agent without changing its status", () => { const [agent] = fold([ activity("task.started", { taskId: "usage-waiting", taskType: "local_agent" }), activity("task.progress", { taskId: "usage-waiting", status: "waiting" }), activity("task.progress", { taskId: "usage-waiting", usageSnapshot: true, typedUsage: { totalTokens: 1_200 }, }), ]); expect(agent?.status).toBe("waiting"); expect(agent?.usage?.totalTokens).toBe(1_200); }); it("a retained usage snapshot can still reconstruct a running agent", () => { const [agent] = fold([ activity("task.progress", { taskId: "usage-only", usageSnapshot: true, typedUsage: { totalTokens: 800 }, }), ]); expect(agent?.status).toBe("running"); expect(agent?.usage?.totalTokens).toBe(800); }); it("partial terminal usage preserves known breakdown fields", () => { const agents = fold([ activity("task.started", { taskId: "task-6", taskType: "local_agent" }), activity("task.progress", { taskId: "task-6", typedUsage: { totalTokens: 800, inputTokens: 600, outputTokens: 150 }, }), activity("task.completed", { taskId: "task-6", status: "completed", typedUsage: { totalTokens: 1000 }, }), ]); expect(agents[0]!.usage).toEqual({ totalTokens: 1000, inputTokens: 600, outputTokens: 150 }); }); it("skips malformed rows individually without failing the fold", () => { const agents = fold([ activity("task.started", { taskId: "task-7", title: "Good", taskType: "local_agent" }), activity("task.progress", { bogus: true }), activity("task.progress", { taskId: 42 }), ]); expect(agents).toHaveLength(1); expect(agents[0]!.title).toBe("Good"); }); it("bounds repeated strings at 180 chars and the activity ring at 6 deduped entries", () => { const long = "x".repeat(500); const rows = [activity("task.started", { taskId: "task-8", taskType: "local_agent" })]; for (let i = 0; i < 10; i += 1) { rows.push(activity("task.progress", { taskId: "task-8", summary: `${long}-${i}` })); } rows.push(activity("task.progress", { taskId: "task-8", summary: `${long}-9` })); const agents = fold(rows); const agent = agents[0]!; expect(agent.recentActivity.length).toBeLessThanOrEqual(6); for (const entry of agent.recentActivity) { expect(entry.summary.length).toBeLessThanOrEqual(180); } // Consecutive identical summaries dedupe (truncation makes them equal). const summaries = agent.recentActivity.map((entry) => entry.summary); expect(new Set(summaries).size).toBe(summaries.length); }); it("plan tasks are not agents", () => { const agents = fold([activity("task.started", { taskId: "plan-1", taskType: "plan" })]); expect(agents).toHaveLength(0); }); it("workflow members key by stable slot and attach to their coordinator", () => { const agents = fold([ activity("task.started", { taskId: "wf-1", taskType: "local_workflow", title: "audit-auth-flow", workflowName: "audit-auth-flow", }), activity("task.progress", { taskId: "wf-1", phases: [ { index: 0, title: "Audit" }, { index: 1, title: "Verify" }, ], }), activity("task.progress", { taskId: "wf-1:wf:0", title: "audit:entrypoints", status: "running", parentAgentId: "wf-1", agentIndex: 0, phaseIndex: 0, phaseTitle: "Audit", timelineBypass: true, }), ]); const workflow = agents.find((agent) => agent.id === "wf-1"); const member = agents.find((agent) => agent.id === "wf-1:wf:0"); expect(workflow?.kind).toBe("workflow"); expect(workflow?.phases).toEqual([ { index: 0, title: "Audit" }, { index: 1, title: "Verify" }, ]); expect(member?.kind).toBe("workflow_agent"); expect(member?.parentAgentId).toBe("wf-1"); }); it("a workflow member retry (attempt bump) is a reactivation of the same slot", () => { const agents = fold([ activity("task.progress", { taskId: "wf-2:wf:1", title: "verify:refresh", status: "failed", error: "attempt 1 died", parentAgentId: "wf-2", attempt: 1, }), activity("task.progress", { taskId: "wf-2:wf:1", title: "verify:refresh", status: "running", parentAgentId: "wf-2", attempt: 2, }), ]); expect(agents).toHaveLength(1); const member = agents[0]!; expect(member.activationCount).toBeGreaterThanOrEqual(2); expect(member.error).toBeNull(); expect(member.status).toBe("running"); }); it("drops non-http(s) session urls at the fold boundary", () => { const agents = fold([ activity("task.started", { taskId: "wf-3", taskType: "local_workflow", runHandles: { sessionUrl: "javascript:alert(1)", runId: "run-1" }, }), ]); expect(agents[0]!.runHandles?.sessionUrl).toBeUndefined(); expect(agents[0]!.runHandles?.runId).toBe("run-1"); });}); describe("deriveAgentPanelModel", () => { const roster = fold([ activity("task.started", { taskId: "wf-1", taskType: "local_workflow", title: "audit" }), activity("task.progress", { taskId: "wf-1", phases: [ { index: 0, title: "Audit" }, { index: 1, title: "Verify" }, ], }), activity("task.progress", { taskId: "wf-1:wf:0", title: "audit:a", status: "completed", parentAgentId: "wf-1", agentIndex: 0, phaseIndex: 0, }), activity("task.completed", { taskId: "wf-1:wf:0", status: "completed", parentAgentId: "wf-1" }), activity("task.progress", { taskId: "wf-1:wf:1", title: "verify:b", status: "running", parentAgentId: "wf-1", agentIndex: 1, phaseIndex: 1, typedUsage: { totalTokens: 4000 }, }), activity("task.started", { taskId: "direct-1", title: "Marlow", role: "explorer" }), activity("task.updated", { taskId: "direct-1", status: "idle" }), ]); it("groups workflow members by phase and separates direct spawns", () => { const model = deriveAgentPanelModel({ agents: roster }); expect(model.workflows).toHaveLength(1); const group = model.workflows[0]!; expect(group.phases).toHaveLength(2); expect(group.phases[0]!.state).toBe("done"); expect(group.phases[1]!.state).toBe("running"); expect(model.directAgents.map((agent) => agent.id)).toEqual(["direct-1"]); }); it("counts idle deliberately and waiting as active", () => { const model = deriveAgentPanelModel({ agents: roster }); expect(model.idleCount).toBe(1); // Member 1 is running; the wf-1 coordinator is a container, not a worker. expect(model.runningCount).toBe(1); // Every agent lands in exactly one bucket, except coordinators that stand // in for their members. expect(model.idleCount + model.runningCount + model.waitingCount + model.settledCount).toBe( roster.length - 1, ); }); it("omits a workflow coordinator from the working-agent count", () => { const model = deriveAgentPanelModel({ agents: roster }); // One member still running plus one idle direct spawn. The coordinator // reports running for the whole workflow and must not inflate the banner. expect(model.liveCount).toBe(1); }); it("omits a finished workflow coordinator from the settled count", () => { const finished = fold([ activity("task.started", { taskId: "wf-2", taskType: "local_workflow", title: "sweep" }), activity("task.progress", { taskId: "wf-2:wf:0", title: "sweep:a", status: "completed", parentAgentId: "wf-2", agentIndex: 0, phaseIndex: 0, }), activity("task.completed", { taskId: "wf-2:wf:0", status: "completed", parentAgentId: "wf-2", }), activity("task.completed", { taskId: "wf-2", status: "completed" }), ]); const model = deriveAgentPanelModel({ agents: finished }); // Only the member settled. The coordinator stands in for it, so counting // both would report two finished agents where one ran. expect(model.settledCount).toBe(1); expect(model.liveCount).toBe(0); }); it("keeps direct spawns in first-seen order as their activity changes", () => { const directRoster = fold([ activity("task.started", { taskId: "direct-a", title: "First" }, "2026-08-01T11:00:00.000Z"), activity("task.started", { taskId: "direct-b", title: "Second" }, "2026-08-01T11:00:01.000Z"), activity( "task.progress", { taskId: "direct-a", summary: "Newest activity" }, "2026-08-01T11:00:02.000Z", ), ]); expect( deriveAgentPanelModel({ agents: directRoster }).directAgents.map((agent) => agent.id), ).toEqual(["direct-a", "direct-b"]); }); it("keeps first-seen order after the roster retention ranking runs", () => { const starts = Array.from({ length: 101 }, (_, index) => activity( "task.started", { taskId: `capped-${index}`, title: `Agent ${index}` }, `2026-08-01T12:${String(Math.floor(index / 60)).padStart(2, "0")}:${String( index % 60, ).padStart(2, "0")}.000Z`, ), ); const cappedRoster = fold([ ...starts, activity( "task.progress", { taskId: "capped-0", summary: "Newest activity" }, "2026-08-01T12:02:00.000Z", ), ]); const ids = deriveAgentPanelModel({ agents: cappedRoster }).directAgents.map( (agent) => agent.id,Lines 1–500 of 893. Load more
import { describe, expect, it } from "vite-plus/test"; import { classifyTaskAgentKind, type OrchestrationThreadActivity } from "@t3tools/contracts"; import { deriveAgentPanelModel, foldSubagentActivities, formatSubagentModelLabel, formatSubagentTokenCount, } from "./subagentRuntime.ts"; let sequence = 0; /** * Fixtures model POST-INGESTION rows: ingestion stamps agentKind on every * task.* payload, so the helper stamps too (same classifier). Pass an * explicit agentKind (or agentKind: undefined via legacy()) to override. */ function activity( kind: string, payload: Record<string, unknown>, at = `2026-08-01T10:00:${String(sequence).padStart(2, "0")}.000Z`, ): OrchestrationThreadActivity { sequence += 1; const stamped = kind.startsWith("task.") && !("agentKind" in payload) ? { ...payload, agentKind: classifyTaskAgentKind({ taskType: typeof payload.taskType === "string" ? payload.taskType : undefined, agentId: typeof payload.agentId === "string" ? payload.agentId : undefined, }), } : payload; return { id: `activity-${sequence}`, tone: "info", kind, summary: kind, payload: stamped, turnId: null, createdAt: at, } as unknown as OrchestrationThreadActivity; } /** A pre-stamp row (legacy thread / old server): no agentKind at all. */ function legacyActivity( kind: string, payload: Record<string, unknown>, ): OrchestrationThreadActivity { sequence += 1; return { id: `activity-${sequence}`, tone: "info", kind, summary: kind, payload, turnId: null, createdAt: `2026-08-01T10:00:${String(sequence).padStart(2, "0")}.000Z`, } as unknown as OrchestrationThreadActivity; } function fold(rows: ReadonlyArray<OrchestrationThreadActivity>) { return foldSubagentActivities(rows); } describe("foldSubagentActivities", () => { it("shows the batch status limit after its parent turn ends without claiming a result", () => { const running = activity("task.progress", { taskId: "batch-1", taskType: "subagent_batch", title: "Antigravity subagent batch", status: "running", summary: "Launch readers", }); const agents = fold([ running, activity("task.updated", { taskId: "batch-1", taskType: "subagent_batch", status: "idle", detail: "Turn ended. Individual agent status is unavailable.", timelineBypass: true, }), ]); expect(agents).toHaveLength(1); expect(agents[0]).toMatchObject({ title: "Antigravity subagent batch", kind: "subagent_batch", status: "idle", progress: "Turn ended. Individual agent status is unavailable.", result: null, error: null, }); }); it("learns batch identity from a later update and retains it on sparse updates", () => { const agents = fold([ activity("task.progress", { taskId: "batch-1", taskType: "subagent", status: "running" }), activity("task.updated", { taskId: "batch-1", taskType: "subagent_batch", status: "idle" }), activity("task.updated", { taskId: "batch-1", status: "idle" }), ]); expect(agents).toHaveLength(1); expect(agents[0]).toMatchObject({ kind: "subagent_batch", status: "idle" }); }); it("builds an agent from start → progress → completion", () => { const agents = fold([ activity("task.started", { taskId: "task-1", title: "Audit auth flow", role: "explorer", }), activity("task.progress", { taskId: "task-1", lastToolName: "Read", typedUsage: { totalTokens: 1200, toolUses: 3 }, }), activity("task.completed", { taskId: "task-1", status: "completed", summary: "Found 2 issues", typedUsage: { totalTokens: 5000, toolUses: 9 }, }), ]); expect(agents).toHaveLength(1); const agent = agents[0]!; expect(agent.title).toBe("Audit auth flow"); expect(agent.role).toBe("explorer"); expect(agent.status).toBe("completed"); expect(agent.result).toBe("Found 2 issues"); expect(agent.usage?.totalTokens).toBe(5000); expect(agent.activationCount).toBe(1); expect(agent.completedAt).not.toBeNull(); }); it("progress can create an agent when its start row aged out of retention", () => { const agents = fold([ activity("task.progress", { taskId: "task-orphan", title: "Recovered agent", role: "verifier", typedUsage: { totalTokens: 100 }, }), ]); expect(agents).toHaveLength(1); expect(agents[0]!.title).toBe("Recovered agent"); expect(agents[0]!.status).toBe("running"); }); it("completion before start stays terminal; a late start only fills metadata", () => { const agents = fold([ activity("task.completed", { taskId: "task-2", status: "failed", summary: "boom", role: "fixer", }), activity("task.started", { taskId: "task-2", title: "Late metadata", role: "fixer" }), ]); expect(agents).toHaveLength(1); const agent = agents[0]!; expect(agent.title).toBe("Late metadata"); expect(agent.role).toBe("fixer"); // The late start must NOT reopen the terminal activation as a new run. expect(agent.status).toBe("failed"); expect(agent.error).toBe("boom"); }); it("duplicate terminal events are idempotent (timestamps do not slide)", () => { const agents = fold([ activity("task.started", { taskId: "task-3", taskType: "local_agent" }), activity( "task.completed", { taskId: "task-3", status: "completed" }, "2026-08-01T11:00:00.000Z", ), activity( "task.completed", { taskId: "task-3", status: "completed" }, "2026-08-01T12:00:00.000Z", ), ]); expect(agents[0]!.completedAt).toBe("2026-08-01T11:00:00.000Z"); }); it("reactivation increments the run count and clears result/error", () => { const agents = fold([ activity("task.started", { taskId: "task-4", taskType: "local_agent" }), activity("task.completed", { taskId: "task-4", status: "completed", summary: "run 1 done" }), activity("task.updated", { taskId: "task-4", status: "running" }), ]); const agent = agents[0]!; expect(agent.activationCount).toBe(2); expect(agent.result).toBeNull(); expect(agent.completedAt).toBeNull(); expect(agent.status).toBe("running"); }); it("idle is nonterminal: an idle agent resumes without losing identity", () => { const agents = fold([ activity("task.started", { taskId: "codex-child-1", title: "Marlow", role: "explorer" }), activity("task.updated", { taskId: "codex-child-1", status: "idle" }), activity("task.updated", { taskId: "codex-child-1", status: "running" }), ]); expect(agents).toHaveLength(1); expect(agents[0]!.activationCount).toBe(2); expect(agents[0]!.status).toBe("running"); }); it("cumulative usage max-merges: duplicate and late frames never shrink or double-count", () => { const agents = fold([ activity("task.started", { taskId: "task-5", taskType: "local_agent" }), activity("task.progress", { taskId: "task-5", typedUsage: { totalTokens: 900, inputTokens: 700 }, }), activity("task.progress", { taskId: "task-5", typedUsage: { totalTokens: 900, inputTokens: 700 }, }), activity("task.progress", { taskId: "task-5", typedUsage: { totalTokens: 500 } }), ]); expect(agents[0]!.usage).toEqual({ totalTokens: 900, inputTokens: 700 }); }); it("usage snapshots enrich an existing agent without changing its status", () => { const [agent] = fold([ activity("task.started", { taskId: "usage-waiting", taskType: "local_agent" }), activity("task.progress", { taskId: "usage-waiting", status: "waiting" }), activity("task.progress", { taskId: "usage-waiting", usageSnapshot: true, typedUsage: { totalTokens: 1_200 }, }), ]); expect(agent?.status).toBe("waiting"); expect(agent?.usage?.totalTokens).toBe(1_200); }); it("a retained usage snapshot can still reconstruct a running agent", () => { const [agent] = fold([ activity("task.progress", { taskId: "usage-only", usageSnapshot: true, typedUsage: { totalTokens: 800 }, }), ]); expect(agent?.status).toBe("running"); expect(agent?.usage?.totalTokens).toBe(800); }); it("partial terminal usage preserves known breakdown fields", () => { const agents = fold([ activity("task.started", { taskId: "task-6", taskType: "local_agent" }), activity("task.progress", { taskId: "task-6", typedUsage: { totalTokens: 800, inputTokens: 600, outputTokens: 150 }, }), activity("task.completed", { taskId: "task-6", status: "completed", typedUsage: { totalTokens: 1000 }, }), ]); expect(agents[0]!.usage).toEqual({ totalTokens: 1000, inputTokens: 600, outputTokens: 150 }); }); it("skips malformed rows individually without failing the fold", () => { const agents = fold([ activity("task.started", { taskId: "task-7", title: "Good", taskType: "local_agent" }), activity("task.progress", { bogus: true }), activity("task.progress", { taskId: 42 }), ]); expect(agents).toHaveLength(1); expect(agents[0]!.title).toBe("Good"); }); it("bounds repeated strings at 180 chars and the activity ring at 6 deduped entries", () => { const long = "x".repeat(500); const rows = [activity("task.started", { taskId: "task-8", taskType: "local_agent" })]; for (let i = 0; i < 10; i += 1) { rows.push(activity("task.progress", { taskId: "task-8", summary: `${long}-${i}` })); } rows.push(activity("task.progress", { taskId: "task-8", summary: `${long}-9` })); const agents = fold(rows); const agent = agents[0]!; expect(agent.recentActivity.length).toBeLessThanOrEqual(6); for (const entry of agent.recentActivity) { expect(entry.summary.length).toBeLessThanOrEqual(180); } // Consecutive identical summaries dedupe (truncation makes them equal). const summaries = agent.recentActivity.map((entry) => entry.summary); expect(new Set(summaries).size).toBe(summaries.length); }); it("plan tasks are not agents", () => { const agents = fold([activity("task.started", { taskId: "plan-1", taskType: "plan" })]); expect(agents).toHaveLength(0); }); it("workflow members key by stable slot and attach to their coordinator", () => { const agents = fold([ activity("task.started", { taskId: "wf-1", taskType: "local_workflow", title: "audit-auth-flow", workflowName: "audit-auth-flow", }), activity("task.progress", { taskId: "wf-1", phases: [ { index: 0, title: "Audit" }, { index: 1, title: "Verify" }, ], }), activity("task.progress", { taskId: "wf-1:wf:0", title: "audit:entrypoints", status: "running", parentAgentId: "wf-1", agentIndex: 0, phaseIndex: 0, phaseTitle: "Audit", timelineBypass: true, }), ]); const workflow = agents.find((agent) => agent.id === "wf-1"); const member = agents.find((agent) => agent.id === "wf-1:wf:0"); expect(workflow?.kind).toBe("workflow"); expect(workflow?.phases).toEqual([ { index: 0, title: "Audit" }, { index: 1, title: "Verify" }, ]); expect(member?.kind).toBe("workflow_agent"); expect(member?.parentAgentId).toBe("wf-1"); }); it("a workflow member retry (attempt bump) is a reactivation of the same slot", () => { const agents = fold([ activity("task.progress", { taskId: "wf-2:wf:1", title: "verify:refresh", status: "failed", error: "attempt 1 died", parentAgentId: "wf-2", attempt: 1, }), activity("task.progress", { taskId: "wf-2:wf:1", title: "verify:refresh", status: "running", parentAgentId: "wf-2", attempt: 2, }), ]); expect(agents).toHaveLength(1); const member = agents[0]!; expect(member.activationCount).toBeGreaterThanOrEqual(2); expect(member.error).toBeNull(); expect(member.status).toBe("running"); }); it("drops non-http(s) session urls at the fold boundary", () => { const agents = fold([ activity("task.started", { taskId: "wf-3", taskType: "local_workflow", runHandles: { sessionUrl: "javascript:alert(1)", runId: "run-1" }, }), ]); expect(agents[0]!.runHandles?.sessionUrl).toBeUndefined(); expect(agents[0]!.runHandles?.runId).toBe("run-1"); }); }); describe("deriveAgentPanelModel", () => { const roster = fold([ activity("task.started", { taskId: "wf-1", taskType: "local_workflow", title: "audit" }), activity("task.progress", { taskId: "wf-1", phases: [ { index: 0, title: "Audit" }, { index: 1, title: "Verify" }, ], }), activity("task.progress", { taskId: "wf-1:wf:0", title: "audit:a", status: "completed", parentAgentId: "wf-1", agentIndex: 0, phaseIndex: 0, }), activity("task.completed", { taskId: "wf-1:wf:0", status: "completed", parentAgentId: "wf-1" }), activity("task.progress", { taskId: "wf-1:wf:1", title: "verify:b", status: "running", parentAgentId: "wf-1", agentIndex: 1, phaseIndex: 1, typedUsage: { totalTokens: 4000 }, }), activity("task.started", { taskId: "direct-1", title: "Marlow", role: "explorer" }), activity("task.updated", { taskId: "direct-1", status: "idle" }), ]); it("groups workflow members by phase and separates direct spawns", () => { const model = deriveAgentPanelModel({ agents: roster }); expect(model.workflows).toHaveLength(1); const group = model.workflows[0]!; expect(group.phases).toHaveLength(2); expect(group.phases[0]!.state).toBe("done"); expect(group.phases[1]!.state).toBe("running"); expect(model.directAgents.map((agent) => agent.id)).toEqual(["direct-1"]); }); it("counts idle deliberately and waiting as active", () => { const model = deriveAgentPanelModel({ agents: roster }); expect(model.idleCount).toBe(1); // Member 1 is running; the wf-1 coordinator is a container, not a worker. expect(model.runningCount).toBe(1); // Every agent lands in exactly one bucket, except coordinators that stand // in for their members. expect(model.idleCount + model.runningCount + model.waitingCount + model.settledCount).toBe( roster.length - 1, ); }); it("omits a workflow coordinator from the working-agent count", () => { const model = deriveAgentPanelModel({ agents: roster }); // One member still running plus one idle direct spawn. The coordinator // reports running for the whole workflow and must not inflate the banner. expect(model.liveCount).toBe(1); }); it("omits a finished workflow coordinator from the settled count", () => { const finished = fold([ activity("task.started", { taskId: "wf-2", taskType: "local_workflow", title: "sweep" }), activity("task.progress", { taskId: "wf-2:wf:0", title: "sweep:a", status: "completed", parentAgentId: "wf-2", agentIndex: 0, phaseIndex: 0, }), activity("task.completed", { taskId: "wf-2:wf:0", status: "completed", parentAgentId: "wf-2", }), activity("task.completed", { taskId: "wf-2", status: "completed" }), ]); const model = deriveAgentPanelModel({ agents: finished }); // Only the member settled. The coordinator stands in for it, so counting // both would report two finished agents where one ran. expect(model.settledCount).toBe(1); expect(model.liveCount).toBe(0); }); it("keeps direct spawns in first-seen order as their activity changes", () => { const directRoster = fold([ activity("task.started", { taskId: "direct-a", title: "First" }, "2026-08-01T11:00:00.000Z"), activity("task.started", { taskId: "direct-b", title: "Second" }, "2026-08-01T11:00:01.000Z"), activity( "task.progress", { taskId: "direct-a", summary: "Newest activity" }, "2026-08-01T11:00:02.000Z", ), ]); expect( deriveAgentPanelModel({ agents: directRoster }).directAgents.map((agent) => agent.id), ).toEqual(["direct-a", "direct-b"]); }); it("keeps first-seen order after the roster retention ranking runs", () => { const starts = Array.from({ length: 101 }, (_, index) => activity( "task.started", { taskId: `capped-${index}`, title: `Agent ${index}` }, `2026-08-01T12:${String(Math.floor(index / 60)).padStart(2, "0")}:${String( index % 60, ).padStart(2, "0")}.000Z`, ), ); const cappedRoster = fold([ ...starts, activity( "task.progress", { taskId: "capped-0", summary: "Newest activity" }, "2026-08-01T12:02:00.000Z", ), ]); const ids = deriveAgentPanelModel({ agents: cappedRoster }).directAgents.map( (agent) => agent.id,