import { c as isRecord } from "./record-coerce-DItp3I4t.js";
import { t as isBlockedObjectKey } from "./prototype-keys-CuYw53fZ.js";
import "./utils-B2aozS-T.js";
import { r as normalizeProviderId } from "./provider-id-DMd-TDFp.js";
import { t as isSafeExecutableValue } from "./exec-safety-DtLGRBJm.js";
import { r as isModelThinkingFormat } from "./types.models-Z6EPRVI_.js";
import { r as resolveUniqueCatalogModelRoute, t as modelTransportRoutesMatch } from "./model-compat-catalog-BNBUeFnX.js";
import { t as planManifestModelCatalogRows } from "./manifest-planner-BpBF2xF-.js";
import { t as listOpenClawPluginManifestMetadata } from "./manifest-metadata-scan-WMzF8wQI.js";
import { r as resolveProviderModelRoutes } from "./provider-model-routes-BwepyywI.js";
import { isDeepStrictEqual } from "node:util";
//#region src/config/legacy.shared.ts
const getRecord = (value) => isRecord(value) ? value : null;
const ensureRecord = (root, key) => {
	const existing = root[key];
	if (isRecord(existing)) return existing;
	const next = {};
	root[key] = next;
	return next;
};
const mergeMissing = (target, source) => {
	for (const [key, value] of Object.entries(source)) {
		if (value === void 0 || isBlockedObjectKey(key)) continue;
		const existing = target[key];
		if (existing === void 0) {
			target[key] = value;
			continue;
		}
		if (isRecord(existing) && isRecord(value)) mergeMissing(existing, value);
	}
};
const mapLegacyAudioTranscription = (value) => {
	const transcriber = getRecord(value);
	const command = Array.isArray(transcriber?.command) ? transcriber?.command : null;
	if (!command || command.length === 0) return null;
	if (typeof command[0] !== "string") return null;
	if (!command.every((part) => typeof part === "string")) return null;
	const rawExecutable = command[0].trim();
	if (!rawExecutable) return null;
	if (!isSafeExecutableValue(rawExecutable)) return null;
	const args = command.slice(1).map((part) => part.replace(/\{input\}/g, "{{AttachmentPath}}"));
	const timeoutSeconds = typeof transcriber?.timeoutSeconds === "number" ? transcriber?.timeoutSeconds : void 0;
	const result = {
		command: rawExecutable,
		type: "cli"
	};
	if (args.length > 0) result.args = args;
	if (timeoutSeconds !== void 0) result.timeoutSeconds = timeoutSeconds;
	return result;
};
const defineLegacyConfigMigration = (migration) => migration;
//#endregion
//#region src/commands/doctor/shared/legacy-config-migrations.runtime.models.catalog.ts
const STALE_CONTEXT_WINDOW_FIXES = {
	"deepseek/deepseek-v4-flash": {
		stale: 2e5,
		correct: 1e6
	},
	"xai/grok-4.20-0309-reasoning": {
		stale: 2e6,
		correct: 1e6
	},
	"xai/grok-4.20-0309-non-reasoning": {
		stale: 2e6,
		correct: 1e6
	},
	"xai/grok-4.20-beta-latest-reasoning": {
		stale: 2e6,
		correct: 1e6
	},
	"xai/grok-4.20-beta-latest-non-reasoning": {
		stale: 2e6,
		correct: 1e6
	},
	"xai/grok-4.20-experimental-beta-0304-reasoning": {
		stale: 2e6,
		correct: 1e6
	},
	"xai/grok-4.20-experimental-beta-0304-non-reasoning": {
		stale: 2e6,
		correct: 1e6
	},
	"xai/grok-4.20-reasoning": {
		stale: 2e6,
		correct: 1e6
	},
	"xai/grok-4.20-non-reasoning": {
		stale: 2e6,
		correct: 1e6
	}
};
const DEAD_MODEL_COMPAT_KEYS = ["nativeWebSearchTool", "requiresMistralToolIds"];
function normalizedCatalogModelKey(provider, modelId) {
	const normalizedProvider = normalizeProviderId(provider);
	const normalizedId = modelId.trim().toLowerCase();
	const providerPrefix = `${normalizedProvider}/`;
	return `${normalizedProvider}::${normalizedId.startsWith(providerPrefix) ? normalizedId.slice(providerPrefix.length) : normalizedId}`;
}
const modelCompatCatalogRowsByProvider = /* @__PURE__ */ new Map();
let modelCompatCatalogPlugins;
function getModelCompatCatalogPlugins() {
	modelCompatCatalogPlugins ??= listOpenClawPluginManifestMetadata().flatMap(({ manifest }) => {
		const id = typeof manifest.id === "string" ? manifest.id.trim() : "";
		const modelCatalog = getRecord(manifest.modelCatalog);
		if (!id || !modelCatalog) return [];
		return [{
			id,
			providers: Array.isArray(manifest.providers) ? manifest.providers.filter((value) => typeof value === "string") : [],
			modelCatalog
		}];
	});
	return modelCompatCatalogPlugins;
}
function buildConfiguredProviderCatalogRows(providers) {
	const rows = /* @__PURE__ */ new Map();
	for (const providerId of Object.keys(providers)) {
		const normalizedProviderId = normalizeProviderId(providerId);
		let providerRows = modelCompatCatalogRowsByProvider.get(normalizedProviderId);
		if (!providerRows) {
			providerRows = planManifestModelCatalogRows({
				registry: { plugins: getModelCompatCatalogPlugins() },
				providerFilter: normalizedProviderId
			}).rows;
			modelCompatCatalogRowsByProvider.set(normalizedProviderId, providerRows);
		}
		for (const row of providerRows) {
			const key = normalizedCatalogModelKey(row.provider, row.id);
			const variants = rows.get(key) ?? [];
			variants.push(row);
			rows.set(key, variants);
		}
	}
	return rows;
}
/** Resolves one catalog identity and whether its configured route remains provider-owned. */
function resolveConfiguredModelCatalogOwnership(params) {
	const modelId = typeof params.model.id === "string" ? params.model.id : "";
	if (!modelId) return;
	const rows = buildConfiguredProviderCatalogRows({ [params.providerId]: params.provider }).get(normalizedCatalogModelKey(params.providerId, modelId));
	const catalogRow = rows?.length === 1 ? rows[0] : void 0;
	if (!catalogRow) return;
	const configuredRoute = {
		api: params.model.api ?? params.provider.api,
		baseUrl: params.model.baseUrl ?? params.provider.baseUrl
	};
	const exactCatalogRoute = modelTransportRoutesMatch(catalogRow, configuredRoute);
	const providerRoutes = resolveProviderModelRoutes({
		provider: params.providerId,
		modelId,
		env: {}
	});
	const providerOwnedRoute = providerRoutes?.kind === "routes" && providerRoutes.routes.some((route) => modelTransportRoutesMatch(route, configuredRoute));
	return {
		catalogRow,
		ownsRoute: exactCatalogRoute || providerOwnedRoute
	};
}
function inspectModelCompatOverrides(providersValue, onEntry) {
	const providers = getRecord(providersValue);
	const total = {
		dead: 0,
		divergent: 0,
		matching: 0
	};
	if (!providers) return total;
	if (!Object.values(providers).some((providerValue) => {
		const models = getRecord(providerValue)?.models;
		return Array.isArray(models) && models.some((modelValue) => Boolean(getRecord(getRecord(modelValue)?.compat)));
	})) return total;
	const catalogRows = buildConfiguredProviderCatalogRows(providers);
	for (const [providerId, providerValue] of Object.entries(providers)) {
		const provider = getRecord(providerValue);
		const models = provider?.models;
		if (!provider || !Array.isArray(models)) continue;
		for (const [modelIndex, modelValue] of models.entries()) {
			const model = getRecord(modelValue);
			const compat = getRecord(model?.compat);
			const modelId = typeof model?.id === "string" ? model.id : "";
			if (!model || !compat || !modelId) continue;
			const state = {
				dead: 0,
				divergent: 0,
				matching: 0
			};
			for (const key of DEAD_MODEL_COMPAT_KEYS) if (Object.hasOwn(compat, key)) state.dead += 1;
			const configuredRoute = {
				api: model.api ?? provider.api,
				baseUrl: model.baseUrl ?? provider.baseUrl
			};
			const catalogRow = resolveUniqueCatalogModelRoute(catalogRows.get(normalizedCatalogModelKey(providerId, modelId)), configuredRoute);
			if (catalogRow !== void 0) {
				const catalogCompat = catalogRow.compat ?? {};
				for (const [key, value] of Object.entries(compat)) {
					if (DEAD_MODEL_COMPAT_KEYS.includes(key)) continue;
					if (isDeepStrictEqual(value, catalogCompat[key])) state.matching += 1;
					else state.divergent += 1;
				}
			}
			total.dead += state.dead;
			total.divergent += state.divergent;
			total.matching += state.matching;
			onEntry?.({
				catalogRow,
				compat,
				model,
				modelIndex,
				provider,
				providerId,
				state
			});
		}
	}
	return total;
}
const MODEL_COMPAT_CATALOG_RULES = [
	{
		path: ["models", "providers"],
		message: "nativeWebSearchTool and requiresMistralToolIds are unused and retired; run \"openclaw doctor --fix\" to remove them.",
		match: (value) => inspectModelCompatOverrides(value).dead > 0
	},
	{
		path: ["models", "providers"],
		message: "Catalog-known model compat values are provider-owned; run \"openclaw doctor --fix\" to remove matching config overrides.",
		match: (value) => inspectModelCompatOverrides(value).matching > 0
	},
	{
		path: ["models", "providers"],
		message: "Catalog-known model compat differs from the provider catalog and was preserved for review. Use a distinct custom route when the endpoint really has different capabilities.",
		match: (value) => inspectModelCompatOverrides(value).divergent > 0
	}
];
function migrateModelCompatCatalogOwnership(raw, changes) {
	inspectModelCompatOverrides(getRecord(getRecord(raw.models)?.providers), ({ catalogRow, compat, model, modelIndex, provider, providerId }) => {
		const removed = [];
		for (const key of DEAD_MODEL_COMPAT_KEYS) if (Object.hasOwn(compat, key)) {
			delete compat[key];
			removed.push(key);
		}
		if (catalogRow && modelTransportRoutesMatch(catalogRow, {
			api: model.api ?? provider.api ?? catalogRow.api,
			baseUrl: model.baseUrl ?? provider.baseUrl ?? catalogRow.baseUrl
		})) {
			const catalogCompat = catalogRow.compat ?? {};
			for (const [key, value] of Object.entries(compat)) if (isDeepStrictEqual(value, catalogCompat[key])) {
				delete compat[key];
				removed.push(key);
			}
		}
		if (removed.length === 0) return;
		if (Object.keys(compat).length === 0) delete model.compat;
		changes.push(`Removed models.providers.${providerId}.models.${modelIndex}.compat catalog/dead overrides: ${removed.toSorted().join(", ")}.`);
	});
}
function resolveStaleContextWindowFix(params) {
	const providerId = params.providerId.trim().toLowerCase();
	const modelId = params.modelId.trim().toLowerCase();
	const providerPrefix = `${providerId}/`;
	const scopedModelId = `${providerId}/${modelId.startsWith(providerPrefix) ? modelId.slice(providerPrefix.length) : modelId}`;
	const fix = STALE_CONTEXT_WINDOW_FIXES[scopedModelId];
	return fix && params.contextWindow === fix.stale ? fix : void 0;
}
function hasStaleContextWindowValue(providers) {
	const providersRecord = getRecord(providers);
	if (!providersRecord) return false;
	for (const [providerId, provider] of Object.entries(providersRecord)) {
		const models = getRecord(provider)?.models;
		if (!Array.isArray(models)) continue;
		for (const model of models) {
			const modelRecord = getRecord(model);
			const modelId = typeof modelRecord?.id === "string" ? modelRecord.id : void 0;
			const contextWindow = modelRecord?.contextWindow;
			if (!modelId || typeof contextWindow !== "number" || !Number.isFinite(contextWindow)) continue;
			if (resolveStaleContextWindowFix({
				providerId,
				modelId,
				contextWindow
			})) return true;
		}
	}
	return false;
}
function hasInvalidThinkingFormat(providers) {
	const providersRecord = getRecord(providers);
	if (!providersRecord) return false;
	for (const provider of Object.values(providersRecord)) {
		const models = getRecord(provider)?.models;
		if (!Array.isArray(models)) continue;
		for (const model of models) {
			const thinkingFormat = getRecord(getRecord(model)?.compat)?.thinkingFormat;
			if (typeof thinkingFormat === "string" && !isModelThinkingFormat(thinkingFormat)) return true;
		}
	}
	return false;
}
//#endregion
export { resolveConfiguredModelCatalogOwnership as a, ensureRecord as c, mergeMissing as d, migrateModelCompatCatalogOwnership as i, getRecord as l, hasInvalidThinkingFormat as n, resolveStaleContextWindowFix as o, hasStaleContextWindowValue as r, defineLegacyConfigMigration as s, MODEL_COMPAT_CATALOG_RULES as t, mapLegacyAudioTranscription as u };
