@miller-tech/uap 2.16.7 → 2.19.5
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/config/capacity-policy.json +33 -0
- package/config/model-profiles/qwen38.json +32 -33
- package/dist/.tsbuildinfo +1 -1
- package/dist/bin/cli.js +57 -0
- package/dist/bin/cli.js.map +1 -1
- package/dist/capacity/policy.d.ts +32 -1
- package/dist/capacity/policy.d.ts.map +1 -1
- package/dist/capacity/policy.js +123 -4
- package/dist/capacity/policy.js.map +1 -1
- package/dist/capacity/probe.d.ts +26 -0
- package/dist/capacity/probe.d.ts.map +1 -1
- package/dist/capacity/probe.js +84 -3
- package/dist/capacity/probe.js.map +1 -1
- package/dist/cli/inference.d.ts +4 -0
- package/dist/cli/inference.d.ts.map +1 -1
- package/dist/cli/inference.js +74 -8
- package/dist/cli/inference.js.map +1 -1
- package/dist/cli/merge-gate.d.ts +59 -0
- package/dist/cli/merge-gate.d.ts.map +1 -0
- package/dist/cli/merge-gate.js +238 -0
- package/dist/cli/merge-gate.js.map +1 -0
- package/dist/cli/merge-queue.d.ts +13 -0
- package/dist/cli/merge-queue.d.ts.map +1 -1
- package/dist/cli/merge-queue.js +48 -2
- package/dist/cli/merge-queue.js.map +1 -1
- package/dist/cli/mission.d.ts +25 -0
- package/dist/cli/mission.d.ts.map +1 -0
- package/dist/cli/mission.js +225 -0
- package/dist/cli/mission.js.map +1 -0
- package/dist/cli/orch.d.ts +27 -0
- package/dist/cli/orch.d.ts.map +1 -0
- package/dist/cli/orch.js +70 -0
- package/dist/cli/orch.js.map +1 -0
- package/dist/cli/systemd-services.d.ts.map +1 -1
- package/dist/cli/systemd-services.js +44 -0
- package/dist/cli/systemd-services.js.map +1 -1
- package/dist/delivery/merge-gate.d.ts +168 -0
- package/dist/delivery/merge-gate.d.ts.map +1 -0
- package/dist/delivery/merge-gate.js +309 -0
- package/dist/delivery/merge-gate.js.map +1 -0
- package/dist/inference/analysis.d.ts +69 -3
- package/dist/inference/analysis.d.ts.map +1 -1
- package/dist/inference/analysis.js +123 -7
- package/dist/inference/analysis.js.map +1 -1
- package/dist/inference/probe.d.ts +38 -1
- package/dist/inference/probe.d.ts.map +1 -1
- package/dist/inference/probe.js +303 -30
- package/dist/inference/probe.js.map +1 -1
- package/dist/inference/strata.d.ts +95 -0
- package/dist/inference/strata.d.ts.map +1 -0
- package/dist/inference/strata.js +167 -0
- package/dist/inference/strata.js.map +1 -0
- package/dist/mission/database.d.ts +29 -0
- package/dist/mission/database.d.ts.map +1 -0
- package/dist/mission/database.js +131 -0
- package/dist/mission/database.js.map +1 -0
- package/dist/mission/ledger.d.ts +109 -0
- package/dist/mission/ledger.d.ts.map +1 -0
- package/dist/mission/ledger.js +294 -0
- package/dist/mission/ledger.js.map +1 -0
- package/dist/mission/poll-cycle.d.ts +73 -0
- package/dist/mission/poll-cycle.d.ts.map +1 -0
- package/dist/mission/poll-cycle.js +100 -0
- package/dist/mission/poll-cycle.js.map +1 -0
- package/dist/mission/poll-executor.d.ts +91 -0
- package/dist/mission/poll-executor.d.ts.map +1 -0
- package/dist/mission/poll-executor.js +328 -0
- package/dist/mission/poll-executor.js.map +1 -0
- package/dist/models/types.d.ts.map +1 -1
- package/dist/models/types.js +33 -27
- package/dist/models/types.js.map +1 -1
- package/dist/self-tuning/profiles/qwen38.d.ts +13 -14
- package/dist/self-tuning/profiles/qwen38.d.ts.map +1 -1
- package/dist/self-tuning/profiles/qwen38.js +17 -18
- package/dist/self-tuning/profiles/qwen38.js.map +1 -1
- package/dist/types/mission.d.ts +80 -0
- package/dist/types/mission.d.ts.map +1 -0
- package/dist/types/mission.js +12 -0
- package/dist/types/mission.js.map +1 -0
- package/docs/architecture/adr/0003-mission-orchestrator.md +99 -0
- package/docs/architecture/adr/0004-deterministic-merge-gate.md +127 -0
- package/docs/guides/CAPACITY_POLICY.md +49 -0
- package/docs/guides/INFERENCE_HEALTH.md +65 -8
- package/docs/guides/MISSIONS.md +170 -0
- package/docs/guides/PROXY.md +2 -0
- package/docs/reports/2026-10-02-plane-admin-fail-closed.md +70 -0
- package/docs/reports/2026-10-02-plane-admin-protect-session.md +116 -0
- package/docs/visual/merge-gate.html +404 -0
- package/docs/visual/mission-orchestrator.html +472 -0
- package/package.json +2 -2
- package/src/policies/enforcers/__pycache__/_common.cpython-312.pyc +0 -0
- package/src/policies/enforcers/__pycache__/expert_review_required.cpython-312.pyc +0 -0
- package/src/policies/enforcers/__pycache__/quality_metrics_gate.cpython-312.pyc +0 -0
- package/src/policies/enforcers/plane_admin_protect.py +133 -0
- package/src/policies/schemas/policies/plane-admin-protect.md +55 -0
- package/templates/hooks/__pycache__/deliver_autoroute.cpython-312.pyc +0 -0
- package/templates/hooks/uap-policy-gate.sh +33 -0
- package/tools/agents/scripts/__pycache__/toolcall_path_normalizer.cpython-312.pyc +0 -0
- package/tools/agents/scripts/anthropic_proxy.py +493 -40
- package/tools/agents/tests/test_anthropic_proxy_streaming.py +171 -0
- package/tools/agents/tests/test_gate_failclosed_plane_admin.py +248 -0
- package/tools/agents/tests/test_plane_admin_protect.py +124 -0
- package/tools/agents/tests/test_stream_heartbeat.py +77 -0
package/dist/capacity/policy.js
CHANGED
|
@@ -42,11 +42,74 @@ export function parsePolicy(text, source = 'policy') {
|
|
|
42
42
|
if (seen.has(svc.name))
|
|
43
43
|
throw new PolicyError(`${where}: duplicate service "${svc.name}"`);
|
|
44
44
|
seen.add(svc.name);
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
// Exactly one probe source. Both at once is ambiguous (which one is the
|
|
46
|
+
// truth?); neither is a service the doctor cannot check at all.
|
|
47
|
+
if (Boolean(svc.systemd) === Boolean(svc.http)) {
|
|
48
|
+
throw new PolicyError(`${where}: exactly one of "systemd" or "http" is required`);
|
|
47
49
|
}
|
|
48
|
-
if (svc.systemd
|
|
49
|
-
|
|
50
|
+
if (svc.systemd) {
|
|
51
|
+
if (typeof svc.systemd.unit !== 'string' || !UNIT_NAME_RE.test(svc.systemd.unit)) {
|
|
52
|
+
throw new PolicyError(`${where}: systemd.unit must match ${UNIT_NAME_RE} (no flags, whitespace, or leading dashes)`);
|
|
53
|
+
}
|
|
54
|
+
if (svc.systemd.scope !== 'user' && svc.systemd.scope !== 'system') {
|
|
55
|
+
throw new PolicyError(`${where}: systemd.scope must be "user" or "system"`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (svc.http) {
|
|
59
|
+
if (svc.http.kind !== 'strata') {
|
|
60
|
+
throw new PolicyError(`${where}: http.kind must be "strata" (the only known /metrics shape)`);
|
|
61
|
+
}
|
|
62
|
+
const url = svc.http.url;
|
|
63
|
+
let parsed;
|
|
64
|
+
try {
|
|
65
|
+
parsed = new URL(url);
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
throw new PolicyError(`${where}: http.url must be a valid URL`);
|
|
69
|
+
}
|
|
70
|
+
// The probe shells out to curl with the URL as a positional argument.
|
|
71
|
+
// Only http(s) with no userinfo/query/fragment can never smuggle flags
|
|
72
|
+
// or credentials; loopback is not REQUIRED (a remote model server is a
|
|
73
|
+
// legitimate declaration), but anything weird is rejected here.
|
|
74
|
+
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
|
|
75
|
+
throw new PolicyError(`${where}: http.url must be http(s)`);
|
|
76
|
+
}
|
|
77
|
+
if (parsed.username || parsed.password || parsed.search || parsed.hash) {
|
|
78
|
+
throw new PolicyError(`${where}: http.url must carry no userinfo, query, or fragment`);
|
|
79
|
+
}
|
|
80
|
+
if (parsed.pathname !== '/' && parsed.pathname !== '') {
|
|
81
|
+
throw new PolicyError(`${where}: http.url must be a base URL with no path`);
|
|
82
|
+
}
|
|
83
|
+
// CANONICAL, not just parseable. The WHATWG parser normalizes away
|
|
84
|
+
// what the RAW string preserves — %-encoded dot-segments (%2e%2e),
|
|
85
|
+
// literal dot-segments (/a/..), an empty query (?), leading
|
|
86
|
+
// whitespace — so a raw string can pass every field check above while
|
|
87
|
+
// curl fetches something other than the validated shape. Require the
|
|
88
|
+
// raw string to equal the parsed href modulo one trailing slash, so
|
|
89
|
+
// the form that was validated is the form that is fetched.
|
|
90
|
+
if (parsed.href !== url && parsed.href !== `${url}/`) {
|
|
91
|
+
throw new PolicyError(`${where}: http.url must be canonical — "${url}" normalizes to "${parsed.href}", ` +
|
|
92
|
+
'and the probe must fetch exactly the form that was validated');
|
|
93
|
+
}
|
|
94
|
+
// Unit-only budgets on an http service would be SILENTLY ignored by
|
|
95
|
+
// computeHealth (no MemoryCurrent, no NRestarts). A declared budget
|
|
96
|
+
// that cannot be verified is the exact anti-pattern this policy
|
|
97
|
+
// exists to prevent, so reject at parse time instead.
|
|
98
|
+
if (svc.budget?.rssMiB !== undefined || svc.restartBudget !== undefined) {
|
|
99
|
+
throw new PolicyError(`${where}: budget.rssMiB and restartBudget require a systemd unit ` +
|
|
100
|
+
'(MemoryCurrent and NRestarts do not exist for an http-probed service)');
|
|
101
|
+
}
|
|
102
|
+
const must = svc.http.metricsMustMatch;
|
|
103
|
+
if (must !== undefined) {
|
|
104
|
+
for (const [key, value] of Object.entries(must)) {
|
|
105
|
+
if (!/^[a-z0-9_]+$/i.test(key) || key.length === 0) {
|
|
106
|
+
throw new PolicyError(`${where}: http.metricsMustMatch keys must be engine field names`);
|
|
107
|
+
}
|
|
108
|
+
if (typeof value !== 'string' && typeof value !== 'number') {
|
|
109
|
+
throw new PolicyError(`${where}: http.metricsMustMatch.${key} must be a string or number`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
50
113
|
}
|
|
51
114
|
for (const [section, keys] of [
|
|
52
115
|
['budget', ['vramMiB', 'rssMiB']],
|
|
@@ -81,6 +144,14 @@ export function parsePolicy(text, source = 'policy') {
|
|
|
81
144
|
/** Pure health computation over a probed state — the deterministic core,
|
|
82
145
|
* fully testable without systemd or a GPU. */
|
|
83
146
|
export function computeHealth(svc, probed, probeAvailable) {
|
|
147
|
+
if (svc.http)
|
|
148
|
+
return computeHttpHealth(svc, probed, probeAvailable);
|
|
149
|
+
// parsePolicy guarantees exactly one source, but computeHealth is exported
|
|
150
|
+
// pure and can be handed a policy built in code — without this guard the
|
|
151
|
+
// unit references below would be lying to the type checker.
|
|
152
|
+
if (!svc.systemd) {
|
|
153
|
+
return { health: 'UNKNOWN', reasons: ['no probe source (systemd or http) declared'] };
|
|
154
|
+
}
|
|
84
155
|
const reasons = [];
|
|
85
156
|
if (!probeAvailable.systemd) {
|
|
86
157
|
return { health: 'UNKNOWN', reasons: ['systemctl unavailable — cannot probe the unit'] };
|
|
@@ -153,4 +224,52 @@ export function computeHealth(svc, probed, probeAvailable) {
|
|
|
153
224
|
reasons.push(`active (${probed.subState ?? 'running'}), all budgets inside policy`);
|
|
154
225
|
return { health: 'GREEN', reasons };
|
|
155
226
|
}
|
|
227
|
+
/**
|
|
228
|
+
* Health for an HTTP-probed service — the same declared-vs-probed doctrine
|
|
229
|
+
* with no unit to lean on: liveness is "it answers /metrics as the expected
|
|
230
|
+
* document", configuration is the metricsMustMatch comparison, and the host
|
|
231
|
+
* headroom check is shared with the systemd path.
|
|
232
|
+
*/
|
|
233
|
+
function computeHttpHealth(svc, probed, probeAvailable) {
|
|
234
|
+
if (!probeAvailable.http) {
|
|
235
|
+
return {
|
|
236
|
+
health: 'UNKNOWN',
|
|
237
|
+
reasons: [`could not reach ${svc.http.url}/metrics — probe unavailable (curl missing or timed out)`],
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
// DARK: same doctrine as the systemd path — a service that is not answering
|
|
241
|
+
// is absent, not degraded.
|
|
242
|
+
if (probed.activeState !== 'active') {
|
|
243
|
+
return {
|
|
244
|
+
health: 'DARK',
|
|
245
|
+
reasons: [`service at ${svc.http.url} is not answering /metrics as ${svc.http.kind} — not serving`],
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
const reasons = [];
|
|
249
|
+
// Configuration drift: declared engine fields vs the live document. A
|
|
250
|
+
// declared key the document lacks is UNVERIFIED (RED), not silently
|
|
251
|
+
// passing — the same rule as execStartMustContain.
|
|
252
|
+
for (const [key, expected] of Object.entries(svc.http.metricsMustMatch ?? {})) {
|
|
253
|
+
const actual = probed.metrics?.[key];
|
|
254
|
+
if (actual === undefined) {
|
|
255
|
+
reasons.push(`metricsMustMatch declared engine.${key} but /metrics did not report it — configuration unverified`);
|
|
256
|
+
}
|
|
257
|
+
else if (actual !== expected) {
|
|
258
|
+
reasons.push(`engine.${key} is ${JSON.stringify(actual)}, policy declares ${JSON.stringify(expected)} — ` +
|
|
259
|
+
'the running configuration has drifted from the policy');
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
if (svc.headroom?.gpuMinFreeMiB !== undefined) {
|
|
263
|
+
if (!probeAvailable.gpu || probed.gpuFreeMiB === undefined) {
|
|
264
|
+
reasons.push('gpu headroom declared but nvidia-smi unavailable — headroom unverified');
|
|
265
|
+
}
|
|
266
|
+
else if (probed.gpuFreeMiB < svc.headroom.gpuMinFreeMiB) {
|
|
267
|
+
reasons.push(`GPU free ${probed.gpuFreeMiB} MiB below required headroom ${svc.headroom.gpuMinFreeMiB} MiB — OOM territory`);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
if (reasons.length > 0)
|
|
271
|
+
return { health: 'RED', reasons };
|
|
272
|
+
reasons.push(`serving ${probed.detail ? `(${probed.detail}) ` : ''}at ${svc.http.url}, all budgets inside policy`);
|
|
273
|
+
return { health: 'GREEN', reasons };
|
|
274
|
+
}
|
|
156
275
|
//# sourceMappingURL=policy.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"policy.js","sourceRoot":"","sources":["../../src/capacity/policy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;
|
|
1
|
+
{"version":3,"file":"policy.js","sourceRoot":"","sources":["../../src/capacity/policy.ts"],"names":[],"mappings":"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"}
|
package/dist/capacity/probe.d.ts
CHANGED
|
@@ -11,9 +11,35 @@ export declare function loadPolicy(projectDir: string, explicitPath?: string): {
|
|
|
11
11
|
policy: CapacityPolicy;
|
|
12
12
|
path: string;
|
|
13
13
|
};
|
|
14
|
+
/** Result of an HTTP service probe: liveness plus the engine facts the
|
|
15
|
+
* metricsMustMatch drift check compares. Null = the probe could not run
|
|
16
|
+
* (curl missing, timeout) — UNKNOWN, never a guess. */
|
|
17
|
+
export interface HttpProbeState {
|
|
18
|
+
activeState: string;
|
|
19
|
+
subState: string;
|
|
20
|
+
detail?: string;
|
|
21
|
+
metrics?: Record<string, string | number>;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Probe a unit-less service over HTTP: fetch <url>/metrics with curl and
|
|
25
|
+
* parse it as the declared kind's document. curl (not node fetch) because
|
|
26
|
+
* runDoctor is synchronous and every other probe here shells out the same
|
|
27
|
+
* way — argv array, no shell, timeout, output bounded.
|
|
28
|
+
*
|
|
29
|
+
* The URL comes from the validated policy (http/https, no userinfo, base
|
|
30
|
+
* path only, and canonicalized so what was validated is what is fetched),
|
|
31
|
+
* so it can never start with a dash. NO `-f`: a 4xx/5xx body must reach the
|
|
32
|
+
* parser and classify as unrecognized (DARK — "answering but wrong") rather
|
|
33
|
+
* than turning into a probe failure (UNKNOWN — "tool missing"), which would
|
|
34
|
+
* split one situation across two verdicts.
|
|
35
|
+
*/
|
|
36
|
+
export declare function probeHttpService(url: string, kind: 'strata', deps?: {
|
|
37
|
+
exec?: (cmd: string, args: string[]) => string;
|
|
38
|
+
}): HttpProbeState | null;
|
|
14
39
|
export interface DoctorDeps {
|
|
15
40
|
probeSystemd: typeof probeSystemd;
|
|
16
41
|
probeGpuFreeMiB: typeof probeGpuFreeMiB;
|
|
42
|
+
probeHttp?: typeof probeHttpService;
|
|
17
43
|
}
|
|
18
44
|
/** Probe every declared service and compute its health. Deps are injectable
|
|
19
45
|
* so the matrix is testable without a host. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"probe.d.ts","sourceRoot":"","sources":["../../src/capacity/probe.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"probe.d.ts","sourceRoot":"","sources":["../../src/capacity/probe.ts"],"names":[],"mappings":"AAUA,OAAO,EAGL,KAAK,cAAc,EACnB,KAAK,MAAM,EACX,KAAK,aAAa,EACnB,MAAM,aAAa,CAAC;AAGrB,MAAM,MAAM,UAAU,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;AAIjD;;2DAE2D;AAC3D,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,QAAQ,GAAG,UAAU,GAAG,IAAI,CAkCtF;AAED,sEAAsE;AACtE,wBAAgB,eAAe,IAAI,MAAM,GAAG,IAAI,CAa/C;AAED,2EAA2E;AAC3E,wBAAgB,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG;IAAE,MAAM,EAAE,cAAc,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAgB9G;AAED;;uDAEuD;AACvD,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC;CAC3C;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,QAAQ,EACd,IAAI,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,MAAM,CAAA;CAAE,GACxD,cAAc,GAAG,IAAI,CAuCvB;AAUD,MAAM,WAAW,UAAU;IACzB,YAAY,EAAE,OAAO,YAAY,CAAC;IAClC,eAAe,EAAE,OAAO,eAAe,CAAC;IACxC,SAAS,CAAC,EAAE,OAAO,gBAAgB,CAAC;CACrC;AAED;+CAC+C;AAC/C,wBAAgB,SAAS,CACvB,MAAM,EAAE,cAAc,EACtB,IAAI,GAAE,UAA2E,GAChF,aAAa,EAAE,CA0BjB;AAED,wEAAwE;AACxE,wBAAgB,WAAW,CAAC,OAAO,EAAE,aAAa,EAAE,GAAG,MAAM,CAK5D"}
|
package/dist/capacity/probe.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Host probes for the capacity doctor: systemd unit state
|
|
2
|
+
* Host probes for the capacity doctor: systemd unit state, HTTP liveness for
|
|
3
|
+
* unit-less services, and GPU headroom.
|
|
3
4
|
* execFileSync with argument arrays only (no shell); every probe fails soft
|
|
4
5
|
* to an unavailable flag — the health computation decides what that means.
|
|
5
6
|
*/
|
|
@@ -8,6 +9,7 @@ import { existsSync, readFileSync } from 'fs';
|
|
|
8
9
|
import { join } from 'path';
|
|
9
10
|
import { homedir } from 'os';
|
|
10
11
|
import { parsePolicy, computeHealth, } from './policy.js';
|
|
12
|
+
import { sanitizeServerText } from '../inference/probe.js';
|
|
11
13
|
const PROBE_TIMEOUT_MS = 5000; // a wedged driver/D-Bus must fail soft, not hang
|
|
12
14
|
/** systemctl show <unit> for the declared scope. Undefined fields when the
|
|
13
15
|
* unit or systemctl is missing. `--` terminates option parsing so even a
|
|
@@ -70,13 +72,92 @@ export function loadPolicy(projectDir, explicitPath) {
|
|
|
70
72
|
throw new Error(`no capacity policy found (looked: ${candidates.join(', ')}) — ` +
|
|
71
73
|
'declare one at config/capacity-policy.json; see docs/guides/CAPACITY_POLICY.md');
|
|
72
74
|
}
|
|
75
|
+
/**
|
|
76
|
+
* Probe a unit-less service over HTTP: fetch <url>/metrics with curl and
|
|
77
|
+
* parse it as the declared kind's document. curl (not node fetch) because
|
|
78
|
+
* runDoctor is synchronous and every other probe here shells out the same
|
|
79
|
+
* way — argv array, no shell, timeout, output bounded.
|
|
80
|
+
*
|
|
81
|
+
* The URL comes from the validated policy (http/https, no userinfo, base
|
|
82
|
+
* path only, and canonicalized so what was validated is what is fetched),
|
|
83
|
+
* so it can never start with a dash. NO `-f`: a 4xx/5xx body must reach the
|
|
84
|
+
* parser and classify as unrecognized (DARK — "answering but wrong") rather
|
|
85
|
+
* than turning into a probe failure (UNKNOWN — "tool missing"), which would
|
|
86
|
+
* split one situation across two verdicts.
|
|
87
|
+
*/
|
|
88
|
+
export function probeHttpService(url, kind, deps) {
|
|
89
|
+
const exec = deps?.exec ?? ((cmd, args) => execFileSync(cmd, args, {
|
|
90
|
+
encoding: 'utf-8',
|
|
91
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
92
|
+
timeout: PROBE_TIMEOUT_MS,
|
|
93
|
+
maxBuffer: 8 * 1024 * 1024,
|
|
94
|
+
}));
|
|
95
|
+
let body;
|
|
96
|
+
try {
|
|
97
|
+
body = exec('curl', [
|
|
98
|
+
'-sS',
|
|
99
|
+
'--max-time',
|
|
100
|
+
`${PROBE_TIMEOUT_MS / 1000}`,
|
|
101
|
+
'--max-filesize',
|
|
102
|
+
'8388608',
|
|
103
|
+
`${url.replace(/\/$/, '')}/metrics`,
|
|
104
|
+
]);
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
if (kind !== 'strata')
|
|
110
|
+
return null; // the only /metrics shape we can parse
|
|
111
|
+
try {
|
|
112
|
+
const doc = JSON.parse(body);
|
|
113
|
+
const engine = doc?.engine;
|
|
114
|
+
if (typeof engine !== 'object' || engine === null)
|
|
115
|
+
return unrecognized();
|
|
116
|
+
const metrics = {};
|
|
117
|
+
for (const [k, v] of Object.entries(engine)) {
|
|
118
|
+
if (typeof v === 'string' || typeof v === 'number')
|
|
119
|
+
metrics[k] = v;
|
|
120
|
+
}
|
|
121
|
+
const model = typeof engine.model === 'string' ? engine.model : undefined;
|
|
122
|
+
if (model === undefined)
|
|
123
|
+
return unrecognized();
|
|
124
|
+
// The model string is SERVER-PROVIDED and reaches the terminal via the
|
|
125
|
+
// doctor's GREEN reason — strip ANSI/C0 before it ever leaves the probe
|
|
126
|
+
// (CWE-117; shared helper with the inference health path).
|
|
127
|
+
return { activeState: 'active', subState: 'serving', detail: sanitizeServerText(model), metrics };
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
return unrecognized();
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/** curl got a body but it is not the expected document: the service is
|
|
134
|
+
* ANSWERING, which is absent-shaped (DARK), not probe-unavailable (UNKNOWN).
|
|
135
|
+
* A wrong engine behind the port is exactly the misroute this exists to
|
|
136
|
+
* catch. */
|
|
137
|
+
function unrecognized() {
|
|
138
|
+
return { activeState: 'unrecognized', subState: 'answered, but not the declared document' };
|
|
139
|
+
}
|
|
73
140
|
/** Probe every declared service and compute its health. Deps are injectable
|
|
74
141
|
* so the matrix is testable without a host. */
|
|
75
|
-
export function runDoctor(policy, deps = { probeSystemd, probeGpuFreeMiB }) {
|
|
142
|
+
export function runDoctor(policy, deps = { probeSystemd, probeGpuFreeMiB, probeHttp: probeHttpService }) {
|
|
76
143
|
// One GPU probe per run, shared across services (nvidia-smi is not cheap).
|
|
77
144
|
const gpuFree = deps.probeGpuFreeMiB();
|
|
145
|
+
const probeHttp = deps.probeHttp ?? probeHttpService;
|
|
78
146
|
return policy.services.map((svc) => {
|
|
79
|
-
|
|
147
|
+
if (svc.http) {
|
|
148
|
+
const http = probeHttp(svc.http.url, svc.http.kind);
|
|
149
|
+
const probed = {
|
|
150
|
+
...(http ?? {}),
|
|
151
|
+
gpuFreeMiB: gpuFree ?? undefined,
|
|
152
|
+
};
|
|
153
|
+
const { health, reasons } = computeHealth(svc, probed, {
|
|
154
|
+
systemd: false,
|
|
155
|
+
gpu: gpuFree !== null,
|
|
156
|
+
http: http !== null,
|
|
157
|
+
});
|
|
158
|
+
return { name: svc.name, health, reasons, probed };
|
|
159
|
+
}
|
|
160
|
+
const sys = svc.systemd ? deps.probeSystemd(svc.systemd.unit, svc.systemd.scope) : null;
|
|
80
161
|
const probed = { ...(sys ?? {}), gpuFreeMiB: gpuFree ?? undefined };
|
|
81
162
|
const { health, reasons } = computeHealth(svc, probed, {
|
|
82
163
|
systemd: sys !== null,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"probe.js","sourceRoot":"","sources":["../../src/capacity/probe.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"probe.js","sourceRoot":"","sources":["../../src/capacity/probe.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAC9C,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EACL,WAAW,EACX,aAAa,GAId,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAI3D,MAAM,gBAAgB,GAAG,IAAI,CAAC,CAAC,iDAAiD;AAEhF;;2DAE2D;AAC3D,MAAM,UAAU,YAAY,CAAC,IAAY,EAAE,KAAwB;IACjE,yEAAyE;IACzE,6EAA6E;IAC7E,MAAM,IAAI,GAAG,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IAC9D,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CACtB,WAAW,EACX,CAAC,GAAG,IAAI,EAAE,IAAI,EAAE,gEAAgE,EAAE,IAAI,EAAE,IAAI,CAAC,EAC7F,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,gBAAgB,EAAE,CAClF,CAAC;QACF,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,CAC9B,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YACxC,MAAM,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YAC1B,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;QAC3C,CAAC,CAAC,CACH,CAAC;QACF,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QACzC,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAClC,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,2BAA2B;QACpE,OAAO;YACL,WAAW,EAAE,KAAK,CAAC,WAAW,IAAI,SAAS;YAC3C,QAAQ,EAAE,KAAK,CAAC,QAAQ,IAAI,SAAS;YACrC,SAAS,EAAE,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS;YAC9E,OAAO,EAAE,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS;YAC1D,gBAAgB,EAAE,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS;YACzF,sEAAsE;YACtE,qEAAqE;YACrE,uEAAuE;YACvE,+DAA+D;YAC/D,SAAS,EAAE,KAAK,CAAC,SAAS,IAAI,SAAS;SACxC,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC,CAAC,iEAAiE;IAChF,CAAC;AACH,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,eAAe;IAC7B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CACtB,YAAY,EACZ,CAAC,yBAAyB,EAAE,+BAA+B,CAAC,EAC5D,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,gBAAgB,EAAE,CAClF,CAAC;QACF,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;QACzC,MAAM,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;QACxB,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,UAAU,CAAC,UAAkB,EAAE,YAAqB;IAClE,MAAM,UAAU,GAAG,YAAY;QAC7B,CAAC,CAAC,CAAC,YAAY,CAAC;QAChB,CAAC,CAAC;YACE,IAAI,CAAC,UAAU,EAAE,QAAQ,EAAE,sBAAsB,CAAC;YAClD,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,sBAAsB,CAAC;SAC1D,CAAC;IACN,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;QAC9B,IAAI,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YACrB,OAAO,EAAE,MAAM,EAAE,WAAW,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC;QAC1E,CAAC;IACH,CAAC;IACD,MAAM,IAAI,KAAK,CACb,qCAAqC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM;QAC9D,gFAAgF,CACnF,CAAC;AACJ,CAAC;AAYD;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,gBAAgB,CAC9B,GAAW,EACX,IAAc,EACd,IAAyD;IAEzD,MAAM,IAAI,GAAG,IAAI,EAAE,IAAI,IAAI,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CACxC,YAAY,CAAC,GAAG,EAAE,IAAI,EAAE;QACtB,QAAQ,EAAE,OAAO;QACjB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;QAC/B,OAAO,EAAE,gBAAgB;QACzB,SAAS,EAAE,CAAC,GAAG,IAAI,GAAG,IAAI;KAC3B,CAAC,CAAC,CAAC;IACN,IAAI,IAAY,CAAC;IACjB,IAAI,CAAC;QACH,IAAI,GAAG,IAAI,CAAC,MAAM,EAAE;YAClB,KAAK;YACL,YAAY;YACZ,GAAG,gBAAgB,GAAG,IAAI,EAAE;YAC5B,gBAAgB;YAChB,SAAS;YACT,GAAG,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,UAAU;SACpC,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,IAAI,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC,CAAC,uCAAuC;IAC3E,IAAI,CAAC;QACH,MAAM,GAAG,GAAY,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACtC,MAAM,MAAM,GAAI,GAAmD,EAAE,MAAM,CAAC;QAC5E,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI;YAAE,OAAO,YAAY,EAAE,CAAC;QACzE,MAAM,OAAO,GAAoC,EAAE,CAAC;QACpD,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAC5C,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,OAAO,CAAC,KAAK,QAAQ;gBAAE,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACrE,CAAC;QACD,MAAM,KAAK,GAAG,OAAO,MAAM,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;QAC1E,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO,YAAY,EAAE,CAAC;QAC/C,uEAAuE;QACvE,wEAAwE;QACxE,2DAA2D;QAC3D,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,kBAAkB,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC;IACpG,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,YAAY,EAAE,CAAC;IACxB,CAAC;AACH,CAAC;AAED;;;YAGY;AACZ,SAAS,YAAY;IACnB,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,QAAQ,EAAE,yCAAyC,EAAE,CAAC;AAC9F,CAAC;AAQD;+CAC+C;AAC/C,MAAM,UAAU,SAAS,CACvB,MAAsB,EACtB,OAAmB,EAAE,YAAY,EAAE,eAAe,EAAE,SAAS,EAAE,gBAAgB,EAAE;IAEjF,2EAA2E;IAC3E,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;IACvC,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,gBAAgB,CAAC;IACrD,OAAO,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;QACjC,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC;YACb,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACpD,MAAM,MAAM,GAAe;gBACzB,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC;gBACf,UAAU,EAAE,OAAO,IAAI,SAAS;aACjC,CAAC;YACF,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE;gBACrD,OAAO,EAAE,KAAK;gBACd,GAAG,EAAE,OAAO,KAAK,IAAI;gBACrB,IAAI,EAAE,IAAI,KAAK,IAAI;aACpB,CAAC,CAAC;YACH,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;QACrD,CAAC;QACD,MAAM,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QACxF,MAAM,MAAM,GAAe,EAAE,GAAG,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,UAAU,EAAE,OAAO,IAAI,SAAS,EAAE,CAAC;QAChF,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE;YACrD,OAAO,EAAE,GAAG,KAAK,IAAI;YACrB,GAAG,EAAE,OAAO,KAAK,IAAI;SACtB,CAAC,CAAC;QACH,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IACrD,CAAC,CAAC,CAAC;AACL,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,WAAW,CAAC,OAAwB;IAClD,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC;QAAE,OAAO,MAAM,CAAC;IAC5D,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC1D,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC;QAAE,OAAO,SAAS,CAAC;IAClE,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
package/dist/cli/inference.d.ts
CHANGED
|
@@ -8,6 +8,10 @@ export interface InferenceOptions {
|
|
|
8
8
|
until?: string;
|
|
9
9
|
json?: boolean;
|
|
10
10
|
strict?: boolean;
|
|
11
|
+
/** Force a backend instead of auto-detecting from /metrics. */
|
|
12
|
+
backend?: 'auto' | 'llamacpp' | 'strata';
|
|
13
|
+
/** Strata serve log path (default: $UAP_STRATA_LOG, if set). */
|
|
14
|
+
strataLogPath?: string;
|
|
11
15
|
}
|
|
12
16
|
export declare function inferenceHealthCommand(options?: InferenceOptions, deps?: ProbeDeps, thresholds?: Thresholds): Promise<void>;
|
|
13
17
|
//# sourceMappingURL=inference.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inference.d.ts","sourceRoot":"","sources":["../../src/cli/inference.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"inference.d.ts","sourceRoot":"","sources":["../../src/cli/inference.ts"],"names":[],"mappings":"AAmBA,OAAO,EAIL,KAAK,UAAU,EAChB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAsB,KAAK,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAG3E,MAAM,WAAW,gBAAgB;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,+DAA+D;IAC/D,OAAO,CAAC,EAAE,MAAM,GAAG,UAAU,GAAG,QAAQ,CAAC;IACzC,gEAAgE;IAChE,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAsBD,wBAAsB,sBAAsB,CAC1C,OAAO,GAAE,gBAAqB,EAC9B,IAAI,CAAC,EAAE,SAAS,EAChB,UAAU,GAAE,UAA+B,GAC1C,OAAO,CAAC,IAAI,CAAC,CAsMf"}
|
package/dist/cli/inference.js
CHANGED
|
@@ -10,10 +10,16 @@
|
|
|
10
10
|
* throughput decaying over a long-lived process, context checkpoints too few
|
|
11
11
|
* to track a growing conversation, and a KV cache quietly pinned at its
|
|
12
12
|
* lowest quality tier.
|
|
13
|
+
*
|
|
14
|
+
* Two backends, auto-detected via /metrics: llama.cpp servers (Prometheus
|
|
15
|
+
* text) and the Strata serve layer (JSON; the local Qwen3.8 backend since
|
|
16
|
+
* 2026-10-04). The strata path reads its serve log for a process-lifetime
|
|
17
|
+
* decode/prefill trend — pass --strata-log or set $UAP_STRATA_LOG.
|
|
13
18
|
*/
|
|
14
19
|
import chalk from 'chalk';
|
|
15
20
|
import { DEFAULT_THRESHOLDS, assessInference, } from '../inference/analysis.js';
|
|
16
|
-
import { collect } from '../inference/probe.js';
|
|
21
|
+
import { collect, redactUrl } from '../inference/probe.js';
|
|
22
|
+
import { draftAcceptanceRate } from '../inference/strata.js';
|
|
17
23
|
const COLORS = {
|
|
18
24
|
GREEN: chalk.green,
|
|
19
25
|
WARN: chalk.yellow,
|
|
@@ -36,13 +42,25 @@ export async function inferenceHealthCommand(options = {}, deps, thresholds = DE
|
|
|
36
42
|
const serverUnit = options.serverUnit ?? DEFAULTS.serverUnit;
|
|
37
43
|
const proxyUnit = options.proxyUnit ?? DEFAULTS.proxyUnit;
|
|
38
44
|
const baseUrl = options.url ?? DEFAULTS.url;
|
|
39
|
-
const
|
|
45
|
+
const strataLogPath = options.strataLogPath ?? process.env.UAP_STRATA_LOG;
|
|
46
|
+
const { snapshot, unit, slots, metrics, strata, backend, unavailable } = await collect({
|
|
47
|
+
serverUnit,
|
|
48
|
+
proxyUnit,
|
|
49
|
+
baseUrl,
|
|
50
|
+
since: options.since,
|
|
51
|
+
until: options.until,
|
|
52
|
+
backend: options.backend,
|
|
53
|
+
strataLogPath,
|
|
54
|
+
}, deps);
|
|
40
55
|
const report = assessInference(snapshot, thresholds);
|
|
41
56
|
if (options.json) {
|
|
42
|
-
// reportVersion pins the shape before monitors start parsing it.
|
|
57
|
+
// reportVersion pins the shape before monitors start parsing it. v2 adds
|
|
58
|
+
// the strata fields (backend, engineModel, decodeTrend, reuse, drafts,
|
|
59
|
+
// vramFreeMiB) — all additive; a v1 monitor keeps parsing.
|
|
43
60
|
console.log(JSON.stringify({
|
|
44
|
-
reportVersion:
|
|
61
|
+
reportVersion: 2,
|
|
45
62
|
health: report.health,
|
|
63
|
+
backend,
|
|
46
64
|
unit: { name: serverUnit, active: unit?.active, uptimeSeconds: unit?.uptimeSeconds },
|
|
47
65
|
snapshot: {
|
|
48
66
|
rails: snapshot.rails,
|
|
@@ -53,9 +71,19 @@ export async function inferenceHealthCommand(options = {}, deps, thresholds = DE
|
|
|
53
71
|
generationTimeouts: snapshot.generationTimeouts,
|
|
54
72
|
prefillSamples: snapshot.prefill.length,
|
|
55
73
|
checkpointSamples: snapshot.checkpoints.length,
|
|
74
|
+
decodeSamples: snapshot.decode?.length,
|
|
75
|
+
engineModel: snapshot.engineModel,
|
|
76
|
+
vramFreeMiB: snapshot.vramFreeMiB,
|
|
56
77
|
},
|
|
57
78
|
trend: report.trend,
|
|
79
|
+
decodeTrend: report.decodeTrend,
|
|
58
80
|
checkpoints: report.checkpoints,
|
|
81
|
+
reuse: report.reuse,
|
|
82
|
+
drafts: strata
|
|
83
|
+
? {
|
|
84
|
+
acceptanceRate: draftAcceptanceRate(strata.samples.drafts),
|
|
85
|
+
}
|
|
86
|
+
: undefined,
|
|
59
87
|
findings: report.findings,
|
|
60
88
|
metrics,
|
|
61
89
|
unavailable,
|
|
@@ -63,25 +91,36 @@ export async function inferenceHealthCommand(options = {}, deps, thresholds = DE
|
|
|
63
91
|
}
|
|
64
92
|
else {
|
|
65
93
|
const historical = Boolean(options.until);
|
|
66
|
-
|
|
94
|
+
// engineModel is already sanitized at the probe boundary; the URL gets
|
|
95
|
+
// redactUrl here because --url is operator-supplied and may carry
|
|
96
|
+
// credentials (it would be echoed straight into a piped report).
|
|
97
|
+
const headline = backend === 'strata'
|
|
98
|
+
? `inference health: strata ${snapshot.engineModel ?? '(model unknown)'} @ ${redactUrl(baseUrl)}`
|
|
99
|
+
: `inference health: ${serverUnit}`;
|
|
100
|
+
console.log(chalk.bold(headline));
|
|
67
101
|
if (historical) {
|
|
68
102
|
// The journal window is in the past but /slots, uptime and the unit's
|
|
69
103
|
// flags are read NOW. Printing them together would describe the wrong
|
|
70
104
|
// process — during an incident review that is worse than silence.
|
|
71
|
-
console.log(chalk.yellow(`REPLAY
|
|
105
|
+
console.log(chalk.yellow(`REPLAY window ${options.since ?? '(default)'} .. ${options.until} — ` +
|
|
72
106
|
'live readings below are omitted; they describe the CURRENT process, not the window'));
|
|
73
107
|
console.log(`${COLORS[report.health](report.health.padEnd(7))} findings for that window`);
|
|
74
108
|
}
|
|
109
|
+
else if (backend === 'strata') {
|
|
110
|
+
console.log(`${COLORS[report.health](report.health.padEnd(7))} strata serve layer on :8080` +
|
|
111
|
+
(slots?.slots ? `, ${slots.slots} rail(s)` : '') +
|
|
112
|
+
(strata?.live.state ? `, live state: ${strata.live.state}` : ''));
|
|
113
|
+
}
|
|
75
114
|
else {
|
|
76
115
|
console.log(`${COLORS[report.health](report.health.padEnd(7))} ` +
|
|
77
116
|
`${unit?.active ?? 'unknown'}, up ${fmtDuration(unit?.uptimeSeconds)}` +
|
|
78
117
|
(slots?.slots ? `, ${slots.slots} rail(s)` : ''));
|
|
79
118
|
}
|
|
80
119
|
if (!historical && snapshot.poolCells !== undefined) {
|
|
81
|
-
const per = snapshot.rails && snapshot.rails >
|
|
120
|
+
const per = snapshot.rails && snapshot.rails > 1
|
|
82
121
|
? ` (${Math.floor(snapshot.poolCells / snapshot.rails).toLocaleString()}/rail if split)`
|
|
83
122
|
: '';
|
|
84
|
-
console.log(chalk.dim(` pool ${snapshot.poolCells.toLocaleString()} cells
|
|
123
|
+
console.log(chalk.dim(` pool ${snapshot.poolCells.toLocaleString()} cells${per}`));
|
|
85
124
|
}
|
|
86
125
|
if (!historical && snapshot.ctxCheckpoints !== undefined) {
|
|
87
126
|
console.log(chalk.dim(` checkpoints ${snapshot.ctxCheckpoints} per slot`));
|
|
@@ -90,6 +129,9 @@ export async function inferenceHealthCommand(options = {}, deps, thresholds = DE
|
|
|
90
129
|
const floor = snapshot.kvFloorBitsPerValue;
|
|
91
130
|
console.log(chalk.dim(` kv ${snapshot.kvBitsPerValue} bpv${floor !== undefined ? ` (floor ${floor})` : ''}`));
|
|
92
131
|
}
|
|
132
|
+
if (!historical && snapshot.vramFreeMiB !== undefined) {
|
|
133
|
+
console.log(chalk.dim(` vram ${snapshot.vramFreeMiB} MiB free (reserve-aware)`));
|
|
134
|
+
}
|
|
93
135
|
const t = report.trend;
|
|
94
136
|
if (t.ratio !== undefined) {
|
|
95
137
|
const arrow = t.ratio < 1 ? '↓' : '↑';
|
|
@@ -99,10 +141,34 @@ export async function inferenceHealthCommand(options = {}, deps, thresholds = DE
|
|
|
99
141
|
else if (t.note) {
|
|
100
142
|
console.log(chalk.dim(` prefill ${t.note}`));
|
|
101
143
|
}
|
|
144
|
+
const d = report.decodeTrend;
|
|
145
|
+
if (d !== undefined) {
|
|
146
|
+
if (d.ratio !== undefined) {
|
|
147
|
+
const arrow = d.ratio < 1 ? '↓' : '↑';
|
|
148
|
+
console.log(chalk.dim(` decode ${Math.round(d.earlyMean)} → ${Math.round(d.recentMean)} tok/s ${arrow} ` +
|
|
149
|
+
`in the ${d.bucket}-depth bucket (n=${d.earlyCount}/${d.recentCount})`));
|
|
150
|
+
}
|
|
151
|
+
else if (d.note) {
|
|
152
|
+
console.log(chalk.dim(` decode ${d.note}`));
|
|
153
|
+
}
|
|
154
|
+
}
|
|
102
155
|
if (report.checkpoints.recovery !== undefined) {
|
|
103
156
|
console.log(chalk.dim(` reuse ${Math.round(report.checkpoints.recovery * 100)}% of the reusable prefix restored ` +
|
|
104
157
|
`(~${Math.round(report.checkpoints.wastedTokens).toLocaleString()} tok/turn re-prefilled)`));
|
|
105
158
|
}
|
|
159
|
+
else if (report.reuse !== undefined && report.reuse.samples > 0 && report.reuse.fraction !== undefined) {
|
|
160
|
+
// Tail-based, same semantics as the cache-miss finding: the question is
|
|
161
|
+
// whether the cache is tracking the CURRENT conversation, not the mean
|
|
162
|
+
// over every cold start since the process began.
|
|
163
|
+
console.log(chalk.dim(` reuse ${Math.round(report.reuse.fraction * 100)}% of prompts served from cache ` +
|
|
164
|
+
`(~${Math.round(report.reuse.wastedTokens ?? 0).toLocaleString()} tok/turn re-read, last ${report.reuse.samples} turn(s))`));
|
|
165
|
+
}
|
|
166
|
+
if (strata) {
|
|
167
|
+
const acc = draftAcceptanceRate(strata.samples.drafts);
|
|
168
|
+
if (acc !== undefined) {
|
|
169
|
+
console.log(chalk.dim(` drafts ${Math.round(acc * 100)}% accepted (speculative decode)`));
|
|
170
|
+
}
|
|
171
|
+
}
|
|
106
172
|
if (!historical && metrics?.busySlotsPerDecode !== undefined) {
|
|
107
173
|
console.log(chalk.dim(` concurrency ${metrics.busySlotsPerDecode.toFixed(3)} busy slots/decode ` +
|
|
108
174
|
`(>1 means the extra rail is actually being used)`));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inference.js","sourceRoot":"","sources":["../../src/cli/inference.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"inference.js","sourceRoot":"","sources":["../../src/cli/inference.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { type ChangedFile, type GateEvidenceCheck, type MergeGateResult } from '../delivery/merge-gate.js';
|
|
2
|
+
export interface MergeGateOptions {
|
|
3
|
+
projectRoot?: string;
|
|
4
|
+
/** Base ref the diff is taken against (default: origin/master, else master). */
|
|
5
|
+
base?: string;
|
|
6
|
+
json?: boolean;
|
|
7
|
+
/** Acknowledge deliberate gate-infrastructure changes (see axiom-honesty). */
|
|
8
|
+
allowGateInfra?: boolean;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Refs flow into one git argv token (`<base>...HEAD`), so a ref beginning
|
|
12
|
+
* with `--` would be parsed as a git option and silently distort the diff the
|
|
13
|
+
* gate evaluates (security review P3). Only plain ref characters pass.
|
|
14
|
+
*/
|
|
15
|
+
export declare function validateBaseRef(base: string): string | null;
|
|
16
|
+
/** The default diff base: origin/master when the remote ref is resolvable
|
|
17
|
+
* (fresher than a stale local master), else master. */
|
|
18
|
+
export declare function resolveDefaultBase(cwd: string): string;
|
|
19
|
+
/** Gather the diff being landed: added lines per changed file. */
|
|
20
|
+
export declare function diffAgainstBase(cwd: string, base: string): string;
|
|
21
|
+
/**
|
|
22
|
+
* Tier-1 evidence read: the gate-evidence artifact deliver records on
|
|
23
|
+
* success, bound to the candidate sha it proved. Malformed artifacts or
|
|
24
|
+
* zero-gate artifacts prove nothing and fail closed (gatesAllZero=false).
|
|
25
|
+
*/
|
|
26
|
+
export declare function readEvidenceArtifact(projectRoot: string, expectedSha: string): GateEvidenceCheck;
|
|
27
|
+
/** HEAD sha of the tree being landed (the standalone gate's candidate). */
|
|
28
|
+
export declare function headSha(cwd: string): string;
|
|
29
|
+
/**
|
|
30
|
+
* Fresh-evidence gathering shared by the standalone CLI and the merge queue.
|
|
31
|
+
* Fails fast when no mission ledger exists (a queue run in a repo that never
|
|
32
|
+
* used missions must not manufacture an empty ledger as a side effect).
|
|
33
|
+
*/
|
|
34
|
+
export declare function gatherGateEvidence(projectRoot: string, missionId: number, changedFiles: ChangedFile[], markerHash8: string | undefined, allowGateInfra?: boolean, expectedSha?: string): {
|
|
35
|
+
result: MergeGateResult;
|
|
36
|
+
} | {
|
|
37
|
+
error: string;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Run the gate for a PR before the queue lands it. The diff arrives as a LAZY
|
|
41
|
+
* thunk so marker-less PRs (the common case) cost zero extra `gh` calls, and
|
|
42
|
+
* a transport failure maps to `gate: 'error'` — the queue skips that PR and
|
|
43
|
+
* continues the batch instead of crashing (code review P2).
|
|
44
|
+
*
|
|
45
|
+
* `expectedSha` is the PR head SHA the evidence artifact must be bound to.
|
|
46
|
+
*/
|
|
47
|
+
export declare function gatePr(projectRoot: string, prTitleBody: string, fetchDiff: () => string, gateInfraAcknowledged: boolean, expectedSha?: string): {
|
|
48
|
+
gate: 'none';
|
|
49
|
+
} | {
|
|
50
|
+
gate: 'pass';
|
|
51
|
+
} | {
|
|
52
|
+
gate: 'fail';
|
|
53
|
+
reasons: string[];
|
|
54
|
+
} | {
|
|
55
|
+
gate: 'error';
|
|
56
|
+
reason: string;
|
|
57
|
+
};
|
|
58
|
+
export declare function mergeGateCommand(missionIdArg: string, options?: MergeGateOptions): void;
|
|
59
|
+
//# sourceMappingURL=merge-gate.d.ts.map
|