use anyllm_client::{Client, ClientError, ToolBuilder, ToolChoiceBuilder};
use anyllm_translate::anthropic::{ContentBlock, MessageCreateRequest, StopReason};
use serde_json::json;
#[tokio::main]
async fn main() {
if let Err(e) = run().await {
eprintln!("Error: {e}");
std::process::exit(1);
}
}
async fn run() -> Result<(), ClientError> {
let url = std::env::var("CHAT_COMPLETIONS_URL")
.unwrap_or_else(|_| "https://api.openai.com/v1/chat/completions".to_string());
let api_key = std::env::var("OPENAI_API_KEY").unwrap_or_default();
let client = Client::builder().base_url(&url).api_key(&api_key).build()?;
let weather_tool = ToolBuilder::new("get_weather")
.description("Get the current weather for a location")
.input_schema(json!({
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "City and country, e.g. 'Paris, France'"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "Temperature unit"
}
},
"required": ["location"]
}))
.build();
let req: MessageCreateRequest = serde_json::from_value(json!({
"model": "claude-sonnet-4-6",
"max_tokens": 512,
"messages": [
{"role": "user", "content": "What is the weather like in Tokyo right now?"}
],
"tools": [serde_json::to_value(&weather_tool).unwrap()],
"tool_choice": serde_json::to_value(ToolChoiceBuilder::auto()).unwrap()
}))
.expect("request JSON is valid");
let response = client.messages(&req).await?;
println!("stop_reason: {:?}", response.stop_reason);
for block in &response.content {
match block {
ContentBlock::Text { text } => {
println!("text: {text}");
}
ContentBlock::ToolUse { id, name, input } => {
println!("tool_use: name={name} id={id}");
println!(" input: {}", serde_json::to_string_pretty(input).unwrap());
let _tool_result = call_weather_tool(input);
println!(" (tool execution would happen here)");
}
_ => {}
}
}
if matches!(response.stop_reason, Some(StopReason::ToolUse)) {
println!("\nNext step: send tool result back in a follow-up messages() call.");
}
Ok(())
}
fn call_weather_tool(input: &serde_json::Value) -> String {
let location = input
.get("location")
.and_then(|v| v.as_str())
.unwrap_or("unknown");
format!("Weather in {location}: 22°C, partly cloudy")
}