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 "../monitoring/logger.js";
class CompactionHandler {
  frameManager;
  metrics;
  tokenAccumulator = 0;
  preservedAnchors = /* @__PURE__ */ new Map();
  constructor(frameManager) {
    this.frameManager = frameManager;
    this.metrics = {
      estimatedTokens: 0,
      warningThreshold: 15e4,
      // 150K tokens
      criticalThreshold: 17e4,
      // 170K tokens
      anchorsPreserved: 0
    };
  }
  /**
   * Track token usage from a message
   */
  trackTokens(content) {
    const estimatedTokens = Math.ceil(content.length / 4);
    this.tokenAccumulator += estimatedTokens;
    this.metrics.estimatedTokens += estimatedTokens;
    if (this.isApproachingCompaction()) {
      this.preserveCriticalContext();
    }
  }
  /**
   * Check if approaching compaction threshold
   */
  isApproachingCompaction() {
    return this.metrics.estimatedTokens >= this.metrics.warningThreshold;
  }
  /**
   * Check if past critical threshold
   */
  isPastCriticalThreshold() {
    return this.metrics.estimatedTokens >= this.metrics.criticalThreshold;
  }
  /**
   * Detect if compaction likely occurred
   */
  detectCompactionEvent(content) {
    const compactionIndicators = [
      "earlier in this conversation",
      "previously discussed",
      "as mentioned before",
      "summarized for brevity",
      "[conversation compressed]",
      "[context truncated]"
    ];
    const lowerContent = content.toLowerCase();
    return compactionIndicators.some(
      (indicator) => lowerContent.includes(indicator)
    );
  }
  /**
   * Preserve critical context before compaction
   */
  async preserveCriticalContext() {
    try {
      const currentFrameId = this.frameManager.getCurrentFrameId();
      if (!currentFrameId) {
        logger.warn("No active frame to preserve context from");
        return;
      }
      const events = this.frameManager.getFrameEvents(currentFrameId);
      const toolCalls = this.extractToolCalls(events);
      const fileOps = this.extractFileOperations(events);
      const decisions = this.extractDecisions(events);
      const errorPatterns = this.extractErrorPatterns(events);
      const anchor = {
        anchor_id: `compact_${Date.now()}`,
        type: "COMPACTION_PRESERVE",
        priority: 10,
        content: {
          tool_calls: toolCalls,
          file_operations: fileOps,
          decisions,
          error_resolutions: errorPatterns
        },
        created_at: Date.now(),
        token_estimate: this.metrics.estimatedTokens
      };
      this.frameManager.addAnchor(
        "CONSTRAINT",
        // Using CONSTRAINT type for now
        JSON.stringify(anchor),
        10,
        {
          compaction_preserve: true,
          token_count: this.metrics.estimatedTokens
        },
        currentFrameId
      );
      this.preservedAnchors.set(anchor.anchor_id, anchor);
      this.metrics.anchorsPreserved++;
      logger.info(
        `Preserved critical context at ${this.metrics.estimatedTokens} tokens`
      );
    } catch (error) {
      logger.error(
        "Failed to preserve critical context:",
        error instanceof Error ? error : void 0
      );
    }
  }
  /**
   * Extract tool calls from events
   */
  extractToolCalls(events) {
    const toolCalls = [];
    const toolEvents = events.filter((e) => e.event_type === "tool_call");
    for (const event of toolEvents) {
      const resultEvent = events.find(
        (e) => e.event_type === "tool_result" && e.seq > event.seq && e.payload.tool_name === event.payload.tool_name
      );
      toolCalls.push({
        tool: event.payload.tool_name || "unknown",
        timestamp: event.ts,
        key_inputs: this.extractKeyInputs(event.payload),
        key_outputs: resultEvent ? this.extractKeyOutputs(resultEvent.payload) : {},
        files_affected: this.extractAffectedFiles(
          event.payload,
          resultEvent?.payload
        ),
        success: resultEvent ? !resultEvent.payload.error : false,
        error: resultEvent?.payload.error
      });
    }
    return toolCalls;
  }
  /**
   * Extract key inputs from tool call
   */
  extractKeyInputs(payload) {
    const keys = [
      "file_path",
      "command",
      "query",
      "path",
      "pattern",
      "content"
    ];
    const result = {};
    for (const key of keys) {
      if (payload.arguments?.[key]) {
        result[key] = payload.arguments[key];
      }
    }
    return result;
  }
  /**
   * Extract key outputs from tool result
   */
  extractKeyOutputs(payload) {
    return {
      success: !payload.error,
      error: payload.error,
      result_type: payload.result_type,
      files_created: payload.files_created,
      files_modified: payload.files_modified
    };
  }
  /**
   * Extract affected files from tool events
   */
  extractAffectedFiles(callPayload, resultPayload) {
    const files = /* @__PURE__ */ new Set();
    if (callPayload?.arguments?.file_path) {
      files.add(callPayload.arguments.file_path);
    }
    if (callPayload?.arguments?.path) {
      files.add(callPayload.arguments.path);
    }
    if (resultPayload?.files_created) {
      resultPayload.files_created.forEach((f) => files.add(f));
    }
    if (resultPayload?.files_modified) {
      resultPayload.files_modified.forEach((f) => files.add(f));
    }
    return Array.from(files);
  }
  /**
   * Extract file operations from events
   */
  extractFileOperations(events) {
    const fileOps = [];
    const fileTools = ["Read", "Write", "Edit", "MultiEdit", "Delete"];
    const toolEvents = events.filter(
      (e) => e.event_type === "tool_call" && fileTools.includes(e.payload.tool_name)
    );
    for (const event of toolEvents) {
      const operation = this.mapToolToOperation(event.payload.tool_name);
      const path = event.payload.arguments?.file_path || event.payload.arguments?.path || "unknown";
      fileOps.push({
        type: operation,
        path,
        timestamp: event.ts,
        success: true,
        // Will be updated from result
        error: void 0
      });
    }
    return fileOps;
  }
  /**
   * Map tool name to file operation type
   */
  mapToolToOperation(toolName) {
    const mapping = {
      Read: "read",
      Write: "write",
      Edit: "edit",
      MultiEdit: "edit",
      Delete: "delete"
    };
    return mapping[toolName] || "read";
  }
  /**
   * Extract decisions from events
   */
  extractDecisions(events) {
    const decisions = [];
    const decisionEvents = events.filter((e) => e.event_type === "decision");
    for (const event of decisionEvents) {
      if (event.payload.text) {
        decisions.push(event.payload.text);
      }
    }
    return decisions;
  }
  /**
   * Extract error patterns and resolutions
   */
  extractErrorPatterns(events) {
    const patterns = [];
    const errorEvents = events.filter(
      (e) => e.event_type === "tool_result" && e.payload.error
    );
    for (const errorEvent of errorEvents) {
      const subsequentTools = events.filter((e) => e.event_type === "tool_call" && e.seq > errorEvent.seq).slice(0, 3);
      if (subsequentTools.length > 0) {
        patterns.push({
          error: errorEvent.payload.error,
          resolution: `Attempted resolution with ${subsequentTools.map((t) => t.payload.tool_name).join(", ")}`,
          tool_sequence: subsequentTools.map((t) => t.payload.tool_name),
          timestamp: errorEvent.ts
        });
      }
    }
    return patterns;
  }
  /**
   * Restore context after compaction detected
   */
  async restoreContext() {
    if (this.preservedAnchors.size === 0) {
      logger.warn("No preserved anchors to restore from");
      return;
    }
    const anchors = Array.from(this.preservedAnchors.values());
    anchors.sort((a, b) => b.created_at - a.created_at);
    const latestAnchor = anchors[0];
    const restorationFrame = this.frameManager.createFrame({
      type: "review",
      name: "Context Restoration After Compaction",
      inputs: { reason: "autocompaction_detected" }
    });
    this.frameManager.addAnchor(
      "FACT",
      `Context restored from token position ${latestAnchor.token_estimate}`,
      10,
      { restoration: true },
      restorationFrame
    );
    const toolSequence = latestAnchor.content.tool_calls.map((t) => t.tool).join(" \u2192 ");
    this.frameManager.addAnchor(
      "FACT",
      `Tool sequence: ${toolSequence}`,
      9,
      {},
      restorationFrame
    );
    const files = /* @__PURE__ */ new Set();
    latestAnchor.content.file_operations.forEach((op) => files.add(op.path));
    if (files.size > 0) {
      this.frameManager.addAnchor(
        "FACT",
        `Files touched: ${Array.from(files).join(", ")}`,
        8,
        {},
        restorationFrame
      );
    }
    for (const decision of latestAnchor.content.decisions) {
      this.frameManager.addAnchor(
        "DECISION",
        decision,
        7,
        {},
        restorationFrame
      );
    }
    logger.info("Context restored after compaction detection");
  }
  /**
   * Get current metrics
   */
  getMetrics() {
    return { ...this.metrics };
  }
  /**
   * Reset token counter (e.g., at session start)
   */
  resetTokenCount() {
    this.metrics.estimatedTokens = 0;
    this.tokenAccumulator = 0;
    this.metrics.lastCompactionAt = void 0;
  }
}
export {
  CompactionHandler
};
//# sourceMappingURL=compaction-handler.js.map
