claude_code_agent_sdk/
lib.rs

1//! # Claude Agent SDK for Rust
2//!
3//! Rust SDK for interacting with Claude Code CLI, enabling programmatic access to Claude's
4//! capabilities with full bidirectional streaming support and 100% feature parity with the
5//! official Python SDK.
6//!
7//! ## Features
8//!
9//! - **Simple Query API**: One-shot queries with both collecting ([`query`]) and streaming ([`query_stream`]) modes
10//! - **Bidirectional Streaming**: Real-time streaming communication with [`ClaudeClient`]
11//! - **Dynamic Control**: Interrupt, change permissions, switch models mid-execution
12//! - **Hooks System**: Intercept and control Claude's behavior at runtime with 6 hook types
13//! - **Custom Tools**: In-process MCP servers with ergonomic [`tool!`](crate::tool) macro
14//! - **Plugin System**: Load custom plugins to extend Claude's capabilities
15//! - **Permission Management**: Fine-grained control over tool execution
16//! - **Cost Control**: Budget limits and fallback models for production reliability
17//! - **Extended Thinking**: Configure maximum thinking tokens for complex reasoning
18//! - **Session Management**: Resume, fork, and manage conversation sessions
19//! - **Multimodal Input**: Send images alongside text using base64 or URLs
20//!
21//! ## Quick Start
22//!
23//! ### Simple Query
24//!
25//! ```no_run
26//! use claude_agent_sdk_rs::{query, Message, ContentBlock};
27//!
28//! #[tokio::main]
29//! async fn main() -> anyhow::Result<()> {
30//!     // One-shot query that collects all messages
31//!     let messages = query("What is 2 + 2?", None).await?;
32//!
33//!     for message in messages {
34//!         if let Message::Assistant(msg) = message {
35//!             for block in &msg.message.content {
36//!                 if let ContentBlock::Text(text) = block {
37//!                     println!("Claude: {}", text.text);
38//!                 }
39//!             }
40//!         }
41//!     }
42//!
43//!     Ok(())
44//! }
45//! ```
46//!
47//! ### Streaming Query
48//!
49//! ```no_run
50//! use claude_agent_sdk_rs::{query_stream, Message, ContentBlock};
51//! use futures::StreamExt;
52//!
53//! #[tokio::main]
54//! async fn main() -> anyhow::Result<()> {
55//!     // Streaming query for memory-efficient processing
56//!     let mut stream = query_stream("Explain Rust ownership", None).await?;
57//!
58//!     while let Some(result) = stream.next().await {
59//!         let message = result?;
60//!         if let Message::Assistant(msg) = message {
61//!             for block in &msg.message.content {
62//!                 if let ContentBlock::Text(text) = block {
63//!                     println!("Claude: {}", text.text);
64//!                 }
65//!             }
66//!         }
67//!     }
68//!
69//!     Ok(())
70//! }
71//! ```
72//!
73//! ### Bidirectional Client
74//!
75//! ```no_run
76//! use claude_agent_sdk_rs::{ClaudeClient, ClaudeAgentOptions, Message, PermissionMode};
77//! use futures::StreamExt;
78//!
79//! #[tokio::main]
80//! async fn main() -> anyhow::Result<()> {
81//!     let options = ClaudeAgentOptions::builder()
82//!         .permission_mode(PermissionMode::BypassPermissions)
83//!         .max_turns(5)
84//!         .build();
85//!
86//!     let mut client = ClaudeClient::new(options);
87//!     client.connect().await?;
88//!
89//!     // Send query
90//!     client.query("What is Rust?").await?;
91//!
92//!     // Receive responses
93//!     {
94//!         let mut stream = client.receive_response();
95//!         while let Some(result) = stream.next().await {
96//!             match result? {
97//!                 Message::Assistant(msg) => {
98//!                     println!("Got assistant message");
99//!                 }
100//!                 Message::Result(_) => break,
101//!                 _ => {}
102//!             }
103//!         }
104//!     } // stream is dropped here
105//!
106//!     client.disconnect().await?;
107//!     Ok(())
108//! }
109//! ```
110//!
111//! ## Multimodal Input (Images)
112//!
113//! The SDK supports sending images alongside text in your prompts using structured content blocks.
114//! Both base64-encoded images and URL references are supported.
115//!
116//! ### Supported Formats
117//!
118//! - JPEG (`image/jpeg`)
119//! - PNG (`image/png`)
120//! - GIF (`image/gif`)
121//! - WebP (`image/webp`)
122//!
123//! ### Size Limits
124//!
125//! - Maximum base64 data size: 15MB (results in ~20MB decoded)
126//! - Large images may timeout or fail - resize before encoding
127//!
128//! ### Example: Query with Image
129//!
130//! ```no_run
131//! use claude_agent_sdk_rs::{query_with_content, UserContentBlock, Message, ContentBlock};
132//!
133//! #[tokio::main]
134//! async fn main() -> anyhow::Result<()> {
135//!     // For real usage, load and base64-encode an image file
136//!     // This example uses a pre-encoded 1x1 red PNG pixel
137//!     let base64_data = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8DwHwAFBQIAX8jx0gAAAABJRU5ErkJggg==";
138//!
139//!     // Query with text and image
140//!     let messages = query_with_content(vec![
141//!         UserContentBlock::text("What color is this image?"),
142//!         UserContentBlock::image_base64("image/png", base64_data)?,
143//!     ], None).await?;
144//!
145//!     for message in messages {
146//!         if let Message::Assistant(msg) = message {
147//!             for block in &msg.message.content {
148//!                 if let ContentBlock::Text(text) = block {
149//!                     println!("Claude: {}", text.text);
150//!                 }
151//!             }
152//!         }
153//!     }
154//!
155//!     Ok(())
156//! }
157//! ```
158//!
159//! ### Example: Using Image URLs
160//!
161//! ```no_run
162//! use claude_agent_sdk_rs::{query_with_content, UserContentBlock};
163//!
164//! #[tokio::main]
165//! async fn main() -> anyhow::Result<()> {
166//!     let messages = query_with_content(vec![
167//!         UserContentBlock::text("Describe this architecture diagram"),
168//!         UserContentBlock::image_url("https://example.com/diagram.png"),
169//!     ], None).await?;
170//!
171//!     Ok(())
172//! }
173//! ```
174//!
175//! ### Example: Streaming with Images
176//!
177//! ```no_run
178//! use claude_agent_sdk_rs::{query_stream_with_content, UserContentBlock, Message, ContentBlock};
179//! use futures::StreamExt;
180//!
181//! #[tokio::main]
182//! async fn main() -> anyhow::Result<()> {
183//!     // Minimal 1x1 PNG for example purposes
184//!     let png_base64 = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==";
185//!
186//!     let mut stream = query_stream_with_content(vec![
187//!         UserContentBlock::image_base64("image/png", png_base64)?,
188//!         UserContentBlock::text("What's in this image?"),
189//!     ], None).await?;
190//!
191//!     while let Some(result) = stream.next().await {
192//!         let message = result?;
193//!         if let Message::Assistant(msg) = message {
194//!             for block in &msg.message.content {
195//!                 if let ContentBlock::Text(text) = block {
196//!                     print!("{}", text.text);
197//!                 }
198//!             }
199//!         }
200//!     }
201//!
202//!     Ok(())
203//! }
204//! ```
205//!
206//! ## Configuration
207//!
208//! The SDK provides extensive configuration through [`ClaudeAgentOptions`]:
209//!
210//! ```no_run
211//! use claude_agent_sdk_rs::{ClaudeAgentOptions, PermissionMode, SdkPluginConfig};
212//!
213//! let options = ClaudeAgentOptions::builder()
214//!     .model("claude-opus-4")
215//!     .fallback_model("claude-sonnet-4")
216//!     .max_budget_usd(10.0)
217//!     .max_thinking_tokens(2000)
218//!     .max_turns(10)
219//!     .permission_mode(PermissionMode::Default)
220//!     .plugins(vec![SdkPluginConfig::local("./my-plugin")])
221//!     .build();
222//! ```
223//!
224//! ## Examples
225//!
226//! The SDK includes 22 comprehensive examples covering all features. See the
227//! [examples directory](https://github.com/yourusername/claude-agent-sdk-rs/tree/master/examples)
228//! for detailed usage patterns.
229//!
230//! ## Documentation
231//!
232//! - [README](https://github.com/soddygo/claude-code-agent-sdk/blob/master/README.md) - Getting started
233//! - [Plugin Guide](https://github.com/soddygo/claude-code-agent-sdk/blob/master/PLUGIN_GUIDE.md) - Plugin development
234//! - [Examples](https://github.com/soddygo/claude-code-agent-sdk/tree/master/examples) - 22 working examples
235//!
236//! ## Tracing Support
237//!
238//! This SDK uses the [`tracing`] crate for instrumentation. All major operations
239//! are automatically traced using `#[instrument]` attributes, making it easy to
240//! monitor and debug your application.
241//!
242//! ### Basic Usage (Console Logging)
243//!
244//! ```no_run
245//! use claude_agent_sdk_rs::query;
246//! use tracing_subscriber;
247//!
248//! #[tokio::main]
249//! async fn main() -> anyhow::Result<()> {
250//!     // Initialize tracing subscriber for console output
251//!     tracing_subscriber::fmt::init();
252//!
253//!     // Use SDK - traces are automatically logged to console
254//!     let messages = query("What is 2 + 2?", None).await?;
255//!
256//!     Ok(())
257//! }
258//! ```
259//!
260//! ### OpenTelemetry Integration
261//!
262//! To export traces to OpenTelemetry-compatible backends (Jaeger, OTel, etc.):
263//!
264//! ```no_run
265//! use claude_agent_sdk_rs::query;
266//! use tracing_subscriber::{Registry, prelude::*};
267//! use tracing_opentelemetry::OpenTelemetryLayer;
268//! use opentelemetry_otlp;
269//!
270//! #[tokio::main]
271//! async fn main() -> anyhow::Result<()> {
272//!     // Initialize OpenTelemetry with OTLP exporter
273//!     let tracer = opentelemetry_otlp::new_pipeline()
274//!         .tracing()
275//!         .with_exporter(opentelemetry_otlp::new_exporter().tonic())
276//!         .install_simple()?;
277//!
278//!     let otel_layer = OpenTelemetryLayer::new(tracer);
279//!
280//!     // Combine with fmt layer for console output too
281//!     Registry::default()
282//!         .with(otel_layer)
283//!         .with(tracing_subscriber::fmt::layer())
284//!         .init();
285//!
286//!     // Use SDK - traces are exported to OTLP
287//!     let messages = query("What is 2 + 2?", None).await?;
288//!
289//!     // Shutdown telemetry
290//!     opentelemetry_sdk::global::shutdown_tracer_provider();
291//!     Ok(())
292//! }
293//! ```
294//!
295//! ### Available Spans
296//!
297//! The SDK creates the following spans for comprehensive tracing:
298//!
299//! - `claude.query` - Top-level one-shot query operation
300//! - `claude.query_stream` - Streaming query operation
301//! - `claude.query_with_content` - Query with structured content (images)
302//! - `claude.query_stream_with_content` - Streaming query with content
303//! - `claude.client.connect` - Client connection establishment
304//! - `claude.client.query` - Client query send
305//! - `claude.client.disconnect` - Client disconnection
306//! - `claude.transport.connect` - Transport layer connection (subprocess spawn)
307//! - `claude.transport.write` - Writing to transport stdin
308//! - `claude.query_full.start` - Background message reader start
309//! - `claude.query_full.initialize` - Query initialization with hooks
310//! - `claude.internal.execute` - Internal client execution
311//!
312//! Each span includes relevant fields:
313//! - `prompt_length` - Length of the user prompt
314//! - `has_options` - Whether custom options were provided
315//! - `content_block_count` - Number of content blocks (for content queries)
316//! - `session_id` - Session identifier (for client queries)
317//! - `model` - Model name being used
318//! - `has_can_use_tool` - Whether permission callback is set
319//! - `has_hooks` - Whether hooks are configured
320//! - `cli_path` - Path to Claude CLI executable
321//! - `data_length` - Length of data being written
322//!
323//! ### Environment Variables
324//!
325//! Control tracing behavior using standard `RUST_LOG` environment variable:
326//!
327//! ```bash
328//! # Show all SDK logs
329//! RUST_LOG=claude_agent_sdk_rs=debug cargo run
330//!
331//! # Show only errors
332//! RUST_LOG=claude_agent_sdk_rs=error cargo run
333//!
334//! # Combine with other crates
335//! RUST_LOG=claude_agent_sdk_rs=info,tokio=warn cargo run
336//! ```
337
338pub mod client;
339pub mod errors;
340mod internal;
341pub mod query;
342pub mod types;
343pub mod version;
344
345// Re-export commonly used types
346pub use errors::{ClaudeError, ImageValidationError, Result};
347pub use types::{
348    config::*,
349    hooks::*,
350    mcp::{
351        // ACP tool name prefix support
352        ACP_TOOL_PREFIX,
353        McpServerConfig,
354        McpServers,
355        SdkMcpServer,
356        SdkMcpTool,
357        ToolDefinition,
358        ToolHandler,
359        ToolResult,
360        ToolResultContent as McpToolResultContent,
361        acp_tool_name,
362        create_sdk_mcp_server,
363        is_acp_tool,
364        strip_acp_prefix,
365    },
366    messages::*,
367    permissions::*,
368    plugin::*,
369};
370
371// Re-export public API
372pub use client::ClaudeClient;
373pub use query::{query, query_stream, query_stream_with_content, query_with_content};