BeamAgent

A general-purpose Elixir agent harness — the LLM tool-use loop, guardrails, and verification other developers can build agents on top of (a shopping agent, a research agent, a coding agent, a workflow or internal-automation agent, etc.). Named BeamAgent rather than Agent to avoid colliding with Elixir's own stdlib Agent module.

Elixir was chosen for the BEAM properties:

Usage

BeamAgent.API.run(
  "Find the cheapest supermarket for a weekly shop",
  llm: {MyApp.LLMClient, model: "..."},
  tools: %{price_check: MyApp.Tools.PriceCheck},
  guardrails: [max_iterations: 8, max_execution_time_ms: 30_000],
  verification: [required_tools: [:price_check]]
)
#=> {:ok, %BeamAgent.Run{}} | {:error, %BeamAgent.Run{}}

{:ok, run} only when the run finished and verification passed; everything else — a guardrail tripped, an unknown tool, a hard timeout, a runner crash, or verification failing a plausible-looking answer — comes back as {:error, run} with the reason on run. Every run.trace entry is retained either way, so a failure is fully inspectable, not just a bare error atom.

To plug in a real model, implement BeamAgent.LLM.Client (chat/2 :: {:reply, text} | {:tool_call, atom, map}). To add a tool, implement BeamAgent.Tools.Behaviour and pass it in the :tools map — tools aren't hardcoded into the harness, each run supplies its own.

Lifecycle and supervision

BeamAgent.API.run/2 starts one BeamAgent.Runner under BeamAgent.RunSupervisor and blocks the caller until a result is ready. Runs are restart: :temporary — a finished, failed, or crashed run is a terminal result to hand back to the caller, not a transient failure to retry, so there is no automatic restart.

See the telemetry reference for the supported events and their measurement, metadata, and privacy contract.

Two independent time limits can race, by design:

Notable features

Development

mix deps.get    # fetch dependencies
mix compile      # compile
mix test          # run the full test suite
mix format          # format per .formatter.exs