#!/usr/bin/env bash # Stack-Post-Update-Check: läuft NACH jedem Update (OS / Engine / Router) und verifiziert, # dass der komplette Inferenz-Stack noch FUNKTIONIERT — nicht nur "Befehl lief durch". # Exit 0 = alles ok, sonst 1 → der jobengine-Job wird im UI ROT (state=failed). # # Pendant zu hermes-postcheck.sh (prüft das Gehirn/Mem0); dieser prüft Router+Engine+MC2 # inkl. einer ECHTEN 1-Token-Inferenz (beweist, dass ein Modell wirklich lädt & generiert). set -uo pipefail SWAP_URL="${MC_LLAMA_SWAP_URL:-http://127.0.0.1:8080}" MC_URL="${MC_URL:-http://127.0.0.1:9001}" MEM0_URL="${MEM0_SERVICE_URL:-http://127.0.0.1:8765}" BRAIN="${MC_WARMUP_MODELS:-fast}"; BRAIN="${BRAIN%% *}" # erstes Modell, falls Liste EMBED="${MC_WARMUP_EMBED:-embed}"; EMBED="${EMBED%% *}" # Embedding-Modell (Mem0/Gedächtnis) fail=0 echo "=== Stack Post-Update: Funktionsprüfung ===" # 0. Auf llama-swap warten — ein Engine/Router-Update startet den Dienst neu, der Erststart # (+ erstes Modell-Laden) kann dauern. Max ~120s. swap_up=0 for _ in $(seq 1 60); do curl -sf -m 5 "$SWAP_URL/v1/models" >/dev/null 2>&1 && { swap_up=1; break; } sleep 2 done # 1. Router-Dienst aktiv? (is-active ist read-only → kein sudo nötig) if systemctl is-active --quiet llama-swap; then echo "PASS · llama-swap-Dienst aktiv" else echo "FAIL · llama-swap-Dienst NICHT aktiv"; fail=1 fi # 2. Engine erreichbar (Modell-Liste)? if [ "$swap_up" -eq 1 ]; then echo "PASS · Engine /v1/models antwortet" else echo "FAIL · Engine /v1/models antwortet nicht (nach 120s)"; fail=1 fi # 3. Echte Inferenz: lädt ein Modell und generiert es ein Token? resp="$(curl -s -m 240 -X POST "$SWAP_URL/v1/chat/completions" \ -H 'Content-Type: application/json' \ -d "{\"model\":\"$BRAIN\",\"max_tokens\":1,\"messages\":[{\"role\":\"user\",\"content\":\"ping\"}]}" 2>/dev/null)" if printf '%s' "$resp" | grep -q '"choices"'; then echo "PASS · Inferenz auf '$BRAIN' liefert eine Antwort" else echo "FAIL · Inferenz auf '$BRAIN' fehlgeschlagen (Modell lädt/generiert nicht)"; fail=1 fi # 3b. Embedding-Modell (für Mem0/Gedächtnis) lädt und liefert einen Vektor? eresp="$(curl -s -m 120 -X POST "$SWAP_URL/v1/embeddings" \ -H 'Content-Type: application/json' \ -d "{\"model\":\"$EMBED\",\"input\":\"ping\"}" 2>/dev/null)" if printf '%s' "$eresp" | grep -q '"embedding"'; then echo "PASS · Embedding-Modell '$EMBED' liefert Vektoren" else echo "FAIL · Embedding-Modell '$EMBED' lädt/antwortet nicht (Mem0/Gedächtnis betroffen)"; fail=1 fi # 4. MC2 selbst gesund (Engine + Gateway erreichbar)? if curl -sf -m 8 "$MC_URL/api/health" 2>/dev/null | grep -qE '"engine_reachable":[[:space:]]*true'; then echo "PASS · MC2 /api/health: engine_reachable=true" else echo "FAIL · MC2 /api/health meldet Engine nicht erreichbar"; fail=1 fi # 4b. MC2-Gateway (eigenständiger /v1-Datenpfad, UMBAU v3 P1) gesund? Nur prüfen, wenn # die Unit enabled ist — Postchecks können auf Ständen vor dem Gateway-Auszug laufen. GW_URL="${MC2_GATEWAY_URL:-http://127.0.0.1:9010}" if systemctl --user is-enabled --quiet mc2-gateway 2>/dev/null; then if curl -sf -m 8 "$GW_URL/gw/health" 2>/dev/null | grep -qE '"engine_reachable":[[:space:]]*true'; then echo "PASS · mc2-gateway gesund (Prozess + Engine)" else echo "FAIL · mc2-gateway antwortet nicht/Engine weg — LLM-DATENPFAD BETROFFEN"; fail=1 fi fi # 4c. MC2-Steward (Wächter-Dienst, UMBAU v3 P2) aktiv? (nur wenn Unit enabled) if systemctl --user is-enabled --quiet mc2-steward 2>/dev/null; then if systemctl --user is-active --quiet mc2-steward; then echo "PASS · mc2-steward aktiv (Wächter laufen)" else echo "FAIL · mc2-steward NICHT aktiv — Box ohne Wächter"; fail=1 fi fi # 5. Mem0-Sidecar (Gedächtnis) erreichbar? if curl -sf -m 5 "$MEM0_URL/health" >/dev/null 2>&1; then echo "PASS · Mem0-Sidecar erreichbar" else echo "FAIL · Mem0-Sidecar NICHT erreichbar"; fail=1 fi if [ "$fail" -eq 0 ]; then echo "=== STACK OK ✓ ===" else echo "=== STACK-CHECK FEHLGESCHLAGEN — bitte prüfen ===" fi exit "$fail"