import OpenAI from "openai";
import { proxyAwareFetch } from "../proxy-bootstrap.js";
export class OpenAIProvider {
    name = "openai";
    client;
    constructor(opts = {}) {
        this.client = new OpenAI({
            apiKey: opts.apiKey,
            baseURL: opts.baseURL,
            fetch: proxyAwareFetch,
        });
    }
    async runTurn(opts) {
        const messages = anthropicToOpenAI(opts.systemPrompt, opts.messages);
        const tools = opts.tools.map((t) => ({
            type: "function",
            function: {
                name: t.name,
                description: t.description,
                parameters: t.inputSchema,
            },
        }));
        const stream = await this.client.chat.completions.create({
            model: opts.model,
            messages,
            tools: tools.length ? tools : undefined,
            max_tokens: opts.maxTokens ?? 16_000,
            stream: true,
            stream_options: { include_usage: true },
        });
        let text = "";
        const toolCalls = new Map();
        let finish = "stop";
        let inputTokens = 0;
        let outputTokens = 0;
        let cacheReadTokens = 0;
        for await (const chunk of stream) {
            const choice = chunk.choices[0];
            if (choice?.delta?.content) {
                text += choice.delta.content;
                opts.handlers?.onTextDelta?.(choice.delta.content);
            }
            if (choice?.delta?.tool_calls) {
                for (const tc of choice.delta.tool_calls) {
                    const idx = tc.index;
                    if (!toolCalls.has(idx)) {
                        toolCalls.set(idx, { id: "", name: "", args: "" });
                    }
                    const acc = toolCalls.get(idx);
                    if (tc.id)
                        acc.id = tc.id;
                    if (tc.function?.name)
                        acc.name = tc.function.name;
                    if (tc.function?.arguments)
                        acc.args += tc.function.arguments;
                }
            }
            if (choice?.finish_reason)
                finish = choice.finish_reason;
            if (chunk.usage) {
                inputTokens = chunk.usage.prompt_tokens ?? 0;
                outputTokens = chunk.usage.completion_tokens ?? 0;
                const details = chunk.usage.prompt_tokens_details;
                cacheReadTokens = details?.cached_tokens ?? 0;
            }
        }
        const content = [];
        if (text) {
            content.push({ type: "text", text, citations: null });
        }
        for (const tc of toolCalls.values()) {
            let parsed = {};
            try {
                parsed = tc.args ? JSON.parse(tc.args) : {};
            }
            catch {
                parsed = { _raw: tc.args };
            }
            content.push({
                type: "tool_use",
                id: tc.id || `call_${tc.name}_${Math.random().toString(36).slice(2)}`,
                name: tc.name,
                input: parsed,
            });
        }
        return {
            content,
            stopReason: finish === "tool_calls" ? "tool_use" : "end_turn",
            usage: {
                inputTokens,
                outputTokens,
                cacheReadTokens,
                cacheWriteTokens: 0,
            },
        };
    }
}
function anthropicToOpenAI(systemPrompt, messages) {
    const out = [
        { role: "system", content: systemPrompt },
    ];
    for (const msg of messages) {
        if (msg.role === "user") {
            const content = msg.content;
            if (typeof content === "string") {
                out.push({ role: "user", content });
                continue;
            }
            const textBlocks = [];
            const toolResults = [];
            for (const block of content) {
                if (block.type === "text") {
                    textBlocks.push(block.text);
                }
                else if (block.type === "tool_result") {
                    const text = typeof block.content === "string"
                        ? block.content
                        : Array.isArray(block.content)
                            ? block.content
                                .map((b) => (b.type === "text" ? b.text : ""))
                                .join("\n")
                            : "";
                    toolResults.push({
                        id: block.tool_use_id,
                        content: text,
                        isError: block.is_error ?? false,
                    });
                }
            }
            if (textBlocks.length) {
                out.push({ role: "user", content: textBlocks.join("\n") });
            }
            for (const tr of toolResults) {
                out.push({
                    role: "tool",
                    tool_call_id: tr.id,
                    content: tr.isError ? `[error] ${tr.content}` : tr.content,
                });
            }
        }
        else {
            const content = msg.content;
            if (typeof content === "string") {
                out.push({ role: "assistant", content });
                continue;
            }
            const textParts = [];
            const toolCalls = [];
            for (const block of content) {
                if (block.type === "text") {
                    textParts.push(block.text);
                }
                else if (block.type === "tool_use") {
                    toolCalls.push({
                        id: block.id,
                        type: "function",
                        function: {
                            name: block.name,
                            arguments: JSON.stringify(block.input ?? {}),
                        },
                    });
                }
            }
            const assistant = {
                role: "assistant",
                content: textParts.join("\n") || null,
            };
            if (toolCalls.length)
                assistant.tool_calls = toolCalls;
            out.push(assistant);
        }
    }
    return out;
}
//# sourceMappingURL=openai.js.map