Expand description
§Agent SDK
A Rust SDK for building AI agents powered by large language models (LLMs).
This crate provides the infrastructure to build agents that can:
- Converse with users via multiple LLM providers
- Execute tools to interact with external systems
- Stream events in real-time for responsive UIs
- Persist conversation history and state
§Quick Start
use agent_sdk::{
builder, AgentEvent, ThreadId, ToolContext,
providers::AnthropicProvider,
};
// 1. Create an LLM provider
let api_key = std::env::var("ANTHROPIC_API_KEY")?;
let provider = AnthropicProvider::sonnet(api_key);
// 2. Build the agent
let agent = builder::<()>()
.provider(provider)
.build();
// 3. Run a conversation
let thread_id = ThreadId::new();
let ctx = ToolContext::new(());
let mut events = agent.run(thread_id, "Hello!".into(), ctx);
// 4. Process streaming events
while let Some(event) = events.recv().await {
match event {
AgentEvent::Text { text } => print!("{text}"),
AgentEvent::Done { .. } => break,
_ => {}
}
}§Core Concepts
§Agent Loop
The AgentLoop orchestrates the conversation cycle:
- User sends a message
- Agent sends message to LLM
- LLM responds with text and/or tool calls
- Agent executes tools and feeds results back to LLM
- Repeat until LLM responds with only text
Use builder() to construct an agent:
use agent_sdk::{builder, AgentConfig, providers::AnthropicProvider};
let agent = builder::<()>()
.provider(AnthropicProvider::sonnet(api_key))
.config(AgentConfig {
max_turns: 20,
system_prompt: "You are a helpful assistant.".into(),
..Default::default()
})
.build();§Tools
Tools let the LLM interact with external systems. Implement the Tool trait:
use agent_sdk::{Tool, ToolContext, ToolResult, ToolTier};
use async_trait::async_trait;
use serde_json::{json, Value};
struct WeatherTool;
#[async_trait]
impl Tool<()> for WeatherTool {
fn name(&self) -> &str { "get_weather" }
fn description(&self) -> &str {
"Get current weather for a city"
}
fn input_schema(&self) -> Value {
json!({
"type": "object",
"properties": {
"city": { "type": "string" }
},
"required": ["city"]
})
}
fn tier(&self) -> ToolTier { ToolTier::Observe }
async fn execute(
&self,
_ctx: &ToolContext<()>,
input: Value,
) -> anyhow::Result<ToolResult> {
let city = input["city"].as_str().unwrap_or("Unknown");
Ok(ToolResult::success(format!("Weather in {city}: Sunny, 72°F")))
}
}Register tools with ToolRegistry:
use agent_sdk::{builder, ToolRegistry, providers::AnthropicProvider};
let mut tools = ToolRegistry::new();
tools.register(WeatherTool);
let agent = builder::<()>()
.provider(AnthropicProvider::sonnet(api_key))
.tools(tools)
.build();§Tool Tiers
Tools are classified by permission level via ToolTier:
| Tier | Description | Example |
|---|---|---|
ToolTier::Observe | Read-only, always allowed | Get balance, read file |
ToolTier::Confirm | Requires user confirmation | Send email, write file |
ToolTier::RequiresPin | Requires PIN verification | Transfer funds |
§Lifecycle Hooks
Implement AgentHooks to intercept and control agent behavior:
use agent_sdk::{AgentHooks, ToolDecision, ToolResult, ToolTier};
use async_trait::async_trait;
use serde_json::Value;
struct MyHooks;
#[async_trait]
impl AgentHooks for MyHooks {
async fn pre_tool_use(
&self,
tool_name: &str,
_input: &Value,
tier: ToolTier,
) -> ToolDecision {
println!("Tool called: {tool_name}");
match tier {
ToolTier::Observe => ToolDecision::Allow,
ToolTier::Confirm => ToolDecision::RequiresConfirmation(
"Please confirm this action".into()
),
ToolTier::RequiresPin => ToolDecision::RequiresPin(
"Enter PIN to continue".into()
),
}
}
async fn post_tool_use(&self, tool_name: &str, result: &ToolResult) {
println!("{tool_name} completed: {}", result.success);
}
}Built-in hook implementations:
DefaultHooks- Tier-based permissions (default)AllowAllHooks- Allow all tools without confirmation (for testing)LoggingHooks- Debug logging for all events
§Events
The agent emits AgentEvents during execution for real-time updates:
| Event | Description |
|---|---|
AgentEvent::Start | Agent begins processing |
AgentEvent::Text | Text response from LLM |
AgentEvent::TextDelta | Streaming text chunk |
AgentEvent::ToolCallStart | Tool execution starting |
AgentEvent::ToolCallEnd | Tool execution completed |
AgentEvent::TurnComplete | One LLM round-trip finished |
AgentEvent::Done | Agent completed successfully |
AgentEvent::Error | An error occurred |
§Task Tracking
Use TodoWriteTool and TodoReadTool to track task progress:
use agent_sdk::todo::{TodoState, TodoWriteTool, TodoReadTool};
use std::sync::Arc;
use tokio::sync::RwLock;
let state = Arc::new(RwLock::new(TodoState::new()));
let write_tool = TodoWriteTool::new(Arc::clone(&state));
let read_tool = TodoReadTool::new(state);Task states: Pending (○), InProgress (⚡), Completed (✓)
§Custom Context
Pass application-specific data to tools via the generic type parameter:
use agent_sdk::{Tool, ToolContext, ToolResult, ToolTier};
use async_trait::async_trait;
use serde_json::Value;
// Your application context
struct AppContext {
user_id: String,
// database: Database,
}
struct UserInfoTool;
#[async_trait]
impl Tool<AppContext> for UserInfoTool {
fn name(&self) -> &str { "get_user_info" }
fn description(&self) -> &str { "Get info about current user" }
fn input_schema(&self) -> Value { serde_json::json!({"type": "object"}) }
async fn execute(
&self,
ctx: &ToolContext<AppContext>,
_input: Value,
) -> anyhow::Result<ToolResult> {
// Access your context
let user_id = &ctx.app.user_id;
Ok(ToolResult::success(format!("User: {user_id}")))
}
}§Modules
| Module | Description |
|---|---|
providers | LLM provider implementations |
primitive_tools | Built-in file operation tools (Read, Write, Edit, Glob, Grep, Bash) |
llm | LLM abstraction layer |
subagent | Nested agent execution with SubagentFactory |
mcp | Model Context Protocol support |
[todo] | Task tracking tools (TodoWriteTool, TodoReadTool) |
user_interaction | User question/confirmation tools (AskUserQuestionTool) |
web | Web search and fetch tools |
skills | Custom skill/command loading |
§Feature Flags
All features are enabled by default. The crate has no optional features currently.
Re-exports§
pub use llm::LlmProvider;pub use user_interaction::AskUserQuestionTool;pub use user_interaction::ConfirmationRequest;pub use user_interaction::ConfirmationResponse;pub use user_interaction::QuestionOption;pub use user_interaction::QuestionRequest;pub use user_interaction::QuestionResponse;pub use subagent::SubagentConfig;pub use subagent::SubagentFactory;pub use subagent::SubagentTool;pub use todo::TodoItem;pub use todo::TodoReadTool;pub use todo::TodoState;pub use todo::TodoStatus;pub use todo::TodoWriteTool;
Modules§
- context
- Context compaction for long-running conversations.
- llm
- mcp
- Model Context Protocol (MCP) client support.
- primitive_
tools - Primitive tools that work with the Environment abstraction.
- providers
- LLM Provider implementations.
- skills
- Skills system for loading agent behavior from markdown files.
- subagent
- Subagent support for spawning child agents.
- todo
- TODO task tracking for agents.
- user_
interaction - User interaction types and tools.
- web
- Web tools for search and fetching.
Structs§
- Agent
Capabilities - Capabilities that control what the agent can do.
- Agent
Config - Configuration for the agent loop
- Agent
Loop - The main agent loop that orchestrates LLM calls and tool execution.
- Agent
Loop Builder - Builder for constructing an
AgentLoop. - Agent
State - Snapshot of agent state for checkpointing
- Allow
AllHooks - Hooks that allow all tools without confirmation
- Default
Hooks - Default hooks implementation that uses tier-based decisions
- Exec
Result - Result from command execution
- File
Entry - Entry in a directory listing
- Grep
Match - Match result from grep operation
- InMemory
File System - In-memory filesystem for testing
- InMemory
Store - In-memory implementation of
MessageStoreandStateStore. Useful for testing and simple use cases. - Local
File System - Local filesystem implementation using
std::fs - Logging
Hooks - Hooks that log all events (useful for debugging)
- Null
Environment - A null environment that rejects all operations. Useful as a default when no environment is configured.
- Pending
Action - State of a pending action that requires confirmation or PIN
- Retry
Config - Configuration for retry behavior on transient errors.
- Thread
Id - Unique identifier for a conversation thread
- Token
Usage - Token usage statistics
- Tool
Context - Context passed to tool execution
- Tool
Registry - Registry of available tools
- Tool
Result - Result of a tool execution
Enums§
- Agent
Event - Events emitted by the agent loop during execution. These are streamed to the client for real-time UI updates.
- Tool
Decision - Decision returned by pre-tool hooks
- Tool
Tier - Permission tier for tools
Traits§
- Agent
Hooks - Lifecycle hooks for the agent loop. Implement this trait to customize agent behavior.
- Environment
- Environment abstraction for file and command operations.
- Message
Store - Trait for storing and retrieving conversation messages. Implement this trait to persist messages to your storage backend.
- State
Store - Trait for storing agent state checkpoints. Implement this to enable conversation recovery and resume.
- Tool
- Definition of a tool that can be called by the agent
Functions§
- builder
- Create a new builder for constructing an
AgentLoop.