ExAgent.Provider behaviour (ExAgent v0.2.0)

Copy Markdown View Source

Behaviour for LLM providers.

A provider is an interchangeable service (OpenAI, Gemini, DeepSeek, ...) implementing a shared capability. Each provider is a struct module that declares @behaviour ExAgent.Provider and implements chat/3 (required) and optionally upload/4. The provider struct carries its own config (api key, model, cached Req client) and is passed as the first argument.

This module also acts as the dispatcher: it forwards to the callback module resolved from the provider struct.

Implementations

Extensibility

To add a new provider, define a struct and implement this behaviour:

defmodule MyApp.Providers.CustomLLM do
  @behaviour ExAgent.Provider
  defstruct [:api_key, :model, :base_url, :system_prompt, :req, tools: []]

  @impl true
  def chat(provider, messages, opts) do
    # Your implementation here
  end
end

Summary

Callbacks

Sends a list of messages to the LLM and returns the assistant's response.

Streams the assistant's response as a lazy enumerable of text chunks.

Uploads binary file data to the provider and returns a file reference.

Functions

Dispatches a chat request to the provider's implementation.

Dispatches a streaming chat request to the provider's implementation.

Dispatches a file upload to the provider's implementation.

Callbacks

chat(provider, list, keyword)

@callback chat(provider :: struct(), [ExAgent.Message.t()], keyword()) ::
  {:ok, ExAgent.Message.t()}
  | {:tool_call, String.t(), map()}
  | {:error, term()}

Sends a list of messages to the LLM and returns the assistant's response.

Returns {:ok, message} for a regular response, {:tool_call, name, args} when the LLM wants to invoke a tool, or {:error, reason} on failure.

stream(provider, list, keyword)

(optional)
@callback stream(provider :: struct(), [ExAgent.Message.t()], keyword()) :: Enumerable.t()

Streams the assistant's response as a lazy enumerable of text chunks.

Optional — providers without streaming support omit this callback.

upload(provider, binary, t, keyword)

(optional)
@callback upload(provider :: struct(), binary(), String.t(), keyword()) ::
  {:ok, ExAgent.FileRef.t()} | {:error, term()}

Uploads binary file data to the provider and returns a file reference.

Optional — providers without file support (e.g. DeepSeek) omit this callback.

Functions

chat(provider, messages, opts \\ [])

@spec chat(struct(), [ExAgent.Message.t()], keyword()) ::
  {:ok, ExAgent.Message.t()}
  | {:tool_call, String.t(), map()}
  | {:error, term()}

Dispatches a chat request to the provider's implementation.

stream(provider, messages, opts \\ [])

@spec stream(struct(), [ExAgent.Message.t()], keyword()) :: Enumerable.t()

Dispatches a streaming chat request to the provider's implementation.

Returns a lazy enumerable of text chunks. Raises ArgumentError if the provider does not implement stream/3.

upload(provider, file_data, mime_type, opts \\ [])

@spec upload(struct(), binary(), String.t(), keyword()) ::
  {:ok, ExAgent.FileRef.t()} | {:error, term()}

Dispatches a file upload to the provider's implementation.

Returns {:error, {:unsupported, :upload, module}} if the provider does not implement upload/4.