"use strict";
// =============================================================================
// Pure Agent - Multimodal Generation Tools
// Ported from server.js MULTIMODAL_TEMPLATES
// generate_image, generate_video, text_to_speech, generate_music
// Routes through the proxy system to configured multimodal providers
// =============================================================================
Object.defineProperty(exports, "__esModule", { value: true });
exports.setMultimodalServicesGetter = setMultimodalServicesGetter;
exports.registerMultimodalTools = registerMultimodalTools;
const tool_registry_1 = require("../tool-registry");
const result_types_1 = require("../result-types");
// ---------------------------------------------------------------------------
// Provider resolution (injected from routes)
// ---------------------------------------------------------------------------
let _getMultimodalServices = null;
function setMultimodalServicesGetter(fn) {
    _getMultimodalServices = fn;
}
function getServicesForType(serviceType) {
    if (!_getMultimodalServices)
        return [];
    try {
        return _getMultimodalServices().filter((s) => s.serviceType === serviceType && s.enabled !== false);
    }
    catch {
        return [];
    }
}
function resolveProvider(serviceType, model) {
    const services = getServicesForType(serviceType);
    if (services.length === 0)
        return null;
    // Find service with matching model, or use first
    for (const svc of services) {
        const models = svc.models || [];
        if (model && models.some((m) => (typeof m === 'string' ? m : m.name) === model)) {
            const key = svc.apiKeys?.find((k) => k.enabled !== false);
            return {
                url: svc.url,
                apiKey: key?.key || svc.apiKey || '',
                brand: svc.brand || 'openai',
                model,
            };
        }
    }
    // Fallback: first service
    const svc = services[0];
    const key = svc.apiKeys?.find((k) => k.enabled !== false);
    const defaultModel = svc.models?.[0];
    return {
        url: svc.url,
        apiKey: key?.key || svc.apiKey || '',
        brand: svc.brand || 'openai',
        model: model || (typeof defaultModel === 'string' ? defaultModel : defaultModel?.name) || '',
    };
}
// ---------------------------------------------------------------------------
// generate_image handler
// ---------------------------------------------------------------------------
async function generateImageHandler(args, context) {
    const { prompt, size = '1024x1024', model } = args;
    if (!prompt)
        return (0, result_types_1.toolError)('Missing required parameter: prompt');
    const provider = resolveProvider('image', model);
    if (!provider)
        return (0, result_types_1.toolError)('No image generation service configured. Add a multimodal service in settings.');
    const headers = {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${provider.apiKey}`,
    };
    try {
        let body;
        let url;
        if (provider.brand === 'minimax') {
            url = provider.url.includes('/v1') ? `${provider.url}/image_generation` : `${provider.url}/v1/image_generation`;
            const ratioMap = { '1024x1024': '1:1', '1792x1024': '16:9', '1024x1792': '9:16' };
            body = { model: provider.model, prompt, aspect_ratio: ratioMap[size] || '1:1' };
        }
        else {
            url = `${provider.url}/v1/images/generations`;
            body = { model: provider.model || 'dall-e-3', prompt, size, n: 1 };
        }
        const response = await fetch(url, {
            method: 'POST',
            headers,
            body: JSON.stringify(body),
            signal: AbortSignal.timeout(120000),
        });
        if (!response.ok) {
            const err = await response.text().catch(() => 'Unknown error');
            return (0, result_types_1.toolError)(`Image generation failed (${response.status}): ${err}`);
        }
        const result = await response.json();
        // MiniMax response
        if (provider.brand === 'minimax') {
            const imageUrls = result.data?.image_urls || result.image_urls || [];
            if (imageUrls.length > 0) {
                // Download first image
                const imgResponse = await fetch(imageUrls[0], { signal: AbortSignal.timeout(30000) });
                const buffer = Buffer.from(await imgResponse.arrayBuffer());
                return (0, result_types_1.toolResult)({
                    success: true,
                    images: [{ name: `img_${Date.now()}.png`, base64_data: buffer.toString('base64') }],
                });
            }
        }
        // OpenAI-compatible response
        const imageUrl = result.data?.[0]?.url;
        if (imageUrl) {
            if (imageUrl.startsWith('data:')) {
                const match = imageUrl.match(/^data:image\/\w+;base64,(.+)$/);
                if (match) {
                    return (0, result_types_1.toolResult)({
                        success: true,
                        images: [{ name: `img_${Date.now()}.png`, base64_data: match[1] }],
                    });
                }
            }
            return (0, result_types_1.toolResult)({ success: true, url: imageUrl, message: 'Image generated. URL: ' + imageUrl });
        }
        return (0, result_types_1.toolResult)({ success: true, raw: result });
    }
    catch (err) {
        return (0, result_types_1.toolError)(`Image generation error: ${err.message}`);
    }
}
// ---------------------------------------------------------------------------
// text_to_speech handler
// ---------------------------------------------------------------------------
async function textToSpeechHandler(args, context) {
    const { text, voice = 'alloy', model } = args;
    if (!text)
        return (0, result_types_1.toolError)('Missing required parameter: text');
    const provider = resolveProvider('tts', model);
    if (!provider)
        return (0, result_types_1.toolError)('No TTS service configured.');
    const headers = {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${provider.apiKey}`,
    };
    try {
        let url;
        let body;
        let isRawAudio = false;
        if (provider.brand === 'minimax') {
            url = provider.url.includes('/v1') ? `${provider.url}/t2a_v2` : `${provider.url}/v1/t2a_v2`;
            body = {
                model: provider.model || 'speech-2.8-hd',
                text,
                voice_setting: { voice_id: voice, speed: 1.0, vol: 1.0, pitch: 0 },
            };
        }
        else {
            // OpenAI-compatible
            url = `${provider.url}/v1/audio/speech`;
            body = { model: provider.model || 'tts-1', input: text, voice };
            isRawAudio = true;
        }
        const response = await fetch(url, {
            method: 'POST',
            headers,
            body: JSON.stringify(body),
            signal: AbortSignal.timeout(60000),
        });
        if (!response.ok) {
            const err = await response.text().catch(() => 'Unknown error');
            return (0, result_types_1.toolError)(`TTS failed (${response.status}): ${err}`);
        }
        if (isRawAudio) {
            // Raw audio response
            const buffer = Buffer.from(await response.arrayBuffer());
            return (0, result_types_1.toolResult)({
                success: true,
                audio_file: `tts_${Date.now()}.mp3`,
                size: buffer.length,
                message: 'Audio generated.',
            });
        }
        // JSON response (MiniMax)
        const result = await response.json();
        const audioHex = result.data?.audio;
        if (audioHex) {
            const buffer = Buffer.from(audioHex, 'hex');
            return (0, result_types_1.toolResult)({
                success: true,
                audio_file: `tts_${Date.now()}.mp3`,
                size: buffer.length,
            });
        }
        return (0, result_types_1.toolResult)({ success: true, raw: result });
    }
    catch (err) {
        return (0, result_types_1.toolError)(`TTS error: ${err.message}`);
    }
}
// ---------------------------------------------------------------------------
// generate_video handler
// ---------------------------------------------------------------------------
async function generateVideoHandler(args, context) {
    const { prompt, duration = 6, model } = args;
    if (!prompt)
        return (0, result_types_1.toolError)('Missing required parameter: prompt');
    const provider = resolveProvider('video', model);
    if (!provider)
        return (0, result_types_1.toolError)('No video generation service configured.');
    const headers = {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${provider.apiKey}`,
    };
    try {
        let url;
        let body;
        if (provider.brand === 'minimax') {
            url = provider.url.includes('/v1') ? `${provider.url}/video_generation` : `${provider.url}/v1/video_generation`;
            body = { model: provider.model || 'MiniMax-Hailuo-2.3', prompt, duration: String(duration) };
        }
        else {
            url = `${provider.url}/v1/video/generations`;
            body = { model: provider.model || 'default', prompt, duration };
        }
        const response = await fetch(url, {
            method: 'POST',
            headers,
            body: JSON.stringify(body),
            signal: AbortSignal.timeout(30000),
        });
        if (!response.ok) {
            const err = await response.text().catch(() => 'Unknown error');
            return (0, result_types_1.toolError)(`Video generation failed (${response.status}): ${err}`);
        }
        const result = await response.json();
        if (result.task_id) {
            return (0, result_types_1.toolResult)({
                success: true,
                status: 'processing',
                task_id: result.task_id,
                message: `Video generation started. Task ID: ${result.task_id}. This may take several minutes.`,
            });
        }
        const videoUrl = result.video_url || result.data?.video_url;
        if (videoUrl) {
            return (0, result_types_1.toolResult)({ success: true, video_url: videoUrl });
        }
        return (0, result_types_1.toolResult)({ success: true, raw: result });
    }
    catch (err) {
        return (0, result_types_1.toolError)(`Video generation error: ${err.message}`);
    }
}
// ---------------------------------------------------------------------------
// generate_music handler
// ---------------------------------------------------------------------------
async function generateMusicHandler(args, context) {
    const { prompt, lyrics, instrumental, model } = args;
    if (!prompt)
        return (0, result_types_1.toolError)('Missing required parameter: prompt');
    const provider = resolveProvider('music', model);
    if (!provider)
        return (0, result_types_1.toolError)('No music generation service configured.');
    const headers = {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${provider.apiKey}`,
    };
    try {
        let url;
        let body;
        if (provider.brand === 'minimax') {
            url = provider.url.includes('/v1') ? `${provider.url}/music_generation` : `${provider.url}/v1/music_generation`;
            body = { model: provider.model || 'music-2.5+', prompt };
            if (instrumental)
                body.instrumental = true;
            if (lyrics) {
                body.lyrics = lyrics;
                body.lyrics_optimizer = true;
            }
        }
        else {
            url = `${provider.url}/v1/music/generations`;
            body = { model: provider.model || 'default', prompt, duration: 30 };
        }
        const response = await fetch(url, {
            method: 'POST',
            headers,
            body: JSON.stringify(body),
            signal: AbortSignal.timeout(120000),
        });
        if (!response.ok) {
            const err = await response.text().catch(() => 'Unknown error');
            return (0, result_types_1.toolError)(`Music generation failed (${response.status}): ${err}`);
        }
        const result = await response.json();
        if (result.data?.audio) {
            const buffer = Buffer.from(result.data.audio, 'hex');
            return (0, result_types_1.toolResult)({
                success: true,
                audio_file: `music_${Date.now()}.mp3`,
                size: buffer.length,
                duration: result.data.duration,
            });
        }
        return (0, result_types_1.toolResult)({ success: true, raw: result });
    }
    catch (err) {
        return (0, result_types_1.toolError)(`Music generation error: ${err.message}`);
    }
}
// ---------------------------------------------------------------------------
// Registration
// ---------------------------------------------------------------------------
function registerMultimodalTools() {
    tool_registry_1.registry.register({
        name: 'generate_image',
        toolset: 'multimodal',
        schema: {
            description: 'Generate an image from a text prompt using AI.',
            parameters: {
                type: 'object',
                properties: {
                    prompt: { type: 'string', description: 'Image description (English works best)' },
                    size: { type: 'string', description: 'Image size: "1024x1024", "1792x1024", "1024x1792". Default: 1024x1024', default: '1024x1024' },
                    model: { type: 'string', description: 'Model override (optional)' },
                },
                required: ['prompt'],
            },
        },
        handler: generateImageHandler,
        isAsync: true,
        description: 'Generate image from text',
        emoji: '🎨',
    });
    tool_registry_1.registry.register({
        name: 'text_to_speech',
        toolset: 'multimodal',
        schema: {
            description: 'Convert text to speech audio.',
            parameters: {
                type: 'object',
                properties: {
                    text: { type: 'string', description: 'Text to convert to speech' },
                    voice: { type: 'string', description: 'Voice ID (default: alloy)', default: 'alloy' },
                    model: { type: 'string', description: 'Model override (optional)' },
                },
                required: ['text'],
            },
        },
        handler: textToSpeechHandler,
        isAsync: true,
        description: 'Text to speech',
        emoji: '🔊',
    });
    tool_registry_1.registry.register({
        name: 'generate_video',
        toolset: 'multimodal',
        schema: {
            description: 'Generate a video from a text prompt using AI. May take several minutes.',
            parameters: {
                type: 'object',
                properties: {
                    prompt: { type: 'string', description: 'Video content description' },
                    duration: { type: 'number', description: 'Duration in seconds (default: 6)', default: 6 },
                    model: { type: 'string', description: 'Model override (optional)' },
                },
                required: ['prompt'],
            },
        },
        handler: generateVideoHandler,
        isAsync: true,
        description: 'Generate video from text',
        emoji: '🎬',
    });
    tool_registry_1.registry.register({
        name: 'generate_music',
        toolset: 'multimodal',
        schema: {
            description: 'Generate music from a text prompt describing style and content.',
            parameters: {
                type: 'object',
                properties: {
                    prompt: { type: 'string', description: 'Music style and content description' },
                    lyrics: { type: 'string', description: 'Lyrics (optional)' },
                    instrumental: { type: 'boolean', description: 'Generate instrumental only (no vocals)', default: false },
                    model: { type: 'string', description: 'Model override (optional)' },
                },
                required: ['prompt'],
            },
        },
        handler: generateMusicHandler,
        isAsync: true,
        description: 'Generate music from text',
        emoji: '🎵',
    });
}
// Auto-register
registerMultimodalTools();
//# sourceMappingURL=multimodal.js.map