AX Agent 메모리 구조 2차 강화: 계층형 메모리 관리 도구 확장
Some checks failed
Release Gate / gate (push) Has been cancelled
Some checks failed
Release Gate / gate (push) Has been cancelled
- memory 도구에 save_scope, delete_scope 액션을 추가해 managed/user/project/local 메모리 파일을 직접 저장 및 삭제할 수 있게 확장함 - search, list 액션이 학습 메모리뿐 아니라 계층형 메모리 문서도 함께 보여주도록 개선함 - AgentMemoryService에 계층형 메모리 파일 쓰기/삭제 경로와 append/remove 로직을 추가해 메모리 계층을 실제로 관리 가능한 상태로 전환함 - 검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify\\ -p:IntermediateOutputPath=obj\\verify\\ (경고 0 / 오류 0)
This commit is contained in:
@@ -45,6 +45,84 @@ public class AgentMemoryService
|
||||
get { lock (_lock) return _instructionDocuments.ToList(); }
|
||||
}
|
||||
|
||||
public string? GetWritableInstructionPath(string scope, string? workFolder)
|
||||
{
|
||||
scope = (scope ?? "").Trim().ToLowerInvariant();
|
||||
return scope switch
|
||||
{
|
||||
"managed" => Path.Combine(ManagedMemoryDir, MemoryFileName),
|
||||
"user" => Path.Combine(MemoryDir, MemoryFileName),
|
||||
"project" => string.IsNullOrWhiteSpace(workFolder) ? null : Path.Combine(Path.GetFullPath(workFolder), MemoryFileName),
|
||||
"local" => string.IsNullOrWhiteSpace(workFolder) ? null : Path.Combine(Path.GetFullPath(workFolder), LocalMemoryFileName),
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
|
||||
public (bool Changed, string Path, string Message) SaveInstruction(string scope, string content, string? workFolder)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
var path = GetWritableInstructionPath(scope, workFolder);
|
||||
if (string.IsNullOrWhiteSpace(path))
|
||||
return (false, "", "해당 scope에 저장할 경로를 결정할 수 없습니다.");
|
||||
|
||||
try
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(path)!);
|
||||
var existing = File.Exists(path) ? File.ReadAllText(path) : "";
|
||||
if (existing.Contains(content, StringComparison.OrdinalIgnoreCase))
|
||||
return (false, path, "이미 같은 내용이 메모리 파일에 있습니다.");
|
||||
|
||||
var sb = new StringBuilder();
|
||||
if (!string.IsNullOrWhiteSpace(existing))
|
||||
{
|
||||
sb.Append(existing.TrimEnd());
|
||||
sb.AppendLine();
|
||||
sb.AppendLine();
|
||||
}
|
||||
|
||||
sb.AppendLine($"- {content.Trim()}");
|
||||
File.WriteAllText(path, sb.ToString());
|
||||
Load(workFolder);
|
||||
return (true, path, "메모리 파일에 지시를 추가했습니다.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogService.Warn($"메모리 파일 저장 실패 ({path}): {ex.Message}");
|
||||
return (false, path, $"메모리 파일 저장 실패: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public (bool Changed, string Path, string Message) DeleteInstruction(string scope, string query, string? workFolder)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
var path = GetWritableInstructionPath(scope, workFolder);
|
||||
if (string.IsNullOrWhiteSpace(path))
|
||||
return (false, "", "해당 scope에 저장된 메모리 파일 경로를 찾을 수 없습니다.");
|
||||
if (!File.Exists(path))
|
||||
return (false, path, "메모리 파일이 아직 없습니다.");
|
||||
|
||||
try
|
||||
{
|
||||
var lines = File.ReadAllLines(path).ToList();
|
||||
var filtered = lines.Where(line => !line.Contains(query, StringComparison.OrdinalIgnoreCase)).ToList();
|
||||
if (filtered.Count == lines.Count)
|
||||
return (false, path, "삭제할 일치 항목을 찾지 못했습니다.");
|
||||
|
||||
File.WriteAllLines(path, filtered);
|
||||
Load(workFolder);
|
||||
return (true, path, "메모리 파일에서 일치 항목을 삭제했습니다.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogService.Warn($"메모리 파일 삭제 실패 ({path}): {ex.Message}");
|
||||
return (false, path, $"메모리 파일 삭제 실패: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>작업 폴더별 메모리 + 전역 메모리를 로드합니다.</summary>
|
||||
public void Load(string? workFolder)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user