Skip to content

agent-sdk ​

Rust port of the Claude Agent SDK. Provides the query() function which drives the agentic loop: prompt → LLM provider → tool execution → feed results → repeat.

Usage ​

rust
use agent_sdk::{query, Options, Message};
use tokio_stream::StreamExt;

let mut stream = query(
    "What files are in this directory?",
    Options::builder()
        .allowed_tools(vec!["Bash".into(), "Glob".into()])
        .build(),
);

while let Some(msg) = stream.next().await {
    let msg = msg?;
    if let Message::Result(result) = &msg {
        println!("{}", result.result.as_deref().unwrap_or(""));
    }
}

Multi-Provider Support ​

The SDK supports multiple LLM providers via the LlmProvider trait. Each provider translates between the canonical API types and its own wire format.

Available Providers ​

ProviderStructAlso Serves
AnthropicAnthropicProvider—
AWS BedrockBedrockProvider—
Google Vertex AIVertexProvider—
OpenAIOpenAiProviderGroq, DeepSeek, OpenRouter, Ollama
GeminiGeminiProvider—

Using a Specific Provider ​

rust
use agent_sdk::{Options, OpenAiProvider};

let provider = OpenAiProvider::new("sk-...");

let stream = query(
    "Hello!",
    Options::builder()
        .provider(Box::new(provider))
        .model("gpt-4.1")
        .build(),
);

Using AWS Bedrock ​

rust
use agent_sdk::{Options, BedrockProvider};

// Reads AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION from env
let provider = BedrockProvider::with_region("eu-west-1");

let stream = query(
    "Hello!",
    Options::builder()
        .provider(Box::new(provider))
        .model("eu.anthropic.claude-sonnet-4-6")
        .build(),
);

Bedrock uses AWS SigV4 authentication and the AWS Event Stream binary protocol for streaming. Model IDs use cross-region inference profiles (e.g. eu.anthropic.claude-sonnet-4-6, us.anthropic.claude-opus-4-6-v1).

Using Google Vertex AI ​

rust
use agent_sdk::{Options, VertexProvider};

// Uses Application Default Credentials (ADC) for auth
let provider = VertexProvider::new("my-gcp-project", "us-central1").await?;

let stream = query(
    "Hello!",
    Options::builder()
        .provider(Box::new(provider))
        .model("claude-sonnet-4-6")
        .build(),
);

Vertex AI uses Google OAuth2 authentication and standard SSE streaming (same as Anthropic). Credentials are discovered via Application Default Credentials: service account JSON (GOOGLE_APPLICATION_CREDENTIALS), gcloud auth application-default login, or GCE metadata. Model IDs are claude-sonnet-4-6, claude-opus-4-6, claude-haiku-4-5@20251001.

If no provider is set, defaults to AnthropicProvider::from_env().

Implementing a Custom Provider ​

rust
use agent_sdk::{LlmProvider, ProviderCapabilities, CostRates};
use agent_sdk::client::{CreateMessageRequest, MessageResponse, StreamEvent};
use async_trait::async_trait;

#[async_trait]
impl LlmProvider for MyProvider {
    fn name(&self) -> &str { "my-provider" }
    fn capabilities(&self) -> ProviderCapabilities { /* ... */ }
    fn cost_rates(&self, model: &str) -> CostRates { /* ... */ }
    async fn create_message(&self, req: &CreateMessageRequest)
        -> Result<MessageResponse> { /* ... */ }
    async fn create_message_stream(&self, req: &CreateMessageRequest)
        -> Result<Pin<Box<dyn Stream<Item = Result<StreamEvent>> + Send>>> { /* ... */ }
}

Options Builder ​

rust
Options::builder()
    .model("claude-haiku-4-5")
    .max_turns(30)
    .system_prompt("You are a helpful assistant")
    .allowed_tools(vec!["Bash".into(), "Read".into()])
    .session_id("my-session")
    .thinking(ThinkingConfig::Enabled { budget_tokens: 10_000 })
    .permission_mode(PermissionMode::BypassPermissions)
    .external_tool_handler(handler_fn)
    .custom_tools(vec![tool_def])
    .provider(Box::new(my_provider))
    .build()
MethodDescription
.model()LLM model identifier
.max_turns()Maximum agentic loop iterations
.system_prompt()System prompt text
.allowed_tools()Restrict available tools
.session_id()Session identifier for multi-turn
.thinking()Extended thinking configuration
.permission_mode()Tool access control
.external_tool_handler()Custom tool callback
.custom_tools()Custom tool definitions
.context_budget()Token threshold for conversation compaction
.compaction_model()Model for generating compaction summaries
.provider()LLM provider (default: Anthropic)
.env_blocklist()Env var names to strip from Bash child processes

Message Types ​

rust
enum Message {
    System(SystemMessage),
    Assistant(AssistantMessage),
    User(UserMessage),
    Result(ResultMessage),
    StreamEvent(StreamEventMessage),
}

Custom Tools ​

Define tools with JSON schemas and handle them with an external callback:

rust
let tool = CustomToolDefinition {
    name: "MyTool".into(),
    description: "Does something useful".into(),
    input_schema: serde_json::json!({
        "type": "object",
        "properties": {
            "query": { "type": "string" }
        },
        "required": ["query"]
    }),
};

let handler: ExternalToolHandlerFn = Arc::new(|name, input| {
    Box::pin(async move {
        if name == "MyTool" {
            Some(ToolResult {
                content: "result".into(),
                is_error: false,
            })
        } else {
            None // Fall through to built-in handler
        }
    })
});

The handler returns Some(ToolResult) to handle a tool, or None to let the SDK's built-in handler run it.

Tests ​

97 tests (including doc-tests).

Released under the MIT License.