[codex] fix empty stream success handling and unknown usage logs (#343)

* fix: preserve repeated short responses deltas

* fix empty stream success handling and unknown usage logs

* fix proxy usage metadata typing

* fix stream bookkeeping and explicit zero usage source

* fix sticky fast path and usage placeholder detection
This commit is contained in:
Cita
2026-03-31 16:45:13 +08:00
committed by GitHub
parent 3ce5179fed
commit 6b19d06140
24 changed files with 926 additions and 73 deletions
@@ -4,6 +4,7 @@ import { type DownstreamFormat, type ParsedSseEvent } from '../../shared/normali
import { createOpenAiChatAggregateState, applyOpenAiChatStreamEvent, finalizeOpenAiChatAggregate } from './aggregator.js';
import { openAiChatOutbound } from './outbound.js';
import { openAiChatStream } from './stream.js';
import { config } from '../../../config.js';
type StreamReader = {
read(): Promise<{ done: boolean; value?: Uint8Array }>;
@@ -49,6 +50,9 @@ export function createChatProxyStreamSession(input: ChatProxyStreamSessionInput)
status: 'completed',
errorMessage: null,
};
let terminalNormalizedFinal: ReturnType<typeof openAiChatOutbound.normalizeFinal> | null = null;
let forwardedDownstreamOutput = false;
const pendingWrites: string[] = [];
const extractFailureMessage = (payload: unknown, fallback = 'upstream stream failed'): string => {
if (payload && typeof payload === 'object' && !Array.isArray(payload)) {
@@ -76,10 +80,116 @@ export function createChatProxyStreamSession(input: ChatProxyStreamSessionInput)
};
};
const hasMeaningfulChatAggregateOutput = (): boolean => {
if (input.downstreamFormat !== 'openai' || !chatAggregateState) return false;
for (const choice of chatAggregateState.choices.values()) {
if (choice.content.length > 0) return true;
if (choice.reasoning.length > 0) return true;
if (choice.toolCalls.some((item) => item.id || item.name || item.arguments)) return true;
}
return false;
};
const hasMeaningfulNormalizedFinalOutput = (): boolean => {
if (!terminalNormalizedFinal) return false;
const choices = Array.isArray(terminalNormalizedFinal.choices)
? terminalNormalizedFinal.choices
: [];
if (choices.some((choice) => (
choice.content.length > 0
|| choice.reasoningContent.length > 0
|| choice.toolCalls.some((toolCall) => toolCall.id || toolCall.name || toolCall.arguments)
))) {
return true;
}
if (terminalNormalizedFinal.content.length > 0) return true;
if (terminalNormalizedFinal.reasoningContent.length > 0) return true;
return terminalNormalizedFinal.toolCalls.some((toolCall) => toolCall.id || toolCall.name || toolCall.arguments);
};
const flushPendingWrites = () => {
if (pendingWrites.length <= 0) return;
input.writeLines([...pendingWrites]);
pendingWrites.length = 0;
};
const emitLines = (lines: string[], options?: { meaningful?: boolean; force?: boolean }) => {
if (lines.length <= 0) return;
if (input.downstreamFormat !== 'openai') {
input.writeLines(lines);
return;
}
if (forwardedDownstreamOutput) {
input.writeLines(lines);
return;
}
if (options?.force) {
pendingWrites.length = 0;
forwardedDownstreamOutput = true;
input.writeLines(lines);
return;
}
if (options?.meaningful) {
forwardedDownstreamOutput = true;
flushPendingWrites();
input.writeLines(lines);
return;
}
pendingWrites.push(...lines);
};
const emitRaw = (chunk: string, options?: { meaningful?: boolean; force?: boolean }) => {
if (!chunk) return;
if (input.downstreamFormat !== 'openai') {
input.writeRaw(chunk);
return;
}
if (forwardedDownstreamOutput) {
input.writeRaw(chunk);
return;
}
if (options?.force) {
pendingWrites.length = 0;
forwardedDownstreamOutput = true;
input.writeRaw(chunk);
return;
}
if (options?.meaningful) {
forwardedDownstreamOutput = true;
flushPendingWrites();
input.writeRaw(chunk);
return;
}
pendingWrites.push(chunk);
};
const shouldFailEmptyChatCompletion = (): boolean => {
if (!config.proxyEmptyContentFailEnabled) return false;
if (input.downstreamFormat !== 'openai') return false;
if (terminalResult.status === 'failed') return false;
if (hasMeaningfulChatAggregateOutput()) return false;
if (hasMeaningfulNormalizedFinalOutput()) return false;
return true;
};
const finalize = () => {
if (finalized) return;
finalized = true;
if (shouldFailEmptyChatCompletion()) {
markFailed({
error: {
message: 'Upstream returned empty content',
},
}, 'Upstream returned empty content');
return;
}
if (input.downstreamFormat === 'openai' && !forwardedDownstreamOutput) {
forwardedDownstreamOutput = true;
flushPendingWrites();
}
// For native Anthropic streams, EOF without message_stop is not a clean
// completion. Forward the partial stream as-is instead of fabricating an
// end_turn/message_stop pair that makes clients think the run finished.
@@ -108,12 +218,12 @@ export function createChatProxyStreamSession(input: ChatProxyStreamSessionInput)
}),
).slice(-1)[0];
if (terminalChunk) {
input.writeLines([`data: ${JSON.stringify(terminalChunk)}\n\n`]);
emitLines([`data: ${JSON.stringify(terminalChunk)}\n\n`], { meaningful: true });
}
}
}
input.writeLines(downstreamTransformer.serializeDone(streamContext, claudeContext));
emitLines(downstreamTransformer.serializeDone(streamContext, claudeContext), { meaningful: true });
};
const handleEventBlock = async (eventBlock: ParsedSseEvent): Promise<boolean> => {
@@ -153,19 +263,26 @@ export function createChatProxyStreamSession(input: ChatProxyStreamSessionInput)
const payloadType = typeof (parsedPayload as Record<string, unknown>).type === 'string'
? String((parsedPayload as Record<string, unknown>).type)
: '';
if (payloadType === 'response.failed' || payloadType === 'error') {
const isFailurePayload = payloadType === 'response.failed' || payloadType === 'error';
if (isFailurePayload) {
markFailed(parsedPayload);
}
const normalizedEvent = downstreamTransformer.transformStreamEvent(parsedPayload, streamContext, input.modelName);
if (input.downstreamFormat === 'openai' && chatAggregateState) {
applyOpenAiChatStreamEvent(chatAggregateState, normalizedEvent);
}
input.writeLines(downstreamTransformer.serializeStreamEvent(normalizedEvent, streamContext, claudeContext));
emitLines(
downstreamTransformer.serializeStreamEvent(normalizedEvent, streamContext, claudeContext),
{
meaningful: hasMeaningfulChatAggregateOutput(),
force: isFailurePayload,
},
);
return input.downstreamFormat === 'claude' && claudeContext.doneSent;
}
if (input.downstreamFormat === 'openai') {
input.writeRaw(`data: ${eventBlock.data}\n\n`);
emitRaw(`data: ${eventBlock.data}\n\n`, { meaningful: true });
return false;
}
@@ -190,16 +307,18 @@ export function createChatProxyStreamSession(input: ChatProxyStreamSessionInput)
}
if (input.downstreamFormat === 'openai') {
const normalizedFinal = openAiChatOutbound.normalizeFinal(payload, input.modelName, fallbackText);
terminalNormalizedFinal = normalizedFinal;
streamContext.id = normalizedFinal.id;
streamContext.model = normalizedFinal.model;
streamContext.created = normalizedFinal.created;
input.writeLines(
emitLines(
openAiChatOutbound
.buildSyntheticChunks(normalizedFinal)
.map((chunk) => `data: ${JSON.stringify(chunk)}\n\n`),
{ meaningful: true },
);
} else {
input.writeLines(
emitLines(
anthropicMessagesTransformer.serializeUpstreamFinalAsStream(
payload,
input.modelName,
@@ -207,6 +326,7 @@ export function createChatProxyStreamSession(input: ChatProxyStreamSessionInput)
streamContext,
claudeContext,
),
{ meaningful: true },
);
}
finalize();
@@ -98,7 +98,7 @@ function shouldFailEmptyResponsesCompletion(input: {
: null;
if (hasMeaningfulAggregateOutput(input.state)) return false;
if (responsePayload && hasMeaningfulResponsesPayloadOutput(responsePayload)) return false;
return input.usage.completionTokens <= 0 && input.usage.totalTokens <= 0;
return input.usage.completionTokens <= 0;
}
function getResponsesStreamFailureMessage(payload: unknown, fallback = 'upstream stream failed'): string {