Remove agent directory syncing, make it pure derived state

Problem: Agent directory was still being synced from SessionProvider to
Zustand store, violating the "SessionProvider is just a message handler"
principle and creating unnecessary state duplication.

Solution: Make agent directory pure derived state:
- Removed agentDirectory from SessionStoreState
- Removed setAgentDirectory/clearAgentDirectory actions
- Changed getAgentDirectory to compute on-demand from session.agents
- Removed buildAgentDirectoryEntries and syncing from SessionProvider
- Updated useAggregatedAgents to derive from sessions directly

How it works now:
- Agent directory is computed on-demand from session.agents Map
- lastActivityAt automatically updates when agents update via WebSocket
- No syncing, no stale state, no overhead
- Single source of truth: session.agents

Benefits:
- Eliminated redundant state (agentDirectory was duplicate of agents)
- No sync overhead or complexity
- Always fresh data (derived on read)
- Simpler mental model (agents is the only source)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Mohamed Boudra
2025-12-02 14:15:32 +00:00
co-authored by Claude
parent f5c6bce54f
commit 8b87b0a4e2
3 changed files with 33 additions and 93 deletions
+1 -28
View File
@@ -137,22 +137,6 @@ function normalizeAgentSnapshot(snapshot: AgentSnapshotPayload, serverId: string
};
}
function buildAgentDirectoryEntries(serverId: string, agents: Map<string, any>): AgentDirectoryEntry[] {
const entries: AgentDirectoryEntry[] = [];
for (const agent of agents.values()) {
entries.push({
id: agent.id,
serverId,
title: agent.title ?? null,
status: agent.status,
lastActivityAt: agent.lastActivityAt,
cwd: agent.cwd,
provider: agent.provider,
});
}
return entries;
}
const createExplorerState = () => ({
directories: new Map(),
files: new Map(),
@@ -231,8 +215,6 @@ export function SessionProvider({ children, serverUrl, serverId }: SessionProvid
// Zustand store actions
const initializeSession = useSessionStore((state) => state.initializeSession);
const clearSession = useSessionStore((state) => state.clearSession);
const setAgentDirectory = useSessionStore((state) => state.setAgentDirectory);
const clearAgentDirectory = useSessionStore((state) => state.clearAgentDirectory);
const setIsPlayingAudio = useSessionStore((state) => state.setIsPlayingAudio);
const setMessages = useSessionStore((state) => state.setMessages);
const setCurrentAssistantMessage = useSessionStore((state) => state.setCurrentAssistantMessage);
@@ -1087,14 +1069,6 @@ export function SessionProvider({ children, serverUrl, serverId }: SessionProvid
};
}, [ws, audioPlayer, serverId, setIsPlayingAudio, setMessages, setCurrentAssistantMessage, setAgentStreamState, setInitializingAgents, setAgents, setCommands, setPendingPermissions, setGitDiffs, setFileExplorer, setProviderModels, setHasHydratedAgents, updateConnectionStatus, getSession, saveDraftInput]);
// Sync agent directory
useEffect(() => {
const session = getSession(serverId);
if (!session) return;
const lightweightAgentDirectory = buildAgentDirectoryEntries(serverId, session.agents);
setAgentDirectory(serverId, lightweightAgentDirectory);
}, [serverId, getSession, setAgentDirectory]);
// Auto-flush queued messages when agent transitions from running -> not running
useEffect(() => {
const session = getSession(serverId);
@@ -1546,9 +1520,8 @@ export function SessionProvider({ children, serverUrl, serverId }: SessionProvid
useEffect(() => {
return () => {
clearSession(serverId);
clearAgentDirectory(serverId);
};
}, [serverId, clearSession, clearAgentDirectory]);
}, [serverId, clearSession]);
const value = useMemo<SessionContextValue>(
() => ({