using System; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Text; using System.Text.Json; using System.Threading; using System.Threading.Tasks; using System.Windows; namespace AxCopilot.Services.Agent; public class SkillManagerTool : IAgentTool { public string Name => "skill_manager"; public string Description => "마크다운 기반 스킬(워크플로우)을 관리합니다.\n- list: 사용 가능한 스킬 목록 조회\n- info: 특정 스킬의 상세 정보 확인\n- reload: 스킬 폴더를 다시 스캔하여 새 스킬 로드"; public ToolParameterSchema Parameters { get { ToolParameterSchema toolParameterSchema = new ToolParameterSchema(); Dictionary dictionary = new Dictionary(); ToolProperty obj = new ToolProperty { Type = "string", Description = "list (목록), info (상세정보), reload (재로드)" }; int num = 3; List list = new List(num); CollectionsMarshal.SetCount(list, num); Span span = CollectionsMarshal.AsSpan(list); span[0] = "list"; span[1] = "info"; span[2] = "reload"; obj.Enum = list; dictionary["action"] = obj; dictionary["skill_name"] = new ToolProperty { Type = "string", Description = "스킬 이름 (info 액션에서 사용)" }; toolParameterSchema.Properties = dictionary; num = 1; List list2 = new List(num); CollectionsMarshal.SetCount(list2, num); CollectionsMarshal.AsSpan(list2)[0] = "action"; toolParameterSchema.Required = list2; return toolParameterSchema; } } public async Task ExecuteAsync(JsonElement args, AgentContext context, CancellationToken ct = default(CancellationToken)) { App app = Application.Current as App; if (!(app?.SettingsService?.Settings.Llm.EnableSkillSystem ?? true)) { return ToolResult.Ok("스킬 시스템이 비활성 상태입니다. 설정 → AX Agent → 공통에서 활성화하세요."); } JsonElement a; string action = (args.TryGetProperty("action", out a) ? (a.GetString() ?? "") : ""); JsonElement s; string skillName = (args.TryGetProperty("skill_name", out s) ? (s.GetString() ?? "") : ""); if (1 == 0) { } ToolResult result = action switch { "list" => ListSkills(), "info" => InfoSkill(skillName), "reload" => ReloadSkills(app), _ => ToolResult.Fail("지원하지 않는 action: " + action + ". list, info, reload 중 선택하세요."), }; if (1 == 0) { } return result; } private static ToolResult ListSkills() { IReadOnlyList skills = SkillService.Skills; if (skills.Count == 0) { return ToolResult.Ok("로드된 스킬이 없습니다. %APPDATA%\\AxCopilot\\skills\\에 *.skill.md 파일을 추가하세요."); } StringBuilder stringBuilder = new StringBuilder(); StringBuilder stringBuilder2 = stringBuilder; StringBuilder stringBuilder3 = stringBuilder2; StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(15, 1, stringBuilder2); handler.AppendLiteral("사용 가능한 스킬 ("); handler.AppendFormatted(skills.Count); handler.AppendLiteral("개):\n"); stringBuilder3.AppendLine(ref handler); foreach (SkillDefinition item in skills) { stringBuilder2 = stringBuilder; StringBuilder stringBuilder4 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(6, 2, stringBuilder2); handler.AppendLiteral(" /"); handler.AppendFormatted(item.Name); handler.AppendLiteral(" — "); handler.AppendFormatted(item.Label); stringBuilder4.AppendLine(ref handler); stringBuilder2 = stringBuilder; StringBuilder stringBuilder5 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(4, 1, stringBuilder2); handler.AppendLiteral(" "); handler.AppendFormatted(item.Description); stringBuilder5.AppendLine(ref handler); stringBuilder.AppendLine(); } stringBuilder.AppendLine("슬래시 명령어(/{name})로 호출하거나, 대화에서 해당 워크플로우를 요청할 수 있습니다."); return ToolResult.Ok(stringBuilder.ToString()); } private static ToolResult InfoSkill(string name) { if (string.IsNullOrEmpty(name)) { return ToolResult.Fail("skill_name이 필요합니다."); } SkillDefinition skillDefinition = SkillService.Find(name); if (skillDefinition == null) { return ToolResult.Fail("'" + name + "' 스킬을 찾을 수 없습니다. skill_manager(action: list)로 목록을 확인하세요."); } StringBuilder stringBuilder = new StringBuilder(); StringBuilder stringBuilder2 = stringBuilder; StringBuilder stringBuilder3 = stringBuilder2; StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(11, 2, stringBuilder2); handler.AppendLiteral("스킬 상세: "); handler.AppendFormatted(skillDefinition.Label); handler.AppendLiteral(" (/"); handler.AppendFormatted(skillDefinition.Name); handler.AppendLiteral(")"); stringBuilder3.AppendLine(ref handler); stringBuilder2 = stringBuilder; StringBuilder stringBuilder4 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(4, 1, stringBuilder2); handler.AppendLiteral("설명: "); handler.AppendFormatted(skillDefinition.Description); stringBuilder4.AppendLine(ref handler); stringBuilder2 = stringBuilder; StringBuilder stringBuilder5 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(4, 1, stringBuilder2); handler.AppendLiteral("파일: "); handler.AppendFormatted(skillDefinition.FilePath); stringBuilder5.AppendLine(ref handler); stringBuilder2 = stringBuilder; StringBuilder stringBuilder6 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(18, 1, stringBuilder2); handler.AppendLiteral("\n--- 시스템 프롬프트 ---\n"); handler.AppendFormatted(skillDefinition.SystemPrompt); stringBuilder6.AppendLine(ref handler); return ToolResult.Ok(stringBuilder.ToString()); } private static ToolResult ReloadSkills(App? app) { string customFolder = app?.SettingsService?.Settings.Llm.SkillsFolderPath ?? ""; SkillService.LoadSkills(customFolder); return ToolResult.Ok($"스킬 재로드 완료. {SkillService.Skills.Count}개 로드됨."); } }