"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseOpenRouterSSE = parseOpenRouterSSE;
const shared_js_1 = require("./shared.js");
function parseOpenRouterSSE(line) {
    const trimmed = line.trim();
    if (trimmed.length === 0)
        return [];
    if (trimmed === '[DONE]')
        return [];
    // OpenRouter passes through OpenAI-style "OPENROUTER PROCESSING"
    // comments on slow upstreams as `: <message>` — these aren't JSON.
    if (trimmed.startsWith(':'))
        return [];
    const obj = (0, shared_js_1.tryJson)(trimmed);
    if (!obj)
        return [];
    // Error envelope (e.g. invalid model, rate limit). OpenRouter wraps
    // these as `{"error":{"message":"...","code":...,"metadata":...}}`.
    if (obj.error && typeof obj.error === 'object') {
        const err = obj.error;
        const message = typeof err.message === 'string' ? err.message : 'OpenRouter stream error';
        const code = typeof err.code === 'string' || typeof err.code === 'number'
            ? String(err.code)
            : 'openrouter_error';
        return [{ type: 'error', kind: code, message }];
    }
    const events = [];
    const choices = obj.choices;
    if (Array.isArray(choices) && choices.length > 0) {
        for (const c of choices) {
            if (!c || typeof c !== 'object')
                continue;
            const choice = c;
            const delta = choice.delta ?? {};
            if (typeof delta.content === 'string' && delta.content.length > 0) {
                events.push({ type: 'text_delta', text: delta.content });
            }
            // finish_reason is set ('stop' | 'length' | 'content_filter' |
            // ...) on the terminal chunk. We don't emit message_done here
            // because the usage-bearing chunk often arrives AFTER the finish
            // chunk; the message_done fires on the usage chunk below.
        }
    }
    // Usage chunk — sent LAST when stream_options.include_usage is set.
    // cost is OpenRouter-specific (USD). Emit a synthetic message_done
    // with empty finalText so the runner's accumulator (which holds the
    // assembled finalText) wins, but usage is attached.
    const usage = obj.usage;
    if (usage && typeof usage === 'object') {
        const inputTokens = typeof usage.prompt_tokens === 'number' ? usage.prompt_tokens : undefined;
        const outputTokens = typeof usage.completion_tokens === 'number'
            ? usage.completion_tokens
            : undefined;
        const cost = typeof usage.cost === 'number' ? usage.cost : undefined;
        const u = {};
        if (inputTokens !== undefined)
            u.inputTokens = inputTokens;
        if (outputTokens !== undefined)
            u.outputTokens = outputTokens;
        if (cost !== undefined)
            u.costUsd = cost;
        if (Object.keys(u).length > 0) {
            events.push({ type: 'message_done', finalText: '', usage: u });
        }
    }
    return events;
}
//# sourceMappingURL=openrouter.js.map