From 9db4c8b710da71ef29df21cb8e49320ce653f0d1 Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Wed, 26 Mar 2025 11:59:03 -0400 Subject: [PATCH] Add Create Directory Tool (#27505) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `mkdir -p` but it works cross-platform and uses project abstractions. Screenshot 2025-03-26 at 11 02 37 AM Release Notes: - N/A --- crates/assistant_tools/src/assistant_tools.rs | 3 + .../src/create_directory_tool.rs | 89 +++++++++++++++++++ .../src/create_directory_tool/description.md | 3 + 3 files changed, 95 insertions(+) create mode 100644 crates/assistant_tools/src/create_directory_tool.rs create mode 100644 crates/assistant_tools/src/create_directory_tool/description.md diff --git a/crates/assistant_tools/src/assistant_tools.rs b/crates/assistant_tools/src/assistant_tools.rs index 5d2b2965e6f08da32065f2eeabaf15e2f760f4a2..b85ec55e98d193d588a444449b57e6266803854f 100644 --- a/crates/assistant_tools/src/assistant_tools.rs +++ b/crates/assistant_tools/src/assistant_tools.rs @@ -1,5 +1,6 @@ mod bash_tool; mod copy_path_tool; +mod create_directory_tool; mod create_file_tool; mod delete_path_tool; mod diagnostics_tool; @@ -24,6 +25,7 @@ use http_client::HttpClientWithUrl; use move_path_tool::MovePathTool; use crate::bash_tool::BashTool; +use crate::create_directory_tool::CreateDirectoryTool; use crate::create_file_tool::CreateFileTool; use crate::delete_path_tool::DeletePathTool; use crate::diagnostics_tool::DiagnosticsTool; @@ -43,6 +45,7 @@ pub fn init(http_client: Arc, cx: &mut App) { let registry = ToolRegistry::global(cx); registry.register_tool(BashTool); + registry.register_tool(CreateDirectoryTool); registry.register_tool(CreateFileTool); registry.register_tool(CopyPathTool); registry.register_tool(DeletePathTool); diff --git a/crates/assistant_tools/src/create_directory_tool.rs b/crates/assistant_tools/src/create_directory_tool.rs new file mode 100644 index 0000000000000000000000000000000000000000..c3e1ef513eabd25885bec8d8c27791cdc3f31984 --- /dev/null +++ b/crates/assistant_tools/src/create_directory_tool.rs @@ -0,0 +1,89 @@ +use anyhow::{anyhow, Result}; +use assistant_tool::{ActionLog, Tool}; +use gpui::{App, Entity, Task}; +use language_model::LanguageModelRequestMessage; +use project::Project; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use std::sync::Arc; +use ui::IconName; +use util::markdown::MarkdownString; + +#[derive(Debug, Serialize, Deserialize, JsonSchema)] +pub struct CreateDirectoryToolInput { + /// The path of the new directory. + /// + /// + /// If the project has the following structure: + /// + /// - directory1/ + /// - directory2/ + /// + /// You can create a new directory by providing a path of "directory1/new_directory" + /// + pub path: String, +} + +pub struct CreateDirectoryTool; + +impl Tool for CreateDirectoryTool { + fn name(&self) -> String { + "create-directory".into() + } + + fn needs_confirmation(&self) -> bool { + true + } + + fn description(&self) -> String { + include_str!("./create_directory_tool/description.md").into() + } + + fn icon(&self) -> IconName { + IconName::Folder + } + + fn input_schema(&self) -> serde_json::Value { + let schema = schemars::schema_for!(CreateDirectoryToolInput); + serde_json::to_value(&schema).unwrap() + } + + fn ui_text(&self, input: &serde_json::Value) -> String { + match serde_json::from_value::(input.clone()) { + Ok(input) => { + format!("Create directory `{}`", MarkdownString::escape(&input.path)) + } + Err(_) => "Create directory".to_string(), + } + } + + fn run( + self: Arc, + input: serde_json::Value, + _messages: &[LanguageModelRequestMessage], + project: Entity, + _action_log: Entity, + cx: &mut App, + ) -> Task> { + let input = match serde_json::from_value::(input) { + Ok(input) => input, + Err(err) => return Task::ready(Err(anyhow!(err))), + }; + let project_path = match project.read(cx).find_project_path(&input.path, cx) { + Some(project_path) => project_path, + None => return Task::ready(Err(anyhow!("Path to create was outside the project"))), + }; + let destination_path: Arc = input.path.as_str().into(); + + cx.spawn(async move |cx| { + project + .update(cx, |project, cx| { + project.create_entry(project_path.clone(), true, cx) + })? + .await + .map_err(|err| anyhow!("Unable to create directory {destination_path}: {err}"))?; + + Ok(format!("Created directory {destination_path}")) + }) + } +} diff --git a/crates/assistant_tools/src/create_directory_tool/description.md b/crates/assistant_tools/src/create_directory_tool/description.md new file mode 100644 index 0000000000000000000000000000000000000000..52056518c23517bf9fd36bf7d41d7e46947b15b6 --- /dev/null +++ b/crates/assistant_tools/src/create_directory_tool/description.md @@ -0,0 +1,3 @@ +Creates a new directory at the specified path within the project. Returns confirmation that the directory was created. + +This tool creates a directory and all necessary parent directories (similar to `mkdir -p`). It should be used whenever you need to create new directories within the project.