claude-sdk-rs 1.0.0

Rust SDK for Claude AI with CLI integration - type-safe async API for Claude Code and direct SDK usage
Documentation
# Part 2: Basic Usage and Response Modes

Now that you can make basic queries, let's explore the different ways to interact with Claude and handle responses.

## Three Response Modes

The claude-sdk-rs SDK offers three distinct response modes, each suited for different use cases:

### 1. Simple Text Mode (Default)

This is the simplest mode - just get the text response:

```rust
use claude_sdk_rs::{Client, Config};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = Client::new(Config::default());
    
    let response = client
        .query("Explain quantum computing in one sentence")
        .send()
        .await?;
    
    println!("Claude says: {}", response);
    Ok(())
}
```

**When to use**: Quick questions, simple integrations, when you only need the text content.

### 2. Full Metadata Mode (JSON)

Get structured response with metadata, costs, and session information:

```rust
use claude_sdk_rs::{Client, Config, StreamFormat};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let config = Config::builder()
        .stream_format(StreamFormat::Json)
        .build();
    let client = Client::new(config);
    
    let response = client
        .query("What's the capital of France?")
        .send_full()  // Note: send_full() instead of send()
        .await?;
    
    println!("Response: {}", response.content);
    println!("Session ID: {}", response.meta.session_id);
    println!("Cost: ${:.4}", response.stats.total_cost_usd);
    println!("Tokens used: {}", response.stats.token_usage.total);
    
    Ok(())
}
```

**When to use**: When you need cost tracking, session management, or response metadata.

### 3. Streaming Mode (StreamJSON)

Process responses in real-time as they're generated:

```rust
use claude_sdk_rs::{Client, Config, StreamFormat, Message};
use futures::StreamExt;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let config = Config::builder()
        .stream_format(StreamFormat::StreamJson)
        .build();
    let client = Client::new(config);
    
    let mut stream = client
        .query("Write a short story about a robot")
        .stream()
        .await?;
    
    while let Some(message) = stream.next().await {
        match message? {
            Message::Assistant { content, .. } => {
                print!("{}", content);
                std::io::Write::flush(&mut std::io::stdout()).unwrap();
            }
            Message::Result { stats, .. } => {
                println!("\n\nDone! Cost: ${:.4}", stats.total_cost_usd);
            }
            _ => {}
        }
    }
    
    Ok(())
}
```

**When to use**: Long responses, real-time output, interactive applications.

## Query Builder Options

The query builder provides several options for customizing your requests:

### System Prompts

Set context or instructions for the conversation:

```rust
let response = client
    .query("What's 2+2?")
    .system_prompt("You are a math tutor. Always explain your reasoning.")
    .send()
    .await?;
```

### Model Selection

Choose which Claude model to use:

```rust
let config = Config::builder()
    .model("claude-3-sonnet-20240229")  // Sonnet model
    .build();
let client = Client::new(config);

let response = client
    .query("Write a haiku about programming")
    .send()
    .await?;
```

### Combining Options

```rust
let response = client
    .query("Analyze this code for potential bugs")
    .system_prompt("You are an expert code reviewer")
    .send()
    .await?;
```

## Error Handling Patterns

Understanding and handling different error types:

```rust
use claude_sdk_rs::{Client, Config, Error};

#[tokio::main]
async fn main() {
    let client = Client::new(Config::default());
    
    match client.query("Hello").send().await {
        Ok(response) => {
            println!("Success: {}", response);
        }
        Err(Error::BinaryNotFound) => {
            eprintln!("Error: Claude CLI not found. Please install it first.");
        }
        Err(Error::Timeout) => {
            eprintln!("Error: Request timed out. Try increasing timeout.");
        }
        Err(Error::ProcessError(msg)) => {
            eprintln!("CLI Error: {}", msg);
        }
        Err(e) => {
            eprintln!("Other error: {:?}", e);
        }
    }
}
```

## Practical Examples

### Code Review Assistant

```rust
use claude_sdk_rs::{Client, Config};

async fn review_code(code: &str) -> Result<String, Box<dyn std::error::Error>> {
    let client = Client::new(Config::default());
    
    let prompt = format!(
        "Review this code for bugs, performance issues, and best practices:\n\n```rust\n{}\n```", 
        code
    );
    
    client
        .query(&prompt)
        .system_prompt("You are an expert Rust developer and code reviewer")
        .send()
        .await
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let code = r#"
fn fibonacci(n: u32) -> u32 {
    if n <= 1 { n } else { fibonacci(n-1) + fibonacci(n-2) }
}
"#;
    
    let review = review_code(code).await?;
    println!("Code Review:\n{}", review);
    
    Ok(())
}
```

### Interactive Chat Loop

```rust
use claude_sdk_rs::{Client, Config, StreamFormat};
use std::io::{self, Write};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let config = Config::builder()
        .stream_format(StreamFormat::Json)
        .build();
    let client = Client::new(config);
    
    println!("Claude Chat - Type 'quit' to exit");
    
    loop {
        print!("You: ");
        io::stdout().flush().unwrap();
        
        let mut input = String::new();
        io::stdin().read_line(&mut input).unwrap();
        let input = input.trim();
        
        if input == "quit" {
            break;
        }
        
        let response = client.query(input).send().await?;
        println!("Claude: {}\n", response);
    }
    
    Ok(())
}
```

## Performance Tips

1. **Reuse clients**: Create one client and use it for multiple queries
2. **Choose appropriate timeouts**: Longer queries need longer timeouts
3. **Use streaming for long responses**: Better user experience
4. **Handle errors gracefully**: Don't crash on network issues

## Next Steps

Ready to dive deeper? Check out:

- **Part 3**: [Configuration and Customization]03-configuration.md - Learn about all the ways to customize your client
- **Part 4**: [Streaming Responses]04-streaming-responses.md - Master real-time response processing

## Common Patterns Summary

```rust
// Quick text response
let text = client.query("Hello").send().await?;

// Full metadata
let full = client.query("Hello").send_full().await?;

// Streaming
let mut stream = client.query("Long response").stream().await?;
while let Some(msg) = stream.next().await { /* process */ }

// With options
let response = client
    .query("Question")
    .system_prompt("Context")
    .send()
    .await?;
```

These patterns will cover 90% of your use cases!