"use client"; import { useState } from "react"; import { useQuery, useQueryClient } from "@tanstack/react-query"; import { api } from "@/lib/client/api"; import { toast } from "@/components/ui/toast"; import { Spinner } from "@/components/ui/primitives"; import { ProviderCards } from "./ProviderCards"; import { CatalogueTable } from "./CatalogueTable"; import { Heatmap } from "./Heatmap"; import { Scatter } from "./Scatter"; import { RoutingTable } from "./RoutingTable"; import { UsagePanel, type UsagePayload } from "./UsagePanel"; import { Provenance } from "./Provenance"; import { hasBench, type ModelsPayload, type RouteDef } from "./format"; const SECTIONS = [["providers", "Providers"], ["catalogue", "Catalogue"], ["heatmap", "Per-task heatmap"], ["scatter", "Trade-offs"], ["routing", "Routing"], ["usage", "Usage"], ["provenance", "Provenance"]] as const; function Section({ id, title, hint, children }: { id: string; title: string; hint?: string; children: React.ReactNode }) { return {title}{hint && {hint}}{children}; } export function ModelsDashboard() { const qc = useQueryClient(); const [discovering, setDiscovering] = useState(false); const [saving, setSaving] = useState(false); const { data, isLoading, error } = useQuery({ queryKey: ["ai-models", "all"], queryFn: () => api("/api/ai/models?all=1"), staleTime: 30_000 }); const { data: usage } = useQuery({ queryKey: ["ai-usage", 30], queryFn: () => api("/api/ai/usage?days=30"), staleTime: 30_000 }); const refresh = () => { qc.invalidateQueries({ queryKey: ["ai-models"] }); }; async function discover() { setDiscovering(true); try { const r = await api("/api/ai/models", { method: "POST", json: { action: "discover" } }); toast("Discovery finished", { description: Object.entries(r).map(([p, v]: any) => `${p}: ${v.status}${v.listed ? ` (${v.listed} listed)` : ""}`).join(" · "), tone: "success" }); refresh(); } catch (e: any) { toast("Discovery failed", { description: e.message, tone: "danger" }); } finally { setDiscovering(false); } } async function toggle(id: string, enabled: boolean) { qc.setQueryData(["ai-models", "all"], (d) => d && { ...d, models: d.models.map((m) => (m.id === id ? { ...m, enabled } : m)) }); try { await api("/api/ai/models", { method: "POST", json: { action: "toggle", id, enabled } }); refresh(); } catch (e: any) { toast("Could not update model", { description: e.message, tone: "danger" }); refresh(); } } async function saveRoutes(routes: Record) { setSaving(true); try { await api("/api/ai/models", { method: "POST", json: { action: "routes", routes } }); toast("Routes saved", { tone: "success" }); refresh(); } catch (e: any) { toast("Could not save routes", { description: e.message, tone: "danger" }); } finally { setSaving(false); } } async function saveBudget(usd: number) { try { await api("/api/ai/models", { method: "POST", json: { action: "budget", usd } }); toast(`Daily budget set to $${usd}`, { tone: "success" }); } catch (e: any) { toast("Could not save budget", { description: e.message, tone: "danger" }); } } if (isLoading) return ; if (error || !data) return Could not load the model catalogue{error ? `: ${(error as Error).message}` : ""}.; const benchmarked = data.models.filter(hasBench); const text = data.models.filter((m) => m.category !== "embedding"); const highlights = [...new Set(Object.values(data.routes).map((r) => r.primary))]; const pricing = { openai: data.models.find((m) => m.provider === "openai" && m.pricingSource)?.pricingSource, anthropic: data.models.find((m) => m.provider === "anthropic" && m.pricingSource)?.pricingSource }; return ( AI models{text.length} text models in the catalogue · {benchmarked.length} benchmarked on {data.benchmark?.runs ?? 0} real runs · routing decided from measurements, not marketing. {SECTIONS.map(([id, l]) => {l})} Latency vs scoreCost per run vs score ); }
{text.length} text models in the catalogue · {benchmarked.length} benchmarked on {data.benchmark?.runs ?? 0} real runs · routing decided from measurements, not marketing.