feat(FN-4854): complete Step 2 — hydrate agents cache

Fusion-Task-Id: FN-4854
Fusion-Task-Lineage: 969ec04a-efe3-4dee-b183-2d4f2de6b388
This commit is contained in:
Fusion (runfusion.ai)
2026-05-17 00:22:40 -07:00
committed by gsxdsm
parent 228daa8f35
commit 0f9c08ace7
2 changed files with 19 additions and 4 deletions

View File

@@ -45,6 +45,7 @@ describe("useAgents", () => {
beforeEach(() => { beforeEach(() => {
MockEventSource.instances = []; MockEventSource.instances = [];
window.sessionStorage.clear(); window.sessionStorage.clear();
window.localStorage.clear();
mockFetchAgents.mockReset().mockResolvedValue([]); mockFetchAgents.mockReset().mockResolvedValue([]);
mockFetchAgentStats.mockReset().mockResolvedValue(defaultStats); mockFetchAgentStats.mockReset().mockResolvedValue(defaultStats);
vi.spyOn(console, "error").mockImplementation(() => {}); vi.spyOn(console, "error").mockImplementation(() => {});

View File

@@ -1,8 +1,9 @@
import { useState, useEffect, useCallback } from "react"; import { useState, useEffect, useCallback, useRef } from "react";
import type { Agent, AgentState, AgentCapability, AgentStats } from "../api"; import type { Agent, AgentState, AgentCapability, AgentStats } from "../api";
import { fetchAgents, fetchAgentStats } from "../api"; import { fetchAgents, fetchAgentStats } from "../api";
import { isEphemeralAgent } from "@fusion/core"; import { isEphemeralAgent } from "@fusion/core";
import { subscribeSse } from "../sse-bus"; import { subscribeSse } from "../sse-bus";
import { readCache, SWR_CACHE_KEYS, writeCache } from "../utils/swrCache";
interface UseAgentsOptions { interface UseAgentsOptions {
filterState?: AgentState | "all"; filterState?: AgentState | "all";
@@ -16,12 +17,21 @@ interface AgentFilter {
} }
export function useAgents(projectId?: string, options?: UseAgentsOptions) { export function useAgents(projectId?: string, options?: UseAgentsOptions) {
const [agents, setAgents] = useState<Agent[]>([]); const [agents, setAgents] = useState<Agent[]>(() => {
const [stats, setStats] = useState<AgentStats | null>(null); const cached = readCache<Agent[]>(SWR_CACHE_KEYS.AGENTS);
return Array.isArray(cached) ? cached : [];
});
const [stats, setStats] = useState<AgentStats | null>(() => {
const cached = readCache<AgentStats>(SWR_CACHE_KEYS.AGENT_STATS);
return cached ?? null;
});
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const hasCachedHydrationRef = useRef(agents.length > 0 || stats !== null);
const loadAgents = useCallback(async (filter?: AgentFilter) => { const loadAgents = useCallback(async (filter?: AgentFilter) => {
setIsLoading(true); if (!hasCachedHydrationRef.current) {
setIsLoading(true);
}
try { try {
const filterState = options?.filterState; const filterState = options?.filterState;
const baseFilter = filterState && filterState !== "all" ? { state: filterState } : undefined; const baseFilter = filterState && filterState !== "all" ? { state: filterState } : undefined;
@@ -40,6 +50,8 @@ export function useAgents(projectId?: string, options?: UseAgentsOptions) {
// with duplicate-key warnings until the dashboard runs out of heap. // with duplicate-key warnings until the dashboard runs out of heap.
const unique = Array.from(new Map(data.map((a) => [a.id, a])).values()); const unique = Array.from(new Map(data.map((a) => [a.id, a])).values());
setAgents(unique); setAgents(unique);
writeCache(SWR_CACHE_KEYS.AGENTS, unique, { maxBytes: 500_000 });
hasCachedHydrationRef.current = hasCachedHydrationRef.current || unique.length > 0;
} catch (err) { } catch (err) {
console.error("Failed to load agents:", err); console.error("Failed to load agents:", err);
} finally { } finally {
@@ -51,6 +63,8 @@ export function useAgents(projectId?: string, options?: UseAgentsOptions) {
try { try {
const data = await fetchAgentStats(projectId); const data = await fetchAgentStats(projectId);
setStats(data); setStats(data);
writeCache(SWR_CACHE_KEYS.AGENT_STATS, data, { maxBytes: 500_000 });
hasCachedHydrationRef.current = true;
} catch (err) { } catch (err) {
console.error("Failed to load agent stats:", err); console.error("Failed to load agent stats:", err);
} }