mirror of
https://github.com/Nezumi-2711/9router.git
synced 2026-09-22 13:38:31 +00:00
refactor(app): RISKY pass R1-R3 — config-driven modal, cursor frame dedup, chunk helper
R1: merge AddOpenAICompatibleModal + AddAnthropicCompatibleModal → AddCompatibleModal (variant config-driven, ~180 dup removed, preserves per-variant useEffect behavior) R3: extract readCursorFrame() helper — dedup protobuf frame header/decompress loop (JSON+SSE transforms, byte-identical) R2: add chatChunkSse() helper, wire 7 cursor SSE scaffolds (byte-identical, cursor golden pass) Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+92
-196
@@ -9,6 +9,7 @@ import {
|
||||
import { buildCursorHeaders } from "../utils/cursorChecksum.js";
|
||||
import { estimateUsage } from "../utils/usageTracking.js";
|
||||
import { SSE_DONE, SSE_HEADERS } from "../utils/sseConstants.js";
|
||||
import { chatChunkSse } from "../utils/sse.js";
|
||||
import { FORMATS } from "../translator/formats.js";
|
||||
import { proxyAwareFetch } from "../utils/proxyFetch.js";
|
||||
import zlib from "zlib";
|
||||
@@ -99,6 +100,32 @@ function decompressPayload(payload, flags) {
|
||||
return payload;
|
||||
}
|
||||
|
||||
// Read one cursor protobuf frame: header + bounds + decompress. Returns status + payload + new offset.
|
||||
function readCursorFrame(buffer, offset, frameNum, tag) {
|
||||
if (offset + 5 > buffer.length) {
|
||||
debugLog(`[CURSOR BUFFER${tag}] Reached end, offset=${offset}, remaining=${buffer.length - offset}`);
|
||||
return { status: "done" };
|
||||
}
|
||||
|
||||
const flags = buffer[offset];
|
||||
const length = buffer.readUInt32BE(offset + 1);
|
||||
debugLog(`[CURSOR BUFFER${tag}] Frame ${frameNum + 1}: flags=0x${flags.toString(16).padStart(2, "0")}, length=${length}`);
|
||||
|
||||
if (offset + 5 + length > buffer.length) {
|
||||
debugLog(`[CURSOR BUFFER${tag}] Incomplete frame, offset=${offset}, length=${length}, buffer.length=${buffer.length}`);
|
||||
return { status: "done" };
|
||||
}
|
||||
|
||||
let payload = buffer.slice(offset + 5, offset + 5 + length);
|
||||
const newOffset = offset + 5 + length;
|
||||
payload = decompressPayload(payload, flags);
|
||||
if (!payload) {
|
||||
debugLog(`[CURSOR BUFFER${tag}] Frame ${frameNum + 1}: decompression failed, skipping`);
|
||||
return { status: "skip", offset: newOffset };
|
||||
}
|
||||
return { status: "ok", payload, offset: newOffset };
|
||||
}
|
||||
|
||||
function createErrorResponse(jsonError) {
|
||||
const errorMsg = jsonError?.error?.details?.[0]?.debug?.details?.title
|
||||
|| jsonError?.error?.details?.[0]?.debug?.details?.detail
|
||||
@@ -287,36 +314,12 @@ export class CursorExecutor extends BaseExecutor {
|
||||
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;
|
||||
const frame = readCursorFrame(buffer, offset, frameCount, "");
|
||||
if (frame.status === "done") break;
|
||||
offset = frame.offset;
|
||||
frameCount++;
|
||||
|
||||
payload = decompressPayload(payload, flags);
|
||||
if (!payload) {
|
||||
debugLog(`[CURSOR BUFFER] Frame ${frameCount}: decompression failed, skipping`);
|
||||
continue;
|
||||
}
|
||||
if (frame.status === "skip") continue;
|
||||
const payload = frame.payload;
|
||||
|
||||
// Check for JSON error frames (byte guard: skip toString on non-JSON frames)
|
||||
if (payload.length > 0 && payload[0] === 0x7b) {
|
||||
@@ -467,36 +470,12 @@ export class CursorExecutor extends BaseExecutor {
|
||||
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;
|
||||
const frame = readCursorFrame(buffer, offset, frameCount, " SSE");
|
||||
if (frame.status === "done") break;
|
||||
offset = frame.offset;
|
||||
frameCount++;
|
||||
|
||||
payload = decompressPayload(payload, flags);
|
||||
if (!payload) {
|
||||
debugLog(`[CURSOR BUFFER SSE] Frame ${frameCount}: decompression failed, skipping`);
|
||||
continue;
|
||||
}
|
||||
if (frame.status === "skip") continue;
|
||||
const payload = frame.payload;
|
||||
|
||||
// Check for JSON error frames (byte-guard: only decode if starts with '{')
|
||||
if (payload[0] === 0x7b) {
|
||||
@@ -543,21 +522,7 @@ export class CursorExecutor extends BaseExecutor {
|
||||
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`
|
||||
);
|
||||
chunks.push(chatChunkSse({ id: responseId, created, model, delta: { role: "assistant", content: "" } }));
|
||||
}
|
||||
|
||||
if (toolCallsMap.has(tc.id)) {
|
||||
@@ -570,33 +535,22 @@ export class CursorExecutor extends BaseExecutor {
|
||||
// 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: [
|
||||
chunks.push(chatChunkSse({
|
||||
id: responseId, created, model,
|
||||
delta: {
|
||||
tool_calls: [
|
||||
{
|
||||
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
|
||||
index: existing.index,
|
||||
id: tc.id,
|
||||
type: "function",
|
||||
function: {
|
||||
name: tc.function.name,
|
||||
arguments: tc.function.arguments
|
||||
}
|
||||
}
|
||||
]
|
||||
})}\n\n`
|
||||
);
|
||||
}
|
||||
}));
|
||||
}
|
||||
} else {
|
||||
// New tool call - assign index and add to map
|
||||
@@ -607,56 +561,34 @@ export class CursorExecutor extends BaseExecutor {
|
||||
|
||||
// Stream initial tool call with name
|
||||
emittedToolCallIds.add(tc.id);
|
||||
chunks.push(
|
||||
`data: ${JSON.stringify({
|
||||
id: responseId,
|
||||
object: "chat.completion.chunk",
|
||||
created,
|
||||
model,
|
||||
choices: [
|
||||
chunks.push(chatChunkSse({
|
||||
id: responseId, created, model,
|
||||
delta: {
|
||||
tool_calls: [
|
||||
{
|
||||
index: 0,
|
||||
delta: {
|
||||
tool_calls: [
|
||||
{
|
||||
index: toolCallIndex,
|
||||
id: tc.id,
|
||||
type: "function",
|
||||
function: {
|
||||
name: tc.function.name,
|
||||
arguments: tc.function.arguments
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
finish_reason: null
|
||||
index: toolCallIndex,
|
||||
id: tc.id,
|
||||
type: "function",
|
||||
function: {
|
||||
name: tc.function.name,
|
||||
arguments: tc.function.arguments
|
||||
}
|
||||
}
|
||||
]
|
||||
})}\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`
|
||||
);
|
||||
chunks.push(chatChunkSse({
|
||||
id: responseId, created, model,
|
||||
delta:
|
||||
chunks.length === 0 && toolCalls.length === 0
|
||||
? { role: "assistant", content: result.text }
|
||||
: { content: result.text }
|
||||
}));
|
||||
}
|
||||
|
||||
if (isComposerModel(model) && result.thinking) {
|
||||
@@ -666,24 +598,13 @@ export class CursorExecutor extends BaseExecutor {
|
||||
const deltaContent = visibleContent.slice(emittedComposerThinkingContentLength);
|
||||
emittedComposerThinkingContentLength = visibleContent.length;
|
||||
totalContent += deltaContent;
|
||||
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: deltaContent }
|
||||
: { content: deltaContent },
|
||||
finish_reason: null
|
||||
}
|
||||
]
|
||||
})}\n\n`
|
||||
);
|
||||
chunks.push(chatChunkSse({
|
||||
id: responseId, created, model,
|
||||
delta:
|
||||
chunks.length === 0 && toolCalls.length === 0
|
||||
? { role: "assistant", content: deltaContent }
|
||||
: { content: deltaContent }
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -709,53 +630,28 @@ export class CursorExecutor extends BaseExecutor {
|
||||
|
||||
// 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: [
|
||||
chunks.push(chatChunkSse({
|
||||
id: responseId, created, model,
|
||||
delta: {
|
||||
tool_calls: [
|
||||
{
|
||||
index: 0,
|
||||
delta: {
|
||||
tool_calls: [
|
||||
{
|
||||
index: toolCallIndex,
|
||||
id: tc.id,
|
||||
type: "function",
|
||||
function: {
|
||||
name: tc.function.name,
|
||||
arguments: tc.function.arguments
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
finish_reason: null
|
||||
index: toolCallIndex,
|
||||
id: tc.id,
|
||||
type: "function",
|
||||
function: {
|
||||
name: tc.function.name,
|
||||
arguments: tc.function.arguments
|
||||
}
|
||||
}
|
||||
]
|
||||
})}\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(chatChunkSse({ id: responseId, created, model, delta: { role: "assistant", content: "" } }));
|
||||
}
|
||||
|
||||
const usage = estimateUsage(body, totalContent.length, FORMATS.OPENAI);
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
export function sseChunk(data) {
|
||||
return `data: ${JSON.stringify(data)}\n\n`;
|
||||
}
|
||||
|
||||
// Build OpenAI chat.completion.chunk SSE frame. Key order: id, object, created, model, choices.
|
||||
export function chatChunkSse({ id, created, model, delta, finishReason = null }) {
|
||||
return sseChunk({
|
||||
id,
|
||||
object: "chat.completion.chunk",
|
||||
created,
|
||||
model,
|
||||
choices: [{ index: 0, delta, finish_reason: finishReason }],
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user