코워크·코드 스트리밍 렌더 윈도우 축소 및 타이머 재예약 최적화
Some checks failed
Release Gate / gate (push) Has been cancelled

- claude-code의 virtualized message list 방향을 참고해 AX transcript에 실행 중 경량 렌더 윈도우를 도입함

- 코워크/코드 스트리밍 중 최근 항목 위주로 더 작은 타임라인만 렌더하도록 조정해 render 대상 수를 줄임

- execution history, agent UI event, task summary, input UI 타이머는 경량 라이브 진행 모드에서 이미 예약되어 있으면 다시 stop/start 하지 않도록 정리함

- README와 DEVELOPMENT 문서를 2026-04-08 12:33 (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:
2026-04-08 23:44:52 +09:00
parent 6bccc229b0
commit 117320af02
3 changed files with 42 additions and 1 deletions

View File

@@ -1507,3 +1507,7 @@ MIT License
- 코워크/코드 실행 중 보조 UI 갱신도 더 느슨하게 조정했습니다. [ChatWindow.xaml.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml.cs) 에서 `입력 보조 UI``작업 요약` 타이머도 경량 라이브 진행 모드일 때 더 긴 간격으로 동작하도록 바꿨습니다. - 코워크/코드 실행 중 보조 UI 갱신도 더 느슨하게 조정했습니다. [ChatWindow.xaml.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml.cs) 에서 `입력 보조 UI``작업 요약` 타이머도 경량 라이브 진행 모드일 때 더 긴 간격으로 동작하도록 바꿨습니다.
- 경량 모드에서는 `Thinking`, `ToolCall` 같은 잦은 이벤트마다 `작업 요약` 갱신을 다시 예약하지 않고, `계획`, `권한 요청`, `도구 결과`, `완료/오류`처럼 실제로 요약 상태가 달라지는 이벤트 중심으로만 요약 UI를 갱신하도록 정리했습니다. - 경량 모드에서는 `Thinking`, `ToolCall` 같은 잦은 이벤트마다 `작업 요약` 갱신을 다시 예약하지 않고, `계획`, `권한 요청`, `도구 결과`, `완료/오류`처럼 실제로 요약 상태가 달라지는 이벤트 중심으로만 요약 UI를 갱신하도록 정리했습니다.
- 결과적으로 코워크/코드 처리 중 transcript 외의 보조 UI 측정/배치 비용도 함께 줄어, 입력 지연과 스크롤 버벅임 완화에 직접적으로 기여하도록 조정했습니다. - 결과적으로 코워크/코드 처리 중 transcript 외의 보조 UI 측정/배치 비용도 함께 줄어, 입력 지연과 스크롤 버벅임 완화에 직접적으로 기여하도록 조정했습니다.
- 업데이트: 2026-04-08 12:33 (KST)
- `claw-code`의 가상화 메시지 리스트에 바로 가기 전 단계로, AX transcript에 `실행 중 렌더 윈도우 축소`를 적용했습니다. 코워크/코드 스트리밍 중에는 최근 항목 위주로 더 작은 타임라인만 렌더하고, 평상시에는 기존 범위를 유지합니다.
- [ChatWindow.xaml.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml.cs)에 `GetActiveTimelineRenderLimit()`를 추가해, 일반 스트리밍은 96개, 경량 라이브 진행 모드는 60개만 렌더하도록 조정했습니다.
- `ScheduleExecutionHistoryRender`, `ScheduleAgentUiEvent`, `ScheduleTaskSummaryRefresh`, `ScheduleInputUiRefresh`도 경량 모드에서는 이미 타이머가 대기 중일 때 다시 stop/start 하지 않게 바꿔, 이벤트 폭주 시 dispatcher 예약 churn을 줄였습니다.

View File

@@ -5454,3 +5454,14 @@ ow + toggle ?쒓컖 ?몄뼱濡??ㅼ떆 ?뺣젹?덈떎.
- transcript 외 보조 UI 재측정/재배치 비용 감소 - transcript 외 보조 UI 재측정/재배치 비용 감소
- 코워크/코드 실행 중 입력 지연과 스크롤 끊김 완화 - 코워크/코드 실행 중 입력 지연과 스크롤 끊김 완화
- 라이브 진행 카드와 상태바는 유지하되, 그 외 UI는 더 느슨하게 갱신 - 라이브 진행 카드와 상태바는 유지하되, 그 외 UI는 더 느슨하게 갱신
## 2026-04-08 12:33 (KST)
- [ChatWindow.xaml.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml.cs)
- `TimelineStreamingRenderLimit = 96`, `TimelineLightweightStreamingRenderLimit = 60`을 추가하고 `GetActiveTimelineRenderLimit()`로 스트리밍 중 실제 렌더 윈도우를 줄이도록 했다.
- `RenderMessages()`는 이제 스트리밍 중 전체 타임라인이 아니라 최근 항목 중심의 더 작은 윈도우를 기준으로 hidden/visible 범위를 계산한다.
- `ScheduleExecutionHistoryRender`, `ScheduleAgentUiEvent`, `ScheduleTaskSummaryRefresh`, `ScheduleInputUiRefresh`는 경량 라이브 진행 모드에서 이미 타이머가 예약돼 있으면 다시 `Stop/Start` 하지 않도록 변경했다.
- 기대 효과
- 코워크/코드 실행 중 transcript 재구성 대상 수 자체 감소
- 高频 이벤트 환경에서 dispatcher timer 재예약 churn 감소
- `claw-code`의 virtualized list 이전 단계로서 실행 중 체감 부하를 더 낮춤

View File

@@ -2280,9 +2280,22 @@ public partial class ChatWindow : Window
// ─── 메시지 렌더링 ─────────────────────────────────────────────────── // ─── 메시지 렌더링 ───────────────────────────────────────────────────
private const int TimelineRenderPageSize = 180; private const int TimelineRenderPageSize = 180;
private const int TimelineStreamingRenderLimit = 96;
private const int TimelineLightweightStreamingRenderLimit = 60;
private string? _lastRenderedConversationId; private string? _lastRenderedConversationId;
private int _timelineRenderLimit = TimelineRenderPageSize; private int _timelineRenderLimit = TimelineRenderPageSize;
private int GetActiveTimelineRenderLimit()
{
if (!_isStreaming)
return _timelineRenderLimit;
var streamingLimit = IsLightweightLiveProgressMode()
? TimelineLightweightStreamingRenderLimit
: TimelineStreamingRenderLimit;
return Math.Min(_timelineRenderLimit, streamingLimit);
}
private void RenderMessages(bool preserveViewport = false) private void RenderMessages(bool preserveViewport = false)
{ {
var previousScrollableHeight = MessageScroll?.ScrollableHeight ?? 0; var previousScrollableHeight = MessageScroll?.ScrollableHeight ?? 0;
@@ -2330,7 +2343,8 @@ public partial class ChatWindow : Window
EmptyState.Visibility = Visibility.Collapsed; EmptyState.Visibility = Visibility.Collapsed;
var orderedTimeline = BuildTimelineRenderActions(visibleMessages, visibleEvents); var orderedTimeline = BuildTimelineRenderActions(visibleMessages, visibleEvents);
var hiddenCount = Math.Max(0, orderedTimeline.Count - _timelineRenderLimit); var effectiveRenderLimit = GetActiveTimelineRenderLimit();
var hiddenCount = Math.Max(0, orderedTimeline.Count - effectiveRenderLimit);
var visibleTimeline = hiddenCount > 0 var visibleTimeline = hiddenCount > 0
? orderedTimeline.GetRange(hiddenCount, orderedTimeline.Count - hiddenCount) ? orderedTimeline.GetRange(hiddenCount, orderedTimeline.Count - hiddenCount)
: orderedTimeline; : orderedTimeline;
@@ -2962,6 +2976,9 @@ public partial class ChatWindow : Window
return; return;
} }
if (IsLightweightLiveProgressMode() && _inputUiRefreshTimer.IsEnabled)
return;
_inputUiRefreshTimer.Stop(); _inputUiRefreshTimer.Stop();
_inputUiRefreshTimer.Start(); _inputUiRefreshTimer.Start();
} }
@@ -6066,6 +6083,9 @@ public partial class ChatWindow : Window
_pendingHiddenExecutionHistoryRender = true; _pendingHiddenExecutionHistoryRender = true;
return; return;
} }
if (IsLightweightLiveProgressMode() && _executionHistoryRenderTimer.IsEnabled)
return;
_executionHistoryRenderTimer.Stop(); _executionHistoryRenderTimer.Stop();
_executionHistoryRenderTimer.Start(); _executionHistoryRenderTimer.Start();
} }
@@ -6112,6 +6132,9 @@ public partial class ChatWindow : Window
return; return;
} }
if (IsLightweightLiveProgressMode() && _taskSummaryRefreshTimer.IsEnabled)
return;
_taskSummaryRefreshTimer.Stop(); _taskSummaryRefreshTimer.Stop();
_taskSummaryRefreshTimer.Start(); _taskSummaryRefreshTimer.Start();
} }
@@ -6135,6 +6158,9 @@ public partial class ChatWindow : Window
return; return;
} }
if (IsLightweightLiveProgressMode() && _agentUiEventTimer.IsEnabled)
return;
_agentUiEventTimer.Stop(); _agentUiEventTimer.Stop();
_agentUiEventTimer.Start(); _agentUiEventTimer.Start();
} }