Skip to main content

limit_agent/
tool.rs

1//! Tool trait and built-in tools for agent execution.
2//!
3//! This module provides the core [`Tool`] trait for defining executable tools
4//! that can be registered with a [`ToolRegistry`](crate::ToolRegistry) and called by AI agents.
5//!
6//! # Defining Custom Tools
7//!
8//! Implement the [`Tool`] trait to create custom tools:
9//!
10//! ```
11//! use async_trait::async_trait;
12//! use limit_agent::{Tool, AgentError};
13//! use serde_json::{json, Value};
14//!
15//! struct CalculatorTool;
16//!
17//! #[async_trait]
18//! impl Tool for CalculatorTool {
19//!     fn name(&self) -> &str {
20//!         "calculate"
21//!     }
22//!     
23//!     async fn execute(&self, args: Value) -> Result<Value, AgentError> {
24//!         let a = args["a"].as_f64().unwrap_or(0.0);
25//!         let b = args["b"].as_f64().unwrap_or(0.0);
26//!         let op = args["op"].as_str().unwrap_or("+");
27//!         
28//!         let result = match op {
29//!             "+" => a + b,
30//!             "-" => a - b,
31//!             "*" => a * b,
32//!             "/" => a / b,
33//!             _ => return Err(AgentError::ToolError("Unknown operator".into())),
34//!         };
35//!         
36//!         Ok(json!({ "result": result }))
37//!     }
38//! }
39//! ```
40//!
41//! # Built-in Tools
42//!
43//! - [`EchoTool`] — Simple echo tool for testing, returns its input unchanged
44
45use crate::error::AgentError;
46use async_trait::async_trait;
47use serde_json::Value;
48
49/// Trait for defining executable tools.
50///
51/// Tools are the primary way for AI agents to interact with the world.
52/// Each tool has a name and an async execute method that takes JSON
53/// arguments and returns a JSON result.
54///
55/// # Thread Safety
56///
57/// All tools must be `Send + Sync` because they may be executed concurrently
58/// across multiple threads.
59pub trait Tool: Send + Sync {
60    /// Returns the unique name of this tool.
61    ///
62    /// Tool names should be descriptive and follow a consistent naming
63    /// convention (e.g., `snake_case`).
64    fn name(&self) -> &str;
65
66    /// Executes the tool with the given arguments.
67    ///
68    /// # Arguments
69    ///
70    /// * `args` - JSON value containing the tool parameters. The structure
71    ///   depends on the tool's parameter schema.
72    ///
73    /// # Returns
74    ///
75    /// A JSON value containing the tool's output, or an error if execution failed.
76    ///
77    /// # Errors
78    ///
79    /// Returns [`AgentError::ToolError`] if the tool execution fails.
80    fn execute<'life0, 'async_trait>(
81        &'life0 self,
82        args: Value,
83    ) -> ::core::pin::Pin<
84        Box<
85            dyn ::core::future::Future<Output = Result<Value, AgentError>>
86                + ::core::marker::Send
87                + 'async_trait,
88        >,
89    >
90    where
91        'life0: 'async_trait,
92        Self: 'async_trait;
93}
94
95/// A simple echo tool that returns its input unchanged.
96///
97/// Primarily useful for testing the tool registration and execution pipeline.
98pub struct EchoTool;
99
100impl EchoTool {
101    /// Creates a new EchoTool instance.
102    pub fn new() -> Self {
103        EchoTool
104    }
105}
106
107impl Default for EchoTool {
108    fn default() -> Self {
109        Self::new()
110    }
111}
112
113#[async_trait]
114impl Tool for EchoTool {
115    fn name(&self) -> &str {
116        "echo"
117    }
118
119    async fn execute(&self, args: Value) -> Result<Value, AgentError> {
120        // Echo back the input arguments unchanged
121        Ok(args)
122    }
123}