AX Agent timeline 조립 helper를 분리해 메시지 렌더 구조를 단순화한다
Some checks failed
Release Gate / gate (push) Has been cancelled
Some checks failed
Release Gate / gate (push) Has been cancelled
RenderMessages()가 직접 처리하던 visible 메시지/이벤트 필터링과 timestamp/order 기반 timeline action 조립을 ChatWindow.TimelinePresentation.cs로 이동해 메인 렌더 루프가 orchestration 중심으로 더 단순해지도록 정리했다. README와 DEVELOPMENT 문서에 2026-04-06 10:36 (KST) 기준 이력을 반영했고, dotnet build 검증 결과 경고 0 / 오류 0을 확인했다.
This commit is contained in:
@@ -1184,3 +1184,5 @@ MIT License
|
|||||||
- 좌측 대화 목록 렌더를 [ChatWindow.ConversationListPresentation.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.ConversationListPresentation.cs) 로 분리했다. `RefreshConversationList`, `RenderConversationList`, `AddLoadMoreButton`, `BuildConversationSpotlightItems`, `AddGroupHeader`, `AddConversationItem`이 메인 [ChatWindow.xaml.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml.cs) 밖으로 이동해, 메인 창은 transcript/runtime orchestration에 더 집중하고 목록 UI는 별도 presentation surface에서 관리되게 정리했다.
|
- 좌측 대화 목록 렌더를 [ChatWindow.ConversationListPresentation.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.ConversationListPresentation.cs) 로 분리했다. `RefreshConversationList`, `RenderConversationList`, `AddLoadMoreButton`, `BuildConversationSpotlightItems`, `AddGroupHeader`, `AddConversationItem`이 메인 [ChatWindow.xaml.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml.cs) 밖으로 이동해, 메인 창은 transcript/runtime orchestration에 더 집중하고 목록 UI는 별도 presentation surface에서 관리되게 정리했다.
|
||||||
- 업데이트: 2026-04-06 10:27 (KST)
|
- 업데이트: 2026-04-06 10:27 (KST)
|
||||||
- transcript 메시지 row 조립을 [ChatWindow.MessageBubblePresentation.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.MessageBubblePresentation.cs) 로 분리했다. `AddMessageBubble(...)`가 메인 [ChatWindow.xaml.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml.cs) 밖으로 이동해, 사용자/assistant bubble, 분기 컨텍스트 카드, 액션 바와 메타 row 조립이 별도 presentation surface에서 관리되게 정리했다.
|
- transcript 메시지 row 조립을 [ChatWindow.MessageBubblePresentation.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.MessageBubblePresentation.cs) 로 분리했다. `AddMessageBubble(...)`가 메인 [ChatWindow.xaml.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml.cs) 밖으로 이동해, 사용자/assistant bubble, 분기 컨텍스트 카드, 액션 바와 메타 row 조립이 별도 presentation surface에서 관리되게 정리했다.
|
||||||
|
- 업데이트: 2026-04-06 10:36 (KST)
|
||||||
|
- timeline 조립 helper를 [ChatWindow.TimelinePresentation.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.TimelinePresentation.cs) 로 분리했다. `RenderMessages()`가 직접 처리하던 visible 메시지 필터링, execution event 노출 집계, timestamp/order 기반 timeline action 조립을 helper 메서드로 옮겨 메인 렌더 루프를 더 단순화했다.
|
||||||
|
|||||||
@@ -4925,3 +4925,5 @@ ow + toggle ?쒓컖 ?몄뼱濡??ㅼ떆 ?뺣젹?덈떎.
|
|||||||
- Document update: 2026-04-06 10:18 (KST) - This keeps the main chat window more focused on transcript/runtime orchestration while isolating sidebar list presentation for future UX tuning and parity work.
|
- Document update: 2026-04-06 10:18 (KST) - This keeps the main chat window more focused on transcript/runtime orchestration while isolating sidebar list presentation for future UX tuning and parity work.
|
||||||
- Document update: 2026-04-06 10:27 (KST) - Split transcript message-row assembly out of `ChatWindow.xaml.cs` into `ChatWindow.MessageBubblePresentation.cs`. The shared `AddMessageBubble(...)` path for user/assistant bubbles, branch-context cards, inline action bars, and assistant meta rows now lives in a dedicated presentation partial.
|
- Document update: 2026-04-06 10:27 (KST) - Split transcript message-row assembly out of `ChatWindow.xaml.cs` into `ChatWindow.MessageBubblePresentation.cs`. The shared `AddMessageBubble(...)` path for user/assistant bubbles, branch-context cards, inline action bars, and assistant meta rows now lives in a dedicated presentation partial.
|
||||||
- Document update: 2026-04-06 10:27 (KST) - This keeps the main chat window more orchestration-focused while making transcript row rendering easier to tune and extend independently.
|
- Document update: 2026-04-06 10:27 (KST) - This keeps the main chat window more orchestration-focused while making transcript row rendering easier to tune and extend independently.
|
||||||
|
- Document update: 2026-04-06 10:36 (KST) - Split timeline visibility filtering and render-action assembly out of `RenderMessages()` into `ChatWindow.TimelinePresentation.cs`. Visible message/event selection and timestamp-ordered timeline action construction now live in dedicated helpers.
|
||||||
|
- Document update: 2026-04-06 10:36 (KST) - This keeps `RenderMessages()` closer to a simple orchestration loop and reduces mixed responsibilities inside the main chat window file.
|
||||||
|
|||||||
52
src/AxCopilot/Views/ChatWindow.TimelinePresentation.cs
Normal file
52
src/AxCopilot/Views/ChatWindow.TimelinePresentation.cs
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using AxCopilot.Models;
|
||||||
|
|
||||||
|
namespace AxCopilot.Views;
|
||||||
|
|
||||||
|
public partial class ChatWindow
|
||||||
|
{
|
||||||
|
private List<ChatMessage> GetVisibleTimelineMessages(ChatConversation? conversation)
|
||||||
|
{
|
||||||
|
return conversation?.Messages?.Where(msg =>
|
||||||
|
{
|
||||||
|
if (string.Equals(msg.Role, "system", StringComparison.OrdinalIgnoreCase))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (string.Equals(msg.Role, "assistant", StringComparison.OrdinalIgnoreCase)
|
||||||
|
&& string.IsNullOrWhiteSpace(msg.Content))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}).ToList() ?? new List<ChatMessage>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<ChatExecutionEvent> GetVisibleTimelineEvents(ChatConversation? conversation)
|
||||||
|
{
|
||||||
|
return (conversation?.ShowExecutionHistory ?? true)
|
||||||
|
? conversation?.ExecutionEvents?.ToList() ?? new List<ChatExecutionEvent>()
|
||||||
|
: new List<ChatExecutionEvent>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<(DateTime Timestamp, int Order, Action Render)> BuildTimelineRenderActions(
|
||||||
|
IReadOnlyCollection<ChatMessage> visibleMessages,
|
||||||
|
IReadOnlyCollection<ChatExecutionEvent> visibleEvents)
|
||||||
|
{
|
||||||
|
var timeline = new List<(DateTime Timestamp, int Order, Action Render)>(visibleMessages.Count + visibleEvents.Count);
|
||||||
|
|
||||||
|
foreach (var msg in visibleMessages)
|
||||||
|
timeline.Add((msg.Timestamp, 0, () => AddMessageBubble(msg.Role, msg.Content, animate: false, message: msg)));
|
||||||
|
|
||||||
|
foreach (var executionEvent in visibleEvents)
|
||||||
|
{
|
||||||
|
var restoredEvent = ToAgentEvent(executionEvent);
|
||||||
|
timeline.Add((executionEvent.Timestamp, 1, () => AddAgentEventBanner(restoredEvent)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return timeline
|
||||||
|
.OrderBy(x => x.Timestamp)
|
||||||
|
.ThenBy(x => x.Order)
|
||||||
|
.ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2723,20 +2723,8 @@ public partial class ChatWindow : Window
|
|||||||
lock (_convLock) conv = _currentConversation;
|
lock (_convLock) conv = _currentConversation;
|
||||||
_appState.RestoreAgentRunHistory(conv?.AgentRunHistory);
|
_appState.RestoreAgentRunHistory(conv?.AgentRunHistory);
|
||||||
|
|
||||||
var visibleMessages = conv?.Messages?.Where(msg =>
|
var visibleMessages = GetVisibleTimelineMessages(conv);
|
||||||
{
|
var visibleEvents = GetVisibleTimelineEvents(conv);
|
||||||
if (string.Equals(msg.Role, "system", StringComparison.OrdinalIgnoreCase))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (string.Equals(msg.Role, "assistant", StringComparison.OrdinalIgnoreCase)
|
|
||||||
&& string.IsNullOrWhiteSpace(msg.Content))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}).ToList() ?? new List<ChatMessage>();
|
|
||||||
var visibleEvents = (conv?.ShowExecutionHistory ?? true)
|
|
||||||
? conv?.ExecutionEvents?.ToList() ?? new List<ChatExecutionEvent>()
|
|
||||||
: new List<ChatExecutionEvent>();
|
|
||||||
|
|
||||||
if (conv == null || (visibleMessages.Count == 0 && visibleEvents.Count == 0))
|
if (conv == null || (visibleMessages.Count == 0 && visibleEvents.Count == 0))
|
||||||
{
|
{
|
||||||
@@ -2752,17 +2740,7 @@ public partial class ChatWindow : Window
|
|||||||
|
|
||||||
EmptyState.Visibility = Visibility.Collapsed;
|
EmptyState.Visibility = Visibility.Collapsed;
|
||||||
|
|
||||||
var timeline = new List<(DateTime Timestamp, int Order, Action Render)>();
|
var orderedTimeline = BuildTimelineRenderActions(visibleMessages, visibleEvents);
|
||||||
foreach (var msg in visibleMessages)
|
|
||||||
timeline.Add((msg.Timestamp, 0, () => AddMessageBubble(msg.Role, msg.Content, animate: false, message: msg)));
|
|
||||||
|
|
||||||
foreach (var executionEvent in visibleEvents)
|
|
||||||
{
|
|
||||||
var restoredEvent = ToAgentEvent(executionEvent);
|
|
||||||
timeline.Add((executionEvent.Timestamp, 1, () => AddAgentEventBanner(restoredEvent)));
|
|
||||||
}
|
|
||||||
|
|
||||||
var orderedTimeline = timeline.OrderBy(x => x.Timestamp).ThenBy(x => x.Order).ToList();
|
|
||||||
var hiddenCount = Math.Max(0, orderedTimeline.Count - _timelineRenderLimit);
|
var hiddenCount = Math.Max(0, orderedTimeline.Count - _timelineRenderLimit);
|
||||||
if (hiddenCount > 0)
|
if (hiddenCount > 0)
|
||||||
MessagePanel.Children.Add(CreateTimelineLoadMoreCard(hiddenCount));
|
MessagePanel.Children.Add(CreateTimelineLoadMoreCard(hiddenCount));
|
||||||
|
|||||||
Reference in New Issue
Block a user