using System.Collections.Generic; using System.Linq; 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 MemoryTool : IAgentTool { public string Name => "memory"; public string Description => "프로젝트 규칙, 사용자 선호도, 학습 내용을 저장하고 검색합니다.\n대화 간 지속되는 메모리로, 새 대화에서도 이전에 학습한 내용을 활용할 수 있습니다.\n- action=\"save\": 새 메모리 저장 (type, content 필수)\n- action=\"search\": 관련 메모리 검색 (query 필수)\n- action=\"list\": 현재 메모리 전체 목록\n- action=\"delete\": 메모리 삭제 (id 필수)\ntype 종류: rule(프로젝트 규칙), preference(사용자 선호), fact(사실), correction(실수 교정)"; public ToolParameterSchema Parameters { get { ToolParameterSchema obj = new ToolParameterSchema { Properties = new Dictionary { ["action"] = new ToolProperty { Type = "string", Description = "save | search | list | delete" }, ["type"] = new ToolProperty { Type = "string", Description = "메모리 유형: rule | preference | fact | correction. save 시 필수." }, ["content"] = new ToolProperty { Type = "string", Description = "저장할 내용. save 시 필수." }, ["query"] = new ToolProperty { Type = "string", Description = "검색 쿼리. search 시 필수." }, ["id"] = new ToolProperty { Type = "string", Description = "메모리 ID. delete 시 필수." } } }; int num = 1; List list = new List(num); CollectionsMarshal.SetCount(list, num); CollectionsMarshal.AsSpan(list)[0] = "action"; obj.Required = list; return obj; } } public Task ExecuteAsync(JsonElement args, AgentContext context, CancellationToken ct = default(CancellationToken)) { App app = Application.Current as App; if (!(app?.SettingsService?.Settings.Llm.EnableAgentMemory ?? true)) { return Task.FromResult(ToolResult.Ok("에이전트 메모리가 비활성 상태입니다. 설정에서 활성화하세요.")); } AgentMemoryService agentMemoryService = app?.MemoryService; if (agentMemoryService == null) { return Task.FromResult(ToolResult.Fail("메모리 서비스를 사용할 수 없습니다.")); } if (!args.TryGetProperty("action", out var value)) { return Task.FromResult(ToolResult.Fail("action이 필요합니다.")); } string text = value.GetString() ?? ""; if (1 == 0) { } ToolResult result = text switch { "save" => ExecuteSave(args, agentMemoryService, context), "search" => ExecuteSearch(args, agentMemoryService), "list" => ExecuteList(agentMemoryService), "delete" => ExecuteDelete(args, agentMemoryService), _ => ToolResult.Fail("알 수 없는 액션: " + text + ". save | search | list | delete 중 선택하세요."), }; if (1 == 0) { } return Task.FromResult(result); } private static ToolResult ExecuteSave(JsonElement args, AgentMemoryService svc, AgentContext context) { JsonElement value; string text = (args.TryGetProperty("type", out value) ? (value.GetString() ?? "fact") : "fact"); JsonElement value2; string text2 = (args.TryGetProperty("content", out value2) ? (value2.GetString() ?? "") : ""); if (string.IsNullOrWhiteSpace(text2)) { return ToolResult.Fail("content가 필요합니다."); } string[] source = new string[4] { "rule", "preference", "fact", "correction" }; if (!source.Contains(text)) { return ToolResult.Fail("잘못된 type: " + text + ". rule | preference | fact | correction 중 선택하세요."); } string workFolder = (string.IsNullOrEmpty(context.WorkFolder) ? null : context.WorkFolder); MemoryEntry memoryEntry = svc.Add(text, text2, "agent:" + context.ActiveTab, workFolder); return ToolResult.Ok($"메모리 저장됨 [{memoryEntry.Type}] (ID: {memoryEntry.Id}): {memoryEntry.Content}"); } private static ToolResult ExecuteSearch(JsonElement args, AgentMemoryService svc) { JsonElement value; string text = (args.TryGetProperty("query", out value) ? (value.GetString() ?? "") : ""); if (string.IsNullOrWhiteSpace(text)) { return ToolResult.Fail("query가 필요합니다."); } List relevant = svc.GetRelevant(text); if (relevant.Count == 0) { return ToolResult.Ok("관련 메모리가 없습니다."); } StringBuilder stringBuilder = new StringBuilder(); StringBuilder stringBuilder2 = stringBuilder; StringBuilder stringBuilder3 = stringBuilder2; StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(9, 1, stringBuilder2); handler.AppendLiteral("관련 메모리 "); handler.AppendFormatted(relevant.Count); handler.AppendLiteral("개:"); stringBuilder3.AppendLine(ref handler); foreach (MemoryEntry item in relevant) { stringBuilder2 = stringBuilder; StringBuilder stringBuilder4 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(18, 4, stringBuilder2); handler.AppendLiteral(" ["); handler.AppendFormatted(item.Type); handler.AppendLiteral("] "); handler.AppendFormatted(item.Content); handler.AppendLiteral(" (사용 "); handler.AppendFormatted(item.UseCount); handler.AppendLiteral("회, ID: "); handler.AppendFormatted(item.Id); handler.AppendLiteral(")"); stringBuilder4.AppendLine(ref handler); } return ToolResult.Ok(stringBuilder.ToString()); } private static ToolResult ExecuteList(AgentMemoryService svc) { IReadOnlyList all = svc.All; if (all.Count == 0) { return ToolResult.Ok("저장된 메모리가 없습니다."); } StringBuilder stringBuilder = new StringBuilder(); StringBuilder stringBuilder2 = stringBuilder; StringBuilder stringBuilder3 = stringBuilder2; StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(9, 1, stringBuilder2); handler.AppendLiteral("전체 메모리 "); handler.AppendFormatted(all.Count); handler.AppendLiteral("개:"); stringBuilder3.AppendLine(ref handler); foreach (IGrouping item in from e in all group e by e.Type) { stringBuilder2 = stringBuilder; StringBuilder stringBuilder4 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(3, 1, stringBuilder2); handler.AppendLiteral("\n["); handler.AppendFormatted(item.Key); handler.AppendLiteral("]"); stringBuilder4.AppendLine(ref handler); foreach (MemoryEntry item2 in item.OrderByDescending((MemoryEntry e) => e.UseCount)) { stringBuilder2 = stringBuilder; StringBuilder stringBuilder5 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(17, 3, stringBuilder2); handler.AppendLiteral(" • "); handler.AppendFormatted(item2.Content); handler.AppendLiteral(" (사용 "); handler.AppendFormatted(item2.UseCount); handler.AppendLiteral("회, ID: "); handler.AppendFormatted(item2.Id); handler.AppendLiteral(")"); stringBuilder5.AppendLine(ref handler); } } return ToolResult.Ok(stringBuilder.ToString()); } private static ToolResult ExecuteDelete(JsonElement args, AgentMemoryService svc) { JsonElement value; string text = (args.TryGetProperty("id", out value) ? (value.GetString() ?? "") : ""); if (string.IsNullOrWhiteSpace(text)) { return ToolResult.Fail("id가 필요합니다."); } return svc.Remove(text) ? ToolResult.Ok("메모리 삭제됨 (ID: " + text + ")") : ToolResult.Fail("해당 ID의 메모리를 찾을 수 없습니다: " + text); } }