diff options
Diffstat (limited to 'modules/core/module-orchestrator.js')
| -rw-r--r-- | modules/core/module-orchestrator.js | 18 |
1 files changed, 12 insertions, 6 deletions
diff --git a/modules/core/module-orchestrator.js b/modules/core/module-orchestrator.js index d03f7eb..b3b76cd 100644 --- a/modules/core/module-orchestrator.js +++ b/modules/core/module-orchestrator.js @@ -25,6 +25,9 @@ class OrchestratorModule { this._a2aPollTimer = null; this._heartbeatInterval = null; this._a2aMessages = {}; + // v4.6.68: on-demand is the design (decision 2026-10-23). Delegations — not + // "agents ever scheduled" — is the number that means something. + this._delegations = 0; this._restartBackoffs = {}; this._eventBus = {}; this._idleSweepInterval = null; @@ -1077,6 +1080,7 @@ class OrchestratorModule { async delegateTask(task, opts = {}) { if (!task) return this.terminal.print('Usage: orchestrate <task description>', 'error'); + this._delegations = (this._delegations || 0) + 1; // Parallel fan-out: decompose and run sub-tasks concurrently if (opts.parallel) { @@ -1423,7 +1427,7 @@ class OrchestratorModule { // v4.6.63: say what the state MEANS. A parked agent with 0 assignments and a parked // agent between tasks looked identical from outside (packet §6). const agentsArr = Object.values(this._agents); - const everScheduled = agentsArr.filter(a => (a.tasksAssigned || 0) > 0).length; + const available = agentsArr.filter(a => a.status === 'idle' || a.status === 'sleeping').length; const describe = (a) => { const n = a.tasksAssigned || 0; const since = a.createdAt ? String(a.createdAt).slice(0, 16).replace('T', ' ') : '?'; @@ -1436,19 +1440,21 @@ class OrchestratorModule { } if (n === 0) { return (a.status === 'sleeping' ? 'parked' : a.status) + - ` — NEVER SCHEDULED (0 tasks since ${since})`; + ` — available, no delegations yet (spawned ${since})`; } return (a.status === 'sleeping' ? 'parked' : a.status) + - ` — waiting for work (${n} task(s), last ${last || '?'})`; + ` — ${n} delegation(s), last ${last || '?'}`; }; agentsArr.forEach(a => { const modelInfo = a.model ? ` [model: ${a.model}]` : ''; const backoff = a.nextRestartAt && a.nextRestartAt > Date.now() ? ` [restart in ${Math.round((a.nextRestartAt - Date.now()) / 1000)}s]` : ''; this.terminal.print(` ${a.id} [${a.role}] — ${describe(a)}${modelInfo}${backoff}`, 'info'); }); - this.terminal.print(` Dispatch: ${everScheduled}/${total} agent(s) have ever been given a task`, everScheduled === 0 && total > 0 ? 'warning' : 'info'); - if (everScheduled === 0 && total > 0) { - this.terminal.print(' ⚠️ No agent has ever been scheduled — spawning is not dispatching. Use orchestrate <task> or orchestrator-spawn <role> <task>.', 'warning'); + // v4.6.68: on-demand by design — a worker with nothing to do is healthy, not broken. + // The number to watch is how many delegations the AI actually made. + this.terminal.print(` Mode: on-demand — ${available}/${total} worker(s) available, ${this._delegations || 0} delegation(s) this session`, 'info'); + if (total > 0 && (this._delegations || 0) === 0) { + this.terminal.print(' Workers wait for delegate_task — spawn-on-demand, no background dispatch queue by design.', 'text-muted'); } } |