Skip to main content

agent_code_lib/tools/
mod.rs

1//! Tool system.
2//!
3//! Tools are the primary way the agent interacts with the environment.
4//! Each tool implements the `Tool` trait and is registered in the
5//! `ToolRegistry` for dispatch by name.
6//!
7//! # Architecture
8//!
9//! - `Tool` trait — defines the interface for all tools
10//! - `ToolRegistry` — collects tools and dispatches by name
11//! - `ToolExecutor` — manages concurrent/serial tool execution
12//! - Individual tool modules — concrete implementations
13//!
14//! # Tool execution flow
15//!
16//! 1. Input validation (schema check)
17//! 2. Permission check (allow/ask/deny)
18//! 3. Tool execution (`call`)
19//! 4. Result mapping (to API format)
20
21pub mod agent;
22pub mod ask_user;
23pub mod bash;
24pub mod bash_parse;
25pub mod executor;
26pub mod file_edit;
27pub mod file_read;
28pub mod file_write;
29pub mod glob;
30pub mod grep;
31pub mod lsp_tool;
32pub mod mcp_proxy;
33pub mod mcp_resources;
34pub mod multi_edit;
35pub mod notebook_edit;
36pub mod plan_mode;
37pub mod plugin_exec;
38pub mod powershell;
39pub mod registry;
40pub mod repl_tool;
41pub mod send_message;
42pub mod skill_tool;
43pub mod sleep_tool;
44pub mod tasks;
45pub mod todo_write;
46pub mod tool_search;
47pub mod web_fetch;
48pub mod web_search;
49pub mod worktree;
50
51use async_trait::async_trait;
52use serde::{Deserialize, Serialize};
53use std::path::PathBuf;
54use std::sync::Arc;
55use tokio_util::sync::CancellationToken;
56
57use crate::permissions::{PermissionChecker, PermissionDecision};
58
59/// The core trait that all tools must implement.
60///
61/// Tools are the bridge between the LLM's intentions and the local
62/// environment. Each tool defines its input schema (for the LLM),
63/// permission requirements, concurrency behavior, and execution logic.
64#[async_trait]
65pub trait Tool: Send + Sync {
66    /// Unique tool name used in API tool_use blocks.
67    fn name(&self) -> &'static str;
68
69    /// Human-readable description sent to the LLM.
70    fn description(&self) -> &'static str;
71
72    /// System prompt instructions for this tool.
73    fn prompt(&self) -> String {
74        self.description().to_string()
75    }
76
77    /// JSON Schema for the tool's input parameters.
78    fn input_schema(&self) -> serde_json::Value;
79
80    /// Execute the tool with validated input.
81    async fn call(
82        &self,
83        input: serde_json::Value,
84        ctx: &ToolContext,
85    ) -> Result<ToolResult, crate::error::ToolError>;
86
87    /// Whether this tool only reads state (no mutations).
88    fn is_read_only(&self) -> bool {
89        false
90    }
91
92    /// Whether this tool can safely run concurrently with other tools.
93    /// Read-only tools are typically concurrency-safe.
94    fn is_concurrency_safe(&self) -> bool {
95        self.is_read_only()
96    }
97
98    /// Whether this tool is destructive (deletes data, force-pushes, etc.).
99    fn is_destructive(&self) -> bool {
100        false
101    }
102
103    /// Whether this tool is currently enabled in the environment.
104    fn is_enabled(&self) -> bool {
105        true
106    }
107
108    /// Maximum result size in characters before truncation.
109    fn max_result_size_chars(&self) -> usize {
110        100_000
111    }
112
113    /// Check permissions for executing this tool with the given input.
114    async fn check_permissions(
115        &self,
116        input: &serde_json::Value,
117        checker: &PermissionChecker,
118    ) -> PermissionDecision {
119        if self.is_read_only() {
120            PermissionDecision::Allow
121        } else {
122            checker.check(self.name(), input)
123        }
124    }
125
126    /// Validate tool input before execution.
127    fn validate_input(&self, _input: &serde_json::Value) -> Result<(), String> {
128        Ok(())
129    }
130
131    /// Extract a file path from the input, if applicable (for permission matching).
132    fn get_path(&self, _input: &serde_json::Value) -> Option<PathBuf> {
133        None
134    }
135}
136
137/// Permission prompt response from the UI layer.
138#[derive(Debug, Clone, PartialEq, Eq)]
139pub enum PermissionResponse {
140    AllowOnce,
141    AllowSession,
142    Deny,
143}
144
145/// Trait for prompting the user for permission decisions.
146/// Implemented by the CLI's UI layer; the lib engine uses this abstraction.
147pub trait PermissionPrompter: Send + Sync {
148    fn ask(
149        &self,
150        tool_name: &str,
151        description: &str,
152        input_preview: Option<&str>,
153    ) -> PermissionResponse;
154}
155
156/// Default prompter that always allows (for non-interactive/testing).
157pub struct AutoAllowPrompter;
158impl PermissionPrompter for AutoAllowPrompter {
159    fn ask(&self, _: &str, _: &str, _: Option<&str>) -> PermissionResponse {
160        PermissionResponse::AllowOnce
161    }
162}
163
164/// Context passed to every tool during execution.
165///
166/// Provides the working directory, cancellation token, permission
167/// checker, file cache, and other shared state. Created by the
168/// executor before each tool call.
169pub struct ToolContext {
170    /// Current working directory.
171    pub cwd: PathBuf,
172    /// Cancellation token for cooperative cancellation.
173    pub cancel: CancellationToken,
174    /// Permission checker instance.
175    pub permission_checker: Arc<PermissionChecker>,
176    /// Whether to produce verbose output.
177    pub verbose: bool,
178    /// Plan mode: only read-only tools allowed.
179    pub plan_mode: bool,
180    /// File content cache for avoiding redundant reads.
181    pub file_cache: Option<Arc<tokio::sync::Mutex<crate::services::file_cache::FileCache>>>,
182    /// Permission denial tracker for reporting.
183    pub denial_tracker:
184        Option<Arc<tokio::sync::Mutex<crate::permissions::tracking::DenialTracker>>>,
185    /// Shared background task manager.
186    pub task_manager: Option<Arc<crate::services::background::TaskManager>>,
187    /// Tools allowed for the rest of the session (via "Allow for session" prompt).
188    pub session_allows: Option<Arc<tokio::sync::Mutex<std::collections::HashSet<String>>>>,
189    /// Permission prompter for interactive approval.
190    pub permission_prompter: Option<Arc<dyn PermissionPrompter>>,
191}
192
193/// Result of a tool execution.
194///
195/// Contains the output text and whether it represents an error.
196/// Injected into the conversation as a `ToolResult` content block.
197#[derive(Debug, Clone, Serialize, Deserialize)]
198pub struct ToolResult {
199    /// The main output content.
200    pub content: String,
201    /// Whether the result represents an error.
202    pub is_error: bool,
203}
204
205impl ToolResult {
206    /// Create a successful result.
207    pub fn success(content: impl Into<String>) -> Self {
208        Self {
209            content: content.into(),
210            is_error: false,
211        }
212    }
213
214    /// Create an error result.
215    pub fn error(content: impl Into<String>) -> Self {
216        Self {
217            content: content.into(),
218            is_error: true,
219        }
220    }
221}
222
223/// Schema information for a tool, used when building API requests.
224#[derive(Debug, Clone, Serialize)]
225pub struct ToolSchema {
226    pub name: &'static str,
227    pub description: &'static str,
228    pub input_schema: serde_json::Value,
229}
230
231impl<T: Tool + ?Sized> From<&T> for ToolSchema {
232    fn from(tool: &T) -> Self {
233        Self {
234            name: tool.name(),
235            description: tool.description(),
236            input_schema: tool.input_schema(),
237        }
238    }
239}