@warmdrift/kgauto-compiler 2.0.0-alpha.60 → 2.0.0-alpha.62
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/README.md +81 -46
- package/dist/brain-proxy.js +5 -1
- package/dist/brain-proxy.mjs +1 -1
- package/dist/{chunk-5TI6PNSK.mjs → chunk-3KQAID63.mjs} +5 -0
- package/dist/{chunk-IUWFML6Z.mjs → chunk-65ZMX5OT.mjs} +5 -1
- package/dist/{chunk-RQ3BUUB6.mjs → chunk-ABFXMO73.mjs} +1 -1
- package/dist/{chunk-IIMPJZNH.mjs → chunk-YZRPNSSQ.mjs} +10 -0
- package/dist/dialect.d.mts +14 -2
- package/dist/dialect.d.ts +14 -2
- package/dist/dialect.js +5 -0
- package/dist/dialect.mjs +1 -1
- 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 +10 -0
- package/dist/glassbox-routes/index.mjs +1 -1
- 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 +255 -7
- package/dist/index.d.ts +255 -7
- package/dist/index.js +841 -7
- package/dist/index.mjs +808 -9
- package/dist/{ir-BC4uDL98.d.mts → ir-B2dRyJXO.d.mts} +84 -11
- package/dist/{ir-B2h0GAEL.d.ts → ir-ClU56aBc.d.ts} +84 -11
- package/dist/key-health.js +1 -1
- package/dist/key-health.mjs +1 -1
- package/dist/profiles.d.mts +1 -1
- package/dist/profiles.d.ts +1 -1
- package/dist/{types-CKuu7Clz.d.ts → types-ByN3r0_7.d.ts} +1 -1
- package/dist/{types-CsB2YASc.d.ts → types-C-Wp7HpI.d.ts} +1 -1
- package/dist/{types-B-pzBJKf.d.mts → types-CSDweZsl.d.mts} +1 -1
- package/dist/{types-CRy90cjp.d.mts → types-axAX1Bg0.d.mts} +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -30,6 +30,7 @@ __export(index_exports, {
|
|
|
30
30
|
DIALECT_VERSION: () => DIALECT_VERSION,
|
|
31
31
|
FamilyResolutionError: () => FamilyResolutionError,
|
|
32
32
|
INTENT_ARCHETYPES: () => INTENT_ARCHETYPES,
|
|
33
|
+
JUDGE_RUBRICS: () => JUDGE_RUBRICS,
|
|
33
34
|
LATENCY_TIER_MS: () => LATENCY_TIER_MS,
|
|
34
35
|
LIBRARY_VERSION: () => LIBRARY_VERSION,
|
|
35
36
|
MEASURED_GROUNDING_MIN_N: () => MEASURED_GROUNDING_MIN_N,
|
|
@@ -41,13 +42,18 @@ __export(index_exports, {
|
|
|
41
42
|
applyArchetypeConvention: () => applyArchetypeConvention,
|
|
42
43
|
applySectionRewrites: () => applySectionRewrites,
|
|
43
44
|
attachCacheControlToStreamTextInput: () => attachCacheControlToStreamTextInput,
|
|
45
|
+
brainHealth: () => brainHealth,
|
|
44
46
|
bucketContext: () => bucketContext,
|
|
45
47
|
bucketHistory: () => bucketHistory,
|
|
46
48
|
bucketToolCount: () => bucketToolCount,
|
|
49
|
+
buildGoldenIrRow: () => buildGoldenIrRow,
|
|
47
50
|
buildLLMJudge: () => buildLLMJudge,
|
|
51
|
+
buildPairwiseJudgePrompt: () => buildPairwiseJudgePrompt,
|
|
48
52
|
buildShadowProbeRow: () => buildShadowProbeRow,
|
|
49
53
|
call: () => call,
|
|
54
|
+
captureGoldenIr: () => captureGoldenIr,
|
|
50
55
|
clearBrain: () => clearBrain,
|
|
56
|
+
combineOrderSwappedVerdicts: () => combineOrderSwappedVerdicts,
|
|
51
57
|
compile: () => compile2,
|
|
52
58
|
compileForAISDKv6: () => compileForAISDKv6,
|
|
53
59
|
configureBrain: () => configureBrain,
|
|
@@ -58,6 +64,7 @@ __export(index_exports, {
|
|
|
58
64
|
deriveOwnership: () => deriveOwnership,
|
|
59
65
|
execute: () => execute,
|
|
60
66
|
findBetterFit: () => findBetterFit,
|
|
67
|
+
flushBrainDeadLetter: () => flushBrainDeadLetter,
|
|
61
68
|
getActionableAdvisories: () => getActionableAdvisories,
|
|
62
69
|
getAllStarterChains: () => getAllStarterChains,
|
|
63
70
|
getAllStarterChainsWithGrounding: () => getAllStarterChainsWithGrounding,
|
|
@@ -92,19 +99,28 @@ __export(index_exports, {
|
|
|
92
99
|
markAdvisoryResolved: () => markAdvisoryResolved,
|
|
93
100
|
markExclusionFindingHandled: () => markExclusionFindingHandled,
|
|
94
101
|
markPromoteReadyHandled: () => markPromoteReadyHandled,
|
|
102
|
+
parseGoldenCaptureRate: () => parseGoldenCaptureRate,
|
|
103
|
+
parseJudgeVerdict: () => parseJudgeVerdict,
|
|
104
|
+
peekBrainDeadLetter: () => peekBrainDeadLetter,
|
|
95
105
|
probeShadow: () => probeShadow,
|
|
96
106
|
profileToRow: () => profileToRow,
|
|
97
107
|
profilesByProvider: () => profilesByProvider,
|
|
98
108
|
readBrainReadEnv: () => readBrainReadEnv,
|
|
99
109
|
record: () => record,
|
|
110
|
+
recordGoldenIr: () => recordGoldenIr,
|
|
100
111
|
recordOutcome: () => recordOutcome,
|
|
101
112
|
recordShadowProbe: () => recordShadowProbe,
|
|
113
|
+
renderIrForJudge: () => renderIrForJudge,
|
|
102
114
|
resetTokenizer: () => resetTokenizer,
|
|
103
115
|
resolveConventionsForProfile: () => resolveConventionsForProfile,
|
|
116
|
+
resolveGoldenCaptureRate: () => resolveGoldenCaptureRate,
|
|
104
117
|
resolvePricingAt: () => resolvePricingAt,
|
|
105
118
|
resolveProviderKey: () => resolveProviderKey,
|
|
119
|
+
rubricFor: () => rubricFor,
|
|
106
120
|
runAdvisor: () => runAdvisor,
|
|
121
|
+
runGoldenEval: () => runGoldenEval,
|
|
107
122
|
setTokenizer: () => setTokenizer,
|
|
123
|
+
shouldCaptureGolden: () => shouldCaptureGolden,
|
|
108
124
|
tryGetProfile: () => tryGetProfile
|
|
109
125
|
});
|
|
110
126
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -2292,6 +2308,11 @@ var INTENT_ARCHETYPES = {
|
|
|
2292
2308
|
name: "transform",
|
|
2293
2309
|
description: "Change format or style while preserving content",
|
|
2294
2310
|
examples: ["markdown \u2192 html", "formal \u2192 casual", "translate"]
|
|
2311
|
+
},
|
|
2312
|
+
judge: {
|
|
2313
|
+
name: "judge",
|
|
2314
|
+
description: "Pairwise comparison of two candidate outputs for the same input",
|
|
2315
|
+
examples: ["golden-set eval A/B verdict", "model-swap non-inferiority check", "response bake-off"]
|
|
2295
2316
|
}
|
|
2296
2317
|
};
|
|
2297
2318
|
var ALL_ARCHETYPES = Object.keys(INTENT_ARCHETYPES);
|
|
@@ -4468,6 +4489,134 @@ function clearBrain() {
|
|
|
4468
4489
|
configureBrainQuery(void 0);
|
|
4469
4490
|
configureExclusionFindingsBrain(void 0);
|
|
4470
4491
|
}
|
|
4492
|
+
var DEAD_LETTER_MAX_ENTRIES = 50;
|
|
4493
|
+
var DEAD_LETTER_MAX_ATTEMPTS = 3;
|
|
4494
|
+
var ledger = {
|
|
4495
|
+
sent: 0,
|
|
4496
|
+
acked: 0,
|
|
4497
|
+
failed: 0,
|
|
4498
|
+
redirected: 0,
|
|
4499
|
+
lastAckAt: void 0,
|
|
4500
|
+
lastFailureAt: void 0,
|
|
4501
|
+
lastFailure: void 0
|
|
4502
|
+
};
|
|
4503
|
+
var deadLetter = [];
|
|
4504
|
+
var flushing = false;
|
|
4505
|
+
function noteSent() {
|
|
4506
|
+
ledger.sent += 1;
|
|
4507
|
+
}
|
|
4508
|
+
function noteAck() {
|
|
4509
|
+
ledger.acked += 1;
|
|
4510
|
+
ledger.lastAckAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
4511
|
+
}
|
|
4512
|
+
function noteFailure(err) {
|
|
4513
|
+
ledger.failed += 1;
|
|
4514
|
+
ledger.lastFailureAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
4515
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
4516
|
+
ledger.lastFailure = msg.length > 300 ? `${msg.slice(0, 300)}\u2026` : msg;
|
|
4517
|
+
}
|
|
4518
|
+
function assertNotRedirected(res, route) {
|
|
4519
|
+
if (!res.redirected) return;
|
|
4520
|
+
ledger.redirected += 1;
|
|
4521
|
+
throw new Error(
|
|
4522
|
+
`brain ${route} POST was redirected to ${res.url} \u2014 the write did NOT land. Likely cause: consumer middleware (auth/login allowlist) intercepts the brain proxy path. Add your kgauto proxy routes to the middleware public paths (the 2026-07-02 tt-intel/IC middleware-drift class).`
|
|
4523
|
+
);
|
|
4524
|
+
}
|
|
4525
|
+
function pushDeadLetter(route, endpoint, payload, err) {
|
|
4526
|
+
if (deadLetter.length >= DEAD_LETTER_MAX_ENTRIES) deadLetter.shift();
|
|
4527
|
+
deadLetter.push({
|
|
4528
|
+
route,
|
|
4529
|
+
endpoint,
|
|
4530
|
+
payload,
|
|
4531
|
+
failedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4532
|
+
attempts: 1,
|
|
4533
|
+
lastError: err instanceof Error ? err.message : String(err)
|
|
4534
|
+
});
|
|
4535
|
+
}
|
|
4536
|
+
function maybeAutoFlush() {
|
|
4537
|
+
if (deadLetter.length === 0 || flushing) return;
|
|
4538
|
+
void flushBrainDeadLetter();
|
|
4539
|
+
}
|
|
4540
|
+
function brainHealth() {
|
|
4541
|
+
let endpointHost;
|
|
4542
|
+
if (activeConfig) {
|
|
4543
|
+
try {
|
|
4544
|
+
endpointHost = new URL(activeConfig.endpoint).host;
|
|
4545
|
+
} catch {
|
|
4546
|
+
endpointHost = void 0;
|
|
4547
|
+
}
|
|
4548
|
+
}
|
|
4549
|
+
return {
|
|
4550
|
+
configState: activeConfig ? "configured" : "not_configured",
|
|
4551
|
+
endpointHost,
|
|
4552
|
+
sync: activeConfig?.sync === true,
|
|
4553
|
+
sent: ledger.sent,
|
|
4554
|
+
acked: ledger.acked,
|
|
4555
|
+
failed: ledger.failed,
|
|
4556
|
+
redirected: ledger.redirected,
|
|
4557
|
+
lastAckAt: ledger.lastAckAt,
|
|
4558
|
+
lastFailureAt: ledger.lastFailureAt,
|
|
4559
|
+
lastFailure: ledger.lastFailure,
|
|
4560
|
+
deadLetterCount: deadLetter.length
|
|
4561
|
+
};
|
|
4562
|
+
}
|
|
4563
|
+
function peekBrainDeadLetter() {
|
|
4564
|
+
return deadLetter.slice();
|
|
4565
|
+
}
|
|
4566
|
+
async function flushBrainDeadLetter() {
|
|
4567
|
+
if (!activeConfig || flushing || deadLetter.length === 0) {
|
|
4568
|
+
return { attempted: 0, delivered: 0, remaining: deadLetter.length };
|
|
4569
|
+
}
|
|
4570
|
+
flushing = true;
|
|
4571
|
+
const config = activeConfig;
|
|
4572
|
+
const fetchFn = brainWriteFetch(config);
|
|
4573
|
+
let attempted = 0;
|
|
4574
|
+
let delivered = 0;
|
|
4575
|
+
try {
|
|
4576
|
+
const batch = deadLetter.filter((e) => e.endpoint === config.endpoint);
|
|
4577
|
+
for (const entry of batch) {
|
|
4578
|
+
attempted += 1;
|
|
4579
|
+
noteSent();
|
|
4580
|
+
try {
|
|
4581
|
+
const res = await fetchFn(`${config.endpoint}/${entry.route}`, {
|
|
4582
|
+
method: "POST",
|
|
4583
|
+
headers: {
|
|
4584
|
+
"Content-Type": "application/json",
|
|
4585
|
+
// Replay never chains a secondary — minimal is correct for all routes.
|
|
4586
|
+
Prefer: "return=minimal",
|
|
4587
|
+
...config.apiKey ? { Authorization: `Bearer ${config.apiKey}` } : {}
|
|
4588
|
+
},
|
|
4589
|
+
body: JSON.stringify(entry.payload)
|
|
4590
|
+
});
|
|
4591
|
+
assertNotRedirected(res, entry.route);
|
|
4592
|
+
if (!res.ok) {
|
|
4593
|
+
const text = await res.text().catch(() => "<no body>");
|
|
4594
|
+
throw new Error(describeBrainWriteFailure(res.status, entry.route, text));
|
|
4595
|
+
}
|
|
4596
|
+
noteAck();
|
|
4597
|
+
delivered += 1;
|
|
4598
|
+
const idx = deadLetter.indexOf(entry);
|
|
4599
|
+
if (idx !== -1) deadLetter.splice(idx, 1);
|
|
4600
|
+
} catch (err) {
|
|
4601
|
+
noteFailure(err);
|
|
4602
|
+
entry.attempts += 1;
|
|
4603
|
+
entry.lastError = err instanceof Error ? err.message : String(err);
|
|
4604
|
+
if (entry.attempts >= DEAD_LETTER_MAX_ATTEMPTS) {
|
|
4605
|
+
const idx = deadLetter.indexOf(entry);
|
|
4606
|
+
if (idx !== -1) deadLetter.splice(idx, 1);
|
|
4607
|
+
(config.onError ?? defaultOnError5)(
|
|
4608
|
+
new Error(
|
|
4609
|
+
`brain dead-letter: dropping ${entry.route} payload after ${entry.attempts} attempts \u2014 last error: ${entry.lastError}`
|
|
4610
|
+
)
|
|
4611
|
+
);
|
|
4612
|
+
}
|
|
4613
|
+
}
|
|
4614
|
+
}
|
|
4615
|
+
} finally {
|
|
4616
|
+
flushing = false;
|
|
4617
|
+
}
|
|
4618
|
+
return { attempted, delivered, remaining: deadLetter.length };
|
|
4619
|
+
}
|
|
4471
4620
|
var compileRegistry = /* @__PURE__ */ new Map();
|
|
4472
4621
|
var REGISTRY_MAX_ENTRIES = 1e4;
|
|
4473
4622
|
function registerCompile(appId, archetype, ir, result) {
|
|
@@ -4575,6 +4724,7 @@ async function record(input) {
|
|
|
4575
4724
|
const fetchFn = brainWriteFetch(config);
|
|
4576
4725
|
const send = async () => {
|
|
4577
4726
|
let outcomeId;
|
|
4727
|
+
noteSent();
|
|
4578
4728
|
try {
|
|
4579
4729
|
const res = await fetchFn(`${config.endpoint}/outcomes`, {
|
|
4580
4730
|
method: "POST",
|
|
@@ -4594,20 +4744,26 @@ async function record(input) {
|
|
|
4594
4744
|
},
|
|
4595
4745
|
body: JSON.stringify(payload)
|
|
4596
4746
|
});
|
|
4747
|
+
assertNotRedirected(res, "outcomes");
|
|
4597
4748
|
if (!res.ok) {
|
|
4598
4749
|
const text = await res.text().catch(() => "<no body>");
|
|
4599
4750
|
throw new Error(describeBrainWriteFailure(res.status, "outcomes", text));
|
|
4600
4751
|
}
|
|
4752
|
+
noteAck();
|
|
4601
4753
|
outcomeId = await tryExtractOutcomeId(res);
|
|
4602
4754
|
} catch (err) {
|
|
4755
|
+
noteFailure(err);
|
|
4756
|
+
pushDeadLetter("outcomes", config.endpoint, payload, err);
|
|
4603
4757
|
(config.onError ?? defaultOnError5)(err);
|
|
4604
4758
|
return;
|
|
4605
4759
|
}
|
|
4760
|
+
maybeAutoFlush();
|
|
4606
4761
|
const advisories = input.advisories ?? reg?.advisoriesFromCompile;
|
|
4607
4762
|
if (!advisories || advisories.length === 0) return;
|
|
4608
4763
|
if (outcomeId === void 0) return;
|
|
4764
|
+
const advisoryPayload = advisories.map((a) => buildAdvisoryRow(outcomeId, a));
|
|
4765
|
+
noteSent();
|
|
4609
4766
|
try {
|
|
4610
|
-
const advisoryPayload = advisories.map((a) => buildAdvisoryRow(outcomeId, a));
|
|
4611
4767
|
const res = await fetchFn(`${config.endpoint}/compile_outcome_advisories`, {
|
|
4612
4768
|
method: "POST",
|
|
4613
4769
|
headers: {
|
|
@@ -4617,11 +4773,15 @@ async function record(input) {
|
|
|
4617
4773
|
},
|
|
4618
4774
|
body: JSON.stringify(advisoryPayload)
|
|
4619
4775
|
});
|
|
4776
|
+
assertNotRedirected(res, "compile_outcome_advisories");
|
|
4620
4777
|
if (!res.ok) {
|
|
4621
4778
|
const text = await res.text().catch(() => "<no body>");
|
|
4622
4779
|
throw new Error(`brain advisories ${res.status}: ${text}`);
|
|
4623
4780
|
}
|
|
4781
|
+
noteAck();
|
|
4624
4782
|
} catch (err) {
|
|
4783
|
+
noteFailure(err);
|
|
4784
|
+
pushDeadLetter("compile_outcome_advisories", config.endpoint, advisoryPayload, err);
|
|
4625
4785
|
(config.onError ?? defaultOnError5)(err);
|
|
4626
4786
|
}
|
|
4627
4787
|
};
|
|
@@ -4760,6 +4920,7 @@ async function recordOutcome(input) {
|
|
|
4760
4920
|
observed_confidence: input.observedConfidence ?? null
|
|
4761
4921
|
};
|
|
4762
4922
|
const send = async () => {
|
|
4923
|
+
noteSent();
|
|
4763
4924
|
try {
|
|
4764
4925
|
const res = await fetchFn(`${config.endpoint}/compile_outcome_quality`, {
|
|
4765
4926
|
method: "POST",
|
|
@@ -4769,16 +4930,19 @@ async function recordOutcome(input) {
|
|
|
4769
4930
|
},
|
|
4770
4931
|
body: JSON.stringify(payload)
|
|
4771
4932
|
});
|
|
4933
|
+
assertNotRedirected(res, "compile_outcome_quality");
|
|
4772
4934
|
if (!res.ok) {
|
|
4773
4935
|
const text = await res.text().catch(() => "<no body>");
|
|
4774
|
-
|
|
4936
|
+
throw new Error(
|
|
4775
4937
|
describeBrainWriteFailure(res.status, "compile_outcome_quality", text)
|
|
4776
4938
|
);
|
|
4777
|
-
(config.onError ?? defaultOnError5)(err);
|
|
4778
|
-
return { ok: false, reason: "persistence_failed" };
|
|
4779
4939
|
}
|
|
4940
|
+
noteAck();
|
|
4941
|
+
maybeAutoFlush();
|
|
4780
4942
|
return { ok: true };
|
|
4781
4943
|
} catch (err) {
|
|
4944
|
+
noteFailure(err);
|
|
4945
|
+
pushDeadLetter("compile_outcome_quality", config.endpoint, payload, err);
|
|
4782
4946
|
(config.onError ?? defaultOnError5)(err);
|
|
4783
4947
|
return { ok: false, reason: "persistence_failed" };
|
|
4784
4948
|
}
|
|
@@ -4787,7 +4951,7 @@ async function recordOutcome(input) {
|
|
|
4787
4951
|
return send();
|
|
4788
4952
|
}
|
|
4789
4953
|
void send();
|
|
4790
|
-
return { ok:
|
|
4954
|
+
return { ok: "queued" };
|
|
4791
4955
|
}
|
|
4792
4956
|
function isBrainSync() {
|
|
4793
4957
|
return activeConfig?.sync === true;
|
|
@@ -4829,6 +4993,7 @@ async function recordShadowProbe(input) {
|
|
|
4829
4993
|
const fetchFn = brainWriteFetch(config);
|
|
4830
4994
|
const row = buildShadowProbeRow(input);
|
|
4831
4995
|
const send = async () => {
|
|
4996
|
+
noteSent();
|
|
4832
4997
|
try {
|
|
4833
4998
|
const res = await fetchFn(`${config.endpoint}/probe_outcomes`, {
|
|
4834
4999
|
method: "POST",
|
|
@@ -4839,11 +5004,71 @@ async function recordShadowProbe(input) {
|
|
|
4839
5004
|
},
|
|
4840
5005
|
body: JSON.stringify(row)
|
|
4841
5006
|
});
|
|
5007
|
+
assertNotRedirected(res, "probe_outcomes");
|
|
4842
5008
|
if (!res.ok) {
|
|
4843
5009
|
const text = await res.text().catch(() => "<no body>");
|
|
4844
5010
|
throw new Error(describeBrainWriteFailure(res.status, "probe_outcomes", text));
|
|
4845
5011
|
}
|
|
5012
|
+
noteAck();
|
|
5013
|
+
maybeAutoFlush();
|
|
4846
5014
|
} catch (err) {
|
|
5015
|
+
noteFailure(err);
|
|
5016
|
+
pushDeadLetter("probe_outcomes", config.endpoint, row, err);
|
|
5017
|
+
(config.onError ?? defaultOnError5)(err);
|
|
5018
|
+
}
|
|
5019
|
+
};
|
|
5020
|
+
if (config.sync) {
|
|
5021
|
+
await send();
|
|
5022
|
+
} else {
|
|
5023
|
+
void send();
|
|
5024
|
+
}
|
|
5025
|
+
}
|
|
5026
|
+
function peekRegisteredShapeKey(handle) {
|
|
5027
|
+
return compileRegistry.get(handle)?.shapeKey;
|
|
5028
|
+
}
|
|
5029
|
+
function buildGoldenIrRow(input) {
|
|
5030
|
+
return {
|
|
5031
|
+
app_id: input.appId,
|
|
5032
|
+
intent_archetype: input.archetype,
|
|
5033
|
+
shape_key: input.shapeKey ?? null,
|
|
5034
|
+
ir: input.ir,
|
|
5035
|
+
incumbent_model: input.incumbentModel,
|
|
5036
|
+
incumbent_output: input.incumbentOutput ?? null,
|
|
5037
|
+
incumbent_latency_ms: input.incumbentLatencyMs ?? null,
|
|
5038
|
+
incumbent_tokens_in: input.incumbentTokensIn ?? null,
|
|
5039
|
+
incumbent_tokens_out: input.incumbentTokensOut ?? null,
|
|
5040
|
+
source: input.source,
|
|
5041
|
+
consent: input.consent,
|
|
5042
|
+
outcome_handle: input.outcomeHandle ?? null
|
|
5043
|
+
};
|
|
5044
|
+
}
|
|
5045
|
+
async function recordGoldenIr(input) {
|
|
5046
|
+
if (!activeConfig) return;
|
|
5047
|
+
const config = activeConfig;
|
|
5048
|
+
const fetchFn = brainWriteFetch(config);
|
|
5049
|
+
const row = buildGoldenIrRow(input);
|
|
5050
|
+
const send = async () => {
|
|
5051
|
+
noteSent();
|
|
5052
|
+
try {
|
|
5053
|
+
const res = await fetchFn(`${config.endpoint}/golden_irs`, {
|
|
5054
|
+
method: "POST",
|
|
5055
|
+
headers: {
|
|
5056
|
+
"Content-Type": "application/json",
|
|
5057
|
+
Prefer: "return=minimal",
|
|
5058
|
+
...config.apiKey ? { Authorization: `Bearer ${config.apiKey}` } : {}
|
|
5059
|
+
},
|
|
5060
|
+
body: JSON.stringify(row)
|
|
5061
|
+
});
|
|
5062
|
+
assertNotRedirected(res, "golden_irs");
|
|
5063
|
+
if (!res.ok) {
|
|
5064
|
+
const text = await res.text().catch(() => "<no body>");
|
|
5065
|
+
throw new Error(describeBrainWriteFailure(res.status, "golden_irs", text));
|
|
5066
|
+
}
|
|
5067
|
+
noteAck();
|
|
5068
|
+
maybeAutoFlush();
|
|
5069
|
+
} catch (err) {
|
|
5070
|
+
noteFailure(err);
|
|
5071
|
+
pushDeadLetter("golden_irs", config.endpoint, row, err);
|
|
4847
5072
|
(config.onError ?? defaultOnError5)(err);
|
|
4848
5073
|
}
|
|
4849
5074
|
};
|
|
@@ -4868,6 +5093,45 @@ var CallError = class extends Error {
|
|
|
4868
5093
|
}
|
|
4869
5094
|
};
|
|
4870
5095
|
|
|
5096
|
+
// src/golden.ts
|
|
5097
|
+
function parseGoldenCaptureRate(raw) {
|
|
5098
|
+
if (raw === void 0 || raw.trim() === "") return 0;
|
|
5099
|
+
const n = Number(raw);
|
|
5100
|
+
if (!Number.isFinite(n)) return 0;
|
|
5101
|
+
return Math.max(0, Math.min(1, n));
|
|
5102
|
+
}
|
|
5103
|
+
function resolveGoldenCaptureRate(optRate) {
|
|
5104
|
+
if (optRate !== void 0 && Number.isFinite(optRate)) {
|
|
5105
|
+
return Math.max(0, Math.min(1, optRate));
|
|
5106
|
+
}
|
|
5107
|
+
const env = typeof process !== "undefined" && process.env ? process.env.KGAUTO_GOLDEN_CAPTURE : void 0;
|
|
5108
|
+
return parseGoldenCaptureRate(env);
|
|
5109
|
+
}
|
|
5110
|
+
function shouldCaptureGolden(rate, rng = Math.random) {
|
|
5111
|
+
if (rate <= 0) return false;
|
|
5112
|
+
if (rate >= 1) return true;
|
|
5113
|
+
return rng() < rate;
|
|
5114
|
+
}
|
|
5115
|
+
async function captureGoldenIr(ctx) {
|
|
5116
|
+
try {
|
|
5117
|
+
await recordGoldenIr({
|
|
5118
|
+
appId: ctx.ir.appId,
|
|
5119
|
+
archetype: ctx.ir.intent.archetype,
|
|
5120
|
+
shapeKey: ctx.shapeKey,
|
|
5121
|
+
ir: ctx.ir,
|
|
5122
|
+
incumbentModel: ctx.servedModel,
|
|
5123
|
+
incumbentOutput: ctx.response.text,
|
|
5124
|
+
incumbentLatencyMs: ctx.latencyMs,
|
|
5125
|
+
incumbentTokensIn: ctx.response.tokens.input,
|
|
5126
|
+
incumbentTokensOut: ctx.response.tokens.output,
|
|
5127
|
+
source: "sampled",
|
|
5128
|
+
consent: ctx.consent,
|
|
5129
|
+
outcomeHandle: ctx.handle
|
|
5130
|
+
});
|
|
5131
|
+
} catch {
|
|
5132
|
+
}
|
|
5133
|
+
}
|
|
5134
|
+
|
|
4871
5135
|
// src/env.ts
|
|
4872
5136
|
var SUPPORTED_PROVIDERS = Object.freeze([
|
|
4873
5137
|
"anthropic",
|
|
@@ -5502,6 +5766,16 @@ var STARTER_CHAINS_GROUNDED = {
|
|
|
5502
5766
|
{ id: "gemini-2.5-pro", grounding: "judgment", reason: "Cross-provider anchor in similar quality bracket" },
|
|
5503
5767
|
{ id: "gpt-5.5", grounding: "judgment", reason: "alpha.16: third-provider frontier-tier floor (archetypePerf=9)" }
|
|
5504
5768
|
],
|
|
5769
|
+
// alpha.62 (eval spine) — pairwise output comparison. Same reasoning-floor
|
|
5770
|
+
// posture as critique (a verdict from a weak judge is worse than no
|
|
5771
|
+
// verdict); tier 0 anchored on the CURRENT opus (4-8, s64 roster). Strict
|
|
5772
|
+
// JSON output, so every tier declares native structured output.
|
|
5773
|
+
judge: [
|
|
5774
|
+
{ id: "claude-opus-4-8", grounding: "judgment", reason: "Highest reasoning bar for pairwise verdicts \u2014 current opus (s64 roster)" },
|
|
5775
|
+
{ id: "claude-sonnet-4-6", grounding: "judgment", reason: "Same-provider walk-down on 429" },
|
|
5776
|
+
{ id: "gemini-2.5-pro", grounding: "judgment", reason: "Cross-provider anchor in similar quality bracket" },
|
|
5777
|
+
{ id: "gpt-5.5", grounding: "judgment", reason: "Third-provider frontier-tier floor" }
|
|
5778
|
+
],
|
|
5505
5779
|
// Reasoning matters — Sonnet primary; walk UP to Opus on 429.
|
|
5506
5780
|
plan: [
|
|
5507
5781
|
{ id: "claude-sonnet-4-6", grounding: "judgment", reason: "Reasoning + cost balance \u2014 engineer pick" },
|
|
@@ -6294,6 +6568,8 @@ async function call(ir, opts = {}) {
|
|
|
6294
6568
|
);
|
|
6295
6569
|
const fellOver = targetModel !== initial.target;
|
|
6296
6570
|
const fallbackReason = fellOver ? normalizeFallbackReason(attempts) : void 0;
|
|
6571
|
+
const goldenRate = resolveGoldenCaptureRate(opts.goldenCapture?.sampleRate);
|
|
6572
|
+
const goldenShapeKey = goldenRate > 0 ? peekRegisteredShapeKey(initial.handle) : void 0;
|
|
6297
6573
|
await record({
|
|
6298
6574
|
handle: initial.handle,
|
|
6299
6575
|
tokensIn: validated.response.tokens.input,
|
|
@@ -6346,6 +6622,23 @@ async function call(ir, opts = {}) {
|
|
|
6346
6622
|
void probe;
|
|
6347
6623
|
}
|
|
6348
6624
|
}
|
|
6625
|
+
if (goldenRate > 0 && validated.response.tokens.output > 0 && shouldCaptureGolden(goldenRate)) {
|
|
6626
|
+
const consent = opts.goldenCapture?.sampleRate !== void 0 ? `CallOptions.goldenCapture.sampleRate=${goldenRate} (consumer code opt-in)` + (opts.goldenCapture.consentNote ? ` \u2014 ${opts.goldenCapture.consentNote}` : "") : `KGAUTO_GOLDEN_CAPTURE=${goldenRate} (consumer env opt-in)`;
|
|
6627
|
+
const capture = captureGoldenIr({
|
|
6628
|
+
ir,
|
|
6629
|
+
servedModel: targetModel,
|
|
6630
|
+
response: validated.response,
|
|
6631
|
+
latencyMs: latencyMs2,
|
|
6632
|
+
handle: initial.handle,
|
|
6633
|
+
shapeKey: goldenShapeKey,
|
|
6634
|
+
consent
|
|
6635
|
+
});
|
|
6636
|
+
if (isBrainSync()) {
|
|
6637
|
+
await capture;
|
|
6638
|
+
} else {
|
|
6639
|
+
void capture;
|
|
6640
|
+
}
|
|
6641
|
+
}
|
|
6349
6642
|
return {
|
|
6350
6643
|
handle: initial.handle,
|
|
6351
6644
|
actualModel: targetModel,
|
|
@@ -6685,6 +6978,18 @@ function safeEmit(fn) {
|
|
|
6685
6978
|
} catch {
|
|
6686
6979
|
}
|
|
6687
6980
|
}
|
|
6981
|
+
var _internal = {
|
|
6982
|
+
compileAndRegister,
|
|
6983
|
+
validateStructuredContract,
|
|
6984
|
+
extractPromptPreview,
|
|
6985
|
+
normalizeFallbackReason,
|
|
6986
|
+
generateTraceId,
|
|
6987
|
+
safeEmit,
|
|
6988
|
+
shouldSampleProbe,
|
|
6989
|
+
normalizeProbeCandidates,
|
|
6990
|
+
runShadowProbe,
|
|
6991
|
+
runProbeCandidates
|
|
6992
|
+
};
|
|
6688
6993
|
|
|
6689
6994
|
// src/streamtext-helpers.ts
|
|
6690
6995
|
function attachCacheControlToStreamTextInput(result, convertedMessages) {
|
|
@@ -6784,12 +7089,525 @@ function extractKeptToolNames(result) {
|
|
|
6784
7089
|
return names;
|
|
6785
7090
|
}
|
|
6786
7091
|
|
|
7092
|
+
// src/golden-eval.ts
|
|
7093
|
+
var GENERIC_RUBRIC = "overall correctness, completeness against the request, clarity, and adherence to any requested format";
|
|
7094
|
+
var JUDGE_RUBRICS = {
|
|
7095
|
+
summarize: "faithfulness to the source (no fabricated facts), coverage of the key points, concision, and adherence to the requested output format",
|
|
7096
|
+
classify: "assignment of the correct category from the allowed set, and nothing outside the allowed set",
|
|
7097
|
+
generate: "relevance to the brief, quality and coherence of the writing, and adherence to the requested format and tone",
|
|
7098
|
+
extract: "completeness of extraction (nothing relevant missed), precision (no invented fields or values), and exact schema adherence",
|
|
7099
|
+
ask: "correctness of the answer with respect to the provided data, relevance, and absence of fabrication",
|
|
7100
|
+
hunt: "relevance and novelty of the discovered entities, and absence of duplicates or fabricated entries",
|
|
7101
|
+
plan: "quality of the decomposition (complete, ordered, actionable steps) and realism of the sequencing",
|
|
7102
|
+
critique: "specificity and correctness of the assessment, and actionability of the feedback",
|
|
7103
|
+
transform: "preservation of the source content and correctness of the target format or style"
|
|
7104
|
+
};
|
|
7105
|
+
function rubricFor(archetype) {
|
|
7106
|
+
return JUDGE_RUBRICS[archetype] ?? GENERIC_RUBRIC;
|
|
7107
|
+
}
|
|
7108
|
+
var INPUT_TRUNCATE_CHARS = 24e3;
|
|
7109
|
+
var OUTPUT_TRUNCATE_CHARS = 12e3;
|
|
7110
|
+
function renderIrForJudge(ir) {
|
|
7111
|
+
const sections = (ir.sections ?? []).map((s) => s.text).filter(Boolean).join("\n\n");
|
|
7112
|
+
const turn = typeof ir.currentTurn?.content === "string" ? ir.currentTurn.content : "";
|
|
7113
|
+
const combined = [
|
|
7114
|
+
sections ? `[system]
|
|
7115
|
+
${sections}` : "",
|
|
7116
|
+
turn ? `[user]
|
|
7117
|
+
${turn}` : ""
|
|
7118
|
+
].filter(Boolean).join("\n\n");
|
|
7119
|
+
return combined.length > INPUT_TRUNCATE_CHARS ? `${combined.slice(0, INPUT_TRUNCATE_CHARS)}
|
|
7120
|
+
\u2026[truncated]` : combined;
|
|
7121
|
+
}
|
|
7122
|
+
function buildPairwiseJudgePrompt(args) {
|
|
7123
|
+
const clip = (s) => s.length > OUTPUT_TRUNCATE_CHARS ? `${s.slice(0, OUTPUT_TRUNCATE_CHARS)}
|
|
7124
|
+
\u2026[truncated]` : s;
|
|
7125
|
+
return `You are a strict pairwise judge comparing two AI responses to the SAME request.
|
|
7126
|
+
|
|
7127
|
+
The request (archetype: ${args.archetype}):
|
|
7128
|
+
<request>
|
|
7129
|
+
${args.renderedInput}
|
|
7130
|
+
</request>
|
|
7131
|
+
|
|
7132
|
+
Response A:
|
|
7133
|
+
<response_a>
|
|
7134
|
+
${clip(args.outputA)}
|
|
7135
|
+
</response_a>
|
|
7136
|
+
|
|
7137
|
+
Response B:
|
|
7138
|
+
<response_b>
|
|
7139
|
+
${clip(args.outputB)}
|
|
7140
|
+
</response_b>
|
|
7141
|
+
|
|
7142
|
+
Judge which response better satisfies the request. Rubric for ${args.archetype}: ${rubricFor(args.archetype)}.
|
|
7143
|
+
|
|
7144
|
+
A tie is a legitimate verdict \u2014 declare it when the responses are of genuinely comparable quality. Do NOT prefer a response merely for being longer.
|
|
7145
|
+
|
|
7146
|
+
Output ONLY this JSON, no other text:
|
|
7147
|
+
{"winner": "A" | "B" | "tie", "rationale": "<one sentence>"}`;
|
|
7148
|
+
}
|
|
7149
|
+
function parseJudgeVerdict(raw) {
|
|
7150
|
+
const cleaned = raw.replace(/^```(?:json)?\s*/i, "").replace(/\s*```\s*$/, "").trim();
|
|
7151
|
+
let parsed;
|
|
7152
|
+
try {
|
|
7153
|
+
parsed = JSON.parse(cleaned);
|
|
7154
|
+
} catch {
|
|
7155
|
+
const match = cleaned.match(/\{[\s\S]*\}/);
|
|
7156
|
+
if (!match) return void 0;
|
|
7157
|
+
try {
|
|
7158
|
+
parsed = JSON.parse(match[0]);
|
|
7159
|
+
} catch {
|
|
7160
|
+
return void 0;
|
|
7161
|
+
}
|
|
7162
|
+
}
|
|
7163
|
+
if (!parsed || typeof parsed !== "object") return void 0;
|
|
7164
|
+
const obj = parsed;
|
|
7165
|
+
const winner = obj.winner;
|
|
7166
|
+
if (winner !== "A" && winner !== "B" && winner !== "tie") return void 0;
|
|
7167
|
+
return {
|
|
7168
|
+
winner,
|
|
7169
|
+
rationale: typeof obj.rationale === "string" ? obj.rationale : void 0
|
|
7170
|
+
};
|
|
7171
|
+
}
|
|
7172
|
+
function combineOrderSwappedVerdicts(run1, run2) {
|
|
7173
|
+
if (run1 === run2) return run1;
|
|
7174
|
+
return "tied";
|
|
7175
|
+
}
|
|
7176
|
+
function p50(values) {
|
|
7177
|
+
if (values.length === 0) return null;
|
|
7178
|
+
const sorted = [...values].sort((a, b) => a - b);
|
|
7179
|
+
return sorted[Math.floor(sorted.length / 2)] ?? null;
|
|
7180
|
+
}
|
|
7181
|
+
function costUsd(model, tokensIn, tokensOut) {
|
|
7182
|
+
const profile = tryGetProfile(model);
|
|
7183
|
+
if (!profile) return null;
|
|
7184
|
+
return tokensIn / 1e6 * profile.costInputPer1m + tokensOut / 1e6 * profile.costOutputPer1m;
|
|
7185
|
+
}
|
|
7186
|
+
function hashForGolden(s) {
|
|
7187
|
+
let h = 5381;
|
|
7188
|
+
for (let i = 0; i < s.length; i += 1) {
|
|
7189
|
+
h = (h << 5) + h + s.charCodeAt(i) >>> 0;
|
|
7190
|
+
}
|
|
7191
|
+
return `g${h.toString(36)}`;
|
|
7192
|
+
}
|
|
7193
|
+
async function runGoldenEval(opts) {
|
|
7194
|
+
const fetchFn = opts.fetchImpl ?? fetch;
|
|
7195
|
+
const progress = opts.onProgress ?? (() => {
|
|
7196
|
+
});
|
|
7197
|
+
const limit = opts.limit ?? 50;
|
|
7198
|
+
const threshold = opts.winOrTieThreshold ?? 0.8;
|
|
7199
|
+
const latencyFloorRatio = opts.latencyFloorRatio ?? 3;
|
|
7200
|
+
const minJudgeable = opts.minJudgeableCases ?? 5;
|
|
7201
|
+
const judgeModel = opts.judgeModel ?? "claude-opus-4-8";
|
|
7202
|
+
const notes = [];
|
|
7203
|
+
const restHeaders = {
|
|
7204
|
+
apikey: opts.serviceKey,
|
|
7205
|
+
Authorization: `Bearer ${opts.serviceKey}`
|
|
7206
|
+
};
|
|
7207
|
+
const rest = (path) => `${opts.supabaseUrl}/rest/v1/${path}`;
|
|
7208
|
+
const setUrl = rest(
|
|
7209
|
+
`kgauto_golden_irs?app_id=eq.${encodeURIComponent(opts.appId)}&intent_archetype=eq.${encodeURIComponent(opts.archetype)}&active=is.true&select=id,app_id,intent_archetype,ir,incumbent_model&order=captured_at.desc&limit=${limit}`
|
|
7210
|
+
);
|
|
7211
|
+
const setRes = await fetchFn(setUrl, { headers: restHeaders });
|
|
7212
|
+
if (!setRes.ok) {
|
|
7213
|
+
throw new Error(
|
|
7214
|
+
`golden-eval: failed to load golden set (${setRes.status}): ${await setRes.text().catch(() => "<no body>")}`
|
|
7215
|
+
);
|
|
7216
|
+
}
|
|
7217
|
+
const goldenRows = await setRes.json();
|
|
7218
|
+
if (goldenRows.length === 0) {
|
|
7219
|
+
throw new Error(
|
|
7220
|
+
`golden-eval: no active golden IRs for (${opts.appId}, ${opts.archetype}) \u2014 seed via KGAUTO_GOLDEN_CAPTURE or scripts/seed-golden-set.mjs first.`
|
|
7221
|
+
);
|
|
7222
|
+
}
|
|
7223
|
+
progress(`Loaded ${goldenRows.length} golden case(s).`);
|
|
7224
|
+
let incumbentModel = opts.incumbentModel;
|
|
7225
|
+
if (!incumbentModel) {
|
|
7226
|
+
const counts = /* @__PURE__ */ new Map();
|
|
7227
|
+
for (const row of goldenRows) {
|
|
7228
|
+
counts.set(row.incumbent_model, (counts.get(row.incumbent_model) ?? 0) + 1);
|
|
7229
|
+
}
|
|
7230
|
+
const top = [...counts.entries()].sort((a, b) => b[1] - a[1])[0];
|
|
7231
|
+
if (!top) throw new Error("golden-eval: could not resolve an incumbent from the golden set.");
|
|
7232
|
+
incumbentModel = top[0];
|
|
7233
|
+
notes.push(`incumbent defaulted to most-captured model: ${incumbentModel}`);
|
|
7234
|
+
}
|
|
7235
|
+
if (incumbentModel === opts.candidateModel) {
|
|
7236
|
+
throw new Error("golden-eval: candidate and incumbent are the same model.");
|
|
7237
|
+
}
|
|
7238
|
+
const judgeProfile = tryGetProfile(judgeModel);
|
|
7239
|
+
if (!judgeProfile) {
|
|
7240
|
+
throw new Error(`golden-eval: judge model '${judgeModel}' is not in the roster.`);
|
|
7241
|
+
}
|
|
7242
|
+
if (judgeProfile.family && [incumbentModel, opts.candidateModel].some(
|
|
7243
|
+
(m) => tryGetProfile(m)?.family === judgeProfile.family
|
|
7244
|
+
)) {
|
|
7245
|
+
notes.push(
|
|
7246
|
+
`WARNING: judge family (${judgeProfile.family}) overlaps a compared model \u2014 self-preference risk; consider --judge from another provider.`
|
|
7247
|
+
);
|
|
7248
|
+
}
|
|
7249
|
+
const replay = async (ir, model) => {
|
|
7250
|
+
try {
|
|
7251
|
+
const evalIr = {
|
|
7252
|
+
...ir,
|
|
7253
|
+
models: [model],
|
|
7254
|
+
constraints: { ...ir.constraints ?? {}, forceModel: model }
|
|
7255
|
+
};
|
|
7256
|
+
const compiled = compile(evalIr);
|
|
7257
|
+
const attempt = () => execute(compiled.request, { apiKeys: opts.apiKeys, fetchImpl: opts.fetchImpl });
|
|
7258
|
+
let started = Date.now();
|
|
7259
|
+
let exec = await attempt();
|
|
7260
|
+
if (!exec.ok && exec.errorType === "retryable") {
|
|
7261
|
+
await new Promise((r) => setTimeout(r, 2e3));
|
|
7262
|
+
started = Date.now();
|
|
7263
|
+
exec = await attempt();
|
|
7264
|
+
}
|
|
7265
|
+
const latencyMs = Date.now() - started;
|
|
7266
|
+
if (!exec.ok) {
|
|
7267
|
+
return {
|
|
7268
|
+
ok: false,
|
|
7269
|
+
text: "",
|
|
7270
|
+
structuredOutput: null,
|
|
7271
|
+
tokensIn: 0,
|
|
7272
|
+
tokensOut: 0,
|
|
7273
|
+
latencyMs,
|
|
7274
|
+
errorClass: exec.errorCode
|
|
7275
|
+
};
|
|
7276
|
+
}
|
|
7277
|
+
const validated = _internal.validateStructuredContract(exec, evalIr);
|
|
7278
|
+
if (!validated.ok) {
|
|
7279
|
+
return {
|
|
7280
|
+
ok: true,
|
|
7281
|
+
text: exec.response.text,
|
|
7282
|
+
structuredOutput: null,
|
|
7283
|
+
tokensIn: exec.response.tokens.input,
|
|
7284
|
+
tokensOut: exec.response.tokens.output,
|
|
7285
|
+
latencyMs,
|
|
7286
|
+
contractViolation: validated.errorCode
|
|
7287
|
+
};
|
|
7288
|
+
}
|
|
7289
|
+
return {
|
|
7290
|
+
ok: true,
|
|
7291
|
+
text: validated.response.text,
|
|
7292
|
+
structuredOutput: validated.response.structuredOutput,
|
|
7293
|
+
parseError: validated.response.parseError,
|
|
7294
|
+
tokensIn: validated.response.tokens.input,
|
|
7295
|
+
tokensOut: validated.response.tokens.output,
|
|
7296
|
+
latencyMs
|
|
7297
|
+
};
|
|
7298
|
+
} catch (err) {
|
|
7299
|
+
return {
|
|
7300
|
+
ok: false,
|
|
7301
|
+
text: "",
|
|
7302
|
+
structuredOutput: null,
|
|
7303
|
+
tokensIn: 0,
|
|
7304
|
+
tokensOut: 0,
|
|
7305
|
+
latencyMs: 0,
|
|
7306
|
+
errorClass: err instanceof Error ? `execute_rejected:${err.message}` : "execute_rejected"
|
|
7307
|
+
};
|
|
7308
|
+
}
|
|
7309
|
+
};
|
|
7310
|
+
const judgeOnce = async (ir, outputA, outputB) => {
|
|
7311
|
+
const judgeIr = {
|
|
7312
|
+
appId: opts.appId,
|
|
7313
|
+
intent: { name: "golden-eval-judge", archetype: "judge" },
|
|
7314
|
+
sections: [
|
|
7315
|
+
{
|
|
7316
|
+
id: "role",
|
|
7317
|
+
text: "You are a strict, impartial pairwise judge. You output only JSON.",
|
|
7318
|
+
weight: 10
|
|
7319
|
+
}
|
|
7320
|
+
],
|
|
7321
|
+
currentTurn: {
|
|
7322
|
+
role: "user",
|
|
7323
|
+
content: buildPairwiseJudgePrompt({
|
|
7324
|
+
archetype: opts.archetype,
|
|
7325
|
+
renderedInput: renderIrForJudge(ir),
|
|
7326
|
+
outputA,
|
|
7327
|
+
outputB
|
|
7328
|
+
})
|
|
7329
|
+
},
|
|
7330
|
+
models: [judgeModel],
|
|
7331
|
+
constraints: { forceModel: judgeModel }
|
|
7332
|
+
};
|
|
7333
|
+
try {
|
|
7334
|
+
const compiled = compile(judgeIr);
|
|
7335
|
+
const exec = await execute(compiled.request, {
|
|
7336
|
+
apiKeys: opts.apiKeys,
|
|
7337
|
+
fetchImpl: opts.fetchImpl
|
|
7338
|
+
});
|
|
7339
|
+
if (!exec.ok) return void 0;
|
|
7340
|
+
return parseJudgeVerdict(exec.response.text);
|
|
7341
|
+
} catch {
|
|
7342
|
+
return void 0;
|
|
7343
|
+
}
|
|
7344
|
+
};
|
|
7345
|
+
const cases = [];
|
|
7346
|
+
const floorDetail = {};
|
|
7347
|
+
const bumpFloor = (k) => {
|
|
7348
|
+
floorDetail[k] = (floorDetail[k] ?? 0) + 1;
|
|
7349
|
+
};
|
|
7350
|
+
for (const [i, row] of goldenRows.entries()) {
|
|
7351
|
+
progress(
|
|
7352
|
+
`Case ${i + 1}/${goldenRows.length} (golden #${row.id}): replaying ${incumbentModel} + ${opts.candidateModel}\u2026`
|
|
7353
|
+
);
|
|
7354
|
+
const [inc, cand] = await Promise.all([
|
|
7355
|
+
replay(row.ir, incumbentModel),
|
|
7356
|
+
replay(row.ir, opts.candidateModel)
|
|
7357
|
+
]);
|
|
7358
|
+
if (!inc.ok || inc.contractViolation) {
|
|
7359
|
+
const why = !inc.ok ? `incumbent replay failed (${inc.errorClass ?? "unknown"})` : `incumbent contract violation (${inc.contractViolation})`;
|
|
7360
|
+
cases.push({
|
|
7361
|
+
goldenIrId: row.id,
|
|
7362
|
+
verdict: "inconclusive",
|
|
7363
|
+
floorViolations: [],
|
|
7364
|
+
excludedReason: why
|
|
7365
|
+
});
|
|
7366
|
+
notes.push(`case #${row.id}: ${why} \u2014 excluded`);
|
|
7367
|
+
continue;
|
|
7368
|
+
}
|
|
7369
|
+
const incumbentLeg = {
|
|
7370
|
+
latencyMs: inc.latencyMs,
|
|
7371
|
+
tokensIn: inc.tokensIn,
|
|
7372
|
+
tokensOut: inc.tokensOut,
|
|
7373
|
+
text: inc.text
|
|
7374
|
+
};
|
|
7375
|
+
const violations = [];
|
|
7376
|
+
if (!cand.ok) {
|
|
7377
|
+
violations.push("candidate_error");
|
|
7378
|
+
bumpFloor("candidate_error");
|
|
7379
|
+
} else if (cand.tokensOut === 0 || cand.text.trim() === "" && !cand.structuredOutput) {
|
|
7380
|
+
violations.push("empty");
|
|
7381
|
+
bumpFloor("empty");
|
|
7382
|
+
} else if (cand.contractViolation) {
|
|
7383
|
+
violations.push("schema");
|
|
7384
|
+
bumpFloor("schema");
|
|
7385
|
+
}
|
|
7386
|
+
if (violations.length > 0) {
|
|
7387
|
+
cases.push({
|
|
7388
|
+
goldenIrId: row.id,
|
|
7389
|
+
verdict: "current-better",
|
|
7390
|
+
floorViolations: violations,
|
|
7391
|
+
errorClass: cand.errorClass ?? cand.contractViolation,
|
|
7392
|
+
incumbent: incumbentLeg,
|
|
7393
|
+
candidate: cand.ok ? { latencyMs: cand.latencyMs, tokensIn: cand.tokensIn, tokensOut: cand.tokensOut, text: cand.text } : void 0
|
|
7394
|
+
});
|
|
7395
|
+
continue;
|
|
7396
|
+
}
|
|
7397
|
+
const [order1, order2] = await Promise.all([
|
|
7398
|
+
judgeOnce(row.ir, inc.text, cand.text),
|
|
7399
|
+
judgeOnce(row.ir, cand.text, inc.text)
|
|
7400
|
+
]);
|
|
7401
|
+
if (!order1 || !order2) {
|
|
7402
|
+
cases.push({
|
|
7403
|
+
goldenIrId: row.id,
|
|
7404
|
+
verdict: "inconclusive",
|
|
7405
|
+
floorViolations: [],
|
|
7406
|
+
incumbent: incumbentLeg,
|
|
7407
|
+
candidate: { latencyMs: cand.latencyMs, tokensIn: cand.tokensIn, tokensOut: cand.tokensOut, text: cand.text },
|
|
7408
|
+
excludedReason: "judge call failed or unparseable"
|
|
7409
|
+
});
|
|
7410
|
+
notes.push(`case #${row.id}: judge failed \u2014 excluded`);
|
|
7411
|
+
continue;
|
|
7412
|
+
}
|
|
7413
|
+
const v1 = order1.winner === "tie" ? "tied" : order1.winner === "B" ? "candidate-better" : "current-better";
|
|
7414
|
+
const v2 = order2.winner === "tie" ? "tied" : order2.winner === "A" ? "candidate-better" : "current-better";
|
|
7415
|
+
const verdict2 = combineOrderSwappedVerdicts(v1, v2);
|
|
7416
|
+
cases.push({
|
|
7417
|
+
goldenIrId: row.id,
|
|
7418
|
+
verdict: verdict2,
|
|
7419
|
+
judgeRationale: order1.rationale ?? order2.rationale,
|
|
7420
|
+
floorViolations: [],
|
|
7421
|
+
incumbent: incumbentLeg,
|
|
7422
|
+
candidate: { latencyMs: cand.latencyMs, tokensIn: cand.tokensIn, tokensOut: cand.tokensOut, text: cand.text }
|
|
7423
|
+
});
|
|
7424
|
+
}
|
|
7425
|
+
const evaluable = cases.filter((c) => !c.excludedReason);
|
|
7426
|
+
const wins = evaluable.filter((c) => c.verdict === "candidate-better").length;
|
|
7427
|
+
const ties = evaluable.filter((c) => c.verdict === "tied").length;
|
|
7428
|
+
const losses = evaluable.filter((c) => c.verdict === "current-better").length;
|
|
7429
|
+
const floorViolations = evaluable.reduce((n, c) => n + c.floorViolations.length, 0);
|
|
7430
|
+
const winOrTieRatio = evaluable.length > 0 ? (wins + ties) / evaluable.length : null;
|
|
7431
|
+
const incP50 = p50(evaluable.map((c) => c.incumbent?.latencyMs ?? NaN).filter(Number.isFinite));
|
|
7432
|
+
const candP50 = p50(evaluable.map((c) => c.candidate?.latencyMs ?? NaN).filter(Number.isFinite));
|
|
7433
|
+
const latencyRatio = incP50 && candP50 ? candP50 / incP50 : null;
|
|
7434
|
+
const sum = (xs) => xs.some((x) => x === null) ? null : xs.reduce((a, b) => a + b, 0);
|
|
7435
|
+
const costIncumbentUsd = sum(
|
|
7436
|
+
evaluable.map(
|
|
7437
|
+
(c) => c.incumbent ? costUsd(incumbentModel, c.incumbent.tokensIn, c.incumbent.tokensOut) : null
|
|
7438
|
+
)
|
|
7439
|
+
);
|
|
7440
|
+
const costCandidateUsd = sum(
|
|
7441
|
+
evaluable.map(
|
|
7442
|
+
(c) => c.candidate ? costUsd(opts.candidateModel, c.candidate.tokensIn, c.candidate.tokensOut) : null
|
|
7443
|
+
)
|
|
7444
|
+
);
|
|
7445
|
+
const latencyFloorOk = latencyRatio === null || latencyRatio <= latencyFloorRatio;
|
|
7446
|
+
if (!latencyFloorOk) bumpFloor("latency");
|
|
7447
|
+
let verdict;
|
|
7448
|
+
if (evaluable.length < minJudgeable) {
|
|
7449
|
+
verdict = "inconclusive";
|
|
7450
|
+
notes.push(
|
|
7451
|
+
`only ${evaluable.length} evaluable case(s) < minJudgeableCases=${minJudgeable}`
|
|
7452
|
+
);
|
|
7453
|
+
} else if (winOrTieRatio !== null && winOrTieRatio >= threshold && floorViolations === 0 && latencyFloorOk) {
|
|
7454
|
+
verdict = "promote-ready";
|
|
7455
|
+
} else {
|
|
7456
|
+
verdict = "not-inferior";
|
|
7457
|
+
}
|
|
7458
|
+
const result = {
|
|
7459
|
+
verdict,
|
|
7460
|
+
appId: opts.appId,
|
|
7461
|
+
archetype: opts.archetype,
|
|
7462
|
+
incumbentModel,
|
|
7463
|
+
candidateModel: opts.candidateModel,
|
|
7464
|
+
judgeModel,
|
|
7465
|
+
nCases: evaluable.length,
|
|
7466
|
+
wins,
|
|
7467
|
+
ties,
|
|
7468
|
+
losses,
|
|
7469
|
+
floorViolations: floorViolations + (latencyFloorOk ? 0 : 1),
|
|
7470
|
+
floorDetail,
|
|
7471
|
+
winOrTieRatio,
|
|
7472
|
+
latencyRatio,
|
|
7473
|
+
costIncumbentUsd,
|
|
7474
|
+
costCandidateUsd,
|
|
7475
|
+
cases,
|
|
7476
|
+
notes
|
|
7477
|
+
};
|
|
7478
|
+
if (opts.dryRun) {
|
|
7479
|
+
notes.push("dry-run: no brain rows written");
|
|
7480
|
+
return result;
|
|
7481
|
+
}
|
|
7482
|
+
progress("Writing eval evidence to the brain\u2026");
|
|
7483
|
+
const runRes = await fetchFn(rest("kgauto_golden_eval_runs"), {
|
|
7484
|
+
method: "POST",
|
|
7485
|
+
headers: {
|
|
7486
|
+
...restHeaders,
|
|
7487
|
+
"Content-Type": "application/json",
|
|
7488
|
+
Prefer: "return=representation"
|
|
7489
|
+
},
|
|
7490
|
+
body: JSON.stringify({
|
|
7491
|
+
app_id: opts.appId,
|
|
7492
|
+
intent_archetype: opts.archetype,
|
|
7493
|
+
incumbent_model: incumbentModel,
|
|
7494
|
+
candidate_model: opts.candidateModel,
|
|
7495
|
+
trigger_source: opts.triggerSource ?? "manual",
|
|
7496
|
+
judge_model: judgeModel,
|
|
7497
|
+
n_cases: result.nCases,
|
|
7498
|
+
wins,
|
|
7499
|
+
ties,
|
|
7500
|
+
losses,
|
|
7501
|
+
floor_violations: result.floorViolations,
|
|
7502
|
+
floor_detail: floorDetail,
|
|
7503
|
+
win_or_tie_ratio: winOrTieRatio,
|
|
7504
|
+
latency_ratio: latencyRatio,
|
|
7505
|
+
verdict,
|
|
7506
|
+
win_or_tie_threshold: threshold,
|
|
7507
|
+
notes: notes.join(" | ") || null
|
|
7508
|
+
})
|
|
7509
|
+
});
|
|
7510
|
+
if (!runRes.ok) {
|
|
7511
|
+
throw new Error(
|
|
7512
|
+
`golden-eval: run-row write failed (${runRes.status}): ${await runRes.text().catch(() => "<no body>")}`
|
|
7513
|
+
);
|
|
7514
|
+
}
|
|
7515
|
+
const runRows = await runRes.json();
|
|
7516
|
+
result.runId = runRows[0]?.id;
|
|
7517
|
+
const caseRows = cases.filter((c) => !c.excludedReason).map((c) => {
|
|
7518
|
+
const row = goldenRows.find((g) => g.id === c.goldenIrId);
|
|
7519
|
+
const turn = typeof row?.ir.currentTurn?.content === "string" ? row.ir.currentTurn.content : "";
|
|
7520
|
+
return {
|
|
7521
|
+
app_id: opts.appId,
|
|
7522
|
+
intent_archetype: opts.archetype,
|
|
7523
|
+
family: tryGetProfile(opts.candidateModel)?.family ?? "unknown",
|
|
7524
|
+
candidate_model: opts.candidateModel,
|
|
7525
|
+
current_model: incumbentModel,
|
|
7526
|
+
prompt_hash: hashForGolden(turn),
|
|
7527
|
+
current_response: c.incumbent?.text.slice(0, 500) ?? null,
|
|
7528
|
+
candidate_response: c.candidate?.text.slice(0, 500) ?? null,
|
|
7529
|
+
judge_verdict: c.floorViolations.length > 0 ? null : c.verdict,
|
|
7530
|
+
judge_rationale: c.floorViolations.length > 0 ? `hard-floor violation: ${c.floorViolations.join(",")}` : c.judgeRationale ?? null,
|
|
7531
|
+
judge_model: judgeModel,
|
|
7532
|
+
tokens_current_in: c.incumbent?.tokensIn ?? null,
|
|
7533
|
+
tokens_current_out: c.incumbent?.tokensOut ?? null,
|
|
7534
|
+
tokens_candidate_in: c.candidate?.tokensIn ?? null,
|
|
7535
|
+
tokens_candidate_out: c.candidate?.tokensOut ?? null,
|
|
7536
|
+
latency_current_ms: c.incumbent?.latencyMs ?? null,
|
|
7537
|
+
latency_candidate_ms: c.candidate?.latencyMs ?? null,
|
|
7538
|
+
prompt_fidelity: 1,
|
|
7539
|
+
replay_source: "golden-replay",
|
|
7540
|
+
outcome: c.floorViolations.includes("candidate_error") ? "candidate_error" : "completed",
|
|
7541
|
+
// migration-032 taxonomy: error_class only on candidate_error rows;
|
|
7542
|
+
// schema-floor detail rides in judge_rationale + the run's floor_detail.
|
|
7543
|
+
error_class: c.floorViolations.includes("candidate_error") ? c.errorClass ?? null : null,
|
|
7544
|
+
golden_run_id: result.runId ?? null,
|
|
7545
|
+
golden_ir_id: c.goldenIrId
|
|
7546
|
+
};
|
|
7547
|
+
});
|
|
7548
|
+
if (caseRows.length > 0) {
|
|
7549
|
+
const casesRes = await fetchFn(rest("probe_outcomes"), {
|
|
7550
|
+
method: "POST",
|
|
7551
|
+
headers: { ...restHeaders, "Content-Type": "application/json", Prefer: "return=minimal" },
|
|
7552
|
+
body: JSON.stringify(caseRows)
|
|
7553
|
+
});
|
|
7554
|
+
if (!casesRes.ok) {
|
|
7555
|
+
notes.push(
|
|
7556
|
+
`case-row write failed (${casesRes.status}): ${await casesRes.text().catch(() => "<no body>")}`
|
|
7557
|
+
);
|
|
7558
|
+
}
|
|
7559
|
+
}
|
|
7560
|
+
const latestRes = await fetchFn(
|
|
7561
|
+
rest(
|
|
7562
|
+
`compile_outcomes?app_id=eq.${encodeURIComponent(opts.appId)}&select=id&order=id.desc&limit=1`
|
|
7563
|
+
),
|
|
7564
|
+
{ headers: restHeaders }
|
|
7565
|
+
);
|
|
7566
|
+
const latest = latestRes.ok ? await latestRes.json() : [];
|
|
7567
|
+
const latestOutcomeId = latest[0]?.id;
|
|
7568
|
+
if (latestOutcomeId !== void 0) {
|
|
7569
|
+
const costLine = costIncumbentUsd !== null && costCandidateUsd !== null ? ` Eval cost basis: incumbent $${costIncumbentUsd.toFixed(4)} vs candidate $${costCandidateUsd.toFixed(4)} across the set.` : "";
|
|
7570
|
+
const message = `Golden-set eval (run #${result.runId}): ${opts.candidateModel} vs ${incumbentModel} on ${opts.appId}/${opts.archetype} \u2014 verdict ${verdict.toUpperCase()}. ${wins}W/${ties}T/${losses}L over ${result.nCases} real workload case(s), wins-or-ties ${(100 * (winOrTieRatio ?? 0)).toFixed(0)}% (threshold ${(100 * threshold).toFixed(0)}%), ${result.floorViolations} hard-floor violation(s), latency ratio ${latencyRatio?.toFixed(2) ?? "n/a"}.` + costLine;
|
|
7571
|
+
const suggestion = verdict === "promote-ready" ? `Candidate passed the non-inferiority rule on your real workload. To promote: node v2/scripts/promote-model.mjs --model ${opts.candidateModel} (or ask kgauto-Cairn). Evidence: kgauto_golden_eval_runs #${result.runId} + probe_outcomes golden_run_id=${result.runId}.` : `Candidate did NOT clear the non-inferiority rule \u2014 no action needed; the incumbent stays. Evidence rows: golden_run_id=${result.runId}.`;
|
|
7572
|
+
const advRes = await fetchFn(rest("compile_outcome_advisories"), {
|
|
7573
|
+
method: "POST",
|
|
7574
|
+
headers: { ...restHeaders, "Content-Type": "application/json", Prefer: "return=minimal" },
|
|
7575
|
+
body: JSON.stringify({
|
|
7576
|
+
outcome_id: latestOutcomeId,
|
|
7577
|
+
code: "golden-eval-verdict",
|
|
7578
|
+
level: "info",
|
|
7579
|
+
recommendation_type: "model-swap",
|
|
7580
|
+
message,
|
|
7581
|
+
suggestion
|
|
7582
|
+
})
|
|
7583
|
+
});
|
|
7584
|
+
if (advRes.ok) {
|
|
7585
|
+
result.advisoryOutcomeId = latestOutcomeId;
|
|
7586
|
+
await fetchFn(rest(`kgauto_golden_eval_runs?id=eq.${result.runId}`), {
|
|
7587
|
+
method: "PATCH",
|
|
7588
|
+
headers: { ...restHeaders, "Content-Type": "application/json", Prefer: "return=minimal" },
|
|
7589
|
+
body: JSON.stringify({ advisory_outcome_id: latestOutcomeId })
|
|
7590
|
+
}).catch(() => {
|
|
7591
|
+
});
|
|
7592
|
+
} else {
|
|
7593
|
+
notes.push(`advisory write failed (${advRes.status})`);
|
|
7594
|
+
}
|
|
7595
|
+
} else {
|
|
7596
|
+
notes.push("no compile_outcomes row for app \u2014 evidence advisory skipped (view needs a real outcome_id)");
|
|
7597
|
+
}
|
|
7598
|
+
return result;
|
|
7599
|
+
}
|
|
7600
|
+
|
|
6787
7601
|
// src/brain-proxy.ts
|
|
6788
7602
|
var SEGMENT_TO_TABLE = {
|
|
6789
7603
|
outcomes: "compile_outcomes",
|
|
6790
7604
|
compile_outcome_advisories: "compile_outcome_advisories",
|
|
6791
7605
|
compile_outcome_quality: "compile_outcome_quality",
|
|
6792
|
-
probe_outcomes: "probe_outcomes"
|
|
7606
|
+
probe_outcomes: "probe_outcomes",
|
|
7607
|
+
// alpha.62 (eval spine): golden-set capture. Only receives rows when the
|
|
7608
|
+
// consumer has explicitly opted in via KGAUTO_GOLDEN_CAPTURE — the segment
|
|
7609
|
+
// existing here does not by itself store anything.
|
|
7610
|
+
golden_irs: "kgauto_golden_irs"
|
|
6793
7611
|
};
|
|
6794
7612
|
var KNOWN_SEGMENTS = Object.keys(SEGMENT_TO_TABLE);
|
|
6795
7613
|
var JSON_HEADERS = { "Content-Type": "application/json" };
|
|
@@ -6947,7 +7765,7 @@ function createBrainForwardRoutes(config) {
|
|
|
6947
7765
|
}
|
|
6948
7766
|
|
|
6949
7767
|
// src/version.ts
|
|
6950
|
-
var LIBRARY_VERSION = "2.0.0-alpha.
|
|
7768
|
+
var LIBRARY_VERSION = "2.0.0-alpha.62";
|
|
6951
7769
|
|
|
6952
7770
|
// src/key-health.ts
|
|
6953
7771
|
var JSON_HEADERS2 = { "Content-Type": "application/json" };
|
|
@@ -7570,6 +8388,7 @@ function compile2(ir, opts) {
|
|
|
7570
8388
|
DIALECT_VERSION,
|
|
7571
8389
|
FamilyResolutionError,
|
|
7572
8390
|
INTENT_ARCHETYPES,
|
|
8391
|
+
JUDGE_RUBRICS,
|
|
7573
8392
|
LATENCY_TIER_MS,
|
|
7574
8393
|
LIBRARY_VERSION,
|
|
7575
8394
|
MEASURED_GROUNDING_MIN_N,
|
|
@@ -7581,13 +8400,18 @@ function compile2(ir, opts) {
|
|
|
7581
8400
|
applyArchetypeConvention,
|
|
7582
8401
|
applySectionRewrites,
|
|
7583
8402
|
attachCacheControlToStreamTextInput,
|
|
8403
|
+
brainHealth,
|
|
7584
8404
|
bucketContext,
|
|
7585
8405
|
bucketHistory,
|
|
7586
8406
|
bucketToolCount,
|
|
8407
|
+
buildGoldenIrRow,
|
|
7587
8408
|
buildLLMJudge,
|
|
8409
|
+
buildPairwiseJudgePrompt,
|
|
7588
8410
|
buildShadowProbeRow,
|
|
7589
8411
|
call,
|
|
8412
|
+
captureGoldenIr,
|
|
7590
8413
|
clearBrain,
|
|
8414
|
+
combineOrderSwappedVerdicts,
|
|
7591
8415
|
compile,
|
|
7592
8416
|
compileForAISDKv6,
|
|
7593
8417
|
configureBrain,
|
|
@@ -7598,6 +8422,7 @@ function compile2(ir, opts) {
|
|
|
7598
8422
|
deriveOwnership,
|
|
7599
8423
|
execute,
|
|
7600
8424
|
findBetterFit,
|
|
8425
|
+
flushBrainDeadLetter,
|
|
7601
8426
|
getActionableAdvisories,
|
|
7602
8427
|
getAllStarterChains,
|
|
7603
8428
|
getAllStarterChainsWithGrounding,
|
|
@@ -7632,18 +8457,27 @@ function compile2(ir, opts) {
|
|
|
7632
8457
|
markAdvisoryResolved,
|
|
7633
8458
|
markExclusionFindingHandled,
|
|
7634
8459
|
markPromoteReadyHandled,
|
|
8460
|
+
parseGoldenCaptureRate,
|
|
8461
|
+
parseJudgeVerdict,
|
|
8462
|
+
peekBrainDeadLetter,
|
|
7635
8463
|
probeShadow,
|
|
7636
8464
|
profileToRow,
|
|
7637
8465
|
profilesByProvider,
|
|
7638
8466
|
readBrainReadEnv,
|
|
7639
8467
|
record,
|
|
8468
|
+
recordGoldenIr,
|
|
7640
8469
|
recordOutcome,
|
|
7641
8470
|
recordShadowProbe,
|
|
8471
|
+
renderIrForJudge,
|
|
7642
8472
|
resetTokenizer,
|
|
7643
8473
|
resolveConventionsForProfile,
|
|
8474
|
+
resolveGoldenCaptureRate,
|
|
7644
8475
|
resolvePricingAt,
|
|
7645
8476
|
resolveProviderKey,
|
|
8477
|
+
rubricFor,
|
|
7646
8478
|
runAdvisor,
|
|
8479
|
+
runGoldenEval,
|
|
7647
8480
|
setTokenizer,
|
|
8481
|
+
shouldCaptureGolden,
|
|
7648
8482
|
tryGetProfile
|
|
7649
8483
|
});
|