@@ -305,7 +305,9 @@ def is_connected(self) -> bool:
305305 # ):
306306 # return True # Still consider connected during finalize grace period
307307
308- return self .connected and self .client is not None
308+ return (
309+ self .connected and self .client is not None and self .client .connected
310+ )
309311
310312 @override
311313 async def send_audio (
@@ -351,6 +353,8 @@ async def send_audio(
351353 return True
352354
353355 except Exception as e :
356+ if self .stopped :
357+ return False
354358 self .ten_env .log (LogLevel .ERROR , f"Error sending audio: { e } " )
355359 await self ._handle_error (e )
356360 return False
@@ -466,16 +470,32 @@ async def _handle_reconnect(self) -> None:
466470 finally :
467471 self ._reconnecting = False
468472
473+ def _result_level_asr_info_fields (
474+ self , result : ASRResponse
475+ ) -> dict [str , Any ]:
476+ """Fields from vendor `result` object that belong in metadata.asr_info.
477+
478+ Only includes keys when present on the vendor payload (e.g. prefetch).
479+ """
480+ rd = result .result
481+ if not rd or not isinstance (rd , dict ):
482+ return {}
483+ if "prefetch" not in rd :
484+ return {}
485+ return {"prefetch" : rd ["prefetch" ]}
486+
469487 def _build_metadata_with_asr_info (
470488 self ,
471489 base_metadata : dict [str , Any ] | None = None ,
472490 additional_fields : dict [str , Any ] | None = None ,
491+ result_level_fields : dict [str , Any ] | None = None ,
473492 ) -> dict [str , Any ]:
474493 """Build metadata according to protocol: session_id at root, others in asr_info.
475494
476495 Args:
477496 base_metadata: Base metadata dict (defaults to self.metadata if None)
478497 additional_fields: Additional fields to add to asr_info
498+ result_level_fields: Vendor result-level fields (e.g. prefetch) for asr_info
479499
480500 Returns:
481501 Metadata dict with structure: {"session_id": "...", "asr_info": {...}}
@@ -501,6 +521,10 @@ def _build_metadata_with_asr_info(
501521 if additional_fields :
502522 asr_info .update (additional_fields )
503523
524+ # Vendor result-level fields (e.g. prefetch under result.{prefetch})
525+ if result_level_fields :
526+ asr_info .update (result_level_fields )
527+
504528 # Build final metadata structure
505529 metadata : dict [str , Any ] = {}
506530 if session_id is not None :
@@ -510,7 +534,9 @@ def _build_metadata_with_asr_info(
510534 return metadata
511535
512536 def _extract_final_result_metadata (
513- self , utterance : Utterance
537+ self ,
538+ utterance : Utterance ,
539+ result_level_fields : dict [str , Any ] | None = None ,
514540 ) -> dict [str , Any ]:
515541 """Extract metadata from utterance additions.
516542
@@ -524,11 +550,14 @@ def _extract_final_result_metadata(
524550 additional_fields = utterance .additions
525551
526552 return self ._build_metadata_with_asr_info (
527- additional_fields = additional_fields
553+ additional_fields = additional_fields ,
554+ result_level_fields = result_level_fields ,
528555 )
529556
530557 def _extract_non_final_result_metadata (
531- self , utterance : Utterance
558+ self ,
559+ utterance : Utterance ,
560+ result_level_fields : dict [str , Any ] | None = None ,
532561 ) -> dict [str , Any ]:
533562 """Extract metadata from utterance additions for non-final results.
534563
@@ -550,7 +579,8 @@ def _extract_non_final_result_metadata(
550579 additional_fields ["source" ] = additions ["source" ]
551580
552581 return self ._build_metadata_with_asr_info (
553- additional_fields = additional_fields
582+ additional_fields = additional_fields ,
583+ result_level_fields = result_level_fields ,
554584 )
555585
556586 def _calculate_utterance_start_ms (
@@ -719,6 +749,8 @@ async def _on_asr_result(self, result: ASRResponse) -> None:
719749 category = LOG_CATEGORY_VENDOR ,
720750 )
721751
752+ result_level_asr_info = self ._result_level_asr_info_fields (result )
753+
722754 # Process utterances: send definite=true individually,
723755 # and concatenate adjacent definite=false utterances together
724756 if not result .utterances :
@@ -728,7 +760,9 @@ async def _on_asr_result(self, result: ASRResponse) -> None:
728760 result .start_ms
729761 )
730762 # Build metadata according to protocol: session_id at root, others in asr_info
731- metadata = self ._build_metadata_with_asr_info ()
763+ metadata = self ._build_metadata_with_asr_info (
764+ result_level_fields = result_level_asr_info
765+ )
732766 await self ._send_asr_result_from_text (
733767 text = result .text ,
734768 is_final = False ,
@@ -767,11 +801,13 @@ async def _on_asr_result(self, result: ASRResponse) -> None:
767801 if is_final :
768802 has_final_result = True
769803 metadata = self ._extract_final_result_metadata (
770- utterance
804+ utterance ,
805+ result_level_fields = result_level_asr_info ,
771806 )
772807 else :
773808 metadata = self ._extract_non_final_result_metadata (
774- utterance
809+ utterance ,
810+ result_level_fields = result_level_asr_info ,
775811 )
776812
777813 await self ._send_asr_result_from_text (
@@ -816,10 +852,14 @@ async def _on_asr_result(self, result: ASRResponse) -> None:
816852 "start_time" : first .start_time ,
817853 "duration_ms" : last .end_time - first .start_time ,
818854 "metadata" : (
819- self ._extract_final_result_metadata (last )
855+ self ._extract_final_result_metadata (
856+ last ,
857+ result_level_fields = result_level_asr_info ,
858+ )
820859 if is_final
821860 else self ._extract_non_final_result_metadata (
822- last
861+ last ,
862+ result_level_fields = result_level_asr_info ,
823863 )
824864 ),
825865 "utterance" : last , # Keep reference for timestamp tracking
0 commit comments