- 유휴 전환 후 하단 상태바 전체 토큰 집계가 사라지지 않도록 대화 기준 합산 복원 경로 추가 - 컨텍스트 사용량 팝업에 마지막 실제 압축 before/after 및 누적 절감량 표시 - total_stats 이벤트가 진행 피드에 흡수되지 않고 전용 통계 카드로 다시 노출되게 수정 - 관련 README 및 개발 문서 이력 갱신 검증: 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:
@@ -32,7 +32,7 @@ internal static class AgentTranscriptDisplayCatalog
|
||||
|
||||
"build_run" => "빌드/실행",
|
||||
"test_loop" => "테스트 루프",
|
||||
"dev_env_detect" => "개발 환경 점검",
|
||||
"dev_env_detect" => "개발 환경 감지",
|
||||
"git_tool" => "Git",
|
||||
"diff_tool" => "Diff",
|
||||
"diff_preview" => "Diff 미리보기",
|
||||
|
||||
@@ -121,6 +121,10 @@ public partial class ChatWindow
|
||||
|
||||
private static bool IsProcessFeedEvent(AgentEvent evt)
|
||||
{
|
||||
if (evt.Type == AgentEventType.StepDone
|
||||
&& string.Equals(evt.ToolName, "total_stats", StringComparison.OrdinalIgnoreCase))
|
||||
return false;
|
||||
|
||||
return evt.Type is AgentEventType.Planning
|
||||
or AgentEventType.StepStart
|
||||
or AgentEventType.StepDone
|
||||
|
||||
@@ -52,7 +52,7 @@ public partial class ChatWindow
|
||||
else if (usageRatio >= triggerRatio)
|
||||
{
|
||||
progressBrush = Brushes.DarkOrange;
|
||||
summary = llm.EnableProactiveContextCompact ? "곧 자동 압축" : "압축 임계 도달";
|
||||
summary = llm.EnableProactiveContextCompact ? "곧 자동 압축" : "압축 한계 도달";
|
||||
compactLabel = "압축 권장";
|
||||
}
|
||||
else if (usageRatio >= triggerRatio * 0.7)
|
||||
@@ -67,6 +67,17 @@ public partial class ChatWindow
|
||||
compactLabel = "압축";
|
||||
}
|
||||
|
||||
string detailText;
|
||||
if (_lastCompactionAt.HasValue && _lastCompactionBeforeTokens.HasValue && _lastCompactionAfterTokens.HasValue)
|
||||
{
|
||||
var compactType = _lastCompactionWasAutomatic ? "자동" : "수동";
|
||||
detailText = $"{compactType} 압축 {Services.TokenEstimator.Format(_lastCompactionBeforeTokens.Value)} → {Services.TokenEstimator.Format(_lastCompactionAfterTokens.Value)}";
|
||||
}
|
||||
else
|
||||
{
|
||||
detailText = $"자동 압축 시작 {triggerPercent}%";
|
||||
}
|
||||
|
||||
TokenUsageArc.Stroke = progressBrush;
|
||||
TokenUsageThresholdMarker.Fill = progressBrush;
|
||||
var percentText = $"{Math.Round(usageRatio * 100):0}%";
|
||||
@@ -80,9 +91,13 @@ public partial class ChatWindow
|
||||
if (TokenUsagePopupUsage != null)
|
||||
TokenUsagePopupUsage.Text = $"{Services.TokenEstimator.Format(currentTokens)}/{Services.TokenEstimator.Format(maxContextTokens)}";
|
||||
if (TokenUsagePopupDetail != null)
|
||||
TokenUsagePopupDetail.Text = _pendingPostCompaction ? "compact 후 첫 응답 대기 중" : $"자동 압축 시작 {triggerPercent}%";
|
||||
TokenUsagePopupDetail.Text = _pendingPostCompaction
|
||||
? $"compact 후 첫 응답 대기 중 · {detailText}"
|
||||
: detailText;
|
||||
if (TokenUsagePopupCompact != null)
|
||||
TokenUsagePopupCompact.Text = "AX Agent가 컨텍스트를 자동으로 관리합니다";
|
||||
TokenUsagePopupCompact.Text = _sessionCompactionCount > 0
|
||||
? $"누적 압축 {_sessionCompactionCount}회 · 절감 {FormatTokenCount(_sessionCompactionSavedTokens)} tokens"
|
||||
: "AX Agent가 컨텍스트를 자동으로 관리합니다";
|
||||
|
||||
TokenUsageCard.ToolTip = null;
|
||||
|
||||
|
||||
@@ -136,10 +136,50 @@ public partial class ChatWindow
|
||||
if (IsDecisionApproved(summary))
|
||||
return "계획 승인됨 · 실행 시작";
|
||||
if (IsDecisionRejected(summary))
|
||||
return "계획 반려됨 · 계획 재작성";
|
||||
return "계획 반려됨 · 계획 수정";
|
||||
return string.IsNullOrWhiteSpace(summary) ? "사용자 의사결정 대기 중" : TruncateForStatus(summary);
|
||||
}
|
||||
|
||||
private (int PromptTokens, int CompletionTokens) GetConversationTokenAggregate()
|
||||
{
|
||||
lock (_convLock)
|
||||
{
|
||||
if (_currentConversation?.Messages == null || _currentConversation.Messages.Count == 0)
|
||||
return (0, 0);
|
||||
|
||||
var prompt = 0;
|
||||
var completion = 0;
|
||||
foreach (var message in _currentConversation.Messages)
|
||||
{
|
||||
prompt += Math.Max(0, message.PromptTokens);
|
||||
completion += Math.Max(0, message.CompletionTokens);
|
||||
}
|
||||
|
||||
return (prompt, completion);
|
||||
}
|
||||
}
|
||||
|
||||
private void RefreshStatusTokenAggregate()
|
||||
{
|
||||
var promptTokens = Math.Max(0, _agentCumulativeInputTokens);
|
||||
var completionTokens = Math.Max(0, _agentCumulativeOutputTokens);
|
||||
|
||||
if (promptTokens == 0 && completionTokens == 0)
|
||||
{
|
||||
var aggregate = GetConversationTokenAggregate();
|
||||
promptTokens = aggregate.PromptTokens;
|
||||
completionTokens = aggregate.CompletionTokens;
|
||||
}
|
||||
|
||||
if (promptTokens > 0 || completionTokens > 0)
|
||||
UpdateStatusTokens(promptTokens, completionTokens);
|
||||
else if (StatusTokens != null)
|
||||
{
|
||||
StatusTokens.Text = "";
|
||||
StatusTokens.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetStatusIdle()
|
||||
{
|
||||
StopStatusAnimation();
|
||||
@@ -150,11 +190,8 @@ public partial class ChatWindow
|
||||
StatusElapsed.Text = "";
|
||||
StatusElapsed.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
if (StatusTokens != null)
|
||||
{
|
||||
StatusTokens.Text = "";
|
||||
StatusTokens.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
|
||||
RefreshStatusTokenAggregate();
|
||||
RefreshContextUsageVisual();
|
||||
ScheduleGitBranchRefresh(250);
|
||||
}
|
||||
@@ -173,6 +210,7 @@ public partial class ChatWindow
|
||||
StatusTokens.Visibility = Visibility.Visible;
|
||||
RefreshContextUsageVisual();
|
||||
}
|
||||
|
||||
private void UpdateStatusBar(AgentEvent evt)
|
||||
{
|
||||
var toolLabel = evt.ToolName switch
|
||||
@@ -200,16 +238,16 @@ public partial class ChatWindow
|
||||
SetStatus("생각 중...", spinning: true);
|
||||
break;
|
||||
case AgentEventType.Planning:
|
||||
SetStatus($"계획 수립 중 — {evt.StepTotal}단계", spinning: true);
|
||||
SetStatus($"계획 정리 중... {evt.StepTotal}단계", spinning: true);
|
||||
break;
|
||||
case AgentEventType.PermissionRequest:
|
||||
SetStatus($"권한 확인 중: {toolLabel}", spinning: false);
|
||||
SetStatus($"권한 확인 중 · {toolLabel}", spinning: false);
|
||||
break;
|
||||
case AgentEventType.PermissionGranted:
|
||||
SetStatus($"권한 승인됨: {toolLabel}", spinning: false);
|
||||
SetStatus($"권한 승인됨 · {toolLabel}", spinning: false);
|
||||
break;
|
||||
case AgentEventType.PermissionDenied:
|
||||
SetStatus($"권한 거부됨: {toolLabel}", spinning: false);
|
||||
SetStatus($"권한 거부됨 · {toolLabel}", spinning: false);
|
||||
StopStatusAnimation();
|
||||
break;
|
||||
case AgentEventType.Decision:
|
||||
@@ -232,7 +270,7 @@ public partial class ChatWindow
|
||||
case AgentEventType.SkillCall:
|
||||
if (!isDebugLogLevel)
|
||||
break;
|
||||
SetStatus($"스킬 실행 중: {TruncateForStatus(evt.Summary)}", spinning: true);
|
||||
SetStatus($"스킬 실행 중 · {TruncateForStatus(evt.Summary)}", spinning: true);
|
||||
break;
|
||||
case AgentEventType.Complete:
|
||||
SetStatus("작업 완료", spinning: false);
|
||||
@@ -245,12 +283,12 @@ public partial class ChatWindow
|
||||
case AgentEventType.Paused:
|
||||
if (!isDebugLogLevel)
|
||||
break;
|
||||
SetStatus("⏸ 일시정지", spinning: false);
|
||||
SetStatus("일시정지", spinning: false);
|
||||
break;
|
||||
case AgentEventType.Resumed:
|
||||
if (!isDebugLogLevel)
|
||||
break;
|
||||
SetStatus("▶ 재개됨", spinning: true);
|
||||
SetStatus("재개", spinning: true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user