Bug Fix: New Chat Removing Old Conversations
Issue
When clicking "New Chat", the old chat was being removed and replaced with the new one, instead of adding the new conversation to the existing list.
Root Cause
The bug had two problems:
Problem 1: Naive Sync Logic
The syncConversationsFromMongoDB() function was doing a naive replacement:
// OLD (BROKEN) CODE:
conversations: [...mongoConversations, ...localOnly]
This completely replaced the conversation list with:
- All MongoDB conversations (fresh from API)
- Local-only conversations (not yet in MongoDB)
Issues:
- Lost the order of conversations
- Discarded any local changes/messages not yet synced
- Could cause race conditions during rapid operations
Problem 2: No Immediate Local Update
When creating a new conversation in MongoDB mode:
// OLD FLOW:
1. Create in MongoDB → GET ID
2. Call syncConversationsFromMongoDB() → Replace entire list
3. Redirect to new conversation
The sync operation would fetch ALL conversations from MongoDB and replace the local store, potentially losing:
- Conversations with unsaved messages
- Recently created conversations
- Local-only conversations
Solution
Fix 1: Intelligent Merge in Sync
Changed syncConversationsFromMongoDB() to merge intelligently:
// NEW (FIXED) CODE:
// 1. Create maps for fast lookup
const existingMap = new Map(state.conversations.map((c) => [c.id, c]));
// 2. Merge: Update existing conversations, add new ones
mongoConversations.forEach((mongoConv) => {
const existing = existingMap.get(mongoConv.id);
if (existing) {
// Keep local messages/events, update metadata from MongoDB
merged.push({
...existing,
title: mongoConv.title,
updatedAt: mongoConv.updatedAt,
// Keep existing messages and events!
});
} else {
merged.push(mongoConv);
}
});
// 3. Add any local-only conversations
state.conversations.forEach((localConv) => {
if (!processedIds.has(localConv.id)) {
merged.push(localConv);
}
});
// 4. Sort by most recent first
merged.sort((a, b) => b.updatedAt.getTime() - a.updatedAt.getTime());
Benefits:
- ✅ Preserves existing conversations
- ✅ Keeps local messages and events
- ✅ Adds new conversations from MongoDB
- ✅ Maintains proper sort order
- ✅ No data loss
Fix 2: Immediate Local Store Update
Changed the new chat creation flow:
// NEW FLOW:
1. Create in MongoDB → GET ID
2. Add to local store IMMEDIATELY
3. Redirect to new conversation
// Sync happens later asynchronously
// Add to local store immediately
const newConversation = {
id: conversation._id,
title: conversation.title,
createdAt: new Date(conversation.created_at),
updatedAt: new Date(conversation.updated_at),
messages: [],
a2aEvents: [],
};
useChatStore.setState((state) => ({
conversations: [newConversation, ...state.conversations],
activeConversationId: conversation._id,
}));
Benefits:
- ✅ Instant UI update
- ✅ New conversation appears in sidebar immediately
- ✅ Old conversations remain visible
- ✅ No delay waiting for sync
Testing
Test Case 1: Create Multiple Conversations
Before (Broken):
1. Have conversation "Chat 1"
2. Click "New Chat"
3. ❌ "Chat 1" disappears
4. ❌ Only "New Conversation" visible
After (Fixed):
1. Have conversation "Chat 1"
2. Click "New Chat"
3. ✅ "Chat 1" still visible
4. ✅ "New Conversation" added at top
5. ✅ Both conversations in sidebar
Test Case 2: Rapid New Chats
Before (Broken):
1. Click "New Chat" → Creates Chat A
2. Quickly click "New Chat" again → Creates Chat B
3. ❌ Chat A might disappear
4. ❌ Only Chat B visible
After (Fixed):
1. Click "New Chat" → Creates Chat A
2. Quickly click "New Chat" again → Creates Chat B
3. ✅ Both Chat A and Chat B visible
4. ✅ Proper chronological order
Test Case 3: MongoDB Sync with Local Conversations
Before (Broken):
1. Create "Local Chat" (localStorage only)
2. Enable MongoDB
3. Create "MongoDB Chat"
4. ❌ "Local Chat" might disappear during sync
After (Fixed):
1. Create "Local Chat" (localStorage only)
2. Enable MongoDB
3. Create "MongoDB Chat"
4. ✅ Both chats remain visible
5. ✅ "Local Chat" marked as local-only
6. ✅ "MongoDB Chat" synced to backend
Code Changes
File: ui/src/store/chat-store.ts
Changed: syncConversationsFromMongoDB() method
- Lines 389-397 (old: naive replacement)
- Lines 389-428 (new: intelligent merge)
Impact: Better merge logic preserves all conversations
File: ui/src/app/(app)/chat/page.tsx
Changed: New conversation creation flow
- Lines 27-42 (old: create + sync)
- Lines 27-52 (new: create + immediate local update)
Impact: Instant UI update, no data loss
Edge Cases Handled
- Race Conditions: Multiple rapid "New Chat" clicks
- Sync Timing: Conversation created during sync operation
- Local vs MongoDB: Conversations in different storage layers
- Order Preservation: Most recent conversations first
- Message Retention: Local messages preserved during sync
Performance Impact
Before:
- Sync operation: O(n) replacement
- UI update: Delayed until sync completes
- Risk: Data loss during sync
After:
- Sync operation: O(n) merge (same complexity, better logic)
- UI update: Immediate (better UX)
- Risk: Zero data loss
Future Improvements
Potential enhancements:
- Optimistic Updates: Show new conversation immediately, sync later
- Conflict Resolution: Handle concurrent edits across devices
- Incremental Sync: Only fetch new/updated conversations
- Local Draft Indicator: Show which conversations have unsaved changes
- Sync Queue: Queue operations during offline mode
Summary
Problem: Creating new chat removed old conversations
Root Cause:
- Sync operation replaced entire list
- No immediate local store update
Solution:
- Intelligent merge preserves existing conversations
- Immediate local update for instant UI feedback
Result:
- ✅ All conversations preserved
- ✅ Proper chronological order
- ✅ Instant UI updates
- ✅ No data loss
- ✅ Better UX
The bug is now fixed! 🎉