/**
 * Middleware Implementations
 *
 * Concrete middleware implementations for conversation control:
 * - TurnLimitMiddleware: Prevents conversations from exceeding turn limits
 * - PriceLimitMiddleware: Monitors and limits session costs
 * - AutoCompactMiddleware: Automatically compacts context when needed
 * - ContextWarningMiddleware: Warns when context is filling up
 */
import { continueResult, stopResult, compactResult, injectMessageResult, } from './types.js';
// ============================================================================
// Turn Limit Middleware
// ============================================================================
/**
 * Prevents conversations from exceeding a maximum turn count
 */
export class TurnLimitMiddleware {
    name = 'turn-limit';
    priority = 10;
    config;
    warningIssued = false;
    constructor(config) {
        this.config = {
            maxTurns: config.maxTurns,
            warningThreshold: config.warningThreshold ?? 0.8,
        };
    }
    async beforeTurn(context) {
        const { turns } = context.stats;
        const { maxTurns, warningThreshold } = this.config;
        // Check if we've exceeded the limit
        if (turns >= maxTurns) {
            return stopResult(`Turn limit reached (${turns}/${maxTurns})`, `Conversation stopped: Maximum turn limit of ${maxTurns} reached. Use /clear to start a new conversation.`);
        }
        // Issue warning if approaching limit
        const warningTurns = Math.floor(maxTurns * warningThreshold);
        if (turns >= warningTurns && !this.warningIssued) {
            this.warningIssued = true;
            return injectMessageResult(`Warning: Approaching turn limit (${turns}/${maxTurns}). Consider summarizing or starting a new conversation.`, 'Turn limit warning');
        }
        return continueResult();
    }
    async afterTurn(_context) {
        return continueResult();
    }
    reset() {
        this.warningIssued = false;
    }
}
// ============================================================================
// Price Limit Middleware
// ============================================================================
/**
 * Monitors and limits session costs
 */
export class PriceLimitMiddleware {
    name = 'price-limit';
    priority = 20;
    config;
    warningIssued = false;
    constructor(config) {
        this.config = {
            maxCost: config.maxCost,
            warningThreshold: config.warningThreshold ?? 0.8,
        };
    }
    async beforeTurn(context) {
        const { sessionCost } = context.stats;
        const { maxCost, warningThreshold } = this.config;
        // Check if we've exceeded the cost limit
        if (sessionCost >= maxCost) {
            return stopResult(`Cost limit reached ($${sessionCost.toFixed(4)}/$${maxCost.toFixed(2)})`, `Conversation stopped: Session cost limit of $${maxCost.toFixed(2)} reached (current: $${sessionCost.toFixed(4)}). Use /clear to start a new session.`);
        }
        // Issue warning if approaching limit
        const warningCost = maxCost * warningThreshold;
        if (sessionCost >= warningCost && !this.warningIssued) {
            this.warningIssued = true;
            const remaining = maxCost - sessionCost;
            return injectMessageResult(`Warning: Session cost is $${sessionCost.toFixed(4)} of $${maxCost.toFixed(2)} limit. $${remaining.toFixed(4)} remaining.`, 'Cost limit warning');
        }
        return continueResult();
    }
    async afterTurn(context) {
        // Re-check after turn in case we went over
        const { sessionCost } = context.stats;
        const { maxCost } = this.config;
        if (sessionCost >= maxCost) {
            return stopResult(`Cost limit exceeded ($${sessionCost.toFixed(4)}/$${maxCost.toFixed(2)})`, `Session cost limit exceeded. Current session cost: $${sessionCost.toFixed(4)}`);
        }
        return continueResult();
    }
    reset() {
        this.warningIssued = false;
    }
}
// ============================================================================
// Auto Compact Middleware
// ============================================================================
/**
 * Automatically triggers context compaction when token usage is high
 */
export class AutoCompactMiddleware {
    name = 'auto-compact';
    priority = 30;
    config;
    lastCompactTokens = 0;
    constructor(config) {
        this.config = {
            tokenThreshold: config.tokenThreshold,
            contextPercentage: config.contextPercentage ?? 0.75,
            minMessagesToKeep: config.minMessagesToKeep ?? 4,
        };
    }
    async beforeTurn(context) {
        const { totalTokens } = context.stats;
        const { maxContextTokens } = context.model;
        const { tokenThreshold, contextPercentage, minMessagesToKeep } = this.config;
        // Calculate effective threshold
        const effectiveThreshold = Math.min(tokenThreshold, Math.floor(maxContextTokens * contextPercentage));
        // Check if we need to compact
        // Only compact if we've grown significantly since last compaction
        if (totalTokens >= effectiveThreshold && totalTokens > this.lastCompactTokens * 1.5) {
            // Don't compact if we have very few messages
            if (context.messages.length <= minMessagesToKeep) {
                return continueResult();
            }
            this.lastCompactTokens = totalTokens;
            return compactResult(`Token usage (${totalTokens}) exceeds threshold (${effectiveThreshold})`, {
                previousTokens: totalTokens,
                threshold: effectiveThreshold,
                messageCount: context.messages.length,
            });
        }
        return continueResult();
    }
    async afterTurn(_context) {
        return continueResult();
    }
    reset() {
        this.lastCompactTokens = 0;
    }
}
// ============================================================================
// Context Warning Middleware
// ============================================================================
/**
 * Issues a warning when context usage reaches a threshold
 */
export class ContextWarningMiddleware {
    name = 'context-warning';
    priority = 40;
    config;
    warningIssued = false;
    constructor(config) {
        this.config = {
            warningPercentage: config.warningPercentage,
            warnOnce: config.warnOnce ?? true,
        };
    }
    async beforeTurn(context) {
        const { totalTokens } = context.stats;
        const { maxContextTokens } = context.model;
        const { warningPercentage, warnOnce } = this.config;
        // Skip if already warned and warnOnce is enabled
        if (warnOnce && this.warningIssued) {
            return continueResult();
        }
        const usagePercentage = (totalTokens / maxContextTokens) * 100;
        const threshold = warningPercentage * 100;
        if (usagePercentage >= threshold) {
            this.warningIssued = true;
            const formattedUsage = usagePercentage.toFixed(1);
            const formattedTokens = totalTokens.toLocaleString();
            const formattedMax = maxContextTokens.toLocaleString();
            return injectMessageResult(`Context usage: ${formattedUsage}% (${formattedTokens}/${formattedMax} tokens). Consider using /compact or /clear to free up space.`, 'Context usage warning');
        }
        return continueResult();
    }
    async afterTurn(_context) {
        return continueResult();
    }
    reset() {
        this.warningIssued = false;
    }
}
// ============================================================================
// Rate Limit Middleware
// ============================================================================
/**
 * Prevents rapid-fire requests (optional rate limiting)
 */
export class RateLimitMiddleware {
    name = 'rate-limit';
    priority = 5;
    lastRequestTime = 0;
    minIntervalMs;
    constructor(minIntervalMs = 500) {
        this.minIntervalMs = minIntervalMs;
    }
    async beforeTurn(_context) {
        const now = Date.now();
        const elapsed = now - this.lastRequestTime;
        if (elapsed < this.minIntervalMs && this.lastRequestTime > 0) {
            // Wait for the remaining time
            await new Promise(resolve => setTimeout(resolve, this.minIntervalMs - elapsed));
        }
        this.lastRequestTime = Date.now();
        return continueResult();
    }
    async afterTurn(_context) {
        return continueResult();
    }
    reset() {
        this.lastRequestTime = 0;
    }
}
// ============================================================================
// Tool Execution Limit Middleware
// ============================================================================
/**
 * Limits the number of tool executions per turn
 */
export class ToolExecutionLimitMiddleware {
    name = 'tool-execution-limit';
    priority = 15;
    maxToolCallsPerTurn;
    currentTurnToolCalls = 0;
    constructor(maxToolCallsPerTurn = 20) {
        this.maxToolCallsPerTurn = maxToolCallsPerTurn;
    }
    async beforeTurn(_context) {
        // Reset counter at start of turn
        this.currentTurnToolCalls = 0;
        return continueResult();
    }
    async afterTurn(_context) {
        // Check if we've exceeded tool calls this turn
        // This would need integration with tool executor to track per-turn calls
        return continueResult();
    }
    /**
     * Called by tool executor before each tool call
     */
    checkToolCall() {
        this.currentTurnToolCalls++;
        return this.currentTurnToolCalls <= this.maxToolCallsPerTurn;
    }
    reset() {
        this.currentTurnToolCalls = 0;
    }
}
// ============================================================================
// Factory Functions
// ============================================================================
/**
 * Create default middleware stack
 */
export function createDefaultMiddlewares(options) {
    const middlewares = [];
    // Turn limit (default: 100 turns)
    middlewares.push(new TurnLimitMiddleware({
        maxTurns: options?.maxTurns ?? 100,
        warningThreshold: 0.8,
    }));
    // Price limit (default: $10)
    middlewares.push(new PriceLimitMiddleware({
        maxCost: options?.maxCost ?? 10,
        warningThreshold: 0.8,
    }));
    // Auto-compact (default: 80k tokens)
    middlewares.push(new AutoCompactMiddleware({
        tokenThreshold: options?.autoCompactThreshold ?? 80000,
        contextPercentage: 0.75,
        minMessagesToKeep: 4,
    }));
    // Context warning (default: 70%)
    middlewares.push(new ContextWarningMiddleware({
        warningPercentage: options?.contextWarningPercentage ?? 0.70,
        warnOnce: true,
    }));
    return middlewares;
}
/**
 * Create YOLO mode middleware stack (relaxed limits)
 */
export function createYoloMiddlewares(options) {
    const middlewares = [];
    // Higher turn limit for YOLO
    middlewares.push(new TurnLimitMiddleware({
        maxTurns: options?.maxTurns ?? 500,
        warningThreshold: 0.9,
    }));
    // Higher cost limit for YOLO
    middlewares.push(new PriceLimitMiddleware({
        maxCost: options?.maxCost ?? 50,
        warningThreshold: 0.9,
    }));
    // Auto-compact with higher threshold
    middlewares.push(new AutoCompactMiddleware({
        tokenThreshold: 100000,
        contextPercentage: 0.85,
        minMessagesToKeep: 2,
    }));
    return middlewares;
}
//# sourceMappingURL=middlewares.js.map