"use strict";
/**
 * Thinking configuration and suffix handling
 * Manages thinking budget suffixes for CLIProxyAPIPlus
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.applyThinkingConfig = exports.getThinkingValueForTier = exports.applyThinkingSuffix = exports.detectTierFromModel = void 0;
const unified_config_types_1 = require("../../config/unified-config-types");
const model_catalog_1 = require("../model-catalog");
const thinking_validator_1 = require("../thinking-validator");
const model_id_normalizer_1 = require("../ai-providers/model-id-normalizer");
const ui_1 = require("../../utils/ui");
const config_loader_facade_1 = require("../../config/config-loader-facade");
const CODEX_EFFORT_REGEX = /^(minimal|low|medium|high|xhigh)$/i;
const CODEX_FAST_TUNING_VALUE_REGEX = /^(?:(minimal|low|medium|high|xhigh)-fast|fast-(minimal|low|medium|high|xhigh)|fast)$/i;
const CODEX_TUNING_SUFFIX_REGEX = /(?:-(?:minimal|low|medium|high|xhigh)(?:-fast)?|-fast(?:-(?:minimal|low|medium|high|xhigh))?)$/i;
/**
 * Normalize model ID for provider capability lookup.
 * Codex may carry effort/service-tier suffixes in legacy "(high)" or current "-high-fast" forms.
 */
function normalizeModelForThinkingLookup(model, provider) {
    const withoutExtendedContext = model.replace(/\[1m\]$/i, '').trim();
    const providerNormalized = (0, model_id_normalizer_1.normalizeModelIdForProvider)(withoutExtendedContext, provider);
    if (provider !== 'codex')
        return providerNormalized;
    // New codex suffix forms: gpt-5.4-low-fast, gpt-5.4-fast-high -> gpt-5.4
    const codexSuffixMatch = providerNormalized.match(/^(.*?)(?:-(?:minimal|low|medium|high|xhigh)(?:-fast)?|-fast(?:-(?:minimal|low|medium|high|xhigh))?)$/i);
    if (codexSuffixMatch?.[1]) {
        return codexSuffixMatch[1].trim();
    }
    // Legacy codex suffix form: gpt-5.3-codex(high) -> gpt-5.3-codex
    const codexLegacyMatch = providerNormalized.match(/^(.*)\((minimal|low|medium|high|xhigh)\)$/i);
    if (codexLegacyMatch?.[1]) {
        return codexLegacyMatch[1].trim();
    }
    return providerNormalized;
}
/**
 * Check if warnings should be shown based on thinking config.
 * Defaults to true if show_warnings is not explicitly false.
 */
function shouldShowWarnings(thinkingConfig) {
    return thinkingConfig.show_warnings !== false;
}
/**
 * Detect tier from model name.
 * Returns 'sonnet' as default if unclear.
 */
function detectTierFromModel(modelName) {
    const lower = modelName.toLowerCase();
    if (lower.includes('opus'))
        return 'opus';
    if (lower.includes('haiku'))
        return 'haiku';
    return 'sonnet'; // Default to sonnet (most common)
}
exports.detectTierFromModel = detectTierFromModel;
/**
 * Apply thinking suffix to model name.
 * CLIProxyAPIPlus parses suffixes like model(level) or model(budget).
 *
 * @param model - Base model name
 * @param thinkingValue - Level name (e.g., 'high') or numeric budget
 * @returns Model name with thinking suffix, e.g., "gemini-3.1-pro-preview(high)"
 */
function applyThinkingSuffix(model, thinkingValue) {
    return applyThinkingSuffixForProvider(model, thinkingValue);
}
exports.applyThinkingSuffix = applyThinkingSuffix;
/**
 * Apply provider-aware thinking suffix to model name.
 * - Most providers: model(level|budget) e.g. "gemini-2.5-pro(high)"
 * - Codex: model-effort e.g. "gpt-5.3-codex-xhigh"
 */
function applyThinkingSuffixForProvider(model, thinkingValue, provider) {
    const parenthesizedSuffixMatch = model.match(/\(([^)]+)\)$/);
    // Existing parenthesized suffix:
    // - keep as-is for non-codex providers unless the target model now expects
    //   named levels and we need to rewrite an old numeric suffix
    // - for codex effort levels, normalize to codex model suffix style
    if (parenthesizedSuffixMatch) {
        if (provider === 'codex') {
            const normalizedParensValue = parenthesizedSuffixMatch[1]?.trim().toLowerCase() || '';
            if (CODEX_EFFORT_REGEX.test(normalizedParensValue)) {
                return model.replace(/\([^)]+\)$/, `-${normalizedParensValue}`);
            }
        }
        if (provider) {
            const normalizedBaseModel = normalizeModelForThinkingLookup(model, provider);
            const thinking = (0, model_catalog_1.getModelThinkingSupport)(provider, normalizedBaseModel);
            if (thinking?.type === 'levels') {
                return model.replace(/\([^)]+\)$/, `(${thinkingValue})`);
            }
        }
        return model;
    }
    if (provider === 'codex') {
        if (CODEX_TUNING_SUFFIX_REGEX.test(model)) {
            return model;
        }
        const normalized = String(thinkingValue).trim().toLowerCase();
        if (CODEX_EFFORT_REGEX.test(normalized) || CODEX_FAST_TUNING_VALUE_REGEX.test(normalized)) {
            return `${model}-${normalized}`;
        }
    }
    return `${model}(${thinkingValue})`;
}
/**
 * Get thinking value for tier based on config.
 * Respects provider-specific overrides if configured.
 */
function getThinkingValueForTier(tier, provider, thinkingConfig) {
    // Check provider-specific override first
    const providerOverride = thinkingConfig.provider_overrides?.[provider]?.[tier];
    if (providerOverride) {
        return providerOverride;
    }
    // Codex effort aliases historically defaulted to xhigh/high/medium per tier.
    // Preserve this behavior when settings are canonicalized (suffix-stripped).
    if (provider === 'codex') {
        if (tier === 'opus')
            return 'xhigh';
        if (tier === 'sonnet')
            return 'high';
        return 'medium';
    }
    // Fall back to global tier default (with null guard, uses centralized defaults)
    return thinkingConfig.tier_defaults?.[tier] ?? unified_config_types_1.DEFAULT_THINKING_TIER_DEFAULTS[tier];
}
exports.getThinkingValueForTier = getThinkingValueForTier;
/**
 * Apply thinking configuration to env vars.
 * Modifies ANTHROPIC_MODEL and tier models with thinking suffixes.
 *
 * @param envVars - Environment variables to modify
 * @param provider - CLIProxy provider (default provider for base model)
 * @param thinkingOverride - Optional CLI override (takes priority over config)
 * @param compositeTierThinking - Optional per-tier thinking overrides for composite variants
 * @param compositeTiers - Optional per-tier provider config for composite variants
 * @returns Modified env vars with thinking suffixes applied
 */
function applyThinkingConfig(envVars, provider, thinkingOverride, compositeTierThinking, compositeTiers) {
    const thinkingConfig = (0, config_loader_facade_1.getThinkingConfig)();
    const result = { ...envVars };
    // Check if thinking is off
    if (thinkingConfig.mode === 'off' && thinkingOverride === undefined) {
        return result;
    }
    // Explicit "off" (CLI override or manual config override) must disable ALL tier thinking.
    const explicitOffOverride = (0, thinking_validator_1.isThinkingOffValue)(thinkingOverride) ||
        (thinkingOverride === undefined &&
            thinkingConfig.mode === 'manual' &&
            (0, thinking_validator_1.isThinkingOffValue)(thinkingConfig.override));
    if (explicitOffOverride) {
        return result;
    }
    // Get base model to check thinking support
    const baseModel = result.ANTHROPIC_MODEL || '';
    const normalizedBaseModel = normalizeModelForThinkingLookup(baseModel, provider);
    const baseModelSupportsThinking = (0, model_catalog_1.supportsThinking)(provider, normalizedBaseModel);
    if (!baseModelSupportsThinking &&
        thinkingOverride !== undefined &&
        shouldShowWarnings(thinkingConfig)) {
        console.warn((0, ui_1.warn)(`Model ${baseModel || 'unknown'} (provider: ${provider}) does not support thinking budget. --thinking flag ignored for default model.`));
    }
    // Determine thinking value to use
    let thinkingValue;
    if (thinkingOverride !== undefined) {
        // CLI override takes priority
        thinkingValue = thinkingOverride;
    }
    else if (thinkingConfig.mode === 'manual' && thinkingConfig.override !== undefined) {
        // Config manual mode with override
        thinkingValue = thinkingConfig.override;
    }
    else if (thinkingConfig.mode === 'auto') {
        // Auto mode: detect tier and apply default
        const tier = detectTierFromModel(normalizedBaseModel);
        // Check per-tier config first if composite
        const perTierValue = compositeTierThinking?.[tier];
        if (perTierValue !== undefined) {
            thinkingValue = perTierValue;
        }
        else {
            thinkingValue = getThinkingValueForTier(tier, provider, thinkingConfig);
        }
    }
    else {
        return result; // No thinking to apply
    }
    if (baseModelSupportsThinking) {
        // Validate thinking value against default model capabilities.
        const validation = (0, thinking_validator_1.validateThinking)(provider, normalizedBaseModel, thinkingValue);
        if (validation.warning && shouldShowWarnings(thinkingConfig)) {
            console.warn((0, ui_1.warn)(validation.warning));
        }
        thinkingValue = validation.value;
    }
    // If auto-detection resolves default tier to "off", skip the main model but still allow
    // explicit per-tier thinking values for other tiers.
    if ((0, thinking_validator_1.isThinkingOffValue)(thinkingValue)) {
        const hasPerTierThinking = compositeTierThinking &&
            Object.values(compositeTierThinking).some((v) => v !== undefined && !(0, thinking_validator_1.isThinkingOffValue)(v));
        if (!hasPerTierThinking) {
            return result; // No thinking to apply anywhere
        }
        // Otherwise, continue to process tiers with their own config (skip main model)
    }
    else if (baseModelSupportsThinking && result.ANTHROPIC_MODEL) {
        // Apply thinking suffix to main model (only if not off)
        result.ANTHROPIC_MODEL = applyThinkingSuffixForProvider(result.ANTHROPIC_MODEL, thinkingValue, provider);
    }
    // Apply to tier models if they support thinking
    const tierModels = [
        'ANTHROPIC_DEFAULT_OPUS_MODEL',
        'ANTHROPIC_DEFAULT_SONNET_MODEL',
        'ANTHROPIC_DEFAULT_HAIKU_MODEL',
    ];
    for (const tierVar of tierModels) {
        const model = result[tierVar];
        if (model) {
            // Get tier-specific thinking value
            const tier = tierVar.includes('OPUS')
                ? 'opus'
                : tierVar.includes('SONNET')
                    ? 'sonnet'
                    : 'haiku';
            // P2 FIX: Use tier-specific provider from compositeTiers for mixed-provider composites
            // Falls back to the default provider if not a composite or tier not specified
            const tierProvider = compositeTiers?.[tier]?.provider ?? provider;
            const normalizedTierModel = normalizeModelForThinkingLookup(model, tierProvider);
            // Check if this tier's model supports thinking (using tier-specific provider)
            if (!(0, model_catalog_1.supportsThinking)(tierProvider, normalizedTierModel)) {
                continue;
            }
            // Priority chain: CLI --thinking > per-tier config > global config > defaults
            let tierThinkingValue;
            if (thinkingOverride !== undefined) {
                // CLI override takes priority
                tierThinkingValue = thinkingOverride;
            }
            else {
                const perTierValue = compositeTierThinking?.[tier];
                if (perTierValue !== undefined) {
                    // Per-tier config from composite variant
                    tierThinkingValue = perTierValue;
                }
                else {
                    // Global config or defaults (use tier-specific provider for provider overrides)
                    tierThinkingValue = getThinkingValueForTier(tier, tierProvider, thinkingConfig);
                }
            }
            // If per-tier thinking is 'off', skip this tier
            if ((0, thinking_validator_1.isThinkingOffValue)(tierThinkingValue)) {
                continue;
            }
            // Validate/clamp tier thinking against this specific tier model capabilities.
            const tierValidation = (0, thinking_validator_1.validateThinking)(tierProvider, normalizedTierModel, tierThinkingValue);
            if (tierValidation.warning && shouldShowWarnings(thinkingConfig)) {
                console.warn((0, ui_1.warn)(tierValidation.warning));
            }
            tierThinkingValue = tierValidation.value;
            if ((0, thinking_validator_1.isThinkingOffValue)(tierThinkingValue)) {
                continue;
            }
            result[tierVar] = applyThinkingSuffixForProvider(model, tierThinkingValue, tierProvider);
        }
    }
    return result;
}
exports.applyThinkingConfig = applyThinkingConfig;
//# sourceMappingURL=thinking-config.js.map