modelrig 0.4.0 → 0.6.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 +238 -0
- package/README.md +65 -3
- package/dist/adapters/anthropic.d.ts.map +1 -1
- package/dist/adapters/anthropic.js +36 -7
- package/dist/adapters/attempt-meta-map.d.ts +63 -0
- package/dist/adapters/attempt-meta-map.d.ts.map +1 -0
- package/dist/adapters/attempt-meta-map.js +154 -0
- package/dist/adapters/deepseek.d.ts.map +1 -1
- package/dist/adapters/deepseek.js +25 -2
- package/dist/adapters/gemini.d.ts +39 -0
- package/dist/adapters/gemini.d.ts.map +1 -1
- package/dist/adapters/gemini.js +82 -4
- package/dist/adapters/grok.d.ts.map +1 -1
- package/dist/adapters/grok.js +25 -2
- package/dist/adapters/openai-compat.d.ts.map +1 -1
- package/dist/adapters/openai-compat.js +25 -2
- package/dist/adapters/openai-stream.d.ts +2 -0
- package/dist/adapters/openai-stream.d.ts.map +1 -1
- package/dist/adapters/openai-stream.js +23 -3
- package/dist/adapters/openai.d.ts.map +1 -1
- package/dist/adapters/openai.js +36 -6
- package/dist/artifacts/artifact.d.ts +3 -2
- package/dist/artifacts/artifact.d.ts.map +1 -1
- package/dist/artifacts/artifact.js +35 -9
- package/dist/artifacts/classification.d.ts +27 -0
- package/dist/artifacts/classification.d.ts.map +1 -0
- package/dist/artifacts/classification.js +38 -0
- package/dist/artifacts/index.d.ts +3 -1
- package/dist/artifacts/index.d.ts.map +1 -1
- package/dist/artifacts/index.js +10 -1
- package/dist/artifacts/run-context.d.ts +33 -2
- package/dist/artifacts/run-context.d.ts.map +1 -1
- package/dist/artifacts/run-context.js +95 -1
- package/dist/artifacts/scrub.d.ts +26 -0
- package/dist/artifacts/scrub.d.ts.map +1 -1
- package/dist/artifacts/scrub.js +53 -0
- package/dist/artifacts/step.d.ts +9 -0
- package/dist/artifacts/step.d.ts.map +1 -1
- package/dist/artifacts/step.js +9 -0
- package/dist/bakeoff/engine.d.ts +46 -4
- package/dist/bakeoff/engine.d.ts.map +1 -1
- package/dist/bakeoff/engine.js +269 -19
- package/dist/bakeoff/eval-cases.d.ts +5 -0
- package/dist/bakeoff/eval-cases.d.ts.map +1 -1
- package/dist/bakeoff/eval-cases.js +3 -0
- package/dist/bakeoff/judge.d.ts +39 -0
- package/dist/bakeoff/judge.d.ts.map +1 -0
- package/dist/bakeoff/judge.js +102 -0
- package/dist/bakeoff/quality.d.ts +44 -0
- package/dist/bakeoff/quality.d.ts.map +1 -0
- package/dist/bakeoff/quality.js +126 -0
- package/dist/bakeoff/reference.d.ts +34 -0
- package/dist/bakeoff/reference.d.ts.map +1 -0
- package/dist/bakeoff/reference.js +68 -0
- package/dist/bakeoff/replay.d.ts +25 -0
- package/dist/bakeoff/replay.d.ts.map +1 -1
- package/dist/bakeoff/replay.js +65 -2
- package/dist/bakeoff/report.d.ts +8 -1
- package/dist/bakeoff/report.d.ts.map +1 -1
- package/dist/bakeoff/report.js +83 -12
- package/dist/bakeoff/samples.d.ts +35 -2
- package/dist/bakeoff/samples.d.ts.map +1 -1
- package/dist/bakeoff/samples.js +67 -6
- package/dist/bakeoff/stats.d.ts +17 -1
- package/dist/bakeoff/stats.d.ts.map +1 -1
- package/dist/bakeoff/stats.js +67 -0
- package/dist/bakeoff/types.d.ts +76 -5
- package/dist/bakeoff/types.d.ts.map +1 -1
- package/dist/bakeoff/types.js +4 -3
- package/dist/cli-query.d.ts +14 -0
- package/dist/cli-query.d.ts.map +1 -0
- package/dist/cli-query.js +59 -0
- package/dist/cli.d.ts +2 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +47 -24
- package/dist/config.d.ts +6 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +14 -0
- package/dist/detect/detector.d.ts +82 -0
- package/dist/detect/detector.d.ts.map +1 -0
- package/dist/detect/detector.js +23 -0
- package/dist/index.d.ts +34 -23
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +49 -12
- package/dist/query/analytics.d.ts +84 -0
- package/dist/query/analytics.d.ts.map +1 -0
- package/dist/query/analytics.js +280 -0
- package/dist/query/columns.d.ts +59 -0
- package/dist/query/columns.d.ts.map +1 -0
- package/dist/query/columns.js +89 -0
- package/dist/query/grammar.d.ts +74 -7
- package/dist/query/grammar.d.ts.map +1 -1
- package/dist/query/grammar.js +179 -71
- package/dist/query/saved.d.ts +26 -0
- package/dist/query/saved.d.ts.map +1 -0
- package/dist/query/saved.js +51 -0
- 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 +54 -31
- package/dist/routes/objective-loader.d.ts +35 -0
- package/dist/routes/objective-loader.d.ts.map +1 -0
- package/dist/routes/objective-loader.js +286 -0
- package/dist/run/accept.d.ts +43 -0
- package/dist/run/accept.d.ts.map +1 -0
- package/dist/run/accept.js +65 -0
- package/dist/run/cost.d.ts +13 -0
- package/dist/run/cost.d.ts.map +1 -1
- package/dist/run/cost.js +27 -0
- package/dist/run/dispatch.d.ts +24 -1
- package/dist/run/dispatch.d.ts.map +1 -1
- package/dist/run/dispatch.js +19 -0
- package/dist/run/ladder-key.d.ts +4 -0
- package/dist/run/ladder-key.d.ts.map +1 -1
- package/dist/run/ladder-key.js +3 -0
- package/dist/run/quality-gate.d.ts +39 -0
- package/dist/run/quality-gate.d.ts.map +1 -0
- package/dist/run/quality-gate.js +70 -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.d.ts +12 -0
- package/dist/run/raw.d.ts.map +1 -1
- package/dist/run/raw.js +107 -8
- package/dist/run/record-attempt.d.ts.map +1 -1
- package/dist/run/record-attempt.js +22 -1
- package/dist/run/resolve.d.ts +17 -1
- package/dist/run/resolve.d.ts.map +1 -1
- package/dist/run/resolve.js +20 -4
- package/dist/run/routing-docs.d.ts.map +1 -1
- package/dist/run/routing-docs.js +12 -5
- package/dist/run/run.d.ts +7 -1
- package/dist/run/run.d.ts.map +1 -1
- package/dist/run/run.js +54 -69
- 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/settings/index.d.ts +1 -1
- package/dist/settings/index.d.ts.map +1 -1
- package/dist/settings/index.js +2 -1
- package/dist/settings/task-settings.d.ts +10 -0
- package/dist/settings/task-settings.d.ts.map +1 -1
- package/dist/settings/task-settings.js +17 -0
- package/dist/telemetry/attempt-meta.d.ts +178 -0
- package/dist/telemetry/attempt-meta.d.ts.map +1 -0
- package/dist/telemetry/attempt-meta.js +319 -0
- package/dist/telemetry/exporter.d.ts.map +1 -1
- package/dist/telemetry/exporter.js +6 -0
- package/dist/telemetry/ingest-protocol.d.ts +11 -0
- package/dist/telemetry/ingest-protocol.d.ts.map +1 -1
- package/dist/telemetry/ingest-protocol.js +3 -0
- package/dist/telemetry/otel-map.d.ts +10 -0
- package/dist/telemetry/otel-map.d.ts.map +1 -1
- package/dist/telemetry/otel-map.js +64 -0
- package/dist/telemetry/store-migrations.d.ts.map +1 -1
- package/dist/telemetry/store-migrations.js +15 -0
- package/dist/telemetry/store.d.ts.map +1 -1
- package/dist/telemetry/store.js +25 -7
- package/dist/types/failures-teaching.d.ts.map +1 -1
- package/dist/types/failures-teaching.js +20 -0
- package/dist/types/failures.d.ts +1 -1
- package/dist/types/failures.d.ts.map +1 -1
- package/dist/types/failures.js +1 -0
- package/dist/types/provider.d.ts +9 -0
- package/dist/types/provider.d.ts.map +1 -1
- package/dist/types/quality.d.ts +41 -0
- package/dist/types/quality.d.ts.map +1 -0
- package/dist/types/quality.js +12 -0
- package/dist/types/route.d.ts +120 -0
- package/dist/types/route.d.ts.map +1 -1
- package/dist/types/telemetry.d.ts +13 -0
- package/dist/types/telemetry.d.ts.map +1 -1
- package/dist/validate-cli.d.ts.map +1 -1
- package/dist/validate-cli.js +10 -0
- 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
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Per-adapter NATIVE metadata mapping (WI-1, spec §2). ONE place that turns a
|
|
4
|
+
* provider's native finish/refusal/usage/id signals into the additive
|
|
5
|
+
* `AdapterResult.meta` (`Partial<AttemptMetaV1>`). Adapters map ONLY what the
|
|
6
|
+
* provider reports; the producer (`telemetry/attempt-meta.ts`) adds
|
|
7
|
+
* hashes/sizes/cost and enforces the classification rule. Absent = unknown;
|
|
8
|
+
* nothing here is inferred.
|
|
9
|
+
*
|
|
10
|
+
* `refusal` derivation, per adapter:
|
|
11
|
+
* - openai / grok / deepseek / deepinfra / fireworks (OpenAI dialect): the
|
|
12
|
+
* stream carried a non-empty `choices[].delta.refusal` string, OR
|
|
13
|
+
* `finish_reason === "content_filter"`.
|
|
14
|
+
* - anthropic: `stop_reason === "refusal"`.
|
|
15
|
+
* - gemini: `finishReason` is `SAFETY` / `PROHIBITED_CONTENT` / `RECITATION`.
|
|
16
|
+
* The refusal TEXT itself is never carried (content) — only the boolean.
|
|
17
|
+
*/
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.mapFinishReason = mapFinishReason;
|
|
20
|
+
exports.samplingEcho = samplingEcho;
|
|
21
|
+
exports.aggregateToolCalls = aggregateToolCalls;
|
|
22
|
+
exports.buildAdapterMeta = buildAdapterMeta;
|
|
23
|
+
exports.transportErrorMeta = transportErrorMeta;
|
|
24
|
+
/** Map a provider's native finish/stop reason to the `FinishReason` enum
|
|
25
|
+
* (spec §2). Unknown/absent ⇒ undefined (never inferred); an unrecognised
|
|
26
|
+
* non-empty value ⇒ `"other"`. */
|
|
27
|
+
function mapFinishReason(provider, raw) {
|
|
28
|
+
if (raw === null || raw === undefined || raw === "")
|
|
29
|
+
return undefined;
|
|
30
|
+
if (provider === "anthropic") {
|
|
31
|
+
switch (raw) {
|
|
32
|
+
case "end_turn":
|
|
33
|
+
case "stop_sequence":
|
|
34
|
+
return "stop";
|
|
35
|
+
case "max_tokens":
|
|
36
|
+
return "length";
|
|
37
|
+
case "tool_use":
|
|
38
|
+
return "tool_calls";
|
|
39
|
+
case "refusal":
|
|
40
|
+
return "refusal";
|
|
41
|
+
default:
|
|
42
|
+
return "other";
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (provider === "gemini") {
|
|
46
|
+
switch (raw) {
|
|
47
|
+
case "STOP":
|
|
48
|
+
return "stop";
|
|
49
|
+
case "MAX_TOKENS":
|
|
50
|
+
return "length";
|
|
51
|
+
case "SAFETY":
|
|
52
|
+
case "PROHIBITED_CONTENT":
|
|
53
|
+
case "RECITATION":
|
|
54
|
+
return "content_filter";
|
|
55
|
+
default:
|
|
56
|
+
return "other";
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// OpenAI dialect (openai / grok / deepseek / deepinfra / fireworks).
|
|
60
|
+
switch (raw) {
|
|
61
|
+
case "stop":
|
|
62
|
+
return "stop";
|
|
63
|
+
case "length":
|
|
64
|
+
return "length";
|
|
65
|
+
case "tool_calls":
|
|
66
|
+
case "function_call":
|
|
67
|
+
return "tool_calls";
|
|
68
|
+
case "content_filter":
|
|
69
|
+
return "content_filter";
|
|
70
|
+
default:
|
|
71
|
+
return "other";
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/** The declared sampling echo (spec §2 `sampling`) — the values ModelRig sent,
|
|
75
|
+
* read back from the request. topP → top_p, maxOutputTokens → max_output_tokens
|
|
76
|
+
* (the raw lane's top-level or the routed lane's `sampling` block). Numbers
|
|
77
|
+
* only; undefined when the caller declared none. */
|
|
78
|
+
function samplingEcho(req) {
|
|
79
|
+
const s = {};
|
|
80
|
+
if (typeof req.sampling?.temperature === "number")
|
|
81
|
+
s.temperature = req.sampling.temperature;
|
|
82
|
+
if (typeof req.sampling?.topP === "number")
|
|
83
|
+
s.top_p = req.sampling.topP;
|
|
84
|
+
const maxOut = req.sampling?.maxOutputTokens ?? req.maxOutputTokens;
|
|
85
|
+
if (typeof maxOut === "number")
|
|
86
|
+
s.max_output_tokens = maxOut;
|
|
87
|
+
return Object.keys(s).length > 0 ? s : undefined;
|
|
88
|
+
}
|
|
89
|
+
/** Aggregate normalized tool calls into `{ name, count }` (RAW names — the
|
|
90
|
+
* producer hashes undeclared ones). Undefined when the turn made none. */
|
|
91
|
+
function aggregateToolCalls(toolCalls) {
|
|
92
|
+
if (toolCalls === undefined || toolCalls.length === 0)
|
|
93
|
+
return undefined;
|
|
94
|
+
const counts = new Map();
|
|
95
|
+
for (const tc of toolCalls) {
|
|
96
|
+
const name = tc.function.name;
|
|
97
|
+
counts.set(name, (counts.get(name) ?? 0) + 1);
|
|
98
|
+
}
|
|
99
|
+
return [...counts.entries()].map(([name, count]) => ({ name, count }));
|
|
100
|
+
}
|
|
101
|
+
/** Build one adapter's NATIVE `meta` (spec §2). Only defined signals appear —
|
|
102
|
+
* everything else is unknown and omitted. The producer takes it from here. */
|
|
103
|
+
function buildAdapterMeta(provider, s) {
|
|
104
|
+
const meta = {};
|
|
105
|
+
const finish = mapFinishReason(provider, s.finishReasonRaw);
|
|
106
|
+
if (finish !== undefined)
|
|
107
|
+
meta.finish_reason = finish;
|
|
108
|
+
if (typeof s.refusal === "boolean")
|
|
109
|
+
meta.refusal = s.refusal;
|
|
110
|
+
if (typeof s.reasoningTokens === "number" && s.reasoningTokens > 0) {
|
|
111
|
+
meta.reasoning_tokens = s.reasoningTokens;
|
|
112
|
+
}
|
|
113
|
+
if (typeof s.modelSnapshot === "string" && s.modelSnapshot !== "")
|
|
114
|
+
meta.model_snapshot = s.modelSnapshot;
|
|
115
|
+
if (typeof s.providerRequestId === "string" && s.providerRequestId !== "") {
|
|
116
|
+
meta.provider_request_id = s.providerRequestId;
|
|
117
|
+
}
|
|
118
|
+
if (typeof s.region === "string" && s.region !== "")
|
|
119
|
+
meta.region = s.region;
|
|
120
|
+
const sampling = samplingEcho(s.req);
|
|
121
|
+
if (sampling !== undefined)
|
|
122
|
+
meta.sampling = sampling;
|
|
123
|
+
const tools = aggregateToolCalls(s.toolCalls);
|
|
124
|
+
if (tools !== undefined)
|
|
125
|
+
meta.tool_calls = tools;
|
|
126
|
+
if (s.grounding !== undefined) {
|
|
127
|
+
const g = {};
|
|
128
|
+
if (typeof s.grounding.citations === "number")
|
|
129
|
+
g.citations = s.grounding.citations;
|
|
130
|
+
if (typeof s.grounding.searchProvider === "string")
|
|
131
|
+
g.search_provider = s.grounding.searchProvider;
|
|
132
|
+
if (Object.keys(g).length > 0)
|
|
133
|
+
meta.grounding = g;
|
|
134
|
+
}
|
|
135
|
+
if (typeof s.streaming === "boolean")
|
|
136
|
+
meta.streaming = s.streaming;
|
|
137
|
+
return meta;
|
|
138
|
+
}
|
|
139
|
+
/** A transport/SDK error's coarse envelope (spec §2 `http_status`/`error_code`).
|
|
140
|
+
* Reads `error.status` (number) and a short `error.code` / `error.error.code`
|
|
141
|
+
* slug — NEVER the message (that is free text). The producer's classification
|
|
142
|
+
* rule drops a code that turns out to be free text. */
|
|
143
|
+
function transportErrorMeta(error) {
|
|
144
|
+
const meta = {};
|
|
145
|
+
if (typeof error === "object" && error !== null) {
|
|
146
|
+
const e = error;
|
|
147
|
+
if (typeof e.status === "number" && Number.isFinite(e.status))
|
|
148
|
+
meta.http_status = e.status;
|
|
149
|
+
const code = typeof e.code === "string" ? e.code : e.error?.code;
|
|
150
|
+
if (typeof code === "string" && code !== "")
|
|
151
|
+
meta.error_code = code;
|
|
152
|
+
}
|
|
153
|
+
return meta;
|
|
154
|
+
}
|
|
@@ -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;
|
|
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;AAQhG,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,CAoLpF"}
|
|
@@ -24,6 +24,7 @@ exports.createDeepSeekAdapter = createDeepSeekAdapter;
|
|
|
24
24
|
const openai_1 = __importDefault(require("openai"));
|
|
25
25
|
const tool_mapping_1 = require("./tool-mapping");
|
|
26
26
|
const openai_stream_1 = require("./openai-stream");
|
|
27
|
+
const attempt_meta_map_1 = require("./attempt-meta-map");
|
|
27
28
|
const sampling_1 = require("./sampling");
|
|
28
29
|
const DEEPSEEK_BASE_URL = "https://api.deepseek.com";
|
|
29
30
|
const DEFAULT_MAX_TOKENS = 64000; // R1/V3 max — full capacity for long reports (ported)
|
|
@@ -102,6 +103,8 @@ function createDeepSeekAdapter(config) {
|
|
|
102
103
|
supportsTools: () => true,
|
|
103
104
|
async call(req) {
|
|
104
105
|
const model = req.candidate.model;
|
|
106
|
+
// WI-1: native attempt envelope for this call (see openai.ts for the pattern).
|
|
107
|
+
let attemptMeta;
|
|
105
108
|
// F1: post-stream failures still billed tokens — attach usage.
|
|
106
109
|
const fail = (cls, message, fixHint, usage) => ({
|
|
107
110
|
ok: false,
|
|
@@ -113,6 +116,7 @@ function createDeepSeekAdapter(config) {
|
|
|
113
116
|
...(fixHint !== undefined ? { fixHint } : {}),
|
|
114
117
|
},
|
|
115
118
|
...(usage !== undefined ? { usage } : {}),
|
|
119
|
+
...(attemptMeta !== undefined ? { meta: attemptMeta } : {}),
|
|
116
120
|
});
|
|
117
121
|
try {
|
|
118
122
|
const client = new openai_1.default({
|
|
@@ -130,12 +134,18 @@ function createDeepSeekAdapter(config) {
|
|
|
130
134
|
let finishReason = null;
|
|
131
135
|
// TTFB (Phase 4 WS3): first streamed chunk = first body byte.
|
|
132
136
|
let ttfbMs;
|
|
137
|
+
let responseModel = "";
|
|
138
|
+
let responseId = "";
|
|
133
139
|
const toolCallAcc = (0, tool_mapping_1.createOpenAIToolCallAccumulator)();
|
|
134
140
|
// Only delta.content is accumulated — a reasoner's reasoning_content
|
|
135
141
|
// (chain-of-thought) must never leak into the JSON buffer (ported).
|
|
136
142
|
for await (const chunk of stream) {
|
|
137
143
|
if (ttfbMs === undefined)
|
|
138
144
|
ttfbMs = Date.now() - dispatchedAt;
|
|
145
|
+
if (responseModel === "" && typeof chunk.model === "string")
|
|
146
|
+
responseModel = chunk.model;
|
|
147
|
+
if (responseId === "" && typeof chunk.id === "string")
|
|
148
|
+
responseId = chunk.id;
|
|
139
149
|
const choice = chunk.choices[0];
|
|
140
150
|
if (choice?.delta?.content)
|
|
141
151
|
text += choice.delta.content;
|
|
@@ -159,8 +169,19 @@ function createDeepSeekAdapter(config) {
|
|
|
159
169
|
};
|
|
160
170
|
// Tool-call turn (spec §4.4): surface normalized calls, skip content guards.
|
|
161
171
|
const toolCalls = toolCallAcc.finalize();
|
|
172
|
+
// WI-1: native attempt envelope. DeepSeek has no `refusal` delta — a
|
|
173
|
+
// refusal surfaces as finish_reason content_filter.
|
|
174
|
+
attemptMeta = (0, attempt_meta_map_1.buildAdapterMeta)("deepseek", {
|
|
175
|
+
req,
|
|
176
|
+
finishReasonRaw: finishReason,
|
|
177
|
+
refusal: finishReason === "content_filter",
|
|
178
|
+
modelSnapshot: responseModel,
|
|
179
|
+
providerRequestId: responseId,
|
|
180
|
+
toolCalls,
|
|
181
|
+
streaming: false,
|
|
182
|
+
});
|
|
162
183
|
if (toolCalls !== undefined) {
|
|
163
|
-
return { ok: true, text, usage, toolCalls };
|
|
184
|
+
return { ok: true, text, usage, toolCalls, meta: attemptMeta };
|
|
164
185
|
}
|
|
165
186
|
if (text.trim().length === 0) {
|
|
166
187
|
return fail("content_invalid", `empty response from DeepSeek (finish_reason=${finishReason ?? "none"})`, undefined, usage);
|
|
@@ -168,11 +189,12 @@ function createDeepSeekAdapter(config) {
|
|
|
168
189
|
if (finishReason === "length" && req.outputSchema !== null) {
|
|
169
190
|
return fail("content_invalid", "DeepSeek JSON output truncated (finish_reason=length)", "raise maxOutputTokens for this route", usage);
|
|
170
191
|
}
|
|
171
|
-
return { ok: true, text, usage };
|
|
192
|
+
return { ok: true, text, usage, meta: attemptMeta };
|
|
172
193
|
}
|
|
173
194
|
catch (error) {
|
|
174
195
|
const message = error instanceof Error ? error.message : String(error);
|
|
175
196
|
const { cls, fixHint } = classifyDeepSeekFailure(message);
|
|
197
|
+
attemptMeta = (0, attempt_meta_map_1.transportErrorMeta)(error);
|
|
176
198
|
return {
|
|
177
199
|
ok: false,
|
|
178
200
|
failure: {
|
|
@@ -183,6 +205,7 @@ function createDeepSeekAdapter(config) {
|
|
|
183
205
|
cause: error,
|
|
184
206
|
...(fixHint !== undefined ? { fixHint } : {}),
|
|
185
207
|
},
|
|
208
|
+
meta: attemptMeta,
|
|
186
209
|
};
|
|
187
210
|
}
|
|
188
211
|
},
|
|
@@ -56,5 +56,44 @@ export interface GeminiShapedRequest {
|
|
|
56
56
|
}
|
|
57
57
|
/** Pure request shaping — everything except the abort signal. */
|
|
58
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;
|
|
59
97
|
export declare function createGeminiAdapter(config: GeminiAdapterConfig): ProviderAdapter;
|
|
98
|
+
export {};
|
|
60
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;
|
|
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;AAQlE,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,CA4MhF"}
|
package/dist/adapters/gemini.js
CHANGED
|
@@ -20,9 +20,13 @@ exports.geminiSupports = geminiSupports;
|
|
|
20
20
|
exports.classifyGeminiFailure = classifyGeminiFailure;
|
|
21
21
|
exports.geminiReasoningUnsupported = geminiReasoningUnsupported;
|
|
22
22
|
exports.buildGeminiRequest = buildGeminiRequest;
|
|
23
|
+
exports.extractGeminiCandidateText = extractGeminiCandidateText;
|
|
24
|
+
exports.geminiCandidateHasFunctionCall = geminiCandidateHasFunctionCall;
|
|
25
|
+
exports.resolveGeminiText = resolveGeminiText;
|
|
23
26
|
exports.createGeminiAdapter = createGeminiAdapter;
|
|
24
27
|
const genai_1 = require("@google/genai");
|
|
25
28
|
const tool_mapping_1 = require("./tool-mapping");
|
|
29
|
+
const attempt_meta_map_1 = require("./attempt-meta-map");
|
|
26
30
|
const sampling_1 = require("./sampling");
|
|
27
31
|
/** Models that accept thinkingConfig — passing it to 2.x models 400s.
|
|
28
32
|
* Ported from the production THINKING_CAPABLE_MODELS set. EXPORTED (CE-9 R6) so
|
|
@@ -190,6 +194,43 @@ function extractServedTier(rawServiceTier, trafficType, requested) {
|
|
|
190
194
|
return "priority";
|
|
191
195
|
return requested;
|
|
192
196
|
}
|
|
197
|
+
/**
|
|
198
|
+
* #245 secondary — concatenate the answer `text` parts of a Gemini candidate's
|
|
199
|
+
* content. On the raw / no-tools lane a grounding-originated `functionCall` part
|
|
200
|
+
* (googleSearch) is NOT a tool-call turn, and the SDK's `response.text` getter
|
|
201
|
+
* returns empty (and logs a warning) on a response that mixes `functionCall` +
|
|
202
|
+
* `text` parts — so read the text parts directly. `thought`-flagged parts are
|
|
203
|
+
* skipped to match `response.text` semantics (they are the reasoning summary, not
|
|
204
|
+
* the answer). Pure + exported for the fixture regression test (no network).
|
|
205
|
+
* (spec §2 Secondary — the SNPS bug.)
|
|
206
|
+
*/
|
|
207
|
+
function extractGeminiCandidateText(candidate) {
|
|
208
|
+
return (candidate?.content?.parts ?? [])
|
|
209
|
+
.filter((p) => p.thought !== true)
|
|
210
|
+
.map((p) => p.text)
|
|
211
|
+
.filter((t) => typeof t === "string")
|
|
212
|
+
.join("");
|
|
213
|
+
}
|
|
214
|
+
/** #245 secondary — whether a candidate carries a `functionCall` part. On the
|
|
215
|
+
* no-tools lane this means grounding produced only a googleSearch invocation with
|
|
216
|
+
* no text answer, which the empty-response `fixHint` should name. */
|
|
217
|
+
function geminiCandidateHasFunctionCall(candidate) {
|
|
218
|
+
return (candidate?.content?.parts ?? []).some((p) => p.functionCall !== undefined && p.functionCall !== null);
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* #245 secondary — pick the answer text from a Gemini response. The branch the
|
|
222
|
+
* `call()` path uses, extracted pure so it is unit-testable without a network:
|
|
223
|
+
* - tools declared: trust the SDK `response.text` getter, byte-identical to
|
|
224
|
+
* pre-#245 (a functionCall turn is handled earlier as a tool-call).
|
|
225
|
+
* - no tools declared: read the candidate's text parts directly, because
|
|
226
|
+
* `response.text` returns empty on a grounding-originated functionCall+text
|
|
227
|
+
* response; fall back to `response.text` only if there is no text part.
|
|
228
|
+
*/
|
|
229
|
+
function resolveGeminiText(candidate, responseText, hasTools) {
|
|
230
|
+
if (hasTools)
|
|
231
|
+
return responseText ?? "";
|
|
232
|
+
return extractGeminiCandidateText(candidate) || (responseText ?? "");
|
|
233
|
+
}
|
|
193
234
|
function createGeminiAdapter(config) {
|
|
194
235
|
const ai = new genai_1.GoogleGenAI({ apiKey: config.apiKey });
|
|
195
236
|
return {
|
|
@@ -200,6 +241,8 @@ function createGeminiAdapter(config) {
|
|
|
200
241
|
const model = req.candidate.model;
|
|
201
242
|
const abortController = new AbortController();
|
|
202
243
|
const timeoutId = setTimeout(() => abortController.abort(), req.timeoutMs);
|
|
244
|
+
// WI-1: native attempt envelope for this call (see openai.ts for the pattern).
|
|
245
|
+
let attemptMeta;
|
|
203
246
|
// F1: post-response failures (refusal/empty/truncation) still billed
|
|
204
247
|
// tokens — they attach the response usage so the run loop accounts them.
|
|
205
248
|
const fail = (cls, message, fixHint, usage) => ({
|
|
@@ -212,6 +255,7 @@ function createGeminiAdapter(config) {
|
|
|
212
255
|
...(fixHint !== undefined ? { fixHint } : {}),
|
|
213
256
|
},
|
|
214
257
|
...(usage !== undefined ? { usage } : {}),
|
|
258
|
+
...(attemptMeta !== undefined ? { meta: attemptMeta } : {}),
|
|
215
259
|
});
|
|
216
260
|
// CE-2 F3: reject reasoning on a non-thinking model BEFORE any dispatch —
|
|
217
261
|
// classified, terminal, never a silent drop (spec §3 F3).
|
|
@@ -242,6 +286,24 @@ function createGeminiAdapter(config) {
|
|
|
242
286
|
const usage = { tokensIn, tokensOut, tokensCached, servedTier, ttfbMs };
|
|
243
287
|
const candidates = response.candidates;
|
|
244
288
|
const finishReason = candidates?.[0]?.finishReason;
|
|
289
|
+
// WI-1 native fields: provider-reported model snapshot + request id.
|
|
290
|
+
const respIds = response;
|
|
291
|
+
// WI-1: native attempt envelope. refusal derives from the safety/recitation
|
|
292
|
+
// finishReasons (mapFinishReason folds them to content_filter). grounding
|
|
293
|
+
// present when this route asked for native grounding (googleSearch).
|
|
294
|
+
const mkMeta = (toolCalls) => (0, attempt_meta_map_1.buildAdapterMeta)("gemini", {
|
|
295
|
+
req,
|
|
296
|
+
finishReasonRaw: finishReason,
|
|
297
|
+
refusal: finishReason === "SAFETY" ||
|
|
298
|
+
finishReason === "PROHIBITED_CONTENT" ||
|
|
299
|
+
finishReason === "RECITATION",
|
|
300
|
+
reasoningTokens: usageMetadata.thoughtsTokenCount,
|
|
301
|
+
modelSnapshot: respIds.modelVersion,
|
|
302
|
+
providerRequestId: respIds.responseId,
|
|
303
|
+
toolCalls,
|
|
304
|
+
grounding: req.grounding === true ? { searchProvider: "google" } : undefined,
|
|
305
|
+
streaming: false,
|
|
306
|
+
});
|
|
245
307
|
// Tool-call turn (spec §4.4): collect functionCall parts. When present,
|
|
246
308
|
// surface normalized calls and skip the text/empty/truncation guards.
|
|
247
309
|
// Read any accompanying text from the parts (not the `response.text`
|
|
@@ -257,27 +319,42 @@ function createGeminiAdapter(config) {
|
|
|
257
319
|
.map((p) => p.text)
|
|
258
320
|
.filter((t) => typeof t === "string")
|
|
259
321
|
.join("");
|
|
260
|
-
|
|
322
|
+
attemptMeta = mkMeta(toolCalls);
|
|
323
|
+
return { ok: true, text: toolText, usage, toolCalls, meta: attemptMeta };
|
|
261
324
|
}
|
|
262
325
|
}
|
|
326
|
+
// Non-tool paths share one envelope (refusal / empty / truncation / ok).
|
|
327
|
+
attemptMeta = mkMeta();
|
|
263
328
|
if (finishReason === "SAFETY" || finishReason === "PROHIBITED_CONTENT") {
|
|
264
329
|
return fail("refusal", `Gemini blocked output via safety filter (finishReason=${finishReason})`, undefined, usage);
|
|
265
330
|
}
|
|
266
331
|
if (finishReason === "RECITATION") {
|
|
267
332
|
return fail("refusal", "Gemini blocked output via recitation filter (finishReason=RECITATION)", undefined, usage);
|
|
268
333
|
}
|
|
269
|
-
|
|
334
|
+
// #245 secondary: when the caller declared NO tools, a `functionCall`
|
|
335
|
+
// part is grounding-originated (googleSearch), NOT a tool-call turn — and
|
|
336
|
+
// `response.text` returns empty on a mixed functionCall+text response, so
|
|
337
|
+
// read the text parts directly. When tools WERE declared this path is
|
|
338
|
+
// reached only for a no-functionCall response, so `response.text` is
|
|
339
|
+
// byte-identical to before.
|
|
340
|
+
const noTools = req.tools === undefined || req.tools.length === 0;
|
|
341
|
+
const text = resolveGeminiText(candidates?.[0], response.text, !noTools);
|
|
270
342
|
if (text.trim().length === 0) {
|
|
271
|
-
|
|
343
|
+
const groundedNoText = noTools &&
|
|
344
|
+
geminiCandidateHasFunctionCall(candidates?.[0]);
|
|
345
|
+
return fail("content_invalid", `empty response from Gemini (finishReason=${finishReason ?? "none"})`, groundedNoText
|
|
346
|
+
? "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"
|
|
347
|
+
: undefined, usage);
|
|
272
348
|
}
|
|
273
349
|
if (finishReason === "MAX_TOKENS" && req.outputSchema !== null) {
|
|
274
350
|
// A truncated structured emission is mid-object and unparseable.
|
|
275
351
|
return fail("content_invalid", "Gemini structured output truncated (finishReason=MAX_TOKENS)", "raise maxOutputTokens for this route or reduce thinking budget", usage);
|
|
276
352
|
}
|
|
277
|
-
return { ok: true, text, usage };
|
|
353
|
+
return { ok: true, text, usage, meta: attemptMeta };
|
|
278
354
|
}
|
|
279
355
|
catch (error) {
|
|
280
356
|
const message = error instanceof Error ? error.message : String(error);
|
|
357
|
+
attemptMeta = (0, attempt_meta_map_1.transportErrorMeta)(error);
|
|
281
358
|
// An abort we triggered is our timeout regardless of message text.
|
|
282
359
|
if (abortController.signal.aborted) {
|
|
283
360
|
return fail("timeout", `Gemini call exceeded timeoutMs=${req.timeoutMs}: ${message}`);
|
|
@@ -293,6 +370,7 @@ function createGeminiAdapter(config) {
|
|
|
293
370
|
cause: error,
|
|
294
371
|
...(fixHint !== undefined ? { fixHint } : {}),
|
|
295
372
|
},
|
|
373
|
+
meta: attemptMeta,
|
|
296
374
|
};
|
|
297
375
|
}
|
|
298
376
|
finally {
|
|
@@ -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;AAShG,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,CAsL5E"}
|
package/dist/adapters/grok.js
CHANGED
|
@@ -22,6 +22,7 @@ exports.createGrokAdapter = createGrokAdapter;
|
|
|
22
22
|
const openai_1 = __importDefault(require("openai"));
|
|
23
23
|
const tool_mapping_1 = require("./tool-mapping");
|
|
24
24
|
const openai_stream_1 = require("./openai-stream");
|
|
25
|
+
const attempt_meta_map_1 = require("./attempt-meta-map");
|
|
25
26
|
const sampling_1 = require("./sampling");
|
|
26
27
|
const raw_support_1 = require("../run/raw-support");
|
|
27
28
|
const GROK_BASE_URL = "https://api.x.ai/v1";
|
|
@@ -135,6 +136,8 @@ function createGrokAdapter(config) {
|
|
|
135
136
|
supportsTools: () => true,
|
|
136
137
|
async call(req) {
|
|
137
138
|
const model = req.candidate.model;
|
|
139
|
+
// WI-1: native attempt envelope for this call (see openai.ts for the pattern).
|
|
140
|
+
let attemptMeta;
|
|
138
141
|
// F1: post-stream failures still billed tokens — attach usage.
|
|
139
142
|
const fail = (cls, message, fixHint, usage) => ({
|
|
140
143
|
ok: false,
|
|
@@ -146,6 +149,7 @@ function createGrokAdapter(config) {
|
|
|
146
149
|
...(fixHint !== undefined ? { fixHint } : {}),
|
|
147
150
|
},
|
|
148
151
|
...(usage !== undefined ? { usage } : {}),
|
|
152
|
+
...(attemptMeta !== undefined ? { meta: attemptMeta } : {}),
|
|
149
153
|
});
|
|
150
154
|
try {
|
|
151
155
|
const client = new openai_1.default({
|
|
@@ -161,10 +165,16 @@ function createGrokAdapter(config) {
|
|
|
161
165
|
let cachedTokens = 0;
|
|
162
166
|
let cacheWriteTokens = 0;
|
|
163
167
|
let finishReason = null;
|
|
168
|
+
let responseModel = "";
|
|
169
|
+
let responseId = "";
|
|
164
170
|
const toolCallAcc = (0, tool_mapping_1.createOpenAIToolCallAccumulator)();
|
|
165
171
|
// Only delta.content is accumulated — a reasoning model's trace must
|
|
166
172
|
// never leak into the JSON buffer (deepseek reasoner rule applied).
|
|
167
173
|
for await (const chunk of stream) {
|
|
174
|
+
if (responseModel === "" && typeof chunk.model === "string")
|
|
175
|
+
responseModel = chunk.model;
|
|
176
|
+
if (responseId === "" && typeof chunk.id === "string")
|
|
177
|
+
responseId = chunk.id;
|
|
168
178
|
const choice = chunk.choices[0];
|
|
169
179
|
if (choice?.delta?.content)
|
|
170
180
|
text += choice.delta.content;
|
|
@@ -190,8 +200,19 @@ function createGrokAdapter(config) {
|
|
|
190
200
|
// Tool-call turn (spec §4.4): surface normalized calls, skip the
|
|
191
201
|
// empty/truncation content guards below.
|
|
192
202
|
const toolCalls = toolCallAcc.finalize();
|
|
203
|
+
// WI-1: native attempt envelope (no `refusal` delta on this dialect →
|
|
204
|
+
// refusal derives from finish_reason content_filter).
|
|
205
|
+
attemptMeta = (0, attempt_meta_map_1.buildAdapterMeta)("grok", {
|
|
206
|
+
req,
|
|
207
|
+
finishReasonRaw: finishReason,
|
|
208
|
+
refusal: finishReason === "content_filter",
|
|
209
|
+
modelSnapshot: responseModel,
|
|
210
|
+
providerRequestId: responseId,
|
|
211
|
+
toolCalls,
|
|
212
|
+
streaming: false,
|
|
213
|
+
});
|
|
193
214
|
if (toolCalls !== undefined) {
|
|
194
|
-
return { ok: true, text, usage, toolCalls };
|
|
215
|
+
return { ok: true, text, usage, toolCalls, meta: attemptMeta };
|
|
195
216
|
}
|
|
196
217
|
if (text.trim().length === 0) {
|
|
197
218
|
return fail("content_invalid", `empty response from Grok (finish_reason=${finishReason ?? "none"})`, undefined, usage);
|
|
@@ -199,11 +220,12 @@ function createGrokAdapter(config) {
|
|
|
199
220
|
if (finishReason === "length" && req.outputSchema !== null) {
|
|
200
221
|
return fail("content_invalid", "Grok structured output truncated (finish_reason=length)", "raise maxOutputTokens for this route", usage);
|
|
201
222
|
}
|
|
202
|
-
return { ok: true, text, usage };
|
|
223
|
+
return { ok: true, text, usage, meta: attemptMeta };
|
|
203
224
|
}
|
|
204
225
|
catch (error) {
|
|
205
226
|
const message = error instanceof Error ? error.message : String(error);
|
|
206
227
|
const { cls, fixHint } = classifyGrokFailure(message);
|
|
228
|
+
attemptMeta = (0, attempt_meta_map_1.transportErrorMeta)(error);
|
|
207
229
|
return {
|
|
208
230
|
ok: false,
|
|
209
231
|
failure: {
|
|
@@ -214,6 +236,7 @@ function createGrokAdapter(config) {
|
|
|
214
236
|
cause: error,
|
|
215
237
|
...(fixHint !== undefined ? { fixHint } : {}),
|
|
216
238
|
},
|
|
239
|
+
meta: attemptMeta,
|
|
217
240
|
};
|
|
218
241
|
}
|
|
219
242
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openai-compat.d.ts","sourceRoot":"","sources":["../../src/adapters/openai-compat.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,KAAK,EAIV,cAAc,EACd,eAAe,EACf,UAAU,EACX,MAAM,mBAAmB,CAAC;AAE3B,OAAO,KAAK,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAMhE,OAAO,KAAK,EAAuB,cAAc,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"openai-compat.d.ts","sourceRoot":"","sources":["../../src/adapters/openai-compat.ts"],"names":[],"mappings":"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"}
|
|
@@ -30,6 +30,7 @@ exports.createOpenAICompatAdapter = createOpenAICompatAdapter;
|
|
|
30
30
|
const openai_1 = __importDefault(require("openai"));
|
|
31
31
|
const tool_mapping_1 = require("./tool-mapping");
|
|
32
32
|
const openai_stream_1 = require("./openai-stream");
|
|
33
|
+
const attempt_meta_map_1 = require("./attempt-meta-map");
|
|
33
34
|
const sampling_1 = require("./sampling");
|
|
34
35
|
const DEFAULT_MAX_TOKENS = 32000;
|
|
35
36
|
/** Fireworks serves models at accounts/fireworks/models/<short> — routes
|
|
@@ -146,6 +147,8 @@ function createOpenAICompatAdapter(config) {
|
|
|
146
147
|
supportsTools: () => true,
|
|
147
148
|
async call(req) {
|
|
148
149
|
const model = req.candidate.model;
|
|
150
|
+
// WI-1: native attempt envelope for this call (see openai.ts for the pattern).
|
|
151
|
+
let attemptMeta;
|
|
149
152
|
const fail = (cls, message, fixHint, usage) => ({
|
|
150
153
|
ok: false,
|
|
151
154
|
failure: {
|
|
@@ -156,6 +159,7 @@ function createOpenAICompatAdapter(config) {
|
|
|
156
159
|
...(fixHint !== undefined ? { fixHint } : {}),
|
|
157
160
|
},
|
|
158
161
|
...(usage !== undefined ? { usage } : {}),
|
|
162
|
+
...(attemptMeta !== undefined ? { meta: attemptMeta } : {}),
|
|
159
163
|
});
|
|
160
164
|
try {
|
|
161
165
|
const client = new openai_1.default({
|
|
@@ -174,10 +178,16 @@ function createOpenAICompatAdapter(config) {
|
|
|
174
178
|
let finishReason = null;
|
|
175
179
|
// TTFB (Phase 4 WS3): first streamed chunk = first body byte.
|
|
176
180
|
let ttfbMs;
|
|
181
|
+
let responseModel = "";
|
|
182
|
+
let responseId = "";
|
|
177
183
|
const toolCallAcc = (0, tool_mapping_1.createOpenAIToolCallAccumulator)();
|
|
178
184
|
for await (const chunk of stream) {
|
|
179
185
|
if (ttfbMs === undefined)
|
|
180
186
|
ttfbMs = Date.now() - dispatchedAt;
|
|
187
|
+
if (responseModel === "" && typeof chunk.model === "string")
|
|
188
|
+
responseModel = chunk.model;
|
|
189
|
+
if (responseId === "" && typeof chunk.id === "string")
|
|
190
|
+
responseId = chunk.id;
|
|
181
191
|
const choice = chunk.choices[0];
|
|
182
192
|
if (choice?.delta?.content)
|
|
183
193
|
text += choice.delta.content;
|
|
@@ -203,8 +213,19 @@ function createOpenAICompatAdapter(config) {
|
|
|
203
213
|
};
|
|
204
214
|
// Tool-call turn (spec §4.4): surface normalized calls, skip content guards.
|
|
205
215
|
const toolCalls = toolCallAcc.finalize();
|
|
216
|
+
// WI-1: native attempt envelope (no `refusal` delta on this dialect →
|
|
217
|
+
// refusal derives from finish_reason content_filter).
|
|
218
|
+
attemptMeta = (0, attempt_meta_map_1.buildAdapterMeta)(config.providerId, {
|
|
219
|
+
req,
|
|
220
|
+
finishReasonRaw: finishReason,
|
|
221
|
+
refusal: finishReason === "content_filter",
|
|
222
|
+
modelSnapshot: responseModel,
|
|
223
|
+
providerRequestId: responseId,
|
|
224
|
+
toolCalls,
|
|
225
|
+
streaming: false,
|
|
226
|
+
});
|
|
206
227
|
if (toolCalls !== undefined) {
|
|
207
|
-
return { ok: true, text, usage, toolCalls };
|
|
228
|
+
return { ok: true, text, usage, toolCalls, meta: attemptMeta };
|
|
208
229
|
}
|
|
209
230
|
if (text.trim().length === 0) {
|
|
210
231
|
return fail("content_invalid", `empty response from ${config.providerId} (finish_reason=${finishReason ?? "none"})`, undefined, usage);
|
|
@@ -212,11 +233,12 @@ function createOpenAICompatAdapter(config) {
|
|
|
212
233
|
if (finishReason === "length" && req.outputSchema !== null) {
|
|
213
234
|
return fail("content_invalid", `${config.providerId} JSON output truncated (finish_reason=length)`, "raise maxOutputTokens for this route", usage);
|
|
214
235
|
}
|
|
215
|
-
return { ok: true, text, usage };
|
|
236
|
+
return { ok: true, text, usage, meta: attemptMeta };
|
|
216
237
|
}
|
|
217
238
|
catch (error) {
|
|
218
239
|
const message = error instanceof Error ? error.message : String(error);
|
|
219
240
|
const { cls, fixHint } = classifyCompatFailure(message, config.providerId);
|
|
241
|
+
attemptMeta = (0, attempt_meta_map_1.transportErrorMeta)(error);
|
|
220
242
|
return {
|
|
221
243
|
ok: false,
|
|
222
244
|
failure: {
|
|
@@ -227,6 +249,7 @@ function createOpenAICompatAdapter(config) {
|
|
|
227
249
|
cause: error,
|
|
228
250
|
...(fixHint !== undefined ? { fixHint } : {}),
|
|
229
251
|
},
|
|
252
|
+
meta: attemptMeta,
|
|
230
253
|
};
|
|
231
254
|
}
|
|
232
255
|
},
|