AX Agent 탭 내 대화 선택 복귀 회귀 수정
- 같은 탭 안에서 다른 대화를 선택할 때 SaveLastConversations로 발생한 SettingsChanged가 UI 전체 갱신을 다시 태우며 현재 선택을 스트리밍 대화로 덮어쓰던 흐름을 차단함 - ChatStreamingUiPolicy에 스트리밍 대화 우선 노출 정책을 분리하고, 사용자가 명시적으로 선택한 대화가 있으면 탭 복귀 후에도 해당 선택을 유지하도록 SwitchToTabConversation 분기를 조정함 - README.md와 docs/DEVELOPMENT.md에 2026-04-15 22:07 (KST) 기준 회귀 원인과 검증 결과를 반영함 검증 결과 - dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\verify_conversation_selection_persist\ -p:IntermediateOutputPath=obj\verify_conversation_selection_persist\ : 경고 0 / 오류 0 - dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter ChatStreamingUiPolicyTests|ChatSessionStateServiceTests -p:OutputPath=bin\verify_conversation_selection_persist_tests\ -p:IntermediateOutputPath=obj\verify_conversation_selection_persist_tests\ : 통과 55
This commit is contained in:
@@ -51,4 +51,22 @@ public class ChatStreamingUiPolicyTests
|
||||
|
||||
result.Should().Be(expected);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, null, false)]
|
||||
[InlineData("run-1", null, true)]
|
||||
[InlineData("run-1", "", true)]
|
||||
[InlineData("run-1", "run-1", true)]
|
||||
[InlineData("run-1", "other-conversation", false)]
|
||||
public void ShouldPreferStreamingConversation_ShouldKeepExplicitConversationSelection(
|
||||
string? streamingConversationId,
|
||||
string? rememberedConversationId,
|
||||
bool expected)
|
||||
{
|
||||
var result = ChatStreamingUiPolicy.ShouldPreferStreamingConversation(
|
||||
streamingConversationId,
|
||||
rememberedConversationId);
|
||||
|
||||
result.Should().Be(expected);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
namespace AxCopilot.Views;
|
||||
|
||||
using System;
|
||||
|
||||
internal enum StreamingGuideVisibility
|
||||
{
|
||||
Hidden,
|
||||
@@ -26,4 +28,15 @@ internal static class ChatStreamingUiPolicy
|
||||
|
||||
internal static bool ShouldRenderConversationBoundContent(StreamingGuideVisibility visibility)
|
||||
=> visibility == StreamingGuideVisibility.ActiveConversation;
|
||||
|
||||
internal static bool ShouldPreferStreamingConversation(
|
||||
string? streamingConversationId,
|
||||
string? rememberedConversationId)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(streamingConversationId))
|
||||
return false;
|
||||
|
||||
return string.IsNullOrWhiteSpace(rememberedConversationId)
|
||||
|| string.Equals(streamingConversationId, rememberedConversationId, StringComparison.Ordinal);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,6 +151,7 @@ public partial class ChatWindow : Window
|
||||
private StackPanel? _selectedMessageActionBar;
|
||||
private Border? _selectedMessageBorder;
|
||||
private bool _isRefreshingFromSettings;
|
||||
private bool _suppressSettingsRefreshForSessionSave;
|
||||
private int? _lastCompactionBeforeTokens;
|
||||
private int? _lastCompactionAfterTokens;
|
||||
private DateTime? _lastCompactionAt;
|
||||
@@ -600,7 +601,7 @@ public partial class ChatWindow : Window
|
||||
|
||||
private void Settings_SettingsChanged(object? sender, EventArgs e)
|
||||
{
|
||||
if (_forceClose || !IsLoaded || _isRefreshingFromSettings)
|
||||
if (_forceClose || !IsLoaded || _isRefreshingFromSettings || _suppressSettingsRefreshForSessionSave)
|
||||
return;
|
||||
|
||||
Dispatcher.BeginInvoke(new Action(() =>
|
||||
@@ -1899,13 +1900,20 @@ public partial class ChatWindow : Window
|
||||
|
||||
Services.LogService.Info($"[SwitchTab] START tab={_activeTab}, emptyState={EmptyState.Visibility}, streaming={_isStreaming}");
|
||||
|
||||
// 현재 탭에 실행 중인 대화가 있으면 차단하지 않고 해당 대화를 그대로 보여줍니다.
|
||||
// 현재 탭에 실행 중인 대화가 있더라도, 사용자가 같은 탭 안에서 다른 대화를 선택한 상태라면
|
||||
// 해당 선택을 유지하고 상단 가이드만 background conversation 모드로 보여줍니다.
|
||||
var session = ChatSession;
|
||||
var streamingConversation = GetStreamingConversation(_activeTab);
|
||||
if (_streamingTabs.Contains(_activeTab) && streamingConversation != null)
|
||||
var rememberedConversationId = session?.GetConversationId(_activeTab);
|
||||
var shouldPreferStreamingConversation = _streamingTabs.Contains(_activeTab)
|
||||
&& ChatStreamingUiPolicy.ShouldPreferStreamingConversation(
|
||||
streamingConversation?.Id,
|
||||
rememberedConversationId);
|
||||
if (shouldPreferStreamingConversation && streamingConversation != null)
|
||||
{
|
||||
Services.LogService.Info($"[SwitchTab] STREAMING_CONV path: tab={_activeTab}, convId={streamingConversation.Id[..Math.Min(8, streamingConversation.Id.Length)]}");
|
||||
lock (_convLock)
|
||||
_currentConversation = ChatSession?.SetCurrentConversation(_activeTab, streamingConversation, _storage) ?? streamingConversation;
|
||||
_currentConversation = session?.SetCurrentConversation(_activeTab, streamingConversation, _storage) ?? streamingConversation;
|
||||
SyncTabConversationIdsFromSession();
|
||||
SaveLastConversations();
|
||||
ClearTranscriptElements();
|
||||
@@ -1919,7 +1927,6 @@ public partial class ChatWindow : Window
|
||||
return;
|
||||
}
|
||||
|
||||
var session = ChatSession;
|
||||
if (session != null)
|
||||
{
|
||||
var conv = session.LoadOrCreateConversation(_activeTab, _storage, _settings);
|
||||
@@ -3391,7 +3398,15 @@ public partial class ChatWindow : Window
|
||||
{
|
||||
SyncTabConversationIdsToSession();
|
||||
session.ActiveTab = _activeTab;
|
||||
session.Save(_settings);
|
||||
_suppressSettingsRefreshForSessionSave = true;
|
||||
try
|
||||
{
|
||||
session.Save(_settings);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_suppressSettingsRefreshForSessionSave = false;
|
||||
}
|
||||
SyncTabConversationIdsFromSession();
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user