open_agent/
lib.rs

1//! # Open Agent SDK - Rust Implementation
2//!
3//! A production-ready, streaming-first Rust SDK for building AI agents with local OpenAI-compatible servers.
4//!
5//! ## Overview
6//!
7//! This SDK provides a clean, ergonomic API for working with local LLM servers such as:
8//! - LM Studio
9//! - Ollama
10//! - llama.cpp
11//! - vLLM
12//!
13//! ## Key Features
14//!
15//! - **Zero API Costs**: Run models on your own hardware
16//! - **Privacy-First**: All data stays local on your machine
17//! - **High Performance**: Native async/await with Tokio runtime
18//! - **Streaming Responses**: Real-time token-by-token streaming
19//! - **Tool Calling**: Define and execute tools with automatic schema generation
20//! - **Lifecycle Hooks**: Intercept and control execution at key points
21//! - **Interrupts**: Gracefully cancel long-running operations
22//! - **Context Management**: Manual token estimation and history truncation
23//! - **Retry Logic**: Exponential backoff with jitter for reliability
24//!
25//! ## Two Interaction Modes
26//!
27//! ### 1. Simple Query Function (`query()`)
28//! For single-turn interactions without conversation state:
29//!
30//! ```rust,no_run
31//! use open_agent::{query, AgentOptions, ContentBlock};
32//! use futures::StreamExt;
33//!
34//! #[tokio::main]
35//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
36//!     // Configure the agent with required settings
37//!     let options = AgentOptions::builder()
38//!         .system_prompt("You are a helpful assistant")
39//!         .model("qwen2.5-32b-instruct")
40//!         .base_url("http://localhost:1234/v1")
41//!         .build()?;
42//!
43//!     // Send a single query and stream the response
44//!     let mut stream = query("What's the capital of France?", &options).await?;
45//!
46//!     // Process each content block as it arrives
47//!     while let Some(block) = stream.next().await {
48//!         match block? {
49//!             ContentBlock::Text(text_block) => {
50//!                 print!("{}", text_block.text);
51//!             }
52//!             ContentBlock::ToolUse(tool_block) => {
53//!                 println!("Tool called: {}", tool_block.name());
54//!             }
55//!             ContentBlock::ToolResult(_) => {
56//!                 // Tool results can be ignored in simple queries
57//!             }
58//!             ContentBlock::Image(_) => {
59//!                 // Images not expected in this example
60//!             }
61//!         }
62//!     }
63//!
64//!     Ok(())
65//! }
66//! ```
67//!
68//! ### 2. Client Object (`Client`)
69//! For multi-turn conversations with persistent state:
70//!
71//! ```rust,no_run
72//! use open_agent::{Client, AgentOptions, ContentBlock};
73//! use futures::StreamExt;
74//!
75//! #[tokio::main]
76//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
77//!     let options = AgentOptions::builder()
78//!         .system_prompt("You are a helpful assistant")
79//!         .model("qwen2.5-32b-instruct")
80//!         .base_url("http://localhost:1234/v1")
81//!         .build()?;
82//!
83//!     // Create a stateful client that maintains conversation history
84//!     let mut client = Client::new(options)?;
85//!
86//!     // First turn
87//!     client.send("What's 2+2?").await?;
88//!     while let Some(block) = client.receive().await? {
89//!         match block {
90//!             ContentBlock::Text(text) => print!("{}", text.text),
91//!             ContentBlock::ToolUse(_) | ContentBlock::ToolResult(_) | ContentBlock::Image(_) => {}
92//!         }
93//!     }
94//!
95//!     // Second turn - client remembers previous context
96//!     client.send("What about if we multiply that by 3?").await?;
97//!     while let Some(block) = client.receive().await? {
98//!         match block {
99//!             ContentBlock::Text(text) => print!("{}", text.text),
100//!             ContentBlock::ToolUse(_) | ContentBlock::ToolResult(_) | ContentBlock::Image(_) => {}
101//!         }
102//!     }
103//!
104//!     Ok(())
105//! }
106//! ```
107//!
108//! ## Architecture
109//!
110//! The SDK is organized into several modules, each with a specific responsibility:
111//!
112//! - **client**: Core streaming query engine and multi-turn client
113//! - **types**: Data structures for messages, content blocks, and configuration
114//! - **tools**: Tool definition system with automatic JSON schema generation
115//! - **hooks**: Lifecycle event system for intercepting execution
116//! - **config**: Provider-specific configuration helpers
117//! - **error**: Comprehensive error types and conversions
118//! - **context**: Token estimation and message truncation utilities
119//! - **retry**: Exponential backoff retry logic with jitter
120//! - **utils**: Internal utilities for SSE parsing and tool aggregation
121
122// ============================================================================
123// MODULE DECLARATIONS
124// ============================================================================
125// These modules are private (internal implementation details) unless explicitly
126// re-exported through `pub use` statements below.
127
128/// Core client implementation providing streaming queries and stateful conversations.
129/// Contains the `query()` function for single-turn queries and `Client` struct
130/// for multi-turn conversations with automatic state management.
131mod client;
132
133/// Provider configuration helpers for LM Studio, Ollama, llama.cpp, and vLLM.
134/// Simplifies endpoint and model name resolution with environment variable support.
135mod config;
136
137/// Context window management utilities for token estimation and history truncation.
138/// Provides manual control over conversation memory to prevent context overflow.
139mod context;
140
141/// Error types and conversions for comprehensive error handling throughout the SDK.
142/// Defines the `Error` enum and `Result<T>` type alias used across all public APIs.
143mod error;
144
145/// Lifecycle hooks system for intercepting and controlling execution at key points.
146/// Enables security gates, audit logging, input/output modification, and compliance checks.
147mod hooks;
148
149/// Tool definition and execution system with automatic JSON schema generation.
150/// Allows LLMs to call Rust functions with type-safe parameter handling.
151mod tools;
152
153/// Core type definitions for messages, content blocks, and agent configuration.
154/// Includes builder patterns for ergonomic configuration and OpenAI API serialization.
155mod types;
156
157/// Internal utilities for Server-Sent Events (SSE) parsing and tool call aggregation.
158/// Handles the low-level details of streaming response parsing.
159mod utils;
160
161// ============================================================================
162// PUBLIC EXPORTS
163// ============================================================================
164// These items form the public API of the SDK. Everything else is internal.
165
166/// Retry utilities with exponential backoff and jitter.
167/// Made public as a module so users can access retry configuration and functions
168/// for their own operations that need retry logic.
169pub mod retry;
170
171// --- Core Client API ---
172
173pub use client::{Client, query};
174
175// --- Provider Configuration ---
176
177pub use config::{Provider, get_base_url, get_model};
178
179// --- Context Management ---
180
181pub use context::{estimate_tokens, is_approaching_limit, truncate_messages};
182
183// --- Error Handling ---
184
185pub use error::{Error, Result};
186
187// --- Lifecycle Hooks ---
188
189pub use hooks::{
190    HOOK_POST_TOOL_USE, HOOK_PRE_TOOL_USE, HOOK_USER_PROMPT_SUBMIT, HookDecision, Hooks,
191    PostToolUseEvent, PreToolUseEvent, UserPromptSubmitEvent,
192};
193
194// --- Tool System ---
195
196pub use tools::{Tool, ToolBuilder, tool};
197
198// --- Core Types ---
199
200pub use types::{
201    AgentOptions, AgentOptionsBuilder, BaseUrl, ContentBlock, ImageBlock, ImageDetail, Message,
202    MessageRole, ModelName, OpenAIContent, OpenAIContentPart, Temperature, TextBlock,
203    ToolResultBlock, ToolUseBlock,
204};
205
206// ============================================================================
207// CONVENIENCE PRELUDE
208// ============================================================================
209
210/// Convenience module containing the most commonly used types and functions.
211/// Import with `use open_agent::prelude::*;` to get everything you need for typical usage.
212///
213/// This includes:
214/// - Configuration: AgentOptions, AgentOptionsBuilder
215/// - Client: Client, query()
216/// - Content: ContentBlock, TextBlock, ToolUseBlock
217/// - Tools: Tool, tool()
218/// - Hooks: Hooks, HookDecision, hook event types
219/// - Errors: Error, Result
220pub mod prelude {
221    pub use crate::{
222        AgentOptions, AgentOptionsBuilder, BaseUrl, Client, ContentBlock, Error, HookDecision,
223        Hooks, ModelName, PostToolUseEvent, PreToolUseEvent, Result, Temperature, TextBlock, Tool,
224        ToolUseBlock, UserPromptSubmitEvent, query, tool,
225    };
226}