anthropic-sdk-rust 0.1.1

Comprehensive, type-safe Rust SDK for the Anthropic API with streaming, tools, vision, files, and batch processing support
Documentation
//! Comprehensive streaming example demonstrating the Anthropic Rust SDK streaming capabilities.
//!
//! This example shows how to use the streaming API to get real-time responses from Claude,
//! including callback-based processing, manual iteration, and error handling.

use anthropic_sdk::{
    Anthropic, MessageCreateBuilder, MessageStreamEvent, ContentBlockDelta,
    Result,
};
use futures::StreamExt;
use std::io::{self, Write};

#[tokio::main]
async fn main() -> Result<()> {
    // Initialize tracing for better debugging
    tracing_subscriber::fmt::init();
    
    println!("šŸ¤– Anthropic Rust SDK - Streaming Example");
    println!("==========================================\n");
    
    // Note: In a real application, you'd get the API key from environment
    // or configuration. For this example, we'll use a placeholder.
    println!("āš ļø  This is a demonstration example.");
    println!("šŸ“ To run with real API calls, set ANTHROPIC_API_KEY environment variable.\n");
    
    // Uncomment the following line when you have a real API key:
    // let client = Anthropic::from_env()?;
    
    // For demonstration purposes, we'll show the API structure
    demonstrate_streaming_api_structure().await;
    
    Ok(())
}

/// Demonstrates the streaming API structure and usage patterns.
async fn demonstrate_streaming_api_structure() {
    println!("šŸ”„ Streaming API Usage Patterns");
    println!("=================================\n");
    
    // Example 1: Basic streaming with callbacks
    println!("1ļøāƒ£  Callback-based Streaming:");
    print_code_example(r#"
let client = Anthropic::from_env()?;

let final_message = client.messages()
    .create_with_builder("claude-3-5-sonnet-latest", 1024)
    .user("Write a haiku about artificial intelligence")
    .system("You are a creative poet")
    .temperature(0.8)
    .stream_send()
    .await?
    .on_text(|delta, _snapshot| {
        print!("{}", delta); // Print each text chunk as it arrives
        io::stdout().flush().unwrap();
    })
    .on_error(|error| {
        eprintln!("\nāŒ Error: {}", error);
    })
    .on_end(|| {
        println!("\nāœ… Stream completed!");
    })
    .final_message()
    .await?;

println!("\nšŸ“œ Final message: {:?}", final_message);
"#);
    
    // Example 2: Manual stream iteration
    println!("\n2ļøāƒ£  Manual Stream Iteration:");
    print_code_example(r#"
let client = Anthropic::from_env()?;

let stream = client.messages().create_stream(
    MessageCreateBuilder::new("claude-3-5-sonnet-latest", 1024)
        .user("Explain quantum computing in simple terms")
        .stream(true)
        .build()
).await?;

let mut content = String::new();

// Process each streaming event manually
while let Some(event) = stream.next().await {
    match event? {
        MessageStreamEvent::MessageStart { message } => {
            println!("šŸ“Ø Message started: {}", message.id);
        }
        MessageStreamEvent::ContentBlockStart { content_block, index } => {
            println!("šŸ“ Content block {} started", index);
        }
        MessageStreamEvent::ContentBlockDelta { delta, index } => {
            match delta {
                ContentBlockDelta::TextDelta { text } => {
                    print!("{}", text);
                    content.push_str(&text);
                    io::stdout().flush().unwrap();
                }
                ContentBlockDelta::InputJsonDelta { partial_json } => {
                    println!("šŸ› ļø  Tool input: {}", partial_json);
                }
                _ => {}
            }
        }
        MessageStreamEvent::MessageDelta { delta, usage } => {
            println!("\nšŸ“Š Usage: {} output tokens", usage.output_tokens);
            if let Some(stop_reason) = delta.stop_reason {
                println!("šŸ›‘ Stop reason: {:?}", stop_reason);
            }
        }
        MessageStreamEvent::MessageStop => {
            println!("\nāœ… Stream completed!");
            break;
        }
        _ => {}
    }
}

println!("\nšŸ“œ Complete response:\n{}", content);
"#);
    
    // Example 3: Error handling and recovery
    println!("\n3ļøāƒ£  Error Handling:");
    print_code_example(r#"
let client = Anthropic::from_env()?;

match client.messages()
    .create_with_builder("claude-3-5-sonnet-latest", 1024)
    .user("Generate a short story")
    .stream_send()
    .await
{
    Ok(stream) => {
        let result = stream
            .on_text(|delta, _| print!("{}", delta))
            .on_error(|error| {
                match error {
                    AnthropicError::RateLimit { .. } => {
                        eprintln!("ā±ļø  Rate limit hit, please wait...");
                    }
                    AnthropicError::Connection { .. } => {
                        eprintln!("🌐 Connection error, retrying...");
                    }
                    _ => {
                        eprintln!("āŒ Unexpected error: {}", error);
                    }
                }
            })
            .final_message()
            .await;
            
        match result {
            Ok(message) => println!("āœ… Success: {:?}", message),
            Err(e) => println!("āŒ Failed: {}", e),
        }
    }
    Err(e) => {
        println!("āŒ Failed to start stream: {}", e);
    }
}
"#);
    
    // Example 4: Advanced features
    println!("\n4ļøāƒ£  Advanced Streaming Features:");
    print_code_example(r#"
use std::sync::{Arc, Mutex};
use std::time::Instant;

let client = Anthropic::from_env()?;
let start_time = Instant::now();
let word_count = Arc::new(Mutex::new(0));
let word_count_clone = word_count.clone();

let final_message = client.messages()
    .create_with_builder("claude-3-5-sonnet-latest", 2048)
    .user("Write a detailed explanation of machine learning")
    .system("You are an expert teacher. Explain concepts clearly.")
    .temperature(0.3)
    .top_p(0.9)
    .stream_send()
    .await?
    .on_text(move |delta, snapshot| {
        // Count words in real-time
        let words_in_delta = delta.split_whitespace().count();
        *word_count_clone.lock().unwrap() += words_in_delta;
        
        print!("{}", delta);
        io::stdout().flush().unwrap();
    })
    .on_stream_event(|event, current_message| {
        match event {
            MessageStreamEvent::MessageDelta { usage, .. } => {
                println!("\nšŸ“Š Tokens: {} output", usage.output_tokens);
            }
            _ => {}
        }
    })
    .final_message()
    .await?;

let elapsed = start_time.elapsed();
let total_words = *word_count.lock().unwrap();

println!("\nšŸ“ˆ Streaming Statistics:");
println!("ā±ļø  Duration: {:.2}s", elapsed.as_secs_f64());
println!("šŸ“ Words: {}", total_words);
println!("šŸš€ Words/sec: {:.1}", total_words as f64 / elapsed.as_secs_f64());
println!("šŸŽÆ Tokens: {}", final_message.usage.output_tokens);
"#);
    
    println!("\n✨ Key Features Demonstrated:");
    println!("• Real-time text streaming with callbacks");
    println!("• Manual event processing and control");
    println!("• Comprehensive error handling");
    println!("• Performance monitoring and statistics");
    println!("• Multiple event types (text, usage, completion)");
    println!("• Graceful stream termination and cleanup");
    
    println!("\nšŸŽÆ Ready for Production Use!");
    println!("The streaming implementation provides full TypeScript SDK parity");
    println!("with zero-cost abstractions and memory-safe processing.");
}

/// Prints a formatted code example
fn print_code_example(code: &str) {
    println!("```rust");
    // Remove leading newline and common indentation
    let lines: Vec<&str> = code.trim().lines().collect();
    for line in lines {
        println!("{}", line);
    }
    println!("```");
}

// Additional helper functions for real streaming (when API key is available)

#[allow(dead_code)]
async fn run_real_streaming_example() -> Result<()> {
    let client = Anthropic::from_env()?;
    
    println!("šŸ”„ Starting real streaming example...");
    
    let final_message = client.messages()
        .create_with_builder("claude-3-5-sonnet-latest", 1024)
        .user("Write a short poem about Rust programming")
        .system("You are a creative programmer poet")
        .temperature(0.7)
        .stream_send()
        .await?
        .on_text(|delta, _| {
            print!("{}", delta);
            io::stdout().flush().unwrap();
        })
        .on_error(|error| {
            eprintln!("\nāŒ Stream error: {}", error);
        })
        .final_message()
        .await?;
    
    println!("\n\nāœ… Stream completed!");
    println!("šŸ“Š Final usage: {:?}", final_message.usage);
    
    Ok(())
}

#[allow(dead_code)]
async fn demonstrate_manual_iteration() -> Result<()> {
    let client = Anthropic::from_env()?;
    
    let mut stream = client.messages().create_stream(
        MessageCreateBuilder::new("claude-3-5-sonnet-latest", 512)
            .user("Count from 1 to 5")
            .stream(true)
            .build()
    ).await?;
    
    // Process events manually
    while let Some(event) = stream.next().await {
        match event? {
            MessageStreamEvent::MessageStart { message } => {
                println!("šŸ“Ø Started: {}", message.id);
            }
            MessageStreamEvent::ContentBlockDelta { delta, .. } => {
                if let ContentBlockDelta::TextDelta { text } = delta {
                    print!("{}", text);
                    io::stdout().flush().unwrap();
                }
            }
            MessageStreamEvent::MessageStop => {
                println!("\nāœ… Completed!");
                break;
            }
            _ => {}
        }
    }
    
    Ok(())
}