modelrig 0.1.0 → 0.3.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 +158 -0
- package/README.md +53 -11
- package/data/PROVENANCE.md +19 -0
- package/data/pricing-manual.json +22 -0
- package/data/pricing-map.json +46362 -0
- package/data/pricing-overlay.json +419 -0
- package/dist/adapters/anthropic.d.ts +50 -6
- package/dist/adapters/anthropic.d.ts.map +1 -1
- package/dist/adapters/anthropic.js +123 -29
- package/dist/adapters/build-adapters.d.ts +11 -0
- package/dist/adapters/build-adapters.d.ts.map +1 -0
- package/dist/adapters/build-adapters.js +45 -0
- package/dist/adapters/deepseek.d.ts +6 -0
- package/dist/adapters/deepseek.d.ts.map +1 -1
- package/dist/adapters/deepseek.js +54 -1
- package/dist/adapters/gemini.d.ts +10 -0
- package/dist/adapters/gemini.d.ts.map +1 -1
- package/dist/adapters/gemini.js +78 -7
- package/dist/adapters/grok.d.ts +9 -0
- package/dist/adapters/grok.d.ts.map +1 -1
- package/dist/adapters/grok.js +67 -3
- package/dist/adapters/openai-compat.d.ts +6 -0
- package/dist/adapters/openai-compat.d.ts.map +1 -1
- package/dist/adapters/openai-compat.js +58 -1
- package/dist/adapters/openai-stream.d.ts +58 -0
- package/dist/adapters/openai-stream.d.ts.map +1 -0
- package/dist/adapters/openai-stream.js +120 -0
- package/dist/adapters/openai.d.ts +6 -0
- package/dist/adapters/openai.d.ts.map +1 -1
- package/dist/adapters/openai.js +60 -1
- package/dist/adapters/sampling.d.ts +28 -0
- package/dist/adapters/sampling.d.ts.map +1 -0
- package/dist/adapters/sampling.js +34 -0
- package/dist/adapters/tool-mapping.d.ts +92 -0
- package/dist/adapters/tool-mapping.d.ts.map +1 -0
- package/dist/adapters/tool-mapping.js +143 -0
- package/dist/artifacts/artifact.d.ts +137 -0
- package/dist/artifacts/artifact.d.ts.map +1 -0
- package/dist/artifacts/artifact.js +377 -0
- package/dist/artifacts/content-uploader.d.ts +87 -0
- package/dist/artifacts/content-uploader.d.ts.map +1 -0
- package/dist/artifacts/content-uploader.js +124 -0
- package/dist/artifacts/index.d.ts +63 -0
- package/dist/artifacts/index.d.ts.map +1 -0
- package/dist/artifacts/index.js +80 -0
- package/dist/artifacts/run-context.d.ts +129 -0
- package/dist/artifacts/run-context.d.ts.map +1 -0
- package/dist/artifacts/run-context.js +208 -0
- package/dist/artifacts/scrub.d.ts +60 -0
- package/dist/artifacts/scrub.d.ts.map +1 -0
- package/dist/artifacts/scrub.js +139 -0
- package/dist/artifacts/step.d.ts +26 -0
- package/dist/artifacts/step.d.ts.map +1 -0
- package/dist/artifacts/step.js +37 -0
- package/dist/artifacts/taint.d.ts +63 -0
- package/dist/artifacts/taint.d.ts.map +1 -0
- package/dist/artifacts/taint.js +76 -0
- package/dist/bakeoff/cache-sim.d.ts +99 -0
- package/dist/bakeoff/cache-sim.d.ts.map +1 -0
- package/dist/bakeoff/cache-sim.js +126 -0
- package/dist/bakeoff/eval-cases.d.ts +96 -0
- package/dist/bakeoff/eval-cases.d.ts.map +1 -0
- package/dist/bakeoff/eval-cases.js +105 -0
- package/dist/bakeoff/report.d.ts +41 -0
- package/dist/bakeoff/report.d.ts.map +1 -0
- package/dist/bakeoff/report.js +142 -0
- package/dist/bakeoff/samples.d.ts +15 -0
- package/dist/bakeoff/samples.d.ts.map +1 -1
- package/dist/bakeoff/samples.js +20 -0
- package/dist/cli.d.ts +1 -3
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +134 -116
- package/dist/config.d.ts +100 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +104 -0
- package/dist/deprecations.d.ts +32 -0
- package/dist/deprecations.d.ts.map +1 -0
- package/dist/deprecations.js +59 -0
- package/dist/gateway/http-protocol.d.ts +175 -0
- package/dist/gateway/http-protocol.d.ts.map +1 -0
- package/dist/gateway/http-protocol.js +105 -0
- package/dist/index.d.ts +106 -19
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +266 -138
- package/dist/init/finder.d.ts +15 -0
- package/dist/init/finder.d.ts.map +1 -1
- package/dist/init/finder.js +46 -0
- package/dist/init/init-cli.d.ts +10 -0
- package/dist/init/init-cli.d.ts.map +1 -0
- package/dist/init/init-cli.js +86 -0
- package/dist/init/observe-cli.d.ts +19 -0
- package/dist/init/observe-cli.d.ts.map +1 -0
- package/dist/init/observe-cli.js +73 -0
- package/dist/init/observe.d.ts +81 -0
- package/dist/init/observe.d.ts.map +1 -0
- package/dist/init/observe.js +245 -0
- package/dist/registry/build.d.ts +94 -1
- package/dist/registry/build.d.ts.map +1 -1
- package/dist/registry/build.js +125 -4
- package/dist/registry/cache-policy.d.ts +94 -0
- package/dist/registry/cache-policy.d.ts.map +1 -0
- package/dist/registry/cache-policy.js +238 -0
- package/dist/registry/call-notes.d.ts.map +1 -1
- package/dist/registry/call-notes.js +40 -2
- package/dist/registry/effective-rate.d.ts +151 -0
- package/dist/registry/effective-rate.d.ts.map +1 -0
- package/dist/registry/effective-rate.js +156 -0
- package/dist/registry/facts.d.ts.map +1 -1
- package/dist/registry/facts.js +16 -0
- package/dist/registry/parity.d.ts +26 -0
- package/dist/registry/parity.d.ts.map +1 -1
- package/dist/registry/parity.js +43 -2
- package/dist/registry/pricing-shape.d.ts +113 -0
- package/dist/registry/pricing-shape.d.ts.map +1 -0
- package/dist/registry/pricing-shape.js +123 -0
- package/dist/registry/pricing.d.ts +25 -1
- package/dist/registry/pricing.d.ts.map +1 -1
- package/dist/registry/pricing.js +64 -6
- package/dist/rigindex/bootstrap.d.ts +36 -0
- package/dist/rigindex/bootstrap.d.ts.map +1 -0
- package/dist/rigindex/bootstrap.js +97 -0
- package/dist/rigindex/fit.d.ts +24 -0
- package/dist/rigindex/fit.d.ts.map +1 -0
- package/dist/rigindex/fit.js +76 -0
- package/dist/rigindex/gates.d.ts +52 -0
- package/dist/rigindex/gates.d.ts.map +1 -0
- package/dist/rigindex/gates.js +109 -0
- package/dist/rigindex/graph.d.ts +31 -0
- package/dist/rigindex/graph.d.ts.map +1 -0
- package/dist/rigindex/graph.js +120 -0
- package/dist/rigindex/index.d.ts +23 -0
- package/dist/rigindex/index.d.ts.map +1 -0
- package/dist/rigindex/index.js +112 -0
- package/dist/rigindex/types.d.ts +76 -0
- package/dist/rigindex/types.d.ts.map +1 -0
- package/dist/rigindex/types.js +8 -0
- package/dist/routes/cache-lint.d.ts +41 -0
- package/dist/routes/cache-lint.d.ts.map +1 -0
- package/dist/routes/cache-lint.js +81 -0
- package/dist/routes/loader.d.ts +48 -0
- package/dist/routes/loader.d.ts.map +1 -1
- package/dist/routes/loader.js +167 -0
- package/dist/routes/resolved-bundle.d.ts +79 -0
- package/dist/routes/resolved-bundle.d.ts.map +1 -0
- package/dist/routes/resolved-bundle.js +148 -0
- package/dist/routes/sampling-config.d.ts +32 -0
- package/dist/routes/sampling-config.d.ts.map +1 -0
- package/dist/routes/sampling-config.js +91 -0
- package/dist/run/ajv.d.ts +22 -0
- package/dist/run/ajv.d.ts.map +1 -0
- package/dist/run/ajv.js +32 -0
- package/dist/run/cache-handle.d.ts +58 -0
- package/dist/run/cache-handle.d.ts.map +1 -0
- package/dist/run/cache-handle.js +54 -0
- package/dist/run/cache-stamp.d.ts +65 -0
- package/dist/run/cache-stamp.d.ts.map +1 -0
- package/dist/run/cache-stamp.js +0 -0
- package/dist/run/capture-write.d.ts +33 -0
- package/dist/run/capture-write.d.ts.map +1 -0
- package/dist/run/capture-write.js +55 -0
- package/dist/run/cost.d.ts.map +1 -1
- package/dist/run/cost.js +1 -1
- package/dist/run/dispatch.d.ts +99 -0
- package/dist/run/dispatch.d.ts.map +1 -0
- package/dist/run/dispatch.js +191 -0
- package/dist/run/raw.d.ts +130 -0
- package/dist/run/raw.d.ts.map +1 -0
- package/dist/run/raw.js +363 -0
- package/dist/run/record-attempt.d.ts +40 -0
- package/dist/run/record-attempt.d.ts.map +1 -0
- package/dist/run/record-attempt.js +99 -0
- package/dist/run/resolve.d.ts +75 -2
- package/dist/run/resolve.d.ts.map +1 -1
- package/dist/run/resolve.js +126 -4
- package/dist/run/run.d.ts +14 -0
- package/dist/run/run.d.ts.map +1 -1
- package/dist/run/run.js +0 -0
- package/dist/run/stream.d.ts +49 -0
- package/dist/run/stream.d.ts.map +1 -0
- package/dist/run/stream.js +87 -0
- package/dist/run/validate.d.ts.map +1 -1
- package/dist/run/validate.js +6 -7
- package/dist/savings/cache-ledger.d.ts +108 -0
- package/dist/savings/cache-ledger.d.ts.map +1 -0
- package/dist/savings/cache-ledger.js +174 -0
- package/dist/savings/cache-reconcile.d.ts +64 -0
- package/dist/savings/cache-reconcile.d.ts.map +1 -0
- package/dist/savings/cache-reconcile.js +59 -0
- package/dist/savings/cache-stats.d.ts +63 -0
- package/dist/savings/cache-stats.d.ts.map +1 -0
- package/dist/savings/cache-stats.js +108 -0
- package/dist/savings/emit.d.ts +13 -0
- package/dist/savings/emit.d.ts.map +1 -1
- package/dist/savings/emit.js +25 -0
- package/dist/savings/swap-execute.d.ts +14 -0
- package/dist/savings/swap-execute.d.ts.map +1 -1
- package/dist/savings/swap-execute.js +44 -1
- package/dist/savings/swaps-client.d.ts +14 -0
- package/dist/savings/swaps-client.d.ts.map +1 -1
- package/dist/savings/swaps-client.js +16 -2
- package/dist/settings/api-fetcher.d.ts +39 -0
- package/dist/settings/api-fetcher.d.ts.map +1 -0
- package/dist/settings/api-fetcher.js +92 -0
- package/dist/settings/index.d.ts +10 -0
- package/dist/settings/index.d.ts.map +1 -0
- package/dist/settings/index.js +15 -0
- package/dist/settings/task-settings.d.ts +91 -0
- package/dist/settings/task-settings.d.ts.map +1 -0
- package/dist/settings/task-settings.js +116 -0
- package/dist/status.d.ts +77 -0
- package/dist/status.d.ts.map +1 -0
- package/dist/status.js +113 -0
- package/dist/telemetry/artifact-store.d.ts +48 -0
- package/dist/telemetry/artifact-store.d.ts.map +1 -0
- package/dist/telemetry/artifact-store.js +189 -0
- package/dist/telemetry/cache-miss-streak.d.ts +79 -0
- package/dist/telemetry/cache-miss-streak.d.ts.map +1 -0
- package/dist/telemetry/cache-miss-streak.js +99 -0
- package/dist/telemetry/capture.d.ts +3 -0
- package/dist/telemetry/capture.d.ts.map +1 -1
- package/dist/telemetry/capture.js +15 -8
- package/dist/telemetry/exporter-setup.d.ts +28 -0
- package/dist/telemetry/exporter-setup.d.ts.map +1 -0
- package/dist/telemetry/exporter-setup.js +34 -0
- package/dist/telemetry/exporter.d.ts +75 -0
- package/dist/telemetry/exporter.d.ts.map +1 -1
- package/dist/telemetry/exporter.js +324 -47
- package/dist/telemetry/health.d.ts +76 -0
- package/dist/telemetry/health.d.ts.map +1 -0
- package/dist/telemetry/health.js +92 -0
- package/dist/telemetry/ingest-protocol.d.ts +152 -3
- package/dist/telemetry/ingest-protocol.d.ts.map +1 -1
- package/dist/telemetry/ingest-protocol.js +204 -4
- package/dist/telemetry/load-error-report.d.ts +24 -0
- package/dist/telemetry/load-error-report.d.ts.map +1 -0
- package/dist/telemetry/load-error-report.js +50 -0
- package/dist/telemetry/otel-map.d.ts +121 -0
- package/dist/telemetry/otel-map.d.ts.map +1 -0
- package/dist/telemetry/otel-map.js +224 -0
- package/dist/telemetry/otel-normalize.d.ts +104 -0
- package/dist/telemetry/otel-normalize.d.ts.map +1 -0
- package/dist/telemetry/otel-normalize.js +530 -0
- package/dist/telemetry/otlp-emitter.d.ts +52 -0
- package/dist/telemetry/otlp-emitter.d.ts.map +1 -0
- package/dist/telemetry/otlp-emitter.js +144 -0
- package/dist/telemetry/otlp-proto.d.ts +29 -0
- package/dist/telemetry/otlp-proto.d.ts.map +1 -0
- package/dist/telemetry/otlp-proto.js +266 -0
- package/dist/telemetry/sinks.d.ts +37 -1
- package/dist/telemetry/sinks.d.ts.map +1 -1
- package/dist/telemetry/sinks.js +121 -30
- package/dist/telemetry/store.d.ts +28 -1
- package/dist/telemetry/store.d.ts.map +1 -1
- package/dist/telemetry/store.js +218 -3
- package/dist/tenancy/api-key-format.d.ts +15 -5
- package/dist/tenancy/api-key-format.d.ts.map +1 -1
- package/dist/tenancy/api-key-format.js +24 -5
- package/dist/types/config-teaching.d.ts +62 -0
- package/dist/types/config-teaching.d.ts.map +1 -0
- package/dist/types/config-teaching.js +183 -0
- package/dist/types/provider.d.ts +147 -1
- package/dist/types/provider.d.ts.map +1 -1
- package/dist/types/provider.js +21 -1
- package/dist/types/route.d.ts +79 -1
- package/dist/types/route.d.ts.map +1 -1
- package/dist/types/telemetry.d.ts +117 -0
- package/dist/types/telemetry.d.ts.map +1 -1
- package/dist/validate-cli.d.ts +12 -0
- package/dist/validate-cli.d.ts.map +1 -0
- package/dist/validate-cli.js +57 -0
- package/dist/verify/capture.d.ts +66 -0
- package/dist/verify/capture.d.ts.map +1 -0
- package/dist/verify/capture.js +180 -0
- package/dist/verify/cli-run.d.ts +23 -0
- package/dist/verify/cli-run.d.ts.map +1 -0
- package/dist/verify/cli-run.js +57 -0
- package/dist/verify/diff.d.ts +48 -0
- package/dist/verify/diff.d.ts.map +1 -0
- package/dist/verify/diff.js +157 -0
- package/dist/verify/index.d.ts +17 -0
- package/dist/verify/index.d.ts.map +1 -0
- package/dist/verify/index.js +24 -0
- package/dist/verify/report.d.ts +14 -0
- package/dist/verify/report.d.ts.map +1 -0
- package/dist/verify/report.js +88 -0
- package/dist/verify/types.d.ts +101 -0
- package/dist/verify/types.d.ts.map +1 -0
- package/dist/verify/types.js +17 -0
- package/dist/verify/verify.d.ts +29 -0
- package/dist/verify/verify.d.ts.map +1 -0
- package/dist/verify/verify.js +148 -0
- package/dist/watch/evaluate.d.ts +162 -3
- package/dist/watch/evaluate.d.ts.map +1 -1
- package/dist/watch/evaluate.js +61 -0
- package/dist/watch/monitor.d.ts +116 -0
- package/dist/watch/monitor.d.ts.map +1 -0
- package/dist/watch/monitor.js +199 -0
- package/dist/watch/proposals.d.ts +20 -4
- package/dist/watch/proposals.d.ts.map +1 -1
- package/dist/watch/proposals.js +31 -3
- package/dist/watch/run.d.ts +33 -0
- package/dist/watch/run.d.ts.map +1 -1
- package/dist/watch/run.js +39 -0
- package/package.json +7 -1
- package/registry/LICENSE +20 -0
- package/registry/leaderboard.json +3639 -0
- package/registry/registry.json +7263 -0
- package/dist/telemetry/supabase-exporter.d.ts +0 -64
- package/dist/telemetry/supabase-exporter.d.ts.map +0 -1
- package/dist/telemetry/supabase-exporter.js +0 -211
|
@@ -5,9 +5,10 @@
|
|
|
5
5
|
* CALL: the route schema becomes the single tool's input_schema and
|
|
6
6
|
* tool_choice pins it, so the accumulated input_json_delta stream IS the
|
|
7
7
|
* JSON output (Anthropic's recommended structured-output pattern; the run
|
|
8
|
-
* loop still ajv-validates like every provider). Prompt caching is
|
|
9
|
-
* cache_control on Anthropic
|
|
10
|
-
*
|
|
8
|
+
* loop still ajv-validates like every provider). Prompt caching (WS-C) is
|
|
9
|
+
* explicit `cache_control` on Anthropic: when the request opts in, the system
|
|
10
|
+
* prefix is marked with an ephemeral breakpoint (buildAnthropicParams) and the
|
|
11
|
+
* `context_cache_explicit` capability is advertised per the cache-policy registry.
|
|
11
12
|
*/
|
|
12
13
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
13
14
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
@@ -17,8 +18,11 @@ exports.isStrictSchemaRejection = isStrictSchemaRejection;
|
|
|
17
18
|
exports.anthropicSupports = anthropicSupports;
|
|
18
19
|
exports.classifyAnthropicFailure = classifyAnthropicFailure;
|
|
19
20
|
exports.buildAnthropicParams = buildAnthropicParams;
|
|
21
|
+
exports.normalizeAnthropicInputUsage = normalizeAnthropicInputUsage;
|
|
20
22
|
exports.createAnthropicAdapter = createAnthropicAdapter;
|
|
21
23
|
const sdk_1 = __importDefault(require("@anthropic-ai/sdk"));
|
|
24
|
+
const tool_mapping_1 = require("./tool-mapping");
|
|
25
|
+
const sampling_1 = require("./sampling");
|
|
22
26
|
const DEFAULT_MAX_TOKENS = 32000;
|
|
23
27
|
const OUTPUT_TOOL_NAME = "route_output";
|
|
24
28
|
/** Strict tool use (constrained decoding) — public beta. Schemas that
|
|
@@ -34,13 +38,14 @@ function anthropicSupports(feature, _model) {
|
|
|
34
38
|
switch (feature) {
|
|
35
39
|
case "structured_native": // forced tool call with the route schema
|
|
36
40
|
case "json_mode":
|
|
41
|
+
case "context_cache_explicit": // cache_control ephemeral blocks (WS-C) — cache-policy registry truth
|
|
37
42
|
return true;
|
|
38
43
|
case "grounded_native": // web-search tool exists but is not wired
|
|
39
|
-
case "
|
|
40
|
-
case "prompt_cache_key":
|
|
44
|
+
case "prompt_cache_key": // anthropic ignores keys — caching is prefix-based via cache_control
|
|
41
45
|
case "prefix_cache_implicit":
|
|
42
46
|
case "tier_flex":
|
|
43
47
|
case "trace_visible": // extended thinking not enabled by this adapter
|
|
48
|
+
case "zero_retention": // never a static adapter attestation — set only from the credential-scoped registry facts (claims.ts)
|
|
44
49
|
return false;
|
|
45
50
|
}
|
|
46
51
|
}
|
|
@@ -73,31 +78,85 @@ function classifyAnthropicFailure(message) {
|
|
|
73
78
|
return { cls: "network" };
|
|
74
79
|
}
|
|
75
80
|
function buildAnthropicParams(model, req, strict = false) {
|
|
81
|
+
// Structured output is a FORCED tool call on the route schema (existing
|
|
82
|
+
// path). Otherwise, caller-supplied `tools` (spec §4.4) map to Anthropic's
|
|
83
|
+
// tool_use — the two are mutually exclusive here (a structured route does
|
|
84
|
+
// not also expose free tools in Phase A).
|
|
85
|
+
const toolBlock = req.outputSchema !== null
|
|
86
|
+
? {
|
|
87
|
+
tools: [
|
|
88
|
+
{
|
|
89
|
+
name: OUTPUT_TOOL_NAME,
|
|
90
|
+
description: "Emit the structured output for this route.",
|
|
91
|
+
input_schema: req.outputSchema,
|
|
92
|
+
...(strict ? { strict: true } : {}),
|
|
93
|
+
},
|
|
94
|
+
],
|
|
95
|
+
tool_choice: { type: "tool", name: OUTPUT_TOOL_NAME },
|
|
96
|
+
}
|
|
97
|
+
: req.tools !== undefined && req.tools.length > 0
|
|
98
|
+
? {
|
|
99
|
+
tools: (0, tool_mapping_1.toAnthropicTools)(req.tools),
|
|
100
|
+
...((0, tool_mapping_1.toAnthropicToolChoice)(req.toolChoice) !== undefined
|
|
101
|
+
? { tool_choice: (0, tool_mapping_1.toAnthropicToolChoice)(req.toolChoice) }
|
|
102
|
+
: {}),
|
|
103
|
+
}
|
|
104
|
+
: {};
|
|
105
|
+
// Prompt caching (WS-C): when the request opts in (`cache` set by the run
|
|
106
|
+
// loop's policy-gated stamp), mark the system prompt — the stable prefix in
|
|
107
|
+
// ModelRig's system-carries-the-task convention — with a `cache_control`
|
|
108
|
+
// ephemeral breakpoint. Anthropic caches the prefix up to and including the
|
|
109
|
+
// marked block (default 5m TTL, refreshes free on read); the `cache.key` is
|
|
110
|
+
// ignored (caching is prefix-based, not key-based — that is why the telemetry
|
|
111
|
+
// `cache_key` for anthropic is null). Extended 1h TTL is a documented
|
|
112
|
+
// follow-up (needs the extended-cache beta header; WS-A already accounts the
|
|
113
|
+
// 5m/1h split when the provider reports it).
|
|
114
|
+
const wantsCache = req.cache?.key !== undefined && req.cache.key !== "";
|
|
115
|
+
const systemField = req.systemPrompt === ""
|
|
116
|
+
? {}
|
|
117
|
+
: wantsCache
|
|
118
|
+
? {
|
|
119
|
+
system: [
|
|
120
|
+
{ type: "text", text: req.systemPrompt, cache_control: { type: "ephemeral" } },
|
|
121
|
+
],
|
|
122
|
+
}
|
|
123
|
+
: { system: req.systemPrompt };
|
|
76
124
|
return {
|
|
77
125
|
model,
|
|
78
|
-
max_tokens: req
|
|
79
|
-
...(
|
|
126
|
+
max_tokens: (0, sampling_1.effectiveMaxOutputTokens)(req, DEFAULT_MAX_TOKENS),
|
|
127
|
+
...(0, sampling_1.openAISamplingFields)(req),
|
|
128
|
+
...systemField,
|
|
80
129
|
messages: [{ role: "user", content: req.userPrompt }],
|
|
81
130
|
stream: true,
|
|
82
|
-
...
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
131
|
+
...toolBlock,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Normalize Anthropic's `message_start` usage to ModelRig's convention
|
|
136
|
+
* (research §4 fix). Anthropic's `input_tokens` is the UNCACHED portion only;
|
|
137
|
+
* ModelRig requires `tokensIn` to INCLUDE cache reads and writes as subsets, so
|
|
138
|
+
* we add them back. Pure and total — the fixture-tested seam for the subset
|
|
139
|
+
* invariant and the 5m/1h split.
|
|
140
|
+
*/
|
|
141
|
+
function normalizeAnthropicInputUsage(u) {
|
|
142
|
+
const uncached = u.input_tokens ?? 0;
|
|
143
|
+
const read = u.cache_read_input_tokens ?? 0;
|
|
144
|
+
const write = u.cache_creation_input_tokens ?? 0;
|
|
145
|
+
// 1h split when the extended-TTL beta reports it; clamp to the total write so
|
|
146
|
+
// a malformed payload can never make the 1h bucket exceed the write bucket.
|
|
147
|
+
const write1h = Math.min(u.cache_creation?.ephemeral_1h_input_tokens ?? 0, write);
|
|
148
|
+
return {
|
|
149
|
+
tokensIn: uncached + read + write,
|
|
150
|
+
tokensCached: read,
|
|
151
|
+
tokensCacheWrite: write,
|
|
152
|
+
tokensCacheWrite1h: write1h,
|
|
95
153
|
};
|
|
96
154
|
}
|
|
97
155
|
function createAnthropicAdapter(config) {
|
|
98
156
|
return {
|
|
99
157
|
id: "anthropic",
|
|
100
158
|
supports: anthropicSupports,
|
|
159
|
+
supportsTools: () => true,
|
|
101
160
|
async call(req) {
|
|
102
161
|
const model = req.candidate.model;
|
|
103
162
|
// F1: post-stream failures still billed tokens — attach usage.
|
|
@@ -136,23 +195,47 @@ function createAnthropicAdapter(config) {
|
|
|
136
195
|
stream = await client.messages.create(buildAnthropicParams(model, req));
|
|
137
196
|
}
|
|
138
197
|
const events = stream;
|
|
198
|
+
// Caller-supplied tools (spec §4.4) live on the non-structured path:
|
|
199
|
+
// accumulate each `tool_use` block's input_json_delta by block index.
|
|
200
|
+
const wantTools = req.outputSchema === null && req.tools !== undefined && req.tools.length > 0;
|
|
201
|
+
const toolBlocks = new Map();
|
|
139
202
|
let text = "";
|
|
140
|
-
|
|
203
|
+
// Input-side usage, normalized at message_start (subset invariant +
|
|
204
|
+
// research §4 tokensIn fix + 5m/1h split live in normalizeAnthropicInputUsage).
|
|
205
|
+
let inputUsage = {
|
|
206
|
+
tokensIn: 0,
|
|
207
|
+
tokensCached: 0,
|
|
208
|
+
tokensCacheWrite: 0,
|
|
209
|
+
tokensCacheWrite1h: 0,
|
|
210
|
+
};
|
|
141
211
|
let completionTokens = 0;
|
|
142
|
-
let cachedTokens = 0;
|
|
143
212
|
let stopReason = null;
|
|
144
213
|
for await (const event of events) {
|
|
145
214
|
if (event.type === "message_start" && event.message?.usage !== undefined) {
|
|
146
|
-
|
|
147
|
-
|
|
215
|
+
inputUsage = normalizeAnthropicInputUsage(event.message.usage);
|
|
216
|
+
}
|
|
217
|
+
else if (event.type === "content_block_start" &&
|
|
218
|
+
wantTools &&
|
|
219
|
+
event.content_block?.type === "tool_use") {
|
|
220
|
+
toolBlocks.set(event.index ?? 0, {
|
|
221
|
+
id: event.content_block.id ?? "",
|
|
222
|
+
name: event.content_block.name ?? "",
|
|
223
|
+
json: "",
|
|
224
|
+
});
|
|
148
225
|
}
|
|
149
226
|
else if (event.type === "content_block_delta") {
|
|
227
|
+
// Tools path: input_json_delta is the tool's arguments, per block.
|
|
150
228
|
// Schema path: the forced tool's input_json_delta IS the output.
|
|
151
|
-
// Plain path: text deltas. Never mix the
|
|
152
|
-
if (
|
|
229
|
+
// Plain path: text deltas. Never mix the buffers.
|
|
230
|
+
if (wantTools && event.delta?.type === "input_json_delta" && event.delta.partial_json) {
|
|
231
|
+
const blk = toolBlocks.get(event.index ?? 0);
|
|
232
|
+
if (blk !== undefined)
|
|
233
|
+
blk.json += event.delta.partial_json;
|
|
234
|
+
}
|
|
235
|
+
else if (wantJson && event.delta?.type === "input_json_delta" && event.delta.partial_json) {
|
|
153
236
|
text += event.delta.partial_json;
|
|
154
237
|
}
|
|
155
|
-
else if (
|
|
238
|
+
else if (event.delta?.type === "text_delta" && event.delta.text) {
|
|
156
239
|
text += event.delta.text;
|
|
157
240
|
}
|
|
158
241
|
}
|
|
@@ -165,12 +248,23 @@ function createAnthropicAdapter(config) {
|
|
|
165
248
|
}
|
|
166
249
|
}
|
|
167
250
|
// Anthropic has no service tiers on this path — served is standard.
|
|
251
|
+
// The input side (tokensIn incl. cached+write, the write buckets) was
|
|
252
|
+
// normalized by normalizeAnthropicInputUsage (research §4 fix).
|
|
168
253
|
const usage = {
|
|
169
|
-
|
|
254
|
+
...inputUsage,
|
|
170
255
|
tokensOut: completionTokens,
|
|
171
|
-
tokensCached: cachedTokens,
|
|
172
256
|
servedTier: "standard",
|
|
173
257
|
};
|
|
258
|
+
// Tool-call turn (spec §4.4): `arguments` is the raw JSON string the
|
|
259
|
+
// model streamed (OpenAI parity) — text may be empty, skip the guards.
|
|
260
|
+
if (wantTools && toolBlocks.size > 0) {
|
|
261
|
+
const toolCalls = [...toolBlocks.values()].map((b, i) => ({
|
|
262
|
+
id: b.id !== "" ? b.id : `call_${i}`,
|
|
263
|
+
type: "function",
|
|
264
|
+
function: { name: b.name, arguments: b.json === "" ? "{}" : b.json },
|
|
265
|
+
}));
|
|
266
|
+
return { ok: true, text, usage, toolCalls };
|
|
267
|
+
}
|
|
174
268
|
if (stopReason === "refusal") {
|
|
175
269
|
return fail("refusal", "Anthropic refused this request (stop_reason=refusal)", undefined, usage);
|
|
176
270
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build the provider-adapter map from resolved config + registry facts.
|
|
3
|
+
* Extracted from index.ts (the SDK entrypoint) so that file stays under the LOC
|
|
4
|
+
* cap — the same reason wireRigArtifacts / buildExportedRouteMirrors live apart.
|
|
5
|
+
* Mechanical, one caller; behaviour is byte-identical to the prior inline block.
|
|
6
|
+
*/
|
|
7
|
+
import type { RigConfig } from "../config";
|
|
8
|
+
import type { RegistryFacts } from "../registry/facts";
|
|
9
|
+
import type { CapabilityFlag, ProviderAdapter } from "../types/provider";
|
|
10
|
+
export declare function buildAdapters(config: RigConfig, registryFacts: RegistryFacts, compatStatic: ReadonlySet<CapabilityFlag>): Map<string, ProviderAdapter>;
|
|
11
|
+
//# sourceMappingURL=build-adapters.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build-adapters.d.ts","sourceRoot":"","sources":["../../src/adapters/build-adapters.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAQzE,wBAAgB,aAAa,CAC3B,MAAM,EAAE,SAAS,EACjB,aAAa,EAAE,aAAa,EAC5B,YAAY,EAAE,WAAW,CAAC,cAAc,CAAC,GACxC,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CA6B9B"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Build the provider-adapter map from resolved config + registry facts.
|
|
4
|
+
* Extracted from index.ts (the SDK entrypoint) so that file stays under the LOC
|
|
5
|
+
* cap — the same reason wireRigArtifacts / buildExportedRouteMirrors live apart.
|
|
6
|
+
* Mechanical, one caller; behaviour is byte-identical to the prior inline block.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.buildAdapters = buildAdapters;
|
|
10
|
+
const anthropic_1 = require("./anthropic");
|
|
11
|
+
const deepseek_1 = require("./deepseek");
|
|
12
|
+
const gemini_1 = require("./gemini");
|
|
13
|
+
const grok_1 = require("./grok");
|
|
14
|
+
const openai_1 = require("./openai");
|
|
15
|
+
const openai_compat_1 = require("./openai-compat");
|
|
16
|
+
function buildAdapters(config, registryFacts, compatStatic) {
|
|
17
|
+
const adapters = new Map();
|
|
18
|
+
if (config.keys.gemini)
|
|
19
|
+
adapters.set("gemini", (0, gemini_1.createGeminiAdapter)({ apiKey: config.keys.gemini }));
|
|
20
|
+
if (config.keys.openai)
|
|
21
|
+
adapters.set("openai", (0, openai_1.createOpenAIAdapter)({ apiKey: config.keys.openai }));
|
|
22
|
+
if (config.keys.deepseek) {
|
|
23
|
+
adapters.set("deepseek", (0, deepseek_1.createDeepSeekAdapter)({ apiKey: config.keys.deepseek }));
|
|
24
|
+
}
|
|
25
|
+
if (config.keys.anthropic) {
|
|
26
|
+
adapters.set("anthropic", (0, anthropic_1.createAnthropicAdapter)({ apiKey: config.keys.anthropic }));
|
|
27
|
+
}
|
|
28
|
+
if (config.keys.grok)
|
|
29
|
+
adapters.set("grok", (0, grok_1.createGrokAdapter)({ apiKey: config.keys.grok }));
|
|
30
|
+
// A1 aggregator hosts behind the generic openai-compatible adapter.
|
|
31
|
+
for (const hostId of ["deepinfra", "fireworks"]) {
|
|
32
|
+
const apiKey = config.keys[hostId];
|
|
33
|
+
if (!apiKey)
|
|
34
|
+
continue;
|
|
35
|
+
const host = openai_compat_1.OPENAI_COMPAT_HOSTS[hostId];
|
|
36
|
+
adapters.set(hostId, (0, openai_compat_1.createOpenAICompatAdapter)({
|
|
37
|
+
providerId: hostId,
|
|
38
|
+
baseUrl: host.baseUrl,
|
|
39
|
+
apiKey,
|
|
40
|
+
...(host.shapeModelId !== undefined ? { shapeModelId: host.shapeModelId } : {}),
|
|
41
|
+
capabilityProfile: (model) => registryFacts.flagsFor(hostId, model, compatStatic) ?? compatStatic,
|
|
42
|
+
}));
|
|
43
|
+
}
|
|
44
|
+
return adapters;
|
|
45
|
+
}
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
import type { CapabilityFlag, ProviderAdapter } from "../types/provider";
|
|
16
16
|
import type { ClassifiedFailure, ShapingInput } from "./gemini";
|
|
17
|
+
import type { OpenAIWireTool, OpenAIWireToolChoice } from "./tool-mapping";
|
|
17
18
|
export interface DeepSeekAdapterConfig {
|
|
18
19
|
readonly apiKey: string;
|
|
19
20
|
}
|
|
@@ -31,9 +32,14 @@ export interface DeepSeekShapedParams {
|
|
|
31
32
|
readonly stream_options: {
|
|
32
33
|
readonly include_usage: true;
|
|
33
34
|
};
|
|
35
|
+
/** CE-6 declared sampling — present only when the route/raw asks for them. */
|
|
36
|
+
readonly temperature?: number;
|
|
37
|
+
readonly top_p?: number;
|
|
34
38
|
readonly response_format?: {
|
|
35
39
|
readonly type: "json_object";
|
|
36
40
|
};
|
|
41
|
+
readonly tools?: readonly OpenAIWireTool[];
|
|
42
|
+
readonly tool_choice?: OpenAIWireToolChoice;
|
|
37
43
|
}
|
|
38
44
|
export declare function buildDeepSeekParams(model: string, req: ShapingInput): DeepSeekShapedParams;
|
|
39
45
|
export declare function createDeepSeekAdapter(config: DeepSeekAdapterConfig): ProviderAdapter;
|
|
@@ -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;
|
|
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,CA2B1F;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,qBAAqB,GAAG,eAAe,CA8JpF"}
|
|
@@ -22,6 +22,9 @@ exports.classifyDeepSeekFailure = classifyDeepSeekFailure;
|
|
|
22
22
|
exports.buildDeepSeekParams = buildDeepSeekParams;
|
|
23
23
|
exports.createDeepSeekAdapter = createDeepSeekAdapter;
|
|
24
24
|
const openai_1 = __importDefault(require("openai"));
|
|
25
|
+
const tool_mapping_1 = require("./tool-mapping");
|
|
26
|
+
const openai_stream_1 = require("./openai-stream");
|
|
27
|
+
const sampling_1 = require("./sampling");
|
|
25
28
|
const DEEPSEEK_BASE_URL = "https://api.deepseek.com";
|
|
26
29
|
const DEFAULT_MAX_TOKENS = 64000; // R1/V3 max — full capacity for long reports (ported)
|
|
27
30
|
function deepseekSupports(feature, model) {
|
|
@@ -69,17 +72,27 @@ function buildDeepSeekParams(model, req) {
|
|
|
69
72
|
];
|
|
70
73
|
return {
|
|
71
74
|
model,
|
|
72
|
-
max_tokens: req
|
|
75
|
+
max_tokens: (0, sampling_1.effectiveMaxOutputTokens)(req, DEFAULT_MAX_TOKENS),
|
|
73
76
|
messages,
|
|
74
77
|
stream: true,
|
|
75
78
|
stream_options: { include_usage: true },
|
|
79
|
+
...(0, sampling_1.openAISamplingFields)(req),
|
|
76
80
|
...(wantJson ? { response_format: { type: "json_object" } } : {}),
|
|
81
|
+
...(req.tools !== undefined && req.tools.length > 0
|
|
82
|
+
? {
|
|
83
|
+
tools: (0, tool_mapping_1.toOpenAITools)(req.tools),
|
|
84
|
+
...((0, tool_mapping_1.toOpenAIToolChoice)(req.toolChoice) !== undefined
|
|
85
|
+
? { tool_choice: (0, tool_mapping_1.toOpenAIToolChoice)(req.toolChoice) }
|
|
86
|
+
: {}),
|
|
87
|
+
}
|
|
88
|
+
: {}),
|
|
77
89
|
};
|
|
78
90
|
}
|
|
79
91
|
function createDeepSeekAdapter(config) {
|
|
80
92
|
return {
|
|
81
93
|
id: "deepseek",
|
|
82
94
|
supports: deepseekSupports,
|
|
95
|
+
supportsTools: () => true,
|
|
83
96
|
async call(req) {
|
|
84
97
|
const model = req.candidate.model;
|
|
85
98
|
// F1: post-stream failures still billed tokens — attach usage.
|
|
@@ -110,6 +123,7 @@ function createDeepSeekAdapter(config) {
|
|
|
110
123
|
let finishReason = null;
|
|
111
124
|
// TTFB (Phase 4 WS3): first streamed chunk = first body byte.
|
|
112
125
|
let ttfbMs;
|
|
126
|
+
const toolCallAcc = (0, tool_mapping_1.createOpenAIToolCallAccumulator)();
|
|
113
127
|
// Only delta.content is accumulated — a reasoner's reasoning_content
|
|
114
128
|
// (chain-of-thought) must never leak into the JSON buffer (ported).
|
|
115
129
|
for await (const chunk of stream) {
|
|
@@ -118,6 +132,7 @@ function createDeepSeekAdapter(config) {
|
|
|
118
132
|
const choice = chunk.choices[0];
|
|
119
133
|
if (choice?.delta?.content)
|
|
120
134
|
text += choice.delta.content;
|
|
135
|
+
toolCallAcc.push(choice?.delta?.tool_calls);
|
|
121
136
|
if (choice?.finish_reason)
|
|
122
137
|
finishReason = choice.finish_reason;
|
|
123
138
|
if (chunk.usage) {
|
|
@@ -135,6 +150,11 @@ function createDeepSeekAdapter(config) {
|
|
|
135
150
|
servedTier: "standard",
|
|
136
151
|
...(ttfbMs !== undefined ? { ttfbMs } : {}),
|
|
137
152
|
};
|
|
153
|
+
// Tool-call turn (spec §4.4): surface normalized calls, skip content guards.
|
|
154
|
+
const toolCalls = toolCallAcc.finalize();
|
|
155
|
+
if (toolCalls !== undefined) {
|
|
156
|
+
return { ok: true, text, usage, toolCalls };
|
|
157
|
+
}
|
|
138
158
|
if (text.trim().length === 0) {
|
|
139
159
|
return fail("content_invalid", `empty response from DeepSeek (finish_reason=${finishReason ?? "none"})`, undefined, usage);
|
|
140
160
|
}
|
|
@@ -159,5 +179,38 @@ function createDeepSeekAdapter(config) {
|
|
|
159
179
|
};
|
|
160
180
|
}
|
|
161
181
|
},
|
|
182
|
+
async *stream(req) {
|
|
183
|
+
const model = req.candidate.model;
|
|
184
|
+
try {
|
|
185
|
+
const client = new openai_1.default({ apiKey: config.apiKey, baseURL: DEEPSEEK_BASE_URL, timeout: req.timeoutMs });
|
|
186
|
+
const params = buildDeepSeekParams(model, req);
|
|
187
|
+
const dispatchedAt = Date.now();
|
|
188
|
+
const stream = await client.chat.completions.create(params);
|
|
189
|
+
// DeepSeek: cached tokens surface as prompt_cache_hit_tokens; no tiers.
|
|
190
|
+
yield* (0, openai_stream_1.streamOpenAIDialect)(stream, req, dispatchedAt, {
|
|
191
|
+
provider: "deepseek",
|
|
192
|
+
cachedTokenSource: "cache_hit",
|
|
193
|
+
mapServedTier: () => "standard",
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
catch (error) {
|
|
197
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
198
|
+
const { cls, fixHint } = classifyDeepSeekFailure(message);
|
|
199
|
+
yield {
|
|
200
|
+
kind: "final",
|
|
201
|
+
result: {
|
|
202
|
+
ok: false,
|
|
203
|
+
failure: {
|
|
204
|
+
class: cls,
|
|
205
|
+
message,
|
|
206
|
+
provider: "deepseek",
|
|
207
|
+
model,
|
|
208
|
+
cause: error,
|
|
209
|
+
...(fixHint !== undefined ? { fixHint } : {}),
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
},
|
|
162
215
|
};
|
|
163
216
|
}
|
|
@@ -33,6 +33,16 @@ export declare function classifyGeminiFailure(message: string): ClassifiedFailur
|
|
|
33
33
|
/** The candidate-independent part of an AdapterRequest (also what the pure
|
|
34
34
|
* shaping helpers take, so unit tests never need a branded CandidateRef). */
|
|
35
35
|
export type ShapingInput = Omit<AdapterRequest, "candidate">;
|
|
36
|
+
/**
|
|
37
|
+
* CE-2 F3 fail-closed guard: `reasoning` declared on a Gemini model that is NOT
|
|
38
|
+
* thinking-capable would 400 at the provider (thinkingConfig on a 2.x model is
|
|
39
|
+
* rejected). Pre-empt with a classified TERMINAL failure so the declaration is
|
|
40
|
+
* never silently dropped and never turns into an unguarded provider 400 — the
|
|
41
|
+
* same fail-closed discipline as the raw-lane provider guard (spec §3 F1/F3).
|
|
42
|
+
* Returns the failure class + fixHint, or null when the request is fine (no
|
|
43
|
+
* reasoning declared, or a thinking-capable model). Pure — unit-tested directly.
|
|
44
|
+
*/
|
|
45
|
+
export declare function geminiReasoningUnsupported(model: string, req: ShapingInput): ClassifiedFailure | null;
|
|
36
46
|
export interface GeminiShapedRequest {
|
|
37
47
|
readonly model: string;
|
|
38
48
|
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;
|
|
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;AAkCD,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,CAgDxF;AA0BD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,mBAAmB,GAAG,eAAe,CA+JhF"}
|
package/dist/adapters/gemini.js
CHANGED
|
@@ -17,9 +17,12 @@
|
|
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
18
|
exports.geminiSupports = geminiSupports;
|
|
19
19
|
exports.classifyGeminiFailure = classifyGeminiFailure;
|
|
20
|
+
exports.geminiReasoningUnsupported = geminiReasoningUnsupported;
|
|
20
21
|
exports.buildGeminiRequest = buildGeminiRequest;
|
|
21
22
|
exports.createGeminiAdapter = createGeminiAdapter;
|
|
22
23
|
const genai_1 = require("@google/genai");
|
|
24
|
+
const tool_mapping_1 = require("./tool-mapping");
|
|
25
|
+
const sampling_1 = require("./sampling");
|
|
23
26
|
/** Models that accept thinkingConfig — passing it to 2.x models 400s.
|
|
24
27
|
* Ported from the production THINKING_CAPABLE_MODELS set. */
|
|
25
28
|
const THINKING_CAPABLE_MODELS = new Set([
|
|
@@ -27,7 +30,16 @@ const THINKING_CAPABLE_MODELS = new Set([
|
|
|
27
30
|
"gemini-3.0-pro-preview",
|
|
28
31
|
"gemini-3.1-flash-preview",
|
|
29
32
|
]);
|
|
30
|
-
/** Gemini
|
|
33
|
+
/** Gemini-3 default. Google STRONGLY recommends temperature=1.0 for all
|
|
34
|
+
* Gemini 3 models and warns that values below 1.0 can cause looping / degraded
|
|
35
|
+
* output — concentrated on complex reasoning/math tasks, not simple
|
|
36
|
+
* classification (verified 2026-08-20 against ai.google.dev/gemini-api/docs/gemini-3;
|
|
37
|
+
* the source pipeline ran gemini-3.1-pro at 0.1 for CLASSIFICATION without
|
|
38
|
+
* looping, which the reasoning-task carve-out explains). It is a recommendation,
|
|
39
|
+
* not a hard API cap: the accepted range stays 0–2. This is the DEFAULT the
|
|
40
|
+
* adapter sends when a route declares no `sampling.temperature`; a declared
|
|
41
|
+
* value overrides it and is sent as-is (CE-6), with a load-time warning emitted
|
|
42
|
+
* for a sub-1.0 value on a Gemini-3 candidate (routes/loader.ts). */
|
|
31
43
|
const GEMINI_TEMPERATURE = 1.0;
|
|
32
44
|
const DEFAULT_MAX_OUTPUT_TOKENS = 64000; // thinking tokens count against this
|
|
33
45
|
const TOP_P = 0.95;
|
|
@@ -88,15 +100,41 @@ function classifyGeminiFailure(message) {
|
|
|
88
100
|
}
|
|
89
101
|
return { cls: "network" };
|
|
90
102
|
}
|
|
103
|
+
/**
|
|
104
|
+
* CE-2 F3 fail-closed guard: `reasoning` declared on a Gemini model that is NOT
|
|
105
|
+
* thinking-capable would 400 at the provider (thinkingConfig on a 2.x model is
|
|
106
|
+
* rejected). Pre-empt with a classified TERMINAL failure so the declaration is
|
|
107
|
+
* never silently dropped and never turns into an unguarded provider 400 — the
|
|
108
|
+
* same fail-closed discipline as the raw-lane provider guard (spec §3 F1/F3).
|
|
109
|
+
* Returns the failure class + fixHint, or null when the request is fine (no
|
|
110
|
+
* reasoning declared, or a thinking-capable model). Pure — unit-tested directly.
|
|
111
|
+
*/
|
|
112
|
+
function geminiReasoningUnsupported(model, req) {
|
|
113
|
+
if (req.reasoning !== undefined && !THINKING_CAPABLE_MODELS.has(model)) {
|
|
114
|
+
return {
|
|
115
|
+
cls: "invariant_violation",
|
|
116
|
+
fixHint: `reasoning control requires a thinking-capable Gemini model; "${model}" is not one — remove reasoning or choose a thinking-capable model`,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
91
121
|
/** Pure request shaping — everything except the abort signal. */
|
|
92
122
|
function buildGeminiRequest(model, req) {
|
|
93
123
|
const usingCache = req.cache?.key !== undefined && req.cache.key !== "";
|
|
124
|
+
// CE-6: a declared sampling field OVERRIDES the ported constant; absent, the
|
|
125
|
+
// constant stands (byte-identical to pre-CE-6). topK stays internal (gemini-only,
|
|
126
|
+
// not on the customer surface — spec §1 non-goals).
|
|
127
|
+
// CE-2 F3: a declared reasoning level replaces the hardcoded `"high"` for the
|
|
128
|
+
// thinking-capable models; absent, `"high"` stands (byte-identical to
|
|
129
|
+
// pre-CE-2). A declared level on a NON-capable model is rejected fail-closed in
|
|
130
|
+
// call() (geminiReasoningUnsupported) — it never reaches this shaping.
|
|
131
|
+
const thinkingLevel = req.reasoning?.level ?? "high";
|
|
94
132
|
const config = {
|
|
95
|
-
temperature: GEMINI_TEMPERATURE,
|
|
96
|
-
maxOutputTokens: req
|
|
97
|
-
topP: TOP_P,
|
|
133
|
+
temperature: req.sampling?.temperature ?? GEMINI_TEMPERATURE,
|
|
134
|
+
maxOutputTokens: (0, sampling_1.effectiveMaxOutputTokens)(req, DEFAULT_MAX_OUTPUT_TOKENS),
|
|
135
|
+
topP: req.sampling?.topP ?? TOP_P,
|
|
98
136
|
topK: TOP_K,
|
|
99
|
-
...(THINKING_CAPABLE_MODELS.has(model) ? { thinkingConfig: { thinkingLevel
|
|
137
|
+
...(THINKING_CAPABLE_MODELS.has(model) ? { thinkingConfig: { thinkingLevel } } : {}),
|
|
100
138
|
};
|
|
101
139
|
if (req.outputSchema !== null) {
|
|
102
140
|
config.responseMimeType = "application/json";
|
|
@@ -115,6 +153,14 @@ function buildGeminiRequest(model, req) {
|
|
|
115
153
|
if (req.grounding === true) {
|
|
116
154
|
config.tools = [{ googleSearch: {} }];
|
|
117
155
|
}
|
|
156
|
+
else if (req.tools !== undefined && req.tools.length > 0) {
|
|
157
|
+
// Caller-supplied tools (spec §4.4) → Gemini functionDeclarations.
|
|
158
|
+
// Grounding wins the single `tools` slot when both are asked for.
|
|
159
|
+
config.tools = (0, tool_mapping_1.toGeminiTools)(req.tools);
|
|
160
|
+
const toolConfig = (0, tool_mapping_1.toGeminiToolConfig)(req.toolChoice);
|
|
161
|
+
if (toolConfig !== undefined)
|
|
162
|
+
config.toolConfig = toolConfig;
|
|
163
|
+
}
|
|
118
164
|
}
|
|
119
165
|
if (req.requestedTier === "flex") {
|
|
120
166
|
config.serviceTier = "flex";
|
|
@@ -139,6 +185,7 @@ function createGeminiAdapter(config) {
|
|
|
139
185
|
return {
|
|
140
186
|
id: "gemini",
|
|
141
187
|
supports: geminiSupports,
|
|
188
|
+
supportsTools: () => true,
|
|
142
189
|
async call(req) {
|
|
143
190
|
const model = req.candidate.model;
|
|
144
191
|
const abortController = new AbortController();
|
|
@@ -156,6 +203,13 @@ function createGeminiAdapter(config) {
|
|
|
156
203
|
},
|
|
157
204
|
...(usage !== undefined ? { usage } : {}),
|
|
158
205
|
});
|
|
206
|
+
// CE-2 F3: reject reasoning on a non-thinking model BEFORE any dispatch —
|
|
207
|
+
// classified, terminal, never a silent drop (spec §3 F3).
|
|
208
|
+
const reasoningUnsupported = geminiReasoningUnsupported(model, req);
|
|
209
|
+
if (reasoningUnsupported !== null) {
|
|
210
|
+
clearTimeout(timeoutId);
|
|
211
|
+
return fail(reasoningUnsupported.cls, `reasoning control declared on the non-thinking Gemini model "${model}"`, reasoningUnsupported.fixHint);
|
|
212
|
+
}
|
|
159
213
|
try {
|
|
160
214
|
const shaped = buildGeminiRequest(model, req);
|
|
161
215
|
const dispatchedAt = Date.now();
|
|
@@ -176,9 +230,26 @@ function createGeminiAdapter(config) {
|
|
|
176
230
|
const tokensOut = (usageMetadata.candidatesTokenCount ?? 0) + (usageMetadata.thoughtsTokenCount ?? 0);
|
|
177
231
|
const tokensCached = usageMetadata.cachedContentTokenCount ?? 0;
|
|
178
232
|
const usage = { tokensIn, tokensOut, tokensCached, servedTier, ttfbMs };
|
|
179
|
-
const candidates = response
|
|
180
|
-
.candidates;
|
|
233
|
+
const candidates = response.candidates;
|
|
181
234
|
const finishReason = candidates?.[0]?.finishReason;
|
|
235
|
+
// Tool-call turn (spec §4.4): collect functionCall parts. When present,
|
|
236
|
+
// surface normalized calls and skip the text/empty/truncation guards.
|
|
237
|
+
// Read any accompanying text from the parts (not the `response.text`
|
|
238
|
+
// getter, which can throw/warn on a functionCall-only response).
|
|
239
|
+
if (req.tools !== undefined && req.tools.length > 0) {
|
|
240
|
+
const parts = candidates?.[0]?.content?.parts ?? [];
|
|
241
|
+
const fnCalls = parts
|
|
242
|
+
.map((p) => p.functionCall)
|
|
243
|
+
.filter((fc) => fc !== undefined && fc !== null);
|
|
244
|
+
const toolCalls = (0, tool_mapping_1.geminiFunctionCallsToToolCalls)(fnCalls);
|
|
245
|
+
if (toolCalls !== undefined) {
|
|
246
|
+
const toolText = parts
|
|
247
|
+
.map((p) => p.text)
|
|
248
|
+
.filter((t) => typeof t === "string")
|
|
249
|
+
.join("");
|
|
250
|
+
return { ok: true, text: toolText, usage, toolCalls };
|
|
251
|
+
}
|
|
252
|
+
}
|
|
182
253
|
if (finishReason === "SAFETY" || finishReason === "PROHIBITED_CONTENT") {
|
|
183
254
|
return fail("refusal", `Gemini blocked output via safety filter (finishReason=${finishReason})`, undefined, usage);
|
|
184
255
|
}
|
package/dist/adapters/grok.d.ts
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import type { CapabilityFlag, ProviderAdapter } from "../types/provider";
|
|
14
14
|
import type { ClassifiedFailure, ShapingInput } from "./gemini";
|
|
15
|
+
import type { OpenAIWireTool, OpenAIWireToolChoice } from "./tool-mapping";
|
|
15
16
|
export interface GrokAdapterConfig {
|
|
16
17
|
readonly apiKey: string;
|
|
17
18
|
}
|
|
@@ -29,6 +30,12 @@ export interface GrokShapedParams {
|
|
|
29
30
|
readonly stream_options: {
|
|
30
31
|
readonly include_usage: true;
|
|
31
32
|
};
|
|
33
|
+
/** CE-6 declared sampling — present only when the route/raw asks for them. */
|
|
34
|
+
readonly temperature?: number;
|
|
35
|
+
readonly top_p?: number;
|
|
36
|
+
/** Prompt-cache routing hint (WS-C) — the stable-prefix fingerprint the run
|
|
37
|
+
* loop stamps; xAI keeps a warm cache keyed to it (writes free today). */
|
|
38
|
+
readonly prompt_cache_key?: string;
|
|
32
39
|
readonly response_format?: {
|
|
33
40
|
readonly type: "json_schema";
|
|
34
41
|
readonly json_schema: {
|
|
@@ -37,6 +44,8 @@ export interface GrokShapedParams {
|
|
|
37
44
|
readonly strict: true;
|
|
38
45
|
};
|
|
39
46
|
};
|
|
47
|
+
readonly tools?: readonly OpenAIWireTool[];
|
|
48
|
+
readonly tool_choice?: OpenAIWireToolChoice;
|
|
40
49
|
}
|
|
41
50
|
export declare function buildGrokParams(model: string, req: ShapingInput): GrokShapedParams;
|
|
42
51
|
export declare function createGrokAdapter(config: GrokAdapterConfig): ProviderAdapter;
|
|
@@ -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;
|
|
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;AAMhG,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,CAsBtE;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,QAAQ,CAAC,eAAe,CAAC,EAAE;QACzB,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;IACF,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,CAsClF;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,iBAAiB,GAAG,eAAe,CAgK5E"}
|