compact 뒤 첨부 참조가 이어지도록 요약/경계 메시지를 보강
- ContextCondenser가 오래된 메시지 구간의 첨부 파일 이름과 이미지 개수를 수집해 microcompact boundary와 요약 메시지에 함께 기록 - 요약 메시지에 AttachedFiles를 보존해 compact 이후 query view에서도 파일 참조 continuity가 유지되도록 조정 - README와 DEVELOPMENT 문서에 2026-04-12 22:36 (KST) 기준 작업 이력 반영 - 검증: 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:
@@ -1651,3 +1651,7 @@ MIT License
|
||||
- compact 이후 응답/컨텍스트 사용 표시에서 남아 있던 후행 운영 메타를 더 줄였습니다.
|
||||
- [ChatWindow.ResponsePresentation.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.ResponsePresentation.cs)는 응답 하단 토큰 메타에서 `compact 직후` 꼬리표를 제거해, 일반 응답과 같은 밀도로 보이도록 정리했습니다.
|
||||
- [ChatWindow.ContextUsagePresentation.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.ContextUsagePresentation.cs)는 token usage 팝업 detail에서 `compact 후 첫 응답 대기 중` 문구를 빼고 실제 컨텍스트/압축 정보만 보여주도록 단순화했습니다.
|
||||
- 업데이트: 2026-04-12 22:36 (KST)
|
||||
- `claw-code`의 post-compact attachments 흐름을 참고해, AX도 요약/경계 메시지에 오래된 첨부 참조를 다시 실어 compact 뒤 컨텍스트 연속성을 보강했습니다.
|
||||
- [ContextCondenser.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Services/Agent/ContextCondenser.cs)는 오래된 메시지에서 첨부 파일 이름과 이미지 개수를 수집해 `microcompact_boundary`와 요약 메시지에 함께 기록합니다.
|
||||
- 요약 메시지에는 `AttachedFiles`도 같이 보존해, compact 이후에도 관련 파일 참조가 query view로 이어질 수 있게 맞췄습니다.
|
||||
|
||||
@@ -657,3 +657,14 @@ owKindCounts를 함께 남겨 %APPDATA%\\AxCopilot\\perf 기준으로 transcript
|
||||
- compact 이후에도 transcript와 usage UI가 일반 응답과 더 비슷한 밀도로 이어집니다.
|
||||
- 운영 상태는 내부 로직/통계에만 남기고, 사용자 화면은 더 `claw-code` 스타일의 얇은 표현에 가까워집니다.
|
||||
|
||||
## compact 후 첨부 참조 재주입 보강 (2026-04-12 22:36 KST)
|
||||
|
||||
- `claw-code`의 `buildPostCompactMessages()`가 attachments를 boundary/summary 뒤에 다시 붙이는 흐름을 참고해, AX도 compact 이후 첨부 참조가 완전히 사라지지 않도록 보강했습니다.
|
||||
- `src/AxCopilot/Services/Agent/ContextCondenser.cs`
|
||||
- 오래된 메시지 구간에서 `AttachedFiles`와 `Images` 개수를 수집하는 helper를 추가했습니다.
|
||||
- `BuildMicrocompactBoundary()`는 compact 경계 메시지에 관련 파일 목록과 이미지 개수를 함께 요약하고, `AttachedFiles`도 메타 메시지에 유지합니다.
|
||||
- `SummarizeOldMessagesAsync()`는 요약 메시지 하단에 `참고 파일`, `참고 이미지` 줄을 추가하고, `AttachedFiles`도 요약 메시지에 보존합니다.
|
||||
- 기대 효과
|
||||
- compact 이후에도 “이 대화가 어떤 파일/이미지를 참고했는지”가 요약 메시지에서 다시 드러납니다.
|
||||
- query view가 compact 이후 메시지를 다시 보낼 때, 파일 참조 continuity가 이전보다 더 자연스럽게 유지됩니다.
|
||||
|
||||
|
||||
@@ -54,6 +54,12 @@ public static class ContextCondenser
|
||||
public int PreservedToolPairs { get; init; }
|
||||
}
|
||||
|
||||
private sealed class CompactionAttachmentSummary
|
||||
{
|
||||
public required List<string> AttachedFiles { get; init; }
|
||||
public int ImageCount { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>모델별 입력 토큰 한도 (대략).</summary>
|
||||
private static int GetModelInputLimit(string service, string model)
|
||||
{
|
||||
@@ -703,17 +709,7 @@ public static class ContextCondenser
|
||||
!(m.Content ?? "").StartsWith("{\"_tool_use_blocks\"", StringComparison.Ordinal) &&
|
||||
m.MetaKind == null);
|
||||
|
||||
var attachedFiles = group
|
||||
.SelectMany(m => m.AttachedFiles ?? Enumerable.Empty<string>())
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.Select(path =>
|
||||
{
|
||||
try { return System.IO.Path.GetFileName(path); }
|
||||
catch { return path; }
|
||||
})
|
||||
.Where(name => !string.IsNullOrWhiteSpace(name))
|
||||
.Take(4)
|
||||
.ToList();
|
||||
var attachmentSummary = CollectCompactionAttachmentSummary(group, 4);
|
||||
|
||||
var lines = new List<string>
|
||||
{
|
||||
@@ -724,7 +720,8 @@ public static class ContextCondenser
|
||||
if (toolCalls > 0) lines.Add($"- 도구 호출 {toolCalls}건 정리");
|
||||
if (metaEvents > 0) lines.Add($"- 실행 메타/로그 {metaEvents}건 정리");
|
||||
if (longTexts > 0) lines.Add($"- 긴 설명/출력 {longTexts}건 축약");
|
||||
if (attachedFiles.Count > 0) lines.Add($"- 관련 파일: {string.Join(", ", attachedFiles)}");
|
||||
if (attachmentSummary.AttachedFiles.Count > 0) lines.Add($"- 관련 파일: {string.Join(", ", attachmentSummary.AttachedFiles)}");
|
||||
if (attachmentSummary.ImageCount > 0) lines.Add($"- 관련 이미지: {attachmentSummary.ImageCount}개");
|
||||
|
||||
return new ChatMessage
|
||||
{
|
||||
@@ -733,6 +730,7 @@ public static class ContextCondenser
|
||||
Timestamp = group.Last().Timestamp,
|
||||
MetaKind = "microcompact_boundary",
|
||||
MetaRunId = group.Last().MetaRunId,
|
||||
AttachedFiles = attachmentSummary.AttachedFiles.Count > 0 ? attachmentSummary.AttachedFiles : null,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -747,6 +745,7 @@ public static class ContextCondenser
|
||||
var systemMsg = window.SystemMessage;
|
||||
var oldMessages = window.OldMessages;
|
||||
var recentMessages = window.RecentMessages;
|
||||
var attachmentSummary = CollectCompactionAttachmentSummary(oldMessages, 6);
|
||||
|
||||
if (oldMessages.Count < 3) return false;
|
||||
|
||||
@@ -787,8 +786,9 @@ public static class ContextCondenser
|
||||
messages.Add(new ChatMessage
|
||||
{
|
||||
Role = "user",
|
||||
Content = $"[이전 대화 요약 — {oldMessages.Count}개 메시지 압축]\n{summary}",
|
||||
Content = BuildSummaryMessageContent(oldMessages.Count, summary, attachmentSummary),
|
||||
Timestamp = DateTime.Now,
|
||||
AttachedFiles = attachmentSummary.AttachedFiles.Count > 0 ? attachmentSummary.AttachedFiles : null,
|
||||
});
|
||||
messages.Add(new ChatMessage
|
||||
{
|
||||
@@ -806,4 +806,42 @@ public static class ContextCondenser
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static CompactionAttachmentSummary CollectCompactionAttachmentSummary(IEnumerable<ChatMessage> messages, int maxFiles)
|
||||
{
|
||||
var attachedFiles = messages
|
||||
.SelectMany(m => m.AttachedFiles ?? Enumerable.Empty<string>())
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.Select(path =>
|
||||
{
|
||||
try { return System.IO.Path.GetFileName(path); }
|
||||
catch { return path; }
|
||||
})
|
||||
.Where(name => !string.IsNullOrWhiteSpace(name))
|
||||
.Take(Math.Max(1, maxFiles))
|
||||
.ToList();
|
||||
|
||||
var imageCount = messages.Sum(m => m.Images?.Count ?? 0);
|
||||
return new CompactionAttachmentSummary
|
||||
{
|
||||
AttachedFiles = attachedFiles,
|
||||
ImageCount = imageCount,
|
||||
};
|
||||
}
|
||||
|
||||
private static string BuildSummaryMessageContent(int oldMessageCount, string summary, CompactionAttachmentSummary attachmentSummary)
|
||||
{
|
||||
var lines = new List<string>
|
||||
{
|
||||
$"[이전 대화 요약 — {oldMessageCount}개 메시지 압축]",
|
||||
summary.Trim()
|
||||
};
|
||||
|
||||
if (attachmentSummary.AttachedFiles.Count > 0)
|
||||
lines.Add($"참고 파일: {string.Join(", ", attachmentSummary.AttachedFiles)}");
|
||||
if (attachmentSummary.ImageCount > 0)
|
||||
lines.Add($"참고 이미지: {attachmentSummary.ImageCount}개");
|
||||
|
||||
return string.Join("\n", lines.Where(x => !string.IsNullOrWhiteSpace(x)));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user