ExAgent.Coordination (ExAgent v1.2.0)

Copy Markdown 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 delegate's token usage is merged into the parent run'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.

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

delegation_tool(delegate, opts \\ [])

@spec delegation_tool(
  ExAgent.t() | (map(), map() -> ExAgent.t()),
  keyword()
) :: ExAgent.Tool.t()

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. The delegate's token usage is merged into the parent run's accumulated usage — so limits and cost accounting cover the whole delegation tree, not just the parent.

Arguments

  • delegate — an ExAgent.t(), or a builder (ctx, args -> ExAgent.t()) so the delegate can be constructed lazily with the parent's context (e.g. to forward deps or pick a model per call).
  • opts:name (default "delegate"), :description, :max_retries (default 1), :prompt_arg (default "prompt").

Example

delegate = ExAgent.new(model: "openai:gpt-4o-mini", instructions: "You summarize.")
parent =
  ExAgent.new(
    model: "openai:gpt-4o",
    tools: [ExAgent.Coordination.delegation_tool(delegate, name: "summarize")]
  )

The parent model can then call summarize(prompt: "...") to hand a sub-task to the cheaper model and get its result back, with both runs' tokens counted together.

handoff(session, to_id)

@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).