/**
 * Local Model Executor
 * Executes local models directly on the user's machine (bypasses gateway)
 * This ensures local models actually work and feel integrated
 */
/**
 * Execute a local model request directly (no gateway)
 */
export async function executeLocalModel(config, messages) {
    const baseUrl = config.baseUrl || getDefaultBaseUrl(config.provider);
    if (config.provider === 'ollama') {
        return executeOllama(baseUrl, config, messages);
    }
    else if (config.provider === 'lm-studio') {
        return executeLMStudio(baseUrl, config, messages);
    }
    else if (config.provider === 'custom') {
        return executeCustom(baseUrl, config, messages);
    }
    else {
        throw new Error(`Unsupported local model provider: ${config.provider}`);
    }
}
function getDefaultBaseUrl(provider) {
    switch (provider) {
        case 'ollama':
            return 'http://localhost:11434';
        case 'lm-studio':
            return 'http://localhost:1234';
        case 'custom':
            return 'http://localhost:8000';
        default:
            return 'http://localhost:11434';
    }
}
/**
 * Execute Ollama model
 */
async function executeOllama(baseUrl, config, messages) {
    const prompt = formatMessagesForOllama(messages);
    const response = await fetch(`${baseUrl}/api/generate`, {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
        },
        body: JSON.stringify({
            model: config.model,
            prompt: prompt,
            stream: false,
            options: {
                temperature: config.temperature ?? 0.7,
                top_p: config.topP,
                num_predict: config.maxTokens,
            },
        }),
    });
    if (!response.ok) {
        const error = await response.text();
        throw new Error(`Ollama API error: ${response.status} - ${error}`);
    }
    const data = await response.json();
    return {
        result: data.response || 'No response',
        model: config.model,
        usage: {
            totalTokens: data.eval_count ? (data.prompt_eval_count || 0) + data.eval_count : undefined,
            promptTokens: data.prompt_eval_count,
            completionTokens: data.eval_count,
        },
        cost: 0,
    };
}
/**
 * Execute LM Studio model (OpenAI-compatible API)
 */
async function executeLMStudio(baseUrl, config, messages) {
    const response = await fetch(`${baseUrl}/v1/chat/completions`, {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
        },
        body: JSON.stringify({
            model: config.model,
            messages: messages,
            temperature: config.temperature ?? 0.7,
            max_tokens: config.maxTokens,
            top_p: config.topP,
            frequency_penalty: config.frequencyPenalty,
            presence_penalty: config.presencePenalty,
        }),
    });
    if (!response.ok) {
        const error = await response.text();
        throw new Error(`LM Studio API error: ${response.status} - ${error}`);
    }
    const data = await response.json();
    const usage = data.usage || {};
    return {
        result: data.choices?.[0]?.message?.content || 'No response',
        model: data.model || config.model,
        usage: {
            totalTokens: usage.total_tokens,
            promptTokens: usage.prompt_tokens,
            completionTokens: usage.completion_tokens,
        },
        cost: 0,
    };
}
/**
 * Execute custom model (OpenAI-compatible API)
 */
async function executeCustom(baseUrl, config, messages) {
    const response = await fetch(`${baseUrl}/v1/chat/completions`, {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
        },
        body: JSON.stringify({
            model: config.model,
            messages: messages,
            temperature: config.temperature ?? 0.7,
            max_tokens: config.maxTokens,
            top_p: config.topP,
            frequency_penalty: config.frequencyPenalty,
            presence_penalty: config.presencePenalty,
        }),
    });
    if (!response.ok) {
        const error = await response.text();
        throw new Error(`Custom model API error: ${response.status} - ${error}`);
    }
    const data = await response.json();
    const usage = data.usage || {};
    return {
        result: data.choices?.[0]?.message?.content || 'No response',
        model: data.model || config.model,
        usage: {
            totalTokens: usage.total_tokens,
            promptTokens: usage.prompt_tokens,
            completionTokens: usage.completion_tokens,
        },
        cost: 0,
    };
}
/**
 * Format messages for Ollama (simple prompt format)
 */
function formatMessagesForOllama(messages) {
    let prompt = '';
    for (const msg of messages) {
        if (msg.role === 'system') {
            prompt += `System: ${msg.content}\n\n`;
        }
        else if (msg.role === 'user') {
            prompt += `User: ${msg.content}\n\n`;
        }
        else if (msg.role === 'assistant') {
            prompt += `Assistant: ${msg.content}\n\n`;
        }
    }
    prompt += 'Assistant:';
    return prompt;
}
/**
 * Verify local model server is running
 */
export async function verifyLocalModelServer(provider, baseUrl) {
    const url = baseUrl || getDefaultBaseUrl(provider);
    try {
        if (provider === 'ollama') {
            const response = await fetch(`${url}/api/tags`, {
                method: 'GET',
                headers: { 'Content-Type': 'application/json' },
            });
            if (!response.ok) {
                return { available: false, error: `Ollama server not responding (${response.status})` };
            }
            const data = await response.json();
            const models = (data.models || []).map((m) => m.name);
            return { available: true, models };
        }
        else if (provider === 'lm-studio' || provider === 'custom') {
            // LM Studio and custom use OpenAI-compatible API
            const response = await fetch(`${url}/v1/models`, {
                method: 'GET',
                headers: { 'Content-Type': 'application/json' },
            });
            if (!response.ok) {
                return { available: false, error: `Server not responding (${response.status})` };
            }
            const data = await response.json();
            const models = (data.data || []).map((m) => m.id);
            return { available: true, models };
        }
    }
    catch (error) {
        return { available: false, error: error.message || 'Connection failed' };
    }
    return { available: false, error: 'Unknown provider' };
}
//# sourceMappingURL=local-model-executor.js.map