/**
 * Curated model metadata + normalization.
 *
 * Live provider listing endpoints return model IDs and little else (rarely
 * capabilities or pricing). We merge those IDs with a curated capability/pricing
 * map so the catalog always knows what a model can do, what it costs, and
 * whether it is current. When no key/live listing is available, the curated
 * entries also serve as the fallback catalog.
 *
 * Matching is prefix-based (longest match wins) so dated provider IDs like
 * `gpt-4o-2024-08-06` resolve to the `gpt-4o` entry, while `gpt-4o-mini-*`
 * resolves to its own entry.
 */
const NO_CAPABILITIES = {
    text: false,
    vision: false,
    imageGeneration: false,
    embeddings: false,
    toolCalling: false,
    structuredOutput: false,
    streaming: false,
    reasoning: false,
    longContext: false,
};
const CURATED = {
    openai: [
        {
            match: ['gpt-4o-mini'],
            canonicalId: 'gpt-4o-mini',
            displayName: 'GPT-4o mini (fast)',
            description: 'Low-cost multimodal model for high-volume tasks.',
            capabilities: {
                text: true,
                vision: true,
                toolCalling: true,
                structuredOutput: true,
                streaming: true,
                longContext: true,
            },
            contextWindow: 128000,
            maxOutputTokens: 16384,
            inputModalities: ['text', 'image'],
            outputModalities: ['text'],
            pricing: { inputPerMillion: 0.15, outputPerMillion: 0.6 },
        },
        {
            match: ['gpt-4o', 'chatgpt-4o'],
            canonicalId: 'gpt-4o',
            displayName: 'GPT-4o (balanced)',
            description: 'Flagship multimodal model balancing quality, speed, and cost.',
            capabilities: {
                text: true,
                vision: true,
                toolCalling: true,
                structuredOutput: true,
                streaming: true,
                longContext: true,
            },
            contextWindow: 128000,
            maxOutputTokens: 16384,
            inputModalities: ['text', 'image'],
            outputModalities: ['text'],
            pricing: { inputPerMillion: 2.5, outputPerMillion: 10 },
        },
        {
            match: ['o3-mini', 'o1-mini'],
            canonicalId: 'o3-mini',
            displayName: 'o3-mini (reasoning)',
            description: 'Fast reasoning model for structured problem solving.',
            capabilities: {
                text: true,
                toolCalling: true,
                structuredOutput: true,
                reasoning: true,
                longContext: true,
            },
            contextWindow: 200000,
            maxOutputTokens: 100000,
            inputModalities: ['text'],
            outputModalities: ['text'],
            pricing: { inputPerMillion: 1.1, outputPerMillion: 4.4 },
        },
        {
            match: ['o3', 'o1'],
            canonicalId: 'o3',
            displayName: 'o3 (reasoning)',
            description: 'High-capability reasoning model.',
            capabilities: {
                text: true,
                vision: true,
                toolCalling: true,
                structuredOutput: true,
                reasoning: true,
                longContext: true,
            },
            contextWindow: 200000,
            maxOutputTokens: 100000,
            inputModalities: ['text', 'image'],
            outputModalities: ['text'],
            pricing: { inputPerMillion: 10, outputPerMillion: 40 },
        },
        {
            match: ['text-embedding-3-large'],
            canonicalId: 'text-embedding-3-large',
            displayName: 'Embedding 3 (large)',
            capabilities: { embeddings: true },
            inputModalities: ['text'],
            outputModalities: ['embedding'],
            pricing: { inputPerMillion: 0.13 },
        },
        {
            match: ['text-embedding-3-small', 'text-embedding'],
            canonicalId: 'text-embedding-3-small',
            displayName: 'Embedding 3 (small)',
            capabilities: { embeddings: true },
            inputModalities: ['text'],
            outputModalities: ['embedding'],
            pricing: { inputPerMillion: 0.02 },
        },
        {
            match: ['gpt-image-1', 'dall-e-3', 'dall-e'],
            canonicalId: 'gpt-image-1',
            displayName: 'GPT Image',
            capabilities: { imageGeneration: true },
            inputModalities: ['text'],
            outputModalities: ['image'],
            pricing: { image: 0.04 },
        },
    ],
    anthropic: [
        {
            match: ['claude-haiku-4-5', 'claude-3-5-haiku', 'claude-haiku', 'claude-3-haiku'],
            canonicalId: 'claude-haiku-4-5',
            displayName: 'Claude Haiku (fast)',
            description: 'Fast, low-cost model for high-throughput tasks.',
            capabilities: {
                text: true,
                vision: true,
                toolCalling: true,
                structuredOutput: true,
                streaming: true,
                longContext: true,
            },
            contextWindow: 200000,
            maxOutputTokens: 8192,
            inputModalities: ['text', 'image'],
            outputModalities: ['text'],
            pricing: { inputPerMillion: 0.8, outputPerMillion: 4 },
        },
        {
            match: ['claude-opus-4-8', 'claude-opus-4', 'claude-opus', 'claude-3-opus'],
            canonicalId: 'claude-opus-4-8',
            displayName: 'Claude Opus (most capable)',
            description: 'Highest-capability Claude model for complex reasoning.',
            capabilities: {
                text: true,
                vision: true,
                toolCalling: true,
                structuredOutput: true,
                streaming: true,
                reasoning: true,
                longContext: true,
            },
            contextWindow: 200000,
            maxOutputTokens: 32000,
            inputModalities: ['text', 'image'],
            outputModalities: ['text'],
            pricing: { inputPerMillion: 15, outputPerMillion: 75 },
        },
        {
            match: ['claude-sonnet-4-6', 'claude-sonnet', 'claude-3-5-sonnet', 'claude-3-sonnet'],
            canonicalId: 'claude-sonnet-4-6',
            displayName: 'Claude Sonnet (balanced)',
            description: 'Balanced Claude model for everyday content and reasoning.',
            capabilities: {
                text: true,
                vision: true,
                toolCalling: true,
                structuredOutput: true,
                streaming: true,
                longContext: true,
            },
            contextWindow: 200000,
            maxOutputTokens: 16384,
            inputModalities: ['text', 'image'],
            outputModalities: ['text'],
            pricing: { inputPerMillion: 3, outputPerMillion: 15 },
        },
    ],
    xai: [
        {
            match: ['grok-4-fast', 'grok-3-mini', 'grok-mini'],
            canonicalId: 'grok-4-fast',
            displayName: 'Grok (fast)',
            description: 'Low-latency Grok model for high-volume tasks.',
            capabilities: {
                text: true,
                toolCalling: true,
                structuredOutput: true,
                streaming: true,
                longContext: true,
            },
            contextWindow: 131072,
            maxOutputTokens: 16384,
            inputModalities: ['text'],
            outputModalities: ['text'],
            pricing: { inputPerMillion: 0.2, outputPerMillion: 0.5 },
        },
        {
            match: ['grok-vision', 'grok-2-vision'],
            canonicalId: 'grok-vision',
            displayName: 'Grok Vision',
            description: 'Multimodal Grok model with image understanding.',
            capabilities: {
                text: true,
                vision: true,
                toolCalling: true,
                structuredOutput: true,
                streaming: true,
                longContext: true,
            },
            contextWindow: 131072,
            maxOutputTokens: 16384,
            inputModalities: ['text', 'image'],
            outputModalities: ['text'],
            pricing: { inputPerMillion: 2, outputPerMillion: 10 },
        },
        {
            match: ['grok'],
            canonicalId: 'grok-4',
            displayName: 'Grok (balanced)',
            description: 'Flagship Grok model.',
            capabilities: {
                text: true,
                toolCalling: true,
                structuredOutput: true,
                streaming: true,
                reasoning: true,
                longContext: true,
            },
            contextWindow: 131072,
            maxOutputTokens: 16384,
            inputModalities: ['text'],
            outputModalities: ['text'],
            pricing: { inputPerMillion: 3, outputPerMillion: 15 },
        },
    ],
};
/** Find the curated entry whose longest `match` prefix applies to the id. */
function findCurated(provider, providerModelId) {
    if (provider === 'custom')
        return null;
    const list = CURATED[provider];
    if (!list)
        return null;
    const id = providerModelId.toLowerCase();
    let best = null;
    for (const meta of list) {
        for (const m of meta.match) {
            if (id.startsWith(m) && (!best || m.length > best.len)) {
                best = { meta, len: m.length };
            }
        }
    }
    return best?.meta ?? null;
}
/**
 * Heuristic capability inference for models with no curated entry (e.g. an
 * unknown custom-provider model). Conservative: assumes text unless the id
 * clearly indicates embeddings/image-only.
 */
function inferCapabilities(providerModelId) {
    const id = providerModelId.toLowerCase();
    const caps = { ...NO_CAPABILITIES };
    if (id.includes('embed')) {
        caps.embeddings = true;
        return caps;
    }
    if (id.includes('image') || id.includes('dall-e') || id.includes('imagen')) {
        caps.imageGeneration = true;
        return caps;
    }
    caps.text = true;
    caps.streaming = true;
    if (id.includes('vision') ||
        id.includes('-o') ||
        id.includes('4o') ||
        id.includes('multimodal')) {
        caps.vision = true;
    }
    if (id.includes('reason') || id.includes('think') || /\bo[13]\b/.test(id)) {
        caps.reasoning = true;
    }
    return caps;
}
/** Merge a (live or fallback) model id with curated metadata into an AIModel. */
export function normalizeModel(input) {
    const curated = findCurated(input.provider, input.providerModelId);
    const capabilities = curated
        ? { ...NO_CAPABILITIES, ...curated.capabilities }
        : inferCapabilities(input.providerModelId);
    return {
        id: `${input.provider}:${input.providerModelId}`,
        provider: input.provider,
        providerModelId: input.providerModelId,
        displayName: curated?.displayName ?? input.displayName ?? input.providerModelId,
        description: curated?.description,
        status: input.status ?? (curated?.deprecated ? 'deprecated' : 'available'),
        capabilities,
        contextWindow: curated?.contextWindow,
        maxOutputTokens: curated?.maxOutputTokens,
        inputModalities: curated?.inputModalities ?? (capabilities.embeddings ? ['text'] : ['text']),
        outputModalities: curated?.outputModalities ??
            (capabilities.embeddings
                ? ['embedding']
                : capabilities.imageGeneration
                    ? ['image']
                    : ['text']),
        pricing: curated?.pricing,
        lastSyncedAt: input.lastSyncedAt,
        source: input.source,
        metadata: curated ? { curated: true } : {},
    };
}
/**
 * Legacy curated fallback ids that older installs may still have saved in Settings
 * > AI. Anthropic no longer accepts the `-latest` aliases used in early catalogs.
 */
const LEGACY_CATALOG_MODEL_IDS = {
    'anthropic:claude-3-5-haiku-latest': 'anthropic:claude-haiku-4-5',
    'anthropic:claude-opus-4-latest': 'anthropic:claude-opus-4-8',
    'anthropic:claude-sonnet-4-latest': 'anthropic:claude-sonnet-4-6',
};
const LEGACY_WIRE_MODEL_IDS = {
    'claude-3-5-haiku-latest': 'claude-haiku-4-5',
    'claude-opus-4-latest': 'claude-opus-4-8',
    'claude-sonnet-4-latest': 'claude-sonnet-4-6',
};
/** Remap a saved catalog model id (`provider:model`) to its current equivalent. */
export function remapLegacyModelId(modelId) {
    if (!modelId)
        return modelId;
    return LEGACY_CATALOG_MODEL_IDS[modelId] ?? modelId;
}
/** Remap a provider-native model id before it is sent on the wire. */
export function resolveWireModelId(providerModelId) {
    return LEGACY_WIRE_MODEL_IDS[providerModelId] ?? providerModelId;
}
/** True when two catalog or wire ids refer to the same model after legacy remaps. */
export function modelsMatch(a, b) {
    if (a === b)
        return true;
    return (remapLegacyModelId(a) ?? a) === (remapLegacyModelId(b) ?? b);
}
/** Curated fallback catalog for a provider (used when no live listing). */
export function curatedFallbackCatalog(provider, lastSyncedAt) {
    if (provider === 'custom')
        return [];
    const list = CURATED[provider] ?? [];
    return list
        .filter((m) => m.fallback !== false)
        .map((m) => normalizeModel({
        provider,
        providerModelId: m.canonicalId,
        source: 'config',
        status: m.deprecated ? 'deprecated' : 'available',
        lastSyncedAt,
    }));
}
//# sourceMappingURL=catalog.js.map