fix(hub): dormant ≠ beschäftigt — arbeitende Agenten nicht mehr als tot melden
`dormantAgents` filterte auf `!inLoop`. `inLoop` ist aber immer false, solange
ein Agent einen Task AUSFÜHRT — dadurch meldete der Pulse jeden hart
arbeitenden Agenten als dormant. Live gesehen: codex mit 17 s altem Check-in
stand als dormant im Pulse. Genau das Signal, auf das sich der Architekt
verlassen soll, hätte ihn dazu gebracht, funktionierende Agenten anzustoßen.
Jetzt zwei getrennte Fälle:
- `loopExitReason` gesetzt → der Agent hat den Loop ausdrücklich verlassen
und hört nicht mehr zu: sofort melden (unverändert).
- kein Exit-Grund, aber Task in Arbeit → er führt aus; erst nach
DORMANT_AFTER_MS (5 min) ohne Check-in ist das mein Fall.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
5fb2b6d6c6
commit
7a4ccaeb61
@ -22,6 +22,15 @@ import { VERSION } from '../../version.js';
|
|||||||
export const ACTIVE_WINDOW_MS = 2 * 60_000;
|
export const ACTIVE_WINDOW_MS = 2 * 60_000;
|
||||||
/** Longer than this without any action ⇒ the agent is stale/offline. */
|
/** Longer than this without any action ⇒ the agent is stale/offline. */
|
||||||
export const STALE_WINDOW_MS = 10 * 60_000;
|
export const STALE_WINDOW_MS = 10 * 60_000;
|
||||||
|
/**
|
||||||
|
* Ab wann gilt ein Agent als DORMANT (der Architekt muss eingreifen)?
|
||||||
|
*
|
||||||
|
* `inLoop` allein taugt dafür NICHT: es ist false, sobald ein Agent einen Task
|
||||||
|
* ausführt — ein hart arbeitender Agent sähe damit genauso aus wie ein toter.
|
||||||
|
* Entscheidend ist, wie lange der letzte Check-in her ist. Alles darunter ist
|
||||||
|
* normale Arbeit und darf keinen Alarm auslösen.
|
||||||
|
*/
|
||||||
|
export const DORMANT_AFTER_MS = 5 * 60_000;
|
||||||
|
|
||||||
export type AgentLight = 'active' | 'busy' | 'idle' | 'stale';
|
export type AgentLight = 'active' | 'busy' | 'idle' | 'stale';
|
||||||
|
|
||||||
|
|||||||
@ -11,7 +11,7 @@ import { getStatus, updateStatus } from '../core/services/statusService.js';
|
|||||||
import { autoDelegate, suggestDelegation } from '../core/services/delegateService.js';
|
import { autoDelegate, suggestDelegation } from '../core/services/delegateService.js';
|
||||||
import { computeBudget } from '../core/services/budgetService.js';
|
import { computeBudget } from '../core/services/budgetService.js';
|
||||||
import { getRoster } from '../core/services/rosterService.js';
|
import { getRoster } from '../core/services/rosterService.js';
|
||||||
import { computeHealth, enterLoop, leaveLoop, stampSeen } from '../core/services/presenceService.js';
|
import { computeHealth, enterLoop, leaveLoop, stampSeen, DORMANT_AFTER_MS } from '../core/services/presenceService.js';
|
||||||
import { resolvePending, hasPending } from '../core/services/checkinService.js';
|
import { resolvePending, hasPending } from '../core/services/checkinService.js';
|
||||||
import { loadConfig, saveConfig } from '../core/config.js';
|
import { loadConfig, saveConfig } from '../core/config.js';
|
||||||
import { agentIdentity } from '../core/services/identityService.js';
|
import { agentIdentity } from '../core/services/identityService.js';
|
||||||
@ -96,8 +96,23 @@ export async function registerRoutes(app: FastifyInstance, cwd: string): Promise
|
|||||||
assignedTo: task.assignedTo,
|
assignedTo: task.assignedTo,
|
||||||
updatedAt: task.updatedAt,
|
updatedAt: task.updatedAt,
|
||||||
})),
|
})),
|
||||||
|
// Zwei verschiedene Zustände, die nicht gleich behandelt werden dürfen:
|
||||||
|
//
|
||||||
|
// a) `loopExitReason` gesetzt → der Agent hat den Loop AUSDRÜCKLICH
|
||||||
|
// verlassen ("turn ended"). Er hört ab sofort nicht mehr zu; ein
|
||||||
|
// Reopen erreicht ihn nie. Sofort melden, ohne Wartezeit.
|
||||||
|
// b) kein Exit-Grund, aber ein Task in Arbeit → der Agent FÜHRT gerade
|
||||||
|
// aus. `inLoop` ist dabei immer false; ohne Zeitbedingung wäre jeder
|
||||||
|
// hart arbeitende Agent "dormant" und der Architekt würde Leute
|
||||||
|
// anstoßen, die einwandfrei laufen. Erst nach DORMANT_AFTER_MS ohne
|
||||||
|
// Check-in ist das ein Fall für mich.
|
||||||
dormantAgents: health.agents
|
dormantAgents: health.agents
|
||||||
.filter((agent) => !agent.inLoop && (agent.taskId || agent.loopExitReason))
|
.filter((agent) => {
|
||||||
|
if (agent.inLoop) return false;
|
||||||
|
if (agent.loopExitReason) return true;
|
||||||
|
if (!agent.taskId) return false;
|
||||||
|
return agent.lastSeenAgoSec === undefined || agent.lastSeenAgoSec * 1000 >= DORMANT_AFTER_MS;
|
||||||
|
})
|
||||||
.map((agent) => ({
|
.map((agent) => ({
|
||||||
name: agent.name,
|
name: agent.name,
|
||||||
taskId: agent.taskId,
|
taskId: agent.taskId,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user