오래된 tool_result를 시간 기반으로 정리하고 compact 직후 안내를 단순화
- 마지막 assistant 이후 긴 휴지기가 있으면 오래된 tool_result를 cleared marker로 교체하는 time-based microcompact 성격의 분기 추가 - compact 직후 첫 턴에서 운영성 thinking 문구를 다시 띄우지 않도록 AgentLoopCompactionPolicy 정리 - README와 DEVELOPMENT 문서에 2026-04-12 22:11 (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:
@@ -42,6 +42,9 @@ public static class ContextCondenser
|
||||
private const int RecentKeepCount = 6;
|
||||
private const int AutoCompactBufferTokens = 13_000;
|
||||
private const int SummaryReserveTokens = 20_000;
|
||||
private const int TimeBasedToolResultGapMinutes = 20;
|
||||
private const int TimeBasedKeepRecentToolResults = 1;
|
||||
private const string TimeBasedClearedToolResultMessage = "[time-based microcompact] 이전 tool_result 내용이 정리되었습니다.";
|
||||
|
||||
private sealed class CompactionWindow
|
||||
{
|
||||
@@ -119,8 +122,16 @@ public static class ContextCondenser
|
||||
|
||||
var currentTokens = TokenEstimator.EstimateMessages(messages);
|
||||
result.BeforeTokens = currentTokens;
|
||||
|
||||
if (ApplyTimeBasedToolResultCompaction(messages, out var clearedToolResults))
|
||||
{
|
||||
result.AppliedStages.Add($"time-gap-tool-result({clearedToolResults})");
|
||||
currentTokens = TokenEstimator.EstimateMessages(messages);
|
||||
}
|
||||
|
||||
if (!force && currentTokens < threshold)
|
||||
{
|
||||
result.Changed = result.AppliedStages.Count > 0;
|
||||
result.AfterTokens = currentTokens;
|
||||
return result;
|
||||
}
|
||||
@@ -240,6 +251,55 @@ public static class ContextCondenser
|
||||
};
|
||||
}
|
||||
|
||||
private static bool ApplyTimeBasedToolResultCompaction(List<ChatMessage> messages, out int clearedCount)
|
||||
{
|
||||
clearedCount = 0;
|
||||
var lastAssistant = messages
|
||||
.Where(m => string.Equals(m.Role, "assistant", StringComparison.OrdinalIgnoreCase))
|
||||
.OrderByDescending(m => m.Timestamp)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (lastAssistant?.Timestamp is not DateTime lastAssistantAt)
|
||||
return false;
|
||||
|
||||
var gapMinutes = (DateTime.Now - lastAssistantAt).TotalMinutes;
|
||||
if (!double.IsFinite(gapMinutes) || gapMinutes < TimeBasedToolResultGapMinutes)
|
||||
return false;
|
||||
|
||||
var candidateIndexes = messages
|
||||
.Select((message, index) => new { message, index })
|
||||
.Where(x => AgentMessageInvariantHelper.TryGetToolResultId(x.message, out _))
|
||||
.Select(x => x.index)
|
||||
.ToList();
|
||||
|
||||
if (candidateIndexes.Count <= TimeBasedKeepRecentToolResults)
|
||||
return false;
|
||||
|
||||
var keepSet = candidateIndexes
|
||||
.TakeLast(Math.Max(1, TimeBasedKeepRecentToolResults))
|
||||
.ToHashSet();
|
||||
|
||||
foreach (var index in candidateIndexes)
|
||||
{
|
||||
if (keepSet.Contains(index))
|
||||
continue;
|
||||
|
||||
var message = messages[index];
|
||||
var content = message.Content ?? "";
|
||||
if (string.IsNullOrWhiteSpace(content))
|
||||
continue;
|
||||
|
||||
var cleared = AgentToolResultBudget.CreateClearedToolResultJson(content, TimeBasedClearedToolResultMessage);
|
||||
if (string.Equals(cleared, content, StringComparison.Ordinal))
|
||||
continue;
|
||||
|
||||
messages[index] = CloneWithContent(message, cleared);
|
||||
clearedCount++;
|
||||
}
|
||||
|
||||
return clearedCount > 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 1단계: 오래된 tool_result는 aggregate budget 기준으로 먼저 줄이고,
|
||||
/// 그 외 긴 assistant/user 메시지는 경량 절단합니다.
|
||||
|
||||
Reference in New Issue
Block a user