Files
OmniRoute/open-sse/executors/cursor.ts
diegosouzapw 4ae488b25b feat(runtime): add hot-reloadable guardrails and model diagnostics
Introduce a runtime settings layer that hydrates persisted config at startup
and reapplies aliases, payload rules, cache behavior, CLI compatibility,
usage tuning, and related switches when settings change or SQLite updates.

Replace the legacy prompt injection middleware path with a guardrail
registry that supports prompt injection detection, PII masking, disabled
guardrail overrides, and post-call response handling across the chat
pipeline.

Add a metadata registry for model catalog and alias resolution so catalog
endpoints return enriched capabilities plus diagnostic headers and typed
alias errors instead of ad hoc responses.

Convert unsupported built-in web_search tools into an OmniRoute fallback
tool, execute them through builtin skills, and preserve Responses API
function call output with sanitized usage fields.

Centralize provider header fingerprints for GitHub, Cursor, Qwen, Qoder,
Kiro, and Antigravity, and migrate management passwords from env or
plaintext storage into persisted bcrypt hashes during startup and login.
2026-04-17 11:56:52 -03:00

911 lines
28 KiB
TypeScript

declare const EdgeRuntime: string | undefined;
/**
* CursorExecutor — Handles communication with the Cursor IDE API.
*
* This executor is the most complex due to Cursor's non-standard protocol:
*
* SECTION 1: Authentication (generateChecksum)
* - SHA-256 based checksum using machine ID and timestamp
* - WorkOS token refresh for session management
*
* SECTION 2: Request Encoding (transformRequest, buildHeaders)
* - ConnectRPC Protobuf binary encoding via cursorProtobuf.js
* - Chat body construction with model routing
*
* SECTION 3: Response Parsing (executeStream, parseEvent*)
* - Binary EventStream → SSE text conversion
* - Gzip decompression of response frames
* - HTTP/2 support with h2 fallback to fetch
*
* @see cursorProtobuf.js for Protobuf encoding/decoding utilities
*/
import { BaseExecutor, mergeUpstreamExtraHeaders } from "./base.ts";
import { getCursorUserAgent } from "../config/providerHeaderProfiles.ts";
import { PROVIDERS, HTTP_STATUS } from "../config/constants.ts";
import {
generateCursorBody,
parseConnectRPCFrame,
extractTextFromResponse,
} from "../utils/cursorProtobuf.ts";
import { estimateUsage } from "../utils/usageTracking.ts";
import { getCursorVersion } from "../utils/cursorVersionDetector.ts";
import { FORMATS } from "../translator/formats.ts";
import crypto from "crypto";
import { v5 as uuidv5 } from "uuid";
import zlib from "zlib";
// Detect cloud environment
const isCloudEnv = () => {
if (typeof caches !== "undefined" && typeof caches === "object") return true;
if (typeof EdgeRuntime !== "undefined") return true;
return false;
};
// Lazy import http2 (only in Node.js environment)
let http2 = null;
if (!isCloudEnv()) {
try {
http2 = await import("http2");
} catch {
// http2 not available
}
}
// --- SECTION 1: Authentication Constants ---
const COMPRESS_FLAG = {
NONE: 0x00,
GZIP: 0x01,
GZIP_ALT: 0x02,
GZIP_BOTH: 0x03,
};
const CURSOR_STREAM_DEBUG = process.env.CURSOR_STREAM_DEBUG === "1";
const debugLog = (...args: unknown[]) => {
if (CURSOR_STREAM_DEBUG) console.log(...args);
};
function decompressPayload(payload, flags) {
// Check if payload is JSON error (starts with {"error")
if (payload.length > 10 && payload[0] === 0x7b && payload[1] === 0x22) {
try {
const text = payload.toString("utf-8");
if (text.startsWith('{"error"')) {
debugLog(`[DECOMPRESS] Detected JSON error, skipping decompression`);
return payload;
}
} catch {}
}
if (
flags === COMPRESS_FLAG.GZIP ||
flags === COMPRESS_FLAG.GZIP_ALT ||
flags === COMPRESS_FLAG.GZIP_BOTH
) {
// Primary: try gzip decompression (standard gzip header 0x1f 0x8b)
try {
return zlib.gunzipSync(payload);
} catch (gzipErr) {
// Fallback: GZIP_ALT (0x02) and GZIP_BOTH (0x03) frames sometimes use
// raw zlib deflate format instead of gzip wrapping (#250)
try {
return zlib.inflateSync(payload);
} catch (deflateErr) {
// Last resort: try raw deflate (no zlib header)
try {
return zlib.inflateRawSync(payload);
} catch (rawErr) {
debugLog(
`[DECOMPRESS ERROR] flags=${flags}, payloadSize=${payload.length}, gzip=${gzipErr.message}, deflate=${deflateErr.message}, raw=${rawErr.message}`
);
debugLog(
`[DECOMPRESS ERROR] First 50 bytes (hex):`,
payload.slice(0, 50).toString("hex")
);
debugLog(
`[DECOMPRESS ERROR] First 50 bytes (utf8):`,
payload
.slice(0, 50)
.toString("utf8")
.replace(/[^\x20-\x7E]/g, ".")
);
// Try to use payload as-is if all decompression methods fail
return payload;
}
}
}
}
return payload;
}
function createErrorResponse(jsonError) {
const errorMsg =
jsonError?.error?.details?.[0]?.debug?.details?.title ||
jsonError?.error?.details?.[0]?.debug?.details?.detail ||
jsonError?.error?.message ||
"API Error";
const isRateLimit = jsonError?.error?.code === "resource_exhausted";
return new Response(
JSON.stringify({
error: {
message: errorMsg,
type: isRateLimit ? "rate_limit_error" : "api_error",
code: jsonError?.error?.details?.[0]?.debug?.error || "unknown",
},
}),
{
status: isRateLimit ? HTTP_STATUS.RATE_LIMITED : HTTP_STATUS.BAD_REQUEST,
headers: { "Content-Type": "application/json" },
}
);
}
function parseCursorJsonErrorFrame(text: string) {
try {
return JSON.parse(text);
} catch {
return null;
}
}
function isToolBoundaryAbort(jsonError: unknown, toolCallCount: number) {
if (!jsonError || toolCallCount <= 0) return false;
const e = jsonError as Record<string, unknown>;
const err = e?.error as Record<string, unknown> | undefined;
const details = (err?.details as Record<string, unknown>[] | undefined)?.[0];
const debug = details?.debug as Record<string, unknown> | undefined;
const debugDetails = debug?.details as Record<string, unknown> | undefined;
const code = (err?.code as string) || "";
const debugError = (debug?.error as string) || "";
const title = (debugDetails?.title as string) || "";
const detail = (debugDetails?.detail as string) || "";
const message = `${title} ${detail}`.toLowerCase();
const isAbortedCode = code === "aborted" || debugError === "ERROR_USER_ABORTED_REQUEST";
return isAbortedCode && message.includes("tool call ended before result was received");
}
function mergeToolCallDelta(existing, incoming) {
const mergedName = incoming?.function?.name || existing?.function?.name || "";
const existingArgs = existing?.function?.arguments || "";
const deltaArgs = incoming?.function?.arguments || "";
return {
id: incoming.id || existing.id,
type: "function",
function: {
name: mergedName,
arguments: `${existingArgs}${deltaArgs}`,
},
isLast: Boolean(existing?.isLast || incoming?.isLast),
index: existing?.index ?? incoming?.index ?? 0,
};
}
type CursorHttpResponse = {
status: number;
headers: Record<string, unknown>;
body: Buffer;
};
export class CursorExecutor extends BaseExecutor {
constructor() {
super("cursor", PROVIDERS.cursor);
}
buildUrl() {
return `${this.config.baseUrl}${this.config.chatPath || ""}`;
}
// Jyh cipher checksum for Cursor API authentication
generateChecksum(machineId) {
const timestamp = Math.floor(Date.now() / 1000000);
const byteArray = new Uint8Array([
(timestamp >> 40) & 0xff,
(timestamp >> 32) & 0xff,
(timestamp >> 24) & 0xff,
(timestamp >> 16) & 0xff,
(timestamp >> 8) & 0xff,
timestamp & 0xff,
]);
let t = 165;
for (let i = 0; i < byteArray.length; i++) {
byteArray[i] = ((byteArray[i] ^ t) + (i % 256)) & 0xff;
t = byteArray[i];
}
const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
let encoded = "";
for (let i = 0; i < byteArray.length; i += 3) {
const a = byteArray[i];
const b = i + 1 < byteArray.length ? byteArray[i + 1] : 0;
const c = i + 2 < byteArray.length ? byteArray[i + 2] : 0;
encoded += alphabet[a >> 2];
encoded += alphabet[((a & 3) << 4) | (b >> 4)];
if (i + 1 < byteArray.length) {
encoded += alphabet[((b & 15) << 2) | (c >> 6)];
}
if (i + 2 < byteArray.length) {
encoded += alphabet[c & 63];
}
}
return `${encoded}${machineId}`;
}
buildHeaders(credentials) {
const accessToken = credentials.accessToken;
const ghostMode = credentials.providerSpecificData?.ghostMode !== false;
// Use stored machineId, or derive a stable one from the access token
// (cursor-agent imports don't provide a machineId)
const machineId =
credentials.providerSpecificData?.machineId ||
crypto.createHash("sha256").update(accessToken).digest("hex");
const cleanToken = accessToken.includes("::") ? accessToken.split("::")[1] : accessToken;
return {
authorization: `Bearer ${cleanToken}`,
"connect-accept-encoding": "gzip",
"connect-protocol-version": "1",
"content-type": "application/connect+proto",
"user-agent": getCursorUserAgent(getCursorVersion()),
"x-amzn-trace-id": `Root=${crypto.randomUUID()}`,
"x-client-key": crypto.createHash("sha256").update(cleanToken).digest("hex"),
"x-cursor-checksum": this.generateChecksum(machineId),
"x-cursor-client-version": getCursorVersion(),
"x-cursor-client-type": "ide",
"x-cursor-client-os":
process.platform === "win32"
? "windows"
: process.platform === "darwin"
? "macos"
: "linux",
"x-cursor-client-arch": process.arch === "arm64" ? "aarch64" : "x64",
"x-cursor-client-device-type": "desktop",
"x-cursor-user-agent": getCursorUserAgent(getCursorVersion()),
"x-cursor-config-version": crypto.randomUUID(),
"x-cursor-timezone": Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC",
"x-ghost-mode": ghostMode ? "true" : "false",
"x-request-id": crypto.randomUUID(),
"x-session-id": uuidv5(cleanToken, uuidv5.DNS),
};
}
transformRequest(model, body, stream, credentials) {
// Messages are already translated by chatCore (claude→openai→cursor)
// Do NOT call buildCursorRequest again — double-translation drops tool_results
const messages = body.messages || [];
const tools = body.tools || [];
const reasoningEffort = body.reasoning_effort || null;
return generateCursorBody(messages, model, tools, reasoningEffort);
}
async makeFetchRequest(
url: string,
headers: Record<string, string>,
body: Uint8Array,
signal?: AbortSignal
): Promise<CursorHttpResponse> {
const response = await fetch(url, {
method: "POST",
headers,
body: body as unknown as BodyInit,
signal,
});
return {
status: response.status,
headers: Object.fromEntries(response.headers.entries()),
body: Buffer.from(await response.arrayBuffer()),
};
}
makeHttp2Request(
url: string,
headers: Record<string, string>,
body: Uint8Array,
signal?: AbortSignal
): Promise<CursorHttpResponse> {
if (!http2) {
throw new Error("http2 module not available");
}
return new Promise<CursorHttpResponse>((resolve, reject) => {
const urlObj = new URL(url);
const client = http2.connect(`https://${urlObj.host}`);
const chunks = [];
let responseHeaders = {};
client.on("error", reject);
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:
typeof responseHeaders[":status"] === "number"
? responseHeaders[":status"]
: Number(responseHeaders[":status"] || HTTP_STATUS.SERVER_ERROR),
headers: responseHeaders,
body: Buffer.concat(chunks),
});
});
req.on("error", (err) => {
client.close();
reject(err);
});
if (signal) {
signal.addEventListener("abort", () => {
req.close();
client.close();
reject(new Error("Request aborted"));
});
}
req.write(body);
req.end();
});
}
async execute({ model, body, stream, credentials, signal, log, upstreamExtraHeaders }) {
const url = this.buildUrl();
const headers = this.buildHeaders(credentials);
mergeUpstreamExtraHeaders(headers, upstreamExtraHeaders);
const transformedBody = await this.transformRequest(model, body, stream, credentials);
try {
const response: CursorHttpResponse = 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";
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 =
stream !== false
? this.transformProtobufToSSE(response.body, model, body)
: this.transformProtobufToJSON(response.body, model, body);
return { response: transformedResponse, url, headers, transformedBody: body };
} catch (error) {
const errorResponse = new Response(
JSON.stringify({
error: {
message: error.message,
type: "connection_error",
code: "",
},
}),
{
status: HTTP_STATUS.SERVER_ERROR,
headers: { "Content-Type": "application/json" },
}
);
return { response: errorResponse, url, headers, transformedBody: body };
}
}
transformProtobufToJSON(buffer, model, body) {
const responseId = `chatcmpl-cursor-${Date.now()}`;
const created = Math.floor(Date.now() / 1000);
let offset = 0;
let totalContent = "";
const toolCalls = [];
const toolCallsMap = new Map(); // Track streaming tool calls by ID
const finalizedIds = new Set<string>();
let frameCount = 0;
debugLog(`[CURSOR BUFFER] Total length: ${buffer.length} bytes`);
while (offset < buffer.length) {
if (offset + 5 > buffer.length) {
debugLog(
`[CURSOR BUFFER] Reached end, offset=${offset}, remaining=${buffer.length - offset}`
);
break;
}
const flags = buffer[offset];
const length = buffer.readUInt32BE(offset + 1);
debugLog(
`[CURSOR BUFFER] Frame ${frameCount + 1}: flags=0x${flags.toString(16).padStart(2, "0")}, length=${length}`
);
if (offset + 5 + length > buffer.length) {
debugLog(
`[CURSOR BUFFER] Incomplete frame, offset=${offset}, length=${length}, buffer.length=${buffer.length}`
);
break;
}
let payload = buffer.slice(offset + 5, offset + 5 + length);
offset += 5 + length;
frameCount++;
payload = decompressPayload(payload, flags);
if (!payload) {
debugLog(`[CURSOR BUFFER] Frame ${frameCount}: decompression failed, skipping`);
continue;
}
// Check for JSON error frames (byte guard: skip toString on non-JSON frames)
if (payload.length > 0 && payload[0] === 0x7b) {
try {
const text = payload.toString("utf-8");
if (text.includes('"error"')) {
const hasContent = totalContent || toolCallsMap.size > 0;
debugLog(
`[CURSOR BUFFER] Error frame (hasContent=${hasContent}): ${text.slice(0, 500)}`
);
if (hasContent) {
break;
}
return createErrorResponse(JSON.parse(text));
}
} catch {}
}
const result = extractTextFromResponse(new Uint8Array(payload));
debugLog(`[CURSOR DECODED] Frame ${frameCount}:`, result);
if (result.error) {
const hasContent = totalContent || toolCallsMap.size > 0;
debugLog(`[CURSOR BUFFER] Decoded error (hasContent=${hasContent}): ${result.error}`);
// If we already have content, treat error as stream termination
if (hasContent) {
break;
}
return new Response(
JSON.stringify({
error: {
message: result.error,
type: "rate_limit_error",
code: "rate_limited",
},
}),
{
status: HTTP_STATUS.RATE_LIMITED,
headers: { "Content-Type": "application/json" },
}
);
}
if (result.toolCall) {
const tc = result.toolCall;
if (toolCallsMap.has(tc.id)) {
// Accumulate arguments for existing tool call
const existing = toolCallsMap.get(tc.id);
existing.function.arguments += tc.function.arguments;
existing.isLast = tc.isLast;
} else {
// New tool call
toolCallsMap.set(tc.id, { ...tc });
}
// Push to final array when isLast is true
if (tc.isLast) {
const finalToolCall = toolCallsMap.get(tc.id);
finalizedIds.add(tc.id);
toolCalls.push({
id: finalToolCall.id,
type: finalToolCall.type,
function: {
name: finalToolCall.function.name,
arguments: finalToolCall.function.arguments,
},
});
}
}
if (result.text) totalContent += result.text;
}
debugLog(
`[CURSOR BUFFER] Parsed ${frameCount} frames, toolCallsMap size: ${toolCallsMap.size}, finalized toolCalls: ${toolCalls.length}`
);
// Finalize all remaining tool calls in map (in case stream ended without isLast=true)
for (const [id, tc] of toolCallsMap.entries()) {
// Check if already in final array
if (!finalizedIds.has(id)) {
debugLog(`[CURSOR BUFFER] Finalizing incomplete tool call: ${id}, isLast=${tc.isLast}`);
toolCalls.push({
id: tc.id,
type: tc.type,
function: {
name: tc.function.name,
arguments: tc.function.arguments,
},
});
}
}
debugLog(`[CURSOR BUFFER] Final toolCalls count: ${toolCalls.length}`);
const message: Record<string, unknown> = {
role: "assistant",
content: totalContent || null,
};
if (toolCalls.length > 0) {
message.tool_calls = toolCalls;
}
const usage = estimateUsage(body, totalContent.length, FORMATS.OPENAI);
const completion = {
id: responseId,
object: "chat.completion",
created,
model,
choices: [
{
index: 0,
message,
finish_reason: toolCalls.length > 0 ? "tool_calls" : "stop",
},
],
usage,
};
return new Response(JSON.stringify(completion), {
status: 200,
headers: { "Content-Type": "application/json" },
});
}
transformProtobufToSSE(buffer, model, body) {
const responseId = `chatcmpl-cursor-${Date.now()}`;
const created = Math.floor(Date.now() / 1000);
const chunks = [];
let offset = 0;
let totalContent = "";
const toolCalls = [];
const toolCallsMap = new Map(); // Track streaming tool calls by ID
const finalizedIds = new Set<string>();
const emittedToolCallIds = new Set<string>();
let frameCount = 0;
debugLog(`[CURSOR BUFFER SSE] Total length: ${buffer.length} bytes`);
while (offset < buffer.length) {
if (offset + 5 > buffer.length) {
debugLog(
`[CURSOR BUFFER SSE] Reached end, offset=${offset}, remaining=${buffer.length - offset}`
);
break;
}
const flags = buffer[offset];
const length = buffer.readUInt32BE(offset + 1);
debugLog(
`[CURSOR BUFFER SSE] Frame ${frameCount + 1}: flags=0x${flags.toString(16).padStart(2, "0")}, length=${length}`
);
if (offset + 5 + length > buffer.length) {
debugLog(
`[CURSOR BUFFER SSE] Incomplete frame, offset=${offset}, length=${length}, buffer.length=${buffer.length}`
);
break;
}
let payload = buffer.slice(offset + 5, offset + 5 + length);
offset += 5 + length;
frameCount++;
payload = decompressPayload(payload, flags);
if (!payload) {
debugLog(`[CURSOR BUFFER SSE] Frame ${frameCount}: decompression failed, skipping`);
continue;
}
// Check for JSON error frames (byte-guard: only decode if starts with '{')
if (payload[0] === 0x7b) {
try {
const text = payload.toString("utf-8");
if (text.includes('"error"')) {
const hasContent = chunks.length > 0 || totalContent || toolCallsMap.size > 0;
debugLog(
`[CURSOR BUFFER SSE] Error frame (hasContent=${hasContent}): ${text.slice(0, 500)}`
);
if (hasContent) {
break;
}
return createErrorResponse(JSON.parse(text));
}
} catch {}
}
const result = extractTextFromResponse(new Uint8Array(payload));
debugLog(`[CURSOR DECODED SSE] Frame ${frameCount}:`, result);
if (result.error) {
const hasContent = chunks.length > 0 || totalContent || toolCallsMap.size > 0;
debugLog(`[CURSOR BUFFER SSE] Decoded error (hasContent=${hasContent}): ${result.error}`);
// If we already have content, treat error as stream termination
if (hasContent) {
break;
}
return new Response(
JSON.stringify({
error: {
message: result.error,
type: "rate_limit_error",
code: "rate_limited",
},
}),
{
status: HTTP_STATUS.RATE_LIMITED,
headers: { "Content-Type": "application/json" },
}
);
}
if (result.toolCall) {
const tc = result.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)) {
// Accumulate arguments for existing tool call
const existing = toolCallsMap.get(tc.id);
const oldArgsLen = existing.function.arguments.length;
existing.function.arguments += tc.function.arguments;
existing.isLast = tc.isLast;
// Stream the delta arguments
if (tc.function.arguments) {
emittedToolCallIds.add(tc.id);
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 {
// New tool call - assign index and add to map
const toolCallIndex = toolCalls.length;
finalizedIds.add(tc.id);
toolCalls.push({ ...tc, index: toolCallIndex });
toolCallsMap.set(tc.id, { ...tc, index: toolCallIndex });
// Stream initial tool call with name
emittedToolCallIds.add(tc.id);
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 (result.text) {
totalContent += result.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: result.text }
: { content: result.text },
finish_reason: null,
},
],
})}\n\n`
);
}
}
debugLog(
`[CURSOR BUFFER SSE] Parsed ${frameCount} frames, toolCallsMap size: ${toolCallsMap.size}, toolCalls array: ${toolCalls.length}`
);
// Finalize all remaining tool calls in map (stream may have ended without isLast=true)
for (const [id, tc] of toolCallsMap.entries()) {
if (!finalizedIds.has(id)) {
debugLog(`[CURSOR BUFFER SSE] Finalizing incomplete tool call: ${id}, isLast=${tc.isLast}`);
const toolCallIndex = toolCalls.length;
toolCalls.push({
id: tc.id,
type: tc.type,
index: toolCallIndex,
function: {
name: tc.function.name,
arguments: tc.function.arguments,
},
});
// Emit SSE chunk for the finalized tool call if not already emitted
if (!emittedToolCallIds.has(tc.id)) {
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 (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`
);
}
const usage = estimateUsage(body, totalContent.length, FORMATS.OPENAI);
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,
})}\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",
},
});
}
async refreshCredentials() {
return null;
}
}
export default CursorExecutor;