Files
OmniRoute/tests/unit/executor-cursor-extended.test.ts
2026-04-21 21:12:29 -03:00

550 lines
18 KiB
TypeScript

import test from "node:test";
import assert from "node:assert/strict";
import { CursorExecutor } from "../../open-sse/executors/cursor.ts";
import {
decodeMessage,
encodeField,
parseConnectRPCFrame,
wrapConnectRPCFrame,
} from "../../open-sse/utils/cursorProtobuf.ts";
import {
buildCursorHeaders,
generateCursorChecksum,
generateHashed64Hex,
generateSessionId,
} from "../../open-sse/utils/cursorChecksum.ts";
import {
getCursorVersion,
resetCursorVersionCache,
} from "../../open-sse/utils/cursorVersionDetector.ts";
const LEN = 2;
const VARINT = 0;
const TOP_LEVEL_TOOL_CALL = 1;
const TOP_LEVEL_RESPONSE = 2;
const RESPONSE_TEXT = 1;
const TOOL_ID = 3;
const TOOL_NAME = 9;
const TOOL_RAW_ARGS = 10;
const TOOL_IS_LAST = 11;
function concatArrays(...arrays) {
const total = arrays.reduce((sum, array) => sum + array.length, 0);
const result = new Uint8Array(total);
let offset = 0;
for (const array of arrays) {
result.set(array, offset);
offset += array.length;
}
return result;
}
function buildTextFrame(text) {
return Buffer.from(
wrapConnectRPCFrame(
encodeField(TOP_LEVEL_RESPONSE, LEN, encodeField(RESPONSE_TEXT, LEN, text)),
false
)
);
}
function buildCompressedTextFrame(text) {
return Buffer.from(
wrapConnectRPCFrame(
encodeField(TOP_LEVEL_RESPONSE, LEN, encodeField(RESPONSE_TEXT, LEN, text)),
true
)
);
}
function buildToolCallFrame({ id, name, args, isLast }) {
return Buffer.from(
wrapConnectRPCFrame(
encodeField(
TOP_LEVEL_TOOL_CALL,
LEN,
concatArrays(
encodeField(TOOL_ID, LEN, id),
encodeField(TOOL_NAME, LEN, name),
encodeField(TOOL_RAW_ARGS, LEN, args),
encodeField(TOOL_IS_LAST, VARINT, isLast ? 1 : 0)
)
),
false
)
);
}
function buildJsonErrorFrame(error) {
return Buffer.from(wrapConnectRPCFrame(new TextEncoder().encode(JSON.stringify(error)), false));
}
test("CursorExecutor.buildUrl uses the configured Cursor endpoint", () => {
const executor = new CursorExecutor();
assert.equal(
executor.buildUrl(),
"https://api2.cursor.sh/aiserver.v1.ChatService/StreamUnifiedChatWithTools"
);
});
test("CursorExecutor.buildHeaders strips token prefixes and derives checksum/session headers", () => {
const executor = new CursorExecutor();
const originalDateNow = Date.now;
const originalDbPath = process.env.CURSOR_STATE_DB_PATH;
// Force fallback by pointing to a non-existent DB path
process.env.CURSOR_STATE_DB_PATH = "/nonexistent/cursor/state.vscdb";
resetCursorVersionCache();
Date.now = () => 1_700_000_000_000;
try {
const headers = executor.buildHeaders({
accessToken: "prefix::real-token",
providerSpecificData: { machineId: "machine-1", ghostMode: false },
});
const expectedVersion = getCursorVersion();
assert.equal(headers.authorization, "Bearer real-token");
assert.equal(headers["x-client-key"], generateHashed64Hex("real-token"));
assert.equal(headers["x-session-id"], generateSessionId("real-token"));
assert.equal(headers["x-cursor-checksum"], generateCursorChecksum("machine-1"));
assert.equal(headers["x-cursor-client-version"], expectedVersion);
assert.equal(headers["x-cursor-user-agent"], `Cursor/${expectedVersion}`);
assert.equal(headers["user-agent"], `Cursor/${expectedVersion}`);
assert.equal(headers["x-ghost-mode"], "false");
assert.equal(headers["connect-protocol-version"], "1");
assert.match(headers["x-amzn-trace-id"], /^Root=/);
assert.ok(headers["x-request-id"]);
} finally {
Date.now = originalDateNow;
if (originalDbPath === undefined) {
delete process.env.CURSOR_STATE_DB_PATH;
} else {
process.env.CURSOR_STATE_DB_PATH = originalDbPath;
}
resetCursorVersionCache();
}
});
test("buildCursorHeaders utility stays aligned with Cursor Composer 2 versioned headers", () => {
const originalDbPath = process.env.CURSOR_STATE_DB_PATH;
process.env.CURSOR_STATE_DB_PATH = "/nonexistent/cursor/state.vscdb";
resetCursorVersionCache();
try {
const headers = buildCursorHeaders("prefix::real-token", "machine-1", false);
const expectedVersion = getCursorVersion();
assert.equal(headers.Authorization, "Bearer real-token");
assert.equal(headers["x-cursor-client-version"], expectedVersion);
assert.equal(headers["x-cursor-user-agent"], `Cursor/${expectedVersion}`);
assert.equal(headers["User-Agent"], `Cursor/${expectedVersion}`);
assert.equal(headers["x-ghost-mode"], "false");
} finally {
if (originalDbPath === undefined) {
delete process.env.CURSOR_STATE_DB_PATH;
} else {
process.env.CURSOR_STATE_DB_PATH = originalDbPath;
}
resetCursorVersionCache();
}
});
test("CursorExecutor.buildHeaders derives machineId when not provided", () => {
const executor = new CursorExecutor();
const headers = executor.buildHeaders({ accessToken: "real-token", providerSpecificData: {} });
assert.ok(headers["x-cursor-checksum"], "should have a checksum header");
assert.ok(headers["x-client-key"], "should have a client key header");
});
test("CursorExecutor.transformRequest produces a framed protobuf payload", () => {
const executor = new CursorExecutor();
const transformed = executor.transformRequest(
"claude-3.5-sonnet",
{ messages: [{ role: "user", content: "Hello" }], tools: [] },
true,
{}
);
const frame = parseConnectRPCFrame(transformed);
const fields = decodeMessage(frame.payload);
assert.ok(transformed instanceof Uint8Array);
assert.equal(frame.flags, 0);
assert.equal(frame.consumed, transformed.length);
assert.equal(fields.has(1), true);
});
test("CursorExecutor.transformProtobufToJSON aggregates text and split tool call arguments", async () => {
const executor = new CursorExecutor();
const body = { messages: [{ role: "user", content: "hi" }] };
const buffer = Buffer.concat([
buildTextFrame("Hello "),
buildToolCallFrame({
id: "call_1",
name: "read_file",
args: '{"path":',
isLast: false,
}),
buildToolCallFrame({
id: "call_1",
name: "read_file",
args: '"/tmp/a"}',
isLast: true,
}),
]);
const response = executor.transformProtobufToJSON(buffer, "cursor-small", body);
const payload = (await response.json()) as any;
assert.equal(response.status, 200);
assert.equal(payload.object, "chat.completion");
assert.equal(payload.model, "cursor-small");
assert.equal(payload.choices[0].message.content, "Hello ");
assert.equal(payload.choices[0].finish_reason, "tool_calls");
assert.equal(payload.choices[0].message.tool_calls[0].function.name, "read_file");
assert.equal(payload.choices[0].message.tool_calls[0].function.arguments, '{"path":"/tmp/a"}');
assert.equal(payload.usage.estimated, true);
});
test("CursorExecutor.transformProtobufToJSON finalizes incomplete tool calls when the stream ends early", async () => {
const executor = new CursorExecutor();
const response = executor.transformProtobufToJSON(
Buffer.concat([
buildToolCallFrame({
id: "call_2",
name: "list_files",
args: '{"path":"/tmp"}',
isLast: false,
}),
]),
"cursor-small",
{ messages: [{ role: "user", content: "hi" }] }
);
const payload = (await response.json()) as any;
assert.equal(payload.choices[0].finish_reason, "tool_calls");
assert.equal(payload.choices[0].message.tool_calls[0].id, "call_2");
assert.equal(payload.choices[0].message.tool_calls[0].function.name, "list_files");
});
test("CursorExecutor.transformProtobufToJSON keeps prior content when an error frame arrives after output", async () => {
const executor = new CursorExecutor();
const response = executor.transformProtobufToJSON(
Buffer.concat([
buildTextFrame("Partial answer"),
buildJsonErrorFrame({
error: {
code: "resource_exhausted",
message: "late error",
},
}),
]),
"cursor-small",
{ messages: [{ role: "user", content: "hi" }] }
);
const payload = (await response.json()) as any;
assert.equal(response.status, 200);
assert.equal(payload.choices[0].message.content, "Partial answer");
assert.equal(payload.choices[0].finish_reason, "stop");
});
test("CursorExecutor.transformProtobufToJSON decompresses gzip frames", async () => {
const executor = new CursorExecutor();
const response = executor.transformProtobufToJSON(
Buffer.concat([buildCompressedTextFrame("Compressed answer")]),
"cursor-small",
{ messages: [{ role: "user", content: "hi" }] }
);
const payload = (await response.json()) as any;
assert.equal(payload.choices[0].message.content, "Compressed answer");
});
test("CursorExecutor.transformProtobufToSSE emits assistant chunks, tool deltas and DONE marker", async () => {
const executor = new CursorExecutor();
const body = { messages: [{ role: "user", content: "hi" }] };
const buffer = Buffer.concat([
buildTextFrame("Hello "),
buildToolCallFrame({
id: "call_1",
name: "read_file",
args: '{"path":',
isLast: false,
}),
buildToolCallFrame({
id: "call_1",
name: "read_file",
args: '"/tmp/a"}',
isLast: true,
}),
]);
const response = executor.transformProtobufToSSE(buffer, "cursor-small", body);
const text = await response.text();
assert.equal(response.status, 200);
assert.equal(response.headers.get("Content-Type"), "text/event-stream");
assert.match(text, /"role":"assistant","content":"Hello "/);
assert.match(text, /"tool_calls":\[/);
assert.match(text, /"name":"read_file"/);
assert.match(text, /"finish_reason":"tool_calls"/);
assert.match(text, /\[DONE\]/);
});
test("CursorExecutor.transformProtobufToSSE finalizes unterminated tool calls at stream end", async () => {
const executor = new CursorExecutor();
const response = executor.transformProtobufToSSE(
Buffer.concat([
buildToolCallFrame({
id: "call_2",
name: "read_file",
args: '{"path":"/tmp/b"}',
isLast: false,
}),
]),
"cursor-small",
{ messages: [{ role: "user", content: "hi" }] }
);
const text = await response.text();
assert.match(text, /"name":"read_file"/);
assert.match(text, /"finish_reason":"tool_calls"/);
assert.match(text, /\[DONE\]/);
});
test("CursorExecutor.transformProtobufToSSE returns a JSON error before any content is streamed", async () => {
const executor = new CursorExecutor();
const response = executor.transformProtobufToSSE(
buildJsonErrorFrame({
error: {
code: "resource_exhausted",
message: "too many requests",
details: [{ debug: { error: "LIMIT", details: { title: "Limit hit" } } }],
},
}),
"cursor-small",
{ messages: [{ role: "user", content: "hi" }] }
);
const payload = (await response.json()) as any;
assert.equal(response.status, 429);
assert.equal(payload.error.type, "rate_limit_error");
assert.equal(payload.error.message, "Limit hit");
assert.equal(payload.error.code, "LIMIT");
});
test("CursorExecutor.transformProtobufToSSE stops gracefully when a JSON error arrives after content", async () => {
const executor = new CursorExecutor();
const response = executor.transformProtobufToSSE(
Buffer.concat([
buildTextFrame("Partial Cursor answer"),
buildJsonErrorFrame({
error: {
code: "resource_exhausted",
message: "late limit",
},
}),
]),
"cursor-small",
{ messages: [{ role: "user", content: "hi" }] }
);
const text = await response.text();
assert.equal(response.status, 200);
assert.match(text, /Partial Cursor answer/);
assert.match(text, /"finish_reason":"stop"/);
assert.match(text, /\[DONE\]/);
});
test("CursorExecutor.transformProtobufToSSE emits plain content deltas after tool call chunks", async () => {
const executor = new CursorExecutor();
const response = executor.transformProtobufToSSE(
Buffer.concat([
buildToolCallFrame({
id: "call_3",
name: "read_file",
args: '{"path":"/tmp/c"}',
isLast: false,
}),
buildTextFrame("Follow-up text"),
]),
"cursor-small",
{ messages: [{ role: "user", content: "hi" }] }
);
const text = await response.text();
assert.match(text, /"name":"read_file"/);
assert.match(text, /"delta":\{"content":"Follow-up text"\}/);
assert.match(text, /"finish_reason":"tool_calls"/);
});
test("CursorExecutor.transformProtobufToSSE emits an empty assistant envelope for empty responses", async () => {
const executor = new CursorExecutor();
const response = executor.transformProtobufToSSE(Buffer.alloc(0), "cursor-small", {
messages: [{ role: "user", content: "hi" }],
});
const text = await response.text();
assert.match(text, /"role":"assistant","content":""/);
assert.match(text, /"finish_reason":"stop"/);
assert.match(text, /\[DONE\]/);
});
test("CursorExecutor.transformProtobufToSSE converts JSON error frames into rate-limit responses", async () => {
const executor = new CursorExecutor();
const response = executor.transformProtobufToSSE(
buildJsonErrorFrame({
error: {
code: "resource_exhausted",
message: "rate limited",
details: [{ debug: { error: "LIMIT", details: { title: "Limit", detail: "Slow down" } } }],
},
}),
"cursor-small",
{ messages: [{ role: "user", content: "hi" }] }
);
const payload = (await response.json()) as any;
assert.equal(response.status, 429);
assert.equal(payload.error.type, "rate_limit_error");
assert.equal(payload.error.message, "Limit");
assert.equal(payload.error.code, "LIMIT");
});
test("CursorExecutor.execute returns transformed JSON for non-stream responses", async () => {
const executor = new CursorExecutor();
const body = { messages: [{ role: "user", content: "hi" }] };
const responseBuffer = Buffer.concat([buildTextFrame("Hello from Cursor")]);
executor.makeHttp2Request = async () => ({
status: 200,
headers: {},
body: responseBuffer,
});
executor.makeFetchRequest = executor.makeHttp2Request;
const result = await executor.execute({
model: "cursor-small",
body,
stream: false,
credentials: {
accessToken: "token",
providerSpecificData: { machineId: "machine-1" },
},
});
const payload = (await result.response.json()) as any;
assert.equal(
result.url,
"https://api2.cursor.sh/aiserver.v1.ChatService/StreamUnifiedChatWithTools"
);
assert.equal(result.transformedBody, body);
assert.equal(result.headers.authorization, "Bearer token");
assert.equal(payload.object, "chat.completion");
assert.equal(payload.choices[0].message.content, "Hello from Cursor");
assert.equal(payload.choices[0].finish_reason, "stop");
});
test("CursorExecutor.execute returns transformed SSE for stream responses", async () => {
const executor = new CursorExecutor();
const body = { messages: [{ role: "user", content: "hi" }] };
const responseBuffer = Buffer.concat([buildTextFrame("Hello stream")]);
executor.makeHttp2Request = async () => ({
status: 200,
headers: {},
body: responseBuffer,
});
executor.makeFetchRequest = executor.makeHttp2Request;
const result = await executor.execute({
model: "cursor-small",
body,
stream: true,
credentials: {
accessToken: "token",
providerSpecificData: { machineId: "machine-1" },
},
});
const text = await result.response.text();
assert.equal(result.response.status, 200);
assert.match(text, /"content":"Hello stream"/);
assert.match(text, /\[DONE\]/);
});
test("CursorExecutor.execute maps non-200 upstream responses to OpenAI-style errors", async () => {
const executor = new CursorExecutor();
const body = { messages: [{ role: "user", content: "hi" }] };
executor.makeHttp2Request = async () => ({
status: 403,
headers: {},
body: Buffer.from("denied"),
});
executor.makeFetchRequest = executor.makeHttp2Request;
const result = await executor.execute({
model: "cursor-small",
body,
stream: false,
credentials: {
accessToken: "token",
providerSpecificData: { machineId: "machine-1" },
},
});
const payload = (await result.response.json()) as any;
assert.equal(result.response.status, 403);
assert.equal(payload.error.type, "invalid_request_error");
assert.match(payload.error.message, /\[403\]: denied/);
});
test("CursorExecutor.execute maps transport failures to connection_error and refreshCredentials returns null", async () => {
const executor = new CursorExecutor();
executor.makeHttp2Request = async () => {
throw new Error("socket hang up");
};
executor.makeFetchRequest = executor.makeHttp2Request;
const result = await executor.execute({
model: "cursor-small",
body: { messages: [{ role: "user", content: "hi" }] },
stream: false,
credentials: {
accessToken: "token",
providerSpecificData: { machineId: "machine-1" },
},
});
const payload = (await result.response.json()) as any;
assert.equal(result.response.status, 500);
assert.equal(payload.error.type, "connection_error");
assert.equal(payload.error.message, "socket hang up");
assert.equal(await executor.refreshCredentials(), null);
});
test("CursorExecutor.transformProtobufToSSE finalizes un-terminated tools when stream abruptly cuts before isLast", async () => {
const executor = new CursorExecutor();
// Send a tool call but never close it
const response = executor.transformProtobufToSSE(
Buffer.concat([
buildToolCallFrame({
id: "call_abrupt",
name: "write_file",
args: '{"content":"partial"',
isLast: false,
}),
]),
"cursor-small",
{ messages: [{ role: "user", content: "hi" }] }
);
const text = await response.text();
assert.match(text, /"name":"write_file"/);
assert.match(text, /"finish_reason":"tool_calls"/);
assert.match(text, /\[DONE\]/);
});