import { a as normalizeLowercaseStringOrEmpty } from "./string-coerce-Bje8XVt9.js";
import { i as assertSecretInputResolved } from "./types.secrets-CwOir82x.js";
import { u as isLoopbackIpAddress } from "./ip-DNT2Re3w.js";
import { i as resolveProviderRequestPolicy, r as resolveProviderRequestCapabilities } from "./provider-attribution-zcs62TBO.js";
//#region src/agents/provider-request-config.ts
const FORBIDDEN_HEADER_KEYS = new Set([
	"__proto__",
	"prototype",
	"constructor"
]);
const FORBIDDEN_INSECURE_TLS_MESSAGE = "Provider transport overrides do not allow insecureSkipVerify";
const FORBIDDEN_RUNTIME_TRANSPORT_OVERRIDE_MESSAGE = "Runtime auth request overrides do not allow proxy or TLS transport settings";
function isLoopbackProviderBaseUrl(baseUrl) {
	if (!baseUrl) return false;
	try {
		const host = new URL(baseUrl).hostname.trim().toLowerCase().replace(/\.+$/, "");
		return host === "localhost" || host.endsWith(".localhost") || isLoopbackIpAddress(host);
	} catch {
		return false;
	}
}
function shouldAutoAllowLoopbackModelRequest(params) {
	return params.capability === "llm" && params.transport === "stream" && params.allowPrivateNetwork === void 0 && params.request?.allowPrivateNetwork === void 0 && isLoopbackProviderBaseUrl(params.baseUrl);
}
function sanitizeConfiguredRequestString(value, path) {
	if (typeof value !== "string") {
		assertSecretInputResolved({
			value,
			path
		});
		return;
	}
	const trimmed = value.trim();
	return trimmed ? trimmed : void 0;
}
function sanitizeConfiguredProviderRequest(request) {
	if (!request || typeof request !== "object" || Array.isArray(request)) return;
	let headers;
	if (request.headers && typeof request.headers === "object" && !Array.isArray(request.headers)) {
		const nextHeaders = {};
		for (const [key, value] of Object.entries(request.headers)) {
			const sanitized = sanitizeConfiguredRequestString(value, `request.headers.${key}`);
			if (sanitized) nextHeaders[key] = sanitized;
		}
		if (Object.keys(nextHeaders).length > 0) headers = nextHeaders;
	}
	let auth;
	const rawAuth = request.auth;
	if (rawAuth && typeof rawAuth === "object" && !Array.isArray(rawAuth)) {
		if (rawAuth.mode === "provider-default") auth = { mode: "provider-default" };
		else if (rawAuth.mode === "authorization-bearer") {
			const token = sanitizeConfiguredRequestString(rawAuth.token, "request.auth.token");
			if (token) auth = {
				mode: "authorization-bearer",
				token
			};
		} else if (rawAuth.mode === "header") {
			const headerName = sanitizeConfiguredRequestString(rawAuth.headerName, "request.auth.headerName");
			const value = sanitizeConfiguredRequestString(rawAuth.value, "request.auth.value");
			const prefix = sanitizeConfiguredRequestString(rawAuth.prefix, "request.auth.prefix");
			if (headerName && value) auth = {
				mode: "header",
				headerName,
				value,
				...prefix ? { prefix } : {}
			};
		}
	}
	const sanitizeTls = (tls, pathPrefix) => {
		if (!tls || typeof tls !== "object" || Array.isArray(tls)) return;
		const rawTls = tls;
		const next = {};
		const ca = sanitizeConfiguredRequestString(rawTls.ca, `${pathPrefix}.ca`);
		const cert = sanitizeConfiguredRequestString(rawTls.cert, `${pathPrefix}.cert`);
		const key = sanitizeConfiguredRequestString(rawTls.key, `${pathPrefix}.key`);
		const passphrase = sanitizeConfiguredRequestString(rawTls.passphrase, `${pathPrefix}.passphrase`);
		const serverName = sanitizeConfiguredRequestString(rawTls.serverName, `${pathPrefix}.serverName`);
		if (ca) next.ca = ca;
		if (cert) next.cert = cert;
		if (key) next.key = key;
		if (passphrase) next.passphrase = passphrase;
		if (serverName) next.serverName = serverName;
		if (rawTls.insecureSkipVerify === true) next.insecureSkipVerify = true;
		else if (rawTls.insecureSkipVerify === false) next.insecureSkipVerify = false;
		return Object.keys(next).length > 0 ? next : void 0;
	};
	let proxy;
	const rawProxy = request.proxy;
	if (rawProxy && typeof rawProxy === "object" && !Array.isArray(rawProxy)) {
		const tls = sanitizeTls(rawProxy.tls, "request.proxy.tls");
		if (rawProxy.mode === "env-proxy") proxy = {
			mode: "env-proxy",
			...tls ? { tls } : {}
		};
		else if (rawProxy.mode === "explicit-proxy") {
			const url = sanitizeConfiguredRequestString(rawProxy.url, "request.proxy.url");
			if (url) proxy = {
				mode: "explicit-proxy",
				url,
				...tls ? { tls } : {}
			};
		}
	}
	const tls = sanitizeTls(request.tls, "request.tls");
	if (!headers && !auth && !proxy && !tls) return;
	return {
		...headers ? { headers } : {},
		...auth ? { auth } : {},
		...proxy ? { proxy } : {},
		...tls ? { tls } : {}
	};
}
function sanitizeConfiguredModelProviderRequest(request) {
	const sanitized = sanitizeConfiguredProviderRequest(request);
	const rawAllow = request?.allowPrivateNetwork;
	const allowPrivateNetwork = rawAllow === true ? true : rawAllow === false ? false : void 0;
	if (!sanitized && allowPrivateNetwork === void 0) return;
	return {
		...sanitized,
		...allowPrivateNetwork !== void 0 ? { allowPrivateNetwork } : {}
	};
}
function mergeProviderRequestOverrides(...overrides) {
	const merged = {};
	let hasMerged = false;
	for (const current of overrides) {
		if (!current) continue;
		hasMerged = true;
		if (current.headers) merged.headers = Object.assign({}, merged.headers, current.headers);
		if (current.auth) merged.auth = current.auth;
		if (current.proxy) merged.proxy = current.proxy;
		if (current.tls) merged.tls = current.tls;
	}
	return hasMerged ? merged : void 0;
}
function mergeModelProviderRequestOverrides(...overrides) {
	let merged = mergeProviderRequestOverrides(...overrides);
	for (const current of overrides) if (current?.allowPrivateNetwork !== void 0) {
		merged ??= {};
		merged.allowPrivateNetwork = current.allowPrivateNetwork;
	}
	return merged;
}
function normalizeBaseUrl(baseUrl, fallback) {
	const raw = baseUrl?.trim() || fallback?.trim();
	if (!raw) return;
	return raw.replace(/\/+$/, "");
}
function mergeProviderRequestHeaders(...headerSets) {
	let merged;
	const headerNamesByLowerKey = /* @__PURE__ */ new Map();
	for (const headers of headerSets) {
		if (!headers) continue;
		if (!merged) merged = Object.create(null);
		for (const [key, value] of Object.entries(headers)) {
			const normalizedKey = normalizeLowercaseStringOrEmpty(key);
			if (FORBIDDEN_HEADER_KEYS.has(normalizedKey)) continue;
			const previousKey = headerNamesByLowerKey.get(normalizedKey);
			if (previousKey && previousKey !== key) delete merged[previousKey];
			merged[key] = value;
			headerNamesByLowerKey.set(normalizedKey, key);
		}
	}
	return merged && Object.keys(merged).length > 0 ? merged : void 0;
}
function resolveTlsOverride(tls) {
	if (!tls) return { configured: false };
	if (tls.insecureSkipVerify === true) throw new Error(FORBIDDEN_INSECURE_TLS_MESSAGE);
	const ca = tls.ca?.trim();
	const cert = tls.cert?.trim();
	const key = tls.key?.trim();
	const passphrase = tls.passphrase?.trim();
	const serverName = tls.serverName?.trim();
	const rejectUnauthorized = tls.insecureSkipVerify === false ? true : void 0;
	if (!ca && !cert && !key && !passphrase && !serverName && rejectUnauthorized === void 0) return { configured: false };
	return {
		configured: true,
		...ca ? { ca } : {},
		...cert ? { cert } : {},
		...key ? { key } : {},
		...passphrase ? { passphrase } : {},
		...serverName ? { serverName } : {},
		...rejectUnauthorized !== void 0 ? { rejectUnauthorized } : {}
	};
}
function resolveAuthOverride(params) {
	const auth = params.request?.auth;
	if (auth?.mode === "authorization-bearer") {
		const value = auth.token.trim();
		if (value) return {
			configured: true,
			mode: "authorization-bearer",
			headerName: "Authorization",
			value,
			injectAuthorizationHeader: true
		};
	}
	if (auth?.mode === "header") {
		const headerName = auth.headerName.trim();
		const value = auth.value.trim();
		const prefix = auth.prefix?.trim();
		if (headerName && value) return {
			configured: true,
			mode: "header",
			headerName,
			value,
			...prefix ? { prefix } : {},
			injectAuthorizationHeader: false
		};
	}
	return {
		configured: false,
		mode: params.authHeader ? "authorization-bearer" : "provider-default",
		injectAuthorizationHeader: params.authHeader === true
	};
}
function sanitizeRuntimeProviderRequestOverrides(request) {
	if (!request) return;
	if (request.proxy || request.tls) throw new Error(FORBIDDEN_RUNTIME_TRANSPORT_OVERRIDE_MESSAGE);
	const headers = request.headers;
	const auth = request.auth;
	if (!headers && !auth) return;
	return {
		...headers ? { headers } : {},
		...auth ? { auth } : {}
	};
}
function resolveProxyOverride(request) {
	const proxy = request?.proxy;
	if (!proxy) return { configured: false };
	const tls = resolveTlsOverride(proxy.tls);
	if (proxy.mode === "env-proxy") return {
		configured: true,
		mode: "env-proxy",
		tls
	};
	const proxyUrl = proxy.url.trim();
	if (!proxyUrl) return { configured: false };
	return {
		configured: true,
		mode: "explicit-proxy",
		proxyUrl,
		tls
	};
}
function applyResolvedAuthHeader(headers, auth) {
	if (!auth.configured) return headers;
	const next = mergeProviderRequestHeaders(headers) ?? Object.create(null);
	const keysToDelete = new Set([normalizeLowercaseStringOrEmpty(auth.headerName)]);
	if (auth.mode === "header") keysToDelete.add("authorization");
	for (const key of Object.keys(next)) if (keysToDelete.has(normalizeLowercaseStringOrEmpty(key))) delete next[key];
	next[auth.headerName] = auth.mode === "authorization-bearer" ? `Bearer ${auth.value}` : `${auth.prefix ?? ""}${auth.value}`;
	return Object.keys(next).length > 0 ? next : void 0;
}
function toTlsConnectOptions(tls) {
	if (!tls.configured) return;
	const next = {};
	if (tls.ca) next.ca = tls.ca;
	if (tls.cert) next.cert = tls.cert;
	if (tls.key) next.key = tls.key;
	if (tls.passphrase) next.passphrase = tls.passphrase;
	if (tls.serverName) next.servername = tls.serverName;
	if (tls.rejectUnauthorized !== void 0) next.rejectUnauthorized = tls.rejectUnauthorized;
	return Object.keys(next).length > 0 ? next : void 0;
}
function buildProviderRequestDispatcherPolicy(request) {
	const targetTls = toTlsConnectOptions(request.tls);
	if (!request.proxy.configured) return targetTls ? {
		mode: "direct",
		connect: targetTls
	} : void 0;
	const proxiedTls = toTlsConnectOptions(request.proxy.tls);
	if (request.proxy.mode === "env-proxy") return {
		mode: "env-proxy",
		...targetTls ? { connect: { ...targetTls } } : {},
		...proxiedTls ? { proxyTls: { ...proxiedTls } } : {}
	};
	return {
		mode: "explicit-proxy",
		proxyUrl: request.proxy.proxyUrl,
		...proxiedTls ? { proxyTls: proxiedTls } : {}
	};
}
function buildProviderRequestTlsClientOptions(request) {
	return toTlsConnectOptions(request.tls);
}
function resolveProviderRequestPolicyConfig(params) {
	const baseUrl = normalizeBaseUrl(params.baseUrl, params.defaultBaseUrl);
	const capability = params.capability ?? "llm";
	const transport = params.transport ?? "http";
	const policyInput = {
		provider: params.provider,
		api: params.api,
		baseUrl,
		capability,
		transport
	};
	const policy = resolveProviderRequestPolicy(policyInput);
	const capabilities = resolveProviderRequestCapabilities({
		...policyInput,
		compat: params.compat,
		modelId: params.modelId
	});
	const auth = resolveAuthOverride({
		authHeader: params.authHeader,
		request: params.request
	});
	const extraHeaders = applyResolvedAuthHeader(mergeProviderRequestHeaders(params.discoveredHeaders, params.providerHeaders, params.modelHeaders, params.request?.headers), auth);
	const protectedAttributionKeys = new Set(Object.keys(policy.attributionHeaders ?? {}).map((key) => normalizeLowercaseStringOrEmpty(key)));
	const unprotectedCallerHeaders = params.callerHeaders ? Object.fromEntries(Object.entries(params.callerHeaders).filter(([key]) => !protectedAttributionKeys.has(normalizeLowercaseStringOrEmpty(key)))) : void 0;
	const mergedDefaults = mergeProviderRequestHeaders(extraHeaders, policy.attributionHeaders);
	const headers = params.precedence === "caller-wins" ? mergeProviderRequestHeaders(mergedDefaults, unprotectedCallerHeaders) : mergeProviderRequestHeaders(unprotectedCallerHeaders, mergedDefaults);
	return {
		api: params.api,
		baseUrl,
		headers,
		extraHeaders: {
			configured: Boolean(extraHeaders),
			headers: extraHeaders
		},
		auth,
		proxy: resolveProxyOverride(params.request),
		tls: resolveTlsOverride(params.request?.tls),
		policy,
		capabilities,
		allowPrivateNetwork: params.allowPrivateNetwork ?? params.request?.allowPrivateNetwork ?? shouldAutoAllowLoopbackModelRequest(params)
	};
}
function resolveProviderRequestConfig(params) {
	const resolved = resolveProviderRequestPolicyConfig(params);
	return {
		api: resolved.api,
		baseUrl: resolved.baseUrl,
		headers: resolved.extraHeaders.headers,
		extraHeaders: resolved.extraHeaders,
		auth: resolved.auth,
		proxy: resolved.proxy,
		tls: resolved.tls,
		policy: resolved.policy
	};
}
function resolveProviderRequestHeaders(params) {
	return resolveProviderRequestPolicyConfig({
		provider: params.provider,
		api: params.api,
		baseUrl: params.baseUrl,
		capability: params.capability,
		transport: params.transport,
		callerHeaders: params.callerHeaders,
		providerHeaders: params.defaultHeaders,
		precedence: params.precedence,
		request: params.request
	}).headers;
}
const MODEL_PROVIDER_REQUEST_TRANSPORT_SYMBOL = Symbol.for("openclaw.modelProviderRequestTransport");
function attachModelProviderRequestTransport(model, request) {
	if (!request) return model;
	const next = { ...model };
	next[MODEL_PROVIDER_REQUEST_TRANSPORT_SYMBOL] = request;
	return next;
}
function getModelProviderRequestTransport(model) {
	return model[MODEL_PROVIDER_REQUEST_TRANSPORT_SYMBOL];
}
//#endregion
export { mergeModelProviderRequestOverrides as a, resolveProviderRequestHeaders as c, sanitizeConfiguredProviderRequest as d, sanitizeRuntimeProviderRequestOverrides as f, getModelProviderRequestTransport as i, resolveProviderRequestPolicyConfig as l, buildProviderRequestDispatcherPolicy as n, normalizeBaseUrl as o, buildProviderRequestTlsClientOptions as r, resolveProviderRequestConfig as s, attachModelProviderRequestTransport as t, sanitizeConfiguredModelProviderRequest as u };
