instar 1.3.780 → 1.3.782
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/dashboard/index.html +161 -0
- package/dist/core/IntelligenceRouter.d.ts +9 -14
- package/dist/core/IntelligenceRouter.d.ts.map +1 -1
- package/dist/core/IntelligenceRouter.js +117 -56
- package/dist/core/IntelligenceRouter.js.map +1 -1
- package/dist/core/PostUpdateMigrator.d.ts +21 -0
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +59 -0
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/core/routingPriceAuthority.d.ts +0 -0
- package/dist/core/routingPriceAuthority.d.ts.map +1 -0
- package/dist/core/routingPriceAuthority.js +0 -0
- package/dist/core/routingPriceAuthority.js.map +1 -0
- package/dist/core/routingSpendView.d.ts +172 -0
- package/dist/core/routingSpendView.d.ts.map +1 -0
- package/dist/core/routingSpendView.js +215 -0
- package/dist/core/routingSpendView.js.map +1 -0
- package/dist/core/types.d.ts +25 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/monitoring/FeatureMetricsLedger.d.ts +74 -2
- package/dist/monitoring/FeatureMetricsLedger.d.ts.map +1 -1
- package/dist/monitoring/FeatureMetricsLedger.js +233 -8
- package/dist/monitoring/FeatureMetricsLedger.js.map +1 -1
- package/dist/scaffold/templates.d.ts.map +1 -1
- package/dist/scaffold/templates.js +2 -1
- package/dist/scaffold/templates.js.map +1 -1
- package/dist/server/AgentServer.d.ts +1 -0
- package/dist/server/AgentServer.d.ts.map +1 -1
- package/dist/server/AgentServer.js +35 -2
- package/dist/server/AgentServer.js.map +1 -1
- package/dist/server/CapabilityIndex.d.ts.map +1 -1
- package/dist/server/CapabilityIndex.js +12 -0
- package/dist/server/CapabilityIndex.js.map +1 -1
- package/dist/server/routes.d.ts +3 -0
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +46 -0
- package/dist/server/routes.js.map +1 -1
- package/package.json +1 -1
- package/scripts/routing-price-refresh.mjs +216 -0
- package/scripts/routing-prices.manifest.json +64 -0
- package/src/data/builtin-manifest.json +64 -64
- package/src/scaffold/templates/jobs/instar/routing-price-refresh.md +30 -0
- package/src/scaffold/templates.ts +2 -1
- package/upgrades/1.3.781.md +25 -0
- package/upgrades/1.3.782.md +60 -0
- package/upgrades/nature-routing-a2.2-enforcing.eli16.md +50 -0
- package/upgrades/side-effects/nature-routing-a2.2-enforcing.md +142 -0
- package/upgrades/side-effects/routing-spend-increment-a.md +84 -0
package/dashboard/index.html
CHANGED
|
@@ -2752,6 +2752,7 @@
|
|
|
2752
2752
|
<button class="tab" data-tab="resources" onclick="switchTab('resources')">Resource Usage</button>
|
|
2753
2753
|
<button class="tab" data-tab="llm-activity" onclick="switchTab('llm-activity')">LLM Activity</button>
|
|
2754
2754
|
<button class="tab" data-tab="routing-map" onclick="switchTab('routing-map')">Routing Map</button>
|
|
2755
|
+
<button class="tab" data-tab="spend" onclick="switchTab('spend')">Spend</button>
|
|
2755
2756
|
<button class="tab" data-tab="threadline" onclick="switchTab('threadline')">Threadline</button>
|
|
2756
2757
|
<button class="tab" data-tab="evidence" onclick="switchTab('evidence')">Evidence</button>
|
|
2757
2758
|
<button class="tab" data-tab="process-health" onclick="switchTab('process-health')">Process Health</button>
|
|
@@ -3373,6 +3374,56 @@
|
|
|
3373
3374
|
</div>
|
|
3374
3375
|
</div>
|
|
3375
3376
|
|
|
3377
|
+
<!-- Spend tab — the read-only Routing Control Room spend/caps view (Increment A,
|
|
3378
|
+
docs/specs/routing-control-room-spend-alerts.md). Immutable token usage priced ON
|
|
3379
|
+
READ + every metered paid-door key with its caps and honest not-live/$0 state.
|
|
3380
|
+
Read-only: data from /routing-spend/summary + /routing-spend/caps. No money controls
|
|
3381
|
+
(caps adjust, go-live, alerts are later, dark increments). -->
|
|
3382
|
+
<div id="spendPanel" style="display:none;flex-direction:column;padding:20px;gap:16px;overflow-y:auto">
|
|
3383
|
+
<div style="display:flex;justify-content:space-between;align-items:center;gap:12px;flex-wrap:wrap">
|
|
3384
|
+
<h2 style="margin:0">Spend</h2>
|
|
3385
|
+
<div style="display:flex;gap:8px;align-items:center">
|
|
3386
|
+
<select id="spendGrain" onchange="loadRoutingSpend()" style="padding:6px 8px">
|
|
3387
|
+
<option value="day" selected>Daily</option>
|
|
3388
|
+
<option value="hour">Hourly (30d)</option>
|
|
3389
|
+
<option value="month">Monthly</option>
|
|
3390
|
+
<option value="total">Total</option>
|
|
3391
|
+
</select>
|
|
3392
|
+
<button onclick="loadRoutingSpend()" style="padding:6px 12px">Refresh</button>
|
|
3393
|
+
</div>
|
|
3394
|
+
</div>
|
|
3395
|
+
<div style="font-size:12px;color:var(--text-dim);line-height:1.4">
|
|
3396
|
+
What the internal AI calls cost, and where the paid-door caps sit. The dollar figures are a
|
|
3397
|
+
<b>reporting</b> view — immutable token counts priced against a reviewed price list on read, so a
|
|
3398
|
+
price correction reflows automatically. <b>No paid door is live yet</b>, so metered spend is $0;
|
|
3399
|
+
subscription/CLI doors are <b>$0 (not per-token billed)</b>. This is read-only — money caps and the
|
|
3400
|
+
go-live control are a later increment.
|
|
3401
|
+
</div>
|
|
3402
|
+
|
|
3403
|
+
<!-- Headline totals -->
|
|
3404
|
+
<div id="spendHeadlineCard" style="border:1px solid var(--border);border-radius:8px;padding:16px">
|
|
3405
|
+
<div id="spendHeadlineBody" style="font-size:13px;overflow-x:auto">
|
|
3406
|
+
<div style="color:var(--text-dim)">Loading...</div>
|
|
3407
|
+
</div>
|
|
3408
|
+
</div>
|
|
3409
|
+
|
|
3410
|
+
<!-- Per door/model spend -->
|
|
3411
|
+
<div style="border:1px solid var(--border);border-radius:8px;padding:16px;display:flex;flex-direction:column;gap:8px">
|
|
3412
|
+
<div style="font-weight:600">By door & model</div>
|
|
3413
|
+
<div id="spendRowsBody" style="font-size:13px;overflow-x:auto">
|
|
3414
|
+
<div style="color:var(--text-dim)">Loading...</div>
|
|
3415
|
+
</div>
|
|
3416
|
+
</div>
|
|
3417
|
+
|
|
3418
|
+
<!-- Paid-door caps -->
|
|
3419
|
+
<div style="border:1px solid var(--border);border-radius:8px;padding:16px;display:flex;flex-direction:column;gap:8px">
|
|
3420
|
+
<div style="font-weight:600">Paid-door caps</div>
|
|
3421
|
+
<div id="spendCapsBody" style="font-size:13px;overflow-x:auto">
|
|
3422
|
+
<div style="color:var(--text-dim)">Loading...</div>
|
|
3423
|
+
</div>
|
|
3424
|
+
</div>
|
|
3425
|
+
</div>
|
|
3426
|
+
|
|
3376
3427
|
<!-- Evidence Tab (WikiClaim Phase 4) — per-entity evidence + reverse "what cites this?" view.
|
|
3377
3428
|
Spec: docs/specs/OPENCLAW-IMPORT-WIKICLAIM-EVIDENCE-SPEC.md § Phase 4 (line 343). -->
|
|
3378
3429
|
<!-- process-health tab -->
|
|
@@ -5046,6 +5097,12 @@
|
|
|
5046
5097
|
display: ['flex'],
|
|
5047
5098
|
onActivate: () => { if (typeof loadRoutingMap === 'function') loadRoutingMap(); },
|
|
5048
5099
|
},
|
|
5100
|
+
{
|
|
5101
|
+
id: 'spend',
|
|
5102
|
+
panels: ['spendPanel'],
|
|
5103
|
+
display: ['flex'],
|
|
5104
|
+
onActivate: () => { if (typeof loadRoutingSpend === 'function') loadRoutingSpend(); },
|
|
5105
|
+
},
|
|
5049
5106
|
{
|
|
5050
5107
|
id: 'threadline',
|
|
5051
5108
|
panels: ['threadlineTab'],
|
|
@@ -5810,6 +5867,110 @@
|
|
|
5810
5867
|
}
|
|
5811
5868
|
}
|
|
5812
5869
|
|
|
5870
|
+
// Routing Control Room — read-only spend/caps view (Increment A). Data from
|
|
5871
|
+
// /routing-spend/summary + /routing-spend/caps. Honest $0 / not-live-yet labelling.
|
|
5872
|
+
async function loadRoutingSpend() {
|
|
5873
|
+
const headEl = document.getElementById('spendHeadlineBody');
|
|
5874
|
+
const rowsEl = document.getElementById('spendRowsBody');
|
|
5875
|
+
const capsEl = document.getElementById('spendCapsBody');
|
|
5876
|
+
const grain = (document.getElementById('spendGrain') || {}).value || 'day';
|
|
5877
|
+
const usd = (n) => '$' + (Number(n) || 0).toFixed(4);
|
|
5878
|
+
const num = (n) => (Number(n) || 0).toLocaleString();
|
|
5879
|
+
const th = (t, right) => '<th style="padding:6px 8px;' + (right ? 'text-align:right' : 'text-align:left') + '">' + t + '</th>';
|
|
5880
|
+
const td = (v, right) => '<td style="padding:6px 8px;vertical-align:top;' + (right ? 'text-align:right' : '') + '">' + v + '</td>';
|
|
5881
|
+
try {
|
|
5882
|
+
const [summary, caps] = await Promise.all([
|
|
5883
|
+
apiFetch('/routing-spend/summary?grain=' + encodeURIComponent(grain)),
|
|
5884
|
+
apiFetch('/routing-spend/caps'),
|
|
5885
|
+
]);
|
|
5886
|
+
|
|
5887
|
+
// Headline totals
|
|
5888
|
+
const t = summary.totals || {};
|
|
5889
|
+
const unpriced = (Number(t.unpricedTokensIn) || 0) + (Number(t.unpricedTokensOut) || 0);
|
|
5890
|
+
const stat = (label, val) => '<div style="min-width:120px"><div style="font-size:11px;color:var(--text-dim)">' + label + '</div><div style="font-size:18px;font-weight:600">' + val + '</div></div>';
|
|
5891
|
+
headEl.innerHTML =
|
|
5892
|
+
'<div style="display:flex;gap:20px;flex-wrap:wrap">' +
|
|
5893
|
+
stat('Gross', usd(t.grossUsd)) +
|
|
5894
|
+
stat('Net (of subsidy/credits)', usd(t.netUsd)) +
|
|
5895
|
+
stat('Committed (cap-enforced)', usd(t.committedUsd)) +
|
|
5896
|
+
stat('Tokens in', num(t.tokensIn)) +
|
|
5897
|
+
stat('Tokens out', num(t.tokensOut)) +
|
|
5898
|
+
(unpriced > 0 ? stat('Unpriced tokens', num(unpriced)) : '') +
|
|
5899
|
+
'</div>' +
|
|
5900
|
+
'<div style="font-size:11px;color:var(--text-dim);margin-top:10px;line-height:1.4">' +
|
|
5901
|
+
escapeHtml(String(summary.note || '')) + '<br>' +
|
|
5902
|
+
escapeHtml(String(summary.horizonNote || '')) +
|
|
5903
|
+
(summary.providerGroundingNote ? '<br>' + escapeHtml(String(summary.providerGroundingNote)) : '') +
|
|
5904
|
+
(summary.reportingBasis ? '<br>Basis: ' + escapeHtml(String(summary.reportingBasis.note || '')) : '') +
|
|
5905
|
+
'</div>';
|
|
5906
|
+
|
|
5907
|
+
// Per door/model rows
|
|
5908
|
+
const rows = summary.rows || [];
|
|
5909
|
+
if (rows.length === 0) {
|
|
5910
|
+
rowsEl.innerHTML = '<div style="color:var(--text-dim)">No internal-LLM usage recorded in this window yet.</div>';
|
|
5911
|
+
} else {
|
|
5912
|
+
rowsEl.innerHTML =
|
|
5913
|
+
'<table style="width:100%;border-collapse:collapse;font-size:12px;min-width:720px">' +
|
|
5914
|
+
'<thead><tr style="color:var(--text-dim)">' +
|
|
5915
|
+
th('Door') + th('Model') + th('Class') + th('Tokens in', true) + th('Tokens out', true) +
|
|
5916
|
+
th('Gross', true) + th('Net', true) + th('Price basis') +
|
|
5917
|
+
'</tr></thead><tbody>' +
|
|
5918
|
+
rows.map((r) => {
|
|
5919
|
+
const cls = r.doorClass === 'metered'
|
|
5920
|
+
? 'metered' + (r.notLiveYet ? ' · not live' : '')
|
|
5921
|
+
: escapeHtml(String(r.doorClass));
|
|
5922
|
+
let basis;
|
|
5923
|
+
if (r.priceBasis === 'subscription-zero') basis = '<span style="color:var(--text-dim)">subscription — not per-token billed</span>';
|
|
5924
|
+
else if (r.priceBasis === 'no-matching-point') basis = '<span style="color:var(--red)">unpriced (no matching price)</span>';
|
|
5925
|
+
else basis = escapeHtml(String(r.priceBasis)) + (r.priceStale ? ' <span style="color:var(--red)">(stale)</span>' : '');
|
|
5926
|
+
const netCell = r.priceBasis === 'subscription-zero' ? '<span style="color:var(--text-dim)">$0 (subscription)</span>' : usd(r.netUsd);
|
|
5927
|
+
return '<tr style="border-top:1px solid var(--border)">' +
|
|
5928
|
+
td('<b>' + escapeHtml(String(r.door)) + '</b>') +
|
|
5929
|
+
td(escapeHtml(String(r.modelId))) +
|
|
5930
|
+
td(escapeHtml(cls)) +
|
|
5931
|
+
td(num(r.tokensIn), true) +
|
|
5932
|
+
td(num(r.tokensOut), true) +
|
|
5933
|
+
td(usd(r.grossUsd), true) +
|
|
5934
|
+
td(netCell, true) +
|
|
5935
|
+
td(basis) +
|
|
5936
|
+
'</tr>';
|
|
5937
|
+
}).join('') +
|
|
5938
|
+
'</tbody></table>';
|
|
5939
|
+
}
|
|
5940
|
+
|
|
5941
|
+
// Paid-door caps
|
|
5942
|
+
const keys = caps.keys || [];
|
|
5943
|
+
capsEl.innerHTML =
|
|
5944
|
+
'<div style="font-size:11px;color:var(--text-dim);margin-bottom:8px">' + escapeHtml(String(caps.note || '')) + '</div>' +
|
|
5945
|
+
'<table style="width:100%;border-collapse:collapse;font-size:12px;min-width:640px">' +
|
|
5946
|
+
'<thead><tr style="color:var(--text-dim)">' +
|
|
5947
|
+
th('Key') + th('Provider') + th('Door') + th('Daily cap', true) + th('Lifetime cap', true) +
|
|
5948
|
+
th('Committed', true) + th('Status') +
|
|
5949
|
+
'</tr></thead><tbody>' +
|
|
5950
|
+
keys.map((k) =>
|
|
5951
|
+
'<tr style="border-top:1px solid var(--border)">' +
|
|
5952
|
+
td('<b>' + escapeHtml(String(k.keyRef)) + '</b>') +
|
|
5953
|
+
td(escapeHtml(String(k.provider))) +
|
|
5954
|
+
td(escapeHtml(String(k.door))) +
|
|
5955
|
+
td(usd(k.dailyCapUsd), true) +
|
|
5956
|
+
td(usd(k.lifetimeCapUsd), true) +
|
|
5957
|
+
td(usd(k.committedDayUsd) + ' / ' + usd(k.committedLifetimeUsd), true) +
|
|
5958
|
+
td('<span style="color:var(--text-dim)">' + escapeHtml(String(k.goLiveState)) + (k.frozen ? ' · frozen' : '') + '</span>') +
|
|
5959
|
+
'</tr>').join('') +
|
|
5960
|
+
'</tbody></table>' +
|
|
5961
|
+
'<div style="font-size:11px;color:var(--text-dim);margin-top:8px">' + escapeHtml(String(caps.singleMachineNote || '')) + '</div>';
|
|
5962
|
+
} catch (err) {
|
|
5963
|
+
const m = err && err.message ? String(err.message) : String(err);
|
|
5964
|
+
if (/503|not enabled|unavailable/i.test(m)) {
|
|
5965
|
+
headEl.innerHTML = '<div style="color:var(--text-dim)">The spend view isn\'t enabled on this agent (it\'s a development-agent surface, dark on the fleet).</div>';
|
|
5966
|
+
} else {
|
|
5967
|
+
headEl.innerHTML = '<div style="color:var(--red)">Error: ' + escapeHtml(m) + '</div>';
|
|
5968
|
+
}
|
|
5969
|
+
rowsEl.innerHTML = '';
|
|
5970
|
+
capsEl.innerHTML = '';
|
|
5971
|
+
}
|
|
5972
|
+
}
|
|
5973
|
+
|
|
5813
5974
|
async function loadResources() {
|
|
5814
5975
|
const headlineEl = document.getElementById('resourcesHeadlineBody');
|
|
5815
5976
|
const sourcesEl = document.getElementById('resourcesSourcesBody');
|
|
@@ -164,15 +164,18 @@ export interface IntelligenceRouterOptions {
|
|
|
164
164
|
* (resolved at the construction boundary, like `ladder`). Absent OR `enabled:false`
|
|
165
165
|
* ⇒ the nature router is inert and routing is BYTE-IDENTICAL to today. When enabled +
|
|
166
166
|
* dryRun (the dev-agent default) the resolver OBSERVES (computes + logs the plan via
|
|
167
|
-
* `onNatureRoutePlan`) and still passes through to today's selection.
|
|
168
|
-
*
|
|
167
|
+
* `onNatureRoutePlan`) and still passes through to today's selection. When enabled +
|
|
168
|
+
* `dryRun:false` (the operator's deliberate post-soak flip — A2.2) the resolved plan
|
|
169
|
+
* REPLACES today's selection: the primary `(door, model)` is used and the swapTail feeds
|
|
170
|
+
* the existing failure-swap loop.
|
|
169
171
|
*/
|
|
170
172
|
resolveNatureRouting?: () => NatureRoutingRuntime | undefined;
|
|
171
173
|
/**
|
|
172
|
-
* S4 A2 — the
|
|
173
|
-
* plan
|
|
174
|
-
* calls it freely. The durable
|
|
175
|
-
* surfaces that consume this
|
|
174
|
+
* S4 A2 — the resolved-plan observation sink (FD11 readable canary). Invoked with the
|
|
175
|
+
* resolved plan on EVERY nature-routing call (dryRun AND enforcing) so the plan is always
|
|
176
|
+
* observable. No-op downstream by default; the router calls it freely. The durable
|
|
177
|
+
* `logs/nature-routing.jsonl` + `GET /intelligence/routing` surfaces that consume this,
|
|
178
|
+
* and the FD6 critical-gate drift notice / baseline, are tracked follow-ups.
|
|
176
179
|
*/
|
|
177
180
|
onNatureRoutePlan?: (plan: NatureRoutePlan) => void;
|
|
178
181
|
}
|
|
@@ -446,8 +449,6 @@ export declare class IntelligenceRouter implements IntelligenceProvider {
|
|
|
446
449
|
private providerFor;
|
|
447
450
|
/** Default framework → shared provider; else the cached per-framework provider (null if binary missing). */
|
|
448
451
|
private resolveProvider;
|
|
449
|
-
/** Already warned that nature-routing enforcing mode is not yet wired (warn ONCE). */
|
|
450
|
-
private warnedNatureEnforceNotWired;
|
|
451
452
|
/**
|
|
452
453
|
* S4 A2 — CLI-door reachability probe for the nature router (FD5 availability walk).
|
|
453
454
|
* CLI doors coincide 1:1 with `IntelligenceFramework`. `resolveRoute` skips metered
|
|
@@ -456,12 +457,6 @@ export declare class IntelligenceRouter implements IntelligenceProvider {
|
|
|
456
457
|
* builds (binary present). Result is cached by `providerFor`.
|
|
457
458
|
*/
|
|
458
459
|
private isCliDoorReachable;
|
|
459
|
-
/**
|
|
460
|
-
* S4 A2 — enforcing-mode honesty guard. Flipping `dryRun:false` in A2.1 does NOT re-route
|
|
461
|
-
* (the selection integration is a tracked A2.2 remainder); routing stays byte-identical.
|
|
462
|
-
* Warn ONCE so the flip is an honest no-op rather than a silent dead switch.
|
|
463
|
-
*/
|
|
464
|
-
private warnNatureEnforceNotWired;
|
|
465
460
|
/** Chains already warned about as rejected (warn ONCE per chain, never per call). */
|
|
466
461
|
private warnedRejectedChains?;
|
|
467
462
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IntelligenceRouter.d.ts","sourceRoot":"","sources":["../../src/core/IntelligenceRouter.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"IntelligenceRouter.d.ts","sourceRoot":"","sources":["../../src/core/IntelligenceRouter.ts"],"names":[],"mappings":"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"}
|
|
@@ -175,16 +175,17 @@ export function isBoundedGatingDegrade(component, options) {
|
|
|
175
175
|
return row.chain !== 'WRITE'; // WRITE is the sanctioned Opus-CLI lane; everything else is bounded/gating
|
|
176
176
|
}
|
|
177
177
|
/* ────────────────────────────────────────────────────────────────────────────
|
|
178
|
-
* S4 Increment A2 — the nature-axis routing RESOLVER
|
|
178
|
+
* S4 Increment A2 — the nature-axis routing RESOLVER.
|
|
179
179
|
*
|
|
180
180
|
* `resolveRoute` is a PURE, side-effect-free evaluator (spec CR2-5): a stateless
|
|
181
181
|
* fold `component → resolvedNature → ordered eligible positions → { primary, swapTail }
|
|
182
182
|
* | 'fall-through' | 'no-route' | throw`. It owns no retry/backoff/breaker/budget
|
|
183
183
|
* machinery — those stay in the existing IntelligenceRouter primitives. Wired into
|
|
184
184
|
* `evaluate()` ONLY when `sessions.natureRouting.enabled` (dev-gated dark). In dryRun
|
|
185
|
-
* (the dev-agent default) it OBSERVES: computes + logs the plan, then passes through
|
|
186
|
-
* today's routing (byte-identical selection).
|
|
187
|
-
*
|
|
185
|
+
* (the dev-agent default, A2.1) it OBSERVES: computes + logs the plan, then passes through
|
|
186
|
+
* to today's routing (byte-identical selection). When `dryRun:false` (A2.2, the operator's
|
|
187
|
+
* deliberate post-soak flip) the resolved plan REPLACES today's selection — the primary
|
|
188
|
+
* `(door, model)` is used and the swapTail feeds the existing failure-swap loop verbatim.
|
|
188
189
|
* Spec: docs/specs/nature-axis-routing.md §Resolver / FD3 / FD4 / FD9.
|
|
189
190
|
* ──────────────────────────────────────────────────────────────────────────── */
|
|
190
191
|
/**
|
|
@@ -643,8 +644,6 @@ export class IntelligenceRouter {
|
|
|
643
644
|
resolveProvider(framework) {
|
|
644
645
|
return framework === this.opts.defaultFramework ? this.opts.defaultProvider : this.providerFor(framework);
|
|
645
646
|
}
|
|
646
|
-
/** Already warned that nature-routing enforcing mode is not yet wired (warn ONCE). */
|
|
647
|
-
warnedNatureEnforceNotWired = false;
|
|
648
647
|
/**
|
|
649
648
|
* S4 A2 — CLI-door reachability probe for the nature router (FD5 availability walk).
|
|
650
649
|
* CLI doors coincide 1:1 with `IntelligenceFramework`. `resolveRoute` skips metered
|
|
@@ -655,20 +654,6 @@ export class IntelligenceRouter {
|
|
|
655
654
|
isCliDoorReachable(door) {
|
|
656
655
|
return this.resolveProvider(door) !== null;
|
|
657
656
|
}
|
|
658
|
-
/**
|
|
659
|
-
* S4 A2 — enforcing-mode honesty guard. Flipping `dryRun:false` in A2.1 does NOT re-route
|
|
660
|
-
* (the selection integration is a tracked A2.2 remainder); routing stays byte-identical.
|
|
661
|
-
* Warn ONCE so the flip is an honest no-op rather than a silent dead switch.
|
|
662
|
-
*/
|
|
663
|
-
warnNatureEnforceNotWired() {
|
|
664
|
-
if (this.warnedNatureEnforceNotWired)
|
|
665
|
-
return;
|
|
666
|
-
this.warnedNatureEnforceNotWired = true;
|
|
667
|
-
console.warn('IntelligenceRouter: sessions.natureRouting.dryRun is false, but nature-routing ENFORCING ' +
|
|
668
|
-
'selection is not wired in this build (Increment A2.1 ships the dark/dryRun observation ' +
|
|
669
|
-
'mechanism; enforcing selection is the tracked A2.2 remainder). Routing stays byte-identical — ' +
|
|
670
|
-
'the resolver plan is logged but not applied.');
|
|
671
|
-
}
|
|
672
657
|
/** Chains already warned about as rejected (warn ONCE per chain, never per call). */
|
|
673
658
|
warnedRejectedChains;
|
|
674
659
|
/**
|
|
@@ -695,13 +680,21 @@ export class IntelligenceRouter {
|
|
|
695
680
|
? explicitCategory
|
|
696
681
|
: categoryForComponent(component);
|
|
697
682
|
const cfg = this.opts.resolveConfig();
|
|
698
|
-
// ── S4 A2 — nature-axis routing
|
|
683
|
+
// ── S4 A2 — nature-axis routing (dev-gated dark; dryRun-first). ──
|
|
699
684
|
// Byte-identical when unset/off: when the feature is absent OR `enabled:false` this
|
|
700
685
|
// whole block is skipped and NOTHING about selection changes. In dryRun (the dev-agent
|
|
701
686
|
// default) it OBSERVES only — computes + logs the plan via `onNatureRoutePlan` — and
|
|
702
|
-
// still falls through to today's selection below.
|
|
703
|
-
//
|
|
704
|
-
//
|
|
687
|
+
// still falls through to today's selection below. When ENFORCING (`dryRun:false`, the
|
|
688
|
+
// operator's deliberate flip after the dryRun soak — A2.2) the resolved plan REPLACES
|
|
689
|
+
// today's selection (spec §Resolver steps 8-9): the primary `(door, model)` becomes the
|
|
690
|
+
// selection and the `swapTail` feeds the EXISTING failure-swap loop verbatim. A resolver
|
|
691
|
+
// error can never break routing here — the DESIGNED critical-gate fail-closed throw
|
|
692
|
+
// (`RouterFailClosedError`) propagates on the real path so the gate caller applies its
|
|
693
|
+
// own fail-closed semantics; any UNEXPECTED resolver error falls through to today's
|
|
694
|
+
// selection (fail-safe). In dryRun EVERY outcome (route / no-route / throw) is recorded
|
|
695
|
+
// only — nothing is ever withheld or re-routed.
|
|
696
|
+
let enforced;
|
|
697
|
+
let enforcedNoRoute = false;
|
|
705
698
|
const natureRt = this.opts.resolveNatureRouting?.();
|
|
706
699
|
if (natureRt?.enabled) {
|
|
707
700
|
const dryRun = natureRt.dryRun !== false; // default true on first enable
|
|
@@ -713,26 +706,69 @@ export class IntelligenceRouter {
|
|
|
713
706
|
isInjectionExposed: (comp) => isComponentInjectionExposed(comp, options?.attribution?.injectionExposed === true),
|
|
714
707
|
});
|
|
715
708
|
this.opts.onNatureRoutePlan?.({ component, category, dryRun, resolution });
|
|
709
|
+
if (!dryRun) {
|
|
710
|
+
// ENFORCE (A2.2): the resolved plan becomes the actual selection.
|
|
711
|
+
if (resolution.outcome === 'route') {
|
|
712
|
+
enforced = { primary: resolution.primary, swapTail: resolution.swapTail };
|
|
713
|
+
}
|
|
714
|
+
else if (resolution.outcome === 'no-route') {
|
|
715
|
+
// Low-stakes mapped, all chain doors down ⇒ the caller's OWN non-gating heuristic
|
|
716
|
+
// (the ordinary provider-down contract) — NEVER legacy category routing, so the
|
|
717
|
+
// harness door can't re-open for a nature-routed component (spec §573-581).
|
|
718
|
+
enforcedNoRoute = true;
|
|
719
|
+
}
|
|
720
|
+
// 'fall-through' (unmapped) ⇒ leave enforcement unset → today's category routing below.
|
|
721
|
+
}
|
|
716
722
|
}
|
|
717
723
|
catch (e) {
|
|
718
724
|
if (e instanceof RouterFailClosedError) {
|
|
719
725
|
this.opts.onNatureRoutePlan?.({ component, category, dryRun, failClosed: true });
|
|
726
|
+
// ENFORCE (A2.2): a mapped FD6 critical gate with no available door FAILS CLOSED on
|
|
727
|
+
// the real path — the caller applies its gating fail-closed semantics (block/deny),
|
|
728
|
+
// never legacy routing and never the harness door. In dryRun the throw is swallowed
|
|
729
|
+
// (observe-and-record only), never surfaced to the call path.
|
|
730
|
+
if (!dryRun)
|
|
731
|
+
throw e;
|
|
720
732
|
}
|
|
721
733
|
else {
|
|
734
|
+
// An UNEXPECTED resolver error (the pure fold only THROWS `RouterFailClosedError` by
|
|
735
|
+
// design). Record it and fall through to today's selection — an unexpected error must
|
|
736
|
+
// never break routing (fail-safe); a real empty-set critical gate is the typed error
|
|
737
|
+
// above, never this branch.
|
|
722
738
|
this.opts.onNatureRoutePlan?.({ component, category, dryRun });
|
|
723
739
|
}
|
|
724
740
|
}
|
|
725
|
-
if (!dryRun)
|
|
726
|
-
this.warnNatureEnforceNotWired();
|
|
727
741
|
}
|
|
728
|
-
//
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
742
|
+
// ENFORCE 'no-route': raise the ordinary non-gating error the caller already catches into
|
|
743
|
+
// its heuristic (tracked never-silent). NEVER legacy category routing (harness-door re-open).
|
|
744
|
+
if (enforcedNoRoute) {
|
|
745
|
+
this.opts.onHeuristicFallthrough?.(component ?? '(none)', this.opts.defaultFramework);
|
|
746
|
+
throw new Error(`IntelligenceRouter: nature-routing 'no-route' — no available door for low-stakes ` +
|
|
747
|
+
`'${component ?? '(none)'}' (all chain doors unreachable); caller uses its heuristic.`);
|
|
748
|
+
}
|
|
749
|
+
// Selection: an enforced nature plan supersedes category routing (its primary door is
|
|
750
|
+
// guaranteed reachable — the resolver only emits reachable CLI doors). Otherwise today's
|
|
751
|
+
// behavior: unconfigured componentFrameworks ⇒ the default provider verbatim.
|
|
752
|
+
let framework;
|
|
753
|
+
let evalOptions = options;
|
|
754
|
+
if (enforced) {
|
|
755
|
+
framework = enforced.primary.door; // resolver emits CLI doors only
|
|
756
|
+
// The resolved primary's CONCRETE model id REPLACES the caller's tier hint (spec step 8).
|
|
757
|
+
// It is already reserve-clamped by the resolver (clampToReserveOnCleanDoor); a concrete id
|
|
758
|
+
// rides `options.model` verbatim to the provider (the adapters resolve tier-or-id).
|
|
759
|
+
evalOptions = { ...(options ?? {}), model: enforced.primary.modelId };
|
|
760
|
+
}
|
|
761
|
+
else {
|
|
762
|
+
if (!cfg)
|
|
763
|
+
return this.opts.defaultProvider.evaluate(prompt, options);
|
|
764
|
+
framework = this.resolveFramework(component, category, cfg);
|
|
765
|
+
}
|
|
732
766
|
const primary = this.resolveProvider(framework);
|
|
733
767
|
// Provider unavailable (binary missing / not built) — unchanged: degrade or error.
|
|
768
|
+
// (`cfg?.` because an enforced nature plan may have superseded category routing with a
|
|
769
|
+
// null `cfg`; an enforced primary door is always reachable, so this branch stays legacy.)
|
|
734
770
|
if (!primary) {
|
|
735
|
-
if ((cfg
|
|
771
|
+
if ((cfg?.fallback ?? 'default') === 'none') {
|
|
736
772
|
throw new Error(`IntelligenceRouter: framework '${framework}' for component '${component ?? '(none)'}' ` +
|
|
737
773
|
`is unavailable and fallback is 'none'.`);
|
|
738
774
|
}
|
|
@@ -785,13 +821,21 @@ export class IntelligenceRouter {
|
|
|
785
821
|
const deferrable = !gating && options?.attribution?.deferrable === true;
|
|
786
822
|
const ladder = this.opts.ladder;
|
|
787
823
|
// Framework-swap applies to a gating OR a deferrable call (both ladder paths include it).
|
|
788
|
-
|
|
824
|
+
// An enforced nature plan supplies the resolved `swapTail` (each a door + concrete model,
|
|
825
|
+
// already reserve-clamped); the legacy path supplies the config `failureSwap` frameworks
|
|
826
|
+
// (each taking the caller's tier, clamped per-door in the loop). BOTH ride the SAME
|
|
827
|
+
// gating||deferrable gate and the SAME loop below — the spec's "reuse verbatim".
|
|
828
|
+
const swapPositions = gating || deferrable
|
|
829
|
+
? enforced
|
|
830
|
+
? enforced.swapTail.map((p) => ({ door: p.door, model: p.modelId }))
|
|
831
|
+
: (cfg?.failureSwap ?? []).map((fw) => ({ door: fw }))
|
|
832
|
+
: [];
|
|
789
833
|
// GATING budget: a single hard wall-clock deadline over the whole gating failure path so an
|
|
790
834
|
// awaited gate stays responsive (no stacking rungs). Deferrable calls are not budgeted this way.
|
|
791
835
|
const gatingDeadlineAt = gating && ladder ? Date.now() + ladder.gatingLadderBudgetMs : undefined;
|
|
792
836
|
let err;
|
|
793
837
|
try {
|
|
794
|
-
const mainResult = await primary.evaluate(prompt,
|
|
838
|
+
const mainResult = await primary.evaluate(prompt, evalOptions);
|
|
795
839
|
this.opts.onResolved?.(component ?? '(none)', framework); // a real answer → auto-resolve any open degradation
|
|
796
840
|
return mainResult;
|
|
797
841
|
}
|
|
@@ -807,7 +851,7 @@ export class IntelligenceRouter {
|
|
|
807
851
|
const delay = Math.min(b.baseMs * Math.pow(b.factor, attempt), b.ceilingMs);
|
|
808
852
|
const jittered = Math.min(Math.floor(delay * (0.5 + Math.random() * 0.5)), b.maxWaitMs);
|
|
809
853
|
try {
|
|
810
|
-
const boResult = await primary.evaluate(prompt, { ...(
|
|
854
|
+
const boResult = await primary.evaluate(prompt, { ...(evalOptions ?? {}), rateLimitWaitMs: jittered });
|
|
811
855
|
this.opts.onResolved?.(component ?? '(none)', framework); // recovered on backoff → auto-resolve
|
|
812
856
|
return boResult;
|
|
813
857
|
}
|
|
@@ -818,12 +862,12 @@ export class IntelligenceRouter {
|
|
|
818
862
|
}
|
|
819
863
|
}
|
|
820
864
|
}
|
|
821
|
-
if (
|
|
865
|
+
if (swapPositions.length === 0) {
|
|
822
866
|
// RUNG (c) — DEFERRABLE queue: no swap configured, but a deferrable call can WAIT for capacity
|
|
823
867
|
// in the LlmQueue before dropping to its heuristic. gating can never reach here (deferrable =
|
|
824
868
|
// !gating && …) — the D5 queue-skip invariant is structural.
|
|
825
869
|
if (deferrable) {
|
|
826
|
-
const q = await this.tryDeferrableQueue(primary, prompt,
|
|
870
|
+
const q = await this.tryDeferrableQueue(primary, prompt, evalOptions, component ?? '(none)', framework, category);
|
|
827
871
|
if (q.ok)
|
|
828
872
|
return q.result;
|
|
829
873
|
}
|
|
@@ -850,7 +894,8 @@ export class IntelligenceRouter {
|
|
|
850
894
|
const budgetMs = isValidMs(this.opts.swapTotalBudgetMs) ? this.opts.swapTotalBudgetMs : undefined;
|
|
851
895
|
const monotonicNow = this.opts.monotonicNow ?? (() => performance.now());
|
|
852
896
|
const swapStartedAt = monotonicNow();
|
|
853
|
-
for (const
|
|
897
|
+
for (const t of swapPositions) {
|
|
898
|
+
const target = t.door;
|
|
854
899
|
// GATING budget: if the awaited gate's total wall-clock budget is consumed, stop swapping
|
|
855
900
|
// and fail closed now (responsiveness over completeness — spec §3a). Deferrable calls have
|
|
856
901
|
// no such deadline (gatingDeadlineAt is undefined for them).
|
|
@@ -873,30 +918,46 @@ export class IntelligenceRouter {
|
|
|
873
918
|
// otherwise-UNcapped attempt (no per-target cap, global ≤0/unset).
|
|
874
919
|
cap = cap === undefined ? remaining : Math.min(cap, remaining);
|
|
875
920
|
}
|
|
876
|
-
//
|
|
877
|
-
//
|
|
878
|
-
//
|
|
879
|
-
//
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
921
|
+
// Model for this swap attempt:
|
|
922
|
+
// - NATURE-enforced position (`t.model` set): its OWN concrete model id, already
|
|
923
|
+
// reserve-clamped by the resolver (`clampToReserveOnCleanDoor`) — so it always
|
|
924
|
+
// overrides the base options.model, and the A1 tier-clamp below is a no-op on it.
|
|
925
|
+
// - LEGACY position (`t.model` undefined): the caller's tier, clamped per SAFETY
|
|
926
|
+
// (S2, R1/R2) — a bounded/gating swap onto claude-code requesting `capable` would
|
|
927
|
+
// resolve to Opus-via-Claude-CLI (the measured-banned door, 81.7% vs 99.1%); clamp
|
|
928
|
+
// it down to `balanced` (Sonnet CLI reserve). Only ever narrows; never upgrades.
|
|
929
|
+
let attemptModel;
|
|
930
|
+
let overrideModel;
|
|
931
|
+
if (t.model !== undefined) {
|
|
932
|
+
attemptModel = t.model;
|
|
933
|
+
overrideModel = true;
|
|
934
|
+
}
|
|
935
|
+
else {
|
|
936
|
+
const clamp = clampClaudeCliSwapModel(target, options?.model);
|
|
937
|
+
attemptModel = clamp.model;
|
|
938
|
+
overrideModel = clamp.clamped;
|
|
939
|
+
if (clamp.clamped) {
|
|
940
|
+
this.opts.onDegrade?.({
|
|
941
|
+
component: component ?? '(none)',
|
|
942
|
+
category,
|
|
943
|
+
from: framework,
|
|
944
|
+
to: target,
|
|
945
|
+
reason: `failure-swap-model-clamp: '${target}' capable→balanced ` +
|
|
946
|
+
`(Opus-via-Claude-CLI is banned for bounded/gating verdicts — R1/R2)`,
|
|
947
|
+
});
|
|
948
|
+
}
|
|
890
949
|
}
|
|
891
950
|
// Pass the cap through as the provider's per-call timeout so the subprocess
|
|
892
951
|
// self-terminates at the bound (no AbortSignal exists on IntelligenceOptions).
|
|
893
|
-
|
|
952
|
+
// Base is `evalOptions` (byte-identical to `options` on the legacy path); an enforced
|
|
953
|
+
// position's model always overrides it below.
|
|
954
|
+
const attemptOptions = cap !== undefined || overrideModel
|
|
894
955
|
? {
|
|
895
|
-
...(
|
|
956
|
+
...(evalOptions ?? {}),
|
|
896
957
|
...(cap !== undefined ? { timeoutMs: cap } : {}),
|
|
897
|
-
...(
|
|
958
|
+
...(overrideModel ? { model: attemptModel } : {}),
|
|
898
959
|
}
|
|
899
|
-
:
|
|
960
|
+
: evalOptions;
|
|
900
961
|
try {
|
|
901
962
|
// withSwapTimeout keeps the shipped, crash-safe Promise.race pattern
|
|
902
963
|
// (InputGuard precedent): it attaches a settlement handler to EACH input,
|
|
@@ -938,7 +999,7 @@ export class IntelligenceRouter {
|
|
|
938
999
|
// for capacity in the LlmQueue before dropping to its heuristic (the gentle order, §3b.3). A
|
|
939
1000
|
// gating call NEVER reaches here (deferrable = !gating && …) — D5 queue-skip is structural.
|
|
940
1001
|
if (deferrable) {
|
|
941
|
-
const q = await this.tryDeferrableQueue(primary, prompt,
|
|
1002
|
+
const q = await this.tryDeferrableQueue(primary, prompt, evalOptions, component ?? '(none)', framework, category);
|
|
942
1003
|
if (q.ok)
|
|
943
1004
|
return q.result;
|
|
944
1005
|
}
|