Single Source of Truth: Frontend/Backend-Ungereimtheiten ausgeraeumt (Review 15.07.)

Backend (Wahrheit reparieren):
- gateway_reachable() prueft jetzt den ECHTEN mc2-gateway (:9010 via V1_UPSTREAM)
  statt nur die Engine - toter Denkpfad war in Health/Cockpit unsichtbar
- /api/system/services vollstaendig: + LLM-Gateway, + Steuerpult, + Waechter
  (mc2-steward via is-active); scope-Feld (user/system); mc2-gateway/mc2-steward
  in die Restart-Allowlist
- Connect-Health Leitung 1 prueft den Client-Pfad (V1_UPSTREAM statt llama-swap)
- agent_status liefert pc_executor_url (UI zeigte hartcodierte IP/Ports)
- SSE-Endlosschleife gefixt: /api/auftragsbuch schrieb announce-branches bei JEDEM
  Aufruf neu -> mtime-Bump -> invalidate -> Refetch im 3-s-Takt je Client;
  jetzt nur noch bei echter Aenderung

Frontend (ein Datenweg):
- SystemDrawer komplett auf React-Query-Hooks (vorher eigenes 3-s-setInterval auf
  dieselben Endpunkte inkl. teurem Updates-Check); Dienste-Liste = Backend-Antwort
  (SERVICES-UI-Kopie geloescht); useDialog statt Eigenbau; fmtBytes statt Duplikat
- useLucyHealth: Dienst-Matching per systemd-unit statt Namensfragment; Gateway-
  Reparatur zielt auf mc2-gateway; neuer Waechter-Check; Backend-tot => ehrliches
  rotes Verdikt statt eingefrorener letzter Stand (auch Sidebar)
- Toter Code raus: views/models/Cockpit.tsx (908 Z.) + RoleAssignModal + Placeholder;
  LaneEditor (Routing-Policy) + WarmSetManager damit ZURUECK im UI als Tab
  "Routing & Warm-Set" im Modell-Manager
- Cockpit: blockierte Ideen-Karten erscheinen in "Braucht dich" + Kachel-Hint;
  Verbinden-Kachel zeigt 3 Leitungen live statt hartem "Zed"
- Maschinenraum: ehrliches "frei" (reale Belegung) + eigenes KV-Cache-Segment
- AgentView: Ports/PC-Adresse aus der API; Guide lehrt Lanes chat/coding
- queries.ts: useModels nutzt SSE-relax; Chronik-Limit im Query-Key;
  useJobs/useZeitmaschine mit enabled-Schalter

Verifiziert: tsc+vite gruen, Backend-Smoke beide Gateway-Modi, UI live gegen die
Box (Cockpit/Werkbank/Routing-Tab/Drawer rendern mit Echtdaten).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Hitonabi
2026-07-15 22:22:27 +02:00
parent b36561990e
commit 0c69c491e5
161 changed files with 1522 additions and 2458 deletions
+46 -10
View File
@@ -14,7 +14,7 @@ from pydantic import BaseModel
import httpx
from config import GATEWAY_URL, HERMES_API_URL, LLAMA_SWAP_URL, MEM0_SERVICE_URL, VOICE_SERVICE_URL
from config import GATEWAY_URL, HERMES_API_URL, LLAMA_SWAP_URL, MEM0_SERVICE_URL, V1_UPSTREAM, VOICE_SERVICE_URL
from services import backup as backup_svc
from services import maintenance
from services.agent import agent_status
@@ -51,20 +51,56 @@ def _voice_reachable() -> bool:
return False
def _user_unit_active(unit: str) -> bool:
"""systemd-User-Unit ohne eigenen HTTP-Port (z. B. mc2-steward) — Zustand via is-active.
Auf Windows/Dev schlägt das harmlos fehl (False)."""
if os.name != "posix":
return False
try:
r = subprocess.run(["systemctl", "--user", "is-active", unit],
capture_output=True, text=True, timeout=3)
return r.stdout.strip() == "active"
except Exception: # noqa: BLE001
return False
@router.get("/system/services")
def services() -> dict:
"""Aggregierte Erreichbarkeit aller Stack-Dienste (für die Health-Anzeige)."""
"""Aggregierte Erreichbarkeit aller Stack-Dienste die EINE Quelle für Cockpit-Kachel,
Schubladen-Liste und Log-Auswahl (Frontend rendert diese Liste, keine UI-Kopie mehr).
`scope`: user|system (Restart-Weg), `unit`: echter systemd-Name (Restart/Logs/Matching)."""
a = agent_status()
gw_url = f"{GATEWAY_URL}/v1"
rows = [
{"name": "Engine (llama-swap)", "unit": "llama-swap", "url": LLAMA_SWAP_URL,
"ok": engine_reachable(), "scope": "system"},
]
# Seit UMBAU v3 P1 ist der LLM-Gateway ein EIGENER Prozess — ohne diese Zeile war er
# in der Dienste-Ampel unsichtbar (Kachel "6/6 grün" bei totem Denkpfad).
if V1_UPSTREAM:
rows.append({"name": "LLM-Gateway (Denkpfad)", "unit": "mc2-gateway", "url": V1_UPSTREAM,
"ok": gateway_reachable(), "scope": "user"})
# MC2 selbst antwortet gerade auf diesen Request — ok=True ist hier ehrlich;
# die Zeile existiert für Restart/Logs, nicht als Erreichbarkeits-Orakel.
rows.append({"name": "Steuerpult (MC2)", "unit": "mission-control-2", "url": gw_url,
"ok": True, "scope": "user"})
else:
rows.append({"name": "Gateway (integriert)", "unit": "mission-control-2", "url": gw_url,
"ok": gateway_reachable(), "scope": "user"})
rows += [
{"name": "Wächter (Steward)", "unit": "mc2-steward", "url": "",
"ok": _user_unit_active("mc2-steward"), "scope": "user"},
{"name": "Hermes-Gateway", "unit": "hermes-gateway", "url": HERMES_API_URL,
"ok": a["gateway_reachable"], "scope": "user"},
{"name": "Hermes-GUI (Desktop-Gateway)", "unit": "hermes-builtin-ui", "url": a["hermes_ui_url"],
"ok": a["hermes_ui_reachable"], "scope": "user"},
{"name": "Mem0 (Gedächtnis)", "unit": "mem0-service", "url": MEM0_SERVICE_URL,
"ok": _mem0_reachable(), "scope": "user"},
{"name": "Voice (STT/TTS)", "unit": "voice-service", "url": VOICE_SERVICE_URL,
"ok": _voice_reachable(), "scope": "user"},
]
return {
"services": [
{"name": "Engine (llama-swap)", "unit": "llama-swap", "url": LLAMA_SWAP_URL, "ok": engine_reachable()},
{"name": "Gateway (integriert)", "unit": "mission-control-2", "url": gw_url, "ok": gateway_reachable()},
{"name": "Hermes-Gateway", "unit": "hermes-gateway", "url": HERMES_API_URL, "ok": a["gateway_reachable"]},
{"name": "Hermes-GUI (Desktop-Gateway)", "unit": "hermes-builtin-ui", "url": a["hermes_ui_url"], "ok": a["hermes_ui_reachable"]},
{"name": "Mem0 (Gedächtnis)", "unit": "mem0-service", "url": MEM0_SERVICE_URL, "ok": _mem0_reachable()},
{"name": "Voice (STT/TTS)", "unit": "voice-service", "url": VOICE_SERVICE_URL, "ok": _voice_reachable()},
],
"services": rows,
"links": {
"engine_ui": f"{LLAMA_SWAP_URL}/ui",
"gateway": gw_url,