Ë
    tPêj$  ã                   ó~  — d Z ddlmZ ddlmZ ddlmZmZmZ ddlm	Z	m
Z
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 dd
lmZ e	rddlmZ dZ G d„ de«      Z G d„ ded¬«      Z G d„ de«      Z G d„ de
«      Z dede fd„Z! edd¬«       G d„ d«      «       Z" G d„ de«      Z# G d „ d!e«      Z$defd"„Z%d#e&de'd$z  fd%„Z(d&ed$z  ded$z  fd'„Z)d(d)de"fd*„Z*d+e"ded$z  fd,„Z+d+e"d$z  de#fd-„Z,d+e"d.e'd/ed0ed1e-de.fd2„Z/ded3e-de"d$z  fd4„Z0ded3e-d5e'dd$fd6„Z1ded3e-dd$fd7„Z2ded3e-d8edd$fd9„Z3ded3e-d8ede'fd:„Z4y$);a  
Persistence for the admin-configured periodic model cost map reload schedule stored in
``LiteLLM_Config``.

Field ownership is split by writer so concurrent writers never overwrite each other:
the schedule endpoints own the ``param_value`` JSON (``interval_hours``), while the
reload job and the manual reload endpoints own the dedicated ``last_run_at`` /
``reload_revision`` columns. ``last_run_at`` lives in the row rather than process memory
so the Admin UI still reports the last execution after a restart and across pods.
``reload_revision`` is a monotonic counter a manual reload increments; each pod records
the revision it last applied and reloads whenever the row's differs, so a request reaches
every pod exactly once without any pod clearing it and without comparing clocks. A booting
pod starts at revision 0 rather than adopting the published one, because it cannot know
whether that request predates the prices it fetched at import. Interval reloads stay
per-pod, driven by when that pod's own copy of the data was loaded.
é    )ÚMapping)Ú	dataclass)ÚdatetimeÚ	timedeltaÚtimezone)ÚTYPE_CHECKINGÚProtocolÚ	TypedDictÚcast)Ú	BaseModelÚ
ConfigDictÚValidationError)Úverbose_proxy_logger)Ú
safe_dumps)ÚPrismaClientÚevict_config_param)ÚConfigRepository)ÚLiteLLM_ConfigÚmodel_cost_map_reload_configc                   ó   — e Zd ZU eed<   y)Ú_RevisionIncrementÚ	incrementN)Ú__name__Ú
__module__Ú__qualname__ÚintÚ__annotations__© ó    úx/home/oem/CyberBrain26-unified/.venv/lib/python3.12/site-packages/litellm/proxy/common_utils/periodic_reload_schedule.pyr   r   )   s   … Ø„Nr   r   c                   ó<   — e Zd ZU eed<   eed<   eed<   eez  ed<   y)Ú_ConfigRowWriteÚ
param_nameÚparam_valueÚlast_run_atÚreload_revisionN)r   r   r   Ústrr   r   r   r   r   r   r    r"   r"   -   s   … ØƒOØÓØÓØÐ-Ñ-Ô-r   r"   F)Útotalc                   ó"   — e Zd ZU eed<   eed<   y)Ú_ConfigUpsertDataÚcreateÚupdateN)r   r   r   r"   r   r   r   r    r*   r*   4   s   … ØÓØÔr   r*   c                   ób   — e Zd Zdeeef   ddfd„Zdeeef   deddfd„Zdedeeef   de	fd„Z
y	)
Ú_ConfigTableÚwhereÚreturnzLiteLLM_Config | Nonec              ƒ   ó   K  — y ­w©Nr   )Úselfr/   s     r    Úfind_uniquez_ConfigTable.find_unique:   ó   è ø� ùó   ‚Údatar   c              ƒ   ó   K  — y ­wr2   r   )r3   r/   r7   s      r    Úupsertz_ConfigTable.upsert<   r5   r6   c              ƒ   ó   K  — y ­wr2   r   )r3   r7   r/   s      r    Úupdate_manyz_ConfigTable.update_many>   r5   r6   N)r   r   r   r   r'   r4   r*   r9   r"   r   r;   r   r   r    r.   r.   9   sR   „ ØY w¨s°C¨xÑ'8ÐYÐ=TÓYàf '¨#¨s¨(Ñ"3ÐfÐ;LÐfÐQaÓfà\ oÐ\¸gÀcÈ3ÀhÑ>OÐ\ÐTWÔ\r   r.   Úprisma_clientr0   c                 óH   — t        t        t        | «      j                  «      S r2   )r   r.   r   Útable)r<   s    r    Ú_config_tabler?   A   s   € Ü”Ô.¨}Ó=×CÑCÓDÐDr   T)ÚfrozenÚslotsc                   óD   — e Zd ZU dZedz  ed<   dZeed<   dZedz  ed<   y)ÚReloadScheduleNÚinterval_hoursr   r&   r%   )	r   r   r   rD   r   r   r&   r%   r   r   r   r    rC   rC   E   s(   … à!%€N�C˜$‘JÓ%Ø€O�SÓØ#'€K�˜D‘Ô'r   rC   c                   óH   — e Zd ZU eed<   edz  ed<   edz  ed<   edz  ed<   y)ÚReloadScheduleStatusÚ	scheduledNrD   Úlast_runÚnext_run)r   r   r   Úboolr   r   r'   r   r   r    rF   rF   L   s%   … ØƒOØ˜$‘JÓØ�D‰jÓØ�D‰jÔr   rF   c                   ó4   — e Zd ZU  ed¬«      ZdZedz  ed<   y)Ú_IntervalConfigT)ÚstrictNrD   )r   r   r   r   Úmodel_configrD   r   r   r   r   r    rL   rL   S   s   … Ù TÔ*€Là!%€N�C˜$‘JÔ%r   rL   c                  óH   — t        j                  t        j                  «      S r2   )r   Únowr   Úutcr   r   r    Úutc_nowrR   Y   s   € Ü�<‰<œŸ™Ó%Ð%r   r$   Nc                 ó¾   — 	 t        | t        «      rt        j                  | «      j                  S t        j                  | «      j                  S # t        $ r Y yw xY w)a  ``param_value`` is written as serialized JSON, and a raw row read can hand it back
    either decoded or still as a string depending on the driver, so accept both rather than
    reading a string as no schedule at all. Mirrors ``ConfigRepository.get_param``N)Ú
isinstancer'   rL   Úmodel_validate_jsonrD   Úmodel_validater   )r$   s    r    Ú_parse_interval_hoursrW   ]   sQ   € ðÜ�k¤3Ô'Ü"×6Ñ6°{ÓC×RÑRÐRÜ×-Ñ-¨kÓ:×IÑIÐIøÜò Ùðús   ‚.A ±A Á	AÁAÚvaluec                 ód   — | €y | j                   �| S | j                  t        j                  ¬«      S )N)Útzinfo)rZ   Úreplacer   rQ   )rX   s    r    Ú_as_utcr\   i   s-   € Ø€}ØØ—L‘LÐ,ˆ5ÐT°%·-±-ÄxÇ|Á|°-Ó2TÐTr   Úrowr   c                 ó˜   — t        t        | j                  «      t        | j                  xs d«      t        | j                  «      ¬«      S )Nr   )rD   r&   r%   )rC   rW   r$   r   r&   r\   r%   )r]   s    r    Úparse_reload_scheduler_   o   s:   € ÜÜ,¨S¯_©_Ó=Ü˜C×/Ñ/Ò4°1Ó5Ü˜CŸO™OÓ,ôð r   Úschedulec                 óz   — | j                   �| j                  €y | j                  t        | j                   ¬«      z   S )N)Úhours)rD   r%   r   )r`   s    r    Únext_run_atrc   w   s8   € Ø×ÑÐ&¨(×*>Ñ*>Ð*FØØ×Ñ¤)°(×2IÑ2IÔ"JÑJÐJr   c                 óØ   — | €dd d d dœS t        | «      }| j                  d u| j                  | j                  �| j                  j                  «       nd |�|j                  «       dœS d dœS )NF)rG   rD   rH   rI   )rc   rD   r%   Ú	isoformat)r`   rI   s     r    Úreload_schedule_statusrf   }   s…   € ØÐØ"°dÈÐZ^Ñ_Ð_Ü˜8Ó$€Hà×,Ñ,°DÐ8Ø"×1Ñ1Ø8@×8LÑ8LÐ8X�H×(Ñ(×2Ñ2Ô4Ð^bØ,4Ð,@�H×&Ñ&Ó(ñ	ð ð GKñ	ð r   Úpod_applied_revisionÚpod_data_loaded_atÚcurrent_timeÚdescriptionc                 ó@  — | j                   |k7  rt        j                  d|«       y| j                  €y| j                  €t        j                  d|«       y||z
  j                  «       dz  }|| j                  k  ryt        j                  d||| j                  «       y)aé  
    Whether this pod should reload now. A revision it has not applied means a manual reload
    it has not served. A pod starts at revision 0, so it serves any request published before
    it booted; that costs one redundant fetch per boot and is what keeps a request from being
    marked applied against data fetched before it. Interval reloads compare against this pod's
    own data, and a schedule that has never run anywhere fires immediately rather than one
    interval later
    z,%s reload triggered by manual reload requestTFz,%s reload triggered - schedule has never runi  zL%s reload triggered by interval. Hours since data loaded: %.2f, Interval: %s)r&   r   ÚinforD   r%   Útotal_seconds)r`   rg   rh   ri   rj   Úhours_since_data_loadeds         r    Úpod_reload_is_duero   ‰   s©   € ð  ×ÑÐ#7Ò7Ü×!Ñ!Ð"PÐR]Ô^ØØ×ÑÐ&ØØ×ÑÐ#Ü×!Ñ!Ð"PÐR]Ô^ØØ+Ð.@Ñ@×OÑOÓQÐTXÑXÐØ ×!8Ñ!8Ò8ØÜ×ÑØVØØØ×Ñô	ð r   r#   c              ƒ   ót   K  — t        | «      j                  d|i¬«      ƒ d {  –—† }|€y t        |«      S 7 Œ­w)Nr#   )r/   )r?   r4   r_   )r<   r#   r]   s      r    Úread_reload_schedulerq   ­   s?   è ø€ Ü˜mÓ,×8Ñ8ÀÈjÐ?YÐ8ÓZ×
Z€CØ
€{ØÜ  Ó%Ð%ð [ús   ‚!8£6¤8rD   c              ƒ   ó°   K  — t        d|i«      }t        | «      j                  d|i||dœd|idœ¬«      ƒ d{  –—†  t        |«      ƒ d{  –—†  y7 Œ7 Œ­w)zRAdmin-owned write: replaces ``param_value`` without touching the job-owned columnsrD   r#   )r#   r$   r$   ©r+   r,   ©r/   r7   N)r   r?   r9   r   )r<   r#   rD   r$   s       r    Úwrite_reload_intervalru   ´   sp   è ø€ äÐ.°Ð?Ó@€KÜ
˜Ó
&×
-Ñ
-Ø˜ZÐ(à%/ÀÑLØ$ kÐ2ñ
ð .ó ÷ ð ô ˜ZÓ
(×(Ñ(ðøð )ús!   ‚7A¹AºAÁAÁAÁAc              ƒ   ó    K  — t        | «      j                  dt        ddi«      id|i¬«      ƒ d{  –—†  t        |«      ƒ d{  –—†  y7 Œ7 Œ­w)a³  Admin-owned write: drops the schedule but keeps the row, because the revision counter
    identifies a request rather than ordering one and so can never reuse a number. Deleting
    the row restarts it, and a reissued revision matches what pods already applied, so their
    next manual reload is silently skipped. The interval is nulled inside the JSON rather
    than by nulling the column, which prisma rejects for a ``Json?`` fieldr$   rD   Nr#   ©r7   r/   )r?   r;   r   r   )r<   r#   s     r    Úclear_reload_intervalrx   Á   s`   è ø€ ô ˜Ó
&×
2Ñ
2ØœZÐ)9¸4Ð(@ÓAÐBØ˜ZÐ(ð 3ó ÷ ð ô ˜ZÓ
(×(Ñ(ð	øð )ús!   ‚/A±A
²AÁAÁAÁAÚran_atc              ƒ   óŠ   K  — t        | «      j                  d|id|i¬«      ƒ d{  –—†  t        |«      ƒ d{  –—†  y7 Œ7 Œ­w)z—Job-owned write after this pod reloaded: stamps the shared last run only if the row
    still exists, so a schedule deleted mid-poll is not resurrectedr%   r#   rw   N)r?   r;   r   )r<   r#   ry   s      r    Úrecord_reload_runr{   Î   sU   è ø€ ô ˜Ó
&×
2Ñ
2Ø˜VÐ$Ø˜ZÐ(ð 3ó ÷ ð ô ˜ZÓ
(×(Ñ(ð	øð )ús   ‚$A¦?§A¹AºAÁAc              ƒ   óÆ   K  — t        | «      j                  d|i||ddœ|ddidœdœ¬«      ƒ d{  –—† }t        |«      ƒ d{  –—†  t        |j                  «      S 7 Œ,7 Œ­w)	af  
    After a manual in-pod reload: stamp the shared last run and bump the revision every other
    pod compares against. The increment is atomic, so concurrent requests each publish a
    distinct revision instead of overwriting one another. Returns the published revision so
    the serving pod can adopt it rather than reloading again on its next poll
    r#   é   )r#   r%   r&   r   )r%   r&   rs   rt   N)r?   r9   r   r   r&   )r<   r#   ry   r]   s       r    Úrecord_manual_reloadr~   Ø   sx   è ø€ ô ˜mÓ,×3Ñ3Ø˜ZÐ(à%/ÀÐ[\Ñ]Ø&,À+ÈqÐAQÑRñ
ð 4ó ÷ €Cô ˜ZÓ
(×(Ð(Üˆs×"Ñ"Ó#Ð#ðøð )ús!   ‚.A!°A±A!ÁAÁA!ÁA!)5Ú__doc__Úcollections.abcr   Údataclassesr   r   r   r   Útypingr   r	   r
   r   Úpydanticr   r   r   Úlitellm._loggingr   Ú*litellm.litellm_core_utils.safe_json_dumpsr   Úlitellm.proxy.utilsr   r   Ú&litellm.repositories.config_repositoryr   Úprisma.modelsr   Ú MODEL_COST_MAP_RELOAD_PARAM_NAMEr   r"   r*   r.   r?   rC   rF   rL   rR   Úobjectr   rW   r\   r_   rc   rf   r'   rJ   ro   rq   ru   rx   r{   r~   r   r   r    ú<module>r‹      s1  ðñõ" $Ý !ß 2Ñ 2÷ó ÷ <Ñ ;å 1Ý Aß @Ý CáÝ,à#AÐ  ô˜ô ô.�i uõ .ô˜	ô ô
]�8ô ]ðE ð E°,ó Eñ �$˜dÔ#÷(ð (ó $ð(ô˜9ô ô&�iô &ð&�ó &ð	 vð 	°#¸±*ó 	ðU�8˜d‘?ð U x°$¡ó UðÐ/ð °Nó ðK˜.ð K¨X¸©_ó Kð	 ^°dÑ%:ð 	Ð?Só 	ð!àð!ð ð!ð !ð	!ð
 ð!ð ð!ð 
ó!ðH&¨lð &Èð &ÐP^ÐaeÑPeó &ð
)¨|ð 
)Èð 
)Ð^að 
)Ðfjó 
)ð
)¨|ð 
)Èð 
)ÐQUó 
)ð)¨<ð )ÀSð )ÐRZð )Ð_có )ð$¨lð $Èð $ÐU]ð $Ðbeô $r   