diff --git a/backend/config.py b/backend/config.py index 1f5be42..0eb8bf7 100644 --- a/backend/config.py +++ b/backend/config.py @@ -19,13 +19,6 @@ MODELS_DIR = Path(os.environ.get("MC_MODELS_DIR", "/srv/models")) # Persistent neben den Modellen (übersteht Deploys). TTL = Frische-Fenster. DISCOVER_CACHE_PATH = Path(os.environ.get("MC_DISCOVER_CACHE", str(MODELS_DIR / "mc2-discover.json"))) DISCOVER_TTL = int(os.environ.get("MC_DISCOVER_TTL", "43200")) # 12 h -# Geteiltes Gedächtnis (SQLite, WAL). Persistent neben den Modellen. -# Hinweis: nur noch für die einmalige Mem0-Migration relevant — das aktive Gedächtnis -# liegt jetzt in Mem0/Chroma hinter dem Sidecar (siehe MEM0_SERVICE_URL). -MEMORY_DB = Path(os.environ.get("MC_MEMORY_DB", str(MODELS_DIR / "mc2-memory.db"))) -# Mem0-Sidecar (auto-lernendes, semantisches Gedächtnis). Läuft im ~/.mem0/venv (Python 3.12), -# weil mem0+chromadb unter dem 3.14-Backend nicht laufen. MC2 spricht ihn lokal per HTTP an. -MEM0_SERVICE_URL = os.environ.get("MC_MEM0_SERVICE_URL", "http://127.0.0.1:8765").rstrip("/") # Befehl-Vorlage für llama-swap: {model}=GGUF-Pfad, {ctx}=Kontext, ${PORT} bleibt stehen. # Hinweis: --prompt-cache/--prompt-cache-all sind llama-CLI-Flags, NICHT llama-server — # llama-server lehnt sie ab ("invalid argument") und startet dann nicht. Prompt-Caching @@ -72,7 +65,7 @@ V1_UPSTREAM = os.environ.get("MC_V1_UPSTREAM", "").rstrip("/") HERMES_API_URL = os.environ.get("HERMES_API_URL", "http://127.0.0.1:8642").rstrip("/") # API-Key der Hermes-`api_server`-Plattform (~/.hermes/.env: API_SERVER_KEY). Nötig für # /v1/chat/completions (Voice-Pipeline) — Bearer-Auth, sonst 401. Derselbe volle Agent -# (Tools + geteiltes Mem0) wie CLI/Telegram, nur über HTTP. +# (Tools + geteiltes Gedächtnis) wie CLI/Telegram, nur über HTTP. def _read_hermes_env(key: str) -> str: """Liest einen Schlüssel aus ~/.hermes/.env (Fallback, falls nicht in der Prozess-Env). Der MC2-Dienst erbt die Hermes-Secrets sonst nicht.""" @@ -97,7 +90,7 @@ HERMES_API_KEY = ( HERMES_API_MODEL = os.environ.get("HERMES_API_MODEL", "hermes") # --- Voice-Sidecar (STT faster-whisper + TTS Piper/Chatterbox) --------------- -# Eigenes Python-3.12-venv (~/.voice/venv), analog Mem0-Sidecar. MC2 proxyt nach außen. +# Eigenes Python-3.12-venv (~/.voice/venv). MC2 proxyt nach außen. VOICE_SERVICE_URL = os.environ.get("MC_VOICE_SERVICE_URL", "http://127.0.0.1:8650").rstrip("/") # Box-Konsole: ttyd-Web-Terminal (echte Login-Shell). Bindet NUR an Loopback # (127.0.0.1:7682, base-path /console) und wird von MC2 über den ohnehin offenen Port 9001 diff --git a/backend/routers/system.py b/backend/routers/system.py index 7ec3eeb..9f8e1f3 100644 --- a/backend/routers/system.py +++ b/backend/routers/system.py @@ -10,7 +10,7 @@ import os import subprocess import httpx -from config import GATEWAY_URL, HERMES_API_URL, LLAMA_SWAP_URL, MEM0_SERVICE_URL, V1_UPSTREAM, VOICE_SERVICE_URL +from config import GATEWAY_URL, HERMES_API_URL, LLAMA_SWAP_URL, V1_UPSTREAM, VOICE_SERVICE_URL from fastapi import APIRouter from pydantic import BaseModel from services import backup as backup_svc @@ -42,13 +42,6 @@ def history(minutes: int = 60) -> dict: return metrics_history.history(minutes) -def _mem0_reachable() -> bool: - try: - return httpx.get(f"{MEM0_SERVICE_URL}/health", timeout=2).status_code == 200 - except Exception: - return False - - def _voice_reachable() -> bool: try: return httpx.get(f"{VOICE_SERVICE_URL}/health", timeout=2).status_code == 200 diff --git a/backend/routers/voice.py b/backend/routers/voice.py index 5a5faa8..8730c7d 100644 --- a/backend/routers/voice.py +++ b/backend/routers/voice.py @@ -3,7 +3,7 @@ Voice-Endpoints für „Mit Hermes reden" (Browser-Voice + 3D-Avatar). Dünner Layer: STT/TTS werden zum Voice-Sidecar (:8650) geproxyt; der Chat geht an den Hermes-`api_server` (:8642, OpenAI-kompatibel) — denselben vollen Agenten mit Tools + -geteiltem Mem0 wie CLI/Telegram. Mit stabilem `X-Hermes-Session-Id` hält die Plattform den +geteiltem Gedächtnis wie CLI/Telegram. Mit stabilem `X-Hermes-Session-Id` hält die Plattform den Transcript server-seitig, daher schickt der Client je Turn nur die neue User-Nachricht. LAN-only (kein Token in der 2.0-Phase), wie die übrigen MC2-Endpoints. @@ -169,7 +169,7 @@ def voice_metrics() -> dict: @router.get("/voice/trace") def voice_trace(limit: int = 20) -> dict: """Per-Turn-Trace: die letzten `limit` Chat-Turns mit Stufen-Breakdown (STT · Vision · Hirn · - Generierung, Mem0 als Unter-Detail). Neueste zuerst. Für die Latenz-Ansicht im Cockpit — + Generierung, Gedächtnis als Unter-Detail). Neueste zuerst. Für die Latenz-Ansicht im Cockpit — damit man den EINEN langsamen Turn sieht, den ein Durchschnitt verschluckt.""" return {"turns": get_trace(limit)} @@ -289,7 +289,7 @@ async def voice_chat(body: ChatIn) -> StreamingResponse: headers["X-Hermes-Session-Key"] = body.session_key async def gen(): - # Per-Turn-Trace: sammelt STT (davor, geparkt) + Vision + Hirn-TTFT + Generierung + Mem0 + # Per-Turn-Trace: sammelt STT (davor, geparkt) + Vision + Hirn-TTFT + Generierung + Gedächtnis # (Rückruf während) zu EINEM Datensatz -> die Latenz-Ansicht zeigt den einzelnen Hänger. trace = TurnTrace(session_id=body.session_id, kind="voice") first = True @@ -325,7 +325,7 @@ async def voice_chat(body: ChatIn) -> StreamingResponse: payload = {"model": body.model or HERMES_API_MODEL, "messages": messages, "stream": True} # Lucys Hirn (Qwen3.6) ist ein Thinking-Modell -> für die gesprochene Assistentin Thinking AUS, # sonst generiert es tausende Reasoning-Token VOR der kurzen Antwort (gemessen: 11k Token, ~30s TTFB). - # Gleiches Muster wie die fast-Spur im Gateway (gateway_proxy.py) und die Mem0-Extraktion. + # Gleiches Muster wie die fast-Spur im Gateway (gateway_proxy.py) und die Gedächtnis-Extraktion. if os.environ.get("MC_VOICE_NO_THINK", "1") not in ("0", "false", "False"): payload["chat_template_kwargs"] = {"enable_thinking": False} try: @@ -342,7 +342,7 @@ async def voice_chat(body: ChatIn) -> StreamingResponse: if first: # Time-To-First-Byte des Hermes-Streams (Verbindungs-Overhead) trace.note_ttfb() first = False - # Erster CONTENT-Delta = echte Hirn-Latenz (Agent-Overhead + Mem0 + LLM-TTFT) — + # Erster CONTENT-Delta = echte Hirn-Latenz (Agent-Overhead + Gedächtnis + LLM-TTFT) — # chat_ttfb misst nur den SSE-Start (~5 ms) und ist dafür blind. if first_content and b'"content"' in chunk: trace.note_first_content() diff --git a/backend/routers/zeitmaschine.py b/backend/routers/zeitmaschine.py index 5b5fe33..60b1021 100644 --- a/backend/routers/zeitmaschine.py +++ b/backend/routers/zeitmaschine.py @@ -33,7 +33,7 @@ def list_snapshots() -> dict: @router.get("/zeitmaschine/inhalt") def snapshot_contents(file: str) -> dict: - """Top-Level-Komponenten eines Snapshots (mem0, hermes, llama-swap, MANIFEST …).""" + """Top-Level-Komponenten eines Snapshots (hermes, llama-swap, MANIFEST …).""" if not _FILE_RX.match(file): raise HTTPException(400, "Ungültiger Snapshot-Name.") p = backup_svc.BACKUP_DIR / file diff --git a/backend/services/sentry.py b/backend/services/sentry.py index 2b01be8..01945c6 100644 --- a/backend/services/sentry.py +++ b/backend/services/sentry.py @@ -1,7 +1,7 @@ """ Health-Wächter der Box (Lucy-Proaktivität, Faden A3). -Prüft periodisch die Kern-Dienste (Engine, Agent-Hirn, Hermes-Gateway, Mem0, +Prüft periodisch die Kern-Dienste (Engine, Agent-Hirn, Hermes-Gateway, Voice-Sidecar, Platte) und meldet ZUSTANDSWECHSEL in den Melde-Briefkasten (services/announce.py → Lucy spricht es) und via notify.sh (Telegram).