ai-agents-tools 1.0.5

Tool system for AI Agents framework
Documentation
mod calculator;
mod command;
mod datetime;
mod echo;
mod file;
mod fs_mutation;
mod fs_readonly;
mod git;
mod host;
mod http;
mod json;
mod math;
mod random;
mod template;
mod text;
mod web_fetch;
mod web_search;

pub use calculator::CalculatorTool;
pub use command::CommandTool;
pub use datetime::DateTimeTool;
pub use echo::EchoTool;
pub use file::FileTool;
pub use fs_mutation::{
    CopyPathTool, DeletePathTool, FileEditTool, FileWriteTool, MovePathTool, PatchTool,
};
pub use fs_readonly::{FileInfoTool, FileListTool, FileReadTool, GlobTool, GrepTool};
pub use git::{GitDiffTool, GitStatusTool};
pub use host::{AskUserTool, DiagnosticsTool, SleepTool, TodoTool};
pub use http::HttpTool;
pub use json::JsonTool;
pub use math::MathTool;
pub use random::RandomTool;
pub use template::TemplateTool;
pub use text::TextTool;
pub use web_fetch::{
    WebFetchResolver, WebFetchTool, WebFetchTransport, WebFetchTransportRequest,
    WebFetchTransportResponse,
};
pub use web_search::WebSearchTool;

use super::Tool;
use crate::types::{TodoStore, UnavailableDiagnosticsProvider};
use parking_lot::RwLock;
use std::sync::Arc;

const BUILTIN_TOOL_IDS: [&str; 30] = [
    "calculator",
    "echo",
    "datetime",
    "json",
    "random",
    "file",
    "glob",
    "grep",
    "file_read",
    "file_write",
    "file_edit",
    "patch",
    "copy_path",
    "move_path",
    "delete_path",
    "file_list",
    "file_info",
    "git_status",
    "git_diff",
    "diagnostics",
    "ask_user",
    "todo",
    "sleep",
    "web_fetch",
    "web_search",
    "command",
    "text",
    "template",
    "math",
    "http",
];

pub fn all_builtin_tools() -> Vec<Arc<dyn Tool>> {
    let versions = crate::types::FileVersionStore::default();
    let command_runner = Arc::new(RwLock::new(
        Arc::new(crate::types::UnavailableCommandRunner) as Arc<dyn crate::types::CommandRunner>,
    ));
    vec![
        Arc::new(CalculatorTool::new()),
        Arc::new(EchoTool::new()),
        Arc::new(DateTimeTool::new()),
        Arc::new(JsonTool::new()),
        Arc::new(RandomTool::new()),
        Arc::new(FileTool::new()),
        Arc::new(GlobTool::new()),
        Arc::new(GrepTool::new()),
        Arc::new(FileReadTool::with_version_store(versions.clone())),
        Arc::new(FileWriteTool::with_version_store(versions.clone())),
        Arc::new(FileEditTool::with_version_store(versions.clone())),
        Arc::new(PatchTool::with_version_store(versions.clone())),
        Arc::new(CopyPathTool::new()),
        Arc::new(MovePathTool::new()),
        Arc::new(DeletePathTool::new()),
        Arc::new(FileListTool::new()),
        Arc::new(FileInfoTool::new()),
        Arc::new(GitStatusTool::new()),
        Arc::new(GitDiffTool::new()),
        Arc::new(DiagnosticsTool::new(Arc::new(RwLock::new(Arc::new(
            UnavailableDiagnosticsProvider,
        ))))),
        Arc::new(AskUserTool::new(Arc::new(RwLock::new(None)))),
        Arc::new(TodoTool::new(TodoStore::default())),
        Arc::new(SleepTool::new()),
        Arc::new(WebFetchTool::new()),
        Arc::new(WebSearchTool::new()),
        Arc::new(CommandTool::new(command_runner)),
        Arc::new(TextTool::new()),
        Arc::new(TemplateTool::new()),
        Arc::new(MathTool::new()),
        Arc::new(HttpTool::new()),
    ]
}

pub fn get_builtin_tool(id: &str) -> Option<Arc<dyn Tool>> {
    if !BUILTIN_TOOL_IDS.contains(&id) {
        return None;
    }

    match id {
        "calculator" => Some(Arc::new(CalculatorTool::new())),
        "echo" => Some(Arc::new(EchoTool::new())),
        "datetime" => Some(Arc::new(DateTimeTool::new())),
        "json" => Some(Arc::new(JsonTool::new())),
        "random" => Some(Arc::new(RandomTool::new())),
        "file" => Some(Arc::new(FileTool::new())),
        "glob" => Some(Arc::new(GlobTool::new())),
        "grep" => Some(Arc::new(GrepTool::new())),
        "file_read" => Some(Arc::new(FileReadTool::new())),
        "file_write" => Some(Arc::new(FileWriteTool::new())),
        "file_edit" => Some(Arc::new(FileEditTool::new())),
        "patch" => Some(Arc::new(PatchTool::new())),
        "copy_path" => Some(Arc::new(CopyPathTool::new())),
        "move_path" => Some(Arc::new(MovePathTool::new())),
        "delete_path" => Some(Arc::new(DeletePathTool::new())),
        "file_list" => Some(Arc::new(FileListTool::new())),
        "file_info" => Some(Arc::new(FileInfoTool::new())),
        "git_status" => Some(Arc::new(GitStatusTool::new())),
        "git_diff" => Some(Arc::new(GitDiffTool::new())),
        "diagnostics" => Some(Arc::new(DiagnosticsTool::new(Arc::new(RwLock::new(
            Arc::new(UnavailableDiagnosticsProvider),
        ))))),
        "ask_user" => Some(Arc::new(AskUserTool::new(Arc::new(RwLock::new(None))))),
        "todo" => Some(Arc::new(TodoTool::new(TodoStore::default()))),
        "sleep" => Some(Arc::new(SleepTool::new())),
        "web_fetch" => Some(Arc::new(WebFetchTool::new())),
        "web_search" => Some(Arc::new(WebSearchTool::new())),
        "command" => Some(Arc::new(CommandTool::new(Arc::new(RwLock::new(Arc::new(
            crate::types::UnavailableCommandRunner,
        )
            as Arc<dyn crate::types::CommandRunner>))))),
        "text" => Some(Arc::new(TextTool::new())),
        "template" => Some(Arc::new(TemplateTool::new())),
        "math" => Some(Arc::new(MathTool::new())),
        "http" => Some(Arc::new(HttpTool::new())),
        _ => None,
    }
}

#[cfg(test)]
mod tests {
    use std::collections::BTreeSet;

    use super::*;

    #[test]
    fn builtin_inventory_and_lookup_stay_in_sync() {
        let tools = all_builtin_tools();
        let actual: BTreeSet<_> = tools.iter().map(|tool| tool.id()).collect();
        let expected: BTreeSet<_> = BUILTIN_TOOL_IDS.into_iter().collect();

        assert_eq!(tools.len(), BUILTIN_TOOL_IDS.len());
        assert_eq!(actual.len(), tools.len(), "built-in IDs must be unique");
        assert_eq!(actual, expected);

        for id in BUILTIN_TOOL_IDS {
            let tool =
                get_builtin_tool(id).unwrap_or_else(|| panic!("missing built-in lookup: {id}"));
            assert_eq!(tool.id(), id);
        }
    }
}