UNPKG

@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,556 lines (1,536 loc) 75.4 kB
"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/internal/index.ts var index_exports = {}; __export(index_exports, { OpenRouterChatLanguageModel: () => OpenRouterChatLanguageModel, OpenRouterCompletionLanguageModel: () => OpenRouterCompletionLanguageModel }); 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; _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) ); } 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); } // 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 openrouter = providerMetadata == null ? void 0 : providerMetadata.openrouter; return (_c = (_b = (_a15 = openrouter == null ? void 0 : openrouter.cacheControl) != null ? _a15 : openrouter == null ? void 0 : openrouter.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: (_r = (_q = (_p = response.usage) == null ? void 0 : _p.prompt_tokens_details) == null ? void 0 : _q.cached_tokens) != null ? _r : 0 }, completionTokensDetails: { reasoningTokens: (_u = (_t = (_s = response.usage) == null ? void 0 : _s.completion_tokens_details) == null ? void 0 : _t.reasoning_tokens) != null ? _u : 0 }, costDetails: { upstreamInferenceCost: (_x = (_w = (_v = response.usage) == null ? void 0 : _v.cost_details) == null ? void 0 : _w.upstream_inference_cost) != null ? _x : 0 } } } }, request: { body: args }, response: { id: response.id, modelId: response.model, headers: responseHeaders } }; } async doStream(options) { var _a15; 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: __spreadProps(__spreadValues({}, args), { stream: true, // onl