Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/google/adk/agents/live_request_queue.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -57,6 +57,14 @@ class LiveRequest(BaseModel):
activity_start > activity_end > blob > content. state_delta, if set, is always
applied regardless of the other fields.
"""
audio_stream_end: Optional[bool] = None
"""If set to True, signal that the audio stream has ended (e.g. microphone
turned off) to force flush buffered audio with VAD enabled.

When multiple fields are set, they are processed by priority (highest first):
activity_start > activity_end > audio_stream_end > blob > content.
state_delta, if set, is always applied regardless of the other fields.
"""
close: bool = False
"""If set, close the queue. queue.shutdown() is only supported in Python 3.13+."""

Expand DownExpand Up@@ -92,6 +100,10 @@ def send_activity_end(self) -> None:
"""Sends an activity end signal to mark the end of user input."""
self._queue.put_nowait(LiveRequest(activity_end=types.ActivityEnd()))

def send_audio_stream_end(self) -> None:
"""Sends an audio stream end signal to force flush buffered audio with VAD."""
self._queue.put_nowait(LiveRequest(audio_stream_end=True))

def send(self, req: LiveRequest) -> None:
self._queue.put_nowait(req)

Expand Down
2 changes: 2 additions & 0 deletions src/google/adk/flows/llm_flows/base_llm_flow.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -827,6 +827,8 @@ async def _send_to_model(
await llm_connection.send_realtime(types.ActivityStart())
elif live_request.activity_end:
await llm_connection.send_realtime(types.ActivityEnd())
elif live_request.audio_stream_end:
await llm_connection.send_realtime(True)
elif live_request.blob:
# Cache input audio chunks before flushing
self.audio_cache_manager.cache_audio(
Expand Down
5 changes: 4 additions & 1 deletion src/google/adk/models/gemini_llm_connection.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -29,7 +29,7 @@

logger = logging.getLogger('google_adk.' + __name__)

RealtimeInput = Union[types.Blob, types.ActivityStart, types.ActivityEnd]
RealtimeInput = Union[types.Blob, types.ActivityStart, types.ActivityEnd, bool]
from typing import TYPE_CHECKING

if TYPE_CHECKING:
Expand DownExpand Up@@ -173,6 +173,9 @@ async def send_realtime(self, input: RealtimeInput) -> None:
elif isinstance(input, types.ActivityEnd):
logger.debug('Sending LLM activity end signal.')
await self._gemini_session.send_realtime_input(activity_end=input)
elif isinstance(input, bool) and input:
logger.debug('Sending LLM audio stream end signal.')
await self._gemini_session.send_realtime_input(audio_stream_end=True)
else:
raise ValueError('Unsupported input type: %s' % type(input))

Expand Down