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.
Files changed (189) hide show
  1. package/CHANGELOG.md +238 -0
  2. package/README.md +65 -3
  3. package/dist/adapters/anthropic.d.ts.map +1 -1
  4. package/dist/adapters/anthropic.js +36 -7
  5. package/dist/adapters/attempt-meta-map.d.ts +63 -0
  6. package/dist/adapters/attempt-meta-map.d.ts.map +1 -0
  7. package/dist/adapters/attempt-meta-map.js +154 -0
  8. package/dist/adapters/deepseek.d.ts.map +1 -1
  9. package/dist/adapters/deepseek.js +25 -2
  10. package/dist/adapters/gemini.d.ts +39 -0
  11. package/dist/adapters/gemini.d.ts.map +1 -1
  12. package/dist/adapters/gemini.js +82 -4
  13. package/dist/adapters/grok.d.ts.map +1 -1
  14. package/dist/adapters/grok.js +25 -2
  15. package/dist/adapters/openai-compat.d.ts.map +1 -1
  16. package/dist/adapters/openai-compat.js +25 -2
  17. package/dist/adapters/openai-stream.d.ts +2 -0
  18. package/dist/adapters/openai-stream.d.ts.map +1 -1
  19. package/dist/adapters/openai-stream.js +23 -3
  20. package/dist/adapters/openai.d.ts.map +1 -1
  21. package/dist/adapters/openai.js +36 -6
  22. package/dist/artifacts/artifact.d.ts +3 -2
  23. package/dist/artifacts/artifact.d.ts.map +1 -1
  24. package/dist/artifacts/artifact.js +35 -9
  25. package/dist/artifacts/classification.d.ts +27 -0
  26. package/dist/artifacts/classification.d.ts.map +1 -0
  27. package/dist/artifacts/classification.js +38 -0
  28. package/dist/artifacts/index.d.ts +3 -1
  29. package/dist/artifacts/index.d.ts.map +1 -1
  30. package/dist/artifacts/index.js +10 -1
  31. package/dist/artifacts/run-context.d.ts +33 -2
  32. package/dist/artifacts/run-context.d.ts.map +1 -1
  33. package/dist/artifacts/run-context.js +95 -1
  34. package/dist/artifacts/scrub.d.ts +26 -0
  35. package/dist/artifacts/scrub.d.ts.map +1 -1
  36. package/dist/artifacts/scrub.js +53 -0
  37. package/dist/artifacts/step.d.ts +9 -0
  38. package/dist/artifacts/step.d.ts.map +1 -1
  39. package/dist/artifacts/step.js +9 -0
  40. package/dist/bakeoff/engine.d.ts +46 -4
  41. package/dist/bakeoff/engine.d.ts.map +1 -1
  42. package/dist/bakeoff/engine.js +269 -19
  43. package/dist/bakeoff/eval-cases.d.ts +5 -0
  44. package/dist/bakeoff/eval-cases.d.ts.map +1 -1
  45. package/dist/bakeoff/eval-cases.js +3 -0
  46. package/dist/bakeoff/judge.d.ts +39 -0
  47. package/dist/bakeoff/judge.d.ts.map +1 -0
  48. package/dist/bakeoff/judge.js +102 -0
  49. package/dist/bakeoff/quality.d.ts +44 -0
  50. package/dist/bakeoff/quality.d.ts.map +1 -0
  51. package/dist/bakeoff/quality.js +126 -0
  52. package/dist/bakeoff/reference.d.ts +34 -0
  53. package/dist/bakeoff/reference.d.ts.map +1 -0
  54. package/dist/bakeoff/reference.js +68 -0
  55. package/dist/bakeoff/replay.d.ts +25 -0
  56. package/dist/bakeoff/replay.d.ts.map +1 -1
  57. package/dist/bakeoff/replay.js +65 -2
  58. package/dist/bakeoff/report.d.ts +8 -1
  59. package/dist/bakeoff/report.d.ts.map +1 -1
  60. package/dist/bakeoff/report.js +83 -12
  61. package/dist/bakeoff/samples.d.ts +35 -2
  62. package/dist/bakeoff/samples.d.ts.map +1 -1
  63. package/dist/bakeoff/samples.js +67 -6
  64. package/dist/bakeoff/stats.d.ts +17 -1
  65. package/dist/bakeoff/stats.d.ts.map +1 -1
  66. package/dist/bakeoff/stats.js +67 -0
  67. package/dist/bakeoff/types.d.ts +76 -5
  68. package/dist/bakeoff/types.d.ts.map +1 -1
  69. package/dist/bakeoff/types.js +4 -3
  70. package/dist/cli-query.d.ts +14 -0
  71. package/dist/cli-query.d.ts.map +1 -0
  72. package/dist/cli-query.js +59 -0
  73. package/dist/cli.d.ts +2 -1
  74. package/dist/cli.d.ts.map +1 -1
  75. package/dist/cli.js +47 -24
  76. package/dist/config.d.ts +6 -0
  77. package/dist/config.d.ts.map +1 -1
  78. package/dist/config.js +14 -0
  79. package/dist/detect/detector.d.ts +82 -0
  80. package/dist/detect/detector.d.ts.map +1 -0
  81. package/dist/detect/detector.js +23 -0
  82. package/dist/index.d.ts +34 -23
  83. package/dist/index.d.ts.map +1 -1
  84. package/dist/index.js +49 -12
  85. package/dist/query/analytics.d.ts +84 -0
  86. package/dist/query/analytics.d.ts.map +1 -0
  87. package/dist/query/analytics.js +280 -0
  88. package/dist/query/columns.d.ts +59 -0
  89. package/dist/query/columns.d.ts.map +1 -0
  90. package/dist/query/columns.js +89 -0
  91. package/dist/query/grammar.d.ts +74 -7
  92. package/dist/query/grammar.d.ts.map +1 -1
  93. package/dist/query/grammar.js +179 -71
  94. package/dist/query/saved.d.ts +26 -0
  95. package/dist/query/saved.d.ts.map +1 -0
  96. package/dist/query/saved.js +51 -0
  97. package/dist/registry/select.d.ts +59 -0
  98. package/dist/registry/select.d.ts.map +1 -1
  99. package/dist/registry/select.js +66 -0
  100. package/dist/routes/loader-warnings.d.ts +28 -0
  101. package/dist/routes/loader-warnings.d.ts.map +1 -0
  102. package/dist/routes/loader-warnings.js +56 -0
  103. package/dist/routes/loader.d.ts +1 -11
  104. package/dist/routes/loader.d.ts.map +1 -1
  105. package/dist/routes/loader.js +54 -31
  106. package/dist/routes/objective-loader.d.ts +35 -0
  107. package/dist/routes/objective-loader.d.ts.map +1 -0
  108. package/dist/routes/objective-loader.js +286 -0
  109. package/dist/run/accept.d.ts +43 -0
  110. package/dist/run/accept.d.ts.map +1 -0
  111. package/dist/run/accept.js +65 -0
  112. package/dist/run/cost.d.ts +13 -0
  113. package/dist/run/cost.d.ts.map +1 -1
  114. package/dist/run/cost.js +27 -0
  115. package/dist/run/dispatch.d.ts +24 -1
  116. package/dist/run/dispatch.d.ts.map +1 -1
  117. package/dist/run/dispatch.js +19 -0
  118. package/dist/run/ladder-key.d.ts +4 -0
  119. package/dist/run/ladder-key.d.ts.map +1 -1
  120. package/dist/run/ladder-key.js +3 -0
  121. package/dist/run/quality-gate.d.ts +39 -0
  122. package/dist/run/quality-gate.d.ts.map +1 -0
  123. package/dist/run/quality-gate.js +70 -0
  124. package/dist/run/raw-defaults.d.ts +52 -0
  125. package/dist/run/raw-defaults.d.ts.map +1 -0
  126. package/dist/run/raw-defaults.js +123 -0
  127. package/dist/run/raw.d.ts +12 -0
  128. package/dist/run/raw.d.ts.map +1 -1
  129. package/dist/run/raw.js +107 -8
  130. package/dist/run/record-attempt.d.ts.map +1 -1
  131. package/dist/run/record-attempt.js +22 -1
  132. package/dist/run/resolve.d.ts +17 -1
  133. package/dist/run/resolve.d.ts.map +1 -1
  134. package/dist/run/resolve.js +20 -4
  135. package/dist/run/routing-docs.d.ts.map +1 -1
  136. package/dist/run/routing-docs.js +12 -5
  137. package/dist/run/run.d.ts +7 -1
  138. package/dist/run/run.d.ts.map +1 -1
  139. package/dist/run/run.js +54 -69
  140. package/dist/run/variant.d.ts +43 -0
  141. package/dist/run/variant.d.ts.map +1 -0
  142. package/dist/run/variant.js +86 -0
  143. package/dist/savings/emit.d.ts +33 -0
  144. package/dist/savings/emit.d.ts.map +1 -1
  145. package/dist/savings/emit.js +75 -3
  146. package/dist/settings/index.d.ts +1 -1
  147. package/dist/settings/index.d.ts.map +1 -1
  148. package/dist/settings/index.js +2 -1
  149. package/dist/settings/task-settings.d.ts +10 -0
  150. package/dist/settings/task-settings.d.ts.map +1 -1
  151. package/dist/settings/task-settings.js +17 -0
  152. package/dist/telemetry/attempt-meta.d.ts +178 -0
  153. package/dist/telemetry/attempt-meta.d.ts.map +1 -0
  154. package/dist/telemetry/attempt-meta.js +319 -0
  155. package/dist/telemetry/exporter.d.ts.map +1 -1
  156. package/dist/telemetry/exporter.js +6 -0
  157. package/dist/telemetry/ingest-protocol.d.ts +11 -0
  158. package/dist/telemetry/ingest-protocol.d.ts.map +1 -1
  159. package/dist/telemetry/ingest-protocol.js +3 -0
  160. package/dist/telemetry/otel-map.d.ts +10 -0
  161. package/dist/telemetry/otel-map.d.ts.map +1 -1
  162. package/dist/telemetry/otel-map.js +64 -0
  163. package/dist/telemetry/store-migrations.d.ts.map +1 -1
  164. package/dist/telemetry/store-migrations.js +15 -0
  165. package/dist/telemetry/store.d.ts.map +1 -1
  166. package/dist/telemetry/store.js +25 -7
  167. package/dist/types/failures-teaching.d.ts.map +1 -1
  168. package/dist/types/failures-teaching.js +20 -0
  169. package/dist/types/failures.d.ts +1 -1
  170. package/dist/types/failures.d.ts.map +1 -1
  171. package/dist/types/failures.js +1 -0
  172. package/dist/types/provider.d.ts +9 -0
  173. package/dist/types/provider.d.ts.map +1 -1
  174. package/dist/types/quality.d.ts +41 -0
  175. package/dist/types/quality.d.ts.map +1 -0
  176. package/dist/types/quality.js +12 -0
  177. package/dist/types/route.d.ts +120 -0
  178. package/dist/types/route.d.ts.map +1 -1
  179. package/dist/types/telemetry.d.ts +13 -0
  180. package/dist/types/telemetry.d.ts.map +1 -1
  181. package/dist/validate-cli.d.ts.map +1 -1
  182. package/dist/validate-cli.js +10 -0
  183. package/dist/watch/evaluate.d.ts +27 -1
  184. package/dist/watch/evaluate.d.ts.map +1 -1
  185. package/dist/watch/evaluate.js +13 -0
  186. package/dist/watch/proposals.d.ts +28 -0
  187. package/dist/watch/proposals.d.ts.map +1 -1
  188. package/dist/watch/proposals.js +51 -0
  189. 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;AAMhG,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAKD,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAMhF;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,iBAAiB,CAiB1E;AAED,UAAU,WAAW;IACnB,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAC;IACjC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,SAAS,WAAW,EAAE,CAAC;IAC1C,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC;IACtB,QAAQ,CAAC,cAAc,EAAE;QAAE,QAAQ,CAAC,aAAa,EAAE,IAAI,CAAA;KAAE,CAAC;IAC1D,8EAA8E;IAC9E,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,eAAe,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAA;KAAE,CAAC;IAC5D,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,cAAc,EAAE,CAAC;IAC3C,QAAQ,CAAC,WAAW,CAAC,EAAE,oBAAoB,CAAC;CAC7C;AAOD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,YAAY,GAAG,oBAAoB,CAkC1F;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,qBAAqB,GAAG,eAAe,CA8JpF"}
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;AAKlE,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;;;mCAImC;AACnC,eAAO,MAAM,8BAA8B,EAAE,WAAW,CAAC,MAAM,CAI7D,CAAC;AA0BH,wBAAgB,cAAc,CAAC,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAG9E;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,GAAG,EAAE,YAAY,CAAC;IAC3B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,iBAAiB,CAyCxE;AAED;6EAC6E;AAC7E,MAAM,MAAM,YAAY,GAAG,IAAI,CAAC,cAAc,EAAE,WAAW,CAAC,CAAC;AAE7D;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,YAAY,GAAG,iBAAiB,GAAG,IAAI,CAQrG;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC1C;AAED,iEAAiE;AACjE,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,YAAY,GAAG,mBAAmB,CAqDxF;AA0BD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,mBAAmB,GAAG,eAAe,CA+JhF"}
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"}
@@ -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
- return { ok: true, text: toolText, usage, toolCalls };
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
- const text = response.text ?? "";
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
- return fail("content_invalid", `empty response from Gemini (finishReason=${finishReason ?? "none"})`, undefined, usage);
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;AAOhG,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAKD,wBAAgB,YAAY,CAAC,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAc7E;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,iBAAiB,CA+BtE;AAED,UAAU,WAAW;IACnB,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAC;IACjC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,SAAS,WAAW,EAAE,CAAC;IAC1C,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC;IACtB,QAAQ,CAAC,cAAc,EAAE;QAAE,QAAQ,CAAC,aAAa,EAAE,IAAI,CAAA;KAAE,CAAC;IAC1D,8EAA8E;IAC9E,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB;8EAC0E;IAC1E,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC;;;4DAGwD;IACxD,QAAQ,CAAC,gBAAgB,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;IAC3C,QAAQ,CAAC,eAAe,CAAC,EACrB;QAAE,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAA;KAAE,GAChC;QACE,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;QAC7B,QAAQ,CAAC,WAAW,EAAE;YAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAA;SAAE,CAAC;KACjG,CAAC;IACN,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,cAAc,EAAE,CAAC;IAC3C,QAAQ,CAAC,WAAW,CAAC,EAAE,oBAAoB,CAAC;CAC7C;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,YAAY,GAAG,gBAAgB,CAmDlF;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,iBAAiB,GAAG,eAAe,CAgK5E"}
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"}
@@ -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":"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"}
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
  },