"use client"; import { useState, useEffect } from "react"; export interface ModelMapping { id: string; pattern: string; comboId: string; comboName?: string; priority: number; enabled: boolean; description: string; } interface Combo { id: string; name: string; } export default function ModelRoutingSection({ combos = [] }: { combos?: Combo[] }) { const [mappings, setMappings] = useState([]); const [loading, setLoading] = useState(true); const [adding, setAdding] = useState(false); const [editingId, setEditingId] = useState(null); // Form state const [pattern, setPattern] = useState(""); const [comboId, setComboId] = useState(""); const [priority, setPriority] = useState(0); const [description, setDescription] = useState(""); const loadMappings = async () => { try { const res = await fetch("/api/model-combo-mappings"); if (res.ok) { const data = await res.json(); return data.mappings || []; } } catch {} return []; }; useEffect(() => { let cancelled = false; loadMappings().then((data) => { if (!cancelled) { setMappings(data); setLoading(false); } }); return () => { cancelled = true; }; }, []); const refetchMappings = async () => { const data = await loadMappings(); setMappings(data); }; const resetForm = () => { setPattern(""); setComboId(""); setPriority(0); setDescription(""); setAdding(false); setEditingId(null); }; const handleSave = async () => { if (!pattern.trim() || !comboId) return; try { if (editingId) { const res = await fetch(`/api/model-combo-mappings/${editingId}`, { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ pattern: pattern.trim(), comboId, priority, description }), }); if (res.ok) await refetchMappings(); } else { const res = await fetch("/api/model-combo-mappings", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ pattern: pattern.trim(), comboId, priority, description }), }); if (res.ok) await refetchMappings(); } } catch {} resetForm(); }; const handleEdit = (m: ModelMapping) => { setPattern(m.pattern); setComboId(m.comboId); setPriority(m.priority); setDescription(m.description); setEditingId(m.id); setAdding(true); }; const handleDelete = async (id: string) => { if (!confirm("Delete this model routing rule?")) return; try { await fetch(`/api/model-combo-mappings/${id}`, { method: "DELETE" }); setMappings((prev) => prev.filter((m) => m.id !== id)); } catch {} }; const handleToggle = async (m: ModelMapping) => { try { const res = await fetch(`/api/model-combo-mappings/${m.id}`, { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ enabled: !m.enabled }), }); if (res.ok) { setMappings((prev) => prev.map((x) => (x.id === m.id ? { ...x, enabled: !x.enabled } : x))); } } catch {} }; return (
route

Model Routing Rules

Automatically route models to specific combos using glob patterns

{!adding && ( )}
{/* Inline form */} {adding && (
setPattern(e.target.value)} placeholder="claude-sonnet*" className="w-full mt-0.5 px-2.5 py-1.5 text-xs rounded-lg border border-black/10 dark:border-white/10 bg-white dark:bg-black/20 focus:outline-none focus:ring-1 focus:ring-primary" />

Use * for any chars, ? for single char. Case-insensitive.

setPriority(Number(e.target.value))} className="w-full mt-0.5 px-2.5 py-1.5 text-xs rounded-lg border border-black/10 dark:border-white/10 bg-white dark:bg-black/20 focus:outline-none focus:ring-1 focus:ring-primary" />

Higher = checked first. Use 10+ for specific patterns.

setDescription(e.target.value)} placeholder="Route Opus models to frontier combo" className="w-full mt-0.5 px-2.5 py-1.5 text-xs rounded-lg border border-black/10 dark:border-white/10 bg-white dark:bg-black/20 focus:outline-none focus:ring-1 focus:ring-primary" />
)} {/* Mappings list */} {loading ? (
Loading...
) : mappings.length === 0 ? (

No routing rules configured. Requests use the global combo by default.

Add a rule like{" "} claude-opus* {" → "} frontier-combo to automatically route requests.

) : (
{mappings.map((m) => (
{m.pattern} {m.comboName || m.comboId.slice(0, 8)} {m.description && ( {m.description} )} P{m.priority}
))}
)}
); }