// Zentrale Daten-Hooks (TanStack Query). Kapseln lib/api.ts und liefern Caching, // Dedup (gleicher queryKey = eine Anfrage über alle Views), Retry und Polling. // Mutations invalidieren gezielt die betroffenen Keys, statt manuell neu zu laden. import { useQuery, useQueryClient, type QueryClient } from "@tanstack/react-query" import { api, type AgentStatus, type ConnectResp, type ConnectHealth, type DiscoverResp, type DraftsResp, type GroupsResp, type HermesBrainResp, type Health, type Job, type Memory, type MemoryGraph, type ModelsResp, type RoutingResp, type RoutingPolicyMeta, type ServicesResp, type SystemStatus, type TokenStats, type UpdatesResp, type VoiceMetrics, } from "./api" // Zentrale Query-Keys (eine Quelle der Wahrheit für invalidate). export const qk = { health: ["health"] as const, systemStatus: ["system-status"] as const, services: ["services"] as const, models: ["models"] as const, groups: ["groups"] as const, routing: ["routing"] as const, routingPolicy: ["routing-policy"] as const, voiceMetrics: ["voice-metrics"] as const, jobs: ["jobs"] as const, tokenStats: ["token-stats"] as const, agentStatus: ["agent-status"] as const, hermesBrain: ["hermes-brain"] as const, updates: ["updates"] as const, discover: ["discover"] as const, drafts: (target?: string) => ["drafts", target ?? ""] as const, connect: (params?: string) => ["connect", params ?? ""] as const, connectHealth: ["connect-health"] as const, memory: (q?: string, category?: string) => ["memory", q ?? "", category ?? ""] as const, memoryGraph: ["memory-graph"] as const, } export const useMemoryGraph = (enabled = true) => useQuery({ queryKey: qk.memoryGraph, queryFn: () => api("/api/memory/graph"), enabled, }) export const useHealth = () => useQuery({ queryKey: qk.health, queryFn: () => api("/api/health"), refetchInterval: 10_000 }) export const useSystemStatus = (refetchInterval = 5_000) => useQuery({ queryKey: qk.systemStatus, queryFn: () => api("/api/system/status"), refetchInterval }) export const useServices = (refetchInterval = 3_000) => useQuery({ queryKey: qk.services, queryFn: () => api("/api/system/services"), refetchInterval }) export const useModels = (refetchInterval = 4_000) => useQuery({ queryKey: qk.models, queryFn: () => api("/api/models"), refetchInterval }) export const useGroups = (refetchInterval = 8_000) => useQuery({ queryKey: qk.groups, queryFn: () => api("/api/groups"), refetchInterval }) export const useRouting = (refetchInterval = 4_000) => useQuery({ queryKey: qk.routing, queryFn: () => api("/api/routing"), refetchInterval }) export const useVoiceMetrics = (refetchInterval = 5_000) => useQuery({ queryKey: qk.voiceMetrics, queryFn: () => api("/api/voice/metrics"), refetchInterval }) export const useRoutingPolicy = () => useQuery({ queryKey: qk.routingPolicy, queryFn: () => api("/api/routing/policy") }) export const useJobs = (refetchInterval = 2_000) => useQuery({ queryKey: qk.jobs, queryFn: () => api<{ jobs: Job[] }>("/api/jobs"), refetchInterval, select: (d) => d.jobs ?? [], }) export const useTokenStats = (refetchInterval = 3_000) => useQuery({ queryKey: qk.tokenStats, queryFn: () => api("/api/system/token-stats"), refetchInterval }) export const useAgentStatus = (refetchInterval = 5_000) => useQuery({ queryKey: qk.agentStatus, queryFn: () => api("/api/agent/status"), refetchInterval }) // Agent-Hirn (Hermes) + bestes NousResearch-Update. Selten pollen (HF-Abfrage). export const useHermesBrain = (refetchInterval = 60_000) => useQuery({ queryKey: qk.hermesBrain, queryFn: () => api("/api/agent/brain"), refetchInterval }) export const useUpdates = (refetchInterval?: number) => useQuery({ queryKey: qk.updates, queryFn: () => api("/api/maintenance/updates"), refetchInterval }) export const useDiscover = () => useQuery({ queryKey: qk.discover, queryFn: () => api("/api/discover") }) // Verfügbare Spec-Draft-Modelle + Vocab-Kompatibilität zum Ziel-Modell (GGUF-Pfad). export const useDrafts = (target?: string) => useQuery({ queryKey: qk.drafts(target), queryFn: () => api(`/api/models/drafts?target=${encodeURIComponent(target ?? "")}`), enabled: !!target, }) export const useConnect = (params?: string) => useQuery({ queryKey: qk.connect(params), queryFn: () => api(params ? `/api/connect?${params}` : "/api/connect"), }) // Live-Status der zwei Leitungen (Gateway + Gedächtnis) — alle 15s aktualisiert. export const useConnectHealth = () => useQuery({ queryKey: qk.connectHealth, queryFn: () => api("/api/connect/health"), refetchInterval: 15000, }) export const useMemory = (opts?: { q?: string; category?: string; limit?: number }) => useQuery({ queryKey: qk.memory(opts?.q, opts?.category), queryFn: () => { const p = new URLSearchParams() if (opts?.q) p.set("q", opts.q) if (opts?.category) p.set("category", opts.category) return api(`/api/memory?${p}`) }, select: (d) => (opts?.limit ? d.slice(0, opts.limit) : d), }) /** Nach Mutationen die betroffenen Listen-Queries neu ziehen. */ export function invalidate(qc: QueryClient, ...keys: readonly unknown[][]) { for (const key of keys) qc.invalidateQueries({ queryKey: key }) } export { useQueryClient }