import { fileURLToPath as __fileURLToPath } from 'url';
import { dirname as __pathDirname } from 'path';
const __filename = __fileURLToPath(import.meta.url);
const __dirname = __pathDirname(__filename);
import { logger } from "../../../core/monitoring/logger.js";
class ContextBudgetManager {
  config;
  tokenUsage = /* @__PURE__ */ new Map();
  DEFAULT_MAX_TOKENS = 4e3;
  TOKEN_CHAR_RATIO = 0.25;
  // Rough estimate: 1 token ≈ 4 chars
  constructor(config) {
    this.config = {
      maxTokens: config?.maxTokens || this.DEFAULT_MAX_TOKENS,
      priorityWeights: {
        task: config?.priorityWeights?.task || 0.3,
        recentWork: config?.priorityWeights?.recentWork || 0.25,
        feedback: config?.priorityWeights?.feedback || 0.2,
        gitHistory: config?.priorityWeights?.gitHistory || 0.15,
        dependencies: config?.priorityWeights?.dependencies || 0.1
      },
      compressionEnabled: config?.compressionEnabled ?? true,
      adaptiveBudgeting: config?.adaptiveBudgeting ?? true
    };
  }
  /**
   * Estimate tokens for a given text
   */
  estimateTokens(text) {
    if (!text) return 0;
    const baseTokens = text.length * this.TOKEN_CHAR_RATIO;
    const codeMultiplier = this.detectCodeContent(text) ? 1.2 : 1;
    const jsonMultiplier = this.detectJsonContent(text) ? 0.9 : 1;
    return Math.ceil(baseTokens * codeMultiplier * jsonMultiplier);
  }
  /**
   * Allocate token budget across different context categories
   */
  allocateBudget(context) {
    const currentTokens = this.calculateCurrentTokens(context);
    if (currentTokens <= this.config.maxTokens) {
      logger.debug("Context within budget", {
        used: currentTokens,
        max: this.config.maxTokens
      });
      return context;
    }
    logger.info("Context exceeds budget, optimizing...", {
      current: currentTokens,
      max: this.config.maxTokens
    });
    if (this.config.adaptiveBudgeting) {
      return this.adaptiveBudgetAllocation(context, currentTokens);
    }
    return this.priorityBasedAllocation(context, currentTokens);
  }
  /**
   * Compress context to fit within budget
   */
  compressContext(context) {
    if (!this.config.compressionEnabled) {
      return context;
    }
    const compressed = {
      ...context,
      task: this.compressTaskContext(context.task),
      history: this.compressHistoryContext(context.history),
      environment: this.compressEnvironmentContext(context.environment),
      memory: this.compressMemoryContext(context.memory),
      tokenCount: 0
    };
    compressed.tokenCount = this.calculateCurrentTokens(compressed);
    logger.debug("Context compressed", {
      original: context.tokenCount,
      compressed: compressed.tokenCount,
      reduction: `${Math.round((1 - compressed.tokenCount / context.tokenCount) * 100)}%`
    });
    return compressed;
  }
  /**
   * Get current token usage statistics
   */
  getUsage() {
    const categories = {};
    let totalUsed = 0;
    for (const [category, tokens] of this.tokenUsage) {
      categories[category] = tokens;
      totalUsed += tokens;
    }
    return {
      used: totalUsed,
      available: this.config.maxTokens - totalUsed,
      categories
    };
  }
  /**
   * Calculate current token count for context
   */
  calculateCurrentTokens(context) {
    this.tokenUsage.clear();
    const taskTokens = this.estimateTokens(JSON.stringify(context.task));
    const historyTokens = this.estimateTokens(JSON.stringify(context.history));
    const envTokens = this.estimateTokens(JSON.stringify(context.environment));
    const memoryTokens = this.estimateTokens(JSON.stringify(context.memory));
    this.tokenUsage.set("task", taskTokens);
    this.tokenUsage.set("history", historyTokens);
    this.tokenUsage.set("environment", envTokens);
    this.tokenUsage.set("memory", memoryTokens);
    return taskTokens + historyTokens + envTokens + memoryTokens;
  }
  /**
   * Adaptive budget allocation based on iteration phase
   */
  adaptiveBudgetAllocation(context, currentTokens) {
    const reductionRatio = this.config.maxTokens / currentTokens;
    const phase = this.determinePhase(context.task.currentIteration);
    const adjustedWeights = this.getPhaseAdjustedWeights(phase);
    return this.applyWeightedReduction(context, reductionRatio, adjustedWeights);
  }
  /**
   * Priority-based allocation using fixed weights
   */
  priorityBasedAllocation(context, currentTokens) {
    const reductionRatio = this.config.maxTokens / currentTokens;
    return this.applyWeightedReduction(context, reductionRatio, this.config.priorityWeights);
  }
  /**
   * Apply weighted reduction to context
   */
  applyWeightedReduction(context, reductionRatio, weights) {
    const reduced = { ...context };
    if (weights.recentWork < 1) {
      const keepCount = Math.ceil(
        context.history.recentIterations.length * reductionRatio * weights.recentWork
      );
      reduced.history = {
        ...context.history,
        recentIterations: context.history.recentIterations.slice(-keepCount)
      };
    }
    if (weights.gitHistory < 1) {
      const keepCount = Math.ceil(
        context.history.gitCommits.length * reductionRatio * weights.gitHistory
      );
      reduced.history.gitCommits = context.history.gitCommits.slice(-keepCount);
    }
    if (weights.dependencies < 1) {
      const keepCount = Math.ceil(
        context.memory.relevantFrames.length * reductionRatio * weights.dependencies
      );
      reduced.memory = {
        ...context.memory,
        relevantFrames: context.memory.relevantFrames.sort((a, b) => (b.created_at || 0) - (a.created_at || 0)).slice(0, keepCount)
      };
    }
    reduced.tokenCount = this.calculateCurrentTokens(reduced);
    return reduced;
  }
  /**
   * Compress task context
   */
  compressTaskContext(task) {
    return {
      ...task,
      description: this.truncateWithEllipsis(task.description, 500),
      criteria: task.criteria.slice(0, 5),
      // Keep top 5 criteria
      feedback: task.feedback ? this.truncateWithEllipsis(task.feedback, 300) : void 0
    };
  }
  /**
   * Compress history context
   */
  compressHistoryContext(history) {
    return {
      ...history,
      recentIterations: history.recentIterations.slice(-5).map((iter) => ({
        ...iter,
        summary: this.truncateWithEllipsis(iter.summary, 100)
      })),
      gitCommits: history.gitCommits.slice(-10).map((commit) => ({
        ...commit,
        message: this.truncateWithEllipsis(commit.message, 80),
        files: commit.files.slice(0, 5)
        // Keep top 5 files
      })),
      changedFiles: history.changedFiles.slice(0, 20),
      // Keep top 20 files
      testResults: history.testResults.slice(-3)
      // Keep last 3 test runs
    };
  }
  /**
   * Compress environment context
   */
  compressEnvironmentContext(env) {
    return {
      ...env,
      dependencies: this.compressObject(env.dependencies, 20),
      // Keep top 20 deps
      configuration: this.compressObject(env.configuration, 10)
      // Keep top 10 config items
    };
  }
  /**
   * Compress memory context
   */
  compressMemoryContext(memory) {
    return {
      ...memory,
      relevantFrames: memory.relevantFrames.slice(0, 5),
      // Keep top 5 frames
      decisions: memory.decisions.filter((d) => d.impact !== "low").slice(-5),
      // Keep last 5
      patterns: memory.patterns.filter((p) => p.successRate > 0.7).slice(0, 3),
      // Keep top 3
      blockers: memory.blockers.filter((b) => !b.resolved)
      // Keep unresolved only
    };
  }
  /**
   * Determine iteration phase
   */
  determinePhase(iteration) {
    if (iteration <= 3) return "early";
    if (iteration <= 10) return "middle";
    return "late";
  }
  /**
   * Get phase-adjusted weights
   */
  getPhaseAdjustedWeights(phase) {
    switch (phase) {
      case "early":
        return {
          task: 0.4,
          recentWork: 0.1,
          feedback: 0.2,
          gitHistory: 0.2,
          dependencies: 0.1
        };
      case "middle":
        return this.config.priorityWeights;
      case "late":
        return {
          task: 0.2,
          recentWork: 0.35,
          feedback: 0.25,
          gitHistory: 0.15,
          dependencies: 0.05
        };
    }
  }
  /**
   * Detect if text contains code
   */
  detectCodeContent(text) {
    const codePatterns = [
      /function\s+\w+\s*\(/,
      /class\s+\w+/,
      /const\s+\w+\s*=/,
      /import\s+.*from/,
      /\{[\s\S]*\}/
    ];
    return codePatterns.some((pattern) => pattern.test(text));
  }
  /**
   * Detect if text contains JSON
   */
  detectJsonContent(text) {
    try {
      JSON.parse(text);
      return true;
    } catch {
      return text.includes('"') && text.includes(":") && text.includes("{");
    }
  }
  /**
   * Truncate text with ellipsis
   */
  truncateWithEllipsis(text, maxLength) {
    if (text.length <= maxLength) return text;
    return text.substring(0, maxLength - 3) + "...";
  }
  /**
   * Compress object by keeping only top N entries
   */
  compressObject(obj, maxEntries) {
    const entries = Object.entries(obj);
    if (entries.length <= maxEntries) return obj;
    const compressed = {};
    entries.slice(0, maxEntries).forEach(([key, value]) => {
      compressed[key] = value;
    });
    return compressed;
  }
}
export {
  ContextBudgetManager
};
//# sourceMappingURL=context-budget-manager.js.map
