const require_rolldown_runtime = require("./rolldown-runtime-D_mwlA32.cjs");
const require_logger = require("./logger-DuG3amVa.cjs");
const require_fetch = require("./fetch-Hdu2Q-w3.cjs");
const require_fileExtensions = require("./fileExtensions-D0tJXtZn.cjs");
const require_util = require("./util-M3cOWPu3.cjs");
const require_dataUrl = require("./dataUrl-DxL5oIH5.cjs");
let zod = require("zod");
let crypto = require("crypto");
crypto = require_rolldown_runtime.__toESM(crypto, 1);
let rfdc = require("rfdc");
rfdc = require_rolldown_runtime.__toESM(rfdc, 1);
//#region src/providers/google/auth.ts
/**
* Centralized authentication manager for Google AI providers.
*
* This module handles authentication for both Google AI Studio and Vertex AI,
* with support for API keys, OAuth/ADC, and service account credentials.
*
* Environment variable priority is aligned with the Python SDK:
* 1. config.apiKey (explicit)
* 2. VERTEX_API_KEY (Vertex mode only)
* 3. GOOGLE_API_KEY (primary - Python SDK alignment)
* 4. GEMINI_API_KEY (secondary)
*/
const EXPECTED_GCP_METADATA_LOOKUP_WARNING_PREFIX = "received unexpected error = ";
let activeGcpMetadataLookupWarningSuppressions = 0;
let restoreEmitWarning;
async function suppressExpectedGcpMetadataLookupWarning(action) {
	if (activeGcpMetadataLookupWarningSuppressions === 0) {
		const originalEmitWarning = process.emitWarning;
		const wrappedEmitWarning = ((warning, ...args) => {
			const message = warning instanceof Error ? warning.message : warning;
			if ((warning instanceof Error ? warning.name : args[0]) === "MetadataLookupWarning" && typeof message === "string" && message.startsWith(EXPECTED_GCP_METADATA_LOOKUP_WARNING_PREFIX)) return;
			Reflect.apply(originalEmitWarning, process, [warning, ...args]);
		});
		process.emitWarning = wrappedEmitWarning;
		restoreEmitWarning = () => {
			if (process.emitWarning === wrappedEmitWarning) process.emitWarning = originalEmitWarning;
		};
	}
	activeGcpMetadataLookupWarningSuppressions += 1;
	try {
		return await action();
	} finally {
		activeGcpMetadataLookupWarningSuppressions -= 1;
		if (activeGcpMetadataLookupWarningSuppressions === 0) {
			restoreEmitWarning?.();
			restoreEmitWarning = void 0;
		}
	}
}
/**
* Centralized authentication manager for Google AI providers.
*
* Handles:
* - API key resolution with proper priority
* - OAuth client creation for Vertex AI
* - Service account credential loading
* - Conflict detection and warnings
*/
var GoogleAuthManager = class {
	static cachedHasDefaultCredentials;
	static pendingHasDefaultCredentials;
	/**
	* Get API key with proper priority order.
	*
	* Priority (aligned with Python SDK):
	* 1. config.apiKey (explicit)
	* 2. VERTEX_API_KEY (Vertex mode only)
	* 3. GOOGLE_API_KEY (primary - Python SDK alignment)
	* 4. GEMINI_API_KEY (secondary)
	* 5. PALM_API_KEY (legacy)
	*
	* @param config - Provider configuration
	* @param env - Environment overrides
	* @param isVertexMode - Whether in Vertex AI mode
	* @returns The resolved API key and its source
	*/
	static getApiKey(config, env, isVertexMode = false) {
		if (config.apiKey) return {
			apiKey: config.apiKey,
			source: "config"
		};
		if (isVertexMode) {
			const vertexKey = env?.VERTEX_API_KEY || require_logger.getEnvString("VERTEX_API_KEY");
			if (vertexKey) {
				require_logger.logger.warn("[Google] VERTEX_API_KEY is not a standard SDK env var. Use GOOGLE_API_KEY instead.");
				return {
					apiKey: vertexKey,
					source: "VERTEX_API_KEY"
				};
			}
		}
		const googleKey = env?.GOOGLE_API_KEY || require_logger.getEnvString("GOOGLE_API_KEY");
		const geminiKey = isVertexMode ? void 0 : env?.GEMINI_API_KEY || require_logger.getEnvString("GEMINI_API_KEY");
		const palmKey = isVertexMode ? void 0 : env?.PALM_API_KEY || require_logger.getEnvString("PALM_API_KEY");
		if (googleKey && geminiKey) require_logger.logger.debug("[Google] Both GOOGLE_API_KEY and GEMINI_API_KEY are set. Using GOOGLE_API_KEY.");
		if (googleKey) return {
			apiKey: googleKey,
			source: "GOOGLE_API_KEY"
		};
		if (geminiKey) {
			require_logger.logger.debug("[Google] GEMINI_API_KEY is not a standard SDK env var. Consider using GOOGLE_API_KEY.");
			return {
				apiKey: geminiKey,
				source: "GEMINI_API_KEY"
			};
		}
		if (palmKey) {
			require_logger.logger.warn("[Google] PALM_API_KEY is deprecated. Use GOOGLE_API_KEY instead.");
			return {
				apiKey: palmKey,
				source: "PALM_API_KEY"
			};
		}
		return {
			apiKey: void 0,
			source: "none"
		};
	}
	/**
	* Validate authentication configuration and emit warnings or throw errors for issues.
	*
	* @param config - Authentication configuration
	* @param env - Environment overrides
	* @throws Error if strictMutualExclusivity is true and mutual exclusivity violation detected
	*/
	static validateAndWarn(config, env) {
		const { apiKey, credentials, projectId, region, vertexai, strictMutualExclusivity } = config;
		const isStrict = strictMutualExclusivity === true;
		const useVertexEnv = require_logger.getEnvString("GOOGLE_GENAI_USE_VERTEXAI");
		const cloudProject = require_logger.getEnvString("GOOGLE_CLOUD_PROJECT");
		if ((projectId || region) && apiKey) {
			const message = "[Google] Project/location and API key are mutually exclusive in the client initializer. Use either apiKey for express mode OR projectId/region for OAuth mode, not both.";
			if (isStrict) throw new Error(message);
			else require_logger.logger.warn(message);
		}
		if (useVertexEnv && vertexai === false) require_logger.logger.warn("[Google] GOOGLE_GENAI_USE_VERTEXAI is set but vertexai: false was specified in config. Config takes precedence.");
		if (cloudProject && projectId && cloudProject !== projectId) require_logger.logger.warn("[Google] Both GOOGLE_CLOUD_PROJECT and config.projectId are set with different values. Using config.projectId.");
		if (apiKey && credentials) require_logger.logger.debug("[Google] Both apiKey and credentials are set. Using API key (express mode). Set expressMode: false to use OAuth/ADC instead.");
		if (vertexai && !apiKey && !projectId && !cloudProject && !credentials) {
			if (!Boolean(env?.GOOGLE_APPLICATION_CREDENTIALS || process.env.GOOGLE_APPLICATION_CREDENTIALS)) require_logger.logger.debug("[Google] Vertex AI mode enabled but no projectId, credentials, or ADC detected. Authentication may fail.");
		}
	}
	/**
	* Determine if Vertex AI mode should be used.
	*
	* Priority:
	* 1. Explicit vertexai config flag
	* 2. GOOGLE_GENAI_USE_VERTEXAI env var (Python SDK compatibility)
	* 3. Auto-detect from projectId/credentials presence
	* 4. Default: false (Google AI Studio)
	*
	* @param config - Provider configuration
	* @param env - Environment overrides
	* @returns Whether to use Vertex AI mode
	*/
	static determineVertexMode(config, env) {
		if (config.vertexai !== void 0) return config.vertexai;
		const useVertexEnv = require_logger.getEnvString("GOOGLE_GENAI_USE_VERTEXAI");
		if (useVertexEnv === "true" || useVertexEnv === "1") {
			require_logger.logger.debug("[Google] Vertex AI mode enabled via GOOGLE_GENAI_USE_VERTEXAI");
			return true;
		}
		if (useVertexEnv === "false" || useVertexEnv === "0") return false;
		const hasProjectId = Boolean(config.projectId || env?.VERTEX_PROJECT_ID || require_logger.getEnvString("VERTEX_PROJECT_ID") || env?.GOOGLE_PROJECT_ID || require_logger.getEnvString("GOOGLE_PROJECT_ID") || require_logger.getEnvString("GOOGLE_CLOUD_PROJECT"));
		const hasCredentials = Boolean(config.credentials);
		if (hasProjectId || hasCredentials) {
			require_logger.logger.debug("[Google] Auto-detected Vertex AI mode from projectId/credentials. Set vertexai: true/false explicitly to suppress this message.");
			return true;
		}
		return false;
	}
	/**
	* Load credentials from file or return as-is.
	*
	* Supports:
	* - file:// prefix to load from external file
	* - Raw JSON string
	* - Pre-parsed object (from config loading pipeline)
	*
	* @param credentials - Credentials string, file path, or pre-parsed object
	* @returns Processed credentials JSON string
	*/
	static loadCredentials(credentials) {
		if (!credentials) return;
		if (typeof credentials === "object") return JSON.stringify(credentials);
		if (credentials.startsWith("file://")) try {
			const loaded = require_util.maybeLoadFromExternalFile(credentials);
			if (typeof loaded === "object") return JSON.stringify(loaded);
			return loaded;
		} catch (error) {
			throw new Error(`Failed to load credentials from file: ${error}`);
		}
		return credentials;
	}
	/**
	* Get or create a Google OAuth client.
	*
	* Supports googleAuthOptions passthrough for advanced configuration
	* like custom scopes, keyFilename, universeDomain, etc.
	*
	* @param options - OAuth client options (can also pass string for backward compatibility)
	* @returns OAuth client and detected project ID
	*/
	static async getOAuthClient(options = {}) {
		const { credentials, googleAuthOptions, scopes, keyFilename } = typeof options === "string" ? { credentials: options } : options;
		const resolvedScopes = scopes ?? googleAuthOptions?.scopes ?? "https://www.googleapis.com/auth/cloud-platform";
		const authOptions = {
			...googleAuthOptions,
			scopes: resolvedScopes
		};
		if (keyFilename && !authOptions.keyFilename) authOptions.keyFilename = keyFilename;
		let GoogleAuthClass;
		try {
			GoogleAuthClass = (await import("google-auth-library")).GoogleAuth;
		} catch {
			throw new Error("The google-auth-library package is required for Vertex AI. Please install it: npm install google-auth-library");
		}
		const auth = new GoogleAuthClass(authOptions);
		const processedCredentials = this.loadCredentials(credentials);
		let client;
		if (processedCredentials) {
			let parsedCredentials;
			try {
				parsedCredentials = JSON.parse(processedCredentials);
			} catch (parseError) {
				const errorMsg = parseError instanceof Error ? parseError.message : String(parseError);
				throw new Error(`[Google] Invalid credentials JSON format: ${errorMsg}`);
			}
			try {
				client = await auth.fromJSON(parsedCredentials);
			} catch (error) {
				const errorMsg = error instanceof Error ? error.message : String(error);
				require_logger.logger.error(`[Google] Could not load credentials: ${errorMsg}`);
				throw new Error(`[Google] Could not load credentials: ${errorMsg}`);
			}
		} else client = await auth.getClient();
		let projectId;
		try {
			projectId = await auth.getProjectId();
		} catch {
			projectId = void 0;
		}
		return {
			client,
			projectId
		};
	}
	/**
	* Resolve project ID from multiple sources.
	*
	* Priority:
	* 1. config.projectId
	* 2. VERTEX_PROJECT_ID env var
	* 3. GOOGLE_PROJECT_ID env var
	* 4. GOOGLE_CLOUD_PROJECT env var (Python SDK compatibility)
	* 5. Auto-detected from OAuth credentials
	*
	* @param config - Provider configuration
	* @param env - Environment overrides
	* @returns Resolved project ID
	*/
	static async resolveProjectId(config, env) {
		const { projectId: authProjectId } = await this.getOAuthClient({
			credentials: config.credentials,
			googleAuthOptions: config.googleAuthOptions,
			keyFilename: config.keyFilename,
			scopes: config.scopes
		});
		const vertexProjectId = env?.VERTEX_PROJECT_ID || require_logger.getEnvString("VERTEX_PROJECT_ID");
		const googleProjectId = env?.GOOGLE_PROJECT_ID || require_logger.getEnvString("GOOGLE_PROJECT_ID");
		const cloudProject = require_logger.getEnvString("GOOGLE_CLOUD_PROJECT");
		if (vertexProjectId && !config.projectId) require_logger.logger.debug("[Google] VERTEX_PROJECT_ID is not a standard SDK env var. Consider using GOOGLE_CLOUD_PROJECT.");
		if (googleProjectId && !config.projectId && !vertexProjectId) require_logger.logger.debug("[Google] GOOGLE_PROJECT_ID is not a standard SDK env var. Consider using GOOGLE_CLOUD_PROJECT.");
		return config.projectId || vertexProjectId || googleProjectId || cloudProject || authProjectId || "";
	}
	/**
	* Resolve region from multiple sources.
	*
	* Priority:
	* 1. config.region
	* 2. VERTEX_REGION env var
	* 3. GOOGLE_CLOUD_LOCATION env var (Python SDK compatibility)
	* 4. Default: 'global' for Vertex AI without API key (SDK aligned), 'us-central1' otherwise
	*
	* @param config - Provider configuration
	* @param env - Environment overrides
	* @param hasApiKey - Whether an API key is configured (affects default region)
	* @returns Resolved region
	*/
	static resolveRegion(config, env, hasApiKey) {
		const vertexRegion = env?.VERTEX_REGION || require_logger.getEnvString("VERTEX_REGION");
		const cloudLocation = require_logger.getEnvString("GOOGLE_CLOUD_LOCATION");
		if (vertexRegion && !config.region) require_logger.logger.debug("[Google] VERTEX_REGION is not a standard SDK env var. Consider using GOOGLE_CLOUD_LOCATION.");
		const configuredRegion = config.region || vertexRegion || cloudLocation;
		if (configuredRegion) return configuredRegion;
		if (hasApiKey === false) return "global";
		return "us-central1";
	}
	/**
	* Check if Application Default Credentials are available.
	*
	* @returns True if ADC is available
	*/
	static async hasDefaultCredentials() {
		if (this.cachedHasDefaultCredentials !== void 0) return this.cachedHasDefaultCredentials;
		if (!this.pendingHasDefaultCredentials) {
			const probe = (async () => {
				try {
					await suppressExpectedGcpMetadataLookupWarning(() => this.getOAuthClient());
					return true;
				} catch {
					return false;
				}
			})();
			this.pendingHasDefaultCredentials = probe;
			probe.then((result) => {
				if (this.pendingHasDefaultCredentials === probe) this.cachedHasDefaultCredentials = result;
				return result;
			}).finally(() => {
				if (this.pendingHasDefaultCredentials === probe) this.pendingHasDefaultCredentials = void 0;
			});
		}
		return this.pendingHasDefaultCredentials;
	}
	/**
	* Clear internal auth detection caches (useful for testing).
	*/
	static clearCache() {
		this.cachedHasDefaultCredentials = void 0;
		this.pendingHasDefaultCredentials = void 0;
	}
};
const loadCredentials = GoogleAuthManager.loadCredentials.bind(GoogleAuthManager);
const getGoogleClient = GoogleAuthManager.getOAuthClient.bind(GoogleAuthManager);
const resolveProjectId = GoogleAuthManager.resolveProjectId.bind(GoogleAuthManager);
const getGoogleApiKey = GoogleAuthManager.getApiKey.bind(GoogleAuthManager);
const determineGoogleVertexMode = GoogleAuthManager.determineVertexMode.bind(GoogleAuthManager);
const hasGoogleDefaultCredentials = GoogleAuthManager.hasDefaultCredentials.bind(GoogleAuthManager);
GoogleAuthManager.clearCache.bind(GoogleAuthManager);
//#endregion
//#region src/providers/google/shared.ts
const GEMINI_3_PRO_COST = {
	input: 2 / 1e6,
	output: 12 / 1e6
};
const GEMINI_3_PRO_TIERED_COST = {
	threshold: 2e5,
	above: {
		input: 4 / 1e6,
		output: 18 / 1e6
	}
};
const GEMINI_2_5_PRO_COST = {
	input: 1.25 / 1e6,
	output: 10 / 1e6
};
const GEMINI_2_5_PRO_TIERED_COST = {
	threshold: 2e5,
	above: {
		input: 2.5 / 1e6,
		output: 15 / 1e6
	}
};
/**
* Google AI Studio models with pricing data.
* Prices are per token (from Google AI pricing page, converted from per-million).
*
* Note: Vertex AI may have different pricing for some models.
*/
const GOOGLE_MODELS = [
	{
		id: "gemini-3.5-flash",
		cost: {
			input: 1.5 / 1e6,
			output: 9 / 1e6
		}
	},
	...["gemini-3.1-pro-preview", "gemini-3.1-pro-preview-customtools"].map((id) => ({
		id,
		cost: GEMINI_3_PRO_COST,
		tieredCost: GEMINI_3_PRO_TIERED_COST
	})),
	...["gemini-3.1-flash-lite", "gemini-3.1-flash-lite-preview"].map((id) => ({
		id,
		cost: {
			input: .25 / 1e6,
			output: 1.5 / 1e6
		}
	})),
	{
		id: "gemini-3-flash-preview",
		cost: {
			input: .5 / 1e6,
			output: 3 / 1e6
		}
	},
	{
		id: "gemini-3-pro-preview",
		cost: GEMINI_3_PRO_COST,
		tieredCost: GEMINI_3_PRO_TIERED_COST
	},
	...["gemini-2.5-pro", "gemini-2.5-computer-use-preview-10-2025"].map((id) => ({
		id,
		cost: GEMINI_2_5_PRO_COST,
		tieredCost: GEMINI_2_5_PRO_TIERED_COST
	})),
	...[
		"gemini-2.5-flash",
		"gemini-2.5-flash-preview-04-17",
		"gemini-flash-latest"
	].map((id) => ({
		id,
		cost: {
			input: .3 / 1e6,
			output: 2.5 / 1e6
		}
	})),
	...["gemini-2.5-flash-lite", "gemini-flash-lite-latest"].map((id) => ({
		id,
		cost: {
			input: .1 / 1e6,
			output: .4 / 1e6
		}
	})),
	...["gemini-2.0-flash", "gemini-2.0-flash-001"].map((id) => ({
		id,
		cost: {
			input: .1 / 1e6,
			output: .4 / 1e6
		},
		vertexCost: {
			input: .15 / 1e6,
			output: .6 / 1e6
		}
	})),
	...["gemini-2.0-flash-lite", "gemini-2.0-flash-lite-001"].map((id) => ({
		id,
		cost: {
			input: .075 / 1e6,
			output: .3 / 1e6
		}
	})),
	{
		id: "gemini-1.5-pro",
		cost: {
			input: 1.25 / 1e6,
			output: 5 / 1e6
		},
		tieredCost: {
			threshold: 128e3,
			above: {
				input: 2.5 / 1e6,
				output: 10 / 1e6
			}
		}
	},
	...[
		"gemini-1.5-pro-001",
		"gemini-1.5-pro-002",
		"gemini-1.5-pro-latest"
	].map((id) => ({
		id,
		cost: {
			input: 1.25 / 1e6,
			output: 5 / 1e6
		},
		tieredCost: {
			threshold: 128e3,
			above: {
				input: 2.5 / 1e6,
				output: 10 / 1e6
			}
		}
	})),
	...["gemini-1.5-pro-preview-0409", "gemini-1.5-pro-preview-0514"].map((id) => ({
		id,
		cost: {
			input: 1.25 / 1e6,
			output: 5 / 1e6
		},
		tieredCost: {
			threshold: 128e3,
			above: {
				input: 2.5 / 1e6,
				output: 10 / 1e6
			}
		}
	})),
	...[
		"gemini-1.5-flash",
		"gemini-1.5-flash-001",
		"gemini-1.5-flash-002",
		"gemini-1.5-flash-latest",
		"gemini-1.5-flash-preview-0514"
	].map((id) => ({
		id,
		cost: {
			input: .075 / 1e6,
			output: .3 / 1e6
		},
		tieredCost: {
			threshold: 128e3,
			above: {
				input: .15 / 1e6,
				output: .6 / 1e6
			}
		}
	})),
	...[
		"gemini-1.5-flash-8b",
		"gemini-1.5-flash-8b-001",
		"gemini-1.5-flash-8b-latest"
	].map((id) => ({
		id,
		cost: {
			input: .0375 / 1e6,
			output: .15 / 1e6
		},
		tieredCost: {
			threshold: 128e3,
			above: {
				input: .075 / 1e6,
				output: .3 / 1e6
			}
		}
	})),
	...[
		"gemini-1.0-pro",
		"gemini-1.0-pro-001",
		"gemini-1.0-pro-002",
		"gemini-1.0-pro-vision",
		"gemini-1.0-pro-vision-001"
	].map((id) => ({
		id,
		cost: {
			input: .5 / 1e6,
			output: 1.5 / 1e6
		}
	})),
	{
		id: "gemini-pro",
		cost: {
			input: .5 / 1e6,
			output: 1.5 / 1e6
		}
	},
	{
		id: "gemini-pro-vision",
		cost: {
			input: .5 / 1e6,
			output: 1.5 / 1e6
		}
	},
	{
		id: "gemini-robotics-er-1.6-preview",
		cost: {
			input: 1 / 1e6,
			output: 5 / 1e6
		}
	},
	{
		id: "gemini-embedding-2",
		cost: {
			input: .2 / 1e6,
			output: 0
		}
	},
	{
		id: "gemini-embedding-001",
		cost: {
			input: .15 / 1e6,
			output: 0
		}
	},
	{ id: "aqa" },
	{ id: "chat-bison" },
	{ id: "chat-bison-32k" },
	{ id: "chat-bison-32k@001" },
	{ id: "chat-bison-32k@002" },
	{ id: "chat-bison@001" },
	{ id: "chat-bison@002" },
	{ id: "codechat-bison" },
	{ id: "codechat-bison-32k" },
	{ id: "codechat-bison-32k@001" },
	{ id: "codechat-bison-32k@002" },
	{ id: "codechat-bison@001" },
	{ id: "codechat-bison@002" },
	{ id: "gemini-ultra" },
	{ id: "gemma" },
	{ id: "gemma-4-31b-it" },
	{ id: "gemma-4-26b-a4b-it" },
	{ id: "codegemma" },
	{ id: "paligemma" },
	{ id: "medlm-medium" },
	{ id: "medlm-large" }
];
/**
* List of chat model IDs for backwards compatibility.
* Used for model validation in ai.studio.ts.
*/
const CHAT_MODELS = GOOGLE_MODELS.map((m) => m.id);
//#endregion
//#region src/providers/google/types.ts
const VALID_SCHEMA_TYPES = [
	"TYPE_UNSPECIFIED",
	"STRING",
	"NUMBER",
	"INTEGER",
	"BOOLEAN",
	"ARRAY",
	"OBJECT"
];
//#endregion
//#region src/providers/google/util.ts
/**
* Normalizes safety settings to use the correct Google API field name `threshold`.
* Accepts the legacy `probability` field for backwards compatibility and maps it to `threshold`.
*/
function normalizeSafetySettings(safetySettings) {
	if (!safetySettings) return;
	return safetySettings.map(({ category, threshold, probability }) => ({
		category,
		threshold: threshold || probability || ""
	}));
}
function normalizeGoogleToolMode(mode) {
	if (typeof mode !== "string") return;
	switch (mode.toUpperCase()) {
		case "MODE_UNSPECIFIED":
		case "AUTO":
		case "VALIDATED":
		case "ANY":
		case "NONE": return mode.toUpperCase();
		default: return;
	}
}
function normalizeExplicitGoogleToolConfig(config) {
	if (config.toolConfig?.functionCallingConfig) {
		const { mode: rawMode, allowedFunctionNames, ...restFunctionCallingConfig } = config.toolConfig.functionCallingConfig;
		const mode = normalizeGoogleToolMode(rawMode);
		const functionCallingConfig = {
			...restFunctionCallingConfig,
			...mode ? { mode } : {},
			...allowedFunctionNames?.length ? { allowedFunctionNames } : {}
		};
		if (Object.keys(functionCallingConfig).length === 0) return;
		return { functionCallingConfig };
	}
	if (config.tool_config?.function_calling_config) {
		const { mode: rawMode, allowed_function_names: allowedFunctionNames, stream_function_call_arguments: streamFunctionCallArguments } = config.tool_config.function_calling_config;
		const mode = normalizeGoogleToolMode(rawMode);
		const functionCallingConfig = {
			...mode ? { mode } : {},
			...allowedFunctionNames?.length ? { allowedFunctionNames } : {},
			...streamFunctionCallArguments === void 0 ? {} : { streamFunctionCallArguments }
		};
		if (Object.keys(functionCallingConfig).length === 0) return;
		return { functionCallingConfig };
	}
}
function resolveGoogleToolConfig(config) {
	const explicitConfig = normalizeExplicitGoogleToolConfig(config);
	const transformedToolChoice = require_fetch.transformToolChoice(config.tool_choice, "google");
	const toolChoiceConfig = transformedToolChoice && typeof transformedToolChoice === "object" ? transformedToolChoice : void 0;
	const explicitMode = normalizeGoogleToolMode(explicitConfig?.functionCallingConfig?.mode);
	const camelCaseMode = normalizeGoogleToolMode(config.toolConfig?.functionCallingConfig?.mode);
	const snakeCaseMode = normalizeGoogleToolMode(config.tool_config?.function_calling_config?.mode);
	const toolChoiceMode = normalizeGoogleToolMode(toolChoiceConfig?.functionCallingConfig?.mode);
	if (explicitMode === "NONE" || camelCaseMode === "NONE" || snakeCaseMode === "NONE" || toolChoiceMode === "NONE") return {
		toolConfig: { functionCallingConfig: { mode: "NONE" } },
		toolsDisabled: true
	};
	return {
		...explicitConfig ? { toolConfig: explicitConfig } : toolChoiceConfig ? { toolConfig: toolChoiceConfig } : {},
		toolsDisabled: false
	};
}
function mergeGoogleCompletionOptions(baseConfig, promptConfig) {
	const mergedConfig = {
		...baseConfig,
		...promptConfig
	};
	const promptHasToolChoice = promptConfig?.tool_choice !== void 0;
	const promptHasToolConfig = promptConfig?.toolConfig !== void 0;
	const promptHasSnakeToolConfig = promptConfig?.tool_config !== void 0;
	if (promptHasToolChoice || promptHasToolConfig || promptHasSnakeToolConfig) {
		delete mergedConfig.tool_choice;
		delete mergedConfig.toolConfig;
		delete mergedConfig.tool_config;
		if (promptHasToolChoice) mergedConfig.tool_choice = promptConfig.tool_choice;
		if (promptHasToolConfig) mergedConfig.toolConfig = promptConfig.toolConfig;
		if (promptHasSnakeToolConfig) mergedConfig.tool_config = promptConfig.tool_config;
	}
	return mergedConfig;
}
function removeGoogleFunctionDeclarations(tools) {
	return tools.flatMap(({ functionDeclarations, ...tool }) => functionDeclarations && Object.keys(tool).length === 0 ? [] : [tool]);
}
function stripExecutableToolFileReferencesFromValue(tools) {
	if (typeof tools === "string" && tools.startsWith("file://")) {
		const { filePath } = require_util.parseFileUrl(tools);
		if (filePath.endsWith(".py") || require_fileExtensions.isJavascriptFile(filePath)) return;
	}
	if (Array.isArray(tools)) return tools.flatMap((tool) => {
		const strippedTool = stripExecutableToolFileReferencesFromValue(tool);
		return strippedTool === void 0 ? [] : [strippedTool];
	});
	return tools;
}
function stripExecutableToolFileReferences(tools, vars) {
	return stripExecutableToolFileReferencesFromValue(require_util.renderVarsInObject(tools, vars));
}
/**
* Calculates the cost for a Google API call.
*
* Handles tiered pricing for models where cost varies by prompt size.
* For example, Gemini Pro models have higher rates for prompts >200k tokens.
* Some models (e.g. Gemini 2.0 Flash) have different pricing on Vertex AI.
*
* @param modelName - The name of the model used
* @param config - Provider configuration (may contain custom cost override)
* @param promptTokens - Number of tokens in the prompt
* @param completionTokens - Number of tokens in the completion
* @param isVertexMode - Whether the call was made via Vertex AI (uses Vertex pricing when available)
* @returns The calculated cost in dollars, or undefined if it cannot be calculated
*/
function calculateGoogleCost(modelName, config, promptTokens, completionTokens, isVertexMode) {
	const model = GOOGLE_MODELS.find((m) => m.id === modelName);
	if (promptTokens != null && completionTokens != null) {
		if (model?.tieredCost && promptTokens > model.tieredCost.threshold) {
			const inputCost = config.inputCost ?? config.cost ?? model.tieredCost.above.input;
			const outputCost = config.outputCost ?? config.cost ?? model.tieredCost.above.output;
			return inputCost * promptTokens + outputCost * completionTokens;
		}
		if (isVertexMode && model?.vertexCost) {
			const inputCost = config.inputCost ?? config.cost ?? model.vertexCost.input;
			const outputCost = config.outputCost ?? config.cost ?? model.vertexCost.output;
			return inputCost * promptTokens + outputCost * completionTokens;
		}
	}
	return require_fetch.calculateCost(modelName, config, promptTokens, completionTokens, GOOGLE_MODELS);
}
const ajv = require_logger.getAjv();
ajv.addKeyword("property_ordering");
const clone = (0, rfdc.default)();
const PartSchema = zod.z.object({
	text: zod.z.string().optional(),
	inline_data: zod.z.object({
		mime_type: zod.z.string(),
		data: zod.z.string()
	}).optional()
});
const ContentSchema = zod.z.object({
	role: zod.z.enum(["user", "model"]).optional(),
	parts: zod.z.array(PartSchema)
});
const GeminiFormatSchema = zod.z.array(ContentSchema);
function maybeCoerceToGeminiFormat(contents, options) {
	let coerced = false;
	const parseResult = GeminiFormatSchema.safeParse(contents);
	if (parseResult.success) {
		let systemInst = void 0;
		if (typeof contents === "object" && "system_instruction" in contents) {
			systemInst = contents.system_instruction;
			coerced = true;
		}
		return {
			contents: parseResult.data,
			coerced,
			systemInstruction: systemInst
		};
	}
	let coercedContents;
	if (typeof contents === "object" && contents !== null && !Array.isArray(contents) && "system_instruction" in contents) {
		const systemInst = contents.system_instruction;
		if ("contents" in contents) coercedContents = contents.contents;
		else coercedContents = [];
		return {
			contents: coercedContents,
			coerced: true,
			systemInstruction: systemInst
		};
	}
	if (typeof contents === "string") {
		coercedContents = [{ parts: [{ text: contents }] }];
		coerced = true;
	} else if (Array.isArray(contents) && contents.every((item) => typeof item.content === "string")) {
		const targetRole = options?.useAssistantRole ? "assistant" : "model";
		coercedContents = contents.map((item) => ({
			role: item.role === "assistant" ? targetRole : item.role,
			parts: [{ text: item.content }]
		}));
		coerced = true;
	} else if (Array.isArray(contents) && contents.every((item) => item.role && item.content)) {
		const targetRole = options?.useAssistantRole ? "assistant" : "model";
		coercedContents = contents.map((item) => {
			const mappedRole = item.role === "assistant" ? targetRole : item.role;
			if (Array.isArray(item.content)) return {
				role: mappedRole,
				parts: item.content.map((contentItem) => {
					if (typeof contentItem === "string") return { text: contentItem };
					else if (contentItem.type === "text") return { text: contentItem.text };
					else return contentItem;
				})
			};
			else if (typeof item.content === "object") return {
				role: mappedRole,
				parts: [item.content]
			};
			else return {
				role: mappedRole,
				parts: [{ text: item.content }]
			};
		});
		coerced = true;
	} else if (typeof contents === "object" && contents !== null && "parts" in contents) {
		coercedContents = [contents];
		coerced = true;
	} else {
		require_logger.logger.warn(`Unknown format for Gemini: ${JSON.stringify(contents)}`);
		return {
			contents: Array.isArray(contents) ? contents : [],
			coerced: false,
			systemInstruction: void 0
		};
	}
	let systemPromptParts = [];
	coercedContents = coercedContents.filter((message) => {
		if (message.role === "system" && message.parts.length > 0) {
			systemPromptParts.push(...message.parts.filter((part) => "text" in part && typeof part.text === "string"));
			return false;
		}
		return true;
	});
	if (coercedContents.length === 0 && systemPromptParts.length > 0) {
		coercedContents = [{
			role: "user",
			parts: systemPromptParts
		}];
		coerced = true;
		systemPromptParts = [];
	}
	return {
		contents: coercedContents,
		coerced,
		systemInstruction: systemPromptParts.length > 0 ? { parts: systemPromptParts } : void 0
	};
}
let cachedGenerativeLanguageAuth = null;
/**
* Gets an OAuth2 access token for Google APIs.
* Used by providers that need to authenticate via OAuth2 instead of API keys.
* @param credentials - Optional credentials JSON string or file:// path
* @param scopes - Optional scopes to use. Defaults to cloud-platform + generative-language scopes
* @returns The access token string, or undefined if authentication fails
*/
async function getGoogleAccessToken(credentials) {
	try {
		if (!cachedGenerativeLanguageAuth) {
			let GoogleAuth;
			try {
				GoogleAuth = (await import("google-auth-library")).GoogleAuth;
				cachedGenerativeLanguageAuth = new GoogleAuth({ scopes: [
					"https://www.googleapis.com/auth/cloud-platform",
					"https://www.googleapis.com/auth/generative-language.retriever",
					"https://www.googleapis.com/auth/generative-language.tuning"
				] });
			} catch {
				throw new Error("The google-auth-library package is required as a peer dependency. Please install it in your project or globally.");
			}
		}
		const processedCredentials = loadCredentials(credentials);
		let client;
		if (processedCredentials) client = await cachedGenerativeLanguageAuth.fromJSON(JSON.parse(processedCredentials));
		else client = await cachedGenerativeLanguageAuth.getClient();
		return (await client.getAccessToken()).token || void 0;
	} catch (error) {
		require_logger.logger.debug("[GoogleAuth] Could not get access token", { error: error instanceof Error ? error.message : String(error) });
		return;
	}
}
function getCandidate(data) {
	if (!data || !data.candidates || data.candidates.length < 1) {
		let errorDetails = "No candidates returned in API response.";
		if (data?.promptFeedback?.blockReason) {
			errorDetails = `Response blocked: ${data.promptFeedback.blockReason}`;
			if (data.promptFeedback.safetyRatings) {
				const flaggedCategories = data.promptFeedback.safetyRatings.filter((rating) => rating.probability !== "NEGLIGIBLE").map((rating) => `${rating.category}: ${rating.probability}`);
				if (flaggedCategories.length > 0) errorDetails += ` (Safety ratings: ${flaggedCategories.join(", ")})`;
			}
		} else if (data?.promptFeedback?.safetyRatings) {
			const flaggedCategories = data.promptFeedback.safetyRatings.filter((rating) => rating.probability !== "NEGLIGIBLE").map((rating) => `${rating.category}: ${rating.probability}`);
			if (flaggedCategories.length > 0) errorDetails = `Response may have been blocked due to safety filters: ${flaggedCategories.join(", ")}`;
		}
		errorDetails += `\n\nGot response: ${JSON.stringify(data)}`;
		throw new Error(errorDetails);
	}
	if (data.candidates.length > 1) require_logger.logger.debug(`Expected one candidate in AI Studio API response, but got ${data.candidates.length}: ${JSON.stringify(data)}`);
	const candidate = data.candidates[0];
	if (!candidate) throw new Error(`No candidates returned in API response.\n\nGot response: ${JSON.stringify(data)}`);
	return candidate;
}
function isNonCandidateStreamChunk(datum) {
	return !datum.candidates?.length && (Boolean(datum.usageMetadata) && !datum.promptFeedback || Boolean(datum.promptFeedback?.safetyRatings) && !datum.promptFeedback?.blockReason);
}
function getLastPromptSafetyRatings(data) {
	let safetyRatings;
	for (const datum of data) if (datum.promptFeedback?.safetyRatings) safetyRatings = datum.promptFeedback.safetyRatings;
	return safetyRatings;
}
function collectGroundingMetadata(data) {
	const candidates = data.filter((d) => d.candidates?.length).map((d) => getCandidate(d));
	const flatChunks = candidates.flatMap((c) => c.groundingChunks ?? []);
	const flatSupports = candidates.flatMap((c) => c.groundingSupports ?? []);
	const flatQueries = candidates.flatMap((c) => c.webSearchQueries ?? []);
	const metas = candidates.map((c) => c.groundingMetadata).filter((m) => Boolean(m));
	let groundingMetadata;
	if (metas.length === 1) groundingMetadata = metas[0];
	else if (metas.length > 1) {
		const merged = {};
		for (const m of metas) for (const [key, value] of Object.entries(m)) {
			if (key === "groundingChunks" || key === "groundingSupports" || key === "webSearchQueries") continue;
			if (value !== void 0) merged[key] = value;
		}
		const innerChunks = metas.flatMap((m) => m.groundingChunks ?? []);
		const innerSupports = metas.flatMap((m) => m.groundingSupports ?? []);
		const innerQueries = metas.flatMap((m) => m.webSearchQueries ?? []);
		if (innerChunks.length) merged.groundingChunks = innerChunks;
		if (innerSupports.length) merged.groundingSupports = innerSupports;
		if (innerQueries.length) merged.webSearchQueries = innerQueries;
		groundingMetadata = merged;
	}
	return {
		...groundingMetadata && { groundingMetadata },
		...flatChunks.length > 0 && { groundingChunks: flatChunks },
		...flatSupports.length > 0 && { groundingSupports: flatSupports },
		...flatQueries.length > 0 && { webSearchQueries: flatQueries }
	};
}
function formatCandidateContents(candidate) {
	if (candidate.finishReason && [
		"SAFETY",
		"RECITATION",
		"PROHIBITED_CONTENT",
		"BLOCKLIST",
		"SPII"
	].includes(candidate.finishReason)) {
		let errorMessage = `Response was blocked with finish reason: ${candidate.finishReason}`;
		if (candidate.safetyRatings) {
			const flaggedCategories = candidate.safetyRatings.filter((rating) => rating.probability !== "NEGLIGIBLE" || rating.blocked).map((rating) => `${rating.category}: ${rating.probability}${rating.blocked ? " (BLOCKED)" : ""}`);
			if (flaggedCategories.length > 0) errorMessage += `\nSafety ratings: ${flaggedCategories.join(", ")}`;
		}
		if (candidate.finishReason === "RECITATION") errorMessage += "\n\nThis typically occurs when the response is too similar to content from the model's training data.";
		else if (candidate.finishReason === "SAFETY") errorMessage += "\n\nThe response was blocked due to safety filters. Consider adjusting safety settings or modifying your prompt.";
		throw new Error(errorMessage);
	}
	if (candidate.content?.parts) {
		let output = "";
		let is_text = true;
		for (const part of candidate.content.parts) if ("text" in part) output += part.text;
		else is_text = false;
		if (is_text) return output;
		else return candidate.content.parts;
	} else throw new Error(`No output found in response: ${JSON.stringify(candidate)}`);
}
function mergeParts(parts1, parts2) {
	if (parts1 === void 0) return typeof parts2 === "string" ? parts2 : [...parts2];
	if (typeof parts1 === "string" && typeof parts2 === "string") return parts1 + parts2;
	const array1 = typeof parts1 === "string" ? [{ text: parts1 }] : parts1;
	const array2 = typeof parts2 === "string" ? [{ text: parts2 }] : parts2;
	array1.push(...array2);
	return array1;
}
/**
* Normalizes and sanitizes tools configuration for Gemini API compatibility.
* - Handles snake_case to camelCase conversion for backwards compatibility
* - Sanitizes function declaration schemas to remove unsupported JSON Schema properties
*   (e.g., additionalProperties, $schema, default) that Gemini doesn't support
*/
function normalizeTools(tools) {
	return tools.map((tool) => {
		const normalizedTool = { ...tool };
		if (tool.google_search && !normalizedTool.googleSearch) normalizedTool.googleSearch = tool.google_search;
		if (tool.code_execution && !normalizedTool.codeExecution) normalizedTool.codeExecution = tool.code_execution;
		if (tool.google_search_retrieval && !normalizedTool.googleSearchRetrieval) normalizedTool.googleSearchRetrieval = tool.google_search_retrieval;
		if (normalizedTool.functionDeclarations) normalizedTool.functionDeclarations = normalizedTool.functionDeclarations.map((fd) => ({
			...fd,
			parameters: fd.parameters ? sanitizeSchemaForGemini(fd.parameters) : void 0
		}));
		return normalizedTool;
	});
}
function loadFile(config_var, context_vars) {
	const fileContents = require_util.maybeLoadFromExternalFile(require_util.renderVarsInObject(config_var, context_vars));
	if (typeof fileContents === "string") try {
		const parsedContents = JSON.parse(fileContents);
		return Array.isArray(parsedContents) ? normalizeTools(parsedContents) : parsedContents;
	} catch (err) {
		require_logger.logger.debug(`ERROR: failed to convert file contents to JSON:\n${JSON.stringify(err)}`);
		return fileContents;
	}
	if (Array.isArray(fileContents)) return normalizeTools(fileContents);
	return fileContents;
}
function isValidBase64Image(data) {
	const base64Data = require_dataUrl.isDataUrl(data) ? require_dataUrl.extractBase64FromDataUrl(data) : data;
	if (!base64Data || base64Data.length < 20) return false;
	try {
		Buffer.from(base64Data, "base64");
		return base64Data.startsWith("/9j/") || base64Data.startsWith("iVBORw0KGgo") || base64Data.startsWith("R0lGODlh") || base64Data.startsWith("R0lGODdh") || base64Data.startsWith("UklGR") || base64Data.startsWith("Qk0") || base64Data.startsWith("Qk1") || base64Data.startsWith("SUkq") || base64Data.startsWith("TU0A") || base64Data.startsWith("AAABAA");
	} catch {
		return false;
	}
}
function getMimeTypeFromBase64(base64DataOrUrl) {
	const parsed = require_dataUrl.parseDataUrl(base64DataOrUrl);
	if (parsed) return parsed.mimeType;
	const base64Data = require_dataUrl.extractBase64FromDataUrl(base64DataOrUrl);
	if (base64Data.startsWith("/9j/")) return "image/jpeg";
	else if (base64Data.startsWith("iVBORw0KGgo")) return "image/png";
	else if (base64Data.startsWith("R0lGODlh") || base64Data.startsWith("R0lGODdh")) return "image/gif";
	else if (base64Data.startsWith("UklGR")) return "image/webp";
	else if (base64Data.startsWith("Qk0") || base64Data.startsWith("Qk1")) return "image/bmp";
	else if (base64Data.startsWith("SUkq") || base64Data.startsWith("TU0A")) return "image/tiff";
	else if (base64Data.startsWith("AAABAA")) return "image/x-icon";
	return "image/jpeg";
}
function processImagesInContents(contents, contextVars) {
	if (!contextVars) return contents;
	if (!Array.isArray(contents)) {
		require_logger.logger.warn("[Google] contents is not an array in processImagesInContents", {
			contentsType: typeof contents,
			contentsValue: contents
		});
		return [];
	}
	const base64ToVarName = /* @__PURE__ */ new Map();
	for (const [varName, value] of Object.entries(contextVars)) if (typeof value === "string" && isValidBase64Image(value)) base64ToVarName.set(value, varName);
	return contents.map((content) => {
		if (content.parts) {
			const newParts = [];
			for (const part of content.parts) if (part.text) {
				const lines = part.text.split("\n");
				let foundValidImage = false;
				let currentTextBlock = "";
				const processedParts = [];
				for (const line of lines) {
					const trimmedLine = line.trim();
					if (base64ToVarName.has(trimmedLine) && isValidBase64Image(trimmedLine)) {
						foundValidImage = true;
						if (currentTextBlock.length > 0) {
							processedParts.push({ text: currentTextBlock });
							currentTextBlock = "";
						}
						const mimeType = getMimeTypeFromBase64(trimmedLine);
						const base64Data = require_dataUrl.isDataUrl(trimmedLine) ? require_dataUrl.extractBase64FromDataUrl(trimmedLine) : trimmedLine;
						processedParts.push({ inlineData: {
							mimeType,
							data: base64Data
						} });
					} else {
						if (currentTextBlock.length > 0) currentTextBlock += "\n";
						currentTextBlock += line;
					}
				}
				if (currentTextBlock.length > 0) processedParts.push({ text: currentTextBlock });
				if (foundValidImage) newParts.push(...processedParts);
				else newParts.push(part);
			} else newParts.push(part);
			return {
				...content,
				parts: newParts
			};
		}
		return content;
	});
}
/**
* Parses and processes config-level systemInstruction.
* Handles file loading, string-to-Content conversion, and Nunjucks template rendering.
*
* @param configSystemInstruction - The systemInstruction from config (can be string, Content, or undefined)
* @param contextVars - Variables for Nunjucks template rendering
* @returns Processed Content object or undefined
*/
function parseConfigSystemInstruction(configSystemInstruction, contextVars) {
	if (!configSystemInstruction) return;
	let configInstruction = clone(configSystemInstruction);
	if (typeof configSystemInstruction === "string") configInstruction = loadFile(configSystemInstruction, contextVars);
	if (typeof configInstruction === "string") configInstruction = { parts: [{ text: configInstruction }] };
	if (contextVars && configInstruction) {
		const nunjucks = require_util.getNunjucksEngine();
		for (const part of configInstruction.parts) if (part.text) try {
			part.text = nunjucks.renderString(part.text, contextVars);
		} catch (err) {
			throw new Error(`Unable to render nunjucks in systemInstruction: ${err}`);
		}
	}
	return configInstruction;
}
function geminiFormatAndSystemInstructions(prompt, contextVars, configSystemInstruction, options) {
	let contents = require_fetch.parseChatPrompt(prompt, [{
		parts: [{ text: prompt }],
		role: "user"
	}]);
	const { contents: updatedContents, coerced, systemInstruction: parsedSystemInstruction } = maybeCoerceToGeminiFormat(contents, options);
	if (coerced) {
		require_logger.logger.debug(`Coerced JSON prompt to Gemini format: ${JSON.stringify(contents)}`);
		contents = updatedContents;
	}
	let systemInstruction = parsedSystemInstruction;
	const parsedConfigInstruction = parseConfigSystemInstruction(configSystemInstruction, contextVars);
	if (parsedConfigInstruction) systemInstruction = systemInstruction ? { parts: [...parsedConfigInstruction.parts, ...systemInstruction.parts] } : parsedConfigInstruction;
	contents = processImagesInContents(contents, contextVars);
	return {
		contents,
		systemInstruction
	};
}
/**
* Recursively traverses a JSON schema object and converts
* uppercase type keywords (string values) to lowercase.
* Handles nested objects and arrays within the schema.
* Creates a deep copy to avoid modifying the original schema.
*
* @param {object | any} schemaNode - The current node (object or value) being processed.
* @returns {object | any} - The processed node with type keywords lowercased.
*/
function normalizeSchemaTypes(schemaNode) {
	if (typeof schemaNode !== "object" || schemaNode === null) return schemaNode;
	if (Array.isArray(schemaNode)) return schemaNode.map(normalizeSchemaTypes);
	const newNode = {};
	for (const key in schemaNode) if (Object.prototype.hasOwnProperty.call(schemaNode, key)) {
		const value = schemaNode[key];
		if (key === "type") if (typeof value === "string" && VALID_SCHEMA_TYPES.includes(value)) newNode[key] = value.toLowerCase();
		else if (Array.isArray(value)) newNode[key] = value.map((t) => typeof t === "string" && VALID_SCHEMA_TYPES.includes(t) ? t.toLowerCase() : t);
		else newNode[key] = normalizeSchemaTypes(value);
		else newNode[key] = normalizeSchemaTypes(value);
	}
	return newNode;
}
function parseStringObject(input) {
	if (typeof input === "string") return JSON.parse(input);
	return input;
}
function validateFunctionCall(output, functions, vars) {
	let functionCalls;
	try {
		let parsedOutput = parseStringObject(output);
		if ("toolCall" in parsedOutput) {
			parsedOutput = parsedOutput.toolCall;
			functionCalls = parsedOutput.functionCalls;
		} else if (Array.isArray(parsedOutput)) functionCalls = parsedOutput.filter((obj) => Object.prototype.hasOwnProperty.call(obj, "functionCall")).map((obj) => obj.functionCall);
		else throw new Error("Unrecognized function call format");
	} catch {
		throw new Error(`Google did not return a valid-looking function call: ${JSON.stringify(output)}`);
	}
	const interpolatedFunctions = loadFile(functions, vars);
	for (const functionCall of functionCalls) {
		const functionName = functionCall.name;
		const functionArgs = parseStringObject(functionCall.args);
		const functionSchema = (interpolatedFunctions?.find((f) => "functionDeclarations" in f))?.functionDeclarations?.find((f) => f.name === functionName);
		if (!functionSchema) throw new Error(`Called "${functionName}", but there is no function with that name`);
		if (Object.keys(functionArgs).length !== 0 && functionSchema?.parameters) {
			const parameterSchema = normalizeSchemaTypes(functionSchema.parameters);
			let validate;
			try {
				validate = ajv.compile(parameterSchema);
			} catch (err) {
				throw new Error(`Tool schema doesn't compile with ajv: ${err}. If this is a valid tool schema you may need to reformulate your assertion without is-valid-function-call.`);
			}
			if (!validate(functionArgs)) throw new Error(`Call to "${functionName}":\n${JSON.stringify(functionCall)}\ndoes not match schema:\n${JSON.stringify(validate.errors)}`);
		} else if (!(JSON.stringify(functionArgs) === "{}" && !functionSchema?.parameters)) throw new Error(`Call to "${functionName}":\n${JSON.stringify(functionCall)}\ndoes not match schema:\n${JSON.stringify(functionSchema)}`);
	}
}
/**
* Properties supported by Gemini's function calling API.
* Based on Google's Schema type definition and API documentation.
* @see https://ai.google.dev/api/caching#Schema
*/
const GEMINI_SUPPORTED_SCHEMA_PROPERTIES = new Set([
	"type",
	"format",
	"description",
	"nullable",
	"enum",
	"maxItems",
	"minItems",
	"properties",
	"required",
	"propertyOrdering",
	"items"
]);
/**
* Valid JSON Schema types mapped to Gemini's expected format (uppercase).
*/
const JSON_SCHEMA_TYPE_MAP = {
	string: "STRING",
	number: "NUMBER",
	integer: "INTEGER",
	boolean: "BOOLEAN",
	array: "ARRAY",
	object: "OBJECT",
	null: "STRING"
};
/**
* Recursively sanitizes a JSON Schema for Gemini API compatibility.
*
* - Removes unsupported properties (additionalProperties, $schema, default, title, etc.)
* - Converts type values to uppercase (string → STRING, object → OBJECT)
* - Recursively processes nested schemas in 'properties' and 'items'
*
* @param schema - The JSON Schema object to sanitize
* @returns A sanitized schema compatible with Gemini's function calling API
*/
function sanitizeSchemaForGemini(schema) {
	if (!schema || typeof schema !== "object") return schema;
	const result = {};
	for (const [key, value] of Object.entries(schema)) {
		if (!GEMINI_SUPPORTED_SCHEMA_PROPERTIES.has(key)) continue;
		if (key === "type") if (typeof value === "string") result[key] = JSON_SCHEMA_TYPE_MAP[value.toLowerCase()] || value.toUpperCase();
		else result[key] = value;
		else if (key === "properties" && typeof value === "object" && value !== null) {
			result[key] = {};
			for (const [propName, propSchema] of Object.entries(value)) if (typeof propSchema === "object" && propSchema !== null) result[key][propName] = sanitizeSchemaForGemini(propSchema);
			else result[key][propName] = propSchema;
		} else if (key === "items" && typeof value === "object" && value !== null) result[key] = sanitizeSchemaForGemini(value);
		else result[key] = value;
	}
	return result;
}
/**
* Create a cache discriminator from auth headers.
*
* This is used to ensure different API keys/credentials don't share cached responses.
* The discriminator is included as a custom property in fetchWithCache options,
* which gets included in the cache key automatically.
*
* Security note: We hash auth headers rather than using them directly to avoid
* exposing sensitive credentials in cache keys or logs. The hash is truncated
* to 16 hex characters (64 bits) for brevity - collision probability is acceptably
* low for cache key differentiation (birthday problem: ~4 billion entries needed
* for 50% collision probability).
*
* @param headers - Request headers containing auth info
* @returns A short hash string for cache key differentiation
*/
function createAuthCacheDiscriminator(headers) {
	const authValues = [];
	for (const name of [
		"authorization",
		"x-goog-api-key",
		"x-api-key",
		"api-key",
		"x-goog-user-project"
	]) {
		const value = headers[name] || headers[name.toLowerCase()];
		if (value) authValues.push(`${name}:${value}`);
	}
	if (authValues.length === 0) return "";
	return crypto.default.createHash("sha256").update(authValues.join("|")).digest("hex").substring(0, 16);
}
//#endregion
Object.defineProperty(exports, "CHAT_MODELS", {
	enumerable: true,
	get: function() {
		return CHAT_MODELS;
	}
});
Object.defineProperty(exports, "GoogleAuthManager", {
	enumerable: true,
	get: function() {
		return GoogleAuthManager;
	}
});
Object.defineProperty(exports, "calculateGoogleCost", {
	enumerable: true,
	get: function() {
		return calculateGoogleCost;
	}
});
Object.defineProperty(exports, "collectGroundingMetadata", {
	enumerable: true,
	get: function() {
		return collectGroundingMetadata;
	}
});
Object.defineProperty(exports, "createAuthCacheDiscriminator", {
	enumerable: true,
	get: function() {
		return createAuthCacheDiscriminator;
	}
});
Object.defineProperty(exports, "determineGoogleVertexMode", {
	enumerable: true,
	get: function() {
		return determineGoogleVertexMode;
	}
});
Object.defineProperty(exports, "formatCandidateContents", {
	enumerable: true,
	get: function() {
		return formatCandidateContents;
	}
});
Object.defineProperty(exports, "geminiFormatAndSystemInstructions", {
	enumerable: true,
	get: function() {
		return geminiFormatAndSystemInstructions;
	}
});
Object.defineProperty(exports, "getCandidate", {
	enumerable: true,
	get: function() {
		return getCandidate;
	}
});
Object.defineProperty(exports, "getGoogleAccessToken", {
	enumerable: true,
	get: function() {
		return getGoogleAccessToken;
	}
});
Object.defineProperty(exports, "getGoogleApiKey", {
	enumerable: true,
	get: function() {
		return getGoogleApiKey;
	}
});
Object.defineProperty(exports, "getGoogleClient", {
	enumerable: true,
	get: function() {
		return getGoogleClient;
	}
});
Object.defineProperty(exports, "getLastPromptSafetyRatings", {
	enumerable: true,
	get: function() {
		return getLastPromptSafetyRatings;
	}
});
Object.defineProperty(exports, "hasGoogleDefaultCredentials", {
	enumerable: true,
	get: function() {
		return hasGoogleDefaultCredentials;
	}
});
Object.defineProperty(exports, "isNonCandidateStreamChunk", {
	enumerable: true,
	get: function() {
		return isNonCandidateStreamChunk;
	}
});
Object.defineProperty(exports, "loadCredentials", {
	enumerable: true,
	get: function() {
		return loadCredentials;
	}
});
Object.defineProperty(exports, "mergeGoogleCompletionOptions", {
	enumerable: true,
	get: function() {
		return mergeGoogleCompletionOptions;
	}
});
Object.defineProperty(exports, "mergeParts", {
	enumerable: true,
	get: function() {
		return mergeParts;
	}
});
Object.defineProperty(exports, "normalizeSafetySettings", {
	enumerable: true,
	get: function() {
		return normalizeSafetySettings;
	}
});
Object.defineProperty(exports, "normalizeTools", {
	enumerable: true,
	get: function() {
		return normalizeTools;
	}
});
Object.defineProperty(exports, "parseConfigSystemInstruction", {
	enumerable: true,
	get: function() {
		return parseConfigSystemInstruction;
	}
});
Object.defineProperty(exports, "removeGoogleFunctionDeclarations", {
	enumerable: true,
	get: function() {
		return removeGoogleFunctionDeclarations;
	}
});
Object.defineProperty(exports, "resolveGoogleToolConfig", {
	enumerable: true,
	get: function() {
		return resolveGoogleToolConfig;
	}
});
Object.defineProperty(exports, "resolveProjectId", {
	enumerable: true,
	get: function() {
		return resolveProjectId;
	}
});
Object.defineProperty(exports, "sanitizeSchemaForGemini", {
	enumerable: true,
	get: function() {
		return sanitizeSchemaForGemini;
	}
});
Object.defineProperty(exports, "stripExecutableToolFileReferences", {
	enumerable: true,
	get: function() {
		return stripExecutableToolFileReferences;
	}
});
Object.defineProperty(exports, "validateFunctionCall", {
	enumerable: true,
	get: function() {
		return validateFunctionCall;
	}
});

//# sourceMappingURL=util-DtSnbKEe.cjs.map