fix(flows): surface waiting and failed task pressure (#129156)

This commit is contained in:
Peter Steinberger
2026-08-25 01:40:07 -07:00
committed by GitHub
parent 1d10b275db
commit e9f78c9cb9
2 changed files with 69 additions and 8 deletions
+56
View File
@@ -235,6 +235,62 @@ describe("flows commands", () => {
});
});
it.each([
{
status: "waiting",
pressure: "0 active · 1 waiting · 0 blocked · 0 cancel-requested · 1 total",
},
{
status: "failed",
pressure: "0 active · 0 blocked · 1 issues · 0 cancel-requested · 1 total",
},
{
status: "lost",
pressure: "0 active · 0 blocked · 1 issues · 0 cancel-requested · 1 total",
},
{
status: "succeeded",
pressure: "0 active · 0 blocked · 0 cancel-requested · 1 total",
},
{
status: "cancelled",
pressure: "0 active · 0 blocked · 0 cancel-requested · 1 total",
},
] as const)(
"accounts for filtered $status flows in TaskFlow pressure",
async ({ status, pressure }) => {
await withTaskFlowCommandStateDir(async () => {
createManagedTaskFlow({
ownerKey: "agent:main:main",
controllerId: `tests/flows-command-${status}`,
goal: `Inspect ${status} work`,
status,
});
createManagedTaskFlow({
ownerKey: "agent:main:main",
controllerId: "tests/flows-command-unrelated",
goal: "Unrelated running work",
status: "running",
});
const runtime = createRuntime();
await flowsListCommand({ status }, runtime);
expect(vi.mocked(runtime.log).mock.calls.map(([line]) => String(line))).toContain(
`TaskFlow pressure: ${pressure}`,
);
const jsonRuntime = createRuntime();
await flowsListCommand({ json: true, status }, jsonRuntime);
expect(vi.mocked(jsonRuntime.writeJson).mock.calls[0]?.[0]).toMatchObject({
count: 1,
status,
flows: [expect.objectContaining({ status })],
});
});
},
);
it("keeps truncated text rows UTF-16 well-formed", async () => {
await withTaskFlowCommandStateDir(async () => {
createManagedTaskFlow({
+13 -8
View File
@@ -122,14 +122,19 @@ function formatFlowRows(flows: TaskFlowRecord[], rich: boolean) {
}
function formatFlowListSummary(flows: TaskFlowRecord[]) {
const active = flows.filter(
(flow) => flow.status === "queued" || flow.status === "running",
).length;
const blocked = flows.filter((flow) => flow.status === "blocked").length;
const cancelRequested = flows.filter(
(flow) => flow.cancelRequestedAt != null && !isTerminalFlowStatus(flow.status),
).length;
return `${active} active · ${blocked} blocked · ${cancelRequested} cancel-requested · ${flows.length} total`;
const counts = { active: 0, waiting: 0, blocked: 0, issues: 0, cancelRequested: 0 };
for (const flow of flows) {
counts.active += Number(flow.status === "queued" || flow.status === "running");
counts.waiting += Number(flow.status === "waiting");
counts.blocked += Number(flow.status === "blocked");
counts.issues += Number(flow.status === "failed" || flow.status === "lost");
counts.cancelRequested += Number(
flow.cancelRequestedAt != null && !isTerminalFlowStatus(flow.status),
);
}
const waiting = counts.waiting ? ` · ${counts.waiting} waiting` : "";
const issues = counts.issues ? ` · ${counts.issues} issues` : "";
return `${counts.active} active${waiting} · ${counts.blocked} blocked${issues} · ${counts.cancelRequested} cancel-requested · ${flows.length} total`;
}
function summarizeWait(flow: TaskFlowRecord): string {