Skip to content

AsyncLiveSession.receive() breaks out of loop after first turn_complete, breaking multi-turn conversations #2244

@sanjay-voxomos

Description

@sanjay-voxomos

Name: google-genai
Version: 1.70.0
Summary: GenAI Python SDK
Home-page: https://github.com/googleapis/python-genai
Author:
Author-email: Google LLC googleapis-packages@google.com
License-Expression: Apache-2.0

Summary
AsyncLiveSession.receive() internally calls break after yielding the first turn_complete message. In multi-turn voice applications that call async for msg in session.receive() once for the entire session lifetime, this silently exits the receive loop after the first turn — causing the bot to go permanently silent after its first response.

SDK version

google-genai ==
Check with: pip show google-genai

Affected code
live.py lines ~456–459:

async def receive(self) -> AsyncIterator[types.LiveServerMessage]:
while result := await self._receive():
if result.server_content and result.server_content.turn_complete:
yield result
break # <-- exits after first turn_complete
yield result
Steps to reproduce

async with client.aio.live.connect(model=model, config=config) as session:
# Send turn 1
await session.send_realtime_input(activity_start=types.ActivityStart())
await session.send_realtime_input(audio=types.Blob(data=pcm, mime_type="audio/pcm;rate=16000"))
await session.send_realtime_input(activity_end=types.ActivityEnd())

# Iterate receive() for the entire session lifetime
async for msg in session.receive():
    sc = msg.server_content
    if sc and sc.turn_complete:
        print("Turn 1 complete")
        # Now send turn 2...
        await session.send_realtime_input(activity_start=types.ActivityStart())
        await session.send_realtime_input(audio=types.Blob(data=pcm2, mime_type="audio/pcm;rate=16000"))
        await session.send_realtime_input(activity_end=types.ActivityEnd())
        # ← No more messages ever arrive — receive() loop has already exited

Expected behaviour
receive() should continue yielding messages across multiple turns for the lifetime of the session, since a Live session is a persistent bidirectional connection designed for multi-turn conversations.

Actual behaviour
After the first turn_complete is yielded, the async for loop exits silently. Any audio or messages sent for subsequent turns are never received, making multi-turn conversations impossible using receive().

Workaround
Call _receive() directly in a while True loop:

while True:
message = await session._receive()
if message is None:
break
# process message...
This is not ideal as _receive() is a private method. The fix should be in receive() itself.

Suggested fix
Either:

Remove the break so receive() continues across turns, or
Add a multi_turn=True parameter (default False for backwards compatibility) that skips the break, or
Document clearly that receive() only covers a single turn and a separate receive_all() / receive_stream() method should be used for multi-turn sessions.
Model tested
gemini-3.1-flash-live-preview
gemini-2.0-flash-live-001

Metadata

Metadata

Labels

priority: p2Moderately-important priority. Fix may not be included in next release.type: bugError or flaw in code with unintended results or allowing sub-optimal usage patterns.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions