"use strict";
// =============================================================================
// Pure Agent - Error Classifier
// Ported from Hermes agent/error_classifier.py
// =============================================================================
Object.defineProperty(exports, "__esModule", { value: true });
exports.FailoverReason = void 0;
exports.classifyApiError = classifyApiError;
exports.isImageRejection = isImageRejection;
exports.hasImagesInMessages = hasImagesInMessages;
exports.stripImagesFromMessages = stripImagesFromMessages;
// ---------------------------------------------------------------------------
// FailoverReason enum
// ---------------------------------------------------------------------------
var FailoverReason;
(function (FailoverReason) {
    FailoverReason["auth"] = "auth";
    FailoverReason["auth_permanent"] = "auth_permanent";
    FailoverReason["billing"] = "billing";
    FailoverReason["rate_limit"] = "rate_limit";
    FailoverReason["overloaded"] = "overloaded";
    FailoverReason["server_error"] = "server_error";
    FailoverReason["timeout"] = "timeout";
    FailoverReason["context_overflow"] = "context_overflow";
    FailoverReason["payload_too_large"] = "payload_too_large";
    FailoverReason["image_too_large"] = "image_too_large";
    FailoverReason["model_not_found"] = "model_not_found";
    FailoverReason["content_policy_blocked"] = "content_policy_blocked";
    FailoverReason["format_error"] = "format_error";
    FailoverReason["thinking_signature"] = "thinking_signature";
    FailoverReason["multimodal_tool_content_unsupported"] = "multimodal_tool_content_unsupported";
    FailoverReason["unknown"] = "unknown";
})(FailoverReason || (exports.FailoverReason = FailoverReason = {}));
// ---------------------------------------------------------------------------
// Image rejection phrases
// ---------------------------------------------------------------------------
const IMAGE_REJECTION_PHRASES = [
    "only 'text' content type is supported",
    'only text content type is supported',
    'image_url is not supported',
    'image content is not supported',
    'multimodal is not supported',
    'multimodal content is not supported',
    'multimodal input is not supported',
    'vision is not supported',
    'vision input is not supported',
    'does not support images',
    'does not support image input',
    'does not support multimodal',
    'does not support vision',
    'model does not support image',
    "image_url'. expected",
    'unknown variant `image_url`, expected `text`',
    'unknown variant image_url, expected text',
];
// ---------------------------------------------------------------------------
// Usage limit patterns (402 disambiguation)
// ---------------------------------------------------------------------------
const USAGE_LIMIT_PATTERNS = [
    'usage limit', 'quota exceeded', 'rate limit', 'too many requests',
    'requests per', 'tokens per', 'daily limit', 'monthly limit',
];
const USAGE_LIMIT_TRANSIENT_SIGNALS = [
    'try again', 'retry', 'temporary', 'cooldown', 'reset',
];
// ---------------------------------------------------------------------------
// classifyApiError
// ---------------------------------------------------------------------------
function classifyApiError(error, statusCode) {
    const message = String(error?.message || error?.error?.message || error?.body || JSON.stringify(error) || '');
    const code = statusCode || error?.status || error?.statusCode || 0;
    const msgLower = message.toLowerCase();
    // Rate limit (429)
    if (code === 429 || msgLower.includes('rate limit') || msgLower.includes('too many requests')) {
        return { reason: FailoverReason.rate_limit, statusCode: 429, message, retryable: true, shouldCompress: false };
    }
    // Billing (402) with disambiguation
    if (code === 402) {
        const hasUsageLimit = USAGE_LIMIT_PATTERNS.some(p => msgLower.includes(p));
        const hasTransient = USAGE_LIMIT_TRANSIENT_SIGNALS.some(p => msgLower.includes(p));
        if (hasUsageLimit && hasTransient) {
            return { reason: FailoverReason.rate_limit, statusCode: 402, message, retryable: true, shouldCompress: false };
        }
        return { reason: FailoverReason.billing, statusCode: 402, message, retryable: false, shouldCompress: false };
    }
    // Auth (401/403)
    if (code === 401 || code === 403) {
        return { reason: FailoverReason.auth, statusCode: code, message, retryable: true, shouldCompress: false };
    }
    // Context overflow
    if (code === 400 && (msgLower.includes('context') || msgLower.includes('too long') ||
        msgLower.includes('maximum context') || msgLower.includes('token limit') ||
        msgLower.includes('context_length_exceeded') || msgLower.includes('max_tokens'))) {
        return { reason: FailoverReason.context_overflow, statusCode: 400, message, retryable: true, shouldCompress: true };
    }
    // Payload too large
    if (code === 413) {
        return { reason: FailoverReason.payload_too_large, statusCode: 413, message, retryable: true, shouldCompress: true };
    }
    // Thinking signature (Anthropic)
    if (code === 400 && msgLower.includes('signature') && msgLower.includes('thinking')) {
        return { reason: FailoverReason.thinking_signature, statusCode: 400, message, retryable: true, shouldCompress: false };
    }
    // Image rejection
    if (code >= 400 && code < 500 && IMAGE_REJECTION_PHRASES.some(p => msgLower.includes(p))) {
        return { reason: FailoverReason.image_too_large, statusCode: code, message, retryable: true, shouldCompress: false };
    }
    // Multimodal tool content unsupported
    if (code === 400 && msgLower.includes('tool') && (msgLower.includes('image') || msgLower.includes('multimodal'))) {
        return { reason: FailoverReason.multimodal_tool_content_unsupported, statusCode: 400, message, retryable: true, shouldCompress: false };
    }
    // Content policy
    if (code === 400 && (msgLower.includes('content policy') || msgLower.includes('safety') || msgLower.includes('blocked'))) {
        return { reason: FailoverReason.content_policy_blocked, statusCode: 400, message, retryable: false, shouldCompress: false };
    }
    // Model not found
    if (code === 404 || (code === 400 && msgLower.includes('model') && msgLower.includes('not found'))) {
        return { reason: FailoverReason.model_not_found, statusCode: code, message, retryable: false, shouldCompress: false };
    }
    // Overloaded (503/529)
    if (code === 503 || code === 529 || msgLower.includes('overloaded')) {
        return { reason: FailoverReason.overloaded, statusCode: code, message, retryable: true, shouldCompress: false };
    }
    // Server error (500/502)
    if (code >= 500) {
        return { reason: FailoverReason.server_error, statusCode: code, message, retryable: true, shouldCompress: false };
    }
    // Format error (400 generic)
    if (code === 400) {
        return { reason: FailoverReason.format_error, statusCode: 400, message, retryable: false, shouldCompress: false };
    }
    // Timeout
    if (msgLower.includes('timeout') || msgLower.includes('timed out')) {
        return { reason: FailoverReason.timeout, statusCode: code, message, retryable: true, shouldCompress: false };
    }
    return { reason: FailoverReason.unknown, statusCode: code, message, retryable: code >= 500 || code === 0, shouldCompress: false };
}
// ---------------------------------------------------------------------------
// Image detection helpers
// ---------------------------------------------------------------------------
function isImageRejection(error, statusCode) {
    const message = String(error?.message || error?.body || '');
    const code = statusCode || error?.status || 0;
    if (code < 400 || code >= 500)
        return false;
    const msgLower = message.toLowerCase();
    return IMAGE_REJECTION_PHRASES.some(p => msgLower.includes(p));
}
function hasImagesInMessages(messages) {
    for (const msg of messages) {
        if (Array.isArray(msg.content)) {
            for (const part of msg.content) {
                if (part.type === 'image_url' || part.type === 'image' || part.type === 'input_image') {
                    return true;
                }
            }
        }
    }
    return false;
}
function stripImagesFromMessages(messages) {
    let removed = 0;
    for (const msg of messages) {
        if (Array.isArray(msg.content)) {
            const filtered = msg.content.filter((part) => {
                if (part.type === 'image_url' || part.type === 'image' || part.type === 'input_image') {
                    removed++;
                    return false;
                }
                return true;
            });
            if (filtered.length !== msg.content.length) {
                msg.content = filtered.length === 1 ? filtered[0].text || '' : filtered;
            }
        }
    }
    return removed;
}
//# sourceMappingURL=error-classifier.js.map