docs: Updated the docs to mention the new support for the teammate pattern in graph agents

Dark-Alex-17 committed 2026-09-09 16:44:01 -06:00
1 parent 8510337795
commit 527a19260f
2 files changed
+75 -3

No files matched your search

+5
@@ -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:
+70 -3
@@ -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