"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getAvailableModels = getAvailableModels;
exports.registerCustomModel = registerCustomModel;
exports.routeTask = routeTask;
exports.logModelCall = logModelCall;
exports.getCostStats = getCostStats;
exports.clearCostLog = clearCostLog;
exports.recordBenchmark = recordBenchmark;
exports.getBestModelForTask = getBestModelForTask;
exports.getBenchmarkStats = getBenchmarkStats;
exports.smartRouteTask = smartRouteTask;
exports.ensureCostTable = ensureCostTable;
exports.recordCloudBenchmark = recordCloudBenchmark;
exports.getCloudBestModelForTask = getCloudBestModelForTask;
exports.getCloudBenchmarkStats = getCloudBenchmarkStats;
const DEFAULT_MODELS = [
    { modelId: 'gpt-4o', name: 'GPT-4o', provider: 'openai', costPerToken: 0.00001, contextWindow: 128000, suitableFor: ['code_gen', 'code_review', 'explain', 'refactor', 'debug'], avgLatencyMs: 2000, qualityScore: 0.95 },
    { modelId: 'gpt-4o-mini', name: 'GPT-4o-mini', provider: 'openai', costPerToken: 0.0000015, contextWindow: 128000, suitableFor: ['simple_edit', 'explain', 'test_gen', 'code_review'], avgLatencyMs: 800, qualityScore: 0.85 },
    { modelId: 'claude-3-opus', name: 'Claude 3 Opus', provider: 'anthropic', costPerToken: 0.000015, contextWindow: 200000, suitableFor: ['code_gen', 'code_review', 'refactor', 'debug'], avgLatencyMs: 3000, qualityScore: 0.93 },
    { modelId: 'claude-3-haiku', name: 'Claude 3 Haiku', provider: 'anthropic', costPerToken: 0.0000025, contextWindow: 200000, suitableFor: ['simple_edit', 'explain', 'test_gen', 'code_review'], avgLatencyMs: 600, qualityScore: 0.82 },
    { modelId: 'deepseek-coder', name: 'DeepSeek Coder', provider: 'deepseek', costPerToken: 0.0000014, contextWindow: 128000, suitableFor: ['code_gen', 'code_review', 'refactor', 'debug', 'test_gen', 'simple_edit'], avgLatencyMs: 1200, qualityScore: 0.88 },
    { modelId: 'codestral', name: 'Codestral', provider: 'mistral', costPerToken: 0.000002, contextWindow: 32000, suitableFor: ['code_gen', 'code_review', 'simple_edit', 'test_gen'], avgLatencyMs: 1000, qualityScore: 0.84 },
];
const TASK_COMPLEXITY_MAP = {
    simple_edit: { complexity: 'low', estimatedTokens: 500 },
    explain: { complexity: 'low', estimatedTokens: 1000 },
    test_gen: { complexity: 'medium', estimatedTokens: 2000 },
    code_review: { complexity: 'medium', estimatedTokens: 3000 },
    debug: { complexity: 'medium', estimatedTokens: 2000 },
    refactor: { complexity: 'high', estimatedTokens: 4000 },
    code_gen: { complexity: 'high', estimatedTokens: 5000 },
};
const database_1 = require("../../06-memory/database/database");
const costLog = [];
const MAX_COST_LOG = 10000;
function getAvailableModels() {
    return DEFAULT_MODELS;
}
function registerCustomModel(model) {
    const idx = DEFAULT_MODELS.findIndex((m) => m.modelId === model.modelId);
    if (idx >= 0)
        DEFAULT_MODELS[idx] = model;
    else
        DEFAULT_MODELS.push(model);
}
function routeTask(task, budget) {
    const suitable = DEFAULT_MODELS
        .filter((m) => m.suitableFor.includes(task.taskType))
        .sort((a, b) => a.costPerToken - b.costPerToken);
    if (suitable.length === 0) {
        return {
            recommendedModel: 'gpt-4o-mini',
            reason: 'No suitable model found, defaulting to cheapest',
            estimatedCost: 0,
            estimatedLatencyMs: 0,
            alternatives: [],
        };
    }
    const tokenEstimate = TASK_COMPLEXITY_MAP[task.taskType]?.estimatedTokens || 1000;
    const budgetMode = budget || (task.complexity === 'low' ? 'cheapest' : task.complexity === 'high' ? 'best' : 'balanced');
    let chosen;
    let reason;
    if (budgetMode === 'cheapest') {
        chosen = suitable[0];
        reason = `Cheapest suitable model for ${task.taskType}`;
    }
    else if (budgetMode === 'best') {
        chosen = suitable.sort((a, b) => b.qualityScore - a.qualityScore)[0];
        reason = `Highest quality model for ${task.taskType}`;
    }
    else {
        chosen = suitable.sort((a, b) => {
            const ratioA = a.costPerToken > 0 ? a.qualityScore / a.costPerToken : 0;
            const ratioB = b.costPerToken > 0 ? b.qualityScore / b.costPerToken : 0;
            return ratioA - ratioB;
        }).reverse()[0];
        reason = `Best quality/cost ratio for ${task.taskType}`;
    }
    const estimatedCost = chosen.costPerToken * tokenEstimate;
    const alternatives = suitable
        .filter((m) => m.modelId !== chosen.modelId)
        .slice(0, 3)
        .map((m) => ({
        modelId: m.modelId,
        cost: m.costPerToken * tokenEstimate,
        qualityDelta: Math.round((chosen.qualityScore - m.qualityScore) * 100),
    }));
    return {
        recommendedModel: chosen.modelId,
        reason,
        estimatedCost: Math.round(estimatedCost * 100000) / 100000,
        estimatedLatencyMs: chosen.avgLatencyMs,
        alternatives,
    };
}
function logModelCall(modelId, tokens, taskType) {
    const model = DEFAULT_MODELS.find((m) => m.modelId === modelId);
    const cost = model ? model.costPerToken * tokens : 0;
    costLog.push({ modelId, tokens, cost, taskType, timestamp: Date.now() });
    if (costLog.length > MAX_COST_LOG)
        costLog.splice(0, costLog.length - MAX_COST_LOG);
}
function getCostStats() {
    const totalCost = costLog.reduce((s, e) => s + e.cost, 0);
    const totalTokens = costLog.reduce((s, e) => s + e.tokens, 0);
    const totalRequests = costLog.length;
    const perModelMap = new Map();
    for (const entry of costLog) {
        const m = perModelMap.get(entry.modelId) || { requests: 0, cost: 0, tokens: 0 };
        m.requests++;
        m.cost += entry.cost;
        m.tokens += entry.tokens;
        perModelMap.set(entry.modelId, m);
    }
    // Estimate savings: compare to using most expensive model for everything
    const mostExpensive = DEFAULT_MODELS.reduce((max, m) => m.costPerToken > max.costPerToken ? m : max, DEFAULT_MODELS[0]);
    const naiveCost = totalTokens * mostExpensive.costPerToken;
    return {
        totalCost: Math.round(totalCost * 100000) / 100000,
        totalTokens,
        totalRequests,
        perModel: Array.from(perModelMap.entries()).map(([modelId, data]) => ({
            modelId, ...data,
            cost: Math.round(data.cost * 100000) / 100000,
        })),
        savingsEstimate: Math.round((naiveCost - totalCost) * 100000) / 100000,
    };
}
function clearCostLog() {
    costLog.length = 0;
}
const benchmarks = [];
const MAX_BENCHMARKS = 5000;
function recordBenchmark(entry) {
    benchmarks.push(entry);
    if (benchmarks.length > MAX_BENCHMARKS)
        benchmarks.splice(0, benchmarks.length - MAX_BENCHMARKS);
}
function getBestModelForTask(taskType, prioritize = 'quality') {
    const entries = benchmarks.filter((b) => b.taskType === taskType);
    if (entries.length < 2)
        return null;
    const grouped = new Map();
    for (const e of entries) {
        const g = grouped.get(e.modelId) || { totalQuality: 0, totalCost: 0, totalLatency: 0, count: 0 };
        g.totalQuality += e.quality;
        g.totalCost += e.cost;
        g.totalLatency += e.latencyMs;
        g.count++;
        grouped.set(e.modelId, g);
    }
    const scored = Array.from(grouped.entries()).map(([modelId, data]) => {
        const avgQuality = data.totalQuality / data.count;
        const avgCost = data.totalCost / data.count;
        const avgLatency = data.totalLatency / data.count;
        let score = 0;
        if (prioritize === 'quality')
            score = avgQuality;
        else if (prioritize === 'cost')
            score = -avgCost;
        else
            score = -avgLatency;
        return { modelId, avgQuality, avgCost, avgLatency, samples: data.count, score };
    });
    scored.sort((a, b) => b.score - a.score);
    return scored[0];
}
function getBenchmarkStats() {
    const byTask = new Map();
    for (const b of benchmarks) {
        const t = byTask.get(b.taskType) || { count: 0, best: '' };
        t.count++;
        byTask.set(b.taskType, t);
    }
    return {
        totalBenchmarks: benchmarks.length,
        perTask: Array.from(byTask.entries()).map(([taskType, data]) => ({
            taskType,
            count: data.count,
            bestModel: getBestModelForTask(taskType)?.modelId || 'insufficient_data',
        })),
    };
}
// ─── SMART ROUTING ──────────────────────────────────
function smartRouteTask(task) {
    const priorDecision = routeTask(task, task.complexity === 'low' ? 'cheapest' : task.complexity === 'high' ? 'best' : 'balanced');
    const bestFromBenchmarks = getBestModelForTask(task.taskType, task.complexity === 'low' ? 'cost' : 'quality');
    if (bestFromBenchmarks) {
        const model = DEFAULT_MODELS.find((m) => m.modelId === bestFromBenchmarks.modelId);
        if (model) {
            return {
                recommendedModel: model.modelId,
                reason: `Smart routing: ${bestFromBenchmarks.avgQuality.toFixed(2)} avg quality from ${bestFromBenchmarks.samples} benchmarks`,
                estimatedCost: Math.round(model.costPerToken * task.estimatedTokens * 100000) / 100000,
                estimatedLatencyMs: Math.round(bestFromBenchmarks.avgLatency),
                alternatives: priorDecision.alternatives,
            };
        }
    }
    return priorDecision;
}
// ─── CLOUD BENCHMARK DB (SQLite) ─────────────────────
function ensureCostTable() {
    const db = (0, database_1.getDb)();
    db.exec(`CREATE TABLE IF NOT EXISTS cost_benchmarks (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    model_id TEXT NOT NULL,
    task_type TEXT NOT NULL,
    tokens_used INT NOT NULL,
    latency_ms INT NOT NULL,
    quality REAL NOT NULL,
    cost REAL NOT NULL
  )`);
}
function recordCloudBenchmark(entry) {
    const db = (0, database_1.getDb)();
    db.prepare(`INSERT INTO cost_benchmarks (model_id, task_type, tokens_used, latency_ms, quality, cost) VALUES (?, ?, ?, ?, ?, ?)`)
        .run(entry.modelId, entry.taskType, entry.tokensUsed, entry.latencyMs, entry.quality, entry.cost);
}
function getCloudBestModelForTask(taskType, prioritize = 'quality') {
    const db = (0, database_1.getDb)();
    const rows = db.prepare(`SELECT model_id, AVG(quality) as avg_quality, AVG(cost) as avg_cost, AVG(latency_ms) as avg_latency, COUNT(*) as samples FROM cost_benchmarks WHERE task_type = ? GROUP BY model_id`).all(taskType);
    if (rows.length < 2)
        return null;
    const scored = rows.map((r) => {
        let score = 0;
        if (prioritize === 'quality')
            score = r.avg_quality;
        else if (prioritize === 'cost')
            score = -r.avg_cost;
        else
            score = -r.avg_latency;
        return { modelId: r.model_id, avgQuality: r.avg_quality, avgCost: r.avg_cost, avgLatency: r.avg_latency, samples: r.samples, score };
    });
    scored.sort((a, b) => b.score - a.score);
    return scored[0];
}
function getCloudBenchmarkStats() {
    const db = (0, database_1.getDb)();
    const totalRow = db.prepare(`SELECT COUNT(*) as total FROM cost_benchmarks`).get();
    const perTask = db.prepare(`SELECT task_type, COUNT(*) as count, AVG(quality) as avg_quality, AVG(cost) as avg_cost FROM cost_benchmarks GROUP BY task_type`).all();
    return { totalBenchmarks: totalRow?.total || 0, perTask };
}
//# sourceMappingURL=cost-optimizer.js.map