하단 토큰 집계와 압축 표시 정확도 수정
Some checks failed
Release Gate / gate (push) Has been cancelled

- 유휴 전환 후 하단 상태바 전체 토큰 집계가 사라지지 않도록 대화 기준 합산 복원 경로 추가
- 컨텍스트 사용량 팝업에 마지막 실제 압축 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:
2026-04-07 09:21:23 +09:00
parent b45ed524e1
commit f34878cbd5
6 changed files with 82 additions and 17 deletions

View File

@@ -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;
}
}