Packages

Multi-agent orchestration strategies for GenAgent. One ensemble process owns N sub-agents under a strategy (Solo, Supervisor, Pool, Pipeline).

Current section

Files

Jump to
gen_agent_ensemble lib gen_agent_ensemble.ex
Raw

lib/gen_agent_ensemble.ex

defmodule GenAgentEnsemble do
@moduledoc """
A session process that owns N `GenAgent` sub-agents under a strategy.
Where `GenAgent` gives you one process per LLM session, `GenAgentEnsemble`
gives you one process per *logical* session -- the single-agent case
is `GenAgentEnsemble.Strategies.Solo`, multi-agent patterns like
Supervisor or Pool are other strategies.
## Public API
{:ok, pid} = GenAgentEnsemble.start_link(
name: "research-1",
strategy: GenAgentEnsemble.Strategies.Solo,
opts: [agent: {"worker-a", MyAgent, backend: GenAgent.Backends.Mock}]
)
{:ok, token} = GenAgentEnsemble.tell("research-1", "hello")
{:ok, :pending} = GenAgentEnsemble.poll("research-1", token)
# ...later...
{:ok, :completed, response} = GenAgentEnsemble.poll("research-1", token)
{:ok, response} = GenAgentEnsemble.ask("research-1", "quick question", timeout: 30_000)
See `GenAgentEnsemble.Strategy` for how to implement your own strategy.
"""
@doc """
Start a new ensemble process. Takes `:name`, `:strategy`, and
`:opts` (the strategy's own options keyword list).
"""
defdelegate start_link(opts), to: GenAgentEnsemble.Server
@doc """
Fire-and-forget prompt. Returns `{:ok, token}` immediately; use
`poll/2` or `inbox/1` to retrieve the response later.
"""
defdelegate tell(name, prompt), to: GenAgentEnsemble.Server
@doc """
Like `tell/2` but with strategy-specific options (e.g.
`agent: "alice"` for Switchboard).
"""
defdelegate tell(name, prompt, opts), to: GenAgentEnsemble.Server
@doc """
Synchronous prompt. Blocks until the strategy replies or the
default timeout expires.
"""
defdelegate ask(name, prompt), to: GenAgentEnsemble.Server
@doc """
Like `ask/2` with options. Supports `timeout:` plus any
strategy-specific keys (e.g. `agent:` for Switchboard).
"""
defdelegate ask(name, prompt, opts), to: GenAgentEnsemble.Server
@doc """
Non-blocking check on a `tell`-minted token. Returns
`{:ok, :pending}`, `{:ok, :completed, response}`, or
`{:error, reason}`.
"""
defdelegate poll(name, token), to: GenAgentEnsemble.Server
@doc """
Drain every completed `tell` token since the last call. Returns
`{:ok, [{token, {:ok, response} | {:error, reason}}, ...]}`.
"""
defdelegate inbox(name), to: GenAgentEnsemble.Server
@doc """
Send an asynchronous event to the strategy (`handle_notify/2`).
"""
defdelegate notify(name, event), to: GenAgentEnsemble.Server
@doc """
Inspect the ensemble: running agents, strategy phase, queue depth.
"""
defdelegate status(name), to: GenAgentEnsemble.Server
@doc """
Stop the ensemble. Sub-agents are terminated in the process.
"""
defdelegate stop(name), to: GenAgentEnsemble.Server
@doc """
List the names of all running ensembles, sorted.
iex> GenAgentEnsemble.list()
["qa-pool", "solo"]
"""
@spec list() :: [String.t()]
def list do
GenAgentEnsemble.Registry
|> Registry.select([{{:"$1", :_, :_}, [], [:"$1"]}])
|> Enum.sort()
end
end