166 lines
6.3 KiB
C#
166 lines
6.3 KiB
C#
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<string, ToolProperty> dictionary = new Dictionary<string, ToolProperty>();
|
|
ToolProperty obj = new ToolProperty
|
|
{
|
|
Type = "string",
|
|
Description = "list (목록), info (상세정보), reload (재로드)"
|
|
};
|
|
int num = 3;
|
|
List<string> list = new List<string>(num);
|
|
CollectionsMarshal.SetCount(list, num);
|
|
Span<string> 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<string> list2 = new List<string>(num);
|
|
CollectionsMarshal.SetCount(list2, num);
|
|
CollectionsMarshal.AsSpan(list2)[0] = "action";
|
|
toolParameterSchema.Required = list2;
|
|
return toolParameterSchema;
|
|
}
|
|
}
|
|
|
|
public async Task<ToolResult> 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<SkillDefinition> 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}개 로드됨.");
|
|
}
|
|
}
|