코워크/코드 실행 중 UI 렌더 부담 완화 및 claude-code 구조 비교 반영
Some checks failed
Release Gate / gate (push) Has been cancelled
Some checks failed
Release Gate / gate (push) Has been cancelled
- claude-code의 Messages, VirtualMessageList, StatusLine, StreamingToolExecutor 흐름을 다시 비교해 AX의 구조적 병목을 점검함 - Cowork/Code에서 실행 히스토리를 접어 둔 상태일 때 process feed 이벤트가 transcript 전체 재렌더를 자주 유발하던 경로를 줄임 - 경량 라이브 진행 모드를 도입해 라이브 카드와 상태 표시를 우선 사용하고 execution history render / agent UI event timer 간격을 더 느슨하게 조정함 - 완료/오류/문서 결과처럼 기록 가치가 큰 이벤트만 적극적으로 transcript 렌더를 요청하도록 정리함 - README와 DEVELOPMENT 문서를 2026-04-08 12:18 (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:
@@ -165,6 +165,20 @@ public partial class ChatWindow : Window
|
||||
private DateTime _lastAgentProgressEventAt = DateTime.UtcNow;
|
||||
private double _lastResponsiveComposerWidth;
|
||||
private double _lastResponsiveMessageWidth;
|
||||
private bool IsLightweightLiveProgressMode(string? runTab = null)
|
||||
{
|
||||
var tab = string.IsNullOrWhiteSpace(runTab) ? (_streamRunTab ?? _activeTab) : runTab!;
|
||||
if (!string.Equals(tab, "Cowork", StringComparison.OrdinalIgnoreCase)
|
||||
&& !string.Equals(tab, "Code", StringComparison.OrdinalIgnoreCase))
|
||||
return false;
|
||||
|
||||
ChatConversation? conversation;
|
||||
lock (_convLock)
|
||||
conversation = _currentConversation;
|
||||
|
||||
return !(conversation?.ShowExecutionHistory ?? true);
|
||||
}
|
||||
|
||||
private void ApplyQuickActionVisual(Button button, bool active, string activeBg, string activeFg)
|
||||
{
|
||||
if (button?.Content is not string text)
|
||||
@@ -255,7 +269,9 @@ public partial class ChatWindow : Window
|
||||
_executionHistoryRenderTimer.Stop();
|
||||
// 스트리밍 중에는 전체 재렌더링 빈도를 줄여 UI 부하 감소
|
||||
_executionHistoryRenderTimer.Interval = _isStreaming
|
||||
? TimeSpan.FromMilliseconds(1500)
|
||||
? (IsLightweightLiveProgressMode()
|
||||
? TimeSpan.FromMilliseconds(2200)
|
||||
: TimeSpan.FromMilliseconds(1500))
|
||||
: TimeSpan.FromMilliseconds(350);
|
||||
RenderMessages(preserveViewport: true);
|
||||
if (_pendingExecutionHistoryAutoScroll)
|
||||
@@ -282,7 +298,9 @@ public partial class ChatWindow : Window
|
||||
{
|
||||
_agentUiEventTimer.Stop();
|
||||
_agentUiEventTimer.Interval = _isStreaming
|
||||
? TimeSpan.FromMilliseconds(300)
|
||||
? (IsLightweightLiveProgressMode()
|
||||
? TimeSpan.FromMilliseconds(420)
|
||||
: TimeSpan.FromMilliseconds(300))
|
||||
: TimeSpan.FromMilliseconds(140);
|
||||
FlushPendingAgentUiEvent();
|
||||
};
|
||||
@@ -6819,8 +6837,16 @@ public partial class ChatWindow : Window
|
||||
// AppendConversationExecutionEvent, AppendConversationAgentRun, 디스크 저장은
|
||||
// 백그라운드 스레드에서 배치 처리됩니다. UI 렌더 갱신도 배치 완료 후 1회만 호출됩니다.
|
||||
var shouldShowExecutionHistory = _currentConversation?.ShowExecutionHistory ?? false;
|
||||
var shouldRender = (shouldShowExecutionHistory || ShouldRenderProgressEventWhenHistoryCollapsed(evt))
|
||||
&& string.Equals(eventTab, _activeTab, StringComparison.OrdinalIgnoreCase);
|
||||
var isActiveRunTab = string.Equals(eventTab, _activeTab, StringComparison.OrdinalIgnoreCase);
|
||||
var lightweightLiveMode = isActiveRunTab
|
||||
&& !shouldShowExecutionHistory
|
||||
&& IsLightweightLiveProgressMode(eventTab);
|
||||
var shouldRender = isActiveRunTab && (
|
||||
shouldShowExecutionHistory
|
||||
|| (!lightweightLiveMode && ShouldRenderProgressEventWhenHistoryCollapsed(evt))
|
||||
|| evt.Type == AgentEventType.Complete
|
||||
|| evt.Type == AgentEventType.Error
|
||||
|| (evt.Type == AgentEventType.ToolResult && evt.Success && IsDocumentCreationTool(evt.ToolName)));
|
||||
EnqueueAgentEventWork(evt, eventTab, shouldRender);
|
||||
|
||||
// ── 3단계: 경량 상태 추적 (UI 스레드) ───────────────────────────────
|
||||
@@ -7430,7 +7456,9 @@ public partial class ChatWindow : Window
|
||||
};
|
||||
|
||||
var runTab = string.IsNullOrWhiteSpace(_streamRunTab) ? _activeTab : _streamRunTab!;
|
||||
if (MessagePanel != null && string.Equals(runTab, _activeTab, StringComparison.OrdinalIgnoreCase))
|
||||
if (MessagePanel != null
|
||||
&& string.Equals(runTab, _activeTab, StringComparison.OrdinalIgnoreCase)
|
||||
&& !IsLightweightLiveProgressMode(runTab))
|
||||
ScheduleExecutionHistoryRender(autoScroll: false);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user