Current section

Files

Jump to
sagents lib sagents factory.ex
Raw

lib/sagents/factory.ex

defmodule Sagents.Factory do
@moduledoc """
Behaviour for modules that build `%Sagents.Agent{}` instances from
validated configuration.
## Contract
A factory implements one callback:
@callback create_agent(agent_id :: String.t(), config :: term()) ::
{:ok, Sagents.Agent.t(), session_opts :: keyword()}
| {:error, term()}
- `agent_id` is generated by `Sagents.Session` from the conversation ID
via the configured `agent_id_fun`. It is system-supplied, opaque to
the factory's domain logic.
- `config` is whatever the configured `Sagents.FactoryRouter` returned
as the third element of `{:ok, factory_module, config}`. The library
treats it as opaque and forwards it verbatim. By convention, `config`
is a typed struct (commonly an `Ecto.Schema embedded_schema`) defined
by a paired `*Config` module — see the host's generated
`FactoryConfig` for the canonical shape.
## Returns
- `{:ok, agent, session_opts}` — successful build. `session_opts` is a
keyword list with library-recognized keys:
- `:fresh_state_attrs` — map seeded into `Sagents.State.new!/1` only
on fresh state (ignored on resume).
- `:supervisor_opts` — keyword list merged into the supervisor child
config (e.g. `:message_preprocessor`).
- All other keys are app-internal; the library forwards but does not
inspect them.
- `{:error, reason}` — propagated up the session-start path.
## Example
defmodule MyApp.Agents.Factory do
@behaviour Sagents.Factory
alias Sagents.Agent
alias MyApp.Agents.FactoryConfig
@impl true
def create_agent(agent_id, %FactoryConfig{} = c) do
agent =
Agent.new!(%{
agent_id: agent_id,
scope: c.scope,
model: build_model(c),
base_system_prompt: base_system_prompt(c),
middleware: build_middleware(c),
tools: build_tools(c),
tool_context: c.tool_context
})
{:ok, agent, []}
end
end
"""
@callback create_agent(agent_id :: String.t(), config :: term()) ::
{:ok, Sagents.Agent.t(), session_opts :: keyword()}
| {:error, term()}
end