탭 전환 빈 대화 누적 방지: 저장 게이트 + 목록 노이즈 필터
Some checks failed
Release Gate / gate (push) Has been cancelled

- ChatSessionStateService.SaveCurrentConversation에 persistable-content 검사 추가

- 무의미한 빈 새 대화는 저장/탭 기억 대상에서 제외

- ChatWindow 대화 목록에서 빈 노이즈 항목 필터링

- ChatSessionStateServiceTests 회귀 추가 및 문서 이력(2026-04-04 15:48 KST) 동기화
This commit is contained in:
2026-04-04 15:49:12 +09:00
parent 73a4111100
commit f8669c735d
5 changed files with 162 additions and 7 deletions

View File

@@ -91,6 +91,7 @@ public sealed class ChatSessionStateService
{
var normalizedTab = NormalizeTab(tab);
var rememberedId = GetConversationId(normalizedTab);
var hadRememberedConversation = !string.IsNullOrWhiteSpace(rememberedId);
if (!string.IsNullOrWhiteSpace(rememberedId))
{
var loaded = storage.Load(rememberedId);
@@ -115,6 +116,30 @@ public sealed class ChatSessionStateService
RememberConversation(normalizedTab, null);
}
if (!hadRememberedConversation)
{
var latestMeta = storage.LoadAllMeta()
.Where(c => string.Equals(NormalizeTab(c.Tab), normalizedTab, StringComparison.OrdinalIgnoreCase))
.OrderByDescending(c => c.Pinned)
.ThenByDescending(c => c.UpdatedAt)
.FirstOrDefault();
if (latestMeta != null)
{
var loaded = storage.Load(latestMeta.Id);
if (loaded != null)
{
loaded.Tab = normalizedTab;
var normalized = NormalizeLoadedConversation(loaded);
CurrentConversation = loaded;
RememberConversation(normalizedTab, loaded.Id);
if (normalized)
try { storage.Save(loaded); } catch { }
return loaded;
}
}
}
RememberConversation(normalizedTab, null);
return CreateFreshConversation(normalizedTab, settings);
}
@@ -209,13 +234,15 @@ public sealed class ChatSessionStateService
var conv = CurrentConversation;
if (conv == null) return;
try { storage.Save(conv); } catch { }
var conversationTab = NormalizeTab(conv.Tab);
if (conv.Messages.Count > 0
|| (conv.ExecutionEvents?.Count ?? 0) > 0
|| (conv.AgentRunHistory?.Count ?? 0) > 0
|| (conv.DraftQueueItems?.Count ?? 0) > 0)
RememberConversation(conversationTab, conv.Id);
if (!HasPersistableContent(conv))
{
RememberConversation(conversationTab, null);
return;
}
try { storage.Save(conv); } catch { }
RememberConversation(conversationTab, conv.Id);
}
public void ClearCurrentConversation(string tab)
@@ -571,6 +598,26 @@ public sealed class ChatSessionStateService
return "Chat";
}
private static bool HasPersistableContent(ChatConversation conv)
{
if ((conv.Messages?.Count ?? 0) > 0) return true;
if ((conv.ExecutionEvents?.Count ?? 0) > 0) return true;
if ((conv.AgentRunHistory?.Count ?? 0) > 0) return true;
if ((conv.DraftQueueItems?.Count ?? 0) > 0) return true;
if (conv.Pinned) return true;
if (!string.IsNullOrWhiteSpace(conv.WorkFolder)) return true;
if (!string.IsNullOrWhiteSpace(conv.SystemCommand)) return true;
if (!string.IsNullOrWhiteSpace(conv.ParentId)) return true;
if (!string.IsNullOrWhiteSpace(conv.Permission)) return true;
if (!string.IsNullOrWhiteSpace(conv.DataUsage)) return true;
if (!string.IsNullOrWhiteSpace(conv.OutputFormat)) return true;
if (!string.IsNullOrWhiteSpace(conv.Mood)) return true;
if (!string.IsNullOrWhiteSpace(conv.Preview)) return true;
if (!string.Equals(conv.Category, ChatCategory.General, StringComparison.OrdinalIgnoreCase)) return true;
if (!string.Equals((conv.Title ?? "").Trim(), "새 대화", StringComparison.OrdinalIgnoreCase)) return true;
return false;
}
private static bool NormalizeLoadedConversation(ChatConversation conversation)
{
var changed = false;