@llm-dev-ops/agentics-cli 2.7.26 → 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 +88 -0
- package/dist/cli/ui/heartbeat.d.ts.map +1 -0
- package/dist/cli/ui/heartbeat.js +158 -0
- package/dist/cli/ui/heartbeat.js.map +1 -0
- package/dist/commands/agents.d.ts.map +1 -1
- package/dist/commands/agents.js +65 -24
- package/dist/commands/agents.js.map +1 -1
- package/dist/pipeline/auto-chain.d.ts.map +1 -1
- package/dist/pipeline/auto-chain.js +86 -2
- package/dist/pipeline/auto-chain.js.map +1 -1
- package/dist/pipeline/local-fallback/phase5a-local-fallback.d.ts +18 -21
- package/dist/pipeline/local-fallback/phase5a-local-fallback.d.ts.map +1 -1
- package/dist/pipeline/local-fallback/phase5a-local-fallback.js +287 -94
- package/dist/pipeline/local-fallback/phase5a-local-fallback.js.map +1 -1
- package/dist/pipeline/phases/prompt-generator.js +65 -136
- package/dist/pipeline/phases/prompt-generator.js.map +1 -1
- package/dist/pipeline/ruflo-phase-executor.d.ts.map +1 -1
- package/dist/pipeline/ruflo-phase-executor.js +12 -1
- package/dist/pipeline/ruflo-phase-executor.js.map +1 -1
- package/dist/synthesis/agent-fleet-decomposer.d.ts +100 -0
- package/dist/synthesis/agent-fleet-decomposer.d.ts.map +1 -0
- package/dist/synthesis/agent-fleet-decomposer.js +550 -0
- package/dist/synthesis/agent-fleet-decomposer.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ADR-PIPELINE-099 D3 + D4 — Process-wide pipeline heartbeat.
|
|
3
|
+
*
|
|
4
|
+
* Singleton that emits a continuous "still alive" signal for the entire
|
|
5
|
+
* `agentics ask` lifecycle, not just Phase 1. Replaces the per-call heartbeat
|
|
6
|
+
* inside `executeNaturalLanguageRoute` which died as soon as auto-chain
|
|
7
|
+
* took over Phases 2–7, leaving the user staring at a silent terminal for
|
|
8
|
+
* minutes at a stretch.
|
|
9
|
+
*
|
|
10
|
+
* Two render modes:
|
|
11
|
+
*
|
|
12
|
+
* - **TTY** (`stderr.isTTY` and not opted out): a single status line is
|
|
13
|
+
* repainted in place every 250ms at the cursor position using a four-frame
|
|
14
|
+
* spinner (`◐ ◓ ◑ ◒`). The line shows the current phase, total elapsed
|
|
15
|
+
* time, time-since-phase-entry, and the most recent activity hint set by
|
|
16
|
+
* the pipeline. Other writers (`console.error`, `process.stderr.write`)
|
|
17
|
+
* print above the status line via cursor save/restore.
|
|
18
|
+
*
|
|
19
|
+
* - **Non-TTY** (CI, piped output, `AGENTICS_NO_HEARTBEAT=1`): the spinner
|
|
20
|
+
* is suppressed; instead a plain `[agentics] ⏳ still working — Phase X
|
|
21
|
+
* (MM:SS) — <activity>` line prints every 10 seconds, throttled to skip
|
|
22
|
+
* any tick that happened within 9s of another stderr write.
|
|
23
|
+
*
|
|
24
|
+
* The singleton is crash-safe: `process.on('exit' | 'SIGINT' | 'SIGTERM')`
|
|
25
|
+
* handlers call `stop()` to clear the live status line so it doesn't leave a
|
|
26
|
+
* stale frame on the user's terminal after Ctrl-C.
|
|
27
|
+
*
|
|
28
|
+
* Usage:
|
|
29
|
+
* ```ts
|
|
30
|
+
* import { pipelineHeartbeat } from './cli/ui/heartbeat.js';
|
|
31
|
+
* pipelineHeartbeat.start('agentics ask');
|
|
32
|
+
* pipelineHeartbeat.setPhase('Phase 4 — ADRs + DDDs');
|
|
33
|
+
* pipelineHeartbeat.setActivity('ruflo: writing adr-007');
|
|
34
|
+
* // ... long-running work ...
|
|
35
|
+
* pipelineHeartbeat.stop();
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
declare class PipelineHeartbeat {
|
|
39
|
+
private readonly started;
|
|
40
|
+
private phase;
|
|
41
|
+
private phaseStartedAt;
|
|
42
|
+
private activity;
|
|
43
|
+
private timer;
|
|
44
|
+
private mode;
|
|
45
|
+
private lastStderrWriteAt;
|
|
46
|
+
private exitHandlersInstalled;
|
|
47
|
+
/**
|
|
48
|
+
* Begin emitting heartbeat ticks. Idempotent — repeated `start()` calls
|
|
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.
|
|
57
|
+
*/
|
|
58
|
+
start(_label: string): void;
|
|
59
|
+
/**
|
|
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.
|
|
63
|
+
*/
|
|
64
|
+
setPhase(phase: string): void;
|
|
65
|
+
/**
|
|
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.
|
|
69
|
+
*/
|
|
70
|
+
setActivity(activity: string): void;
|
|
71
|
+
/** Stop the timer. */
|
|
72
|
+
stop(): void;
|
|
73
|
+
private tickPlain;
|
|
74
|
+
private installExitHandlers;
|
|
75
|
+
}
|
|
76
|
+
/** Process-wide singleton. */
|
|
77
|
+
export declare const pipelineHeartbeat: PipelineHeartbeat;
|
|
78
|
+
/**
|
|
79
|
+
* Bracket a phase with `[BEGIN]` / `[END]` log markers and update the
|
|
80
|
+
* heartbeat's phase label. Call at the top of each phase in auto-chain.
|
|
81
|
+
*
|
|
82
|
+
* Returns a `done()` closure that emits the matching `[END]` line when the
|
|
83
|
+
* phase finishes. Always pair `phaseBoundary` with its returned `done` to
|
|
84
|
+
* keep the trace greppable.
|
|
85
|
+
*/
|
|
86
|
+
export declare function phaseBoundary(phaseLabel: string, totalElapsedFromStart: number): () => void;
|
|
87
|
+
export {};
|
|
88
|
+
//# sourceMappingURL=heartbeat.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
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"}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ADR-PIPELINE-099 D3 + D4 — Process-wide pipeline heartbeat.
|
|
3
|
+
*
|
|
4
|
+
* Singleton that emits a continuous "still alive" signal for the entire
|
|
5
|
+
* `agentics ask` lifecycle, not just Phase 1. Replaces the per-call heartbeat
|
|
6
|
+
* inside `executeNaturalLanguageRoute` which died as soon as auto-chain
|
|
7
|
+
* took over Phases 2–7, leaving the user staring at a silent terminal for
|
|
8
|
+
* minutes at a stretch.
|
|
9
|
+
*
|
|
10
|
+
* Two render modes:
|
|
11
|
+
*
|
|
12
|
+
* - **TTY** (`stderr.isTTY` and not opted out): a single status line is
|
|
13
|
+
* repainted in place every 250ms at the cursor position using a four-frame
|
|
14
|
+
* spinner (`◐ ◓ ◑ ◒`). The line shows the current phase, total elapsed
|
|
15
|
+
* time, time-since-phase-entry, and the most recent activity hint set by
|
|
16
|
+
* the pipeline. Other writers (`console.error`, `process.stderr.write`)
|
|
17
|
+
* print above the status line via cursor save/restore.
|
|
18
|
+
*
|
|
19
|
+
* - **Non-TTY** (CI, piped output, `AGENTICS_NO_HEARTBEAT=1`): the spinner
|
|
20
|
+
* is suppressed; instead a plain `[agentics] ⏳ still working — Phase X
|
|
21
|
+
* (MM:SS) — <activity>` line prints every 10 seconds, throttled to skip
|
|
22
|
+
* any tick that happened within 9s of another stderr write.
|
|
23
|
+
*
|
|
24
|
+
* The singleton is crash-safe: `process.on('exit' | 'SIGINT' | 'SIGTERM')`
|
|
25
|
+
* handlers call `stop()` to clear the live status line so it doesn't leave a
|
|
26
|
+
* stale frame on the user's terminal after Ctrl-C.
|
|
27
|
+
*
|
|
28
|
+
* Usage:
|
|
29
|
+
* ```ts
|
|
30
|
+
* import { pipelineHeartbeat } from './cli/ui/heartbeat.js';
|
|
31
|
+
* pipelineHeartbeat.start('agentics ask');
|
|
32
|
+
* pipelineHeartbeat.setPhase('Phase 4 — ADRs + DDDs');
|
|
33
|
+
* pipelineHeartbeat.setActivity('ruflo: writing adr-007');
|
|
34
|
+
* // ... long-running work ...
|
|
35
|
+
* pipelineHeartbeat.stop();
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
const PLAIN_TICK_MS = 10_000;
|
|
39
|
+
const PLAIN_QUIET_THRESHOLD_MS = 9_000;
|
|
40
|
+
function fmtElapsed(ms) {
|
|
41
|
+
const totalSec = Math.floor(ms / 1000);
|
|
42
|
+
const m = Math.floor(totalSec / 60);
|
|
43
|
+
const s = totalSec % 60;
|
|
44
|
+
return `${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}`;
|
|
45
|
+
}
|
|
46
|
+
class PipelineHeartbeat {
|
|
47
|
+
started = Date.now();
|
|
48
|
+
phase = 'starting';
|
|
49
|
+
phaseStartedAt = Date.now();
|
|
50
|
+
activity = '';
|
|
51
|
+
timer = null;
|
|
52
|
+
mode = 'off';
|
|
53
|
+
lastStderrWriteAt = Date.now();
|
|
54
|
+
exitHandlersInstalled = false;
|
|
55
|
+
/**
|
|
56
|
+
* Begin emitting heartbeat ticks. Idempotent — repeated `start()` calls
|
|
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.
|
|
65
|
+
*/
|
|
66
|
+
start(_label) {
|
|
67
|
+
if (this.timer)
|
|
68
|
+
return;
|
|
69
|
+
if (process.env['AGENTICS_HEARTBEAT_OFF'] === '1')
|
|
70
|
+
return;
|
|
71
|
+
this.mode = 'plain';
|
|
72
|
+
this.installExitHandlers();
|
|
73
|
+
this.timer = setInterval(() => this.tickPlain(), PLAIN_TICK_MS);
|
|
74
|
+
this.timer.unref();
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
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.
|
|
80
|
+
*/
|
|
81
|
+
setPhase(phase) {
|
|
82
|
+
if (this.phase === phase)
|
|
83
|
+
return;
|
|
84
|
+
this.phase = phase;
|
|
85
|
+
this.phaseStartedAt = Date.now();
|
|
86
|
+
this.activity = '';
|
|
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
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
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.
|
|
97
|
+
*/
|
|
98
|
+
setActivity(activity) {
|
|
99
|
+
this.activity = activity;
|
|
100
|
+
}
|
|
101
|
+
/** Stop the timer. */
|
|
102
|
+
stop() {
|
|
103
|
+
if (this.timer) {
|
|
104
|
+
clearInterval(this.timer);
|
|
105
|
+
this.timer = null;
|
|
106
|
+
}
|
|
107
|
+
this.mode = 'off';
|
|
108
|
+
}
|
|
109
|
+
// ── Internal ─────────────────────────────────────────────────────────────
|
|
110
|
+
tickPlain() {
|
|
111
|
+
if (this.mode === 'off')
|
|
112
|
+
return;
|
|
113
|
+
// Skip if some other writer just printed something — the user already
|
|
114
|
+
// has a fresh signal that we're alive.
|
|
115
|
+
if (Date.now() - this.lastStderrWriteAt < PLAIN_QUIET_THRESHOLD_MS)
|
|
116
|
+
return;
|
|
117
|
+
const elapsed = fmtElapsed(Date.now() - this.started);
|
|
118
|
+
const phaseSegment = this.phase ? `${this.phase} (${fmtElapsed(Date.now() - this.phaseStartedAt)})` : '';
|
|
119
|
+
const activitySegment = this.activity ? ` — ${this.activity}` : '';
|
|
120
|
+
process.stderr.write(`[agentics] ⏳ still working — ${elapsed} — ${phaseSegment}${activitySegment}\n`);
|
|
121
|
+
this.lastStderrWriteAt = Date.now();
|
|
122
|
+
}
|
|
123
|
+
installExitHandlers() {
|
|
124
|
+
if (this.exitHandlersInstalled)
|
|
125
|
+
return;
|
|
126
|
+
this.exitHandlersInstalled = true;
|
|
127
|
+
const cleanup = () => this.stop();
|
|
128
|
+
process.on('exit', cleanup);
|
|
129
|
+
process.on('SIGINT', () => { cleanup(); process.exit(130); });
|
|
130
|
+
process.on('SIGTERM', () => { cleanup(); process.exit(143); });
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/** Process-wide singleton. */
|
|
134
|
+
export const pipelineHeartbeat = new PipelineHeartbeat();
|
|
135
|
+
/**
|
|
136
|
+
* Bracket a phase with `[BEGIN]` / `[END]` log markers and update the
|
|
137
|
+
* heartbeat's phase label. Call at the top of each phase in auto-chain.
|
|
138
|
+
*
|
|
139
|
+
* Returns a `done()` closure that emits the matching `[END]` line when the
|
|
140
|
+
* phase finishes. Always pair `phaseBoundary` with its returned `done` to
|
|
141
|
+
* keep the trace greppable.
|
|
142
|
+
*/
|
|
143
|
+
export function phaseBoundary(phaseLabel, totalElapsedFromStart) {
|
|
144
|
+
const tStart = Date.now();
|
|
145
|
+
const t = fmtElapsed(totalElapsedFromStart);
|
|
146
|
+
pipelineHeartbeat.setPhase(phaseLabel);
|
|
147
|
+
// ANSI bold for the [BEGIN] marker so it stands out in scrollback.
|
|
148
|
+
process.stderr.write(`\n${'='.repeat(72)}\n` +
|
|
149
|
+
` ▶ ${phaseLabel} [BEGIN] T+${t}\n` +
|
|
150
|
+
`${'='.repeat(72)}\n`);
|
|
151
|
+
return () => {
|
|
152
|
+
const dur = fmtElapsed(Date.now() - tStart);
|
|
153
|
+
process.stderr.write(`${'='.repeat(72)}\n` +
|
|
154
|
+
` ▼ ${phaseLabel} ✓ completed (${dur}) [END]\n` +
|
|
155
|
+
`${'='.repeat(72)}\n\n`);
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=heartbeat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAMxD,OAAO,EAAwB,KAAK,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;
|
|
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
|
@@ -17,6 +17,7 @@ import { execFileSync } from 'node:child_process';
|
|
|
17
17
|
import { isTransientFailure, isTerminalFailure } from '../errors/transient.js';
|
|
18
18
|
import { recordDegradation, drainDegradations } from '../observability/degradations.js';
|
|
19
19
|
import { computePhase1Verdict } from '../pipeline/phase1-verdict.js';
|
|
20
|
+
import { pipelineHeartbeat } from '../cli/ui/heartbeat.js';
|
|
20
21
|
// ============================================================================
|
|
21
22
|
// ADR-066: Copilot agents via claude --print (Claude Max — no API key needed)
|
|
22
23
|
// ============================================================================
|
|
@@ -3779,26 +3780,14 @@ export async function executeNaturalLanguageRoute(query, options) {
|
|
|
3779
3780
|
// the user sees the route is executing even if subsequent operations
|
|
3780
3781
|
// (graph load, ruvector simulation, fleet dispatch) take a while.
|
|
3781
3782
|
process.stderr.write(`[agentics] route entered — query="${query.slice(0, 100)}${query.length > 100 ? '…' : ''}" depth=${options.depth ?? 'lite'} trace=${correlationId.slice(0, 8)}\n`);
|
|
3782
|
-
//
|
|
3783
|
-
//
|
|
3784
|
-
//
|
|
3785
|
-
//
|
|
3786
|
-
//
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
|
|
3790
|
-
process.stderr.write = (chunk, ...rest) => {
|
|
3791
|
-
lastOutputAt = Date.now();
|
|
3792
|
-
return realStderrWrite(chunk, ...rest);
|
|
3793
|
-
};
|
|
3794
|
-
const heartbeat = setInterval(() => {
|
|
3795
|
-
if (Date.now() - lastOutputAt < 9_000)
|
|
3796
|
-
return; // something else just wrote
|
|
3797
|
-
const elapsedSec = Math.floor((Date.now() - start) / 1000);
|
|
3798
|
-
realStderrWrite(`[agentics] ⏳ still working — ${elapsedSec}s elapsed\n`);
|
|
3799
|
-
lastOutputAt = Date.now();
|
|
3800
|
-
}, 10_000);
|
|
3801
|
-
heartbeat.unref();
|
|
3783
|
+
// ADR-PIPELINE-099 D3 — process-wide heartbeat. Survives across the
|
|
3784
|
+
// executeNaturalLanguageRoute → executeAutoChain handoff (the previous
|
|
3785
|
+
// per-call heartbeat died at the function boundary, leaving Phases 2–7
|
|
3786
|
+
// silent for minutes at a time). Idempotent — auto-chain calls start()
|
|
3787
|
+
// again with no effect. Stop happens at the end of executeAutoChain or
|
|
3788
|
+
// via the singleton's exit handlers.
|
|
3789
|
+
pipelineHeartbeat.start('agentics ask');
|
|
3790
|
+
pipelineHeartbeat.setPhase('Phase 1 — Fleet Dispatch + Simulation');
|
|
3802
3791
|
// ========================================================================
|
|
3803
3792
|
// ADR-030: Capability Graph Routing
|
|
3804
3793
|
//
|
|
@@ -3841,6 +3830,7 @@ export async function executeNaturalLanguageRoute(query, options) {
|
|
|
3841
3830
|
console.error(graphResult.routing.explanation);
|
|
3842
3831
|
// Run ruvector simulation first (same as full-fleet path, ADR-016)
|
|
3843
3832
|
console.error(' [RUVECTOR] Running simulation before graph-routed dispatch (ADR-016)...');
|
|
3833
|
+
pipelineHeartbeat.setActivity(`ruvector: simulating ${graphResult.routing.totalAgents}-agent graph route`);
|
|
3844
3834
|
const simResult = await (async () => {
|
|
3845
3835
|
const MAX_RETRIES = 3;
|
|
3846
3836
|
let lastErr;
|
|
@@ -3879,8 +3869,21 @@ export async function executeNaturalLanguageRoute(query, options) {
|
|
|
3879
3869
|
const REPO_LOCAL_DOMAINS = new Set(['copilot']);
|
|
3880
3870
|
const prevLocalAgents = process.env['AGENTICS_LOCAL_AGENTS'];
|
|
3881
3871
|
console.error(` Dispatching ${graphResult.agents.length} graph-routed agents...`);
|
|
3872
|
+
pipelineHeartbeat.setActivity(`fleet: dispatching ${graphResult.agents.length} graph-routed agents`);
|
|
3882
3873
|
const agentPromises = [];
|
|
3883
|
-
|
|
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`);
|
|
3884
3887
|
agentPromises.push((async () => {
|
|
3885
3888
|
try {
|
|
3886
3889
|
if (!REPO_LOCAL_DOMAINS.has(ref.domain)) {
|
|
@@ -3894,12 +3897,25 @@ export async function executeNaturalLanguageRoute(query, options) {
|
|
|
3894
3897
|
}
|
|
3895
3898
|
const payload = buildDomainPayload(ref.domain, ref.agent, query, correlationId);
|
|
3896
3899
|
const result = await executeAgentsInvokeCommand(ref.domain, ref.agent, payload, options);
|
|
3897
|
-
|
|
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 };
|
|
3898
3907
|
}
|
|
3899
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`);
|
|
3900
3913
|
return { kind: 'agent', domain: ref.domain, agent: ref.agent, status: 502, response: { error: err instanceof Error ? err.message : String(err) } };
|
|
3901
3914
|
}
|
|
3902
3915
|
})());
|
|
3916
|
+
});
|
|
3917
|
+
if (fleetStartedCount > 0) {
|
|
3918
|
+
process.stderr.write(` [FLEET-CALL] all ${fleetStartedCount} agents in flight — awaiting responses...\n`);
|
|
3903
3919
|
}
|
|
3904
3920
|
const allResults = await Promise.allSettled([Promise.resolve(simResult), ...agentPromises]);
|
|
3905
3921
|
const elapsed = Date.now() - start;
|
|
@@ -4189,6 +4205,7 @@ export async function executeNaturalLanguageRoute(query, options) {
|
|
|
4189
4205
|
{ domain: 'platform', agent: 'risk-score' },
|
|
4190
4206
|
];
|
|
4191
4207
|
console.error(`Dispatching ${fleetAgents.length} agents across ALL 27 domains + ruvector simulation`);
|
|
4208
|
+
pipelineHeartbeat.setActivity(`fleet: dispatching ${fleetAgents.length} agents across 27 domains`);
|
|
4192
4209
|
// ========================================================================
|
|
4193
4210
|
// ADR-016: Run ruvector simulation BEFORE fleet dispatch (sequential).
|
|
4194
4211
|
//
|
|
@@ -4201,6 +4218,7 @@ export async function executeNaturalLanguageRoute(query, options) {
|
|
|
4201
4218
|
// start the fleet. Adds ~5s latency but guarantees simulation success.
|
|
4202
4219
|
// ========================================================================
|
|
4203
4220
|
console.error(' [RUVECTOR] Running simulation before fleet dispatch (ADR-016)...');
|
|
4221
|
+
pipelineHeartbeat.setActivity('ruvector: pre-fleet simulation');
|
|
4204
4222
|
const simResult = await (async () => {
|
|
4205
4223
|
const MAX_RETRIES = 3;
|
|
4206
4224
|
let lastErr;
|
|
@@ -4247,12 +4265,24 @@ export async function executeNaturalLanguageRoute(query, options) {
|
|
|
4247
4265
|
const WAVE_SIZE = 15;
|
|
4248
4266
|
const WAVE_DELAY_MS = 2000;
|
|
4249
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;
|
|
4250
4276
|
for (let i = 0; i < fleetAgents.length; i += WAVE_SIZE) {
|
|
4251
4277
|
const wave = fleetAgents.slice(i, i + WAVE_SIZE);
|
|
4252
4278
|
const waveNum = Math.floor(i / WAVE_SIZE) + 1;
|
|
4253
4279
|
const totalWaves = Math.ceil(fleetAgents.length / WAVE_SIZE);
|
|
4254
|
-
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 ? '...' : ''})`);
|
|
4255
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`);
|
|
4256
4286
|
agentPromises.push((async () => {
|
|
4257
4287
|
try {
|
|
4258
4288
|
// Toggle repo-local per-agent: only copilot uses repo-local
|
|
@@ -4267,9 +4297,19 @@ export async function executeNaturalLanguageRoute(query, options) {
|
|
|
4267
4297
|
}
|
|
4268
4298
|
const payload = buildDomainPayload(domain, agent, query, correlationId);
|
|
4269
4299
|
const result = await executeAgentsInvokeCommand(domain, agent, payload, options);
|
|
4270
|
-
|
|
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 };
|
|
4271
4307
|
}
|
|
4272
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`);
|
|
4273
4313
|
return { kind: 'agent', domain, agent, status: 502, response: { error: err instanceof Error ? err.message : String(err) } };
|
|
4274
4314
|
}
|
|
4275
4315
|
})());
|
|
@@ -4279,6 +4319,7 @@ export async function executeNaturalLanguageRoute(query, options) {
|
|
|
4279
4319
|
await new Promise(resolve => setTimeout(resolve, WAVE_DELAY_MS));
|
|
4280
4320
|
}
|
|
4281
4321
|
}
|
|
4322
|
+
process.stderr.write(` [FLEET-CALL] all ${fleetTotal} agents in flight — awaiting final responses...\n`);
|
|
4282
4323
|
const allResults = await Promise.allSettled([Promise.resolve(simResult), ...agentPromises]);
|
|
4283
4324
|
const elapsed = Date.now() - start;
|
|
4284
4325
|
// Restore repo-local mode setting
|