Initial commit: Agentic OS troubleshooting platform

Self-hosted, Docker-based agentic troubleshooting platform: FastAPI backend +
LangGraph agent, Next.js UI, tiered LLM routing (local Ollama -> Gemini ->
DeepSeek -> OpenRouter), MCP server manager, encrypted device credentials,
RBAC, audit log, project-memory + Obsidian integrations, and editable
troubleshooting decision rules tuned for the GeneseasX vessel stack.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-14 22:11:07 +03:00
commit 6185b9b85a
126 changed files with 14565 additions and 0 deletions

View File

@@ -0,0 +1,368 @@
"use client";
import { useMemo, useState } from "react";
import useSWR from "swr";
import AppShell from "@/components/AppShell";
import { PageHeader } from "@/components/ui";
import { api, fetcher } from "@/lib/api";
import { useAuth } from "@/lib/auth";
type CatalogEntry = {
id: string;
backend: string;
model: string;
tier: string;
label: string;
display: string;
input_per_m: number;
output_per_m: number;
};
type RoutingResponse = {
config: {
local_model_id: string;
economy_gemini_id: string;
economy_deepseek_id: string;
economy_openrouter_id: string;
premium_gemini_id: string;
premium_deepseek_id: string;
premium_openrouter_id: string;
cloud_provider_order: string[];
auto_escalate: boolean;
max_tier: string;
};
catalog: Record<string, Record<string, CatalogEntry[]>>;
available_backends: Record<string, boolean>;
strategy: string;
};
type LiveModel = { id: string; label: string; [key: string]: unknown };
type AvailableModelsResponse = {
providers: Record<
string,
{ available: boolean; error?: string; models: LiveModel[]; note?: string }
>;
routing_order: string;
};
const TIER_LABEL: Record<string, string> = {
local: "Local (always tried first)",
economy: "Economy cloud (capable, low cost)",
premium: "Premium cloud (strongest, higher cost)",
};
const PROVIDER_ORDER_OPTIONS = [
{ value: "gemini,deepseek,openrouter", label: "Gemini → DeepSeek → OpenRouter" },
{ value: "gemini,openrouter,deepseek", label: "Gemini → OpenRouter → DeepSeek" },
{ value: "deepseek,gemini,openrouter", label: "DeepSeek → Gemini → OpenRouter" },
{ value: "deepseek,openrouter,gemini", label: "DeepSeek → OpenRouter → Gemini" },
{ value: "openrouter,gemini,deepseek", label: "OpenRouter → Gemini → DeepSeek" },
{ value: "openrouter,deepseek,gemini", label: "OpenRouter → DeepSeek → Gemini" },
];
function priceLabel(m: CatalogEntry) {
if (m.input_per_m === 0 && m.output_per_m === 0) return "free tier eligible";
return `$${m.input_per_m}/${m.output_per_m} per 1M`;
}
export default function ModelsPage() {
const { user } = useAuth();
const { data, mutate } = useSWR<RoutingResponse>("/api/llm/routing", fetcher);
const { data: liveModels } = useSWR<AvailableModelsResponse>(
user?.role === "admin" ? "/api/llm/models/available" : null,
fetcher,
);
const [form, setForm] = useState<RoutingResponse["config"] | null>(null);
const [saving, setSaving] = useState(false);
const [msg, setMsg] = useState<string | null>(null);
const [showLive, setShowLive] = useState(false);
const cfg = form ?? data?.config;
const economyOptions = useMemo(() => {
if (!data) return { gemini: [], deepseek: [], openrouter: [] };
return {
gemini: data.catalog.economy?.gemini || [],
deepseek: data.catalog.economy?.deepseek || [],
openrouter: data.catalog.economy?.openrouter || [],
};
}, [data]);
const premiumOptions = useMemo(() => {
if (!data) return { gemini: [], deepseek: [], openrouter: [] };
return {
gemini: data.catalog.premium?.gemini || [],
deepseek: data.catalog.premium?.deepseek || [],
openrouter: data.catalog.premium?.openrouter || [],
};
}, [data]);
const localOptions = data?.catalog.local?.ollama || [];
const save = async (e: React.FormEvent) => {
e.preventDefault();
if (!cfg) return;
setSaving(true);
setMsg(null);
try {
await api("/api/llm/routing", { method: "PUT", body: JSON.stringify(cfg) });
setMsg("Saved — new tasks will use this routing.");
mutate();
} catch (err: any) {
setMsg(err.message);
} finally {
setSaving(false);
}
};
if (user?.role !== "admin") {
return (
<AppShell>
<PageHeader title="Model routing" subtitle="Admin access required" />
</AppShell>
);
}
return (
<AppShell>
<PageHeader
title="Model routing"
subtitle="Local first, then Gemini → DeepSeek → OpenRouter on escalation"
/>
{data?.strategy && (
<div className="card mb-6 text-sm text-muted">{data.strategy}</div>
)}
<div className="mb-6 flex flex-wrap gap-3">
{Object.entries(data?.available_backends || {}).map(([k, ok]) => (
<span
key={k}
className={`badge ${ok ? "bg-good/20 text-good" : "bg-panel2 text-muted"}`}
>
{k}: {ok ? "available" : "no API key"}
</span>
))}
</div>
{!cfg ? (
<div className="card text-muted">Loading</div>
) : (
<form onSubmit={save} className="space-y-6">
<div className="card">
<h2 className="mb-1 font-semibold">{TIER_LABEL.local}</h2>
<p className="mb-4 text-xs text-muted">Used for triage and first reasoning attempt on every task.</p>
<select
className="input"
value={cfg.local_model_id}
onChange={(e) => setForm({ ...cfg, local_model_id: e.target.value })}
>
{localOptions.map((m) => (
<option key={m.id} value={m.id}>
{m.label} ({m.model}) free
</option>
))}
</select>
</div>
<div className="card">
<h2 className="mb-1 font-semibold">{TIER_LABEL.economy}</h2>
<p className="mb-4 text-xs text-muted">
Escalation target for medium complexity, partial diagnostic failures, or follow-up runs.
</p>
<div className="grid gap-4 md:grid-cols-3">
<div>
<label className="label">Gemini economy</label>
<select
className="input"
value={cfg.economy_gemini_id}
disabled={!data?.available_backends.gemini}
onChange={(e) => setForm({ ...cfg, economy_gemini_id: e.target.value })}
>
{economyOptions.gemini.map((m) => (
<option key={m.id} value={m.id}>
{m.label} {priceLabel(m)}
</option>
))}
</select>
</div>
<div>
<label className="label">DeepSeek economy</label>
<select
className="input"
value={cfg.economy_deepseek_id}
disabled={!data?.available_backends.deepseek}
onChange={(e) => setForm({ ...cfg, economy_deepseek_id: e.target.value })}
>
{economyOptions.deepseek.map((m) => (
<option key={m.id} value={m.id}>
{m.label} {priceLabel(m)}
</option>
))}
</select>
</div>
<div>
<label className="label">OpenRouter economy</label>
<select
className="input"
value={cfg.economy_openrouter_id}
disabled={!data?.available_backends.openrouter}
onChange={(e) => setForm({ ...cfg, economy_openrouter_id: e.target.value })}
>
{economyOptions.openrouter.map((m) => (
<option key={m.id} value={m.id}>
{m.label} {priceLabel(m)}
</option>
))}
</select>
</div>
</div>
</div>
<div className="card">
<h2 className="mb-1 font-semibold">{TIER_LABEL.premium}</h2>
<p className="mb-4 text-xs text-muted">
Used for critical severity, many diagnostic failures, or when economy/local models request escalation.
</p>
<div className="grid gap-4 md:grid-cols-3">
<div>
<label className="label">Gemini premium</label>
<select
className="input"
value={cfg.premium_gemini_id}
disabled={!data?.available_backends.gemini}
onChange={(e) => setForm({ ...cfg, premium_gemini_id: e.target.value })}
>
{premiumOptions.gemini.map((m) => (
<option key={m.id} value={m.id}>
{m.label} {priceLabel(m)}
</option>
))}
</select>
</div>
<div>
<label className="label">DeepSeek premium</label>
<select
className="input"
value={cfg.premium_deepseek_id}
disabled={!data?.available_backends.deepseek}
onChange={(e) => setForm({ ...cfg, premium_deepseek_id: e.target.value })}
>
{premiumOptions.deepseek.map((m) => (
<option key={m.id} value={m.id}>
{m.label} {priceLabel(m)}
</option>
))}
</select>
</div>
<div>
<label className="label">OpenRouter premium</label>
<select
className="input"
value={cfg.premium_openrouter_id}
disabled={!data?.available_backends.openrouter}
onChange={(e) => setForm({ ...cfg, premium_openrouter_id: e.target.value })}
>
{premiumOptions.openrouter.map((m) => (
<option key={m.id} value={m.id}>
{m.label} {priceLabel(m)}
</option>
))}
</select>
</div>
</div>
</div>
<div className="card grid gap-4 md:grid-cols-3">
<div>
<label className="label">Cloud provider priority</label>
<select
className="input"
value={cfg.cloud_provider_order.join(",")}
onChange={(e) =>
setForm({ ...cfg, cloud_provider_order: e.target.value.split(",") })
}
>
{PROVIDER_ORDER_OPTIONS.map((opt) => (
<option key={opt.value} value={opt.value}>
{opt.label}
</option>
))}
</select>
</div>
<div>
<label className="label">Max tier (cost cap)</label>
<select
className="input"
value={cfg.max_tier}
onChange={(e) => setForm({ ...cfg, max_tier: e.target.value })}
>
<option value="local">Local only</option>
<option value="economy">Up to economy</option>
<option value="premium">Up to premium</option>
</select>
</div>
<div className="flex items-end">
<label className="flex cursor-pointer items-center gap-2 text-sm">
<input
type="checkbox"
checked={cfg.auto_escalate}
onChange={(e) => setForm({ ...cfg, auto_escalate: e.target.checked })}
className="rounded"
/>
Auto-escalate when local/economy is uncertain
</label>
</div>
</div>
{msg && <div className="text-sm text-muted">{msg}</div>}
<button className="btn-primary" disabled={saving}>
{saving ? "Saving…" : "Save routing config"}
</button>
</form>
)}
{liveModels && (
<div className="card mt-8">
<div className="mb-4 flex items-center justify-between">
<h2 className="font-semibold">Live models from each API</h2>
<button type="button" className="btn-secondary text-sm" onClick={() => setShowLive(!showLive)}>
{showLive ? "Hide" : "Show all"}
</button>
</div>
{!showLive ? (
<p className="text-sm text-muted">
Ollama: {liveModels.providers.ollama?.models?.length ?? 0} · Gemini:{" "}
{liveModels.providers.gemini?.models?.length ?? 0} · DeepSeek:{" "}
{liveModels.providers.deepseek?.models?.length ?? 0} · OpenRouter:{" "}
{liveModels.providers.openrouter?.models?.length ?? 0}
</p>
) : (
<div className="space-y-6">
{Object.entries(liveModels.providers).map(([name, info]) => (
<div key={name}>
<h3 className="mb-2 text-sm font-medium capitalize">
{name}{" "}
<span className={info.available ? "text-good" : "text-muted"}>
({info.available ? `${info.models.length} models` : info.error || "unavailable"})
</span>
</h3>
{info.note && <p className="mb-2 text-xs text-muted">{info.note}</p>}
<ul className="max-h-48 overflow-y-auto text-xs text-muted">
{info.models.map((m) => (
<li key={m.id} className="font-mono">
{m.id}
{m.label !== m.id ? `${m.label}` : ""}
</li>
))}
</ul>
</div>
))}
</div>
)}
</div>
)}
</AppShell>
);
}