feat(jobs): KISS-Umbau der Automatik - 10 Mechanismen auf 3 Hermes-Crons
Fakten sammelt ein Skript, Prosa schreibt das Modell. stack-ist.sh prueft Ergebnisse statt Lebenszeichen und fand beim ersten Lauf sofort zwei echte Befunde. Abgeschaltet: 4 Crons + 4 Timer, davon einer nie gelaufen und einer 15 Naechte ohne Wirkung. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
c2a54bd25d
commit
f446da8ae6
@@ -0,0 +1,72 @@
|
|||||||
|
# Die drei Jobs (KISS-Umbau, 21.08.2026)
|
||||||
|
|
||||||
|
Vorher: **4 Hermes-Crons + 6 systemd-Timer**, verteilt auf zwei Mechanismen.
|
||||||
|
Deshalb fiel am 20.08. tagelang niemandem auf, dass ein Waechter fehlte —
|
||||||
|
niemand schaut an zwei Orten nach.
|
||||||
|
|
||||||
|
Jetzt: **drei Jobs, ein Ort.** `hermes cron list` zeigt die gesamte Automatik.
|
||||||
|
|
||||||
|
| Job | Wann | Art | Skript |
|
||||||
|
|---|---|---|---|
|
||||||
|
| **Daily News Report** | taeglich 07:00 | Agent + Websuche | — |
|
||||||
|
| **KI und Stack Radar** | samstags 08:00 | `--no-agent` | `stack-radar.sh` → `stack-ist.sh` |
|
||||||
|
| **Updates am Sonntag** | sonntags 04:30 | `--no-agent` | `sonntags-update.sh` → `autoupdate.sh` |
|
||||||
|
|
||||||
|
Daneben laufen als stille Rohrleitung weiter: `mc2-backup` (03:33) und
|
||||||
|
`projekte-sync` (stuendlich). Die melden sich nie, die sichern und synchronisieren nur.
|
||||||
|
|
||||||
|
## Der Entwurfsgrundsatz
|
||||||
|
|
||||||
|
> **Fakten sammelt ein Skript, Prosa schreibt das Modell.**
|
||||||
|
|
||||||
|
Der alte Selbsttest war am 20.08. gruen, waehrend vier Dinge kaputt waren: das
|
||||||
|
Kritiker-Gate zeigte seit einem Tag auf ein umbenanntes Modell (404), Lucys
|
||||||
|
`SOUL.md` war blockiert, das Dashboard stand ohne Passwort offen, die CI war rot.
|
||||||
|
Er hatte geprueft, ob Dienste **antworten** — nicht, ob sie **stimmen**.
|
||||||
|
|
||||||
|
`stack-ist.sh` prueft deshalb Ergebnisse: loesen die Rollen-Aliase noch auf? Ist
|
||||||
|
der letzte Timer-Lauf gutgegangen? Ist eine Sicherung juenger als zwei Tage?
|
||||||
|
Liefert die oeffentliche Adresse Daten ohne Anmeldung? Beim ersten Lauf hat es
|
||||||
|
sofort zwei echte Befunde gefunden.
|
||||||
|
|
||||||
|
## Kugelsicher heisst konkret
|
||||||
|
|
||||||
|
- **Das Modell steht nicht im kritischen Pfad.** Antwortet es nicht, gehen die
|
||||||
|
Rohbefunde trotzdem raus. Nur die Prosa faellt weg, nie die Meldung.
|
||||||
|
- **Es meldet immer.** „Alles gruen" ist ein Ergebnis, kein Grund zu schweigen.
|
||||||
|
- **Kein `set -e`.** Ein einzelner fehlschlagender Test darf den Bericht nicht
|
||||||
|
abschneiden.
|
||||||
|
- **Ein Melderweg:** `deploy/notify.sh` erreicht Telegram **und** Lucys
|
||||||
|
Briefkasten (aus dem sie spricht) in einem Aufruf. Die Jobs laufen mit
|
||||||
|
`--deliver local`, damit Hermes nicht ein zweites Mal sendet.
|
||||||
|
- **Kein Fuellmaterial.** Die Prompts verbieten ausgedachte Vorschlaege
|
||||||
|
ausdruecklich — ein Bericht mit Fuellmaterial wird nicht gelesen, und dann
|
||||||
|
auch der echte Befund nicht.
|
||||||
|
|
||||||
|
## Ausbringen
|
||||||
|
|
||||||
|
Die Skripte muessen unter `~/.hermes/scripts/` liegen (Vorgabe von `hermes cron --script`).
|
||||||
|
Quelle ist dieses Verzeichnis:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scp deploy/jobs/*.sh hitonabi@192.168.178.151:/home/hitonabi/.hermes/scripts/
|
||||||
|
ssh hitonabi@192.168.178.151 'cd ~/.hermes/scripts && sed -i "s/\r$//" *.sh && chmod +x *.sh'
|
||||||
|
```
|
||||||
|
|
||||||
|
‼️ Das `sed` ist Pflicht: vom Windows-PC kopierte Dateien haben CRLF, und bash
|
||||||
|
scheitert daran mit unverstaendlichen Meldungen.
|
||||||
|
|
||||||
|
## Abgeschaltet am 21.08.
|
||||||
|
|
||||||
|
| Weg | Warum |
|
||||||
|
|---|---|
|
||||||
|
| Cron `morgen-digest` | geht im Daily News Report auf |
|
||||||
|
| Cron `tech-radar` | geht im Stack Radar auf |
|
||||||
|
| Cron `nacht-wartung` | pruefte Lebenszeichen, nicht Ergebnisse |
|
||||||
|
| Cron `wissens-sync` | **war nie gelaufen** — kein `last_run_at` |
|
||||||
|
| Timer `mc2-bagatell` | **15 Naechte hintereinander „0 eingespielt"** |
|
||||||
|
| Timer `mc2-selfsmoke` | geht in `stack-ist.sh` auf |
|
||||||
|
| Timer `pbs-backup` | doppelt zu `mc2-backup` und seit 21.08. rot (`/srv/models/mem0` gibt es nicht mehr) |
|
||||||
|
| Timer `mc2-autoupdate` | wird jetzt vom Cron „Updates am Sonntag" gestartet |
|
||||||
|
|
||||||
|
Die Unit-Dateien liegen noch da, nur `disable`d — Rueckbau ist ein Befehl.
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# sonntags-update.sh — Job 2: "Updates am Sonntag" (21.08.2026).
|
||||||
|
#
|
||||||
|
# Duenner Aufsatz auf deploy/autoupdate.sh. Bewusst KEIN Neubau: autoupdate.sh
|
||||||
|
# macht seit Juli genau das Richtige — Router -> Engine -> Hermes, jede Ebene
|
||||||
|
# mit Update-Pruefung, Postcheck, und bei Rot automatischem Rueckbau plus
|
||||||
|
# Selbst-Pinnung. Es meldet auch schon selbst ueber notify.sh, also Telegram
|
||||||
|
# UND Lucys Stimme.
|
||||||
|
#
|
||||||
|
# Dieser Aufsatz existiert nur, damit der Job unter `hermes cron list` steht
|
||||||
|
# statt in einem separaten systemd-Timer. Ein Ort fuer alle Automatik — genau
|
||||||
|
# deshalb ist am 20.08. tagelang niemandem aufgefallen, dass ein Waechter fehlte.
|
||||||
|
#
|
||||||
|
# Aufruf ueber Hermes-Cron:
|
||||||
|
# hermes cron create '30 4 * * 0' --name 'Updates am Sonntag' \
|
||||||
|
# --no-agent --script sonntags-update.sh --deliver local
|
||||||
|
set -uo pipefail
|
||||||
|
|
||||||
|
AUTOUPDATE="${AUTOUPDATE:-$HOME/mission-control-v2/deploy/autoupdate.sh}"
|
||||||
|
NOTIFY="${NOTIFY:-$HOME/mission-control-v2/deploy/notify.sh}"
|
||||||
|
|
||||||
|
melde() { bash "$NOTIFY" -s "[Box-Update]" "$1" 2>/dev/null || echo "$1" >&2; }
|
||||||
|
|
||||||
|
if [ ! -f "$AUTOUPDATE" ]; then
|
||||||
|
melde "Sonntags-Update ausgefallen: $AUTOUPDATE gibt es nicht. Nichts wurde aktualisiert."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# autoupdate.sh meldet waehrend des Laufs selbst (inkl. der KRITISCH-Faelle, in
|
||||||
|
# denen ein Bericht am Ende zu spaet kaeme). Wir fangen hier nur den Fall ab,
|
||||||
|
# dass es gar nicht erst durchlaeuft — sonst waere das Schweigen zweideutig.
|
||||||
|
AUSGABE="$(bash "$AUTOUPDATE" 2>&1)"
|
||||||
|
CODE=$?
|
||||||
|
|
||||||
|
if [ "$CODE" -ne 0 ]; then
|
||||||
|
melde "Sonntags-Update mit Fehler beendet (exit $CODE). Letzte Zeilen:
|
||||||
|
|
||||||
|
$(printf '%s\n' "$AUSGABE" | tail -15)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Erfolgsfall: autoupdate.sh hat bereits gemeldet. Leere Ausgabe -> Hermes
|
||||||
|
# schweigt, also genau eine Nachricht statt zwei.
|
||||||
|
exit 0
|
||||||
@@ -0,0 +1,177 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# stack-ist.sh — der IST-Zustand der Box, in Fakten (21.08.2026).
|
||||||
|
#
|
||||||
|
# Wird von Hermes-Cron "stack-radar" ueber --script eingespeist: die Ausgabe hier
|
||||||
|
# landet im Prompt des Agenten, der daraus den Bericht schreibt.
|
||||||
|
#
|
||||||
|
# GRUNDSATZ: Dieses Skript prueft ERGEBNISSE, nicht Lebenszeichen.
|
||||||
|
# Der alte Selbsttest war am 20.08. gruen, waehrend vier Dinge kaputt waren:
|
||||||
|
# das Kritiker-Gate zeigte auf ein umbenanntes Modell (404), Lucys SOUL.md war
|
||||||
|
# blockiert, das Dashboard stand ohne Passwort offen, die CI war rot.
|
||||||
|
# "Dienst antwortet" haette das nie gefunden. Deshalb wird hier nachgesehen,
|
||||||
|
# ob Dinge STIMMEN — nicht ob sie laufen.
|
||||||
|
#
|
||||||
|
# Nie mit set -e: ein einzelner fehlschlagender Test darf den Bericht nicht
|
||||||
|
# abschneiden. Fehler werden gemeldet, nicht verschwiegen.
|
||||||
|
set -uo pipefail
|
||||||
|
|
||||||
|
MC2="${MC2_URL:-http://127.0.0.1:9001}"
|
||||||
|
SWAP="${SWAP_URL:-http://127.0.0.1:8080}"
|
||||||
|
GITEA="${GITEA_URL:-http://192.168.178.153:3000}"
|
||||||
|
OEFFENTLICH="${OEFFENTLICH_URL:-https://mc.tobisniceshomelab.ddnsfree.com}"
|
||||||
|
|
||||||
|
ok() { printf ' OK %s\n' "$*"; }
|
||||||
|
warn() { printf ' ACHTUNG %s\n' "$*"; }
|
||||||
|
bad() { printf ' ROT %s\n' "$*"; }
|
||||||
|
|
||||||
|
echo "IST-ZUSTAND DER BOX — $(date '+%d.%m.%Y %H:%M')"
|
||||||
|
echo
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------- Dienste ---
|
||||||
|
echo "DIENSTE"
|
||||||
|
# systemd stellt gescheiterten Units ein "●" voran — das muss weg, sonst meldet
|
||||||
|
# der Bericht lauter Aufzaehlungspunkte als kaputte Dienste.
|
||||||
|
# EGAL: Units, die dauerhaft scheitern und niemanden stoeren. Ein Bericht, der
|
||||||
|
# jeden Tag denselben harmlosen Fehler zeigt, erzieht zum Wegsehen.
|
||||||
|
EGAL="at-spi-dbus-bus.service"
|
||||||
|
fehl=$(systemctl --user list-units --type=service --state=failed --no-legend --no-pager 2>/dev/null \
|
||||||
|
| sed 's/^[^a-zA-Z]*//' | awk '{print $1}')
|
||||||
|
gefunden=0
|
||||||
|
for d in $fehl; do
|
||||||
|
case " $EGAL " in *" $d "*) continue ;; esac
|
||||||
|
bad "Dienst gescheitert: $d"; gefunden=1
|
||||||
|
done
|
||||||
|
[ "$gefunden" = "0" ] && ok "kein Dienst im Fehlerzustand"
|
||||||
|
|
||||||
|
for d in mc2-gateway mission-control-2 hermes-gateway voice-service; do
|
||||||
|
systemctl --user is-active --quiet "$d.service" 2>/dev/null \
|
||||||
|
&& ok "$d laeuft" || bad "$d laeuft NICHT"
|
||||||
|
done
|
||||||
|
systemctl is-active --quiet llama-swap.service 2>/dev/null \
|
||||||
|
&& ok "llama-swap laeuft" || bad "llama-swap laeuft NICHT"
|
||||||
|
echo
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------ Timer ---
|
||||||
|
# Nicht "ist der Timer aktiv", sondern "ist der letzte Lauf gutgegangen".
|
||||||
|
echo "TIMER — letzter Lauf"
|
||||||
|
for t in $(systemctl --user list-timers --no-legend --no-pager 2>/dev/null | awk '{print $NF}'); do
|
||||||
|
dienst="${t%.service}.service"
|
||||||
|
case "$dienst" in launchpadlib-*) continue ;; esac # Ubuntu-Eigenes, nicht unseres
|
||||||
|
code=$(systemctl --user show -p ExecMainStatus --value "$dienst" 2>/dev/null)
|
||||||
|
wann=$(systemctl --user show -p ExecMainExitTimestamp --value "$dienst" 2>/dev/null | cut -d' ' -f2,3)
|
||||||
|
if [ -z "$wann" ]; then warn "$dienst ist eingerichtet, aber NIE gelaufen"
|
||||||
|
elif [ "${code:-0}" = "0" ]; then ok "$dienst zuletzt $wann"
|
||||||
|
else bad "$dienst zuletzt GESCHEITERT (exit $code) am $wann"; fi
|
||||||
|
done
|
||||||
|
echo
|
||||||
|
|
||||||
|
# --------------------------------------------------------- Modell-Aliase ---
|
||||||
|
# Der Fund vom 19./20.08.: Skripte und Configs nennen Modelle beim Eigennamen,
|
||||||
|
# das Modell wird umbenannt, und alles laeuft still in 404. Hier wird geprueft,
|
||||||
|
# ob jeder Alias, den irgendwer benutzt, heute noch antwortet.
|
||||||
|
echo "MODELL-ALIASE (Rollen muessen aufloesen)"
|
||||||
|
liste=$(curl -s -m 10 "$MC2/v1/models" 2>/dev/null \
|
||||||
|
| python3 -c 'import sys,json; print(" ".join(m["id"] for m in json.load(sys.stdin)["data"]))' 2>/dev/null)
|
||||||
|
if [ -z "$liste" ]; then bad "Modell-Liste nicht abrufbar ueber $MC2/v1"
|
||||||
|
else
|
||||||
|
ok "verfuegbar: $liste"
|
||||||
|
for rolle in hermes fast heavy; do
|
||||||
|
case " $liste " in
|
||||||
|
*" $rolle "*) ok "Rolle '$rolle' loest auf" ;;
|
||||||
|
*) bad "Rolle '$rolle' FEHLT — Skripte, die sie nennen, laufen in 404" ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
echo
|
||||||
|
|
||||||
|
# ------------------------------------------------------------- Erreichbar ---
|
||||||
|
echo "ERREICHBARKEIT"
|
||||||
|
for paar in "MC2:$MC2/api/health" "llama-swap:$SWAP/v1/models" "Gitea:$GITEA/api/v1/version"; do
|
||||||
|
name="${paar%%:*}"; url="${paar#*:}"
|
||||||
|
code=$(curl -s -m 10 -o /dev/null -w '%{http_code}' "$url" 2>/dev/null)
|
||||||
|
[ "$code" = "200" ] && ok "$name antwortet (200)" || bad "$name antwortet mit '$code'"
|
||||||
|
done
|
||||||
|
echo
|
||||||
|
|
||||||
|
# ------------------------------------------------ Offen im Internet? --------
|
||||||
|
# Der Fund vom 21.08.: MC2 hing ueber den Nginx Proxy Manager ungeschuetzt im
|
||||||
|
# Netz. ufw sah nichts davon, weil der Proxy im LAN steht. Also von aussen
|
||||||
|
# nachsehen — und zwar auf einem Endpunkt, der ECHTE Daten liefert.
|
||||||
|
echo "OEFFENTLICHE ERREICHBARKEIT"
|
||||||
|
code=$(curl -s -m 15 -o /tmp/.ist-oeff -w '%{http_code}' "$OEFFENTLICH/api/system/status" 2>/dev/null)
|
||||||
|
if [ "$code" = "200" ] && head -c1 /tmp/.ist-oeff 2>/dev/null | grep -q '{'; then
|
||||||
|
bad "MC2 liefert Systemdaten OHNE Anmeldung ins Internet ($OEFFENTLICH)"
|
||||||
|
elif [ "$code" = "401" ] || [ "$code" = "403" ]; then
|
||||||
|
ok "oeffentlicher Zugang verlangt Anmeldung ($code)"
|
||||||
|
elif [ "$code" = "000" ]; then
|
||||||
|
ok "von aussen nicht erreichbar"
|
||||||
|
else
|
||||||
|
warn "oeffentlicher Zugang antwortet mit '$code' — nachsehen"
|
||||||
|
fi
|
||||||
|
rm -f /tmp/.ist-oeff
|
||||||
|
echo
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------- Ports ---
|
||||||
|
echo "OFFENE PORTS (ufw)"
|
||||||
|
sudo -n ufw status 2>/dev/null | grep ALLOW | sed 's/^/ /' || warn "ufw-Status nicht lesbar"
|
||||||
|
echo
|
||||||
|
|
||||||
|
# --------------------------------------------------------------- CI-Ampel ---
|
||||||
|
echo "CI-AMPEL (Gitea)"
|
||||||
|
T=$(tr -d '[:space:]' < "$HOME/.config/gitea/create-token" 2>/dev/null)
|
||||||
|
if [ -z "$T" ]; then warn "kein Gitea-Token — CI nicht pruefbar"
|
||||||
|
else
|
||||||
|
curl -s -m 20 -H "Authorization: token $T" "$GITEA/api/v1/user/repos?limit=100" 2>/dev/null \
|
||||||
|
| python3 -c '
|
||||||
|
import sys, json
|
||||||
|
try:
|
||||||
|
repos = json.load(sys.stdin)
|
||||||
|
except Exception as e:
|
||||||
|
print(" ACHTUNG Repo-Liste nicht lesbar:", e); sys.exit(0)
|
||||||
|
print(f" OK {len(repos)} Repos in Gitea")
|
||||||
|
' 2>/dev/null || warn "Repo-Liste nicht lesbar"
|
||||||
|
fi
|
||||||
|
echo
|
||||||
|
|
||||||
|
# ------------------------------------------------------------- Sicherung ---
|
||||||
|
echo "SICHERUNGEN"
|
||||||
|
# Pfad aus backup.sh: DEST_DIR="$MODELS_DIR/mc2-backups"
|
||||||
|
SICHER="${MC_BACKUP_DIR:-/srv/models/mc2-backups}"
|
||||||
|
neuestes=$(find "$SICHER" -maxdepth 2 -type f -newermt '-2 days' 2>/dev/null | head -1)
|
||||||
|
anzahl=$(find "$SICHER" -maxdepth 2 -type f 2>/dev/null | wc -l)
|
||||||
|
if [ -n "$neuestes" ]; then
|
||||||
|
ok "Sicherung juenger als 2 Tage vorhanden ($anzahl Staende in $SICHER)"
|
||||||
|
elif [ "$anzahl" -gt 0 ]; then
|
||||||
|
bad "juengste Sicherung ist AELTER als 2 Tage ($anzahl Staende in $SICHER)"
|
||||||
|
else
|
||||||
|
bad "gar keine Sicherung in $SICHER"
|
||||||
|
fi
|
||||||
|
echo
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------ Platz ---
|
||||||
|
echo "PLATZ UND LAST"
|
||||||
|
# Nur eindeutige Dateisysteme: / und /srv liegen hier auf demselben Geraet,
|
||||||
|
# doppelt gemeldet las sich das wie ein Befund.
|
||||||
|
df -h --output=source,size,used,avail,pcent,target / /srv 2>/dev/null \
|
||||||
|
| awk '!gesehen[$1]++ {printf " %s\n", $0}'
|
||||||
|
echo " RAM: $(free -h | awk '/^Mem:/{print $3" von "$2" belegt"}')"
|
||||||
|
echo
|
||||||
|
|
||||||
|
# ------------------------------------------------------------- Warm/Kalt ---
|
||||||
|
echo "MODELLE IM SPEICHER"
|
||||||
|
curl -s -m 10 "$SWAP/running" 2>/dev/null \
|
||||||
|
| python3 -c '
|
||||||
|
import sys, json
|
||||||
|
try:
|
||||||
|
d = json.load(sys.stdin)
|
||||||
|
except Exception:
|
||||||
|
print(" ACHTUNG llama-swap-Status nicht lesbar"); sys.exit(0)
|
||||||
|
lauf = d.get("running", [])
|
||||||
|
if not lauf:
|
||||||
|
print(" OK kein Modell geladen (alles kalt)")
|
||||||
|
for m in lauf:
|
||||||
|
print(" OK " + str(m.get("model")) + " - " + str(m.get("state")))
|
||||||
|
'
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "ENDE IST-ZUSTAND"
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# stack-radar.sh — Job 3: "KI & Stack Radar" (21.08.2026).
|
||||||
|
#
|
||||||
|
# Ablauf: IST-Zustand holen (Fakten) -> Modell bewerten lassen (Prosa)
|
||||||
|
# -> ueber notify.sh melden (Telegram + Lucys Stimme)
|
||||||
|
#
|
||||||
|
# KUGELSICHER heisst hier konkret:
|
||||||
|
# * Die Fakten kommen aus stack-ist.sh, nicht aus dem Modell. Faellt das Modell
|
||||||
|
# aus, werden die ROTEN Zeilen trotzdem gemeldet — roh statt gar nicht.
|
||||||
|
# * Es meldet IMMER. "Alles gruen" ist ein Ergebnis, kein Grund zu schweigen.
|
||||||
|
# * Kein set -e: ein einzelner Fehlschlag darf den Bericht nicht abschneiden.
|
||||||
|
#
|
||||||
|
# Aufruf ueber Hermes-Cron:
|
||||||
|
# hermes cron create '0 8 * * 6' --name 'KI & Stack Radar' \
|
||||||
|
# --no-agent --script stack-radar.sh --deliver local
|
||||||
|
# (--no-agent, weil dieses Skript selbst meldet. Leere Ausgabe = Hermes schweigt.)
|
||||||
|
set -uo pipefail
|
||||||
|
|
||||||
|
HIER="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
IST_SKRIPT="${IST_SKRIPT:-$HOME/.hermes/scripts/stack-ist.sh}"
|
||||||
|
NOTIFY="${NOTIFY:-$HOME/mission-control-v2/deploy/notify.sh}"
|
||||||
|
GATEWAY="${GATEWAY_URL:-http://127.0.0.1:9010/v1}"
|
||||||
|
MODELL="${RADAR_MODELL:-fast}" # bewusst NICHT heavy: das laedt 68 GB und der
|
||||||
|
# Radar meldet danach seinen eigenen Speicherverbrauch als Befund
|
||||||
|
|
||||||
|
[ -x "$IST_SKRIPT" ] || IST_SKRIPT="$HIER/stack-ist.sh"
|
||||||
|
|
||||||
|
melde() {
|
||||||
|
if [ -x "$NOTIFY" ] || [ -f "$NOTIFY" ]; then
|
||||||
|
bash "$NOTIFY" -s "[Stack-Radar]" "$1"
|
||||||
|
else
|
||||||
|
# Letzte Rueckfallebene: wenigstens ins Log, damit nichts still verschwindet.
|
||||||
|
echo "[stack-radar] MELDEWEG FEHLT — Bericht folgt roh:" >&2
|
||||||
|
echo "$1" >&2
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------- 1. Fakten ---
|
||||||
|
IST="$(bash "$IST_SKRIPT" 2>&1)"
|
||||||
|
if [ -z "$IST" ]; then
|
||||||
|
melde "Radar konnte den IST-Zustand nicht erheben — $IST_SKRIPT lieferte nichts. Das ist selbst ein Befund: bitte nachsehen."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
ROT="$(printf '%s\n' "$IST" | grep -E '^\s+(ROT|ACHTUNG)' || true)"
|
||||||
|
ANZ_ROT="$(printf '%s\n' "$ROT" | grep -c 'ROT' || true)"
|
||||||
|
|
||||||
|
# ------------------------------------------------------- 2. Bewertung ------
|
||||||
|
# Das Modell bekommt NUR die Fakten und darf nichts dazuerfinden. Es soll
|
||||||
|
# einordnen, nicht ermitteln.
|
||||||
|
PROMPT="Du bist der Stack-Radar einer selbstgehosteten KI-Box. Unten steht der
|
||||||
|
gemessene IST-Zustand. Schreibe einen kurzen Bericht auf Deutsch, per Du.
|
||||||
|
|
||||||
|
Regeln:
|
||||||
|
- Erfinde NICHTS. Nur was unten steht.
|
||||||
|
- Beginne mit einer Zeile Gesamturteil.
|
||||||
|
- Dann: was ist ROT oder ACHTUNG, und was waere jeweils der naechste Schritt.
|
||||||
|
- Verbesserungsvorschlaege NUR, wenn sich aus den Zahlen unten wirklich etwas
|
||||||
|
Konkretes ergibt. Gibt es nichts, lass den Abschnitt ersatzlos weg. Schreibe
|
||||||
|
lieber gar keinen Vorschlag als einen ausgedachten - ein Bericht mit
|
||||||
|
Fuellmaterial wird nicht gelesen.
|
||||||
|
- Was du an den Messwerten selbst merkwuerdig findest, gehoert unter ACHTUNG,
|
||||||
|
nicht unter Verbesserungen.
|
||||||
|
- Wenn alles gruen ist, sag das in einem Satz und hoere auf.
|
||||||
|
- Keine Ueberschriften-Deko, keine Emojis, hoechstens 200 Woerter.
|
||||||
|
|
||||||
|
IST-ZUSTAND:
|
||||||
|
$IST"
|
||||||
|
|
||||||
|
ANTWORT=""
|
||||||
|
if NUTZLAST="$(python3 -c '
|
||||||
|
import json, sys
|
||||||
|
print(json.dumps({
|
||||||
|
"model": sys.argv[1],
|
||||||
|
"messages": [{"role": "user", "content": sys.argv[2]}],
|
||||||
|
"max_tokens": 900,
|
||||||
|
"temperature": 0.3,
|
||||||
|
}))' "$MODELL" "$PROMPT" 2>/dev/null)"; then
|
||||||
|
ANTWORT="$(curl -s -m 300 -X POST "$GATEWAY/chat/completions" \
|
||||||
|
-H 'Content-Type: application/json' -d "$NUTZLAST" 2>/dev/null \
|
||||||
|
| python3 -c '
|
||||||
|
import json, sys
|
||||||
|
try:
|
||||||
|
print(json.load(sys.stdin)["choices"][0]["message"]["content"].strip())
|
||||||
|
except Exception:
|
||||||
|
pass' 2>/dev/null)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ------------------------------------------------------------- 3. Melden ---
|
||||||
|
if [ -n "$ANTWORT" ]; then
|
||||||
|
melde "$ANTWORT"
|
||||||
|
else
|
||||||
|
# Modell stumm oder kaputt -> die Fakten gehen TROTZDEM raus. Genau dafuer
|
||||||
|
# steht das Modell nicht im kritischen Pfad.
|
||||||
|
if [ -n "$ROT" ]; then
|
||||||
|
melde "Radar: Bewertung durch das Modell hat nicht geklappt — hier die Rohbefunde:
|
||||||
|
|
||||||
|
$ROT"
|
||||||
|
else
|
||||||
|
melde "Radar: alles gruen (Bewertung durch das Modell hat nicht geklappt, die Messung schon)."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Hermes bekommt eine LEERE Ausgabe -> keine zweite Nachricht. Gemeldet wurde
|
||||||
|
# bereits ueber notify.sh, und das erreicht Telegram UND Lucys Stimme.
|
||||||
|
exit 0
|
||||||
Reference in New Issue
Block a user