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

Function handleDirectTextStream

src/handler.ts:898–1139  ·  view source on GitHub ↗
(
    res: Response,
    cursorReq: CursorChatRequest,
    body: AnthropicRequest,
    log: RequestLogger,
    clientRequestedThinking: boolean,
    streamState: { blockIndex: number; textBlockStarted: boolean; thinkingEmitted: boolean },
)

Source from the content-addressed store, hash-verified

896}
897
898async function handleDirectTextStream(
899 res: Response,
900 cursorReq: CursorChatRequest,
901 body: AnthropicRequest,
902 log: RequestLogger,
903 clientRequestedThinking: boolean,
904 streamState: { blockIndex: number; textBlockStarted: boolean; thinkingEmitted: boolean },
905): Promise<void> {
906 // ★ 流式保活:增量流式路径也需要 keepalive,防止 thinking 缓冲期间网关 504
907 const keepaliveInterval = setInterval(() => {
908 try {
909 res.write(': keepalive\n\n');
910 // @ts-expect-error flush exists on ServerResponse when compression is used
911 if (typeof res.flush === 'function') res.flush();
912 } catch { /* connection already closed, ignore */ }
913 }, 15000);
914
915 try {
916 let activeCursorReq = cursorReq;
917 let retryCount = 0;
918 let finalRawResponse = '';
919 let finalVisibleText = '';
920 let finalThinkingContent = '';
921 let cursorUsage: { inputTokens?: number; outputTokens?: number; totalTokens?: number } | undefined;
922 let streamer = createIncrementalTextStreamer({
923 warmupChars: 300, // ★ 与工具模式对齐:前 300 chars 不释放,确保拒绝检测完成后再流
924 transform: sanitizeResponse,
925 isBlockedPrefix: (text) => isRefusal(text.substring(0, 300)),
926 });
927
928 const executeAttempt = async (): Promise<{
929 rawResponse: string;
930 visibleText: string;
931 thinkingContent: string;
932 streamer: ReturnType<typeof createIncrementalTextStreamer>;
933 }> => {
934 let rawResponse = '';
935 let visibleText = '';
936 let leadingBuffer = '';
937 let leadingResolved = false;
938 let thinkingContent = '';
939 const attemptStreamer = createIncrementalTextStreamer({
940 warmupChars: 300, // ★ 与工具模式对齐
941 transform: sanitizeResponse,
942 isBlockedPrefix: (text) => isRefusal(text.substring(0, 300)),
943 });
944
945 const flushVisible = (chunk: string): void => {
946 if (!chunk) return;
947 visibleText += chunk;
948 const delta = attemptStreamer.push(chunk);
949 if (!delta) return;
950
951 if (clientRequestedThinking && thinkingContent && !streamState.thinkingEmitted) {
952 emitAnthropicThinkingBlock(res, streamState, thinkingContent);
953 }
954 writeAnthropicTextDelta(res, streamState, delta);
955 };

Callers 1

handleStreamFunction · 0.85

Calls 15

isRefusalFunction · 0.90
buildRetryRequestFunction · 0.85
convertToCursorRequestFunction · 0.85
hasLeadingThinkingFunction · 0.85
extractThinkingFunction · 0.85
isToolCapabilityQuestionFunction · 0.85
writeAnthropicTextDeltaFunction · 0.85
writeSSEFunction · 0.85
sanitizeResponseFunction · 0.85
estimateCursorReqTokensFunction · 0.85

Tested by

no test coverage detected