Files
mission-control-v2/backend/gateway_app.py
T
Hitonabi c697356f5a Neue Ansicht 'Von allein': Skills + Vorschlags-Bilanz der Box (+ schlafende P1-Basis)
User-Wunsch 15.07.: EIN Viewpoint, was die Box selbst geleistet hat -
Chronik ist zu kompliziert. Neue Operativ-Ansicht #eigenleben:
- Skills aus ~/.hermes/skills (= Lucys Satz) mit Klartext-Beschreibung,
  Nutzungszaehler (.usage.json) und Herkunft (selbst erstellt / von uns
  gebaut / mitgeliefert), aufklappbar mit vollem SKILL.md.
- Vorschlags-Bilanz: angenommen (Auftragsbuch-Chronik) + abgelehnt mit
  Grund (Lern-Journal) als eine Timeline + Zaehler.
Backend: services/eigenleben.py + routers/eigenleben.py (read-only).

Mit an Bord (User-Ja, schlafend): P1-Basis des Gateway-Auszugs der
Parallel-Session (config.V1_UPSTREAM + app.py-Weiche + gateway_forward) -
ohne MC_V1_UPSTREAM in der Unit exakt altes Verhalten; Rest von P1
(gateway_app, deploy.sh, Unit, token_stats) committet die andere Session.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 10:43:09 +02:00

65 lines
2.4 KiB
Python

"""
MC2-Gateway — der /v1-Datenpfad als EIGENER Prozess (UMBAU v3, P1).
Befund der Live-Inspektion 15.07.2026: Jeder LLM-Aufruf der Box (Lucys Haupt-Hirn,
Nacht-Crons, Worker-Delegation, Vision, Decomposer/Specifier/Curator) lief durch den
Steuerpult-Prozess auf :9001 — den am häufigsten neu gestarteten Dienst des Stacks.
Dieser Einstieg hebt denselben Gateway-Router (routers/gateway_proxy.py) UNVERÄNDERT
in einen bewusst winzigen, langweiligen Prozess: Unit mc2-gateway.service, Loopback
:9010, Restart=always. Das Steuerpult darf beliebig neu starten — die Wirbelsäule steht.
Bewusst NICHT hier: weitere Router, Hintergrund-Loops, CORS, Frontend-Auslieferung.
LAN-Clients (IDE-Lane) erreichen /v1 weiter über MC2 :9001, das roh hierher
durchreicht (routers/gateway_forward.py, MC_V1_UPSTREAM).
"""
import logging
import os
from contextlib import asynccontextmanager
from typing import AsyncGenerator
import httpx
from fastapi import FastAPI, Request
from config import LLAMA_SWAP_URL, VERSION
from routers import gateway_proxy
logging.basicConfig(
level=os.environ.get("MC_LOG_LEVEL", "INFO").upper(),
format="%(asctime)s %(levelname)-7s %(name)s: %(message)s",
)
log = logging.getLogger(__name__)
@asynccontextmanager
async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]:
# Gleiche Client-Parameter wie zuvor in app.py: Keep-Alive/Pooling statt neuer
# Client pro Anfrage (Sockets/TIME_WAIT unter parallelen Agent-Strömen).
app.state.gw_client = httpx.AsyncClient(
timeout=httpx.Timeout(connect=10.0, read=None, write=None, pool=10.0),
limits=httpx.Limits(max_keepalive_connections=100, max_connections=200),
)
log.info("mc2-gateway bereit (Engine: %s)", LLAMA_SWAP_URL)
try:
yield
finally:
await app.state.gw_client.aclose()
app = FastAPI(title="MC2 Gateway", version=VERSION, lifespan=lifespan)
app.include_router(gateway_proxy.router)
@app.get("/gw/health")
async def health(request: Request):
"""Eigener Health-Pfad (nicht /api/health — das gehört dem Steuerpult):
beweist Prozess UND Engine-Erreichbarkeit, für deploy.sh/stack-postcheck.sh."""
engine = False
try:
r = await request.app.state.gw_client.get(f"{LLAMA_SWAP_URL}/v1/models", timeout=5.0)
engine = r.status_code == 200
except httpx.HTTPError:
pass
return {"status": "ok", "service": "mc2-gateway", "version": VERSION,
"engine_reachable": engine}