

























@@ -2657,6 +2657,11 @@ async function processOpenAICompletionsStream(
26572657let sawStopFinishReason = false;
26582658const blockIndex = () => output.content.length - 1;
26592659const measureUtf8Bytes = (text: string) => Buffer.byteLength(text, "utf8");
2660+let chunkPushedEvent = false;
2661+const pushStreamEvent = (event: unknown) => {
2662+chunkPushedEvent = true;
2663+stream.push(event);
2664+};
26602665const finishCurrentBlock = () => {
26612666if (!currentBlock) {
26622667return;
@@ -2697,13 +2702,13 @@ async function processOpenAICompletionsStream(
26972702currentBlock = {
26982703type: "thinking",
26992704thinking: "",
2700-thinkingSignature: reasoningDelta.signature,
2705+...(reasoningDelta.signature ? { thinkingSignature: reasoningDelta.signature } : {}),
27012706};
27022707output.content.push(currentBlock);
2703-stream.push({ type: "thinking_start", contentIndex: blockIndex(), partial: output });
2708+pushStreamEvent({ type: "thinking_start", contentIndex: blockIndex(), partial: output });
27042709}
27052710currentBlock.thinking += reasoningDelta.text;
2706-stream.push({
2711+pushStreamEvent({
27072712type: "thinking_delta",
27082713contentIndex: blockIndex(),
27092714delta: reasoningDelta.text,
@@ -2715,10 +2720,10 @@ async function processOpenAICompletionsStream(
27152720finishCurrentBlock();
27162721currentBlock = { type: "text", text: "" };
27172722output.content.push(currentBlock);
2718-stream.push({ type: "text_start", contentIndex: blockIndex(), partial: output });
2723+pushStreamEvent({ type: "text_start", contentIndex: blockIndex(), partial: output });
27192724}
27202725currentBlock.text += text;
2721-stream.push({
2726+pushStreamEvent({
27222727type: "text_delta",
27232728contentIndex: blockIndex(),
27242729delta: text,
@@ -2782,12 +2787,12 @@ async function processOpenAICompletionsStream(
27822787};
27832788currentBlock = block;
27842789output.content.push(block);
2785-stream.push({
2790+pushStreamEvent({
27862791type: "toolcall_start",
27872792contentIndex: output.content.indexOf(block),
27882793partial: output,
27892794});
2790-stream.push({
2795+pushStreamEvent({
27912796type: "toolcall_delta",
27922797contentIndex: output.content.indexOf(block),
27932798delta: toolCall.partialArgs,
@@ -2853,6 +2858,19 @@ async function processOpenAICompletionsStream(
28532858appendFilteredVisibleTextDelta(delta.text);
28542859}
28552860};
2861+const emitReasoningUsageActivity = (hasReasoningUsageActivity: boolean) => {
2862+if (!hasReasoningUsageActivity || chunkPushedEvent || !emitReasoning) {
2863+return;
2864+}
2865+const latestBlock = output.content[output.content.length - 1];
2866+if (currentBlock?.type === "text" || currentBlock?.type === "toolCall") {
2867+return;
2868+}
2869+if (latestBlock?.type === "text" || latestBlock?.type === "toolCall") {
2870+return;
2871+}
2872+appendThinkingDelta({ signature: "", text: "" });
2873+};
28562874const flushReasoningTagTextPartitionerAtEnd = () => {
28572875for (const delta of reasoningTagTextPartitioner.flush()) {
28582876appendPartitionedVisibleDelta(delta);
@@ -2861,23 +2879,28 @@ async function processOpenAICompletionsStream(
28612879const cooperativeScheduler = createModelStreamCooperativeScheduler(options?.signal);
28622880for await (const rawChunk of responseStream as AsyncIterable<unknown>) {
28632881throwIfModelStreamAborted(options?.signal);
2882+chunkPushedEvent = false;
28642883if (!rawChunk || typeof rawChunk !== "object") {
28652884await cooperativeScheduler.afterEvent();
28662885continue;
28672886}
28682887const chunk = rawChunk as ChatCompletionChunk;
28692888output.responseId ||= chunk.id;
2889+let hasReasoningUsageActivity = false;
28702890if (chunk.usage) {
28712891output.usage = parseTransportChunkUsage(chunk.usage, model);
2892+hasReasoningUsageActivity = hasOpenAICompletionsReasoningUsageActivity(chunk.usage);
28722893}
28732894const choice = Array.isArray(chunk.choices) ? chunk.choices[0] : undefined;
28742895if (!choice) {
2896+emitReasoningUsageActivity(hasReasoningUsageActivity);
28752897await cooperativeScheduler.afterEvent();
28762898continue;
28772899}
28782900const choiceUsage = (choice as unknown as { usage?: ChatCompletionChunk["usage"] }).usage;
28792901if (!chunk.usage && choiceUsage) {
28802902output.usage = parseTransportChunkUsage(choiceUsage, model);
2903+hasReasoningUsageActivity = hasOpenAICompletionsReasoningUsageActivity(choiceUsage);
28812904}
28822905if (choice.finish_reason) {
28832906const finishReasonResult = mapStopReason(choice.finish_reason);
@@ -2893,6 +2916,7 @@ async function processOpenAICompletionsStream(
28932916choice.delta ??
28942917(choice as unknown as { message?: ChatCompletionChunk["choices"][number]["delta"] }).message;
28952918if (!choiceDelta) {
2919+emitReasoningUsageActivity(hasReasoningUsageActivity);
28962920await cooperativeScheduler.afterEvent();
28972921continue;
28982922}
@@ -2961,7 +2985,7 @@ async function processOpenAICompletionsStream(
29612985 ...(initialSig ? { thoughtSignature: initialSig } : {}),
29622986};
29632987output.content.push(block);
2964-stream.push({
2988+pushStreamEvent({
29652989type: "toolcall_start",
29662990contentIndex: output.content.indexOf(block),
29672991partial: output,
@@ -2991,7 +3015,7 @@ async function processOpenAICompletionsStream(
29913015toolCallBlockBytes.set(block, currentBlockArgBytes + nextArgumentBytes);
29923016block.partialArgs += toolCall.function.arguments;
29933017block.arguments = parseStreamingJson(block.partialArgs);
2994-stream.push({
3018+pushStreamEvent({
29953019type: "toolcall_delta",
29963020contentIndex: output.content.indexOf(block),
29973021delta: toolCall.function.arguments,
@@ -3001,6 +3025,7 @@ async function processOpenAICompletionsStream(
30013025}
30023026}
30033027flushPendingPostToolCallDeltas();
3028+emitReasoningUsageActivity(hasReasoningUsageActivity);
30043029await cooperativeScheduler.afterEvent();
30053030}
30063031flushReasoningTagTextPartitionerAtEnd();
@@ -4207,6 +4232,15 @@ export function parseTransportChunkUsage(
42074232return usage;
42084233}
420942344235+function hasOpenAICompletionsReasoningUsageActivity(
4236+rawUsage: NonNullable<ChatCompletionChunk["usage"]>,
4237+) {
4238+const reasoningTokens = rawUsage.completion_tokens_details?.reasoning_tokens;
4239+return (
4240+typeof reasoningTokens === "number" && Number.isFinite(reasoningTokens) && reasoningTokens > 0
4241+);
4242+}
4243+42104244function mapStopReason(reason: string | null) {
42114245if (reason === null) {
42124246return { stopReason: "stop" };
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。