// Force strict mode and setup for ESM
"use strict";
import {
  resolveModelConfig,
  resolveProviderProtocol
} from "./chunk-VDNAD6JC.js";
import {
  external_exports
} from "./chunk-H6XPXXMH.js";
import {
  stripRuntimeSnapshotPrefix
} from "./chunk-QP2X3YUW.js";
import {
  REASONING_EFFORT_TIERS,
  normalizeReasoningEffort
} from "./chunk-DGEIYUC3.js";
import {
  AuthType,
  MODEL_GENERATION_CONFIG_FIELDS
} from "./chunk-O4Z6JR7D.js";
import {
  init_esbuild_shims
} from "./chunk-5O2XNYP6.js";
import {
  __name
} from "./chunk-J2S4EL5Y.js";

// packages/cli/src/utils/acpModelUtils.ts
init_esbuild_shims();
import { createHash } from "node:crypto";
var ACP_ROUTE_ID_PREFIX = "qwen-route:v1:";
function getRouteEndpointIdentity(baseUrl) {
  if (!baseUrl) return null;
  try {
    const url = new URL(baseUrl);
    url.username = "";
    url.password = "";
    url.search = "";
    url.hash = "";
    return url.href;
  } catch {
    return sanitizeProviderBaseUrl(baseUrl).split(/[?#]/, 1)[0] ?? null;
  }
}
__name(getRouteEndpointIdentity, "getRouteEndpointIdentity");
function formatAcpModelId(modelId, authType) {
  return `${modelId}(${authType})`;
}
__name(formatAcpModelId, "formatAcpModelId");
function buildAcpModelOptions(models) {
  const candidates = models.filter(
    (model) => model.fastOnly !== true && model.voiceOnly !== true && model.imageOnly !== true
  ).map((model) => {
    const effectiveModelId = model.isRuntimeModel && model.runtimeSnapshotId ? model.runtimeSnapshotId : model.id;
    return {
      model,
      effectiveModelId,
      legacyModelId: formatAcpModelId(effectiveModelId, model.authType)
    };
  });
  const counts = /* @__PURE__ */ new Map();
  for (const candidate of candidates) {
    counts.set(
      candidate.legacyModelId,
      (counts.get(candidate.legacyModelId) ?? 0) + 1
    );
  }
  const discriminators = /* @__PURE__ */ new Set();
  return candidates.map(({ model, effectiveModelId, legacyModelId }) => {
    const discriminator = [
      legacyModelId,
      model.label,
      model.envKey ?? null,
      model.registryBaseUrl === void 0,
      getRouteEndpointIdentity(model.registryBaseUrl ?? model.baseUrl)
    ];
    const discriminatorKey = JSON.stringify(discriminator);
    if (counts.get(legacyModelId) !== 1 && discriminators.has(discriminatorKey)) {
      throw new Error(
        `ACP model routes for "${legacyModelId}" need distinct names, envKey values, or public endpoints.`
      );
    }
    discriminators.add(discriminatorKey);
    return {
      model,
      effectiveModelId,
      modelId: counts.get(legacyModelId) === 1 ? legacyModelId : `${ACP_ROUTE_ID_PREFIX}${createHash("sha256").update(discriminatorKey).digest("base64url").slice(0, 16)}`
    };
  });
}
__name(buildAcpModelOptions, "buildAcpModelOptions");
function resolveAcpModelOption(input, models) {
  const matched = buildAcpModelOptions(models).find(
    (option) => option.modelId === input.trim()
  );
  if (!matched) return null;
  return {
    modelId: matched.effectiveModelId,
    authType: matched.model.authType,
    ...matched.model.registryBaseUrl !== void 0 ? { baseUrl: matched.model.registryBaseUrl } : {},
    ...!matched.model.isRuntimeModel ? { registryBaseUrl: matched.model.registryBaseUrl ?? null } : {},
    isRuntime: matched.model.isRuntimeModel === true
  };
}
__name(resolveAcpModelOption, "resolveAcpModelOption");
function getCurrentAcpModelId(options, modelId, authType, registryBaseUrl) {
  if (!modelId || !authType) return modelId;
  const matching = options.filter(
    (option) => option.effectiveModelId === modelId && option.model.authType === authType
  );
  if (matching[0]?.model.isRuntimeModel) return matching[0].modelId;
  if (registryBaseUrl !== void 0) {
    const exact = matching.find(
      (option) => (option.model.registryBaseUrl ?? null) === registryBaseUrl
    );
    return exact?.modelId ?? modelId;
  }
  return matching.length === 1 ? matching[0].modelId : formatAcpModelId(modelId, authType);
}
__name(getCurrentAcpModelId, "getCurrentAcpModelId");
function sanitizeProviderBaseUrl(baseUrl) {
  const scheme = baseUrl.match(/^[A-Za-z][A-Za-z\d+.-]*:\/\//);
  if (!scheme) {
    return baseUrl;
  }
  const authorityStart = scheme[0].length;
  const stripAt = /* @__PURE__ */ __name((at) => `${baseUrl.slice(0, authorityStart)}${baseUrl.slice(at + 1)}`, "stripAt");
  const authorityEnd = findAuthorityEnd(baseUrl, authorityStart);
  const authorityAt = baseUrl.slice(authorityStart, authorityEnd).lastIndexOf("@");
  const authorityAtIndex = authorityAt === -1 ? -1 : authorityStart + authorityAt;
  try {
    const parsed = new URL(baseUrl);
    if (parsed.username || parsed.password) {
      return authorityAtIndex >= authorityStart ? stripAt(authorityAtIndex) : baseUrl;
    }
    return baseUrl;
  } catch {
    if (authorityAtIndex >= authorityStart) {
      return stripAt(authorityAtIndex);
    }
    const fallbackAt = findUnescapedUserInfoFallbackAt(
      baseUrl,
      authorityStart,
      authorityEnd
    );
    return fallbackAt === -1 ? baseUrl : stripAt(fallbackAt);
  }
}
__name(sanitizeProviderBaseUrl, "sanitizeProviderBaseUrl");
function findUnescapedUserInfoFallbackAt(baseUrl, authorityStart, authorityEnd) {
  const at = baseUrl.lastIndexOf("@");
  if (at < authorityStart || authorityEnd >= at) {
    return -1;
  }
  const colon = baseUrl.indexOf(":", authorityStart);
  if (colon === -1 || colon > authorityEnd) {
    return -1;
  }
  const portCandidate = baseUrl.slice(colon + 1, authorityEnd);
  return /^\d+$/.test(portCandidate) ? -1 : at;
}
__name(findUnescapedUserInfoFallbackAt, "findUnescapedUserInfoFallbackAt");
function findAuthorityEnd(baseUrl, authorityStart) {
  const slash = baseUrl.indexOf("/", authorityStart);
  const query = baseUrl.indexOf("?", authorityStart);
  const hash = baseUrl.indexOf("#", authorityStart);
  let end = baseUrl.length;
  if (slash !== -1) end = Math.min(end, slash);
  if (query !== -1) end = Math.min(end, query);
  if (hash !== -1) end = Math.min(end, hash);
  return end;
}
__name(findAuthorityEnd, "findAuthorityEnd");
function parseAcpBaseModelId(value) {
  const trimmed = value.trim();
  const closeIdx = trimmed.lastIndexOf(")");
  const openIdx = trimmed.lastIndexOf("(");
  if (openIdx >= 0 && closeIdx === trimmed.length - 1 && openIdx < closeIdx) {
    return trimmed.slice(0, openIdx);
  }
  return trimmed;
}
__name(parseAcpBaseModelId, "parseAcpBaseModelId");
function parseAcpModelOption(input) {
  const trimmed = input.trim();
  const closeIdx = trimmed.lastIndexOf(")");
  const openIdx = trimmed.lastIndexOf("(");
  if (openIdx >= 0 && closeIdx === trimmed.length - 1 && openIdx < closeIdx) {
    const maybeModelId = trimmed.slice(0, openIdx);
    const maybeAuthType = trimmed.slice(openIdx + 1, closeIdx);
    const parsedAuthType = external_exports.nativeEnum(AuthType).safeParse(maybeAuthType);
    if (parsedAuthType.success) {
      return { modelId: maybeModelId, authType: parsedAuthType.data };
    }
  }
  return { modelId: trimmed };
}
__name(parseAcpModelOption, "parseAcpModelOption");
function isInlineModelOverrideAllowed(config, modelId) {
  const contentGeneratorConfig = config.getContentGeneratorConfig();
  const authType = contentGeneratorConfig?.authType;
  if (!authType) {
    return false;
  }
  const activeBaseUrl = contentGeneratorConfig.baseUrl;
  const activeEnvKey = contentGeneratorConfig.apiKeyEnvKey;
  return config.getAvailableModelsForAuthType(authType).filter((m) => !m.fastOnly && !m.voiceOnly && !m.imageOnly).some(
    (m) => m.id === modelId && (m.baseUrl ?? void 0) === (activeBaseUrl ?? void 0) && (m.envKey ?? void 0) === (activeEnvKey ?? void 0)
  );
}
__name(isInlineModelOverrideAllowed, "isInlineModelOverrideAllowed");

// packages/cli/src/utils/modelConfigUtils.ts
init_esbuild_shims();
var AUTH_ENV_MODEL_VARS = {
  ["openai" /* USE_OPENAI */]: ["OPENAI_MODEL", "QWEN_MODEL"],
  ["gemini" /* USE_GEMINI */]: ["GEMINI_MODEL"],
  ["vertex-ai" /* USE_VERTEX_AI */]: ["GOOGLE_MODEL"],
  ["anthropic" /* USE_ANTHROPIC */]: ["ANTHROPIC_MODEL"],
  ["qwen-oauth" /* QWEN_OAUTH */]: []
};
function collectProviderModelsForProtocol(modelProviders, providerProtocol, protocol) {
  if (!modelProviders) {
    return [];
  }
  const out = [];
  for (const [providerId, models] of Object.entries(modelProviders)) {
    if (!Array.isArray(models)) {
      continue;
    }
    if (resolveProviderProtocol(providerId, providerProtocol) === protocol) {
      out.push(...models);
    }
  }
  return out;
}
__name(collectProviderModelsForProtocol, "collectProviderModelsForProtocol");
function findProviderIdForModel(modelProviders, providerProtocol, protocol, modelProvider) {
  if (!modelProviders || !modelProvider) {
    return void 0;
  }
  for (const [providerId, models] of Object.entries(modelProviders)) {
    if (!Array.isArray(models)) {
      continue;
    }
    if (resolveProviderProtocol(providerId, providerProtocol) !== protocol) {
      continue;
    }
    if (models.includes(modelProvider)) {
      return providerId;
    }
  }
  return void 0;
}
__name(findProviderIdForModel, "findProviderIdForModel");
function buildSkippedProviderWarnings(modelProviders, providerProtocol) {
  if (!modelProviders) {
    return [];
  }
  const warnings = [];
  const known = Object.values(AuthType).join(", ");
  for (const [providerId, models] of Object.entries(modelProviders)) {
    if (!Array.isArray(models) || models.length === 0) {
      continue;
    }
    const protocol = resolveProviderProtocol(providerId, providerProtocol);
    if (protocol === "qwen-oauth" /* QWEN_OAUTH */ && providerId !== "qwen-oauth" /* QWEN_OAUTH */) {
      warnings.push(
        `Warning: modelProviders provider "${providerId}" maps to "qwen-oauth" via providerProtocol, but qwen-oauth uses hard-coded models only; its ${models.length} model(s) are ignored.`
      );
      continue;
    }
    if (protocol !== void 0) {
      continue;
    }
    const mapped = providerProtocol && Object.hasOwn(providerProtocol, providerId) ? providerProtocol[providerId] : void 0;
    warnings.push(
      mapped !== void 0 ? `Warning: providerProtocol["${providerId}"] = "${mapped}" is not a known protocol (expected one of: ${known}); its ${models.length} model(s) are ignored.` : `Warning: modelProviders provider "${providerId}" is not a built-in protocol (${known}) and has no providerProtocol mapping; its ${models.length} model(s) are ignored. Add providerProtocol["${providerId}"] (e.g. "openai") to enable them.`
    );
  }
  return warnings;
}
__name(buildSkippedProviderWarnings, "buildSkippedProviderWarnings");
function getIgnoredTopLevelGenerationConfigFields(settingsGenerationConfig, modelProvider) {
  if (!settingsGenerationConfig || !modelProvider) {
    return [];
  }
  const providerGenerationConfig = modelProvider.generationConfig ?? {};
  return MODEL_GENERATION_CONFIG_FIELDS.filter(
    (field) => Object.hasOwn(settingsGenerationConfig, field) && !Object.hasOwn(providerGenerationConfig, field)
  );
}
__name(getIgnoredTopLevelGenerationConfigFields, "getIgnoredTopLevelGenerationConfigFields");
function buildIgnoredTopLevelGenerationConfigWarning(providerId, modelProvider, ignoredFields) {
  if (ignoredFields.length === 0) {
    return void 0;
  }
  const fieldList = ignoredFields.map((field) => `model.generationConfig.${field}`).join(", ");
  const isSingular = ignoredFields.length === 1;
  const verb = isSingular ? "is" : "are";
  const fieldReference = isSingular ? "this field" : "these fields";
  const pronoun = isSingular ? "it" : "them";
  return `Warning: ${fieldList} ${verb} ignored for provider model "${modelProvider.id}" from modelProviders.${providerId}. Move ${fieldReference} to modelProviders.${providerId}[].generationConfig for that model if you want ${pronoun} to apply.`;
}
__name(buildIgnoredTopLevelGenerationConfigWarning, "buildIgnoredTopLevelGenerationConfigWarning");
function getAuthTypeFromEnv(env = process.env) {
  if (env["QWEN_OAUTH"]) {
    return "qwen-oauth" /* QWEN_OAUTH */;
  }
  if (env["OPENAI_API_KEY"] && (env["OPENAI_MODEL"] || env["QWEN_MODEL"]) && env["OPENAI_BASE_URL"]) {
    return "openai" /* USE_OPENAI */;
  }
  if (env["GEMINI_API_KEY"] && env["GEMINI_MODEL"]) {
    return "gemini" /* USE_GEMINI */;
  }
  if (env["GOOGLE_API_KEY"] && env["GOOGLE_MODEL"]) {
    return "vertex-ai" /* USE_VERTEX_AI */;
  }
  if (env["ANTHROPIC_API_KEY"] && env["ANTHROPIC_MODEL"] && env["ANTHROPIC_BASE_URL"]) {
    return "anthropic" /* USE_ANTHROPIC */;
  }
  return void 0;
}
__name(getAuthTypeFromEnv, "getAuthTypeFromEnv");
function resolveCliGenerationConfig(inputs) {
  const { argv, settings, selectedAuthType } = inputs;
  const env = inputs.env ?? process.env;
  const authType = selectedAuthType;
  let resolvedModel;
  let sourceEnvVar;
  let resolvedFromSettings = false;
  if (argv.model) {
    resolvedModel = argv.model;
  } else if (settings.model?.name) {
    resolvedModel = stripRuntimeSnapshotPrefix(settings.model.name);
    resolvedFromSettings = true;
  } else if (authType && AUTH_ENV_MODEL_VARS[authType]) {
    for (const envVar of AUTH_ENV_MODEL_VARS[authType]) {
      if (env[envVar]) {
        resolvedModel = env[envVar];
        sourceEnvVar = envVar;
        break;
      }
    }
  }
  let modelProvider;
  let disambiguationWarning;
  if (resolvedModel && authType && settings.modelProviders) {
    const providers = collectProviderModelsForProtocol(
      settings.modelProviders,
      settings.providerProtocol,
      authType
    );
    if (providers.length > 0) {
      const persistedBaseUrl = settings.model?.baseUrl;
      if (resolvedFromSettings && persistedBaseUrl) {
        const exactMatch = providers.find(
          (p) => p.id === resolvedModel && p.baseUrl === persistedBaseUrl
        );
        modelProvider = exactMatch ?? providers.find((p) => p.id === resolvedModel);
        if (!exactMatch && modelProvider) {
          const fallbackBaseUrl = modelProvider.baseUrl === void 0 ? "(default baseUrl)" : sanitizeProviderBaseUrl(modelProvider.baseUrl);
          disambiguationWarning = `Persisted model.baseUrl '${sanitizeProviderBaseUrl(persistedBaseUrl)}' no longer matches any provider for model '${resolvedModel}' (authType '${authType}'); using the first id match ('${fallbackBaseUrl}'). Re-select the model to update it.`;
        }
      } else {
        modelProvider = providers.find((p) => p.id === resolvedModel);
      }
    }
  }
  const allModelEnvVars = Object.values(AUTH_ENV_MODEL_VARS).flat();
  const filteredEnv = { ...env };
  if (sourceEnvVar) {
    for (const envVar of allModelEnvVars) {
      if (envVar !== sourceEnvVar) {
        delete filteredEnv[envVar];
      }
    }
  } else {
    for (const envVar of allModelEnvVars) {
      delete filteredEnv[envVar];
    }
  }
  const configSources = {
    authType,
    cli: {
      model: argv.model,
      apiKey: argv.openaiApiKey,
      baseUrl: argv.openaiBaseUrl
    },
    settings: {
      model: settings.model?.name ? stripRuntimeSnapshotPrefix(settings.model.name) : void 0,
      apiKey: settings.security?.auth?.apiKey,
      baseUrl: settings.security?.auth?.baseUrl,
      generationConfig: settings.model?.generationConfig
    },
    modelProvider,
    env: filteredEnv
  };
  const resolved = resolveModelConfig(configSources);
  const ignoredGenerationConfigWarning = authType && modelProvider ? buildIgnoredTopLevelGenerationConfigWarning(
    findProviderIdForModel(
      settings.modelProviders,
      settings.providerProtocol,
      authType,
      modelProvider
    ) ?? authType,
    modelProvider,
    getIgnoredTopLevelGenerationConfigFields(
      settings.model?.generationConfig,
      modelProvider
    )
  ) : void 0;
  const enableOpenAILogging = (typeof argv.openaiLogging === "undefined" ? settings.model?.enableOpenAILogging : argv.openaiLogging) ?? false;
  const openAILoggingDir = argv.openaiLoggingDir || settings.model?.openAILoggingDir;
  const generationConfig = {
    ...resolved.config,
    enableOpenAILogging,
    openAILoggingDir
  };
  const rawReasoningEffort = settings.model?.reasoningEffort;
  const reasoningEffort = normalizeReasoningEffort(rawReasoningEffort);
  const invalidReasoningEffortWarning = rawReasoningEffort && !reasoningEffort ? `Ignoring invalid model.reasoningEffort "${rawReasoningEffort}"; expected one of: ${REASONING_EFFORT_TIERS.join(", ")}.` : void 0;
  if (reasoningEffort && generationConfig.reasoning !== false) {
    generationConfig.reasoning = {
      ...generationConfig.reasoning ?? {},
      effort: reasoningEffort
    };
  }
  return {
    model: resolved.config.model || "",
    apiKey: resolved.config.apiKey || "",
    baseUrl: resolved.config.baseUrl || "",
    generationConfig,
    ...modelProvider ? { registryBaseUrl: modelProvider.baseUrl ?? null } : {},
    sources: resolved.sources,
    warnings: [
      ...resolved.warnings,
      ...invalidReasoningEffortWarning ? [invalidReasoningEffortWarning] : [],
      ...disambiguationWarning ? [disambiguationWarning] : [],
      ...ignoredGenerationConfigWarning ? [ignoredGenerationConfigWarning] : [],
      ...buildSkippedProviderWarnings(
        settings.modelProviders,
        settings.providerProtocol
      )
    ]
  };
}
__name(resolveCliGenerationConfig, "resolveCliGenerationConfig");

export {
  ACP_ROUTE_ID_PREFIX,
  buildAcpModelOptions,
  resolveAcpModelOption,
  getCurrentAcpModelId,
  sanitizeProviderBaseUrl,
  parseAcpBaseModelId,
  parseAcpModelOption,
  isInlineModelOverrideAllowed,
  collectProviderModelsForProtocol,
  getAuthTypeFromEnv,
  resolveCliGenerationConfig
};
/**
 * @license
 * Copyright 2025 Qwen Team
 * SPDX-License-Identifier: Apache-2.0
 */
