use claude_agent_sdk::{
ClaudeAgentOptions, ClaudeClient, ContentBlock, Message, ToolResultContent,
};
use futures::StreamExt;
use std::env;
use std::time::Duration;
fn display_message(msg: &Message) {
match msg {
Message::User(user_msg) => {
if let Some(ref content) = user_msg.content {
for block in content {
if let ContentBlock::Text(text) = block {
println!("User: {}", text.text);
}
}
} else if let Some(ref text) = user_msg.text {
println!("User: {}", text);
}
},
Message::Assistant(assistant_msg) => {
for block in &assistant_msg.message.content {
if let ContentBlock::Text(text) = block {
println!("Claude: {}", text.text);
}
}
},
Message::System(_) => {
},
Message::Result(_) => {
println!("Result ended");
},
_ => {},
}
}
async fn example_basic_streaming() -> Result<(), Box<dyn std::error::Error>> {
println!("=== Basic Streaming Example ===");
let mut client = ClaudeClient::new(ClaudeAgentOptions::default());
client.connect().await?;
println!("User: What is 2+2?");
client.query("What is 2+2?").await?;
let mut stream = client.receive_response();
while let Some(message) = stream.next().await {
display_message(&message?);
}
drop(stream);
client.disconnect().await?;
println!("\n");
Ok(())
}
async fn example_multi_turn_conversation() -> Result<(), Box<dyn std::error::Error>> {
println!("=== Multi-Turn Conversation Example ===");
let mut client = ClaudeClient::new(ClaudeAgentOptions::default());
client.connect().await?;
println!("User: What's the capital of France?");
client.query("What's the capital of France?").await?;
let mut stream = client.receive_response();
while let Some(message) = stream.next().await {
display_message(&message?);
}
drop(stream);
println!("\nUser: What's the population of that city?");
client.query("What's the population of that city?").await?;
let mut stream = client.receive_response();
while let Some(message) = stream.next().await {
display_message(&message?);
}
drop(stream);
client.disconnect().await?;
println!("\n");
Ok(())
}
async fn example_with_options() -> Result<(), Box<dyn std::error::Error>> {
println!("=== Custom Options Example ===");
let options = ClaudeAgentOptions {
allowed_tools: vec!["Read".to_string(), "Write".to_string()], system_prompt: Some("You are a helpful coding assistant.".into()),
..Default::default()
};
let mut client = ClaudeClient::new(options);
client.connect().await?;
println!("User: Create a simple hello.txt file with a greeting message");
client
.query("Create a simple hello.txt file with a greeting message")
.await?;
let mut tool_uses = Vec::new();
let mut stream = client.receive_response();
while let Some(message) = stream.next().await {
let msg = message?;
if let Message::Assistant(ref assistant_msg) = msg {
display_message(&msg);
for block in &assistant_msg.message.content {
if let ContentBlock::ToolUse(tool_use) = block {
tool_uses.push(tool_use.name.clone());
}
}
} else {
display_message(&msg);
}
}
drop(stream);
if !tool_uses.is_empty() {
println!("Tools used: {}", tool_uses.join(", "));
}
client.disconnect().await?;
println!("\n");
Ok(())
}
async fn example_manual_message_handling() -> Result<(), Box<dyn std::error::Error>> {
println!("=== Manual Message Handling Example ===");
let mut client = ClaudeClient::new(ClaudeAgentOptions::default());
client.connect().await?;
client
.query("List 5 programming languages and their main use cases")
.await?;
let mut languages_found = Vec::new();
let language_list = vec!["Python", "JavaScript", "Java", "C++", "Go", "Rust", "Ruby"];
let mut stream = client.receive_messages();
while let Some(message) = stream.next().await {
let msg = message?;
match msg {
Message::Assistant(assistant_msg) => {
for block in assistant_msg.message.content {
if let ContentBlock::Text(text) = block {
println!("Claude: {}", text.text);
for lang in &language_list {
if text.text.contains(lang)
&& !languages_found.contains(&lang.to_string())
{
languages_found.push(lang.to_string());
println!("Found language: {}", lang);
}
}
}
}
},
Message::Result(_) => {
display_message(&msg);
println!("Total languages mentioned: {}", languages_found.len());
break;
},
_ => {},
}
}
drop(stream);
client.disconnect().await?;
println!("\n");
Ok(())
}
async fn example_bash_command() -> Result<(), Box<dyn std::error::Error>> {
println!("=== Bash Command Example ===");
let mut client = ClaudeClient::new(ClaudeAgentOptions::default());
client.connect().await?;
println!("User: Run a bash echo command");
client
.query("Run a bash echo command that says 'Hello from bash!'")
.await?;
let mut message_types = Vec::new();
let mut stream = client.receive_messages();
while let Some(message) = stream.next().await {
let msg = message?;
message_types.push(
format!("{:?}", msg)
.split('(')
.next()
.unwrap_or("Unknown")
.to_string(),
);
match msg {
Message::User(user_msg) => {
if let Some(ref content) = user_msg.content {
for block in content {
if let ContentBlock::Text(text) = block {
println!("User: {}", text.text);
} else if let ContentBlock::ToolResult(tool_result) = block {
let content_str = match &tool_result.content {
Some(ToolResultContent::Text(s)) => s.as_str(),
Some(ToolResultContent::Blocks(_)) => "[structured content]",
None => "None",
};
let preview = if content_str.len() > 100 {
&content_str[..100]
} else {
content_str
};
println!(
"Tool Result (id: {}): {}...",
tool_result.tool_use_id, preview
);
}
}
}
},
Message::Assistant(assistant_msg) => {
for block in assistant_msg.message.content {
match block {
ContentBlock::Text(text) => {
println!("Claude: {}", text.text);
},
ContentBlock::ToolUse(tool_use) => {
println!("Tool Use: {} (id: {})", tool_use.name, tool_use.id);
if tool_use.name == "Bash"
&& let Some(command) = tool_use.input.get("command")
&& let Some(cmd_str) = command.as_str()
{
println!(" Command: {}", cmd_str);
}
},
_ => {},
}
}
},
Message::Result(result_msg) => {
println!("Result ended");
if let Some(cost) = result_msg.total_cost_usd {
println!("Cost: ${:.4}", cost);
}
break;
},
_ => {},
}
}
drop(stream);
let mut unique_types: Vec<_> = message_types.into_iter().collect();
unique_types.sort();
unique_types.dedup();
println!("\nMessage types received: {}", unique_types.join(", "));
client.disconnect().await?;
println!("\n");
Ok(())
}
async fn example_control_protocol() -> Result<(), Box<dyn std::error::Error>> {
println!("=== Control Protocol Example ===");
println!("Shows server info retrieval and interrupt capability\n");
let mut client = ClaudeClient::new(ClaudeAgentOptions::default());
client.connect().await?;
println!("1. Getting server info...");
let server_info = client.get_server_info().await;
if let Some(info) = server_info {
println!("✓ Server info retrieved successfully!");
if let Some(commands) = info.get("commands")
&& let Some(commands_array) = commands.as_array()
{
println!(" - Available commands: {}", commands_array.len());
}
if let Some(output_style) = info.get("output_style") {
println!(" - Output style: {}", output_style);
}
if let Some(styles) = info.get("available_output_styles")
&& let Some(styles_array) = styles.as_array()
{
let style_names: Vec<_> = styles_array.iter().filter_map(|s| s.as_str()).collect();
println!(" - Available output styles: {}", style_names.join(", "));
}
if let Some(commands) = info.get("commands")
&& let Some(commands_array) = commands.as_array()
{
println!(" - Example commands:");
for cmd in commands_array.iter().take(5) {
if let Some(name) = cmd.get("name")
&& let Some(name_str) = name.as_str()
{
println!(" • {}", name_str);
}
}
}
} else {
println!("✗ No server info available (may not be in streaming mode)");
}
println!("\n2. Testing interrupt capability...");
println!("User: Count from 1 to 20 slowly");
client
.query("Count from 1 to 20 slowly, pausing between each number")
.await?;
let mut messages = Vec::new();
let mut stream = client.receive_response();
for _ in 0..3 {
if let Some(message) = stream.next().await {
let msg = message?;
if let Message::Assistant(ref assistant_msg) = msg {
for block in &assistant_msg.message.content {
if let ContentBlock::Text(text) = block {
let preview = if text.text.len() > 50 {
&text.text[..50]
} else {
&text.text
};
println!("Claude: {}...", preview);
break;
}
}
}
messages.push(msg);
}
}
drop(stream);
tokio::time::sleep(Duration::from_secs(2)).await;
println!("\n[Sending interrupt after 2 seconds...]");
match client.interrupt().await {
Ok(_) => println!("✓ Interrupt sent successfully"),
Err(e) => println!("✗ Interrupt failed: {}", e),
}
tokio::time::sleep(Duration::from_millis(500)).await;
println!("\nUser: Just say 'Hello!'");
client.query("Just say 'Hello!'").await?;
let mut stream = client.receive_response();
while let Some(message) = stream.next().await {
let msg = message?;
if let Message::Assistant(ref assistant_msg) = msg {
for block in &assistant_msg.message.content {
if let ContentBlock::Text(text) = block {
println!("Claude: {}", text.text);
}
}
}
}
drop(stream);
client.disconnect().await?;
println!("\n");
Ok(())
}
async fn example_error_handling() -> Result<(), Box<dyn std::error::Error>> {
println!("=== Error Handling Example ===");
let mut client = ClaudeClient::new(ClaudeAgentOptions::default());
match client.connect().await {
Ok(_) => {
println!("User: Run a bash sleep command for 60 seconds not in the background");
client
.query("Run a bash sleep command for 60 seconds not in the background")
.await?;
let mut messages = Vec::new();
let timeout_duration = Duration::from_secs(10);
match tokio::time::timeout(timeout_duration, async {
let mut stream = client.receive_response();
while let Some(message) = stream.next().await {
let msg = message?;
if let Message::Assistant(ref assistant_msg) = msg {
for block in &assistant_msg.message.content {
if let ContentBlock::Text(text) = block {
let preview = if text.text.len() > 50 {
&text.text[..50]
} else {
&text.text
};
println!("Claude: {}...", preview);
}
}
} else if let Message::Result(_) = msg {
display_message(&msg);
}
messages.push(msg);
}
Ok::<(), Box<dyn std::error::Error>>(())
})
.await
{
Ok(result) => {
result?;
},
Err(_) => {
println!(
"\nResponse timeout after 10 seconds - demonstrating graceful handling"
);
println!("Received {} messages before timeout", messages.len());
},
}
},
Err(e) => {
println!("Connection error: {}", e);
},
}
client.disconnect().await?;
println!("\n");
Ok(())
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let args: Vec<String> = env::args().collect();
if args.len() < 2 {
println!("Usage: cargo run --example 14_streaming_mode <example_name>");
println!("\nAvailable examples:");
println!(" all - Run all examples");
println!(" basic_streaming");
println!(" multi_turn_conversation");
println!(" with_options");
println!(" manual_message_handling");
println!(" bash_command");
println!(" control_protocol");
println!(" error_handling");
return Ok(());
}
let example_name = &args[1];
match example_name.as_str() {
"all" => {
println!("\n=== Running: basic_streaming ===\n");
example_basic_streaming().await?;
println!("{}\n", "-".repeat(50));
println!("\n=== Running: multi_turn_conversation ===\n");
example_multi_turn_conversation().await?;
println!("{}\n", "-".repeat(50));
println!("\n=== Running: with_options ===\n");
example_with_options().await?;
println!("{}\n", "-".repeat(50));
println!("\n=== Running: manual_message_handling ===\n");
example_manual_message_handling().await?;
println!("{}\n", "-".repeat(50));
println!("\n=== Running: bash_command ===\n");
example_bash_command().await?;
println!("{}\n", "-".repeat(50));
println!("\n=== Running: control_protocol ===\n");
example_control_protocol().await?;
println!("{}\n", "-".repeat(50));
println!("\n=== Running: error_handling ===\n");
example_error_handling().await?;
println!("{}\n", "-".repeat(50));
},
"basic_streaming" => example_basic_streaming().await?,
"multi_turn_conversation" => example_multi_turn_conversation().await?,
"with_options" => example_with_options().await?,
"manual_message_handling" => example_manual_message_handling().await?,
"bash_command" => example_bash_command().await?,
"control_protocol" => example_control_protocol().await?,
"error_handling" => example_error_handling().await?,
_ => {
println!("Error: Unknown example '{}'", example_name);
println!("\nAvailable examples:");
println!(" all - Run all examples");
println!(" basic_streaming");
println!(" multi_turn_conversation");
println!(" with_options");
println!(" manual_message_handling");
println!(" bash_command");
println!(" control_protocol");
println!(" error_handling");
std::process::exit(1);
},
}
Ok(())
}