modelrig 0.1.0 → 0.2.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 (309) hide show
  1. package/CHANGELOG.md +94 -0
  2. package/README.md +41 -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.map +1 -1
  17. package/dist/adapters/gemini.js +46 -6
  18. package/dist/adapters/grok.d.ts +9 -0
  19. package/dist/adapters/grok.d.ts.map +1 -1
  20. package/dist/adapters/grok.js +67 -3
  21. package/dist/adapters/openai-compat.d.ts +6 -0
  22. package/dist/adapters/openai-compat.d.ts.map +1 -1
  23. package/dist/adapters/openai-compat.js +58 -1
  24. package/dist/adapters/openai-stream.d.ts +58 -0
  25. package/dist/adapters/openai-stream.d.ts.map +1 -0
  26. package/dist/adapters/openai-stream.js +120 -0
  27. package/dist/adapters/openai.d.ts +6 -0
  28. package/dist/adapters/openai.d.ts.map +1 -1
  29. package/dist/adapters/openai.js +60 -1
  30. package/dist/adapters/sampling.d.ts +28 -0
  31. package/dist/adapters/sampling.d.ts.map +1 -0
  32. package/dist/adapters/sampling.js +34 -0
  33. package/dist/adapters/tool-mapping.d.ts +92 -0
  34. package/dist/adapters/tool-mapping.d.ts.map +1 -0
  35. package/dist/adapters/tool-mapping.js +143 -0
  36. package/dist/artifacts/artifact.d.ts +137 -0
  37. package/dist/artifacts/artifact.d.ts.map +1 -0
  38. package/dist/artifacts/artifact.js +377 -0
  39. package/dist/artifacts/content-uploader.d.ts +87 -0
  40. package/dist/artifacts/content-uploader.d.ts.map +1 -0
  41. package/dist/artifacts/content-uploader.js +124 -0
  42. package/dist/artifacts/index.d.ts +63 -0
  43. package/dist/artifacts/index.d.ts.map +1 -0
  44. package/dist/artifacts/index.js +80 -0
  45. package/dist/artifacts/run-context.d.ts +129 -0
  46. package/dist/artifacts/run-context.d.ts.map +1 -0
  47. package/dist/artifacts/run-context.js +208 -0
  48. package/dist/artifacts/scrub.d.ts +60 -0
  49. package/dist/artifacts/scrub.d.ts.map +1 -0
  50. package/dist/artifacts/scrub.js +139 -0
  51. package/dist/artifacts/step.d.ts +26 -0
  52. package/dist/artifacts/step.d.ts.map +1 -0
  53. package/dist/artifacts/step.js +37 -0
  54. package/dist/artifacts/taint.d.ts +63 -0
  55. package/dist/artifacts/taint.d.ts.map +1 -0
  56. package/dist/artifacts/taint.js +76 -0
  57. package/dist/bakeoff/cache-sim.d.ts +99 -0
  58. package/dist/bakeoff/cache-sim.d.ts.map +1 -0
  59. package/dist/bakeoff/cache-sim.js +126 -0
  60. package/dist/bakeoff/eval-cases.d.ts +96 -0
  61. package/dist/bakeoff/eval-cases.d.ts.map +1 -0
  62. package/dist/bakeoff/eval-cases.js +105 -0
  63. package/dist/bakeoff/report.d.ts +41 -0
  64. package/dist/bakeoff/report.d.ts.map +1 -0
  65. package/dist/bakeoff/report.js +142 -0
  66. package/dist/bakeoff/samples.d.ts +15 -0
  67. package/dist/bakeoff/samples.d.ts.map +1 -1
  68. package/dist/bakeoff/samples.js +20 -0
  69. package/dist/cli.d.ts +1 -3
  70. package/dist/cli.d.ts.map +1 -1
  71. package/dist/cli.js +134 -116
  72. package/dist/config.d.ts +100 -0
  73. package/dist/config.d.ts.map +1 -1
  74. package/dist/config.js +104 -0
  75. package/dist/deprecations.d.ts +32 -0
  76. package/dist/deprecations.d.ts.map +1 -0
  77. package/dist/deprecations.js +59 -0
  78. package/dist/gateway/http-protocol.d.ts +175 -0
  79. package/dist/gateway/http-protocol.d.ts.map +1 -0
  80. package/dist/gateway/http-protocol.js +105 -0
  81. package/dist/index.d.ts +105 -18
  82. package/dist/index.d.ts.map +1 -1
  83. package/dist/index.js +266 -138
  84. package/dist/init/finder.d.ts +15 -0
  85. package/dist/init/finder.d.ts.map +1 -1
  86. package/dist/init/finder.js +46 -0
  87. package/dist/init/init-cli.d.ts +10 -0
  88. package/dist/init/init-cli.d.ts.map +1 -0
  89. package/dist/init/init-cli.js +86 -0
  90. package/dist/init/observe-cli.d.ts +19 -0
  91. package/dist/init/observe-cli.d.ts.map +1 -0
  92. package/dist/init/observe-cli.js +73 -0
  93. package/dist/init/observe.d.ts +81 -0
  94. package/dist/init/observe.d.ts.map +1 -0
  95. package/dist/init/observe.js +245 -0
  96. package/dist/registry/build.d.ts +94 -1
  97. package/dist/registry/build.d.ts.map +1 -1
  98. package/dist/registry/build.js +125 -4
  99. package/dist/registry/cache-policy.d.ts +94 -0
  100. package/dist/registry/cache-policy.d.ts.map +1 -0
  101. package/dist/registry/cache-policy.js +238 -0
  102. package/dist/registry/call-notes.d.ts.map +1 -1
  103. package/dist/registry/call-notes.js +40 -2
  104. package/dist/registry/effective-rate.d.ts +151 -0
  105. package/dist/registry/effective-rate.d.ts.map +1 -0
  106. package/dist/registry/effective-rate.js +156 -0
  107. package/dist/registry/facts.d.ts.map +1 -1
  108. package/dist/registry/facts.js +16 -0
  109. package/dist/registry/parity.d.ts +26 -0
  110. package/dist/registry/parity.d.ts.map +1 -1
  111. package/dist/registry/parity.js +43 -2
  112. package/dist/registry/pricing-shape.d.ts +113 -0
  113. package/dist/registry/pricing-shape.d.ts.map +1 -0
  114. package/dist/registry/pricing-shape.js +123 -0
  115. package/dist/registry/pricing.d.ts +25 -1
  116. package/dist/registry/pricing.d.ts.map +1 -1
  117. package/dist/registry/pricing.js +64 -6
  118. package/dist/rigindex/bootstrap.d.ts +36 -0
  119. package/dist/rigindex/bootstrap.d.ts.map +1 -0
  120. package/dist/rigindex/bootstrap.js +97 -0
  121. package/dist/rigindex/fit.d.ts +24 -0
  122. package/dist/rigindex/fit.d.ts.map +1 -0
  123. package/dist/rigindex/fit.js +76 -0
  124. package/dist/rigindex/gates.d.ts +52 -0
  125. package/dist/rigindex/gates.d.ts.map +1 -0
  126. package/dist/rigindex/gates.js +109 -0
  127. package/dist/rigindex/graph.d.ts +31 -0
  128. package/dist/rigindex/graph.d.ts.map +1 -0
  129. package/dist/rigindex/graph.js +120 -0
  130. package/dist/rigindex/index.d.ts +23 -0
  131. package/dist/rigindex/index.d.ts.map +1 -0
  132. package/dist/rigindex/index.js +112 -0
  133. package/dist/rigindex/types.d.ts +76 -0
  134. package/dist/rigindex/types.d.ts.map +1 -0
  135. package/dist/rigindex/types.js +8 -0
  136. package/dist/routes/cache-lint.d.ts +41 -0
  137. package/dist/routes/cache-lint.d.ts.map +1 -0
  138. package/dist/routes/cache-lint.js +81 -0
  139. package/dist/routes/loader.d.ts +37 -0
  140. package/dist/routes/loader.d.ts.map +1 -1
  141. package/dist/routes/loader.js +138 -0
  142. package/dist/routes/resolved-bundle.d.ts +79 -0
  143. package/dist/routes/resolved-bundle.d.ts.map +1 -0
  144. package/dist/routes/resolved-bundle.js +148 -0
  145. package/dist/routes/sampling-config.d.ts +32 -0
  146. package/dist/routes/sampling-config.d.ts.map +1 -0
  147. package/dist/routes/sampling-config.js +91 -0
  148. package/dist/run/ajv.d.ts +22 -0
  149. package/dist/run/ajv.d.ts.map +1 -0
  150. package/dist/run/ajv.js +32 -0
  151. package/dist/run/cache-handle.d.ts +58 -0
  152. package/dist/run/cache-handle.d.ts.map +1 -0
  153. package/dist/run/cache-handle.js +54 -0
  154. package/dist/run/cache-stamp.d.ts +65 -0
  155. package/dist/run/cache-stamp.d.ts.map +1 -0
  156. package/dist/run/cache-stamp.js +0 -0
  157. package/dist/run/capture-write.d.ts +33 -0
  158. package/dist/run/capture-write.d.ts.map +1 -0
  159. package/dist/run/capture-write.js +55 -0
  160. package/dist/run/cost.d.ts.map +1 -1
  161. package/dist/run/cost.js +1 -1
  162. package/dist/run/dispatch.d.ts +99 -0
  163. package/dist/run/dispatch.d.ts.map +1 -0
  164. package/dist/run/dispatch.js +191 -0
  165. package/dist/run/raw.d.ts +88 -0
  166. package/dist/run/raw.d.ts.map +1 -0
  167. package/dist/run/raw.js +286 -0
  168. package/dist/run/record-attempt.d.ts +40 -0
  169. package/dist/run/record-attempt.d.ts.map +1 -0
  170. package/dist/run/record-attempt.js +99 -0
  171. package/dist/run/resolve.d.ts +75 -2
  172. package/dist/run/resolve.d.ts.map +1 -1
  173. package/dist/run/resolve.js +126 -4
  174. package/dist/run/run.d.ts +14 -0
  175. package/dist/run/run.d.ts.map +1 -1
  176. package/dist/run/run.js +0 -0
  177. package/dist/run/stream.d.ts +49 -0
  178. package/dist/run/stream.d.ts.map +1 -0
  179. package/dist/run/stream.js +87 -0
  180. package/dist/run/validate.d.ts.map +1 -1
  181. package/dist/run/validate.js +6 -7
  182. package/dist/savings/cache-ledger.d.ts +108 -0
  183. package/dist/savings/cache-ledger.d.ts.map +1 -0
  184. package/dist/savings/cache-ledger.js +174 -0
  185. package/dist/savings/cache-reconcile.d.ts +64 -0
  186. package/dist/savings/cache-reconcile.d.ts.map +1 -0
  187. package/dist/savings/cache-reconcile.js +59 -0
  188. package/dist/savings/cache-stats.d.ts +63 -0
  189. package/dist/savings/cache-stats.d.ts.map +1 -0
  190. package/dist/savings/cache-stats.js +108 -0
  191. package/dist/savings/emit.d.ts +13 -0
  192. package/dist/savings/emit.d.ts.map +1 -1
  193. package/dist/savings/emit.js +25 -0
  194. package/dist/savings/swap-execute.d.ts +14 -0
  195. package/dist/savings/swap-execute.d.ts.map +1 -1
  196. package/dist/savings/swap-execute.js +44 -1
  197. package/dist/savings/swaps-client.d.ts +14 -0
  198. package/dist/savings/swaps-client.d.ts.map +1 -1
  199. package/dist/savings/swaps-client.js +16 -2
  200. package/dist/settings/api-fetcher.d.ts +39 -0
  201. package/dist/settings/api-fetcher.d.ts.map +1 -0
  202. package/dist/settings/api-fetcher.js +92 -0
  203. package/dist/settings/index.d.ts +10 -0
  204. package/dist/settings/index.d.ts.map +1 -0
  205. package/dist/settings/index.js +15 -0
  206. package/dist/settings/task-settings.d.ts +91 -0
  207. package/dist/settings/task-settings.d.ts.map +1 -0
  208. package/dist/settings/task-settings.js +116 -0
  209. package/dist/status.d.ts +77 -0
  210. package/dist/status.d.ts.map +1 -0
  211. package/dist/status.js +113 -0
  212. package/dist/telemetry/artifact-store.d.ts +48 -0
  213. package/dist/telemetry/artifact-store.d.ts.map +1 -0
  214. package/dist/telemetry/artifact-store.js +189 -0
  215. package/dist/telemetry/cache-miss-streak.d.ts +79 -0
  216. package/dist/telemetry/cache-miss-streak.d.ts.map +1 -0
  217. package/dist/telemetry/cache-miss-streak.js +99 -0
  218. package/dist/telemetry/capture.d.ts +3 -0
  219. package/dist/telemetry/capture.d.ts.map +1 -1
  220. package/dist/telemetry/capture.js +15 -8
  221. package/dist/telemetry/exporter-setup.d.ts +28 -0
  222. package/dist/telemetry/exporter-setup.d.ts.map +1 -0
  223. package/dist/telemetry/exporter-setup.js +34 -0
  224. package/dist/telemetry/exporter.d.ts +75 -0
  225. package/dist/telemetry/exporter.d.ts.map +1 -1
  226. package/dist/telemetry/exporter.js +324 -47
  227. package/dist/telemetry/health.d.ts +76 -0
  228. package/dist/telemetry/health.d.ts.map +1 -0
  229. package/dist/telemetry/health.js +92 -0
  230. package/dist/telemetry/ingest-protocol.d.ts +152 -3
  231. package/dist/telemetry/ingest-protocol.d.ts.map +1 -1
  232. package/dist/telemetry/ingest-protocol.js +204 -4
  233. package/dist/telemetry/load-error-report.d.ts +24 -0
  234. package/dist/telemetry/load-error-report.d.ts.map +1 -0
  235. package/dist/telemetry/load-error-report.js +50 -0
  236. package/dist/telemetry/otel-map.d.ts +121 -0
  237. package/dist/telemetry/otel-map.d.ts.map +1 -0
  238. package/dist/telemetry/otel-map.js +224 -0
  239. package/dist/telemetry/otel-normalize.d.ts +104 -0
  240. package/dist/telemetry/otel-normalize.d.ts.map +1 -0
  241. package/dist/telemetry/otel-normalize.js +530 -0
  242. package/dist/telemetry/otlp-emitter.d.ts +52 -0
  243. package/dist/telemetry/otlp-emitter.d.ts.map +1 -0
  244. package/dist/telemetry/otlp-emitter.js +144 -0
  245. package/dist/telemetry/otlp-proto.d.ts +29 -0
  246. package/dist/telemetry/otlp-proto.d.ts.map +1 -0
  247. package/dist/telemetry/otlp-proto.js +266 -0
  248. package/dist/telemetry/sinks.d.ts +37 -1
  249. package/dist/telemetry/sinks.d.ts.map +1 -1
  250. package/dist/telemetry/sinks.js +121 -30
  251. package/dist/telemetry/store.d.ts +28 -1
  252. package/dist/telemetry/store.d.ts.map +1 -1
  253. package/dist/telemetry/store.js +218 -3
  254. package/dist/tenancy/api-key-format.d.ts +15 -5
  255. package/dist/tenancy/api-key-format.d.ts.map +1 -1
  256. package/dist/tenancy/api-key-format.js +24 -5
  257. package/dist/types/config-teaching.d.ts +62 -0
  258. package/dist/types/config-teaching.d.ts.map +1 -0
  259. package/dist/types/config-teaching.js +183 -0
  260. package/dist/types/provider.d.ts +122 -1
  261. package/dist/types/provider.d.ts.map +1 -1
  262. package/dist/types/provider.js +21 -1
  263. package/dist/types/route.d.ts +79 -1
  264. package/dist/types/route.d.ts.map +1 -1
  265. package/dist/types/telemetry.d.ts +117 -0
  266. package/dist/types/telemetry.d.ts.map +1 -1
  267. package/dist/validate-cli.d.ts +12 -0
  268. package/dist/validate-cli.d.ts.map +1 -0
  269. package/dist/validate-cli.js +57 -0
  270. package/dist/verify/capture.d.ts +66 -0
  271. package/dist/verify/capture.d.ts.map +1 -0
  272. package/dist/verify/capture.js +180 -0
  273. package/dist/verify/cli-run.d.ts +23 -0
  274. package/dist/verify/cli-run.d.ts.map +1 -0
  275. package/dist/verify/cli-run.js +57 -0
  276. package/dist/verify/diff.d.ts +48 -0
  277. package/dist/verify/diff.d.ts.map +1 -0
  278. package/dist/verify/diff.js +157 -0
  279. package/dist/verify/index.d.ts +17 -0
  280. package/dist/verify/index.d.ts.map +1 -0
  281. package/dist/verify/index.js +24 -0
  282. package/dist/verify/report.d.ts +14 -0
  283. package/dist/verify/report.d.ts.map +1 -0
  284. package/dist/verify/report.js +88 -0
  285. package/dist/verify/types.d.ts +101 -0
  286. package/dist/verify/types.d.ts.map +1 -0
  287. package/dist/verify/types.js +17 -0
  288. package/dist/verify/verify.d.ts +29 -0
  289. package/dist/verify/verify.d.ts.map +1 -0
  290. package/dist/verify/verify.js +148 -0
  291. package/dist/watch/evaluate.d.ts +162 -3
  292. package/dist/watch/evaluate.d.ts.map +1 -1
  293. package/dist/watch/evaluate.js +61 -0
  294. package/dist/watch/monitor.d.ts +116 -0
  295. package/dist/watch/monitor.d.ts.map +1 -0
  296. package/dist/watch/monitor.js +199 -0
  297. package/dist/watch/proposals.d.ts +20 -4
  298. package/dist/watch/proposals.d.ts.map +1 -1
  299. package/dist/watch/proposals.js +31 -3
  300. package/dist/watch/run.d.ts +33 -0
  301. package/dist/watch/run.d.ts.map +1 -1
  302. package/dist/watch/run.js +39 -0
  303. package/package.json +7 -1
  304. package/registry/LICENSE +20 -0
  305. package/registry/leaderboard.json +3639 -0
  306. package/registry/registry.json +7263 -0
  307. package/dist/telemetry/supabase-exporter.d.ts +0 -64
  308. package/dist/telemetry/supabase-exporter.d.ts.map +0 -1
  309. package/dist/telemetry/supabase-exporter.js +0 -211
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ /**
3
+ * Load-error console reporting — follow-up #2.
4
+ *
5
+ * When a route bundle fails to load, tell the console WHY. `loadRoutes` throws
6
+ * before the exporter loop exists, so the run-loop path never gets a chance to
7
+ * mirror the failure. This sends a one-shot manifest batch carrying
8
+ * `describeConfigFailure(error)` onto `rig_manifests.load_errors`, which drives
9
+ * /setup's "Define your first route" step to `failed` with what we looked for
10
+ * and what we found.
11
+ *
12
+ * Fire-and-forget, and best-effort by design: `createRig` is synchronous and
13
+ * re-throws (the rig genuinely cannot run), and telemetry must never change the
14
+ * error the caller sees. KNOWN LIMITATION: this only reaches the console once
15
+ * the app runs with an export configured (MODELRIG_API_KEY / direct creds); a
16
+ * first-timer who hasn't connected yet still gets the full diagnosis at their
17
+ * terminal via `renderConfigErrorForTerminal`.
18
+ *
19
+ * Lives here rather than in index.ts to keep that file under the LOC cap (P1) —
20
+ * the same relocation `buildTelemetrySink` made to `sinks.ts`.
21
+ */
22
+ Object.defineProperty(exports, "__esModule", { value: true });
23
+ exports.reportLoadError = reportLoadError;
24
+ const node_path_1 = require("node:path");
25
+ const node_os_1 = require("node:os");
26
+ const manifest_1 = require("../routes/manifest");
27
+ const config_teaching_1 = require("../types/config-teaching");
28
+ const exporter_1 = require("./exporter");
29
+ const sinks_1 = require("./sinks");
30
+ function reportLoadError(config, error) {
31
+ if (config.export === undefined)
32
+ return;
33
+ const sourceId = config.export.sourceId ?? (0, node_os_1.hostname)();
34
+ // rig.yaml can load fine even when a route bundle can't — carry its
35
+ // name/dimensions/contribution so the reporting upsert doesn't blank them.
36
+ let manifestMeta = null;
37
+ try {
38
+ manifestMeta = (0, manifest_1.loadManifest)((0, node_path_1.dirname)(config.routesDir));
39
+ }
40
+ catch {
41
+ // rig.yaml is itself broken/absent; fall back to source-id naming so the
42
+ // row still lands and the console still learns of the failure.
43
+ }
44
+ const sink = (0, sinks_1.buildTelemetrySink)(config.export, sourceId);
45
+ const batch = (0, exporter_1.buildLoadErrorBatch)(sourceId, manifestMeta, [(0, config_teaching_1.describeConfigFailure)(error)]);
46
+ void sink.send(batch).catch((err) => {
47
+ console.warn(`[modelrig] could not report the route load error to the console: ` +
48
+ `${err instanceof Error ? err.message : String(err)}`);
49
+ });
50
+ }
@@ -0,0 +1,121 @@
1
+ /**
2
+ * OTLP mapping — E1 (spec §3, §4). PURE: no I/O, no env, no imports from the
3
+ * exporter/sinks/store. One `inferences` row → one OTLP/HTTP JSON span.
4
+ *
5
+ * ── THE ONE PLACE gen_ai.* NAMES LIVE ────────────────────────────────────
6
+ * Every OpenTelemetry semantic-convention attribute name this product emits is
7
+ * declared in THIS module and nowhere else (architect-review-2026-08 §2(f)).
8
+ * The pin is `SEMCONV_VERSION` below — bump it here and the wire changes in one
9
+ * edit, not scattered across the codebase. If you find a `"gen_ai.*"` string
10
+ * literal outside this file, it is a bug.
11
+ *
12
+ * ── WHY HAND-BUILT JSON, NOT @opentelemetry/* ────────────────────────────
13
+ * We are mapping completed rows, not instrumenting live code, so the SDK's
14
+ * tracer runtime would be dead weight (spec §2.2). The shape below is the
15
+ * OTLP/HTTP `ExportTraceServiceRequest` JSON encoding. Two encoding rules bite
16
+ * here and are easy to get wrong (plan §"risks"):
17
+ * • trace_id / span_id are LOWERCASE HEX strings — the documented OTLP/JSON
18
+ * exception to Protobuf's base64-for-bytes. NOT base64.
19
+ * • int64 attribute + timestamp values are DECIMAL STRINGS; doubles are
20
+ * numbers. `intValue`/`startTimeUnixNano` are strings on the wire.
21
+ */
22
+ import type { TelemetryRow } from "../types/telemetry";
23
+ import type { CacheContext } from "../watch/evaluate";
24
+ /** Semantic-conventions pin (architect ruling §2(f)). The scope version on the
25
+ * wire and the single source of truth for which gen_ai vintage we speak. */
26
+ export declare const SEMCONV_VERSION = "1.41.0";
27
+ /** STATUS_CODE_UNSET / STATUS_CODE_ERROR (OK is never set — gen_ai convention
28
+ * leaves a successful span UNSET). */
29
+ declare const STATUS_UNSET = 0;
30
+ declare const STATUS_ERROR = 2;
31
+ export type OtlpAnyValue = {
32
+ readonly stringValue: string;
33
+ } | {
34
+ readonly intValue: string;
35
+ } | {
36
+ readonly doubleValue: number;
37
+ } | {
38
+ readonly boolValue: boolean;
39
+ };
40
+ export interface OtlpAttribute {
41
+ readonly key: string;
42
+ readonly value: OtlpAnyValue;
43
+ }
44
+ export interface OtlpStatus {
45
+ readonly code: typeof STATUS_UNSET | typeof STATUS_ERROR;
46
+ readonly message?: string;
47
+ }
48
+ export interface OtlpSpanJson {
49
+ /** 32 lowercase hex chars (16 bytes). */
50
+ readonly traceId: string;
51
+ /** 16 lowercase hex chars (8 bytes). */
52
+ readonly spanId: string;
53
+ /** 16 lowercase hex chars — present only when a caller traceparent nests us. */
54
+ readonly parentSpanId?: string;
55
+ readonly name: string;
56
+ readonly kind: number;
57
+ readonly startTimeUnixNano: string;
58
+ readonly endTimeUnixNano: string;
59
+ readonly attributes: readonly OtlpAttribute[];
60
+ readonly status: OtlpStatus;
61
+ }
62
+ export interface OtlpResource {
63
+ readonly serviceName: string;
64
+ /** Optional extra resource attributes (e.g. deployment.environment). */
65
+ readonly attributes?: readonly OtlpAttribute[];
66
+ }
67
+ export interface ExportTraceServiceRequestJson {
68
+ readonly resourceSpans: ReadonlyArray<{
69
+ readonly resource: {
70
+ readonly attributes: readonly OtlpAttribute[];
71
+ };
72
+ readonly scopeSpans: ReadonlyArray<{
73
+ readonly scope: {
74
+ readonly name: string;
75
+ readonly version: string;
76
+ };
77
+ readonly spans: readonly OtlpSpanJson[];
78
+ }>;
79
+ }>;
80
+ }
81
+ /** The tag key the gateway stashes an inbound traceparent under (spec §2.5). */
82
+ export declare const TRACEPARENT_TAG = "otel.traceparent";
83
+ export interface Traceparent {
84
+ /** Caller's trace id — the emitted span joins this trace. */
85
+ readonly traceId: string;
86
+ /** Caller's span id — the emitted span's parent. */
87
+ readonly parentSpanId: string;
88
+ }
89
+ /**
90
+ * Parse a W3C `traceparent` value, or null when absent/malformed. The gateway
91
+ * (packages/modelrig-server) reuses this so the SDK and the server cannot
92
+ * disagree about what "well-formed" means. All-zero trace/parent ids are
93
+ * rejected per the W3C spec (they mean "no parent").
94
+ */
95
+ export declare function parseTraceparent(value: string | undefined | null): Traceparent | null;
96
+ /**
97
+ * Map one telemetry row to one OTLP span (spec §3, normative). Pure and total:
98
+ * every field comes from the row; nulls are omitted (never emitted as empty).
99
+ */
100
+ export declare function inferenceToSpan(row: TelemetryRow): OtlpSpanJson;
101
+ /**
102
+ * Decision-span attributes for a cache-aware routing decision (cache-aware-routing
103
+ * spec §5.5 — "routing must never be opaque"). Returns the `modelrig.cache.*`
104
+ * attribute set a caller attaches to the swap/proposal decision span so the
105
+ * verdict + its economics travel to any OTLP backend alongside the inference
106
+ * spans. Declared HERE because this module is the one place OTLP attribute names
107
+ * live (the pin at the top of this file).
108
+ *
109
+ * `breakeven_conformant_calls` can be `Infinity` ("never breaks even"), which is
110
+ * not a valid JSON number — so it is emitted as a double ONLY when finite, and a
111
+ * boolean `modelrig.cache.breakeven_reachable` records the never-case explicitly
112
+ * rather than dropping the fact.
113
+ */
114
+ export declare function cacheDecisionSpanAttributes(ctx: CacheContext): OtlpAttribute[];
115
+ /**
116
+ * Wrap spans in the OTLP `ExportTraceServiceRequest` envelope (spec §4, pure).
117
+ * One resource, one scope (`modelrig` @ SEMCONV_VERSION), N spans.
118
+ */
119
+ export declare function buildExportTraceRequest(spans: readonly OtlpSpanJson[], resource: OtlpResource): ExportTraceServiceRequestJson;
120
+ export {};
121
+ //# sourceMappingURL=otel-map.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"otel-map.d.ts","sourceRoot":"","sources":["../../src/telemetry/otel-map.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,224 @@
1
+ "use strict";
2
+ /**
3
+ * OTLP mapping — E1 (spec §3, §4). PURE: no I/O, no env, no imports from the
4
+ * exporter/sinks/store. One `inferences` row → one OTLP/HTTP JSON span.
5
+ *
6
+ * ── THE ONE PLACE gen_ai.* NAMES LIVE ────────────────────────────────────
7
+ * Every OpenTelemetry semantic-convention attribute name this product emits is
8
+ * declared in THIS module and nowhere else (architect-review-2026-08 §2(f)).
9
+ * The pin is `SEMCONV_VERSION` below — bump it here and the wire changes in one
10
+ * edit, not scattered across the codebase. If you find a `"gen_ai.*"` string
11
+ * literal outside this file, it is a bug.
12
+ *
13
+ * ── WHY HAND-BUILT JSON, NOT @opentelemetry/* ────────────────────────────
14
+ * We are mapping completed rows, not instrumenting live code, so the SDK's
15
+ * tracer runtime would be dead weight (spec §2.2). The shape below is the
16
+ * OTLP/HTTP `ExportTraceServiceRequest` JSON encoding. Two encoding rules bite
17
+ * here and are easy to get wrong (plan §"risks"):
18
+ * • trace_id / span_id are LOWERCASE HEX strings — the documented OTLP/JSON
19
+ * exception to Protobuf's base64-for-bytes. NOT base64.
20
+ * • int64 attribute + timestamp values are DECIMAL STRINGS; doubles are
21
+ * numbers. `intValue`/`startTimeUnixNano` are strings on the wire.
22
+ */
23
+ Object.defineProperty(exports, "__esModule", { value: true });
24
+ exports.TRACEPARENT_TAG = exports.SEMCONV_VERSION = void 0;
25
+ exports.parseTraceparent = parseTraceparent;
26
+ exports.inferenceToSpan = inferenceToSpan;
27
+ exports.cacheDecisionSpanAttributes = cacheDecisionSpanAttributes;
28
+ exports.buildExportTraceRequest = buildExportTraceRequest;
29
+ const node_crypto_1 = require("node:crypto");
30
+ /** Semantic-conventions pin (architect ruling §2(f)). The scope version on the
31
+ * wire and the single source of truth for which gen_ai vintage we speak. */
32
+ exports.SEMCONV_VERSION = "1.41.0";
33
+ /** SPAN_KIND_CLIENT — an LLM call leaving this process to a provider. */
34
+ const SPAN_KIND_CLIENT = 3;
35
+ /** SPAN_KIND_INTERNAL — the synthetic search/tool-execution span. */
36
+ const SPAN_KIND_INTERNAL = 1;
37
+ /** STATUS_CODE_UNSET / STATUS_CODE_ERROR (OK is never set — gen_ai convention
38
+ * leaves a successful span UNSET). */
39
+ const STATUS_UNSET = 0;
40
+ const STATUS_ERROR = 2;
41
+ // ── attribute constructors (typed value wrappers) ────────────────────────
42
+ const strAttr = (key, value) => ({ key, value: { stringValue: value } });
43
+ const intAttr = (key, value) => ({
44
+ key,
45
+ value: { intValue: String(Math.trunc(value)) },
46
+ });
47
+ const dblAttr = (key, value) => ({ key, value: { doubleValue: value } });
48
+ const boolAttr = (key, value) => ({ key, value: { boolValue: value } });
49
+ // ── W3C traceparent ──────────────────────────────────────────────────────
50
+ /** The tag key the gateway stashes an inbound traceparent under (spec §2.5). */
51
+ exports.TRACEPARENT_TAG = "otel.traceparent";
52
+ /** version(00) - trace-id(32hex) - parent-id(16hex) - flags(2hex). */
53
+ const TRACEPARENT_RE = /^00-([0-9a-f]{32})-([0-9a-f]{16})-[0-9a-f]{2}$/i;
54
+ /**
55
+ * Parse a W3C `traceparent` value, or null when absent/malformed. The gateway
56
+ * (packages/modelrig-server) reuses this so the SDK and the server cannot
57
+ * disagree about what "well-formed" means. All-zero trace/parent ids are
58
+ * rejected per the W3C spec (they mean "no parent").
59
+ */
60
+ function parseTraceparent(value) {
61
+ if (value === undefined || value === null)
62
+ return null;
63
+ const match = TRACEPARENT_RE.exec(value.trim());
64
+ if (match === null)
65
+ return null;
66
+ const traceId = match[1].toLowerCase();
67
+ const parentSpanId = match[2].toLowerCase();
68
+ if (/^0+$/.test(traceId) || /^0+$/.test(parentSpanId))
69
+ return null;
70
+ return { traceId, parentSpanId };
71
+ }
72
+ // ── deterministic span identity (spec §2.6) ──────────────────────────────
73
+ // Same row twice ⇒ byte-identical span, so a re-emit after a crash is
74
+ // idempotent at the sink. Both are truncations of sha256(inference id).
75
+ function sha256Hex(input) {
76
+ return (0, node_crypto_1.createHash)("sha256").update(input).digest("hex");
77
+ }
78
+ function traceIdFor(inferenceId) {
79
+ return sha256Hex(inferenceId).slice(0, 32); // 16 bytes
80
+ }
81
+ function spanIdFor(inferenceId) {
82
+ return sha256Hex(inferenceId).slice(0, 16); // 8 bytes
83
+ }
84
+ /** ISO timestamp (+ optional ms offset) → OTLP `*UnixNano` decimal string.
85
+ * BigInt keeps nanosecond precision that Number would lose past 2^53. */
86
+ function toUnixNano(iso, plusMs = 0) {
87
+ const ms = Date.parse(iso);
88
+ const baseMs = Number.isFinite(ms) ? ms : 0;
89
+ return (BigInt(baseMs + Math.trunc(plusMs)) * 1000000n).toString();
90
+ }
91
+ /** The synthetic search-cost row is emitted as a tool-execution span (§2.7). */
92
+ function isSearchRow(row) {
93
+ return row.provider === "search";
94
+ }
95
+ function readTraceparentTag(row) {
96
+ let tags;
97
+ try {
98
+ tags = JSON.parse(row.tagsJson);
99
+ }
100
+ catch {
101
+ return null;
102
+ }
103
+ if (tags === null || typeof tags !== "object")
104
+ return null;
105
+ const raw = tags[exports.TRACEPARENT_TAG];
106
+ return typeof raw === "string" ? parseTraceparent(raw) : null;
107
+ }
108
+ /**
109
+ * Map one telemetry row to one OTLP span (spec §3, normative). Pure and total:
110
+ * every field comes from the row; nulls are omitted (never emitted as empty).
111
+ */
112
+ function inferenceToSpan(row) {
113
+ const search = isSearchRow(row);
114
+ const operationName = search ? "execute_tool" : "chat";
115
+ const spanName = search ? "execute_tool search" : `chat ${row.model}`;
116
+ const attrs = [
117
+ strAttr("gen_ai.operation.name", operationName),
118
+ strAttr("gen_ai.provider.name", row.provider),
119
+ strAttr("gen_ai.request.model", row.model),
120
+ strAttr("gen_ai.response.model", row.model),
121
+ intAttr("gen_ai.usage.input_tokens", row.tokensIn),
122
+ intAttr("gen_ai.usage.output_tokens", row.tokensOut),
123
+ intAttr("gen_ai.usage.cached_input_tokens", row.tokensCached),
124
+ strAttr("modelrig.route", row.route),
125
+ intAttr("modelrig.route_version", row.routeVersion),
126
+ // Honest zero: cost stays 0 for an unpriced model; the flag says so rather
127
+ // than the code inventing a dollar figure (spec §3, addendum A1).
128
+ dblAttr("modelrig.cost_estimate_usd", row.costEstimateUsd),
129
+ strAttr("modelrig.served_tier", row.servedTier),
130
+ ];
131
+ // Cache accounting (WS-A / E1 parity). Emitted only when non-zero to keep the
132
+ // vast majority of spans lean. `cache_read_tokens` carries the same quantity
133
+ // as the pre-existing `cached_input_tokens` under the spelling the cache-aware
134
+ // spec (§2) names; both are kept — S3 retires nothing, and a consumer reads a
135
+ // specific key rather than summing, so this is detail, not double-count.
136
+ if (row.tokensCached > 0)
137
+ attrs.push(intAttr("gen_ai.usage.cache_read_tokens", row.tokensCached));
138
+ const cacheWrite = row.tokensCacheWrite ?? 0;
139
+ if (cacheWrite > 0)
140
+ attrs.push(intAttr("gen_ai.usage.cache_creation_tokens", cacheWrite));
141
+ if (row.pricingMissing)
142
+ attrs.push(boolAttr("modelrig.pricing_missing", true));
143
+ if (row.ttfbMs !== null)
144
+ attrs.push(intAttr("modelrig.ttfb_ms", row.ttfbMs));
145
+ if (row.servedVariant !== null)
146
+ attrs.push(strAttr("modelrig.served_variant", row.servedVariant));
147
+ if (row.repairedBy !== null)
148
+ attrs.push(strAttr("modelrig.repaired_by", row.repairedBy));
149
+ if (row.fingerprintCell !== null) {
150
+ // Irreversible by construction (a schema hash) — safe to emit (spec §3).
151
+ attrs.push(strAttr("modelrig.fingerprint_cell", row.fingerprintCell));
152
+ }
153
+ if (row.failureClass !== null)
154
+ attrs.push(strAttr("modelrig.failure_class", row.failureClass));
155
+ const parent = readTraceparentTag(row);
156
+ const traceId = parent !== null ? parent.traceId : traceIdFor(row.id);
157
+ const span = {
158
+ traceId,
159
+ spanId: spanIdFor(row.id),
160
+ ...(parent !== null ? { parentSpanId: parent.parentSpanId } : {}),
161
+ name: spanName,
162
+ kind: search ? SPAN_KIND_INTERNAL : SPAN_KIND_CLIENT,
163
+ startTimeUnixNano: toUnixNano(row.ts),
164
+ endTimeUnixNano: toUnixNano(row.ts, row.latencyMs),
165
+ attributes: attrs,
166
+ // Failures are facts: a non-null class flips the span to ERROR (spec §2.7).
167
+ status: row.failureClass !== null
168
+ ? { code: STATUS_ERROR, message: row.failureClass }
169
+ : { code: STATUS_UNSET },
170
+ };
171
+ return span;
172
+ }
173
+ /**
174
+ * Decision-span attributes for a cache-aware routing decision (cache-aware-routing
175
+ * spec §5.5 — "routing must never be opaque"). Returns the `modelrig.cache.*`
176
+ * attribute set a caller attaches to the swap/proposal decision span so the
177
+ * verdict + its economics travel to any OTLP backend alongside the inference
178
+ * spans. Declared HERE because this module is the one place OTLP attribute names
179
+ * live (the pin at the top of this file).
180
+ *
181
+ * `breakeven_conformant_calls` can be `Infinity` ("never breaks even"), which is
182
+ * not a valid JSON number — so it is emitted as a double ONLY when finite, and a
183
+ * boolean `modelrig.cache.breakeven_reachable` records the never-case explicitly
184
+ * rather than dropping the fact.
185
+ */
186
+ function cacheDecisionSpanAttributes(ctx) {
187
+ const attrs = [
188
+ strAttr("modelrig.cache.verdict", ctx.verdict),
189
+ dblAttr("modelrig.cache.observed_hit_rate", ctx.observed_hit_rate),
190
+ dblAttr("modelrig.cache.observed_write_rate", ctx.observed_write_rate),
191
+ intAttr("modelrig.cache.window_days", ctx.window_days),
192
+ dblAttr("modelrig.cache.incumbent_effective_in_per_mtok", ctx.incumbent_effective_in_per_mtok),
193
+ dblAttr("modelrig.cache.challenger_cold_in_per_mtok", ctx.challenger_cold_in_per_mtok),
194
+ dblAttr("modelrig.cache.switch_cost_usd", ctx.switch_cost_usd),
195
+ dblAttr("modelrig.cache.cache_option_value_usd", ctx.cache_option_value_usd),
196
+ ];
197
+ const reachable = Number.isFinite(ctx.breakeven_conformant_calls);
198
+ attrs.push(boolAttr("modelrig.cache.breakeven_reachable", reachable));
199
+ if (reachable) {
200
+ attrs.push(dblAttr("modelrig.cache.breakeven_conformant_calls", ctx.breakeven_conformant_calls));
201
+ }
202
+ return attrs;
203
+ }
204
+ /**
205
+ * Wrap spans in the OTLP `ExportTraceServiceRequest` envelope (spec §4, pure).
206
+ * One resource, one scope (`modelrig` @ SEMCONV_VERSION), N spans.
207
+ */
208
+ function buildExportTraceRequest(spans, resource) {
209
+ return {
210
+ resourceSpans: [
211
+ {
212
+ resource: {
213
+ attributes: [strAttr("service.name", resource.serviceName), ...(resource.attributes ?? [])],
214
+ },
215
+ scopeSpans: [
216
+ {
217
+ scope: { name: "modelrig", version: exports.SEMCONV_VERSION },
218
+ spans,
219
+ },
220
+ ],
221
+ },
222
+ ],
223
+ };
224
+ }
@@ -0,0 +1,104 @@
1
+ /**
2
+ * OTLP-in v0 normalizer — Expansion E3-Harvest (spec §3). PURE: no I/O, no env,
3
+ * no imports from the exporter/sinks/server. The INBOUND sibling of `otel-map.ts`
4
+ * (which is the OUTBOUND our-rows → OTLP mapper). Foreign OTLP spans in →
5
+ * `runs` + attested `steps` out.
6
+ *
7
+ * ── SCOPE (spec §3.1): identity, structure, timing, status, model/provider,
8
+ * usage ONLY. ZERO content extraction — prompts/completions/messages in foreign
9
+ * spans are never read, never stored, never passed to the envelope. Retention-
10
+ * free default; content custody arrives with E2-C. This deletes ~60% of
11
+ * Langfuse's problem surface deliberately.
12
+ *
13
+ * ── VINTAGE HANDLING is pure NAME-UNION, not versioned dispatch (learnings
14
+ * §1.1, their proven approach), with our two divergences (spec §3.3):
15
+ * (1) namespaced attributes outrank bare ones — `gen_ai.*`/`llm.*` are checked
16
+ * BEFORE a bare `model`;
17
+ * (2) provider IS normalized (Langfuse never reads provider on ingest), because
18
+ * `model_key = provider/model` feeds our registry/priors/leaderboard —
19
+ * recorded honestly, ending at "unknown", never guessed.
20
+ *
21
+ * The usage de-double-counting and the agent-span aggregate skip are adopted
22
+ * from OtelIngestionProcessor's generic extractor (learnings §1.2, read for
23
+ * pattern per §5.3 — implemented fresh here, no bodies copied).
24
+ */
25
+ import type { WireRun, WireStep } from "./ingest-protocol";
26
+ export interface AttestedUsage {
27
+ /** Non-cached input tokens (cache buckets subtracted, floored 0). */
28
+ readonly input?: number;
29
+ /** Non-reasoning/-audio output tokens (subtracted, floored 0). */
30
+ readonly output?: number;
31
+ readonly total?: number;
32
+ readonly input_cached_tokens?: number;
33
+ readonly input_cache_creation?: number;
34
+ readonly output_reasoning_tokens?: number;
35
+ readonly output_audio_tokens?: number;
36
+ /** Any other gen_ai.usage.* / llm.token_count.* bucket, name preserved. */
37
+ readonly [bucket: string]: number | undefined;
38
+ }
39
+ export interface AttestedEnvelope {
40
+ /** Resolved model, or null when no model attribute was present. */
41
+ readonly model: string | null;
42
+ /** Resolved provider — honest, ending at "unknown", NEVER guessed. */
43
+ readonly provider: string;
44
+ /** Classified operation (generation/tool/agent/retriever/embedding/span). */
45
+ readonly operation: string;
46
+ /** De-double-counted usage; omitted entirely on agent-aggregate spans. */
47
+ readonly usage?: AttestedUsage;
48
+ /** The emitting instrumentation scope (name + optional version). */
49
+ readonly scope: {
50
+ readonly name: string;
51
+ readonly version: string | null;
52
+ };
53
+ }
54
+ type OtlpAnyValueIn = Record<string, unknown>;
55
+ interface OtlpKeyValueIn {
56
+ key?: string;
57
+ value?: OtlpAnyValueIn;
58
+ }
59
+ /** What a decoded span looks like to us (both transports converge here). */
60
+ export interface OtlpSpanIn {
61
+ traceId?: unknown;
62
+ trace_id?: unknown;
63
+ spanId?: unknown;
64
+ span_id?: unknown;
65
+ parentSpanId?: unknown;
66
+ parent_span_id?: unknown;
67
+ name?: unknown;
68
+ kind?: unknown;
69
+ startTimeUnixNano?: unknown;
70
+ start_time_unix_nano?: unknown;
71
+ endTimeUnixNano?: unknown;
72
+ end_time_unix_nano?: unknown;
73
+ attributes?: OtlpKeyValueIn[];
74
+ status?: {
75
+ code?: unknown;
76
+ message?: unknown;
77
+ };
78
+ }
79
+ export interface NormalizeResult {
80
+ readonly runs: WireRun[];
81
+ /** Attested steps (each carries the `attested` envelope). */
82
+ readonly steps: WireStep[];
83
+ /** reason → count (bad_otlp_span, unmapped_attribute, ts_copied_edge, …). */
84
+ readonly drops: Record<string, number>;
85
+ /** Total spans seen (before drops) — for the conversion-failure log. */
86
+ readonly spanCount: number;
87
+ /** Distinct instrumentation-scope names seen — named in the logs-mistake 400. */
88
+ readonly scopeNames: string[];
89
+ }
90
+ /**
91
+ * Normalize a decoded OTLP `TracesData` structure into runs + attested steps.
92
+ * Total and defensive: a malformed span is dropped-and-counted, never thrown.
93
+ * `nowMs` is injected so callers/tests are deterministic (default Date.now()).
94
+ */
95
+ export declare function normalizeOtlpTraces(data: unknown, nowMs?: number): NormalizeResult;
96
+ /**
97
+ * Logs-exporter detection (learnings §1.2). ResourceLogs and ResourceSpans share
98
+ * protobuf field numbers, so a logs exporter pointed at the traces endpoint
99
+ * decodes as id-less "spans". A JSON logs body carries `resourceLogs` outright.
100
+ * Returns true when the body is a logs payload that must be rejected 400.
101
+ */
102
+ export declare function looksLikeLogsPayload(data: unknown): boolean;
103
+ export {};
104
+ //# sourceMappingURL=otel-normalize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"otel-normalize.d.ts","sourceRoot":"","sources":["../../src/telemetry/otel-normalize.ts"],"names":[],"mappings":"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"}