modelrig 0.3.0 → 0.4.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 (78) hide show
  1. package/CHANGELOG.md +140 -0
  2. package/README.md +66 -14
  3. package/dist/adapters/deepseek.d.ts.map +1 -1
  4. package/dist/adapters/deepseek.js +8 -1
  5. package/dist/adapters/gemini.d.ts +6 -0
  6. package/dist/adapters/gemini.d.ts.map +1 -1
  7. package/dist/adapters/gemini.js +14 -4
  8. package/dist/adapters/grok.d.ts +7 -0
  9. package/dist/adapters/grok.d.ts.map +1 -1
  10. package/dist/adapters/grok.js +23 -1
  11. package/dist/adapters/openai-compat.d.ts +7 -0
  12. package/dist/adapters/openai-compat.d.ts.map +1 -1
  13. package/dist/adapters/openai-compat.js +24 -1
  14. package/dist/adapters/openai.d.ts +7 -0
  15. package/dist/adapters/openai.d.ts.map +1 -1
  16. package/dist/adapters/openai.js +23 -1
  17. package/dist/cli.d.ts.map +1 -1
  18. package/dist/cli.js +5 -4
  19. package/dist/config.d.ts +7 -1
  20. package/dist/config.d.ts.map +1 -1
  21. package/dist/index.d.ts +6 -6
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +28 -25
  24. package/dist/init/init-cli.d.ts.map +1 -1
  25. package/dist/init/init-cli.js +2 -1
  26. package/dist/init/observe-cli.d.ts.map +1 -1
  27. package/dist/init/observe-cli.js +2 -1
  28. package/dist/routes/sampling-config.d.ts.map +1 -1
  29. package/dist/routes/sampling-config.js +11 -0
  30. package/dist/run/dispatch.d.ts +14 -2
  31. package/dist/run/dispatch.d.ts.map +1 -1
  32. package/dist/run/dispatch.js +31 -2
  33. package/dist/run/ladder-key.d.ts +40 -0
  34. package/dist/run/ladder-key.d.ts.map +1 -0
  35. package/dist/run/ladder-key.js +39 -0
  36. package/dist/run/raw-support.d.ts +123 -0
  37. package/dist/run/raw-support.d.ts.map +1 -0
  38. package/dist/run/raw-support.js +150 -0
  39. package/dist/run/raw.d.ts +41 -11
  40. package/dist/run/raw.d.ts.map +1 -1
  41. package/dist/run/raw.js +67 -23
  42. package/dist/run/rawonly.d.ts +60 -0
  43. package/dist/run/rawonly.d.ts.map +1 -0
  44. package/dist/run/rawonly.js +120 -0
  45. package/dist/run/record-attempt.d.ts +14 -1
  46. package/dist/run/record-attempt.d.ts.map +1 -1
  47. package/dist/run/record-attempt.js +43 -2
  48. package/dist/run/resolve.d.ts +4 -0
  49. package/dist/run/resolve.d.ts.map +1 -1
  50. package/dist/run/resolve.js +9 -2
  51. package/dist/run/routing-docs.d.ts +73 -0
  52. package/dist/run/routing-docs.d.ts.map +1 -0
  53. package/dist/run/routing-docs.js +222 -0
  54. package/dist/run/run.d.ts.map +1 -1
  55. package/dist/run/run.js +24 -22
  56. package/dist/telemetry/exporter.d.ts.map +1 -1
  57. package/dist/telemetry/exporter.js +6 -0
  58. package/dist/telemetry/ingest-protocol.d.ts +7 -0
  59. package/dist/telemetry/ingest-protocol.d.ts.map +1 -1
  60. package/dist/telemetry/load-error-report.d.ts.map +1 -1
  61. package/dist/telemetry/load-error-report.js +4 -1
  62. package/dist/telemetry/otel-map.d.ts.map +1 -1
  63. package/dist/telemetry/otel-map.js +8 -0
  64. package/dist/telemetry/store-migrations.d.ts +15 -0
  65. package/dist/telemetry/store-migrations.d.ts.map +1 -0
  66. package/dist/telemetry/store-migrations.js +119 -0
  67. package/dist/telemetry/store.d.ts.map +1 -1
  68. package/dist/telemetry/store.js +26 -93
  69. package/dist/types/failures-teaching.js +1 -1
  70. package/dist/types/provider.d.ts +13 -0
  71. package/dist/types/provider.d.ts.map +1 -1
  72. package/dist/types/route.d.ts +6 -1
  73. package/dist/types/route.d.ts.map +1 -1
  74. package/dist/types/telemetry.d.ts +31 -0
  75. package/dist/types/telemetry.d.ts.map +1 -1
  76. package/dist/validate-cli.d.ts.map +1 -1
  77. package/dist/validate-cli.js +17 -4
  78. package/package.json +1 -1
@@ -0,0 +1,123 @@
1
+ /**
2
+ * CE-9 (spec R5) — the raw-lane provider × knob support matrix, the SINGLE
3
+ * source of truth for which knobs each provider honors on `rig.runRaw`.
4
+ *
5
+ * BOTH the runtime guard (`assertRawKnobsSupported`, run/raw.ts) and the docs
6
+ * generator (scripts/build-docs-site.ts) import `RAW_KNOB_SUPPORT` — so the
7
+ * fail-closed behavior a customer hits at runtime and the published matrix they
8
+ * read beforehand can never disagree. The guard's provider sets are no longer
9
+ * inline literals; adding a provider (or widening a knob) is one edit here.
10
+ *
11
+ * The knob discipline this table encodes (spec R1/R2/R4):
12
+ * - grounding: gemini honors native web grounding (grok's Live Search was retired by
13
+ * xAI — 410 on the CE-9 live gate — so grok is fail-closed until CE-9b lands the
14
+ * Responses-API web_search path); every other provider
15
+ * FAILS CLOSED pre-dispatch (guarded).
16
+ * - reasoning: NO per-model allowlist outside gemini (the drift cost the
17
+ * customer flagged). openai/deepinfra/fireworks forward `level` verbatim as
18
+ * `reasoning_effort` and let the provider enforce (a rejection is classified
19
+ * teachably in each adapter); grok forwards a DISCLOSED coarsening
20
+ * (`coarsenGrokReasoningEffort`); gemini stays model-gated (the adapter
21
+ * rejects a non-thinking model); deepseek + anthropic FAIL CLOSED at the
22
+ * guard with a provider-specific fixHint.
23
+ * - responseFormat ("json_object"): the OpenAI-dialect providers + gemini
24
+ * (mime-shaping only) honor it; anthropic FAILS CLOSED (guarded). This is
25
+ * mime-shaping, NOT schema enforcement — F4 stands (no validation/repair,
26
+ * `meta.validated` stays false).
27
+ * - cache + serviceTier are INFORMATIONAL here (never a hard fail): the cache
28
+ * directive is provider-neutral (a resource HANDLE on gemini, a routing HINT
29
+ * on the prompt_cache_key providers) and serviceTier forwards everywhere.
30
+ */
31
+ import type { ProviderId, ReasoningLevel } from "../types/provider";
32
+ /** How a provider treats a declared `reasoning.level` on the raw lane (R1). */
33
+ export type ReasoningSupportKind =
34
+ /** openai / deepinfra / fireworks — `level` → `reasoning_effort` 1:1,
35
+ * forwarded verbatim; an "unsupported parameter" rejection is classified
36
+ * teachably by the adapter (no per-model allowlist). */
37
+ "forward"
38
+ /** grok — `level` coarsened to xAI's `low|high` via
39
+ * `coarsenGrokReasoningEffort` (a DISCLOSED lossy mapping, never silent). */
40
+ | "coarsen"
41
+ /** gemini — honored only on a thinking-capable model; the adapter rejects a
42
+ * non-thinking model classified (`geminiReasoningUnsupported`). */
43
+ | "model-gated"
44
+ /** deepseek / anthropic — no effort control exists; rejected pre-dispatch by
45
+ * the guard with a provider-specific fixHint. */
46
+ | "fail-closed";
47
+ /** Cache-directive semantics per provider (R3) — documentation only; the raw
48
+ * lane never fails a call over the cache directive. */
49
+ export type CacheSemantics =
50
+ /** gemini — `cache.key` is a `cachedContent` resource HANDLE (customer-owned;
51
+ * ModelRig never creates/refreshes/deletes it). */
52
+ "handle"
53
+ /** openai / grok / deepinfra / fireworks — `cache.key` → `prompt_cache_key`, a
54
+ * routing HINT (openai also maps `ttlSeconds ≥ 86400` → 24h retention). */
55
+ | "hint"
56
+ /** deepseek — automatic prefix cache; the key is not used. */
57
+ | "implicit"
58
+ /** anthropic — prefix caching via `cache_control` markers; the key is not
59
+ * used (out of scope for the raw lane). */
60
+ | "marker";
61
+ /** A guarded knob (grounding / responseFormat): boolean support + the matrix
62
+ * cell text. The guard computes its thrown fixHint from the matrix (the list of
63
+ * supported providers), so widening the matrix updates the error too. */
64
+ export interface KnobFact {
65
+ readonly supported: boolean;
66
+ /** Human teaching string rendered in the docs matrix cell. */
67
+ readonly note: string;
68
+ }
69
+ /** Reasoning support per provider (R1) — `kind` drives the guard (only
70
+ * `fail-closed` throws) and the docs. */
71
+ export interface ReasoningFact {
72
+ readonly kind: ReasoningSupportKind;
73
+ readonly note: string;
74
+ /** Rendered by the guard's thrown error when `kind === "fail-closed"`. */
75
+ readonly fixHint?: string;
76
+ }
77
+ export interface CacheFact {
78
+ readonly semantics: CacheSemantics;
79
+ readonly note: string;
80
+ }
81
+ export interface RawKnobSupport {
82
+ /** GUARDED — a declared `grounding` on an unsupported provider throws. */
83
+ readonly grounding: KnobFact;
84
+ /** GUARDED only when `kind === "fail-closed"` (deepseek/anthropic). */
85
+ readonly reasoning: ReasoningFact;
86
+ /** GUARDED — a declared `responseFormat` on an unsupported provider throws. */
87
+ readonly responseFormat: KnobFact;
88
+ /** INFORMATIONAL — the cache directive never hard-fails on the raw lane. */
89
+ readonly cache: CacheFact;
90
+ /** INFORMATIONAL — serviceTier forwards to every adapter; the served tier
91
+ * reports the truth. */
92
+ readonly serviceTier: KnobFact;
93
+ }
94
+ /**
95
+ * The grok reasoning coarsening (R1): xAI's `reasoning_effort` accepts only
96
+ * `"low" | "high"`, so the four-level neutral vocabulary is coarsened —
97
+ * `minimal, low → "low"`; `medium, high → "high"`. This is a DISCLOSED, lossy
98
+ * mapping (it appears in the matrix note, the grok field's doc comment, and the
99
+ * `grok.test.ts` test), never a silent semantic drop. Kept here — beside the
100
+ * matrix that documents it — as the ONE place the algorithm lives (grok.ts
101
+ * imports it).
102
+ */
103
+ export declare function coarsenGrokReasoningEffort(level: ReasoningLevel): "low" | "high";
104
+ /** The matrix. Exhaustive over ProviderId — a new provider forces a compile
105
+ * error here (Record<ProviderId, …>), so it can never be silently unlisted. */
106
+ export declare const RAW_KNOB_SUPPORT: Record<ProviderId, RawKnobSupport>;
107
+ /** Pure lookup into the matrix (spec R6, exported from the package root). A
108
+ * customer's multi-provider dispatcher ASKS this instead of duplicating the
109
+ * provider lists. */
110
+ export declare function rawKnobSupport(provider: ProviderId): RawKnobSupport;
111
+ /** Providers that honor a knob, in PROVIDER_IDS order — used by the guard to
112
+ * build a "supported on X, Y only" fixHint from the matrix (so the error text
113
+ * can never drift from the table). */
114
+ export declare function groundingSupportedProviders(): readonly ProviderId[];
115
+ export declare function responseFormatSupportedProviders(): readonly ProviderId[];
116
+ /** Matrix-level notes rendered below the table (spec §3.2 restated in docs). */
117
+ export declare const RAW_KNOB_MATRIX_NOTES: readonly string[];
118
+ /** Render the provider × knob matrix as a Markdown table + notes, FROM the
119
+ * matrix (never a hand-written table — R5). Consumed by the docs generator
120
+ * (scripts/build-docs-site.ts) so the published matrix and the runtime guard
121
+ * derive from the same source. */
122
+ export declare function renderRawKnobMatrix(): string;
123
+ //# sourceMappingURL=raw-support.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"raw-support.d.ts","sourceRoot":"","sources":["../../src/run/raw-support.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEpE,+EAA+E;AAC/E,MAAM,MAAM,oBAAoB;AAC9B;;wDAEwD;AACtD,SAAS;AACX;6EAC6E;GAC3E,SAAS;AACX;mEACmE;GACjE,aAAa;AACf;iDACiD;GAC/C,aAAa,CAAC;AAElB;uDACuD;AACvD,MAAM,MAAM,cAAc;AACxB;mDACmD;AACjD,QAAQ;AACV;2EAC2E;GACzE,MAAM;AACR,8DAA8D;GAC5D,UAAU;AACZ;2CAC2C;GACzC,QAAQ,CAAC;AAEb;;yEAEyE;AACzE,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,8DAA8D;IAC9D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED;yCACyC;AACzC,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CAAC;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,0EAA0E;IAC1E,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,SAAS,EAAE,cAAc,CAAC;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,cAAc;IAC7B,0EAA0E;IAC1E,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC;IAC7B,uEAAuE;IACvE,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC;IAClC,+EAA+E;IAC/E,QAAQ,CAAC,cAAc,EAAE,QAAQ,CAAC;IAClC,4EAA4E;IAC5E,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAC1B;4BACwB;IACxB,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC;CAChC;AAED;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,cAAc,GAAG,KAAK,GAAG,MAAM,CAEhF;AAED;+EAC+E;AAC/E,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,UAAU,EAAE,cAAc,CA+D/D,CAAC;AAEF;;qBAEqB;AACrB,wBAAgB,cAAc,CAAC,QAAQ,EAAE,UAAU,GAAG,cAAc,CAEnE;AAED;;sCAEsC;AACtC,wBAAgB,2BAA2B,IAAI,SAAS,UAAU,EAAE,CAEnE;AAED,wBAAgB,gCAAgC,IAAI,SAAS,UAAU,EAAE,CAExE;AAED,gFAAgF;AAChF,eAAO,MAAM,qBAAqB,EAAE,SAAS,MAAM,EAKlD,CAAC;AAEF;;;kCAGkC;AAClC,wBAAgB,mBAAmB,IAAI,MAAM,CAQ5C"}
@@ -0,0 +1,150 @@
1
+ "use strict";
2
+ /**
3
+ * CE-9 (spec R5) — the raw-lane provider × knob support matrix, the SINGLE
4
+ * source of truth for which knobs each provider honors on `rig.runRaw`.
5
+ *
6
+ * BOTH the runtime guard (`assertRawKnobsSupported`, run/raw.ts) and the docs
7
+ * generator (scripts/build-docs-site.ts) import `RAW_KNOB_SUPPORT` — so the
8
+ * fail-closed behavior a customer hits at runtime and the published matrix they
9
+ * read beforehand can never disagree. The guard's provider sets are no longer
10
+ * inline literals; adding a provider (or widening a knob) is one edit here.
11
+ *
12
+ * The knob discipline this table encodes (spec R1/R2/R4):
13
+ * - grounding: gemini honors native web grounding (grok's Live Search was retired by
14
+ * xAI — 410 on the CE-9 live gate — so grok is fail-closed until CE-9b lands the
15
+ * Responses-API web_search path); every other provider
16
+ * FAILS CLOSED pre-dispatch (guarded).
17
+ * - reasoning: NO per-model allowlist outside gemini (the drift cost the
18
+ * customer flagged). openai/deepinfra/fireworks forward `level` verbatim as
19
+ * `reasoning_effort` and let the provider enforce (a rejection is classified
20
+ * teachably in each adapter); grok forwards a DISCLOSED coarsening
21
+ * (`coarsenGrokReasoningEffort`); gemini stays model-gated (the adapter
22
+ * rejects a non-thinking model); deepseek + anthropic FAIL CLOSED at the
23
+ * guard with a provider-specific fixHint.
24
+ * - responseFormat ("json_object"): the OpenAI-dialect providers + gemini
25
+ * (mime-shaping only) honor it; anthropic FAILS CLOSED (guarded). This is
26
+ * mime-shaping, NOT schema enforcement — F4 stands (no validation/repair,
27
+ * `meta.validated` stays false).
28
+ * - cache + serviceTier are INFORMATIONAL here (never a hard fail): the cache
29
+ * directive is provider-neutral (a resource HANDLE on gemini, a routing HINT
30
+ * on the prompt_cache_key providers) and serviceTier forwards everywhere.
31
+ */
32
+ Object.defineProperty(exports, "__esModule", { value: true });
33
+ exports.RAW_KNOB_MATRIX_NOTES = exports.RAW_KNOB_SUPPORT = void 0;
34
+ exports.coarsenGrokReasoningEffort = coarsenGrokReasoningEffort;
35
+ exports.rawKnobSupport = rawKnobSupport;
36
+ exports.groundingSupportedProviders = groundingSupportedProviders;
37
+ exports.responseFormatSupportedProviders = responseFormatSupportedProviders;
38
+ exports.renderRawKnobMatrix = renderRawKnobMatrix;
39
+ const provider_1 = require("../types/provider");
40
+ /**
41
+ * The grok reasoning coarsening (R1): xAI's `reasoning_effort` accepts only
42
+ * `"low" | "high"`, so the four-level neutral vocabulary is coarsened —
43
+ * `minimal, low → "low"`; `medium, high → "high"`. This is a DISCLOSED, lossy
44
+ * mapping (it appears in the matrix note, the grok field's doc comment, and the
45
+ * `grok.test.ts` test), never a silent semantic drop. Kept here — beside the
46
+ * matrix that documents it — as the ONE place the algorithm lives (grok.ts
47
+ * imports it).
48
+ */
49
+ function coarsenGrokReasoningEffort(level) {
50
+ return level === "minimal" || level === "low" ? "low" : "high";
51
+ }
52
+ /** The matrix. Exhaustive over ProviderId — a new provider forces a compile
53
+ * error here (Record<ProviderId, …>), so it can never be silently unlisted. */
54
+ exports.RAW_KNOB_SUPPORT = {
55
+ gemini: {
56
+ grounding: { supported: true, note: "native — Google Search (`googleSearch` tool)" },
57
+ reasoning: { kind: "model-gated", note: "`level` → `thinkingConfig.thinkingLevel`, thinking-capable models only (see `GEMINI_THINKING_CAPABLE_MODELS`)" },
58
+ responseFormat: { supported: true, note: "`responseMimeType: application/json` (mime-shaping only — no schema, `validated` stays false)" },
59
+ cache: { semantics: "handle", note: "`cache.key` = a `cachedContent` resource handle (customer-owned lifecycle)" },
60
+ serviceTier: { supported: true, note: "`flex` / `standard` / `priority` honored" },
61
+ },
62
+ openai: {
63
+ grounding: { supported: false, note: "fail-closed" },
64
+ reasoning: { kind: "forward", note: "`level` → `reasoning_effort` (1:1); a non-reasoning model's rejection is classified teachably" },
65
+ responseFormat: { supported: true, note: "`response_format: { type: json_object }`" },
66
+ cache: { semantics: "hint", note: "`cache.key` → `prompt_cache_key`; `ttlSeconds ≥ 86400` → `prompt_cache_retention: 24h`" },
67
+ serviceTier: { supported: true, note: "`flex` (allowlist) / `priority`; flex→standard is a customer-side degrade (§3.2)" },
68
+ },
69
+ grok: {
70
+ grounding: { supported: false, note: "fail-closed — xAI retired Live Search (HTTP 410, 2026-08-21); native `web_search` needs the Responses API, tracked as CE-9b" },
71
+ reasoning: { kind: "coarsen", note: 'coarsened (disclosed): `minimal,low → "low"`; `medium,high → "high"` → `reasoning_effort`' },
72
+ responseFormat: { supported: true, note: "`response_format: { type: json_object }`" },
73
+ cache: { semantics: "hint", note: "`cache.key` → `prompt_cache_key` (routing hint)" },
74
+ serviceTier: { supported: false, note: "no tiers — always `standard`" },
75
+ },
76
+ deepseek: {
77
+ grounding: { supported: false, note: "fail-closed" },
78
+ reasoning: {
79
+ kind: "fail-closed",
80
+ note: "no effort control — reasoning is model selection (`deepseek-reasoner`)",
81
+ fixHint: "DeepSeek has no reasoning-effort control — select the deepseek-reasoner model instead and remove reasoning",
82
+ },
83
+ responseFormat: { supported: true, note: "`response_format: { type: json_object }` — the prompt must contain the word \"JSON\" (caller's responsibility on the raw lane)" },
84
+ cache: { semantics: "implicit", note: "automatic prefix cache — the key is not used" },
85
+ serviceTier: { supported: false, note: "no tiers — always `standard`" },
86
+ },
87
+ anthropic: {
88
+ grounding: { supported: false, note: "fail-closed" },
89
+ reasoning: {
90
+ kind: "fail-closed",
91
+ note: "extended thinking is not wired on the raw lane (future work)",
92
+ fixHint: "Anthropic extended thinking is not wired on the raw lane in v1 — remove reasoning",
93
+ },
94
+ responseFormat: {
95
+ supported: false,
96
+ note: "fail-closed — no json_object equivalent (structured output is a forced tool call)",
97
+ },
98
+ cache: { semantics: "marker", note: "prefix caching via `cache_control` markers — the key is not used" },
99
+ serviceTier: { supported: false, note: "no tiers — always `standard`" },
100
+ },
101
+ deepinfra: {
102
+ grounding: { supported: false, note: "fail-closed" },
103
+ reasoning: { kind: "forward", note: "`level` → `reasoning_effort` (1:1); a non-reasoning model's rejection is classified teachably" },
104
+ responseFormat: { supported: true, note: "`response_format: { type: json_object }`" },
105
+ cache: { semantics: "hint", note: "`cache.key` → `prompt_cache_key` (routing hint)" },
106
+ serviceTier: { supported: false, note: "no tiers — always `standard`" },
107
+ },
108
+ fireworks: {
109
+ grounding: { supported: false, note: "fail-closed" },
110
+ reasoning: { kind: "forward", note: "`level` → `reasoning_effort` (1:1); a non-reasoning model's rejection is classified teachably" },
111
+ responseFormat: { supported: true, note: "`response_format: { type: json_object }`" },
112
+ cache: { semantics: "hint", note: "`cache.key` → `prompt_cache_key` (routing hint; caching is automatic host-side)" },
113
+ serviceTier: { supported: false, note: "no tiers — always `standard`" },
114
+ },
115
+ };
116
+ /** Pure lookup into the matrix (spec R6, exported from the package root). A
117
+ * customer's multi-provider dispatcher ASKS this instead of duplicating the
118
+ * provider lists. */
119
+ function rawKnobSupport(provider) {
120
+ return exports.RAW_KNOB_SUPPORT[provider];
121
+ }
122
+ /** Providers that honor a knob, in PROVIDER_IDS order — used by the guard to
123
+ * build a "supported on X, Y only" fixHint from the matrix (so the error text
124
+ * can never drift from the table). */
125
+ function groundingSupportedProviders() {
126
+ return provider_1.PROVIDER_IDS.filter((p) => exports.RAW_KNOB_SUPPORT[p].grounding.supported);
127
+ }
128
+ function responseFormatSupportedProviders() {
129
+ return provider_1.PROVIDER_IDS.filter((p) => exports.RAW_KNOB_SUPPORT[p].responseFormat.supported);
130
+ }
131
+ /** Matrix-level notes rendered below the table (spec §3.2 restated in docs). */
132
+ exports.RAW_KNOB_MATRIX_NOTES = [
133
+ "**Fail-closed is discoverable, not a surprise.** A knob a provider cannot honor throws `RigFailureError` `invariant_violation` PRE-DISPATCH (no meter, no provider call, no telemetry row) — read this table before you call, not after.",
134
+ "**reasoning has NO per-model allowlist outside gemini.** openai/deepinfra/fireworks forward `level` verbatim and let the provider enforce; a rejection surfaces as a classified failure that names the fix. grok coarsens (disclosed above). deepseek reasoning is model selection (`deepseek-reasoner`); anthropic extended thinking is unwired.",
135
+ "**responseFormat is mime-shaping, not schema enforcement.** `json_object` forces syntactic JSON only — the raw lane still never validates or repairs, and `meta.validated` stays `false` (F4).",
136
+ "**§3.2 flex degrade is customer-side.** ModelRig does not replicate the gemini direct-path infra-retry wrapper on the raw lane; under `flex` a capacity rejection surfaces classified (`capacity_shed`) for your own `→ standard` retry ladder — a NAMED difference for your migration record, not a silent one.",
137
+ ];
138
+ /** Render the provider × knob matrix as a Markdown table + notes, FROM the
139
+ * matrix (never a hand-written table — R5). Consumed by the docs generator
140
+ * (scripts/build-docs-site.ts) so the published matrix and the runtime guard
141
+ * derive from the same source. */
142
+ function renderRawKnobMatrix() {
143
+ const header = "| Provider | grounding | reasoning | responseFormat | cache | serviceTier |";
144
+ const sep = "|---|---|---|---|---|---|";
145
+ const rows = provider_1.PROVIDER_IDS.map((p) => {
146
+ const s = exports.RAW_KNOB_SUPPORT[p];
147
+ return `| \`${p}\` | ${s.grounding.note} | ${s.reasoning.note} | ${s.responseFormat.note} | ${s.cache.note} | ${s.serviceTier.note} |`;
148
+ });
149
+ return [header, sep, ...rows, "", ...exports.RAW_KNOB_MATRIX_NOTES].join("\n");
150
+ }
package/dist/run/raw.d.ts CHANGED
@@ -28,10 +28,18 @@
28
28
  * Each is ADDITIVE: absent ⇒ byte-identical dispatch. A DECLARED directive is
29
29
  * never silently dropped — `grounding`/`reasoning` on a provider that cannot
30
30
  * honor it are rejected fail-closed PRE-DISPATCH (`assertRawKnobsSupported`),
31
- * with no meter, no provider call, and no telemetry row. v1 support set for
32
- * both = { gemini }. `serviceTier` forwards to every adapter's tier path and
33
- * `meta.requestedTier` now reports the DECLARED tier (an honesty fix — it
34
- * previously hardcoded `"standard"`).
31
+ * with no meter, no provider call, and no telemetry row. `serviceTier`
32
+ * forwards to every adapter's tier path and `meta.requestedTier` now reports
33
+ * the DECLARED tier (an honesty fix — it previously hardcoded `"standard"`).
34
+ * - CE-9: multi-provider parity. `grounding` now also serves grok (xAI Live
35
+ * Search); `reasoning` generalizes beyond gemini WITHOUT a per-model
36
+ * allowlist — openai/deepinfra/fireworks forward `level` → `reasoning_effort`
37
+ * verbatim (provider enforces, rejection classified teachably), grok coarsens
38
+ * (disclosed), gemini stays model-gated, deepseek/anthropic fail closed; a
39
+ * new `responseFormat: "json_object"` knob mime-shapes on the OpenAI-dialect
40
+ * providers + gemini (anthropic fails closed). The provider×knob support set
41
+ * is ONE table (`run/raw-support.ts`) the guard AND the published docs matrix
42
+ * both read — they can never disagree (R5).
35
43
  */
36
44
  import type { AdapterRequest, CandidateRef, ProviderId, ReasoningParams, ServiceTier, ToolChoice, ToolDefinition } from "../types/provider";
37
45
  import type { RunResult, RunTags } from "../types/route";
@@ -95,6 +103,16 @@ export interface RawRunInput {
95
103
  * pre-dispatch (`assertRawKnobsSupported`); declared on a non-thinking gemini
96
104
  * model is rejected classified by the adapter (`geminiReasoningUnsupported`). */
97
105
  readonly reasoning?: ReasoningParams;
106
+ /** CE-9 R4 — syntactic-JSON response shaping on the raw lane. `"json_object"`
107
+ * maps to each provider's json_object / json-mime directive (OpenAI-dialect
108
+ * providers + gemini); ABSENT ⇒ byte-identical (no key added). This is
109
+ * MIME-SHAPING, NOT schema enforcement — F4 stands: no validation, no repair,
110
+ * `meta.validated` stays false. GUARDED: anthropic has no equivalent and is
111
+ * rejected fail-closed pre-dispatch (`assertRawKnobsSupported`). DeepSeek's
112
+ * documented wrinkle — its json_object mode 400s when the literal word "JSON"
113
+ * appears nowhere in the prompt — is the CALLER's prompt responsibility on the
114
+ * raw lane (documented in the R5 matrix, never injected here). */
115
+ readonly responseFormat?: "json_object";
98
116
  }
99
117
  export interface RawRunDeps {
100
118
  readonly telemetry: TelemetryStore;
@@ -104,13 +122,25 @@ export interface RawRunDeps {
104
122
  readonly unpricedRateUsdPerMTok?: number;
105
123
  }
106
124
  /**
107
- * CE-2 fail-closed guard (spec §3 F1/F3). A DECLARED directive is NEVER silently
108
- * dropped: `grounding`/`reasoning` on a provider that cannot honor it — or a
109
- * `grounding.mode` other than the v1-supported `"native"` — throws
110
- * `RigFailureError` `invariant_violation` (the existing TERMINAL class; no new
111
- * FailureClass member, spec §3 rationale) BEFORE any adapter is built, any
112
- * provider call is made, or any telemetry row is written. Exported so the guard
113
- * is unit-testable without a network. Idempotent and side-effect-free.
125
+ * CE-2/CE-9 fail-closed guard (spec §3 F1/F3, CE-9 R1/R2/R4). A DECLARED
126
+ * directive is NEVER silently dropped: a `grounding`/`responseFormat` on a
127
+ * provider that cannot honor it, a `reasoning` on a provider with NO effort
128
+ * control (deepseek/anthropic), or a `grounding.mode` other than the
129
+ * v1-supported `"native"` throws `RigFailureError` `invariant_violation` (the
130
+ * existing TERMINAL class; no new FailureClass member) BEFORE any adapter is
131
+ * built, any provider call is made, or any telemetry row is written.
132
+ *
133
+ * The support facts come from `RAW_KNOB_SUPPORT` (run/raw-support.ts) — the ONE
134
+ * table the published docs matrix also reads, so the guard and the docs can
135
+ * never disagree (R5). What the guard does NOT reject (and why):
136
+ * - reasoning on openai/deepinfra/fireworks is FORWARDED verbatim
137
+ * (`kind: "forward"`) and the provider enforces — a rejection is classified
138
+ * teachably by the adapter (no per-model allowlist, R1).
139
+ * - reasoning on grok is a DISCLOSED coarsening (`kind: "coarsen"`).
140
+ * - reasoning on gemini is model-gated (`kind: "model-gated"`) — the adapter
141
+ * rejects a non-thinking model (`geminiReasoningUnsupported`).
142
+ * Exported so the guard is unit-testable without a network. Idempotent and
143
+ * side-effect-free.
114
144
  */
115
145
  export declare function assertRawKnobsSupported(input: RawRunInput): void;
116
146
  /** Pure raw-lane request shaping — exported for unit tests (no network). */
@@ -1 +1 @@
1
- {"version":3,"file":"raw.d.ts","sourceRoot":"","sources":["../../src/run/raw.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAYH,OAAO,KAAK,EACV,cAAc,EAGd,YAAY,EAGZ,UAAU,EACV,eAAe,EACf,WAAW,EACX,UAAU,EACV,cAAc,EACf,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAW,SAAS,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAClE,OAAO,KAAK,EAAkB,eAAe,EAAE,MAAM,UAAU,CAAC;AAChE,OAAO,KAAK,EAAgB,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEvE;;;sCAGsC;AACtC,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB;iFAC6E;IAC7E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC;;;6EAGyE;IACzE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,cAAc,EAAE,CAAC;IAC3C,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC;IACjC;;;;;;;0BAOsB;IACtB,QAAQ,CAAC,KAAK,CAAC,EAAE;QAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACxE;;;;;;;iDAO6C;IAC7C,QAAQ,CAAC,SAAS,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;KAAE,CAAC;IACjD;;;;mFAI+E;IAC/E,QAAQ,CAAC,WAAW,CAAC,EAAE,WAAW,CAAC;IACnC;;;;qFAIiF;IACjF,QAAQ,CAAC,SAAS,CAAC,EAAE,eAAe,CAAC;CACtC;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,SAAS,EAAE,cAAc,CAAC;IACnC;;+EAE2E;IAC3E,QAAQ,CAAC,sBAAsB,CAAC,EAAE,MAAM,CAAC;CAC1C;AAkDD;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI,CAiChE;AAED,4EAA4E;AAC5E,wBAAgB,eAAe,CAAC,SAAS,EAAE,YAAY,EAAE,KAAK,EAAE,WAAW,GAAG,cAAc,CAiC3F;AAsJD;wDACwD;AACxD,wBAAsB,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,SAAS,CAAC,CASrF;AAcD;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,WAAW,GAAG,eAAe,CA6ClF"}
1
+ {"version":3,"file":"raw.d.ts","sourceRoot":"","sources":["../../src/run/raw.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAiBH,OAAO,KAAK,EACV,cAAc,EAGd,YAAY,EAGZ,UAAU,EACV,eAAe,EACf,WAAW,EACX,UAAU,EACV,cAAc,EACf,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAW,SAAS,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAClE,OAAO,KAAK,EAAkB,eAAe,EAAE,MAAM,UAAU,CAAC;AAChE,OAAO,KAAK,EAA+B,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEtF;;;sCAGsC;AACtC,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB;iFAC6E;IAC7E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC;;;6EAGyE;IACzE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,cAAc,EAAE,CAAC;IAC3C,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC;IACjC;;;;;;;0BAOsB;IACtB,QAAQ,CAAC,KAAK,CAAC,EAAE;QAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACxE;;;;;;;iDAO6C;IAC7C,QAAQ,CAAC,SAAS,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;KAAE,CAAC;IACjD;;;;mFAI+E;IAC/E,QAAQ,CAAC,WAAW,CAAC,EAAE,WAAW,CAAC;IACnC;;;;qFAIiF;IACjF,QAAQ,CAAC,SAAS,CAAC,EAAE,eAAe,CAAC;IACrC;;;;;;;;sEAQkE;IAClE,QAAQ,CAAC,cAAc,CAAC,EAAE,aAAa,CAAC;CACzC;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,SAAS,EAAE,cAAc,CAAC;IACnC;;+EAE2E;IAC3E,QAAQ,CAAC,sBAAsB,CAAC,EAAE,MAAM,CAAC;CAC1C;AA0CD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI,CAiDhE;AAED,4EAA4E;AAC5E,wBAAgB,eAAe,CAAC,SAAS,EAAE,YAAY,EAAE,KAAK,EAAE,WAAW,GAAG,cAAc,CAqC3F;AAsKD;wDACwD;AACxD,wBAAsB,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,SAAS,CAAC,CASrF;AAcD;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,WAAW,GAAG,eAAe,CA6ClF"}
package/dist/run/raw.js CHANGED
@@ -29,10 +29,18 @@
29
29
  * Each is ADDITIVE: absent ⇒ byte-identical dispatch. A DECLARED directive is
30
30
  * never silently dropped — `grounding`/`reasoning` on a provider that cannot
31
31
  * honor it are rejected fail-closed PRE-DISPATCH (`assertRawKnobsSupported`),
32
- * with no meter, no provider call, and no telemetry row. v1 support set for
33
- * both = { gemini }. `serviceTier` forwards to every adapter's tier path and
34
- * `meta.requestedTier` now reports the DECLARED tier (an honesty fix — it
35
- * previously hardcoded `"standard"`).
32
+ * with no meter, no provider call, and no telemetry row. `serviceTier`
33
+ * forwards to every adapter's tier path and `meta.requestedTier` now reports
34
+ * the DECLARED tier (an honesty fix — it previously hardcoded `"standard"`).
35
+ * - CE-9: multi-provider parity. `grounding` now also serves grok (xAI Live
36
+ * Search); `reasoning` generalizes beyond gemini WITHOUT a per-model
37
+ * allowlist — openai/deepinfra/fireworks forward `level` → `reasoning_effort`
38
+ * verbatim (provider enforces, rejection classified teachably), grok coarsens
39
+ * (disclosed), gemini stays model-gated, deepseek/anthropic fail closed; a
40
+ * new `responseFormat: "json_object"` knob mime-shapes on the OpenAI-dialect
41
+ * providers + gemini (anthropic fails closed). The provider×knob support set
42
+ * is ONE table (`run/raw-support.ts`) the guard AND the published docs matrix
43
+ * both read — they can never disagree (R5).
36
44
  */
37
45
  Object.defineProperty(exports, "__esModule", { value: true });
38
46
  exports.assertRawKnobsSupported = assertRawKnobsSupported;
@@ -48,6 +56,7 @@ const openai_1 = require("../adapters/openai");
48
56
  const openai_compat_1 = require("../adapters/openai-compat");
49
57
  const cost_1 = require("./cost");
50
58
  const resolve_1 = require("./resolve");
59
+ const raw_support_1 = require("./raw-support");
51
60
  const failures_1 = require("../types/failures");
52
61
  /** Absent a route timeout, the raw lane uses a generous default — a passthrough
53
62
  * should not be shorter-fused than the underlying provider SDK. */
@@ -86,23 +95,29 @@ function buildRawAdapter(provider, apiKey) {
86
95
  }
87
96
  }
88
97
  }
89
- /** Providers that can honor a DECLARED raw-lane directive in v1 (spec §3
90
- * fail-closed matrix). Native grounding and reasoning are both gemini-only
91
- * today; the other adapters would silently ignore the field — exactly the bug
92
- * class CE-2 makes impossible. A new-provider entry here is a deliberate,
93
- * spec-gated widening, never an accident. */
94
- const NATIVE_GROUNDING_PROVIDERS = new Set(["gemini"]);
95
- const REASONING_PROVIDERS = new Set(["gemini"]);
96
98
  /**
97
- * CE-2 fail-closed guard (spec §3 F1/F3). A DECLARED directive is NEVER silently
98
- * dropped: `grounding`/`reasoning` on a provider that cannot honor it — or a
99
- * `grounding.mode` other than the v1-supported `"native"` — throws
100
- * `RigFailureError` `invariant_violation` (the existing TERMINAL class; no new
101
- * FailureClass member, spec §3 rationale) BEFORE any adapter is built, any
102
- * provider call is made, or any telemetry row is written. Exported so the guard
103
- * is unit-testable without a network. Idempotent and side-effect-free.
99
+ * CE-2/CE-9 fail-closed guard (spec §3 F1/F3, CE-9 R1/R2/R4). A DECLARED
100
+ * directive is NEVER silently dropped: a `grounding`/`responseFormat` on a
101
+ * provider that cannot honor it, a `reasoning` on a provider with NO effort
102
+ * control (deepseek/anthropic), or a `grounding.mode` other than the
103
+ * v1-supported `"native"` throws `RigFailureError` `invariant_violation` (the
104
+ * existing TERMINAL class; no new FailureClass member) BEFORE any adapter is
105
+ * built, any provider call is made, or any telemetry row is written.
106
+ *
107
+ * The support facts come from `RAW_KNOB_SUPPORT` (run/raw-support.ts) — the ONE
108
+ * table the published docs matrix also reads, so the guard and the docs can
109
+ * never disagree (R5). What the guard does NOT reject (and why):
110
+ * - reasoning on openai/deepinfra/fireworks is FORWARDED verbatim
111
+ * (`kind: "forward"`) and the provider enforces — a rejection is classified
112
+ * teachably by the adapter (no per-model allowlist, R1).
113
+ * - reasoning on grok is a DISCLOSED coarsening (`kind: "coarsen"`).
114
+ * - reasoning on gemini is model-gated (`kind: "model-gated"`) — the adapter
115
+ * rejects a non-thinking model (`geminiReasoningUnsupported`).
116
+ * Exported so the guard is unit-testable without a network. Idempotent and
117
+ * side-effect-free.
104
118
  */
105
119
  function assertRawKnobsSupported(input) {
120
+ const support = raw_support_1.RAW_KNOB_SUPPORT[input.provider];
106
121
  const groundingMode = input.grounding?.mode;
107
122
  if (groundingMode !== undefined) {
108
123
  if (groundingMode !== "native") {
@@ -114,23 +129,35 @@ function assertRawKnobsSupported(input) {
114
129
  fixHint: 'only { mode: "native" } grounding is supported on the raw lane in v1',
115
130
  });
116
131
  }
117
- if (!NATIVE_GROUNDING_PROVIDERS.has(input.provider)) {
132
+ if (!support.grounding.supported) {
118
133
  throw new failures_1.RigFailureError({
119
134
  class: "invariant_violation",
120
135
  message: `native grounding on the raw lane is not supported for provider "${input.provider}"`,
121
136
  provider: input.provider,
122
137
  model: input.model,
123
- fixHint: "native grounding on the raw lane is gemini-only in v1; remove grounding or switch provider",
138
+ fixHint: `native grounding on the raw lane is supported on ${(0, raw_support_1.groundingSupportedProviders)().join(", ")} only; remove grounding or switch provider`,
124
139
  });
125
140
  }
126
141
  }
127
- if (input.reasoning !== undefined && !REASONING_PROVIDERS.has(input.provider)) {
142
+ if (input.reasoning !== undefined && support.reasoning.kind === "fail-closed") {
128
143
  throw new failures_1.RigFailureError({
129
144
  class: "invariant_violation",
130
145
  message: `reasoning control on the raw lane is not supported for provider "${input.provider}"`,
131
146
  provider: input.provider,
132
147
  model: input.model,
133
- fixHint: "reasoning control on the raw lane is gemini-only in v1; remove reasoning or switch provider",
148
+ // Provider-specific teaching straight from the matrix (deepseek →
149
+ // deepseek-reasoner; anthropic → extended thinking unwired).
150
+ fixHint: support.reasoning.fixHint ??
151
+ "reasoning control is not available for this provider on the raw lane; remove reasoning",
152
+ });
153
+ }
154
+ if (input.responseFormat !== undefined && !support.responseFormat.supported) {
155
+ throw new failures_1.RigFailureError({
156
+ class: "invariant_violation",
157
+ message: `responseFormat on the raw lane is not supported for provider "${input.provider}"`,
158
+ provider: input.provider,
159
+ model: input.model,
160
+ fixHint: `responseFormat: "json_object" on the raw lane is supported on ${(0, raw_support_1.responseFormatSupportedProviders)().join(", ")} only; remove responseFormat or switch provider`,
134
161
  });
135
162
  }
136
163
  }
@@ -163,6 +190,10 @@ function buildRawRequest(candidate, input) {
163
190
  ...(input.grounding?.mode === "native" ? { grounding: true } : {}),
164
191
  // CE-2 F3: forward reasoning verbatim; absent ⇒ no key added (byte-identical).
165
192
  ...(input.reasoning !== undefined ? { reasoning: input.reasoning } : {}),
193
+ // CE-9 R4: forward the json_object directive verbatim; absent ⇒ no key added
194
+ // (byte-identical). An unsupported provider (anthropic) never reaches here —
195
+ // the guard (assertRawKnobsSupported) rejects it pre-dispatch.
196
+ ...(input.responseFormat !== undefined ? { responseFormat: input.responseFormat } : {}),
166
197
  ...(input.tools !== undefined ? { tools: input.tools } : {}),
167
198
  ...(input.toolChoice !== undefined ? { toolChoice: input.toolChoice } : {}),
168
199
  ...(input.cache !== undefined ? { cache: input.cache } : {}),
@@ -193,7 +224,10 @@ function recordRawRow(telemetry, p) {
193
224
  ttfbMs: p.usage?.ttfbMs ?? null,
194
225
  failureClass: p.failureClass,
195
226
  attemptsJson: "{}",
196
- tagsJson: JSON.stringify(p.tags),
227
+ // Rung tag (R1 review, F1): the raw lane is a single primary dispatch. Raw
228
+ // rows carry `lane: "raw"` and are excluded from route rollups, but every row
229
+ // gets a rung for a uniform contract.
230
+ tagsJson: JSON.stringify({ ...p.tags, rung: "primary" }),
197
231
  fingerprintCell: null,
198
232
  servedVariant: null,
199
233
  repairedBy: null,
@@ -203,6 +237,10 @@ function recordRawRow(telemetry, p) {
203
237
  // provenance rule reads any non-null key here as `customer`.
204
238
  cacheKey: p.cacheKey ?? null,
205
239
  prefixFingerprint: null,
240
+ // Ladder key (spec §2.1 R0): raw lane = one row per call, seq 1, index 0.
241
+ callId: p.callId,
242
+ attemptSeq: 1,
243
+ candidateIndex: 0,
206
244
  };
207
245
  telemetry.record(row);
208
246
  }
@@ -215,6 +253,9 @@ function recordRawRow(telemetry, p) {
215
253
  function finalizeRaw(deps, input, result, latencyMs) {
216
254
  const unpricedRatePerTok = (deps.unpricedRateUsdPerMTok ?? cost_1.DEFAULT_UNPRICED_RATE_USD_PER_MTOK) / 1000000;
217
255
  const rawModelId = `${input.provider}/${input.model}`;
256
+ // One call_id for this raw invocation — shared by the (single) recorded row and
257
+ // the returned meta (spec §2.1 R0).
258
+ const callId = (0, node_crypto_1.randomUUID)();
218
259
  // CE-2 F2: the declared tier is reported truthfully on the row AND the meta.
219
260
  const requestedTier = input.serviceTier ?? "standard";
220
261
  // lane is SDK-owned and cannot be overridden by a caller-supplied tag.
@@ -239,6 +280,7 @@ function finalizeRaw(deps, input, result, latencyMs) {
239
280
  failureClass: result.failure.class,
240
281
  tags,
241
282
  pricingMissing,
283
+ callId,
242
284
  ...(input.cache !== undefined ? { cacheKey: input.cache.key } : {}),
243
285
  });
244
286
  throw new failures_1.RigFailureError(result.failure);
@@ -257,6 +299,7 @@ function finalizeRaw(deps, input, result, latencyMs) {
257
299
  failureClass: null,
258
300
  tags,
259
301
  pricingMissing,
302
+ callId,
260
303
  ...(input.cache !== undefined ? { cacheKey: input.cache.key } : {}),
261
304
  });
262
305
  const toolCalls = result.toolCalls;
@@ -278,6 +321,7 @@ function finalizeRaw(deps, input, result, latencyMs) {
278
321
  attemptsByClass: {},
279
322
  servedVariant: null,
280
323
  repairedBy: null,
324
+ callId,
281
325
  ...(isToolTurn ? { toolCalls } : {}),
282
326
  };
283
327
  return { output: isToolTurn ? null : result.text, meta };
@@ -0,0 +1,60 @@
1
+ /**
2
+ * runRaw-only construction — CE-8 (ruling R1,
3
+ * `docs/ModelRig/customer-efficiency/ce8-runraw-only-rig-spec-plan.md`).
4
+ *
5
+ * A Lane-B customer who only calls `rig.runRaw`/`rig.runRawStream` has no routes.
6
+ * With `routesDir: null`, `createRig` SKIPS route loading, the `rig.yaml`
7
+ * manifest, and the serveable-candidate gate — so a stray route file (or a route
8
+ * whose provider key is absent in this deployment) can no longer down a rig that
9
+ * never serves it. The raw lane is unchanged; every route-dependent surface
10
+ * (`run`/`runStream`/`runBundle`/`replay`/`bakeoff`/`verifySwap`) fails with a
11
+ * TERMINAL `invariant_violation` that teaches the fix — Promise surfaces reject,
12
+ * the two streaming surfaces hand back a handle whose `result`/`events` fail
13
+ * (never a synchronous throw, matching the real `runStream` contract).
14
+ *
15
+ * This module holds the small pieces of that opt-out (the empty store, the
16
+ * teaching failure, the throwing route methods) so `index.ts` stays under the
17
+ * 700-LOC cap — `createRig` remains the ONE construction path (a separate
18
+ * `createRawRig()` factory was considered and REJECTED, spec §2 R1).
19
+ */
20
+ import type { RigConfig } from "../config";
21
+ import { type LoadedRoutes } from "../routes/loader";
22
+ import { RigFailureError } from "../types/failures";
23
+ import type { Rig } from "../index";
24
+ /** The teaching remediation for a route-lane call on a runRaw-only rig (spec §2
25
+ * R1). One constant so the failure and the docs stay in lock-step. */
26
+ export declare const RAW_ONLY_FIX_HINT = "this rig was constructed runRaw-only (routesDir: null); give createRig a routesDir to serve routes";
27
+ /** Build the TERMINAL failure a route-dependent surface throws when the rig was
28
+ * constructed runRaw-only. Reuses `invariant_violation` (already TERMINAL + in
29
+ * the teaching table) — no new FailureClass (spec §3 rationale). */
30
+ export declare function rawOnlyRouteFailure(surface: string): RigFailureError;
31
+ /** Narrow a config's `routesDir` to a string for a route-REQUIRED context (the
32
+ * route-oriented CLI subcommands: bakeoff/watch/swap/init/observe/validate),
33
+ * throwing the teaching failure if the rig was built runRaw-only.
34
+ * `loadConfigFromEnv` always yields a string (R2), so this is unreachable for
35
+ * env-built configs — it guards a hand-built `routesDir: null` reaching a
36
+ * route-only command, and satisfies the `string | null` type at those seams. */
37
+ export declare function requireRoutesDir(config: RigConfig, surface: string): string;
38
+ /** The empty route store for a runRaw-only rig: `list()` is `[]` (so
39
+ * serveability, capture-detection, and the exported route mirror are all no-ops)
40
+ * and `get()` teaches, though no public surface reaches it — every route method
41
+ * is overridden by {@link rawOnlyRouteMethods}. */
42
+ export declare function emptyRouteStore(): LoadedRoutes;
43
+ /** Load routes from a real (string) `routesDir`, mirroring a malformed-bundle
44
+ * diagnosis to the console before re-throwing — the byte-for-byte behaviour the
45
+ * string path had inline in `createRig` before CE-8 extracted it here. */
46
+ export declare function loadRoutesOrReport(config: RigConfig, routesDir: string): LoadedRoutes;
47
+ /** The route-dependent slice of the {@link Rig} surface, replaced wholesale when
48
+ * `routesDir === null` so every one of them throws the teaching failure rather
49
+ * than dereferencing an empty store. Spread LAST over the real methods in
50
+ * `createRig`, so later keys win. */
51
+ type RouteMethods = Pick<Rig, "run" | "runStream" | "runBundle" | "runBundleStream" | "replay" | "bakeoff" | "bakeoffFromEvalCases" | "verifySwap">;
52
+ /** The throwing overrides for a runRaw-only rig (spec §2 R1). Each names the
53
+ * surface + the route/task the caller asked for, so the terminal error points at
54
+ * exactly the call that needs a `routesDir`. Promise-returning surfaces REJECT
55
+ * (matching the routed lane, where errors surface as rejections); the two
56
+ * streaming surfaces return a handle synchronously, so they throw synchronously
57
+ * — the caller never reaches an event to await. */
58
+ export declare function rawOnlyRouteMethods(): RouteMethods;
59
+ export {};
60
+ //# sourceMappingURL=rawonly.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rawonly.d.ts","sourceRoot":"","sources":["../../src/run/rawonly.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAyC,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAE5F,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAEpC;sEACsE;AACtE,eAAO,MAAM,iBAAiB,uGACwE,CAAC;AAEvG;;oEAEoE;AACpE,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe,CAMpE;AAsBD;;;;;gFAKgF;AAChF,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAG3E;AAED;;;mDAGmD;AACnD,wBAAgB,eAAe,IAAI,YAAY,CAS9C;AAED;;0EAE0E;AAC1E,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,GAAG,YAAY,CASrF;AAED;;;qCAGqC;AACrC,KAAK,YAAY,GAAG,IAAI,CACtB,GAAG,EACD,KAAK,GACL,WAAW,GACX,WAAW,GACX,iBAAiB,GACjB,QAAQ,GACR,SAAS,GACT,sBAAsB,GACtB,YAAY,CACf,CAAC;AAEF;;;;;mDAKmD;AACnD,wBAAgB,mBAAmB,IAAI,YAAY,CAYlD"}