using System.Diagnostics; using System.IO; using System.Text.Json; namespace AxCopilot.Services.Agent; /// 파일/URL을 시스템 기본 앱으로 여는 도구. public class OpenExternalTool : IAgentTool { public string Name => "open_external"; public string Description => "Open a file with its default application or open a URL in the default browser. " + "Also supports opening a folder in File Explorer. " + "Use after creating documents, reports, or charts for the user to view."; public ToolParameterSchema Parameters => new() { Properties = new() { ["path"] = new() { Type = "string", Description = "File path, directory path, or URL to open", }, }, Required = ["path"], }; public Task ExecuteAsync(JsonElement args, AgentContext context, CancellationToken ct = default) { var rawPath = args.GetProperty("path").GetString() ?? ""; if (string.IsNullOrWhiteSpace(rawPath)) return Task.FromResult(ToolResult.Fail("경로가 비어 있습니다.")); try { // URL인 경우 if (rawPath.StartsWith("http://", StringComparison.OrdinalIgnoreCase) || rawPath.StartsWith("https://", StringComparison.OrdinalIgnoreCase)) { Process.Start(new ProcessStartInfo(rawPath) { UseShellExecute = true }); return Task.FromResult(ToolResult.Ok($"URL 열기: {rawPath}")); } // 파일/폴더 경로 var path = Path.IsPathRooted(rawPath) ? rawPath : Path.Combine(context.WorkFolder, rawPath); if (!context.IsPathAllowed(path)) return Task.FromResult(ToolResult.Fail($"경로 접근 차단: {path}")); if (File.Exists(path)) { Process.Start(new ProcessStartInfo(path) { UseShellExecute = true }); return Task.FromResult(ToolResult.Ok($"파일 열기: {path}", filePath: path)); } if (Directory.Exists(path)) { Process.Start(new ProcessStartInfo("explorer.exe", path)); return Task.FromResult(ToolResult.Ok($"폴더 열기: {path}", filePath: path)); } return Task.FromResult(ToolResult.Fail($"경로를 찾을 수 없습니다: {path}")); } catch (Exception ex) { return Task.FromResult(ToolResult.Fail($"열기 오류: {ex.Message}")); } } }