Feat: Frontend-Overhaul E — Lane-Editor, Routing-Policy (hot-reload) & Latenz-Karte
Teil 1: VoiceLatencyCard auf dem Dashboard (GET /api/voice/metrics, C2) — zeigt STT/Vision/Chat-TTFB/TTS mit p50/p95/last + count. Teil 2: UI-editierbare Routing-Policy. Neuer routing_policy.py (hot-reload JSON unter MODELS_DIR/mc2-routing.json, Env=Defaults, atomarer Write, Validierung). router_logic, gateway_proxy und gateway.routing_summary lesen jetzt live via load_policy(); routing_summary ist lane-bewusst (chat/coding statt altem auto). Neue Endpoints GET/PUT /api/routing/policy. Teil 3: LaneEditor.tsx als ZONE im Cockpit (chat/coding-Aliase + Schwellen + fast_no_think, Speichern/Default-je-Feld); Gateway-Node zeigt die Lanes. Verifiziert: npm run build (tsc strict) clean, FastAPI TestClient (GET/PUT, Validierung, Persistenz, Hot-reload durch die API), venv-Smoke (Routing). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -8,6 +8,7 @@ import { cn } from "@/lib/utils"
|
||||
import { fmtSize, fmtCtx } from "@/lib/format"
|
||||
import { getBrandInfo, ROLES, roleTone } from "@/components/models/ModelBadges"
|
||||
import { SpecDraftModal } from "@/components/models/SpecDraftModal"
|
||||
import { LaneEditor } from "@/components/models/LaneEditor"
|
||||
|
||||
export function Cockpit() {
|
||||
const qc = useQueryClient()
|
||||
@@ -532,17 +533,22 @@ export function Cockpit() {
|
||||
<span>Continue</span>
|
||||
</div>
|
||||
|
||||
{/* COLUMN 2: Central Gateway Node */}
|
||||
<div
|
||||
className="absolute select-none z-10 w-36 py-3 px-4 -translate-y-1/2 -translate-x-1/2 rounded-2xl border border-primary/50 bg-card/90 backdrop-blur-md flex flex-col items-center justify-center text-center shadow-lg shadow-primary/5"
|
||||
{/* COLUMN 2: Central Gateway Node — virtuelle Lanes (Router pickt das echte Modell) */}
|
||||
<div
|
||||
className="absolute select-none z-10 w-40 py-3 px-4 -translate-y-1/2 -translate-x-1/2 rounded-2xl border border-primary/50 bg-card/90 backdrop-blur-md flex flex-col items-center justify-center text-center shadow-lg shadow-primary/5"
|
||||
style={{ left: "50%", top: "50%" }}
|
||||
>
|
||||
<div className="text-[10px] uppercase font-bold text-primary font-space tracking-wide">Gateway Auto</div>
|
||||
<div className="text-[10px] font-mono text-muted-foreground mt-0.5">
|
||||
Schwelle: > {routing?.heavy_threshold_chars ? (routing.heavy_threshold_chars / 1000) : "4"}k Zeichen
|
||||
<div className="text-[10px] uppercase font-bold text-primary font-space tracking-wide">Gateway · Lanes</div>
|
||||
<div className="mt-1 flex flex-col gap-0.5 text-[9px] font-mono text-muted-foreground">
|
||||
{routing?.lanes?.length ? routing.lanes.map((l) => (
|
||||
<span key={l.name}>
|
||||
<span className="text-foreground font-semibold">{l.name}</span>
|
||||
{l.threshold_chars ? ` ›${(l.threshold_chars / 1000).toFixed(0)}k` : l.escalate_chars ? ` ⇧${(l.escalate_chars / 1000).toFixed(0)}k` : ""}
|
||||
</span>
|
||||
)) : <span>chat · coding</span>}
|
||||
</div>
|
||||
<div className="mt-1 px-1.5 py-0.5 rounded bg-primary/10 border border-primary/20 text-[9px] font-semibold text-primary uppercase font-mono">
|
||||
Auto-Swap
|
||||
Router
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -696,6 +702,9 @@ export function Cockpit() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* ZONE B.4: Lane-Routing & Policy (UI-editierbar, hot-reload) */}
|
||||
<LaneEditor />
|
||||
|
||||
{/* ZONE B.5: Slot-Belegung */}
|
||||
<div className="rounded-2xl border border-border/60 bg-card/45 backdrop-blur-md p-5 shadow-lg shadow-black/10 space-y-3.5">
|
||||
<div className="text-xs font-bold uppercase tracking-wider text-muted-foreground px-1">
|
||||
|
||||
Reference in New Issue
Block a user