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;