@wrongstack/providers 0.267.0 → 0.268.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/dist/index.d.ts CHANGED
@@ -93,7 +93,7 @@ declare abstract class WireAdapter implements Provider {
93
93
  /** Map Request fields to the wire request body. */
94
94
  protected abstract buildBody(req: Request): Record<string, unknown>;
95
95
  /** Translate wire SSE events into canonical StreamEvent[]. */
96
- protected abstract parseStream(body: ReadableStream<Uint8Array> | NodeJS.ReadableStream | null, fallbackModel: string): AsyncIterable<StreamEvent>;
96
+ protected abstract parseStream(body: ReadableStream<Uint8Array> | NodeJS.ReadableStream | null, fallbackModel: string, req: Request): AsyncIterable<StreamEvent>;
97
97
  /** Build a ProviderError from an HTTP failure response. */
98
98
  protected translateError(status: number, body: string): ProviderError;
99
99
  }
@@ -115,7 +115,7 @@ declare class AnthropicProvider extends WireAdapter {
115
115
  protected buildUrl(_req: Request): string;
116
116
  protected buildHeaders(req: Request): Record<string, string>;
117
117
  protected buildBody(req: Request): Record<string, unknown>;
118
- protected parseStream(body: Parameters<typeof parseSSE>[0], fallbackModel: string): AsyncIterable<StreamEvent>;
118
+ protected parseStream(body: Parameters<typeof parseSSE>[0], fallbackModel: string, req: Request): AsyncIterable<StreamEvent>;
119
119
  protected translateError(status: number, text: string): ProviderError;
120
120
  private normalizeMessage;
121
121
  }
@@ -197,6 +197,7 @@ interface OpenAIProviderOptions {
197
197
  quirks?: ConvertOptions & {
198
198
  parallelToolsDisabled?: boolean | undefined;
199
199
  jsonArgumentsBuggy?: boolean | undefined;
200
+ thinkingParam?: 'zai-glm' | 'kimi-toggle' | 'always-on' | undefined;
200
201
  } | undefined;
201
202
  id?: string | undefined;
202
203
  capabilities?: Partial<Capabilities> | undefined;
@@ -231,6 +232,7 @@ interface CompatibilityQuirks {
231
232
  parallelToolsDisabled?: boolean | undefined;
232
233
  jsonArgumentsBuggy?: boolean | undefined;
233
234
  emptyToolCallContent?: 'null' | 'empty_string' | undefined;
235
+ thinkingParam?: 'zai-glm' | 'kimi-toggle' | 'always-on' | undefined;
234
236
  }
235
237
  interface OpenAICompatibleOptions {
236
238
  id: string;
@@ -260,6 +262,7 @@ declare class OpenAICompatibleProvider extends OpenAIProvider {
260
262
  * OpenAI's newer `max_completion_tokens`. Keep the legacy field here. See #10.
261
263
  */
262
264
  protected tokenLimitParam(): string;
265
+ protected buildBody(req: Request): Record<string, unknown>;
263
266
  protected buildHeaders(req: Request): Record<string, string>;
264
267
  }
265
268
 
package/dist/index.js CHANGED
@@ -271,6 +271,13 @@ var init_aggregate = __esm({
271
271
 
272
272
  // src/anthropic.ts
273
273
  init_tool_input();
274
+
275
+ // src/object-utils.ts
276
+ function isPlainObject(value) {
277
+ return typeof value === "object" && value !== null && !Array.isArray(value);
278
+ }
279
+
280
+ // src/error-parse.ts
274
281
  function parseProviderHttpError(providerId, status, rawText) {
275
282
  const body = parseBody(rawText);
276
283
  const retryable = isRetryable(status, body.type);
@@ -288,9 +295,9 @@ function parseBody(rawText) {
288
295
  } catch {
289
296
  return body;
290
297
  }
291
- if (!isRecord(parsed)) return body;
298
+ if (!isPlainObject(parsed)) return body;
292
299
  const errField = parsed["error"];
293
- if (isRecord(errField)) {
300
+ if (isPlainObject(errField)) {
294
301
  const t = stringOf(errField["type"]) ?? stringOf(errField["status"]);
295
302
  const m = stringOf(errField["message"]);
296
303
  if (t) body.type = t;
@@ -317,9 +324,6 @@ function isRetryable(status, type) {
317
324
  if (type === "overloaded_error" || type === "rate_limit_error") return true;
318
325
  return false;
319
326
  }
320
- function isRecord(v) {
321
- return typeof v === "object" && v !== null && !Array.isArray(v);
322
- }
323
327
  function stringOf(v) {
324
328
  return typeof v === "string" && v.length > 0 ? v : void 0;
325
329
  }
@@ -719,7 +723,7 @@ var WireAdapter = class {
719
723
  if (this.streamHangTimeoutMs > 0) {
720
724
  sseBody = this.wrapWithHangDetection(sseBody, req.model);
721
725
  }
722
- yield* this.parseStream(sseBody, req.model);
726
+ yield* this.parseStream(sseBody, req.model, req);
723
727
  }
724
728
  /**
725
729
  * Wrap a readable stream body to log a compact status line per incoming
@@ -891,7 +895,12 @@ var AnthropicProvider = class extends WireAdapter {
891
895
  messages: req.messages.map((m) => this.normalizeMessage(m)),
892
896
  stream: true
893
897
  };
894
- if (req.system && req.system.length > 0) body["system"] = req.system;
898
+ if (req.system && req.system.length > 0) {
899
+ const systemBlocks = req.system;
900
+ body["system"] = systemBlocks.map(
901
+ (b, index) => req.cache?.ttl && index === systemBlocks.length - 1 ? { ...b, cache_control: { type: "ephemeral", ttl: req.cache.ttl } } : b
902
+ );
903
+ }
895
904
  if (req.tools && req.tools.length > 0) body["tools"] = toolsToAnthropic(req.tools);
896
905
  if (req.temperature !== void 0) body["temperature"] = req.temperature;
897
906
  if (req.topP !== void 0) body["top_p"] = req.topP;
@@ -899,8 +908,8 @@ var AnthropicProvider = class extends WireAdapter {
899
908
  if (req.toolChoice) body["tool_choice"] = req.toolChoice;
900
909
  return body;
901
910
  }
902
- parseStream(body, fallbackModel) {
903
- return parseAnthropicStream(body, fallbackModel);
911
+ parseStream(body, fallbackModel, req) {
912
+ return parseAnthropicStream(body, fallbackModel, req.cache?.ttl);
904
913
  }
905
914
  translateError(status, text) {
906
915
  return parseProviderHttpError(this.id, status, text);
@@ -934,7 +943,7 @@ function sanitizeAnthropicBlock(b) {
934
943
  return b;
935
944
  }
936
945
  }
937
- async function* parseAnthropicStream(body, fallbackModel) {
946
+ async function* parseAnthropicStream(body, fallbackModel, cacheTtl) {
938
947
  const blocks = /* @__PURE__ */ new Map();
939
948
  let model = fallbackModel;
940
949
  let usage = { input: 0, output: 0 };
@@ -951,11 +960,14 @@ async function* parseAnthropicStream(body, fallbackModel) {
951
960
  case "message_start": {
952
961
  const message = ev["message"];
953
962
  if (message?.model) model = message.model;
963
+ const cacheWrite = message?.usage?.cache_creation_input_tokens;
954
964
  usage = {
955
965
  input: message?.usage?.input_tokens ?? 0,
956
966
  output: 0,
957
967
  cacheRead: message?.usage?.cache_read_input_tokens,
958
- cacheWrite: message?.usage?.cache_creation_input_tokens
968
+ cacheWrite,
969
+ cacheWrite5m: cacheTtl === "1h" ? void 0 : cacheWrite,
970
+ cacheWrite1h: cacheTtl === "1h" ? cacheWrite : void 0
959
971
  };
960
972
  if (!started) {
961
973
  started = true;
@@ -2181,7 +2193,8 @@ var VALID_QUIRK_KEYS = /* @__PURE__ */ new Set([
2181
2193
  "preserveToolCallIds",
2182
2194
  "parallelToolsDisabled",
2183
2195
  "jsonArgumentsBuggy",
2184
- "emptyToolCallContent"
2196
+ "emptyToolCallContent",
2197
+ "thinkingParam"
2185
2198
  ]);
2186
2199
  function isCompatibilityQuirks(value) {
2187
2200
  if (value === void 0) return true;
@@ -2191,6 +2204,8 @@ function isCompatibilityQuirks(value) {
2191
2204
  if (!VALID_QUIRK_KEYS.has(key)) return false;
2192
2205
  if (key === "emptyToolCallContent") {
2193
2206
  if (v !== "null" && v !== "empty_string") return false;
2207
+ } else if (key === "thinkingParam") {
2208
+ if (v !== "zai-glm" && v !== "kimi-toggle" && v !== "always-on") return false;
2194
2209
  } else if (typeof v !== "boolean") {
2195
2210
  return false;
2196
2211
  }
@@ -2231,6 +2246,11 @@ var OpenAICompatibleProvider = class extends OpenAIProvider {
2231
2246
  tokenLimitParam() {
2232
2247
  return "max_tokens";
2233
2248
  }
2249
+ buildBody(req) {
2250
+ const body = super.buildBody(req);
2251
+ applyThinkingParams(body, req, this.opts.quirks?.thinkingParam);
2252
+ return body;
2253
+ }
2234
2254
  buildHeaders(req) {
2235
2255
  return {
2236
2256
  ...super.buildHeaders(req),
@@ -2238,6 +2258,36 @@ var OpenAICompatibleProvider = class extends OpenAIProvider {
2238
2258
  };
2239
2259
  }
2240
2260
  };
2261
+ function applyThinkingParams(body, req, mode) {
2262
+ if (!mode || !req.reasoning) return;
2263
+ if (mode === "always-on") {
2264
+ return;
2265
+ }
2266
+ if (req.reasoning.enabled === false) {
2267
+ body["thinking"] = { type: "disabled" };
2268
+ return;
2269
+ }
2270
+ if (mode === "kimi-toggle" && req.reasoning.enabled === true) {
2271
+ body["thinking"] = { type: "enabled" };
2272
+ }
2273
+ if (mode === "zai-glm" && req.reasoning.effort) {
2274
+ body["reasoning_effort"] = mapZaiReasoningEffort(req.reasoning.effort);
2275
+ }
2276
+ }
2277
+ function mapZaiReasoningEffort(effort) {
2278
+ switch (effort) {
2279
+ case "none":
2280
+ case "minimal":
2281
+ return "none";
2282
+ case "low":
2283
+ case "medium":
2284
+ return "high";
2285
+ case "xhigh":
2286
+ return "max";
2287
+ default:
2288
+ return effort;
2289
+ }
2290
+ }
2241
2291
 
2242
2292
  // src/wire-format.ts
2243
2293
  var WireFormatProvider = class extends WireAdapter {
@@ -3033,9 +3083,6 @@ function normalizeToolResultContent(raw, opts) {
3033
3083
  if (raw === void 0 || raw === null) return "";
3034
3084
  return JSON.stringify(raw);
3035
3085
  }
3036
- function isPlainObject(v) {
3037
- return typeof v === "object" && v !== null && !Array.isArray(v);
3038
- }
3039
3086
  function contentFromOpenAI(choice, opts = {}) {
3040
3087
  const out = [];
3041
3088
  const text = choice.message.content;