-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Description
Is your feature request related to a specific problem?
Yes. When building voice assistants with Gemini Live API via run_live(), we cannot implement cross-WebSocket-connection session resumption.
The problem:
- User connects via WebSocket →
run_live()starts a Gemini Live session - User has a conversation, Gemini sends
live_session_resumption_updatemessages with handles - ADK receives and logs these:
Update session resumption handle: new_handle='...' resumable=True - User's connection drops (network switch, browser refresh, mobile app backgrounded)
- User reconnects via new WebSocket → new
run_live()invocation - We cannot pass the previous handle because ADK never exposed it to us
The Gemini Live API documentation describes session resumption as a key feature for production applications, but ADK's current implementation only handles resumption within a single run_live() call (for Gemini's ~10 minute connection limits), not across separate run_live() invocations.
Describe the solution you'd like
Expose live_session_resumption_update in Events so applications can capture, persist, and reuse the handle.
Root cause: In flows/llm_flows/base_llm_flow.py, the _postprocess_live method has a skip condition that discards events without content. When llm_response contains only live_session_resumption_update (no content, transcription, etc.), the event is discarded before it can be yielded.
Proposed fix: Add a handler for live_session_resumption_update before the skip condition, following the same pattern used for transcription events. In _postprocess_live, add this block after the processor loop and before the skip condition:
# Runs processors.
async with Aclosing(
self._postprocess_run_processors_async(invocation_context, llm_response)
) as agen:
async for event in agen:
yield event
# Handle session resumption updates for cross-connection resumption
# (Must be before skip condition - resumption updates have no content)
if llm_response.live_session_resumption_update:
model_response_event.live_session_resumption_update = (
llm_response.live_session_resumption_update
)
yield model_response_event
return
# Skip the model response event if there is no content and no error code.
# ... existing skip condition ...This follows ADK's existing pattern for handling transcription events - yield the event early and return before the skip condition can discard it.
Expected usage:
async for event in runner.run_live(user_id, session_id, queue, run_config):
# Capture handle when received
if event.live_session_resumption_update:
handle = event.live_session_resumption_update.new_handle
await persist_to_session_state(session_id, handle)
# ... handle other events
# On reconnection, pass the saved handle
run_config = RunConfig(
session_resumption=types.SessionResumptionConfig(handle=saved_handle)
)Describe alternatives you've considered
-
Modifying the skip condition - Adding
and not llm_response.live_session_resumption_updateto the skip condition. This works but requires changes in two places (skip condition + handler). The proposed solution is cleaner. -
Using
after_agent_callback- Doesn't fire during Gemini Live streaming sessions; the "agent turn" concept doesn't apply the same way. -
Using
after_tool_callbackto accesstool_context._invocation_context.live_session_resumption_handle- Only works when tools are called, not reliable for all sessions. -
Using
after_model_callback- Callback doesn't fire for resumption-only messages. -
Patching ADK locally - Works (we've tested this) but not maintainable across upgrades.
How does this feature impact your work?
Critical for production voice assistants. Our application serves users who:
- Switch networks (WiFi → cellular)
- Refresh browser tabs
- Background mobile apps briefly
- Experience brief connectivity drops
Users expect conversation continuity. Currently, every reconnection starts a fresh session with no memory of the previous conversation, creating a poor user experience.
Timeline: We've implemented and tested a local patch. Would like to contribute this upstream.
Would you be willing to submit a PR for this feature?
Yes. We have a working implementation. Happy to submit a PR with:
- The code change (8 lines, following existing transcription pattern)
- Unit test verifying events with
live_session_resumption_updateare yielded - Documentation update in adk-docs repo
Additional context
Environment:
- ADK Version: 1.22.1
- Python: 3.11
- Model:
gemini-live-2.5-flash-native-audiovia Vertex AI - Use case: Production voice assistant with WebSocket-based frontend
ADK already handles the hard parts:
- Receiving the handle from Gemini ✓
- Storing it in
InvocationContext.live_session_resumption_handle✓ - Logging it:
Update session resumption handle: new_handle='...'✓ - Using it for internal reconnection within
run_live()✓ Eventclass inherits the field fromLlmResponse✓
The only missing piece is yielding the event so applications can persist the handle for cross-connection resumption.
We've tested this fix - it correctly exposes the resumption handle in events, allowing us to persist it and pass it on reconnection via SessionResumptionConfig(handle=saved_handle).
Related documentation: