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