From 8de9502f1c2e45fd130dd38ed2ad92828f414be1 Mon Sep 17 00:00:00 2001 From: Raimund Bauer Date: Tue, 2 Jun 2026 12:12:12 +0200 Subject: [PATCH] =?UTF-8?q?fix/subconfirm:=20Push-Mechanismus=20=E2=80=94?= =?UTF-8?q?=20injiziert=20Alerts=20direkt=20in=20Orchestrator-Session?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SubConfirm schrieb bisher nur in eine Alert-Datei, die der Guard nur beim nächsten Tool-Call liest. Ein idle Orchestrator schlief durch. Neu: --orchestrator Parameter — bei Stasis wird ein Alert- Text via tmux send-keys direkt in die Orchestrator-Session getippt, sofern Pi nicht gerade "Working..." zeigt. AGENTS.md: Start-Befehl mit --orchestrator aktualisiert. --- agent/AGENTS.md | 8 +++- bin/SubConfirm | 98 +++++++++++++++++++++++++++++++++---------------- 2 files changed, 73 insertions(+), 33 deletions(-) diff --git a/agent/AGENTS.md b/agent/AGENTS.md index ac8723a..62cc07d 100644 --- a/agent/AGENTS.md +++ b/agent/AGENTS.md @@ -52,7 +52,13 @@ Zu Beginn einer komplexen Aufgabe (bevor eigene Lösungen gebaut werden): 6. **Arbeitsweise laden:** `~/.pi/agent/memory/arbeitsweise.md` — Orchestrator + SubAgenten-Workflow. Der Orchestrator delegiert alle Arbeiten, SubAgenten speichern Ergebnisse in aufgabenspezifischen Unterverzeichnissen. -7. **SubConfirm starten:** `SubConfirm --skip "$(tmux display-message -p '#S')" &` — startet den Stasis-Detektor im Hintergrund. Läuft bereits? `pgrep -f SubConfirm` prüfen, nicht doppelt starten. +7. **SubConfirm starten:** + ```bash + _ME=$(tmux display-message -p '#S') + SubConfirm --orchestrator "$_ME" --skip "$_ME" & + ``` + Startet den Stasis-Detektor. Bei Stasis: schreibt in Alert-Datei UND injiziert direkt in diese Session. + Läuft bereits? `pgrep -fa SubConfirm` prüfen — nicht doppelt starten. 8. **SubAgent Auto-Check System laden:** `~/.pi/agent/memory/subagent-autocheck.md` — Hintergrundinformation; SubConfirm übernimmt die proaktive Erkennung automatisch. diff --git a/bin/SubConfirm b/bin/SubConfirm index b2cf468..9aa7f39 100644 --- a/bin/SubConfirm +++ b/bin/SubConfirm @@ -3,28 +3,28 @@ # # Läuft als Hintergrund-Daemon und prüft alle 30 Sekunden alle tmux-Sessions. # Wenn eine Session ihren Output seit >30s nicht verändert hat (Stasis), -# wird der vollständige Pane-Inhalt in die Alert-Datei geschrieben. -# Die arbeitsweise-guard.ts Extension zeigt diesen Alert dem Orchestrator -# beim nächsten Tool-Call — der Orchestrator beurteilt dann selbst ob -# Handlung nötig ist. -# -# KEIN Keyword-Matching — der Orchestrator entscheidet was zu tun ist. +# wird der vollständige Pane-Inhalt in die Alert-Datei geschrieben UND +# direkt in die Orchestrator-Session injiziert (tmux send-keys). # # Architektur: # SubConfirm → /tmp/.pi-subagent-alert → arbeitsweise-guard.ts → Orchestrator +# SubConfirm → tmux send-keys → Orchestrator-Session (direkter Push) # # Nutzung: -# SubConfirm & # Im Hintergrund starten -# SubConfirm --interval 15 & # Kürzeres Intervall -# SubConfirm --skip "main-session" & # Session ausschließen (Orchestrator-Session) -# pkill -f SubConfirm # Beenden +# SubConfirm --orchestrator "session-name" & # Mit Push in Orchestrator-Session +# SubConfirm --interval 15 & # Kürzeres Intervall +# SubConfirm --skip "main-session" & # Session ausschließen +# pkill -f SubConfirm # Beenden # -# Autostart: In AGENTS.md Session-Start-Checkliste eingetragen. +# Der --orchestrator und --skip Parameter sind oft gleich: +# NAME=$(tmux display-message -p '#S') +# SubConfirm --orchestrator "$NAME" --skip "$NAME" & set -euo pipefail INTERVAL=30 SKIP_SESSION="" +ORCHESTRATOR_SESSION="" REPORT_COOLDOWN=90 # Sekunden zwischen wiederholten Meldungen zur selben Session ALERT_FILE="/tmp/.pi-subagent-alert" STATE_DIR="/tmp/.pi-subconfirm-state" @@ -32,8 +32,9 @@ PID_FILE="/tmp/.pi-subconfirm.pid" while [[ $# -gt 0 ]]; do case "$1" in - --interval) INTERVAL="$2"; shift 2 ;; - --skip) SKIP_SESSION="$2"; shift 2 ;; + --interval) INTERVAL="$2"; shift 2 ;; + --skip) SKIP_SESSION="$2"; shift 2 ;; + --orchestrator) ORCHESTRATOR_SESSION="$2"; shift 2 ;; *) shift ;; esac done @@ -45,16 +46,59 @@ log() { echo "[SubConfirm $(date '+%H:%M:%S')] $1" >&2 } -alert() { - local msg="$1" - # In Alert-Datei schreiben (Guard zeigt das beim nächsten Tool-Call) - echo "$(date '+%H:%M:%S') $msg" >> "$ALERT_FILE" - # Desktop-Notification als zusätzlicher Hinweis - zenity --notification --text="SubConfirm: $msg" 2>/dev/null & - echo -e "\a" 2>/dev/null || true +# Prüft ob Pi im Orchestrator-Terminal gerade auf Eingabe wartet. +# Pi zeigt am Ende des Pane-Inhalts einen Eingabe-Cursor (leere Zeile oder ">"). +orchestrator_is_idle() { + [ -z "$ORCHESTRATOR_SESSION" ] && return 1 + local last + last=$(tmux capture-pane -t "$ORCHESTRATOR_SESSION" -p 2>/dev/null \ + | sed 's/\x1b\[[0-9;]*[mGKHF]//g' \ + | grep -v '^[[:space:]]*$' \ + | tail -3) + # Pi ist idle wenn die letzte sichtbare Zeile den Status-Bar zeigt + # (kein "Working..." oder Spinner sichtbar) + echo "$last" | grep -qE '(Working\.\.\.|⠋|⠙|⠹|⠸|⠼|⠴|⠦|⠧|⠇|⠏)' && return 1 + return 0 } -log "Gestartet (PID $$, Intervall: ${INTERVAL}s, Skip: '${SKIP_SESSION}')" +# Injiziert eine Nachricht in die Orchestrator-Session via tmux send-keys. +inject_to_orchestrator() { + local msg="$1" + [ -z "$ORCHESTRATOR_SESSION" ] && return + orchestrator_is_idle || return + # Nachricht tippen + Enter → Pi verarbeitet es als User-Input + tmux send-keys -t "$ORCHESTRATOR_SESSION" "$msg" Enter 2>/dev/null || true + log "Injiziert in Orchestrator-Session: ${msg:0:60}..." +} + +alert() { + local session="$1" + local pane_display="$2" + local short_msg="⏸️ SUBAGENT-STASIS [$session] — braucht Eingabe" + + # 1. In Alert-Datei schreiben (Guard zeigt das beim nächsten Tool-Call) + cat >> "$ALERT_FILE" </dev/null & + echo -e "\a" 2>/dev/null || true + + # 3. Direkt in Orchestrator-Session injizieren wenn idle + inject_to_orchestrator "$short_msg — bitte prüfen und reagieren (tmux capture-pane -t '$session' -p | tail -20)" +} + +log "Gestartet (PID $$, Intervall: ${INTERVAL}s, Skip: '${SKIP_SESSION}', Orchestrator: '${ORCHESTRATOR_SESSION}')" while true; do sleep "$INTERVAL" @@ -80,26 +124,16 @@ while true; do PREV=$(cat "$STATE_FILE" 2>/dev/null || echo "") if [ "$CURRENT" = "$PREV" ]; then - # Stasis — Output hat sich nicht verändert seit letztem Check NOW=$(date +%s) LAST_REPORT=$(cat "$REPORT_FILE" 2>/dev/null || echo 0) if [ $((NOW - LAST_REPORT)) -gt "$REPORT_COOLDOWN" ]; then PANE_DISPLAY=$(echo "$CURRENT" | tr '§' '\n') - alert "⏸️ SUBAGENT-STASIS [$session] — Output seit >${INTERVAL}s unverändert. - -Pane-Inhalt: -$PANE_DISPLAY - -Mögliche Reaktionen: - Bestätigen (Yes): tmux send-keys -t \"$session\" \"\" Enter - Ablehnen (No): tmux send-keys -t \"$session\" \"\" && tmux send-keys -t \"$session\" \"\" Enter - Ignorieren: (keine Aktion — nächste Meldung in ${REPORT_COOLDOWN}s wenn noch Stasis)" + alert "$session" "$PANE_DISPLAY" log "Stasis gemeldet: $session" echo "$NOW" > "$REPORT_FILE" fi else - # Aktivität — State aktualisieren, Stasis-Zustand zurücksetzen echo "$CURRENT" > "$STATE_FILE" rm -f "$REPORT_FILE" fi