fix: filter empty-text parts in GoogleGenAiChatModel to prevent API errors (#4556)#5762
Open
anuragg-saxenaa wants to merge 1 commit intospring-projects:mainfrom
Conversation
…rrors Fixes spring-projects#4556 When the Google GenAI API returns a candidate whose parts contain no text (e.g. thought-signature-only or server-side tool-invocation parts), the response converter was producing AssistantMessages with empty content. When these empty messages were stored in chat memory and sent in subsequent requests, the Google API rejected them with 'missing parts field' errors, breaking multi-turn conversations with tool calling. Two fixes applied: 1. responseCandidateToGeneration: add filter on part.text() presence so only parts with actual text content produce generations. Uses part.text().get() after the filter guard (no orElse needed). 2. toGeminiContent: filter out Content items whose parts list is empty before building the API request, so a stale empty-content AssistantMessage in chat memory cannot cause a 400 error. Also adds two unit tests in GoogleGenAiChatModelExtendedUsageTests covering both the empty-part candidate response and the clean text-part round-trip, so regressions are caught without a live API key. Signed-off-by: anuragg-saxenaa <anuragg.saxenaa@gmail.com>
1626ee5 to
a4c5c84
Compare
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.
Problem
Fixes #4556
When using Spring AI's Google GenAI integration with tool calling and chat memory (
MessageChatMemoryAdvisor), the Google API sometimes returns candidates whose parts contain no text content (e.g. thought-signature-only parts or server-side tool invocation parts with no accompanying text).The previous code produced
AssistantMessageinstances withcontent("")for these parts. WhenMessageChatMemoryAdvisorstored these in chat history and they were sent back on subsequent requests, the Google API rejected the request with a missingpartsfield error, breaking multi-turn conversations as soon as a tool-calling turn produced any empty-text candidate parts.Root Cause
In
responseCandidateToGeneration, the stream mapped every non-toolCall/non-toolResponse part to a Generation usingpart.text().orElse("")— including parts with no text at all. These emptyAssistantMessageobjects then round-tripped throughmessageToParts, which correctly skips empty text (line 309 guard), resulting in aContentwith an emptypartslist that the API rejects.Fix
Two targeted changes to
GoogleGenAiChatModel:responseCandidateToGeneration— add a filter so only parts with actual text produce generationstoGeminiContent— filter outContentitems with empty parts before sending to the API as a defensive backstopTests
Two new unit tests in
GoogleGenAiChatModelExtendedUsageTests(no live API key required):testResponseCandidateWithEmptyTextPartsProducesNoEmptyGenerationstestToGeminiContentFiltersOutEmptyPartContent