import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);

// src/gateway-models.ts
var DEFAULT_GATEWAY_MODEL = "claude-opus-4-8";
var DEFAULT_CODEX_MODEL = "gpt-5.5";
var BLOCKED_MODELS = /* @__PURE__ */ new Set([
  "gpt-5-mini",
  "openai/gpt-5-mini",
  "gpt-5.2",
  "openai/gpt-5.2",
  "gpt-5.3",
  "openai/gpt-5.3",
  "gpt-5.3-codex",
  "openai/gpt-5.3-codex",
  "claude-opus-4-5",
  "anthropic/claude-opus-4-5",
  "claude-opus-4-6",
  "anthropic/claude-opus-4-6",
  "claude-sonnet-4-5",
  "anthropic/claude-sonnet-4-5",
  "claude-haiku-4-5",
  "anthropic/claude-haiku-4-5"
]);
function isBlockedModelId(modelId) {
  return BLOCKED_MODELS.has(modelId.toLowerCase());
}
var CACHE_TTL = 10 * 60 * 1e3;
var GATEWAY_FETCH_TIMEOUT_MS = 1e4;
function readModelsCache(cache, url, token) {
  if (!cache || cache.url !== url || cache.token !== token) return null;
  return Date.now() < cache.expiry ? cache.models : null;
}
function authHeaders(authToken) {
  return authToken ? { Authorization: `Bearer ${authToken}` } : void 0;
}
var gatewayModelsCache = null;
async function fetchGatewayModels(options) {
  const gatewayUrl = options?.gatewayUrl ?? process.env.ANTHROPIC_BASE_URL;
  if (!gatewayUrl) {
    return [];
  }
  const token = options?.authToken ?? null;
  const cached = readModelsCache(gatewayModelsCache, gatewayUrl, token);
  if (cached) return cached;
  const modelsUrl = `${gatewayUrl}/v1/models`;
  try {
    const response = await fetch(modelsUrl, {
      headers: authHeaders(options?.authToken),
      signal: AbortSignal.timeout(GATEWAY_FETCH_TIMEOUT_MS)
    });
    if (!response.ok) {
      return [];
    }
    const data = await response.json();
    const models = (data.data ?? []).filter((m) => !isBlockedModelId(m.id)).map((m) => ({ ...m, allowed: m.allowed !== false }));
    gatewayModelsCache = {
      models,
      expiry: Date.now() + CACHE_TTL,
      url: gatewayUrl,
      token
    };
    return models;
  } catch {
    return [];
  }
}
function isAnthropicModel(model) {
  if (model.owned_by) {
    return model.owned_by === "anthropic";
  }
  return model.id.startsWith("claude-") || model.id.startsWith("anthropic/");
}
function isOpenAIModel(model) {
  if (model.owned_by) {
    return model.owned_by === "openai";
  }
  return model.id.startsWith("gpt-") || model.id.startsWith("openai/");
}
function isCloudflareModelId(modelId) {
  return modelId.startsWith("@cf/");
}
function isCloudflareModel(model) {
  return isCloudflareModelId(model.id) || model.owned_by === "cloudflare";
}
var modelsListCache = null;
async function fetchModelsList(options) {
  const gatewayUrl = options?.gatewayUrl ?? process.env.ANTHROPIC_BASE_URL;
  if (!gatewayUrl) {
    return [];
  }
  const token = options?.authToken ?? null;
  const cached = readModelsCache(modelsListCache, gatewayUrl, token);
  if (cached) return cached;
  try {
    const modelsUrl = `${gatewayUrl}/v1/models`;
    const response = await fetch(modelsUrl, {
      headers: authHeaders(options?.authToken),
      signal: AbortSignal.timeout(GATEWAY_FETCH_TIMEOUT_MS)
    });
    if (!response.ok) {
      return [];
    }
    const data = await response.json();
    const models = Array.isArray(data) ? data : data.data ?? data.models ?? [];
    const results = [];
    for (const model of models) {
      const id = model?.id ? String(model.id) : "";
      if (!id) continue;
      if (isBlockedModelId(id)) continue;
      results.push({
        id,
        owned_by: model?.owned_by,
        allowed: model?.allowed !== false,
        restriction_reason: model?.restriction_reason ?? null
      });
    }
    modelsListCache = {
      models: results,
      expiry: Date.now() + CACHE_TTL,
      url: gatewayUrl,
      token
    };
    return results;
  } catch {
    return [];
  }
}
function pickAllowedModel(models, preferred) {
  if (models.length === 0) return preferred;
  const preferredEntry = models.find((m) => m.id === preferred);
  if (!preferredEntry || preferredEntry.allowed) return preferred;
  const allowed = models.filter((m) => m.allowed);
  if (allowed.length === 0) return preferred;
  return allowed.reduce(
    (best, candidate) => getClaudeModelRecency(candidate.id) >= getClaudeModelRecency(best.id) ? candidate : best
  ).id;
}
var PROVIDER_NAMES = {
  anthropic: "Anthropic",
  openai: "OpenAI",
  "google-vertex": "Gemini"
};
function getProviderName(ownedBy) {
  return PROVIDER_NAMES[ownedBy] ?? ownedBy;
}
function getClaudeModelRecency(modelId) {
  const match = modelId.toLowerCase().match(/-(\d+)(?:[-.](\d+))?/);
  if (!match) return Number.MAX_SAFE_INTEGER;
  const major = Number(match[1]);
  const minor = match[2] ? Number(match[2]) : 0;
  return major * 1e3 + minor;
}
var PROVIDER_PREFIXES = ["anthropic/", "openai/", "google-vertex/"];
function formatGatewayModelName(model) {
  if (isCloudflareModel(model)) {
    return (model.id.split("/").pop() ?? model.id).toLowerCase();
  }
  if (isOpenAIModel(model)) {
    return stripProviderPrefix(model.id).toLowerCase();
  }
  return formatModelId(model.id);
}
function stripProviderPrefix(modelId) {
  for (const prefix of PROVIDER_PREFIXES) {
    if (modelId.startsWith(prefix)) {
      return modelId.slice(prefix.length);
    }
  }
  return modelId;
}
function formatModelId(modelId) {
  let cleanId = modelId;
  for (const prefix of PROVIDER_PREFIXES) {
    if (cleanId.startsWith(prefix)) {
      cleanId = cleanId.slice(prefix.length);
      break;
    }
  }
  cleanId = cleanId.replace(/(\d)-(\d)/g, "$1.$2");
  const words = cleanId.split(/[-_]/).map((word) => {
    if (word.match(/^[0-9.]+$/)) return word;
    return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
  });
  return words.join(" ");
}
export {
  DEFAULT_CODEX_MODEL,
  DEFAULT_GATEWAY_MODEL,
  fetchGatewayModels,
  fetchModelsList,
  formatGatewayModelName,
  formatModelId,
  getClaudeModelRecency,
  getProviderName,
  isAnthropicModel,
  isBlockedModelId,
  isCloudflareModel,
  isCloudflareModelId,
  isOpenAIModel,
  pickAllowedModel
};
//# sourceMappingURL=gateway-models.js.map