
    Mibh                       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  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  S SKJr  S SKJrJr  S SKJrJ r J!r!J"r"J#r#J$r$  S S	K%J&r&  S S
K'J(r(J)r)   S SK*r*S SK,J-r-J.r.  S SKrS SK/rS SK0rS SKJ1r1J2r2J3r3J4r4J5r5  S SK6J7r7  S SK8J9r9J:r:  S SK;J<r<J=r=  S SK>J?r?  S SK@JArA  S SKBJCrC  S SKDJErE  S SKFJGrG  S SK0JHrH  S SKIJJrJ  S SKKJLrL  S SKMJNrN  S SKJOrOJPrPJQrQJRrRJSrS  S SKTJUrU  S SKVJWrWJXrX  S SKYJZrZ  S SK[J\r\  S SK]J^r^  S S K_J`r`  S S!KaJbrbJcrc  S S"KdJere  S S#KfJgrg  S S$KhJiri  S S%KjJkrk  S S&KlJmrm  S S'KnJoro  S S(KpJqrqJrrrJsrs  S S)K'JtrtJuru  \(       a  S S*KvJwrx  S SK0JHry  \\x\4   rwO\rw\`" 5       rzS+ r{ " S, S-5      r| " S. S/5      r}S0 r~S1\S2\4S3 jr " S4 S55      rS6\S7\<S8\4S9 jr   SS:\\   S;\\   S<\\   4S= jjrS>\4S? jrS>\S2\4S@ jr " SA SB5      rSC\SD\\N   SE\}4SF jrSG\SH\SE\}4SI jrSJ\SK\\   4SL jrSJ\SK\\   S2\\   4SM jrSSN jrSO rS1\SP\\5   S2\4SQ jrS1\SR\S2\4SS jrSG\S2\4ST jrS2\\   4SU jrS2\\   4SV jrSG\S2\"4SW jrSSX\\   4SY jjrSZ\\   SP\\5   S2\4S[ jrS\\S2\4S] jrS^\S_\S2\4S` jrSSa\S_\\   S2\4Sb jjrS2\\   4Sc jrS2\4Sd jrSe\4Sf jrSg\S2\4Sh jrS2\\   4Si jr SSj\Sk\\\\\4         Sl\\\\4      S2\\\\4      4Sm jjr       SSnSoSP\Sp   Sq\Sr\\   SC\S5   SE\S/   Ss\\   St\Su\Sv\Sw\Sx   S2\\   4Sy jjr   SSz\S{\S|\S}\\   SP\Sp   S2\4S~ jjrSz\S\\   S2S4S jrg! \+ a	    \+" S5      ef = f)    N)datetime	timedelta)MIMEMultipart)MIMEText)	TYPE_CHECKINGAnyDictListLiteralOptionalUnioncastoverload)+_custom_logger_compatible_callbacks_literal)DEFAULT_MODEL_CREATED_AT_TIMEMAX_TEAM_LIST_LIMIT)DB_CONNECTION_ERROR_TYPESCommonProxyErrorsProxyErrorTypesProxyExceptionSpendLogsMetadataSpendLogsPayloadGuardrailEventHooks)	CallTypesCallTypesLiteralzEbackoff is not installed. Please install it via 'pip install backoff')HTTPExceptionstatus)EmbeddingResponseImageResponseModelResponseModelResponseStreamRouter)verbose_proxy_logger)ServiceLoggingServiceTypes)	DualCache
RedisCache)RejectedRequestError)CustomGuardrail)CustomLogger)SlackAlerting)_add_langfuse_trace_id_to_alert)Logging)
safe_dumps)safe_json_loads)HTTPHandler)	AlertTypeCallInfoLiteLLM_VerificationTokenViewMemberUserAPIKeyAuth)RouteChecks)create_missing_viewsshould_create_missing_views)DBSpendUpdateWriter)log_db_metrics)PrismaWrapper)UnifiedLLMGuardrails)PROXY_HOOKSget_proxy_hook)_PROXY_CacheControlCheck)_PROXY_MaxBudgetLimiter)!_PROXY_MaxParallelRequestsHandler)LiteLLMProxyRequestSetup)str_to_bool)DEFAULT_ALERT_TYPES)MCPDuringCallResponseObjectMCPPreCallRequestObjectMCPPreCallResponseObject)LLMResponseTypesLoggedLiteLLMParams)Spanc                     SSK n[        R                  " SR                  XR                  " 5       5      5        [
        R                  (       a  [        SU  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: )	tracebackr$   debugformat
format_exclitellmset_verboseprint)print_statementrM   s     m/var/www/eduai.edurigo.com/storigo/production/storigo_env/lib/python3.13/site-packages/litellm/proxy/utils.pyprint_verboserV   t   sE     x@T@T@VWX012     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     rU   __init__InternalUsageCache.__init__   s    %/rW   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)keyrc   parent_otel_span )r[   async_get_cache)r_   rf   rb   rc   kwargss        rU   ri   "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)rf   valuerc   rb   rh   )r[   async_set_cacher_   rf   rn   rb   rc   rj   s         rU   ro   "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)rs   rc   rb   rh   )r[   async_set_cache_pipeline)r_   rs   rb   rc   rj   s        rU   async_batch_set_cache(InternalUsageCache.async_batch_set_cache   s@      __== 
!!%=
 	
 
 	
 
rl   keysrg   c                 T   #    U R                   R                  UUUS9I S h  vN $  N7f)N)rx   rg   rc   )r[   async_batch_get_cache)r_   rx   rg   rc   s       rU   rz   (InternalUsageCache.async_batch_get_cache   s6      __::-! ; 
 
 	
 
s   (&(rn   c                 `   #    U R                   R                  " SUUUUS.UD6I S h  vN $  N7f)N)rf   rn   rc   rg   rh   )r[   async_increment_cacherp   s         rU   r}   (InternalUsageCache.async_increment_cache   sC      __:: 
!5	

 
 
 	
 
rr   c                 B    U R                   R                  " SUUUS.UD6$ )N)rf   rn   rc   rh   )r[   	set_cache)r_   rf   rn   rc   rj   s        rU   r   InternalUsageCache.set_cache   s3     (( 
!
 	
 	
rW   c                 @    U R                   R                  " SUUS.UD6$ )N)rf   rc   rh   )r[   	get_cache)r_   rf   rc   rj   s       rU   r   InternalUsageCache.get_cache   s0     (( 
!
 
 	
rW   r^   F)NF)__name__
__module____qualname____firstlineno__r'   r`   r   rK   boolr   ri   ro   r
   rv   listr   rz   floatr}   r   r   __static_attributes__rh   rW   rU   rY   rY      sH   09 0 !	
 #(d
"3
 	
 

& !
 #(d
"3	

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

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

 


 

rW   rY   c                      \ rS rSrSr SUS\S\4S jjrS\\	   S\\
   4S jr      SVS
\\   S\\   S\\
   S\\\      S\\   S\\   4S jjrSWS\\	   4S jjrS\S\\   4S jrSWS\\	   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%S/ r&S0\'S1\S2\\(   S3\)S\\   4
S4 jr*\+S2\(S1S	S3\)SS	4S5 j5       r,\+S2\(S1\S3\)S\4S6 j5       r,S2\(S1\\   S3\)S\\   4S7 jr,S1\S2\\(   S3\)4S8 jr-S9\S:\4S; jr.S<\S=   S>\/4S? jr0 SWS@\SA\SB   SC\SD\\   4SE jjr1 SXSF\S3\4SG jjr2   SYSD\SH\3S2\(SI\\4   SJ\\   SK\\   4SL jjr5  SZSH\3SI\\4   SJ\\   S\4SM jjr6  SZSD\S2\(SJ\\   SH\\3   4SN jjr7S1\S'\8S2\(4SO jr9 SWS1\S'\:\;\<\=\>4   S2\(SP\\   4SQ jjr?S2\(SD\4SR jr@SWS1\\   4SS jjrASTrBg	)[ProxyLogging   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        X l        ['        5       U l        [+        5       U l        0 U l        SU l        SU l        g )Nr      )default_in_memory_ttlr^   i,  )alerting_thresholdalertinginternal_usage_cacheF)call_detailsrY   r'   r   rB   max_parallel_request_limiterrA   max_budget_limiterr@   cache_control_checkr   r   rE   alert_typesalert_to_webhook_urlr,   r[   slack_alerting_instancer   r%   service_logging_objr:   db_spend_update_writerproxy_hook_mappingdaily_report_startedhanging_requests_check_started)r_   r   r   s      rU   r`   ProxyLogging.__init__   s     #%2D./8J q99
! -N%%-
) #:";#;#= (,),,?48!6C#66]]!%!:!:!E!E7
$
 )#1#3 &9&;#;= +0!49+rW   
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_reportr2   llm_requests_hangingr   hanging_request_checkcheck_for_hanging_requests)r_   r   r   s      rU   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 5rW   Nr   r   r   r   alerting_argsr   c                    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SL a  U R                  R                  U R                   U R                  U R                  UU R                  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   slackr   outage_alertsregion_outage_alerts)r   r   r   r   r   r   rQ   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   updated_slack_alertings           rU   r   ProxyLogging.update_values?  sZ    (-$M%)")&8#%)""*%)"+(<%%)"!T)((66#'#:#: ,,+%)%>%> 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 #rW   c           	      F   SSK Jn  [         H  n[        U5      nSSKnU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        XR                  U'   M     g)z&
Add proxy hooks to litellm.callbacks
r   prisma_clientNr   r   rh   )litellm.proxy.proxy_serverr   r>   r?   inspectgetfullargspecargsr   r   r+   rQ   r   r   r   )	r_   r   r   hook
proxy_hookr   expected_argspassed_in_argsproxy_hook_objs	            rU   _add_proxy_hooksProxyLogging._add_proxy_hooksq  s     	=D'-J#22:>CCM-/N%69=9R9R56-/2?/!,
0L^0LMN,,AA.Q,:##D)  rW   r   rd   c                 8    U R                   R                  U5      $ )z.
Get a proxy hook from the proxy_hook_mapping
)r   get)r_   r   s     rU   r?   ProxyLogging.get_proxy_hook  s     &&**400rW   c                 d   U R                  U5        [        R                  R                  U R                  5        [        R
                   GH  n[        U[        5      (       aP  [        R                  R                  R                  [        [        U5      U R                  R                  US9nUc  Mi  U[        R                  ;  a  [        R                  R!                  U5        U[        R"                  ;  a  [        R                  R%                  U5        U[        R&                  ;  a  [        R                  R)                  U5        U[        R*                  ;  a  [        R                  R-                  U5        U[        R.                  ;  a  [        R                  R1                  U5        U[        R2                  ;  d  GM  [        R2                  R!                  U5        GM     [5        [        R                  5      S:  d:  [5        [        R"                  5      S:  d  [5        [        R&                  5      S:  al  [7        [9        [        R                  [        R"                  -   [        R&                  -   5      5      n[        R                  R                  R;                  US9  g g )N)r   r   r   )callback_list)r   rQ   r   r   r   	callbacks
isinstancestrlitellm_core_utilslitellm_logging$_init_custom_logger_compatible_classr   r   r   r[   input_callbackappendsuccess_callbackr   failure_callbackadd_litellm_failure_callback_async_success_callback"add_litellm_async_success_callback_async_failure_callback"add_litellm_async_failure_callbackservice_callbacklenr   setset_callbacks)r_   r   callbackr   s       rU   r   $ProxyLogging._init_litellm_callbacks  s   j)((==d>V>VW))H(C(("55EEjjDhO)-)B)B)M)M) k 
 #w555&&--h7w77700MMhWw77700MMhWw>>>00SST\]w>>>00SST\]w777((//9) *. &&'!+7++,q07++,q0 **../../M &&66DD+ E  1rW   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)rf   rn   rc   ttlrb   )r   r   r   ro   rO   )r_   r   r   r   s       rU   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     rU   "_convert_user_api_key_auth_to_dict/ProxyLogging._convert_user_api_key_auth_to_dict  sF    
 !,,l;;,7799.
;;,555	rW   rj   c           
      P   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                  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)	messagesr  r  r  r  r  r  mcp_tool_namemcp_arguments)litellm.types.llms.openair   	tool_name	argumentsr   )r_   request_objrj   r   tool_call_contentsynthetic_messagesynthetic_datas          rU   _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

 rW   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   )rH   FN)should_proceederror_messagemodified_argumentsr  r   r   r    blocked	violationzContent blocked by guardrailTz<Could not parse modified arguments from guardrail response: z"Error parsing modified arguments: )litellm.types.mcprH   r   	Exceptionr   dictr   r  r  lower(_extract_modified_arguments_from_contentr$   warningerror)	r_   
llm_resultr  rH   modified_messagesoriginal_contentnew_contentmodified_argses	            rU   #_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: )jsonr$   rN   stripsplit	enumerate
startswithr   loadsJSONDecodeError_parse_arguments_manuallyr  r  r  r   )
r_   r)  r  r,  linesiline	args_textr%  r&  s
             rU   r  5ProxyLogging._extract_modified_arguments_from_contentE  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'r7  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copyitemsr   r   escapesearch
IGNORECASEgroupr-  r  r$   r   )r_   r7  r9  r;  r%  rf   original_valuepatternmatch	new_valuer&  s              rU   r3  &ProxyLogging._parse_arguments_manuallyv  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_continuer  r  r   r   r   r   r  r  z-Content blocked by guardrail during executionz.Content modified by guardrail during executionN)	r   r  rF   r   r  r   r  r  r  )r_   r!  r  r"  r#  r$  s         rU   *_convert_llm_result_to_mcp_during_response7ProxyLogging._convert_llm_result_to_mcp_during_response  s     j),,. %S_ 
 j$'' *z :  [223=AVAV@WX ! @Q%a(,,Y;VX  2&){7H7H7J*J:,1*Y    ;,1*Z   j#&&. %Z  rW   dynamic_success_callbacksglobal_callbacksc                 8    Uc  U$ [        [        X-   5      5      $ r]   )r   r   )r_   rK  rL  s      rU   get_combined_callback_list'ProxyLogging.get_combined_callback_list  s$     %,##C1DEFFrW   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
)r  r  r  hidden_params)r  r  r  r  rS  )r_   rP  rQ  results       rU   !_parse_pre_mcp_call_hook_response.ProxyLogging._parse_pre_mcp_call_hook_response  sD     '55"*"="= #*))%33%33
 rW   rG   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)rG   user_api_key_authnamer  r  server_name)r  r  r[  rY  rS  )litellm.types.llms.baserX  r  rG   r   r   )r_   rj   rX  rG   user_api_key_auth_dicts        rU   &_create_mcp_request_object_from_kwargs3ProxyLogging._create_mcp_request_object_from_kwargs  sg     	9=!%!H!HJJ*+"
 'jj,jjb1

=14&.
 	
rW   response_dataoriginal_kwargsc                 t    U(       d  U$ UR                  5       nUR                  S5      (       a  US   US'   U$ )zQ
Helper function to convert pre_call_hook response back to kwargs for MCP usage.
r  r  )r<  r   )r_   r`  ra  modified_kwargss       rU   $_convert_mcp_hook_response_to_kwargs1ProxyLogging._convert_mcp_hook_response_to_kwargs  sG     "" *..0 122+89M+NOK(rW   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_completionr  r  )messager  llm_providerrequest_data  r   status_codedetail)r   r  r  r   r)   r   r   )r_   rP  data	call_types       rU   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   rp  user_api_key_dictrq  c                   #    SSK Jn  UR                  nUS:X  a  UR                  nUR	                  X&S9SLa  gS[        U5      R                  ;   a0  XS'   [        R                  UU R                  S	   UUS
9I Sh  vN nO'UR                  UU R                  S	   UUS
9I Sh  vN nUb  U R                  XrUS9I Sh  vN nU$  NI N# N
7f)a`  
Process a guardrail callback during pre-call hook.

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   r   mcp_callrp  
event_typeTNapply_guardrailguardrail_to_applyr   rt  cacherp  rq  rP  rp  rq  )litellm.types.guardrailsr   pre_callpre_mcp_callshould_run_guardrailtyper   unified_guardrailasync_pre_call_hookr   rr  )r_   r   rp  rt  rq  r   rx  rP  s           rU   _process_guardrail_callback(ProxyLogging._process_guardrail_callback  s    & 	A )11

",99J ((d(JRVV X 7 77)1%&.BB"3''(<=#	 C  H &99"3''(<=#	 :  H <<!	 =  D +s6   A;C=C>'C%C	&C CC	CCc                    #    g 7fr]   rh   r_   rt  rp  rq  s       rU   pre_call_hookProxyLogging.pre_call_hookT  
      	   c                    #    g 7fr]   rh   r  s       rU   r  r  ]  r  r  c                   #    SSK Jn  [        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b  Ub  US	:X  d  US
:X  a  SSKJ	n  UR                  U5      nUR                  U5      n	Sn
U	b  U	R                  R                  n
U(       a  U
b  UR                  UR                  SS5      UR                  S/ 5      U" US9U
UUR                  SS5      UR                  SS5      UR                  SS5      S9u  nnnUR                  U5        XS'   XS'    [         R"                   GH  n[$        R$                  " 5       nSn['        U[(        5      (       a8  [         R*                  R,                  R/                  [        [0        U5      5      nOUnUb:  ['        U[2        5      (       a%  Ub"  U R5                  UUUUS9I Sh  vN nUc  M  UnOUb  ['        U[6        5      (       a  S[9        UR:                  5      ;   av  UR:                  R<                  [6        R<                  :w  aN  US:X  a  Uc  GM  UR=                  UU R>                  S   UUS9I Sh  vN nUb  U RA                  UX#S9I Sh  vN n[$        R$                  " 5       nUU-
  n[C        U S5      (       d  GM|  US:  d  GM  U RD                  RG                  [H        RJ                  UUR:                  RL                   URN                  UUS9I Sh  vN   GM     U$  GNE N N N! [P         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
r   )!get_non_default_completion_paramsz#Inside Proxy Logging Pre-call hook!rp  NLiteLLMLoggingObjlitellm_logging_obj	prompt_idrg  acompletion)IN_MEMORY_PROMPT_REGISTRYr  r  r  )rj   prompt_variablesprompt_labelprompt_version)r  r  non_default_paramsr  prompt_management_loggerr  r  r  )r   rp  rt  rq  r  rv  r   r{  r}  r   g{Gz?)servicedurationrq  rg   
start_timeend_time))litellm.utilsr  r$   rN   #_init_response_taking_too_long_taskr   r   r   %litellm.proxy.prompts.prompt_registryr  get_prompt_callback_by_idget_prompt_by_idlitellm_paramsr  get_chat_completion_promptupdaterQ   r   timer   r   r   r   "get_custom_logger_compatible_classr   r*   r  r+   vars	__class__r  r   rr  r   r   async_service_success_hookr&   PROXY_PRE_CALLr   rg   r  )r_   rt  rp  rq  r  r  r  r  custom_loggerprompt_speclitellm_prompt_idr  r  optional_paramsr   r  	_callbackrT  rP  r  r  r&  s                         rU   r  r  f  s}     	D""#HI00d0;<"()4884I4+P
 HH[$/	  +%l*i=.HW5OOM 4DDYOK/3&$/$>$>$H$H!!2!>
 (BB((7B/!XXj"5'HPT'U/-:%)XX.@$%G!%.$!?#'88,<d#C C 		# O, %W#+Z =	#--!YY[
 	h,, ' : : J J m mH(S!I !)I)"9o>>(#'#C#C!*!*;"+	 $D $ F ~ !D )"9l;;-i6I6I1JJ!++??#778 !J.3D3L %.%B%B*;"//0DE!"+	 &C &  H  +%)%H%H%-D &I &    99;#j0D"788X_22MM , ; ;!)%.%8%8%A%A$B):)K)K#-!) N   e .t KY(    	G	s   EMB*M 8L=9BM M M 'M(-M M #AM 1M2
M <M=M  M M M 
MMMMc           	      *  #    / n[         R                   H  n[        U[        5      (       d  M  UR                  c$  [        US5      (       a  UR                  S:X  a    gO8SSKJn  UR                  nUS:X  a  UR                  nUR                  XS9SLa  M  US:X  a  U R                  U5      nOUnUR                  UR                  UUUS	95        M     U(       a   [        R                   " U6 I Sh  vN   U$ U$  N! ["         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   rv  rw  T)rp  rt  rq  )rQ   r   r   r*   
event_hookr   r  r~  r   during_callduring_mcp_callr  r   r   async_moderation_hookr   gatherr  )
r_   rp  rt  rq  guardrail_tasksr   r   rx  r]  r&  s
             rU   during_call_hookProxyLogging.during_call_hook  s>     ))H(O44 &&.704 4  00J> ? M!4!@!@J J.%8%H%H
 !55!% 6   $$
 !
*??@QR + .?*  &&22!*@"+ 3 I *Z nno666
 t 7 sA   )DB.DC? 4C=5C? 9D=C? ?
D	DDDr  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)r  r  )r   r   failed_tracking_alert)r_   r  r  s      rU   r  "ProxyLogging.failed_tracking_alert'  sQ     
 == ''..DD++ E    (s   =AA Ar  )token_budgetuser_budgetsoft_budgetteam_budgetproxy_budgetprojected_limit_exceeded	user_infoc                 p   #    U R                   c  g U R                  R                  UUS9I S h  vN   g  N7f)N)r  r  )r   r   budget_alerts)r_   r  r  s      rU   r  ProxyLogging.budget_alerts5  s=      == **88 9 
 	
 	
s   ,646ri  level)LowMediumHigh
alert_typerk  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: ``rk  u   🪢 Langfuse Traceu   

🪢 Langfuse Trace: {}metadataalerting_metadatar   )ri  r  r  r  r  sentryz#Missing SENTRY_DSN from environmentrh   )r   r   nowstrftimeosgetenvr-   rO   r   r   r  r   
send_alertrQ   utilssentry_sdk_instancecapture_messager  )r_   ri  r  r  rk  r   current_time_proxy_base_urlformatted_messageextra_kwargsr  _urlclients                rU   alerting_handlerProxyLogging.alerting_handlerI  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r  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[        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  ri  r  r  rk  r   )r  r  r   rq  )r   )r2   db_exceptionsr   r   r   ro  r   r  r,  dumpsr   r   r  r   r   async_service_failure_hookr&   DBrQ   r  capture_exception)r_   original_exceptionr  rq  traceback_strr  s         rU   failure_handlerProxyLogging.failure_handler  sS     ""$*:*::(-88,33S99 2 9 9.55t<< $

+=+D+D E #$6 7 23MmS))5D11M!!5m_E$22	 " 	
 4.//**EE$!##	 F    ==**MM++2D+E +s   E	FFAFr  
error_typerouter  c           
        #    U R                  UR                  SS5      SS9I Sh  vN   [        R                  U R                  ;   am  [        U[        5      (       dX   [        USS5      n[        U5      nUb  X-  n[        R                  " U R                  SU S3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   [        R                    H  n	 Sn
[        U	[        5      (       a8  [        R"                  R$                  R'                  [)        [*        U	5      5      n
OU	n
U
b?  [        U
[,        5      (       a(  [        R                  " U
R/                  UUUUS95        M  M  M     g GNv N! [0         a$  n[2        R4                  " SU 35         SnAM  SnAff = f7f)aj  
Allows users to raise custom exceptions/log when a call fails, without having to deal with parsing Request body.

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
r   r  r   )r   r   Nlitellm_debug_infozLLM API call failed: `r  r  r  )r  r  r  )rk  rt  r  r  )rk  rt  r  r  z0[Non-Blocking] Error in post_call_failure_hook: )r   r   r2   llm_exceptionsr   r   r   getattrr   r   r   r  _is_proxy_only_llm_api_errorrequest_route _handle_logging_proxy_only_errorrQ   r   r   r   r  r   r   r+   async_post_call_failure_hookr  r$   	exception)r_   rk  r  rt  r  r  r  r  exception_strr   r  r&  s               rU   post_call_failure_hook#ProxyLogging.post_call_failure_hook  s    6 (((,,->CF ) 
 	
 	
 ##t'7'77
A
 A

 "));=QSW!X 23M!-3%%4]O1E (77!-	 &  ,,1!#11 - 

 77)"3#5	 8     ))H48	h,, ' : : J J m mH(S!I !)I(Z	<-P-P''!>>)5.?/A*7	 ?  .Q( *, 	y	
>2  $..FqcJ sM   $GFCG+F,GBF!
GG!
G+G
G
GGc                     Uc  g[         R                  " U5      SLa  g[        U[        5      =(       d    U[        R
                  :H  $ )z
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)
FT)r7   is_llm_api_router   r   r   
auth_error)r_   r  r  r  s       rU   r  )ProxyLogging._is_proxy_only_llm_api_error  sE    . =''.d:,m< 
/444	
rW   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
:w  d  M  US:w  d  M   XU'   M&     UR%                  UR                  S
S5      UR                  SS5      U	U
S9  SnSU;   aK  ['        US   [(        5      (       a3  US   nXR*                  S'   [,        R.                  R0                  Ul        OSU;   aK  ['        US   [        5      (       a3  US   nXR*                  S'   [,        R4                  R0                  Ul        OPSU;   aJ  ['        US   [(        5      (       a2  US   nXR*                  S'   [,        R6                  R0                  Ul        UR9                  USS9  UR;                  U[<        R>                  " 5       S9I Sh  vN   [@        RB                  " URD                  U[<        R>                  " 5       4S9RG                  5         gg NH7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   )uuidr   )rt  IGNORE_THIS)original_function	rules_objr  r  r  r   r  )r  r   r  r  r  promptinput)r
  api_key)r  traceback_exception)targetr   rh   )$r   litellm._uuidr  r   uuid4rC   'get_sanitized_user_information_from_keyrQ   r  function_setupRulesr   r  r  rJ   __annotations__rx   r=  update_environment_variablesr   r   model_call_detailsr   r  rn   rq  atext_completion
aembeddingr  async_failure_handlerrM   rP   	threadingThreadr  start)r_   rk  rt  r  r  r  r  user_api_key_logged_metadatarp  _optional_params_litellm_paramslitellm_param_keyskvr
  s                  rU   r  -ProxyLogging._handle_logging_proxy_only_error-  s     2>1A1A!42
 &*.1$**,.?L*+(PP&7 ) )0(D(D )"'"8=!----/#<<>) 	)% -+-Z($++,HI*! O!4!D!D!I!I!K$**,*)*A&'\a6k*+Q'	 -  <<"&&w3!%%fb1 0.	 =  -/E\)jZ($/ / %Z0EJ66zB090E0E0K0K#-\)jh9OQT.U.U$X.CH66x@090J0J0P0P#-L(ZW8Mt-T-T$W-BG66w?090D0D0J0J#-(( )  &;;,$-$8$8$: <   
 *::&((* egg +Ps    DKK!E$KKA	Kc                   #    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     U Hv  nUR                  XR                  S9SLa  M!  S[        U5      R                   ;   a#  XqS'   ["        R%                  UUUS9I Sh  vN nM]  UR%                  UUUS9I Sh  vN nMx     U H  nUR%                  X1US9I Sh  vN   M     U$  NF N- N! [&         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   Nrw  Try  rz  )rt  rp  rP  )r~  r   rQ   r   r   r   r   r   r  r   r   r*   r   r  	post_callr  r   r  async_post_call_success_hookr  )
r_   rp  rP  rt  r   guardrail_callbacksother_callbacksr   r  r&  s
             rU   post_call_success_hook#ProxyLogging.post_call_success_hook  s     	A57.02	#--48	h,, ' : : J J m mH(S!I !)I(!)_==+229='..y9 ." 0 11!.K.K 2    
 $X(?(??19-.%6%S%S*;!!) &T &  H &.%J%J*;!!) &K &  H' 06 ,;;&7X <    , )    	G	sf   E-A%E 7BE EE 'E( E E	E E-E E E 
E*#E%%E**E-
str_so_farc                   #    SSK Jn  Sn[        U[        [        45      (       a  [
        R                  " US9nUGb   [
        R                   GH  n Sn[        U[        5      (       a.  SSK	J
n	  [        XS9n
UR                  U
U	R                  S9SLa  MJ  [        U[        5      (       a8  [
        R                  R                   R#                  [%        [&        U5      5      nOUnUbo  [        U[(        5      (       aW  Ub  XF-   nOUnUR+                  UUS	9I Sh  vN n[        U[        5      (       a  UR-                  S
5      (       a  Us  $ GM  GM  GM  GM     U$  NC! [.         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_objr   )rp  r   rw  T)rt  rP  zdata: )r   r   r   r!   r"   rQ   get_response_stringr   r*   r~  r   '_check_and_merge_model_level_guardrailsr  r$  r   r   r   r  r   r   r+   async_post_call_streaming_hookr0  r  )r_   rp  rP  rt  r*  r   response_strr   r  r   modified_datacomplete_responsepotential_error_responser&  s                 rU   r/  +ProxyLogging.async_post_call_streaming_hook  s     	:&*h0C DEE"66HML##--)8<I!(O<<P )P!%)
 %99%2+>+H+H :  $(	( %!(C00$+$>$>$N$N$q$q !LhW%	 %-	 ,I|1T1T%10:0I-0<-"+"J"J2C): #K #  1 &4c 6AA(KK#;; L 2U,5 .V  ! GsJ   AE6AE"E6BE"E 0E"E6 E""
E3,E..E33E6c                    [         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[        R                  S9(       d  M  UR                  UUUS9nM     U$ )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
Nrw  )rt  rP  rk  )rQ   r   r   r   r   r   r  r   r   r+   r*   r  r   r$  'async_post_call_streaming_iterator_hook)r_   rP  rt  rk  r   r  s         rU   r6  4ProxyLogging.async_post_call_streaming_iterator_hook  s      ))H04I(C((#66FFiiDhO	 %	$I|)L)L! 33%2E2O2O 4    )PP*;!)%1  Q  H *& rW   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_   rp  s     rU   r  0ProxyLogging._init_response_taking_too_long_task1  sP     ((,,55A,,EESWEX B )rW   )r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   )NNNNNNr]   )r  NNN)NN)Cr   r   r   r   __doc__r'   r   r`   r   r#   r(   r   r
   r   r2   r  r   r   r   r+   r?   r   r   r   r   r  r   r'  r  r3  rI  rN  rH   rG   r	   rU  r^  rd  rr  r*   r6   r   r  r   r  r  r  r3   r  r  r  r  r   r  r  r  rI   r(  r   r!   r   r    r"   r/  r6  r  r   rh   rW   rU   r   r      sG    # :% :  :D'7V$'7 $J/'7V $(.2,015(,/30S4.0S %UO0S j)	0S
 d9o.0S  ~0S 'tn0Sd;8F+; ;*13 18L+A 1'(62B 'R
"
,34E,F
,d t <L	#L\/!/	$/b-1	$B-	#-^G)1$GKOG	G* 2 
c3h	*

	"
*%d^>B	$"7!7 7 $N3	7
 $7 
$7t )  $	
 
  )  $	
 
 })} tn} $	}
 
$}~@@ $N3@ $	@D 
(

 
2 (,?K?K ./?K 	?K
 tn?KD RT(F,1(F>A(F^ 15#'+WW &W *	W
 _-W }W  }Wx 15#	
%
 _-
 }	

 

H  $26VV *V }	V
 %Y/VpFF #F *	F^ %)@@ ,m=PP
@ *@ SM@D  *  	 D  rW   r   c                 &    [        SU S    35        g )Nz!Backing off... this was attempt #tries)rV   )detailss    rU   
on_backoffr@  F  s    5gg6F5GHIrW   rp  rd   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  r,  r  r  )rp  db_datar   r!  s       rU   jsonify_objectrF  K  sb    mmD!Ga8!ZZ]
   N  87
8   A""A43A4c            #       
   \ rS rSr% / r\\S'    SMS\S\S\	\
   4S jjrS\\\4   S	\S
   4S jrS\4S jrS\S	\4S jr\R(                  " \R*                  \SS\S9S 5       r\\R(                  " \R*                  \SS\S9S\S\
S\S   4S j5       5       r\R(                  " \R*                  \SS\S9\               SNS\	\\\4      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 \R(                  " \R*                  \SS\S9S\S\S,   4S- j5       r!\R(                  " \R*                  \SS\S9S0 SSSS.SSS4	S\	\   S\S/\	\   S\	\   S\	\   S!\S0   S\	\S1      S2\	\   S3\	\   4S4 jj5       r"\R(                  " \R*                  \SS\S9    SOS5\	\   S\	\   S\	\S6      S\	\   4S7 jj5       r#\R(                  " \R*                  \SS\S9S8 5       r$\R(                  " \R*                  \SS\S9S9 5       r%\R(                  " \R*                  \SS\S9S: 5       r&S	\4S; jr'\R(                  " \R*                  \SS\S9SPS< j5       r(S=\	\)   S	\	\)   4S> jr*S?\	\   S	\	\   4S@ jr+       SQSA\SB\SC\SD\SE\	\   S=\	\)   S?\	\   SF\	\   SG\	\   4SH jjr,    SRSA\	\   S&\S%\SI\	\   4SJ jjr-SK r.SLr/g)SPrismaClientiX  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b-  [        U" US	9U R                  b  U R                  OS
S9U l        O-[        U" 5       U R                  b  U R                  OS
S9U l        [
        R                  " S5        g ! [         aU  n[
        R                  " SU 35        [
        R                  " S5        [
        R                  " S5        [        S5      eS nAff = f)N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.)httpF)original_prismaiam_token_db_authzSuccess - Created Prisma Client)rL  rD   r  r  rS  r$   rN   prismarP  r  r   r<   db)r_   rK  rL  rM  rP  r&  s         rU   r`   PrismaClient.__init__[  s    "31<II)*2
 	""#=>	% "# &K 8 --9 **DG $ & --9 **DG 	""#DE;  
	 &&)I!'MN &&K !&&M U 
	s   B< <
DADDpayloadrd   )r   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   rX  r   )	r   r   r   r   r	   r,  r1  r2  AttributeError)r_   rW  payload_metadatapayload_metadata_jsons       rU   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tokenc                 j    [         R                  " UR                  5       5      R                  5       nU$ r]   hashlibsha256encode	hexdigest)r_   r_  hashed_tokens      rU   
hash_tokenPrismaClient.hash_token  s%    ~~elln5??ArW   rp  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rB  rC  )r_   rp  rE  r   r!  s        rU   rF  PrismaClient.jsonify_object  sb    --%MMODA!T""<!%AGJ $  ! <!;GJ<rG     
   	max_triesmax_timer@  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.
)r4   MonthlyGlobalSpendLast30dKeysBySpendLast30dModelsBySpendMonthlyGlobalSpendPerKeyMonthlyGlobalSpendPerUserPerKeyLast30dTopEndUsersSpendDailyTagSpendr4   z, c              3   .   #    U  H  nS U S 3v   M     g7f)'Nrh   ).0views     rU   	<genexpr>1PrismaClient.check_view_exists.<locals>.<genexpr>  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!)rU  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  rU  	query_rawr   r$   infohealth_checkexecute_rawr9   r8   r   r  rO   r  )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              rU   check_view_existsPrismaClient.check_view_exists  s    *K		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 - 	}, .$ +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      rf   rn   
table_name)usersrx   configspendc           
      X  #    [         R                   " 5       n US:X  a.  U R                  R                  R                  X0S9I Sh  vN nU$ US:X  a.  U R                  R                  R                  X0S9I Sh  vN nU$ US:X  a.  U R                  R
                  R                  X0S9I Sh  vN nU$ US:X  a,  U R                  R                  R                  X0S9I Sh  vN nW$  N Np N> N! [         a  nSSKnS[        U5       3n[        R                  " U5        US	R                  [        U5      5      -   nUS
-   UR                  " 5       -   n	[         R                   " 5       n
X-
  n[        R                   " U R"                  R%                  UUU	SS95        UeSnAff = f7f)z$
Generic implementation of get data
r  whereNrx   r  r  r   z2LiteLLM Prisma Client Exception get_generic_data: z
Exception Type: {}r+  get_generic_data)r  r  r  rq  )r  rU  litellm_usertable
find_firstlitellm_verificationtokenlitellm_configlr  rM   r   r$   r   rO   r  rP   r   r   rL  r  )r_   rf   rn   r  r  rP  r&  rM   	error_msgerror_tracebackr  	_durations               rU   r  PrismaClient.get_generic_data   s    " YY[
$	W$!%!:!:!E!E, "F "  O v%!%!B!B!M!M, "N "  O x'!%!7!7!B!B, "C "  O	 w&!%!5!5, "6 "  O  	LSQRVHUI &&y1!$:$A$A$q'$JJI'$.1E1E1GGOyy{H -I&&66'(&"10	 7  G%	s   F*-C1 C)C1 F*-C1 :C+;C1  F*-C1 .C-/C1 4F*5-C1 "C/#C1 (F*)C1 +C1 -C1 /C1 1
F';B'F""F''F*user_iduser_id_listteam_idteam_id_listkey_val)	r   rf   r  r  enduserbudgetteamuser_notificationcombined_view
query_type)find_uniquefind_allexpiresreset_atoffsetlimitrg   budget_id_listc           
      Z  #    [        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 R                  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 R                  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 R                  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OUS:X  a  U	b  U
b  U R                  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 R                  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bY  US:X  GaR  US:X  a7  Uc  SU0nU R                  R,                  R                  USS0S9I S h  vN nU$ US:X  a0  Ub-  U R                  R,                  R!                  US9I S h  vN nU$ US:X  a4  U
b1  U R                  R,                  R!                  SSU
00S9I S h  vN nU$ US:X  a4  Ub1  U R                  R,                  R!                  SSU00S9I S h  vN nU$ US:X  ac  U	b:  U R                  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                  R/                  UX5      I S h  vN nU$ US:X  a  [
        R                  " S#5        Ubv  US:X  a5  U R                  R0                  R                  US   US$   0S9I S h  vN nU$ US:X  a3  U R                  R0                  R!                  US   US$   0S9I S h  vN nU$ U R                  R0                  R!                  S%S0S&9I S h  vN nU$ US':X  aI  U
bF  US:X  a?  U R                  R2                  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b8  US:X  a1  U R                  R4                  R!                  S,SU00S9I S h  vN nU$ g US-:X  Ga#  US:X  a2  U R                  R6                  R                  SU0S.S0S9I S h  vN nU$ US:X  a4  U
b1  U R                  R6                  R!                  SSU
00S9I S h  vN nU$ US:X  a7  Ub4  U R                  R6                  R!                  S/S0U00S
S0S9I S h  vN nU$ US:X  a4  Ub1  U R                  R6                  R!                  SSU00S9I S h  vN nU$ US:X  a2  Uc/  U R                  R6                  R!                  [8        S19I S h  vN nU$ US2:X  ai  US:X  a/  U R                  R:                  R                  SU0S9I S h  vN nU$ US:X  a,  U R                  R:                  R!                  5       I S h  vN nU$ US3:X  Ga\  Ub7  [        U[        5      (       a"  [	        US9n[
        R                  " SU 35        US:X  Ga  Uc  [        SSSU 30S9eS4U S53nU R                  R=                  US69I S h  vN nUb  US7   c  / US7'   US8   c  S9US8'   S nUS:   bL  US   bF   US:    H<  nUR?                  S5      c  M  US   UR?                  S5      :X  d  M1  [A        SA0 UD6nM>     UUS;'   [C        SA0 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N GN] GN GN, GN GN| GNI GN GN GN GNv GN GN GN GNp GN2 GN GN GN GNM GN GN GN GN-! [D         a  nSS K#nS=U 3nU[        U5      -   n[I        U5        US>-   URJ                  " 5       -   n [
        R                  " U 5        [        R                  " 5       n!U!U-
  n"[L        RN                  " U RP                  RS                  UU"S?U S@95        UeS nAff = f7f)BNrf   r_  z%PrismaClient: find_unique for token: r  rl  r   zNo token passed in. Token=rm  r_  litellm_budget_tableT)r  includezQAuthentication Error: invalid user key - user key does not exist in db. User Key=r  r  r   r  r  gtlt)ORbudget_reset_atr  insk-r  desc)orderr  r  z=Authentication Error: invalid user key - token does not existr   organization_membershipsr  r  )r  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'rn   	startTimer  r  ANDNOTbudget_durationr  	budget_idr  litellm_model_tablemembershas)taker  r  a  
                        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,
                            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.organization_id as org_id,
                            tm.spend AS team_member_spend,
                            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,
                            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_ModelTable" m ON t.model_id = m.id
                        LEFT JOIN "LiteLLM_BudgetTable" AS b ON v.budget_id = b.budget_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 = 'z'
                    queryteam_modelsteam_blockedFteam_members_with_rolesteam_memberlast_refreshed_atzHLiteLLM Prisma Client Exception: Error with `get_data`. Args passed in: r+  get_datar  r  rq  r  rh   )*localsr  r   r   _hash_token_if_neededr$   rN   r   rU  r  r  r  r   	isoformatr   HTTP_401_UNAUTHORIZED	find_manyr   r   r0  rg  r   r  r  litellm_spendlogslitellm_budgettablelitellm_endusertablelitellm_teamtabler   litellm_usernotificationsquery_firstr   r5   r4   r  rM   rV   rP   r   r   rL  r  )#r_   r_  r  r  r  r  r  r  r  r  r  r  r  rg   rL  r  args_passed_inr  rf  rP  rwhere_filterhashed_tokenst	new_token	sql_queryr  tmr&  rM   prisma_query_infor  r  r  r  s#                                      rU   r  PrismaClient.get_dataX  su    P  YY[
&*]	 H!j&8&:+> $!%--'<5'I,22CL>R .<3K}+(+$+/I%-Q#R  &*WW%F%F%R%R&5!7 > &S &  H  +#++7J$,,h= = 08/?/?/I/I/KH, ,(.(D(D%vw|v}#~   :-'2E%)WW%F%F%P%P('2!7 > &Q &  H  +H0A!)A)!))X>>,-II,?,?,A	 "*  :-'2E%)WW%F%F%P%P('2!7 > &Q &  H  +H0A!)A)!))X>>,-II,?,?,A	 "* *,+ ,%)WW%F%F%P%P "+D 1!*T7O <# 15h/? &Q &  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%)WW%F%F%P%P&/*!7 > &Q &  H
 '#O ($*$@$@^  %**<&:+?.#,g"6%)WW%>%>%J%J%!;T B &K &  H\  S  :-'2E%)WW%>%>%H%H% &I &  HP  K  :-(2F%)WW%>%>%H%H-h/? &I &  HH  ?  :-,2J%)WW%>%>%H%H(4*>? &I &  H<  7  :-*)-)B)B)L)L#*F"3 $%.$5%.w$@'"# *M * $2  %	 *.):):9e)T#Tw&$**C &!]2)-)B)B)N)N '0@# *O * $ $O $z1)-)B)B)L)L '0@# *M * $
 $O%)WW%>%>%H%H*F3 &I &  H $Ox'H,@+%)WW%@%@%J%J $)):D(A).1BD0I(J,&!" "3T84D E#
 &K &  H $O ,  y(^-G+%)WW%A%A%K%K*T>,BC &L &  H $O	 ,
 v%.%)WW%>%>%J%J('2!6 = &K &  H2  +  :-(2F%)WW%>%>%H%H-h/? &I &  H(    :-'2E%)WW%>%>%H%H%w'7 "8 >	 &I &  H    :-,2J%)WW%>%>%H%H(4*>? &I &  H  	  :-,2F%)WW%>%>%H%H0 &I &  H  22.%)WW%F%F%R%R('2 &S &  H
    :-%)WW%F%F%P%P%RRH.$!%--'<5'I,22CL>R .}+(+$+/I%-Q#R 
!%*B +0 1C"!IH &*WW%8%8y%8%IIH+#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,#Ok / /u "   < (    
$0 $U$$  "  
       Sj  JV  	"jkyjz {)CF2I)$'$.1E1E1GGO &&7yy{H :-I&&66'(&("1	 7  G'	s  "j+Bg> 8f69B#g> f98g> Ag> 2f<38g> /A$g> f?8g> Dg>  g!g> )j+*Ag> 	g
g> j+/g> ?g g> j+3g> 9g:g> ?j+ 3g> 3g4g> 9j+:<g> 6g7g> <j+=!g> gg> $j+%Ag> 8g9g> >j+?4g> 3g4g> 9j+:(g> "g#g> (j+)Ag> 0g 1g> 6j+89g> 1g#2g> 7j+98g> 1g&2g> 7j+83g> +g),g> 1j+26g> (g,)g> .j+/3g> "g/#g> (j+)3g> g2g> "j+#4g> g5g> j+-g> g8g> j+A<g> g;Ag> g> 1Bg> 3j+6g> 9g> <g> ?g> g> g> g> g> g> g> g> g> g> g>  g> #g> &g> )g> ,g> /g> 2g> 5g> 8g> ;g> >
j(Bj##j((j+rE  c                     U R                  US9nUR                  SS 5      b4  [        US   [        5      (       a  [        R
                  " US   5      US'   U$ )Nr  members_with_roles)rF  r   r   r   r,  r  )r_   rE  s     rU   jsonify_team_object PrismaClient.jsonify_team_object  sa    %%7%3;;+T2>:()4D
 D
 -1JJw?S7T,UG()rW   )r   rf   r  r  r  r  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'   [        S5        U R                  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 R                  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 R                  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        H[  u  pUn["        R$                  " U5      nU R                  R&                  R                  SU0XS.SU0S.S9nUR)                  U5        M]     [*        R,                  " U6 I Sh  vN   [        R                  " S 5        gUS!:X  a]  U R	                  US9nU R                  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 R                  R0                  R                  S"US"   00 UE0 S.S9I Sh  vN n[        R                  " S%5        U$ g GNU 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N" N Na! [         a  n	S&SKnS'[        U	5       3n[        U5        US(-   UR4                  " 5       -   n[         R                   " 5       nUU-
  n[*        R6                  " U R8                  R;                  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: %srf   r_  r  r  z:PrismaClient: Before upsert into litellm_verificationtokencreater  r  T)r  rp  r  NzData Inserted into Keys Tabler   r  r  rp  z\Foreign key constraint failed on the field: `LiteLLM_UserTable_organization_id_fkey (index)`rl  r   z/Foreign Key Constraint failed. Organization ID=organization_idzM does not exist in LiteLLM_OrganizationTable. Create via `/organization/new`.rm  zData Inserted into User Tabler  rE  r  zData Inserted into Team Tabler  
param_name)r  param_valuer  zData Inserted into Config Tabler  
request_idzData Inserted into Spend Tabler  z&Data Inserted into Model Request Tabler   z0LiteLLM Prisma Client Exception in insert_data: r+  insert_datar  )r  r$   rN   rg  rF  rV   rU  r  upsertr  r  r  r   r   r  r  r=  r,  r  r  r   r   r  r  r  rM   rP   r   rL  r  )r_   rp  r  r  r_  rf  rE  new_verification_tokennew_user_rowr&  new_team_rowtasksr   r!  updated_dataupdated_table_rownew_spend_rownew_user_notification_rowrM   r  r  r  r  s                          rU   r  PrismaClient.insert_data  sc    " YY[
z	 &&'FMU"W#U;--4-8#/ P 04ww/P/P/W/W #.W+"$ 4T: 0X 	0 	*& %))*IJ--v%--4-8)-)B)B)I)I($y/:&1k&( *J * $L& %))*IJ##v%2242@%)WW%>%>%E%E$d9o6"-W+"$ &F &   %))*IJ##x'  JJLDA#$L#'::l#;L(,(>(>(E(E+Q/56&T'4l&C )F )% LL!23 ) nne,,,$))*KLw&--4-8&*gg&?&?&F&F'l);<"-W+"$ 'G ' ! %))*JK$$22--4-8'';;BB+T,-?@&1k&( C   * %))*RS00 3e	*$ ! vq6" ,(+ '+Z[bct[uZv  wD  *E$  G  > -!  	J3q6(SI)$'$.1E1E1GGOyy{H :-I&&66'(&+"1	 7  G!	s   OB L4 K.L4 5O6L4 1K4 =K1>K4 L4 OAL4  L*!L4 <O=BL4 L-L4 &O'AL4 -L0.L4 	O
AL4 L2L4 ,O.L4 1K4 4
L'>$L""L''L4 -L4 0L4 2L4 4
O>B N>>OOr  	data_list)r  update_many)r   rf   r  r  r  r  r  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 35        [        US9nXS'   U R                  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bx  US:X  ar  US:X  al   Uc  US   nUc  U	b  U	nOUnU R                  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 R                  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,                  R/                  S5      (       a  U R1                  UR,                  S9Ul         U R                  UR                  SS9S9nUR                  R                  SUR,                  00 UES9  M     UR3                  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R                  R                  SUR4                  00 UE0 UES.S9  MR     UR3                  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R6                  R                  SUR4                  00 UE0 UES.S9  MO     UR3                  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R8                  R                  S!UR:                  00 UE0 UES.S9  MO     UR3                  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 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  MR     UR3                  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No 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&[C        U5       3n[	        U5        US'-   URD                  " 5       -   n[        R                  " 5       nUU
-
  n[F        RH                  " U RJ                  RM                  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: r  Nztoken: r  r_  r  z[91mz DB Token Table update succeeded z[0m)r_  rp  r   r  r  r  z!DB User Table - update succeeded )r  rp  r  r  r  z!DB Team Table - update succeeded )r  rp  rf   r  r  T)exclude_nonez([91mDB Token Table update succeeded[0mz-[91mDB User Table Batch update succeeded[0mr  z1[91mDB End User Table Batch update succeeded[0mr  r  z/[91mDB Budget Table Batch update succeeded[0mr  z-[91mDB Team Table Batch update succeeded[0mr   z/LiteLLM Prisma Client Exception - update_data: r+  update_datar  )'r$   rN   r  rF  rV   r  rU  r  r  r   r  r  r  r  r  r   r   r,  r  r  batch_r/  r_  r0  rg  commitr  r  r  r  r  r  rM   r   rP   r   r   rL  r  )r_   r_  rp  r  r  r  r  r  r  r  r  rE  rP  _dataupdate_user_rowupdate_team_rowbatcheridxr  	data_jsonr   r  r  r  r&  rM   r  r  r  r  s                                 rU   r
  PrismaClient.update_dataz	  sn	    0 	""5j\B	
 YY[
J	))t)4G ,$($7$7=N$7$O! w/0-E:#( !%!B!B!I!I"E*$G "J "  %**8
CD 
 !'0 ( 3 3 5 "'66#*zV/C(* ?%i0G$,5A,J),3)(,(A(A(H(H$g."-W+#/# )I ) # %))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)*>??%&:; )-(A(A(H(H$g."-W+#/# )I ) # %))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^ 0Z1&^ `*C^ )Z"*&^ `*B^ #Z%??^ >[?^ `*A^ #[?A^ \^ `*A^ '\A^ \4^ "`*#A^ +\7A^ ]%^ &`*'A^ :](A^ ^^ 5`*;^ >Z^ Z^ "^ %&[^ [^ '\ <^ ?\  ^ '\1-^ 0\11^ 7']"^ !]""^ (&^^ ^^ 
`'"B `""`''`*tokens)r   rf   r  r  r  c           
      F  #    [         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 R                  R                  R                  U	S9I Sh  vN n
[        R                  " S	U
5        S
U
0$ US:X  aK  UbH  [        U[        5      (       a3  U R                  R                  R                  SSU00S9I Sh  vN   SU0$ US:X  aJ  UbF  [        U[        5      (       a0  U R                  R                  R                  SSU00S9I Sh  vN   gggg N N[ 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.
Nr  r  r  r_  r  r  r  zdeleted_tokens: %sdeleted_keysr  r  deleted_teamsrf   r   z/LiteLLM Prisma Client Exception - delete_data: r+  delete_datar  )r  r   r
   r   r0  rg  r   rU  r  delete_manyr$   rN   r  r  rM   rV   rP   r   r   rL  r  )r_   r  r  r  r  r  r  r_  rf  filter_querydeleted_tokensr&  rM   r  r  r  r  s                    rU   r  PrismaClient.delete_data
  s[    & YY[
9	!j&>&> "#E!%--%2B2B52I2I'+U'C',!((6 $ &(&4*? @9gBVW$L %,dM-B#CL'+ww'H'H'T'T& (U ( " %**+?P&77f$ ,|T22 gg//;;$t\&:; <    (66e# ,|T22 gg77CC$t\&:; D    3 - $!"  	I#a&RI)$'$.1E1E1GGOyy{H -I&&66'(&+"1	 7  G!	sz   H!B/F F
	F 'H!(AF 0F1F 8H!9A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(): r+  connectr  )r  r$   rN   rU  is_connectedr  r  rM   r   rV   rP   r   r   rL  r  r_   r  r&  rM   r  r  r  r  s           rU   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(): r+  
disconnectr  )r  rU  r$  r  rM   r   rV   rP   r   r   rL  r  r   s           rU   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           
        #    [         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
zSELECT 1Nr   r#  r+  r  r  )r  rU  r  r  rM   r   rV   rP   r   r   rL  r  )
r_   r  r  rP  r&  rM   r  r  r  r  s
             rU   r  PrismaClient.health_check5  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.
rk  rl  rm  rd   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;
            r  r   	reltuples)rU  r  )r  rT  r_   s     rU   _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expor  r@  intr$   r   )r_   r+  r&  s   `  rU   _get_spend_logs_row_count&PrismaClient._get_spend_logs_row_countZ  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_namern   )r   r4  r1  set_proxy_state_variable)r_   r4  _num_spend_logs_rowss      rU   (_set_spend_logs_row_count_in_proxy_state5PrismaClient._set_spend_logs_row_count_in_proxy_statew  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   
ValueError	TypeErrorr$   r  )r_   r;  rn   s      rU   _validate_response_time$PrismaClient._validate_response_time  s     #	*+E >eE%L%-3P&P  
 I& 	 ((23C2DE 		s   +4 4 )A A r?  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  r0   r/   r  r$   r  )r_   r?  r&  s      rU   _clean_detailsPrismaClient._clean_details  sP    '4((	":g#677 	 ((+I!)MN	s   , 
AAA
model_namer   healthy_countunhealthy_countr  
checked_bymodel_idc
                   #     [        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 R                  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)rE  r   rF  rG  Ni  )r  r;  r?  rH  rI  zSaving health check data: r  z+Error saving health check result for model : )r   r0  r@  rC  r  r=  r$   rN   rU  litellm_healthchecktabler  r  r   )r_   rE  r   rF  rG  r  r;  r?  rH  rI  health_check_dataoptional_fieldsr   r!  r&  s                  rU   save_health_check_result%PrismaClient.save_health_check_result  s2    	 "*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99@@FW@XXX	 L Y 	 &&=j\A3O 		sT   EB(D ,	D
9D
?AD DD 
ED 
ED>9E>EEstatus_filterc                   #     0 nU(       a  XS'   U(       a  XES'   U R                   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
rE  r   
checked_atr  )r  r  r  skipNz$Error getting health check history: )rU  rL  r  r  r$   r   )r_   rE  r  r  rQ  where_clauseresultsr&  s           rU   get_health_check_history%PrismaClient.get_health_check_history  s     	L-7\*)6X& GG<<FF"#V,	 G  G N  	 &&)MaS'QRI	sG   BAA AA BA 
A?A:4A?5B:A??Bc                 V  #     U R                   R                  R                  SS0S9I Sh  vN n0 nU H#  nUR                  U;  d  M  X2UR                  '   M%     [	        UR                  5       5      $  NH! [         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
rS  r  r  Nz(Error getting all latest health checks: )	rU  rL  r  rE  r   valuesr  r$   r   )r_   
all_checkslatest_checkscheckr&  s        rU   get_all_latest_health_checks)PrismaClient.get_all_latest_health_checks  s     	#ww??II#V,  J   J
 M###=86;%"2"23 $ ,,.//  	 &&)QRSQT'UVI	sJ   B)(A7 A5A7 
*A7 4B)5A7 7
B&B!B&B)!B&&B))rU  rS  rL  r]   )NNNNNNNr  NNNNNNN)NNNN)rd   N)r   r   NNNNN)Nr   r   N)0r   r   r   r   rJ  r
   r  r   r   r   r   r`   r   r  r   r   r]  rg  rF  r-  r.  r/  r  r@  r  r;   r  r   r   r0  rK   r  r  r  r
  r  r  r$  r  r1  r9  r   r@  rC  rO  rW  r^  r   rh   rW   rU   rI  rI  X  s(   #%D% &*	+F+F (+F c]	+FZ!T#334!	%	&!F 
4 
D 
 ZZx .. . >?	. .`   -1!%'+!%'+"& 9F&*'+ $ +/48.2=@c4i()@ #@ tn	@
 #@ tn@ $@ !

@* 56+@, (#-@. 8$/@0 1@2 
3@8 #4.9@: $L1;@< !c+=@ @D4  EE I
EEP   $$(!%!%7? ,09=_}_ _ D>	_
 #_ #_ 34_ QR
_ $D>_ )1__D	  "&'+RV!%FF tnF W%MNO	F
 #FFR < , < : 

 (	%&htn $   '+,0"&$("&++ + 	+
 +  }+ #5/+ $+ SM+ 3-+^ %)'+SM  	
  }8rW   rI  r  r|  rU  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)rf   N)r  z
User Row: z	, type = model_dump_jsoniX  )rf   rn   r   )	r   r  rV   r  r   callabler  rb  r   )r  r|  rU  	cache_keyrP  user_rowcache_values          rU   _cache_user_rowrg    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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         [        R                  " UUS9 n	[         R                  " SS5      S:w  a  U	R                  5         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,
	SMTP_HOST	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 setrj  )hostportSMTP_TLSTrueFalse)r   password)msg	from_addrto_addrsz*An error occurred while sending the email:)r  r  r0  r>  r   r$   rN   attachr   smtplibSMTPstarttlsloginsend_messager  r  r   )rh  ri  rj  	smtp_host	smtp_portsmtp_usernamesmtp_passwordsender_emailemail_messageserverr&  s              rU   
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
\\
 yyV,7! &*   !&'   
 
 
*  
&&83q6A	
 	

sU   DGF )AFF G
FF GF 
G("G
GGGr_  c                 j    SS K nUR                  " U R                  5       5      R                  5       nU$ )Nr   ra  )r_  rb  rf  s      rU   rg  rg  j  s*     >>%,,.1;;=LrW   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
r  r  )r0  rg  r  s    rU   r  r  s  s%     &&rW   c                       \ rS rSr\S\S\S\S\\	\
4   4S j5       r\S\S\S\\   S\4S j5       r\S	\4S
 j5       rSrg)ProxyUpdateSpendi  n_retry_timesr   rL  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        H?  u  nn	[        R                  b   UR                  R                  SU0UU	SS.SS	U	00S
.S9  MA     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MQ  S n
A
f[         a  n
[        XUS9   S n
A
GMo  S n
A
ff = f7f)Nr   <   )seconds)timeoutr  F)r  r  r  r  	incrementr  r  r&  r  rL  r  )ranger  rU  txr   r  r=  rQ   max_end_user_budgetr  r  r   $_raise_failed_update_spend_exceptionr   sleepr  )r  r   rL  r  r5  r  transactionr  end_user_idresponse_costr&  s              rU   update_end_user_spend&ProxyUpdateSpend.update_end_user_spend  st     }q()AJ"(++..%b1 /   *1133w 8==?')&::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C*?D
C(DD DD F$D &D(D*D0C31D=DD D	DD	D  
F*+E"EE"F"F/
F 9F FFdb_writer_clientc           	        #    SnSnUR                   S U n[        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        UR                  U	S-   [        R                  " U5      S	S
0S9I S h  vN n
U
R                  S:X  a  UR                   [        U5      S  Ul         O[        S[        U5      U5       H{  nXkX-    nU Vs/ s H  nUR                  0 UE5      PM     nnUR                  R                   R#                  USS9I S h  vN   [        R                  " S[        U5       S35        M}     UR                   [        U5      S  Ul         [        R                  " [        U5       S[        UR                   5       35          g    g  GN!s  snf  N! [$         a2    Uc  SnX:  a  e [&        R(                  " SU-  5      I S h  vN     GM  f = f! [*         a1  nUR                   [        U5      S  Ul         [-        XUS9   S nAg S nAff = f7f)Nr   r  r   SPEND_LOGS_URLr   /zbase_url: {}zspend/updatezContent-Typezapplication/json)urlrp  headers   T)rp  skip_duplicateszFlushed z logs to the DB.z% logs processed. Remaining in queue: r  r  )rJ  r  r  r  r  r   endswithr$   rN   rO   postr,  r  rn  rF  rU  r  create_manyr   r   r  r  r  )r  r   r  rL  
BATCH_SIZEMAX_LOGS_PER_INTERVALlogs_to_processr  r5  base_urlrP  jbatchentrybatch_with_datesr&  s                   rU   update_spend_logs"ProxyUpdateSpend.update_spend_logs  s     
 	 (>>?U@UVYY[
8	=1,-/.!yy)94@HO,q0$0,8'0055$OH,22>3H3H3RS)9)>)> (> 9!%O!<%35G$H *? * $
 $//36 - D D$'$8$:!" *@ "'q#o*>
!KA$3$GE .30-2E !. < <YY G-2 - 0 #0"2"2"D"D"P"P%5t #Q #   166"*3u:,6F G "L *@@_AUAWX &< -22"?344YZ]^k  _C  _C  [D  ZE  F U .$0 1 .y)!--1---.  	3@3W3WO$&4M0 1>O		s   )J I BHG9AH.G<)H4H5A?H4I 5J 6I 8J 9H<H1H?4H75H?:I >H??I 
I='I83J 8I==J rd   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    rU   r  &ProxyUpdateSpend.disable_spend_updates  s"     	@ 78D@rW   rh   N)r   r   r   r   staticmethodr0  rI  r   r	   r   r   r  r   r1   r  r   r  r   rh   rW   rU   r  r    s    **#* (* %)e$4	* *X EE#E #;/E (	E EN 	4 	 	rW   r  r   r  rL  c                 >  #    SnUR                   R                  U UUS9I Sh  vN   [        R                  " SR	                  [        U R                  5      5      5        [        U R                  5      S:  a  [        R                  UU UUS9I Sh  vN   gg Nu N7f)z
Batch write updates to db.

Triggered every minute.

Requires:
user_id_list: dict,
keys_list: list,
team_list: list,
spend_logs: list,
rk  )r   r  rL  NzSpend Logs transactions: {}r   )r  r   rL  r  )	r   #db_update_spend_transaction_handlerr$   rN   rO   r   rJ  r  r  )r   r  rL  r  s       rU   update_spendr    s       M

2
2
V
V##+ W    %,,S1U1U-VW =//01400''/-	 1 
 	
 	
 5	
s"   !BBA.BBBBr&  r  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: r+  r  r  )rM   r   rP   r  r   r   r  )r&  r  rL  rM   r  r  r  r  s           rU   r  r  '  s      NcRSfXV   $&)=)=)??Oyy{H%I)) $)	 	* 	
 GrW   current_spendsoft_budget_limitc                    SSK Jn  Uc  gUR                  5       nUR                  S:X  a"  U" UR                  S-   SS5      [        SS9-
  nO+U" UR                  UR                  S-   S5      [        SS9-
  nXC-
  R                  nUR                  S:X  a  U nOXR                  S-
  -  nXU-  -   nXq:  a  [        S5        gg)	Nr   )dateF   r   daysz*Projected spend exceeds soft budget limit!T)	r   r  todaymonthyearr   r  dayrV   )r  r  r  r  	end_monthremaining_daysdaily_spend_estimateprojected_spends           rU   _is_projected_spend_over_limitr  C  s      JJLE {{baA.1BB	U[[1_a89!;LL	'--N yyA~,,		A> $n'LMO*BCrW   c                 D   SS K nUc  g UR                  R                  5       nUR                  " UR                  UR                  S-   S5      UR
                  " SS9-
  nXC-
  R                  nU UR                  S-
  -  nXe-  nXq:  a  X-  nX2R
                  " US9-   n	Xy4$ g )Nr   r   r  )r   r  r  r  r  r   r  r  )
r  r  r   r  r  r  daily_spendr  approx_dayslimit_exceed_dates
             rU   _get_projected_spend_over_limitr  e  s      MM!Eejj%++/1=@R@RA I  '--N		AK "2O*'5!$6$6K$HH 11rW   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modelsr  zInvalid model for team rK  z.  Valid models for team are: r+  )popr  )r  team_configrk  valid_modelsmodel_in_requests        rU   _is_valid_team_configsr    sk    +-1E;"x0'0/)'"5E4FFdeqdrrtu  rW   c                 :    [        U R                  5       S-  5      $ )Ng    eA)r0  	timestamp)dts    rU   _to_nsr    s    r||~#$$rW   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  
model_infoid)rI  
guardrails)r   get_deploymentr  _merge_guardrails_with_existing)rp  r   r  r  rI  
deploymentmodel_level_guardrailss          rU   r.  r.    s      xx
#)rHl+1rJ~~dD)H **H*=J'66::<H% +4HHrW   r  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<  
setdefaultr   r   r   r   )rp  r  r1  r  existing_guardrailss        rU   r  r    s     IIKM''
B7H",,|R8 )4007J23PR ,d33(>#$B 	
 "#&9&R"STH\rW   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$ )Nr  ri  )	r   r   ro  r   r  r,  r  r   r  )r&  r  _errors      rU   get_error_message_strr    s    M!]##ahh$$HHM  $'' JJqxx0M  Q	""Q	40F&#&& &  FD)) $

6 2
   FM  ArW   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  rD   )	redoc_urls    rU   _get_redoc_urlr    s:     IIk**y*299Z()T1rW   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  r  )docs_urls    rU   _get_docs_urlr    s9     99Z((x(299Y'(D0rW   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 $ [        S[        U 5      -   [        R                  [        U SS5      UR                  S
9$ )z_
Returns an Exception as ProxyException, this ensures all exceptions are OpenAI API compatible
r   )r   zException: ro  zerror()paramNonern  )ri  r  r  codezInternal Server Error, )fastapir   r$   r  r   r   r   r  r   r   internal_server_errorHTTP_500_INTERNAL_SERVER_ERROR)r&  r   s     rU   handle_exception_on_proxyr    s     ""[#45!]##Ax6#a&);< 66!Wf-M6+P+PQ	
 	
 
A~	&	&)CF222a&)22	 rW   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  r   rm  N)r   r   r   not_premium_userrn   r   )r  r   
detail_msgs      rU   _premium_user_checkr  '  s~     8TU\T]]_`q  aC  aC  aI  aI  `J  K
TUfUwUwU}U}T~
Z(
 	
 rW   r  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   )r  r   model_namesmodel_names_set
is_in_lists        rU   is_known_modelr  9  s?     }
*,,.K+&OJ
rW   
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)rQ   vector_store_index_registryget_vector_store_indexes)r  s    rU   is_known_vector_store_indexr  J  s-    
 **2<<UUWWWrW   	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      rU   
join_pathsr  T  s      %ILLE #5'{,,  AeW+&&

  "{!E7+
rW   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      $ )Nr  )get_proxy_base_urlget_server_root_pathr  )r  r  server_base_urlr  server_root_pathintermediate_urls         rU   get_custom_urlr   k  s^    (*O""#+-r!)(E.66h..(55rW   c                  .    [         R                  " S5      $ )z8
Get the proxy base url from the environment variables.
r  r  r  rh   rW   rU   r  r    s     99%&&rW   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_PATHr  r"  rh   rW   rU   r  r    s     99'--rW   ri  c                 L    SSK Jn  Uc  [        [        R                  SU 0S9eU$ )Nr   r   r   rm  )r   r   r   r   r  )ri  r   s     rU   get_prisma_client_or_throwr&    s1    8==W%
 	
 rW   rf   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   NFrk  r   z^sk-[A-Za-z0-9_-]+$Tz^[a-fA-F0-9]{64}$)r;  r   r   r   rD  )rf   r;  s     rU   is_valid_api_keyr(    s\     c3CH
 	 88*C0088(#..rW   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~  r  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_encrK  s
             rU   $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rW   model_to_user  r  c                   #    U(       d  g SSK nSSKnSnUb!  UR                  S0 5      R                  S5      nU(       d  UR                  " S5      nU(       aO  U(       aH  UR	                  US9nUR
                  R                  R                  U US/S9nUR                  nS	n	UU	S
.$ g! [         a    [        R                  " S5         g[         a$  n
[        R                  " SU
 S35         Sn
A
gSn
A
ff = f7f)aH  
Helper function to count tokens using Anthropic API directly.

Args:
    model_to_use: The model name to use for token counting
    messages: The messages to count tokens for
    deployment: Optional deployment configuration containing API key

Returns:
    Optional dict with token count and tokenizer info, or None if failed
Nr   r  r  ANTHROPIC_API_KEY)r  ztoken-counting-2024-11-01)r  r  betasanthropic_api)total_tokenstokenizer_usedzBAnthropic library not available, falling back to LiteLLM tokenizerzError calling Anthropic API: z#, falling back to LiteLLM tokenizer)r  	anthropicr   r  	Anthropicbetar  count_tokensinput_tokensImportErrorr$   r  r  )r=  r  r  r  rD  anthropic_api_keyr  rP  rB  rC  r&  s              rU   count_tokens_with_anthropic_apirK    s      (
 !! */? D H H S ! "		*= >((1B(CF {{++88"!23 9 H
 $00L,N !-"0    
$$P	
 	  
$$+A3.QR	
 	
 	
s;   	C<BB* (C<* C9
C<	C9C4/C<4C99C<rt  r6   r#   r  
user_modelr  include_model_access_groupsonly_model_access_groupsreturn_wildcard_routesr   r'   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(       a;  U(       a4  U(       a-  U
(       a&  / nU" UUU
US9I Sh  vN nU" U US9  UR                  nU" UUUUS	9nU" UUUUUR                  S
S5      U	UUUUS9
nU$  NA7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)rt  proxy_model_listmodel_access_groupsrM  )r  r   r   rL  )rt  
team_table)r  rV  rW  rM  infer_model_from_keysF)

key_modelsr  rV  rL  rY  rO  r   rW  rM  rN  )litellm.proxy.auth.auth_checksrQ  litellm.proxy.auth.model_checksrR  rS  rT  1litellm.proxy.management_endpoints.team_endpointsrU  r	  get_model_access_groupsr  r  r   )rt  r   r  rL  r   rL  r  rM  rN  rO  r   rQ  rR  rS  rT  rU  rV  rW  rZ  r  team_object
all_modelss                         rU   get_available_models_for_userra    s    > ? 
 V  %557(@@B  +)/$?	J /::K =%6;M
+'1/	
 
 	.?KX!((!)/$?	K )).223JER5/$?!9J =
s   A>C CACrI  providerinclude_metadatafallback_typec                     SSK Jn  U S[        US.nU(       a/  0 n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
XS'   XvS'   U$ )a/  
Create a standardized model info response.

Args:
    model_id: The model ID
    provider: The model provider
    include_metadata: Whether to include metadata
    fallback_type: Type of fallbacks to include
    llm_router: LiteLLM router instance

Returns:
    Dictionary containing model information
r   )get_all_fallbacksr  )r  objectcreatedowned_bygeneral)rj  context_windowcontent_policyrl  z'Invalid fallback_type. Must be one of: rm  )r  r   rd  	fallbacksr  )r\  rf  r   r   )rI  rb  rc  rd  r   rf  r  r  effective_fallback_typevalid_fallback_typesrm  s              rU   create_model_info_responserp  p  s    ( B 0	J  +6MI 	 
  O">@AU@VW 
 &!1
	
 !*!):rW   available_modelsc                 @    X;  a  [        SSR                  U 5      S9eg)z
Validate that a model is accessible to the user.

Args:
    model_id: The model ID to validate
    available_models: List of models available to the user

Raises:
    HTTPException: If the model is not accessible
i  z2The model `{}` does not exist or is not accessiblerm  N)r   rO   )rI  rq  s     rU   validate_model_accessrs    s0     'GNN
 	
 (rW   r;  r]   )NNNFFFN)FNN)r   r<  rb  r,  r  r  r  r  rM   r   r   email.mime.multipartr   email.mime.textr   typingr   r   r	   r
   r   r   r   r   r   rQ   r   litellm.constantsr   r   litellm.proxy._typesr   r   r   r   r   r   r~  r   litellm.types.utilsr   r   r-  rI  r  r   r   litellm.litellm_core_utils*litellm.litellm_core_utils.litellm_loggingr   r    r!   r"   r#   litellm._loggingr$   litellm._service_loggerr%   r&   litellm.caching.cachingr'   r(   litellm.exceptionsr)   %litellm.integrations.custom_guardrailr*   "litellm.integrations.custom_loggerr+   1litellm.integrations.SlackAlerting.slack_alertingr,   (litellm.integrations.SlackAlerting.utilsr-   r.   *litellm.litellm_core_utils.safe_json_dumpsr/   *litellm.litellm_core_utils.safe_json_loadsr0   'litellm.llms.custom_httpx.httpx_handlerr1   r2   r3   r4   r5   r6   litellm.proxy.auth.route_checksr7   litellm.proxy.db.create_viewsr8   r9   'litellm.proxy.db.db_spend_update_writerr:   litellm.proxy.db.log_db_metricsr;   litellm.proxy.db.prisma_clientr<   Llitellm.proxy.guardrails.guardrail_hooks.unified_guardrail.unified_guardrailr=   litellm.proxy.hooksr>   r?   'litellm.proxy.hooks.cache_control_checkr@   &litellm.proxy.hooks.max_budget_limiterrA   ,litellm.proxy.hooks.parallel_request_limiterrB   $litellm.proxy.litellm_pre_call_utilsrC   litellm.secret_managers.mainrD   )litellm.types.integrations.slack_alertingrE   r  rF   rG   rH   rI   rJ   opentelemetry.tracerK   _Spanr  r  rV   rY   r   r@  r  rF  rI  r   rg  r  rg  r  r  r  r  r   r  r  tupler  r  r  r.  r  r  r  r  r  r  r   r  r  r  r   r  r  r&  r(  r<  rK  ra  rp  rs  rh   rW   rU   <module>r     sh       	     ( . $
 
 
 @ P  9 ; *  ! 1  2 @ 9 3 A ; K T > A F ?  8 H : 8 < L J J 4 I 
 F1WDD )* 3d
 d
PU Uv*J

 
$ 
n nh-3 y l , %)!F
SMF
c]F
 3-F
Rc 	 	 	@ @F"
"
{+"
 $"
J#8D8-5e_D-5e_e_:%#I
#I$V,#I	#IL$  PT <Y 3 ( "x} " ~ 2
# 
$(3- Xf5E $ "XC XD X# c c .6S 6# 6# 6('HSM '.c . # $ &"hsm "P ,0<<tDcN+,< c3h(< d38n	<H /326!(-%*#(04['["[ [ 	[
 N+[  /[ c][ "&[ #[ ![ !-[ 
#Y[B ##'%)777 7 C=	7
 "7 
7t

3i
 

E|  
O s   <M) )M8