import { a as normalizeLowercaseStringOrEmpty, c as normalizeOptionalString } from "./string-coerce-DW4mBlAt.js";
import { b as parseStrictPositiveInteger } from "./number-coercion-CJQ8TR--.js";
import { _ as resolveSessionAgentId } from "./agent-scope-uF6sww3K.js";
import { a as resolveAgentDir, o as resolveAgentWorkspaceDir } from "./agent-scope-config-BGhyaQxC.js";
import { n as resolveDefaultAgentWorkspaceDir } from "./workspace-default-h9TzWSvp.js";
import { r as getCurrentPluginMetadataSnapshot } from "./current-plugin-metadata-snapshot-BRGfHyP_.js";
import { a as listOpenAIAuthProfileProvidersForAgentRuntime, p as openAIModelCatalogRoutePolicy } from "./openai-routing-D3lruFAk.js";
import { t as resolveAgentHarnessPolicy } from "./policy-7OqEPS72.js";
import { _ as resolveBareModelDefaultProvider, f as modelCatalogLogicalKey, i as buildModelAliasIndex, x as resolveModelRefFromString } from "./model-selection-shared-CHgH9Zpi.js";
import { o as normalizeProviderId } from "./model-selection-normalize-C8CoAiXe.js";
import { r as resolveDefaultModelForAgent } from "./codex-plugin-diagnostics-NiiKabys.js";
import { t as getChannelPlugin } from "./registry-C4wI3qQi.js";
import "./plugins-CM60lhmn.js";
import "./model-selection-BKPLWl62.js";
import { r as loadModelCatalogSnapshot } from "./model-catalog-J4TN7Emd.js";
import "./workspace-BgBtNT1e.js";
import { n as createProviderAuthChecker } from "./model-provider-auth-BROygjtN.js";
import { n as listCliRuntimeModelBackendBindings } from "./cli-backends-DhaFiH1U.js";
import { n as createModelVisibilityPolicy, t as RUNTIME_MODEL_VISIBILITY_NORMALIZATION } from "./model-visibility-policy-DzAtBe7K.js";
import { r as rejectUnauthorizedCommand } from "./command-gates-Buv3rnd6.js";
import { t as resolveAgentRuntimeLabel } from "./agent-runtime-label-CvWfHBSa.js";
import { t as resolveModelAuthLabel } from "./model-auth-label-Btwvq83y.js";
import { n as loadModelCatalogSnapshotForBrowse } from "./model-catalog-browse-CXqnrtoA.js";
import { n as resolveLogicalVisibleModelCatalog, t as resolveLogicalModelCatalogEntryState } from "./model-catalog-visibility-B7v5yWXa.js";
import { n as isRetiredModelPickerProvider } from "./model-picker-visibility-28-K5miM.js";
//#region src/auto-reply/reply/commands-models.ts
const PAGE_SIZE_DEFAULT = 20;
const PAGE_SIZE_MAX = 100;
const MODELS_ADD_DEPRECATED_TEXT = "⚠️ /models add is deprecated. Use /models to browse providers and /model to switch models.";
function isModelsBrowseVisibleProvider(provider) {
	return !isRetiredModelPickerProvider(provider);
}
function usesUnfilteredCatalogModels(provider, cliRuntimeProviders) {
	return cliRuntimeProviders.has(normalizeProviderId(provider));
}
function normalizeRuntimeChoiceId(runtime) {
	const normalized = normalizeLowercaseStringOrEmpty(runtime);
	if (!normalized || normalized === "auto" || normalized === "default") return "openclaw";
	return normalized;
}
function buildRuntimeChoice(params) {
	const id = normalizeRuntimeChoiceId(params.runtime);
	const label = resolveAgentRuntimeLabel({
		config: params.cfg,
		resolvedHarness: id
	});
	return {
		id,
		label,
		description: id === "openclaw" ? "Use the built-in OpenClaw runtime." : params.cli ? `Run ${params.provider} models through ${label}.` : `Use the ${label} runtime selected by the effective harness policy.`
	};
}
function buildDefaultRuntimeChoice(params) {
	const harnessPolicy = resolveAgentHarnessPolicy({
		config: params.cfg,
		provider: params.provider,
		modelId: params.modelId,
		agentId: params.agentId
	});
	return buildRuntimeChoice({
		cfg: params.cfg,
		provider: params.provider,
		runtime: harnessPolicy.runtime
	});
}
function addRuntimeChoice(choices, choice) {
	if (!choices.some((existing) => existing.id === choice.id)) choices.push(choice);
	return choices;
}
async function buildModelsProviderData(cfg, agentId, options = {}) {
	const resolvedDefault = resolveDefaultModelForAgent({
		cfg,
		agentId
	});
	const workspaceDir = options.workspaceDir ?? (agentId ? resolveAgentWorkspaceDir(cfg, agentId) : void 0) ?? resolveDefaultAgentWorkspaceDir();
	const metadataSnapshot = getCurrentPluginMetadataSnapshot({
		config: cfg,
		workspaceDir,
		env: process.env,
		allowScopedSnapshot: true
	});
	const cliRuntimeProviders = new Set(listCliRuntimeModelBackendBindings().map((binding) => normalizeProviderId(binding.runtime)));
	const snapshot = await loadModelCatalogSnapshotForBrowse({
		cfg,
		view: options.view ?? "default",
		loadCatalog: ({ readOnly }) => loadModelCatalogSnapshot({
			config: cfg,
			readOnly,
			metadataSnapshot
		})
	});
	const catalog = snapshot.entries;
	const visibilityPolicy = createModelVisibilityPolicy({
		cfg,
		catalog,
		defaultProvider: resolvedDefault.provider,
		defaultModel: resolvedDefault.model,
		agentId,
		...RUNTIME_MODEL_VISIBILITY_NORMALIZATION
	});
	const authChecker = createProviderAuthChecker({
		cfg,
		workspaceDir,
		agentId,
		allowPluginSyntheticAuth: false,
		discoverExternalCliAuth: false,
		allowPreparedRuntimeAuth: true
	});
	const logicalModelKey = (entry) => openAIModelCatalogRoutePolicy.resolveIdentity(entry)?.key ?? modelCatalogLogicalKey(entry);
	const incompatibleModelKeys = /* @__PURE__ */ new Set();
	const hasAuth = options.view === "all" ? async () => true : authChecker;
	const visibleCatalog = await resolveLogicalVisibleModelCatalog({
		cfg,
		catalog,
		defaultProvider: resolvedDefault.provider,
		defaultModel: resolvedDefault.model,
		agentId,
		workspaceDir,
		view: options.view,
		routePolicy: openAIModelCatalogRoutePolicy,
		routeVariants: snapshot.routeVariants,
		evaluateEntry: async (entry, routeVariants) => {
			const identity = openAIModelCatalogRoutePolicy.resolveIdentity(entry);
			const evaluation = await authChecker.evaluateModelAuth(entry.provider, {
				modelId: identity?.id ?? entry.id,
				observedRoutes: routeVariants.map((variant) => ({
					api: variant.api,
					baseUrl: variant.baseUrl
				}))
			});
			if (evaluation.routeResolution?.kind === "incompatible") incompatibleModelKeys.add(logicalModelKey(entry));
			return resolveLogicalModelCatalogEntryState({
				entry,
				evaluation,
				authBacked: options.view === "all" || evaluation.availability === true,
				routePolicy: openAIModelCatalogRoutePolicy
			});
		}
	});
	const aliasIndex = buildModelAliasIndex({
		cfg,
		defaultProvider: resolvedDefault.provider
	});
	const restrictToProviderWildcards = options.view !== "all" && visibilityPolicy.hasProviderWildcards;
	const byProvider = /* @__PURE__ */ new Map();
	const add = (p, m) => {
		const key = normalizeProviderId(p);
		if (!isModelsBrowseVisibleProvider(key)) return;
		if (restrictToProviderWildcards && !usesUnfilteredCatalogModels(key, cliRuntimeProviders) && !visibilityPolicy.allows({
			provider: key,
			model: m
		})) return;
		const set = byProvider.get(key) ?? /* @__PURE__ */ new Set();
		set.add(m);
		byProvider.set(key, set);
	};
	const addRawModelRef = (raw) => {
		const trimmed = normalizeOptionalString(raw);
		if (!trimmed) return;
		const resolved = resolveModelRefFromString({
			raw: trimmed,
			defaultProvider: !trimmed.includes("/") ? resolveBareModelDefaultProvider({
				cfg,
				catalog,
				model: trimmed,
				defaultProvider: resolvedDefault.provider
			}) : resolvedDefault.provider,
			aliasIndex
		});
		if (!resolved) return;
		if (incompatibleModelKeys.has(logicalModelKey({
			provider: resolved.ref.provider,
			id: resolved.ref.model
		}))) return;
		add(resolved.ref.provider, resolved.ref.model);
	};
	const addModelConfigEntries = () => {
		const modelConfig = cfg.agents?.defaults?.model;
		if (typeof modelConfig === "string") addRawModelRef(modelConfig);
		else if (modelConfig && typeof modelConfig === "object") {
			addRawModelRef(modelConfig.primary);
			for (const fallback of modelConfig.fallbacks ?? []) addRawModelRef(fallback);
		}
		const imageConfig = cfg.agents?.defaults?.imageModel;
		if (typeof imageConfig === "string") addRawModelRef(imageConfig);
		else if (imageConfig && typeof imageConfig === "object") {
			addRawModelRef(imageConfig.primary);
			for (const fallback of imageConfig.fallbacks ?? []) addRawModelRef(fallback);
		}
	};
	for (const entry of visibleCatalog) {
		if (incompatibleModelKeys.has(logicalModelKey(entry))) continue;
		add(entry.provider, entry.id);
	}
	for (const entry of catalog) if (usesUnfilteredCatalogModels(entry.provider, cliRuntimeProviders) && await hasAuth(entry.provider, {
		modelId: entry.id,
		api: entry.api,
		baseUrl: entry.baseUrl
	})) add(entry.provider, entry.id);
	for (const raw of visibilityPolicy.exactModelRefs) addRawModelRef(raw);
	if (!incompatibleModelKeys.has(logicalModelKey({
		provider: resolvedDefault.provider,
		id: resolvedDefault.model
	}))) add(resolvedDefault.provider, resolvedDefault.model);
	addModelConfigEntries();
	const providers = [...byProvider.keys()].toSorted();
	const modelNames = /* @__PURE__ */ new Map();
	for (const entry of [...catalog, ...visibleCatalog]) if (entry.name && entry.name !== entry.id) modelNames.set(`${normalizeProviderId(entry.provider)}/${entry.id}`, entry.name);
	const runtimeChoicesByProvider = /* @__PURE__ */ new Map();
	const runtimeBindings = [{
		provider: "openai",
		runtime: "codex",
		cli: false
	}, ...listCliRuntimeModelBackendBindings().map((binding) => ({
		provider: binding.provider,
		runtime: binding.runtime,
		cli: true
	}))];
	for (const binding of runtimeBindings) {
		const provider = normalizeProviderId(binding.provider);
		const defaultModelId = provider === normalizeProviderId(resolvedDefault.provider) ? resolvedDefault.model : void 0;
		const choices = runtimeChoicesByProvider.get(provider) ?? [buildDefaultRuntimeChoice({
			cfg,
			agentId,
			provider,
			modelId: defaultModelId
		})];
		addRuntimeChoice(choices, buildRuntimeChoice({
			cfg,
			provider,
			runtime: "openclaw"
		}));
		addRuntimeChoice(choices, buildRuntimeChoice({
			cfg,
			provider,
			runtime: binding.runtime,
			cli: binding.cli
		}));
		runtimeChoicesByProvider.set(provider, choices);
	}
	return {
		byProvider,
		providers,
		resolvedDefault,
		modelNames,
		runtimeChoicesByProvider
	};
}
function formatProviderLine(params) {
	return `- ${params.provider} (${params.count})`;
}
function parseListArgs(tokens) {
	const provider = normalizeOptionalString(tokens[0]);
	let page = 1;
	let all = false;
	for (const token of tokens.slice(1)) {
		const lower = normalizeLowercaseStringOrEmpty(token);
		if (lower === "all" || lower === "--all") {
			all = true;
			continue;
		}
		if (lower.startsWith("page=")) {
			const value = parseStrictPositiveInteger(lower.slice(5));
			if (value !== void 0) page = value;
			continue;
		}
		const pageToken = parseStrictPositiveInteger(lower);
		if (pageToken !== void 0) page = pageToken;
	}
	let pageSize = PAGE_SIZE_DEFAULT;
	for (const token of tokens) {
		const lower = normalizeLowercaseStringOrEmpty(token);
		if (lower.startsWith("limit=") || lower.startsWith("size=")) {
			const value = parseStrictPositiveInteger(lower.slice(lower.indexOf("=") + 1));
			if (value !== void 0) pageSize = Math.min(PAGE_SIZE_MAX, value);
		}
	}
	return {
		action: "list",
		provider: provider ? normalizeProviderId(provider) : void 0,
		page,
		pageSize,
		all
	};
}
function parseModelsArgs(raw) {
	const trimmed = raw.trim();
	if (!trimmed) return { action: "providers" };
	const tokens = trimmed.split(/\s+/g).filter(Boolean);
	switch (normalizeLowercaseStringOrEmpty(tokens[0])) {
		case "providers": return { action: "providers" };
		case "list": return parseListArgs(tokens.slice(1));
		case "add": return {
			action: "add",
			provider: normalizeOptionalString(tokens[1]),
			modelId: normalizeOptionalString(tokens.slice(2).join(" "))
		};
		default: return parseListArgs(tokens);
	}
}
function resolveProviderLabel(params) {
	const harnessPolicy = resolveAgentHarnessPolicy({
		config: params.cfg,
		provider: params.provider,
		agentId: params.agentId
	});
	const acceptedProviderIds = listOpenAIAuthProfileProvidersForAgentRuntime({
		provider: params.provider,
		harnessRuntime: harnessPolicy.runtime,
		config: params.cfg
	});
	const authLabel = resolveModelAuthLabel({
		provider: params.provider,
		acceptedProviderIds,
		cfg: params.cfg,
		sessionEntry: params.sessionEntry,
		agentDir: params.agentDir,
		workspaceDir: params.workspaceDir
	});
	if (!authLabel || authLabel === "unknown") return params.provider;
	return `${params.provider} · 🔑 ${authLabel}`;
}
function formatModelsAvailableHeader(params) {
	return `Models (${resolveProviderLabel({
		provider: params.provider,
		cfg: params.cfg,
		agentId: params.agentId,
		agentDir: params.agentDir,
		workspaceDir: params.workspaceDir,
		sessionEntry: params.sessionEntry
	})}) — ${params.total} available`;
}
function buildModelsMenuText(params) {
	return [
		"Providers:",
		...params.providers.map((provider) => formatProviderLine({
			provider,
			count: params.byProvider.get(provider)?.size ?? 0
		})),
		"",
		"Use: /models <provider>",
		"Switch: /model <provider/model>"
	].join("\n");
}
function buildProviderInfos(params) {
	return params.providers.map((provider) => ({
		id: provider,
		count: params.byProvider.get(provider)?.size ?? 0
	}));
}
async function resolveModelsCommandReply(params) {
	const body = params.commandBodyNormalized.trim();
	if (!body.startsWith("/models")) return null;
	const parsed = parseModelsArgs(body.replace(/^\/models\b/i, "").trim());
	const { byProvider, providers, modelNames } = await buildModelsProviderData(params.cfg, params.agentId, {
		...parsed.action === "list" && parsed.all ? { view: "all" } : {},
		workspaceDir: params.workspaceDir
	});
	const commandPlugin = params.surface ? getChannelPlugin(params.surface) : null;
	const providerInfos = buildProviderInfos({
		providers,
		byProvider
	});
	if (parsed.action === "providers") {
		const channelData = commandPlugin?.commands?.buildModelsMenuChannelData?.({ providers: providerInfos }) ?? commandPlugin?.commands?.buildModelsProviderChannelData?.({ providers: providerInfos });
		if (channelData) return {
			text: "Select a provider:",
			channelData
		};
		return { text: buildModelsMenuText({
			providers,
			byProvider
		}) };
	}
	if (parsed.action === "add") return { text: MODELS_ADD_DEPRECATED_TEXT };
	const { provider, page, pageSize, all } = parsed;
	if (!provider) {
		const channelData = commandPlugin?.commands?.buildModelsProviderChannelData?.({ providers: providerInfos });
		if (channelData) return {
			text: "Select a provider:",
			channelData
		};
		return { text: buildModelsMenuText({
			providers,
			byProvider
		}) };
	}
	if (!byProvider.has(provider)) return { text: [
		`Unknown provider: ${provider}`,
		"",
		"Available providers:",
		...providers.map((entry) => `- ${entry}`),
		"",
		"Use: /models <provider>"
	].join("\n") };
	const models = [...byProvider.get(provider) ?? /* @__PURE__ */ new Set()].toSorted();
	const total = models.length;
	if (total === 0) return { text: [
		`Models (${resolveProviderLabel({
			provider,
			cfg: params.cfg,
			agentId: params.agentId,
			agentDir: params.agentDir,
			workspaceDir: params.workspaceDir,
			sessionEntry: params.sessionEntry
		})}) — none`,
		"",
		"Browse: /models",
		"Switch: /model <provider/model>"
	].join("\n") };
	const interactivePageSize = 8;
	const interactiveTotalPages = Math.max(1, Math.ceil(total / interactivePageSize));
	const interactivePage = Math.max(1, Math.min(page, interactiveTotalPages));
	const interactiveChannelData = commandPlugin?.commands?.buildModelsListChannelData?.({
		provider,
		models,
		currentModel: params.currentModel,
		currentPage: interactivePage,
		totalPages: interactiveTotalPages,
		pageSize: interactivePageSize,
		modelNames
	});
	if (interactiveChannelData) return {
		text: formatModelsAvailableHeader({
			provider,
			total,
			cfg: params.cfg,
			agentId: params.agentId,
			agentDir: params.agentDir,
			workspaceDir: params.workspaceDir,
			sessionEntry: params.sessionEntry
		}),
		channelData: interactiveChannelData
	};
	const effectivePageSize = all ? total : pageSize;
	const pageCount = effectivePageSize > 0 ? Math.ceil(total / effectivePageSize) : 1;
	const safePage = all ? 1 : Math.max(1, Math.min(page, pageCount));
	if (!all && page !== safePage) return { text: [
		`Page out of range: ${page} (valid: 1-${pageCount})`,
		"",
		`Try: /models list ${provider} ${safePage}`,
		`All: /models list ${provider} all`
	].join("\n") };
	const startIndex = (safePage - 1) * effectivePageSize;
	const endIndexExclusive = Math.min(total, startIndex + effectivePageSize);
	const pageModels = models.slice(startIndex, endIndexExclusive);
	const lines = [`Models (${resolveProviderLabel({
		provider,
		cfg: params.cfg,
		agentId: params.agentId,
		agentDir: params.agentDir,
		workspaceDir: params.workspaceDir,
		sessionEntry: params.sessionEntry
	})}) — showing ${startIndex + 1}-${endIndexExclusive} of ${total} (page ${safePage}/${pageCount})`];
	for (const id of pageModels) lines.push(`- ${provider}/${id}`);
	lines.push("", "Switch: /model <provider/model>");
	if (!all && safePage < pageCount) lines.push(`More: /models list ${provider} ${safePage + 1}`);
	if (!all) lines.push(`All: /models list ${provider} all`);
	return { text: lines.join("\n") };
}
const handleModelsCommand = async (params, allowTextCommands) => {
	if (!allowTextCommands) return null;
	const commandBodyNormalized = params.command.commandBodyNormalized.trim();
	if (!commandBodyNormalized.startsWith("/models")) return null;
	const parsed = parseModelsArgs(commandBodyNormalized.replace(/^\/models\b/i, "").trim());
	const unauthorized = rejectUnauthorizedCommand(params, "/models");
	if (unauthorized) return unauthorized;
	if (parsed.action === "add") return {
		shouldContinue: false,
		reply: { text: MODELS_ADD_DEPRECATED_TEXT }
	};
	const modelsAgentId = params.sessionKey ? resolveSessionAgentId({
		sessionKey: params.sessionKey,
		config: params.cfg
	}) : params.agentId ?? "main";
	const currentAgentId = params.agentId ?? "main";
	const modelsAgentDir = modelsAgentId === currentAgentId && params.agentDir ? params.agentDir : resolveAgentDir(params.cfg, modelsAgentId);
	const targetSessionEntry = params.sessionStore?.[params.sessionKey] ?? params.sessionEntry;
	const reply = await resolveModelsCommandReply({
		cfg: params.cfg,
		commandBodyNormalized,
		surface: params.ctx.Surface,
		currentModel: params.model ? `${params.provider}/${params.model}` : void 0,
		agentId: modelsAgentId,
		agentDir: modelsAgentDir,
		workspaceDir: targetSessionEntry?.spawnedWorkspaceDir ?? (modelsAgentId === currentAgentId ? params.workspaceDir : void 0),
		sessionEntry: targetSessionEntry
	});
	if (!reply) return null;
	return {
		reply,
		shouldContinue: false
	};
};
//#endregion
export { resolveModelsCommandReply as i, formatModelsAvailableHeader as n, handleModelsCommand as r, buildModelsProviderData as t };
