"use strict";
// =============================================================================
// Pure Agent - Anthropic Adapter
// Ported from Hermes agent/anthropic_adapter.py
// Message/tool/response format conversion for Anthropic Messages API
// =============================================================================
Object.defineProperty(exports, "__esModule", { value: true });
exports.convertMessagesToAnthropic = convertMessagesToAnthropic;
exports.convertToolsToAnthropic = convertToolsToAnthropic;
exports.buildAnthropicRequestBody = buildAnthropicRequestBody;
exports.getAnthropicEndpoint = getAnthropicEndpoint;
exports.getAnthropicHeaders = getAnthropicHeaders;
exports.normalizeAnthropicResponse = normalizeAnthropicResponse;
exports.normalizeAnthropicStreamEvent = normalizeAnthropicStreamEvent;
const logger_1 = require("../logger");
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
const ANTHROPIC_OUTPUT_LIMITS = {
    'claude-opus-4-8': 128000, 'claude-opus-4-7': 128000,
    'claude-opus-4-6': 128000, 'claude-sonnet-4-6': 64000,
    'claude-opus-4-5': 64000, 'claude-sonnet-4-5': 64000,
    'claude-haiku-4-5': 64000, 'claude-opus-4': 32000,
    'claude-sonnet-4': 64000, 'claude-3-7-sonnet': 128000,
    'claude-3-5-sonnet': 8192, 'claude-3-5-haiku': 8192,
    'claude-3-opus': 4096, 'claude-3-sonnet': 4096, 'claude-3-haiku': 4096,
};
const ANTHROPIC_DEFAULT_OUTPUT_LIMIT = 128000;
const STOP_REASON_MAP = {
    'end_turn': 'stop',
    'tool_use': 'tool_calls',
    'max_tokens': 'length',
    'stop_sequence': 'stop',
    'refusal': 'content_filter',
    'model_context_window_exceeded': 'length',
};
// Thinking budget by effort level
const THINKING_BUDGET = {
    xhigh: 32000, high: 16000, medium: 8000, low: 4000,
};
// ---------------------------------------------------------------------------
// Model capability detection
// ---------------------------------------------------------------------------
function normalizeModelName(model) {
    return model
        .replace(/^anthropic\//, '')
        .replace(/(\d)\.(\d)/g, '$1-$2'); // 4.6 -> 4-6
}
function getMaxOutput(model) {
    const normalized = normalizeModelName(model);
    // Longest prefix match
    let best = ANTHROPIC_DEFAULT_OUTPUT_LIMIT;
    let bestLen = 0;
    for (const [prefix, limit] of Object.entries(ANTHROPIC_OUTPUT_LIMITS)) {
        if (normalized.includes(prefix) && prefix.length > bestLen) {
            best = limit;
            bestLen = prefix.length;
        }
    }
    return best;
}
function supportsAdaptiveThinking(model) {
    const m = normalizeModelName(model);
    return m.includes('4-6') || m.includes('4-7') || m.includes('4-8');
}
function supportsXhighEffort(model) {
    const m = normalizeModelName(model);
    return m.includes('4-7') || m.includes('4-8');
}
// ---------------------------------------------------------------------------
// Convert OpenAI messages to Anthropic format
// ---------------------------------------------------------------------------
function convertMessagesToAnthropic(messages) {
    let systemPrompt = null;
    const result = [];
    for (const msg of messages) {
        if (msg.role === 'system') {
            // Extract system prompt (Anthropic uses separate parameter)
            systemPrompt = typeof msg.content === 'string' ? msg.content : '';
            continue;
        }
        if (msg.role === 'user') {
            result.push(convertUserMessage(msg));
        }
        else if (msg.role === 'assistant') {
            const converted = convertAssistantMessage(msg);
            if (converted)
                result.push(converted);
        }
        else if (msg.role === 'tool') {
            // Tool results get merged into user messages
            const toolResult = convertToolResultMessage(msg);
            const lastMsg = result[result.length - 1];
            if (lastMsg && lastMsg.role === 'user' && Array.isArray(lastMsg.content)) {
                // Merge consecutive tool results
                lastMsg.content.push(toolResult);
            }
            else {
                result.push({ role: 'user', content: [toolResult] });
            }
        }
    }
    // Post-process: merge consecutive same-role messages
    const merged = mergeConsecutiveRoles(result);
    // Strip orphaned tool blocks
    const cleaned = stripOrphanedToolBlocks(merged);
    return { system: systemPrompt, anthropicMessages: cleaned };
}
function convertUserMessage(msg) {
    if (typeof msg.content === 'string') {
        return { role: 'user', content: msg.content || '(empty message)' };
    }
    // Multimodal content array
    if (Array.isArray(msg.content)) {
        const blocks = msg.content.map((part) => {
            if (part.type === 'text')
                return { type: 'text', text: part.text };
            if (part.type === 'image_url') {
                return convertImageToAnthropic(part.image_url?.url || part.url);
            }
            return { type: 'text', text: JSON.stringify(part) };
        }).filter(Boolean);
        return { role: 'user', content: blocks };
    }
    return { role: 'user', content: '(empty message)' };
}
function convertAssistantMessage(msg) {
    const blocks = [];
    // Text content
    if (msg.content) {
        blocks.push({ type: 'text', text: msg.content });
    }
    // Reasoning/thinking content
    if (msg.reasoning_content) {
        blocks.push({ type: 'thinking', thinking: msg.reasoning_content });
    }
    // Tool calls -> tool_use blocks
    if (msg.tool_calls) {
        for (const tc of msg.tool_calls) {
            let input;
            try {
                input = JSON.parse(tc.function.arguments);
            }
            catch {
                input = tc.function.arguments;
            }
            blocks.push({
                type: 'tool_use',
                id: tc.id,
                name: tc.function.name,
                input,
            });
        }
    }
    if (blocks.length === 0) {
        blocks.push({ type: 'text', text: '(empty)' });
    }
    return { role: 'assistant', content: blocks };
}
function convertToolResultMessage(msg) {
    const content = typeof msg.content === 'string' ? msg.content : JSON.stringify(msg.content);
    return {
        type: 'tool_result',
        tool_use_id: msg.tool_call_id,
        content: content,
    };
}
function convertImageToAnthropic(url) {
    if (!url)
        return null;
    if (url.startsWith('data:')) {
        // base64 data URL
        const match = url.match(/^data:(image\/\w+);base64,(.+)$/);
        if (match) {
            return {
                type: 'image',
                source: { type: 'base64', media_type: match[1], data: match[2] },
            };
        }
    }
    // HTTP URL
    return {
        type: 'image',
        source: { type: 'url', url },
    };
}
// ---------------------------------------------------------------------------
// Post-processing
// ---------------------------------------------------------------------------
function mergeConsecutiveRoles(messages) {
    if (messages.length <= 1)
        return messages;
    const merged = [messages[0]];
    for (let i = 1; i < messages.length; i++) {
        const prev = merged[merged.length - 1];
        const curr = messages[i];
        if (prev.role === curr.role) {
            // Merge content
            const prevContent = Array.isArray(prev.content) ? prev.content : [{ type: 'text', text: prev.content || '' }];
            const currContent = Array.isArray(curr.content) ? curr.content : [{ type: 'text', text: curr.content || '' }];
            prev.content = [...prevContent, ...currContent];
        }
        else {
            merged.push(curr);
        }
    }
    return merged;
}
function stripOrphanedToolBlocks(messages) {
    // Collect all tool_use IDs from assistant messages
    const toolUseIds = new Set();
    const toolResultIds = new Set();
    for (const msg of messages) {
        if (!Array.isArray(msg.content))
            continue;
        for (const block of msg.content) {
            if (block.type === 'tool_use' && block.id)
                toolUseIds.add(block.id);
            if (block.type === 'tool_result' && block.tool_use_id)
                toolResultIds.add(block.tool_use_id);
        }
    }
    // Remove orphaned blocks
    return messages.map(msg => {
        if (!Array.isArray(msg.content))
            return msg;
        const filtered = msg.content.filter((block) => {
            if (block.type === 'tool_use' && block.id && !toolResultIds.has(block.id))
                return false;
            if (block.type === 'tool_result' && block.tool_use_id && !toolUseIds.has(block.tool_use_id))
                return false;
            return true;
        });
        return { ...msg, content: filtered };
    }).filter(msg => {
        if (!Array.isArray(msg.content))
            return true;
        return msg.content.length > 0;
    });
}
// ---------------------------------------------------------------------------
// Convert OpenAI tools to Anthropic format
// ---------------------------------------------------------------------------
function convertToolsToAnthropic(tools) {
    const seen = new Set();
    const result = [];
    for (const tool of tools) {
        const name = tool.function.name;
        if (seen.has(name)) {
            (0, logger_1.getLogger)().warn(`Duplicate tool name: ${name}, skipping`);
            continue;
        }
        seen.add(name);
        let inputSchema = tool.function.parameters || { type: 'object', properties: {} };
        // Normalize: ensure type: "object"
        if (!inputSchema.type)
            inputSchema = { ...inputSchema, type: 'object' };
        if (!inputSchema.properties)
            inputSchema = { ...inputSchema, properties: {} };
        result.push({
            name,
            description: tool.function.description || '',
            input_schema: inputSchema,
        });
    }
    return result;
}
// ---------------------------------------------------------------------------
// Build complete Anthropic API request body
// ---------------------------------------------------------------------------
function buildAnthropicRequestBody(model, messages, tools, params) {
    const { system, anthropicMessages } = convertMessagesToAnthropic(messages);
    const maxTokens = params?.maxTokens || getMaxOutput(model);
    const temperature = params?.temperature;
    const body = {
        model: normalizeModelName(model),
        messages: anthropicMessages,
        max_tokens: maxTokens,
    };
    if (system) {
        body.system = system;
    }
    if (tools && tools.length > 0) {
        body.tools = convertToolsToAnthropic(tools);
    }
    // Thinking/reasoning config
    if (params?.reasoningEffort) {
        const effort = params.reasoningEffort;
        if (supportsAdaptiveThinking(model)) {
            body.thinking = { type: 'adaptive', display: 'summarized' };
        }
        else {
            const budget = THINKING_BUDGET[effort] || THINKING_BUDGET.medium;
            body.thinking = { type: 'enabled', budget_tokens: budget };
            body.temperature = 1; // Required for thinking on pre-4.7
        }
    }
    if (temperature !== undefined && !params?.reasoningEffort) {
        body.temperature = temperature;
    }
    return body;
}
// ---------------------------------------------------------------------------
// Get endpoint and headers
// ---------------------------------------------------------------------------
function getAnthropicEndpoint() {
    return '/messages';
}
function getAnthropicHeaders(apiKey) {
    return {
        'x-api-key': apiKey,
        'anthropic-version': '2023-06-01',
        'content-type': 'application/json',
    };
}
// ---------------------------------------------------------------------------
// Normalize Anthropic response to standard format
// ---------------------------------------------------------------------------
function normalizeAnthropicResponse(response) {
    const contentBlocks = response?.content || [];
    const textParts = [];
    const reasoningParts = [];
    const toolCalls = [];
    for (const block of contentBlocks) {
        if (block.type === 'text') {
            textParts.push(block.text);
        }
        else if (block.type === 'thinking') {
            reasoningParts.push(block.thinking);
        }
        else if (block.type === 'tool_use') {
            toolCalls.push({
                id: block.id,
                name: block.name,
                arguments: typeof block.input === 'string' ? block.input : JSON.stringify(block.input),
            });
        }
    }
    const finishReason = STOP_REASON_MAP[response?.stop_reason] || 'stop';
    let usage = null;
    if (response?.usage) {
        usage = {
            promptTokens: response.usage.input_tokens || 0,
            completionTokens: response.usage.output_tokens || 0,
            totalTokens: (response.usage.input_tokens || 0) + (response.usage.output_tokens || 0),
            cachedTokens: response.usage.cache_read_input_tokens || 0,
        };
    }
    return {
        content: textParts.join('') || null,
        toolCalls: toolCalls.length > 0 ? toolCalls : null,
        finishReason,
        reasoning: reasoningParts.join('') || null,
        usage,
    };
}
// ---------------------------------------------------------------------------
// Normalize Anthropic streaming event
// ---------------------------------------------------------------------------
function normalizeAnthropicStreamEvent(event) {
    if (!event)
        return null;
    switch (event.type) {
        case 'content_block_delta':
            if (event.delta?.type === 'text_delta') {
                return { type: 'content', content: event.delta.text };
            }
            if (event.delta?.type === 'thinking_delta') {
                return { type: 'reasoning', reasoning: event.delta.thinking };
            }
            if (event.delta?.type === 'input_json_delta') {
                return {
                    type: 'tool_call_delta',
                    toolCall: {
                        index: event.index,
                        arguments: event.delta.partial_json,
                    },
                };
            }
            return null;
        case 'content_block_start':
            if (event.content_block?.type === 'tool_use') {
                return {
                    type: 'tool_call_start',
                    toolCall: {
                        index: event.index,
                        id: event.content_block.id,
                        name: event.content_block.name,
                        arguments: '',
                    },
                };
            }
            return null;
        case 'message_delta':
            if (event.delta?.stop_reason) {
                return {
                    type: 'finish',
                    finishReason: STOP_REASON_MAP[event.delta.stop_reason] || 'stop',
                };
            }
            if (event.usage) {
                return {
                    type: 'usage',
                    usage: {
                        completionTokens: event.usage.output_tokens,
                    },
                };
            }
            return null;
        case 'message_start':
            if (event.message?.usage) {
                return {
                    type: 'usage',
                    usage: {
                        promptTokens: event.message.usage.input_tokens,
                        totalTokens: (event.message.usage.input_tokens || 0) + (event.message.usage.output_tokens || 0),
                    },
                };
            }
            return null;
        default:
            return null;
    }
}
//# sourceMappingURL=anthropic-adapter.js.map