UNPKG

@ai-sdk/provider-utils

Version:
5,306 lines • 181 kB
import { AISDKError, APICallError, EmptyResponseBodyError, InvalidArgumentError, InvalidResponseDataError, JSONParseError, LoadAPIKeyError, LoadSettingError, NoSuchProviderReferenceError, TypeValidationError, UnsupportedFunctionalityError, getErrorMessage } from "@ai-sdk/provider";
import { safeParseAsync } from "zod/v4";
import { config, toJSONSchema } from "zod/v4/core";
import en from "zod/v4/locales/en.js";
import { EventSourceParserStream, EventSourceParserStream as EventSourceParserStream$1 } from "eventsource-parser/stream";
import { WORKFLOW_DESERIALIZE, WORKFLOW_SERIALIZE } from "@workflow/serde";
//#region src/as-array.ts
/**
* Normalizes a possibly undefined or non-array value into an array.
*/
function asArray(value) {
	return value === void 0 ? [] : Array.isArray(value) ? value : [value];
}
//#endregion
//#region src/combine-headers.ts
function combineHeaders(...headers) {
	return headers.reduce((combinedHeaders, currentHeaders) => ({
		...combinedHeaders,
		...currentHeaders
	}), {});
}
//#endregion
//#region src/remove-undefined-entries.ts
/**
* Removes entries from a record where the value is null or undefined.
* @param record - The input object whose entries may be null or undefined.
* @returns A new object containing only entries with non-null and non-undefined values.
*/
function removeUndefinedEntries(record) {
	return Object.fromEntries(Object.entries(record).filter(([_key, value]) => value != null));
}
//#endregion
//#region src/delay.ts
/**
* Creates a Promise that resolves after a specified delay
* @param delayInMs - The delay duration in milliseconds. If null or undefined, resolves immediately.
* @param signal - Optional AbortSignal to cancel the delay
* @returns A Promise that resolves after the specified delay
* @throws {DOMException} When the signal is aborted
*/
async function delay(delayInMs, options) {
	if (delayInMs == null) return;
	const signal = options?.abortSignal;
	return new Promise((resolve, reject) => {
		if (signal?.aborted) {
			reject(createAbortError());
			return;
		}
		const timeoutId = setTimeout(() => {
			cleanup();
			resolve();
		}, delayInMs);
		const cleanup = () => {
			clearTimeout(timeoutId);
			signal?.removeEventListener("abort", onAbort);
		};
		const onAbort = () => {
			cleanup();
			reject(createAbortError());
		};
		signal?.addEventListener("abort", onAbort);
	});
}
function createAbortError() {
	return new DOMException("Delay was aborted", "AbortError");
}
//#endregion
//#region src/websocket.ts
function getWebSocketConstructor(webSocket) {
	const WebSocketConstructor = webSocket ?? globalThis.WebSocket;
	if (WebSocketConstructor == null) throw new Error("No WebSocket implementation available.");
	return WebSocketConstructor;
}
/**
* Converts an http(s) URL to the corresponding ws(s) URL.
*/
function toWebSocketUrl(url) {
	const wsUrl = new URL(url);
	if (wsUrl.protocol === "http:") wsUrl.protocol = "ws:";
	else if (wsUrl.protocol === "https:") wsUrl.protocol = "wss:";
	return wsUrl;
}
const textDecoder$1 = new TextDecoder();
/**
* Reads WebSocket message data as text, handling string, binary,
* and Blob payloads.
*/
async function readWebSocketMessageText(data) {
	if (typeof data === "string") return data;
	if (data instanceof ArrayBuffer) return textDecoder$1.decode(data);
	if (ArrayBuffer.isView(data)) return textDecoder$1.decode(data);
	if (typeof Blob !== "undefined" && data instanceof Blob) return data.text();
	return String(data);
}
const WEBSOCKET_OPEN_STATE = 1;
/**
* Waits until the socket's send buffer drains below `highWaterMark` bytes.
* No-op for implementations that do not expose `bufferedAmount`. There is no
* portable drain event, so this polls. Returns as soon as the socket is no
* longer open or the signal aborts — `bufferedAmount` never drains on a
* closed socket, so waiting on would poll forever.
*/
async function waitForWebSocketBufferDrain(socket, { highWaterMark = 1048576, pollIntervalMs = 20, abortSignal } = {}) {
	while (socket.readyState === WEBSOCKET_OPEN_STATE && (socket.bufferedAmount ?? 0) > highWaterMark) {
		if (abortSignal?.aborted === true) return;
		await delay(pollIntervalMs);
	}
}
//#endregion
//#region src/connect-to-websocket.ts
/**
* Opens a WebSocket for a provider model, owning the transport-generic layer
* (analogous to `postToApi` for HTTP): constructor resolution, header hygiene,
* abort wiring, and message decoding. Callers own the URL, the auth channel
* (subprotocols vs headers), and the wire protocol.
*/
function connectToWebSocket({ url, protocols, headers, webSocket, abortSignal, onOpen, onMessageText, onProcessingError, onSocketError, onClose, onAbort }) {
	let socket;
	let abortListener;
	const close = (code) => {
		if (abortListener != null) {
			abortSignal?.removeEventListener("abort", abortListener);
			abortListener = void 0;
		}
		try {
			socket?.close(code);
		} catch {}
	};
	if (abortSignal?.aborted) {
		onAbort?.(abortSignal.reason ?? /* @__PURE__ */ new Error("Aborted"));
		return {
			socket: void 0,
			close
		};
	}
	try {
		socket = new (getWebSocketConstructor(webSocket))(url, protocols, { headers: removeUndefinedEntries(headers ?? {}) });
	} catch (error) {
		onProcessingError(error);
		return {
			socket: void 0,
			close
		};
	}
	if (abortSignal != null && onAbort != null) {
		abortListener = () => onAbort(abortSignal.reason ?? /* @__PURE__ */ new Error("Aborted"));
		abortSignal.addEventListener("abort", abortListener, { once: true });
	}
	const openedSocket = socket;
	socket.onopen = () => {
		try {
			onOpen?.(openedSocket);
		} catch (error) {
			onProcessingError(error);
		}
	};
	let tail = Promise.resolve();
	socket.onmessage = (event) => {
		tail = tail.then(() => readWebSocketMessageText(event.data)).then((text) => onMessageText(text)).catch(onProcessingError);
	};
	socket.onerror = () => {
		tail = tail.then(() => onSocketError?.()).catch(onProcessingError);
	};
	socket.onclose = (event) => {
		const closeEvent = event;
		const code = typeof closeEvent?.code === "number" ? closeEvent.code : void 0;
		const reason = typeof closeEvent?.reason === "string" ? closeEvent.reason : void 0;
		tail = tail.then(() => onClose?.({
			code,
			reason
		})).catch(onProcessingError);
	};
	return {
		socket,
		close
	};
}
//#endregion
//#region src/convert-async-iterator-to-readable-stream.ts
/**
* Converts an AsyncIterator to a ReadableStream.
*
* @template T - The type of elements produced by the AsyncIterator.
* @param { <T>} iterator - The AsyncIterator to convert.
* @returns {ReadableStream<T>} - A ReadableStream that provides the same data as the AsyncIterator.
*/
function convertAsyncIteratorToReadableStream(iterator) {
	let cancelled = false;
	return new ReadableStream({
		/**
		* Called when the consumer wants to pull more data from the stream.
		*
		* @param {ReadableStreamDefaultController<T>} controller - The controller to enqueue data into the stream.
		* @returns {Promise<void>}
		*/
		async pull(controller) {
			if (cancelled) return;
			try {
				const { value, done } = await iterator.next();
				if (done) controller.close();
				else controller.enqueue(value);
			} catch (error) {
				controller.error(error);
			}
		},
		/**
		* Called when the consumer cancels the stream.
		*/
		async cancel(reason) {
			cancelled = true;
			if (iterator.return) try {
				await iterator.return(reason);
			} catch {}
		}
	});
}
//#endregion
//#region src/uint8-utils.ts
const { btoa, atob } = globalThis;
function convertBase64ToUint8Array(base64String) {
	const base64Url = base64String.replace(/-/g, "+").replace(/_/g, "/");
	const latin1string = atob(base64Url);
	const bytes = new Uint8Array(latin1string.length);
	for (let i = 0; i < latin1string.length; i++) bytes[i] = latin1string.charCodeAt(i);
	return bytes;
}
function convertUint8ArrayToBase64(array) {
	if (typeof globalThis.Buffer?.from === "function") return globalThis.Buffer.from(array.buffer, array.byteOffset, array.byteLength).toString("base64");
	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(""));
}
const typedArrayTag = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(Uint8Array.prototype), Symbol.toStringTag).get;
const arrayBufferByteLength = Object.getOwnPropertyDescriptor(ArrayBuffer.prototype, "byteLength").get;
function isUint8Array(value) {
	return ArrayBuffer.isView(value) && typedArrayTag.call(value) === "Uint8Array";
}
function isArrayBuffer(value) {
	if (typeof value !== "object" || value === null || !("byteLength" in value)) return false;
	try {
		arrayBufferByteLength.call(value);
		return true;
	} catch {
		return false;
	}
}
function convertToBase64(value) {
	return isUint8Array(value) ? convertUint8ArrayToBase64(value) : value;
}
//#endregion
//#region src/convert-inline-file-data-to-uint8-array.ts
/**
* Converts inline file data (a tagged `data` or `text` shape) into raw bytes.
*
* - `{ type: 'text', text }` → UTF-8 encoded bytes
* - `{ type: 'data', data: Uint8Array | Buffer }` → returned as-is
* - `{ type: 'data', data: ArrayBuffer }` → wrapped in a `Uint8Array`
* - `{ type: 'data', data: string }` → decoded as base64
*
* `{ type: 'stream' }` data is rejected: providers without streaming upload
* support funnel here and surface a clear `UnsupportedFunctionalityError`.
*/
function convertInlineFileDataToUint8Array(data) {
	if (data.type === "stream") {
		const error = new UnsupportedFunctionalityError({ functionality: "streaming file upload" });
		data.stream.cancel(error).catch(() => {});
		throw error;
	}
	if (data.type === "text") return new TextEncoder().encode(data.text);
	if (data.data instanceof Uint8Array) return data.data;
	if (isUint8Array(data.data)) return new Uint8Array(data.data.buffer, data.data.byteOffset, data.data.byteLength);
	if (isArrayBuffer(data.data)) return new Uint8Array(data.data);
	return convertBase64ToUint8Array(data.data);
}
//#endregion
//#region src/convert-image-model-file-to-data-uri.ts
/**
* Convert an ImageModelV4File to a URL or data URI string.
*
* If the file is a URL, it returns the URL as-is.
* If the file is base64 data, it returns a data URI with the base64 data.
* If the file is a Uint8Array, it converts it to base64 and returns a data URI.
*/
function convertImageModelFileToDataUri(file) {
	if (file.type === "url") return file.url;
	return `data:${file.mediaType};base64,${typeof file.data === "string" ? file.data : convertUint8ArrayToBase64(file.data)}`;
}
//#endregion
//#region src/convert-json-response-tool-stream.ts
/**
* Providers that cannot use native structured output for a request can use a
* JSON response tool instead. This utility converts that tool's streamed input
* into text events so the SDK can parse it as structured output.
*
* Conversational text is suppressed. Application tool calls pass through so the
* caller can execute them. A response containing only the JSON tool finishes
* with `stop`; a response containing application calls keeps its finish reason.
*/
function convertJsonResponseToolStream(toolName) {
	const responseToolIds = /* @__PURE__ */ new Set();
	const responseToolsWithDeltas = /* @__PURE__ */ new Set();
	let hasResponseTool = false;
	let hasApplicationTool = false;
	return new TransformStream({ transform(part, controller) {
		switch (part.type) {
			case "text-start":
			case "text-delta":
			case "text-end": return;
			case "tool-input-start":
				if (part.toolName === toolName) {
					responseToolIds.add(part.id);
					controller.enqueue({
						type: "text-start",
						id: part.id,
						...part.providerMetadata && { providerMetadata: part.providerMetadata }
					});
					return;
				}
				break;
			case "tool-input-delta":
				if (responseToolIds.has(part.id)) {
					if (part.delta.length > 0) responseToolsWithDeltas.add(part.id);
					controller.enqueue({
						type: "text-delta",
						id: part.id,
						delta: part.delta,
						...part.providerMetadata && { providerMetadata: part.providerMetadata }
					});
					return;
				}
				break;
			case "tool-input-end":
				if (responseToolIds.has(part.id)) return;
				break;
			case "tool-call":
				if (part.toolName === toolName) {
					if (!responseToolsWithDeltas.has(part.toolCallId)) controller.enqueue({
						type: "text-delta",
						id: part.toolCallId,
						delta: part.input,
						...part.providerMetadata && { providerMetadata: part.providerMetadata }
					});
					controller.enqueue({
						type: "text-end",
						id: part.toolCallId,
						...part.providerMetadata && { providerMetadata: part.providerMetadata }
					});
					hasResponseTool = true;
					return;
				}
				if (!part.providerExecuted) hasApplicationTool = true;
				break;
			case "finish": if (hasResponseTool && !hasApplicationTool && part.finishReason.unified === "tool-calls") {
				controller.enqueue({
					...part,
					finishReason: {
						...part.finishReason,
						unified: "stop"
					}
				});
				return;
			}
		}
		controller.enqueue(part);
	} });
}
//#endregion
//#region src/convert-to-form-data.ts
/**
* Converts an input object to FormData for multipart/form-data requests.
*
* Handles the following cases:
* - `null` or `undefined` values are skipped
* - Arrays with a single element are appended as a single value
* - Arrays with multiple elements are appended with `[]` suffix (e.g., `image[]`)
*   unless `useArrayBrackets` is set to `false`
* - All other values are appended directly
*
* @param input - The input object to convert. Use a generic type for type validation.
* @param options - Optional configuration object.
* @param options.useArrayBrackets - Whether to add `[]` suffix for multi-element arrays.
*   Defaults to `true`. Set to `false` for APIs that expect repeated keys without brackets.
* @returns A FormData object containing the input values.
*
* @example
* ```ts
* type MyInput = {
*   model: string;
*   prompt: string;
*   images: Blob[];
* };
*
* const formData = convertToFormData<MyInput>({
*   model: 'gpt-image-1',
*   prompt: 'A cat',
*   images: [blob1, blob2],
* });
* ```
*/
function convertToFormData(input, options = {}) {
	const { useArrayBrackets = true } = options;
	const formData = new FormData();
	for (const [key, value] of Object.entries(input)) {
		if (value == null) continue;
		if (Array.isArray(value)) {
			if (value.length === 1) {
				formData.append(key, value[0]);
				continue;
			}
			const arrayKey = useArrayBrackets ? `${key}[]` : key;
			for (const item of value) formData.append(arrayKey, item);
			continue;
		}
		formData.append(key, value);
	}
	return formData;
}
//#endregion
//#region src/create-language-model-response-metadata.ts
/**
* Converts common provider response fields into language model response
* metadata.
*/
function createLanguageModelResponseMetadata({ id, model, created }) {
	return {
		id: id ?? void 0,
		modelId: model ?? void 0,
		timestamp: created != null ? /* @__PURE__ */ new Date(created * 1e3) : void 0
	};
}
//#endregion
//#region src/create-null-language-model-usage.ts
/**
* Creates an empty language model usage result for unavailable usage data.
*/
function createNullLanguageModelUsage() {
	return {
		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
	};
}
//#endregion
//#region src/create-tool-name-mapping.ts
/**
* @param tools - Tools that were passed to the language model.
* @param providerToolNames - Maps the provider tool ids to the provider tool names.
*/
function createToolNameMapping({ tools = [], providerToolNames }) {
	const customToolNameToProviderToolName = {};
	const providerToolNameToCustomToolName = {};
	for (const tool of tools) if (tool.type === "provider" && tool.id in providerToolNames) {
		const providerToolName = providerToolNames[tool.id];
		customToolNameToProviderToolName[tool.name] = providerToolName;
		providerToolNameToCustomToolName[providerToolName] = tool.name;
	}
	return {
		toProviderToolName: (customToolName) => customToolNameToProviderToolName[customToolName] ?? customToolName,
		toCustomToolName: (providerToolName) => providerToolNameToCustomToolName[providerToolName] ?? providerToolName
	};
}
//#endregion
//#region src/create-provider-stream-error.ts
const marker$2 = Symbol.for("vercel.ai.providerStreamError");
/**
* Adds provider-owned status and retry metadata to a stream error payload
* without requiring provider packages to depend on AI SDK Core.
*/
function createProviderStreamError({ message, type, code, statusCode, isRetryable, data }) {
	const error = {
		message,
		type,
		code,
		statusCode,
		isRetryable,
		data
	};
	Object.defineProperty(error, marker$2, { value: true });
	return error;
}
function isProviderStreamError(error) {
	return typeof error === "object" && error != null && error[marker$2] === true;
}
//#endregion
//#region src/delayed-promise.ts
/**
* Delayed promise. It is only constructed once the value is accessed.
* This is useful to avoid unhandled promise rejections when the promise is created
* but not accessed.
*/
var DelayedPromise = class {
	constructor() {
		this.status = { type: "pending" };
		this._resolve = void 0;
		this._reject = void 0;
	}
	get promise() {
		if (this._promise) return this._promise;
		this._promise = new Promise((resolve, reject) => {
			if (this.status.type === "resolved") resolve(this.status.value);
			else if (this.status.type === "rejected") reject(this.status.error);
			this._resolve = resolve;
			this._reject = reject;
		});
		return this._promise;
	}
	resolve(value) {
		this.status = {
			type: "resolved",
			value
		};
		if (this._promise) this._resolve?.(value);
	}
	reject(error) {
		this.status = {
			type: "rejected",
			error
		};
		if (this._promise) this._reject?.(error);
	}
	isResolved() {
		return this.status.type === "resolved";
	}
	isRejected() {
		return this.status.type === "rejected";
	}
	isPending() {
		return this.status.type === "pending";
	}
};
//#endregion
//#region src/extract-response-headers.ts
/**
* Extracts the headers from a response object and returns them as a key-value object.
*
* @param response - The response object to extract headers from.
* @returns The headers as a key-value object.
*/
function extractResponseHeaders(response) {
	return Object.fromEntries([...response.headers]);
}
//#endregion
//#region src/get-runtime-environment-user-agent.ts
function getRuntimeEnvironmentUserAgent(globalThisAny = globalThis) {
	if (globalThisAny.navigator?.userAgent) return globalThisAny.navigator.userAgent.toLowerCase();
	if (globalThisAny.process?.versions?.node) return `node.js/${globalThisAny.process.version}`;
	if (globalThisAny.EdgeRuntime) return "vercel-edge";
	return "";
}
//#endregion
//#region src/is-abort-error.ts
function isAbortError(error) {
	return (error instanceof Error || typeof DOMException === "function" && error instanceof DOMException) && (error.name === "AbortError" || error.name === "ResponseAborted" || error.name === "TimeoutError");
}
//#endregion
//#region src/handle-fetch-error.ts
const FETCH_FAILED_ERROR_MESSAGES = ["fetch failed", "failed to fetch"];
const 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;
	}
}
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
		});
	}
	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;
}
//#endregion
//#region src/version.ts
const VERSION = "5.0.81";
//#endregion
//#region src/normalize-headers.ts
/**
* Normalizes different header inputs into a plain record with lower-case keys.
* Entries with `undefined` or `null` values are removed.
*
* @param headers - Input headers (`Headers`, tuples array, plain record) to normalize.
* @returns A record containing the normalized header entries.
*/
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;
}
//#endregion
//#region src/with-user-agent-suffix.ts
/**
* Appends suffix parts to the `user-agent` header.
* If a `user-agent` header already exists, the suffix parts are appended to it.
* If no `user-agent` header exists, a new one is created with the suffix parts.
* Automatically removes undefined entries from the headers.
*
* @param headers - The original headers.
* @param userAgentSuffixParts - The parts to append to the `user-agent` header.
* @returns The new headers with the `user-agent` header set or updated.
*/
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());
}
//#endregion
//#region src/delete-from-api.ts
const getOriginalFetch$3 = () => globalThis.fetch;
/**
* Sends a DELETE request. For URLs built from developer-configured endpoints
* only — there is no untrusted-URL validation path (use `getFromApi` with
* `validateUrl` for response-supplied URLs).
*/
const deleteFromApi = async ({ url, headers = {}, failedResponseHandler, successfulResponseHandler, abortSignal, fetch = getOriginalFetch$3() }) => {
	try {
		const response = await fetch(url, {
			method: "DELETE",
			headers: withUserAgentSuffix(headers, `ai-sdk-provider-utils/${VERSION}`, getRuntimeEnvironmentUserAgent()),
			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: {}
		});
	}
};
//#endregion
//#region src/detect-media-type.ts
const imageMediaTypeSignatures = [
	{
		mediaType: "image/gif",
		bytesPrefix: [
			71,
			73,
			70,
			56,
			55,
			97
		]
	},
	{
		mediaType: "image/gif",
		bytesPrefix: [
			71,
			73,
			70,
			56,
			57,
			97
		]
	},
	{
		mediaType: "image/png",
		bytesPrefix: [
			137,
			80,
			78,
			71
		]
	},
	{
		mediaType: "image/jpeg",
		bytesPrefix: [255, 216]
	},
	{
		mediaType: "image/webp",
		bytesPrefix: [
			82,
			73,
			70,
			70,
			null,
			null,
			null,
			null,
			87,
			69,
			66,
			80
		]
	},
	{
		mediaType: "image/bmp",
		bytesPrefix: [
			66,
			77,
			null,
			null,
			null,
			null,
			0,
			0,
			0,
			0
		]
	},
	{
		mediaType: "image/tiff",
		bytesPrefix: [
			73,
			73,
			42,
			0
		]
	},
	{
		mediaType: "image/tiff",
		bytesPrefix: [
			77,
			77,
			0,
			42
		]
	},
	{
		mediaType: "image/avif",
		bytesPrefix: [
			0,
			0,
			0,
			null,
			102,
			116,
			121,
			112,
			97,
			118,
			105,
			102
		]
	},
	{
		mediaType: "image/heic",
		bytesPrefix: [
			0,
			0,
			0,
			null,
			102,
			116,
			121,
			112,
			104,
			101,
			105,
			99
		]
	}
];
const documentMediaTypeSignatures = [{
	mediaType: "application/pdf",
	bytesPrefix: [
		37,
		80,
		68,
		70
	]
}];
const audioMediaTypeSignaturesWithoutMp4 = [
	{
		mediaType: "audio/aac",
		bytesPrefix: [255, 240]
	},
	{
		mediaType: "audio/aac",
		bytesPrefix: [255, 241]
	},
	{
		mediaType: "audio/aac",
		bytesPrefix: [255, 248]
	},
	{
		mediaType: "audio/aac",
		bytesPrefix: [255, 249]
	},
	{
		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,
			73,
			70,
			70,
			null,
			null,
			null,
			null,
			87,
			65,
			86,
			69
		]
	},
	{
		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
		]
	}
];
const audioMediaTypeSignatures = [...audioMediaTypeSignaturesWithoutMp4, {
	mediaType: "audio/mp4",
	bytesPrefix: [
		0,
		0,
		0,
		null,
		102,
		116,
		121,
		112
	]
}];
const videoMediaTypeSignatures = [
	{
		mediaType: "video/mp4",
		bytesPrefix: [
			0,
			0,
			0,
			null,
			102,
			116,
			121,
			112
		]
	},
	{
		mediaType: "video/webm",
		bytesPrefix: [
			26,
			69,
			223,
			163
		]
	},
	{
		mediaType: "video/quicktime",
		bytesPrefix: [
			0,
			0,
			0,
			20,
			102,
			116,
			121,
			112,
			113,
			116
		]
	},
	{
		mediaType: "video/x-msvideo",
		bytesPrefix: [
			82,
			73,
			70,
			70
		]
	}
];
const DEFAULT_SNIFF_BYTES = 18;
const ID3_SCAN_BYTES = 131084;
function decodePrefix(data, maxBytes) {
	if (typeof data !== "string") return data.length > maxBytes ? data.subarray(0, maxBytes) : data;
	const maxChars = Math.ceil(maxBytes / 3) * 4;
	const bytes = convertBase64ToUint8Array(data.substring(0, Math.min(data.length, maxChars)));
	return bytes.length > maxBytes ? bytes.subarray(0, maxBytes) : bytes;
}
function hasID3(bytes) {
	return bytes.length > 10 && bytes[0] === 73 && bytes[1] === 68 && bytes[2] === 51;
}
const stripID3 = (bytes) => {
	const id3Size = (bytes[6] & 127) << 21 | (bytes[7] & 127) << 14 | (bytes[8] & 127) << 7 | bytes[9] & 127;
	return bytes.subarray(id3Size + 10);
};
function detectMediaTypeBySignatures({ data, signatures }) {
	let bytes = decodePrefix(data, DEFAULT_SNIFF_BYTES);
	if (hasID3(bytes)) bytes = stripID3(decodePrefix(data, ID3_SCAN_BYTES));
	for (const signature of signatures) if (bytes.length >= signature.bytesPrefix.length && signature.bytesPrefix.every((byte, index) => byte === null || bytes[index] === byte)) return signature.mediaType;
}
const topLevelSignatureTables = {
	image: imageMediaTypeSignatures,
	audio: audioMediaTypeSignatures,
	video: videoMediaTypeSignatures,
	application: documentMediaTypeSignatures
};
/**
* Detect the IANA media type of a file from its raw bytes or base64 string.
*
* - When `topLevelType` is omitted, every known signature is considered
*   (image, audio, video, and application). Returns `undefined` when the
*   bytes do not match any known signature.
* - When `topLevelType` is provided, only signatures for that top-level
*   segment are considered. Returns `undefined` for unsupported segments
*   (e.g. `"text"`) or when no signature matches.
*/
function detectMediaType({ data, topLevelType }) {
	if (topLevelType === void 0) return detectMediaTypeBySignatures({
		data,
		signatures: [
			...imageMediaTypeSignatures,
			...documentMediaTypeSignatures,
			...audioMediaTypeSignaturesWithoutMp4,
			...videoMediaTypeSignatures
		]
	});
	if (!Object.prototype.hasOwnProperty.call(topLevelSignatureTables, topLevelType)) return;
	return detectMediaTypeBySignatures({
		data,
		signatures: topLevelSignatureTables[topLevelType]
	});
}
/**
* Returns the top-level segment of a media type (the portion before `/`).
*
* Examples:
*   - `"image/png"` -> `"image"`
*   - `"image/*"` -> `"image"`
*   - `"image"` -> `"image"`
*   - `"image/"` -> `"image"`
*   - `""` -> `""`
*   - `"/"` -> `""`
*/
function getTopLevelMediaType(mediaType) {
	const slashIndex = mediaType.indexOf("/");
	return slashIndex === -1 ? mediaType : mediaType.substring(0, slashIndex);
}
/**
* Returns `true` only when the given media type has a non-empty, non-wildcard
* subtype (i.e. matches the form `type/subtype`, and `subtype` is not `*`).
*
* Examples:
*   - `"image/png"` -> `true`
*   - `"image/*"` -> `false`
*   - `"image"` -> `false`
*   - `"image/"` -> `false`
*   - `""` -> `false`
*   - `"/"` -> `false`
*/
function isFullMediaType(mediaType) {
	const slashIndex = mediaType.indexOf("/");
	if (slashIndex === -1) return false;
	const subtype = mediaType.substring(slashIndex + 1);
	return subtype.length > 0 && subtype !== "*";
}
//#endregion
//#region src/cancel-response-body.ts
/**
* Cancels a response body to release the underlying connection.
*
* When a fetch Response is rejected without consuming its body (e.g. a failed
* status code, an open-redirect rejection, or a Content-Length that exceeds the
* size limit), the underlying TCP socket is not returned to the connection pool
* and may stay open until the process runs out of file descriptors. Cancelling
* the body avoids this leak.
*
* Errors thrown while cancelling are ignored: the body may already be locked,
* disturbed, or absent, none of which should mask the original rejection.
*/
async function cancelResponseBody(response) {
	try {
		await response.body?.cancel();
	} catch {}
}
//#endregion
//#region src/download-error.ts
const name$1 = "AI_DownloadError";
const marker$1 = `vercel.ai.error.${name$1}`;
const symbol$1 = Symbol.for(marker$1);
var DownloadError = class extends AISDKError {
	constructor({ url, statusCode, statusText, cause, message = cause == null ? `Failed to download ${url}: ${statusCode} ${statusText}` : `Failed to download ${url}: ${cause}` }) {
		super({
			name: name$1,
			message,
			cause
		});
		this[symbol$1] = true;
		this.url = url;
		this.statusCode = statusCode;
		this.statusText = statusText;
	}
	static isInstance(error) {
		return AISDKError.hasMarker(error, marker$1);
	}
};
//#endregion
//#region src/is-browser-runtime.ts
/**
* Returns `true` when running in a browser.
*
* Detection keys on the presence of a global `window`, matching the browser
* check used elsewhere in this package (see `getRuntimeEnvironmentUserAgent`)
* so the SDK has a single, consistent definition of "browser". Server runtimes
* (Node.js, Deno, Bun, edge/workers) do not define `window`.
*/
function isBrowserRuntime(globalThisAny = globalThis) {
	return globalThisAny.window != null;
}
//#endregion
//#region src/is-same-origin.ts
/**
* Returns true when `url` has the same origin (scheme + host + port) as
* `baseUrl`.
*
* Used to decide whether provider credentials may be attached to a request to a
* URL taken from a provider response (e.g. a polling or media-download URL).
* Credentials must only be sent to the provider's own origin; a response that
* names a foreign host (a CDN, or an attacker-controlled host if the response
* is tampered with) must not receive the API key.
*
* Returns false if either value is not a valid absolute URL (fail-closed).
*/
function isSameOrigin(url, baseUrl) {
	try {
		return new URL(url).origin === new URL(baseUrl).origin;
	} catch {
		return false;
	}
}
//#endregion
//#region src/sanitize-request-headers.ts
/**
* Request headers stripped before fetching an untrusted URL: host/virtual-host
* routing, proxy/origin spoofing, cloud-metadata, cookies, and hop-by-hop
* transport headers (RFC 7230 §6.1).
*
* `Authorization` and other credential-bearing caller headers (e.g. `x-key`)
* are intentionally not listed because trusted provider requests may need
* them. `fetchUntrustedUrl` separately restricts an untrusted first hop to an
* explicit allowlist of non-credential request metadata. Both it and
* `fetchWithValidatedRedirects` drop all caller headers except the user-agent
* on a cross-origin redirect.
*/
const BLOCKED_REQUEST_HEADERS = [
	"connection",
	"keep-alive",
	"te",
	"trailer",
	"transfer-encoding",
	"upgrade",
	"host",
	"forwarded",
	"proxy-authorization",
	"via",
	"x-forwarded-for",
	"x-forwarded-host",
	"x-forwarded-proto",
	"x-real-ip",
	"metadata",
	"metadata-flavor",
	"x-aws-ec2-metadata-token",
	"x-metadata-token",
	"cookie",
	"set-cookie"
];
/**
* Returns a fresh `Headers` built from `input` with {@link BLOCKED_REQUEST_HEADERS}
* removed. The input is never mutated.
*/
function sanitizeRequestHeaders(input) {
	const headers = new Headers(input);
	for (const name of BLOCKED_REQUEST_HEADERS) headers.delete(name);
	return headers;
}
//#endregion
//#region src/validate-download-url.ts
/**
* Validates that a URL is safe to download from, blocking private/internal addresses
* to prevent SSRF attacks.
*
* This function performs string/literal-IP checks only. DNS validation must
* be provided by the fetch transport or network egress controls.
*
* @param url - The URL string to validate.
* @throws DownloadError if the URL is unsafe.
*/
function validateDownloadUrl(url) {
	let parsed;
	try {
		parsed = new URL(url);
	} catch {
		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") || hostname.endsWith(".internal")) throw new DownloadError({
		url,
		message: `URL with hostname ${hostname} is not allowed`
	});
	if (hostname.startsWith("[") && hostname.endsWith("]")) {
		if (isPrivateIPv6(hostname.slice(1, -1))) 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`
		});
	}
}
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 [a, b, c] = ip.split(".").map(Number);
	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;
}
/**
* Expands an IPv6 address string into its 8 16-bit groups, handling `::`
* compression and an optional dotted-decimal IPv4 tail (e.g. `::ffff:127.0.0.1`).
*
* @returns the 8 groups, or null if the input is not a parseable IPv6 address.
*/
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;
	if (topZero(6) || topZero(5) && groups[5] === 65535 || topZero(4) && groups[4] === 65535 && groups[5] === 0 || groups[0] === 100 && groups[1] === 65435 && groups[2] === 0 && groups[3] === 0 && groups[4] === 0 && groups[5] === 0 || groups[0] === 100 && groups[1] === 65435 && groups[2] === 1) return isPrivateIPv4(`${groups[6] >> 8 & 255}.${groups[6] & 255}.${groups[7] >> 8 & 255}.${groups[7] & 255}`);
	return false;
}
//#endregion
//#region src/fetch-with-validated-redirects.ts
const MAX_DOWNLOAD_REDIRECTS = 10;
const REDIRECT_STATUS_CODES = /* @__PURE__ */ new Set([
	301,
	302,
	303,
	307,
	308
]);
/**
* Fetches one validated URL without following redirects.
*
* Uses the supplied fetch or the runtime's global fetch. URL validation does
* not resolve DNS; inject a transport such as guarded-fetch on Node.js
* when connection-time DNS validation is needed.
* Redirects are rejected by default. Callers using `redirect: 'manual'` must
* validate the Location target before issuing another request.
*/
async function fetchWithValidatedEndpoint({ url, init, fetch: customFetch, trustedOrigin, redirect = "error", requireDnsValidation = false }) {
	const urlText = url.toString();
	if (!(trustedOrigin !== void 0 && isSameOrigin(urlText, trustedOrigin))) {
		validateDownloadUrl(urlText);
		if (requireDnsValidation && (customFetch == null || customFetch === globalThis.fetch) && !(isBrowserRuntime() && typeof document !== "undefined")) throw new DownloadError({
			url: urlText,
			message: "This server runtime requires a custom fetch with connect-time DNS validation for untrusted URLs"
		});
	}
	return await (customFetch ?? globalThis.fetch)(url, {
		...init,
		redirect
	});
}
/**
* Fetches a URL while enforcing the download guard on every hop.
*
* Redirects are followed manually (`redirect: 'manual'`) so each hop is
* validated with {@link validateDownloadUrl} *before* it is requested. Relying
* on the default `redirect: 'follow'` would issue the request to a redirect
* target (e.g. an internal address) before we ever see its URL, defeating the
* guard.
*
* Manually followed redirects from HTTPS to HTTP are rejected before requesting
* the target.
*
* Request headers are also protected: {@link sanitizeRequestHeaders} strips
* proxy/metadata/cookie/hop-by-hop headers before the first request, and all
* caller headers except `User-Agent` are dropped on a cross-origin redirect.
* Credentials and custom headers are preserved on the first hop for backwards
* compatibility. The caller must ensure that the initial URL may receive them.
* Use `fetchUntrustedUrl` for URLs that require first-hop credential isolation.
* The fetch spec only strips `Authorization` on cross-origin redirects because
* in a browser, CORS preflighting protects custom headers; there is no CORS on
* the server, so provider API keys carried in custom headers (e.g. `x-key`)
* must be dropped here as well.
*
* A `redirect: 'manual'` request yields an unreadable opaque response in the
* browser (and in other spec-compliant fetch implementations), so the redirect
* target cannot be validated here. In a real browser this is safe to follow
* natively because reaching an internal network is not possible (fetch is
* constrained by CORS and cannot reach a server's internal network or
* cloud-metadata). On any other runtime we cannot validate the hop, so we fail
* closed rather than follow it blindly and bypass the guard.
*
* A hop that is same-origin with `trustedOrigin` (the developer-configured
* provider endpoint) skips target validation: that origin is exactly what an
* unvalidated, config-derived request would fetch anyway, and validating it
* would break legitimate self-hosted / localhost deployments whose response
* URLs point back at the configured host. Hops on any other origin are always
* validated.
*
* The returned response is the final (non-redirect) response. The caller is
* responsible for checking `response.ok` and reading the body.
*
* URL validation does not resolve DNS. Use guarded-fetch on Node.js
* for connection-time DNS validation, or enforce network egress restrictions.
*
* @throws DownloadError if a hop is unsafe, the redirect limit is exceeded, or
* a redirect cannot be validated on a non-browser runtime.
*/
async function fetchWithValidatedRedirects({ url, headers, abortSignal, maxRedirects = MAX_DOWNLOAD_REDIRECTS, fetch: customFetch, trustedOrigin }) {
	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++) {
		if (!(trustedOrigin !== void 0 && isSameOrigin(currentUrl, trustedOrigin))) validateDownloadUrl(currentUrl);
		const fetch = customFetch ?? globalThis.fetch;
		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 = response.headers?.get("location");
		if (REDIRECT_STATUS_CODES.has(response.status) && location) {
			cancelResponseBody(response);
			const nextUrl = new URL(location, currentUrl).toString();
			if (new URL(currentUrl).protocol === "https:" && new URL(nextUrl).protocol === "http:") throw new DownloadError({
				url,
				message: "Redirect from HTTPS to HTTP was blocked"
			});
			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})`
	});
}
//#endregion
//#region src/fetch-untrusted-url.ts
const SAFE_UNTRUSTED_FIRST_HOP_HEADERS = /* @__PURE__ */ new Set([
	"accept",
	"accept-language",
	"baggage",
	"cache-control",
	"idempotency-key",
	"if-match",
	"if-modified-since",
	"if-none-match",
	"if-range",
	"if-unmodified-since",
	"pragma",
	"range",
	"traceparent",
	"tracestate",
	"user-agent",
	"x-correlation-id",
	"x-request-id"
]);
/**
* Fetches an untrusted URL with first-hop credential isolation and validated
* redirects. Uses the URL validation, runtime fetch transport, redirect
* limits, and cross-origin header stripping of {@link fetchWithValidatedRedirects}.
* Inject guarded-fetch on Node.js for connect-time DNS validation.
*
* Without a matching `credentialedOrigin` (or `trustedOrigin` when it is
* omitted), only allowlisted request metadata is sent on the first hop.
* Arbitrary caller headers require an explicit matching origin because vendor
* credential names cannot be inferred safely. Proxy, metadata, cookie, and
* hop-by-hop headers are sanitized even for a matching origin.
*
* `trustedOrigin` also exempts same-origin hops from URL validation, allowing
* developer-configured private endpoints. Both origin options must come from
* developer configuration, never from untrusted response data.
*
* This is an opt-in alternative to `fetchWithValidatedRedirects`, whose
* existing first-hop header behavior is preserved for compatibility.
*/
async function fetchUntrustedUrl({ headers, credentialedOrigin, untrustedFirstHopHeaders, ...options }) {
	let firstHopHeaders;
	if (headers !== void 0) {
		firstHopHeaders = sanitizeRequestHeaders(headers);
		const origin = credentialedOrigin ?? options.trustedOrigin;
		if (origin === void 0 || !isSameOrigin(options.url, origin)) {
			const allowedHeaders = /* @__PURE__ */ new Set([...SAFE_UNTRUSTED_FIRST_HOP_HEADERS, ...(untrustedFirstHopHeaders ?? []).map((name) => name.toLowerCase())]);
			firstHopHeaders = new Headers([...firstHopHeaders].filter(([name]) => allowedHeaders.has(name)));
		}
	}
	return fetchWithValidatedRedirects({
		...options,
		headers: firstHopHeaders
	});
}
//#endregion
//#region src/read-response-with-size-limit.ts
/**
* Default maximum download size: 2 GiB.
*
* `fetch().arrayBuffer()` has ~2x peak memory overhead (undici buffers the
* body internally, then creates the JS ArrayBuffer), so very large downloads
* risk exceeding the default V8 heap limit on 64-bit systems and terminating
* the process with an out-of-memory error.
*
* Setting this limit converts an unrecoverable OOM crash into a catchable
* `DownloadError`.
*/
const DEFAULT_MAX_DOWNLOAD_SIZE = 2147483648;
/**
* Reads a fetch Response body with a size limit to prevent memory exhaustion.
*
* Checks the Content-Length header for early rejection, then reads the body
* incrementally via ReadableStream and aborts with a DownloadError when the
* limit is exceeded.
*
* @param response - The fetch Response to read.
* @param url - The URL being downloaded (used in error messages).
* @param maxBytes - Maximum allowed bytes. Defaults to DEFAULT_MAX_DOWNLOAD_SIZE.
* @param onChunk - Optional. Receives each chunk instead of the chunks being
* collected, so the body is not held in memory, and the returned array is empty.
* The chunk may be a view on a larger buffer, copy what you keep.
* @returns A Uint8Array containing the response body.
* @throws DownloadError if the response exceeds maxBytes.
*/
async function readResponseWithSizeLimit({ response, url, maxBytes = DEFAULT_MAX_DOWNLOAD_SIZE, onChunk }) {
	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 /* @__PURE__ */ 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.`
			});
			if (onChunk != null) {
				onChunk(value);
				continue;
			}
			chunks.push(value.byteLength < value.buffer.byteLength ? new Uint8Array(value) : value);
		}
	} finally {
		try {
			await reader.cancel();
		} catch {} finally {
			reader.releaseLock();
		}
	}
	const result = new Uint8Array(onChunk != null ? 0 : totalBytes);
	let offset = 0;
	for (const chunk of chunks) {
		result.set(chunk, offset);
		offset += chunk.length;
	}
	return result;
}
//#endregion
//#region src/download-blob.ts
/**
* Download a file from a URL and return it as a Blob.
*
* @param url - The URL to download from.
* @param options - Optional settings for the download.
* @param options.maxBytes - Maximum allowed download size in bytes. Defaults to 100 MiB.
* @param options.abortSignal - An optional abort signal to cancel the download.
* @param options.fetch - Fetch transport, e.g. guarded-fetch for DNS validation on Node.js.
* @returns A Promise that resolves to the downloaded Blob.
*
* @throws DownloadError if the download fails or exceeds maxBytes.
*/
async function downloadBlob(url, options) {
	try {
		const response = await fetchUntrustedUrl({
			url,
			abortSignal: options?.abortSignal,
			fetch: options?.fetch
		});
		if (!response.ok) {
			await cancelResponseBody(response);
			throw new DownloadError({
				url,
				statusCode: response.status,
				statusText: response.statusText
			});
		}
		const data = await readResponseWithSizeLimit({
			response,
			url,
			maxBytes: options?.maxBytes ?? 2147483648
		});
		const contentType = response.headers.get("content-type") ?? void 0;
		return new Blob([data], contentType ? { type: contentType } : void 0);
	} catch (error) {
		if (DownloadError.isInstance(error)) throw error;
		throw new DownloadError({
			url,
			cause: error
		});
	}
}
//#endregion
//#region src/embedding-model-capabilities.ts
/**
* Symbol for exposing the UTF-8 input byte budget of an embedding model.
*
* This capability is experimental and intentionally lives outside the versioned
* embedding model specification.
*/
const EMBEDDING_MODEL_MAX_INPUT_BYTES_PER_CALL = Symbol.for("vercel.ai.embeddingModel.maxInputBytesPerCall");
/**
* Symbol for transforming provider options for an automatically batched
* embedding model call.
*
* This capability is experimental and intentionally lives outside the versioned
* embedding model specification.
*/
const EMBEDDING_MODEL_PROVIDER_OPTIONS_TRANSFORMER = Symbol.for("vercel.ai.embeddingModel.providerOptionsTransformer");
//#endregion
//#region src/encode-path-segment.ts
/**
* Encodes a raw identifier as one URL path segment, including standalone dot
* segments that URL parsers would otherwise normalize. Pass unencoded values;
* for resource paths with intentional slashes, encode each segment separately.
*/
function encodePathSegment(value) {
	const encodedValue = encodeURIComponent(value);
	return encodedValue === "." ? "%252E" : encodedValue === ".." ? "%252E%252E" : encodedValue;
}
//#endregion
//#region src/extract-lines.ts
/**
* Extracts a 1-based inclusive line range from `text`, auto-detecting the
* file's line ending (`\r\n`, `\n`, or `\r`, in that priority).
*
* Mixed line endings are not supported: detection picks one and uses it for
* both the split and the rejoin, so files that mix conventions will not slice
* cleanly. When neither `startLine` nor `endLine` is provided, the input is
* returned unchanged. `endLine` past EOF clamps to the last line.
*/
function extractLines({ text, startLine, endLine }) {
	if (startLine == null && endLine == null) return text;
	const lineEnding = text.includes("\r\n") ? "\r\n" : text.includes("\n") ? "\n" : text.includes("\r") ? "\r" : "\n";
	const lines = text.split(lineEnding);
	const start = Math.max(1, startLine ?? 1) - 1;
	const end = Math.min(lines.length, endLine ?? lines.length);
	return lines.slice(start, end).join(lineEnding);
}
//#endregion
//#region src/filter-nullable.ts
/**
* Filters `null` and `undefined` values out of a list of values.
*
* @param values - The values to filter.
* @returns A new array containing only non-nullish values.
*/
function filterNullable(...values) {
	return values.filter((value) => value != null);
}
//#endregion
//#region src/generate-id.ts
/**
* Creates an ID generator.
* The total length of the ID is the sum of the prefix, separator, and random part length.
* Not cryptographically secure.
*
* @param alphabet - The alphabet to use for the ID. Default: '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.
* @param prefix - The prefix of the ID to generate. Optional.
* @param separator - The separator between the prefix and the random part of the ID. Default: '-'.
* @param size - The size of the random part of the ID to generate. Default: 16.
*/
const 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()}`;
};
/**
* Generates a 16-character random string to use for IDs.
* Not cryptographically secure.
*/
const generateId = createIdGenerator();
//#endregion
//#region src/get-from-api.ts
const getOriginalFetch$2 = () => globalThis.fetch;
const getFromApi = async ({ url, headers = {}, successfulResponseHandler, failedResponseHandler, abortSignal, fetch, validateUrl, credentialedOrigin, trustedOrigin }) => {
	try {
		const requestFetch = fetch ?? getOriginalFetch$2();
		const requestHeaders = withUserAgentSuffix(credentialedOrigin !== void 0 && !isSameOrigin(url, credentialedOrigin) ? {} : headers, `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: {}
		});
	}
};
//#endregion
//#region src/inject-json-instruction.ts
const DEFAULT_SCHEMA_PREFIX = "JSON schema:";
const DEFAULT_SCHEMA_SUFFIX = "You MUST answer with a JSON object that matches the JSON schema above.";
const DEFAULT_GENERIC_SUFFIX = "You MUST answer with JSON.";
function injectJsonInstruction({ prompt, schema, schemaPrefix = schema != null ? DEFAULT_SCHEMA_PREFIX : void 0, schemaSuffix = schema != null ? DEFAULT_SCHEMA_SUFFIX : DEFAULT_GENERIC_SUFFIX }) {
	return [
		prompt != null && prompt.length > 0 ? prompt : void 0,
		prompt != null && prompt.length > 0 ? "" : void 0,
		schemaPrefix,
		schema != null ? JSON.stringify(schema) : void 0,
		schemaSuffix
	].filter((line) => line != null).join("\n");
}
function injectJsonInstructionIntoMessages({ messages, schema, schemaPrefix, schemaSuffix }) {
	const systemMessage = messages[0]?.role === "system" ? { ...messages[0] } : {
		role: "system",
		content: ""
	};
	systemMessage.content = injectJsonInstruction({
		prompt: systemMessage.content,
		schema,
		schemaPrefix,
		schemaSuffix
	});
	return [systemMessage, ...messages[0]?.role === "system" ? messages.slice(1) : messages];
}
//#endregion
//#region src/is-buffer.ts
/**
* Type-guard for Node.js `Buffer` instances.
*
* Uses optional chaining on `globalThis.Buffer` so it returns `false` in
* runtimes where `Buffer` is not available (e.g. CloudFlare Workers).
*/
function isBuffer(value) {
	return globalThis.Buffer?.isBuffer(value) ?? false;
}
//#endregion
//#region src/is-non-nullable.ts
/**
* Type guard that checks whether a value is not `null` or `undefined`.
*
* @template T - The type of the value to check.
* @param value - The value to check.
* @returns `true` if the value is neither `null` nor `undefined`, otherwise `false`.
*/
function isNonNullable(value) {
	return value != null;
}
//#endregion
//#region src/is-provider-reference.ts
/**
* Checks whether a value is a provider reference (a mapping of provider names
* to provider-specific identifiers) as opposed to raw bytes, a URL, or a
* tagged `{ type: ... }` object.
*/
function isProviderReference(data) {
	return typeof data === "object" && data !== null && !isUint8Array(data) && !(data instanceof URL) && !isArrayBuffer(data) && !isBuffer(data) && !("type" in data);
}
//#endregion
//#region src/is-record.ts
/**
* Checks whether a value is a non-null, non-array object.
*/
function isRecord(value) {
	return value != null && typeof value === "object" && !Array.isArray(value);
}
//#endregion
//#region src/is-url-supported.ts
/**
* Checks if the given URL is supported natively by the model.
*
* @param mediaType - The media type of the URL. Case-insensitive. May be a full
*                    `type/subtype`, a wildcard `type/*`, or just the
*                    top-level segment (e.g. `image`).
* @param url - The URL to check.
* @param supportedUrls - A record where keys are case-insensitive media types (or '*')
*                        and values are arrays of RegExp patterns for URLs.
*
* @returns `true` if the URL matches a pattern under the specific media type
*          or the wildcard '*', `false` otherwise.
*/
function isUrlSupported({ mediaType, url, supportedUrls }) {
	mediaType = mediaType.toLowerCase();
	const isTopLevelOnly = !mediaType.includes("/");
	return Object.entries(supportedUrls).map(([key, value]) => {
		const mediaType = key.toLowerCase();
		return mediaType === "*" || mediaType === "*/*" ? {
			mediaTypePrefix: "",
			regexes: value
		} : {
			mediaTypePrefix: mediaType.replace(/\*/, ""),
			regexes: value
		};
	}).filter(({ mediaTypePrefix }) => {
		if (mediaTypePrefix === "") return true;
		if (isTopLevelOnly) return `${mediaType}/` === mediaTypePrefix;
		return mediaTypePrefix.endsWith("/") ? mediaType.startsWith(mediaTypePrefix) : mediaType === mediaTypePrefix;
	}).flatMap(({ regexes }) => regexes).some((pattern) => testRegExpFromStart(pattern, url));
}
function testRegExpFromStart(pattern, value) {
	if (!pattern.global && !pattern.sticky) return pattern.test(value);
	const lastIndex = pattern.lastIndex;
	pattern.lastIndex = 0;
	try {
		return pattern.test(value);
	} finally {
		pattern.lastIndex = lastIndex;
	}
}
//#endregion
//#region src/is-valid-hostname-part.ts
/**
* Checks whether a value is a valid ASCII hostname part: 1–63 letters, digits,
* or hyphens, without a leading or trailing hyphen.
*
* Use this before inserting a resource name, region, or location into a
* generated hostname. Rejects values such as `evil.example.com/#` and
* `user@localhost:8080/#` that could change the request destination.
*/
function isValidHostnamePart(value) {
	return /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/i.exec(value)?.[0] === value;
}
//#endregion
//#region src/load-api-key.ts
function loadApiKey({ apiKey, environmentVariableName, apiKeyParameterName = "apiKey", description }) {
	if (typeof apiKey === "string") return apiKey;
	if (apiKey != null) throw new LoadAPIKeyError({ message: `${description} API key must be a string.` });
	if (typeof process === "undefined") throw new LoadAPIKeyError({ message: `${description} API key is missing. Pass it using the '${apiKeyParameterName}' parameter. Environment variables are not supported in this environment.` });
	apiKey = process.env[environmentVariableName];
	if (apiKey == null) throw new LoadAPIKeyError({ message: `${description} API key is missing. Pass it using the '${apiKeyParameterName}' parameter or the ${environmentVariableName} environment variable.` });
	if (typeof apiKey !== "string") throw new LoadAPIKeyError({ message: `${description} API key must be a string. The value of the ${environmentVariableName} environment variable is not a string.` });
	return apiKey;
}
//#endregion
//#region src/load-optional-setting.ts
/**
* Loads an optional `string` setting from the environment or a parameter.
*
* @param settingValue - The setting value.
* @param environmentVariableName - The environment variable name.
* @returns The setting value.
*/
function loadOptionalSetting({ settingValue, environmentVariableName }) {
	if (typeof settingValue === "string") return settingValue;
	if (settingValue != null || typeof process === "undefined") return;
	settingValue = process.env[environmentVariableName];
	if (settingValue == null || typeof settingValue !== "string") return;
	return settingValue;
}
//#endregion
//#region src/load-setting.ts
/**
* Loads a `string` setting from the environment or a parameter.
*
* @param settingValue - The setting value.
* @param environmentVariableName - The environment variable name.
* @param settingName - The setting name.
* @param description - The description of the setting.
* @returns The setting value.
*/
function loadSetting({ settingValue, environmentVariableName, settingName, description }) {
	if (typeof settingValue === "string") return settingValue;
	if (settingValue != null) throw new LoadSettingError({ message: `${description} setting must be a string.` });
	if (typeof process === "undefined") throw new LoadSettingError({ message: `${description} setting is missing. Pass it using the '${settingName}' parameter. Environment variables are not supported in this environment.` });
	settingValue = process.env[environmentVariableName];
	if (settingValue == null) throw new LoadSettingError({ message: `${description} setting is missing. Pass it using the '${settingName}' parameter or the ${environmentVariableName} environment variable.` });
	if (typeof settingValue !== "string") throw new LoadSettingError({ message: `${description} setting must be a string. The value of the ${environmentVariableName} environment variable is not a string.` });
	return settingValue;
}
//#endregion
//#region src/map-reasoning-to-provider.ts
/**
* Reasoning levels in ascending order.
*/
const REASONING_LEVELS = [
	"minimal",
	"low",
	"medium",
	"high",
	"xhigh",
	"max"
];
function isCustomReasoning(reasoning) {
	return reasoning !== void 0 && reasoning !== "provider-default";
}
/**
* Maps a top-level reasoning value to a provider-specific effort string.
*
* A `providerOptionsEffort` (the reasoning effort set in provider options) is
* returned unchanged. Otherwise, `undefined` and `'provider-default'` return
* `undefined`, and other reasoning values are mapped with the effort map.
*
* The effort map should only contain the values that the model supports. An
* unsupported value maps to the next lower supported level, or the next higher
* one if there is no lower level. `'none'` is never used as a fallback, so an
* unsupported `'none'` maps to the lowest supported level.
*
* Pushes a compatibility warning if the effort that is sent differs from the
* requested value, or an unsupported warning if the effort map is empty.
*
* @returns The provider options effort, the mapped effort string, or
*   `undefined` if no effort should be sent.
*/
function mapReasoningToProviderEffort({ reasoning, effortMap, providerOptionsEffort, warnings }) {
	if (providerOptionsEffort != null) return providerOptionsEffort;
	if (!isCustomReasoning(reasoning)) return;
	const index = REASONING_LEVELS.indexOf(reasoning);
	const level = [
		reasoning,
		...REASONING_LEVELS.slice(0, Math.max(index, 0)).reverse(),
		...REASONING_LEVELS.slice(index + 1)
	].find((candidate) => effortMap[candidate] != null);
	if (level == null) {
		warnings.push({
			type: "unsupported",
			feature: "reasoning",
			details: `reasoning "${reasoning}" is not supported by this model.`
		});
		return;
	}
	const mapped = effortMap[level];
	if (mapped !== reasoning) warnings.push({
		type: "compatibility",
		feature: "reasoning",
		details: `reasoning "${reasoning}" is not directly supported by this model. mapped to effort "${mapped}".`
	});
	return mapped;
}
const DEFAULT_REASONING_BUDGET_PERCENTAGES = {
	minimal: .02,
	low: .1,
	medium: .3,
	high: .6,
	xhigh: .9,
	max: .95
};
/**
* Maps a top-level reasoning value to an absolute token budget by multiplying
* the model's max output tokens by a percentage for the level. Levels missing
* from `budgetPercentages` use the default percentages. The result is clamped
* between `minReasoningBudget` (default 1024) and `maxReasoningBudget`.
*
* Handle `'none'` before calling this function when the model can disable
* reasoning. Otherwise, `'none'` maps to `minReasoningBudget` with a
* compatibility warning.
*
* @returns The computed token budget.
*/
function mapReasoningToProviderBudget({ reasoning, maxOutputTokens, maxReasoningBudget, minReasoningBudget = 1024, budgetPercentages, warnings }) {
	if (reasoning === "none") {
		warnings.push({
			type: "compatibility",
			feature: "reasoning",
			details: `reasoning "none" is not supported by this model. mapped to the minimum reasoning budget of ${minReasoningBudget} tokens.`
		});
		return minReasoningBudget;
	}
	const percentage = budgetPercentages?.[reasoning] ?? DEFAULT_REASONING_BUDGET_PERCENTAGES[reasoning];
	return Math.min(maxReasoningBudget, Math.max(minReasoningBudget, Math.round(maxOutputTokens * percentage)));
}
//#endregion
//#region src/media-type-to-extension.ts
/**
* Maps a media type to its corresponding file extension.
* It was originally introduced to set a filename for audio file uploads
* in https://github.com/vercel/ai/pull/8159.
*
* @param mediaType The media type to map.
* @returns The corresponding file extension
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/MIME_types/Common_types
*/
function mediaTypeToExtension(mediaType) {
	const [_type, subtype = ""] = mediaType.toLowerCase().split("/");
	return {
		mpeg: "mp3",
		"x-wav": "wav",
		opus: "ogg",
		mp4: "m4a",
		"x-m4a": "m4a"
	}[subtype] ?? subtype;
}
//#endregion
//#region src/normalize-batch-request-counts.ts
/**
* Normalizes complete batch request counts.
*
* Returns `undefined` when any count is missing, is not a non-negative safe
* integer, or when the item counts do not add up to the total.
*/
function normalizeBatchRequestCounts({ total, pending, completed, failed }) {
	if (isNonNegativeSafeInteger(total) && isNonNegativeSafeInteger(pending) && isNonNegativeSafeInteger(completed) && isNonNegativeSafeInteger(failed) && pending + completed + failed === total) return {
		total,
		pending,
		completed,
		failed
	};
}
function isNonNegativeSafeInteger(value) {
	return value != null && Number.isSafeInteger(value) && value >= 0;
}
//#endregion
//#region src/secure-json-parse.ts
const suspectProtoRx = /"(?:_|\\u005[Ff])(?:_|\\u005[Ff])(?:p|\\u0070)(?:r|\\u0072)(?:o|\\u006[Ff])(?:t|\\u0074)(?:o|\\u006[Ff])(?:_|\\u005[Ff])(?:_|\\u005[Ff])"\s*:/;
const 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 {
		return _parse(text);
	}
	try {
		return _parse(text);
	} finally {
		Error.stackTraceLimit = stackTraceLimit;
	}
}
//#endregion
//#region src/add-additional-properties-to-json-schema.ts
/**
* Recursively adds additionalProperties: false to object schemas that do not
* define a schema for their additional properties. This is necessary because
* some providers (e.g. OpenAI) do not support additionalProperties: true.
*/
function addAdditionalPropertiesToJsonSchema(jsonSchema) {
	if (jsonSchema.type === "object" || Array.isArray(jsonSchema.type) && jsonSchema.type.includes("object")) {
		const { additionalProperties } = jsonSchema;
		jsonSchema.additionalProperties = additionalProperties != null && typeof additionalProperties !== "boolean" ? visit(additionalProperties) : false;
		const { properties } = jsonSchema;
		if (properties != null) for (const key of Object.keys(properties)) properties[key] = visit(properties[key]);
	}
	if (jsonSchema.items != null) jsonSchema.items = Array.isArray(jsonSchema.items) ? jsonSchema.items.map(visit) : visit(jsonSchema.items);
	if (jsonSchema.anyOf != null) jsonSchema.anyOf = jsonSchema.anyOf.map(visit);
	if (jsonSchema.allOf != null) jsonSchema.allOf = jsonSchema.allOf.map(visit);
	if (jsonSchema.oneOf != null) jsonSchema.oneOf = jsonSchema.oneOf.map(visit);
	const { definitions } = jsonSchema;
	if (definitions != null) for (const key of Object.keys(definitions)) definitions[key] = visit(definitions[key]);
	return jsonSchema;
}
function visit(def) {
	if (typeof def === "boolean") return def;
	return addAdditionalPropertiesToJsonSchema(def);
}
//#endregion
//#region src/to-json-schema/zod3-to-json-schema/options.ts
const ignoreOverride = Symbol("Let zodToJsonSchema decide on which parser to use");
const 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"
};
const getDefaultOptions = (options) => typeof options === "string" ? {
	...defaultOptions,
	name: options
} : {
	...defaultOptions,
	...options
};
//#endregion
//#region src/to-json-schema/zod3-to-json-schema/parsers/any.ts
function parseAnyDef() {
	return {};
}
//#endregion
//#region src/to-json-schema/zod3-to-json-schema/parsers/array.ts
function parseArrayDef(def, refs) {
	const res = { type: "array" };
	if (def.type?._def && def.type?._def?.typeName !== "ZodAny") res.items = parseDef(def.type._def, {
		...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;
}
//#endregion
//#region src/to-json-schema/zod3-to-json-schema/parsers/bigint.ts
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;
	}
	return res;
}
//#endregion
//#region src/to-json-schema/zod3-to-json-schema/parsers/boolean.ts
function parseBooleanDef() {
	return { type: "boolean" };
}
//#endregion
//#region src/to-json-schema/zod3-to-json-schema/parsers/branded.ts
function parseBrandedDef(_def, refs) {
	return parseDef(_def.type._def, refs);
}
//#endregion
//#region src/to-json-schema/zod3-to-json-schema/parsers/catch.ts
const parseCatchDef = (def, refs) => {
	return parseDef(def.innerType._def, refs);
};
//#endregion
//#region src/to-json-schema/zod3-to-json-schema/parsers/date.ts
function parseDateDef(def, refs, overrideDateStrategy) {
	const strategy = 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);
	}
}
const 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;
	}
	return res;
};
//#endregion
//#region src/to-json-schema/zod3-to-json-schema/parsers/default.ts
function parseDefaultDef(_def, refs) {
	return {
		...parseDef(_def.innerType._def, refs),
		default: _def.defaultValue()
	};
}
//#endregion
//#region src/to-json-schema/zod3-to-json-schema/parsers/effects.ts
function parseEffectsDef(_def, refs) {
	return refs.effectStrategy === "input" ? parseDef(_def.schema._def, refs) : parseAnyDef();
}
//#endregion
//#region src/to-json-schema/zod3-to-json-schema/parsers/enum.ts
function parseEnumDef(def) {
	return {
		type: "string",
		enum: Array.from(def.values)
	};
}
//#endregion
//#region src/to-json-schema/zod3-to-json-schema/parsers/intersection.ts
const 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, {
		...refs,
		currentPath: [
			...refs.currentPath,
			"allOf",
			"0"
		]
	}), parseDef(def.right._def, {
		...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 { additionalProperties: _additionalProperties, ...rest } = schema;
				nestedSchema = rest;
			}
			mergedAllOf.push(nestedSchema);
		}
	});
	return mergedAllOf.length ? { allOf: mergedAllOf } : void 0;
}
//#endregion
//#region src/to-json-schema/zod3-to-json-schema/parsers/literal.ts
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
	};
}
//#endregion
//#region src/to-json-schema/zod3-to-json-schema/parsers/string.ts
let emojiRegex = void 0;
/**
* Generated from the regular expressions found here as of 2024-05-22:
* https://github.com/colinhacks/zod/blob/master/src/types.ts.
*
* Expressions with /i flag have been changed accordingly.
*/
const 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;
		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;
		case "nanoid": addPattern(res, zodPatterns.nanoid, check.message, refs);
	}
	return res;
}
function escapeLiteralCheckValue(literal, refs) {
	return refs.patternStrategy === "escape" ? escapeNonAlphaNumeric(literal) : literal;
}
const ALPHA_NUMERIC = /* @__PURE__ */ 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) {
	if (schema.format || schema.anyOf?.some((x) => x.format)) {
		if (!schema.anyOf) schema.anyOf = [];
		if (schema.format) {
			schema.anyOf.push({ format: schema.format });
			delete schema.format;
		}
		schema.anyOf.push({
			format: value,
			...message && refs.errorMessages && { errorMessage: { format: message } }
		});
	} else schema.format = value;
}
function addPattern(schema, regex, message, refs) {
	if (schema.pattern || schema.allOf?.some((x) => x.pattern)) {
		if (!schema.allOf) schema.allOf = [];
		if (schema.pattern) {
			schema.allOf.push({ pattern: schema.pattern });
			delete schema.pattern;
		}
		schema.allOf.push({
			pattern: stringifyRegExpWithFlags(regex, refs),
			...message && refs.errorMessages && { errorMessage: { pattern: message } }
		});
	} else schema.pattern = stringifyRegExpWithFlags(regex, refs);
}
function stringifyRegExpWithFlags(regex, refs) {
	if (!refs.applyRegexFlags || !regex.flags) return regex.source;
	const flags = {
		i: regex.flags.includes("i"),
		m: regex.flags.includes("m"),
		s: regex.flags.includes("s")
	};
	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] === "-" && source[i + 2]?.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\n]))`;
				continue;
			} else if (source[i] === "$") {
				pattern += `($|(?=[\r\n]))`;
				continue;
			}
		}
		if (flags.s && source[i] === ".") {
			pattern += inCharGroup ? `${source[i]}\r\n` : `[${source[i]}\r\n]`;
			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 {
		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;
}
//#endregion
//#region src/to-json-schema/zod3-to-json-schema/parsers/record.ts
function parseRecordDef(def, refs) {
	const schema = {
		type: "object",
		additionalProperties: parseDef(def.valueType._def, {
			...refs,
			currentPath: [...refs.currentPath, "additionalProperties"]
		}) ?? refs.allowedAdditionalProperties
	};
	if (def.keyType?._def.typeName === "ZodString" && def.keyType._def.checks?.length) {
		const { type: _type, ...keyType } = parseStringDef(def.keyType._def, refs);
		return {
			...schema,
			propertyNames: keyType
		};
	} else if (def.keyType?._def.typeName === "ZodEnum") return {
		...schema,
		propertyNames: { enum: def.keyType._def.values }
	};
	else if (def.keyType?._def.typeName === "ZodBranded" && def.keyType._def.type._def.typeName === "ZodString" && def.keyType._def.type._def.checks?.length) {
		const { type: _type, ...keyType } = parseBrandedDef(def.keyType._def, refs);
		return {
			...schema,
			propertyNames: keyType
		};
	}
	return schema;
}
//#endregion
//#region src/to-json-schema/zod3-to-json-schema/parsers/map.ts
function parseMapDef(def, refs) {
	if (refs.mapStrategy === "record") return parseRecordDef(def, refs);
	return {
		type: "array",
		maxItems: 125,
		items: {
			type: "array",
			items: [parseDef(def.keyType._def, {
				...refs,
				currentPath: [
					...refs.currentPath,
					"items",
					"items",
					"0"
				]
			}) || parseAnyDef(), parseDef(def.valueType._def, {
				...refs,
				currentPath: [
					...refs.currentPath,
					"items",
					"items",
					"1"
				]
			}) || parseAnyDef()],
			minItems: 2,
			maxItems: 2
		}
	};
}
//#endregion
//#region src/to-json-schema/zod3-to-json-schema/parsers/native-enum.ts
function parseNativeEnumDef(def) {
	const object = def.values;
	const actualValues = Object.keys(def.values).filter((key) => {
		return typeof object[object[key]] !== "number";
	}).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
	};
}
//#endregion
//#region src/to-json-schema/zod3-to-json-schema/parsers/never.ts
function parseNeverDef() {
	return { not: parseAnyDef() };
}
//#endregion
//#region src/to-json-schema/zod3-to-json-schema/parsers/null.ts
function parseNullDef() {
	return { type: "null" };
}
//#endregion
//#region src/to-json-schema/zod3-to-json-schema/parsers/union.ts
const 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((types, x) => {
			const type = primitiveMappings[x._def.typeName];
			return type && !types.includes(type) ? [...types, type] : types;
		}, []);
		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"];
				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((x) => !acc.includes(x))], [])
	};
	return asAnyOf(def, refs);
}
const asAnyOf = (def, refs) => {
	const anyOf = (def.options instanceof Map ? Array.from(def.options.values()) : def.options).map((x, i) => parseDef(x._def, {
		...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;
};
//#endregion
//#region src/to-json-schema/zod3-to-json-schema/parsers/nullable.ts
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, {
		...refs,
		currentPath: [
			...refs.currentPath,
			"anyOf",
			"0"
		]
	});
	return base && { anyOf: [base, { type: "null" }] };
}
//#endregion
//#region src/to-json-schema/zod3-to-json-schema/parsers/number.ts
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;
	}
	return res;
}
//#endregion
//#region src/to-json-schema/zod3-to-json-schema/parsers/object.ts
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, {
			...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, {
		...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 {
		return true;
	}
}
//#endregion
//#region src/to-json-schema/zod3-to-json-schema/parsers/optional.ts
const parseOptionalDef = (def, refs) => {
	if (refs.currentPath.toString() === refs.propertyPath?.toString()) return parseDef(def.innerType._def, refs);
	const innerSchema = parseDef(def.innerType._def, {
		...refs,
		currentPath: [
			...refs.currentPath,
			"anyOf",
			"1"
		]
	});
	return innerSchema ? { anyOf: [{ not: parseAnyDef() }, innerSchema] } : parseAnyDef();
};
//#endregion
//#region src/to-json-schema/zod3-to-json-schema/parsers/pipeline.ts
const 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, {
		...refs,
		currentPath: [
			...refs.currentPath,
			"allOf",
			"0"
		]
	});
	return { allOf: [inputSchema, parseDef(def.out._def, {
		...refs,
		currentPath: [
			...refs.currentPath,
			"allOf",
			inputSchema ? "1" : "0"
		]
	})].filter((schema) => schema !== void 0) };
};
//#endregion
//#region src/to-json-schema/zod3-to-json-schema/parsers/promise.ts
function parsePromiseDef(def, refs) {
	return parseDef(def.type._def, refs);
}
//#endregion
//#region src/to-json-schema/zod3-to-json-schema/parsers/set.ts
function parseSetDef(def, refs) {
	const schema = {
		type: "array",
		uniqueItems: true,
		items: parseDef(def.valueType._def, {
			...refs,
			currentPath: [...refs.currentPath, "items"]
		})
	};
	if (def.minSize) schema.minItems = def.minSize.value;
	if (def.maxSize) schema.maxItems = def.maxSize.value;
	return schema;
}
//#endregion
//#region src/to-json-schema/zod3-to-json-schema/parsers/tuple.ts
function parseTupleDef(def, refs) {
	if (def.rest) return {
		type: "array",
		minItems: def.items.length,
		items: def.items.map((x, i) => parseDef(x._def, {
			...refs,
			currentPath: [
				...refs.currentPath,
				"items",
				`${i}`
			]
		})).reduce((acc, x) => x === void 0 ? acc : [...acc, x], []),
		additionalItems: parseDef(def.rest._def, {
			...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, {
			...refs,
			currentPath: [
				...refs.currentPath,
				"items",
				`${i}`
			]
		})).reduce((acc, x) => x === void 0 ? acc : [...acc, x], [])
	};
}
//#endregion
//#region src/to-json-schema/zod3-to-json-schema/parsers/undefined.ts
function parseUndefinedDef() {
	return { not: parseAnyDef() };
}
//#endregion
//#region src/to-json-schema/zod3-to-json-schema/parsers/unknown.ts
function parseUnknownDef() {
	return parseAnyDef();
}
//#endregion
//#region src/to-json-schema/zod3-to-json-schema/parsers/readonly.ts
const parseReadonlyDef = (def, refs) => {
	return parseDef(def.innerType._def, refs);
};
//#endregion
//#region src/to-json-schema/zod3-to-json-schema/select-parser.ts
const 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;
		default:
 /* c8 ignore next */
		return ((_) => void 0)(typeName);
	}
};
//#endregion
//#region src/to-json-schema/zod3-to-json-schema/get-relative-path.ts
const 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("/");
};
//#endregion
//#region src/to-json-schema/zod3-to-json-schema/parse-def.ts
function parseDef(def, refs, forceResolution = false) {
	const seenItem = refs.seen.get(def);
	if (refs.override) {
		const overrideResult = refs.override?.(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 jsonSchema = typeof jsonSchemaOrGetter === "function" ? parseDef(jsonSchemaOrGetter(), refs) : jsonSchemaOrGetter;
	if (jsonSchema) addMeta(def, refs, jsonSchema);
	if (refs.postProcess) {
		const postProcessResult = refs.postProcess(jsonSchema, def, refs);
		newItem.jsonSchema = jsonSchema;
		return postProcessResult;
	}
	newItem.jsonSchema = jsonSchema;
	return jsonSchema;
}
const 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;
	}
};
const addMeta = (def, refs, jsonSchema) => {
	if (def.description) jsonSchema.description = def.description;
	return jsonSchema;
};
//#endregion
//#region src/to-json-schema/zod3-to-json-schema/refs.ts
const getRefs = (options) => {
	const _options = getDefaultOptions(options);
	const currentPath = _options.name !== void 0 ? [
		..._options.basePath,
		_options.definitionPath,
		_options.name
	] : _options.basePath;
	return {
		..._options,
		currentPath,
		propertyPath: void 0,
		seen: new Map(Object.entries(_options.definitions).map(([name, def]) => [def._def, {
			def: def._def,
			path: [
				..._options.basePath,
				_options.definitionPath,
				name
			],
			jsonSchema: void 0
		}]))
	};
};
//#endregion
//#region src/to-json-schema/zod3-to-json-schema/zod3-to-json-schema.ts
const zod3ToJsonSchema = (schema, options) => {
	const refs = getRefs(options);
	let definitions = typeof options === "object" && options.definitions ? Object.entries(options.definitions).reduce((acc, [name, schema]) => ({
		...acc,
		[name]: parseDef(schema._def, {
			...refs,
			currentPath: [
				...refs.basePath,
				refs.definitionPath,
				name
			]
		}, true) ?? parseAnyDef()
	}), {}) : void 0;
	const name = typeof options === "string" ? options : options?.nameStrategy === "title" ? void 0 : options?.name;
	const main = parseDef(schema._def, name === void 0 ? refs : {
		...refs,
		currentPath: [
			...refs.basePath,
			refs.definitionPath,
			name
		]
	}, false) ?? 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 = name === void 0 ? definitions ? {
		...main,
		[refs.definitionPath]: definitions
	} : main : {
		$ref: [
			...refs.$refStrategy === "relative" ? [] : refs.basePath,
			refs.definitionPath,
			name
		].join("/"),
		[refs.definitionPath]: {
			...definitions,
			[name]: main
		}
	};
	combined.$schema = "http://json-schema.org/draft-07/schema#";
	return combined;
};
//#endregion
//#region src/schema.ts
/**
* Used to mark schemas so we can support both Zod and custom schemas.
*/
const schemaSymbol = Symbol.for("vercel.ai.schema");
/**
* Creates a schema with deferred creation.
* This is important to reduce the startup time of the library
* and to avoid initializing unused validators.
*
* @param createValidator A function that creates a schema.
* @returns A function that returns a schema.
*/
function lazySchema(createSchema) {
	let schema;
	return () => {
		if (schema == null) schema = createSchema();
		return schema;
	};
}
/**
* Create a schema using a JSON Schema.
*
* @param jsonSchema The JSON Schema for the schema.
* @param options.validate Optional. A validation function for the schema.
*/
function jsonSchema(jsonSchema, { validate } = {}) {
	return {
		[schemaSymbol]: true,
		_type: void 0,
		get jsonSchema() {
			if (typeof jsonSchema === "function") jsonSchema = jsonSchema();
			return jsonSchema;
		},
		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(standardSchema) {
	return jsonSchema(() => {
		if (!hasStandardJsonSchema(standardSchema)) throw new Error(`Standard schema vendor '${standardSchema["~standard"].vendor}' does not support JSON Schema conversion.`);
		return addAdditionalPropertiesToJsonSchema(standardSchema["~standard"].jsonSchema.input({ target: "draft-07" }));
	}, { validate: async (value) => {
		const result = await standardSchema["~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(zodSchema, options) {
	const useReferences = options?.useReferences ?? false;
	return jsonSchema(() => zod3ToJsonSchema(zodSchema, { $refStrategy: useReferences ? "root" : "none" }), { validate: async (value) => {
		const result = await zodSchema.safeParseAsync(value);
		return result.success ? {
			success: true,
			value: result.data
		} : {
			success: false,
			error: result.error
		};
	} });
}
function zod4Schema(zodSchema, options) {
	if (!config().localeError) config(en());
	const useReferences = options?.useReferences ?? false;
	return jsonSchema(() => addAdditionalPropertiesToJsonSchema(toJSONSchema(zodSchema, {
		target: "draft-7",
		io: "input",
		reused: useReferences ? "ref" : "inline"
	})), { validate: async (value) => {
		const result = await safeParseAsync(zodSchema, value);
		return result.success ? {
			success: true,
			value: result.data
		} : {
			success: false,
			error: result.error
		};
	} });
}
function isZod4Schema(zodSchema) {
	return "_zod" in zodSchema;
}
function zodSchema(zodSchema, options) {
	if (isZod4Schema(zodSchema)) return zod4Schema(zodSchema, options);
	else return zod3Schema(zodSchema, options);
}
//#endregion
//#region src/validate-types.ts
/**
* Validates the types of an unknown object using a schema and
* return a strongly-typed object.
*
* @template T - The type of the object to validate.
* @param {string} options.value - The object to validate.
* @param {Validator<T>} options.schema - The schema to use for validating the JSON.
* @param {TypeValidationContext} options.context - Optional context about what is being validated.
* @returns {Promise<T>} - The typed object.
*/
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;
}
/**
* Safely validates the types of an unknown object using a schema and
* return a strongly-typed object.
*
* @template T - The type of the object to validate.
* @param {string} options.value - The JSON object to validate.
* @param {Validator<T>} options.schema - The schema to use for validating the JSON.
* @param {TypeValidationContext} options.context - Optional context about what is being validated.
* @returns An object with either a `success` flag and the parsed and typed data, or a `success` flag and an error object.
*/
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
		};
	}
}
//#endregion
//#region src/parse-json.ts
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 {
		return false;
	}
}
//#endregion
//#region src/parse-json-event-stream.ts
/**
* Parses a JSON event stream into a stream of parsed JSON objects.
*/
function parseJsonEventStream({ stream, schema }) {
	return stream.pipeThrough(new TextDecoderStream()).pipeThrough(new EventSourceParserStream$1()).pipeThrough(new TransformStream({ async transform({ data }, controller) {
		if (data === "[DONE]") return;
		controller.enqueue(await safeParseJSON({
			text: data,
			schema
		}));
	} }));
}
//#endregion
//#region src/parse-provider-options.ts
async function parseProviderOptions({ provider, providerOptions, schema }) {
	if (providerOptions?.[provider] == null) return;
	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;
}
//#endregion
//#region src/resolve-provider-options.ts
/**
* Parses provider options that a model accepts under more than one
* `providerOptions` namespace, e.g. a canonical key plus a provider-specific
* or legacy alias.
*
* Each present namespace is validated against `schema` exactly like
* `parseProviderOptions` does, so an invalid namespace throws.
*
* @returns the resolved options (`undefined` when no namespace is present)
* and the namespaces that contributed to them, in resolution order.
*/
async function resolveProviderOptions({ providerOptions, namespaces, resolution, schema }) {
	const parsed = [];
	const matched = [];
	for (const namespace of new Set(namespaces)) {
		const options = await parseProviderOptions({
			provider: namespace,
			providerOptions,
			schema
		});
		if (options == null) continue;
		if (resolution === "first") return {
			options,
			namespaces: [namespace]
		};
		parsed.push(options);
		matched.push(namespace);
	}
	return {
		options: parsed.length === 0 ? void 0 : Object.assign({}, ...parsed),
		namespaces: matched
	};
}
//#endregion
//#region src/post-multipart-stream-to-api.ts
const getOriginalFetch$1 = () => globalThis.fetch;
function escapeMultipartHeaderValue(value) {
	return value.replace(/[\r\n]/g, "").replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
}
function createMultipartBody(parts, boundary) {
	const encoder = new TextEncoder();
	let disposed = false;
	let activeReader;
	const enteredStreams = /* @__PURE__ */ new Set();
	async function* emitParts() {
		for (const part of parts) {
			if (disposed) return;
			const disposition = `--${boundary}\r\nContent-Disposition: form-data; name="${escapeMultipartHeaderValue(part.name)}"`;
			if (part.type === "field") {
				yield encoder.encode(`${disposition}\r\n\r\n${part.value}\r\n`);
				continue;
			}
			const filenameParameter = `; filename="${escapeMultipartHeaderValue(part.filename ?? "blob")}"`;
			const mediaType = (part.mediaType ?? "application/octet-stream").replace(/[\r\n]/g, "");
			yield encoder.encode(`${disposition}${filenameParameter}\r\nContent-Type: ${mediaType}\r\n\r\n`);
			if (part.content instanceof Uint8Array) yield part.content;
			else {
				const reader = part.content.getReader();
				activeReader = reader;
				enteredStreams.add(part.content);
				let finished = false;
				try {
					while (true) {
						const { done, value } = await reader.read();
						if (done || disposed) {
							finished = done;
							break;
						}
						yield value;
					}
				} finally {
					activeReader = void 0;
					if (!finished) await reader.cancel().catch(() => {});
					reader.releaseLock();
				}
				if (disposed) return;
			}
			yield encoder.encode("\r\n");
		}
		yield encoder.encode(`--${boundary}--\r\n`);
	}
	return {
		stream: convertAsyncIteratorToReadableStream(emitParts()),
		async dispose(reason) {
			if (disposed) return;
			disposed = true;
			const reader = activeReader;
			if (reader != null) await reader.cancel(reason).catch(() => {});
			for (const part of parts) if (part.type === "file" && !(part.content instanceof Uint8Array) && !enteredStreams.has(part.content)) await part.content.cancel(reason).catch(() => {});
		}
	};
}
/**
* POSTs a multipart/form-data body as a request stream, so file parts backed
* by a `ReadableStream` are sent without buffering the full file in memory.
*
* Requires a fetch implementation that supports streaming request bodies
* (`duplex: 'half'`). Callers with fully buffered payloads can keep using
* `postFormDataToApi`.
*/
const postMultipartStreamToApi = async ({ url, headers = {}, parts, failedResponseHandler, successfulResponseHandler, abortSignal, fetch = getOriginalFetch$1() }) => {
	const boundary = `ai-sdk-multipart-${generateId()}`;
	const requestBodyValues = Object.fromEntries(parts.map((part) => [part.name, part.type === "field" ? part.value : `<file:${part.filename ?? part.name}>`]));
	const body = createMultipartBody(parts, boundary);
	try {
		const response = await fetch(url, {
			method: "POST",
			headers: withUserAgentSuffix({
				...headers,
				"Content-Type": `multipart/form-data; boundary=${boundary}`
			}, `ai-sdk-provider-utils/${VERSION}`, getRuntimeEnvironmentUserAgent()),
			body: body.stream,
			duplex: "half",
			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) {
		await body.dispose(error);
		throw handleFetchError({
			error,
			url,
			requestBodyValues
		});
	}
};
//#endregion
//#region src/post-to-api.ts
const getOriginalFetch = () => globalThis.fetch;
const postJsonToApi = async ({ url, headers, body, failedResponseHandler, successfulResponseHandler, abortSignal, fetch }) => await postToApi({
	url,
	headers: {
		"Content-Type": "application/json",
		...headers
	},
	body: {
		content: JSON.stringify(body),
		values: body
	},
	failedResponseHandler,
	successfulResponseHandler,
	abortSignal,
	fetch
});
const postFormDataToApi = async ({ url, headers, formData, failedResponseHandler, successfulResponseHandler, abortSignal, fetch }) => await postToApi({
	url,
	headers,
	body: {
		content: formData,
		values: Object.fromEntries(formData.entries())
	},
	failedResponseHandler,
	successfulResponseHandler,
	abortSignal,
	fetch
});
const postToApi = async ({ url, headers = {}, body, successfulResponseHandler, failedResponseHandler, abortSignal, fetch = getOriginalFetch() }) => {
	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
		});
	}
};
//#endregion
//#region src/types/tool.ts
function tool(tool) {
	return tool;
}
/**
* Define a dynamic tool.
*/
function dynamicTool(tool) {
	return {
		...tool,
		type: "dynamic"
	};
}
//#endregion
//#region src/telemetry-redaction.ts
const telemetryRedaction = Symbol.for("vercel.ai.telemetry.redact");
/**
* Attach a provider-owned telemetry view without changing the original value.
* The annotation is not serialized or included in enumerable application data.
* Keep the annotated object when forwarding tool arguments or provider metadata.
*/
function withTelemetryRedaction(value, redact) {
	return Object.create(Object.getPrototypeOf(value), {
		...Object.getOwnPropertyDescriptors(value),
		[telemetryRedaction]: {
			value: redact,
			configurable: true
		}
	});
}
/** Apply the provider's telemetry view, leaving unannotated values unchanged. */
function redactTelemetryValue(value) {
	if (value == null || typeof value !== "object") return value;
	const redact = Object.getOwnPropertyDescriptor(value, telemetryRedaction)?.value;
	if (typeof redact !== "function") return value;
	try {
		return redact(value);
	} catch {
		return;
	}
}
//#endregion
//#region src/provider-defined-tool-factory.ts
function createProviderDefinedToolFactory({ id, inputSchema, redactArgs }) {
	return ({ execute, outputSchema, needsApproval, toModelOutput, onInputStart, onInputDelta, onInputAvailable, ...args }) => tool({
		type: "provider",
		isProviderExecuted: false,
		id,
		args: redactArgs == null ? args : withTelemetryRedaction(args, redactArgs),
		inputSchema,
		outputSchema,
		execute,
		needsApproval,
		toModelOutput,
		onInputStart,
		onInputDelta,
		onInputAvailable
	});
}
function createProviderDefinedToolFactoryWithOutputSchema({ id, inputSchema, outputSchema, redactArgs }) {
	return ({ execute, needsApproval, toModelOutput, onInputStart, onInputDelta, onInputAvailable, ...args }) => tool({
		type: "provider",
		isProviderExecuted: false,
		id,
		args: redactArgs == null ? args : withTelemetryRedaction(args, redactArgs),
		inputSchema,
		outputSchema,
		execute,
		needsApproval,
		toModelOutput,
		onInputStart,
		onInputDelta,
		onInputAvailable
	});
}
//#endregion
//#region src/provider-executed-tool-factory.ts
function createProviderExecutedToolFactory({ id, inputSchema, outputSchema, supportsDeferredResults, redactArgs }) {
	return ({ onInputStart, onInputDelta, onInputAvailable, ...args }) => tool({
		type: "provider",
		isProviderExecuted: true,
		id,
		args: redactArgs == null ? args : withTelemetryRedaction(args, redactArgs),
		inputSchema,
		outputSchema,
		onInputStart,
		onInputDelta,
		onInputAvailable,
		supportsDeferredResults
	});
}
//#endregion
//#region src/resolve.ts
/**
* Resolves a value that could be a raw value, a Promise, a function returning a value,
* or a function returning a Promise.
*/
async function resolve(value) {
	if (typeof value === "function") value = value();
	return value;
}
/**
* Resolves and transforms a value, preserving synchronous results. This allows
* synchronous credentials to remain usable by workflow serialization while
* asynchronous credentials are awaited by request handlers.
*/
function resolveWith(value, transform) {
	const resolved = typeof value === "function" ? value() : value;
	if (resolved != null && (typeof resolved === "object" || typeof resolved === "function") && typeof resolved.then === "function") return Promise.resolve(resolved).then(transform);
	return transform(resolved);
}
//#endregion
//#region src/resolve-full-media-type.ts
/**
* Resolves a file part's media type to a full `type/subtype` form required by
* providers whose API demands the full IANA media type.
*
* - If `part.mediaType` is already a full media type (e.g. `image/png`), it is
*   returned as-is.
* - Otherwise, when inline bytes are available (`part.data.type === 'data'`),
*   the subtype is sniffed from the bytes using the signature table that
*   corresponds to the top-level segment.
* - When neither applies (e.g. top-level-only with a URL source, or bytes that
*   cannot be detected), an `UnsupportedFunctionalityError` is thrown.
*/
function resolveFullMediaType({ part }) {
	if (isFullMediaType(part.mediaType)) return part.mediaType;
	if (part.data.type === "data") {
		const detected = detectMediaType({
			data: part.data.data,
			topLevelType: getTopLevelMediaType(part.mediaType)
		});
		if (detected) return detected;
		throw new UnsupportedFunctionalityError({ functionality: `file of media type "${part.mediaType}" must specify subtype since it could not be auto-detected` });
	}
	throw new UnsupportedFunctionalityError({ functionality: `file of media type "${part.mediaType}" must specify subtype since it is not passed as inline bytes` });
}
//#endregion
//#region src/resolve-provider-reference.ts
/**
* Resolves a provider reference to the provider-specific identifier for the
* given provider. Throws `NoSuchProviderReferenceError` if the provider is not
* found in the reference mapping.
*/
function resolveProviderReference({ reference, provider }) {
	const id = reference[provider];
	if (id != null) return id;
	throw new NoSuchProviderReferenceError({
		provider,
		reference
	});
}
//#endregion
//#region src/retry-with-exponential-backoff.ts
/**
* Retries a failed operation with exponential backoff.
*/
const retryWithExponentialBackoff = ({ maxRetries = 2, initialDelayInMs = 2e3, backoffFactor = 2, abortSignal, shouldRetry, getDelayInMs = ({ exponentialBackoffDelay }) => exponentialBackoffDelay, createRetryError = ({ message }) => new Error(message) }) => async (f) => retryWithExponentialBackoffInternal(f, {
	maxRetries,
	delayInMs: initialDelayInMs,
	backoffFactor,
	abortSignal,
	shouldRetry,
	getDelayInMs,
	createRetryError
});
async function retryWithExponentialBackoffInternal(f, { maxRetries, delayInMs, backoffFactor, abortSignal, shouldRetry, getDelayInMs, createRetryError }, errors = []) {
	try {
		return await f();
	} catch (error) {
		if (isAbortError(error)) throw error;
		if (maxRetries === 0) throw error;
		const errorMessage = getErrorMessage(error);
		const newErrors = [...errors, error];
		const tryNumber = newErrors.length;
		if (tryNumber > maxRetries) throw createRetryError({
			message: `Failed after ${tryNumber} attempts. Last error: ${errorMessage}`,
			reason: "maxRetriesExceeded",
			errors: newErrors
		});
		if (await shouldRetry(error) && tryNumber <= maxRetries) {
			await delay(getDelayInMs({
				error,
				exponentialBackoffDelay: delayInMs
			}), { abortSignal });
			return retryWithExponentialBackoffInternal(f, {
				maxRetries,
				delayInMs: backoffFactor * delayInMs,
				backoffFactor,
				abortSignal,
				shouldRetry,
				getDelayInMs,
				createRetryError
			}, newErrors);
		}
		if (tryNumber === 1) throw error;
		throw createRetryError({
			message: `Failed after ${tryNumber} attempts with non-retryable error: '${errorMessage}'`,
			reason: "errorNotRetryable",
			errors: newErrors
		});
	}
}
//#endregion
//#region src/json-binary-field-scanner.ts
/**
* Streaming extraction of large base64 strings from a JSON response body.
*
* A JSON response that carries an image or a file is mostly one very long
* base64 string. The regular pipeline (collect chunks, concatenate, decode to
* text, `JSON.parse`, decode base64) holds about four copies of that string at
* once. The scanner reads the body chunk by chunk instead: strings at the
* configured paths are decoded to bytes while they stream in, and the text that
* is handed to `JSON.parse` (the "skeleton") holds a short placeholder in their
* place.
*
* - The skeleton is the original body except for the extracted strings, so
*   `secureJsonParse` still sees every key (a base64 string cannot contain a
*   quote, so it cannot hide one).
* - A string is extracted only if it is canonical standard-alphabet base64
*   (length divisible by 4, `=` only as the final padding, zero trailing bits,
*   no escape sequences or whitespace). The bytes are then exactly what `atob`
*   gives for it. Everything else stays a string. What was decoded before a
*   string turned out not to qualify is encoded back, which gives the original
*   characters.
*/
/** Strings that decode to fewer bytes stay strings. */
const DEFAULT_BINARY_FIELD_MIN_BYTES = 65536;
const QUOTE = 34;
const BACKSLASH = 92;
const EQUALS = 61;
const COMMA = 44;
const COLON = 58;
const LEFT_BRACE = 123;
const RIGHT_BRACE = 125;
const LEFT_BRACKET = 91;
const RIGHT_BRACKET = 93;
const OUTSIDE = 0;
const KEY = 1;
const SKIP = 2;
const BLOB = 3;
/**
* Compiles paths such as `images[*]` or `content[*].data.data`: plain object
* keys (letters, digits, `_` and `-`) joined by `.`, and `[*]` for every
* element of an array. Keys are compared with the raw bytes of the key in the
* body, so a key written with an escape sequence never matches.
*/
function compileBinaryFieldPaths(paths) {
	const root = /* @__PURE__ */ new Map();
	for (const path of paths) {
		if (!/^(?:[\w-]+|\[\*])(?:\.[\w-]+|\[\*])*$/.test(path)) throw new InvalidArgumentError({
			argument: "experimental_binaryFields",
			message: `Invalid binary field path "${path}"`
		});
		let node = root;
		for (const segment of path.match(/\[\*]|[\w-]+/g)) {
			const edges = segment === "[*]" ? [null] : new TextEncoder().encode(`${segment}"`);
			for (const edge of edges) {
				let next = node.get(edge);
				if (next === void 0) node.set(edge, next = /* @__PURE__ */ new Map());
				node = next;
			}
		}
		node.set(true, node);
	}
	return root;
}
function join(parts, length) {
	const bytes = new Uint8Array(length);
	let at = 0;
	for (const part of parts) {
		bytes.set(part, at);
		at += part.length;
	}
	return bytes;
}
function createJsonBinaryFieldScanner(paths, minBytes = DEFAULT_BINARY_FIELD_MIN_BYTES) {
	const sextet = (/* @__PURE__ */ new Uint8Array(256)).fill(64);
	for (let index = 0; index < 64; index++) sextet["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charCodeAt(index)] = index;
	const encoder = new TextEncoder();
	const pieces = [];
	let piece = /* @__PURE__ */ new Uint8Array(65536);
	let pieceLength = 0;
	let size = 0;
	const binaries = /* @__PURE__ */ new Map();
	const frames = [];
	let skipped = 0;
	let mode = OUTSIDE;
	let escaped = false;
	let last = 0;
	let key;
	let segments = [];
	let segment = /* @__PURE__ */ new Uint8Array(0);
	let at = 0;
	let total = 0;
	let bits = 0;
	let chars = 0;
	let padding = 0;
	const add = (bytes) => {
		for (let offset = 0; offset < bytes.length;) {
			const length = Math.min(piece.length - pieceLength, bytes.length - offset);
			piece.set(bytes.subarray(offset, offset + length), pieceLength);
			pieceLength += length;
			offset += length;
			size += length;
			if (pieceLength === piece.length) {
				pieces.push(piece);
				piece = /* @__PURE__ */ new Uint8Array(65536);
				pieceLength = 0;
			}
		}
	};
	const emit = (chunk, start, end) => add(chunk.subarray(start, end));
	const reset = () => {
		segments = [];
		segment = /* @__PURE__ */ new Uint8Array(0);
		at = 0;
		total = 0;
		bits = 0;
		chars = 0;
		padding = 0;
	};
	const grow = () => {
		if (at > 0) segments.push(segment.subarray(0, at));
		segment = new Uint8Array(Math.min(Math.max(total, 4096), 4 << 20));
		at = 0;
	};
	const rest = () => bits << (4 - chars) * 6;
	const restore = () => {
		for (const part of [...segments, segment.subarray(0, at)]) add(encoder.encode(convertUint8ArrayToBase64(part)));
		const group = rest();
		add(encoder.encode(convertUint8ArrayToBase64(Uint8Array.of(group >> 16, group >> 8, group)).slice(0, chars) + "=".repeat(padding)));
		reset();
	};
	const closeBlob = () => {
		mode = OUTSIDE;
		const tail = chars && chars - 1;
		if (padding === (4 - chars) % 4 && !(bits & (1 << (4 - chars) * 2) - 1) && total + tail >= minBytes) {
			const group = rest();
			const bytes = join([...segments, segment.subarray(0, at)], total + tail);
			for (let index = 0; index < tail; index++) bytes[total + index] = group >> 16 - 8 * index;
			const placeholder = `[binary data: ${bytes.length} bytes; ref ${crypto.getRandomValues(/* @__PURE__ */ new Uint32Array(2)).join("-")}]`;
			binaries.set(placeholder, bytes);
			add(encoder.encode(placeholder));
			reset();
		} else restore();
	};
	const push = (chunk) => {
		let from = 0;
		const { length } = chunk;
		for (let index = 0; index < length; index++) {
			let byte = chunk[index];
			if (mode === BLOB) {
				if (padding === 0) {
					let pending = bits;
					let count = chars;
					for (let value; index < length && (value = sextet[chunk[index]]) < 64; index++) {
						pending = pending << 6 | value;
						if (++count === 4) {
							if (at + 3 > segment.length) grow();
							segment[at++] = pending >> 16;
							segment[at++] = pending >> 8;
							segment[at++] = pending;
							total += 3;
							pending = 0;
							count = 0;
						}
					}
					bits = pending;
					chars = count;
				}
				if (index >= length) break;
				byte = chunk[index];
				if (byte === QUOTE) {
					closeBlob();
					from = index;
				} else if (byte === EQUALS && chars > 1 && padding < 4 - chars) padding++;
				else {
					restore();
					mode = SKIP;
					from = index--;
				}
			} else if (mode !== OUTSIDE) {
				if (mode === KEY) key = key?.get(byte);
				if (escaped) escaped = false;
				else if (byte === BACKSLASH) escaped = true;
				else if (byte === QUOTE) {
					if (mode === KEY) frames.at(-1).next = key;
					mode = OUTSIDE;
				}
			} else if (byte === QUOTE) {
				const frame = frames.at(-1);
				if (skipped > 0) mode = SKIP;
				else if (frame?.keys && (last === LEFT_BRACE || last === COMMA)) {
					mode = KEY;
					key = frame.keys;
				} else if ((frame ? frame.next : paths)?.get(true)) {
					mode = BLOB;
					emit(chunk, from, index + 1);
				} else mode = SKIP;
			} else if (byte === LEFT_BRACE || byte === LEFT_BRACKET) {
				last = byte;
				const frame = frames.at(-1);
				const node = skipped > 0 ? void 0 : frame ? frame.next : paths;
				const items = node?.get(null);
				if (byte === LEFT_BRACE && node) frames.push({ keys: node });
				else if (byte === LEFT_BRACKET && items) frames.push({
					keys: null,
					next: items
				});
				else skipped++;
			} else if (byte === RIGHT_BRACE || byte === RIGHT_BRACKET) {
				if (skipped > 0) skipped--;
				else frames.pop();
			} else if (byte === COMMA || byte === COLON) last = byte;
		}
		if (mode !== BLOB) emit(chunk, from, length);
	};
	const finish = () => {
		if (mode === BLOB) restore();
		return {
			text: new TextDecoder().decode(join([...pieces, piece.subarray(0, pieceLength)], size)),
			binaries
		};
	};
	return {
		push,
		finish
	};
}
/**
* Replaces the placeholders in a parsed value with the bytes they stand for.
* Objects and arrays are copied, the parsed value is not modified. A
* placeholder holds a random number, so a string that equals one is ours.
*/
function replaceBinaryFieldPlaceholders(value, binaries) {
	if (typeof value === "string") return binaries.get(value) ?? value;
	if (Array.isArray(value)) return value.map((item) => replaceBinaryFieldPlaceholders(item, binaries));
	if (value != null && typeof value === "object") return Object.fromEntries(Object.entries(value).map(([name, item]) => [name, replaceBinaryFieldPlaceholders(item, binaries)]));
	return value;
}
/**
* Makes `JSON.stringify` give the placeholder for each of the arrays, instead
* of `{"0":…,"1":…}` with an entry for every byte: 24 MiB of bytes would
* become a string of more than 300 MB. That is what a validator, or the code
* that reports its issues, does with a value it puts into an error message.
* The property is not enumerable, so the arrays look the same otherwise.
* Returns the function that removes it again.
*/
function maskBinariesInJson(binaries) {
	for (const [placeholder, bytes] of binaries) Object.defineProperty(bytes, "toJSON", {
		value: () => placeholder,
		configurable: true
	});
	return () => {
		for (const bytes of binaries.values()) Reflect.deleteProperty(bytes, "toJSON");
	};
}
/**
* Wraps a schema so that it validates the extracted bytes in place of their
* placeholders. The value parsed from the skeleton, and the value of the
* validation error of the response, keep the placeholders: reporting an error
* never prints the bytes.
*
* The errors of the schema itself may hold the bytes: a Standard Schema
* validator wraps the value it was given into an error, and the issues it
* reports may carry the offending input. So that their messages do not grow
* with the image, the arrays stringify as their placeholders, and keep doing
* so as long as an error can refer to them. When the validation succeeds the
* arrays are plain again, for whoever receives them.
*/
function withBinaryFields(schema, binaries) {
	if (binaries.size === 0) return schema;
	const actualSchema = asSchema(schema);
	return jsonSchema({}, { validate: async (value) => {
		const replaced = replaceBinaryFieldPlaceholders(value, binaries);
		const unmask = maskBinariesInJson(binaries);
		const result = actualSchema.validate ? await actualSchema.validate(replaced) : {
			success: true,
			value: replaced
		};
		if (result.success) unmask();
		return result;
	} });
}
//#endregion
//#region src/response-handler.ts
const textDecoder = new TextDecoder();
const DEFAULT_MAX_JSON_LINE_BYTES = 67108864;
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 textDecoder.decode(await readResponseWithSizeLimit({
		response,
		url
	}));
}
const 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?.(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?.(response, parsedError)
			})
		};
	} catch {
		return {
			responseHeaders,
			value: new APICallError({
				message: response.statusText,
				url,
				requestBodyValues,
				statusCode: response.status,
				responseHeaders,
				responseBody,
				isRetryable: isRetryable?.(response)
			})
		};
	}
};
const 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
		})
	};
};
const createJsonResponseHandler = (responseSchema, { experimental_binaryFields } = {}) => {
	const binaryFieldPaths = experimental_binaryFields?.length ? compileBinaryFieldPaths(experimental_binaryFields) : void 0;
	return async ({ response, url, requestBodyValues }) => {
		let responseBody;
		let schema = responseSchema;
		if (binaryFieldPaths == null) responseBody = await readResponseBodyAsText({
			response,
			url
		});
		else {
			const scanner = createJsonBinaryFieldScanner(binaryFieldPaths);
			await readResponseWithSizeLimit({
				response,
				url,
				onChunk: scanner.push
			});
			const scanned = scanner.finish();
			responseBody = scanned.text;
			schema = withBinaryFields(responseSchema, scanned.binaries);
		}
		const parsedResult = await safeParseJSON({
			text: responseBody,
			schema
		});
		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
		};
	};
};
const createJsonLinesResponseHandler = (responseSchema, { maxLineBytes = DEFAULT_MAX_JSON_LINE_BYTES } = {}) => {
	if (!Number.isSafeInteger(maxLineBytes) || maxLineBytes <= 0) throw new InvalidArgumentError({
		argument: "maxLineBytes",
		message: "maxLineBytes must be a positive safe integer."
	});
	return async ({ response, url }) => {
		const responseHeaders = extractResponseHeaders(response);
		if (response.body == null) throw new EmptyResponseBodyError({});
		return {
			responseHeaders,
			value: parseJsonLines({
				stream: response.body,
				schema: responseSchema,
				url,
				maxLineBytes
			})
		};
	};
};
async function* parseJsonLines({ stream, schema, url, maxLineBytes }) {
	const reader = stream.getReader();
	const decoder = new TextDecoder();
	let buffer = "";
	let lineBytes = 0;
	let finished = false;
	try {
		while (true) {
			const { done, value } = await reader.read();
			if (done) {
				finished = true;
				buffer += decoder.decode();
				break;
			}
			let offset = 0;
			while (offset < value.length) {
				const lineEnd = value.indexOf(10, offset);
				const segmentEnd = lineEnd === -1 ? value.length : lineEnd;
				lineBytes += segmentEnd - offset;
				if (lineBytes > maxLineBytes) throw new DownloadError({
					message: `JSON Lines response exceeded maximum line size of ${maxLineBytes} bytes.`,
					url
				});
				const decodeEnd = lineEnd === -1 ? segmentEnd : lineEnd + 1;
				buffer += decoder.decode(value.subarray(offset, decodeEnd), { stream: true });
				if (lineEnd === -1) break;
				const line = buffer.slice(0, -1).replace(/\r$/, "");
				buffer = "";
				lineBytes = 0;
				offset = decodeEnd;
				if (line.trim().length > 0) yield await parseJSON({
					text: line,
					schema
				});
			}
		}
		const finalLine = buffer.replace(/\r$/, "");
		if (finalLine.trim().length > 0) yield await parseJSON({
			text: finalLine,
			schema
		});
	} finally {
		if (!finished) await reader.cancel().catch(() => {});
		reader.releaseLock();
	}
}
const createBinaryResponseHandler = () => async ({ response, url, requestBodyValues }) => {
	const responseHeaders = extractResponseHeaders(response);
	if (!response.body) throw new APICallError({
		message: "Response body is empty",
		url,
		requestBodyValues,
		statusCode: response.status,
		responseHeaders,
		responseBody: void 0
	});
	try {
		const buffer = await response.arrayBuffer();
		return {
			responseHeaders,
			value: new Uint8Array(buffer)
		};
	} catch (error) {
		throw new APICallError({
			message: "Failed to read response as array buffer",
			url,
			requestBodyValues,
			statusCode: response.status,
			responseHeaders,
			responseBody: void 0,
			cause: error
		});
	}
};
/**
* Passes the response body through as a `ReadableStream<Uint8Array>` without
* buffering it (unlike `createBinaryResponseHandler`). The consumer is
* responsible for draining or cancelling the stream.
*/
const createBinaryStreamResponseHandler = () => async ({ response, url, requestBodyValues }) => {
	const responseHeaders = extractResponseHeaders(response);
	if (response.body == null) throw new EmptyResponseBodyError({});
	return {
		responseHeaders,
		value: wrapResponseBodyStream({
			stream: response.body,
			url,
			requestBodyValues,
			statusCode: response.status,
			responseHeaders
		})
	};
};
const createStatusCodeErrorResponseHandler = () => async ({ response, url, requestBodyValues }) => {
	const responseHeaders = extractResponseHeaders(response);
	const responseBody = await readResponseBodyAsText({
		response,
		url
	});
	return {
		responseHeaders,
		value: new APICallError({
			message: response.statusText,
			url,
			requestBodyValues,
			statusCode: response.status,
			responseHeaders,
			responseBody
		})
	};
};
//#endregion
//#region src/is-json-serializable.ts
/**
* Checks whether a value can cross a workflow serialization boundary.
*
* The check accepts JSON-like primitives, arrays, and plain objects whose
* nested values are also serializable. It rejects functions, symbols,
* bigints, and non-plain objects such as class instances, dates, and regexes.
*/
function isJSONSerializable(value) {
	if (value === null || value === void 0) return true;
	const type = typeof value;
	if (type === "string" || type === "number" || type === "boolean") return true;
	if (type === "function" || type === "symbol" || type === "bigint") return false;
	if (Array.isArray(value)) return value.every(isJSONSerializable);
	if (Object.getPrototypeOf(value) === Object.prototype) return Object.values(value).every(isJSONSerializable);
	return false;
}
//#endregion
//#region src/serialization-error.ts
const name = "AI_SerializationError";
const marker = `vercel.ai.error.${name}`;
const symbol = Symbol.for(marker);
var SerializationError = class extends AISDKError {
	constructor({ message = "Failed to serialize value.", cause } = {}) {
		super({
			name,
			message,
			cause
		});
		this[symbol] = true;
	}
	static isInstance(error) {
		return AISDKError.hasMarker(error, marker);
	}
};
//#endregion
//#region src/serialize-model-options.ts
/**
* Serializes a model instance for workflow step boundaries.
* Returns the `modelId` plus the JSON-serializable config properties.
*
* Non-serializable values are omitted. As a special case, a
* function-valued `headers` property is resolved during serialization
* and included if the returned value is JSON-serializable.
*
* Used as the body of `static [WORKFLOW_SERIALIZE]` in provider models.
*
* @example
* ```ts
* static [WORKFLOW_SERIALIZE](model: MyLanguageModel) {
*   return serializeModelOptions({
*     modelId: model.modelId,
*     config: model.config,
*   });
* }
* ```
*/
function serializeModelOptions(options) {
	const serializableConfig = {};
	for (const [key, value] of Object.entries(options.config)) if (key === "headers") {
		const resolvedHeaders = resolveSync(value);
		if (isJSONSerializable(resolvedHeaders)) serializableConfig[key] = resolvedHeaders;
	} else if (isJSONSerializable(value)) serializableConfig[key] = value;
	return {
		modelId: options.modelId,
		config: serializableConfig
	};
}
function resolveSync(value) {
	let next = value;
	if (typeof value === "function") next = value();
	if (next instanceof Promise) throw new SerializationError({ message: "Cannot serialize asynchronous model options." });
	return next;
}
//#endregion
//#region src/speech-stream-envelope.ts
/**
* Experimental speech-stream WebSocket envelope (v1): the standard
* serialization of `Experimental_StreamingSpeechModelV4.doStream` over a WebSocket. Clients (e.g.
* the `@ai-sdk/gateway` provider) encode with this module and servers (e.g.
* AI Gateway) decode with it, so the two sides cannot drift.
*
* Envelope rules:
*
* 1. The client sends exactly one `speech-stream.start` TEXT frame first.
* 2. Input text rides `speech-stream.text-delta` TEXT frames, in order. A
*    frame may carry its text part's `voice` and `providerOptions`. A long
*    part may span several frames: `voice` is repeated on each, and
*    `providerOptions` appear on the first only, so they must describe an
*    event at the start of the part (e.g. a turn break), not a setting. An
*    empty `delta` is valid and carries only part metadata; it does not end
*    the input.
* 3. The client signals the end of the input text with the
*    `speech-stream.text-done` TEXT frame; a plain close without it is an
*    abort.
* 4. Every server→client TEXT frame is one JSON-serialized
*    `SpeechModelV4StreamPart` (flattened, no wrapper). `audio` payloads are
*    base64 strings. `Date` values (`response-metadata.timestamp`) serialize
*    to ISO 8601 strings and are revived by `parseSpeechStreamPart`. `Error`
*    payloads in `error` parts serialize as `{ name, message }`; servers may
*    instead send `{ type, message }`, where `type` names an error class the
*    client can map to a typed error (e.g. `invalid_request_error`).
* 5. The server closes with code 1000 after the `finish` part. Over this
*    envelope an `error` part is terminal: the server sends it on failure and
*    then closes non-1000. A close without a prior `finish` is an error.
* 6. Unknown frame/part types are ignored in both directions (forward
*    compatibility).
* 7. Servers may enforce a maximum frame size (the AI Gateway rejects frames
*    over 256 KiB); clients should keep text-delta frames under 64 KiB.
* 8. Connection establishment (URL, auth) is transport-specific and out of
*    scope.
*
* The envelope validates frame shape only; server policy layers on top. Both
* parsers use `secureJsonParse`, so frames carrying `__proto__` /
* `constructor.prototype` keys are rejected rather than parsed.
*/
/** Type of the first client TEXT frame. */
const SPEECH_STREAM_START_FRAME_TYPE = "speech-stream.start";
/** Type of the client TEXT frame that carries one input text delta. */
const SPEECH_STREAM_TEXT_DELTA_FRAME_TYPE = "speech-stream.text-delta";
/** Type of the client TEXT frame that signals the end of the input text. */
const SPEECH_STREAM_TEXT_DONE_FRAME_TYPE = "speech-stream.text-done";
const optionalStartFrameFields = {
	instructions: "string",
	language: "string",
	speed: "number",
	voice: "string",
	includeRawChunks: "boolean"
};
/**
* Server-side: parse a client TEXT frame. Validates envelope shape only and
* rejects prototype-pollution payloads. Never throws.
*/
function parseSpeechStreamClientFrame(text) {
	let value;
	try {
		value = secureJsonParse(text);
	} catch {
		return {
			type: "invalid",
			message: "malformed JSON"
		};
	}
	if (!isRecord(value)) return {
		type: "invalid",
		message: "frame must be a JSON object"
	};
	if (typeof value.type !== "string") return {
		type: "invalid",
		message: "frame type must be a string"
	};
	switch (value.type) {
		case SPEECH_STREAM_START_FRAME_TYPE: {
			for (const [field, type] of Object.entries(optionalStartFrameFields)) if (value[field] !== void 0 && typeof value[field] !== type) return {
				type: "invalid",
				message: `${field} must be a ${type} when present`
			};
			if (value.outputFormat !== void 0 && !isAudioFormat(value.outputFormat)) return {
				type: "invalid",
				message: "outputFormat must be an audio format object ({ type, rate? }) when present"
			};
			if (value.providerOptions !== void 0 && !isProviderOptions(value.providerOptions)) return {
				type: "invalid",
				message: "providerOptions must be an object of provider objects when present"
			};
			const frame = { type: SPEECH_STREAM_START_FRAME_TYPE };
			for (const field of Object.keys(optionalStartFrameFields)) if (value[field] !== void 0) frame[field] = value[field];
			if (value.outputFormat !== void 0) {
				const { type, rate } = value.outputFormat;
				frame.outputFormat = {
					type,
					...rate !== void 0 && { rate }
				};
			}
			if (value.providerOptions !== void 0) frame.providerOptions = value.providerOptions;
			return {
				type: "start",
				frame
			};
		}
		case SPEECH_STREAM_TEXT_DELTA_FRAME_TYPE:
			if (typeof value.delta !== "string") return {
				type: "invalid",
				message: "text-delta frame must have a string delta"
			};
			if (value.voice !== void 0 && typeof value.voice !== "string") return {
				type: "invalid",
				message: "text-delta voice must be a string when present"
			};
			if (value.providerOptions !== void 0 && !isProviderOptions(value.providerOptions)) return {
				type: "invalid",
				message: "text-delta providerOptions must be an object of provider objects when present"
			};
			return {
				type: "text-delta",
				delta: value.delta,
				...value.voice !== void 0 && { voice: value.voice },
				...value.providerOptions !== void 0 && { providerOptions: value.providerOptions }
			};
		case SPEECH_STREAM_TEXT_DONE_FRAME_TYPE: return { type: "text-done" };
		default: return { type: "unknown" };
	}
}
/**
* Server-side: serialize a speech stream part as one TEXT frame. Binary audio
* is base64-encoded and `Error` payloads serialize as `{ name, message }`.
* Returns `undefined` for payloads that are not JSON-serializable; callers
* drop the frame.
*/
function serializeSpeechStreamPart(part) {
	try {
		if (part.type === "audio" && part.audio instanceof Uint8Array) return JSON.stringify({
			...part,
			audio: convertUint8ArrayToBase64(part.audio)
		});
		if (part.type === "error" && isError$1(part.error)) return JSON.stringify({
			...part,
			error: {
				name: part.error.name,
				message: part.error.message
			}
		});
		return JSON.stringify(part);
	} catch {
		return;
	}
}
function isError$1(value) {
	return value instanceof Error || Object.prototype.toString.call(value) === "[object Error]";
}
/**
* Client-side: parse a server TEXT frame into a speech stream part. Returns
* `undefined` for malformed or unsafe JSON, unknown part types, and known
* part types whose fields are missing or mistyped. Revives
* `response-metadata.timestamp` to a `Date`.
*/
function parseSpeechStreamPart(text) {
	let value;
	try {
		value = secureJsonParse(text);
	} catch {
		return;
	}
	if (!isRecord(value)) return;
	const part = value;
	switch (part.type) {
		case "stream-start": {
			if (!Array.isArray(part.warnings)) return;
			const warnings = part.warnings.filter((warning) => !isUnknownWarningType(warning));
			return warnings.every(isWarning$1) ? {
				...part,
				warnings
			} : void 0;
		}
		case "audio": return isString$1(part.audio) && isAudioFormat(part.audioFormat) && isOptional$1(part.id, isString$1) && isOptional$1(part.providerMetadata, isRecord) ? part : void 0;
		case "finish": return isOptional$1(part.usage, isUsage) && isOptional$1(part.providerMetadata, isRecord) ? part : void 0;
		case "response-metadata": {
			if (!(isOptional$1(part.modelId, isString$1) && isOptional$1(part.headers, isRecord))) return;
			const timestamp = part.timestamp;
			if (timestamp == null) return {
				...part,
				timestamp: void 0
			};
			if (typeof timestamp !== "string") return;
			const revived = new Date(timestamp);
			return Number.isNaN(revived.getTime()) ? void 0 : {
				...part,
				timestamp: revived
			};
		}
		case "raw": return "rawValue" in part ? part : void 0;
		case "error": return "error" in part ? part : void 0;
		default: return;
	}
}
function isString$1(value) {
	return typeof value === "string";
}
function isOptional$1(value, check) {
	return value === void 0 || check(value);
}
const knownWarningTypes = /* @__PURE__ */ new Set([
	"compatibility",
	"deprecated",
	"other",
	"unsupported"
]);
function isUnknownWarningType(value) {
	return isRecord(value) && isString$1(value.type) && !knownWarningTypes.has(value.type);
}
function isWarning$1(value) {
	if (!isRecord(value)) return false;
	switch (value.type) {
		case "compatibility":
		case "unsupported": return isString$1(value.feature) && isOptional$1(value.details, isString$1);
		case "deprecated": return isString$1(value.setting) && isString$1(value.message);
		case "other": return isString$1(value.message);
		default: return false;
	}
}
function isProviderOptions(value) {
	return isRecord(value) && Object.values(value).every(isRecord);
}
function isAudioFormat(value) {
	return isRecord(value) && isString$1(value.type) && value.type.length > 0 && isOptional$1(value.rate, (rate) => typeof rate === "number" && Number.isFinite(rate) && rate > 0);
}
function isUsage(value) {
	return isRecord(value) && [
		"inputCharacters",
		"inputTokens",
		"outputTokens"
	].every((key) => isOptional$1(value[key], (count) => typeof count === "number"));
}
//#endregion
//#region src/streaming-tool-call-argument-state.ts
function startsWithStructuredValue(value) {
	if (typeof value !== "string") return false;
	const firstCharacter = value.trimStart()[0];
	return firstCharacter === "{" || firstCharacter === "[";
}
/**
* Incrementally tracks whether streamed tool-call arguments contain a complete
* structured JSON value. This is intentionally structural rather than a JSON
* parse: a currently parsable scalar can still be the prefix of a later value.
*/
var StreamingToolCallArgumentState = class {
	constructor(initialValue = "") {
		this.structure = { kind: "undetermined" };
		this.append(initialValue);
	}
	get hasCompleteStructuredValue() {
		return this.structure.kind === "structured" && this.structure.complete === true;
	}
	append(delta) {
		let nextStructure = this.structure;
		for (const character of delta) {
			if (nextStructure.kind === "undetermined") {
				if (/\s/.test(character)) continue;
				if (character !== "{" && character !== "[") {
					nextStructure = { kind: "other" };
					continue;
				}
				nextStructure = {
					kind: "structured",
					stack: [character],
					inString: false,
					escaped: false,
					complete: false
				};
				continue;
			}
			if (nextStructure.kind !== "structured" || nextStructure.complete) continue;
			if (nextStructure.inString) {
				if (nextStructure.escaped) nextStructure.escaped = false;
				else if (character === "\\") nextStructure.escaped = true;
				else if (character === "\"") nextStructure.inString = false;
				continue;
			}
			if (character === "\"") nextStructure.inString = true;
			else if (character === "{" || character === "[") nextStructure.stack.push(character);
			else if (character === "}" || character === "]") {
				const expectedOpening = character === "}" ? "{" : "[";
				if (nextStructure.stack.at(-1) !== expectedOpening) {
					nextStructure = { kind: "other" };
					continue;
				}
				nextStructure.stack.pop();
				if (nextStructure.stack.length === 0) nextStructure.complete = true;
			}
		}
		this.structure = nextStructure;
	}
};
//#endregion
//#region src/streaming-tool-call-tracker.ts
/**
* Tracks streaming tool call state across multiple deltas from an
* OpenAI-compatible chat completion stream. Handles argument accumulation,
* emits tool-input-start/delta/end and tool-call events, and finalizes
* unfinished tool calls on flush.
*
* Used by openai, openai-compatible, groq, deepseek, alibaba, mistral, and
* moonshotai providers.
*/
var StreamingToolCallTracker = class {
	constructor(controller, options = {}) {
		this.toolCalls = [];
		this.toolCallsById = /* @__PURE__ */ new Map();
		this.toolCallsByIndex = /* @__PURE__ */ new Map();
		this.usedToolCallIds = /* @__PURE__ */ new Set();
		this.nextGeneratedIdSuffixes = /* @__PURE__ */ new Map();
		this.controller = controller;
		this._generateId = options.generateId ?? generateId;
		this.typeValidation = options.typeValidation ?? "none";
		this.extractMetadata = options.extractMetadata;
		this.buildToolCallProviderMetadata = options.buildToolCallProviderMetadata;
	}
	/**
	* Process a tool call delta from a streaming response chunk.
	* Emits tool-input-start, tool-input-delta, tool-input-end, and tool-call
	* events as appropriate.
	*/
	processDelta(toolCallDelta) {
		const wireName = toolCallDelta.function?.name;
		const hasBlankName = typeof wireName === "string" && wireName.trim().length === 0;
		const wireId = this.getNonBlankString(toolCallDelta.id);
		const name = this.getNonBlankString(wireName);
		const argumentsDelta = toolCallDelta.function?.arguments;
		const { index } = toolCallDelta;
		const resolution = this.resolveToolCall({
			wireId,
			index,
			name,
			hasExplicitCallStart: name != null && startsWithStructuredValue(argumentsDelta),
			hasEmptyArguments: argumentsDelta == null || argumentsDelta.trim().length === 0
		});
		if (resolution.kind === "ambiguous") return;
		let toolCall;
		if (resolution.kind === "new") {
			if (hasBlankName) return;
			toolCall = this.processNewToolCall(toolCallDelta, {
				wireId,
				index,
				name
			});
		} else {
			toolCall = resolution.toolCall;
			if (wireId != null) this.associateWireId(toolCall, wireId);
			this.processExistingToolCall(toolCall, toolCallDelta);
		}
		if (index != null) this.associateIndex(toolCall, index);
	}
	/**
	* Finalize any unfinished tool calls. Should be called during the stream's
	* flush handler to ensure all tool calls are properly completed.
	*/
	flush() {
		const toolCalls = this.toolCalls.every((toolCall) => toolCall.index != null) ? [...this.toolCalls].sort((a, b) => a.index - b.index || a.sequence - b.sequence) : this.toolCalls;
		for (const toolCall of toolCalls) if (!toolCall.hasFinished) this.finishToolCall(toolCall);
	}
	/**
	* Correlation precedence for streamed deltas:
	*
	* | ID evidence | index/name evidence | start evidence | resolution |
	* | --- | --- | --- | --- |
	* | known | matching | any | matching call, new call, or ambiguity |
	* | known | conflicting | named | new call |
	* | unseen | matching | structured start | new call |
	* | unseen | matching | named empty arguments | incomplete call, new call, or ambiguity |
	* | unseen | matching | continuation | matching call or ambiguity |
	* | absent | matching | any | matching call, new call, or ambiguity |
	* | absent | absent | named | new call |
	* | absent | absent | unnamed | sole unfinished call, new call, or ambiguity |
	*/
	resolveToolCall({ wireId, index, name, hasExplicitCallStart, hasEmptyArguments }) {
		const indexedToolCalls = index != null ? this.toolCallsByIndex.get(index) : void 0;
		const matchingIndexedToolCalls = this.filterToolCallsByName(indexedToolCalls, name);
		if (wireId != null) {
			const toolCallsWithId = this.toolCallsById.get(wireId);
			if (toolCallsWithId != null) {
				if (index != null) {
					const matchingToolCalls = matchingIndexedToolCalls.filter((toolCall) => toolCallsWithId.has(toolCall));
					const matchingToolCall = this.resolveMatchingToolCall(matchingToolCalls, hasExplicitCallStart);
					if (matchingToolCall.kind !== "new") return matchingToolCall;
					if (name != null) return { kind: "new" };
					if (indexedToolCalls != null) return { kind: "ambiguous" };
					return this.resolveMatchingToolCall([...toolCallsWithId], false);
				}
				if (name != null) {
					const matchingToolCalls = [...toolCallsWithId].filter((toolCall) => toolCall.function.name === name);
					return this.resolveMatchingToolCall(matchingToolCalls, hasExplicitCallStart);
				}
				return this.resolveMatchingToolCall([...toolCallsWithId], false);
			}
			if (matchingIndexedToolCalls.length > 0) return hasExplicitCallStart ? { kind: "new" } : this.resolveMatchingToolCall(matchingIndexedToolCalls, name != null && hasEmptyArguments);
			return { kind: "new" };
		}
		if (indexedToolCalls != null) return this.resolveMatchingToolCall(matchingIndexedToolCalls, hasExplicitCallStart);
		if (name != null) return { kind: "new" };
		const unfinishedToolCalls = this.toolCalls.filter((toolCall) => !toolCall.hasFinished);
		return this.resolveMatchingToolCall(unfinishedToolCalls, false);
	}
	filterToolCallsByName(toolCalls, name) {
		if (toolCalls == null) return [];
		return [...toolCalls].filter((toolCall) => name == null || toolCall.function.name === name);
	}
	resolveMatchingToolCall(toolCalls, hasExplicitCallStart) {
		if (toolCalls.length === 0) return { kind: "new" };
		const continuableToolCalls = toolCalls.filter((toolCall) => !toolCall.argumentState.hasCompleteStructuredValue);
		if (!hasExplicitCallStart && toolCalls.length === 1) return {
			kind: "existing",
			toolCall: toolCalls[0]
		};
		if (continuableToolCalls.length === 1) return {
			kind: "existing",
			toolCall: continuableToolCalls[0]
		};
		if (continuableToolCalls.length > 1 || !hasExplicitCallStart) return { kind: "ambiguous" };
		return { kind: "new" };
	}
	processNewToolCall(toolCallDelta, { wireId, index, name }) {
		if (this.typeValidation === "required") {
			if (toolCallDelta.type !== "function") throw new InvalidResponseDataError({
				data: toolCallDelta,
				message: `Expected 'function' type.`
			});
		} else if (this.typeValidation === "if-present") {
			if (toolCallDelta.type != null && toolCallDelta.type !== "function") throw new InvalidResponseDataError({
				data: toolCallDelta,
				message: `Expected 'function' type.`
			});
		}
		if (name == null) throw new InvalidResponseDataError({
			data: toolCallDelta,
			message: `Expected 'function.name' to be a string.`
		});
		const id = this.createToolCallId(wireId);
		this.controller.enqueue({
			type: "tool-input-start",
			id,
			toolName: name
		});
		const metadata = this.extractMetadata?.(toolCallDelta);
		const initialArguments = toolCallDelta.function?.arguments ?? "";
		const toolCall = {
			id,
			index: index ?? void 0,
			sequence: this.toolCalls.length,
			type: "function",
			function: {
				name,
				arguments: initialArguments
			},
			argumentState: new StreamingToolCallArgumentState(initialArguments),
			hasFinished: false,
			metadata
		};
		this.toolCalls.push(toolCall);
		if (wireId != null) this.associateWireId(toolCall, wireId);
		if (toolCall.function.arguments.length > 0) this.controller.enqueue({
			type: "tool-input-delta",
			id: toolCall.id,
			delta: toolCall.function.arguments
		});
		return toolCall;
	}
	associateWireId(toolCall, wireId) {
		let toolCallsWithId = this.toolCallsById.get(wireId);
		if (toolCallsWithId == null) {
			toolCallsWithId = /* @__PURE__ */ new Set();
			this.toolCallsById.set(wireId, toolCallsWithId);
		}
		toolCallsWithId.add(toolCall);
	}
	associateIndex(toolCall, index) {
		let toolCallsWithIndex = this.toolCallsByIndex.get(index);
		if (toolCallsWithIndex == null) {
			toolCallsWithIndex = /* @__PURE__ */ new Set();
			this.toolCallsByIndex.set(index, toolCallsWithIndex);
		}
		toolCallsWithIndex.add(toolCall);
	}
	createToolCallId(wireId) {
		if (wireId != null && !this.usedToolCallIds.has(wireId)) {
			this.usedToolCallIds.add(wireId);
			return wireId;
		}
		const generatedId = this.getNonBlankString(this._generateId()) ?? "tool-call";
		if (!this.usedToolCallIds.has(generatedId)) {
			this.usedToolCallIds.add(generatedId);
			return generatedId;
		}
		const initialSuffix = this.nextGeneratedIdSuffixes.get(generatedId) ?? 1;
		const maximumSuffix = initialSuffix + this.usedToolCallIds.size;
		for (let suffix = initialSuffix; suffix <= maximumSuffix; suffix++) {
			const suffixedId = `${generatedId}-${suffix}`;
			if (!this.usedToolCallIds.has(suffixedId)) {
				this.usedToolCallIds.add(suffixedId);
				this.nextGeneratedIdSuffixes.set(generatedId, suffix + 1);
				return suffixedId;
			}
		}
		throw new Error("Failed to create a unique tool call ID.");
	}
	getNonBlankString(value) {
		return value != null && value.trim().length > 0 ? value : void 0;
	}
	processExistingToolCall(toolCall, toolCallDelta) {
		if (toolCall.hasFinished) return;
		if (toolCallDelta.function?.arguments != null) {
			toolCall.argumentState.append(toolCallDelta.function.arguments);
			toolCall.function.arguments += toolCallDelta.function.arguments;
			this.controller.enqueue({
				type: "tool-input-delta",
				id: toolCall.id,
				delta: toolCallDelta.function.arguments
			});
		}
	}
	finishToolCall(toolCall) {
		this.controller.enqueue({
			type: "tool-input-end",
			id: toolCall.id
		});
		const providerMetadata = this.buildToolCallProviderMetadata?.(toolCall.metadata);
		this.controller.enqueue({
			type: "tool-call",
			toolCallId: toolCall.id,
			toolName: toolCall.function.name,
			input: toolCall.function.arguments,
			...providerMetadata ? { providerMetadata } : {}
		});
		toolCall.hasFinished = true;
	}
};
//#endregion
//#region src/strip-file-extension.ts
/**
* Strips file extension segments from a filename.
*
* Examples:
* - "report.pdf" -> "report"
* - "archive.tar.gz" -> "archive"
* - "filename" -> "filename"
*/
function stripFileExtension(filename) {
	const firstDotIndex = filename.indexOf(".");
	return firstDotIndex === -1 ? filename : filename.slice(0, firstDotIndex);
}
//#endregion
//#region src/transcription-stream-envelope.ts
/**
* Experimental transcription-stream WebSocket envelope (v1): the standard
* serialization of `TranscriptionModelV4.doStream` over a WebSocket. Clients
* (e.g. the `@ai-sdk/gateway` provider) encode with this module and servers
* (e.g. AI Gateway) decode with it, so the two sides cannot drift.
*
* Envelope rules:
*
* 1. The client sends exactly one `transcription-stream.start` TEXT frame
*    first.
* 2. Audio rides BINARY frames containing raw bytes in the declared
*    `inputAudioFormat` (base64 string chunks are decoded before sending).
* 3. The client signals end of audio with the
*    `transcription-stream.audio-done` TEXT frame; a plain close without it
*    is an abort.
* 4. Every server→client TEXT frame is one JSON-serialized
*    `TranscriptionModelV4StreamPart` (flattened, no wrapper). Payloads must
*    be JSON-serializable. `Date` values (`response-metadata.timestamp`)
*    serialize to ISO 8601 strings and are revived by
*    `parseTranscriptionStreamPart`. `Error` payloads in `error` parts
*    serialize as `{ name, message }`.
* 5. The server closes with code 1000 after the `finish` part; on failure it
*    sends an `error` part and closes non-1000. A close without a prior
*    `finish` is an error.
* 6. Unknown frame/part types are ignored in both directions (forward
*    compatibility).
* 7. Servers may enforce a maximum frame size (the AI Gateway rejects frames
*    over 256 KiB); clients should split audio into frames of at most
*    64 KiB.
* 8. Connection establishment (URL, auth) is transport-specific and out of
*    scope.
*
* The envelope validates frame shape only; server policy (accepted audio
* formats, required `rate`, size limits) layers on top. Both parsers use
* `secureJsonParse`, so frames carrying `__proto__` / `constructor.prototype`
* keys are rejected (prototype-pollution protection) rather than parsed.
*/
/** Type of the first client TEXT frame. */
const TRANSCRIPTION_STREAM_START_FRAME_TYPE = "transcription-stream.start";
/** Type of the client TEXT frame that signals the end of the audio input. */
const TRANSCRIPTION_STREAM_AUDIO_DONE_FRAME_TYPE = "transcription-stream.audio-done";
/**
* Server-side: parse a client TEXT frame. Validates envelope shape only and
* rejects prototype-pollution payloads (parsed with `secureJsonParse`). Never
* throws.
*/
function parseTranscriptionStreamClientFrame(text) {
	let value;
	try {
		value = secureJsonParse(text);
	} catch {
		return {
			type: "invalid",
			message: "malformed JSON"
		};
	}
	if (value == null || typeof value !== "object" || Array.isArray(value)) return {
		type: "invalid",
		message: "frame must be a JSON object"
	};
	const frame = value;
	if (typeof frame.type !== "string") return {
		type: "invalid",
		message: "frame type must be a string"
	};
	switch (frame.type) {
		case TRANSCRIPTION_STREAM_START_FRAME_TYPE: {
			const inputAudioFormat = frame.inputAudioFormat;
			if (inputAudioFormat == null || typeof inputAudioFormat !== "object" || Array.isArray(inputAudioFormat) || typeof inputAudioFormat.type !== "string") return {
				type: "invalid",
				message: "start frame must have an inputAudioFormat object with a string type"
			};
			if (inputAudioFormat.rate !== void 0 && typeof inputAudioFormat.rate !== "number") return {
				type: "invalid",
				message: "inputAudioFormat.rate must be a number when present"
			};
			if (frame.providerOptions !== void 0 && (frame.providerOptions == null || typeof frame.providerOptions !== "object" || Array.isArray(frame.providerOptions))) return {
				type: "invalid",
				message: "providerOptions must be an object when present"
			};
			if (frame.includeRawChunks !== void 0 && typeof frame.includeRawChunks !== "boolean") return {
				type: "invalid",
				message: "includeRawChunks must be a boolean when present"
			};
			return {
				type: "start",
				frame
			};
		}
		case TRANSCRIPTION_STREAM_AUDIO_DONE_FRAME_TYPE: return { type: "audio-done" };
		default: return { type: "unknown" };
	}
}
/**
* Server-side: serialize a transcription stream part as one TEXT frame.
* `Error` payloads in `error` parts serialize as `{ name, message }` —
* `Error` properties are non-enumerable, so a plain `JSON.stringify` would
* serialize them to `{}` and lose the message end-to-end. Returns
* `undefined` for payloads that are not JSON-serializable (envelope rule 4,
* e.g. bigint or cyclic values); callers drop the frame.
*/
function serializeTranscriptionStreamPart(part) {
	try {
		if (part.type === "error" && isError(part.error)) return JSON.stringify({
			...part,
			error: {
				name: part.error.name,
				message: part.error.message
			}
		});
		return JSON.stringify(part);
	} catch {
		return;
	}
}
function isError(value) {
	return value instanceof Error || Object.prototype.toString.call(value) === "[object Error]";
}
/**
* Client-side: parse a server TEXT frame into a transcription stream part.
* Returns `undefined` for malformed or unsafe (prototype-polluting) JSON
* (parsed with `secureJsonParse`), unknown part types, and known part types
* whose required or optional fields are missing or mistyped (including
* warning and segment elements) — downstream SDK code dereferences those
* fields, so a drifted server must not crash or pollute the stream.
* Revives `response-metadata.timestamp` to a `Date`.
*/
function parseTranscriptionStreamPart(text) {
	let value;
	try {
		value = secureJsonParse(text);
	} catch {
		return;
	}
	if (value == null || typeof value !== "object" || Array.isArray(value)) return;
	const part = value;
	switch (part.type) {
		case "stream-start": return Array.isArray(part.warnings) && part.warnings.every(isWarning) ? part : void 0;
		case "transcript-delta": return isString(part.delta) && isOptional(part.id, isString) && isOptional(part.providerMetadata, isRecord) ? part : void 0;
		case "transcript-partial": return isString(part.text) && isOptional(part.id, isString) && isOptional(part.startSecond, isNumber) && isOptional(part.durationInSeconds, isNumber) && isOptional(part.channelIndex, isNumber) && isOptional(part.providerMetadata, isRecord) ? part : void 0;
		case "transcript-final": return isString(part.text) && isOptional(part.id, isString) && isOptional(part.startSecond, isNumber) && isOptional(part.endSecond, isNumber) && isOptional(part.channelIndex, isNumber) && isOptional(part.providerMetadata, isRecord) ? part : void 0;
		case "finish": return isString(part.text) && Array.isArray(part.segments) && part.segments.every(isSegment) && isOptional(part.language, isString) && isOptional(part.durationInSeconds, isNumber) && isOptional(part.usage, isRecord) && isOptional(part.providerMetadata, isRecord) ? part : void 0;
		case "response-metadata": {
			if (!(isOptional(part.modelId, isString) && isOptional(part.headers, isRecord))) return;
			const timestamp = part.timestamp;
			if (timestamp == null) return {
				...part,
				timestamp: void 0
			};
			if (typeof timestamp !== "string") return;
			const revived = new Date(timestamp);
			return Number.isNaN(revived.getTime()) ? void 0 : {
				...part,
				timestamp: revived
			};
		}
		case "raw": return "rawValue" in part ? part : void 0;
		case "error": return "error" in part ? part : void 0;
		default: return;
	}
}
function isString(value) {
	return typeof value === "string";
}
function isNumber(value) {
	return typeof value === "number";
}
function isOptional(value, check) {
	return value === void 0 || check(value);
}
function isWarning(value) {
	return isRecord(value) && isString(value.type);
}
function isSegment(value) {
	return isRecord(value) && isString(value.text) && isNumber(value.startSecond) && isNumber(value.endSecond);
}
//#endregion
//#region src/validate-base-url.ts
function validateBaseURL(baseURL) {
	if (baseURL?.trim() === "") throw new InvalidArgumentError({
		argument: "baseURL",
		message: "baseURL must be a non-empty string."
	});
	return baseURL;
}
//#endregion
//#region src/without-trailing-slash.ts
function withoutTrailingSlash(url) {
	return url?.replace(/\/$/, "");
}
//#endregion
//#region src/types/executable-tool.ts
/**
* Checks whether a tool exposes an execute function.
*/
function isExecutableTool(tool) {
	return tool != null && typeof tool.execute === "function";
}
//#endregion
//#region src/is-async-iterable.ts
function isAsyncIterable(obj) {
	return obj != null && typeof obj[Symbol.asyncIterator] === "function";
}
//#endregion
//#region src/types/execute-tool.ts
/**
* Executes a tool function and normalizes its results into a stream of outputs.
*
* - If the tool's `execute` function returns an `AsyncIterable`, each yielded value is emitted as
*   `{ type: "preliminary", output }`. After iteration completes, the last yielded value is emitted
*   again as `{ type: "final", output }`.
* - If the tool returns a direct value or Promise, a single `{ type: "final", output }` is yielded.
*
* @param params.tool The tool whose `execute` function should be invoked.
* @param params.input The input value to pass to the tool.
* @param params.options Additional options for tool execution.
* @yields A preliminary output for each streamed value, followed by a final output, or a single final
* output for non-streaming tools.
*/
async function* executeTool({ tool, input, options }) {
	const result = tool.execute(input, options);
	if (isAsyncIterable(result)) {
		let lastOutput;
		for await (const output of result) {
			lastOutput = output;
			yield {
				type: "preliminary",
				output
			};
		}
		yield {
			type: "final",
			output: lastOutput
		};
	} else yield {
		type: "final",
		output: await result
	};
}
//#endregion
//#region src/types/tool-caller.ts
function toolCaller(tool, definition) {
	return Object.defineProperty({ ...tool }, "experimental_toolCaller", { value: definition });
}
function getToolCaller(tool) {
	return tool?.experimental_toolCaller;
}
//#endregion
//#region src/stringify-with-bigint-and-cycles.ts
/**
* Serializes a value as JSON, representing BigInt values as decimal strings and
* ancestor cycles as "[Circular]". Reused objects, toJSON methods, and other JSON
* serialization behavior are preserved. Getters and toJSON methods may throw.
*/
function stringifyWithBigIntAndCycles(value) {
	const ancestors = [];
	return JSON.stringify(value, function(_key, value) {
		if (typeof value === "bigint") return value.toString();
		if (typeof value !== "object" || value === null) return value;
		while (ancestors.length > 0 && ancestors.at(-1) !== this) ancestors.pop();
		if (ancestors.includes(value)) return "[Circular]";
		ancestors.push(value);
		return value;
	});
}
//#endregion
export { DEFAULT_MAX_DOWNLOAD_SIZE, DelayedPromise, DownloadError, EMBEDDING_MODEL_MAX_INPUT_BYTES_PER_CALL as EXPERIMENTAL_EMBEDDING_MODEL_MAX_INPUT_BYTES_PER_CALL, EMBEDDING_MODEL_PROVIDER_OPTIONS_TRANSFORMER as EXPERIMENTAL_EMBEDDING_MODEL_PROVIDER_OPTIONS_TRANSFORMER, SPEECH_STREAM_START_FRAME_TYPE as EXPERIMENTAL_SPEECH_STREAM_START_FRAME_TYPE, SPEECH_STREAM_TEXT_DELTA_FRAME_TYPE as EXPERIMENTAL_SPEECH_STREAM_TEXT_DELTA_FRAME_TYPE, SPEECH_STREAM_TEXT_DONE_FRAME_TYPE as EXPERIMENTAL_SPEECH_STREAM_TEXT_DONE_FRAME_TYPE, TRANSCRIPTION_STREAM_AUDIO_DONE_FRAME_TYPE as EXPERIMENTAL_TRANSCRIPTION_STREAM_AUDIO_DONE_FRAME_TYPE, TRANSCRIPTION_STREAM_START_FRAME_TYPE as EXPERIMENTAL_TRANSCRIPTION_STREAM_START_FRAME_TYPE, EventSourceParserStream, SerializationError, StreamingToolCallTracker, VERSION, WORKFLOW_DESERIALIZE, WORKFLOW_SERIALIZE, asArray, asSchema, cancelResponseBody, combineHeaders, connectToWebSocket, convertAsyncIteratorToReadableStream, convertBase64ToUint8Array, convertImageModelFileToDataUri, convertInlineFileDataToUint8Array, convertJsonResponseToolStream, convertToBase64, convertToFormData, convertUint8ArrayToBase64, createBinaryResponseHandler, createBinaryStreamResponseHandler, createEventSourceResponseHandler, createIdGenerator, createJsonErrorResponseHandler, createJsonLinesResponseHandler, createJsonResponseHandler, createLanguageModelResponseMetadata, createNullLanguageModelUsage, createProviderDefinedToolFactory, createProviderDefinedToolFactoryWithOutputSchema, createProviderExecutedToolFactory, createProviderStreamError, createStatusCodeErrorResponseHandler, createToolNameMapping, delay, deleteFromApi, detectMediaType, downloadBlob, dynamicTool, encodePathSegment, executeTool, getToolCaller as experimental_getToolCaller, parseSpeechStreamClientFrame as experimental_parseSpeechStreamClientFrame, parseSpeechStreamPart as experimental_parseSpeechStreamPart, parseTranscriptionStreamClientFrame as experimental_parseTranscriptionStreamClientFrame, parseTranscriptionStreamPart as experimental_parseTranscriptionStreamPart, serializeSpeechStreamPart as experimental_serializeSpeechStreamPart, serializeTranscriptionStreamPart as experimental_serializeTranscriptionStreamPart, toolCaller as experimental_toolCaller, extractLines, extractResponseHeaders, fetchUntrustedUrl, fetchWithValidatedEndpoint, fetchWithValidatedRedirects, filterNullable, generateId, getErrorMessage, getFromApi, getRuntimeEnvironmentUserAgent, getTopLevelMediaType, getWebSocketConstructor, injectJsonInstructionIntoMessages, isAbortError, isArrayBuffer, isBrowserRuntime, isBuffer, isCustomReasoning, isExecutableTool, isFullMediaType, isNonNullable, isParsableJson, isProviderReference, isProviderStreamError, isRecord, isSameOrigin, isUint8Array, isUrlSupported, isValidHostnamePart, jsonSchema, lazySchema, loadApiKey, loadOptionalSetting, loadSetting, mapReasoningToProviderBudget, mapReasoningToProviderEffort, mediaTypeToExtension, normalizeBatchRequestCounts, normalizeHeaders, parseJSON, parseJsonEventStream, parseProviderOptions, postFormDataToApi, postJsonToApi, postMultipartStreamToApi, postToApi, readResponseWithSizeLimit, readWebSocketMessageText, redactTelemetryValue, removeUndefinedEntries, resolve, resolveFullMediaType, resolveProviderOptions, resolveProviderReference, resolveWith, retryWithExponentialBackoff, safeParseJSON, safeValidateTypes, secureJsonParse, serializeModelOptions, stringifyWithBigIntAndCycles, stripFileExtension, toWebSocketUrl, tool, validateBaseURL, validateDownloadUrl, validateTypes, waitForWebSocketBufferDrain, withTelemetryRedaction, withUserAgentSuffix, withoutTrailingSlash, zodSchema };

//# sourceMappingURL=index.js.map