feat/guard: watch_subagents Custom-Tool — proaktiver 30s-Watcher ohne externen Prozess

pi.registerTool('watch_subagents'): wartet 30s (respektiert AbortSignal),
gibt dann tmux-Status aller Sessions zurück. AGENTS.md: Orchestrator MUSS
das Tool nach jedem Return sofort neu aufrufen — permanente Polling-Schleife.
Kein SubConfirm, kein tmux send-keys, kein externer Prozess nötig.
This commit is contained in:
Raimund Bauer 2026-06-02 12:17:13 +02:00
parent 8de9502f1c
commit 5057f500a0
2 changed files with 45 additions and 7 deletions

View file

@ -52,13 +52,10 @@ 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:**
```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.
7. **`watch_subagents` sofort aufrufen** — das ist der permanente Subagenten-Watcher.
Das Tool wartet 30 Sekunden, gibt dann den Status aller tmux-Sessions zurück.
**Nach dem Return SOFORT wieder aufrufen** — immer und ohne Ausnahme.
Das ist die Polling-Schleife. Sie stoppt nie während die Session läuft.
8. **SubAgent Auto-Check System laden:** `~/.pi/agent/memory/subagent-autocheck.md` — Hintergrundinformation; SubConfirm übernimmt die proaktive Erkennung automatisch.

View file

@ -25,6 +25,7 @@
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
import { isToolCallEventType } from "@earendil-works/pi-coding-agent";
import { Type } from "typebox";
import { execSync } from "node:child_process";
import { readFileSync, writeFileSync, existsSync } from "node:fs";
@ -205,6 +206,46 @@ function tmuxSubagentenStatus(): string | null {
export default function (pi: ExtensionAPI) {
if (!ORCHESTRATOR_AKTIV) return;
// -------------------------------------------------------------------------
// watch_subagents — Proaktiver 30s-Watcher
//
// Wartet 30 Sekunden, dann gibt es den aktuellen Status aller tmux-Sessions
// zurück. Der Orchestrator MUSS dieses Tool sofort nach dem Return neu
// aufrufen — so entsteht eine permanente 30s-Polling-Schleife ohne externen
// Prozess. AbortSignal wird respektiert: bei Nutzer-Input endet der Sleep
// sofort und der Status wird sofort zurückgegeben.
// -------------------------------------------------------------------------
pi.registerTool({
name: "watch_subagents",
label: "Subagenten-Watcher (30s)",
description:
"Wartet 30 Sekunden und prüft dann alle Subagenten-Sessions. " +
"PFLICHT: Nach dem Return sofort wieder aufrufen. " +
"Nur im Orchestrator aktiv. Nutzer-Input unterbricht den Sleep sofort.",
parameters: Type.Object({}),
execute: async (_toolCallId, _params, signal, _onUpdate, _ctx) => {
await new Promise<void>((resolve) => {
const timer = setTimeout(resolve, 30_000);
signal?.addEventListener("abort", () => {
clearTimeout(timer);
resolve();
});
});
const status = tmuxSubagentenStatus();
const alerts = leseSubWatcherAlerts();
const parts = ["⏱️ [watch_subagents] 30s-Check:"];
if (status) parts.push(status);
if (alerts) parts.push(alerts);
if (!status && !alerts) parts.push("Alle Sessions aktiv, kein Handlungsbedarf.");
return {
content: [{ type: "text" as const, text: parts.join("\n\n") }],
details: {},
};
},
});
pi.on("tool_call", async (event, ctx) => {
let grund: string | null = null;