modelrig 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +156 -0
- package/README.md +27 -2
- package/dist/artifacts/artifact.d.ts +12 -13
- package/dist/artifacts/artifact.d.ts.map +1 -1
- package/dist/artifacts/artifact.js +17 -23
- package/dist/artifacts/index.d.ts +13 -5
- package/dist/artifacts/index.d.ts.map +1 -1
- package/dist/artifacts/index.js +11 -4
- package/dist/artifacts/run-context.d.ts +3 -24
- package/dist/artifacts/run-context.d.ts.map +1 -1
- package/dist/artifacts/run-context.js +3 -39
- package/dist/bakeoff/engine.d.ts +29 -0
- package/dist/bakeoff/engine.d.ts.map +1 -1
- package/dist/bakeoff/engine.js +47 -0
- package/dist/bakeoff/eval-cases-rig.d.ts +36 -0
- package/dist/bakeoff/eval-cases-rig.d.ts.map +1 -0
- package/dist/bakeoff/eval-cases-rig.js +27 -0
- package/dist/bakeoff/eval-cases.d.ts +19 -0
- package/dist/bakeoff/eval-cases.d.ts.map +1 -1
- package/dist/bakeoff/eval-cases.js +18 -1
- package/dist/bakeoff/golden-judge.d.ts +47 -0
- package/dist/bakeoff/golden-judge.d.ts.map +1 -0
- package/dist/bakeoff/golden-judge.js +49 -0
- package/dist/bakeoff/quality.d.ts +30 -0
- package/dist/bakeoff/quality.d.ts.map +1 -1
- package/dist/bakeoff/quality.js +21 -0
- package/dist/bakeoff/replay.d.ts +11 -0
- package/dist/bakeoff/replay.d.ts.map +1 -1
- package/dist/bakeoff/replay.js +8 -0
- package/dist/bakeoff/report.d.ts +7 -0
- package/dist/bakeoff/report.d.ts.map +1 -1
- package/dist/bakeoff/report.js +26 -0
- package/dist/cli-judge.d.ts +12 -0
- package/dist/cli-judge.d.ts.map +1 -0
- package/dist/cli-judge.js +48 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +14 -42
- package/dist/config.d.ts +54 -29
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +86 -47
- package/dist/detect/detector.d.ts +4 -2
- package/dist/detect/detector.d.ts.map +1 -1
- package/dist/detect/safe-harbor.d.ts +57 -0
- package/dist/detect/safe-harbor.d.ts.map +1 -0
- package/dist/detect/safe-harbor.js +278 -0
- package/dist/feedback/coverage.d.ts +11 -8
- package/dist/feedback/coverage.d.ts.map +1 -1
- package/dist/feedback/coverage.js +29 -16
- package/dist/feedback/grade.d.ts +51 -0
- package/dist/feedback/grade.d.ts.map +1 -0
- package/dist/feedback/grade.js +63 -0
- package/dist/gateway/http-protocol.d.ts +1 -1
- package/dist/gateway/http-protocol.d.ts.map +1 -1
- package/dist/gateway/http-protocol.js +1 -1
- package/dist/index.d.ts +44 -27
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +110 -43
- package/dist/init/observe-cli.js +1 -1
- package/dist/init/observe.d.ts +2 -2
- package/dist/init/observe.d.ts.map +1 -1
- package/dist/init/observe.js +11 -7
- package/dist/mask/arm.d.ts +112 -0
- package/dist/mask/arm.d.ts.map +1 -0
- package/dist/mask/arm.js +179 -0
- package/dist/mask/index.d.ts +2 -0
- package/dist/mask/index.d.ts.map +1 -1
- package/dist/mask/index.js +7 -1
- package/dist/mask/mask-policy-cli.d.ts +12 -4
- package/dist/mask/mask-policy-cli.d.ts.map +1 -1
- package/dist/mask/mask-policy-cli.js +34 -9
- package/dist/query/grammar.d.ts +2 -2
- package/dist/query/grammar.d.ts.map +1 -1
- package/dist/query/grammar.js +3 -1
- package/dist/query/saved.d.ts +13 -0
- package/dist/query/saved.d.ts.map +1 -1
- package/dist/query/saved.js +67 -1
- package/dist/receipts/types.d.ts +1 -1
- package/dist/receipts/types.d.ts.map +1 -1
- package/dist/receipts/types.js +1 -0
- package/dist/registry/build.d.ts +43 -1
- package/dist/registry/build.d.ts.map +1 -1
- package/dist/registry/build.js +52 -0
- package/dist/registry/pricing-shape.d.ts +29 -0
- package/dist/registry/pricing-shape.d.ts.map +1 -1
- package/dist/registry/pricing-shape.js +10 -1
- package/dist/registry/rows.d.ts.map +1 -1
- package/dist/registry/rows.js +1 -0
- package/dist/registry/select.d.ts +6 -1
- package/dist/registry/select.d.ts.map +1 -1
- package/dist/registry/select.js +11 -0
- package/dist/routes/call-config.d.ts +199 -0
- package/dist/routes/call-config.d.ts.map +1 -0
- package/dist/routes/call-config.js +343 -0
- package/dist/routes/loader.js +5 -3
- package/dist/routes/objective-loader.d.ts +12 -0
- package/dist/routes/objective-loader.d.ts.map +1 -1
- package/dist/routes/objective-loader.js +82 -0
- package/dist/routes/resolved-bundle.d.ts +50 -0
- package/dist/routes/resolved-bundle.d.ts.map +1 -1
- package/dist/routes/resolved-bundle.js +52 -0
- package/dist/routes/screen-loader.d.ts +28 -0
- package/dist/routes/screen-loader.d.ts.map +1 -1
- package/dist/routes/screen-loader.js +51 -0
- package/dist/run/accept.d.ts +2 -0
- package/dist/run/accept.d.ts.map +1 -1
- package/dist/run/accept.js +1 -0
- package/dist/run/dispatch.d.ts +42 -13
- package/dist/run/dispatch.d.ts.map +1 -1
- package/dist/run/dispatch.js +107 -25
- package/dist/run/grounding.d.ts +28 -2
- package/dist/run/grounding.d.ts.map +1 -1
- package/dist/run/grounding.js +54 -10
- package/dist/run/record-attempt.d.ts +4 -0
- package/dist/run/record-attempt.d.ts.map +1 -1
- package/dist/run/record-attempt.js +4 -0
- package/dist/run/routing-docs.js +1 -1
- package/dist/run/run.d.ts.map +1 -1
- package/dist/run/run.js +21 -26
- package/dist/savings/odometer.d.ts +4 -0
- package/dist/savings/odometer.d.ts.map +1 -1
- package/dist/savings/odometer.js +20 -1
- package/dist/savings/swap-execute.d.ts +7 -0
- package/dist/savings/swap-execute.d.ts.map +1 -1
- package/dist/savings/swap-execute.js +30 -0
- package/dist/savings/swaps-client.d.ts +10 -0
- package/dist/savings/swaps-client.d.ts.map +1 -1
- package/dist/screen/fixtures/probe-corpora.d.ts +23 -0
- package/dist/screen/fixtures/probe-corpora.d.ts.map +1 -0
- package/dist/screen/fixtures/probe-corpora.js +69 -0
- package/dist/screen/index.d.ts +21 -0
- package/dist/screen/index.d.ts.map +1 -0
- package/dist/screen/index.js +64 -0
- package/dist/screen/model-screen.d.ts +111 -0
- package/dist/screen/model-screen.d.ts.map +1 -0
- package/dist/screen/model-screen.js +178 -0
- package/dist/screen/patterns.d.ts +51 -0
- package/dist/screen/patterns.d.ts.map +1 -0
- package/dist/screen/patterns.js +151 -0
- package/dist/screen/phi-gate.d.ts +52 -0
- package/dist/screen/phi-gate.d.ts.map +1 -0
- package/dist/screen/phi-gate.js +86 -0
- package/dist/screen/policy.d.ts +71 -0
- package/dist/screen/policy.d.ts.map +1 -0
- package/dist/screen/policy.js +334 -0
- package/dist/screen/probe.d.ts +118 -0
- package/dist/screen/probe.d.ts.map +1 -0
- package/dist/screen/probe.js +132 -0
- package/dist/screen/screen-cli.d.ts +16 -0
- package/dist/screen/screen-cli.d.ts.map +1 -0
- package/dist/screen/screen-cli.js +178 -0
- package/dist/screen/screen.d.ts +99 -0
- package/dist/screen/screen.d.ts.map +1 -0
- package/dist/screen/screen.js +0 -0
- package/dist/screen/sidecar.d.ts +69 -0
- package/dist/screen/sidecar.d.ts.map +1 -0
- package/dist/screen/sidecar.js +145 -0
- package/dist/screen/types.d.ts +43 -2
- package/dist/screen/types.d.ts.map +1 -1
- package/dist/settings/api-fetcher.d.ts +14 -3
- package/dist/settings/api-fetcher.d.ts.map +1 -1
- package/dist/settings/api-fetcher.js +61 -10
- package/dist/settings/grading-guide.d.ts +76 -0
- package/dist/settings/grading-guide.d.ts.map +1 -0
- package/dist/settings/grading-guide.js +23 -0
- package/dist/settings/index.d.ts +3 -2
- package/dist/settings/index.d.ts.map +1 -1
- package/dist/settings/index.js +2 -1
- package/dist/settings/task-settings.d.ts +44 -7
- package/dist/settings/task-settings.d.ts.map +1 -1
- package/dist/settings/task-settings.js +53 -12
- package/dist/status.d.ts +26 -20
- package/dist/status.d.ts.map +1 -1
- package/dist/status.js +47 -29
- package/dist/telemetry/artifact-store.d.ts +5 -6
- package/dist/telemetry/artifact-store.d.ts.map +1 -1
- package/dist/telemetry/artifact-store.js +10 -24
- package/dist/telemetry/attempt-meta.d.ts +21 -0
- package/dist/telemetry/attempt-meta.d.ts.map +1 -1
- package/dist/telemetry/attempt-meta.js +9 -0
- package/dist/telemetry/exporter.d.ts +2 -2
- package/dist/telemetry/exporter.d.ts.map +1 -1
- package/dist/telemetry/exporter.js +22 -41
- package/dist/telemetry/grade-mappers.d.ts +22 -0
- package/dist/telemetry/grade-mappers.d.ts.map +1 -0
- package/dist/telemetry/grade-mappers.js +58 -0
- package/dist/telemetry/grades-sql.d.ts +53 -0
- package/dist/telemetry/grades-sql.d.ts.map +1 -0
- package/dist/telemetry/grades-sql.js +133 -0
- package/dist/telemetry/ingest-protocol.d.ts +29 -46
- package/dist/telemetry/ingest-protocol.d.ts.map +1 -1
- package/dist/telemetry/ingest-protocol.js +16 -54
- package/dist/telemetry/store-migrations.d.ts.map +1 -1
- package/dist/telemetry/store-migrations.js +51 -0
- package/dist/telemetry/store.d.ts +9 -6
- package/dist/telemetry/store.d.ts.map +1 -1
- package/dist/telemetry/store.js +8 -50
- package/dist/tenancy/api-key-format.d.ts +30 -1
- package/dist/tenancy/api-key-format.d.ts.map +1 -1
- package/dist/tenancy/api-key-format.js +33 -1
- package/dist/types/provider.d.ts +3 -0
- package/dist/types/provider.d.ts.map +1 -1
- package/dist/types/provider.js +25 -0
- package/dist/types/route.d.ts +78 -2
- package/dist/types/route.d.ts.map +1 -1
- package/dist/types/telemetry.d.ts +43 -46
- package/dist/types/telemetry.d.ts.map +1 -1
- package/dist/validate-cli.d.ts.map +1 -1
- package/dist/validate-cli.js +32 -0
- package/dist/verify/verify.d.ts +5 -0
- package/dist/verify/verify.d.ts.map +1 -1
- package/dist/verify/verify.js +2 -0
- package/dist/watch/evaluate.d.ts +84 -1
- package/dist/watch/evaluate.d.ts.map +1 -1
- package/dist/watch/evaluate.js +28 -0
- package/dist/watch/monitor.d.ts +8 -2
- package/dist/watch/monitor.d.ts.map +1 -1
- package/dist/watch/monitor.js +13 -5
- package/dist/watch/regret-monitor-cli.d.ts +16 -0
- package/dist/watch/regret-monitor-cli.d.ts.map +1 -0
- package/dist/watch/regret-monitor-cli.js +137 -0
- package/dist/watch/regret-monitor.d.ts +168 -0
- package/dist/watch/regret-monitor.d.ts.map +1 -0
- package/dist/watch/regret-monitor.js +304 -0
- package/dist/watch/upgrade.d.ts +62 -0
- package/dist/watch/upgrade.d.ts.map +1 -0
- package/dist/watch/upgrade.js +57 -0
- package/docs/agent-skill/SKILL.md +109 -5
- package/docs/how-it-fits.md +3 -2
- package/docs/instrumentation.md +149 -21
- package/docs/llms.txt +64 -20
- package/docs/mcp-oracle.md +249 -0
- package/docs/quickstart.md +103 -9
- package/package.json +16 -3
- package/registry/leaderboard.json +74 -0
- package/registry/registry.json +150 -112
- package/screen.d.ts +16 -0
- package/templates/call-disposition-qa.json +77 -0
- package/templates/catalog-cleansing.json +77 -0
- package/templates/compliance-review.json +76 -0
- package/templates/cs-next-action.json +76 -0
- package/templates/document-extraction.json +78 -0
- package/templates/financial-classification.json +75 -0
- package/templates/lead-qualification.json +76 -0
- package/templates/medical-classification.json +71 -0
- package/templates/ticket-triage.json +76 -0
- package/dist/telemetry/supabase-exporter.d.ts +0 -64
- package/dist/telemetry/supabase-exporter.d.ts.map +0 -1
- package/dist/telemetry/supabase-exporter.js +0 -211
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
* write that fails is logged and dropped; the customer's pipeline is untouched.
|
|
15
15
|
*
|
|
16
16
|
* ── GATING ────────────────────────────────────────────────────────────────
|
|
17
|
-
* The namespace is inert unless the rig enabled it (
|
|
17
|
+
* The namespace is inert unless the rig enabled it (a control plane is configured,
|
|
18
|
+
* or the dev-only local force-on; the org capture posture governs at runtime).
|
|
18
19
|
* A disabled namespace's `run.start()` sets NO context, so `getActiveRunContext`
|
|
19
20
|
* returns null everywhere and the run loop's auto-step is never reached —
|
|
20
21
|
* v1 wire, zero new rows, zero behaviour change (spec §1.4).
|
|
@@ -129,30 +130,7 @@ function warnOnce(scope, err) {
|
|
|
129
130
|
}
|
|
130
131
|
function createRunNamespace(deps) {
|
|
131
132
|
const { buffer, enabled } = deps;
|
|
132
|
-
const
|
|
133
|
-
/** Write ONE run-subject evaluation (artifactId null, runId set). Fail-open. */
|
|
134
|
-
function writeRunEvaluation(runId, opts) {
|
|
135
|
-
if (!enabled || evalStore === undefined || runId === "")
|
|
136
|
-
return;
|
|
137
|
-
try {
|
|
138
|
-
evalStore.recordArtifactEvaluation({
|
|
139
|
-
id: (0, node_crypto_1.randomUUID)(),
|
|
140
|
-
artifactId: null,
|
|
141
|
-
runId,
|
|
142
|
-
evaluator: opts.evaluator,
|
|
143
|
-
evaluatorKind: opts.kind,
|
|
144
|
-
score: opts.score ?? null,
|
|
145
|
-
passed: opts.passed ?? null,
|
|
146
|
-
label: opts.label ?? null,
|
|
147
|
-
explanation: opts.explanation ?? null,
|
|
148
|
-
createdBy: null,
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
|
-
catch (err) {
|
|
152
|
-
warnOnce("run.evaluate", err);
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
const inertHandle = { runId: "", end() { }, evaluate() { } };
|
|
133
|
+
const inertHandle = { runId: "", end() { } };
|
|
156
134
|
function buildContext(startRow, traceId, zeroRetention) {
|
|
157
135
|
const runId = startRow.id;
|
|
158
136
|
const episodeKey = startRow.episodeKey;
|
|
@@ -250,7 +228,6 @@ function createRunNamespace(deps) {
|
|
|
250
228
|
return {
|
|
251
229
|
runId: ctx.runId,
|
|
252
230
|
end: (status) => endContext(ctx, status),
|
|
253
|
-
evaluate: (opts2) => writeRunEvaluation(ctx.runId, opts2),
|
|
254
231
|
};
|
|
255
232
|
},
|
|
256
233
|
end(status) {
|
|
@@ -258,19 +235,6 @@ function createRunNamespace(deps) {
|
|
|
258
235
|
if (ctx !== undefined)
|
|
259
236
|
endContext(ctx, status);
|
|
260
237
|
},
|
|
261
|
-
evaluate(opts) {
|
|
262
|
-
const ctx = storage.getStore();
|
|
263
|
-
// `ended` counts as gone — same rule as getActiveRunContext. `enterWith`
|
|
264
|
-
// has no lexical exit, so an ended run's context stays ambient on this
|
|
265
|
-
// async path; without this check ns.evaluate re-attributes verdicts to
|
|
266
|
-
// the ended run (post-end verdicts belong to the HANDLE, which closes
|
|
267
|
-
// over its runId — that path is unaffected).
|
|
268
|
-
if (ctx === undefined || ctx.ended) {
|
|
269
|
-
console.warn("[modelrig artifacts] run.evaluate() with no active run — dropped");
|
|
270
|
-
return;
|
|
271
|
-
}
|
|
272
|
-
writeRunEvaluation(ctx.runId, opts);
|
|
273
|
-
},
|
|
274
238
|
async scope(opts, fn) {
|
|
275
239
|
if (!enabled)
|
|
276
240
|
return fn();
|
package/dist/bakeoff/engine.d.ts
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
import type { CaptureStore } from "../telemetry/capture";
|
|
14
14
|
import type { RunDeps } from "../run/run";
|
|
15
15
|
import type { CandidateSpec, ObjectiveMode, RouteBundle } from "../types/route";
|
|
16
|
+
import type { GraderType } from "./quality";
|
|
16
17
|
import type { QualityGate } from "../types/quality";
|
|
17
18
|
import type { ArmSamples, KeepOutputsMode } from "./samples";
|
|
18
19
|
import type { BakeoffArtifact, BakeoffObjective, VariantMetrics } from "./types";
|
|
@@ -52,6 +53,10 @@ export interface BakeoffRequest {
|
|
|
52
53
|
readonly expected?: ReadonlyMap<string, {
|
|
53
54
|
readonly value: unknown;
|
|
54
55
|
}>;
|
|
56
|
+
/** LRE-1b: the golden set's grader for `expected` scoring (`exact` binary /
|
|
57
|
+
* `field-level` per-field / `llm-judge` deferred). Set by the from-eval-cases
|
|
58
|
+
* runner from the eval set's grader; absent ⇒ field-level (pre-LRE-1b). */
|
|
59
|
+
readonly graderType?: GraderType;
|
|
55
60
|
/** Q1 quality gate (spec §4.2): scored on every replayed sample to populate
|
|
56
61
|
* valueAccuracy + the quality pass rate, unlocking computeProposal's cost-first
|
|
57
62
|
* third clause. A function, so it rides `rig.bakeoff` (programmatic) only — the
|
|
@@ -84,11 +89,35 @@ export interface BakeoffMirrorConfig {
|
|
|
84
89
|
* Same PostgREST transport pattern as the telemetry exporter; captures have
|
|
85
90
|
* no cloud surface — ONLY aggregate metrics travel. */
|
|
86
91
|
export declare function mirrorBakeoff(artifact: BakeoffArtifact, config: BakeoffMirrorConfig): Promise<void>;
|
|
92
|
+
/** N4 swap direction (near-optimal spec §4.2): the winner's effective $/1k vs the
|
|
93
|
+
* incumbent's. `up` = better-and-dearer (raises cost to cut regret); `down` = the
|
|
94
|
+
* shipped saving; `lateral` = within EPS (RB-1 never proposes a true lateral, but
|
|
95
|
+
* the label is honest at the boundary). Zero new measurement — both arms are
|
|
96
|
+
* already in the matrix. */
|
|
97
|
+
export interface SwapDirection {
|
|
98
|
+
readonly direction: "up" | "down" | "lateral";
|
|
99
|
+
/** winnerEff − incumbentEff, signed (USD per 1k conformant); null if either ∞. */
|
|
100
|
+
readonly costDeltaUsdPer1k: number | null;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Derive a bake-off's proposed-swap direction from the winner's vs the
|
|
104
|
+
* incumbent's `effectiveUsdPer1kConformant` (spec §4.2). The incumbent is the
|
|
105
|
+
* `default` arm when present, else the first non-reference arm — matching
|
|
106
|
+
* `computeProposal`'s incumbent selection (requested variants keep their order in
|
|
107
|
+
* the matrix, with the reference pushed last). Null when there is no proposal.
|
|
108
|
+
* Pure, additive: `computeProposal` is untouched (the winner is only read back).
|
|
109
|
+
*/
|
|
110
|
+
export declare function deriveSwapDirection(artifact: BakeoffArtifact): SwapDirection | null;
|
|
87
111
|
/**
|
|
88
112
|
* The proposal-evidence jsonb for a bake-off artifact (near-optimal spec §4.6) —
|
|
89
113
|
* the winning variant, the RB-1 objective/reference/regret/quality_metric, and a
|
|
90
114
|
* per-arm matrix (with per-arm regret). Built here so the CLI stays thin; the PR
|
|
91
115
|
* body reads these fields back off `proposal.evidence`. ZERO DDL — freeform jsonb.
|
|
116
|
+
*
|
|
117
|
+
* N4 (spec §4.2, ADDITIVE): when a proposal exists, stamp `swap_direction` +
|
|
118
|
+
* `cost_delta_usd_per_1k` so the PR body, the approval prompt, and the odometer
|
|
119
|
+
* treat a cost-raising promotion honestly. Absent on a no-proposal artifact (the
|
|
120
|
+
* existing evidence shape is byte-identical).
|
|
92
121
|
*/
|
|
93
122
|
export declare function bakeoffEvidence(artifact: BakeoffArtifact, spentUsd: number): Record<string, unknown>;
|
|
94
123
|
//# sourceMappingURL=engine.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/bakeoff/engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAG1C,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,WAAW,EAAgB,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/bakeoff/engine.ts"],"names":[],"mappings":"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"}
|
package/dist/bakeoff/engine.js
CHANGED
|
@@ -16,12 +16,14 @@ exports.REFERENCE_ARM = void 0;
|
|
|
16
16
|
exports.runBakeoff = runBakeoff;
|
|
17
17
|
exports.computeProposal = computeProposal;
|
|
18
18
|
exports.mirrorBakeoff = mirrorBakeoff;
|
|
19
|
+
exports.deriveSwapDirection = deriveSwapDirection;
|
|
19
20
|
exports.bakeoffEvidence = bakeoffEvidence;
|
|
20
21
|
const node_crypto_1 = require("node:crypto");
|
|
21
22
|
const loader_1 = require("../routes/loader");
|
|
22
23
|
const replay_1 = require("./replay");
|
|
23
24
|
const stats_1 = require("./stats");
|
|
24
25
|
const judge_1 = require("./judge");
|
|
26
|
+
const golden_judge_1 = require("./golden-judge");
|
|
25
27
|
const pairwise_1 = require("./pairwise");
|
|
26
28
|
const disagreement_1 = require("./disagreement");
|
|
27
29
|
const reference_1 = require("./reference");
|
|
@@ -81,6 +83,11 @@ async function runBakeoff(deps, captures, req, samplesSink) {
|
|
|
81
83
|
// reference comparison in the engine) — WITHOUT the keepOutputs sink persist.
|
|
82
84
|
const pairwiseJudgeCfg = route.bakeoff?.pairwise?.judge;
|
|
83
85
|
const retainForPairwise = pairwiseJudgeCfg !== undefined;
|
|
86
|
+
// LRE-2 llm-judge grader: when the eval set grades by `llm-judge`, each arm's
|
|
87
|
+
// output is scored against its GOLDEN via the pairwise judge. Reuse the route's
|
|
88
|
+
// declared (load-validated, #223 F3) pairwise/bakeoff judge model — a golden
|
|
89
|
+
// judge is built FRESH per arm (its cap is per arm) inside the replay calls.
|
|
90
|
+
const goldenJudgeCfg = req.graderType === "llm-judge" ? (route.bakeoff?.pairwise?.judge ?? route.bakeoff?.judge) : undefined;
|
|
84
91
|
// Replay every requested arm. Raw samples are kept ALWAYS (paired regret is
|
|
85
92
|
// computed from per-sample quality); the keepOutputs sink is separate. A fresh
|
|
86
93
|
// judge scorer per arm keeps `max_samples` per-arm (spec §4.3).
|
|
@@ -96,7 +103,9 @@ async function runBakeoff(deps, captures, req, samplesSink) {
|
|
|
96
103
|
...(keepOutputs ? { keepOutputs: true } : {}),
|
|
97
104
|
...(retainForPairwise ? { retainOutputForPairwise: true } : {}),
|
|
98
105
|
...(req.expected !== undefined ? { expected: req.expected } : {}),
|
|
106
|
+
...(req.graderType !== undefined ? { graderType: req.graderType } : {}),
|
|
99
107
|
...(judgeCfg !== undefined ? { judge: (0, judge_1.makeJudgeScorer)(deps, route, judgeCfg) } : {}),
|
|
108
|
+
...(goldenJudgeCfg !== undefined ? { goldenJudge: (0, golden_judge_1.makeGoldenJudge)(deps, route, goldenJudgeCfg) } : {}),
|
|
100
109
|
...(req.qualityGate !== undefined ? { qualityGate: req.qualityGate } : {}),
|
|
101
110
|
});
|
|
102
111
|
replayN = Math.max(replayN, samples.length);
|
|
@@ -122,7 +131,9 @@ async function runBakeoff(deps, captures, req, samplesSink) {
|
|
|
122
131
|
envelopeUsd: refEnvelope,
|
|
123
132
|
...(retainForPairwise ? { retainOutputForPairwise: true } : {}),
|
|
124
133
|
...(req.expected !== undefined ? { expected: req.expected } : {}),
|
|
134
|
+
...(req.graderType !== undefined ? { graderType: req.graderType } : {}),
|
|
125
135
|
...(judgeCfg !== undefined ? { judge: (0, judge_1.makeJudgeScorer)(deps, route, judgeCfg) } : {}),
|
|
136
|
+
...(goldenJudgeCfg !== undefined ? { goldenJudge: (0, golden_judge_1.makeGoldenJudge)(deps, route, goldenJudgeCfg) } : {}),
|
|
126
137
|
...(req.qualityGate !== undefined ? { qualityGate: req.qualityGate } : {}),
|
|
127
138
|
});
|
|
128
139
|
const partial = refSamples.length < replayN || refSamples.some((s) => s.failureClass === "budget_exhausted");
|
|
@@ -421,14 +432,50 @@ async function mirrorBakeoff(artifact, config) {
|
|
|
421
432
|
throw new Error(`bakeoff mirror upsert → ${response.status} ${await response.text().catch(() => "")}`);
|
|
422
433
|
}
|
|
423
434
|
}
|
|
435
|
+
/**
|
|
436
|
+
* Derive a bake-off's proposed-swap direction from the winner's vs the
|
|
437
|
+
* incumbent's `effectiveUsdPer1kConformant` (spec §4.2). The incumbent is the
|
|
438
|
+
* `default` arm when present, else the first non-reference arm — matching
|
|
439
|
+
* `computeProposal`'s incumbent selection (requested variants keep their order in
|
|
440
|
+
* the matrix, with the reference pushed last). Null when there is no proposal.
|
|
441
|
+
* Pure, additive: `computeProposal` is untouched (the winner is only read back).
|
|
442
|
+
*/
|
|
443
|
+
function deriveSwapDirection(artifact) {
|
|
444
|
+
const p = artifact.proposal;
|
|
445
|
+
if (p === null || p === undefined)
|
|
446
|
+
return null;
|
|
447
|
+
const winner = artifact.variants.find((m) => m.variant === p.variant);
|
|
448
|
+
const incumbent = artifact.variants.find((m) => m.variant === "default" && m.isReference !== true) ??
|
|
449
|
+
artifact.variants.find((m) => m.isReference !== true);
|
|
450
|
+
if (winner === undefined || incumbent === undefined)
|
|
451
|
+
return null;
|
|
452
|
+
const w = winner.effectiveUsdPer1kConformant;
|
|
453
|
+
const i = incumbent.effectiveUsdPer1kConformant;
|
|
454
|
+
const costDeltaUsdPer1k = Number.isFinite(w) && Number.isFinite(i) ? w - i : null;
|
|
455
|
+
const direction = costDeltaUsdPer1k === null || Math.abs(costDeltaUsdPer1k) <= EPS
|
|
456
|
+
? "lateral"
|
|
457
|
+
: costDeltaUsdPer1k > 0
|
|
458
|
+
? "up"
|
|
459
|
+
: "down";
|
|
460
|
+
return { direction, costDeltaUsdPer1k };
|
|
461
|
+
}
|
|
424
462
|
/**
|
|
425
463
|
* The proposal-evidence jsonb for a bake-off artifact (near-optimal spec §4.6) —
|
|
426
464
|
* the winning variant, the RB-1 objective/reference/regret/quality_metric, and a
|
|
427
465
|
* per-arm matrix (with per-arm regret). Built here so the CLI stays thin; the PR
|
|
428
466
|
* body reads these fields back off `proposal.evidence`. ZERO DDL — freeform jsonb.
|
|
467
|
+
*
|
|
468
|
+
* N4 (spec §4.2, ADDITIVE): when a proposal exists, stamp `swap_direction` +
|
|
469
|
+
* `cost_delta_usd_per_1k` so the PR body, the approval prompt, and the odometer
|
|
470
|
+
* treat a cost-raising promotion honestly. Absent on a no-proposal artifact (the
|
|
471
|
+
* existing evidence shape is byte-identical).
|
|
429
472
|
*/
|
|
430
473
|
function bakeoffEvidence(artifact, spentUsd) {
|
|
474
|
+
const dir = deriveSwapDirection(artifact);
|
|
431
475
|
return {
|
|
476
|
+
...(dir !== null
|
|
477
|
+
? { swap_direction: dir.direction, cost_delta_usd_per_1k: dir.costDeltaUsdPer1k }
|
|
478
|
+
: {}),
|
|
432
479
|
bakeoff_id: artifact.id,
|
|
433
480
|
replay_n: artifact.replayN,
|
|
434
481
|
ran_at: artifact.ranAt,
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The rig-facing from-eval-cases bake-off delegates — extracted from index.ts to
|
|
3
|
+
* keep it under the 700-LOC cap (P1). Both `rig.bakeoffFromEvalCases` (LOCAL
|
|
4
|
+
* artifact store + captures) and `rig.bakeoffFromEvalCasesWith` (LRE-1b: stores
|
|
5
|
+
* the CALLER injects — the server's cross-plane rehydration resolver) funnel
|
|
6
|
+
* through `runRigEvalCasesBakeoff`, so option defaulting lives in one place.
|
|
7
|
+
*/
|
|
8
|
+
import { type EvalCaseBakeoffResult, type EvalCaseStores } from "./eval-cases";
|
|
9
|
+
import type { BakeoffSamplesSink } from "./engine";
|
|
10
|
+
import type { GraderType } from "./quality";
|
|
11
|
+
import type { KeepOutputsMode } from "./samples";
|
|
12
|
+
import type { RunDeps } from "../run/run";
|
|
13
|
+
import type { CandidateSpec, ObjectiveMode, RouteBundle } from "../types/route";
|
|
14
|
+
import type { QualityGate } from "../types/quality";
|
|
15
|
+
/** The shared option shape for both from-eval-cases rig entry points. */
|
|
16
|
+
export interface EvalCasesBakeoffOpts {
|
|
17
|
+
readonly variants: readonly string[];
|
|
18
|
+
readonly envelopeUsdPerVariant?: number;
|
|
19
|
+
readonly keepOutputs?: KeepOutputsMode;
|
|
20
|
+
readonly objectiveMode?: ObjectiveMode;
|
|
21
|
+
readonly qualityGate?: QualityGate;
|
|
22
|
+
readonly graderType?: GraderType;
|
|
23
|
+
}
|
|
24
|
+
/** Run the from-eval-cases engine over the given deps + stores, defaulting the
|
|
25
|
+
* envelope and threading the reference-auto resolver + samples sink. Pure over
|
|
26
|
+
* its inputs — no local-store assumptions (the caller picks the stores). */
|
|
27
|
+
export declare function runRigEvalCasesBakeoff(input: {
|
|
28
|
+
readonly deps: RunDeps;
|
|
29
|
+
readonly stores: EvalCaseStores;
|
|
30
|
+
readonly task: string;
|
|
31
|
+
readonly samplesSink?: BakeoffSamplesSink;
|
|
32
|
+
readonly resolveReferenceAuto: (route: RouteBundle) => CandidateSpec | null;
|
|
33
|
+
readonly defaultEnvelopeUsd: number;
|
|
34
|
+
readonly opts: EvalCasesBakeoffOpts;
|
|
35
|
+
}): Promise<EvalCaseBakeoffResult>;
|
|
36
|
+
//# sourceMappingURL=eval-cases-rig.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eval-cases-rig.d.ts","sourceRoot":"","sources":["../../src/bakeoff/eval-cases-rig.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAA2B,KAAK,qBAAqB,EAAE,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AACxG,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AACnD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAChF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD,yEAAyE;AACzE,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,QAAQ,CAAC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IACxC,QAAQ,CAAC,WAAW,CAAC,EAAE,eAAe,CAAC;IACvC,QAAQ,CAAC,aAAa,CAAC,EAAE,aAAa,CAAC;IACvC,QAAQ,CAAC,WAAW,CAAC,EAAE,WAAW,CAAC;IACnC,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC;CAClC;AAED;;4EAE4E;AAC5E,wBAAgB,sBAAsB,CAAC,KAAK,EAAE;IAC5C,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,CAAC,EAAE,kBAAkB,CAAC;IAC1C,QAAQ,CAAC,oBAAoB,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,aAAa,GAAG,IAAI,CAAC;IAC5E,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CAAC;CACrC,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAiBjC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* The rig-facing from-eval-cases bake-off delegates — extracted from index.ts to
|
|
4
|
+
* keep it under the 700-LOC cap (P1). Both `rig.bakeoffFromEvalCases` (LOCAL
|
|
5
|
+
* artifact store + captures) and `rig.bakeoffFromEvalCasesWith` (LRE-1b: stores
|
|
6
|
+
* the CALLER injects — the server's cross-plane rehydration resolver) funnel
|
|
7
|
+
* through `runRigEvalCasesBakeoff`, so option defaulting lives in one place.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.runRigEvalCasesBakeoff = runRigEvalCasesBakeoff;
|
|
11
|
+
const eval_cases_1 = require("./eval-cases");
|
|
12
|
+
/** Run the from-eval-cases engine over the given deps + stores, defaulting the
|
|
13
|
+
* envelope and threading the reference-auto resolver + samples sink. Pure over
|
|
14
|
+
* its inputs — no local-store assumptions (the caller picks the stores). */
|
|
15
|
+
function runRigEvalCasesBakeoff(input) {
|
|
16
|
+
const { deps, stores, task, samplesSink, resolveReferenceAuto, defaultEnvelopeUsd, opts } = input;
|
|
17
|
+
return (0, eval_cases_1.runBakeoffFromEvalCases)(deps, stores, {
|
|
18
|
+
task,
|
|
19
|
+
variants: opts.variants,
|
|
20
|
+
envelopeUsdPerVariant: opts.envelopeUsdPerVariant ?? defaultEnvelopeUsd,
|
|
21
|
+
qualityGate: opts.qualityGate,
|
|
22
|
+
...(opts.keepOutputs !== undefined ? { keepOutputs: opts.keepOutputs } : {}),
|
|
23
|
+
...(opts.objectiveMode !== undefined ? { objectiveMode: opts.objectiveMode } : {}),
|
|
24
|
+
...(opts.graderType !== undefined ? { graderType: opts.graderType } : {}),
|
|
25
|
+
resolveReferenceAuto,
|
|
26
|
+
}, samplesSink);
|
|
27
|
+
}
|
|
@@ -21,6 +21,7 @@ import type { ExportableTelemetryStore } from "../telemetry/store";
|
|
|
21
21
|
import type { EvalCaseRow } from "../types/telemetry";
|
|
22
22
|
import type { RunDeps } from "../run/run";
|
|
23
23
|
import { type BakeoffSamplesSink } from "./engine";
|
|
24
|
+
import type { GraderType } from "./quality";
|
|
24
25
|
import type { KeepOutputsMode } from "./samples";
|
|
25
26
|
import type { BakeoffArtifact } from "./types";
|
|
26
27
|
import type { CandidateSpec, ObjectiveMode, RouteBundle } from "../types/route";
|
|
@@ -39,6 +40,10 @@ export interface EvalCaseSelectionDeps {
|
|
|
39
40
|
export interface RehydratedCase {
|
|
40
41
|
readonly caseId: string;
|
|
41
42
|
readonly capture: CaptureRow;
|
|
43
|
+
/** LRE-1b: the golden (corrected) artifact id, or null for a failure case (no
|
|
44
|
+
* golden to grade against — it scores by conformance only). Carried so the
|
|
45
|
+
* runner can build the `expected` map from the golden's content. */
|
|
46
|
+
readonly correctedArtifactId: string | null;
|
|
42
47
|
}
|
|
43
48
|
export interface EvalCaseRefusal {
|
|
44
49
|
readonly caseId: string;
|
|
@@ -88,6 +93,15 @@ export interface EvalCaseStores {
|
|
|
88
93
|
readonly artifacts: Pick<ArtifactStore, "readEvalCasesByTask" | "getArtifactById"> | null;
|
|
89
94
|
readonly telemetry: Pick<ExportableTelemetryStore, "getStepInferenceId">;
|
|
90
95
|
readonly captures: () => Pick<CaptureStore, "getByInferenceId">;
|
|
96
|
+
/** LRE-1b: resolve a golden (corrected) artifact's PARSED content value, or
|
|
97
|
+
* null when it is not readable (predates retention, evicted, or content custody
|
|
98
|
+
* is off). Injected so the runner can score a challenger's output against the
|
|
99
|
+
* golden (the `exact` grader). Absent ⇒ from-eval-cases scores by conformance
|
|
100
|
+
* only (pre-LRE-1b behavior) — a golden with no readable content is honest
|
|
101
|
+
* about it rather than pretending the case is graded. */
|
|
102
|
+
readonly golden?: (correctedArtifactId: string) => {
|
|
103
|
+
readonly value: unknown;
|
|
104
|
+
} | null;
|
|
91
105
|
}
|
|
92
106
|
export declare function runBakeoffFromEvalCases(deps: RunDeps, stores: EvalCaseStores, req: {
|
|
93
107
|
readonly task: string;
|
|
@@ -97,5 +111,10 @@ export declare function runBakeoffFromEvalCases(deps: RunDeps, stores: EvalCaseS
|
|
|
97
111
|
readonly objectiveMode?: ObjectiveMode;
|
|
98
112
|
readonly resolveReferenceAuto?: (route: RouteBundle) => CandidateSpec | null;
|
|
99
113
|
readonly qualityGate?: QualityGate;
|
|
114
|
+
/** The golden set's grader — all three wired: `exact` (binary), `field-level`
|
|
115
|
+
* (per-field partial credit), `llm-judge` (pairwise vs the golden, LRE-2).
|
|
116
|
+
* Applied to every case that HAS a readable golden; a failure case (no golden)
|
|
117
|
+
* still scores by conformance. */
|
|
118
|
+
readonly graderType?: GraderType;
|
|
100
119
|
}, samplesSink?: BakeoffSamplesSink): Promise<EvalCaseBakeoffResult>;
|
|
101
120
|
//# sourceMappingURL=eval-cases.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eval-cases.d.ts","sourceRoot":"","sources":["../../src/bakeoff/eval-cases.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AACnE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAc,KAAK,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAC/D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAChF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD;oDACoD;AACpD,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,mBAAmB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,WAAW,EAAE,CAAC;IAC9D,QAAQ,CAAC,eAAe,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK;QAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,CAAC;IAClG,QAAQ,CAAC,kBAAkB,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;IAC/E,QAAQ,CAAC,uBAAuB,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,UAAU,GAAG,IAAI,CAAC;CAC9E;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"eval-cases.d.ts","sourceRoot":"","sources":["../../src/bakeoff/eval-cases.ts"],"names":[],"mappings":"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"}
|
|
@@ -53,7 +53,7 @@ function selectEvalCaseCaptures(deps, task) {
|
|
|
53
53
|
refuse("input not captured locally (route `capture` was off, or the capture was evicted)");
|
|
54
54
|
continue;
|
|
55
55
|
}
|
|
56
|
-
rehydratable.push({ caseId: c.id, capture });
|
|
56
|
+
rehydratable.push({ caseId: c.id, capture, correctedArtifactId: c.correctedArtifactId });
|
|
57
57
|
}
|
|
58
58
|
return { task, total: cases.length, rehydratable, refusals };
|
|
59
59
|
}
|
|
@@ -94,11 +94,28 @@ async function runBakeoffFromEvalCases(deps, stores, req, samplesSink) {
|
|
|
94
94
|
}, req.task);
|
|
95
95
|
if (selection.rehydratable.length === 0)
|
|
96
96
|
return { selection, artifact: null };
|
|
97
|
+
// LRE-1b: build the golden `expected` map — for each rehydratable case that has
|
|
98
|
+
// a corrected artifact whose content the injected `golden` resolver can read,
|
|
99
|
+
// key the golden value by the capture's inferenceId (the engine's `expected`
|
|
100
|
+
// key). A failure case (no golden) or an unreadable golden simply omits its
|
|
101
|
+
// key → that sample scores by conformance, never a silent zero.
|
|
102
|
+
const expected = new Map();
|
|
103
|
+
if (stores.golden !== undefined) {
|
|
104
|
+
for (const r of selection.rehydratable) {
|
|
105
|
+
if (r.correctedArtifactId === null)
|
|
106
|
+
continue;
|
|
107
|
+
const g = stores.golden(r.correctedArtifactId);
|
|
108
|
+
if (g !== null)
|
|
109
|
+
expected.set(r.capture.inferenceId, { value: g.value });
|
|
110
|
+
}
|
|
111
|
+
}
|
|
97
112
|
const artifact = await (0, engine_1.runBakeoff)(deps, evalCaseCaptureStore(selection.rehydratable), {
|
|
98
113
|
route: req.task,
|
|
99
114
|
variants: req.variants,
|
|
100
115
|
replayLastN: selection.rehydratable.length, // replay every rehydratable case
|
|
101
116
|
envelopeUsdPerVariant: req.envelopeUsdPerVariant,
|
|
117
|
+
...(expected.size > 0 ? { expected } : {}),
|
|
118
|
+
...(req.graderType !== undefined ? { graderType: req.graderType } : {}),
|
|
102
119
|
...(req.keepOutputs !== undefined ? { keepOutputs: req.keepOutputs } : {}),
|
|
103
120
|
...(req.objectiveMode !== undefined ? { objectiveMode: req.objectiveMode } : {}),
|
|
104
121
|
...(req.resolveReferenceAuto !== undefined ? { resolveReferenceAuto: req.resolveReferenceAuto } : {}),
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `llm-judge` grader (LRE-2, live-routing-evals §R-3/§4). When a golden eval
|
|
3
|
+
* set's `grader.type` is `llm-judge`, each rehydratable case is scored by an LLM
|
|
4
|
+
* COMPARISON of the challenger's output against the case's GOLDEN (`expected`)
|
|
5
|
+
* value — reusing the N5/N6 PAIRWISE judge machinery (pairwise.ts), not a new
|
|
6
|
+
* dispatch path.
|
|
7
|
+
*
|
|
8
|
+
* Why pairwise-vs-golden (R-3, "LLM-judge reuses the N5/N6 pairwise judge"):
|
|
9
|
+
* - The pairwise judge already asks "which of A / B is the better answer for
|
|
10
|
+
* VALUE (correctness + completeness)". Presenting A = the challenger output
|
|
11
|
+
* and B = the golden turns that into "is the challenger at least as good as
|
|
12
|
+
* the known-correct golden?" — exactly a grade against a reference.
|
|
13
|
+
* - The verdict maps to a per-sample value accuracy via the SAME `winValue`
|
|
14
|
+
* the pairwise aggregation uses (win=1, tie=0.5, loss=0). This is the
|
|
15
|
+
* CONSERVATIVE mapping (L5, never round in our favor): a tie against the
|
|
16
|
+
* golden is 0.5, never rounded up to full credit; a loss is 0. Builder
|
|
17
|
+
* decision — flagged in the PR body for QA.
|
|
18
|
+
* - The judge model MUST be a declared candidate (#223 F3) — enforced at load
|
|
19
|
+
* for `bakeoff.pairwise.judge` / `bakeoff.judge`, whose model this reuses, so
|
|
20
|
+
* it is a real, reachable model here.
|
|
21
|
+
*
|
|
22
|
+
* CAPPED + METERED + fail-closed exactly like the pairwise judge (it IS the
|
|
23
|
+
* pairwise judge): past `maxSamples` per arm `score()` returns null and the
|
|
24
|
+
* sample falls back to conformance (counted by omission), an unparseable verdict
|
|
25
|
+
* returns null, and the metered attempt row still stands.
|
|
26
|
+
*/
|
|
27
|
+
import type { RunDeps } from "../run/run";
|
|
28
|
+
import type { CandidateSpec, RouteBundle } from "../types/route";
|
|
29
|
+
/** A per-arm golden grader: `score(output, golden, taskInput)` returns the
|
|
30
|
+
* challenger output's value accuracy in [0,1] judged against the golden, or null
|
|
31
|
+
* when the cap is hit or the judge could not produce a valid verdict. */
|
|
32
|
+
export interface GoldenJudgeScorer {
|
|
33
|
+
score(output: unknown, golden: unknown, taskInput: unknown): Promise<number | null>;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Build a golden judge over the pairwise-judge loop. Each arm gets a FRESH judge
|
|
37
|
+
* (the underlying pairwise judge caps `maxSamples` per arm). A = the challenger
|
|
38
|
+
* output, B = the golden `expected` value; the pairwise verdict (win/tie/loss)
|
|
39
|
+
* maps to [0,1] via `winValue` — an output judged at least as good as the golden
|
|
40
|
+
* scores high, a worse output scores 0. Position bias is the pairwise judge's
|
|
41
|
+
* known limit (fixed A/B order); noted in verification.
|
|
42
|
+
*/
|
|
43
|
+
export declare function makeGoldenJudge(deps: RunDeps, baseRoute: RouteBundle, judge: {
|
|
44
|
+
readonly model: CandidateSpec;
|
|
45
|
+
readonly maxSamples: number;
|
|
46
|
+
}): GoldenJudgeScorer;
|
|
47
|
+
//# sourceMappingURL=golden-judge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"golden-judge.d.ts","sourceRoot":"","sources":["../../src/bakeoff/golden-judge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAGjE;;yEAEyE;AACzE,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CACrF;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,OAAO,EACb,SAAS,EAAE,WAAW,EACtB,KAAK,EAAE;IAAE,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GACpE,iBAAiB,CAUnB"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* The `llm-judge` grader (LRE-2, live-routing-evals §R-3/§4). When a golden eval
|
|
4
|
+
* set's `grader.type` is `llm-judge`, each rehydratable case is scored by an LLM
|
|
5
|
+
* COMPARISON of the challenger's output against the case's GOLDEN (`expected`)
|
|
6
|
+
* value — reusing the N5/N6 PAIRWISE judge machinery (pairwise.ts), not a new
|
|
7
|
+
* dispatch path.
|
|
8
|
+
*
|
|
9
|
+
* Why pairwise-vs-golden (R-3, "LLM-judge reuses the N5/N6 pairwise judge"):
|
|
10
|
+
* - The pairwise judge already asks "which of A / B is the better answer for
|
|
11
|
+
* VALUE (correctness + completeness)". Presenting A = the challenger output
|
|
12
|
+
* and B = the golden turns that into "is the challenger at least as good as
|
|
13
|
+
* the known-correct golden?" — exactly a grade against a reference.
|
|
14
|
+
* - The verdict maps to a per-sample value accuracy via the SAME `winValue`
|
|
15
|
+
* the pairwise aggregation uses (win=1, tie=0.5, loss=0). This is the
|
|
16
|
+
* CONSERVATIVE mapping (L5, never round in our favor): a tie against the
|
|
17
|
+
* golden is 0.5, never rounded up to full credit; a loss is 0. Builder
|
|
18
|
+
* decision — flagged in the PR body for QA.
|
|
19
|
+
* - The judge model MUST be a declared candidate (#223 F3) — enforced at load
|
|
20
|
+
* for `bakeoff.pairwise.judge` / `bakeoff.judge`, whose model this reuses, so
|
|
21
|
+
* it is a real, reachable model here.
|
|
22
|
+
*
|
|
23
|
+
* CAPPED + METERED + fail-closed exactly like the pairwise judge (it IS the
|
|
24
|
+
* pairwise judge): past `maxSamples` per arm `score()` returns null and the
|
|
25
|
+
* sample falls back to conformance (counted by omission), an unparseable verdict
|
|
26
|
+
* returns null, and the metered attempt row still stands.
|
|
27
|
+
*/
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.makeGoldenJudge = makeGoldenJudge;
|
|
30
|
+
const pairwise_1 = require("./pairwise");
|
|
31
|
+
/**
|
|
32
|
+
* Build a golden judge over the pairwise-judge loop. Each arm gets a FRESH judge
|
|
33
|
+
* (the underlying pairwise judge caps `maxSamples` per arm). A = the challenger
|
|
34
|
+
* output, B = the golden `expected` value; the pairwise verdict (win/tie/loss)
|
|
35
|
+
* maps to [0,1] via `winValue` — an output judged at least as good as the golden
|
|
36
|
+
* scores high, a worse output scores 0. Position bias is the pairwise judge's
|
|
37
|
+
* known limit (fixed A/B order); noted in verification.
|
|
38
|
+
*/
|
|
39
|
+
function makeGoldenJudge(deps, baseRoute, judge) {
|
|
40
|
+
const pairwise = (0, pairwise_1.makePairwiseJudge)(deps, baseRoute, judge);
|
|
41
|
+
return {
|
|
42
|
+
async score(output, golden, taskInput) {
|
|
43
|
+
// compare(A=output, B=golden): "win" ⇒ output beats the golden, "tie" ⇒ as
|
|
44
|
+
// good as, "loss" ⇒ worse. winValue gives 1 / 0.5 / 0.
|
|
45
|
+
const outcome = await pairwise.compare(output, golden, taskInput);
|
|
46
|
+
return outcome === null ? null : (0, pairwise_1.winValue)(outcome);
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
}
|
|
@@ -13,6 +13,15 @@
|
|
|
13
13
|
* ordering.
|
|
14
14
|
*/
|
|
15
15
|
import type { ValueCheck } from "../types/route";
|
|
16
|
+
/**
|
|
17
|
+
* The grader a golden eval set scores with (live-routing-evals §2.2/§4). All
|
|
18
|
+
* three are wired: `exact` (binary normalized equality, LRE-1b), `field-level`
|
|
19
|
+
* (schema-aware per-field partial credit via {@link fieldAccuracy}, first-class
|
|
20
|
+
* as of LRE-2), and `llm-judge` (a PAIRWISE comparison of the output against the
|
|
21
|
+
* golden — NOT a deterministic tier, so this resolver returns null for it and the
|
|
22
|
+
* caller's golden judge (golden-judge.ts, LRE-2) scores it against `expected`).
|
|
23
|
+
*/
|
|
24
|
+
export type GraderType = "exact" | "field-level" | "llm-judge";
|
|
16
25
|
/**
|
|
17
26
|
* Schema-aware field accuracy in [0,1]: the fraction of the EXPECTED value's leaf
|
|
18
27
|
* fields that the actual output matches. Recurses into objects/arrays keyed by
|
|
@@ -21,6 +30,18 @@ import type { ValueCheck } from "../types/route";
|
|
|
21
30
|
* expected ⇒ 1 (nothing to be wrong about).
|
|
22
31
|
*/
|
|
23
32
|
export declare function fieldAccuracy(expected: unknown, actual: unknown): number;
|
|
33
|
+
/**
|
|
34
|
+
* The `exact` grader (LRE-1b, spec §4): normalized EQUALITY of the parsed output
|
|
35
|
+
* against the golden → 1 (match) or 0 (mismatch). Binary, never partial credit —
|
|
36
|
+
* that is the whole point of `exact` vs `field-level` (`fieldAccuracy`).
|
|
37
|
+
*
|
|
38
|
+
* Normalization is `normalizeDeep`: object keys are order-insensitive (sorted),
|
|
39
|
+
* string leaves are whitespace-trimmed, arrays stay ORDER-sensitive (a reordered
|
|
40
|
+
* list is a different value), and types are strict (`1` ≠ `"1"`, `null` ≠
|
|
41
|
+
* `undefined`). So `{a:1, b:" x "}` matches `{b:"x", a:1}` but `[1,2]` does not
|
|
42
|
+
* match `[2,1]`. Pure + unit-tested (exact-grader.test.ts).
|
|
43
|
+
*/
|
|
44
|
+
export declare function exactMatch(expected: unknown, actual: unknown): number;
|
|
24
45
|
/** Resolve an RFC 6901 JSON pointer against a value. Returns `undefined` when any
|
|
25
46
|
* segment is missing (a missing field fails its value check). */
|
|
26
47
|
export declare function resolveJsonPointer(value: unknown, pointer: string): unknown;
|
|
@@ -35,6 +56,15 @@ export interface DeterministicQualityInput {
|
|
|
35
56
|
/** Set when `expected` is meaningfully present (distinguishes a golden `null`
|
|
36
57
|
* expected value from "no eval case"). */
|
|
37
58
|
readonly hasExpected?: boolean;
|
|
59
|
+
/** The golden set's grader. Only consulted alongside `hasExpected`:
|
|
60
|
+
* • `exact` → binary normalized equality (exactMatch).
|
|
61
|
+
* • `field-level`→ schema-aware per-field partial credit (fieldAccuracy) —
|
|
62
|
+
* the fraction of the golden's leaf fields the output matches, in [0,1].
|
|
63
|
+
* • `llm-judge` → NOT a deterministic tier; returns null so the caller's
|
|
64
|
+
* golden judge (golden-judge.ts) scores the output against the golden via
|
|
65
|
+
* the N5/N6 pairwise judge (LRE-2).
|
|
66
|
+
* Absent ⇒ `field-level` behavior (byte-identical to pre-LRE-1b default). */
|
|
67
|
+
readonly graderType?: GraderType;
|
|
38
68
|
}
|
|
39
69
|
/**
|
|
40
70
|
* Deterministic value accuracy for one sample, or null when neither an eval-case
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"quality.d.ts","sourceRoot":"","sources":["../../src/bakeoff/quality.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"quality.d.ts","sourceRoot":"","sources":["../../src/bakeoff/quality.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEjD;;;;;;;GAOG;AACH,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,aAAa,GAAG,WAAW,CAAC;AAiB/D;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,GAAG,MAAM,CAgBxE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,GAAG,MAAM,CAErE;AAED;iEACiE;AACjE,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAmB3E;AAED,uFAAuF;AACvF,wBAAgB,WAAW,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAWvE;AAYD,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IAC7C;oDACgD;IAChD,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B;8CAC0C;IAC1C,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAC/B;;;;;;;iFAO6E;IAC7E,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC;CAClC;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,yBAAyB,GAAG,MAAM,GAAG,IAAI,CAc3F"}
|
package/dist/bakeoff/quality.js
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
*/
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
exports.fieldAccuracy = fieldAccuracy;
|
|
18
|
+
exports.exactMatch = exactMatch;
|
|
18
19
|
exports.resolveJsonPointer = resolveJsonPointer;
|
|
19
20
|
exports.checkPasses = checkPasses;
|
|
20
21
|
exports.resolveDeterministicQuality = resolveDeterministicQuality;
|
|
@@ -58,6 +59,20 @@ function fieldAccuracy(expected, actual) {
|
|
|
58
59
|
}
|
|
59
60
|
return scalarEqual(expected, actual) ? 1 : 0;
|
|
60
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* The `exact` grader (LRE-1b, spec §4): normalized EQUALITY of the parsed output
|
|
64
|
+
* against the golden → 1 (match) or 0 (mismatch). Binary, never partial credit —
|
|
65
|
+
* that is the whole point of `exact` vs `field-level` (`fieldAccuracy`).
|
|
66
|
+
*
|
|
67
|
+
* Normalization is `normalizeDeep`: object keys are order-insensitive (sorted),
|
|
68
|
+
* string leaves are whitespace-trimmed, arrays stay ORDER-sensitive (a reordered
|
|
69
|
+
* list is a different value), and types are strict (`1` ≠ `"1"`, `null` ≠
|
|
70
|
+
* `undefined`). So `{a:1, b:" x "}` matches `{b:"x", a:1}` but `[1,2]` does not
|
|
71
|
+
* match `[2,1]`. Pure + unit-tested (exact-grader.test.ts).
|
|
72
|
+
*/
|
|
73
|
+
function exactMatch(expected, actual) {
|
|
74
|
+
return JSON.stringify(normalizeDeep(expected)) === JSON.stringify(normalizeDeep(actual)) ? 1 : 0;
|
|
75
|
+
}
|
|
61
76
|
/** Resolve an RFC 6901 JSON pointer against a value. Returns `undefined` when any
|
|
62
77
|
* segment is missing (a missing field fails its value check). */
|
|
63
78
|
function resolveJsonPointer(value, pointer) {
|
|
@@ -115,6 +130,12 @@ function normalizeDeep(v) {
|
|
|
115
130
|
*/
|
|
116
131
|
function resolveDeterministicQuality(input) {
|
|
117
132
|
if (input.hasExpected === true) {
|
|
133
|
+
// llm-judge is not deterministic — defer to the judge tier (LRE-2 seam).
|
|
134
|
+
if (input.graderType === "llm-judge")
|
|
135
|
+
return null;
|
|
136
|
+
if (input.graderType === "exact")
|
|
137
|
+
return exactMatch(input.expected, input.output);
|
|
138
|
+
// field-level (explicit) or unspecified default → schema-aware field accuracy.
|
|
118
139
|
return fieldAccuracy(input.expected, input.output);
|
|
119
140
|
}
|
|
120
141
|
const checks = input.valueChecks;
|
package/dist/bakeoff/replay.d.ts
CHANGED
|
@@ -19,7 +19,9 @@
|
|
|
19
19
|
*/
|
|
20
20
|
import type { CaptureStore } from "../telemetry/capture";
|
|
21
21
|
import type { RunDeps } from "../run/run";
|
|
22
|
+
import type { GraderType } from "./quality";
|
|
22
23
|
import type { JudgeScorer } from "./judge";
|
|
24
|
+
import type { GoldenJudgeScorer } from "./golden-judge";
|
|
23
25
|
import type { QualityGate } from "../types/quality";
|
|
24
26
|
export interface ReplayRequest {
|
|
25
27
|
readonly route: string;
|
|
@@ -42,9 +44,18 @@ export interface ReplayRequest {
|
|
|
42
44
|
readonly expected?: ReadonlyMap<string, {
|
|
43
45
|
readonly value: unknown;
|
|
44
46
|
}>;
|
|
47
|
+
/** LRE-1b: the golden set's grader — how an `expected` value is scored against
|
|
48
|
+
* the output (`exact` binary, `field-level` per-field, `llm-judge` deferred to
|
|
49
|
+
* the judge tier). Absent ⇒ field-level (pre-LRE-1b behavior). */
|
|
50
|
+
readonly graderType?: GraderType;
|
|
45
51
|
/** RB-1: an opt-in judge scorer (tier 3), used only when neither an eval-case
|
|
46
52
|
* expected value nor a declared value check yields a score. Capped internally. */
|
|
47
53
|
readonly judge?: JudgeScorer;
|
|
54
|
+
/** LRE-2: the `llm-judge` grader — scores a produced output against its GOLDEN
|
|
55
|
+
* (`expected`) value via the N5/N6 pairwise judge. Used ONLY when
|
|
56
|
+
* `graderType==='llm-judge'` AND this sample has an eval-case expected value (a
|
|
57
|
+
* failure case with no golden still scores by conformance). Capped internally. */
|
|
58
|
+
readonly goldenJudge?: GoldenJudgeScorer;
|
|
48
59
|
/** Q1 quality gate (spec §4.2): scored on each replayed sample's output to
|
|
49
60
|
* populate `valueAccuracy` + `qualityPassed`. NOT passed into the inner
|
|
50
61
|
* `run()` — a bake-off MEASURES quality, it does not gate serving; injecting
|