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.
Files changed (310) hide show
  1. package/CHANGELOG.md +158 -0
  2. package/README.md +53 -11
  3. package/data/PROVENANCE.md +19 -0
  4. package/data/pricing-manual.json +22 -0
  5. package/data/pricing-map.json +46362 -0
  6. package/data/pricing-overlay.json +419 -0
  7. package/dist/adapters/anthropic.d.ts +50 -6
  8. package/dist/adapters/anthropic.d.ts.map +1 -1
  9. package/dist/adapters/anthropic.js +123 -29
  10. package/dist/adapters/build-adapters.d.ts +11 -0
  11. package/dist/adapters/build-adapters.d.ts.map +1 -0
  12. package/dist/adapters/build-adapters.js +45 -0
  13. package/dist/adapters/deepseek.d.ts +6 -0
  14. package/dist/adapters/deepseek.d.ts.map +1 -1
  15. package/dist/adapters/deepseek.js +54 -1
  16. package/dist/adapters/gemini.d.ts +10 -0
  17. package/dist/adapters/gemini.d.ts.map +1 -1
  18. package/dist/adapters/gemini.js +78 -7
  19. package/dist/adapters/grok.d.ts +9 -0
  20. package/dist/adapters/grok.d.ts.map +1 -1
  21. package/dist/adapters/grok.js +67 -3
  22. package/dist/adapters/openai-compat.d.ts +6 -0
  23. package/dist/adapters/openai-compat.d.ts.map +1 -1
  24. package/dist/adapters/openai-compat.js +58 -1
  25. package/dist/adapters/openai-stream.d.ts +58 -0
  26. package/dist/adapters/openai-stream.d.ts.map +1 -0
  27. package/dist/adapters/openai-stream.js +120 -0
  28. package/dist/adapters/openai.d.ts +6 -0
  29. package/dist/adapters/openai.d.ts.map +1 -1
  30. package/dist/adapters/openai.js +60 -1
  31. package/dist/adapters/sampling.d.ts +28 -0
  32. package/dist/adapters/sampling.d.ts.map +1 -0
  33. package/dist/adapters/sampling.js +34 -0
  34. package/dist/adapters/tool-mapping.d.ts +92 -0
  35. package/dist/adapters/tool-mapping.d.ts.map +1 -0
  36. package/dist/adapters/tool-mapping.js +143 -0
  37. package/dist/artifacts/artifact.d.ts +137 -0
  38. package/dist/artifacts/artifact.d.ts.map +1 -0
  39. package/dist/artifacts/artifact.js +377 -0
  40. package/dist/artifacts/content-uploader.d.ts +87 -0
  41. package/dist/artifacts/content-uploader.d.ts.map +1 -0
  42. package/dist/artifacts/content-uploader.js +124 -0
  43. package/dist/artifacts/index.d.ts +63 -0
  44. package/dist/artifacts/index.d.ts.map +1 -0
  45. package/dist/artifacts/index.js +80 -0
  46. package/dist/artifacts/run-context.d.ts +129 -0
  47. package/dist/artifacts/run-context.d.ts.map +1 -0
  48. package/dist/artifacts/run-context.js +208 -0
  49. package/dist/artifacts/scrub.d.ts +60 -0
  50. package/dist/artifacts/scrub.d.ts.map +1 -0
  51. package/dist/artifacts/scrub.js +139 -0
  52. package/dist/artifacts/step.d.ts +26 -0
  53. package/dist/artifacts/step.d.ts.map +1 -0
  54. package/dist/artifacts/step.js +37 -0
  55. package/dist/artifacts/taint.d.ts +63 -0
  56. package/dist/artifacts/taint.d.ts.map +1 -0
  57. package/dist/artifacts/taint.js +76 -0
  58. package/dist/bakeoff/cache-sim.d.ts +99 -0
  59. package/dist/bakeoff/cache-sim.d.ts.map +1 -0
  60. package/dist/bakeoff/cache-sim.js +126 -0
  61. package/dist/bakeoff/eval-cases.d.ts +96 -0
  62. package/dist/bakeoff/eval-cases.d.ts.map +1 -0
  63. package/dist/bakeoff/eval-cases.js +105 -0
  64. package/dist/bakeoff/report.d.ts +41 -0
  65. package/dist/bakeoff/report.d.ts.map +1 -0
  66. package/dist/bakeoff/report.js +142 -0
  67. package/dist/bakeoff/samples.d.ts +15 -0
  68. package/dist/bakeoff/samples.d.ts.map +1 -1
  69. package/dist/bakeoff/samples.js +20 -0
  70. package/dist/cli.d.ts +1 -3
  71. package/dist/cli.d.ts.map +1 -1
  72. package/dist/cli.js +134 -116
  73. package/dist/config.d.ts +100 -0
  74. package/dist/config.d.ts.map +1 -1
  75. package/dist/config.js +104 -0
  76. package/dist/deprecations.d.ts +32 -0
  77. package/dist/deprecations.d.ts.map +1 -0
  78. package/dist/deprecations.js +59 -0
  79. package/dist/gateway/http-protocol.d.ts +175 -0
  80. package/dist/gateway/http-protocol.d.ts.map +1 -0
  81. package/dist/gateway/http-protocol.js +105 -0
  82. package/dist/index.d.ts +106 -19
  83. package/dist/index.d.ts.map +1 -1
  84. package/dist/index.js +266 -138
  85. package/dist/init/finder.d.ts +15 -0
  86. package/dist/init/finder.d.ts.map +1 -1
  87. package/dist/init/finder.js +46 -0
  88. package/dist/init/init-cli.d.ts +10 -0
  89. package/dist/init/init-cli.d.ts.map +1 -0
  90. package/dist/init/init-cli.js +86 -0
  91. package/dist/init/observe-cli.d.ts +19 -0
  92. package/dist/init/observe-cli.d.ts.map +1 -0
  93. package/dist/init/observe-cli.js +73 -0
  94. package/dist/init/observe.d.ts +81 -0
  95. package/dist/init/observe.d.ts.map +1 -0
  96. package/dist/init/observe.js +245 -0
  97. package/dist/registry/build.d.ts +94 -1
  98. package/dist/registry/build.d.ts.map +1 -1
  99. package/dist/registry/build.js +125 -4
  100. package/dist/registry/cache-policy.d.ts +94 -0
  101. package/dist/registry/cache-policy.d.ts.map +1 -0
  102. package/dist/registry/cache-policy.js +238 -0
  103. package/dist/registry/call-notes.d.ts.map +1 -1
  104. package/dist/registry/call-notes.js +40 -2
  105. package/dist/registry/effective-rate.d.ts +151 -0
  106. package/dist/registry/effective-rate.d.ts.map +1 -0
  107. package/dist/registry/effective-rate.js +156 -0
  108. package/dist/registry/facts.d.ts.map +1 -1
  109. package/dist/registry/facts.js +16 -0
  110. package/dist/registry/parity.d.ts +26 -0
  111. package/dist/registry/parity.d.ts.map +1 -1
  112. package/dist/registry/parity.js +43 -2
  113. package/dist/registry/pricing-shape.d.ts +113 -0
  114. package/dist/registry/pricing-shape.d.ts.map +1 -0
  115. package/dist/registry/pricing-shape.js +123 -0
  116. package/dist/registry/pricing.d.ts +25 -1
  117. package/dist/registry/pricing.d.ts.map +1 -1
  118. package/dist/registry/pricing.js +64 -6
  119. package/dist/rigindex/bootstrap.d.ts +36 -0
  120. package/dist/rigindex/bootstrap.d.ts.map +1 -0
  121. package/dist/rigindex/bootstrap.js +97 -0
  122. package/dist/rigindex/fit.d.ts +24 -0
  123. package/dist/rigindex/fit.d.ts.map +1 -0
  124. package/dist/rigindex/fit.js +76 -0
  125. package/dist/rigindex/gates.d.ts +52 -0
  126. package/dist/rigindex/gates.d.ts.map +1 -0
  127. package/dist/rigindex/gates.js +109 -0
  128. package/dist/rigindex/graph.d.ts +31 -0
  129. package/dist/rigindex/graph.d.ts.map +1 -0
  130. package/dist/rigindex/graph.js +120 -0
  131. package/dist/rigindex/index.d.ts +23 -0
  132. package/dist/rigindex/index.d.ts.map +1 -0
  133. package/dist/rigindex/index.js +112 -0
  134. package/dist/rigindex/types.d.ts +76 -0
  135. package/dist/rigindex/types.d.ts.map +1 -0
  136. package/dist/rigindex/types.js +8 -0
  137. package/dist/routes/cache-lint.d.ts +41 -0
  138. package/dist/routes/cache-lint.d.ts.map +1 -0
  139. package/dist/routes/cache-lint.js +81 -0
  140. package/dist/routes/loader.d.ts +48 -0
  141. package/dist/routes/loader.d.ts.map +1 -1
  142. package/dist/routes/loader.js +167 -0
  143. package/dist/routes/resolved-bundle.d.ts +79 -0
  144. package/dist/routes/resolved-bundle.d.ts.map +1 -0
  145. package/dist/routes/resolved-bundle.js +148 -0
  146. package/dist/routes/sampling-config.d.ts +32 -0
  147. package/dist/routes/sampling-config.d.ts.map +1 -0
  148. package/dist/routes/sampling-config.js +91 -0
  149. package/dist/run/ajv.d.ts +22 -0
  150. package/dist/run/ajv.d.ts.map +1 -0
  151. package/dist/run/ajv.js +32 -0
  152. package/dist/run/cache-handle.d.ts +58 -0
  153. package/dist/run/cache-handle.d.ts.map +1 -0
  154. package/dist/run/cache-handle.js +54 -0
  155. package/dist/run/cache-stamp.d.ts +65 -0
  156. package/dist/run/cache-stamp.d.ts.map +1 -0
  157. package/dist/run/cache-stamp.js +0 -0
  158. package/dist/run/capture-write.d.ts +33 -0
  159. package/dist/run/capture-write.d.ts.map +1 -0
  160. package/dist/run/capture-write.js +55 -0
  161. package/dist/run/cost.d.ts.map +1 -1
  162. package/dist/run/cost.js +1 -1
  163. package/dist/run/dispatch.d.ts +99 -0
  164. package/dist/run/dispatch.d.ts.map +1 -0
  165. package/dist/run/dispatch.js +191 -0
  166. package/dist/run/raw.d.ts +130 -0
  167. package/dist/run/raw.d.ts.map +1 -0
  168. package/dist/run/raw.js +363 -0
  169. package/dist/run/record-attempt.d.ts +40 -0
  170. package/dist/run/record-attempt.d.ts.map +1 -0
  171. package/dist/run/record-attempt.js +99 -0
  172. package/dist/run/resolve.d.ts +75 -2
  173. package/dist/run/resolve.d.ts.map +1 -1
  174. package/dist/run/resolve.js +126 -4
  175. package/dist/run/run.d.ts +14 -0
  176. package/dist/run/run.d.ts.map +1 -1
  177. package/dist/run/run.js +0 -0
  178. package/dist/run/stream.d.ts +49 -0
  179. package/dist/run/stream.d.ts.map +1 -0
  180. package/dist/run/stream.js +87 -0
  181. package/dist/run/validate.d.ts.map +1 -1
  182. package/dist/run/validate.js +6 -7
  183. package/dist/savings/cache-ledger.d.ts +108 -0
  184. package/dist/savings/cache-ledger.d.ts.map +1 -0
  185. package/dist/savings/cache-ledger.js +174 -0
  186. package/dist/savings/cache-reconcile.d.ts +64 -0
  187. package/dist/savings/cache-reconcile.d.ts.map +1 -0
  188. package/dist/savings/cache-reconcile.js +59 -0
  189. package/dist/savings/cache-stats.d.ts +63 -0
  190. package/dist/savings/cache-stats.d.ts.map +1 -0
  191. package/dist/savings/cache-stats.js +108 -0
  192. package/dist/savings/emit.d.ts +13 -0
  193. package/dist/savings/emit.d.ts.map +1 -1
  194. package/dist/savings/emit.js +25 -0
  195. package/dist/savings/swap-execute.d.ts +14 -0
  196. package/dist/savings/swap-execute.d.ts.map +1 -1
  197. package/dist/savings/swap-execute.js +44 -1
  198. package/dist/savings/swaps-client.d.ts +14 -0
  199. package/dist/savings/swaps-client.d.ts.map +1 -1
  200. package/dist/savings/swaps-client.js +16 -2
  201. package/dist/settings/api-fetcher.d.ts +39 -0
  202. package/dist/settings/api-fetcher.d.ts.map +1 -0
  203. package/dist/settings/api-fetcher.js +92 -0
  204. package/dist/settings/index.d.ts +10 -0
  205. package/dist/settings/index.d.ts.map +1 -0
  206. package/dist/settings/index.js +15 -0
  207. package/dist/settings/task-settings.d.ts +91 -0
  208. package/dist/settings/task-settings.d.ts.map +1 -0
  209. package/dist/settings/task-settings.js +116 -0
  210. package/dist/status.d.ts +77 -0
  211. package/dist/status.d.ts.map +1 -0
  212. package/dist/status.js +113 -0
  213. package/dist/telemetry/artifact-store.d.ts +48 -0
  214. package/dist/telemetry/artifact-store.d.ts.map +1 -0
  215. package/dist/telemetry/artifact-store.js +189 -0
  216. package/dist/telemetry/cache-miss-streak.d.ts +79 -0
  217. package/dist/telemetry/cache-miss-streak.d.ts.map +1 -0
  218. package/dist/telemetry/cache-miss-streak.js +99 -0
  219. package/dist/telemetry/capture.d.ts +3 -0
  220. package/dist/telemetry/capture.d.ts.map +1 -1
  221. package/dist/telemetry/capture.js +15 -8
  222. package/dist/telemetry/exporter-setup.d.ts +28 -0
  223. package/dist/telemetry/exporter-setup.d.ts.map +1 -0
  224. package/dist/telemetry/exporter-setup.js +34 -0
  225. package/dist/telemetry/exporter.d.ts +75 -0
  226. package/dist/telemetry/exporter.d.ts.map +1 -1
  227. package/dist/telemetry/exporter.js +324 -47
  228. package/dist/telemetry/health.d.ts +76 -0
  229. package/dist/telemetry/health.d.ts.map +1 -0
  230. package/dist/telemetry/health.js +92 -0
  231. package/dist/telemetry/ingest-protocol.d.ts +152 -3
  232. package/dist/telemetry/ingest-protocol.d.ts.map +1 -1
  233. package/dist/telemetry/ingest-protocol.js +204 -4
  234. package/dist/telemetry/load-error-report.d.ts +24 -0
  235. package/dist/telemetry/load-error-report.d.ts.map +1 -0
  236. package/dist/telemetry/load-error-report.js +50 -0
  237. package/dist/telemetry/otel-map.d.ts +121 -0
  238. package/dist/telemetry/otel-map.d.ts.map +1 -0
  239. package/dist/telemetry/otel-map.js +224 -0
  240. package/dist/telemetry/otel-normalize.d.ts +104 -0
  241. package/dist/telemetry/otel-normalize.d.ts.map +1 -0
  242. package/dist/telemetry/otel-normalize.js +530 -0
  243. package/dist/telemetry/otlp-emitter.d.ts +52 -0
  244. package/dist/telemetry/otlp-emitter.d.ts.map +1 -0
  245. package/dist/telemetry/otlp-emitter.js +144 -0
  246. package/dist/telemetry/otlp-proto.d.ts +29 -0
  247. package/dist/telemetry/otlp-proto.d.ts.map +1 -0
  248. package/dist/telemetry/otlp-proto.js +266 -0
  249. package/dist/telemetry/sinks.d.ts +37 -1
  250. package/dist/telemetry/sinks.d.ts.map +1 -1
  251. package/dist/telemetry/sinks.js +121 -30
  252. package/dist/telemetry/store.d.ts +28 -1
  253. package/dist/telemetry/store.d.ts.map +1 -1
  254. package/dist/telemetry/store.js +218 -3
  255. package/dist/tenancy/api-key-format.d.ts +15 -5
  256. package/dist/tenancy/api-key-format.d.ts.map +1 -1
  257. package/dist/tenancy/api-key-format.js +24 -5
  258. package/dist/types/config-teaching.d.ts +62 -0
  259. package/dist/types/config-teaching.d.ts.map +1 -0
  260. package/dist/types/config-teaching.js +183 -0
  261. package/dist/types/provider.d.ts +147 -1
  262. package/dist/types/provider.d.ts.map +1 -1
  263. package/dist/types/provider.js +21 -1
  264. package/dist/types/route.d.ts +79 -1
  265. package/dist/types/route.d.ts.map +1 -1
  266. package/dist/types/telemetry.d.ts +117 -0
  267. package/dist/types/telemetry.d.ts.map +1 -1
  268. package/dist/validate-cli.d.ts +12 -0
  269. package/dist/validate-cli.d.ts.map +1 -0
  270. package/dist/validate-cli.js +57 -0
  271. package/dist/verify/capture.d.ts +66 -0
  272. package/dist/verify/capture.d.ts.map +1 -0
  273. package/dist/verify/capture.js +180 -0
  274. package/dist/verify/cli-run.d.ts +23 -0
  275. package/dist/verify/cli-run.d.ts.map +1 -0
  276. package/dist/verify/cli-run.js +57 -0
  277. package/dist/verify/diff.d.ts +48 -0
  278. package/dist/verify/diff.d.ts.map +1 -0
  279. package/dist/verify/diff.js +157 -0
  280. package/dist/verify/index.d.ts +17 -0
  281. package/dist/verify/index.d.ts.map +1 -0
  282. package/dist/verify/index.js +24 -0
  283. package/dist/verify/report.d.ts +14 -0
  284. package/dist/verify/report.d.ts.map +1 -0
  285. package/dist/verify/report.js +88 -0
  286. package/dist/verify/types.d.ts +101 -0
  287. package/dist/verify/types.d.ts.map +1 -0
  288. package/dist/verify/types.js +17 -0
  289. package/dist/verify/verify.d.ts +29 -0
  290. package/dist/verify/verify.d.ts.map +1 -0
  291. package/dist/verify/verify.js +148 -0
  292. package/dist/watch/evaluate.d.ts +162 -3
  293. package/dist/watch/evaluate.d.ts.map +1 -1
  294. package/dist/watch/evaluate.js +61 -0
  295. package/dist/watch/monitor.d.ts +116 -0
  296. package/dist/watch/monitor.d.ts.map +1 -0
  297. package/dist/watch/monitor.js +199 -0
  298. package/dist/watch/proposals.d.ts +20 -4
  299. package/dist/watch/proposals.d.ts.map +1 -1
  300. package/dist/watch/proposals.js +31 -3
  301. package/dist/watch/run.d.ts +33 -0
  302. package/dist/watch/run.d.ts.map +1 -1
  303. package/dist/watch/run.js +39 -0
  304. package/package.json +7 -1
  305. package/registry/LICENSE +20 -0
  306. package/registry/leaderboard.json +3639 -0
  307. package/registry/registry.json +7263 -0
  308. package/dist/telemetry/supabase-exporter.d.ts +0 -64
  309. package/dist/telemetry/supabase-exporter.d.ts.map +0 -1
  310. 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"}
@@ -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":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,+BAA+B;IAC/B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,uEAAuE;IACvE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC;kFAC8E;IAC9E,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACzC;AAED,8DAA8D;AAC9D,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC;AAED,0DAA0D;AAC1D,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;CAC5B;AAED,0CAA0C;AAC1C,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3C;AAED,MAAM,WAAW,cAAc;IAC7B,0DAA0D;IAC1D,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,KAAK,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;IACrC,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,WAAW,EAAE,GAAG,IAAI,CAAC;IACvD,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxC,QAAQ,CAAC,QAAQ,CAAC,EAAE,aAAa,GAAG,IAAI,CAAC;IACzC,iDAAiD;IACjD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,8EAA8E;IAC9E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED;iFACiF;AACjF,eAAO,MAAM,cAAc,0CAAgC,CAAC;AAE5D;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,GAAG,IAAI,EACzB,IAAI,EAAE,MAAM,EACZ,MAAM,SAAqB,GAC1B,cAAc,CAWhB;AAED,MAAM,MAAM,eAAe,GAAG,UAAU,GAAG,MAAM,GAAG,WAAW,CAAC;AAMhE;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,eAAe,GAAG,UAAU,GAAG,IAAI,CAU3F;AAED;gFACgF;AAChF,MAAM,WAAW,gBAAgB;IAC/B,wEAAwE;IACxE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,yDAAyD;IACzD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,8EAA8E;IAC9E,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,wDAAwD;IACxD,QAAQ,CAAC,KAAK,EAAE,SAAS;QAAE,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACrF,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,2EAA2E;IAC3E,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CACnC;AAqBD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,cAAc,GAAG,gBAAgB,CAqC3E"}
@@ -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
- export declare function estimateCostUsd(pricing: ModelPricing, tokensIn: number, tokensOut: number, tokensCached: number): number;
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;AAEpD,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;CAC9C;AAmCD,wBAAgB,UAAU,CAAC,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAqBnF;AAED,wBAAgB,eAAe,CAC7B,OAAO,EAAE,YAAY,EACrB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,GACnB,MAAM,CAWR"}
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"}
@@ -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 raw = (0, node_fs_1.readFileSync)((0, node_path_1.join)(__dirname, "..", "..", "data", "pricing-map.json"), "utf8");
36
- cachedMap = JSON.parse(raw);
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
- function estimateCostUsd(pricing, tokensIn, tokensOut, tokensCached) {
61
- // Providers report tokensCached as a subset of tokensIn; bill the cached
62
- // part at the cached rate (input rate when none) and never negatively.
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 uncachedIn = Math.max(tokensIn - cached, 0);
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