// engine/model-router/historical-learner.ts — Learn from past model outcomes.
// SPEC-076 AC-03
// ---------------------------------------------------------------------------
// In-memory outcome store (JSON persistence is left to the storage layer)
// ---------------------------------------------------------------------------
let outcomes = [];
const TIER_ORDER = ['haiku', 'sonnet', 'opus'];
function tierIndex(tier) {
    return TIER_ORDER.indexOf(tier);
}
function tierByIndex(index) {
    const clamped = Math.max(0, Math.min(index, TIER_ORDER.length - 1));
    return TIER_ORDER[clamped] ?? 'sonnet';
}
// ---------------------------------------------------------------------------
// Public API
// ---------------------------------------------------------------------------
/** Record a model outcome for future learning. */
export function recordOutcome(outcome) {
    outcomes.push(outcome);
}
/** Get all recorded outcomes (for testing / export). */
export function getOutcomes() {
    return outcomes;
}
/** Clear all outcomes (for testing). */
export function clearOutcomes() {
    outcomes = [];
}
/** Load outcomes from an external source (e.g. JSON file). */
export function loadOutcomes(loaded) {
    outcomes = [...loaded];
}
/**
 * Find outcomes whose taskSignature matches the given signature.
 * Uses exact match for now; vector similarity can be added later (SPEC-075).
 */
export function findSimilarOutcomes(taskSignature) {
    return outcomes.filter((o) => o.taskSignature === taskSignature);
}
/**
 * Compute a task signature from a description or spec ID.
 * For now this is a simple normalisation; in the future it can use embeddings.
 */
export function computeTaskSignature(text) {
    return text.trim().toLowerCase().replace(/\s+/g, '-').slice(0, 80);
}
/**
 * Given the rules engine recommendation and a task signature,
 * adjust the tier based on historical outcomes.
 * Maximum adjustment: plus or minus 1 tier.
 */
export function adjustFromHistory(recommendedModel, taskSignature) {
    const similar = findSimilarOutcomes(taskSignature);
    if (similar.length === 0) {
        return {
            adjustedModel: recommendedModel,
            reason: 'No historical data available.',
            adjusted: false,
        };
    }
    const successCount = similar.filter((o) => o.success).length;
    const failCount = similar.length - successCount;
    const successRate = successCount / similar.length;
    // Check if a lighter model was consistently successful
    const lighterSuccesses = similar.filter((o) => o.success && tierIndex(o.modelUsed) < tierIndex(recommendedModel));
    if (lighterSuccesses.length >= 2 && successRate > 0.8) {
        const lighterTier = tierByIndex(tierIndex(recommendedModel) - 1);
        return {
            adjustedModel: lighterTier,
            reason: `Historical data shows a lighter model (${lighterTier}) succeeded ${String(lighterSuccesses.length)} times for similar tasks.`,
            adjusted: true,
        };
    }
    // Check if the recommended model or lighter models frequently failed
    const recFailures = similar.filter((o) => !o.success && tierIndex(o.modelUsed) <= tierIndex(recommendedModel));
    if (recFailures.length >= 2 && failCount > successCount) {
        const heavierTier = tierByIndex(tierIndex(recommendedModel) + 1);
        return {
            adjustedModel: heavierTier,
            reason: `Historical data shows ${String(recFailures.length)} failures at tier ${recommendedModel} or below — upgrading to ${heavierTier}.`,
            adjusted: true,
        };
    }
    return {
        adjustedModel: recommendedModel,
        reason: 'Historical data supports the current recommendation.',
        adjusted: false,
    };
}
//# sourceMappingURL=historical-learner.js.map