From 527a19260fe2bd50308762bcd1881e1c7936dea0 Mon Sep 17 00:00:00 2001 From: Alex Clarke Date: Wed, 9 Sep 2026 16:44:01 -0600 Subject: [PATCH] docs: Updated the docs to mention the new support for the teammate pattern in graph agents --- Agents.md | 5 ++++ Graph-Agents.md | 73 +++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 75 insertions(+), 3 deletions(-) diff --git a/Agents.md b/Agents.md index 90f5afd..37add57 100644 --- a/Agents.md +++ b/Agents.md @@ -729,6 +729,11 @@ their siblings. For a working example of the teammate pattern, see the built-in [code-reviewer](https://github.com/Dark-Alex-17/coyote/blob/main/assets/agents/code-reviewer) agent, which spawns file-specific reviewers that share cross-cutting findings with each other. +Sub-agents run by [graph agent nodes](Graph-Agents#agent) can also form per-fan-out teams: set `teammates: true` on the +agent node and concurrent siblings (map branches or same-super-step flagged nodes) get pre-provisioned inboxes, a roster +block in their prompts, and a `peers` section in `agent__list_running`. See +[Teammate messaging in fan-outs](Graph-Agents#teammate-messaging-in-fan-outs). + ## Runaway Safeguards The spawning system includes built-in safeguards to prevent runaway agent chains: diff --git a/Graph-Agents.md b/Graph-Agents.md index 5b857cf..5fb4df6 100644 --- a/Graph-Agents.md +++ b/Graph-Agents.md @@ -67,6 +67,10 @@ top_p: null # default sampling top-p reasoning_effort: null # default reasoning effort for llm nodes (model-dependent; e.g. low, medium, high) max_concurrent_jobs: null # optional; graph-wide [background job](Background-Jobs) budget shared by all llm nodes # (jobs themselves are node-local); overrides the global setting, 0 disables +can_spawn_agents: null # optional; whether llm nodes may spawn dynamic sub-agents via the agent__* tools; + # defaults to true iff the graph contains at least one agent node +max_concurrent_agents: null # optional; cap on dynamically spawned sub-agents running at once (default 4) +max_agent_depth: null # optional; max agent nesting depth, i.e. agents spawning agents (default 3) global_tools: # global tools available to nodes - web_search_coyote.sh mcp_servers: # MCP servers available to nodes @@ -132,9 +136,17 @@ nodes: see a variable inside prompts, seed its value into state (typically via a setup script that reads the env var and writes it into state) so `{{name}}` resolves. -- **`can_spawn_agents` is derived, not declared.** A graph agent can spawn - child agents iff its graph contains at least one `agent` node. You don't - set a flag. The `agent` node's presence *is* the declaration. +- **`can_spawn_agents` is declared, or derived when omitted.** When the key + is absent, a graph agent can spawn dynamic child agents iff its graph + contains at least one `agent` node; an explicit value overrides that + derivation. Set `can_spawn_agents: true` on a graph with only `llm` nodes + to build an **orchestrator graph**: its `llm` nodes get the full + `agent__*` toolset (spawn/collect/messaging/task queue) and can drive + dynamic sub-agent teams. Setting it `false` on a graph that *does* have + `agent` nodes still runs those nodes; only dynamic spawning from `llm` + nodes is disabled (the agent-recursion depth guard stays active either + way). `max_concurrent_agents` (default 4) and `max_agent_depth` + (default 3) cap dynamic spawning; the validator warns on zero values. - **`max_loop_iterations`:** This is a **per-node visit cap**, not a total graph-step cap. If the same node id is entered more than this many times, execution aborts with `Node 'X' visited N times (max_loop_iterations=...)`. @@ -230,6 +242,7 @@ research_topic: agent: deep-researcher # name of an existing Coyote agent prompt: "Research {{topic}}" # interpolated against state timeout: 600 # optional, in seconds (default 300) + teammates: false # optional; peer messaging with concurrent siblings (see below) state_updates: findings: "{{output}}" output_schema: { ... } # optional, see "Structured Output" below @@ -244,6 +257,11 @@ research_topic: whole graph fails (no built-in fallback path on agent nodes). - **`state_updates`:** Map of `state_key: "{{template}}"`. The child agent's final text is available inside this map as `{{output}}`. +- **`teammates`:** Opt-in peer messaging. When `true` and this node runs + concurrently with other flagged agent nodes (as branches of one `map` + fan-out, or alongside other `teammates: true` agent nodes in the same + super-step), the sibling sub-agents can message each other during the + run. See [Teammate messaging in fan-outs](#teammate-messaging-in-fan-outs). --- @@ -999,6 +1017,55 @@ invoking `research_subject` with `{{subject}}` bound to the item. Outputs are collected into `research_results` **in input order** regardless of which sub-branch finished first. +## Teammate messaging in fan-outs + +By default, concurrent sub-agents in a fan-out are mutually invisible: +each reports only through its own branch output. Setting `teammates: true` +on an `agent` node turns the concurrent siblings into a communicating +team: + +```yaml +review_file: + id: review_file + type: agent + agent: file-reviewer + prompt: "Review {{file}}" + teammates: true +``` + +Mechanics: + +- **Scope = one fan-out.** A team forms per `map` node (its branches) or + per super-step (the `teammates: true` agent nodes in that frontier), and + requires at least two members. Each fan-out gets its *own* registry: a + flagged map fan-out and a flagged agent node in the same super-step form + two separate teams and cannot message each other. +- **Pre-provisioned inboxes.** Every member's `(id, inbox)` pair is created + before any branch starts, so a fast sibling can message one that has not + started yet -- the message simply waits in its inbox. +- **Roster injection.** Each member's prompt gains a roster block naming + its teammates (collision-safe `graph_agent_*` ids plus human labels: + `branch[idx]` for map branches, the node id for super-step nodes). + Members can also rediscover peers at runtime via `agent__list_running`, + which lists them in a dedicated `peers` section. +- **Messaging only.** The team registry carries no lifecycle semantics: + peers are not collectible, do not count against `max_concurrent_agents`, + and outputs still flow exclusively through `collect_into` / state + reducers. Once a member finishes, sending to it returns an error -- its + results travel through the graph's collected outputs, not its inbox. +- **The registry dies with the fan-out.** If the node is done, so is the + team. + +Upward fan-in needs no flag: every branch already shares the graph agent's +own inbox, so children can `agent__send_message --id parent` at any time +and a downstream `llm` node can drain those findings with +`agent__check_inbox`. + +**When to use it:** research or implementation lanes where one branch's +discovery should redirect a sibling's work mid-flight. Leave it off for +independent-verdict lanes (e.g. parallel reviewers), where cross-talk +invites anchoring bias. + ## Reducers When two or more parallel branches write to the same state key in the