AX Agent 코워크·코드 흐름과 컨텍스트 관리를 claude-code 기준으로 대폭 정리

- 코워크·코드 프롬프트, 도구 선택, 문서 생성/검증 흐름을 claude-code 동등 품질 기준으로 재정렬함

- OpenAI/vLLM 경로의 오래된 tool history를 평탄화하고 최근 이력만 구조화해 컨텍스트 직렬화를 경량화함

- AX Agent UI를 테마 기준으로 재구성하고 플랜 승인/오버레이/이벤트 렌더링/명령 입력 상호작용을 개선함

- 파일 후보 제안, 반복 경로 정체 복구, LSP 보강, 문서·PPT 처리 개선, 설정/서비스 인터페이스 정리를 함께 반영함

- README.md 및 docs/DEVELOPMENT.md를 작업 시점별로 갱신함

- 검증: 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-12 22:02:14 +09:00
parent b8f4df1892
commit fb0bea41f7
137 changed files with 18532 additions and 1144 deletions

View File

@@ -1,4 +1,5 @@
using System;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
@@ -49,9 +50,9 @@ public partial class ChatWindow
{
BorderBrush = borderBrush,
BorderThickness = new Thickness(1),
CornerRadius = new CornerRadius(12),
Padding = new Thickness(11, 7, 11, 7),
HorizontalAlignment = HorizontalAlignment.Right,
CornerRadius = new CornerRadius(14),
Padding = new Thickness(14, 10, 14, 10),
HorizontalAlignment = HorizontalAlignment.Stretch,
};
// DynamicResource 방식으로 바인딩 — 테마 전환 시 기존 버블도 자동 업데이트
bubble.SetResourceReference(Border.BackgroundProperty, "HintBackground");
@@ -158,18 +159,30 @@ public partial class ChatWindow
ApplyMessageEntryAnimation(container);
var (agentName, _, _) = GetAgentIdentity();
var header = new StackPanel { Orientation = Orientation.Horizontal, Margin = new Thickness(2, 0, 0, 1.5) };
header.Children.Add(CreateMiniLauncherIcon(pixelSize: 4.0));
var (iconHost, iconPixels, iconGlows, iconRotate, iconScale) = CreateMiniLauncherIconEx(4.0, "none");
var header = new StackPanel { Orientation = Orientation.Horizontal, Margin = new Thickness(2, 4, 0, 0) };
header.Children.Add(iconHost);
header.Children.Add(new TextBlock
{
Text = agentName,
FontSize = 11.5,
FontSize = 11,
FontWeight = FontWeights.SemiBold,
Foreground = secondaryText,
Margin = new Thickness(4, 0, 0, 0),
VerticalAlignment = VerticalAlignment.Center,
});
container.Children.Add(header);
// 아이콘 애니메이션 적용
var canvas = iconHost.Children.OfType<Canvas>().FirstOrDefault();
if (canvas != null)
{
var animState = new ChatIconAnimState
{
Host = iconHost, Canvas = canvas, Pixels = iconPixels,
Glows = iconGlows, Rotate = iconRotate, Scale = iconScale,
IsRandomMode = _settings.Settings.Launcher.EnableChatIconRandomAnimation,
};
StartChatIconAnimation(animState);
}
var contentCard = new Border
{
@@ -297,6 +310,18 @@ public partial class ChatWindow
contentCard.Child = contentStack;
container.Children.Add(contentCard);
// 에이전트 이름 푸터 (메시지 본문 아래)
container.Children.Add(header);
// 어시스턴트 메시지에 파일 경로가 포함되어 있으면 프리뷰/열기 퀵 액션 추가
var outputFilePath = ExtractOutputFilePathFromContent(content);
if (!string.IsNullOrEmpty(outputFilePath) && System.IO.File.Exists(outputFilePath))
{
var quickActions = BuildFileQuickActions(outputFilePath);
quickActions.Margin = new Thickness(2, 4, 0, 2);
container.Children.Add(quickActions);
}
var actionBar = new StackPanel
{
Orientation = Orientation.Horizontal,
@@ -345,4 +370,29 @@ public partial class ChatWindow
if (message?.MsgId != null) _elementCache[$"m_{message.MsgId}"] = container;
AddTranscriptElement(container);
}
/// <summary>
/// 어시스턴트 메시지 텍스트에서 출력 파일 경로(절대 경로)를 추출합니다.
/// "완료: C:\...\file.ext" 패턴을 우선 찾고, 없으면 일반 절대 경로를 검색합니다.
/// </summary>
private static string? ExtractOutputFilePathFromContent(string content)
{
if (string.IsNullOrWhiteSpace(content)) return null;
// 패턴 1: "완료: C:\path\file.ext" 또는 "완료: E:\path\file.ext"
var completionMatch = System.Text.RegularExpressions.Regex.Match(
content,
@"완료:\s*([A-Za-z]:\\[^\s\n""',;)]+\.(?:docx|xlsx|pptx|html|htm|pdf|csv|md|txt))");
if (completionMatch.Success)
return completionMatch.Groups[1].Value.TrimEnd('.');
// 패턴 2: 임의의 절대 경로 (알려진 문서 확장자)
var absMatch = System.Text.RegularExpressions.Regex.Match(
content,
@"([A-Za-z]:\\[^\s\n""',;)]+\.(?:docx|xlsx|pptx|html|htm|pdf|csv|md|txt))");
if (absMatch.Success)
return absMatch.Groups[1].Value.TrimEnd('.');
return null;
}
}