From eb65a2be8826428adccb64069b8eb7ad0efb7739 Mon Sep 17 00:00:00 2001 From: Cita Date: Mon, 30 Mar 2026 22:54:05 +0800 Subject: [PATCH] fix: preserve repeated short responses deltas (#336) --- src/server/routes/proxy/chat.stream.test.ts | 45 +++++++++++++++++++ .../openai/responses/aggregator.ts | 12 ++++- 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/src/server/routes/proxy/chat.stream.test.ts b/src/server/routes/proxy/chat.stream.test.ts index e6e696b..7bd6abe 100644 --- a/src/server/routes/proxy/chat.stream.test.ts +++ b/src/server/routes/proxy/chat.stream.test.ts @@ -2039,6 +2039,51 @@ describe('chat proxy stream behavior', () => { expect(response.body).toContain('"text":"The user asked \\"whoru\\" which is a common internet slang and shorthand for who are you."'); }); + it('preserves legitimate repeated short deltas when /v1/responses is converted from /v1/messages stream', async () => { + fetchModelPricingCatalogMock.mockResolvedValue({ + models: [ + { + modelName: 'upstream-gpt', + supportedEndpointTypes: ['/v1/messages'], + }, + ], + groupRatio: {}, + }); + + const encoder = new TextEncoder(); + const upstreamBody = new ReadableStream({ + start(controller) { + controller.enqueue(encoder.encode('event: message_start\ndata: {"type":"message_start","message":{"id":"msg_repeat_short_1","model":"upstream-gpt"}}\n\n')); + controller.enqueue(encoder.encode('event: content_block_delta\ndata: {"type":"content_block_delta","delta":{"type":"text_delta","text":"ha"}}\n\n')); + controller.enqueue(encoder.encode('event: content_block_delta\ndata: {"type":"content_block_delta","delta":{"type":"text_delta","text":"ha"}}\n\n')); + controller.enqueue(encoder.encode('event: message_stop\ndata: {"type":"message_stop"}\n\n')); + controller.enqueue(encoder.encode('data: [DONE]\n\n')); + controller.close(); + }, + }); + + fetchMock.mockResolvedValue(new Response(upstreamBody, { + status: 200, + headers: { 'content-type': 'text/event-stream; charset=utf-8' }, + })); + + const response = await app.inject({ + method: 'POST', + url: '/v1/responses', + payload: { + model: 'claude-sonnet-4-6', + stream: true, + input: 'laugh', + }, + }); + + expect(response.statusCode).toBe(200); + const deltaMatches = response.body.match(/event: response\.output_text\.delta/g) || []; + expect(deltaMatches.length).toBe(2); + expect(response.body).toContain('"delta":"ha"'); + expect(response.body).toContain('"text":"haha"'); + }); + it('preserves function_call/function_call_output when /v1/responses falls back to /v1/chat/completions', async () => { fetchModelPricingCatalogMock.mockResolvedValue({ models: [ diff --git a/src/server/transformers/openai/responses/aggregator.ts b/src/server/transformers/openai/responses/aggregator.ts index dfa1b50..ccfe536 100644 --- a/src/server/transformers/openai/responses/aggregator.ts +++ b/src/server/transformers/openai/responses/aggregator.ts @@ -656,13 +656,21 @@ function mergeImageGenerationFields( } function computeNovelDelta(existingText: string, incomingDelta: string): string { + const replayWindowMinLength = 24; if (!incomingDelta) return ''; if (!existingText) return incomingDelta; - if (existingText.endsWith(incomingDelta)) return ''; + if (existingText.endsWith(incomingDelta)) { + return incomingDelta.length >= replayWindowMinLength ? '' : incomingDelta; + } if (incomingDelta.startsWith(existingText)) { return incomingDelta.slice(existingText.length); } - if (existingText.includes(incomingDelta)) return ''; + if ( + incomingDelta.length >= replayWindowMinLength + && existingText.includes(incomingDelta) + ) { + return ''; + } const maxOverlap = Math.min(existingText.length, incomingDelta.length); for (let overlap = maxOverlap; overlap > 0; overlap -= 1) {