Files
AX-Copilot/src/AxCopilot/Views/Controls/AgentSettingsPanel.xaml
lacvet 90d5943327 [Phase 17-A] Reflexion 자기성찰 메모리 시스템 구현
ReflexionEvaluatorService 신규 구현 (ReflexionService.cs):
- LLM 기반 자기평가: 완성도 점수(0~1), 강점/약점/교훈 추출
- $$raw string 평가 프롬프트로 JSON 포맷 안전하게 삽입
- JSON 블록 추출 + 역직렬화, LLM 실패 시 규칙 기반 폴백 엔트리
- ReflexionRepository.BuildContextPromptAsync() maxEntries 파라미터 추가

AgentLoopService.Reflexion.cs (신규, 82줄):
- InjectReflexionContextAsync(): 세션 시작 전 과거 교훈→시스템 메시지 주입
- FireAndForgetReflexionEval(): 세션 완료 후 Task.Run 비동기 자기평가 저장
- 지연 초기화(_reflexionRepo, _reflexionEval): 사용 시점에 생성

AgentLoopService.cs 통합 포인트 2개 추가:
- RunAsync() 루프 시작 전: await InjectReflexionContextAsync()
- finally 블록 통계 섹션: FireAndForgetReflexionEval() 호출

AgentSettingsPanel — 자기성찰 메모리 섹션 추가:
- 활성화 토글(ChkReflexionEnabled)
- 성공 세션만 평가 토글(ChkReflexionSuccessOnly)
- 최대 참고 교훈 수 슬라이더(1~20, 기본값 5)
- LoadFromSettings() 초기화 + 3개 이벤트 핸들러

빌드: 경고 0, 오류 0
2026-04-03 23:07:59 +09:00

357 lines
21 KiB
XML

<UserControl x:Class="AxCopilot.Views.Controls.AgentSettingsPanel"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="300" MinWidth="280">
<!-- Phase 32-A: 우측 슬라이드인 설정 패널 (CC Claude.ai 스타일)
ChatWindow 내부에서 AX Agent 모든 설정을 인라인으로 제어.
SettingsWindow의 AX Agent 탭을 완전 대체. -->
<UserControl.RenderTransform>
<TranslateTransform x:Name="SlideTransform" X="300"/>
</UserControl.RenderTransform>
<Border Background="{DynamicResource LauncherBackground}"
BorderBrush="{DynamicResource BorderColor}"
BorderThickness="1,0,0,0"
CornerRadius="0">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="48"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- 헤더: 설정 타이틀 + 닫기 -->
<Border Grid.Row="0" BorderBrush="{DynamicResource BorderColor}" BorderThickness="0,0,0,1">
<Grid Margin="16,0">
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
<TextBlock Text="&#xE713;" FontFamily="Segoe MDL2 Assets" FontSize="16"
Foreground="{DynamicResource AccentColor}" VerticalAlignment="Center"/>
<TextBlock Text=" 설정" FontSize="15" FontWeight="SemiBold"
Foreground="{DynamicResource PrimaryText}" VerticalAlignment="Center" Margin="6,0,0,0"/>
</StackPanel>
<Border HorizontalAlignment="Right" VerticalAlignment="Center"
Background="Transparent" Cursor="Hand" Padding="8,4"
CornerRadius="4" MouseLeftButtonUp="BtnClose_Click">
<Border.Style>
<Style TargetType="Border">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#18FFFFFF"/>
</Trigger>
</Style.Triggers>
</Style>
</Border.Style>
<TextBlock Text="&#xE8BB;" FontFamily="Segoe MDL2 Assets" FontSize="12"
Foreground="{DynamicResource SecondaryText}"/>
</Border>
</Grid>
</Border>
<!-- 설정 본문: 스크롤 가능 -->
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Disabled" Padding="0,0,2,0">
<StackPanel Margin="16,12,16,20">
<!-- 현재 탭 표시 -->
<Border Background="{DynamicResource ItemBackground}" CornerRadius="8" Padding="12,8" Margin="0,0,0,16">
<StackPanel Orientation="Horizontal">
<TextBlock Text="현재 탭:" Foreground="{DynamicResource SecondaryText}" FontSize="12"/>
<TextBlock x:Name="TxtCurrentTab" Text="Chat" FontSize="12" FontWeight="SemiBold"
Foreground="{DynamicResource AccentColor}" Margin="6,0,0,0"/>
</StackPanel>
</Border>
<!-- ═══ 모델 & 서비스 ═══ -->
<TextBlock Text="모델 &amp; 서비스" FontSize="13" FontWeight="SemiBold"
Foreground="{DynamicResource PrimaryText}" Margin="0,0,0,8"/>
<!-- LLM 서비스 -->
<Grid Margin="0,0,0,8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="LLM 서비스" Foreground="{DynamicResource SecondaryText}" FontSize="12"
VerticalAlignment="Center"/>
<Border Grid.Column="1" Background="{DynamicResource ItemBackground}"
CornerRadius="6" Padding="10,6" Cursor="Hand"
MouseLeftButtonUp="BtnServiceSelector_Click">
<Border.Style>
<Style TargetType="Border">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{DynamicResource ItemHoverBackground}"/>
</Trigger>
</Style.Triggers>
</Style>
</Border.Style>
<Grid>
<TextBlock x:Name="TxtServiceName" Text="Ollama" FontSize="12"
Foreground="{DynamicResource PrimaryText}"/>
<TextBlock Text="&#xE70D;" FontFamily="Segoe MDL2 Assets" FontSize="10"
Foreground="{DynamicResource SecondaryText}"
HorizontalAlignment="Right" VerticalAlignment="Center"/>
</Grid>
</Border>
</Grid>
<!-- 모델 -->
<Grid Margin="0,0,0,8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="모델" Foreground="{DynamicResource SecondaryText}" FontSize="12"
VerticalAlignment="Center"/>
<Border Grid.Column="1" Background="{DynamicResource ItemBackground}"
CornerRadius="6" Padding="10,6" Cursor="Hand"
MouseLeftButtonUp="BtnModelSelector_Click">
<Border.Style>
<Style TargetType="Border">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{DynamicResource ItemHoverBackground}"/>
</Trigger>
</Style.Triggers>
</Style>
</Border.Style>
<Grid>
<TextBlock x:Name="TxtModelName" Text="llama3:8b" FontSize="12"
Foreground="{DynamicResource PrimaryText}"/>
<TextBlock Text="&#xE70D;" FontFamily="Segoe MDL2 Assets" FontSize="10"
Foreground="{DynamicResource SecondaryText}"
HorizontalAlignment="Right" VerticalAlignment="Center"/>
</Grid>
</Border>
</Grid>
<!-- API 엔드포인트 -->
<Grid Margin="0,0,0,8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="API 엔드포인트" Foreground="{DynamicResource SecondaryText}" FontSize="12"
VerticalAlignment="Center"/>
<TextBox x:Name="TxtApiEndpoint" FontSize="12" Padding="8,5"
Background="{DynamicResource ItemBackground}"
Foreground="{DynamicResource PrimaryText}"
BorderBrush="{DynamicResource BorderColor}"
BorderThickness="1" Grid.Column="1"
LostFocus="TxtApiEndpoint_LostFocus"/>
</Grid>
<Border Height="1" Background="{DynamicResource BorderColor}" Margin="0,8,0,16"/>
<!-- ═══ 에이전트 동작 ═══ -->
<TextBlock Text="에이전트 동작" FontSize="13" FontWeight="SemiBold"
Foreground="{DynamicResource PrimaryText}" Margin="0,0,0,8"/>
<!-- 최대 반복 횟수 -->
<Grid Margin="0,0,0,8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="40"/>
</Grid.ColumnDefinitions>
<TextBlock Text="최대 반복 횟수" Foreground="{DynamicResource SecondaryText}" FontSize="12"
VerticalAlignment="Center"/>
<TextBlock x:Name="TxtMaxIterations" Grid.Column="1" Text="25"
Foreground="{DynamicResource PrimaryText}" FontSize="12"
HorizontalAlignment="Right" VerticalAlignment="Center"/>
</Grid>
<Slider x:Name="SliderMaxIterations" Minimum="1" Maximum="100" Value="25"
IsSnapToTickEnabled="True" TickFrequency="1"
ValueChanged="SliderMaxIterations_ValueChanged" Margin="0,0,0,8"/>
<!-- 오류 시 재시도 -->
<Grid Margin="0,0,0,8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="40"/>
</Grid.ColumnDefinitions>
<TextBlock Text="오류 시 재시도" Foreground="{DynamicResource SecondaryText}" FontSize="12"
VerticalAlignment="Center"/>
<TextBlock x:Name="TxtMaxRetry" Grid.Column="1" Text="3"
Foreground="{DynamicResource PrimaryText}" FontSize="12"
HorizontalAlignment="Right" VerticalAlignment="Center"/>
</Grid>
<Slider x:Name="SliderMaxRetry" Minimum="0" Maximum="10" Value="3"
IsSnapToTickEnabled="True" TickFrequency="1"
ValueChanged="SliderMaxRetry_ValueChanged" Margin="0,0,0,8"/>
<!-- 병렬 도구 실행 토글 -->
<Grid Margin="0,0,0,8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Text="병렬 도구 실행" Foreground="{DynamicResource SecondaryText}" FontSize="12"
VerticalAlignment="Center"/>
<CheckBox x:Name="ChkParallelTools" Grid.Column="1"
Style="{StaticResource ToggleSwitch}"
Checked="ChkParallelTools_Changed" Unchecked="ChkParallelTools_Changed"/>
</Grid>
<Border Height="1" Background="{DynamicResource BorderColor}" Margin="0,8,0,16"/>
<!-- ═══ 자기성찰 메모리 (Phase 17-A) ═══ -->
<TextBlock Text="자기성찰 메모리" FontSize="13" FontWeight="SemiBold"
Foreground="{DynamicResource PrimaryText}" Margin="0,0,0,8"/>
<!-- 자기성찰 활성화 -->
<Grid Margin="0,0,0,8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<StackPanel>
<TextBlock Text="자기성찰 메모리" Foreground="{DynamicResource SecondaryText}" FontSize="12"/>
<TextBlock Text="동일 유형 작업 시 과거 교훈 자동 참고" FontSize="10"
Foreground="{DynamicResource SecondaryText}" Opacity="0.7"/>
</StackPanel>
<CheckBox x:Name="ChkReflexionEnabled" Grid.Column="1"
Style="{StaticResource ToggleSwitch}"
Checked="ChkReflexion_Changed" Unchecked="ChkReflexion_Changed"/>
</Grid>
<!-- 성공 시만 평가 -->
<Grid Margin="0,0,0,8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Text="성공 세션만 평가" Foreground="{DynamicResource SecondaryText}" FontSize="12"
VerticalAlignment="Center"/>
<CheckBox x:Name="ChkReflexionSuccessOnly" Grid.Column="1"
Style="{StaticResource ToggleSwitch}"
Checked="ChkReflexionSuccessOnly_Changed" Unchecked="ChkReflexionSuccessOnly_Changed"/>
</Grid>
<!-- 최대 참고 교훈 수 -->
<Grid Margin="0,0,0,4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="40"/>
</Grid.ColumnDefinitions>
<TextBlock Text="최대 참고 교훈 수" Foreground="{DynamicResource SecondaryText}" FontSize="12"
VerticalAlignment="Center"/>
<TextBlock x:Name="TxtReflexionMaxEntries" Grid.Column="1" Text="5"
Foreground="{DynamicResource PrimaryText}" FontSize="12"
HorizontalAlignment="Right" VerticalAlignment="Center"/>
</Grid>
<Slider x:Name="SliderReflexionMaxEntries" Minimum="1" Maximum="20" Value="5"
IsSnapToTickEnabled="True" TickFrequency="1"
ValueChanged="SliderReflexionMaxEntries_ValueChanged" Margin="0,0,0,8"/>
<Border Height="1" Background="{DynamicResource BorderColor}" Margin="0,8,0,16"/>
<!-- ═══ 탭 전용 설정 ═══ -->
<TextBlock Text="탭 전용 설정" FontSize="13" FontWeight="SemiBold"
Foreground="{DynamicResource PrimaryText}" Margin="0,0,0,8"/>
<!-- Cowork 전용 -->
<StackPanel x:Name="PanelCoworkSettings" Visibility="Collapsed">
<Grid Margin="0,0,0,8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Text="검증 강제" Foreground="{DynamicResource SecondaryText}" FontSize="12"
VerticalAlignment="Center"/>
<CheckBox x:Name="ChkCoworkVerify" Grid.Column="1"
Style="{StaticResource ToggleSwitch}"
Checked="ChkCoworkVerify_Changed" Unchecked="ChkCoworkVerify_Changed"/>
</Grid>
</StackPanel>
<!-- Code 전용 -->
<StackPanel x:Name="PanelCodeSettings" Visibility="Collapsed">
<Grid Margin="0,0,0,8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Text="LSP 분석" Foreground="{DynamicResource SecondaryText}" FontSize="12"
VerticalAlignment="Center"/>
<CheckBox x:Name="ChkCodeLsp" Grid.Column="1"
Style="{StaticResource ToggleSwitch}"
Checked="ChkCodeLsp_Changed" Unchecked="ChkCodeLsp_Changed"/>
</Grid>
<Grid Margin="0,0,0,8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Text="코드 검증" Foreground="{DynamicResource SecondaryText}" FontSize="12"
VerticalAlignment="Center"/>
<CheckBox x:Name="ChkCodeVerify" Grid.Column="1"
Style="{StaticResource ToggleSwitch}"
Checked="ChkCodeVerify_Changed" Unchecked="ChkCodeVerify_Changed"/>
</Grid>
</StackPanel>
<Border Height="1" Background="{DynamicResource BorderColor}" Margin="0,8,0,16"/>
<!-- ═══ 도구 관리 ═══ -->
<TextBlock Text="도구 관리" FontSize="13" FontWeight="SemiBold"
Foreground="{DynamicResource PrimaryText}" Margin="0,0,0,8"/>
<StackPanel x:Name="PanelToolToggles">
<!-- 코드비하인드에서 동적 생성 -->
</StackPanel>
<Border Height="1" Background="{DynamicResource BorderColor}" Margin="0,8,0,16"/>
<!-- ═══ 고급 ═══ -->
<TextBlock Text="고급" FontSize="13" FontWeight="SemiBold"
Foreground="{DynamicResource PrimaryText}" Margin="0,0,0,8"/>
<!-- 자동 컴팩션 임계치 -->
<Grid Margin="0,0,0,8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="40"/>
</Grid.ColumnDefinitions>
<TextBlock Text="자동 컴팩션 (%)" Foreground="{DynamicResource SecondaryText}" FontSize="12"
VerticalAlignment="Center"/>
<TextBlock x:Name="TxtAutoCompact" Grid.Column="1" Text="80"
Foreground="{DynamicResource PrimaryText}" FontSize="12"
HorizontalAlignment="Right" VerticalAlignment="Center"/>
</Grid>
<Slider x:Name="SliderAutoCompact" Minimum="50" Maximum="95" Value="80"
IsSnapToTickEnabled="True" TickFrequency="5"
ValueChanged="SliderAutoCompact_ValueChanged" Margin="0,0,0,8"/>
<!-- 프로젝트 규칙 -->
<Grid Margin="0,0,0,8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Text="프로젝트 규칙 (AX.md)" Foreground="{DynamicResource SecondaryText}" FontSize="12"
VerticalAlignment="Center"/>
<CheckBox x:Name="ChkProjectRules" Grid.Column="1"
Style="{StaticResource ToggleSwitch}" IsChecked="True"
Checked="ChkProjectRules_Changed" Unchecked="ChkProjectRules_Changed"/>
</Grid>
<!-- 개발자 모드 -->
<Grid Margin="0,0,0,8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Text="개발자 모드" Foreground="{DynamicResource SecondaryText}" FontSize="12"
VerticalAlignment="Center"/>
<CheckBox x:Name="ChkDevMode" Grid.Column="1"
Style="{StaticResource ToggleSwitch}"
Checked="ChkDevMode_Changed" Unchecked="ChkDevMode_Changed"/>
</Grid>
</StackPanel>
</ScrollViewer>
</Grid>
</Border>
</UserControl>