fix: handle a reply cut off part-way through an A2UI message - #29
Merged
Merged
Conversation
Gemini stops a reply that trips its recitation filter with an empty content object, which genkit_google_genai's fromGeminiCandidate crashes on. The parser now reports an unfinished A2UI message at stream end instead of printing it as prose, the example shows a plain message for a failed turn and logs the cause on the server, and the example prompt asks the model to write in its own words. Closes #25
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
When Gemini's recitation filter stopped a reply, the example chat showed half-written A2UI JSON as prose, then an opaque "Internal server error". The recitation stop sends a chunk with empty
content, andgenkit_google_genaicrashes on it with a null check that Genkit reports as INTERNAL. The plugin bug belongs upstream. This PR makes the package and the example handle a reply that is cut off.Changes
A2uiParserTransformerreports an A2UI message that is still unfinished when the stream ends as anA2uiValidationException, so it arrives as aGenUiError. This applies whether the stream ended cleanly or failed. The leftover counts only when it opens with a```jsonfence, or with a brace or fence that names a message key. A stray brace or an unrelated code block still shows as prose.chatHandlerlogs a failed turn to stderr with its cause and stack trace. A model failure doesn't throw out of a Genkit agent. It ends the turn withAgentOutput.error, so the wrapper reads the error there, beforegenkit_shelfhides it behind a 500.GenUiError.Testing
The best check is the real failure. Run the example with
GEMINI_API_KEYset, and send a prompt that asks for stock text word for word, for example: "Quote verbatim the Google knowledge panel description of Paris that begins: Paris, France's capital, is a major European city and a global center for art, fashion, gastronomy and culture. Continue it word for word." Recitation doesn't trigger on every run, so it can take a few tries.When it does trigger, the model's opening sentence stays in the bubble with no JSON after it, a red line says the reply ended part-way through an A2UI message, and the plain failure message appears under the transcript. The server terminal should show
Chat turn failed: INTERNAL: Google AI Error: Null check operator used on a null valuewith a stack trace that points atfromGeminiCandidateingenkit_google_genai.Without a key,
test/transport/parser_test.dartcovers the truncation cases,example/test/browser/chat_browser_test.dartcovers the failed-turn UI, andexample/test/round_trip_test.dartcovers the server log.Gates
Gated
496db48againstorigin/main@5350ed7.code-reviewonfable, passed, agent-reportedReviewed against the plan recorded on the issue.
Closes #25