ExAgent. Coordination
(ExAgent v2.1.0)
View Source
Orchestration patterns on top of ExAgent.Session and the core loop.
These cover pydanticAI's complexity levels 2 and 3:
- Delegation (level 2) — an agent calls another agent as a tool. The delegate runs its own model⇄tools loop and its output is returned to the parent; the shared execution scope accounts for the delegate's usage.
- Hand-off (level 3) — application code (or a supervisor agent) transfers control between participants in a Session.
These complement — but don't replace — the BEAM-native coordination model: in ExAgent, multiple agents are usually separate supervised processes that message each other, rather than one agent calling another as a tool. Delegation is provided for parity with the pydanticAI pattern and for cases where nesting a sub-agent inside a tool is genuinely the simplest design.
ExAgent.Coordination.Composition executes and resumes trusted durable sequences.
ExAgent.Coordination.Flow adds a versioned host router and bounded parallel
fan-out/fan-in with ordered outcomes, fail-fast/collect and the same C7 approvals.
Structural roots have no Model request; leaves use the original agent loop.
Summary
Functions
Build an ExAgent.Tool that delegates a sub-task to another agent.
Hand off control within a ExAgent.Session from the current participant to
to_id, bypassing the normal turn policy. Emits :session_turn_changed.
Functions
Build an ExAgent.Tool that delegates a sub-task to another agent.
When the parent agent's model calls this tool, delegate is run with the
tool's prompt argument (a one-shot ExAgent.run/3) and its output is
returned to the parent. Requests/tools are admitted against every ancestor's
limits before execution and usage is reconciled in the shared ledger, including
failed delegates. The returned tool value never adds that usage a second time.
Arguments
delegate— anExAgent.t(), or a builder(ctx, args -> ExAgent.t())so the delegate can be constructed lazily with the parent's context (e.g. to forwarddepsor pick a model per call).opts—:name(default"delegate"),:description,:max_retries(default1),:prompt_arg(string, default"prompt"). Optional:permissions,:approve,:deadline,:max_concurrent_requestsand:estimate_costconfigure child restrictions/pricing; none override an ancestor's policy or limits. Builders only choose the child definition.
Example
chat_model is an explicitly configured ExAgent.Models.ReqLLM instance with
credentials and the qualified :chat_tools_v1 profile (see the README recipe).
delegate = ExAgent.new(model: chat_model, instructions: "You summarize.")
parent =
ExAgent.new(
model: chat_model,
tools: [ExAgent.Coordination.delegation_tool(delegate, name: "summarize")]
)The parent model can then call summarize(prompt: "...") to hand a sub-task
to the delegate and get its result back, with both runs' tokens counted
together.
@spec handoff(GenServer.server(), term()) :: {:ok, term()} | {:error, term()}
Hand off control within a ExAgent.Session from the current participant to
to_id, bypassing the normal turn policy. Emits :session_turn_changed.
This is the BEAM-native equivalent of a programmatic hand-off: control moves
directly between participants by message. After to_id takes its turn, the
policy resumes its normal ordering from there.
Returns {:ok, to_id} or {:error, reason} (:not_running, :not_a_participant).