Ë
    tPêjMÊ  ã            !       óB  — U d dl Z d dlZd dlZd dlmZ d dlmZmZ d dlmZ d dlm	Z	m
Z
mZmZ d dlmZ d dlZd dlmZ d dlmZmZmZmZ d d	lmZ d d
lmZmZ d dlmZ d dlmZm Z m!Z! d dl"m#Z#m$Z$ d dl%m&Z&m'Z' d dl(m)Z) d dl*m+Z+m,Z, d dl-m.Z.m/Z/m0Z0m1Z1m2Z2m3Z3m4Z4m5Z5m6Z6 d dl7m8Z8 de9fd„Z:de;dz  de;dz  de<fd„Z= ej|                  d«      Z?de;de<fd„Z@ddœde;dz  de<de;dz  fd„ZA	 	 	 	 	 	 	 	 	 	 	 	 	 	 dwdeBdz  d eCe;   dz  d!eCe;   dz  d"e9dz  d#e9dz  d$e1dz  d%eCe5   dz  d&eCe0   dz  d'eBdz  d(e2dz  d)e;dz  d*eDdz  d+e/dz  d,e;dz  d-eDdz  de&f d.„ZEd/ZFe
eGd0<   d1e;d2eBd3eBde;dz  fd4„ZHd2e	d5eBdeBfd6„ZId3ee;eJf   dz  deKe;d7f   fd8„ZLd9e3dz  d:ed;   de;fd<„ZMde'fd=„ZNd3eBd9e3dz  de;fd>„ZOd?ed@ede9dz  fdA„ZPdBedefdC„ZQdDedEedFe;dz  dGe+fdH„ZRdDedEedFe;dIe;dGe+f
dJ„ZS	 dxd9e3dz  deBdz  de;fdK„ZT eUdLh«      ZVe
eGdM<   	 	 dydNeBdOeWdz  dPe9dz  deBfdQ„ZXdRZYe
eGdS<   dTZZe
eGdU<    ej|                  dVdWj·                  eY«      z   dXz   dWj·                  eZ«      z   dYz   «      Z\e
eGdZ<   d[e;d\e9d]e;de9fd^„Z]d[e;d\e9de9fd_„Z^d[e;de;fd`„Z_d&eCe0   dz  deCe0   dz  fda„Z`dbZae
eGdc<   ddZbe
eGde<   dfeJdeBe;e9eDz  f   dz  fdg„Zcdhe0de0fdi„Zddje4dz  de4dz  fdk„Zedzdle	dOeWdz  dme9de	fdn„Zf	 dxdeBdoeBd3eBdz  de;fdp„Zgd%eCe5   dz  deCe5   dz  fdq„Zh	 dxdre3dz  d3eBdz  de;fds„Zide<fdt„ZjdeBdedu   fdv„Zky){é    N)ÚMapping)ÚdatetimeÚtimezone)r   )ÚAnyÚFinalÚLiteralÚcast)Ú	BaseModel)Úverbose_proxy_logger)ÚLITELLM_PROXY_MASTER_KEY_ALIASÚLITELLM_TRUNCATED_PAYLOAD_FIELDÚ$LITELLM_TRUNCATION_DB_SAFEGUARD_NOTEÚREDACTED_BY_LITELM_STRING)ÚMAX_STRING_LENGTH_PROMPT_IN_DB)Ú get_litellm_metadata_from_kwargsÚreconstruct_model_name)Úis_unbilled_non_inference_call)Úcoerce_model_access_groupsÚis_valid_sha256_hashÚ/request_model_access_groups_from_litellm_params)Ú
safe_dumpsÚstrip_null_bytes)ÚSpendLogsMetadataÚSpendLogsPayload)Úspend_log_error)ÚPrismaClientÚ
hash_token)	Ú	CallTypesÚCostBreakdownÚ#StandardLoggingGuardrailInformationÚStandardLoggingMCPToolCallÚStandardLoggingModelInformationÚStandardLoggingPayloadÚ&StandardLoggingPayloadErrorInformationÚ!StandardLoggingVectorStoreRequestÚVectorStoreSearchResponse)Ú!get_end_user_id_for_cost_trackingÚreturnc                  óŠ   — t        j                  d«      } | €t        S 	 t        | «      S # t        t
        f$ r	 t        cY S w xY w)z‡
    Resolve prompt truncation threshold at runtime so values loaded later via
    proxy config environment_variables are honored.
    r   )ÚosÚgetenvÚ&DEFAULT_MAX_STRING_LENGTH_PROMPT_IN_DBÚintÚ	TypeErrorÚ
ValueError)Úmax_length_strs    úv/home/oem/CyberBrain26-unified/.venv/lib/python3.12/site-packages/litellm/proxy/spend_tracking/spend_tracking_utils.pyÚ#_get_max_string_length_prompt_in_dbr2   2   sI   € ô
 ŸI™IÐ&FÓG€NØÐÜ5Ð5ð6Ü�>Ó"Ð"øÜ”zÐ"ò 6Ü5Ò5ð6ús   Ÿ
* ªAÁAÚapi_keyÚ_master_keyc                 ó8   — |�| €yt        j                  | |«      S )u–   
    Raw-only constant-time master-key comparison. The hashed form is never
    considered equivalent â€” only the raw master-key string matches.
    F)ÚsecretsÚcompare_digest)r3   r4   s     r1   Ú_is_master_keyr8   @   s$   € ð
 Ð˜g˜oØÜ×!Ñ! '¨;Ó7Ð7ó    zhashed-jwt-[a-fA-F0-9]{64}Úvaluec                 ó`   — | t         k(  xs$ t        | «      xs t        j                  | «      d uS ©N)r   r   Ú_HASHED_JWT_REÚ	fullmatch)r:   s    r1   Ú_is_non_secret_key_valuer?   M   s5   € àÔ/Ñ/ò 	7Ü Ó&ò	7ä×#Ñ# EÓ*°$Ð6ðr9   F©Úalready_redactedrA   c                ó�   — t        | t        «      r| sy t        j                  dd| «      }|sy |rt	        |«      r|S t        |«      S )Nz(?i)^bearer Ú )Ú
isinstanceÚstrÚreÚsubr?   r   )r:   rA   Ústrippeds      r1   Ú_redact_logged_api_keyrI   U   sD   € Ü�eœSÔ!©ØÜ—f‘f˜_¨b°%Ó8€HÙØÙÔ4°XÔ>ØˆÜ�hÓÐr9   ÚmetadataÚapplied_guardrailsÚbatch_modelsÚbatch_successful_requestsÚbatch_failed_requestsÚmcp_tool_call_metadataÚvector_store_request_metadataÚguardrail_informationÚusage_objectÚmodel_map_informationÚcold_storage_object_keyÚlitellm_overhead_time_msÚcost_breakdownÚlitellm_call_idÚautorouter_savingsc                 ó8  — | €ut        d)i dd “dd “dd “dd “dd “dd “dd “dd “d	d “d
d “dd “dd “dd“dd “dd “dd “dd “dd “dd “dd “dd “dd “dd “dd “dd “d|
“dd “dd “dd “dd “d d “d!d “d"d “d#|“d$d “d%|“ŽS t        j                  d&t        t	        | j                  «       «      «      z   «       t        d)i t         j                  D �ci c]  }|| j                  |«      “Œ c}¤Ž}|j                  d«      }| j                  d'«      }t        |t        «      xr t        |«      xr ||k(  }t        ||¬(«      |d<   ||d<   ||d<   ||d<   ||d<   ||d<   t        |«      |d<   t        |«      |d<   ||d<   |	|d<   |
|d<   ||d<   ||d!<   ||d#<   ||d%<   |S c c}w )*NÚuser_api_keyÚuser_api_key_aliasÚuser_api_key_team_idÚuser_api_key_project_idÚuser_api_key_project_aliasÚuser_api_key_org_idÚuser_api_key_user_idÚuser_api_key_team_aliasÚspend_logs_metadataÚrequester_ip_addressÚadditional_usage_valuesrK   ÚstatusÚsuccessÚerror_informationÚproxy_server_requestrL   rM   rN   rO   rP   rS   rR   rQ   Úinternal_call_originÚeval_informationrT   rU   Úattempted_retriesÚmax_retriesÚattempted_fallbacksÚoriginal_model_grouprV   Úcompression_savingsrX   Úlitellm_gateway_injected_cacherW   z;getting payload for SpendLogs, available keys in metadata: Úuser_api_key_hashr@   © )r   r   ÚdebugrE   ÚlistÚkeysÚ__annotations__ÚgetrD   r?   rI   Ú0_get_vector_store_request_for_spend_logs_payloadÚ._sanitize_guardrail_information_for_spend_logs)rJ   rK   rL   rM   rN   rO   rP   rQ   rR   rS   rT   rU   rV   rW   rX   ÚkeyÚclean_metadataÚ_raw_keyÚ_trusted_hashÚ_already_redacteds                       r1   Ú_get_spend_logs_metadatar   `   sï  € ð" ÐÜ ò %
Ùð%
á#ð%
ñ "&ð%
ñ %)ð	%
ñ
 (,ð%
ñ !%ð%
ñ "&ð%
ñ %)ð%
ñ !%ð%
ñ "&ð%
ñ %)ð%
ñ  $ð%
ñ %ð%
ñ #ð%
ñ "&ð%
ñ  ð!%
ñ" '+ð#%
ñ$ #'ð%%
ñ& $(ð'%
ñ( +/ð)%
ñ* #'ð+%
ñ, ð-%
ñ. #'ð/%
ñ0 "&ð1%
ñ2 "ð3%
ñ4 %<ð5%
ñ6 &*ð7%
ñ8 #ð9%
ñ: ð;%
ñ< !%ð=%
ñ> "&ð?%
ñ@  ðA%
ñB !%ðC%
ñD  2ðE%
ñF ,0ðG%
ñH ,ðI%
ð %	
ôL ×ÑØEÌÌDÐQY×Q^ÑQ^ÓQ`ÓLaÓHbÑbôô
 .ÑvÔSd×StÑStÖ0uÈC°°h·l±lÀ3Ó6GÑ1GÒ0uÑv€NØ$×(Ñ(¨Ó8€HØ#Ÿ<™<Ð(;Ó<€Mä�=¤#Ó&ÒpÔ+CÀMÓ+RÒpÐWdÐhpÑWpð ô &<¸HÐWhÔ%i€N�>Ñ"Ø+=€NÐ'Ñ(Ø%1€N�>Ñ"Ø2K€NÐ.Ñ/Ø.C€NÐ*Ñ+Ø/E€NÐ+Ñ,Ü6fØ%ó7€NÐ2Ñ3ô /]Ð]rÓ.s€NÐ*Ñ+Ø%1€N�>Ñ"Ø.C€NÐ*Ñ+Ø0G€NÐ,Ñ-Ø1I€NÐ-Ñ.Ø'5€NÐ#Ñ$Ø+=€NÐ'Ñ(Ø(7€NÐ$Ñ%àÐùò1 1vs   Ã	FÚ_batch_costÚBATCH_COST_REQUEST_ID_SUFFIXÚ	call_typeÚresponse_objÚkwargsc                 ó(  — |j                  d«      }|j                  d«      t        |t        «      r|j                  d«      nd |j                  d«      f}t        d„ |D «       d «      }|�'| t        j
                  j                  k(  r
|› t        › �S |S )NÚstandard_logging_objectÚidrW   c              3   óH   K  — | ]  }t        |t        «      sŒ|sŒ|–— Œ y ­wr<   )rD   rE   )Ú.0Ú	candidates     r1   ú	<genexpr>z$get_spend_logs_id.<locals>.<genexpr>Ã   s   è ø€ Ò^�y´ZÀ	Ì3Õ5OÒT]ŒÑ^ùs   ‚"˜"›")rw   rD   ÚdictÚnextr   Úaretrieve_batchr:   r�   )r‚   rƒ   r„   Ústandard_logging_payloadÚcandidate_idsÚresolved_ids         r1   Úget_spend_logs_idr’   »   sš   € Ø%Ÿz™zÐ*CÓDÐà×Ñ˜ÓÜ.8Ð9QÔSWÔ.XÐ ×$Ñ$ TÔ*Ð^bØ�
‰
Ð$Ó%ð€Mô
 Ù^ MÔ^Ð`dó€Kð Ð 9´	×0IÑ0I×0OÑ0OÒ#OØ�Ô;Ð<Ð=Ð=ØÐr9   Úresponse_obj_dictc                 ó~  — d}t        |t        «      rd|v r|j                  d«      }|sLt        | d«      r@| j                  }t        |d«      r|j                  «       }nt        |d«      rt        |«      }|�Et        |t        «      r.ddddœ}|j                  «       D ]
  \  }}|||<   Œ d|vrd|d<   |S dddddœS i S )	a»  
    Extract usage information for OCR/AOCR calls.

    OCR responses use usage_info (with pages_processed) instead of token-based usage.

    Args:
        response_obj: The raw response object (can be dict, BaseModel, or other)
        response_obj_dict: Dictionary representation of the response object

    Returns:
        A dict with prompt_tokens=0, completion_tokens=0, total_tokens=0,
        and pages_processed from usage_info.
    NÚ
usage_infoÚ
model_dumpÚ__dict__r   )Úprompt_tokensÚcompletion_tokensÚtotal_tokensÚpages_processed)r˜   r™   rš   r›   )rD   rŒ   rw   Úhasattrr•   r–   ÚvarsÚitems)rƒ   r“   r•   Úresultrz   r:   s         r1   Ú_extract_usage_for_ocr_callr    Ê   sõ   € ð €Jô Ð#¤TÔ*¨|Ð?PÑ/PØ&×*Ñ*¨<Ó8ˆ
ñ œ' ,°Ô=Ø!×,Ñ,ˆ
Ü�:˜|Ô,Ø#×.Ñ.Ó0‰JÜ�Z Ô,Ü˜jÓ)ˆJð Ðä�j¤$Ô'à!"Ø%&Ø !ñˆFð )×.Ñ.Ó0ò $‘
��UØ#��s’ð$ð !¨Ñ.Ø,-�Ð(Ñ)ØˆMð "#Ø%&Ø !Ø#$ñ	ð ð ˆ	r9   .c                 óà   — | €y| j                  d«      }t        |t        «      rt        |j                  d«      «      }|r|S | j                  d«      }t        |t        «      syt	        |«      S )z`Model access groups that authorized this request, as stamped onto request metadata at auth time.rr   r†   Úrequest_model_access_groupsÚlitellm_params)rw   rD   r   r   r   )r„   r�   Úfrom_payloadr£   s       r1   Úget_request_model_access_groupsr¥     sl   € à€~Øà&,§j¡jÐ1JÓ&KÐÜÐ*¬GÔ4Ü8Ð9Q×9UÑ9UÐVsÓ9tÓuˆÙØÐà"ŸJ™JÐ'7Ó8€NÜ�n¤gÔ.ØÜ:¸>ÓJÐJr9   r�   Úfield)Úmodel_idÚmodel_groupÚapi_baseÚcustom_llm_providerc                 ó2   — | €y| j                  |«      xs dS )NrC   ©rw   )r�   r¦   s     r1   Ú_sl_attribution_fallbackr­     s#   € ð  Ð'ØØ#×'Ñ'¨Ó.Ò4°"Ð4r9   c                 óJ  — | €i } |€i }n-t        |t        «      st        |t        «      sdt        |«      i}| j	                  di «      }t        | «      }| j	                  d|«      }| j	                  d«      }| j	                  dd«      }t        |t        «      r|}	n#t        |t        «      r|j                  «       }	ni }	i }
|dv rt        ||	«      }
n[t        |||	«      sN|	j	                  dd «      xs i }t        |t        j                  «      rt        |«      }
nt        |t        «      r|}
| j	                  d	«      }|
s*t        |t        j                  «      r|j                  «       }
t        |xs d
|	| «      }t        t        d z  | j	                  dd «      «      }t        |«      }|j	                  dd«      }d}d}d}|�6|j	                  dd«      }|j	                  dd«      }|j	                  dd«      }|j	                  d«      }t        |t        «      xr t        |«      xr ||k(  }t!        ||¬«      xs d}|�?|xs# t!        |d   j	                  d«      d¬«      xs d}|xs |d   j	                  d«      }t        |j	                  dg «      t"        «      rt%        |j	                  dg «      «      nd}|�|j	                  d«      �t%        |d   «      }|j	                  di «      j	                  dd«      xs t'        |d«      }|j	                  dd«      xs t'        |d«      }|j	                  dd«      xs t'        |d«      }d }|�#|j	                  di «      }|j	                  d «      }t)        ||�|d   j	                  d!d «      nd |�"|j	                  di «      j	                  d"d «      nd |�"|j	                  di «      j	                  d#d «      nd |�"|j	                  di «      j	                  d$d «      nd |�|d   j	                  d%d «      nd |�|d   j	                  d&d «      nd |�|d   j	                  d'd «      nd |�|d(   nd |�|j	                  d)d «      n|�|j	                  d*d «      nd |�|d   j	                  d+d «      nd ||�|j	                  d,d «      nd |�|j	                  d-d «      nd t        t        d z  | j	                  d.«      xs |j	                  d.«      «      ¬/«      }g d0¢}i }|
j+                  «       D ]=  \  }} ||vsŒt        | t        «      r| j                  «       } |j-                  || i«       Œ? |j	                  d1«      }!t        |!t        «      s2|j	                  d'«      }"t        |"t        «      r|"j	                  d1«      }!t        |!t        «      rqd2|vr+|!j	                  d3«      }#t        |#t.        «      r
|#dkD  r|#|d2<   d4|vr>|!j	                  d5«      xs |!j	                  d6«      }$t        |$t.        «      r
|$dkD  r|$|d4<   ||d7<   t        j0                  � t        j0                  j2                  d]i | ¤Ž}%nd8}%|du rdd l}&|› d9|&j5                  «       › �}d }'|j	                  d%«      }(|(�|(j	                  d:d «      }'| j	                  d;«      xs |j	                  d;«      })| j	                  d<«      xs t'        |d<«      xs d }*t        t        | j	                  d=«      xs d«      }+|�|j	                  d=«      nd xs t7        |+|*|xs i «      },	 t9        d]i d>t        |«      “d|xs d“d?t        |«      “dt        |«      “d@t;        |«      “dAt;        |«      “dBt;        |«      “d=|,“dC|j	                  dDd«      xs d“dE|j	                  dFd«      xs d“dG|j	                  dH«      xs d“dt%        |«      “dI|%“dJ| j	                  dKd«      “d|
j	                  d|«      “d|
j	                  d|«      “d|
j	                  d|«      “d|“dL|xs d“d|“d|“d|“dM|'“d;|)“dN|j	                  dNd «      “d<|*xs d“dOt=        ||¬P«      “dQt?        || ¬R«      “dStA        ||| ¬T«      “dUtC        | |¬V«      “dWtE        ||«      “dXtG        |¬Y«      “Ž}-tI        jJ                  dZ|-j	                  d>«      |-j	                  d=«      |-j	                  dJ«      «       ~	~
~~|-S # tL        $ r}.tO        d[t        |.«      |.¬\«       |.‚d }.~.ww xY w)^NrŸ   r£   Úcompletion_start_timer‚   Ú	cache_hitF)ÚocrÚaocrÚusageÚcombined_usage_objectÚacompletionr†   rZ   rC   r   r˜   r™   rš   rq   r@   rJ   TÚuser_api_key_end_user_idÚtagsz[]Úrequest_tagsÚ
model_infor‡   r§   r¨   r©   Úhidden_paramsrU   rK   rL   rM   rN   rO   rP   rR   rS   rQ   Ú&standard_logging_guardrail_informationrT   rV   rX   rW   )rK   rL   rM   rN   rO   rP   rR   rS   rQ   rT   rU   rV   rX   rW   )r™   r˜   rš   Úprompt_tokens_detailsÚcache_read_input_tokensÚcached_tokensÚcache_creation_input_tokensÚcache_write_tokensÚcache_creation_tokensrd   z	Cache OFFÚ
_cache_hitÚnamespaced_tool_nameÚagent_idrª   ÚmodelÚ
request_idr3   Ú	startTimeÚendTimeÚcompletionStartTimeÚuserr`   Úteam_idr\   Úorganization_idr_   Ú	cache_keyÚspendÚresponse_costÚend_userÚmcp_namespaced_tool_namerc   Úmessages)r�   rJ   Úresponse)Úpayloadr„   rh   )rJ   r£   r„   Ú
session_id)r„   r�   Úrequest_duration_msre   )rJ   zBSpendTable: created payload - request_id: %s, model: %s, spend: %sz$Error creating spendlogs object - %s)Úexcrr   )(rD   r
   rŒ   rE   rw   r   r–   r    r   ÚlitellmÚUsager’   r	   r#   r'   r?   rI   rt   r   r­   r   rž   Úupdater-   ÚcacheÚget_cache_keyÚtimer   r   Ú_ensure_datetime_utcÚ$_get_messages_for_spend_logs_payloadÚ$_get_response_for_spend_logs_payloadÚ0_get_proxy_server_request_for_spend_logs_payloadÚ_get_session_id_for_spend_logÚ_get_request_duration_msÚ_get_status_for_spend_logr   rs   Ú	Exceptionr   )/r„   rƒ   Ú
start_timeÚend_timer£   rJ   r¯   r‚   r°   r“   r³   Ú_usageÚ_combined_usager‡   r�   Úend_user_idr3   Ústandard_logging_prompt_tokensÚ"standard_logging_completion_tokensÚstandard_logging_total_tokensr}   Ú_key_already_redactedr¸   Ú	_model_idÚ_model_groupÚ	_api_baserU   rº   r{   Úspecial_usage_fieldsrd   ÚkÚvr¼   rR   r¾   rÀ   rÍ   rÝ   rÑ   rO   rÄ   rª   Ú	raw_modelÚ
model_namerÔ   Úes/                                                  r1   Úget_logging_payloadrø     s~
  € Ø€~ØˆàÐØ‰Ü˜¤iÔ0¼ÀLÔRVÔ9WØ ¤# lÓ"3Ð4ˆà"ŸJ™JÐ'7¸Ó<€NÜ6°vÓ>€HØ#)§:¡:Ð.EÀxÓ#PÐØ—z‘z +Ó.€IØ—z‘z +¨uÓ5€Iô �,¤Ô%Ø(ÑÜ	�L¤)Ô	,Ø(×3Ñ3Ó5ÑàÐð €EØ�OÑ#Ü+¨LÐ:KÓL‰Ü+¨I°xÐARÔSà)×-Ñ-¨g°tÓ<ÒBÀˆÜ�fœgŸm™mÔ,Ü˜“L‰EÜ˜¤Ô%ØˆEð
 $ŸZ™ZÐ(?Ó@€OÙ”Z ´·±Ô?Ø×*Ñ*Ó,ˆä	˜9Ò5¨Ð7HÈ&Ó	Q€BÜ&*Ô+AÀDÑ+HÈ&Ï*É*ÐUnÐptÓJuÓ&vÐä3°NÓC€Kà�l‰l˜>¨2Ó.€Gà*+Ð"Ø./Ð&Ø)*Ð!ØÐ+Ø)A×)EÑ)EÀoÐWXÓ)YÐ&Ø-E×-IÑ-IÐJ]Ð_`Ó-aÐ*Ø(@×(DÑ(DÀ^ÐUVÓ(WÐ%Ø—L‘LÐ!4Ó5€Mä�=¤#Ó&ÒoÔ+CÀMÓ+RÒoÐWdÐhoÑWoð ô % WÐ?TÔUÒ[ÐY[€Gð 	!Ð,ð ò Ü%Ø(¨Ñ4×8Ñ8Ð9LÓMÐ`dôòð ð 	ð "ÒiÐ%=¸jÑ%I×%MÑ%MÐNhÓ%iˆÜ;EÀhÇlÁlÐSYÐ[]ÓF^Ô`dÔ;e”:˜hŸl™l¨6°2Ó6Ô7Ðko€Là Ð,Ð1I×1MÑ1MÈnÓ1]Ð1iä!Ð":¸>Ñ"JÓKˆà—|‘| L°"Ó5×9Ñ9¸$ÀÓCò ÔG_Ø  *óH€Ið #Ÿ,™, }°bÓ9ò Ô=UØ  -ó>€Lð &×)Ñ)¨*°bÓ9ò Ô=UØ  *ó>€Ið
  $ÐØÐ+Ø7×;Ñ;¸OÈRÓPˆØ#0×#4Ñ#4Ð5OÓ#PÐ ô .Øð (Ð3ð % ZÑ0×4Ñ4Ð5IÈ4ÔPàð (Ð3ð %×(Ñ(¨¸"Ó=×AÑAÀ.ÐRVÔWàð (Ð3ð %×(Ñ(¨¸"Ó=×AÑAÐB]Ð_cÔdàð (Ð3ð %×(Ñ(¨¸"Ó=×AÑAÐBYÐ[_Ô`àð (Ð3ð % ZÑ0×4Ñ4Ð5MÈtÔTàð (Ð3ð % ZÑ0×4Ñ4Ð5TÐVZÔ[àð (Ð3ð % ZÑ0×4Ñ4°^ÀTÔJàð BZÐAeÐ$Ð%<Ò=Ðkoð (Ð3ð %×(Ñ(Ð)@À$ÔGàRZÐRf�(—,‘,ÐGÈÔNÐlpð (Ð3ð % ZÑ0×4Ñ4Ð5NÐPTÔUàà!9àD\ÐDhÐ$×(Ñ(Ð)9¸4Ô@Ðnrð IaÐHlÐ$×(Ñ(Ð)=¸tÔDÐrväÜ�$‰JØ�J‰JÐ(Ó)ÒR¨^×-?Ñ-?Ð@QÓ-Ró
ôs=€Nò~ #YÐØ ÐØ—‘“ò 3‰ˆˆ1ØÐ(Ò(Ü˜!œYÔ'Ø—L‘L“N�Ø#×*Ñ*¨A¨q¨6Õ2ð	3ð
 4×7Ñ7Ð8OÓPÐÜÐ+¬TÔ2Ø,×0Ñ0°Ó@ˆÜ�l¤DÔ)Ø$0×$4Ñ$4Ð5LÓ$MÐ!ÜÐ'¬Ô.Ø$Ð,CÑCØ#8×#<Ñ#<¸_Ó#MˆMÜ˜-¬Ô-°-À!Ò2CØERÐ'Ð(AÑBØ(Ð0GÑGØ(=×(AÑ(AÐBVÓ(Wò )Ð[p×[tÑ[tØ'ó\Ðô Ð,¬cÔ2Ð7IÈAÒ7MØI[Ð'Ð(EÑFØ0G€NÐ,Ñ-ä‡}�}Ð Ü—M‘M×/Ñ/Ñ9°&Ñ9‰	àˆ	Ø�DÑÛàˆt�:˜dŸi™i›k˜]Ð+ˆà#ÐØGU×GYÑGYÐZrÓGsÐØÐ)Ø#9×#=Ñ#=Ð>TÐVZÓ#[Ð ð #)§*¡*¨ZÓ"8Ò"T¸H¿L¹LÈÓ<T€Hà�
‰
Ð(Ó)ò 	Ü#Ð$<Ð>SÓTò	àð ô
 œC §¡¨GÓ!4Ò!:¸Ó;€Ià1IÐ1UÐ ×$Ñ$ WÔ-Ð[_òPä	 	Ð+>ÀÂÈBÓ	Oð ð:Ü+;ò *,
Ü˜2”wð*,
à’o 2øð*,
ô ˜”Lð*,
ô ˜)”nð	*,
ô
 +¨:Ô6ð*,
ô )¨Ô2ð*,
ô !5Ð5JÔ Kð*,
ñ ð*,
ð —‘Ð4°bÓ9Ò?¸Røð*,
ð —L‘LÐ!7¸Ó<ÒBÀøð*,
ð %ŸL™LÐ)>Ó?ÒEÀ2øð*,
ô   Ô/ð*,
ñ  ð*,
ð —*‘*˜_¨aÔ0ð*,
ð Ÿ™ >Ð3PÔQð*,
ð   Ÿ)™) OÐ5SÔTð!*,
ð" $Ÿi™iÐ(;Ð=_Ô`ð#*,
ñ$ &ð%*,
ð& !Ò& Bøð'*,
ñ( ð)*,
ñ* %ð+*,
ñ, ð-*,
ñ. &>ð/*,
ñ0 ð1*,
ð2 "0×!3Ñ!3Ð4JÈDÔ!Qð3*,
ð4 !4Ò 9°røð5*,
ô6 :Ø)AÈHõð7*,
ô< :ÐBZÐciÕjð=*,
ô> "RØ!°.Èõ"ð?*,
ôD 5ØØ)AõðE*,
ôL !9¸ÀXÔ NðM*,
ôN -Ø!õðO*,
ˆôX 	×"Ñ"ØPØ�K‰K˜Ó%Ø�K‰K˜Ó Ø�K‰K˜Ó ô		
ð ˜u nÐ6MàˆøÜò ÜÐ>ÄÀAÃÈAÕNØˆûðús   Ü0G
c; ã;	d"ädäd"c                 óð   — ddl m} |�+|j                  d«      �t        |j                  d«      «      S | j                  d«      �t        | j                  d«      «      S t        |j	                  «       «      S )zy
    Get the session id for the spend log.

    This ensures each spend log is associated with a unique session id.

    r   )ÚuuidÚtrace_idÚlitellm_trace_id)Úlitellm._uuidrú   rw   rE   Úuuid4)r„   r�   rú   s      r1   râ   râ   *  so   € õ #àÐ+Ð0H×0LÑ0LÈZÓ0XÐ0dÜÐ+×/Ñ/°
Ó;Ó<Ð<ð ‡z�zÐ$Ó%Ð1Ü�6—:‘:Ð0Ó1Ó2Ð2ô ˆt�z‰z‹|ÓÐr9   ræ   rç   c                 ó`   — 	 t        || z
  j                  «       dz  «      S # t        $ r Y yw xY w)zBCompute request duration in milliseconds from start and end times.iè  N)r-   Útotal_secondsrå   )ræ   rç   s     r1   rã   rã   A  s7   € ðÜ�H˜zÑ)×8Ñ8Ó:¸TÑAÓBÐBøÜò Ùðús   ‚! ¡	-¬-Ú	timestampc                 óD   — | j                  t        j                  «      } | S )z#Helper to ensure datetime is in UTC)Ú
astimezoner   Úutc)r  s    r1   rÞ   rÞ   I  s   € à×$Ñ$¤X§\¡\Ó2€IØÐr9   Ú
start_dateÚend_daterË   Úprisma_clientc              ƒ   ój   K  — d}|j                   j                  || ||«      ƒ d {  –—† }|€g S |S 7 Œ
­w)Na­  
    WITH SpendByModelApiKey AS (
        SELECT
            date_trunc('day', sl."startTime") AS group_by_day,
            COALESCE(tt.team_alias, 'Unassigned Team') AS team_name,
            sl.model,
            sl.api_key,
            SUM(sl.spend) AS model_api_spend,
            SUM(sl.total_tokens) AS model_api_tokens
        FROM
            "LiteLLM_SpendLogs" sl
        LEFT JOIN
            "LiteLLM_TeamTable" tt
        ON
            sl.team_id = tt.team_id
        WHERE
            sl."startTime" >= ($1::timestamptz AT TIME ZONE 'UTC')
            AND sl."startTime" <  (($2::timestamptz + INTERVAL '1 day') AT TIME ZONE 'UTC')
            AND ($3::text IS NULL OR sl.team_id = $3)
        GROUP BY
            date_trunc('day', sl."startTime"),
            tt.team_alias,
            sl.model,
            sl.api_key
    )
        SELECT
            group_by_day,
            jsonb_agg(jsonb_build_object(
                'team_name', team_name,
                'total_spend', total_spend,
                'metadata', metadata
            )) AS teams
        FROM (
            SELECT
                group_by_day,
                team_name,
                SUM(model_api_spend) AS total_spend,
                jsonb_agg(jsonb_build_object(
                    'model', model,
                    'api_key', api_key,
                    'spend', model_api_spend,
                    'total_tokens', model_api_tokens
                )) AS metadata
            FROM
                SpendByModelApiKey
            GROUP BY
                group_by_day,
                team_name
        ) AS aggregated
        GROUP BY
            group_by_day
        ORDER BY
            group_by_day;
    ©ÚdbÚ	query_raw)r  r  rË   r  Ú	sql_queryÚdb_responses         r1   Úget_spend_by_teamr  O  sH   è ø€ ð5€Iðn  -×/Ñ/×9Ñ9¸)ÀZÐQYÐ[bÓc×c€KØÐØˆ	àÐð	 dús   ‚$3¦1§3Úcustomer_idc              ƒ   ól   K  — d}|j                   j                  || |||«      ƒ d {  –—† }|€g S |S 7 Œ
­w)Na_  
    WITH SpendByModelApiKey AS (
        SELECT
            date_trunc('day', sl."startTime") AS group_by_day,
            COALESCE(tt.team_alias, 'Unassigned Team') AS team_name,
            sl.end_user AS customer,
            sl.model,
            sl.api_key,
            SUM(sl.spend) AS model_api_spend,
            SUM(sl.total_tokens) AS model_api_tokens
        FROM 
            "LiteLLM_SpendLogs" sl
        LEFT JOIN 
            "LiteLLM_TeamTable" tt 
        ON 
            sl.team_id = tt.team_id
        WHERE
            sl."startTime" >= ($1::timestamptz AT TIME ZONE 'UTC')
            AND sl."startTime" <  (($2::timestamptz + INTERVAL '1 day') AT TIME ZONE 'UTC')
            AND sl.team_id = $3
            AND sl.end_user = $4
        GROUP BY
            date_trunc('day', sl."startTime"),
            tt.team_alias,
            sl.end_user,
            sl.model,
            sl.api_key
    )
        SELECT
            group_by_day,
            jsonb_agg(jsonb_build_object(
                'team_name', team_name,
                'customer', customer,
                'total_spend', total_spend,
                'metadata', metadata
            )) AS teams_customers
        FROM (
            SELECT
                group_by_day,
                team_name,
                customer,
                SUM(model_api_spend) AS total_spend,
                jsonb_agg(jsonb_build_object(
                    'model', model,
                    'api_key', api_key,
                    'spend', model_api_spend,
                    'total_tokens', model_api_tokens
                )) AS metadata
            FROM 
                SpendByModelApiKey
            GROUP BY
                group_by_day,
                team_name,
                customer
        ) AS aggregated
        GROUP BY
            group_by_day
        ORDER BY
            group_by_day;
    r	  )r  r  rË   r  r  r  r  s          r1   Úget_spend_by_team_and_customerr  “  sK   è ø€ ð;€Iðz  -×/Ñ/×9Ñ9¸)ÀZÐQYÐ[bÐdoÓp×p€KØÐØˆ	àÐð	 qús   ‚%4§2¨4c                 ó¦   — t        «       r8| �6| j                  dd«      }|dk(  r| j                  d«      }|�	 t        |«      S y# t        $ r Y yw xY w)Nr‚   rC   Ú
_arealtimerÒ   ú{})Ú1_should_store_prompts_and_responses_in_spend_logsrw   r   rå   )r�   rJ   r‚   rÒ   s       r1   rß   rß   Þ  si   € ô 9Ô:Ø#Ð/Ø7×;Ñ;¸KÈÓLˆIØ˜LÒ(Ø":×">Ñ">¸zÓ"J�ØÐ'ð$Ü)¨(Ó3Ð3ð øô %ò $Ù#ð$ús   ¸
A Á	AÁAÚsecret_fieldsÚ_SENSITIVE_REQUEST_BODY_KEYSÚrequest_bodyÚvisitedÚmax_string_length_prompt_in_dbc                 ó.  ‡‡‡‡‡— ddl mŠmŠ ‰€
t        «       Š‰€
t	        «       Št        | «      }|‰v ri S ‰j                  |«       dt        dt        fˆˆˆˆˆfd„Š| j                  «       D ��ci c]  \  }}|t        vsŒ| ‰|«      “Œ c}}S c c}}w )am  
    Recursively sanitize request body to prevent logging large base64 strings or other large values.
    Truncates strings longer than MAX_STRING_LENGTH_PROMPT_IN_DB characters and handles nested dictionaries.

    Also strips keys listed in _SENSITIVE_REQUEST_BODY_KEYS (e.g. secret_fields
    which contains raw HTTP headers including Authorization tokens).
    r   )r   r   r:   r(   c                 ó¤  •— t        | t        «      rt        | ‰‰«      S t        | t        «      r| D �cg c]
  } ‰|«      ‘Œ c}S t        | t        «      rvt        | «      ‰kD  rfd}d}t        ‰|z  «      }t        ‰|z  «      }||z   }|‰kD  r‰|z
  }t        | «      ‰k  r| S t        | «      |z
  }| d | › d‰	› d|› d‰
› d| | d  › �	}|S | S | S c c}w )NgffffffÖ?gÍÌÌÌÌÌä?z... (z	 skipped z chars. z) ...)rD   rŒ   Ú-_sanitize_request_body_for_spend_logs_payloadrt   rE   Úlenr-   )r:   ÚitemÚstart_ratioÚ	end_ratioÚstart_charsÚ	end_charsÚ
total_keepÚskipped_charsÚtruncated_valuer   r   Ú_sanitize_valuer  r  s            €€€€€r1   r'  zF_sanitize_request_body_for_spend_logs_payload.<locals>._sanitize_value  s  ø€ Ü�eœTÔ"Ü@ÀÈÐQoÓpÐpÜ˜œtÔ$Ø6;Ö<¨d‘O DÕ)Ò<Ð<Ü˜œsÔ#Ü�5‹zÐ:Ò:ð &*�Ø#'�	ô &)Ð)GÈ+Ñ)UÓ%V�ÜÐ >ÀÑ JÓK�	ð %0°)Ñ$;�
ØÐ >Ò>Ø >ÀÑ L�Iô �u“:Ð!?Ò?Ø �Lô (+¨5£z°JÑ'>�ð ˜\˜kÐ*Ð+ØÐ;Ð<¸IÀmÀ_ÐT\Ø;Ð<¸EØ˜i˜Z˜[Ð)Ð*ð,ð  ð 'Ð&ØˆLØˆùòC =s   ³C)
Úlitellm.constantsr   r   Úsetr2   r‡   Úaddr   rž   r  )	r  r  r  Úobj_idró   rô   r   r   r'  s	    ``   @@@r1   r  r  ò  s˜   ü€ ÷ð
 €Ü“%ˆØ%Ð-Ü)LÓ)NÐ&ô �|Ó$€FØ�ÑØˆ	Ø‡K�K�Ôð%œsð %¤s÷ %ñ %ðN /;×.@Ñ.@Ó.B×l¡d a¨ÀaÔOkÒFkˆA‰˜qÓ!Ñ!ÓlÐlùÓls   Á1BÂB)ÚinputrÒ   ÚpromptÚ_ERROR_MESSAGE_PROMPT_LEAK_KEYS)Úinput_valueÚ_ERROR_MESSAGE_ASSIGN_LEAK_KEYSz(?:['\"](?:ú|z)['\"]\s*:\s*|\b(?:z	)\s*=\s*)Ú_SENSITIVE_KEY_START_PATTERNÚtextÚstartÚquotec                 óx   — t        | «      }|dz   }||k  r%| |   }|dk(  r|dz  }Œ||k(  r|dz   S |dz  }||k  rŒ%y)z³
    Given ``text[start] == quote`` (``'`` or ``"``), return the index just
    past the matching close quote, honoring backslash escapes. Returns
    ``-1`` if unterminated.
    é   ú\é   éÿÿÿÿ)r  )r3  r4  r5  ÚnÚiÚcs         r1   Ú_scan_quoted_string_endr>  P  s`   € ô �4‹y€AØ�‰	€AØ
ˆaŠ%Ø�‰GˆØ�Š9Ø�‰FˆAØØ�Š:Ø�q‘5ˆLØ	ˆQ‰ˆð ˆa‹%ð r9   c                 ó  — t        | «      }||k\  ry| |   }|dv rt        | ||«      S |dk(  rd}n	|dk(  rd}nyd}|}||k  rI| |   }|dv rt        | ||«      }|dk(  ry|}Œ$||k(  r|dz  }n||k(  r|dz  }|dk(  r|dz   S |dz  }||k  rŒIy)	u  
    Given ``text[start]`` is ``[``, ``{``, ``'`` or ``"``, return the index
    just past the matching close, accounting for nested brackets and
    quoted strings (with escape sequences). Returns ``-1`` if the
    structure is unterminated.

    Implemented iteratively (no self-recursion): the bracket scanner
    inlines a quote-skip helper rather than re-entering itself, since
    JSON-style values cannot contain another bracket *as a first char*
    inside a quoted string â€” only the quote-skip case can occur.
    r:  )ú'ú"ú[ú]ú{ú}r   r7  )r  r>  )	r3  r4  r;  ÚfirstÚcloseÚdepthr<  r=  Úends	            r1   Ú_scan_balanced_value_endrJ  c  sÚ   € ô �4‹y€AØ�‚zØØ˜‘;€EØ�
ÑÜ& t¨U°EÓ:Ð:Ø�‚|Ø‰Ø	�#ŠØ‰àØ€EØ€AØ
ˆaŠ%Ø�‰GˆØ�
‰?Ü)¨$°°1Ó5ˆCØ�bŠyØØˆAØØ�Š:Ø�Q‰J‰EØ�%ŠZØ�Q‰JˆEØ˜ŠzØ˜1‘u�Ø	ˆQ‰ˆð ˆa‹%ð r9   c                 óÆ  — | s| S dt         › d�}g }t        | «      }d}||k  r¯t        j                  | |«      }|s|j	                  | |d «       n‚|j	                  | ||j                  «        «       |j                  «       }||k\  rnJ| |   }|dv r9t        | |«      }|dk(  r|j	                  |«       |}n|j	                  |«       |}n|}||k  rŒ¯dj                  |«      S )uê  
    Strip echoed request input from provider error strings.

    Provider validation errors (e.g. OpenAI ``RateLimitError`` carrying 178
    pydantic validation errors, each with its own ``'input': [...]`` field)
    embed the full request body in their message. When prompts must not be
    stored in spend logs, that echo is a back-door leak.

    Two leak shapes are handled:

    - Quoted-key form â€” ``"<key>": <value>`` where ``key`` is ``input``,
      ``messages`` or ``prompt`` (covers JSON bodies, Python dict-reprs,
      and ``/v1/completions`` payloads).
    - Assignment form â€” ``input_value=<value>`` from Pydantic v2 validation
      errors, which render the offending value as a Python repr inside
      ``[type=..., input_value=..., input_type=...]``.

    The value scan understands nested ``[]`` / ``{}`` and quoted strings,
    so multi-modal payloads (``'messages': [{'content': [{...}]}]``) and
    user text containing brackets (``"secret[123"``) are handled correctly.
    rA  r   N)rB  rD  r@  rA  r:  rC   )r   r  r2  ÚsearchÚappendrI  rJ  Újoin)	r3  Ú	redactionÚoutr;  ÚposÚmÚv_startrF  Úv_ends	            r1   Ú$_redact_prompt_leaks_in_error_stringrU  �  sú   € ñ, ØˆØÔ4Ð5°QÐ7€IØ€CÜ�4‹y€AØ
€CØ
�Š'Ü(×/Ñ/°°cÓ:ˆÙØ�J‰J�t˜C˜D�zÔ"ØØ�
‰
�4˜˜aŸe™e›gÐ&Ô'Ø—%‘%“'ˆØ�aŠ<ØØ�W‘ˆØÐ(Ñ(Ü,¨T°7Ó;ˆEØ˜Š{ð —
‘
˜9Ô%Ø�ØØ�J‰J�yÔ!Ø‰Cð ˆCð/ �‹'ð0 �7‰7�3‹<Ðr9   c                 ó¦   — | �
t        «       r| S t        | t        «      r| gn| }|D �cg c]  }t        |t        «      sŒt        |«      ‘Œ  c}S c c}w )a
  
    When ``store_prompts_in_spend_logs`` is False, redact prompt-carrying fields
    (``guardrail_request``, ``guardrail_response``, ``match_details``,
    ``classification``) before they land in ``LiteLLM_SpendLogs.metadata``.

    Guardrail hooks may echo the LLM request payload back into
    ``guardrail_response``, and two first-party hooks
    (``block_code_execution``, ``litellm_content_filter``) inline user-prompt
    substrings into ``match_details`` / ``classification`` too, so the flag
    must cover all four fields. Every other typed field on the entry (name,
    provider, mode, status, timings, action, violation_categories, risk_score,
    masked_entity_count, ...) is preserved so guardrail dashboards keep
    working.

    ``guardrail_information`` is typed ``Optional[List[...]]`` but at least
    one writer (``xecguard``) assigns a bare dict, so normalize to a list
    here to match OTEL's defensive read pattern; otherwise iteration would
    yield the dict's keys and crash the whole spend-log write.
    )r  rD   rŒ   Ú(_redact_prompt_fields_in_guardrail_entry)rQ   ÚentriesÚentrys      r1   ry   ry   Æ  sS   € ð, Ð$Ô(YÔ([Ø$Ð$Ü0:Ð;PÔRVÔ0WÐ+Ñ,Ð]r€GØIPÖlÀÔT^Ð_dÔfjÕTkÔ4°UÕ;ÒlÐlùÒls
   ¨A¾A)Úguardrail_requestÚguardrail_responseÚmatch_detailsÚclassificationÚ!_PROMPT_CARRYING_GUARDRAIL_FIELDS)Útokens_beforeÚtokens_afterÚtokens_savedÚcompression_ratioÚ_NUMERIC_COMPRESSION_STAT_KEYSr[  c           	      óÞ   — t        | t        «      sy | j                  «       D ��ci c]6  \  }}|t        v r)t        |t        t
        f«      rt        |t        «      s||“Œ8 }}}|xs d S c c}}w r<   )rD   rŒ   rž   rc  r-   ÚfloatÚbool)r[  rz   r:   Ústatss       r1   Ú2_numeric_compression_stats_from_guardrail_responserh  ñ  su   € ô Ð(¬$Ô/Øð -×2Ñ2Ó4÷áˆC�ØÔ0Ñ0´ZÀÌÌUÀ|Ô5TÔ]gÐhmÔosÔ]tð 	ˆU‰
ð€Eñ ð
 Š=�DÐùós   ¥;A)rY  c                 óœ   — t        | j                  d«      «      }i | ¥t        D �ci c]  }|| v sŒ|t        “Œ c}¥}|€|S i |¥d|i¥S c c}w )aE  
    Replace prompt-carrying fields with the redaction marker. Purely numeric
    compression stats inside ``guardrail_response`` (e.g. Headroom's
    ``tokens_saved``) cannot carry prompt content, so they are preserved as a
    stats-only dict; spend aggregation reads them via
    ``extract_compression_saved_tokens``.
    r[  )rh  rw   r^  r   )rY  Úpreserved_statsrz   Úredacteds       r1   rW  rW  þ  ss   € ô PÐPU×PYÑPYÐZnÓPoÓp€Oð<Ø
ð<ä5VÖ
g¨cÐZ]ÐafÒZfˆ3Ô)Ñ)Ò
gð<€Hð ÐØˆØ>ˆhÐ>Ð,¨oÑ>Ð>ùò	 hs
   ¦	A	°	A	rg   c                 óä   — | €yt        t        i | ¥«      }t        «       s7dD ]2  }|j                  |«      }t	        |t
        «      sŒ%t        |«      ||<   Œ4 t        |«      }t        t        |«      S )uA  
    Sanitize ``error_information`` before it lands in ``LiteLLM_SpendLogs.metadata``.

    Provider errors are stored verbatim via ``str(original_exception)``; those
    strings can echo the full request body, producing multi-megabyte spend-log
    rows.

    - Always: cap ``error_message`` and ``traceback`` with the existing
      ``MAX_STRING_LENGTH_PROMPT_IN_DB`` DB-storage safeguard.
    - When ``store_prompts_in_spend_logs`` is False: additionally redact
      ``'input'`` / ``'messages'`` / ``'prompt'`` values *and* Pydantic v2
      ``input_value=...`` assignments inside both ``error_message`` and
      ``traceback`` so prompts cannot leak through either field.

    Scoped to the spend-log path â€” OTEL/Datadog/etc. callbacks still receive
    the untruncated error per ``LITELLM_TRUNCATION_DB_SAFEGUARD_NOTE``.
    N)Úerror_messageÚ	traceback)	r	   rŒ   r  rw   rD   rE   rU  r  r$   )rg   Ú	sanitizedr¦   r:   s       r1   Ú*_sanitize_error_information_for_spend_logsrp    sx   € ð( Ð Øä”TÐ0Ð/Ð0Ó1€Iä<Ô>Ø3ò 	OˆEØ—M‘M %Ó(ˆEÜ˜%¤Õ%Ü#GÈÓ#N�	˜%Ò ð	Oô
 >¸iÓH€IÜÔ6¸	ÓBÐBr9   ÚobjÚ	max_depthc                 óf  — |dk  ry|€
t        «       }t        | «      }||v ryt        | t        t        f«      st        | d«      r|j                  |«       	 t        | t        «      r6| j                  «       }t        |||dz
  «      ||v r|j                  |«       S S t        | t        «      rH| j                  «       D ��ci c]  \  }}|t        |||dz
  «      “Œ c}}||v r|j                  |«       S S t        | t        «      r4| D �cg c]  }t        |||dz
  «      ‘Œ c}||v r|j                  |«       S S t        | d«      r0t        | j                  ||dz
  «      ||v r|j                  |«       S S | ||v r|j                  |«       S S c c}}w c c}w # ||v r|j                  |«       w w xY w)aß  
    Convert object to JSON-serializable dict, handling Pydantic models safely.

    This avoids pickle-based deepcopy which fails on Pydantic v2 models
    containing _thread.RLock objects.

    Args:
        obj: Object to convert (dict, list, Pydantic model, or primitive)
        visited: Set of object IDs to track circular references
        max_depth: Maximum recursion depth to prevent infinite recursion

    Returns:
        JSON-serializable version of the object
    r   z<max_depth_exceeded>z<circular_reference>r—   r7  )r)  r‡   rD   rŒ   rt   rœ   r*  r
   r–   Ú"_convert_to_json_serializable_dictÚremoverž   r—   )rq  r  rr  r+  rŸ   ró   rô   r  s           r1   rt  rt  5  s¼  € ð �A‚~à%à€Ü“%ˆô �s“G€FØ�Ñà%ô �#œœd�|Ô$¬°°ZÔ(@Ø�‰�FÔð#Ü�cœ9Ô%àŸN™NÓ,ˆFä5°f¸gÀyÐSTÁ}ÓUð �WÑØ�N‰N˜6Õ"ð ô ˜œTÔ"Øad×ajÑajÓal×mÑY]ÐYZÐ\]�AÔ9¸!¸WÀiÐRSÁmÓTÑTÓmð �WÑØ�N‰N˜6Õ"ð ô ˜œTÔ"ØadÖeÐY]Ô6°t¸WÀiÐRSÁmÕTÒeð �WÑØ�N‰N˜6Õ"ð ô �S˜*Ô%ä5°c·l±lÀGÈYÐYZÉ]Ó[ð �WÑØ�N‰N˜6Õ"ð ð ð �WÑØ�N‰N˜6Õ"ð ùó nùâeøð �WÑØ�N‰N˜6Õ"ð úsB   Á/F Â#F Ã FÃF Ã5F Ä	FÄ F Ä9%F Å5F ÆF ÆF0r£   c                 óÄ  — t        «       rÖt        t        dz  |j                  di «      «      }|�±|j                  di «      xs i }|�#|j                  d«      }|rt        |«      }||d<   |�:ddlm}m} ||j                  d«      d	œ} ||¬
«      rt        |«      } ||d¬«       t        |«      }t        |«      }	t        |	v rt        j                  dt        «       |	S y)z¥
    Only store if _should_store_prompts_and_responses_in_spend_logs() is True

    If turn_off_message_logging is enabled, redact messages in the request body.
    Nrh   ÚbodyÚrealtime_toolsÚtoolsr   ©Úperform_redactionÚshould_redact_message_loggingÚ standard_callback_dynamic_params©r£   r}  ©Úmodel_call_details©r€  rŸ   z>Spend Log: request body was truncated before storing in DB. %sr  )r  r	   rŒ   rw   Ú*litellm.litellm_core_utils.redact_messagesr{  r|  rt  r  r   r   r   Úinfor   )
rJ   r£   r„   Ú_proxy_server_requestÚ_request_bodyrx  r{  r|  r€  Ú_request_body_json_strs
             r1   rá   rá   k  sö   € ô 9Ô:Ü'+¬D°4©K¸×9KÑ9KÐLbÐdfÓ9gÓ'hÐØ Ð,Ø1×5Ñ5°f¸bÓAÒGÀRˆMàÐ!Ø(.¯
©
Ð3CÓ(D�Ù!Ü$(¨Ó$7�MØ-;�M 'Ñ*ð Ð!÷ð '5Ø8>¿
¹
ÐCeÓ8fñ-Ð"ñ 1ÐDVÕWÜ$FÀ}Ó$U�MÙ%¸ÈtÕTäIÈ-ÓXˆMÜ,6°}Ó,EÐ"Ü.Ð2HÑHÜ$×)Ñ)ØTÜ8ôð *Ð)Ør9   c                 óø   — t        «       r| S | €y| D ]e  }|j                  d«      xs
 t        «       }|j                  dg «      xs g }|D ]+  }|j                  dg «      xs g D ]  }d|v sŒt        |d<   Œ Œ- Œg | S )z~
    If user does not want to store prompts and responses, then remove the content from the vector store request metadata
    NÚvector_store_search_responseÚdataÚcontentr3  )r  rw   r&   r   )rP   Úvector_store_requestrˆ  Úresponse_dataÚresponse_itemÚcontent_items         r1   rx   rx   �  s±   € ô 9Ô:Ø,Ð,ð %Ð,ØØ =ò EÐà ×$Ñ$Ð%CÓDÒcÔHaÓHcð 	%ð 5×8Ñ8¸ÀÓDÒJÈˆØ*ò 	EˆMØ -× 1Ñ 1°)¸RÓ @Ò FÀBò E�Ø˜\Ò)Ü+D�L Ò(ñEñ	EðEð )Ð(r9   rÔ   c                 ó(  — | €yt        «       �r| j                  d«      }|€y|�3|j                  d«      }|r t        |t        «      rt        |«      }||d<   |�Lddlm}m} |j                  di «      }||j                  d«      d	œ} ||¬
«      rt        |«      } |i |¬«      }t        d|i«      }|j                  d|«      }	|	€yt        |	t        «      rt        |	«      }
nt        |	«      }
t        |
v rt        j                  dt        «       |
S y)Nr  rÓ   Úrealtime_tool_callsÚ
tool_callsr   rz  r£   r}  r~  r  r�  z:Spend Log: response was truncated before storing in DB. %s)r  rw   rD   rŒ   r‚  r{  r|  rt  r  rE   r   r   r   r   rƒ  r   )rÔ   r„   rƒ   r�  r{  r|  r£   r€  Úsanitized_wrapperÚsanitized_responseÚ
result_strs              r1   rà   rà   µ  s.  € ð €ØÜ8Õ:Ø#ŸK™K¨
Ó3ˆØÐØàÐØ)/¯©Ð4IÓ)JÐÙ"¤z°,ÄÔ'EÜ# LÓ1�Ø-@�˜\Ñ*ð Ð÷ð
 %+§J¡JÐ/?ÀÓ$DˆNà"0Ø4:·J±JÐ?aÓ4bñ)Ðñ -Ð@RÕSÜAÀ,ÓO�Ù0ÀBÈ|Ô\�ä#PÐR\Ð^jÐQkÓ#lÐà$5×$9Ñ$9¸*ÀlÓ$SÐàÐ%ØÜÐ(¬#Ô.Ü)Ð*<Ó=‰Jä#Ð$6Ó7ˆJÜ*¨jÑ8Ü ×%Ñ%ØLÜ4ôð ÐØr9   c                  ó¢   — ddl m}  ddlm} | j	                  d«      }|du ryt        |t        «      r|j                  «       dk(  ry |d«      du S )Nr   )Úgeneral_settings)Úget_secret_boolÚstore_prompts_in_spend_logsTÚtrueÚSTORE_PROMPTS_IN_SPEND_LOGS)Úlitellm.proxy.proxy_serverr–  Úlitellm.secret_managers.mainr—  rw   rD   rE   Úlower)r–  r—  Ústore_prompts_values      r1   r  r  ë  s[   € Ý;Ý<ð "2×!5Ñ!5Ð6SÓ!TÐð ˜dÑ"ØÜ	Ð'¬Ô	-à×$Ñ$Ó&¨&Ò0Øñ Ð8Ó9¸TÐAÐAr9   )rf   Úfailurec                 ó4   — | j                  dd«      }|dk(  ryy)zk
    Get the status for the spend log.

    It's only a failure if metadata.get("status") is "failure"
    re   NrŸ  rf   r¬   )rJ   Ú_statuss     r1   rä   rä   þ  s"   € ð "*§¡¨h¸Ó!=€GØ�)ÒØØr9   )NNNNNNNNNNNNNNr<   )NN)Né   )lr*   rF   r6   Úcollections.abcr   r   r   ÚdtÚtypingr   r   r   r	   Úpydanticr
   rØ   Úlitellm._loggingr   r(  r   r   r   r   r   r,   Ú'litellm.litellm_core_utils.core_helpersr   r   Ú1litellm.litellm_core_utils.internal_call_metadatar   Ú*litellm.litellm_core_utils.litellm_loggingr   r   r   Ú*litellm.litellm_core_utils.safe_json_dumpsr   r   Úlitellm.proxy._typesr   r   Ú3litellm.proxy.spend_tracking.spend_log_error_loggerr   Úlitellm.proxy.utilsr   r   Úlitellm.types.utilsr   r   r    r!   r"   r#   r$   r%   r&   Úlitellm.utilsr'   r-   r2   rE   rf  r8   Úcompiler=   r?   rI   rŒ   rt   re  r   r�   rv   r’   r    ÚobjectÚtupler¥   r­   rø   râ   rã   rÞ   r  r  rß   Ú	frozensetr  r)  r  r.  r0  rN  r2  r>  rJ  rU  ry   r^  rc  rh  rW  rp  rt  rá   rx   rà   r  rä   rr   r9   r1   ú<module>rµ     sp  ðÜ 	Û 	Û Ý #ß 'Ý #ß ,Ó ,å ã Ý 1÷ó õ÷õ ]÷ñ ÷
 Tß DÝ Oß 8÷
÷ 
õ 
õ <ð6¨Só 6ð8˜C $™Jð 8°S¸4±Zð 8ÀDó 8ð �—‘Ð9Ó:€ð Cð ¨Dó ð KPò   #¨¡*ð  À4ð  ÐTWÐZ^ÑT^ó  ð ,0Ø%)Ø,0Ø(,Ø@DØTXØNRØ $ØDHØ*.Ø-1Ø+/Ø"&Ø'+ñUØ�T‰kðUà˜S™	 DÑ(ðUð �s‘)˜dÑ"ðUð  # T™zð	Uð
  ™:ðUð 7¸Ñ=ðUð $(Ð(IÑ#JÈTÑ#QðUð  Ð CÑDÀtÑKðUð ˜‘+ðUð ;¸TÑAðUð ! 4™ZðUð $ d™lðUð " DÑ(ðUð ˜4‘ZðUð  ™ðUð  ó!Uðp '4Ð ˜eÓ 3ð ð °Dð À$ð È3ÐQUÉ:ó ð4¨cð 4Àdð 4Ètó 4ðnK¨G°C¸°KÑ,@À4Ñ,Gð KÈEÐRUÐWZÐRZÉOó Kð"5Ø4°tÑ;ð5àÐOÑPð5ð 	ó5ðLÐGWó Lð^Øðà4°tÑ;ðð 	óð.¨ð ¸Xð È#ÐPTÉ*ó ð Hð °ó ðAØðAàðAð �4‰ZðAð  ó	AðHHØðHàðHð ðHð ð	Hð
  óHðZ !ñØ4°tÑ;ðà�T‰kðð 	óñ" '0°Ð0AÓ&BÐ ˜eÓ Bð
 Ø15ñCmØðCmà�4‰ZðCmð %(¨$¡JðCmð 
ó	CmðT *IÐ  Ó Hð *:Ð  Ó 9ð '1 b§j¡jðØ—(‘(Ð:Ó;ñ<ð?ñð �x‰xÐ7Ó8ñ9ð<	ñ	ó'Ð ˜eó ð #ð ¨cð ¸#ð À#ó ð&) 3ð )¨sð )°só )ðX4¨sð 4°só 4ðnmØÐ CÑDÀtÑKðmà	Ð
-Ñ.°Ñ5ómð8,Ð ! 5ó ð)Ð  ó ð
Øð
à	ˆ#ˆs�U‰{Ð
Ñ˜dÑ"ó
ð?Ø.ð?à(ó?ð( CØ=ÀÑDð Cà+¨dÑ2ó CñF3#¨Cð 3#¸#À¹*ð 3#ÐX[ð 3#Ðehó 3#ðr ñ/Øð/àð/ð �4‰Kð/ð 	ó	/ðd)Ø#'Ð(IÑ#JÈTÑ#Qð)à	Ð
+Ñ,¨tÑ3ó)ð4 ñ3Ø# dÑ*ð3à�4‰Kð3ð 	ó3ðlB¸4ó Bð&ØðàÐ!Ñ"ôr9   