@openrouter/ai-sdk-provider
Version:
The [OpenRouter](https://openrouter.ai/) provider for the [Vercel AI SDK](https://sdk.vercel.ai/docs) gives access to over 300 large language models on the OpenRouter chat and completion APIs.
1,570 lines (1,550 loc) • 79.9 kB
JavaScript
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp.call(b, prop))
__defNormalProp(a, prop, b[prop]);
if (__getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(b)) {
if (__propIsEnum.call(b, prop))
__defNormalProp(a, prop, b[prop]);
}
return a;
};
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
var __export = (target, all) => {
for (var name14 in all)
__defProp(target, name14, { get: all[name14], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var index_exports = {};
__export(index_exports, {
OpenRouter: () => OpenRouter,
createOpenRouter: () => createOpenRouter,
openrouter: () => openrouter
});
module.exports = __toCommonJS(index_exports);
// node_modules/.pnpm/@ai-sdk+provider@2.0.0/node_modules/@ai-sdk/provider/dist/index.mjs
var marker = "vercel.ai.error";
var symbol = Symbol.for(marker);
var _a;
var _AISDKError = class _AISDKError2 extends Error {
/**
* Creates an AI SDK Error.
*
* @param {Object} params - The parameters for creating the error.
* @param {string} params.name - The name of the error.
* @param {string} params.message - The error message.
* @param {unknown} [params.cause] - The underlying cause of the error.
*/
constructor({
name: name14,
message,
cause
}) {
super(message);
this[_a] = true;
this.name = name14;
this.cause = cause;
}
/**
* Checks if the given error is an AI SDK Error.
* @param {unknown} error - The error to check.
* @returns {boolean} True if the error is an AI SDK Error, false otherwise.
*/
static isInstance(error) {
return _AISDKError2.hasMarker(error, marker);
}
static hasMarker(error, marker15) {
const markerSymbol = Symbol.for(marker15);
return error != null && typeof error === "object" && markerSymbol in error && typeof error[markerSymbol] === "boolean" && error[markerSymbol] === true;
}
};
_a = symbol;
var AISDKError = _AISDKError;
var name = "AI_APICallError";
var marker2 = `vercel.ai.error.${name}`;
var symbol2 = Symbol.for(marker2);
var _a2;
var APICallError = class extends AISDKError {
constructor({
message,
url,
requestBodyValues,
statusCode,
responseHeaders,
responseBody,
cause,
isRetryable = statusCode != null && (statusCode === 408 || // request timeout
statusCode === 409 || // conflict
statusCode === 429 || // too many requests
statusCode >= 500),
// server error
data
}) {
super({ name, message, cause });
this[_a2] = true;
this.url = url;
this.requestBodyValues = requestBodyValues;
this.statusCode = statusCode;
this.responseHeaders = responseHeaders;
this.responseBody = responseBody;
this.isRetryable = isRetryable;
this.data = data;
}
static isInstance(error) {
return AISDKError.hasMarker(error, marker2);
}
};
_a2 = symbol2;
var name2 = "AI_EmptyResponseBodyError";
var marker3 = `vercel.ai.error.${name2}`;
var symbol3 = Symbol.for(marker3);
var _a3;
var EmptyResponseBodyError = class extends AISDKError {
// used in isInstance
constructor({ message = "Empty response body" } = {}) {
super({ name: name2, message });
this[_a3] = true;
}
static isInstance(error) {
return AISDKError.hasMarker(error, marker3);
}
};
_a3 = symbol3;
function getErrorMessage(error) {
if (error == null) {
return "unknown error";
}
if (typeof error === "string") {
return error;
}
if (error instanceof Error) {
return error.message;
}
return JSON.stringify(error);
}
var name3 = "AI_InvalidArgumentError";
var marker4 = `vercel.ai.error.${name3}`;
var symbol4 = Symbol.for(marker4);
var _a4;
var InvalidArgumentError = class extends AISDKError {
constructor({
message,
cause,
argument
}) {
super({ name: name3, message, cause });
this[_a4] = true;
this.argument = argument;
}
static isInstance(error) {
return AISDKError.hasMarker(error, marker4);
}
};
_a4 = symbol4;
var name4 = "AI_InvalidPromptError";
var marker5 = `vercel.ai.error.${name4}`;
var symbol5 = Symbol.for(marker5);
var _a5;
var InvalidPromptError = class extends AISDKError {
constructor({
prompt,
message,
cause
}) {
super({ name: name4, message: `Invalid prompt: ${message}`, cause });
this[_a5] = true;
this.prompt = prompt;
}
static isInstance(error) {
return AISDKError.hasMarker(error, marker5);
}
};
_a5 = symbol5;
var name5 = "AI_InvalidResponseDataError";
var marker6 = `vercel.ai.error.${name5}`;
var symbol6 = Symbol.for(marker6);
var _a6;
var InvalidResponseDataError = class extends AISDKError {
constructor({
data,
message = `Invalid response data: ${JSON.stringify(data)}.`
}) {
super({ name: name5, message });
this[_a6] = true;
this.data = data;
}
static isInstance(error) {
return AISDKError.hasMarker(error, marker6);
}
};
_a6 = symbol6;
var name6 = "AI_JSONParseError";
var marker7 = `vercel.ai.error.${name6}`;
var symbol7 = Symbol.for(marker7);
var _a7;
var JSONParseError = class extends AISDKError {
constructor({ text, cause }) {
super({
name: name6,
message: `JSON parsing failed: Text: ${text}.
Error message: ${getErrorMessage(cause)}`,
cause
});
this[_a7] = true;
this.text = text;
}
static isInstance(error) {
return AISDKError.hasMarker(error, marker7);
}
};
_a7 = symbol7;
var name7 = "AI_LoadAPIKeyError";
var marker8 = `vercel.ai.error.${name7}`;
var symbol8 = Symbol.for(marker8);
var _a8;
var LoadAPIKeyError = class extends AISDKError {
// used in isInstance
constructor({ message }) {
super({ name: name7, message });
this[_a8] = true;
}
static isInstance(error) {
return AISDKError.hasMarker(error, marker8);
}
};
_a8 = symbol8;
var name8 = "AI_LoadSettingError";
var marker9 = `vercel.ai.error.${name8}`;
var symbol9 = Symbol.for(marker9);
var _a9;
_a9 = symbol9;
var name9 = "AI_NoContentGeneratedError";
var marker10 = `vercel.ai.error.${name9}`;
var symbol10 = Symbol.for(marker10);
var _a10;
_a10 = symbol10;
var name10 = "AI_NoSuchModelError";
var marker11 = `vercel.ai.error.${name10}`;
var symbol11 = Symbol.for(marker11);
var _a11;
_a11 = symbol11;
var name11 = "AI_TooManyEmbeddingValuesForCallError";
var marker12 = `vercel.ai.error.${name11}`;
var symbol12 = Symbol.for(marker12);
var _a12;
_a12 = symbol12;
var name12 = "AI_TypeValidationError";
var marker13 = `vercel.ai.error.${name12}`;
var symbol13 = Symbol.for(marker13);
var _a13;
var _TypeValidationError = class _TypeValidationError2 extends AISDKError {
constructor({ value, cause }) {
super({
name: name12,
message: `Type validation failed: Value: ${JSON.stringify(value)}.
Error message: ${getErrorMessage(cause)}`,
cause
});
this[_a13] = true;
this.value = value;
}
static isInstance(error) {
return AISDKError.hasMarker(error, marker13);
}
/**
* Wraps an error into a TypeValidationError.
* If the cause is already a TypeValidationError with the same value, it returns the cause.
* Otherwise, it creates a new TypeValidationError.
*
* @param {Object} params - The parameters for wrapping the error.
* @param {unknown} params.value - The value that failed validation.
* @param {unknown} params.cause - The original error or cause of the validation failure.
* @returns {TypeValidationError} A TypeValidationError instance.
*/
static wrap({
value,
cause
}) {
return _TypeValidationError2.isInstance(cause) && cause.value === value ? cause : new _TypeValidationError2({ value, cause });
}
};
_a13 = symbol13;
var TypeValidationError = _TypeValidationError;
var name13 = "AI_UnsupportedFunctionalityError";
var marker14 = `vercel.ai.error.${name13}`;
var symbol14 = Symbol.for(marker14);
var _a14;
var UnsupportedFunctionalityError = class extends AISDKError {
constructor({
functionality,
message = `'${functionality}' functionality not supported.`
}) {
super({ name: name13, message });
this[_a14] = true;
this.functionality = functionality;
}
static isInstance(error) {
return AISDKError.hasMarker(error, marker14);
}
};
_a14 = symbol14;
// node_modules/.pnpm/eventsource-parser@3.0.3/node_modules/eventsource-parser/dist/index.js
var ParseError = class extends Error {
constructor(message, options) {
super(message), this.name = "ParseError", this.type = options.type, this.field = options.field, this.value = options.value, this.line = options.line;
}
};
function noop(_arg) {
}
function createParser(callbacks) {
if (typeof callbacks == "function")
throw new TypeError(
"`callbacks` must be an object, got a function instead. Did you mean `{onEvent: fn}`?"
);
const { onEvent = noop, onError = noop, onRetry = noop, onComment } = callbacks;
let incompleteLine = "", isFirstChunk = true, id, data = "", eventType = "";
function feed(newChunk) {
const chunk = isFirstChunk ? newChunk.replace(/^\xEF\xBB\xBF/, "") : newChunk, [complete, incomplete] = splitLines(`${incompleteLine}${chunk}`);
for (const line of complete)
parseLine(line);
incompleteLine = incomplete, isFirstChunk = false;
}
function parseLine(line) {
if (line === "") {
dispatchEvent();
return;
}
if (line.startsWith(":")) {
onComment && onComment(line.slice(line.startsWith(": ") ? 2 : 1));
return;
}
const fieldSeparatorIndex = line.indexOf(":");
if (fieldSeparatorIndex !== -1) {
const field = line.slice(0, fieldSeparatorIndex), offset = line[fieldSeparatorIndex + 1] === " " ? 2 : 1, value = line.slice(fieldSeparatorIndex + offset);
processField(field, value, line);
return;
}
processField(line, "", line);
}
function processField(field, value, line) {
switch (field) {
case "event":
eventType = value;
break;
case "data":
data = `${data}${value}
`;
break;
case "id":
id = value.includes("\0") ? void 0 : value;
break;
case "retry":
/^\d+$/.test(value) ? onRetry(parseInt(value, 10)) : onError(
new ParseError(`Invalid \`retry\` value: "${value}"`, {
type: "invalid-retry",
value,
line
})
);
break;
default:
onError(
new ParseError(
`Unknown field "${field.length > 20 ? `${field.slice(0, 20)}\u2026` : field}"`,
{ type: "unknown-field", field, value, line }
)
);
break;
}
}
function dispatchEvent() {
data.length > 0 && onEvent({
id,
event: eventType || void 0,
// If the data buffer's last character is a U+000A LINE FEED (LF) character,
// then remove the last character from the data buffer.
data: data.endsWith(`
`) ? data.slice(0, -1) : data
}), id = void 0, data = "", eventType = "";
}
function reset(options = {}) {
incompleteLine && options.consume && parseLine(incompleteLine), isFirstChunk = true, id = void 0, data = "", eventType = "", incompleteLine = "";
}
return { feed, reset };
}
function splitLines(chunk) {
const lines = [];
let incompleteLine = "", searchIndex = 0;
for (; searchIndex < chunk.length; ) {
const crIndex = chunk.indexOf("\r", searchIndex), lfIndex = chunk.indexOf(`
`, searchIndex);
let lineEnd = -1;
if (crIndex !== -1 && lfIndex !== -1 ? lineEnd = Math.min(crIndex, lfIndex) : crIndex !== -1 ? lineEnd = crIndex : lfIndex !== -1 && (lineEnd = lfIndex), lineEnd === -1) {
incompleteLine = chunk.slice(searchIndex);
break;
} else {
const line = chunk.slice(searchIndex, lineEnd);
lines.push(line), searchIndex = lineEnd + 1, chunk[searchIndex - 1] === "\r" && chunk[searchIndex] === `
` && searchIndex++;
}
}
return [lines, incompleteLine];
}
// node_modules/.pnpm/eventsource-parser@3.0.3/node_modules/eventsource-parser/dist/stream.js
var EventSourceParserStream = class extends TransformStream {
constructor({ onError, onRetry, onComment } = {}) {
let parser;
super({
start(controller) {
parser = createParser({
onEvent: (event) => {
controller.enqueue(event);
},
onError(error) {
onError === "terminate" ? controller.error(error) : typeof onError == "function" && onError(error);
},
onRetry,
onComment
});
},
transform(chunk) {
parser.feed(chunk);
}
});
}
};
// node_modules/.pnpm/@ai-sdk+provider-utils@3.0.1_zod@3.25.76/node_modules/@ai-sdk/provider-utils/dist/index.mjs
var z4 = __toESM(require("zod/v4"), 1);
// node_modules/.pnpm/zod-to-json-schema@3.24.6_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/Options.js
var ignoreOverride = Symbol("Let zodToJsonSchema decide on which parser to use");
// node_modules/.pnpm/zod-to-json-schema@3.24.6_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/selectParser.js
var import_zod3 = require("zod");
// node_modules/.pnpm/zod-to-json-schema@3.24.6_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/parsers/array.js
var import_zod = require("zod");
// node_modules/.pnpm/zod-to-json-schema@3.24.6_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/parsers/record.js
var import_zod2 = require("zod");
// node_modules/.pnpm/zod-to-json-schema@3.24.6_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/parsers/string.js
var ALPHA_NUMERIC = new Set("ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvxyz0123456789");
// node_modules/.pnpm/@ai-sdk+provider-utils@3.0.1_zod@3.25.76/node_modules/@ai-sdk/provider-utils/dist/index.mjs
function combineHeaders(...headers) {
return headers.reduce(
(combinedHeaders, currentHeaders) => __spreadValues(__spreadValues({}, combinedHeaders), currentHeaders != null ? currentHeaders : {}),
{}
);
}
function extractResponseHeaders(response) {
return Object.fromEntries([...response.headers]);
}
var createIdGenerator = ({
prefix,
size = 16,
alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
separator = "-"
} = {}) => {
const generator = () => {
const alphabetLength = alphabet.length;
const chars = new Array(size);
for (let i = 0; i < size; i++) {
chars[i] = alphabet[Math.random() * alphabetLength | 0];
}
return chars.join("");
};
if (prefix == null) {
return generator;
}
if (alphabet.includes(separator)) {
throw new InvalidArgumentError({
argument: "separator",
message: `The separator "${separator}" must not be part of the alphabet "${alphabet}".`
});
}
return () => `${prefix}${separator}${generator()}`;
};
var generateId = createIdGenerator();
function isAbortError(error) {
return (error instanceof Error || error instanceof DOMException) && (error.name === "AbortError" || error.name === "ResponseAborted" || // Next.js
error.name === "TimeoutError");
}
var FETCH_FAILED_ERROR_MESSAGES = ["fetch failed", "failed to fetch"];
function handleFetchError({
error,
url,
requestBodyValues
}) {
if (isAbortError(error)) {
return error;
}
if (error instanceof TypeError && FETCH_FAILED_ERROR_MESSAGES.includes(error.message.toLowerCase())) {
const cause = error.cause;
if (cause != null) {
return new APICallError({
message: `Cannot connect to API: ${cause.message}`,
cause,
url,
requestBodyValues,
isRetryable: true
// retry when network error
});
}
}
return error;
}
function removeUndefinedEntries(record) {
return Object.fromEntries(
Object.entries(record).filter(([_key, value]) => value != null)
);
}
function loadApiKey({
apiKey,
environmentVariableName,
apiKeyParameterName = "apiKey",
description
}) {
if (typeof apiKey === "string") {
return apiKey;
}
if (apiKey != null) {
throw new LoadAPIKeyError({
message: `${description} API key must be a string.`
});
}
if (typeof process === "undefined") {
throw new LoadAPIKeyError({
message: `${description} API key is missing. Pass it using the '${apiKeyParameterName}' parameter. Environment variables is not supported in this environment.`
});
}
apiKey = process.env[environmentVariableName];
if (apiKey == null) {
throw new LoadAPIKeyError({
message: `${description} API key is missing. Pass it using the '${apiKeyParameterName}' parameter or the ${environmentVariableName} environment variable.`
});
}
if (typeof apiKey !== "string") {
throw new LoadAPIKeyError({
message: `${description} API key must be a string. The value of the ${environmentVariableName} environment variable is not a string.`
});
}
return apiKey;
}
var suspectProtoRx = /"__proto__"\s*:/;
var suspectConstructorRx = /"constructor"\s*:/;
function _parse(text) {
const obj = JSON.parse(text);
if (obj === null || typeof obj !== "object") {
return obj;
}
if (suspectProtoRx.test(text) === false && suspectConstructorRx.test(text) === false) {
return obj;
}
return filter(obj);
}
function filter(obj) {
let next = [obj];
while (next.length) {
const nodes = next;
next = [];
for (const node of nodes) {
if (Object.prototype.hasOwnProperty.call(node, "__proto__")) {
throw new SyntaxError("Object contains forbidden prototype property");
}
if (Object.prototype.hasOwnProperty.call(node, "constructor") && Object.prototype.hasOwnProperty.call(node.constructor, "prototype")) {
throw new SyntaxError("Object contains forbidden prototype property");
}
for (const key in node) {
const value = node[key];
if (value && typeof value === "object") {
next.push(value);
}
}
}
}
return obj;
}
function secureJsonParse(text) {
const { stackTraceLimit } = Error;
Error.stackTraceLimit = 0;
try {
return _parse(text);
} finally {
Error.stackTraceLimit = stackTraceLimit;
}
}
var validatorSymbol = Symbol.for("vercel.ai.validator");
function validator(validate) {
return { [validatorSymbol]: true, validate };
}
function isValidator(value) {
return typeof value === "object" && value !== null && validatorSymbol in value && value[validatorSymbol] === true && "validate" in value;
}
function asValidator(value) {
return isValidator(value) ? value : standardSchemaValidator(value);
}
function standardSchemaValidator(standardSchema) {
return validator(async (value) => {
const result = await standardSchema["~standard"].validate(value);
return result.issues == null ? { success: true, value: result.value } : {
success: false,
error: new TypeValidationError({
value,
cause: result.issues
})
};
});
}
async function validateTypes({
value,
schema
}) {
const result = await safeValidateTypes({ value, schema });
if (!result.success) {
throw TypeValidationError.wrap({ value, cause: result.error });
}
return result.value;
}
async function safeValidateTypes({
value,
schema
}) {
const validator2 = asValidator(schema);
try {
if (validator2.validate == null) {
return { success: true, value, rawValue: value };
}
const result = await validator2.validate(value);
if (result.success) {
return { success: true, value: result.value, rawValue: value };
}
return {
success: false,
error: TypeValidationError.wrap({ value, cause: result.error }),
rawValue: value
};
} catch (error) {
return {
success: false,
error: TypeValidationError.wrap({ value, cause: error }),
rawValue: value
};
}
}
async function parseJSON({
text,
schema
}) {
try {
const value = secureJsonParse(text);
if (schema == null) {
return value;
}
return validateTypes({ value, schema });
} catch (error) {
if (JSONParseError.isInstance(error) || TypeValidationError.isInstance(error)) {
throw error;
}
throw new JSONParseError({ text, cause: error });
}
}
async function safeParseJSON({
text,
schema
}) {
try {
const value = secureJsonParse(text);
if (schema == null) {
return { success: true, value, rawValue: value };
}
return await safeValidateTypes({ value, schema });
} catch (error) {
return {
success: false,
error: JSONParseError.isInstance(error) ? error : new JSONParseError({ text, cause: error }),
rawValue: void 0
};
}
}
function isParsableJson(input) {
try {
secureJsonParse(input);
return true;
} catch (e) {
return false;
}
}
function parseJsonEventStream({
stream,
schema
}) {
return stream.pipeThrough(new TextDecoderStream()).pipeThrough(new EventSourceParserStream()).pipeThrough(
new TransformStream({
async transform({ data }, controller) {
if (data === "[DONE]") {
return;
}
controller.enqueue(await safeParseJSON({ text: data, schema }));
}
})
);
}
var getOriginalFetch2 = () => globalThis.fetch;
var postJsonToApi = async ({
url,
headers,
body,
failedResponseHandler,
successfulResponseHandler,
abortSignal,
fetch
}) => postToApi({
url,
headers: __spreadValues({
"Content-Type": "application/json"
}, headers),
body: {
content: JSON.stringify(body),
values: body
},
failedResponseHandler,
successfulResponseHandler,
abortSignal,
fetch
});
var postToApi = async ({
url,
headers = {},
body,
successfulResponseHandler,
failedResponseHandler,
abortSignal,
fetch = getOriginalFetch2()
}) => {
try {
const response = await fetch(url, {
method: "POST",
headers: removeUndefinedEntries(headers),
body: body.content,
signal: abortSignal
});
const responseHeaders = extractResponseHeaders(response);
if (!response.ok) {
let errorInformation;
try {
errorInformation = await failedResponseHandler({
response,
url,
requestBodyValues: body.values
});
} catch (error) {
if (isAbortError(error) || APICallError.isInstance(error)) {
throw error;
}
throw new APICallError({
message: "Failed to process error response",
cause: error,
statusCode: response.status,
url,
responseHeaders,
requestBodyValues: body.values
});
}
throw errorInformation.value;
}
try {
return await successfulResponseHandler({
response,
url,
requestBodyValues: body.values
});
} catch (error) {
if (error instanceof Error) {
if (isAbortError(error) || APICallError.isInstance(error)) {
throw error;
}
}
throw new APICallError({
message: "Failed to process successful response",
cause: error,
statusCode: response.status,
url,
responseHeaders,
requestBodyValues: body.values
});
}
} catch (error) {
throw handleFetchError({ error, url, requestBodyValues: body.values });
}
};
var createJsonErrorResponseHandler = ({
errorSchema,
errorToMessage,
isRetryable
}) => async ({ response, url, requestBodyValues }) => {
const responseBody = await response.text();
const responseHeaders = extractResponseHeaders(response);
if (responseBody.trim() === "") {
return {
responseHeaders,
value: new APICallError({
message: response.statusText,
url,
requestBodyValues,
statusCode: response.status,
responseHeaders,
responseBody,
isRetryable: isRetryable == null ? void 0 : isRetryable(response)
})
};
}
try {
const parsedError = await parseJSON({
text: responseBody,
schema: errorSchema
});
return {
responseHeaders,
value: new APICallError({
message: errorToMessage(parsedError),
url,
requestBodyValues,
statusCode: response.status,
responseHeaders,
responseBody,
data: parsedError,
isRetryable: isRetryable == null ? void 0 : isRetryable(response, parsedError)
})
};
} catch (parseError) {
return {
responseHeaders,
value: new APICallError({
message: response.statusText,
url,
requestBodyValues,
statusCode: response.status,
responseHeaders,
responseBody,
isRetryable: isRetryable == null ? void 0 : isRetryable(response)
})
};
}
};
var createEventSourceResponseHandler = (chunkSchema) => async ({ response }) => {
const responseHeaders = extractResponseHeaders(response);
if (response.body == null) {
throw new EmptyResponseBodyError({});
}
return {
responseHeaders,
value: parseJsonEventStream({
stream: response.body,
schema: chunkSchema
})
};
};
var createJsonResponseHandler = (responseSchema) => async ({ response, url, requestBodyValues }) => {
const responseBody = await response.text();
const parsedResult = await safeParseJSON({
text: responseBody,
schema: responseSchema
});
const responseHeaders = extractResponseHeaders(response);
if (!parsedResult.success) {
throw new APICallError({
message: "Invalid JSON response",
cause: parsedResult.error,
statusCode: response.status,
responseHeaders,
responseBody,
url,
requestBodyValues
});
}
return {
responseHeaders,
value: parsedResult.value,
rawValue: parsedResult.rawValue
};
};
var schemaSymbol = Symbol.for("vercel.ai.schema");
var { btoa, atob } = globalThis;
function convertUint8ArrayToBase64(array) {
let latin1string = "";
for (let i = 0; i < array.length; i++) {
latin1string += String.fromCodePoint(array[i]);
}
return btoa(latin1string);
}
function withoutTrailingSlash(url) {
return url == null ? void 0 : url.replace(/\/$/, "");
}
// src/schemas/reasoning-details.ts
var import_v4 = require("zod/v4");
var ReasoningDetailSummarySchema = import_v4.z.object({
type: import_v4.z.literal("reasoning.summary" /* Summary */),
summary: import_v4.z.string()
});
var ReasoningDetailEncryptedSchema = import_v4.z.object({
type: import_v4.z.literal("reasoning.encrypted" /* Encrypted */),
data: import_v4.z.string()
});
var ReasoningDetailTextSchema = import_v4.z.object({
type: import_v4.z.literal("reasoning.text" /* Text */),
text: import_v4.z.string().nullish(),
signature: import_v4.z.string().nullish()
});
var ReasoningDetailUnionSchema = import_v4.z.union([
ReasoningDetailSummarySchema,
ReasoningDetailEncryptedSchema,
ReasoningDetailTextSchema
]);
var ReasoningDetailsWithUnknownSchema = import_v4.z.union([
ReasoningDetailUnionSchema,
import_v4.z.unknown().transform(() => null)
]);
var ReasoningDetailArraySchema = import_v4.z.array(ReasoningDetailsWithUnknownSchema).transform((d) => d.filter((d2) => !!d2));
// src/schemas/error-response.ts
var import_v42 = require("zod/v4");
var OpenRouterErrorResponseSchema = import_v42.z.object({
error: import_v42.z.object({
code: import_v42.z.union([import_v42.z.string(), import_v42.z.number()]).nullable().optional().default(null),
message: import_v42.z.string(),
type: import_v42.z.string().nullable().optional().default(null),
param: import_v42.z.any().nullable().optional().default(null)
})
});
var openrouterFailedResponseHandler = createJsonErrorResponseHandler({
errorSchema: OpenRouterErrorResponseSchema,
errorToMessage: (data) => data.error.message
});
// src/utils/map-finish-reason.ts
function mapOpenRouterFinishReason(finishReason) {
switch (finishReason) {
case "stop":
return "stop";
case "length":
return "length";
case "content_filter":
return "content-filter";
case "function_call":
case "tool_calls":
return "tool-calls";
default:
return "unknown";
}
}
// src/chat/is-url.ts
function isUrl({
url,
protocols
}) {
try {
const urlObj = new URL(url);
return protocols.has(urlObj.protocol);
} catch (_) {
return false;
}
}
// src/chat/file-url-utils.ts
function getFileUrl({
part,
defaultMediaType
}) {
var _a15, _b;
if (part.data instanceof Uint8Array) {
const base64 = convertUint8ArrayToBase64(part.data);
return `data:${(_a15 = part.mediaType) != null ? _a15 : defaultMediaType};base64,${base64}`;
}
const stringUrl = part.data.toString();
if (isUrl({
url: stringUrl,
protocols: /* @__PURE__ */ new Set(["http:", "https:"])
})) {
return stringUrl;
}
return stringUrl.startsWith("data:") ? stringUrl : `data:${(_b = part.mediaType) != null ? _b : defaultMediaType};base64,${stringUrl}`;
}
// src/chat/convert-to-openrouter-chat-messages.ts
function getCacheControl(providerMetadata) {
var _a15, _b, _c;
const anthropic = providerMetadata == null ? void 0 : providerMetadata.anthropic;
const openrouter2 = providerMetadata == null ? void 0 : providerMetadata.openrouter;
return (_c = (_b = (_a15 = openrouter2 == null ? void 0 : openrouter2.cacheControl) != null ? _a15 : openrouter2 == null ? void 0 : openrouter2.cache_control) != null ? _b : anthropic == null ? void 0 : anthropic.cacheControl) != null ? _c : anthropic == null ? void 0 : anthropic.cache_control;
}
function convertToOpenRouterChatMessages(prompt) {
var _a15, _b, _c;
const messages = [];
for (const { role, content, providerOptions } of prompt) {
switch (role) {
case "system": {
messages.push({
role: "system",
content,
cache_control: getCacheControl(providerOptions)
});
break;
}
case "user": {
if (content.length === 1 && ((_a15 = content[0]) == null ? void 0 : _a15.type) === "text") {
const cacheControl = (_b = getCacheControl(providerOptions)) != null ? _b : getCacheControl(content[0].providerOptions);
const contentWithCacheControl = cacheControl ? [
{
type: "text",
text: content[0].text,
cache_control: cacheControl
}
] : content[0].text;
messages.push({
role: "user",
content: contentWithCacheControl
});
break;
}
const messageCacheControl = getCacheControl(providerOptions);
const contentParts = content.map(
(part) => {
var _a16, _b2, _c2, _d, _e, _f;
const cacheControl = (_a16 = getCacheControl(part.providerOptions)) != null ? _a16 : messageCacheControl;
switch (part.type) {
case "text":
return {
type: "text",
text: part.text,
// For text parts, only use part-specific cache control
cache_control: cacheControl
};
case "file": {
if ((_b2 = part.mediaType) == null ? void 0 : _b2.startsWith("image/")) {
const url = getFileUrl({
part,
defaultMediaType: "image/jpeg"
});
return {
type: "image_url",
image_url: {
url
},
// For image parts, use part-specific or message-level cache control
cache_control: cacheControl
};
}
const fileName = String(
(_f = (_e = (_d = (_c2 = part.providerOptions) == null ? void 0 : _c2.openrouter) == null ? void 0 : _d.filename) != null ? _e : part.filename) != null ? _f : ""
);
const fileData = getFileUrl({
part,
defaultMediaType: "application/pdf"
});
if (isUrl({
url: fileData,
protocols: /* @__PURE__ */ new Set(["http:", "https:"])
})) {
return {
type: "file",
file: {
filename: fileName,
file_data: fileData
}
};
}
return {
type: "file",
file: {
filename: fileName,
file_data: fileData
},
cache_control: cacheControl
};
}
default: {
return {
type: "text",
text: "",
cache_control: cacheControl
};
}
}
}
);
messages.push({
role: "user",
content: contentParts
});
break;
}
case "assistant": {
let text = "";
let reasoning = "";
const reasoningDetails = [];
const toolCalls = [];
for (const part of content) {
switch (part.type) {
case "text": {
text += part.text;
break;
}
case "tool-call": {
toolCalls.push({
id: part.toolCallId,
type: "function",
function: {
name: part.toolName,
arguments: JSON.stringify(part.input)
}
});
break;
}
case "reasoning": {
reasoning += part.text;
reasoningDetails.push({
type: "reasoning.text" /* Text */,
text: part.text
});
break;
}
case "file":
break;
default: {
break;
}
}
}
messages.push({
role: "assistant",
content: text,
tool_calls: toolCalls.length > 0 ? toolCalls : void 0,
reasoning: reasoning || void 0,
reasoning_details: reasoningDetails.length > 0 ? reasoningDetails : void 0,
cache_control: getCacheControl(providerOptions)
});
break;
}
case "tool": {
for (const toolResponse of content) {
const content2 = getToolResultContent(toolResponse);
messages.push({
role: "tool",
tool_call_id: toolResponse.toolCallId,
content: content2,
cache_control: (_c = getCacheControl(providerOptions)) != null ? _c : getCacheControl(toolResponse.providerOptions)
});
}
break;
}
default: {
break;
}
}
}
return messages;
}
function getToolResultContent(input) {
return input.output.type === "text" ? input.output.value : JSON.stringify(input.output.value);
}
// src/chat/get-tool-choice.ts
var import_v43 = require("zod/v4");
var ChatCompletionToolChoiceSchema = import_v43.z.union([
import_v43.z.literal("auto"),
import_v43.z.literal("none"),
import_v43.z.literal("required"),
import_v43.z.object({
type: import_v43.z.literal("function"),
function: import_v43.z.object({
name: import_v43.z.string()
})
})
]);
function getChatCompletionToolChoice(toolChoice) {
switch (toolChoice.type) {
case "auto":
case "none":
case "required":
return toolChoice.type;
case "tool": {
return {
type: "function",
function: { name: toolChoice.toolName }
};
}
default: {
toolChoice;
throw new Error(`Invalid tool choice type: ${toolChoice}`);
}
}
}
// src/chat/schemas.ts
var import_v44 = require("zod/v4");
var OpenRouterChatCompletionBaseResponseSchema = import_v44.z.object({
id: import_v44.z.string().optional(),
model: import_v44.z.string().optional(),
provider: import_v44.z.string().optional(),
usage: import_v44.z.object({
prompt_tokens: import_v44.z.number(),
prompt_tokens_details: import_v44.z.object({
cached_tokens: import_v44.z.number()
}).nullish(),
completion_tokens: import_v44.z.number(),
completion_tokens_details: import_v44.z.object({
reasoning_tokens: import_v44.z.number()
}).nullish(),
total_tokens: import_v44.z.number(),
cost: import_v44.z.number().optional(),
cost_details: import_v44.z.object({
upstream_inference_cost: import_v44.z.number().nullish()
}).nullish()
}).nullish()
});
var OpenRouterNonStreamChatCompletionResponseSchema = OpenRouterChatCompletionBaseResponseSchema.extend({
choices: import_v44.z.array(
import_v44.z.object({
message: import_v44.z.object({
role: import_v44.z.literal("assistant"),
content: import_v44.z.string().nullable().optional(),
reasoning: import_v44.z.string().nullable().optional(),
reasoning_details: ReasoningDetailArraySchema.nullish(),
tool_calls: import_v44.z.array(
import_v44.z.object({
id: import_v44.z.string().optional().nullable(),
type: import_v44.z.literal("function"),
function: import_v44.z.object({
name: import_v44.z.string(),
arguments: import_v44.z.string()
})
})
).optional(),
annotations: import_v44.z.array(
import_v44.z.object({
type: import_v44.z.enum(["url_citation"]),
url_citation: import_v44.z.object({
end_index: import_v44.z.number(),
start_index: import_v44.z.number(),
title: import_v44.z.string(),
url: import_v44.z.string(),
content: import_v44.z.string().optional()
})
})
).nullish()
}),
index: import_v44.z.number().nullish(),
logprobs: import_v44.z.object({
content: import_v44.z.array(
import_v44.z.object({
token: import_v44.z.string(),
logprob: import_v44.z.number(),
top_logprobs: import_v44.z.array(
import_v44.z.object({
token: import_v44.z.string(),
logprob: import_v44.z.number()
})
)
})
).nullable()
}).nullable().optional(),
finish_reason: import_v44.z.string().optional().nullable()
})
)
});
var OpenRouterStreamChatCompletionChunkSchema = import_v44.z.union([
OpenRouterChatCompletionBaseResponseSchema.extend({
choices: import_v44.z.array(
import_v44.z.object({
delta: import_v44.z.object({
role: import_v44.z.enum(["assistant"]).optional(),
content: import_v44.z.string().nullish(),
reasoning: import_v44.z.string().nullish().optional(),
reasoning_details: ReasoningDetailArraySchema.nullish(),
tool_calls: import_v44.z.array(
import_v44.z.object({
index: import_v44.z.number().nullish(),
id: import_v44.z.string().nullish(),
type: import_v44.z.literal("function").optional(),
function: import_v44.z.object({
name: import_v44.z.string().nullish(),
arguments: import_v44.z.string().nullish()
})
})
).nullish(),
annotations: import_v44.z.array(
import_v44.z.object({
type: import_v44.z.enum(["url_citation"]),
url_citation: import_v44.z.object({
end_index: import_v44.z.number(),
start_index: import_v44.z.number(),
title: import_v44.z.string(),
url: import_v44.z.string(),
content: import_v44.z.string().optional()
})
})
).nullish()
}).nullish(),
logprobs: import_v44.z.object({
content: import_v44.z.array(
import_v44.z.object({
token: import_v44.z.string(),
logprob: import_v44.z.number(),
top_logprobs: import_v44.z.array(
import_v44.z.object({
token: import_v44.z.string(),
logprob: import_v44.z.number()
})
)
})
).nullable()
}).nullish(),
finish_reason: import_v44.z.string().nullable().optional(),
index: import_v44.z.number().nullish()
})
)
}),
OpenRouterErrorResponseSchema
]);
// src/chat/index.ts
var OpenRouterChatLanguageModel = class {
constructor(modelId, settings, config) {
this.specificationVersion = "v2";
this.provider = "openrouter";
this.defaultObjectGenerationMode = "tool";
this.supportedUrls = {
"image/*": [
/^data:image\/[a-zA-Z]+;base64,/,
/^https?:\/\/.+\.(jpg|jpeg|png|gif|webp)$/i
],
// 'text/*': [/^data:text\//, /^https?:\/\/.+$/],
"application/*": [/^data:application\//, /^https?:\/\/.+$/]
};
this.modelId = modelId;
this.settings = settings;
this.config = config;
}
getArgs({
prompt,
maxOutputTokens,
temperature,
topP,
frequencyPenalty,
presencePenalty,
seed,
stopSequences,
responseFormat,
topK,
tools,
toolChoice
}) {
var _a15;
const baseArgs = __spreadValues(__spreadValues({
// model id:
model: this.modelId,
models: this.settings.models,
// model specific settings:
logit_bias: this.settings.logitBias,
logprobs: this.settings.logprobs === true || typeof this.settings.logprobs === "number" ? true : void 0,
top_logprobs: typeof this.settings.logprobs === "number" ? this.settings.logprobs : typeof this.settings.logprobs === "boolean" ? this.settings.logprobs ? 0 : void 0 : void 0,
user: this.settings.user,
parallel_tool_calls: this.settings.parallelToolCalls,
// standardized settings:
max_tokens: maxOutputTokens,
temperature,
top_p: topP,
frequency_penalty: frequencyPenalty,
presence_penalty: presencePenalty,
seed,
stop: stopSequences,
response_format: responseFormat,
top_k: topK,
// messages:
messages: convertToOpenRouterChatMessages(prompt),
// OpenRouter specific settings:
include_reasoning: this.settings.includeReasoning,
reasoning: this.settings.reasoning,
usage: this.settings.usage,
// Web search settings:
plugins: this.settings.plugins,
web_search_options: this.settings.web_search_options,
// Provider routing settings:
provider: this.settings.provider
}, this.config.extraBody), this.settings.extraBody);
if ((responseFormat == null ? void 0 : responseFormat.type) === "json" && responseFormat.schema != null) {
return __spreadProps(__spreadValues({}, baseArgs), {
response_format: {
type: "json_schema",
json_schema: __spreadValues({
schema: responseFormat.schema,
strict: true,
name: (_a15 = responseFormat.name) != null ? _a15 : "response"
}, responseFormat.description && {
description: responseFormat.description
})
}
});
}
if (tools && tools.length > 0) {
const mappedTools = tools.filter((tool) => tool.type === "function").map((tool) => ({
type: "function",
function: {
name: tool.name,
description: tool.type,
parameters: tool.inputSchema
}
}));
return __spreadProps(__spreadValues({}, baseArgs), {
tools: mappedTools,
tool_choice: toolChoice ? getChatCompletionToolChoice(toolChoice) : void 0
});
}
return baseArgs;
}
async doGenerate(options) {
var _a15, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x;
const providerOptions = options.providerOptions || {};
const openrouterOptions = providerOptions.openrouter || {};
const args = __spreadValues(__spreadValues({}, this.getArgs(options)), openrouterOptions);
const { value: response, responseHeaders } = await postJsonToApi({
url: this.config.url({
path: "/chat/completions",
modelId: this.modelId
}),
headers: combineHeaders(this.config.headers(), options.headers),
body: args,
failedResponseHandler: openrouterFailedResponseHandler,
successfulResponseHandler: createJsonResponseHandler(
OpenRouterNonStreamChatCompletionResponseSchema
),
abortSignal: options.abortSignal,
fetch: this.config.fetch
});
const choice = response.choices[0];
if (!choice) {
throw new Error("No choice in response");
}
const usageInfo = response.usage ? {
inputTokens: (_a15 = response.usage.prompt_tokens) != null ? _a15 : 0,
outputTokens: (_b = response.usage.completion_tokens) != null ? _b : 0,
totalTokens: ((_c = response.usage.prompt_tokens) != null ? _c : 0) + ((_d = response.usage.completion_tokens) != null ? _d : 0),
reasoningTokens: (_f = (_e = response.usage.completion_tokens_details) == null ? void 0 : _e.reasoning_tokens) != null ? _f : 0,
cachedInputTokens: (_h = (_g = response.usage.prompt_tokens_details) == null ? void 0 : _g.cached_tokens) != null ? _h : 0
} : {
inputTokens: 0,
outputTokens: 0,
totalTokens: 0,
reasoningTokens: 0,
cachedInputTokens: 0
};
const reasoningDetails = (_i = choice.message.reasoning_details) != null ? _i : [];
const reasoning = reasoningDetails.length > 0 ? reasoningDetails.map((detail) => {
switch (detail.type) {
case "reasoning.text" /* Text */: {
if (detail.text) {
return {
type: "reasoning",
text: detail.text
};
}
break;
}
case "reasoning.summary" /* Summary */: {
if (detail.summary) {
return {
type: "reasoning",
text: detail.summary
};
}
break;
}
case "reasoning.encrypted" /* Encrypted */: {
if (detail.data) {
return {
type: "reasoning",
text: "[REDACTED]"
};
}
break;
}
default: {
detail;
}
}
return null;
}).filter((p) => p !== null) : choice.message.reasoning ? [
{
type: "reasoning",
text: choice.message.reasoning
}
] : [];
const content = [];
content.push(...reasoning);
if (choice.message.content) {
content.push({
type: "text",
text: choice.message.content
});
}
if (choice.message.tool_calls) {
for (const toolCall of choice.message.tool_calls) {
content.push({
type: "tool-call",
toolCallId: (_j = toolCall.id) != null ? _j : generateId(),
toolName: toolCall.function.name,
input: toolCall.function.arguments
});
}
}
if (choice.message.annotations) {
for (const annotation of choice.message.annotations) {
if (annotation.type === "url_citation") {
content.push({
type: "source",
sourceType: "url",
id: annotation.url_citation.url,
url: annotation.url_citation.url,
title: annotation.url_citation.title,
providerMetadata: {
openrouter: {
content: annotation.url_citation.content || ""
}
}
});
}
}
}
return {
content,
finishReason: mapOpenRouterFinishReason(choice.finish_reason),
usage: usageInfo,
warnings: [],
providerMetadata: {
openrouter: {
provider: (_k = response.provider) != null ? _k : "",
usage: {
promptTokens: (_l = usageInfo.inputTokens) != null ? _l : 0,
completionTokens: (_m = usageInfo.outputTokens) != null ? _m : 0,
totalTokens: (_n = usageInfo.totalTokens) != null ? _n : 0,
cost: (_o = response.usage) == null ? void 0 : _o.cost,
promptTokensDetails: {
cachedTokens: (_