fix(gemini-web): prefer latest non-empty stream chunk in parser#154
Closed
manhtruong03 wants to merge 1 commit into
Closed
fix(gemini-web): prefer latest non-empty stream chunk in parser#154manhtruong03 wants to merge 1 commit into
manhtruong03 wants to merge 1 commit into
Conversation
Gemini streams BardChatUi responses across multiple wrb.fr chunks; the first chunk with a candidate often holds an empty placeholder. The parser broke at that placeholder and returned text="", surfacing as '(no text output)' for gemini-3-pro / gemini-3.1-pro browser runs. The bug was hard to spot because some routes (notably macOS) coalesce the stream into a single chunk and never hit the placeholder. Loop through all chunks instead, preferring the latest one whose text is non-empty. Add a typeof guard since getNestedValue does not validate the runtime type - without it, a future schema drift would silently lock the parser onto a wrong chunk. Adds 3 unit tests in tests/gemini-web/parse.test.ts: multi-chunk streaming, single-chunk regression guard, and empty-after-non-empty reset.
a23e8e4 to
d92baef
Compare
Owner
|
Superseded by #157, which landed the same Gemini streaming parser fix with regression tests and kept the generated-image scan anchored at the first candidate chunk. Thanks again @manhtruong03; credited in CHANGELOG.md. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes the
(no text output)symptom forgemini-3-pro/gemini-3.1-probrowser-engine runs by makingparseGeminiStreamGenerateResponsewalk everywrb.frchunk and prefer the latest one with non-empty text, instead ofbreak-ing at the first chunk with a candidate (which is usually an empty placeholder under streaming).Fixes #153.
What changed
src/gemini-web/client.ts— two adjustments insideparseGeminiStreamGenerateResponse:breakin the chunk-selection loop; iterate to the end and pick the latest chunk whose text is non-empty. The first chunk with a candidate is kept as the anchor so coalesced 1-chunk responses still parse.getNestedValue<string>(...)togetNestedValue<unknown>(...)and narrow withtypeof === "string". The helper does not validate the runtime shape; this matches the pattern already used elsewhere in the file (lines 256, 269) and prevents a silent lock-in if the schema drifts.tests/gemini-web/parse.test.ts— 3 new unit tests covering multi-chunk streaming, single-chunk regression guard, and a defensive empty-after-non-empty case. Two small synthetic-body helpers added to keep the new cases readable.Diff size: +56 / -7 across 2 files.
Why this approach
src/gemini-web/client.ts:297-328) iterates frombodyIndexforward looking for chunks with image data. With the new predicate,bodyIndexis the latest chunk with non-empty text instead of the first chunk with a candidate. In every captured response the image-bearing chunks arrive at-or-after the final text chunk, so the loop still finds them — but I do not have an automated test for this and a maintainer with--generate-imageaccess may want to spot-check before merging.How to test
Expected end-to-end: a non-empty
Answer:block and↓<n>tokens > 0 (was↓0before the fix).Test plan
pnpm typecheckpasses.pnpm vitest run tests/gemini-webpasses (18/18).pnpm vitest runpasses (615/0/49).gemini-3-pro— answer text renders, output tokens > 0 (was↓0before the fix).--generate-imagebranch not exercised — see "Risks" below.Risks and non-goals
textextraction logic moves.bodyIndexsemantic shift. Before: first chunk with a candidate. After: the chunk eventually selected asbody(typically the last with non-empty text). Only one in-function consumer (hasGenerated) readsbodyIndex; behavior verified for the text path, not actively tested for the image path. Documented as a known limitation in the issue comment.log?.warn(...)whenres.okbuttext === ""— separate follow-up PR. "Longest text" predicate also out of scope (no data justifying it yet).Notes for the reviewer
typeofguard reads slightly defensive for a 4-line patch; rationale is in the inline comment and in the issue thread (the helper does not validate runtime types).gemini-3-prorun was used to derive the chunk sequence. It is not committed because (a) the synthetic minimal bodies in the new tests cover the same shapes more readably, and (b) the raw response embeds an account-bound conversation URL that I would need to scrub before sharing. I can attach a scrubbed copy to the issue if a reviewer wants it.Branch:
fix/gemini-streaming-parse-empty-text(single commit:fix(gemini-web): prefer latest non-empty stream chunk in parser).