Description
Function/tool calling does not work in live (bidirectional streaming) mode when using Gemini 3.1 Flash Live models (e.g., gemini-3.1-flash-live-preview). The model correctly issues tool calls, but they are never executed by the framework, causing the conversation to hang indefinitely.
Root Cause
In GeminiLlmConnection.receive(), tool call parts received via message.tool_call (LiveServerToolCall) are accumulated into tool_call_parts but only yielded in two cases:
- When
turn_complete is received
- When the receive loop exits
Gemini 3.1 Flash Live models send tool calls via LiveServerToolCall and do not emit turn_complete until they receive the tool response. This creates a deadlock:
- Model sends tool call → accumulated in
tool_call_parts, not yielded
- Framework waits for
turn_complete to yield the tool call event
- Model waits for tool response before sending
turn_complete
- Neither side makes progress
This works with earlier Gemini 2.x models because they either send tool calls differently or send turn_complete immediately after the tool call.
Steps to Reproduce
- Create an agent with any
FunctionTool
- Use
gemini-3.1-flash-live-preview as the model
- Start a live session with
runner.run_live()
- Send a message that triggers a tool call
- Observe: the tool call is received by the ADK (visible in debug logs) but the tool never executes, and the model never responds
Expected Behavior
Tool calls should be yielded immediately so the framework can execute them and send responses back to the model.
Proposed Fix
Yield tool_call_parts immediately after receiving message.tool_call instead of deferring until turn_complete. This is safe because:
- The existing
turn_complete yield path handles the case where tool_call_parts is empty (no-op)
- The post-loop yield path similarly becomes a no-op
- Earlier models that do send
turn_complete after tool calls will still work correctly
Environment
google-adk version: 1.31.0
- Model:
gemini-3.1-flash-live-preview
- Python: 3.13
Description
Function/tool calling does not work in live (bidirectional streaming) mode when using Gemini 3.1 Flash Live models (e.g.,
gemini-3.1-flash-live-preview). The model correctly issues tool calls, but they are never executed by the framework, causing the conversation to hang indefinitely.Root Cause
In
GeminiLlmConnection.receive(), tool call parts received viamessage.tool_call(LiveServerToolCall) are accumulated intotool_call_partsbut only yielded in two cases:turn_completeis receivedGemini 3.1 Flash Live models send tool calls via
LiveServerToolCalland do not emitturn_completeuntil they receive the tool response. This creates a deadlock:tool_call_parts, not yieldedturn_completeto yield the tool call eventturn_completeThis works with earlier Gemini 2.x models because they either send tool calls differently or send
turn_completeimmediately after the tool call.Steps to Reproduce
FunctionToolgemini-3.1-flash-live-previewas the modelrunner.run_live()Expected Behavior
Tool calls should be yielded immediately so the framework can execute them and send responses back to the model.
Proposed Fix
Yield
tool_call_partsimmediately after receivingmessage.tool_callinstead of deferring untilturn_complete. This is safe because:turn_completeyield path handles the case wheretool_call_partsis empty (no-op)turn_completeafter tool calls will still work correctlyEnvironment
google-adkversion: 1.31.0gemini-3.1-flash-live-preview