@openrouter/ai-sdk-provider
Version:

6,032 lines • 201 kB
JavaScript
var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __typeError = (msg) => {
throw TypeError(msg);
};
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 __objRest = (source, exclude) => {
var target = {};
for (var prop in source)
if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
target[prop] = source[prop];
if (source != null && __getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(source)) {
if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
target[prop] = source[prop];
}
return target;
};
var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
// node_modules/.pnpm/@ai-sdk+provider@4.0.16/node_modules/@ai-sdk/provider/dist/index.js
var marker = "vercel.ai.error";
var symbol = Symbol.for(marker);
var _a;
var _b;
var AISDKError = class _AISDKError extends (_b = Error, _a = symbol, _b) {
/**
* 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: name162,
message,
cause
}) {
super(message);
this[_a] = true;
this.name = name162;
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 _AISDKError.hasMarker(error, marker);
}
static hasMarker(error, marker17) {
const markerSymbol = Symbol.for(marker17);
return error != null && typeof error === "object" && markerSymbol in error && typeof error[markerSymbol] === "boolean" && error[markerSymbol] === true;
}
};
var name = "AI_APICallError";
var marker2 = `vercel.ai.error.${name}`;
var symbol2 = Symbol.for(marker2);
var _a2;
var _b2;
var APICallError = class extends (_b2 = AISDKError, _a2 = symbol2, _b2) {
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);
}
};
var name2 = "AI_EmptyResponseBodyError";
var marker3 = `vercel.ai.error.${name2}`;
var symbol3 = Symbol.for(marker3);
var _a3;
var _b3;
var EmptyResponseBodyError = class extends (_b3 = AISDKError, _a3 = symbol3, _b3) {
// used in isInstance
constructor({ message = "Empty response body" } = {}) {
super({ name: name2, message });
this[_a3] = true;
}
static isInstance(error) {
return AISDKError.hasMarker(error, marker3);
}
};
var name3 = "AI_EvaluationUnsupportedQuestionTypeError";
var marker4 = `vercel.ai.error.${name3}`;
var symbol4 = Symbol.for(marker4);
var _a4;
var _b4;
var EvaluationUnsupportedQuestionTypeError = class extends (_b4 = AISDKError, _a4 = symbol4, _b4) {
constructor({
questionId,
questionType,
provider,
modelId,
message = `Question "${questionId}" has type "${questionType}", which is not supported by provider "${provider}" and model "${modelId}".`
}) {
super({ name: name3, message });
this[_a4] = true;
this.questionId = questionId;
this.questionType = questionType;
this.provider = provider;
this.modelId = modelId;
}
static isInstance(error) {
return AISDKError.hasMarker(error, marker4);
}
};
function getErrorMessage(error) {
if (error == null) {
return "unknown error";
}
if (typeof error === "string") {
return error;
}
if (error instanceof Error) {
return error.toString();
}
return JSON.stringify(error);
}
var name4 = "AI_InvalidArgumentError";
var marker5 = `vercel.ai.error.${name4}`;
var symbol5 = Symbol.for(marker5);
var _a5;
var _b5;
var InvalidArgumentError = class extends (_b5 = AISDKError, _a5 = symbol5, _b5) {
constructor({
message,
cause,
argument
}) {
super({ name: name4, message, cause });
this[_a5] = true;
this.argument = argument;
}
static isInstance(error) {
return AISDKError.hasMarker(error, marker5);
}
};
var name5 = "AI_InvalidPromptError";
var marker6 = `vercel.ai.error.${name5}`;
var symbol6 = Symbol.for(marker6);
var _a6;
var _b6;
var InvalidPromptError = class extends (_b6 = AISDKError, _a6 = symbol6, _b6) {
constructor({
prompt,
message,
cause
}) {
super({ name: name5, message: `Invalid prompt: ${message}`, cause });
this[_a6] = true;
this.prompt = prompt;
}
static isInstance(error) {
return AISDKError.hasMarker(error, marker6);
}
};
var name6 = "AI_InvalidResponseDataError";
var marker7 = `vercel.ai.error.${name6}`;
var symbol7 = Symbol.for(marker7);
var _a7;
var _b7;
var InvalidResponseDataError = class extends (_b7 = AISDKError, _a7 = symbol7, _b7) {
constructor({
data,
message = `Invalid response data: ${JSON.stringify(data)}.`
}) {
super({ name: name6, message });
this[_a7] = true;
this.data = data;
}
static isInstance(error) {
return AISDKError.hasMarker(error, marker7);
}
};
var name7 = "AI_JSONParseError";
var marker8 = `vercel.ai.error.${name7}`;
var symbol8 = Symbol.for(marker8);
var _a8;
var _b8;
var JSONParseError = class extends (_b8 = AISDKError, _a8 = symbol8, _b8) {
constructor({ text, cause }) {
super({
name: name7,
message: `JSON parsing failed: Text: ${text}.
Error message: ${getErrorMessage(cause)}`,
cause
});
this[_a8] = true;
this.text = text;
}
static isInstance(error) {
return AISDKError.hasMarker(error, marker8);
}
};
var name8 = "AI_LoadAPIKeyError";
var marker9 = `vercel.ai.error.${name8}`;
var symbol9 = Symbol.for(marker9);
var _a9;
var _b9;
var LoadAPIKeyError = class extends (_b9 = AISDKError, _a9 = symbol9, _b9) {
// used in isInstance
constructor({ message }) {
super({ name: name8, message });
this[_a9] = true;
}
static isInstance(error) {
return AISDKError.hasMarker(error, marker9);
}
};
var name9 = "AI_LoadSettingError";
var marker10 = `vercel.ai.error.${name9}`;
var symbol10 = Symbol.for(marker10);
var _a10;
var _b10;
var LoadSettingError = class extends (_b10 = AISDKError, _a10 = symbol10, _b10) {
// used in isInstance
constructor({ message }) {
super({ name: name9, message });
this[_a10] = true;
}
static isInstance(error) {
return AISDKError.hasMarker(error, marker10);
}
};
var name10 = "AI_NoContentGeneratedError";
var marker11 = `vercel.ai.error.${name10}`;
var symbol11 = Symbol.for(marker11);
var _a11;
var _b11;
var NoContentGeneratedError = class extends (_b11 = AISDKError, _a11 = symbol11, _b11) {
// used in isInstance
constructor({
message = "No content generated."
} = {}) {
super({ name: name10, message });
this[_a11] = true;
}
static isInstance(error) {
return AISDKError.hasMarker(error, marker11);
}
};
var name11 = "AI_NoSuchModelError";
var marker12 = `vercel.ai.error.${name11}`;
var symbol12 = Symbol.for(marker12);
var _a12;
var _b12;
var NoSuchModelError = class extends (_b12 = AISDKError, _a12 = symbol12, _b12) {
constructor({
errorName = name11,
modelId,
modelType,
message = `No such ${modelType}: ${modelId}`
}) {
super({ name: errorName, message });
this[_a12] = true;
this.modelId = modelId;
this.modelType = modelType;
}
static isInstance(error) {
return AISDKError.hasMarker(error, marker12);
}
};
var name12 = "AI_NoSuchProviderReferenceError";
var marker13 = `vercel.ai.error.${name12}`;
var symbol13 = Symbol.for(marker13);
var _a13;
var _b13;
var NoSuchProviderReferenceError = class extends (_b13 = AISDKError, _a13 = symbol13, _b13) {
constructor({
provider,
reference,
message = `No provider reference found for provider '${provider}'. Available providers: ${Object.keys(reference).join(", ")}`
}) {
super({ name: name12, message });
this[_a13] = true;
this.provider = provider;
this.reference = reference;
}
static isInstance(error) {
return AISDKError.hasMarker(error, marker13);
}
};
var name13 = "AI_TooManyEmbeddingValuesForCallError";
var marker14 = `vercel.ai.error.${name13}`;
var symbol14 = Symbol.for(marker14);
var _a14;
var _b14;
var TooManyEmbeddingValuesForCallError = class extends (_b14 = AISDKError, _a14 = symbol14, _b14) {
constructor(options) {
super({
name: name13,
message: `Too many values for a single embedding call. The ${options.provider} model "${options.modelId}" can only embed up to ${options.maxEmbeddingsPerCall} values per call, but ${options.values.length} values were provided.`
});
this[_a14] = true;
this.provider = options.provider;
this.modelId = options.modelId;
this.maxEmbeddingsPerCall = options.maxEmbeddingsPerCall;
this.values = options.values;
}
static isInstance(error) {
return AISDKError.hasMarker(error, marker14);
}
};
var name14 = "AI_TypeValidationError";
var marker15 = `vercel.ai.error.${name14}`;
var symbol15 = Symbol.for(marker15);
var _a15;
var _b15;
var TypeValidationError = class _TypeValidationError extends (_b15 = AISDKError, _a15 = symbol15, _b15) {
constructor({
value,
cause,
context
}) {
let contextPrefix = "Type validation failed";
if (context == null ? void 0 : context.field) {
contextPrefix += ` for ${context.field}`;
}
if ((context == null ? void 0 : context.entityName) || (context == null ? void 0 : context.entityId)) {
contextPrefix += " (";
const parts = [];
if (context.entityName) {
parts.push(context.entityName);
}
if (context.entityId) {
parts.push(`id: "${context.entityId}"`);
}
contextPrefix += parts.join(", ");
contextPrefix += ")";
}
super({
name: name14,
message: `${contextPrefix}: Value: ${JSON.stringify(value)}.
Error message: ${getErrorMessage(cause)}`,
cause
});
this[_a15] = true;
this.value = value;
this.context = context;
}
static isInstance(error) {
return AISDKError.hasMarker(error, marker15);
}
/**
* Wraps an error into a TypeValidationError.
* If the cause is already a TypeValidationError with the same value and context, 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.
* @param {TypeValidationContext} params.context - Optional context about what is being validated.
* @returns {TypeValidationError} A TypeValidationError instance.
*/
static wrap({
value,
cause,
context
}) {
var _a172, _b172, _c;
if (_TypeValidationError.isInstance(cause) && cause.value === value && ((_a172 = cause.context) == null ? void 0 : _a172.field) === (context == null ? void 0 : context.field) && ((_b172 = cause.context) == null ? void 0 : _b172.entityName) === (context == null ? void 0 : context.entityName) && ((_c = cause.context) == null ? void 0 : _c.entityId) === (context == null ? void 0 : context.entityId)) {
return cause;
}
return new _TypeValidationError({ value, cause, context });
}
};
var name15 = "AI_UnsupportedFunctionalityError";
var marker16 = `vercel.ai.error.${name15}`;
var symbol16 = Symbol.for(marker16);
var _a16;
var _b16;
var UnsupportedFunctionalityError = class extends (_b16 = AISDKError, _a16 = symbol16, _b16) {
constructor({
functionality,
message = `'${functionality}' functionality not supported.`
}) {
super({ name: name15, message });
this[_a16] = true;
this.functionality = functionality;
}
static isInstance(error) {
return AISDKError.hasMarker(error, marker16);
}
};
// node_modules/.pnpm/@ai-sdk+provider-utils@5.0.42_zod@4.3.5/node_modules/@ai-sdk/provider-utils/dist/index.js
import { safeParseAsync } from "zod/v4";
import { toJSONSchema } from "zod/v4/core";
// node_modules/.pnpm/eventsource-parser@3.1.0/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;
}
};
var LF = 10;
var CR = 13;
var SPACE = 32;
function noop(_arg) {
}
function createParser(config) {
if (typeof config == "function")
throw new TypeError(
"`config` must be an object, got a function instead. Did you mean `createParser({onEvent: fn})`?"
);
const { onEvent = noop, onError = noop, onRetry = noop, onComment, maxBufferSize } = config, pendingFragments = [];
let pendingFragmentsLength = 0, isFirstChunk = true, id, data = "", dataLines = 0, eventType, terminated = false;
function feed(chunk) {
if (terminated)
throw new Error(
"Cannot feed parser: it was terminated after exceeding the configured max buffer size. Call `reset()` to resume parsing."
);
if (isFirstChunk && (isFirstChunk = false, chunk.charCodeAt(0) === 239 && chunk.charCodeAt(1) === 187 && chunk.charCodeAt(2) === 191 && (chunk = chunk.slice(3))), pendingFragments.length === 0) {
const trailing2 = processLines(chunk);
trailing2 !== "" && (pendingFragments.push(trailing2), pendingFragmentsLength = trailing2.length), checkBufferSize();
return;
}
if (chunk.indexOf(`
`) === -1 && chunk.indexOf("\r") === -1) {
pendingFragments.push(chunk), pendingFragmentsLength += chunk.length, checkBufferSize();
return;
}
pendingFragments.push(chunk);
const input = pendingFragments.join("");
pendingFragments.length = 0, pendingFragmentsLength = 0;
const trailing = processLines(input);
trailing !== "" && (pendingFragments.push(trailing), pendingFragmentsLength = trailing.length), checkBufferSize();
}
function checkBufferSize() {
maxBufferSize !== void 0 && (pendingFragmentsLength + data.length <= maxBufferSize || (terminated = true, pendingFragments.length = 0, pendingFragmentsLength = 0, id = void 0, data = "", dataLines = 0, eventType = void 0, onError(
new ParseError(`Buffered data exceeded max buffer size of ${maxBufferSize} characters`, {
type: "max-buffer-size-exceeded"
})
)));
}
function processLines(chunk) {
let searchIndex = 0;
if (chunk.indexOf("\r") === -1) {
let lfIndex = chunk.indexOf(`
`, searchIndex);
for (; lfIndex !== -1; ) {
if (searchIndex === lfIndex) {
dataLines > 0 && onEvent({ id, event: eventType, data }), id = void 0, data = "", dataLines = 0, eventType = void 0, searchIndex = lfIndex + 1, lfIndex = chunk.indexOf(`
`, searchIndex);
continue;
}
const firstCharCode = chunk.charCodeAt(searchIndex);
if (isDataPrefix(chunk, searchIndex, firstCharCode)) {
const valueStart = chunk.charCodeAt(searchIndex + 5) === SPACE ? searchIndex + 6 : searchIndex + 5, value = chunk.slice(valueStart, lfIndex);
if (dataLines === 0 && chunk.charCodeAt(lfIndex + 1) === LF) {
onEvent({ id, event: eventType, data: value }), id = void 0, data = "", eventType = void 0, searchIndex = lfIndex + 2, lfIndex = chunk.indexOf(`
`, searchIndex);
continue;
}
data = dataLines === 0 ? value : `${data}
${value}`, dataLines++;
} else isEventPrefix(chunk, searchIndex, firstCharCode) ? eventType = chunk.slice(
chunk.charCodeAt(searchIndex + 6) === SPACE ? searchIndex + 7 : searchIndex + 6,
lfIndex
) || void 0 : parseLine(chunk, searchIndex, lfIndex);
searchIndex = lfIndex + 1, lfIndex = chunk.indexOf(`
`, searchIndex);
}
return chunk.slice(searchIndex);
}
for (; searchIndex < chunk.length; ) {
const crIndex = chunk.indexOf("\r", searchIndex), lfIndex = chunk.indexOf(`
`, searchIndex);
let lineEnd = -1;
if (crIndex !== -1 && lfIndex !== -1 ? lineEnd = crIndex < lfIndex ? crIndex : lfIndex : crIndex !== -1 ? crIndex === chunk.length - 1 ? lineEnd = -1 : lineEnd = crIndex : lfIndex !== -1 && (lineEnd = lfIndex), lineEnd === -1)
break;
parseLine(chunk, searchIndex, lineEnd), searchIndex = lineEnd + 1, chunk.charCodeAt(searchIndex - 1) === CR && chunk.charCodeAt(searchIndex) === LF && searchIndex++;
}
return chunk.slice(searchIndex);
}
function parseLine(chunk, start, end) {
if (start === end) {
dispatchEvent();
return;
}
const firstCharCode = chunk.charCodeAt(start);
if (isDataPrefix(chunk, start, firstCharCode)) {
const valueStart = chunk.charCodeAt(start + 5) === SPACE ? start + 6 : start + 5, value2 = chunk.slice(valueStart, end);
data = dataLines === 0 ? value2 : `${data}
${value2}`, dataLines++;
return;
}
if (isEventPrefix(chunk, start, firstCharCode)) {
eventType = chunk.slice(chunk.charCodeAt(start + 6) === SPACE ? start + 7 : start + 6, end) || void 0;
return;
}
if (firstCharCode === 105 && chunk.charCodeAt(start + 1) === 100 && chunk.charCodeAt(start + 2) === 58) {
const value2 = chunk.slice(chunk.charCodeAt(start + 3) === SPACE ? start + 4 : start + 3, end);
id = value2.includes("\0") ? void 0 : value2;
return;
}
if (firstCharCode === 58) {
if (onComment) {
const line2 = chunk.slice(start, end);
onComment(line2.slice(chunk.charCodeAt(start + 1) === SPACE ? 2 : 1));
}
return;
}
const line = chunk.slice(start, end), fieldSeparatorIndex = line.indexOf(":");
if (fieldSeparatorIndex === -1) {
processField(line, "", line);
return;
}
const field = line.slice(0, fieldSeparatorIndex), offset = line.charCodeAt(fieldSeparatorIndex + 1) === SPACE ? 2 : 1, value = line.slice(fieldSeparatorIndex + offset);
processField(field, value, line);
}
function processField(field, value, line) {
switch (field) {
case "event":
eventType = value || void 0;
break;
case "data":
data = dataLines === 0 ? value : `${data}
${value}`, dataLines++;
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() {
dataLines > 0 && onEvent({
id,
event: eventType,
data
}), id = void 0, data = "", dataLines = 0, eventType = void 0;
}
function reset(options = {}) {
if (options.consume && pendingFragments.length > 0) {
const incompleteLine = pendingFragments.join("");
parseLine(incompleteLine, 0, incompleteLine.length);
}
isFirstChunk = true, id = void 0, data = "", dataLines = 0, eventType = void 0, pendingFragments.length = 0, pendingFragmentsLength = 0, terminated = false;
}
return { feed, reset };
}
function isDataPrefix(chunk, i, firstCharCode) {
return firstCharCode === 100 && chunk.charCodeAt(i + 1) === 97 && chunk.charCodeAt(i + 2) === 116 && chunk.charCodeAt(i + 3) === 97 && chunk.charCodeAt(i + 4) === 58;
}
function isEventPrefix(chunk, i, firstCharCode) {
return firstCharCode === 101 && chunk.charCodeAt(i + 1) === 118 && chunk.charCodeAt(i + 2) === 101 && chunk.charCodeAt(i + 3) === 110 && chunk.charCodeAt(i + 4) === 116 && chunk.charCodeAt(i + 5) === 58;
}
// node_modules/.pnpm/eventsource-parser@3.1.0/node_modules/eventsource-parser/dist/stream.js
var EventSourceParserStream = class extends TransformStream {
constructor({ onError, onRetry, onComment, maxBufferSize } = {}) {
let parser;
super({
start(controller) {
parser = createParser({
onEvent: (event) => {
controller.enqueue(event);
},
onError(error) {
typeof onError == "function" && onError(error), (onError === "terminate" || error.type === "max-buffer-size-exceeded") && controller.error(error);
},
onRetry,
onComment,
maxBufferSize
});
},
transform(chunk) {
parser.feed(chunk);
}
});
}
};
// node_modules/.pnpm/@workflow+serde@4.1.0/node_modules/@workflow/serde/dist/index.js
var WORKFLOW_SERIALIZE = Symbol.for("workflow-serialize");
var WORKFLOW_DESERIALIZE = Symbol.for("workflow-deserialize");
// node_modules/.pnpm/@ai-sdk+provider-utils@5.0.42_zod@4.3.5/node_modules/@ai-sdk/provider-utils/dist/index.js
function combineHeaders(...headers) {
return headers.reduce(
(combinedHeaders, currentHeaders) => __spreadValues(__spreadValues({}, combinedHeaders), currentHeaders != null ? currentHeaders : {}),
{}
);
}
function removeUndefinedEntries(record) {
return Object.fromEntries(
Object.entries(record).filter(([_key, value]) => value != null)
);
}
async function delay(delayInMs, options) {
if (delayInMs == null) {
return Promise.resolve();
}
const signal = options == null ? void 0 : options.abortSignal;
return new Promise((resolve2, reject) => {
if (signal == null ? void 0 : signal.aborted) {
reject(createAbortError());
return;
}
const timeoutId = setTimeout(() => {
cleanup();
resolve2();
}, delayInMs);
const cleanup = () => {
clearTimeout(timeoutId);
signal == null ? void 0 : signal.removeEventListener("abort", onAbort);
};
const onAbort = () => {
cleanup();
reject(createAbortError());
};
signal == null ? void 0 : signal.addEventListener("abort", onAbort);
});
}
function createAbortError() {
return new DOMException("Delay was aborted", "AbortError");
}
var textDecoder = new TextDecoder();
var { btoa, atob } = globalThis;
function convertUint8ArrayToBase64(array) {
const chunks = [];
const chunkSize = 4096;
for (let i = 0; i < array.length; i += chunkSize) {
chunks.push(String.fromCodePoint(...array.subarray(i, i + chunkSize)));
}
return btoa(chunks.join(""));
}
function extractResponseHeaders(response) {
return Object.fromEntries([...response.headers]);
}
function getRuntimeEnvironmentUserAgent(globalThisAny = globalThis) {
var _a32, _b32, _c;
if (globalThisAny.window) {
return `runtime/browser`;
}
if ((_a32 = globalThisAny.navigator) == null ? void 0 : _a32.userAgent) {
return `runtime/${globalThisAny.navigator.userAgent.toLowerCase()}`;
}
if ((_c = (_b32 = globalThisAny.process) == null ? void 0 : _b32.versions) == null ? void 0 : _c.node) {
return `runtime/node.js/${globalThisAny.process.version.substring(0)}`;
}
if (globalThisAny.EdgeRuntime) {
return `runtime/vercel-edge`;
}
return "runtime/unknown";
}
function isAbortError(error) {
return (error instanceof Error || typeof DOMException === "function" && error instanceof DOMException) && (error.name === "AbortError" || error.name === "ResponseAborted" || // Next.js
error.name === "TimeoutError");
}
var FETCH_FAILED_ERROR_MESSAGES = ["fetch failed", "failed to fetch"];
var RETRYABLE_NETWORK_ERROR_CODES = /* @__PURE__ */ new Set([
"ConnectionRefused",
"ConnectionClosed",
"FailedToOpenSocket",
"ECONNRESET",
"ECONNREFUSED",
"ETIMEDOUT",
"EPIPE",
"UND_ERR_SOCKET",
"UND_ERR_HEADERS_TIMEOUT",
"UND_ERR_BODY_TIMEOUT",
"UND_ERR_CONNECT_TIMEOUT"
]);
function findNetworkError(error) {
const visited = /* @__PURE__ */ new Set();
let current = error;
while (current instanceof Error && !visited.has(current)) {
visited.add(current);
const errorWithCode = current;
if (typeof errorWithCode.code === "string" && RETRYABLE_NETWORK_ERROR_CODES.has(errorWithCode.code)) {
return errorWithCode;
}
current = current.cause;
}
return void 0;
}
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
});
}
}
const networkError = findNetworkError(error);
if (networkError != null) {
if (APICallError.isInstance(error)) {
return new APICallError({
message: error.message,
cause: error.cause,
url: error.url,
requestBodyValues: error.requestBodyValues,
statusCode: error.statusCode,
responseHeaders: error.responseHeaders,
responseBody: error.responseBody,
data: error.data,
isRetryable: true
});
}
return new APICallError({
message: `Cannot connect to API: ${error instanceof Error ? error.message : networkError.message}`,
cause: error,
url,
requestBodyValues,
isRetryable: true
});
}
return error;
}
var VERSION = true ? "5.0.42" : "0.0.0-test";
function normalizeHeaders(headers) {
if (headers == null) {
return {};
}
const normalized = {};
if (headers instanceof Headers) {
headers.forEach((value, key) => {
normalized[key.toLowerCase()] = value;
});
} else {
if (!Array.isArray(headers)) {
headers = Object.entries(headers);
}
for (const [key, value] of headers) {
if (value != null) {
normalized[key.toLowerCase()] = value;
}
}
}
return normalized;
}
function withUserAgentSuffix(headers, ...userAgentSuffixParts) {
const normalizedHeaders = new Headers(normalizeHeaders(headers));
const currentUserAgentHeader = normalizedHeaders.get("user-agent") || "";
normalizedHeaders.set(
"user-agent",
[currentUserAgentHeader, ...userAgentSuffixParts].filter(Boolean).join(" ")
);
return Object.fromEntries(normalizedHeaders.entries());
}
var audioMediaTypeSignaturesWithoutMp4 = [
{
mediaType: "audio/mpeg",
bytesPrefix: [255, 251]
},
{
mediaType: "audio/mpeg",
bytesPrefix: [255, 250]
},
{
mediaType: "audio/mpeg",
bytesPrefix: [255, 243]
},
{
mediaType: "audio/mpeg",
bytesPrefix: [255, 242]
},
{
mediaType: "audio/mpeg",
bytesPrefix: [255, 227]
},
{
mediaType: "audio/mpeg",
bytesPrefix: [255, 226]
},
{
mediaType: "audio/wav",
bytesPrefix: [
82,
// R
73,
// I
70,
// F
70,
// F
null,
null,
null,
null,
87,
// W
65,
// A
86,
// V
69
// E
]
},
{
mediaType: "audio/ogg",
bytesPrefix: [79, 103, 103, 83]
},
{
mediaType: "audio/flac",
bytesPrefix: [102, 76, 97, 67]
},
{
mediaType: "audio/aac",
bytesPrefix: [64, 21, 0, 0]
},
{
mediaType: "audio/webm",
bytesPrefix: [26, 69, 223, 163]
}
];
var audioMediaTypeSignatures = [
...audioMediaTypeSignaturesWithoutMp4,
{
mediaType: "audio/mp4",
bytesPrefix: [
0,
0,
0,
null,
102,
116,
121,
112
// ftyp
]
}
];
var MAX_SIGNATURE_BYTES = 12;
var MAX_ID3_TAG_BYTES = 128 * 1024;
var ID3_SCAN_BYTES = MAX_ID3_TAG_BYTES + MAX_SIGNATURE_BYTES;
async function cancelResponseBody(response) {
var _a32;
try {
await ((_a32 = response.body) == null ? void 0 : _a32.cancel());
} catch (e) {
}
}
var name16 = "AI_DownloadError";
var marker22 = `vercel.ai.error.${name16}`;
var symbol17 = Symbol.for(marker22);
var _a17;
var _b17;
var DownloadError = class extends (_b17 = AISDKError, _a17 = symbol17, _b17) {
constructor({
url,
statusCode,
statusText,
cause,
message = cause == null ? `Failed to download ${url}: ${statusCode} ${statusText}` : `Failed to download ${url}: ${cause}`
}) {
super({ name: name16, message, cause });
this[_a17] = true;
this.url = url;
this.statusCode = statusCode;
this.statusText = statusText;
}
static isInstance(error) {
return AISDKError.hasMarker(error, marker22);
}
};
function isBrowserRuntime(globalThisAny = globalThis) {
return globalThisAny.window != null;
}
function isSameOrigin(url, baseUrl) {
try {
return new URL(url).origin === new URL(baseUrl).origin;
} catch (e) {
return false;
}
}
function validateDownloadUrl(url) {
let parsed;
try {
parsed = new URL(url);
} catch (e) {
throw new DownloadError({
url,
message: `Invalid URL: ${url}`
});
}
if (parsed.protocol === "data:") {
return;
}
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
throw new DownloadError({
url,
message: `URL scheme must be http, https, or data, got ${parsed.protocol}`
});
}
const hostname = parsed.hostname.toLowerCase().replace(/\.+$/, "");
if (!hostname) {
throw new DownloadError({
url,
message: `URL must have a hostname`
});
}
if (hostname === "localhost" || hostname.endsWith(".local") || hostname.endsWith(".localhost")) {
throw new DownloadError({
url,
message: `URL with hostname ${hostname} is not allowed`
});
}
if (hostname.startsWith("[") && hostname.endsWith("]")) {
const ipv6 = hostname.slice(1, -1);
if (isPrivateIPv6(ipv6)) {
throw new DownloadError({
url,
message: `URL with IPv6 address ${hostname} is not allowed`
});
}
return;
}
if (isIPv4(hostname)) {
if (isPrivateIPv4(hostname)) {
throw new DownloadError({
url,
message: `URL with IP address ${hostname} is not allowed`
});
}
return;
}
}
function validateDownloadAddress({
address,
family,
hostname
}) {
const isUnsafe = family === 4 ? !isIPv4(address) || isPrivateIPv4(address) : family === 6 ? isPrivateIPv6(address) : true;
if (isUnsafe) {
throw new DownloadError({
url: hostname,
message: `Hostname ${hostname} resolved to disallowed IP address ${address}`
});
}
}
function isIPv4(hostname) {
const parts = hostname.split(".");
if (parts.length !== 4) return false;
return parts.every((part) => {
const num = Number(part);
return Number.isInteger(num) && num >= 0 && num <= 255 && String(num) === part;
});
}
function isPrivateIPv4(ip) {
const parts = ip.split(".").map(Number);
const [a, b, c] = parts;
if (a === 0) return true;
if (a === 10) return true;
if (a === 100 && b >= 64 && b <= 127) return true;
if (a === 127) return true;
if (a === 169 && b === 254) return true;
if (a === 172 && b >= 16 && b <= 31) return true;
if (a === 192 && b === 0 && c === 0) return true;
if (a === 192 && b === 0 && c === 2) return true;
if (a === 192 && b === 168) return true;
if (a === 198 && (b === 18 || b === 19)) return true;
if (a === 198 && b === 51 && c === 100) return true;
if (a === 203 && b === 0 && c === 113) return true;
if (a >= 224) return true;
return false;
}
function parseIPv6(ip) {
let address = ip.toLowerCase();
const zoneIndex = address.indexOf("%");
if (zoneIndex !== -1) {
address = address.slice(0, zoneIndex);
}
const halves = address.split("::");
if (halves.length > 2) return null;
const toGroups = (segment) => {
if (segment === "") return [];
const groups = [];
const parts = segment.split(":");
for (let i = 0; i < parts.length; i++) {
const part = parts[i];
if (part.includes(".")) {
if (i !== parts.length - 1 || !isIPv4(part)) return null;
const [a, b, c, d] = part.split(".").map(Number);
groups.push(a << 8 | b, c << 8 | d);
continue;
}
if (!/^[0-9a-f]{1,4}$/.test(part)) return null;
groups.push(parseInt(part, 16));
}
return groups;
};
const head = toGroups(halves[0]);
if (head === null) return null;
if (halves.length === 2) {
const tail = toGroups(halves[1]);
if (tail === null) return null;
const fill = 8 - head.length - tail.length;
if (fill < 0) return null;
return [...head, ...new Array(fill).fill(0), ...tail];
}
return head.length === 8 ? head : null;
}
function isPrivateIPv6(ip) {
const groups = parseIPv6(ip);
if (groups === null) return true;
const topZero = (count) => groups.slice(0, count).every((group) => group === 0);
if (topZero(7) && (groups[7] === 0 || groups[7] === 1)) return true;
if ((groups[0] & 65024) === 64512) return true;
if ((groups[0] & 65472) === 65152) return true;
if ((groups[0] & 65472) === 65216) return true;
if ((groups[0] & 65280) === 65280) return true;
if (groups[0] === 8193 && groups[1] === 3512) return true;
if (groups[0] === 16383 && (groups[1] & 61440) === 0) return true;
const embedsIPv4 = (
// ::/96 — IPv4-compatible (deprecated)
topZero(6) || // ::ffff:0:0/96 — IPv4-mapped (ffff in group 5)
topZero(5) && groups[5] === 65535 || // ::ffff:0:0/96 — IPv4-translated form (ffff in group 4, group 5 zero)
topZero(4) && groups[4] === 65535 && groups[5] === 0 || // 64:ff9b::/96 — NAT64 well-known prefix
groups[0] === 100 && groups[1] === 65435 && groups[2] === 0 && groups[3] === 0 && groups[4] === 0 && groups[5] === 0 || // 64:ff9b:1::/48 — NAT64 local-use prefix
groups[0] === 100 && groups[1] === 65435 && groups[2] === 1
);
if (embedsIPv4) {
const a = groups[6] >> 8 & 255;
const b = groups[6] & 255;
const c = groups[7] >> 8 & 255;
const d = groups[7] & 255;
return isPrivateIPv4(`${a}.${b}.${c}.${d}`);
}
return false;
}
function createSafeLookup(lookup) {
return ((hostname, options, callback) => {
lookup(hostname, __spreadProps(__spreadValues({}, options), { all: true }), (error, addresses) => {
if (error) {
callback(error);
return;
}
try {
const [firstAddress] = addresses;
if (firstAddress == null) {
throw new Error(`Hostname ${hostname} did not resolve to an address`);
}
for (const { address, family } of addresses) {
validateDownloadAddress({ address, family, hostname });
}
if (options.all === true) {
callback(null, addresses);
} else {
callback(
null,
firstAddress.address,
firstAddress.family
);
}
} catch (error2) {
callback(
error2 instanceof Error ? error2 : new Error(String(error2))
);
}
});
});
}
var safeNodeFetchPromise;
function isNodeRuntime() {
var _a32, _b32, _c;
const runtimeProcess = globalThis.process;
return ((_a32 = runtimeProcess == null ? void 0 : runtimeProcess.release) == null ? void 0 : _a32.name) === "node" && ((_b32 = runtimeProcess.versions) == null ? void 0 : _b32.bun) == null && ((_c = runtimeProcess.versions) == null ? void 0 : _c.deno) == null && runtimeProcess.title !== "workerd" && globalThis.EdgeRuntime == null;
}
async function getDefaultDownloadFetch() {
if (!isNodeRuntime()) {
return globalThis.fetch;
}
return safeNodeFetchPromise != null ? safeNodeFetchPromise : safeNodeFetchPromise = Promise.resolve().then(createSafeNodeFetch);
}
function createSafeNodeFetch() {
const { createRequire } = loadBuiltinModule("node:module");
const { lookup } = loadBuiltinModule("node:dns");
const { Agent, fetch } = createRequire(getCurrentModulePath())(
"undici"
);
const dispatcher = new Agent({
connect: {
lookup: createSafeLookup(lookup)
}
});
return ((input, init) => fetch(
input,
__spreadProps(__spreadValues({}, init), {
dispatcher
})
));
}
function loadBuiltinModule(id) {
var _a32;
const processWithBuiltins = globalThis.process;
const builtinModule = (_a32 = processWithBuiltins == null ? void 0 : processWithBuiltins.getBuiltinModule) == null ? void 0 : _a32.call(processWithBuiltins, id);
if (builtinModule == null) {
throw new Error(`Node.js built-in module ${id} is unavailable`);
}
return builtinModule;
}
function getCurrentModulePath() {
const originalPrepareStackTrace = Error.prepareStackTrace;
try {
Error.prepareStackTrace = (_error, callSites) => callSites;
const error = new Error("Capture current module path");
Error.captureStackTrace(error, getCurrentModulePath);
const [caller] = error.stack;
const fileName = caller == null ? void 0 : caller.getFileName();
if (fileName == null) {
throw new Error("Unable to determine the current module path");
}
return fileName;
} finally {
Error.prepareStackTrace = originalPrepareStackTrace;
}
}
var BLOCKED_REQUEST_HEADERS = [
// Hop-by-hop / transport (RFC 7230 §6.1)
"connection",
"keep-alive",
"te",
"trailer",
"transfer-encoding",
"upgrade",
// Host / virtual-host routing
"host",
// Proxy / origin spoofing
"forwarded",
"proxy-authorization",
"via",
"x-forwarded-for",
"x-forwarded-host",
"x-forwarded-proto",
"x-real-ip",
// Cloud metadata (GCP, AWS IMDSv1/v2, Azure, Alibaba, DigitalOcean)
"metadata",
"metadata-flavor",
"x-aws-ec2-metadata-token",
"x-metadata-token",
// Session / cookie
"cookie",
"set-cookie"
];
function sanitizeRequestHeaders(input) {
const headers = new Headers(input);
for (const name32 of BLOCKED_REQUEST_HEADERS) {
headers.delete(name32);
}
return headers;
}
var MAX_DOWNLOAD_REDIRECTS = 10;
var REDIRECT_STATUS_CODES = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]);
async function getValidatedFetch(customFetch) {
return customFetch == null || customFetch === globalThis.fetch ? await getDefaultDownloadFetch() : customFetch;
}
async function fetchWithValidatedRedirects({
url,
headers,
abortSignal,
maxRedirects = MAX_DOWNLOAD_REDIRECTS,
fetch: customFetch,
trustedOrigin
}) {
var _a32;
let currentHeaders = headers === void 0 ? void 0 : sanitizeRequestHeaders(headers);
const perHopInit = (redirect) => {
const init = { signal: abortSignal, redirect };
if (currentHeaders !== void 0) {
init.headers = new Headers(currentHeaders);
}
return init;
};
let currentUrl = url;
for (let redirectCount = 0; redirectCount <= maxRedirects; redirectCount++) {
const isTrustedHop = trustedOrigin !== void 0 && isSameOrigin(currentUrl, trustedOrigin);
if (!isTrustedHop) {
validateDownloadUrl(currentUrl);
}
const fetch = isTrustedHop && customFetch != null ? customFetch : isTrustedHop ? globalThis.fetch : await getValidatedFetch(customFetch);
const response = await fetch(currentUrl, perHopInit("manual"));
if (response.type === "opaqueredirect") {
if (!isBrowserRuntime()) {
throw new DownloadError({
url,
message: `Redirect from ${currentUrl} could not be validated and was blocked`
});
}
return await fetch(currentUrl, perHopInit("follow"));
}
const location = (_a32 = response.headers) == null ? void 0 : _a32.get("location");
if (REDIRECT_STATUS_CODES.has(response.status) && location) {
await cancelResponseBody(response);
const nextUrl = new URL(location, currentUrl).toString();
if (currentHeaders !== void 0 && !isSameOrigin(nextUrl, currentUrl)) {
const userAgent = currentHeaders.get("user-agent");
currentHeaders = new Headers(
userAgent == null ? void 0 : { "user-agent": userAgent }
);
}
currentUrl = nextUrl;
continue;
}
return response;
}
throw new DownloadError({
url,
message: `Too many redirects (max ${maxRedirects})`
});
}
var DEFAULT_MAX_DOWNLOAD_SIZE = 2 * 1024 * 1024 * 1024;
async function readResponseWithSizeLimit({
response,
url,
maxBytes = DEFAULT_MAX_DOWNLOAD_SIZE
}) {
const contentLength = response.headers.get("content-length");
if (contentLength != null) {
const length = parseInt(contentLength, 10);
if (!isNaN(length) && length > maxBytes) {
await cancelResponseBody(response);
throw new DownloadError({
url,
message: `Download of ${url} exceeded maximum size of ${maxBytes} bytes (Content-Length: ${length}).`
});
}
}
const body = response.body;
if (body == null) {
return new Uint8Array(0);
}
const reader = body.getReader();
const chunks = [];
let totalBytes = 0;
try {
while (true) {
const { done, value } = await reader.read();
if (done) {
break;
}
totalBytes += value.length;
if (totalBytes > maxBytes) {
throw new DownloadError({
url,
message: `Download of ${url} exceeded maximum size of ${maxBytes} bytes.`
});
}
chunks.push(value);
}
} finally {
try {
await reader.cancel();
} catch (e) {
} finally {
reader.releaseLock();
}
}
const result = new Uint8Array(totalBytes);
let offset = 0;
for (const chunk of chunks) {
result.set(chunk, offset);
offset += chunk.length;
}
return result;
}
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();
var getOriginalFetch2 = () => globalThis.fetch;
var getFromApi = async ({
url,
headers = {},
successfulResponseHandler,
failedResponseHandler,
abortSignal,
fetch,
validateUrl,
credentialedOrigin,
trustedOrigin
}) => {
try {
const requestFetch = fetch != null ? fetch : getOriginalFetch2();
const outgoingHeaders = credentialedOrigin !== void 0 && !isSameOrigin(url, credentialedOrigin) ? {} : headers;
const requestHeaders = withUserAgentSuffix(
outgoingHeaders,
`ai-sdk/provider-utils/${VERSION}`,
getRuntimeEnvironmentUserAgent()
);
const response = validateUrl ? await fetchWithValidatedRedirects({
url,
headers: requestHeaders,
abortSignal,
fetch,
trustedOrigin
}) : await requestFetch(url, {
method: "GET",
headers: requestHeaders,
signal: abortSignal
});
const responseHeaders = extractResponseHeaders(response);
if (!response.ok) {
let errorInformation;
try {
errorInformation = await failedResponseHandler({
response,
url,
requestBodyValues: {}
});
} 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: {}
});
}
throw errorInformation.value;
}
try {
return await successfulResponseHandler({
response,
url,
requestBodyValues: {}
});
} 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: {}
});
}
} catch (error) {
throw handleFetchError({ error, url, requestBodyValues: {} });
}
};
var suspectProtoRx = /"(?:_|\\u005[Ff])(?:_|\\u005[Ff])(?:p|\\u0070)(?:r|\\u0072)(?:o|\\u006[Ff])(?:t|\\u0074)(?:o|\\u006[Ff])(?:_|\\u005[Ff])(?:_|\\u005[Ff])"\s*:/;
var suspectConstructorRx = /"(?:c|\\u0063)(?:o|\\u006[Ff])(?:n|\\u006[Ee])(?:s|\\u0073)(?:t|\\u0074)(?:r|\\u0072)(?:u|\\u0075)(?:c|\\u0063)(?:t|\\u0074)(?:o|\\u006[Ff])(?:r|\\u0072)"\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") && node.constructor !== null && typeof node.constructor === "object" && 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;
try {
Error.stackTraceLimit = 0;
} catch (e) {
return _parse(text);
}
try {
return _parse(text);
} finally {
Error.stackTraceLimit = stackTraceLimit;
}
}
function addAdditionalPropertiesToJsonSchema(jsonSchema2) {
if (jsonSchema2.type === "object" || Array.isArray(jsonSchema2.type) && jsonSchema2.type.includes("object")) {
const { additionalProperties } = jsonSchema2;
jsonSchema2.additionalProperties = additionalProperties != null && typeof additionalProperties !== "boolean" ? visit(additionalProperties) : false;
const { properties } = jsonSchema2;
if (properties != null) {
for (const key of Object.keys(properties)) {
properties[key] = visit(properties[key]);
}
}
}
if (jsonSchema2.items != null) {
jsonSchema2.items = Array.isArray(jsonSchema2.items) ? jsonSchema2.items.map(visit) : visit(jsonSchema2.items);
}
if (jsonSchema2.anyOf != null) {
jsonSchema2.anyOf = jsonSchema2.anyOf.map(visit);
}
if (jsonSchema2.allOf != null) {
jsonSchema2.allOf = jsonSchema2.allOf.map(visit);
}
if (jsonSchema2.oneOf != null) {
jsonSchema2.oneOf = jsonSchema2.oneOf.map(visit);
}
const { definitions } = jsonSchema2;
if (definitions != null) {
for (const key of Object.keys(definitions)) {
definitions[key] = visit(definitions[key]);
}
}
return jsonSchema2;
}
function visit(def) {
if (typeof def === "boolean") return def;
return addAdditionalPropertiesToJsonSchema(def);
}
var ignoreOverride = /* @__PURE__ */ Symbol(
"Let zodToJsonSchema decide on which parser to use"
);
var defaultOptions = {
name: void 0,
$refStrategy: "root",
basePath: ["#"],
effectStrategy: "input",
pipeStrategy: "all",
dateStrategy: "format:date-time",
mapStrategy: "entries",
removeAdditionalStrategy: "passthrough",
allowedAdditionalProperties: true,
rejectedAdditionalProperties: false,
definitionPath: "definitions",
strictUnions: false,
definitions: {},
errorMessages: false,
patternStrategy: "escape",
applyRegexFlags: false,
emailStrategy: "format:email",
base64Strategy: "contentEncoding:base64",
nameStrategy: "ref"
};
var getDefaultOptions = (options) => typeof options === "string" ? __spreadProps(__spreadValues({}, defaultOptions), {
name: options
}) : __spreadValues(__spreadValues({}, defaultOptions), options);
function parseAnyDef() {
return {};
}
function parseArrayDef(def, refs) {
var _a32, _b32, _c;
const res = {
type: "array"
};
if (((_a32 = def.type) == null ? void 0 : _a32._def) && ((_c = (_b32 = def.type) == null ? void 0 : _b32._def) == null ? void 0 : _c.typeName) !== "ZodAny") {
res.items = parseDef(def.type._def, __spreadProps(__spreadValues({}, refs), {
currentPath: [...refs.currentPath, "items"]
}));
}
if (def.minLength) {
res.minItems = def.minLength.value;
}
if (def.maxLength) {
res.maxItems = def.maxLength.value;
}
if (def.exactLength) {
res.minItems = def.exactLength.value;
res.maxItems = def.exactLength.value;
}
return res;
}
function parseBigintDef(def) {
const res = {
type: "integer",
format: "int64"
};
if (!def.checks) return res;
for (const check of def.checks) {
switch (check.kind) {
case "min":
if (check.inclusive) {
res.minimum = check.value;
} else {
res.exclusiveMinimum = check.value;
}
break;
case "max":
if (check.inclusive) {
res.maximum = check.value;
} else {
res.exclusiveMaximum = check.value;
}
break;
case "multipleOf":
res.multipleOf = check.value;
break;
}
}
return res;
}
function parseBooleanDef() {
return { type: "boolean" };
}
function parseBrandedDef(_def, refs) {
return parseDef(_def.type._def, refs);
}
var parseCatchDef = (def, refs) => {
return parseDef(def.innerType._def, refs);
};
function parseDateDef(def, refs, overrideDateStrategy) {
const strategy = overrideDateStrategy != null ? overrideDateStrategy : refs.dateStrategy;
if (Array.isArray(strategy)) {
return {
anyOf: strategy.map((item) => parseDateDef(def, refs, item))
};
}
switch (strategy) {
case "string":
case "format:date-time":
return {
type: "string",
format: "date-time"
};
case "format:date":
return {
type: "string",
format: "date"
};
case "integer":
return integerDateParser(def);
}
}
var integerDateParser = (def) => {
const res = {
type: "integer",
format: "unix-time"
};
for (const check of def.checks) {
switch (check.kind) {
case "min":
res.minimum = check.value;
break;
case "max":
res.maximum = check.value;
break;
}
}
return res;
};
function parseDefaultDef(_def, refs) {
return __spreadProps(__spreadValues({}, parseDef(_def.innerType._def, refs)), {
default: _def.defaultValue()
});
}
function parseEffectsDef(_def, refs) {
return refs.effectStrategy === "input" ? parseDef(_def.schema._def, refs) : parseAnyDef();
}
function parseEnumDef(def) {
return {
type: "string",
enum: Array.from(def.values)
};
}
var isJsonSchema7AllOfType = (type) => {
if ("type" in type && type.type === "string") return false;
return "allOf" in type;
};
function parseIntersectionDef(def, refs) {
const allOf = [
parseDef(def.left._def, __spreadProps(__spreadValues({}, refs), {
currentPath: [...refs.currentPath, "allOf", "0"]
})),
parseDef(def.right._def, __spreadProps(__spreadValues({}, refs), {
currentPath: [...refs.currentPath, "allOf", "1"]
}))
].filter((x) => !!x);
const mergedAllOf = [];
allOf.forEach((schema) => {
if (isJsonSchema7AllOfType(schema)) {
mergedAllOf.push(...schema.allOf);
} else {
let nestedSchema = schema;
if ("additionalProperties" in schema && schema.additionalProperties === false) {
const _a18 = schema, { additionalProperties: _additionalProperties } = _a18, rest = __objRest(_a18, ["additionalProperties"]);
nestedSchema = rest;
}
mergedAllOf.push(nestedSchema);
}
});
return mergedAllOf.length ? { allOf: mergedAllOf } : void 0;
}
function parseLiteralDef(def) {
const parsedType = typeof def.value;
if (parsedType !== "bigint" && parsedType !== "number" && parsedType !== "boolean" && parsedType !== "string") {
return {
type: Array.isArray(def.value) ? "array" : "object"
};
}
return {
type: parsedType === "bigint" ? "integer" : parsedType,
const: def.value
};
}
var emojiRegex = void 0;
var zodPatterns = {
/**
* `c` was changed to `[cC]` to replicate /i flag
*/
cuid: /^[cC][^\s-]{8,}$/,
cuid2: /^[0-9a-z]+$/,
ulid: /^[0-9A-HJKMNP-TV-Z]{26}$/,
/**
* `a-z` was added to replicate /i flag
*/
email: /^(?!\.)(?!.*\.\.)([a-zA-Z0-9_'+\-\.]*)[a-zA-Z0-9_+-]@([a-zA-Z0-9][a-zA-Z0-9\-]*\.)+[a-zA-Z]{2,}$/,
/**
* Constructed a valid Unicode RegExp
*
* Lazily instantiate since this type of regex isn't supported
* in all envs (e.g. React Native).
*
* See:
* https://github.com/colinhacks/zod/issues/2433
* Fix in Zod:
* https://github.com/colinhacks/zod/commit/9340fd51e48576a75adc919bff65dbc4a5d4c99b
*/
emoji: () => {
if (emojiRegex === void 0) {
emojiRegex = RegExp(
"^(\\p{Extended_Pictographic}|\\p{Emoji_Component})+$",
"u"
);
}
return emojiRegex;
},
/**
* Unused
*/
uuid: /^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/,
/**
* Unused
*/
ipv4: /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/,
ipv4Cidr: /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/(3[0-2]|[12]?[0-9])$/,
/**
* Unused
*/
ipv6: /^(([a-f0-9]{1,4}:){7}|::([a-f0-9]{1,4}:){0,6}|([a-f0-9]{1,4}:){1}:([a-f0-9]{1,4}:){0,5}|([a-f0-9]{1,4}:){2}:([a-f0-9]{1,4}:){0,4}|([a-f0-9]{1,4}:){3}:([a-f0-9]{1,4}:){0,3}|([a-f0-9]{1,4}:){4}:([a-f0-9]{1,4}:){0,2}|([a-f0-9]{1,4}:){5}:([a-f0-9]{1,4}:){0,1})([a-f0-9]{1,4}|(((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\.){3}((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2})))$/,
ipv6Cidr: /^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$/,
base64: /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/,
base64url: /^([0-9a-zA-Z-_]{4})*(([0-9a-zA-Z-_]{2}(==)?)|([0-9a-zA-Z-_]{3}(=)?))?$/,
nanoid: /^[a-zA-Z0-9_-]{21}$/,
jwt: /^[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]*$/
};
function parseStringDef(def, refs) {
const res = {
type: "string"
};
if (def.checks) {
for (const check of def.checks) {
switch (check.kind) {
case "min":
res.minLength = typeof res.minLength === "number" ? Math.max(res.minLength, check.value) : check.value;
break;
case "max":
res.maxLength = typeof res.maxLength === "number" ? Math.min(res.maxLength, check.value) : check.value;
break;
case "email":
switch (refs.emailStrategy) {
case "format:email":
addFormat(res, "email", check.message, refs);
break;
case "format:idn-email":
addFormat(res, "idn-email", check.message, refs);
break;
case "pattern:zod":
addPattern(res, zodPatterns.email, check.message, refs);
break;
}
break;
case "url":
addFormat(res, "uri", check.message, refs);
break;
case "uuid":
addFormat(res, "uuid", check.message, refs);
break;
case "regex":
addPattern(res, check.regex, check.message, refs);
break;
case "cuid":
addPattern(res, zodPatterns.cuid, check.message, refs);
break;
case "cuid2":
addPattern(res, zodPatterns.cuid2, check.message, refs);
break;
case "startsWith":
addPattern(
res,
RegExp(`^${escapeLiteralCheckValue(check.value, refs)}`),
check.message,
refs
);
break;
case "endsWith":
addPattern(
res,
RegExp(`${escapeLiteralCheckValue(check.value, refs)}$`),
check.message,
refs
);
break;
case "datetime":
addFormat(res, "date-time", check.message, refs);
break;
case "date":
addFormat(res, "date", check.message, refs);
break;
case "time":
addFormat(res, "time", check.message, refs);
break;
case "duration":
addFormat(res, "duration", check.message, refs);
break;
case "length":
res.minLength = typeof res.minLength === "number" ? Math.max(res.minLength, check.value) : check.value;
res.maxLength = typeof res.maxLength === "number" ? Math.min(res.maxLength, check.value) : check.value;
break;
case "includes": {
addPattern(
res,
RegExp(escapeLiteralCheckValue(check.value, refs)),
check.message,
refs
);
break;
}
case "ip": {
if (check.version !== "v6") {
addFormat(res, "ipv4", check.message, refs);
}
if (check.version !== "v4") {
addFormat(res, "ipv6", check.message, refs);
}
break;
}
case "base64url":
addPattern(res, zodPatterns.base64url, check.message, refs);
break;
case "jwt":
addPattern(res, zodPatterns.jwt, check.message, refs);
break;
case "cidr": {
if (check.version !== "v6") {
addPattern(res, zodPatterns.ipv4Cidr, check.message, refs);
}
if (check.version !== "v4") {
addPattern(res, zodPatterns.ipv6Cidr, check.message, refs);
}
break;
}
case "emoji":
addPattern(res, zodPatterns.emoji(), check.message, refs);
break;
case "ulid": {
addPattern(res, zodPatterns.ulid, check.message, refs);
break;
}
case "base64": {
switch (refs.base64Strategy) {
case "format:binary": {
addFormat(res, "binary", check.message, refs);
break;
}
case "contentEncoding:base64": {
res.contentEncoding = "base64";
break;
}
case "pattern:zod": {
addPattern(res, zodPatterns.base64, check.message, refs);
break;
}
}
break;
}
case "nanoid": {
addPattern(res, zodPatterns.nanoid, check.message, refs);
}
case "toLowerCase":
case "toUpperCase":
case "trim":
break;
default:
/* @__PURE__ */ ((_) => {
})(check);
}
}
}
return res;
}
function escapeLiteralCheckValue(literal, refs) {
return refs.patternStrategy === "escape" ? escapeNonAlphaNumeric(literal) : literal;
}
var ALPHA_NUMERIC = new Set(
"ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvxyz0123456789"
);
function escapeNonAlphaNumeric(source) {
let result = "";
for (let i = 0; i < source.length; i++) {
if (!ALPHA_NUMERIC.has(source[i])) {
result += "\\";
}
result += source[i];
}
return result;
}
function addFormat(schema, value, message, refs) {
var _a32;
if (schema.format || ((_a32 = schema.anyOf) == null ? void 0 : _a32.some((x) => x.format))) {
if (!schema.anyOf) {
schema.anyOf = [];
}
if (schema.format) {
schema.anyOf.push({
format: schema.format
});
delete schema.format;
}
schema.anyOf.push(__spreadValues({
format: value
}, message && refs.errorMessages && { errorMessage: { format: message } }));
} else {
schema.format = value;
}
}
function addPattern(schema, regex, message, refs) {
var _a32;
if (schema.pattern || ((_a32 = schema.allOf) == null ? void 0 : _a32.some((x) => x.pattern))) {
if (!schema.allOf) {
schema.allOf = [];
}
if (schema.pattern) {
schema.allOf.push({
pattern: schema.pattern
});
delete schema.pattern;
}
schema.allOf.push(__spreadValues({
pattern: stringifyRegExpWithFlags(regex, refs)
}, message && refs.errorMessages && { errorMessage: { pattern: message } }));
} else {
schema.pattern = stringifyRegExpWithFlags(regex, refs);
}
}
function stringifyRegExpWithFlags(regex, refs) {
var _a32;
if (!refs.applyRegexFlags || !regex.flags) {
return regex.source;
}
const flags = {
i: regex.flags.includes("i"),
// Case-insensitive
m: regex.flags.includes("m"),
// `^` and `$` matches adjacent to newline characters
s: regex.flags.includes("s")
// `.` matches newlines
};
const source = flags.i ? regex.source.toLowerCase() : regex.source;
let pattern = "";
let isEscaped = false;
let inCharGroup = false;
let inCharRange = false;
for (let i = 0; i < source.length; i++) {
if (isEscaped) {
pattern += source[i];
isEscaped = false;
continue;
}
if (flags.i) {
if (inCharGroup) {
if (source[i].match(/[a-z]/)) {
if (inCharRange) {
pattern += source[i];
pattern += `${source[i - 2]}-${source[i]}`.toUpperCase();
inCharRange = false;
} else if (source[i + 1] === "-" && ((_a32 = source[i + 2]) == null ? void 0 : _a32.match(/[a-z]/))) {
pattern += source[i];
inCharRange = true;
} else {
pattern += `${source[i]}${source[i].toUpperCase()}`;
}
continue;
}
} else if (source[i].match(/[a-z]/)) {
pattern += `[${source[i]}${source[i].toUpperCase()}]`;
continue;
}
}
if (flags.m) {
if (source[i] === "^") {
pattern += `(^|(?<=[\r
]))`;
continue;
} else if (source[i] === "$") {
pattern += `($|(?=[\r
]))`;
continue;
}
}
if (flags.s && source[i] === ".") {
pattern += inCharGroup ? `${source[i]}\r
` : `[${source[i]}\r
]`;
continue;
}
pattern += source[i];
if (source[i] === "\\") {
isEscaped = true;
} else if (inCharGroup && source[i] === "]") {
inCharGroup = false;
} else if (!inCharGroup && source[i] === "[") {
inCharGroup = true;
}
}
try {
new RegExp(pattern);
} catch (e) {
console.warn(
`Could not convert regex pattern at ${refs.currentPath.join(
"/"
)} to a flag-independent form! Falling back to the flag-ignorant source`
);
return regex.source;
}
return pattern;
}
function parseRecordDef(def, refs) {
var _a32, _b32, _c, _d, _e, _f;
const schema = {
type: "object",
additionalProperties: (_a32 = parseDef(def.valueType._def, __spreadProps(__spreadValues({}, refs), {
currentPath: [...refs.currentPath, "additionalProperties"]
}))) != null ? _a32 : refs.allowedAdditionalProperties
};
if (((_b32 = def.keyType) == null ? void 0 : _b32._def.typeName) === "ZodString" && ((_c = def.keyType._def.checks) == null ? void 0 : _c.length)) {
const _a18 = parseStringDef(def.keyType._def, refs), { type: _type } = _a18, keyType = __objRest(_a18, ["type"]);
return __spreadProps(__spreadValues({}, schema), {
propertyNames: keyType
});
} else if (((_d = def.keyType) == null ? void 0 : _d._def.typeName) === "ZodEnum") {
return __spreadProps(__spreadValues({}, schema), {
propertyNames: {
enum: def.keyType._def.values
}
});
} else if (((_e = def.keyType) == null ? void 0 : _e._def.typeName) === "ZodBranded" && def.keyType._def.type._def.typeName === "ZodString" && ((_f = def.keyType._def.type._def.checks) == null ? void 0 : _f.length)) {
const _b18 = parseBrandedDef(
def.keyType._def,
refs
), { type: _type } = _b18, keyType = __objRest(_b18, ["type"]);
return __spreadProps(__spreadValues({}, schema), {
propertyNames: keyType
});
}
return schema;
}
function parseMapDef(def, refs) {
if (refs.mapStrategy === "record") {
return parseRecordDef(def, refs);
}
const keys = parseDef(def.keyType._def, __spreadProps(__spreadValues({}, refs), {
currentPath: [...refs.currentPath, "items", "items", "0"]
})) || parseAnyDef();
const values = parseDef(def.valueType._def, __spreadProps(__spreadValues({}, refs), {
currentPath: [...refs.currentPath, "items", "items", "1"]
})) || parseAnyDef();
return {
type: "array",
maxItems: 125,
items: {
type: "array",
items: [keys, values],
minItems: 2,
maxItems: 2
}
};
}
function parseNativeEnumDef(def) {
const object = def.values;
const actualKeys = Object.keys(def.values).filter((key) => {
return typeof object[object[key]] !== "number";
});
const actualValues = actualKeys.map((key) => object[key]);
const parsedTypes = Array.from(
new Set(actualValues.map((values) => typeof values))
);
return {
type: parsedTypes.length === 1 ? parsedTypes[0] === "string" ? "string" : "number" : ["string", "number"],
enum: actualValues
};
}
function parseNeverDef() {
return { not: parseAnyDef() };
}
function parseNullDef() {
return {
type: "null"
};
}
var primitiveMappings = {
ZodString: "string",
ZodNumber: "number",
ZodBigInt: "integer",
ZodBoolean: "boolean",
ZodNull: "null"
};
function parseUnionDef(def, refs) {
const options = def.options instanceof Map ? Array.from(def.options.values()) : def.options;
if (options.every(
(x) => x._def.typeName in primitiveMappings && (!x._def.checks || !x._def.checks.length)
)) {
const types = options.reduce((types2, x) => {
const type = primitiveMappings[x._def.typeName];
return type && !types2.includes(type) ? [...types2, type] : types2;
}, []);
return {
type: types.length > 1 ? types : types[0]
};
} else if (options.every((x) => x._def.typeName === "ZodLiteral" && !x.description)) {
const types = options.reduce(
(acc, x) => {
const type = typeof x._def.value;
switch (type) {
case "string":
case "number":
case "boolean":
return [...acc, type];
case "bigint":
return [...acc, "integer"];
case "object":
if (x._def.value === null) return [...acc, "null"];
case "symbol":
case "undefined":
case "function":
default:
return acc;
}
},
[]
);
if (types.length === options.length) {
const uniqueTypes = types.filter((x, i, a) => a.indexOf(x) === i);
return {
type: uniqueTypes.length > 1 ? uniqueTypes : uniqueTypes[0],
enum: options.reduce(
(acc, x) => {
return acc.includes(x._def.value) ? acc : [...acc, x._def.value];
},
[]
)
};
}
} else if (options.every((x) => x._def.typeName === "ZodEnum")) {
return {
type: "string",
enum: options.reduce(
(acc, x) => [
...acc,
...x._def.values.filter((x2) => !acc.includes(x2))
],
[]
)
};
}
return asAnyOf(def, refs);
}
var asAnyOf = (def, refs) => {
const anyOf = (def.options instanceof Map ? Array.from(def.options.values()) : def.options).map(
(x, i) => parseDef(x._def, __spreadProps(__spreadValues({}, refs), {
currentPath: [...refs.currentPath, "anyOf", `${i}`]
}))
).filter(
(x) => !!x && (!refs.strictUnions || typeof x === "object" && Object.keys(x).length > 0)
);
return anyOf.length ? { anyOf } : void 0;
};
function parseNullableDef(def, refs) {
if (["ZodString", "ZodNumber", "ZodBigInt", "ZodBoolean", "ZodNull"].includes(
def.innerType._def.typeName
) && (!def.innerType._def.checks || !def.innerType._def.checks.length)) {
return {
type: [
primitiveMappings[def.innerType._def.typeName],
"null"
]
};
}
const base = parseDef(def.innerType._def, __spreadProps(__spreadValues({}, refs), {
currentPath: [...refs.currentPath, "anyOf", "0"]
}));
return base && { anyOf: [base, { type: "null" }] };
}
function parseNumberDef(def) {
const res = {
type: "number"
};
if (!def.checks) return res;
for (const check of def.checks) {
switch (check.kind) {
case "int":
res.type = "integer";
break;
case "min":
if (check.inclusive) {
res.minimum = check.value;
} else {
res.exclusiveMinimum = check.value;
}
break;
case "max":
if (check.inclusive) {
res.maximum = check.value;
} else {
res.exclusiveMaximum = check.value;
}
break;
case "multipleOf":
res.multipleOf = check.value;
break;
}
}
return res;
}
function parseObjectDef(def, refs) {
const result = {
type: "object",
properties: {}
};
const required = [];
const shape = def.shape();
for (const propName in shape) {
let propDef = shape[propName];
if (propDef === void 0 || propDef._def === void 0) {
continue;
}
const propOptional = safeIsOptional(propDef);
const parsedDef = parseDef(propDef._def, __spreadProps(__spreadValues({}, refs), {
currentPath: [...refs.currentPath, "properties", propName],
propertyPath: [...refs.currentPath, "properties", propName]
}));
if (parsedDef === void 0) {
continue;
}
result.properties[propName] = parsedDef;
if (!propOptional) {
required.push(propName);
}
}
if (required.length) {
result.required = required;
}
const additionalProperties = decideAdditionalProperties(def, refs);
if (additionalProperties !== void 0) {
result.additionalProperties = additionalProperties;
}
return result;
}
function decideAdditionalProperties(def, refs) {
if (def.catchall._def.typeName !== "ZodNever") {
return parseDef(def.catchall._def, __spreadProps(__spreadValues({}, refs), {
currentPath: [...refs.currentPath, "additionalProperties"]
}));
}
switch (def.unknownKeys) {
case "passthrough":
return refs.allowedAdditionalProperties;
case "strict":
return refs.rejectedAdditionalProperties;
case "strip":
return refs.removeAdditionalStrategy === "strict" ? refs.allowedAdditionalProperties : refs.rejectedAdditionalProperties;
}
}
function safeIsOptional(schema) {
try {
return schema.isOptional();
} catch (e) {
return true;
}
}
var parseOptionalDef = (def, refs) => {
var _a32;
if (refs.currentPath.toString() === ((_a32 = refs.propertyPath) == null ? void 0 : _a32.toString())) {
return parseDef(def.innerType._def, refs);
}
const innerSchema = parseDef(def.innerType._def, __spreadProps(__spreadValues({}, refs), {
currentPath: [...refs.currentPath, "anyOf", "1"]
}));
return innerSchema ? { anyOf: [{ not: parseAnyDef() }, innerSchema] } : parseAnyDef();
};
var parsePipelineDef = (def, refs) => {
if (refs.pipeStrategy === "input") {
return parseDef(def.in._def, refs);
} else if (refs.pipeStrategy === "output") {
return parseDef(def.out._def, refs);
}
const inputSchema = parseDef(def.in._def, __spreadProps(__spreadValues({}, refs), {
currentPath: [...refs.currentPath, "allOf", "0"]
}));
const outputSchema = parseDef(def.out._def, __spreadProps(__spreadValues({}, refs), {
currentPath: [...refs.currentPath, "allOf", inputSchema ? "1" : "0"]
}));
return {
allOf: [inputSchema, outputSchema].filter(
(schema) => schema !== void 0
)
};
};
function parsePromiseDef(def, refs) {
return parseDef(def.type._def, refs);
}
function parseSetDef(def, refs) {
const items = parseDef(def.valueType._def, __spreadProps(__spreadValues({}, refs), {
currentPath: [...refs.currentPath, "items"]
}));
const schema = {
type: "array",
uniqueItems: true,
items
};
if (def.minSize) {
schema.minItems = def.minSize.value;
}
if (def.maxSize) {
schema.maxItems = def.maxSize.value;
}
return schema;
}
function parseTupleDef(def, refs) {
if (def.rest) {
return {
type: "array",
minItems: def.items.length,
items: def.items.map(
(x, i) => parseDef(x._def, __spreadProps(__spreadValues({}, refs), {
currentPath: [...refs.currentPath, "items", `${i}`]
}))
).reduce(
(acc, x) => x === void 0 ? acc : [...acc, x],
[]
),
additionalItems: parseDef(def.rest._def, __spreadProps(__spreadValues({}, refs), {
currentPath: [...refs.currentPath, "additionalItems"]
}))
};
} else {
return {
type: "array",
minItems: def.items.length,
maxItems: def.items.length,
items: def.items.map(
(x, i) => parseDef(x._def, __spreadProps(__spreadValues({}, refs), {
currentPath: [...refs.currentPath, "items", `${i}`]
}))
).reduce(
(acc, x) => x === void 0 ? acc : [...acc, x],
[]
)
};
}
}
function parseUndefinedDef() {
return {
not: parseAnyDef()
};
}
function parseUnknownDef() {
return parseAnyDef();
}
var parseReadonlyDef = (def, refs) => {
return parseDef(def.innerType._def, refs);
};
var selectParser = (def, typeName, refs) => {
switch (typeName) {
case "ZodString":
return parseStringDef(def, refs);
case "ZodNumber":
return parseNumberDef(def);
case "ZodObject":
return parseObjectDef(def, refs);
case "ZodBigInt":
return parseBigintDef(def);
case "ZodBoolean":
return parseBooleanDef();
case "ZodDate":
return parseDateDef(def, refs);
case "ZodUndefined":
return parseUndefinedDef();
case "ZodNull":
return parseNullDef();
case "ZodArray":
return parseArrayDef(def, refs);
case "ZodUnion":
case "ZodDiscriminatedUnion":
return parseUnionDef(def, refs);
case "ZodIntersection":
return parseIntersectionDef(def, refs);
case "ZodTuple":
return parseTupleDef(def, refs);
case "ZodRecord":
return parseRecordDef(def, refs);
case "ZodLiteral":
return parseLiteralDef(def);
case "ZodEnum":
return parseEnumDef(def);
case "ZodNativeEnum":
return parseNativeEnumDef(def);
case "ZodNullable":
return parseNullableDef(def, refs);
case "ZodOptional":
return parseOptionalDef(def, refs);
case "ZodMap":
return parseMapDef(def, refs);
case "ZodSet":
return parseSetDef(def, refs);
case "ZodLazy":
return () => def.getter()._def;
case "ZodPromise":
return parsePromiseDef(def, refs);
case "ZodNaN":
case "ZodNever":
return parseNeverDef();
case "ZodEffects":
return parseEffectsDef(def, refs);
case "ZodAny":
return parseAnyDef();
case "ZodUnknown":
return parseUnknownDef();
case "ZodDefault":
return parseDefaultDef(def, refs);
case "ZodBranded":
return parseBrandedDef(def, refs);
case "ZodReadonly":
return parseReadonlyDef(def, refs);
case "ZodCatch":
return parseCatchDef(def, refs);
case "ZodPipeline":
return parsePipelineDef(def, refs);
case "ZodFunction":
case "ZodVoid":
case "ZodSymbol":
return void 0;
default:
return /* @__PURE__ */ ((_) => void 0)(typeName);
}
};
var getRelativePath = (pathA, pathB) => {
let i = 0;
for (; i < pathA.length && i < pathB.length; i++) {
if (pathA[i] !== pathB[i]) break;
}
return [(pathA.length - i).toString(), ...pathB.slice(i)].join("/");
};
function parseDef(def, refs, forceResolution = false) {
var _a32;
const seenItem = refs.seen.get(def);
if (refs.override) {
const overrideResult = (_a32 = refs.override) == null ? void 0 : _a32.call(
refs,
def,
refs,
seenItem,
forceResolution
);
if (overrideResult !== ignoreOverride) {
return overrideResult;
}
}
if (seenItem && !forceResolution) {
const seenSchema = get$ref(seenItem, refs);
if (seenSchema !== void 0) {
return seenSchema;
}
}
const newItem = { def, path: refs.currentPath, jsonSchema: void 0 };
refs.seen.set(def, newItem);
const jsonSchemaOrGetter = selectParser(def, def.typeName, refs);
const jsonSchema2 = typeof jsonSchemaOrGetter === "function" ? parseDef(jsonSchemaOrGetter(), refs) : jsonSchemaOrGetter;
if (jsonSchema2) {
addMeta(def, refs, jsonSchema2);
}
if (refs.postProcess) {
const postProcessResult = refs.postProcess(jsonSchema2, def, refs);
newItem.jsonSchema = jsonSchema2;
return postProcessResult;
}
newItem.jsonSchema = jsonSchema2;
return jsonSchema2;
}
var get$ref = (item, refs) => {
switch (refs.$refStrategy) {
case "root":
return { $ref: item.path.join("/") };
case "relative":
return { $ref: getRelativePath(refs.currentPath, item.path) };
case "none":
case "seen": {
if (item.path.length < refs.currentPath.length && item.path.every((value, index) => refs.currentPath[index] === value)) {
console.warn(
`Recursive reference detected at ${refs.currentPath.join(
"/"
)}! Defaulting to any`
);
return parseAnyDef();
}
return refs.$refStrategy === "seen" ? parseAnyDef() : void 0;
}
}
};
var addMeta = (def, refs, jsonSchema2) => {
if (def.description) {
jsonSchema2.description = def.description;
}
return jsonSchema2;
};
var getRefs = (options) => {
const _options = getDefaultOptions(options);
const currentPath = _options.name !== void 0 ? [..._options.basePath, _options.definitionPath, _options.name] : _options.basePath;
return __spreadProps(__spreadValues({}, _options), {
currentPath,
propertyPath: void 0,
seen: new Map(
Object.entries(_options.definitions).map(([name32, def]) => [
def._def,
{
def: def._def,
path: [..._options.basePath, _options.definitionPath, name32],
// Resolution of references will be forced even though seen, so it's ok that the schema is undefined here for now.
jsonSchema: void 0
}
])
)
});
};
var zod3ToJsonSchema = (schema, options) => {
var _a32;
const refs = getRefs(options);
let definitions = typeof options === "object" && options.definitions ? Object.entries(options.definitions).reduce(
(acc, [name42, schema2]) => {
var _a42;
return __spreadProps(__spreadValues({}, acc), {
[name42]: (_a42 = parseDef(
schema2._def,
__spreadProps(__spreadValues({}, refs), {
currentPath: [...refs.basePath, refs.definitionPath, name42]
}),
true
)) != null ? _a42 : parseAnyDef()
});
},
{}
) : void 0;
const name32 = typeof options === "string" ? options : (options == null ? void 0 : options.nameStrategy) === "title" ? void 0 : options == null ? void 0 : options.name;
const main = (_a32 = parseDef(
schema._def,
name32 === void 0 ? refs : __spreadProps(__spreadValues({}, refs), {
currentPath: [...refs.basePath, refs.definitionPath, name32]
}),
false
)) != null ? _a32 : parseAnyDef();
const title = typeof options === "object" && options.name !== void 0 && options.nameStrategy === "title" ? options.name : void 0;
if (title !== void 0) {
main.title = title;
}
const combined = name32 === void 0 ? definitions ? __spreadProps(__spreadValues({}, main), {
[refs.definitionPath]: definitions
}) : main : {
$ref: [
...refs.$refStrategy === "relative" ? [] : refs.basePath,
refs.definitionPath,
name32
].join("/"),
[refs.definitionPath]: __spreadProps(__spreadValues({}, definitions), {
[name32]: main
})
};
combined.$schema = "http://json-schema.org/draft-07/schema#";
return combined;
};
var schemaSymbol = /* @__PURE__ */ Symbol.for("vercel.ai.schema");
function jsonSchema(jsonSchema2, {
validate
} = {}) {
return {
[schemaSymbol]: true,
_type: void 0,
// should never be used directly
get jsonSchema() {
if (typeof jsonSchema2 === "function") {
jsonSchema2 = jsonSchema2();
}
return jsonSchema2;
},
validate
};
}
function isSchema(value) {
return typeof value === "object" && value !== null && schemaSymbol in value && value[schemaSymbol] === true && "jsonSchema" in value && "validate" in value;
}
function asSchema(schema) {
return schema == null ? jsonSchema({
type: "object",
properties: {},
additionalProperties: false
}) : isSchema(schema) ? schema : "~standard" in schema ? schema["~standard"].vendor === "zod" ? zodSchema(schema) : standardSchema(schema) : schema();
}
function standardSchema(standardSchema2) {
return jsonSchema(
() => {
if (!hasStandardJsonSchema(standardSchema2)) {
throw new Error(
`Standard schema vendor '${standardSchema2["~standard"].vendor}' does not support JSON Schema conversion.`
);
}
return addAdditionalPropertiesToJsonSchema(
standardSchema2["~standard"].jsonSchema.input({
target: "draft-07"
})
);
},
{
validate: async (value) => {
const result = await standardSchema2["~standard"].validate(value);
return "value" in result ? { success: true, value: result.value } : {
success: false,
error: new TypeValidationError({
value,
cause: result.issues
})
};
}
}
);
}
function hasStandardJsonSchema(schema) {
return schema["~standard"].jsonSchema != null;
}
function zod3Schema(zodSchema2, options) {
var _a32;
const useReferences = (_a32 = options == null ? void 0 : options.useReferences) != null ? _a32 : false;
return jsonSchema(
// defer json schema creation to avoid unnecessary computation when only validation is needed
() => zod3ToJsonSchema(zodSchema2, {
$refStrategy: useReferences ? "root" : "none"
}),
{
validate: async (value) => {
const result = await zodSchema2.safeParseAsync(value);
return result.success ? { success: true, value: result.data } : { success: false, error: result.error };
}
}
);
}
function zod4Schema(zodSchema2, options) {
var _a32;
const useReferences = (_a32 = options == null ? void 0 : options.useReferences) != null ? _a32 : false;
return jsonSchema(
// defer json schema creation to avoid unnecessary computation when only validation is needed
() => addAdditionalPropertiesToJsonSchema(
toJSONSchema(zodSchema2, {
target: "draft-7",
io: "input",
reused: useReferences ? "ref" : "inline"
})
),
{
validate: async (value) => {
const result = await safeParseAsync(zodSchema2, value);
return result.success ? { success: true, value: result.data } : { success: false, error: result.error };
}
}
);
}
function isZod4Schema(zodSchema2) {
return "_zod" in zodSchema2;
}
function zodSchema(zodSchema2, options) {
if (isZod4Schema(zodSchema2)) {
return zod4Schema(zodSchema2, options);
} else {
return zod3Schema(zodSchema2, options);
}
}
async function validateTypes({
value,
schema,
context
}) {
const result = await safeValidateTypes({ value, schema, context });
if (!result.success) {
throw TypeValidationError.wrap({ value, cause: result.error, context });
}
return result.value;
}
async function safeValidateTypes({
value,
schema,
context
}) {
const actualSchema = asSchema(schema);
try {
if (actualSchema.validate == null) {
return { success: true, value, rawValue: value };
}
const result = await actualSchema.validate(value);
if (result.success) {
return { success: true, value: result.value, rawValue: value };
}
return {
success: false,
error: TypeValidationError.wrap({ value, cause: result.error, context }),
rawValue: value
};
} catch (error) {
return {
success: false,
error: TypeValidationError.wrap({ value, cause: error, context }),
rawValue: value
};
}
}
async function parseJSON({
text,
schema
}) {
try {
const value = secureJsonParse(text);
if (schema == null) {
return value;
}
return await 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 }));
}
})
);
}
async function parseProviderOptions({
provider,
providerOptions,
schema
}) {
if ((providerOptions == null ? void 0 : providerOptions[provider]) == null) {
return void 0;
}
const parsedProviderOptions = await safeValidateTypes({
value: providerOptions[provider],
schema
});
if (!parsedProviderOptions.success) {
throw new InvalidArgumentError({
argument: "providerOptions",
message: `invalid ${provider} provider options`,
cause: parsedProviderOptions.error
});
}
return parsedProviderOptions.value;
}
var getOriginalFetch4 = () => globalThis.fetch;
var postJsonToApi = async ({
url,
headers,
body,
failedResponseHandler,
successfulResponseHandler,
abortSignal,
fetch
}) => await 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 = getOriginalFetch4()
}) => {
try {
const response = await fetch(url, {
method: "POST",
headers: withUserAgentSuffix(
headers,
`ai-sdk/provider-utils/${VERSION}`,
getRuntimeEnvironmentUserAgent()
),
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 textDecoder2 = new TextDecoder();
function wrapResponseBodyStream({
stream,
url,
requestBodyValues,
statusCode,
responseHeaders
}) {
const reader = stream.getReader();
let readerReleased = false;
const releaseReader = () => {
if (!readerReleased) {
reader.releaseLock();
readerReleased = true;
}
};
return new ReadableStream({
async pull(controller) {
try {
const { done, value } = await reader.read();
if (done) {
releaseReader();
controller.close();
} else {
controller.enqueue(value);
}
} catch (error) {
releaseReader();
if (isAbortError(error)) {
controller.error(error);
return;
}
controller.error(
handleFetchError({
error: new APICallError({
message: "Failed to process successful response",
cause: error,
statusCode,
url,
responseHeaders,
requestBodyValues
}),
url,
requestBodyValues
})
);
}
},
async cancel(reason) {
try {
await reader.cancel(reason);
} finally {
releaseReader();
}
}
});
}
async function readResponseBodyAsText({
response,
url
}) {
return textDecoder2.decode(
await readResponseWithSizeLimit({
response,
url
})
);
}
var createJsonErrorResponseHandler = ({
errorSchema,
errorToMessage,
isRetryable
}) => async ({ response, url, requestBodyValues }) => {
const responseBody = await readResponseBodyAsText({ response, url });
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 (e) {
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, url, requestBodyValues }) => {
const responseHeaders = extractResponseHeaders(response);
if (response.body == null) {
throw new EmptyResponseBodyError({});
}
return {
responseHeaders,
value: parseJsonEventStream({
stream: wrapResponseBodyStream({
stream: response.body,
url,
requestBodyValues,
statusCode: response.status,
responseHeaders
}),
schema: chunkSchema
})
};
};
var createJsonResponseHandler = (responseSchema) => async ({ response, url, requestBodyValues }) => {
const responseBody = await readResponseBodyAsText({ response, url });
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 name22 = "AI_SerializationError";
var marker32 = `vercel.ai.error.${name22}`;
var symbol22 = Symbol.for(marker32);
var _a22;
var _b22;
var SerializationError = class extends (_b22 = AISDKError, _a22 = symbol22, _b22) {
// used in isInstance
constructor({
message = "Failed to serialize value.",
cause
} = {}) {
super({ name: name22, message, cause });
this[_a22] = true;
}
static isInstance(error) {
return AISDKError.hasMarker(error, marker32);
}
};
// src/schemas/reasoning-details.ts
import { z } from "zod/v4";
// src/utils/type-guards.ts
function isDefinedOrNotNull(value) {
return value !== null && value !== void 0;
}
// src/schemas/format.ts
var ReasoningFormat = /* @__PURE__ */ ((ReasoningFormat2) => {
ReasoningFormat2["Unknown"] = "unknown";
ReasoningFormat2["OpenAIResponsesV1"] = "openai-responses-v1";
ReasoningFormat2["AzureOpenAIResponsesV1"] = "azure-openai-responses-v1";
ReasoningFormat2["XAIResponsesV1"] = "xai-responses-v1";
ReasoningFormat2["AnthropicClaudeV1"] = "anthropic-claude-v1";
ReasoningFormat2["GoogleGeminiV1"] = "google-gemini-v1";
return ReasoningFormat2;
})(ReasoningFormat || {});
var DEFAULT_REASONING_FORMAT = "anthropic-claude-v1" /* AnthropicClaudeV1 */;
// src/schemas/reasoning-details.ts
var CommonReasoningDetailSchema = z.object({
id: z.string().nullish(),
format: z.enum(ReasoningFormat).nullish(),
index: z.number().optional()
}).loose();
var ReasoningDetailSummarySchema = z.object({
type: z.literal("reasoning.summary" /* Summary */),
summary: z.string()
}).extend(CommonReasoningDetailSchema.shape);
var ReasoningDetailEncryptedSchema = z.object({
type: z.literal("reasoning.encrypted" /* Encrypted */),
data: z.string()
}).extend(CommonReasoningDetailSchema.shape);
var ReasoningDetailTextSchema = z.object({
type: z.literal("reasoning.text" /* Text */),
text: z.string().nullish(),
signature: z.string().nullish()
}).extend(CommonReasoningDetailSchema.shape);
var ReasoningDetailUnionSchema = z.union([
ReasoningDetailSummarySchema,
ReasoningDetailEncryptedSchema,
ReasoningDetailTextSchema
]);
var ReasoningDetailsWithUnknownSchema = z.union([
ReasoningDetailUnionSchema,
z.unknown().transform(() => null)
]);
var ReasoningDetailArraySchema = z.array(ReasoningDetailsWithUnknownSchema).transform((d) => d.filter((d2) => !!d2));
var OutputUnionToReasoningDetailsSchema = z.union([
z.object({
delta: z.object({
reasoning_details: z.array(ReasoningDetailsWithUnknownSchema)
})
}).transform(
(data) => data.delta.reasoning_details.filter(isDefinedOrNotNull)
),
z.object({
message: z.object({
reasoning_details: z.array(ReasoningDetailsWithUnknownSchema)
})
}).transform(
(data) => data.message.reasoning_details.filter(isDefinedOrNotNull)
),
z.object({
text: z.string(),
reasoning_details: z.array(ReasoningDetailsWithUnknownSchema)
}).transform((data) => data.reasoning_details.filter(isDefinedOrNotNull))
]);
// src/schemas/error-response.ts
import { z as z2 } from "zod/v4";
var OpenRouterErrorResponseSchema = z2.object({
error: z2.object({
code: z2.union([z2.string(), z2.number()]).nullable().optional().default(null),
message: z2.string(),
type: z2.string().nullable().optional().default(null),
param: z2.any().nullable().optional().default(null)
}).passthrough()
}).passthrough();
function extractErrorMessage(data) {
const error = data.error;
const metadata = error.metadata;
if (!metadata) {
return data.error.message;
}
const parts = [];
if (typeof metadata.provider_name === "string" && metadata.provider_name) {
parts.push(`[${metadata.provider_name}]`);
}
const raw = metadata.raw;
const rawMessage = extractRawMessage(raw);
if (rawMessage && rawMessage !== data.error.message) {
parts.push(rawMessage);
} else {
parts.push(data.error.message);
}
return parts.join(" ");
}
function extractRawMessage(raw) {
if (typeof raw === "string") {
try {
const parsed = JSON.parse(raw);
if (typeof parsed === "object" && parsed !== null) {
return extractRawMessage(parsed);
}
return raw;
} catch (e) {
return raw;
}
}
if (typeof raw !== "object" || raw === null) {
return void 0;
}
const obj = raw;
for (const field of ["message", "error", "detail", "details", "msg"]) {
const value = obj[field];
if (typeof value === "string" && value.length > 0) {
return value;
}
if (typeof value === "object" && value !== null) {
const nested = extractRawMessage(value);
if (nested) {
return nested;
}
}
}
return void 0;
}
var openrouterFailedResponseHandler = createJsonErrorResponseHandler({
errorSchema: OpenRouterErrorResponseSchema,
errorToMessage: extractErrorMessage
});
// src/schemas/provider-metadata.ts
import { z as z3 } from "zod/v4";
var FileAnnotationSchema = z3.object({
type: z3.literal("file"),
file: z3.object({
hash: z3.string(),
name: z3.string(),
content: z3.array(
z3.object({
type: z3.string(),
text: z3.string().optional()
}).catchall(z3.any())
).optional()
}).catchall(z3.any())
}).catchall(z3.any());
var OpenRouterProviderMetadataSchema = z3.object({
provider: z3.string(),
reasoning_details: z3.array(ReasoningDetailUnionSchema).optional(),
annotations: z3.array(FileAnnotationSchema).optional(),
usage: z3.object({
promptTokens: z3.number(),
promptTokensDetails: z3.object({
cachedTokens: z3.number()
}).catchall(z3.any()).optional(),
completionTokens: z3.number(),
completionTokensDetails: z3.object({
reasoningTokens: z3.number()
}).catchall(z3.any()).optional(),
totalTokens: z3.number(),
cost: z3.number().optional(),
costDetails: z3.object({
upstreamInferenceCost: z3.number()
}).catchall(z3.any()).optional()
}).catchall(z3.any())
}).catchall(z3.any());
var OpenRouterProviderOptionsSchema = z3.object({
openrouter: z3.object({
// Use ReasoningDetailArraySchema (with unknown fallback) instead of
// z.array(ReasoningDetailUnionSchema) so that a single malformed entry
// (e.g., a future format not yet in the enum) is individually dropped
// rather than causing the entire array to fail parsing.
reasoning_details: ReasoningDetailArraySchema.optional(),
annotations: z3.array(FileAnnotationSchema).optional()
}).optional()
}).optional();
// src/utils/compute-token-usage.ts
function computeTokenUsage(usage) {
var _a18, _b18, _c, _d, _e, _f, _g, _h;
const promptTokens = (_a18 = usage.prompt_tokens) != null ? _a18 : 0;
const completionTokens = (_b18 = usage.completion_tokens) != null ? _b18 : 0;
const cacheReadTokens = (_d = (_c = usage.prompt_tokens_details) == null ? void 0 : _c.cached_tokens) != null ? _d : 0;
const cacheWriteTokens = (_f = (_e = usage.prompt_tokens_details) == null ? void 0 : _e.cache_write_tokens) != null ? _f : void 0;
const reasoningTokens = (_h = (_g = usage.completion_tokens_details) == null ? void 0 : _g.reasoning_tokens) != null ? _h : 0;
return {
inputTokens: {
total: promptTokens,
noCache: promptTokens - cacheReadTokens,
cacheRead: cacheReadTokens,
cacheWrite: cacheWriteTokens
},
outputTokens: {
total: completionTokens,
text: completionTokens - reasoningTokens,
reasoning: reasoningTokens
},
raw: usage
};
}
function emptyUsage() {
return {
inputTokens: {
total: 0,
noCache: void 0,
cacheRead: void 0,
cacheWrite: void 0
},
outputTokens: {
total: 0,
text: void 0,
reasoning: void 0
},
raw: void 0
};
}
// src/utils/map-finish-reason.ts
function mapToUnified(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 "other";
}
}
function mapOpenRouterFinishReason(finishReason) {
return {
unified: mapToUnified(finishReason),
raw: finishReason != null ? finishReason : void 0
};
}
function createFinishReason(unified, raw) {
return { unified, raw };
}
// src/utils/with-stream-error-handling.ts
function withStreamErrorHandling(source, onError) {
const reader = source.getReader();
return new ReadableStream({
async pull(controller) {
try {
const { done, value } = await reader.read();
if (done) {
controller.close();
} else {
controller.enqueue(value);
}
} catch (err) {
onError(err);
reader.cancel().catch(() => {
});
controller.close();
}
},
cancel(reason) {
reader.cancel(reason);
}
});
}
// src/utils/deterministic-stringify.ts
function deterministicStringify(value) {
return JSON.stringify(sortKeys(value));
}
function sortKeys(value) {
if (value === null || value === void 0) {
return value;
}
if (Array.isArray(value)) {
return value.map(sortKeys);
}
if (typeof value === "object") {
const sorted = {};
const entries = Object.entries(value);
entries.sort(([a], [b]) => a.localeCompare(b));
for (const [key, val] of entries) {
sorted[key] = sortKeys(val);
}
return sorted;
}
return value;
}
// src/utils/reasoning-details-duplicate-tracker.ts
var _seenKeys;
var ReasoningDetailsDuplicateTracker = class {
constructor() {
__privateAdd(this, _seenKeys, /* @__PURE__ */ new Set());
}
/**
* Attempts to track a detail.
* Returns true if this is a NEW detail (not seen before and has valid key),
* false if it was skipped (no valid key) or already seen (duplicate).
*/
upsert(detail) {
const key = this.getCanonicalKey(detail);
if (key === null) {
return false;
}
if (__privateGet(this, _seenKeys).has(key)) {
return false;
}
__privateGet(this, _seenKeys).add(key);
return true;
}
getCanonicalKey(detail) {
switch (detail.type) {
case "reasoning.summary" /* Summary */:
return detail.summary;
case "reasoning.encrypted" /* Encrypted */:
if (detail.id) {
return detail.id;
}
return detail.data;
case "reasoning.text" /* Text */: {
if (detail.text) {
return detail.text;
}
if (detail.signature) {
return detail.signature;
}
return null;
}
default: {
return null;
}
}
}
};
_seenKeys = new WeakMap();
// src/types/openrouter-chat-completions-input.ts
var OPENROUTER_AUDIO_FORMATS = [
"wav",
"mp3",
"aiff",
"aac",
"ogg",
"flac",
"m4a",
"pcm16",
"pcm24"
];
// 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 buildFileDataUrl({
data,
mediaType,
defaultMediaType
}) {
if (data instanceof Uint8Array) {
const base64 = convertUint8ArrayToBase64(data);
return `data:${mediaType != null ? mediaType : defaultMediaType};base64,${base64}`;
}
const stringData = data.toString();
if (isUrl({
url: stringData,
protocols: /* @__PURE__ */ new Set(["http:", "https:"])
})) {
return stringData;
}
return stringData.startsWith("data:") ? stringData : `data:${mediaType != null ? mediaType : defaultMediaType};base64,${stringData}`;
}
function getFileUrl({
part,
defaultMediaType
}) {
return getFileDataUrl({
data: part.data,
mediaType: part.mediaType,
defaultMediaType
});
}
function getFileDataUrl({
data,
mediaType,
defaultMediaType
}) {
switch (data.type) {
case "data":
return buildFileDataUrl({
data: data.data,
mediaType,
defaultMediaType
});
case "url": {
const url = data.url.toString();
if (url.startsWith("data:") || isUrl({
url,
protocols: /* @__PURE__ */ new Set(["http:", "https:"])
})) {
return url;
}
throw new Error(
"Only http(s) and data: file URLs are supported by OpenRouter"
);
}
case "text": {
const encoded = new TextEncoder().encode(data.text);
return buildFileDataUrl({
data: encoded,
mediaType: mediaType != null ? mediaType : "text/plain",
defaultMediaType
});
}
case "reference":
throw new Error(
"Provider file references are not supported by OpenRouter"
);
}
const _exhaustiveCheck = data;
return buildFileDataUrl({
data: _exhaustiveCheck,
mediaType,
defaultMediaType
});
}
function getMediaType(dataUrl, defaultMediaType) {
var _a18;
const match = dataUrl.match(/^data:([^;]+)/);
return match ? (_a18 = match[1]) != null ? _a18 : defaultMediaType : defaultMediaType;
}
function getBase64FromDataUrl(dataUrl) {
const match = dataUrl.match(/^data:[^;]*;base64,(.+)$/);
return match ? match[1] : dataUrl;
}
var MIME_TO_FORMAT = {
// MP3 variants
mpeg: "mp3",
mp3: "mp3",
// WAV variants
"x-wav": "wav",
wave: "wav",
wav: "wav",
// OGG variants
ogg: "ogg",
vorbis: "ogg",
// AAC variants
aac: "aac",
"x-aac": "aac",
// M4A variants
m4a: "m4a",
"x-m4a": "m4a",
mp4: "m4a",
// AIFF variants
aiff: "aiff",
"x-aiff": "aiff",
// FLAC
flac: "flac",
"x-flac": "flac",
// PCM variants
pcm16: "pcm16",
pcm24: "pcm24"
};
function getInputAudioData(part) {
const fileData = getFileUrl({
part,
defaultMediaType: "audio/mpeg"
});
if (isUrl({
url: fileData,
protocols: /* @__PURE__ */ new Set(["http:", "https:"])
})) {
throw new Error(
`Audio files cannot be provided as URLs.
OpenRouter requires audio to be base64-encoded. Please:
1. Download the audio file locally
2. Read it as a Buffer or Uint8Array
3. Pass it as the data parameter
The AI SDK will automatically handle base64 encoding.
Learn more: https://openrouter.ai/docs/features/multimodal/audio`
);
}
const data = getBase64FromDataUrl(fileData);
const mediaType = part.mediaType || "audio/mpeg";
const rawFormat = mediaType.replace("audio/", "");
const format = MIME_TO_FORMAT[rawFormat];
if (format === void 0) {
const supportedList = OPENROUTER_AUDIO_FORMATS.join(", ");
throw new Error(
`Unsupported audio format: "${mediaType}"
OpenRouter supports the following audio formats: ${supportedList}
Learn more: https://openrouter.ai/docs/features/multimodal/audio`
);
}
return { data, format };
}
// src/chat/convert-to-openrouter-chat-messages.ts
function getCacheControl(providerMetadata) {
var _a18, _b18, _c;
const anthropic = providerMetadata == null ? void 0 : providerMetadata.anthropic;
const openrouter = providerMetadata == null ? void 0 : providerMetadata.openrouter;
return (_c = (_b18 = (_a18 = openrouter == null ? void 0 : openrouter.cacheControl) != null ? _a18 : openrouter == null ? void 0 : openrouter.cache_control) != null ? _b18 : anthropic == null ? void 0 : anthropic.cacheControl) != null ? _c : anthropic == null ? void 0 : anthropic.cache_control;
}
function convertToOpenRouterChatMessages(prompt) {
var _a18, _b18, _c, _d, _e, _f, _g, _h;
const messages = [];
const reasoningDetailsTracker = new ReasoningDetailsDuplicateTracker();
for (const { role, content, providerOptions } of prompt) {
switch (role) {
case "system": {
const cacheControl = getCacheControl(providerOptions);
messages.push({
role: "system",
content: [
__spreadValues({
type: "text",
text: content
}, cacheControl && { cache_control: cacheControl })
]
});
break;
}
case "user": {
if (content.length === 1 && ((_a18 = content[0]) == null ? void 0 : _a18.type) === "text") {
const cacheControl = (_b18 = getCacheControl(providerOptions)) != null ? _b18 : 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);
let lastTextPartIndex = -1;
for (let i = content.length - 1; i >= 0; i--) {
if (((_c = content[i]) == null ? void 0 : _c.type) === "text") {
lastTextPartIndex = i;
break;
}
}
const contentParts = content.map(
(part, index) => {
var _a19, _b19, _c2, _d2, _e2, _f2, _g2;
const isLastTextPart = part.type === "text" && index === lastTextPartIndex;
const partCacheControl = getCacheControl(part.providerOptions);
const cacheControl = part.type === "text" ? partCacheControl != null ? partCacheControl : isLastTextPart ? messageCacheControl : void 0 : partCacheControl;
switch (part.type) {
case "text":
return __spreadValues({
type: "text",
text: part.text
}, cacheControl && { cache_control: cacheControl });
case "file": {
if ((_a19 = part.mediaType) == null ? void 0 : _a19.startsWith("image/")) {
const url = getFileUrl({
part,
defaultMediaType: "image/jpeg"
});
return __spreadValues({
type: "image_url",
image_url: {
url
}
}, cacheControl && { cache_control: cacheControl });
}
if ((_b19 = part.mediaType) == null ? void 0 : _b19.startsWith("video/")) {
const url = getFileUrl({
part,
defaultMediaType: "video/mp4"
});
return __spreadValues({
type: "video_url",
video_url: {
url
}
}, cacheControl && { cache_control: cacheControl });
}
if ((_c2 = part.mediaType) == null ? void 0 : _c2.startsWith("audio/")) {
return __spreadValues({
type: "input_audio",
input_audio: getInputAudioData(part)
}, cacheControl && { cache_control: cacheControl });
}
const fileName = String(
(_g2 = (_f2 = (_e2 = (_d2 = part.providerOptions) == null ? void 0 : _d2.openrouter) == null ? void 0 : _e2.filename) != null ? _f2 : part.filename) != null ? _g2 : ""
);
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 __spreadValues({
type: "file",
file: {
filename: fileName,
file_data: fileData
}
}, cacheControl && { cache_control: cacheControl });
}
default: {
return __spreadValues({
type: "text",
text: ""
}, cacheControl && { cache_control: cacheControl });
}
}
}
);
messages.push({
role: "user",
content: contentParts
});
break;
}
case "assistant": {
let text = "";
let reasoning = "";
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: deterministicStringify(part.input)
}
});
break;
}
case "reasoning": {
reasoning += part.text;
break;
}
case "file":
break;
default: {
break;
}
}
}
const parsedProviderOptions = OpenRouterProviderOptionsSchema.safeParse(providerOptions);
const messageReasoningDetails = parsedProviderOptions.success ? (_e = (_d = parsedProviderOptions.data) == null ? void 0 : _d.openrouter) == null ? void 0 : _e.reasoning_details : void 0;
const messageAnnotations = parsedProviderOptions.success ? (_g = (_f = parsedProviderOptions.data) == null ? void 0 : _f.openrouter) == null ? void 0 : _g.annotations : void 0;
const candidateReasoningDetails = messageReasoningDetails && Array.isArray(messageReasoningDetails) ? messageReasoningDetails : findFirstReasoningDetails(content);
let finalReasoningDetails;
if (candidateReasoningDetails) {
const validDetails = candidateReasoningDetails.filter((detail) => {
var _a19;
if (detail.type !== "reasoning.text" /* Text */) {
return true;
}
const format = (_a19 = detail.format) != null ? _a19 : DEFAULT_REASONING_FORMAT;
if (format !== "anthropic-claude-v1" /* AnthropicClaudeV1 */ && format !== "google-gemini-v1" /* GoogleGeminiV1 */) {
return true;
}
return !!detail.signature;
});
if (validDetails.length < candidateReasoningDetails.length) {
const logger = globalThis.AI_SDK_LOG_WARNINGS;
if (logger !== false && typeof logger !== "function") {
console.warn(
"[openrouter] Some reasoning_details entries were removed because they were missing signatures. See https://github.com/OpenRouterTeam/ai-sdk-provider/issues/423 and https://github.com/OpenRouterTeam/ai-sdk-provider/issues/418 for more details."
);
}
}
const uniqueDetails = [];
for (const detail of validDetails) {
if (reasoningDetailsTracker.upsert(detail)) {
uniqueDetails.push(detail);
}
}
finalReasoningDetails = uniqueDetails;
}
const effectiveReasoning = reasoning && finalReasoningDetails && finalReasoningDetails.length > 0 ? reasoning : void 0;
messages.push({
role: "assistant",
content: text || null,
tool_calls: toolCalls.length > 0 ? toolCalls : void 0,
reasoning: effectiveReasoning,
reasoning_details: finalReasoningDetails,
annotations: messageAnnotations,
cache_control: getCacheControl(providerOptions)
});
break;
}
case "tool": {
for (const toolResponse of content) {
if (toolResponse.type === "tool-approval-response") {
continue;
}
const content2 = getToolResultContent(toolResponse);
messages.push({
role: "tool",
tool_call_id: toolResponse.toolCallId,
content: content2,
name: toolResponse.toolName,
cache_control: (_h = getCacheControl(providerOptions)) != null ? _h : getCacheControl(toolResponse.providerOptions)
});
}
break;
}
default: {
break;
}
}
}
return messages;
}
function getToolResultContent(input) {
var _a18;
switch (input.output.type) {
case "text":
case "error-text":
return input.output.value;
case "json":
case "error-json":
return JSON.stringify(input.output.value);
case "content":
return mapToolResultContentParts(input.output.value);
case "execution-denied":
return (_a18 = input.output.reason) != null ? _a18 : "Tool execution denied";
}
}
function mapToolResultContentParts(parts) {
return parts.map((part) => {
var _a18, _b18, _c, _d;
switch (part.type) {
case "text":
return { type: "text", text: part.text };
case "file": {
const dataUrl = getFileDataUrl({
data: part.data,
mediaType: part.mediaType,
defaultMediaType: "application/octet-stream"
});
if ((_a18 = part.mediaType) == null ? void 0 : _a18.startsWith("image/")) {
return {
type: "image_url",
image_url: { url: dataUrl }
};
}
if ((_b18 = part.mediaType) == null ? void 0 : _b18.startsWith("video/")) {
return {
type: "video_url",
video_url: { url: dataUrl }
};
}
if ((_c = part.mediaType) == null ? void 0 : _c.startsWith("audio/")) {
const rawFormat = part.mediaType.replace("audio/", "");
const format = MIME_TO_FORMAT[rawFormat];
if (format !== void 0) {
return {
type: "input_audio",
input_audio: {
data: getBase64FromDataUrl(dataUrl),
format
}
};
}
}
return {
type: "file",
file: {
filename: (_d = part.filename) != null ? _d : "",
file_data: dataUrl
}
};
}
case "custom":
return { type: "text", text: JSON.stringify(part) };
default: {
const _exhaustiveCheck = part;
return { type: "text", text: JSON.stringify(_exhaustiveCheck) };
}
}
});
}
function findFirstReasoningDetails(content) {
var _a18, _b18, _c, _d;
for (const part of content) {
if (part.type === "tool-call") {
const parsed = OpenRouterProviderOptionsSchema.safeParse(
part.providerOptions
);
if (parsed.success && ((_b18 = (_a18 = parsed.data) == null ? void 0 : _a18.openrouter) == null ? void 0 : _b18.reasoning_details) && parsed.data.openrouter.reasoning_details.length > 0) {
return parsed.data.openrouter.reasoning_details;
}
}
}
for (const part of content) {
if (part.type === "reasoning") {
const parsed = OpenRouterProviderOptionsSchema.safeParse(
part.providerOptions
);
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) {
return parsed.data.openrouter.reasoning_details;
}
}
}
return void 0;
}
// src/chat/get-tool-choice.ts
import { z as z4 } from "zod/v4";
var ChatCompletionToolChoiceSchema = z4.union([
z4.literal("auto"),
z4.literal("none"),
z4.literal("required"),
z4.object({
type: z4.literal("function"),
function: z4.object({
name: z4.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 InvalidArgumentError({
argument: "toolChoice",
message: `Invalid tool choice type: ${JSON.stringify(toolChoice)}`
});
}
}
}
// src/chat/schemas.ts
import { z as z6 } from "zod/v4";
// src/schemas/image.ts
import { z as z5 } from "zod/v4";
var ImageResponseSchema = z5.object({
type: z5.literal("image_url"),
image_url: z5.object({
url: z5.string()
}).passthrough()
}).passthrough();
var ImageResponseWithUnknownSchema = z5.union([
ImageResponseSchema,
z5.unknown().transform(() => null)
]);
var ImageResponseArraySchema = z5.array(ImageResponseWithUnknownSchema).transform((d) => d.filter((d2) => !!d2));
// src/chat/schemas.ts
var OpenRouterChatCompletionBaseResponseSchema = z6.object({
id: z6.string().optional(),
model: z6.string().optional(),
provider: z6.string().optional(),
usage: z6.object({
prompt_tokens: z6.number(),
prompt_tokens_details: z6.object({
cached_tokens: z6.number(),
cache_write_tokens: z6.number().nullish()
}).passthrough().nullish(),
completion_tokens: z6.number(),
completion_tokens_details: z6.object({
reasoning_tokens: z6.number()
}).passthrough().nullish(),
total_tokens: z6.number(),
cost: z6.number().optional(),
cost_details: z6.object({
upstream_inference_cost: z6.number().nullish()
}).passthrough().nullish()
}).passthrough().nullish()
}).passthrough();
var OpenRouterNonStreamChatCompletionResponseSchema = z6.union([
// Success response with choices
OpenRouterChatCompletionBaseResponseSchema.extend({
choices: z6.array(
z6.object({
message: z6.object({
role: z6.literal("assistant"),
content: z6.string().nullable().optional(),
reasoning: z6.string().nullable().optional(),
reasoning_details: ReasoningDetailArraySchema.nullish(),
images: ImageResponseArraySchema.nullish(),
tool_calls: z6.array(
z6.object({
id: z6.string().optional().nullable(),
type: z6.literal("function"),
function: z6.object({
name: z6.string(),
arguments: z6.string().optional()
}).passthrough()
}).passthrough()
).optional(),
annotations: z6.array(
z6.union([
// URL citation from web search
// title, start_index, end_index are optional as some upstream providers may omit them
z6.object({
type: z6.literal("url_citation"),
url_citation: z6.object({
url: z6.string(),
title: z6.string().optional(),
start_index: z6.number().optional(),
end_index: z6.number().optional(),
content: z6.string().optional()
}).passthrough()
}).passthrough(),
// File annotation from FileParserPlugin (old format)
z6.object({
type: z6.literal("file_annotation"),
file_annotation: z6.object({
file_id: z6.string(),
quote: z6.string().optional()
}).passthrough()
}).passthrough(),
// File annotation from FileParserPlugin (new format)
z6.object({
type: z6.literal("file"),
file: z6.object({
hash: z6.string(),
name: z6.string(),
content: z6.array(
z6.object({
type: z6.string(),
text: z6.string().optional()
}).passthrough()
).optional()
}).passthrough()
}).passthrough()
])
).nullish()
}).passthrough(),
index: z6.number().nullish(),
logprobs: z6.object({
content: z6.array(
z6.object({
token: z6.string(),
logprob: z6.number(),
top_logprobs: z6.array(
z6.object({
token: z6.string(),
logprob: z6.number()
}).passthrough()
)
}).passthrough()
).nullable()
}).passthrough().nullable().optional(),
finish_reason: z6.string().optional().nullable()
}).passthrough()
)
}),
// Error response (HTTP 200 with error payload)
OpenRouterErrorResponseSchema.extend({
user_id: z6.string().optional()
})
]);
var OpenRouterStreamChatCompletionChunkSchema = z6.union([
OpenRouterChatCompletionBaseResponseSchema.extend({
choices: z6.array(
z6.object({
delta: z6.object({
role: z6.enum(["assistant"]).optional(),
content: z6.string().nullish(),
reasoning: z6.string().nullish().optional(),
reasoning_details: ReasoningDetailArraySchema.nullish(),
images: ImageResponseArraySchema.nullish(),
tool_calls: z6.array(
z6.object({
index: z6.number().nullish(),
id: z6.string().nullish(),
type: z6.literal("function").optional(),
function: z6.object({
name: z6.string().nullish(),
arguments: z6.string().nullish()
}).passthrough()
}).passthrough()
).nullish(),
annotations: z6.array(
z6.union([
// URL citation from web search
// title, start_index, end_index are optional as some upstream providers may omit them
z6.object({
type: z6.literal("url_citation"),
url_citation: z6.object({
url: z6.string(),
title: z6.string().optional(),
start_index: z6.number().optional(),
end_index: z6.number().optional(),
content: z6.string().optional()
}).passthrough()
}).passthrough(),
// File annotation from FileParserPlugin (old format)
z6.object({
type: z6.literal("file_annotation"),
file_annotation: z6.object({
file_id: z6.string(),
quote: z6.string().optional()
}).passthrough()
}).passthrough(),
// File annotation from FileParserPlugin (new format)
z6.object({
type: z6.literal("file"),
file: z6.object({
hash: z6.string(),
name: z6.string(),
content: z6.array(
z6.object({
type: z6.string(),
text: z6.string().optional()
}).passthrough()
).optional()
}).passthrough()
}).passthrough()
])
).nullish()
}).passthrough().nullish(),
logprobs: z6.object({
content: z6.array(
z6.object({
token: z6.string(),
logprob: z6.number(),
top_logprobs: z6.array(
z6.object({
token: z6.string(),
logprob: z6.number()
}).passthrough()
)
}).passthrough()
).nullable()
}).passthrough().nullish(),
finish_reason: z6.string().nullable().optional(),
index: z6.number().nullish()
}).passthrough()
)
}),
OpenRouterErrorResponseSchema
]);
// src/chat/index.ts
var OpenRouterChatLanguageModel = class {
constructor(modelId, settings, config) {
this.specificationVersion = "v4";
this.provider = "openrouter";
this.defaultObjectGenerationMode = "tool";
this.supportsImageUrls = true;
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 _a18, _b18, _c, _d;
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 (call-level options override model-level settings):
max_tokens: maxOutputTokens != null ? maxOutputTokens : this.settings.maxTokens,
temperature: temperature != null ? temperature : this.settings.temperature,
top_p: topP != null ? topP : this.settings.topP,
frequency_penalty: frequencyPenalty != null ? frequencyPenalty : this.settings.frequencyPenalty,
presence_penalty: presencePenalty != null ? presencePenalty : this.settings.presencePenalty,
seed,
stop: stopSequences,
response_format: (responseFormat == null ? void 0 : responseFormat.type) === "json" ? responseFormat.schema != null ? {
type: "json_schema",
json_schema: __spreadValues({
schema: responseFormat.schema,
strict: (_b18 = (_a18 = this.settings.structuredOutputs) == null ? void 0 : _a18.strict) != null ? _b18 : true,
name: (_c = responseFormat.name) != null ? _c : "response"
}, responseFormat.description && {
description: responseFormat.description
})
} : { type: "json_object" } : void 0,
top_k: topK != null ? topK : this.settings.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,
// Debug settings:
debug: this.settings.debug,
// Anthropic automatic caching:
cache_control: this.settings.cache_control
}, this.config.extraBody), this.settings.extraBody);
if (tools && tools.length > 0) {
const mappedTools = [];
for (const tool of tools) {
if (tool.type === "function") {
const openrouterOptions = (_d = tool.providerOptions) == null ? void 0 : _d.openrouter;
const eagerInputStreaming = openrouterOptions == null ? void 0 : openrouterOptions.eager_input_streaming;
mappedTools.push(__spreadValues({
type: "function",
function: {
name: tool.name,
description: tool.description,
parameters: tool.inputSchema
}
}, eagerInputStreaming != null && {
eager_input_streaming: eagerInputStreaming
}));
} else if (tool.type === "provider") {
mappedTools.push(mapProviderTool(tool));
}
}
return __spreadProps(__spreadValues({}, baseArgs), {
tools: mappedTools,
tool_choice: toolChoice ? getChatCompletionToolChoice(toolChoice) : void 0
});
}
return baseArgs;
}
async doGenerate(options) {
var _b18, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v;
const providerOptions = options.providerOptions || {};
const openrouterOptions = providerOptions.openrouter || {};
const _a18 = openrouterOptions, { cacheControl } = _a18, restOpenrouterOptions = __objRest(_a18, ["cacheControl"]);
const args = __spreadValues(__spreadValues(__spreadValues({}, this.getArgs(options)), restOpenrouterOptions), cacheControl != null && !("cache_control" in restOpenrouterOptions) ? { cache_control: cacheControl } : {});
const { value: responseValue, 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
});
if ("error" in responseValue) {
const errorData = responseValue.error;
throw new APICallError({
message: errorData.message,
url: this.config.url({
path: "/chat/completions",
modelId: this.modelId
}),
requestBodyValues: args,
statusCode: 200,
responseHeaders,
data: errorData
});
}
const response = responseValue;
const choice = response.choices[0];
if (!choice) {
throw new NoContentGeneratedError({
message: "No choice in response"
});
}
const usageInfo = response.usage ? computeTokenUsage(response.usage) : emptyUsage();
const reasoningDetails = (_b18 = choice.message.reasoning_details) != null ? _b18 : [];
const reasoning = reasoningDetails.length > 0 ? reasoningDetails.map((detail) => {
switch (detail.type) {
case "reasoning.text" /* Text */: {
if (detail.text) {
return {
type: "reasoning",
text: detail.text,
providerMetadata: {
openrouter: {
reasoning_details: [detail]
}
}
};
}
break;
}
case "reasoning.summary" /* Summary */: {
if (detail.summary) {
return {
type: "reasoning",
text: detail.summary,
providerMetadata: {
openrouter: {
reasoning_details: [detail]
}
}
};
}
break;
}
case "reasoning.encrypted" /* Encrypted */: {
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) {
let reasoningDetailsAttachedToToolCall = false;
const seenToolCallIds = /* @__PURE__ */ new Set();
for (const toolCall of choice.message.tool_calls) {
let toolCallId = toolCall.id;
if (!toolCallId || seenToolCallIds.has(toolCallId)) {
toolCallId = generateId();
}
seenToolCallIds.add(toolCallId);
content.push({
type: "tool-call",
toolCallId,
toolName: toolCall.function.name,
input: (_c = toolCall.function.arguments) != null ? _c : "{}",
providerMetadata: !reasoningDetailsAttachedToToolCall ? {
openrouter: {
reasoning_details: reasoningDetails
}
} : void 0
});
reasoningDetailsAttachedToToolCall = true;
}
}
if (choice.message.images) {
for (const image of choice.message.images) {
content.push({
type: "file",
mediaType: getMediaType(image.image_url.url, "image/jpeg"),
data: {
type: "data",
data: getBase64FromDataUrl(image.image_url.url)
}
});
}
}
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: (_d = annotation.url_citation.title) != null ? _d : "",
providerMetadata: {
openrouter: {
content: (_e = annotation.url_citation.content) != null ? _e : "",
startIndex: (_f = annotation.url_citation.start_index) != null ? _f : 0,
endIndex: (_g = annotation.url_citation.end_index) != null ? _g : 0
}
}
});
}
}
}
const fileAnnotations = (_h = choice.message.annotations) == null ? void 0 : _h.filter(
(a) => a.type === "file"
);
const hasToolCalls = choice.message.tool_calls && choice.message.tool_calls.length > 0;
const hasEncryptedReasoning = reasoningDetails.some(
(d) => d.type === "reasoning.encrypted" /* Encrypted */ && d.data
);
const shouldOverrideFinishReason = hasToolCalls && hasEncryptedReasoning && choice.finish_reason === "stop";
const mappedFinishReason = shouldOverrideFinishReason ? createFinishReason("tool-calls", (_i = choice.finish_reason) != null ? _i : void 0) : mapOpenRouterFinishReason(choice.finish_reason);
const effectiveFinishReason = hasToolCalls && mappedFinishReason.unified === "other" ? createFinishReason("tool-calls", mappedFinishReason.raw) : mappedFinishReason;
return {
content,
finishReason: effectiveFinishReason,
usage: usageInfo,
warnings: [],
providerMetadata: {
openrouter: OpenRouterProviderMetadataSchema.parse({
provider: (_j = response.provider) != null ? _j : "",
reasoning_details: (_k = choice.message.reasoning_details) != null ? _k : [],
annotations: fileAnnotations && fileAnnotations.length > 0 ? fileAnnotations : void 0,
usage: __spreadValues(__spreadValues(__spreadValues(__spreadValues({
promptTokens: (_l = usageInfo.inputTokens.total) != null ? _l : 0,
completionTokens: (_m = usageInfo.outputTokens.total) != null ? _m : 0,
totalTokens: ((_n = usageInfo.inputTokens.total) != null ? _n : 0) + ((_o = usageInfo.outputTokens.total) != null ? _o : 0)
}, ((_p = response.usage) == null ? void 0 : _p.cost) != null ? { cost: response.usage.cost } : {}), ((_r = (_q = response.usage) == null ? void 0 : _q.prompt_tokens_details) == null ? void 0 : _r.cached_tokens) != null ? {
promptTokensDetails: {
cachedTokens: response.usage.prompt_tokens_details.cached_tokens
}
} : {}), ((_t = (_s = response.usage) == null ? void 0 : _s.completion_tokens_details) == null ? void 0 : _t.reasoning_tokens) != null ? {
completionTokensDetails: {
reasoningTokens: response.usage.completion_tokens_details.reasoning_tokens
}
} : {}), ((_v = (_u = response.usage) == null ? void 0 : _u.cost_details) == null ? void 0 : _v.upstream_inference_cost) != null ? {
costDetails: {
upstreamInferenceCost: response.usage.cost_details.upstream_inference_cost
}
} : {})
})
},
request: { body: args },
response: {
id: response.id,
modelId: response.model,
headers: responseHeaders,
body: response
}
};
}
async doStream(options) {
var _b18;
const providerOptions = options.providerOptions || {};
const openrouterOptions = providerOptions.openrouter || {};
const _a18 = openrouterOptions, { cacheControl } = _a18, restOpenrouterOptions = __objRest(_a18, ["cacheControl"]);
const args = __spreadValues(__spreadValues(__spreadValues({}, this.getArgs(options)), restOpenrouterOptions), cacheControl != null && !("cache_control" in restOpenrouterOptions) ? { cache_control: cacheControl } : {});
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,
// only include stream_options when in strict compatibility mode:
stream_options: this.config.compatibility === "strict" ? __spreadValues({
include_usage: true
}, ((_b18 = this.settings.usage) == null ? void 0 : _b18.include) ? { include_usage: true } : {}) : void 0
}),
failedResponseHandler: openrouterFailedResponseHandler,
successfulResponseHandler: createEventSourceResponseHandler(
OpenRouterStreamChatCompletionChunkSchema
),
abortSignal: options.abortSignal,
fetch: this.config.fetch
});
let streamError;
const safeResponse = withStreamErrorHandling(response, (err) => {
streamError = err;
});
const toolCalls = [];
const seenToolCallIds = /* @__PURE__ */ new Set();
let finishReason = createFinishReason("other");
const usage = {
inputTokens: {
total: void 0,
noCache: void 0,
cacheRead: void 0,
cacheWrite: void 0
},
outputTokens: {
total: void 0,
text: void 0,
reasoning: void 0
},
raw: void 0
};
const openrouterUsage = {};
let rawUsage;
const accumulatedReasoningDetails = [];
let reasoningDetailsAttachedToToolCall = false;
const accumulatedFileAnnotations = [];
let textStarted = false;
let reasoningStarted = false;
let textId;
let reasoningId;
let openrouterResponseId;
let provider;
const warnings = [];
return {
stream: safeResponse.pipeThrough(
new TransformStream({
start(controller) {
controller.enqueue({ type: "stream-start", warnings });
},
transform(chunk, controller) {
var _a19, _b19, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u;
if (options.includeRawChunks) {
controller.enqueue({ type: "raw", rawValue: chunk.rawValue });
}
if (!chunk.success) {
finishReason = createFinishReason("error");
controller.enqueue({ type: "error", error: chunk.error });
return;
}
const value = chunk.value;
if ("error" in value) {
finishReason = createFinishReason("error");
controller.enqueue({ type: "error", error: value.error });
return;
}
if (value.provider) {
provider = value.provider;
}
if (value.id) {
openrouterResponseId = value.id;
controller.enqueue({
type: "response-metadata",
id: value.id
});
}
if (value.model) {
controller.enqueue({
type: "response-metadata",
modelId: value.model
});
}
if (value.usage != null) {
const computed = computeTokenUsage(value.usage);
Object.assign(usage.inputTokens, computed.inputTokens);
Object.assign(usage.outputTokens, computed.outputTokens);
rawUsage = value.usage;
const promptTokens = (_a19 = value.usage.prompt_tokens) != null ? _a19 : 0;
const completionTokens = (_b19 = value.usage.completion_tokens) != null ? _b19 : 0;
openrouterUsage.promptTokens = promptTokens;
if (value.usage.prompt_tokens_details) {
openrouterUsage.promptTokensDetails = {
cachedTokens: (_c = value.usage.prompt_tokens_details.cached_tokens) != null ? _c : 0
};
}
openrouterUsage.completionTokens = completionTokens;
if (value.usage.completion_tokens_details) {
openrouterUsage.completionTokensDetails = {
reasoningTokens: (_d = value.usage.completion_tokens_details.reasoning_tokens) != null ? _d : 0
};
}
if (value.usage.cost != null) {
openrouterUsage.cost = value.usage.cost;
}
openrouterUsage.totalTokens = value.usage.total_tokens;
const upstreamInferenceCost = (_e = value.usage.cost_details) == null ? void 0 : _e.upstream_inference_cost;
if (upstreamInferenceCost != null) {
openrouterUsage.costDetails = {
upstreamInferenceCost
};
}
}
const choice = value.choices[0];
if ((choice == null ? void 0 : choice.finish_reason) != null) {
finishReason = mapOpenRouterFinishReason(choice.finish_reason);
}
if ((choice == null ? void 0 : choice.delta) == null) {
return;
}
const delta = choice.delta;
const emitReasoningChunk = (chunkText) => {
if (!reasoningStarted) {
reasoningId = generateId();
controller.enqueue({
type: "reasoning-start",
id: reasoningId
});
reasoningStarted = true;
}
controller.enqueue({
type: "reasoning-delta",
delta: chunkText,
id: reasoningId || generateId()
});
};
if (delta.reasoning_details && delta.reasoning_details.length > 0) {
for (const detail of delta.reasoning_details) {
const lastDetail = accumulatedReasoningDetails[accumulatedReasoningDetails.length - 1];
if (detail.type === "reasoning.text" /* Text */) {
if ((lastDetail == null ? void 0 : lastDetail.type) === "reasoning.text" /* Text */) {
lastDetail.text = (lastDetail.text || "") + (detail.text || "");
lastDetail.signature = lastDetail.signature || detail.signature;
lastDetail.format = lastDetail.format || detail.format;
} else {
accumulatedReasoningDetails.push(__spreadValues({}, detail));
}
} else if (detail.type === "reasoning.summary" /* Summary */) {
if ((lastDetail == null ? void 0 : lastDetail.type) === "reasoning.summary" /* Summary */) {
lastDetail.summary = (lastDetail.summary || "") + (detail.summary || "");
lastDetail.format = lastDetail.format || detail.format;
} else {
accumulatedReasoningDetails.push(__spreadValues({}, detail));
}
} else {
accumulatedReasoningDetails.push(detail);
}
}
if (!textStarted) {
for (const detail of delta.reasoning_details) {
switch (detail.type) {
case "reasoning.text" /* Text */: {
emitReasoningChunk(detail.text || "");
break;
}
case "reasoning.encrypted" /* Encrypted */: {
break;
}
case "reasoning.summary" /* Summary */: {
if (detail.summary) {
emitReasoningChunk(detail.summary);
}
break;
}
default: {
detail;
break;
}
}
}
}
} else if (delta.reasoning && !textStarted) {
emitReasoningChunk(delta.reasoning);
}
if (delta.content) {
if (reasoningStarted && !textStarted) {
controller.enqueue({
type: "reasoning-end",
id: reasoningId || generateId(),
// Always include accumulated reasoning_details so the AI SDK can
// update the reasoning part's providerMetadata with the correct
// signature. The signature typically arrives in the last delta,
// but reasoning-start only carries the first delta's metadata.
// An empty array is intentional — it signals the provider produced
// no reasoning tokens this turn (e.g. DeepSeek V4).
providerMetadata: {
openrouter: {
reasoning_details: accumulatedReasoningDetails
}
}
});
reasoningStarted = false;
}
if (!textStarted) {
textId = openrouterResponseId || generateId();
controller.enqueue({
type: "text-start",
id: textId
});
textStarted = true;
}
controller.enqueue({
type: "text-delta",
delta: delta.content,
id: textId || generateId()
});
}
if (delta.annotations) {
for (const annotation of delta.annotations) {
if (annotation.type === "url_citation") {
controller.enqueue({
type: "source",
sourceType: "url",
id: annotation.url_citation.url,
url: annotation.url_citation.url,
title: (_f = annotation.url_citation.title) != null ? _f : "",
providerMetadata: {
openrouter: {
content: (_g = annotation.url_citation.content) != null ? _g : "",
startIndex: (_h = annotation.url_citation.start_index) != null ? _h : 0,
endIndex: (_i = annotation.url_citation.end_index) != null ? _i : 0
}
}
});
} else if (annotation.type === "file") {
const file = annotation.file;
if (file && typeof file === "object" && "hash" in file && "name" in file) {
accumulatedFileAnnotations.push(
annotation
);
}
}
}
}
if (delta.tool_calls != null) {
for (const toolCallDelta of delta.tool_calls) {
const index = (_j = toolCallDelta.index) != null ? _j : toolCalls.length - 1;
if (toolCalls[index] == null) {
if (toolCallDelta.type !== "function") {
throw new InvalidResponseDataError({
data: toolCallDelta,
message: `Expected 'function' type.`
});
}
if (((_k = toolCallDelta.function) == null ? void 0 : _k.name) == null) {
throw new InvalidResponseDataError({
data: toolCallDelta,
message: `Expected 'function.name' to be a string.`
});
}
let toolCallId = (_l = toolCallDelta.id) != null ? _l : "";
if (!toolCallId || seenToolCallIds.has(toolCallId)) {
toolCallId = generateId();
}
seenToolCallIds.add(toolCallId);
toolCalls[index] = {
id: toolCallId,
type: "function",
function: {
name: toolCallDelta.function.name,
arguments: (_m = toolCallDelta.function.arguments) != null ? _m : ""
},
inputStarted: false,
sent: false
};
const toolCall2 = toolCalls[index];
if (toolCall2 == null) {
throw new InvalidResponseDataError({
data: { index, toolCallsLength: toolCalls.length },
message: `Tool call at index ${index} is missing after creation.`
});
}
if (((_n = toolCall2.function) == null ? void 0 : _n.name) != null && ((_o = toolCall2.function) == null ? void 0 : _o.arguments) != null && isParsableJson(toolCall2.function.arguments)) {
toolCall2.inputStarted = true;
controller.enqueue({
type: "tool-input-start",
id: toolCall2.id,
toolName: toolCall2.function.name
});
controller.enqueue({
type: "tool-input-delta",
id: toolCall2.id,
delta: toolCall2.function.arguments
});
controller.enqueue({
type: "tool-input-end",
id: toolCall2.id
});
controller.enqueue({
type: "tool-call",
toolCallId: toolCall2.id,
toolName: toolCall2.function.name,
input: toolCall2.function.arguments,
providerMetadata: !reasoningDetailsAttachedToToolCall ? {
openrouter: {
reasoning_details: accumulatedReasoningDetails
}
} : void 0
});
reasoningDetailsAttachedToToolCall = true;
toolCall2.sent = true;
}
continue;
}
const toolCall = toolCalls[index];
if (toolCall == null) {
throw new InvalidResponseDataError({
data: {
index,
toolCallsLength: toolCalls.length,
toolCallDelta
},
message: `Tool call at index ${index} is missing during merge.`
});
}
if (!toolCall.inputStarted) {
toolCall.inputStarted = true;
controller.enqueue({
type: "tool-input-start",
id: toolCall.id,
toolName: toolCall.function.name
});
if (toolCall.function.arguments) {
controller.enqueue({
type: "tool-input-delta",
id: toolCall.id,
delta: toolCall.function.arguments
});
}
}
if (((_p = toolCallDelta.function) == null ? void 0 : _p.arguments) != null) {
toolCall.function.arguments += (_r = (_q = toolCallDelta.function) == null ? void 0 : _q.arguments) != null ? _r : "";
}
controller.enqueue({
type: "tool-input-delta",
id: toolCall.id,
delta: (_s = toolCallDelta.function.arguments) != null ? _s : ""
});
if (!toolCall.sent && ((_t = toolCall.function) == null ? void 0 : _t.name) != null && ((_u = toolCall.function) == null ? void 0 : _u.arguments) != null && isParsableJson(toolCall.function.arguments)) {
controller.enqueue({
type: "tool-input-end",
id: toolCall.id
});
controller.enqueue({
type: "tool-call",
toolCallId: toolCall.id,
toolName: toolCall.function.name,
input: toolCall.function.arguments,
providerMetadata: !reasoningDetailsAttachedToToolCall ? {
openrouter: {
reasoning_details: accumulatedReasoningDetails
}
} : void 0
});
reasoningDetailsAttachedToToolCall = true;
toolCall.sent = true;
}
}
}
if (delta.images != null) {
for (const image of delta.images) {
controller.enqueue({
type: "file",
mediaType: getMediaType(image.image_url.url, "image/jpeg"),
data: {
type: "data",
data: getBase64FromDataUrl(image.image_url.url)
}
});
}
}
},
flush(controller) {
const hasToolCalls = toolCalls.length > 0;
if (streamError != null) {
finishReason = createFinishReason("error");
controller.enqueue({ type: "error", error: streamError });
}
const hasEncryptedReasoning = accumulatedReasoningDetails.some(
(d) => d.type === "reasoning.encrypted" /* Encrypted */ && d.data
);
if (hasToolCalls && hasEncryptedReasoning && finishReason.unified === "stop") {
finishReason = createFinishReason("tool-calls", finishReason.raw);
}
if (hasToolCalls && finishReason.unified === "other") {
finishReason = createFinishReason("tool-calls", finishReason.raw);
}
if (finishReason.unified === "tool-calls") {
for (const toolCall of toolCalls) {
if (toolCall && !toolCall.sent) {
const input = isParsableJson(toolCall.function.arguments) ? toolCall.function.arguments : "{}";
if (!toolCall.inputStarted) {
controller.enqueue({
type: "tool-input-start",
id: toolCall.id,
toolName: toolCall.function.name
});
controller.enqueue({
type: "tool-input-delta",
id: toolCall.id,
delta: input
});
}
controller.enqueue({
type: "tool-input-end",
id: toolCall.id
});
controller.enqueue({
type: "tool-call",
toolCallId: toolCall.id,
toolName: toolCall.function.name,
input,
providerMetadata: !reasoningDetailsAttachedToToolCall ? {
openrouter: {
reasoning_details: accumulatedReasoningDetails
}
} : void 0
});
reasoningDetailsAttachedToToolCall = true;
toolCall.sent = true;
}
}
}
if (reasoningStarted) {
controller.enqueue({
type: "reasoning-end",
id: reasoningId || generateId(),
// Always include accumulated reasoning_details so the AI SDK can
// update the reasoning part's providerMetadata. An empty array is
// intentional — it signals the provider produced no reasoning tokens.
providerMetadata: {
openrouter: {
reasoning_details: accumulatedReasoningDetails
}
}
});
}
if (textStarted) {
controller.enqueue({
type: "text-end",
id: textId || generateId()
});
}
const openrouterMetadata = {
usage: openrouterUsage
};
if (provider !== void 0) {
openrouterMetadata.provider = provider;
}
openrouterMetadata.reasoning_details = accumulatedReasoningDetails;
if (accumulatedFileAnnotations.length > 0) {
openrouterMetadata.annotations = accumulatedFileAnnotations;
}
if (usage.inputTokens.total === void 0 && openrouterUsage.promptTokens !== void 0) {
usage.inputTokens.total = openrouterUsage.promptTokens;
}
if (usage.outputTokens.total === void 0 && openrouterUsage.completionTokens !== void 0) {
usage.outputTokens.total = openrouterUsage.completionTokens;
}
usage.raw = rawUsage;
controller.enqueue({
type: "finish",
finishReason,
usage,
providerMetadata: {
openrouter: openrouterMetadata
}
});
}
})
),
warnings,
request: { body: args },
response: { headers: responseHeaders }
};
}
};
function mapProviderTool(tool) {
const [provider, toolName] = tool.id.split(".");
const apiToolType = `${provider}:${toolName}`;
const mappedArgs = {};
for (const [key, value] of Object.entries(tool.args)) {
if (value !== void 0) {
mappedArgs[camelToSnake(key)] = value;
}
}
return __spreadValues({
type: apiToolType
}, mappedArgs);
}
function camelToSnake(str) {
return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
}
// src/completion/convert-to-openrouter-completion-prompt.ts
function convertToOpenRouterCompletionPrompt({
prompt,
inputFormat,
user = "user",
assistant = "assistant"
}) {
if (inputFormat === "prompt" && prompt.length === 1 && prompt[0] && prompt[0].role === "user" && prompt[0].content.length === 1 && prompt[0].content[0] && prompt[0].content[0].type === "text") {
return { prompt: prompt[0].content[0].text };
}
let text = "";
if (prompt[0] && prompt[0].role === "system") {
text += `${prompt[0].content}
`;
prompt = prompt.slice(1);
}
for (const { role, content } of prompt) {
switch (role) {
case "system": {
throw new InvalidPromptError({
message: `Unexpected system message in prompt: ${content}`,
prompt
});
}
case "user": {
const userMessage = content.map((part) => {
switch (part.type) {
case "text": {
return part.text;
}
case "file": {
throw new UnsupportedFunctionalityError({
functionality: "file attachments"
});
}
default: {
return "";
}
}
}).join("");
text += `${user}:
${userMessage}
`;
break;
}
case "assistant": {
const assistantMessage = content.map((part) => {
switch (part.type) {
case "text": {
return part.text;
}
case "tool-call": {
throw new UnsupportedFunctionalityError({
functionality: "tool-call messages"
});
}
case "tool-result": {
throw new UnsupportedFunctionalityError({
functionality: "tool-result messages"
});
}
case "reasoning": {
throw new UnsupportedFunctionalityError({
functionality: "reasoning messages"
});
}
case "file": {
throw new UnsupportedFunctionalityError({
functionality: "file attachments"
});
}
default: {
return "";
}
}
}).join("");
text += `${assistant}:
${assistantMessage}
`;
break;
}
case "tool": {
throw new UnsupportedFunctionalityError({
functionality: "tool messages"
});
}
default: {
break;
}
}
}
text += `${assistant}:
`;
return {
prompt: text
};
}
// src/completion/schemas.ts
import { z as z7 } from "zod/v4";
var OpenRouterCompletionChunkSchema = z7.union([
z7.object({
id: z7.string().optional(),
model: z7.string().optional(),
provider: z7.string().optional(),
choices: z7.array(
z7.object({
text: z7.string(),
reasoning: z7.string().nullish().optional(),
reasoning_details: ReasoningDetailArraySchema.nullish(),
finish_reason: z7.string().nullish(),
index: z7.number().nullish(),
logprobs: z7.object({
tokens: z7.array(z7.string()),
token_logprobs: z7.array(z7.number()),
top_logprobs: z7.array(z7.record(z7.string(), z7.number())).nullable()
}).passthrough().nullable().optional()
}).passthrough()
),
usage: z7.object({
prompt_tokens: z7.number(),
prompt_tokens_details: z7.object({
cached_tokens: z7.number(),
cache_write_tokens: z7.number().nullish()
}).passthrough().nullish(),
completion_tokens: z7.number(),
completion_tokens_details: z7.object({
reasoning_tokens: z7.number()
}).passthrough().nullish(),
total_tokens: z7.number(),
cost: z7.number().optional(),
cost_details: z7.object({
upstream_inference_cost: z7.number().nullish()
}).passthrough().nullish()
}).passthrough().nullish()
}).passthrough(),
OpenRouterErrorResponseSchema
]);
// src/completion/index.ts
var OpenRouterCompletionLanguageModel = class {
constructor(modelId, settings, config) {
this.specificationVersion = "v4";
this.provider = "openrouter";
this.supportsImageUrls = true;
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.defaultObjectGenerationMode = void 0;
this.modelId = modelId;
this.settings = settings;
this.config = config;
}
getArgs({
prompt,
maxOutputTokens,
temperature,
topP,
frequencyPenalty,
presencePenalty,
seed,
responseFormat,
topK,
stopSequences,
tools,
toolChoice
}) {
const { prompt: completionPrompt } = convertToOpenRouterCompletionPrompt({
prompt,
inputFormat: "prompt"
});
if (tools == null ? void 0 : tools.length) {
throw new UnsupportedFunctionalityError({
functionality: "tools"
});
}
if (toolChoice) {
throw new UnsupportedFunctionalityError({
functionality: "toolChoice"
});
}
return __spreadValues(__spreadValues({
// model id:
model: this.modelId,
models: this.settings.models,
// model specific settings:
logit_bias: this.settings.logitBias,
logprobs: typeof this.settings.logprobs === "number" ? this.settings.logprobs : typeof this.settings.logprobs === "boolean" ? this.settings.logprobs ? 0 : void 0 : void 0,
suffix: this.settings.suffix,
user: this.settings.user,
// standardized settings (call-level options override model-level settings):
max_tokens: maxOutputTokens != null ? maxOutputTokens : this.settings.maxTokens,
temperature: temperature != null ? temperature : this.settings.temperature,
top_p: topP != null ? topP : this.settings.topP,
frequency_penalty: frequencyPenalty != null ? frequencyPenalty : this.settings.frequencyPenalty,
presence_penalty: presencePenalty != null ? presencePenalty : this.settings.presencePenalty,
seed,
stop: stopSequences,
response_format: responseFormat,
top_k: topK != null ? topK : this.settings.topK,
// prompt:
prompt: completionPrompt,
// OpenRouter specific settings:
include_reasoning: this.settings.includeReasoning,
reasoning: this.settings.reasoning
}, this.config.extraBody), this.settings.extraBody);
}
async doGenerate(options) {
var _a18, _b18, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q;
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: "/completions",
modelId: this.modelId
}),
headers: combineHeaders(this.config.headers(), options.headers),
body: args,
failedResponseHandler: openrouterFailedResponseHandler,
successfulResponseHandler: createJsonResponseHandler(
OpenRouterCompletionChunkSchema
),
abortSignal: options.abortSignal,
fetch: this.config.fetch
});
if ("error" in response) {
const errorData = response.error;
throw new APICallError({
message: errorData.message,
url: this.config.url({
path: "/completions",
modelId: this.modelId
}),
requestBodyValues: args,
statusCode: 200,
responseHeaders,
data: errorData
});
}
const choice = response.choices[0];
if (!choice) {
throw new NoContentGeneratedError({
message: "No choice in OpenRouter completion response"
});
}
return {
content: [
{
type: "text",
text: (_a18 = choice.text) != null ? _a18 : ""
}
],
finishReason: mapOpenRouterFinishReason(choice.finish_reason),
usage: response.usage ? computeTokenUsage(response.usage) : emptyUsage(),
warnings: [],
providerMetadata: {
openrouter: OpenRouterProviderMetadataSchema.parse({
provider: (_b18 = response.provider) != null ? _b18 : "",
usage: __spreadValues(__spreadValues(__spreadValues(__spreadValues({
promptTokens: (_d = (_c = response.usage) == null ? void 0 : _c.prompt_tokens) != null ? _d : 0,
completionTokens: (_f = (_e = response.usage) == null ? void 0 : _e.completion_tokens) != null ? _f : 0,
totalTokens: ((_h = (_g = response.usage) == null ? void 0 : _g.prompt_tokens) != null ? _h : 0) + ((_j = (_i = response.usage) == null ? void 0 : _i.completion_tokens) != null ? _j : 0)
}, ((_k = response.usage) == null ? void 0 : _k.cost) != null ? { cost: response.usage.cost } : {}), ((_m = (_l = response.usage) == null ? void 0 : _l.prompt_tokens_details) == null ? void 0 : _m.cached_tokens) != null ? {
promptTokensDetails: {
cachedTokens: response.usage.prompt_tokens_details.cached_tokens
}
} : {}), ((_o = (_n = response.usage) == null ? void 0 : _n.completion_tokens_details) == null ? void 0 : _o.reasoning_tokens) != null ? {
completionTokensDetails: {
reasoningTokens: response.usage.completion_tokens_details.reasoning_tokens
}
} : {}), ((_q = (_p = response.usage) == null ? void 0 : _p.cost_details) == null ? void 0 : _q.upstream_inference_cost) != null ? {
costDetails: {
upstreamInferenceCost: response.usage.cost_details.upstream_inference_cost
}
} : {})
})
},
response: {
headers: responseHeaders
}
};
}
async doStream(options) {
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: "/completions",
modelId: this.modelId
}),
headers: combineHeaders(this.config.headers(), options.headers),
body: __spreadProps(__spreadValues({}, args), {
stream: true,
// only include stream_options when in strict compatibility mode:
stream_options: this.config.compatibility === "strict" ? { include_usage: true } : void 0
}),
failedResponseHandler: openrouterFailedResponseHandler,
successfulResponseHandler: createEventSourceResponseHandler(
OpenRouterCompletionChunkSchema
),
abortSignal: options.abortSignal,
fetch: this.config.fetch
});
let streamError;
const safeResponse = withStreamErrorHandling(response, (err) => {
streamError = err;
});
let finishReason = createFinishReason("other");
const usage = {
inputTokens: {
total: void 0,
noCache: void 0,
cacheRead: void 0,
cacheWrite: void 0
},
outputTokens: {
total: void 0,
text: void 0,
reasoning: void 0
},
raw: void 0
};
const openrouterUsage = {};
let provider;
let rawUsage;
const warnings = [];
return {
stream: safeResponse.pipeThrough(
new TransformStream({
start(controller) {
controller.enqueue({ type: "stream-start", warnings });
},
transform(chunk, controller) {
var _a18, _b18, _c, _d, _e;
if (options.includeRawChunks) {
controller.enqueue({ type: "raw", rawValue: chunk.rawValue });
}
if (!chunk.success) {
finishReason = createFinishReason("error");
controller.enqueue({ type: "error", error: chunk.error });
return;
}
const value = chunk.value;
if ("error" in value) {
finishReason = createFinishReason("error");
controller.enqueue({ type: "error", error: value.error });
return;
}
if (value.provider) {
provider = value.provider;
}
if (value.usage != null) {
const computed = computeTokenUsage(value.usage);
Object.assign(usage.inputTokens, computed.inputTokens);
Object.assign(usage.outputTokens, computed.outputTokens);
rawUsage = value.usage;
const promptTokens = (_a18 = value.usage.prompt_tokens) != null ? _a18 : 0;
const completionTokens = (_b18 = value.usage.completion_tokens) != null ? _b18 : 0;
openrouterUsage.promptTokens = promptTokens;
if (value.usage.prompt_tokens_details) {
openrouterUsage.promptTokensDetails = {
cachedTokens: (_c = value.usage.prompt_tokens_details.cached_tokens) != null ? _c : 0
};
}
openrouterUsage.completionTokens = completionTokens;
if (value.usage.completion_tokens_details) {
openrouterUsage.completionTokensDetails = {
reasoningTokens: (_d = value.usage.completion_tokens_details.reasoning_tokens) != null ? _d : 0
};
}
if (value.usage.cost != null) {
openrouterUsage.cost = value.usage.cost;
}
openrouterUsage.totalTokens = value.usage.total_tokens;
const upstreamInferenceCost = (_e = value.usage.cost_details) == null ? void 0 : _e.upstream_inference_cost;
if (upstreamInferenceCost != null) {
openrouterUsage.costDetails = {
upstreamInferenceCost
};
}
}
const choice = value.choices[0];
if ((choice == null ? void 0 : choice.finish_reason) != null) {
finishReason = mapOpenRouterFinishReason(choice.finish_reason);
}
if ((choice == null ? void 0 : choice.text) != null) {
controller.enqueue({
type: "text-delta",
delta: choice.text,
id: generateId()
});
}
},
flush(controller) {
if (streamError != null) {
finishReason = createFinishReason("error");
controller.enqueue({ type: "error", error: streamError });
}
usage.raw = rawUsage;
const openrouterMetadata = {
usage: openrouterUsage
};
if (provider !== void 0) {
openrouterMetadata.provider = provider;
}
controller.enqueue({
type: "finish",
finishReason,
usage,
providerMetadata: {
openrouter: openrouterMetadata
}
});
}
})
),
response: {
headers: responseHeaders
}
};
}
};
// src/embedding/schemas.ts
import { z as z8 } from "zod/v4";
var openrouterEmbeddingUsageSchema = z8.object({
prompt_tokens: z8.number(),
total_tokens: z8.number(),
cost: z8.number().optional()
});
var openrouterEmbeddingDataSchema = z8.object({
object: z8.literal("embedding"),
embedding: z8.array(z8.number()),
index: z8.number().optional()
});
var OpenRouterEmbeddingResponseSchema = z8.object({
id: z8.string().optional(),
object: z8.literal("list"),
data: z8.array(openrouterEmbeddingDataSchema),
model: z8.string(),
provider: z8.string().optional(),
usage: openrouterEmbeddingUsageSchema.optional()
});
// src/embedding/index.ts
var OpenRouterEmbeddingModel = class {
constructor(modelId, settings, config) {
this.specificationVersion = "v4";
this.provider = "openrouter";
this.maxEmbeddingsPerCall = void 0;
this.supportsParallelCalls = true;
this.modelId = modelId;
this.settings = settings;
this.config = config;
}
async doEmbed(options) {
var _a18, _b18, _c, _d, _e, _f;
const { values, abortSignal, headers } = options;
const args = __spreadValues(__spreadValues({
model: this.modelId,
input: values,
user: this.settings.user,
provider: this.settings.provider
}, this.config.extraBody), this.settings.extraBody);
const { value: responseValue, responseHeaders } = await postJsonToApi({
url: this.config.url({
path: "/embeddings",
modelId: this.modelId
}),
headers: combineHeaders(this.config.headers(), headers),
body: args,
failedResponseHandler: openrouterFailedResponseHandler,
successfulResponseHandler: createJsonResponseHandler(
OpenRouterEmbeddingResponseSchema
),
abortSignal,
fetch: this.config.fetch
});
return {
embeddings: responseValue.data.map((item) => item.embedding),
usage: responseValue.usage ? { tokens: responseValue.usage.prompt_tokens } : void 0,
providerMetadata: {
openrouter: OpenRouterProviderMetadataSchema.parse({
provider: (_a18 = responseValue.provider) != null ? _a18 : "",
usage: __spreadValues({
promptTokens: (_c = (_b18 = responseValue.usage) == null ? void 0 : _b18.prompt_tokens) != null ? _c : 0,
completionTokens: 0,
totalTokens: (_e = (_d = responseValue.usage) == null ? void 0 : _d.total_tokens) != null ? _e : 0
}, ((_f = responseValue.usage) == null ? void 0 : _f.cost) != null ? { cost: responseValue.usage.cost } : {})
})
},
response: {
headers: responseHeaders,
body: responseValue
},
warnings: []
};
}
};
// src/evaluation/schemas.ts
import { z as z9 } from "zod/v4";
var JsonValueSchema = z9.lazy(
() => z9.union([
z9.string(),
z9.number(),
z9.boolean(),
z9.null(),
z9.array(JsonValueSchema),
z9.record(z9.string(), JsonValueSchema)
])
);
var OpenRouterDecisionsTextSchema = z9.union([
z9.string(),
z9.record(z9.string(), JsonValueSchema),
z9.array(JsonValueSchema)
]);
var OpenRouterDecisionsProviderOptionsSchema = z9.object({
user: z9.string().optional(),
provider: z9.record(z9.string(), JsonValueSchema).optional(),
session_id: z9.string().optional(),
trace: z9.record(z9.string(), JsonValueSchema).optional()
}).loose();
var OpenRouterDecisionsNoulAnswerSchema = z9.object({
type: z9.literal("noul"),
noul: z9.number()
});
var OpenRouterDecisionsChoiceAnswerSchema = z9.object({
type: z9.literal("choice"),
choice: z9.string(),
probabilities: z9.record(z9.string(), z9.number()).optional(),
confidence: z9.number().optional()
});
var OpenRouterDecisionsScoreAnswerSchema = z9.object({
type: z9.literal("score"),
score: z9.number(),
legend: z9.record(z9.string(), OpenRouterDecisionsTextSchema).optional(),
probabilities: z9.record(z9.string(), z9.number()).optional(),
confidence: z9.number().optional()
});
var OpenRouterDecisionsAnswerSchema = z9.discriminatedUnion("type", [
OpenRouterDecisionsNoulAnswerSchema,
OpenRouterDecisionsChoiceAnswerSchema,
OpenRouterDecisionsScoreAnswerSchema
]);
var OpenRouterDecisionsResponseSchema = z9.object({
id: z9.string().optional(),
model: z9.string().optional(),
provider: z9.string().optional(),
answers: z9.record(z9.string(), OpenRouterDecisionsAnswerSchema),
usage: z9.object({
input_tokens: z9.number().optional(),
output_tokens: z9.number().optional(),
cost: z9.number().optional()
}).optional()
});
// src/evaluation/index.ts
var DECISIONS_ROUNDING = {
probabilityDecimals: 2,
scoreDecimals: 2
};
var OpenRouterEvaluationModel = class {
constructor(modelId, settings, config) {
this.specificationVersion = "v4";
this.provider = "openrouter";
this.supportedQuestionTypes = ["choice", "score", "boolean"];
this.modelId = modelId;
this.settings = settings;
this.config = config;
}
async doEvaluate(options) {
var _a18;
const { state, questions, abortSignal, headers, providerOptions } = options;
const decisionsQuestions = Object.fromEntries(
Object.entries(questions).map(([id, question]) => [
id,
toDecisionsQuestion(id, question)
])
);
const openrouterOptions = await parseProviderOptions({
provider: "openrouter",
providerOptions,
schema: OpenRouterDecisionsProviderOptionsSchema
});
const { user, provider, session_id, trace, extraBody } = this.settings;
const body = __spreadProps(__spreadValues(__spreadValues(__spreadValues(__spreadValues({}, this.config.extraBody), extraBody), removeUndefinedEntries({ user, provider, session_id, trace })), openrouterOptions), {
model: this.modelId,
state,
questions: decisionsQuestions
});
const {
value: response,
rawValue,
responseHeaders
} = await postJsonToApi({
url: this.config.url({ path: "/decisions" }),
headers: combineHeaders(this.config.headers(), headers),
body,
failedResponseHandler: openrouterFailedResponseHandler,
successfulResponseHandler: createJsonResponseHandler(
OpenRouterDecisionsResponseSchema
),
abortSignal,
fetch: this.config.fetch
});
const answers = Object.fromEntries(
Object.entries(response.answers).map(([id, answer]) => [
id,
toEvaluationAnswer(answer)
])
);
const answerMetadata = Object.fromEntries(
Object.entries(response.answers).map(([id, answer]) => [
id,
toAnswerMetadata(answer)
])
);
return {
answers,
rounding: DECISIONS_ROUNDING,
usage: response.usage ? {
inputTokens: response.usage.input_tokens,
outputTokens: response.usage.output_tokens
} : void 0,
warnings: [],
providerMetadata: {
openrouter: __spreadValues(__spreadProps(__spreadValues({}, response.provider != null ? { provider: response.provider } : {}), {
answers: answerMetadata
}), ((_a18 = response.usage) == null ? void 0 : _a18.cost) != null ? { usage: { cost: response.usage.cost } } : {})
},
response: {
id: response.id,
modelId: response.model,
headers: responseHeaders,
body: rawValue
}
};
}
};
function toDecisionsQuestion(id, question) {
var _a18, _b18;
switch (question.type) {
case "choice":
return {
type: "choice",
instructions: question.instructions,
criteria: question.criteria
};
case "score":
return {
type: "score",
instructions: question.instructions,
criteria: question.criteria.map((criterion, index) => {
if (criterion == null) {
throw new InvalidArgumentError({
argument: `questions.${id}.criteria[${index}]`,
message: `Question "${id}": the OpenRouter Decisions API requires a description for every score criterion.`
});
}
return criterion;
})
};
case "boolean": {
const trueCriterion = (_a18 = question.criteria) == null ? void 0 : _a18.true;
const falseCriterion = (_b18 = question.criteria) == null ? void 0 : _b18.false;
if (trueCriterion == null && falseCriterion == null) {
return { type: "noul", instructions: question.instructions };
}
if (trueCriterion == null || falseCriterion == null) {
throw new InvalidArgumentError({
argument: `questions.${id}.criteria`,
message: `Question "${id}": the OpenRouter Decisions API requires both "true" and "false" descriptions when boolean criteria are given.`
});
}
return {
type: "noul",
instructions: question.instructions,
criteria: { true: trueCriterion, false: falseCriterion }
};
}
default:
return question;
}
}
function toEvaluationAnswer(answer) {
switch (answer.type) {
case "noul":
return { type: "boolean", probability: answer.noul };
case "choice":
return {
type: "choice",
choice: answer.choice,
probabilities: answer.probabilities
};
case "score":
return {
type: "score",
score: answer.score,
probabilities: answer.probabilities
};
default:
return answer;
}
}
function toAnswerMetadata(answer) {
switch (answer.type) {
case "noul":
return {};
case "choice":
return answer.confidence != null ? { confidence: answer.confidence } : {};
case "score":
return __spreadValues(__spreadValues({}, answer.confidence != null ? { confidence: answer.confidence } : {}), answer.legend != null ? { legend: answer.legend } : {});
default:
return answer;
}
}
// src/image/schemas.ts
import { z as z10 } from "zod/v4";
var OpenRouterImageResponseSchema = z10.object({
created: z10.number().optional(),
data: z10.array(
z10.object({
b64_json: z10.string()
}).passthrough()
),
usage: z10.object({
prompt_tokens: z10.number(),
completion_tokens: z10.number(),
total_tokens: z10.number()
}).passthrough().optional()
}).passthrough();
// src/image/index.ts
var OpenRouterImageModel = class {
constructor(modelId, settings, config) {
this.specificationVersion = "v4";
this.provider = "openrouter";
this.maxImagesPerCall = 10;
this.modelId = modelId;
this.settings = settings;
this.config = config;
}
async doGenerate(options) {
const {
prompt,
n,
size,
aspectRatio,
seed,
files,
mask,
abortSignal,
headers,
providerOptions
} = options;
const openrouterOptions = (providerOptions == null ? void 0 : providerOptions.openrouter) || {};
const warnings = [];
if (mask !== void 0) {
throw new UnsupportedFunctionalityError({
functionality: "image inpainting (mask parameter)"
});
}
const hasFiles = files !== void 0 && files.length > 0;
const inputReferences = hasFiles ? files.map((file) => convertFileToInputReference(file)) : void 0;
const body = __spreadValues(__spreadValues(__spreadValues(__spreadValues(__spreadValues(__spreadValues(__spreadValues(__spreadValues(__spreadValues(__spreadValues({
model: this.modelId,
prompt: prompt != null ? prompt : ""
}, n !== void 0 && { n }), size !== void 0 && { size }), aspectRatio !== void 0 && { aspect_ratio: aspectRatio }), seed !== void 0 && { seed }), inputReferences !== void 0 && {
input_references: inputReferences
}), this.settings.user !== void 0 && { user: this.settings.user }), this.settings.provider !== void 0 && {
provider: this.settings.provider
}), this.config.extraBody), this.settings.extraBody), openrouterOptions);
const { value: responseValue, responseHeaders } = await postJsonToApi({
url: this.config.url({
path: "/images",
modelId: this.modelId
}),
headers: combineHeaders(this.config.headers(), headers),
body,
failedResponseHandler: openrouterFailedResponseHandler,
successfulResponseHandler: createJsonResponseHandler(
OpenRouterImageResponseSchema
),
abortSignal,
fetch: this.config.fetch
});
if (!responseValue.data || responseValue.data.length === 0) {
throw new NoContentGeneratedError({
message: "No images in response"
});
}
const images = responseValue.data.map((item) => item.b64_json);
const usage = responseValue.usage ? {
inputTokens: responseValue.usage.prompt_tokens,
outputTokens: responseValue.usage.completion_tokens,
totalTokens: responseValue.usage.total_tokens
} : void 0;
return {
images,
warnings,
response: {
timestamp: /* @__PURE__ */ new Date(),
modelId: this.modelId,
headers: responseHeaders
},
usage
};
}
};
var DEFAULT_IMAGE_MEDIA_TYPE = "image/png";
function convertFileToInputReference(file) {
if (file.type === "url") {
return {
type: "image_url",
image_url: { url: file.url }
};
}
const url = buildFileDataUrl({
data: file.data,
mediaType: file.mediaType,
defaultMediaType: DEFAULT_IMAGE_MEDIA_TYPE
});
return {
type: "image_url",
image_url: { url }
};
}
// src/video/schemas.ts
import { z as z11 } from "zod/v4";
var VideoGenerationSubmitResponseSchema = z11.object({
id: z11.string(),
generation_id: z11.string().optional(),
polling_url: z11.string(),
status: z11.string()
}).passthrough();
var VideoGenerationPollResponseSchema = z11.object({
id: z11.string(),
generation_id: z11.string().optional(),
polling_url: z11.string(),
status: z11.string(),
unsigned_urls: z11.array(z11.string()).optional(),
usage: z11.object({
cost: z11.number().optional(),
is_byok: z11.boolean().optional()
}).passthrough().optional(),
error: z11.string().optional()
}).passthrough();
// src/video/index.ts
var DEFAULT_POLL_INTERVAL_MS = 2e3;
var DEFAULT_MAX_POLL_TIME_MS = 6e5;
var OpenRouterVideoModel = class {
constructor(modelId, settings, config) {
this.specificationVersion = "v4";
this.provider = "openrouter";
this.maxVideosPerCall = 1;
this.modelId = modelId;
this.settings = settings;
this.config = config;
}
async doGenerate(options) {
var _a18, _b18, _c, _d, _e;
const {
prompt,
n,
aspectRatio,
resolution,
duration,
seed,
image,
abortSignal,
headers,
providerOptions
} = options;
const warnings = [];
if (n > 1) {
warnings.push({
type: "unsupported",
feature: "n > 1",
details: `OpenRouter video generation returns 1 video per call. Requested ${n} videos.`
});
}
const body = __spreadValues(__spreadValues(__spreadValues(__spreadValues(__spreadValues(__spreadValues(__spreadValues(__spreadValues(__spreadValues({
model: this.modelId,
prompt: prompt != null ? prompt : ""
}, aspectRatio !== void 0 && { aspect_ratio: aspectRatio }), resolution !== void 0 && { size: resolution }), duration !== void 0 && { duration }), seed !== void 0 && { seed }), this.settings.generateAudio !== void 0 && {
generate_audio: this.settings.generateAudio
}), image !== void 0 && {
frame_images: [convertImageToFrameImage(image)]
}), this.config.extraBody), this.settings.extraBody), providerOptions.openrouter);
const mergedHeaders = combineHeaders(this.config.headers(), headers);
const { value: submitResponse, responseHeaders } = await postJsonToApi({
url: this.config.url({
path: "/videos",
modelId: this.modelId
}),
headers: mergedHeaders,
body,
failedResponseHandler: openrouterFailedResponseHandler,
successfulResponseHandler: createJsonResponseHandler(
VideoGenerationSubmitResponseSchema
),
abortSignal,
fetch: this.config.fetch
});
const pollIntervalMs = (_a18 = this.settings.pollIntervalMs) != null ? _a18 : DEFAULT_POLL_INTERVAL_MS;
const maxPollTimeMs = (_b18 = this.settings.maxPollTimeMs) != null ? _b18 : DEFAULT_MAX_POLL_TIME_MS;
const pollResult = await this.pollUntilComplete({
jobId: submitResponse.id,
headers: mergedHeaders,
abortSignal,
pollIntervalMs,
maxPollTimeMs
});
const videos = [];
if (pollResult.unsigned_urls) {
for (const url of pollResult.unsigned_urls) {
videos.push({
type: "url",
url,
mediaType: "video/mp4"
});
}
}
const providerMetadata = {
openrouter: {
generationId: (_c = pollResult.generation_id) != null ? _c : null,
cost: (_e = (_d = pollResult.usage) == null ? void 0 : _d.cost) != null ? _e : null
}
};
return {
videos,
warnings,
providerMetadata,
response: {
timestamp: /* @__PURE__ */ new Date(),
modelId: this.modelId,
headers: responseHeaders
}
};
}
async pollUntilComplete({
jobId,
headers,
abortSignal,
pollIntervalMs,
maxPollTimeMs
}) {
var _a18;
const startTime = Date.now();
while (Date.now() - startTime < maxPollTimeMs) {
abortSignal == null ? void 0 : abortSignal.throwIfAborted();
await delay(pollIntervalMs);
abortSignal == null ? void 0 : abortSignal.throwIfAborted();
const { value: pollResponse } = await getFromApi({
url: this.config.url({
path: `/videos/${jobId}`,
modelId: this.modelId
}),
headers,
failedResponseHandler: openrouterFailedResponseHandler,
successfulResponseHandler: createJsonResponseHandler(
VideoGenerationPollResponseSchema
),
abortSignal,
fetch: this.config.fetch
});
if (pollResponse.status === "completed") {
return {
generation_id: pollResponse.generation_id,
unsigned_urls: pollResponse.unsigned_urls,
usage: pollResponse.usage
};
}
if (pollResponse.status === "failed" || pollResponse.status === "dead" || pollResponse.status === "cancelled" || pollResponse.status === "expired") {
throw new APICallError({
message: (_a18 = pollResponse.error) != null ? _a18 : `Video generation failed with status: ${pollResponse.status}`,
url: this.config.url({
path: `/videos/${jobId}`,
modelId: this.modelId
}),
requestBodyValues: {},
statusCode: 500,
isRetryable: false
});
}
}
throw new APICallError({
message: `Video generation timed out after ${maxPollTimeMs}ms`,
url: this.config.url({
path: `/videos/${jobId}`,
modelId: this.modelId
}),
requestBodyValues: {},
statusCode: 408,
isRetryable: true
});
}
};
function convertImageToFrameImage(file) {
if (file.type === "url") {
return {
type: "image_url",
image_url: { url: file.url },
frame_type: "first_frame"
};
}
const url = buildFileDataUrl({
data: file.data,
mediaType: file.mediaType,
defaultMediaType: "image/png"
});
return {
type: "image_url",
image_url: { url },
frame_type: "first_frame"
};
}
export {
OpenRouterChatLanguageModel,
OpenRouterCompletionLanguageModel,
OpenRouterEmbeddingModel,
OpenRouterEvaluationModel,
OpenRouterImageModel,
OpenRouterVideoModel
};
//# sourceMappingURL=index.js.map