Skip to main content

Crate open_agent

Crate open_agent 

Source
Expand description

§Open Agent SDK - Rust Implementation

A production-ready, streaming-first Rust SDK for building AI agents over two wire protocols: OpenAI chat completions and Anthropic messages.

§Overview

The protocol is a property of the endpoint. Select it with AgentOptions::builder().protocol(..); it defaults to ApiProtocol::OpenAiChat.

ApiProtocol::OpenAiChat posts to {base_url}/chat/completions with bearer auth:

  • LM Studio, Ollama, llama.cpp, vLLM, and other local servers
  • OpenAI, OpenRouter, z.ai, and other hosted OpenAI-compatible endpoints

ApiProtocol::Anthropic posts to {base_url}/messages with x-api-key and anthropic-version:

  • Anthropic
  • Moonshot Kimi for Coding, MiniMax, and other Anthropic-shaped endpoints

§Key Features

  • Two Wire Protocols: OpenAI chat completions or Anthropic messages, per endpoint
  • Local or Hosted: Zero-cost inference on your own hardware, or a vendor endpoint
  • High Performance: Native async/await with Tokio runtime
  • Streaming Responses: Real-time token-by-token streaming
  • Finish Reasons: Every stream reports why generation stopped
  • Reasoning Channel: Extended thinking and reasoning deltas kept out of content
  • Tool Calling: Define and execute tools with automatic schema generation
  • Lifecycle Hooks: Intercept and control execution at key points
  • Interrupts: Gracefully cancel long-running operations
  • Context Management: Manual token estimation and history truncation
  • Retry Logic: Exponential backoff with jitter for reliability

§Two Interaction Modes

§1. Simple Query Function (query())

For single-turn interactions without conversation state:

use open_agent::{query, AgentOptions, ContentBlock, FinishReason, StreamEvent};
use futures::StreamExt;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Configure the agent with required settings
    let options = AgentOptions::builder()
        .system_prompt("You are a helpful assistant")
        .model("qwen2.5-32b-instruct")
        .base_url("http://localhost:1234/v1")
        .build()?;

    // Send a single query and stream the response
    let mut stream = query("What's the capital of France?", &options).await?;

    // Process each event as it arrives; the stream always ends with one Finish
    while let Some(event) = stream.next().await {
        match event? {
            StreamEvent::Block(ContentBlock::Text(text_block)) => {
                print!("{}", text_block.text);
            }
            StreamEvent::Block(ContentBlock::ToolUse(tool_block)) => {
                println!("Tool called: {}", tool_block.name());
            }
            StreamEvent::Finish(FinishReason::Length) => {
                eprintln!("response was truncated at the token cap");
            }
            _ => {}
        }
    }

    Ok(())
}

§2. Client Object (Client)

For multi-turn conversations with persistent state:

use open_agent::{Client, AgentOptions, ContentBlock};
use futures::StreamExt;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let options = AgentOptions::builder()
        .system_prompt("You are a helpful assistant")
        .model("qwen2.5-32b-instruct")
        .base_url("http://localhost:1234/v1")
        .build()?;

    // Create a stateful client that maintains conversation history
    let mut client = Client::new(options)?;

    // First turn
    client.send("What's 2+2?").await?;
    while let Some(block) = client.receive().await? {
        match block {
            ContentBlock::Text(text) => print!("{}", text.text),
            ContentBlock::ToolUse(_) | ContentBlock::ToolResult(_) | ContentBlock::Image(_) => {}
        }
    }

    // Second turn - client remembers previous context
    client.send("What about if we multiply that by 3?").await?;
    while let Some(block) = client.receive().await? {
        match block {
            ContentBlock::Text(text) => print!("{}", text.text),
            ContentBlock::ToolUse(_) | ContentBlock::ToolResult(_) | ContentBlock::Image(_) => {}
        }
    }

    Ok(())
}

§Architecture

The SDK is organized into several modules, each with a specific responsibility:

  • client: Core streaming query engine and multi-turn client, and the transport boundary where the protocol is applied
  • types: Data structures for messages, content blocks, configuration, and the OpenAI and Anthropic wire formats
  • tools: Tool definition system with automatic JSON schema generation
  • hooks: Lifecycle event system for intercepting execution
  • config: Provider-specific configuration helpers
  • error: Comprehensive error types and conversions
  • context: Token estimation and message truncation utilities
  • retry: Exponential backoff retry logic with jitter
  • utils: Internal utilities for SSE parsing and tool aggregation

Modules§

prelude
Convenience module containing the most commonly used types and functions. Import with use open_agent::prelude::*; to get everything you need for typical usage.
retry
Retry utilities with exponential backoff and jitter. Made public as a module so users can access retry configuration and functions for their own operations that need retry logic. Retry utilities with exponential backoff

Structs§

AgentOptions
Configuration options for an AI agent instance.
AgentOptionsBuilder
Builder for constructing AgentOptions with validation.
AnthropicErrorBody
The body of a mid-stream error event.
AnthropicMessage
One conversation turn.
AnthropicMessageDelta
Top-level message changes, carrying the reason generation stopped.
AnthropicRequest
Request payload for POST {base_url}/messages.
BaseUrl
Validated base URL with compile-time type safety.
Client
Stateful client for multi-turn conversations with automatic history management.
HookDecision
Decision returned by a hook handler to control agent execution flow.
Hooks
Container for registering and managing lifecycle hooks.
ImageBlock
Image content block for vision-capable models.
Message
A complete message in a conversation.
ModelName
Validated model name with compile-time type safety.
OpenAIFunction
OpenAI function call details.
OpenAIMessage
OpenAIRequest
Complete request payload for OpenAI chat completions API.
OpenAIToolCall
OpenAI tool call representation in API messages.
PostToolUseEvent
Event fired after a tool completes execution, enabling audit, filtering, or validation.
PreToolUseEvent
Event fired before a tool is executed, enabling validation, modification, or blocking.
Temperature
Validated temperature value with compile-time type safety.
TextBlock
Simple text content in a message.
Tool
Tool definition for function calling, over either wire protocol.
ToolBuilder
Builder for creating tools with a fluent API.
ToolResultBlock
Tool execution result sent back to the model.
ToolUseBlock
Tool use request from the AI model.
UserPromptSubmitEvent
Event fired before processing user input, enabling content moderation and prompt enhancement.

Enums§

AnthropicBlockStart
The declaration that opens a content block.
AnthropicDelta
One fragment appended to an open block.
AnthropicEvent
One event from an Anthropic streaming response.
ApiProtocol
The wire protocol an endpoint exposes.
ContentBlock
Multi-modal content blocks that can appear in messages.
Error
Comprehensive error type covering all failure modes in the SDK.
FinishReason
Why the model stopped generating.
ImageDetail
Image detail level for vision API calls.
MessageRole
Identifies the sender/role of a message in the conversation.
OpenAIContent
OpenAI API message format for serialization.
OpenAIContentPart
A single content part in an OpenAI message.
Provider
Enum representing supported local LLM server providers.
StreamEvent
One item in the stream returned by query().

Constants§

HOOK_POST_TOOL_USE
String constant for the PostToolUse hook event name.
HOOK_PRE_TOOL_USE
String constant for the PreToolUse hook event name.
HOOK_USER_PROMPT_SUBMIT
String constant for the UserPromptSubmit hook event name.

Functions§

anthropic_finish_reason
Maps an Anthropic stop_reason onto the SDK’s protocol-neutral FinishReason.
estimate_tokens
Estimate token count for message list
get_base_url
Get the base URL for API requests with environment variable support.
get_model
Get the model name with optional environment variable override.
is_approaching_limit
Check if history is approaching a token limit
query
Simple query function for single-turn interactions without conversation history.
tool
Create a tool using the builder pattern (convenience function).
truncate_messages
Truncate message history, keeping recent messages

Type Aliases§

EventStream
A pinned, boxed stream of events from the model.
Result
Type alias for Result<T, Error> used throughout the SDK.