Sagents (Sagents v0.7.0)
Copy MarkdownSagents provides hierarchical agent capabilities with composable middleware.
Sagents extends LangChain with powerful features:
- Middleware System: Composable components for agent capabilities
- TODO Management: Task planning and progress tracking
- Virtual Filesystem: File operations for agent workflows
- Task Delegation: Hierarchical sub-agents for complex tasks
- Context Management: Automatic summarization and optimization
- Observability: Custom telemetry and tracing via middleware callbacks (see Observability Guide)
Quick Start
alias Sagents
alias LangChain.ChatModels.ChatAnthropic
# Create an agent
{:ok, agent} = Sagents.new(
model: ChatAnthropic.new!(%{model: "claude-sonnet-4-6"}),
system_prompt: "You are a helpful assistant."
)
# Execute with messages
{:ok, result} = Sagents.execute(agent, [
%{role: "user", content: "Hello!"}
])Middleware Composition
Sagents uses a middleware pattern for extensibility:
# Use default middleware (TODO, Filesystem, SubAgent, etc.)
{:ok, agent} = Sagents.new(
model: model,
middleware: [MyCustomMiddleware]
)
# Customize default middleware
{:ok, agent} = Sagents.new(
model: model,
filesystem_opts: [long_term_memory: true]
)
# Provide complete middleware stack
{:ok, agent} = Sagents.new(
model: model,
replace_default_middleware: true,
middleware: [MyMiddleware1, MyMiddleware2]
)Creating Custom Middleware
defmodule MyMiddleware do
@behaviour Sagents.Middleware
@impl true
def init(opts) do
{:ok, %{enabled: Keyword.get(opts, :enabled, true)}}
end
@impl true
def system_prompt(_config) do
"Custom instructions for the agent."
end
@impl true
def tools(_config) do
[my_custom_tool()]
end
@impl true
def before_model(state, _config) do
# Preprocess state before LLM
{:ok, state}
end
@impl true
def after_model(state, _config) do
# Postprocess after LLM response
{:ok, state}
end
endState Management
Agent state flows through middleware and execution:
state = State.new!(%{
messages: [%{role: "user", content: "Hello"}],
files: %{"/notes.txt" => "content"},
metadata: %{session_id: "123"}
})
{:ok, result_state} = Sagents.execute(agent, state)See Sagents.State for state management functions.
Summary
Functions
Execute an agent with the given state.
Execute an agent asynchronously.
Create a new Agent with default middleware stack.
Create a new Agent, raising on error.
Functions
Execute an agent with the given state.
Examples
# Execute with State struct
state = State.new!(%{messages: [%{role: "user", content: "Hello"}]})
{:ok, result_state} = Sagents.execute(agent, state)
# Execute with message list (convenience)
{:ok, result_state} = Sagents.execute(agent, [
%{role: "user", content: "Hello"}
])
Execute an agent asynchronously.
Returns a Task that can be awaited.
Examples
task = Sagents.execute_async(agent, messages)
{:ok, result_state} = Task.await(task)
Create a new Agent with default middleware stack.
This is a convenience function that delegates to Sagents.Agent.new/1 with
sensible defaults for common use cases.
Options
All options from Sagents.Agent.new/1 are supported. Common options:
:model- LangChain ChatModel struct (required):system_prompt- Base system instructions:tools- Additional tools beyond middleware:middleware- Extra middleware (appended to defaults):replace_default_middleware- Use only provided middleware (default: false):name- Agent name for identification
Examples
# Basic agent
{:ok, agent} = Sagents.new(
model: ChatAnthropic.new!(%{model: "claude-sonnet-4-6"}),
system_prompt: "You are helpful."
)
# With custom tools
{:ok, agent} = Sagents.new(
model: model,
tools: [calculator_tool, search_tool]
)
# With custom middleware
{:ok, agent} = Sagents.new(
model: model,
middleware: [LoggingMiddleware, MetricsMiddleware]
)
Create a new Agent, raising on error.
See new/1 for options.