use std::sync::Arc;
use crate::backends::gemini::api::SharedClient;
use crate::filesystem::SharedFilesystem;
use crate::tools::{Tool, ToolRunner};
use crate::types::{BuiltinTool, CapabilitiesConfig};
mod ask_question;
mod create_file;
mod delete_file;
mod edit_file;
mod find_file;
mod finish;
mod generate_image;
mod list_directory;
mod rename_file;
#[cfg(feature = "native")]
mod run_command;
mod search_directory;
mod start_subagent;
mod view_file;
pub use ask_question::AskQuestion;
pub use create_file::CreateFile;
pub use delete_file::DeleteFile;
pub use edit_file::EditFile;
pub use find_file::FindFile;
pub use finish::{Finish, FINISH_TOOL_NAME};
pub use generate_image::GenerateImage;
pub use list_directory::ListDirectory;
pub use rename_file::RenameFile;
#[cfg(feature = "native")]
pub use run_command::RunCommand;
pub use search_directory::SearchDirectory;
pub use start_subagent::StartSubagent;
pub use view_file::ViewFile;
pub struct BuiltinDeps {
pub chat_client: Option<SharedClient>,
pub chat_model: String,
pub image_client: Option<SharedClient>,
pub image_model: String,
pub fs: Option<SharedFilesystem>,
}
macro_rules! fs_tool {
($deps:expr, $ty:ident) => {
$deps
.fs
.as_ref()
.map(|fs| Arc::new($ty::new(fs.clone())) as Arc<dyn Tool>)
};
}
pub fn register_builtins(
runner: &ToolRunner,
capabilities: &CapabilitiesConfig,
deps: &BuiltinDeps,
) -> Vec<String> {
let enabled = capabilities.effective_tools();
let mut registered = Vec::new();
for tool in BuiltinTool::ALL {
if !enabled.contains(tool) {
continue;
}
let boxed: Option<Arc<dyn Tool>> = match tool {
BuiltinTool::Finish => Some(Arc::new(Finish)),
BuiltinTool::AskQuestion => Some(Arc::new(AskQuestion)),
BuiltinTool::GenerateImage => deps.image_client.as_ref().map(|c| {
Arc::new(GenerateImage::new(c.clone(), deps.image_model.clone())) as Arc<dyn Tool>
}),
BuiltinTool::StartSubagent => deps.chat_client.as_ref().map(|c| {
Arc::new(StartSubagent::new(c.clone(), deps.chat_model.clone())) as Arc<dyn Tool>
}),
BuiltinTool::ListDirectory => fs_tool!(deps, ListDirectory),
BuiltinTool::ViewFile => fs_tool!(deps, ViewFile),
BuiltinTool::FindFile => fs_tool!(deps, FindFile),
BuiltinTool::SearchDirectory => fs_tool!(deps, SearchDirectory),
BuiltinTool::CreateFile => fs_tool!(deps, CreateFile),
BuiltinTool::EditFile => fs_tool!(deps, EditFile),
BuiltinTool::DeleteFile => fs_tool!(deps, DeleteFile),
BuiltinTool::RenameFile => fs_tool!(deps, RenameFile),
BuiltinTool::RunCommand => instantiate_run_command(),
};
if let Some(t) = boxed {
let name = t.name().to_string();
let existing = runner.names();
if !existing.iter().any(|n| n == &name) {
runner.register(t);
registered.push(name);
}
}
}
registered
}
#[cfg(feature = "native")]
fn instantiate_run_command() -> Option<Arc<dyn Tool>> {
Some(Arc::new(RunCommand))
}
#[cfg(not(feature = "native"))]
fn instantiate_run_command() -> Option<Arc<dyn Tool>> {
None
}