// src/runtime/model-catalog.ts
var PROVIDER_TIER = [
  "anthropic",
  "openai",
  "google",
  "xai",
  "deepseek",
  "moonshotai",
  "moonshot",
  "zai",
  "z-ai",
  "mistral",
  "groq",
  "nvidia",
  "cohere",
  "cerebras"
];
var EXCLUDED_ID = /(embedding|tts|transcribe|whisper|audio|realtime|image|lyria|sora|dall-e|moderation|content-safety|search-preview|search-api|deep-research)/;
var FEATURED_RULES = [
  { providers: ["anthropic"], match: /^claude-sonnet-[\d-]+$/ },
  { providers: ["anthropic"], match: /^claude-opus-[\d-]+$/ },
  { providers: ["anthropic"], match: /^claude-haiku-[\d-]+$/ },
  { providers: ["openai"], match: /^gpt-\d+(\.\d+)?$/ },
  { providers: ["openai"], match: /^gpt-\d+(\.\d+)?-mini$/ },
  { providers: ["google"], match: /^gemini-[\d.]+-pro(-preview)?$/ },
  { providers: ["google"], match: /^gemini-[\d.]+-flash(-preview)?$/ },
  { providers: ["xai"], match: /^grok-[\d.]+$/ },
  { providers: ["deepseek"], match: /^deepseek-(chat|v[\d.]+(-\w+)?)$/ },
  { providers: ["moonshotai", "moonshot"], match: /^kimi-k[\d.]+$/ },
  { providers: ["zai", "z-ai"], match: /^glm-[\d.]+$/ },
  { providers: ["mistral"], match: /^mistral-(large|medium)-?[\d.-]*$/ }
];
var TOOL_CAPABLE_FAMILY = /^(claude|gpt-[45]|gpt-oss|o[134]|gemini|grok|deepseek|glm|kimi|mistral|ministral|magistral|command|nemotron|llama)/;
function normalizeModelId(id) {
  let tail = id.split("/").pop() ?? id;
  tail = tail.replace(/:free$/, "");
  tail = tail.replace(/-\d{8}$/, "");
  tail = tail.replace(/-\d{4}-\d{2}-\d{2}$/, "");
  return tail;
}
function versionOf(normId) {
  return (normId.match(/\d+/g) ?? []).map(Number);
}
function compareVersions(a, b) {
  const len = Math.max(a.length, b.length);
  for (let i = 0; i < len; i++) {
    const d = (a[i] ?? -1) - (b[i] ?? -1);
    if (d !== 0) return d;
  }
  return 0;
}
function aliasPenalty(id) {
  let p = 0;
  if (id.includes("/")) p += 4;
  if (/-\d{8}$|-\d{4}-\d{2}-\d{2}$/.test(id.replace(/:free$/, ""))) p += 2;
  if (id.endsWith(":free")) p += 1;
  return p;
}
function providerRank(provider) {
  const i = PROVIDER_TIER.indexOf(provider);
  return i === -1 ? PROVIDER_TIER.length : i;
}
function isChatModel(m) {
  const arch = m.architecture;
  if (!arch?.input_modalities || !arch?.output_modalities) return true;
  return arch.input_modalities.includes("text") && arch.output_modalities.includes("text");
}
function isRouteable(m) {
  return m.routeability?.routeable !== false && m.routeability?.status !== "unavailable";
}
function familyOf(normId) {
  return normId.replace(/[\d.]+/g, "").replace(/-+/g, "-").replace(/-$/, "");
}
function buildCatalog(raw, opts) {
  const candidates = raw.filter(
    (m) => m.id && isRouteable(m) && isChatModel(m) && !EXCLUDED_ID.test(normalizeModelId(m.id))
  );
  const groups = /* @__PURE__ */ new Map();
  for (const m of candidates) {
    const key = `${m._provider ?? ""}::${normalizeModelId(m.id)}`;
    const g = groups.get(key);
    if (g) g.push(m);
    else groups.set(key, [m]);
  }
  const reps = [];
  for (const group of groups.values()) {
    group.sort((a, b) => aliasPenalty(a.id) - aliasPenalty(b.id) || a.id.length - b.id.length);
    const rep = group[0];
    const mergedParams = new Set(group.flatMap((m) => m.supported_parameters ?? []));
    reps.push({ model: rep, normId: normalizeModelId(rep.id), mergedParams });
  }
  const featuredIds = [];
  for (const rule of FEATURED_RULES) {
    const matches = reps.filter(
      (r) => rule.providers.includes(r.model._provider ?? "") && rule.match.test(r.normId) && !featuredIds.includes(r.model.id)
    );
    if (!matches.length) continue;
    matches.sort(
      (a, b) => compareVersions(versionOf(b.normId), versionOf(a.normId)) || Number(a.normId.includes("preview")) - Number(b.normId.includes("preview")) || a.model.id.length - b.model.id.length
    );
    featuredIds.push(matches[0].model.id);
  }
  const toCatalogModel = (r) => {
    const m = r.model;
    const provider = m._provider ?? "unknown";
    return {
      id: m.id,
      name: m.name ?? m.id,
      provider,
      description: m.description ? m.description.slice(0, 160) : void 0,
      contextLength: m.context_length,
      pricing: m.pricing?.prompt || m.pricing?.completion ? { prompt: m.pricing.prompt ?? void 0, completion: m.pricing.completion ?? void 0 } : void 0,
      supportsTools: r.mergedParams.has("tools") || TOOL_CAPABLE_FAMILY.test(r.normId),
      supportsReasoning: r.mergedParams.has("reasoning") || r.mergedParams.has("include_reasoning"),
      featured: featuredIds.includes(m.id)
    };
  };
  const featured = featuredIds.map((id) => reps.find((r) => r.model.id === id)).map(toCatalogModel);
  const rest = reps.filter((r) => !featuredIds.includes(r.model.id)).sort((a, b) => {
    const pa = providerRank(a.model._provider ?? "");
    const pb = providerRank(b.model._provider ?? "");
    if (pa !== pb) return pa - pb;
    const fa = familyOf(a.normId);
    const fb = familyOf(b.normId);
    if (fa !== fb) return fa.localeCompare(fb);
    return compareVersions(versionOf(b.normId), versionOf(a.normId)) || a.model.id.localeCompare(b.model.id);
  }).map(toCatalogModel);
  const models = [...featured, ...rest];
  const preferred = opts?.preferredDefault;
  const defaultModelId = preferred && models.find((m) => m.id === preferred || normalizeModelId(m.id) === normalizeModelId(preferred))?.id || featured.find((m) => m.supportsTools)?.id || models[0]?.id || null;
  return { defaultModelId, fetchedAt: (/* @__PURE__ */ new Date()).toISOString(), models };
}
var CATALOG_TTL_MS = 5 * 60 * 1e3;
var _cache = null;
async function fetchModelCatalog(cfg) {
  if (_cache && Date.now() - _cache.at < CATALOG_TTL_MS) {
    return _cache.catalog;
  }
  try {
    const res = await fetch(`${cfg.baseUrl}/models`, {
      headers: { Authorization: `Bearer ${cfg.apiKey}` }
    });
    if (!res.ok) throw new Error(`Router /models returned ${res.status}`);
    const data = await res.json();
    const catalog = buildCatalog(data.data ?? [], { preferredDefault: cfg.preferredDefault });
    _cache = { catalog, at: Date.now() };
    return catalog;
  } catch (err) {
    if (_cache) return _cache.catalog;
    throw err;
  }
}
function __resetCatalogCache() {
  _cache = null;
}

export {
  normalizeModelId,
  buildCatalog,
  fetchModelCatalog,
  __resetCatalogCache
};
//# sourceMappingURL=chunk-TQOFR6XY.js.map