
    Cj)                    D   % S SK r S SKrS SKrS SKrS SKrS SKrS SKrS SKrS SKrS SK	r	S SK
r
S SKrS SKJrJr  S SKJrJrJrJr  S SKJr  S SKJr  S SKJrJrJrJrJrJrJrJrJ r 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-J.r.J/r/J0r0J1r1  S S
K2J3r3  S SK4J5r5  S SK6J7r7  S SK8J9r9J:r:   S SK;J<r<  S SK=J>r>  S SK?J@r@  S SKAJBrB   S SKDrDS SKEJFrFJGrG  S SK%r%S SKHr%S SKIr%S SK%JJrJJKrKJLrLJMrMJNrN  S SKOJPrPJQrQ  S SKRJSrSJTrT  S SKUJVrVJWrW  S SKXJYrY  S SKZJ[r[J\r\  S SK]J^r^J_r_  S SK`Jara  S SKbJcrc  S SKdJere  S SKfJgrg  S SKIJhrh  S S KiJjrj  S S!KkJlrl  S S"KmJnrn  S S#K+JoroJprpJqrqJrrrJsrs  S S$KtJuru  S S%KvJwrw  S S&KxJyryJzrz  S S'K{J|r|  S S(K}J~r~Jr  S S)KJr  S S*KJrJr  S S+KJr  S S,KJr  S S-KJrJr  S S.KJr  S S/KJr  S S0KJr  S S1KJr  S S2KJr  S S3KJr  S S4KJr  S S5KJr  S S6KJrJrJrJr  S S7KJr  S S8KJr  S S9KJr  S S:KJr  S S;KJr  S S<KJrJrJr  S S=KJr  S S>K8JrJr  \(       a  S S?KJr  S SKIJhr  \"\\4   rO\r\" 5       rS@ rSA r " SB SC5      r0 r\\\4   \SD'   SE\cSF\4SG jrSH\SI\SFS4SJ jr\" SKSL9 " SM SN5      5       r " SO SP5      rSQ rSR\SF\4SS jr\Y" STSU9r\Y\SV'   SWrSX\SY\SF\ \   4SZ jr\" \GR                  GR                  S[S\5      5      r\\S]'   S^r\\S_'   \V" \\S`9r\V\Sa'    " Sb Sc5      rSd\SF\4Se jrSf\SF\\\4   4Sg jrSh\SF\ \   4Si jrSj\Sd\SF\ \   4Sk jrSd\SFS4Sl jrSj\Sm\\   SFS4Sn jr " So Sp5      rSq\Sr\VSX\4Ss jrSt\SF\4Su jrSv\St\SF\GR                  4Sw jr   SSx\ \   Sy\ \   Sz\ \   4S{ jjrS|\4S} jrS~\SF\4S jrS~\S\SF\4S jrSF\4S jrS|\SF\4S jr " S S5      rSj\S\ \n   S\4S jrSj\S\4S jrSj\S\ \n   S\4S jrSj\S\ \n   S\4S jrS\S\S\4S jrS\SF\4S jrS\S\ \   4S jrS\S\ \   SF\ \   4S jrSS jrS rSR\S\ \N   SF\4S jrSR\S\SF\4S jrS\SF\4S jrSF\ \   4S jrSF\ \   4S jrSF\ \   4S jrS\SF\/4S jrSS\ \   4S jjrS\ \   S\ \N   SF\4S jrS\SF\4S jrS\S\SF\4S jrSS\S\ \   SF\4S jjrSF\ \   4S jrSF\4S jrS\SF\ \   4S jrS\4S jrS\SF\4S jGr SF\ \   4S jGr       SSSS\ S   S\S\ \   Sj\ Sp   S\ SP   S\ \   S\S\S\S\ S   SF\\   4S jjGr   SS\S\S\S\ \   S\ S   SF\74S jjGrS\S\\   SFS4S jGr/ SQGr\\\\4      \S'     SS\S\ \\      S\SF\\\4   4S jjGrg! \C a    Sr<Sr@SrBSr> GNf = f! \C a	    \C" S5      ef = f)    N)	dataclassfield)datedatetime	timedeltatimezone)MIMEMultipart)MIMEText)TYPE_CHECKINGAnyAsyncGenerator	AwaitableClassVarDictListLiteralOptionalTupleUnioncastoverload)+_custom_logger_compatible_callbacks_literal)DEFAULT_MODEL_CREATED_AT_TIME$LITELLM_LOGGING_NO_UPSTREAM_LLM_CALLMAX_TEAM_LIST_LIMIT)DB_CONNECTION_ERROR_TYPESCommonProxyErrorsProxyErrorTypesProxyExceptionSpendLogsMetadataSpendLogsPayload)spend_log_errorGuardrailEventHooks)ModelInfoResponse)	CallTypesCallTypesLiteral)BaseEmailLogger)ResendEmailLogger)SendGridEmailLogger)SMTPEmailLoggerzEbackoff is not installed. Please install it via 'pip install backoff')HTTPExceptionstatus)EmbeddingResponseImageResponseModelResponseModelResponseStreamRouter)_redact_stringverbose_proxy_logger)ServiceLoggingServiceTypes)	DualCache
RedisCache)LimitedSizeOrderedDict)RejectedRequestErrorSensitiveDataRouteException)CustomGuardrailModifyResponseException)"_PROXY_SensitiveDataRoutingHandler)CustomLogger)SlackAlerting)_add_langfuse_trace_id_to_alert)Logging)
safe_dumps)safe_json_loads)AsyncHTTPHandler)	AlertTypeCallInfoLiteLLM_VerificationTokenViewMemberUserAPIKeyAuth)RouteChecks)UserApiKeyCache)create_missing_viewsshould_create_missing_views)DBSpendUpdateWriter)PrismaDBExceptionHandlercall_with_db_reconnect_retry)log_db_metrics)PrismaWrapperparse_iam_endpoint_from_url)RoutingPrismaWrapper)UnifiedLLMGuardrails)PROXY_HOOKSget_proxy_hook)_PROXY_CacheControlCheck)_PROXY_MaxBudgetLimiter)!_PROXY_MaxParallelRequestsHandler)$_PROXY_MaxParallelRequestsHandler_v3)LiteLLMProxyRequestSetup)PipelineExecutor)BudgetRepository)ConfigRepository)EndUserRepositoryHealthCheckRepositorySpendLogsRepositoryUserNotificationsRepository)TeamRepository)UserRepository)VerificationTokenRepository)str_to_bool)DEFAULT_ALERT_TYPES)MCPDuringCallResponseObjectMCPPreCallRequestObjectMCPPreCallResponseObject)PipelineExecutionResult)LLMResponseTypesLoggedLiteLLMParams)Spanc                     SSK n[        R                  " SR                  XR                  " 5       5      5        [
        R                  (       a!  [        S[        [        U 5      5       35        gg)a  
Prints the given `print_statement` to the console if `litellm.set_verbose` is True.
Also logs the `print_statement` at the debug level using `verbose_proxy_logger`.

:param print_statement: The statement to be printed and logged.
:type print_statement: Any
r   Nz{}
{}zLiteLLM Proxy: )
	tracebackr4   debugformat
format_exclitellmset_verboseprintr3   str)print_statementrr   s     e/home/rurouni/.local/share/pipx/venvs/strix-agent/lib/python3.13/site-packages/litellm/proxy/utils.pyprint_verboser|      sO     x@T@T@VWXs?/C DEFG     c                     [         c  g[        b!  [        R                  " S5      (       a  [        $ [        b!  [        R                  " S5      (       a  [        $ [
        b!  [        R                  " S5      (       a  [
        $ [         $ )z
Determine which email logger class to use based on environment variables.
Priority: SendGrid > Resend > SMTP > BaseEmailLogger (fallback)

Returns:
    The email logger class to use, or None if BaseEmailLogger is not available
NSENDGRID_API_KEYRESEND_API_KEY	SMTP_HOST)r(   r*   osgetenvr)   r+    r}   r{   _get_email_logger_classr      sk      &2995G+H+H"" $3C)D)D   "ryy'='= r}   c            	          \ rS rSrS\4S jr SS\\S4   S\S\	4S jjr
 SS\\S4   S\SS4S	 jjr SS
\S\\S4   S\SS4S jjr  SS\S\\   S\4S jjr SS\S\\S4   S\4S jjr SS\SS4S jjr SS\S\	4S jjrSrg)InternalUsageCache   
dual_cachec                     Xl         g Nr   )selfr   s     r{   __init__InternalUsageCache.__init__   s    %/r}   litellm_parent_otel_spanN
local_onlyreturnc                 ^   #    U R                   R                  " SUUUS.UD6I S h  vN $  N7f)N)keyr   parent_otel_spanr   )r   async_get_cache)r   r   r   r   kwargss        r{   r   "InternalUsageCache.async_get_cache   s@      __44 
!5
 	
 
 	
 
   $-+-c                 `   #    U R                   R                  " SUUUUS.UD6I S h  vN $  N7f)N)r   valuer   r   r   )r   async_set_cacher   r   r   r   r   r   s         r{   r   "InternalUsageCache.async_set_cache   sC      __44 
!%=	

 
 
 	
 
   %.,.
cache_listc                 ^   #    U R                   R                  " SUUUS.UD6I S h  vN $  N7f)N)r   r   r   r   )r   async_set_cache_pipeline)r   r   r   r   r   s        r{   async_batch_set_cache(InternalUsageCache.async_batch_set_cache  s@      __== 
!!%=
 	
 
 	
 
r   keysr   c                 T   #    U R                   R                  UUUS9I S h  vN $  N7f)N)r   r   r   )r   async_batch_get_cache)r   r   r   r   s       r{   r   (InternalUsageCache.async_batch_get_cache  s6      __::-! ; 
 
 	
 
s   (&(r   c                 `   #    U R                   R                  " SUUUUS.UD6I S h  vN $  N7f)N)r   r   r   r   r   )r   async_increment_cacher   s         r{   r   (InternalUsageCache.async_increment_cache  sC      __:: 
!5	

 
 
 	
 
r   c                 B    U R                   R                  " SUUUS.UD6$ )N)r   r   r   r   )r   	set_cache)r   r   r   r   r   s        r{   r   InternalUsageCache.set_cache-  s3     (( 
!
 	
 	
r}   c                 @    U R                   R                  " SUUS.UD6$ )N)r   r   r   )r   	get_cache)r   r   r   r   s       r{   r   InternalUsageCache.get_cache;  s0     (( 
!
 
 	
r}   r   F)NF)__name__
__module____qualname____firstlineno__r7   r   r   rp   boolr   r   r   r   r   listr   r   floatr   r   r   __static_attributes__r   r}   r{   r   r      sH   09 0 !	
 #(d
"3
 	
 

& !
 #(d
"3	

 
 

( !	

 #(d
"3
 	
 

" ,0 	



 #4.

 	

" !
 
 #(d
"3	

 
( !	
 	
 

" !

 


 


 

r}   r   _CALLBACK_ACCEPTS_CALL_INFOcbr   c                     [        [        U 5      5      nU[        ;  a6  [        R                  " U R
                  5      nSUR                  ;   [        U'   [        U   $ )Nlitellm_call_info)idtyper   inspect	signature%async_post_call_response_headers_hook
parameters)r   r   sigs      r{   _accepts_litellm_call_infor   N  sM    
T"X,C
-- H HI+>#..+P#C(&s++r}   exccallbackc                    [        U [        5      (       d  g[        U SS5      n[        U[        5      (       d  g[        USS5      nU(       a  UR	                  SU5        [        USS5      nU(       a  UR	                  SU5        gg)af  
If `exc` is an HTTPException with a dict `detail`, mutate it in place to
add `guardrail_name` and `guardrail_mode` taken from the callback instance.

Uses setdefault so guardrails that already populate these fields explicitly
win over the inferred defaults. No-op for non-HTTPException, non-dict-detail,
or callbacks without `guardrail_name`. Never raises.
Ndetailguardrail_name
event_hookguardrail_mode)
isinstancer,   getattrdict
setdefault)r   r   r   r   r   s        r{   -_enrich_http_exception_with_guardrail_contextr   V  s|     c=))S(D)Ffd##X'7>N*N;<6J*J7 r}   T)frozenc                       \ rS rSr% SrSr\\S'   Sr\\S'   Sr	\\S'   Sr
\\S'   Sr\\S'   \" \S	9r\\\\4   S
4   \S'   \" \S	9r\\S
4   \S'   Srg)_CallbackCapabilitiesin  u  Cached per-hook capability flags derived from ``litellm.callbacks``.

Recomputing this per request walked the callback list and resolved every
string entry via ``get_custom_logger_compatible_class`` — a measurable
chunk of overhead on streaming and non-streaming chat completions.
Fhas_post_call_response_headershas_iterator_overridehas_streaming_chunk_overridehas_guardrailhas_pre_call_override)default_factory.iterator_overridesresolved_callbacksr   N)r   r   r   r   __doc__r   r   __annotations__r   r   r   r   r   tupler   r   r   ry   r   r   r   r}   r{   r   r   n  s}     ,1"D0"'4'). $.M4"'4' 7<E6ReCHos23R +0*Fc3hFr}   r   c                   "   \ rS rSr% Sr S}S\S\4S jjrS\\	   S\\
   4S jr       S~S
\\   S\\   S\\
   S\\\      S\\   S\\   S\\   4S jjrSS\\	   4S jjrS\S\\   4S jrSS\\	   4S jjrS\S\S   4S jrS rS\S\4S jrS\\   4S jrS\S\\   4S  jrS!\S"\S\\   4S# jrS\\   4S$ jrS%\\   S&\S\4S' jrS(\ S)\!S\"\\4   4S* jr#S\SS+4S, jr$S-\\   S.\S\4S/ jr%S0 r&S1\S\4S2 jr' SS3S4S5\S6\S7\\(   S8\)S(\\   S\4S9 jjr* SS1\S5\S6\S7\\(   S8\)S(\\   S\4S: jjr+S3\,S6\S7\\(   S8\)S;\-S\\   4S< jr.S6\S=\S>\S?\S8\)SS	4S@ jr/S6\SS	4SA jr0S6\S7\(S8\SB\S\4
SC jr1\2SD\S6\SE\S\4SF j5       r3\4S7\(S6S	S8\)SS	4SG j5       r5\4S7\(S6\S8\)S\4SH j5       r5S7\(S6\\   S8\)S\\   4SI jr5SJ\6S6\\   S7\\(   S\\   4SK jr7\2S3\SL\8\   S\4SM j5       r9\2S3\SN\:\S	4   S\:\S	4   4SO j5       r;0 r<\=\"\>\?\>\?SP4   4   SQ4      \@SR'   \2SSS j5       rA\2S\4ST j5       rB\2S\4SU j5       rC\2S\4SV j5       rDS\4SW jrES\4SX jrF\2S\4SY j5       rGS6\S7\\(   S8\)4SZ jrHS[\S\\4S] jrIS^\S_   S`\J4Sa jrK SSb\Sc\Sd   Se\Sf\\   4Sg jjrL SSh\S8\4Si jjrM   SSf\Sj\NS7\(Sk\\O   Sl\\   Sm\\   S\\P   4Sn jjrQ  SSj\NSk\\O   Sl\\   S\4So jjrR  SSf\S7\(Sl\\   Sj\\N   4Sp jjrSS6\S(\TS7\(4Sq jrU SS6\S7\(S(\Sr\\"\\4      S\"\\4   4
Ss jjrV\2S6\S(\S\"\\4   4St j5       rWS(\S\4Su jrX SS6\S(\Y\Z\[\\\]4   S7\(Sv\\   4Sw jjr^S7\(Sf\4Sx jr_\2Sf\SS	4Sy j5       r`S7\(SS	4Sz jraSS6\\   4S{ jjrbS|rcg	)ProxyLoggingi  z
Logging/Custom Handlers for proxy.

Implemented mainly to:
- log successful/failed db read/writes
- support the max parallel request integration
user_api_key_cachepremium_userc                 ^   0 U l         XR                   S'   [        [        SS9S9U l        [	        U R                  5      U l        [        5       U l        [        5       U l	        S U l
        SU l        [        U l        S U l        [        U R                  U R                  U R                  R                   S9U l        S U l        [&        b,  [)        5       nUb  U" U R                  R                   S9U l        X l        [-        5       U l        [1        5       U l        0 U l        SU l        SU l        g )	Nr      )default_in_memory_ttlr   i,  )alerting_thresholdalertinginternal_usage_cache)r   F)call_detailsr   r7   r   r[   max_parallel_request_limiterrZ   max_budget_limiterrY   cache_control_checkr   r   ri   alert_typesalert_to_webhook_urlr@   r   slack_alerting_instanceemail_logging_instancer(   r   r   r5   service_logging_objrO   db_spend_update_writerproxy_hook_mappingdaily_report_startedhanging_requests_check_started)r   r   r   email_logger_classs       r{   r   ProxyLogging.__init__  s    #%2D./8J q99
! -N%%-
) #:";#;#= (,),,?48!6C#66]]!%!:!:!E!E7
$
 6:#&!8!:!-.@)-)B)B)M)M/+ )#1#3 &9&;#;= +0!49+r}   
llm_routerredis_usage_cachec                 Z   U R                   R                  US9  U R                  US9  U R                  US9  U R                   b_  SU R                   R                  ;   aE  U R                  (       d4  [
        R                  " U R                   R                  US95        SU l        U R                   b{  [        R                  U R                   R                  ;   aR  U R                  (       d@  [
        R                  " U R                   R                  R                  5       5        SU l
        gggg)z0Initialize logging and alerting on proxy startupr   )redis_cacheNdaily_reportsT)r   update_values_init_litellm_callbacksr   r   asynciocreate_task_run_scheduled_daily_reportrF   llm_requests_hangingr   hanging_request_checkcheck_for_hanging_requests)r   r   r   s      r{   startup_eventProxyLogging.startup_event  s    	$$22j2I 	) 	 	
 	$$! 	% 	

 ((44#?#?#K#KK--,,HH) I 
 )-D% ((4..++77877,,BB]]_ 37D/ 88 5r}   Nr   r   r   r   alerting_argsr   alert_type_configc           	         SnUb  Xl         SnUb  X l        SnUb  X@l        SnUb  X`l        SnUb  SnUSL a  U R                  R                  U R                   U R                  U R                  UU R                  US9  U R                   b  SU R                   ;   a  SU R                  ;   d   SU R                  ;   d  SU R                  ;   a)  [        R                  R                  U R                  5        [        R                  R                  U R                  R                  5        UbO  X0R                  R                  l        X0R                  R                  l        X0R                  R                   l        g g )NFT)r   r   r   r
  r   r  slackr   outage_alertsregion_outage_alerts)r   r   r   r   r   r   rv   logging_callback_manageradd_litellm_callbackadd_litellm_success_callback!response_taking_too_long_callbackr   r   r   r   redis_update_bufferpod_lock_manager)	r   r   r   r   r   r
  r   r  updated_slack_alertings	            r{   r   ProxyLogging.update_values  si    (-$M%)")&8#%)""*%)"+(<%%)"(%)"!T)((66#'#:#: ,,+%)%>%>"3 7  }}(W-E $t'7'77&$*:*::-1A1AA44II$JfJfg00MM00RR "?J%%00<JU'';;GGR''88D #r}   c           	      H   SSK Jn  [         H  n[        U5      n[        R
                  " U5      R                  n0 nSU;   a  U R                  US'   SU;   a  X&S'   [        [        U" S0 UD65      n[        R                  R                  U5        XpR                  U'   M     g)z&
Add proxy hooks to litellm.callbacks
r   prisma_clientr   r  Nr   )litellm.proxy.proxy_serverr  rW   rX   r   getfullargspecargsr   r   r?   rv   r  r  r   )r   r   r  hook
proxy_hookexpected_argspassed_in_argsproxy_hook_objs           r{   _add_proxy_hooksProxyLogging._add_proxy_hooks  s     	=D'-J#22:>CCM-/N%69=9R9R56-/2?/!,
0L^0LMN,,AA.Q,:##D)  r}   r  r   c                 8    U R                   R                  U5      $ )z.
Get a proxy hook from the proxy_hook_mapping
)r   get)r   r  s     r{   rX   ProxyLogging.get_proxy_hook+  s     &&**400r}   c                 B   U R                  U5        [        R                  R                  U R                  5        0 n[        [        R                  5       Hp  u  p4[        U[        5      (       d  M  [        R                  R                  R                  [        [        U5      U R                  R                  US9nUc  Ml  XRU'   Mr     UR!                  5        H  u  p5U[        R                  U'   M     [        R                   H  n[        U["        5      (       d  M  [        R                  R%                  U5        [        R                  R'                  U5        [        R                  R)                  U5        [        R                  R+                  U5        M     g )N)r   r   )r#  rv   r  r  r   	enumerate	callbacksr   ry   litellm_core_utilslitellm_logging$_init_custom_logger_compatible_classr   r   r   r   itemsr?   r  add_litellm_failure_callback"add_litellm_async_success_callback"add_litellm_async_failure_callback)r   r   string_callbacks_to_replaceidxr   initialized_callbacks         r{   r  $ProxyLogging._init_litellm_callbacks1  sI   j)((==d>V>VW
 @B#&w'8'89MC(C(('.'A'A'Q'Q'v'vDhO)-)B)B)M)M) (w ($ (37K4 : *E)J)J)L%C%9Gc" *M  ))H(L1100MMhW00MMhW00SS 00SS *r}   litellm_call_idr-   )successfailc                    #    U R                   c  g U R                  nUS-  nU R                  R                  SR	                  U5      USUS S9I S h  vN   g  N7f)Nd   zrequest_status:{}T)r   r   r   ttlr   )r   r   r   r   rt   )r   r6  r-   r   s       r{   update_request_status"ProxyLogging.update_request_status]  sl      ==  %)$;$; 	c!''77#**?;"%) 8 
 	
 	
s   AAAAc                     Ub>  [        US5      (       a  UR                  5       $ [        US5      (       a  UR                  $ 0 $ )zs
Helper function to convert UserAPIKeyAuth object to dictionary.
Handles both Pydantic models and regular objects.

model_dump__dict__)hasattrr?  r@  )r   user_api_key_auth_objs     r{   "_convert_user_api_key_auth_to_dict/ProxyLogging._convert_user_api_key_auth_to_dicts  sF    
 !,,l;;,7799.
;;,555	r}   r   c                    SSK Jn  SUR                   SUR                   3nU" SUS9nU/UR	                  SS5      UR	                  S	5      UR	                  S
5      UR	                  S5      UR	                  S5      UR	                  S5      UR                  UR                  UR	                  S5      UR	                  S5      S.nU$ )zP
Convert MCP tool call to LLM message format for existing guardrail validation.
r   )ChatCompletionUserMessageTool: 
Arguments: user)rolecontentmodelzmcp-tool-calluser_api_key_user_iduser_api_key_team_iduser_api_key_end_user_iduser_api_key_hashuser_api_key_request_routemcp_rate_limit_server_nameincoming_bearer_token)messagesrL  rM  rN  rO  rP  rQ  mcp_tool_namemcp_argumentsmcp_server_namerS  )litellm.types.llms.openairF  	tool_name	argumentsr&  )r   request_objr   rF  tool_call_contentsynthetic_messagesynthetic_datas          r{   _convert_mcp_to_llm_format'ProxyLogging._convert_mcp_to_llm_format  s     	H [**+=9N9N8OP 	 6!2
 ++ZZ9$*JJ/E$F$*JJ/E$F(.

3M(N!',?!@*0**5Q*R(22(22%zz*FG &,ZZ0G%H
" r}   c                    SSK Jn  [        U[        5      (       a  U" S[	        U5      SS9$ [        U[
        5      (       a  UR                  S5      nU(       a  SUR                   SUR                   3nU(       a  US   R                  S	S
5      OS
nXe:w  an  U(       a(  SUR                  5       ;   d  SUR                  5       ;   a  U" SSSS9$  U R                  Xb5      nUb  U" SSUS9$ [        R                  " SU 35        g[        U[        5      (       a  U" SUSS9$ g! [         a#  n[        R                  " SU 35         SnAgSnAff = f)z;
Convert LLM guardrail result back to MCP response format.
r   )rl   FN)should_proceederror_messagemodified_argumentsrT  rG  rH  rK   blocked	violationzContent blocked by guardrailTz<Could not parse modified arguments from guardrail response: z"Error parsing modified arguments: )litellm.types.mcprl   r   	Exceptionry   r   r&  rY  rZ  lower(_extract_modified_arguments_from_contentr4   warningerror)	r   
llm_resultr[  rl   modified_messagesoriginal_contentnew_contentmodified_argses	            r{   #_convert_llm_result_to_mcp_response0ProxyLogging._convert_llm_result_to_mcp_response  s    	? j),,+$!*o#'  j$'' *z :  [223=AVAV@WX ! @Q%a(,,Y;VX  2 ($(9(9(;;&+*;*;*==  8+0*H/3  ( !% M M$/!" *
  -8'?37267D(" !" !5 < <&bcnbo$p!" (, j#&&+$JSW    ) (066"DQC H $((s   D% -D% %
E/EEmasked_contentc                    SSK n[        R                  " SU 35         UR                  5       R	                  S5      n[        U5       H  u  pVUR                  S5      (       d  M  U[        S5      S R                  5       n[        R                  " SU 35         UR                  " U5      n[        R                  " SU 35        Us  $    [        R                  " S
5        g! UR                   aC  n	[        R                  " SU S	U	 35        U R                  XrR                  5      s Sn	A	s  $ Sn	A	ff = f! [         a#  n	[        R                  " SU	 35         Sn	A	gSn	A	ff = f)zH
Extract modified/masked arguments from the guardrail response content.
r   Nz'Extracting modified args from content: 
z
Arguments:zFound arguments text: zSuccessfully parsed JSON args: z Failed to parse JSON arguments: z	, error: z2Could not find 'Arguments:' line in masked contentz%Error extracting modified arguments: )jsonr4   rs   stripsplitr)  
startswithlenloadsJSONDecodeError_parse_arguments_manuallyrZ  rl  ri  rm  )
r   rv  r[  ry  linesiline	args_textrr  rs  s
             r{   rk  5ProxyLogging._extract_modified_arguments_from_content  s\    	""5n5EF	
#	 #((*006E$U+??<00 $S%6%8 9 ? ? AI(..1G	{/ST(,

9(=,22=m_M  -, ,0 !((D   // ,22>ykSTRUV  $==%'<'<    	 &&)Nqc'RS	sT   AD: &5D: ,C$D: D: $D746D2*D7+D: 2D77D: :
E'E""E'r  original_argsc                    SSK n UR                  5       nUR                  5        H  u  pV[        U[        5      (       d  M  SUR                  U5       S3nUR                  XqUR                  5      nU(       d  MV  UR                  S5      R                  5       n	U	(       d  M~  XU'   M     U$ ! [         a#  n
[        R                  " SU
 35         Sn
A
gSn
A
ff = f)z
Try to manually parse arguments when JSON parsing fails.
This is a fallback for cases where the guardrail modifies the format.
r   Nz['\"]?z#['\"]?\s*:\s*['\"]?([^,'\"]*)['\"]?r   z"Error in manual argument parsing: )recopyr.  r   ry   escapesearch
IGNORECASEgrouprz  ri  r4   rm  )r   r  r  r  rr  r   original_valuepatternmatch	new_valuers  s              r{   r  &ProxyLogging._parse_arguments_manually#  s     		)..0M (5':':'<#nc22 ""))C.!11TU  IIg"--HEu$)KKN$8$8$:	$91:#. (= !  	 &&)KA3'OP	s)   8B. 6B. <$B. $	B. .
C8CCc                    [        U[        5      (       a  [        S[        U5      S9$ [        U[        5      (       a  UR                  S5      nU(       an  SUR                   SUR                   3nU(       a  US   R                  SS5      OSnXT:w  a/  U(       a  S	UR                  5       ;   a
  [        SS
S9$ [        SSS9$ [        U[        5      (       a
  [        SUS9$ g)zG
Convert LLM guardrail result back to MCP during call response format.
F)should_continuerc  rT  rG  rH  r   rK  re  rf  z-Content blocked by guardrail during executionz.Content modified by guardrail during executionN)	r   ri  rj   ry   r   r&  rY  rZ  rj  )r   rn  r[  ro  rp  rq  s         r{   *_convert_llm_result_to_mcp_during_response7ProxyLogging._convert_llm_result_to_mcp_during_responseD  s     j),,. %S_ 
 j$'' *z :  [223=AVAV@WX ! @Q%a(,,Y;VX  2&){7H7H7J*J:,1*Y    ;,1*Z   j#&&. %Z  r}   dynamic_success_callbacksglobal_callbacksc                 J    Uc  [        U5      $ [        [        X-   5      5      $ r   )r   set)r   r  r  s      r{   get_combined_callback_list'ProxyLogging.get_combined_callback_lists  s*     %,())C1DEFFr}   responseoriginal_requestc                     UR                   UR                  =(       d    UR                  UR                  UR                  S.nU$ )z
Parse the response from the pre_mcp_tool_call_hook

1. Check if the call should proceed
2. Apply any argument modifications
3. Handle validation errors
)rb  rd  rc  hidden_params)rb  rd  rZ  rc  r  )r   r  r  results       r{   !_parse_pre_mcp_call_hook_response.ProxyLogging._parse_pre_mcp_call_hook_responsez  sD     '55"*"="= #*))%33%33
 r}   rk   c                     SSK Jn  SSKJn  U R	                  UR                  S5      5      nU" UR                  SS5      UR                  S0 5      UR                  S5      UU" 5       S	9$ )
z[
Helper function to create MCPPreCallRequestObject from kwargs for standard pre_call_hook.
r   )HiddenParams)rk   user_api_key_authnamere  rZ  server_name)rY  rZ  r  r  r  )litellm.types.llms.baser  rh  rk   rC  r&  )r   r   r  rk   user_api_key_auth_dicts        r{   &_create_mcp_request_object_from_kwargs3ProxyLogging._create_mcp_request_object_from_kwargs  sg     	9=!%!H!HJJ*+"
 'jj,jjb1

=14&.
 	
r}   response_dataoriginal_kwargsc                     U(       d  U$ UR                  5       nUR                  S5      (       a  US   US'   UR                  S5      (       a&  UR                  S5      =(       d    0 n0 UEUS   EUS'   U$ )z
Helper function to convert pre_call_hook response back to kwargs for MCP usage.

Supports:
- modified_arguments: Override tool call arguments
- extra_headers: Inject custom headers into the outbound MCP request
rd  rZ  extra_headers)r  r&  )r   r  r  modified_kwargsexistings        r{   $_convert_mcp_hook_response_to_kwargs1ProxyLogging._convert_mcp_hook_response_to_kwargs  s     "")..0122+89M+NOK(_--
 '**?;ArH0000OO,
 r}   c                    #    [        U[        5      (       a  Ue[        U[        5      (       a  U$ [        U[        5      (       a.  US;   a  [	        UUR                  SS5      SUS9e[        SSU0S9eU$ 7f)N)
completiontext_completionrL  re  )messagerL  llm_providerrequest_data  rm  status_coder   )r   ri  r   ry   r:   r&  r,   )r   r  data	call_types       r{   process_pre_call_hook_response+ProxyLogging.process_pre_call_hook_response  s|     h	**Nh%%Oh$$==*$((7B/!#!%	  $Wh<OPPs   A4A6r   c                     SSK Jn  Ub  [        US5      (       d  gUR                   Vs/ s H  nUR	                  S5      U:X  d  M  UPM     nn[        U5      S:  $ s  snf )z
Check if load balancing should be used for this guardrail.

Returns True if the router has multiple deployments for this guardrail name.
r   r   guardrail_listFr   r   )r  r   rA  r  r&  r}  )r   r   r   gmatchings        r{   $_should_use_guardrail_load_balancing1ProxyLogging._should_use_guardrail_load_balancing  sm     	:WZ9I%J%J  ..
.uu%&.8 . 	 

 8}q  
s   AAr   r<   	hook_typer  user_api_key_dictr  c                   #    S[        U5      R                  ;   nU=(       a    US:H  =(       a    [        USS5      (       + nU(       a  XS'   U(       a  [        OUn	US:X  a'  U	R	                  UU R
                  S   UUS9I S	h  vN $ US:X  a  U	R                  UUUS
9I S	h  vN $ US:X  a  U	R                  UUUS9I S	h  vN $ [        SU 35      e NP N3 N7f)aZ  
Execute a single guardrail's hook.

Args:
    callback: The guardrail callback to execute
    hook_type: One of "pre_call", "during_call", "post_call"
    data: Request data
    user_api_key_dict: User API key auth
    call_type: Type of call
    response: Response object (for post_call hooks)

Returns:
    Result from the guardrail execution
apply_guardrailduring_calluse_native_during_call_hookFguardrail_to_applypre_callr   r  cacher  r  Nr  r  r  	post_callr  r  r  zUnknown hook_type: )	r   r@  r   unified_guardrailasync_pre_call_hookr   async_moderation_hookasync_post_call_success_hook
ValueError)
r   r   r  r  r  r  r  has_apply_guardrailuse_unifiedtargets
             r{   _execute_guardrail_hook$ProxyLogging._execute_guardrail_hook  s    0 04>3J3JJ) 
& H"?G/
 )1%&&1"x
"33"3''(<=#	 4    -'55"3# 6   
 +%<<"3! =    29+>??'s6   BCCC#C$CCCCCc           	         #    SSK Jn  Uc  [        S5      eUR                  US9nUR	                  S5      n	U	c  [        SU 35      eU R                  U	UUUUUS9I Sh  vN $  N7f)	ah  
Execute a guardrail using the router's load balancing.

Args:
    guardrail_name: Name of the guardrail
    hook_type: One of "pre_call", "during_call", "post_call"
    data: Request data
    user_api_key_dict: User API key auth
    call_type: Type of call
    response: Response object (for post_call hooks)

Returns:
    Result from the guardrail execution
r   r   NzRouter not initialized)r   r   z!No callback found for guardrail: )r   r  r  r  r  r  )r  r   r  get_available_guardrailr&  r  )
r   r   r  r  r  r  r  r   selected_guardrailr   s
             r{   &_execute_guardrail_with_load_balancing3ProxyLogging._execute_guardrail_with_load_balancing!  s     . 	:566 (??) @ 
 &))*5@@PQRR11/ 2 
 
 	
 
s   AA&A$ A&
event_typec                   #    SSK Jn  SSKJn  XWR                  L a*  U[
        R                  R                  :X  a  UR                  nUR                  X%S9SLa  gUR                  n[        R                  " 5       n	Sn
Sn U(       a2  U R                  U5      (       a  U R                  USUUUS	9I Sh  vN nOU R                  USUUUS
9I Sh  vN nUb  U R!                  XUS9I Sh  vN nUR#                  U5         [        R                  " 5       nX-
  nU=(       d*    [/        USUR0                  R*                  5      =(       d    Sn[2        R4                   H*  n[7        UU5      (       d  M  UR9                  UUU
USS9    U$     U$  N N N! [$         a    Sn
e [&         a(  nSn
[)        U5      R*                  n[-        X5        e SnAff = f! [        R                  " 5       nX-
  nU=(       d*    [/        USUR0                  R*                  5      =(       d    Sn[2        R4                   H)  n[7        UU5      (       d  M  UR9                  UUU
USS9    f    f = f7f)a  
Process a guardrail callback during pre-call hook.

Supports load balancing when multiple guardrail deployments exist.

Args:
    callback: The CustomGuardrail callback to process
    data: The request data dictionary
    user_api_key_dict: User API key authentication details
    call_type: The type of API call being made

Returns:
    Updated data dictionary if guardrail passes, None if guardrail should be skipped
r   )PrometheusLoggerr#   r  r  TNr7  r  )r   r  r  r  r  )r   r  r  r  r  r  r  r  
intervenedrm  r   unknown)r   latency_secondsr-   
error_typer  )litellm.integrations.prometheusr  litellm.types.guardrailsr$   r  r&   call_mcp_toolr   pre_mcp_callshould_run_guardrailr   timeperf_counterr  r  r  r  mark_pre_call_hook_ranr;   ri  r   r   r   r   	__class__rv   r*  r   _record_guardrail_metrics)r   r   r  r  r  r  r  r$   r   guardrail_start_timer-   r  r  rs  guardrail_end_timer  metrics_guardrail_nameprom_callbacks                     r{   _process_guardrail_callback(ProxyLogging._process_guardrail_callbackO  s    , 	E@ 666Y44:::,99J ((d(JRVV!00  $002
=	$"K"K# # "&!L!L#1(&7' "M "  "&!=!=%(&7' "> "  #!@@%I A   ++D1 "&!2!2!40GO  8%5x7I7I7R7RS # ")!2!2m-=>>!;;'=(7%#-", <   "3 u + 	!F 	Fa))J9!F	 "&!2!2!40GO  8%5x7I7I7R7RS # ")!2!2m-=>>!;;'=(7%#-", <   "3sz   A=I# 3F 3F4F FF *F+F A.I#3I#F F F G*#GGG A/I I  I#litellm_logging_obj	prompt_idprompt_versionc                   #    SSK JnJn  SSKJn  SSKJn	  Uc  U" UUR                  S9n
OU" X4S9n
UR                  U
5      nUR                  U
5      nSnUb(  UR                  R                  nUR                  SS5        U(       Ga  Ub  UR                  UR                  S	S
5      UR                  S/ 5      U	" US9=(       d    0 UUUUR                  SS5      =(       d    0 UR                  SS5      =(       d    0 UR                  SS5      =(       d    0 S9	I Sh  vN u  nnnUR                  U5        XS	'   XS'   UR                  SS5        UR                  SS5        UR                  SS5        UR                  SS5        ggg Nl7f)z&Process prompt template if applicable.r   )construct_versioned_prompt_idget_latest_version_prompt_id)IN_MEMORY_PROMPT_REGISTRY)!get_non_default_completion_paramsN)r  all_prompt_ids)r  versionr  rL  re  rT  )r   prompt_variablesprompt_labelr  )	rL  rT  non_default_paramsr  prompt_specprompt_management_loggerr  r  r  )&litellm.proxy.prompts.prompt_endpointsr  r  %litellm.proxy.prompts.prompt_registryr  litellm.utilsr  IN_MEMORY_PROMPTSget_prompt_callback_by_idget_prompt_by_idlitellm_paramsr  pop async_get_chat_completion_promptr&  update)r   r  r  r  r  r  r  r  r  r  lookup_prompt_idcustom_loggerr
  litellm_prompt_idrL  rT  optional_paramss                    r{   _process_prompt_template%ProxyLogging._process_prompt_template  s    	
 	TC!;#8JJ 
  =#  2KK
 0@@AQR+/" + : : D DHH[$'[4
 *JJhhw+*b1#DD#Q#WUW+')6!%*<d!C!Ir!XXnd;Ar#xx(8$?E2 K 
 
	 KK(!M'HH[$'HH'.HH^T*HH%t,1 5=

s   DFFA-Fc                    SSK Jn  UR                  S5      =(       d    0 nUR                  S5      =(       d    0 n/ n[        U[        5      (       a  SU;   a  UR                  S/ 5      nO-[        U[        5      (       a  SU;   a  UR                  S/ 5      nU(       a  [        U[
        5      (       a  / n[        U[        5      (       a  SU;   a  UR                  S/ 5      nO-[        U[        5      (       a  SU;   a  UR                  S/ 5      n[        U[
        5      (       d  / nU H'  n[        U[        5      (       d  M  Xv;  d  M!  U" XS9  M)     ggg)	z?Process guardrails from metadata and add to applied_guardrails.r   )*add_guardrail_to_applied_guardrails_headermetadatalitellm_metadata
guardrailsapplied_guardrails)r  r   N))litellm.proxy.common_utils.callback_utilsr  r&  r   r   r   ry   )r   r  r  metadata_standardmetadata_litellmguardrails_in_metadatar!  r   s           r{   _process_guardrail_metadata(ProxyLogging._process_guardrail_metadata  s=   	
 !HHZ06B88$67=2!#'..<CT3T%6%:%:<%L"($//LDT4T%5%9%9,%K"!j1G&N&N!#,d33(,==%6%:%:;OQS%T"+T22(,<<%5%9%9:NPR%S"0$77%'""8~s33&@>%) #9! 'O!r}   r   c           
      b  #    UR                  SUR                  S0 5      5      =(       d    0 nUR                  S5      nU(       d  U$ U H]  u  pxUR                  U:w  a  M  [        R                  " UR                  UR                  UUUUS9I Sh  vN n	U R                  U	UUS9nM_     U$  N7f)z
Execute guardrail pipelines if any are configured for this request.

Checks metadata for pipelines resolved by the policy engine
and executes them. Handles the result (allow/block/modify_response).

Returns the (possibly modified) data dict.
r  r  _guardrail_pipelines)stepsmoder  r  r  policy_nameN)r  r  r,  )r&  r+  r^   execute_stepsr*  _handle_pipeline_result)
r   r  r  r  r   r  	pipelinesr,  pipeliner  s
             r{   _maybe_execute_pipelines%ProxyLogging._maybe_execute_pipelines"  s      88J1CR(HIORLL!78	K%.!K}}
*4D4R4Rnn]]"3#'5 /F //' 0 D &/& /s   BB/B-B/r  r,  c                    U R                   S:X  a*  U R                  b  UR                  U R                  5        U$ U R                   S:X  aW  U R                   Vs/ s H'  nUR                  UR
                  UR                  S.PM)     nnSSU S3SUUS	.S
.0n[        SUS9eU R                   S:X  a3  [        U R                  =(       d    SUR                  SS5      USU 3SS9eU$ s  snf )u   
Handle a PipelineExecutionResult — allow, block, or modify_response.

Returns data dict if allowed, raises on block/modify_response.
allowNblock)	guardrailoutcomeactionrm  z'Content blocked by guardrail pipeline ''guardrail_pipeline_error)policystep_results)r  r   pipeline_contextr  r  modify_responsezResponse modified by pipelinerL  r  z	pipeline:)r  rL  r  r   detection_info)terminal_actionmodified_datar  r<  r   r7  action_takenr,   r=   modify_response_messager&  )r  r  r,  srstep_results_serializableerror_details         r{   r.  $ProxyLogging._handle_pipeline_resultK  s    !!W,##/F001K!!W, !--) .B	 "$!2!2!zz oo
 . & ) !HUVW6"-(A)	L  CEE!!%66)66 32hhw	2!!*;-8#  =)s   .C'c                    #    g 7fr   r   r   r  r  r  s       r{   pre_call_hookProxyLogging.pre_call_hook}  
      	   c                    #    g 7fr   r   rI  s       r{   rJ  rK    rL  rM  c           
        #    [         R                  " S5        U R                  US9  Uc  g[        [        S   UR                  SS5      5      nUR                  SS5      nUR                  SS5      nUb*  Ub'  US:X  d  US	:X  a  U R                  UUUUUS
9I Sh  vN    U R                  UUUSS9I Sh  vN nUR                  SUR                  S0 5      5      =(       d    0 nUR                  S[        5       5      n[        R                  5       n	U	R                  (       d'  U	R                  (       d  Ub  U R                  U5        U$ Sn
U	R                   GH  n[        R                  " 5       n [!        U["        5      (       aW  UbT  UR$                  (       a  UR$                  U;   a  MU  U R'                  UUUU[(        R*                  S9I Sh  vN nUc  M  UnOUb  [!        U[,        5      (       a  S[/        UR0                  5      ;   au  UR0                  R2                  [,        R2                  :w  aM  US:X  a  Uc  M  UR3                  UU R4                  S   UUS9I Sh  vN nUb  U R7                  XUS9I Sh  vN n[        R                  " 5       nUU-
  n[;        U S5      (       d  GMZ  US:  d  GMc  U R<                  R?                  [@        RB                  UUR0                  RD                   URF                  UUS9I Sh  vN   GM     U
b  Ub  U RI                  XU5      I Sh  vN nUb  U R                  U5        U$  GN GN GN~ N N! [8         a  nU
c  Un
 SnANSnAff = f Nh NE! [8         a;  nU RI                  XU5      I Sh  vN  nUb  U R                  U5        Us SnA$ SnAf[J         a  nUeSnAff = f7f)z
Allows users to modify/reject the incoming request to the proxy, without having to deal with parsing Request body.

Covers:
1. /chat/completions
2. /embeddings
3. /image/generation
z#Inside Proxy Logging Pre-call hook!r  NLiteLLMLoggingObjr  r  r  r  acompletion)r  r  r  r  r  r  )r  r  r  r   r  r  _pipeline_managed_guardrails)r   r  r  r  r  r  r  r   r  r  r   g{Gz?)servicedurationr  r   
start_timeend_time)&r4   rs   #_init_response_taking_too_long_taskr   r   r&  r  r1  r  r   _callback_capabilitiesr   r   r&  r   r  r   r<   r   r  r$   r  r?   varsr  r  r   r  r;   rA  r   async_service_success_hookr6   PROXY_PRE_CALLr   r   &_handle_sensitive_data_route_exceptionri  )r   r  r  r  r  r  r  r  pipeline_managedcapsdeferred_route_exc	_callbackrV  r  r  rs  rW  rU  s                     r{   rJ  rK    s     	""#HI00d0;<"()4884I4+P
 HH[$/	"2D9
  +%l*i=.H//$7#-# 0   k	66"3#%	 7  D xx
DHH5G,LMSQSH$,LL1OQTQV$W668D %%d.H.H#44T:HL!44	!YY[
//!)_==$BR &44 ) 8 8<L L$'+'G'G%.!%.?&/':'C'C (H ( " ">$% "-&y,??1T):M:M5NN%//CC';;< %7<M<U$)2)F)F.?"&"3"34H"I!%&/	 *G * $ $/)-)L)L)1	 *M * $D  99;#j0D"788X_22MM , ; ;!)%.%8%8%A%A$B):)K)K#-!) N   q 5B "-$2B!HH&.?  006KUD"*$$ 3 / *1-.*/ + 	DD*  D 006K 	G	s5  BOMO!M8 6M7BM8 O'M8 49M-M8 /$MMMM8 MM8  A"MM8 "M&M'MMM)M8 4M8 =AM8 M4$M8 0M61M8 
OM8 MMM
M1"M,'M8 ,M11M8 6M8 8
ON8NN82O3O8OOOOr   c                   #    Uc  g[         R                  " SUR                  UR                  UR                  UR
                  5        UR
                  (       a  U R                  S5      n[        U[        5      (       a9  UR                  UR                  UR                  UUR                  S9I Sh  vN   O![         R                  " SUR                  5        UR                  S5      nUR                  US'   UR                  S5      =(       d    0 nSUS	'   XVS
'   UR                  US'   UR                  US'   XbS'   U$  N7f)z
Handle SensitiveDataRouteException by rerouting the current request to
the target model and, when sticky_session_routing is enabled, persisting
the session override so subsequent requests reuse the same model.
NzZSensitiveDataRouteException caught: session_id=%s route_to_model=%s guardrail=%s sticky=%ssensitive_data_routing)
session_idrL  r  r   zSensitiveDataRouteException requested sticky routing for session_id=%s but the 'sensitive_data_routing' hook is not registered. Only this request will be rerouted; subsequent requests will not be sticky.rL  r  Tsensitive_data_routing_applied%sensitive_data_routing_original_model sensitive_data_routing_guardrail%sensitive_data_routing_detection_info)r4   inford  route_to_modelr   sticky_session_routingrX   r   r>   set_session_routingrl  r&  r?  )r   r   r  r  sensitive_routing_hookoriginal_modelr  s          r{   r]  3ProxyLogging._handle_sensitive_data_route_exception&  sA     <!!hNN&&	
 %%%)%8%89Q%R"02TUU,@@"~~,,&7#&#5#5	 A    %,,P NN	 '***W88J'-25912<J897:7I7I34<?<N<N89#Z1s   B1E3E4BEcoroc                 `   #     UI Sh  vN $  N! [          a  n[        X 5        e SnAff = f7f)z
Await `coro`; if it raises an HTTPException with dict detail,
enrich the detail with the originating callback's `guardrail_name`
and `guardrail_mode` before re-raising.
Nri  r   )r   rp  rs  s      r{   #_run_guardrail_task_with_enrichment0ProxyLogging._run_guardrail_task_with_enrichmentY  s.     	:: 	9!F	s(   .  . 
+&+.genc                t   #     U  Sh  vN nU7v   M   N
 g! [          a  n[        X05        e SnAff = f7f)ao  
Yield from `gen`; if iteration raises an HTTPException with dict detail,
enrich the detail with the originating callback's `guardrail_name` and
`guardrail_mode` before re-raising. Used to wrap each layer of the
async_post_call_streaming_iterator_hook chain so the enrichment is
attributed to the callback that produced the chunk pipeline at that
point in the chain.
Nrr  )r   ru  chunkrs  s       r{   (_wrap_streaming_iterator_with_enrichment5ProxyLogging._wrap_streaming_iterator_with_enrichmenth  s:     	" es 	9!F	s4   8   8
5058.r   _callback_capabilities_cachec                     [         R                  n [        U 5      [        S U  5       5      4n[        R
                  nUR                  U5      nUb  U$ SnSnSnSnSn/ n	/ n
U  GH9  n[        U[        5      (       a8  [         R                  R                  R                  [        [        U5      5      nOUnUb  [        U[        5      (       d  Mm  U
R                  U5        [!        U5      nU[        L a  M  [        U["        5      (       a  SnUR$                  nSU;   a  SnSU;   a  SnU	R                  US45        OSU;   a  U	R                  US45        [        R&                  n[)        USU5      n[)        US	U5      [)        US	U5      La  SnS
U;   d  GM7  SnGM<     [+        UU=(       d    [-        S U	 5       5      UUU[        U	5      [        U
5      S9n[        U5      S:  a  UR/                  5         UX!'   U$ )u  
Inspect ``litellm.callbacks`` once and answer the per-hook capability
questions used to short-circuit no-op work on the chat-completions hot
path. Per-request callers iterated ``litellm.callbacks`` and called
``get_custom_logger_compatible_class`` for every string entry — that
scanning cost dominated the proxy overhead on low-config deployments.

Cache invalidates whenever the list length or member identities change.
c              3   8   #    U  H  n[        U5      v   M     g 7fr   )r   .0cs     r{   	<genexpr>6ProxyLogging._callback_capabilities.<locals>.<genexpr>  s     $>IqRUUIs   FTr   'async_post_call_streaming_iterator_hookoverrider  async_post_call_streaming_hook__func__r  c              3   0   #    U  H  u  pUS :H  v   M     g7f)r  Nr   )r~  _kinds      r{   r  r    s     O<N4,,<Ns   )r   r   r   r   r   r   r       )rv   r*  r}  r   r   rz  r&  r   ry   r+  r,  "get_custom_logger_compatible_classr   r   r?   appendr   r<   r@  r  r   r   anyclear)r*  r   r  cachedr   r   r   r   r   r   r   r   resolvedcls	cls_attrsbase_streaming_hookcls_streaming_hookr_  s                     r{   rY  #ProxyLogging._callback_capabilities  s     %%	9~u$>I$>>?993M).& %',$ %46(*!H(C((..>>aaH(S  $z(L'I'I%%h/x.Cl"(O44 $ I6)C15.8IE(,%"))8Z*@A"i/"))85F*GH #/"M"M!(0#"
 "J0B0*>QRS 04,$	1(,%c "f %+I"7 #PO<NOO)E'"7$%78$%78	
 u:KKM
r}   c                  >    [         R                  5       R                  $ r   )r   rY  r   r   r}   r{   (has_post_call_response_headers_callbacks5ProxyLogging.has_post_call_response_headers_callbacks  s    224SSSr}   c                      [         R                  5       n U R                  =(       d    U R                  =(       d    U R                  $ r   )r   rY  r   r   r   r_  s    r{   has_streaming_callbacks$ProxyLogging.has_streaming_callbacks  s:    224&& "00"!!	
r}   c                  h    [         R                  5       n U R                  =(       d    U R                  $ )z|True iff any callback overrides ``async_post_call_streaming_hook``
(the per-chunk hook, distinct from the iterator wrapper).r   rY  r   r   r  s    r{   "has_streaming_chunk_hook_overrides/ProxyLogging.has_streaming_chunk_hook_overrides  s)     22400FD4F4FFr}   c                 >    [         R                  5       R                  $ )zWhether ``async_data_generator`` needs to wrap the upstream stream
through ``async_post_call_streaming_iterator_hook``. Instance method
so tests can override the gate via ``MagicMock(spec=ProxyLogging)``.
)r   rY  r   r   s    r{   needs_iterator_wrap ProxyLogging.needs_iterator_wrap  s    
 224JJJr}   c                 h    [         R                  5       nUR                  =(       d    UR                  $ )zWhether ``async_data_generator`` needs to call the per-chunk
``_apply_streaming_chunk_hooks`` for every emitted chunk. Instance
method for the same reason as :py:meth:`needs_iterator_wrap`.
r  )r   r_  s     r{   needs_per_chunk_streaming_hook+ProxyLogging.needs_per_chunk_streaming_hook  s)    
 22400FD4F4FFr}   c                  >    [         R                  5       R                  $ r   )r   rY  r   r   r}   r{   has_during_call_guardrails'ProxyLogging.has_during_call_guardrails  s    224BBBr}   c           
        #    [         R                  5       R                  (       d  U$ / n[        R                   GHX  n[        U[        5      (       d  M  UR                  c$  [        US5      (       a  UR                  S:X  a    gOPSSK
Jn  UR                  nU[        R                  R                  :X  a  UR                   nUR#                  XS9SLa  M  U[        R                  R                  :X  a  U R%                  U5      nOUnS['        U5      R(                  ;   a?  Ub<  [+        US	S
5      (       d*  XQS'   U R-                  U[.        R1                  UUUS95      n	O!U R-                  UUR1                  UUUS95      n	UR3                  U	5        GM[     U(       a   [4        R6                  " U6 I Sh  vN   U$ U$  N! [8         a  n
U
eSn
A
ff = f7f)z@
Runs the CustomGuardrail's async_moderation_hook() in parallel
Nmoderation_checkr  r   r#   r  Tr  r  Fr  )r  r  r  r  )r   rY  r   rv   r*  r   r<   r   rA  r  r  r$   r  r&   r  r   during_mcp_callr  rC  r   r@  r   rs  r  r  r  r  gatherri  )r   r  r  r  guardrail_tasksr   r$   r  r  guardrail_taskrs  s              r{   during_call_hookProxyLogging.during_call_hook  s     224BBK))H(O44 &&.704 4  00J> ? M!4!@!@J I$;$;$A$AA%8%H%H
 !5545W#$ !	 7 7 = ==-1-T-T).* .?* &h)@)@@)5#H.KUSS19-.%)%M%M )??.?!%&/ @ &N &*%M%M  66!%.D&/ 7 &N  &&~6q *v nno666
 t 7 sC   AGE	GG  5F>6G  :G>G   
G
GGGrc  failing_modelc                    #    U R                   c  g U R                  (       a#  U R                  R                  UUS9I S h  vN   g g  N7f)N)rc  r  )r   r   failed_tracking_alert)r   rc  r  s      r{   r  "ProxyLogging.failed_tracking_alert]  sQ     
 == ''..DD++ E    (s   =AA Ar   )	token_budgetuser_budgetsoft_budgetmax_budget_alertteam_budgetorganization_budgetproxy_budgetprojected_limit_exceededproject_budget	user_infoc                   #    US:H  =(       a-    UR                   S L=(       a    [        UR                   5      S:  nU R                  c  U(       d  g U R                  b?  SU R                  ;   a/  U R                  b"  U R                  R	                  UUS9I S h  vN   U R                  S L=(       a    SU R                  ;   =(       d    UnU(       a1  U R
                  b#  U R
                  R	                  UUS9I S h  vN   g g g  Nj N	7f)Nr  r   r  )r   r  email)alert_emailsr}  r   r   budget_alertsr   )r   r   r   is_soft_budget_with_alert_emailsshould_send_emails        r{   r  ProxyLogging.budget_alertsk  s    ( M! 0&&d20I**+a/ 	) == )I==$DMM)A++722@@' A    MM%B'T]]*B.- 	 !<!<!H--;;# <    "Is%   BDDA"D;D<DDr  level)LowMediumHigh
alert_typer  c           
        #    U R                   c  gSSKJn  UR                  " 5       R                  S5      n[        R
                  " SS5      nSU SU SU 3nUb	  US	U S
3-  n0 n	0 n
Ubk  [        US9I Sh  vN nUb  XS'   USR                  U5      -  nSU;   a9  US   R                  SS5      b#  [        US   S   [        5      (       a  US   S   n
U R                    H  nUS:X  a,  U R                  R                  " SUUUSU
S.U	D6I Sh  vN   M5  US:X  d  M=  [        R                  R                  b+  [        R                  R                  R!                  U5        M  [#        S5      e   g N Nd7f)a  
Alerting based on thresholds: - https://github.com/BerriAI/litellm/issues/1298

- Responses taking too long
- Requests are hanging
- Calls are failing
- DB Read/Writes are failing
- Proxy Close to max budget
- Key Close to max budget

Parameters:
    level: str - Low|Medium|High - if calls might fail (Medium) or are failing (High); Currently, no alerts would be 'Low'.
    message: str - what is the alert about
Nr   )r   z%H:%M:%SPROXY_BASE_URLzLevel: `z`
Timestamp: `z`

Message: z

Proxy URL: ``r  u   🪢 Langfuse Traceu   

🪢 Langfuse Trace: {}r  alerting_metadatar  )r  r  r  r  r  sentryz#Missing SENTRY_DSN from environmentr   )r   r   nowstrftimer   r   rA   rt   r&  r   r   r   
send_alertrv   utilssentry_sdk_instancecapture_messageri  )r   r  r  r  r  r   current_time_proxy_base_urlformatted_messageextra_kwargsr  _urlclients                r{   alerting_handlerProxyLogging.alerting_handler  s    * == %  ||~..z:))$4d;ug_\N.	R 	 &#3O3DA!FF#8lSSD6:23!%B%I%I$%OO!l* ,001DdKW|J78KLdSS$0$<=P$Q!mmF 22== #)"&7 #   8#==44@MM55EEFWX#$IJJ $ Ts,   A6E88E49BE8E6
E8 AE86E8rU  c           	      :  #    [         R                  U R                  ;  a  g[        U[        5      (       ax  [        UR
                  [        5      (       a  UR
                  nOW[        UR
                  [        5      (       a!  [        R                  " UR
                  5      nO[        U5      nO[        U5      n[        U[        5      (       a  XTSS -  n[        U5      n[        R                  " U R                  SU 3S[         R                  0 S95        [        U S5      (       a2  U R                  R!                  ["        R$                  UUUS9I Sh  vN   [&        R(                  R*                  (       a  [&        R(                  R+                  US9  gg NB7f)	zE
Log failed db read/writes

Currently only logs exceptions to sentry
N  zDB read/write call failed: r  r  r  r  r  r   )rT  rU  rm  r  )rm  )rF   db_exceptionsr   r   r,   r   ry   r   ry  dumpsr3   r  r  r  rA  r   async_service_failure_hookr6   DBrv   r  capture_exception)r   original_exceptionrU  r  traceback_strrc  s         r{   failure_handlerProxyLogging.failure_handler  s]     ""$*:*::(-88,33S99 2 9 9.55t<< $

+=+D+D E #$6 7 23MmS))5D11M&}5!!5m_E$22	 " 	
 4.//**EE$!##	 F    ==**MM++2D+E +s   EFFAFr  r  router  c           	        #    U R                  UR                  SS5      SS9I Sh  vN   [        R                  U R                  ;   a|  [        U[        [        45      (       da   [        USS5      n[        U5      nUb  X-  n[        R                  " U R                  [        SU S35      S	[        R                  US
95        U R                  UUUR                  S9(       a  U R!                  UUUUS9I Sh  vN   UR                  S5      n	U	bQ  [        U	S0 5      n
U
R                  S5      nUb  XS'   U
R                  S5      nUb  XS'   U
R                  S5      US'   UR#                  SS5        Sn[$        R&                   H  n Sn[        U[        5      (       a8  [$        R(                  R*                  R-                  [/        [0        U5      5      nOUnUbR  [        U[2        5      (       a;   UR5                  UUUUS9I Sh  vN n[        U[        5      (       a	  Uc  UnM  M  M  M  M     U$  GN GNA N2! [         a  nUc  Un SnAM   SnAM  SnAf[6         a$  n[8        R:                  " SU 35         SnAM  SnAff = f! [6         a%  n[8        R:                  " SU 35         SnAGM1  SnAff = f7f)a  
Allows users to raise custom exceptions/log when a call fails, without having to deal with parsing Request body.
Callbacks can return or raise HTTPException to transform error responses sent to clients.

Covers:
1. /chat/completions
2. /embeddings
3. /image/generation

Args:
    - request_data: dict - The request data.
    - original_exception: Exception - The original exception.
    - user_api_key_dict: UserAPIKeyAuth - The user api key dict.
    - error_type: Optional[ProxyErrorTypes] - The error type.
    - route: Optional[str] - The route.
    - traceback_str: Optional[str] - The traceback string, sometimes upstream endpoints might need to send the upstream traceback. In which case we use this

Returns:
    - Optional[HTTPException]: If any callback returns or raises an HTTPException, the first one found is returned.
                              Otherwise, returns None and the original exception is used.
r6  re  r8  )r6  r-   Nlitellm_debug_infozLLM API call failed: `r  r  r  )r  r  r  )r  r  r  r  r  model_call_detailsfirst_api_call_start_timecombined_usage_objectresponse_cost)r  r  r  r  z?[Non-Blocking] Error in async_post_call_failure_hook callback: zA[Non-Blocking] Error setting up post_call_failure_hook callback: )r<  r&  rF   llm_exceptionsr   r   r,   r   r   ry   r  r  r  r3   _is_proxy_only_llm_api_errorrequest_route _handle_logging_proxy_only_errorr  rv   r*  r+  r,  r  r   r   r?   async_post_call_failure_hookri  r4   	exception)r   r  r  r  r  r  r  r  exception_str_logging_obj_model_call_details_first_handoff_recovered_usagetransformed_exceptionr   ra  hook_resultrs  s                     r{   post_call_failure_hook#ProxyLogging.post_call_failure_hook  s    @ (((,,->CF ) 
 	
 	
 ##t'7'77
 ?A
 A

 "));=QSW!X 23M!-3%%*-CM?RS+TU (77!-	 &  ,,1!#11 - 

 77)"3#5	 8    $''(=>#"),8Lb"Q0445PQN)<J89  3667NO+8H450C0G0G0X_- 	.5 :>))H"48	h,, ' : : J J m mH(S!I !)I(Z	<-P-P,5,R,R)5.?/A*7	 -S - ' '{MBB 5 =4?1 !> C .Q( *J %$K	
>X' ) 608451 9$ ,66]^_]`a 
  $..WXYWZ[ s   $KH8CK:H;;BKA)J6I H>I *K;K>I  
J
IJKJKJ(JJKJJ
J>J92K9J>>Kc                     Uc  g[         R                  " U5      (       d  [         R                  " U5      (       d  g[        U[        [
        45      =(       d    U[        R                  :H  $ )a-  
Return True if the error is a Proxy Only LLM API Error

Prevents double logging of LLM API exceptions

e.g should only return True for:
    - Authentication Errors from user_api_key_auth
    - HTTP HTTPException (rate limit errors)
    - ProxyException (guardrail blocks, budget / rate-limit errors)
F)rK   is_llm_api_routeis_info_router   r,   r   r   
auth_error)r   r  r  r  s       r{   r  )ProxyLogging._is_proxy_only_llm_api_error  sX    0 =((//;3L3LU3S3S,}n.MN 
/444	
r}   c                   #    UR                  SS5      nUc  SSKJn  [        UR	                  5       5      US'   [
        R                  " US9n[        R                  R                  " SU=(       d    S[        R                  R                  5       [        R                  " 5       S.UD6u  pXS	U;  a  0 US	'   US	   R                  U5        UGb  0 n	0 n
[        R                  R!                  5       nUR#                  5        H  u  pX;   a  XU'   M  US
;  d  M  XU'   M     UR%                  UR                  SS5      UR                  SS5      U	U
S9  SnSnSU;   an  ['        US   [(        5      (       aV  US   nXR*                  S'   UR,                  [.        R0                  R2                  :w  a  [.        R4                  R2                  nOSU;   an  ['        US   [        5      (       aV  US   nXR*                  S'   UR,                  [.        R0                  R2                  :w  a  [.        R6                  R2                  nOsSU;   am  ['        US   [(        5      (       aU  US   nXR*                  S'   UR,                  [.        R0                  R2                  :w  a  [.        R8                  R2                  nUb  Xl        UUR*                  S'   UR,                  [.        R0                  R2                  :X  a  gSUR*                  [:        '   UR=                  USS9  UR?                  U[@        RB                  " 5       S9I Sh  vN   [D        RF                  " URH                  U[@        RB                  " 5       4SS9RK                  5         gg NI7f)z
Handle logging for proxy only errors by calling `litellm_logging_obj.async_failure_handler`

Is triggered when self._is_proxy_only_error() returns True
r  Nr   )uuidr6  )r  IGNORE_THIS)original_function	rules_objrV  r  )rL  rI  r  rL  re  rI  )rL  rI  r  r  rT  promptinputr  T)r  api_key)r  traceback_exception)r  r  daemonr   )&r&  litellm._uuidr  ry   uuid4r]   'get_sanitized_user_information_from_keyrv   r  function_setupRulesr   r  r  ro   r   r   r.  update_environment_variablesr   r   r  r  r&   pass_throughr   rR  atext_completion
aembeddingr   r  async_failure_handlerrr   ru   	threadingThreadr  start)r   r  r  r  r  r  r  user_api_key_logged_metadatar  _optional_params_litellm_paramslitellm_param_keyskvr  normalized_call_types                   r{   r  -ProxyLogging._handle_logging_proxy_only_error  so     2>1A1A!42
 &*.1$**,.?L*+(PP&7 ) )0(D(D )"'"8=!----/#<<>) 	)% -+-Z($++,HI*! O!4!D!D!I!I!K$**,*)*A&FF*+Q'	 -  <<"&&w3!%%fb1 0.	 =  -/E26 \)jZ($/ / %Z0EJ66zB&00I4J4J4P4PP+4+@+@+F+F(\)jh9OQT.U.U$X.CH66x@&00I4J4J4P4PP+4+E+E+K+K(L(ZW8Mt-T-T$W-BG66w?&00I4J4J4P4PP+4+?+?+E+E(#/0D-( $66{C
 #,,	0F0F0L0LL   224  (( )  &;;,$-$8$8$: <   
 *::&((*  egU +|s   DNH#N<N=A
Nc                   #    SSK Jn  SSKJn  / n/ n [        R
                   H  nSn	[        U[        5      (       a8  [        R                  R                  R                  [        [        U5      5      n	OUn	U	c  MY  [        U	[        5      (       a  UR                  U	5        M  UR                  U	5        M     [        XS9n
U H  nUR!                  U
UR"                  S9SLa  M"  SnS[%        U5      R&                  ;   a#  XS	'    [(        R+                  UUUS
9I Sh  vN nO UR+                  UUUS
9I Sh  vN nUc  M  UnM     U H"  nUR+                  X1US
9I Sh  vN nUc  M   UnM$     U$  NT! [,         a  n[/        X5        e SnAff = f NY! [,         a  n[/        X5        e SnAff = f NQ! [,         a  nUeSnAff = f7f)zp
Allow user to modify outgoing data

Covers:
1. /chat/completions
2. /embeddings
3. /image/generation
4. /files
r   r   r#   Nr  r   r  Tr  r  r  )r  r   r  r$   rv   r*  r   ry   r+  r,  r  r   r   r<   r  '_check_and_merge_model_level_guardrailsr  r  r   r@  r  r  ri  r   )r   r  r  r  r   r$   guardrail_callbacksother_callbacksr   ra  guardrail_dataguardrail_responsers  callback_responses                 r{   post_call_success_hook#ProxyLogging.post_call_success_hook!	  s      	:@57.0L	#--48	h,, ' : : J J m mH(S!I !)I(!)_==+229='..y9 .$ EN 0 11+#6#@#@ 2   	  48"$X(?(??19-.
"3"P"P2C%))1 #Q #  +
"*"G"G2C%))1 #H #  + &11HS 0\ ,*2*O*O&7X +P + %! %00H , I % EaR % EaR%
  	G	s   G
A%F6 =B	F6 E6E4 E6$F6 &F:F;F?F6 F6 "F4#F6 ,F6 2G
4E66
F FFF6 F
F1 F,,F11F6 6
G GGG
request_headersc           	        #    0 n[         R                  5       R                  (       d  U$  U R                  XS9n[        R
                   H  nSn[        U[        5      (       a8  [        R                  R                  R                  [        [        U5      5      nOUnUc  MY  [        U[        5      (       d  Mp  [        U5      (       a  UR                  UUUUUS9I Sh  vN n	OUR                  UUUUS9I Sh  vN n	U	c  M  UR!                  U	5        M     U$  N; N"! ["         a+  n
[$        R&                  " S[        U
5      5         Sn
A
U$ Sn
A
ff = f7f)z
Calls async_post_call_response_headers_hook on all CustomLogger callbacks.
Merges all returned header dicts (later callbacks override earlier ones).

Returns:
    Dict[str, str]: Merged headers from all callbacks.
)r  r  N)r  r  r  r0  r   )r  r  r  r0  z,Error in post_call_response_headers_hook: %s)r   rY  r   _build_litellm_call_inforv   r*  r   ry   r+  r,  r  r   r   r?   r   r   r  ri  r4   r  )r   r  r  r  r0  merged_headersr   r   ra  r  rs  s              r{   post_call_response_headers_hook,ProxyLogging.post_call_response_headers_hook	  sd     *, 224SS!!%	 $ = = !> ! $--48	h,, ' : : J J m mH(S!I !)I(Z	<-P-P1)<<'0'V'V!%.?%-,;.? (W ( " (1'V'V!%.?%-,;	 (W ( " )&--f57 .@ +""  	 **>A  		se   (EA4D  #D  :&D   D!D  ;D<D  D  ED  D   
E* E
EEEc                    [        US0 5      =(       d    0 nU R                  S5      =(       d    0 R                  S5      =(       d2    U R                  S5      =(       d    0 R                  S5      =(       d    0 nUR                  S5      =(       d    [        USS5      UUR                  S5      UR                  S5      S	.$ )
z
Build a normalized dict of routing metadata from response._hidden_params
and data, abstracting away the metadata vs litellm_metadata split.
_hidden_paramsr  
model_infor  custom_llm_providerNapi_basemodel_id)r9  r8  r:  r;  )r   r&  )r  r  r  r8  s       r{   r2  %ProxyLogging._build_litellm_call_info	  s      *:B?E2 XXj!'R,,\: +,277E 	 $1#4#45J#K $>x!6=$%))*5%))*5
 	
r}   c                 6   ^ / SQn[        U4S jU 5       5      $ )N)jsonrpcr   r  c              3   ,   >#    U  H	  oT;   v   M     g 7fr   r   )r~  r   r  s     r{   r  9ProxyLogging.is_a2a_streaming_response.<locals>.<genexpr>	  s     <ms(?ms   )all)r   r  expected_keyss    ` r{   is_a2a_streaming_response&ProxyLogging.is_a2a_streaming_response	  s    3<m<<<r}   
str_so_farc                   #    [         R                  5       nUR                  (       d  UR                  (       d  U$ SSKJn  Sn[        U[        [        45      (       a  [        R                  " US9nO9[        U[        5      (       a$  U R                  U5      (       a  SSKJn  U" U5      nUb  Sn	Sn
[        R                   H  n Sn[        U[         5      (       a7  SSKJn  U
(       d  ['        XS9n	S	n
UR)                  U	UR*                  S
9S	La  MR  [        U[,        5      (       a8  [        R.                  R0                  R3                  [5        [6        U5      5      nOUnUbB  [        U[8        5      (       a+  Ub  XG-   nOUnUR;                  UUS9I Sh  vN nUb  UnM  M  M  M     U$  N! [<         a  nUeSnAff = f7f)zY
Allow user to modify outgoing streaming data -> per chunk

Covers:
1. /chat/completions
r   r   N)response_obj)extract_text_from_a2a_responseFr#   r'  Tr  )r  r  )r   rY  r   r   r  r   r   r0   r1   rv   get_response_stringr   rC  litellm.llms.a2a.common_utilsrH  r*  r<   r  r$   r(  r  r  ry   r+  r,  r  r   r   r?   r  ri  )r   r  r  r  rE  r_  r   response_strrH  _cached_guardrail_data_guardrail_data_computedr   ra  r$   complete_responser-  rs  s                    r{   r  +ProxyLogging.async_post_call_streaming_hook	  s    * 224009K9KO9&*h0C DEE"66HML$''D,J,J8,T,TT9(CL# 6:"',$#--+8<I!(O<<P  8 G)-!" 3
 8<4 %99%;+>+H+H :  $(	( %!(C00$+$>$>$N$N$q$q !LhW%	 %-	 ,I|1T1T%10:0I-0<-"+"J"J2C): #K #  * -8'8H 9 2U,= .Z  ! GsJ   CGAF1GBF1F/	F1#G/F11
G;F==GGc           
     `  #    [         R                  5       nUR                  (       d  U  Sh  vN nU7v   M  SSKJn  [        X6S9nUnUR                   H  u  p[        U[        5      (       a#  UR                  U[        R                  S9SLa  M=  U	S:X  a#  U R                  UUR                  UUUS95      nMf  XS	'   U R                  U[        R                  UUUS
95      nM     U  Sh  vN nU7v   M   N
 [         R                  U5        g N$
 [         R                  U5        g7f)z
Allow user to modify outgoing streaming data -> Given a whole response iterator.
This hook is best used when you need to modify multiple chunks of the response at once.

Covers:
1. /chat/completions
Nr   r   r'  r  Tr  )r  r  r  r  )r  r  r  )r   rY  r   _fire_deferred_stream_loggingr  r   r(  r   r<   r  r$   r  rx  r  r  )
r   r  r  r  r_  rw  r   current_responseresolved_callbackr  s
             r{   r  4ProxyLogging.async_post_call_streaming_iterator_hook6
  sT     224 &&' e 	: ?
 $'+'>'>#+_==%::)6I6S6S ;    
 z!#'#P#P%%MM*;!1%1 N $  6G12#'#P#P%%MM*;%1!1 N $ + (?> , 	%K]x66|DT	+ 	22<@sJ   (D.C>C<C>B:D.,D0D1D4D.<C>>D.DD.c                     U R                  S5      nUc  g[        USS5      n[        USS5      nUb,  Ub(  SUl        SUl        [        R
                  " U" U6 5        ggg)aS  
Fire the deferred streaming logging callback after the full streaming
pipeline (including guardrail end-of-stream blocks) has completed.

CSW.__anext__ stores the callback and args on logging_obj instead of
scheduling via create_task (which would race with unified_guardrail's
end-of-stream block).  This method retrieves and fires them.
r  N_on_deferred_stream_complete_deferred_stream_complete_args)r&  r   rV  rW  r  r  )r  logging_obj_deferred_cb_argss       r{   rQ  *ProxyLogging._fire_deferred_stream_logging
  sr     #&&'<={,JDQ%EtL#(97;K49=K6e 45 ):#r}   c                     U R                  S5      n[        U[        5      (       d  g [        R                  " UR                  U5      5        g! [         a    [        R                  " S5         gf = f)au  
Release the api-key max_parallel_requests slot when a streaming
response is cancelled mid-flight (client disconnect). Neither the
success nor failure logging callback fires on the resulting
CancelledError / GeneratorExit, so the pre-call +1 would otherwise
leak.

Must be called from the outermost streaming generator (the one
Starlette drives and closes on disconnect). A nested iterator-hook
generator only receives GeneratorExit when it is garbage collected,
which is non-deterministic, so the refund cannot live there.

Scheduled fire-and-forget (no await) because awaiting is not
permitted while unwinding a GeneratorExit.
parallel_request_limiterNzparallel_request_limiter_v3: could not schedule max_parallel_requests release on disconnect; no running event loop. Slot will be reclaimed when its window TTL expires)	rX   r   r\   r  r  1async_release_max_parallel_requests_on_disconnectRuntimeErrorr4   rl  )r   r  limiters      r{   ,_release_max_parallel_requests_on_disconnect9ProxyLogging._release_max_parallel_requests_on_disconnect
  sq    $ %%&@A'#GHH	II%
  	 !((Q	s   %A  A21A2c                     U R                   (       aF  U R                   R                  b.  [        R                  " U R                   R	                  US95        ggg)z
Initialize the response taking too long task if user is using slack alerting

Only run task if user is using slack alerting

This handles checking for if a request is hanging for too long
Nr  )r   r   r  r  response_taking_too_long)r   r  s     r{   rX  0ProxyLogging._init_response_taking_too_long_task
  sP     ((,,55A,,EESWEX B )r}   )r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   )NNNNNNNr   )r   r   )re  NNN)NN)dr   r   r   r   r   rL   r   r   r   r2   r8   r  r   r   rF   r   r   r#  ry   r?   rX   r  r   r<  rC  r_  r   rt  rk  r  r  r  rl   rk   r   r  r  r  r  r  rJ   r'   r  r  r<   r$   r  r  r&  r1  staticmethodr.  r   rJ  r;   r]  r   rs  r   rx  rz  r   r   intr   rY  r  r  r  r  r  r  r  r  rG   r  r  r  ri  r   r,   r   r  r  rn   r.  r4  r2  rC  r   r0   r.   r/   r1   r  r  rQ  ra  rX  r   r   r}   r{   r   r     se	    #(:+(: (:T'7V$'7 $J/'7V $(.2,015(,/3,04S4.4S %UO4S j)	4S
 d9o.4S  ~4S 'tn4S $D>4Sl;8F+; ;&13 18L+A 1*(62B *X
"
,34E,F
,!d !t !FL	#L\/!/	$/b-1	$B-	#-^G)1$GKOG	G* 2 
c3h	*

	"
*%d^>B	>"!! 
!8 #'6@#6@ 6@ 	6@
 $N36@ $6@ 3-6@ 
6@~ #',
,
 ,
 	,

 $N3,
 $,
 3-,
 
,
\k!k k $N3	k
 $k (k 
$kZ<-<- !<- 	<-
 <- $<- 
<-|& & &P'' *' 	'
 ' 
'R ... . 
	. .b )  $	
 
  )  $	
 
 U)U tnU $	U
 
$Un1(1 tn1 $N3	1
 
$1f &s^	  *395	T		" . 	 !(U3c3h'(*AAB#  [ [z Td T T 
T 
 
 G G GKT KG G C C CTT $N3T $	Tl /

/ /l (,?K?K ./?K 	?K
 tn?KD RT)F,1)F>A)F` 15#'+E%E% &E% *	E%
 _-E% }E%  }E% 
-	 E%T 15#	!
%!
 _-!
 }	!

 
!
N  $26mm *m }	m
 %Y/m^bb #b *	bR 59== *= 	=
 "$sCx.1= 
c3h=~ 
t 
s 
tCH~ 
 
,=$ =4 = %)UU ,m=PP
U *U SMUnHA *HA 	HAT 6D 6T 6 6&"!/"	"H  r}   r   c                 &    [        SU S    35        g )Nz!Backing off... this was attempt #tries)r|   )detailss    r{   
on_backoffrl  
  s    5gg6F5GHIr}   r  c                     [         R                  " U 5      nUR                  5        H5  u  p#[        U[        5      (       d  M   [
        R                  " U5      X'   M7     U$ ! [         a    SX'    ML  f = fNzfailed-to-serialize-jsonr  deepcopyr.  r   r   ry  r  ri  )r  db_datar"  r#  s       r{   jsonify_objectrr  
  sb    mmD!Ga8!ZZ]
   N  87
8   A""A43A4r  )max_size_deprecated_key_cache<   dbhashed_tokenc                 V  #    [         R                  " [        R                  5      nUR	                  5       n[
        R                  U5      nUb'  Uu  pVnX6:  a  X7:  a  U$ [
        R                  US5         U R                  R                  USU0S.S9I Sh  vN nU(       aT  UR                  (       aC  UR                  n	UR                  U[        -   U	R	                  5       4[
        U'   UR                  $ g N`! [         a!  n
[        R                  " SU
5         Sn
A
gSn
A
ff = f7f)z
Check if a token exists in the deprecated keys table and is still within its grace period.

Returns the active_token_id if found and valid, otherwise None.
Uses an in-memory cache to avoid DB queries on every auth request.
Ngt)token	revoke_atwherez!Deprecated key lookup skipped: %s)r   r  r   utc	timestampru  r&  r  #litellm_deprecatedverificationtoken
find_firstactive_token_idr|  !_DEPRECATED_KEY_CACHE_TTL_SECONDSri  r4   rs   )rw  rx  r  now_tsr  r  cache_expires_at_tsrevoke_at_tsdeprecated_rowr|  rs  s              r{   _lookup_deprecated_keyr  
  s"     ,,x||
$C]]_F #&&|4F=C:l'F,A""!!,5K!EEPP%"C[  Q  
 
 n<<&00I..::##%3!,/
 "111 '
   K""#FJJKsC   A4D)7!C; C9AC; 7D)9C; ;
D&D!D)!D&&D)&LITELLM_CONFIG_PARAM_CACHE_TTL_SECONDS60 LITELLM_CONFIG_CACHE_TTL_SECONDS__litellm_config_param_miss___CONFIG_CACHE_MISS)r   default_redis_ttllitellm_config_cachec                   2    \ rS rSrSrSrS\S\SS4S jrSr	g)	
_ConfigRowi   z>Mimics the Prisma litellm_config row shape for cached entries.
param_nameparam_valuer  r  r   Nc                     Xl         X l        g r   r  )r   r  r  s      r{   r   _ConfigRow.__init__%  s    $&r}   )
r   r   r   r   r   	__slots__ry   r   r   r   r   r}   r{   r  r     s$    H-I'3 'S 'T 'r}   r  r  c                     SU  3$ )Nzlitellm_config:param:r   r  s    r{   _config_cache_keyr  *  s    ":,//r}   rowc                 4    U R                   U R                  S.$ )Nr  r  )r  s    r{   _pack_config_rowr  .  s    ..IIr}   r  c                 n    U b
  U [         :X  a  g [        U [        5      (       a  [        U S   U S   5      $ g )Nr  r  )r  r   r   r  )r  s    r{   _unpack_config_rowr  2  s9    ~#55&$&.}0EFFr}   r  c                    #    [        U5      n[        R                  U5      I Sh  vN nUb  [        U5      $ U R	                  SUSS9I Sh  vN nUb  [        U5      O[        n[        R                  X%[        S9I Sh  vN   U$  Na N< N
7f)zKCached read of a LiteLLM_Config row; returns row, _ConfigRow shim, or None.Nr  config)r   r   
table_namer;  )	r  r  r   r  get_generic_datar  r  r   r  )r  r  	cache_keyr  r  cache_values         r{   get_config_paramr  :  s     !*-I'77	BBF!&))..
x /  C 14',EWK

.
.$D /    J Cs3   $BB&BB
3BBB
BBc                 \   #    [         R                  [        U 5      5      I Sh  vN   g N7f)zDEvict from both cache layers; call after every LiteLLM_Config write.N)r  async_delete_cacher  r  s    r{   invalidate_config_paramr  K  s     

1
12CJ2O
PPPs   ",*,param_namesc                   #    U(       d  g [        U 5      R                  R                  SSU00S9I Sh  vN nU Vs0 s H  oDR                  U_M     nnU HR  nUR                  U5      nUb  [        U5      O[        n[        R                  [        U5      U[        S9I Sh  vN   MT     g Ny! [         a!  n[        R
                  " SU5         SnAgSnAff = fs  snf  N>7f)zABatch-load LiteLLM_Config rows into the cache with one find_many.Nr  inr}  zGprefetch_config_params failed, falling through to per-param queries: %sr  )r`   table	find_manyri  r4   rs   r  r&  r  r  r  r   r  r  )r  r  rowsrs  r  by_namer  r  s           r{   prefetch_config_paramsr  P  s     	%m4::DD$!45 E 
 
 /33ds~~s"dG3kk$%(_S!:L 	 #22d#[6V 3 
 	
 	
 
  ""U	
 	 4	
sU   	C&)B1 B/B1 C&CAC&%C$&	C&/B1 1
C;CC&C	C&c            #          \ rS rSr% / r\\S'   \R                  " 5       r	 SlS\
S\S\\   4S jjr\S\4S	 j5       rS
\\\4   S\S   4S jrS\
4S jrS\S\4S jr\R4                  " \R6                  \SS\S9S 5       r\\R4                  " \R6                  \SS\S9S\
S\S\S   4S j5       5       r S\
S\\   4S jr!\R4                  " \R6                  \SS\S9\                SmS\\\
\"4      S\\
   S\\"   S \\
   S!\\"   S"\\   S\\S#      S$\S%   S&\\#   S'\\#   S(\\$   S)\\$   S*\\%   S\\   S+\\\
      S,\&4 S- jj5       5       r'S.\4S/ jr(\R4                  " \R6                  \SS\S9S\S\S0   4S1 j5       r)\R4                  " \R6                  \SS\S9S0 SSSS2SSS4	S\\
   S\S3\\   S\\
   S \\
   S$\S4   S\\S5      S6\\   S7\\   4S8 jj5       r*\R4                  " \R6                  \SS\S9    SnS9\\   S!\\   S\\S:      S\\
   4S; jj5       r+\R4                  " \R6                  \SS\S9S< 5       r,\R4                  " \R6                  \SS\S9S= 5       r-S\$4S> jr.S\&4S? jr/\0S\14S@ j5       r2SA\$S\&4SB jr3SA\$SC\Rh                  SS4SD jr5SA\$S\&4SE jr6SF\$SS4SG jr7SA\$S\&4SH jr8SoSI jr9SoSJ jr:SoSK jr;SoSL jr<SoSM jr=SoSN jr> SlSO\\?   SS4SP jjr@SQ\&SR\
SO\\?   S\&4SS jrA   SpSR\
SQ\&SO\\?   ST\\?   S\&4
SU jjrBSoSV jrCSoSW jrDSoSX jrE\R4                  " \R6                  \SS\S9SY 5       rFS\$4SZ jrG\R4                  " \R6                  \SS\S9SoS[ j5       rHS\\\?   S\\?   4S] jrIS^\\   S\\   4S_ jrJ       SqS`\
Sa\
Sb\$Sc\$Sd\\
   S\\\?   S^\\   Se\\
   Sf\\
   4Sg jjrK    SrS`\\
   S)\$S(\$Sh\\
   4Si jjrLSj rMSkrNg)sPrismaClientii  spend_log_transactionsNdatabase_urlproxy_logging_objhttp_clientc           	         X l         [        [        R                  " S5      5      U l        [
        R                  " S5         SSKJn  U R                  b  U R                  OS	n[        R                  " S
5      nU(       a  SOSnUb  [        U" US9UUS9n	O[        U" 5       UUS9n	U   U(       a   U(       a  [        U5      OS n
U(       aS  U
bP  SSKJn  U" U
R                  U
R                   U
R"                  S9nU
R%                  U5      nU[        R&                  S
'   SSU00nUb  U" S2SU0UD6nOU" S20 UD6n[        UUS
U
SSS9n[)        XS9U l        [
        R,                  " SU(       a  SOS-   5        OXl        [0        R2                  " 5       U l        S U l        SU l        [;        S[=        [        R                  " SS5      5      5      U l        [;        S[=        [        R                  " S S!5      5      5      U l         [        [        R                  " S"S#5      5      SL U l!        [;        S$[E        [        R                  " S%S&5      5      5      U l#        [;        S'[E        [        R                  " S(S)5      5      5      U l$        [;        S$[E        [        R                  " S*S+5      5      5      U l%        [;        S[E        [        R                  " S,S-5      5      5      U l&        SU l'        [;        S[=        [        R                  " S.S/5      5      5      U l(        S0U l)        SU l*        S	U l+        S	U l,        S U l-        [
        R                  " S15        g ! [         aU  n[
        R                  " SU 35        [
        R                  " S5        [
        R                  " S5        [        S5      eS nAff = f! [         a(  n[
        R.                  " SU5        Xl         S nAGNhS nAff = f)3NIAM_TOKEN_DB_AUTHzCreating Prisma Client..r   )Prismaz Failed to import Prisma client: z9This usually means 'prisma generate' hasn't been run yet.z;Please run 'prisma generate' to generate the Prisma client.zCUnable to find Prisma binaries. Please run 'prisma generate' first.FDATABASE_URL_READ_REPLICAz[writer]re  )http)original_prismaiam_token_db_auth
log_prefix)generate_iam_auth_token)db_hostdb_portdb_user
datasourceurlr  Tz[reader])r  r  db_url_env_variam_endpointrecreate_uses_datasourcer  )writerreaderzHPrismaClient: read-replica routing enabled via DATABASE_URL_READ_REPLICAz (with IAM token auto-refresh)z|Failed to initialize read replica Prisma client: %s. Falling back to writer-only mode (no read routing) until proxy restart.g        r   !PRISMA_RECONNECT_COOLDOWN_SECONDS15   'PRISMA_HEALTH_WATCHDOG_INTERVAL_SECONDS30PRISMA_HEALTH_WATCHDOG_ENABLEDtrueg      ?,PRISMA_HEALTH_WATCHDOG_PROBE_TIMEOUT_SECONDSz5.0g      ?)PRISMA_WATCHDOG_RECONNECT_TIMEOUT_SECONDSz30.0%PRISMA_AUTH_RECONNECT_TIMEOUT_SECONDSz2.0*PRISMA_AUTH_RECONNECT_LOCK_TIMEOUT_SECONDSz0.1%PRISMA_RECONNECT_ESCALATION_THRESHOLD3zSuccess - Created Prisma Clientr   ).r  rh   r   r   r  r4   rs   prismar  ri  rm  rS   rT    litellm.proxy.auth.rds_iam_tokenr  hostportrI  	build_urlenvironrU   rw  ri  rl  r  Lock_db_reconnect_lock_db_health_watchdog_task_db_last_reconnect_attempt_tsmaxrh  _db_reconnect_cooldown_seconds$_db_health_watchdog_interval_seconds_db_health_watchdog_enabledr   )_db_health_watchdog_probe_timeout_seconds&_db_watchdog_reconnect_timeout_seconds"_db_auth_reconnect_timeout_seconds'_db_auth_reconnect_lock_timeout_seconds_consecutive_reconnect_failures_reconnect_escalation_threshold_engine_pidfd_engine_pid_watching_engine_engine_confirmed_dead_engine_wait_thread)r   r  r  r  r  rs  iam_flagread_replica_urlwriter_log_prefixwriter_wrapperreader_iam_endpointr  reader_tokenreader_kwargsreader_prismareader_wrappers                   r{   r   PrismaClient.__init__m  s    "31<II)*2
 	""#=>	% '+&<&<&HD""e 	 99%@A*:J"* &K 8"*,N + &"*,N 	@) FN/0@ASW $  3 ? $; 3 8 8 3 8 8 3 8 8$L
 (;'D'D\'R$>NBJJ:; 5*:";1 *$*$M$M}$MM$*$;]$;M!.$1&.#>!4-1)" /) %))^;C7M( %G"),,.@D%47*36s299@$GH4
+ :=s299FMN:
1 		"BFKLPTT 	( AD"))JERSA
6 >Aryy!LfUV>
3 :=ryy!H%PQ:
/ ?B"))H%PQ?
4 56,47s299DcJK5
, #% !&+,1#?C ""#DE[  
	 &&)I!'MN &&K !&&M U 
	r  ) %,,^
 ))s2   M 1CN; 
N8#AN33N8;
O-O((O-r   c                     [        U R                  [        5      (       a  U R                  R                  $ U R                  $ )zEUnderlying writer Prisma wrapper, regardless of read-replica routing.)r   rw  rU   r  r  s    r{   	writer_dbPrismaClient.writer_db
  s-     dgg34477>>!wwr}   payload)r7  failurec                     UR                  S0 5      n[        U[        5      (       a%  [        [        [
        R                  " U5      5      nOUnUR                  S5      S:X  a  S$ S$ ! [
        R                  [        4 a     gf = f)z
Determine if a request was successful or failed based on payload metadata.

Args:
    payload (Union[dict, SpendLogsPayload]): Request payload containing metadata

Returns:
    Literal["success", "failure"]: Request status
r  r-   r  r7  )	r&  r   ry   r   r   ry  r~  r  AttributeError)r   r  payload_metadatapayload_metadata_jsons       r{   get_request_statusPrismaClient.get_request_status  s    	DKKKBE *C00HL$**%56I% )9%
 ),,X6)C   $$n5 		s   A$A) 'A) )BBr{  c                 j    [         R                  " UR                  5       5      R                  5       nU$ r   hashlibsha256encode	hexdigest)r   r{  rx  s      r{   
hash_tokenPrismaClient.hash_token4  s%    ~~elln5??Ar}   r  c                     [         R                  " U5      nUR                  5        H5  u  p4[        U[        5      (       d  M   [
        R                  " U5      X#'   M7     U$ ! [         a    SX#'    ML  f = frn  ro  )r   r  rq  r"  r#  s        r{   rr  PrismaClient.jsonify_object:  sb    --%MMODA!T""<!%AGJ $  ! <!;GJ<rs     
   	max_triesmax_timerl  c                 f  #     / SQnSnSR                  S U 5       5      n[        R                  " SS5      nU R                  R	                  SU SU S	35      I S
h  vN n[        U5      nUS   S   U:X  a  [        R                  " S5        g
US   S   (       a]  X%S   S   ;  aR  U R                  5       I S
h  vN   U R                  R                  S5      I S
h  vN   [        R                  " S5        g
[        U R                  S9I S
h  vN nU(       a  [        U R                  S9I S
h  vN   g
US   S   (       a  [        US   S   5      O	[        5       n[        U5      n	X-
  n
[        R                  " SR                  U
5      5         g
 GN9 N N N Nl! [         a    e f = f7f)aT  
Checks if the LiteLLM_VerificationTokenView and MonthlyGlobalSpend exists in the user's db.

LiteLLM_VerificationTokenView: This view is used for getting the token + team data in user_api_key_auth

MonthlyGlobalSpend: This view is used for the admin view to see global spend for this month

If the view doesn't exist, one will be created.
)rH   MonthlyGlobalSpendLast30dKeysBySpendLast30dModelsBySpendMonthlyGlobalSpendPerKeyMonthlyGlobalSpendPerUserPerKeyLast30dTopEndUsersSpendDailyTagSpendrH   , c              3   .   #    U  H  nS U S 3v   M     g7f)r9  Nr   )r~  views     r{   r  1PrismaClient.check_view_exists.<locals>.<genexpr>g  s     *R>4QtfA;>s   DATABASE_SCHEMApublicz
                WITH existing_views AS (
                    SELECT viewname
                    FROM pg_views
                    WHERE schemaname = 'z,' AND viewname IN (
                        z
                    )
                )
                SELECT
                    (SELECT COUNT(*) FROM existing_views) AS view_count,
                    ARRAY_AGG(viewname) AS view_names
                FROM existing_views
                Nr   
view_countzAll necessary views exist!
view_namesa"  
                            CREATE VIEW "LiteLLM_VerificationTokenView" AS
                            SELECT
                            v.*,
                            t.spend AS team_spend,
                            t.max_budget AS team_max_budget,
                            t.tpm_limit AS team_tpm_limit,
                            t.rpm_limit AS team_rpm_limit
                            FROM "LiteLLM_VerificationToken" v
                            LEFT JOIN "LiteLLM_TeamTable" t ON v.team_id = t.team_id;
                        z,LiteLLM_VerificationTokenView Created in DB!)rw  z

[93mNot all views exist in db, needed for UI 'Usage' tab. Missing={}.
Run 'create_views.py' from https://github.com/BerriAI/litellm/tree/main/db_scripts to create missing views.[0m
)joinr   r   rw  	query_rawr}  r4   ri  health_checkexecute_rawrN   rM   r  rl  rt   ri  )r   expected_viewsrequired_viewexpected_views_str	pg_schemaretexpected_total_viewsshould_create_viewsret_view_names_setexpected_views_setmissing_viewss              r{   check_view_existsPrismaClient.check_view_existsF  s    *G		N <M!%*R>*R!R		"3X>I)) /) *3 4+, -+  C $'~#6 1vl#';;$))*FG q6,'MQAU,U++---''-- 
/ 
 
 
 )--F2 	+ 1Ltww0W*W'*2dgg>>>& 	 :=Q9MCA| 45SVSX + .1-@*(:(O,44 b  i  i - 	u( .
  +X>"  		s   F1AF" F1F" F1+F" <F="F" F F" :F1;F" F!F" 3F 4F" 8F19AF" F1F" F" F" F"  F" "F..F1r      r   r   r  )usersr   r  spendc           
        ^ ^^^#    [         R                   " 5       nUU UU4S jn [        T UST S3S9I Sh  vN $  N! [         a  nS[        U5       3n[        R
                  " U5        USR                  [        U5      5      -   nUS-   [        R                  " 5       -   n[         R                   " 5       n	X-
  n
[        R                  " T R                  R                  UU
US	S
95        UeSnAff = f7f)uK  
Generic implementation of get data.

Self-heals across a single transient transport blip via
`call_with_db_reconnect_retry`: on `httpx.ReadError` /
`ClientNotConnectedError` / similar, attempt one DB reconnect and
retry once before surfacing the failure. Restores the 1.82.6 behavior
that was lost in 1.83.x — see issue #25143.
c                    >#    TS:X  a,  [        T5      R                  R                  T T0S9I S h  vN $ TS:X  a,  [        T5      R                  R                  T T0S9I S h  vN $ TS:X  a,  [	        T5      R                  R                  T T0S9I S h  vN $ TS:X  a-  TR
                  R                  R                  T T0S9I S h  vN $ g  N Nl N< N7f)Nr9  r}  r   r  r:  )rf   r  r  rg   r`   rw  l)r   r   r  r   s   r{   	_do_query0PrismaClient.get_generic_data.<locals>._do_query  s    W$+D177BB, C    v%8>DDOO, P    x'-d399DD, E    w&!WWYY11, 2    sE   .CC1C#C$1CC2CC	CCCCprisma_get_generic_data__lookup_failurereasonNz2LiteLLM Prisma Client Exception get_generic_data: z
Exception Type: {}rx  r  )r  rU  r  r  )r  rQ   ri  ry   r4   rm  rt   r   rr   ru   r  r  r  r  )r   r   r   r  rV  r>  rs  	error_msgerror_tracebackrW  	_durations   ````       r{   r  PrismaClient.get_generic_data  s     . YY[
	 	&	51*_M   
  	LSQRVHUI &&y1!$:$A$A$q'$JJI'$.1E1E1GGOyy{H -I&&66'(&"10	 7  G!	s2   C8? =? C8? 
C5	B'C00C55C8	sql_queryc                 P  #     U R                   R                  " U/UQ76 I Sh  vN $  N! [         an  nS[        U5      ;  a  e [        R
                  " S5        U R                  SS9I Sh  vN    U R                   R                  " U/UQ76 I Sh  vN  s SnA$ SnAff = f7f)ae  
Execute a query, recovering once from PostgreSQL's "cached plan must not
change result type" error.

That error surfaces during rolling deployments when a schema change
invalidates the prepared-statement plans that pooled connections still
hold. Clearing only the server-side plans with DEALLOCATE ALL makes
things worse: Prisma's query engine keeps a per-connection client-side
cache of prepared-statement names, so once the server drops a plan the
engine re-sends a name PostgreSQL no longer recognizes and the
connection breaks with `prepared statement "sN" does not exist`. With a
small pool that connection stays poisoned and every auth lookup fails.

Recreating the Prisma client kills the engine subprocess and drops the
server-side plans and the engine's client-side name cache together, so
the retried query is prepared fresh. We reconnect through
`attempt_db_reconnect`, which is singleflight: when a schema change
poisons every pooled connection at once, the first cached-plan error
recreates the client and the concurrent waiters reuse that single
recreate instead of racing to kill each other's fresh engine. We then
retry the identical query exactly once.

The retry reuses the original query byte-for-byte. Mutating the SQL
(e.g. injecting a unique comment) would defeat PostgreSQL's plan cache,
forcing a fresh plan on every request and pegging the database CPU.

If the reconnect is skipped because a recent reconnect is still within
its cooldown, the retry runs against the same connection and may fail
again; the get_data backoff decorator re-runs the lookup and a later
attempt reconnects once the cooldown elapses.
Nz'cached plan must not change result typezPostgreSQL cached plan error detected for token lookup; recreating the database connection and retrying with the same query. This may occur during rolling deployments when schema changes are applied.postgres_cached_plan_errorrB  )rw  query_firstri  ry   r4   rl  attempt_db_reconnect)r   rH  r  rs  s       r{   &_query_first_with_cached_plan_fallback3PrismaClient._query_first_with_cached_plan_fallback  s     D	?,,Y>>>>> 
	?8AF ((' ++3O+PPP,,Y>>>>>
	?sT   B& + )+ B&+ 
B#8B-A0.%BBBB#B&B##B&user_iduser_id_listteam_idteam_id_listkey_val)	rI  r   r  r:  enduserbudgetteamuser_notificationcombined_view
query_type)find_uniquefind_allexpiresreset_atoffsetlimitr   budget_id_listcheck_deprecatedc           
        #    [        5       n[        R                  " 5       nS n S nUb  Ub  UGb  US:X  Ga  Ub7  [        U[        5      (       a"  [	        US9n[
        R                  " SU 35        US:X  a  Ub  Uc  [        SSSU 30S9e[        U 5      R                  R                  S	U0S
S0S9I S h  vN nUbM  UR                  b>  [        UR                  [        5      (       a  UR                  R                  5       Ul        GO[        [        R                  SU 3S9eUS:X  a  Ub  [        U 5      R                  R!                  SU0S
S0S9I S h  vN nUbX  [#        U5      S:  aI  U HC  n[        UR                  [        5      (       d  M$  UR                  R                  5       Ul        ME     GO%US:X  a  Ub  [        U 5      R                  R!                  USU0S
S0S9I S h  vN nUbX  [#        U5      S:  aI  U HC  n[        UR                  [        5      (       d  M$  UR                  R                  5       Ul        ME     GOUS:X  a  U	b  U
b  [        U 5      R                  R!                  SS 0SSU	00/SU
0S.S9I S h  vN nUbX  [#        U5      S:  aI  U HC  n[        UR                  [        5      (       d  M$  UR                  R                  5       Ul        ME     OUS:X  a  0 nUb  0 US	'   [        U[        5      (       a  [	        US9nU/US	   S'   O[        U[$        5      (       as  / nU Hc  n[        U[        5      (       d   eUR'                  S5      (       a"  U R)                  US9nUR+                  U5        MR  UR+                  U5        Me     UUS	   S'   [        U 5      R                  R!                  SS0US
S0S9I S h  vN nUb  U$ [        [        R                  SS9eUb  Ub  UGbT  US:X  GaM  US:X  a6  Uc  SU0n[-        U 5      R                  R                  USS0S9I S h  vN nU$ US:X  a/  Ub,  [-        U 5      R                  R!                  US9I S h  vN nU$ US:X  a3  U
b0  [-        U 5      R                  R!                  S SU
00S9I S h  vN nU$ US:X  a3  Ub0  [-        U 5      R                  R!                  SSU00S9I S h  vN nU$ US:X  ab  U	b9  [-        U 5      R                  R!                  SS0S!SS 0SSU	00/0S"9I S h  vN nU$ S#nU R.                  R1                  UX5      I S h  vN nU$ US:X  a  [
        R                  " S$5        Ubt  US:X  a4  [3        U 5      R                  R                  US   US%   0S9I S h  vN nU$ US:X  a2  [3        U 5      R                  R!                  US   US%   0S9I S h  vN nU$ [3        U 5      R                  R!                  S&S0S'9I S h  vN nU$ US(:X  aH  U
bE  US:X  a>  [5        U 5      R                  R!                  S!S)S S 0S*S+S 00/0S SU
00/0S9I S h  vN nU$ g US,:X  a:  Ub7  US:X  a0  [7        U 5      R                  R!                  S-SU00S9I S h  vN nU$ g US.:X  Ga  US:X  a1  [9        U 5      R                  R                  SU0S/S0S9I S h  vN nU$ US:X  a3  U
b0  [9        U 5      R                  R!                  S SU
00S9I S h  vN nU$ US:X  a6  Ub3  [9        U 5      R                  R!                  S0S1U00S
S0S9I S h  vN nU$ US:X  a3  Ub0  [9        U 5      R                  R!                  SSU00S9I S h  vN nU$ US:X  a1  Uc.  [9        U 5      R                  R!                  [:        S29I S h  vN nU$ US3:X  ag  US:X  a.  [=        U 5      R                  R                  SU0S9I S h  vN nU$ US:X  a+  [=        U 5      R                  R!                  5       I S h  vN nU$ US4:X  Ga  Ub7  [        U[        5      (       a"  [	        US9n[
        R                  " SU 35        US:X  Gav  Uc  [        SSSU 30S9eS5nU R?                  UU5      I S h  vN nUcd  Uba  U(       aZ  [A        U R.                  US69I S h  vN nU(       a7  U RC                  US4SUUS7S89I S h  vN nUb  [
        R                  " S95        U$ Ub  US:   c  / US:'   US;   c  S7US;'   S nUS<   bL  US   bF   US<    H<  nURE                  S5      c  M  US   URE                  S5      :X  d  M1  [G        SC0 UD6nM>     UUS='   [I        SC0 UDS>[        R                  " 5       0D6nUR                  b>  [        UR                  [        5      (       a  UR                  R                  5       Ul        U$ g g  G	NF GN GN GNv GN- GN GN GN` GN* GN GN GNp GN9 GN GN GN GNK GN GN GN GNp GN9 GN	 GN GNn GNN! [J         a  nSS K&n S?U 3n!U![        U5      -   n"[O        U"5        U"S@-   U RP                  " 5       -   n#[
        R                  " U#5        [        R                  " 5       n$U$U-
  n%[R        RT                  " U RV                  RY                  UU%SAU#SB95        UeS nAff = f7f)DNr   r{  z%PrismaClient: find_unique for token: rZ  r  rm  zNo token passed in. Token=r  r{  litellm_budget_tableT)r~  includezQAuthentication Error: invalid user key - user key does not exist in db. User Key=r[  rO  r   rQ  )taker~  re  r\  rz  lt)ORbudget_reset_atr}  r  sk-r:  desc)orderr~  re  z=Authentication Error: invalid user key - token does not existrI  organization_membershipsri  rh  )rl  r~  a  
                        SELECT
                            u.*,
                            json_agg(v.key_alias) AS key_aliases
                        FROM
                            "LiteLLM_UserTable" u
                        LEFT JOIN "LiteLLM_VerificationToken" v ON u.user_id = v.user_id
                        GROUP BY
                            u.user_id
                        ORDER BY u.spend DESC
                        LIMIT $1
                        OFFSET $2
                        z-PrismaClient: get_data: table_name == 'spend'r   	startTime)rl  rU  ANDNOTbudget_durationrT  	budget_idrV  litellm_model_tablemembershas)rf  rW  rX  a.  
                        SELECT 
                            v.*,
                            t.spend AS team_spend, 
                            t.max_budget AS team_max_budget,
                            t.soft_budget AS team_soft_budget,
                            t.tpm_limit AS team_tpm_limit,
                            t.rpm_limit AS team_rpm_limit,
                            t.models AS team_models,
                            t.metadata AS team_metadata,
                            t.blocked AS team_blocked,
                            t.team_alias AS team_alias,
                            t.metadata AS team_metadata,
                            t.members_with_roles AS team_members_with_roles,
                            t.object_permission_id AS team_object_permission_id,
                            t.organization_id as org_id,
                            p.project_alias AS project_alias,
                            tm.spend AS team_member_spend,
                            b_tm.tpm_limit AS team_member_tpm_limit,
                            b_tm.rpm_limit AS team_member_rpm_limit,
                            m.aliases AS team_model_aliases,
                            -- Added comma to separate b.* columns
                            b.max_budget AS litellm_budget_table_max_budget,
                            b.tpm_limit AS litellm_budget_table_tpm_limit,
                            b.rpm_limit AS litellm_budget_table_rpm_limit,
                            b.model_max_budget as litellm_budget_table_model_max_budget,
                            b.soft_budget as litellm_budget_table_soft_budget,
                            o.metadata as organization_metadata,
                            o.organization_alias as organization_alias,
                            b2.max_budget as organization_max_budget,
                            b2.tpm_limit as organization_tpm_limit,
                            b2.rpm_limit as organization_rpm_limit
                        FROM "LiteLLM_VerificationToken" AS v
                        LEFT JOIN "LiteLLM_TeamTable" AS t ON v.team_id = t.team_id
                        LEFT JOIN "LiteLLM_TeamMembership" AS tm ON v.team_id = tm.team_id AND tm.user_id = v.user_id
                        LEFT JOIN "LiteLLM_BudgetTable" AS b_tm ON tm.budget_id = b_tm.budget_id
                        LEFT JOIN "LiteLLM_ModelTable" m ON t.model_id = m.id
                        LEFT JOIN "LiteLLM_BudgetTable" AS b ON v.budget_id = b.budget_id
                        LEFT JOIN "LiteLLM_ProjectTable" AS p ON v.project_id = p.project_id
                        LEFT JOIN "LiteLLM_OrganizationTable" AS o ON v.organization_id = o.organization_id
                        LEFT JOIN "LiteLLM_BudgetTable" AS b2 ON o.budget_id = b2.budget_id
                        WHERE v.token = $1
                    )rw  rx  F)r{  r  rY  r   r  ra  z'Deprecated key used during grace periodteam_modelsteam_blockedteam_members_with_rolesteam_memberlast_refreshed_atzHLiteLLM Prisma Client Exception: Error with `get_data`. Args passed in: rx  get_datar  rU  r  r  r   )-localsr  r   ry   _hash_token_if_neededr4   rs   r,   rg   r  rZ  r\  r   	isoformatr-   HTTP_401_UNAUTHORIZEDr  r}  r   r|  r  r  rf   rw  r)  rc   r_   ra   re   r   rd   rM  r  r{  r&  rI   rH   ri  rr   r|   ru   r  r  r  r  )&r   r{  rO  rP  rQ  rR  rS  r  rY  r\  r]  r^  r_  r   r  r`  ra  args_passed_inrV  rx  r  rwhere_filterhashed_tokenst	new_tokenrH  r  deprecated_responsery  tmrs  rr   prisma_query_inforD  rE  rW  rF  s&                                         r{   r{  PrismaClient.get_data  s    R  YY[
&*F	 H!j&8&:+> $!%--'<5'I,22CL>R .<3K}+(+$+/I%-Q#R  &A&eKK&5!7 > (  H  +#++7J$,,h= = 08/?/?/I/I/KH, ,(.(D(D%vw|v}#~   :-'2E%@%F%L%L%V%V('2!7 > &W &  H  +H0A!)A)!))X>>,-II,?,?,A	 "*  :-'2E%@%F%L%L%V%V"('2!7 > &W &  H
  +H0A!)A)!))X>>,-II,?,?,A	 "* *,+ ,%@%F%L%L%V%V "+D 1!*T7O <# 15h/? &W &  H  +H0A!)A)!))X>>,-II,?,?,A	 "*  :-)+L(02W-%eS11$9$FE;@'L1$7't44,.M%*'1!S'9'9 9'9#$<<#6#604a0HI$1$8$8$C$1$8$8$; &+ ;HL1$7%@%F%L%L%V%V&/*!7 > &W &  H
 '#O ($*$@$@^  %**<&:+?.#,g"6%3D%9%?%?%K%K%!;T B &L &  H\  S  :-'2E%3D%9%?%?%I%I% &J &  HP  K  :-(2F%3D%9%?%?%I%I-h/? &J &  HH  ?  :-,2J%3D%9%?%?%I%I(4*>? &J &  H<  7  :-*)7)=)C)C)M)M#*F"3 $%.$5%.w$@'"# *N * $2  %	 *.):):9e)T#Tw&$**C &!]2)<T)B)H)H)T)T '0@# *U * $ $O $z1)<T)B)H)H)R)R '0@# *S * $
 $O%8%>%D%D%N%N*F3 &O &  H $Ox'H,@+%5d%;%A%A%K%K $)):D(A).1BD0I(J,&!" "3T84D E#
 &L &  H $O ,  y(^-G+%6t%<%B%B%L%L*T>,BC &M &  H $O	 ,
 v%.%3D%9%?%?%K%K('2!6 = &L &  H2  +  :-(2F%3D%9%?%?%I%I-h/? &J &  H(    :-'2E%3D%9%?%?%I%I%w'7 "8 >	 &J &  H    :-,2J%3D%9%?%?%I%I(4*>? &J &  H  	  :-,2F%3D%9%?%?%I%I0 &J &  H  22.%@%F%L%L%X%X('2 &Y &  H
    :-%@%F%L%L%V%V%XXH.$!%--'<5'I,22CL>R .}+(+$+/I%-Q#R 
*!IX &*%P%P!<&  H !((4,0F#ww\1 + + 9=&5+:+81A2C16 9F 9 3/  3> 4 : :$M!" $76+#M2:68H]3#N3;7<H^48<$%>?K ( 3 ?  '//H&I#%66)#4#@X$-F"%'VVI%6F7 39,2,K	 'J
 3>/#@ $&$:>))+$ $++7J$,,h= = 08/?/?/I/I/KH,#Ow / /{ &   < (    
$0 $U$$  "  
       Yz +3n  	"jkyjz {)CF2I)$'$.1E1E1GGO &&7yy{H :-I&&66'(&("1	 7  G'	s  "k8Bi 7g=8B"i h 8i Ai 0h18i -A#i h8i Di h	i %k8&Ai hi 
k8.i 9h:i ?k8 2i 2h3i 8k892i +h,i 1k82;i -h.i 3k84!i hi k8Ai .h/i 4k853i (h!)i .k8/'i h$i k8Ai #h'$i )k8+8i #h*$i )k8+7i "h-#i (k8)2i h0i !k8"5i h3i k82i h6i k82i 	h9
i k83i h<i 	k8
,i 6h?7i <k8=A1i .i/(i i"i :i;i k8A i i 8Bi :k8=i  i i i 	i i i i i i i i !i $i 'i *i -i 0i 3i 6i 9i <i ?i i i i 
k5Bk00k55k8rq  c                     U R                  US9nUR                  SS 5      b4  [        US   [        5      (       a  [        R
                  " US   5      US'   U$ )NrP  members_with_roles)rr  r&  r   r   ry  r  )r   rq  s     r{   jsonify_team_object PrismaClient.jsonify_team_object  sa    %%7%3;;+T2>:()4D
 D
 -1JJw?S7T,UG()r}   )rI  r   r  r:  rV  rW  c           
      &  #    [         R                   " 5       n [        R                  " SU5        US:X  a  US   nU R                  US9nU R	                  US9nXVS'   UR                  S5      c  UR                  SS5        [        S5        [        U 5      R                  R                  SU00 UE0 S	.S
S0S9I Sh  vN n[        R                  " S5        U$ US:X  a]  U R	                  US9n [        U 5      R                  R                  SUS   00 UE0 S	.S9I Sh  vN n[        R                  " S5        U$ US:X  a\  U R!                  US9n[#        U 5      R                  R                  SUS   00 UE0 S	.S9I Sh  vN n
[        R                  " S5        U
$ US:X  a   / nUR%                  5        HZ  u  pUn[&        R(                  " U5      n[+        U 5      R                  R                  SU0XS.S U0S	.S9nUR-                  U5        M\     [.        R0                  " U6 I Sh  vN   UR3                  5        H  n[5        U5      I Sh  vN   M     [        R                  " S!5        gUS":X  a\  U R	                  US9n[7        U 5      R                  R                  S#US#   00 UE0 S	.S9I Sh  vN n[        R                  " S$5        U$ US%:X  a\  U R	                  US9n[9        U 5      R                  R                  S#US#   00 UE0 S	.S9I Sh  vN n[        R                  " S&5        U$ g GNz GN! [         a)  n	S[        U	5      ;   a  [        SSSUS    S30S9eU	eSn	A	ff = f GN GNJ GN' N Nd! [         a  n	S'SKnS([        U	5       3n[        U5        US)-   UR<                  " 5       -   n[         R                   " 5       nUU-
  n[.        R>                  " U R@                  RC                  U	US*US+95        U	eSn	A	ff = f7f),z>
Add a key to the database. If it already exists, do nothing.
zPrismaClient: insert_data: %sr   r{  rc  rP  budget_limitsNz:PrismaClient: Before upsert into litellm_verificationtokencreater  rd  T)r~  r  re  zData Inserted into Keys TablerI  rO  r~  r  z\Foreign key constraint failed on the field: `LiteLLM_UserTable_organization_id_fkey (index)`r  rm  z/Foreign Key Constraint failed. Organization ID=organization_idzM does not exist in LiteLLM_OrganizationTable. Create via `/organization/new`.r  zData Inserted into User TablerV  rq  rQ  zData Inserted into Team Tabler  r  r  r  zData Inserted into Config Tabler:  
request_idzData Inserted into Spend TablerW  z&Data Inserted into Model Request Tabler   z0LiteLLM Prisma Client Exception in insert_data: rx  insert_datar|  )"r  r4   rs   r  rr  r&  r  r|   rg   r  upsertri  rf   ri  ry   r,   r  re   r.  ry  r  r`   r  r  r  r   r  rc   rd   rr   ru   r  r  r  )r   r  r  rV  r{  rx  rq  new_verification_tokennew_user_rowrs  new_team_rowtasksr"  r#  updated_dataupdated_table_rownew_spend_rownew_user_notification_rowrr   rD  rE  rW  rF  s                          r{   r  PrismaClient.insert_data  s    " YY[
A	 &&'FMU"W#U;--4-8#/  ;;/7KK6P 0K4/P/V/V/]/] #.W+"$ 4T: 0^ 	0 	*& %))*IJ--v%--4-8)7)=)C)C)J)J($y/:&1k&( *K * $L& %))*IJ##v%2242@%3D%9%?%?%F%F$d9o6"-W+"$ &G &   %))*IJ##x'  JJLDA#$L#'::l#;L(8(>(D(D(K(K+Q/56&T'4l&C )L )% LL!23 ) nne,,,A1!444 %$))*KLw&--4-8&9$&?&E&E&L&L'l);<"-W+"$ 'M ' ! %))*JK$$22--4-82M3%'l);<"-W+"$  -) %))*RS00 3k	*$ ! vq6" ,(+ '+Z[bct[uZv  wD  *E$  G  > - 5!-  	J3q6(SI)$'$.1E1E1GGOyy{H :-I&&66'(&+"1	 7  G!	s  PB#M? <L6=M? PM? /0L< L9 L< $M? ;P<AM? M2M? PBM? +M5,%M? M8M? 0P1AM? 6M;7M? PAM? M=M? 4P6M? 9L< <
M/$M**M//M? 5M? 8M? ;M? =M? ?
P	B P		PPr  	data_list)r  update_many)rI  r   r  r:  rV  rT  rU  update_key_valuesupdate_key_values_custom_queryc
           
      X  #    [         R                  " SU 35        [        R                  " 5       n
 U R                  US9nUb  U R                  US9nUb  [	        SUSL S35        [        US9nXS'   [        U 5      R                  R                  SU00 UES9I Sh  vN n[         R                  " S	S
U 3-   S-   5        0 nUb   UR                  5       nXS.$ Uc  Ubw  US:X  aq  US:X  ak   Uc  US   nUc  U	b  U	nOUn[        U 5      R                  R                  SU00 UE0 UES.S9I Sh  vN n[         R                  " S	SU 3-   S-   5        XNS.$ Uc  Ub  US:X  a  US:X  a   Uc  US   nUc  UnSU;  a  Ub  X[S'   SU;   a4  [        US   [         5      (       a  ["        R$                  " US   5      US'   SU;   a4  [        US   [         5      (       a  ["        R$                  " US   5      US'   ['        U 5      R                  R                  SU00 UE0 UES.S9I Sh  vN n[         R                  " S	SU 3-   S-   5        X_S.$ Ub  US:X  a  US:X  a  Ub  [        U[         5      (       a   U R(                  R+                  5       n[-        U5       H  u  nnUR.                  R1                  S5      (       a  U R3                  UR.                  S9Ul         U R                  UR                  SS9S9nUR4                  R                  SUR.                  00 UES9  M     UR7                  5       I Sh  vN   [	        S5        gUb  US:X  a  US:X  a  Ub  [        U[         5      (       a   U R(                  R+                  5       n[-        U5       HP  u  nn U R                  UR                  SS9S9nUR8                  R                  SUR:                  00 UE0 UES.S9  MR     UR7                  5       I Sh  vN   [         R                  " S5        gUb  US:X  a  US:X  a  Ub  [        U[         5      (       a   U R(                  R+                  5       nU HM  n U R                  UR                  SS9S9nUR<                  R                  SUR:                  00 UE0 UES.S9  MO     UR7                  5       I Sh  vN   [         R                  " S 5        gUb  US!:X  a  US:X  a  Ub  [        U[         5      (       a   U R(                  R+                  5       nU HM  n U R                  UR                  SS9S9nUR>                  R                  S"UR@                  00 UE0 UES.S9  MO     UR7                  5       I Sh  vN   [         R                  " S#5        gUb  US:X  a  US:X  a  Ub  [        U[         5      (       a  U R(                  R+                  5       n[-        U5       HP  u  nn U RC                  UR                  SS9S$9nURD                  R                  SURF                  00 UE0 UES.S9  MR     UR7                  5       I Sh  vN   [         R                  " S%5        gggggg GN! [         a    UR                  5       n GNf = f GNn GNy! [         a     U R                  UR                  SS9S9n GNf = f GN! [         a!    U R                  UR                  5       S9n GN@f = f GN ! [         a!    U R                  UR                  5       S9n GNf = f GNm! [         a!    U R                  UR                  5       S9n GNf = f GN! [         a     U R                  UR                  SS9S9n GN{f = f GN;! [         a  nS&SK$nS'[K        U5       3n[	        U5        US(-   URL                  " 5       -   n[        R                  " 5       nUU
-
  n[N        RP                  " U RR                  RU                  UUS)US*95        UeSnAff = f7f)+z
Update existing data
z'PrismaClient: update_data, table_name: rP  Nztoken: [set=]rc  r{  r  z[91mz DB Token Table update succeeded z[0m)r{  r  rI  r  rO  r  z!DB User Table - update succeeded )rO  r  rV  rQ  r  z!DB Team Table - update succeeded )rQ  r  r   r  rj  T)exclude_nonez([91mDB Token Table update succeeded[0mz-[91mDB User Table Batch update succeeded[0mrT  z1[91mDB End User Table Batch update succeeded[0mrU  rr  z/[91mDB Budget Table Batch update succeeded[0mr  z-[91mDB Team Table Batch update succeeded[0mr   z/LiteLLM Prisma Client Exception - update_data: rx  update_datar|  )+r4   rs   r  rr  r|   r~  rg   r  r  r?  ri  r   rf   r  ri  r   r   ry  r  re   rw  batch_r)  r{  r|  r  litellm_verificationtokencommitlitellm_usertablerO  litellm_endusertablelitellm_budgettablerr  r  litellm_teamtablerQ  rr   ry   ru   r  r  r  r  )r   r{  r  r  rO  rQ  rY  r  r  r  rV  rq  r  _dataupdate_user_rowupdate_team_rowbatcherr3  r  	data_jsonrI  rT  rU  rV  rs  rr   rD  rE  rW  rF  s                                 r{   r  PrismaClient.update_datal  sy	    0 	""5j\B	
 YY[
J	))t)4G ,$($7$7=N$7$O! U$->,?qAB-E:#( !<T!B!H!H!O!O"E*$G "P "  %**8
CD 
 !'0 ( 3 3 5 "'66#*zV/C(* ?%i0G$,5A,J),3)(6t(<(B(B(I(I$g."-W+#/# )J ) # %))9/9JKL 
 $+DD#*zV/C(* ?%i0G$,(/%G+0C)0I&'72z0148 8 59JJ 455G01 (+<<%&:;TB B ?Cjj)*>??%&:; )7t(<(B(B(I(I$g."-W+#/# )J ) # %))9/9JKL 
 $+DD&%'-/)y$// ''..*'	2FCww))%00"&///"@X$($7$7!"4!@ %8 %	
 55<<&0*	] =  3 nn&&&N &&(-/)y$// ''..*!*9!5ICJ$($7$7!%d!C %8 %	
 --44($,,7&3m'"+' 5  "6  nn&&&$))S &)+-/)y$// ''..*(GM$($7$7!(!3!3!3!F %8 %	
 0077('//:&3m'"+' 8   )  nn&&&$))W &(*-/)y$// ''..*'FL$($7$7!'!2!2!2!E %8 %	
 //66*F,<,<=&3m'"+' 7  (  nn&&&$))U &&(-/)y$// ''..*!*9!5IC$($<$<$(OOO$F %= %	 --44($,,7&3m'"+' 5  "6$ nn&&&$))S/ 0 * 0 ) 'e % 0 (0$#R#D % X$($7$7QVVQUV=V$7$W	X '( % J$($7$7TYY[$7$I	J '( % M$($7$7W\\^$7$L	M '( % L$($7$7V[[]$7$K	L '$ % $($7$7!%!= %8 %	 '
  	I#a&RI)$'$.1E1E1GGOyy{H :-I&&66'(&+"1	 7  G!	s  /`*A,^ Y;(^ Y> ^ `*A^ 1Z2&^ `*C^ )Z"*&^ `*B^ #Z%??^ >[?^ `*A^ #[?A^ \^ `*A^ '\A^ \4^ "`*#A^ +\7A^ ]%^ &`*'A^ :](A^ ^^ 5`*;^ >Z^ Z^ "^ %&[^ [^ '\ <^ ?\  ^ '\1-^ 0\11^ 7']"^ !]""^ (&^^ ^^ 
`'"B `""`''`*tokens)rI  r   r  r:  rV  c           
      @  #    [         R                   " 5       n Ub  [        U[        5      (       a  / nU HQ  n[        U[        5      (       a&  UR	                  S5      (       a  U R                  US9nOUnUR                  U5        MS     0 n	Ub  SSSU00SU0/0n	OSSU00n	[        U 5      R                  R                  U	S9I Sh  vN n
[        R                  " S	U
5        S
U
0$ US:X  aJ  UbG  [        U[        5      (       a2  [        U 5      R                  R                  SSU00S9I Sh  vN   SU0$ US:X  aI  UbE  [        U[        5      (       a/  [        U 5      R                  R                  SSU00S9I Sh  vN   gggg N NZ N! [         a  nSSKnS[        U5       3n[        U5        US-   UR                   " 5       -   n[         R                   " 5       nX-
  n["        R$                  " U R&                  R)                  UUSUS95        UeSnAff = f7f)zI
Allow user to delete a key(s)

Ensure user owns that key, unless admin.
Nrj  rc  ro  r{  r  rO  r}  zdeleted_tokens: %sdeleted_keysrV  rQ  deleted_teamsr   r   z/LiteLLM Prisma Client Exception - delete_data: rx  delete_datar|  )r  r   r   ry   r|  r  r  rg   r  delete_manyr4   rs   re   ri  rr   r|   ru   r  r  r  r  )r   r  rR  r  rO  rV  r  r{  rx  filter_querydeleted_tokensrs  rr   rD  rE  rW  rF  s                    r{   r  PrismaClient.delete_data  s]    & YY[
;	!j&>&> "#E!%--%2B2B52I2I'+U'C',!((6 $ &(&4*? @9gBVW$L %,dM-B#CL'B(%& $ "
 %**+?P&77f$ ,|T22 %T*00<<$t\&:; =    (66e# ,|T22 2$7==II$t\&:; J    3 - $%"  	I#a&RI)$'$.1E1E1GGOyy{H -I&&66'(&+"1	 7  G!	sz   HB.F FF &H'AF .F	/F 6H7AF >F?F HF 	F F 
HA?HHHc           
      6  #    [         R                   " 5       n [        R                  " S5        U R                  R	                  5       SL a9  [        R                  " S5        U R                  R                  5       I S h  vN   g g  N! [         a  nSS KnS[        U5       3n[        U5        US-   UR                  " 5       -   n[         R                   " 5       nXa-
  n[        R                  " U R                  R                  UUSUS95        UeS nAff = f7f)	Nz:PrismaClient: connect() called Attempting to Connect to DBFz;PrismaClient: DB not connected, Attempting to Connect to DBr   z+LiteLLM Prisma Client Exception connect(): rx  connectr|  )r  r4   rs   rw  is_connectedr  ri  rr   ry   r|   ru   r  r  r  r  r   rV  rs  rr   rD  rE  rW  rF  s           r{   r  PrismaClient.connect  s      YY[
	 &&L ww##%.$**Q ggoo'''	 / ( 	Ec!fXNI)$'$.1E1E1GGOyy{H -I&&66'(&'"1	 7  G!	s<   DA&B ?B B DB 
DA?DDDc           
        #    [         R                   " 5       n U R                  R                  5       I S h  vN   g  N! [         a  nSS KnS[        U5       3n[        U5        US-   UR                  " 5       -   n[         R                   " 5       nXa-
  n[        R                  " U R                  R                  UUSUS95        UeS nAff = f7f)Nr   .LiteLLM Prisma Client Exception disconnect(): rx  
disconnectr|  )r  rw  r  ri  rr   ry   r|   ru   r  r  r  r  r  s           r{   r  PrismaClient.disconnect  s      YY[
	''$$&&& 	HQQI)$'$.1E1E1GGOyy{H -I&&66'(&*"1	 7  G!	s2   C> <> C> 
CA?CCCc                      U R                   R                  R                  nUb  [        USS 5      OS nUb  UR                  $  g! [
        [        4 a     gf = f)Nprocessr   )rw  _original_prisma_enginer   pidr  	TypeError)r   enginer  s      r{   _get_engine_pidPrismaClient._get_engine_pid)  sh    	WW--55F:@:Lgfi6RVG"{{" #  	* 		s   A A AAc                     U R                   S::  a  g [        R                  " U R                   S5        g! [         a     g[        [
        4 a     gf = f)Nr   TF)r  r   killProcessLookupErrorPermissionErrorOSErrorr  s    r{   _is_engine_alivePrismaClient._is_engine_alive3  sQ    q 	GGD$$a(! 	) 		s   !5 
AAAc                      [         R                  S:X  a
  [        5       $ [        5       n   [        R                  " S[        R
                  5      u  pUS:X  a   U $ U R                  U5        MD  ! [         a     U $ f = f)a  Reap ALL zombie child processes via waitpid(-1, WNOHANG).

Returns a set of reaped PIDs.  As PID 1 in Docker (or any
process that spawns children), we must reap ALL terminated
children to prevent zombie accumulation.

No-op on Windows: os.waitpid and os.WNOHANG are Unix-only.
win32r  r   )sysplatformr  r   waitpidWNOHANGaddChildProcessError)reapedr  r  s      r{   _reap_all_zombiesPrismaClient._reap_all_zombies>  sx     <<7"5LeB

3!8  

3  % s   -A. A. .
A<;A<r  c                    [         R                  S:X  a  g [        R                  " U[        R                  5      u  p#X!:X  a  [        R                  " SU5        U R                  U5      (       a(  [        R                  " SU5        U R                  5         gSU l        U R                  5         U R                  5         [        R                  " U R!                  SSS95        g [        R"                  " 5       n[&        R(                  " U R*                  X4SS	U 3S
9nUR-                  5         XPl        g! [
         a    [        R                  " SU5         gf = f! [$         a     gf = f)a  Watch engine PID via os.waitpid() in a dedicated thread.

The thread blocks on os.waitpid(pid, 0) which is a kernel-level
wait and with zero CPU overhead, instant detection when the process exits.
When the process dies, the thread notifies the asyncio event loop
via call_soon_threadsafe.

Returns True if the thread was started, False on failure.
On Windows, returns False immediately (os.waitpid/WNOHANG are Unix-only);
caller falls back to os.kill polling.
r  Fz6PID %s is not a child process; skipping waitpid watch.z7prisma-query-engine PID %s already dead at watch start.zEPID %s death was planned (engine already replaced); not reconnecting.Tengine_process_deathrC  forcezprisma-engine-waitpid-)r  r  r  r  )r  r  r   r  r  r  r4   rs   rl  _consume_expected_deathri  _cleanup_engine_watcherr  r  r  r  rL  get_running_loopr_  r  r  _waitpid_thread_funcr  r  )r   r  	probe_pidr  loopthreads         r{   _try_waitpid_watchPrismaClient._try_waitpid_watchU  sc    <<7"	::c2::6LI  ((I ++C00$))(
 ,,.*.D'""$((*))1 *  	++-D !!,,)#/	
 	#) Y ! 	 &&H 	B  		s#   'D6 %E 6!EE
E*)E*r  c                      [         R                  " US5         UR	                  U R
                  U5        g! [         a     N*[         a     N5f = f! [         a     gf = f)a  Thread function: block until engine PID exits, then notify event loop.

Note: uvloop/libuv may reap the child first via waitpid(-1, WNOHANG)
in its SIGCHLD handler. In that case our waitpid raises ChildProcessError.
we still notify the event loop because the engine is dead either way.
r   N)r   r  r  r  call_soon_threadsafe_on_engine_death_from_threadr_  )r   r  r  s      r{   r  !PrismaClient._waitpid_thread_func  sb    	JJsA
	%%d&G&GM ! 	 		  		s&   7 A 
A	AA
AAc                     [        U R                  SS5      n[        U[        5      (       a  X;   a  UR	                  U5        gg)aA  True iff ``pid`` was killed on purpose by a planned recreate.

`PrismaWrapper.recreate_prisma_client` records the old engine PID in
`_expected_engine_deaths` before SIGTERM-ing it (IAM token refresh,
guarded reconnect). When the watcher then sees that PID die, this lets
it recognize the death as planned and skip its own reconnect, which
would otherwise kill the engine the recreate just spawned (#29176).

Consumes (removes) the PID so a later real crash of a reused PID is
still handled. Tolerant of `self.db` stand-ins (tests / older clients)
that don't expose a real set.
_expected_engine_deathsNTF)r   rw  r   r  discard)r   r  expecteds      r{   r  $PrismaClient._consume_expected_death  s<     477$=tDh$$S!r}   dead_pidc                    U R                   (       a  gXR                  :w  a  gU R                  U5      (       a(  [        R                  " SU5        U R                  5         g[        R                  " SU5        SU l         U R                  5         U R                  5         [        R                  " U R                  SSS95        g)zMCalled on the event loop thread when the waitpid thread detects engine death.Nzkprisma-query-engine PID %s exited as part of a planned restart; not reconnecting (engine already replaced).zIprisma-query-engine PID %s exited (waitpid thread); triggering reconnect.Tr  r  )r  r  r  r4   ri  r  rm  r  r  r  rL  r   r  s     r{   r  )PrismaClient._on_engine_death_from_thread  s    &&'''''11 %%>
 ((*""W	
 '+# $$&%%- & 	
r}   c                 $   [        [        S5      (       d  gSn [        R                  " US5      n[        R                  " 5       R                  X R                  5        X l        g! [         a    US:  a  [        R                  " U5         gf = f)z
Watch engine PID via pidfd_open + asyncio event loop reader.

Returns True if pidfd watch was set up, False if unavailable or failed.
Broad OSError catch handles both ENOSYS and SECCOMP-blocked syscalls.

pidfd_openFr  r   T)
rA  r   r  r  r  
add_reader_on_pidfd_readabler  r  close)r   r  fds      r{   _try_pidfd_watchPrismaClient._try_pidfd_watch  sx     r<((	sA&B$$&11"6M6MN!# 	Qw	s   AA& &&BBc                    U R                   (       ah  U R                  S:  aW   [        R                  " 5       R	                  U R                  5         [        R                  " U R                  5        SU l        gU R                  nU R                  U5      (       a(  [        R                  " SU5        U R                  5         g[        R                  " SU5        SU l         U R                  5         U R                  5         [        R                   " U R#                  SSS95        g! [
         a     Nf = f! [         a     Nf = f)	zpidfd became readable: engine process exited or became zombie.

Sets _engine_confirmed_dead BEFORE cleanup so _run_reconnect_cycle
takes the heavy path (recreate Prisma client + re-arm watcher).
r   r  Nzyprisma-query-engine PID %s exited (pidfd event) as part of a planned restart; not reconnecting (engine already replaced).zFprisma-query-engine PID %s exited (pidfd event); triggering reconnect.Tr  r  )r  r  r  r  remove_readerri  r   r  r  r  r  r4   ri  r  rm  r  r  rL  r  s     r{   r  PrismaClient._on_pidfd_readable  s)    &&!!Q&,,.<<T=O=OPHHT//0 &("##''11 %%O
 ((*""T	
 '+# $$&%%- & 	
1 !   s#   .D'  D7 '
D43D47
EEc                   #    U R                   (       av  U R                  S:  ae   [        R                  " U R                  S5        [         R"                  " S	5      I Sh  vN   U R                   (       a  U R                  S:  a  Mc  gggg! [         a    U R                  nU R                  U5      (       a)  [        R                  " SU5        U R                  5          g[        R                  " SU5        SU l
        U R                  5         U R                  5         U R                  SSS9I Sh  vN     g[        [        4 a4    [        R                  " SU R                  5        U R                  5          gf = f GN 7f)
zpoll via os.kill(pid, 0) every 1s.
Only used when BOTH waitpid thread and pidfd are unavailable
(e.g., PID is not our child process and pidfd_open fails)
r   ziprisma-query-engine PID %s gone as part of a planned restart; not reconnecting (engine already replaced).Nz6prisma-query-engine PID %s gone; triggering reconnect.Tr  r  z+Cannot signal PID %s; stopping engine poll.r   )r  r  r   r  r  r  r4   ri  r  rm  r  r  rL  r  r  rs   r  sleepr  s     r{   _poll_engine_procPrismaClient._poll_engine_proc  s\    
 ##(8(81(<((!,< --"""A ##(8(81(<#(<# & ++//99(--O 
 002$**L /3+&&(,,.//1 0    #W- $**A$$ ,,. #sa   "F!B FE? %FFAE<F AE<1D42E<7F9A E<9F;E<<Fc                 <   SU l         U R                  S:  aW   [        R                  " 5       R	                  U R                  5         [        R                  " U R                  5        SU l        SU l	        SU l
        g! [
         a     NCf = f! [         a     N2f = f)zKClean up pidfd reader, waitpid thread ref, or stop polling and reset state.Fr   r  N)r  r  r  r  r  ri  r   r  r  r  r  r  s    r{   r  $PrismaClient._cleanup_engine_watcher9  s     %"((*889K9KL++, "$D#'     s#   .A>  B >
B
B
BBc                 b  #    U R                   (       d  U R                  S:  d  U R                  b  gU R                  5       nUS:X  a  [        R
                  " S5        gXl        SU l        [        R                  " SU5        U R                  U5      nU(       a  SOU R                  U5      nU(       a  [        R                  " SU5        gU(       a  [        R                  " SU5        g[        R                  " SU5        S	U l         [        R                  " U R                  5       5        g7f)
a3  
Start watching the Prisma query engine process for death.

Detection priority:
1. os.waitpid() in a dedicated thread, works with all event loops.
2. pidfd_open kernel fd registered with asyncio.
3. os.kill(pid, 0) polling (1s), last-resort fallback when neither
   waitpid thread nor pidfd are available.

r   NzKCould not find prisma-query-engine PID; engine death detection unavailable.Fz$Found prisma-query-engine at PID %s.z*Watching engine PID %s via waitpid thread.z!Watching engine PID %s via pidfd.z+Watching engine PID %s via os.kill polling.T)r  r  r  r  r4   rs   r  r  ri  r  r  r  r  r  )r   r  
waitpid_okpidfd_oks       r{   _start_engine_watcher"PrismaClient._start_engine_watcherI  s     !!!!Q&''3""$!8 &&] &+#!!"H#N,,S1
&5D,A,A#,F %%<  %%3
 !%%= %)D! 6 6 89s   D-D/c                 ^    U R                  5         SU l        [        R                  " S5        g)z<Stop watching the engine process and clean up all resources.FzStopped engine process watcher.N)r  r  r4   rs   r  s    r{   _stop_engine_watcher!PrismaClient._stop_engine_watcherw  s%    $$&&+#""#DEr}   c                 z    SU l         U R                  5         [        R                  " U R	                  5       5        g)ap  Re-arm the engine watcher after a planned writer-engine restart.

Wired as `PrismaWrapper.on_engine_replaced` and invoked from inside
`recreate_prisma_client` once the new engine is connected (IAM token
refresh, guarded reconnect). The old watcher was tracking the engine
we just intentionally killed, so we tear it down and re-arm on the new
PID. Scheduling `_start_engine_watcher` as a task (rather than awaiting)
keeps us from blocking the recreate while it still holds the wrapper's
reconnection lock. Without this re-arm, a planned restart would leave
the proxy with no engine-death detection until the next reconnect.
FN)r  r  r  r  r  r  s    r{   _handle_writer_engine_replaced+PrismaClient._handle_writer_engine_replaced}  s/     ',#$$&D6689r}   timeout_secondsc                 `  ^ ^#    Ub  UOT R                   n[        T R                  SS5      mT R                  =(       d+    T R                  S:  =(       a    T R                  5       (       + nU(       av  T R                  n[        R                  " SU5        T R                  5         T R                  5         S
UU 4S jjn[        R                  " U" 5       US9I Sh  vN   ST l        g[        R                  " S5        S
UU 4S	 jjn[        R                  " U" 5       US9I Sh  vN   g NN N7f)a(  
Run a reconnect cycle with a single overall timeout budget.

Uses the _engine_confirmed_dead flag (set by waitpid thread / pidfd / poll
handlers) to choose between heavy reconnect (engine dead -- recreate
Prisma client, re-arm watcher) and direct reconnect (network blip --
recreate Prisma client, re-arm watcher, SELECT 1). Both paths recreate
the client via the non-blocking kill-then-construct flow rather than
calling disconnect(), which blocks the event loop on the synchronous
subprocess.Popen.wait() inside prisma-client-py (see issue #26191).
N_engine_generationr   z1prisma-query-engine PID %s is dead; reconnecting.c                    >#    [         R                  " SS5      n U (       d!  [        R                  " S5        [	        S5      eTR
                  R                  U TS9I S h  vN   TR                  5       I S h  vN   g  N N7f)NDATABASE_URLre  z4DATABASE_URL not set; cannot recreate Prisma client.DATABASE_URL not setexpected_generation)r   r   r4   rm  r_  rw  recreate_prisma_clientr  )db_urlr!  r   s    r{   _do_heavy_reconnect>PrismaClient._run_reconnect_cycle.<locals>._do_heavy_reconnect  s     >26(..N ''=>> gg440C 5    00222 3s$   AB A>!B8B 9B BtimeoutFz9Performing Prisma DB reconnect (engine alive or unknown).c                  z  >#    [         R                  " SS5      n U (       d!  [        R                  " S5        [	        S5      eTR
                  n UR                  S5      I S h  vN   [        R                  " S5        TR                  5       I S h  vN   g  N3 N! [         a!  n[        R                  " SU5         S nAOS nAff = fTR                  5         TR                  R                  U TS9I S h  vN    TR                  5       I S h  vN    TR
                  R                  S5      I S h  vN    g 7f)	Nr  re  z5DATABASE_URL not set; cannot reconnect Prisma client.r  SELECT 1z_Writer healthy on probe; skipping recreate (engine likely already replaced by a token refresh).z3Writer probe failed (%s); recreating Prisma client.r   )r   r   r4   rm  r_  r  r)  ri  r  ri  rl  r  rw  r"  )r#  r  	probe_errr!  r   s      r{   _do_direct_reconnect?PrismaClient._run_reconnect_cycle.<locals>._do_direct_reconnect  s    >26(..O ''=>>  **:666(--G 44666 7
 7  (00M!  ,,.gg440C 5    00222 nn..z:::sx   AD;B $B%-B BB D;B B 
C&C=D;C0D;7C:8D;D#D;4D75D;r   N)r  r   r  r  r  r  r4   rl  r  r  r  wait_forrs   )r   r  effective_timeoutengine_is_deadr  r$  r+  r!  s   `      @r{   _run_reconnect_cycle!PrismaClient._run_reconnect_cycle  s      * << 	 &dnn6JDQ44 
q @)>)>)@%@ 	 ''H ((C ""$((*3 3& ""#6#8BSTTT +0D' &&K); );V ""#7#9CTUUUo Un Vs%   CD.D*AD.$D,%D.,D.r  rC  c                   #    [         R                   " 5       nUSL a4  X@R                  -
  U R                  :  a  [        R                  " SU5        gU R
                  U R                  :  a)  [        R                  " SU R
                  U5        SU l        [        R                  " SU5        Sn U R                  US9I S h  vN   SnSU l        [        R                  " SU5        [         R                   " 5       U l        U$  N@! [         aB  nU =R
                  S	-  sl        [        R                  " S
U R
                  UU5         S nANeS nAff = f! [         R                   " 5       U l        f = f7f)NFzDSkipping DB reconnect attempt inside lock due to cooldown. reason=%szFEscalating to heavy reconnect after %d consecutive failures. reason=%sTz)Attempting Prisma DB reconnect. reason=%s)r  r   z(Prisma DB reconnect succeeded. reason=%sr   z?Prisma DB reconnect failed (%d consecutive). reason=%s error=%s)r  r  r  r4   rs   r  r  rl  r  r1  ri  ri  rm  )r   r  rC  r  r  reconnect_succeededreconnect_errs          r{   _attempt_reconnect_inside_lock+PrismaClient._attempt_reconnect_inside_lock  sW     iikUN888112 !&&V  //43W3WW ((X44
 +/D'$$7	
 $	=++O+LLL"&34D0 %%:F 26D.""# M  	00A50 &&Q44	 	 26D.sN   B+E1.D  D$D %E1D 
E8E
E 
EE E..E1lock_timeout_secondsc                   ^ ^#    [         R                   " 5       nUSL a5  UT R                  -
  T R                  :  a  [        R                  " SU5        gUc@  T R
                   ISh  vN   T R                  X!U5      I Sh  vN sSSS5      ISh  vN   $ SmS[        4UU 4S jjn[        R                  " U" 5       5      n[        R                  " U1U[        R                  S9I Sh  vN u  pXx;  aV  UR                  5          UI Sh  vN   T(       a   T R
                  R                  5         [        R                  " SUU5        g UR#                  5          T R                  X!U5      I Sh  vN T R
                  R                  5         $  GN, GN GN! , ISh  vN  (       d  f       GN= f N N! [        R                   a     N[         a     Nf = f! [          a     Nf = f! [         a"  n
[        R                  " SUU
5         Sn
A
gSn
A
ff = f N! T R
                  R                  5         f = f7f)	z
Attempt to reconnect the Prisma client in a singleflight manner.

Returns:
    bool: True if reconnection succeeded, else False.
Fz8Skipping DB reconnect attempt due to cooldown. reason=%sNr   c                  Z   >#    TR                   R                  5       I S h  vN   Sm g N7fNT)r  acquire)lock_acquired_by_timeout_taskr   s   r{   _acquire_reconnect_lockBPrismaClient.attempt_db_reconnect.<locals>._acquire_reconnect_lock^  s,     ))11333,0) 4s   +)+)r'  return_whenzTSkipping DB reconnect attempt due to lock acquisition timeout. reason=%s timeout=%sszOSkipping DB reconnect attempt due to lock acquisition error. reason=%s error=%s)r  r  r  r4   rs   r  r6  r   r  r  waitFIRST_COMPLETEDcancelCancelledErrorri  releaser_  r  )r   rC  r  r  r8  r  r>  acquire_taskdone_pendinglock_acquire_errr=  s   `          @r{   rL  !PrismaClient.attempt_db_reconnect=  s     iikUNd888112 !&&J '...!@@?  /..
 ).%	t 	 	 **+B+DE&||N(// 
 

 #!""" -++335 !&&f$
 	!	.<<  ##++-q / /...
 #))   $   	 &&a 
 	 ##++-s  A#I 'F(I +FFFI FAI +F7,I F; F9F; I G  4I G0 H! 4H5H! 8I FI F4"F%#F4/	I 9F; ;GI 	GI GI  
G-*I ,G--I 0
H:HI HI H! !H==I c                   #    U R                   SLa  [        R                  " S5        gU R                  b  gU R                  U R
                  l        [        R                  " U R                  5       5      U l        [        R                  " SU R                  U R                  U R                  U R                  5        U R                  5       I Sh  vN   g N7f)zStart background tasks that monitor DB health:
- A periodic SELECT 1 probe that triggers reconnect on network/connection failure.
- A process-level watcher that detects engine death via waitpid thread, pidfd, or os.kill polling.
TzEPrisma DB health watchdog disabled via PRISMA_HEALTH_WATCHDOG_ENABLEDNzrStarted Prisma DB health watchdog (interval=%ss, reconnect_cooldown=%ss, probe_timeout=%ss, reconnect_timeout=%ss))r  r4   rs   r  r  r  on_engine_replacedr  r  _db_health_watchdog_loopri  r  r  r  r  r  r  s    r{   start_db_health_watchdog_task*PrismaClient.start_db_health_watchdog_task  s     
 ++47 &&W ((4
 -1,O,O)(/(;(;))+)
% 	!! A55//::77	
 ((***s   CCCCc                   #    U R                  5         U R                  c  gU R                  R                  5          U R                  I Sh  vN   SU l        [
        R                  " S5        g N"! [        R                   a     N6f = f7f)z;Stop DB health watchdog task and engine watcher gracefully.Nz!Stopped Prisma DB health watchdog)r  r  rC  r  rD  r4   ri  r  s    r{   stop_db_health_watchdog_task)PrismaClient.stop_db_health_watchdog_task  s{     !!#((0%%,,.	//// )-%!!"EF	 0%% 		s:   9B
A0 A.A0 B
.A0 0BB
BB
c                 4  #      [         R                  " U R                  5      I S h  vN   [         R                  " U R                  R                  S5      U R                  S9I S h  vN   Mk   NF N! [         R                   a     g [         a  n[        U[         R                  5      (       d  [        R                  " U5      (       a(  U R                  SU R                  S9I S h  vN     S nAN[        R                   " SU5         S nANS nAff = f7f)Nr)  r&  #db_health_watchdog_connection_error)rC  r  z3Prisma DB health watchdog observed non-DB error: %s)r  r
  r  r.  rw  r)  r  rD  ri  r   TimeoutErrorrP   is_database_connection_errorrL  r  r4   rs   r   rs  s     r{   rM  %PrismaClient._db_health_watchdog_loop  s     mmD$M$MNNN&&GG%%j1 JJ   N ))  w++ -JJ1MM33D(,(S(S 4   
 )..Mq su   D#A3 A/?A3 (A1)A3 -D/A3 1A3 3DD		DAD)C,*D/D4DDDDc           
        #    [         R                   " 5       n SnU R                  R                  U5      I Sh  vN nU$  N! [         a  nSSKnS[        U5       3n[        U5        US-   UR                  " 5       -   n[         R                   " 5       nX-
  n	[        R                  " U R                  R                  UU	SUS95        UeSnAff = f7f)z-
Health check endpoint for the prisma client
r)  Nr   r  rx  r*  r|  )r  rw  r)  ri  rr   ry   r|   ru   r  r  r  r  )
r   rV  rH  r  rs  rr   rD  rE  rW  rF  s
             r{   r*  PrismaClient.health_check  s      YY[
	"I "WW..y99HO : 	HQQI)$'$.1E1E1GGOyy{H -I&&66'(&,"1	 7  G!	s8   C A A A C A 
CA?CCCc                   ^ #    [         R                  " [         R                  [        SS[        S9S[
        4U 4S jj5       n U" 5       I Sh  vN $  N! [         a#  n[        R                  " SU 35         SnAgSnAff = f7f)	zT
Get the row count from LiteLLM_SpendLogs table using PostgreSQL system statistics.
r  r  r  r   c                  f   >#    Sn TR                   R                  U S9I S h  vN nUS   S   $  N7f)Nz
            SELECT reltuples::BIGINT
            FROM pg_class
            WHERE oid = '"LiteLLM_SpendLogs"'::regclass;
            )queryr   	reltuples)rw  r)  )rH  r  r   s     r{   _fetch_row_count@PrismaClient._get_spend_logs_row_count.<locals>._fetch_row_count  s=     I
  77,,9,==F!9[)) >s   1/1Nz+Error getting LiteLLM_SpendLogs row count: r   )backoffon_exceptionexpori  rl  rh  r4   rm  )r   r_  rs  s   `  r{   _get_spend_logs_row_count&PrismaClient._get_spend_logs_row_count  s     
 
		LL!

	* 	*

	*	)++++ 	 &&=aSA 		sB   A B
A AA BA 
BA=8B=BBc                 l   #    SSK Jn  U R                  5       I Sh  vN nUR                  SUS9  g N7f)z
Set the `LiteLLM_SpendLogs`row count in proxy state.

This is used later to determine if we should run expensive UI Usage queries.
r   )proxy_stateNspend_logs_row_count)variable_namer   )r  rg  rd  set_proxy_state_variable)r   rg  _num_spend_logs_rowss      r{   (_set_spend_logs_row_count_in_proxy_state5PrismaClient._set_spend_logs_row_count_in_proxy_state  s;      	;%)%C%C%EE,,0& 	- 	
  Fs   424response_time_msc                     Uc  g [        U5      nX":X  a  U[        S5      [        S5      4;  a  U$ S$ ! [        [        4 a    [        R                  " SU 35         gf = f)z&Validate and clean response time valueNinfz-infz Invalid response_time_ms value: )r   r  r  r4   rl  )r   rn  r   s      r{   _validate_response_time$PrismaClient._validate_response_time*  s     #	*+E >eE%L%-3P&P  
 I& 	 ((23C2DE 		s   +4 4 )A A rk  c                     [        U[        5      (       d  g [        [        U5      5      $ ! [         a#  n[
        R                  " SU 35         SnAgSnAff = f)zClean and validate details JSONNzFailed to clean details JSON: )r   r   rD   rC   ri  r4   rl  )r   rk  rs  s      r{   _clean_detailsPrismaClient._clean_details=  sP    '4((	":g#677 	 ((+I!)MN	s   , 
AAA
model_namer-   healthy_countunhealthy_countrc  
checked_byr;  c
                   #     [        U5      [        U5      [        U5      [        U5      S.n
U(       a  [        U5      SS OSU R                  U5      U R                  U5      U(       a  [        U5      OSU	(       a  [        U	5      OSS.nU
R	                  UR                  5        VVs0 s H  u  pUc  M
  X_M     snn5        [        R                  " SU
 35        [        U 5      R                  R                  U
S9I Sh  vN $ s  snnf  N
! [         a&  n[        R                  " SU SU 35         SnAgSnAff = f7f)	z$Save health check result to database)rv  r-   rw  rx  Ni  )rc  rn  rk  ry  r;  zSaving health check data: rP  z+Error saving health check result for model : )ry   rh  rq  rt  r  r.  r4   rs   rb   r  r  ri  rm  )r   rv  r-   rw  rx  rc  rn  rk  ry  r;  health_check_dataoptional_fieldsr"  r#  rs  s                  r{   save_health_check_result%PrismaClient.save_health_check_resultG  s=     	 "*of+!$]!3#&#7	! >K]!3DS!9PT$($@$@AQ$R..w71;c*o-5CM4O $$"1"7"7"9K"9$!Q"9K !&&)CDUCV'WX.t4::AA& B   	 L  	 &&=j\A3O 		sT   EB(D ,	D

9D

?AD DD 	E
D 
ED=8E=EEstatus_filterc                   #     0 nU(       a  XS'   U(       a  XES'   [        U 5      R                  R                  USS0UUS9I Sh  vN nU$  N! [         a%  n[        R
                  " SU 35        / s SnA$ SnAff = f7f)z2
Get health check history with optional filtering
rv  r-   
checked_atrk  )r~  rl  rf  skipNz$Error getting health check history: rb   r  r  ri  r4   rm  )r   rv  r_  r^  r  where_clauseresultsrs  s           r{   get_health_check_history%PrismaClient.get_health_check_historyv  s     	L-7\*)6X&1$7==GG"#V,	 H  G N  	 &&)MaS'QRI	sG   BAA AA BA 
A>A93A>4B9A>>Bc                    #     [        U 5      R                  R                  SS/SS0SS0SS0/S9I Sh  vN $  N! [         a%  n[        R
                  " SU 35        / s SnA$ SnAff = f7f)	z
Get the latest health check for each model.

Uses DB-level DISTINCT ON (model_id, model_name) with ORDER BY checked_at DESC
(via Prisma ``distinct`` + ``order``) so we never load the full history into memory.
r;  rv  ascr  rk  )distinctrl  Nz(Error getting all latest health checks: r  rW  s     r{   get_all_latest_health_checks)PrismaClient.get_all_latest_health_checks  s     	.t4::DD$l3'!5)!6* E      	 &&)QRSQT'UVI	s=   A.1< :< A.< 
A+A& A+!A.&A++A.)r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  rw  r  r  r   )NNNNNNNrZ  NNNNNNNT)NNNNr-  FNN)r   r   NNNNN)Nr:  r   N)Or   r   r   r   r  r   r   r  r  _spend_log_transactions_lockry   r   r   r   r   propertyrS   r  r   r   r!   r   r  r  rr  ra  rb  rc  ri  rl  r6  rR   r  rM  r   r   rh  rp   r   r{  r  r  r  r  r  r  r  r  rg  r  r  r  AbstractEventLoopr  r  r  r  r  r  r  r  r  r  r   r1  r6  rL  rN  rQ  rM  r*  rd  rl  rq  rt  r~  r  r  r   r   r}   r{   r  r  i  s   #%D%#*<<>  &*	[F[F ([F c]	[Fz =  !T#334!	%	&!F 
4 
D 
 VVp :: : >?	: :x.?.?	$.?`   -1!%'+!%'+"& 9F&*'+ $ +/48.2!%?jc4i()j #j tn	j
 #j tnj $j !

j* 56+j, (#-j. 8$/j0 1j2 
3j8 #4.9j: $L1;j< !c+=j> ?j jX4  LL I
LL^   $$(!%!%7? ,09=_}_ _ D>	_
 #_ #_ 34_ QR
_ $D>_ )1__D	  "&'+RV!%HH tnH W%MNO	H
 #HHV < , 	$ 	 s  ,<c <d <| 73L3L QU $3 4 &
S 
T 
8C D ((
T%#N ,:\F:" 26vV'vV	vVp6#6# 6# "%	6#
 
6#v +/04R.R. R. "%	R.
 'uoR. 
R.h+:G. < : 

 (	%&htn $   '+,0"&$("&-- - 	-
 -  }- #5/- $- SM- 3--b %)'+SM  	
  }8r}   r  rO  r  c                 <  #    U  S3nUR                  US9nUc  UR                  U S9I Sh  vN nUbe  [        SU S[        U5       35        [	        US5      (       a:  [        [        US5      5      (       a   UR                  5       nUR                  X6SS	9  g Nm7f)
z9
Check if a user_id exists in cache,
if not retrieve it.
_user_api_key_user_id)r   N)rO  z
User Row: z	, type = model_dump_jsoniX  )r   r   r;  )	r   r{  r|   r   rA  callabler   r  r   )rO  r  rw  r  r  user_rowr  s          r{   _cache_user_rowr    s     
 )01I9-HW55Jxj	$x.9IJKx!233"349 9 '668!#     6s   *BBA.B	smtp_portc                 N    [         R                  " SS5      S:H  =(       d    U S:H  $ )z
Port 465 expects an immediate TLS handshake (implicit SSL), so a plain
smtplib.SMTP connection hangs waiting for an SMTP banner. Use SMTP_SSL
there, or when SMTP_USE_SSL is explicitly enabled.
SMTP_USE_SSLFalseTruei  r   r   r  s    r{   _should_use_smtp_sslr    s$     99^W-7K9;KKr}   	smtp_hostc                     [        US9(       a(  [        R                  " X[        R                  " 5       S9$ [        R
                  " XS9$ )Nr  )r  r  context)r  r  )r  smtplibSMTP_SSLsslcreate_default_contextSMTPr  r  s     r{   _create_smtp_connectionr    s<    i0C4N4N4P
 	
 <<Y77r}   receiver_emailsubjecthtmlc                   #    [         R                  " S5      n[        [         R                  " SS5      5      n[         R                  " S5      n[         R                  " S5      n[         R                  " SS5      nUc  [        S5      eU c  [        S	U  35      eUc  [        S
U 35      eUc  [        SU 35      e[	        5       nXxS'   XS'   XS'   [
        R                  " SXp5        Uc  [        S5      eUR                  [        US5      5         [        US9n	[        UUS9 n
U	(       d=  [         R                  " SS5      S:w  a"  U
R                  [        R                  " 5       S9  U(       a  U(       a  U
R                  UUS9  U
R                  UUU S9  SSS5        g! , (       d  f       g= f! [          a,  n[
        R"                  " S[%        U5      -   5         SnAgSnAff = f7f)zP
smtp_host,
smtp_port,
smtp_username,
smtp_password,
sender_name,
sender_email,
r   	SMTP_PORT587SMTP_USERNAMESMTP_PASSWORDSMTP_SENDER_EMAILNz4Trying to use SMTP, but SMTP_SENDER_EMAIL is not setz+No receiver email provided for SMTP email. z$No subject provided for SMTP email. z&No HTML body provided for SMTP email. FromToSubjectzsending email from %s to %sz,Trying to use SMTP, but SMTP_HOST is not setr  r  r  SMTP_TLSr  r  )r  )rI  password)msg	from_addrto_addrsz*An error occurred while sending the email:)r   r   rh  r  r	   r4   rs   attachr
   r  r  starttlsr  r  loginsend_messageri  r  ry   )r  r  r  r  r  smtp_usernamesmtp_passwordsender_emailemail_message	using_sslserverrs  s               r{   
send_emailr    s     		+&IBIIk512IIIo.MIIo.M990$7LOPPF~FVWXX?yIJJ|A$HII "OM(&($&)%| GHH $/0
(9=	$
 :v!>'!I(B(B(DE &*   !&'   
 
 
*  
&&83q6A	
 	

sU   DG.F5 'A4F$F5 #G.$
F2.F5 1G.2F5 5
G+?"G&!G.&G++G.r{  c                 j    SS K nUR                  " U R                  5       5      R                  5       nU$ )Nr   r
  )r{  r  rx  s      r{   r  r    s*     >>%,,.1;;=Lr}   r  c           	          SSK nSSKnSSKnUR                  " S5      nUR                  " U R                  5       USSSSS9nS	UR                  XE-   5      R                  5       -   $ )
z0Hash a password using scrypt with a random salt.r   N    @     r   r  saltnr  pdklenscrypt:)base64r  r   urandomscryptr  	b64encodedecode)r  r  r  r   r  dks         r{   hash_passwordr  "  sX    ::b>D	)ar	RBv''	299;;;r}   storedc           	         SSK nSSKnSSKnUR                  S5      (       aR   UR	                  USS 5      nUSS USS pvUR
                  " U R                  5       USSSS	S
9nUR                  Xx5      $ [        U5      S:X  aq  [        S U 5       5      (       aZ  UR                  UR                  " U R                  5       5      R                  5       R                  5       UR                  5       5      $ g! [         a     gf = f)zDVerify a password against a stored hash. Supports scrypt and SHA256.r   Nr     r  r  r  r   r  r  F@   c              3   *   #    U  H	  oS ;   v   M     g7f0123456789abcdefNr   r}  s     r{   r  "verify_password.<locals>.<genexpr>>  s      I&Q&8!8&   )r  r  secretsr|  	b64decoder  r  compare_digestri  r}  rA  r  r  )	r  r  r  r  r  rawr  r  dk2s	            r{   verify_passwordr  -  s    ##	""6!":.C3BxRS"..!arC ))"22 6{bS I& III%%NN8??,-779@@BFMMO
 	
   		s   AC6 6
DDc                 2  #    [        U 5      R                  R                  SSS00S9I Sh  vN nS[        S[        4S jnU Vs/ s HS  nUR
                  (       d  M  UR
                  R                  S5      (       a  M8  U" UR
                  5      (       a  MQ  UPMU     nnU(       d  g	U HO  n[        U 5      R                  R                  S
UR                  0S[        UR
                  5      0S9I Sh  vN   MQ     S[        U5       S3$  Ns  snf  N7f)z
Migrate plaintext passwords in the DB to scrypt. SHA256 passwords
are left alone (they migrate on next login via the SHA256 fallback).
Skips quickly if no plaintext passwords exist.
r  notNr}  sr   c                 P    [        U 5      S:H  =(       a    [        S U  5       5      $ )Nr  c              3   *   #    U  H	  oS ;   v   M     g7fr  r   r}  s     r{   r  Lmigrate_passwords_to_scrypt_async.<locals>._is_sha256_hex.<locals>.<genexpr>P  s     #GQ);$;Qr  )r}  rA  )r  s    r{   _is_sha256_hex9migrate_passwords_to_scrypt_async.<locals>._is_sha256_hexO  s     1v|G#GQ#G GGr}   r  zNo plaintext passwords foundrO  r  z	Migrated z plaintext passwords to scrypt)rf   r  r  ry   r   r  r|  r  rO  r  r}  )r  all_with_pwr  uplaintext_usersrI  s         r{   !migrate_passwords_to_scrypt_asyncr  E  s"     '}5;;EEE4=) F  KH# H$ H
 A:: 	
 

%%i0 	
 qzz*	 	
   -]+1188dll+mDMM:; 9 
 	
 	
  
 s?+,,JKK-	
s@   *DDDDDDD AD6D7DDc                 D    U R                  S5      (       a	  [        U S9$ U $ )zT
Hash the token if it's a string and starts with "sk-"

Else return the token as is
rj  rc  )r|  r  rc  s    r{   r~  r~  d  s%     &&r}   c                       \ rS rSr\S\S\S\S\\	\
4   4S j5       r\ SS\S\S\\   S\S	\\\\	\4         4
S
 jj5       r\S\4S j5       rSrg)ProxyUpdateSpendip  n_retry_timesr  r  end_user_list_transactionsc                 $  #    [        U S-   5       H  n[        R                  " 5       n UR                  R                  [	        SS9S9 IS h  vN nUR                  5        IS h  vN n[        UR                  5       5       H>  u  p[        R                  b   UR                  R                  SU0UU	SS.SS	U	00S
.S9  M@     S S S 5      IS h  vN   S S S 5      IS h  vN     g    g  N N N! , IS h  vN  (       d  f       N2= f N)! , IS h  vN  (       d  f       N>= f! [         a=  n
X@:  a
  [        XUS9  [        R                  " SU-  5      I S h  vN     S n
A
GMY  S n
A
f[          a  n
[        XUS9   S n
A
GMw  S n
A
ff = f7f)Nr   rv  )secondsr&  rO  F)rO  r:  rf  r:  	incrementr  r  rs  rV  r  r8  )ranger  rw  txr   r  sortedr.  rv   max_end_user_budgetr  r  r   $_raise_failed_update_spend_exceptionr  r
  ri  )r  r  r  r  r  rV  transactionr  end_user_idr  rs  s              r{   update_end_user_spend&ProxyUpdateSpend.update_end_user_spendq  su     }q()AJ"(++..%b1 /   *1133w:@6<<>;6K  '::F $#88??'0+&> 4?1>38/&
 07m8T.U&" @ 
;  43 , 3 *  4333   . - *%8FW mmAqD)))) 4BS s   'F$D(C,D(D'C.
(D+AC2DC0DD("D#D('F,D(.D0D2D	8C;9D	DD(D%	DD%	!D((
F2+E*E E*#F*F7
FFFFNdb_writer_clientlogs_to_processc                   #    SnSnSnUcS  UR                    IS h  vN   UR                  S U nUR                  [        U5      S  Ul        S S S 5      IS h  vN   Sn[        U5      S:  a   [        R                  " S[        U5      5        [
        R
                  " 5       n [        U S-   5       GH  n	 [        R                  " SS 5      n
[        U5      S:  a  U
b  Ub  U
R                  S	5      (       d  U
S	-  n
[        R                  " S
R                  U
5      5        [        R                  " U5      nUR                  U
S-   USS0S9I S h  vN nAUR                  S:X  a   O[        S[        U5      U5       H|  nXMX-    nU Vs/ s H  nUR!                  0 UE5      PM     nn[#        U5      R$                  R'                  USS9I S h  vN   [        R                  " S[        U5       S35        AAM~     UR                    IS h  vN   [        UR                  5      nS S S 5      IS h  vN   [        R                  " [        U5       SW 35          O    U(       a  Ag g  GNQ GN! , IS h  vN  (       d  f       GN.= f GN<s  snf  N N Nd! , IS h  vN  (       d  f       Ny= f! [(         ah  nU	c  Sn	[        R*                  " SU	S-   U [        U5      [-        U5      5        X:  a  e [.        R0                  " SU	-  5      I S h  vN     S nAGMq  S nAff = f! [2         a  n[5        UXS9   S nANS nAff = f! U(       a  Af f = f7f)Nr  '  FTr   z6Spend tracking - processing %d spend logs for DB writer   SPEND_LOGS_URL/zbase_url: {}zspend/updatezContent-Typezapplication/json)r  r  headers   )r  skip_duplicateszFlushed z logs to the DB.z% logs processed. Remaining in queue: z]Spend tracking - DB connection error writing spend logs, retry %d/%d. logs_count=%d, error=%sr8  r  )r  r  r}  r4   ri  r  r  r   r   endswithrs   rt   ry  r  postr  rr  rc   r  create_manyr   rl  ry   r  r
  ri  r   )r  r  r  r  r  
BATCH_SIZEMAX_LOGS_PER_INTERVALpopped_batchrV  r  base_url	json_datar  jbatchentrybatch_with_datesremaining_countrs  s                      r{   update_spend_logs"ProxyUpdateSpend.update_spend_logs  sL     
 	 "$AAA"/"F"F**#
 "88_9M9OP 4 BA  L!# %%HO$ YY[
D	$=1,-8.!yy)94@HO,q0$0,8'0055$OH,22>3H3H3RS$(JJ$?	)9)>)> (> 9!*%35G$H *? * $
 &#//36 !&q#o*>
!KA$3$GE .30-2E !. < <YY G-2 - 0 #6m"D"J"J"V"V%5t #W #   166"*3u:,6F G !&'7 "L  $1#M#M#M.1-2V2V.WO $N#M,22"?344YZiYjk W .D # e BAAA8$0 $N#M#M#M 1 .y(00?A%O,A )!--1----.  	 1
	 # s=  MI-M-I3MI0A
M$L+ 7BJ6J:J6J*(J6J=J6JJ6J*J65J6(J6L+ M  L+ "M #M0M3J9I<:JMJ6J6J6J6J3	"J%#J3	/J66
L( AL#LL#L+ #L((L+ +
M	5
M?M M		M MMr   c                  :    SSK Jn   U R                  S5      SL a  gg)zs
returns True if should not update spend in db
Skips writing spend logs and updates to key, team, user spend to DB
r   general_settingsdisable_spend_updatesTF)r  r  r&  r  s    r{   r   &ProxyUpdateSpend.disable_spend_updates  s"     	@ 78D@r}   r   r   )r   r   r   r   rg  rh  r  r   r   ry   r   r  r   rE   r   r   r  r   r   r   r   r}   r{   r  r  p  s    **#* (* %)e$4	* *X  ;?a$a$#a$ ##34a$ (	a$
 "$tCH~"67a$ a$F 	4 	 	r}   r  r  r  c                   #    SnUR                   R                  U UUS9I Sh  vN   U R                   ISh  vN   [        U R                  5      nSSS5      ISh  vN   [
        R                  " SR                  W5      5        US:  a  [        U UUS9I Sh  vN   gg N~ Nk NH! , ISh  vN  (       d  f       N]= f N&7f)a'  
Batch write updates to db.

Triggered every minute.

NOTE: This job now skips tag spend updates, which are handled by a separate
scheduler job (update_daily_tag_spend) at a longer interval to reduce contention.

Requires:
user_id_list: dict,
keys_list: list,
team_list: list,
spend_logs: list,
r  r  r  r  NzSpend Logs transactions: {}r   r  r  r  )	r   #db_update_spend_transaction_handlerr  r}  r  r4   rs   rt   update_spend_logs_job)r  r  r  r  
queue_sizes        r{   update_spendr(    s     & M

2
2
V
V##+ W    999==>
 :9<CCJOP A~#'-/
 	
 	
 # :999	
s`   !CB"CB$CB(CB&=CCC$C&C(B?.B1/B?;Cc                 Z  #    Sn UR                   R                  R                  5       (       a$  UR                   R                  U UUS9I Sh  vN   gUR                   R	                  U UUS9I Sh  vN   g N) N! [
         a#  n[        R                  " SU 35         SnAgSnAff = f7f)a  
Separate scheduler job to commit daily tag spend updates.

Runs at a longer interval (2.3x default) than the main update_spend job
to reduce query contention for DailyTagSpend table.

This is called by a dedicated scheduler job and does NOT process:
- Regular spend updates (user, key, team, org)
- End-user spend
- Agent spend
- Spend logs

Only processes tag spend transactions from the daily_tag_spend_update_queue.

Args:
    prisma_client: PrismaClient instance
    proxy_logging_obj: ProxyLogging instance for error handling
r  r#  Nz Error updating daily tag spend: )r   r  %_should_commit_spend_updates_to_redis(_commit_daily_tag_spend_to_db_with_redis_commit_daily_tag_spend_to_dbri  r4   rm  )r  r  r  rs  s       r{   update_daily_tag_spendr-  <  s     , MK44HHnnpp#::cc++"3 d    $::XX++"3 Y   
  K 	""%EaS#IJJKs_   B+AA; A7A; B+A; 1A92A; 6B+7A; 9A; ;
B(B#B+#B((B+c                 
  #    SnSnU R                    ISh  vN   [        U R                  5      nSSS5      ISh  vN   WS:X  a  gU R                    ISh  vN   U R                  SU nU R                  [        U5      S U l        SSS5      ISh  vN   [        R	                  UU UUWS9I Sh  vN    SSKJn  U" U US9I Sh  vN    SS	K
Jn	  U	" U US9I Sh  vN   g N N! , ISh  vN  (       d  f       N= f N Np! , ISh  vN  (       d  f       N= f Nm NY! [         a!  n[        R                  " SU5         SnAN}SnAff = f Ns! [         a!  n
[        R                  " S
U
5         Sn
A
gSn
A
ff = f7f)z
Job to process spend_log_transactions queue.

This job is triggered based on queue size rather than time.
Pops the batch once, writes spend logs, then runs guardrail usage tracking.
r  r  Nr   )r  r  r  r  r  )"process_spend_logs_guardrail_usage)r  r  z@Spend tracking - guardrail usage tracking failed (non-fatal): %s)process_spend_logs_tool_usagez;Spend tracking - tool usage tracking failed (non-fatal): %s)r  r}  r  r  r  'litellm.proxy.guardrails.usage_trackingr/  ri  r4   rl  %litellm.proxy.db.spend_log_tool_indexr0  )r  r  r  r  r  r'  r  r/  guardrail_tracking_errr0  tool_tracking_errs              r{   r&  r&  k  s}     M! 999==>
 :9Q999'>>?U@UV/</S/S "0
, :9 
,
,##+)' -   
	
 1'+
 	
 	

W+'+
 	
 	
O :999
 :999	
  
$$N"	
 	

	
  
$$I	
 	

s  FC%FC)FC'FDF-D	FDF3D!4F9D% 	D#
D% E E E $F'F)D /C20D <FFDDDF#D% %
E/EFEFE 
F E;6F;F  Fc                   #    SSK JnJn  UnUnSnSnUn	[        R                  " SU SU S35          U R
                   ISh  vN   [        U R                  5      n
SSS5      ISh  vN   W
S:  ad  X:  a   [        R                  " S	U
 S
U S35        Un	O+[        R                  " S	U
 SU S35        [        X-  U5      n	[        U UUS9I Sh  vN   O[        X-  U5      n	[        R                  " U	5      I Sh  vN   M   N N! , ISh  vN  (       d  f       N= f NQ N&! [         aK  n[        S[        U5      US9  [        X-  U5      n	[        R                  " U	5      I Sh  vN     SnANtSnAff = f7f)a&  
Background task that monitors the spend_log_transactions queue size
and triggers processing when the threshold is reached.

Args:
    prisma_client: Prisma client instance
    db_writer_client: Optional HTTP handler for external spend logs endpoint
    proxy_logging_obj: Proxy logging object
r   )SPEND_LOG_QUEUE_POLL_INTERVALSPEND_LOG_QUEUE_SIZE_THRESHOLDg      >@g      ?z.Starting spend logs queue monitor (threshold: z, poll_interval: zs)NzSpend logs queue size (z) reached threshold (z), triggering processingz) below threshold (z), processing with backoffr$  z%Error in spend logs queue monitor: %s)r   )litellm.constantsr6  r7  r4   ri  r  r}  r  rs   minr&  r  r
  ri  r"   ry   )r  r  r  r6  r7  	thresholdbase_intervalmax_backoffbackoff_multipliercurrent_intervalr'  rs  s               r{   _monitor_spend_logs_queuer?    s    
 /I1MK$
8CTUbTccef %	2$AAA !E!EF
 BA A~*(..1*=RS\R]]uv (5$(..1*=PQZP[[uv (+(={($ ,"/%5&7   $'$9;$  -- 0111C  BAAA& 2 	2CSVQRS"#3#H+V-- 0111		2s   1F D( DD( D
D( )D*A(D( D$,D( ?D& D( F D( D( 
D!DD!D( &D( (
E=2;E8-E0.E83F 8E==F rs  rV  c           	          SSK nS[        U 5       3nUS-   UR                  " 5       -   n[        R                  " 5       nXa-
  n[        R
                  " UR                  U USUS95        U e)z
Raise an exception for failed update spend logs

- Calls proxy_logging_obj.failure_handler to log the error
- Ensures error messages says "Non-Blocking"
r   NzC[Non-Blocking]LiteLLM Prisma Client Exception - update spend logs: rx  r(  r|  )rr   ry   ru   r  r  r  r  )rs  rV  r  rr   rD  rE  rW  rF  s           r{   r   r     s      NcRSfXV   $&)=)=)??Oyy{H%I)) $)	 	* 	
 Gr}   todayc                     U R                   S:X  a$  [        U R                  S-   SS5      [        SS9-
  $ [        U R                  U R                   S-   S5      [        SS9-
  $ )N   r   days)monthr   yearr   )rA  s    r{   _get_month_end_daterH    sT    {{bEJJNAq)I1,===

EKK!OQ/)2CCCr}   current_spendsoft_budget_limitc                     Uc  g[         R                  " 5       n[        U5      nX2-
  R                  nUR                  S:X  a  U nOXR                  S-
  -  nXU-  -   nXa:  a  [        S5        gg)NFr   z*Projected spend exceeds soft budget limit!T)r   rA  rH  rE  dayr|   )rI  rJ  rA  	end_monthremaining_daysdaily_spend_estimateprojected_spends          r{   _is_projected_spend_over_limitrQ    sz      JJLE $E*I'--N yyA~,,		A> $n'LMO*BCr}   c                 "   Uc  g [         R                  " 5       n[        U5      nX2-
  R                  nUR                  S:X  a  U nOXR                  S-
  -  nXU-  -   nXa:  a-  US::  a  UnXg4$ X-
  nUS::  a  UnXg4$ X-  n	U[        U	S9-   nXg4$ g )Nr   r   rD  )r   rA  rH  rE  rL  r   )
rI  rJ  rA  rM  rN  daily_spendrP  limit_exceed_dateremaining_budgetapprox_dayss
             r{   _get_projected_spend_over_limitrW  1  s      JJLE#E*I'--N yyA~##yy1}5#^'CDO*! % 11  1@1$$)! 11	 /<$)I;,G$G! 11r}   c           	          U b  Ub  Uc  g SU;   a0  UR                  S5      nUS   nXC;  a  [        SU  SU SU S35      eg )NmodelsrL  zInvalid model for team r{  z.  Valid models for team are: rx  )r  ri  )rQ  team_configr  valid_modelsmodel_in_requests        r{   _is_valid_team_configsr]  S  sk    +-1E;"x0'0/)'"5E4FFdeqdrrtu  r}   c                 :    [        U R                  5       S-  5      $ )Ng    eA)rh  r  )dts    r{   _to_nsr`  a  s    r||~#$$r}   r   c                     Uc  U $ U R                  S5      =(       d    0 nUR                  S5      =(       d    0 nUR                  SS5      nUc  U $ UR                  US9nUc  U $ UR                  R                  S5      nUc  U $ [        X5      $ )a1  
Check if the model has guardrails defined and merge them with existing guardrails in the request data.

Args:
    data: The request data dict
    llm_router: The LLM router instance to get deployment info from

Returns:
    Modified data dict with merged guardrails (if any model-level guardrails exist)
Nr  r8  r   )r;  r   )r&  get_deploymentr  _merge_guardrails_with_existing)r  r   r  r8  r;  
deploymentmodel_level_guardrailss          r{   r(  r(  e  s      xx
#)rHl+1rJ~~dD)H **H*=J'66::<H% +4HHr}   re  c                 $   U R                  5       nUR                  S0 5      nUR                  S/ 5      n[        U[        5      (       d  U(       a  U/O/ n[        U[        5      (       d  U(       a  U/O/ n[	        [        XA-   5      5      US'   U$ )z
Merge model-level guardrails with any existing guardrails in the request data.

Args:
    data: The request data dict
    model_level_guardrails: Guardrails defined at the model level

Returns:
    Modified data dict with merged guardrails in metadata
r  r   )r  r   r&  r   r   r  )r  re  rA  r  existing_guardrailss        r{   rc  rc    s     IIKM''
B7H",,|R8 )4007J23PR ,d33(>#$B 	
 "#&9&R"STH\r}   c                 
   Sn[        U [        5      (       a  [        U R                  [        5      (       a  U R                  nU$ [        U R                  [        5      (       a"  [
        R                  " U R                  5      nU$ [        U S5      (       aS  [        U SS 5      n[        U[        5      (       a  UnU$ [        U[        5      (       a  [
        R                  " U5      nU$ [        U 5      n U$ [        U 5      nU$ )Nre  r  )	r   r,   r   ry   r   ry  r  rA  r   )rs  rc  _errors      r{   get_error_message_strrj    s    M!]##ahh$$HHM  $'' JJqxx0M  Q	""Q	40F&#&& &  FD)) $

6 2
   FM  Ar}   c                      [         R                  " S5      =n (       a  U $ [        [         R                  " S5      5      SL a  gg)z
Get the Redoc URL from the environment variables.

- If REDOC_URL is set, return it.
- If NO_REDOC is True, return None.
- Otherwise, default to "/redoc".
	REDOC_URLNO_REDOCTNz/redocr   r   rh   )	redoc_urls    r{   _get_redoc_urlrp    s:     IIk**y*299Z()T1r}   c                      [         R                  " S5      =n (       a  U $ [        [         R                  " S5      5      SL a  gg)z
Get the docs (Swagger UI) URL from the environment variables.

- If DOCS_URL is set, return it.
- If NO_DOCS is True, return None.
- Otherwise, default to "/".
DOCS_URLNO_DOCSTNr
  rn  )docs_urls    r{   _get_docs_urlru    s9     99Z((x(299Y'(D0r}   c                      [         R                  " S5      =n (       a  U $ [        [         R                  " S5      5      SL a  gg)z
Get the OpenAPI JSON URL from the environment variables.

- If OPENAPI_URL is set, return it.
- If NO_OPENAPI is True, return None.
- Otherwise, default to "/openapi.json".
OPENAPI_URL
NO_OPENAPITNz/openapi.jsonrn  )openapi_urls    r{   _get_openapi_urlrz    s:     ii..{.299\*+t3r}   c           
         SSK Jn  [        R                  " SU  35        [	        U [
        5      (       aR  [        [        U SS[        U 5       S35      [        R                  [        U SS5      [        U S	UR                  5      S
9$ [	        U [        5      (       a  U $ [        U S	UR                  5      n[        [        U 5      [        R                  [        U SS5      US
9$ )z_
Returns an Exception as ProxyException, this ensures all exceptions are OpenAI API compatible
r   )r-   zException: r   zerror()paramNoner  )r  r   r}  code)fastapir-   r4   r  r   r,   r   r   ry   r   internal_server_errorHTTP_500_INTERNAL_SERVER_ERROR)rs  r-   _status_codes      r{   handle_exception_on_proxyr    s     ""[#45!]##Ax6#a&);< 66!Wf-M6+P+PQ	
 	
 
A~	&	&1mV-R-RSLA22a&)	 r}   featurec                     SSK Jn  U (       a!  SU  S[        R                  R                   3nOS[        R                  R                   3nU(       d  [        SSU0S9eg	)
z;
Raises an HTTPException if the user is not a premium user
r   )r   z=This feature is only available for LiteLLM Enterprise users: z. z=This feature is only available for LiteLLM Enterprise users. i  rm  r  N)r  r   r   not_premium_userr   r,   )r  r   
detail_msgs      r{   _premium_user_checkr  
  s~     8TU\T]]_`q  aC  aC  aI  aI  `J  K
TUfUwUwU}U}T~
Z(
 	
 r}   rL  c                 \    U b  Uc  gUR                  5       n[        U5      nSnX;   a  SnU$ )z<
Returns True if the model is in the llm_router model names
FT)get_model_namesr  )rL  r   model_namesmodel_names_set
is_in_lists        r{   is_known_modelr    s?     }
*,,.K+&OJ
r}   
index_namec                 h    [         R                  c  gU [         R                  R                  5       ;   $ )zR
Returns True if the vector store index is in the llm_router vector store indexes
F)rv   vector_store_index_registryget_vector_store_indexes)r  s    r{   is_known_vector_store_indexr  -  s-    
 **2<<UUWWWr}   	base_pathr  c                     U R                  S5      n UR                  S5      nU (       d  U(       a  SU 3$ S$ U(       d  U $ U R                  SU 35      (       a  U nU$ U  SU 3nU$ )Nr
  )rstriplstripr  )r  r  
final_paths      r{   
join_pathsr  7  s      %ILLE #5'{,,  AeW+&&

  "{!E7+
r}   request_base_urlc                     [        5       nUb  UnOU n[        5       nUb'  US:w  a  [        X45      n[        XQ5      $ [        X15      $ [        X45      $ )Nre  )get_proxy_base_urlget_server_root_pathr  )r  r  server_base_urlr  server_root_pathintermediate_urls         r{   get_custom_urlr  N  s^    (*O""#+-r!)(E.66h..(55r}   c                  .    [         R                  " S5      $ )z8
Get the proxy base url from the environment variables.
r  r  r   r}   r{   r  r  b  s     99%&&r}   c                  0    [         R                  " SS5      $ )z
Get the server root path from the environment variables.

- If SERVER_ROOT_PATH is set, return it.
- Otherwise, default to "/".
SERVER_ROOT_PATHre  r  r   r}   r{   r  r  i  s     99',,r}   c                     [        5       nU(       a.  US:w  a(  U R                  US-   5      (       a  U [        U5      S $ gU $ )zbStrip SERVER_ROOT_PATH prefix. Returns de-prefixed route, or None if route is not under root path.r
  N)r  r|  r}  )r  	root_paths     r{   normalize_route_for_root_pathr  s  sC    $&IY#%IO,,Y)**Lr}   r  c                 L    SSK Jn  Uc  [        [        R                  SU 0S9eU$ )Nr   r  rm  r  )r  r  r,   r-   r  )r  r  s     r{   get_prisma_client_or_throwr  }  s1    8==W%
 	
 r}   r   c                     SSK n[        U [        5      (       d  gS[        U 5      s=::  a  S::  a3  O  gUR	                  SU 5      (       a  gUR	                  SU 5      (       a  gg)	z
Validates API key format:
- sk- keys: must match ^sk-[A-Za-z0-9_-]+$
- hashed keys: must match ^[a-fA-F0-9]{64}$
- Length between 20 and 100 characters
r   NFr  r:  z^sk-[A-Za-z0-9_-]+$Tz^[a-fA-F0-9]{64}$)r  r   ry   r}  r  )r   r  s     r{   is_valid_api_keyr    s\     c3CH
 	 88*C0088(#..r}   c                  *   SSK n [        R                  " S5      n[        R                  " S5      n[        R                  " S5      n[        R                  " S5      n[        R                  " S5      nU(       a  U(       a  U(       a  U R                  R	                  U5      nU(       a  U R                  R	                  U5      OSnU R                  R	                  U5      nU(       a  S	U S
U SU SU 3n	OS	U SU SU 3n	U(       a  U	SU 3-  n	U	$ g)z
Construct a DATABASE_URL from individual environment variables.
Returns:
    Optional[str]: The constructed DATABASE_URL or None if required variables are missing
r   NDATABASE_HOSTDATABASE_USERNAMEDATABASE_PASSWORDDATABASE_NAMEr$  re  zpostgresql://:@r
  z?schema=)urllib.parser   r   parse
quote_plus)
urllibdatabase_hostdatabase_usernamedatabase_passworddatabase_namedatabase_schemadatabase_username_encdatabase_password_encdatabase_name_encr  s
             r{   $construct_database_url_from_env_varsr    s     IIo.M		"56		"56IIo.Mii 12O*} & 7 78I J:KFLL##$56QS 	 #LL33MB *+@*ACXBYYZ[hZiijk|j}~L*+@*A=/QRSdRefLh&788Lr}   r  rJ   r2   r  
user_modelrQ  include_model_access_groupsonly_model_access_groupsreturn_wildcard_routesr   rL   c                   #    SSK Jn  SSKJnJnJn  SSKJn  Uc  / n0 nO UR                  5       nUR                  5       nU" U UUUS9nU R                  nU(       aC  U(       a<  U(       a5  U
(       a.  / nU" UUU
US9I Sh  vN nU" U US9I Sh  vN   UR                  nU" UUUUS	9nU=(       d    U R                  nU" UUUUUR                  S
S5      U	UUUUUS9nU$  N_ NR7f)a  
Get the list of models available to a user based on their API key and team permissions.

Args:
    user_api_key_dict: User API key authentication object
    llm_router: LiteLLM router instance
    general_settings: General settings from config
    user_model: User-specific model
    prisma_client: Prisma client for database operations
    proxy_logging_obj: Proxy logging object
    team_id: Specific team ID to check (optional)
    include_model_access_groups: Whether to include model access groups
    only_model_access_groups: Whether to only return model access groups
    return_wildcard_routes: Whether to return wildcard routes

Returns:
    List of model names available to the user
r   )get_team_object)get_complete_model_listget_key_modelsget_team_models)validate_membershipN)r  proxy_model_listmodel_access_groupsr  )rQ  r  r   r  )r  
team_table)rv  r  r  r  infer_model_from_keysF)
key_modelsrv  r  r  r  r  r   r  r  r  rQ  )litellm.proxy.auth.auth_checksr  litellm.proxy.auth.model_checksr  r  r  1litellm.proxy.management_endpoints.team_endpointsr  r  get_model_access_groupsrv  rY  rQ  r&  )r  r   r  r  r  r  rQ  r  r  r  r   r  r  r  r  r  r  r  r  rv  team_objecteffective_team_id
all_modelss                          r{   get_available_models_for_userr    s<    > ? 
 V  %557(@@B  +)/$?	J /::K =%6;M
+'1/	
 
 "/K
 	
 	
 "((!)/$?	K  <#4#<#< )).223JER5/$?!9!J G
	
s%   A>C$ C C$C"AC$"C$r;  providerinclude_metadatafallback_typec                    SSK Jn  U S[        US.nUb_   UR                  U 5      nUbJ  UR                  b  [        UR                  5      US'   UR                  b  [        UR                  5      US'   U(       d  U$ Ub  UOS	n	/ S
Qn
X;  a  [        SSU
 3S9eU" U UU	S9n0 UESSU00E$ ! [         a$  n[
        R                  " SU U5        Sn SnANSnAff = f)a  
Create a standardized OpenAI-compatible model object.

When include_metadata is true, attaches the model's configured fallbacks
(resolved via the router under fallback_type, defaulting to "general").
Raises HTTPException(400) for an unknown fallback_type.
r   )get_all_fallbacksrL  )r   objectcreatedowned_byNzBcreate_model_info_response: get_model_group_info failed for %s: %smax_input_tokensmax_output_tokensgeneral)r  context_windowcontent_policyr  z'Invalid fallback_type. Must be one of: r  )rL  r   r  r  	fallbacks)r  r  r   get_model_group_infori  r4   rs   r  rh  r  r,   )r;  r  r  r  r   r  basemodel_group_infors  effective_fallback_typevalid_fallback_typesr  s               r{   create_model_info_responser  #  s%    B 0	D 	$)>>xH '00<+./?/P/P+Q'(11=,/0@0R0R,S()/</HmiJ:<=Q<RS
 	

 "-I
 :d9Ji 899=  	$ &&T
  $	$s   B, ,
C6CCavailable_modelsc                 N   SU ;   aw  U R                  S5       Vs/ s H  o"R                  5       PM     nnU Vs/ s H  o"U;  d  M
  UPM     nnU(       a(  [        SSR                  SR	                  U5      5      S9egX;  a  [        SSR                  U 5      S9egs  snf s  snf )a:  
Validate that a model is accessible to the user.
Supports batch requests with comma-separated model IDs.

Args:
    model_id: The model ID to validate (can be comma-separated for batch requests)
    available_models: List of models available to the user

Raises:
    HTTPException: If the model is not accessible
,i  z=The following model(s) do not exist or are not accessible: {}r   r  z2The model `{}` does not exist or is not accessibleN)r{  rz  r,   rt   r(  )r;  r  mrY  inaccessible_modelss        r{   validate_model_accessr  b  s      h%-^^C%89%8'')%89*0N&Q=M4Mq&NV]]II12   +KRR  , :Ns   B	B"B"))r  rK  )r  rJ  )deltarK  _PRESERVED_NONE_FIELDSobjpreserve_fieldsexclude_unsetc                 R   U R                  SUS9nUR                  S5      nU(       d  U$ U R                  n[        XT5       Ha  u  pg[         HR  u  pUR                  U5      n
U
c  M  X;  d  M"  [        XhS5      nUc  M3  [        X5      (       d  ME  [        X5      X'   MT     Mc     U$ )a  
Serialize a Pydantic model to a dictionary while preserving specific fields
even if they are None.

Fields listed in _PRESERVED_NONE_FIELDS are restored after
model_dump(exclude_none=True) strips them.

Args:
    obj: The Pydantic BaseModel instance to serialize
    preserve_fields: Deprecated, kept for backward compatibility.
    exclude_unset: Whether to exclude fields that were not explicitly set

Returns:
    Dictionary representation with None values excluded except for preserved fields
T)r  r  choicesN)r?  r&  r  zipr  r   rA  )r  r  r  r  r  obj_choices
choice_objchoice_dict
sub_object
field_namesub_dictsub_objs               r{    model_dump_with_preserved_fieldsr    s    ( ^^]^KFjj#G++K#&{#<
&<"J"z2H)!*$?&77+G+G+27+GH( '= $= Mr}   rf  r   )NNNFFFNr  r;  (  r  r  r  r   ry  r   r  r  r  r  r  rr   dataclassesr   r   r   r   r   r   email.mime.multipartr	   email.mime.textr
   typingr   r   r   r   r   r   r   r   r   r   r   r   r   rv   r   r8  r   r   r   litellm.proxy._typesr   r   r   r   r    r!   3litellm.proxy.spend_tracking.spend_log_error_loggerr"   r  r$   !litellm.types.proxy.model_listingr%   litellm.types.utilsr&   r'   >litellm_enterprise.enterprise_callbacks.send_emails.base_emailr(   @litellm_enterprise.enterprise_callbacks.send_emails.resend_emailr)   Blitellm_enterprise.enterprise_callbacks.send_emails.sendgrid_emailr*   >litellm_enterprise.enterprise_callbacks.send_emails.smtp_emailr+   ImportErrorra  r  r,   r-   litellm.litellm_core_utils*litellm.litellm_core_utils.litellm_loggingr.   r/   r0   r1   r2   litellm._loggingr3   r4   litellm._service_loggerr5   r6   litellm.caching.cachingr7   r8   litellm.caching.dual_cacher9   litellm.exceptionsr:   r;   %litellm.integrations.custom_guardrailr<   r=   *litellm.proxy.hooks.sensitive_data_routingr>   "litellm.integrations.custom_loggerr?   1litellm.integrations.SlackAlerting.slack_alertingr@   (litellm.integrations.SlackAlerting.utilsrA   rB   *litellm.litellm_core_utils.safe_json_dumpsrC   *litellm.litellm_core_utils.safe_json_loadsrD   &litellm.llms.custom_httpx.http_handlerrE   rF   rG   rH   rI   rJ   litellm.proxy.auth.route_checksrK   -litellm.proxy.common_utils.user_api_key_cacherL   litellm.proxy.db.create_viewsrM   rN   'litellm.proxy.db.db_spend_update_writerrO   "litellm.proxy.db.exception_handlerrP   rQ   litellm.proxy.db.log_db_metricsrR   litellm.proxy.db.prisma_clientrS   rT   'litellm.proxy.db.routing_prisma_wrapperrU   Llitellm.proxy.guardrails.guardrail_hooks.unified_guardrail.unified_guardrailrV   litellm.proxy.hooksrW   rX   'litellm.proxy.hooks.cache_control_checkrY   &litellm.proxy.hooks.max_budget_limiterrZ   ,litellm.proxy.hooks.parallel_request_limiterr[   /litellm.proxy.hooks.parallel_request_limiter_v3r\   $litellm.proxy.litellm_pre_call_utilsr]   -litellm.proxy.policy_engine.pipeline_executorr^   &litellm.repositories.budget_repositoryr_   &litellm.repositories.config_repositoryr`   'litellm.repositories.table_repositoriesra   rb   rc   rd   $litellm.repositories.team_repositoryre   $litellm.repositories.user_repositoryrf   2litellm.repositories.verification_token_repositoryrg   litellm.secret_managers.mainrh   )litellm.types.integrations.slack_alertingri   rh  rj   rk   rl   0litellm.types.proxy.policy_engine.pipeline_typesrm   rn   ro   opentelemetry.tracerp   _SpanrQ  r  r|   r   r   r   rh  r   r   r   BaseExceptionr   r   r   rl  r   rr  ru  r  ry   r  r  r&  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r~  r  r(  r-  r&  r?  ri  r   r   rH  rQ  r   rW  r]  r`  r(  rc  rj  rp  ru  rz  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r   r}   r{   <module>r:     s        	  
 
    ( 8 8 . $     @ 
  P 8 ? ; *  ! 1  B @ 9 = P < K T > A F C  8 I H ; I < L J J J C C  @ ? 5 I 
 U E1WDD )* H6d
 d
T 02 T#t)_ 1,< ,D ,8	8"%8	80 $G G G.A% A%NJJ

 
$ 
" 1GPT0U - U$& !))) c])\ ),JJNN;TB)  #  : C 9"+:6# i ' '0# 0# 0J# J$sCx. Js x
'; # 3 8C= "Qc Qd Q

 
$s) 
PT 
2{$ {$BJ3 y l *LC LD L8s 8s 8w|| 8 %)!F
SMF
c]F
 3-F
Rc <C <C <c 3 4 0Lc L>	 	 	\ \~*
*
/0*
 $*
Z,K,K#,K^>
>
/0>
 $>
BC2C2/0C2 $C2L#8D8Dt D D-5e_:-5e_e_D%#I
#I$V,#I	#IL$  PT <Y 3 ( "x} "(3- " ~ 4
# 
$(3- Xf5E $ "XC XD X# c c .6S 6# 6# 6('HSM '-c - #  # $ &"hsm "T /326!(-%*#(6:`'`"` ` 	`
 N+`  /` c]` "&` #` !` !!23` 
#Y`L ##'%)<:<:<: <: C=	<:
 "<: <:~""3i" 
"J1 U38_-  ,0%	%d3i(% % 
#s(^	%[J  OO	  
O s   +U; V ;VVV