"use strict";
/**
 * Cursor Executor
 * Handles HTTP/2 requests to Cursor API with protobuf encoding/decoding
 */
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.CursorExecutor = void 0;
const cursor_protobuf_js_1 = require("./cursor-protobuf.js");
const cursor_translator_js_1 = require("./cursor-translator.js");
const cursor_protobuf_schema_js_1 = require("./cursor-protobuf-schema.js");
const cursor_client_policy_js_1 = require("./cursor-client-policy.js");
const logging_1 = require("../services/logging");
const logger = (0, logging_1.createLogger)('cursor:executor');
const cursor_stream_parser_js_1 = require("./cursor-stream-parser.js");
/** Lazy import http2 */
let http2Module = null;
async function getHttp2() {
    if (http2Module)
        return http2Module;
    try {
        http2Module = await Promise.resolve().then(() => __importStar(require('http2')));
        return http2Module;
    }
    catch (err) {
        if (process.env.CCS_DEBUG) {
            console.error('[cursor] http2 module not available, falling back to fetch:', err);
        }
        return null;
    }
}
/**
 * Create error response from JSON error
 */
function toCursorErrorPayloadFromJson(jsonError) {
    const errorMsg = jsonError?.error?.details?.[0]?.debug?.details?.title ||
        jsonError?.error?.details?.[0]?.debug?.details?.detail ||
        jsonError?.error?.message ||
        'API Error';
    const mappedError = (0, cursor_stream_parser_js_1.mapCursorConnectError)(jsonError?.error?.code);
    return {
        message: errorMsg,
        status: mappedError.status,
        errorType: mappedError.errorType,
        code: jsonError?.error?.details?.[0]?.debug?.error || 'unknown',
    };
}
function buildCursorErrorEnvelope(error) {
    return JSON.stringify({
        error: {
            message: error.message,
            type: error.errorType,
            code: error.code,
            status: error.status,
        },
    });
}
function createCursorErrorResponse(error) {
    return new Response(buildCursorErrorEnvelope(error), {
        status: error.status,
        headers: { 'Content-Type': 'application/json' },
    });
}
function toCursorExecutorErrorPayload(error) {
    if (error instanceof cursor_stream_parser_js_1.CursorConnectFrameError) {
        return {
            message: error.message,
            status: error.status,
            errorType: error.errorType,
            code: 'cursor_protocol_error',
        };
    }
    return {
        message: error instanceof Error ? error.message : 'Cursor streaming failed.',
        status: 502,
        errorType: 'server_error',
        code: 'cursor_error',
    };
}
class CursorExecutor {
    constructor() {
        this.baseUrl = 'https://api2.cursor.sh';
        this.chatPath = '/aiserver.v1.AiService/StreamChat';
    }
    buildUrl() {
        return `${this.baseUrl}${this.chatPath}`;
    }
    /**
     * Generate checksum using Jyh cipher (time-based XOR with rolling key seed=165)
     */
    generateChecksum(machineId) {
        return (0, cursor_client_policy_js_1.generateCursorChecksum)(machineId);
    }
    buildHeaders(credentials) {
        return (0, cursor_client_policy_js_1.buildCursorConnectHeaders)(credentials);
    }
    transformRequest(model, body, stream, credentials) {
        const translatedBody = (0, cursor_translator_js_1.buildCursorRequest)(model, body, stream, credentials);
        const messages = translatedBody.messages || [];
        const tools = (translatedBody.tools || body.tools || []);
        const reasoningEffort = body.reasoning_effort || null;
        return (0, cursor_protobuf_js_1.generateCursorBody)(messages, model, tools, reasoningEffort);
    }
    async makeFetchRequest(url, headers, body, signal) {
        const response = await fetch(url, {
            method: 'POST',
            headers,
            body,
            signal,
        });
        const responseHeaders = {};
        response.headers.forEach((value, key) => {
            responseHeaders[key] = value;
        });
        return {
            status: response.status,
            headers: responseHeaders,
            body: Buffer.from(await response.arrayBuffer()),
        };
    }
    async makeHttp2Request(url, headers, body, signal) {
        const http2 = await getHttp2();
        if (!http2) {
            throw new Error('http2 module not available');
        }
        return new Promise((resolve, reject) => {
            const urlObj = new URL(url);
            const client = http2.connect(`https://${urlObj.host}`);
            const chunks = [];
            let responseHeaders = {};
            client.on('error', (err) => {
                client.close();
                reject(err);
            });
            const req = client.request({
                ':method': 'POST',
                ':path': urlObj.pathname,
                ':authority': urlObj.host,
                ':scheme': 'https',
                ...headers,
            });
            req.on('response', (hdrs) => {
                responseHeaders = hdrs;
            });
            req.on('data', (chunk) => {
                chunks.push(chunk);
            });
            req.on('end', () => {
                client.close();
                resolve({
                    status: Number(responseHeaders[':status']) || 500,
                    headers: responseHeaders,
                    body: Buffer.concat(chunks),
                });
            });
            req.on('error', (err) => {
                client.close();
                reject(err);
            });
            if (signal) {
                const onAbort = () => {
                    req.close();
                    client.close();
                    reject(new Error('Request aborted'));
                };
                signal.addEventListener('abort', onAbort, { once: true });
                const cleanup = () => {
                    signal.removeEventListener('abort', onAbort);
                };
                req.on('end', cleanup);
                req.on('error', cleanup);
            }
            req.write(body);
            req.end();
        });
    }
    async execute(params) {
        const { model, body, stream, credentials, signal } = params;
        const url = this.buildUrl();
        const headers = this.buildHeaders(credentials);
        const transformedBody = this.transformRequest(model, body, stream, credentials);
        const startedAt = Date.now();
        logger.stage('upstream', 'cursor.upstream.request', 'Sending Cursor upstream request', {
            provider: 'cursor',
            model,
            stream,
        });
        try {
            // Streaming requests use incremental HTTP/2 → SSE pipeline
            if (stream) {
                const response = await this.executeStreaming(url, headers, transformedBody, model, body, signal);
                return { response, url, headers, transformedBody: body };
            }
            // Non-streaming: buffer entire response then transform to JSON
            const http2 = await getHttp2();
            const response = http2
                ? await this.makeHttp2Request(url, headers, transformedBody, signal)
                : await this.makeFetchRequest(url, headers, transformedBody, signal);
            if (response.status !== 200) {
                const errorText = response.body?.toString() || 'Unknown error';
                logger.stage('cleanup', 'cursor.upstream.error', 'Cursor upstream returned non-200 status', { provider: 'cursor', model, status: response.status }, { level: 'error', latencyMs: Date.now() - startedAt });
                const errorResponse = new Response(JSON.stringify({
                    error: {
                        message: `[${response.status}]: ${errorText}`,
                        type: 'invalid_request_error',
                        code: '',
                    },
                }), {
                    status: response.status,
                    headers: { 'Content-Type': 'application/json' },
                });
                return { response: errorResponse, url, headers, transformedBody: body };
            }
            const transformedResponse = this.transformProtobufToJSON(response.body, model, body);
            logger.stage('transform', 'cursor.upstream.transformed', 'Cursor response transformed', { provider: 'cursor', model }, { latencyMs: Date.now() - startedAt });
            return { response: transformedResponse, url, headers, transformedBody: body };
        }
        catch (error) {
            const err = error;
            logger.stage('cleanup', 'cursor.upstream.exception', 'Cursor upstream request threw', { provider: 'cursor', model }, {
                level: 'error',
                latencyMs: Date.now() - startedAt,
                error: { name: err.name, message: err.message },
            });
            const errorResponse = new Response(JSON.stringify({
                error: {
                    message: err.message,
                    type: 'connection_error',
                    code: '',
                },
            }), {
                status: 500,
                headers: { 'Content-Type': 'application/json' },
            });
            return { response: errorResponse, url, headers, transformedBody: body };
        }
    }
    /**
     * Execute a streaming request, piping HTTP/2 data events through
     * StreamingFrameParser for incremental SSE output.
     * Falls back to buffered transformProtobufToSSE when http2 is unavailable.
     */
    async executeStreaming(url, headers, body, model, requestBody, signal) {
        const http2 = await getHttp2();
        if (!http2) {
            const response = await this.makeFetchRequest(url, headers, body, signal);
            if (response.status !== 200) {
                const errorText = response.body?.toString() || 'Unknown error';
                return new Response(JSON.stringify({
                    error: {
                        message: `[${response.status}]: ${errorText}`,
                        type: response.status === 429 ? 'rate_limit_error' : 'invalid_request_error',
                        code: '',
                    },
                }), { status: response.status, headers: { 'Content-Type': 'application/json' } });
            }
            return this.transformProtobufToSSE(response.body, model, requestBody);
        }
        const responseId = `chatcmpl-cursor-${Date.now()}`;
        const created = Math.floor(Date.now() / 1000);
        return new Promise((resolve, reject) => {
            let settled = false;
            const resolveOnce = (response) => {
                if (settled)
                    return;
                settled = true;
                resolve(response);
            };
            const rejectOnce = (error) => {
                if (settled)
                    return;
                settled = true;
                reject(error);
            };
            const urlObj = new URL(url);
            const client = http2.connect(`https://${urlObj.host}`);
            client.on('error', (err) => {
                client.close();
                rejectOnce(err instanceof Error ? err : new Error(String(err)));
            });
            const req = client.request({
                ':method': 'POST',
                ':path': urlObj.pathname,
                ':authority': urlObj.host,
                ':scheme': 'https',
                ...headers,
            });
            // Register abort before response headers arrive so cancellation works at all stages
            let streamClosed = false;
            let streamController = null;
            if (signal) {
                const onAbort = () => {
                    streamClosed = true;
                    // If stream already started, close readable to unblock consumers.
                    if (streamController) {
                        try {
                            streamController.close();
                        }
                        catch {
                            /* already closed */
                        }
                    }
                    req.close();
                    client.close();
                    rejectOnce(new Error('Request aborted'));
                };
                signal.addEventListener('abort', onAbort, { once: true });
                const cleanup = () => signal.removeEventListener('abort', onAbort);
                req.on('end', cleanup);
                req.on('error', cleanup);
            }
            req.on('response', (hdrs) => {
                const status = Number(hdrs[':status']) || 500;
                if (status !== 200) {
                    const errorChunks = [];
                    req.on('data', (c) => errorChunks.push(c));
                    req.on('end', () => {
                        client.close();
                        const errorText = Buffer.concat(errorChunks).toString();
                        resolveOnce(new Response(JSON.stringify({
                            error: {
                                message: `[${status}]: ${errorText}`,
                                type: status === 429 ? 'rate_limit_error' : 'invalid_request_error',
                                code: '',
                            },
                        }), { status, headers: { 'Content-Type': 'application/json' } }));
                    });
                    return;
                }
                // Status 200: set up incremental streaming pipeline
                const parser = new cursor_stream_parser_js_1.StreamingFrameParser();
                const enc = new TextEncoder();
                const toolCallsMap = new Map();
                const pendingPackets = [];
                let chunkCount = 0;
                let toolCallCount = 0;
                let streamResponseResolved = false;
                const flushPendingPackets = () => {
                    if (!streamController || pendingPackets.length === 0 || streamClosed)
                        return;
                    for (const packet of pendingPackets.splice(0)) {
                        streamController.enqueue(enc.encode(packet));
                    }
                };
                const queuePacket = (packet) => {
                    if (streamClosed)
                        return;
                    if (streamController) {
                        streamController.enqueue(enc.encode(packet));
                        return;
                    }
                    pendingPackets.push(packet);
                };
                const emitSSE = (data) => {
                    queuePacket(`data: ${data}\n\n`);
                };
                const emitSSEEvent = (event, data) => {
                    queuePacket(`event: ${event}\ndata: ${data}\n\n`);
                };
                const readable = new ReadableStream({
                    start(controller) {
                        streamController = controller;
                        flushPendingPackets();
                    },
                });
                const resolveStreamingResponse = () => {
                    if (streamResponseResolved || settled)
                        return;
                    streamResponseResolved = true;
                    resolveOnce(new Response(readable, {
                        status: 200,
                        headers: {
                            'Content-Type': 'text/event-stream',
                            'Cache-Control': 'no-cache',
                            Connection: 'keep-alive',
                        },
                    }));
                    flushPendingPackets();
                };
                const closeStream = () => {
                    if (streamClosed)
                        return;
                    streamClosed = true;
                    if (streamController) {
                        try {
                            streamController.close();
                        }
                        catch {
                            /* already closed */
                        }
                    }
                    client.close();
                };
                const buildChunk = (delta, finishReason) => JSON.stringify({
                    id: responseId,
                    object: 'chat.completion.chunk',
                    created,
                    model,
                    choices: [{ index: 0, delta, finish_reason: finishReason }],
                });
                const handleFrameError = (frame) => {
                    const errorPayload = buildCursorErrorEnvelope({
                        message: frame.message,
                        status: frame.status,
                        errorType: frame.errorType,
                        code: frame.errorType === 'rate_limit_error' ? 'rate_limited' : 'cursor_error',
                    });
                    if (!streamResponseResolved && chunkCount === 0 && toolCallCount === 0) {
                        streamClosed = true;
                        req.close();
                        client.close();
                        resolveOnce(new Response(errorPayload, {
                            status: frame.status,
                            headers: { 'Content-Type': 'application/json' },
                        }));
                        return;
                    }
                    resolveStreamingResponse();
                    emitSSEEvent('error', errorPayload);
                    closeStream();
                };
                req.on('data', (chunk) => {
                    if (streamClosed)
                        return;
                    for (const frame of parser.push(chunk)) {
                        if (frame.type === 'error') {
                            handleFrameError(frame);
                            return;
                        }
                        resolveStreamingResponse();
                        if (frame.type === 'toolCall') {
                            const tc = frame.toolCall;
                            // Emit role chunk on first content
                            if (chunkCount === 0) {
                                emitSSE(buildChunk({ role: 'assistant', content: '' }, null));
                                chunkCount++;
                            }
                            if (toolCallsMap.has(tc.id)) {
                                const existing = toolCallsMap.get(tc.id);
                                if (!existing)
                                    continue;
                                existing.function.arguments += tc.function.arguments;
                                existing.isLast = tc.isLast;
                                if (tc.function.arguments) {
                                    emitSSE(buildChunk({
                                        tool_calls: [
                                            {
                                                index: existing.index,
                                                id: tc.id,
                                                type: 'function',
                                                function: {
                                                    name: tc.function.name,
                                                    arguments: tc.function.arguments,
                                                },
                                            },
                                        ],
                                    }, null));
                                    chunkCount++;
                                }
                            }
                            else {
                                const idx = toolCallCount++;
                                toolCallsMap.set(tc.id, { ...tc, index: idx });
                                emitSSE(buildChunk({
                                    tool_calls: [
                                        {
                                            index: idx,
                                            id: tc.id,
                                            type: 'function',
                                            function: {
                                                name: tc.function.name,
                                                arguments: tc.function.arguments,
                                            },
                                        },
                                    ],
                                }, null));
                                chunkCount++;
                            }
                        }
                        if (frame.type === 'text') {
                            const delta = chunkCount === 0 && toolCallCount === 0
                                ? { role: 'assistant', content: frame.text }
                                : { content: frame.text };
                            emitSSE(buildChunk(delta, null));
                            chunkCount++;
                        }
                        if (frame.type === 'thinking') {
                            const delta = chunkCount === 0 && toolCallCount === 0
                                ? { role: 'assistant', reasoning_content: frame.text }
                                : { reasoning_content: frame.text };
                            emitSSE(buildChunk(delta, null));
                            chunkCount++;
                        }
                    }
                });
                req.on('end', () => {
                    if (streamClosed)
                        return;
                    for (const frame of parser.finish()) {
                        if (frame.type === 'error') {
                            handleFrameError(frame);
                            return;
                        }
                    }
                    resolveStreamingResponse();
                    if (chunkCount === 0 && toolCallCount === 0) {
                        emitSSE(buildChunk({ role: 'assistant', content: '' }, null));
                    }
                    emitSSE(JSON.stringify({
                        id: responseId,
                        object: 'chat.completion.chunk',
                        created,
                        model,
                        choices: [
                            {
                                index: 0,
                                delta: {},
                                finish_reason: toolCallCount > 0 ? 'tool_calls' : 'stop',
                            },
                        ],
                        usage: { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 },
                    }));
                    emitSSE('[DONE]');
                    closeStream();
                });
                req.on('error', (err) => {
                    client.close();
                    if (!streamResponseResolved) {
                        rejectOnce(err instanceof Error ? err : new Error(String(err)));
                        return;
                    }
                    if (!streamClosed) {
                        try {
                            streamController?.error(err);
                        }
                        catch {
                            /* already closed */
                        }
                    }
                });
            });
            req.on('error', (err) => {
                client.close();
                rejectOnce(err instanceof Error ? err : new Error(String(err)));
            });
            req.write(body);
            req.end();
        });
    }
    /**
     * Parse protobuf buffer into frames and extract text/toolcalls.
     * Shared logic between JSON and SSE transformers.
     */
    *parseProtobufFrames(buffer) {
        let offset = 0;
        while (offset < buffer.length) {
            if (offset + 5 > buffer.length)
                break;
            const flags = buffer[offset];
            const length = buffer.readUInt32BE(offset + 1);
            if (offset + 5 + length > buffer.length)
                break;
            let payload = buffer.slice(offset + 5, offset + 5 + length);
            offset += 5 + length;
            try {
                payload = (0, cursor_stream_parser_js_1.decompressPayload)(payload, flags);
            }
            catch (error) {
                yield { type: 'error', error: toCursorExecutorErrorPayload(error) };
                return;
            }
            if ((0, cursor_protobuf_schema_js_1.isEndStreamConnectFrame)(flags)) {
                try {
                    const json = JSON.parse(payload.toString('utf-8'));
                    const msg = json?.error?.details?.[0]?.debug?.details?.title ||
                        json?.error?.details?.[0]?.debug?.details?.detail ||
                        json?.error?.message;
                    if (msg) {
                        const mappedError = (0, cursor_stream_parser_js_1.mapCursorConnectError)(json?.error?.code);
                        yield {
                            type: 'error',
                            error: {
                                message: msg,
                                status: mappedError.status,
                                errorType: mappedError.errorType,
                                code: json?.error?.code || 'cursor_error',
                            },
                        };
                        return;
                    }
                }
                catch {
                    // Ignore successful end-stream metadata trailers.
                }
                continue;
            }
            // Check for JSON error format
            try {
                const text = payload.toString('utf-8');
                if (text.startsWith('{') && text.includes('"error"')) {
                    yield { type: 'error', error: toCursorErrorPayloadFromJson(JSON.parse(text)) };
                    return;
                }
            }
            catch (err) {
                if (process.env.CCS_DEBUG) {
                    console.error('[cursor] parseProtobufFrames error parsing failed:', err);
                }
            }
            const result = (0, cursor_protobuf_js_1.extractTextFromResponse)(new Uint8Array(payload));
            // Check for protobuf-decoded error
            if (result.error) {
                const errorLower = result.error.toLowerCase();
                const isRateLimit = errorLower.includes('rate limit') ||
                    errorLower.includes('resource_exhausted') ||
                    errorLower.includes('too many requests');
                yield {
                    type: 'error',
                    error: {
                        message: result.error,
                        status: isRateLimit ? 429 : 502,
                        errorType: isRateLimit ? 'rate_limit_error' : 'server_error',
                        code: isRateLimit ? 'rate_limited' : 'cursor_error',
                    },
                };
                return;
            }
            if (result.toolCall) {
                yield { type: 'toolCall', toolCall: result.toolCall };
            }
            if (result.text) {
                yield { type: 'text', text: result.text };
            }
            if (result.thinking) {
                yield { type: 'thinking', text: result.thinking };
            }
        }
        if (offset !== buffer.length) {
            yield {
                type: 'error',
                error: {
                    message: 'Truncated Cursor ConnectRPC frame.',
                    status: 502,
                    errorType: 'server_error',
                    code: 'cursor_protocol_error',
                },
            };
        }
    }
    transformProtobufToJSON(buffer, model, _body) {
        const responseId = `chatcmpl-cursor-${Date.now()}`;
        const created = Math.floor(Date.now() / 1000);
        let totalContent = '';
        let totalReasoning = '';
        const toolCalls = [];
        const toolCallsMap = new Map();
        for (const frame of this.parseProtobufFrames(buffer)) {
            if (frame.type === 'error') {
                return createCursorErrorResponse(frame.error);
            }
            if (frame.type === 'toolCall') {
                const tc = frame.toolCall;
                if (toolCallsMap.has(tc.id)) {
                    const existing = toolCallsMap.get(tc.id);
                    if (!existing)
                        continue;
                    existing.function.arguments += tc.function.arguments;
                    existing.isLast = tc.isLast;
                }
                else {
                    toolCallsMap.set(tc.id, {
                        ...tc,
                        index: toolCallsMap.size,
                    });
                }
                if (tc.isLast) {
                    const finalToolCall = toolCallsMap.get(tc.id);
                    if (!finalToolCall)
                        continue;
                    toolCalls.push({
                        id: finalToolCall.id,
                        type: finalToolCall.type,
                        function: {
                            name: finalToolCall.function.name,
                            arguments: finalToolCall.function.arguments,
                        },
                    });
                }
            }
            if (frame.type === 'text') {
                totalContent += frame.text;
            }
            if (frame.type === 'thinking') {
                totalReasoning += frame.text;
            }
        }
        // Finalize remaining tool calls
        for (const id of Array.from(toolCallsMap.keys())) {
            const tc = toolCallsMap.get(id);
            if (!tc)
                continue;
            if (!toolCalls.find((t) => t.id === id)) {
                toolCalls.push({
                    id: tc.id,
                    type: tc.type,
                    function: {
                        name: tc.function.name,
                        arguments: tc.function.arguments,
                    },
                });
            }
        }
        const message = {
            role: 'assistant',
            content: totalContent || null,
        };
        if (toolCalls.length > 0) {
            message.tool_calls = toolCalls;
        }
        if (totalReasoning) {
            message.reasoning_content = totalReasoning;
        }
        const completion = {
            id: responseId,
            object: 'chat.completion',
            created,
            model,
            choices: [
                {
                    index: 0,
                    message,
                    finish_reason: toolCalls.length > 0 ? 'tool_calls' : 'stop',
                },
            ],
            usage: {
                prompt_tokens: 0,
                completion_tokens: 0,
                total_tokens: 0,
            },
        };
        return new Response(JSON.stringify(completion), {
            status: 200,
            headers: { 'Content-Type': 'application/json' },
        });
    }
    /** @deprecated Use executeStreaming() for real-time SSE. Retained for fetch fallback. */
    transformProtobufToSSE(buffer, model, _body) {
        const responseId = `chatcmpl-cursor-${Date.now()}`;
        const created = Math.floor(Date.now() / 1000);
        const chunks = [];
        const toolCalls = [];
        const toolCallsMap = new Map();
        for (const frame of this.parseProtobufFrames(buffer)) {
            if (frame.type === 'error') {
                if (chunks.length === 0 && toolCalls.length === 0) {
                    return createCursorErrorResponse(frame.error);
                }
                chunks.push(`event: error\ndata: ${buildCursorErrorEnvelope(frame.error)}\n\n`);
                return new Response(chunks.join(''), {
                    status: 200,
                    headers: {
                        'Content-Type': 'text/event-stream',
                        'Cache-Control': 'no-cache',
                        Connection: 'keep-alive',
                    },
                });
            }
            if (frame.type === 'toolCall') {
                const tc = frame.toolCall;
                if (chunks.length === 0) {
                    chunks.push(`data: ${JSON.stringify({
                        id: responseId,
                        object: 'chat.completion.chunk',
                        created,
                        model,
                        choices: [
                            {
                                index: 0,
                                delta: { role: 'assistant', content: '' },
                                finish_reason: null,
                            },
                        ],
                    })}\n\n`);
                }
                if (toolCallsMap.has(tc.id)) {
                    const existing = toolCallsMap.get(tc.id);
                    if (!existing)
                        continue;
                    existing.function.arguments += tc.function.arguments;
                    existing.isLast = tc.isLast;
                    if (tc.function.arguments) {
                        chunks.push(`data: ${JSON.stringify({
                            id: responseId,
                            object: 'chat.completion.chunk',
                            created,
                            model,
                            choices: [
                                {
                                    index: 0,
                                    delta: {
                                        tool_calls: [
                                            {
                                                index: existing.index,
                                                id: tc.id,
                                                type: 'function',
                                                function: {
                                                    name: tc.function.name,
                                                    arguments: tc.function.arguments,
                                                },
                                            },
                                        ],
                                    },
                                    finish_reason: null,
                                },
                            ],
                        })}\n\n`);
                    }
                }
                else {
                    const toolCallIndex = toolCalls.length;
                    toolCalls.push({ ...tc, index: toolCallIndex });
                    toolCallsMap.set(tc.id, { ...tc, index: toolCallIndex });
                    chunks.push(`data: ${JSON.stringify({
                        id: responseId,
                        object: 'chat.completion.chunk',
                        created,
                        model,
                        choices: [
                            {
                                index: 0,
                                delta: {
                                    tool_calls: [
                                        {
                                            index: toolCallIndex,
                                            id: tc.id,
                                            type: 'function',
                                            function: {
                                                name: tc.function.name,
                                                arguments: tc.function.arguments,
                                            },
                                        },
                                    ],
                                },
                                finish_reason: null,
                            },
                        ],
                    })}\n\n`);
                }
            }
            if (frame.type === 'text') {
                chunks.push(`data: ${JSON.stringify({
                    id: responseId,
                    object: 'chat.completion.chunk',
                    created,
                    model,
                    choices: [
                        {
                            index: 0,
                            delta: chunks.length === 0 && toolCalls.length === 0
                                ? { role: 'assistant', content: frame.text }
                                : { content: frame.text },
                            finish_reason: null,
                        },
                    ],
                })}\n\n`);
            }
            if (frame.type === 'thinking') {
                chunks.push(`data: ${JSON.stringify({
                    id: responseId,
                    object: 'chat.completion.chunk',
                    created,
                    model,
                    choices: [
                        {
                            index: 0,
                            delta: chunks.length === 0 && toolCalls.length === 0
                                ? { role: 'assistant', reasoning_content: frame.text }
                                : { reasoning_content: frame.text },
                            finish_reason: null,
                        },
                    ],
                })}\n\n`);
            }
        }
        if (chunks.length === 0 && toolCalls.length === 0) {
            chunks.push(`data: ${JSON.stringify({
                id: responseId,
                object: 'chat.completion.chunk',
                created,
                model,
                choices: [
                    {
                        index: 0,
                        delta: { role: 'assistant', content: '' },
                        finish_reason: null,
                    },
                ],
            })}\n\n`);
        }
        chunks.push(`data: ${JSON.stringify({
            id: responseId,
            object: 'chat.completion.chunk',
            created,
            model,
            choices: [
                {
                    index: 0,
                    delta: {},
                    finish_reason: toolCalls.length > 0 ? 'tool_calls' : 'stop',
                },
            ],
            usage: {
                prompt_tokens: 0,
                completion_tokens: 0,
                total_tokens: 0,
            },
        })}\n\n`);
        chunks.push('data: [DONE]\n\n');
        return new Response(chunks.join(''), {
            status: 200,
            headers: {
                'Content-Type': 'text/event-stream',
                'Cache-Control': 'no-cache',
                Connection: 'keep-alive',
            },
        });
    }
}
exports.CursorExecutor = CursorExecutor;
exports.default = CursorExecutor;
//# sourceMappingURL=cursor-executor.js.map