AX Agent 라이브 진행 문구 지속 표시 회귀 수정
- V2 라이브 진행 카드에 고정 상태 본문/상세/메타 영역을 추가해 실행 로그만 남고 상단 메시지가 비어 보이던 문제를 줄임 - 스트리밍 시작 시 초기 내러티브를 채우고 각 AgentEvent 처리마다 상태 카드를 갱신하도록 정리함 - README.md와 docs/DEVELOPMENT.md에 2026-04-15 22:18 (KST) 기준 변경 이력과 검증 결과를 반영함 검증 결과 - dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\verify_live_message_persistence2\ -p:IntermediateOutputPath=obj\verify_live_message_persistence2\ : 경고 0 / 오류 0 - dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter ChatStreamingUiPolicyTests|ChatWindowSlashPolicyTests -p:OutputPath=bin\verify_live_message_persistence_tests\ -p:IntermediateOutputPath=obj\verify_live_message_persistence_tests\ : 통과 69 - dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\verify_live_message_persistence3\ -p:IntermediateOutputPath=obj\verify_live_message_persistence3\ : 경고 0 / 오류 0
This commit is contained in:
@@ -15,6 +15,10 @@ public partial class ChatWindow
|
||||
private DispatcherTimer? _v2LiveElapsedTimer;
|
||||
private DateTime _v2LiveStartTime;
|
||||
private TextBlock? _v2LiveElapsedText;
|
||||
private Border? _v2LiveStatusCard;
|
||||
private TextBlock? _v2LiveStatusText;
|
||||
private TextBlock? _v2LiveStatusDetailText;
|
||||
private TextBlock? _v2LiveStatusMetaText;
|
||||
|
||||
/// <summary>V2: 스트리밍 시작 시 라이브 진행 컨테이너 생성</summary>
|
||||
private void ShowAgentLiveCardV2(string runTab)
|
||||
@@ -29,7 +33,10 @@ public partial class ChatWindow
|
||||
_v2LastLiveToolCallId = null;
|
||||
|
||||
var msgMaxWidth = GetMessageMaxWidth();
|
||||
var accentBrush = TryFindResource("AccentColor") as Brush ?? Brushes.CornflowerBlue;
|
||||
var accentColor = ResolveLiveProgressAccentColor(accentBrush);
|
||||
var secondaryText = TryFindResource("SecondaryText") as Brush ?? Brushes.Gray;
|
||||
var primaryText = TryFindResource("PrimaryText") as Brush ?? Brushes.White;
|
||||
|
||||
_v2LiveContainer = new StackPanel
|
||||
{
|
||||
@@ -87,6 +94,52 @@ public partial class ChatWindow
|
||||
|
||||
_v2LiveContainer.Children.Add(headerGrid);
|
||||
|
||||
_v2LiveStatusText = new TextBlock
|
||||
{
|
||||
FontSize = 14,
|
||||
FontWeight = FontWeights.SemiBold,
|
||||
Foreground = primaryText,
|
||||
TextWrapping = TextWrapping.Wrap,
|
||||
LineHeight = 20,
|
||||
};
|
||||
_v2LiveStatusDetailText = new TextBlock
|
||||
{
|
||||
FontSize = 11,
|
||||
Foreground = secondaryText,
|
||||
Opacity = 0.88,
|
||||
TextWrapping = TextWrapping.Wrap,
|
||||
LineHeight = 18,
|
||||
Margin = new Thickness(0, 4, 0, 0),
|
||||
};
|
||||
_v2LiveStatusMetaText = new TextBlock
|
||||
{
|
||||
FontSize = 10,
|
||||
Foreground = secondaryText,
|
||||
Opacity = 0.72,
|
||||
Margin = new Thickness(0, 8, 0, 0),
|
||||
};
|
||||
|
||||
_v2LiveStatusCard = new Border
|
||||
{
|
||||
Background = new SolidColorBrush(Color.FromArgb(0x12, accentColor.R, accentColor.G, accentColor.B)),
|
||||
BorderBrush = new SolidColorBrush(Color.FromArgb(0x36, accentColor.R, accentColor.G, accentColor.B)),
|
||||
BorderThickness = new Thickness(1),
|
||||
CornerRadius = new CornerRadius(12),
|
||||
Padding = new Thickness(14, 12, 14, 12),
|
||||
Margin = new Thickness(0, 4, 0, 6),
|
||||
Child = new StackPanel
|
||||
{
|
||||
Children =
|
||||
{
|
||||
_v2LiveStatusText,
|
||||
_v2LiveStatusDetailText,
|
||||
_v2LiveStatusMetaText,
|
||||
}
|
||||
}
|
||||
};
|
||||
_v2LiveContainer.Children.Add(_v2LiveStatusCard);
|
||||
RefreshV2LiveStatusCard(runTab);
|
||||
|
||||
AddTranscriptElement(_v2LiveContainer);
|
||||
ForceScrollToEnd();
|
||||
|
||||
@@ -108,6 +161,7 @@ public partial class ChatWindow
|
||||
var secondaryText = TryFindResource("SecondaryText") as Brush ?? Brushes.Gray;
|
||||
var primaryText = TryFindResource("PrimaryText") as Brush ?? Brushes.White;
|
||||
var msgMaxWidth = GetMessageMaxWidth();
|
||||
UpdateV2LiveStatusCardFromEvent(agentEvent);
|
||||
|
||||
switch (agentEvent.Type)
|
||||
{
|
||||
@@ -327,6 +381,10 @@ public partial class ChatWindow
|
||||
_v2LiveElapsedTimer?.Stop();
|
||||
_v2LiveElapsedTimer = null;
|
||||
_v2LiveElapsedText = null;
|
||||
_v2LiveStatusCard = null;
|
||||
_v2LiveStatusText = null;
|
||||
_v2LiveStatusDetailText = null;
|
||||
_v2LiveStatusMetaText = null;
|
||||
|
||||
if (_v2LiveContainer == null) return;
|
||||
|
||||
@@ -347,4 +405,62 @@ public partial class ChatWindow
|
||||
|
||||
RemoveTranscriptElement(toRemove);
|
||||
}
|
||||
|
||||
private void RefreshV2LiveStatusCard(string runTab)
|
||||
{
|
||||
if (_v2LiveStatusText == null)
|
||||
return;
|
||||
|
||||
var hint = GetLiveAgentProgressHint();
|
||||
if (hint != null)
|
||||
{
|
||||
var narrative = AgentStatusNarrativeCatalog.BuildFromEvent(hint, runTab);
|
||||
var hintSummary = string.IsNullOrWhiteSpace(hint.Summary)
|
||||
? narrative.Message
|
||||
: hint.Summary;
|
||||
UpdateV2LiveStatusCard(hintSummary, narrative.Detail, BuildReadableProgressMetaText(hint));
|
||||
return;
|
||||
}
|
||||
|
||||
var initial = AgentStatusNarrativeCatalog.BuildInitial(runTab);
|
||||
UpdateV2LiveStatusCard(initial.Message, initial.Detail, null);
|
||||
}
|
||||
|
||||
private void UpdateV2LiveStatusCardFromEvent(AgentEvent agentEvent)
|
||||
{
|
||||
if (_v2LiveStatusText == null)
|
||||
return;
|
||||
|
||||
var narrative = AgentStatusNarrativeCatalog.BuildFromEvent(agentEvent, _activeTab);
|
||||
var normalizedThinking = agentEvent.Type == AgentEventType.Thinking
|
||||
? AgentProgressSummarySanitizer.NormalizeThinkingSummary(
|
||||
agentEvent.Summary,
|
||||
agentEvent.ToolName,
|
||||
maxLength: 160)
|
||||
: string.Empty;
|
||||
var message = string.IsNullOrWhiteSpace(normalizedThinking)
|
||||
? narrative.Message
|
||||
: normalizedThinking;
|
||||
UpdateV2LiveStatusCard(message, narrative.Detail, BuildReadableProgressMetaText(agentEvent));
|
||||
}
|
||||
|
||||
private void UpdateV2LiveStatusCard(string message, string? detail, string? meta)
|
||||
{
|
||||
if (_v2LiveStatusText == null || _v2LiveStatusDetailText == null || _v2LiveStatusMetaText == null)
|
||||
return;
|
||||
|
||||
_v2LiveStatusText.Text = string.IsNullOrWhiteSpace(message)
|
||||
? "작업을 이어가고 있습니다..."
|
||||
: message;
|
||||
|
||||
_v2LiveStatusDetailText.Text = detail ?? string.Empty;
|
||||
_v2LiveStatusDetailText.Visibility = string.IsNullOrWhiteSpace(detail)
|
||||
? Visibility.Collapsed
|
||||
: Visibility.Visible;
|
||||
|
||||
_v2LiveStatusMetaText.Text = meta ?? string.Empty;
|
||||
_v2LiveStatusMetaText.Visibility = string.IsNullOrWhiteSpace(meta)
|
||||
? Visibility.Collapsed
|
||||
: Visibility.Visible;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user