Subagents v2 in the CLI (harness spec 3.4.0): the main agent's tree, modes and requests, findings, finishing and running out of context; progress phases
ci / check (push) Waiting to run

team/team.ts: ids, positions, parents; only the main agent adds, assigns, replaces, stops and
decides; sub-managers; slots; modes inherited and never widened, request options and grants;
findings; team_finish; pause and out_of_context; ended subagents kept; the tree's data.
Seven new tools. A subagent's call is decided by team/delegation.ts (itself, the main agent
through a request, or the person). Its engine does not compact: at pause_at it is paused and
gets one final turn. Every engine says its progress as phase events (session/progress.ts).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
HomerandClaude Opus 5.5 committed 2026-11-10 08:21:29 +00:00
1 parent b66891e186
commit 8c5edc0f01
15 files changed
+951 -77

No files matched your search

+2 -2
View File
@@ -26,7 +26,7 @@ const yes = { ask: async (): Promise<AskReply> => ({ kind: "once" }) }
const say = (text: string): Scripted => ({ chunks: [delta({ content: text }, "stop")] })
const call = (id: string, name: string, args: unknown): Scripted => ({ chunks: [toolCall(0, id, name, JSON.stringify(args)), delta({}, "tool_calls")] })
const system = (body: any): string => body.messages[0].content
const isMember = (body: any, name: string) => system(body).includes(`You are "${name}", a member of a team`)
const isMember = (body: any, name: string) => new RegExp(`You are "${name}" \\(s\\d+\\), a subagent`).test(system(body))
const lastUser = (body: any): string => {
const u = [...body.messages].reverse().find((m: any) => m.role === "user")
return typeof u.content === "string" ? u.content : u.content.map((p: any) => p.text ?? "").join("")
@@ -95,7 +95,7 @@ describe("a team at work (team.md)", () => {
expect(t.get("parser")!.state).toBe("finished")
expect(t.isManager("lead")).toBe(true)
expect(teamLabel(t)).toBe("agents 2/4")
expect(teamText(app, "")).toContain("- parser — the parser · finished")
expect(teamText(app, "")).toContain("- parser (s1) — the parser · finished")
expect(await Bun.file(join(dir, "x.txt")).exists()).toBe(false)
// A member is not a job to the model.
expect(app.jobs().every((j) => j.team === "parser")).toBe(true)