/**
 * Model registry — UI-relevant metadata for all platform-supported LLM models.
 *
 * Fetches from the public model registry API endpoint at runtime and caches
 * the result in the {@link StigmerProvider} context. This eliminates the
 * static JSON file that previously shipped in the npm package.
 *
 * Platform consumers (React SDK, cursor-runner, graphton) all fetch from the
 * same endpoint, each with their own local TTL cache.
 */
/**
 * Providers whose models should be hidden from the UI.
 *
 * The model entries themselves stay in the registry so backend
 * compatibility is preserved. The useModelRegistry hook filters
 * them out before anything reaches a component.
 *
 * To re-enable a provider, simply remove it from this set.
 */
export const DISABLED_PROVIDERS = new Set([
    "ollama",
]);
/**
 * Build a compound key that uniquely identifies a model across harnesses.
 *
 * The same underlying model name (e.g. `claude-4.6-sonnet`) can exist in
 * both native and cursor harnesses. The compound key disambiguates.
 */
export function modelKey(harness, modelId) {
    return `${harness}/${modelId}`;
}
/**
 * Parse a compound key back into its `(harness, modelId)` parts.
 * Returns `undefined` for malformed keys.
 */
export function parseModelKey(key) {
    const idx = key.indexOf("/");
    if (idx < 1)
        return undefined;
    const harness = key.slice(0, idx);
    if (harness !== "native" && harness !== "cursor")
        return undefined;
    return { harness, modelId: key.slice(idx + 1) };
}
const VALID_COST_TIERS = new Set(["economy", "standard", "premium"]);
const VALID_SPEED_TIERS = new Set(["fastest", "fast", "balanced", "slow"]);
const VALID_HARNESSES = new Set(["native", "cursor", "copilot", "claude_code", "codex", "devin"]);
function isModelEntry(entry) {
    return (typeof entry.id === "string" &&
        typeof entry.displayName === "string" &&
        typeof entry.provider === "string" &&
        typeof entry.harness === "string" && VALID_HARNESSES.has(entry.harness) &&
        typeof entry.costTier === "string" && VALID_COST_TIERS.has(entry.costTier));
}
/**
 * Parse raw registry JSON (from the API or a static file) into `ModelInfo[]`.
 *
 * Expects the shape `{ models: RegistryJsonEntry[] }`. Filters out comment
 * entries and invalid rows, then maps to the `ModelInfo` interface.
 */
export function parseRegistryJson(data) {
    if (!data || typeof data !== "object")
        return [];
    const models = data.models;
    if (!Array.isArray(models))
        return [];
    return models
        .filter(isModelEntry)
        .map((m) => ({
        modelId: m.id,
        provider: m.provider,
        displayName: m.displayName,
        shortDescription: m.shortDescription ?? "",
        speedTier: (VALID_SPEED_TIERS.has(m.speedTier ?? "") ? m.speedTier : "fast"),
        costTier: m.costTier,
        harness: m.harness,
        featured: m.featured ?? false,
    }));
}
/**
 * Fetch the model registry from the authenticated API endpoint.
 *
 * @param apiUrl - Base URL of the Stigmer Cloud API (e.g. `https://api.stigmer.ai`)
 * @param token - Bearer token for authentication (from `client.getAuthCredential()`)
 * @param customFetch - Optional custom `fetch` implementation. Required in
 *   Tauri where the global `fetch` is restricted by webview CSP/CORS policies.
 *   When omitted, the global `fetch` is used.
 * @returns Parsed `ModelInfo[]`.
 */
export async function fetchModelRegistry(apiUrl, token, customFetch) {
    const doFetch = customFetch ?? globalThis.fetch;
    const headers = {};
    if (token) {
        headers["Authorization"] = `Bearer ${token}`;
    }
    const res = await doFetch(`${apiUrl}/v1/proxy/model-registry`, { headers });
    if (!res.ok)
        throw new Error(`Model registry fetch failed: ${res.status}`);
    const data = await res.json();
    return parseRegistryJson(data);
}
/**
 * Model ID used when no user preference is set (native harness).
 *
 * @deprecated Use {@link resolveDefaultModelId} for dynamic resolution
 * based on the active harness and featured models. This constant is kept
 * as the last-resort platform fallback.
 */
export const DEFAULT_MODEL_ID = "claude-sonnet-4.6";
/** Model ID used when the Cursor harness is selected and no user preference is set. */
export const DEFAULT_CURSOR_MODEL_ID = "default";
/**
 * Resolve the default model for a given harness using a priority chain.
 *
 * Priority (Phase 1 — no backend):
 * 1. localStorage user preference (passed in as `userPreference`)
 * 2. First featured model for the harness from the registry
 * 3. Hardcoded platform fallback
 *
 * Future phases will add org-level and agent-level defaults between
 * user preference and harness default.
 */
export function resolveDefaultModelId(harness, models, options) {
    if (options?.userPreference) {
        const model = models.find((m) => m.harness === harness && m.modelId === options.userPreference);
        if (model)
            return { modelId: model.modelId, source: "user_preference" };
    }
    if (options?.orgDefault) {
        const model = models.find((m) => m.harness === harness && m.modelId === options.orgDefault);
        if (model)
            return { modelId: model.modelId, source: "org_default" };
    }
    if (options?.agentDefault) {
        const model = models.find((m) => m.harness === harness && m.modelId === options.agentDefault);
        if (model)
            return { modelId: model.modelId, source: "agent_default" };
    }
    const featured = models.find((m) => m.harness === harness && m.featured);
    if (featured)
        return { modelId: featured.modelId, source: "harness_default" };
    const fallbackId = harness === "cursor" ? DEFAULT_CURSOR_MODEL_ID : DEFAULT_MODEL_ID;
    return { modelId: fallbackId, source: "platform_fallback" };
}
//# sourceMappingURL=registry.js.map