1414 ThreadItemUpdated ,
1515 ThreadMetadata ,
1616 ThreadStreamEvent ,
17- WidgetItem ,
1817)
1918from google .adk .events import Event
2019
2120from ._client_tool_call import ClientToolCallState
22- from ._constants import CLIENT_TOOL_KEY_IN_TOOL_RESPONSE , WIDGET_KEY_IN_TOOL_RESPONSE
21+ from ._constants import CLIENT_TOOL_KEY_IN_TOOL_RESPONSE
22+ from ._context import ADKAgentContext
23+ from ._event_utils import AsyncQueueIterator , EventWrapper , merge_generators
2324
2425
25- async def stream_agent_response (
26+ async def _handle_function_response (
27+ event : Event ,
2628 thread : ThreadMetadata ,
29+ ) -> AsyncGenerator [ThreadItemDoneEvent , None ]:
30+ if fn_responses := event .get_function_responses ():
31+ for fn_response in fn_responses :
32+ if not fn_response .response :
33+ continue
34+
35+ adk_client_tool : ClientToolCallState | None = fn_response .response .get (
36+ CLIENT_TOOL_KEY_IN_TOOL_RESPONSE , None
37+ )
38+ if adk_client_tool :
39+ yield ThreadItemDoneEvent (
40+ item = ClientToolCallItem (
41+ id = event .id ,
42+ thread_id = thread .id ,
43+ name = adk_client_tool .name ,
44+ arguments = adk_client_tool .arguments ,
45+ status = adk_client_tool .status ,
46+ created_at = datetime .fromtimestamp (event .timestamp ),
47+ call_id = adk_client_tool .id ,
48+ ),
49+ )
50+
51+
52+ async def stream_agent_response (
53+ context : ADKAgentContext ,
2754 adk_response : AsyncGenerator [Event , None ],
2855) -> AsyncIterator [ThreadStreamEvent ]:
29- if adk_response is None :
30- return
31-
56+ queue_iterator = AsyncQueueIterator (context ._events )
3257 response_id = str (uuid .uuid4 ())
3358
59+ thread = context .thread
60+
3461 content_index = 0
35- async for event in adk_response :
62+ async for event in merge_generators (adk_response , queue_iterator ):
63+ if event is None :
64+ continue
65+
66+ if isinstance (event , EventWrapper ):
67+ yield event .event
68+ continue
69+
3670 if event .content is None :
3771 # we need to throw item added event first
3872 yield ThreadItemAddedEvent (
@@ -53,38 +87,8 @@ async def stream_agent_response(
5387 ),
5488 )
5589 else :
56- # Since Widgets are recorded in the function responses
57- # they are handled here
58- if fn_responses := event .get_function_responses ():
59- for fn_response in fn_responses :
60- if not fn_response .response :
61- continue
62- widget = fn_response .response .get (WIDGET_KEY_IN_TOOL_RESPONSE , None )
63- if widget :
64- # No Streaming for Widgets for now
65- yield ThreadItemDoneEvent (
66- item = WidgetItem (
67- id = str (uuid .uuid4 ()),
68- thread_id = thread .id ,
69- created_at = datetime .fromtimestamp (event .timestamp ),
70- widget = widget ,
71- )
72- )
73- adk_client_tool : ClientToolCallState | None = fn_response .response .get (
74- CLIENT_TOOL_KEY_IN_TOOL_RESPONSE , None
75- )
76- if adk_client_tool :
77- yield ThreadItemDoneEvent (
78- item = ClientToolCallItem (
79- id = event .id ,
80- thread_id = thread .id ,
81- name = adk_client_tool .name ,
82- arguments = adk_client_tool .arguments ,
83- status = adk_client_tool .status ,
84- created_at = datetime .fromtimestamp (event .timestamp ),
85- call_id = adk_client_tool .id ,
86- ),
87- )
90+ async for item in _handle_function_response (event , thread ):
91+ yield item
8892
8993 if event .content .parts :
9094 text_from_final_update = ""
@@ -116,3 +120,9 @@ async def stream_agent_response(
116120 created_at = datetime .fromtimestamp (event .timestamp ),
117121 )
118122 )
123+
124+ context ._complete ()
125+
126+ # Drain remaining events
127+ async for event in queue_iterator :
128+ yield event .event
0 commit comments