변경 목적: - AX Agent의 도구 이름, 내부 설정, 스킬 정책, 실행 루프 사이의 불일치를 줄이고 전체 동작 품질을 높인다. - claw-code 수준의 일관된 동작 품질을 참고하되 AX 구조에 맞는 고유한 카탈로그·정규화 레이어로 재구성한다. 핵심 수정사항: - 도구 canonical id, legacy alias, 탭 노출, 설정 카테고리, read-only 분류를 중앙 카탈로그로 통합했다. - ToolRegistry, AgentLoopService, 병렬 실행 분류, 권한 처리, 훅 처리, 스킬 allowed-tools 해석이 같은 이름 체계를 사용하도록 정리했다. - Agent 설정/일반 설정/도움말의 도구 카드와 훅 편집기, 스킬 설명을 현재 런타임 구조에 맞게 갱신했다. - 컨텍스트 압축, intent gate, spawn agents, session learning, model prompt adapter, workspace context 관련 변경과 테스트 추가를 함께 반영했다. - 문서 이력과 비교/로드맵 문서를 최신 상태로 갱신했다. 검증 결과: - dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\verify_toolcat\ -p:IntermediateOutputPath=obj\verify_toolcat\ : 경고 0 / 오류 0 - dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter AgentToolCatalogTests -p:OutputPath=bin\verify_toolcat_tests\ -p:IntermediateOutputPath=obj\verify_toolcat_tests\ : 통과 8
98 lines
3.2 KiB
C#
98 lines
3.2 KiB
C#
using System;
|
||
using System.Linq;
|
||
using System.Windows;
|
||
using System.Windows.Controls;
|
||
using System.Windows.Media;
|
||
using System.Windows.Media.Animation;
|
||
using System.Windows.Threading;
|
||
|
||
namespace AxCopilot.Views;
|
||
|
||
public partial class ChatWindow
|
||
{
|
||
private void ShowAgentLiveCard(string runTab)
|
||
{
|
||
if (MessageList == null) return;
|
||
if (!string.Equals(runTab, _activeTab, StringComparison.OrdinalIgnoreCase)) return;
|
||
|
||
ShowAgentLiveCardV2(runTab);
|
||
}
|
||
|
||
private void UpdateAgentLiveCard(string message, string? subItem = null,
|
||
string? category = null, bool clearSubItems = false)
|
||
{
|
||
if (_agentLiveContainer == null || _agentLiveStatusText == null) return;
|
||
|
||
_agentLiveStatusText.Text = message;
|
||
|
||
if (clearSubItems || (category != null && category != _agentLiveCurrentCategory))
|
||
{
|
||
_agentLiveSubItemTexts.Clear();
|
||
_agentLiveSubItems?.Children.Clear();
|
||
if (category != null)
|
||
_agentLiveCurrentCategory = category;
|
||
}
|
||
|
||
if (string.IsNullOrEmpty(subItem) || _agentLiveSubItemTexts.Contains(subItem))
|
||
return;
|
||
|
||
_agentLiveSubItemTexts.Add(subItem);
|
||
const int maxLiveSubItems = 8;
|
||
if (_agentLiveSubItemTexts.Count > maxLiveSubItems)
|
||
{
|
||
_agentLiveSubItemTexts.RemoveAt(0);
|
||
if (_agentLiveSubItems?.Children.Count > 0)
|
||
_agentLiveSubItems.Children.RemoveAt(0);
|
||
}
|
||
|
||
var secondary = TryFindResource("SecondaryText") as Brush ?? Brushes.Gray;
|
||
var tb = new TextBlock
|
||
{
|
||
Text = $"› {subItem}",
|
||
FontSize = 10.5,
|
||
FontFamily = s_segoeUiFont,
|
||
Foreground = secondary,
|
||
Opacity = 0.62,
|
||
TextTrimming = TextTrimming.CharacterEllipsis,
|
||
MaxWidth = 520,
|
||
Margin = new Thickness(0, 1, 0, 0),
|
||
};
|
||
_agentLiveSubItems?.Children.Add(tb);
|
||
ForceScrollToEnd();
|
||
}
|
||
|
||
private void RemoveAgentLiveCard(bool animated = true)
|
||
{
|
||
// V2 분기 — V2 라이브 컨테이너도 함께 정리
|
||
if (_v2LiveContainer != null)
|
||
RemoveAgentLiveCardV2(animated);
|
||
|
||
_agentLiveElapsedTimer?.Stop();
|
||
_agentLiveElapsedTimer = null;
|
||
|
||
if (_agentLiveContainer == null)
|
||
return;
|
||
|
||
// 라이브 카드에 연결된 아이콘 애니메이션 상태 제거
|
||
_chatIconAnimStates.RemoveAll(s => s.Host != null && !s.Host.IsVisible);
|
||
|
||
var toRemove = _agentLiveContainer;
|
||
_agentLiveContainer = null;
|
||
_agentLiveStatusText = null;
|
||
_agentLiveSubItems = null;
|
||
_agentLiveElapsedText = null;
|
||
_agentLiveSubItemTexts.Clear();
|
||
_agentLiveCurrentCategory = null;
|
||
|
||
if (animated && ContainsTranscriptElement(toRemove) && !IsLightweightLiveProgressMode())
|
||
{
|
||
var anim = new DoubleAnimation(toRemove.Opacity, 0, TimeSpan.FromMilliseconds(160));
|
||
anim.Completed += (_, _) => RemoveTranscriptElement(toRemove);
|
||
toRemove.BeginAnimation(UIElement.OpacityProperty, anim);
|
||
return;
|
||
}
|
||
|
||
RemoveTranscriptElement(toRemove);
|
||
}
|
||
}
|