Crate agent_sdk

Crate agent_sdk 

Source
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:

  1. User sends a message
  2. Agent sends message to LLM
  3. LLM responds with text and/or tool calls
  4. Agent executes tools and feeds results back to LLM
  5. 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:

TierDescriptionExample
ToolTier::ObserveRead-only, always allowedGet balance, read file
ToolTier::ConfirmRequires user confirmationSend email, write file
ToolTier::RequiresPinRequires PIN verificationTransfer 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:

§Events

The agent emits AgentEvents during execution for real-time updates:

EventDescription
AgentEvent::StartAgent begins processing
AgentEvent::TextText response from LLM
AgentEvent::TextDeltaStreaming text chunk
AgentEvent::ToolCallStartTool execution starting
AgentEvent::ToolCallEndTool execution completed
AgentEvent::TurnCompleteOne LLM round-trip finished
AgentEvent::DoneAgent completed successfully
AgentEvent::ErrorAn 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

ModuleDescription
providersLLM provider implementations
primitive_toolsBuilt-in file operation tools (Read, Write, Edit, Glob, Grep, Bash)
llmLLM abstraction layer
subagentNested agent execution with SubagentFactory
mcpModel Context Protocol support
[todo]Task tracking tools (TodoWriteTool, TodoReadTool)
user_interactionUser question/confirmation tools (AskUserQuestionTool)
webWeb search and fetch tools
skillsCustom 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§

AgentCapabilities
Capabilities that control what the agent can do.
AgentConfig
Configuration for the agent loop
AgentLoop
The main agent loop that orchestrates LLM calls and tool execution.
AgentLoopBuilder
Builder for constructing an AgentLoop.
AgentState
Snapshot of agent state for checkpointing
AllowAllHooks
Hooks that allow all tools without confirmation
DefaultHooks
Default hooks implementation that uses tier-based decisions
ExecResult
Result from command execution
FileEntry
Entry in a directory listing
GrepMatch
Match result from grep operation
InMemoryFileSystem
In-memory filesystem for testing
InMemoryStore
In-memory implementation of MessageStore and StateStore. Useful for testing and simple use cases.
LocalFileSystem
Local filesystem implementation using std::fs
LoggingHooks
Hooks that log all events (useful for debugging)
NullEnvironment
A null environment that rejects all operations. Useful as a default when no environment is configured.
PendingAction
State of a pending action that requires confirmation or PIN
RetryConfig
Configuration for retry behavior on transient errors.
ThreadId
Unique identifier for a conversation thread
TokenUsage
Token usage statistics
ToolContext
Context passed to tool execution
ToolRegistry
Registry of available tools
ToolResult
Result of a tool execution

Enums§

AgentEvent
Events emitted by the agent loop during execution. These are streamed to the client for real-time UI updates.
ToolDecision
Decision returned by pre-tool hooks
ToolTier
Permission tier for tools

Traits§

AgentHooks
Lifecycle hooks for the agent loop. Implement this trait to customize agent behavior.
Environment
Environment abstraction for file and command operations.
MessageStore
Trait for storing and retrieving conversation messages. Implement this trait to persist messages to your storage backend.
StateStore
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.