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:
@@ -2279,3 +2279,9 @@ MIT License
|
||||
- 검증:
|
||||
- `dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_ppt_quality_gate\\ -p:IntermediateOutputPath=obj\\verify_ppt_quality_gate\\` 경고 0 / 오류 0
|
||||
- `dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "PptxSkillTemplatePackTests|PptxSkillAutoRepairTests|PptxSkillGoldenDeckTests|PptQualityGatePolicyTests|PptxTemplateManifestCatalogTests" -p:OutputPath=bin\\verify_ppt_quality_gate_tests\\ -p:IntermediateOutputPath=obj\\verify_ppt_quality_gate_tests\\` 통과 12
|
||||
업데이트: 2026-04-15 22:18 (KST)
|
||||
- AX Agent V2 라이브 진행 카드에 항상 남아 있는 상태 본문을 추가했습니다. 실행 로그 카드만 쌓이고 상단 안내 문구가 비어 보이던 문제를 줄이기 위해 `src/AxCopilot/Views/ChatWindow.V2LiveProgressPresentation.cs`에서 고정 상태 카드와 상세/메타 텍스트를 함께 렌더링하도록 바꿨습니다.
|
||||
- 라이브 카드 시작 시에는 초기 내러티브를, 이벤트 수신 중에는 최신 상태 요약을 같은 카드에 계속 갱신해 툴 호출 사이 공백 구간에도 “현재 무엇을 하고 있는지” 문구가 남도록 조정했습니다.
|
||||
- 검증:
|
||||
- `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
|
||||
|
||||
@@ -1602,3 +1602,9 @@ UI ?遺우쁽????域뱀뮆???귐뗫솯?醫딆춦 ???袁る퓮 ?臾믩씜 ??疫
|
||||
- 검증:
|
||||
- `dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_ppt_quality_gate\\ -p:IntermediateOutputPath=obj\\verify_ppt_quality_gate\\` 경고 0 / 오류 0
|
||||
- `dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "PptxSkillTemplatePackTests|PptxSkillAutoRepairTests|PptxSkillGoldenDeckTests|PptQualityGatePolicyTests|PptxTemplateManifestCatalogTests" -p:OutputPath=bin\\verify_ppt_quality_gate_tests\\ -p:IntermediateOutputPath=obj\\verify_ppt_quality_gate_tests\\` 통과 12
|
||||
업데이트: 2026-04-15 22:18 (KST)
|
||||
- AX Agent V2 라이브 진행 카드의 상태 본문 지속성을 보강했습니다. `src/AxCopilot/Views/ChatWindow.V2LiveProgressPresentation.cs`에 고정 상태 카드(`_v2LiveStatusCard`)와 본문/상세/메타 텍스트를 추가해, 실행 로그 항목만 남고 상단 안내 문구가 사라진 것처럼 보이던 회귀를 줄였습니다.
|
||||
- 스트리밍 시작 시 `RefreshV2LiveStatusCard(runTab)`로 초기 상태를 먼저 채우고, 각 `AgentEvent` 처리 시 `UpdateV2LiveStatusCardFromEvent(...)`로 카드 내용을 갱신하도록 정리했습니다. 이제 툴 호출 카드가 접히거나 thinking 요약이 비어도 라이브 카드 상단 메시지는 유지됩니다.
|
||||
- 검증:
|
||||
- `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
|
||||
|
||||
@@ -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