Files

210 lines
7.7 KiB
C#

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<string, ToolProperty>
{
["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<string> list = new List<string>(num);
CollectionsMarshal.SetCount(list, num);
CollectionsMarshal.AsSpan(list)[0] = "action";
obj.Required = list;
return obj;
}
}
public Task<ToolResult> 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<MemoryEntry> 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<MemoryEntry> 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<string, MemoryEntry> 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);
}
}