descry-tool-core 0.3.1

Core traits and types for descry-tool framework
Documentation
//! Complete example demonstrating #[tool] macro with examples

use descry_tool_core::{call_tool, tool_names, ToolContext, ToolError};
use descry_tool_macros::tool;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::sync::Arc;

// Tool 1: Add
#[derive(Deserialize, JsonSchema)]
struct AddParams {
    a: i32,
    b: i32,
}

#[derive(Serialize, JsonSchema)]
struct AddOutput {
    result: i32,
}

#[tool(
    name = "add",
    description = "Add two numbers"
)]
async fn add(_ctx: Arc<ToolContext>, params: AddParams) -> Result<AddOutput, ToolError> {
    Ok(AddOutput {
        result: params.a + params.b,
    })
}

// Tool 2: Subtract
#[derive(Deserialize, JsonSchema)]
struct SubtractParams {
    a: i32,
    b: i32,
}

#[derive(Serialize, JsonSchema)]
struct SubtractOutput {
    result: i32,
}

#[tool(
    name = "subtract",
    description = "Subtract two numbers"
)]
async fn subtract(_ctx: Arc<ToolContext>, params: SubtractParams) -> Result<SubtractOutput, ToolError> {
    Ok(SubtractOutput {
        result: params.a - params.b,
    })
}

// Tool 3: Divide (with error handling)
#[derive(Deserialize, JsonSchema)]
struct DivideParams {
    dividend: i32,
    divisor: i32,
}

#[derive(Serialize, JsonSchema)]
struct DivideOutput {
    quotient: i32,
    remainder: i32,
}

#[tool(
    name = "divide",
    description = "Divide two integers with remainder"
)]
async fn divide(_ctx: Arc<ToolContext>, params: DivideParams) -> Result<DivideOutput, ToolError> {
    if params.divisor == 0 {
        return Err(ToolError::invalid_params("Divisor cannot be zero"));
    }
    
    Ok(DivideOutput {
        quotient: params.dividend / params.divisor,
        remainder: params.dividend % params.divisor,
    })
}

#[tokio::main]
async fn main() {
    println!("=== Descry 2.0 Complete Example ===\n");

    // Show all registered tools
    let names = tool_names();
    println!("Registered tools: {:?}", names);
    println!("Tool count: {}\n", names.len());

    let ctx = Arc::new(ToolContext::new());

    // Test add
    println!("Testing add(10, 5)...");
    match call_tool("add", serde_json::json!({"a": 10, "b": 5}), ctx.clone()).await {
        Ok(result) => println!("Result: {}\n", serde_json::to_string(&result).unwrap()),
        Err(e) => eprintln!("Error: {}\n", e),
    }

    // Test subtract
    println!("Testing subtract(10, 5)...");
    match call_tool("subtract", serde_json::json!({"a": 10, "b": 5}), ctx.clone()).await {
        Ok(result) => println!("Result: {}\n", serde_json::to_string(&result).unwrap()),
        Err(e) => eprintln!("Error: {}\n", e),
    }

    // Test divide
    println!("Testing divide(17, 5)...");
    match call_tool("divide", serde_json::json!({"dividend": 17, "divisor": 5}), ctx.clone()).await {
        Ok(result) => println!("Result: {}\n", serde_json::to_string(&result).unwrap()),
        Err(e) => eprintln!("Error: {}\n", e),
    }

    // Test divide by zero
    println!("Testing divide(10, 0) [should fail]...");
    match call_tool("divide", serde_json::json!({"dividend": 10, "divisor": 0}), ctx.clone()).await {
        Ok(result) => println!("Result: {}\n", serde_json::to_string(&result).unwrap()),
        Err(e) => println!("Expected error: {}\n", e),
    }

    // Test nonexistent tool
    println!("Testing nonexistent tool [should fail]...");
    match call_tool("power", serde_json::json!({}), ctx).await {
        Ok(result) => println!("Result: {}\n", serde_json::to_string(&result).unwrap()),
        Err(e) => println!("Expected error: {}\n", e),
    }

    // Show tool schemas
    for name in &["add", "subtract", "divide"] {
        if let Some(schema) = descry_tool_core::get_tool_schema(name) {
            println!("Schema for '{}':", name);
            println!("  Title: {}", schema.get("title").unwrap().as_str().unwrap());
            println!("  Properties: {:?}", schema.get("properties").unwrap().as_object().unwrap().keys().collect::<Vec<_>>());
        }
    }
}