From 6ce91c3eec813fc81171894b8498a8ab853a7f19 Mon Sep 17 00:00:00 2001 From: Eliot Joslin Date: Sun, 28 Jun 2026 21:25:25 -0500 Subject: [PATCH] fix(cli): resolve uncaught RuntimeError during generator exhaustion in stream_query --- src/google/adk/cli/fast_api.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/google/adk/cli/fast_api.py b/src/google/adk/cli/fast_api.py index a6e7d9f62c..00d6d42f39 100644 --- a/src/google/adk/cli/fast_api.py +++ b/src/google/adk/cli/fast_api.py @@ -835,6 +835,11 @@ async def _invoke_callable_or_raise( "OpenTelemetry tracing is not enabled. Please set the" " `OTEL_PYTHON_TRACER_PROVIDER` environment variable to enable" " tracing." + ) + + " tracing." + ) + ) @app.middleware("http") @@ -923,14 +928,16 @@ async def stream_query(request: Request): output = await _invoke_callable_or_raise(method, parsed.input or {}) if inspect.isgenerator(output): + _sentinel = object() async def _aiter_from_iter(iterator): while True: - try: - chunk = await run_in_threadpool(next, iterator) - yield chunk - except StopIteration: + # next(iterator, _sentinel) returns the sentinel object when exhausted, + # avoiding a StopIteration traceback and its PEP 479 RuntimeError conversion. + chunk = await run_in_threadpool(next, iterator, _sentinel) + if chunk is _sentinel: break + yield chunk content_iter = _aiter_from_iter(output) else: @@ -941,4 +948,4 @@ async def _aiter_from_iter(iterator): media_type="application/json", ) - return app + return app \ No newline at end of file