modelrig 0.2.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.
- package/CHANGELOG.md +204 -0
- package/README.md +68 -4
- package/dist/adapters/deepseek.d.ts.map +1 -1
- package/dist/adapters/deepseek.js +8 -1
- package/dist/adapters/gemini.d.ts +16 -0
- package/dist/adapters/gemini.d.ts.map +1 -1
- package/dist/adapters/gemini.js +44 -3
- package/dist/adapters/grok.d.ts +7 -0
- package/dist/adapters/grok.d.ts.map +1 -1
- package/dist/adapters/grok.js +23 -1
- package/dist/adapters/openai-compat.d.ts +7 -0
- package/dist/adapters/openai-compat.d.ts.map +1 -1
- package/dist/adapters/openai-compat.js +24 -1
- package/dist/adapters/openai.d.ts +7 -0
- package/dist/adapters/openai.d.ts.map +1 -1
- package/dist/adapters/openai.js +23 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +5 -4
- package/dist/config.d.ts +7 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/index.d.ts +6 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +28 -25
- package/dist/init/init-cli.d.ts.map +1 -1
- package/dist/init/init-cli.js +2 -1
- package/dist/init/observe-cli.d.ts.map +1 -1
- package/dist/init/observe-cli.js +2 -1
- package/dist/routes/loader.d.ts +11 -0
- package/dist/routes/loader.d.ts.map +1 -1
- package/dist/routes/loader.js +29 -0
- package/dist/routes/sampling-config.d.ts.map +1 -1
- package/dist/routes/sampling-config.js +11 -0
- package/dist/run/dispatch.d.ts +14 -2
- package/dist/run/dispatch.d.ts.map +1 -1
- package/dist/run/dispatch.js +31 -2
- package/dist/run/ladder-key.d.ts +40 -0
- package/dist/run/ladder-key.d.ts.map +1 -0
- package/dist/run/ladder-key.js +39 -0
- package/dist/run/raw-support.d.ts +123 -0
- package/dist/run/raw-support.d.ts.map +1 -0
- package/dist/run/raw-support.js +150 -0
- package/dist/run/raw.d.ts +73 -1
- package/dist/run/raw.d.ts.map +1 -1
- package/dist/run/raw.js +129 -8
- package/dist/run/rawonly.d.ts +60 -0
- package/dist/run/rawonly.d.ts.map +1 -0
- package/dist/run/rawonly.js +120 -0
- package/dist/run/record-attempt.d.ts +14 -1
- package/dist/run/record-attempt.d.ts.map +1 -1
- package/dist/run/record-attempt.js +43 -2
- package/dist/run/resolve.d.ts +4 -0
- package/dist/run/resolve.d.ts.map +1 -1
- package/dist/run/resolve.js +9 -2
- package/dist/run/routing-docs.d.ts +73 -0
- package/dist/run/routing-docs.d.ts.map +1 -0
- package/dist/run/routing-docs.js +222 -0
- package/dist/run/run.d.ts.map +1 -1
- package/dist/run/run.js +24 -22
- package/dist/telemetry/exporter.d.ts.map +1 -1
- package/dist/telemetry/exporter.js +6 -0
- package/dist/telemetry/ingest-protocol.d.ts +7 -0
- package/dist/telemetry/ingest-protocol.d.ts.map +1 -1
- package/dist/telemetry/load-error-report.d.ts.map +1 -1
- package/dist/telemetry/load-error-report.js +4 -1
- package/dist/telemetry/otel-map.d.ts.map +1 -1
- package/dist/telemetry/otel-map.js +8 -0
- package/dist/telemetry/store-migrations.d.ts +15 -0
- package/dist/telemetry/store-migrations.d.ts.map +1 -0
- package/dist/telemetry/store-migrations.js +119 -0
- package/dist/telemetry/store.d.ts.map +1 -1
- package/dist/telemetry/store.js +26 -93
- package/dist/types/failures-teaching.js +1 -1
- package/dist/types/provider.d.ts +38 -0
- package/dist/types/provider.d.ts.map +1 -1
- package/dist/types/route.d.ts +6 -1
- package/dist/types/route.d.ts.map +1 -1
- package/dist/types/telemetry.d.ts +31 -0
- package/dist/types/telemetry.d.ts.map +1 -1
- package/dist/validate-cli.d.ts.map +1 -1
- package/dist/validate-cli.js +17 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,210 @@ published package diverge.
|
|
|
10
10
|
This project adheres to [Semantic Versioning](https://semver.org/). Dates are
|
|
11
11
|
UTC.
|
|
12
12
|
|
|
13
|
+
## [0.4.0] — 2026-08-22
|
|
14
|
+
|
|
15
|
+
Released with the docs/registry mirror in one R-A ceremony. NOT in this tag:
|
|
16
|
+
the R3 declare-first `trial:` candidate flag (#239) and raw-lane artifact
|
|
17
|
+
steps (G1) — both land in 0.5.0.
|
|
18
|
+
|
|
19
|
+
CE-9 raw-lane multi-provider parity — the `reasoning` and native-grounding knobs
|
|
20
|
+
generalize beyond gemini, a `responseFormat` knob joins the raw lane, and the
|
|
21
|
+
provider×knob support set becomes ONE table (`RAW_KNOB_SUPPORT`) that the runtime
|
|
22
|
+
guard AND the published docs matrix both read, so they can never disagree. Every
|
|
23
|
+
knob stays ADDITIVE: absent ⇒ byte-identical to the 0.3.0 request shape.
|
|
24
|
+
|
|
25
|
+
### Added — docs
|
|
26
|
+
|
|
27
|
+
- **Routing & reliability page** (`https://modelrig.dev/routing-reliability.html`) —
|
|
28
|
+
the runtime model in one concept page: resolve -> candidate ladder -> validate ->
|
|
29
|
+
repair -> fall-through -> exhaust, what is stored per attempt, and a **code-anchored
|
|
30
|
+
boundary** (`ROUTING_BOUNDARY`, one tripwire test per entry) that lists what does not
|
|
31
|
+
trigger fall-through and what is not built — the build fails if a listed feature ships
|
|
32
|
+
without the entry being updated.
|
|
33
|
+
|
|
34
|
+
### Fixed
|
|
35
|
+
|
|
36
|
+
- **Failure-teaching links resolve.** `RigFailureError.docsUrl` (and the CLI/console
|
|
37
|
+
error render) now point at `routing-reliability.html#<class>` — one stable heading per
|
|
38
|
+
failure class — instead of the never-built `/docs/failures` path, which 404'd on
|
|
39
|
+
every typed failure.
|
|
40
|
+
|
|
41
|
+
### Added — `rig.runRaw` / `rig.runRawStream`
|
|
42
|
+
|
|
43
|
+
- **`reasoning` generalizes beyond gemini WITHOUT a per-model allowlist (R1).**
|
|
44
|
+
openai / deepinfra / fireworks forward `level` → `reasoning_effort` verbatim
|
|
45
|
+
and let the provider enforce — a model that does not accept it surfaces a
|
|
46
|
+
CLASSIFIED, teaching failure ("this model does not accept reasoning_effort —
|
|
47
|
+
remove reasoning or pick a reasoning model"), never a cryptic 400 or a silent
|
|
48
|
+
drop. grok forwards a DISCLOSED coarsening (`minimal,low → "low"`;
|
|
49
|
+
`medium,high → "high"`; xAI accepts `low|high` only). gemini stays
|
|
50
|
+
model-gated (thinking-capable models only). deepseek + anthropic FAIL CLOSED
|
|
51
|
+
pre-dispatch with a provider-specific fixHint (deepseek → select the
|
|
52
|
+
`deepseek-reasoner` model; anthropic → extended thinking unwired).
|
|
53
|
+
- **Grok native grounding (R2) — WITHDRAWN before release.** The CE-9 live gate hit xAI's `410 Live search is deprecated`; the replacement `web_search` tool is Responses-API-only, which the grok adapter does not speak yet. grok grounding FAILS CLOSED (matrix `supported: false`, teaching note) until CE-9b lands that path. Original entry, kept for the record: `grounding: { mode: "native" }` on grok →
|
|
54
|
+
xAI Live Search (`search_parameters: { mode: "on" }`). Citations are not
|
|
55
|
+
surfaced on `meta` in v1 (same documented limitation as gemini).
|
|
56
|
+
- **`responseFormat?: "json_object"` (R4).** MIME-shaping on the OpenAI-dialect
|
|
57
|
+
providers (openai/deepseek/grok/deepinfra/fireworks → `response_format: { type:
|
|
58
|
+
"json_object" }`) and gemini (`responseMimeType: "application/json"`, no
|
|
59
|
+
schema). This is syntactic-JSON forcing, NOT schema enforcement — F4 stands:
|
|
60
|
+
no validation, no repair, `meta.validated` stays false. anthropic has no
|
|
61
|
+
equivalent and FAILS CLOSED. DeepSeek's word-"JSON" prompt wrinkle is the
|
|
62
|
+
caller's responsibility on the raw lane (documented, never injected).
|
|
63
|
+
- **DeepInfra/Fireworks prompt-cache hint (R3).** `cache.key` now maps to
|
|
64
|
+
`prompt_cache_key` on the openai-compatible adapter, closing the DeepInfra cost
|
|
65
|
+
gap. (openai and grok already mapped `cache.key → prompt_cache_key` on 0.3.0 —
|
|
66
|
+
that was a docs gap, not a code gap; it is now documented as plain fact.)
|
|
67
|
+
|
|
68
|
+
### Added — exports (R5/R6)
|
|
69
|
+
|
|
70
|
+
- **`RAW_KNOB_SUPPORT`** (the provider×knob matrix) + **`rawKnobSupport(provider)`**
|
|
71
|
+
(a pure lookup) — a multi-provider dispatcher ASKS which knobs a provider
|
|
72
|
+
honors instead of duplicating our lists. The guard (`assertRawKnobsSupported`)
|
|
73
|
+
and the docs generator both import this table.
|
|
74
|
+
- **`GEMINI_THINKING_CAPABLE_MODELS`** — the thinking-capable set (previously
|
|
75
|
+
un-exported), so customers stop duplicating it (the §3.1 drift complaint).
|
|
76
|
+
- **`coarsenGrokReasoningEffort`** + **`renderRawKnobMatrix`** — the disclosed
|
|
77
|
+
grok coarsening and the docs matrix renderer.
|
|
78
|
+
|
|
79
|
+
### Docs
|
|
80
|
+
|
|
81
|
+
- A generated provider×knob matrix on the modelrig.dev route-bundles page and in
|
|
82
|
+
`llms.txt`, rendered FROM `RAW_KNOB_SUPPORT` (never a hand-written twin).
|
|
83
|
+
- `caching-lifecycle.md`: the cache directive is provider-neutral — a resource
|
|
84
|
+
HANDLE on gemini, a routing HINT (`prompt_cache_key`, retention on openai) on
|
|
85
|
+
the OpenAI-dialect providers.
|
|
86
|
+
|
|
87
|
+
CE-8 — first-class **runRaw-only construction**. A Lane-B customer who only calls
|
|
88
|
+
`rig.runRaw`/`runRawStream` can now build a rig with no routes at all, so a stray
|
|
89
|
+
route file it never serves cannot down construction — retiring the empty-temp-dir
|
|
90
|
+
workaround.
|
|
91
|
+
|
|
92
|
+
### Added
|
|
93
|
+
|
|
94
|
+
- **`RigConfig.routesDir` now accepts `null`** (was `string`). With `null`,
|
|
95
|
+
`createRig` SKIPS route loading, the `rig.yaml` manifest, and the
|
|
96
|
+
serveable-candidate gate; `runRaw`/`runRawStream` work exactly as before. The
|
|
97
|
+
`string` path is byte-identical to 0.3.0 (the existing serveability hard-error
|
|
98
|
+
on a zero-serveable route is unchanged and regression-pinned).
|
|
99
|
+
- **`requireRoutesDir(config, surface)`** exported — narrows `routesDir` to a
|
|
100
|
+
string for route-required contexts, throwing the teaching failure on `null`.
|
|
101
|
+
Used by `modelrig-server` and `modelrig-oracle` (both always serve routes).
|
|
102
|
+
|
|
103
|
+
### Behaviour
|
|
104
|
+
|
|
105
|
+
- On a `routesDir: null` rig, `run`/`runStream`/`runBundle`/`runBundleStream`/
|
|
106
|
+
`replay`/`bakeoff`/`bakeoffFromEvalCases`/`verifySwap` throw `RigFailureError`
|
|
107
|
+
class `invariant_violation` (no new failure class) with the fixHint
|
|
108
|
+
*"this rig was constructed runRaw-only (routesDir: null); give createRig a
|
|
109
|
+
routesDir to serve routes"*. `rig.serveability` is `[]`.
|
|
110
|
+
- `loadConfigFromEnv` stays string-only (no env var disables routes, by design);
|
|
111
|
+
opt out in code: `createRig({ ...loadConfigFromEnv(), routesDir: null })`.
|
|
112
|
+
|
|
113
|
+
### Docs
|
|
114
|
+
|
|
115
|
+
- README, `docs/migration-playbook.md` (Lane-B seam + C4 checkpoint), and the
|
|
116
|
+
generated `llms.txt` gain the runRaw-only construction snippet, the `apiKey`
|
|
117
|
+
BYOK line on every `runRaw` example, the combined-prompt → `userPrompt` note,
|
|
118
|
+
and the note that the cache-ratio-vs-baseline metric is a REAL-run measurement
|
|
119
|
+
(deferred-to-first-run at the checkpoint), not a probe.
|
|
120
|
+
|
|
121
|
+
R0 — the **per-call telemetry ladder key** (routing-console spec §2.1). Every
|
|
122
|
+
inference row now records which call it belongs to and its position in the
|
|
123
|
+
routing ladder, so a dashboard can reconstruct the exact sequence one `rig.run`
|
|
124
|
+
walked and compute fallback / repair rates.
|
|
125
|
+
|
|
126
|
+
### Added — telemetry ladder key
|
|
127
|
+
|
|
128
|
+
- **`RunMeta.callId`** — the `call_id` shared by every telemetry row a single
|
|
129
|
+
`run` / `runStream` / `runBundle` / `runRaw` invocation writes (primary, retry,
|
|
130
|
+
repair, grounding-search, tool-call), so a caller can correlate a `RunResult`
|
|
131
|
+
with its ladder in the console. Additive & OPTIONAL — a pre-0.4.0 caller's meta
|
|
132
|
+
omits it.
|
|
133
|
+
- Telemetry rows gain **`call_id`**, **`attempt_seq`** (1-based, monotonic across
|
|
134
|
+
every row of the call), and **`candidate_index`** (position of the dispatched
|
|
135
|
+
candidate in the call's EFFECTIVE declared list — after variant narrowing and
|
|
136
|
+
per-run filters; a repair row carries the repaired candidate's index; the raw
|
|
137
|
+
lane is seq 1 / index 0). All three are OPTIONAL on the wire and nullable in
|
|
138
|
+
storage: an older SDK OMITS them and the payload is byte-identical to before
|
|
139
|
+
R0; a reader treats null as *"recorded by an SDK older than 0.4.0."*
|
|
140
|
+
- OTLP spans gain `modelrig.call_id` / `modelrig.attempt_seq` /
|
|
141
|
+
`modelrig.candidate_index`, emitted only when present.
|
|
142
|
+
- **`CandidateIterator.index`** (read-only getter, public type) — the index of the
|
|
143
|
+
candidate the last `next()` returned (−1 before the first call). Additive for
|
|
144
|
+
callers; an external IMPLEMENTER of the interface must add the member.
|
|
145
|
+
- **`tags.rung`** on every telemetry row (R1 review, F1) — one of `primary` |
|
|
146
|
+
`retry` | `repair` | `search` | `tool_call` | `predispatch_fail`, so the routing
|
|
147
|
+
dashboard and ladder view can tell a real candidate dispatch from a tool-call
|
|
148
|
+
turn or a pre-dispatch failure without column heuristics. Additive (rides
|
|
149
|
+
`tags_json`, no schema change); a pre-0.4.0 row omits it and the rollup falls
|
|
150
|
+
back to `repaired_by` / `provider = "search"`. Public type `TelemetryRung` is
|
|
151
|
+
exported.
|
|
152
|
+
|
|
153
|
+
## [0.3.0] — 2026-08-21
|
|
154
|
+
|
|
155
|
+
The `modelrig-oracle` MCP server ships to npm alongside this release (its own
|
|
156
|
+
package, 0.1.0) — `npx modelrig-oracle` now works as the docs describe.
|
|
157
|
+
|
|
158
|
+
CE-2 raw-lane parity — three new provider knobs on `rig.runRaw` /
|
|
159
|
+
`rig.runRawStream` (and the OpenAI-compatible `/v1/chat/completions` raw lane),
|
|
160
|
+
so the Lane-B report-pipeline seam (`callProvider` → `rig.runRaw`) can swap
|
|
161
|
+
behaviour-identically. Every knob is ADDITIVE: absent ⇒ byte-identical to the
|
|
162
|
+
0.2.0 request shape.
|
|
163
|
+
|
|
164
|
+
### Added — `RawRunInput` (all additive, absent ⇒ byte-identical)
|
|
165
|
+
|
|
166
|
+
- **`grounding?: { mode: "native" }`** — native provider web grounding on the
|
|
167
|
+
raw lane (F1). Maps to the adapter's native-grounding directive (gemini →
|
|
168
|
+
the `googleSearch` tool). GEMINI-ONLY in v1: declared on any other provider
|
|
169
|
+
throws `RigFailureError` with class `invariant_violation` PRE-DISPATCH (no
|
|
170
|
+
meter, no provider call, no telemetry row). Interplay with `cache.key` needs
|
|
171
|
+
no code — the gemini `cachedContent` path excludes tools by design (the
|
|
172
|
+
`googleSearch` tool is expected to be baked into the customer's cache resource
|
|
173
|
+
at creation).
|
|
174
|
+
- **`serviceTier?: "standard" | "flex" | "priority"`** — service tier on the raw
|
|
175
|
+
lane (F2). Forwarded to the adapter's tier path; `RunMeta.requestedTier` now
|
|
176
|
+
reports the DECLARED tier (previously hardcoded `"standard"` — an honesty fix).
|
|
177
|
+
ModelRig does NOT degrade flex→standard on the raw lane; a capacity rejection
|
|
178
|
+
surfaces classified (`capacity_shed`) for the customer's own retry ladder.
|
|
179
|
+
- **`reasoning?: { level: "minimal" | "low" | "medium" | "high" }`** —
|
|
180
|
+
provider-neutral reasoning/thinking effort (F3). Gemini maps `level` to
|
|
181
|
+
`thinkingConfig.thinkingLevel` (replacing the hardcoded `"high"`). GEMINI-ONLY
|
|
182
|
+
in v1: declared on another provider throws `invariant_violation` pre-dispatch;
|
|
183
|
+
declared on a non-thinking-capable gemini model is rejected classified by the
|
|
184
|
+
adapter (never a silent drop, never an unguarded provider 400).
|
|
185
|
+
|
|
186
|
+
### Added — `AdapterRequest`
|
|
187
|
+
|
|
188
|
+
- **`reasoning?: ReasoningParams`** (+ exported `ReasoningParams` /
|
|
189
|
+
`ReasoningLevel` types) — the provider-neutral reasoning shape adapters map to
|
|
190
|
+
their native field.
|
|
191
|
+
|
|
192
|
+
### Added — HTTP gateway (`/v1/chat/completions`, raw lane only)
|
|
193
|
+
|
|
194
|
+
- Top-level OpenAI-standard `temperature` / `top_p` / `max_tokens` /
|
|
195
|
+
`service_tier` are now forwarded onto the raw lane (the open CE-6 co-item);
|
|
196
|
+
`modelrig.grounding` / `modelrig.reasoning` ride in the `modelrig` body object.
|
|
197
|
+
A malformed `grounding.mode` / `reasoning.level` is a teaching 4xx. The SLUG
|
|
198
|
+
lane still ignores all generation params (the verified route owns them).
|
|
199
|
+
|
|
200
|
+
### Added — route loader
|
|
201
|
+
|
|
202
|
+
- Load-time WARN when a route's output schema has an ARRAY root — OpenAI strict
|
|
203
|
+
structured output requires a top-level object, so an array-root schema cannot
|
|
204
|
+
use strict enforcement on OpenAI candidates (the A5 co-item). The route still
|
|
205
|
+
loads and serves as declared.
|
|
206
|
+
|
|
207
|
+
### Confirmed (already true on 0.2.0, now pinned by regression tests)
|
|
208
|
+
|
|
209
|
+
- **F5** — an invalid/evicted customer `cache.key` on the raw lane surfaces as a
|
|
210
|
+
thrown `RigFailureError` with `.failure.class === "cache_invalid"`; the raw
|
|
211
|
+
lane is single-dispatch, so a silent un-cached retry is structurally
|
|
212
|
+
impossible.
|
|
213
|
+
- **F6** — success `RunMeta` carries `servedTier` / `tokensCached` / `latencyMs`
|
|
214
|
+
(and provider/model/cost); a per-attempt failure's class + provider/model
|
|
215
|
+
travel on the thrown error's `.failure`.
|
|
216
|
+
|
|
13
217
|
## [0.2.0] — unreleased (staged for the R-A ceremony)
|
|
14
218
|
|
|
15
219
|
- Ships the probed capability registry and leaderboard (`registry/registry.json`, `registry/leaderboard.json`) so a clean install routes on the probed profile instead of the static fallback (R-1 F2 ruling). The `modelrig-oracle` MCP server remains unreleased and is flagged as such in the docs.
|
package/README.md
CHANGED
|
@@ -99,15 +99,75 @@ over the route's `cache: auto` stamp, and a non-matching fallback dispatches
|
|
|
99
99
|
without it. ModelRig carries the handle and prices the hits — it never creates,
|
|
100
100
|
refreshes, or deletes the resource, so a long job needs your own TTL heartbeat
|
|
101
101
|
(see the [caching lifecycle](https://modelrig.dev/caching-lifecycle.html) doc).
|
|
102
|
-
The Lane-B `rig.runRaw({ provider, model, …, cache: { key } })` seam takes
|
|
103
|
-
same field.
|
|
102
|
+
The Lane-B `rig.runRaw({ provider, model, apiKey, …, cache: { key } })` seam takes
|
|
103
|
+
the same field.
|
|
104
|
+
|
|
105
|
+
`rig.runRaw` also accepts
|
|
106
|
+
provider knobs, each additive — absent ⇒ byte-identical dispatch:
|
|
107
|
+
`grounding: { mode: "native" }` (native provider web grounding —
|
|
108
|
+
gemini; grok fail-closed until CE-9b), `serviceTier: "standard" | "flex" | "priority"`,
|
|
109
|
+
`reasoning: { level: "minimal" | "low" | "medium" | "high" }` (reasoning effort¹),
|
|
110
|
+
and `responseFormat: "json_object"` (syntactic-JSON forcing¹ — MIME-shaping, NOT
|
|
111
|
+
schema enforcement, so `meta.validated` stays `false`). A declared directive a
|
|
112
|
+
provider cannot honor FAILS CLOSED — a thrown `RigFailureError` with class
|
|
113
|
+
`invariant_violation`, pre-dispatch (no meter, no provider call) — never a silent
|
|
114
|
+
drop. **Which provider honors which knob is one table** — the runtime guard and
|
|
115
|
+
the published
|
|
116
|
+
[provider × knob matrix](https://modelrig.dev/route-bundles.html#raw-lane-provider-knob-support-rigrunraw)
|
|
117
|
+
are generated from the same `RAW_KNOB_SUPPORT`; ask it in code with
|
|
118
|
+
`rawKnobSupport(provider)` (and `GEMINI_THINKING_CAPABLE_MODELS` is exported so
|
|
119
|
+
you don't duplicate the thinking-model set). A grounded step that also passes a
|
|
120
|
+
`cache.key` keeps its cached-token ratio: bake the `googleSearch` tool into the
|
|
121
|
+
cache resource at creation (ModelRig sends `cachedContent` without tools, which
|
|
122
|
+
the provider requires).
|
|
123
|
+
|
|
124
|
+
_¹ Multi-provider `reasoning` and `responseFormat` ship in
|
|
125
|
+
0.4.0; on the published package `reasoning`/`grounding` are gemini-only._
|
|
126
|
+
|
|
127
|
+
**runRaw — a BYOK passthrough (Lane B).** When you don't need a route — no
|
|
128
|
+
schema, no validation, no retries — call a `provider/model` directly with your
|
|
129
|
+
own provider key:
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
const rig = createRig(loadConfigFromEnv());
|
|
133
|
+
const result = await rig.runRaw({
|
|
134
|
+
provider: "gemini",
|
|
135
|
+
model: "gemini-3.1-pro",
|
|
136
|
+
apiKey: process.env.GEMINI_API_KEY!, // runRaw is BYOK — pass your provider key
|
|
137
|
+
systemPrompt: "", // one combined prompt? put it ALL in userPrompt, leave systemPrompt empty
|
|
138
|
+
userPrompt: buildPrompt(input),
|
|
139
|
+
});
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
`runRaw` is BYOK — pass your provider key; ModelRig holds it for the one call and
|
|
143
|
+
never stores it. It records one metered `lane=raw` telemetry row at the
|
|
144
|
+
provider's list price (zero ModelRig margin) and throws a typed `RigFailureError`
|
|
145
|
+
on failure, exactly like `rig.run`.
|
|
146
|
+
|
|
147
|
+
**runRaw-only construction (`routesDir: null`) — 0.4.0+.** A
|
|
148
|
+
Lane-B deployment that ONLY calls `runRaw`/`runRawStream` has no routes. Build it
|
|
149
|
+
with `routesDir: null` and `createRig` skips route loading, the `rig.yaml`
|
|
150
|
+
manifest, and the serveability gate entirely — so a stray route file it never
|
|
151
|
+
calls (or a route whose provider key is absent in this deployment) can no longer
|
|
152
|
+
down construction:
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
const rig = createRig({ ...loadConfigFromEnv(), routesDir: null });
|
|
156
|
+
await rig.runRaw({ provider, model, apiKey, systemPrompt, userPrompt });
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
`loadConfigFromEnv()` always yields a string `routesDir`, so the opt-out is a
|
|
160
|
+
deliberate code-level choice — override it as above; there is no env var that
|
|
161
|
+
disables routes, by design. On such a rig, `rig.run` and every other
|
|
162
|
+
route-dependent surface (`runStream`, `runBundle`, bake-offs, watch, replay,
|
|
163
|
+
`verifySwap`) throws a terminal `invariant_violation` naming the fix.
|
|
104
164
|
|
|
105
165
|
Every attempt is recorded in a local SQLite file (`.modelrig/telemetry.db`)
|
|
106
166
|
tagged with your `tags`. Failures are typed —
|
|
107
167
|
`RigFailureError.failure.class` is one of `content_invalid`, `capacity_shed`,
|
|
108
|
-
`network`, `refusal`, `cache_invalid`, `timeout`, `budget_exhausted`,
|
|
168
|
+
`network`, `refusal`, `cache_invalid`, `timeout`, `config_auth`, `budget_exhausted`,
|
|
109
169
|
`invariant_violation` — with a separate retry budget per class, so a flaky
|
|
110
|
-
network never spends your content-validation retries.
|
|
170
|
+
network never spends your content-validation retries. What each class means, whether it retries, and how it backs off is on [Routing & reliability](https://modelrig.dev/routing-reliability.html#5-failure-classes).
|
|
111
171
|
|
|
112
172
|
## CLI
|
|
113
173
|
|
|
@@ -143,6 +203,10 @@ on the quickstart:
|
|
|
143
203
|
stable enough to build on, not frozen.
|
|
144
204
|
- **`modelrig serve` needs the `modelrig-server` package** — it is not bundled
|
|
145
205
|
here.
|
|
206
|
+
- **What the ladder does and does not do.** Fall-through is structural and
|
|
207
|
+
infrastructural, never a quality judgment; the full boundary (quality gate,
|
|
208
|
+
raw-lane structure, latency ordering…) is generated and tripwire-tested on
|
|
209
|
+
[Routing & reliability](https://modelrig.dev/routing-reliability.html#10-not-yet-implemented-the-boundary).
|
|
146
210
|
|
|
147
211
|
## License
|
|
148
212
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deepseek.d.ts","sourceRoot":"","sources":["../../src/adapters/deepseek.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,EAIV,cAAc,EACd,eAAe,EAChB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,KAAK,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAMhE,OAAO,KAAK,EAAuB,cAAc,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAMhG,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAKD,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAMhF;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,iBAAiB,CAiB1E;AAED,UAAU,WAAW;IACnB,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAC;IACjC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,SAAS,WAAW,EAAE,CAAC;IAC1C,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC;IACtB,QAAQ,CAAC,cAAc,EAAE;QAAE,QAAQ,CAAC,aAAa,EAAE,IAAI,CAAA;KAAE,CAAC;IAC1D,8EAA8E;IAC9E,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,eAAe,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAA;KAAE,CAAC;IAC5D,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,cAAc,EAAE,CAAC;IAC3C,QAAQ,CAAC,WAAW,CAAC,EAAE,oBAAoB,CAAC;CAC7C;AAOD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,YAAY,GAAG,oBAAoB,
|
|
1
|
+
{"version":3,"file":"deepseek.d.ts","sourceRoot":"","sources":["../../src/adapters/deepseek.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,EAIV,cAAc,EACd,eAAe,EAChB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,KAAK,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAMhE,OAAO,KAAK,EAAuB,cAAc,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAMhG,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAKD,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAMhF;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,iBAAiB,CAiB1E;AAED,UAAU,WAAW;IACnB,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAC;IACjC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,SAAS,WAAW,EAAE,CAAC;IAC1C,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC;IACtB,QAAQ,CAAC,cAAc,EAAE;QAAE,QAAQ,CAAC,aAAa,EAAE,IAAI,CAAA;KAAE,CAAC;IAC1D,8EAA8E;IAC9E,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,eAAe,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAA;KAAE,CAAC;IAC5D,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,cAAc,EAAE,CAAC;IAC3C,QAAQ,CAAC,WAAW,CAAC,EAAE,oBAAoB,CAAC;CAC7C;AAOD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,YAAY,GAAG,oBAAoB,CAkC1F;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,qBAAqB,GAAG,eAAe,CA8JpF"}
|
|
@@ -62,6 +62,13 @@ function classifyDeepSeekFailure(message) {
|
|
|
62
62
|
const JSON_GUARD = "Respond with a single valid JSON object.";
|
|
63
63
|
function buildDeepSeekParams(model, req) {
|
|
64
64
|
const wantJson = req.outputSchema !== null;
|
|
65
|
+
// CE-9 R4: the raw lane's `responseFormat: "json_object"` also drives DeepSeek's
|
|
66
|
+
// json_object mode (the flag previously fired ONLY on the routed outputSchema
|
|
67
|
+
// path, which is always null on the raw lane). Absent both ⇒ no key
|
|
68
|
+
// (byte-identical). The JSON_GUARD below stays keyed on the ROUTED path only:
|
|
69
|
+
// on the raw lane the word-"JSON" wrinkle is the caller's prompt responsibility
|
|
70
|
+
// (spec R4), not silently intercepted here.
|
|
71
|
+
const jsonObject = wantJson || req.responseFormat === "json_object";
|
|
65
72
|
let systemPrompt = req.systemPrompt;
|
|
66
73
|
if (wantJson && !req.systemPrompt.includes("JSON") && !req.userPrompt.includes("JSON")) {
|
|
67
74
|
systemPrompt = systemPrompt === "" ? JSON_GUARD : `${systemPrompt}\n\n${JSON_GUARD}`;
|
|
@@ -77,7 +84,7 @@ function buildDeepSeekParams(model, req) {
|
|
|
77
84
|
stream: true,
|
|
78
85
|
stream_options: { include_usage: true },
|
|
79
86
|
...(0, sampling_1.openAISamplingFields)(req),
|
|
80
|
-
...(
|
|
87
|
+
...(jsonObject ? { response_format: { type: "json_object" } } : {}),
|
|
81
88
|
...(req.tools !== undefined && req.tools.length > 0
|
|
82
89
|
? {
|
|
83
90
|
tools: (0, tool_mapping_1.toOpenAITools)(req.tools),
|
|
@@ -18,6 +18,12 @@ import type { FailureClass } from "../types/failures";
|
|
|
18
18
|
export interface GeminiAdapterConfig {
|
|
19
19
|
readonly apiKey: string;
|
|
20
20
|
}
|
|
21
|
+
/** Models that accept thinkingConfig — passing it to 2.x models 400s.
|
|
22
|
+
* Ported from the production THINKING_CAPABLE_MODELS set. EXPORTED (CE-9 R6) so
|
|
23
|
+
* a multi-provider customer's dispatcher reads THIS set instead of duplicating
|
|
24
|
+
* it (the §3.1 drift complaint) — the same fact the raw-lane guard uses to keep
|
|
25
|
+
* gemini reasoning model-gated. */
|
|
26
|
+
export declare const GEMINI_THINKING_CAPABLE_MODELS: ReadonlySet<string>;
|
|
21
27
|
export declare function geminiSupports(feature: CapabilityFlag, model: string): boolean;
|
|
22
28
|
export interface ClassifiedFailure {
|
|
23
29
|
readonly cls: FailureClass;
|
|
@@ -33,6 +39,16 @@ export declare function classifyGeminiFailure(message: string): ClassifiedFailur
|
|
|
33
39
|
/** The candidate-independent part of an AdapterRequest (also what the pure
|
|
34
40
|
* shaping helpers take, so unit tests never need a branded CandidateRef). */
|
|
35
41
|
export type ShapingInput = Omit<AdapterRequest, "candidate">;
|
|
42
|
+
/**
|
|
43
|
+
* CE-2 F3 fail-closed guard: `reasoning` declared on a Gemini model that is NOT
|
|
44
|
+
* thinking-capable would 400 at the provider (thinkingConfig on a 2.x model is
|
|
45
|
+
* rejected). Pre-empt with a classified TERMINAL failure so the declaration is
|
|
46
|
+
* never silently dropped and never turns into an unguarded provider 400 — the
|
|
47
|
+
* same fail-closed discipline as the raw-lane provider guard (spec §3 F1/F3).
|
|
48
|
+
* Returns the failure class + fixHint, or null when the request is fine (no
|
|
49
|
+
* reasoning declared, or a thinking-capable model). Pure — unit-tested directly.
|
|
50
|
+
*/
|
|
51
|
+
export declare function geminiReasoningUnsupported(model: string, req: ShapingInput): ClassifiedFailure | null;
|
|
36
52
|
export interface GeminiShapedRequest {
|
|
37
53
|
readonly model: string;
|
|
38
54
|
readonly contents: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gemini.d.ts","sourceRoot":"","sources":["../../src/adapters/gemini.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,EACV,cAAc,EAGd,cAAc,EACd,eAAe,EAEhB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,YAAY,EAAc,MAAM,mBAAmB,CAAC;AAKlE,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;
|
|
1
|
+
{"version":3,"file":"gemini.d.ts","sourceRoot":"","sources":["../../src/adapters/gemini.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,EACV,cAAc,EAGd,cAAc,EACd,eAAe,EAEhB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,YAAY,EAAc,MAAM,mBAAmB,CAAC;AAKlE,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;;;mCAImC;AACnC,eAAO,MAAM,8BAA8B,EAAE,WAAW,CAAC,MAAM,CAI7D,CAAC;AA0BH,wBAAgB,cAAc,CAAC,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAG9E;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,GAAG,EAAE,YAAY,CAAC;IAC3B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,iBAAiB,CAyCxE;AAED;6EAC6E;AAC7E,MAAM,MAAM,YAAY,GAAG,IAAI,CAAC,cAAc,EAAE,WAAW,CAAC,CAAC;AAE7D;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,YAAY,GAAG,iBAAiB,GAAG,IAAI,CAQrG;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC1C;AAED,iEAAiE;AACjE,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,YAAY,GAAG,mBAAmB,CAqDxF;AA0BD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,mBAAmB,GAAG,eAAe,CA+JhF"}
|
package/dist/adapters/gemini.js
CHANGED
|
@@ -15,16 +15,21 @@
|
|
|
15
15
|
* gemini transformation logic is consulted during the port.
|
|
16
16
|
*/
|
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.GEMINI_THINKING_CAPABLE_MODELS = void 0;
|
|
18
19
|
exports.geminiSupports = geminiSupports;
|
|
19
20
|
exports.classifyGeminiFailure = classifyGeminiFailure;
|
|
21
|
+
exports.geminiReasoningUnsupported = geminiReasoningUnsupported;
|
|
20
22
|
exports.buildGeminiRequest = buildGeminiRequest;
|
|
21
23
|
exports.createGeminiAdapter = createGeminiAdapter;
|
|
22
24
|
const genai_1 = require("@google/genai");
|
|
23
25
|
const tool_mapping_1 = require("./tool-mapping");
|
|
24
26
|
const sampling_1 = require("./sampling");
|
|
25
27
|
/** Models that accept thinkingConfig — passing it to 2.x models 400s.
|
|
26
|
-
* Ported from the production THINKING_CAPABLE_MODELS set.
|
|
27
|
-
|
|
28
|
+
* Ported from the production THINKING_CAPABLE_MODELS set. EXPORTED (CE-9 R6) so
|
|
29
|
+
* a multi-provider customer's dispatcher reads THIS set instead of duplicating
|
|
30
|
+
* it (the §3.1 drift complaint) — the same fact the raw-lane guard uses to keep
|
|
31
|
+
* gemini reasoning model-gated. */
|
|
32
|
+
exports.GEMINI_THINKING_CAPABLE_MODELS = new Set([
|
|
28
33
|
"gemini-3.1-pro-preview",
|
|
29
34
|
"gemini-3.0-pro-preview",
|
|
30
35
|
"gemini-3.1-flash-preview",
|
|
@@ -99,23 +104,52 @@ function classifyGeminiFailure(message) {
|
|
|
99
104
|
}
|
|
100
105
|
return { cls: "network" };
|
|
101
106
|
}
|
|
107
|
+
/**
|
|
108
|
+
* CE-2 F3 fail-closed guard: `reasoning` declared on a Gemini model that is NOT
|
|
109
|
+
* thinking-capable would 400 at the provider (thinkingConfig on a 2.x model is
|
|
110
|
+
* rejected). Pre-empt with a classified TERMINAL failure so the declaration is
|
|
111
|
+
* never silently dropped and never turns into an unguarded provider 400 — the
|
|
112
|
+
* same fail-closed discipline as the raw-lane provider guard (spec §3 F1/F3).
|
|
113
|
+
* Returns the failure class + fixHint, or null when the request is fine (no
|
|
114
|
+
* reasoning declared, or a thinking-capable model). Pure — unit-tested directly.
|
|
115
|
+
*/
|
|
116
|
+
function geminiReasoningUnsupported(model, req) {
|
|
117
|
+
if (req.reasoning !== undefined && !exports.GEMINI_THINKING_CAPABLE_MODELS.has(model)) {
|
|
118
|
+
return {
|
|
119
|
+
cls: "invariant_violation",
|
|
120
|
+
fixHint: `reasoning control requires a thinking-capable Gemini model; "${model}" is not one — remove reasoning or choose a thinking-capable model`,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
102
125
|
/** Pure request shaping — everything except the abort signal. */
|
|
103
126
|
function buildGeminiRequest(model, req) {
|
|
104
127
|
const usingCache = req.cache?.key !== undefined && req.cache.key !== "";
|
|
105
128
|
// CE-6: a declared sampling field OVERRIDES the ported constant; absent, the
|
|
106
129
|
// constant stands (byte-identical to pre-CE-6). topK stays internal (gemini-only,
|
|
107
130
|
// not on the customer surface — spec §1 non-goals).
|
|
131
|
+
// CE-2 F3: a declared reasoning level replaces the hardcoded `"high"` for the
|
|
132
|
+
// thinking-capable models; absent, `"high"` stands (byte-identical to
|
|
133
|
+
// pre-CE-2). A declared level on a NON-capable model is rejected fail-closed in
|
|
134
|
+
// call() (geminiReasoningUnsupported) — it never reaches this shaping.
|
|
135
|
+
const thinkingLevel = req.reasoning?.level ?? "high";
|
|
108
136
|
const config = {
|
|
109
137
|
temperature: req.sampling?.temperature ?? GEMINI_TEMPERATURE,
|
|
110
138
|
maxOutputTokens: (0, sampling_1.effectiveMaxOutputTokens)(req, DEFAULT_MAX_OUTPUT_TOKENS),
|
|
111
139
|
topP: req.sampling?.topP ?? TOP_P,
|
|
112
140
|
topK: TOP_K,
|
|
113
|
-
...(
|
|
141
|
+
...(exports.GEMINI_THINKING_CAPABLE_MODELS.has(model) ? { thinkingConfig: { thinkingLevel } } : {}),
|
|
114
142
|
};
|
|
115
143
|
if (req.outputSchema !== null) {
|
|
116
144
|
config.responseMimeType = "application/json";
|
|
117
145
|
config.responseJsonSchema = req.outputSchema;
|
|
118
146
|
}
|
|
147
|
+
else if (req.responseFormat === "json_object") {
|
|
148
|
+
// CE-9 R4: mime-shaping ONLY — force a JSON mime type WITHOUT a schema. This
|
|
149
|
+
// is the raw lane, so F4 stands: no responseJsonSchema, no validation, no
|
|
150
|
+
// repair, `validated` stays false. Absent ⇒ no key (byte-identical).
|
|
151
|
+
config.responseMimeType = "application/json";
|
|
152
|
+
}
|
|
119
153
|
// cachedContent excludes systemInstruction and tools — the API rejects
|
|
120
154
|
// requests setting both (they are baked into the cache at creation time,
|
|
121
155
|
// including the googleSearch tool for cached grounded steps).
|
|
@@ -179,6 +213,13 @@ function createGeminiAdapter(config) {
|
|
|
179
213
|
},
|
|
180
214
|
...(usage !== undefined ? { usage } : {}),
|
|
181
215
|
});
|
|
216
|
+
// CE-2 F3: reject reasoning on a non-thinking model BEFORE any dispatch —
|
|
217
|
+
// classified, terminal, never a silent drop (spec §3 F3).
|
|
218
|
+
const reasoningUnsupported = geminiReasoningUnsupported(model, req);
|
|
219
|
+
if (reasoningUnsupported !== null) {
|
|
220
|
+
clearTimeout(timeoutId);
|
|
221
|
+
return fail(reasoningUnsupported.cls, `reasoning control declared on the non-thinking Gemini model "${model}"`, reasoningUnsupported.fixHint);
|
|
222
|
+
}
|
|
182
223
|
try {
|
|
183
224
|
const shaped = buildGeminiRequest(model, req);
|
|
184
225
|
const dispatchedAt = Date.now();
|
package/dist/adapters/grok.d.ts
CHANGED
|
@@ -36,7 +36,14 @@ export interface GrokShapedParams {
|
|
|
36
36
|
/** Prompt-cache routing hint (WS-C) — the stable-prefix fingerprint the run
|
|
37
37
|
* loop stamps; xAI keeps a warm cache keyed to it (writes free today). */
|
|
38
38
|
readonly prompt_cache_key?: string;
|
|
39
|
+
/** CE-9 R1 — xAI accepts `reasoning_effort: "low" | "high"` ONLY, so the
|
|
40
|
+
* neutral four-level `level` is coarsened by `coarsenGrokReasoningEffort`
|
|
41
|
+
* (a DISCLOSED, lossy mapping: `minimal,low → "low"`; `medium,high → "high"`).
|
|
42
|
+
* Present only when the caller declared `reasoning`. */
|
|
43
|
+
readonly reasoning_effort?: "low" | "high";
|
|
39
44
|
readonly response_format?: {
|
|
45
|
+
readonly type: "json_object";
|
|
46
|
+
} | {
|
|
40
47
|
readonly type: "json_schema";
|
|
41
48
|
readonly json_schema: {
|
|
42
49
|
readonly name: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grok.d.ts","sourceRoot":"","sources":["../../src/adapters/grok.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EAIV,cAAc,EACd,eAAe,EAChB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,KAAK,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAMhE,OAAO,KAAK,EAAuB,cAAc,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"grok.d.ts","sourceRoot":"","sources":["../../src/adapters/grok.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EAIV,cAAc,EACd,eAAe,EAChB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,KAAK,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAMhE,OAAO,KAAK,EAAuB,cAAc,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAOhG,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAKD,wBAAgB,YAAY,CAAC,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAc7E;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,iBAAiB,CA+BtE;AAED,UAAU,WAAW;IACnB,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAC;IACjC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,SAAS,WAAW,EAAE,CAAC;IAC1C,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC;IACtB,QAAQ,CAAC,cAAc,EAAE;QAAE,QAAQ,CAAC,aAAa,EAAE,IAAI,CAAA;KAAE,CAAC;IAC1D,8EAA8E;IAC9E,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB;8EAC0E;IAC1E,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC;;;4DAGwD;IACxD,QAAQ,CAAC,gBAAgB,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;IAC3C,QAAQ,CAAC,eAAe,CAAC,EACrB;QAAE,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAA;KAAE,GAChC;QACE,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;QAC7B,QAAQ,CAAC,WAAW,EAAE;YAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAA;SAAE,CAAC;KACjG,CAAC;IACN,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,cAAc,EAAE,CAAC;IAC3C,QAAQ,CAAC,WAAW,CAAC,EAAE,oBAAoB,CAAC;CAC7C;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,YAAY,GAAG,gBAAgB,CAmDlF;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,iBAAiB,GAAG,eAAe,CAgK5E"}
|
package/dist/adapters/grok.js
CHANGED
|
@@ -23,6 +23,7 @@ const openai_1 = __importDefault(require("openai"));
|
|
|
23
23
|
const tool_mapping_1 = require("./tool-mapping");
|
|
24
24
|
const openai_stream_1 = require("./openai-stream");
|
|
25
25
|
const sampling_1 = require("./sampling");
|
|
26
|
+
const raw_support_1 = require("../run/raw-support");
|
|
26
27
|
const GROK_BASE_URL = "https://api.x.ai/v1";
|
|
27
28
|
const DEFAULT_MAX_TOKENS = 32000;
|
|
28
29
|
function grokSupports(feature, _model) {
|
|
@@ -65,6 +66,14 @@ function classifyGrokFailure(message) {
|
|
|
65
66
|
fixHint: "the candidate model was not found — fix the model id in the route's candidate list",
|
|
66
67
|
};
|
|
67
68
|
}
|
|
69
|
+
// CE-9 R1: a non-reasoning grok variant rejects `reasoning_effort` — teach the
|
|
70
|
+
// fix (pick a reasoning variant) rather than surface a cryptic 400.
|
|
71
|
+
if (/reasoning_effort/.test(msg)) {
|
|
72
|
+
return {
|
|
73
|
+
cls: "network",
|
|
74
|
+
fixHint: "this Grok model does not accept reasoning_effort — remove reasoning or pick a Grok reasoning variant",
|
|
75
|
+
};
|
|
76
|
+
}
|
|
68
77
|
return { cls: "network" };
|
|
69
78
|
}
|
|
70
79
|
function buildGrokParams(model, req) {
|
|
@@ -84,6 +93,17 @@ function buildGrokParams(model, req) {
|
|
|
84
93
|
...(req.cache?.key !== undefined && req.cache.key !== ""
|
|
85
94
|
? { prompt_cache_key: req.cache.key }
|
|
86
95
|
: {}),
|
|
96
|
+
// CE-9 R1: coarsen the neutral level to xAI's low|high (disclosed mapping).
|
|
97
|
+
// Absent ⇒ no key. A non-reasoning grok model's rejection is taught below.
|
|
98
|
+
...(req.reasoning !== undefined
|
|
99
|
+
? { reasoning_effort: (0, raw_support_1.coarsenGrokReasoningEffort)(req.reasoning.level) }
|
|
100
|
+
: {}),
|
|
101
|
+
// CE-9b: grounding is NOT mapped here. xAI retired Live Search
|
|
102
|
+
// (`search_parameters` → HTTP 410 on the CE-9 live gate); the replacement
|
|
103
|
+
// `web_search` tool is Responses-API-only. The raw-lane guard fails grok
|
|
104
|
+
// grounding closed (matrix: supported=false) until CE-9b adds that path.
|
|
105
|
+
// response_format: a native strict json_schema (routed lane) wins; else the
|
|
106
|
+
// RAW lane's mime-shaping json_object (CE-9 R4). Absent both ⇒ no key.
|
|
87
107
|
...(req.outputSchema !== null
|
|
88
108
|
? {
|
|
89
109
|
response_format: {
|
|
@@ -95,7 +115,9 @@ function buildGrokParams(model, req) {
|
|
|
95
115
|
},
|
|
96
116
|
},
|
|
97
117
|
}
|
|
98
|
-
:
|
|
118
|
+
: req.responseFormat === "json_object"
|
|
119
|
+
? { response_format: { type: "json_object" } }
|
|
120
|
+
: {}),
|
|
99
121
|
...(req.tools !== undefined && req.tools.length > 0
|
|
100
122
|
? {
|
|
101
123
|
tools: (0, tool_mapping_1.toOpenAITools)(req.tools),
|
|
@@ -49,6 +49,13 @@ export interface OpenAICompatShapedParams {
|
|
|
49
49
|
/** CE-6 declared sampling — present only when the route/raw asks for them. */
|
|
50
50
|
readonly temperature?: number;
|
|
51
51
|
readonly top_p?: number;
|
|
52
|
+
/** CE-9 R1 — reasoning effort forwarded verbatim (1:1). Present only when the
|
|
53
|
+
* caller declared `reasoning`; a host/model that does not accept it rejects at
|
|
54
|
+
* the provider and `classifyCompatFailure` teaches (no per-model allowlist). */
|
|
55
|
+
readonly reasoning_effort?: "minimal" | "low" | "medium" | "high";
|
|
56
|
+
/** CE-9 R3 — the DeepInfra prompt_cache_key gap: `cache.key` → the routing
|
|
57
|
+
* hint. Present only when the caller supplies `cache.key`. */
|
|
58
|
+
readonly prompt_cache_key?: string;
|
|
52
59
|
readonly response_format?: {
|
|
53
60
|
readonly type: "json_object";
|
|
54
61
|
} | {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openai-compat.d.ts","sourceRoot":"","sources":["../../src/adapters/openai-compat.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,KAAK,EAIV,cAAc,EACd,eAAe,EACf,UAAU,EACX,MAAM,mBAAmB,CAAC;AAE3B,OAAO,KAAK,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAMhE,OAAO,KAAK,EAAuB,cAAc,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAQhG;;8CAE8C;AAC9C,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;CACnD;AAED;;;0EAG0E;AAC1E,eAAO,MAAM,mBAAmB,EAAE,QAAQ,CAAC,MAAM,CAAC,WAAW,GAAG,WAAW,EAAE,gBAAgB,CAAC,CAG7F,CAAC;AAEF,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,iBAAiB,
|
|
1
|
+
{"version":3,"file":"openai-compat.d.ts","sourceRoot":"","sources":["../../src/adapters/openai-compat.ts"],"names":[],"mappings":"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"}
|
|
@@ -66,6 +66,15 @@ function classifyCompatFailure(message, host) {
|
|
|
66
66
|
fixHint: "the candidate model was not found — fix the model id in the route's candidate list",
|
|
67
67
|
};
|
|
68
68
|
}
|
|
69
|
+
// CE-9 R1: a model that does not accept `reasoning_effort` rejects the request
|
|
70
|
+
// — teach it rather than surfacing a cryptic generic 400 (the reason we forward
|
|
71
|
+
// verbatim instead of keeping a per-model allowlist).
|
|
72
|
+
if (/reasoning_effort/.test(msg)) {
|
|
73
|
+
return {
|
|
74
|
+
cls: "network",
|
|
75
|
+
fixHint: `this ${host} model does not accept reasoning_effort — remove reasoning or pick a reasoning model`,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
69
78
|
return { cls: "network" };
|
|
70
79
|
}
|
|
71
80
|
/** json_object mode 400s on several compat backends when the literal word
|
|
@@ -93,6 +102,18 @@ function buildOpenAICompatParams(model, req, profileFlags) {
|
|
|
93
102
|
stream: true,
|
|
94
103
|
stream_options: { include_usage: true },
|
|
95
104
|
...(0, sampling_1.openAISamplingFields)(req),
|
|
105
|
+
// CE-9 R1: forward reasoning effort verbatim (1:1). Absent ⇒ no key.
|
|
106
|
+
...(req.reasoning !== undefined ? { reasoning_effort: req.reasoning.level } : {}),
|
|
107
|
+
// CE-9 R3: the DeepInfra prompt_cache_key gap — map cache.key → the routing
|
|
108
|
+
// hint (absent ⇒ no key, byte-identical). Additive; unrecognized on a host
|
|
109
|
+
// that doesn't cache, the hint is simply ignored.
|
|
110
|
+
...(req.cache?.key !== undefined && req.cache.key !== ""
|
|
111
|
+
? { prompt_cache_key: req.cache.key }
|
|
112
|
+
: {}),
|
|
113
|
+
// response_format: a routed strict json_schema (structured_native profile)
|
|
114
|
+
// wins; else routed json_object; else the RAW lane's mime-shaping json_object
|
|
115
|
+
// (CE-9 R4). The raw path carries NO JSON_GUARD injection — the word-"JSON"
|
|
116
|
+
// wrinkle is the caller's prompt responsibility on the raw lane.
|
|
96
117
|
...(wantJson
|
|
97
118
|
? strict
|
|
98
119
|
? {
|
|
@@ -102,7 +123,9 @@ function buildOpenAICompatParams(model, req, profileFlags) {
|
|
|
102
123
|
},
|
|
103
124
|
}
|
|
104
125
|
: { response_format: { type: "json_object" } }
|
|
105
|
-
:
|
|
126
|
+
: req.responseFormat === "json_object"
|
|
127
|
+
? { response_format: { type: "json_object" } }
|
|
128
|
+
: {}),
|
|
106
129
|
...(req.tools !== undefined && req.tools.length > 0
|
|
107
130
|
? {
|
|
108
131
|
tools: (0, tool_mapping_1.toOpenAITools)(req.tools),
|
|
@@ -38,7 +38,14 @@ export interface OpenAIShapedParams {
|
|
|
38
38
|
readonly service_tier?: "flex" | "priority";
|
|
39
39
|
readonly prompt_cache_key?: string;
|
|
40
40
|
readonly prompt_cache_retention?: "24h";
|
|
41
|
+
/** CE-9 R1 — reasoning effort forwarded verbatim (1:1 from the neutral
|
|
42
|
+
* `level`). Present only when the caller declared `reasoning`. A model that
|
|
43
|
+
* does not accept it rejects at the provider; `classifyOpenAIFailure` turns
|
|
44
|
+
* that 400 into a teaching failure (no per-model allowlist). */
|
|
45
|
+
readonly reasoning_effort?: "minimal" | "low" | "medium" | "high";
|
|
41
46
|
readonly response_format?: {
|
|
47
|
+
readonly type: "json_object";
|
|
48
|
+
} | {
|
|
42
49
|
readonly type: "json_schema";
|
|
43
50
|
readonly json_schema: {
|
|
44
51
|
readonly name: string;
|