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 powershell;
38pub mod registry;
39pub mod repl_tool;
40pub mod send_message;
41pub mod skill_tool;
42pub mod sleep_tool;
43pub mod tasks;
44pub mod todo_write;
45pub mod tool_search;
46pub mod web_fetch;
47pub mod web_search;
48pub mod worktree;
49
50use async_trait::async_trait;
51use serde::{Deserialize, Serialize};
52use std::path::PathBuf;
53use std::sync::Arc;
54use tokio_util::sync::CancellationToken;
55
56use crate::permissions::{PermissionChecker, PermissionDecision};
57
58#[async_trait]
64pub trait Tool: Send + Sync {
65 fn name(&self) -> &'static str;
67
68 fn description(&self) -> &'static str;
70
71 fn prompt(&self) -> String {
73 self.description().to_string()
74 }
75
76 fn input_schema(&self) -> serde_json::Value;
78
79 async fn call(
81 &self,
82 input: serde_json::Value,
83 ctx: &ToolContext,
84 ) -> Result<ToolResult, crate::error::ToolError>;
85
86 fn is_read_only(&self) -> bool {
88 false
89 }
90
91 fn is_concurrency_safe(&self) -> bool {
94 self.is_read_only()
95 }
96
97 fn is_destructive(&self) -> bool {
99 false
100 }
101
102 fn is_enabled(&self) -> bool {
104 true
105 }
106
107 fn max_result_size_chars(&self) -> usize {
109 100_000
110 }
111
112 async fn check_permissions(
114 &self,
115 input: &serde_json::Value,
116 checker: &PermissionChecker,
117 ) -> PermissionDecision {
118 if self.is_read_only() {
119 PermissionDecision::Allow
120 } else {
121 checker.check(self.name(), input)
122 }
123 }
124
125 fn validate_input(&self, _input: &serde_json::Value) -> Result<(), String> {
127 Ok(())
128 }
129
130 fn get_path(&self, _input: &serde_json::Value) -> Option<PathBuf> {
132 None
133 }
134}
135
136#[derive(Debug, Clone, PartialEq, Eq)]
138pub enum PermissionResponse {
139 AllowOnce,
140 AllowSession,
141 Deny,
142}
143
144pub trait PermissionPrompter: Send + Sync {
147 fn ask(
148 &self,
149 tool_name: &str,
150 description: &str,
151 input_preview: Option<&str>,
152 ) -> PermissionResponse;
153}
154
155pub struct AutoAllowPrompter;
157impl PermissionPrompter for AutoAllowPrompter {
158 fn ask(&self, _: &str, _: &str, _: Option<&str>) -> PermissionResponse {
159 PermissionResponse::AllowOnce
160 }
161}
162
163pub struct ToolContext {
165 pub cwd: PathBuf,
167 pub cancel: CancellationToken,
169 pub permission_checker: Arc<PermissionChecker>,
171 pub verbose: bool,
173 pub plan_mode: bool,
175 pub file_cache: Option<Arc<tokio::sync::Mutex<crate::services::file_cache::FileCache>>>,
177 pub denial_tracker:
179 Option<Arc<tokio::sync::Mutex<crate::permissions::tracking::DenialTracker>>>,
180 pub task_manager: Option<Arc<crate::services::background::TaskManager>>,
182 pub session_allows: Option<Arc<tokio::sync::Mutex<std::collections::HashSet<String>>>>,
184 pub permission_prompter: Option<Arc<dyn PermissionPrompter>>,
186}
187
188#[derive(Debug, Clone, Serialize, Deserialize)]
190pub struct ToolResult {
191 pub content: String,
193 pub is_error: bool,
195}
196
197impl ToolResult {
198 pub fn success(content: impl Into<String>) -> Self {
200 Self {
201 content: content.into(),
202 is_error: false,
203 }
204 }
205
206 pub fn error(content: impl Into<String>) -> Self {
208 Self {
209 content: content.into(),
210 is_error: true,
211 }
212 }
213}
214
215#[derive(Debug, Clone, Serialize)]
217pub struct ToolSchema {
218 pub name: &'static str,
219 pub description: &'static str,
220 pub input_schema: serde_json::Value,
221}
222
223impl<T: Tool + ?Sized> From<&T> for ToolSchema {
224 fn from(tool: &T) -> Self {
225 Self {
226 name: tool.name(),
227 description: tool.description(),
228 input_schema: tool.input_schema(),
229 }
230 }
231}