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 notebook_edit;
35pub mod plan_mode;
36pub mod powershell;
37pub mod registry;
38pub mod repl_tool;
39pub mod send_message;
40pub mod skill_tool;
41pub mod sleep_tool;
42pub mod tasks;
43pub mod todo_write;
44pub mod tool_search;
45pub mod web_fetch;
46pub mod web_search;
47pub mod worktree;
48
49use async_trait::async_trait;
50use serde::{Deserialize, Serialize};
51use std::path::PathBuf;
52use std::sync::Arc;
53use tokio_util::sync::CancellationToken;
54
55use crate::permissions::{PermissionChecker, PermissionDecision};
56
57#[async_trait]
63pub trait Tool: Send + Sync {
64 fn name(&self) -> &'static str;
66
67 fn description(&self) -> &'static str;
69
70 fn prompt(&self) -> String {
72 self.description().to_string()
73 }
74
75 fn input_schema(&self) -> serde_json::Value;
77
78 async fn call(
80 &self,
81 input: serde_json::Value,
82 ctx: &ToolContext,
83 ) -> Result<ToolResult, crate::error::ToolError>;
84
85 fn is_read_only(&self) -> bool {
87 false
88 }
89
90 fn is_concurrency_safe(&self) -> bool {
93 self.is_read_only()
94 }
95
96 fn is_destructive(&self) -> bool {
98 false
99 }
100
101 fn is_enabled(&self) -> bool {
103 true
104 }
105
106 fn max_result_size_chars(&self) -> usize {
108 100_000
109 }
110
111 async fn check_permissions(
113 &self,
114 input: &serde_json::Value,
115 checker: &PermissionChecker,
116 ) -> PermissionDecision {
117 if self.is_read_only() {
118 PermissionDecision::Allow
119 } else {
120 checker.check(self.name(), input)
121 }
122 }
123
124 fn validate_input(&self, _input: &serde_json::Value) -> Result<(), String> {
126 Ok(())
127 }
128
129 fn get_path(&self, _input: &serde_json::Value) -> Option<PathBuf> {
131 None
132 }
133}
134
135#[derive(Debug, Clone, PartialEq, Eq)]
137pub enum PermissionResponse {
138 AllowOnce,
139 AllowSession,
140 Deny,
141}
142
143pub trait PermissionPrompter: Send + Sync {
146 fn ask(
147 &self,
148 tool_name: &str,
149 description: &str,
150 input_preview: Option<&str>,
151 ) -> PermissionResponse;
152}
153
154pub struct AutoAllowPrompter;
156impl PermissionPrompter for AutoAllowPrompter {
157 fn ask(&self, _: &str, _: &str, _: Option<&str>) -> PermissionResponse {
158 PermissionResponse::AllowOnce
159 }
160}
161
162pub struct ToolContext {
164 pub cwd: PathBuf,
166 pub cancel: CancellationToken,
168 pub permission_checker: Arc<PermissionChecker>,
170 pub verbose: bool,
172 pub plan_mode: bool,
174 pub file_cache: Option<Arc<tokio::sync::Mutex<crate::services::file_cache::FileCache>>>,
176 pub denial_tracker:
178 Option<Arc<tokio::sync::Mutex<crate::permissions::tracking::DenialTracker>>>,
179 pub task_manager: Option<Arc<crate::services::background::TaskManager>>,
181 pub session_allows: Option<Arc<tokio::sync::Mutex<std::collections::HashSet<String>>>>,
183 pub permission_prompter: Option<Arc<dyn PermissionPrompter>>,
185}
186
187#[derive(Debug, Clone, Serialize, Deserialize)]
189pub struct ToolResult {
190 pub content: String,
192 pub is_error: bool,
194}
195
196impl ToolResult {
197 pub fn success(content: impl Into<String>) -> Self {
199 Self {
200 content: content.into(),
201 is_error: false,
202 }
203 }
204
205 pub fn error(content: impl Into<String>) -> Self {
207 Self {
208 content: content.into(),
209 is_error: true,
210 }
211 }
212}
213
214#[derive(Debug, Clone, Serialize)]
216pub struct ToolSchema {
217 pub name: &'static str,
218 pub description: &'static str,
219 pub input_schema: serde_json::Value,
220}
221
222impl<T: Tool + ?Sized> From<&T> for ToolSchema {
223 fn from(tool: &T) -> Self {
224 Self {
225 name: tool.name(),
226 description: tool.description(),
227 input_schema: tool.input_schema(),
228 }
229 }
230}