import { describe, it, expect } from "vitest"; import { CursorExecutor } from "../../open-sse/executors/cursor.js"; import { encodeField, wrapConnectRPCFrame } from "../../open-sse/utils/cursorProtobuf.js"; const LEN = 2; function cursorResponseFrame({ text = "", thinking = "" }) { const responseFields = []; if (text) { responseFields.push(encodeField(1, LEN, text)); } if (thinking) { const thinkingMessage = encodeField(1, LEN, thinking); responseFields.push(encodeField(25, LEN, thinkingMessage)); } const response = Buffer.concat(responseFields.map((field) => Buffer.from(field))); const envelope = encodeField(2, LEN, response); return Buffer.from(wrapConnectRPCFrame(envelope)); } function parseSSE(text) { return text .split("\n\n") .filter((chunk) => chunk.startsWith("data: ")) .map((chunk) => chunk.slice("data: ".length)) .filter((data) => data !== "[DONE]") .map((data) => JSON.parse(data)); } describe("CursorExecutor Composer thinking-field responses", () => { it("uses visible content after for non-streaming Composer responses", async () => { const executor = new CursorExecutor(); const buffer = cursorResponseFrame({ thinking: "private reasoning that must not leakOK", }); const response = executor.transformProtobufToJSON(buffer, "cu/composer-2.5", { messages: [{ role: "user", content: "reply OK" }], }); const payload = await response.json(); expect(payload.choices[0].message.content).toBe("OK"); expect(JSON.stringify(payload)).not.toContain("private reasoning"); expect(payload.usage.completion_tokens).toBeGreaterThan(0); }); it("streams only visible content after for Composer responses", async () => { const executor = new CursorExecutor(); const buffer = Buffer.concat([ cursorResponseFrame({ thinking: "private reasoning" }), cursorResponseFrame({ thinking: " that must not leakO" }), cursorResponseFrame({ thinking: "K" }), ]); const response = executor.transformProtobufToSSE(buffer, "composer-2.5-fast", { messages: [{ role: "user", content: "reply OK" }], }); const events = parseSSE(await response.text()); const content = events .map((event) => event.choices?.[0]?.delta?.content || "") .join(""); expect(content).toBe("OK"); expect(JSON.stringify(events)).not.toContain("private reasoning"); expect(events.at(-1).usage.completion_tokens).toBeGreaterThan(0); }); it("does not treat thinking as visible output for non-Composer models", async () => { const executor = new CursorExecutor(); const buffer = cursorResponseFrame({ thinking: "private reasoningSHOULD_NOT_APPEAR", }); const response = executor.transformProtobufToJSON(buffer, "gpt-5.3-codex", { messages: [{ role: "user", content: "hi" }], }); const payload = await response.json(); expect(payload.choices[0].message.content).toBeNull(); expect(JSON.stringify(payload)).not.toContain("SHOULD_NOT_APPEAR"); }); });