Add move_path tool (#27366)
<img width="629" alt="Screenshot 2025-03-24 at 10 06 39 AM" src="https://github.com/user-attachments/assets/b099fcc0-b2f4-44ee-8c8f-416808363689" /> Release Notes: - N/A --------- Co-authored-by: Marshall Bowers <git@maxdeviant.com>
This commit is contained in:
parent
f38ee81e83
commit
43712285bf
3 changed files with 133 additions and 0 deletions
|
@ -4,6 +4,7 @@ mod diagnostics_tool;
|
||||||
mod edit_files_tool;
|
mod edit_files_tool;
|
||||||
mod fetch_tool;
|
mod fetch_tool;
|
||||||
mod list_directory_tool;
|
mod list_directory_tool;
|
||||||
|
mod move_path_tool;
|
||||||
mod now_tool;
|
mod now_tool;
|
||||||
mod path_search_tool;
|
mod path_search_tool;
|
||||||
mod read_file_tool;
|
mod read_file_tool;
|
||||||
|
@ -15,6 +16,7 @@ use std::sync::Arc;
|
||||||
use assistant_tool::ToolRegistry;
|
use assistant_tool::ToolRegistry;
|
||||||
use gpui::App;
|
use gpui::App;
|
||||||
use http_client::HttpClientWithUrl;
|
use http_client::HttpClientWithUrl;
|
||||||
|
use move_path_tool::MovePathTool;
|
||||||
|
|
||||||
use crate::bash_tool::BashTool;
|
use crate::bash_tool::BashTool;
|
||||||
use crate::delete_path_tool::DeletePathTool;
|
use crate::delete_path_tool::DeletePathTool;
|
||||||
|
@ -35,6 +37,7 @@ pub fn init(http_client: Arc<HttpClientWithUrl>, cx: &mut App) {
|
||||||
let registry = ToolRegistry::global(cx);
|
let registry = ToolRegistry::global(cx);
|
||||||
registry.register_tool(BashTool);
|
registry.register_tool(BashTool);
|
||||||
registry.register_tool(DeletePathTool);
|
registry.register_tool(DeletePathTool);
|
||||||
|
registry.register_tool(MovePathTool);
|
||||||
registry.register_tool(DiagnosticsTool);
|
registry.register_tool(DiagnosticsTool);
|
||||||
registry.register_tool(EditFilesTool);
|
registry.register_tool(EditFilesTool);
|
||||||
registry.register_tool(ListDirectoryTool);
|
registry.register_tool(ListDirectoryTool);
|
||||||
|
|
125
crates/assistant_tools/src/move_path_tool.rs
Normal file
125
crates/assistant_tools/src/move_path_tool.rs
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
use anyhow::{anyhow, Result};
|
||||||
|
use assistant_tool::{ActionLog, Tool};
|
||||||
|
use gpui::{App, AppContext, Entity, Task};
|
||||||
|
use language_model::LanguageModelRequestMessage;
|
||||||
|
use project::Project;
|
||||||
|
use schemars::JsonSchema;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::{path::Path, sync::Arc};
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
|
||||||
|
pub struct MovePathToolInput {
|
||||||
|
/// The source path of the file or directory to move/rename.
|
||||||
|
///
|
||||||
|
/// <example>
|
||||||
|
/// If the project has the following files:
|
||||||
|
///
|
||||||
|
/// - directory1/a/something.txt
|
||||||
|
/// - directory2/a/things.txt
|
||||||
|
/// - directory3/a/other.txt
|
||||||
|
///
|
||||||
|
/// You can move the first file by providing a source_path of "directory1/a/something.txt"
|
||||||
|
/// </example>
|
||||||
|
pub source_path: String,
|
||||||
|
|
||||||
|
/// The destination path where the file or directory should be moved/renamed to.
|
||||||
|
/// If the paths are the same except for the filename, then this will be a rename.
|
||||||
|
///
|
||||||
|
/// <example>
|
||||||
|
/// To move "directory1/a/something.txt" to "directory2/b/renamed.txt",
|
||||||
|
/// provide a destination_path of "directory2/b/renamed.txt"
|
||||||
|
/// </example>
|
||||||
|
pub destination_path: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct MovePathTool;
|
||||||
|
|
||||||
|
impl Tool for MovePathTool {
|
||||||
|
fn name(&self) -> String {
|
||||||
|
"move-path".into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn needs_confirmation(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn description(&self) -> String {
|
||||||
|
include_str!("./move_path_tool/description.md").into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn input_schema(&self) -> serde_json::Value {
|
||||||
|
let schema = schemars::schema_for!(MovePathToolInput);
|
||||||
|
serde_json::to_value(&schema).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ui_text(&self, input: &serde_json::Value) -> String {
|
||||||
|
match serde_json::from_value::<MovePathToolInput>(input.clone()) {
|
||||||
|
Ok(input) => {
|
||||||
|
let src = input.source_path.as_str();
|
||||||
|
let dest = input.destination_path.as_str();
|
||||||
|
let src_path = Path::new(src);
|
||||||
|
let dest_path = Path::new(dest);
|
||||||
|
|
||||||
|
match dest_path
|
||||||
|
.file_name()
|
||||||
|
.and_then(|os_str| os_str.to_os_string().into_string().ok())
|
||||||
|
{
|
||||||
|
Some(filename) if src_path.parent() == dest_path.parent() => {
|
||||||
|
format!("Rename `{src}` to `{filename}`")
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
format!("Move `{src}` to `{dest}`")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(_) => "Move path".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
self: Arc<Self>,
|
||||||
|
input: serde_json::Value,
|
||||||
|
_messages: &[LanguageModelRequestMessage],
|
||||||
|
project: Entity<Project>,
|
||||||
|
_action_log: Entity<ActionLog>,
|
||||||
|
cx: &mut App,
|
||||||
|
) -> Task<Result<String>> {
|
||||||
|
let input = match serde_json::from_value::<MovePathToolInput>(input) {
|
||||||
|
Ok(input) => input,
|
||||||
|
Err(err) => return Task::ready(Err(anyhow!(err))),
|
||||||
|
};
|
||||||
|
let rename_task = project.update(cx, |project, cx| {
|
||||||
|
match project
|
||||||
|
.find_project_path(&input.source_path, cx)
|
||||||
|
.and_then(|project_path| project.entry_for_path(&project_path, cx))
|
||||||
|
{
|
||||||
|
Some(entity) => match project.find_project_path(&input.destination_path, cx) {
|
||||||
|
Some(project_path) => project.rename_entry(entity.id, project_path.path, cx),
|
||||||
|
None => Task::ready(Err(anyhow!(
|
||||||
|
"Destination path {} was outside the project.",
|
||||||
|
input.destination_path
|
||||||
|
))),
|
||||||
|
},
|
||||||
|
None => Task::ready(Err(anyhow!(
|
||||||
|
"Source path {} was not found in the project.",
|
||||||
|
input.source_path
|
||||||
|
))),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
cx.background_spawn(async move {
|
||||||
|
match rename_task.await {
|
||||||
|
Ok(_) => Ok(format!(
|
||||||
|
"Moved {} to {}",
|
||||||
|
input.source_path, input.destination_path
|
||||||
|
)),
|
||||||
|
Err(err) => Err(anyhow!(
|
||||||
|
"Failed to move {} to {}: {}",
|
||||||
|
input.source_path,
|
||||||
|
input.destination_path,
|
||||||
|
err
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
5
crates/assistant_tools/src/move_path_tool/description.md
Normal file
5
crates/assistant_tools/src/move_path_tool/description.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
Moves or rename a file or directory in the project, and returns confirmation that the move succeeded.
|
||||||
|
If the source and destination directories are the same, but the filename is different, this performs
|
||||||
|
a rename. Otherwise, it performs a move.
|
||||||
|
|
||||||
|
This tool should be used when it's desirable to move or rename a file or directory without changing its contents at all.
|
Loading…
Add table
Add a link
Reference in a new issue