Harness spec 3.2.0: teams — subagents that work together
team.md: a lead adds members (team_add) that work in the background on
the parts they own; members may lead areas of their own. The chat
setting agents {min, max} (defaults 1/4, an instance cap of 32) bounds
the whole tree, task helpers included; a team is offered only where
subagents are enabled and the model serves two requests at once
(capacity.parallel). A manager's work calls — risk write or execute,
bar job_stop and reading bash — answer a fixed refusal while the tool
list stays unchanged. The room: team_send to names or all, delivered
under "[Team message from X to Y:]" at the next step or waking a
finished member; a member's final reply is its report to its manager;
team_read shows the tree and the visible part of the room; team_stop
stops a subtree. Past the model's capacity a member waits for a slot,
the lead first. Size notes in context.note; texts in loop.json team;
prompts blocks/team_lead.md and team_member.md; tools allowed by
default. Conformance area team, written from a reference model.
The CLI embeds the new tool and prompt files; its tools are pending.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
14 files changed
+3899
-5
No files matched your search
+13
-1
@@ -153,10 +153,22 @@ test("spec 3.0.0: every tool says where it is offered; the CLI's are the agent's
|
||||
// plan_write's former name rather than a tool.
|
||||
expect(TOOL_SPECS.todo).toBeUndefined()
|
||||
expect(TOOL_SPECS.plan_write!.aliases.cli).toEqual(["todo"])
|
||||
const shared = ["ask_user", "edit", "glob", "grep", "job_list", "job_output", "job_send", "job_stop", "list", "memory", "plan_submit", "plan_update", "plan_write", "read", "recall", "report", "session_search", "show", "skill_manage", "skill_view", "skills_list", "task", "web_fetch", "web_search", "write"]
|
||||
const shared = ["ask_user", "edit", "glob", "grep", "job_list", "job_output", "job_send", "job_stop", "list", "memory", "plan_submit", "plan_update", "plan_write", "read", "recall", "report", "session_search", "show", "skill_manage", "skill_view", "skills_list", "task", "team_add", "team_read", "team_send", "team_stop", "web_fetch", "web_search", "write"]
|
||||
expect(Object.values(TOOL_SPECS).filter((t) => t.scope === "shared").map((t) => t.name).sort()).toEqual(shared.sort())
|
||||
})
|
||||
|
||||
test("spec 3.2.0: the team tools need `team` and answer one_agent; a manager's refused tools are exactly the writers and executors", () => {
|
||||
const loop = JSON.parse(readFileSync(join(HARNESS, "loop.json"), "utf8")) as { team: { unavailable: { one_agent: string }; work: { write: string[]; execute: string[]; kept: string[] } } }
|
||||
for (const n of ["team_add", "team_read", "team_send", "team_stop"]) {
|
||||
const t = TOOL_SPECS[n]!
|
||||
expect([t.scope, t.sessions, t.requires, t.unavailable]).toEqual(["shared", "both", ["team"], loop.team.unavailable.one_agent])
|
||||
}
|
||||
// team.work names every tool by its risk class, and nothing else: a new tool is placed by its class.
|
||||
const byRisk = (r: string) => Object.values(TOOL_SPECS).filter((t) => t.risk === r).map((t) => t.name).sort()
|
||||
expect([...loop.team.work.write].sort()).toEqual(byRisk("write"))
|
||||
expect([...loop.team.work.execute, ...loop.team.work.kept].sort()).toEqual(byRisk("execute"))
|
||||
})
|
||||
|
||||
test("the personality presets are shared prompt texts, one paragraph each", () => {
|
||||
const index = JSON.parse(readFileSync(join(HARNESS, "prompts", "index.json"), "utf8")) as { prompts: Record<string, { scope: string; llembas_text?: string }> }
|
||||
for (const n of ["concise", "pragmatic", "optimistic", "funny", "formal", "socratic"]) {
|
||||
|
||||
Reference in new issue
Block a user