import { useEffect, useState } from "react" import { Sliders, RotateCcw, Check, Loader2, MessageSquare, Code2 } from "lucide-react" import { updateRoutingPolicy, type RoutingPolicy } from "@/lib/api" import { useRoutingPolicy, useQueryClient, qk } from "@/lib/queries" import { cn } from "@/lib/utils" // Welche Policy-Felder zu welcher Lane gehören (Rest ist global). const CHAT_FIELDS: (keyof RoutingPolicy)[] = ["fast", "heavy", "heavy_chars"] const CODING_FIELDS: (keyof RoutingPolicy)[] = ["coder_lite", "coder", "coding_escalate_chars"] export function LaneEditor() { const qc = useQueryClient() const { data: meta, isLoading } = useRoutingPolicy() const [draft, setDraft] = useState(null) const [saving, setSaving] = useState(false) const [err, setErr] = useState("") const [savedAt, setSavedAt] = useState(0) // Draft initialisieren, sobald die Policy geladen ist (und nicht überschreiben, wenn schon editiert). useEffect(() => { if (meta?.policy && !draft) setDraft({ ...meta.policy }) }, [meta, draft]) if (isLoading || !meta || !draft) { return (
Lade Routing-Policy…
) } const fieldSpec = (key: keyof RoutingPolicy) => meta.fields.find((f) => f.key === key)! const dirty = (Object.keys(draft) as (keyof RoutingPolicy)[]).some((k) => draft[k] !== meta.policy[k]) const set = (key: K, value: RoutingPolicy[K]) => { setDraft((d) => (d ? { ...d, [key]: value } : d)) setErr("") } const resetField = (key: keyof RoutingPolicy) => set(key, meta.defaults[key]) async function save() { if (!draft) return const patch: Partial = {} for (const k of Object.keys(draft) as (keyof RoutingPolicy)[]) { if (draft[k] !== meta!.policy[k]) (patch as any)[k] = draft[k] } if (Object.keys(patch).length === 0) return setSaving(true) setErr("") try { const { policy } = await updateRoutingPolicy(patch) setDraft({ ...policy }) qc.invalidateQueries({ queryKey: qk.routingPolicy }) qc.invalidateQueries({ queryKey: qk.routing }) setSavedAt(Date.now()) setTimeout(() => setSavedAt(0), 2000) } catch (e: any) { setErr(e.message || String(e)) } finally { setSaving(false) } } function Field({ k }: { k: keyof RoutingPolicy }) { const spec = fieldSpec(k) const val = draft![k] const isDefault = draft![k] === meta!.defaults[k] return (
{!isDefault && ( )}
{spec.type === "bool" ? ( ) : spec.type === "int" ? ( set(k, Number(e.target.value) as any)} className="h-8 w-full rounded-lg border border-border/40 bg-background/40 px-3 font-mono text-[11px] text-foreground outline-none focus:border-primary/50" /> ) : ( set(k, e.target.value as any)} className="h-8 w-full rounded-lg border border-border/40 bg-background/40 px-3 font-mono text-[11px] text-foreground outline-none focus:border-primary/50" /> )}
) } return (
Lane-Routing & Policy hot-reload
{err && {err}} {savedAt > 0 && ( gespeichert )}

Welches echte Modell hinter den virtuellen Lanes chat und{" "} coding steckt. Änderungen greifen sofort (kein Neustart). Die Keyword-Heuristiken bleiben im Code.

{/* chat-Lane */}
chat (= auto)
{CHAT_FIELDS.map((k) => )}
{/* coding-Lane */}
coding (agentisch → immer Coder)
{CODING_FIELDS.map((k) => )}
{/* Globale Schalter */}
) }