@warmdrift/kgauto-compiler 2.0.0-alpha.77 → 2.0.0-alpha.79
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/{chunk-GB7VJQ6C.mjs → chunk-DRYCOR6G.mjs} +1 -1
- package/dist/{chunk-46U2NVOL.mjs → chunk-FT2FN6ZP.mjs} +13 -1
- package/dist/{chunk-N36LE3MK.mjs → chunk-VVRDFE6T.mjs} +16 -0
- package/dist/glassbox/index.d.mts +3 -3
- package/dist/glassbox/index.d.ts +3 -3
- package/dist/glassbox-routes/format.d.mts +2 -2
- package/dist/glassbox-routes/format.d.ts +2 -2
- package/dist/glassbox-routes/index.d.mts +4 -4
- package/dist/glassbox-routes/index.d.ts +4 -4
- package/dist/glassbox-routes/index.js +16 -0
- package/dist/glassbox-routes/index.mjs +2 -2
- package/dist/glassbox-routes/react/index.d.mts +2 -2
- package/dist/glassbox-routes/react/index.d.ts +2 -2
- package/dist/index.d.mts +300 -24
- package/dist/index.d.ts +300 -24
- package/dist/index.js +1485 -1033
- package/dist/index.mjs +1450 -1033
- package/dist/{ir-CRV1_taF.d.mts → ir-BFwWhj2s.d.mts} +51 -1
- package/dist/{ir-C02EIElQ.d.ts → ir-DZKS1tI7.d.ts} +51 -1
- package/dist/key-health.js +1 -1
- package/dist/key-health.mjs +1 -1
- package/dist/profiles.d.mts +12 -2
- package/dist/profiles.d.ts +12 -2
- package/dist/profiles.js +16 -0
- package/dist/profiles.mjs +1 -1
- package/dist/{types-C5BX9bzi.d.ts → types-B4kz3Vs0.d.ts} +1 -1
- package/dist/{types-CkRvjxrI.d.ts → types-D_fLt_Xv.d.ts} +1 -1
- package/dist/{types-Caq-hOIj.d.mts → types-DpcAMmk-.d.mts} +1 -1
- package/dist/{types-3WdGMqin.d.mts → types-hjzSWxtv.d.mts} +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -25,6 +25,7 @@ __export(index_exports, {
|
|
|
25
25
|
ALL_ARCHETYPES: () => ALL_ARCHETYPES,
|
|
26
26
|
ARCHETYPE_FAMILY_FITS: () => ARCHETYPE_FAMILY_FITS,
|
|
27
27
|
ARCHETYPE_FLOOR_DEFAULT: () => ARCHETYPE_FLOOR_DEFAULT,
|
|
28
|
+
BRAIN_READ_ENV_NAMES: () => BRAIN_READ_ENV_NAMES,
|
|
28
29
|
COACH_CFG: () => COACH_CFG,
|
|
29
30
|
CallError: () => CallError,
|
|
30
31
|
DECOMPOSITION_TEMPLATES: () => DECOMPOSITION_TEMPLATES,
|
|
@@ -32,6 +33,7 @@ __export(index_exports, {
|
|
|
32
33
|
DEFAULT_FINDINGS_ENDPOINT: () => DEFAULT_FINDINGS_ENDPOINT,
|
|
33
34
|
DEFAULT_MEASURED_FAILURE_ENDPOINT: () => DEFAULT_MEASURED_FAILURE_ENDPOINT,
|
|
34
35
|
DEFAULT_PROMOTIONS_ENDPOINT: () => DEFAULT_PROMOTIONS_ENDPOINT,
|
|
36
|
+
DELEGATE_TOOL_DEFINITION: () => DELEGATE_TOOL_DEFINITION,
|
|
35
37
|
DIALECT_VERSION: () => DIALECT_VERSION,
|
|
36
38
|
DISCIPLINE_GATES_V1_ALT_HEADER: () => DISCIPLINE_GATES_V1_ALT_HEADER,
|
|
37
39
|
FamilyResolutionError: () => FamilyResolutionError,
|
|
@@ -43,6 +45,7 @@ __export(index_exports, {
|
|
|
43
45
|
MEASURED_GROUNDING_MIN_N: () => MEASURED_GROUNDING_MIN_N,
|
|
44
46
|
PRODUCER_OWNED_RULE_CODES: () => PRODUCER_OWNED_RULE_CODES,
|
|
45
47
|
PROVIDER_ENV_KEYS: () => PROVIDER_ENV_KEYS,
|
|
48
|
+
ROLLBACK_SUPPRESSION_WINDOW_DAYS: () => ROLLBACK_SUPPRESSION_WINDOW_DAYS,
|
|
46
49
|
RULE_DISCIPLINE_GATES_V1: () => RULE_DISCIPLINE_GATES_V1,
|
|
47
50
|
RULE_DISCIPLINE_GATES_V1_STRUCTURED: () => RULE_DISCIPLINE_GATES_V1_STRUCTURED,
|
|
48
51
|
RULE_SEQUENTIAL_TOOL_CLIFF: () => RULE_SEQUENTIAL_TOOL_CLIFF,
|
|
@@ -78,6 +81,7 @@ __export(index_exports, {
|
|
|
78
81
|
configurePromotionsBrain: () => configurePromotionsBrain,
|
|
79
82
|
countTokens: () => countTokens,
|
|
80
83
|
createBrainForwardRoutes: () => createBrainForwardRoutes,
|
|
84
|
+
createDelegate: () => createDelegate,
|
|
81
85
|
createKeyHealthRoute: () => createKeyHealthRoute,
|
|
82
86
|
deriveFamilyFromModelId: () => deriveFamilyFromModelId,
|
|
83
87
|
deriveOwnership: () => deriveOwnership,
|
|
@@ -96,17 +100,20 @@ __export(index_exports, {
|
|
|
96
100
|
getPerAxisMetrics: () => getPerAxisMetrics,
|
|
97
101
|
getProfile: () => getProfile,
|
|
98
102
|
getReachabilityDiagnostic: () => getReachabilityDiagnostic,
|
|
103
|
+
getRecentRollback: () => getRecentRollback,
|
|
99
104
|
getRecommendedPrimary: () => getRecommendedPrimary,
|
|
100
105
|
getSequentialStarterChain: () => getSequentialStarterChain,
|
|
101
106
|
getSequentialStarterChainWithGrounding: () => getSequentialStarterChainWithGrounding,
|
|
102
107
|
getStaleExclusionFindings: () => getStaleExclusionFindings,
|
|
103
108
|
getStarterChain: () => getStarterChain,
|
|
104
109
|
getStarterChainWithGrounding: () => getStarterChainWithGrounding,
|
|
110
|
+
hasMutation: () => hasMutation,
|
|
105
111
|
hashShape: () => hashShape,
|
|
106
112
|
isArchetype: () => isArchetype,
|
|
107
113
|
isAutoPromoteEnabledFromEnv: () => isAutoPromoteEnabledFromEnv,
|
|
108
114
|
isBrainQueryActiveFor: () => isBrainQueryActiveFor,
|
|
109
115
|
isBrainSync: () => isBrainSync,
|
|
116
|
+
isDelegateEnabledFromEnv: () => isDelegateEnabledFromEnv,
|
|
110
117
|
isExclusionFindingsBrainActive: () => isExclusionFindingsBrainActive,
|
|
111
118
|
isMeasuredFailureBrainActive: () => isMeasuredFailureBrainActive,
|
|
112
119
|
isMeasuredFailureGateEnabledFromEnv: () => isMeasuredFailureGateEnabledFromEnv,
|
|
@@ -122,9 +129,11 @@ __export(index_exports, {
|
|
|
122
129
|
loadChainsFromBrain: () => loadChainsFromBrain,
|
|
123
130
|
loadModelsFromBrain: () => loadModelsFromBrain,
|
|
124
131
|
loadPricingFromBrain: () => loadPricingFromBrain,
|
|
132
|
+
mapMeasuredFailureRows: () => mapMeasuredFailureRows,
|
|
125
133
|
markAdvisoryResolved: () => markAdvisoryResolved,
|
|
126
134
|
markExclusionFindingHandled: () => markExclusionFindingHandled,
|
|
127
135
|
markPromoteReadyHandled: () => markPromoteReadyHandled,
|
|
136
|
+
mutationId: () => mutationId,
|
|
128
137
|
parseGoldenCaptureRate: () => parseGoldenCaptureRate,
|
|
129
138
|
parseJudgeVerdict: () => parseJudgeVerdict,
|
|
130
139
|
peekBrainDeadLetter: () => peekBrainDeadLetter,
|
|
@@ -693,6 +702,22 @@ var PROFILES_RAW = [
|
|
|
693
702
|
threshold: 16,
|
|
694
703
|
action: "drop_to_top_relevant",
|
|
695
704
|
reason: "Haiku reliability degrades above ~16 tools"
|
|
705
|
+
},
|
|
706
|
+
{
|
|
707
|
+
// alpha.78 — the declared `structuredOutput: 'grammar'` does NOT
|
|
708
|
+
// hold on long-input summarize. MEASURED (brain, playbacksam):
|
|
709
|
+
// 21 disambiguated `structured_output_parse_failed` fallover rows
|
|
710
|
+
// 2026-07-22..27, tokens_in 12,280–31,450; PB's gate counted 20/20
|
|
711
|
+
// in-window failures. Clean traffic p50 sits at ~9K tokens_in, so
|
|
712
|
+
// 12K gates the failing band without touching the working one.
|
|
713
|
+
// Short-input summarize carries no failure evidence and stays
|
|
714
|
+
// ungated — this is why it's a cliff, not an archetype-wide
|
|
715
|
+
// `structuredOutputHint: 'avoid'`.
|
|
716
|
+
metric: "input_tokens",
|
|
717
|
+
threshold: 12e3,
|
|
718
|
+
action: "quality_gate_structured",
|
|
719
|
+
whenIntent: "summarize",
|
|
720
|
+
reason: "Structured-output parse failures at 100% in-window on long-input summarize (measured on playbacksam, 2026-07-25..27; haiku only led when input size made price dominate, then failed every time)."
|
|
696
721
|
}
|
|
697
722
|
],
|
|
698
723
|
costInputPer1m: 1,
|
|
@@ -2939,11 +2964,18 @@ function passScoreTargets(ir, opts) {
|
|
|
2939
2964
|
}
|
|
2940
2965
|
}
|
|
2941
2966
|
let qualityGatePenalty = 0;
|
|
2967
|
+
let structuredCliffGate;
|
|
2942
2968
|
if (constraints.structuredOutput) {
|
|
2943
2969
|
const schemaWeak = effectiveConventions(profile).some(
|
|
2944
2970
|
(c) => c.archetype === ir.intent.archetype && c.structuredOutputHint === "avoid"
|
|
2945
2971
|
);
|
|
2946
2972
|
if (schemaWeak) qualityGatePenalty = QUALITY_GATE_PENALTY;
|
|
2973
|
+
if (!schemaWeak) {
|
|
2974
|
+
structuredCliffGate = profile.cliffs.find(
|
|
2975
|
+
(c) => c.action === "quality_gate_structured" && (!c.whenIntent || c.whenIntent === ir.intent.archetype) && c.metric === "input_tokens" && opts.estimatedInputTokens >= c.threshold
|
|
2976
|
+
);
|
|
2977
|
+
if (structuredCliffGate) qualityGatePenalty = QUALITY_GATE_PENALTY;
|
|
2978
|
+
}
|
|
2947
2979
|
}
|
|
2948
2980
|
const measuredGate = opts.measuredFailureGates?.get(modelId);
|
|
2949
2981
|
if (measuredGate) qualityGatePenalty = QUALITY_GATE_PENALTY;
|
|
@@ -3008,6 +3040,16 @@ function passScoreTargets(ir, opts) {
|
|
|
3008
3040
|
rankAfter: rank,
|
|
3009
3041
|
description: `Model ${modelId} gated below the quality floor for archetype '${ir.intent.archetype}' by MEASURED evidence from this app's own outcomes \u2014 ${measuredGate.nFail} of ${measuredGate.n} attempts failed on the quality axis in the trailing window (${pct(measuredGate.rate)}; 95% lower bound ${pct(measuredGate.lowerBound)} > 50%). Rank ${rankBefore.toFixed(2)} \u2192 ${rank.toFixed(2)} (\u2212${qualityGatePenalty.toFixed(2)}). Down-ranked out of leadership; retained as graceful fallback only. The gate is derived, not stored \u2014 it lifts on its own once the failures age out of the window.`
|
|
3010
3042
|
});
|
|
3043
|
+
} else if (structuredCliffGate) {
|
|
3044
|
+
policyMutations.push({
|
|
3045
|
+
id: `quality-gate-structured-cliff-${modelId}`,
|
|
3046
|
+
source: "quality_gate",
|
|
3047
|
+
passName: "score_targets",
|
|
3048
|
+
rankDelta: -qualityGatePenalty,
|
|
3049
|
+
rankBefore,
|
|
3050
|
+
rankAfter: rank,
|
|
3051
|
+
description: `Model ${modelId} gated below the quality floor for archetype '${ir.intent.archetype}' \u2014 declared structuredOutput + input_tokens \u2265 ${structuredCliffGate.threshold} trips a measured cliff: ${structuredCliffGate.reason} Rank ${rankBefore.toFixed(2)} \u2192 ${rank.toFixed(2)} (\u2212${qualityGatePenalty.toFixed(2)}). Down-ranked out of leadership; retained as graceful fallback only. Bundled knowledge \u2014 active on cold isolates with no brain.`
|
|
3052
|
+
});
|
|
3011
3053
|
} else {
|
|
3012
3054
|
policyMutations.push({
|
|
3013
3055
|
id: `quality-gate-structured-${modelId}`,
|
|
@@ -3691,13 +3733,8 @@ function getArchetypePerfScore(modelId, archetype) {
|
|
|
3691
3733
|
return { score, n, grounding };
|
|
3692
3734
|
}
|
|
3693
3735
|
|
|
3694
|
-
// src/
|
|
3695
|
-
function
|
|
3696
|
-
if (!x || typeof x !== "object") return false;
|
|
3697
|
-
const r = x;
|
|
3698
|
-
return typeof r.intent_archetype === "string" && typeof r.family === "string" && typeof r.candidate_model === "string" && typeof r.current_model === "string" && typeof r.detected_at === "string";
|
|
3699
|
-
}
|
|
3700
|
-
function coerceNumber(v) {
|
|
3736
|
+
// src/measured-failure-brain.ts
|
|
3737
|
+
function coerceCount(v) {
|
|
3701
3738
|
if (typeof v === "number") return Number.isFinite(v) ? v : null;
|
|
3702
3739
|
if (typeof v === "string") {
|
|
3703
3740
|
const n = Number(v);
|
|
@@ -3705,58 +3742,144 @@ function coerceNumber(v) {
|
|
|
3705
3742
|
}
|
|
3706
3743
|
return null;
|
|
3707
3744
|
}
|
|
3708
|
-
function
|
|
3745
|
+
function isRawFailureRow(x) {
|
|
3746
|
+
if (!x || typeof x !== "object") return false;
|
|
3747
|
+
const r = x;
|
|
3748
|
+
return typeof r.intent_archetype === "string" && typeof r.model === "string" && (typeof r.n === "number" || typeof r.n === "string");
|
|
3749
|
+
}
|
|
3750
|
+
function mapRows(rows) {
|
|
3709
3751
|
const out = [];
|
|
3710
3752
|
for (const row of rows) {
|
|
3711
|
-
if (!
|
|
3712
|
-
const
|
|
3713
|
-
const
|
|
3714
|
-
|
|
3715
|
-
if (sampleN === null || passRate === null || avgScore === null) continue;
|
|
3753
|
+
if (!isRawFailureRow(row)) continue;
|
|
3754
|
+
const n = coerceCount(row.n);
|
|
3755
|
+
const nFail = coerceCount(row.n_fail) ?? 0;
|
|
3756
|
+
if (n === null || n <= 0) continue;
|
|
3716
3757
|
out.push({
|
|
3717
3758
|
archetype: row.intent_archetype,
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
sampleN,
|
|
3722
|
-
judgePassRate: passRate,
|
|
3723
|
-
judgeAvgScore: avgScore,
|
|
3724
|
-
costDeltaPct: coerceNumber(row.cost_delta_pct),
|
|
3725
|
-
detectedAt: row.detected_at
|
|
3759
|
+
model: row.model,
|
|
3760
|
+
n,
|
|
3761
|
+
nFail
|
|
3726
3762
|
});
|
|
3727
3763
|
}
|
|
3728
3764
|
return out;
|
|
3729
3765
|
}
|
|
3766
|
+
var MEASURED_FAILURE_CFG = {
|
|
3767
|
+
/**
|
|
3768
|
+
* Hard minimum attempts before ANY gate may be created. Guards against
|
|
3769
|
+
* pathological tiny samples that the confidence bound alone would let
|
|
3770
|
+
* through in edge cases. At 5-for-5 the bound clears the threshold; at
|
|
3771
|
+
* 3-for-3 it does not, which is the behaviour we want (three failures is
|
|
3772
|
+
* a bad day, five in a row is a pattern).
|
|
3773
|
+
*/
|
|
3774
|
+
minSample: 5,
|
|
3775
|
+
/**
|
|
3776
|
+
* Gate when we are 95% confident the model fails MORE OFTEN THAN IT
|
|
3777
|
+
* SUCCEEDS on this surface. Deliberately unarguable rather than tuned —
|
|
3778
|
+
* a model that probably fails the majority of the time has no business
|
|
3779
|
+
* leading a surface, whatever its declared scores say.
|
|
3780
|
+
*/
|
|
3781
|
+
lowerBoundThreshold: 0.5,
|
|
3782
|
+
/** 95% one-sided-ish confidence (standard two-sided z at α=0.05). */
|
|
3783
|
+
z: 1.96,
|
|
3784
|
+
/** Must match the view's window. Documented here for the advisory text. */
|
|
3785
|
+
windowDays: 28
|
|
3786
|
+
};
|
|
3787
|
+
function wilsonLowerBound(failures, n, z = MEASURED_FAILURE_CFG.z) {
|
|
3788
|
+
if (n <= 0) return 0;
|
|
3789
|
+
const p = failures / n;
|
|
3790
|
+
const z2 = z * z;
|
|
3791
|
+
const denom = 1 + z2 / n;
|
|
3792
|
+
const centre = p + z2 / (2 * n);
|
|
3793
|
+
const margin = z * Math.sqrt(p * (1 - p) / n + z2 / (4 * n * n));
|
|
3794
|
+
const lower2 = (centre - margin) / denom;
|
|
3795
|
+
return lower2 < 0 ? 0 : lower2;
|
|
3796
|
+
}
|
|
3797
|
+
function mapMeasuredFailureRows(rows) {
|
|
3798
|
+
return mapRows(rows);
|
|
3799
|
+
}
|
|
3800
|
+
function judgeMeasuredFailure(row, cfg = MEASURED_FAILURE_CFG) {
|
|
3801
|
+
if (!row) return void 0;
|
|
3802
|
+
const normalized = "nFail" in row && typeof row.n === "number" ? row : mapRows([row])[0];
|
|
3803
|
+
if (!normalized || normalized.n < cfg.minSample) return void 0;
|
|
3804
|
+
const lowerBound = wilsonLowerBound(normalized.nFail, normalized.n, cfg.z);
|
|
3805
|
+
return {
|
|
3806
|
+
gated: lowerBound > cfg.lowerBoundThreshold,
|
|
3807
|
+
rate: normalized.nFail / normalized.n,
|
|
3808
|
+
lowerBound,
|
|
3809
|
+
n: normalized.n,
|
|
3810
|
+
nFail: normalized.nFail
|
|
3811
|
+
};
|
|
3812
|
+
}
|
|
3730
3813
|
var snapshots2 = /* @__PURE__ */ new Map();
|
|
3731
3814
|
var runtime3;
|
|
3732
3815
|
var warnedOnce2 = false;
|
|
3733
|
-
|
|
3816
|
+
var DEFAULT_MEASURED_FAILURE_ENDPOINT = "https://kgauto-dashboard.vercel.app/api/kgauto-v2/measured-failure";
|
|
3817
|
+
function isMeasuredFailureGateEnabledFromEnv(envSource) {
|
|
3818
|
+
const env = envSource ?? (typeof process !== "undefined" && process.env ? process.env : {});
|
|
3819
|
+
const raw = (env.KGAUTO_MEASURED_FAILURE_GATE ?? "").trim().toLowerCase();
|
|
3820
|
+
return !(raw === "0" || raw === "false");
|
|
3821
|
+
}
|
|
3822
|
+
function configureMeasuredFailureBrain(rt) {
|
|
3823
|
+
runtime3 = rt;
|
|
3824
|
+
snapshots2.clear();
|
|
3825
|
+
warnedOnce2 = false;
|
|
3826
|
+
}
|
|
3827
|
+
function isMeasuredFailureBrainActive() {
|
|
3734
3828
|
return runtime3 !== void 0;
|
|
3735
3829
|
}
|
|
3736
|
-
function
|
|
3830
|
+
function prefetchMeasuredFailure(appId) {
|
|
3737
3831
|
const rt = runtime3;
|
|
3738
|
-
if (!rt) return
|
|
3739
|
-
|
|
3740
|
-
if (!
|
|
3832
|
+
if (!rt || !appId) return void 0;
|
|
3833
|
+
let snap = snapshots2.get(appId);
|
|
3834
|
+
if (!snap) {
|
|
3835
|
+
snap = { data: [], expiresAt: 0, refreshing: false };
|
|
3836
|
+
snapshots2.set(appId, snap);
|
|
3837
|
+
}
|
|
3838
|
+
if (snap.expiresAt > Date.now()) return void 0;
|
|
3839
|
+
const inflight = pendingRefreshes2.get(appId);
|
|
3840
|
+
if (inflight) return inflight;
|
|
3841
|
+
if (snap.refreshing) return void 0;
|
|
3842
|
+
snap.refreshing = true;
|
|
3843
|
+
void asyncRefresh3(rt, appId);
|
|
3844
|
+
return pendingRefreshes2.get(appId);
|
|
3845
|
+
}
|
|
3846
|
+
async function awaitMeasuredFailureReady(appId, timeoutMs) {
|
|
3847
|
+
if (!runtime3 || !appId) return;
|
|
3848
|
+
const pending = prefetchMeasuredFailure(appId) ?? pendingRefreshes2.get(appId);
|
|
3849
|
+
if (!(timeoutMs > 0)) return;
|
|
3850
|
+
if (!pending) return;
|
|
3851
|
+
let timer;
|
|
3852
|
+
try {
|
|
3853
|
+
await Promise.race([
|
|
3854
|
+
pending,
|
|
3855
|
+
new Promise((resolve) => {
|
|
3856
|
+
timer = setTimeout(resolve, timeoutMs);
|
|
3857
|
+
})
|
|
3858
|
+
]);
|
|
3859
|
+
} catch {
|
|
3860
|
+
} finally {
|
|
3861
|
+
if (timer) clearTimeout(timer);
|
|
3862
|
+
}
|
|
3863
|
+
}
|
|
3864
|
+
function getMeasuredFailureVerdict(opts) {
|
|
3865
|
+
const rt = runtime3;
|
|
3866
|
+
if (!rt) return void 0;
|
|
3867
|
+
const { appId, archetype, model } = opts;
|
|
3868
|
+
if (!appId || !archetype || !model) return void 0;
|
|
3741
3869
|
let snap = snapshots2.get(appId);
|
|
3742
3870
|
if (!snap) {
|
|
3743
3871
|
snap = { data: [], expiresAt: 0, refreshing: false };
|
|
3744
3872
|
snapshots2.set(appId, snap);
|
|
3745
3873
|
}
|
|
3746
3874
|
const now = Date.now();
|
|
3747
|
-
|
|
3748
|
-
if (stale && !snap.refreshing) {
|
|
3875
|
+
if (snap.expiresAt <= now && !snap.refreshing) {
|
|
3749
3876
|
snap.refreshing = true;
|
|
3750
3877
|
void asyncRefresh3(rt, appId);
|
|
3751
3878
|
}
|
|
3752
|
-
|
|
3753
|
-
|
|
3754
|
-
|
|
3755
|
-
|
|
3756
|
-
if (opts.family) {
|
|
3757
|
-
rows = rows.filter((f) => f.family === opts.family);
|
|
3758
|
-
}
|
|
3759
|
-
return rows;
|
|
3879
|
+
const row = snap.data.find(
|
|
3880
|
+
(r) => r.archetype === archetype && r.model === model
|
|
3881
|
+
);
|
|
3882
|
+
return judgeMeasuredFailure(row);
|
|
3760
3883
|
}
|
|
3761
3884
|
var pendingRefreshes2 = /* @__PURE__ */ new Map();
|
|
3762
3885
|
async function asyncRefresh3(rt, appId) {
|
|
@@ -3780,12 +3903,11 @@ async function doRefresh3(rt, appId) {
|
|
|
3780
3903
|
try {
|
|
3781
3904
|
const res = await rt.fetchImpl(url, { method: "GET" });
|
|
3782
3905
|
if (!res.ok) {
|
|
3783
|
-
throw new Error(`
|
|
3906
|
+
throw new Error(`measured-failure ${res.status}: ${res.statusText}`);
|
|
3784
3907
|
}
|
|
3785
3908
|
const body = await res.json();
|
|
3786
3909
|
if (runtime3 !== rt) return;
|
|
3787
|
-
|
|
3788
|
-
snap.data = rows;
|
|
3910
|
+
snap.data = Array.isArray(body) ? mapRows(body) : [];
|
|
3789
3911
|
snap.expiresAt = Date.now() + rt.ttlMs;
|
|
3790
3912
|
snap.refreshing = false;
|
|
3791
3913
|
} catch (err) {
|
|
@@ -3800,193 +3922,84 @@ async function doRefresh3(rt, appId) {
|
|
|
3800
3922
|
}
|
|
3801
3923
|
function defaultOnError3(err) {
|
|
3802
3924
|
console.warn(
|
|
3803
|
-
"[kgauto]
|
|
3925
|
+
"[kgauto] measured-failure fetch failed (gate inactive until next refresh):",
|
|
3804
3926
|
err
|
|
3805
3927
|
);
|
|
3806
3928
|
}
|
|
3807
|
-
function
|
|
3808
|
-
|
|
3809
|
-
|
|
3810
|
-
|
|
3811
|
-
|
|
3929
|
+
function _testResetMeasuredFailure() {
|
|
3930
|
+
runtime3 = void 0;
|
|
3931
|
+
snapshots2.clear();
|
|
3932
|
+
pendingRefreshes2 = /* @__PURE__ */ new Map();
|
|
3933
|
+
warnedOnce2 = false;
|
|
3812
3934
|
}
|
|
3813
|
-
async function
|
|
3814
|
-
const
|
|
3815
|
-
|
|
3816
|
-
archetype,
|
|
3817
|
-
family,
|
|
3818
|
-
resolution,
|
|
3819
|
-
resolutionNote,
|
|
3820
|
-
brainEndpoint,
|
|
3821
|
-
brainJwt,
|
|
3822
|
-
brainAnonKey,
|
|
3823
|
-
fetch: injectedFetch
|
|
3824
|
-
} = opts;
|
|
3825
|
-
if (!appId) return { ok: false, reason: "app_id_required" };
|
|
3826
|
-
if (!archetype) return { ok: false, reason: "archetype_required" };
|
|
3827
|
-
if (!family) return { ok: false, reason: "family_required" };
|
|
3828
|
-
if (resolution !== "promoted" && resolution !== "declined" && resolution !== "still-evaluating") {
|
|
3829
|
-
return { ok: false, reason: "resolution_invalid" };
|
|
3830
|
-
}
|
|
3831
|
-
const doFetch = resolveFetchImpl(injectedFetch);
|
|
3832
|
-
const base = normalizeEndpoint(brainEndpoint);
|
|
3833
|
-
const url = `${base}/rest/v1/promote_ready_findings?app_id=eq.${encodeURIComponent(appId)}&intent_archetype=eq.${encodeURIComponent(archetype)}&family=eq.${encodeURIComponent(family)}&resolved_at=is.null`;
|
|
3834
|
-
const patchBody = {
|
|
3835
|
-
resolved_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3836
|
-
resolution
|
|
3837
|
-
};
|
|
3838
|
-
if (resolutionNote !== void 0) {
|
|
3839
|
-
patchBody.resolution_note = resolutionNote;
|
|
3840
|
-
}
|
|
3841
|
-
let res;
|
|
3842
|
-
try {
|
|
3843
|
-
res = await doFetch(url, {
|
|
3844
|
-
method: "PATCH",
|
|
3845
|
-
headers: {
|
|
3846
|
-
Authorization: `Bearer ${brainJwt}`,
|
|
3847
|
-
apikey: brainAnonKey,
|
|
3848
|
-
"Content-Type": "application/json",
|
|
3849
|
-
Accept: "application/json",
|
|
3850
|
-
Prefer: "return=minimal"
|
|
3851
|
-
},
|
|
3852
|
-
body: JSON.stringify(patchBody)
|
|
3853
|
-
});
|
|
3854
|
-
} catch (err) {
|
|
3855
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
3856
|
-
return { ok: false, reason: `network_error:${msg}` };
|
|
3857
|
-
}
|
|
3858
|
-
if (res.status === 401 || res.status === 403) {
|
|
3859
|
-
return { ok: false, reason: "brain_auth_misconfig" };
|
|
3860
|
-
}
|
|
3861
|
-
if (res.status >= 500) {
|
|
3862
|
-
return { ok: false, reason: "brain_unavailable" };
|
|
3863
|
-
}
|
|
3864
|
-
if (!res.ok) {
|
|
3865
|
-
return { ok: false, reason: `patch_failed:${res.status}` };
|
|
3866
|
-
}
|
|
3867
|
-
return { ok: true };
|
|
3935
|
+
async function _testWaitForMeasuredFailureRefresh() {
|
|
3936
|
+
const pending = Array.from(pendingRefreshes2.values());
|
|
3937
|
+
if (pending.length > 0) await Promise.all(pending);
|
|
3868
3938
|
}
|
|
3869
3939
|
|
|
3870
|
-
// src/
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
|
|
3874
|
-
|
|
3875
|
-
function shouldFirePromoteReady(finding, resolvedPrimary) {
|
|
3876
|
-
if (finding.currentModel !== resolvedPrimary) return false;
|
|
3877
|
-
if (finding.judgePassRate < PROMOTE_READY_THRESHOLDS.minPassRate) return false;
|
|
3878
|
-
if (finding.judgeAvgScore < PROMOTE_READY_THRESHOLDS.minAvgScore) return false;
|
|
3879
|
-
return true;
|
|
3940
|
+
// src/promotions-brain.ts
|
|
3941
|
+
function isRawPromotionRow(x) {
|
|
3942
|
+
if (!x || typeof x !== "object") return false;
|
|
3943
|
+
const r = x;
|
|
3944
|
+
return (typeof r.id === "number" || typeof r.id === "string") && typeof r.intent_archetype === "string" && typeof r.promoted_model === "string" && typeof r.incumbent_model === "string";
|
|
3880
3945
|
}
|
|
3881
|
-
function
|
|
3882
|
-
if (
|
|
3883
|
-
if (
|
|
3884
|
-
|
|
3885
|
-
|
|
3886
|
-
|
|
3887
|
-
if (/^gemini-.*-pro/.test(modelId)) return "gemini-pro";
|
|
3888
|
-
if (/^deepseek-.*-pro/.test(modelId)) return "deepseek-reasoner";
|
|
3889
|
-
if (modelId.startsWith("deepseek-")) return "deepseek-chat";
|
|
3890
|
-
if (modelId.startsWith("gpt-")) return "openai-gpt";
|
|
3946
|
+
function coerceId(v) {
|
|
3947
|
+
if (typeof v === "number") return Number.isFinite(v) ? v : null;
|
|
3948
|
+
if (typeof v === "string") {
|
|
3949
|
+
const n = Number(v);
|
|
3950
|
+
return Number.isFinite(n) ? n : null;
|
|
3951
|
+
}
|
|
3891
3952
|
return null;
|
|
3892
3953
|
}
|
|
3893
|
-
function
|
|
3894
|
-
if (!isPromoteReadyBrainActive()) return [];
|
|
3895
|
-
if (!ctx.appId) return [];
|
|
3896
|
-
if (!ctx.resolvedPrimary) return [];
|
|
3897
|
-
const family = deriveFamilyLocal(ctx.resolvedPrimary);
|
|
3898
|
-
if (!family) return [];
|
|
3899
|
-
const findings = loadPromoteReadyFindings({
|
|
3900
|
-
appId: ctx.appId,
|
|
3901
|
-
archetype: ctx.archetype,
|
|
3902
|
-
family
|
|
3903
|
-
});
|
|
3904
|
-
if (findings.length === 0) return [];
|
|
3905
|
-
const qualifying = findings.filter(
|
|
3906
|
-
(f) => shouldFirePromoteReady(f, ctx.resolvedPrimary)
|
|
3907
|
-
);
|
|
3908
|
-
if (qualifying.length === 0) return [];
|
|
3909
|
-
qualifying.sort((a, b) => {
|
|
3910
|
-
if (a.judgeAvgScore !== b.judgeAvgScore) {
|
|
3911
|
-
return b.judgeAvgScore - a.judgeAvgScore;
|
|
3912
|
-
}
|
|
3913
|
-
return b.judgePassRate - a.judgePassRate;
|
|
3914
|
-
});
|
|
3915
|
-
const top = qualifying[0];
|
|
3916
|
-
const pctPass = Math.round(top.judgePassRate * 100);
|
|
3917
|
-
const score = top.judgeAvgScore.toFixed(2);
|
|
3918
|
-
let costClause = "";
|
|
3919
|
-
if (top.costDeltaPct !== null) {
|
|
3920
|
-
const sign = top.costDeltaPct < 0 ? "cheaper" : "more expensive";
|
|
3921
|
-
const magnitude = Math.abs(top.costDeltaPct * 100).toFixed(1);
|
|
3922
|
-
costClause = `, cost ${magnitude}% ${sign}`;
|
|
3923
|
-
}
|
|
3924
|
-
const message = `Probe found ${top.candidateModel} produces equivalent-or-better outputs vs ${top.currentModel} on ${top.sampleN} recent ${top.archetype} prompts (pass rate ${pctPass}%, avg score ${score}/5${costClause}). Consider promoting via markPromoteReadyHandled.`;
|
|
3925
|
-
return [
|
|
3926
|
-
{
|
|
3927
|
-
level: "info",
|
|
3928
|
-
code: "promote-ready",
|
|
3929
|
-
message,
|
|
3930
|
-
suggestion: `Migrate ${top.archetype} traffic from ${top.currentModel} to ${top.candidateModel}, then call markPromoteReadyHandled({ appId, archetype: '${top.archetype}', family: '${top.family}', resolution: 'promoted' }) to silence this advisory.`,
|
|
3931
|
-
// alpha.36 architectural field — not a no-ai-needed case.
|
|
3932
|
-
recommendedArchitecture: void 0,
|
|
3933
|
-
docsUrl: "https://github.com/stue/command-center/blob/main/interfaces/kgauto.md#best-practice-advisories"
|
|
3934
|
-
}
|
|
3935
|
-
];
|
|
3936
|
-
}
|
|
3937
|
-
|
|
3938
|
-
// src/advisor-rules/consumer-on-stale-model.ts
|
|
3939
|
-
function isStaleStatus(v) {
|
|
3940
|
-
return v === "legacy" || v === "deprecated";
|
|
3941
|
-
}
|
|
3942
|
-
function asString(v) {
|
|
3943
|
-
return typeof v === "string" && v.length > 0 ? v : void 0;
|
|
3944
|
-
}
|
|
3945
|
-
function mapRowsToFindings3(rows) {
|
|
3954
|
+
function mapRowsToPromotions(rows) {
|
|
3946
3955
|
const out = [];
|
|
3947
|
-
for (const
|
|
3948
|
-
if (!
|
|
3949
|
-
const
|
|
3950
|
-
|
|
3951
|
-
const
|
|
3952
|
-
|
|
3953
|
-
|
|
3954
|
-
|
|
3955
|
-
|
|
3956
|
-
|
|
3957
|
-
|
|
3958
|
-
|
|
3959
|
-
|
|
3960
|
-
|
|
3961
|
-
|
|
3962
|
-
|
|
3963
|
-
|
|
3964
|
-
|
|
3965
|
-
|
|
3966
|
-
|
|
3967
|
-
|
|
3968
|
-
};
|
|
3969
|
-
const suggestion = asString(r.suggestion);
|
|
3970
|
-
if (suggestion) row.suggestion = suggestion;
|
|
3971
|
-
if (typeof r.observation_count === "number" && Number.isFinite(r.observation_count)) {
|
|
3972
|
-
row.observationCount = r.observation_count;
|
|
3973
|
-
}
|
|
3974
|
-
out.push(row);
|
|
3956
|
+
for (const row of rows) {
|
|
3957
|
+
if (!isRawPromotionRow(row)) continue;
|
|
3958
|
+
const id = coerceId(row.id);
|
|
3959
|
+
if (id === null) continue;
|
|
3960
|
+
const mode = row.mode === "strategy" ? "strategy" : row.mode === "downswap" || row.mode === void 0 ? "downswap" : null;
|
|
3961
|
+
if (mode === null) continue;
|
|
3962
|
+
out.push({
|
|
3963
|
+
id,
|
|
3964
|
+
archetype: row.intent_archetype,
|
|
3965
|
+
mode,
|
|
3966
|
+
strategy: typeof row.strategy === "string" ? row.strategy : null,
|
|
3967
|
+
promotedModel: row.promoted_model,
|
|
3968
|
+
incumbentModel: row.incumbent_model,
|
|
3969
|
+
evalRunId: coerceId(row.eval_run_id ?? null),
|
|
3970
|
+
suppressQualityGate: row.suppress_quality_gate === true,
|
|
3971
|
+
promotedAt: typeof row.promoted_at === "string" ? row.promoted_at : "",
|
|
3972
|
+
// Pre-.78 endpoints serve no status column and only active rows —
|
|
3973
|
+
// defaulting to 'active' is exact, not optimistic.
|
|
3974
|
+
status: row.status === "rolled_back" ? "rolled_back" : "active",
|
|
3975
|
+
...typeof row.rolled_back_at === "string" ? { rolledBackAt: row.rolled_back_at } : {},
|
|
3976
|
+
...typeof row.rollback_class === "string" ? { rollbackClass: row.rollback_class } : {}
|
|
3977
|
+
});
|
|
3975
3978
|
}
|
|
3976
3979
|
return out;
|
|
3977
3980
|
}
|
|
3978
3981
|
var snapshots3 = /* @__PURE__ */ new Map();
|
|
3979
3982
|
var runtime4;
|
|
3980
3983
|
var warnedOnce3 = false;
|
|
3981
|
-
var
|
|
3982
|
-
function
|
|
3984
|
+
var DEFAULT_PROMOTIONS_ENDPOINT = "https://kgauto-dashboard.vercel.app/api/kgauto-v2/promotions";
|
|
3985
|
+
function isAutoPromoteEnabledFromEnv(envSource) {
|
|
3986
|
+
const env = envSource ?? (typeof process !== "undefined" && process.env ? process.env : {});
|
|
3987
|
+
const raw = (env.KGAUTO_AUTO_PROMOTE ?? "").trim().toLowerCase();
|
|
3988
|
+
return raw === "1" || raw === "true";
|
|
3989
|
+
}
|
|
3990
|
+
function configurePromotionsBrain(rt) {
|
|
3991
|
+
runtime4 = rt;
|
|
3992
|
+
snapshots3.clear();
|
|
3993
|
+
warnedOnce3 = false;
|
|
3994
|
+
}
|
|
3995
|
+
function isPromotionsBrainActive() {
|
|
3983
3996
|
return runtime4 !== void 0;
|
|
3984
3997
|
}
|
|
3985
|
-
function
|
|
3998
|
+
function getApplicablePromotion(opts) {
|
|
3986
3999
|
const rt = runtime4;
|
|
3987
|
-
if (!rt) return
|
|
4000
|
+
if (!rt) return void 0;
|
|
3988
4001
|
const appId = opts.appId;
|
|
3989
|
-
if (!appId) return
|
|
4002
|
+
if (!appId || !opts.archetype || !opts.mode) return void 0;
|
|
3990
4003
|
let snap = snapshots3.get(appId);
|
|
3991
4004
|
if (!snap) {
|
|
3992
4005
|
snap = { data: [], expiresAt: 0, refreshing: false };
|
|
@@ -3998,11 +4011,31 @@ function getStaleModelFindings(opts) {
|
|
|
3998
4011
|
snap.refreshing = true;
|
|
3999
4012
|
void asyncRefresh4(rt, appId);
|
|
4000
4013
|
}
|
|
4001
|
-
|
|
4002
|
-
|
|
4014
|
+
return snap.data.find(
|
|
4015
|
+
(p) => p.status === "active" && p.archetype === opts.archetype && p.mode === opts.mode
|
|
4016
|
+
);
|
|
4017
|
+
}
|
|
4018
|
+
var ROLLBACK_SUPPRESSION_WINDOW_DAYS = 28;
|
|
4019
|
+
function getRecentRollback(opts) {
|
|
4020
|
+
const rt = runtime4;
|
|
4021
|
+
if (!rt) return void 0;
|
|
4022
|
+
if (!opts.appId || !opts.archetype || !opts.model) return void 0;
|
|
4023
|
+
let snap = snapshots3.get(opts.appId);
|
|
4024
|
+
if (!snap) {
|
|
4025
|
+
snap = { data: [], expiresAt: 0, refreshing: false };
|
|
4026
|
+
snapshots3.set(opts.appId, snap);
|
|
4003
4027
|
}
|
|
4004
|
-
|
|
4028
|
+
const now = opts.nowMs ?? Date.now();
|
|
4029
|
+
if (snap.expiresAt <= now && !snap.refreshing) {
|
|
4030
|
+
snap.refreshing = true;
|
|
4031
|
+
void asyncRefresh4(rt, opts.appId);
|
|
4032
|
+
}
|
|
4033
|
+
const windowMs = (opts.windowDays ?? ROLLBACK_SUPPRESSION_WINDOW_DAYS) * 864e5;
|
|
4034
|
+
return snap.data.find(
|
|
4035
|
+
(p) => p.status === "rolled_back" && p.archetype === opts.archetype && p.promotedModel === opts.model && typeof p.rolledBackAt === "string" && now - Date.parse(p.rolledBackAt) <= windowMs
|
|
4036
|
+
);
|
|
4005
4037
|
}
|
|
4038
|
+
var pendingRefreshes3 = /* @__PURE__ */ new Map();
|
|
4006
4039
|
async function asyncRefresh4(rt, appId) {
|
|
4007
4040
|
const promise = doRefresh4(rt, appId);
|
|
4008
4041
|
pendingRefreshes3.set(appId, promise);
|
|
@@ -4015,7 +4048,7 @@ async function asyncRefresh4(rt, appId) {
|
|
|
4015
4048
|
}
|
|
4016
4049
|
}
|
|
4017
4050
|
async function doRefresh4(rt, appId) {
|
|
4018
|
-
const url = `${rt.endpoint}?app_id=${encodeURIComponent(appId)}`;
|
|
4051
|
+
const url = `${rt.endpoint}?app_id=${encodeURIComponent(appId)}&with_rollbacks=1`;
|
|
4019
4052
|
let snap = snapshots3.get(appId);
|
|
4020
4053
|
if (!snap) {
|
|
4021
4054
|
snap = { data: [], expiresAt: 0, refreshing: false };
|
|
@@ -4024,11 +4057,11 @@ async function doRefresh4(rt, appId) {
|
|
|
4024
4057
|
try {
|
|
4025
4058
|
const res = await rt.fetchImpl(url, { method: "GET" });
|
|
4026
4059
|
if (!res.ok) {
|
|
4027
|
-
throw new Error(`
|
|
4060
|
+
throw new Error(`promotions ${res.status}: ${res.statusText}`);
|
|
4028
4061
|
}
|
|
4029
4062
|
const body = await res.json();
|
|
4030
4063
|
if (runtime4 !== rt) return;
|
|
4031
|
-
const rows = Array.isArray(body) ?
|
|
4064
|
+
const rows = Array.isArray(body) ? mapRowsToPromotions(body) : [];
|
|
4032
4065
|
snap.data = rows;
|
|
4033
4066
|
snap.expiresAt = Date.now() + rt.ttlMs;
|
|
4034
4067
|
snap.refreshing = false;
|
|
@@ -4044,847 +4077,905 @@ async function doRefresh4(rt, appId) {
|
|
|
4044
4077
|
}
|
|
4045
4078
|
function defaultOnError4(err) {
|
|
4046
4079
|
console.warn(
|
|
4047
|
-
"[kgauto]
|
|
4080
|
+
"[kgauto] promotions fetch failed (promotion boost inactive until next refresh):",
|
|
4048
4081
|
err
|
|
4049
4082
|
);
|
|
4050
4083
|
}
|
|
4051
|
-
|
|
4052
|
-
|
|
4053
|
-
|
|
4054
|
-
|
|
4055
|
-
|
|
4056
|
-
|
|
4057
|
-
|
|
4058
|
-
|
|
4059
|
-
if (
|
|
4060
|
-
const ranked = [...findings].sort((a, b) => {
|
|
4061
|
-
if (a.staleStatus !== b.staleStatus) {
|
|
4062
|
-
return a.staleStatus === "deprecated" ? -1 : 1;
|
|
4063
|
-
}
|
|
4064
|
-
return a.staleModel.localeCompare(b.staleModel);
|
|
4065
|
-
});
|
|
4066
|
-
const top = ranked[0];
|
|
4067
|
-
const extraCount = findings.length - 1;
|
|
4068
|
-
const extraNote = extraCount > 0 ? ` (+ ${extraCount} more stale model${extraCount === 1 ? "" : "s"} for this archetype)` : "";
|
|
4069
|
-
return [
|
|
4070
|
-
{
|
|
4071
|
-
level: "warn",
|
|
4072
|
-
code: CONSUMER_ON_STALE_MODEL_RULE_CODE,
|
|
4073
|
-
message: `${top.message}${extraNote}`,
|
|
4074
|
-
suggestion: top.suggestion ?? `Migrate ${top.staleModel} \u2192 ${top.recommendedModel} for archetype "${top.archetype}". The newer model is the current latest in the "${top.family}" family; the stale one is ${top.staleStatus}.`,
|
|
4075
|
-
recommendationType: "model-swap",
|
|
4076
|
-
docsUrl: "https://github.com/stue/command-center/blob/main/interfaces/kgauto.md#best-practice-advisories"
|
|
4077
|
-
}
|
|
4078
|
-
];
|
|
4084
|
+
function _testResetPromotions() {
|
|
4085
|
+
runtime4 = void 0;
|
|
4086
|
+
snapshots3.clear();
|
|
4087
|
+
pendingRefreshes3 = /* @__PURE__ */ new Map();
|
|
4088
|
+
warnedOnce3 = false;
|
|
4089
|
+
}
|
|
4090
|
+
async function _testWaitForPromotionsRefresh() {
|
|
4091
|
+
const pending = Array.from(pendingRefreshes3.values());
|
|
4092
|
+
if (pending.length > 0) await Promise.all(pending);
|
|
4079
4093
|
}
|
|
4080
4094
|
|
|
4081
|
-
// src/
|
|
4082
|
-
|
|
4083
|
-
|
|
4084
|
-
|
|
4085
|
-
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
{
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
reason: "Critique archetype rewards epistemic humility and explicit reasoning \u2014 reasoner-family default behavior. Sonnet/Opus over-confident on critique tasks; reasoners surface uncertainty productively.",
|
|
4093
|
-
costGuidance: "comparable or cheaper at current pricing"
|
|
4094
|
-
}
|
|
4095
|
-
]);
|
|
4096
|
-
function findBetterFit(archetype, currentFamily) {
|
|
4097
|
-
for (const fit of ARCHETYPE_FAMILY_FITS) {
|
|
4098
|
-
if (fit.archetype !== archetype) continue;
|
|
4099
|
-
if (fit.betterFitFamily === currentFamily) return null;
|
|
4100
|
-
return fit;
|
|
4095
|
+
// src/promote-ready-brain.ts
|
|
4096
|
+
function isRawPromoteReadyRow(x) {
|
|
4097
|
+
if (!x || typeof x !== "object") return false;
|
|
4098
|
+
const r = x;
|
|
4099
|
+
return typeof r.intent_archetype === "string" && typeof r.family === "string" && typeof r.candidate_model === "string" && typeof r.current_model === "string" && typeof r.detected_at === "string";
|
|
4100
|
+
}
|
|
4101
|
+
function coerceNumber(v) {
|
|
4102
|
+
if (typeof v === "number") return Number.isFinite(v) ? v : null;
|
|
4103
|
+
if (typeof v === "string") {
|
|
4104
|
+
const n = Number(v);
|
|
4105
|
+
return Number.isFinite(n) ? n : null;
|
|
4101
4106
|
}
|
|
4102
4107
|
return null;
|
|
4103
4108
|
}
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
const
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
if (
|
|
4112
|
-
|
|
4109
|
+
function mapRowsToFindings2(rows) {
|
|
4110
|
+
const out = [];
|
|
4111
|
+
for (const row of rows) {
|
|
4112
|
+
if (!isRawPromoteReadyRow(row)) continue;
|
|
4113
|
+
const sampleN = coerceNumber(row.sample_n);
|
|
4114
|
+
const passRate = coerceNumber(row.judge_pass_rate);
|
|
4115
|
+
const avgScore = coerceNumber(row.judge_avg_score);
|
|
4116
|
+
if (sampleN === null || passRate === null || avgScore === null) continue;
|
|
4117
|
+
out.push({
|
|
4118
|
+
archetype: row.intent_archetype,
|
|
4119
|
+
family: row.family,
|
|
4120
|
+
candidateModel: row.candidate_model,
|
|
4121
|
+
currentModel: row.current_model,
|
|
4122
|
+
sampleN,
|
|
4123
|
+
judgePassRate: passRate,
|
|
4124
|
+
judgeAvgScore: avgScore,
|
|
4125
|
+
costDeltaPct: coerceNumber(row.cost_delta_pct),
|
|
4126
|
+
detectedAt: row.detected_at
|
|
4127
|
+
});
|
|
4113
4128
|
}
|
|
4114
|
-
return
|
|
4129
|
+
return out;
|
|
4115
4130
|
}
|
|
4116
|
-
|
|
4117
|
-
|
|
4118
|
-
|
|
4119
|
-
|
|
4120
|
-
|
|
4121
|
-
if (profile.status !== "current") continue;
|
|
4122
|
-
if (profile.active === false) continue;
|
|
4123
|
-
candidates.push(profile.id);
|
|
4124
|
-
if (candidates.length >= 3) break;
|
|
4125
|
-
}
|
|
4126
|
-
return candidates;
|
|
4131
|
+
var snapshots4 = /* @__PURE__ */ new Map();
|
|
4132
|
+
var runtime5;
|
|
4133
|
+
var warnedOnce4 = false;
|
|
4134
|
+
function isPromoteReadyBrainActive() {
|
|
4135
|
+
return runtime5 !== void 0;
|
|
4127
4136
|
}
|
|
4128
|
-
function
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
|
|
4132
|
-
|
|
4133
|
-
|
|
4134
|
-
if (!
|
|
4135
|
-
|
|
4136
|
-
|
|
4137
|
-
|
|
4138
|
-
const
|
|
4139
|
-
|
|
4140
|
-
|
|
4141
|
-
|
|
4142
|
-
|
|
4143
|
-
|
|
4144
|
-
|
|
4145
|
-
|
|
4146
|
-
|
|
4147
|
-
|
|
4137
|
+
function loadPromoteReadyFindings(opts) {
|
|
4138
|
+
const rt = runtime5;
|
|
4139
|
+
if (!rt) return [];
|
|
4140
|
+
const appId = opts.appId;
|
|
4141
|
+
if (!appId) return [];
|
|
4142
|
+
let snap = snapshots4.get(appId);
|
|
4143
|
+
if (!snap) {
|
|
4144
|
+
snap = { data: [], expiresAt: 0, refreshing: false };
|
|
4145
|
+
snapshots4.set(appId, snap);
|
|
4146
|
+
}
|
|
4147
|
+
const now = Date.now();
|
|
4148
|
+
const stale = snap.expiresAt <= now;
|
|
4149
|
+
if (stale && !snap.refreshing) {
|
|
4150
|
+
snap.refreshing = true;
|
|
4151
|
+
void asyncRefresh5(rt, appId);
|
|
4152
|
+
}
|
|
4153
|
+
let rows = snap.data;
|
|
4154
|
+
if (opts.archetype) {
|
|
4155
|
+
rows = rows.filter((f) => f.archetype === opts.archetype);
|
|
4156
|
+
}
|
|
4157
|
+
if (opts.family) {
|
|
4158
|
+
rows = rows.filter((f) => f.family === opts.family);
|
|
4159
|
+
}
|
|
4160
|
+
return rows;
|
|
4161
|
+
}
|
|
4162
|
+
var pendingRefreshes4 = /* @__PURE__ */ new Map();
|
|
4163
|
+
async function asyncRefresh5(rt, appId) {
|
|
4164
|
+
const promise = doRefresh5(rt, appId);
|
|
4165
|
+
pendingRefreshes4.set(appId, promise);
|
|
4166
|
+
try {
|
|
4167
|
+
await promise;
|
|
4168
|
+
} finally {
|
|
4169
|
+
if (pendingRefreshes4.get(appId) === promise) {
|
|
4170
|
+
pendingRefreshes4.delete(appId);
|
|
4148
4171
|
}
|
|
4149
|
-
|
|
4172
|
+
}
|
|
4150
4173
|
}
|
|
4151
|
-
|
|
4152
|
-
|
|
4153
|
-
|
|
4154
|
-
|
|
4155
|
-
|
|
4156
|
-
|
|
4157
|
-
|
|
4158
|
-
|
|
4159
|
-
|
|
4160
|
-
|
|
4161
|
-
|
|
4174
|
+
async function doRefresh5(rt, appId) {
|
|
4175
|
+
const url = `${rt.endpoint}?app_id=${encodeURIComponent(appId)}`;
|
|
4176
|
+
let snap = snapshots4.get(appId);
|
|
4177
|
+
if (!snap) {
|
|
4178
|
+
snap = { data: [], expiresAt: 0, refreshing: false };
|
|
4179
|
+
snapshots4.set(appId, snap);
|
|
4180
|
+
}
|
|
4181
|
+
try {
|
|
4182
|
+
const res = await rt.fetchImpl(url, { method: "GET" });
|
|
4183
|
+
if (!res.ok) {
|
|
4184
|
+
throw new Error(`promote-ready ${res.status}: ${res.statusText}`);
|
|
4185
|
+
}
|
|
4186
|
+
const body = await res.json();
|
|
4187
|
+
if (runtime5 !== rt) return;
|
|
4188
|
+
const rows = Array.isArray(body) ? mapRowsToFindings2(body) : [];
|
|
4189
|
+
snap.data = rows;
|
|
4190
|
+
snap.expiresAt = Date.now() + rt.ttlMs;
|
|
4191
|
+
snap.refreshing = false;
|
|
4192
|
+
} catch (err) {
|
|
4193
|
+
if (runtime5 !== rt) return;
|
|
4194
|
+
snap.refreshing = false;
|
|
4195
|
+
snap.expiresAt = Date.now() + rt.ttlMs;
|
|
4196
|
+
if (!warnedOnce4) {
|
|
4197
|
+
warnedOnce4 = true;
|
|
4198
|
+
(rt.onError ?? defaultOnError5)(err);
|
|
4199
|
+
}
|
|
4200
|
+
}
|
|
4162
4201
|
}
|
|
4163
|
-
function
|
|
4164
|
-
|
|
4165
|
-
|
|
4166
|
-
|
|
4167
|
-
|
|
4168
|
-
|
|
4169
|
-
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
|
|
4173
|
-
|
|
4202
|
+
function defaultOnError5(err) {
|
|
4203
|
+
console.warn(
|
|
4204
|
+
"[kgauto] promote-ready fetch failed (using empty fallback):",
|
|
4205
|
+
err
|
|
4206
|
+
);
|
|
4207
|
+
}
|
|
4208
|
+
function resolveFetchImpl(injected) {
|
|
4209
|
+
return injected ?? ((...args) => globalThis.fetch(...args));
|
|
4210
|
+
}
|
|
4211
|
+
function normalizeEndpoint(endpoint) {
|
|
4212
|
+
return endpoint.replace(/\/+$/, "");
|
|
4213
|
+
}
|
|
4214
|
+
async function markPromoteReadyHandled(opts) {
|
|
4215
|
+
const {
|
|
4216
|
+
appId,
|
|
4217
|
+
archetype,
|
|
4218
|
+
family,
|
|
4219
|
+
resolution,
|
|
4220
|
+
resolutionNote,
|
|
4221
|
+
brainEndpoint,
|
|
4222
|
+
brainJwt,
|
|
4223
|
+
brainAnonKey,
|
|
4224
|
+
fetch: injectedFetch
|
|
4225
|
+
} = opts;
|
|
4226
|
+
if (!appId) return { ok: false, reason: "app_id_required" };
|
|
4227
|
+
if (!archetype) return { ok: false, reason: "archetype_required" };
|
|
4228
|
+
if (!family) return { ok: false, reason: "family_required" };
|
|
4229
|
+
if (resolution !== "promoted" && resolution !== "declined" && resolution !== "still-evaluating") {
|
|
4230
|
+
return { ok: false, reason: "resolution_invalid" };
|
|
4174
4231
|
}
|
|
4175
|
-
|
|
4176
|
-
|
|
4232
|
+
const doFetch = resolveFetchImpl(injectedFetch);
|
|
4233
|
+
const base = normalizeEndpoint(brainEndpoint);
|
|
4234
|
+
const url = `${base}/rest/v1/promote_ready_findings?app_id=eq.${encodeURIComponent(appId)}&intent_archetype=eq.${encodeURIComponent(archetype)}&family=eq.${encodeURIComponent(family)}&resolved_at=is.null`;
|
|
4235
|
+
const patchBody = {
|
|
4236
|
+
resolved_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4237
|
+
resolution
|
|
4238
|
+
};
|
|
4239
|
+
if (resolutionNote !== void 0) {
|
|
4240
|
+
patchBody.resolution_note = resolutionNote;
|
|
4177
4241
|
}
|
|
4178
|
-
|
|
4179
|
-
|
|
4242
|
+
let res;
|
|
4243
|
+
try {
|
|
4244
|
+
res = await doFetch(url, {
|
|
4245
|
+
method: "PATCH",
|
|
4246
|
+
headers: {
|
|
4247
|
+
Authorization: `Bearer ${brainJwt}`,
|
|
4248
|
+
apikey: brainAnonKey,
|
|
4249
|
+
"Content-Type": "application/json",
|
|
4250
|
+
Accept: "application/json",
|
|
4251
|
+
Prefer: "return=minimal"
|
|
4252
|
+
},
|
|
4253
|
+
body: JSON.stringify(patchBody)
|
|
4254
|
+
});
|
|
4255
|
+
} catch (err) {
|
|
4256
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
4257
|
+
return { ok: false, reason: `network_error:${msg}` };
|
|
4180
4258
|
}
|
|
4181
|
-
if (
|
|
4182
|
-
|
|
4183
|
-
...advisorRulePromoteReady({
|
|
4184
|
-
appId: ir.appId,
|
|
4185
|
-
archetype: ir.intent.archetype,
|
|
4186
|
-
resolvedPrimary: profile.id
|
|
4187
|
-
})
|
|
4188
|
-
);
|
|
4189
|
-
out.push(...advisorRuleConsumerOnStaleModel(ir));
|
|
4259
|
+
if (res.status === 401 || res.status === 403) {
|
|
4260
|
+
return { ok: false, reason: "brain_auth_misconfig" };
|
|
4190
4261
|
}
|
|
4191
|
-
if (
|
|
4192
|
-
|
|
4193
|
-
...advisorRuleCrossFamilyFit({
|
|
4194
|
-
archetype: ir.intent.archetype,
|
|
4195
|
-
resolvedPrimary: profile.id
|
|
4196
|
-
})
|
|
4197
|
-
);
|
|
4262
|
+
if (res.status >= 500) {
|
|
4263
|
+
return { ok: false, reason: "brain_unavailable" };
|
|
4198
4264
|
}
|
|
4199
|
-
|
|
4200
|
-
}
|
|
4201
|
-
function translatorClearedToolCallCliff(phase2) {
|
|
4202
|
-
const rewrites = phase2?.sectionRewritesApplied;
|
|
4203
|
-
if (!rewrites || rewrites.length === 0) return false;
|
|
4204
|
-
for (const rw of rewrites) {
|
|
4205
|
-
if (rw.kind === "tool_call_contract") return true;
|
|
4265
|
+
if (!res.ok) {
|
|
4266
|
+
return { ok: false, reason: `patch_failed:${res.status}` };
|
|
4206
4267
|
}
|
|
4207
|
-
return
|
|
4268
|
+
return { ok: true };
|
|
4208
4269
|
}
|
|
4209
|
-
|
|
4210
|
-
|
|
4211
|
-
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
|
|
4270
|
+
|
|
4271
|
+
// src/advisor-rules/promote-ready.ts
|
|
4272
|
+
var PROMOTE_READY_THRESHOLDS = {
|
|
4273
|
+
minPassRate: 0.8,
|
|
4274
|
+
minAvgScore: 4
|
|
4275
|
+
};
|
|
4276
|
+
function shouldFirePromoteReady(finding, resolvedPrimary) {
|
|
4277
|
+
if (finding.currentModel !== resolvedPrimary) return false;
|
|
4278
|
+
if (finding.judgePassRate < PROMOTE_READY_THRESHOLDS.minPassRate) return false;
|
|
4279
|
+
if (finding.judgeAvgScore < PROMOTE_READY_THRESHOLDS.minAvgScore) return false;
|
|
4280
|
+
return true;
|
|
4281
|
+
}
|
|
4282
|
+
function deriveFamilyLocal(modelId) {
|
|
4283
|
+
if (modelId.startsWith("claude-opus-")) return "claude-opus";
|
|
4284
|
+
if (modelId.startsWith("claude-sonnet-")) return "claude-sonnet";
|
|
4285
|
+
if (modelId.startsWith("claude-haiku-")) return "claude-haiku";
|
|
4286
|
+
if (/^gemini-.*-flash-lite/.test(modelId)) return "gemini-flash-lite";
|
|
4287
|
+
if (/^gemini-.*-flash/.test(modelId)) return "gemini-flash";
|
|
4288
|
+
if (/^gemini-.*-pro/.test(modelId)) return "gemini-pro";
|
|
4289
|
+
if (/^deepseek-.*-pro/.test(modelId)) return "deepseek-reasoner";
|
|
4290
|
+
if (modelId.startsWith("deepseek-")) return "deepseek-chat";
|
|
4291
|
+
if (modelId.startsWith("gpt-")) return "openai-gpt";
|
|
4292
|
+
return null;
|
|
4293
|
+
}
|
|
4294
|
+
function advisorRulePromoteReady(ctx) {
|
|
4295
|
+
if (!isPromoteReadyBrainActive()) return [];
|
|
4296
|
+
if (!ctx.appId) return [];
|
|
4297
|
+
if (!ctx.resolvedPrimary) return [];
|
|
4298
|
+
const family = deriveFamilyLocal(ctx.resolvedPrimary);
|
|
4299
|
+
if (!family) return [];
|
|
4300
|
+
const findings = loadPromoteReadyFindings({
|
|
4301
|
+
appId: ctx.appId,
|
|
4302
|
+
archetype: ctx.archetype,
|
|
4303
|
+
family
|
|
4304
|
+
});
|
|
4305
|
+
if (findings.length === 0) return [];
|
|
4306
|
+
const qualifying = findings.filter(
|
|
4307
|
+
(f) => shouldFirePromoteReady(f, ctx.resolvedPrimary)
|
|
4308
|
+
);
|
|
4309
|
+
if (qualifying.length === 0) return [];
|
|
4310
|
+
qualifying.sort((a, b) => {
|
|
4311
|
+
if (a.judgeAvgScore !== b.judgeAvgScore) {
|
|
4312
|
+
return b.judgeAvgScore - a.judgeAvgScore;
|
|
4313
|
+
}
|
|
4314
|
+
return b.judgePassRate - a.judgePassRate;
|
|
4315
|
+
});
|
|
4316
|
+
const top = qualifying[0];
|
|
4317
|
+
const pctPass = Math.round(top.judgePassRate * 100);
|
|
4318
|
+
const score = top.judgeAvgScore.toFixed(2);
|
|
4319
|
+
let costClause = "";
|
|
4320
|
+
if (top.costDeltaPct !== null) {
|
|
4321
|
+
const sign = top.costDeltaPct < 0 ? "cheaper" : "more expensive";
|
|
4322
|
+
const magnitude = Math.abs(top.costDeltaPct * 100).toFixed(1);
|
|
4323
|
+
costClause = `, cost ${magnitude}% ${sign}`;
|
|
4324
|
+
}
|
|
4325
|
+
const message = `Probe found ${top.candidateModel} produces equivalent-or-better outputs vs ${top.currentModel} on ${top.sampleN} recent ${top.archetype} prompts (pass rate ${pctPass}%, avg score ${score}/5${costClause}). Consider promoting via markPromoteReadyHandled.`;
|
|
4215
4326
|
return [
|
|
4216
4327
|
{
|
|
4217
|
-
level: "
|
|
4218
|
-
code: "
|
|
4219
|
-
message
|
|
4220
|
-
suggestion:
|
|
4328
|
+
level: "info",
|
|
4329
|
+
code: "promote-ready",
|
|
4330
|
+
message,
|
|
4331
|
+
suggestion: `Migrate ${top.archetype} traffic from ${top.currentModel} to ${top.candidateModel}, then call markPromoteReadyHandled({ appId, archetype: '${top.archetype}', family: '${top.family}', resolution: 'promoted' }) to silence this advisory.`,
|
|
4332
|
+
// alpha.36 architectural field — not a no-ai-needed case.
|
|
4333
|
+
recommendedArchitecture: void 0,
|
|
4221
4334
|
docsUrl: "https://github.com/stue/command-center/blob/main/interfaces/kgauto.md#best-practice-advisories"
|
|
4222
4335
|
}
|
|
4223
4336
|
];
|
|
4224
4337
|
}
|
|
4225
|
-
|
|
4226
|
-
|
|
4227
|
-
|
|
4228
|
-
|
|
4229
|
-
if (!only || only.text.length <= 1e3) return [];
|
|
4230
|
-
return [
|
|
4231
|
-
{
|
|
4232
|
-
level: "info",
|
|
4233
|
-
code: "single-chunk-system",
|
|
4234
|
-
message: `System prompt is a single ${only.text.length}-char chunk. Splitting into NamedChunks (static role/persona vs dynamic context) gives the lowering pass a finer cache-marker boundary \u2014 only the static portion needs to be byte-stable for the cache to hit.`,
|
|
4235
|
-
suggestion: "Refactor the system builder to return an array of `PromptSection` shaped { id, text, cacheable?: boolean }. Static chunks (role, persona, tool policy) get `cacheable: true`; dynamic ones (current context, today's date) don't.",
|
|
4236
|
-
docsUrl: "https://github.com/stue/command-center/blob/main/interfaces/kgauto.md#best-practice-advisories"
|
|
4237
|
-
}
|
|
4238
|
-
];
|
|
4338
|
+
|
|
4339
|
+
// src/advisor-rules/consumer-on-stale-model.ts
|
|
4340
|
+
function isStaleStatus(v) {
|
|
4341
|
+
return v === "legacy" || v === "deprecated";
|
|
4239
4342
|
}
|
|
4240
|
-
function
|
|
4241
|
-
|
|
4242
|
-
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
|
|
4246
|
-
"
|
|
4247
|
-
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
message: `${toolsKept} tools kept after the relevance pass for archetype="${ir.intent.archetype}" (consumer declared ${ir.tools.length}). This archetype is short-output and rarely needs more than 3 tools; each tool definition eats ~350 tokens of context budget.`,
|
|
4257
|
-
suggestion: "Tighten `relevanceByIntent: { [archetype]: 0..1 }` per ToolDefinition. Tools below `toolRelevanceThreshold` (default 0.2) get dropped. Without `relevanceByIntent`, every tool defaults to neutral (0.5) and stays.",
|
|
4258
|
-
docsUrl: "https://github.com/stue/kgauto/blob/main/v2/README.md#tools"
|
|
4343
|
+
function asString(v) {
|
|
4344
|
+
return typeof v === "string" && v.length > 0 ? v : void 0;
|
|
4345
|
+
}
|
|
4346
|
+
function mapRowsToFindings3(rows) {
|
|
4347
|
+
const out = [];
|
|
4348
|
+
for (const raw of rows) {
|
|
4349
|
+
if (!raw || typeof raw !== "object") continue;
|
|
4350
|
+
const r = raw;
|
|
4351
|
+
const archetype = asString(r.intent_archetype) ?? asString(r.applies_to_archetype);
|
|
4352
|
+
const staleModel = asString(r.stale_model) ?? asString(r.applies_to_model);
|
|
4353
|
+
const staleProvider = asString(r.stale_provider);
|
|
4354
|
+
const recommendedModel = asString(r.recommended_model);
|
|
4355
|
+
const family = asString(r.family);
|
|
4356
|
+
const message = asString(r.message);
|
|
4357
|
+
if (!archetype || !staleModel || !recommendedModel || !family || !message) {
|
|
4358
|
+
continue;
|
|
4259
4359
|
}
|
|
4260
|
-
|
|
4360
|
+
if (!isStaleStatus(r.stale_status)) continue;
|
|
4361
|
+
const row = {
|
|
4362
|
+
archetype,
|
|
4363
|
+
staleModel,
|
|
4364
|
+
staleProvider: staleProvider ?? "unknown",
|
|
4365
|
+
staleStatus: r.stale_status,
|
|
4366
|
+
recommendedModel,
|
|
4367
|
+
family,
|
|
4368
|
+
message
|
|
4369
|
+
};
|
|
4370
|
+
const suggestion = asString(r.suggestion);
|
|
4371
|
+
if (suggestion) row.suggestion = suggestion;
|
|
4372
|
+
if (typeof r.observation_count === "number" && Number.isFinite(r.observation_count)) {
|
|
4373
|
+
row.observationCount = r.observation_count;
|
|
4374
|
+
}
|
|
4375
|
+
out.push(row);
|
|
4376
|
+
}
|
|
4377
|
+
return out;
|
|
4261
4378
|
}
|
|
4262
|
-
|
|
4263
|
-
|
|
4264
|
-
|
|
4265
|
-
|
|
4266
|
-
|
|
4379
|
+
var snapshots5 = /* @__PURE__ */ new Map();
|
|
4380
|
+
var runtime6;
|
|
4381
|
+
var warnedOnce5 = false;
|
|
4382
|
+
var pendingRefreshes5 = /* @__PURE__ */ new Map();
|
|
4383
|
+
function isStaleModelFindingsBrainActive() {
|
|
4384
|
+
return runtime6 !== void 0;
|
|
4385
|
+
}
|
|
4386
|
+
function getStaleModelFindings(opts) {
|
|
4387
|
+
const rt = runtime6;
|
|
4388
|
+
if (!rt) return [];
|
|
4389
|
+
const appId = opts.appId;
|
|
4390
|
+
if (!appId) return [];
|
|
4391
|
+
let snap = snapshots5.get(appId);
|
|
4392
|
+
if (!snap) {
|
|
4393
|
+
snap = { data: [], expiresAt: 0, refreshing: false };
|
|
4394
|
+
snapshots5.set(appId, snap);
|
|
4267
4395
|
}
|
|
4268
|
-
|
|
4269
|
-
|
|
4270
|
-
|
|
4271
|
-
|
|
4272
|
-
|
|
4273
|
-
|
|
4274
|
-
|
|
4275
|
-
|
|
4276
|
-
|
|
4396
|
+
const now = Date.now();
|
|
4397
|
+
const stale = snap.expiresAt <= now;
|
|
4398
|
+
if (stale && !snap.refreshing) {
|
|
4399
|
+
snap.refreshing = true;
|
|
4400
|
+
void asyncRefresh6(rt, appId);
|
|
4401
|
+
}
|
|
4402
|
+
if (opts.archetype) {
|
|
4403
|
+
return snap.data.filter((f) => f.archetype === opts.archetype);
|
|
4404
|
+
}
|
|
4405
|
+
return snap.data;
|
|
4277
4406
|
}
|
|
4278
|
-
function
|
|
4279
|
-
|
|
4280
|
-
|
|
4281
|
-
|
|
4282
|
-
|
|
4283
|
-
|
|
4284
|
-
|
|
4285
|
-
|
|
4286
|
-
message: `\`ir.models\` has length 1 (only "${only}") and posture is not 'locked'. A single-model chain has no safety net \u2014 the first 429 / 5xx / cliff hits the user as a failure. Master plan \xA71.2 closes the reliability gap with a 2-step minimum.`,
|
|
4287
|
-
suggestion: "Use `getDefaultFallbackChain({ archetype: ir.intent.archetype, primary: '" + only + "', posture: 'preferred' })` for a user-anchored chain, or `getDefaultFallbackChain({ archetype, posture: 'open' })` for library-picked. If single-model is intentional (compliance/brand promise), set `policy.posture = 'locked'` to silence this rule.",
|
|
4288
|
-
docsUrl: "https://github.com/stue/command-center/blob/main/interfaces/kgauto.md#single-model-array"
|
|
4407
|
+
async function asyncRefresh6(rt, appId) {
|
|
4408
|
+
const promise = doRefresh6(rt, appId);
|
|
4409
|
+
pendingRefreshes5.set(appId, promise);
|
|
4410
|
+
try {
|
|
4411
|
+
await promise;
|
|
4412
|
+
} finally {
|
|
4413
|
+
if (pendingRefreshes5.get(appId) === promise) {
|
|
4414
|
+
pendingRefreshes5.delete(appId);
|
|
4289
4415
|
}
|
|
4290
|
-
|
|
4416
|
+
}
|
|
4291
4417
|
}
|
|
4292
|
-
function
|
|
4293
|
-
|
|
4294
|
-
|
|
4295
|
-
|
|
4296
|
-
|
|
4297
|
-
|
|
4298
|
-
if (!chosenHasRoomToGrow) return [];
|
|
4299
|
-
let bestAlt = null;
|
|
4300
|
-
for (const altId of phase2.fallbackChain) {
|
|
4301
|
-
const altProfile = phase2.profileResolver(altId);
|
|
4302
|
-
if (!altProfile) continue;
|
|
4303
|
-
if (altProfile.id === profile.id) continue;
|
|
4304
|
-
const altScore = getArchetypePerfScore(altProfile.id, archetype);
|
|
4305
|
-
if (altScore.score < QUALITY_FLOOR_FOR_RECOMMENDATION) continue;
|
|
4306
|
-
if (altScore.score < chosenScore.score) continue;
|
|
4307
|
-
if (altProfile.costInputPer1m >= profile.costInputPer1m) continue;
|
|
4308
|
-
if (!bestAlt || altScore.score > bestAlt.score.score || altScore.score === bestAlt.score.score && altProfile.costInputPer1m < bestAlt.profile.costInputPer1m) {
|
|
4309
|
-
bestAlt = { id: altId, profile: altProfile, score: altScore };
|
|
4310
|
-
}
|
|
4418
|
+
async function doRefresh6(rt, appId) {
|
|
4419
|
+
const url = `${rt.endpoint}?app_id=${encodeURIComponent(appId)}`;
|
|
4420
|
+
let snap = snapshots5.get(appId);
|
|
4421
|
+
if (!snap) {
|
|
4422
|
+
snap = { data: [], expiresAt: 0, refreshing: false };
|
|
4423
|
+
snapshots5.set(appId, snap);
|
|
4311
4424
|
}
|
|
4312
|
-
|
|
4313
|
-
|
|
4314
|
-
|
|
4315
|
-
|
|
4316
|
-
const altGrounding = bestAlt.score.grounding === "measured" ? `archetypePerf.${archetype}=${bestAlt.score.score}, measured, n=${bestAlt.score.n}` : `archetypePerf.${archetype}=${bestAlt.score.score}, judgment`;
|
|
4317
|
-
return [
|
|
4318
|
-
{
|
|
4319
|
-
level: "warn",
|
|
4320
|
-
code: "cost-mismatched-archetype",
|
|
4321
|
-
message: `Cost-mismatched-archetype: target=${profile.id} (${chosenGrounding}) selected for ${archetype}. Alternative ${bestAlt.id} (${altGrounding}) is cheaper ($${bestAlt.profile.costInputPer1m}/$${bestAlt.profile.costOutputPer1m} vs $${profile.costInputPer1m}/$${profile.costOutputPer1m} per 1M) at equal-or-better quality.`,
|
|
4322
|
-
suggestion: `Consider declaring \`${bestAlt.id}\` as the primary model for this archetype, or relax to posture='open' to let kgauto select among the chain. If the chosen model is required for compliance/brand reasons, set \`policy.posture = 'locked'\` to silence this rule.`,
|
|
4323
|
-
recommendationType: profile.provider === bestAlt.profile.provider ? "tier-down" : "model-swap",
|
|
4324
|
-
docsUrl: "https://github.com/stue/command-center/blob/main/interfaces/kgauto.md#best-practice-advisories"
|
|
4425
|
+
try {
|
|
4426
|
+
const res = await rt.fetchImpl(url, { method: "GET" });
|
|
4427
|
+
if (!res.ok) {
|
|
4428
|
+
throw new Error(`stale-model findings ${res.status}: ${res.statusText}`);
|
|
4325
4429
|
}
|
|
4326
|
-
|
|
4327
|
-
|
|
4328
|
-
|
|
4329
|
-
|
|
4330
|
-
|
|
4331
|
-
|
|
4332
|
-
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
recommendationType: "prompt-fix",
|
|
4340
|
-
docsUrl: "https://github.com/stue/command-center/blob/main/interfaces/kgauto.md#best-practice-advisories"
|
|
4430
|
+
const body = await res.json();
|
|
4431
|
+
if (runtime6 !== rt) return;
|
|
4432
|
+
const rows = Array.isArray(body) ? mapRowsToFindings3(body) : [];
|
|
4433
|
+
snap.data = rows;
|
|
4434
|
+
snap.expiresAt = Date.now() + rt.ttlMs;
|
|
4435
|
+
snap.refreshing = false;
|
|
4436
|
+
} catch (err) {
|
|
4437
|
+
if (runtime6 !== rt) return;
|
|
4438
|
+
snap.refreshing = false;
|
|
4439
|
+
snap.expiresAt = Date.now() + rt.ttlMs;
|
|
4440
|
+
if (!warnedOnce5) {
|
|
4441
|
+
warnedOnce5 = true;
|
|
4442
|
+
(rt.onError ?? defaultOnError6)(err);
|
|
4341
4443
|
}
|
|
4342
|
-
|
|
4444
|
+
}
|
|
4343
4445
|
}
|
|
4344
|
-
function
|
|
4345
|
-
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
|
|
4349
|
-
|
|
4350
|
-
|
|
4351
|
-
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
|
|
4357
|
-
|
|
4358
|
-
|
|
4359
|
-
|
|
4360
|
-
if (
|
|
4361
|
-
|
|
4446
|
+
function defaultOnError6(err) {
|
|
4447
|
+
console.warn(
|
|
4448
|
+
"[kgauto] stale-model findings fetch failed (using empty fallback):",
|
|
4449
|
+
err
|
|
4450
|
+
);
|
|
4451
|
+
}
|
|
4452
|
+
var CONSUMER_ON_STALE_MODEL_RULE_CODE = "consumer-on-stale-model";
|
|
4453
|
+
function advisorRuleConsumerOnStaleModel(ir) {
|
|
4454
|
+
if (!isStaleModelFindingsBrainActive()) return [];
|
|
4455
|
+
if (!ir.appId) return [];
|
|
4456
|
+
const findings = getStaleModelFindings({
|
|
4457
|
+
appId: ir.appId,
|
|
4458
|
+
archetype: ir.intent.archetype
|
|
4459
|
+
});
|
|
4460
|
+
if (findings.length === 0) return [];
|
|
4461
|
+
const ranked = [...findings].sort((a, b) => {
|
|
4462
|
+
if (a.staleStatus !== b.staleStatus) {
|
|
4463
|
+
return a.staleStatus === "deprecated" ? -1 : 1;
|
|
4362
4464
|
}
|
|
4363
|
-
|
|
4364
|
-
|
|
4365
|
-
const
|
|
4465
|
+
return a.staleModel.localeCompare(b.staleModel);
|
|
4466
|
+
});
|
|
4467
|
+
const top = ranked[0];
|
|
4468
|
+
const extraCount = findings.length - 1;
|
|
4469
|
+
const extraNote = extraCount > 0 ? ` (+ ${extraCount} more stale model${extraCount === 1 ? "" : "s"} for this archetype)` : "";
|
|
4366
4470
|
return [
|
|
4367
4471
|
{
|
|
4368
4472
|
level: "warn",
|
|
4369
|
-
code:
|
|
4370
|
-
message:
|
|
4371
|
-
suggestion: `
|
|
4372
|
-
recommendationType: "
|
|
4473
|
+
code: CONSUMER_ON_STALE_MODEL_RULE_CODE,
|
|
4474
|
+
message: `${top.message}${extraNote}`,
|
|
4475
|
+
suggestion: top.suggestion ?? `Migrate ${top.staleModel} \u2192 ${top.recommendedModel} for archetype "${top.archetype}". The newer model is the current latest in the "${top.family}" family; the stale one is ${top.staleStatus}.`,
|
|
4476
|
+
recommendationType: "model-swap",
|
|
4373
4477
|
docsUrl: "https://github.com/stue/command-center/blob/main/interfaces/kgauto.md#best-practice-advisories"
|
|
4374
4478
|
}
|
|
4375
4479
|
];
|
|
4376
4480
|
}
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
|
|
4380
|
-
|
|
4381
|
-
|
|
4382
|
-
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
|
|
4388
|
-
|
|
4389
|
-
|
|
4390
|
-
|
|
4391
|
-
|
|
4392
|
-
|
|
4393
|
-
|
|
4394
|
-
|
|
4481
|
+
|
|
4482
|
+
// src/archetype-fits.ts
|
|
4483
|
+
var ARCHETYPE_FAMILY_FITS = Object.freeze([
|
|
4484
|
+
{
|
|
4485
|
+
archetype: "plan",
|
|
4486
|
+
betterFitFamily: "deepseek-reasoner",
|
|
4487
|
+
reason: "Plan archetype is reasoning-shaped (multi-step chains, hypothesis-and-check, sub-goal decomposition) \u2014 exactly where reasoner-family models excel. Sonnet/Opus produce plans but at higher cost; reasoners produce equivalent-or-better plans at 7-17x lower cost at current promo pricing (deepseek-v4-pro $0.435/$0.87 per 1M promo through 2026-05-31 vs sonnet $3/$15).",
|
|
4488
|
+
costGuidance: "substantially cheaper at current pricing (deepseek-v4-pro promo: ~7-17x cheaper than sonnet)"
|
|
4489
|
+
},
|
|
4490
|
+
{
|
|
4491
|
+
archetype: "critique",
|
|
4492
|
+
betterFitFamily: "deepseek-reasoner",
|
|
4493
|
+
reason: "Critique archetype rewards epistemic humility and explicit reasoning \u2014 reasoner-family default behavior. Sonnet/Opus over-confident on critique tasks; reasoners surface uncertainty productively.",
|
|
4494
|
+
costGuidance: "comparable or cheaper at current pricing"
|
|
4495
|
+
}
|
|
4496
|
+
]);
|
|
4497
|
+
function findBetterFit(archetype, currentFamily) {
|
|
4498
|
+
for (const fit of ARCHETYPE_FAMILY_FITS) {
|
|
4499
|
+
if (fit.archetype !== archetype) continue;
|
|
4500
|
+
if (fit.betterFitFamily === currentFamily) return null;
|
|
4501
|
+
return fit;
|
|
4395
4502
|
}
|
|
4503
|
+
return null;
|
|
4504
|
+
}
|
|
4505
|
+
|
|
4506
|
+
// src/advisor-rules/cross-family-fit.ts
|
|
4507
|
+
function familyHasCurrentActiveModel(family) {
|
|
4508
|
+
for (const profile of allProfiles()) {
|
|
4509
|
+
const profileFamily = profile.family ?? deriveFamilyFromModelId(profile.id);
|
|
4510
|
+
if (profileFamily !== family) continue;
|
|
4511
|
+
if (profile.status !== "current") continue;
|
|
4512
|
+
if (profile.active === false) continue;
|
|
4513
|
+
return true;
|
|
4514
|
+
}
|
|
4515
|
+
return false;
|
|
4516
|
+
}
|
|
4517
|
+
function listCandidatesInFamily(family) {
|
|
4518
|
+
const candidates = [];
|
|
4519
|
+
for (const profile of allProfiles()) {
|
|
4520
|
+
const profileFamily = profile.family ?? deriveFamilyFromModelId(profile.id);
|
|
4521
|
+
if (profileFamily !== family) continue;
|
|
4522
|
+
if (profile.status !== "current") continue;
|
|
4523
|
+
if (profile.active === false) continue;
|
|
4524
|
+
candidates.push(profile.id);
|
|
4525
|
+
if (candidates.length >= 3) break;
|
|
4526
|
+
}
|
|
4527
|
+
return candidates;
|
|
4528
|
+
}
|
|
4529
|
+
function advisorRuleCrossFamilyFit(ctx) {
|
|
4530
|
+
if (!ctx.resolvedPrimary) return [];
|
|
4531
|
+
const currentFamily = deriveFamilyFromModelId(ctx.resolvedPrimary);
|
|
4532
|
+
if (!currentFamily) return [];
|
|
4533
|
+
const fit = findBetterFit(ctx.archetype, currentFamily);
|
|
4534
|
+
if (!fit) return [];
|
|
4535
|
+
if (!familyHasCurrentActiveModel(fit.betterFitFamily)) return [];
|
|
4536
|
+
const candidates = listCandidatesInFamily(fit.betterFitFamily);
|
|
4537
|
+
if (candidates.length === 0) return [];
|
|
4538
|
+
const candidateStr = candidates.join(", ");
|
|
4539
|
+
const message = `Your ${currentFamily} call on ${ctx.archetype} could shift to ${fit.betterFitFamily} \u2014 typically better quality + ${fit.costGuidance}. Suggested candidates: ${candidateStr}.`;
|
|
4396
4540
|
return [
|
|
4397
4541
|
{
|
|
4398
|
-
level: "
|
|
4399
|
-
code: "
|
|
4400
|
-
|
|
4401
|
-
|
|
4542
|
+
level: "info",
|
|
4543
|
+
code: "cross-family-fit-candidate",
|
|
4544
|
+
ownership: "consumer-actionable",
|
|
4545
|
+
message,
|
|
4546
|
+
suggestion: `Swap the model literal in \`ir.models\` to one of: ${candidateStr}. Or call \`getRecommendedPrimary({ family: '${fit.betterFitFamily}', archetype: '${ctx.archetype}', fallback: { id: '${candidates[0]}', reason: 'cross-family-fit-recommendation' } })\` to let kgauto resolve to the current+active family member.`,
|
|
4402
4547
|
recommendationType: "model-swap",
|
|
4403
4548
|
docsUrl: "https://github.com/stue/command-center/blob/main/interfaces/kgauto.md#best-practice-advisories"
|
|
4404
4549
|
}
|
|
4405
4550
|
];
|
|
4406
4551
|
}
|
|
4407
|
-
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
|
|
4411
|
-
|
|
4412
|
-
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
|
|
4421
|
-
|
|
4422
|
-
|
|
4423
|
-
|
|
4552
|
+
|
|
4553
|
+
// src/advisor.ts
|
|
4554
|
+
var QUALITY_FLOOR_FOR_RECOMMENDATION = 6;
|
|
4555
|
+
var TIER_DOWN_COST_RATIO = 0.5;
|
|
4556
|
+
var COST_MISMATCHED_CHOSEN_SCORE_CEILING = 7;
|
|
4557
|
+
var PRODUCER_OWNED_RULE_CODES = Object.freeze(
|
|
4558
|
+
/* @__PURE__ */ new Set(["model-stale-evidence", "promote-ready"])
|
|
4559
|
+
);
|
|
4560
|
+
function deriveOwnership(code, selfDeclared) {
|
|
4561
|
+
if (selfDeclared) return selfDeclared;
|
|
4562
|
+
return PRODUCER_OWNED_RULE_CODES.has(code) ? "producer-owned" : "consumer-actionable";
|
|
4563
|
+
}
|
|
4564
|
+
function runAdvisor(ir, result, profile, policy, phase2) {
|
|
4565
|
+
const out = [];
|
|
4566
|
+
out.push(...detectCachingOff(ir, profile));
|
|
4567
|
+
out.push(...detectSingleChunkSystem(ir, profile));
|
|
4568
|
+
out.push(...detectToolBloat(ir, result));
|
|
4569
|
+
out.push(...detectHistoryUncached(ir, profile));
|
|
4570
|
+
out.push(...detectSingleModelArray(ir, policy));
|
|
4571
|
+
if (policy?.posture !== "locked") {
|
|
4572
|
+
out.push(...detectCostMismatchedArchetype(ir, profile, phase2));
|
|
4573
|
+
out.push(...detectModelStaleEvidence(ir, profile));
|
|
4574
|
+
out.push(...detectTierDown(ir, profile, phase2));
|
|
4575
|
+
}
|
|
4576
|
+
if (!translatorClearedToolCallCliff(phase2)) {
|
|
4577
|
+
out.push(...detectArchetypePerfFloorBreach(ir, profile));
|
|
4578
|
+
}
|
|
4579
|
+
if (policy?.posture !== "locked") {
|
|
4580
|
+
out.push(...detectStaleExclusionCandidate(ir));
|
|
4581
|
+
}
|
|
4582
|
+
if (policy?.posture !== "locked" && ir.appId) {
|
|
4583
|
+
out.push(
|
|
4584
|
+
...advisorRulePromoteReady({
|
|
4585
|
+
appId: ir.appId,
|
|
4586
|
+
archetype: ir.intent.archetype,
|
|
4587
|
+
resolvedPrimary: profile.id
|
|
4588
|
+
})
|
|
4589
|
+
);
|
|
4590
|
+
out.push(...advisorRuleConsumerOnStaleModel(ir));
|
|
4591
|
+
}
|
|
4592
|
+
if (policy?.posture !== "locked") {
|
|
4593
|
+
out.push(
|
|
4594
|
+
...advisorRuleCrossFamilyFit({
|
|
4595
|
+
archetype: ir.intent.archetype,
|
|
4596
|
+
resolvedPrimary: profile.id
|
|
4597
|
+
})
|
|
4598
|
+
);
|
|
4599
|
+
}
|
|
4600
|
+
return out;
|
|
4601
|
+
}
|
|
4602
|
+
function translatorClearedToolCallCliff(phase2) {
|
|
4603
|
+
const rewrites = phase2?.sectionRewritesApplied;
|
|
4604
|
+
if (!rewrites || rewrites.length === 0) return false;
|
|
4605
|
+
for (const rw of rewrites) {
|
|
4606
|
+
if (rw.kind === "tool_call_contract") return true;
|
|
4607
|
+
}
|
|
4608
|
+
return false;
|
|
4609
|
+
}
|
|
4610
|
+
function detectCachingOff(ir, profile) {
|
|
4611
|
+
if (profile.provider !== "anthropic") return [];
|
|
4612
|
+
const totalChars = ir.sections.reduce((s, sec) => s + sec.text.length, 0);
|
|
4613
|
+
if (totalChars < 2e3) return [];
|
|
4614
|
+
const anyCacheable = ir.sections.some((s) => s.cacheable === true);
|
|
4615
|
+
if (anyCacheable) return [];
|
|
4424
4616
|
return [
|
|
4425
4617
|
{
|
|
4426
|
-
level: "
|
|
4427
|
-
code: "
|
|
4428
|
-
message:
|
|
4429
|
-
suggestion:
|
|
4430
|
-
recommendationType: "tier-down",
|
|
4618
|
+
level: "warn",
|
|
4619
|
+
code: "caching-off-on-claude",
|
|
4620
|
+
message: `System prompt is ${totalChars} chars on Anthropic but no PromptSection has cacheable=true. Anthropic prompt caching cuts cached-prefix input cost by ~90% on subsequent calls; without it, every turn re-pays full price for the static system context.`,
|
|
4621
|
+
suggestion: "Mark stable system sections (role, persona, tool policy) with `cacheable: true`. The lowering pass concatenates cacheable sections into a single cache-controlled block before the dynamic ones.",
|
|
4431
4622
|
docsUrl: "https://github.com/stue/command-center/blob/main/interfaces/kgauto.md#best-practice-advisories"
|
|
4432
4623
|
}
|
|
4433
4624
|
];
|
|
4434
4625
|
}
|
|
4435
|
-
function
|
|
4436
|
-
if (
|
|
4437
|
-
if (
|
|
4438
|
-
|
|
4626
|
+
function detectSingleChunkSystem(ir, profile) {
|
|
4627
|
+
if (profile.provider !== "anthropic") return [];
|
|
4628
|
+
if (ir.sections.length !== 1) return [];
|
|
4629
|
+
const only = ir.sections[0];
|
|
4630
|
+
if (!only || only.text.length <= 1e3) return [];
|
|
4631
|
+
return [
|
|
4632
|
+
{
|
|
4633
|
+
level: "info",
|
|
4634
|
+
code: "single-chunk-system",
|
|
4635
|
+
message: `System prompt is a single ${only.text.length}-char chunk. Splitting into NamedChunks (static role/persona vs dynamic context) gives the lowering pass a finer cache-marker boundary \u2014 only the static portion needs to be byte-stable for the cache to hit.`,
|
|
4636
|
+
suggestion: "Refactor the system builder to return an array of `PromptSection` shaped { id, text, cacheable?: boolean }. Static chunks (role, persona, tool policy) get `cacheable: true`; dynamic ones (current context, today's date) don't. NOTE: the lowering pass HOISTS cacheable sections ahead of dynamic ones on the Anthropic wire (prefix caching requires it) \u2014 if your prompt has a protected ordering (e.g. a voice/persona block that must precede boilerplate), splitting will reorder the compiled output; declining this advisory is then correct. Also: a cacheable block under ~1024 tokens gets NO cache_control marker (provider minimum), so marking small sections is inert, not harmful.",
|
|
4637
|
+
docsUrl: "https://github.com/stue/command-center/blob/main/interfaces/kgauto.md#best-practice-advisories"
|
|
4638
|
+
}
|
|
4639
|
+
];
|
|
4439
4640
|
}
|
|
4440
|
-
|
|
4441
|
-
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
|
|
4447
|
-
|
|
4448
|
-
|
|
4449
|
-
|
|
4450
|
-
|
|
4451
|
-
|
|
4452
|
-
|
|
4453
|
-
|
|
4454
|
-
|
|
4455
|
-
|
|
4456
|
-
|
|
4457
|
-
|
|
4458
|
-
|
|
4459
|
-
2. One extra signal: when a finding feels conclusive, check one more adjacent signal before stating it.
|
|
4460
|
-
3. Innocent explanation first: state the most plausible benign reading before alleging the alarming one.
|
|
4461
|
-
4. Label each claim: mark it observed, inferred, or assumed.
|
|
4462
|
-
5. A surfaced gap beats a guessed answer: flag what you cannot determine rather than fabricating past it.`;
|
|
4463
|
-
var RULE_DISCIPLINE_GATES_V1_STRUCTURED = "discipline-gates-v1-structured";
|
|
4464
|
-
var DISCIPLINE_GATES_V1_STRUCTURED_WITH_TOOLS = `Work through these gates at every judgment point, explicitly:
|
|
4465
|
-
1. Evidence before reasoning: cite what you observed before concluding from it.
|
|
4466
|
-
2. One extra signal: when a finding feels conclusive, check one more adjacent signal before stating it.
|
|
4467
|
-
3. Expand, don't guess: resolve a compressed or referenced item by looking it up rather than inferring its contents.
|
|
4468
|
-
4. Innocent explanation first: state the most plausible benign reading before alleging the alarming one.`;
|
|
4469
|
-
var DISCIPLINE_GATES_V1_STRUCTURED_NO_TOOLS = `Work through these gates at every judgment point, explicitly:
|
|
4470
|
-
1. Evidence before reasoning: cite what you observed before concluding from it.
|
|
4471
|
-
2. One extra signal: when a finding feels conclusive, check one more adjacent signal before stating it.
|
|
4472
|
-
3. Innocent explanation first: state the most plausible benign reading before alleging the alarming one.`;
|
|
4473
|
-
var DISCIPLINE_ELIGIBLE_ARCHETYPES = /* @__PURE__ */ new Set([
|
|
4474
|
-
"hunt",
|
|
4475
|
-
"summarize",
|
|
4476
|
-
"plan",
|
|
4477
|
-
"critique",
|
|
4478
|
-
"judge"
|
|
4479
|
-
]);
|
|
4480
|
-
function matchRule(kind, profile, archetype, ctx) {
|
|
4481
|
-
if (kind === "discipline_contract") {
|
|
4482
|
-
if (!DISCIPLINE_ELIGIBLE_ARCHETYPES.has(archetype)) return null;
|
|
4483
|
-
if (ctx.outputMode !== "text") {
|
|
4484
|
-
return {
|
|
4485
|
-
id: RULE_DISCIPLINE_GATES_V1_STRUCTURED,
|
|
4486
|
-
preamble: ctx.hasTools ? DISCIPLINE_GATES_V1_STRUCTURED_WITH_TOOLS : DISCIPLINE_GATES_V1_STRUCTURED_NO_TOOLS
|
|
4487
|
-
};
|
|
4641
|
+
function detectToolBloat(ir, result) {
|
|
4642
|
+
const SHORT_OUTPUT = /* @__PURE__ */ new Set([
|
|
4643
|
+
"classify",
|
|
4644
|
+
"extract",
|
|
4645
|
+
"summarize",
|
|
4646
|
+
"transform",
|
|
4647
|
+
"critique"
|
|
4648
|
+
]);
|
|
4649
|
+
if (!ir.tools || ir.tools.length === 0) return [];
|
|
4650
|
+
const toolsKept = result.diagnostics.toolsKept;
|
|
4651
|
+
if (toolsKept <= 10) return [];
|
|
4652
|
+
if (!SHORT_OUTPUT.has(ir.intent.archetype)) return [];
|
|
4653
|
+
return [
|
|
4654
|
+
{
|
|
4655
|
+
level: "warn",
|
|
4656
|
+
code: "tool-bloat",
|
|
4657
|
+
message: `${toolsKept} tools kept after the relevance pass for archetype="${ir.intent.archetype}" (consumer declared ${ir.tools.length}). This archetype is short-output and rarely needs more than 3 tools; each tool definition eats ~350 tokens of context budget.`,
|
|
4658
|
+
suggestion: "Tighten `relevanceByIntent: { [archetype]: 0..1 }` per ToolDefinition. Tools below `toolRelevanceThreshold` (default 0.2) get dropped. Without `relevanceByIntent`, every tool defaults to neutral (0.5) and stays.",
|
|
4659
|
+
docsUrl: "https://github.com/stue/kgauto/blob/main/v2/README.md#tools"
|
|
4488
4660
|
}
|
|
4489
|
-
|
|
4490
|
-
|
|
4491
|
-
|
|
4492
|
-
|
|
4661
|
+
];
|
|
4662
|
+
}
|
|
4663
|
+
function detectHistoryUncached(ir, profile) {
|
|
4664
|
+
if (profile.provider !== "anthropic") return [];
|
|
4665
|
+
if (!ir.history || ir.history.length < 2) return [];
|
|
4666
|
+
if (ir.historyCachePolicy && ir.historyCachePolicy.strategy !== "none") {
|
|
4667
|
+
return [];
|
|
4493
4668
|
}
|
|
4494
|
-
|
|
4495
|
-
|
|
4496
|
-
|
|
4497
|
-
|
|
4498
|
-
|
|
4669
|
+
return [
|
|
4670
|
+
{
|
|
4671
|
+
level: "warn",
|
|
4672
|
+
code: "history-uncached-on-claude",
|
|
4673
|
+
message: `${ir.history.length} history messages on Anthropic with no historyCachePolicy. Every turn re-pays for the full conversation context; with caching, subsequent turns hit the cache at ~10% the input cost.`,
|
|
4674
|
+
suggestion: "Set `historyCachePolicy: { strategy: 'all-but-latest' }` on this IR. The lowering pass marks the message immediately preceding currentTurn with cache_control; subsequent turns whose history prefix matches byte-for-byte hit the cache.",
|
|
4675
|
+
docsUrl: "https://github.com/stue/command-center/blob/main/interfaces/kgauto.md#best-practice-advisories"
|
|
4499
4676
|
}
|
|
4500
|
-
|
|
4501
|
-
|
|
4502
|
-
|
|
4503
|
-
|
|
4504
|
-
|
|
4505
|
-
|
|
4506
|
-
|
|
4507
|
-
|
|
4508
|
-
|
|
4509
|
-
|
|
4510
|
-
|
|
4511
|
-
}
|
|
4677
|
+
];
|
|
4678
|
+
}
|
|
4679
|
+
function detectSingleModelArray(ir, policy) {
|
|
4680
|
+
if (ir.models.length !== 1) return [];
|
|
4681
|
+
if (policy?.posture === "locked") return [];
|
|
4682
|
+
const only = ir.models[0];
|
|
4683
|
+
return [
|
|
4684
|
+
{
|
|
4685
|
+
level: "warn",
|
|
4686
|
+
code: "single-model-array",
|
|
4687
|
+
message: `\`ir.models\` has length 1 (only "${only}") and posture is not 'locked'. A single-model chain has no safety net \u2014 the first 429 / 5xx / cliff hits the user as a failure. Master plan \xA71.2 closes the reliability gap with a 2-step minimum.`,
|
|
4688
|
+
suggestion: "Use `getDefaultFallbackChain({ archetype: ir.intent.archetype, primary: '" + only + "', posture: 'preferred' })` for a user-anchored chain, or `getDefaultFallbackChain({ archetype, posture: 'open' })` for library-picked. If single-model is intentional (compliance/brand promise), set `policy.posture = 'locked'` to silence this rule.",
|
|
4689
|
+
docsUrl: "https://github.com/stue/command-center/blob/main/interfaces/kgauto.md#single-model-array"
|
|
4512
4690
|
}
|
|
4513
|
-
|
|
4514
|
-
|
|
4515
|
-
|
|
4516
|
-
|
|
4517
|
-
|
|
4691
|
+
];
|
|
4692
|
+
}
|
|
4693
|
+
function detectCostMismatchedArchetype(ir, profile, phase2) {
|
|
4694
|
+
if (!phase2 || phase2.fallbackChain.length === 0) return [];
|
|
4695
|
+
if (!phase2.profileResolver) return [];
|
|
4696
|
+
const archetype = ir.intent.archetype;
|
|
4697
|
+
const chosenScore = getArchetypePerfScore(profile.id, archetype);
|
|
4698
|
+
const chosenHasRoomToGrow = chosenScore.grounding === "judgment" || chosenScore.score < COST_MISMATCHED_CHOSEN_SCORE_CEILING;
|
|
4699
|
+
if (!chosenHasRoomToGrow) return [];
|
|
4700
|
+
let bestAlt = null;
|
|
4701
|
+
for (const altId of phase2.fallbackChain) {
|
|
4702
|
+
const altProfile = phase2.profileResolver(altId);
|
|
4703
|
+
if (!altProfile) continue;
|
|
4704
|
+
if (altProfile.id === profile.id) continue;
|
|
4705
|
+
const altScore = getArchetypePerfScore(altProfile.id, archetype);
|
|
4706
|
+
if (altScore.score < QUALITY_FLOOR_FOR_RECOMMENDATION) continue;
|
|
4707
|
+
if (altScore.score < chosenScore.score) continue;
|
|
4708
|
+
if (altProfile.costInputPer1m >= profile.costInputPer1m) continue;
|
|
4709
|
+
if (getMeasuredFailureVerdict({
|
|
4710
|
+
appId: ir.appId,
|
|
4711
|
+
archetype,
|
|
4712
|
+
model: altProfile.id
|
|
4713
|
+
})?.gated === true) {
|
|
4714
|
+
continue;
|
|
4715
|
+
}
|
|
4716
|
+
if (ir.constraints?.structuredOutput && effectiveConventions(altProfile).some(
|
|
4717
|
+
(c) => c.archetype === archetype && c.structuredOutputHint === "avoid"
|
|
4718
|
+
)) {
|
|
4719
|
+
continue;
|
|
4720
|
+
}
|
|
4721
|
+
if (getRecentRollback({
|
|
4722
|
+
appId: ir.appId,
|
|
4723
|
+
archetype,
|
|
4724
|
+
model: altProfile.id
|
|
4725
|
+
}) !== void 0) {
|
|
4726
|
+
continue;
|
|
4727
|
+
}
|
|
4728
|
+
if (!bestAlt || altScore.score > bestAlt.score.score || altScore.score === bestAlt.score.score && altProfile.costInputPer1m < bestAlt.profile.costInputPer1m) {
|
|
4729
|
+
bestAlt = { id: altId, profile: altProfile, score: altScore };
|
|
4518
4730
|
}
|
|
4519
|
-
return null;
|
|
4520
4731
|
}
|
|
4521
|
-
return
|
|
4732
|
+
if (!bestAlt) return [];
|
|
4733
|
+
const tierDownWouldFire = bestAlt.score.grounding === "measured" && bestAlt.profile.costInputPer1m <= profile.costInputPer1m * TIER_DOWN_COST_RATIO;
|
|
4734
|
+
if (tierDownWouldFire) return [];
|
|
4735
|
+
const chosenGrounding = chosenScore.grounding === "judgment" ? `archetypePerf.${archetype}=judgment` : `archetypePerf.${archetype}=${chosenScore.score}`;
|
|
4736
|
+
const altGrounding = bestAlt.score.grounding === "measured" ? `archetypePerf.${archetype}=${bestAlt.score.score}, measured, n=${bestAlt.score.n}` : `archetypePerf.${archetype}=${bestAlt.score.score}, judgment`;
|
|
4737
|
+
return [
|
|
4738
|
+
{
|
|
4739
|
+
level: "warn",
|
|
4740
|
+
code: "cost-mismatched-archetype",
|
|
4741
|
+
message: `Cost-mismatched-archetype: target=${profile.id} (${chosenGrounding}) selected for ${archetype}. Alternative ${bestAlt.id} (${altGrounding}) is cheaper ($${bestAlt.profile.costInputPer1m}/$${bestAlt.profile.costOutputPer1m} vs $${profile.costInputPer1m}/$${profile.costOutputPer1m} per 1M) at equal-or-better quality.`,
|
|
4742
|
+
suggestion: `Consider declaring \`${bestAlt.id}\` as the primary model for this archetype, or relax to posture='open' to let kgauto select among the chain. If the chosen model is required for compliance/brand reasons, set \`policy.posture = 'locked'\` to silence this rule.`,
|
|
4743
|
+
recommendationType: profile.provider === bestAlt.profile.provider ? "tier-down" : "model-swap",
|
|
4744
|
+
docsUrl: "https://github.com/stue/command-center/blob/main/interfaces/kgauto.md#best-practice-advisories"
|
|
4745
|
+
}
|
|
4746
|
+
];
|
|
4522
4747
|
}
|
|
4523
|
-
function
|
|
4524
|
-
|
|
4525
|
-
|
|
4526
|
-
|
|
4748
|
+
function detectModelStaleEvidence(ir, profile) {
|
|
4749
|
+
if (!isBrainQueryActiveFor("kgauto_archetype_perf")) return [];
|
|
4750
|
+
const archetype = ir.intent.archetype;
|
|
4751
|
+
const chosen = getArchetypePerfScore(profile.id, archetype);
|
|
4752
|
+
if (chosen.grounding !== "judgment") return [];
|
|
4753
|
+
return [
|
|
4754
|
+
{
|
|
4755
|
+
level: "info",
|
|
4756
|
+
code: "model-stale-evidence",
|
|
4757
|
+
message: `Model-stale-evidence: target=${profile.id} archetype=${archetype} is judgment-grounded (n=${chosen.n}, cross-app 90d window) despite brain-query mode being active. Fewer than 10 outcomes back this (model, archetype) tuple across ALL consumers \u2014 routing decisions remain pre-measured for this slot.`,
|
|
4758
|
+
suggestion: "Verify that `record()` is being called on every call() outcome. Counts are cross-app (migration 050 view): once ANY consumers accumulate n>=10 rows on this tuple, the score promotes from judgment to measured automatically within the 5-min SWR window. (Before alpha.78 this promotion was advertised but had no implementing mechanism \u2014 n was never populated; if this advisory has been firing for weeks at n=0 despite real traffic, bump to >=alpha.78 and it will clear on its own.)",
|
|
4759
|
+
recommendationType: "prompt-fix",
|
|
4760
|
+
docsUrl: "https://github.com/stue/command-center/blob/main/interfaces/kgauto.md#best-practice-advisories"
|
|
4761
|
+
}
|
|
4762
|
+
];
|
|
4763
|
+
}
|
|
4764
|
+
function detectTierDown(ir, profile, phase2) {
|
|
4765
|
+
if (!phase2 || phase2.fallbackChain.length === 0) return [];
|
|
4766
|
+
if (!phase2.profileResolver) return [];
|
|
4767
|
+
const archetype = ir.intent.archetype;
|
|
4768
|
+
const chosenScore = getArchetypePerfScore(profile.id, archetype);
|
|
4769
|
+
const chosenCost = profile.costInputPer1m;
|
|
4770
|
+
let bestAlt = null;
|
|
4771
|
+
for (const altId of phase2.fallbackChain) {
|
|
4772
|
+
const altProfile = phase2.profileResolver(altId);
|
|
4773
|
+
if (!altProfile) continue;
|
|
4774
|
+
if (altProfile.id === profile.id) continue;
|
|
4775
|
+
const altScore = getArchetypePerfScore(altProfile.id, archetype);
|
|
4776
|
+
if (altScore.grounding !== "measured") continue;
|
|
4777
|
+
if (altScore.score < QUALITY_FLOOR_FOR_RECOMMENDATION) continue;
|
|
4778
|
+
if (altScore.score < chosenScore.score) continue;
|
|
4779
|
+
if (altProfile.costInputPer1m > chosenCost * TIER_DOWN_COST_RATIO) continue;
|
|
4780
|
+
if (!bestAlt || altProfile.costInputPer1m < bestAlt.profile.costInputPer1m || altProfile.costInputPer1m === bestAlt.profile.costInputPer1m && altScore.score > bestAlt.score.score) {
|
|
4781
|
+
bestAlt = { id: altId, profile: altProfile, score: altScore };
|
|
4782
|
+
}
|
|
4527
4783
|
}
|
|
4528
|
-
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
|
|
4538
|
-
|
|
4539
|
-
|
|
4540
|
-
|
|
4541
|
-
|
|
4542
|
-
|
|
4543
|
-
|
|
4544
|
-
|
|
4545
|
-
sectionId: section.id,
|
|
4546
|
-
kind: section.kind,
|
|
4547
|
-
rule: rule.id,
|
|
4548
|
-
originalText,
|
|
4549
|
-
transformedText,
|
|
4550
|
-
...rule.wireOverrides ? { wireOverrides: rule.wireOverrides } : {}
|
|
4551
|
-
});
|
|
4552
|
-
return { ...section, text: transformedText };
|
|
4784
|
+
if (!bestAlt) return [];
|
|
4785
|
+
const chosenDesc = chosenScore.grounding === "measured" ? `archetypePerf.${archetype}=${chosenScore.score} (measured, n=${chosenScore.n})` : `archetypePerf.${archetype}=${chosenScore.score} (${chosenScore.grounding})`;
|
|
4786
|
+
return [
|
|
4787
|
+
{
|
|
4788
|
+
level: "warn",
|
|
4789
|
+
code: "tier-down",
|
|
4790
|
+
message: `Tier-down: target=${profile.id} (${chosenDesc}) selected for ${archetype}. Brain shows ${bestAlt.id} delivers equal-or-better quality (archetypePerf.${archetype}=${bestAlt.score.score}, measured, n=${bestAlt.score.n}) at $${bestAlt.profile.costInputPer1m}/$${bestAlt.profile.costOutputPer1m} per 1M vs $${profile.costInputPer1m}/$${profile.costOutputPer1m} \u2014 a measured tier-down opportunity.`,
|
|
4791
|
+
suggestion: `Move \`${bestAlt.id}\` to primary for this archetype. The brain has n=${bestAlt.score.n} measured outcomes backing the recommendation; this is data, not opinion. If posture='locked' is required (compliance/brand promise), set it explicitly to silence this rule.`,
|
|
4792
|
+
recommendationType: "tier-down",
|
|
4793
|
+
docsUrl: "https://github.com/stue/command-center/blob/main/interfaces/kgauto.md#best-practice-advisories"
|
|
4794
|
+
}
|
|
4795
|
+
];
|
|
4796
|
+
}
|
|
4797
|
+
function detectArchetypePerfFloorBreach(ir, profile) {
|
|
4798
|
+
const compat = getModelCompatibility(profile.id, {
|
|
4799
|
+
archetype: ir.intent.archetype,
|
|
4800
|
+
toolOrchestration: ir.constraints?.toolOrchestration
|
|
4553
4801
|
});
|
|
4554
|
-
if (
|
|
4555
|
-
|
|
4802
|
+
if (compat.status === "compatible") return [];
|
|
4803
|
+
if (compat.status === "requires-adapter") {
|
|
4804
|
+
return [
|
|
4805
|
+
{
|
|
4806
|
+
level: "warn",
|
|
4807
|
+
code: "archetype-perf-floor-breach",
|
|
4808
|
+
message: `${profile.id} sits below the archetype floor for ${ir.intent.archetype} (score ${compat.archetypePerf}/10, floor ${6}). A known adapter would lift it: ${compat.adapter.parameter}=${compat.adapter.value}. ${compat.adapter.consequence}`,
|
|
4809
|
+
suggestion: `Pass \`ir.constraints.${compat.adapter.parameter} = '${compat.adapter.value}'\` for this call, OR pick a model whose archetypePerf for ${ir.intent.archetype} already clears the floor (call \`getModelCompatibility(modelId, { archetype: '${ir.intent.archetype}' })\` to check). Estimated post-adapter score: ${compat.archetypePerfWithAdapter}/10.`,
|
|
4810
|
+
recommendationType: "prompt-fix",
|
|
4811
|
+
suggestedAdaptation: compat.adapter,
|
|
4812
|
+
docsUrl: "https://github.com/stue/command-center/blob/main/interfaces/kgauto.md#best-practice-advisories"
|
|
4813
|
+
}
|
|
4814
|
+
];
|
|
4556
4815
|
}
|
|
4557
|
-
|
|
4558
|
-
|
|
4816
|
+
return [
|
|
4817
|
+
{
|
|
4818
|
+
level: "critical",
|
|
4819
|
+
code: "archetype-perf-floor-breach",
|
|
4820
|
+
message: `${profile.id} sits below the archetype floor for ${ir.intent.archetype} (score ${compat.archetypePerf}/10, floor ${6}) and no known adapter would lift it. ${compat.reason}`,
|
|
4821
|
+
suggestion: `Swap to a model whose archetypePerf for ${ir.intent.archetype} clears the floor. Use \`getModelCompatibility(candidateId, { archetype: '${ir.intent.archetype}' })\` to vet candidates, or \`getDefaultFallbackChain({ archetype: '${ir.intent.archetype}', posture: 'open' })\` for a library-picked chain that respects the floor by construction.`,
|
|
4822
|
+
recommendationType: "model-swap",
|
|
4823
|
+
docsUrl: "https://github.com/stue/command-center/blob/main/interfaces/kgauto.md#best-practice-advisories"
|
|
4824
|
+
}
|
|
4825
|
+
];
|
|
4559
4826
|
}
|
|
4560
|
-
|
|
4561
|
-
|
|
4562
|
-
|
|
4563
|
-
|
|
4564
|
-
|
|
4565
|
-
|
|
4827
|
+
function detectStaleExclusionCandidate(ir) {
|
|
4828
|
+
if (!isExclusionFindingsBrainActive()) return [];
|
|
4829
|
+
if (!ir.appId) return [];
|
|
4830
|
+
const findings = getStaleExclusionFindings({
|
|
4831
|
+
appId: ir.appId,
|
|
4832
|
+
archetype: ir.intent.archetype
|
|
4833
|
+
});
|
|
4834
|
+
if (findings.length === 0) return [];
|
|
4835
|
+
const ranked = [...findings].sort((a, b) => {
|
|
4836
|
+
const sa = a.estimatedSavingsUsd30d ?? -Infinity;
|
|
4837
|
+
const sb = b.estimatedSavingsUsd30d ?? -Infinity;
|
|
4838
|
+
if (sa !== sb) return sb - sa;
|
|
4839
|
+
return confidenceRank(b.confidence) - confidenceRank(a.confidence);
|
|
4840
|
+
});
|
|
4841
|
+
const top = ranked[0];
|
|
4842
|
+
const extraCount = findings.length - 1;
|
|
4843
|
+
const extraNote = extraCount > 0 ? ` (+ ${extraCount} more excluded model${extraCount === 1 ? "" : "s"} for this archetype)` : "";
|
|
4844
|
+
return [
|
|
4845
|
+
{
|
|
4846
|
+
level: "info",
|
|
4847
|
+
code: "stale-exclusion-candidate",
|
|
4848
|
+
message: `${top.message}${extraNote}`,
|
|
4849
|
+
suggestion: top.suggestion,
|
|
4850
|
+
recommendationType: "tier-down",
|
|
4851
|
+
docsUrl: "https://github.com/stue/command-center/blob/main/interfaces/kgauto.md#best-practice-advisories"
|
|
4852
|
+
}
|
|
4853
|
+
];
|
|
4566
4854
|
}
|
|
4567
|
-
function
|
|
4568
|
-
if (
|
|
4569
|
-
if (
|
|
4570
|
-
|
|
4571
|
-
return Number.isFinite(n) ? n : null;
|
|
4572
|
-
}
|
|
4573
|
-
return null;
|
|
4574
|
-
}
|
|
4575
|
-
function mapRowsToPromotions(rows) {
|
|
4576
|
-
const out = [];
|
|
4577
|
-
for (const row of rows) {
|
|
4578
|
-
if (!isRawPromotionRow(row)) continue;
|
|
4579
|
-
const id = coerceId(row.id);
|
|
4580
|
-
if (id === null) continue;
|
|
4581
|
-
const mode = row.mode === "strategy" ? "strategy" : row.mode === "downswap" || row.mode === void 0 ? "downswap" : null;
|
|
4582
|
-
if (mode === null) continue;
|
|
4583
|
-
out.push({
|
|
4584
|
-
id,
|
|
4585
|
-
archetype: row.intent_archetype,
|
|
4586
|
-
mode,
|
|
4587
|
-
strategy: typeof row.strategy === "string" ? row.strategy : null,
|
|
4588
|
-
promotedModel: row.promoted_model,
|
|
4589
|
-
incumbentModel: row.incumbent_model,
|
|
4590
|
-
evalRunId: coerceId(row.eval_run_id ?? null),
|
|
4591
|
-
suppressQualityGate: row.suppress_quality_gate === true,
|
|
4592
|
-
promotedAt: typeof row.promoted_at === "string" ? row.promoted_at : ""
|
|
4593
|
-
});
|
|
4594
|
-
}
|
|
4595
|
-
return out;
|
|
4596
|
-
}
|
|
4597
|
-
var snapshots4 = /* @__PURE__ */ new Map();
|
|
4598
|
-
var runtime5;
|
|
4599
|
-
var warnedOnce4 = false;
|
|
4600
|
-
var DEFAULT_PROMOTIONS_ENDPOINT = "https://kgauto-dashboard.vercel.app/api/kgauto-v2/promotions";
|
|
4601
|
-
function isAutoPromoteEnabledFromEnv(envSource) {
|
|
4602
|
-
const env = envSource ?? (typeof process !== "undefined" && process.env ? process.env : {});
|
|
4603
|
-
const raw = (env.KGAUTO_AUTO_PROMOTE ?? "").trim().toLowerCase();
|
|
4604
|
-
return raw === "1" || raw === "true";
|
|
4605
|
-
}
|
|
4606
|
-
function configurePromotionsBrain(rt) {
|
|
4607
|
-
runtime5 = rt;
|
|
4608
|
-
snapshots4.clear();
|
|
4609
|
-
warnedOnce4 = false;
|
|
4610
|
-
}
|
|
4611
|
-
function isPromotionsBrainActive() {
|
|
4612
|
-
return runtime5 !== void 0;
|
|
4613
|
-
}
|
|
4614
|
-
function getApplicablePromotion(opts) {
|
|
4615
|
-
const rt = runtime5;
|
|
4616
|
-
if (!rt) return void 0;
|
|
4617
|
-
const appId = opts.appId;
|
|
4618
|
-
if (!appId || !opts.archetype || !opts.mode) return void 0;
|
|
4619
|
-
let snap = snapshots4.get(appId);
|
|
4620
|
-
if (!snap) {
|
|
4621
|
-
snap = { data: [], expiresAt: 0, refreshing: false };
|
|
4622
|
-
snapshots4.set(appId, snap);
|
|
4623
|
-
}
|
|
4624
|
-
const now = Date.now();
|
|
4625
|
-
const stale = snap.expiresAt <= now;
|
|
4626
|
-
if (stale && !snap.refreshing) {
|
|
4627
|
-
snap.refreshing = true;
|
|
4628
|
-
void asyncRefresh5(rt, appId);
|
|
4629
|
-
}
|
|
4630
|
-
return snap.data.find(
|
|
4631
|
-
(p) => p.archetype === opts.archetype && p.mode === opts.mode
|
|
4632
|
-
);
|
|
4633
|
-
}
|
|
4634
|
-
var pendingRefreshes4 = /* @__PURE__ */ new Map();
|
|
4635
|
-
async function asyncRefresh5(rt, appId) {
|
|
4636
|
-
const promise = doRefresh5(rt, appId);
|
|
4637
|
-
pendingRefreshes4.set(appId, promise);
|
|
4638
|
-
try {
|
|
4639
|
-
await promise;
|
|
4640
|
-
} finally {
|
|
4641
|
-
if (pendingRefreshes4.get(appId) === promise) {
|
|
4642
|
-
pendingRefreshes4.delete(appId);
|
|
4643
|
-
}
|
|
4644
|
-
}
|
|
4645
|
-
}
|
|
4646
|
-
async function doRefresh5(rt, appId) {
|
|
4647
|
-
const url = `${rt.endpoint}?app_id=${encodeURIComponent(appId)}`;
|
|
4648
|
-
let snap = snapshots4.get(appId);
|
|
4649
|
-
if (!snap) {
|
|
4650
|
-
snap = { data: [], expiresAt: 0, refreshing: false };
|
|
4651
|
-
snapshots4.set(appId, snap);
|
|
4652
|
-
}
|
|
4653
|
-
try {
|
|
4654
|
-
const res = await rt.fetchImpl(url, { method: "GET" });
|
|
4655
|
-
if (!res.ok) {
|
|
4656
|
-
throw new Error(`promotions ${res.status}: ${res.statusText}`);
|
|
4657
|
-
}
|
|
4658
|
-
const body = await res.json();
|
|
4659
|
-
if (runtime5 !== rt) return;
|
|
4660
|
-
const rows = Array.isArray(body) ? mapRowsToPromotions(body) : [];
|
|
4661
|
-
snap.data = rows;
|
|
4662
|
-
snap.expiresAt = Date.now() + rt.ttlMs;
|
|
4663
|
-
snap.refreshing = false;
|
|
4664
|
-
} catch (err) {
|
|
4665
|
-
if (runtime5 !== rt) return;
|
|
4666
|
-
snap.refreshing = false;
|
|
4667
|
-
snap.expiresAt = Date.now() + rt.ttlMs;
|
|
4668
|
-
if (!warnedOnce4) {
|
|
4669
|
-
warnedOnce4 = true;
|
|
4670
|
-
(rt.onError ?? defaultOnError5)(err);
|
|
4671
|
-
}
|
|
4672
|
-
}
|
|
4673
|
-
}
|
|
4674
|
-
function defaultOnError5(err) {
|
|
4675
|
-
console.warn(
|
|
4676
|
-
"[kgauto] promotions fetch failed (promotion boost inactive until next refresh):",
|
|
4677
|
-
err
|
|
4678
|
-
);
|
|
4679
|
-
}
|
|
4680
|
-
function _testResetPromotions() {
|
|
4681
|
-
runtime5 = void 0;
|
|
4682
|
-
snapshots4.clear();
|
|
4683
|
-
pendingRefreshes4 = /* @__PURE__ */ new Map();
|
|
4684
|
-
warnedOnce4 = false;
|
|
4685
|
-
}
|
|
4686
|
-
async function _testWaitForPromotionsRefresh() {
|
|
4687
|
-
const pending = Array.from(pendingRefreshes4.values());
|
|
4688
|
-
if (pending.length > 0) await Promise.all(pending);
|
|
4855
|
+
function confidenceRank(c) {
|
|
4856
|
+
if (c === "high") return 3;
|
|
4857
|
+
if (c === "medium") return 2;
|
|
4858
|
+
return 1;
|
|
4689
4859
|
}
|
|
4690
4860
|
|
|
4691
|
-
// src/
|
|
4692
|
-
|
|
4693
|
-
|
|
4694
|
-
|
|
4695
|
-
|
|
4696
|
-
|
|
4697
|
-
|
|
4698
|
-
|
|
4699
|
-
|
|
4700
|
-
|
|
4701
|
-
|
|
4702
|
-
|
|
4703
|
-
|
|
4704
|
-
|
|
4705
|
-
|
|
4706
|
-
|
|
4707
|
-
|
|
4708
|
-
|
|
4709
|
-
|
|
4710
|
-
|
|
4711
|
-
|
|
4712
|
-
|
|
4713
|
-
|
|
4714
|
-
|
|
4715
|
-
|
|
4716
|
-
|
|
4717
|
-
|
|
4718
|
-
|
|
4719
|
-
|
|
4720
|
-
|
|
4721
|
-
|
|
4722
|
-
|
|
4723
|
-
|
|
4724
|
-
|
|
4725
|
-
|
|
4726
|
-
|
|
4727
|
-
|
|
4728
|
-
|
|
4729
|
-
|
|
4730
|
-
|
|
4731
|
-
|
|
4732
|
-
|
|
4733
|
-
|
|
4734
|
-
|
|
4735
|
-
|
|
4736
|
-
|
|
4737
|
-
|
|
4738
|
-
z: 1.96,
|
|
4739
|
-
/** Must match the view's window. Documented here for the advisory text. */
|
|
4740
|
-
windowDays: 28
|
|
4741
|
-
};
|
|
4742
|
-
function wilsonLowerBound(failures, n, z = MEASURED_FAILURE_CFG.z) {
|
|
4743
|
-
if (n <= 0) return 0;
|
|
4744
|
-
const p = failures / n;
|
|
4745
|
-
const z2 = z * z;
|
|
4746
|
-
const denom = 1 + z2 / n;
|
|
4747
|
-
const centre = p + z2 / (2 * n);
|
|
4748
|
-
const margin = z * Math.sqrt(p * (1 - p) / n + z2 / (4 * n * n));
|
|
4749
|
-
const lower2 = (centre - margin) / denom;
|
|
4750
|
-
return lower2 < 0 ? 0 : lower2;
|
|
4751
|
-
}
|
|
4752
|
-
function judgeMeasuredFailure(row, cfg = MEASURED_FAILURE_CFG) {
|
|
4753
|
-
if (!row || row.n < cfg.minSample) return void 0;
|
|
4754
|
-
const lowerBound = wilsonLowerBound(row.nFail, row.n, cfg.z);
|
|
4755
|
-
return {
|
|
4756
|
-
gated: lowerBound > cfg.lowerBoundThreshold,
|
|
4757
|
-
rate: row.nFail / row.n,
|
|
4758
|
-
lowerBound,
|
|
4759
|
-
n: row.n,
|
|
4760
|
-
nFail: row.nFail
|
|
4761
|
-
};
|
|
4762
|
-
}
|
|
4763
|
-
var snapshots5 = /* @__PURE__ */ new Map();
|
|
4764
|
-
var runtime6;
|
|
4765
|
-
var warnedOnce5 = false;
|
|
4766
|
-
var DEFAULT_MEASURED_FAILURE_ENDPOINT = "https://kgauto-dashboard.vercel.app/api/kgauto-v2/measured-failure";
|
|
4767
|
-
function isMeasuredFailureGateEnabledFromEnv(envSource) {
|
|
4768
|
-
const env = envSource ?? (typeof process !== "undefined" && process.env ? process.env : {});
|
|
4769
|
-
const raw = (env.KGAUTO_MEASURED_FAILURE_GATE ?? "").trim().toLowerCase();
|
|
4770
|
-
return !(raw === "0" || raw === "false");
|
|
4771
|
-
}
|
|
4772
|
-
function configureMeasuredFailureBrain(rt) {
|
|
4773
|
-
runtime6 = rt;
|
|
4774
|
-
snapshots5.clear();
|
|
4775
|
-
warnedOnce5 = false;
|
|
4776
|
-
}
|
|
4777
|
-
function isMeasuredFailureBrainActive() {
|
|
4778
|
-
return runtime6 !== void 0;
|
|
4779
|
-
}
|
|
4780
|
-
function prefetchMeasuredFailure(appId) {
|
|
4781
|
-
const rt = runtime6;
|
|
4782
|
-
if (!rt || !appId) return void 0;
|
|
4783
|
-
let snap = snapshots5.get(appId);
|
|
4784
|
-
if (!snap) {
|
|
4785
|
-
snap = { data: [], expiresAt: 0, refreshing: false };
|
|
4786
|
-
snapshots5.set(appId, snap);
|
|
4787
|
-
}
|
|
4788
|
-
if (snap.expiresAt > Date.now()) return void 0;
|
|
4789
|
-
const inflight = pendingRefreshes5.get(appId);
|
|
4790
|
-
if (inflight) return inflight;
|
|
4791
|
-
if (snap.refreshing) return void 0;
|
|
4792
|
-
snap.refreshing = true;
|
|
4793
|
-
void asyncRefresh6(rt, appId);
|
|
4794
|
-
return pendingRefreshes5.get(appId);
|
|
4795
|
-
}
|
|
4796
|
-
async function awaitMeasuredFailureReady(appId, timeoutMs) {
|
|
4797
|
-
if (!runtime6 || !appId) return;
|
|
4798
|
-
const pending = prefetchMeasuredFailure(appId) ?? pendingRefreshes5.get(appId);
|
|
4799
|
-
if (!(timeoutMs > 0)) return;
|
|
4800
|
-
if (!pending) return;
|
|
4801
|
-
let timer;
|
|
4802
|
-
try {
|
|
4803
|
-
await Promise.race([
|
|
4804
|
-
pending,
|
|
4805
|
-
new Promise((resolve) => {
|
|
4806
|
-
timer = setTimeout(resolve, timeoutMs);
|
|
4807
|
-
})
|
|
4808
|
-
]);
|
|
4809
|
-
} catch {
|
|
4810
|
-
} finally {
|
|
4811
|
-
if (timer) clearTimeout(timer);
|
|
4812
|
-
}
|
|
4813
|
-
}
|
|
4814
|
-
function getMeasuredFailureVerdict(opts) {
|
|
4815
|
-
const rt = runtime6;
|
|
4816
|
-
if (!rt) return void 0;
|
|
4817
|
-
const { appId, archetype, model } = opts;
|
|
4818
|
-
if (!appId || !archetype || !model) return void 0;
|
|
4819
|
-
let snap = snapshots5.get(appId);
|
|
4820
|
-
if (!snap) {
|
|
4821
|
-
snap = { data: [], expiresAt: 0, refreshing: false };
|
|
4822
|
-
snapshots5.set(appId, snap);
|
|
4823
|
-
}
|
|
4824
|
-
const now = Date.now();
|
|
4825
|
-
if (snap.expiresAt <= now && !snap.refreshing) {
|
|
4826
|
-
snap.refreshing = true;
|
|
4827
|
-
void asyncRefresh6(rt, appId);
|
|
4828
|
-
}
|
|
4829
|
-
const row = snap.data.find(
|
|
4830
|
-
(r) => r.archetype === archetype && r.model === model
|
|
4831
|
-
);
|
|
4832
|
-
return judgeMeasuredFailure(row);
|
|
4833
|
-
}
|
|
4834
|
-
var pendingRefreshes5 = /* @__PURE__ */ new Map();
|
|
4835
|
-
async function asyncRefresh6(rt, appId) {
|
|
4836
|
-
const promise = doRefresh6(rt, appId);
|
|
4837
|
-
pendingRefreshes5.set(appId, promise);
|
|
4838
|
-
try {
|
|
4839
|
-
await promise;
|
|
4840
|
-
} finally {
|
|
4841
|
-
if (pendingRefreshes5.get(appId) === promise) {
|
|
4842
|
-
pendingRefreshes5.delete(appId);
|
|
4861
|
+
// src/translator.ts
|
|
4862
|
+
var TRANSLATOR_FLOOR = ARCHETYPE_FLOOR_DEFAULT;
|
|
4863
|
+
var RULE_SEQUENTIAL_TOOL_CLIFF = "sequential-tool-cliff-below-floor";
|
|
4864
|
+
var RULE_NARRATION_DRIFT_ANTHROPIC = "narration-drift-anthropic";
|
|
4865
|
+
var RULE_NARRATION_THINKING_LEAK_DEEPSEEK = "narration-thinking-leak-deepseek";
|
|
4866
|
+
var SEQUENTIAL_TOOL_PREAMBLE = "IMPORTANT: Use one tool call per response. Wait for the tool result before deciding the next tool. Do NOT batch tool calls in parallel.";
|
|
4867
|
+
var NARRATION_DRIFT_ANTHROPIC_PREAMBLE = "Output ONLY the requested content. Do not narrate your thought process. Each line \u2264 12 words.";
|
|
4868
|
+
var NARRATION_THINKING_LEAK_DEEPSEEK_PREAMBLE = "Reasoning is internal. Output ONLY the requested content; do not emit <thinking> blocks or internal monologue as user-facing text.";
|
|
4869
|
+
var RULE_DISCIPLINE_GATES_V1 = "discipline-gates-v1";
|
|
4870
|
+
var DISCIPLINE_GATES_V1_WITH_TOOLS = `Work through these gates at every judgment point, explicitly:
|
|
4871
|
+
1. Evidence before reasoning: cite what you observed before concluding from it.
|
|
4872
|
+
2. One extra signal: when a finding feels conclusive, check one more adjacent signal before stating it.
|
|
4873
|
+
3. Expand, don't guess: resolve a compressed or referenced item by looking it up rather than inferring its contents.
|
|
4874
|
+
4. Innocent explanation first: state the most plausible benign reading before alleging the alarming one.
|
|
4875
|
+
5. Label each claim: mark it observed, inferred, or assumed.
|
|
4876
|
+
6. A surfaced gap beats a guessed answer: flag what you cannot determine rather than fabricating past it.`;
|
|
4877
|
+
var DISCIPLINE_GATES_V1_NO_TOOLS = `Work through these gates at every judgment point, explicitly:
|
|
4878
|
+
1. Evidence before reasoning: cite what you observed before concluding from it.
|
|
4879
|
+
2. One extra signal: when a finding feels conclusive, check one more adjacent signal before stating it.
|
|
4880
|
+
3. Innocent explanation first: state the most plausible benign reading before alleging the alarming one.
|
|
4881
|
+
4. Label each claim: mark it observed, inferred, or assumed.
|
|
4882
|
+
5. A surfaced gap beats a guessed answer: flag what you cannot determine rather than fabricating past it.`;
|
|
4883
|
+
var RULE_DISCIPLINE_GATES_V1_STRUCTURED = "discipline-gates-v1-structured";
|
|
4884
|
+
var DISCIPLINE_GATES_V1_STRUCTURED_WITH_TOOLS = `Work through these gates at every judgment point, explicitly:
|
|
4885
|
+
1. Evidence before reasoning: cite what you observed before concluding from it.
|
|
4886
|
+
2. One extra signal: when a finding feels conclusive, check one more adjacent signal before stating it.
|
|
4887
|
+
3. Expand, don't guess: resolve a compressed or referenced item by looking it up rather than inferring its contents.
|
|
4888
|
+
4. Innocent explanation first: state the most plausible benign reading before alleging the alarming one.`;
|
|
4889
|
+
var DISCIPLINE_GATES_V1_STRUCTURED_NO_TOOLS = `Work through these gates at every judgment point, explicitly:
|
|
4890
|
+
1. Evidence before reasoning: cite what you observed before concluding from it.
|
|
4891
|
+
2. One extra signal: when a finding feels conclusive, check one more adjacent signal before stating it.
|
|
4892
|
+
3. Innocent explanation first: state the most plausible benign reading before alleging the alarming one.`;
|
|
4893
|
+
var DISCIPLINE_ELIGIBLE_ARCHETYPES = /* @__PURE__ */ new Set([
|
|
4894
|
+
"hunt",
|
|
4895
|
+
"summarize",
|
|
4896
|
+
"plan",
|
|
4897
|
+
"critique",
|
|
4898
|
+
"judge"
|
|
4899
|
+
]);
|
|
4900
|
+
function matchRule(kind, profile, archetype, ctx) {
|
|
4901
|
+
if (kind === "discipline_contract") {
|
|
4902
|
+
if (!DISCIPLINE_ELIGIBLE_ARCHETYPES.has(archetype)) return null;
|
|
4903
|
+
if (ctx.outputMode !== "text") {
|
|
4904
|
+
return {
|
|
4905
|
+
id: RULE_DISCIPLINE_GATES_V1_STRUCTURED,
|
|
4906
|
+
preamble: ctx.hasTools ? DISCIPLINE_GATES_V1_STRUCTURED_WITH_TOOLS : DISCIPLINE_GATES_V1_STRUCTURED_NO_TOOLS
|
|
4907
|
+
};
|
|
4843
4908
|
}
|
|
4909
|
+
return {
|
|
4910
|
+
id: RULE_DISCIPLINE_GATES_V1,
|
|
4911
|
+
preamble: ctx.hasTools ? DISCIPLINE_GATES_V1_WITH_TOOLS : DISCIPLINE_GATES_V1_NO_TOOLS
|
|
4912
|
+
};
|
|
4844
4913
|
}
|
|
4845
|
-
|
|
4846
|
-
|
|
4847
|
-
|
|
4848
|
-
|
|
4849
|
-
|
|
4850
|
-
|
|
4851
|
-
|
|
4914
|
+
if (kind === "tool_call_contract") {
|
|
4915
|
+
if (!profile.archetypePerf) return null;
|
|
4916
|
+
const archetypeScore = profile.archetypePerf[archetype];
|
|
4917
|
+
if (typeof archetypeScore !== "number" || archetypeScore >= TRANSLATOR_FLOOR) {
|
|
4918
|
+
return null;
|
|
4919
|
+
}
|
|
4920
|
+
return {
|
|
4921
|
+
id: RULE_SEQUENTIAL_TOOL_CLIFF,
|
|
4922
|
+
preamble: SEQUENTIAL_TOOL_PREAMBLE,
|
|
4923
|
+
wireOverrides: { parallelToolCalls: false }
|
|
4924
|
+
};
|
|
4852
4925
|
}
|
|
4853
|
-
|
|
4854
|
-
|
|
4855
|
-
|
|
4856
|
-
|
|
4926
|
+
if (kind === "narration_contract") {
|
|
4927
|
+
if (profile.provider === "anthropic") {
|
|
4928
|
+
return {
|
|
4929
|
+
id: RULE_NARRATION_DRIFT_ANTHROPIC,
|
|
4930
|
+
preamble: NARRATION_DRIFT_ANTHROPIC_PREAMBLE
|
|
4931
|
+
};
|
|
4857
4932
|
}
|
|
4858
|
-
|
|
4859
|
-
|
|
4860
|
-
|
|
4861
|
-
|
|
4862
|
-
|
|
4863
|
-
} catch (err) {
|
|
4864
|
-
if (runtime6 !== rt) return;
|
|
4865
|
-
snap.refreshing = false;
|
|
4866
|
-
snap.expiresAt = Date.now() + rt.ttlMs;
|
|
4867
|
-
if (!warnedOnce5) {
|
|
4868
|
-
warnedOnce5 = true;
|
|
4869
|
-
(rt.onError ?? defaultOnError6)(err);
|
|
4933
|
+
if (profile.provider === "deepseek") {
|
|
4934
|
+
return {
|
|
4935
|
+
id: RULE_NARRATION_THINKING_LEAK_DEEPSEEK,
|
|
4936
|
+
preamble: NARRATION_THINKING_LEAK_DEEPSEEK_PREAMBLE
|
|
4937
|
+
};
|
|
4870
4938
|
}
|
|
4939
|
+
return null;
|
|
4871
4940
|
}
|
|
4941
|
+
return null;
|
|
4872
4942
|
}
|
|
4873
|
-
function
|
|
4874
|
-
|
|
4875
|
-
|
|
4876
|
-
|
|
4877
|
-
|
|
4878
|
-
|
|
4879
|
-
|
|
4880
|
-
|
|
4881
|
-
|
|
4882
|
-
|
|
4883
|
-
|
|
4884
|
-
}
|
|
4885
|
-
|
|
4886
|
-
const
|
|
4887
|
-
|
|
4943
|
+
function applySectionRewrites(args) {
|
|
4944
|
+
const { ir, profile, archetype } = args;
|
|
4945
|
+
if (!Array.isArray(ir.sections) || ir.sections.length === 0) {
|
|
4946
|
+
return { rewrittenIR: ir, rewrites: [] };
|
|
4947
|
+
}
|
|
4948
|
+
const outputMode = args.outputMode ?? resolveOutputMode({
|
|
4949
|
+
declared: ir.constraints?.outputMode,
|
|
4950
|
+
structuredOutput: ir.constraints?.structuredOutput,
|
|
4951
|
+
toolCount: ir.tools?.length ?? 0
|
|
4952
|
+
});
|
|
4953
|
+
const hasTools = (ir.tools?.length ?? 0) > 0;
|
|
4954
|
+
const ctx = { outputMode, hasTools };
|
|
4955
|
+
const rewrites = [];
|
|
4956
|
+
const newSections = ir.sections.map((section) => {
|
|
4957
|
+
if (!section.kind || section.kind === "arbitrary") return section;
|
|
4958
|
+
const rule = matchRule(section.kind, profile, archetype, ctx);
|
|
4959
|
+
if (!rule) return section;
|
|
4960
|
+
const originalText = section.text;
|
|
4961
|
+
const transformedText = `${rule.preamble}
|
|
4962
|
+
|
|
4963
|
+
${originalText}`;
|
|
4964
|
+
rewrites.push({
|
|
4965
|
+
sectionId: section.id,
|
|
4966
|
+
kind: section.kind,
|
|
4967
|
+
rule: rule.id,
|
|
4968
|
+
originalText,
|
|
4969
|
+
transformedText,
|
|
4970
|
+
...rule.wireOverrides ? { wireOverrides: rule.wireOverrides } : {}
|
|
4971
|
+
});
|
|
4972
|
+
return { ...section, text: transformedText };
|
|
4973
|
+
});
|
|
4974
|
+
if (rewrites.length === 0) {
|
|
4975
|
+
return { rewrittenIR: ir, rewrites: [] };
|
|
4976
|
+
}
|
|
4977
|
+
const rewrittenIR = { ...ir, sections: newSections };
|
|
4978
|
+
return { rewrittenIR, rewrites };
|
|
4888
4979
|
}
|
|
4889
4980
|
|
|
4890
4981
|
// src/compile.ts
|
|
@@ -6014,6 +6105,17 @@ function parseJsonLoose(raw) {
|
|
|
6014
6105
|
var FAILED = /* @__PURE__ */ Symbol("parse-failed");
|
|
6015
6106
|
|
|
6016
6107
|
// src/ir.ts
|
|
6108
|
+
function mutationId(m) {
|
|
6109
|
+
return typeof m === "string" ? m : m.id;
|
|
6110
|
+
}
|
|
6111
|
+
function hasMutation(list, idOrPrefix) {
|
|
6112
|
+
if (!Array.isArray(list)) return false;
|
|
6113
|
+
const prefix = idOrPrefix.endsWith("*") ? idOrPrefix.slice(0, -1) : void 0;
|
|
6114
|
+
return list.some((m) => {
|
|
6115
|
+
const id = mutationId(m);
|
|
6116
|
+
return prefix !== void 0 ? id.startsWith(prefix) : id === idOrPrefix;
|
|
6117
|
+
});
|
|
6118
|
+
}
|
|
6017
6119
|
var CallError = class extends Error {
|
|
6018
6120
|
attempts;
|
|
6019
6121
|
lastErrorCode;
|
|
@@ -6136,6 +6238,17 @@ function getReachabilityDiagnostic(opts = {}) {
|
|
|
6136
6238
|
}
|
|
6137
6239
|
return out;
|
|
6138
6240
|
}
|
|
6241
|
+
var BRAIN_READ_ENV_NAMES = {
|
|
6242
|
+
endpoint: "KGAUTO_V2_BRAIN_SUPABASE_URL",
|
|
6243
|
+
jwt: "KGAUTO_V2_BRAIN_JWT",
|
|
6244
|
+
anonKey: "KGAUTO_V2_BRAIN_ANON_KEY",
|
|
6245
|
+
/** Accepted fallbacks, in resolution order after the canonical name. */
|
|
6246
|
+
fallbacks: {
|
|
6247
|
+
endpoint: ["KGAUTO_V2_BRAIN_URL"],
|
|
6248
|
+
jwt: ["GLASSBOX_BRAIN_JWT"],
|
|
6249
|
+
anonKey: []
|
|
6250
|
+
}
|
|
6251
|
+
};
|
|
6139
6252
|
function readBrainReadEnv(envSource = defaultEnv()) {
|
|
6140
6253
|
const endpoint = readKeyValue(envSource.KGAUTO_V2_BRAIN_SUPABASE_URL) ?? readKeyValue(envSource.KGAUTO_V2_BRAIN_URL);
|
|
6141
6254
|
const jwt = readKeyValue(envSource.KGAUTO_V2_BRAIN_JWT) ?? readKeyValue(envSource.GLASSBOX_BRAIN_JWT);
|
|
@@ -6152,12 +6265,46 @@ function isSameModelRetryEnabledFromEnv(envSource = defaultEnv()) {
|
|
|
6152
6265
|
}
|
|
6153
6266
|
|
|
6154
6267
|
// src/streaming.ts
|
|
6268
|
+
function classifyThrownFetchError(err) {
|
|
6269
|
+
const name = err?.name;
|
|
6270
|
+
if (name === "TimeoutError") {
|
|
6271
|
+
return { errorType: "retryable", errorCode: "timeout", message: String(err) };
|
|
6272
|
+
}
|
|
6273
|
+
if (name === "AbortError") {
|
|
6274
|
+
return { errorType: "terminal", errorCode: "aborted", message: "aborted by caller signal" };
|
|
6275
|
+
}
|
|
6276
|
+
return { errorType: "retryable", errorCode: "network_error", message: String(err) };
|
|
6277
|
+
}
|
|
6278
|
+
function createStallGuard(external, stallTimeoutMs) {
|
|
6279
|
+
const ctl = new AbortController();
|
|
6280
|
+
if (external) {
|
|
6281
|
+
if (external.aborted) ctl.abort(external.reason);
|
|
6282
|
+
else external.addEventListener("abort", () => ctl.abort(external.reason), { once: true });
|
|
6283
|
+
}
|
|
6284
|
+
let timer;
|
|
6285
|
+
const arm = () => {
|
|
6286
|
+
if (!stallTimeoutMs || stallTimeoutMs <= 0) return;
|
|
6287
|
+
if (timer) clearTimeout(timer);
|
|
6288
|
+
timer = setTimeout(() => {
|
|
6289
|
+
ctl.abort(
|
|
6290
|
+
new DOMException(`stream stalled: no bytes for ${stallTimeoutMs}ms`, "TimeoutError")
|
|
6291
|
+
);
|
|
6292
|
+
}, stallTimeoutMs);
|
|
6293
|
+
};
|
|
6294
|
+
const clear = () => {
|
|
6295
|
+
if (timer) clearTimeout(timer);
|
|
6296
|
+
timer = void 0;
|
|
6297
|
+
};
|
|
6298
|
+
return { signal: ctl.signal, arm, clear };
|
|
6299
|
+
}
|
|
6155
6300
|
var ANTHROPIC_URL = "https://api.anthropic.com/v1/messages";
|
|
6156
6301
|
async function streamAnthropic(request, apiKey, opts) {
|
|
6157
6302
|
const { provider: _provider, ...body } = request;
|
|
6158
6303
|
const fetchFn = opts.fetchImpl ?? fetch;
|
|
6304
|
+
const guard = createStallGuard(opts.signal, opts.stallTimeoutMs);
|
|
6159
6305
|
let res;
|
|
6160
6306
|
try {
|
|
6307
|
+
guard.arm();
|
|
6161
6308
|
res = await fetchFn(ANTHROPIC_URL, {
|
|
6162
6309
|
method: "POST",
|
|
6163
6310
|
headers: {
|
|
@@ -6165,12 +6312,16 @@ async function streamAnthropic(request, apiKey, opts) {
|
|
|
6165
6312
|
"anthropic-version": "2023-06-01",
|
|
6166
6313
|
"content-type": "application/json"
|
|
6167
6314
|
},
|
|
6168
|
-
body: JSON.stringify({ ...body, stream: true })
|
|
6315
|
+
body: JSON.stringify({ ...body, stream: true }),
|
|
6316
|
+
signal: guard.signal
|
|
6169
6317
|
});
|
|
6170
6318
|
} catch (err) {
|
|
6171
|
-
|
|
6319
|
+
guard.clear();
|
|
6320
|
+
const c = classifyThrownFetchError(err);
|
|
6321
|
+
return { ok: false, status: 0, errorType: c.errorType, errorCode: c.errorCode, message: c.message, raw: null };
|
|
6172
6322
|
}
|
|
6173
6323
|
if (!res.ok) {
|
|
6324
|
+
guard.clear();
|
|
6174
6325
|
const errBody = await res.json().catch(() => ({}));
|
|
6175
6326
|
return classifyHttpError(res.status, errBody);
|
|
6176
6327
|
}
|
|
@@ -6233,9 +6384,13 @@ async function streamAnthropic(request, apiKey, opts) {
|
|
|
6233
6384
|
if (typeof p.usage?.output_tokens === "number") outputTokens = p.usage.output_tokens;
|
|
6234
6385
|
return;
|
|
6235
6386
|
}
|
|
6236
|
-
});
|
|
6387
|
+
}, guard.arm, guard.signal);
|
|
6237
6388
|
} catch (err) {
|
|
6238
|
-
|
|
6389
|
+
const c = classifyThrownFetchError(err);
|
|
6390
|
+
const code = c.errorCode === "network_error" ? "stream_interrupted" : c.errorCode;
|
|
6391
|
+
return { ok: false, status: 0, errorType: c.errorType, errorCode: code, message: c.message, raw: null };
|
|
6392
|
+
} finally {
|
|
6393
|
+
guard.clear();
|
|
6239
6394
|
}
|
|
6240
6395
|
const toolCalls = Array.from(toolBlocks.values()).map((b) => ({
|
|
6241
6396
|
id: b.id,
|
|
@@ -6262,6 +6417,7 @@ async function streamAnthropic(request, apiKey, opts) {
|
|
|
6262
6417
|
async function streamOpenAILike(url, request, apiKey, providerLabel, opts) {
|
|
6263
6418
|
const { provider: _provider, ...body } = request;
|
|
6264
6419
|
const fetchFn = opts.fetchImpl ?? fetch;
|
|
6420
|
+
const guard = createStallGuard(opts.signal, opts.stallTimeoutMs);
|
|
6265
6421
|
const reqBody = {
|
|
6266
6422
|
...body,
|
|
6267
6423
|
stream: true,
|
|
@@ -6272,18 +6428,23 @@ async function streamOpenAILike(url, request, apiKey, providerLabel, opts) {
|
|
|
6272
6428
|
};
|
|
6273
6429
|
let res;
|
|
6274
6430
|
try {
|
|
6431
|
+
guard.arm();
|
|
6275
6432
|
res = await fetchFn(url, {
|
|
6276
6433
|
method: "POST",
|
|
6277
6434
|
headers: {
|
|
6278
6435
|
authorization: `Bearer ${apiKey}`,
|
|
6279
6436
|
"content-type": "application/json"
|
|
6280
6437
|
},
|
|
6281
|
-
body: JSON.stringify(reqBody)
|
|
6438
|
+
body: JSON.stringify(reqBody),
|
|
6439
|
+
signal: guard.signal
|
|
6282
6440
|
});
|
|
6283
6441
|
} catch (err) {
|
|
6284
|
-
|
|
6442
|
+
guard.clear();
|
|
6443
|
+
const c = classifyThrownFetchError(err);
|
|
6444
|
+
return { ok: false, status: 0, errorType: c.errorType, errorCode: c.errorCode, message: c.message, raw: null };
|
|
6285
6445
|
}
|
|
6286
6446
|
if (!res.ok) {
|
|
6447
|
+
guard.clear();
|
|
6287
6448
|
const errBody = await res.json().catch(() => ({}));
|
|
6288
6449
|
return classifyHttpError(res.status, errBody);
|
|
6289
6450
|
}
|
|
@@ -6336,9 +6497,13 @@ async function streamOpenAILike(url, request, apiKey, providerLabel, opts) {
|
|
|
6336
6497
|
const details = usage.prompt_tokens_details;
|
|
6337
6498
|
if (typeof details?.cached_tokens === "number") cachedTokens = details.cached_tokens;
|
|
6338
6499
|
}
|
|
6339
|
-
});
|
|
6500
|
+
}, guard.arm, guard.signal);
|
|
6340
6501
|
} catch (err) {
|
|
6341
|
-
|
|
6502
|
+
const c = classifyThrownFetchError(err);
|
|
6503
|
+
const code = c.errorCode === "network_error" ? "stream_interrupted" : c.errorCode;
|
|
6504
|
+
return { ok: false, status: 0, errorType: c.errorType, errorCode: code, message: c.message, raw: null };
|
|
6505
|
+
} finally {
|
|
6506
|
+
guard.clear();
|
|
6342
6507
|
}
|
|
6343
6508
|
const toolCalls = Array.from(toolBuffers.values()).filter((b) => b.name.length > 0).map((b) => ({
|
|
6344
6509
|
id: b.id,
|
|
@@ -6361,15 +6526,28 @@ async function streamOpenAILike(url, request, apiKey, providerLabel, opts) {
|
|
|
6361
6526
|
};
|
|
6362
6527
|
return { ok: true, status: res.status, response };
|
|
6363
6528
|
}
|
|
6364
|
-
async function parseSSEStream(response, handler) {
|
|
6529
|
+
async function parseSSEStream(response, handler, onRead, signal) {
|
|
6365
6530
|
const body = response.body;
|
|
6366
6531
|
if (!body) throw new Error("Response has no body for SSE parse");
|
|
6367
6532
|
const reader = body.getReader();
|
|
6368
6533
|
const decoder = new TextDecoder("utf-8");
|
|
6369
6534
|
let buffer = "";
|
|
6535
|
+
const abortRace = signal ? new Promise((_resolve, reject) => {
|
|
6536
|
+
if (signal.aborted) return reject(signal.reason);
|
|
6537
|
+
signal.addEventListener("abort", () => reject(signal.reason), { once: true });
|
|
6538
|
+
}) : void 0;
|
|
6370
6539
|
for (; ; ) {
|
|
6371
|
-
|
|
6540
|
+
let readResult;
|
|
6541
|
+
try {
|
|
6542
|
+
readResult = abortRace ? await Promise.race([reader.read(), abortRace]) : await reader.read();
|
|
6543
|
+
} catch (err) {
|
|
6544
|
+
void reader.cancel().catch(() => {
|
|
6545
|
+
});
|
|
6546
|
+
throw err;
|
|
6547
|
+
}
|
|
6548
|
+
const { value, done } = readResult;
|
|
6372
6549
|
if (done) break;
|
|
6550
|
+
onRead?.();
|
|
6373
6551
|
buffer += decoder.decode(value, { stream: true });
|
|
6374
6552
|
let sep;
|
|
6375
6553
|
while (sep = buffer.indexOf("\n\n"), sep !== -1) {
|
|
@@ -6480,9 +6658,6 @@ function extractErrorMessage(body) {
|
|
|
6480
6658
|
if (typeof b.message === "string") return b.message;
|
|
6481
6659
|
return void 0;
|
|
6482
6660
|
}
|
|
6483
|
-
function retryableError(status, code, message, raw) {
|
|
6484
|
-
return { ok: false, status, errorType: "retryable", errorCode: code, message, raw };
|
|
6485
|
-
}
|
|
6486
6661
|
|
|
6487
6662
|
// src/execute.ts
|
|
6488
6663
|
var ANTHROPIC_URL2 = "https://api.anthropic.com/v1/messages";
|
|
@@ -6527,7 +6702,9 @@ async function executeAnthropic(request, opts) {
|
|
|
6527
6702
|
if (opts.onChunk) {
|
|
6528
6703
|
return streamAnthropic(request, apiKey, {
|
|
6529
6704
|
onChunk: opts.onChunk,
|
|
6530
|
-
fetchImpl: opts.fetchImpl
|
|
6705
|
+
fetchImpl: opts.fetchImpl,
|
|
6706
|
+
signal: opts.signal,
|
|
6707
|
+
stallTimeoutMs: opts.stallTimeoutMs
|
|
6531
6708
|
});
|
|
6532
6709
|
}
|
|
6533
6710
|
const { provider: _provider, ...body } = request;
|
|
@@ -6542,11 +6719,13 @@ async function executeAnthropic(request, opts) {
|
|
|
6542
6719
|
"anthropic-version": "2023-06-01",
|
|
6543
6720
|
"content-type": "application/json"
|
|
6544
6721
|
},
|
|
6545
|
-
body: JSON.stringify(body)
|
|
6722
|
+
body: JSON.stringify(body),
|
|
6723
|
+
signal: opts.signal
|
|
6546
6724
|
});
|
|
6547
6725
|
json = await res.json().catch(() => ({}));
|
|
6548
6726
|
} catch (err) {
|
|
6549
|
-
|
|
6727
|
+
const c = classifyThrownFetchError(err);
|
|
6728
|
+
return { ok: false, status: 0, errorType: c.errorType, errorCode: c.errorCode, message: c.message, raw: null };
|
|
6550
6729
|
}
|
|
6551
6730
|
if (!res.ok) return classifyHttpError2(res.status, json);
|
|
6552
6731
|
return { ok: true, status: res.status, response: normalizeAnthropic(json) };
|
|
@@ -6578,11 +6757,13 @@ async function executeGoogle(request, opts) {
|
|
|
6578
6757
|
res = await fetchFn(url, {
|
|
6579
6758
|
method: "POST",
|
|
6580
6759
|
headers: { "content-type": "application/json" },
|
|
6581
|
-
body: JSON.stringify(body)
|
|
6760
|
+
body: JSON.stringify(body),
|
|
6761
|
+
signal: opts.signal
|
|
6582
6762
|
});
|
|
6583
6763
|
json = await res.json().catch(() => ({}));
|
|
6584
6764
|
} catch (err) {
|
|
6585
|
-
|
|
6765
|
+
const c = classifyThrownFetchError(err);
|
|
6766
|
+
return { ok: false, status: 0, errorType: c.errorType, errorCode: c.errorCode, message: c.message, raw: null };
|
|
6586
6767
|
}
|
|
6587
6768
|
if (!res.ok) return classifyHttpError2(res.status, json);
|
|
6588
6769
|
return { ok: true, status: res.status, response: normalizeGoogle(json) };
|
|
@@ -6614,7 +6795,9 @@ async function executeOpenAI(request, opts) {
|
|
|
6614
6795
|
if (opts.onChunk) {
|
|
6615
6796
|
return streamOpenAILike(OPENAI_URL, request, apiKey, "openai", {
|
|
6616
6797
|
onChunk: opts.onChunk,
|
|
6617
|
-
fetchImpl: opts.fetchImpl
|
|
6798
|
+
fetchImpl: opts.fetchImpl,
|
|
6799
|
+
signal: opts.signal,
|
|
6800
|
+
stallTimeoutMs: opts.stallTimeoutMs
|
|
6618
6801
|
});
|
|
6619
6802
|
}
|
|
6620
6803
|
const { provider: _provider, ...body } = request;
|
|
@@ -6625,11 +6808,13 @@ async function executeOpenAI(request, opts) {
|
|
|
6625
6808
|
res = await fetchFn(OPENAI_URL, {
|
|
6626
6809
|
method: "POST",
|
|
6627
6810
|
headers: { authorization: `Bearer ${apiKey}`, "content-type": "application/json" },
|
|
6628
|
-
body: JSON.stringify(body)
|
|
6811
|
+
body: JSON.stringify(body),
|
|
6812
|
+
signal: opts.signal
|
|
6629
6813
|
});
|
|
6630
6814
|
json = await res.json().catch(() => ({}));
|
|
6631
6815
|
} catch (err) {
|
|
6632
|
-
|
|
6816
|
+
const c = classifyThrownFetchError(err);
|
|
6817
|
+
return { ok: false, status: 0, errorType: c.errorType, errorCode: c.errorCode, message: c.message, raw: null };
|
|
6633
6818
|
}
|
|
6634
6819
|
if (!res.ok) return classifyHttpError2(res.status, json);
|
|
6635
6820
|
return { ok: true, status: res.status, response: normalizeOpenAILike(json) };
|
|
@@ -6642,7 +6827,9 @@ async function executeDeepSeek(request, opts) {
|
|
|
6642
6827
|
if (opts.onChunk) {
|
|
6643
6828
|
return streamOpenAILike(DEEPSEEK_URL, request, apiKey, "deepseek", {
|
|
6644
6829
|
onChunk: opts.onChunk,
|
|
6645
|
-
fetchImpl: opts.fetchImpl
|
|
6830
|
+
fetchImpl: opts.fetchImpl,
|
|
6831
|
+
signal: opts.signal,
|
|
6832
|
+
stallTimeoutMs: opts.stallTimeoutMs
|
|
6646
6833
|
});
|
|
6647
6834
|
}
|
|
6648
6835
|
const { provider: _provider, ...body } = request;
|
|
@@ -6653,11 +6840,13 @@ async function executeDeepSeek(request, opts) {
|
|
|
6653
6840
|
res = await fetchFn(DEEPSEEK_URL, {
|
|
6654
6841
|
method: "POST",
|
|
6655
6842
|
headers: { authorization: `Bearer ${apiKey}`, "content-type": "application/json" },
|
|
6656
|
-
body: JSON.stringify(body)
|
|
6843
|
+
body: JSON.stringify(body),
|
|
6844
|
+
signal: opts.signal
|
|
6657
6845
|
});
|
|
6658
6846
|
json = await res.json().catch(() => ({}));
|
|
6659
6847
|
} catch (err) {
|
|
6660
|
-
|
|
6848
|
+
const c = classifyThrownFetchError(err);
|
|
6849
|
+
return { ok: false, status: 0, errorType: c.errorType, errorCode: c.errorCode, message: c.message, raw: null };
|
|
6661
6850
|
}
|
|
6662
6851
|
if (!res.ok) return classifyHttpError2(res.status, json);
|
|
6663
6852
|
return { ok: true, status: res.status, response: normalizeOpenAILike(json) };
|
|
@@ -6670,7 +6859,9 @@ async function executeOpenAICompatible(request, opts, spec) {
|
|
|
6670
6859
|
if (opts.onChunk) {
|
|
6671
6860
|
return streamOpenAILike(spec.url, request, apiKey, spec.provider, {
|
|
6672
6861
|
onChunk: opts.onChunk,
|
|
6673
|
-
fetchImpl: opts.fetchImpl
|
|
6862
|
+
fetchImpl: opts.fetchImpl,
|
|
6863
|
+
signal: opts.signal,
|
|
6864
|
+
stallTimeoutMs: opts.stallTimeoutMs
|
|
6674
6865
|
});
|
|
6675
6866
|
}
|
|
6676
6867
|
const { provider: _provider, ...body } = request;
|
|
@@ -6681,11 +6872,13 @@ async function executeOpenAICompatible(request, opts, spec) {
|
|
|
6681
6872
|
res = await fetchFn(spec.url, {
|
|
6682
6873
|
method: "POST",
|
|
6683
6874
|
headers: { authorization: `Bearer ${apiKey}`, "content-type": "application/json" },
|
|
6684
|
-
body: JSON.stringify(body)
|
|
6875
|
+
body: JSON.stringify(body),
|
|
6876
|
+
signal: opts.signal
|
|
6685
6877
|
});
|
|
6686
6878
|
json = await res.json().catch(() => ({}));
|
|
6687
6879
|
} catch (err) {
|
|
6688
|
-
|
|
6880
|
+
const c = classifyThrownFetchError(err);
|
|
6881
|
+
return { ok: false, status: 0, errorType: c.errorType, errorCode: c.errorCode, message: c.message, raw: null };
|
|
6689
6882
|
}
|
|
6690
6883
|
if (!res.ok) return classifyHttpError2(res.status, json);
|
|
6691
6884
|
return { ok: true, status: res.status, response: normalizeOpenAILike(json) };
|
|
@@ -6755,9 +6948,6 @@ function extractErrorMessage2(body) {
|
|
|
6755
6948
|
function terminalError(status, code, message) {
|
|
6756
6949
|
return { ok: false, status, errorType: "terminal", errorCode: code, message, raw: null };
|
|
6757
6950
|
}
|
|
6758
|
-
function retryableError2(status, code, message, raw) {
|
|
6759
|
-
return { ok: false, status, errorType: "retryable", errorCode: code, message, raw };
|
|
6760
|
-
}
|
|
6761
6951
|
function tryParseJson2(s) {
|
|
6762
6952
|
if (typeof s !== "string" || s.length === 0) return void 0;
|
|
6763
6953
|
try {
|
|
@@ -7566,6 +7756,15 @@ async function call(ir, opts = {}) {
|
|
|
7566
7756
|
let retriedSameModel = false;
|
|
7567
7757
|
for (let i = 0; i < targetsToTry.length; i++) {
|
|
7568
7758
|
const targetModel = targetsToTry[i];
|
|
7759
|
+
if (opts.abortSignal?.aborted) {
|
|
7760
|
+
attempts.push({
|
|
7761
|
+
model: targetModel,
|
|
7762
|
+
status: "terminal",
|
|
7763
|
+
errorCode: "aborted",
|
|
7764
|
+
message: "Skipped \u2014 caller abortSignal fired before this attempt started"
|
|
7765
|
+
});
|
|
7766
|
+
break;
|
|
7767
|
+
}
|
|
7569
7768
|
const targetProfile = tryGetProfile(targetModel);
|
|
7570
7769
|
const providerFailReason = targetProfile ? failedProviders.get(targetProfile.provider) : void 0;
|
|
7571
7770
|
if (targetProfile && providerFailReason && !opts.noFallback) {
|
|
@@ -7602,16 +7801,29 @@ async function call(ir, opts = {}) {
|
|
|
7602
7801
|
);
|
|
7603
7802
|
const targetSupportsStreaming = targetProfile?.streaming === true;
|
|
7604
7803
|
const streamingOnChunk = opts.onChunk && !opts.noStream && targetSupportsStreaming ? opts.onChunk : void 0;
|
|
7605
|
-
const
|
|
7804
|
+
const mkExecOpts = () => ({
|
|
7606
7805
|
apiKeys: opts.apiKeys,
|
|
7607
7806
|
fetchImpl: opts.fetchImpl,
|
|
7608
7807
|
providerOverrides: opts.providerOverrides,
|
|
7609
|
-
onChunk: streamingOnChunk
|
|
7610
|
-
|
|
7611
|
-
|
|
7808
|
+
onChunk: streamingOnChunk,
|
|
7809
|
+
signal: composeAttemptSignal(
|
|
7810
|
+
streamingOnChunk ? void 0 : opts.attemptTimeoutMs,
|
|
7811
|
+
opts.abortSignal
|
|
7812
|
+
),
|
|
7813
|
+
stallTimeoutMs: streamingOnChunk ? opts.attemptTimeoutMs : void 0
|
|
7814
|
+
});
|
|
7815
|
+
const exec = await execute(activeCompile.request, mkExecOpts());
|
|
7612
7816
|
let validated = exec.ok ? validateStructuredContract(exec, ir) : exec;
|
|
7613
7817
|
let servedByRetry = false;
|
|
7614
|
-
|
|
7818
|
+
let retrySuppressionNote;
|
|
7819
|
+
if (!validated.ok && isStructuredContractViolation(validated.errorCode) && sameModelRetryEnabled && !retriedSameModel && getMeasuredFailureVerdict({
|
|
7820
|
+
appId: ir.appId,
|
|
7821
|
+
archetype: ir.intent.archetype,
|
|
7822
|
+
model: targetModel
|
|
7823
|
+
})?.gated === true) {
|
|
7824
|
+
retrySuppressionNote = " [sameModelRetry suppressed: this model carries an active measured-failure gate for this archetype \u2014 retrying it would near-certainly bill a second doomed inference; walking the chain instead]";
|
|
7825
|
+
}
|
|
7826
|
+
if (!validated.ok && isStructuredContractViolation(validated.errorCode) && sameModelRetryEnabled && !retriedSameModel && !retrySuppressionNote) {
|
|
7615
7827
|
retriedSameModel = true;
|
|
7616
7828
|
attempts.push({
|
|
7617
7829
|
model: targetModel,
|
|
@@ -7623,7 +7835,7 @@ async function call(ir, opts = {}) {
|
|
|
7623
7835
|
safeEmit(
|
|
7624
7836
|
() => emitExecuteAttempt(traceId, ir.appId, { model: targetModel, attemptIndex: i })
|
|
7625
7837
|
);
|
|
7626
|
-
const retryExec = await execute(retryRequest,
|
|
7838
|
+
const retryExec = await execute(retryRequest, mkExecOpts());
|
|
7627
7839
|
validated = retryExec.ok ? validateStructuredContract(retryExec, ir) : retryExec;
|
|
7628
7840
|
servedByRetry = true;
|
|
7629
7841
|
}
|
|
@@ -7750,7 +7962,7 @@ async function call(ir, opts = {}) {
|
|
|
7750
7962
|
model: targetModel,
|
|
7751
7963
|
status: validated.errorType,
|
|
7752
7964
|
errorCode: validated.errorCode,
|
|
7753
|
-
message: validated.message,
|
|
7965
|
+
message: retrySuppressionNote ? validated.message + retrySuppressionNote : validated.message,
|
|
7754
7966
|
...servedByRetry ? { sameModelRetry: true } : {}
|
|
7755
7967
|
});
|
|
7756
7968
|
lastErr = validated;
|
|
@@ -7789,6 +8001,25 @@ async function call(ir, opts = {}) {
|
|
|
7789
8001
|
lastErr?.errorCode
|
|
7790
8002
|
);
|
|
7791
8003
|
}
|
|
8004
|
+
function composeAttemptSignal(attemptTimeoutMs, callerSignal) {
|
|
8005
|
+
const signals = [];
|
|
8006
|
+
if (callerSignal) signals.push(callerSignal);
|
|
8007
|
+
if (typeof attemptTimeoutMs === "number" && attemptTimeoutMs > 0) {
|
|
8008
|
+
signals.push(AbortSignal.timeout(attemptTimeoutMs));
|
|
8009
|
+
}
|
|
8010
|
+
if (signals.length === 0) return void 0;
|
|
8011
|
+
if (signals.length === 1) return signals[0];
|
|
8012
|
+
if (typeof AbortSignal.any === "function") return AbortSignal.any(signals);
|
|
8013
|
+
const ctl = new AbortController();
|
|
8014
|
+
for (const s of signals) {
|
|
8015
|
+
if (s.aborted) {
|
|
8016
|
+
ctl.abort(s.reason);
|
|
8017
|
+
break;
|
|
8018
|
+
}
|
|
8019
|
+
s.addEventListener("abort", () => ctl.abort(s.reason), { once: true });
|
|
8020
|
+
}
|
|
8021
|
+
return ctl.signal;
|
|
8022
|
+
}
|
|
7792
8023
|
function compileAndRegister(ir, opts) {
|
|
7793
8024
|
const result = compile(ir, {
|
|
7794
8025
|
policy: opts.policy,
|
|
@@ -8843,6 +9074,12 @@ async function runGoldenEval(opts) {
|
|
|
8843
9074
|
);
|
|
8844
9075
|
}
|
|
8845
9076
|
}
|
|
9077
|
+
if (wins + ties + losses === 0) {
|
|
9078
|
+
notes.push(
|
|
9079
|
+
"zero cases judged \u2014 run row persisted, evidence advisory deliberately NOT written (a verdict on n=0 is not evidence)"
|
|
9080
|
+
);
|
|
9081
|
+
return result;
|
|
9082
|
+
}
|
|
8846
9083
|
const latestRes = await fetchFn(
|
|
8847
9084
|
rest(
|
|
8848
9085
|
`compile_outcomes?app_id=eq.${encodeURIComponent(opts.appId)}&select=id&order=id.desc&limit=1`
|
|
@@ -9078,7 +9315,7 @@ function createBrainForwardRoutes(config) {
|
|
|
9078
9315
|
}
|
|
9079
9316
|
|
|
9080
9317
|
// src/version.ts
|
|
9081
|
-
var LIBRARY_VERSION = "2.0.0-alpha.
|
|
9318
|
+
var LIBRARY_VERSION = "2.0.0-alpha.79";
|
|
9082
9319
|
|
|
9083
9320
|
// src/key-health.ts
|
|
9084
9321
|
var JSON_HEADERS2 = { "Content-Type": "application/json" };
|
|
@@ -9364,6 +9601,171 @@ function clamp(n) {
|
|
|
9364
9601
|
return Math.max(0, Math.min(1, n));
|
|
9365
9602
|
}
|
|
9366
9603
|
|
|
9604
|
+
// src/delegate.ts
|
|
9605
|
+
function isDelegateEnabledFromEnv(envSource) {
|
|
9606
|
+
const env = envSource ?? (typeof process !== "undefined" && process.env ? process.env : {});
|
|
9607
|
+
const raw = (env.KGAUTO_DELEGATE ?? "").trim().toLowerCase();
|
|
9608
|
+
return raw === "1" || raw === "true";
|
|
9609
|
+
}
|
|
9610
|
+
var DELEGATE_TOOL_DEFINITION = {
|
|
9611
|
+
name: "delegate",
|
|
9612
|
+
description: "Delegate a self-contained sub-task to a cheaper executor model chosen by kgauto from measured evidence. YOU decide what to delegate and supply a complete input; kgauto decides which model runs it (never outside the declared pool). The call may be refused (budget exhausted, no qualified executor) \u2014 on refusal, continue and compose with what you have. Verify sub-results before composing them into your answer; do not present unverified delegated content as checked.",
|
|
9613
|
+
inputSchema: {
|
|
9614
|
+
type: "object",
|
|
9615
|
+
properties: {
|
|
9616
|
+
sub_archetype: {
|
|
9617
|
+
type: "string",
|
|
9618
|
+
enum: ALL_ARCHETYPES,
|
|
9619
|
+
description: "What kind of work the sub-task is (its routing archetype)."
|
|
9620
|
+
},
|
|
9621
|
+
input: {
|
|
9622
|
+
type: "string",
|
|
9623
|
+
description: "Complete, self-contained sub-task input. Include everything the executor needs \u2014 it sees nothing else."
|
|
9624
|
+
},
|
|
9625
|
+
quality_floor: {
|
|
9626
|
+
type: "number",
|
|
9627
|
+
minimum: 0,
|
|
9628
|
+
maximum: 10,
|
|
9629
|
+
description: "Optional minimum executor quality score (0-10) for this archetype. Omit to accept the evidence-ranked default."
|
|
9630
|
+
}
|
|
9631
|
+
},
|
|
9632
|
+
required: ["sub_archetype", "input"],
|
|
9633
|
+
additionalProperties: false
|
|
9634
|
+
}
|
|
9635
|
+
};
|
|
9636
|
+
function createDelegate(opts) {
|
|
9637
|
+
const { parentIr, parentHandle } = opts;
|
|
9638
|
+
const enabled = opts.enabled ?? isDelegateEnabledFromEnv();
|
|
9639
|
+
const budget = opts.callOpts?.policy?.maxCostPerTraceUsd;
|
|
9640
|
+
let spentUsd = 0;
|
|
9641
|
+
async function handler(args) {
|
|
9642
|
+
if (!enabled) {
|
|
9643
|
+
return {
|
|
9644
|
+
ok: false,
|
|
9645
|
+
reason: "delegate_not_enabled",
|
|
9646
|
+
detail: "Delegation is not enabled for this consumer (KGAUTO_DELEGATE / CreateDelegateOpts.enabled). Do the sub-task yourself."
|
|
9647
|
+
};
|
|
9648
|
+
}
|
|
9649
|
+
const archetype = args.sub_archetype;
|
|
9650
|
+
if (!ALL_ARCHETYPES.includes(archetype)) {
|
|
9651
|
+
return {
|
|
9652
|
+
ok: false,
|
|
9653
|
+
reason: "invalid_sub_archetype",
|
|
9654
|
+
detail: `Unknown sub_archetype '${String(args.sub_archetype)}'. Valid: ${ALL_ARCHETYPES.join(", ")}. Re-classify or do the sub-task yourself.`
|
|
9655
|
+
};
|
|
9656
|
+
}
|
|
9657
|
+
const pool = parentIr.models;
|
|
9658
|
+
const concreteIds = pool.filter((m) => typeof m === "string");
|
|
9659
|
+
let blockedByFloor = [];
|
|
9660
|
+
if (typeof args.quality_floor === "number") {
|
|
9661
|
+
blockedByFloor = concreteIds.filter(
|
|
9662
|
+
(m) => getArchetypePerfScore(m, archetype).score < args.quality_floor
|
|
9663
|
+
);
|
|
9664
|
+
if (blockedByFloor.length === pool.length) {
|
|
9665
|
+
const scores = concreteIds.map((m) => `${m}=${getArchetypePerfScore(m, archetype).score}`).join(", ");
|
|
9666
|
+
return {
|
|
9667
|
+
ok: false,
|
|
9668
|
+
reason: "no_qualified_executor",
|
|
9669
|
+
detail: `No model in the declared pool clears quality_floor=${args.quality_floor} for '${archetype}' (${scores}). Lower the floor or do the sub-task yourself.`
|
|
9670
|
+
};
|
|
9671
|
+
}
|
|
9672
|
+
}
|
|
9673
|
+
const subIr = {
|
|
9674
|
+
appId: parentIr.appId,
|
|
9675
|
+
intent: { name: `delegate:${archetype}`, archetype },
|
|
9676
|
+
sections: [{ id: "delegated-task", text: args.input }],
|
|
9677
|
+
currentTurn: { role: "user", content: args.input },
|
|
9678
|
+
models: pool
|
|
9679
|
+
};
|
|
9680
|
+
const mergedPolicy = {
|
|
9681
|
+
...opts.callOpts?.policy ?? {},
|
|
9682
|
+
blockedModels: [
|
|
9683
|
+
...opts.callOpts?.policy?.blockedModels ?? [],
|
|
9684
|
+
...blockedByFloor
|
|
9685
|
+
]
|
|
9686
|
+
};
|
|
9687
|
+
if (typeof budget === "number" && budget > 0) {
|
|
9688
|
+
let estimate = 0;
|
|
9689
|
+
try {
|
|
9690
|
+
estimate = compile(subIr, { policy: mergedPolicy }).estimatedCostUsd;
|
|
9691
|
+
} catch {
|
|
9692
|
+
estimate = 0;
|
|
9693
|
+
}
|
|
9694
|
+
if (spentUsd + estimate > budget) {
|
|
9695
|
+
return {
|
|
9696
|
+
ok: false,
|
|
9697
|
+
reason: "trace_budget_exhausted",
|
|
9698
|
+
detail: `Trace budget $${budget.toFixed(4)} would be exceeded (spent $${spentUsd.toFixed(4)} + estimated $${estimate.toFixed(4)}). Compose your answer from the sub-results you already have.`
|
|
9699
|
+
};
|
|
9700
|
+
}
|
|
9701
|
+
}
|
|
9702
|
+
let result;
|
|
9703
|
+
try {
|
|
9704
|
+
result = await call(subIr, {
|
|
9705
|
+
...opts.callOpts ?? {},
|
|
9706
|
+
policy: mergedPolicy,
|
|
9707
|
+
parentHandle
|
|
9708
|
+
// R0 linkage — branch row, trace_id = parent
|
|
9709
|
+
});
|
|
9710
|
+
} catch (err) {
|
|
9711
|
+
const detail = err instanceof CallError ? `Sub-call failed after ${err.attempts.length} attempt(s): ${err.attempts.map((a) => a.errorCode).join(" \u2192 ")}.` : String(err);
|
|
9712
|
+
return {
|
|
9713
|
+
ok: false,
|
|
9714
|
+
reason: "call_failed",
|
|
9715
|
+
detail: `${detail} Compose without this sub-result or retry with different input.`
|
|
9716
|
+
};
|
|
9717
|
+
}
|
|
9718
|
+
const profile = tryGetProfile(result.actualModel);
|
|
9719
|
+
const costUsd2 = profile ? result.response.tokens.input / 1e6 * profile.costInputPer1m + result.response.tokens.output / 1e6 * profile.costOutputPer1m : 0;
|
|
9720
|
+
spentUsd += costUsd2;
|
|
9721
|
+
return {
|
|
9722
|
+
ok: true,
|
|
9723
|
+
output: result.response.structuredOutput !== null ? JSON.stringify(result.response.structuredOutput) : result.response.text,
|
|
9724
|
+
subHandle: result.handle,
|
|
9725
|
+
executorModel: result.actualModel,
|
|
9726
|
+
costUsd: costUsd2,
|
|
9727
|
+
latencyMs: result.latencyMs,
|
|
9728
|
+
verification: "trusted"
|
|
9729
|
+
};
|
|
9730
|
+
}
|
|
9731
|
+
async function reportComposition(report) {
|
|
9732
|
+
const env = readBrainReadEnv();
|
|
9733
|
+
if (!env.endpoint || !env.jwt || !env.anonKey) {
|
|
9734
|
+
return { ok: false, reason: `brain_read_not_configured:${env.missingEnv.join(",")}` };
|
|
9735
|
+
}
|
|
9736
|
+
try {
|
|
9737
|
+
const res = await fetch(
|
|
9738
|
+
`${env.endpoint.replace(/\/$/, "")}/rest/v1/kgauto_composition_reports`,
|
|
9739
|
+
{
|
|
9740
|
+
method: "POST",
|
|
9741
|
+
headers: {
|
|
9742
|
+
Authorization: `Bearer ${env.jwt}`,
|
|
9743
|
+
apikey: env.anonKey,
|
|
9744
|
+
"Content-Type": "application/json",
|
|
9745
|
+
Prefer: "return=minimal"
|
|
9746
|
+
},
|
|
9747
|
+
body: JSON.stringify({
|
|
9748
|
+
app_id: parentIr.appId,
|
|
9749
|
+
sub_handle: report.subHandle,
|
|
9750
|
+
disposition: report.disposition,
|
|
9751
|
+
...report.note ? { note: report.note } : {}
|
|
9752
|
+
})
|
|
9753
|
+
}
|
|
9754
|
+
);
|
|
9755
|
+
if (!res.ok) return { ok: false, reason: `write_failed:${res.status}` };
|
|
9756
|
+
return { ok: true };
|
|
9757
|
+
} catch (err) {
|
|
9758
|
+
return { ok: false, reason: `network_error:${err instanceof Error ? err.message : String(err)}` };
|
|
9759
|
+
}
|
|
9760
|
+
}
|
|
9761
|
+
return {
|
|
9762
|
+
toolDefinition: DELEGATE_TOOL_DEFINITION,
|
|
9763
|
+
handler,
|
|
9764
|
+
reportComposition,
|
|
9765
|
+
traceSpendUsd: () => spentUsd
|
|
9766
|
+
};
|
|
9767
|
+
}
|
|
9768
|
+
|
|
9367
9769
|
// src/advisories-api.ts
|
|
9368
9770
|
var SEVERITY_SET = /* @__PURE__ */ new Set(["info", "warn", "critical"]);
|
|
9369
9771
|
var STATUS_SET = /* @__PURE__ */ new Set(["open", "snoozed", "resolved"]);
|
|
@@ -9435,19 +9837,32 @@ function resolveFetch(injected) {
|
|
|
9435
9837
|
function normalizeEndpoint2(endpoint) {
|
|
9436
9838
|
return endpoint.replace(/\/+$/, "");
|
|
9437
9839
|
}
|
|
9840
|
+
function resolveBrainReadTrio(opts) {
|
|
9841
|
+
const env = readBrainReadEnv();
|
|
9842
|
+
const brainEndpoint = opts.brainEndpoint ?? env.endpoint;
|
|
9843
|
+
const brainJwt = opts.brainJwt ?? env.jwt;
|
|
9844
|
+
const brainAnonKey = opts.brainAnonKey ?? env.anonKey;
|
|
9845
|
+
if (brainEndpoint && brainJwt && brainAnonKey) {
|
|
9846
|
+
return { ok: true, brainEndpoint, brainJwt, brainAnonKey };
|
|
9847
|
+
}
|
|
9848
|
+
const missingEnv = [];
|
|
9849
|
+
if (!brainEndpoint) missingEnv.push("KGAUTO_V2_BRAIN_SUPABASE_URL");
|
|
9850
|
+
if (!brainJwt) missingEnv.push("KGAUTO_V2_BRAIN_JWT");
|
|
9851
|
+
if (!brainAnonKey) missingEnv.push("KGAUTO_V2_BRAIN_ANON_KEY");
|
|
9852
|
+
return { ok: false, missingEnv };
|
|
9853
|
+
}
|
|
9438
9854
|
async function getActionableAdvisories(opts) {
|
|
9439
|
-
const {
|
|
9440
|
-
appId,
|
|
9441
|
-
severity,
|
|
9442
|
-
status,
|
|
9443
|
-
brainEndpoint,
|
|
9444
|
-
brainJwt,
|
|
9445
|
-
brainAnonKey,
|
|
9446
|
-
fetch: injectedFetch
|
|
9447
|
-
} = opts;
|
|
9855
|
+
const { appId, severity, status, fetch: injectedFetch } = opts;
|
|
9448
9856
|
if (!appId) {
|
|
9449
9857
|
throw new Error("getActionableAdvisories: appId is required");
|
|
9450
9858
|
}
|
|
9859
|
+
const trio = resolveBrainReadTrio(opts);
|
|
9860
|
+
if (!trio.ok) {
|
|
9861
|
+
throw new Error(
|
|
9862
|
+
`getActionableAdvisories: brain-read-not-configured \u2014 missing ${trio.missingEnv.join(", ")} (pass brainEndpoint/brainJwt/brainAnonKey explicitly or set the canonical env vars)`
|
|
9863
|
+
);
|
|
9864
|
+
}
|
|
9865
|
+
const { brainEndpoint, brainJwt, brainAnonKey } = trio;
|
|
9451
9866
|
const doFetch = resolveFetch(injectedFetch);
|
|
9452
9867
|
const base = normalizeEndpoint2(brainEndpoint);
|
|
9453
9868
|
const qs = new URLSearchParams();
|
|
@@ -9500,17 +9915,15 @@ async function getActionableAdvisories(opts) {
|
|
|
9500
9915
|
return out;
|
|
9501
9916
|
}
|
|
9502
9917
|
async function markAdvisoryResolved(opts) {
|
|
9503
|
-
const {
|
|
9504
|
-
id,
|
|
9505
|
-
resolutionNote,
|
|
9506
|
-
brainEndpoint,
|
|
9507
|
-
brainJwt,
|
|
9508
|
-
brainAnonKey,
|
|
9509
|
-
fetch: injectedFetch
|
|
9510
|
-
} = opts;
|
|
9918
|
+
const { id, resolutionNote, fetch: injectedFetch } = opts;
|
|
9511
9919
|
if (!id) {
|
|
9512
9920
|
return { ok: false, reason: "id_required" };
|
|
9513
9921
|
}
|
|
9922
|
+
const trio = resolveBrainReadTrio(opts);
|
|
9923
|
+
if (!trio.ok) {
|
|
9924
|
+
return { ok: false, reason: `brain_read_not_configured:${trio.missingEnv.join(",")}` };
|
|
9925
|
+
}
|
|
9926
|
+
const { brainEndpoint, brainJwt, brainAnonKey } = trio;
|
|
9514
9927
|
const doFetch = resolveFetch(injectedFetch);
|
|
9515
9928
|
const base = normalizeEndpoint2(brainEndpoint);
|
|
9516
9929
|
const lookupUrl = `${base}/rest/v1/actionable_advisories_v?id=eq.${encodeURIComponent(id)}&select=app_id,rule`;
|
|
@@ -9595,7 +10008,7 @@ async function markAdvisoryResolved(opts) {
|
|
|
9595
10008
|
}
|
|
9596
10009
|
}
|
|
9597
10010
|
if (outcomeIds.length === 0) {
|
|
9598
|
-
return { ok: true };
|
|
10011
|
+
return { ok: true, firingsResolved: 0, status: "unknown" };
|
|
9599
10012
|
}
|
|
9600
10013
|
const inList = outcomeIds.join(",");
|
|
9601
10014
|
const patchUrl = `${base}/rest/v1/compile_outcome_advisories?outcome_id=in.(${inList})&code=eq.${encodeURIComponent(code)}&resolved_at=is.null`;
|
|
@@ -9615,8 +10028,10 @@ async function markAdvisoryResolved(opts) {
|
|
|
9615
10028
|
apikey: brainAnonKey,
|
|
9616
10029
|
"Content-Type": "application/json",
|
|
9617
10030
|
Accept: "application/json",
|
|
9618
|
-
//
|
|
9619
|
-
|
|
10031
|
+
// alpha.78 — count what actually changed. An RLS-filtered PATCH
|
|
10032
|
+
// returns 2xx with zero rows; return=representation makes that
|
|
10033
|
+
// visible instead of success-shaped.
|
|
10034
|
+
Prefer: "return=representation"
|
|
9620
10035
|
},
|
|
9621
10036
|
body: JSON.stringify(patchBody)
|
|
9622
10037
|
});
|
|
@@ -9633,7 +10048,33 @@ async function markAdvisoryResolved(opts) {
|
|
|
9633
10048
|
if (!patchRes.ok) {
|
|
9634
10049
|
return { ok: false, reason: `patch_failed:${patchRes.status}` };
|
|
9635
10050
|
}
|
|
9636
|
-
|
|
10051
|
+
let patchedRows = [];
|
|
10052
|
+
try {
|
|
10053
|
+
patchedRows = await patchRes.json();
|
|
10054
|
+
} catch {
|
|
10055
|
+
}
|
|
10056
|
+
const firingsResolved = Array.isArray(patchedRows) ? patchedRows.length : 0;
|
|
10057
|
+
let status = "unknown";
|
|
10058
|
+
try {
|
|
10059
|
+
const statusRes = await doFetch(
|
|
10060
|
+
`${base}/rest/v1/actionable_advisories_v?id=eq.${encodeURIComponent(id)}&select=status`,
|
|
10061
|
+
{
|
|
10062
|
+
method: "GET",
|
|
10063
|
+
headers: {
|
|
10064
|
+
Authorization: `Bearer ${brainJwt}`,
|
|
10065
|
+
apikey: brainAnonKey,
|
|
10066
|
+
Accept: "application/json"
|
|
10067
|
+
}
|
|
10068
|
+
}
|
|
10069
|
+
);
|
|
10070
|
+
if (statusRes.ok) {
|
|
10071
|
+
const rows = await statusRes.json();
|
|
10072
|
+
const s = Array.isArray(rows) ? rows[0]?.status : void 0;
|
|
10073
|
+
if (s === "open" || s === "resolved") status = s;
|
|
10074
|
+
}
|
|
10075
|
+
} catch {
|
|
10076
|
+
}
|
|
10077
|
+
return { ok: true, firingsResolved, status };
|
|
9637
10078
|
}
|
|
9638
10079
|
async function markExclusionFindingHandled(opts) {
|
|
9639
10080
|
const {
|
|
@@ -9642,12 +10083,14 @@ async function markExclusionFindingHandled(opts) {
|
|
|
9642
10083
|
excludedModel,
|
|
9643
10084
|
resolution,
|
|
9644
10085
|
resolutionNote,
|
|
9645
|
-
brainEndpoint,
|
|
9646
|
-
brainJwt,
|
|
9647
|
-
brainAnonKey,
|
|
9648
10086
|
fetch: injectedFetch
|
|
9649
10087
|
} = opts;
|
|
9650
10088
|
if (!appId) return { ok: false, reason: "app_id_required" };
|
|
10089
|
+
const trio = resolveBrainReadTrio(opts);
|
|
10090
|
+
if (!trio.ok) {
|
|
10091
|
+
return { ok: false, reason: `brain_read_not_configured:${trio.missingEnv.join(",")}` };
|
|
10092
|
+
}
|
|
10093
|
+
const { brainEndpoint, brainJwt, brainAnonKey } = trio;
|
|
9651
10094
|
if (!archetype) return { ok: false, reason: "archetype_required" };
|
|
9652
10095
|
if (!excludedModel) {
|
|
9653
10096
|
return { ok: false, reason: "excluded_model_required" };
|
|
@@ -9914,6 +10357,7 @@ function compile2(ir, opts) {
|
|
|
9914
10357
|
ALL_ARCHETYPES,
|
|
9915
10358
|
ARCHETYPE_FAMILY_FITS,
|
|
9916
10359
|
ARCHETYPE_FLOOR_DEFAULT,
|
|
10360
|
+
BRAIN_READ_ENV_NAMES,
|
|
9917
10361
|
COACH_CFG,
|
|
9918
10362
|
CallError,
|
|
9919
10363
|
DECOMPOSITION_TEMPLATES,
|
|
@@ -9921,6 +10365,7 @@ function compile2(ir, opts) {
|
|
|
9921
10365
|
DEFAULT_FINDINGS_ENDPOINT,
|
|
9922
10366
|
DEFAULT_MEASURED_FAILURE_ENDPOINT,
|
|
9923
10367
|
DEFAULT_PROMOTIONS_ENDPOINT,
|
|
10368
|
+
DELEGATE_TOOL_DEFINITION,
|
|
9924
10369
|
DIALECT_VERSION,
|
|
9925
10370
|
DISCIPLINE_GATES_V1_ALT_HEADER,
|
|
9926
10371
|
FamilyResolutionError,
|
|
@@ -9932,6 +10377,7 @@ function compile2(ir, opts) {
|
|
|
9932
10377
|
MEASURED_GROUNDING_MIN_N,
|
|
9933
10378
|
PRODUCER_OWNED_RULE_CODES,
|
|
9934
10379
|
PROVIDER_ENV_KEYS,
|
|
10380
|
+
ROLLBACK_SUPPRESSION_WINDOW_DAYS,
|
|
9935
10381
|
RULE_DISCIPLINE_GATES_V1,
|
|
9936
10382
|
RULE_DISCIPLINE_GATES_V1_STRUCTURED,
|
|
9937
10383
|
RULE_SEQUENTIAL_TOOL_CLIFF,
|
|
@@ -9967,6 +10413,7 @@ function compile2(ir, opts) {
|
|
|
9967
10413
|
configurePromotionsBrain,
|
|
9968
10414
|
countTokens,
|
|
9969
10415
|
createBrainForwardRoutes,
|
|
10416
|
+
createDelegate,
|
|
9970
10417
|
createKeyHealthRoute,
|
|
9971
10418
|
deriveFamilyFromModelId,
|
|
9972
10419
|
deriveOwnership,
|
|
@@ -9985,17 +10432,20 @@ function compile2(ir, opts) {
|
|
|
9985
10432
|
getPerAxisMetrics,
|
|
9986
10433
|
getProfile,
|
|
9987
10434
|
getReachabilityDiagnostic,
|
|
10435
|
+
getRecentRollback,
|
|
9988
10436
|
getRecommendedPrimary,
|
|
9989
10437
|
getSequentialStarterChain,
|
|
9990
10438
|
getSequentialStarterChainWithGrounding,
|
|
9991
10439
|
getStaleExclusionFindings,
|
|
9992
10440
|
getStarterChain,
|
|
9993
10441
|
getStarterChainWithGrounding,
|
|
10442
|
+
hasMutation,
|
|
9994
10443
|
hashShape,
|
|
9995
10444
|
isArchetype,
|
|
9996
10445
|
isAutoPromoteEnabledFromEnv,
|
|
9997
10446
|
isBrainQueryActiveFor,
|
|
9998
10447
|
isBrainSync,
|
|
10448
|
+
isDelegateEnabledFromEnv,
|
|
9999
10449
|
isExclusionFindingsBrainActive,
|
|
10000
10450
|
isMeasuredFailureBrainActive,
|
|
10001
10451
|
isMeasuredFailureGateEnabledFromEnv,
|
|
@@ -10011,9 +10461,11 @@ function compile2(ir, opts) {
|
|
|
10011
10461
|
loadChainsFromBrain,
|
|
10012
10462
|
loadModelsFromBrain,
|
|
10013
10463
|
loadPricingFromBrain,
|
|
10464
|
+
mapMeasuredFailureRows,
|
|
10014
10465
|
markAdvisoryResolved,
|
|
10015
10466
|
markExclusionFindingHandled,
|
|
10016
10467
|
markPromoteReadyHandled,
|
|
10468
|
+
mutationId,
|
|
10017
10469
|
parseGoldenCaptureRate,
|
|
10018
10470
|
parseJudgeVerdict,
|
|
10019
10471
|
peekBrainDeadLetter,
|