use std::sync::Arc;
use async_trait::async_trait;
use rust_llm::{Agent, Parameter, SharedTool, Tool, ToolCall, ToolError, ToolResult};
use serde_json::{Map, Value, json};
struct Weather;
#[async_trait]
impl Tool for Weather {
fn description(&self) -> String {
"Get current weather".into()
}
fn parameters(&self) -> Vec<Parameter> {
vec![Parameter::new("latitude"), Parameter::new("longitude")]
}
async fn execute(
&self,
args: Map<String, Value>,
_: &ToolCall,
) -> Result<ToolResult, ToolError> {
Ok(json!({ "latitude": args["latitude"], "longitude": args["longitude"], "temperature_2m": 14.2, "wind_speed_10m": 11.0 }).into())
}
}
struct WeatherAssistant;
impl Agent for WeatherAssistant {
fn model(&self) -> Option<&str> {
Some("claude-opus-5-5")
}
fn provider(&self) -> Option<&str> {
Some("anthropic")
}
fn instructions(&self) -> Option<String> {
Some("Be concise and always use tools for weather.".into())
}
fn tools(&self) -> Vec<SharedTool> {
vec![Arc::new(Weather)]
}
}
#[derive(schemars::JsonSchema)]
#[allow(dead_code)]
struct Product {
name: String,
price: f64,
features: Vec<String>,
}
fn new_chat() -> rust_llm::Result<rust_llm::Chat> {
rust_llm::Chat::new(Some("claude-opus-5-5"), Some("anthropic"))
}
#[tokio::main]
async fn main() -> rust_llm::Result<()> {
rust_llm::configure(|c| {
c.default_model = "claude-opus-5-5".into();
if let Ok(base) = std::env::var("ANTHROPIC_BASE_URL") {
c.set("anthropic_api_base", base);
}
if let Ok(key) = std::env::var("ANTHROPIC_AUTH_TOKEN") {
c.set("anthropic_api_key", key);
}
});
let answer = new_chat()?
.with_max_output_tokens(200)
.ask("In one sentence: what's the best way to learn Rust?")
.await?;
println!("ask -> {}", answer.content());
print!("stream -> ");
let mut chat = new_chat()?;
let streamed = chat
.ask_stream(
"Count from 1 to 5, comma separated, nothing else.",
|chunk| {
if let Some(text) = &chunk.content {
print!("{text}");
}
},
)
.await?;
println!(
" [{} in / {} out tokens]",
streamed.tokens().input.unwrap_or(0),
streamed.tokens().output.unwrap_or(0)
);
let mut chat = new_chat()?.with_tool(Weather).before_tool_call(|call| {
println!(
"tool -> {}({})",
call.name,
Value::Object(call.arguments())
)
});
let weather = chat
.ask("What's the weather in Berlin (52.52, 13.405)? One sentence.")
.await?;
println!("tools -> {}", weather.content());
let reply = WeatherAssistant
.chat()?
.ask("Weather in Paris (48.8575, 2.3514)?")
.await?;
println!("agent -> {}", reply.content());
let mut chat = new_chat()?.with_schema_for::<Product>();
let product = chat
.ask("Invent a product: a mechanical keyboard for Rust programmers.")
.await?;
println!("schema -> {}", product.parsed()?.unwrap_or_default());
println!(
"cost -> ${:.6} across {} billed requests",
chat.cost().total().unwrap_or_default(),
chat.usage_entries().len()
);
Ok(())
}