169 lines
5.0 KiB
C#
169 lines
5.0 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Runtime.InteropServices;
|
|
using System.Text.Json;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace AxCopilot.Services.Agent;
|
|
|
|
public class FileManageTool : IAgentTool
|
|
{
|
|
public string Name => "file_manage";
|
|
|
|
public string Description => "Manage files and directories. Actions: 'move' — move file/folder to destination; 'copy' — copy file/folder to destination; 'rename' — rename file/folder; 'delete' — delete file (requires Ask permission); 'mkdir' — create directory recursively.";
|
|
|
|
public ToolParameterSchema Parameters
|
|
{
|
|
get
|
|
{
|
|
ToolParameterSchema toolParameterSchema = new ToolParameterSchema();
|
|
Dictionary<string, ToolProperty> dictionary = new Dictionary<string, ToolProperty>();
|
|
ToolProperty obj = new ToolProperty
|
|
{
|
|
Type = "string",
|
|
Description = "Action to perform"
|
|
};
|
|
int num = 5;
|
|
List<string> list = new List<string>(num);
|
|
CollectionsMarshal.SetCount(list, num);
|
|
Span<string> span = CollectionsMarshal.AsSpan(list);
|
|
span[0] = "move";
|
|
span[1] = "copy";
|
|
span[2] = "rename";
|
|
span[3] = "delete";
|
|
span[4] = "mkdir";
|
|
obj.Enum = list;
|
|
dictionary["action"] = obj;
|
|
dictionary["path"] = new ToolProperty
|
|
{
|
|
Type = "string",
|
|
Description = "Source file/folder path"
|
|
};
|
|
dictionary["destination"] = new ToolProperty
|
|
{
|
|
Type = "string",
|
|
Description = "Destination path (for move/copy/rename)"
|
|
};
|
|
toolParameterSchema.Properties = dictionary;
|
|
num = 2;
|
|
List<string> list2 = new List<string>(num);
|
|
CollectionsMarshal.SetCount(list2, num);
|
|
Span<string> span2 = CollectionsMarshal.AsSpan(list2);
|
|
span2[0] = "action";
|
|
span2[1] = "path";
|
|
toolParameterSchema.Required = list2;
|
|
return toolParameterSchema;
|
|
}
|
|
}
|
|
|
|
public async Task<ToolResult> ExecuteAsync(JsonElement args, AgentContext context, CancellationToken ct = default(CancellationToken))
|
|
{
|
|
string action = args.GetProperty("action").GetString() ?? "";
|
|
string rawPath = args.GetProperty("path").GetString() ?? "";
|
|
JsonElement d;
|
|
string dest = (args.TryGetProperty("destination", out d) ? (d.GetString() ?? "") : "");
|
|
string path = (Path.IsPathRooted(rawPath) ? rawPath : Path.Combine(context.WorkFolder, rawPath));
|
|
if (!context.IsPathAllowed(path))
|
|
{
|
|
return ToolResult.Fail("경로 접근 차단: " + path);
|
|
}
|
|
try
|
|
{
|
|
switch (action)
|
|
{
|
|
case "mkdir":
|
|
Directory.CreateDirectory(path);
|
|
return ToolResult.Ok("디렉토리 생성: " + path);
|
|
case "delete":
|
|
if (context.AskPermission != null && !(await context.AskPermission("file_manage(delete)", path)))
|
|
{
|
|
return ToolResult.Fail("사용자가 삭제를 거부했습니다.");
|
|
}
|
|
if (File.Exists(path))
|
|
{
|
|
File.Delete(path);
|
|
return ToolResult.Ok("파일 삭제: " + path, path);
|
|
}
|
|
if (Directory.Exists(path))
|
|
{
|
|
Directory.Delete(path, recursive: true);
|
|
return ToolResult.Ok("폴더 삭제: " + path, path);
|
|
}
|
|
return ToolResult.Fail("경로를 찾을 수 없습니다: " + path);
|
|
case "move":
|
|
case "copy":
|
|
case "rename":
|
|
{
|
|
if (string.IsNullOrEmpty(dest))
|
|
{
|
|
return ToolResult.Fail("'" + action + "' 작업에는 'destination'이 필요합니다.");
|
|
}
|
|
string destPath = (Path.IsPathRooted(dest) ? dest : Path.Combine(context.WorkFolder, dest));
|
|
if (!context.IsPathAllowed(destPath))
|
|
{
|
|
return ToolResult.Fail("대상 경로 접근 차단: " + destPath);
|
|
}
|
|
string destDir = Path.GetDirectoryName(destPath);
|
|
if (!string.IsNullOrEmpty(destDir) && !Directory.Exists(destDir))
|
|
{
|
|
Directory.CreateDirectory(destDir);
|
|
}
|
|
if (action == "rename")
|
|
{
|
|
string dir = Path.GetDirectoryName(path) ?? context.WorkFolder;
|
|
destPath = Path.Combine(dir, dest);
|
|
}
|
|
if (File.Exists(path))
|
|
{
|
|
if (action == "copy")
|
|
{
|
|
File.Copy(path, destPath, overwrite: true);
|
|
}
|
|
else
|
|
{
|
|
File.Move(path, destPath, overwrite: true);
|
|
}
|
|
return ToolResult.Ok($"{action}: {path} → {destPath}", destPath);
|
|
}
|
|
if (Directory.Exists(path))
|
|
{
|
|
if (action == "copy")
|
|
{
|
|
CopyDirectory(path, destPath);
|
|
}
|
|
else
|
|
{
|
|
Directory.Move(path, destPath);
|
|
}
|
|
return ToolResult.Ok($"{action}: {path} → {destPath}", destPath);
|
|
}
|
|
return ToolResult.Fail("소스 경로를 찾을 수 없습니다: " + path);
|
|
}
|
|
default:
|
|
return ToolResult.Fail("Unknown action: " + action);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return ToolResult.Fail("파일 관리 오류: " + ex.Message);
|
|
}
|
|
}
|
|
|
|
private static void CopyDirectory(string src, string dst)
|
|
{
|
|
Directory.CreateDirectory(dst);
|
|
string[] files = Directory.GetFiles(src);
|
|
foreach (string text in files)
|
|
{
|
|
File.Copy(text, Path.Combine(dst, Path.GetFileName(text)), overwrite: true);
|
|
}
|
|
string[] directories = Directory.GetDirectories(src);
|
|
foreach (string text2 in directories)
|
|
{
|
|
CopyDirectory(text2, Path.Combine(dst, Path.GetFileName(text2)));
|
|
}
|
|
}
|
|
}
|