Installation
Quick Start
use ;
async
Use Cases
Example applications built with this project:
- Terminal REPL: interactive terminal chat with less than 100 lines of code
- Project Scanner: scan and analyze local files
- Divide and Conquer: partition a math problem across an agent pool
- Deep Research: multi-agent research with web search (requires
BRAVE_API_KEY) - Model Pricing Tracker: check model prices
Consider configuring your LLM provider (see Environment).
API
- Providers: multi-provider support
- Agents: the base interface
- Models: context window auto-detection
- Prompting: identity, instruction, context, behavior
- Tools: built-in file, search, shell, and web tools
- Events: agent and provider activity
- Guardrails: retries, token caps, and turn limits
- AgentOutput: validated, schema-based responses
- Sub-agents: nested workers
- Batches: parallel execution
- Todo: planned work
Providers
You can integrate your agentic application with the following providers:
use ;
let provider = new;
let provider = new;
let provider = new;
let provider = new;
Agents
The Agent interface is the main entry point. Build with Agent::new(), chain configurations, then call .run():
let output = new
.provider
.model_name
.instruction_prompt
.tool
.run
.await?;
Keep Agents Alive
Use .spawn() when you want to keep sending instructions to your agent:
let = new
.provider
.model_name
.identity_prompt
.tool
.spawn;
agent.send;
agent.send;
agent.cancel;
let output = output.await?;
The agent waits for the next send after each reply. Call cancel() to stop it.
Methods on the spawned agent:
| Method | Description |
|---|---|
.send(instruction) |
Send a new instruction |
.cancel() |
Stop the agent |
.is_cancelled() |
Check if the agent was cancelled |
.clone() |
Get another handle to the same agent |
Models
You can configure each agent to use a single model:
new.model_name
new.model
Prompting
Prompts are the core ingredient of every agentic application. Here are different prompt types which can be used to drive your agent's behavior.
use Agent;
let output = new
.provider
.model_name
.identity_prompt
.instruction_prompt
.tool
.run
.await?;
The following methods on Agent configure prompts:
| Method | Description |
|---|---|
.identity_prompt(_file) |
Persistent identity of the agent |
.instruction_prompt(_file) |
Task for the current run |
.context_prompt(_file) |
Additional context appended after environment metadata (working directory, platform, OS version, date) |
.behavior_prompt(_file) |
Override the default behavioral directives (DEFAULT_BEHAVIOR_PROMPT) |
new
.identity_prompt_file
.instruction_prompt
.behavior_prompt_file
Use {key} placeholders in the identity prompt and fill them with template_variable:
new
.identity_prompt
.template_variable
.template_variable
Tools
Give your agent access to simple tools for driving tasks:
use ;
let tool = new
.schema
.read_only
.handler;
Use
.read_only(true)when a tool has no side effects. If set, the the execution loop will run tools in parallel.
Built-in tools
| Tool | Description | |
|---|---|---|
| File | ReadFileTool |
Read a file with line numbers, offset, and limit |
WriteFileTool |
Create or overwrite a file | |
EditFileTool |
Find-and-replace in a file | |
| Search | GlobTool |
Find files by pattern |
GrepTool |
Search file contents by substring | |
ListDirectoryTool |
List directory entries with type and size | |
| Web | WebFetchTool |
Fetch a URL and return its content as text |
| Utility | BashTool |
Execute shell commands matching a glob pattern |
SpawnAgentTool |
Delegate work to a sub-agent | |
SendMessageTool |
Send messages to other agents | |
TaskTool |
Perform task management | |
ToolSearchTool |
Discover available tools by keyword |
use ;
let agent = new
.tool
.tool
.tool
.tool
.tool
.tool
.tool
.tool
.tool
.tool
.tool
.tool
.run.await?;
Events
You can inspect what your agent is doing and how the LLM provider API is used:
use ;
let handler = new;
When
.event_handler(...)is not set, agents log tool activity and lifecycle events to stderr viaEvent::default_logger(). You can call.silent()on the agent to silence the output.
| Kind | Description | |
|---|---|---|
| Agent | AgentStarted |
Agent run began |
AgentFinished |
Agent run finished | |
TurnStarted |
Agentic loop turn began | |
TurnFinished |
Agentic loop turn finished | |
AgentPaused |
Keep-alive agent is waiting for new input | |
AgentResumed |
Keep-alive agent resumed after being paused | |
| Provider | RequestStarted |
Provider request began |
RequestFinished |
Provider request finished | |
RequestRetried |
Transient provider error triggered a retry | |
RequestError |
Provider request failed after exhausting retries | |
TextChunkReceived |
Streamed text token arrived | |
TokensReported |
Provider reported token counts for the last request | |
| Context | OutputTruncated |
Response was cut off at the configured length cap |
ContextCompacted |
Conversation history was compacted to stay within the model's window | |
InputBudgetExhausted |
Cumulative input tokens crossed max_input_tokens |
|
OutputBudgetExhausted |
Cumulative output tokens crossed max_output_tokens |
|
| Tool | ToolCallStarted |
Tool invocation began |
ToolCallFinished |
Tool invocation succeeded | |
ToolCallError |
Tool invocation failed |
Guardrails
For protecting your budget or data, you can define clear execution rules for typical LLM failures. You can configure the following on your Agent:
| Method | Default | Description |
|---|---|---|
.max_turns(10) |
no limit | Stop after N agentic loop iterations |
.max_request_tokens(4096) |
provider default | Cap output tokens per LLM request |
.max_input_tokens(200_000) |
no limit | Cap cumulative input tokens across the whole run |
.max_output_tokens(50_000) |
no limit | Cap cumulative output tokens across the whole run |
.max_schema_retries(3) |
10 | Retry structured output compliance |
.max_request_retries(5) |
10 | Retry on API errors (429, 529, 5xx) |
.request_retry_delay(2000) |
500 | Base delay in milliseconds for exponential backoff between request retries |
AgentOutput
The result of running an agent.
output.response_raw // Raw LLM output
output.response // validated with schema
output.statistics.input_tokens // total input tokens
output.statistics.output_tokens// total output tokens
output.statistics.requests // number of LLM requests
output.statistics.tool_calls // number of tool calls
output.statistics.turns // number of loop turns
With an output schema, the agent returns validated JSON:
let output = new
.output_schema
.max_schema_retries
.run.await?;
output.response.unwrap
Or load the schema from a file:
let output = new
.output_schema_file
.run.await?;
Sub-agents
Sub-agents allow orchestrator agents to launch her own workers.
Orchestrator agents automatically have access to the SpawnAgentTool.
let researcher_base = new
.model_name
.identity_prompt
.tool
.max_turns;
let r1 = researcher_base.clone.name;
let r2 = researcher_base.clone.name;
let output = new
.name
.identity_prompt
.sub_agents
Inheritance
The following fields are inherited, shared or owned by the sub-agents:
| Behavior | Fields |
|---|---|
| Inherited | provider, model, working_directory, event_handler, cancel_signal |
| Shared | command_queue, session_store |
| Per sub-agent | identity_prompt, instruction_prompt, behavior_prompt, context_prompt, tools, output_schema, max_turns, max_request_tokens, max_input_tokens, max_output_tokens, max_schema_retries, max_request_retries, request_retry_delay |
Batches
Run many agents in parallel with Batch.
Static Batch
Wait for the execution of all agents in a fixed sized pool. Results arrive in submission order:
use ;
let template = new
.provider
.model_name
.tool;
let docs = ;
let agents = docs.iter.map;
let results = new
.concurrency
.agents
.run
.await;
for in docs.iter.zip
Dynamic Number of Agents
Start a dynamic pool of agents, which might grow over time. Results stream back in completion order:
let = new
.concurrency
.spawn;
let docs = ;
for doc in &docs
pool.drain;
while let Some = results.next.await
BatchHandle::submit returns the index it assigned, so dynamic callers can keep a parallel map of index → context.
| Method | Description |
|---|---|
.submit(agent) |
Enqueue another agent |
.drain() |
Stop adding new agents and let running agents finish |
.cancel() |
Interrupt in-flight agents and close the pool |
.is_cancelled() |
Check if the pool was cancelled |
.clone() |
Get another handle to the same pool |
Todo
Planned additions to the crate:
- Context compression: summarize older messages when a conversation exceeds the LLM context window
- Session state handling: resume and persist agent sessions across runs
Development
Building and testing
Integration tests
Consider configuring your LLM provider (see Environment).
Use cases
Publishing
LiteLLM proxy
Start a local LiteLLM proxy on port 4000 that forwards to a provider. Requires Docker.
Local inference servers
agentwerk relies on server-side tool calling. You can enable it through the following flags:
| Server | Flag |
|---|---|
| vLLM | --enable-auto-tool-choice --tool-call-parser <parser> |
| SGLang | --tool-call-parser <parser> |
llama.cpp llama-server |
--jinja (enables tool calling) |
| Ollama | tool calling enabled by default |
Environment
Use cases and integration tests use the following environment variables:
General
| Variable | Description |
|---|---|
LITELLM_PROVIDER |
Explicit provider selection (anthropic, mistral, openai, litellm). Skips auto-detection |
Anthropic
| Variable | Description |
|---|---|
ANTHROPIC_API_KEY |
API key (required) |
ANTHROPIC_BASE_URL |
API URL (default: https://api.anthropic.com) |
ANTHROPIC_MODEL |
Model (default: claude-sonnet-4-20250514) |
Mistral
| Variable | Description |
|---|---|
MISTRAL_API_KEY |
API key (required) |
MISTRAL_BASE_URL |
API URL (default: https://api.mistral.ai) |
MISTRAL_MODEL |
Model (default: mistral-medium-2508) |
OpenAI
| Variable | Description |
|---|---|
OPENAI_API_KEY |
API key (required) |
OPENAI_BASE_URL |
API URL (default: https://api.openai.com) |
OPENAI_MODEL |
Model (default: gpt-4o) |
LiteLLM proxy
| Variable | Description |
|---|---|
LITELLM_BASE_URL |
Proxy URL (default: http://localhost:4000) |
LITELLM_API_KEY |
Auth key (optional) |
LITELLM_MODEL |
Model (default: claude-sonnet-4-20250514) |
LITELLM_PROVIDER |
LLM provider (default: anthropic, options: anthropic, mistral, openai) |