계층형 메모리 문서 로드 후 동일한 규칙 내용은 더 가까운 계층만 남기고 중복을 제거하도록 NormalizeInstructionDocuments 로직을 추가했습니다. 최종 메모리 문서는 managed, user, project, local 순서로 다시 정렬되고 우선순위 번호를 부여하며, MemoryTool의 list와 search 결과에서 그 우선순위를 함께 보여주도록 했습니다. README와 DEVELOPMENT 문서에 2026-04-07 00:39 (KST) 기준 이력을 반영했고 Release 빌드 경고 0 오류 0을 확인했습니다.
This commit is contained in:
@@ -1405,3 +1405,6 @@ MIT License
|
||||
- 업데이트: 2026-04-07 00:31 (KST)
|
||||
- [AgentMemoryService.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Services/AgentMemoryService.cs)에 `description:` frontmatter 메타를 추가해 계층형 메모리 규칙 파일이 “무엇을 위한 규칙인지” 설명을 가질 수 있게 했습니다.
|
||||
- [MemoryTool.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Services/Agent/MemoryTool.cs) 는 `show_scope` 액션을 새로 지원합니다. 이제 `/memory` 계열 명령으로 `managed / user / project / local` 메모리 파일의 실제 내용을 직접 확인할 수 있고, `list/search` 결과에도 `description`과 `paths` 범위가 함께 표시됩니다.
|
||||
- 업데이트: 2026-04-07 00:39 (KST)
|
||||
- [AgentMemoryService.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Services/AgentMemoryService.cs)에 계층형 메모리 우선순위/병합 정책을 추가했습니다. 같은 내용의 규칙이 여러 계층에 중복될 경우 더 가까운 규칙만 남기고, 최종 메모리 문서는 `managed → user → project → local` 순으로 다시 정렬됩니다.
|
||||
- [MemoryTool.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Services/Agent/MemoryTool.cs) 의 `list/search`는 이제 최종 우선순위 번호를 같이 보여줘, 어떤 규칙이 실제로 더 강하게 적용되는지 바로 확인할 수 있습니다.
|
||||
|
||||
@@ -5185,3 +5185,13 @@ ow + toggle ?쒓컖 ?몄뼱濡??ㅼ떆 ?뺣젹?덈떎.
|
||||
- [MemoryTool.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Services/Agent/MemoryTool.cs)
|
||||
- `show_scope` 액션을 추가해 `managed / user / project / local` 메모리 파일의 실제 경로와 본문을 바로 확인할 수 있게 했다.
|
||||
- `list`, `search` 출력에는 계층형 메모리 문서의 `description`과 `paths` 메타를 함께 노출해, `claw-code`의 rule 파일처럼 어떤 규칙이 어느 범위에 적용되는지 빠르게 읽을 수 있도록 정리했다.
|
||||
|
||||
## 2026-04-07 00:39 (KST)
|
||||
|
||||
- [AgentMemoryService.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Services/AgentMemoryService.cs)
|
||||
- 계층형 메모리 로드 뒤 `NormalizeInstructionDocuments()`를 수행하도록 바꿨다.
|
||||
- 동일한 규칙 내용이 여러 계층에 중복되면 더 나중에 로드된 문서, 즉 현재 작업 위치에 더 가까운 문서를 남기고 앞선 중복 문서는 제거한다.
|
||||
- 최종 문서는 `managed → user → project → local` 순서로 다시 정렬하고, 각 문서에 최종 적용 우선순위 번호를 부여한다.
|
||||
- [MemoryTool.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Services/Agent/MemoryTool.cs)
|
||||
- `list`, `search` 출력에 계층형 메모리 문서의 우선순위를 함께 노출하도록 정리했다.
|
||||
- 사용자는 이제 `/memory` 결과에서 어떤 규칙이 실제로 더 강하게 적용되는지 바로 읽을 수 있다.
|
||||
|
||||
@@ -107,9 +107,10 @@ public class MemoryTool : IAgentTool
|
||||
sb.AppendLine($"계층형 메모리 {docs.Count}개:");
|
||||
foreach (var doc in docs)
|
||||
{
|
||||
var priority = doc.Priority > 0 ? $" (우선순위 {doc.Priority})" : "";
|
||||
var suffix = string.IsNullOrWhiteSpace(doc.Description) ? "" : $" — {doc.Description}";
|
||||
var scopeHint = doc.Paths.Count > 0 ? $" (paths: {string.Join(", ", doc.Paths)})" : "";
|
||||
sb.AppendLine($" [{doc.Label}] {doc.Path}{suffix}{scopeHint}");
|
||||
sb.AppendLine($" [{doc.Label}] {doc.Path}{priority}{suffix}{scopeHint}");
|
||||
}
|
||||
sb.AppendLine();
|
||||
}
|
||||
@@ -136,9 +137,10 @@ public class MemoryTool : IAgentTool
|
||||
sb.AppendLine($"계층형 메모리 파일 {docs.Count}개:");
|
||||
foreach (var doc in docs)
|
||||
{
|
||||
var priority = doc.Priority > 0 ? $" (우선순위 {doc.Priority})" : "";
|
||||
var suffix = string.IsNullOrWhiteSpace(doc.Description) ? "" : $" — {doc.Description}";
|
||||
var scopeHint = doc.Paths.Count > 0 ? $" (paths: {string.Join(", ", doc.Paths)})" : "";
|
||||
sb.AppendLine($" • [{doc.Label}] {doc.Path}{suffix}{scopeHint}");
|
||||
sb.AppendLine($" • [{doc.Label}] {doc.Path}{priority}{suffix}{scopeHint}");
|
||||
}
|
||||
sb.AppendLine();
|
||||
}
|
||||
|
||||
@@ -146,6 +146,7 @@ public class AgentMemoryService
|
||||
}
|
||||
|
||||
LoadInstructionDocuments(workFolder);
|
||||
NormalizeInstructionDocuments();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -416,7 +417,8 @@ public class AgentMemoryService
|
||||
Path = fullPath,
|
||||
Content = frontMatter.Content.Trim(),
|
||||
Paths = frontMatter.Paths,
|
||||
Description = frontMatter.Description
|
||||
Description = frontMatter.Description,
|
||||
LoadOrder = _instructionDocuments.Count
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -425,6 +427,60 @@ public class AgentMemoryService
|
||||
}
|
||||
}
|
||||
|
||||
private void NormalizeInstructionDocuments()
|
||||
{
|
||||
if (_instructionDocuments.Count <= 1)
|
||||
return;
|
||||
|
||||
var seenNormalized = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
var selected = new List<MemoryInstructionDocument>();
|
||||
|
||||
foreach (var doc in _instructionDocuments.OrderByDescending(d => d.LoadOrder))
|
||||
{
|
||||
var normalized = NormalizeInstructionContent(doc.Content);
|
||||
if (!string.IsNullOrWhiteSpace(normalized) && !seenNormalized.Add(normalized))
|
||||
continue;
|
||||
|
||||
selected.Add(doc);
|
||||
}
|
||||
|
||||
selected = selected
|
||||
.OrderBy(d => GetLayerRank(d.Layer))
|
||||
.ThenBy(d => d.LoadOrder)
|
||||
.ToList();
|
||||
|
||||
for (var i = 0; i < selected.Count; i++)
|
||||
{
|
||||
selected[i].Priority = i + 1;
|
||||
}
|
||||
|
||||
_instructionDocuments.Clear();
|
||||
_instructionDocuments.AddRange(selected);
|
||||
}
|
||||
|
||||
private static string NormalizeInstructionContent(string content)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(content))
|
||||
return "";
|
||||
|
||||
var normalizedLines = content
|
||||
.Replace("\r\n", "\n")
|
||||
.Split('\n')
|
||||
.Select(line => string.Join(" ", line.Split(' ', '\t').Where(part => part.Length > 0)).Trim())
|
||||
.Where(line => line.Length > 0);
|
||||
|
||||
return string.Join("\n", normalizedLines).Trim();
|
||||
}
|
||||
|
||||
private static int GetLayerRank(string layer) => layer switch
|
||||
{
|
||||
"managed" => 0,
|
||||
"user" => 1,
|
||||
"project" => 2,
|
||||
"local" => 3,
|
||||
_ => 9
|
||||
};
|
||||
|
||||
private static IEnumerable<string> EnumerateDirectoryChain(string projectRoot, string workFolder)
|
||||
{
|
||||
var current = Path.GetFullPath(workFolder);
|
||||
@@ -804,4 +860,10 @@ public class MemoryInstructionDocument
|
||||
|
||||
[JsonPropertyName("description")]
|
||||
public string Description { get; set; } = "";
|
||||
|
||||
[JsonPropertyName("loadOrder")]
|
||||
public int LoadOrder { get; set; }
|
||||
|
||||
[JsonPropertyName("priority")]
|
||||
public int Priority { get; set; }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user