import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { addAdminMemoryEntry, addAdminV1Fact, deleteAdminMemoryEntry, deleteAdminV1Fact, generateUserLeaderboardReport, getUserMemory, getUserAnalytics, getUserLeaderboard, refreshTodayLeaderboard, listUserQa, listUserThreadMessages, listUserThreads, replaceAdminMemoryEntry, updateAdminV1Fact, updateAdminV1Section, } from "./api"; import { cancelActiveRun, cancelAllActiveRuns, getMonitorSettings, loadActiveRuns, loadConcurrencySeries, loadTokenSpeedSeries, updateMonitorSettings, type Granularity, } from "./active-runs"; // ── 实时并发监控 (admin) ───────────────────────────────────────────────────── /** Live snapshot of in-flight runs. Polls every `intervalMs` while `enabled`. */ export function useActiveRuns(enabled = true, intervalMs = 4000) { return useQuery({ queryKey: ["admin-active-runs", "live"], queryFn: loadActiveRuns, enabled, refetchInterval: enabled ? intervalMs : false, refetchOnWindowFocus: false, }); } /** 并发量时序 (peak/avg per minute|hour). */ export function useConcurrencySeries( granularity: Granularity, hours: number | undefined, enabled = true, intervalMs = 15000, ) { return useQuery({ queryKey: ["admin-active-runs", "concurrency", granularity, hours ?? null], queryFn: () => loadConcurrencySeries(granularity, hours), enabled, refetchInterval: enabled ? intervalMs : false, refetchOnWindowFocus: false, }); } /** 大模型 token 出字速度时序 (tokens/sec per minute|hour). */ export function useTokenSpeedSeries( granularity: Granularity, hours: number | undefined, enabled = true, intervalMs = 15000, ) { return useQuery({ queryKey: ["admin-active-runs", "token-speed", granularity, hours ?? null], queryFn: () => loadTokenSpeedSeries(granularity, hours), enabled, refetchInterval: enabled ? intervalMs : false, refetchOnWindowFocus: false, }); } export function useCancelActiveRun() { const qc = useQueryClient(); return useMutation({ mutationFn: (runId: string) => cancelActiveRun(runId), onSuccess: () => qc.invalidateQueries({ queryKey: ["admin-active-runs", "live"] }), }); } export function useCancelAllActiveRuns() { const qc = useQueryClient(); return useMutation({ mutationFn: () => cancelAllActiveRuns(), onSuccess: () => qc.invalidateQueries({ queryKey: ["admin-active-runs", "live"] }), }); } export function useMonitorSettings(enabled = true) { return useQuery({ queryKey: ["admin-active-runs", "settings"], queryFn: getMonitorSettings, enabled, refetchOnWindowFocus: false, }); } export function useUpdateMonitorSettings() { const qc = useQueryClient(); return useMutation({ mutationFn: (nextEnabled: boolean) => updateMonitorSettings(nextEnabled), onSuccess: (data) => { qc.setQueryData(["admin-active-runs", "settings"], data); }, }); } export function useUserLeaderboard( range: { since: string; until: string; days?: number; }, limit = 20, ) { return useQuery({ queryKey: [ "admin-activity", "leaderboard", range.since, range.until, limit, ], queryFn: () => getUserLeaderboard(range, limit), refetchInterval: (query) => { const status = query.state.data?.status; return status === "running" || status === "refreshing" ? 3000 : false; }, }); } /** * Force-rebuild today's snapshot, then prime + invalidate the matching * leaderboard query so the page shows the freshly recomputed numbers. */ export function useRefreshTodayLeaderboard() { const qc = useQueryClient(); return useMutation({ mutationFn: ({ range, limit = 20, }: { range: { since: string; until: string; days?: number }; limit?: number; }) => refreshTodayLeaderboard(range, limit), onSuccess: (data, variables) => { qc.setQueryData( [ "admin-activity", "leaderboard", variables.range.since, variables.range.until, variables.limit ?? 20, ], data, ); qc.invalidateQueries({ queryKey: ["admin-activity", "leaderboard"] }); }, }); } export function useUserAnalytics( userId: string | null, range: { since: string; until: string; days?: number }, limit = 20, ) { return useQuery({ queryKey: ["admin-activity", "analytics", userId, range.since, range.until, limit], queryFn: () => getUserAnalytics(userId!, range, limit), enabled: !!userId, }); } export function useGenerateUserLeaderboardReport() { return useMutation({ mutationFn: ({ range, limit, modelName, }: { range: { since: string; until: string; days?: number }; limit?: number; modelName?: string; }) => generateUserLeaderboardReport(range, limit ?? 30, modelName), }); } /** Threads owned by a given user. Disabled until a user is picked. */ export function useUserThreads(userId: string | null) { return useQuery({ queryKey: ["admin-activity", "threads", userId], queryFn: () => listUserThreads(userId!), enabled: !!userId, }); } export function useUserQa( userId: string | null, params: { page: number; pageSize: number; q?: string }, ) { return useQuery({ queryKey: ["admin-activity", "qa", userId, params.page, params.pageSize, params.q ?? ""], queryFn: () => listUserQa(userId!, params), enabled: !!userId, }); } /** Messages of a given thread. Disabled until a thread is picked. */ export function useUserThreadMessages( userId: string | null, threadId: string | null, ) { return useQuery({ queryKey: ["admin-activity", "messages", userId, threadId], queryFn: () => listUserThreadMessages(userId!, threadId!), enabled: !!userId && !!threadId, }); } /** All memory buckets of a given user. Disabled until a user is picked. */ export function useUserMemory(userId: string | null) { return useQuery({ queryKey: ["admin-activity", "memory", userId], queryFn: () => getUserMemory(userId!), enabled: !!userId, }); } function useMemoryInvalidate(userId: string) { const qc = useQueryClient(); return () => qc.invalidateQueries({ queryKey: ["admin-activity", "memory", userId] }); } export function useAdminAddMemoryEntry(userId: string) { const invalidate = useMemoryInvalidate(userId); return useMutation({ mutationFn: ({ content, agent }: { content: string; agent: string | null }) => addAdminMemoryEntry(userId, content, agent), onSuccess: invalidate, }); } export function useAdminReplaceMemoryEntry(userId: string) { const invalidate = useMemoryInvalidate(userId); return useMutation({ mutationFn: ({ oldText, content, agent }: { oldText: string; content: string; agent: string | null }) => replaceAdminMemoryEntry(userId, oldText, content, agent), onSuccess: invalidate, }); } export function useAdminDeleteMemoryEntry(userId: string) { const invalidate = useMemoryInvalidate(userId); return useMutation({ mutationFn: ({ oldText, agent }: { oldText: string; agent: string | null }) => deleteAdminMemoryEntry(userId, oldText, agent), onSuccess: invalidate, }); } // ── V1 CRUD hooks ────────────────────────────────────────────────────────── export function useAdminUpdateV1Section(userId: string) { const invalidate = useMemoryInvalidate(userId); return useMutation({ mutationFn: ({ sectionType, field, summary, agent, }: { sectionType: "user" | "history"; field: string; summary: string; agent: string | null; }) => updateAdminV1Section(userId, sectionType, field, summary, agent), onSuccess: invalidate, }); } export function useAdminAddV1Fact(userId: string) { const invalidate = useMemoryInvalidate(userId); return useMutation({ mutationFn: ({ content, category, confidence, agent, }: { content: string; category: string; confidence: number; agent: string | null; }) => addAdminV1Fact(userId, content, category, confidence, agent), onSuccess: invalidate, }); } export function useAdminUpdateV1Fact(userId: string) { const invalidate = useMemoryInvalidate(userId); return useMutation({ mutationFn: ({ factId, updates, agent, }: { factId: string; updates: { content?: string; category?: string; confidence?: number }; agent: string | null; }) => updateAdminV1Fact(userId, factId, updates, agent), onSuccess: invalidate, }); } export function useAdminDeleteV1Fact(userId: string) { const invalidate = useMemoryInvalidate(userId); return useMutation({ mutationFn: ({ factId, agent }: { factId: string; agent: string | null }) => deleteAdminV1Fact(userId, factId, agent), onSuccess: invalidate, }); }