ExAgent.Agent (ExAgent v0.2.0)

Copy Markdown View Source

GenServer that manages a single LLM agent.

Holds the provider struct in state and dispatches calls via the ExAgent.Provider behaviour. Contains the tool execution loop that automatically invokes tools when the LLM requests them.

State

The agent state includes:

  • provider - any struct implementing ExAgent.Provider
  • context - conversation history (ExAgent.Context)
  • tools - available tools for function-calling
  • skills - loadable skill definitions
  • active_skill - currently active skill (if any)

Summary

Functions

Sends a user message to the agent and returns the response.

Sends a user message asynchronously, returning a Task.

Sends a user message and returns a lazy Stream of the assistant's text chunks.

Returns a specification to start this module under a supervisor.

Returns the current conversation context.

Dynamically loads a skill into the agent.

Resets the agent's conversation context.

Starts an agent process linked to the current process.

Types

agent_opts()

@type agent_opts() :: [
  id: String.t(),
  provider: struct(),
  tools: [ExAgent.Tool.t()],
  skills: [ExAgent.Skill.t()],
  name: GenServer.name()
]

state()

@type state() :: %{
  id: String.t(),
  provider: struct(),
  context: ExAgent.Context.t(),
  tools: [ExAgent.Tool.t()],
  skills: [ExAgent.Skill.t()],
  active_skill: ExAgent.Skill.t() | nil,
  built_in_tools: [atom()],
  status: :idle | :processing | :handed_off,
  reply_to: GenServer.from() | nil,
  task_ref: reference() | nil
}

Functions

chat(agent, user_input, opts \\ [])

@spec chat(GenServer.server(), String.t(), keyword()) ::
  {:ok, ExAgent.Message.t()}
  | {:handoff, pid() | atom(), ExAgent.Context.t()}
  | {:error, term()}

Sends a user message to the agent and returns the response.

The agent appends the message to its context, evaluates skills, calls the LLM, and executes any requested tools in a loop until a final response or handoff is returned.

Options

  • :files - list of file attachments, each a map with :mime_type and either :data (binary) or :path (file path). Files become part of the conversation context and are sent to the LLM alongside the text message.
  • :built_in_tools - list of provider-specific built-in tools to enable for this message. Overrides the agent-level built_in_tools if provided. Examples: [:google_search], [:web_search], [:thinking].

Examples

ExAgent.Agent.chat(agent, "Describe this image",
  files: [%{path: "photo.jpg", mime_type: "image/jpeg"}])

ExAgent.Agent.chat(agent, "Search the web for Elixir news",
  built_in_tools: [:google_search])

chat_async(agent, user_input, opts \\ [])

@spec chat_async(GenServer.server(), String.t(), keyword()) :: Task.t()

Sends a user message asynchronously, returning a Task.

Accepts the same options as chat/3.

chat_stream(agent, user_input, opts \\ [])

@spec chat_stream(GenServer.server(), String.t(), keyword()) :: Enumerable.t()

Sends a user message and returns a lazy Stream of the assistant's text chunks.

Tool-call turns (if any tools are configured) are resolved first without streaming; only the final assistant turn is streamed. When no tools are configured the response is streamed directly.

The conversation context is committed when the stream is fully consumed, so the returned stream must be consumed (e.g. with Enum/Stream functions) for the agent to return to idle. Raises ExAgent.StreamError if the agent is busy with another request.

Examples

agent
|> ExAgent.Agent.chat_stream("Explain OTP step by step")
|> Enum.each(&IO.write/1)

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

get_context(agent)

@spec get_context(GenServer.server()) :: ExAgent.Context.t()

Returns the current conversation context.

load_skill(agent, skill)

@spec load_skill(GenServer.server(), ExAgent.Skill.t()) :: :ok

Dynamically loads a skill into the agent.

reset(agent)

@spec reset(GenServer.server()) :: :ok

Resets the agent's conversation context.

start_link(opts)

@spec start_link(agent_opts()) :: GenServer.on_start()

Starts an agent process linked to the current process.