import { OpenAiCompatibleCodec } from './openai-compatible-codec.js';
import { OpenAiCompatibleModelName } from './openai-compatible-model.js';
/**
 * Shared adapter for OpenAI-compatible `/chat/completions` providers such as
 * Ollama, LM Studio, LiteLLM, vLLM, Hugging Face router, OpenRouter, Together,
 * and Groq. Profiles own endpoint/model identity; this class owns the common
 * HTTP transport and response parsing.
 */
export class OpenAiCompatibleAdapter {
    info;
    profile;
    model;
    displayModel;
    endpointBaseUrl;
    endpointAuth;
    fetcher;
    constructor(options) {
        const endpoint = options.runtime?.endpoint;
        if (!endpoint) {
            throw new Error(`Missing ${options.profile.label} endpoint runtime. Resolve provider runtime before creating the adapter.`);
        }
        this.profile = options.profile;
        this.model = OpenAiCompatibleModelName.toProviderModel(options.profile, options.model);
        this.displayModel = OpenAiCompatibleModelName.toHeddleModel(options.profile, this.model);
        this.endpointBaseUrl = OpenAiCompatibleAdapter.trimTrailingSlash(endpoint.baseUrl);
        this.endpointAuth = endpoint.auth;
        this.fetcher = options.runtime?.fetchImpl ?? OpenAiCompatibleAdapter.defaultFetch;
        this.info = {
            provider: options.profile.id,
            model: this.displayModel,
            capabilities: options.profile.capabilities,
        };
    }
    async chat(messages, tools, signal, onStreamEvent) {
        const response = await this.fetcher(`${this.endpointBaseUrl}/chat/completions`, {
            method: 'POST',
            signal,
            headers: OpenAiCompatibleAdapter.headers(this.endpointAuth),
            body: JSON.stringify({
                model: this.model,
                messages: OpenAiCompatibleCodec.toMessages(messages),
                tools: tools.length > 0 ? OpenAiCompatibleCodec.toTools(tools) : undefined,
                tool_choice: tools.length > 0 ? 'auto' : undefined,
                stream: false,
            }),
        });
        const body = await this.readJsonResponse(response);
        const content = OpenAiCompatibleCodec.extractContent(body);
        if (content) {
            onStreamEvent?.({ type: 'content.delta', delta: content });
            onStreamEvent?.({ type: 'content.done', content });
        }
        return {
            content,
            toolCalls: OpenAiCompatibleCodec.extractToolCalls(body),
            usage: OpenAiCompatibleCodec.extractUsage(body),
        };
    }
    async readJsonResponse(response) {
        const text = await response.text();
        if (!response.ok) {
            throw new Error(`${this.profile.label} chat-completions request failed: ${response.status} ${response.statusText}${text ? `: ${text}` : ''}`);
        }
        return text.trim() ? JSON.parse(text) : {};
    }
    static trimTrailingSlash(value) {
        return value.replace(/\/+$/, '');
    }
    static headers(auth) {
        return {
            'content-type': 'application/json',
            ...(auth.type === 'bearer' ? { authorization: `Bearer ${auth.token}` } : {}),
        };
    }
    static async defaultFetch(url, init) {
        return await fetch(url, init);
    }
}
//# sourceMappingURL=openai-compatible-adapter.js.map