Skip to content

Commit cf62fdd

Browse files
caohy1988claude
andcommitted
fix: widen run-error try/except and fix traceback truncation sentinel
- Move try/except in _exec_with_plugin to cover the full run lifecycle (before_run_callback, early-exit, execution loop). Previously only the execution loop was covered, so failures in before_run_callback escaped without run-error notification or BQAA cleanup. - Fix traceback truncation: use max_len > 0 instead of bare if max_len, so -1 (no truncation sentinel) is not misinterpreted as enabled. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent bed95cb commit cf62fdd

2 files changed

Lines changed: 43 additions & 60 deletions

File tree

src/google/adk/plugins/bigquery_agent_analytics_plugin.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3541,7 +3541,7 @@ async def on_agent_error_callback(
35413541
)
35423542
)
35433543
max_len = self.config.max_content_length
3544-
if max_len and len(error_tb) > max_len:
3544+
if max_len > 0 and len(error_tb) > max_len:
35453545
error_tb = error_tb[:max_len] + "... [truncated]"
35463546

35473547
await self._log_event(
@@ -3586,7 +3586,7 @@ async def on_run_error_callback(
35863586
)
35873587
)
35883588
max_len = self.config.max_content_length
3589-
if max_len and len(error_tb) > max_len:
3589+
if max_len > 0 and len(error_tb) > max_len:
35903590
error_tb = error_tb[:max_len] + "... [truncated]"
35913591

35923592
await self._log_event(

src/google/adk/runners.py

Lines changed: 41 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -851,52 +851,40 @@ async def _exec_with_plugin(
851851

852852
plugin_manager = invocation_context.plugin_manager
853853

854-
# Step 1: Run the before_run callbacks to see if we should early exit.
855-
early_exit_result = await plugin_manager.run_before_run_callback(
856-
invocation_context=invocation_context
857-
)
858-
if isinstance(early_exit_result, types.Content):
859-
early_exit_event = Event(
860-
invocation_id=invocation_context.invocation_id,
861-
author='model',
862-
content=early_exit_result,
863-
)
864-
_apply_run_config_custom_metadata(
865-
early_exit_event, invocation_context.run_config
854+
try:
855+
# Step 1: Run the before_run callbacks to see if we should
856+
# early exit.
857+
early_exit_result = await plugin_manager.run_before_run_callback(
858+
invocation_context=invocation_context
866859
)
867-
if self._should_append_event(early_exit_event, is_live_call):
868-
await self.session_service.append_event(
869-
session=session,
870-
event=early_exit_event,
860+
if isinstance(early_exit_result, types.Content):
861+
early_exit_event = Event(
862+
invocation_id=invocation_context.invocation_id,
863+
author='model',
864+
content=early_exit_result,
871865
)
872-
yield early_exit_event
873-
else:
874-
# Step 2: Otherwise continue with normal execution
875-
# Note for live/bidi:
876-
# the transcription may arrive later than the action(function call
877-
# event and thus function response event). In this case, the order of
878-
# transcription and function call event will be wrong if we just
879-
# append as it arrives. To address this, we should check if there is
880-
# transcription going on. If there is transcription going on, we
881-
# should hold on appending the function call event until the
882-
# transcription is finished. The transcription in progress can be
883-
# identified by checking if the transcription event is partial. When
884-
# the next transcription event is not partial, it means the previous
885-
# transcription is finished. Then if there is any buffered function
886-
# call event, we should append them after this finished(non-partial)
887-
# transcription event.
888-
buffered_events: list[Event] = []
889-
is_transcribing: bool = False
866+
_apply_run_config_custom_metadata(
867+
early_exit_event, invocation_context.run_config
868+
)
869+
if self._should_append_event(early_exit_event, is_live_call):
870+
await self.session_service.append_event(
871+
session=session,
872+
event=early_exit_event,
873+
)
874+
yield early_exit_event
875+
else:
876+
# Step 2: Otherwise continue with normal execution
877+
buffered_events: list[Event] = []
878+
is_transcribing: bool = False
890879

891-
try:
892880
async with Aclosing(execute_fn(invocation_context)) as agen:
893881
async for event in agen:
894882
_apply_run_config_custom_metadata(
895883
event, invocation_context.run_config
896884
)
897-
# Step 3: Run the on_event callbacks before persisting so
898-
# callback changes are stored in the session and match the
899-
# streamed event.
885+
# Step 3: Run the on_event callbacks before persisting
886+
# so callback changes are stored in the session and
887+
# match the streamed event.
900888
modified_event = await plugin_manager.run_on_event_callback(
901889
invocation_context=invocation_context, event=event
902890
)
@@ -910,23 +898,15 @@ async def _exec_with_plugin(
910898
if event.partial and _is_transcription(event):
911899
is_transcribing = True
912900
if is_transcribing and _is_tool_call_or_response(event):
913-
# only buffer function call and function response event
914-
# which is non-partial
915901
buffered_events.append(output_event)
916902
continue
917-
# Note for live/bidi: for audio response, it's considered
918-
# as non-partial event(event.partial=None)
919-
# event.partial=False and event.partial=None are considered
920-
# as non-partial event; event.partial=True is considered as
921-
# partial event.
922903
if event.partial is not True:
923904
if _is_transcription(event) and (
924905
_has_non_empty_transcription_text(event.input_transcription)
925906
or _has_non_empty_transcription_text(
926907
event.output_transcription
927908
)
928909
):
929-
# transcription end signal, append buffered events
930910
is_transcribing = False
931911
logger.debug(
932912
'Appending transcription finished event: %s',
@@ -938,14 +918,16 @@ async def _exec_with_plugin(
938918
)
939919

940920
for buffered_event in buffered_events:
941-
logger.debug('Appending buffered event: %s', buffered_event)
921+
logger.debug(
922+
'Appending buffered event: %s',
923+
buffered_event,
924+
)
942925
await self.session_service.append_event(
943926
session=session, event=buffered_event
944927
)
945928
yield buffered_event
946929
buffered_events = []
947930
else:
948-
# non-transcription event or empty transcription event
949931
if self._should_append_event(event, is_live_call):
950932
logger.debug('Appending non-buffered event: %s', event)
951933
await self.session_service.append_event(
@@ -958,17 +940,18 @@ async def _exec_with_plugin(
958940
)
959941

960942
yield output_event
961-
except Exception as e:
962-
# Notify plugins of the unhandled execution error.
963-
# Notification-only; the exception is always re-raised.
964-
await plugin_manager.run_on_run_error_callback(
965-
invocation_context=invocation_context,
966-
error=e,
967-
)
968-
raise
943+
except Exception as e:
944+
# Notify plugins of the unhandled execution error. Covers
945+
# failures in before_run_callback, early-exit, and the main
946+
# execution loop. Notification-only; always re-raised.
947+
await plugin_manager.run_on_run_error_callback(
948+
invocation_context=invocation_context,
949+
error=e,
950+
)
951+
raise
969952

970-
# Step 4: Run the after_run callbacks to perform global cleanup tasks
971-
# or finalizing logs and metrics data.
953+
# Step 4: Run the after_run callbacks to perform global cleanup
954+
# tasks or finalizing logs and metrics data.
972955
# This does NOT emit any event. Only runs on success.
973956
await plugin_manager.run_after_run_callback(
974957
invocation_context=invocation_context

0 commit comments

Comments
 (0)