""" Zentrale Konfiguration für Mission Control 2.0. Eine Quelle der Wahrheit für Pfade, URLs und Defaults — alles über Env-Vars überschreibbar. Bewusst schlank: MC 2.0 ist ein Glue-Cockpit, das vorhandene Dienste (llama-swap, LiteLLM-Gateway, Hermes) steuert, statt sie nachzubauen. """ import os from pathlib import Path from ruamel.yaml import YAML # --- Engine (llama-swap) ----------------------------------------------------- LLAMA_SWAP_URL = os.environ.get("MC_LLAMA_SWAP_URL", "http://127.0.0.1:8080").rstrip("/") CONFIG_PATH = Path(os.environ.get("MC_CONFIG_PATH", "/etc/llama-swap/config.yaml")) MODELS_DIR = Path(os.environ.get("MC_MODELS_DIR", "/srv/models")) # Cache der Modell-Entdeckung ("aktuell beste Modelle", live von HuggingFace). # 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. MEMORY_DB = Path(os.environ.get("MC_MEMORY_DB", str(MODELS_DIR / "mc2-memory.db"))) # 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 # macht llama-server ohnehin automatisch pro Slot (KV-Reuse). _DEFAULT_CMD_TEMPLATE = ( "llama-server -m {model} --host 127.0.0.1 --port ${PORT} " "-c {ctx} -ngl 999 -fa 1 --no-mmap" ) CMD_TEMPLATE = os.environ.get("MC_CMD_TEMPLATE", _DEFAULT_CMD_TEMPLATE) if "{model}" not in CMD_TEMPLATE: CMD_TEMPLATE = _DEFAULT_CMD_TEMPLATE DEFAULT_TTL = int(os.environ.get("MC_DEFAULT_TTL", "300")) # Draft-Modell für Speculative Decoding (nur fast/coder, wenn vorhanden). Eine # Quelle der Wahrheit für llamaswap.register_model + migrate_config. SPEC_DRAFT_MODEL_PATH = os.environ.get( "MC_SPEC_DRAFT_MODEL", f"{MODELS_DIR.as_posix()}/drafts/qwen2.5-1.5b-instruct-q4_k_m.gguf") # Env für HuggingFace-Downloads: XET deaktivieren (Hänger bei ~6 MB, siehe v1-Gotcha). HF_DOWNLOAD_ENV = {"HF_HUB_DISABLE_XET": "1"} # --- Routing-Gateway (LiteLLM, model: auto) ---------------------------------- GATEWAY_URL = os.environ.get("MC_GATEWAY_URL", f"http://127.0.0.1:{os.environ.get('MC_PORT', '9000')}").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"))) # PC Executor — läuft auf dem Windows-PC, erreichbar über LAN. PC_EXECUTOR_URL = os.environ.get("MC_PC_EXECUTOR_URL", "http://192.168.178.98:7777").rstrip("/") # --- Server ------------------------------------------------------------------ HOST = os.environ.get("MC_HOST", "0.0.0.0") PORT = int(os.environ.get("MC_PORT", "9000")) # Gebautes React-Frontend (frontend/dist). In Prod liefert FastAPI es statisch aus; # im Dev läuft der Vite-Dev-Server separat und proxyt /api hierher. 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-w8" # Gemeinsame YAML-Instanz (preserve_quotes hält Kommentare/Quotes in config.yaml). yaml = YAML() yaml.preserve_quotes = True