AX Agent 실행 이벤트 UI 갱신을 배치형으로 조정해 Cowork·Code 흔들림을 줄임
Some checks failed
Release Gate / gate (push) Has been cancelled
Some checks failed
Release Gate / gate (push) Has been cancelled
- ChatWindow에 agent UI event timer를 추가해 상태바, 진행률, 플랜 뷰어, 자동 프리뷰를 최근 이벤트 기준으로 묶어서 반영 - OnAgentEvent는 실행 상태를 먼저 conversation/app state에 반영하고 화면 갱신은 FlushPendingAgentUiEvent 경로로 분리 - README와 DEVELOPMENT 문서에 2026-04-05 13:29 (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:
@@ -86,6 +86,7 @@ public partial class ChatWindow : Window
|
||||
private readonly DispatcherTimer _executionHistoryRenderTimer;
|
||||
private readonly DispatcherTimer _taskSummaryRefreshTimer;
|
||||
private readonly DispatcherTimer _conversationPersistTimer;
|
||||
private readonly DispatcherTimer _agentUiEventTimer;
|
||||
private CancellationTokenSource? _gitStatusRefreshCts;
|
||||
private int _displayedLength; // 현재 화면에 표시된 글자 수
|
||||
private ResourceDictionary? _agentThemeDictionary;
|
||||
@@ -122,6 +123,7 @@ public partial class ChatWindow : Window
|
||||
private bool _pendingExecutionHistoryAutoScroll;
|
||||
private readonly Dictionary<string, ChatConversation> _pendingConversationPersists = new(StringComparer.OrdinalIgnoreCase);
|
||||
private readonly HashSet<string> _expandedDraftQueueTabs = new(StringComparer.OrdinalIgnoreCase);
|
||||
private AgentEvent? _pendingAgentUiEvent;
|
||||
private void ApplyQuickActionVisual(Button button, bool active, string activeBg, string activeFg)
|
||||
{
|
||||
if (button?.Content is not string text)
|
||||
@@ -260,6 +262,12 @@ public partial class ChatWindow : Window
|
||||
_conversationPersistTimer.Stop();
|
||||
FlushPendingConversationPersists();
|
||||
};
|
||||
_agentUiEventTimer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(90) };
|
||||
_agentUiEventTimer.Tick += (_, _) =>
|
||||
{
|
||||
_agentUiEventTimer.Stop();
|
||||
FlushPendingAgentUiEvent();
|
||||
};
|
||||
|
||||
KeyDown += ChatWindow_KeyDown;
|
||||
UpdateConversationFailureFilterUi();
|
||||
@@ -8543,6 +8551,7 @@ public partial class ChatWindow : Window
|
||||
private void ResetStreamingUiState()
|
||||
{
|
||||
FlushPendingConversationPersists();
|
||||
FlushPendingAgentUiEvent();
|
||||
_cursorTimer.Stop();
|
||||
_elapsedTimer.Stop();
|
||||
_typingTimer.Stop();
|
||||
@@ -8550,6 +8559,7 @@ public partial class ChatWindow : Window
|
||||
_pendingExecutionHistoryAutoScroll = false;
|
||||
_taskSummaryRefreshTimer.Stop();
|
||||
_conversationPersistTimer.Stop();
|
||||
_agentUiEventTimer.Stop();
|
||||
HideStickyProgress();
|
||||
StopRainbowGlow();
|
||||
_activeStreamText = null;
|
||||
@@ -8628,6 +8638,51 @@ public partial class ChatWindow : Window
|
||||
_conversationPersistTimer.Start();
|
||||
}
|
||||
|
||||
private void ScheduleAgentUiEvent(AgentEvent evt)
|
||||
{
|
||||
_pendingAgentUiEvent = evt;
|
||||
_agentUiEventTimer.Stop();
|
||||
_agentUiEventTimer.Start();
|
||||
}
|
||||
|
||||
private void FlushPendingAgentUiEvent()
|
||||
{
|
||||
var evt = _pendingAgentUiEvent;
|
||||
_pendingAgentUiEvent = null;
|
||||
if (evt == null)
|
||||
return;
|
||||
|
||||
UpdateStatusBar(evt);
|
||||
UpdateAgentProgressBar(evt);
|
||||
if (evt.StepCurrent > 0 && evt.StepTotal > 0)
|
||||
UpdatePlanViewerStep(evt);
|
||||
if (evt.Type == AgentEventType.Complete)
|
||||
CompletePlanViewer();
|
||||
|
||||
if (evt.Success && !string.IsNullOrEmpty(evt.FilePath))
|
||||
RefreshFileTreeIfVisible();
|
||||
|
||||
if (evt.Type == AgentEventType.ToolResult && evt.ToolName == "suggest_actions" && evt.Success)
|
||||
RenderSuggestActionChips(evt.Summary);
|
||||
|
||||
if (evt.Success && !string.IsNullOrEmpty(evt.FilePath) &&
|
||||
(evt.Type == AgentEventType.ToolResult || evt.Type == AgentEventType.Complete) &&
|
||||
WriteToolNames.Contains(evt.ToolName))
|
||||
{
|
||||
var autoPreview = _settings.Settings.Llm.AutoPreview;
|
||||
if (autoPreview == "auto")
|
||||
{
|
||||
if (PreviewWindow.IsOpen)
|
||||
PreviewWindow.RefreshIfOpen(evt.FilePath);
|
||||
else
|
||||
TryShowPreview(evt.FilePath);
|
||||
|
||||
if (!PreviewWindow.IsOpen)
|
||||
TryShowPreview(evt.FilePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void PersistConversationSnapshot(string rememberTab, ChatConversation conversation, string failureLabel)
|
||||
{
|
||||
if (conversation == null || string.IsNullOrWhiteSpace(conversation.Id))
|
||||
@@ -9063,8 +9118,6 @@ public partial class ChatWindow : Window
|
||||
&& string.Equals(eventTab, _activeTab, StringComparison.OrdinalIgnoreCase))
|
||||
ScheduleExecutionHistoryRender(autoScroll: true);
|
||||
|
||||
// 하단 상태바 업데이트
|
||||
UpdateStatusBar(evt);
|
||||
_appState.ApplyAgentEvent(evt);
|
||||
if (evt.Type == AgentEventType.Complete)
|
||||
AppendConversationAgentRun(evt, "completed", string.IsNullOrWhiteSpace(evt.Summary) ? "작업 완료" : evt.Summary, eventTab);
|
||||
@@ -9079,42 +9132,7 @@ public partial class ChatWindow : Window
|
||||
UpdateStatusTokens(_agentCumulativeInputTokens, _agentCumulativeOutputTokens);
|
||||
}
|
||||
|
||||
// 스티키 진행률 바 업데이트
|
||||
UpdateAgentProgressBar(evt);
|
||||
|
||||
// 계획 뷰어 단계 갱신
|
||||
if (evt.StepCurrent > 0 && evt.StepTotal > 0)
|
||||
UpdatePlanViewerStep(evt);
|
||||
if (evt.Type == AgentEventType.Complete)
|
||||
CompletePlanViewer();
|
||||
|
||||
// 파일 탐색기 자동 새로고침
|
||||
if (evt.Success && !string.IsNullOrEmpty(evt.FilePath))
|
||||
RefreshFileTreeIfVisible();
|
||||
|
||||
// suggest_actions 도구 결과 → 후속 작업 칩 표시
|
||||
if (evt.Type == AgentEventType.ToolResult && evt.ToolName == "suggest_actions" && evt.Success)
|
||||
RenderSuggestActionChips(evt.Summary);
|
||||
|
||||
// 파일 생성/수정 결과가 있으면 미리보기 자동 표시 또는 갱신
|
||||
if (evt.Success && !string.IsNullOrEmpty(evt.FilePath) &&
|
||||
(evt.Type == AgentEventType.ToolResult || evt.Type == AgentEventType.Complete) &&
|
||||
WriteToolNames.Contains(evt.ToolName))
|
||||
{
|
||||
var autoPreview = _settings.Settings.Llm.AutoPreview;
|
||||
if (autoPreview == "auto")
|
||||
{
|
||||
// 별도 창 미리보기: 이미 열린 파일이면 새로고침, 아니면 새 탭 추가
|
||||
if (PreviewWindow.IsOpen)
|
||||
PreviewWindow.RefreshIfOpen(evt.FilePath);
|
||||
else
|
||||
TryShowPreview(evt.FilePath);
|
||||
|
||||
// 새 파일이면 항상 표시
|
||||
if (!PreviewWindow.IsOpen)
|
||||
TryShowPreview(evt.FilePath);
|
||||
}
|
||||
}
|
||||
ScheduleAgentUiEvent(evt);
|
||||
|
||||
ScheduleTaskSummaryRefresh();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user