fix(sentry): Hermes-Probe schickt ihren Schluessel mit — 720 Fehler/Tag weniger

Beim Untersuchen von Hermes' Log gefunden: MC2s eigene Erreichbarkeits-Probe rief
`GET /v1/models` ohne API-Schluessel und produzierte damit alle zwei Minuten ein
`API server rejected invalid API key` in ~/.hermes/logs/agent.log.

  Gemessen: 30 Vorfaelle/Stunde, seit dem 27.08. 15:05 durchgehend — 558 Eintraege
  im aktuellen Log, ~720/Tag.

Das URTEIL war nie falsch: `_reach` prueft `status_code < 500`, und ein 401 beweist
ja, dass jemand zuhoert. Falsch war der Laerm — und dass ein echter Auth-Fehler darin
untergegangen waere.

MC2 hat den Schluessel laengst in der Config (HERMES_API_KEY, aus ~/.hermes/.env).
Die Probe schickt ihn jetzt als Bearer mit. Die Nachsichtigkeit von `< 500` bleibt
absichtlich: Die Frage ist "laeuft der Dienst", nicht "darf ich rein".

Auf der Box gegengeprueft:
  ohne Schluessel: 401
  mit Schluessel:  200

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Hitonabi
2026-08-28 09:44:45 +02:00
co-authored by Claude Opus 5
parent dcee0096fe
commit 7957cda438
+16 -4
View File
@@ -20,7 +20,7 @@ import time
import httpx
import psutil
from config import HERMES_API_URL, MODELS_DIR, VOICE_SERVICE_URL
from config import HERMES_API_KEY, HERMES_API_URL, MODELS_DIR, VOICE_SERVICE_URL
from services import announce, llamaswap
@@ -34,14 +34,26 @@ REMIND_S = int(os.environ.get("MC_SENTRY_REMIND_S", "21600")) # Erinnerung
DISK_ALARM_PCT = float(os.environ.get("MC_SENTRY_DISK_PCT", "90"))
def _reach(url: str, path: str = "/health") -> bool:
def _reach(url: str, path: str = "/health", headers: dict[str, str] | None = None) -> bool:
"""Antwortet der Dienst ueberhaupt? `< 500` ist bewusst nachsichtig: Die Frage ist
"laeuft er", nicht "darf ich rein" — ein 401 beweist, dass jemand zuhoert.
`headers` gibt es seit dem 28.08.2026: Die Hermes-Probe schlug ohne API-Schluessel an
und erzeugte dabei 720 `rejected invalid API key`-Warnungen pro Tag in dessen Log
(gemessen: 30/Stunde seit dem 27.08. 15:05). Das Urteil war richtig, der Laerm nicht —
und er haette einen echten Auth-Fehler unter sich begraben."""
try:
with httpx.Client(timeout=5.0) as c:
return c.get(f"{url}{path}").status_code < 500
return c.get(f"{url}{path}", headers=headers or {}).status_code < 500
except Exception:
return False
def _hermes_kopf() -> dict[str, str]:
"""Bearer-Kopf fuer die Hermes-Platform, falls ein Schluessel konfiguriert ist."""
return {"Authorization": f"Bearer {HERMES_API_KEY}"} if HERMES_API_KEY else {}
def _check_engine() -> bool:
return llamaswap.engine_reachable()
@@ -70,7 +82,7 @@ CHECKS: dict[str, tuple] = {
"brain": (_check_brain,
"Mein Gehirn lädt nicht — ich kann gerade nicht richtig denken. Ein Neustart der Engine könnte helfen.",
"Mein Gehirn ist wieder geladen. Alles klar bei mir."),
"hermes": (lambda: _reach(HERMES_API_URL, "/v1/models"),
"hermes": (lambda: _reach(HERMES_API_URL, "/v1/models", _hermes_kopf()),
"Der Agent-Dienst ist ausgefallen — Telegram und meine Tools gehen gerade nicht.",
"Der Agent-Dienst läuft wieder."),
"voice": (lambda: _reach(VOICE_SERVICE_URL),