MCPcopy
hub / github.com/7836246/cursor2api / handleResponsesStream

Function handleResponsesStream

src/openai-handler.ts:1530–1770  ·  view source on GitHub ↗

* Responses API 流式处理 * * ★ 与 Chat Completions 流式的核心区别: * 1. 使用 event: 前缀的 SSE 事件(不是 data-only) * 2. 必须发送 response.completed 事件,否则 Codex 报 "stream closed before response.completed" * 3. 工具调用用 function_call 类型的 output item 表示

(
    res: Response,
    cursorReq: CursorChatRequest,
    body: Record<string, unknown>,
    anthropicReq: AnthropicRequest,
    log: RequestLogger,
)

Source from the content-addressed store, hash-verified

1528 * 3. 工具调用用 function_call 类型的 output item 表示
1529 */
1530async function handleResponsesStream(
1531 res: Response,
1532 cursorReq: CursorChatRequest,
1533 body: Record<string, unknown>,
1534 anthropicReq: AnthropicRequest,
1535 log: RequestLogger,
1536): Promise<void> {
1537 res.writeHead(200, {
1538 'Content-Type': 'text/event-stream',
1539 'Cache-Control': 'no-cache',
1540 'Connection': 'keep-alive',
1541 'X-Accel-Buffering': 'no',
1542 });
1543
1544 const respId = responsesId();
1545 const model = (body.model as string) || 'gpt-4';
1546 const hasTools = (anthropicReq.tools?.length ?? 0) > 0;
1547 let toolCallsDetected = 0;
1548
1549 // 缓冲完整响应再处理(复用 Chat Completions 的逻辑)
1550 let fullResponse = '';
1551 let activeCursorReq = cursorReq;
1552 let retryCount = 0;
1553
1554 // ★ 流式保活:防止网关 504
1555 const keepaliveInterval = setInterval(() => {
1556 try {
1557 res.write(': keepalive\n\n');
1558 if (typeof (res as unknown as { flush: () => void }).flush === 'function') {
1559 (res as unknown as { flush: () => void }).flush();
1560 }
1561 } catch { /* connection already closed */ }
1562 }, 15000);
1563
1564 try {
1565 const executeStream = async () => {
1566 fullResponse = '';
1567 await sendCursorRequest(activeCursorReq, (event: CursorSSEEvent) => {
1568 if (event.type !== 'text-delta' || !event.delta) return;
1569 fullResponse += event.delta;
1570 });
1571 };
1572
1573 await executeStream();
1574
1575 // Thinking 提取
1576 if (hasLeadingThinking(fullResponse)) {
1577 const { strippedText } = extractThinking(fullResponse);
1578 fullResponse = strippedText;
1579 }
1580
1581 // 拒绝检测 + 自动重试
1582 const shouldRetryRefusal = () => {
1583 if (!isRefusal(fullResponse)) return false;
1584 if (hasTools && hasToolCalls(fullResponse)) return false;
1585 return true;
1586 };
1587

Callers 1

handleOpenAIResponsesFunction · 0.85

Calls 15

parseToolCallsFunction · 0.90
isRefusalFunction · 0.90
responsesIdFunction · 0.85
hasLeadingThinkingFunction · 0.85
extractThinkingFunction · 0.85
buildRetryRequestFunction · 0.85
convertToCursorRequestFunction · 0.85
isToolCapabilityQuestionFunction · 0.85
sanitizeResponseFunction · 0.85
estimateInputTokensFunction · 0.85
hasToolCallsFunction · 0.85

Tested by

no test coverage detected