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
|
@@ -22,5 +22,31 @@ export interface ParityReport {
|
|
|
22
22
|
readonly probedPct: number;
|
|
23
23
|
readonly gaps: readonly ParityGap[];
|
|
24
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* Normalize a model key for the parity join. The parity list is a hand-curated
|
|
27
|
+
* monthly snapshot; the registry is machine-generated from probe result files.
|
|
28
|
+
* Two keys that differ only by CASE or surrounding whitespace name the same
|
|
29
|
+
* model, so we match modulo those — a benign rename (e.g. `Qwen` vs `qwen` in a
|
|
30
|
+
* host catalog) must not silently drop coverage and force another manual
|
|
31
|
+
* id_repair. This is deliberately conservative: it collapses case/whitespace
|
|
32
|
+
* only, never leaf variants, so distinct ids (`grok/grok-4-2` vs `grok/grok-4.3`)
|
|
33
|
+
* stay distinct and an unprobed model is never falsely counted as probed.
|
|
34
|
+
*/
|
|
35
|
+
export declare function normalizeParityKey(key: string): string;
|
|
25
36
|
export declare function computeParity(list: readonly ParityListEntry[], registry: Registry): ParityReport;
|
|
37
|
+
/** Does the registry contain at least one model with probed schema samples?
|
|
38
|
+
* The precondition for the zero-coverage gate below: a 0 coverage number is
|
|
39
|
+
* only suspicious when there IS probed data that failed to join. */
|
|
40
|
+
export declare function registryHasProbedModels(registry: Registry): boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Mechanical zero-coverage gate — makes the parity-list ↔ registry join
|
|
43
|
+
* regression un-forgettable. If parity coverage computes 0 probed WHILE the
|
|
44
|
+
* registry actually contains probed models, the join is broken (an id/namespace
|
|
45
|
+
* mismatch between the curated list and the machine-generated registry, exactly
|
|
46
|
+
* the failure the id_repair_note documents), and a leaderboard rendered from it
|
|
47
|
+
* would publish 0% coverage as if it were true. Throw rather than render that.
|
|
48
|
+
* A legitimately-empty registry (no probed models yet) computes 0 and is fine.
|
|
49
|
+
* Call this wherever computeParity feeds a rendered/published surface.
|
|
50
|
+
*/
|
|
51
|
+
export declare function assertParityCoverageSane(report: ParityReport, registry: Registry): void;
|
|
26
52
|
//# sourceMappingURL=parity.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parity.d.ts","sourceRoot":"","sources":["../../src/registry/parity.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAExC,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;CAC3C;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,gBAAgB,GAAG,iBAAiB,CAAC;CACvD;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,SAAS,SAAS,EAAE,CAAC;CACrC;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,SAAS,eAAe,EAAE,EAAE,QAAQ,EAAE,QAAQ,GAAG,YAAY,CA4BhG"}
|
|
1
|
+
{"version":3,"file":"parity.d.ts","sourceRoot":"","sources":["../../src/registry/parity.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAExC,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;CAC3C;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,gBAAgB,GAAG,iBAAiB,CAAC;CACvD;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,SAAS,SAAS,EAAE,CAAC;CACrC;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,SAAS,eAAe,EAAE,EAAE,QAAQ,EAAE,QAAQ,GAAG,YAAY,CA4BhG;AAED;;oEAEoE;AACpE,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAEnE;AAED;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAUvF"}
|
package/dist/registry/parity.js
CHANGED
|
@@ -7,16 +7,32 @@
|
|
|
7
7
|
* Gaps are named on the leaderboard ("not yet probed"), never invisible.
|
|
8
8
|
*/
|
|
9
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.normalizeParityKey = normalizeParityKey;
|
|
10
11
|
exports.computeParity = computeParity;
|
|
12
|
+
exports.registryHasProbedModels = registryHasProbedModels;
|
|
13
|
+
exports.assertParityCoverageSane = assertParityCoverageSane;
|
|
14
|
+
/**
|
|
15
|
+
* Normalize a model key for the parity join. The parity list is a hand-curated
|
|
16
|
+
* monthly snapshot; the registry is machine-generated from probe result files.
|
|
17
|
+
* Two keys that differ only by CASE or surrounding whitespace name the same
|
|
18
|
+
* model, so we match modulo those — a benign rename (e.g. `Qwen` vs `qwen` in a
|
|
19
|
+
* host catalog) must not silently drop coverage and force another manual
|
|
20
|
+
* id_repair. This is deliberately conservative: it collapses case/whitespace
|
|
21
|
+
* only, never leaf variants, so distinct ids (`grok/grok-4-2` vs `grok/grok-4.3`)
|
|
22
|
+
* stay distinct and an unprobed model is never falsely counted as probed.
|
|
23
|
+
*/
|
|
24
|
+
function normalizeParityKey(key) {
|
|
25
|
+
return key.trim().toLowerCase();
|
|
26
|
+
}
|
|
11
27
|
function computeParity(list, registry) {
|
|
12
|
-
const byKey = new Map(registry.models.map((m) => [m.model_key, m]));
|
|
28
|
+
const byKey = new Map(registry.models.map((m) => [normalizeParityKey(m.model_key), m]));
|
|
13
29
|
let probed = 0;
|
|
14
30
|
let listedUnprobed = 0;
|
|
15
31
|
let missing = 0;
|
|
16
32
|
const gaps = [];
|
|
17
33
|
for (const entry of list) {
|
|
18
34
|
const matches = entry.registry_keys
|
|
19
|
-
.map((k) => byKey.get(k))
|
|
35
|
+
.map((k) => byKey.get(normalizeParityKey(k)))
|
|
20
36
|
.filter((m) => m !== undefined);
|
|
21
37
|
if (matches.some((m) => (m.probed?.schema?.samples ?? 0) > 0)) {
|
|
22
38
|
probed += 1;
|
|
@@ -39,3 +55,28 @@ function computeParity(list, registry) {
|
|
|
39
55
|
gaps,
|
|
40
56
|
};
|
|
41
57
|
}
|
|
58
|
+
/** Does the registry contain at least one model with probed schema samples?
|
|
59
|
+
* The precondition for the zero-coverage gate below: a 0 coverage number is
|
|
60
|
+
* only suspicious when there IS probed data that failed to join. */
|
|
61
|
+
function registryHasProbedModels(registry) {
|
|
62
|
+
return registry.models.some((m) => (m.probed?.schema?.samples ?? 0) > 0);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Mechanical zero-coverage gate — makes the parity-list ↔ registry join
|
|
66
|
+
* regression un-forgettable. If parity coverage computes 0 probed WHILE the
|
|
67
|
+
* registry actually contains probed models, the join is broken (an id/namespace
|
|
68
|
+
* mismatch between the curated list and the machine-generated registry, exactly
|
|
69
|
+
* the failure the id_repair_note documents), and a leaderboard rendered from it
|
|
70
|
+
* would publish 0% coverage as if it were true. Throw rather than render that.
|
|
71
|
+
* A legitimately-empty registry (no probed models yet) computes 0 and is fine.
|
|
72
|
+
* Call this wherever computeParity feeds a rendered/published surface.
|
|
73
|
+
*/
|
|
74
|
+
function assertParityCoverageSane(report, registry) {
|
|
75
|
+
if (report.probed === 0 && registryHasProbedModels(registry)) {
|
|
76
|
+
throw new Error("parity-50 coverage computed 0 probed, but the registry contains probed models — " +
|
|
77
|
+
"the parity-list↔registry join is broken (likely an id/namespace mismatch between the " +
|
|
78
|
+
"curated list keys and the registry model_keys). Refusing to render a leaderboard that " +
|
|
79
|
+
"hides real coverage. Fix the registry_keys in registry/parity-50.json or the " +
|
|
80
|
+
"normalization in src/registry/parity.ts.");
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* First-class pricing shape — spec `pricing-first-class/spec.md` §2.1.
|
|
3
|
+
*
|
|
4
|
+
* A structured, additive representation of a model's price that can carry
|
|
5
|
+
* every component a vendor publishes (serving-tier multipliers, cache-write,
|
|
6
|
+
* context-length bands, batch discounts, per-modality input rates), each with
|
|
7
|
+
* `source` + `as_of`, and — required — a `basis` string stating what the
|
|
8
|
+
* headline number *is*. It exists ALONGSIDE the flat three-component
|
|
9
|
+
* `DeclaredLayer.pricing` (which is not retired this pass — S3 order of
|
|
10
|
+
* destruction); a snapshot-only entry maps trivially via `synthesizeFromFlat`.
|
|
11
|
+
*
|
|
12
|
+
* GOVERNING RULE (dev-rule L5, spec §3): never fabricate a component you have
|
|
13
|
+
* not verified against the vendor's published number. Tier multipliers are
|
|
14
|
+
* MULTIPLIERS on `base` (1.0 = base), not absolute rates — a mis-read
|
|
15
|
+
* multiplier is worse than a missing one, so absent data degrades to
|
|
16
|
+
* `base`-only, never to a guessed tier.
|
|
17
|
+
*
|
|
18
|
+
* Units: every `TokenRates` field is USD PER TOKEN (not per-Mtok) — the same
|
|
19
|
+
* unit as `ModelPricing.inputUsdPerTok`, so synthesis is a pure passthrough.
|
|
20
|
+
*/
|
|
21
|
+
export interface TokenRates {
|
|
22
|
+
readonly input: number;
|
|
23
|
+
readonly output: number;
|
|
24
|
+
/** context-cache READ rate. */
|
|
25
|
+
readonly cache_read?: number | null;
|
|
26
|
+
/** context-cache WRITE rate (Anthropic-class 5m TTL / OpenAI 5.6+). */
|
|
27
|
+
readonly cache_write?: number | null;
|
|
28
|
+
/** 1h-TTL context-cache WRITE rate (Anthropic 2×; WS-A). Additive — absent
|
|
29
|
+
* ⇒ the 1h write bucket bills at `cache_write` (fail-closed, dev-rule L5). */
|
|
30
|
+
readonly cache_write_1h?: number | null;
|
|
31
|
+
}
|
|
32
|
+
/** MULTIPLIERS on `base` (1.0 = base), NOT absolute rates. */
|
|
33
|
+
export interface ServingTiers {
|
|
34
|
+
readonly priority?: number | null;
|
|
35
|
+
readonly fast?: number | null;
|
|
36
|
+
readonly region_us?: number | null;
|
|
37
|
+
}
|
|
38
|
+
/** A rate change that applies above a token threshold. */
|
|
39
|
+
export interface ContextBand {
|
|
40
|
+
readonly above_tokens: number;
|
|
41
|
+
readonly rates: TokenRates;
|
|
42
|
+
}
|
|
43
|
+
/** Non-text input units, USD per unit. */
|
|
44
|
+
export interface ModalityRates {
|
|
45
|
+
readonly image_per_unit?: number | null;
|
|
46
|
+
readonly audio_per_second?: number | null;
|
|
47
|
+
}
|
|
48
|
+
export interface ModelPricingV2 {
|
|
49
|
+
/** standard-tier text — the only REQUIRED rates block. */
|
|
50
|
+
readonly base: TokenRates;
|
|
51
|
+
readonly tiers?: ServingTiers | null;
|
|
52
|
+
readonly context_bands?: readonly ContextBand[] | null;
|
|
53
|
+
readonly batch_discount?: number | null;
|
|
54
|
+
readonly modality?: ModalityRates | null;
|
|
55
|
+
/** provenance: host-api / website / snapshot. */
|
|
56
|
+
readonly source: string;
|
|
57
|
+
readonly as_of: string;
|
|
58
|
+
/** What `base` represents, rendered verbatim on the surface (P5, in code). */
|
|
59
|
+
readonly basis: string;
|
|
60
|
+
}
|
|
61
|
+
/** The basis string for a snapshot-synthesized (base-only, standard, text)
|
|
62
|
+
* entry — the honest caveat when nothing richer than three components exists. */
|
|
63
|
+
export declare const SNAPSHOT_BASIS = "base \u00B7 standard tier \u00B7 text";
|
|
64
|
+
/**
|
|
65
|
+
* Map a flat three-component price (USD per token) to a `ModelPricingV2` with
|
|
66
|
+
* `base` only — `tiers`, `context_bands`, `batch`, `modality` all null. This is
|
|
67
|
+
* the fail-closed default for every model the sweep could not enrich: it
|
|
68
|
+
* asserts nothing beyond the standard text rate the flat field already carried.
|
|
69
|
+
*
|
|
70
|
+
* `asOf`/`source` are provenance the shape requires (spec §2.1 marks both
|
|
71
|
+
* required); the plan names the three rate values as the essential inputs, and
|
|
72
|
+
* the caller supplies provenance. `source` defaults to the snapshot lane.
|
|
73
|
+
*/
|
|
74
|
+
export declare function synthesizeFromFlat(input: number, output: number, cache_read: number | null, asOf: string, source?: string): ModelPricingV2;
|
|
75
|
+
export type ServingTierName = "priority" | "fast" | "region_us";
|
|
76
|
+
/**
|
|
77
|
+
* Absolute rates for a serving tier = `base × multiplier`. Returns `null` when
|
|
78
|
+
* the tier's multiplier is absent — fail-closed, so no surface can render a
|
|
79
|
+
* tier price the model never published. The multiplier scales every rate
|
|
80
|
+
* component present on `base`.
|
|
81
|
+
*/
|
|
82
|
+
export declare function tierRates(pricing: ModelPricingV2, tier: ServingTierName): TokenRates | null;
|
|
83
|
+
/** A display-ready projection of a price. `basis` is always present, so a
|
|
84
|
+
* surface built from this object can never show a number without its caveat. */
|
|
85
|
+
export interface PricingV2Display {
|
|
86
|
+
/** what the headline number IS — always present (the render caveat). */
|
|
87
|
+
readonly basis: string;
|
|
88
|
+
/** "$3.00 in · $15.00 out per Mtok" — the base rates. */
|
|
89
|
+
readonly base: string;
|
|
90
|
+
readonly cacheRead: string | null;
|
|
91
|
+
readonly cacheWrite: string | null;
|
|
92
|
+
/** 1h-TTL cache-write rate per Mtok (Anthropic 2×); null when unpublished. */
|
|
93
|
+
readonly cacheWrite1h: string | null;
|
|
94
|
+
/** absolute tier rates, base × multiplier, per Mtok. */
|
|
95
|
+
readonly tiers: readonly {
|
|
96
|
+
readonly name: ServingTierName;
|
|
97
|
+
readonly rate: string;
|
|
98
|
+
}[];
|
|
99
|
+
readonly contextBands: readonly string[];
|
|
100
|
+
readonly batch: string | null;
|
|
101
|
+
readonly modality: readonly string[];
|
|
102
|
+
readonly source: string;
|
|
103
|
+
readonly asOf: string;
|
|
104
|
+
/** vendor page URL if the `source` embeds one, for a "full terms" link. */
|
|
105
|
+
readonly vendorUrl: string | null;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Build the display projection. Every returned object carries `basis`; the
|
|
109
|
+
* base rate string is only ever produced together with it — the render-caveat
|
|
110
|
+
* guarantee lives here, in code, so no consumer can bypass it.
|
|
111
|
+
*/
|
|
112
|
+
export declare function describePricingV2(pricing: ModelPricingV2): PricingV2Display;
|
|
113
|
+
//# sourceMappingURL=pricing-shape.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pricing-shape.d.ts","sourceRoot":"","sources":["../../src/registry/pricing-shape.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* First-class pricing shape — spec `pricing-first-class/spec.md` §2.1.
|
|
4
|
+
*
|
|
5
|
+
* A structured, additive representation of a model's price that can carry
|
|
6
|
+
* every component a vendor publishes (serving-tier multipliers, cache-write,
|
|
7
|
+
* context-length bands, batch discounts, per-modality input rates), each with
|
|
8
|
+
* `source` + `as_of`, and — required — a `basis` string stating what the
|
|
9
|
+
* headline number *is*. It exists ALONGSIDE the flat three-component
|
|
10
|
+
* `DeclaredLayer.pricing` (which is not retired this pass — S3 order of
|
|
11
|
+
* destruction); a snapshot-only entry maps trivially via `synthesizeFromFlat`.
|
|
12
|
+
*
|
|
13
|
+
* GOVERNING RULE (dev-rule L5, spec §3): never fabricate a component you have
|
|
14
|
+
* not verified against the vendor's published number. Tier multipliers are
|
|
15
|
+
* MULTIPLIERS on `base` (1.0 = base), not absolute rates — a mis-read
|
|
16
|
+
* multiplier is worse than a missing one, so absent data degrades to
|
|
17
|
+
* `base`-only, never to a guessed tier.
|
|
18
|
+
*
|
|
19
|
+
* Units: every `TokenRates` field is USD PER TOKEN (not per-Mtok) — the same
|
|
20
|
+
* unit as `ModelPricing.inputUsdPerTok`, so synthesis is a pure passthrough.
|
|
21
|
+
*/
|
|
22
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
+
exports.SNAPSHOT_BASIS = void 0;
|
|
24
|
+
exports.synthesizeFromFlat = synthesizeFromFlat;
|
|
25
|
+
exports.tierRates = tierRates;
|
|
26
|
+
exports.describePricingV2 = describePricingV2;
|
|
27
|
+
/** The basis string for a snapshot-synthesized (base-only, standard, text)
|
|
28
|
+
* entry — the honest caveat when nothing richer than three components exists. */
|
|
29
|
+
exports.SNAPSHOT_BASIS = "base · standard tier · text";
|
|
30
|
+
/**
|
|
31
|
+
* Map a flat three-component price (USD per token) to a `ModelPricingV2` with
|
|
32
|
+
* `base` only — `tiers`, `context_bands`, `batch`, `modality` all null. This is
|
|
33
|
+
* the fail-closed default for every model the sweep could not enrich: it
|
|
34
|
+
* asserts nothing beyond the standard text rate the flat field already carried.
|
|
35
|
+
*
|
|
36
|
+
* `asOf`/`source` are provenance the shape requires (spec §2.1 marks both
|
|
37
|
+
* required); the plan names the three rate values as the essential inputs, and
|
|
38
|
+
* the caller supplies provenance. `source` defaults to the snapshot lane.
|
|
39
|
+
*/
|
|
40
|
+
function synthesizeFromFlat(input, output, cache_read, asOf, source = "litellm-snapshot") {
|
|
41
|
+
return {
|
|
42
|
+
base: { input, output, cache_read },
|
|
43
|
+
tiers: null,
|
|
44
|
+
context_bands: null,
|
|
45
|
+
batch_discount: null,
|
|
46
|
+
modality: null,
|
|
47
|
+
source,
|
|
48
|
+
as_of: asOf,
|
|
49
|
+
basis: exports.SNAPSHOT_BASIS,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function scale(rate, mult) {
|
|
53
|
+
return rate === null || rate === undefined ? null : rate * mult;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Absolute rates for a serving tier = `base × multiplier`. Returns `null` when
|
|
57
|
+
* the tier's multiplier is absent — fail-closed, so no surface can render a
|
|
58
|
+
* tier price the model never published. The multiplier scales every rate
|
|
59
|
+
* component present on `base`.
|
|
60
|
+
*/
|
|
61
|
+
function tierRates(pricing, tier) {
|
|
62
|
+
const mult = pricing.tiers?.[tier];
|
|
63
|
+
if (mult === null || mult === undefined)
|
|
64
|
+
return null;
|
|
65
|
+
return {
|
|
66
|
+
input: pricing.base.input * mult,
|
|
67
|
+
output: pricing.base.output * mult,
|
|
68
|
+
cache_read: scale(pricing.base.cache_read, mult),
|
|
69
|
+
cache_write: scale(pricing.base.cache_write, mult),
|
|
70
|
+
cache_write_1h: scale(pricing.base.cache_write_1h, mult),
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
const TIER_ORDER = ["priority", "fast", "region_us"];
|
|
74
|
+
/** USD-per-token → "$X.XX" per Mtok. Adaptive precision: a pricing-authority
|
|
75
|
+
* surface must not misrepresent a rate — `$0.075/M` renders as `$0.075`, not a
|
|
76
|
+
* rounded `$0.07`/`$0.08`. Shows up to 6 decimals, trailing zeros trimmed, with
|
|
77
|
+
* a 2-decimal floor for readability. */
|
|
78
|
+
function perMtok(perToken) {
|
|
79
|
+
const v = perToken * 1e6;
|
|
80
|
+
const trimmed = v.toFixed(6).replace(/\.?0+$/, "");
|
|
81
|
+
const decimals = trimmed.includes(".") ? trimmed.split(".")[1].length : 0;
|
|
82
|
+
return `$${decimals >= 2 ? trimmed : v.toFixed(2)}`;
|
|
83
|
+
}
|
|
84
|
+
function inOut(rates) {
|
|
85
|
+
return `${perMtok(rates.input)} in · ${perMtok(rates.output)} out per Mtok`;
|
|
86
|
+
}
|
|
87
|
+
const URL_RE = /https?:\/\/[^\s)]+/;
|
|
88
|
+
/**
|
|
89
|
+
* Build the display projection. Every returned object carries `basis`; the
|
|
90
|
+
* base rate string is only ever produced together with it — the render-caveat
|
|
91
|
+
* guarantee lives here, in code, so no consumer can bypass it.
|
|
92
|
+
*/
|
|
93
|
+
function describePricingV2(pricing) {
|
|
94
|
+
const tiers = [];
|
|
95
|
+
for (const name of TIER_ORDER) {
|
|
96
|
+
const rates = tierRates(pricing, name);
|
|
97
|
+
if (rates !== null)
|
|
98
|
+
tiers.push({ name, rate: inOut(rates) });
|
|
99
|
+
}
|
|
100
|
+
const contextBands = (pricing.context_bands ?? []).map((b) => `above ${b.above_tokens.toLocaleString()} tok: ${inOut(b.rates)}`);
|
|
101
|
+
const modality = [];
|
|
102
|
+
if (pricing.modality?.image_per_unit != null) {
|
|
103
|
+
modality.push(`image: $${pricing.modality.image_per_unit.toFixed(4)} per unit`);
|
|
104
|
+
}
|
|
105
|
+
if (pricing.modality?.audio_per_second != null) {
|
|
106
|
+
modality.push(`audio: $${pricing.modality.audio_per_second.toFixed(4)} per second`);
|
|
107
|
+
}
|
|
108
|
+
const urlMatch = URL_RE.exec(pricing.source);
|
|
109
|
+
return {
|
|
110
|
+
basis: pricing.basis,
|
|
111
|
+
base: inOut(pricing.base),
|
|
112
|
+
cacheRead: pricing.base.cache_read != null ? `${perMtok(pricing.base.cache_read)} per Mtok` : null,
|
|
113
|
+
cacheWrite: pricing.base.cache_write != null ? `${perMtok(pricing.base.cache_write)} per Mtok` : null,
|
|
114
|
+
cacheWrite1h: pricing.base.cache_write_1h != null ? `${perMtok(pricing.base.cache_write_1h)} per Mtok` : null,
|
|
115
|
+
tiers,
|
|
116
|
+
contextBands,
|
|
117
|
+
batch: pricing.batch_discount != null ? `${(pricing.batch_discount * 100).toFixed(0)}% off base` : null,
|
|
118
|
+
modality,
|
|
119
|
+
source: pricing.source,
|
|
120
|
+
asOf: pricing.as_of,
|
|
121
|
+
vendorUrl: urlMatch ? urlMatch[0] : null,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
@@ -9,11 +9,35 @@
|
|
|
9
9
|
* Copyright (c) 2023 Berri AI, MIT License (https://github.com/BerriAI/litellm).
|
|
10
10
|
*/
|
|
11
11
|
import type { ProviderId } from "../types/provider";
|
|
12
|
+
import type { ModelPricingV2 } from "./pricing-shape";
|
|
12
13
|
export interface ModelPricing {
|
|
13
14
|
readonly inputUsdPerTok: number;
|
|
14
15
|
readonly outputUsdPerTok: number;
|
|
15
16
|
readonly cachedInputUsdPerTok: number | null;
|
|
17
|
+
/** Cache-CREATION (write) rate, USD/tok (WS-A). From LiteLLM
|
|
18
|
+
* `cache_creation_input_token_cost`. null ⇒ unverified: cache writes bill at
|
|
19
|
+
* the input rate (1.0×), never a guessed premium (dev-rule L5). */
|
|
20
|
+
readonly cacheWriteUsdPerTok: number | null;
|
|
21
|
+
/** 1h-TTL cache-write rate, USD/tok (Anthropic 2×; WS-A). From LiteLLM
|
|
22
|
+
* `cache_creation_input_token_cost_above_1hr`. null ⇒ the 1h portion falls
|
|
23
|
+
* back to `cacheWriteUsdPerTok` (then to input) — fail-closed. */
|
|
24
|
+
readonly cacheWrite1hUsdPerTok: number | null;
|
|
16
25
|
}
|
|
17
26
|
export declare function getPricing(provider: ProviderId, model: string): ModelPricing | null;
|
|
18
|
-
|
|
27
|
+
/**
|
|
28
|
+
* The richer `ModelPricingV2` a vendor overlay/manual entry carries, if any —
|
|
29
|
+
* resolved by the SAME key precedence as {@link getPricing} (snapshot wins on a
|
|
30
|
+
* shared key, and the snapshot never carries `pricing_v2`, so a shared key
|
|
31
|
+
* yields null → the caller synthesizes from the flat rate). Returns null when
|
|
32
|
+
* no richer shape is on file. Never guesses: absence is `base`-only downstream.
|
|
33
|
+
*/
|
|
34
|
+
export declare function getPricingV2(provider: ProviderId, model: string): ModelPricingV2 | null;
|
|
35
|
+
export declare function estimateCostUsd(pricing: ModelPricing, tokensIn: number, tokensOut: number, tokensCached: number,
|
|
36
|
+
/** Cache-CREATION (write) tokens — a subset of tokensIn, WS-A (spec §4.1).
|
|
37
|
+
* Defaults to 0: with a zero write the whole expression collapses to the
|
|
38
|
+
* pre-WS-A formula BYTE-IDENTICALLY (the regression pin), so every existing
|
|
39
|
+
* caller and stored cost is unchanged. */
|
|
40
|
+
tokensCacheWrite?: number,
|
|
41
|
+
/** 1h-TTL portion of the write (bills at the higher multiplier when known). */
|
|
42
|
+
tokensCacheWrite1h?: number): number;
|
|
19
43
|
//# sourceMappingURL=pricing.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pricing.d.ts","sourceRoot":"","sources":["../../src/registry/pricing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"pricing.d.ts","sourceRoot":"","sources":["../../src/registry/pricing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEtD,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7C;;uEAEmE;IACnE,QAAQ,CAAC,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5C;;sEAEkE;IAClE,QAAQ,CAAC,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/C;AAyDD,wBAAgB,UAAU,CAAC,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CA6BnF;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAYvF;AAED,wBAAgB,eAAe,CAC7B,OAAO,EAAE,YAAY,EACrB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM;AACpB;;;0CAG0C;AAC1C,gBAAgB,SAAI;AACpB,+EAA+E;AAC/E,kBAAkB,SAAI,GACrB,MAAM,CAsBR"}
|
package/dist/registry/pricing.js
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
13
|
exports.getPricing = getPricing;
|
|
14
|
+
exports.getPricingV2 = getPricingV2;
|
|
14
15
|
exports.estimateCostUsd = estimateCostUsd;
|
|
15
16
|
const node_fs_1 = require("node:fs");
|
|
16
17
|
const node_path_1 = require("node:path");
|
|
@@ -30,10 +31,22 @@ const KEY_PREFIXES = {
|
|
|
30
31
|
fireworks: ["fireworks_ai/accounts/fireworks/models/", "fireworks_ai/"],
|
|
31
32
|
};
|
|
32
33
|
let cachedMap = null;
|
|
34
|
+
/** Host-swept gap-filler (scripts/pricing-sweep.ts): prices for models the
|
|
35
|
+
* pinned LiteLLM snapshot has not caught up to. Merged BENEATH the snapshot —
|
|
36
|
+
* the snapshot wins on any shared key (stability); the overlay only fills gaps.
|
|
37
|
+
* Absent file ⇒ no overlay, unchanged behaviour. */
|
|
38
|
+
function loadOverlay(dataDir) {
|
|
39
|
+
const path = (0, node_path_1.join)(dataDir, "pricing-overlay.json");
|
|
40
|
+
if (!(0, node_fs_1.existsSync)(path))
|
|
41
|
+
return {};
|
|
42
|
+
const parsed = JSON.parse((0, node_fs_1.readFileSync)(path, "utf8"));
|
|
43
|
+
return parsed.prices ?? {};
|
|
44
|
+
}
|
|
33
45
|
function loadMap() {
|
|
34
46
|
if (cachedMap === null) {
|
|
35
|
-
const
|
|
36
|
-
|
|
47
|
+
const dataDir = (0, node_path_1.join)(__dirname, "..", "..", "data");
|
|
48
|
+
const snapshot = JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(dataDir, "pricing-map.json"), "utf8"));
|
|
49
|
+
cachedMap = { ...loadOverlay(dataDir), ...snapshot };
|
|
37
50
|
}
|
|
38
51
|
return cachedMap;
|
|
39
52
|
}
|
|
@@ -52,18 +65,63 @@ function getPricing(provider, model) {
|
|
|
52
65
|
cachedInputUsdPerTok: typeof entry.cache_read_input_token_cost === "number"
|
|
53
66
|
? entry.cache_read_input_token_cost
|
|
54
67
|
: null,
|
|
68
|
+
cacheWriteUsdPerTok: typeof entry.cache_creation_input_token_cost === "number"
|
|
69
|
+
? entry.cache_creation_input_token_cost
|
|
70
|
+
: null,
|
|
71
|
+
cacheWrite1hUsdPerTok: typeof entry.cache_creation_input_token_cost_above_1hr === "number"
|
|
72
|
+
? entry.cache_creation_input_token_cost_above_1hr
|
|
73
|
+
: null,
|
|
55
74
|
};
|
|
56
75
|
}
|
|
57
76
|
}
|
|
58
77
|
return null;
|
|
59
78
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
79
|
+
/**
|
|
80
|
+
* The richer `ModelPricingV2` a vendor overlay/manual entry carries, if any —
|
|
81
|
+
* resolved by the SAME key precedence as {@link getPricing} (snapshot wins on a
|
|
82
|
+
* shared key, and the snapshot never carries `pricing_v2`, so a shared key
|
|
83
|
+
* yields null → the caller synthesizes from the flat rate). Returns null when
|
|
84
|
+
* no richer shape is on file. Never guesses: absence is `base`-only downstream.
|
|
85
|
+
*/
|
|
86
|
+
function getPricingV2(provider, model) {
|
|
87
|
+
if (model === "")
|
|
88
|
+
return null;
|
|
89
|
+
const map = loadMap();
|
|
90
|
+
for (const prefix of KEY_PREFIXES[provider]) {
|
|
91
|
+
const entry = map[`${prefix}${model}`];
|
|
92
|
+
if (entry !== undefined && typeof entry.input_cost_per_token === "number") {
|
|
93
|
+
// Resolve on the same entry getPricing would pick; only that entry's
|
|
94
|
+
// pricing_v2 counts (a later-prefix match must not shadow it).
|
|
95
|
+
return entry.pricing_v2 ?? null;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
function estimateCostUsd(pricing, tokensIn, tokensOut, tokensCached,
|
|
101
|
+
/** Cache-CREATION (write) tokens — a subset of tokensIn, WS-A (spec §4.1).
|
|
102
|
+
* Defaults to 0: with a zero write the whole expression collapses to the
|
|
103
|
+
* pre-WS-A formula BYTE-IDENTICALLY (the regression pin), so every existing
|
|
104
|
+
* caller and stored cost is unchanged. */
|
|
105
|
+
tokensCacheWrite = 0,
|
|
106
|
+
/** 1h-TTL portion of the write (bills at the higher multiplier when known). */
|
|
107
|
+
tokensCacheWrite1h = 0) {
|
|
108
|
+
// Providers report tokensCached and tokensCacheWrite as subsets of tokensIn;
|
|
109
|
+
// bill each at its rate, the remainder at the input rate, never negatively.
|
|
63
110
|
const cached = Math.min(Math.max(tokensCached, 0), Math.max(tokensIn, tokensCached));
|
|
64
|
-
const
|
|
111
|
+
const write = Math.max(tokensCacheWrite, 0);
|
|
112
|
+
const write1h = Math.min(Math.max(tokensCacheWrite1h, 0), write);
|
|
113
|
+
// uncached subtracts BOTH cache buckets. With write === 0 this is exactly the
|
|
114
|
+
// former `max(tokensIn − cached, 0)`, so a zero-write call is unchanged.
|
|
115
|
+
const uncachedIn = Math.max(tokensIn - cached - write, 0);
|
|
65
116
|
const cachedRate = pricing.cachedInputUsdPerTok ?? pricing.inputUsdPerTok;
|
|
117
|
+
// L5 fail-closed: an unverified write rate degrades to the INPUT rate (1.0×),
|
|
118
|
+
// never a guessed premium; the 1h rate degrades to the 5m write rate, then to
|
|
119
|
+
// input. Below-min / non-cache-write callers pass 0 and touch none of this.
|
|
120
|
+
const writeRate = pricing.cacheWriteUsdPerTok ?? pricing.inputUsdPerTok;
|
|
121
|
+
const write1hRate = pricing.cacheWrite1hUsdPerTok ?? writeRate;
|
|
66
122
|
return (uncachedIn * pricing.inputUsdPerTok +
|
|
67
123
|
cached * cachedRate +
|
|
124
|
+
(write - write1h) * writeRate +
|
|
125
|
+
write1h * write1hRate +
|
|
68
126
|
Math.max(tokensOut, 0) * pricing.outputUsdPerTok);
|
|
69
127
|
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hierarchical bootstrap CI — RATIFIED PER THE ERRATUM (stop2-architect-review
|
|
3
|
+
* §1): per rep, (1) resample fixtures within the subtype with replacement,
|
|
4
|
+
* then (2) ONE resample of each (model, fixture)'s samples, used consistently
|
|
5
|
+
* across ALL of that model's comparisons in the rep (NOT per model-pair — the
|
|
6
|
+
* archived prototype's per-pair form injects extra noise and is superseded).
|
|
7
|
+
* ≥200 reps; 2.5/97.5 percentiles. RNG is seeded and injectable so a fixed
|
|
8
|
+
* seed reproduces scores and tiers exactly.
|
|
9
|
+
*
|
|
10
|
+
* Any change to the resampling scheme re-opens STOP-2.
|
|
11
|
+
*/
|
|
12
|
+
import type { SubtypeSamples } from "./types";
|
|
13
|
+
export declare const BOOTSTRAP_REPS = 200;
|
|
14
|
+
export declare const CI_LO = 0.025;
|
|
15
|
+
export declare const CI_HI = 0.975;
|
|
16
|
+
/** Deterministic PRNG (mulberry32) — seedable, dependency-free. */
|
|
17
|
+
export declare function mulberry32(seed: number): () => number;
|
|
18
|
+
/**
|
|
19
|
+
* The per-rep resampling plan, exposed for the determinism test family (f):
|
|
20
|
+
* one fixture multiset draw + exactly ONE per-(model, fixture) sample
|
|
21
|
+
* resample, keyed so the same array object serves every comparison the model
|
|
22
|
+
* enters that rep.
|
|
23
|
+
*/
|
|
24
|
+
export declare function drawRep(samples: SubtypeSamples, fixtures: readonly string[], rng: () => number): {
|
|
25
|
+
readonly fixtureDraws: readonly string[];
|
|
26
|
+
readonly resampled: SubtypeSamples;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Bootstrap CIs for one subtype's anchored scores. Returns modelKey →
|
|
30
|
+
* [2.5th, 97.5th] percentile of the rep RigIndex distribution. A rep where the
|
|
31
|
+
* basket cannot anchor (all basket members drew empty) is skipped — with the
|
|
32
|
+
* probe corpus every model has every fixture, so this is a degenerate-input
|
|
33
|
+
* guard, not a data path.
|
|
34
|
+
*/
|
|
35
|
+
export declare function bootstrapCis(samples: SubtypeSamples, basket: readonly string[], reps: number, rng: () => number): Record<string, readonly [number, number]>;
|
|
36
|
+
//# sourceMappingURL=bootstrap.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../../src/rigindex/bootstrap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,KAAK,EAAgB,cAAc,EAAE,MAAM,SAAS,CAAC;AAE5D,eAAO,MAAM,cAAc,MAAM,CAAC;AAClC,eAAO,MAAM,KAAK,QAAQ,CAAC;AAC3B,eAAO,MAAM,KAAK,QAAQ,CAAC;AAE3B,mEAAmE;AACnE,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,MAAM,CASrD;AAOD;;;;;GAKG;AACH,wBAAgB,OAAO,CACrB,OAAO,EAAE,cAAc,EACvB,QAAQ,EAAE,SAAS,MAAM,EAAE,EAC3B,GAAG,EAAE,MAAM,MAAM,GAChB;IACD,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC,QAAQ,CAAC,SAAS,EAAE,cAAc,CAAC;CACpC,CAYA;AAWD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,cAAc,EACvB,MAAM,EAAE,SAAS,MAAM,EAAE,EACzB,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,MAAM,GAChB,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAsB3C"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Hierarchical bootstrap CI — RATIFIED PER THE ERRATUM (stop2-architect-review
|
|
4
|
+
* §1): per rep, (1) resample fixtures within the subtype with replacement,
|
|
5
|
+
* then (2) ONE resample of each (model, fixture)'s samples, used consistently
|
|
6
|
+
* across ALL of that model's comparisons in the rep (NOT per model-pair — the
|
|
7
|
+
* archived prototype's per-pair form injects extra noise and is superseded).
|
|
8
|
+
* ≥200 reps; 2.5/97.5 percentiles. RNG is seeded and injectable so a fixed
|
|
9
|
+
* seed reproduces scores and tiers exactly.
|
|
10
|
+
*
|
|
11
|
+
* Any change to the resampling scheme re-opens STOP-2.
|
|
12
|
+
*/
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.CI_HI = exports.CI_LO = exports.BOOTSTRAP_REPS = void 0;
|
|
15
|
+
exports.mulberry32 = mulberry32;
|
|
16
|
+
exports.drawRep = drawRep;
|
|
17
|
+
exports.bootstrapCis = bootstrapCis;
|
|
18
|
+
const graph_1 = require("./graph");
|
|
19
|
+
const fit_1 = require("./fit");
|
|
20
|
+
exports.BOOTSTRAP_REPS = 200;
|
|
21
|
+
exports.CI_LO = 0.025;
|
|
22
|
+
exports.CI_HI = 0.975;
|
|
23
|
+
/** Deterministic PRNG (mulberry32) — seedable, dependency-free. */
|
|
24
|
+
function mulberry32(seed) {
|
|
25
|
+
let a = seed >>> 0;
|
|
26
|
+
return () => {
|
|
27
|
+
a = (a + 0x6d2b79f5) >>> 0;
|
|
28
|
+
let t = a;
|
|
29
|
+
t = Math.imul(t ^ (t >>> 15), t | 1);
|
|
30
|
+
t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
|
|
31
|
+
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/** One with-replacement resample of `list`, same length. */
|
|
35
|
+
function resample(list, rng) {
|
|
36
|
+
return list.map(() => list[Math.floor(rng() * list.length)]);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* The per-rep resampling plan, exposed for the determinism test family (f):
|
|
40
|
+
* one fixture multiset draw + exactly ONE per-(model, fixture) sample
|
|
41
|
+
* resample, keyed so the same array object serves every comparison the model
|
|
42
|
+
* enters that rep.
|
|
43
|
+
*/
|
|
44
|
+
function drawRep(samples, fixtures, rng) {
|
|
45
|
+
const fixtureDraws = resample(fixtures, rng);
|
|
46
|
+
// ONE resample per (model, fixture) — iterate in stable sorted order so a
|
|
47
|
+
// fixed seed reproduces the plan exactly.
|
|
48
|
+
const resampled = {};
|
|
49
|
+
for (const model of Object.keys(samples).sort()) {
|
|
50
|
+
resampled[model] = {};
|
|
51
|
+
for (const fixtureId of Object.keys(samples[model]).sort()) {
|
|
52
|
+
resampled[model][fixtureId] = resample(samples[model][fixtureId], rng);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return { fixtureDraws, resampled };
|
|
56
|
+
}
|
|
57
|
+
function percentile(sorted, q) {
|
|
58
|
+
if (sorted.length === 0)
|
|
59
|
+
return NaN;
|
|
60
|
+
const idx = q * (sorted.length - 1);
|
|
61
|
+
const lo = Math.floor(idx);
|
|
62
|
+
const hi = Math.ceil(idx);
|
|
63
|
+
if (lo === hi)
|
|
64
|
+
return sorted[lo];
|
|
65
|
+
return sorted[lo] + (sorted[hi] - sorted[lo]) * (idx - lo);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Bootstrap CIs for one subtype's anchored scores. Returns modelKey →
|
|
69
|
+
* [2.5th, 97.5th] percentile of the rep RigIndex distribution. A rep where the
|
|
70
|
+
* basket cannot anchor (all basket members drew empty) is skipped — with the
|
|
71
|
+
* probe corpus every model has every fixture, so this is a degenerate-input
|
|
72
|
+
* guard, not a data path.
|
|
73
|
+
*/
|
|
74
|
+
function bootstrapCis(samples, basket, reps, rng) {
|
|
75
|
+
const models = Object.keys(samples).sort();
|
|
76
|
+
const fixtures = [...new Set(models.flatMap((m) => Object.keys(samples[m])))].sort();
|
|
77
|
+
const draws = Object.fromEntries(models.map((m) => [m, []]));
|
|
78
|
+
for (let rep = 0; rep < reps; rep += 1) {
|
|
79
|
+
const { fixtureDraws, resampled } = drawRep(samples, fixtures, rng);
|
|
80
|
+
const graph = (0, graph_1.buildSubtypeGraph)(resampled, fixtureDraws);
|
|
81
|
+
const scores = (0, fit_1.anchorScores)((0, fit_1.fitBradleyTerry)(graph), basket);
|
|
82
|
+
if (scores === null)
|
|
83
|
+
continue;
|
|
84
|
+
for (const m of models) {
|
|
85
|
+
if (scores[m] !== undefined)
|
|
86
|
+
draws[m].push(scores[m]);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
const out = {};
|
|
90
|
+
for (const m of models) {
|
|
91
|
+
const sorted = [...draws[m]].sort((a, b) => a - b);
|
|
92
|
+
if (sorted.length === 0)
|
|
93
|
+
continue;
|
|
94
|
+
out[m] = [percentile(sorted, exports.CI_LO), percentile(sorted, exports.CI_HI)];
|
|
95
|
+
}
|
|
96
|
+
return out;
|
|
97
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bradley-Terry fit + frontier anchor — RATIFIED (stop2-architect-review §1):
|
|
3
|
+
* Hunter's MM algorithm, 400 iterations or convergence, symmetric 0.01
|
|
4
|
+
* pseudo-wins per ordered pair (keeps saturated all-tie graphs finite and the
|
|
5
|
+
* graph connected), geometric-mean-normalized per iteration. Anchor:
|
|
6
|
+
* RigIndex_i = 100 × p_i / GM(basket strengths) — scores >100 are expected
|
|
7
|
+
* ("above the frontier average").
|
|
8
|
+
*
|
|
9
|
+
* Any change to the solver, regularization, or anchor re-opens STOP-2.
|
|
10
|
+
*/
|
|
11
|
+
import type { SubtypeGraph } from "./types";
|
|
12
|
+
export declare const MM_MAX_ITERS = 400;
|
|
13
|
+
export declare const MM_CONVERGENCE = 1e-10;
|
|
14
|
+
export declare const PSEUDO_WINS = 0.01;
|
|
15
|
+
/** Fit BT strengths over the graph's models. Returns modelKey → p, GM-normalized
|
|
16
|
+
* to 1. Deterministic — no randomness in the fit. */
|
|
17
|
+
export declare function fitBradleyTerry(graph: SubtypeGraph): Record<string, number>;
|
|
18
|
+
/** Geometric mean of the basket members' strengths, over the members present
|
|
19
|
+
* in the fit. Null when NO basket member is in the graph — the subtype cannot
|
|
20
|
+
* be anchored (and must not publish a score). */
|
|
21
|
+
export declare function basketGeometricMean(strengths: Readonly<Record<string, number>>, basket: readonly string[]): number | null;
|
|
22
|
+
/** RigIndex_i = 100 × p_i / GM(basket) (review §1). Null when unanchorable. */
|
|
23
|
+
export declare function anchorScores(strengths: Readonly<Record<string, number>>, basket: readonly string[]): Record<string, number> | null;
|
|
24
|
+
//# sourceMappingURL=fit.d.ts.map
|