diff --git a/src/components/Sidebar.tsx b/src/components/Sidebar.tsx index 8fc1378..1b44747 100644 --- a/src/components/Sidebar.tsx +++ b/src/components/Sidebar.tsx @@ -147,6 +147,9 @@ export function Sidebar({ sessions, activeSession, onSwitch, open, onClose }: Pr {s.isActive && ( )} + {s.hasUnread && !isActive && ( + + )}
diff --git a/src/hooks/useGateway.ts b/src/hooks/useGateway.ts index e8ba502..e045630 100644 --- a/src/hooks/useGateway.ts +++ b/src/hooks/useGateway.ts @@ -41,6 +41,7 @@ export function useGateway() { useEffect(() => { activeSessionRef.current = activeSession; }, [activeSession]); const currentRunIdRef = useRef(null); const [activeSessions, setActiveSessions] = useState>(new Set()); + const [unreadSessions, setUnreadSessions] = useState>(new Set()); const handleAgentEvent = useCallback((payload: JsonPayload) => { if (payload?.stream !== 'tool') return; @@ -241,7 +242,18 @@ export function useGateway() { } } - if (evtSession !== activeSessionRef.current) return; + if (evtSession !== activeSessionRef.current) { + // Mark non-active sessions as unread when they receive a final message + if (state === 'final' && evtSession) { + setUnreadSessions(prev => { + if (prev.has(evtSession)) return prev; + const next = new Set(prev); + next.add(evtSession); + return next; + }); + } + return; + } if (state === 'delta') { const text = extractText(message); @@ -358,6 +370,12 @@ export function useGateway() { setActiveSession(key); activeSessionRef.current = key; setMessages([]); + setUnreadSessions(prev => { + if (!prev.has(key)) return prev; + const next = new Set(prev); + next.delete(key); + return next; + }); loadHistory(key); }, [loadHistory]); @@ -388,6 +406,7 @@ export function useGateway() { const enrichedSessions = sessions.map(s => ({ ...s, isActive: activeSessions.has(s.key), + hasUnread: unreadSessions.has(s.key), })); return { diff --git a/src/types/index.ts b/src/types/index.ts index 516bc8d..550f6d4 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -20,6 +20,7 @@ export interface Session { label?: string; messageCount?: number; isActive?: boolean; + hasUnread?: boolean; totalTokens?: number; contextTokens?: number; inputTokens?: number;