A high-performance Rust framework for building AI agents with custom tools, sub-agents, and persistent state management. Built for production use with enterprise-grade features like token tracking, cost monitoring, and human-in-the-loop workflows.
- Streaming Events: Real-time token-by-token event broadcasting for streaming responses
- StreamingToken Events: New
AgentEvent::StreamingTokenvariant for live updates - Opt-in Streaming: Broadcasters can enable streaming via
supports_streaming()method - Backward Compatible: Existing broadcasters work unchanged (streaming disabled by default)
- Enhanced Streaming:
handle_message_stream()now emits events for SSE/WebSocket integrations - Example: New
streaming-events-demoshowing real-time token broadcasting
Add to your Cargo.toml:
[dependencies]
agents-sdk = "0.0.24"
tokio = { version = "1.0", features = ["full"] }
anyhow = "1.0"use agents_sdk::{ConfigurableAgentBuilder, OpenAiConfig, OpenAiChatModel, get_default_model};
use agents_macros::tool;
use agents_core::state::AgentStateSnapshot;
use std::sync::Arc;
// Define a tool using the #[tool] macro
#[tool("Adds two numbers together")]
fn add(a: i32, b: i32) -> i32 {
a + b
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// Create OpenAI configuration
let config = OpenAiConfig::new(
std::env::var("OPENAI_API_KEY")?,
"gpt-4o-mini"
);
// Create the model
let model = Arc::new(OpenAiChatModel::new(config)?);
// Build an agent with tools
let agent = ConfigurableAgentBuilder::new("You are a helpful math assistant.")
.with_model(model)
.with_tool(AddTool::as_tool())
.build()?;
// Use the agent
let response = agent.handle_message(
"What is 5 + 3?",
Arc::new(AgentStateSnapshot::default())
).await?;
println!("{}", response.content.as_text().unwrap_or("No response"));
Ok(())
}The ConfigurableAgentBuilder provides a fluent interface for constructing agents:
use agents_sdk::{ConfigurableAgentBuilder, OpenAiConfig, OpenAiChatModel, AnthropicConfig, AnthropicMessagesModel, GeminiConfig, GeminiChatModel};
use std::sync::Arc;
// OpenAI
let config = OpenAiConfig::new(api_key, "gpt-4o-mini")?;
let model = Arc::new(OpenAiChatModel::new(config)?);
let agent = ConfigurableAgentBuilder::new("You are a helpful assistant")
.with_model(model)
.build()?;
// Anthropic
let config = AnthropicConfig::new(api_key, "claude-3-5-sonnet-20241022")?;
let model = Arc::new(AnthropicMessagesModel::new(config)?);
let agent = ConfigurableAgentBuilder::new("You are a helpful assistant")
.with_model(model)
.build()?;
// Gemini
let config = GeminiConfig::new(api_key, "gemini-2.0-flash-exp")?;
let model = Arc::new(GeminiChatModel::new(config)?);
let agent = ConfigurableAgentBuilder::new("You are a helpful assistant")
.with_model(model)
.build()?;Define tools using the #[tool] macro:
use agents_macros::tool;
// Simple synchronous tool
#[tool("Multiplies two numbers")]
fn multiply(a: f64, b: f64) -> f64 {
a * b
}
// Async tool
#[tool("Fetches user data from API")]
async fn get_user(user_id: String) -> String {
// Make API call...
format!("User {}", user_id)
}
// Tool with optional parameters
#[tool("Searches with optional filters")]
fn search(query: String, max_results: Option<u32>) -> Vec<String> {
let limit = max_results.unwrap_or(10);
// Perform search...
vec![]
}
// Use the tools
let agent = ConfigurableAgentBuilder::new("You are a helpful assistant")
.with_model(model)
.with_tools(vec![
MultiplyTool::as_tool(),
GetUserTool::as_tool(),
SearchTool::as_tool(),
])
.build()?;Choose from multiple persistence backends:
use agents_sdk::{ConfigurableAgentBuilder, InMemoryCheckpointer, RedisCheckpointer};
// In-memory (development)
let checkpointer = Arc::new(InMemoryCheckpointer::new());
// Redis (production)
let checkpointer = Arc::new(
RedisCheckpointer::new("redis://127.0.0.1:6379").await?
);
let agent = ConfigurableAgentBuilder::new("You are a helpful assistant")
.with_model(model)
.with_checkpointer(checkpointer)
.build()?;
// Save and load state across sessions
let thread_id = "user-123";
agent.save_state(&thread_id).await?;
agent.load_state(&thread_id).await?;Monitor LLM usage and costs with built-in token tracking:
use agents_sdk::{ConfigurableAgentBuilder, TokenTrackingConfig, TokenCosts};
// Enable token tracking with default settings
let model = Arc::new(OpenAiChatModel::new(config)?);
let agent = ConfigurableAgentBuilder::new("You are a helpful assistant")
.with_model(model)
.with_token_tracking(true) // Enable with defaults
.build()?;
// Or configure with custom settings
let token_config = TokenTrackingConfig {
enabled: true,
emit_events: true,
log_usage: true,
custom_costs: Some(TokenCosts::openai_gpt4o_mini()),
};
let model = Arc::new(OpenAiChatModel::new(config)?);
let agent = ConfigurableAgentBuilder::new("You are a helpful assistant")
.with_model(model)
.with_token_tracking_config(token_config)
.build()?;Features:
- Real-time token usage tracking
- Cost estimation with predefined pricing models
- Performance metrics (duration, throughput)
- Event broadcasting integration
- Flexible configuration options
Require human approval for critical operations:
use agents_sdk::{ConfigurableAgentBuilder, HitlPolicy};
use std::collections::HashMap;
// Configure HITL policies
let mut policies = HashMap::new();
policies.insert(
"delete_file".to_string(),
HitlPolicy {
allow_auto: false,
note: Some("File deletion requires security review".to_string()),
}
);
let agent = ConfigurableAgentBuilder::new("You are a helpful assistant")
.with_model(model)
.with_tool_interrupts(policies)
.with_checkpointer(checkpointer) // Required for HITL
.build()?;
// Handle interrupts
match agent.handle_message("Delete the old_data.txt file", state).await {
Ok(response) => {
// Check if execution was paused
if let Some(text) = response.content.as_text() {
if text.contains("paused") || text.contains("approval") {
// HITL was triggered!
if let Some(interrupt) = agent.current_interrupt().await? {
println!("Tool: {}", interrupt.tool_name);
println!("Args: {}", interrupt.tool_args);
}
}
}
}
Err(e) => println!("Error: {}", e),
}
// Resume with approval
agent.resume_with_approval(HitlAction::Accept).await?;Real-time progress tracking and multi-channel notifications:
use agents_sdk::{ConfigurableAgentBuilder, EventBroadcaster};
use agents_core::events::AgentEvent;
use async_trait::async_trait;
struct ConsoleLogger;
#[async_trait]
impl EventBroadcaster for ConsoleLogger {
fn id(&self) -> &str { "console" }
async fn broadcast(&self, event: &AgentEvent) -> anyhow::Result<()> {
match event {
AgentEvent::AgentStarted(e) => println!("π Agent started: {}", e.agent_name),
AgentEvent::ToolStarted(e) => println!("π§ Tool started: {}", e.tool_name),
AgentEvent::ToolCompleted(e) => println!("β
Tool completed: {}", e.tool_name),
AgentEvent::TokenUsage(e) => println!("π Token usage: ${:.4}", e.usage.estimated_cost),
_ => {}
}
Ok(())
}
}
let agent = ConfigurableAgentBuilder::new("You are a helpful assistant")
.with_model(model)
.with_event_broadcaster(Arc::new(ConsoleLogger))
.build()?;Built-in security features prevent PII leakage:
// PII sanitization is enabled by default
let agent = ConfigurableAgentBuilder::new("You are a helpful assistant")
.with_model(model)
.build()?;
// Events automatically have:
// - Message previews truncated to 100 characters
// - Sensitive fields (passwords, tokens, etc.) redacted
// - PII patterns (emails, phones, credit cards) removed
// Disable only if you need raw data and have other security measures
let agent = ConfigurableAgentBuilder::new("You are a helpful assistant")
.with_model(model)
.with_pii_sanitization(false) // Not recommended for production
.build()?;Delegate tasks to specialized sub-agents:
use agents_sdk::{ConfigurableAgentBuilder, SubAgentConfig};
let subagent = SubAgentConfig {
name: "data-processor".to_string(),
description: "Processes complex data with custom logic".to_string(),
instructions: "You are a data processing specialist.".to_string(),
tools: vec![/* specialized tools */],
};
let agent = ConfigurableAgentBuilder::new("You are a helpful assistant")
.with_model(model)
.with_subagent(subagent)
.with_auto_general_purpose(true) // Enable automatic delegation
.build()?;The SDK includes useful built-in tools:
let agent = ConfigurableAgentBuilder::new("You are a helpful assistant")
.with_model(model)
.with_builtin_tools(vec![
"write_todos".to_string(),
"ls".to_string(),
"read_file".to_string(),
"write_file".to_string(),
])
.build()?;Optimize performance with prompt caching:
let agent = ConfigurableAgentBuilder::new("You are a helpful assistant")
.with_model(model)
.with_prompt_caching(true)
.build()?;The SDK includes comprehensive examples:
simple-agent- Basic agent with OpenAItoken-tracking-demo- Token usage monitoringhitl-financial-advisor- Human-in-the-loop workflowsevent-system-demo- Event broadcastingcheckpointer-demo- State persistencesubagent-demo- Sub-agent delegation
Run examples:
# Clone the repository
git clone https://github.com/yafatek/rust-deep-agents-sdk.git
cd rust-deep-agents-sdk
# Run a specific example
cargo run --example simple-agent
cargo run --example token-tracking-democrates/agents-core- Core traits, message structures, and state modelscrates/agents-runtime- Runtime engine, builders, and middlewarecrates/agents-toolkit- Built-in tools and utilitiescrates/agents-aws- AWS integrations (DynamoDB, Secrets Manager)crates/agents-persistence- Persistence backends (Redis, PostgreSQL)crates/agents-sdk- Unified SDK with feature flagsexamples/- Working examples and demosdocs/- Documentation and guides
The SDK includes a powerful middleware system:
- Planning Middleware: Todo list management
- Filesystem Middleware: Mock filesystem operations
- SubAgent Middleware: Task delegation
- HITL Middleware: Human approval workflows
- Token Tracking Middleware: Usage and cost monitoring
- Summarization Middleware: Context window management
- PII Sanitization: Automatic data protection
- OpenAI: GPT models (gpt-4o, gpt-4o-mini, gpt-4-turbo, gpt-3.5-turbo)
- Anthropic: Claude models (claude-3-5-sonnet-20241022, claude-3-haiku-20240307)
- Gemini: Google's Gemini models (gemini-2.0-flash-exp, gemini-1.5-pro)
git clone https://github.com/yafatek/rust-deep-agents-sdk.git
cd rust-deep-agents-sdk
# Format, lint, and test
cargo fmt
cargo clippy --all-targets --all-features -- -D warnings
cargo test --all
# Build release
cargo build --releaseThe SDK supports feature flags for modular functionality:
[dependencies]
agents-sdk = { version = "0.0.23", features = ["aws", "redis"] }
# Available features:
# - "aws" - AWS integrations (DynamoDB, Secrets Manager)
# - "redis" - Redis persistence backend
# - "postgres" - PostgreSQL persistence backend
# - "dynamodb" - DynamoDB persistence backend
# - "full" - All features enabledRequired environment variables:
# OpenAI
export OPENAI_API_KEY="your-openai-api-key"
# Anthropic
export ANTHROPIC_API_KEY="your-anthropic-api-key"
# Gemini
export GOOGLE_API_KEY="your-google-api-key"
# Optional: Tavily for web search
export TAVILY_API_KEY="your-tavily-api-key"The Rust SDK is designed for high performance:
- Memory Efficient: Zero-copy message handling where possible
- Async First: Built on Tokio for concurrent operations
- Type Safe: Compile-time guarantees for agent configurations
- Fast Compilation: Optimized build times with feature flags
- Low Latency: Minimal overhead for tool calls and state management
We welcome contributions! Please see our Contributing Guide for details.
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests
- Run
cargo fmtandcargo clippy - Submit a pull request
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.
- π Documentation
- π Issue Tracker
- π¬ Discussions
- Custom sub-agent execution graphs
- Dict-based model configuration
- Advanced state features (encryption, migrations)
- Enhanced tool system (composition, validation)
- Performance optimizations
- Additional LLM providers
Built with β€οΈ in Rust for the AI community