feat(agent): Pi subagents via agent.spawn / agent.await
- agent_run gains depth / spawn_reason (0029); agent_run_event types
subagent_spawned / subagent_event / subagent_completed
- agent.spawn (propose, medium, replay never): allowlist ⊆ parent, mode not
above parent, budget carved from parent's remainder, idempotent per run+input;
settings.pi.subagents {enabled, maxConcurrent, maxDepth} (subagentsEnabled kept as alias)
- child runs claim a concurrency slot under an advisory lock (waitForFact while
queued); agent.await polls business tables without calling the model
- parent abort cascades to all descendants; parent runtime budget counts
descendant usage; child events mirrored into the parent stream by parent seq
- authorize caps every child call by all ancestors' allowlists/kinds
- session page shows parent link, inherited info and the subagent tree
- e2e E11; runbook section on subagents
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
daa85a8bb4
commit
459991421e
27 files changed
+1720
-32
No files matched your search
@@ -22,10 +22,28 @@ const samples: C.AgentRunEventBody[] = [
|
||||
{ type: "compaction", phase: "end", reason: "threshold", status: "completed" },
|
||||
{ type: "run_completed", finalText: "done", usage },
|
||||
{ type: "run_failed", reason: "budget", message: "超预算", usage, budget: "tokens" },
|
||||
{
|
||||
type: "subagent_spawned",
|
||||
childRunId: RUN,
|
||||
goal: "子目标",
|
||||
mode: "plan_only",
|
||||
depth: 1,
|
||||
capabilities: ["inventory.query"],
|
||||
budget: { maxToolCalls: 5 },
|
||||
},
|
||||
{
|
||||
type: "subagent_event",
|
||||
childRunId: RUN,
|
||||
childSeq: 3,
|
||||
childType: "tool_call_end",
|
||||
capabilityId: "inventory.query",
|
||||
summary: "{}",
|
||||
},
|
||||
{ type: "subagent_completed", childRunId: RUN, status: "succeeded", summary: "ok", usage, toolCalls: 1 },
|
||||
];
|
||||
|
||||
describe("agent 运行事件", () => {
|
||||
it("样例覆盖全部 9 种事件类型", () => {
|
||||
it("样例覆盖全部 12 种事件类型", () => {
|
||||
expect(samples.map((s) => s.type).sort()).toEqual([...C.AgentRunEventType.options].sort());
|
||||
});
|
||||
|
||||
@@ -60,6 +78,9 @@ describe("agent 运行事件", () => {
|
||||
null,
|
||||
"agent.run_status:succeeded",
|
||||
"agent.run_status:budget_exceeded",
|
||||
"agent.tool_call:started",
|
||||
"agent.tool_call:started",
|
||||
"agent.tool_call:succeeded",
|
||||
]);
|
||||
for (const b of bus) if (b) expect(C.parseEventPayload(b.type, b.payload), b.type).not.toBeNull();
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user