nexus-agents 2.162.1 → 2.164.0
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/{child-mcp-config-VXXBVJY3.js → child-mcp-config-Q3XDLAVG.js} +3 -3
- package/dist/{chunk-EZHYOWWO.js → chunk-2O4TMKUN.js} +2 -2
- package/dist/{chunk-DXEYJAGO.js → chunk-4WZWUONK.js} +2 -2
- package/dist/{chunk-HJZ3RES7.js → chunk-5HLHFSTH.js} +2 -2
- package/dist/{chunk-MJOHZFJP.js → chunk-6RIGFUZF.js} +15 -8
- package/dist/chunk-6RIGFUZF.js.map +1 -0
- package/dist/{chunk-7QWGLBCE.js → chunk-A57TGFAC.js} +5 -5
- package/dist/{chunk-NL7SZQPW.js → chunk-AXTD4TFK.js} +5 -1
- package/dist/{chunk-NL7SZQPW.js.map → chunk-AXTD4TFK.js.map} +1 -1
- package/dist/{chunk-RN5ISNYK.js → chunk-BE7MNC7B.js} +3 -3
- package/dist/{chunk-V7CIVDNO.js → chunk-BOE7RCND.js} +3 -3
- package/dist/{chunk-6ILEOLNW.js → chunk-FQNXEOL3.js} +2 -2
- package/dist/{chunk-FFH35IKD.js → chunk-FTYO3F2S.js} +3 -3
- package/dist/{chunk-23ZSFBBM.js → chunk-GATA7PDR.js} +9 -9
- package/dist/{chunk-YUAQRJRF.js → chunk-GMLPL5P2.js} +4 -4
- package/dist/{chunk-JB37LBSG.js → chunk-HLP36YBZ.js} +7 -7
- package/dist/{chunk-WP6L2PTV.js → chunk-IH7A6MNH.js} +7 -7
- package/dist/{chunk-ZGSAYLPE.js → chunk-JAGAZMUT.js} +2 -2
- package/dist/{chunk-DBHK6EDT.js → chunk-K54QBTB6.js} +2 -2
- package/dist/{chunk-THUX4X43.js → chunk-K6II2MEP.js} +3 -3
- package/dist/{chunk-EQJR6WMY.js → chunk-KCVJPSZF.js} +2 -2
- package/dist/{chunk-JYR6SBUB.js → chunk-KWYMR424.js} +4 -4
- package/dist/{chunk-TJJW4BGX.js → chunk-M2BRITA3.js} +4 -4
- package/dist/{chunk-XWAV3UC2.js → chunk-M5LNQ6DM.js} +5 -5
- package/dist/{chunk-WGDZFYP3.js → chunk-N6WRMZYA.js} +297 -38
- package/dist/chunk-N6WRMZYA.js.map +1 -0
- package/dist/{chunk-W3ZTVYZN.js → chunk-NSZVUPZH.js} +2 -2
- package/dist/{chunk-GJSJRJ6Y.js → chunk-NWIN6KOK.js} +2 -2
- package/dist/{chunk-VWV34IMA.js → chunk-P2BP7MJS.js} +2 -2
- package/dist/{chunk-754RDQAS.js → chunk-P67JWFPG.js} +2 -2
- package/dist/{chunk-RDYGX6MQ.js → chunk-RYUMBYYR.js} +2 -2
- package/dist/{chunk-JIXCOX7D.js → chunk-SOWWAZ5C.js} +3 -3
- package/dist/{chunk-MJLN336B.js → chunk-UFWFHXDP.js} +3 -3
- package/dist/{chunk-ZIPTXCET.js → chunk-UGNUHVZP.js} +37 -37
- package/dist/{chunk-N67NSSQT.js → chunk-V2PFGYOM.js} +2 -2
- package/dist/{chunk-EVYIQ6N5.js → chunk-VGOPIPDV.js} +6 -6
- package/dist/{chunk-GMSYKYFA.js → chunk-WEIYBIV3.js} +2 -2
- package/dist/{chunk-U4KMGGGF.js → chunk-XYA7W5IQ.js} +2 -2
- package/dist/{chunk-6FWMNTPO.js → chunk-YLA7NOSK.js} +4 -4
- package/dist/{cli-circuit-breaker-B4RH2ELX.js → cli-circuit-breaker-G2P42V3H.js} +5 -5
- package/dist/cli.js +42 -42
- package/dist/{composite-router-4PYFIB2G.js → composite-router-NZPVPGSN.js} +3 -3
- package/dist/{consensus-vote-MM5YG3A5.js → consensus-vote-BTN37MRV.js} +16 -16
- package/dist/{context-retriever-YGPEAEPO.js → context-retriever-4SWGSINU.js} +9 -9
- package/dist/{doctor-deep-N576AXQE.js → doctor-deep-SYEDHAPX.js} +4 -4
- package/dist/{expert-bridge-YEE7F6TA.js → expert-bridge-6I34TGL7.js} +5 -5
- package/dist/factory-2BGHWTMC.js +15 -0
- package/dist/factory-KKRPWZ2A.js +22 -0
- package/dist/{improvement-review-5CZJIOEH.js → improvement-review-4RX6YUVD.js} +6 -6
- package/dist/index.d.ts +33 -0
- package/dist/index.js +31 -31
- package/dist/{init-opencode-R3PEVUUI.js → init-opencode-CXUIMAUP.js} +7 -7
- package/dist/issue-triage-4VXHABBD.js +18 -0
- package/dist/{learning-persistence-M3OTCCNI.js → learning-persistence-6D5GGT7D.js} +4 -2
- package/dist/{pr-reviewer-helpers-TOMMTISB.js → pr-reviewer-helpers-5BOB2KK4.js} +5 -5
- package/dist/{registry-command-EBGQHFT3.js → registry-command-4PDAF4XP.js} +3 -3
- package/dist/{repo-security-plan-CWJ3Z4CC.js → repo-security-plan-UMNW5FP6.js} +4 -4
- package/dist/{research-helpers-synthesize-UNLGVEND.js → research-helpers-synthesize-WYFSSCKX.js} +5 -5
- package/dist/{routing-memory-MTGIZZUO.js → routing-memory-IMJPZUKI.js} +3 -3
- package/dist/{session-memory-QGUF5TNU.js → session-memory-XKJFKI6R.js} +4 -4
- package/dist/{setup-command-6QSWQMBJ.js → setup-command-BPNKRJB2.js} +12 -12
- package/dist/setup-config-DHGAMWSI.js +11 -0
- package/dist/{setup-custom-api-QON4YKJ3.js → setup-custom-api-ESPG7XTX.js} +4 -4
- package/dist/{tool-memory-SNH4B5Q7.js → tool-memory-VGEHRRGE.js} +6 -6
- package/dist/{unified-registry-XEA2GEOZ.js → unified-registry-GLVZZGSC.js} +10 -10
- package/dist/{weather-report-QQ42WBNZ.js → weather-report-ITGCNNPJ.js} +3 -3
- package/package.json +1 -1
- package/dist/chunk-MJOHZFJP.js.map +0 -1
- package/dist/chunk-WGDZFYP3.js.map +0 -1
- package/dist/factory-NQEQY7NV.js +0 -15
- package/dist/factory-TWK2UKNH.js +0 -22
- package/dist/issue-triage-Y35K4BUV.js +0 -18
- package/dist/setup-config-4TGGV7AQ.js +0 -11
- /package/dist/{child-mcp-config-VXXBVJY3.js.map → child-mcp-config-Q3XDLAVG.js.map} +0 -0
- /package/dist/{chunk-EZHYOWWO.js.map → chunk-2O4TMKUN.js.map} +0 -0
- /package/dist/{chunk-DXEYJAGO.js.map → chunk-4WZWUONK.js.map} +0 -0
- /package/dist/{chunk-HJZ3RES7.js.map → chunk-5HLHFSTH.js.map} +0 -0
- /package/dist/{chunk-7QWGLBCE.js.map → chunk-A57TGFAC.js.map} +0 -0
- /package/dist/{chunk-RN5ISNYK.js.map → chunk-BE7MNC7B.js.map} +0 -0
- /package/dist/{chunk-V7CIVDNO.js.map → chunk-BOE7RCND.js.map} +0 -0
- /package/dist/{chunk-6ILEOLNW.js.map → chunk-FQNXEOL3.js.map} +0 -0
- /package/dist/{chunk-FFH35IKD.js.map → chunk-FTYO3F2S.js.map} +0 -0
- /package/dist/{chunk-23ZSFBBM.js.map → chunk-GATA7PDR.js.map} +0 -0
- /package/dist/{chunk-YUAQRJRF.js.map → chunk-GMLPL5P2.js.map} +0 -0
- /package/dist/{chunk-JB37LBSG.js.map → chunk-HLP36YBZ.js.map} +0 -0
- /package/dist/{chunk-WP6L2PTV.js.map → chunk-IH7A6MNH.js.map} +0 -0
- /package/dist/{chunk-ZGSAYLPE.js.map → chunk-JAGAZMUT.js.map} +0 -0
- /package/dist/{chunk-DBHK6EDT.js.map → chunk-K54QBTB6.js.map} +0 -0
- /package/dist/{chunk-THUX4X43.js.map → chunk-K6II2MEP.js.map} +0 -0
- /package/dist/{chunk-EQJR6WMY.js.map → chunk-KCVJPSZF.js.map} +0 -0
- /package/dist/{chunk-JYR6SBUB.js.map → chunk-KWYMR424.js.map} +0 -0
- /package/dist/{chunk-TJJW4BGX.js.map → chunk-M2BRITA3.js.map} +0 -0
- /package/dist/{chunk-XWAV3UC2.js.map → chunk-M5LNQ6DM.js.map} +0 -0
- /package/dist/{chunk-W3ZTVYZN.js.map → chunk-NSZVUPZH.js.map} +0 -0
- /package/dist/{chunk-GJSJRJ6Y.js.map → chunk-NWIN6KOK.js.map} +0 -0
- /package/dist/{chunk-VWV34IMA.js.map → chunk-P2BP7MJS.js.map} +0 -0
- /package/dist/{chunk-754RDQAS.js.map → chunk-P67JWFPG.js.map} +0 -0
- /package/dist/{chunk-RDYGX6MQ.js.map → chunk-RYUMBYYR.js.map} +0 -0
- /package/dist/{chunk-JIXCOX7D.js.map → chunk-SOWWAZ5C.js.map} +0 -0
- /package/dist/{chunk-MJLN336B.js.map → chunk-UFWFHXDP.js.map} +0 -0
- /package/dist/{chunk-ZIPTXCET.js.map → chunk-UGNUHVZP.js.map} +0 -0
- /package/dist/{chunk-N67NSSQT.js.map → chunk-V2PFGYOM.js.map} +0 -0
- /package/dist/{chunk-EVYIQ6N5.js.map → chunk-VGOPIPDV.js.map} +0 -0
- /package/dist/{chunk-GMSYKYFA.js.map → chunk-WEIYBIV3.js.map} +0 -0
- /package/dist/{chunk-U4KMGGGF.js.map → chunk-XYA7W5IQ.js.map} +0 -0
- /package/dist/{chunk-6FWMNTPO.js.map → chunk-YLA7NOSK.js.map} +0 -0
- /package/dist/{cli-circuit-breaker-B4RH2ELX.js.map → cli-circuit-breaker-G2P42V3H.js.map} +0 -0
- /package/dist/{composite-router-4PYFIB2G.js.map → composite-router-NZPVPGSN.js.map} +0 -0
- /package/dist/{consensus-vote-MM5YG3A5.js.map → consensus-vote-BTN37MRV.js.map} +0 -0
- /package/dist/{context-retriever-YGPEAEPO.js.map → context-retriever-4SWGSINU.js.map} +0 -0
- /package/dist/{doctor-deep-N576AXQE.js.map → doctor-deep-SYEDHAPX.js.map} +0 -0
- /package/dist/{expert-bridge-YEE7F6TA.js.map → expert-bridge-6I34TGL7.js.map} +0 -0
- /package/dist/{factory-NQEQY7NV.js.map → factory-2BGHWTMC.js.map} +0 -0
- /package/dist/{factory-TWK2UKNH.js.map → factory-KKRPWZ2A.js.map} +0 -0
- /package/dist/{improvement-review-5CZJIOEH.js.map → improvement-review-4RX6YUVD.js.map} +0 -0
- /package/dist/{init-opencode-R3PEVUUI.js.map → init-opencode-CXUIMAUP.js.map} +0 -0
- /package/dist/{issue-triage-Y35K4BUV.js.map → issue-triage-4VXHABBD.js.map} +0 -0
- /package/dist/{learning-persistence-M3OTCCNI.js.map → learning-persistence-6D5GGT7D.js.map} +0 -0
- /package/dist/{pr-reviewer-helpers-TOMMTISB.js.map → pr-reviewer-helpers-5BOB2KK4.js.map} +0 -0
- /package/dist/{registry-command-EBGQHFT3.js.map → registry-command-4PDAF4XP.js.map} +0 -0
- /package/dist/{repo-security-plan-CWJ3Z4CC.js.map → repo-security-plan-UMNW5FP6.js.map} +0 -0
- /package/dist/{research-helpers-synthesize-UNLGVEND.js.map → research-helpers-synthesize-WYFSSCKX.js.map} +0 -0
- /package/dist/{routing-memory-MTGIZZUO.js.map → routing-memory-IMJPZUKI.js.map} +0 -0
- /package/dist/{session-memory-QGUF5TNU.js.map → session-memory-XKJFKI6R.js.map} +0 -0
- /package/dist/{setup-command-6QSWQMBJ.js.map → setup-command-BPNKRJB2.js.map} +0 -0
- /package/dist/{setup-config-4TGGV7AQ.js.map → setup-config-DHGAMWSI.js.map} +0 -0
- /package/dist/{setup-custom-api-QON4YKJ3.js.map → setup-custom-api-ESPG7XTX.js.map} +0 -0
- /package/dist/{tool-memory-SNH4B5Q7.js.map → tool-memory-VGEHRRGE.js.map} +0 -0
- /package/dist/{unified-registry-XEA2GEOZ.js.map → unified-registry-GLVZZGSC.js.map} +0 -0
- /package/dist/{weather-report-QQ42WBNZ.js.map → weather-report-ITGCNNPJ.js.map} +0 -0
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ensureLearningDir,
|
|
3
3
|
getDecisionCostFile,
|
|
4
|
+
getModelSelectionShadowFile,
|
|
4
5
|
isPersistenceEnabled
|
|
5
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-AXTD4TFK.js";
|
|
6
7
|
import {
|
|
7
8
|
nexusDataPath
|
|
8
9
|
} from "./chunk-DHVMSIT5.js";
|
|
@@ -1499,6 +1500,12 @@ var DEFAULT_MODEL_PER_CLI = {
|
|
|
1499
1500
|
codex: "gpt-5.5",
|
|
1500
1501
|
opencode: "opencode-default"
|
|
1501
1502
|
};
|
|
1503
|
+
var STATIC_CLI_COST_PER_1M = {
|
|
1504
|
+
claude: { input: 3, output: 15 },
|
|
1505
|
+
gemini: { input: 0.075, output: 0.3 },
|
|
1506
|
+
codex: { input: 2.5, output: 10 },
|
|
1507
|
+
opencode: { input: 2, output: 8 }
|
|
1508
|
+
};
|
|
1502
1509
|
|
|
1503
1510
|
// src/config/model-derivation.ts
|
|
1504
1511
|
var DEFAULT_ENTRY = {
|
|
@@ -2612,7 +2619,7 @@ function setDefaultRegistry(registry) {
|
|
|
2612
2619
|
}
|
|
2613
2620
|
async function reloadDefaultRegistry() {
|
|
2614
2621
|
globalRegistry = buildDefaultRegistry();
|
|
2615
|
-
const { resetGlobalRegistry } = await import("./unified-registry-
|
|
2622
|
+
const { resetGlobalRegistry } = await import("./unified-registry-GLVZZGSC.js");
|
|
2616
2623
|
resetGlobalRegistry();
|
|
2617
2624
|
return globalRegistry;
|
|
2618
2625
|
}
|
|
@@ -2642,6 +2649,14 @@ function getDefaultModelForCli(cli) {
|
|
|
2642
2649
|
if (registry === void 0) return staticDefault;
|
|
2643
2650
|
return registry.getEntry(staticDefault).id;
|
|
2644
2651
|
}
|
|
2652
|
+
function resolveModelCostPer1M(modelId, fallback) {
|
|
2653
|
+
const pricing = getModelPricing(modelId);
|
|
2654
|
+
if (pricing === void 0) return fallback;
|
|
2655
|
+
return { input: pricing.inputPer1M, output: pricing.outputPer1M };
|
|
2656
|
+
}
|
|
2657
|
+
function resolveCliCostPer1M(cli) {
|
|
2658
|
+
return resolveModelCostPer1M(getDefaultModelForCli(cli), STATIC_CLI_COST_PER_1M[cli]);
|
|
2659
|
+
}
|
|
2645
2660
|
function getCliModelName(modelId) {
|
|
2646
2661
|
const entry = lookupInTree(modelId);
|
|
2647
2662
|
return entry?.cliModelName ?? entry?.cliAlias ?? modelId;
|
|
@@ -2692,9 +2707,10 @@ function buildTopsisProfiles() {
|
|
|
2692
2707
|
for (const [cli, modelId] of Object.entries(DEFAULT_MODEL_PER_CLI)) {
|
|
2693
2708
|
const entry = byId.get(modelId);
|
|
2694
2709
|
const q = entry?.qualityScores;
|
|
2695
|
-
|
|
2696
|
-
if (entry === void 0 || q === void 0 || p === void 0) continue;
|
|
2710
|
+
if (entry === void 0 || q === void 0) continue;
|
|
2697
2711
|
if (entry.contextWindow === void 0) continue;
|
|
2712
|
+
const p = entry.pricing;
|
|
2713
|
+
const price = p !== void 0 ? { input: p.inputPer1M, output: p.outputPer1M } : STATIC_CLI_COST_PER_1M[cli];
|
|
2698
2714
|
profiles.push({
|
|
2699
2715
|
cliName: cli,
|
|
2700
2716
|
capabilities: {
|
|
@@ -2704,8 +2720,8 @@ function buildTopsisProfiles() {
|
|
|
2704
2720
|
speed: q.speed,
|
|
2705
2721
|
cost: q.cost
|
|
2706
2722
|
},
|
|
2707
|
-
costPerMillionInput:
|
|
2708
|
-
costPerMillionOutput:
|
|
2723
|
+
costPerMillionInput: price.input,
|
|
2724
|
+
costPerMillionOutput: price.output,
|
|
2709
2725
|
averageLatencyMs: cliAvgLatency()[cli],
|
|
2710
2726
|
qualityScore: (q.reasoning + q.codeGeneration) / 2
|
|
2711
2727
|
});
|
|
@@ -5356,17 +5372,11 @@ var RoutingMemoryError = class extends Error {
|
|
|
5356
5372
|
};
|
|
5357
5373
|
|
|
5358
5374
|
// src/cli-adapters/budget-utils.ts
|
|
5359
|
-
var TOKEN_COSTS = {
|
|
5360
|
-
claude: { input: 3, output: 15 },
|
|
5361
|
-
gemini: { input: 0.075, output: 0.3 },
|
|
5362
|
-
codex: { input: 2.5, output: 10 },
|
|
5363
|
-
opencode: { input: 2, output: 8 }
|
|
5364
|
-
};
|
|
5365
5375
|
function estimateTokens2(content) {
|
|
5366
5376
|
return Math.ceil(content.length / 4);
|
|
5367
5377
|
}
|
|
5368
5378
|
function estimateCost(model, inputTokens, outputTokens) {
|
|
5369
|
-
const costs =
|
|
5379
|
+
const costs = resolveCliCostPer1M(model);
|
|
5370
5380
|
const inputCost = inputTokens / 1e6 * costs.input;
|
|
5371
5381
|
const outputCost = outputTokens / 1e6 * costs.output;
|
|
5372
5382
|
return inputCost + outputCost;
|
|
@@ -9018,14 +9028,14 @@ function detectSuccessPatterns(groups, threshold) {
|
|
|
9018
9028
|
const patterns = [];
|
|
9019
9029
|
for (const g of groups) {
|
|
9020
9030
|
const successCount = g.outcomes.filter((o) => o.success).length;
|
|
9021
|
-
const
|
|
9022
|
-
if (
|
|
9031
|
+
const successRate3 = successCount / g.outcomes.length;
|
|
9032
|
+
if (successRate3 >= threshold) {
|
|
9023
9033
|
patterns.push({
|
|
9024
9034
|
cli: g.cli,
|
|
9025
9035
|
category: g.category,
|
|
9026
9036
|
patternType: "success-rate",
|
|
9027
9037
|
action: "boost",
|
|
9028
|
-
metric:
|
|
9038
|
+
metric: successRate3,
|
|
9029
9039
|
observationCount: g.outcomes.length
|
|
9030
9040
|
});
|
|
9031
9041
|
}
|
|
@@ -9218,10 +9228,10 @@ var StrategyDistiller = class {
|
|
|
9218
9228
|
}
|
|
9219
9229
|
/** Convert rule metrics into ModelPerformance for RoutingMemory. */
|
|
9220
9230
|
ruleToPerformance(rule) {
|
|
9221
|
-
const
|
|
9231
|
+
const successRate3 = rule.patternType === "success-rate" ? rule.metric : 1 - rule.metric;
|
|
9222
9232
|
return {
|
|
9223
9233
|
avgQuality: rule.confidence,
|
|
9224
|
-
successRate: Math.max(0, Math.min(1,
|
|
9234
|
+
successRate: Math.max(0, Math.min(1, successRate3)),
|
|
9225
9235
|
avgLatencyMs: 0,
|
|
9226
9236
|
avgTokens: 0,
|
|
9227
9237
|
observations: rule.observationCount
|
|
@@ -12419,9 +12429,9 @@ function getAdaptiveBonus(cli, category, config) {
|
|
|
12419
12429
|
const cliName = cli;
|
|
12420
12430
|
const outcomes = queryWithLookback(store, cliName, category, cfg);
|
|
12421
12431
|
if (outcomes.length < cfg.coldStartThreshold) return 0;
|
|
12422
|
-
const
|
|
12432
|
+
const successRate3 = outcomes.filter((o) => o.success).length / outcomes.length;
|
|
12423
12433
|
const FIXED_BASELINE = 0.7;
|
|
12424
|
-
const delta =
|
|
12434
|
+
const delta = successRate3 - FIXED_BASELINE;
|
|
12425
12435
|
const FULL_CONFIDENCE_SAMPLES2 = 50;
|
|
12426
12436
|
const windowedConfidence = Math.min(1, outcomes.length / FULL_CONFIDENCE_SAMPLES2);
|
|
12427
12437
|
const maxBonus = Math.min(cfg.maxBonusAdjustment * windowedConfidence, cfg.maxBonusAdjustment);
|
|
@@ -12696,17 +12706,17 @@ function buildExpertPerformance() {
|
|
|
12696
12706
|
const successes = outcomes.filter((o) => o.success).length;
|
|
12697
12707
|
const totalDuration = outcomes.reduce((s, o) => s + o.durationMs, 0);
|
|
12698
12708
|
const dominantErrorPattern = findDominantError(outcomes.filter((o) => !o.success));
|
|
12699
|
-
const
|
|
12709
|
+
const successRate3 = successes / outcomes.length;
|
|
12700
12710
|
const consecutiveFailures = countTrailingFailures(outcomes);
|
|
12701
12711
|
const lastSuccess = [...outcomes].reverse().find((o) => o.success);
|
|
12702
12712
|
const lastSuccessAt = lastSuccess !== void 0 ? new Date(lastSuccess.timestamp).toISOString() : void 0;
|
|
12703
12713
|
entries.push({
|
|
12704
12714
|
role,
|
|
12705
12715
|
totalTasks: outcomes.length,
|
|
12706
|
-
successRate:
|
|
12716
|
+
successRate: successRate3,
|
|
12707
12717
|
avgDurationMs: Math.round(totalDuration / outcomes.length),
|
|
12708
12718
|
consecutiveFailures,
|
|
12709
|
-
degraded:
|
|
12719
|
+
degraded: successRate3 < 0.5,
|
|
12710
12720
|
...dominantErrorPattern !== void 0 ? { dominantErrorPattern } : {},
|
|
12711
12721
|
...lastSuccessAt !== void 0 ? { lastSuccessAt } : {}
|
|
12712
12722
|
});
|
|
@@ -13686,6 +13696,169 @@ function resolveModelForTier(cliName, tier, opts = {}) {
|
|
|
13686
13696
|
return scored[0]?.id ?? getDefaultModelForCli(cliName);
|
|
13687
13697
|
}
|
|
13688
13698
|
|
|
13699
|
+
// src/cli-adapters/model-selection-shadow.ts
|
|
13700
|
+
import { appendFileSync as appendFileSync2, existsSync as existsSync7, readFileSync as readFileSync6 } from "fs";
|
|
13701
|
+
import { z as z19 } from "zod";
|
|
13702
|
+
function isRouteModelShadowEnabled() {
|
|
13703
|
+
return process.env["NEXUS_ROUTE_MODEL_SHADOW"] === "1" && isPersistenceEnabled();
|
|
13704
|
+
}
|
|
13705
|
+
var MODEL_SELECTION_SHADOW_SCHEMA_VERSION = 1;
|
|
13706
|
+
var READ_LOOKBACK_DAYS = 30;
|
|
13707
|
+
var READ_LOOKBACK_MS = READ_LOOKBACK_DAYS * 24 * 60 * 60 * 1e3;
|
|
13708
|
+
var ModelTierSchema = z19.enum(["fast", "balanced", "powerful"]);
|
|
13709
|
+
var ModelSelectionShadowRecordSchema = z19.object({
|
|
13710
|
+
schema: z19.literal(MODEL_SELECTION_SHADOW_SCHEMA_VERSION),
|
|
13711
|
+
/** ISO timestamp of the outcome join. */
|
|
13712
|
+
timestamp: z19.string().min(1),
|
|
13713
|
+
/** Display slot of the routed CLI (api:* arms collapse to their slot). */
|
|
13714
|
+
cli: z19.string().min(1).max(40),
|
|
13715
|
+
/** Difficulty tier the ZeroRouter computed for the task. */
|
|
13716
|
+
tier: ModelTierSchema,
|
|
13717
|
+
/** Model the live decision actually used (or the CLI default when route-time selection is off). */
|
|
13718
|
+
actualModel: z19.string().min(1).max(120),
|
|
13719
|
+
/** Model `resolveModelForTier` WOULD have picked (never executed). */
|
|
13720
|
+
shadowModel: z19.string().min(1).max(120),
|
|
13721
|
+
/** Whether shadow and actual agree. */
|
|
13722
|
+
agree: z19.boolean(),
|
|
13723
|
+
/** Whether the actually-executed decision succeeded. */
|
|
13724
|
+
success: z19.boolean(),
|
|
13725
|
+
/** Measured cost of the actual execution, when available (unmeasured today on the routing path). */
|
|
13726
|
+
costUsd: z19.number().nonnegative().optional()
|
|
13727
|
+
});
|
|
13728
|
+
function computeModelSelectionShadow(cli, tier, actualModel) {
|
|
13729
|
+
const shadowModel = resolveModelForTier(cli, tier);
|
|
13730
|
+
const actual = actualModel ?? getDefaultModelForCli(cli);
|
|
13731
|
+
return { cli, tier, actualModel: actual, shadowModel, agree: shadowModel === actual };
|
|
13732
|
+
}
|
|
13733
|
+
var shadowFailureCount = 0;
|
|
13734
|
+
function recordModelSelectionShadowFailure() {
|
|
13735
|
+
return ++shadowFailureCount;
|
|
13736
|
+
}
|
|
13737
|
+
var persistLogger = createLogger({ component: "ModelSelectionShadow" });
|
|
13738
|
+
function persistModelSelectionShadowRecord(record) {
|
|
13739
|
+
try {
|
|
13740
|
+
ensureLearningDir();
|
|
13741
|
+
appendFileSync2(getModelSelectionShadowFile(), JSON.stringify(record) + "\n", "utf-8");
|
|
13742
|
+
} catch (err2) {
|
|
13743
|
+
recordModelSelectionShadowFailure();
|
|
13744
|
+
persistLogger.warn("Failed to persist model-selection shadow record (ignored)", {
|
|
13745
|
+
error: getErrorMessage(err2)
|
|
13746
|
+
});
|
|
13747
|
+
}
|
|
13748
|
+
}
|
|
13749
|
+
function readModelSelectionShadowRecords() {
|
|
13750
|
+
const file = getModelSelectionShadowFile();
|
|
13751
|
+
if (!existsSync7(file)) return [];
|
|
13752
|
+
const records = [];
|
|
13753
|
+
try {
|
|
13754
|
+
const cutoff = Date.now() - READ_LOOKBACK_MS;
|
|
13755
|
+
const lines = readFileSync6(file, "utf-8").split("\n").filter((l) => l.trim().length > 0);
|
|
13756
|
+
for (const line of lines) {
|
|
13757
|
+
let parsed;
|
|
13758
|
+
try {
|
|
13759
|
+
parsed = JSON.parse(line);
|
|
13760
|
+
} catch {
|
|
13761
|
+
continue;
|
|
13762
|
+
}
|
|
13763
|
+
const result = ModelSelectionShadowRecordSchema.safeParse(parsed);
|
|
13764
|
+
if (!result.success) continue;
|
|
13765
|
+
const ts = Date.parse(result.data.timestamp);
|
|
13766
|
+
if (Number.isNaN(ts) || ts < cutoff) continue;
|
|
13767
|
+
records.push(result.data);
|
|
13768
|
+
}
|
|
13769
|
+
} catch (err2) {
|
|
13770
|
+
persistLogger.warn("Failed to read model-selection shadow records (ignored)", {
|
|
13771
|
+
error: getErrorMessage(err2)
|
|
13772
|
+
});
|
|
13773
|
+
}
|
|
13774
|
+
return records;
|
|
13775
|
+
}
|
|
13776
|
+
|
|
13777
|
+
// src/cli-adapters/model-selection-readiness.ts
|
|
13778
|
+
var DEFAULT_MODEL_SELECTION_READINESS_CONFIG = {
|
|
13779
|
+
minDivergingDecisions: 50,
|
|
13780
|
+
minSuccessDelta: 0.05,
|
|
13781
|
+
minCostSamples: 10
|
|
13782
|
+
};
|
|
13783
|
+
function successRate2(t) {
|
|
13784
|
+
return t.count === 0 ? 0 : t.successes / t.count;
|
|
13785
|
+
}
|
|
13786
|
+
function summarizeModelSelectionShadow(records) {
|
|
13787
|
+
const agree = { count: 0, successes: 0 };
|
|
13788
|
+
const diverge = { count: 0, successes: 0 };
|
|
13789
|
+
let costSamples = 0;
|
|
13790
|
+
let costTotal = 0;
|
|
13791
|
+
for (const r of records) {
|
|
13792
|
+
const cohort = r.agree ? agree : diverge;
|
|
13793
|
+
cohort.count++;
|
|
13794
|
+
if (r.success) cohort.successes++;
|
|
13795
|
+
if (r.costUsd !== void 0) {
|
|
13796
|
+
costSamples++;
|
|
13797
|
+
costTotal += r.costUsd;
|
|
13798
|
+
}
|
|
13799
|
+
}
|
|
13800
|
+
const agreeSuccessRate = successRate2(agree);
|
|
13801
|
+
const divergeSuccessRate = successRate2(diverge);
|
|
13802
|
+
const successDelta = agree.count === 0 || diverge.count === 0 ? 0 : agreeSuccessRate - divergeSuccessRate;
|
|
13803
|
+
return {
|
|
13804
|
+
total: records.length,
|
|
13805
|
+
agreeing: agree.count,
|
|
13806
|
+
diverging: diverge.count,
|
|
13807
|
+
agreeSuccessRate,
|
|
13808
|
+
divergeSuccessRate,
|
|
13809
|
+
successDelta,
|
|
13810
|
+
costSamples,
|
|
13811
|
+
meanCostUsd: costSamples === 0 ? 0 : costTotal / costSamples
|
|
13812
|
+
};
|
|
13813
|
+
}
|
|
13814
|
+
function evaluateModelSelectionReadiness(records, config = DEFAULT_MODEL_SELECTION_READINESS_CONFIG) {
|
|
13815
|
+
const s = summarizeModelSelectionShadow(records);
|
|
13816
|
+
const criteria = [
|
|
13817
|
+
{
|
|
13818
|
+
name: "volume",
|
|
13819
|
+
met: s.diverging >= config.minDivergingDecisions,
|
|
13820
|
+
detail: `${String(s.diverging)} shadow-diverging decisions (need \u2265 ${String(config.minDivergingDecisions)})`
|
|
13821
|
+
},
|
|
13822
|
+
{
|
|
13823
|
+
name: "success-delta",
|
|
13824
|
+
met: s.successDelta >= config.minSuccessDelta,
|
|
13825
|
+
detail: `agree\u2212diverge success delta ${s.successDelta.toFixed(2)} (agree ${s.agreeSuccessRate.toFixed(2)} over ${String(s.agreeing)}, diverge ${s.divergeSuccessRate.toFixed(2)} over ${String(s.diverging)}; need \u2265 ${config.minSuccessDelta.toFixed(2)})`
|
|
13826
|
+
},
|
|
13827
|
+
{
|
|
13828
|
+
name: "cost-measured",
|
|
13829
|
+
met: s.costSamples >= config.minCostSamples,
|
|
13830
|
+
detail: `${String(s.costSamples)} decisions with measured costUsd, mean $${s.meanCostUsd.toFixed(4)} (need \u2265 ${String(config.minCostSamples)})`
|
|
13831
|
+
}
|
|
13832
|
+
];
|
|
13833
|
+
const blockers = criteria.filter((c) => !c.met).map((c) => c.name);
|
|
13834
|
+
return { ready: blockers.length === 0, criteria, blockers };
|
|
13835
|
+
}
|
|
13836
|
+
var readinessLogged = false;
|
|
13837
|
+
function logModelSelectionReadinessOnce(logger14) {
|
|
13838
|
+
if (readinessLogged) return;
|
|
13839
|
+
readinessLogged = true;
|
|
13840
|
+
try {
|
|
13841
|
+
const records = readModelSelectionShadowRecords();
|
|
13842
|
+
const summary = summarizeModelSelectionShadow(records);
|
|
13843
|
+
const verdict = evaluateModelSelectionReadiness(records);
|
|
13844
|
+
logger14.info("route-model-selection shadow readiness", {
|
|
13845
|
+
ready: verdict.ready,
|
|
13846
|
+
blockers: verdict.blockers,
|
|
13847
|
+
total: summary.total,
|
|
13848
|
+
diverging: summary.diverging,
|
|
13849
|
+
successDelta: summary.successDelta,
|
|
13850
|
+
agreeSuccessRate: summary.agreeSuccessRate,
|
|
13851
|
+
divergeSuccessRate: summary.divergeSuccessRate,
|
|
13852
|
+
costSamples: summary.costSamples,
|
|
13853
|
+
meanCostUsd: summary.meanCostUsd
|
|
13854
|
+
});
|
|
13855
|
+
} catch (err2) {
|
|
13856
|
+
logger14.warn("route-model-selection readiness signal failed (non-fatal)", {
|
|
13857
|
+
error: getErrorMessage(err2)
|
|
13858
|
+
});
|
|
13859
|
+
}
|
|
13860
|
+
}
|
|
13861
|
+
|
|
13689
13862
|
// src/cli-adapters/composite-router-outcome.ts
|
|
13690
13863
|
var sharedAnalyzer3 = createSharedTaskAnalyzer();
|
|
13691
13864
|
function recordBanditOutcome(cliName, task, reward, deps) {
|
|
@@ -13894,6 +14067,13 @@ var CompositeRouter = class _CompositeRouter {
|
|
|
13894
14067
|
lastRoutedTask;
|
|
13895
14068
|
// Track last traceId for metrics correlation (Issue #559)
|
|
13896
14069
|
lastTraceId;
|
|
14070
|
+
/**
|
|
14071
|
+
* Pending model-selection shadow comparison awaiting its outcome join
|
|
14072
|
+
* (#4197). Keyed by task content like {@link lastRoutedTask}; persisted with
|
|
14073
|
+
* `success` when `recordDifficultyOutcome` reports the matching outcome.
|
|
14074
|
+
* The task content itself is never persisted.
|
|
14075
|
+
*/
|
|
14076
|
+
pendingModelShadow;
|
|
13897
14077
|
constructor(adapters, config, logger14) {
|
|
13898
14078
|
const {
|
|
13899
14079
|
preferenceRouterConfig,
|
|
@@ -14078,7 +14258,7 @@ var CompositeRouter = class _CompositeRouter {
|
|
|
14078
14258
|
*/
|
|
14079
14259
|
async consultUnifiedContext(task) {
|
|
14080
14260
|
try {
|
|
14081
|
-
const { getContextForTask, inferTaskCategory } = await import("./context-retriever-
|
|
14261
|
+
const { getContextForTask, inferTaskCategory } = await import("./context-retriever-4SWGSINU.js");
|
|
14082
14262
|
const ctx = await getContextForTask({
|
|
14083
14263
|
task: task.content,
|
|
14084
14264
|
category: inferTaskCategory(task.content),
|
|
@@ -14202,12 +14382,16 @@ var CompositeRouter = class _CompositeRouter {
|
|
|
14202
14382
|
return pipelineResult;
|
|
14203
14383
|
}
|
|
14204
14384
|
this.trackLastRoutedTask(task, pipelineResult.value);
|
|
14205
|
-
|
|
14385
|
+
const decisionResult = this.buildRoutingDecision({
|
|
14206
14386
|
...pipelineResult.value,
|
|
14207
14387
|
taskProfile,
|
|
14208
14388
|
stagesExecuted,
|
|
14209
14389
|
startTime
|
|
14210
14390
|
});
|
|
14391
|
+
if (decisionResult.ok) {
|
|
14392
|
+
this.trackModelSelectionShadow(task, decisionResult.value);
|
|
14393
|
+
}
|
|
14394
|
+
return decisionResult;
|
|
14211
14395
|
} catch (error) {
|
|
14212
14396
|
return this.handleRoutingError(error, stagesExecuted);
|
|
14213
14397
|
}
|
|
@@ -14293,6 +14477,80 @@ var CompositeRouter = class _CompositeRouter {
|
|
|
14293
14477
|
};
|
|
14294
14478
|
}
|
|
14295
14479
|
}
|
|
14480
|
+
/**
|
|
14481
|
+
* Compute the model-selection SHADOW comparison for a routed decision
|
|
14482
|
+
* (#4197): what `resolveModelForTier` WOULD have picked vs the model the
|
|
14483
|
+
* decision actually carries (or the CLI default the adapter will resolve).
|
|
14484
|
+
* Held pending until `recordDifficultyOutcome` supplies the outcome, then
|
|
14485
|
+
* persisted to the dedicated shadow log. Gated behind
|
|
14486
|
+
* `NEXUS_ROUTE_MODEL_SHADOW=1` (default OFF). NEVER affects the live
|
|
14487
|
+
* decision — any failure increments the shadow-failure counter and is
|
|
14488
|
+
* logged, not thrown into the routing path.
|
|
14489
|
+
*
|
|
14490
|
+
* Tasks with a PINNED model (`CliTask.model`) are SKIPPED entirely: the
|
|
14491
|
+
* adapter executes the pinned model (base-adapter), not the CLI default the
|
|
14492
|
+
* comparison would otherwise assume, so a pinned run says nothing about the
|
|
14493
|
+
* tier selector — sampling it would mislabel the agree/diverge cohorts and
|
|
14494
|
+
* pad the volume criterion with garbage (#4218 review).
|
|
14495
|
+
*/
|
|
14496
|
+
trackModelSelectionShadow(task, decision) {
|
|
14497
|
+
try {
|
|
14498
|
+
if (!isRouteModelShadowEnabled() || decision.difficultyTier === void 0) return;
|
|
14499
|
+
if (task.model !== void 0) return;
|
|
14500
|
+
logModelSelectionReadinessOnce(this.logger);
|
|
14501
|
+
const comparison = computeModelSelectionShadow(
|
|
14502
|
+
routingArmDisplaySlot(decision.cliName),
|
|
14503
|
+
decision.difficultyTier,
|
|
14504
|
+
decision.model
|
|
14505
|
+
);
|
|
14506
|
+
this.pendingModelShadow = { ...comparison, taskContent: task.content };
|
|
14507
|
+
this.logger.debug("Model-selection shadow computed (#4197)", {
|
|
14508
|
+
cli: comparison.cli,
|
|
14509
|
+
tier: comparison.tier,
|
|
14510
|
+
actualModel: comparison.actualModel,
|
|
14511
|
+
shadowModel: comparison.shadowModel,
|
|
14512
|
+
agree: comparison.agree
|
|
14513
|
+
});
|
|
14514
|
+
} catch (error) {
|
|
14515
|
+
const failures = recordModelSelectionShadowFailure();
|
|
14516
|
+
this.logger.warn("Model-selection shadow failed (non-fatal, #4197)", {
|
|
14517
|
+
error: getErrorMessage(error),
|
|
14518
|
+
failures
|
|
14519
|
+
});
|
|
14520
|
+
}
|
|
14521
|
+
}
|
|
14522
|
+
/**
|
|
14523
|
+
* Join a pending model-selection shadow comparison with its task outcome and
|
|
14524
|
+
* persist the completed record (#4197). Matches by task content, mirroring
|
|
14525
|
+
* {@link getDifficultyInfo}'s lastRoutedTask join. `costUsd` is deliberately
|
|
14526
|
+
* absent: the routing outcome path measures no per-decision cost today, and
|
|
14527
|
+
* the readiness gate's cost criterion stays fail-closed until it does.
|
|
14528
|
+
* Exception-guarded — an outcome-join failure never breaks outcome recording.
|
|
14529
|
+
*/
|
|
14530
|
+
joinModelSelectionShadowOutcome(task, success) {
|
|
14531
|
+
const pending = this.pendingModelShadow;
|
|
14532
|
+
if (pending === void 0) return;
|
|
14533
|
+
if (pending.taskContent !== task.content) return;
|
|
14534
|
+
this.pendingModelShadow = void 0;
|
|
14535
|
+
try {
|
|
14536
|
+
persistModelSelectionShadowRecord({
|
|
14537
|
+
schema: MODEL_SELECTION_SHADOW_SCHEMA_VERSION,
|
|
14538
|
+
timestamp: new Date(getTimeProvider().now()).toISOString(),
|
|
14539
|
+
cli: pending.cli,
|
|
14540
|
+
tier: pending.tier,
|
|
14541
|
+
actualModel: pending.actualModel,
|
|
14542
|
+
shadowModel: pending.shadowModel,
|
|
14543
|
+
agree: pending.agree,
|
|
14544
|
+
success
|
|
14545
|
+
});
|
|
14546
|
+
} catch (error) {
|
|
14547
|
+
const failures = recordModelSelectionShadowFailure();
|
|
14548
|
+
this.logger.warn("Model-selection shadow outcome join failed (non-fatal, #4197)", {
|
|
14549
|
+
error: getErrorMessage(error),
|
|
14550
|
+
failures
|
|
14551
|
+
});
|
|
14552
|
+
}
|
|
14553
|
+
}
|
|
14296
14554
|
buildRoutingDecision(params) {
|
|
14297
14555
|
const selectedAdapter = this.adapters.get(params.selectedCli);
|
|
14298
14556
|
if (selectedAdapter === void 0) {
|
|
@@ -14373,6 +14631,7 @@ var CompositeRouter = class _CompositeRouter {
|
|
|
14373
14631
|
}
|
|
14374
14632
|
recordDifficultyOutcome(task, success, qualityScore) {
|
|
14375
14633
|
recordZeroRouterOutcome(task, success, qualityScore, this.getOutcomeDependencies());
|
|
14634
|
+
this.joinModelSelectionShadowOutcome(task, success);
|
|
14376
14635
|
}
|
|
14377
14636
|
hasMinimumPreferenceData() {
|
|
14378
14637
|
return hasMinimumPreferenceData(this.getOutcomeDependencies());
|
|
@@ -14503,7 +14762,7 @@ import { dirname as dirname5 } from "path";
|
|
|
14503
14762
|
import { mkdirSync as mkdirSync3 } from "fs";
|
|
14504
14763
|
|
|
14505
14764
|
// src/context/mobimem-types.ts
|
|
14506
|
-
import { z as
|
|
14765
|
+
import { z as z20 } from "zod";
|
|
14507
14766
|
var DEFAULT_MOBIMEM_CONFIG = {
|
|
14508
14767
|
dbPath: ":memory:",
|
|
14509
14768
|
maxProfileEntries: 100,
|
|
@@ -14515,15 +14774,15 @@ var DEFAULT_MOBIMEM_CONFIG = {
|
|
|
14515
14774
|
minExperienceSuccessRate: 0.7,
|
|
14516
14775
|
autoEviction: true
|
|
14517
14776
|
};
|
|
14518
|
-
var MobiMemConfigSchema =
|
|
14519
|
-
dbPath:
|
|
14520
|
-
maxProfileEntries:
|
|
14521
|
-
maxExperiencePatterns:
|
|
14522
|
-
maxActionCacheEntries:
|
|
14523
|
-
actionCacheTtlMs:
|
|
14524
|
-
minProfileConfidence:
|
|
14525
|
-
minExperienceSuccessRate:
|
|
14526
|
-
autoEviction:
|
|
14777
|
+
var MobiMemConfigSchema = z20.object({
|
|
14778
|
+
dbPath: z20.string(),
|
|
14779
|
+
maxProfileEntries: z20.number().int().positive().default(100),
|
|
14780
|
+
maxExperiencePatterns: z20.number().int().positive().default(500),
|
|
14781
|
+
maxActionCacheEntries: z20.number().int().positive().default(1e3),
|
|
14782
|
+
actionCacheTtlMs: z20.number().int().positive().default(36e5),
|
|
14783
|
+
minProfileConfidence: z20.number().min(0).max(1).default(0.6),
|
|
14784
|
+
minExperienceSuccessRate: z20.number().min(0).max(1).default(0.7),
|
|
14785
|
+
autoEviction: z20.boolean().default(true)
|
|
14527
14786
|
});
|
|
14528
14787
|
|
|
14529
14788
|
// src/context/mobimem-impl.ts
|
|
@@ -14543,9 +14802,9 @@ function generatePatternKey(taskType, actionSequence, contextSignature) {
|
|
|
14543
14802
|
function hashInput(input) {
|
|
14544
14803
|
return createHash2("sha256").update(JSON.stringify(input)).digest("hex");
|
|
14545
14804
|
}
|
|
14546
|
-
function calculatePatternScore(
|
|
14805
|
+
function calculatePatternScore(successRate3, contextMatches, attemptCount) {
|
|
14547
14806
|
const contextMatch = contextMatches ? 1 : 0.5;
|
|
14548
|
-
return
|
|
14807
|
+
return successRate3 * contextMatch * Math.log10(attemptCount + 1);
|
|
14549
14808
|
}
|
|
14550
14809
|
function computeSuccessRate(successCount, attemptCount) {
|
|
14551
14810
|
return attemptCount > 0 ? successCount / attemptCount : 0;
|
|
@@ -15588,4 +15847,4 @@ export {
|
|
|
15588
15847
|
AgentCapability,
|
|
15589
15848
|
OrchestratorError
|
|
15590
15849
|
};
|
|
15591
|
-
//# sourceMappingURL=chunk-
|
|
15850
|
+
//# sourceMappingURL=chunk-N6WRMZYA.js.map
|