/**
 * src/models/provider.ts
 * واجهة مزود النماذج الموحدة — Abstract model provider + OpenAI-compatible caller
 */
import { createChildLogger } from '../utils/logger.js';
const log = createChildLogger('models:provider');
/**
 * دالة مشتركة لاستدعاء أي API متوافق مع OpenAI
 * Used by Together AI (Qwen), DeepSeek, and any OpenAI-compatible endpoint
 */
export async function callOpenAICompatible(baseUrl, apiKey, model, messages, options = {}) {
    const startTime = Date.now();
    const url = `${baseUrl.replace(/\/$/, '')}/chat/completions`;
    // بناء الطلب
    const body = {
        model,
        messages: messages.map(m => {
            const msg = { role: m.role, content: m.content };
            if (m.name)
                msg.name = m.name;
            if (m.tool_call_id)
                msg.tool_call_id = m.tool_call_id;
            if (m.tool_calls)
                msg.tool_calls = m.tool_calls;
            return msg;
        }),
        stream: false, // non-streaming for now
    };
    if (options.temperature !== undefined)
        body.temperature = options.temperature;
    if (options.maxTokens !== undefined)
        body.max_tokens = options.maxTokens;
    if (options.topP !== undefined)
        body.top_p = options.topP;
    if (options.stop)
        body.stop = options.stop;
    if (options.tools?.length)
        body.tools = options.tools;
    if (options.toolChoice)
        body.tool_choice = options.toolChoice;
    if (options.responseFormat)
        body.response_format = options.responseFormat;
    log.debug({ model, messageCount: messages.length }, 'Calling OpenAI-compatible API');
    // Per-tier timeouts: routers/brains 30s, reasoning models override to 60s+.
    const timeoutMs = options.timeoutMs ?? 30_000;
    const response = await fetch(url, {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            'Authorization': `Bearer ${apiKey}`,
        },
        body: JSON.stringify(body),
        signal: AbortSignal.timeout(timeoutMs),
    });
    if (!response.ok) {
        const errorText = await response.text().catch(() => 'Unknown error');
        const latencyMs = Date.now() - startTime;
        log.error({ model, status: response.status, errorText, latencyMs }, 'API call failed');
        throw new ModelError(`${model} API error: ${response.status} — ${errorText}`, response.status, model);
    }
    const data = (await response.json());
    const latencyMs = Date.now() - startTime;
    const choice = data.choices?.[0];
    if (!choice) {
        throw new ModelError(`${model} returned no choices`, 500, model);
    }
    const result = {
        content: choice.message.content ?? '',
        tokensInput: data.usage?.prompt_tokens ?? 0,
        tokensOutput: data.usage?.completion_tokens ?? 0,
        model: data.model || model,
        latencyMs,
        finishReason: choice.finish_reason,
    };
    if (choice.message.tool_calls?.length) {
        result.toolCalls = choice.message.tool_calls;
    }
    log.debug({ model, tokensIn: result.tokensInput, tokensOut: result.tokensOutput, latencyMs }, 'API call completed');
    return result;
}
// ─── Model Error ─────────────────────────────────────────────────────
export class ModelError extends Error {
    statusCode;
    model;
    constructor(message, statusCode, model) {
        super(message);
        this.statusCode = statusCode;
        this.model = model;
        this.name = 'ModelError';
    }
    /** هل الخطأ قابل لإعادة المحاولة؟ */
    get isRetryable() {
        return this.statusCode === 429 || this.statusCode >= 500;
    }
}
//# sourceMappingURL=provider.js.map