feat(2.0): Phase 4 — Hermes-Schicht (MC-Seite + Runbook)

MC-Seite: services/agent.py + routers/agent.py (GET /api/agent/status:
Gateway/WebUI-Reachability + Verdrahtungs-Hinweise), AgentView (Status-
Tiles, Hermes-oeffnen-Button, Offline-Hinweis). deploy/hermes-webui.service
(systemd-USER, :8787). Box-Runbook docs/HERMES_SETUP.md (hermes-webui
installieren, Brain=model:auto via Gateway, Tools/MCP verdrahten inkl.
mcp_mc+mcp_memory, SSH-Windows, LiteLLM-Caveat #26489).

Lokal verifiziert: agent/status + Frontend-Build + Browser (Hermes-View).
Box-Ausfuehrung der Verdrahtung steht aus (Runbook). Docs aktualisiert.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Hitonabi
2026-06-25 08:22:28 +02:00
parent 81468df9c0
commit c773dd7eae
16 changed files with 428 additions and 174 deletions
+2 -1
View File
@@ -13,7 +13,7 @@ from fastapi.staticfiles import StaticFiles
from starlette.requests import Request
from config import FRONTEND_DIST, VERSION
from routers import connect, health, memory, models, routing, system
from routers import agent, connect, health, memory, models, routing, system
app = FastAPI(title="Mission Control 2.0", version=VERSION)
@@ -40,6 +40,7 @@ app.include_router(routing.router)
app.include_router(system.router)
app.include_router(connect.router)
app.include_router(memory.router)
app.include_router(agent.router)
# Prod: gebautes Frontend ausliefern (falls vorhanden). SPA-Fallback auf index.html.
+7 -1
View File
@@ -38,6 +38,12 @@ GATEWAY_URL = os.environ.get("MC_GATEWAY_URL", "http://127.0.0.1:4000").rstrip("
GATEWAY_CONFIG_PATH = Path(os.environ.get(
"MC_GATEWAY_CONFIG", str(Path(__file__).resolve().parent.parent / "gateway" / "config.yaml")))
# --- Hermes Agent (eigener Dienst auf der Box) -------------------------------
# Gateway (OpenAI-API des Agenten) + standalone Web-UI (nesquena/hermes-webui).
HERMES_API_URL = os.environ.get("HERMES_API_URL", "http://127.0.0.1:8642").rstrip("/")
HERMES_WEBUI_URL = os.environ.get("HERMES_WEBUI_URL", "http://127.0.0.1:8787").rstrip("/")
HERMES_HOME = Path(os.path.expanduser(os.environ.get("HERMES_HOME", "~/.hermes")))
# --- Server ------------------------------------------------------------------
HOST = os.environ.get("MC_HOST", "0.0.0.0")
PORT = int(os.environ.get("MC_PORT", "9000"))
@@ -46,7 +52,7 @@ PORT = int(os.environ.get("MC_PORT", "9000"))
FRONTEND_DIST = Path(os.environ.get("MC_FRONTEND_DIST", str(Path(__file__).resolve().parent.parent / "frontend" / "dist")))
# Version (Phase 0 — Greenfield-Skeleton).
VERSION = "2.0.0-phase3"
VERSION = "2.0.0-phase4"
# Gemeinsame YAML-Instanz (preserve_quotes hält Kommentare/Quotes in config.yaml).
yaml = YAML()
+12
View File
@@ -0,0 +1,12 @@
"""Agent-Endpoint: Hermes-Status + WebUI-Link (MC verlinkt nur, betreibt nicht)."""
from fastapi import APIRouter
from services.agent import agent_status
router = APIRouter(prefix="/api")
@router.get("/agent/status")
def status() -> dict:
return agent_status()
+33
View File
@@ -0,0 +1,33 @@
"""
Hermes-Agent-Status (Control-Plane-Read). MC betreibt Hermes NICHT — es zeigt nur
Status + verlinkt das standalone hermes-webui. Voller Zugriff + Tools/MCP werden in
Hermes' eigener Config verdrahtet (siehe docs/HERMES_SETUP.md).
"""
import httpx
from config import HERMES_API_URL, HERMES_HOME, HERMES_WEBUI_URL
def _reach(url: str, path: str = "") -> bool:
try:
with httpx.Client(timeout=3.0) as c:
return c.get(f"{url}{path}").status_code < 500
except Exception:
return False
def agent_status() -> dict:
"""Erreichbarkeit von Gateway (:8642) + WebUI (:8787) + lokale Hinweise."""
home = HERMES_HOME
return {
"gateway_url": HERMES_API_URL,
"webui_url": HERMES_WEBUI_URL,
"gateway_reachable": _reach(HERMES_API_URL, "/v1/models"),
"webui_reachable": _reach(HERMES_WEBUI_URL),
"home_exists": home.exists(),
# Best-effort: welche Verdrahtung lokal sichtbar ist (auf der Box aussagekräftig).
"has_config": (home / "config.yaml").exists() or (home / "config.json").exists(),
"has_skills": (home / "skills").exists(),
"has_memories": (home / "memories").exists(),
}