
    /j)                    N   S SK Jr  S SKrS SKrS SKrS SKJr  S SKJr  S SKJ	r	J
r
Jr  SSKJrJr  SSKJr  SS	KJrJrJrJr  S
SKJr  S
SKJrJrJr  S
SKJrJr  \" S \R>                  S9r \ " S S5      5       r!\ " S S5      5       r" " S S\\S      5      r# " S S\5      r$g)    )annotationsN)AsyncIterable)	dataclass)AnyClassVarLiteral   )APIConnectionErrorAPIError)logger)DEFAULT_API_CONNECT_OPTIONS	NOT_GIVENAPIConnectOptions
NotGivenOr   )ChatContext)LLM	ChatChunk	LLMStream)Tool
ToolChoice)	max_retrytimeoutc                  *    \ rS rSr% S\S'   S\S'   Srg)
_LLMStatus   bool	availablezasyncio.Task[None] | Nonerecovering_task N__name__
__module____qualname____firstlineno____annotations____static_attributes__r        T/app/agent/.venv/lib/python3.13/site-packages/livekit/agents/llm/fallback_adapter.pyr   r      s    O..r(   r   c                  *    \ rS rSr% S\S'   S\S'   Srg)AvailabilityChangedEvent   r   llmr   r   r    Nr!   r    r(   r)   r+   r+      s    	HOr(   r+   c                     ^  \ rS rSrSSSSS.           SU 4S jjjr\SS j5       r\SS	 j5       rS
\\	\	\	S.             SS jjr
SS jrSS jrSrU =r$ )FallbackAdapter"   g      @r   g      ?F)attempt_timeoutmax_retry_per_llmretry_intervalretry_on_chunk_sentc               N  > [        U5      S:  a  [        S5      e[        TU ]  5         Xl        X l        X0l        X@l        XPl        U R                   Vs/ s H  n[        SSS9PM     snU l
        U R                   H  nUR                  SU R                  5        M!     gs  snf )a  FallbackAdapter is an LLM that can fallback to a different LLM if the current LLM fails.

Args:
    llm (list[LLM]): List of LLM instances to fallback to.
    attempt_timeout (float, optional): Timeout for each LLM attempt. Defaults to 5.0.
    max_retry_per_llm (int, optional): Internal retries per LLM. Defaults to 0, which means no
        internal retries, the failed LLM will be skipped and the next LLM will be used.
    retry_interval (float, optional): Interval between retries. Defaults to 0.5.
    retry_on_chunk_sent (bool, optional): Whether to retry when a LLM failed after chunks
        are sent. Defaults to False.

Raises:
    ValueError: If no LLM instances are provided.
r   z+at least one LLM instance must be provided.TN)r   r   metrics_collected)len
ValueErrorsuper__init___llm_instances_attempt_timeout_max_retry_per_llm_retry_interval_retry_on_chunk_sentr   _statuson_on_metrics_collected)	selfr-   r1   r2   r3   r4   _llm_instance	__class__s	           r)   r:   FallbackAdapter.__init__%   s    0 s8a<JKK! /"3-$7! GKFYFY
FYJt<FY
 !//LOO/1K1KL 0	
s   B"c                    g)Nr/   r    rC   s    r)   modelFallbackAdapter.modelO   s     r(   c                    g)Nlivekitr    rI   s    r)   providerFallbackAdapter.providerS   s    r(   N)toolsconn_optionsparallel_tool_callstool_choiceextra_kwargsc          
     2    [        U UUU=(       d    / UUUS9$ )N)r-   rQ   chat_ctxrP   rR   rS   rT   )FallbackLLMStream)rC   rV   rP   rQ   rR   rS   rT   s          r)   chatFallbackAdapter.chatW   s*     !%+2 3#%
 	
r(   c                j   #    U R                    H  nUR                  SU R                  5        M!     g 7fNr6   )r;   offrB   )rC   rE   s     r)   acloseFallbackAdapter.aclosek   s,      //L0$2L2LM 0s   13c                0    U R                   " S/UQ70 UD6  g r[   )emit)rC   argskwargss      r)   rB   %FallbackAdapter._on_metrics_collectedo   s    		%777r(   )r<   r;   r=   r>   r?   r@   )r-   z	list[LLM]r1   floatr2   intr3   rd   r4   r   returnNone)rf   str)rV   r   rP   zlist[Tool] | NonerQ   r   rR   NotGivenOr[bool]rS   NotGivenOr[ToolChoice]rT   NotGivenOr[dict[str, Any]]rf   r   rf   rg   )ra   r   rb   r   rf   rg   )r"   r#   r$   r%   r:   propertyrJ   rN   $DEFAULT_FALLBACK_API_CONNECT_OPTIONSr   rX   r]   rB   r'   __classcell__rF   s   @r)   r/   r/   "   s     "%!" #$)(M(M 	(M (M (M "(M 
(M (MT ! !   $(*N09.73<
 
 !	

 (
 .
 ,
 1
 

(N8 8r(   r/   llm_availability_changedc                     ^  \ rS rSr% SrS\S'   \\\S.               SU 4S jjjr\SS j5       r	\SS j5       r
S	S
.     SS jjrSS jrSS jrSS jrSrU =r$ )rW   s   llm_fallback_adapterzClassVar[str]_llm_request_span_name)rR   rS   rT   c               `   > [         TU ]  XX4S9  Xl        XPl        X`l        Xpl        S U l        g )N)rV   rP   rQ   )r9   r:   _fallback_adapter_parallel_tool_calls_tool_choice_extra_kwargs_current_stream)	rC   r-   rV   rP   rQ   rR   rS   rT   rF   s	           r)   r:   FallbackLLMStream.__init__v   s7     	uX!$$7!')15r(   c                `    U R                   c  U R                  $ U R                   R                  $ N)r{   	_chat_ctxrV   rI   s    r)   rV   FallbackLLMStream.chat_ctx   s*    '>>!##,,,r(   c                `    U R                   c  U R                  $ U R                   R                  $ r~   )r{   _toolsrP   rI   s    r)   rP   FallbackLLMStream.tools   s*    ';;##)))r(   F)check_recoveryc              D  #     UR                  U R                  U R                  U R                  U R                  U R
                  [        R                  " U R                  U R                  R                  U R                  R                  U R                  R                  S9S9 ISh  vN nU(       + nU  Sh  vN nU(       a  SnX0l        U7v   M   N, N
 SSS5      ISh  vN    g! , ISh  vN  (       d  f       g= f! [        R                   aP    U(       a$  [         R"                  " UR$                   S35        e [         R"                  " UR$                   S35        e [&         aR  nU(       a#  [         R"                  " UR$                   S3US9  e [         R"                  " UR$                   S	3US9  e SnAf[(         aP    U(       a$  [         R*                  " UR$                   S
35        e [         R*                  " UR$                   S35        e f = f7f)a7  
Try to generate with the given LLM.

Args:
    llm: The LLM instance to generate with
    check_recovery: When True, indicates this is a background recovery check and the
                  result will not be used. Recovery checks verify if a previously
                  failed LLM has become available again.
)r   r   r3   )rV   rP   rR   rS   rT   rQ   NFz recovery timed outz! timed out, switching to next LLMz recovery failed)exc_infoz failed, switching to next LLMz recovery unexpected errorz( unexpected error, switching to next LLM)rX   r   r   rx   ry   rz   dataclassesreplace_conn_optionsrw   r=   r<   r>   r{   asyncioTimeoutErrorr   warninglabelr   	Exception	exception)rC   r-   r   streamshould_set_currentchunkes          r)   _try_generateFallbackLLMStream._try_generate   s    6	xxkk$($=$= --!//(00&&"44GG 22CC#'#9#9#I#I	     )7%7"#)  %)-2*/5,K% 6     ( ## 		#)),?@ANN99+>?  	yyk!12 NN99+;<  
	  yyk!;< 99+EF 
	s   H B%D )C*D -
C-7C;C<C?C-D CC-D &C)'D ,H -D3C64D D H D A,H3AG  AHH c                .  ^ ^ T R                   R                  T R                   R                  R                  U5         mTR                  b  TR                  R                  5       (       a+  SUU 4S jjn[        R                  " U" U5      5      Tl        g g )Nc                
  >#     TR                  U SS9  S h  vN nM   N
 STl        [        R                  " SU R                   S35        TR
                  R                  S[        U SS95        g ! [         a     g f = f7f)NTr-   r   zllm.FallbackAdapter, z
 recoveredrq   r-   r   )	r   r   r   infor   rw   r`   r+   r   )r-   rD   
llm_statusrC   s     r)   _recover_llm_task:FallbackLLMStream._try_recovery.<locals>._recover_llm_task   s     #'#5#5#d#5#S a#S ,0J(KK"7		{* MN**//20SDI ! sC   BA3 " "A3 "AA3 2B3
B =B?B  Br-   r   rf   rg   )rw   r@   r;   indexr   doner   create_task)rC   r-   r   r   s   `  @r)   _try_recoveryFallbackLLMStream._try_recovery   s    ++33""1177<

 %%-1K1K1P1P1R1R  *1)<)<=Ns=S)TJ&! 2Sr(   c           
     >  #    [         R                   " 5       n[        S U R                  R                   5       5      nU(       a  [        R
                  " S5        [        U R                  R                  5       H  u  p4U R                  R                  U   nUR                  (       d  U(       a  Sn/ n U R                  USS9  S h  vN nUR                  (       ak  UR                  R                  (       a  XhR                  R                  -  nUR                  R                   H  n	UR                  U	R                  5        M      U R                  R!                  U5        M  U R/                  U5        GM     [1        SU R                  R                   Vs/ s H  oDR*                  PM     sn S[         R                   " 5       U-
   S35      e GN

   g ! ["         a    UR                  (       a+  SUl        U R                  R%                  S['        USS95        U(       d  U(       ad  XgS.n
U R                  R(                  (       d#  [        R
                  " UR*                   S	3U
S
9  e [        R,                  " UR*                   S3U
S
9   GN-f = fs  snf 7f)Nc              3  B   #    U  H  oR                   (       + v   M     g 7fr~   )r   ).0r   s     r)   	<genexpr>)FallbackLLMStream._run.<locals>.<genexpr>   s     cDbj1111Dbs   z$all LLMs are unavailable, retrying.. Fr   rq   r   )	text_senttool_calls_sentzy failed after sending chunk, skip retrying. Set `retry_on_chunk_sent` to `True` to enable retrying after chunks are sent.)extraz' failed after sending chunk, retrying..zall LLMs failed (z) after z seconds)timeallrw   r@   r   error	enumerater;   r   r   deltacontent
tool_callsappendname	_event_chsend_nowaitr   r`   r+   r?   r   r   r   r
   )rC   
start_time
all_failedir-   r   r   r   result	tool_callr   s              r)   _runFallbackLLMStream._run   s-    YY[
cDDZDZDbDbcc
LL?@ 6 6 E EFFA//77:J##z!#	-/ (,(:(:sSX(:(Y ;f!<<%||33 )\\-A-A A	-3\\-D-D	 / 6 6y~~ F .E 226:4 s#O GR !d6L6L6[6[ \6[s6[ \]]efjfofofqt~f~e  @H  I
 	
G;(Y   !++/4
,..3364N
 !O.7 \#55JJ"LL#&99+ .p !p&+
 ""yyk)PQ"'%4 !]sb   B2J5GG	G
GBG'4JJ
0#JGGJB8JJJJc                   #    g 7fr~   r    )rC   event_aiters     r)   _metrics_monitor_task'FallbackLLMStream._metrics_monitor_task#  s     s   )r{   rz   rw   rx   ry   )r-   r/   rV   r   rP   
list[Tool]rQ   r   rR   ri   rS   rj   rT   rk   rf   rg   )rf   r   )rf   r   )r-   r   r   r   rf   AsyncIterable[ChatChunk]r   rl   )r   r   rf   rg   )r"   r#   r$   r%   ru   r&   r   r:   rm   rV   rP   r   r   r   r   r'   ro   rp   s   @r)   rW   rW   s   s    ,BMB 1:.73<66 	6
 6 (6 .6 ,6 16 
6 6& - -
 * * 38BB+/B	!BHU,2
h r(   rW   )%
__future__r   r   r   r   collections.abcr   r   typingr   r   r   _exceptionsr
   r   logr   typesr   r   r   r   chat_contextr   r-   r   r   r   tool_contextr   r   r   rn   r   r+   r/   rW   r    r(   r)   <module>r      s    "    ) ! ) ) 6  Y Y % * * *'84<<( $
 / / /
   
N8*+,N8bq	 qr(   