{"version":3,"file":"pruneCalibration.cjs","sources":["../../../src/utils/pruneCalibration.ts"],"sourcesContent":["// src/utils/pruneCalibration.ts\nimport type { PruneCalibrationState } from '@/types/graph';\nimport {\n  PRUNING_EMA_ALPHA,\n  PRUNING_INITIAL_CALIBRATION,\n} from '@/common/constants';\n\n/**\n * Creates an initial pruning calibration state.\n *\n * @param initialRatio - Starting calibration ratio (default: 1.0)\n * @returns Fresh calibration state\n */\nexport function createPruneCalibration(\n  initialRatio?: number\n): PruneCalibrationState {\n  return {\n    ratio: initialRatio ?? PRUNING_INITIAL_CALIBRATION,\n    iterations: 0,\n  };\n}\n\n/**\n * Updates the pruning calibration using Exponential Moving Average (EMA).\n *\n * Problem: Without calibration, the pruner's token estimates can diverge from\n * reality across iterations, causing either:\n * - Over-pruning (context cliff): Too many messages removed at once, losing critical tool results\n * - Under-pruning: Not enough messages removed, hitting hard token limits\n *\n * Solution: Track the ratio between actual token usage (from API response) and\n * estimated token usage (from our token counter). Apply EMA smoothing so the\n * calibration adjusts gradually, preventing oscillation.\n *\n * The calibration ratio is applied to maxTokens in the pruner:\n *   effectiveMaxTokens = maxTokens * calibrationRatio\n *\n * If actual > estimated → ratio decreases → prune more aggressively\n * If actual < estimated → ratio increases → prune less aggressively\n *\n * @param state - Current calibration state\n * @param actualTokens - Actual token count from API response (UsageMetadata)\n * @param estimatedTokens - Estimated token count from token counter\n * @param alpha - EMA smoothing factor (default: PRUNING_EMA_ALPHA)\n * @returns Updated calibration state (new object, does not mutate input)\n */\nexport function updatePruneCalibration(\n  state: PruneCalibrationState,\n  actualTokens: number,\n  estimatedTokens: number,\n  alpha: number = PRUNING_EMA_ALPHA\n): PruneCalibrationState {\n  // Guard against division by zero or invalid inputs\n  if (estimatedTokens <= 0 || actualTokens <= 0) {\n    return state;\n  }\n\n  // Raw ratio: how much our estimate differs from reality\n  const observedRatio = estimatedTokens / actualTokens;\n\n  // Clamp to prevent extreme adjustments from outlier readings\n  // Range [0.5, 2.0] means we never more than double or halve the budget\n  const clampedRatio = Math.max(0.5, Math.min(2.0, observedRatio));\n\n  // Apply EMA: new_ratio = α * observed + (1 - α) * previous\n  const newRatio = alpha * clampedRatio + (1 - alpha) * state.ratio;\n\n  return {\n    ratio: newRatio,\n    iterations: state.iterations + 1,\n  };\n}\n\n/**\n * Applies the calibration ratio to a max token budget.\n * The ratio adjusts the effective budget so pruning is more or less aggressive\n * based on observed vs. estimated token divergence.\n *\n * @param maxTokens - Raw max token budget\n * @param state - Current calibration state\n * @returns Adjusted max token budget\n */\nexport function applyCalibration(\n  maxTokens: number,\n  state: PruneCalibrationState\n): number {\n  if (state.iterations === 0) {\n    // No calibration data yet — use raw budget\n    return maxTokens;\n  }\n  return Math.floor(maxTokens * state.ratio);\n}\n"],"names":["PRUNING_INITIAL_CALIBRATION","PRUNING_EMA_ALPHA"],"mappings":";;;;AAOA;;;;;AAKG;AACG,SAAU,sBAAsB,CACpC,YAAqB,EAAA;IAErB,OAAO;QACL,KAAK,EAAE,YAAY,IAAIA,qCAA2B;AAClD,QAAA,UAAU,EAAE,CAAC;KACd;AACH;AAEA;;;;;;;;;;;;;;;;;;;;;;;AAuBG;AACG,SAAU,sBAAsB,CACpC,KAA4B,EAC5B,YAAoB,EACpB,eAAuB,EACvB,KAAA,GAAgBC,2BAAiB,EAAA;;IAGjC,IAAI,eAAe,IAAI,CAAC,IAAI,YAAY,IAAI,CAAC,EAAE;AAC7C,QAAA,OAAO,KAAK;IACd;;AAGA,IAAA,MAAM,aAAa,GAAG,eAAe,GAAG,YAAY;;;AAIpD,IAAA,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;;AAGhE,IAAA,MAAM,QAAQ,GAAG,KAAK,GAAG,YAAY,GAAG,CAAC,CAAC,GAAG,KAAK,IAAI,KAAK,CAAC,KAAK;IAEjE,OAAO;AACL,QAAA,KAAK,EAAE,QAAQ;AACf,QAAA,UAAU,EAAE,KAAK,CAAC,UAAU,GAAG,CAAC;KACjC;AACH;AAEA;;;;;;;;AAQG;AACG,SAAU,gBAAgB,CAC9B,SAAiB,EACjB,KAA4B,EAAA;AAE5B,IAAA,IAAI,KAAK,CAAC,UAAU,KAAK,CAAC,EAAE;;AAE1B,QAAA,OAAO,SAAS;IAClB;IACA,OAAO,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC;AAC5C;;;;;;"}