@openrouter/ai-sdk-provider 2.3.2 → 2.4.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.mjs CHANGED
@@ -2183,11 +2183,13 @@ function isDefinedOrNotNull(value) {
2183
2183
  var ReasoningFormat = /* @__PURE__ */ ((ReasoningFormat2) => {
2184
2184
  ReasoningFormat2["Unknown"] = "unknown";
2185
2185
  ReasoningFormat2["OpenAIResponsesV1"] = "openai-responses-v1";
2186
+ ReasoningFormat2["AzureOpenAIResponsesV1"] = "azure-openai-responses-v1";
2186
2187
  ReasoningFormat2["XAIResponsesV1"] = "xai-responses-v1";
2187
2188
  ReasoningFormat2["AnthropicClaudeV1"] = "anthropic-claude-v1";
2188
2189
  ReasoningFormat2["GoogleGeminiV1"] = "google-gemini-v1";
2189
2190
  return ReasoningFormat2;
2190
2191
  })(ReasoningFormat || {});
2192
+ var DEFAULT_REASONING_FORMAT = "anthropic-claude-v1" /* AnthropicClaudeV1 */;
2191
2193
 
2192
2194
  // src/schemas/reasoning-details.ts
2193
2195
  var CommonReasoningDetailSchema = z.object({
@@ -2340,7 +2342,11 @@ var OpenRouterProviderMetadataSchema = z3.object({
2340
2342
  }).catchall(z3.any());
2341
2343
  var OpenRouterProviderOptionsSchema = z3.object({
2342
2344
  openrouter: z3.object({
2343
- reasoning_details: z3.array(ReasoningDetailUnionSchema).optional(),
2345
+ // Use ReasoningDetailArraySchema (with unknown fallback) instead of
2346
+ // z.array(ReasoningDetailUnionSchema) so that a single malformed entry
2347
+ // (e.g., a future format not yet in the enum) is individually dropped
2348
+ // rather than causing the entire array to fail parsing.
2349
+ reasoning_details: ReasoningDetailArraySchema.optional(),
2344
2350
  annotations: z3.array(FileAnnotationSchema).optional()
2345
2351
  }).optional()
2346
2352
  }).optional();
@@ -2411,6 +2417,31 @@ function createFinishReason(unified, raw) {
2411
2417
  return { unified, raw };
2412
2418
  }
2413
2419
 
2420
+ // src/utils/with-stream-error-handling.ts
2421
+ function withStreamErrorHandling(source, onError) {
2422
+ const reader = source.getReader();
2423
+ return new ReadableStream({
2424
+ async pull(controller) {
2425
+ try {
2426
+ const { done, value } = await reader.read();
2427
+ if (done) {
2428
+ controller.close();
2429
+ } else {
2430
+ controller.enqueue(value);
2431
+ }
2432
+ } catch (err) {
2433
+ onError(err);
2434
+ reader.cancel().catch(() => {
2435
+ });
2436
+ controller.close();
2437
+ }
2438
+ },
2439
+ cancel(reason) {
2440
+ reader.cancel(reason);
2441
+ }
2442
+ });
2443
+ }
2444
+
2414
2445
  // src/utils/reasoning-details-duplicate-tracker.ts
2415
2446
  var _seenKeys;
2416
2447
  var ReasoningDetailsDuplicateTracker = class {
@@ -2752,8 +2783,24 @@ function convertToOpenRouterChatMessages(prompt) {
2752
2783
  const candidateReasoningDetails = messageReasoningDetails && Array.isArray(messageReasoningDetails) && messageReasoningDetails.length > 0 ? messageReasoningDetails : findFirstReasoningDetails(content);
2753
2784
  let finalReasoningDetails;
2754
2785
  if (candidateReasoningDetails && candidateReasoningDetails.length > 0) {
2786
+ const validDetails = candidateReasoningDetails.filter((detail) => {
2787
+ var _a17;
2788
+ if (detail.type !== "reasoning.text" /* Text */) {
2789
+ return true;
2790
+ }
2791
+ const format = (_a17 = detail.format) != null ? _a17 : DEFAULT_REASONING_FORMAT;
2792
+ if (format !== "anthropic-claude-v1" /* AnthropicClaudeV1 */) {
2793
+ return true;
2794
+ }
2795
+ return !!detail.signature;
2796
+ });
2797
+ if (validDetails.length < candidateReasoningDetails.length) {
2798
+ console.warn(
2799
+ "[openrouter] Some reasoning_details entries were removed because they were missing signatures. See https://github.com/OpenRouterTeam/ai-sdk-provider/issues/423 for more details."
2800
+ );
2801
+ }
2755
2802
  const uniqueDetails = [];
2756
- for (const detail of candidateReasoningDetails) {
2803
+ for (const detail of validDetails) {
2757
2804
  if (reasoningDetailsTracker.upsert(detail)) {
2758
2805
  uniqueDetails.push(detail);
2759
2806
  }
@@ -2782,6 +2829,7 @@ function convertToOpenRouterChatMessages(prompt) {
2782
2829
  role: "tool",
2783
2830
  tool_call_id: toolResponse.toolCallId,
2784
2831
  content: content2,
2832
+ name: toolResponse.toolName,
2785
2833
  cache_control: (_h = getCacheControl(providerOptions)) != null ? _h : getCacheControl(toolResponse.providerOptions)
2786
2834
  });
2787
2835
  }
@@ -2923,13 +2971,14 @@ function filenameFromUrl(url) {
2923
2971
  }
2924
2972
  }
2925
2973
  function findFirstReasoningDetails(content) {
2926
- var _a16, _b16, _c;
2974
+ var _a16, _b16, _c, _d;
2927
2975
  for (const part of content) {
2928
2976
  if (part.type === "tool-call") {
2929
- const openrouter2 = (_a16 = part.providerOptions) == null ? void 0 : _a16.openrouter;
2930
- const details = openrouter2 == null ? void 0 : openrouter2.reasoning_details;
2931
- if (Array.isArray(details) && details.length > 0) {
2932
- return details;
2977
+ const parsed = OpenRouterProviderOptionsSchema.safeParse(
2978
+ part.providerOptions
2979
+ );
2980
+ if (parsed.success && ((_b16 = (_a16 = parsed.data) == null ? void 0 : _a16.openrouter) == null ? void 0 : _b16.reasoning_details) && parsed.data.openrouter.reasoning_details.length > 0) {
2981
+ return parsed.data.openrouter.reasoning_details;
2933
2982
  }
2934
2983
  }
2935
2984
  }
@@ -2938,7 +2987,7 @@ function findFirstReasoningDetails(content) {
2938
2987
  const parsed = OpenRouterProviderOptionsSchema.safeParse(
2939
2988
  part.providerOptions
2940
2989
  );
2941
- if (parsed.success && ((_c = (_b16 = parsed.data) == null ? void 0 : _b16.openrouter) == null ? void 0 : _c.reasoning_details) && parsed.data.openrouter.reasoning_details.length > 0) {
2990
+ if (parsed.success && ((_d = (_c = parsed.data) == null ? void 0 : _c.openrouter) == null ? void 0 : _d.reasoning_details) && parsed.data.openrouter.reasoning_details.length > 0) {
2942
2991
  return parsed.data.openrouter.reasoning_details;
2943
2992
  }
2944
2993
  }
@@ -3443,7 +3492,8 @@ var OpenRouterChatLanguageModel = class {
3443
3492
  (d) => d.type === "reasoning.encrypted" /* Encrypted */ && d.data
3444
3493
  );
3445
3494
  const shouldOverrideFinishReason = hasToolCalls && hasEncryptedReasoning && choice.finish_reason === "stop";
3446
- const effectiveFinishReason = shouldOverrideFinishReason ? createFinishReason("tool-calls", (_j = choice.finish_reason) != null ? _j : void 0) : mapOpenRouterFinishReason(choice.finish_reason);
3495
+ const mappedFinishReason = shouldOverrideFinishReason ? createFinishReason("tool-calls", (_j = choice.finish_reason) != null ? _j : void 0) : mapOpenRouterFinishReason(choice.finish_reason);
3496
+ const effectiveFinishReason = hasToolCalls && mappedFinishReason.unified === "other" ? createFinishReason("tool-calls", mappedFinishReason.raw) : mappedFinishReason;
3447
3497
  return {
3448
3498
  content,
3449
3499
  finishReason: effectiveFinishReason,
@@ -3507,6 +3557,10 @@ var OpenRouterChatLanguageModel = class {
3507
3557
  abortSignal: options.abortSignal,
3508
3558
  fetch: this.config.fetch
3509
3559
  });
3560
+ let streamError;
3561
+ const safeResponse = withStreamErrorHandling(response, (err) => {
3562
+ streamError = err;
3563
+ });
3510
3564
  const toolCalls = [];
3511
3565
  let finishReason = createFinishReason("other");
3512
3566
  const usage = {
@@ -3535,7 +3589,7 @@ var OpenRouterChatLanguageModel = class {
3535
3589
  let openrouterResponseId;
3536
3590
  let provider;
3537
3591
  return {
3538
- stream: response.pipeThrough(
3592
+ stream: safeResponse.pipeThrough(
3539
3593
  new TransformStream({
3540
3594
  transform(chunk, controller) {
3541
3595
  var _a17, _b17, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u;
@@ -3857,12 +3911,19 @@ var OpenRouterChatLanguageModel = class {
3857
3911
  flush(controller) {
3858
3912
  var _a17;
3859
3913
  const hasToolCalls = toolCalls.length > 0;
3914
+ if (streamError != null) {
3915
+ finishReason = createFinishReason("error");
3916
+ controller.enqueue({ type: "error", error: streamError });
3917
+ }
3860
3918
  const hasEncryptedReasoning = accumulatedReasoningDetails.some(
3861
3919
  (d) => d.type === "reasoning.encrypted" /* Encrypted */ && d.data
3862
3920
  );
3863
3921
  if (hasToolCalls && hasEncryptedReasoning && finishReason.unified === "stop") {
3864
3922
  finishReason = createFinishReason("tool-calls", finishReason.raw);
3865
3923
  }
3924
+ if (hasToolCalls && finishReason.unified === "other") {
3925
+ finishReason = createFinishReason("tool-calls", finishReason.raw);
3926
+ }
3866
3927
  if (finishReason.unified === "tool-calls") {
3867
3928
  for (const toolCall of toolCalls) {
3868
3929
  if (toolCall && !toolCall.sent) {
@@ -4248,6 +4309,10 @@ var OpenRouterCompletionLanguageModel = class {
4248
4309
  abortSignal: options.abortSignal,
4249
4310
  fetch: this.config.fetch
4250
4311
  });
4312
+ let streamError;
4313
+ const safeResponse = withStreamErrorHandling(response, (err) => {
4314
+ streamError = err;
4315
+ });
4251
4316
  let finishReason = createFinishReason("other");
4252
4317
  const usage = {
4253
4318
  inputTokens: {
@@ -4267,7 +4332,7 @@ var OpenRouterCompletionLanguageModel = class {
4267
4332
  let provider;
4268
4333
  let rawUsage;
4269
4334
  return {
4270
- stream: response.pipeThrough(
4335
+ stream: safeResponse.pipeThrough(
4271
4336
  new TransformStream({
4272
4337
  transform(chunk, controller) {
4273
4338
  var _a16, _b16, _c, _d, _e;
@@ -4331,6 +4396,10 @@ var OpenRouterCompletionLanguageModel = class {
4331
4396
  }
4332
4397
  },
4333
4398
  flush(controller) {
4399
+ if (streamError != null) {
4400
+ finishReason = createFinishReason("error");
4401
+ controller.enqueue({ type: "error", error: streamError });
4402
+ }
4334
4403
  usage.raw = rawUsage;
4335
4404
  const openrouterMetadata = {
4336
4405
  usage: openrouterUsage
@@ -4444,17 +4513,19 @@ var OpenRouter = class {
4444
4513
  this.apiKey = options.apiKey;
4445
4514
  this.headers = options.headers;
4446
4515
  this.api_keys = options.api_keys;
4516
+ this.appName = options.appName;
4517
+ this.appUrl = options.appUrl;
4447
4518
  }
4448
4519
  get baseConfig() {
4449
4520
  return {
4450
4521
  baseURL: this.baseURL,
4451
- headers: () => __spreadValues(__spreadValues({
4522
+ headers: () => __spreadValues(__spreadValues(__spreadValues(__spreadValues({
4452
4523
  Authorization: `Bearer ${loadApiKey({
4453
4524
  apiKey: this.apiKey,
4454
4525
  environmentVariableName: "OPENROUTER_API_KEY",
4455
4526
  description: "OpenRouter"
4456
4527
  })}`
4457
- }, this.headers), this.api_keys && Object.keys(this.api_keys).length > 0 && {
4528
+ }, this.appName && { "X-OpenRouter-Title": this.appName }), this.appUrl && { "HTTP-Referer": this.appUrl }), this.headers), this.api_keys && Object.keys(this.api_keys).length > 0 && {
4458
4529
  "X-Provider-API-Keys": JSON.stringify(this.api_keys)
4459
4530
  })
4460
4531
  };
@@ -4691,7 +4762,7 @@ function withUserAgentSuffix2(headers, ...userAgentSuffixParts) {
4691
4762
  }
4692
4763
 
4693
4764
  // src/version.ts
4694
- var VERSION2 = false ? "0.0.0-test" : "2.3.2";
4765
+ var VERSION2 = false ? "0.0.0-test" : "2.4.0";
4695
4766
 
4696
4767
  // src/provider.ts
4697
4768
  function createOpenRouter(options = {}) {
@@ -4699,13 +4770,13 @@ function createOpenRouter(options = {}) {
4699
4770
  const baseURL = (_b16 = withoutTrailingSlash((_a16 = options.baseURL) != null ? _a16 : options.baseUrl)) != null ? _b16 : "https://openrouter.ai/api/v1";
4700
4771
  const compatibility = (_c = options.compatibility) != null ? _c : "compatible";
4701
4772
  const getHeaders = () => withUserAgentSuffix2(
4702
- __spreadValues(__spreadValues({
4773
+ __spreadValues(__spreadValues(__spreadValues(__spreadValues({
4703
4774
  Authorization: `Bearer ${loadApiKey({
4704
4775
  apiKey: options.apiKey,
4705
4776
  environmentVariableName: "OPENROUTER_API_KEY",
4706
4777
  description: "OpenRouter"
4707
4778
  })}`
4708
- }, options.headers), options.api_keys && Object.keys(options.api_keys).length > 0 && {
4779
+ }, options.appName && { "X-OpenRouter-Title": options.appName }), options.appUrl && { "HTTP-Referer": options.appUrl }), options.headers), options.api_keys && Object.keys(options.api_keys).length > 0 && {
4709
4780
  "X-Provider-API-Keys": JSON.stringify(options.api_keys)
4710
4781
  }),
4711
4782
  `ai-sdk/openrouter/${VERSION2}`