fix(models): preserve tool_call co-delivered with turn_complete - #6618
fix(models): preserve tool_call co-delivered with turn_complete#6618patrickswedish wants to merge 1 commit into
Conversation
|
Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). View this failed invocation of the CLA check for more information. For the most up to date status, view the checks section at the bottom of the pull request. |
|
@googlebot I signed the CLA! |
|
Hi team! 👋 Just a quick heads up on this PR — it fixes two silent data-loss bugs in the live streaming receive loop that affect real-world multimodal and tool-calling use cases:
Both fixes are surgical (25 lines changed, one file), backward-compatible, and traced directly against the live API message format. Happy to add unit tests or address any review feedback. Looking forward to getting this in! 🙏 |
fafc450 to
9f57073
Compare
9f57073 to
231c7b8
Compare
In GeminiLlmConnection.receive(), when a LiveServerMessage carries both server_content.turn_complete=True and message.tool_call, the turn_complete branch previously broke out of the receive loop before the message.tool_call handler could execute, silently dropping the tool call. Restructure the control flow so all message fields (including tool_call) are processed through their standard handling semantics before finalizing turn_complete and exiting the loop. Fixes google#6615
231c7b8 to
c5e137f
Compare
|
This is a non-issue. |
|
Thanks for reviewing and providing the feedback, @wuliang229! Appreciate your time. |
Summary
Fixes #6615.
In
GeminiLlmConnection.receive(), when aLiveServerMessagecarries bothserver_content.turn_complete=Trueandmessage.tool_call, the previous control flow broke out of the receive loop before reaching the lowerif message.tool_call:handler, silently discarding the tool call.Note: Multipart text data loss (#6616) has already landed upstream via commit
2109ea96e1c7431225e57fb6db6c4c116e632867(PR #6617). This PR is now solely and cleanly focused on #6615.Root cause
The receive loop was structured as:
python async for message in agen: if message.server_content: ... if message.server_content.turn_complete: ... break # exits receive loop if message.tool_call: # unreachable when turn_complete is present ...When a single
LiveServerMessagecontains bothturn_complete=Trueandtool_call, thebreakterminated receive beforeif message.tool_call:could execute.Fix
Restructured
GeminiLlmConnection.receive()so that all message fields (includingtool_call,session_resumption_update,voice_activity, andgo_away) are processed through their standard handling semantics before finalizingturn_completeand exiting the receive loop.if message.tool_call:before evaluatingif message.server_content.turn_complete:.grounding_metadata,last_grounding_metadata,tool_call_metadata,live_session_id,model_version).Testing
pytest tests/unittests/models/test_gemini_llm_connection.py(66 / 66 passed)test_receive_preserves_tool_call_codelivered_with_turn_complete(verifies multi-function tool call preserved before turn_complete)test_receive_preserves_text_and_tool_call_codelivered_with_turn_complete(verifies text + tool_call + turn_complete ordering and content)test_receive_codelivered_tool_call_empty_function_calls(verifies empty function_calls handling)pytest tests/unittests/models/(1068 / 1068 passed)ruff,isort,pyink(Clean)uv build(Built sdist and wheel successfully)git diff --check(Clean)