AX Agent 중간 처리 메시지를 Claude Code 스타일에 가깝게 정리
Some checks failed
Release Gate / gate (push) Has been cancelled
Some checks failed
Release Gate / gate (push) Has been cancelled
- 진행 중 이벤트(Planning, StepStart, StepDone, Thinking, ToolCall, SkillCall)를 작은 상태 칩 대신 요약줄+본문 설명 구조로 재구성했습니다. - claw-code의 AssistantToolUseMessage/HookProgressMessage 흐름을 참고해 중간 처리 과정이 hover 없이도 transcript 안에서 읽히도록 조정했습니다. - 권한 요청 및 결과 카드는 기존 richer card 구조를 유지하고, process feed 이벤트만 별도 경량 표현으로 분리했습니다. - README와 DEVELOPMENT 문서에 2026-04-06 22:31 (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:
@@ -14,12 +14,12 @@ public partial class ChatWindow
|
||||
{
|
||||
return new Border
|
||||
{
|
||||
Background = hintBg,
|
||||
BorderBrush = borderBrush,
|
||||
BorderThickness = new Thickness(1),
|
||||
CornerRadius = new CornerRadius(999),
|
||||
Padding = new Thickness(8, 4, 8, 4),
|
||||
Margin = new Thickness(8, 3, 180, 3),
|
||||
Background = Brushes.Transparent,
|
||||
BorderBrush = Brushes.Transparent,
|
||||
BorderThickness = new Thickness(0),
|
||||
CornerRadius = new CornerRadius(0),
|
||||
Padding = new Thickness(0),
|
||||
Margin = new Thickness(12, 4, 12, 2),
|
||||
HorizontalAlignment = HorizontalAlignment.Left,
|
||||
Child = new StackPanel
|
||||
{
|
||||
@@ -28,26 +28,144 @@ public partial class ChatWindow
|
||||
{
|
||||
new TextBlock
|
||||
{
|
||||
Text = "\uE9CE",
|
||||
FontFamily = new FontFamily("Segoe MDL2 Assets"),
|
||||
FontSize = 9.5,
|
||||
Foreground = accentBrush,
|
||||
Text = "›",
|
||||
FontSize = 12,
|
||||
Foreground = secondaryText,
|
||||
VerticalAlignment = VerticalAlignment.Center,
|
||||
Margin = new Thickness(0, 0, 6, 0),
|
||||
},
|
||||
new TextBlock
|
||||
{
|
||||
Text = summary,
|
||||
FontSize = 9.5,
|
||||
FontWeight = FontWeights.Medium,
|
||||
Foreground = primaryText,
|
||||
Margin = new Thickness(5, 0, 0, 0),
|
||||
FontSize = 11,
|
||||
FontWeight = FontWeights.Normal,
|
||||
Foreground = secondaryText,
|
||||
VerticalAlignment = VerticalAlignment.Center,
|
||||
TextWrapping = TextWrapping.Wrap,
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private Border CreateProcessFeedBody(string text, Brush primaryText)
|
||||
{
|
||||
return new Border
|
||||
{
|
||||
Background = Brushes.Transparent,
|
||||
BorderBrush = Brushes.Transparent,
|
||||
BorderThickness = new Thickness(0),
|
||||
Padding = new Thickness(0),
|
||||
Margin = new Thickness(26, 3, 12, 8),
|
||||
Child = new TextBlock
|
||||
{
|
||||
Text = text,
|
||||
FontSize = 13.5,
|
||||
FontWeight = FontWeights.Medium,
|
||||
Foreground = primaryText,
|
||||
TextWrapping = TextWrapping.Wrap,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static bool IsProcessFeedEvent(AgentEvent evt)
|
||||
{
|
||||
return evt.Type is AgentEventType.Planning
|
||||
or AgentEventType.StepStart
|
||||
or AgentEventType.StepDone
|
||||
or AgentEventType.Thinking
|
||||
or AgentEventType.ToolCall
|
||||
or AgentEventType.SkillCall;
|
||||
}
|
||||
|
||||
private static string BuildProcessFeedSummary(AgentEvent evt, string transcriptBadgeLabel, string itemDisplayName)
|
||||
{
|
||||
return evt.Type switch
|
||||
{
|
||||
AgentEventType.Planning when evt.Steps is { Count: > 0 }
|
||||
=> $"{evt.Steps.Count}단계 계획 정리",
|
||||
AgentEventType.StepStart when evt.StepTotal > 0
|
||||
=> $"{evt.StepCurrent}/{evt.StepTotal} 단계 진행",
|
||||
AgentEventType.StepDone when evt.StepTotal > 0
|
||||
=> $"{evt.StepCurrent}/{evt.StepTotal} 단계 완료",
|
||||
AgentEventType.Thinking when !string.IsNullOrWhiteSpace(evt.Summary)
|
||||
=> evt.Summary,
|
||||
AgentEventType.ToolCall
|
||||
=> string.IsNullOrWhiteSpace(itemDisplayName)
|
||||
? $"{transcriptBadgeLabel} 실행"
|
||||
: $"{itemDisplayName} 실행",
|
||||
AgentEventType.SkillCall
|
||||
=> string.IsNullOrWhiteSpace(itemDisplayName)
|
||||
? "스킬 실행"
|
||||
: $"{itemDisplayName} 실행",
|
||||
_ => string.IsNullOrWhiteSpace(evt.Summary) ? transcriptBadgeLabel : evt.Summary,
|
||||
};
|
||||
}
|
||||
|
||||
private void AddProcessFeedMessage(AgentEvent evt, string transcriptBadgeLabel, string itemDisplayName, string? eventSummaryText)
|
||||
{
|
||||
var primaryText = TryFindResource("PrimaryText") as Brush ?? Brushes.Black;
|
||||
var secondaryText = TryFindResource("SecondaryText") as Brush ?? Brushes.DimGray;
|
||||
var hintBg = TryFindResource("HintBackground") as Brush
|
||||
?? new SolidColorBrush(Color.FromArgb(0x18, 0xFF, 0xFF, 0xFF));
|
||||
var borderBrush = TryFindResource("BorderColor") as Brush ?? Brushes.Gray;
|
||||
var accentBrush = TryFindResource("AccentColor") as Brush ?? Brushes.CornflowerBlue;
|
||||
|
||||
var summary = BuildProcessFeedSummary(evt, transcriptBadgeLabel, itemDisplayName).Trim();
|
||||
if (string.IsNullOrWhiteSpace(summary))
|
||||
summary = transcriptBadgeLabel;
|
||||
|
||||
var stack = new StackPanel
|
||||
{
|
||||
Margin = new Thickness(0),
|
||||
};
|
||||
|
||||
var summaryRow = CreateCompactEventPill(summary, primaryText, secondaryText, hintBg, borderBrush, accentBrush);
|
||||
summaryRow.Opacity = 0;
|
||||
summaryRow.BeginAnimation(UIElement.OpacityProperty, new DoubleAnimation(0, 1, TimeSpan.FromMilliseconds(140)));
|
||||
stack.Children.Add(summaryRow);
|
||||
|
||||
var body = (eventSummaryText ?? string.Empty).Trim();
|
||||
if (!string.IsNullOrWhiteSpace(body)
|
||||
&& !string.Equals(body, summary, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var bodyBlock = CreateProcessFeedBody(body, primaryText);
|
||||
bodyBlock.Opacity = 0;
|
||||
bodyBlock.BeginAnimation(UIElement.OpacityProperty, new DoubleAnimation(0, 1, TimeSpan.FromMilliseconds(180)));
|
||||
stack.Children.Add(bodyBlock);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(evt.FilePath))
|
||||
{
|
||||
var compactPathRow = new StackPanel
|
||||
{
|
||||
Orientation = Orientation.Horizontal,
|
||||
Margin = new Thickness(26, 0, 12, 8),
|
||||
ToolTip = evt.FilePath,
|
||||
};
|
||||
compactPathRow.Children.Add(new TextBlock
|
||||
{
|
||||
Text = "\uE8B7",
|
||||
FontFamily = new FontFamily("Segoe MDL2 Assets"),
|
||||
FontSize = 9,
|
||||
Foreground = secondaryText,
|
||||
VerticalAlignment = VerticalAlignment.Center,
|
||||
Margin = new Thickness(0, 0, 4, 0),
|
||||
});
|
||||
compactPathRow.Children.Add(new TextBlock
|
||||
{
|
||||
Text = System.IO.Path.GetFileName(evt.FilePath),
|
||||
FontSize = 10.5,
|
||||
Foreground = secondaryText,
|
||||
VerticalAlignment = VerticalAlignment.Center,
|
||||
TextTrimming = TextTrimming.CharacterEllipsis,
|
||||
});
|
||||
stack.Children.Add(compactPathRow);
|
||||
}
|
||||
|
||||
MessagePanel.Children.Add(stack);
|
||||
}
|
||||
|
||||
private Border CreateAgentMetaChip(string text, string icon, Brush foreground, Brush background, Brush borderBrush)
|
||||
{
|
||||
return new Border
|
||||
@@ -422,59 +540,6 @@ public partial class ChatWindow
|
||||
{
|
||||
var logLevel = _settings.Settings.Llm.AgentLogLevel;
|
||||
|
||||
if (evt.Type == AgentEventType.Planning && evt.Steps is { Count: > 0 })
|
||||
{
|
||||
var compactPrimaryText = TryFindResource("PrimaryText") as Brush ?? Brushes.White;
|
||||
var compactSecondaryText = TryFindResource("SecondaryText") as Brush ?? Brushes.Gray;
|
||||
var compactHintBg = TryFindResource("HintBackground") as Brush
|
||||
?? new SolidColorBrush(Color.FromArgb(0x18, 0xFF, 0xFF, 0xFF));
|
||||
var compactBorderBrush = TryFindResource("BorderColor") as Brush ?? Brushes.Gray;
|
||||
var compactAccentBrush = TryFindResource("AccentColor") as Brush ?? Brushes.CornflowerBlue;
|
||||
var summary = !string.IsNullOrWhiteSpace(evt.Summary)
|
||||
? evt.Summary!
|
||||
: $"계획 {evt.Steps.Count}단계";
|
||||
var pill = CreateCompactEventPill(summary, compactPrimaryText, compactSecondaryText, compactHintBg, compactBorderBrush, compactAccentBrush);
|
||||
pill.Opacity = 0;
|
||||
pill.BeginAnimation(UIElement.OpacityProperty, new DoubleAnimation(0, 1, TimeSpan.FromMilliseconds(160)));
|
||||
MessagePanel.Children.Add(pill);
|
||||
return;
|
||||
}
|
||||
|
||||
if (evt.Type == AgentEventType.StepStart && evt.StepTotal > 0)
|
||||
{
|
||||
UpdateProgressBar(evt);
|
||||
var compactPrimaryText = TryFindResource("PrimaryText") as Brush ?? Brushes.White;
|
||||
var compactSecondaryText = TryFindResource("SecondaryText") as Brush ?? Brushes.Gray;
|
||||
var compactHintBg = TryFindResource("HintBackground") as Brush
|
||||
?? new SolidColorBrush(Color.FromArgb(0x18, 0xFF, 0xFF, 0xFF));
|
||||
var compactBorderBrush = TryFindResource("BorderColor") as Brush ?? Brushes.Gray;
|
||||
var compactAccentBrush = TryFindResource("AccentColor") as Brush ?? Brushes.CornflowerBlue;
|
||||
var stepSummary = !string.IsNullOrWhiteSpace(evt.Summary)
|
||||
? evt.Summary!
|
||||
: $"단계 진행 중 ({evt.StepCurrent}/{evt.StepTotal})";
|
||||
var pill = CreateCompactEventPill(stepSummary, compactPrimaryText, compactSecondaryText, compactHintBg, compactBorderBrush, compactAccentBrush);
|
||||
pill.Opacity = 0;
|
||||
pill.BeginAnimation(UIElement.OpacityProperty, new DoubleAnimation(0, 1, TimeSpan.FromMilliseconds(160)));
|
||||
MessagePanel.Children.Add(pill);
|
||||
return;
|
||||
}
|
||||
|
||||
if (evt.Type == AgentEventType.Thinking &&
|
||||
ContainsAny(evt.Summary ?? "", "컨텍스트 압축", "microcompact", "session memory", "compact"))
|
||||
{
|
||||
var compactPrimaryText = TryFindResource("PrimaryText") as Brush ?? Brushes.White;
|
||||
var compactSecondaryText = TryFindResource("SecondaryText") as Brush ?? Brushes.Gray;
|
||||
var compactHintBg = TryFindResource("HintBackground") as Brush
|
||||
?? new SolidColorBrush(Color.FromArgb(0x18, 0xFF, 0xFF, 0xFF));
|
||||
var compactBorderBrush = TryFindResource("BorderColor") as Brush ?? Brushes.Gray;
|
||||
var compactAccentBrush = TryFindResource("AccentColor") as Brush ?? Brushes.CornflowerBlue;
|
||||
var pill = CreateCompactEventPill(string.IsNullOrWhiteSpace(evt.Summary) ? "컨텍스트 압축" : evt.Summary, compactPrimaryText, compactSecondaryText, compactHintBg, compactBorderBrush, compactAccentBrush);
|
||||
pill.Opacity = 0;
|
||||
pill.BeginAnimation(UIElement.OpacityProperty, new DoubleAnimation(0, 1, TimeSpan.FromMilliseconds(160)));
|
||||
MessagePanel.Children.Add(pill);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!string.Equals(logLevel, "debug", StringComparison.OrdinalIgnoreCase)
|
||||
&& evt.Type is AgentEventType.Paused or AgentEventType.Resumed)
|
||||
return;
|
||||
@@ -524,6 +589,15 @@ public partial class ChatWindow
|
||||
};
|
||||
}
|
||||
|
||||
if (evt.Type == AgentEventType.StepStart && evt.StepTotal > 0)
|
||||
UpdateProgressBar(evt);
|
||||
|
||||
if (IsProcessFeedEvent(evt))
|
||||
{
|
||||
AddProcessFeedMessage(evt, transcriptBadgeLabel, itemDisplayName, eventSummaryText);
|
||||
return;
|
||||
}
|
||||
|
||||
var primaryText = TryFindResource("PrimaryText") as Brush ?? Brushes.Black;
|
||||
var secondaryText = TryFindResource("SecondaryText") as Brush ?? Brushes.DimGray;
|
||||
var hintBg = TryFindResource("HintBackground") as Brush ?? BrushFromHex("#F8FAFC");
|
||||
|
||||
Reference in New Issue
Block a user