Skip to main content
Tools extend agent capabilities beyond text generation.

Quick Start

1

Define Tool

use praisonai::tool;

#[tool(description = "Search the web for information")]
async fn search(query: String) -> String {
    format!("Results for: {}", query)
}
2

Add to Agent

use praisonai::Agent;

let agent = Agent::new()
    .instructions("Use search to help users")
    .tool(search)
    .build()?;

agent.chat("Search for Rust tutorials").await?;

#[tool] Macro

The #[tool] macro automatically:
  • Generates tool schema from function signature
  • Handles JSON serialization/deserialization
  • Registers tool with the agent
#[tool(description = "Description shown to the LLM")]
async fn my_tool(
    param1: String,  // Required parameter
    param2: i32,     // Types are inferred
) -> String {
    // Return result as String
    format!("Got {} and {}", param1, param2)
}

Parameter Types

Supported types in tool functions:
TypeJSON TypeExample
Stringstring"hello"
i32, i64integer42
f32, f64number3.14
boolbooleantrue

Examples

Calculator Tool

#[tool(description = "Add two numbers")]
async fn add(a: i32, b: i32) -> String {
    (a + b).to_string()
}

#[tool(description = "Multiply two numbers")]
async fn multiply(a: i32, b: i32) -> String {
    (a * b).to_string()
}

let agent = Agent::new()
    .instructions("Use calculator tools for math")
    .tool(add)
    .tool(multiply)
    .build()?;

Web Request Tool

#[tool(description = "Fetch content from a URL")]
async fn fetch_url(url: String) -> String {
    // Using reqwest
    match reqwest::get(&url).await {
        Ok(resp) => resp.text().await.unwrap_or_default(),
        Err(e) => format!("Error: {}", e),
    }
}

File Tool

#[tool(description = "Read a text file")]
async fn read_file(path: String) -> String {
    std::fs::read_to_string(&path)
        .unwrap_or_else(|e| format!("Error: {}", e))
}

Manual Tool Implementation

For advanced control, implement the Tool trait directly:
use praisonai::tools::Tool;
use serde_json::{json, Value};

struct MyTool;

impl Tool for MyTool {
    fn name(&self) -> &str {
        "my_tool"
    }
    
    fn description(&self) -> &str {
        "Does something useful"
    }
    
    fn parameters(&self) -> Value {
        json!({
            "type": "object",
            "properties": {
                "input": {
                    "type": "string",
                    "description": "The input value"
                }
            },
            "required": ["input"]
        })
    }
    
    async fn execute(&self, args: Value) -> anyhow::Result<String> {
        let input = args["input"].as_str().unwrap_or("");
        Ok(format!("Processed: {}", input))
    }
}

Best Practices

Write descriptions that help the LLM understand when to use the tool.
Return error messages as strings rather than panicking.
Each tool should do one thing well.