modelrig 0.11.1 → 0.12.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 (182) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/dist/adapters/anthropic.d.ts +4 -4
  3. package/dist/adapters/anthropic.d.ts.map +1 -1
  4. package/dist/adapters/anthropic.js +8 -1
  5. package/dist/adapters/deepseek.d.ts +2 -4
  6. package/dist/adapters/deepseek.d.ts.map +1 -1
  7. package/dist/adapters/deepseek.js +9 -5
  8. package/dist/adapters/gemini.d.ts +4 -1
  9. package/dist/adapters/gemini.d.ts.map +1 -1
  10. package/dist/adapters/gemini.js +16 -1
  11. package/dist/adapters/grok.d.ts +2 -4
  12. package/dist/adapters/grok.d.ts.map +1 -1
  13. package/dist/adapters/grok.js +8 -4
  14. package/dist/adapters/history-mapping.d.ts +126 -0
  15. package/dist/adapters/history-mapping.d.ts.map +1 -0
  16. package/dist/adapters/history-mapping.js +230 -0
  17. package/dist/adapters/openai-compat.d.ts +2 -4
  18. package/dist/adapters/openai-compat.d.ts.map +1 -1
  19. package/dist/adapters/openai-compat.js +9 -5
  20. package/dist/adapters/openai.d.ts +2 -4
  21. package/dist/adapters/openai.d.ts.map +1 -1
  22. package/dist/adapters/openai.js +8 -4
  23. package/dist/adapters/responses-api.d.ts.map +1 -1
  24. package/dist/adapters/responses-api.js +9 -4
  25. package/dist/artifacts/artifact.d.ts.map +1 -1
  26. package/dist/artifacts/artifact.js +79 -0
  27. package/dist/artifacts/conversation.d.ts +128 -0
  28. package/dist/artifacts/conversation.d.ts.map +1 -0
  29. package/dist/artifacts/conversation.js +172 -0
  30. package/dist/artifacts/index.d.ts +1 -1
  31. package/dist/artifacts/index.d.ts.map +1 -1
  32. package/dist/artifacts/media.d.ts +46 -0
  33. package/dist/artifacts/media.d.ts.map +1 -0
  34. package/dist/artifacts/media.js +88 -0
  35. package/dist/artifacts/run-context.d.ts +61 -2
  36. package/dist/artifacts/run-context.d.ts.map +1 -1
  37. package/dist/artifacts/run-context.js +183 -12
  38. package/dist/artifacts/scrub.d.ts +3 -0
  39. package/dist/artifacts/scrub.d.ts.map +1 -1
  40. package/dist/bakeoff/engine.d.ts.map +1 -1
  41. package/dist/bakeoff/engine.js +34 -7
  42. package/dist/bakeoff/eval-cases.d.ts +5 -0
  43. package/dist/bakeoff/eval-cases.d.ts.map +1 -1
  44. package/dist/bakeoff/eval-cases.js +10 -1
  45. package/dist/bakeoff/replay.d.ts +15 -0
  46. package/dist/bakeoff/replay.d.ts.map +1 -1
  47. package/dist/bakeoff/replay.js +19 -1
  48. package/dist/bakeoff/report.d.ts.map +1 -1
  49. package/dist/bakeoff/report.js +9 -2
  50. package/dist/bakeoff/turn-replay.d.ts +93 -0
  51. package/dist/bakeoff/turn-replay.d.ts.map +1 -0
  52. package/dist/bakeoff/turn-replay.js +150 -0
  53. package/dist/bakeoff/types.d.ts +12 -0
  54. package/dist/bakeoff/types.d.ts.map +1 -1
  55. package/dist/feedback/grade.d.ts +7 -2
  56. package/dist/feedback/grade.d.ts.map +1 -1
  57. package/dist/feedback/grade.js +14 -0
  58. package/dist/feedback/outcome.d.ts +103 -0
  59. package/dist/feedback/outcome.d.ts.map +1 -0
  60. package/dist/feedback/outcome.js +175 -0
  61. package/dist/gateway/history-bridge.d.ts +32 -0
  62. package/dist/gateway/history-bridge.d.ts.map +1 -0
  63. package/dist/gateway/history-bridge.js +64 -0
  64. package/dist/gateway/serve-client.d.ts.map +1 -1
  65. package/dist/gateway/serve-client.js +6 -0
  66. package/dist/index.d.ts +44 -1
  67. package/dist/index.d.ts.map +1 -1
  68. package/dist/index.js +106 -6
  69. package/dist/init/observe.d.ts.map +1 -1
  70. package/dist/init/observe.js +3 -3
  71. package/dist/registry/build.d.ts +4 -0
  72. package/dist/registry/build.d.ts.map +1 -1
  73. package/dist/registry/generation-models.d.ts +68 -0
  74. package/dist/registry/generation-models.d.ts.map +1 -0
  75. package/dist/registry/generation-models.js +168 -0
  76. package/dist/registry/model-kind.d.ts +34 -0
  77. package/dist/registry/model-kind.d.ts.map +1 -0
  78. package/dist/registry/model-kind.js +40 -0
  79. package/dist/registry/pricing-shape.d.ts +29 -1
  80. package/dist/registry/pricing-shape.d.ts.map +1 -1
  81. package/dist/registry/pricing-shape.js +9 -0
  82. package/dist/registry/pricing.d.ts +26 -0
  83. package/dist/registry/pricing.d.ts.map +1 -1
  84. package/dist/registry/pricing.js +29 -0
  85. package/dist/registry/rows.d.ts.map +1 -1
  86. package/dist/registry/rows.js +3 -1
  87. package/dist/registry/unit-pricing.d.ts +32 -0
  88. package/dist/registry/unit-pricing.d.ts.map +1 -0
  89. package/dist/registry/unit-pricing.js +62 -0
  90. package/dist/routes/input-loader.d.ts +38 -0
  91. package/dist/routes/input-loader.d.ts.map +1 -0
  92. package/dist/routes/input-loader.js +80 -0
  93. package/dist/routes/loader.d.ts.map +1 -1
  94. package/dist/routes/loader.js +3 -0
  95. package/dist/routes/resolved-bundle.d.ts +2 -0
  96. package/dist/routes/resolved-bundle.d.ts.map +1 -1
  97. package/dist/routes/resolved-bundle.js +3 -0
  98. package/dist/run/cost.d.ts +28 -0
  99. package/dist/run/cost.d.ts.map +1 -1
  100. package/dist/run/cost.js +74 -0
  101. package/dist/run/dispatch.d.ts +4 -1
  102. package/dist/run/dispatch.d.ts.map +1 -1
  103. package/dist/run/dispatch.js +3 -0
  104. package/dist/run/limits.d.ts +88 -0
  105. package/dist/run/limits.d.ts.map +1 -0
  106. package/dist/run/limits.js +155 -0
  107. package/dist/run/messages.d.ts +199 -0
  108. package/dist/run/messages.d.ts.map +1 -0
  109. package/dist/run/messages.js +430 -0
  110. package/dist/run/raw-finalize.d.ts +5 -2
  111. package/dist/run/raw-finalize.d.ts.map +1 -1
  112. package/dist/run/raw-finalize.js +8 -5
  113. package/dist/run/raw-request.d.ts.map +1 -1
  114. package/dist/run/raw-request.js +2 -1
  115. package/dist/run/raw.d.ts +10 -4
  116. package/dist/run/raw.d.ts.map +1 -1
  117. package/dist/run/raw.js +11 -3
  118. package/dist/run/record-attempt.d.ts.map +1 -1
  119. package/dist/run/record-attempt.js +16 -6
  120. package/dist/run/record-call.d.ts +13 -2
  121. package/dist/run/record-call.d.ts.map +1 -1
  122. package/dist/run/record-call.js +50 -7
  123. package/dist/run/run.d.ts.map +1 -1
  124. package/dist/run/run.js +12 -8
  125. package/dist/telemetry/attempt-meta.d.ts +49 -1
  126. package/dist/telemetry/attempt-meta.d.ts.map +1 -1
  127. package/dist/telemetry/attempt-meta.js +45 -1
  128. package/dist/telemetry/exporter.d.ts.map +1 -1
  129. package/dist/telemetry/exporter.js +2 -1
  130. package/dist/telemetry/grade-mappers.d.ts +1 -1
  131. package/dist/telemetry/grade-mappers.d.ts.map +1 -1
  132. package/dist/telemetry/grade-mappers.js +7 -1
  133. package/dist/telemetry/grade-task.d.ts +49 -0
  134. package/dist/telemetry/grade-task.d.ts.map +1 -0
  135. package/dist/telemetry/grade-task.js +85 -0
  136. package/dist/telemetry/grades-sql.d.ts +16 -1
  137. package/dist/telemetry/grades-sql.d.ts.map +1 -1
  138. package/dist/telemetry/grades-sql.js +64 -4
  139. package/dist/telemetry/ingest-protocol.d.ts +24 -1
  140. package/dist/telemetry/ingest-protocol.d.ts.map +1 -1
  141. package/dist/telemetry/ingest-protocol.js +72 -43
  142. package/dist/telemetry/otel-content.d.ts +31 -0
  143. package/dist/telemetry/otel-content.d.ts.map +1 -0
  144. package/dist/telemetry/otel-content.js +106 -0
  145. package/dist/telemetry/otel-hierarchy.d.ts +57 -0
  146. package/dist/telemetry/otel-hierarchy.d.ts.map +1 -0
  147. package/dist/telemetry/otel-hierarchy.js +155 -0
  148. package/dist/telemetry/otel-normalize.d.ts +15 -1
  149. package/dist/telemetry/otel-normalize.d.ts.map +1 -1
  150. package/dist/telemetry/otel-normalize.js +24 -39
  151. package/dist/telemetry/sinks.d.ts +4 -1
  152. package/dist/telemetry/sinks.d.ts.map +1 -1
  153. package/dist/telemetry/sinks.js +53 -34
  154. package/dist/telemetry/store-migrations.d.ts.map +1 -1
  155. package/dist/telemetry/store-migrations.js +8 -0
  156. package/dist/telemetry/store.d.ts +9 -0
  157. package/dist/telemetry/store.d.ts.map +1 -1
  158. package/dist/telemetry/store.js +10 -0
  159. package/dist/telemetry/uniform-rows.d.ts +43 -0
  160. package/dist/telemetry/uniform-rows.d.ts.map +1 -0
  161. package/dist/telemetry/uniform-rows.js +139 -0
  162. package/dist/types/failures-teaching.d.ts.map +1 -1
  163. package/dist/types/failures-teaching.js +11 -0
  164. package/dist/types/failures.d.ts +1 -1
  165. package/dist/types/failures.d.ts.map +1 -1
  166. package/dist/types/failures.js +2 -0
  167. package/dist/types/provider.d.ts +12 -0
  168. package/dist/types/provider.d.ts.map +1 -1
  169. package/dist/types/route.d.ts +13 -0
  170. package/dist/types/route.d.ts.map +1 -1
  171. package/dist/types/telemetry.d.ts +14 -1
  172. package/dist/types/telemetry.d.ts.map +1 -1
  173. package/docs/agent-skill/SKILL.md +16 -3
  174. package/docs/how-it-fits.md +3 -3
  175. package/docs/instrumentation.md +15 -6
  176. package/docs/llms.txt +55 -7
  177. package/docs/mcp-oracle.md +15 -4
  178. package/docs/quickstart.md +6 -5
  179. package/package.json +4 -2
  180. package/registry/registry.json +456 -0
  181. package/templates/creative-approval.json +81 -0
  182. package/templates/support-conversation.json +82 -0
@@ -84,10 +84,28 @@ export type ImageInputPrice = {
84
84
  readonly source: string;
85
85
  readonly as_of: string;
86
86
  };
87
- /** Non-text input units, USD per unit. */
87
+ /** Where a modality block's UNIT rates came from (ARC-4). REQUIRED for any of
88
+ * `image_per_unit` / `audio_per_second` / `video_per_second` /
89
+ * `characters_per_million` to be priced: a unit rate with no provenance is
90
+ * never used (L5 — absent beats guessed). */
91
+ export interface UnitRateProvenance {
92
+ readonly source: string;
93
+ readonly as_of: string;
94
+ }
95
+ /** Non-token units, USD per unit. For an `llm` entry these are INPUT units (an
96
+ * image or a second of audio sent in); for a declared generation model
97
+ * (registry `kind` image_gen | video_gen | tts | stt — ARC-4) they are what the
98
+ * call is billed in: images generated, seconds produced (video/tts) or
99
+ * transcribed (stt), characters synthesized. */
88
100
  export interface ModalityRates {
89
101
  readonly image_per_unit?: number | null;
90
102
  readonly audio_per_second?: number | null;
103
+ /** ARC-4: USD per second of generated video. */
104
+ readonly video_per_second?: number | null;
105
+ /** ARC-4: USD per MILLION characters (TTS input text). */
106
+ readonly characters_per_million?: number | null;
107
+ /** ARC-4: provenance for the unit rates above (see {@link UnitRateProvenance}). */
108
+ readonly provenance?: UnitRateProvenance | null;
91
109
  /** Typed, provenance-bearing image-input price (UC-3 M0). Additive and
92
110
  * optional; absent when the vendor's image price could not be sourced —
93
111
  * absence is honest, never a zero or a guess. Supersedes the bare
@@ -169,4 +187,14 @@ export interface PricingV2Display {
169
187
  * guarantee lives here, in code, so no consumer can bypass it.
170
188
  */
171
189
  export declare function describePricingV2(pricing: ModelPricingV2): PricingV2Display;
190
+ /**
191
+ * ARC-4: the price block of a DECLARED-ONLY generation model (registry `kind`
192
+ * other than `llm`). Same shape as {@link ModelPricingV2} except `base` is
193
+ * null: these models publish no per-token rate, and a placeholder `0` would be
194
+ * read as "$0 per token" by anything that reads the registry (L5). The price is
195
+ * the `modality` unit rates, with their provenance.
196
+ */
197
+ export interface GenerationPricingV2 extends Omit<ModelPricingV2, "base"> {
198
+ readonly base: null;
199
+ }
172
200
  //# sourceMappingURL=pricing-shape.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"pricing-shape.d.ts","sourceRoot":"","sources":["../../src/registry/pricing-shape.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pricing-shape.d.ts","sourceRoot":"","sources":["../../src/registry/pricing-shape.ts"],"names":[],"mappings":"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"}
@@ -142,6 +142,7 @@ function describePricingV2(pricing) {
142
142
  if (pricing.modality?.audio_per_second != null) {
143
143
  modality.push(`audio: $${pricing.modality.audio_per_second.toFixed(4)} per second`);
144
144
  }
145
+ pushGenerationRates(modality, pricing.modality ?? null);
145
146
  const urlMatch = URL_RE.exec(pricing.source);
146
147
  return {
147
148
  basis: pricing.basis,
@@ -158,3 +159,11 @@ function describePricingV2(pricing) {
158
159
  vendorUrl: urlMatch ? urlMatch[0] : null,
159
160
  };
160
161
  }
162
+ /** ARC-4: the generation unit rates (video seconds, TTS characters), rendered
163
+ * only when present — honest absence otherwise. */
164
+ function pushGenerationRates(out, m) {
165
+ if (m?.video_per_second != null)
166
+ out.push(`video: $${m.video_per_second.toFixed(4)} per second`);
167
+ if (m?.characters_per_million != null)
168
+ out.push(`text-to-speech: $${m.characters_per_million.toFixed(2)} per 1M characters`);
169
+ }
@@ -41,4 +41,30 @@ export declare function estimateCostUsd(pricing: ModelPricing, tokensIn: number,
41
41
  tokensCacheWrite?: number,
42
42
  /** 1h-TTL portion of the write (bills at the higher multiplier when known). */
43
43
  tokensCacheWrite1h?: number): number;
44
+ /**
45
+ * ARC-4: the per-unit rates the vendored LiteLLM snapshot publishes for a
46
+ * GENERATION model, read by mode (LiteLLM spells the same unit differently per
47
+ * mode, so the mode decides which key is the billed unit — nothing is summed or
48
+ * inferred across keys):
49
+ * - `image_generation`: USD per generated image = `output_cost_per_image`,
50
+ * else `input_cost_per_image` (LiteLLM files OpenAI's per-image price there).
51
+ * - `video_generation`: USD per second = `output_cost_per_video_per_second`,
52
+ * else `output_cost_per_second`.
53
+ * - `audio_speech` (TTS): USD per character = `input_cost_per_character`;
54
+ * USD per second of produced audio = `output_cost_per_second` (billed only
55
+ * when the entry has no per-character rate — one billed unit per model).
56
+ * - `audio_transcription` (STT): USD per second of input audio =
57
+ * `input_cost_per_second` (the snapshot's `output_cost_per_second` on some STT
58
+ * entries is not a billed unit and is ignored).
59
+ * Any other mode (chat, embedding, …) has NO unit price here. Key resolution:
60
+ * a known provider's own prefixes, then `<provider>/<model>`.
61
+ */
62
+ export interface MapUnitRates {
63
+ readonly key: string;
64
+ readonly mode: string;
65
+ readonly perImage: number | null;
66
+ readonly perSecond: number | null;
67
+ readonly perCharacter: number | null;
68
+ }
69
+ export declare function getMapUnitRates(provider: string, model: string): MapUnitRates | null;
44
70
  //# 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;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;AA+DD,wBAAgB,UAAU,CAAC,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CA6BnF;AAED;;;;;;;GAOG;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"}
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;AA0ED,wBAAgB,UAAU,CAAC,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CA6BnF;AAED;;;;;;;GAOG;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;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CACtC;AAMD,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAsBpF"}
@@ -13,6 +13,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
13
13
  exports.getPricing = getPricing;
14
14
  exports.getPricingV2 = getPricingV2;
15
15
  exports.estimateCostUsd = estimateCostUsd;
16
+ exports.getMapUnitRates = getMapUnitRates;
16
17
  const node_fs_1 = require("node:fs");
17
18
  const node_path_1 = require("node:path");
18
19
  /** LiteLLM key prefixes per provider, most-specific first. Verified against
@@ -129,3 +130,31 @@ tokensCacheWrite1h = 0) {
129
130
  write1h * write1hRate +
130
131
  Math.max(tokensOut, 0) * pricing.outputUsdPerTok);
131
132
  }
133
+ function finiteRate(v) {
134
+ return typeof v === "number" && Number.isFinite(v) && v >= 0 ? v : null;
135
+ }
136
+ function getMapUnitRates(provider, model) {
137
+ if (provider === "" || model === "")
138
+ return null;
139
+ const map = loadMap();
140
+ const prefixes = KEY_PREFIXES[provider] ?? [];
141
+ const candidates = [...prefixes.map((p) => `${p}${model}`), `${provider}/${model}`];
142
+ for (const key of candidates) {
143
+ const e = map[key];
144
+ if (e === undefined || typeof e.mode !== "string")
145
+ continue;
146
+ switch (e.mode) {
147
+ case "image_generation":
148
+ return { key, mode: e.mode, perImage: finiteRate(e.output_cost_per_image) ?? finiteRate(e.input_cost_per_image), perSecond: null, perCharacter: null };
149
+ case "video_generation":
150
+ return { key, mode: e.mode, perImage: null, perSecond: finiteRate(e.output_cost_per_video_per_second) ?? finiteRate(e.output_cost_per_second), perCharacter: null };
151
+ case "audio_speech":
152
+ return { key, mode: e.mode, perImage: null, perSecond: finiteRate(e.output_cost_per_second), perCharacter: finiteRate(e.input_cost_per_character) };
153
+ case "audio_transcription":
154
+ return { key, mode: e.mode, perImage: null, perSecond: finiteRate(e.input_cost_per_second), perCharacter: null };
155
+ default:
156
+ return null;
157
+ }
158
+ }
159
+ return null;
160
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"rows.d.ts","sourceRoot":"","sources":["../../src/registry/rows.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AA0C/C;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,cAAc,EAAE,CA4BxE"}
1
+ {"version":3,"file":"rows.d.ts","sourceRoot":"","sources":["../../src/registry/rows.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AA4C/C;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,cAAc,EAAE,CA6BxE"}
@@ -10,6 +10,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
10
10
  exports.loadRegistryRows = loadRegistryRows;
11
11
  const node_fs_1 = require("node:fs");
12
12
  const node_path_1 = require("node:path");
13
+ const model_kind_1 = require("./model-kind");
13
14
  function packagedRegistryDir() {
14
15
  // dist/ and src/ both sit one level under the package root.
15
16
  return (0, node_path_1.join)(__dirname, "..", "..", "registry");
@@ -38,7 +39,8 @@ function loadRegistryRows(registryPath) {
38
39
  const dir = registryFile.slice(0, Math.max(registryFile.lastIndexOf("/"), 0));
39
40
  const leaderboard = readJson((0, node_path_1.join)(dir, "leaderboard.json")) ?? [];
40
41
  const effective = new Map(leaderboard.map((r) => [r.model_key, r.effective_usd_per_1k_conformant ?? null]));
41
- return (registry.models ?? []).map((entry) => {
42
+ // ARC-4 rank wall: declared-only generation models never enter selection.
43
+ return (registry.models ?? []).filter(model_kind_1.isRankable).map((entry) => {
42
44
  const [provider] = entry.model_key.split("/");
43
45
  return {
44
46
  key: entry.model_key,
@@ -0,0 +1,32 @@
1
+ /**
2
+ * ARC-4 — the registry half of unit pricing: a DECLARED-ONLY generation entry's
3
+ * `pricing_v2.modality` unit rates, read from the packaged registry.json. Only
4
+ * a non-`llm` entry (model-kind.ts) whose modality carries `provenance` (source
5
+ * + as_of) answers; anything else is "no registry price" and the caller falls
6
+ * through to the vendored pricing map (run/cost.ts `estimateUnitCostUsd`).
7
+ */
8
+ import { type GenerationKind } from "./model-kind";
9
+ import type { ModalityRates } from "./pricing-shape";
10
+ export interface RegistryUnitRates {
11
+ readonly modelKey: string;
12
+ readonly kind: GenerationKind;
13
+ readonly modality: ModalityRates;
14
+ }
15
+ interface RegistryEntryShape {
16
+ readonly model_key?: unknown;
17
+ readonly kind?: unknown;
18
+ readonly declared?: {
19
+ readonly pricing_v2?: {
20
+ readonly modality?: ModalityRates | null;
21
+ } | null;
22
+ } | null;
23
+ }
24
+ /** Build the lookup from registry entries (exported for tests and the registry
25
+ * drift test). */
26
+ export declare function unitRatesIndex(models: readonly RegistryEntryShape[]): Map<string, RegistryUnitRates>;
27
+ /** The registry's unit rates for `provider/model`, or null. */
28
+ export declare function getRegistryUnitRates(provider: string, model: string): RegistryUnitRates | null;
29
+ /** Test-only: replace (or with null, reset) the loaded registry index. */
30
+ export declare function setRegistryUnitRatesForTest(models: readonly RegistryEntryShape[] | null): void;
31
+ export {};
32
+ //# sourceMappingURL=unit-pricing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unit-pricing.d.ts","sourceRoot":"","sources":["../../src/registry/unit-pricing.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,EAAe,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC;CAClC;AAED,UAAU,kBAAkB;IAC1B,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,QAAQ,CAAC,EAAE;QAAE,QAAQ,CAAC,UAAU,CAAC,EAAE;YAAE,QAAQ,CAAC,QAAQ,CAAC,EAAE,aAAa,GAAG,IAAI,CAAA;SAAE,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,CAAC;CAC1G;AAcD;kBACkB;AAClB,wBAAgB,cAAc,CAAC,MAAM,EAAE,SAAS,kBAAkB,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,iBAAiB,CAAC,CASpG;AAkBD,+DAA+D;AAC/D,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI,CAE9F;AAED,0EAA0E;AAC1E,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,SAAS,kBAAkB,EAAE,GAAG,IAAI,GAAG,IAAI,CAE9F"}
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ /**
3
+ * ARC-4 — the registry half of unit pricing: a DECLARED-ONLY generation entry's
4
+ * `pricing_v2.modality` unit rates, read from the packaged registry.json. Only
5
+ * a non-`llm` entry (model-kind.ts) whose modality carries `provenance` (source
6
+ * + as_of) answers; anything else is "no registry price" and the caller falls
7
+ * through to the vendored pricing map (run/cost.ts `estimateUnitCostUsd`).
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.unitRatesIndex = unitRatesIndex;
11
+ exports.getRegistryUnitRates = getRegistryUnitRates;
12
+ exports.setRegistryUnitRatesForTest = setRegistryUnitRatesForTest;
13
+ const node_fs_1 = require("node:fs");
14
+ const node_path_1 = require("node:path");
15
+ const model_kind_1 = require("./model-kind");
16
+ let cached = null;
17
+ function packagedRegistryPath() {
18
+ // dist/ and src/ both sit one level under the package root.
19
+ return (0, node_path_1.join)(__dirname, "..", "..", "registry", "registry.json");
20
+ }
21
+ function hasProvenance(m) {
22
+ const p = m?.provenance;
23
+ return p != null && typeof p.source === "string" && p.source !== "" && typeof p.as_of === "string" && p.as_of !== "";
24
+ }
25
+ /** Build the lookup from registry entries (exported for tests and the registry
26
+ * drift test). */
27
+ function unitRatesIndex(models) {
28
+ const out = new Map();
29
+ for (const e of models) {
30
+ if (typeof e.model_key !== "string" || !(0, model_kind_1.isModelKind)(e.kind) || e.kind === "llm")
31
+ continue;
32
+ const modality = e.declared?.pricing_v2?.modality;
33
+ if (!hasProvenance(modality))
34
+ continue;
35
+ out.set(e.model_key, { modelKey: e.model_key, kind: e.kind, modality });
36
+ }
37
+ return out;
38
+ }
39
+ function load() {
40
+ if (cached === null) {
41
+ const path = packagedRegistryPath();
42
+ let models = [];
43
+ if ((0, node_fs_1.existsSync)(path)) {
44
+ try {
45
+ models = (JSON.parse((0, node_fs_1.readFileSync)(path, "utf8")).models ?? []);
46
+ }
47
+ catch {
48
+ models = []; // an unreadable registry is "no registry price", never a throw
49
+ }
50
+ }
51
+ cached = unitRatesIndex(models);
52
+ }
53
+ return cached;
54
+ }
55
+ /** The registry's unit rates for `provider/model`, or null. */
56
+ function getRegistryUnitRates(provider, model) {
57
+ return load().get(`${provider}/${model}`) ?? null;
58
+ }
59
+ /** Test-only: replace (or with null, reset) the loaded registry index. */
60
+ function setRegistryUnitRatesForTest(models) {
61
+ cached = models === null ? null : unitRatesIndex(models);
62
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Route INPUT contract at load — ARC-β messages lane (builder-prompt-02 §1.3).
3
+ * Carved out of routes/loader.ts (near the 700-LOC cap), like output-loader.ts.
4
+ *
5
+ * YAML forms accepted for `input:`:
6
+ * (absent) → variables (the default; byte-identical)
7
+ * input: variables → variables (explicit; identical to absent)
8
+ * input: messages → a chat / tool-loop route
9
+ * input: { kind: messages } → same
10
+ * input: { kind: variables } → variables
11
+ *
12
+ * The parsed result OMITS `inputKind` for variables so an existing route's
13
+ * bundle (and its `bundle_sha`) is unchanged; only `messages` is ever carried.
14
+ *
15
+ * Fail-closed pairing: `repair:` re-asks without the conversation (ruling M1);
16
+ * `mask:` and `screen:` operate on the rendered user slot
17
+ * and the declared untrusted variables — they do not yet see caller history.
18
+ * Rather than serve a conversation the guard cannot read, a messages route that
19
+ * declares either is a LOAD error that says so.
20
+ */
21
+ export declare const INPUT_KINDS: ReadonlySet<string>;
22
+ export interface ParsedInputBlock {
23
+ /** Present ONLY for `messages` (variables ⇒ omitted ⇒ byte-identical bundle). */
24
+ readonly inputKind?: "messages";
25
+ }
26
+ export interface InputBlockContext {
27
+ readonly maskDeclared: boolean;
28
+ readonly screenDeclared: boolean;
29
+ /** A `repair:` rung on the route or any variant (architect ruling M1). */
30
+ readonly repairDeclared: boolean;
31
+ }
32
+ /** The teaching problem for a messages route that also declares mask/screen —
33
+ * shared by the loader and the run-time guard (mirror bundles skip the loader). */
34
+ export declare function messagesGuardConflict(ctx: InputBlockContext): string | null;
35
+ /** Parse the bundle's `input:` key. Pushes teaching problems; returns `{}` for
36
+ * variables (absent / explicit) so the bundle spread adds nothing. */
37
+ export declare function parseInputBlock(raw: unknown, ctx: InputBlockContext, problems: string[]): ParsedInputBlock;
38
+ //# sourceMappingURL=input-loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input-loader.d.ts","sourceRoot":"","sources":["../../src/routes/input-loader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,eAAO,MAAM,WAAW,EAAE,WAAW,CAAC,MAAM,CAAsC,CAAC;AAGnF,MAAM,WAAW,gBAAgB;IAC/B,iFAAiF;IACjF,QAAQ,CAAC,SAAS,CAAC,EAAE,UAAU,CAAC;CACjC;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACjC,0EAA0E;IAC1E,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;CAClC;AAMD;mFACmF;AACnF,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,iBAAiB,GAAG,MAAM,GAAG,IAAI,CAkB3E;AAED;sEACsE;AACtE,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,gBAAgB,CAyB1G"}
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ /**
3
+ * Route INPUT contract at load — ARC-β messages lane (builder-prompt-02 §1.3).
4
+ * Carved out of routes/loader.ts (near the 700-LOC cap), like output-loader.ts.
5
+ *
6
+ * YAML forms accepted for `input:`:
7
+ * (absent) → variables (the default; byte-identical)
8
+ * input: variables → variables (explicit; identical to absent)
9
+ * input: messages → a chat / tool-loop route
10
+ * input: { kind: messages } → same
11
+ * input: { kind: variables } → variables
12
+ *
13
+ * The parsed result OMITS `inputKind` for variables so an existing route's
14
+ * bundle (and its `bundle_sha`) is unchanged; only `messages` is ever carried.
15
+ *
16
+ * Fail-closed pairing: `repair:` re-asks without the conversation (ruling M1);
17
+ * `mask:` and `screen:` operate on the rendered user slot
18
+ * and the declared untrusted variables — they do not yet see caller history.
19
+ * Rather than serve a conversation the guard cannot read, a messages route that
20
+ * declares either is a LOAD error that says so.
21
+ */
22
+ Object.defineProperty(exports, "__esModule", { value: true });
23
+ exports.INPUT_KINDS = void 0;
24
+ exports.messagesGuardConflict = messagesGuardConflict;
25
+ exports.parseInputBlock = parseInputBlock;
26
+ exports.INPUT_KINDS = new Set(["variables", "messages"]);
27
+ const INPUT_BLOCK_KEYS = new Set(["kind"]);
28
+ function isRecord(v) {
29
+ return typeof v === "object" && v !== null && !Array.isArray(v);
30
+ }
31
+ /** The teaching problem for a messages route that also declares mask/screen —
32
+ * shared by the loader and the run-time guard (mirror bundles skip the loader). */
33
+ function messagesGuardConflict(ctx) {
34
+ // Architect ruling M1 (2026-10-24): the repair rung re-asks WITHOUT the
35
+ // conversation, so on a messages route it would answer a turn it cannot see —
36
+ // refused rather than served a context-free "corrected" reply.
37
+ if (ctx.repairDeclared) {
38
+ return ("input: messages cannot be combined with repair: — the repair rung re-asks the model without the " +
39
+ "conversation, so a repaired reply would answer a turn it cannot see. Remove repair: (route and variants) " +
40
+ "from this route; an invalid reply is retried from the content_invalid budget instead (see messages-lane.md)");
41
+ }
42
+ const which = [ctx.maskDeclared ? "mask:" : null, ctx.screenDeclared ? "screen:" : null].filter((x) => x !== null);
43
+ if (which.length === 0)
44
+ return null;
45
+ return (`input: messages cannot be combined with ${which.join(" / ")} yet — masking and screening read the rendered ` +
46
+ "user slot and declared variables, not caller history, so the conversation would pass unguarded. Remove " +
47
+ `${which.join(" / ")} from this route, or serve the content as variables (see messages-lane.md)`);
48
+ }
49
+ /** Parse the bundle's `input:` key. Pushes teaching problems; returns `{}` for
50
+ * variables (absent / explicit) so the bundle spread adds nothing. */
51
+ function parseInputBlock(raw, ctx, problems) {
52
+ if (raw === undefined || raw === null)
53
+ return {};
54
+ let kind;
55
+ if (typeof raw === "string") {
56
+ kind = raw;
57
+ }
58
+ else if (isRecord(raw)) {
59
+ for (const key of Object.keys(raw)) {
60
+ if (!INPUT_BLOCK_KEYS.has(key))
61
+ problems.push(`input.${key} is not a known key — the block is {kind: variables|messages}`);
62
+ }
63
+ kind = raw.kind;
64
+ }
65
+ else {
66
+ problems.push(`input must be "variables", "messages", or {kind} — got ${JSON.stringify(raw)}`);
67
+ return {};
68
+ }
69
+ if (typeof kind !== "string" || !exports.INPUT_KINDS.has(kind)) {
70
+ problems.push(`input kind "${String(kind)}" is not one of [variables, messages] — write \`input: { kind: messages }\` for a ` +
71
+ "chat or tool-loop route, or omit it for a variables route (the default)");
72
+ return {};
73
+ }
74
+ if (kind === "variables")
75
+ return {};
76
+ const conflict = messagesGuardConflict(ctx);
77
+ if (conflict !== null)
78
+ problems.push(conflict);
79
+ return { inputKind: "messages" };
80
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/routes/loader.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AASH,OAAO,KAAK,EAKV,WAAW,EAGZ,MAAM,gBAAgB,CAAC;AAaxB,OAAO,EAAE,sBAAsB,EAAE,kCAAkC,EAAE,8BAA8B,EAAE,MAAM,mBAAmB,CAAC;AAE/H;;;;;GAKG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;gBAEzB,OAAO,EAAE,MAAM,EAAE,IAAI,GAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;KAAO;CAOxF;AA+BD,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,CAAC;IAChC,IAAI,IAAI,SAAS,WAAW,EAAE,CAAC;CAChC;AA2aD;;;;;;;GAOG;AACH;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,YAAY,CAItF;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,GAAG,YAAY,CAyB1F;AAED;;yBAEyB;AACzB,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;CACtC;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,eAAe,EAAE,CA6CtE;AAED,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,CA2C1D"}
1
+ {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/routes/loader.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AASH,OAAO,KAAK,EAKV,WAAW,EAGZ,MAAM,gBAAgB,CAAC;AAcxB,OAAO,EAAE,sBAAsB,EAAE,kCAAkC,EAAE,8BAA8B,EAAE,MAAM,mBAAmB,CAAC;AAE/H;;;;;GAKG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;gBAEzB,OAAO,EAAE,MAAM,EAAE,IAAI,GAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;KAAO;CAOxF;AA+BD,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,CAAC;IAChC,IAAI,IAAI,SAAS,WAAW,EAAE,CAAC;CAChC;AA6aD;;;;;;;GAOG;AACH;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,YAAY,CAItF;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,GAAG,YAAY,CAyB1F;AAED;;yBAEyB;AACzB,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;CACtC;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,eAAe,EAAE,CA6CtE;AAED,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,CA2C1D"}
@@ -24,6 +24,7 @@ const screen_loader_1 = require("./screen-loader");
24
24
  const prompt_loader_1 = require("./prompt-loader"); // issue #5 (R1): `prompt.user` + the prompt block (moved out for the LOC cap)
25
25
  const mask_loader_1 = require("./mask-loader");
26
26
  const objective_loader_1 = require("./objective-loader");
27
+ const input_loader_1 = require("./input-loader");
27
28
  const output_loader_1 = require("./output-loader"); // issue #1: `output: text` (prose) + the schema reader (moved out for the LOC cap)
28
29
  // Re-exported so existing importers of "./loader" keep resolving these advisories
29
30
  // (they live in ./loader-warnings to hold loader.ts under the 700-LOC cap).
@@ -392,6 +393,7 @@ function loadBundleFile(filePath) {
392
393
  // x-trust) — parsed in prompt-loader.ts; both templates are files relative to
393
394
  // the bundle and share one declared-variable list.
394
395
  const { systemTemplate, userTemplate, variables, variableTrust } = (0, prompt_loader_1.parsePromptBlock)(doc.prompt, bundleDir, problems);
396
+ const input = (0, input_loader_1.parseInputBlock)(doc.input, { maskDeclared: mask !== undefined, screenDeclared: screen !== undefined, repairDeclared: repair !== undefined || variants.some((v) => v.repair !== undefined) }, problems); // ARC-β `input: messages` (input-loader.ts)
395
397
  (0, screen_loader_1.pushUndeclaredVariableProblems)(systemTemplate, groundingQuery, variables, problems, userTemplate);
396
398
  if (problems.length > 0) {
397
399
  throw new RouteConfigError("invalid route bundle", { file: filePath, problems });
@@ -443,6 +445,7 @@ function loadBundleFile(filePath) {
443
445
  prefer: Object.freeze(prefer),
444
446
  systemTemplate,
445
447
  ...(userTemplate !== undefined ? { userTemplate } : {}), // issue #5 (R1): present ONLY when declared (absent ⇒ unchanged bundle_sha)
448
+ ...input, // ARC-β inputKind — present ONLY for `input: messages` (variables ⇒ nothing added)
446
449
  variables: Object.freeze(variables),
447
450
  policy,
448
451
  ...(repair !== undefined ? { repair } : {}),
@@ -56,6 +56,8 @@ export interface ResolvedRouteBundle {
56
56
  * `bundle_sha`), so the hosted/mirror lane renders the same user turn and a
57
57
  * cache handle composes there too. */
58
58
  readonly userTemplate?: string;
59
+ /** ARC-β — `input: messages`, carried ONLY when declared (unchanged `bundle_sha` otherwise). */
60
+ readonly inputKind?: "messages";
59
61
  readonly variables: readonly string[];
60
62
  readonly policy: RoutePolicy;
61
63
  readonly repair?: RepairPolicy;
@@ -1 +1 @@
1
- {"version":3,"file":"resolved-bundle.d.ts","sourceRoot":"","sources":["../../src/routes/resolved-bundle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAIH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAG7C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,EACV,aAAa,EACb,UAAU,EACV,YAAY,EACZ,WAAW,EACX,WAAW,EACX,WAAW,EACX,YAAY,EACb,MAAM,gBAAgB,CAAC;AAExB;;;;;GAKG;AACH,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,iFAAiF;IACjF,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC;;;+EAG2E;IAC3E,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,UAAU,EAAE,SAAS,aAAa,EAAE,CAAC;IAC9C,QAAQ,CAAC,OAAO,EAAE,SAAS,WAAW,EAAE,CAAC;IACzC,QAAQ,CAAC,MAAM,EAAE,SAAS,UAAU,EAAE,CAAC;IACvC,4DAA4D;IAC5D,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC;;;0CAGsC;IACtC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE,YAAY,CAAC;IAC/B,QAAQ,CAAC,QAAQ,EAAE,SAAS,YAAY,EAAE,CAAC;IAC3C,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC;iFAC6E;IAC7E,QAAQ,CAAC,iBAAiB,CAAC,EAAE,QAAQ,GAAG,WAAW,CAAC;IACpD;;;;2BAIuB;IACvB,QAAQ,CAAC,aAAa,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;IAC/D;;;;;;;;;;;mBAWe;IACf,QAAQ,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC;IACrC;;;;;;;mCAO+B;IAC/B,QAAQ,CAAC,IAAI,CAAC,EAAE,kBAAkB,CAAC;IACnC;;;;;oEAKgE;IAChE,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC;CAC9B;AAED;sEACsE;AACtE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,WAAW,GAAG,mBAAmB,CA8B3E;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAe1D;AAiBD,mEAAmE;AACnE,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,mBAAmB,GAAG,MAAM,CAEvE;AAED;gFACgF;AAChF,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,mBAAmB,GAAG,MAAM,CAEtE;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,GAAG,WAAW,CAoE5D;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,WAAW,GAAG,YAAY,CAclE"}
1
+ {"version":3,"file":"resolved-bundle.d.ts","sourceRoot":"","sources":["../../src/routes/resolved-bundle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAIH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAG7C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,EACV,aAAa,EACb,UAAU,EACV,YAAY,EACZ,WAAW,EACX,WAAW,EACX,WAAW,EACX,YAAY,EACb,MAAM,gBAAgB,CAAC;AAExB;;;;;GAKG;AACH,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,iFAAiF;IACjF,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC;;;+EAG2E;IAC3E,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,UAAU,EAAE,SAAS,aAAa,EAAE,CAAC;IAC9C,QAAQ,CAAC,OAAO,EAAE,SAAS,WAAW,EAAE,CAAC;IACzC,QAAQ,CAAC,MAAM,EAAE,SAAS,UAAU,EAAE,CAAC;IACvC,4DAA4D;IAC5D,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC;;;0CAGsC;IACtC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,gGAAgG;IAChG,QAAQ,CAAC,SAAS,CAAC,EAAE,UAAU,CAAC;IAChC,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE,YAAY,CAAC;IAC/B,QAAQ,CAAC,QAAQ,EAAE,SAAS,YAAY,EAAE,CAAC;IAC3C,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC;iFAC6E;IAC7E,QAAQ,CAAC,iBAAiB,CAAC,EAAE,QAAQ,GAAG,WAAW,CAAC;IACpD;;;;2BAIuB;IACvB,QAAQ,CAAC,aAAa,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;IAC/D;;;;;;;;;;;mBAWe;IACf,QAAQ,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC;IACrC;;;;;;;mCAO+B;IAC/B,QAAQ,CAAC,IAAI,CAAC,EAAE,kBAAkB,CAAC;IACnC;;;;;oEAKgE;IAChE,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC;CAC9B;AAED;sEACsE;AACtE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,WAAW,GAAG,mBAAmB,CA+B3E;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAe1D;AAiBD,mEAAmE;AACnE,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,mBAAmB,GAAG,MAAM,CAEvE;AAED;gFACgF;AAChF,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,mBAAmB,GAAG,MAAM,CAEtE;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,GAAG,WAAW,CAsE5D;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,WAAW,GAAG,YAAY,CAclE"}
@@ -51,6 +51,7 @@ function resolveRouteBundle(bundle) {
51
51
  prefer: bundle.prefer,
52
52
  systemTemplate: bundle.systemTemplate,
53
53
  ...(bundle.userTemplate !== undefined ? { userTemplate: bundle.userTemplate } : {}), // issue #5 (R1)
54
+ ...(bundle.inputKind === "messages" ? { inputKind: "messages" } : {}), // ARC-β
54
55
  variables: bundle.variables,
55
56
  policy: bundle.policy,
56
57
  ...(bundle.repair !== undefined ? { repair: bundle.repair } : {}),
@@ -174,6 +175,8 @@ function bundleFromResolved(raw) {
174
175
  // Issue #5 (R1): a mirrored `prompt.user` rebuilds as the user turn; anything
175
176
  // but a non-empty string ⇒ absent ⇒ the fixed trigger (byte-identical).
176
177
  ...(typeof b.userTemplate === "string" && b.userTemplate !== "" ? { userTemplate: b.userTemplate } : {}),
178
+ // ARC-β: only the literal "messages" rebuilds a messages route (anything else ⇒ variables).
179
+ ...(b.inputKind === "messages" ? { inputKind: "messages" } : {}),
177
180
  variables: Object.freeze([...(b.variables ?? [])]),
178
181
  policy: b.policy,
179
182
  ...(b.repair !== undefined ? { repair: b.repair } : {}),
@@ -20,6 +20,7 @@
20
20
  * WITHOUT a served tier and so prices at base. That is a money path and is
21
21
  * deliberately not changed alongside this; tracked for the next money-path MR.
22
22
  */
23
+ import type { RecordedUnits, UnitKey } from "../telemetry/attempt-meta";
23
24
  import type { ModelPricing } from "../registry/pricing";
24
25
  import type { AdapterUsage, ProviderId, ServiceTier } from "../types/provider";
25
26
  /** The `servedTier` an attempt reports, when the caller has it — optional so
@@ -64,5 +65,32 @@ export declare function costComponents(provider: ProviderId, model: string, usag
64
65
  /** Pre-dispatch upper-bound estimate for the envelope precheck: prompt
65
66
  * length + the full output bound, at real pricing or the conservative rate. */
66
67
  export declare function dispatchEstimateUsd(provider: ProviderId, model: string, promptChars: number, unpricedRatePerTok: number): number;
68
+ /** Where a unit price came from. */
69
+ export type UnitPriceSource = "registry" | "pricing-map";
70
+ export interface UnitCost {
71
+ /** USD for the call's BILLED unit; 0 when unpriced. */
72
+ readonly costUsd: number;
73
+ /** True when the call reported units ModelRig cannot price (never guessed). */
74
+ readonly pricingMissing: boolean;
75
+ /** The unit the price applies to (one per model — the others are recorded,
76
+ * not priced, so a TTS call's seconds never double-bill its characters). */
77
+ readonly billedUnit: UnitKey | null;
78
+ readonly usdPerUnit: number | null;
79
+ readonly source: UnitPriceSource | null;
80
+ }
81
+ /**
82
+ * ARC-4 — the list-price cost of a call's non-token units. The chain, first
83
+ * hit wins (dev-rule L5 — never guessed, NEVER synthesized from token rates):
84
+ * 1. the registry: a declared generation entry's `pricing_v2.modality` unit
85
+ * rate, which must carry provenance (source + as_of);
86
+ * 2. the vendored LiteLLM pricing map's per-mode unit key;
87
+ * 3. else `pricingMissing: true`, cost 0.
88
+ * Each model bills ONE unit (its kind / mode decides which); other units are
89
+ * recorded on `meta.units` but not priced. A call whose billed unit is absent
90
+ * or zero while it reports other units is `pricingMissing` (we cannot price what
91
+ * it reported). `steps` is never billed. No units (or all zero) ⇒ $0, not
92
+ * missing. Pure apart from the cached registry/map reads.
93
+ */
94
+ export declare function estimateUnitCostUsd(provider: string, model: string, units: RecordedUnits | undefined): UnitCost;
67
95
  export {};
68
96
  //# sourceMappingURL=cost.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cost.d.ts","sourceRoot":"","sources":["../../src/run/cost.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGxD,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAS/E;uEACuE;AACvE,KAAK,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC,CAAC;AAE3D;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,UAAU,EACpB,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,WAAW,GAAG,SAAS,GAClC,YAAY,GAAG,IAAI,CAiBrB;AAED,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAC1C,eAAO,MAAM,0BAA0B,QAAS,CAAC;AAEjD;;yEAEyE;AACzE,eAAO,MAAM,kCAAkC,MAAM,CAAC;AAEtD,MAAM,WAAW,WAAW;IAC1B,kEAAkE;IAClE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,uEAAuE;IACvE,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;CAClC;AAED,wBAAgB,WAAW,CACzB,QAAQ,EAAE,UAAU,EACpB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,YAAY,EACnB,kBAAkB,EAAE,MAAM,GACzB,WAAW,CAoBb;AAED;;;;;4EAK4E;AAC5E,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,UAAU,EACpB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,IAAI,CACT,YAAY,EACZ,UAAU,GAAG,WAAW,GAAG,cAAc,GAAG,kBAAkB,GAAG,oBAAoB,CACtF,GACC,SAAS,GACV;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAmB5F;AAED;+EAC+E;AAC/E,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,UAAU,EACpB,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,EACnB,kBAAkB,EAAE,MAAM,GACzB,MAAM,CAOR"}
1
+ {"version":3,"file":"cost.d.ts","sourceRoot":"","sources":["../../src/run/cost.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGxD,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAS/E;uEACuE;AACvE,KAAK,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC,CAAC;AAE3D;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,UAAU,EACpB,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,WAAW,GAAG,SAAS,GAClC,YAAY,GAAG,IAAI,CAiBrB;AAED,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAC1C,eAAO,MAAM,0BAA0B,QAAS,CAAC;AAEjD;;yEAEyE;AACzE,eAAO,MAAM,kCAAkC,MAAM,CAAC;AAEtD,MAAM,WAAW,WAAW;IAC1B,kEAAkE;IAClE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,uEAAuE;IACvE,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;CAClC;AAED,wBAAgB,WAAW,CACzB,QAAQ,EAAE,UAAU,EACpB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,YAAY,EACnB,kBAAkB,EAAE,MAAM,GACzB,WAAW,CAoBb;AAED;;;;;4EAK4E;AAC5E,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,UAAU,EACpB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,IAAI,CACT,YAAY,EACZ,UAAU,GAAG,WAAW,GAAG,cAAc,GAAG,kBAAkB,GAAG,oBAAoB,CACtF,GACC,SAAS,GACV;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAmB5F;AAED;+EAC+E;AAC/E,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,UAAU,EACpB,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,EACnB,kBAAkB,EAAE,MAAM,GACzB,MAAM,CAOR;AAID,oCAAoC;AACpC,MAAM,MAAM,eAAe,GAAG,UAAU,GAAG,aAAa,CAAC;AAEzD,MAAM,WAAW,QAAQ;IACvB,uDAAuD;IACvD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,+EAA+E;IAC/E,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACjC;gFAC4E;IAC5E,QAAQ,CAAC,UAAU,EAAE,OAAO,GAAG,IAAI,CAAC;IACpC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAAC;CACzC;AAiDD;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,SAAS,GAAG,QAAQ,CAc/G"}
package/dist/run/cost.js CHANGED
@@ -27,7 +27,9 @@ exports.pricingForServedTier = pricingForServedTier;
27
27
  exports.attemptCost = attemptCost;
28
28
  exports.costComponents = costComponents;
29
29
  exports.dispatchEstimateUsd = dispatchEstimateUsd;
30
+ exports.estimateUnitCostUsd = estimateUnitCostUsd;
30
31
  const pricing_1 = require("../registry/pricing");
32
+ const unit_pricing_1 = require("../registry/unit-pricing");
31
33
  const pricing_shape_1 = require("../registry/pricing-shape");
32
34
  /** The served tiers that carry their own published rates (issue #2). `standard`
33
35
  * is `base` by definition; an unlisted tier bills at base (fail-closed, L5). */
@@ -121,3 +123,75 @@ function dispatchEstimateUsd(provider, model, promptChars, unpricedRatePerTok) {
121
123
  }
122
124
  return (0, pricing_1.estimateCostUsd)(pricing, promptTokens, exports.ESTIMATE_MAX_OUTPUT_TOKENS, 0);
123
125
  }
126
+ /** The registry profile of a declared generation model: its kind names the
127
+ * billed unit; the rate is the matching `pricing_v2.modality` field. */
128
+ function registryProfile(provider, model) {
129
+ const r = (0, unit_pricing_1.getRegistryUnitRates)(provider, model);
130
+ if (r === null)
131
+ return null;
132
+ const m = r.modality;
133
+ switch (r.kind) {
134
+ case "image_gen":
135
+ return { billedUnit: "images", usdPerUnit: m.image_per_unit ?? null };
136
+ case "video_gen":
137
+ return { billedUnit: "seconds", usdPerUnit: m.video_per_second ?? null };
138
+ case "tts":
139
+ return m.characters_per_million != null
140
+ ? { billedUnit: "characters", usdPerUnit: m.characters_per_million / 1000000 }
141
+ : { billedUnit: "seconds", usdPerUnit: m.audio_per_second ?? null };
142
+ case "stt":
143
+ return { billedUnit: "seconds", usdPerUnit: m.audio_per_second ?? null };
144
+ }
145
+ }
146
+ /** The vendored pricing map's profile, by LiteLLM mode (pricing.ts
147
+ * `getMapUnitRates` documents which key is the billed unit per mode). */
148
+ function mapProfile(provider, model) {
149
+ const r = (0, pricing_1.getMapUnitRates)(provider, model);
150
+ if (r === null)
151
+ return null;
152
+ switch (r.mode) {
153
+ case "image_generation":
154
+ return { billedUnit: "images", usdPerUnit: r.perImage };
155
+ case "video_generation":
156
+ case "audio_transcription":
157
+ return { billedUnit: "seconds", usdPerUnit: r.perSecond };
158
+ case "audio_speech":
159
+ return r.perCharacter !== null
160
+ ? { billedUnit: "characters", usdPerUnit: r.perCharacter }
161
+ : { billedUnit: "seconds", usdPerUnit: r.perSecond };
162
+ default:
163
+ return null;
164
+ }
165
+ }
166
+ const UNPRICED = { costUsd: 0, pricingMissing: true, billedUnit: null, usdPerUnit: null, source: null };
167
+ /**
168
+ * ARC-4 — the list-price cost of a call's non-token units. The chain, first
169
+ * hit wins (dev-rule L5 — never guessed, NEVER synthesized from token rates):
170
+ * 1. the registry: a declared generation entry's `pricing_v2.modality` unit
171
+ * rate, which must carry provenance (source + as_of);
172
+ * 2. the vendored LiteLLM pricing map's per-mode unit key;
173
+ * 3. else `pricingMissing: true`, cost 0.
174
+ * Each model bills ONE unit (its kind / mode decides which); other units are
175
+ * recorded on `meta.units` but not priced. A call whose billed unit is absent
176
+ * or zero while it reports other units is `pricingMissing` (we cannot price what
177
+ * it reported). `steps` is never billed. No units (or all zero) ⇒ $0, not
178
+ * missing. Pure apart from the cached registry/map reads.
179
+ */
180
+ function estimateUnitCostUsd(provider, model, units) {
181
+ const any = units !== undefined && Object.values(units).some((v) => typeof v === "number" && v > 0);
182
+ if (!any || units === undefined)
183
+ return { costUsd: 0, pricingMissing: false, billedUnit: null, usdPerUnit: null, source: null };
184
+ const candidates = [
185
+ ["registry", registryProfile(provider, model)],
186
+ ["pricing-map", mapProfile(provider, model)],
187
+ ];
188
+ for (const [source, profile] of candidates) {
189
+ if (profile === null || profile.usdPerUnit === null)
190
+ continue;
191
+ const count = units[profile.billedUnit] ?? 0;
192
+ if (count <= 0)
193
+ return { ...UNPRICED, billedUnit: profile.billedUnit, source };
194
+ return { costUsd: count * profile.usdPerUnit, pricingMissing: false, billedUnit: profile.billedUnit, usdPerUnit: profile.usdPerUnit, source };
195
+ }
196
+ return UNPRICED;
197
+ }