@llm-dev-ops/agentics-cli 2.7.27 → 2.7.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/ui/heartbeat.d.ts +15 -28
- package/dist/cli/ui/heartbeat.d.ts.map +1 -1
- package/dist/cli/ui/heartbeat.js +28 -145
- package/dist/cli/ui/heartbeat.js.map +1 -1
- package/dist/commands/agents.d.ts.map +1 -1
- package/dist/commands/agents.js +52 -4
- package/dist/commands/agents.js.map +1 -1
- package/package.json +1 -1
|
@@ -37,53 +37,40 @@
|
|
|
37
37
|
*/
|
|
38
38
|
declare class PipelineHeartbeat {
|
|
39
39
|
private readonly started;
|
|
40
|
-
private label;
|
|
41
40
|
private phase;
|
|
42
41
|
private phaseStartedAt;
|
|
43
42
|
private activity;
|
|
44
|
-
private activitySetAt;
|
|
45
|
-
private frameIndex;
|
|
46
43
|
private timer;
|
|
47
44
|
private mode;
|
|
48
45
|
private lastStderrWriteAt;
|
|
49
|
-
private statusLineRendered;
|
|
50
|
-
private originalStderrWrite;
|
|
51
46
|
private exitHandlersInstalled;
|
|
52
47
|
/**
|
|
53
48
|
* Begin emitting heartbeat ticks. Idempotent — repeated `start()` calls
|
|
54
49
|
* with a different label update the label but do not restart the timer.
|
|
50
|
+
*
|
|
51
|
+
* Always uses plain-line mode (no stderr interception, no in-place
|
|
52
|
+
* cursor manipulation). The previous TTY-with-interceptor design risked
|
|
53
|
+
* swallowing other writers' output when the wrapped function chain
|
|
54
|
+
* misbehaved (observed in 2.7.27 — the user saw NO output for 6 min
|
|
55
|
+
* because the interceptor ate every console.error). Plain-line mode
|
|
56
|
+
* interleaves with other logs but is provably safe.
|
|
55
57
|
*/
|
|
56
|
-
start(
|
|
58
|
+
start(_label: string): void;
|
|
57
59
|
/**
|
|
58
|
-
* Update the current phase label.
|
|
59
|
-
*
|
|
60
|
-
*
|
|
60
|
+
* Update the current phase label. Emits an immediate `[agentics] ▶ <phase>`
|
|
61
|
+
* line to stderr so the user sees the boundary even before the next 10s
|
|
62
|
+
* tick. Resets the per-phase timer.
|
|
61
63
|
*/
|
|
62
64
|
setPhase(phase: string): void;
|
|
63
65
|
/**
|
|
64
|
-
* Update the latest activity hint.
|
|
65
|
-
*
|
|
66
|
-
*
|
|
66
|
+
* Update the latest activity hint. Stored for the next 10s tick to print
|
|
67
|
+
* if no other writer beat it. Does NOT print on its own — that's what
|
|
68
|
+
* caused 2.7.27's silence.
|
|
67
69
|
*/
|
|
68
70
|
setActivity(activity: string): void;
|
|
69
|
-
/** Stop the timer
|
|
71
|
+
/** Stop the timer. */
|
|
70
72
|
stop(): void;
|
|
71
|
-
private tickTty;
|
|
72
|
-
private repaintTtyNow;
|
|
73
73
|
private tickPlain;
|
|
74
|
-
private paintStatusLine;
|
|
75
|
-
private clearStatusLine;
|
|
76
|
-
/**
|
|
77
|
-
* Wrap process.stderr.write so other writers (`console.error` etc.) clear
|
|
78
|
-
* the status line before printing, then we repaint after. This prevents
|
|
79
|
-
* the status line from being interleaved with normal log output in TTY
|
|
80
|
-
* mode. In plain mode the wrapper just records the timestamp so the 10s
|
|
81
|
-
* tick can self-suppress when other writes are happening.
|
|
82
|
-
*/
|
|
83
|
-
private installStderrInterceptor;
|
|
84
|
-
private uninstallStderrInterceptor;
|
|
85
|
-
/** Bypass the interceptor — used for our own status-line paint/clear. */
|
|
86
|
-
private writeRaw;
|
|
87
74
|
private installExitHandlers;
|
|
88
75
|
}
|
|
89
76
|
/** Process-wide singleton. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"heartbeat.d.ts","sourceRoot":"","sources":["../../../src/cli/ui/heartbeat.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;
|
|
1
|
+
{"version":3,"file":"heartbeat.d.ts","sourceRoot":"","sources":["../../../src/cli/ui/heartbeat.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAYH,cAAM,iBAAiB;IACrB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAc;IACtC,OAAO,CAAC,KAAK,CAAc;IAC3B,OAAO,CAAC,cAAc,CAAc;IACpC,OAAO,CAAC,QAAQ,CAAM;IACtB,OAAO,CAAC,KAAK,CAA+B;IAC5C,OAAO,CAAC,IAAI,CAA0B;IACtC,OAAO,CAAC,iBAAiB,CAAc;IACvC,OAAO,CAAC,qBAAqB,CAAS;IAEtC;;;;;;;;;;OAUG;IACH,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAU3B;;;;OAIG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAY7B;;;;OAIG;IACH,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAInC,sBAAsB;IACtB,IAAI,IAAI,IAAI;IAUZ,OAAO,CAAC,SAAS;IAYjB,OAAO,CAAC,mBAAmB;CAQ5B;AAED,8BAA8B;AAC9B,eAAO,MAAM,iBAAiB,mBAA0B,CAAC;AAEzD;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,qBAAqB,EAAE,MAAM,GAAG,MAAM,IAAI,CAkB3F"}
|
package/dist/cli/ui/heartbeat.js
CHANGED
|
@@ -35,28 +35,8 @@
|
|
|
35
35
|
* pipelineHeartbeat.stop();
|
|
36
36
|
* ```
|
|
37
37
|
*/
|
|
38
|
-
const FRAMES = ['◐', '◓', '◑', '◒'];
|
|
39
|
-
const TTY_FRAME_MS = 250;
|
|
40
38
|
const PLAIN_TICK_MS = 10_000;
|
|
41
39
|
const PLAIN_QUIET_THRESHOLD_MS = 9_000;
|
|
42
|
-
const COLOR = {
|
|
43
|
-
reset: '\x1b[0m',
|
|
44
|
-
dim: '\x1b[2m',
|
|
45
|
-
cyan: '\x1b[36m',
|
|
46
|
-
gray: '\x1b[90m',
|
|
47
|
-
};
|
|
48
|
-
/** True when stderr is a TTY and the user has not opted out. */
|
|
49
|
-
function isTtyEnabled() {
|
|
50
|
-
if (process.env['AGENTICS_NO_HEARTBEAT'] === '1')
|
|
51
|
-
return false;
|
|
52
|
-
if (process.env['AGENTICS_NO_LIVE'] === '1')
|
|
53
|
-
return false;
|
|
54
|
-
if (process.env['CI'])
|
|
55
|
-
return false;
|
|
56
|
-
if (process.env['NO_COLOR'])
|
|
57
|
-
return false;
|
|
58
|
-
return Boolean(process.stderr.isTTY);
|
|
59
|
-
}
|
|
60
40
|
function fmtElapsed(ms) {
|
|
61
41
|
const totalSec = Math.floor(ms / 1000);
|
|
62
42
|
const m = Math.floor(totalSec / 60);
|
|
@@ -65,93 +45,71 @@ function fmtElapsed(ms) {
|
|
|
65
45
|
}
|
|
66
46
|
class PipelineHeartbeat {
|
|
67
47
|
started = Date.now();
|
|
68
|
-
label = 'agentics';
|
|
69
48
|
phase = 'starting';
|
|
70
49
|
phaseStartedAt = Date.now();
|
|
71
50
|
activity = '';
|
|
72
|
-
activitySetAt = 0;
|
|
73
|
-
frameIndex = 0;
|
|
74
51
|
timer = null;
|
|
75
52
|
mode = 'off';
|
|
76
53
|
lastStderrWriteAt = Date.now();
|
|
77
|
-
statusLineRendered = false;
|
|
78
|
-
originalStderrWrite = null;
|
|
79
54
|
exitHandlersInstalled = false;
|
|
80
55
|
/**
|
|
81
56
|
* Begin emitting heartbeat ticks. Idempotent — repeated `start()` calls
|
|
82
57
|
* with a different label update the label but do not restart the timer.
|
|
58
|
+
*
|
|
59
|
+
* Always uses plain-line mode (no stderr interception, no in-place
|
|
60
|
+
* cursor manipulation). The previous TTY-with-interceptor design risked
|
|
61
|
+
* swallowing other writers' output when the wrapped function chain
|
|
62
|
+
* misbehaved (observed in 2.7.27 — the user saw NO output for 6 min
|
|
63
|
+
* because the interceptor ate every console.error). Plain-line mode
|
|
64
|
+
* interleaves with other logs but is provably safe.
|
|
83
65
|
*/
|
|
84
|
-
start(
|
|
85
|
-
this.label = label;
|
|
66
|
+
start(_label) {
|
|
86
67
|
if (this.timer)
|
|
87
68
|
return;
|
|
88
|
-
// AGENTICS_HEARTBEAT_OFF=1 disables the singleton entirely (e.g. for
|
|
89
|
-
// tests or for users who pipe stderr to a file and don't want the
|
|
90
|
-
// periodic chatter). Default behaviour: tty mode if stderr is a tty,
|
|
91
|
-
// plain mode otherwise.
|
|
92
69
|
if (process.env['AGENTICS_HEARTBEAT_OFF'] === '1')
|
|
93
70
|
return;
|
|
94
|
-
this.mode =
|
|
95
|
-
this.installStderrInterceptor();
|
|
71
|
+
this.mode = 'plain';
|
|
96
72
|
this.installExitHandlers();
|
|
97
|
-
|
|
98
|
-
this.timer = setInterval(() => this.tickTty(), TTY_FRAME_MS);
|
|
99
|
-
}
|
|
100
|
-
else {
|
|
101
|
-
this.timer = setInterval(() => this.tickPlain(), PLAIN_TICK_MS);
|
|
102
|
-
}
|
|
73
|
+
this.timer = setInterval(() => this.tickPlain(), PLAIN_TICK_MS);
|
|
103
74
|
this.timer.unref();
|
|
104
75
|
}
|
|
105
76
|
/**
|
|
106
|
-
* Update the current phase label.
|
|
107
|
-
*
|
|
108
|
-
*
|
|
77
|
+
* Update the current phase label. Emits an immediate `[agentics] ▶ <phase>`
|
|
78
|
+
* line to stderr so the user sees the boundary even before the next 10s
|
|
79
|
+
* tick. Resets the per-phase timer.
|
|
109
80
|
*/
|
|
110
81
|
setPhase(phase) {
|
|
82
|
+
if (this.phase === phase)
|
|
83
|
+
return;
|
|
111
84
|
this.phase = phase;
|
|
112
85
|
this.phaseStartedAt = Date.now();
|
|
113
86
|
this.activity = '';
|
|
114
|
-
this.
|
|
115
|
-
|
|
116
|
-
|
|
87
|
+
if (this.mode !== 'off') {
|
|
88
|
+
const elapsed = fmtElapsed(Date.now() - this.started);
|
|
89
|
+
process.stderr.write(`[agentics] ▶ ${phase} · T+${elapsed}\n`);
|
|
90
|
+
this.lastStderrWriteAt = Date.now();
|
|
91
|
+
}
|
|
117
92
|
}
|
|
118
93
|
/**
|
|
119
|
-
* Update the latest activity hint.
|
|
120
|
-
*
|
|
121
|
-
*
|
|
94
|
+
* Update the latest activity hint. Stored for the next 10s tick to print
|
|
95
|
+
* if no other writer beat it. Does NOT print on its own — that's what
|
|
96
|
+
* caused 2.7.27's silence.
|
|
122
97
|
*/
|
|
123
98
|
setActivity(activity) {
|
|
124
99
|
this.activity = activity;
|
|
125
|
-
this.activitySetAt = Date.now();
|
|
126
|
-
if (this.mode === 'tty')
|
|
127
|
-
this.repaintTtyNow();
|
|
128
100
|
}
|
|
129
|
-
/** Stop the timer
|
|
101
|
+
/** Stop the timer. */
|
|
130
102
|
stop() {
|
|
131
103
|
if (this.timer) {
|
|
132
104
|
clearInterval(this.timer);
|
|
133
105
|
this.timer = null;
|
|
134
106
|
}
|
|
135
|
-
if (this.mode === 'tty' && this.statusLineRendered) {
|
|
136
|
-
this.clearStatusLine();
|
|
137
|
-
}
|
|
138
|
-
this.uninstallStderrInterceptor();
|
|
139
107
|
this.mode = 'off';
|
|
140
108
|
}
|
|
141
109
|
// ── Internal ─────────────────────────────────────────────────────────────
|
|
142
|
-
tickTty() {
|
|
143
|
-
// Auto-suppress flicker: if setActivity fired within the last 750ms, skip
|
|
144
|
-
// this tick — the activity-driven repaint already happened.
|
|
145
|
-
if (Date.now() - this.activitySetAt < 750 && this.activitySetAt > 0)
|
|
146
|
-
return;
|
|
147
|
-
this.frameIndex = (this.frameIndex + 1) % FRAMES.length;
|
|
148
|
-
this.paintStatusLine();
|
|
149
|
-
}
|
|
150
|
-
repaintTtyNow() {
|
|
151
|
-
this.frameIndex = (this.frameIndex + 1) % FRAMES.length;
|
|
152
|
-
this.paintStatusLine();
|
|
153
|
-
}
|
|
154
110
|
tickPlain() {
|
|
111
|
+
if (this.mode === 'off')
|
|
112
|
+
return;
|
|
155
113
|
// Skip if some other writer just printed something — the user already
|
|
156
114
|
// has a fresh signal that we're alive.
|
|
157
115
|
if (Date.now() - this.lastStderrWriteAt < PLAIN_QUIET_THRESHOLD_MS)
|
|
@@ -159,78 +117,8 @@ class PipelineHeartbeat {
|
|
|
159
117
|
const elapsed = fmtElapsed(Date.now() - this.started);
|
|
160
118
|
const phaseSegment = this.phase ? `${this.phase} (${fmtElapsed(Date.now() - this.phaseStartedAt)})` : '';
|
|
161
119
|
const activitySegment = this.activity ? ` — ${this.activity}` : '';
|
|
162
|
-
|
|
163
|
-
this.
|
|
164
|
-
}
|
|
165
|
-
paintStatusLine() {
|
|
166
|
-
const frame = FRAMES[this.frameIndex];
|
|
167
|
-
const elapsedTotal = fmtElapsed(Date.now() - this.started);
|
|
168
|
-
const elapsedPhase = fmtElapsed(Date.now() - this.phaseStartedAt);
|
|
169
|
-
const phaseStr = `${COLOR.cyan}${this.phase}${COLOR.reset}`;
|
|
170
|
-
const elapsedStr = `${COLOR.dim}${elapsedTotal} total · ${elapsedPhase} phase${COLOR.reset}`;
|
|
171
|
-
const activityStr = this.activity ? ` ${COLOR.gray}·${COLOR.reset} ${this.activity}` : '';
|
|
172
|
-
const line = ` ${COLOR.cyan}${frame}${COLOR.reset} [${this.label}] ${phaseStr} ${COLOR.gray}·${COLOR.reset} ${elapsedStr}${activityStr}`;
|
|
173
|
-
this.clearStatusLine();
|
|
174
|
-
this.writeRaw(line);
|
|
175
|
-
this.statusLineRendered = true;
|
|
176
|
-
}
|
|
177
|
-
clearStatusLine() {
|
|
178
|
-
if (!this.statusLineRendered)
|
|
179
|
-
return;
|
|
180
|
-
// \r returns to column 0; \x1b[2K clears the entire line.
|
|
181
|
-
this.writeRaw('\r\x1b[2K');
|
|
182
|
-
this.statusLineRendered = false;
|
|
183
|
-
}
|
|
184
|
-
/**
|
|
185
|
-
* Wrap process.stderr.write so other writers (`console.error` etc.) clear
|
|
186
|
-
* the status line before printing, then we repaint after. This prevents
|
|
187
|
-
* the status line from being interleaved with normal log output in TTY
|
|
188
|
-
* mode. In plain mode the wrapper just records the timestamp so the 10s
|
|
189
|
-
* tick can self-suppress when other writes are happening.
|
|
190
|
-
*/
|
|
191
|
-
installStderrInterceptor() {
|
|
192
|
-
if (this.originalStderrWrite)
|
|
193
|
-
return;
|
|
194
|
-
const stderr = process.stderr;
|
|
195
|
-
this.originalStderrWrite = stderr.write.bind(stderr);
|
|
196
|
-
const orig = this.originalStderrWrite;
|
|
197
|
-
const self = this;
|
|
198
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
199
|
-
stderr.write = function (chunk, ...rest) {
|
|
200
|
-
self.lastStderrWriteAt = Date.now();
|
|
201
|
-
// If our own paint is in flight, just pass through.
|
|
202
|
-
if (self.mode !== 'tty') {
|
|
203
|
-
return orig(chunk, ...rest);
|
|
204
|
-
}
|
|
205
|
-
// For TTY: clear the status line, write the foreign output, repaint.
|
|
206
|
-
// We detect "our own writes" by a sentinel prefix — calls to writeRaw
|
|
207
|
-
// bypass this interceptor entirely.
|
|
208
|
-
if (self.statusLineRendered) {
|
|
209
|
-
orig('\r\x1b[2K');
|
|
210
|
-
self.statusLineRendered = false;
|
|
211
|
-
}
|
|
212
|
-
const ok = orig(chunk, ...rest);
|
|
213
|
-
// Defer repaint by one tick so chained writes (multi-line console.error)
|
|
214
|
-
// don't repaint between every line.
|
|
215
|
-
queueMicrotask(() => {
|
|
216
|
-
if (self.mode === 'tty' && !self.statusLineRendered && self.timer) {
|
|
217
|
-
self.paintStatusLine();
|
|
218
|
-
}
|
|
219
|
-
});
|
|
220
|
-
return ok;
|
|
221
|
-
};
|
|
222
|
-
}
|
|
223
|
-
uninstallStderrInterceptor() {
|
|
224
|
-
if (!this.originalStderrWrite)
|
|
225
|
-
return;
|
|
226
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
227
|
-
process.stderr.write = this.originalStderrWrite;
|
|
228
|
-
this.originalStderrWrite = null;
|
|
229
|
-
}
|
|
230
|
-
/** Bypass the interceptor — used for our own status-line paint/clear. */
|
|
231
|
-
writeRaw(s) {
|
|
232
|
-
const w = this.originalStderrWrite ?? process.stderr.write.bind(process.stderr);
|
|
233
|
-
w(s);
|
|
120
|
+
process.stderr.write(`[agentics] ⏳ still working — ${elapsed} — ${phaseSegment}${activitySegment}\n`);
|
|
121
|
+
this.lastStderrWriteAt = Date.now();
|
|
234
122
|
}
|
|
235
123
|
installExitHandlers() {
|
|
236
124
|
if (this.exitHandlersInstalled)
|
|
@@ -240,11 +128,6 @@ class PipelineHeartbeat {
|
|
|
240
128
|
process.on('exit', cleanup);
|
|
241
129
|
process.on('SIGINT', () => { cleanup(); process.exit(130); });
|
|
242
130
|
process.on('SIGTERM', () => { cleanup(); process.exit(143); });
|
|
243
|
-
process.on('uncaughtException', (err) => {
|
|
244
|
-
cleanup();
|
|
245
|
-
// Re-throw on next tick so default handler still prints + exits non-zero.
|
|
246
|
-
setImmediate(() => { throw err; });
|
|
247
|
-
});
|
|
248
131
|
}
|
|
249
132
|
}
|
|
250
133
|
/** Process-wide singleton. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"heartbeat.js","sourceRoot":"","sources":["../../../src/cli/ui/heartbeat.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,MAAM,
|
|
1
|
+
{"version":3,"file":"heartbeat.js","sourceRoot":"","sources":["../../../src/cli/ui/heartbeat.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../../src/commands/agents.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../../src/commands/agents.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/agents.js
CHANGED
|
@@ -3871,7 +3871,19 @@ export async function executeNaturalLanguageRoute(query, options) {
|
|
|
3871
3871
|
console.error(` Dispatching ${graphResult.agents.length} graph-routed agents...`);
|
|
3872
3872
|
pipelineHeartbeat.setActivity(`fleet: dispatching ${graphResult.agents.length} graph-routed agents`);
|
|
3873
3873
|
const agentPromises = [];
|
|
3874
|
-
|
|
3874
|
+
// ADR-PIPELINE-100 D2 — emit a `[FLEET-CALL]` line as each agent
|
|
3875
|
+
// STARTS and a result line when each FINISHES. The fleet runs in
|
|
3876
|
+
// parallel via Promise.allSettled, so without these lines the user
|
|
3877
|
+
// sees nothing for 1-3 minutes between the dispatch banner and the
|
|
3878
|
+
// aggregate result. Pre-2.7.27 builds had this same silence — it
|
|
3879
|
+
// never went away by itself when the heartbeat singleton was added.
|
|
3880
|
+
const fleetTotal = graphResult.agents.length;
|
|
3881
|
+
let fleetStartedCount = 0;
|
|
3882
|
+
let fleetFinishedCount = 0;
|
|
3883
|
+
graphResult.agents.forEach((ref, idx) => {
|
|
3884
|
+
const agentStart = Date.now();
|
|
3885
|
+
fleetStartedCount++;
|
|
3886
|
+
process.stderr.write(` [FLEET-CALL] [${String(idx + 1).padStart(3, ' ')}/${fleetTotal}] → ${ref.domain}/${ref.agent}\n`);
|
|
3875
3887
|
agentPromises.push((async () => {
|
|
3876
3888
|
try {
|
|
3877
3889
|
if (!REPO_LOCAL_DOMAINS.has(ref.domain)) {
|
|
@@ -3885,12 +3897,25 @@ export async function executeNaturalLanguageRoute(query, options) {
|
|
|
3885
3897
|
}
|
|
3886
3898
|
const payload = buildDomainPayload(ref.domain, ref.agent, query, correlationId);
|
|
3887
3899
|
const result = await executeAgentsInvokeCommand(ref.domain, ref.agent, payload, options);
|
|
3888
|
-
|
|
3900
|
+
const elapsed = ((Date.now() - agentStart) / 1000).toFixed(1);
|
|
3901
|
+
fleetFinishedCount++;
|
|
3902
|
+
const status = result.status ?? 200;
|
|
3903
|
+
const ok = status >= 200 && status < 300;
|
|
3904
|
+
process.stderr.write(` [FLEET-CALL] [${String(idx + 1).padStart(3, ' ')}/${fleetTotal}] ${ok ? '✓' : '✗'} ${ref.domain}/${ref.agent} (${elapsed}s, ${fleetFinishedCount}/${fleetTotal} done)\n`);
|
|
3905
|
+
pipelineHeartbeat.setActivity(`fleet: ${fleetFinishedCount}/${fleetTotal} agents complete`);
|
|
3906
|
+
return { kind: 'agent', domain: ref.domain, agent: ref.agent, status, response: result.response };
|
|
3889
3907
|
}
|
|
3890
3908
|
catch (err) {
|
|
3909
|
+
fleetFinishedCount++;
|
|
3910
|
+
const elapsed = ((Date.now() - agentStart) / 1000).toFixed(1);
|
|
3911
|
+
const errMsg = err instanceof Error ? err.message.slice(0, 80) : String(err).slice(0, 80);
|
|
3912
|
+
process.stderr.write(` [FLEET-CALL] [${String(idx + 1).padStart(3, ' ')}/${fleetTotal}] ✗ ${ref.domain}/${ref.agent} (${elapsed}s) — ${errMsg}\n`);
|
|
3891
3913
|
return { kind: 'agent', domain: ref.domain, agent: ref.agent, status: 502, response: { error: err instanceof Error ? err.message : String(err) } };
|
|
3892
3914
|
}
|
|
3893
3915
|
})());
|
|
3916
|
+
});
|
|
3917
|
+
if (fleetStartedCount > 0) {
|
|
3918
|
+
process.stderr.write(` [FLEET-CALL] all ${fleetStartedCount} agents in flight — awaiting responses...\n`);
|
|
3894
3919
|
}
|
|
3895
3920
|
const allResults = await Promise.allSettled([Promise.resolve(simResult), ...agentPromises]);
|
|
3896
3921
|
const elapsed = Date.now() - start;
|
|
@@ -4240,12 +4265,24 @@ export async function executeNaturalLanguageRoute(query, options) {
|
|
|
4240
4265
|
const WAVE_SIZE = 15;
|
|
4241
4266
|
const WAVE_DELAY_MS = 2000;
|
|
4242
4267
|
const agentPromises = [];
|
|
4268
|
+
// ADR-PIPELINE-100 D2 — per-agent visibility for the full-fleet path.
|
|
4269
|
+
// Without these per-call lines the user sees a "Wave N/M" banner then
|
|
4270
|
+
// 1-3 minutes of silence per wave, then nothing until ALL waves
|
|
4271
|
+
// finish. The user explicitly demanded "I should see them being
|
|
4272
|
+
// called" — these are the lines that satisfy that.
|
|
4273
|
+
const fleetTotal = fleetAgents.length;
|
|
4274
|
+
let fleetFinishedCount = 0;
|
|
4275
|
+
let agentDispatchIdx = 0;
|
|
4243
4276
|
for (let i = 0; i < fleetAgents.length; i += WAVE_SIZE) {
|
|
4244
4277
|
const wave = fleetAgents.slice(i, i + WAVE_SIZE);
|
|
4245
4278
|
const waveNum = Math.floor(i / WAVE_SIZE) + 1;
|
|
4246
4279
|
const totalWaves = Math.ceil(fleetAgents.length / WAVE_SIZE);
|
|
4247
|
-
console.error(` Wave ${waveNum}/${totalWaves}: ${wave.length} agents (${wave.map(a => `${a.domain}/${a.agent}`).slice(0, 3).join(', ')}${wave.length > 3 ? '...' : ''})`);
|
|
4280
|
+
console.error(` Wave ${waveNum}/${totalWaves}: dispatching ${wave.length} agents (${wave.map(a => `${a.domain}/${a.agent}`).slice(0, 3).join(', ')}${wave.length > 3 ? '...' : ''})`);
|
|
4248
4281
|
for (const { domain, agent } of wave) {
|
|
4282
|
+
agentDispatchIdx++;
|
|
4283
|
+
const myIdx = agentDispatchIdx;
|
|
4284
|
+
const agentStart = Date.now();
|
|
4285
|
+
process.stderr.write(` [FLEET-CALL] [${String(myIdx).padStart(3, ' ')}/${fleetTotal}] → ${domain}/${agent}\n`);
|
|
4249
4286
|
agentPromises.push((async () => {
|
|
4250
4287
|
try {
|
|
4251
4288
|
// Toggle repo-local per-agent: only copilot uses repo-local
|
|
@@ -4260,9 +4297,19 @@ export async function executeNaturalLanguageRoute(query, options) {
|
|
|
4260
4297
|
}
|
|
4261
4298
|
const payload = buildDomainPayload(domain, agent, query, correlationId);
|
|
4262
4299
|
const result = await executeAgentsInvokeCommand(domain, agent, payload, options);
|
|
4263
|
-
|
|
4300
|
+
fleetFinishedCount++;
|
|
4301
|
+
const elapsed = ((Date.now() - agentStart) / 1000).toFixed(1);
|
|
4302
|
+
const status = result.status ?? 200;
|
|
4303
|
+
const ok = status >= 200 && status < 300;
|
|
4304
|
+
process.stderr.write(` [FLEET-CALL] [${String(myIdx).padStart(3, ' ')}/${fleetTotal}] ${ok ? '✓' : '✗'} ${domain}/${agent} (${elapsed}s, ${fleetFinishedCount}/${fleetTotal} done)\n`);
|
|
4305
|
+
pipelineHeartbeat.setActivity(`fleet: ${fleetFinishedCount}/${fleetTotal} agents complete`);
|
|
4306
|
+
return { kind: 'agent', domain, agent, status, response: result.response };
|
|
4264
4307
|
}
|
|
4265
4308
|
catch (err) {
|
|
4309
|
+
fleetFinishedCount++;
|
|
4310
|
+
const elapsed = ((Date.now() - agentStart) / 1000).toFixed(1);
|
|
4311
|
+
const errMsg = err instanceof Error ? err.message.slice(0, 80) : String(err).slice(0, 80);
|
|
4312
|
+
process.stderr.write(` [FLEET-CALL] [${String(myIdx).padStart(3, ' ')}/${fleetTotal}] ✗ ${domain}/${agent} (${elapsed}s) — ${errMsg}\n`);
|
|
4266
4313
|
return { kind: 'agent', domain, agent, status: 502, response: { error: err instanceof Error ? err.message : String(err) } };
|
|
4267
4314
|
}
|
|
4268
4315
|
})());
|
|
@@ -4272,6 +4319,7 @@ export async function executeNaturalLanguageRoute(query, options) {
|
|
|
4272
4319
|
await new Promise(resolve => setTimeout(resolve, WAVE_DELAY_MS));
|
|
4273
4320
|
}
|
|
4274
4321
|
}
|
|
4322
|
+
process.stderr.write(` [FLEET-CALL] all ${fleetTotal} agents in flight — awaiting final responses...\n`);
|
|
4275
4323
|
const allResults = await Promise.allSettled([Promise.resolve(simResult), ...agentPromises]);
|
|
4276
4324
|
const elapsed = Date.now() - start;
|
|
4277
4325
|
// Restore repo-local mode setting
|