mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-06 07:12:12 +03:00
This commit is contained in:
committed by
GitHub
parent
3a92236d7a
commit
01476e6e6a
1
changelog.d/fixes/7163-gemini-web-duplicated-text.md
Normal file
1
changelog.d/fixes/7163-gemini-web-duplicated-text.md
Normal file
@@ -0,0 +1 @@
|
||||
- fix(sse): stop duplicating text in Gemini Web streamed responses (#7163)
|
||||
@@ -112,12 +112,15 @@ function parseCookies(raw: string): Array<{ name: string; value: string }> {
|
||||
* [["wrb.fr", null, "<JSON string>"]]
|
||||
*
|
||||
* The JSON string contains nested array: inner[4][0][1] = ["text chunks"].
|
||||
* We concatenate text from every wrb.fr line because Gemini can split one
|
||||
* assistant answer across multiple StreamGenerate chunks.
|
||||
* Each wrb.fr line is a CUMULATIVE snapshot of the whole answer generated so
|
||||
* far (not an independent delta), so we keep only the text from the LAST
|
||||
* frame that yields non-empty text instead of concatenating every frame —
|
||||
* concatenating would reproduce the same growing text with each snapshot
|
||||
* (see #7163).
|
||||
*/
|
||||
export function parseStreamResponse(raw: string): string {
|
||||
const lines = raw.split("\n");
|
||||
const textChunks: string[] = [];
|
||||
let lastText = "";
|
||||
|
||||
for (const rawLine of lines) {
|
||||
const line = rawLine.trim();
|
||||
@@ -133,12 +136,12 @@ export function parseStreamResponse(raw: string): string {
|
||||
const responseArray = inner?.[4]?.[0]?.[1];
|
||||
if (!Array.isArray(responseArray)) continue;
|
||||
const text = responseArray.filter((c: unknown) => typeof c === "string").join("");
|
||||
if (text) textChunks.push(text);
|
||||
if (text) lastText = text;
|
||||
} catch {
|
||||
// Skip unparseable lines
|
||||
}
|
||||
}
|
||||
return textChunks.join("");
|
||||
return lastText;
|
||||
}
|
||||
|
||||
function readCredentialString(value: unknown): string {
|
||||
|
||||
@@ -266,15 +266,20 @@ test("#2832: GeminiWebExecutor catch block sanitizes Playwright launch errors (i
|
||||
|
||||
// ─── StreamGenerate parsing ─────────────────────────────────────────────────
|
||||
|
||||
test("parseStreamResponse concatenates Gemini Web text from multiple wrb.fr chunks", () => {
|
||||
test("parseStreamResponse keeps only the final cumulative StreamGenerate snapshot (no duplication) — regression for #7163", () => {
|
||||
const makeChunk = (text: string) => {
|
||||
const inner = new Array(80).fill(null);
|
||||
inner[4] = [[null, [text]]];
|
||||
return `[["wrb.fr", null, ${JSON.stringify(JSON.stringify(inner))}]]`;
|
||||
};
|
||||
|
||||
const raw = `)]}'\n10\n${makeChunk("First ")}\n5\n${makeChunk("chunk")}`;
|
||||
assert.equal(parseStreamResponse(raw), "First chunk");
|
||||
// Gemini's StreamGenerate frames are CUMULATIVE snapshots: each later frame
|
||||
// repeats the full answer generated so far, not just the new characters.
|
||||
const frame1 = "Hello!";
|
||||
const frame2 = "Hello! How can I";
|
||||
const frame3 = "Hello! How can I help you out today?";
|
||||
const raw = `)]}'\n10\n${makeChunk(frame1)}\n5\n${makeChunk(frame2)}\n5\n${makeChunk(frame3)}`;
|
||||
assert.equal(parseStreamResponse(raw), frame3);
|
||||
});
|
||||
|
||||
test("parseStreamResponse ignores wrb.fr lines whose first entry is not an array", () => {
|
||||
|
||||
Reference in New Issue
Block a user