diff --git a/src/pages/Chat/ChatMessage.tsx b/src/pages/Chat/ChatMessage.tsx
index 8de44b0e2..416bcd6b6 100644
--- a/src/pages/Chat/ChatMessage.tsx
+++ b/src/pages/Chat/ChatMessage.tsx
@@ -346,9 +346,9 @@ function MessageBubble({
)}
>
{isUser ? (
-
{text}
+ {text}
) : (
-
+
+
{children}
);
@@ -372,7 +372,7 @@ function MessageBubble({
},
a({ href, children }) {
return (
-
+
{children}
);
diff --git a/src/pages/Chat/index.tsx b/src/pages/Chat/index.tsx
index 4a2c65d2a..cfc2e99fc 100644
--- a/src/pages/Chat/index.tsx
+++ b/src/pages/Chat/index.tsx
@@ -35,6 +35,8 @@ export function Chat() {
const abortRun = useChatStore((s) => s.abortRun);
const clearError = useChatStore((s) => s.clearError);
+ const cleanupEmptySession = useChatStore((s) => s.cleanupEmptySession);
+
const messagesEndRef = useRef(null);
const [streamingTimestamp, setStreamingTimestamp] = useState(0);
@@ -54,8 +56,11 @@ export function Chat() {
})();
return () => {
cancelled = true;
+ // If the user navigates away without sending any messages, remove the
+ // empty session so it doesn't linger as a ghost entry in the sidebar.
+ cleanupEmptySession();
};
- }, [isGatewayRunning, loadHistory, loadSessions]);
+ }, [isGatewayRunning, loadHistory, loadSessions, cleanupEmptySession]);
// Auto-scroll on new messages, streaming, or activity changes
useEffect(() => {
diff --git a/src/stores/chat.ts b/src/stores/chat.ts
index 62ebf1e62..54c14cac5 100644
--- a/src/stores/chat.ts
+++ b/src/stores/chat.ts
@@ -99,6 +99,7 @@ interface ChatState {
switchSession: (key: string) => void;
newSession: () => void;
deleteSession: (key: string) => Promise;
+ cleanupEmptySession: () => void;
loadHistory: (quiet?: boolean) => Promise;
sendMessage: (text: string, attachments?: Array<{ fileName: string; mimeType: string; fileSize: number; stagedPath: string; preview: string | null }>) => Promise;
abortRun: () => Promise;
@@ -973,8 +974,11 @@ export const useChatStore = create((set, get) => ({
}
}
if (!dedupedSessions.find((s) => s.key === nextSessionKey) && dedupedSessions.length > 0) {
- // Current session not found at all — switch to the first available session
- nextSessionKey = dedupedSessions[0].key;
+ // Current session not found in the backend list
+ const isNewEmptySession = get().messages.length === 0;
+ if (!isNewEmptySession) {
+ nextSessionKey = dedupedSessions[0].key;
+ }
}
const sessionsWithCurrent = !dedupedSessions.find((s) => s.key === nextSessionKey) && nextSessionKey
@@ -1153,6 +1157,27 @@ export const useChatStore = create((set, get) => ({
}));
},
+ // ── Cleanup empty session on navigate away ──
+
+ cleanupEmptySession: () => {
+ const { currentSessionKey, messages } = get();
+ // Only remove non-main sessions that were never used (no messages sent).
+ // This mirrors the "leavingEmpty" logic in switchSession so that creating
+ // a new session and immediately navigating away doesn't leave a ghost entry
+ // in the sidebar.
+ const isEmptyNonMain = !currentSessionKey.endsWith(':main') && messages.length === 0;
+ if (!isEmptyNonMain) return;
+ set((s) => ({
+ sessions: s.sessions.filter((sess) => sess.key !== currentSessionKey),
+ sessionLabels: Object.fromEntries(
+ Object.entries(s.sessionLabels).filter(([k]) => k !== currentSessionKey),
+ ),
+ sessionLastActivity: Object.fromEntries(
+ Object.entries(s.sessionLastActivity).filter(([k]) => k !== currentSessionKey),
+ ),
+ }));
+ },
+
// ── Load chat history ──
loadHistory: async (quiet = false) => {