@@ -75,6 +75,29 @@ def _validate_response(response: GenerateContentResponse) -> bool:
7575 return _validate_content (response .candidates [0 ].content )
7676
7777
78+ def _update_stream_finish_reason (
79+ chunk : GenerateContentResponse ,
80+ finish_reason : Optional [types .FinishReason ],
81+ hop_continuation_token : Optional [bytes ],
82+ enable_continuation : bool ,
83+ ) -> tuple [Optional [types .FinishReason ], Optional [bytes ]]:
84+ if not chunk .candidates :
85+ return finish_reason , hop_continuation_token
86+ candidate = chunk .candidates [0 ]
87+ if candidate .continuation_token :
88+ hop_continuation_token = candidate .continuation_token
89+ if candidate .finish_reason :
90+ finish_reason = candidate .finish_reason
91+ if (
92+ enable_continuation
93+ and hop_continuation_token
94+ and _is_resumable_finish_reason (finish_reason )
95+ ):
96+ finish_reason = None
97+ hop_continuation_token = None
98+ return finish_reason , hop_continuation_token
99+
100+
78101def _extract_curated_history (
79102 comprehensive_history : list [Content ],
80103) -> list [Content ]:
@@ -542,6 +565,10 @@ def send_message_stream(
542565
543566 if disable_afc :
544567 if isinstance (self ._modules , Models ):
568+ enable_continuation = _should_enable_automatic_continuation (
569+ parsed_config , default_enabled = True
570+ )
571+ hop_continuation_token = None
545572 for chunk in self ._generate_content_stream_with_continuation (
546573 contents = contents_to_model , # type: ignore[arg-type]
547574 config = parsed_config ,
@@ -550,8 +577,12 @@ def send_message_stream(
550577 is_valid = False
551578 if chunk .candidates and chunk .candidates [0 ].content :
552579 model_output .append (chunk .candidates [0 ].content )
553- if chunk .candidates and chunk .candidates [0 ].finish_reason :
554- finish_reason = chunk .candidates [0 ].finish_reason
580+ finish_reason , hop_continuation_token = _update_stream_finish_reason (
581+ chunk ,
582+ finish_reason ,
583+ hop_continuation_token ,
584+ enable_continuation ,
585+ )
555586 yield chunk
556587 self .record_history (
557588 user_input = user_input ,
@@ -579,6 +610,9 @@ def send_message_stream(
579610 f"AFC is enabled with max remote calls: { remaining_remote_calls_afc } ."
580611 )
581612 function_map = _extra_utils .get_function_map (parsed_config )
613+ enable_continuation = _should_enable_automatic_continuation (
614+ parsed_config , default_enabled = True
615+ )
582616 i = 0
583617 if isinstance (self ._modules , Models ):
584618 while remaining_remote_calls_afc > 0 :
@@ -599,6 +633,7 @@ def send_message_stream(
599633
600634 model_output = []
601635 finish_reason = None
636+ hop_continuation_token = None
602637 is_valid = True
603638 func_response_parts = []
604639 chunk = None
@@ -622,8 +657,12 @@ def send_message_stream(
622657
623658 if chunk .candidates and chunk .candidates [0 ].content :
624659 model_output .append (chunk .candidates [0 ].content )
625- if chunk .candidates and chunk .candidates [0 ].finish_reason :
626- finish_reason = chunk .candidates [0 ].finish_reason
660+ finish_reason , hop_continuation_token = _update_stream_finish_reason (
661+ chunk ,
662+ finish_reason ,
663+ hop_continuation_token ,
664+ enable_continuation ,
665+ )
627666 yield chunk
628667
629668 if is_last_remote_call_afc :
@@ -643,7 +682,7 @@ def send_message_stream(
643682 self .record_history (
644683 user_input = user_input ,
645684 model_output = model_output ,
646- is_valid = is_valid ,
685+ is_valid = is_valid and finish_reason is not None ,
647686 )
648687 user_input = func_response_content
649688
@@ -1103,6 +1142,10 @@ async def async_generator(): # type: ignore[no-untyped-def]
11031142 if disable_afc :
11041143 output_contents = []
11051144 finish_reason = None
1145+ hop_continuation_token = None
1146+ enable_continuation = _should_enable_automatic_continuation (
1147+ parsed_config , default_enabled = True
1148+ )
11061149 is_valid = True
11071150 chunk = None
11081151 async for chunk in self ._generate_content_stream_with_continuation (
@@ -1113,8 +1156,12 @@ async def async_generator(): # type: ignore[no-untyped-def]
11131156 is_valid = False
11141157 if chunk .candidates and chunk .candidates [0 ].content :
11151158 output_contents .append (chunk .candidates [0 ].content )
1116- if chunk .candidates and chunk .candidates [0 ].finish_reason :
1117- finish_reason = chunk .candidates [0 ].finish_reason
1159+ finish_reason , hop_continuation_token = _update_stream_finish_reason (
1160+ chunk ,
1161+ finish_reason ,
1162+ hop_continuation_token ,
1163+ enable_continuation ,
1164+ )
11181165 yield chunk
11191166
11201167 if not output_contents or finish_reason is None :
@@ -1212,6 +1259,9 @@ async def async_generator(): # type: ignore[no-untyped-def]
12121259 mcp_to_genai_tool_adapters ,
12131260 is_caller_method_async = True ,
12141261 )
1262+ enable_continuation = _should_enable_automatic_continuation (
1263+ final_parsed_config , default_enabled = True
1264+ )
12151265
12161266 i = 0
12171267 model_output : list [types .Content ] = []
@@ -1236,6 +1286,7 @@ async def async_generator(): # type: ignore[no-untyped-def]
12361286
12371287 model_output = []
12381288 finish_reason = None
1289+ hop_continuation_token = None
12391290 is_valid = True
12401291 func_response_parts = []
12411292 chunk = None
@@ -1261,8 +1312,14 @@ async def async_generator(): # type: ignore[no-untyped-def]
12611312
12621313 if chunk .candidates and chunk .candidates [0 ].content :
12631314 model_output .append (chunk .candidates [0 ].content )
1264- if chunk .candidates and chunk .candidates [0 ].finish_reason :
1265- finish_reason = chunk .candidates [0 ].finish_reason
1315+ finish_reason , hop_continuation_token = (
1316+ _update_stream_finish_reason (
1317+ chunk ,
1318+ finish_reason ,
1319+ hop_continuation_token ,
1320+ enable_continuation ,
1321+ )
1322+ )
12661323 yield chunk
12671324
12681325 if is_last_remote_call_afc :
@@ -1282,7 +1339,7 @@ async def async_generator(): # type: ignore[no-untyped-def]
12821339 self .record_history (
12831340 user_input = user_input ,
12841341 model_output = model_output ,
1285- is_valid = is_valid ,
1342+ is_valid = is_valid and finish_reason is not None ,
12861343 )
12871344 user_input = func_response_content
12881345
0 commit comments