From 6a4cd3231298ff9dceaa533c38f369f96e5474e7 Mon Sep 17 00:00:00 2001 From: chahinebrini Date: Wed, 29 Jul 2026 20:17:40 +0200 Subject: [PATCH] =?UTF-8?q?feat(pulse):=20notListening=20=E2=80=94=20Agent?= =?UTF-8?q?en=20mit=20offener=20Arbeit,=20die=20nicht=20im=20Loop=20sitzen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Der Fall, der den Menschen zum Postman macht: eine Task ist an einen Agenten adressiert, aber er sitzt nicht in agenthub_work. Er ist dann NICHT dormant (er lebt womöglich und hat gerade erst mit dem Hub gesprochen), hört aber nicht zu — die Arbeit bleibt liegen, ohne dass irgendwo ein Fehler erscheint. Real erlebt: TSK-0288 lag offen an codex adressiert, codex war `active` (75 s zuvor gesehen) mit inLoop=false. Der Architekt hat es nicht bemerkt und dem CEO stattdessen erzählt, die Task werde "automatisch" geclaimt. Genau diese Erwartungs-statt-Prüfung soll das Signal künftig unmöglich machen. `/architect/pulse` liefert dazu `notListening` mit Agent, Anzahl wartender Tasks und einem Klartext-Hinweis. Co-Authored-By: Claude Opus 5 (1M context) --- src/server/routes.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/server/routes.ts b/src/server/routes.ts index b674f7d..db00d61 100644 --- a/src/server/routes.ts +++ b/src/server/routes.ts @@ -120,6 +120,21 @@ export async function registerRoutes(app: FastifyInstance, cwd: string): Promise loopExitAgoSec: agent.loopExitAgoSec, loopExitReason: agent.loopExitReason, })), + // Der Fall, der den Menschen sonst zum Postman macht: eine Task ist an + // einen Agenten adressiert, aber er sitzt nicht im Work-Loop. Er ist dann + // nicht "dormant" (er lebt vielleicht sogar), hoert aber nicht zu — die + // Arbeit bleibt liegen, ohne dass irgendwo ein Fehler erscheint. Real + // erlebt: codex war `active` (75s zuvor gesehen) mit inLoop=false, + // waehrend TSK-0288 offen an ihn adressiert dalag. + notListening: health.agents + .filter((agent) => !agent.inLoop && agent.pendingCount > 0) + .map((agent) => ({ + name: agent.name, + waitingTasks: agent.pendingCount, + taskId: agent.waitingTaskId, + lastSeenAgoSec: agent.lastSeenAgoSec, + hint: `${agent.name} hat offene Arbeit, sitzt aber nicht im Work-Loop — anstossen oder Session neu starten.`, + })), messages: allMessages.slice(0, messageLimit).map(({ id, from, taskId, createdAt }) => ({ id, from, taskId, createdAt, })),