Skip to main content

pulse_system_types/
tool.rs

1//! Tool trait — the shared contract for LLM-callable tools.
2//!
3//! Plugins contribute tools via [`Plugin::tools()`](crate::plugin::Plugin::tools).
4//! The host registers them and exposes them to the LLM.
5
6use std::fmt;
7use std::future::Future;
8use std::pin::Pin;
9
10/// Async result type for tool execution.
11pub type ToolResult<'a> = Pin<Box<dyn Future<Output = Result<String, ToolError>> + Send + 'a>>;
12
13/// Errors from tool execution.
14#[derive(Debug)]
15pub enum ToolError {
16    /// The requested resource was not found.
17    NotFound(String),
18    /// Tool execution failed.
19    ExecutionFailed(String),
20    /// Access denied.
21    PermissionDenied(String),
22}
23
24impl fmt::Display for ToolError {
25    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26        match self {
27            ToolError::NotFound(msg) => write!(f, "not found: {msg}"),
28            ToolError::ExecutionFailed(msg) => write!(f, "execution failed: {msg}"),
29            ToolError::PermissionDenied(msg) => write!(f, "permission denied: {msg}"),
30        }
31    }
32}
33
34impl std::error::Error for ToolError {}
35
36/// A tool that can be invoked by an LLM.
37///
38/// Tools are contributed by plugins via [`Plugin::tools()`](crate::plugin::Plugin::tools)
39/// and registered with the host's tool registry. The LLM calls tools by name.
40///
41/// # Object Safety
42///
43/// This trait is object-safe and designed for use as `Box<dyn Tool>`.
44pub trait Tool: Send + Sync {
45    /// Tool name — must match what the LLM calls.
46    fn name(&self) -> &str;
47
48    /// Human-readable description for the LLM.
49    fn description(&self) -> &str;
50
51    /// JSON Schema for the tool's input parameters.
52    fn input_schema(&self) -> serde_json::Value;
53
54    /// Execute the tool with the given input.
55    fn execute(&self, input: serde_json::Value) -> ToolResult<'_>;
56}