aboutsummaryrefslogtreecommitdiff
path: root/modules/core/module-orchestrator.js
diff options
context:
space:
mode:
Diffstat (limited to 'modules/core/module-orchestrator.js')
-rw-r--r--modules/core/module-orchestrator.js18
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');
}
}