Some checks failed
Release Gate / gate (push) Has been cancelled
- claude-code 선택적 탐색 흐름을 참고해 Cowork/Code 시스템 프롬프트에서 folder_map 상시 선행 지시를 완화하고 glob/grep 기반 좁은 탐색을 우선하도록 조정함 - FolderMapTool 기본 depth를 2로, include_files 기본값을 false로 낮추고 MultiReadTool 최대 파일 수를 8개로 줄여 초기 과탐색 폭을 보수적으로 조정함 - AgentLoopExplorationPolicy partial을 추가해 탐색 범위 분류, broad-scan corrective hint, exploration_breadth 성능 로그를 연결함 - AgentLoopService에 탐색 범위 가이드 주입과 실행 중 탐색 폭 추적을 추가하고, 좁은 질문에서 반복적인 folder_map/대량 multi_read를 교정하도록 정리함 - DocxToHtmlConverter nullable 경고를 수정해 Release 빌드 경고 0 / 오류 0 기준을 다시 충족함 - README와 docs/DEVELOPMENT.md에 2026-04-09 10:36 (KST) 기준 개발 이력을 반영함
604 lines
21 KiB
C#
604 lines
21 KiB
C#
using System;
|
|
using System.Linq;
|
|
using System.Windows;
|
|
using System.Windows.Controls;
|
|
using System.Windows.Controls.Primitives;
|
|
using System.Windows.Input;
|
|
using System.Windows.Media;
|
|
using AxCopilot.Models;
|
|
using AxCopilot.Services;
|
|
|
|
namespace AxCopilot.Views;
|
|
|
|
public partial class ChatWindow
|
|
{
|
|
// ── A-1: TopicButtonPanel 이벤트 위임 ──
|
|
private Border? _lastHoveredTopicBorder;
|
|
private bool _topicPanelDelegationInitialized;
|
|
|
|
/// <summary>프리셋 카드 Border.Tag에 저장하는 메타 데이터.</summary>
|
|
private sealed class TopicCardTag
|
|
{
|
|
public required string Action { get; init; } // "preset" | "etc" | "add" | "custom_preset"
|
|
public TopicPreset? Preset { get; init; }
|
|
public required Brush NormalBackground { get; init; }
|
|
public required Brush HoverBackground { get; init; }
|
|
public Brush? NormalBorderBrush { get; init; }
|
|
}
|
|
|
|
/// <summary>TopicButtonPanel에 이벤트 위임 핸들러를 1회 등록합니다.</summary>
|
|
private void InitTopicPanelDelegation()
|
|
{
|
|
if (_topicPanelDelegationInitialized || TopicButtonPanel == null)
|
|
return;
|
|
_topicPanelDelegationInitialized = true;
|
|
|
|
TopicButtonPanel.Background = Brushes.Transparent; // 갭 영역도 히트테스트 대상으로 등록
|
|
TopicButtonPanel.MouseMove += TopicPanel_DelegatedMouseMove;
|
|
TopicButtonPanel.MouseLeave += TopicPanel_DelegatedMouseLeave;
|
|
TopicButtonPanel.PreviewMouseLeftButtonDown += TopicPanel_DelegatedLeftButtonDown;
|
|
TopicButtonPanel.PreviewMouseRightButtonUp += TopicPanel_DelegatedRightButtonUp;
|
|
}
|
|
|
|
private void TopicPanel_DelegatedMouseMove(object sender, MouseEventArgs e)
|
|
{
|
|
var border = FindAncestorWithTag<Border>(e.OriginalSource as DependencyObject);
|
|
if (ReferenceEquals(border, _lastHoveredTopicBorder))
|
|
return;
|
|
|
|
// 이전 호버 해제
|
|
if (_lastHoveredTopicBorder?.Tag is TopicCardTag prevTag)
|
|
{
|
|
_lastHoveredTopicBorder.Background = prevTag.NormalBackground;
|
|
if (prevTag.NormalBorderBrush != null)
|
|
_lastHoveredTopicBorder.BorderBrush = prevTag.NormalBorderBrush;
|
|
}
|
|
|
|
_lastHoveredTopicBorder = border;
|
|
|
|
// 새 호버 적용
|
|
if (border?.Tag is TopicCardTag tag)
|
|
{
|
|
border.Background = tag.HoverBackground;
|
|
border.BorderBrush = TryFindResource("AccentColor") as Brush ?? tag.NormalBorderBrush ?? border.BorderBrush;
|
|
}
|
|
}
|
|
|
|
private void TopicPanel_DelegatedMouseLeave(object sender, MouseEventArgs e)
|
|
{
|
|
if (_lastHoveredTopicBorder?.Tag is TopicCardTag prevTag)
|
|
{
|
|
_lastHoveredTopicBorder.Background = prevTag.NormalBackground;
|
|
if (prevTag.NormalBorderBrush != null)
|
|
_lastHoveredTopicBorder.BorderBrush = prevTag.NormalBorderBrush;
|
|
}
|
|
_lastHoveredTopicBorder = null;
|
|
}
|
|
|
|
private void TopicPanel_DelegatedLeftButtonDown(object sender, MouseButtonEventArgs e)
|
|
{
|
|
var border = FindAncestorWithTag<Border>(e.OriginalSource as DependencyObject);
|
|
if (border?.Tag is not TopicCardTag tag)
|
|
return;
|
|
|
|
e.Handled = true;
|
|
switch (tag.Action)
|
|
{
|
|
case "preset" or "custom_preset" when tag.Preset != null:
|
|
SelectTopic(tag.Preset);
|
|
break;
|
|
case "etc":
|
|
EmptyState.Visibility = Visibility.Collapsed;
|
|
InputBox.Focus();
|
|
break;
|
|
case "add":
|
|
ShowCustomPresetDialog();
|
|
break;
|
|
}
|
|
}
|
|
|
|
private void TopicPanel_DelegatedRightButtonUp(object sender, MouseButtonEventArgs e)
|
|
{
|
|
var border = FindAncestorWithTag<Border>(e.OriginalSource as DependencyObject);
|
|
if (border?.Tag is not TopicCardTag tag)
|
|
return;
|
|
|
|
if (tag.Action == "custom_preset" && tag.Preset != null)
|
|
{
|
|
e.Handled = true;
|
|
ShowCustomPresetContextMenu(border, tag.Preset);
|
|
}
|
|
}
|
|
|
|
/// <summary>프리셋 대화 주제 버튼을 동적으로 생성합니다.</summary>
|
|
private void BuildTopicButtons()
|
|
{
|
|
_lastHoveredTopicBorder = null;
|
|
TopicButtonPanel.Children.Clear();
|
|
TopicButtonPanel.Visibility = Visibility.Visible;
|
|
if (TopicPresetScrollViewer != null)
|
|
TopicPresetScrollViewer.Visibility = Visibility.Visible;
|
|
|
|
if (_activeTab == "Cowork" || _activeTab == "Code")
|
|
{
|
|
if (EmptyStateTitle != null)
|
|
EmptyStateTitle.Text = _activeTab == "Code" ? "코드 작업을 입력하세요" : "작업 유형을 선택하세요";
|
|
if (EmptyStateDesc != null)
|
|
EmptyStateDesc.Text = _activeTab == "Code"
|
|
? "코딩 에이전트가 코드 분석, 수정, 빌드, 테스트를 수행합니다"
|
|
: "에이전트가 상세한 데이터를 작성합니다";
|
|
}
|
|
else
|
|
{
|
|
if (EmptyStateTitle != null)
|
|
EmptyStateTitle.Text = "대화 주제를 선택하세요";
|
|
if (EmptyStateDesc != null)
|
|
EmptyStateDesc.Text = "주제에 맞는 전문 프리셋이 자동 적용됩니다";
|
|
}
|
|
|
|
if (_activeTab == "Code")
|
|
{
|
|
TopicButtonPanel.Visibility = Visibility.Collapsed;
|
|
if (TopicPresetScrollViewer != null)
|
|
TopicPresetScrollViewer.Visibility = Visibility.Collapsed;
|
|
return;
|
|
}
|
|
|
|
var presets = Services.PresetService.GetByTabWithCustom(_activeTab, _settings.Settings.Llm.CustomPresets);
|
|
var cardBackground = TryFindResource("ItemBackground") as Brush ?? Brushes.Transparent;
|
|
var cardHoverBackground = TryFindResource("ItemHoverBackground") as Brush ?? Brushes.Transparent;
|
|
var cardBorder = TryFindResource("BorderColor") as Brush ?? BrushFromHex("#E5E7EB");
|
|
var primaryText = TryFindResource("PrimaryText") as Brush ?? Brushes.White;
|
|
var secondaryText = TryFindResource("SecondaryText") as Brush ?? Brushes.Gray;
|
|
|
|
foreach (var preset in presets)
|
|
{
|
|
var buttonColor = BrushFromHex(preset.Color);
|
|
|
|
var border = new Border
|
|
{
|
|
Background = cardBackground,
|
|
BorderBrush = cardBorder,
|
|
BorderThickness = new Thickness(1),
|
|
CornerRadius = new CornerRadius(14),
|
|
Padding = new Thickness(14, 14, 14, 12),
|
|
Margin = new Thickness(6, 6, 6, 8),
|
|
Cursor = Cursors.Hand,
|
|
Width = 148,
|
|
Height = 124,
|
|
ClipToBounds = true,
|
|
};
|
|
|
|
var contentGrid = new Grid();
|
|
var stack = new StackPanel
|
|
{
|
|
HorizontalAlignment = HorizontalAlignment.Center,
|
|
VerticalAlignment = VerticalAlignment.Center,
|
|
};
|
|
|
|
var iconCircle = new Border
|
|
{
|
|
Width = 34,
|
|
Height = 34,
|
|
CornerRadius = new CornerRadius(17),
|
|
Background = new SolidColorBrush(((SolidColorBrush)buttonColor).Color) { Opacity = 0.15 },
|
|
HorizontalAlignment = HorizontalAlignment.Center,
|
|
Margin = new Thickness(0, 0, 0, 9),
|
|
};
|
|
var iconBlock = new TextBlock
|
|
{
|
|
Text = preset.Symbol,
|
|
FontFamily = new FontFamily("Segoe MDL2 Assets"),
|
|
FontSize = 15,
|
|
Foreground = buttonColor,
|
|
HorizontalAlignment = HorizontalAlignment.Center,
|
|
VerticalAlignment = VerticalAlignment.Center,
|
|
};
|
|
iconCircle.Child = iconBlock;
|
|
stack.Children.Add(iconCircle);
|
|
|
|
stack.Children.Add(new TextBlock
|
|
{
|
|
Text = preset.Label,
|
|
FontSize = 15,
|
|
FontWeight = FontWeights.SemiBold,
|
|
Foreground = primaryText,
|
|
HorizontalAlignment = HorizontalAlignment.Center,
|
|
TextAlignment = TextAlignment.Center,
|
|
TextWrapping = TextWrapping.Wrap,
|
|
MaxWidth = 112,
|
|
});
|
|
|
|
contentGrid.Children.Add(stack);
|
|
|
|
if (preset.IsCustom)
|
|
{
|
|
var badge = new Border
|
|
{
|
|
Width = 16,
|
|
Height = 16,
|
|
CornerRadius = new CornerRadius(4),
|
|
Background = new SolidColorBrush(Color.FromArgb(0x60, 0xFF, 0xFF, 0xFF)),
|
|
HorizontalAlignment = HorizontalAlignment.Left,
|
|
VerticalAlignment = VerticalAlignment.Top,
|
|
Margin = new Thickness(2, 2, 0, 0),
|
|
};
|
|
badge.Child = new TextBlock
|
|
{
|
|
Text = "\uE710",
|
|
FontFamily = new FontFamily("Segoe MDL2 Assets"),
|
|
FontSize = 8,
|
|
Foreground = buttonColor,
|
|
HorizontalAlignment = HorizontalAlignment.Center,
|
|
VerticalAlignment = VerticalAlignment.Center,
|
|
};
|
|
contentGrid.Children.Add(badge);
|
|
}
|
|
|
|
border.Child = contentGrid;
|
|
|
|
// A-1: 이벤트 위임 — 개별 람다 대신 Tag에 메타 저장
|
|
border.Tag = new TopicCardTag
|
|
{
|
|
Action = preset.IsCustom ? "custom_preset" : "preset",
|
|
Preset = preset,
|
|
NormalBackground = cardBackground,
|
|
HoverBackground = cardHoverBackground,
|
|
NormalBorderBrush = cardBorder,
|
|
};
|
|
|
|
TopicButtonPanel.Children.Add(border);
|
|
}
|
|
|
|
var etcColor = BrushFromHex("#6B7280");
|
|
var etcBorder = new Border
|
|
{
|
|
Background = cardBackground,
|
|
BorderBrush = cardBorder,
|
|
BorderThickness = new Thickness(1),
|
|
CornerRadius = new CornerRadius(14),
|
|
Padding = new Thickness(14, 14, 14, 12),
|
|
Margin = new Thickness(6, 6, 6, 8),
|
|
Cursor = Cursors.Hand,
|
|
Width = 148,
|
|
Height = 124,
|
|
ClipToBounds = true,
|
|
};
|
|
|
|
var etcGrid = new Grid();
|
|
var etcStack = new StackPanel
|
|
{
|
|
HorizontalAlignment = HorizontalAlignment.Center,
|
|
VerticalAlignment = VerticalAlignment.Center,
|
|
};
|
|
|
|
var etcIconCircle = new Border
|
|
{
|
|
Width = 34,
|
|
Height = 34,
|
|
CornerRadius = new CornerRadius(17),
|
|
Background = new SolidColorBrush(((SolidColorBrush)etcColor).Color) { Opacity = 0.15 },
|
|
HorizontalAlignment = HorizontalAlignment.Center,
|
|
Margin = new Thickness(0, 0, 0, 9),
|
|
};
|
|
etcIconCircle.Child = new TextBlock
|
|
{
|
|
Text = "\uE70F",
|
|
FontFamily = new FontFamily("Segoe MDL2 Assets"),
|
|
FontSize = 15,
|
|
Foreground = etcColor,
|
|
HorizontalAlignment = HorizontalAlignment.Center,
|
|
VerticalAlignment = VerticalAlignment.Center,
|
|
};
|
|
etcStack.Children.Add(etcIconCircle);
|
|
etcStack.Children.Add(new TextBlock
|
|
{
|
|
Text = "기타",
|
|
FontSize = 15,
|
|
FontWeight = FontWeights.SemiBold,
|
|
Foreground = primaryText,
|
|
HorizontalAlignment = HorizontalAlignment.Center,
|
|
TextAlignment = TextAlignment.Center,
|
|
});
|
|
etcGrid.Children.Add(etcStack);
|
|
etcBorder.Child = etcGrid;
|
|
etcBorder.Tag = new TopicCardTag
|
|
{
|
|
Action = "etc",
|
|
NormalBackground = cardBackground,
|
|
HoverBackground = cardHoverBackground,
|
|
NormalBorderBrush = cardBorder,
|
|
};
|
|
TopicButtonPanel.Children.Add(etcBorder);
|
|
|
|
var addBorder = new Border
|
|
{
|
|
Background = Brushes.Transparent,
|
|
BorderBrush = cardBorder,
|
|
BorderThickness = new Thickness(1),
|
|
CornerRadius = new CornerRadius(14),
|
|
Padding = new Thickness(14, 14, 14, 12),
|
|
Margin = new Thickness(6, 6, 6, 8),
|
|
Cursor = Cursors.Hand,
|
|
Width = 148,
|
|
Height = 124,
|
|
ClipToBounds = true,
|
|
};
|
|
|
|
var addGrid = new Grid();
|
|
var addStack = new StackPanel
|
|
{
|
|
HorizontalAlignment = HorizontalAlignment.Center,
|
|
VerticalAlignment = VerticalAlignment.Center,
|
|
};
|
|
|
|
addStack.Children.Add(new TextBlock
|
|
{
|
|
Text = "\uE710",
|
|
FontFamily = new FontFamily("Segoe MDL2 Assets"),
|
|
FontSize = 18,
|
|
Foreground = secondaryText,
|
|
HorizontalAlignment = HorizontalAlignment.Center,
|
|
Margin = new Thickness(0, 8, 0, 8),
|
|
});
|
|
addStack.Children.Add(new TextBlock
|
|
{
|
|
Text = "프리셋 추가",
|
|
FontSize = 14,
|
|
FontWeight = FontWeights.SemiBold,
|
|
Foreground = secondaryText,
|
|
HorizontalAlignment = HorizontalAlignment.Center,
|
|
});
|
|
|
|
addGrid.Children.Add(addStack);
|
|
addBorder.Child = addGrid;
|
|
addBorder.Tag = new TopicCardTag
|
|
{
|
|
Action = "add",
|
|
NormalBackground = Brushes.Transparent,
|
|
HoverBackground = cardHoverBackground,
|
|
NormalBorderBrush = cardBorder,
|
|
};
|
|
TopicButtonPanel.Children.Add(addBorder);
|
|
|
|
UpdateTopicPresetScrollMode();
|
|
}
|
|
|
|
private void UpdateTopicPresetScrollMode()
|
|
{
|
|
if (TopicPresetScrollViewer == null || TopicButtonPanel == null)
|
|
return;
|
|
|
|
Dispatcher.BeginInvoke(new Action(() =>
|
|
{
|
|
if (TopicPresetScrollViewer == null || TopicButtonPanel == null)
|
|
return;
|
|
|
|
TopicPresetScrollViewer.UpdateLayout();
|
|
var shouldScroll = TopicPresetScrollViewer.ExtentHeight > TopicPresetScrollViewer.ViewportHeight + 1;
|
|
TopicPresetScrollViewer.VerticalScrollBarVisibility = shouldScroll
|
|
? ScrollBarVisibility.Auto
|
|
: ScrollBarVisibility.Disabled;
|
|
TopicPresetScrollViewer.Padding = shouldScroll
|
|
? new Thickness(0, 2, 6, 0)
|
|
: new Thickness(0, 2, 0, 0);
|
|
}), System.Windows.Threading.DispatcherPriority.Loaded);
|
|
}
|
|
|
|
private void ShowCustomPresetDialog(CustomPresetEntry? existing = null)
|
|
{
|
|
var dialog = new CustomPresetDialog(
|
|
existingName: existing?.Label ?? "",
|
|
existingDesc: existing?.Description ?? "",
|
|
existingPrompt: existing?.SystemPrompt ?? "",
|
|
existingColor: existing?.Color ?? "#6366F1",
|
|
existingSymbol: existing?.Symbol ?? "\uE713",
|
|
existingTab: existing?.Tab ?? _activeTab)
|
|
{
|
|
Owner = this,
|
|
};
|
|
|
|
if (dialog.ShowDialog() != true)
|
|
return;
|
|
|
|
if (existing != null)
|
|
{
|
|
existing.Label = dialog.PresetName;
|
|
existing.Description = dialog.PresetDescription;
|
|
existing.SystemPrompt = dialog.PresetSystemPrompt;
|
|
existing.Color = dialog.PresetColor;
|
|
existing.Symbol = dialog.PresetSymbol;
|
|
existing.Tab = dialog.PresetTab;
|
|
}
|
|
else
|
|
{
|
|
_settings.Settings.Llm.CustomPresets.Add(new CustomPresetEntry
|
|
{
|
|
Label = dialog.PresetName,
|
|
Description = dialog.PresetDescription,
|
|
SystemPrompt = dialog.PresetSystemPrompt,
|
|
Color = dialog.PresetColor,
|
|
Symbol = dialog.PresetSymbol,
|
|
Tab = dialog.PresetTab,
|
|
});
|
|
}
|
|
|
|
_settings.Save();
|
|
BuildTopicButtons();
|
|
}
|
|
|
|
private void ShowCustomPresetContextMenu(Border? anchor, Services.TopicPreset preset)
|
|
{
|
|
if (anchor == null || preset.CustomId == null)
|
|
return;
|
|
|
|
var popup = new Popup
|
|
{
|
|
PlacementTarget = anchor,
|
|
Placement = PlacementMode.Bottom,
|
|
StaysOpen = false,
|
|
AllowsTransparency = true,
|
|
};
|
|
|
|
var menuBackground = TryFindResource("LauncherBackground") as Brush ?? Brushes.Black;
|
|
var primaryText = TryFindResource("PrimaryText") as Brush ?? Brushes.White;
|
|
var borderBrush = TryFindResource("BorderColor") as Brush ?? Brushes.Gray;
|
|
|
|
var menuBorder = new Border
|
|
{
|
|
Background = menuBackground,
|
|
CornerRadius = new CornerRadius(10),
|
|
BorderBrush = borderBrush,
|
|
BorderThickness = new Thickness(1),
|
|
Padding = new Thickness(4),
|
|
MinWidth = 120,
|
|
Effect = new System.Windows.Media.Effects.DropShadowEffect
|
|
{
|
|
BlurRadius = 12,
|
|
ShadowDepth = 2,
|
|
Opacity = 0.3,
|
|
Color = Colors.Black,
|
|
},
|
|
};
|
|
|
|
var stack = new StackPanel();
|
|
|
|
var editItem = CreateContextMenuItem("\uE70F", "편집", primaryText);
|
|
editItem.MouseLeftButtonDown += (_, _) =>
|
|
{
|
|
popup.IsOpen = false;
|
|
var entry = _settings.Settings.Llm.CustomPresets.FirstOrDefault(item => item.Id == preset.CustomId);
|
|
if (entry != null)
|
|
ShowCustomPresetDialog(entry);
|
|
};
|
|
stack.Children.Add(editItem);
|
|
|
|
var deleteItem = CreateContextMenuItem("\uE74D", "삭제", new SolidColorBrush(Color.FromRgb(0xEF, 0x44, 0x44)));
|
|
deleteItem.MouseLeftButtonDown += (_, _) =>
|
|
{
|
|
popup.IsOpen = false;
|
|
var result = CustomMessageBox.Show(
|
|
$"'{preset.Label}' 프리셋을 삭제하시겠습니까?",
|
|
"프리셋 삭제",
|
|
MessageBoxButton.YesNo,
|
|
MessageBoxImage.Question);
|
|
if (result != MessageBoxResult.Yes)
|
|
return;
|
|
|
|
_settings.Settings.Llm.CustomPresets.RemoveAll(item => item.Id == preset.CustomId);
|
|
_settings.Save();
|
|
BuildTopicButtons();
|
|
};
|
|
stack.Children.Add(deleteItem);
|
|
|
|
menuBorder.Child = stack;
|
|
popup.Child = menuBorder;
|
|
popup.IsOpen = true;
|
|
}
|
|
|
|
private Border CreateContextMenuItem(string icon, string label, Brush foreground)
|
|
{
|
|
var item = new Border
|
|
{
|
|
Background = Brushes.Transparent,
|
|
CornerRadius = new CornerRadius(6),
|
|
Padding = new Thickness(10, 6, 14, 6),
|
|
Cursor = Cursors.Hand,
|
|
};
|
|
|
|
var stack = new StackPanel { Orientation = Orientation.Horizontal };
|
|
stack.Children.Add(new TextBlock
|
|
{
|
|
Text = icon,
|
|
FontFamily = new FontFamily("Segoe MDL2 Assets"),
|
|
FontSize = 13,
|
|
Foreground = foreground,
|
|
VerticalAlignment = VerticalAlignment.Center,
|
|
Margin = new Thickness(0, 0, 8, 0),
|
|
});
|
|
stack.Children.Add(new TextBlock
|
|
{
|
|
Text = label,
|
|
FontSize = 13,
|
|
Foreground = foreground,
|
|
VerticalAlignment = VerticalAlignment.Center,
|
|
});
|
|
item.Child = stack;
|
|
|
|
var hoverBackground = TryFindResource("ItemHoverBackground") as Brush ?? Brushes.Transparent;
|
|
item.MouseEnter += (sender, _) =>
|
|
{
|
|
if (sender is Border hovered)
|
|
hovered.Background = hoverBackground;
|
|
};
|
|
item.MouseLeave += (sender, _) =>
|
|
{
|
|
if (sender is Border hovered)
|
|
hovered.Background = Brushes.Transparent;
|
|
};
|
|
|
|
return item;
|
|
}
|
|
|
|
private Border CreateContextMenuItem(string icon, string label, Brush foreground, Brush secondaryForeground)
|
|
=> CreateContextMenuItem(icon, label, foreground);
|
|
|
|
private void SelectTopic(Services.TopicPreset preset)
|
|
{
|
|
bool hasConversation;
|
|
bool hasMessages;
|
|
lock (_convLock)
|
|
{
|
|
hasConversation = _currentConversation != null;
|
|
hasMessages = _currentConversation?.Messages.Count > 0;
|
|
}
|
|
|
|
var hasInput = !string.IsNullOrEmpty(InputBox.Text);
|
|
if (!hasConversation)
|
|
StartNewConversation();
|
|
|
|
lock (_convLock)
|
|
{
|
|
if (_currentConversation == null)
|
|
return;
|
|
|
|
var session = ChatSession;
|
|
if (session != null)
|
|
{
|
|
_currentConversation = session.UpdateConversationMetadata(_activeTab, conversation =>
|
|
{
|
|
conversation.SystemCommand = preset.SystemPrompt;
|
|
conversation.Category = preset.Category;
|
|
}, _storage);
|
|
}
|
|
else
|
|
{
|
|
_currentConversation.SystemCommand = preset.SystemPrompt;
|
|
_currentConversation.Category = preset.Category;
|
|
}
|
|
}
|
|
|
|
UpdateCategoryLabel();
|
|
SaveConversationSettings();
|
|
RefreshConversationList();
|
|
UpdateSelectedPresetGuide();
|
|
if (EmptyState != null)
|
|
EmptyState.Visibility = Visibility.Collapsed;
|
|
|
|
InputBox.Focus();
|
|
|
|
if (!string.IsNullOrEmpty(preset.Placeholder))
|
|
{
|
|
_promptCardPlaceholder = preset.Placeholder;
|
|
if (!hasMessages && !hasInput)
|
|
ShowPlaceholder();
|
|
}
|
|
|
|
if (hasMessages || hasInput)
|
|
ShowToast($"프리셋 변경 · {preset.Label}");
|
|
|
|
if (_activeTab == "Cowork")
|
|
BuildBottomBar();
|
|
}
|
|
}
|