pub mod agent;
pub mod ask_user;
pub mod bash;
pub mod executor;
pub mod file_edit;
pub mod file_read;
pub mod file_write;
pub mod glob;
pub mod grep;
pub mod lsp_tool;
pub mod mcp_proxy;
pub mod mcp_resources;
pub mod notebook_edit;
pub mod plan_mode;
pub mod registry;
pub mod repl_tool;
pub mod send_message;
pub mod skill_tool;
pub mod sleep_tool;
pub mod streaming_executor;
pub mod tasks;
pub mod todo_write;
pub mod tool_search;
pub mod web_fetch;
pub mod web_search;
pub mod worktree;
use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
use std::sync::Arc;
use tokio_util::sync::CancellationToken;
use crate::permissions::{PermissionChecker, PermissionDecision};
#[async_trait]
pub trait Tool: Send + Sync {
fn name(&self) -> &'static str;
fn description(&self) -> &'static str;
fn prompt(&self) -> String {
self.description().to_string()
}
fn input_schema(&self) -> serde_json::Value;
async fn call(
&self,
input: serde_json::Value,
ctx: &ToolContext,
) -> Result<ToolResult, crate::error::ToolError>;
fn is_read_only(&self) -> bool {
false
}
fn is_concurrency_safe(&self) -> bool {
self.is_read_only()
}
fn is_destructive(&self) -> bool {
false
}
fn is_enabled(&self) -> bool {
true
}
fn max_result_size_chars(&self) -> usize {
100_000
}
async fn check_permissions(
&self,
input: &serde_json::Value,
checker: &PermissionChecker,
) -> PermissionDecision {
if self.is_read_only() {
PermissionDecision::Allow
} else {
checker.check(self.name(), input)
}
}
fn validate_input(&self, _input: &serde_json::Value) -> Result<(), String> {
Ok(())
}
fn get_path(&self, _input: &serde_json::Value) -> Option<PathBuf> {
None
}
}
pub struct ToolContext {
pub cwd: PathBuf,
pub cancel: CancellationToken,
pub permission_checker: Arc<PermissionChecker>,
pub verbose: bool,
pub plan_mode: bool,
pub file_cache: Option<Arc<tokio::sync::Mutex<crate::services::file_cache::FileCache>>>,
pub denial_tracker:
Option<Arc<tokio::sync::Mutex<crate::permissions::tracking::DenialTracker>>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ToolResult {
pub content: String,
pub is_error: bool,
}
impl ToolResult {
pub fn success(content: impl Into<String>) -> Self {
Self {
content: content.into(),
is_error: false,
}
}
pub fn error(content: impl Into<String>) -> Self {
Self {
content: content.into(),
is_error: true,
}
}
}
#[derive(Debug, Clone, Serialize)]
pub struct ToolSchema {
pub name: &'static str,
pub description: &'static str,
pub input_schema: serde_json::Value,
}
impl<T: Tool + ?Sized> From<&T> for ToolSchema {
fn from(tool: &T) -> Self {
Self {
name: tool.name(),
description: tool.description(),
input_schema: tool.input_schema(),
}
}
}