fix: refine tools (#2229)

This commit is contained in:
yetone
2025-06-16 01:27:39 +08:00
committed by GitHub
parent b8aa182c3f
commit fcf457ed7f
15 changed files with 247 additions and 169 deletions

View File

@@ -95,21 +95,20 @@ function M.write_global_file(opts, on_log, on_complete)
end)
end
---@type AvanteLLMToolFunc<{ path: string, new_path: string }>
function M.rename_file(opts, on_log, on_complete)
local abs_path = Helpers.get_abs_path(opts.path)
---@type AvanteLLMToolFunc<{ source_path: string, destination_path: string }>
function M.move_path(opts, on_log, on_complete)
local abs_path = Helpers.get_abs_path(opts.source_path)
if not Helpers.has_permission_to_access(abs_path) then return false, "No permission to access path: " .. abs_path end
if not Path:new(abs_path):exists() then return false, "File not found: " .. abs_path end
if not Path:new(abs_path):is_file() then return false, "Path is not a file: " .. abs_path end
local new_abs_path = Helpers.get_abs_path(opts.new_path)
if not Path:new(abs_path):exists() then return false, "The source path not found: " .. abs_path end
local new_abs_path = Helpers.get_abs_path(opts.destination_path)
if on_log then on_log(abs_path .. " -> " .. new_abs_path) end
if not Helpers.has_permission_to_access(new_abs_path) then
return false, "No permission to access path: " .. new_abs_path
end
if Path:new(new_abs_path):exists() then return false, "File already exists: " .. new_abs_path end
if Path:new(new_abs_path):exists() then return false, "The destination path already exists: " .. new_abs_path end
if not on_complete then return false, "on_complete not provided" end
Helpers.confirm(
"Are you sure you want to rename the file: " .. abs_path .. " to: " .. new_abs_path,
"Are you sure you want to move the path: " .. abs_path .. " to: " .. new_abs_path,
function(ok, reason)
if not ok then
on_complete(false, "User declined, reason: " .. (reason or "unknown"))
@@ -121,35 +120,61 @@ function M.rename_file(opts, on_log, on_complete)
)
end
---@type AvanteLLMToolFunc<{ path: string, new_path: string }>
function M.copy_file(opts, on_log)
local abs_path = Helpers.get_abs_path(opts.path)
---@type AvanteLLMToolFunc<{ source_path: string, destination_path: string }>
function M.copy_path(opts, on_log, on_complete)
local abs_path = Helpers.get_abs_path(opts.source_path)
if not Helpers.has_permission_to_access(abs_path) then return false, "No permission to access path: " .. abs_path end
if not Path:new(abs_path):exists() then return false, "File not found: " .. abs_path end
if not Path:new(abs_path):is_file() then return false, "Path is not a file: " .. abs_path end
local new_abs_path = Helpers.get_abs_path(opts.new_path)
if not Path:new(abs_path):exists() then return false, "The source path not found: " .. abs_path end
local new_abs_path = Helpers.get_abs_path(opts.destination_path)
if not Helpers.has_permission_to_access(new_abs_path) then
return false, "No permission to access path: " .. new_abs_path
end
if Path:new(new_abs_path):exists() then return false, "File already exists: " .. new_abs_path end
if on_log then on_log("Copying file: " .. abs_path .. " to " .. new_abs_path) end
Path:new(new_abs_path):write(Path:new(abs_path):read())
return true, nil
if Path:new(new_abs_path):exists() then return false, "The destination path already exists: " .. new_abs_path end
if not on_complete then return false, "on_complete not provided" end
Helpers.confirm(
"Are you sure you want to copy the path: " .. abs_path .. " to: " .. new_abs_path,
function(ok, reason)
if not ok then
on_complete(false, "User declined, reason: " .. (reason or "unknown"))
return
end
if on_log then on_log("Copying path: " .. abs_path .. " to " .. new_abs_path) end
if Path:new(abs_path):is_dir() then
Path:new(new_abs_path):mkdir({ parents = true })
for _, entry in ipairs(Path:new(abs_path):list()) do
local new_entry_path = Path:new(new_abs_path):joinpath(entry)
if entry:match("^%.") then goto continue end
if Path:new(new_entry_path):exists() then
if Path:new(new_entry_path):is_dir() then
Path:new(new_entry_path):rmdir()
else
Path:new(new_entry_path):unlink()
end
end
vim.fn.mkdir(new_entry_path, "p")
Path:new(new_entry_path):write(Path:new(abs_path):joinpath(entry):read())
::continue::
end
else
Path:new(new_abs_path):write(Path:new(abs_path):read())
end
on_complete(true, nil)
end
)
end
---@type AvanteLLMToolFunc<{ path: string }>
function M.delete_file(opts, on_log, on_complete)
function M.delete_path(opts, on_log, on_complete)
local abs_path = Helpers.get_abs_path(opts.path)
if not Helpers.has_permission_to_access(abs_path) then return false, "No permission to access path: " .. abs_path end
if not Path:new(abs_path):exists() then return false, "File not found: " .. abs_path end
if not Path:new(abs_path):is_file() then return false, "Path is not a file: " .. abs_path end
if not Path:new(abs_path):exists() then return false, "Path not found: " .. abs_path end
if not on_complete then return false, "on_complete not provided" end
Helpers.confirm("Are you sure you want to delete the file: " .. abs_path, function(ok, reason)
Helpers.confirm("Are you sure you want to delete the path: " .. abs_path, function(ok, reason)
if not ok then
on_complete(false, "User declined, reason: " .. (reason or "unknown"))
return
end
if on_log then on_log("Deleting file: " .. abs_path) end
if on_log then on_log("Deleting path: " .. abs_path) end
os.remove(abs_path)
on_complete(true, nil)
end)
@@ -172,50 +197,6 @@ function M.create_dir(opts, on_log, on_complete)
end)
end
---@type AvanteLLMToolFunc<{ path: string, new_path: string }>
function M.rename_dir(opts, on_log, on_complete)
local abs_path = Helpers.get_abs_path(opts.path)
if not Helpers.has_permission_to_access(abs_path) then return false, "No permission to access path: " .. abs_path end
if not Path:new(abs_path):exists() then return false, "Directory not found: " .. abs_path end
if not Path:new(abs_path):is_dir() then return false, "Path is not a directory: " .. abs_path end
local new_abs_path = Helpers.get_abs_path(opts.new_path)
if not Helpers.has_permission_to_access(new_abs_path) then
return false, "No permission to access path: " .. new_abs_path
end
if Path:new(new_abs_path):exists() then return false, "Directory already exists: " .. new_abs_path end
if not on_complete then return false, "on_complete not provided" end
Helpers.confirm(
"Are you sure you want to rename directory " .. abs_path .. " to " .. new_abs_path .. "?",
function(ok, reason)
if not ok then
on_complete(false, "User declined, reason: " .. (reason or "unknown"))
return
end
if on_log then on_log("Renaming directory: " .. abs_path .. " to " .. new_abs_path) end
os.rename(abs_path, new_abs_path)
on_complete(true, nil)
end
)
end
---@type AvanteLLMToolFunc<{ path: string }>
function M.delete_dir(opts, on_log, on_complete)
local abs_path = Helpers.get_abs_path(opts.path)
if not Helpers.has_permission_to_access(abs_path) then return false, "No permission to access path: " .. abs_path end
if not Path:new(abs_path):exists() then return false, "Directory not found: " .. abs_path end
if not Path:new(abs_path):is_dir() then return false, "Path is not a directory: " .. abs_path end
if not on_complete then return false, "on_complete not provided" end
Helpers.confirm("Are you sure you want to delete the directory: " .. abs_path, function(ok, reason)
if not ok then
on_complete(false, "User declined, reason: " .. (reason or "unknown"))
return
end
if on_log then on_log("Deleting directory: " .. abs_path) end
os.remove(abs_path)
on_complete(true, nil)
end)
end
---@type AvanteLLMToolFunc<{ query: string }>
function M.web_search(opts, on_log)
local provider_type = Config.web_search_engine.provider
@@ -896,25 +877,42 @@ M._tools = {
},
},
{
name = "rename_file",
description = "Rename a file in current project scope",
name = "move_path",
description = [[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.]],
param = {
type = "table",
fields = {
{
name = "path",
description = "Relative path to the file in current project scope",
name = "source_path",
description = [[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>]],
type = "string",
},
{
name = "new_path",
description = "New relative path for the file",
name = "destination_path",
description = [[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>]],
type = "string",
},
},
usage = {
path = "Relative path to the file in current project scope",
new_path = "New relative path for the file",
source_path = "The source path of the file or directory to move/rename",
destination_path = "The destination path where the file or directory should be moved/renamed to",
},
},
returns = {
@@ -932,19 +930,81 @@ M._tools = {
},
},
{
name = "delete_file",
description = "Delete a file in current project scope",
name = "copy_path",
description = [[Copies a file or directory from the project to a new location, and returns confirmation that the copy succeeded.
This tool should be used when it's desirable to copy a file or directory without changing its contents at all.]],
param = {
type = "table",
fields = {
{
name = "source_path",
description = [[The source path of the file or directory to copy.
<example>
If the project has the following files:
- directory1/a/something.txt
- directory2/a/things.txt
- directory3/a/other.txt
You can copy the first file by providing a source_path of "directory1/a/something.txt"
</example>]],
type = "string",
},
{
name = "destination_path",
description = [[The destination path where the file or directory should be copied to.
<example>
To copy "directory1/a/something.txt" to "directory2/b/copied.txt", provide a destination_path of "directory2/b/copied.txt"
</example>]],
type = "string",
},
},
usage = {
source_path = "The source path of the file or directory to copy",
destination_path = "The destination path where the file or directory should be copied to",
},
},
returns = {
{
name = "success",
description = "True if the file was copied successfully, false otherwise",
type = "boolean",
},
{
name = "error",
description = "Error message if the file was not copied successfully",
type = "string",
optional = true,
},
},
},
{
name = "delete_path",
description = "Deletes the file or directory (and the directory's contents, recursively) at the specified path in the project, and returns confirmation of the deletion.",
param = {
type = "table",
fields = {
{
name = "path",
description = "Relative path to the file in current project scope",
description = [[The path of the file or directory to delete.
<example>
If the project has the following files:
- directory1/a/something.txt
- directory2/a/things.txt
- directory3/a/other.txt
You can delete the first file by providing a path of "directory1/a/something.txt"
</example>
]],
type = "string",
},
},
usage = {
path = "Relative path to the file in current project scope",
path = "Relative path to the file or directory in the current project scope",
},
},
returns = {
@@ -991,72 +1051,7 @@ M._tools = {
},
},
},
{
name = "rename_dir",
description = "Rename a directory in current project scope",
param = {
type = "table",
fields = {
{
name = "path",
description = "Relative path to the project directory",
type = "string",
},
{
name = "new_path",
description = "New relative path for the directory",
type = "string",
},
},
usage = {
path = "Relative path to the project directory",
new_path = "New relative path for the directory",
},
},
returns = {
{
name = "success",
description = "True if the directory was renamed successfully, false otherwise",
type = "boolean",
},
{
name = "error",
description = "Error message if the directory was not renamed successfully",
type = "string",
optional = true,
},
},
},
{
name = "delete_dir",
description = "Delete a directory in current project scope",
param = {
type = "table",
fields = {
{
name = "path",
description = "Relative path to the project directory",
type = "string",
},
},
usage = {
path = "Relative path to the project directory",
},
},
returns = {
{
name = "success",
description = "True if the directory was deleted successfully, false otherwise",
type = "boolean",
},
{
name = "error",
description = "Error message if the directory was not deleted successfully",
type = "string",
optional = true,
},
},
},
require("avante.llm_tools.thinking"),
require("avante.llm_tools.get_diagnostics"),
require("avante.llm_tools.bash"),
require("avante.llm_tools.attempt_completion"),
@@ -1188,8 +1183,6 @@ M.run_python = M.python
---@return string | nil result
---@return string | nil error
function M.process_tool_use(tools, tool_use, on_log, on_complete, session_ctx)
-- Utils.debug("use tool", tool_use.name, tool_use.input_json)
-- Check if execution is already cancelled
if Helpers.is_cancelled then
Utils.debug("Tool execution cancelled before starting: " .. tool_use.name)