modelrig 0.1.0 → 0.3.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 +158 -0
- package/README.md +53 -11
- package/data/PROVENANCE.md +19 -0
- package/data/pricing-manual.json +22 -0
- package/data/pricing-map.json +46362 -0
- package/data/pricing-overlay.json +419 -0
- package/dist/adapters/anthropic.d.ts +50 -6
- package/dist/adapters/anthropic.d.ts.map +1 -1
- package/dist/adapters/anthropic.js +123 -29
- package/dist/adapters/build-adapters.d.ts +11 -0
- package/dist/adapters/build-adapters.d.ts.map +1 -0
- package/dist/adapters/build-adapters.js +45 -0
- package/dist/adapters/deepseek.d.ts +6 -0
- package/dist/adapters/deepseek.d.ts.map +1 -1
- package/dist/adapters/deepseek.js +54 -1
- package/dist/adapters/gemini.d.ts +10 -0
- package/dist/adapters/gemini.d.ts.map +1 -1
- package/dist/adapters/gemini.js +78 -7
- package/dist/adapters/grok.d.ts +9 -0
- package/dist/adapters/grok.d.ts.map +1 -1
- package/dist/adapters/grok.js +67 -3
- package/dist/adapters/openai-compat.d.ts +6 -0
- package/dist/adapters/openai-compat.d.ts.map +1 -1
- package/dist/adapters/openai-compat.js +58 -1
- package/dist/adapters/openai-stream.d.ts +58 -0
- package/dist/adapters/openai-stream.d.ts.map +1 -0
- package/dist/adapters/openai-stream.js +120 -0
- package/dist/adapters/openai.d.ts +6 -0
- package/dist/adapters/openai.d.ts.map +1 -1
- package/dist/adapters/openai.js +60 -1
- package/dist/adapters/sampling.d.ts +28 -0
- package/dist/adapters/sampling.d.ts.map +1 -0
- package/dist/adapters/sampling.js +34 -0
- package/dist/adapters/tool-mapping.d.ts +92 -0
- package/dist/adapters/tool-mapping.d.ts.map +1 -0
- package/dist/adapters/tool-mapping.js +143 -0
- package/dist/artifacts/artifact.d.ts +137 -0
- package/dist/artifacts/artifact.d.ts.map +1 -0
- package/dist/artifacts/artifact.js +377 -0
- package/dist/artifacts/content-uploader.d.ts +87 -0
- package/dist/artifacts/content-uploader.d.ts.map +1 -0
- package/dist/artifacts/content-uploader.js +124 -0
- package/dist/artifacts/index.d.ts +63 -0
- package/dist/artifacts/index.d.ts.map +1 -0
- package/dist/artifacts/index.js +80 -0
- package/dist/artifacts/run-context.d.ts +129 -0
- package/dist/artifacts/run-context.d.ts.map +1 -0
- package/dist/artifacts/run-context.js +208 -0
- package/dist/artifacts/scrub.d.ts +60 -0
- package/dist/artifacts/scrub.d.ts.map +1 -0
- package/dist/artifacts/scrub.js +139 -0
- package/dist/artifacts/step.d.ts +26 -0
- package/dist/artifacts/step.d.ts.map +1 -0
- package/dist/artifacts/step.js +37 -0
- package/dist/artifacts/taint.d.ts +63 -0
- package/dist/artifacts/taint.d.ts.map +1 -0
- package/dist/artifacts/taint.js +76 -0
- package/dist/bakeoff/cache-sim.d.ts +99 -0
- package/dist/bakeoff/cache-sim.d.ts.map +1 -0
- package/dist/bakeoff/cache-sim.js +126 -0
- package/dist/bakeoff/eval-cases.d.ts +96 -0
- package/dist/bakeoff/eval-cases.d.ts.map +1 -0
- package/dist/bakeoff/eval-cases.js +105 -0
- package/dist/bakeoff/report.d.ts +41 -0
- package/dist/bakeoff/report.d.ts.map +1 -0
- package/dist/bakeoff/report.js +142 -0
- package/dist/bakeoff/samples.d.ts +15 -0
- package/dist/bakeoff/samples.d.ts.map +1 -1
- package/dist/bakeoff/samples.js +20 -0
- package/dist/cli.d.ts +1 -3
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +134 -116
- package/dist/config.d.ts +100 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +104 -0
- package/dist/deprecations.d.ts +32 -0
- package/dist/deprecations.d.ts.map +1 -0
- package/dist/deprecations.js +59 -0
- package/dist/gateway/http-protocol.d.ts +175 -0
- package/dist/gateway/http-protocol.d.ts.map +1 -0
- package/dist/gateway/http-protocol.js +105 -0
- package/dist/index.d.ts +106 -19
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +266 -138
- package/dist/init/finder.d.ts +15 -0
- package/dist/init/finder.d.ts.map +1 -1
- package/dist/init/finder.js +46 -0
- package/dist/init/init-cli.d.ts +10 -0
- package/dist/init/init-cli.d.ts.map +1 -0
- package/dist/init/init-cli.js +86 -0
- package/dist/init/observe-cli.d.ts +19 -0
- package/dist/init/observe-cli.d.ts.map +1 -0
- package/dist/init/observe-cli.js +73 -0
- package/dist/init/observe.d.ts +81 -0
- package/dist/init/observe.d.ts.map +1 -0
- package/dist/init/observe.js +245 -0
- package/dist/registry/build.d.ts +94 -1
- package/dist/registry/build.d.ts.map +1 -1
- package/dist/registry/build.js +125 -4
- package/dist/registry/cache-policy.d.ts +94 -0
- package/dist/registry/cache-policy.d.ts.map +1 -0
- package/dist/registry/cache-policy.js +238 -0
- package/dist/registry/call-notes.d.ts.map +1 -1
- package/dist/registry/call-notes.js +40 -2
- package/dist/registry/effective-rate.d.ts +151 -0
- package/dist/registry/effective-rate.d.ts.map +1 -0
- package/dist/registry/effective-rate.js +156 -0
- package/dist/registry/facts.d.ts.map +1 -1
- package/dist/registry/facts.js +16 -0
- package/dist/registry/parity.d.ts +26 -0
- package/dist/registry/parity.d.ts.map +1 -1
- package/dist/registry/parity.js +43 -2
- package/dist/registry/pricing-shape.d.ts +113 -0
- package/dist/registry/pricing-shape.d.ts.map +1 -0
- package/dist/registry/pricing-shape.js +123 -0
- package/dist/registry/pricing.d.ts +25 -1
- package/dist/registry/pricing.d.ts.map +1 -1
- package/dist/registry/pricing.js +64 -6
- package/dist/rigindex/bootstrap.d.ts +36 -0
- package/dist/rigindex/bootstrap.d.ts.map +1 -0
- package/dist/rigindex/bootstrap.js +97 -0
- package/dist/rigindex/fit.d.ts +24 -0
- package/dist/rigindex/fit.d.ts.map +1 -0
- package/dist/rigindex/fit.js +76 -0
- package/dist/rigindex/gates.d.ts +52 -0
- package/dist/rigindex/gates.d.ts.map +1 -0
- package/dist/rigindex/gates.js +109 -0
- package/dist/rigindex/graph.d.ts +31 -0
- package/dist/rigindex/graph.d.ts.map +1 -0
- package/dist/rigindex/graph.js +120 -0
- package/dist/rigindex/index.d.ts +23 -0
- package/dist/rigindex/index.d.ts.map +1 -0
- package/dist/rigindex/index.js +112 -0
- package/dist/rigindex/types.d.ts +76 -0
- package/dist/rigindex/types.d.ts.map +1 -0
- package/dist/rigindex/types.js +8 -0
- package/dist/routes/cache-lint.d.ts +41 -0
- package/dist/routes/cache-lint.d.ts.map +1 -0
- package/dist/routes/cache-lint.js +81 -0
- package/dist/routes/loader.d.ts +48 -0
- package/dist/routes/loader.d.ts.map +1 -1
- package/dist/routes/loader.js +167 -0
- package/dist/routes/resolved-bundle.d.ts +79 -0
- package/dist/routes/resolved-bundle.d.ts.map +1 -0
- package/dist/routes/resolved-bundle.js +148 -0
- package/dist/routes/sampling-config.d.ts +32 -0
- package/dist/routes/sampling-config.d.ts.map +1 -0
- package/dist/routes/sampling-config.js +91 -0
- package/dist/run/ajv.d.ts +22 -0
- package/dist/run/ajv.d.ts.map +1 -0
- package/dist/run/ajv.js +32 -0
- package/dist/run/cache-handle.d.ts +58 -0
- package/dist/run/cache-handle.d.ts.map +1 -0
- package/dist/run/cache-handle.js +54 -0
- package/dist/run/cache-stamp.d.ts +65 -0
- package/dist/run/cache-stamp.d.ts.map +1 -0
- package/dist/run/cache-stamp.js +0 -0
- package/dist/run/capture-write.d.ts +33 -0
- package/dist/run/capture-write.d.ts.map +1 -0
- package/dist/run/capture-write.js +55 -0
- package/dist/run/cost.d.ts.map +1 -1
- package/dist/run/cost.js +1 -1
- package/dist/run/dispatch.d.ts +99 -0
- package/dist/run/dispatch.d.ts.map +1 -0
- package/dist/run/dispatch.js +191 -0
- package/dist/run/raw.d.ts +130 -0
- package/dist/run/raw.d.ts.map +1 -0
- package/dist/run/raw.js +363 -0
- package/dist/run/record-attempt.d.ts +40 -0
- package/dist/run/record-attempt.d.ts.map +1 -0
- package/dist/run/record-attempt.js +99 -0
- package/dist/run/resolve.d.ts +75 -2
- package/dist/run/resolve.d.ts.map +1 -1
- package/dist/run/resolve.js +126 -4
- package/dist/run/run.d.ts +14 -0
- package/dist/run/run.d.ts.map +1 -1
- package/dist/run/run.js +0 -0
- package/dist/run/stream.d.ts +49 -0
- package/dist/run/stream.d.ts.map +1 -0
- package/dist/run/stream.js +87 -0
- package/dist/run/validate.d.ts.map +1 -1
- package/dist/run/validate.js +6 -7
- package/dist/savings/cache-ledger.d.ts +108 -0
- package/dist/savings/cache-ledger.d.ts.map +1 -0
- package/dist/savings/cache-ledger.js +174 -0
- package/dist/savings/cache-reconcile.d.ts +64 -0
- package/dist/savings/cache-reconcile.d.ts.map +1 -0
- package/dist/savings/cache-reconcile.js +59 -0
- package/dist/savings/cache-stats.d.ts +63 -0
- package/dist/savings/cache-stats.d.ts.map +1 -0
- package/dist/savings/cache-stats.js +108 -0
- package/dist/savings/emit.d.ts +13 -0
- package/dist/savings/emit.d.ts.map +1 -1
- package/dist/savings/emit.js +25 -0
- package/dist/savings/swap-execute.d.ts +14 -0
- package/dist/savings/swap-execute.d.ts.map +1 -1
- package/dist/savings/swap-execute.js +44 -1
- package/dist/savings/swaps-client.d.ts +14 -0
- package/dist/savings/swaps-client.d.ts.map +1 -1
- package/dist/savings/swaps-client.js +16 -2
- package/dist/settings/api-fetcher.d.ts +39 -0
- package/dist/settings/api-fetcher.d.ts.map +1 -0
- package/dist/settings/api-fetcher.js +92 -0
- package/dist/settings/index.d.ts +10 -0
- package/dist/settings/index.d.ts.map +1 -0
- package/dist/settings/index.js +15 -0
- package/dist/settings/task-settings.d.ts +91 -0
- package/dist/settings/task-settings.d.ts.map +1 -0
- package/dist/settings/task-settings.js +116 -0
- package/dist/status.d.ts +77 -0
- package/dist/status.d.ts.map +1 -0
- package/dist/status.js +113 -0
- package/dist/telemetry/artifact-store.d.ts +48 -0
- package/dist/telemetry/artifact-store.d.ts.map +1 -0
- package/dist/telemetry/artifact-store.js +189 -0
- package/dist/telemetry/cache-miss-streak.d.ts +79 -0
- package/dist/telemetry/cache-miss-streak.d.ts.map +1 -0
- package/dist/telemetry/cache-miss-streak.js +99 -0
- package/dist/telemetry/capture.d.ts +3 -0
- package/dist/telemetry/capture.d.ts.map +1 -1
- package/dist/telemetry/capture.js +15 -8
- package/dist/telemetry/exporter-setup.d.ts +28 -0
- package/dist/telemetry/exporter-setup.d.ts.map +1 -0
- package/dist/telemetry/exporter-setup.js +34 -0
- package/dist/telemetry/exporter.d.ts +75 -0
- package/dist/telemetry/exporter.d.ts.map +1 -1
- package/dist/telemetry/exporter.js +324 -47
- package/dist/telemetry/health.d.ts +76 -0
- package/dist/telemetry/health.d.ts.map +1 -0
- package/dist/telemetry/health.js +92 -0
- package/dist/telemetry/ingest-protocol.d.ts +152 -3
- package/dist/telemetry/ingest-protocol.d.ts.map +1 -1
- package/dist/telemetry/ingest-protocol.js +204 -4
- package/dist/telemetry/load-error-report.d.ts +24 -0
- package/dist/telemetry/load-error-report.d.ts.map +1 -0
- package/dist/telemetry/load-error-report.js +50 -0
- package/dist/telemetry/otel-map.d.ts +121 -0
- package/dist/telemetry/otel-map.d.ts.map +1 -0
- package/dist/telemetry/otel-map.js +224 -0
- package/dist/telemetry/otel-normalize.d.ts +104 -0
- package/dist/telemetry/otel-normalize.d.ts.map +1 -0
- package/dist/telemetry/otel-normalize.js +530 -0
- package/dist/telemetry/otlp-emitter.d.ts +52 -0
- package/dist/telemetry/otlp-emitter.d.ts.map +1 -0
- package/dist/telemetry/otlp-emitter.js +144 -0
- package/dist/telemetry/otlp-proto.d.ts +29 -0
- package/dist/telemetry/otlp-proto.d.ts.map +1 -0
- package/dist/telemetry/otlp-proto.js +266 -0
- package/dist/telemetry/sinks.d.ts +37 -1
- package/dist/telemetry/sinks.d.ts.map +1 -1
- package/dist/telemetry/sinks.js +121 -30
- package/dist/telemetry/store.d.ts +28 -1
- package/dist/telemetry/store.d.ts.map +1 -1
- package/dist/telemetry/store.js +218 -3
- package/dist/tenancy/api-key-format.d.ts +15 -5
- package/dist/tenancy/api-key-format.d.ts.map +1 -1
- package/dist/tenancy/api-key-format.js +24 -5
- package/dist/types/config-teaching.d.ts +62 -0
- package/dist/types/config-teaching.d.ts.map +1 -0
- package/dist/types/config-teaching.js +183 -0
- package/dist/types/provider.d.ts +147 -1
- package/dist/types/provider.d.ts.map +1 -1
- package/dist/types/provider.js +21 -1
- package/dist/types/route.d.ts +79 -1
- package/dist/types/route.d.ts.map +1 -1
- package/dist/types/telemetry.d.ts +117 -0
- package/dist/types/telemetry.d.ts.map +1 -1
- package/dist/validate-cli.d.ts +12 -0
- package/dist/validate-cli.d.ts.map +1 -0
- package/dist/validate-cli.js +57 -0
- package/dist/verify/capture.d.ts +66 -0
- package/dist/verify/capture.d.ts.map +1 -0
- package/dist/verify/capture.js +180 -0
- package/dist/verify/cli-run.d.ts +23 -0
- package/dist/verify/cli-run.d.ts.map +1 -0
- package/dist/verify/cli-run.js +57 -0
- package/dist/verify/diff.d.ts +48 -0
- package/dist/verify/diff.d.ts.map +1 -0
- package/dist/verify/diff.js +157 -0
- package/dist/verify/index.d.ts +17 -0
- package/dist/verify/index.d.ts.map +1 -0
- package/dist/verify/index.js +24 -0
- package/dist/verify/report.d.ts +14 -0
- package/dist/verify/report.d.ts.map +1 -0
- package/dist/verify/report.js +88 -0
- package/dist/verify/types.d.ts +101 -0
- package/dist/verify/types.d.ts.map +1 -0
- package/dist/verify/types.js +17 -0
- package/dist/verify/verify.d.ts +29 -0
- package/dist/verify/verify.d.ts.map +1 -0
- package/dist/verify/verify.js +148 -0
- package/dist/watch/evaluate.d.ts +162 -3
- package/dist/watch/evaluate.d.ts.map +1 -1
- package/dist/watch/evaluate.js +61 -0
- package/dist/watch/monitor.d.ts +116 -0
- package/dist/watch/monitor.d.ts.map +1 -0
- package/dist/watch/monitor.js +199 -0
- package/dist/watch/proposals.d.ts +20 -4
- package/dist/watch/proposals.d.ts.map +1 -1
- package/dist/watch/proposals.js +31 -3
- package/dist/watch/run.d.ts +33 -0
- package/dist/watch/run.d.ts.map +1 -1
- package/dist/watch/run.js +39 -0
- package/package.json +7 -1
- package/registry/LICENSE +20 -0
- package/registry/leaderboard.json +3639 -0
- package/registry/registry.json +7263 -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
package/dist/run/resolve.js
CHANGED
|
@@ -8,6 +8,10 @@
|
|
|
8
8
|
*/
|
|
9
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
10
|
exports.resolveCandidates = resolveCandidates;
|
|
11
|
+
exports.applyRunRequirements = applyRunRequirements;
|
|
12
|
+
exports.candidateFilterFromOptions = candidateFilterFromOptions;
|
|
13
|
+
exports.filterSummary = filterSummary;
|
|
14
|
+
exports.mintRawCandidate = mintRawCandidate;
|
|
11
15
|
exports.resolveDeclaredCandidate = resolveDeclaredCandidate;
|
|
12
16
|
function satisfiesRequirements(route, flags, searchAvailable) {
|
|
13
17
|
for (const requirement of route.require) {
|
|
@@ -38,15 +42,43 @@ function satisfiesRequirements(route, flags, searchAvailable) {
|
|
|
38
42
|
return false;
|
|
39
43
|
break;
|
|
40
44
|
case "zero_retention":
|
|
41
|
-
//
|
|
42
|
-
//
|
|
45
|
+
// G-3: opt-in data-governance filter. Route only to endpoints the
|
|
46
|
+
// credential-scoped registry facts designate zero-retention (claims.ts
|
|
47
|
+
// → facts.ts materializes the flag under the managed/any scope). A hard
|
|
48
|
+
// capability filter exactly like trace_visible; the empty-set case falls
|
|
49
|
+
// through to the existing no-eligible-candidate path (fail-closed — never
|
|
50
|
+
// a silent non-ZDR dispatch). The claim ceiling: "route only to
|
|
51
|
+
// zero-retention–designated endpoints," never "verified non-retention."
|
|
52
|
+
if (!flags.has("zero_retention"))
|
|
53
|
+
return false;
|
|
43
54
|
break;
|
|
44
55
|
}
|
|
45
56
|
}
|
|
46
57
|
return true;
|
|
47
58
|
}
|
|
48
|
-
function resolveCandidates(route, capabilities, costUsdPerMTok, searchAvailable = false) {
|
|
49
|
-
|
|
59
|
+
function resolveCandidates(route, capabilities, costUsdPerMTok, searchAvailable = false, filter, shadowWarmth) {
|
|
60
|
+
// Filter order (spec §4.1): provider only → provider ignore → capability+ZDR
|
|
61
|
+
// → maxPrice → prefer:[cost]. When `filter` is absent every step is a no-op,
|
|
62
|
+
// so the path is byte-for-byte the pre-G-2 behavior (back-compat).
|
|
63
|
+
let pool = route.candidates;
|
|
64
|
+
if (filter?.only && filter.only.length > 0) {
|
|
65
|
+
const only = new Set(filter.only);
|
|
66
|
+
pool = pool.filter((c) => only.has(c.provider));
|
|
67
|
+
}
|
|
68
|
+
if (filter?.ignore && filter.ignore.length > 0) {
|
|
69
|
+
const ignore = new Set(filter.ignore);
|
|
70
|
+
pool = pool.filter((c) => !ignore.has(c.provider));
|
|
71
|
+
}
|
|
72
|
+
let eligible = pool.filter((c) => satisfiesRequirements(route, capabilities(c.provider, c.model), searchAvailable));
|
|
73
|
+
if (filter?.maxPriceUsdPerMTok != null) {
|
|
74
|
+
const cap = filter.maxPriceUsdPerMTok;
|
|
75
|
+
// Unknown cost + a ceiling set → DROP (fail-closed: we can't prove it is
|
|
76
|
+
// under the cap; same stance as the envelope on unpriced models).
|
|
77
|
+
eligible = eligible.filter((c) => {
|
|
78
|
+
const usd = costUsdPerMTok(c.provider, c.model);
|
|
79
|
+
return usd !== null && usd <= cap;
|
|
80
|
+
});
|
|
81
|
+
}
|
|
50
82
|
// prefer: [cost] — ascending, unknown cost sorts last, stable otherwise.
|
|
51
83
|
// "latency" is advisory in Phase 1 (no probe data): declared order stands.
|
|
52
84
|
const ordered = [...eligible];
|
|
@@ -56,6 +88,37 @@ function resolveCandidates(route, capabilities, costUsdPerMTok, searchAvailable
|
|
|
56
88
|
return usd === null ? Number.POSITIVE_INFINITY : usd;
|
|
57
89
|
};
|
|
58
90
|
ordered.sort((a, b) => cost(a) - cost(b));
|
|
91
|
+
// SHADOW MODE (spec §5.5, step 8): compute what ordering by cache-ADJUSTED
|
|
92
|
+
// effective cost would recommend, log chosen-vs-recommended, and DO NOTHING
|
|
93
|
+
// ELSE. `ordered` (the list-cost order) is what we return — warmth never
|
|
94
|
+
// flips a route this mission. A no-op when `shadowWarmth` is absent, so the
|
|
95
|
+
// returned order is byte-identical to the pre-WS-B resolver.
|
|
96
|
+
//
|
|
97
|
+
// WRAPPED so shadow-mode is STRICTLY non-interfering: this is the actuation
|
|
98
|
+
// path (the only CandidateRef minter). A throwing warmth/log callback is a
|
|
99
|
+
// shadow-observation bug and must NEVER take down live candidate resolution
|
|
100
|
+
// — swallow it. `ordered` is already fixed above; nothing here can change it.
|
|
101
|
+
if (shadowWarmth !== undefined) {
|
|
102
|
+
try {
|
|
103
|
+
const effCost = (c) => {
|
|
104
|
+
const usd = shadowWarmth.effectiveCostUsdPerMTok(c.provider, c.model);
|
|
105
|
+
return usd === null ? Number.POSITIVE_INFINITY : usd;
|
|
106
|
+
};
|
|
107
|
+
const recommended = [...eligible].sort((a, b) => effCost(a) - effCost(b));
|
|
108
|
+
const same = recommended.length === ordered.length &&
|
|
109
|
+
recommended.every((c, i) => c.provider === ordered[i].provider && c.model === ordered[i].model);
|
|
110
|
+
shadowWarmth.log({
|
|
111
|
+
route: route.route,
|
|
112
|
+
chosen: ordered.map((c) => ({ provider: c.provider, model: c.model })),
|
|
113
|
+
recommended: recommended.map((c) => ({ provider: c.provider, model: c.model })),
|
|
114
|
+
diverged: !same,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
// Shadow observation failed — intentionally ignored. Routing proceeds on
|
|
119
|
+
// the list-cost order exactly as if no warmth had been supplied.
|
|
120
|
+
}
|
|
121
|
+
}
|
|
59
122
|
}
|
|
60
123
|
// THE brand site — the only place in the codebase a CandidateRef may be
|
|
61
124
|
// minted. The cast below is the single sanctioned exception to the
|
|
@@ -68,6 +131,65 @@ function resolveCandidates(route, capabilities, costUsdPerMTok, searchAvailable
|
|
|
68
131
|
},
|
|
69
132
|
};
|
|
70
133
|
}
|
|
134
|
+
/**
|
|
135
|
+
* Per-run requirement opt-ins (G-3). A caller can demand zero-retention routing
|
|
136
|
+
* for a single run without editing the route bundle: `zero_retention` is unioned
|
|
137
|
+
* into the effective `require`, so the existing satisfiesRequirements filter, the
|
|
138
|
+
* no-eligible-candidate message, and the fail-closed empty-set path all apply
|
|
139
|
+
* unchanged. Additive only — a run opts INTO a stricter requirement, never OUT of
|
|
140
|
+
* a route's declared one (opting out would be a governance downgrade).
|
|
141
|
+
*/
|
|
142
|
+
function applyRunRequirements(route, zeroRetention) {
|
|
143
|
+
if (!zeroRetention || route.require.includes("zero_retention"))
|
|
144
|
+
return route;
|
|
145
|
+
return Object.freeze({
|
|
146
|
+
...route,
|
|
147
|
+
require: Object.freeze([...route.require, "zero_retention"]),
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
/** Map a run's RunOptions to a CandidateFilter (G-2), or undefined when no knob
|
|
151
|
+
* is set — so the resolver takes the byte-identical pre-G-2 path (back-compat). */
|
|
152
|
+
function candidateFilterFromOptions(opts) {
|
|
153
|
+
const only = opts.providers?.only;
|
|
154
|
+
const ignore = opts.providers?.ignore;
|
|
155
|
+
const max = opts.maxPriceUsdPerMTok;
|
|
156
|
+
if (max == null && (only?.length ?? 0) === 0 && (ignore?.length ?? 0) === 0)
|
|
157
|
+
return undefined;
|
|
158
|
+
return {
|
|
159
|
+
...(max != null ? { maxPriceUsdPerMTok: max } : {}),
|
|
160
|
+
...(only ? { only } : {}),
|
|
161
|
+
...(ignore ? { ignore } : {}),
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
/** A human-readable suffix naming the binding request-time filters, for the
|
|
165
|
+
* existing no-eligible-candidate error (spec §4.3 — explainability, not a new
|
|
166
|
+
* error class). Empty when no filter is set. */
|
|
167
|
+
function filterSummary(opts) {
|
|
168
|
+
const parts = [];
|
|
169
|
+
if (opts.maxPriceUsdPerMTok != null)
|
|
170
|
+
parts.push(`maxPrice ≤ $${opts.maxPriceUsdPerMTok}/MTok`);
|
|
171
|
+
if (opts.providers?.only?.length)
|
|
172
|
+
parts.push(`only=[${opts.providers.only.join(", ")}]`);
|
|
173
|
+
if (opts.providers?.ignore?.length)
|
|
174
|
+
parts.push(`ignore=[${opts.providers.ignore.join(", ")}]`);
|
|
175
|
+
return parts.length > 0 ? ` and request filters {${parts.join("; ")}}` : "";
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Mint a CandidateRef for the RAW LANE (http-gateway spec §4.2) — a
|
|
179
|
+
* `provider/model` the caller named explicitly, dispatched at zero margin on
|
|
180
|
+
* the caller's own BYOK key with NO route and NO verified pipeline.
|
|
181
|
+
*
|
|
182
|
+
* The candidate-set invariant guards against substituting a model outside a
|
|
183
|
+
* ROUTE's declared list; a route-free, explicitly-named passthrough is outside
|
|
184
|
+
* that invariant's scope by construction (there is no list to escape). This is
|
|
185
|
+
* the ONE sanctioned brand site for it, so the "no `as CandidateRef`" grep stays
|
|
186
|
+
* clean and the brand stays centralized here. The authorization that replaces
|
|
187
|
+
* route membership lives server-side: the raw lane dispatches only after
|
|
188
|
+
* `resolveProviderKeyForCall` returns a BYOK key fail-closed (spec §4.2).
|
|
189
|
+
*/
|
|
190
|
+
function mintRawCandidate(provider, model) {
|
|
191
|
+
return Object.freeze({ provider, model });
|
|
192
|
+
}
|
|
71
193
|
/**
|
|
72
194
|
* Mint a CandidateRef for a SPECIFIC declared candidate (the repair rung's
|
|
73
195
|
* designated repair model — loader-validated to be in the route's candidate
|
package/dist/run/run.d.ts
CHANGED
|
@@ -14,6 +14,8 @@ import type { TelemetryStore } from "../types/telemetry";
|
|
|
14
14
|
import type { CaptureStore } from "../telemetry/capture";
|
|
15
15
|
import type { CapabilityLookup } from "./resolve";
|
|
16
16
|
import type { SearchProvider } from "./grounding";
|
|
17
|
+
import type { StreamDeltaSink } from "./dispatch";
|
|
18
|
+
import type { TaskSettingsResolver } from "../settings/task-settings";
|
|
17
19
|
export interface RunDeps {
|
|
18
20
|
readonly routes: LoadedRoutes;
|
|
19
21
|
readonly adapters: ReadonlyMap<string, ProviderAdapter>;
|
|
@@ -36,6 +38,18 @@ export interface RunDeps {
|
|
|
36
38
|
readonly search?: SearchProvider | null;
|
|
37
39
|
/** Injectable backoff sleep — tests pass a no-op. */
|
|
38
40
|
readonly sleep?: (ms: number) => Promise<void>;
|
|
41
|
+
/** Streaming side-channel (G-1/G-5 Phase A). When set AND the serving
|
|
42
|
+
* adapter can stream, the primary attempt forwards raw text deltas here as
|
|
43
|
+
* they arrive; the buffered terminal result still drives validation/telemetry
|
|
44
|
+
* unchanged. `rig.runStream()` wires this; `rig.run()` leaves it undefined. */
|
|
45
|
+
readonly onStreamDelta?: StreamDeltaSink;
|
|
46
|
+
/** Control-plane task-settings resolver (settings-plane §1.5) — present only
|
|
47
|
+
* in api mode. The capture-WRITE gate consults it: `effectiveCapture` lets a
|
|
48
|
+
* control-plane flip WIN over the YAML `capture:` flag (a console flip turns
|
|
49
|
+
* capture on/off with no redeploy), and the task's scrub setting governs
|
|
50
|
+
* content before a capture row is written. null/omitted = local-only (the
|
|
51
|
+
* YAML flag governs, no per-task scrub policy). */
|
|
52
|
+
readonly settings?: TaskSettingsResolver | null;
|
|
39
53
|
}
|
|
40
54
|
export declare function run(deps: RunDeps, routeName: string, opts: RunOptions): Promise<RunResult>;
|
|
41
55
|
//# 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;
|
|
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,EAAsC,UAAU,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChG,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAQlD,OAAO,KAAK,EAAE,cAAc,EAAoC,MAAM,aAAa,CAAC;AASpF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAIlD,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;CACjD;AAsED,wBAAsB,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,CAoiBhG"}
|
package/dist/run/run.js
CHANGED
|
Binary file
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Streaming surface on the run path — G-1/G-5 Phase A (http-gateway spec §4.3).
|
|
3
|
+
*
|
|
4
|
+
* `runStream` wraps the existing `run()` loop with a delta side-channel: as the
|
|
5
|
+
* serving adapter streams, raw text tokens are emitted as `delta` events; when
|
|
6
|
+
* the run resolves, its terminal `RunResult` is emitted as the `final` event.
|
|
7
|
+
* Crucially the SAME pipeline (resolve → dispatch → validate → repair →
|
|
8
|
+
* telemetry) drives both streamed and buffered runs — streaming is purely a
|
|
9
|
+
* side-channel, so validation, repair, ZDR (G-3) and routing controls (G-2)
|
|
10
|
+
* all apply unchanged. `rig.run()` is left exactly as it was.
|
|
11
|
+
*
|
|
12
|
+
* The structured-route caveat (spec §4.3): streamed `delta` bytes are the
|
|
13
|
+
* model's RAW pre-validation output. The `final` event is authoritative — it
|
|
14
|
+
* carries the schema-validated (and, if repair fired, repaired) object plus
|
|
15
|
+
* `meta.validated` / `meta.repairedBy`. Callers wanting validated-only output
|
|
16
|
+
* pass `buffered: true` (no deltas, just the final) — the SDK mirror of the
|
|
17
|
+
* endpoint's `x-modelrig-stream: buffered`.
|
|
18
|
+
*
|
|
19
|
+
* ModelRig never executes a tool (spec §4.4); a tool-call turn surfaces on the
|
|
20
|
+
* final event's `meta.toolCalls` exactly as it does through `run()`.
|
|
21
|
+
*/
|
|
22
|
+
import type { RunDeps } from "./run";
|
|
23
|
+
import type { RunOptions, RunResult } from "../types/route";
|
|
24
|
+
export type RunStreamEvent = {
|
|
25
|
+
readonly type: "delta";
|
|
26
|
+
readonly text: string;
|
|
27
|
+
} | {
|
|
28
|
+
readonly type: "final";
|
|
29
|
+
readonly result: RunResult;
|
|
30
|
+
};
|
|
31
|
+
export interface RunStreamOptions extends RunOptions {
|
|
32
|
+
/** Buffered mode (spec §4.3): suppress token deltas and emit only the
|
|
33
|
+
* terminal (validated) result. Default false = stream-then-final. */
|
|
34
|
+
readonly buffered?: boolean;
|
|
35
|
+
}
|
|
36
|
+
export interface RunStreamHandle {
|
|
37
|
+
/** Async-iterable of `delta` events then a single `final`. Re-throws the
|
|
38
|
+
* run's error if it failed (after any deltas already emitted). */
|
|
39
|
+
readonly events: AsyncIterable<RunStreamEvent>;
|
|
40
|
+
/** The terminal RunResult, or a rejection with the run's typed failure.
|
|
41
|
+
* Resolves with the same object carried by the `final` event. */
|
|
42
|
+
readonly result: Promise<RunResult>;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Drive a route with token streaming. Returns an async-iterable of events plus
|
|
46
|
+
* a `result` promise for callers that only want the terminal value.
|
|
47
|
+
*/
|
|
48
|
+
export declare function runStream(deps: RunDeps, routeName: string, opts: RunStreamOptions): RunStreamHandle;
|
|
49
|
+
//# sourceMappingURL=stream.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../../src/run/stream.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AACrC,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE5D,MAAM,MAAM,cAAc,GACtB;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACjD;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAA;CAAE,CAAC;AAE3D,MAAM,WAAW,gBAAiB,SAAQ,UAAU;IAClD;yEACqE;IACrE,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,MAAM,WAAW,eAAe;IAC9B;sEACkE;IAClE,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,cAAc,CAAC,CAAC;IAC/C;qEACiE;IACjE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;CACrC;AAED;;;GAGG;AACH,wBAAgB,SAAS,CACvB,IAAI,EAAE,OAAO,EACb,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,gBAAgB,GACrB,eAAe,CA6DjB"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Streaming surface on the run path — G-1/G-5 Phase A (http-gateway spec §4.3).
|
|
4
|
+
*
|
|
5
|
+
* `runStream` wraps the existing `run()` loop with a delta side-channel: as the
|
|
6
|
+
* serving adapter streams, raw text tokens are emitted as `delta` events; when
|
|
7
|
+
* the run resolves, its terminal `RunResult` is emitted as the `final` event.
|
|
8
|
+
* Crucially the SAME pipeline (resolve → dispatch → validate → repair →
|
|
9
|
+
* telemetry) drives both streamed and buffered runs — streaming is purely a
|
|
10
|
+
* side-channel, so validation, repair, ZDR (G-3) and routing controls (G-2)
|
|
11
|
+
* all apply unchanged. `rig.run()` is left exactly as it was.
|
|
12
|
+
*
|
|
13
|
+
* The structured-route caveat (spec §4.3): streamed `delta` bytes are the
|
|
14
|
+
* model's RAW pre-validation output. The `final` event is authoritative — it
|
|
15
|
+
* carries the schema-validated (and, if repair fired, repaired) object plus
|
|
16
|
+
* `meta.validated` / `meta.repairedBy`. Callers wanting validated-only output
|
|
17
|
+
* pass `buffered: true` (no deltas, just the final) — the SDK mirror of the
|
|
18
|
+
* endpoint's `x-modelrig-stream: buffered`.
|
|
19
|
+
*
|
|
20
|
+
* ModelRig never executes a tool (spec §4.4); a tool-call turn surfaces on the
|
|
21
|
+
* final event's `meta.toolCalls` exactly as it does through `run()`.
|
|
22
|
+
*/
|
|
23
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
|
+
exports.runStream = runStream;
|
|
25
|
+
const run_1 = require("./run");
|
|
26
|
+
/**
|
|
27
|
+
* Drive a route with token streaming. Returns an async-iterable of events plus
|
|
28
|
+
* a `result` promise for callers that only want the terminal value.
|
|
29
|
+
*/
|
|
30
|
+
function runStream(deps, routeName, opts) {
|
|
31
|
+
const queue = [];
|
|
32
|
+
let wake = null;
|
|
33
|
+
let done = false;
|
|
34
|
+
let failure = null;
|
|
35
|
+
const emit = (ev) => {
|
|
36
|
+
queue.push(ev);
|
|
37
|
+
if (wake !== null) {
|
|
38
|
+
wake();
|
|
39
|
+
wake = null;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
const finish = () => {
|
|
43
|
+
done = true;
|
|
44
|
+
if (wake !== null) {
|
|
45
|
+
wake();
|
|
46
|
+
wake = null;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
// Buffered mode omits the delta sink entirely — the loop then dispatches via
|
|
50
|
+
// the adapter's buffered call() (no true streaming), exactly as before.
|
|
51
|
+
const streamDeps = opts.buffered === true
|
|
52
|
+
? deps
|
|
53
|
+
: { ...deps, onStreamDelta: ({ text }) => emit({ type: "delta", text }) };
|
|
54
|
+
const result = (0, run_1.run)(streamDeps, routeName, opts)
|
|
55
|
+
.then((r) => {
|
|
56
|
+
emit({ type: "final", result: r });
|
|
57
|
+
return r;
|
|
58
|
+
})
|
|
59
|
+
.catch((e) => {
|
|
60
|
+
failure = e;
|
|
61
|
+
throw e;
|
|
62
|
+
})
|
|
63
|
+
.finally(finish);
|
|
64
|
+
// A caller may consume only `events`; keep the promise from becoming an
|
|
65
|
+
// unhandled rejection (the error still surfaces through the iterator).
|
|
66
|
+
result.catch(() => undefined);
|
|
67
|
+
const events = {
|
|
68
|
+
async *[Symbol.asyncIterator]() {
|
|
69
|
+
for (;;) {
|
|
70
|
+
while (queue.length > 0) {
|
|
71
|
+
const ev = queue.shift();
|
|
72
|
+
if (ev !== undefined)
|
|
73
|
+
yield ev;
|
|
74
|
+
}
|
|
75
|
+
if (done) {
|
|
76
|
+
if (failure !== null)
|
|
77
|
+
throw failure;
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
await new Promise((res) => {
|
|
81
|
+
wake = res;
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
return { events, result };
|
|
87
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/run/validate.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/run/validate.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAGlD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,8DAA8D;IAC9D,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B;AAwBD,wBAAgB,cAAc,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,iBAAiB,CA6BlF"}
|
package/dist/run/validate.js
CHANGED
|
@@ -4,15 +4,14 @@
|
|
|
4
4
|
* Phase 1 checks schema conformance; value-accuracy gates arrive with the
|
|
5
5
|
* bake-off in Phase 3.
|
|
6
6
|
*/
|
|
7
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
8
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
9
|
-
};
|
|
10
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
8
|
exports.validateOutput = validateOutput;
|
|
12
|
-
const ajv_1 =
|
|
13
|
-
// Mirrors the production probe harness
|
|
14
|
-
//
|
|
15
|
-
|
|
9
|
+
const ajv_1 = require("./ajv");
|
|
10
|
+
// Mirrors the production probe harness (packages/modelrig-probes/src/harness.ts):
|
|
11
|
+
// an Ajv-2020 instance with the draft-07 meta added for back-compat — the two
|
|
12
|
+
// must enforce identically, or a fixture would score differently than it serves.
|
|
13
|
+
// Schemas trip ajv strict-mode warnings by design (strict:false).
|
|
14
|
+
const ajv = (0, ajv_1.createModelrigAjv)();
|
|
16
15
|
const MAX_ERRORS = 12;
|
|
17
16
|
/** Compiled validators cached per (route, version) — recompiling a 300-line
|
|
18
17
|
* schema per attempt is measurable. */
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cache Ledger — DERIVED in v1 (cache-aware-routing spec §5.2, [Briefing §8]).
|
|
3
|
+
*
|
|
4
|
+
* The Briefing's Cache Ledger is a first-class fast-state store; v1 does NOT
|
|
5
|
+
* build one. It DERIVES warm-set state from telemetry rows at decision time —
|
|
6
|
+
* ZERO new tables (spec schema budget). The `CacheLedgerEntry` TYPE ships now so
|
|
7
|
+
* that when the conversational-gateway phase needs a dedicated store (per-message
|
|
8
|
+
* traffic makes per-call derivation too hot), it is a swap of BACKING, not of
|
|
9
|
+
* SHAPE. Nothing here persists anything.
|
|
10
|
+
*
|
|
11
|
+
* This answers the Briefing's first-milestone question — "which candidate routes
|
|
12
|
+
* appear warm, by how much, at what confidence" [§41] — with a 4-value status:
|
|
13
|
+
*
|
|
14
|
+
* observed_hot — the most recent use within the TTL window actually READ
|
|
15
|
+
* cache (tokensCached>0): the cache is demonstrably warm.
|
|
16
|
+
* probably_hot — last use within the TTL window but no read observed on it:
|
|
17
|
+
* warmth is INFERRED from recency, not seen.
|
|
18
|
+
* probably_expired— last use past the TTL but within a bounded grace: likely
|
|
19
|
+
* cold, yet recent enough that a switch-back could still hit
|
|
20
|
+
* (LiteLLM: 99.3% of switch-backs land within TTL, [§6]).
|
|
21
|
+
* cold — no recent use, well past any grace, or the provider does
|
|
22
|
+
* not cache on our path (fail-closed).
|
|
23
|
+
*
|
|
24
|
+
* ── CONSERVATISM (spec §10 cache-state overconfidence) ────────────────────
|
|
25
|
+
* The TTL comes from the POLICY REGISTRY only. When a provider publishes no TTL
|
|
26
|
+
* (deepseek "hours-to-days", gemini/fireworks best-effort → `default_ttl_seconds:
|
|
27
|
+
* null`), we do NOT invent a warm window: the entry can reach `observed_hot`
|
|
28
|
+
* only via a demonstrated read within a short fallback recency, and otherwise is
|
|
29
|
+
* `cold`. Under-claiming warmth never over-predicts a hit.
|
|
30
|
+
*/
|
|
31
|
+
import type { CachePolicy } from "../registry/cache-policy";
|
|
32
|
+
import type { ProviderId } from "../types/provider";
|
|
33
|
+
import type { TelemetryRow } from "../types/telemetry";
|
|
34
|
+
export type WarmStatus = "observed_hot" | "probably_hot" | "probably_expired" | "cold";
|
|
35
|
+
/**
|
|
36
|
+
* One derived warm-set entry: a (route, candidate, prefix_fingerprint, cache_key)
|
|
37
|
+
* group's current cache standing. The shape is the phase-2 storage seam —
|
|
38
|
+
* everything a dedicated ledger row would carry is here, derived.
|
|
39
|
+
*/
|
|
40
|
+
export interface CacheLedgerEntry {
|
|
41
|
+
readonly route: string;
|
|
42
|
+
readonly provider: string;
|
|
43
|
+
readonly model: string;
|
|
44
|
+
/** The cacheable-prefix identity (WS-C fills it; null in WS-A telemetry). */
|
|
45
|
+
readonly prefixFingerprint: string | null;
|
|
46
|
+
/** The provider cache key sent, if any (WS-C fills it; null otherwise). */
|
|
47
|
+
readonly cacheKey: string | null;
|
|
48
|
+
readonly status: WarmStatus;
|
|
49
|
+
/** Most recent use of this group (ISO). */
|
|
50
|
+
readonly lastSeenAt: string;
|
|
51
|
+
/** Seconds since `lastSeenAt` relative to the injected `now`. */
|
|
52
|
+
readonly ageSeconds: number;
|
|
53
|
+
/** Best estimate of the warm prefix size, tokens ("by how much" [§41]): the
|
|
54
|
+
* largest observed cache-READ on the group, or — when no read was observed —
|
|
55
|
+
* the mean input tokens as an upper bound of what COULD be cached. */
|
|
56
|
+
readonly warmTokens: number;
|
|
57
|
+
/** Largest observed cache-read on the group (0 ⇒ warmth is inferred, not seen). */
|
|
58
|
+
readonly observedReadTokens: number;
|
|
59
|
+
/** The policy TTL used to classify (seconds), or null when undocumented. */
|
|
60
|
+
readonly ttlSeconds: number | null;
|
|
61
|
+
/** Workflow identity (spec §9): run-loop = route; E2 runs carry episode_id.
|
|
62
|
+
* v1 normalizes to the route handle — the field exists so the ledger type is
|
|
63
|
+
* stable when episode-keyed workflows arrive. */
|
|
64
|
+
readonly workflowId: string;
|
|
65
|
+
}
|
|
66
|
+
export interface CacheLedgerOptions {
|
|
67
|
+
/** Reference "now" (epoch ms) — injected for deterministic derivation/tests. */
|
|
68
|
+
readonly now: number;
|
|
69
|
+
/** Policy lookup — injected for tests; defaults to the live registry. */
|
|
70
|
+
readonly policyFor?: (provider: ProviderId) => CachePolicy;
|
|
71
|
+
/** Only rows at/after this window start (epoch ms) are considered. Older rows
|
|
72
|
+
* cannot be warm and are skipped. Defaults to 24h before `now` — well past any
|
|
73
|
+
* seeded TTL, so no genuinely-warm group is dropped. */
|
|
74
|
+
readonly windowStartMs?: number;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Fallback recency window (seconds) for the `observed_hot` decision when a
|
|
78
|
+
* provider publishes NO TTL. NOT a claimed provider TTL — a conservative display
|
|
79
|
+
* bound so an ancient demonstrated read is not still called "hot". 5 minutes is
|
|
80
|
+
* the shortest real cache TTL in the registry (Anthropic 5m), so it never
|
|
81
|
+
* over-claims relative to any documented policy.
|
|
82
|
+
*/
|
|
83
|
+
export declare const NULL_TTL_OBSERVED_HOT_SECONDS = 300;
|
|
84
|
+
/**
|
|
85
|
+
* Grace multiplier past the TTL for `probably_expired` before an entry is called
|
|
86
|
+
* `cold`. Beyond `ttl × this`, a switch-back is very unlikely to still hit.
|
|
87
|
+
*/
|
|
88
|
+
export declare const PROBABLY_EXPIRED_TTL_MULTIPLE = 3;
|
|
89
|
+
/**
|
|
90
|
+
* Classify a group's warm status from its policy TTL, age, and whether the most
|
|
91
|
+
* recent use read cache. Pure and total; the boundary rules are the architect
|
|
92
|
+
* math-review surface, so they are spelled out rather than folded together.
|
|
93
|
+
*/
|
|
94
|
+
export declare function classifyWarmStatus(policy: CachePolicy, ageSeconds: number, lastUseReadCache: boolean): WarmStatus;
|
|
95
|
+
/**
|
|
96
|
+
* Derive the warm-set ledger from telemetry rows (spec §5.2). Groups production
|
|
97
|
+
* rows by (route, provider, model, prefix_fingerprint, cache_key), takes each
|
|
98
|
+
* group's most-recent use to classify warmth via the policy TTL, and estimates
|
|
99
|
+
* the warm prefix size. Replay rows are excluded (odometer parity). Output is
|
|
100
|
+
* sorted for deterministic rendering. Nothing is stored.
|
|
101
|
+
*/
|
|
102
|
+
export declare function deriveCacheLedger(rows: readonly TelemetryRow[], opts: CacheLedgerOptions): CacheLedgerEntry[];
|
|
103
|
+
/** The warm candidates for a route — `observed_hot` or `probably_hot` — as the
|
|
104
|
+
* warmth input for shadow-mode ordering (WS-B step 8) and the console warm-set
|
|
105
|
+
* chips (WS-D). `probably_expired`/`cold` are excluded: warmth we would ACT on
|
|
106
|
+
* must be current, not merely recent. */
|
|
107
|
+
export declare function warmEntries(ledger: readonly CacheLedgerEntry[]): CacheLedgerEntry[];
|
|
108
|
+
//# sourceMappingURL=cache-ledger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache-ledger.d.ts","sourceRoot":"","sources":["../../src/savings/cache-ledger.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,MAAM,MAAM,UAAU,GAAG,cAAc,GAAG,cAAc,GAAG,kBAAkB,GAAG,MAAM,CAAC;AAEvF;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,6EAA6E;IAC7E,QAAQ,CAAC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1C,2EAA2E;IAC3E,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,2CAA2C;IAC3C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,iEAAiE;IACjE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B;;0EAEsE;IACtE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,mFAAmF;IACnF,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,4EAA4E;IAC5E,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC;;qDAEiD;IACjD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,kBAAkB;IACjC,gFAAgF;IAChF,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,yEAAyE;IACzE,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,UAAU,KAAK,WAAW,CAAC;IAC3D;;4DAEwD;IACxD,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;CACjC;AAED;;;;;;GAMG;AACH,eAAO,MAAM,6BAA6B,MAAM,CAAC;AAEjD;;;GAGG;AACH,eAAO,MAAM,6BAA6B,IAAI,CAAC;AAa/C;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,WAAW,EACnB,UAAU,EAAE,MAAM,EAClB,gBAAgB,EAAE,OAAO,GACxB,UAAU,CAkBZ;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,SAAS,YAAY,EAAE,EAC7B,IAAI,EAAE,kBAAkB,GACvB,gBAAgB,EAAE,CA6FpB;AAED;;;yCAGyC;AACzC,wBAAgB,WAAW,CAAC,MAAM,EAAE,SAAS,gBAAgB,EAAE,GAAG,gBAAgB,EAAE,CAEnF"}
|