Ë
    tPêjø  ã            
       óŒ  — U d dl Z d dlZd dlZd dlZd dlmZmZmZmZm	Z	 d dl
mZmZ d dlmZmZmZ d dlmZ d dlmZ d dlmZmZmZmZmZ d dlZd dlmZ d d	lmZ d d
lm Z m!Z!m"Z"m#Z#m$Z$m%Z% d dl&m'Z' d dl(m)Z)m*Z*m+Z+m,Z,m-Z-m.Z.m/Z/ d dl0m1Z1m2Z2m3Z3 d dl4m5Z5m6Z6m7Z7m8Z8 d dl9m:Z: d dl;m<Z< d dl=m>Z> d dl?m@Z@mAZA d dlBmCZC d dlDmEZE d dlFmGZGmHZHmIZImJZJ d dlKmLZL d dlMmNZNmOZOmPZP d dlQmRZR d dlSmTZT  ed«      ZU eddd idœ«      ZVeeeWeXf      eYd<    eddd ii«      ZZeeeWeXf      eYd<    G d „ d!e«      Z[ G d"„ d#e[e«      Z\ G d$„ d%e[e«      Z] G d&„ d'e[e«      Z^ G d(„ d)e[e«      Z_ G d*„ d+e[e«      Z` G d,„ d-e[e«      Zad.ebfd/„Zcd0eddz  d.eddz  fd1„Zededdz  d2eddz  d.edfd3„Zfd4e[d5eeWedf   d.edfd6„Zgd4e\d.eWfd7„Zhd4e\d.eieWd8f   fd9„Zjd4e]d.eWfd:„Zkd4e]d.eieWd8f   fd;„Zld4e^d.eWfd<„Zmd4e^d.eieWd8f   fd=„Znd4e_d.eWfd>„Zod4e_d.eieWd8f   fd?„Zpd4e`d.eWfd@„Zqd4e`d.eieWd8f   fdA„Zrd4ead.eWfdB„Zsd4ead.eieWd8f   fdC„Ztd4ead5eeWedf   d.edfdD„Zu ei «      fdEe	eW   dFeeWeXf   d.eveWeXf   fdG„Zw ei «      fdHeNdIdJdFeeWeXf   d.dfdK„ZxdHeNdIdJd.dfdL„Zy edMdM¬N«       G dO„ dJ«      «       Zz edMdM¬N«       G dP„ dQ«      «       Z{ edMdM¬N«       G dR„ dS«      «       Z| ez«       Z}eeYdT<    edMdM¬N«       G dU„ dV«      «       Z~ e~d d ¬W«      ZeeYdX<   dYed.efdZ„Z€d[eeX   d\ed.e�fd]„Z‚d^e~d.ebfd_„Zƒd`eg ee~   f   d.dfda„Z„ edMdM¬N«       G db„ dc«      «       Z… G dd„ dee«      Z†dfe@dgeWdheWd.dfdi„Z‡dfe@dgeWdheWd.dfdj„Zˆ edMdM¬N«       G dk„ dl«      «       Z‰ e‰dmdne,�j                  dodpdqe‡¬r«       e‰dsdte,�j                  dudvdweˆ¬r«      fZŒeeie‰d8f      eYdx<   dIezd.eveWeXf   fdy„Z� G dz„ d{«      ZŽy)|é    N)Ú	AwaitableÚCallableÚIterableÚMappingÚSequence)Ú	dataclassÚfield)ÚdatetimeÚ	timedeltaÚtimezone)ÚEnum©ÚMappingProxyType)ÚFinalÚLiteralÚProtocolÚTypeVarÚassert_never)Úverbose_proxy_logger)Ú	DualCache)ÚGLOBAL_PROXY_SPEND_CACHE_KEYÚLITELLM_PROXY_BUDGET_NAMEÚRESET_BUDGET_JOB_BATCH_SIZEÚ!RESET_BUDGET_JOB_LOCK_TTL_SECONDSÚ#RESET_BUDGET_JOB_MAX_CHUNKS_PER_RUNÚRESET_BUDGET_JOB_NAME)Úduration_in_seconds)ÚDB_RETRY_SAFE_ERROR_TYPESÚLiteLLM_BudgetTableFullÚLiteLLM_EndUserTableÚLitellm_EntityTypeÚLiteLLM_TeamTableÚLiteLLM_UserTableÚLiteLLM_VerificationToken)ÚBudgetResetSettingsÚcompute_budget_reset_atÚget_budget_reset_settings)Úend_user_cache_keyÚmodel_access_group_cache_keyÚ$model_access_group_spend_counter_keyÚtag_cache_key)Úroll_window_spend_row)ÚPodLockManager)Úcall_with_db_reconnect_retry)ÚPrismaClientÚProxyLogging)ÚOrganizationRepository)ÚSpendLinkedTable)ÚEndUserRepositoryÚ ModelAccessGroupBudgetRepositoryÚTagRepositoryÚTeamMembershipRepository)ÚTeamRepository)ÚLinkedSpendResetWritesÚbudget_cascade_unit_of_workÚspend_reset_unit_of_work)ÚVerificationTokenRepository)ÚServiceTypesÚ_RowTÚgt)Úbudget_durationÚspendÚ_LINKED_KEYS_WHEREr@   Ú_SPENT_ROWS_WHEREc                   óD   — e Zd Zededz  fd„«       Zededz  fd„«       Zy)Ú_BudgetLinkedRowÚreturnNc                  ó   — y ©N© ©Úselfs    úp/home/oem/CyberBrain26-unified/.venv/lib/python3.12/site-packages/litellm/proxy/common_utils/reset_budget_job.pyr@   z_BudgetLinkedRow.spendJ   s   € Ø%(ó    c                  ó   — y rG   rH   rI   s    rK   Ú	budget_idz_BudgetLinkedRow.budget_idM   s   € Ø'*rL   )Ú__name__Ú
__module__Ú__qualname__ÚpropertyÚfloatr@   ÚstrrN   rH   rL   rK   rD   rD   I   s0   „ ØØ(�u˜t‘|Ò(ó Ø(àØ*˜3 ™:Ò*ó Ù*rL   rD   c                   ó8   — e Zd Zedefd„«       Zedefd„«       Zy)Ú_TeamMembershipRowrE   c                  ó   — y rG   rH   rI   s    rK   Úuser_idz_TeamMembershipRow.user_idR   ó   € Ø!rL   c                  ó   — y rG   rH   rI   s    rK   Úteam_idz_TeamMembershipRow.team_idU   rY   rL   N)rO   rP   rQ   rR   rT   rX   r[   rH   rL   rK   rV   rV   Q   s(   „ ØØ!˜Ò!ó Ø!àØ!˜Ò!ó Ù!rL   rV   c                   ó"   — e Zd Zedefd„«       Zy)Ú_KeyRowrE   c                  ó   — y rG   rH   rI   s    rK   Útokenz_KeyRow.tokenZ   s   € ØrL   N)rO   rP   rQ   rR   rT   r_   rH   rL   rK   r]   r]   Y   s   „ ØØ�sÒó ÙrL   r]   c                   ó"   — e Zd Zedefd„«       Zy)Ú_OrgRowrE   c                  ó   — y rG   rH   rI   s    rK   Úorganization_idz_OrgRow.organization_id_   s   € Ø&)rL   N)rO   rP   rQ   rR   rT   rc   rH   rL   rK   ra   ra   ^   s   „ ØØ) Ò)ó Ù)rL   ra   c                   ó"   — e Zd Zedefd„«       Zy)Ú_TagRowrE   c                  ó   — y rG   rH   rI   s    rK   Útag_namez_TagRow.tag_named   s   € Ø"rL   N)rO   rP   rQ   rR   rT   rg   rH   rL   rK   re   re   c   s   „ ØØ"˜#Ò"ó Ù"rL   re   c                   ó"   — e Zd Zedefd„«       Zy)Ú_ModelAccessGroupRowrE   c                  ó   — y rG   rH   rI   s    rK   Úaccess_group_namez&_ModelAccessGroupRow.access_group_namei   s   € Ø(+rL   N)rO   rP   rQ   rR   rT   rk   rH   rL   rK   ri   ri   h   s   „ ØØ+ 3Ò+ó Ù+rL   ri   c                   ó"   — e Zd Zedefd„«       Zy)Ú_EndUserRowrE   c                  ó   — y rG   rH   rI   s    rK   rX   z_EndUserRow.user_idn   rY   rL   N)rO   rP   rQ   rR   rT   rX   rH   rL   rK   rm   rm   m   s   „ ØØ!˜Ò!ó Ù!rL   rm   rE   c                  ó&   — t         j                  du S )NT)ÚlitellmÚbudget_rolloverrH   rL   rK   Ú_rollover_enabledrr   r   s   € Ü×"Ñ" dÐ*Ð*rL   Ú
max_budgetc                 ó6   — | �t        j                  | «      sy | S rG   )ÚmathÚisfinite)rs   s    rK   Ú_rollover_caprw   v   s   € ØÐ¤§¡¨zÔ!:ØØÐrL   Úcapc                 ó.   — |€yt        d| xs d|z
  «      S ©Nç        )Úmax)r@   rx   s     rK   Ú_carried_spendr}   |   s    € Ø
€{ØÜˆs�U’\˜c SÑ(Ó)Ð)rL   ÚrowÚcapsc                 óŠ   — |syt        | j                  | j                  �|j                  | j                  «      «      S d «      S rz   )r}   r@   rN   Úget)r~   r   s     rK   Ú_row_carried_spendr‚   ‚   s8   € ÙØÜ˜#Ÿ)™)ÀÇÁÐ@Y T§X¡X¨c¯m©mÓ%<ÓdÐdÐ_cÓdÐdrL   c                 ó:   — d| j                   › d| j                  › �S )Nzspend:team_member:ú:)rX   r[   ©r~   s    rK   Ú_team_membership_counter_keyr†   ˆ   s   € Ø §¡˜}¨A¨c¯k©k¨]Ð;Ð;rL   .c                 ó:   — | j                   › d| j                  › �fS )NÚ_)r[   rX   r…   s    rK   Ú_team_membership_cache_keysr‰   Œ   s   € Ø�{‰{ˆm˜1˜SŸ[™[˜MÐ*Ð,Ð,rL   c                 ó    — d| j                   › �S )Nú
spend:key:©r_   r…   s    rK   Ú_key_counter_keyr�   �   s   € Ø˜Ÿ	™	�{Ð#Ð#rL   c                 ó   — | j                   fS rG   rŒ   r…   s    rK   Ú_key_cache_keysr�   ”   s   € Ø�I‰Iˆ<ÐrL   c                 ó    — d| j                   › �S )Nz
spend:org:©rc   r…   s    rK   Ú_org_counter_keyr’   ˜   s   € Ø˜×+Ñ+Ð,Ð-Ð-rL   c                 ó@   — d| j                   › �d| j                   › d�fS )Nzorg_id:z:with_budgetr‘   r…   s    rK   Ú_org_cache_keysr”   œ   s0   € à
�#×%Ñ%Ð&Ð'Ø
�#×%Ñ%Ð& lÐ3ðð rL   c                 ó    — d| j                   › �S )Nz
spend:tag:)rg   r…   s    rK   Ú_tag_counter_keyr–   £   s   € Ø˜Ÿ™�~Ð&Ð&rL   c                 ó.   — t        | j                  «      fS rG   )r+   rg   r…   s    rK   Ú_tag_cache_keysr˜   §   s   € Ü˜#Ÿ,™,Ó'Ð)Ð)rL   c                 ó,   — t        | j                  «      S rG   )r*   rk   r…   s    rK   Ú_model_access_group_counter_keyrš   «   s   € Ü/°×0EÑ0EÓFÐFrL   c                 ó.   — t        | j                  «      fS rG   )r)   rk   r…   s    rK   Ú_model_access_group_cache_keysrœ   ¯   s   € Ü(¨×)>Ñ)>Ó?ÐAÐArL   c                 ó    — d| j                   › �S )Nzspend:end_user:)rX   r…   s    rK   Ú_enduser_counter_keyrž   ³   s   € Ø˜SŸ[™[˜MÐ*Ð*rL   c                 ó.   — t        | j                  «      fS rG   )r(   rX   r…   s    rK   Ú_enduser_cache_keysr    ·   s   € Ü˜sŸ{™{Ó+Ð-Ð-rL   c                 óž   — |sy| j                   xs t        j                  }t        | j                  |�|j                  |«      «      S d «      S rz   )rN   rp   Úmax_end_user_budget_idr}   r@   r�   )r~   r   Úeffective_budget_ids      rK   Ú_enduser_carried_spendr¤   »   sG   € ÙØØŸ-™-ÒI¬7×+IÑ+IÐÜ˜#Ÿ)™)ÐFYÐFe T§X¡XÐ.AÓ%BÓpÐpÐkoÓpÐprL   Ú
budget_idsÚextrac                 ó$   — ddt        | «      ii|¥S )NrN   Úin)Úlist)r¥   r¦   s     rK   Ú_budget_link_whererª   Â   s   € ð ˜$¤ ZÓ 0Ð1Ð;°UÐ;Ð;rL   ÚwritesÚcascadeÚ_BudgetCascadec                 ó8  ‡— ‰j                   j                  «       D ]?  \  }}| j                  d|i|¥dd|dœi¥¬«       | j                  d|i|¥dd|ii¥|¬«       ŒA t	        ˆfd„‰j
                  D «       «      }|r| j                  t        ||«      ¬«       y	y	)
aÆ  Reset one linked table's spend for every expiring tier: tiers with a
    rollover cap keep spend beyond the cap (decrement preserves writes racing
    the reset), everything else is zeroed as before. Zero the under-cap rows
    BEFORE decrementing the over-cap ones: the statements run sequentially in
    one transaction, so the reverse order lets the zero re-match a row the
    decrement just moved into the (0, cap] range and erase its carried spend.rN   r@   r   ©r>   Últe©Úwherer>   ©r²   Úamountc              3   ó@   •K  — | ]  }|‰j                   vsŒ|–— Œ y ­wrG   )Úrollover_caps)Ú.0Úbidr¬   s     €rK   ú	<genexpr>z._queue_budget_linked_resets.<locals>.<genexpr>Û   s   øè ø€ Òc SÀ#ÈW×MbÑMbÒBbœSÑcùs   ƒ—N)r¶   ÚitemsÚqueue_spend_zeroÚqueue_spend_decrementÚtupler¥   rª   )r«   r¬   r¦   rN   rx   Ú	plain_idss    `    rK   Ú_queue_budget_linked_resetsr¿   É   s¼   ø€ ð "×/Ñ/×5Ñ5Ó7ò 
‰ˆ	�3Ø×ÑØ 	ÐS¨UÐS°GÀAÈcÑ=RÑSð 	 ô 	
ð 	×$Ñ$Ø 	ÐI¨UÐI°G¸dÀC¸[ÑIÐRUð 	%õ 	
ð	
ô Óc¨G×,>Ñ,>ÔcÓc€IÙØ×ÑÔ&8¸ÀEÓ&JÐÕKð rL   c                 ó:  — t        | |t        ¬«       t        j                  }|�||j                  vry|j
                  j                  |«      }|€| j                  ddit        ¥¬«       y| j                  dd|dœdœ¬«       | j                  dd|idœ|¬	«       y)
a÷  End users reset on the budget link like every other gated table, plus a
    NULL-budget_id branch: rows created implicitly persist no link and ride the
    default tier (litellm.max_end_user_budget_id).

    Matching on the link rather than enumerating user ids keeps a statement's
    bind count proportional to the expiring tiers instead of the customer
    population, which past ~32,700 dependents exceeds PostgreSQL's per-statement
    bind ceiling and wedges the cascade permanently (#40564).
    ©r¦   NrN   r±   r   r¯   ©rN   r@   r>   r³   )	r¿   rB   rp   r¢   r¥   r¶   r�   r»   r¼   )r«   r¬   Údefault_budget_idrx   s       rK   Ú_queue_enduser_resetsrÄ   à   s¹   € ô   ¨Ô7HÕIÜ&×=Ñ=ÐØÐ Ð$5¸W×=OÑ=OÑ$OØØ×&Ñ&×*Ñ*Ð+<Ó=€CØ
€{Ø×ÑØ Ð:Ô(9Ð:ð 	 ô 	
ð 	Ø
×ÑØ °!¸CÑ+@ÑAð ô ð × Ñ Ø ¨D°#¨;Ñ7Àð !õ rL   T)ÚfrozenÚslotsc                   óÞ   — e Zd ZU dZdZeedf   ed<   dZee	df   ed<   dZ
eee	ef   df   ed<   dZeedf   ed<   dZeee	ef   df   ed<   dZee	df   ed	<    ed
„ ¬«      Zee	ef   ed<   y)r­   zDEverything one budget-tier reset touches, resolved before any write.rH   .Úbudgetsr¥   Úbudget_resetsÚendusersÚcounter_resetsÚ
cache_keysc                  ó   — t        i «      S rG   r   rH   rL   rK   ú<lambda>z_BudgetCascade.<lambda>  s   € ÔGWÐXZÓG[€ rL   )Údefault_factoryr¶   N)rO   rP   rQ   Ú__doc__rÈ   r½   r   Ú__annotations__r¥   rT   rÉ   r
   rÊ   rm   rË   rS   rÌ   r	   r¶   r   rH   rL   rK   r­   r­   ü   s¥   … áNà35€GˆUÐ*¨CÐ/Ñ0Ó5Ø"$€J��c˜3�h‘Ó$Ø68€M�5˜˜s H˜}Ñ-¨sÐ2Ñ3Ó8Ø(*€Hˆe�K Ð$Ñ%Ó*Ø46€N�E˜%  U 
Ñ+¨SÐ0Ñ1Ó6Ø"$€J��c˜3�h‘Ó$Ù).Ñ?[Ô)\€M�7˜3 ˜:Ñ&Ô\rL   c                   ó"   — e Zd ZU eed<   eed<   y)Ú_BudgetCascadeCommittedr¬   ÚadvancedN)rO   rP   rQ   r­   rÑ   ÚintrH   rL   rK   rÓ   rÓ   	  s   … àÓØ„MrL   rÓ   c                   ó"   — e Zd ZU eed<   eed<   y)Ú_BudgetCascadeFailedr¬   ÚerrorN)rO   rP   rQ   r­   rÑ   Ú	ExceptionrH   rL   rK   r×   r×     s   … àÓØÔrL   r×   Ú_EMPTY_CASCADEc                   ó&   — e Zd ZU dZeed<   eed<   y)Ú_ChunkOutcomezËOne chunk of a reset phase: rows read, and rows whose new budget_reset_at
    cleared the due cutoff. Anything else is still due and would come straight
    back on the next fetch, so it is not progress.ÚfetchedrÔ   N)rO   rP   rQ   rÐ   rÕ   rÑ   rH   rL   rK   rÜ   rÜ     s   … ñ6ð ƒLØ„MrL   rÜ   ©rÝ   rÔ   Ú_NO_PROGRESSÚmomentc                 ó^   — | j                   �| S | j                  t        j                  ¬«      S )N©Útzinfo)rã   Úreplacer   Úutc)rà   s    rK   Ú_as_utcræ   %  s%   € Ø—]‘]Ð.ˆ6ÐW°F·N±NÌ(Ï,É,°NÓ4WÐWrL   Ú	reset_atsÚcutoffc                 óB   ‡— t        |«      Št        ˆfd„| D «       «      S )a$  How many rows the write actually moved past the due cutoff.

    A budget_duration of "0s" (or one the parser cannot read) resolves to the
    current time, so the row is written and stays due. Counting it as progress
    would re-read the same chunk until the per-run cap on every tick.
    c              3   ób   •K  — | ]&  }t        |t        «      sŒt        |«      ‰kD  sŒ#d –— Œ( y­w)é   N)Ú
isinstancer
   ræ   )r·   Úreset_atÚ
utc_cutoffs     €rK   r¹   z"_count_advanced.<locals>.<genexpr>1  s)   øè ø€ Òp�X¬j¸Ä8Õ.LÔQXÐYaÓQbÐeoÓQoŒqÑpùs   ƒ/™/¨/)ræ   Úsum)rç   rè   rî   s     @rK   Ú_count_advancedrð   )  s   ø€ ô   ›€JÜÓp ÔpÓpÐprL   Úoutcomec                 óJ   — | j                   t        k  xs | j                  dk(  S )z¸A short chunk means the due rows ran out. A full chunk that advanced
    nothing would be re-read unchanged forever, so it ends the phase too and
    those rows wait for the next tick.r   )rÝ   r   rÔ   )rñ   s    rK   Ú_phase_is_drainedró   4  s%   € ð �?‰?Ô8Ñ8ÒQ¸G×<LÑ<LÐPQÑ<QÐQrL   Úprocess_chunkc              ƒ   ól   K  — t        t        «      D ]  }t         | «       ƒ d{  –—† «      sŒ y y7 Œ­w)z„Drive one reset phase a chunk at a time, capped so a single run cannot
    spin unbounded: leftovers are picked up by the next tick.N)Úranger   ró   )rô   rˆ   s     rK   Ú_run_phase_in_chunksr÷   ;  s0   è ø€ ô Ô6Ó7ò ˆÜ¡=£?×2Õ3ÙñØ2ús   ‚"4¤2
¥4®4c                   ó(   — e Zd ZU dZeed<   defd„Zy)Ú	_LazyJsonaA  Serialize only if a log record is actually emitted.

    ``logger.debug("... %s", json.dumps(rows))`` evaluates the dump before the
    logger decides to drop the record, so a chunk of rows is serialized on the
    event loop on every tick at any log level. Passing this instead defers the
    work to the formatter.
    ÚvaluerE   c                 óN   — t        j                  | j                  dt        ¬«      S )Né   )ÚindentÚdefault)ÚjsonÚdumpsrú   rT   rI   s    rK   Ú__str__z_LazyJson.__str__O  s   € Ü�z‰z˜$Ÿ*™*¨Q¼Ô<Ð<rL   N)rO   rP   rQ   rÐ   ÚobjectrÑ   rT   r  rH   rL   rK   rù   rù   C  s   … ñð ƒMð=˜ô =rL   rù   c                   ó   — e Zd ZdZdZdZdZy)Ú_Leasez?Whether this pod may sweep, and whether it owes a lock release.ÚleaderÚ	unguardedÚfollowerN)rO   rP   rQ   rÐ   ÚLEADERÚ	UNGUARDEDÚFOLLOWERrH   rL   rK   r  r  S  s   „ ÙIà€FØ€IØ�HrL   r  Úprisma_clientÚrow_idÚpayloadc              ƒ   ót   K  — t        | «      j                  j                  d|id|i¬«      ƒ d {  –—†  y 7 Œ­w)Nr_   Úbudget_limits©r²   Údata)r;   ÚtableÚupdate©r  r  r  s      rK   Ú_write_key_windowsr  [  s?   è ø€ Ü
% mÓ
4×
:Ñ
:×
AÑ
AØ˜ÐØ˜wÐ'ð Bó ÷ ò úó   ‚.8°6±8c              ƒ   ót   K  — t        | «      j                  j                  d|id|i¬«      ƒ d {  –—†  y 7 Œ­w)Nr[   r  r  )r7   r  r  r  s      rK   Ú_write_team_windowsr  b  s>   è ø€ Ü
˜Ó
'×
-Ñ
-×
4Ñ
4Ø˜&Ð!Ø˜wÐ'ð 5ó ÷ ò úr  c                   óz   — e Zd ZU dZeed<   eed<   eed<   eed<   eed<   eed<   eeeege	d   f   ed	<   d
efd„Z
y)Ú_WindowSourcez<A table whose rows carry their own per-window budget limits.r  Ú	id_columnÚentity_typeÚcounter_prefixÚlog_subjectÚretry_subjectNÚwriterE   c           	      óp   — d| j                   › d| j                  › d| j                   › d| j                   › d�	S )ar  One keyset page, ordered by the primary key so the cursor never repeats a row.

        prisma-client-python cannot null-filter a ``Json?`` column (no DbNull /
        JsonNull sentinel, RobertCraigie/prisma-client-py#714), so the read stays
        raw SQL; the table and column names are module constants, never input.
        Writes still go through the ORM.
        zSELECT z, budget_limits FROM "z&" WHERE budget_limits IS NOT NULL AND z > $1 ORDER BY z	 LIMIT $2)r  r  rI   s    rK   Ú
page_queryz_WindowSource.page_queryu  sG   € ð �d—n‘nÐ%Ð%;¸D¿J¹J¸<ð H3Ø37·>±>Ð2Bð CØŸ™Ð' yð2ð	
rL   )rO   rP   rQ   rÐ   rT   rÑ   r!   r   r/   r   r"  rH   rL   rK   r  r  i  sN   … áFàƒJØƒNØ#Ó#ØÓØÓØÓØ�\ 3¨Ð,¨i¸©oÐ=Ñ>Ó>ð
˜Cô 
rL   r  r$   r_   z	spend:keyÚkeysÚkey)r  r  r  r  r  r  r   r"   r[   z
spend:teamÚteamsÚteamÚ_WINDOW_SOURCESc                 óX   — t        | j                  «      t        | j                  «      dœS )N)Únum_budgets_foundÚnum_endusers_found)ÚlenrÈ   rÊ   )r¬   s    rK   Ú_budget_cascade_event_metadatar,  š  s&   € ä  §¡Ó1Ü! '×"2Ñ"2Ó3ñð rL   c                   ó$  — e Zd ZdZ	 	 dWdedededz  dedz  fd„Zded	e	fd
„Z
d	efd„Zd„ Zdeg ee   f   ded	efd„Zdeg ee   f   ded	efd„ZedXdeded	dfd„«       ZedYd„«       Zeded	dfd„«       Zdee   deeef   ded	eedf   fd„Zdee   d	eedf   fd„Z dee!   d	e"fd„Z#d e"d	dfd!„Z$d e"d	dfd"„Z%d e"d	dfd#„Z&d	e'e(z  fd$„Z)dYd%„Z*d	e+fd&„Z,d	e-e.   fd'„Z/d(e-e0   d	dfd)„Z1d(e-e0   d	dfd*„Z2d+e-e3   d	dfd,„Z4d+e-e3   d	dfd-„Z5d.e-e6   d	dfd/„Z7d.e-e6   d	dfd0„Z8d1ed2e9d3ed4ed5e:eef   d	dfd6„Z;dYd7„Z<d	e+fd8„Z=dYd9„Z>d	e+fd:„Z?dYd;„Z@d	e+fd<„ZAed=e:ded>eBd?eCdeded@eDdAed	e	fdB„«       ZEeded@eDdAedCedDeCd	dfdE„«       ZFed=eeef   ded>eBd	efdF„«       ZGdYdG„ZHdHeId?eCd>eBd	dfdI„ZJdHeIdJed?eCd>eBd	edz  f
dK„ZKedLe6e3z  e0z  dMeCdNeLdO   defdP„«       ZMedQe6dMeCded	e6dz  fdR„«       ZNedSe3dMeCded	e3dz  fdT„«       ZOedUe0dMeCded	e0dz  fdV„«       ZPy)ZÚResetBudgetJobzK
    Resets the budget for all the keys, users, and teams that need it
    NÚproxy_logging_objr  Úreset_settingsÚpod_lock_managerc                 óT   — || _         || _        |xs
 t        «       | _        || _        y rG   )r/  r  r'   r0  r1  )rJ   r/  r  r0  r1  s        rK   Ú__init__zResetBudgetJob.__init__¦  s.   € ð 0AˆÔØ+8ˆÔØ3AÒ3`ÔE^ÓE`ˆÔØ7GˆÕrL   Úlock_managerrE   c              ƒ   ó  K  — |j                   €y	 |j                  t        «      }t        |j                   j	                  |«      ƒ d{  –—† «      S 7 Œ# t
        $ r }t        j                  d|«       Y d}~yd}~ww xY w­w)a  True only when the lease is readable and someone holds it.

        An unreadable lock reports as unheld so the caller sweeps rather than
        skipping; being wrong here costs a duplicate sweep, and the alternative
        strands every expired budget at its cap.
        NFz4Reset budget job: could not read the reset lease: %s)Úredis_cacheÚget_redis_lock_keyr   ÚboolÚasync_get_cacherÙ   r   Úwarning)rJ   r4  Úlock_keyÚexcs       rK   Ú_lease_is_heldzResetBudgetJob._lease_is_held²  ss   è ø€ ð ×#Ñ#Ð+Øð	Ø*×=Ñ=Ô>SÓTˆHÜ˜l×6Ñ6×FÑFÀxÓP×PÓQÐQÐPùÜò 	Ü ×(Ñ(Ð)_ÐadÔeÜûð	üs@   ‚B ‘8A Á	AÁ
A ÁB ÁA Á	A=ÁA8Á3B Á8A=Á=B c              ƒ   ó’  K  — | j                   }|�|j                  €t        j                  S |j	                  t
        t        ¬«      ƒ d{  –—† rt        j                  S | j                  |«      ƒ d{  –—† r%t        j                  d«       t        j                  S t        j                  d«       t        j                  S 7 Œw7 ŒP­w)am  Elect one sweeper per tick.

        Every pod schedules this job, and each one otherwise re-reads the whole
        due population and writes it back at the same calendar boundary, so a
        fleet multiplies one sweep's Postgres load by its replica count. A
        deployment with no Redis-backed lock manager runs unguarded, as it
        always has.
        N)Ú
cronjob_idÚttlzGReset budget job: another pod holds the reset lease, skipping this tickz|Reset budget job: could not take the reset lease and no other pod holds it, sweeping unguarded rather than skipping the tick)r1  r6  r  r	  Úacquire_lockr   r   r  r=  r   Údebugr
  r:  )rJ   r4  s     rK   Ú_acquire_leasezResetBudgetJob._acquire_leaseÂ  sº   è ø€ ð #×3Ñ3ˆØÐ <×#;Ñ#;Ð#CÜ×#Ñ#Ð#à×*Ñ*Ü,Ü1ð +ó 
÷ 
ð 
ô —=‘=Ð à×$Ñ$ \Ó2×2Ð2Ü ×&Ñ&Ð'pÔqÜ—?‘?Ð"ô 	×$Ñ$ð?ô	
ô ×ÑÐð%
øð 3ús%   ‚A	CÁCÁ(CÁ4CÁ5ACÃCc              ƒ   ó¶  K  — | j                   €y| j                  «       ƒ d{  –—† }|t        j                  u ry	 | j	                  «       ƒ d{  –—†  | j                  «       ƒ d{  –—†  | j                  «       ƒ d{  –—†  | j                  «       ƒ d{  –—†  | j                  «       ƒ d{  –—†  |t        j                  u r6| j                  �)| j                  j                  t        ¬«      ƒ d{  –—†  yyy7 ŒÙ7 Œ¯7 Œ™7 Œƒ7 Œm7 ŒW7 Œ# |t        j                  u r7| j                  �*| j                  j                  t        ¬«      ƒ d{  –—†7   w w w xY w­w)zÊ
        Gets all the non-expired keys for a db, which need spend to be reset

        Resets their spend

        Updates db

        Runs on one pod per tick where a Redis lease is available.
        N)r?  )r  rC  r  r
  Úreset_budget_for_litellm_keysÚreset_budget_for_litellm_usersÚreset_budget_for_litellm_teamsÚ%reset_budget_for_litellm_budget_tableÚreset_budget_windowsr  r1  Úrelease_lockr   )rJ   Úleases     rK   Úreset_budgetzResetBudgetJob.reset_budgetã  s8  è ø€ ð ×ÑÐ%Øà!×0Ñ0Ó2×2ˆØ”F—O‘OÑ#Øð	[Ø×4Ñ4Ó6×6Ð6Ø×5Ñ5Ó7×7Ð7Ø×5Ñ5Ó7×7Ð7Ø×<Ñ<Ó>×>Ð>Ø×+Ñ+Ó-×-Ð-àœŸ™Ñ%¨$×*?Ñ*?Ð*KØ×+Ñ+×8Ñ8ÔDYÐ8ÓZ×ZÑZð +LÐ%ð 3øð
 7øØ7øØ7øØ>øØ-øð [ùð œŸ™Ñ%¨$×*?Ñ*?Ð*KØ×+Ñ+×8Ñ8ÔDYÐ8ÓZ×ZÒZð +LÐ%üs    ‚!E£C=¤E¼D ÁC?ÁD Á'DÁ(D Á?DÂ D ÂDÂD Â/DÂ0D Â4AEÃ5D	Ã6EÃ?D ÄD ÄD ÄD ÄD Ä	EÄAEÅEÅEÅEÚ	operationÚreasonc             ƒ   óN   K  — t        | j                  ||¬«      ƒ d{  –—† S 7 Œ­w)z‚Reconnect and retry once on a transport error, so a dropped connection
        costs one retry instead of the whole tick.
        ©rN  N)r.   r  ©rJ   rM  rN  s      rK   Ú_with_db_retryzResetBudgetJob._with_db_retry   s$   è ø€ ô 2°$×2DÑ2DÀiÐX^Ô_×_Ð_Ð_ús   ‚%ž#Ÿ%c             ƒ   óX   K  — t        | j                  ||t        ¬«      ƒ d{  –—† S 7 Œ­w)záSame, for writes: only replay when the statements provably never
        reached the database. A reset zeroes spend unconditionally, so replaying
        an ambiguous commit would erase spend accrued since it landed.
        )rN  Úretry_safe_error_typesN)r.   r  r   rQ  s      rK   Ú_with_db_write_retryz#ResetBudgetJob._with_db_write_retry  s1   è ø€ ô
 2Ø×ÑØØÜ#<ô	
÷ 
ð 	
ð 
ús   ‚!*£(¤*Úcounter_keyÚ	new_spendc              ƒ   óv  K  — 	 ddl m} |j                  j                  | |d¬«       |j                  �(	 |j                  j                  | |d¬«      ƒ d{  –—†  yy7 Œ# t        $ r!}t        j                  d| |«       Y d}~yd}~ww xY w# t        $ r!}t        j                  d| |«       Y d}~yd}~ww xY w­w)a‹  Overwrite a spend counter with the post-reset value (0, or the carried
        overage when budget rollover is enabled) so a DB-row reset takes effect
        immediately.

        Call AFTER the DB write commits. Clearing Redis before the DB
        commit opens a window where get_current_spend reads 0 from Redis
        while the DB still holds the pre-reset value, allowing bypass.
        r   ©Úspend_counter_cacheé<   )r$  rú   r@  NzaFailed to reset spend counter %s in Redis: %s. Budget may be over-enforced until counter expires.z$Failed to reset spend counter %s: %s)	Úlitellm.proxy.proxy_serverrZ  Úin_memory_cacheÚ	set_cacher6  Úasync_set_cacherÙ   r   r:  )rV  rW  rZ  Ú	redis_errÚes        rK   Ú_invalidate_spend_counterz(ResetBudgetJob._invalidate_spend_counter  sÁ   è ø€ ð	aÝFà×/Ñ/×9Ñ9¸kÐQZÐ`bÐ9ÔcØ"×.Ñ.Ð:ðØ-×9Ñ9×IÑIÈkÐajÐprÐIÓs×sÑsð ;àsùÜ ò Ü(×0Ñ0ðMà#Ø!÷	ñ ûðûô ò 	aÜ ×(Ñ(Ð)OÐQ\Ð^_×`Ñ`ûð	aüsi   ‚B9„0B µ!A ÁAÁA ÁB9ÁA Á	B	Á(BÁ?B ÂB9ÂB	Â	B Â	B6ÂB1Â,B9Â1B6Â6B9c               ƒ   óR   K  — t         j                  t        «      ƒ d{  –—†  y7 Œ­w)zßDrop the cached global-proxy spend accumulator after the proxy
        budget aggregate row is reset, so the next auth-time load reads the
        zeroed row instead of a stale (potentially never-expiring) counter.
        N)r.  Ú$_invalidate_user_api_key_cache_entryr   rH   rL   rK   Ú$_invalidate_global_proxy_spend_cachez3ResetBudgetJob._invalidate_global_proxy_spend_cache-  s   è ø€ ô ×AÑAÔB^Ó_×_Ò_ús   ‚'Ÿ% 'Ú	cache_keyc              ƒ   ó¬   K  — 	 ddl m} |j                  | ¬«      ƒ d{  –—†  y7 Œ# t        $ r!}t	        j
                  d| |«       Y d}~yd}~ww xY w­w)a8  Drop a stale management-cache entry so the next read fetches from DB.

        Tags and end-users are not reseeded by ``SpendCounterReseed.from_db``;
        for those, when the spend counter expires the budget check falls back
        to ``cached_obj.spend``. Keys, orgs, and team memberships are reseeded
        from the DB, but auth still may consult ``user_api_key_cache`` objects
        whose ``.spend`` field can lag a cross-pod DB reset. Deleting the cache
        entry forces the next auth-time fetch to reload the zeroed row from
        Postgres.
        r   )Úuser_api_key_cache©r$  Nz4Failed to invalidate user_api_key_cache entry %s: %s)r\  rh  Úasync_delete_cacherÙ   r   r:  )rf  rh  ra  s      rK   rd  z3ResetBudgetJob._invalidate_user_api_key_cache_entry5  sP   è ø€ ð		ÝEà$×7Ñ7¸IÐ7ÓF×FÒFùÜò 	Ü ×(Ñ(ØFØØ÷ñ ûð	üs6   ‚A„' Ÿ% ' ¤A¥' §	A°AÁAÁAÁAr  r²   r  .c           
   ƒ   óæ   ‡‡K  — 	 t        | j                  ˆˆfd„d|j                  dd«      › d�¬«      ƒ d{  –—† «      S 7 Œ# t        $ r!}t	        j
                  d||«       Y d}~y	d}~ww xY w­w)
zoRead the rows the cascade will zero, so their counters can be
        invalidated once the transaction commits.c                  ó(   •— ‰ j                  ‰¬«      S )Nr±   ©Ú	find_many)r  r²   s   €€rK   rÎ   z3ResetBudgetJob._fetch_linked_rows.<locals>.<lambda>W  s   ø€ ˜EŸO™O°%˜OÓ8€ rL   Úreset_budget_read_ú rˆ   Ú_failurerP  Nz/Failed to fetch %s for counter invalidation: %srH   )r½   rR  rä   rÙ   r   r:  )rJ   r  r²   r  ra  s    ``  rK   Ú_fetch_linked_rowsz!ResetBudgetJob._fetch_linked_rowsL  s|   ùè ø€ ð		ÜØ×)Ñ)Ü8Ø/°×0CÑ0CÀCÈÓ0MÐ/NÈhÐWð *ó ÷ óð ðùô
 ò 	Ü ×(Ñ(Ð)ZÐ\gÐijÔkÜûð	üs>   „A1†3A ¹AºA ÁA1ÁA Á	A.ÁA)Á$A1Á)A.Á.A1r¥   c              ƒ   óø   ‡ ‡K  — ‰ j                  ˆˆ fd„d¬«      ƒ d {  –—† }t        j                  �t        j                  ‰vrt        |xs d«      S g |xs d¢‰ j	                  «       ƒ d {  –—† ¢­S 7 ŒV7 Œ­w)Nc                  óR   •— ‰j                   j                  ddt        ‰ «      ¬«      S )NÚenduserÚfind_all)Ú
table_nameÚ
query_typeÚbudget_id_list)r  Úget_datar©   )r¥   rJ   s   €€rK   rÎ   z;ResetBudgetJob._collect_endusers_to_reset.<locals>.<lambda>a  s+   ø€ �D×&Ñ&×/Ñ/Ø$Ø%Ü# JÓ/ð 0ó € rL   Ú"reset_budget_read_endusers_failurerP  rH   )rR  rp   r¢   r½   Ú_get_endusers_with_no_budget_id)rJ   r¥   Úlinkeds   `` rK   Ú_collect_endusers_to_resetz)ResetBudgetJob._collect_endusers_to_reset_  sƒ   ùè ø€ Ø<@×<OÑ<Oôð
 8ð =Pó =
÷ 7
ˆô ×)Ñ)Ð1´W×5SÑ5SÐ[eÑ5eÜ˜š 2Ó&Ð&ØO�&’,˜BÐO¨×(LÑ(LÓ(N×"NÑOÐOð7
øð #Oús"   „A:ŸA6 AA:Á/A8Á0A:Á8A:Úbudgets_to_resetc              ƒ   óP  ‡ ‡K  — t        d„ |D «       «      }|st        S ‰ j                  t        ‰ j                  «      j
                  t        |«      d¬«      ƒ d{  –—† }‰ j                  t        ‰ j                  «      j
                  t        |t        «      d¬«      ƒ d{  –—† }‰ j                  t        ‰ j                  «      j
                  t        |t        «      d¬«      ƒ d{  –—† }‰ j                  t        ‰ j                  «      j
                  t        |t        «      d¬«      ƒ d{  –—† }‰ j                  t        ‰ j                  «      j
                  t        |t        «      d¬«      ƒ d{  –—† }t        t        «       r>|D �ci c]2  }|j                  �$t!        |j"                  «      x}	�|j                  |	“Œ4 c}ni «      Š‰ j%                  |«      ƒ d{  –—† }
t'        t        |«      |t        ˆ fd	„|D «       «      |
g ˆfd
„|D «       ¢ˆfd„|D «       ¢ˆfd„|D «       ¢ˆfd„|D «       ¢ˆfd„|D «       ¢ˆfd„|
D «       ¢­‰g d„ |D «       ¢d„ |D «       ¢d„ |D «       ¢d„ |D «       ¢d„ |D «       ¢d„ |
D «       ¢­¬«      S 7 �Œ47 �Œð7 �Œ¬7 �Œh7 �Œ$c c}w 7 Œ¿­w)a  Resolve every row the expiring budget tiers gate, before any write.

        Keys carrying their own budget_duration are left out: they run on their
        own schedule via reset_budget_for_litellm_keys(), so sweeping them here
        would reset them twice.
        c              3   óN   K  — | ]  }|j                   €Œ|j                   –— Œ y ­wrG   )rN   )r·   Úbs     rK   r¹   z9ResetBudgetJob._collect_budget_cascade.<locals>.<genexpr>s  s   è ø€ Ò!c°!È1Ï;É;ÑKb !§+¥+Ñ!cùs   ‚%”%zteam memberships)r  r²   r  Nr#  ÚorgsÚtagszmodel access groupsc              3   ó¨   •K  — | ]I  }|j                   �;|j                  �/|j                   t        |j                  ‰j                  ¬«      f–— ŒK y ­w)N©r?   Úsettings)rN   r?   r&   r0  )r·   r‚  rJ   s     €rK   r¹   z9ResetBudgetJob._collect_budget_cascade.<locals>.<genexpr>�  sP   øè ø€ ò  ð
 Ø—;‘;Ð*¨q×/@Ñ/@Ð/Lð	 —K‘KÜ+¸A×<MÑ<MÐX\×XkÑXkÔlôñ ùs   ƒAAc              3   óL   •K  — | ]  }t        |«      t        |‰«      f–— Œ y ­wrG   )r†   r‚   ©r·   r~   r¶   s     €rK   r¹   z9ResetBudgetJob._collect_budget_cascade.<locals>.<genexpr>§  s,   øè ø€ ò àô 2°#Ó6Ô8JÈ3ÐP]Ó8^Ô_ñùó   ƒ!$c              3   óL   •K  — | ]  }t        |«      t        |‰«      f–— Œ y ­wrG   )r�   r‚   r‰  s     €rK   r¹   z9ResetBudgetJob._collect_budget_cascade.<locals>.<genexpr>«  ó%   øè ø€ ÒbÐVYÔ# CÓ(Ô*<¸SÀ-Ó*PÔQÑbùrŠ  c              3   óL   •K  — | ]  }t        |«      t        |‰«      f–— Œ y ­wrG   )r’   r‚   r‰  s     €rK   r¹   z9ResetBudgetJob._collect_budget_cascade.<locals>.<genexpr>¬  rŒ  rŠ  c              3   óL   •K  — | ]  }t        |«      t        |‰«      f–— Œ y ­wrG   )r–   r‚   r‰  s     €rK   r¹   z9ResetBudgetJob._collect_budget_cascade.<locals>.<genexpr>­  rŒ  rŠ  c              3   óL   •K  — | ]  }t        |«      t        |‰«      f–— Œ y ­wrG   )rš   r‚   r‰  s     €rK   r¹   z9ResetBudgetJob._collect_budget_cascade.<locals>.<genexpr>®  s,   øè ø€ ò àô 5°SÓ9Ô;MÈcÐS`Ó;aÔbñùrŠ  c              3   óL   •K  — | ]  }t        |«      t        |‰«      f–— Œ y ­wrG   )rž   r¤   r‰  s     €rK   r¹   z9ResetBudgetJob._collect_budget_cascade.<locals>.<genexpr>²  s%   øè ø€ ÒnÐ^aÔ'¨Ó,Ô.DÀSÈ-Ó.XÔYÑnùrŠ  c              3   ó@   K  — | ]  }t        |«      D ]  }|–— Œ Œ y ­wrG   )r‰   ©r·   r~   r$  s      rK   r¹   z9ResetBudgetJob._collect_budget_cascade.<locals>.<genexpr>¶  s#   è ø€ Ò^˜#Ô=XÐY\Ó=]Ò^°c”#Ð^�#Ñ^ùó   ‚c              3   ó@   K  — | ]  }t        |«      D ]  }|–— Œ Œ y ­wrG   )r�   r’  s      rK   r¹   z9ResetBudgetJob._collect_budget_cascade.<locals>.<genexpr>·  ó!   è ø€ ÒF˜#´ÀÓ1EÒF¨#”#ÐF�#ÑFùr“  c              3   ó@   K  — | ]  }t        |«      D ]  }|–— Œ Œ y ­wrG   )r”   r’  s      rK   r¹   z9ResetBudgetJob._collect_budget_cascade.<locals>.<genexpr>¸  r•  r“  c              3   ó@   K  — | ]  }t        |«      D ]  }|–— Œ Œ y ­wrG   )r˜   r’  s      rK   r¹   z9ResetBudgetJob._collect_budget_cascade.<locals>.<genexpr>¹  r•  r“  c              3   ó@   K  — | ]  }t        |«      D ]  }|–— Œ Œ y ­wrG   )rœ   r’  s      rK   r¹   z9ResetBudgetJob._collect_budget_cascade.<locals>.<genexpr>º  s#   è ø€ Òd˜#Ô@^Ð_bÓ@cÒd¸”#Ðd�#Ñdùr“  c              3   ó@   K  — | ]  }t        |«      D ]  }|–— Œ Œ y ­wrG   )r    r’  s      rK   r¹   z9ResetBudgetJob._collect_budget_cascade.<locals>.<genexpr>»  s"   è ø€ ÒN˜#Ô5HÈÓ5MÒN¨c”#ÐN�#ÑNùr“  )rÈ   r¥   rÉ   rÊ   rË   r¶   rÌ   )r½   rÚ   rr  r6   r  r  rª   r;   rA   r1   rB   r5   r4   r   rr   rN   rw   rs   r~  r­   )rJ   r  r¥   Úteam_membershipsr#  rƒ  r„  Úmodel_access_groupsr‚  rx   rÊ   r¶   s   `          @rK   Ú_collect_budget_cascadez&ResetBudgetJob._collect_budget_cascadel  s  ùè ø€ ô "Ñ!cÐ7GÔ!cÓcˆ
ÙÜ!Ð!àHL×H_ÑH_Ü*¨4×+=Ñ+=Ó>×DÑDÜ$ ZÓ0Ø*ð I`ó I
÷ C
Ðð
 26×1HÑ1HÜ-¨d×.@Ñ.@ÓA×GÑGÜ$ ZÔ1CÓDØð 2Ió 2
÷ ,
ˆð
 26×1HÑ1HÜ(¨×);Ñ);Ó<×BÑBÜ$ ZÔ1BÓCØð 2Ió 2
÷ ,
ˆð
 26×1HÑ1HÜ × 2Ñ 2Ó3×9Ñ9Ü$ ZÔ1BÓCØð 2Ió 2
÷ ,
ˆð
 NR×MdÑMdÜ2°4×3EÑ3EÓF×LÑLÜ$ ZÔ1BÓCØ-ð Neó N
÷ H
Ðô
 5Eô !Ô"ð *öàØ—;‘;Ð*´}ÀQÇ\Á\Ó7RÐ0R°Ð/_ð —‘˜SÑ óð ó5
ˆð :>×9XÑ9XÐYcÓ9d×3dˆÜÜÐ*Ó+Ø!Üó  ð
 *ô ó ð ðóà/ôðó
 cÐ]aÔbðó cÐ]aÔbðó cÐ]aÔbðóà2ôðó oÐemÔnñð (ðÙ^Ð!1Ô^ðáF ÔFðñ G ÔFðñ G ÔFð	ñ
 eÐ!4Ôdðñ O ÔNñô7#
ð #	
ðGC
ùð
,
ùð
,
ùð
,
ùð
H
ûòð 4eús}   „AJ&ÁJÁAJ&Â#JÂ$AJ&Ã*JÃ+AJ&Ä1JÄ2AJ&Å8JÅ9J&Æ7JÇJ&Ç$J$Ç%B,J&ÊJ&ÊJ&ÊJ&ÊJ&ÊJ&r¬   c              ƒ   ól   ‡ ‡K  — ‰j                   sy‰ j                  ˆˆ fd„d¬«      ƒ d{  –—†  y7 Œ­w)a\  Zero the gated spend and advance ``budget_reset_at`` in one transaction.

        Advancing the window on its own hides the tier from every later tick
        while its dependents stay pinned at the cap for the whole window;
        batching both means a mid-cascade failure persists nothing and the rows
        stay due for the next run.
        Nc                  ó&   •— ‰j                  ‰ «      S rG   )Ú_commit_budget_cascade_once)r¬   rJ   s   €€rK   rÎ   z7ResetBudgetJob._commit_budget_cascade.<locals>.<lambda>Ë  s   ø€ �D×4Ñ4°WÓ=€ rL   Ú)reset_budget_write_budget_cascade_failurerP  )r¥   rU  )rJ   r¬   s   ``rK   Ú_commit_budget_cascadez%ResetBudgetJob._commit_budget_cascade¿  s8   ùè ø€ ð ×!Ò!Øà×'Ñ'Ü=Ø>ð (ó 
÷ 	
ò 	
ús   „(4¬2­4c              ƒ   ó\  K  — t        | j                  j                  j                  «      4 ƒd {  –—† }t	        |j
                  |«       t	        |j                  |t        ¬«       t	        |j                  |t        ¬«       t	        |j                  |t        ¬«       t	        |j                  |t        ¬«       t        |j                  |«       |j                  D ]"  \  }}|j                  j!                  ||¬«       Œ$ d d d «      ƒd {  –—†  y 7 Œâ7 Œ# 1 ƒd {  –—†7  sw Y   y xY w­w)NrÁ   )rN   Úbudget_reset_at)r9   r  ÚdbÚbatch_r¿   rš  r#  rA   ÚorganizationsrB   r„  r›  rÄ   rÊ   rÉ   rÈ   Úqueue_window_advance)rJ   r¬   ÚuowrN   r£  s        rK   rŸ  z*ResetBudgetJob._commit_budget_cascade_onceÏ  sõ   è ø€ Ü.¨t×/AÑ/A×/DÑ/D×/KÑ/KÓL÷ 	gð 	gÐPSÜ'¨×(<Ñ(<¸gÔFÜ'¨¯©°'ÔASÕTÜ'¨×(9Ñ(9¸7ÔJ[Õ\Ü'¨¯©°'ÔARÕSÜ'¨×(?Ñ(?ÀÔPaÕbÜ! #§,¡,°Ô8Ø.5×.CÑ.Cò gÑ*�	˜?Ø—‘×0Ñ0¸9ÐVeÐ0Õfðg÷	g÷ 	gñ 	gøð 	gø÷ 	g÷ 	gñ 	güsE   ‚.D,°D±D,´CDÄD,ÄDÄD,ÄD,ÄD)ÄD ÄD)Ä%D,c              ƒ   óÆ   K  — |j                   D ]   \  }}| j                  ||¬«      ƒ d {  –—†  Œ" |j                  D ]  }| j                  |«      ƒ d {  –—†  Œ y 7 Œ17 Œ	­w)N©rW  )rË   rb  rÌ   rd  )rJ   r¬   rV  rW  rf  s        rK   Ú!_invalidate_budget_cascade_cachesz0ResetBudgetJob._invalidate_budget_cascade_cachesÚ  sp   è ø€ Ø&-×&<Ñ&<ò 	SÑ"ˆK˜Ø×0Ñ0°È	Ð0ÓR×RÑRð	Sà ×+Ñ+ò 	GˆIØ×;Ñ;¸IÓF×FÑFñ	Gð SøàFús!   ‚)A!«A¬)A!ÁAÁA!ÁA!c           	   ƒ   ól  ‡ ‡K  — t        j                  t        j                  «      Š	 ‰ j	                  ˆˆ fd„d¬«      ƒ d {  –—† }‰ j                  |xs d«      ƒ d {  –—† }	 ‰ j                  |«      ƒ d {  –—†  ‰ j                  |«      ƒ d {  –—†  t        |t        d„ |j                  D «       t        j                  t        j                  «      ¬«      ¬«      S 7 Œž7 Œƒ# t        $ r}t        t        |¬«      cY d }~S d }~ww xY w7 Œ’# t        $ r}t        ||¬«      cY d }~S d }~ww xY w7 Œž­w)	Nc                  óJ   •— ‰j                   j                  dd‰ t        ¬«      S )NÚbudgetrv  ©rw  rx  rí   Úlimit©r  rz  r   ©ÚnowrJ   s   €€rK   rÎ   z>ResetBudgetJob._reset_expired_budget_cascade.<locals>.<lambda>ä  s)   ø€ ˜×*Ñ*×3Ñ3Ø'Ø)Ø Ü5ð	 4ó € rL   Ú!reset_budget_read_budgets_failurerP  rH   ©r¬   rØ   c              3   ó&   K  — | ]	  \  }}|–— Œ y ­wrG   rH   )r·   rˆ   rí   s      rK   r¹   z?ResetBudgetJob._reset_expired_budget_cascade.<locals>.<genexpr>ù  s   è ø€ ÒC™k˜a ”ÑCùs   ‚©rè   ©r¬   rÔ   )r
   r³  r   rå   rR  rœ  rÙ   r×   rÚ   r¡  r«  rÓ   rð   rÉ   )rJ   r  r¬   ra  r³  s   `   @rK   Ú_reset_expired_budget_cascadez,ResetBudgetJob._reset_expired_budget_cascadeà  s  ùè ø€ Ü—\‘\¤(§,¡,Ó/ˆð	IØVZ×ViÑViôð ;ð Wjó W÷ QÐð $(×#?Ñ#?Ð@PÒ@VÐTVÓ#W×WˆGð	BØ×-Ñ-¨gÓ6×6Ð6ð ×4Ñ4°WÓ=×=Ð=Ü&ØÜ$ÙC¨W×-BÑ-BÔCÜ—|‘|¤H§L¡LÓ1ôô
ð 	
ð'Qøð XùÜò 	IÜ'´ÀaÔHÕHûð	Iúð 7ùÜò 	BÜ'°¸qÔAÕAûð	Búð 	>ús¡   „$D4©C& ÁC"ÁC& Á C$Á!C& Á&D Á:DÁ;D Á?D4ÂD2ÂAD4Ã"C& Ã$C& Ã&	D
Ã/DÃ?D
Ä D4ÄD
Ä
D4ÄD Ä	D/ÄD*Ä$D/Ä%D4Ä*D/Ä/D4c              ƒ   óJ   K  — t        | j                  «      ƒ d{  –—†  y7 Œ­w)aV  
        Resets the spend a budget tier gates (end users, team members, keys,
        orgs, tags, model access groups) and advances the tier's
        budget_reset_at, atomically.

        Caches are invalidated only after the transaction commits, so a failed
        run cannot leave a zeroed counter in front of an un-reset DB row.
        N)r÷   Ú,_reset_budget_for_litellm_budget_table_chunkrI   s    rK   rH  z4ResetBudgetJob.reset_budget_for_litellm_budget_tableþ  s   è ø€ ô # 4×#TÑ#TÓU×UÒUúó   ‚#›!œ#c              ƒ   óú  K  — t        j                   «       }| j                  «       ƒ d {  –—† }t        j                   «       }|xt        d˜ x�—\  }} t        j                  | j
                  j                  j                  t        j                  ||z
  d||i t        |«      ¥t        |j                  «      ddœ¥¬«      «       t        t        |j                  «      |¬«      S  t        d˜ x�{\  }}t!        j"                  d||¬	«       t        j                  | j
                  j                  j%                  t        j                  ||z
  |d
||t        |«      ¬«      «       t&        S  	 t)        |«       y 7 �ŒN­w)Nr¸  Úreset_budget_budget_tabler   )Únum_endusers_updatedÚnum_endusers_failed©ÚserviceÚdurationÚ	call_typeÚ
start_timeÚend_timeÚevent_metadatarÞ   rµ  zÁFailed to reset the budget table cascade (team member, enduser, org, tag and model access group spend, plus budget_reset_at); nothing was committed and the budgets stay due for the next run: %s)Úexc_infoÚreset_budget_endusers©rÂ  rÃ  rØ   rÄ  rÅ  rÆ  rÇ  )Útimer¹  rÓ   ÚasyncioÚcreate_taskr/  Úservice_logging_objÚasync_service_success_hookr<   ÚRESET_BUDGET_JOBr,  r+  rÊ   rÜ   rÈ   r×   r   Ú	exceptionÚasync_service_failure_hookrß   r   )rJ   rÅ  rñ   rÆ  r¬   rÔ   rØ   s          rK   r»  z;ResetBudgetJob._reset_budget_for_litellm_budget_table_chunk	  sd  è ø€ Ü ŸI™I›Kˆ
Ø#×AÑAÓC×CˆÜŸ)™)›+ˆàØLÔ(×LÐLÜ×#Ñ#Ø×*Ñ*×>Ñ>×YÑYÜ ,× =Ñ =Ø!)¨JÑ!6Ø"=Ø#-Ø!)ð(Ü<¸WÓEð(ä47¸×8HÑ8HÓ4IØ34ò(ð Zó ôô %¬S°·±Ó-AÈHÔUÐUð Mô  &×CÜ$×.Ñ.ð#ð Ø"õô ×#Ñ#Ø×*Ñ*×>Ñ>×YÑYÜ ,× =Ñ =Ø!)¨JÑ!6Ø#Ø"9Ø#-Ø!)Ü'EÀgÓ'Nð Zó ô
ô $Ð#ð' Dð( Ü˜WÕ%ðS Dûs   ‚(E;ªE8«EE;c              ƒ   óö   ‡K  — t        | j                  «      j                  Š| j                  ˆfd„d¬«      ƒ d{  –—† }|D �cg c]%  }t	        j
                  |j                  «       «      ‘Œ' c}S 7 Œ5c c}w ­w)a  
        Fetch end users that have no explicit budget_id set (NULL) and have
        accumulated spend > 0.  These are implicitly-created end users that
        rely on the default budget (litellm.max_end_user_budget_id) applied
        in-memory during auth checks.
        c                  ó2   •— ‰ j                  d ddidœ¬«      S )Nr>   r   rÂ   r±   rm  )r  s   €rK   rÎ   z@ResetBudgetJob._get_endusers_with_no_budget_id.<locals>.<lambda>A  s$   ø€ �E—O‘Oà!%Ø" A˜Yñð $ó € rL   Ú4reset_budget_read_endusers_without_budget_id_failurerP  N)r3   r  r  rR  r    Úmodel_validateÚ
model_dump)rJ   Úrowsr~   r  s      @rK   r|  z.ResetBudgetJob._get_endusers_with_no_budget_id6  sw   øè ø€ ô )¨×);Ñ);Ó<×BÑBˆØ ×/Ñ/óð Jð 0ó 
÷ 
ˆð RVÖVÈ#Ô$×3Ñ3°C·N±NÓ4DÕEÒVÐVð
úò Wùs!   ƒ9A9¼A2½A9Á*A4Á/A9Á4A9Úupdated_keysc              ƒ   óR   ‡ ‡K  — ‰ j                  ˆ ˆfd„d¬«      ƒ d{  –—†  y7 Œ­w)uß  
        Write per-row {spend, budget_reset_at} updates for keys.

        Avoids the batched full-model update path, which trips
        prisma.errors.DataError on any row carrying object_permission_id or
        budget_limits (see #27730). Both fields are rejected by Prisma's
        update input type for LiteLLM_VerificationToken, and the failure
        aborts the entire batch â€” silently leaving spend over the cap and
        budget_reset_at unchanged forever.
        c                  ó&   •— ‰ j                  ‰«      S rG   )Ú_write_key_reset_updates_once©rJ   rÙ  s   €€rK   rÎ   z9ResetBudgetJob._write_key_reset_updates.<locals>.<lambda>W  s   ø€ �D×6Ñ6°|ÓD€ rL   Úreset_budget_write_keys_failurerP  N©rU  rÝ  s   ``rK   Ú_write_key_reset_updatesz'ResetBudgetJob._write_key_reset_updatesK  s,   ùè ø€ ð ×'Ñ'ÜDØ4ð (ó 
÷ 	
ò 	
úó   „'Ÿ% 'c              ƒ   óŒ  K  — t        | j                  j                  j                  «      4 ƒd {  –—† }|D ]`  }|j                  €Œ|j
                  j                  |j                  |j                  |j                  xs ddkD  r|j                  nd ¬«       Œb d d d «      ƒd {  –—†  y 7 Œz7 Œ# 1 ƒd {  –—†7  sw Y   y xY w­w)Nr{   )r_   r£  Úspend_decrement)
r:   r  r¤  r¥  r_   r#  Úqueue_spend_resetr£  r@   rs   )rJ   rÙ  r¨  Úks       rK   rÜ  z,ResetBudgetJob._write_key_reset_updates_once[  s¬   è ø€ Ü+¨D×,>Ñ,>×,AÑ,A×,HÑ,HÓI÷ 	ð 	ÈSØ!ò �Ø—7‘7�?ØØ—‘×*Ñ*ØŸ'™'Ø$%×$5Ñ$5Ø56·W±W²^ÀÀsÒ4J A§L¢LÐPTð +õ ð÷	÷ 	ñ 	øð 	ø÷ 	÷ 	ñ 	üsE   ‚.C°B+±C´A&B/ÂCÂ%B-Â&CÂ-CÂ/CÂ5B8Â6CÂ=CÚupdated_usersc              ƒ   óR   ‡ ‡K  — ‰ j                  ˆ ˆfd„d¬«      ƒ d{  –—†  y7 Œ­w)uü   
        Write per-row {spend, budget_reset_at} updates for users.

        Mirrors _write_key_reset_updates â€” avoids the full-model update path
        that trips Prisma's DataError on rows carrying unrecognised fields
        (see #27730).
        c                  ó&   •— ‰ j                  ‰«      S rG   )Ú_write_user_reset_updates_once©rJ   ræ  s   €€rK   rÎ   z:ResetBudgetJob._write_user_reset_updates.<locals>.<lambda>o  ó   ø€ �D×7Ñ7¸ÓF€ rL   Ú reset_budget_write_users_failurerP  Nrß  rê  s   ``rK   Ú_write_user_reset_updatesz(ResetBudgetJob._write_user_reset_updatesf  ó,   ùè ø€ ð ×'Ñ'ÜFØ5ð (ó 
÷ 	
ò 	
úrá  c              ƒ   ór  K  — t        | j                  j                  j                  «      4 ƒd {  –—† }|D ]S  }|j                  j                  |j                  |j                  |j                  xs ddkD  r|j                  nd ¬«       ŒU d d d «      ƒd {  –—†  y 7 Œm7 Œ# 1 ƒd {  –—†7  sw Y   y xY w­w)Nr{   )rX   r£  rã  )
r:   r  r¤  r¥  Úusersrä  rX   r£  r@   rs   )rJ   ræ  r¨  Úus       rK   ré  z-ResetBudgetJob._write_user_reset_updates_onces  ó    è ø€ Ü+¨D×,>Ñ,>×,AÑ,A×,HÑ,HÓI÷ 	ð 	ÈSØ"ò �Ø—	‘	×+Ñ+ØŸI™IØ$%×$5Ñ$5Ø56·W±W²^ÀÀsÒ4J A§L¢LÐPTð ,õ ð÷	÷ 	ñ 	øð 	ø÷ 	÷ 	ñ 	üóE   ‚.B7°B±B7´AB"ÂB7ÂB ÂB7Â B7Â"B4Â(B+Â)B4Â0B7Úupdated_teamsc              ƒ   óR   ‡ ‡K  — ‰ j                  ˆ ˆfd„d¬«      ƒ d{  –—†  y7 Œ­w)uü   
        Write per-row {spend, budget_reset_at} updates for teams.

        Mirrors _write_key_reset_updates â€” avoids the full-model update path
        that trips Prisma's DataError on rows carrying unrecognised fields
        (see #27730).
        c                  ó&   •— ‰ j                  ‰«      S rG   )Ú_write_team_reset_updates_once©rJ   rô  s   €€rK   rÎ   z:ResetBudgetJob._write_team_reset_updates.<locals>.<lambda>…  rë  rL   Ú reset_budget_write_teams_failurerP  Nrß  rø  s   ``rK   Ú_write_team_reset_updatesz(ResetBudgetJob._write_team_reset_updates|  rî  rá  c              ƒ   ór  K  — t        | j                  j                  j                  «      4 ƒd {  –—† }|D ]S  }|j                  j                  |j                  |j                  |j                  xs ddkD  r|j                  nd ¬«       ŒU d d d «      ƒd {  –—†  y 7 Œm7 Œ# 1 ƒd {  –—†7  sw Y   y xY w­w)Nr{   )r[   r£  rã  )
r:   r  r¤  r¥  r%  rä  r[   r£  r@   rs   )rJ   rô  r¨  Úts       rK   r÷  z-ResetBudgetJob._write_team_reset_updates_once‰  rò  ró  rÄ  rØ   rÅ  rÆ  rÇ  c                 óÒ   — t        j                  d||«       t        j                  | j                  j
                  j                  t        j                  ||z
  |||||¬«      «       y)zÍReport rows that could not be reset without failing the chunk: the
        rows that did reset are already committed, and raising here would cost
        the phase every remaining chunk this tick.
        z%s: %srÊ  N)	r   rØ   rÌ  rÍ  r/  rÎ  rÒ  r<   rÐ  )rJ   rÄ  rØ   rÅ  rÆ  rÇ  s         rK   Ú_emit_phase_failurez"ResetBudgetJob._emit_phase_failure’  sd   € ô 	×"Ñ" 8¨Y¸Ô>Ü×ÑØ×"Ñ"×6Ñ6×QÑQÜ$×5Ñ5Ø! JÑ.ØØ#Ø%Ø!Ø-ð Ró õ
	
rL   c              ƒ   óJ   K  — t        | j                  «      ƒ d{  –—†  y7 Œ­w)zf
        Resets the budget for all the litellm keys

        Catches Exceptions and logs them
        N)r÷   Ú$_reset_budget_for_litellm_keys_chunkrI   s    rK   rE  z,ResetBudgetJob.reset_budget_for_litellm_keys«  s   è ø€ ô # 4×#LÑ#LÓM×MÒMúr¼  c              ƒ   ó$  ‡ ‡K  — t        j                  «       Št        j                  «       }d }	 ‰ j                  ˆˆ fd„d¬«      ƒ d {  –—† }t	        j
                  dt        |«      «       g }g }|�æt        |«      dkD  rØ|D ]U  }	 t        j                  |‰‰ j                  ¬«      ƒ d {  –—† }|�|j                  |«       n|j                  |ddœ«       ŒW t	        j
                  d
t        |«      «       |r]‰ j                  |¬«      ƒ d {  –—†  |D ]>  }t!        |dd «      }	|	sŒ‰ j#                  d|	› �|j$                  xs d¬«      ƒ d {  –—†  Œ@ t        j                  «       }
t'        |rt        |«      ndt)        d„ |D «       t        j*                  t,        j.                  «      ¬«      ¬«      }t        |«      dkD  rX‰ j1                  dt        dt        |«      › dt3        j4                  |t        ¬«      › �«      ||
d|rt        |«      ndi¬«       |S t7        j8                  ‰ j:                  j<                  j?                  t@        jB                  |
|z
  d||
|rt        |«      ndt        |«      t        |«      dœ¬«      «       |S 7 �ŒK7 �Œë# t        $ r>}|j                  |t        |«      dœ«       t	        j                  d	|«       Y d }~�ŒYd }~ww xY w7 �ŒÓ7 �Œ•# t        $ r™}t        j                  «       }
t7        j8                  ‰ j:                  j<                  jE                  t@        jB                  |
|z
  |d||
d|rt        |«      ndi¬«      «       t	        j                  d|«       tF        cY d }~S d }~ww xY w­w)Nc                  óL   •— ‰j                   j                  dd‰ ‰ t        ¬«      S )Nr$  rv  )rw  rx  Úexpiresrí   r°  r±  r²  s   €€rK   rÎ   zEResetBudgetJob._reset_budget_for_litellm_keys_chunk.<locals>.<lambda>¹  s,   ø€ ˜×*Ñ*×3Ñ3Ø$Ø)ØØ Ü5ð 4ó € rL   Úreset_budget_read_keys_failurerP  zKeys to reset %sr   ©r$  Úcurrent_timer0  úReturned None without exception)r$  rØ   z"Failed to reset budget for key: %szUpdated keys %s)rÙ  r_   r‹   r{   rª  c              3   ó4   K  — | ]  }|j                   –— Œ y ­wrG   ©r£  )r·   rå  s     rK   r¹   zFResetBudgetJob._reset_budget_for_litellm_keys_chunk.<locals>.<genexpr>â  s   è ø€ Ò=¨1�Q×&Õ&Ñ=ùó   ‚r·  rÞ   Úreset_budget_keysúFailed to reset z keys: ©rþ   Únum_keys_found©rÄ  rØ   rÅ  rÆ  rÇ  )r  Únum_keys_updatedÚnum_keys_failedrÁ  rÊ  z#Failed to reset budget for keys: %s)$r
   ÚutcnowrË  rR  r   rB  rù   r+  r.  Ú_reset_budget_for_keyr0  ÚappendrÙ   rT   rÑ  rà  Úgetattrrb  r@   rÜ   rð   r³  r   rå   rþ  rÿ   r   rÌ  rÍ  r/  rÎ  rÏ  r<   rÐ  rÒ  rß   )rJ   rÅ  Úkeys_to_resetrÙ  Úfailed_keysr$  Úupdated_keyra  rå  r_   rÆ  rñ   r³  s   `           @rK   r   z3ResetBudgetJob._reset_budget_for_litellm_keys_chunk³  s…  ùè ø€ Ü—_‘_Ó&ˆÜ ŸI™I›Kˆ
Ø@Dˆð[	Ø"&×"5Ñ"5ôð 8ð #6ó 	#÷ 	ˆMô !×&Ñ&Ð'9¼9À]Ó;SÔTØCEˆLØ!#ˆKØÐ(¬S°Ó-?À!Ò-CØ(ò b�CðbÜ,:×,PÑ,PØ #Ø),Ø+/×+>Ñ+>ð -Qó -÷ '˜ð
 'Ð2Ø(×/Ñ/°Õ<à'×.Ñ.°sÐEfÑ/gÔhøðbô %×*Ñ*Ð+<¼iÈÓ>UÔVáØ×7Ñ7À\Ð7ÓR×RÐRØ)ò q˜Ü '¨¨7°DÓ 9˜Ú Ø"&×"@Ñ"@À:ÈeÈWÐAUÐab×ahÑahÒaoÐloÐ"@Ó"p×pÑpðqô
 —y‘y“{ˆHÜ*Ù.;œ˜MÔ*ÀÜ(Ù=°Ô=Ü#Ÿ<™<¬¯©Ó5ôôˆGô �;Ó !Ò#Ø×(Ñ(Ø1Ü#Ð&6´s¸;Ó7GÐ6HÈÔPT×PZÑPZÐ[fÔpsÔPtÐOuÐ$vÓwØ)Ø%à(Á¬#¨mÔ*<ÐSTð$ð )ô ð �ä×ÑØ×&Ñ&×:Ñ:×UÑUÜ(×9Ñ9Ø%¨
Ñ2Ø1Ø)Ø%á@M¬#¨mÔ*<ÐSTÜ,/°Ó,=Ü+.¨{Ó+;ñ$ð Vó ôð@ ˆNðu	ùð 'úô %ò bØ#×*Ñ*°3ÄÀQÃÑ+HÔIÜ,×6Ñ6Ð7[Ð]`×aÒaûðbúð Sùð qúôH ò 	 Ü—y‘y“{ˆHÜ×ÑØ×&Ñ&×:Ñ:×UÑUÜ(×9Ñ9Ø%¨
Ñ2ØØ1Ø)Ø%à(Á¬#¨mÔ*<ÐSTð$ð Vó 
ôô !×*Ñ*Ð+PÐRSÔTÜÕûð!	 üsµ   „+N°K+ Á
JÁ<K+ Â%JÂ-JÂ.,JÃ8K+ ÄK%ÄK+ Ä,'K+ ÅK(ÅCK+ È NÈ!A2K+ ÊNÊK+ ÊJÊ	K"Ê$3KËK+ ËK"Ë"K+ Ë(K+ Ë+	NË4BNÎNÎNÎNÎNc              ƒ   óJ   K  — t        | j                  «      ƒ d{  –—†  y7 Œ­w)z^
        Resets the budget for all LiteLLM Internal Users if their budget has expired
        N)r÷   Ú%_reset_budget_for_litellm_users_chunkrI   s    rK   rF  z-ResetBudgetJob.reset_budget_for_litellm_users  ó   è ø€ ô # 4×#MÑ#MÓN×NÒNúr¼  c              ƒ   ó0  ‡ ‡K  — t        j                  «       Št        j                  «       }d }	 ‰ j                  ˆˆ fd„d¬«      ƒ d {  –—† }g }g }|��t	        |«      dkD  rù|D ]U  }	 t
        j                  |‰‰ j                  ¬«      ƒ d {  –—† }|�|j                  |«       n|j                  |ddœ«       ŒW t        j                  d	t        |«      «       |r~‰ j                  |¬
«      ƒ d {  –—†  |D ]_  }t!        |dd «      }	|	r,‰ j#                  d|	› �|j$                  xs d¬«      ƒ d {  –—†  |	t&        k(  sŒH‰ j)                  «       ƒ d {  –—†  Œa t        j                  «       }
t+        |rt	        |«      ndt-        d„ |D «       t        j.                  t0        j2                  «      ¬«      ¬«      }t	        |«      dkD  rX‰ j5                  dt        dt	        |«      › dt7        j8                  |t        ¬«      › �«      ||
d|rt	        |«      ndi¬«       |S t;        j<                  ‰ j>                  j@                  jC                  tD        jF                  |
|z
  d||
|rt	        |«      ndt	        |«      t	        |«      dœ¬«      «       |S 7 �ŒN7 �Œ# t        $ r>}|j                  |t        |«      dœ«       t        j                  d|«       Y d }~�Œzd }~ww xY w7 �Œô7 �Œ·7 �Œ˜# t        $ r™}t        j                  «       }
t;        j<                  ‰ j>                  j@                  jI                  tD        jF                  |
|z
  |d||
d|rt	        |«      ndi¬«      «       t        j                  d|«       tJ        cY d }~S d }~ww xY w­w)Nc                  óJ   •— ‰j                   j                  dd‰ t        ¬«      S )NÚuserrv  r¯  r±  r²  s   €€rK   rÎ   zFResetBudgetJob._reset_budget_for_litellm_users_chunk.<locals>.<lambda>   ó)   ø€ ˜×*Ñ*×3Ñ3Ø%Ø)Ø Ü5ð	 4ó € rL   Úreset_budget_read_users_failurerP  r   ©r  r  r0  r  )r  rØ   z#Failed to reset budget for user: %szUpdated users %s)ræ  rX   zspend:user:r{   rª  c              3   ó4   K  — | ]  }|j                   –— Œ y ­wrG   r	  )r·   rñ  s     rK   r¹   zGResetBudgetJob._reset_budget_for_litellm_users_chunk.<locals>.<genexpr>M  ó   è ø€ Ò>¨1�Q×&Õ&Ñ>ùr
  r·  rÞ   Úreset_budget_usersr  z users: r  Únum_users_foundr  )r%  Únum_users_updatedÚnum_users_failedrÁ  rÊ  z$Failed to reset budget for users: %s)&r
   r  rË  rR  r+  r.  Ú_reset_budget_for_userr0  r  rÙ   rT   r   rÑ  rB  rù   rí  r  rb  r@   r   re  rÜ   rð   r³  r   rå   rþ  rÿ   r   rÌ  rÍ  r/  rÎ  rÏ  r<   rÐ  rÒ  rß   )rJ   rÅ  Úusers_to_resetræ  Úfailed_usersr  Úupdated_userra  rñ  rX   rÆ  rñ   r³  s   `           @rK   r  z4ResetBudgetJob._reset_budget_for_litellm_users_chunk  s”  ùè ø€ Ü—_‘_Ó&ˆÜ ŸI™I›Kˆ
Ø9=ˆða	Ø#'×#6Ñ#6ôð 9ð $7ó $÷ ˆNð =?ˆMØ"$ˆLØÑ)¬c°.Ó.AÀAÒ.EØ*ò d�DðdÜ-;×-RÑ-RØ!%Ø),Ø+/×+>Ñ+>ð .Só .÷ (˜ð
 (Ð3Ø)×0Ñ0°Õ>à(×/Ñ/à,0Ø-Nñ!"ôøðdô( %×*Ñ*Ð+=¼yÈÓ?WÔXÙ Ø×8Ñ8À}Ð8ÓU×UÐUØ*ò N˜Ü")¨!¨Y¸Ó"=˜Ù"Ø"&×"@Ñ"@À;ÈwÈiÐAXÐde×dkÑdkÒdrÐorÐ"@Ó"s×sÐsØ"Ô&?Ó?Ø"&×"KÑ"KÓ"M×MÑMðNô —y‘y“{ˆHÜ*Ù/=œ˜NÔ+À1Ü(Ù>°Ô>Ü#Ÿ<™<¬¯©Ó5ôôˆGô �<Ó  1Ò$Ø×(Ñ(Ø2Ü#Ø*¬3¨|Ó+<Ð*=¸XÄdÇjÁjÐQ]ÔgjÔFkÐElÐmóð  *Ø%à)Á.¬3¨~Ô+>ÐVWð$ð )ô 
ð �ä×ÑØ×&Ñ&×:Ñ:×UÑUÜ(×9Ñ9Ø%¨
Ñ2Ø2Ø)Ø%áBP¬3¨~Ô+>ÐVWÜ-0°Ó-?Ü,/°Ó,=ñ$ð Vó ôð@ ˆNðAùð(úô %ò dØ$×+Ñ+°TÄCÈÃFÑ,KÔLÜ,×6Ñ6Ð7\Ð^b×cÒcûðdúð Vùð tùàMúôL ò 	 Ü—y‘y“{ˆHÜ×ÑØ×&Ñ&×:Ñ:×UÑUÜ(×9Ñ9Ø%¨
Ñ2ØØ2Ø)Ø%à)Á.¬3¨~Ô+>ÐVWð$ð Vó 
ôô !×*Ñ*Ð+QÐSTÔUÜÕûð!	 üsÇ   „+N°K1 Á
JÁK1 Á*%JÂJÂ,JÂ<8K1 Ã4K(Ã5?K1 Ä4K+Ä5K1 ÅK1 ÅK.ÅCK1 È#NÈ$A2K1 ÊNÊK1 ÊJÊ	K%Ê'3K ËK1 Ë K%Ë%K1 Ë+K1 Ë.K1 Ë1	NË:BNÎNÎ	NÎNÎNc              ƒ   óJ   K  — t        | j                  «      ƒ d{  –—†  y7 Œ­w)z^
        Resets the budget for all LiteLLM Internal Teams if their budget has expired
        N)r÷   Ú%_reset_budget_for_litellm_teams_chunkrI   s    rK   rG  z-ResetBudgetJob.reset_budget_for_litellm_teams�  r  r¼  c              ƒ   óæ  ‡ ‡K  — t        j                  «       Št        j                  «       }d }	 ‰ j                  ˆˆ fd„d¬«      ƒ d {  –—† }g }g }|�æt	        |«      dkD  rØ|D ]U  }	 t
        j                  |‰‰ j                  ¬«      ƒ d {  –—† }|�|j                  |«       n|j                  |ddœ«       ŒW t        j                  d	t        |«      «       |r]‰ j                  |¬
«      ƒ d {  –—†  |D ]>  }t!        |dd «      }	|	sŒ‰ j#                  d|	› �|j$                  xs d¬«      ƒ d {  –—†  Œ@ t        j                  «       }
t'        |rt	        |«      ndt)        d„ |D «       t        j*                  t,        j.                  «      ¬«      ¬«      }t	        |«      dkD  rX‰ j1                  dt        dt	        |«      › dt3        j4                  |t        ¬«      › �«      ||
d|rt	        |«      ndi¬«       |S t7        j8                  ‰ j:                  j<                  j?                  t@        jB                  |
|z
  d||
|rt	        |«      ndt	        |«      t	        |«      dœ¬«      «       |S 7 �Œ,7 �Œë# t        $ r>}|j                  |t        |«      dœ«       t        j                  d|«       Y d }~�ŒYd }~ww xY w7 �ŒÓ7 �Œ•# t        $ r™}t        j                  «       }
t7        j8                  ‰ j:                  j<                  jE                  t@        jB                  |
|z
  |d||
d|rt	        |«      ndi¬«      «       t        j                  d|«       tF        cY d }~S d }~ww xY w­w)Nc                  óJ   •— ‰j                   j                  dd‰ t        ¬«      S )Nr&  rv  r¯  r±  r²  s   €€rK   rÎ   zFResetBudgetJob._reset_budget_for_litellm_teams_chunk.<locals>.<lambda>�  r  rL   Úreset_budget_read_teams_failurerP  r   ©r&  r  r0  r  )r&  rØ   z#Failed to reset budget for team: %szUpdated teams %s)rô  r[   zspend:team:r{   rª  c              3   ó4   K  — | ]  }|j                   –— Œ y ­wrG   r	  )r·   rü  s     rK   r¹   zGResetBudgetJob._reset_budget_for_litellm_teams_chunk.<locals>.<genexpr>¸  r#  r
  r·  rÞ   Úreset_budget_teamsr  z teams: r  Únum_teams_foundr  )r4  Únum_teams_updatedÚnum_teams_failedrÁ  rÊ  z$Failed to reset budget for teams: %s)$r
   r  rË  rR  r+  r.  Ú_reset_budget_for_teamr0  r  rÙ   rT   r   rÑ  rB  rù   rú  r  rb  r@   rÜ   rð   r³  r   rå   rþ  rÿ   r   rÌ  rÍ  r/  rÎ  rÏ  r<   rÐ  rÒ  rß   )rJ   rÅ  Úteams_to_resetrô  Úfailed_teamsr&  Úupdated_teamra  rü  r[   rÆ  rñ   r³  s   `           @rK   r-  z4ResetBudgetJob._reset_budget_for_litellm_teams_chunk‡  su  ùè ø€ Ü—_‘_Ó&ˆÜ ŸI™I›Kˆ
Ø9=ˆð_	Ø#'×#6Ñ#6ôð 9ð $7ó $÷ ˆNð =?ˆMØ"$ˆLØÐ)¬c°.Ó.AÀAÒ.EØ*ò d�DðdÜ-;×-RÑ-RØ!%Ø),Ø+/×+>Ñ+>ð .Só .÷ (˜ð
 (Ð3Ø)×0Ñ0°Õ>à(×/Ñ/à,0Ø-Nñ!"ôøðdô( %×*Ñ*Ð+=¼yÈÓ?WÔXÙ Ø×8Ñ8À}Ð8ÓU×UÐUØ*ò t˜Ü")¨!¨Y¸Ó"=˜Ú"Ø"&×"@Ñ"@À;ÈwÈiÐAXÐde×dkÑdkÒdrÐorÐ"@Ó"s×sÑsðtô
 —y‘y“{ˆHÜ*Ù/=œ˜NÔ+À1Ü(Ù>°Ô>Ü#Ÿ<™<¬¯©Ó5ôôˆGô �<Ó  1Ò$Ø×(Ñ(Ø2Ü#Ø*¬3¨|Ó+<Ð*=¸XÄdÇjÁjÐQ]ÔgjÔFkÐElÐmóð  *Ø%à)Á.¬3¨~Ô+>ÐVWð$ð )ô 
ð �ä×ÑØ×&Ñ&×:Ñ:×UÑUÜ(×9Ñ9Ø%¨
Ñ2Ø2Ø)Ø%áBP¬3¨~Ô+>ÐVWÜ-0°Ó-?Ü,/°Ó,=ñ$ð Vó ôð@ ˆNð}ùð(úô %ò dØ$×+Ñ+°TÄCÈÃFÑ,KÔLÜ,×6Ñ6Ð7\Ð^b×cÒcûðdúð Vùð túôL ò 	 Ü—y‘y“{ˆHÜ×ÑØ×&Ñ&×:Ñ:×UÑUÜ(×9Ñ9Ø%¨
Ñ2ØØ2Ø)Ø%à)Á.¬3¨~Ô+>ÐVWð$ð Vó 
ôô !×*Ñ*Ð+QÐSTÔUÜÕûð!	 üsµ   „+M1°K Á
I6ÁK Á)%I<ÂI9Â,I<Â;8K Ã3KÃ4K Ä'K Ä4K	Ä5CK ÈM1ÈA2K É4M1É6K É9I<É<	KÊ3J>Ê8K Ê>KËK Ë	K Ë	M.ËBM)Í#M.Í$M1Í)M.Í.M1ÚwindowrZ  r³  r  Ú	entity_idc              ƒ   óz  K  — | j                  d«      }|syt        j                  |j                  dd«      «      j                  d¬«      }	|	|kD  ryt        j                  | ||«      ƒ d{  –—† }
|j                  j                  ||
¬«       |j                  �&	 |j                  j                  ||
¬«      ƒ d{  –—†  | d	   }t        ||¬
«      }|j                  «       | d<   t        j                  |||||¬«      ƒ d{  –—†  y7 Œ›7 ŒN# t        $ r!}t        j                  d||«       Y d}~Œqd}~ww xY w7 Œ6­w)zNReset a single budget window if expired. Returns True if the window was reset.rí   FÚZz+00:00Nrâ   )r$  rú   z$Failed to reset Redis counter %s: %sr?   r†  )r  r  r<  r?   Únext_reset_atT)r�   r
   Úfromisoformaträ   r.  Ú_window_carried_spendr]  r^  r6  r_  rÙ   r   r:  r&   Ú	isoformatÚ_roll_window_spend_row)r;  rV  rZ  r³  r0  r  r  r<  Úreset_at_strrí   Ú	new_valuer`  r?   r?  s                 rK   Ú_reset_expired_windowz$ResetBudgetJob._reset_expired_windowì  sO  è ø€ ð %Ÿj™j¨Ó4ˆÙØÜ"×0Ñ0°×1EÑ1EÀcÈ8Ó1TÓU×]Ñ]ÐeiÐ]ÓjˆØ�cŠ>ØÜ!/×!EÑ!EÀfÈkÐ[nÓ!o×oˆ	Ø×+Ñ+×5Ñ5¸+ÈYÐ5ÔWØ×*Ñ*Ð6ðmØ)×5Ñ5×EÑEÈ+Ð]fÐEÓg×gÐgð "(Ð(9Ñ!:ˆÜ6ÀÐaoÔpˆØ*×4Ñ4Ó6ˆˆzÑÜ×3Ñ3Ø'Ø#ØØ+Ø'ð 4ó 
÷ 	
ð 	
ð ð# pøð hùÜò mÜ$×,Ñ,Ð-SÐU`Ðbk×lÑlûðmúð
	
ús[   ‚A*D;Á,DÁ--D;Â D Â;D
Â<D Ã AD;ÄD9ÄD;Ä
D Ä	D6ÄD1Ä,D;Ä1D6Ä6D;r?   r?  c              ƒ   óT  K  — 	 |t        t        |«      ¬«      z
  }	 t        | |j                  |||¬«      ƒ d{  –—†  y# t        $ r!}t        j                  d||«       Y d}~yd}~ww xY w7 Œ2# t        $ r-}t        j                  d|j                  |||«       Y d}~yd}~ww xY w­w)a|  Move this window's LiteLLM_BudgetWindowSpend row onto the window
        that just started, so the maintained total the read path uses starts
        from zero alongside the counter.

        Best effort: the row is an optimization over aggregating
        LiteLLM_SpendLogs, so a failure here must not stop the remaining
        windows from having their counters reset.
        )Úsecondsz"Unparseable budget_duration %s: %sN)r  r  r<  Úwindow_durationÚnew_window_startz>Failed to roll budget window spend row for %s=%s window=%s: %s)r   r   rÙ   r   r:  r,   rú   )r  r  r<  r?   r?  Úwindow_startra  s          rK   rC  z%ResetBudgetJob._roll_window_spend_row  s´   è ø€ ð 	Ø"/´)ÔDWÐXgÓDhÔ2iÑ"iˆLð	Ü'Ø+Ø'×-Ñ-Ø#Ø /Ø!-ô÷ ñ øô	 ò 	Ü ×(Ñ(Ð)MÈÐ`aÔbÜûð	úðùô ò 	Ü ×(Ñ(ØPØ×!Ñ!ØØØ÷ñ ûð	üs`   ‚B(„A  �A/ ºA-»A/ ¿B(Á 	A*Á	A%Á B(Á%A*Á*B(Á-A/ Á/	B%Á8#B ÂB(Â B%Â%B(c              ƒ   óz  K  — t        «       sy| j                  d«      }t        |t        t        f«      rt        |«      nd}|€y	 |j                  |¬«      ƒ d{  –—† }t        |t        t        f«      syt        t	        |«      |«      S 7 Œ0# t        $ r!}t        j                  d||«       Y d}~yd}~ww xY w­w)zzPer-window spend lives only in the counter, so the carried overage is
        read from it before the reset overwrites it.r{   rs   Nri  z0Failed to read spend counter %s for rollover: %s)rr   r�   rì   rÕ   rS   rw   r9  rÙ   r   r:  r}   )r;  rV  rZ  Ú
window_maxrx   Úcurrentra  s          rK   rA  z$ResetBudgetJob._window_carried_spend7  s­   è ø€ ô !Ô"ØØ"ŸJ™J |Ó4ˆ
Ü2<¸ZÌ#ÌuÈÔ2V”] :Ô.Ð\`ˆØˆ;Øð	Ø#6×#FÑ#FÈ;Ð#FÓ#W×WˆGô ˜'¤C¬ <Ô0ØÜœe G›n¨cÓ2Ð2ð XùÜò 	Ü ×(Ñ(Ð)[Ð]hÐjkÔlÜûð	üsB   ‚AB;ÁB ÁBÁB Á ,B;ÂB Â	B8ÂB3Â.B;Â3B8Â8B;c              ƒ   ó  K  — ddl m} t        j                  «       }t        D ]  }	 | j                  |||¬«      ƒ d{  –—†  Œ! y7 Œ# t        $ r+}t        j                  d|j                  |«       Y d}~ŒTd}~ww xY w­w)zµ
        For keys and teams with budget_limits, reset any individual windows where
        reset_at <= now. Only the expired windows are reset; other windows are untouched.
        r   rY  )Úsourcer³  rZ  Nz)Failed to reset budget windows for %s: %s)
r\  rZ  r
   r  r'  Ú_reset_windows_forrÙ   r   rÑ  r  )rJ   rZ  r³  rP  ra  s        rK   rI  z#ResetBudgetJob.reset_budget_windowsL  s}   è ø€ õ 	Cä—_‘_Ó&ˆÜ%ò 	sˆFðsØ×-Ñ-°VÀÐZmÐ-Ón×nÑnñ	sànùÜò sÜ$×.Ñ.Ð/ZÐ\b×\nÑ\nÐpq×rÑrûðsüs>   ‚$A?§A¾A¿AÁA?ÁAÁ	A<Á!A7Á2A?Á7A<Á<A?rP  c              ƒ   óZ   K  — d}	 | j                  ||||¬«      ƒ d{  –—† }|€y|}Œ#7 Œ
­w)a  Walk one table's windowed rows a page at a time, to the end.

        Paging is what bounds the memory: the previous form pulled every row
        carrying budget_limits into one result set on every tick, which grows
        with the deployment's key count and is paid on the event loop.

        The walk deliberately has no per-run page cap. A cap has to remember
        where it stopped, and that position cannot live in the process: the
        lease is released after each sweep, so the next tick can elect a
        different pod whose own position is unset. It would restart at the first
        row and never reach the tail, pinning those windows at their cap for
        good. The cursor strictly advances, so the walk terminates on its own
        without needing a bound.
        Ú )rP  Úcursorr³  rZ  N)Ú_reset_window_page)rJ   rP  r³  rZ  rT  Únext_cursors         rK   rQ  z!ResetBudgetJob._reset_windows_for[  sP   è ø€ ð( ˆØØ $× 7Ñ 7ØØØØ$7ð	 !8ó !÷ ˆKð Ð"ØØ ˆFð ðús   ‚+ž)Ÿ+rT  c              ƒ   ó‚  ‡ ‡‡‡‡K  — ‰ j                  ˆˆ ˆfd„d‰j                  › d�¬«      ƒ d{  –—† }|D ]Ø  }|d   }|sŒ|‰j                     Št        |t        «      r|nt        j                  |«      Šd}‰D ]_  }	‰j                  › d‰› d	|	d
   › �}
t        j                  |	|
||‰ j                  ‰ j                  ‰j                  ‰¬«      ƒ d{  –—† sŒ^d}Œa |sŒª‰ j                  ˆˆ ˆˆfd„d‰j                  › d�¬«      ƒ d{  –—†  ŒÚ t        |«      t        k  ry|d   ‰j                     S 7 �Œ7 Œe7 Œ0­w)zHReset one page of windows; return the next cursor, or None when drained.c                  óv   •— ‰j                   j                  j                  ‰j                  «       ‰ t        «      S rG   )r  r¤  Ú	query_rawr"  r   )rT  rJ   rP  s   €€€rK   rÎ   z3ResetBudgetJob._reset_window_page.<locals>.<lambda>„  s,   ø€ �D×&Ñ&×)Ñ)×3Ñ3°F×4EÑ4EÓ4GÈÔQlÓm€ rL   ro  Ú_windows_failurerP  Nr  Fr„   z:window:r?   )r  r  r<  Tc                  ód   •— ‰j                  ‰j                  ‰ t        j                  ‰«      «      S rG   )r   r  rÿ   r   )r  rJ   rP  Úwindowss   €€€€rK   rÎ   z3ResetBudgetJob._reset_window_page.<locals>.<lambda>�  s$   ø€ ˜FŸL™L¨×);Ñ);¸VÄTÇZÁZÐPWÓEXÓY€ rL   Úreset_budget_write_éÿÿÿÿ)rR  r  r  rì   r©   rÿ   Úloadsr  r.  rF  r0  r  r  rU  r+  r   )rJ   rP  rT  r³  rZ  rØ  r~   ÚrawÚchangedr;  rV  r  r\  s   ```        @@rK   rU  z!ResetBudgetJob._reset_window_page{  s€  üè ø€ ð !×/Ñ/ÝmØ'¨×(<Ñ(<Ð'=Ð=MÐNð 0ó 
÷ 
ˆð ò 	ˆCØ�oÑ&ˆCÙØØ˜f×.Ñ.Ñ/ˆFÜ6@ÀÄdÔ6K©sÔQU×Q[ÑQ[Ð\_ÓQ`ˆGØˆGØ!ò #�Ø!'×!6Ñ!6Ð 7°q¸¸ÀÈÐPaÑIbÐHcÐd�Ü'×=Ñ=ØØØ'ØØ×'Ñ'Ø"&×"4Ñ"4Ø &× 2Ñ 2Ø$ð >ó 	÷ 	ñ 	ð #‘Gð#ò Ø×/Ñ/ÞYØ0°×1EÑ1EÐ0FÐFVÐWð 0ó ÷ ñ ð+	ô4 ˆt‹9Ô2Ò2ØØ�B‰x˜×(Ñ(Ñ)Ð)ðA
ùð	øðús@   ‡*D?±D8²B#D?ÃD;ÃD?ÃD?Ã"*D?ÄD=Ä,D?Ä;D?Ä=D?Úitemr  Ú	item_type)r$  r&  r  c              ƒ   óB  K  — 	 t        «       r)t        | j                  t        | j                  «      «      nd| _        t        | d«      r(| j                  �t        | j                  |¬«      | _        | S # t        $ r}t        j                  d||| «       |‚d}~ww xY w­w)aÜ  
        In-place, updates spend=0, and sets budget_reset_at to current_time + budget_duration

        Common logic for resetting budget for a team, user, or key.

        Spend-counter invalidation happens in the caller, AFTER the DB write
        commits. Zeroing the counter here would open a bypass window when the
        DB write fails: get_current_spend reads 0 from Redis while the DB
        still holds the pre-reset value, admitting requests past the cap.
        r{   r?   Nr†  z+Error resetting budget for %s: %s. Item: %s)rr   r}   r@   rw   rs   Úhasattrr?   r&   r£  rÙ   r   rÑ  )rb  r  rc  r0  ra  s        rK   Ú_reset_budget_commonz#ResetBudgetJob._reset_budget_common¥  s�   è ø€ ð"		ÜWhÔWjœ¨¯
©
´MÀ$Ç/Á/Ó4RÔSÐpsˆDŒJÜ�tÐ.Ô/°D×4HÑ4HÐ4TÜ'>Ø$(×$8Ñ$8À>ô(�Ô$ð ˆKøÜò 	Ü ×*Ñ*Ð+XÐZcÐefÐhlÔmØˆGûð	üs)   ‚B„A/A4 Á3BÁ4	BÁ=BÂBÂBr&  c              ƒ   óT   K  — t         j                  | |d|¬«      ƒ d {  –—†  | S 7 Œ­w)Nr&  ©rb  r  rc  r0  ©r.  rf  r1  s      rK   r7  z%ResetBudgetJob._reset_budget_for_teamÁ  ó=   è ø€ ô ×1Ñ1ØØ%ØØ)ð	 2ó 
÷ 	
ð 	
ð ˆð	
úó   ‚(Ÿ& (r  c              ƒ   óT   K  — t         j                  | |d|¬«      ƒ d {  –—†  | S 7 Œ­w)Nr  rh  ri  r!  s      rK   r(  z%ResetBudgetJob._reset_budget_for_userÏ  rj  rk  r$  c              ƒ   óT   K  — t         j                  | |d|¬«      ƒ d {  –—†  | S 7 Œ­w)Nr$  rh  ri  r  s      rK   r  z$ResetBudgetJob._reset_budget_for_keyÝ  s=   è ø€ ô ×1Ñ1ØØ%ØØ)ð	 2ó 
÷ 	
ð 	
ð ˆ
ð	
úrk  )NN)r{   )rE   N)QrO   rP   rQ   rÐ   r0   r/   r%   r-   r3  r8  r=  r  rC  rL  r   r   r=   rT   rR  rU  ÚstaticmethodrS   rb  re  rd  r2   r   r  r½   rr  r   rm   r~  r   r­   rœ  r¡  rŸ  r«  rÓ   r×   r¹  rH  rÜ   r»  r©   r    r|  r$   rà  rÜ  r#   rí  ré  r"   rú  r÷  rÙ   Údictrþ  rE  r   rF  r  rG  r-  r   r
   r!   rF  rC  rA  rI  r  rQ  rU  r   rf  r7  r(  r  rH   rL   rK   r.  r.  ¡  s¶  „ ñð 6:Ø26ñ
Hà'ð
Hð $ð
Hð ,¨dÑ2ð	
Hð
 )¨4Ñ/ó
Hð°ð ÀDó ð   fó  òB[ð:`¨h°r¸9ÀUÑ;KÐ7KÑ.Lð `ÐY\ð `Ðafó `ð

°H¸RÀÈ5ÑAQÐ=QÑ4Rð 

Ð_bð 

Ðgló 

ð ña°Sð aÀUð aÐUYò aó ðað4 ò`ó ð`ð ð¸cð Àdò ó ðð,à Ñ&ðð �s˜F�{Ñ#ðð ð	ð
 
ˆu�cˆzÑ	óð&P¸8ÀC¹=ð PÈUÐS^Ð`cÐScÑMdó PðQ
¸hÐG^Ñ>_ð Q
Ðdró Q
ðf
°Nð 
Àtó 
ð 	g¸ð 	gÈDó 	gðG¸~ð GÐRVó Gð
Ð5LÐOcÑ5có 
ó<	Vð+&ÀMó +&ðZWà	Ð"Ñ	#óWð*
¸4Ð@YÑ;Zð 
Ð_có 
ð 	ÀÐE^Ñ@_ð 	Ðdhó 	ð
¸TÐBSÑ=Tð 
ÐY]ó 
ðÀ$ÐGXÑBYð Ð^bó ð
¸TÐBSÑ=Tð 
ÐY]ó 
ðÀ$ÐGXÑBYð Ð^bó ð
àð
ð ð
ð ð	
ð
 ð
ð ˜S &˜[Ñ)ð
ð 
ó
ó2Nð_¸Mó _óBOðe¸]ó eóNOðc¸]ó cðJ ð"Øð"àð"ð 'ð"ð ð	"ð
 ,ð"ð $ð"ð (ð"ð ð"ð 
ò"ó ð"ðH ð#Ø#ð#à'ð#ð ð#ð ð	#ð
  ð#ð 
ò#ó ð#ðJ ð3Ø˜˜V˜Ñ$ð3Ø36ð3ØMVð3à	ò3ó ð3ó(sð!àð!ð ð!ð 'ð	!ð
 
ó!ð@(*àð(*ð ð(*ð ð	(*ð
 'ð(*ð 
ˆt‰ó(*ðT ðØÐ"3Ñ3Ð6OÑOðàðð Ð0Ñ1ðð ,ò	ó ðð6 ðØðàðð ,ðð 
˜TÑ	!ò	ó ðð ðØðàðð ,ðð 
˜TÑ	!ò	ó ðð ðØ&ðàðð ,ðð 
# TÑ	)ò	ó ñrL   r.  )�rÌ  rÿ   ru   rË  Úcollections.abcr   r   r   r   r   Údataclassesr   r	   r
   r   r   Úenumr   Útypesr   Útypingr   r   r   r   r   rp   Úlitellm._loggingr   Úlitellm.caching.dual_cacher   Úlitellm.constantsr   r   r   r   r   r   Ú*litellm.litellm_core_utils.duration_parserr   Úlitellm.proxy._typesr   r   r    r!   r"   r#   r$   Ú)litellm.proxy.common_utils.timezone_utilsr%   r&   r'   Ú-litellm.proxy.common_utils.user_api_key_cacher(   r)   r*   r+   Ú+litellm.proxy.db.budget_window_spend_writerr,   Ú6litellm.proxy.db.db_transaction_queue.pod_lock_managerr-   Ú"litellm.proxy.db.exception_handlerr.   Úlitellm.proxy.utilsr/   r0   Ú,litellm.repositories.organization_repositoryr1   Ú%litellm.repositories.prisma_protocolsr2   Ú'litellm.repositories.table_repositoriesr3   r4   r5   r6   Ú$litellm.repositories.team_repositoryr7   Ú!litellm.repositories.unit_of_workr8   r9   r:   Ú2litellm.repositories.verification_token_repositoryr;   Úlitellm.types.servicesr<   r=   rA   rT   r  rÑ   rB   rD   rV   r]   ra   re   ri   rm   r8  rr   rS   rw   r}   r‚   r†   r½   r‰   r�   r�   r’   r”   r–   r˜   rš   rœ   rž   r    r¤   ro  rª   r¿   rÄ   r­   rÓ   r×   rÚ   rÜ   rß   ræ   rÕ   rð   ró   r÷   rù   r  r  r  r  ÚKEYÚTEAMr'  r,  r.  rH   rL   rK   ú<module>r‰     sï  ðÜ Û Û Û ß LÕ Lß (ß 2Ñ 2Ý Ý "ß BÕ Bã Ý 1Ý 0÷÷ õ K÷÷ ñ ÷ñ ÷
ó õ NÝ QÝ Kß :Ý OÝ B÷ó õ @÷ñ õ
õ 0á�Ó€á2BÐW[ÐgkÐmnÐfoÑCpÓ2qÐ �E˜' # v +Ñ.Ñ/Ó qÙ1AÀ7ÈTÐSTÈIÐBVÓ1WÐ �5˜  f Ñ-Ñ.Ó Wô+�xô +ô"Ð)¨8ô "ô Ð ô  ô
*Ð ô *ô
#Ð ô #ô
,Ð+¨Xô ,ô
"Ð" Hô "ð
+˜4ó +ð˜e d™lð ¨u°t©|ó ð*˜% $™,ð *¨U°T©\ð *¸eó *ðeÐ,ð e°G¸CÀ¸JÑ4Gð eÈEó eð<Ð&8ð <¸Só <ð-Ð%7ð -¸EÀ#ÀsÀ(¹Oó -ð$˜'ð $ có $ð˜ð  U¨3°¨8¡_ó ð.˜'ð . có .ð˜ð  U¨3°¨8¡_ó ð'˜'ð ' có 'ð*˜ð * U¨3°¨8¡_ó *ðGÐ)=ð GÀ#ó GðBÐ(<ð BÀÀsÈCÀxÁó Bð+˜kð +¨có +ð.˜[ð .¨U°3¸°8©_ó .ðq ð q°7¸3À¸:Ñ3Fð qÈ5ó qñ #3°2Ó"6ñ<Ø˜‘ð<à�3˜�;Ñð<ð 
ˆ#ˆvˆ+Ñó<ñ #3°2Ó"6ñLØ"ðLàðLð �3˜�;ÑðLð 
ó	Lð.Ð"8ð ÐCSð ÐX\ó ñ8 �$˜dÔ#÷	]ð 	]ó $ð	]ñ �$˜dÔ#÷ð ó $ðñ
 �$˜dÔ#÷ð ó $ðñ
 'Ó(€�Ó (ñ �$˜dÔ#÷ð ó $ðñ $¨A¸Ô:€ˆeÓ :ðX�Hð X ó Xðq˜x¨Ñ/ð q¸ð qÀcó qðR˜}ð R°ó Rð¨h°r¸9À]Ñ;SÐ7SÑ.Tð ÐY]ó ñ �$˜dÔ#÷=ð =ó $ð=ôˆTô ð¨Lð À#ð ÐPSð ÐX\ó ð¨\ð À3ð ÐQTð ÐY]ó ñ �$˜dÔ#÷
ð 
ó $ð
ñ6 Ø)ØØ&×*Ò*Ø"ØØØ ôñ Ø!ØØ&×+Ò+Ø#ØØØ!ôð5€��u˜]¨CÐ/Ñ0Ñ1ó ð,¨Nð ¸tÀCÈÀKÑ?Pó ÷Hò HrL   