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, AgentInput, 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, _final_state) = agent.run(
thread_id,
AgentInput::Text("Hello!".to_string()),
ctx,
);
// 4. Process streaming events
while let Some(event) = events.recv().await {
match event {
AgentEvent::Text { message_id: _, 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::{DynamicToolName, Tool, ToolContext, ToolResult, ToolTier};
use serde_json::{json, Value};
use std::future::Future;
struct WeatherTool;
// No #[async_trait] needed - Rust 1.75+ supports native async traits
impl Tool<()> for WeatherTool {
type Name = DynamicToolName;
fn name(&self) -> DynamicToolName { DynamicToolName::new("get_weather") }
fn display_name(&self) -> &'static str { "Weather" }
fn description(&self) -> &'static 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 }
fn execute(
&self,
_ctx: &ToolContext<()>,
input: Value,
) -> impl Future<Output = anyhow::Result<ToolResult>> + Send {
async move {
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, DynamicToolName, 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, 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()
),
}
}
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::{DynamicToolName, Tool, ToolContext, ToolResult, ToolTier};
use serde_json::Value;
use std::future::Future;
// Your application context
struct AppContext {
user_id: String,
// database: Database,
}
struct UserInfoTool;
impl Tool<AppContext> for UserInfoTool {
type Name = DynamicToolName;
fn name(&self) -> DynamicToolName { DynamicToolName::new("get_user_info") }
fn display_name(&self) -> &'static str { "User Info" }
fn description(&self) -> &'static str { "Get info about current user" }
fn input_schema(&self) -> Value { serde_json::json!({"type": "object"}) }
fn execute(
&self,
ctx: &ToolContext<AppContext>,
_input: Value,
) -> impl Future<Output = anyhow::Result<ToolResult>> + Send {
let user_id = ctx.app.user_id.clone();
async move {
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 |
reminders | System reminder infrastructure for agent guidance |
§System Reminders
The SDK includes a reminder system that provides contextual guidance to the AI agent
using the <system-reminder> XML tag pattern. Claude is trained to recognize these
tags and follow the instructions without mentioning them to users.
use agent_sdk::reminders::{wrap_reminder, ReminderConfig, ReminderTracker};
// Wrap guidance in system-reminder tags
let reminder = wrap_reminder("Verify the output before proceeding.");
// Configure reminder behavior
let config = ReminderConfig::new()
.with_todo_reminder_turns(5)
.with_repeated_action_threshold(3);§Feature Flags
All features are enabled by default. The crate has no optional features currently.
Re-exports§
pub use llm::LlmProvider;pub use llm::ThinkingConfig;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;pub use reminders::ReminderConfig;pub use reminders::ReminderTracker;pub use reminders::ReminderTrigger;pub use reminders::ToolReminder;pub use reminders::append_reminder;pub use reminders::wrap_reminder;
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.
- reminders
- System reminder infrastructure for agent guidance.
- 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
Continuation - Continuation state that allows resuming the agent loop.
- Agent
Error - Error from 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
- Dynamic
Tool Name - Dynamic tool name for runtime-created tools (MCP bridges, subagents).
- Exec
Result - Result from command execution
- File
Entry - Entry in a directory listing
- Grep
Match - Match result from grep operation
- InMemory
Execution Store - In-memory implementation of
ToolExecutionStore. - 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
Tool Call Info - Information about a pending tool call that was extracted from the LLM response.
- 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
Execution - Record of a tool execution for idempotency.
- 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.
- Agent
Input - Input to start or resume an agent run.
- Agent
RunState - Outcome of running the agent loop.
- Erased
Tool Status - Type-erased status for the agent loop.
- Execution
Status - Status of a tool execution for idempotency tracking.
- Primitive
Tool Name - Tool names for SDK’s built-in primitive tools.
- Tool
Decision - Decision returned by pre-tool hooks
- Tool
Outcome - Result of tool execution - may indicate async operation in progress.
- Tool
Status - Status update from an async tool operation.
- Tool
Tier - Permission tier for tools
- Turn
Outcome - Outcome of running a single turn.
Traits§
- Agent
Hooks - Lifecycle hooks for the agent loop. Implement this trait to customize agent behavior.
- Async
Tool - A tool that performs long-running async operations.
- Environment
- Environment abstraction for file and command operations.
- Erased
Async Tool - Type-erased async tool trait for registry storage.
- Erased
Tool - Type-erased tool trait for registry storage.
- Message
Store - Trait for storing and retrieving conversation messages. Implement this trait to persist messages to your storage backend.
- Progress
Stage - Marker trait for tool progress stages (type-safe, like
ToolName). - 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.
- Tool
Execution Store - Store for tracking tool executions (idempotency).
- Tool
Name - Marker trait for tool names.
Functions§
- builder
- Create a new builder for constructing an
AgentLoop. - stage_
to_ string - Helper to get string representation of a progress stage via serde.
- tool_
name_ from_ str - Parse a tool name from string via serde.
- tool_
name_ to_ string - Helper to get string representation of a tool name via serde.