/**
 * Compression configuration constants
 */
export const COMPRESSION_CONSTANTS = {
    /** Default number of recent messages to keep at full detail */
    DEFAULT_KEEP_RECENT_MESSAGES: 2,
    /** Character threshold for compressing user messages */
    USER_MESSAGE_COMPRESSION_THRESHOLD: 500,
    /** Character threshold for compressing assistant messages with tool_calls */
    ASSISTANT_WITH_TOOLS_THRESHOLD: 300,
    /** Target length for aggressive text truncation */
    AGGRESSIVE_TRUNCATION_LIMIT: 100,
    /** Target length for default text truncation */
    DEFAULT_TRUNCATION_LIMIT: 200,
    /** Target length for aggressive assistant message truncation */
    AGGRESSIVE_ASSISTANT_LIMIT: 150,
    /** Target length for default assistant message truncation */
    DEFAULT_ASSISTANT_LIMIT: 300,
    /** Minimum valid auto-compact threshold percentage */
    MIN_THRESHOLD_PERCENT: 50,
    /** Maximum valid auto-compact threshold percentage */
    MAX_THRESHOLD_PERCENT: 95,
    /** Character threshold for compressing user messages in conservative mode */
    CONSERVATIVE_USER_MESSAGE_THRESHOLD: 1000,
    /** Target length for conservative mode text truncation */
    CONSERVATIVE_TRUNCATION_LIMIT: 500,
};
/**
 * Compress message history while preserving essential information
 * @param messages - Original messages to compress
 * @param tokenizer - Tokenizer for counting tokens
 * @param options - Compression options
 * @returns Compression result with compressed messages and statistics
 */
export function compressMessages(messages, tokenizer, options) {
    if (messages.length === 0) {
        return {
            compressedMessages: [],
            originalTokenCount: 0,
            compressedTokenCount: 0,
            reductionPercentage: 0,
            preservedInfo: {
                keyDecisions: 0,
                fileModifications: 0,
                toolResults: 0,
                recentMessages: 0,
            },
        };
    }
    const keepRecent = options.keepRecentMessages ??
        COMPRESSION_CONSTANTS.DEFAULT_KEEP_RECENT_MESSAGES;
    const originalTokenCount = countTotalTokens(messages, tokenizer);
    // Separate messages into: system, compressible, and recent (keep full)
    const systemMessages = [];
    const compressibleMessages = [];
    const recentMessages = [];
    for (let i = 0; i < messages.length; i++) {
        const msg = messages[i];
        if (msg.role === 'system') {
            systemMessages.push(msg);
        }
        else if (i >= messages.length - keepRecent) {
            recentMessages.push(msg);
        }
        else {
            compressibleMessages.push(msg);
        }
    }
    // Compress the compressible messages
    const compressed = compressMessageSegment(compressibleMessages, options.mode);
    // Combine: system + compressed + recent
    const compressedMessages = [
        ...systemMessages,
        ...compressed,
        ...recentMessages,
    ];
    const compressedTokenCount = countTotalTokens(compressedMessages, tokenizer);
    const reductionPercentage = originalTokenCount > 0
        ? ((originalTokenCount - compressedTokenCount) / originalTokenCount) * 100
        : 0;
    // Count preserved information
    const preservedInfo = {
        keyDecisions: countKeyDecisions(compressed),
        fileModifications: countFileModifications(compressed),
        toolResults: countToolResults(compressed),
        recentMessages: recentMessages.length,
    };
    return {
        compressedMessages,
        originalTokenCount,
        compressedTokenCount,
        reductionPercentage,
        preservedInfo,
    };
}
// Compress a segment of messages excluding system and recent
function compressMessageSegment(messages, mode) {
    if (messages.length === 0) {
        return [];
    }
    const compressed = [];
    let i = 0;
    while (i < messages.length) {
        const msg = messages[i];
        // Handle tool messages
        if (msg.role === 'tool') {
            const compressedTool = compressToolResult(msg, mode);
            compressed.push(compressedTool);
            i++;
            continue;
        }
        // Handle assistant messages with tool calls
        if (msg.role === 'assistant' &&
            msg.tool_calls &&
            msg.tool_calls.length > 0) {
            // Keep assistant message with tool calls, but compress content if verbose
            const compressedMsg = compressAssistantMessage(msg, mode);
            compressed.push(compressedMsg);
            i++;
            continue;
        }
        // Handle user messages, summarize if verbose
        if (msg.role === 'user') {
            const compressedUser = compressUserMessage(msg, mode);
            compressed.push(compressedUser);
            i++;
            continue;
        }
        // Handle assistant messages, summarize if verbose
        if (msg.role === 'assistant') {
            const compressedAssistant = compressAssistantMessage(msg, mode);
            compressed.push(compressedAssistant);
            i++;
            continue;
        }
        // Unknown role keep
        compressed.push(msg);
        i++;
    }
    return compressed;
}
// Compress a tool result message, Keep things like facts,terminal logs, verbose JSON, etc.
function compressToolResult(msg, mode) {
    if (msg.role !== 'tool' || !msg.name) {
        return msg;
    }
    const toolName = msg.name;
    const content = msg.content || '';
    // Extract error status
    const hasError = checkForError(content);
    // Compress based on mode
    let compressedContent;
    if (mode === 'aggressive') {
        // Most aggressive: just outcome
        compressedContent = hasError
            ? compressToolError(toolName, content)
            : `Tool: ${toolName}\nResult: success`;
    }
    else if (mode === 'conservative') {
        // Conservative: keep more detail
        compressedContent = compressToolResultConservative(toolName, content);
    }
    else {
        // Default: balanced
        compressedContent = compressToolResultDefault(toolName, content);
    }
    return {
        ...msg,
        content: compressedContent,
    };
}
// Compress tool result in default mode
function compressToolResultDefault(toolName, content) {
    const error = extractErrorInfo(content);
    if (error) {
        return `Tool: ${toolName}\nError: ${error.type}\n${error.details}\nResolved: ${error.resolved ? 'yes' : 'no'}`;
    }
    // Check for success indicators
    if (isSuccess(content)) {
        return `Tool: ${toolName}\nResult: success`;
    }
    // Extract key information like first line, key metrics, etc.
    const lines = content.split('\n');
    const firstLine = lines[0] || '';
    const keyInfo = extractKeyInfo(content);
    if (keyInfo) {
        return `Tool: ${toolName}\nResult: ${keyInfo}`;
    }
    // Fallback: truncate to first meaningful line
    return `Tool: ${toolName}\nResult: ${firstLine.substring(0, 100)}`;
}
// Compress tool result in conservative mode
function compressToolResultConservative(toolName, content) {
    const error = extractErrorInfo(content);
    if (error) {
        return `Tool: ${toolName}\nError: ${error.type}\n${error.details}\nResolved: ${error.resolved ? 'yes' : 'no'}`;
    }
    // Keep first few lines and summary
    const lines = content.split('\n').filter(line => line.trim());
    const importantLines = lines.slice(0, 3);
    const summary = importantLines.join('\n');
    return `Tool: ${toolName}\nResult: ${summary}${lines.length > 3 ? '...' : ''}`;
}
// Compress tool error
function compressToolError(toolName, content) {
    const error = extractErrorInfo(content);
    if (error) {
        return `Tool: ${toolName}\nError: ${error.type}\n${error.details}\nResolved: ${error.resolved ? 'yes' : 'no'}`;
    }
    return `Tool: ${toolName}\nError: (error occurred)`;
}
// Extract error information from tool result
function extractErrorInfo(content) {
    // Look for common error patterns
    const errorPatterns = [/Error:\s*(\w+)/i, /(\w+Error):/i, /(\w+Exception):/i];
    for (const pattern of errorPatterns) {
        const match = content.match(pattern);
        if (match) {
            const errorType = match[1];
            // Try to extract file and line if present
            const fileMatch = content.match(/File:\s*([^\n]+)/i);
            const lineMatch = content.match(/Line:\s*(\d+)/i);
            let details = errorType;
            if (fileMatch) {
                details += ` in ${fileMatch[1]}`;
                if (lineMatch) {
                    details += `:${lineMatch[1]}`;
                }
            }
            // Check if resolved
            const resolved = /fixed|resolved|success|working/i.test(content) &&
                !/failed|error|broken/i.test(content.slice(content.indexOf(match[0]) + match[0].length));
            return {
                type: errorType,
                details,
                resolved,
            };
        }
    }
    return null;
}
// Check if content indicates success
function isSuccess(content) {
    const successPatterns = [
        /^success$/i,
        /^ok$/i,
        /^done$/i,
        /completed successfully/i,
        /no errors/i,
    ];
    return successPatterns.some(pattern => pattern.test(content));
}
// Check for error in content
function checkForError(content) {
    return /error|exception|failed|failure/i.test(content);
}
// Extract key information from tool result
function extractKeyInfo(content) {
    // Look for key metrics or summary lines
    const lines = content.split('\n').filter(line => line.trim());
    if (lines.length === 0) {
        return null;
    }
    // Prefer short, informative lines
    for (const line of lines.slice(0, 5)) {
        if (line.length < 100 && !line.includes('...') && !line.includes('node:')) {
            return line;
        }
    }
    return null;
}
// Compress user message
function compressUserMessage(msg, mode) {
    if (msg.role !== 'user') {
        return msg;
    }
    const content = msg.content || '';
    // Conservative mode: only compress very long messages (>1000 chars)
    if (mode === 'conservative') {
        if (content.length > COMPRESSION_CONSTANTS.CONSERVATIVE_USER_MESSAGE_THRESHOLD) {
            const summary = summarizeText(content, COMPRESSION_CONSTANTS.CONSERVATIVE_TRUNCATION_LIMIT);
            return {
                ...msg,
                content: summary,
            };
        }
        return msg;
    }
    // Default/Aggressive: summarize if very long
    if (content.length > COMPRESSION_CONSTANTS.USER_MESSAGE_COMPRESSION_THRESHOLD) {
        const summary = summarizeText(content, mode === 'aggressive'
            ? COMPRESSION_CONSTANTS.AGGRESSIVE_TRUNCATION_LIMIT
            : COMPRESSION_CONSTANTS.DEFAULT_TRUNCATION_LIMIT);
        return {
            ...msg,
            content: summary,
        };
    }
    return msg;
}
// Compress assistant message
function compressAssistantMessage(msg, mode) {
    if (msg.role !== 'assistant') {
        return msg;
    }
    const content = msg.content || '';
    // Keep tool calls as is
    if (msg.tool_calls && msg.tool_calls.length > 0) {
        // Compress content if verbose, but keep tool calls
        if (content.length > COMPRESSION_CONSTANTS.ASSISTANT_WITH_TOOLS_THRESHOLD &&
            mode !== 'conservative') {
            return {
                ...msg,
                content: summarizeText(content, mode === 'aggressive'
                    ? COMPRESSION_CONSTANTS.AGGRESSIVE_TRUNCATION_LIMIT
                    : COMPRESSION_CONSTANTS.DEFAULT_TRUNCATION_LIMIT),
            };
        }
        return msg;
    }
    // Conservative mode: keep as is
    if (mode === 'conservative') {
        return msg;
    }
    // Default/Aggressive: summarize if very long
    if (content.length > COMPRESSION_CONSTANTS.USER_MESSAGE_COMPRESSION_THRESHOLD) {
        const summary = summarizeText(content, mode === 'aggressive'
            ? COMPRESSION_CONSTANTS.AGGRESSIVE_ASSISTANT_LIMIT
            : COMPRESSION_CONSTANTS.DEFAULT_ASSISTANT_LIMIT);
        return {
            ...msg,
            content: summary,
        };
    }
    return msg;
}
// Summarize text to target length
function summarizeText(text, targetLength) {
    if (text.length <= targetLength) {
        return text;
    }
    // Try to keep first sentence/paragraph
    const sentences = text.split(/[.!?]\s+/);
    let summary = '';
    for (const sentence of sentences) {
        if ((summary + sentence).length <= targetLength - 3) {
            summary += sentence + '. ';
        }
        else {
            break;
        }
    }
    if (summary) {
        return summary.trim() + '...';
    }
    // Fallback
    return text.substring(0, targetLength - 3) + '...';
}
// Count total tokens in messages
function countTotalTokens(messages, tokenizer) {
    let total = 0;
    for (const msg of messages) {
        total += tokenizer.countTokens(msg);
    }
    return total;
}
// Count key decisions in compressed messages
function countKeyDecisions(messages) {
    // Look for messages with decision indicators
    let count = 0;
    for (const msg of messages) {
        if (msg.role === 'user' || msg.role === 'assistant') {
            const content = (msg.content || '').toLowerCase();
            if (/decided|decision|chose|chosen|will use|using|selected|choose/i.test(content)) {
                count++;
            }
        }
    }
    return count;
}
// Count file modifications
function countFileModifications(messages) {
    let count = 0;
    for (const msg of messages) {
        if (msg.role === 'tool' && msg.name) {
            const toolName = msg.name.toLowerCase();
            if (toolName.includes('write') ||
                toolName.includes('edit') ||
                toolName.includes('create') ||
                toolName.includes('modify')) {
                count++;
            }
        }
    }
    return count;
}
// Count tool results
function countToolResults(messages) {
    return messages.filter(msg => msg.role === 'tool').length;
}
//# sourceMappingURL=message-compression.js.map