@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.d.mts +19 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +87 -16
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +87 -16
- package/dist/index.mjs.map +1 -1
- package/dist/internal/index.d.mts +1 -0
- package/dist/internal/index.d.ts +1 -0
- package/dist/internal/index.js +80 -11
- package/dist/internal/index.js.map +1 -1
- package/dist/internal/index.mjs +80 -11
- package/dist/internal/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -431,6 +431,7 @@ type OpenRouterCompletionSettings = {
|
|
|
431
431
|
declare enum ReasoningFormat {
|
|
432
432
|
Unknown = "unknown",
|
|
433
433
|
OpenAIResponsesV1 = "openai-responses-v1",
|
|
434
|
+
AzureOpenAIResponsesV1 = "azure-openai-responses-v1",
|
|
434
435
|
XAIResponsesV1 = "xai-responses-v1",
|
|
435
436
|
AnthropicClaudeV1 = "anthropic-claude-v1",
|
|
436
437
|
GoogleGeminiV1 = "google-gemini-v1"
|
|
@@ -676,6 +677,16 @@ interface OpenRouterProviderSettings {
|
|
|
676
677
|
* Maps provider slugs (e.g. "anthropic", "openai") to their respective API keys.
|
|
677
678
|
*/
|
|
678
679
|
api_keys?: Record<string, string>;
|
|
680
|
+
/**
|
|
681
|
+
* Your app's display name. Sets the `X-OpenRouter-Title` header on
|
|
682
|
+
* every request for app attribution on the openrouter.ai dashboard.
|
|
683
|
+
*/
|
|
684
|
+
appName?: string;
|
|
685
|
+
/**
|
|
686
|
+
* Your app's URL or identifier. Sets the `HTTP-Referer` header on every request,
|
|
687
|
+
* used to identify your app on the openrouter.ai dashboard.
|
|
688
|
+
*/
|
|
689
|
+
appUrl?: string;
|
|
679
690
|
}
|
|
680
691
|
/**
|
|
681
692
|
Create an OpenRouter provider instance.
|
|
@@ -708,6 +719,14 @@ declare class OpenRouter {
|
|
|
708
719
|
* Record of provider slugs to API keys for injecting into provider routing.
|
|
709
720
|
*/
|
|
710
721
|
readonly api_keys?: Record<string, string>;
|
|
722
|
+
/**
|
|
723
|
+
* App display name for the `X-OpenRouter-Title` header.
|
|
724
|
+
*/
|
|
725
|
+
readonly appName?: string;
|
|
726
|
+
/**
|
|
727
|
+
* App URL for the `HTTP-Referer` header.
|
|
728
|
+
*/
|
|
729
|
+
readonly appUrl?: string;
|
|
711
730
|
/**
|
|
712
731
|
* Creates a new OpenRouter provider instance.
|
|
713
732
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -431,6 +431,7 @@ type OpenRouterCompletionSettings = {
|
|
|
431
431
|
declare enum ReasoningFormat {
|
|
432
432
|
Unknown = "unknown",
|
|
433
433
|
OpenAIResponsesV1 = "openai-responses-v1",
|
|
434
|
+
AzureOpenAIResponsesV1 = "azure-openai-responses-v1",
|
|
434
435
|
XAIResponsesV1 = "xai-responses-v1",
|
|
435
436
|
AnthropicClaudeV1 = "anthropic-claude-v1",
|
|
436
437
|
GoogleGeminiV1 = "google-gemini-v1"
|
|
@@ -676,6 +677,16 @@ interface OpenRouterProviderSettings {
|
|
|
676
677
|
* Maps provider slugs (e.g. "anthropic", "openai") to their respective API keys.
|
|
677
678
|
*/
|
|
678
679
|
api_keys?: Record<string, string>;
|
|
680
|
+
/**
|
|
681
|
+
* Your app's display name. Sets the `X-OpenRouter-Title` header on
|
|
682
|
+
* every request for app attribution on the openrouter.ai dashboard.
|
|
683
|
+
*/
|
|
684
|
+
appName?: string;
|
|
685
|
+
/**
|
|
686
|
+
* Your app's URL or identifier. Sets the `HTTP-Referer` header on every request,
|
|
687
|
+
* used to identify your app on the openrouter.ai dashboard.
|
|
688
|
+
*/
|
|
689
|
+
appUrl?: string;
|
|
679
690
|
}
|
|
680
691
|
/**
|
|
681
692
|
Create an OpenRouter provider instance.
|
|
@@ -708,6 +719,14 @@ declare class OpenRouter {
|
|
|
708
719
|
* Record of provider slugs to API keys for injecting into provider routing.
|
|
709
720
|
*/
|
|
710
721
|
readonly api_keys?: Record<string, string>;
|
|
722
|
+
/**
|
|
723
|
+
* App display name for the `X-OpenRouter-Title` header.
|
|
724
|
+
*/
|
|
725
|
+
readonly appName?: string;
|
|
726
|
+
/**
|
|
727
|
+
* App URL for the `HTTP-Referer` header.
|
|
728
|
+
*/
|
|
729
|
+
readonly appUrl?: string;
|
|
711
730
|
/**
|
|
712
731
|
* Creates a new OpenRouter provider instance.
|
|
713
732
|
*/
|
package/dist/index.js
CHANGED
|
@@ -2216,11 +2216,13 @@ function isDefinedOrNotNull(value) {
|
|
|
2216
2216
|
var ReasoningFormat = /* @__PURE__ */ ((ReasoningFormat2) => {
|
|
2217
2217
|
ReasoningFormat2["Unknown"] = "unknown";
|
|
2218
2218
|
ReasoningFormat2["OpenAIResponsesV1"] = "openai-responses-v1";
|
|
2219
|
+
ReasoningFormat2["AzureOpenAIResponsesV1"] = "azure-openai-responses-v1";
|
|
2219
2220
|
ReasoningFormat2["XAIResponsesV1"] = "xai-responses-v1";
|
|
2220
2221
|
ReasoningFormat2["AnthropicClaudeV1"] = "anthropic-claude-v1";
|
|
2221
2222
|
ReasoningFormat2["GoogleGeminiV1"] = "google-gemini-v1";
|
|
2222
2223
|
return ReasoningFormat2;
|
|
2223
2224
|
})(ReasoningFormat || {});
|
|
2225
|
+
var DEFAULT_REASONING_FORMAT = "anthropic-claude-v1" /* AnthropicClaudeV1 */;
|
|
2224
2226
|
|
|
2225
2227
|
// src/schemas/reasoning-details.ts
|
|
2226
2228
|
var CommonReasoningDetailSchema = import_v4.z.object({
|
|
@@ -2373,7 +2375,11 @@ var OpenRouterProviderMetadataSchema = import_v43.z.object({
|
|
|
2373
2375
|
}).catchall(import_v43.z.any());
|
|
2374
2376
|
var OpenRouterProviderOptionsSchema = import_v43.z.object({
|
|
2375
2377
|
openrouter: import_v43.z.object({
|
|
2376
|
-
|
|
2378
|
+
// Use ReasoningDetailArraySchema (with unknown fallback) instead of
|
|
2379
|
+
// z.array(ReasoningDetailUnionSchema) so that a single malformed entry
|
|
2380
|
+
// (e.g., a future format not yet in the enum) is individually dropped
|
|
2381
|
+
// rather than causing the entire array to fail parsing.
|
|
2382
|
+
reasoning_details: ReasoningDetailArraySchema.optional(),
|
|
2377
2383
|
annotations: import_v43.z.array(FileAnnotationSchema).optional()
|
|
2378
2384
|
}).optional()
|
|
2379
2385
|
}).optional();
|
|
@@ -2444,6 +2450,31 @@ function createFinishReason(unified, raw) {
|
|
|
2444
2450
|
return { unified, raw };
|
|
2445
2451
|
}
|
|
2446
2452
|
|
|
2453
|
+
// src/utils/with-stream-error-handling.ts
|
|
2454
|
+
function withStreamErrorHandling(source, onError) {
|
|
2455
|
+
const reader = source.getReader();
|
|
2456
|
+
return new ReadableStream({
|
|
2457
|
+
async pull(controller) {
|
|
2458
|
+
try {
|
|
2459
|
+
const { done, value } = await reader.read();
|
|
2460
|
+
if (done) {
|
|
2461
|
+
controller.close();
|
|
2462
|
+
} else {
|
|
2463
|
+
controller.enqueue(value);
|
|
2464
|
+
}
|
|
2465
|
+
} catch (err) {
|
|
2466
|
+
onError(err);
|
|
2467
|
+
reader.cancel().catch(() => {
|
|
2468
|
+
});
|
|
2469
|
+
controller.close();
|
|
2470
|
+
}
|
|
2471
|
+
},
|
|
2472
|
+
cancel(reason) {
|
|
2473
|
+
reader.cancel(reason);
|
|
2474
|
+
}
|
|
2475
|
+
});
|
|
2476
|
+
}
|
|
2477
|
+
|
|
2447
2478
|
// src/utils/reasoning-details-duplicate-tracker.ts
|
|
2448
2479
|
var _seenKeys;
|
|
2449
2480
|
var ReasoningDetailsDuplicateTracker = class {
|
|
@@ -2785,8 +2816,24 @@ function convertToOpenRouterChatMessages(prompt) {
|
|
|
2785
2816
|
const candidateReasoningDetails = messageReasoningDetails && Array.isArray(messageReasoningDetails) && messageReasoningDetails.length > 0 ? messageReasoningDetails : findFirstReasoningDetails(content);
|
|
2786
2817
|
let finalReasoningDetails;
|
|
2787
2818
|
if (candidateReasoningDetails && candidateReasoningDetails.length > 0) {
|
|
2819
|
+
const validDetails = candidateReasoningDetails.filter((detail) => {
|
|
2820
|
+
var _a17;
|
|
2821
|
+
if (detail.type !== "reasoning.text" /* Text */) {
|
|
2822
|
+
return true;
|
|
2823
|
+
}
|
|
2824
|
+
const format = (_a17 = detail.format) != null ? _a17 : DEFAULT_REASONING_FORMAT;
|
|
2825
|
+
if (format !== "anthropic-claude-v1" /* AnthropicClaudeV1 */) {
|
|
2826
|
+
return true;
|
|
2827
|
+
}
|
|
2828
|
+
return !!detail.signature;
|
|
2829
|
+
});
|
|
2830
|
+
if (validDetails.length < candidateReasoningDetails.length) {
|
|
2831
|
+
console.warn(
|
|
2832
|
+
"[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."
|
|
2833
|
+
);
|
|
2834
|
+
}
|
|
2788
2835
|
const uniqueDetails = [];
|
|
2789
|
-
for (const detail of
|
|
2836
|
+
for (const detail of validDetails) {
|
|
2790
2837
|
if (reasoningDetailsTracker.upsert(detail)) {
|
|
2791
2838
|
uniqueDetails.push(detail);
|
|
2792
2839
|
}
|
|
@@ -2815,6 +2862,7 @@ function convertToOpenRouterChatMessages(prompt) {
|
|
|
2815
2862
|
role: "tool",
|
|
2816
2863
|
tool_call_id: toolResponse.toolCallId,
|
|
2817
2864
|
content: content2,
|
|
2865
|
+
name: toolResponse.toolName,
|
|
2818
2866
|
cache_control: (_h = getCacheControl(providerOptions)) != null ? _h : getCacheControl(toolResponse.providerOptions)
|
|
2819
2867
|
});
|
|
2820
2868
|
}
|
|
@@ -2956,13 +3004,14 @@ function filenameFromUrl(url) {
|
|
|
2956
3004
|
}
|
|
2957
3005
|
}
|
|
2958
3006
|
function findFirstReasoningDetails(content) {
|
|
2959
|
-
var _a16, _b16, _c;
|
|
3007
|
+
var _a16, _b16, _c, _d;
|
|
2960
3008
|
for (const part of content) {
|
|
2961
3009
|
if (part.type === "tool-call") {
|
|
2962
|
-
const
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
3010
|
+
const parsed = OpenRouterProviderOptionsSchema.safeParse(
|
|
3011
|
+
part.providerOptions
|
|
3012
|
+
);
|
|
3013
|
+
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) {
|
|
3014
|
+
return parsed.data.openrouter.reasoning_details;
|
|
2966
3015
|
}
|
|
2967
3016
|
}
|
|
2968
3017
|
}
|
|
@@ -2971,7 +3020,7 @@ function findFirstReasoningDetails(content) {
|
|
|
2971
3020
|
const parsed = OpenRouterProviderOptionsSchema.safeParse(
|
|
2972
3021
|
part.providerOptions
|
|
2973
3022
|
);
|
|
2974
|
-
if (parsed.success && ((
|
|
3023
|
+
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) {
|
|
2975
3024
|
return parsed.data.openrouter.reasoning_details;
|
|
2976
3025
|
}
|
|
2977
3026
|
}
|
|
@@ -3476,7 +3525,8 @@ var OpenRouterChatLanguageModel = class {
|
|
|
3476
3525
|
(d) => d.type === "reasoning.encrypted" /* Encrypted */ && d.data
|
|
3477
3526
|
);
|
|
3478
3527
|
const shouldOverrideFinishReason = hasToolCalls && hasEncryptedReasoning && choice.finish_reason === "stop";
|
|
3479
|
-
const
|
|
3528
|
+
const mappedFinishReason = shouldOverrideFinishReason ? createFinishReason("tool-calls", (_j = choice.finish_reason) != null ? _j : void 0) : mapOpenRouterFinishReason(choice.finish_reason);
|
|
3529
|
+
const effectiveFinishReason = hasToolCalls && mappedFinishReason.unified === "other" ? createFinishReason("tool-calls", mappedFinishReason.raw) : mappedFinishReason;
|
|
3480
3530
|
return {
|
|
3481
3531
|
content,
|
|
3482
3532
|
finishReason: effectiveFinishReason,
|
|
@@ -3540,6 +3590,10 @@ var OpenRouterChatLanguageModel = class {
|
|
|
3540
3590
|
abortSignal: options.abortSignal,
|
|
3541
3591
|
fetch: this.config.fetch
|
|
3542
3592
|
});
|
|
3593
|
+
let streamError;
|
|
3594
|
+
const safeResponse = withStreamErrorHandling(response, (err) => {
|
|
3595
|
+
streamError = err;
|
|
3596
|
+
});
|
|
3543
3597
|
const toolCalls = [];
|
|
3544
3598
|
let finishReason = createFinishReason("other");
|
|
3545
3599
|
const usage = {
|
|
@@ -3568,7 +3622,7 @@ var OpenRouterChatLanguageModel = class {
|
|
|
3568
3622
|
let openrouterResponseId;
|
|
3569
3623
|
let provider;
|
|
3570
3624
|
return {
|
|
3571
|
-
stream:
|
|
3625
|
+
stream: safeResponse.pipeThrough(
|
|
3572
3626
|
new TransformStream({
|
|
3573
3627
|
transform(chunk, controller) {
|
|
3574
3628
|
var _a17, _b17, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u;
|
|
@@ -3890,12 +3944,19 @@ var OpenRouterChatLanguageModel = class {
|
|
|
3890
3944
|
flush(controller) {
|
|
3891
3945
|
var _a17;
|
|
3892
3946
|
const hasToolCalls = toolCalls.length > 0;
|
|
3947
|
+
if (streamError != null) {
|
|
3948
|
+
finishReason = createFinishReason("error");
|
|
3949
|
+
controller.enqueue({ type: "error", error: streamError });
|
|
3950
|
+
}
|
|
3893
3951
|
const hasEncryptedReasoning = accumulatedReasoningDetails.some(
|
|
3894
3952
|
(d) => d.type === "reasoning.encrypted" /* Encrypted */ && d.data
|
|
3895
3953
|
);
|
|
3896
3954
|
if (hasToolCalls && hasEncryptedReasoning && finishReason.unified === "stop") {
|
|
3897
3955
|
finishReason = createFinishReason("tool-calls", finishReason.raw);
|
|
3898
3956
|
}
|
|
3957
|
+
if (hasToolCalls && finishReason.unified === "other") {
|
|
3958
|
+
finishReason = createFinishReason("tool-calls", finishReason.raw);
|
|
3959
|
+
}
|
|
3899
3960
|
if (finishReason.unified === "tool-calls") {
|
|
3900
3961
|
for (const toolCall of toolCalls) {
|
|
3901
3962
|
if (toolCall && !toolCall.sent) {
|
|
@@ -4281,6 +4342,10 @@ var OpenRouterCompletionLanguageModel = class {
|
|
|
4281
4342
|
abortSignal: options.abortSignal,
|
|
4282
4343
|
fetch: this.config.fetch
|
|
4283
4344
|
});
|
|
4345
|
+
let streamError;
|
|
4346
|
+
const safeResponse = withStreamErrorHandling(response, (err) => {
|
|
4347
|
+
streamError = err;
|
|
4348
|
+
});
|
|
4284
4349
|
let finishReason = createFinishReason("other");
|
|
4285
4350
|
const usage = {
|
|
4286
4351
|
inputTokens: {
|
|
@@ -4300,7 +4365,7 @@ var OpenRouterCompletionLanguageModel = class {
|
|
|
4300
4365
|
let provider;
|
|
4301
4366
|
let rawUsage;
|
|
4302
4367
|
return {
|
|
4303
|
-
stream:
|
|
4368
|
+
stream: safeResponse.pipeThrough(
|
|
4304
4369
|
new TransformStream({
|
|
4305
4370
|
transform(chunk, controller) {
|
|
4306
4371
|
var _a16, _b16, _c, _d, _e;
|
|
@@ -4364,6 +4429,10 @@ var OpenRouterCompletionLanguageModel = class {
|
|
|
4364
4429
|
}
|
|
4365
4430
|
},
|
|
4366
4431
|
flush(controller) {
|
|
4432
|
+
if (streamError != null) {
|
|
4433
|
+
finishReason = createFinishReason("error");
|
|
4434
|
+
controller.enqueue({ type: "error", error: streamError });
|
|
4435
|
+
}
|
|
4367
4436
|
usage.raw = rawUsage;
|
|
4368
4437
|
const openrouterMetadata = {
|
|
4369
4438
|
usage: openrouterUsage
|
|
@@ -4477,17 +4546,19 @@ var OpenRouter = class {
|
|
|
4477
4546
|
this.apiKey = options.apiKey;
|
|
4478
4547
|
this.headers = options.headers;
|
|
4479
4548
|
this.api_keys = options.api_keys;
|
|
4549
|
+
this.appName = options.appName;
|
|
4550
|
+
this.appUrl = options.appUrl;
|
|
4480
4551
|
}
|
|
4481
4552
|
get baseConfig() {
|
|
4482
4553
|
return {
|
|
4483
4554
|
baseURL: this.baseURL,
|
|
4484
|
-
headers: () => __spreadValues(__spreadValues({
|
|
4555
|
+
headers: () => __spreadValues(__spreadValues(__spreadValues(__spreadValues({
|
|
4485
4556
|
Authorization: `Bearer ${loadApiKey({
|
|
4486
4557
|
apiKey: this.apiKey,
|
|
4487
4558
|
environmentVariableName: "OPENROUTER_API_KEY",
|
|
4488
4559
|
description: "OpenRouter"
|
|
4489
4560
|
})}`
|
|
4490
|
-
}, this.headers), this.api_keys && Object.keys(this.api_keys).length > 0 && {
|
|
4561
|
+
}, 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 && {
|
|
4491
4562
|
"X-Provider-API-Keys": JSON.stringify(this.api_keys)
|
|
4492
4563
|
})
|
|
4493
4564
|
};
|
|
@@ -4724,7 +4795,7 @@ function withUserAgentSuffix2(headers, ...userAgentSuffixParts) {
|
|
|
4724
4795
|
}
|
|
4725
4796
|
|
|
4726
4797
|
// src/version.ts
|
|
4727
|
-
var VERSION2 = false ? "0.0.0-test" : "2.
|
|
4798
|
+
var VERSION2 = false ? "0.0.0-test" : "2.4.0";
|
|
4728
4799
|
|
|
4729
4800
|
// src/provider.ts
|
|
4730
4801
|
function createOpenRouter(options = {}) {
|
|
@@ -4732,13 +4803,13 @@ function createOpenRouter(options = {}) {
|
|
|
4732
4803
|
const baseURL = (_b16 = withoutTrailingSlash((_a16 = options.baseURL) != null ? _a16 : options.baseUrl)) != null ? _b16 : "https://openrouter.ai/api/v1";
|
|
4733
4804
|
const compatibility = (_c = options.compatibility) != null ? _c : "compatible";
|
|
4734
4805
|
const getHeaders = () => withUserAgentSuffix2(
|
|
4735
|
-
__spreadValues(__spreadValues({
|
|
4806
|
+
__spreadValues(__spreadValues(__spreadValues(__spreadValues({
|
|
4736
4807
|
Authorization: `Bearer ${loadApiKey({
|
|
4737
4808
|
apiKey: options.apiKey,
|
|
4738
4809
|
environmentVariableName: "OPENROUTER_API_KEY",
|
|
4739
4810
|
description: "OpenRouter"
|
|
4740
4811
|
})}`
|
|
4741
|
-
}, options.headers), options.api_keys && Object.keys(options.api_keys).length > 0 && {
|
|
4812
|
+
}, 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 && {
|
|
4742
4813
|
"X-Provider-API-Keys": JSON.stringify(options.api_keys)
|
|
4743
4814
|
}),
|
|
4744
4815
|
`ai-sdk/openrouter/${VERSION2}`
|