Skip to content

Commit 4340208

Browse files
wuliang229copybara-github
authored andcommitted
fix: remove live event buffering in runner
Keep the ADK events in their original order as they arrive. In the original code, if the output transcriptions are long, the function call and response events are only appended at the very end of transcription. If any downstream program consumes the events, they are in the wrong order. Co-authored-by: Liang Wu <wuliang@google.com> PiperOrigin-RevId: 933812997
1 parent 054da5d commit 4340208

2 files changed

Lines changed: 254 additions & 317 deletions

File tree

src/google/adk/runners.py

Lines changed: 8 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -106,10 +106,6 @@ def _find_active_task_isolation_scope(session) -> Optional[str]:
106106
return None
107107

108108

109-
def _is_tool_call_or_response(event: Event) -> bool:
110-
return bool(event.get_function_calls() or event.get_function_responses())
111-
112-
113109
def _get_function_responses_from_content(
114110
content: types.Content,
115111
) -> list[types.FunctionResponse]:
@@ -120,21 +116,6 @@ def _get_function_responses_from_content(
120116
]
121117

122118

123-
def _is_transcription(event: Event) -> bool:
124-
return (
125-
event.input_transcription is not None
126-
or event.output_transcription is not None
127-
)
128-
129-
130-
def _has_non_empty_transcription_text(
131-
transcription: types.Transcription,
132-
) -> bool:
133-
return bool(
134-
transcription and transcription.text and transcription.text.strip()
135-
)
136-
137-
138119
def _apply_run_config_custom_metadata(
139120
event: Event, run_config: RunConfig | None
140121
) -> None:
@@ -1393,22 +1374,6 @@ async def _exec_with_plugin(
13931374
yield early_exit_event
13941375
else:
13951376
# Step 2: Otherwise continue with normal execution
1396-
# Note for live/bidi:
1397-
# the transcription may arrive later than the action(function call
1398-
# event and thus function response event). In this case, the order of
1399-
# transcription and function call event will be wrong if we just
1400-
# append as it arrives. To address this, we should check if there is
1401-
# transcription going on. If there is transcription going on, we
1402-
# should hold on appending the function call event until the
1403-
# transcription is finished. The transcription in progress can be
1404-
# identified by checking if the transcription event is partial. When
1405-
# the next transcription event is not partial, it means the previous
1406-
# transcription is finished. Then if there is any buffered function
1407-
# call event, we should append them after this finished(non-partial)
1408-
# transcription event.
1409-
buffered_events: list[Event] = []
1410-
is_transcribing: bool = False
1411-
14121377
async with aclosing(execute_fn(invocation_context)) as agen:
14131378
async for event in agen:
14141379
_apply_run_config_custom_metadata(
@@ -1426,50 +1391,14 @@ async def _exec_with_plugin(
14261391
)
14271392

14281393
if is_live_call:
1429-
if event.partial and _is_transcription(event):
1430-
is_transcribing = True
1431-
if is_transcribing and _is_tool_call_or_response(event):
1432-
# only buffer function call and function response event which is
1433-
# non-partial
1434-
buffered_events.append(output_event)
1435-
continue
1436-
# Note for live/bidi: for audio response, it's considered as
1437-
# non-partial event(event.partial=None)
1438-
# event.partial=False and event.partial=None are considered as
1439-
# non-partial event; event.partial=True is considered as partial
1440-
# event.
1441-
if event.partial is not True:
1442-
if _is_transcription(event) and (
1443-
_has_non_empty_transcription_text(event.input_transcription)
1444-
or _has_non_empty_transcription_text(
1445-
event.output_transcription
1446-
)
1447-
):
1448-
# transcription end signal, append buffered events
1449-
is_transcribing = False
1450-
logger.debug(
1451-
'Appending transcription finished event: %s', event
1452-
)
1453-
if self._should_append_event(event, is_live_call):
1454-
await self.session_service.append_event(
1455-
session=invocation_context.session, event=output_event
1456-
)
1457-
1458-
for buffered_event in buffered_events:
1459-
logger.debug('Appending buffered event: %s', buffered_event)
1460-
await self.session_service.append_event(
1461-
session=invocation_context.session, event=buffered_event
1462-
)
1463-
yield buffered_event # yield buffered events to caller
1464-
buffered_events = []
1465-
else:
1466-
# non-transcription event or empty transcription event, for
1467-
# example, event that stores blob reference, should be appended.
1468-
if self._should_append_event(event, is_live_call):
1469-
logger.debug('Appending non-buffered event: %s', event)
1470-
await self.session_service.append_event(
1471-
session=invocation_context.session, event=output_event
1472-
)
1394+
# Skip partial transcriptions for Live
1395+
if event.partial is not True and self._should_append_event(
1396+
event, is_live_call
1397+
):
1398+
logger.debug('Appending live event: %s', output_event)
1399+
await self.session_service.append_event(
1400+
session=invocation_context.session, event=output_event
1401+
)
14731402
else:
14741403
if event.partial is not True:
14751404
await self.session_service.append_event(

0 commit comments

Comments
 (0)