
    g                        d Z ddlZddlmZmZmZ ddlmZmZmZm	Z	m
Z
mZ ddlZddlmZ ddlmZ ddlmZ ddlmZmZ dd	lmZ dd
lmZ ddlmZ ddlmZ ddlmZm Z m!Z! ddl"m#Z# ddl"m#Z$ ddl"m%Z%m&Z& dZ' G d de      Z(y)a  
Provider budget limiting

Use this if you want to set $ budget limits for each provider.

Note: This is a filter, like tag-routing. Meaning it will accept healthy deployments and then filter out deployments that have exceeded their budget limit.

This means you can use this with weighted-pick, lowest-latency, simple-shuffle, routing etc

Example:
```
openai:
	budget_limit: 0.000000000001
	time_period: 1d
anthropic:
	budget_limit: 100
	time_period: 7d
```
    N)datetime	timedeltatimezone)AnyDictListOptionalTupleUnion)verbose_router_logger)	DualCache)RedisPipelineIncrementOperation)CustomLoggerSpan)duration_in_seconds)_get_tags_from_request_kwargs)%_get_prometheus_logger_from_callbacks)AllMessageValues)DeploymentTypedDictLiteLLM_ParamsRouterErrors)BudgetConfig)GenericBudgetConfigTypeStandardLoggingPayload   c                      e Zd Z	 d5dedee   deeee   ee	e
ef      f      fdZ	 	 d6de
dedeee      d	ee   d
ee   dee   fdZdee	e
ef      dee	e
ef      de	e
ef   de	e
ef   de	e
ef   dee
   deee	e
ef      e
f   fdZ	 d5dee	e
ef      d	ee	   deee
   e	e
ef   e	e
ef   f   fdZde
dededefdZde
de
dedededefdZde
dedefdZd Zdede
de
defdZd  Zd! Zd" Zd#e
dee   fd$Zd%e
dee   fd&Zd'e
dee   fd(Z d)e	dee
   fd*Z!d%e
d+ed,efd-Z"d%e
dee   fd.Z#d%e
dee
   fd/Z$d%e
defd0Z%e&	 d5dee   deeee   ee	e
ef      f      fd1       Z'd2 Z(	 d5deeee   ee	e
ef      f      fd3Z)d4 Z*y)7RouterBudgetLimitingN
dual_cacheprovider_budget_config
model_listc                 p   || _         g | _        t        j                  | j	                                || _        d | _        d | _        | j                          | j                  |       | j                          t        t        j                  t              r t        j                  j                  |        y y )N)r    )r   redis_increment_operation_queueasynciocreate_task(periodic_sync_in_memory_spend_with_redisr   deployment_budget_configtag_budget_config_init_provider_budgets_init_deployment_budgets_init_tag_budgets
isinstancelitellm	callbackslistappend)selfr   r   r    s       [/var/www/openai/venv/lib/python3.12/site-packages/litellm/router_strategy/budget_limiter.py__init__zRouterBudgetLimiting.__init__-   s     %VX,DIIKL" 	# LP%DH##%%%%<  g''.$$T* /    modelhealthy_deploymentsmessagesrequest_kwargsparent_otel_spanreturnc           
      6  K   t        |t              r|g}t        |      dk(  r|S g }| j                  ||       d{   \  }}}	t        |      dkD  r| j                  j                  ||       d{   }
|
xs dgt        |      z  }i }t        |      D ]  \  }}t        ||   xs d      ||<    | j                  |||	||t        |            \  }}t        |      dk(  r(t        t        j                  j                   d|       |S |S 7 7 w)	z
        Filter out deployments that have exceeded their provider budget limit.


        Example:
        if deployment = openai/gpt-3.5-turbo
            and openai spend > openai budget limit
                then skip this deployment
        r   )r5   r7   N)keysr8           r7   )r5   provider_configsdeployment_configs	spend_mappotential_deploymentsrequest_tags: )r+   dictlen0_async_get_cache_keys_for_router_budget_limitingr   async_batch_get_cache	enumeratefloat$_filter_out_deployments_above_budgetr   
ValueErrorr   +no_deployments_with_provider_budget_routingvalue)r0   r4   r5   r6   r7   r8   rA   
cache_keysr>   r?   _current_spendscurrent_spendsr@   idxkeydeployment_above_budget_infos                   r1   async_filter_deploymentsz-RouterBudgetLimiting.async_filter_deploymentsE   sr    & )40#6"7 "#q(&&,. GG$7- H   	9
$&8 z?Q$(OO$I$I!1 %J % O $3#Msec*o6MN +-I%j1S!&~c':'Ac!B	# 2 99(;%5'9'*?!>'5" : 	 @!#? ()Q. #OOUUVVXYuXvw  )(&&Os"   <DD6D5D6B DDrA   r>   r?   r@   rB   c                    d}|D ]L  }d}	| j                   r| j                  |      }
|
|v r||
   }|j                  9|j                  d|
 d|j                   d      }| j                  |
||j                         |j                  r/||j                  k\  r d|
 d| d	|j                   }|| d
z  }d}	| j                  r|	r|j                  d      }|j                  d      xs i }|j                  d      }|j                  di       j                  d      }||v r~||   }|j                  d| d|j                   d      }|j                  rK||j                  k\  r<d| d| d| d| d	|j                   
}t        j                  |       || d
z  }d}	| j                  r|	r|D ]  }| j                  |      }|s|j                  d| d|j                   d      }|j                  sF||j                  k\  sVd| d| d|j                   }t        j                  |       || d
z  }d}	 |	s<|j                  |       O ||fS )a  
        Filter out deployments that have exceeded their budget limit.
        Follow budget checks are run here:
            - Provider budget
            - Deployment budget
            - Request tags budget
        Returns:
            Tuple[List[Dict[str, Any]], str]:
                - A tuple containing the filtered deployments
                - A string containing debug information about deployments that exceeded their budget limit.
         Tprovider_spend::r<   providerspendbudget_limitzExceeded budget for provider rC   z >= 
F
model_namelitellm_paramsr4   
model_infoiddeployment_spend:z+Exceeded budget for deployment model_name: z, litellm_params.model: , model_id: 
tag_spend:zExceeded budget for tag='z', tag_spend=z, tag_budget_limit=)r    _get_llm_provider_for_deployment
max_budgetgetbudget_duration+_track_provider_remaining_budget_prometheusr&   r   debugr'   _get_budget_config_for_tagr/   )r0   rA   r5   r>   r?   r@   rB   rS   
deploymentis_within_budgetrZ   configcurrent_spend	debug_msg_model_name_litellm_params_litellm_model_namemodel_id_tag_tag_budget_config
_tag_spends                        r1   rJ   z9RouterBudgetLimiting._filter_out_deployments_above_budget   s.   * -/$-J# **@@L//-h7F((0 $-MM)(1V5K5K4LMs%M DD!)+%+%6%6 E  ((]f>O>O-O&CH:RP]^bcictctbu$v	49+R8HH4+0(  ,,1A(nn\:",..1A"B"Hb&5&9&9'&B#%>>,;??E11/9F$-MM+H:Qv7M7M6NOQT%M ((]f>O>O-O&QR]Q^^v  xK  wL  LX  Ya  Xb  bd  er  ds  sw  x~  xN  xN  wO  %P	-33I>49+R8HH4+0( %%*:(D)-)H)H)N&)%.]](a0B0R0R/ST&

 /99 *.@.K.K K*CD6WaVbbu  wI  wT  wT  vU  )VI177	B8yk<LL8/4,$ )   %,,Z8{ .~ %&BBBr3   c                 t  K   g }i }i }|D ]$  }| j                   rX| j                  |      }|E| j                  |      }|2|j                  &|||<   |j	                  d| d|j                          | j
                  r\|j                  di       j                  d      }	|	9| j                  |	      }|&|||	<   |j	                  d|	 d|j                          | j                  st        |      }
|
D ]7  }| j                  |      }|s|j	                  d| d|j                          9 ' |||fS w)a  
        Returns list of cache keys to fetch from router cache for budget limiting and provider and deployment configs

        Returns:
            Tuple[List[str], Dict[str, GenericBudgetInfo], Dict[str, GenericBudgetInfo]]:
                - List of cache keys to fetch from router cache for budget limiting
                - Dict of provider budget configs `provider_configs`
                - Dict of deployment budget configs `deployment_configs`
        rW   rX   r`   ra   rb   r=   rd   )r   re   _get_budget_config_for_providerrh   r/   r&   rg   !_get_budget_config_for_deploymentr'   r   rk   )r0   r5   r7   rN   r>   r?   rl   rZ   budget_configrt   rB   ru   rv   s                r1   rF   zERouterBudgetLimiting._async_get_cache_keys_for_router_budget_limiting   sv     !#
9;;=-J**@@L'$($H$H$RM%1)99E5B(2"))-hZq9V9V8WX
 ,,%>>,;??E'$($J$J8$TM$07D*84"))/z=;X;X:YZ %%<#1  )D)-)H)H)N&)"))(a0B0R0R/ST )= .H +-???s   C%D8($D8+D8start_time_keycurrent_timettl_secondsc                    K   | j                   j                  |       d{   }|(| j                   j                  |||       d{    |S t        |      S 7 97 w)z
        Checks if the key = `provider_budget_start_time:{provider}` exists in cache.

        If it does, return the value.
        If it does not, set the key to `current_time` and return the value.
        NrR   rM   ttl)r   async_get_cacheasync_set_cacherI   )r0   r|   r}   r~   budget_starts        r1   _get_or_set_budget_start_timez2RouterBudgetLimiting._get_or_set_budget_start_time  sl      "__<<^LL//11",K 2     \"" Ms!   AA'A	A
AA	spend_keyresponse_costc                    K   | j                   j                  |||       d{    | j                   j                  |||       d{    |S 7 ,7 w)a  
        Handle start of new budget window by resetting spend and start time

        Enters this when:
        - The budget does not exist in cache, so we need to set it
        - The budget window has expired, so we need to reset everything

        Does 2 things:
        - stores key: `provider_spend:{provider}:1d`, value: response_cost
        - stores key: `provider_budget_start_time:{provider}`, value: current_time.
            This stores the start time of the new budget window
        r   N)r   r   )r0   r   r|   r}   r   r~   s         r1   _handle_new_budget_windowz.RouterBudgetLimiting._handle_new_budget_window+  sm     ( oo--K . 
 	
 	
 oo--l . 
 	
 	
 	
	
s!   "AA%A
AAAr   c                    K   | j                   j                  j                  |||       d{    t        |||      }| j                  j                  |       y7 .w)a  
        Increment spend within existing budget window

        Runs once the budget start time exists in Redis Cache (on the 2nd and subsequent requests to the same provider)

        - Increments the spend in memory cache (so spend instantly updated in memory)
        - Queues the increment operation to Redis Pipeline (using batched pipeline to optimize performance. Using Redis for multi instance environment of LiteLLM)
        r   N)rR   increment_valuer   )r   in_memory_cacheasync_incrementr   r"   r/   )r0   r   r   r   increment_ops        r1   "_increment_spend_in_current_windowz7RouterBudgetLimiting._increment_spend_in_current_windowG  sh      oo--== > 
 	
 	

 7)

 	,,33LA	
s   ,AA/Ac                 &  K   t        j                  d       |j                  dd      }|t        d      |j                  dd      }t	        |j                  dd            }|j                  d	i       j                  d
d      }|t        d      | j                  |      }	|	r4d| d|	j                   }
d| }| j                  |	|
||       d{    | j                  |      }|r4d| d|j                   }d| }| j                  ||||       d{    t        |      }t        |      dkD  rP|D ]J  }| j                  |      }|sd| d|j                   }d| }| j                  ||||       d{    L yy7 7 p7 w)z)Original method now uses helper functionsz/in RouterBudgetLimiting.async_log_success_eventstandard_logging_objectNz$standard_logging_payload is requiredr   r   rt   rV   r_   custom_llm_providerzcustom_llm_provider is requiredrW   rX   provider_budget_start_time:)r{   r   r|   r   rb   zdeployment_budget_start_time:rd   ztag_budget_start_time:)r   rj   rg   rK   strry   rh   _increment_spend_for_keyrz   r   rE   rk   )r0   kwargsresponse_obj
start_timeend_timestandard_logging_payloadr   rt   r   r{   r   r|   r&   deployment_spend_keydeployment_start_time_keyrB   ru   rv   _tag_spend_key_tag_start_time_keys                       r1   async_log_success_eventz,RouterBudgetLimiting.async_log_success_event^  s    ##$UVEKZZ%tF
  $+CDD7;;OQO488RHI#)::.>#C#G#G!4$
 &>??<<=PQ ""5!6a8U8U7VW   ;;N:OPN//+#-+	 0    $(#I#I(#S #%6xjBZBjBjAk#l *Gz(R%//6.8+	 0    5V<|q $%)%D%DT%J"%$TF!,>,N,N+OP # -C4&*I'77&8"0':&3	 8    % !) s=   CFFAFF5F/FF	FFFr{   c                 H  K   |j                   y t        j                  t        j                        j                         }t        |j                         }| j                  |||       d {   }|| j                  |||||       d {   }nk||z
  |kD  r4t        j                  d       | j                  |||||       d {   }n/|||z
  z
  }t        |      }	| j                  |||	       d {    t        j                  d| d|        y 7 7 7 T7 &w)N)r|   r}   r~   )r   r|   r}   r   r~   z,Budget window expired - resetting everything)r   r   r   zIncremented spend for z by )rh   r   nowr   utc	timestampr   r   r   r   rj   intr   )
r0   r{   r   r|   r   r}   r~   r   remaining_timettl_for_increments
             r1   r   z-RouterBudgetLimiting._increment_spend_for_key  sY     ((0||HLL1;;=)-*G*GH!??)%# @ 
 
 !%!?!?#-)+' "@ " L \)[8!''(VW!%!?!?#-)+' "@ " L )L<,GHN #N 399#=FW :    	##$YKtM?C	
E
sH   A+D"-D.D"D;D"	D
/D"9D :!D"D"D" D"c                 <  K   	 	 | j                          d{    t        j                  t               d{    ;7 &7 # t        $ rM}t        j                  dt        |              t        j                  t               d{  7   Y d}~Vd}~ww xY ww)z
        Handler that triggers sync_in_memory_spend_with_redis every DEFAULT_REDIS_SYNC_INTERVAL seconds

        Required for multi-instance environment usage of provider budgets
        NzError in periodic sync task: ) _sync_in_memory_spend_with_redisr#   sleepDEFAULT_REDIS_SYNC_INTERVAL	Exceptionr   errorr   r0   es     r1   r%   z=RouterBudgetLimiting.periodic_sync_in_memory_spend_with_redis  s      	;;===mm/   =  %++.KCPQF8,TUmm/  sW   BA ? A AA BA A 	B=B	B
BBBBc                   K   	 | j                   j                  syt        j                  d| j                         t        | j                        dkD  rCt        j                  | j                   j                  j                  | j                               g | _        y# t        $ r+}t        j                  dt        |              Y d}~yd}~ww xY ww)a  
        How this works:
        - async_log_success_event collects all provider spend increments in `redis_increment_operation_queue`
        - This function pushes all increments to Redis in a batched pipeline to optimize performance

        Only runs if Redis is initialized
        Nz.Pushing Redis Increment Pipeline for queue: %sr   )increment_list*Error syncing in-memory cache with Redis: )r   redis_cacher   rj   r"   rE   r#   r$   async_increment_pipeliner   r   r   r   s     r1   #_push_in_memory_increments_to_redisz8RouterBudgetLimiting._push_in_memory_increments_to_redis  s     	??..!''@44 47781<##OO//HH'+'K'K I  46D0 	!''<SVHE 	s9   CB CBB C	C'!CCCCc                 2  K   	 | j                   j                  y| j                          d{    g }| j                  F| j                  j	                         D ])  \  }}|	|j                  d| d|j                          + | j                  F| j                  j	                         D ])  \  }}|	|j                  d| d|j                          + | j                  F| j                  j	                         D ])  \  }}|	|j                  d| d|j                          + | j                   j                  j                  |       d{   }t        |t              ro|j	                         D ][  \  }}|	| j                   j                  j                  |t        |             d{    t        j                   d| d	|        ] yy7 7 7 (# t"        $ r+}	t        j$                  d
t'        |	              Y d}	~	yd}	~	ww xY ww)a  
        Ensures in-memory cache is updated with latest Redis values for all provider spends.

        Why Do we need this?
        - Optimization to hit sub 100ms latency. Performance was impacted when redis was used for read/write per request
        - Use provider budgets in multi-instance environment, we use Redis to sync spend across all instances

        What this does:
        1. Push all provider spend increments to Redis
        2. Fetch all current provider spend from Redis to update in-memory cache
        NrW   rX   rb   rd   )key_list)rR   rM   zUpdated in-memory cache for rC   r   )r   r   r   r   itemsr/   rh   r&   r'   rG   r+   rD   r   r   rI   r   rj   r   r   r   )
r0   rN   rZ   rn   rt   tagredis_valuesrR   rM   r   s
             r1   r   z5RouterBudgetLimiting._sync_in_memory_spend_with_redis  s.    4	**2 ::<<< J**6(,(C(C(I(I(K$Hf~ %%)(1V5K5K4LM )L ,,8(,(E(E(K(K(M$Hf~ %%+H:Qv7M7M6NO )N %%1#'#9#9#?#?#AKC~ %%
3%q9O9O8P&QR $B "&!<!<!R!R# "S " L
 ,-"."4"4"6JC("oo==MM #5< N    .33:3%r%I #7 .C =8  	!''<SVHE 	ss   HG  HG  GD%G  G,G  3G  5G6!G  HG  G  G   	H)!H
HHHrt   c                 T    | j                   y | j                   j                  |d       S N)r&   rg   )r0   rt   s     r1   rz   z6RouterBudgetLimiting._get_budget_config_for_deployment?  s,     ((0,,004@@r3   rZ   c                 T    | j                   y | j                   j                  |d       S r   )r   rg   )r0   rZ   s     r1   ry   z4RouterBudgetLimiting._get_budget_config_for_providerG  s,     &&.**..x>>r3   r   c                 T    | j                   y | j                   j                  |d       S r   )r'   rg   )r0   r   s     r1   rk   z/RouterBudgetLimiting._get_budget_config_for_tagN  s*    !!)%%))#t44r3   rl   c           	          	 t        di |j                  dddi      }t        j                  |j                  |      \  }}}}|S # t
        $ r t        j                  d|        Y y w xY w)Nr_   r4   rV   )r4   r_   z+Error getting LLM provider for deployment:  )r   rg   r,   get_llm_providerr4   r   r   r   )r0   rl   rr   _r   s        r1   re   z5RouterBudgetLimiting._get_llm_provider_for_deploymentS  s    	.< /..!1GR=A/O ,3+C+C%++.,(A"Aq #"  	!''=j\J 		s   AA !A+*A+r[   r\   c                 F    t               }|r|j                  |||       yy)z
        Optional helper - emit provider remaining budget metric to Prometheus

        This is helpful for debugging and monitoring provider budget limits.
        rY   N)r   track_provider_remaining_budget)r0   rZ   r[   r\   prometheus_loggers        r1   ri   z@RouterBudgetLimiting._track_provider_remaining_budget_prometheusc  s2     BC==!) >  r3   c                 J  K   | j                  |      }|yd| d|j                   }| j                  j                  r.| j                  j                  j	                  |       d{   }n#| j                  j	                  |       d{   }|t        |      S dS 7 77 w)ab  
        GET the current spend for a provider from cache

        used for GET /provider/budgets endpoint in spend_management_endpoints.py

        Args:
            provider (str): The provider to get spend for (e.g., "openai", "anthropic")

        Returns:
            Optional[float]: The current spend for the provider, or None if not found
        NrW   rX   r<   )ry   rh   r   r   r   rI   )r0   rZ   r{   r   ro   s        r1   _get_current_provider_spendz0RouterBudgetLimiting._get_current_provider_spendt  s      <<XF %hZq1N1N0OP	??&&"&//"="="M"Mi"XXM #'//"A"A)"LLM'4'@u]#IcI	 Y Ms$   A%B#'B(#B#B!B#!B#c                   K   | j                  |      }|y d| d|j                   }| j                  j                  r.| j                  j                  j	                  |       d {   }n#| j                  j	                  |       d {   }|y t        j                  t        j                        t        |      z   j                         S 7 i7 Gw)NrW   rX   )seconds)ry   rh   r   r   async_get_ttlr   r   r   r   r   	isoformat)r0   rZ   r{   r   r~   s        r1   %_get_current_provider_budget_reset_atz:RouterBudgetLimiting._get_current_provider_budget_reset_at  s      <<XF %hZq1N1N0OP	??&& $ ; ; I I) TTK $ = =i HHKX\\*Y{-KKVVXX UHs%   A%C'C(#CCACCc                    K   d| d|j                    }d| }d}|j                   t        |j                         }| j                  j                  |       d{   }|Wt	        j
                  t        j                        j                         }| j                  j                  |||       d{    | j                  j                  |       d{   }|'| j                  j                  |d|       d{    yy7 7 S7 27 w)a!  
        Initialize provider budget in cache by storing the following keys if they don't exist:
        - provider_spend:{provider}:{budget_config.time_period} - stores the current spend
        - provider_budget_start_time:{provider} - stores the start time of the budget window

        rW   rX   r   Nr   r<   )
rh   r   r   r   r   r   r   r   r   r   )r0   rZ   r{   r   r|   r~   r   
_spend_keys           r1   _init_provider_budget_in_cachez3RouterBudgetLimiting._init_provider_budget_in_cache  s     &hZq1N1N0OP	6xjA%)((4-m.K.KLK!__<<^LL#<<5??AL//11",K 2     ??::9EE
//11Sk 2     M FsI   ADDAD4D5"DD
'D?D DD
DDc                     | yt         j                  y|y|D ]8  }|j                  di       }|j                  d      s|j                  d      8 y y)a  
        Returns `True` if the router budget routing settings are set and RouterBudgetLimiting should be initialized

        Either:
         - provider_budget_config is set
         - budgets are set for deployments in the model_list
         - tag_budget_config is set
        TFr_   rf   rh   )r,   r'   rg   )r   r    _modelrr   s       r1   !should_init_router_budget_limiterz6RouterBudgetLimiting.should_init_router_budget_limiter  sh     "-$$0 F$jj)92>O##L1"&&'89E ! r3   c                    | j                   | j                   j                         D ]  \  }}|t        d| d| j                          t        |t              s8t	        |j                  d      |j                  d            | j                   |<   t        j                  | j                  || j                   |                 t        j                  d| j                           y y )Nz$No budget config found for provider z, provider_budget_config: r\   time_period)r\   r   )rZ   r{   z#Initalized Provider budget config: )r   r   rK   r+   GenericBudgetInforg   r#   r$   r   r   rj   )r0   rZ   rn   s      r1   r(   z+RouterBudgetLimiting._init_provider_budgets  s    &&2$($?$?$E$E$G &>$>xjHbcgc~c~b  A  "&*;<<M%+ZZ%?$*JJ}$==D//9 ##77!)&*&A&A(&K 8  %H$ "''5d6Q6Q5RS) 3r3   c           	         |y |D ]  }|j                  di       }|j                  di       }|j                  d      }|j                  d      }|j                  d      }t        j                  d| d| d|        |{|~|t        ||	      }| j                  i | _        || j                  |<    t        j                  d
| j                          y )Nr_   r`   ra   rf   rh   z$Init Deployment Budget: max_budget: z, budget_duration: rc   r   r\   z&Initialized Deployment Budget Config: )rg   r   rj   r   r&   )	r0   r    r   rr   _model_info	_model_id_max_budget_budget_duration_budget_configs	            r1   r)   z-RouterBudgetLimiting._init_deployment_budgets  s      F$jj)92>O **\26K#-I)--l;K.223DE!''6{mCVWgVhhtu~t  A '$0)!2 0!," 00846D1;I--i8+ !. 	##4T5R5R4ST	
r3   c                    t         j                  y ddlm}m} |durt        d|j                         | j                  i | _        t         j                  j                         D ]P  \  }}t        |t              rt        di |}t        |j                  |j                        }|| j                  |<   R t        j                  d| j                          y )Nr   )CommonProxyErrorspremium_userTz,Tag budgets are an Enterprise only feature, r   zInitialized Tag Budget Config: r   )r,   r'   litellm.proxy.proxy_serverr   r   rK   not_premium_userr   r+   rD   r   r   rh   rf   r   rj   )r0   r   r   ru   rv   _generic_budget_configs         r1   r*   z&RouterBudgetLimiting._init_tag_budgets  s    $$,Nt#>?P?a?a>bc  !!)%'D"(/(A(A(G(G(I$D$,d3%1%G4F%G"%6.>>/::&" ,BD""4( )J 	##-d.D.D-EF	
r3   r   )NN)+__name__
__module____qualname__r   r	   rD   r   r   r   r   r   r   r2   r   r   rT   r   rI   r
   rJ   rF   r   r   r   r   r   r   r%   r   r   rz   ry   rk   re   ri   r   r   r   staticmethodr   r(   r)   r*   r   r3   r1   r   r   ,   s    ++ !)+ $*+T$sCx.-AAB
	+: *.+/D'D' "D' 4 012	D'
 !D' #4.D' 
dD'LUC#DcN3UC "$sCx.1UC s$556	UC
 !&7!78UC U
#UC 3iUC 
tDcN#S(	)UCt *.6@!$sCx.16@ !6@ 
tCy$s$556SBS=S8TT	U	6@p#!#16#EH#	#"  	
   
8BB-2B9<B.9v1
(1
 1
 	1

 1
f$<AFAA 
#	$A??	#	$?5c 5h?P6Q 5
#4 #HSM # $)9>"J# J(5/ J4YY	#Y$,=: 
 	 ($*+T$sCx.-AAB
 @: 	!
$*+T$sCx.-AAB
!
F
r3   r   ))__doc__r#   r   r   r   typingr   r   r   r	   r
   r   r,   litellm._loggingr   litellm.caching.cachingr   litellm.caching.redis_cacher   "litellm.integrations.custom_loggerr   r   *litellm.litellm_core_utils.duration_parserr   )litellm.router_strategy.tag_based_routingr   'litellm.router_utils.cooldown_callbacksr   litellm.types.llms.openair   litellm.types.routerr   r   r   litellm.types.utilsr   r   r   r   r   r   r   r3   r1   <module>r      s]   (  2 2 : :  2 - G A J S 7 R R , A O F
< F
r3   