feat(pi): label subagent work items
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
import assert from "node:assert/strict";
|
||||
import test from "node:test";
|
||||
import { milestoneNotification } from "./status.ts";
|
||||
import { Supervisor } from "./supervisor.ts";
|
||||
import type { ChildHandle, ChildRunner, RunnerEvents, SpawnRequest } from "./types.ts";
|
||||
import { widget } from "./ui.ts";
|
||||
|
||||
class FakeHandle implements ChildHandle {
|
||||
cancelCalls = 0;
|
||||
@@ -110,6 +112,77 @@ test("completed children ignore later cancel", async () => {
|
||||
assert.equal(runner.starts[0].handle.cancelCalls, 0);
|
||||
});
|
||||
|
||||
test("explicit labels are reused across accepted status list and result surfaces", async () => {
|
||||
const runner = new FakeRunner();
|
||||
const supervisor = new Supervisor(runner, "/tmp");
|
||||
const label = "Review risky migration";
|
||||
|
||||
const accepted = supervisor.spawn({ prompt: "inspect the migration plan", label } as SpawnRequest & { label: string });
|
||||
await sleep(0);
|
||||
runner.starts[0].events.completed("done", "agent_settled");
|
||||
|
||||
assert.deepEqual(
|
||||
{
|
||||
accepted: accepted.label,
|
||||
status: supervisor.status(accepted.id).label,
|
||||
list: supervisor.list().find((status) => status.id === accepted.id)?.label,
|
||||
result: (supervisor.result(accepted.id) as { label?: string }).label,
|
||||
},
|
||||
{
|
||||
accepted: label,
|
||||
status: label,
|
||||
list: label,
|
||||
result: label,
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
test("ad hoc fallback labels are prompt-derived and reused by widget and result surfaces", async () => {
|
||||
const runner = new FakeRunner();
|
||||
const supervisor = new Supervisor(runner, "/tmp");
|
||||
const prompt = " Audit\n\tguest enablement plan ";
|
||||
const label = "Audit guest enablement plan";
|
||||
|
||||
const accepted = supervisor.spawn({ prompt });
|
||||
await sleep(0);
|
||||
runner.starts[0].events.completed("done", "agent_settled");
|
||||
const statuses = supervisor.list();
|
||||
const inspectorLines = widget(statuses, true)().render(240);
|
||||
|
||||
assert.deepEqual(
|
||||
{
|
||||
accepted: accepted.label,
|
||||
childRequest: runner.starts[0].request.label,
|
||||
status: supervisor.status(accepted.id).label,
|
||||
list: statuses.find((status) => status.id === accepted.id)?.label,
|
||||
result: supervisor.result(accepted.id).label,
|
||||
},
|
||||
{
|
||||
accepted: label,
|
||||
childRequest: label,
|
||||
status: label,
|
||||
list: label,
|
||||
result: label,
|
||||
},
|
||||
);
|
||||
assert.ok(inspectorLines.some((line) => line.includes(`${accepted.id} ${label} independent completed`)), inspectorLines.join("\n"));
|
||||
assert.doesNotMatch(accepted.label, /^ad-hoc sg-/u);
|
||||
});
|
||||
|
||||
test("milestone notifications use the stored label", async () => {
|
||||
const runner = new FakeRunner();
|
||||
const supervisor = new Supervisor(runner, "/tmp");
|
||||
const accepted = supervisor.spawn({ prompt: "work", label: "Review migration" });
|
||||
await sleep(0);
|
||||
runner.starts[0].events.completed("done", "agent_settled");
|
||||
|
||||
assert.deepEqual(milestoneNotification(supervisor.status(accepted.id), "completed"), {
|
||||
message: "Subagent Review migration completed",
|
||||
level: "info",
|
||||
});
|
||||
assert.equal(milestoneNotification(supervisor.status(accepted.id), "running"), undefined);
|
||||
});
|
||||
|
||||
test("shutdown clears recent terminal expiry timer", async () => {
|
||||
const runner = new FakeRunner();
|
||||
let changes = 0;
|
||||
@@ -128,17 +201,22 @@ test("shutdown clears recent terminal expiry timer", async () => {
|
||||
assert.equal(changes, afterShutdown);
|
||||
});
|
||||
|
||||
test("batch spawn returns accepted ids and per-entry failures", async () => {
|
||||
test("batch spawn returns explicit labels on accepted child requests and statuses while preserving failures", async () => {
|
||||
const runner = new FakeRunner();
|
||||
const supervisor = new Supervisor(runner, "/tmp");
|
||||
|
||||
const result = supervisor.spawnBatch([{ prompt: "one" }, { prompt: "" }, { prompt: "two" }]);
|
||||
const result = supervisor.spawnBatch([
|
||||
{ prompt: "one", label: "Review docs" },
|
||||
{ prompt: "" },
|
||||
{ prompt: "two", label: "Check tests" },
|
||||
]);
|
||||
await sleep(0);
|
||||
|
||||
assert.equal(result.accepted.length, 2);
|
||||
assert.deepEqual(result.accepted.map((accepted) => accepted.label), ["Review docs", "Check tests"]);
|
||||
assert.equal(result.failed.length, 1);
|
||||
assert.equal(result.failed[0].index, 1);
|
||||
assert.equal(runner.starts.length, 2);
|
||||
assert.deepEqual(runner.starts.map((start) => start.request.label), ["Review docs", "Check tests"]);
|
||||
assert.deepEqual(result.accepted.map((accepted) => supervisor.status(accepted.id).label), ["Review docs", "Check tests"]);
|
||||
});
|
||||
|
||||
test("maxConcurrent preserves queued records", async () => {
|
||||
|
||||
Reference in New Issue
Block a user