Skip to content

[Gemini Live API] Expose live_session_resumption_update in Events for cross-connection session resumption #4357

@AshleyMaloney

Description

@AshleyMaloney

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_update messages 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

  1. Modifying the skip condition - Adding and not llm_response.live_session_resumption_update to the skip condition. This works but requires changes in two places (skip condition + handler). The proposed solution is cleaner.

  2. Using after_agent_callback - Doesn't fire during Gemini Live streaming sessions; the "agent turn" concept doesn't apply the same way.

  3. Using after_tool_callback to access tool_context._invocation_context.live_session_resumption_handle - Only works when tools are called, not reliable for all sessions.

  4. Using after_model_callback - Callback doesn't fire for resumption-only messages.

  5. 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_update are 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-audio via 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()
  • Event class inherits the field from LlmResponse

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:

Metadata

Metadata

Assignees

No one assigned

    Labels

    live[Component] This issue is related to live, voice and video chat

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions