use claude_api::Client;
use claude_api::messages::{
ContentBlock, CreateMessageRequest, CustomTool, KnownBlock, MessageInput, Tool,
ToolResultContent,
};
use claude_api::types::{ModelId, StopReason};
use serde_json::json;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let api_key = std::env::var("ANTHROPIC_API_KEY")
.map_err(|_| "ANTHROPIC_API_KEY must be set in the environment")?;
let client = Client::new(api_key);
let weather_tool = Tool::Custom(
CustomTool::new(
"get_weather",
json!({
"type": "object",
"properties": {
"city": {"type": "string", "description": "City name"}
},
"required": ["city"]
}),
)
.description("Get the current weather for a city. Returns a short string."),
);
let mut messages = vec![MessageInput::user(
"What's the weather like in Paris and Tokyo right now?",
)];
for iteration in 1..=8 {
let request = CreateMessageRequest::builder()
.model(ModelId::SONNET_4_6)
.max_tokens(1024)
.messages(messages.clone())
.tools(vec![weather_tool.clone()])
.build()?;
let response = client.messages().create(request).await?;
for block in &response.content {
if let ContentBlock::Known(KnownBlock::Text { text, .. }) = block {
println!("[assistant#{iteration}] {text}");
}
}
if response.stop_reason != Some(StopReason::ToolUse) {
break;
}
messages.push(MessageInput::assistant(response.content.clone()));
let mut tool_results: Vec<ContentBlock> = Vec::new();
for block in &response.content {
if let ContentBlock::Known(KnownBlock::ToolUse { id, name, input }) = block {
println!("[tool#{iteration}] {name}({input})");
let result = run_tool(name, input);
println!("[result#{iteration}] {result}");
tool_results.push(ContentBlock::Known(KnownBlock::ToolResult {
tool_use_id: id.clone(),
content: ToolResultContent::Text(result),
is_error: None,
cache_control: None,
}));
}
}
messages.push(MessageInput::user(tool_results));
}
Ok(())
}
fn run_tool(name: &str, input: &serde_json::Value) -> String {
match name {
"get_weather" => {
let city = input.get("city").and_then(|v| v.as_str()).unwrap_or("?");
format!("It's 72°F and sunny in {city}.")
}
other => format!("(no implementation registered for tool '{other}')"),
}
}