agent_code_lib/tools/
mod.rs1pub 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#[async_trait]
65pub trait Tool: Send + Sync {
66 fn name(&self) -> &'static str;
68
69 fn description(&self) -> &'static str;
71
72 fn prompt(&self) -> String {
74 self.description().to_string()
75 }
76
77 fn input_schema(&self) -> serde_json::Value;
79
80 async fn call(
82 &self,
83 input: serde_json::Value,
84 ctx: &ToolContext,
85 ) -> Result<ToolResult, crate::error::ToolError>;
86
87 fn is_read_only(&self) -> bool {
89 false
90 }
91
92 fn is_concurrency_safe(&self) -> bool {
95 self.is_read_only()
96 }
97
98 fn is_destructive(&self) -> bool {
100 false
101 }
102
103 fn is_enabled(&self) -> bool {
105 true
106 }
107
108 fn max_result_size_chars(&self) -> usize {
110 100_000
111 }
112
113 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 fn validate_input(&self, _input: &serde_json::Value) -> Result<(), String> {
128 Ok(())
129 }
130
131 fn get_path(&self, _input: &serde_json::Value) -> Option<PathBuf> {
133 None
134 }
135}
136
137#[derive(Debug, Clone, PartialEq, Eq)]
139pub enum PermissionResponse {
140 AllowOnce,
141 AllowSession,
142 Deny,
143}
144
145pub 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
156pub struct AutoAllowPrompter;
158impl PermissionPrompter for AutoAllowPrompter {
159 fn ask(&self, _: &str, _: &str, _: Option<&str>) -> PermissionResponse {
160 PermissionResponse::AllowOnce
161 }
162}
163
164pub struct ToolContext {
170 pub cwd: PathBuf,
172 pub cancel: CancellationToken,
174 pub permission_checker: Arc<PermissionChecker>,
176 pub verbose: bool,
178 pub plan_mode: bool,
180 pub file_cache: Option<Arc<tokio::sync::Mutex<crate::services::file_cache::FileCache>>>,
182 pub denial_tracker:
184 Option<Arc<tokio::sync::Mutex<crate::permissions::tracking::DenialTracker>>>,
185 pub task_manager: Option<Arc<crate::services::background::TaskManager>>,
187 pub session_allows: Option<Arc<tokio::sync::Mutex<std::collections::HashSet<String>>>>,
189 pub permission_prompter: Option<Arc<dyn PermissionPrompter>>,
191}
192
193#[derive(Debug, Clone, Serialize, Deserialize)]
198pub struct ToolResult {
199 pub content: String,
201 pub is_error: bool,
203}
204
205impl ToolResult {
206 pub fn success(content: impl Into<String>) -> Self {
208 Self {
209 content: content.into(),
210 is_error: false,
211 }
212 }
213
214 pub fn error(content: impl Into<String>) -> Self {
216 Self {
217 content: content.into(),
218 is_error: true,
219 }
220 }
221}
222
223#[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}