modelrig 0.4.0 → 0.5.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 +129 -0
- package/README.md +13 -0
- package/dist/adapters/gemini.d.ts +39 -0
- package/dist/adapters/gemini.d.ts.map +1 -1
- package/dist/adapters/gemini.js +53 -2
- package/dist/artifacts/artifact.d.ts +3 -2
- package/dist/artifacts/artifact.d.ts.map +1 -1
- package/dist/artifacts/artifact.js +11 -4
- package/dist/artifacts/run-context.d.ts +21 -2
- package/dist/artifacts/run-context.d.ts.map +1 -1
- package/dist/artifacts/run-context.js +46 -1
- package/dist/bakeoff/replay.d.ts.map +1 -1
- package/dist/bakeoff/replay.js +17 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +21 -1
- package/dist/index.d.ts +15 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -5
- package/dist/registry/select.d.ts +59 -0
- package/dist/registry/select.d.ts.map +1 -1
- package/dist/registry/select.js +66 -0
- package/dist/routes/loader-warnings.d.ts +28 -0
- package/dist/routes/loader-warnings.d.ts.map +1 -0
- package/dist/routes/loader-warnings.js +56 -0
- package/dist/routes/loader.d.ts +1 -11
- package/dist/routes/loader.d.ts.map +1 -1
- package/dist/routes/loader.js +44 -26
- package/dist/run/raw-defaults.d.ts +52 -0
- package/dist/run/raw-defaults.d.ts.map +1 -0
- package/dist/run/raw-defaults.js +123 -0
- package/dist/run/raw.d.ts +12 -0
- package/dist/run/raw.d.ts.map +1 -1
- package/dist/run/raw.js +90 -8
- package/dist/run/resolve.d.ts +17 -1
- package/dist/run/resolve.d.ts.map +1 -1
- package/dist/run/resolve.js +20 -4
- package/dist/run/routing-docs.js +1 -1
- package/dist/run/run.d.ts +7 -1
- package/dist/run/run.d.ts.map +1 -1
- package/dist/run/run.js +14 -33
- package/dist/run/variant.d.ts +43 -0
- package/dist/run/variant.d.ts.map +1 -0
- package/dist/run/variant.js +86 -0
- package/dist/savings/emit.d.ts +33 -0
- package/dist/savings/emit.d.ts.map +1 -1
- package/dist/savings/emit.js +75 -3
- package/dist/types/route.d.ts +31 -0
- package/dist/types/route.d.ts.map +1 -1
- package/dist/watch/evaluate.d.ts +27 -1
- package/dist/watch/evaluate.d.ts.map +1 -1
- package/dist/watch/evaluate.js +13 -0
- package/dist/watch/proposals.d.ts +28 -0
- package/dist/watch/proposals.d.ts.map +1 -1
- package/dist/watch/proposals.js +51 -0
- package/package.json +1 -1
package/dist/run/run.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ import type { RigManifest } from "../routes/manifest";
|
|
|
12
12
|
import type { RunOptions, RunResult } from "../types/route";
|
|
13
13
|
import type { TelemetryStore } from "../types/telemetry";
|
|
14
14
|
import type { CaptureStore } from "../telemetry/capture";
|
|
15
|
-
import type { CapabilityLookup } from "./resolve";
|
|
15
|
+
import type { CapabilityLookup, RunMode } from "./resolve";
|
|
16
16
|
import type { SearchProvider } from "./grounding";
|
|
17
17
|
import type { StreamDeltaSink } from "./dispatch";
|
|
18
18
|
import type { TaskSettingsResolver } from "../settings/task-settings";
|
|
@@ -50,6 +50,12 @@ export interface RunDeps {
|
|
|
50
50
|
* content before a capture row is written. null/omitted = local-only (the
|
|
51
51
|
* YAML flag governs, no per-task scrub policy). */
|
|
52
52
|
readonly settings?: TaskSettingsResolver | null;
|
|
53
|
+
/** Resolution mode (routing-console spec §4.4, R3) — `live` (default) on every
|
|
54
|
+
* production surface, `trial` ONLY on the bake-off replay path (`replayVariant`
|
|
55
|
+
* sets it). `trial` keeps declared `trial` candidates and permits selecting a
|
|
56
|
+
* trial variant; `live` drops trial candidates before minting and rejects a
|
|
57
|
+
* trial variant. Absent ⇒ live ⇒ byte-identical to the pre-R3 loop. */
|
|
58
|
+
readonly mode?: RunMode;
|
|
53
59
|
}
|
|
54
60
|
export declare function run(deps: RunDeps, routeName: string, opts: RunOptions): Promise<RunResult>;
|
|
55
61
|
//# sourceMappingURL=run.d.ts.map
|
package/dist/run/run.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/run/run.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAMrD,OAAO,KAAK,EAAE,eAAe,EAAgB,MAAM,mBAAmB,CAAC;AAGvE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/run/run.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAMrD,OAAO,KAAK,EAAE,eAAe,EAAgB,MAAM,mBAAmB,CAAC;AAGvE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,KAAK,EAAW,UAAU,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AACrE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,KAAK,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAS3D,OAAO,KAAK,EAAE,cAAc,EAAoC,MAAM,aAAa,CAAC;AAUpF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAKlD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAEtE,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IACxD,QAAQ,CAAC,SAAS,EAAE,cAAc,CAAC;IACnC,QAAQ,CAAC,YAAY,EAAE,gBAAgB,CAAC;IACxC,+EAA+E;IAC/E,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IACpC;;gDAE4C;IAC5C,QAAQ,CAAC,sBAAsB,CAAC,EAAE,MAAM,CAAC;IACzC,0EAA0E;IAC1E,QAAQ,CAAC,QAAQ,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IACvC;2EACuE;IACvE,QAAQ,CAAC,QAAQ,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;IACxC;;0BAEsB;IACtB,QAAQ,CAAC,MAAM,CAAC,EAAE,cAAc,GAAG,IAAI,CAAC;IACxC,qDAAqD;IACrD,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C;;;mFAG+E;IAC/E,QAAQ,CAAC,aAAa,CAAC,EAAE,eAAe,CAAC;IACzC;;;;;uDAKmD;IACnD,QAAQ,CAAC,QAAQ,CAAC,EAAE,oBAAoB,GAAG,IAAI,CAAC;IAChD;;;;2EAIuE;IACvE,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;CACzB;AAsBD,wBAAsB,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,CAgkBhG"}
|
package/dist/run/run.js
CHANGED
|
@@ -17,6 +17,7 @@ const pricing_1 = require("../registry/pricing");
|
|
|
17
17
|
const failures_1 = require("../types/failures");
|
|
18
18
|
const manifest_1 = require("../routes/manifest");
|
|
19
19
|
const resolve_1 = require("./resolve");
|
|
20
|
+
const variant_1 = require("./variant");
|
|
20
21
|
const envelope_1 = require("./envelope");
|
|
21
22
|
const retry_1 = require("./retry");
|
|
22
23
|
const repair_1 = require("./repair");
|
|
@@ -27,35 +28,6 @@ const record_attempt_1 = require("./record-attempt");
|
|
|
27
28
|
const ladder_key_1 = require("./ladder-key");
|
|
28
29
|
const run_context_1 = require("../artifacts/run-context");
|
|
29
30
|
const capture_write_1 = require("./capture-write");
|
|
30
|
-
/** Look up a named variant; null = default (base config). Unknown names are
|
|
31
|
-
* config errors — the caller asked for something the bundle doesn't define. */
|
|
32
|
-
function resolveVariant(route, name) {
|
|
33
|
-
if (name === undefined || name === "default")
|
|
34
|
-
return null;
|
|
35
|
-
const variant = route.variants.find((v) => v.name === name);
|
|
36
|
-
if (variant === undefined) {
|
|
37
|
-
throw new loader_1.RouteConfigError(`route "${route.route}" has no variant "${name}" — defined: [${route.variants
|
|
38
|
-
.map((v) => v.name)
|
|
39
|
-
.join(", ")}]`);
|
|
40
|
-
}
|
|
41
|
-
return variant;
|
|
42
|
-
}
|
|
43
|
-
/** The variant-effective view of a route: narrowed candidates, overridden
|
|
44
|
-
* json rung, overridden template. Loader validation guarantees variant
|
|
45
|
-
* candidates ⊆ declared candidates, so the candidate-set invariant holds. */
|
|
46
|
-
function effectiveRoute(route, variant) {
|
|
47
|
-
if (variant === null)
|
|
48
|
-
return route;
|
|
49
|
-
return Object.freeze({
|
|
50
|
-
...route,
|
|
51
|
-
candidates: variant.candidates ?? route.candidates,
|
|
52
|
-
systemTemplate: variant.promptOverride ?? route.systemTemplate,
|
|
53
|
-
policy: Object.freeze({
|
|
54
|
-
...route.policy,
|
|
55
|
-
json: variant.json ?? route.policy.json,
|
|
56
|
-
}),
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
31
|
/** Phase 1 prompt convention: the bundle's system template carries the whole
|
|
60
32
|
* task (constitution, data, step instructions); the user turn is a terse
|
|
61
33
|
* trigger. Providers treat long system prompts + short user turns well, and
|
|
@@ -73,10 +45,11 @@ function costPerMTok(provider, model) {
|
|
|
73
45
|
}
|
|
74
46
|
const DEFAULT_SLEEP = (ms) => ms <= 0 ? Promise.resolve() : new Promise((resolve) => setTimeout(resolve, ms));
|
|
75
47
|
async function run(deps, routeName, opts) {
|
|
48
|
+
const mode = deps.mode ?? "live";
|
|
76
49
|
const baseRoute = deps.routes.get(routeName);
|
|
77
|
-
const variant = resolveVariant(baseRoute, opts.variant);
|
|
50
|
+
const variant = (0, variant_1.resolveVariant)(baseRoute, opts.variant, mode);
|
|
78
51
|
const servedVariant = variant?.name ?? null;
|
|
79
|
-
const route = (0, resolve_1.applyRunRequirements)(effectiveRoute(baseRoute, variant), opts.zeroRetention === true);
|
|
52
|
+
const route = (0, resolve_1.applyRunRequirements)((0, variant_1.effectiveRoute)(baseRoute, variant), opts.zeroRetention === true);
|
|
80
53
|
const effectiveTags = route.require.includes("zero_retention") ? { ...opts.tags, zdr_enforced: "true" } : opts.tags;
|
|
81
54
|
// Data-hygiene warning (spec WS5): once per process per dimension.
|
|
82
55
|
(0, manifest_1.warnMissingRequiredDimensions)(deps.manifest ?? null, opts.tags);
|
|
@@ -96,7 +69,7 @@ async function run(deps, routeName, opts) {
|
|
|
96
69
|
// exit that records an inference also records a ground-truth step referencing
|
|
97
70
|
// it (attempt-per-row, ruling c). Inert without a run.start on this path.
|
|
98
71
|
const runCtx = (0, run_context_1.getActiveRunContext)();
|
|
99
|
-
const autoStepKey = runCtx !== null ? runCtx.nextStepKey(route.route) : null;
|
|
72
|
+
const autoStepKey = runCtx !== null ? (0, run_context_1.resolveStepKey)(opts.stepKey, opts.tags.step, () => runCtx.nextStepKey(route.route)) : null;
|
|
100
73
|
// Per-call ladder key (spec §2.1 R0): one call_id, a monotonic attempt_seq per
|
|
101
74
|
// row, and the current candidate_index (advanced by nextCandidate below).
|
|
102
75
|
const ladder = (0, ladder_key_1.createLadderKeyMinter)();
|
|
@@ -146,6 +119,14 @@ async function run(deps, routeName, opts) {
|
|
|
146
119
|
systemPrompt = originalSystemPrompt + (0, repair_1.repairFeedbackBlock)(errors);
|
|
147
120
|
}
|
|
148
121
|
else {
|
|
122
|
+
// Declare-first backstop (spec §4.4): the loader rejects a `trial` candidate
|
|
123
|
+
// as `repair_model`, but a programmatically-built bundle (runBundle) could
|
|
124
|
+
// bypass the loader — so refuse to mint a trial candidate for LIVE repair
|
|
125
|
+
// here too (the primary ladder's trial-drop has no repair-path equivalent).
|
|
126
|
+
if (mode === "live" &&
|
|
127
|
+
route.candidates.some((c) => c.provider === step.model.provider && c.model === step.model.model && c.trial === true)) {
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
149
130
|
// Brand stays in resolve.ts; loader validated repairModel ⊆ declared.
|
|
150
131
|
const minted = (0, resolve_1.resolveDeclaredCandidate)(route, step.model);
|
|
151
132
|
if (minted === null)
|
|
@@ -255,7 +236,7 @@ async function run(deps, routeName, opts) {
|
|
|
255
236
|
};
|
|
256
237
|
}
|
|
257
238
|
const searchAvailable = deps.search !== undefined && deps.search !== null;
|
|
258
|
-
const iter = (0, resolve_1.resolveCandidates)(route, deps.capabilities, costPerMTok, searchAvailable, (0, resolve_1.candidateFilterFromOptions)(opts));
|
|
239
|
+
const iter = (0, resolve_1.resolveCandidates)(route, deps.capabilities, costPerMTok, searchAvailable, (0, resolve_1.candidateFilterFromOptions)(opts), undefined, mode);
|
|
259
240
|
// Advance the iterator AND publish the served candidate's index to the ladder,
|
|
260
241
|
// so every row of this candidate's turn (incl. repair rows) carries it (§2.1).
|
|
261
242
|
const nextCandidate = () => {
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Variant resolution — extracted from run.ts (spec §4.4, R3) to host the
|
|
3
|
+
* declare-first "a trial variant selected live is a config error" rule and to
|
|
4
|
+
* keep run.ts under the LOC cap. Pure: bundle + requested name (+ run mode) →
|
|
5
|
+
* the resolved variant and the variant-effective route view.
|
|
6
|
+
*/
|
|
7
|
+
import type { RouteBundle, RouteVariant } from "../types/route";
|
|
8
|
+
import type { RunMode } from "./resolve";
|
|
9
|
+
/**
|
|
10
|
+
* A variant is trial-only when it has candidates and EVERY one maps to a
|
|
11
|
+
* declared `trial` candidate. Computed dynamically from `route.candidates`
|
|
12
|
+
* rather than trusted from the stored `variant.trialOnly` stamp, so a bundle
|
|
13
|
+
* built in code — a programmatic `runBundle` whose variants never passed
|
|
14
|
+
* through the loader that sets the flag — is judged exactly like a loaded one
|
|
15
|
+
* (and still earns the teaching error on a live trial selection). The loader's
|
|
16
|
+
* stamp, when present, is honored as a fast path.
|
|
17
|
+
*/
|
|
18
|
+
export declare function isTrialOnlyVariant(route: RouteBundle, variant: RouteVariant): boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Look up a named variant; null = default (base config). Unknown names are
|
|
21
|
+
* config errors — the caller asked for something the bundle doesn't define.
|
|
22
|
+
*
|
|
23
|
+
* Declare-first (spec §4.4): a `trialOnly` variant — one whose candidates are
|
|
24
|
+
* ALL declared `trial` candidates — is valid only in bake-off replay
|
|
25
|
+
* (`mode: "trial"`). Selecting it on a LIVE path is a `RouteConfigError` with a
|
|
26
|
+
* teaching message that names the bake-off, never a silent fallback (residual
|
|
27
|
+
* flag F2′): the run loop must not dispatch an undeclared OR trial model live.
|
|
28
|
+
*/
|
|
29
|
+
export declare function resolveVariant(route: RouteBundle, name: string | undefined, mode?: RunMode): RouteVariant | null;
|
|
30
|
+
/**
|
|
31
|
+
* The variant-effective view of a route: narrowed candidates, overridden json
|
|
32
|
+
* rung, overridden template. Loader validation guarantees variant candidates ⊆
|
|
33
|
+
* declared candidates, so the candidate-set invariant holds.
|
|
34
|
+
*
|
|
35
|
+
* Declare-first (spec §4.4): a variant's `candidates` entries are authored as
|
|
36
|
+
* bare `{provider, model}` and do NOT carry the route-level `trial` flag. We
|
|
37
|
+
* MUST re-attach it from the matching declared candidate — otherwise a variant
|
|
38
|
+
* that narrows to a trial candidate (e.g. a mixed trial+live variant, which is
|
|
39
|
+
* not `trialOnly` and IS selectable live) would strip the flag and
|
|
40
|
+
* `resolveCandidates`' live trial-drop would let the trial model serve live.
|
|
41
|
+
*/
|
|
42
|
+
export declare function effectiveRoute(route: RouteBundle, variant: RouteVariant | null): RouteBundle;
|
|
43
|
+
//# sourceMappingURL=variant.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"variant.d.ts","sourceRoot":"","sources":["../../src/run/variant.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAChE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAYrF;AAED;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,WAAW,EAClB,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,IAAI,GAAE,OAAgB,GACrB,YAAY,GAAG,IAAI,CAkBrB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,YAAY,GAAG,IAAI,GAAG,WAAW,CAoB5F"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Variant resolution — extracted from run.ts (spec §4.4, R3) to host the
|
|
4
|
+
* declare-first "a trial variant selected live is a config error" rule and to
|
|
5
|
+
* keep run.ts under the LOC cap. Pure: bundle + requested name (+ run mode) →
|
|
6
|
+
* the resolved variant and the variant-effective route view.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.isTrialOnlyVariant = isTrialOnlyVariant;
|
|
10
|
+
exports.resolveVariant = resolveVariant;
|
|
11
|
+
exports.effectiveRoute = effectiveRoute;
|
|
12
|
+
const loader_1 = require("../routes/loader");
|
|
13
|
+
/**
|
|
14
|
+
* A variant is trial-only when it has candidates and EVERY one maps to a
|
|
15
|
+
* declared `trial` candidate. Computed dynamically from `route.candidates`
|
|
16
|
+
* rather than trusted from the stored `variant.trialOnly` stamp, so a bundle
|
|
17
|
+
* built in code — a programmatic `runBundle` whose variants never passed
|
|
18
|
+
* through the loader that sets the flag — is judged exactly like a loaded one
|
|
19
|
+
* (and still earns the teaching error on a live trial selection). The loader's
|
|
20
|
+
* stamp, when present, is honored as a fast path.
|
|
21
|
+
*/
|
|
22
|
+
function isTrialOnlyVariant(route, variant) {
|
|
23
|
+
if (variant.trialOnly === true)
|
|
24
|
+
return true;
|
|
25
|
+
const cands = variant.candidates;
|
|
26
|
+
return (cands !== undefined &&
|
|
27
|
+
cands.length > 0 &&
|
|
28
|
+
cands.every((vc) => route.candidates.some((rc) => rc.provider === vc.provider && rc.model === vc.model && rc.trial === true)));
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Look up a named variant; null = default (base config). Unknown names are
|
|
32
|
+
* config errors — the caller asked for something the bundle doesn't define.
|
|
33
|
+
*
|
|
34
|
+
* Declare-first (spec §4.4): a `trialOnly` variant — one whose candidates are
|
|
35
|
+
* ALL declared `trial` candidates — is valid only in bake-off replay
|
|
36
|
+
* (`mode: "trial"`). Selecting it on a LIVE path is a `RouteConfigError` with a
|
|
37
|
+
* teaching message that names the bake-off, never a silent fallback (residual
|
|
38
|
+
* flag F2′): the run loop must not dispatch an undeclared OR trial model live.
|
|
39
|
+
*/
|
|
40
|
+
function resolveVariant(route, name, mode = "live") {
|
|
41
|
+
if (name === undefined || name === "default")
|
|
42
|
+
return null;
|
|
43
|
+
const variant = route.variants.find((v) => v.name === name);
|
|
44
|
+
if (variant === undefined) {
|
|
45
|
+
throw new loader_1.RouteConfigError(`route "${route.route}" has no variant "${name}" — defined: [${route.variants
|
|
46
|
+
.map((v) => v.name)
|
|
47
|
+
.join(", ")}]`);
|
|
48
|
+
}
|
|
49
|
+
if (mode === "live" && isTrialOnlyVariant(route, variant)) {
|
|
50
|
+
throw new loader_1.RouteConfigError(`route "${route.route}" variant "${name}" is a trial variant (all its candidates are declared ` +
|
|
51
|
+
`trial: true) — trial variants are declared but never served live. Measure it with a bake-off ` +
|
|
52
|
+
`(rig.bakeoff / "Run bake-off" in the console), then promote the winner to a live candidate.`);
|
|
53
|
+
}
|
|
54
|
+
return variant;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* The variant-effective view of a route: narrowed candidates, overridden json
|
|
58
|
+
* rung, overridden template. Loader validation guarantees variant candidates ⊆
|
|
59
|
+
* declared candidates, so the candidate-set invariant holds.
|
|
60
|
+
*
|
|
61
|
+
* Declare-first (spec §4.4): a variant's `candidates` entries are authored as
|
|
62
|
+
* bare `{provider, model}` and do NOT carry the route-level `trial` flag. We
|
|
63
|
+
* MUST re-attach it from the matching declared candidate — otherwise a variant
|
|
64
|
+
* that narrows to a trial candidate (e.g. a mixed trial+live variant, which is
|
|
65
|
+
* not `trialOnly` and IS selectable live) would strip the flag and
|
|
66
|
+
* `resolveCandidates`' live trial-drop would let the trial model serve live.
|
|
67
|
+
*/
|
|
68
|
+
function effectiveRoute(route, variant) {
|
|
69
|
+
if (variant === null)
|
|
70
|
+
return route;
|
|
71
|
+
const candidates = variant.candidates === undefined
|
|
72
|
+
? route.candidates
|
|
73
|
+
: variant.candidates.map((vc) => {
|
|
74
|
+
const declared = route.candidates.find((c) => c.provider === vc.provider && c.model === vc.model);
|
|
75
|
+
return declared?.trial === true ? { ...vc, trial: true } : vc;
|
|
76
|
+
});
|
|
77
|
+
return Object.freeze({
|
|
78
|
+
...route,
|
|
79
|
+
candidates,
|
|
80
|
+
systemTemplate: variant.promptOverride ?? route.systemTemplate,
|
|
81
|
+
policy: Object.freeze({
|
|
82
|
+
...route.policy,
|
|
83
|
+
json: variant.json ?? route.policy.json,
|
|
84
|
+
}),
|
|
85
|
+
});
|
|
86
|
+
}
|
package/dist/savings/emit.d.ts
CHANGED
|
@@ -6,6 +6,13 @@
|
|
|
6
6
|
* greps for it.
|
|
7
7
|
*/
|
|
8
8
|
import type { CandidateSpec, RouteBundle } from "../types/route";
|
|
9
|
+
/** A challenger to declare/promote — just the identifying pair. Loose on purpose
|
|
10
|
+
* (`provider: string`): a challenger comes from a stored proposal or the picker,
|
|
11
|
+
* where the provider is already validated, and the emitters only render YAML. */
|
|
12
|
+
export interface ChallengerRef {
|
|
13
|
+
readonly provider: string;
|
|
14
|
+
readonly model: string;
|
|
15
|
+
}
|
|
9
16
|
export interface SwapChange {
|
|
10
17
|
readonly route: string;
|
|
11
18
|
readonly file: string;
|
|
@@ -34,5 +41,31 @@ export declare function buildRestoreYaml(route: string, incumbent: readonly {
|
|
|
34
41
|
readonly provider: string;
|
|
35
42
|
readonly model: string;
|
|
36
43
|
}[], currentVersion: number): string;
|
|
44
|
+
/** The paste-ready change that DECLARES a `trial` challenger (routing-console
|
|
45
|
+
* spec §4.4, declare step). Additive-only: nothing existing is removed. */
|
|
46
|
+
export interface DeclareTrialChange {
|
|
47
|
+
readonly route: string;
|
|
48
|
+
readonly file: string;
|
|
49
|
+
readonly challenger: ChallengerRef;
|
|
50
|
+
/** The auto-named trial variant a bake-off replays (`trial-<provider>-<model>`). */
|
|
51
|
+
readonly trialVariant: string;
|
|
52
|
+
readonly newVersion: number;
|
|
53
|
+
/** Paste-ready YAML: version bump + full candidates block (challenger appended
|
|
54
|
+
* with `trial: true`) + the trial variant to add. Complete, no elisions (A4). */
|
|
55
|
+
readonly yaml: string;
|
|
56
|
+
}
|
|
57
|
+
/** A stable, YAML-safe trial variant name for a challenger. */
|
|
58
|
+
export declare function trialVariantName(challenger: ChallengerRef): string;
|
|
59
|
+
/**
|
|
60
|
+
* Emit the declare-first YAML that adds a `trial` challenger to a route (spec
|
|
61
|
+
* §4.4 step 1): the challenger appended to `candidates` with `trial: true`, a
|
|
62
|
+
* `trial-<provider>-<model>` variant that narrows to it, and `version: n+1`. The
|
|
63
|
+
* challenger is DECLARED but never served live (the loader/resolver enforce
|
|
64
|
+
* that) — so a bake-off can measure it on real traffic before promotion. Pure,
|
|
65
|
+
* no filesystem (emit.test.ts greps for that). Throws when the challenger is
|
|
66
|
+
* already a declared candidate — you don't declare what's already declared (the
|
|
67
|
+
* server maps this to 422).
|
|
68
|
+
*/
|
|
69
|
+
export declare function buildDeclareTrialChange(bundle: RouteBundle, challenger: ChallengerRef): DeclareTrialChange;
|
|
37
70
|
export declare function buildSwapChange(bundle: RouteBundle, winningVariant: string): SwapChange;
|
|
38
71
|
//# sourceMappingURL=emit.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"emit.d.ts","sourceRoot":"","sources":["../../src/savings/emit.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAgB,MAAM,gBAAgB,CAAC;AAE/E,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,2EAA2E;IAC3E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;yCACqC;IACrC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B;+DAC2D;IAC3D,QAAQ,CAAC,mBAAmB,EAAE,SAAS,aAAa,EAAE,CAAC;CACxD;
|
|
1
|
+
{"version":3,"file":"emit.d.ts","sourceRoot":"","sources":["../../src/savings/emit.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAgB,MAAM,gBAAgB,CAAC;AAE/E;;iFAEiF;AACjF,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,2EAA2E;IAC3E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;yCACqC;IACrC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B;+DAC2D;IAC3D,QAAQ,CAAC,mBAAmB,EAAE,SAAS,aAAa,EAAE,CAAC;CACxD;AA2CD;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,SAAS;IAAE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAAE,EAC3E,cAAc,EAAE,MAAM,GACrB,MAAM,CAgBR;AAED;2EAC2E;AAC3E,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,aAAa,CAAC;IACnC,oFAAoF;IACpF,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B;qFACiF;IACjF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,+DAA+D;AAC/D,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,aAAa,GAAG,MAAM,CAElE;AAED;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,aAAa,GAAG,kBAAkB,CAiC1G;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,GAAG,UAAU,CAgEvF"}
|
package/dist/savings/emit.js
CHANGED
|
@@ -8,9 +8,19 @@
|
|
|
8
8
|
*/
|
|
9
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
10
|
exports.buildRestoreYaml = buildRestoreYaml;
|
|
11
|
+
exports.trialVariantName = trialVariantName;
|
|
12
|
+
exports.buildDeclareTrialChange = buildDeclareTrialChange;
|
|
11
13
|
exports.buildSwapChange = buildSwapChange;
|
|
12
14
|
function candidateLines(candidates) {
|
|
13
|
-
|
|
15
|
+
// Preserve a candidate's `trial: true` (declare-first, spec §4.4) so an
|
|
16
|
+
// emitted candidates block never silently promotes a DECLARED-trial candidate
|
|
17
|
+
// to live. The promote path drops the flag from the WINNER explicitly (it
|
|
18
|
+
// passes a winner entry without `trial`), never here.
|
|
19
|
+
return candidates.flatMap((c) => [
|
|
20
|
+
` - provider: ${c.provider}`,
|
|
21
|
+
` model: ${c.model}`,
|
|
22
|
+
...(c.trial === true ? [" trial: true"] : []),
|
|
23
|
+
]);
|
|
14
24
|
}
|
|
15
25
|
function overrideLines(variant) {
|
|
16
26
|
const lines = [];
|
|
@@ -57,26 +67,88 @@ function buildRestoreYaml(route, incumbent, currentVersion) {
|
|
|
57
67
|
"",
|
|
58
68
|
].join("\n");
|
|
59
69
|
}
|
|
70
|
+
/** A stable, YAML-safe trial variant name for a challenger. */
|
|
71
|
+
function trialVariantName(challenger) {
|
|
72
|
+
return `trial-${challenger.provider}-${challenger.model}`.replace(/[^A-Za-z0-9._-]/g, "-");
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Emit the declare-first YAML that adds a `trial` challenger to a route (spec
|
|
76
|
+
* §4.4 step 1): the challenger appended to `candidates` with `trial: true`, a
|
|
77
|
+
* `trial-<provider>-<model>` variant that narrows to it, and `version: n+1`. The
|
|
78
|
+
* challenger is DECLARED but never served live (the loader/resolver enforce
|
|
79
|
+
* that) — so a bake-off can measure it on real traffic before promotion. Pure,
|
|
80
|
+
* no filesystem (emit.test.ts greps for that). Throws when the challenger is
|
|
81
|
+
* already a declared candidate — you don't declare what's already declared (the
|
|
82
|
+
* server maps this to 422).
|
|
83
|
+
*/
|
|
84
|
+
function buildDeclareTrialChange(bundle, challenger) {
|
|
85
|
+
if (bundle.candidates.some((c) => c.provider === challenger.provider && c.model === challenger.model)) {
|
|
86
|
+
throw new Error(`${challenger.provider}/${challenger.model} is already a declared candidate on "${bundle.route}" — ` +
|
|
87
|
+
"nothing to declare (pick a model that is not yet in the route to trial it)");
|
|
88
|
+
}
|
|
89
|
+
const file = `modelrig/routes/${bundle.route}.yaml`;
|
|
90
|
+
const newVersion = bundle.version + 1;
|
|
91
|
+
const variant = trialVariantName(challenger);
|
|
92
|
+
const newCandidates = [...bundle.candidates, { ...challenger, trial: true }];
|
|
93
|
+
const yaml = [
|
|
94
|
+
`# declare a trial of ${challenger.provider}/${challenger.model} on ${bundle.route}`,
|
|
95
|
+
`# a trial candidate is DECLARED but NEVER served live — a bake-off measures it, then Promote makes it live.`,
|
|
96
|
+
`# apply to ${file}:`,
|
|
97
|
+
`# 1) bump the version`,
|
|
98
|
+
`version: ${newVersion}`,
|
|
99
|
+
`# 2) replace your candidates: block with this (the challenger is appended and marked for trial)`,
|
|
100
|
+
"candidates:",
|
|
101
|
+
...candidateLines(newCandidates),
|
|
102
|
+
`# 3) add this entry to your variants: block (create the block if the route has none)`,
|
|
103
|
+
"variants:",
|
|
104
|
+
` - name: ${variant}`,
|
|
105
|
+
" candidates:",
|
|
106
|
+
` - provider: ${challenger.provider}`,
|
|
107
|
+
` model: ${challenger.model}`,
|
|
108
|
+
`# Requires the modelrig SDK release that understands \`trial:\` — an older SDK ignores the flag and`,
|
|
109
|
+
`# would serve the model live. Bake it off with: modelrig bakeoff --from-proposal <id>`,
|
|
110
|
+
"",
|
|
111
|
+
].join("\n");
|
|
112
|
+
return { route: bundle.route, file, challenger, trialVariant: variant, newVersion, yaml };
|
|
113
|
+
}
|
|
60
114
|
function buildSwapChange(bundle, winningVariant) {
|
|
61
115
|
const variant = bundle.variants.find((v) => v.name === winningVariant);
|
|
62
116
|
if (variant === undefined) {
|
|
63
117
|
throw new Error(`route "${bundle.route}" has no variant "${winningVariant}" — cannot emit a swap for it`);
|
|
64
118
|
}
|
|
65
|
-
|
|
119
|
+
// Promote drops `trial: true` from the WINNER and moves it to position 0. The
|
|
120
|
+
// flag is stripped EXPLICITLY here (not merely relied upon being absent from a
|
|
121
|
+
// bare variant candidate) so a hand-authored `trial: true` inside the variant's
|
|
122
|
+
// candidate block can never leave the promoted winner as a trial candidate — a
|
|
123
|
+
// silent no-op promotion where the "promoted" model is then dropped live. Other
|
|
124
|
+
// declared candidates keep their own trial flags (candidateLines preserves them).
|
|
125
|
+
const winners = (variant.candidates ?? bundle.candidates).map((c) => ({
|
|
126
|
+
provider: c.provider,
|
|
127
|
+
model: c.model,
|
|
128
|
+
}));
|
|
66
129
|
if (winners.length === 0) {
|
|
67
130
|
throw new Error(`variant "${winningVariant}" has no candidates to promote`);
|
|
68
131
|
}
|
|
69
132
|
const incumbent = bundle.candidates[0];
|
|
133
|
+
// Trial-winner promotes also remove the now-redundant trial variant (spec §4.4).
|
|
134
|
+
const isTrialPromotion = variant.trialOnly === true;
|
|
70
135
|
const promoted = promotedOrder(bundle.candidates, winners);
|
|
71
136
|
const file = `modelrig/routes/${bundle.route}.yaml`;
|
|
72
137
|
const newVersion = bundle.version + 1;
|
|
138
|
+
const applyComment = isTrialPromotion
|
|
139
|
+
? `# apply to ${file} — replace version + candidates, and REMOVE the trial variant "${winningVariant}" from variants:`
|
|
140
|
+
: `# apply to ${file} — replace the version and candidates fields; nothing else changes`;
|
|
141
|
+
const trialRemovalLine = isTrialPromotion
|
|
142
|
+
? [`# remove this now-promoted trial variant from variants: (its candidate is live at position 0 above):`, `# - name: ${winningVariant}`]
|
|
143
|
+
: [];
|
|
73
144
|
const yaml = [
|
|
74
145
|
`# swap: serve ${bundle.route} on ${winners[0].provider}/${winners[0].model}`,
|
|
75
|
-
|
|
146
|
+
applyComment,
|
|
76
147
|
`version: ${newVersion}`,
|
|
77
148
|
"candidates:",
|
|
78
149
|
...candidateLines(promoted),
|
|
79
150
|
...overrideLines(variant),
|
|
151
|
+
...trialRemovalLine,
|
|
80
152
|
"",
|
|
81
153
|
].join("\n");
|
|
82
154
|
const revertYaml = [
|
package/dist/types/route.d.ts
CHANGED
|
@@ -7,6 +7,23 @@ import type { ProviderId, SamplingParams, ServiceTier, ToolCall, ToolChoice, Too
|
|
|
7
7
|
export interface CandidateSpec {
|
|
8
8
|
readonly provider: ProviderId;
|
|
9
9
|
readonly model: string;
|
|
10
|
+
/**
|
|
11
|
+
* Declare-first experiment flag (routing-console spec §4.4, R3). A `trial`
|
|
12
|
+
* candidate is DECLARED — it is in the list the brand type, the loader and the
|
|
13
|
+
* runtime candidate-set guard all derive from, so the candidate-set invariant
|
|
14
|
+
* is untouched — but `resolveCandidates` drops it on EVERY live path
|
|
15
|
+
* (`rig.run`, `runStream`, `runBundle`, the hosted gateway slug lane) exactly
|
|
16
|
+
* as it drops a `providers.ignore` entry. Only the bake-off replay path
|
|
17
|
+
* (`replayVariant`, run `mode: "trial"`) keeps it, so a customer can measure a
|
|
18
|
+
* new model on real captured traffic before promoting it to a live candidate.
|
|
19
|
+
* Optional & additive (S3): absent ⇒ false ⇒ an ordinary live candidate.
|
|
20
|
+
*
|
|
21
|
+
* OLDER-SDK CAVEAT (spec §7): the pre-0.4.0 loader is TOLERANT of unknown
|
|
22
|
+
* candidate keys — it would ignore `trial` and serve the candidate LIVE. A
|
|
23
|
+
* bundle using `trial: true` therefore REQUIRES the SDK release that
|
|
24
|
+
* understands it; the console's declare-YAML says so.
|
|
25
|
+
*/
|
|
26
|
+
readonly trial?: boolean;
|
|
10
27
|
}
|
|
11
28
|
export type Requirement = "schema_conformant" | "grounded" | "zero_retention" | "trace_visible";
|
|
12
29
|
export type Preference = "cost" | "latency";
|
|
@@ -57,6 +74,14 @@ export interface RouteVariant {
|
|
|
57
74
|
/** JSON rung override for this variant. */
|
|
58
75
|
readonly json?: "native" | "json_mode";
|
|
59
76
|
readonly repair?: RepairPolicy;
|
|
77
|
+
/**
|
|
78
|
+
* COMPUTED at load (not authored): true when every candidate this variant
|
|
79
|
+
* narrows to is a declared `trial` candidate (routing-console spec §4.4). A
|
|
80
|
+
* trial variant is valid for `rig.bakeoff` but a `RouteConfigError` if a live
|
|
81
|
+
* caller selects it — trial candidates are declared, never live-served. The
|
|
82
|
+
* declare-first flow's `trial-<provider>-<model>` variant is exactly this.
|
|
83
|
+
*/
|
|
84
|
+
readonly trialOnly?: boolean;
|
|
60
85
|
}
|
|
61
86
|
export interface RouteBundle {
|
|
62
87
|
readonly route: string;
|
|
@@ -100,6 +125,12 @@ export interface RunTags {
|
|
|
100
125
|
export interface RunOptions {
|
|
101
126
|
readonly input: Record<string, unknown>;
|
|
102
127
|
readonly tags: RunTags;
|
|
128
|
+
/** Names the ground-truth step this run records (G1 spec §3) — the same field
|
|
129
|
+
* the raw lane exposes, so a routed and a raw call, plus an `artifact.save`,
|
|
130
|
+
* can be composed into ONE step group. Resolution: `stepKey ?? tags.step ??`
|
|
131
|
+
* an auto-minted `route#n`. Validated `[A-Za-z0-9_.:#-]{1,128}`; an invalid
|
|
132
|
+
* value is warned and dropped to the auto key. Absent ⇒ unchanged behavior. */
|
|
133
|
+
readonly stepKey?: string;
|
|
103
134
|
readonly budget?: {
|
|
104
135
|
readonly envelope: string;
|
|
105
136
|
/** Budget for this envelope when it is FIRST opened (open-or-get: the first
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../src/types/route.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEhH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../src/types/route.ts"],"names":[],"mappings":"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"}
|
package/dist/watch/evaluate.d.ts
CHANGED
|
@@ -56,7 +56,26 @@ export interface WatchConfig {
|
|
|
56
56
|
* Analyst's triggers ride the widened kinds (`insight`/`promote-eval`) or reuse
|
|
57
57
|
* `bakeoff` for an Analyst-initiated bake-off — all through the SAME proposals
|
|
58
58
|
* machinery and the SAME `submitDrafts` seam (trajectory F1/F4, one emission path). */
|
|
59
|
-
export type ProposalTrigger = EconomicsTrigger | ConformDegradationTrigger | AnalystClusterTrigger | AnalystPromoteEvalTrigger | AnalystBakeoffTrigger;
|
|
59
|
+
export type ProposalTrigger = EconomicsTrigger | ConformDegradationTrigger | AnalystClusterTrigger | AnalystPromoteEvalTrigger | AnalystBakeoffTrigger | ManualChallengerTrigger;
|
|
60
|
+
/**
|
|
61
|
+
* A human-initiated declare-first challenger (routing-console spec §2.4 / §3, R3)
|
|
62
|
+
* — the console picker (or the oracle) proposes trialing a specific model on a
|
|
63
|
+
* route. `kind` stays `"bakeoff"`; this trigger carries the challenger and the
|
|
64
|
+
* `trial-<provider>-<model>` variant name a bake-off replays. `reason` /
|
|
65
|
+
* `requestedBy` are audit context and are DELIBERATELY excluded from the
|
|
66
|
+
* idempotency hash (see {@link manualChallengerTriggerHash}) so two people
|
|
67
|
+
* declaring the same challenger dedupe to one proposal.
|
|
68
|
+
*/
|
|
69
|
+
export interface ManualChallengerTrigger {
|
|
70
|
+
readonly type: "manual_challenger";
|
|
71
|
+
readonly route: string;
|
|
72
|
+
readonly challenger: CandidateEconomics;
|
|
73
|
+
/** The trial variant a bake-off replays: `trial-<provider>-<model>`. */
|
|
74
|
+
readonly variant: string;
|
|
75
|
+
readonly reason?: string;
|
|
76
|
+
/** Actor id (user or key) that initiated the declare — audit only. */
|
|
77
|
+
readonly requestedBy?: string;
|
|
78
|
+
}
|
|
60
79
|
/** The measured statistics behind one Analyst cluster — all deterministic. */
|
|
61
80
|
export interface AnalystClusterStats {
|
|
62
81
|
/** Runs in this (task, cluster) over the window. */
|
|
@@ -169,6 +188,13 @@ export interface ProposalDraft {
|
|
|
169
188
|
}
|
|
170
189
|
export declare const PROPOSAL_TTL_DAYS = 30;
|
|
171
190
|
export declare function triggerHash(route: string, trigger: ProposalTrigger): string;
|
|
191
|
+
/**
|
|
192
|
+
* Idempotency key for a declare-first manual challenger — per (route, challenger)
|
|
193
|
+
* ONLY (spec §2.4), so `reason`/`requestedBy` never split a dedupe. The
|
|
194
|
+
* control-plane unique index is (org_id, route, trigger_hash), so the same
|
|
195
|
+
* challenger declared twice on a route by the same org is a no-op.
|
|
196
|
+
*/
|
|
197
|
+
export declare function manualChallengerTriggerHash(route: string, challenger: CandidateEconomics): string;
|
|
172
198
|
export declare function evaluateEvents(routes: readonly RouteEconomics[], events: readonly WatchEvent[], config: WatchConfig): ProposalDraft[];
|
|
173
199
|
/** The §5.5 evidence block — every field the rendered explanation and the
|
|
174
200
|
* verdict need, in one self-describing object. Rates are per-Mtok (the surface
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"evaluate.d.ts","sourceRoot":"","sources":["../../src/watch/evaluate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAYH,OAAO,KAAK,EACV,qBAAqB,EACrB,YAAY,EACZ,cAAc,EACd,kBAAkB,EACnB,MAAM,4BAA4B,CAAC;AAEpC,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,SAAS,kBAAkB,EAAE,CAAC;CACpD;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;CAClC;AAED,MAAM,MAAM,UAAU,GAClB;IACE,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAC;IACzB,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAC;CAC1B,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,UAAU,GAAG,IAAI,CAAC;CACrC,CAAC;AAEN,MAAM,WAAW,WAAW;IAC1B,8DAA8D;IAC9D,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B;;;;qFAIiF;IACjF,QAAQ,CAAC,eAAe,CAAC,EAAE,qBAAqB,CAAC;CAClD;AAED;;;;;;uFAMuF;AACvF,MAAM,MAAM,eAAe,GACvB,gBAAgB,GAChB,yBAAyB,GACzB,qBAAqB,GACrB,yBAAyB,GACzB,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"evaluate.d.ts","sourceRoot":"","sources":["../../src/watch/evaluate.ts"],"names":[],"mappings":"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"}
|
package/dist/watch/evaluate.js
CHANGED
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
19
|
exports.PROPOSAL_TTL_DAYS = void 0;
|
|
20
20
|
exports.triggerHash = triggerHash;
|
|
21
|
+
exports.manualChallengerTriggerHash = manualChallengerTriggerHash;
|
|
21
22
|
exports.evaluateEvents = evaluateEvents;
|
|
22
23
|
exports.buildCacheContext = buildCacheContext;
|
|
23
24
|
exports.explainCacheContext = explainCacheContext;
|
|
@@ -35,6 +36,18 @@ function blended(rates) {
|
|
|
35
36
|
function triggerHash(route, trigger) {
|
|
36
37
|
return (0, node_crypto_1.createHash)("sha256").update(`${route}\n${JSON.stringify(trigger)}`).digest("hex").slice(0, 32);
|
|
37
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* Idempotency key for a declare-first manual challenger — per (route, challenger)
|
|
41
|
+
* ONLY (spec §2.4), so `reason`/`requestedBy` never split a dedupe. The
|
|
42
|
+
* control-plane unique index is (org_id, route, trigger_hash), so the same
|
|
43
|
+
* challenger declared twice on a route by the same org is a no-op.
|
|
44
|
+
*/
|
|
45
|
+
function manualChallengerTriggerHash(route, challenger) {
|
|
46
|
+
return (0, node_crypto_1.createHash)("sha256")
|
|
47
|
+
.update(`manual_challenger\n${route}\n${challenger.provider}/${challenger.model}`)
|
|
48
|
+
.digest("hex")
|
|
49
|
+
.slice(0, 32);
|
|
50
|
+
}
|
|
38
51
|
function expiryStamp() {
|
|
39
52
|
return new Date(Date.now() + exports.PROPOSAL_TTL_DAYS * 24 * 3600 * 1000).toISOString();
|
|
40
53
|
}
|
|
@@ -84,6 +84,34 @@ export interface ProposalsClient {
|
|
|
84
84
|
decide(id: string, from: ProposalStatus, to: "approved" | "rejected", decidedBy: string, decidedByUserId?: string | null, orgId?: string): Promise<boolean>;
|
|
85
85
|
/** One sweep: overdue suggested/evidenced → expired. */
|
|
86
86
|
expireOverdue(now: Date): Promise<void>;
|
|
87
|
+
/**
|
|
88
|
+
* Declare-first (routing-console spec §3, R3): create a HUMAN/oracle-initiated
|
|
89
|
+
* `manual_challenger` proposal (kind `"bakeoff"`). Idempotent on
|
|
90
|
+
* (org_id, route, trigger_hash) where the hash keys on (route, challenger)
|
|
91
|
+
* only — a duplicate returns the EXISTING id with `created:false` (the caller
|
|
92
|
+
* maps that to 409). Provenance (`created_by`/`created_by_key`, migration
|
|
93
|
+
* 00055) records the actor. Returns the row id + whether it was newly created.
|
|
94
|
+
*/
|
|
95
|
+
createManualChallenger(input: CreateManualChallengerInput): Promise<{
|
|
96
|
+
id: string;
|
|
97
|
+
created: boolean;
|
|
98
|
+
status?: ProposalStatus;
|
|
99
|
+
}>;
|
|
100
|
+
}
|
|
101
|
+
export interface CreateManualChallengerInput {
|
|
102
|
+
readonly route: string;
|
|
103
|
+
readonly challenger: {
|
|
104
|
+
readonly provider: string;
|
|
105
|
+
readonly model: string;
|
|
106
|
+
};
|
|
107
|
+
/** The trial variant a bake-off replays (`trial-<provider>-<model>`). */
|
|
108
|
+
readonly variant: string;
|
|
109
|
+
readonly reason?: string;
|
|
110
|
+
/** Actor recorded in the trigger for the console (audit); NOT part of the hash. */
|
|
111
|
+
readonly requestedBy?: string;
|
|
112
|
+
/** Provenance columns (00055): exactly one is set for a console/oracle draft. */
|
|
113
|
+
readonly createdByUserId?: string | null;
|
|
114
|
+
readonly createdByKeyId?: string | null;
|
|
87
115
|
}
|
|
88
116
|
export declare function createProposalsClient(config: ProposalsClientConfig): ProposalsClient;
|
|
89
117
|
//# sourceMappingURL=proposals.d.ts.map
|