multica/apps/web/app/hooks/use-hub-store.ts
Naiyuan Qing 403c44f536 refactor(web): unify hub + agent state into single Zustand store
Replace useState-based useHub hook and separate useActiveAgent store
with a single useHubStore (Zustand). This fixes the bug where
HubSidebar and Chat held independent state copies, causing stale data
and duplicate 30s polling. Agent create/delete logic now lives in the
store with automatic activeAgentId management.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 23:15:11 +08:00

75 lines
1.8 KiB
TypeScript

import { create } from "zustand"
import { CONSOLE_URL } from "../lib/config"
interface HubInfo {
hubId: string
url: string
connectionState: string
agentCount: number
}
interface Agent {
id: string
closed: boolean
}
type HubStatus = "idle" | "loading" | "connected" | "error"
interface HubStore {
status: HubStatus
hub: HubInfo | null
agents: Agent[]
activeAgentId: string | null
setActiveAgentId: (id: string | null) => void
fetchHub: () => Promise<void>
fetchAgents: () => Promise<void>
createAgent: () => Promise<void>
deleteAgent: (id: string) => Promise<void>
}
export const useHubStore = create<HubStore>()((set, get) => ({
status: "idle",
hub: null,
agents: [],
activeAgentId: null,
setActiveAgentId: (id) => set({ activeAgentId: id }),
fetchHub: async () => {
set({ status: "loading" })
try {
const res = await fetch(`${CONSOLE_URL}/api/hub`)
if (!res.ok) throw new Error(res.statusText)
const data: HubInfo = await res.json()
set({
hub: data,
status: data.connectionState === "registered" ? "connected" : "error",
})
} catch {
set({ status: "error", hub: null })
}
},
fetchAgents: async () => {
try {
const res = await fetch(`${CONSOLE_URL}/api/agents`)
if (res.ok) set({ agents: await res.json() })
} catch { /* silent */ }
},
createAgent: async () => {
const res = await fetch(`${CONSOLE_URL}/api/agents`, { method: "POST" })
await get().fetchAgents()
if (res.ok) {
const data = await res.json()
if (data.id) set({ activeAgentId: data.id })
}
},
deleteAgent: async (id) => {
if (get().activeAgentId === id) set({ activeAgentId: null })
await fetch(`${CONSOLE_URL}/api/agents/${id}`, { method: "DELETE" })
await get().fetchAgents()
},
}))