diff --git a/internal/js/chat-stream/vercel_stream.js b/internal/js/chat-stream/vercel_stream.js index 439edb8..4b1d6f3 100644 --- a/internal/js/chat-stream/vercel_stream.js +++ b/internal/js/chat-stream/vercel_stream.js @@ -1,33 +1,22 @@ 'use strict'; const { - extractToolNames, createToolSieveState, processToolSieveChunk, flushToolSieve, parseStandaloneToolCalls, formatOpenAIStreamToolCalls, } = require('../helpers/stream-tool-sieve'); -const { - BASE_HEADERS, -} = require('../shared/deepseek-constants'); - -const { - writeOpenAIError, -} = require('./error_shape'); -const { - parseChunkForContent, - isCitation, -} = require('./sse_parse'); -const { - buildUsage, -} = require('./token_usage'); +const { BASE_HEADERS } = require('../shared/deepseek-constants'); +const { writeOpenAIError } = require('./error_shape'); +const { parseChunkForContent, isCitation } = require('./sse_parse'); +const { buildUsage } = require('./token_usage'); const { resolveToolcallPolicy, + formatIncrementalToolCallDeltas, + filterIncrementalToolCallDeltasByAllowed, } = require('./toolcall_policy'); -const { - createChatCompletionEmitter, -} = require('./stream_emitter'); +const { createChatCompletionEmitter } = require('./stream_emitter'); const { asString, isAbortError, @@ -57,6 +46,7 @@ async function handleVercelStream(req, res, rawBody, payload) { const searchEnabled = toBool(prep.body.search_enabled); const toolPolicy = resolveToolcallPolicy(prep.body, payload.tools); const toolNames = toolPolicy.toolNames; + const emitEarlyToolDeltas = toolPolicy.emitEarlyToolDeltas; if (!model || !leaseID || !deepseekToken || !powHeader || !completionPayload) { writeOpenAIError(res, 500, 'invalid vercel prepare response'); @@ -132,6 +122,7 @@ async function handleVercelStream(req, res, rawBody, payload) { const toolSieveState = createToolSieveState(); let toolCallsEmitted = false; const streamToolCallIDs = new Map(); + const streamToolNames = new Map(); const decoder = new TextDecoder(); reader = completionRes.body.getReader(); let buffered = ''; @@ -255,6 +246,18 @@ async function handleVercelStream(req, res, rawBody, payload) { } const events = processToolSieveChunk(toolSieveState, p.text, toolNames); for (const evt of events) { + if (evt.type === 'tool_call_deltas') { + if (!emitEarlyToolDeltas) { + continue; + } + const filtered = filterIncrementalToolCallDeltasByAllowed(evt.deltas, toolNames, streamToolNames); + const formatted = formatIncrementalToolCallDeltas(filtered, streamToolCallIDs); + if (formatted.length > 0) { + toolCallsEmitted = true; + sendDeltaFrame({ tool_calls: formatted }); + } + continue; + } if (evt.type === 'tool_calls') { toolCallsEmitted = true; sendDeltaFrame({ tool_calls: formatOpenAIStreamToolCalls(evt.calls, streamToolCallIDs) });