ExAgent (ExAgent v0.1.0)

Copy Markdown View Source

An agent: model + instructions + tools + output spec, runnable as a loop that alternates between calling the model and executing tools until a final result is produced.

This is the heart of the framework. It follows a small loop:

UserPromptNode  ModelRequestNode  CallToolsNode  End

It is implemented as idiomatic Elixir recursion. Each recursive step issues a model request or handles returned tool calls; termination happens when the model returns a valid final response (no tool calls) or an empty response with allow_text_output.

Quick start

alias ExAgent

agent =
  ExAgent.new(
    model: "test",
    instructions: "Be concise."
  )

{:ok, %{output: text}} = ExAgent.run(agent, "Hello!")

Summary

Functions

Build an agent from options. Use :output for the output spec.

Run the agent against prompt, returning {:ok, result} or {:error, _}.

Run synchronously and return the output value directly, raising on error.

Run the agent, returning a lazy stream of events as the model generates.

Types

output_type()

@type output_type() :: :text | module()

result()

@type result() :: %{
  output: term(),
  messages: [ExAgent.Message.t()],
  new_messages: [ExAgent.Message.t()],
  usage: ExAgent.Message.Usage.t(),
  run_step: non_neg_integer()
}

t()

@type t() :: %ExAgent{
  capabilities: [module() | struct()],
  instructions: [ExAgent.Message.Part.System.t()],
  model: ExAgent.Model.model(),
  name: String.t() | nil,
  output_retries: non_neg_integer(),
  output_type: output_type(),
  settings: ExAgent.ModelSettings.t(),
  tool_timeout: pos_integer(),
  tools: [ExAgent.Tool.t()],
  usage_limits: ExAgent.UsageLimits.t() | nil
}

Functions

new(opts)

@spec new(keyword()) :: t()

Build an agent from options. Use :output for the output spec.

run(agent, prompt, opts \\ [])

@spec run(t(), String.t(), keyword()) :: {:ok, result()} | {:error, term()}

Run the agent against prompt, returning {:ok, result} or {:error, _}.

Options:

  • :deps — dependency value threaded into RunContext.
  • :message_history — prior Message.t() list to continue from.
  • :model_settings — per-run settings overrides.

run!(agent, prompt, opts \\ [])

@spec run!(t(), String.t(), keyword()) :: term()

Run synchronously and return the output value directly, raising on error.

run_stream(agent, prompt, opts \\ [])

@spec run_stream(t(), String.t(), keyword()) :: Enumerable.t()

Run the agent, returning a lazy stream of events as the model generates.

This is the streaming variant. It yields:

  • {:delta, binary} — incremental output text (one per model text chunk),
  • {:result, map} — the final result once the stream completes.

It is text-focused: best suited to chat / response-streaming UIs. Tool calls emitted mid-stream are not re-executed in this path (use run/3 for full agentic tool loops). The same per-run options as run/3 apply.