modelrig 0.9.0 → 0.11.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 (231) hide show
  1. package/CHANGELOG.md +227 -0
  2. package/README.md +51 -27
  3. package/data/PROVENANCE.md +14 -0
  4. package/data/pricing-map.json +26 -0
  5. package/dist/adapters/attempt-meta-map.d.ts +8 -1
  6. package/dist/adapters/attempt-meta-map.d.ts.map +1 -1
  7. package/dist/adapters/attempt-meta-map.js +4 -0
  8. package/dist/adapters/build-adapters.js +2 -2
  9. package/dist/adapters/gemini.d.ts +28 -1
  10. package/dist/adapters/gemini.d.ts.map +1 -1
  11. package/dist/adapters/gemini.js +38 -9
  12. package/dist/adapters/grok.d.ts.map +1 -1
  13. package/dist/adapters/grok.js +53 -4
  14. package/dist/adapters/openai-compat.d.ts +8 -2
  15. package/dist/adapters/openai-compat.d.ts.map +1 -1
  16. package/dist/adapters/openai-compat.js +8 -1
  17. package/dist/adapters/openai-stream.d.ts +10 -2
  18. package/dist/adapters/openai-stream.d.ts.map +1 -1
  19. package/dist/adapters/openai-stream.js +5 -1
  20. package/dist/adapters/openai.d.ts +10 -1
  21. package/dist/adapters/openai.d.ts.map +1 -1
  22. package/dist/adapters/openai.js +57 -7
  23. package/dist/adapters/responses-api.d.ts +61 -0
  24. package/dist/adapters/responses-api.d.ts.map +1 -0
  25. package/dist/adapters/responses-api.js +124 -0
  26. package/dist/artifacts/artifact.d.ts +20 -0
  27. package/dist/artifacts/artifact.d.ts.map +1 -1
  28. package/dist/artifacts/artifact.js +207 -171
  29. package/dist/artifacts/index.d.ts +3 -1
  30. package/dist/artifacts/index.d.ts.map +1 -1
  31. package/dist/artifacts/index.js +8 -1
  32. package/dist/bakeoff/groundedness.d.ts +58 -0
  33. package/dist/bakeoff/groundedness.d.ts.map +1 -0
  34. package/dist/bakeoff/groundedness.js +165 -0
  35. package/dist/bakeoff/quality.d.ts +14 -1
  36. package/dist/bakeoff/quality.d.ts.map +1 -1
  37. package/dist/bakeoff/quality.js +10 -0
  38. package/dist/bakeoff/replay.d.ts.map +1 -1
  39. package/dist/bakeoff/replay.js +4 -0
  40. package/dist/cli.d.ts.map +1 -1
  41. package/dist/cli.js +8 -0
  42. package/dist/config.d.ts +31 -0
  43. package/dist/config.d.ts.map +1 -1
  44. package/dist/config.js +23 -0
  45. package/dist/doctor-cli.d.ts +7 -0
  46. package/dist/doctor-cli.d.ts.map +1 -0
  47. package/dist/doctor-cli.js +68 -0
  48. package/dist/doctor-preflight.d.ts +64 -0
  49. package/dist/doctor-preflight.d.ts.map +1 -0
  50. package/dist/doctor-preflight.js +167 -0
  51. package/dist/feedback/coverage.d.ts.map +1 -1
  52. package/dist/feedback/coverage.js +9 -2
  53. package/dist/feedback/grade.d.ts +8 -1
  54. package/dist/feedback/grade.d.ts.map +1 -1
  55. package/dist/feedback/grade.js +4 -0
  56. package/dist/gateway/http-protocol.d.ts +19 -0
  57. package/dist/gateway/http-protocol.d.ts.map +1 -1
  58. package/dist/gateway/serve-client.d.ts +99 -0
  59. package/dist/gateway/serve-client.d.ts.map +1 -0
  60. package/dist/gateway/serve-client.js +360 -0
  61. package/dist/index.d.ts +31 -3
  62. package/dist/index.d.ts.map +1 -1
  63. package/dist/index.js +71 -8
  64. package/dist/prompts/manifest.d.ts +128 -0
  65. package/dist/prompts/manifest.d.ts.map +1 -0
  66. package/dist/prompts/manifest.js +214 -0
  67. package/dist/prompts/prompt-fetch.d.ts +84 -0
  68. package/dist/prompts/prompt-fetch.d.ts.map +1 -0
  69. package/dist/prompts/prompt-fetch.js +120 -0
  70. package/dist/prompts/prompt-resolve.d.ts +76 -0
  71. package/dist/prompts/prompt-resolve.d.ts.map +1 -0
  72. package/dist/prompts/prompt-resolve.js +93 -0
  73. package/dist/prompts/slot-resolver.d.ts +91 -0
  74. package/dist/prompts/slot-resolver.d.ts.map +1 -0
  75. package/dist/prompts/slot-resolver.js +135 -0
  76. package/dist/prompts/tools-register.d.ts +60 -0
  77. package/dist/prompts/tools-register.d.ts.map +1 -0
  78. package/dist/prompts/tools-register.js +48 -0
  79. package/dist/prompts/version-hash.d.ts +29 -0
  80. package/dist/prompts/version-hash.d.ts.map +1 -0
  81. package/dist/prompts/version-hash.js +54 -0
  82. package/dist/prompts-export-cli.d.ts +21 -0
  83. package/dist/prompts-export-cli.d.ts.map +1 -0
  84. package/dist/prompts-export-cli.js +130 -0
  85. package/dist/registry/cache-policy.d.ts.map +1 -1
  86. package/dist/registry/cache-policy.js +22 -0
  87. package/dist/registry/pricing-shape.d.ts +38 -8
  88. package/dist/registry/pricing-shape.d.ts.map +1 -1
  89. package/dist/registry/pricing-shape.js +40 -12
  90. package/dist/registry/pricing.d.ts +6 -5
  91. package/dist/registry/pricing.d.ts.map +1 -1
  92. package/dist/registry/pricing.js +9 -5
  93. package/dist/routes/destination-loader.d.ts +16 -0
  94. package/dist/routes/destination-loader.d.ts.map +1 -0
  95. package/dist/routes/destination-loader.js +29 -0
  96. package/dist/routes/draft.d.ts +7 -0
  97. package/dist/routes/draft.d.ts.map +1 -1
  98. package/dist/routes/draft.js +12 -0
  99. package/dist/routes/loader.d.ts.map +1 -1
  100. package/dist/routes/loader.js +27 -54
  101. package/dist/routes/output-loader.d.ts +42 -0
  102. package/dist/routes/output-loader.d.ts.map +1 -0
  103. package/dist/routes/output-loader.js +112 -0
  104. package/dist/routes/prompt-loader.d.ts +49 -0
  105. package/dist/routes/prompt-loader.d.ts.map +1 -0
  106. package/dist/routes/prompt-loader.js +113 -0
  107. package/dist/routes/resolved-bundle.d.ts +19 -0
  108. package/dist/routes/resolved-bundle.d.ts.map +1 -1
  109. package/dist/routes/resolved-bundle.js +24 -0
  110. package/dist/routes/screen-loader.d.ts +1 -1
  111. package/dist/routes/screen-loader.d.ts.map +1 -1
  112. package/dist/routes/screen-loader.js +8 -1
  113. package/dist/run/accept.d.ts +3 -0
  114. package/dist/run/accept.d.ts.map +1 -1
  115. package/dist/run/accept.js +1 -0
  116. package/dist/run/cost.d.ts +31 -2
  117. package/dist/run/cost.d.ts.map +1 -1
  118. package/dist/run/cost.js +57 -2
  119. package/dist/run/destination.d.ts +39 -0
  120. package/dist/run/destination.d.ts.map +1 -0
  121. package/dist/run/destination.js +45 -0
  122. package/dist/run/dispatch.d.ts +25 -3
  123. package/dist/run/dispatch.d.ts.map +1 -1
  124. package/dist/run/dispatch.js +26 -4
  125. package/dist/run/raw-defaults.d.ts.map +1 -1
  126. package/dist/run/raw-defaults.js +6 -1
  127. package/dist/run/raw-finalize.d.ts +96 -0
  128. package/dist/run/raw-finalize.d.ts.map +1 -0
  129. package/dist/run/raw-finalize.js +283 -0
  130. package/dist/run/raw-knobs.d.ts +36 -0
  131. package/dist/run/raw-knobs.d.ts.map +1 -0
  132. package/dist/run/raw-knobs.js +99 -0
  133. package/dist/run/raw-request.d.ts +24 -0
  134. package/dist/run/raw-request.d.ts.map +1 -0
  135. package/dist/run/raw-request.js +69 -0
  136. package/dist/run/raw-schema.d.ts +76 -0
  137. package/dist/run/raw-schema.d.ts.map +1 -0
  138. package/dist/run/raw-schema.js +166 -0
  139. package/dist/run/raw-search-cost.d.ts +49 -0
  140. package/dist/run/raw-search-cost.d.ts.map +1 -0
  141. package/dist/run/raw-search-cost.js +79 -0
  142. package/dist/run/raw-support.d.ts +64 -6
  143. package/dist/run/raw-support.d.ts.map +1 -1
  144. package/dist/run/raw-support.js +84 -11
  145. package/dist/run/raw.d.ts +25 -26
  146. package/dist/run/raw.d.ts.map +1 -1
  147. package/dist/run/raw.js +30 -351
  148. package/dist/run/record-attempt.d.ts +8 -0
  149. package/dist/run/record-attempt.d.ts.map +1 -1
  150. package/dist/run/record-attempt.js +26 -12
  151. package/dist/run/record-call.d.ts +104 -0
  152. package/dist/run/record-call.d.ts.map +1 -0
  153. package/dist/run/record-call.js +277 -0
  154. package/dist/run/repair-attempt.d.ts +68 -0
  155. package/dist/run/repair-attempt.d.ts.map +1 -0
  156. package/dist/run/repair-attempt.js +180 -0
  157. package/dist/run/resolve-destination.d.ts +49 -0
  158. package/dist/run/resolve-destination.d.ts.map +1 -0
  159. package/dist/run/resolve-destination.js +76 -0
  160. package/dist/run/routing-docs.d.ts.map +1 -1
  161. package/dist/run/routing-docs.js +9 -4
  162. package/dist/run/run.d.ts +30 -1
  163. package/dist/run/run.d.ts.map +1 -1
  164. package/dist/run/run.js +75 -148
  165. package/dist/run/telemetry-row.d.ts +92 -0
  166. package/dist/run/telemetry-row.d.ts.map +1 -0
  167. package/dist/run/telemetry-row.js +81 -0
  168. package/dist/run/validate.d.ts +12 -1
  169. package/dist/run/validate.d.ts.map +1 -1
  170. package/dist/run/validate.js +31 -0
  171. package/dist/run/web-search-pricing.d.ts +43 -0
  172. package/dist/run/web-search-pricing.d.ts.map +1 -0
  173. package/dist/run/web-search-pricing.js +56 -0
  174. package/dist/settings/grading-guide.d.ts +27 -1
  175. package/dist/settings/grading-guide.d.ts.map +1 -1
  176. package/dist/status.d.ts +6 -0
  177. package/dist/status.d.ts.map +1 -1
  178. package/dist/status.js +4 -1
  179. package/dist/telemetry/artifact-store.d.ts.map +1 -1
  180. package/dist/telemetry/artifact-store.js +11 -0
  181. package/dist/telemetry/attempt-meta.d.ts +66 -1
  182. package/dist/telemetry/attempt-meta.d.ts.map +1 -1
  183. package/dist/telemetry/attempt-meta.js +27 -1
  184. package/dist/telemetry/exporter-setup.d.ts +2 -0
  185. package/dist/telemetry/exporter-setup.d.ts.map +1 -1
  186. package/dist/telemetry/exporter-setup.js +6 -1
  187. package/dist/telemetry/grade-mappers.d.ts +5 -2
  188. package/dist/telemetry/grade-mappers.d.ts.map +1 -1
  189. package/dist/telemetry/grade-mappers.js +8 -2
  190. package/dist/telemetry/grades-sql.d.ts +4 -1
  191. package/dist/telemetry/grades-sql.d.ts.map +1 -1
  192. package/dist/telemetry/grades-sql.js +26 -3
  193. package/dist/telemetry/ingest-protocol.d.ts +26 -2
  194. package/dist/telemetry/ingest-protocol.d.ts.map +1 -1
  195. package/dist/telemetry/ingest-protocol.js +32 -29
  196. package/dist/telemetry/lanes.d.ts +31 -0
  197. package/dist/telemetry/lanes.d.ts.map +1 -0
  198. package/dist/telemetry/lanes.js +41 -0
  199. package/dist/telemetry/org-identity.d.ts +47 -0
  200. package/dist/telemetry/org-identity.d.ts.map +1 -0
  201. package/dist/telemetry/org-identity.js +100 -0
  202. package/dist/telemetry/route-registration.d.ts +48 -0
  203. package/dist/telemetry/route-registration.d.ts.map +1 -0
  204. package/dist/telemetry/route-registration.js +77 -0
  205. package/dist/telemetry/sinks.d.ts +10 -1
  206. package/dist/telemetry/sinks.d.ts.map +1 -1
  207. package/dist/telemetry/sinks.js +52 -6
  208. package/dist/telemetry/store-migrations.d.ts.map +1 -1
  209. package/dist/telemetry/store-migrations.js +13 -0
  210. package/dist/tenancy/api-key-format.d.ts +16 -1
  211. package/dist/tenancy/api-key-format.d.ts.map +1 -1
  212. package/dist/tenancy/api-key-format.js +17 -0
  213. package/dist/types/provider.d.ts +20 -3
  214. package/dist/types/provider.d.ts.map +1 -1
  215. package/dist/types/provider.js +1 -0
  216. package/dist/types/route.d.ts +76 -0
  217. package/dist/types/route.d.ts.map +1 -1
  218. package/dist/types/telemetry.d.ts +30 -2
  219. package/dist/types/telemetry.d.ts.map +1 -1
  220. package/docs/agent-skill/SKILL.md +75 -5
  221. package/docs/instrumentation.md +98 -36
  222. package/docs/llms.txt +96 -16
  223. package/docs/managed-serving.md +150 -0
  224. package/docs/mcp-oracle.md +75 -2
  225. package/docs/migration-playbook.md +5 -4
  226. package/docs/quickstart.md +169 -83
  227. package/package.json +3 -2
  228. package/registry/registry.json +82 -0
  229. package/dist/feedback/feedback.d.ts +0 -35
  230. package/dist/feedback/feedback.d.ts.map +0 -1
  231. package/dist/feedback/feedback.js +0 -39
@@ -14,10 +14,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
14
14
  exports.rungOf = rungOf;
15
15
  exports.createRecordAttempt = createRecordAttempt;
16
16
  const node_crypto_1 = require("node:crypto");
17
+ const dispatch_1 = require("./dispatch");
18
+ const destination_1 = require("./destination");
17
19
  const failures_1 = require("../types/failures");
18
20
  const cache_stamp_1 = require("./cache-stamp");
19
21
  const cache_handle_1 = require("./cache-handle");
20
22
  const attempt_meta_1 = require("../telemetry/attempt-meta");
23
+ const telemetry_row_1 = require("./telemetry-row");
21
24
  /**
22
25
  * Classify a recorded row's ladder rung (R1 review, F1). `primaryDispatched`
23
26
  * carries the candidate indices already given a primary dispatch on this call —
@@ -109,6 +112,9 @@ function createRecordAttempt(deps) {
109
112
  tokensIn: attempt.tokensIn,
110
113
  tokensOut: attempt.tokensOut,
111
114
  tokensCached: attempt.tokensCached,
115
+ // Issue #2 (L6 F1): the SERVED tier, so meta.cost components price at
116
+ // the same tier as cost_estimate_usd and still sum to the row (WI-1).
117
+ servedTier: attempt.servedTier,
112
118
  ...(attempt.tokensCacheWrite !== undefined ? { tokensCacheWrite: attempt.tokensCacheWrite } : {}),
113
119
  ...(attempt.tokensCacheWrite1h !== undefined ? { tokensCacheWrite1h: attempt.tokensCacheWrite1h } : {}),
114
120
  },
@@ -121,9 +127,13 @@ function createRecordAttempt(deps) {
121
127
  // stepKey ?? tags.step ?? the auto `route#n` key, so a caller's own step lands
122
128
  // unchanged and the tag agrees with the ground-truth step row.
123
129
  const stepTag = runCtx !== null && autoStepKey !== null ? { step: autoStepKey } : {};
124
- const row = {
130
+ // U4: the row is assembled — and its tags serialized — by the ONE shared
131
+ // builder (./telemetry-row.ts). `rung` is stamped LAST inside stampRowTags so
132
+ // a caller's extraTags (Q1 quality tags) can never override the
133
+ // recorder-owned rung. Cache-write accounting (WS-A) + WS-C substrate + the
134
+ // CS-1 mask receipt ride the same builder unchanged.
135
+ const row = (0, telemetry_row_1.buildTelemetryRow)({
125
136
  id: (0, node_crypto_1.randomUUID)(),
126
- ts: new Date().toISOString(),
127
137
  route: route.route,
128
138
  routeVersion: route.version,
129
139
  provider: attempt.candidate.provider,
@@ -133,31 +143,35 @@ function createRecordAttempt(deps) {
133
143
  tokensIn: attempt.tokensIn,
134
144
  tokensOut: attempt.tokensOut,
135
145
  tokensCached: attempt.tokensCached,
136
- // Cache-write accounting (WS-A) + request-path substrate (WS-C).
137
146
  tokensCacheWrite: attempt.tokensCacheWrite ?? 0,
138
147
  tokensCacheWrite1h: attempt.tokensCacheWrite1h ?? 0,
139
- cacheKey,
140
- prefixFingerprint: cacheStamp?.prefixFingerprint ?? null,
141
148
  costEstimateUsd: attempt.costUsd,
142
149
  latencyMs: attempt.latencyMs,
143
150
  ttfbMs: attempt.ttfbMs ?? null,
144
151
  failureClass: attempt.failure?.class ?? null,
145
152
  attemptsJson: JSON.stringify(ledger.snapshot()),
146
- // `rung` is stamped LAST so a caller's extraTags (Q1 quality tags) can
147
- // never override the recorder-owned rung.
148
- tagsJson: JSON.stringify({ ...stepTag, ...effectiveTags, ...attempt.extraTags, rung }),
153
+ // U3 (D-2) × U4: the serving `destination` tag rides the ONE shared row
154
+ // builder — `buildTelemetryRow` → `stampRowTags` serializes `tags_json` in a
155
+ // single place, and `rung` is stamped LAST there so a caller's extraTags can
156
+ // never override it. `destinationTag()` returns `{}` for the default `direct`,
157
+ // so a direct/absent routed row stays byte-identical; a `modelrig-served` row
158
+ // gains `destination`. Folded into `baseTags` here because `destination` is a
159
+ // routed-lane concept (the raw/search recorders have none).
160
+ baseTags: { ...stepTag, ...effectiveTags, ...(0, dispatch_1.destinationTag)(deps.destination ?? destination_1.DEFAULT_DESTINATION) },
161
+ extraTags: attempt.extraTags,
162
+ rung,
149
163
  fingerprintCell: route.fingerprintCell,
150
164
  servedVariant,
151
165
  repairedBy: attempt.repairedBy ?? null,
152
166
  pricingMissing: attempt.pricingMissing ?? false,
167
+ cacheKey,
168
+ prefixFingerprint: cacheStamp?.prefixFingerprint ?? null,
153
169
  callId: ladderKey.callId,
154
170
  attemptSeq: ladderKey.attemptSeq,
155
171
  candidateIndex: ladderKey.candidateIndex,
156
172
  meta,
157
- // CS-1 (spec §6): the counts-only mask receipt for this attempt, or absent
158
- // when the route does not mask. NEVER a matched value.
159
- ...(attempt.mask !== undefined ? { mask: attempt.mask } : {}),
160
- };
173
+ mask: attempt.mask,
174
+ });
161
175
  telemetry.record(row);
162
176
  // Mirror this inference into a ground-truth step attempt (fail-open — the
163
177
  // context swallows buffer errors; the run loop is never affected).
@@ -0,0 +1,104 @@
1
+ /**
2
+ * OBS-1 — `rig.recordCall()`: record a provider call ModelRig did NOT dispatch
3
+ * (acceptance ruling M12, Option A). The customer's own code made the call with
4
+ * its own key; it reports what the provider returned (tokens, tier, latency,
5
+ * failure) and ModelRig writes ONE telemetry row for it, exactly the shape the
6
+ * raw lane writes — same builder, same cost function, same step emission — so
7
+ * the call shows on /inferences, joins its run and step, and can be graded.
8
+ *
9
+ * WHAT IS DIFFERENT FROM THE RAW LANE (and nothing else is):
10
+ * - `tags.lane = "external"` (SDK-owned, stamped LAST — a caller tag cannot
11
+ * override it). Named `external`, not `direct`: ruling D-2 already uses
12
+ * "direct" for `destination`.
13
+ * - `tags.key_ownership = "byok"` (SDK-owned). Gate B-0 (usage-aggregation.ts):
14
+ * a BYOK seam must stamp the tag at that seam. A recorded call is always the
15
+ * customer's key — ModelRig bore no provider cost — so it can never settle as
16
+ * a managed charge.
17
+ * - `meta.provenance = "caller-reported"`: the numbers are the caller's, not a
18
+ * measurement. Nothing was validated (`validated` is never claimed).
19
+ *
20
+ * CONTRACT: synchronous (the row is written to the local store; the exporter
21
+ * ships it on its normal cadence) and NEVER throws into the caller. Bad input is
22
+ * warned with a teaching fix (P4) and returns `{ inferenceId: null, … }` with no
23
+ * row written.
24
+ *
25
+ * No route/registry/capability-gate dependency beyond the raw lane's own (cost
26
+ * + telemetry + run context) — the raw lane's no-hard-hot-path invariant holds.
27
+ */
28
+ import type { FailureClass } from "../types/failures";
29
+ import type { ProviderId, ServiceTier } from "../types/provider";
30
+ import type { RunTags } from "../types/route";
31
+ import type { RawRunDeps } from "./raw";
32
+ /** The lane tag a recorded call carries (SDK-owned) — the shared classifier's constant. */
33
+ export { EXTERNAL_LANE } from "../telemetry/lanes";
34
+ /** Where the warning's fix points (the "record them" section). */
35
+ export declare const RECORD_CALL_DOCS_URL = "https://modelrig.dev/not-captured.html";
36
+ /** Usage the caller's provider response reported. Same convention as every
37
+ * adapter (`AdapterUsage`): `tokensIn` is the TOTAL input and INCLUDES
38
+ * `tokensCached` and `tokensCacheWrite` as subsets. Token counts (and
39
+ * `latencyMs`/`ttfbMs`) are ROUNDED to the nearest integer and clamped
40
+ * (tokens ≤ Number.MAX_SAFE_INTEGER, milliseconds ≤ 2³¹−1) before recording. */
41
+ export interface RecordCallUsage {
42
+ readonly tokensIn: number;
43
+ readonly tokensOut: number;
44
+ readonly tokensCached?: number;
45
+ readonly tokensCacheWrite?: number;
46
+ readonly reasoningTokens?: number;
47
+ }
48
+ export interface RecordCallInput {
49
+ /** A ModelRig `ProviderId` is priced; any other non-empty provider id is
50
+ * recorded at $0 with `pricingMissing: true`. */
51
+ readonly provider: ProviderId | (string & {});
52
+ readonly model: string;
53
+ readonly usage: RecordCallUsage;
54
+ /** The tier that SERVED the call — the row is priced at it (flex is cheaper),
55
+ * exactly as the raw lane prices. Default `"standard"`. */
56
+ readonly servedTier?: ServiceTier;
57
+ /** The tier your code asked for. Default: `servedTier`. */
58
+ readonly requestedTier?: ServiceTier;
59
+ readonly latencyMs: number;
60
+ readonly ttfbMs?: number;
61
+ /** A failed attempt that the provider still billed is still a row. */
62
+ readonly failureClass?: FailureClass | null;
63
+ /** Native web-search tool calls billed on this call — writes the separate
64
+ * `rung:"search"` cost row, as the raw lane does for native grounding. */
65
+ readonly webSearchCalls?: number;
66
+ /** The ground-truth step inside an active run (same rule as `runRaw`). */
67
+ readonly stepKey?: string;
68
+ readonly tags?: RunTags;
69
+ readonly providerRequestId?: string;
70
+ /** The provider's native finish reason (`STOP`, `end_turn`, `stop`, …) or a
71
+ * normalized one; mapped to the envelope enum. */
72
+ readonly finishReason?: string;
73
+ }
74
+ export interface RecordCallResult {
75
+ /** The recorded inference id (pass it to `rig.grade`), or null when the input
76
+ * was rejected and nothing was recorded. */
77
+ readonly inferenceId: string | null;
78
+ readonly callId: string | null;
79
+ /** The token row's list-price cost (a `webSearchCalls` surcharge rides its own
80
+ * row, as on the raw lane). 0 when unpriced or rejected. */
81
+ readonly costEstimateUsd: number;
82
+ readonly pricingMissing: boolean;
83
+ }
84
+ /** Server ingest's route cap (`modelrig-server` ingest.ts `isNonEmptyString(raw.route, 200)`). */
85
+ export declare const MAX_ROUTE_CHARS = 200;
86
+ /** Test-only: clear the once-per-rule warning latch. */
87
+ export declare function resetRecordCallWarningsForTest(): void;
88
+ /** The ceiling for latency/ttfb (Postgres `integer`, 2³¹−1 ms ≈ 24.8 days). */
89
+ export declare const MAX_MS = 2147483647;
90
+ /**
91
+ * L6 MUST-3 integer hygiene. Telemetry columns are integers, but a caller's
92
+ * `performance.now()` delta is fractional — so ROUND to the nearest integer
93
+ * (friendlier than rejecting) and CLAMP: latency/ttfb to ≤ 2³¹−1 ms, token
94
+ * counts to ≤ Number.MAX_SAFE_INTEGER. Applied before any check that compares
95
+ * token counts, so validation and the recorded row see the same numbers.
96
+ */
97
+ export declare function toCount(v: number, max: number): number;
98
+ /**
99
+ * Record one call the caller made itself. See the module header for the
100
+ * contract. `deps` is the rig's raw-lane deps (telemetry + unpriced rate +
101
+ * manifest) — the same object `runRaw` receives.
102
+ */
103
+ export declare function recordCall(deps: RawRunDeps, input: RecordCallInput): RecordCallResult;
104
+ //# sourceMappingURL=record-call.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"record-call.d.ts","sourceRoot":"","sources":["../../src/run/record-call.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAYH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,EAAgB,UAAU,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAC/E,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAExC,2FAA2F;AAC3F,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD,kEAAkE;AAClE,eAAO,MAAM,oBAAoB,2CAA2C,CAAC;AAE7E;;;;gFAIgF;AAChF,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;CACnC;AAED,MAAM,WAAW,eAAe;IAC9B;qDACiD;IACjD,QAAQ,CAAC,QAAQ,EAAE,UAAU,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;IAC9C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAC;IAChC;+DAC2D;IAC3D,QAAQ,CAAC,UAAU,CAAC,EAAE,WAAW,CAAC;IAClC,2DAA2D;IAC3D,QAAQ,CAAC,aAAa,CAAC,EAAE,WAAW,CAAC;IACrC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,sEAAsE;IACtE,QAAQ,CAAC,YAAY,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;IAC5C;8EAC0E;IAC1E,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,0EAA0E;IAC1E,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IACpC;sDACkD;IAClD,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;CAChC;AAED,MAAM,WAAW,gBAAgB;IAC/B;gDAC4C;IAC5C,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B;gEAC4D;IAC5D,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;CAClC;AAQD,kGAAkG;AAClG,eAAO,MAAM,eAAe,MAAM,CAAC;AAcnC,wDAAwD;AACxD,wBAAgB,8BAA8B,IAAI,IAAI,CAErD;AAMD,+EAA+E;AAC/E,eAAO,MAAM,MAAM,aAAgB,CAAC;AAEpC;;;;;;GAMG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAEtD;AA6GD;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,eAAe,GAAG,gBAAgB,CAarF"}
@@ -0,0 +1,277 @@
1
+ "use strict";
2
+ /**
3
+ * OBS-1 — `rig.recordCall()`: record a provider call ModelRig did NOT dispatch
4
+ * (acceptance ruling M12, Option A). The customer's own code made the call with
5
+ * its own key; it reports what the provider returned (tokens, tier, latency,
6
+ * failure) and ModelRig writes ONE telemetry row for it, exactly the shape the
7
+ * raw lane writes — same builder, same cost function, same step emission — so
8
+ * the call shows on /inferences, joins its run and step, and can be graded.
9
+ *
10
+ * WHAT IS DIFFERENT FROM THE RAW LANE (and nothing else is):
11
+ * - `tags.lane = "external"` (SDK-owned, stamped LAST — a caller tag cannot
12
+ * override it). Named `external`, not `direct`: ruling D-2 already uses
13
+ * "direct" for `destination`.
14
+ * - `tags.key_ownership = "byok"` (SDK-owned). Gate B-0 (usage-aggregation.ts):
15
+ * a BYOK seam must stamp the tag at that seam. A recorded call is always the
16
+ * customer's key — ModelRig bore no provider cost — so it can never settle as
17
+ * a managed charge.
18
+ * - `meta.provenance = "caller-reported"`: the numbers are the caller's, not a
19
+ * measurement. Nothing was validated (`validated` is never claimed).
20
+ *
21
+ * CONTRACT: synchronous (the row is written to the local store; the exporter
22
+ * ships it on its normal cadence) and NEVER throws into the caller. Bad input is
23
+ * warned with a teaching fix (P4) and returns `{ inferenceId: null, … }` with no
24
+ * row written.
25
+ *
26
+ * No route/registry/capability-gate dependency beyond the raw lane's own (cost
27
+ * + telemetry + run context) — the raw lane's no-hard-hot-path invariant holds.
28
+ */
29
+ Object.defineProperty(exports, "__esModule", { value: true });
30
+ exports.MAX_MS = exports.MAX_ROUTE_CHARS = exports.RECORD_CALL_DOCS_URL = exports.EXTERNAL_LANE = void 0;
31
+ exports.resetRecordCallWarningsForTest = resetRecordCallWarningsForTest;
32
+ exports.toCount = toCount;
33
+ exports.recordCall = recordCall;
34
+ const node_crypto_1 = require("node:crypto");
35
+ const cost_1 = require("./cost");
36
+ const raw_finalize_1 = require("./raw-finalize");
37
+ const raw_search_cost_1 = require("./raw-search-cost");
38
+ const attempt_meta_map_1 = require("../adapters/attempt-meta-map");
39
+ const run_context_1 = require("../artifacts/run-context");
40
+ const lanes_1 = require("../telemetry/lanes");
41
+ const attempt_meta_1 = require("../telemetry/attempt-meta");
42
+ const failures_teaching_1 = require("../types/failures-teaching");
43
+ const provider_1 = require("../types/provider");
44
+ /** The lane tag a recorded call carries (SDK-owned) — the shared classifier's constant. */
45
+ var lanes_2 = require("../telemetry/lanes");
46
+ Object.defineProperty(exports, "EXTERNAL_LANE", { enumerable: true, get: function () { return lanes_2.EXTERNAL_LANE; } });
47
+ /** Where the warning's fix points (the "record them" section). */
48
+ exports.RECORD_CALL_DOCS_URL = "https://modelrig.dev/not-captured.html";
49
+ const REJECTED = { inferenceId: null, callId: null, costEstimateUsd: 0, pricingMissing: false };
50
+ const SERVICE_TIERS = new Set(["standard", "flex", "priority"]);
51
+ const FINISH_REASONS = new Set([
52
+ "stop", "length", "tool_calls", "content_filter", "refusal", "error", "other",
53
+ ]);
54
+ const KNOWN_PROVIDERS = new Set(provider_1.PROVIDER_IDS);
55
+ /** Server ingest's route cap (`modelrig-server` ingest.ts `isNonEmptyString(raw.route, 200)`). */
56
+ exports.MAX_ROUTE_CHARS = 200;
57
+ /** Max distinct rules the once-per-rule warning latch remembers (L6 NIT-3). */
58
+ const WARN_LATCH_MAX = 100;
59
+ const warned = new Set();
60
+ /** Warn once per validation RULE. The latch key is the rule id — never a
61
+ * caller-supplied string — and the set is bounded, so a caller looping over bad
62
+ * input with varying values cannot grow it. */
63
+ function warnOnce(rule, problem, fix) {
64
+ if (warned.has(rule))
65
+ return;
66
+ if (warned.size < WARN_LATCH_MAX)
67
+ warned.add(rule);
68
+ console.warn(`[modelrig recordCall] ${problem} — nothing was recorded. fix: ${fix} (${exports.RECORD_CALL_DOCS_URL})`);
69
+ }
70
+ /** Test-only: clear the once-per-rule warning latch. */
71
+ function resetRecordCallWarningsForTest() {
72
+ warned.clear();
73
+ }
74
+ function isCount(v) {
75
+ return typeof v === "number" && Number.isFinite(v) && v >= 0;
76
+ }
77
+ /** The ceiling for latency/ttfb (Postgres `integer`, 2³¹−1 ms ≈ 24.8 days). */
78
+ exports.MAX_MS = 2147483647;
79
+ /**
80
+ * L6 MUST-3 integer hygiene. Telemetry columns are integers, but a caller's
81
+ * `performance.now()` delta is fractional — so ROUND to the nearest integer
82
+ * (friendlier than rejecting) and CLAMP: latency/ttfb to ≤ 2³¹−1 ms, token
83
+ * counts to ≤ Number.MAX_SAFE_INTEGER. Applied before any check that compares
84
+ * token counts, so validation and the recorded row see the same numbers.
85
+ */
86
+ function toCount(v, max) {
87
+ return Math.min(Math.round(v), max);
88
+ }
89
+ const tok = (v) => (typeof v === "number" ? toCount(v, Number.MAX_SAFE_INTEGER) : 0);
90
+ function isNonEmpty(v, max) {
91
+ return typeof v === "string" && v.length > 0 && v.length <= max;
92
+ }
93
+ /** Validate the caller's input. Returns the failed rule, or null. */
94
+ function validate(input) {
95
+ const p = validateShape(input);
96
+ return p === null ? null : { rule: p.fix, ...p };
97
+ }
98
+ /** The rule checks. Every `fix` string is built only from SDK constants and
99
+ * field names (never from a caller value), so it doubles as the rule id. */
100
+ function validateShape(input) {
101
+ if (typeof input !== "object" || input === null) {
102
+ return { problem: "input is not an object", fix: "call rig.recordCall({ provider, model, usage, latencyMs })" };
103
+ }
104
+ const i = input;
105
+ if (!isNonEmpty(i.provider, 100)) {
106
+ return { problem: "provider is missing", fix: 'pass the provider id, e.g. provider: "gemini"' };
107
+ }
108
+ if (!isNonEmpty(i.model, 200)) {
109
+ return { problem: "model is missing", fix: 'pass the model id your code called, e.g. model: "gemini-3.1-pro-preview"' };
110
+ }
111
+ // L6 SHOULD-2: the row's route is `provider/model`; server ingest drops a
112
+ // route over 200 chars (ingest.ts), so refuse here instead of writing a row
113
+ // that would never arrive.
114
+ if (i.provider.length + 1 + i.model.length > exports.MAX_ROUTE_CHARS) {
115
+ return {
116
+ problem: `provider/model is longer than ${exports.MAX_ROUTE_CHARS} characters`,
117
+ fix: `shorten the provider or model id so "provider/model" is at most ${exports.MAX_ROUTE_CHARS} characters`,
118
+ };
119
+ }
120
+ const u = i.usage;
121
+ if (typeof u !== "object" || u === null || !isCount(u.tokensIn) || !isCount(u.tokensOut)) {
122
+ return {
123
+ problem: "usage.tokensIn / usage.tokensOut are missing or not non-negative numbers",
124
+ fix: "copy them from the provider response's usage block (Gemini usageMetadata.promptTokenCount / candidatesTokenCount; OpenAI usage.prompt_tokens / completion_tokens)",
125
+ };
126
+ }
127
+ for (const k of ["tokensCached", "tokensCacheWrite", "reasoningTokens"]) {
128
+ if (u[k] !== undefined && !isCount(u[k])) {
129
+ return { problem: `usage.${k} is not a non-negative number`, fix: `omit usage.${k} or pass a number ≥ 0` };
130
+ }
131
+ }
132
+ if (tok(u.tokensCached) + tok(u.tokensCacheWrite) > tok(u.tokensIn)) {
133
+ return {
134
+ problem: "usage.tokensCached + usage.tokensCacheWrite exceed usage.tokensIn",
135
+ fix: "tokensIn is the TOTAL input and includes cached and cache-write tokens (Anthropic reports input_tokens without them — add cache_read_input_tokens and cache_creation_input_tokens back)",
136
+ };
137
+ }
138
+ if (!isCount(i.latencyMs)) {
139
+ return { problem: "latencyMs is missing or not a non-negative number", fix: "measure the call's wall time in ms and pass latencyMs" };
140
+ }
141
+ if (i.ttfbMs !== undefined && !isCount(i.ttfbMs)) {
142
+ return { problem: "ttfbMs is not a non-negative number", fix: "omit ttfbMs or pass a number ≥ 0" };
143
+ }
144
+ for (const k of ["servedTier", "requestedTier"]) {
145
+ if (i[k] !== undefined && !(typeof i[k] === "string" && SERVICE_TIERS.has(i[k]))) {
146
+ return { problem: `${k} is not a service tier`, fix: `pass "standard", "flex" or "priority", or omit ${k}` };
147
+ }
148
+ }
149
+ if (i.failureClass !== undefined && i.failureClass !== null) {
150
+ if (typeof i.failureClass !== "string" || !Object.prototype.hasOwnProperty.call(failures_teaching_1.FAILURE_TEACHING, i.failureClass)) {
151
+ return {
152
+ problem: `failureClass "${String(i.failureClass)}" is not a ModelRig failure class`,
153
+ fix: `use one of ${Object.keys(failures_teaching_1.FAILURE_TEACHING).join(", ")}, or null for a success`,
154
+ };
155
+ }
156
+ }
157
+ if (i.webSearchCalls !== undefined && !(isCount(i.webSearchCalls) && Number.isInteger(i.webSearchCalls))) {
158
+ return { problem: "webSearchCalls is not a whole number ≥ 0", fix: "pass the count of billed web_search tool calls, or omit it" };
159
+ }
160
+ if (i.tags !== undefined) {
161
+ if (typeof i.tags !== "object" || i.tags === null || Array.isArray(i.tags)) {
162
+ return { problem: "tags is not an object", fix: 'pass tags as { key: "value" } strings' };
163
+ }
164
+ for (const [k, v] of Object.entries(i.tags)) {
165
+ if (v !== undefined && typeof v !== "string") {
166
+ return { problem: `tags.${k} is not a string`, fix: "tag values are strings — String() the value" };
167
+ }
168
+ }
169
+ }
170
+ for (const k of ["stepKey", "providerRequestId", "finishReason"]) {
171
+ if (i[k] !== undefined && typeof i[k] !== "string") {
172
+ return { problem: `${k} is not a string`, fix: `omit ${k} or pass a string` };
173
+ }
174
+ }
175
+ return null;
176
+ }
177
+ /** Normalize a caller finish reason: an enum value passes; a provider-native one
178
+ * maps through the adapters' own table; empty ⇒ absent. */
179
+ function finishReasonOf(provider, raw) {
180
+ if (raw === undefined || raw === "")
181
+ return undefined;
182
+ if (FINISH_REASONS.has(raw))
183
+ return raw;
184
+ return (0, attempt_meta_map_1.mapFinishReason)((KNOWN_PROVIDERS.has(provider) ? provider : "openai"), raw);
185
+ }
186
+ /**
187
+ * Record one call the caller made itself. See the module header for the
188
+ * contract. `deps` is the rig's raw-lane deps (telemetry + unpriced rate +
189
+ * manifest) — the same object `runRaw` receives.
190
+ */
191
+ function recordCall(deps, input) {
192
+ try {
193
+ const bad = validate(input);
194
+ if (bad !== null) {
195
+ warnOnce(bad.rule, bad.problem, bad.fix);
196
+ return REJECTED;
197
+ }
198
+ return record(deps, input);
199
+ }
200
+ catch (err) {
201
+ // Instrumentation never throws into customer code (P4 graceful degradation).
202
+ warnOnce("unexpected", `unexpected error (${err instanceof Error ? err.message : String(err)})`, "report this to ModelRig");
203
+ return REJECTED;
204
+ }
205
+ }
206
+ function record(deps, input) {
207
+ // Same ALS-boundary read + step key resolution + dimension hygiene as runRaw.
208
+ const step = (0, raw_finalize_1.prepareRawStep)(deps, input);
209
+ const provider = input.provider;
210
+ const known = KNOWN_PROVIDERS.has(provider);
211
+ const rawModelId = `${provider}/${input.model}`;
212
+ const servedTier = input.servedTier ?? "standard";
213
+ const requestedTier = input.requestedTier ?? servedTier;
214
+ // MUST-3: integers only on the row (rounded + clamped — see toCount).
215
+ const usage = {
216
+ tokensIn: tok(input.usage.tokensIn),
217
+ tokensOut: tok(input.usage.tokensOut),
218
+ tokensCached: tok(input.usage.tokensCached),
219
+ ...(input.usage.tokensCacheWrite !== undefined ? { tokensCacheWrite: tok(input.usage.tokensCacheWrite) } : {}),
220
+ servedTier,
221
+ ...(input.ttfbMs !== undefined ? { ttfbMs: toCount(input.ttfbMs, exports.MAX_MS) } : {}),
222
+ };
223
+ const latencyMs = toCount(input.latencyMs, exports.MAX_MS);
224
+ // Priced exactly like the raw lane: list price at the SERVED tier. A provider
225
+ // ModelRig has no price table for is recorded honestly at $0, flagged.
226
+ const unpricedRatePerTok = (deps.unpricedRateUsdPerMTok ?? cost_1.DEFAULT_UNPRICED_RATE_USD_PER_MTOK) / 1000000;
227
+ const { costUsd, pricingMissing } = known
228
+ ? (0, cost_1.attemptCost)(provider, input.model, usage, unpricedRatePerTok)
229
+ : { costUsd: 0, pricingMissing: true };
230
+ // Tags: caller tags + the ambient step/run_id (same order as finalizeRaw), then
231
+ // the SDK-owned markers LAST so a caller value cannot override them.
232
+ const stepTag = step !== null ? { step: step.stepKey } : {};
233
+ const tags = {
234
+ ...stepTag,
235
+ ...(0, run_context_1.withRunIdTag)(input.tags ?? {}, step?.runCtx ?? null),
236
+ key_ownership: "byok",
237
+ lane: lanes_1.EXTERNAL_LANE,
238
+ };
239
+ const finishReason = finishReasonOf(provider, input.finishReason);
240
+ const adapterMeta = {
241
+ ...(finishReason !== undefined ? { finish_reason: finishReason } : {}),
242
+ ...(input.providerRequestId !== undefined ? { provider_request_id: input.providerRequestId } : {}),
243
+ ...(input.usage.reasoningTokens !== undefined ? { reasoning_tokens: tok(input.usage.reasoningTokens) } : {}),
244
+ };
245
+ // No rendered request and no output text: ModelRig never saw the content, so
246
+ // there is no input/output hash. Cost components only for a priced provider.
247
+ const meta = (0, attempt_meta_1.summarizeAttemptMeta)({
248
+ adapterMeta,
249
+ provenance: "caller-reported",
250
+ ...(known ? { provider: provider, model: input.model } : {}),
251
+ usage,
252
+ });
253
+ const id = (0, node_crypto_1.randomUUID)();
254
+ const callId = (0, node_crypto_1.randomUUID)();
255
+ const failureClass = input.failureClass ?? null;
256
+ (0, raw_finalize_1.recordRawRow)(deps.telemetry, {
257
+ id,
258
+ rawModelId,
259
+ provider,
260
+ model: input.model,
261
+ usage,
262
+ costUsd,
263
+ latencyMs,
264
+ requestedTier,
265
+ failureClass,
266
+ tags,
267
+ pricingMissing,
268
+ callId,
269
+ meta,
270
+ });
271
+ (0, raw_finalize_1.emitRawStep)(step, input.tags?.step ?? rawModelId, id, failureClass);
272
+ const searchCalls = input.webSearchCalls ?? 0;
273
+ if (searchCalls >= 1) {
274
+ (0, raw_search_cost_1.recordRawSearchCostRow)(deps.telemetry, { provider, rawModelId, tags, callId, searchCalls });
275
+ }
276
+ return { inferenceId: id, callId, costEstimateUsd: costUsd, pricingMissing };
277
+ }
@@ -0,0 +1,68 @@
1
+ /**
2
+ * The routed lane's REPAIR RUNG (spec §4, WS2), extracted from run.ts as a
3
+ * factory over the run's per-call state — mirroring the `createRecordAttempt`
4
+ * factory pattern in ./record-attempt.ts, and for the same reason: run.ts sits
5
+ * at the 700-LOC cap (dev-rule P1), and the repair closure is a large,
6
+ * self-contained block (~157 LOC). This is a PURE MOVE (Unified Route U4,
7
+ * behavior-preserving): the logic, the record shapes, the throw conditions, and
8
+ * the returned `RunResult` meta are byte-identical to the former inline closure.
9
+ *
10
+ * The one mechanical change the move forces: the former closure read the run
11
+ * loop's mutable `injectedSources` binding directly; the factory-built function
12
+ * receives it as an explicit call argument instead (the run loop passes the
13
+ * value in scope for the candidate being repaired), so behavior is unchanged.
14
+ */
15
+ import type { ProviderAdapter, CandidateRef } from "../types/provider";
16
+ import type { RigFailure } from "../types/failures";
17
+ import type { RouteBundle, RunResult } from "../types/route";
18
+ import type { ScreenReceipt } from "../screen/types";
19
+ import type { EnvelopeGuard } from "./envelope";
20
+ import type { RunMode } from "./resolve";
21
+ import type { RepairStep } from "./repair";
22
+ import type { AttemptTelemetry } from "./dispatch";
23
+ import type { SearchResultItem } from "./grounding";
24
+ import type { LadderKeyMinter } from "./ladder-key";
25
+ import type { RetryLedger } from "./retry";
26
+ import type { Destination } from "./destination";
27
+ /** User turn for repair calls (WS2) — same terse-trigger convention run.ts uses
28
+ * for the primary directive. Moved here with the repair closure. */
29
+ export declare const REPAIR_DIRECTIVE = "Produce the corrected JSON object now, following the system instructions exactly.";
30
+ /** The user turn of a SAME-MODEL repair re-ask (issue #5, R1): on a route that
31
+ * declares `prompt.user`, the rendered per-call user turn is kept ahead of the
32
+ * repair directive (the delta is content the model needs to correct against —
33
+ * dropping it would be the silent loss R1 closes); on every other route the
34
+ * directive alone, byte-identical to pre-R1. Pure; exported for the tests. */
35
+ export declare function repairUserTurn(route: Pick<RouteBundle, "userTemplate">, originalUserPrompt: string): string;
36
+ export interface RepairAttemptOutcome {
37
+ readonly done?: RunResult;
38
+ readonly invalid?: {
39
+ readonly text: string;
40
+ readonly errors: readonly string[];
41
+ };
42
+ }
43
+ export interface AttemptRepairDeps {
44
+ readonly adapters: ReadonlyMap<string, ProviderAdapter>;
45
+ readonly guard: EnvelopeGuard | null;
46
+ readonly unpricedRatePerTok: number;
47
+ readonly route: RouteBundle;
48
+ readonly mode: RunMode;
49
+ readonly recordAttempt: (attempt: AttemptTelemetry) => string;
50
+ readonly captureAttempt: (inferenceId: string, text: string) => void;
51
+ readonly ledger: RetryLedger;
52
+ readonly servedVariant: string | null;
53
+ readonly ladder: LadderKeyMinter;
54
+ readonly destination: Destination;
55
+ /** run.ts's `failRun` — records a pre-dispatch terminal row and throws. */
56
+ readonly failRun: (candidate: CandidateRef, failure: RigFailure, latencyMs: number, screen?: ScreenReceipt) => never;
57
+ }
58
+ /**
59
+ * Build the run loop's `attemptRepair`. Returns a function performing ONE repair
60
+ * dispatch: `{done}` on schema-valid output, `{invalid}` with the newest
61
+ * output+errors for chaining, or null when the dispatch itself failed (adapter
62
+ * failure / unmintable repair candidate). `injectedSources` is the run loop's
63
+ * current grounding-inject payload for the candidate under repair (null when the
64
+ * run is not spotlight-grounded) — passed in so the returned `done` meta carries
65
+ * the same `groundingMeta` the primary success path would.
66
+ */
67
+ export declare function createAttemptRepair(deps: AttemptRepairDeps): (step: RepairStep, original: CandidateRef, originalSystemPrompt: string, invalidText: string, errors: readonly string[], injectedSources: readonly SearchResultItem[] | null, originalUserPrompt?: string) => Promise<RepairAttemptOutcome | null>;
68
+ //# sourceMappingURL=repair-attempt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repair-attempt.d.ts","sourceRoot":"","sources":["../../src/run/repair-attempt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACvE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC7D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGzC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAG3C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC3C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD;oEACoE;AACpE,eAAO,MAAM,gBAAgB,sFAAsF,CAAC;AAEpH;;;;8EAI8E;AAC9E,wBAAgB,cAAc,CAAC,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,cAAc,CAAC,EAAE,kBAAkB,EAAE,MAAM,GAAG,MAAM,CAE3G;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC;IAC1B,QAAQ,CAAC,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;KAAE,CAAC;CAClF;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IACxD,QAAQ,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,CAAC;IACrC,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,aAAa,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,MAAM,CAAC;IAC9D,QAAQ,CAAC,cAAc,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACrE,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC;IACjC,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;IAClC,2EAA2E;IAC3E,QAAQ,CAAC,OAAO,EAAE,CAAC,SAAS,EAAE,YAAY,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,aAAa,KAAK,KAAK,CAAC;CACtH;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,iBAAiB,GACtB,CACD,IAAI,EAAE,UAAU,EAChB,QAAQ,EAAE,YAAY,EACtB,oBAAoB,EAAE,MAAM,EAC5B,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,SAAS,MAAM,EAAE,EACzB,eAAe,EAAE,SAAS,gBAAgB,EAAE,GAAG,IAAI,EACnD,kBAAkB,CAAC,EAAE,MAAM,KACxB,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CA0KxC"}