Skip to main content
Tools extend agent capabilities by providing callable functions for actions like searching, calculating, or API calls.

Quick Start

1

Create a Tool with #[tool] Macro

use praisonai::{Agent, tool};

#[tool]
fn search(query: String) -> String {
    format!("Results for: {}", query)
}

let agent = Agent::new()
    .name("Researcher")
    .instructions("Use the search tool when asked")
    .tool(search)
    .build()?;

let response = agent.chat("Search for Rust programming").await?;
2

Tool with Description

use praisonai::tool;

#[tool(description = "Calculate a mathematical expression")]
fn calculate(expression: String) -> String {
    // Parse and evaluate expression
    format!("Result: {}", expression)
}
3

Async Tool

use praisonai::tool;

#[tool(description = "Fetch data from a URL")]
async fn fetch_url(url: String) -> String {
    // Async HTTP request
    format!("Fetched content from: {}", url)
}

User Interaction Flow


Tool Trait

Define custom tools by implementing the Tool trait:
#[async_trait]
pub trait Tool: Send + Sync {
    fn name(&self) -> &str;
    fn description(&self) -> &str;
    fn parameters_schema(&self) -> Value;
    async fn execute(&self, args: Value) -> Result<Value>;
    fn definition(&self) -> ToolDefinition;  // default impl
}

Trait Methods

MethodSignatureDescription
name()fn name(&self) -> &strTool identifier
description()fn description(&self) -> &strHuman-readable description
parameters_schema()fn parameters_schema(&self) -> ValueJSON Schema for parameters
execute(args)async fn execute(&self, Value) -> Result<Value>Run the tool
definition()fn definition(&self) -> ToolDefinitionGet LLM function definition

ToolRegistry

Manages a collection of tools for an agent.
pub struct ToolRegistry {
    tools: HashMap<String, Arc<dyn Tool>>,
}

Methods

MethodSignatureDescription
new()fn new() -> SelfCreate empty registry
register(tool)fn register(&mut self, impl Tool + 'static)Add a tool
get(name)fn get(&self, &str) -> Option<Arc<dyn Tool>>Get tool by name
has(name)fn has(&self, &str) -> boolCheck if tool exists
list()fn list(&self) -> Vec<&str>List all tool names
definitions()fn definitions(&self) -> Vec<ToolDefinition>Get all definitions
execute(name, args)async fn execute(&self, &str, Value) -> Result<ToolResult>Run tool
len()fn len(&self) -> usizeNumber of tools

ToolResult

Result returned from tool execution.
pub struct ToolResult {
    pub name: String,
    pub value: Value,
    pub success: bool,
    pub error: Option<String>,
}

Factory Methods

MethodSignatureDescription
success(name, value)fn success(impl Into<String>, Value) -> SelfCreate success result
failure(name, error)fn failure(impl Into<String>, impl Into<String>) -> SelfCreate error result

ToolDefinition

Definition sent to LLM for function calling.
pub struct ToolDefinition {
    pub name: String,
    pub description: String,
    pub parameters: Value,  // JSON Schema
}

Creating Tools

use praisonai::tool;

// Basic tool
#[tool]
fn greet(name: String) -> String {
    format!("Hello, {}!", name)
}

// With description
#[tool(description = "Add two numbers together")]
fn add(a: i32, b: i32) -> i32 {
    a + b
}

// Async tool
#[tool(description = "Fetch weather data")]
async fn get_weather(city: String) -> String {
    format!("Weather in {}: Sunny", city)
}

Using FunctionTool

use praisonai::FunctionTool;
use serde_json::json;

let tool = FunctionTool::new(
    "greet",
    "Greet a person by name",
    json!({
        "type": "object",
        "properties": {
            "name": {"type": "string"}
        },
        "required": ["name"]
    }),
    |args| async move {
        let name = args["name"].as_str().unwrap_or("World");
        Ok(json!(format!("Hello, {}!", name)))
    }
);

Implementing Tool Trait

use praisonai::{Tool, async_trait};
use serde_json::{Value, json};

struct MyTool;

#[async_trait]
impl Tool for MyTool {
    fn name(&self) -> &str { "my_tool" }
    
    fn description(&self) -> &str { "Custom tool implementation" }
    
    fn parameters_schema(&self) -> Value {
        json!({
            "type": "object",
            "properties": {
                "input": {"type": "string"}
            }
        })
    }
    
    async fn execute(&self, args: Value) -> Result<Value> {
        let input = args["input"].as_str().unwrap_or("");
        Ok(json!(format!("Processed: {}", input)))
    }
}

Multiple Tools Example

use praisonai::{Agent, tool};

#[tool(description = "Search the web for information")]
fn web_search(query: String) -> String {
    format!("Web results for: {}", query)
}

#[tool(description = "Calculate a math expression")]
fn calculate(expr: String) -> String {
    format!("Calculation: {} = 42", expr)
}

#[tool(description = "Get current time")]
fn get_time() -> String {
    "Current time: 12:34 PM".to_string()
}

let agent = Agent::new()
    .name("MultiTool Agent")
    .instructions("Use available tools to help the user")
    .tool(web_search)
    .tool(calculate)
    .tool(get_time)
    .build()?;

let response = agent.chat("What time is it and search for today's weather").await?;

Best Practices

Names should clearly indicate what the tool does: web_search, calculate_tax, send_email.
The LLM uses descriptions to decide when to call tools. Be specific and clear.
Return meaningful error messages that help the agent recover.
Each tool should do one thing well. Compose multiple tools for complex operations.