modelrig 0.3.0 → 0.5.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 +269 -0
- package/README.md +79 -14
- package/dist/adapters/deepseek.d.ts.map +1 -1
- package/dist/adapters/deepseek.js +8 -1
- package/dist/adapters/gemini.d.ts +45 -0
- package/dist/adapters/gemini.d.ts.map +1 -1
- package/dist/adapters/gemini.js +67 -6
- 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/artifacts/artifact.d.ts +3 -2
- package/dist/artifacts/artifact.d.ts.map +1 -1
- package/dist/artifacts/artifact.js +11 -4
- package/dist/artifacts/run-context.d.ts +21 -2
- package/dist/artifacts/run-context.d.ts.map +1 -1
- package/dist/artifacts/run-context.js +46 -1
- package/dist/bakeoff/replay.d.ts.map +1 -1
- package/dist/bakeoff/replay.js +17 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +26 -5
- package/dist/config.d.ts +7 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/index.d.ts +21 -15
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +39 -26
- 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/registry/select.d.ts +59 -0
- package/dist/registry/select.d.ts.map +1 -1
- package/dist/registry/select.js +66 -0
- package/dist/routes/loader-warnings.d.ts +28 -0
- package/dist/routes/loader-warnings.d.ts.map +1 -0
- package/dist/routes/loader-warnings.js +56 -0
- package/dist/routes/loader.d.ts +1 -11
- package/dist/routes/loader.d.ts.map +1 -1
- package/dist/routes/loader.js +44 -26
- 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-defaults.d.ts +52 -0
- package/dist/run/raw-defaults.d.ts.map +1 -0
- package/dist/run/raw-defaults.js +123 -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 +53 -11
- package/dist/run/raw.d.ts.map +1 -1
- package/dist/run/raw.js +157 -31
- 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 +21 -1
- package/dist/run/resolve.d.ts.map +1 -1
- package/dist/run/resolve.js +29 -6
- 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 +7 -1
- package/dist/run/run.d.ts.map +1 -1
- package/dist/run/run.js +38 -55
- package/dist/run/variant.d.ts +43 -0
- package/dist/run/variant.d.ts.map +1 -0
- package/dist/run/variant.js +86 -0
- package/dist/savings/emit.d.ts +33 -0
- package/dist/savings/emit.d.ts.map +1 -1
- package/dist/savings/emit.js +75 -3
- 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 +13 -0
- package/dist/types/provider.d.ts.map +1 -1
- package/dist/types/route.d.ts +37 -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/dist/watch/evaluate.d.ts +27 -1
- package/dist/watch/evaluate.d.ts.map +1 -1
- package/dist/watch/evaluate.js +13 -0
- package/dist/watch/proposals.d.ts +28 -0
- package/dist/watch/proposals.d.ts.map +1 -1
- package/dist/watch/proposals.js +51 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,275 @@ published package diverge.
|
|
|
10
10
|
This project adheres to [Semantic Versioning](https://semver.org/). Dates are
|
|
11
11
|
UTC.
|
|
12
12
|
|
|
13
|
+
## [0.5.0] — 2026-08-22
|
|
14
|
+
|
|
15
|
+
Released with the docs/registry mirror in one R-A ceremony. Headline for router
|
|
16
|
+
codebases: `rig.runRaw` inside a run context now records a step (the `/runs`
|
|
17
|
+
tree fills in), raw-lane timeouts are tier-aware and teach, the `trial:`
|
|
18
|
+
candidate flag + console picker ship (deploy the server before any YAML uses
|
|
19
|
+
`trial:`), and the console rollups show cost and quality together by route or
|
|
20
|
+
tag. `modelrig-oracle` 0.2.0 ships alongside (`propose_candidates`).
|
|
21
|
+
|
|
22
|
+
Raw-lane defaults (#245) — the raw lane teaches its own timeouts. The `timeoutMs`
|
|
23
|
+
default becomes tier-aware, a `timeout` failure carries a teaching `fixHint`, an
|
|
24
|
+
empty no-tools gemini response carries a hint naming grounding, and the raw-lane
|
|
25
|
+
defaults are published as a generated table that cannot drift from the runtime.
|
|
26
|
+
|
|
27
|
+
Declare-first experiment ergonomics (routing-console R3, #239) — a `trial:`
|
|
28
|
+
candidate you declare but never serve live, a console challenger picker, and a
|
|
29
|
+
one-command bake-off that measures it on real captured traffic before you
|
|
30
|
+
promote it.
|
|
31
|
+
|
|
32
|
+
### Changed
|
|
33
|
+
|
|
34
|
+
- **Raw-lane `timeoutMs` default is now tier-aware** (was a flat 120 s):
|
|
35
|
+
`standard`/`priority` default to 300 s and `flex` to 900 s (the 15-minute budget
|
|
36
|
+
ModelRig advertises) — a passthrough should not be shorter-fused than the tier it
|
|
37
|
+
advertises, and grounded/large prompts routinely exceed 120 s even at standard.
|
|
38
|
+
An explicit `timeoutMs` **always wins** (no pre-dispatch rejection — a short
|
|
39
|
+
deadline is a choice), and a `timeout` failure on the raw lane now carries a
|
|
40
|
+
`fixHint` naming the elapsed time, the tier, that tier's budget, and the two
|
|
41
|
+
fixes (raise `timeoutMs`, or drop to `serviceTier: "standard"`). The routed
|
|
42
|
+
lane's required `policy.timeout_ms` is unchanged. Callers who relied on a fast
|
|
43
|
+
120 s failure should set `timeoutMs` explicitly.
|
|
44
|
+
|
|
45
|
+
### Added — declare-first experiment (routing-console R3)
|
|
46
|
+
|
|
47
|
+
- **`candidates[].trial: true`** (route bundle) — a DECLARED candidate that is
|
|
48
|
+
NEVER served live. The loader parses and validates it, marks an all-trial
|
|
49
|
+
variant `trialOnly`, and warns on a trial candidate no variant references;
|
|
50
|
+
`resolveCandidates` drops trial candidates on every live path (`rig.run`,
|
|
51
|
+
`runStream`, `runBundle`, the hosted gateway slug lane) and keeps them only in
|
|
52
|
+
bake-off replay. Selecting a trial variant on a live call is a
|
|
53
|
+
`RouteConfigError` that names the bake-off. This lets a customer measure a new
|
|
54
|
+
model on real captured traffic before promoting it. Additive: a route with no
|
|
55
|
+
trial candidate is byte-identical to before.
|
|
56
|
+
- CAVEAT — **deploy the server before any customer YAML carries `trial:`.** An
|
|
57
|
+
SDK/server older than 0.5.0 IGNORES `trial:` (the loader has always been
|
|
58
|
+
tolerant of unknown candidate keys) and its resolver has no trial-mode filter,
|
|
59
|
+
so it would serve the candidate LIVE — including an older hosted-gateway build
|
|
60
|
+
reading the flag through the mirror. Roll the server first, then let routes
|
|
61
|
+
start declaring `trial:`. The console's declare-YAML says so inline.
|
|
62
|
+
- **`requirementPredicates(route)` / `evaluateChallengerEligibility(...)`** (new
|
|
63
|
+
exports) — decompose a route's `require` + json rung into capability-flag
|
|
64
|
+
requirements and answer "can this model be a trial challenger?", pinned in
|
|
65
|
+
agreement with the live resolver's `satisfiesRequirements`.
|
|
66
|
+
- **`buildDeclareTrialChange(bundle, challenger)` / `trialVariantName(...)`** and
|
|
67
|
+
a trial-winner branch of **`buildSwapChange`** (new exports) — the paste-ready
|
|
68
|
+
declare-YAML (challenger appended `trial: true`, a `trial-<provider>-<model>`
|
|
69
|
+
variant, `version: n+1`) and the promote-YAML that drops the winner's trial
|
|
70
|
+
flag, moves it to position 0, and removes the trial variant. No filesystem, no
|
|
71
|
+
git — the human applies the PR (F6).
|
|
72
|
+
- **`ManualChallengerTrigger` + `manualChallengerTriggerHash`**, and
|
|
73
|
+
**`proposalsClient.createManualChallenger`** — a console/oracle-initiated
|
|
74
|
+
declare-first proposal (`kind:"bakeoff"`, idempotent per `(route, challenger)`).
|
|
75
|
+
- **`RunMeta`/`Rig` additions:** `rig.capabilities` and `rig.searchAvailable` are
|
|
76
|
+
exposed so the challenger picker answers eligibility with the exact live flags;
|
|
77
|
+
`modelrig bakeoff --from-proposal <id>` reads the trial variant from a
|
|
78
|
+
manual_challenger proposal (default vs that one variant).
|
|
79
|
+
- **`resolveRouteBundle` / `hashResolvedBundle`** (new exports) — the canonical
|
|
80
|
+
`bundle_sha` helpers, used by the hosted-lane bake-off to prove the caller org's
|
|
81
|
+
mirrored bundle is the SAME bundle the deployment holds locally (a route-name
|
|
82
|
+
collision on a multi-tenant mirror otherwise baked off a foreign org's route).
|
|
83
|
+
|
|
84
|
+
### Added
|
|
85
|
+
|
|
86
|
+
- **A grounding-naming `fixHint` on an empty no-tools gemini response.** When a
|
|
87
|
+
call that declared no tools comes back with no text parts (a grounding turn
|
|
88
|
+
that produced only `functionCall` parts, for example), the `content_invalid`
|
|
89
|
+
"empty response" failure now names grounding as the likely cause. Note: the
|
|
90
|
+
text extraction itself is unchanged in effect — the SDK already concatenated
|
|
91
|
+
mixed `functionCall` + text parts — so the customer-zero empty-response report
|
|
92
|
+
(#245 secondary) remains an OPEN investigation pending a captured response.
|
|
93
|
+
|
|
94
|
+
### Docs
|
|
95
|
+
|
|
96
|
+
- **Raw-lane defaults table** — a generated table (`RAW_DEFAULTS`, rendered at the
|
|
97
|
+
`<!-- RAW_DEFAULTS -->` marker in `route-bundles.md` and in `llms.txt`) lists
|
|
98
|
+
every raw-lane knob and its default, with the tier-aware `timeoutMs` read from
|
|
99
|
+
the same constant the runtime resolves from — so the published defaults cannot
|
|
100
|
+
drift from what `rig.runRaw` sends. README / quickstart / migration-playbook
|
|
101
|
+
gain the "flex ⇒ set `timeoutMs` in minutes" one-liner.
|
|
102
|
+
|
|
103
|
+
Raw-lane artifact graph + tags parity (G1). A `rig.runRaw` / `rig.runRawStream`
|
|
104
|
+
call inside a `rig.artifacts.run.start` context now records a ground-truth step,
|
|
105
|
+
so a router or report pipeline that wraps raw (BYOK) calls in a run context gets
|
|
106
|
+
a real per-run tree at `/runs/[id]` instead of an empty one. ZERO DDL.
|
|
107
|
+
|
|
108
|
+
### Added — raw-lane graph
|
|
109
|
+
|
|
110
|
+
- **Raw calls record a ground-truth step.** Inside a run context,
|
|
111
|
+
`runRaw`/`runRawStream` emit a step (on success AND failure, buffered AND
|
|
112
|
+
streaming) whose `inference_id` joins the metered `lane=raw` row — parity with
|
|
113
|
+
the routed lane's auto-step. Fail-open: a buffer error there never affects the
|
|
114
|
+
returned result. Outside a run context the dispatch is byte-identical to 0.4.0
|
|
115
|
+
(no step row). Raw steps are **metadata only** — no artifact content is written
|
|
116
|
+
on the raw lane.
|
|
117
|
+
- **`stepKey` on BOTH lanes.** `RunOptions.stepKey` (routed) and
|
|
118
|
+
`RawRunInput.stepKey` (raw) name the step. Resolution is `stepKey ?? tags.step
|
|
119
|
+
?? auto` (`route#n` / `provider/model#n`), validated `[A-Za-z0-9_.:#-]{1,128}`;
|
|
120
|
+
an invalid value is warned once and dropped to the auto key (never thrown). A
|
|
121
|
+
raw row's step **task** is `tags.step ?? provider/model`.
|
|
122
|
+
- **Ambient artifact step.** `artifact.save` without a `stepKey` now attaches to
|
|
123
|
+
the ambient step (the most recent step in the run context), so the two grouping
|
|
124
|
+
mechanisms compose — a raw/routed call and the artifacts saved around it land in
|
|
125
|
+
one group.
|
|
126
|
+
- **Required-dimension hygiene on the raw lane.** `runRaw`/`runRawStream` run the
|
|
127
|
+
same once-per-process "required dimension missing from tags" warning the routed
|
|
128
|
+
lane does.
|
|
129
|
+
|
|
130
|
+
### Added — docs
|
|
131
|
+
|
|
132
|
+
- **instrumentation.md** gains "Tags, dimensions, and the graph": tags = flat
|
|
133
|
+
filter/rollup (`/costs`), the graph = the per-run tree (`/runs/[id]`), how
|
|
134
|
+
`stepKey` + ambient artifacts compose, and the raw-lane behavior.
|
|
135
|
+
- **The per-service key rule** is now stated in the quickstart, the migration
|
|
136
|
+
playbook (F-6), and llms.txt: `MODELRIG_API_KEY` gates the exporter *per
|
|
137
|
+
process* — set it on EVERY service, worker, and cron, or a keyless process
|
|
138
|
+
buffers to its own local SQLite and ships nothing.
|
|
139
|
+
- **route-bundles.md** points at where `rig.yaml` `dimensions` are declared; the
|
|
140
|
+
**README** documents `stepKey` on the raw lane.
|
|
141
|
+
|
|
142
|
+
## [0.4.0] — 2026-08-22
|
|
143
|
+
|
|
144
|
+
Released with the docs/registry mirror in one R-A ceremony. NOT in this tag:
|
|
145
|
+
the R3 declare-first `trial:` candidate flag (#239) and raw-lane artifact
|
|
146
|
+
steps (G1) — both land in 0.5.0.
|
|
147
|
+
|
|
148
|
+
CE-9 raw-lane multi-provider parity — the `reasoning` and native-grounding knobs
|
|
149
|
+
generalize beyond gemini, a `responseFormat` knob joins the raw lane, and the
|
|
150
|
+
provider×knob support set becomes ONE table (`RAW_KNOB_SUPPORT`) that the runtime
|
|
151
|
+
guard AND the published docs matrix both read, so they can never disagree. Every
|
|
152
|
+
knob stays ADDITIVE: absent ⇒ byte-identical to the 0.3.0 request shape.
|
|
153
|
+
|
|
154
|
+
### Added — docs
|
|
155
|
+
|
|
156
|
+
- **Routing & reliability page** (`https://modelrig.dev/routing-reliability.html`) —
|
|
157
|
+
the runtime model in one concept page: resolve -> candidate ladder -> validate ->
|
|
158
|
+
repair -> fall-through -> exhaust, what is stored per attempt, and a **code-anchored
|
|
159
|
+
boundary** (`ROUTING_BOUNDARY`, one tripwire test per entry) that lists what does not
|
|
160
|
+
trigger fall-through and what is not built — the build fails if a listed feature ships
|
|
161
|
+
without the entry being updated.
|
|
162
|
+
|
|
163
|
+
### Fixed
|
|
164
|
+
|
|
165
|
+
- **Failure-teaching links resolve.** `RigFailureError.docsUrl` (and the CLI/console
|
|
166
|
+
error render) now point at `routing-reliability.html#<class>` — one stable heading per
|
|
167
|
+
failure class — instead of the never-built `/docs/failures` path, which 404'd on
|
|
168
|
+
every typed failure.
|
|
169
|
+
|
|
170
|
+
### Added — `rig.runRaw` / `rig.runRawStream`
|
|
171
|
+
|
|
172
|
+
- **`reasoning` generalizes beyond gemini WITHOUT a per-model allowlist (R1).**
|
|
173
|
+
openai / deepinfra / fireworks forward `level` → `reasoning_effort` verbatim
|
|
174
|
+
and let the provider enforce — a model that does not accept it surfaces a
|
|
175
|
+
CLASSIFIED, teaching failure ("this model does not accept reasoning_effort —
|
|
176
|
+
remove reasoning or pick a reasoning model"), never a cryptic 400 or a silent
|
|
177
|
+
drop. grok forwards a DISCLOSED coarsening (`minimal,low → "low"`;
|
|
178
|
+
`medium,high → "high"`; xAI accepts `low|high` only). gemini stays
|
|
179
|
+
model-gated (thinking-capable models only). deepseek + anthropic FAIL CLOSED
|
|
180
|
+
pre-dispatch with a provider-specific fixHint (deepseek → select the
|
|
181
|
+
`deepseek-reasoner` model; anthropic → extended thinking unwired).
|
|
182
|
+
- **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 →
|
|
183
|
+
xAI Live Search (`search_parameters: { mode: "on" }`). Citations are not
|
|
184
|
+
surfaced on `meta` in v1 (same documented limitation as gemini).
|
|
185
|
+
- **`responseFormat?: "json_object"` (R4).** MIME-shaping on the OpenAI-dialect
|
|
186
|
+
providers (openai/deepseek/grok/deepinfra/fireworks → `response_format: { type:
|
|
187
|
+
"json_object" }`) and gemini (`responseMimeType: "application/json"`, no
|
|
188
|
+
schema). This is syntactic-JSON forcing, NOT schema enforcement — F4 stands:
|
|
189
|
+
no validation, no repair, `meta.validated` stays false. anthropic has no
|
|
190
|
+
equivalent and FAILS CLOSED. DeepSeek's word-"JSON" prompt wrinkle is the
|
|
191
|
+
caller's responsibility on the raw lane (documented, never injected).
|
|
192
|
+
- **DeepInfra/Fireworks prompt-cache hint (R3).** `cache.key` now maps to
|
|
193
|
+
`prompt_cache_key` on the openai-compatible adapter, closing the DeepInfra cost
|
|
194
|
+
gap. (openai and grok already mapped `cache.key → prompt_cache_key` on 0.3.0 —
|
|
195
|
+
that was a docs gap, not a code gap; it is now documented as plain fact.)
|
|
196
|
+
|
|
197
|
+
### Added — exports (R5/R6)
|
|
198
|
+
|
|
199
|
+
- **`RAW_KNOB_SUPPORT`** (the provider×knob matrix) + **`rawKnobSupport(provider)`**
|
|
200
|
+
(a pure lookup) — a multi-provider dispatcher ASKS which knobs a provider
|
|
201
|
+
honors instead of duplicating our lists. The guard (`assertRawKnobsSupported`)
|
|
202
|
+
and the docs generator both import this table.
|
|
203
|
+
- **`GEMINI_THINKING_CAPABLE_MODELS`** — the thinking-capable set (previously
|
|
204
|
+
un-exported), so customers stop duplicating it (the §3.1 drift complaint).
|
|
205
|
+
- **`coarsenGrokReasoningEffort`** + **`renderRawKnobMatrix`** — the disclosed
|
|
206
|
+
grok coarsening and the docs matrix renderer.
|
|
207
|
+
|
|
208
|
+
### Docs
|
|
209
|
+
|
|
210
|
+
- A generated provider×knob matrix on the modelrig.dev route-bundles page and in
|
|
211
|
+
`llms.txt`, rendered FROM `RAW_KNOB_SUPPORT` (never a hand-written twin).
|
|
212
|
+
- `caching-lifecycle.md`: the cache directive is provider-neutral — a resource
|
|
213
|
+
HANDLE on gemini, a routing HINT (`prompt_cache_key`, retention on openai) on
|
|
214
|
+
the OpenAI-dialect providers.
|
|
215
|
+
|
|
216
|
+
CE-8 — first-class **runRaw-only construction**. A Lane-B customer who only calls
|
|
217
|
+
`rig.runRaw`/`runRawStream` can now build a rig with no routes at all, so a stray
|
|
218
|
+
route file it never serves cannot down construction — retiring the empty-temp-dir
|
|
219
|
+
workaround.
|
|
220
|
+
|
|
221
|
+
### Added
|
|
222
|
+
|
|
223
|
+
- **`RigConfig.routesDir` now accepts `null`** (was `string`). With `null`,
|
|
224
|
+
`createRig` SKIPS route loading, the `rig.yaml` manifest, and the
|
|
225
|
+
serveable-candidate gate; `runRaw`/`runRawStream` work exactly as before. The
|
|
226
|
+
`string` path is byte-identical to 0.3.0 (the existing serveability hard-error
|
|
227
|
+
on a zero-serveable route is unchanged and regression-pinned).
|
|
228
|
+
- **`requireRoutesDir(config, surface)`** exported — narrows `routesDir` to a
|
|
229
|
+
string for route-required contexts, throwing the teaching failure on `null`.
|
|
230
|
+
Used by `modelrig-server` and `modelrig-oracle` (both always serve routes).
|
|
231
|
+
|
|
232
|
+
### Behaviour
|
|
233
|
+
|
|
234
|
+
- On a `routesDir: null` rig, `run`/`runStream`/`runBundle`/`runBundleStream`/
|
|
235
|
+
`replay`/`bakeoff`/`bakeoffFromEvalCases`/`verifySwap` throw `RigFailureError`
|
|
236
|
+
class `invariant_violation` (no new failure class) with the fixHint
|
|
237
|
+
*"this rig was constructed runRaw-only (routesDir: null); give createRig a
|
|
238
|
+
routesDir to serve routes"*. `rig.serveability` is `[]`.
|
|
239
|
+
- `loadConfigFromEnv` stays string-only (no env var disables routes, by design);
|
|
240
|
+
opt out in code: `createRig({ ...loadConfigFromEnv(), routesDir: null })`.
|
|
241
|
+
|
|
242
|
+
### Docs
|
|
243
|
+
|
|
244
|
+
- README, `docs/migration-playbook.md` (Lane-B seam + C4 checkpoint), and the
|
|
245
|
+
generated `llms.txt` gain the runRaw-only construction snippet, the `apiKey`
|
|
246
|
+
BYOK line on every `runRaw` example, the combined-prompt → `userPrompt` note,
|
|
247
|
+
and the note that the cache-ratio-vs-baseline metric is a REAL-run measurement
|
|
248
|
+
(deferred-to-first-run at the checkpoint), not a probe.
|
|
249
|
+
|
|
250
|
+
R0 — the **per-call telemetry ladder key** (routing-console spec §2.1). Every
|
|
251
|
+
inference row now records which call it belongs to and its position in the
|
|
252
|
+
routing ladder, so a dashboard can reconstruct the exact sequence one `rig.run`
|
|
253
|
+
walked and compute fallback / repair rates.
|
|
254
|
+
|
|
255
|
+
### Added — telemetry ladder key
|
|
256
|
+
|
|
257
|
+
- **`RunMeta.callId`** — the `call_id` shared by every telemetry row a single
|
|
258
|
+
`run` / `runStream` / `runBundle` / `runRaw` invocation writes (primary, retry,
|
|
259
|
+
repair, grounding-search, tool-call), so a caller can correlate a `RunResult`
|
|
260
|
+
with its ladder in the console. Additive & OPTIONAL — a pre-0.4.0 caller's meta
|
|
261
|
+
omits it.
|
|
262
|
+
- Telemetry rows gain **`call_id`**, **`attempt_seq`** (1-based, monotonic across
|
|
263
|
+
every row of the call), and **`candidate_index`** (position of the dispatched
|
|
264
|
+
candidate in the call's EFFECTIVE declared list — after variant narrowing and
|
|
265
|
+
per-run filters; a repair row carries the repaired candidate's index; the raw
|
|
266
|
+
lane is seq 1 / index 0). All three are OPTIONAL on the wire and nullable in
|
|
267
|
+
storage: an older SDK OMITS them and the payload is byte-identical to before
|
|
268
|
+
R0; a reader treats null as *"recorded by an SDK older than 0.4.0."*
|
|
269
|
+
- OTLP spans gain `modelrig.call_id` / `modelrig.attempt_seq` /
|
|
270
|
+
`modelrig.candidate_index`, emitted only when present.
|
|
271
|
+
- **`CandidateIterator.index`** (read-only getter, public type) — the index of the
|
|
272
|
+
candidate the last `next()` returned (−1 before the first call). Additive for
|
|
273
|
+
callers; an external IMPLEMENTER of the interface must add the member.
|
|
274
|
+
- **`tags.rung`** on every telemetry row (R1 review, F1) — one of `primary` |
|
|
275
|
+
`retry` | `repair` | `search` | `tool_call` | `predispatch_fail`, so the routing
|
|
276
|
+
dashboard and ladder view can tell a real candidate dispatch from a tool-call
|
|
277
|
+
turn or a pre-dispatch failure without column heuristics. Additive (rides
|
|
278
|
+
`tags_json`, no schema change); a pre-0.4.0 row omits it and the rollup falls
|
|
279
|
+
back to `repaired_by` / `provider = "search"`. Public type `TelemetryRung` is
|
|
280
|
+
exported.
|
|
281
|
+
|
|
13
282
|
## [0.3.0] — 2026-08-21
|
|
14
283
|
|
|
15
284
|
The `modelrig-oracle` MCP server ships to npm alongside this release (its own
|
package/README.md
CHANGED
|
@@ -99,27 +99,88 @@ 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
104
|
|
|
105
105
|
`rig.runRaw` also accepts
|
|
106
|
-
|
|
107
|
-
`grounding: { mode: "native" }` (native provider web grounding
|
|
108
|
-
|
|
109
|
-
`reasoning: { level: "minimal" | "low" | "medium" | "high" }` (
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
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
|
+
Called inside a `rig.artifacts.run.start` context, `runRaw`/`runRawStream` also
|
|
148
|
+
records a ground-truth **step** in the run's graph (`/runs/[id]`) — since
|
|
149
|
+
modelrig 0.5.0, on success and on failure. Name it with `stepKey` (the same field
|
|
150
|
+
`RunOptions` exposes on the routed lane; precedence `stepKey` > `tags.step` > an
|
|
151
|
+
auto `provider/model#n` key), so a raw call and the artifacts you `save` around it
|
|
152
|
+
group under one step.
|
|
153
|
+
|
|
154
|
+
The raw-lane `timeoutMs` default is **tier-aware** since 0.5.0 — `standard`/
|
|
155
|
+
`priority` 300 s, `flex` 900 s; an explicit `timeoutMs` always wins, and a
|
|
156
|
+
`timeout` failure teaches the tier + budget in its `fixHint`. **flex ⇒ set
|
|
157
|
+
`timeoutMs` in minutes** (default 900 s since 0.5.0). See the generated
|
|
158
|
+
[raw-lane defaults table](https://modelrig.dev/route-bundles.html#raw-lane-defaults-rigrunraw).
|
|
159
|
+
|
|
160
|
+
**runRaw-only construction (`routesDir: null`) — 0.4.0+.** A
|
|
161
|
+
Lane-B deployment that ONLY calls `runRaw`/`runRawStream` has no routes. Build it
|
|
162
|
+
with `routesDir: null` and `createRig` skips route loading, the `rig.yaml`
|
|
163
|
+
manifest, and the serveability gate entirely — so a stray route file it never
|
|
164
|
+
calls (or a route whose provider key is absent in this deployment) can no longer
|
|
165
|
+
down construction:
|
|
166
|
+
|
|
167
|
+
```ts
|
|
168
|
+
const rig = createRig({ ...loadConfigFromEnv(), routesDir: null });
|
|
169
|
+
await rig.runRaw({ provider, model, apiKey, systemPrompt, userPrompt });
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
`loadConfigFromEnv()` always yields a string `routesDir`, so the opt-out is a
|
|
173
|
+
deliberate code-level choice — override it as above; there is no env var that
|
|
174
|
+
disables routes, by design. On such a rig, `rig.run` and every other
|
|
175
|
+
route-dependent surface (`runStream`, `runBundle`, bake-offs, watch, replay,
|
|
176
|
+
`verifySwap`) throws a terminal `invariant_violation` naming the fix.
|
|
116
177
|
|
|
117
178
|
Every attempt is recorded in a local SQLite file (`.modelrig/telemetry.db`)
|
|
118
179
|
tagged with your `tags`. Failures are typed —
|
|
119
180
|
`RigFailureError.failure.class` is one of `content_invalid`, `capacity_shed`,
|
|
120
|
-
`network`, `refusal`, `cache_invalid`, `timeout`, `budget_exhausted`,
|
|
181
|
+
`network`, `refusal`, `cache_invalid`, `timeout`, `config_auth`, `budget_exhausted`,
|
|
121
182
|
`invariant_violation` — with a separate retry budget per class, so a flaky
|
|
122
|
-
network never spends your content-validation retries.
|
|
183
|
+
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).
|
|
123
184
|
|
|
124
185
|
## CLI
|
|
125
186
|
|
|
@@ -155,6 +216,10 @@ on the quickstart:
|
|
|
155
216
|
stable enough to build on, not frozen.
|
|
156
217
|
- **`modelrig serve` needs the `modelrig-server` package** — it is not bundled
|
|
157
218
|
here.
|
|
219
|
+
- **What the ladder does and does not do.** Fall-through is structural and
|
|
220
|
+
infrastructural, never a quality judgment; the full boundary (quality gate,
|
|
221
|
+
raw-lane structure, latency ordering…) is generated and tripwire-tested on
|
|
222
|
+
[Routing & reliability](https://modelrig.dev/routing-reliability.html#10-not-yet-implemented-the-boundary).
|
|
158
223
|
|
|
159
224
|
## License
|
|
160
225
|
|
|
@@ -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;
|
|
@@ -50,5 +56,44 @@ export interface GeminiShapedRequest {
|
|
|
50
56
|
}
|
|
51
57
|
/** Pure request shaping — everything except the abort signal. */
|
|
52
58
|
export declare function buildGeminiRequest(model: string, req: ShapingInput): GeminiShapedRequest;
|
|
59
|
+
/** A candidate's parts as we read them post-response — `functionCall`, `text`,
|
|
60
|
+
* and (if `includeThoughts` were ever set) a `thought`-flagged text part may all
|
|
61
|
+
* appear on the same candidate (a grounded / thinking turn). */
|
|
62
|
+
type GeminiCandidatePart = {
|
|
63
|
+
readonly functionCall?: unknown;
|
|
64
|
+
readonly text?: string;
|
|
65
|
+
readonly thought?: boolean;
|
|
66
|
+
};
|
|
67
|
+
type GeminiCandidateShape = {
|
|
68
|
+
readonly content?: {
|
|
69
|
+
readonly parts?: readonly GeminiCandidatePart[];
|
|
70
|
+
};
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* #245 secondary — concatenate the answer `text` parts of a Gemini candidate's
|
|
74
|
+
* content. On the raw / no-tools lane a grounding-originated `functionCall` part
|
|
75
|
+
* (googleSearch) is NOT a tool-call turn, and the SDK's `response.text` getter
|
|
76
|
+
* returns empty (and logs a warning) on a response that mixes `functionCall` +
|
|
77
|
+
* `text` parts — so read the text parts directly. `thought`-flagged parts are
|
|
78
|
+
* skipped to match `response.text` semantics (they are the reasoning summary, not
|
|
79
|
+
* the answer). Pure + exported for the fixture regression test (no network).
|
|
80
|
+
* (spec §2 Secondary — the SNPS bug.)
|
|
81
|
+
*/
|
|
82
|
+
export declare function extractGeminiCandidateText(candidate: GeminiCandidateShape | undefined): string;
|
|
83
|
+
/** #245 secondary — whether a candidate carries a `functionCall` part. On the
|
|
84
|
+
* no-tools lane this means grounding produced only a googleSearch invocation with
|
|
85
|
+
* no text answer, which the empty-response `fixHint` should name. */
|
|
86
|
+
export declare function geminiCandidateHasFunctionCall(candidate: GeminiCandidateShape | undefined): boolean;
|
|
87
|
+
/**
|
|
88
|
+
* #245 secondary — pick the answer text from a Gemini response. The branch the
|
|
89
|
+
* `call()` path uses, extracted pure so it is unit-testable without a network:
|
|
90
|
+
* - tools declared: trust the SDK `response.text` getter, byte-identical to
|
|
91
|
+
* pre-#245 (a functionCall turn is handled earlier as a tool-call).
|
|
92
|
+
* - no tools declared: read the candidate's text parts directly, because
|
|
93
|
+
* `response.text` returns empty on a grounding-originated functionCall+text
|
|
94
|
+
* response; fall back to `response.text` only if there is no text part.
|
|
95
|
+
*/
|
|
96
|
+
export declare function resolveGeminiText(candidate: GeminiCandidateShape | undefined, responseText: string | undefined, hasTools: boolean): string;
|
|
53
97
|
export declare function createGeminiAdapter(config: GeminiAdapterConfig): ProviderAdapter;
|
|
98
|
+
export {};
|
|
54
99
|
//# sourceMappingURL=gemini.d.ts.map
|
|
@@ -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;;gEAEgE;AAChE,KAAK,mBAAmB,GAAG;IACzB,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,CAAC;IAChC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;CAC5B,CAAC;AACF,KAAK,oBAAoB,GAAG;IAAE,QAAQ,CAAC,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,mBAAmB,EAAE,CAAA;KAAE,CAAA;CAAE,CAAC;AAEvG;;;;;;;;;GASG;AACH,wBAAgB,0BAA0B,CAAC,SAAS,EAAE,oBAAoB,GAAG,SAAS,GAAG,MAAM,CAM9F;AAED;;qEAEqE;AACrE,wBAAgB,8BAA8B,CAAC,SAAS,EAAE,oBAAoB,GAAG,SAAS,GAAG,OAAO,CAInG;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,oBAAoB,GAAG,SAAS,EAC3C,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,QAAQ,EAAE,OAAO,GAChB,MAAM,CAGR;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,mBAAmB,GAAG,eAAe,CA+KhF"}
|
package/dist/adapters/gemini.js
CHANGED
|
@@ -15,17 +15,24 @@
|
|
|
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;
|
|
20
21
|
exports.geminiReasoningUnsupported = geminiReasoningUnsupported;
|
|
21
22
|
exports.buildGeminiRequest = buildGeminiRequest;
|
|
23
|
+
exports.extractGeminiCandidateText = extractGeminiCandidateText;
|
|
24
|
+
exports.geminiCandidateHasFunctionCall = geminiCandidateHasFunctionCall;
|
|
25
|
+
exports.resolveGeminiText = resolveGeminiText;
|
|
22
26
|
exports.createGeminiAdapter = createGeminiAdapter;
|
|
23
27
|
const genai_1 = require("@google/genai");
|
|
24
28
|
const tool_mapping_1 = require("./tool-mapping");
|
|
25
29
|
const sampling_1 = require("./sampling");
|
|
26
30
|
/** Models that accept thinkingConfig — passing it to 2.x models 400s.
|
|
27
|
-
* Ported from the production THINKING_CAPABLE_MODELS set.
|
|
28
|
-
|
|
31
|
+
* Ported from the production THINKING_CAPABLE_MODELS set. EXPORTED (CE-9 R6) so
|
|
32
|
+
* a multi-provider customer's dispatcher reads THIS set instead of duplicating
|
|
33
|
+
* it (the §3.1 drift complaint) — the same fact the raw-lane guard uses to keep
|
|
34
|
+
* gemini reasoning model-gated. */
|
|
35
|
+
exports.GEMINI_THINKING_CAPABLE_MODELS = new Set([
|
|
29
36
|
"gemini-3.1-pro-preview",
|
|
30
37
|
"gemini-3.0-pro-preview",
|
|
31
38
|
"gemini-3.1-flash-preview",
|
|
@@ -110,7 +117,7 @@ function classifyGeminiFailure(message) {
|
|
|
110
117
|
* reasoning declared, or a thinking-capable model). Pure — unit-tested directly.
|
|
111
118
|
*/
|
|
112
119
|
function geminiReasoningUnsupported(model, req) {
|
|
113
|
-
if (req.reasoning !== undefined && !
|
|
120
|
+
if (req.reasoning !== undefined && !exports.GEMINI_THINKING_CAPABLE_MODELS.has(model)) {
|
|
114
121
|
return {
|
|
115
122
|
cls: "invariant_violation",
|
|
116
123
|
fixHint: `reasoning control requires a thinking-capable Gemini model; "${model}" is not one — remove reasoning or choose a thinking-capable model`,
|
|
@@ -134,12 +141,18 @@ function buildGeminiRequest(model, req) {
|
|
|
134
141
|
maxOutputTokens: (0, sampling_1.effectiveMaxOutputTokens)(req, DEFAULT_MAX_OUTPUT_TOKENS),
|
|
135
142
|
topP: req.sampling?.topP ?? TOP_P,
|
|
136
143
|
topK: TOP_K,
|
|
137
|
-
...(
|
|
144
|
+
...(exports.GEMINI_THINKING_CAPABLE_MODELS.has(model) ? { thinkingConfig: { thinkingLevel } } : {}),
|
|
138
145
|
};
|
|
139
146
|
if (req.outputSchema !== null) {
|
|
140
147
|
config.responseMimeType = "application/json";
|
|
141
148
|
config.responseJsonSchema = req.outputSchema;
|
|
142
149
|
}
|
|
150
|
+
else if (req.responseFormat === "json_object") {
|
|
151
|
+
// CE-9 R4: mime-shaping ONLY — force a JSON mime type WITHOUT a schema. This
|
|
152
|
+
// is the raw lane, so F4 stands: no responseJsonSchema, no validation, no
|
|
153
|
+
// repair, `validated` stays false. Absent ⇒ no key (byte-identical).
|
|
154
|
+
config.responseMimeType = "application/json";
|
|
155
|
+
}
|
|
143
156
|
// cachedContent excludes systemInstruction and tools — the API rejects
|
|
144
157
|
// requests setting both (they are baked into the cache at creation time,
|
|
145
158
|
// including the googleSearch tool for cached grounded steps).
|
|
@@ -180,6 +193,43 @@ function extractServedTier(rawServiceTier, trafficType, requested) {
|
|
|
180
193
|
return "priority";
|
|
181
194
|
return requested;
|
|
182
195
|
}
|
|
196
|
+
/**
|
|
197
|
+
* #245 secondary — concatenate the answer `text` parts of a Gemini candidate's
|
|
198
|
+
* content. On the raw / no-tools lane a grounding-originated `functionCall` part
|
|
199
|
+
* (googleSearch) is NOT a tool-call turn, and the SDK's `response.text` getter
|
|
200
|
+
* returns empty (and logs a warning) on a response that mixes `functionCall` +
|
|
201
|
+
* `text` parts — so read the text parts directly. `thought`-flagged parts are
|
|
202
|
+
* skipped to match `response.text` semantics (they are the reasoning summary, not
|
|
203
|
+
* the answer). Pure + exported for the fixture regression test (no network).
|
|
204
|
+
* (spec §2 Secondary — the SNPS bug.)
|
|
205
|
+
*/
|
|
206
|
+
function extractGeminiCandidateText(candidate) {
|
|
207
|
+
return (candidate?.content?.parts ?? [])
|
|
208
|
+
.filter((p) => p.thought !== true)
|
|
209
|
+
.map((p) => p.text)
|
|
210
|
+
.filter((t) => typeof t === "string")
|
|
211
|
+
.join("");
|
|
212
|
+
}
|
|
213
|
+
/** #245 secondary — whether a candidate carries a `functionCall` part. On the
|
|
214
|
+
* no-tools lane this means grounding produced only a googleSearch invocation with
|
|
215
|
+
* no text answer, which the empty-response `fixHint` should name. */
|
|
216
|
+
function geminiCandidateHasFunctionCall(candidate) {
|
|
217
|
+
return (candidate?.content?.parts ?? []).some((p) => p.functionCall !== undefined && p.functionCall !== null);
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* #245 secondary — pick the answer text from a Gemini response. The branch the
|
|
221
|
+
* `call()` path uses, extracted pure so it is unit-testable without a network:
|
|
222
|
+
* - tools declared: trust the SDK `response.text` getter, byte-identical to
|
|
223
|
+
* pre-#245 (a functionCall turn is handled earlier as a tool-call).
|
|
224
|
+
* - no tools declared: read the candidate's text parts directly, because
|
|
225
|
+
* `response.text` returns empty on a grounding-originated functionCall+text
|
|
226
|
+
* response; fall back to `response.text` only if there is no text part.
|
|
227
|
+
*/
|
|
228
|
+
function resolveGeminiText(candidate, responseText, hasTools) {
|
|
229
|
+
if (hasTools)
|
|
230
|
+
return responseText ?? "";
|
|
231
|
+
return extractGeminiCandidateText(candidate) || (responseText ?? "");
|
|
232
|
+
}
|
|
183
233
|
function createGeminiAdapter(config) {
|
|
184
234
|
const ai = new genai_1.GoogleGenAI({ apiKey: config.apiKey });
|
|
185
235
|
return {
|
|
@@ -256,9 +306,20 @@ function createGeminiAdapter(config) {
|
|
|
256
306
|
if (finishReason === "RECITATION") {
|
|
257
307
|
return fail("refusal", "Gemini blocked output via recitation filter (finishReason=RECITATION)", undefined, usage);
|
|
258
308
|
}
|
|
259
|
-
|
|
309
|
+
// #245 secondary: when the caller declared NO tools, a `functionCall`
|
|
310
|
+
// part is grounding-originated (googleSearch), NOT a tool-call turn — and
|
|
311
|
+
// `response.text` returns empty on a mixed functionCall+text response, so
|
|
312
|
+
// read the text parts directly. When tools WERE declared this path is
|
|
313
|
+
// reached only for a no-functionCall response, so `response.text` is
|
|
314
|
+
// byte-identical to before.
|
|
315
|
+
const noTools = req.tools === undefined || req.tools.length === 0;
|
|
316
|
+
const text = resolveGeminiText(candidates?.[0], response.text, !noTools);
|
|
260
317
|
if (text.trim().length === 0) {
|
|
261
|
-
|
|
318
|
+
const groundedNoText = noTools &&
|
|
319
|
+
geminiCandidateHasFunctionCall(candidates?.[0]);
|
|
320
|
+
return fail("content_invalid", `empty response from Gemini (finishReason=${finishReason ?? "none"})`, groundedNoText
|
|
321
|
+
? "the grounded response returned only a googleSearch functionCall part with no text — refine the grounding query, or remove grounding if the model can answer directly"
|
|
322
|
+
: undefined, usage);
|
|
262
323
|
}
|
|
263
324
|
if (finishReason === "MAX_TOKENS" && req.outputSchema !== null) {
|
|
264
325
|
// A truncated structured emission is mid-object and unparseable.
|
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"}
|