use rsllm::tool;
use rsllm::tools::{ToolCall as ToolCallExec, ToolRegistry};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use serde_json::json;
use std::error::Error;
#[derive(JsonSchema, Serialize, Deserialize)]
pub struct AddParams {
pub a: f64,
pub b: f64,
}
#[derive(JsonSchema, Serialize, Deserialize)]
pub struct MultiplyParams {
pub x: f64,
pub y: f64,
}
#[derive(JsonSchema, Serialize, Deserialize)]
pub struct PowerParams {
pub base: f64,
pub exp: f64,
}
#[derive(JsonSchema, Serialize, Deserialize)]
pub struct MathResult {
pub result: f64,
}
#[tool(description = "Adds two numbers")]
fn add_simple(params: AddParams) -> Result<MathResult, Box<dyn Error + Send + Sync>> {
tracing::debug!(" 🔢 Adding {} + {}", params.a, params.b);
Ok(MathResult {
result: params.a + params.b,
})
}
#[tool(description = "Multiplies two numbers")]
fn multiply(params: MultiplyParams) -> Result<MathResult, Box<dyn Error + Send + Sync>> {
tracing::debug!(" ✖️ Multiplying {} × {}", params.x, params.y);
Ok(MathResult {
result: params.x * params.y,
})
}
#[tool(description = "Raises base to the power of exponent")]
fn power(params: PowerParams) -> Result<MathResult, Box<dyn Error + Send + Sync>> {
tracing::debug!(" ⚡ Calculating {}^{}", params.base, params.exp);
Ok(MathResult {
result: params.base.powf(params.exp),
})
}
fn main() -> Result<(), Box<dyn Error>> {
tracing::debug!("🎯 Tool Calling with Parameter Structs");
tracing::debug!("======================================\n");
let mut registry = ToolRegistry::new();
tracing::debug!("📦 Registering tools...");
registry.register(Box::new(AddSimpleTool))?;
registry.register(Box::new(MultiplyTool))?;
registry.register(Box::new(PowerTool))?;
tracing::debug!(" ✅ Registered {} tools\n", registry.len());
tracing::debug!("💡 Key Point: Each tool uses a params struct for type safety!");
tracing::debug!(" AddParams, MultiplyParams, PowerParams define the schemas\n");
tracing::debug!("🔍 Auto-generated schemas:");
for def in registry.tool_definitions() {
tracing::debug!("\n 📝 {}", def.name);
tracing::debug!(" {}", serde_json::to_string_pretty(&def.parameters)?);
}
tracing::debug!("🚀 Executing tools:\n");
let add_result = registry.execute(&ToolCallExec::new(
"1",
"add_simple",
json!({"a": 15, "b": 27}),
));
tracing::debug!(" ✅ add_simple(15, 27) = {}", add_result.content);
let mul_result = registry.execute(&ToolCallExec::new("2", "multiply", json!({"x": 6, "y": 7})));
tracing::debug!(" ✅ multiply(6, 7) = {}", mul_result.content);
let pow_result = registry.execute(&ToolCallExec::new(
"3",
"power",
json!({"base": 2, "exp": 10}),
));
tracing::debug!(" ✅ power(2, 10) = {}", pow_result.content);
tracing::debug!("\n🎉 Tool calling with parameter structs complete!");
tracing::debug!("\n💡 Benefits:");
tracing::debug!(" ✅ Type-safe parameter definitions");
tracing::debug!(" ✅ Automatic JSON schema generation from Rust types");
tracing::debug!(" ✅ Clear documentation via doc comments");
tracing::debug!(" ✅ Perfect for tools with multiple parameters");
Ok(())
}