+
    iHàj¨#  ã                   ó:  € R t ^ RIt^ RIt^ RIt^ RIt^ RIHtHtHt ^ RIH	t	 ^ RI
HtHt ^ s]P                  ! 4       tR*t^tR R lt]P&                  ! R	]P(                  4      t]P&                  ! R
]P(                  4      t]P&                  ! R]P(                  4      t]P&                  ! R]P(                  4      tR R ltR R lt]]3]R 3]R 3]]33tR R ltR R ltRRRRRR/R R lltR R ltR  R! lt R"]/R# R$ llt!]3R% R& llt"Rt#R't$R( R) lt%R# )+uÑ   Retry utilities â€” jittered backoff for decorrelated retries.

Jittered delays (vs. fixed exponential) prevent thundering-herd retry spikes
when many sessions hit the same rate-limited provider concurrently.
N)ÚdatetimeÚtimezoneÚUTC)Úparsedate_to_datetime)ÚAnyÚOptionalç      N@ç      ^@c                óF   € V ^8„  d   QhR\         R\        \        ,          /# )é   Úvalue_or_headersÚreturn©r   r   Úfloat)Úformats   "Ú6/home/ubuntu/.hermes/hermes-agent/agent/retry_utils.pyÚ__annotate__r      s"   € ÷ "@ñ "@´ð "@¼Ä½ñ "@ó    c                ó(  € T pVeW   \        V\        \        \        34      '       g6   \	        VRR4      p\        V4      '       g   R#  V! R4      pVf	   V! R4      pVe   \        V\        4      '       d   R# \        V\        \        34      '       d   \        R\        V4      4      # \        V4      P                  4       pV'       g   R#  \        R\        V4      4      #   \         d     R# i ; i  \        \        3 d     Mi ; i \        T4      pM  \        \        3 d     R# i ; iTf   R# TP                  f   TP                  \        R7      p\        RT\         P"                  ! \        4      ,
          P%                  4       4      # )z›Parse a ``Retry-After`` value (numeric / HTTP-date) or a headers mapping (both casings tried) into
seconds, clamped at 0.0; None when absent / unparseable.NÚgetzRetry-Afterzretry-afterg        )Útzinfo)Ú
isinstanceÚstrÚintr   ÚgetattrÚcallableÚ	ExceptionÚboolÚmaxÚstripÚ	TypeErrorÚ
ValueErrorr   r   Úreplacer   r   ÚnowÚtotal_seconds)r   ÚrawÚgetterÚtextÚwhens   &    r   Úparse_retry_after_secondsr)      sW  € ð €CØ
‚œz¨#´´S¼%Ð/@×AÒAÜ˜˜e TÓ*ˆÜ˜×ÒÙð	Ù˜Ó'ˆCØŠ{Ù˜]Ó+�ð ‚{”j ¤d×+Ò+ÙÜ�#œœU�|×$Ò$Ü�3œ˜c›
Ó#Ð#Üˆs‹8�>‰>Ó€DßÙðÜ�3œ˜d›Ó$Ð$øô ô 	Úð	ûô ”zÐ"ô ÙðúðÜ$ TÓ*‰øÜ”zÐ"ô Úðúà‚|ÙØ‡{�{ÒØ�|‰|¤3ˆ|Ó'ˆÜˆs�TœHŸLšL¬Ó-Õ-×<Ñ<Ó>Ó?Ð?s6   Á	C# ÃC5 Ã#C2Ã1C2Ã5D	ÄD	ÄD ÄD.Ä-D.z,quotaResetDelay[:\s\"]+(\d+(?:\.\d+)?)(ms|s)z±resets?\s+in\s+(?:(\d+(?:\.\d+)?)\s*(?:h|hr|hrs|hour|hours)\b\s*)?(?:(\d+(?:\.\d+)?)\s*(?:m|min|mins|minute|minutes)\b\s*)?(?:(\d+(?:\.\d+)?)\s*(?:s|sec|secs|second|seconds)\b)?z?retry\s+(?:after\s+)?(\d+(?:\.\d+)?)\s*(?:sec|secs|seconds|s\b)z'resets_in_seconds\W{1,4}(\d+(?:\.\d+)?)c                óZ   € V ^8„  d   QhR\         P                  \        ,          R\        /# ©r   Úmr   )ÚreÚMatchr   r   )r   s   "r   r   r   R   s&   € ÷ Cñ CœBŸH™H¤S�Mð C¬eñ Cr   c                 ó”   € \        V P                  ^4      4      pV P                  ^4      P                  4       R8X  d
   VR,          # T# )é   Úmsg     @�@)r   ÚgroupÚlower)r,   Úvalues   & r   Ú_quota_reset_secondsr5   R   s;   € Ü�!—'‘'˜!“*Ó€EØŸW™W Q›Z×-Ñ-Ó/°4Ô7ˆ5�6�>ÐB¸UÐBr   c                óp   € V ^8„  d   QhR\         P                  \        ,          R\        \        ,          /# r+   )r-   r.   r   r   r   )r   s   "r   r   r   W   s*   € ÷ `ñ `œ"Ÿ(™(¤3�-ð `¬H´U­Oñ `r   c                 óL  € \        V P                  4       4      '       g   R # \        V P                  ^4      ;'       g    ^ 4      R,          \        V P                  ^4      ;'       g    ^ 4      ^<,          ,           \        V P                  ^4      ;'       g    ^ 4      ,           # )Né  )ÚanyÚgroupsr   r2   ©r,   s   &r   Ú_resets_in_secondsr<   W   si   € Üˆq�x‰x‹z�?Š?ÙÜ�—‘˜“—�˜qÓ! DÕ(¬5°·±¸³·°¸qÓ+AÀBÕ+FÕFÌÈqÏwÉwÐWXËzÏÈÐ]^ÓI_Õ_Ð_r   c                 ó6   € \        V P                  ^4      4      # ©r0   ©r   r2   r;   s   &r   Ú<lambda>r@   b   s   € ¬¨a¯g©g°a«jÔ(9r   c                 ó6   € \        V P                  ^4      4      # r>   r?   r;   s   &r   r@   r@   c   s   € ¬E°!·'±'¸!³*Ô,=r   c                ó0   € V ^8„  d   QhR\         R\        /# )r   Úsecondsr   )r   r   )r   s   "r   r   r   h   s   € ÷ Zñ Z¤ð Z¬3ñ Zr   c                ób   € \        V 4      p V R8¼  d   RV ) R,          )  R2# RV ) ^<,          )  R2# )zS``~9h`` / ``~45 min`` for chat copy naming when a quota window reopens (ceilinged).r8   Ú~Úhz min©r   )rC   s   &r   Úformat_reset_windowrH   h   sE   € ä�'‹l€GØ)0°D¬ˆQ�'�˜TÕ!Ð"Ð# 1Ð%ÐYÀÀWÀHÐPRÅNÐBSÐATÐTXÐ>YÐYr   c                óF   € V ^8„  d   QhR\         R\        \        ,          /# )r   Úmessager   )r   r   r   )r   s   "r   r   r   n   s   € ÷ ñ ¤cð ¬h´u­oñ r   c                óŽ   € V '       g   R# \          F0  w  rVP                  V 4      pV'       g   K   V! V4      ;pf   K.  Vu # 	  R# )zKSeconds-until-reset parsed from free-text provider error messages, or None.N)ÚRETRY_DELAY_PATTERNSÚsearch)rJ   ÚpatternÚ
to_secondsr,   rC   s   &    r   Úreset_delay_from_messagerP   n   s@   € çÙß3ÑˆØ�N‰N˜7Ó#ˆß‰1™Z¨›]Ð*�'Ô7ØŠNñ  4ñ r   Ú
base_delayg      @Ú	max_delayÚjitter_ratiog      à?c          
      óT   € V ^8„  d   QhR\         R\        R\        R\        R\        /# )r   ÚattemptrQ   rR   rS   r   )r   r   )r   s   "r   r   r   y   s8   € ÷ Hñ Hœcð H´%ð HÌ%ð HÔglð HÔw|ñ Hr   c               ó°  € \         ;_uu_ 4        \        ^,          s\        pRRR4       \        ^ V ^,
          4      pV^?8¼  g   V^ 8:  d   TM\        V^V,          ,          V4      p\        P
                  ! 4       XR,          ,          R,          pV\        P                  ! V4      P                  ^ W6,          4      ,           #   + '       g   i     Lª; i)zkmin(base * 2^(attempt-1), max_delay) + uniform jitter in
[0, jitter_ratio * delay]. ``attempt`` is 1-based.Nl   ¹yn< l   ÿÿ )	Ú_jitter_lockÚ_jitter_counterr   ÚminÚtimeÚtime_nsÚrandomÚRandomÚuniform)rU   rQ   rR   rS   ÚtickÚexponentÚdelayÚseeds   &$$$    r   Újittered_backoffrc   y   sž   € ÷ 
ŽÜ˜1ÕˆÜˆ÷ 
ô �1�g •kÓ"€HØ" bœ.¨J¸!¬O‰IÄ#ÀjÐTUÐYaÕTaÕFbÐdmÓBn€Eô �LŠL‹N˜d ZÕ/Õ0°JÕ>€DØ”6—=’= Ó&×.Ñ.¨q°,Õ2FÓGÕGÐG÷ 
�ús   �CÃC	c                ó0   € V ^8„  d   QhR\         R\        /# ©r   Úerrorr   )r   r   )r   s   "r   r   r   ‰   s   € ÷ Mñ M”sð Mœsñ Mr   c                óœ   € V \        V RR4      \        V RR4      \        V RR4      .pRP                  R V 4       4      P                  4       # )zCBest-effort flattened provider error text for retry classification.rJ   NÚbodyÚresponseÚ c              3   óB   "  € T F  qf   K  \        V4      x € K  	  R # 5i)N)r   )Ú.0Úparts   & r   Ú	<genexpr>Ú_error_text.<locals>.<genexpr>Œ   s   é € ÐD©% $”I”C˜—I�I«%ùs   ‚Œ)r   Újoinr3   )rf   Úpartss   & r   Ú_error_textrr   ‰   sM   € à”G˜E 9¨dÓ3´W¸UÀFÈDÓ5QÔSZÐ[`ÐblÐnrÓSsÐt€EØ�8‰8ÑD©%ÓDÓD×JÑJÓLÐLr   c                ód   € V ^8„  d   QhR\         R,          R\         R,          R\        R\        /# )r   Úbase_urlNÚmodelrf   r   )r   r   r   )r   s   "r   r   r   �   s2   € ÷ 	ñ 	¬c°D­jð 	ÄÀtÅð 	ÔTWð 	Ô\`ñ 	r   c                ó   € \        V4      p\        VRR4      R8H  ;'       d]    RT ;'       g    RP                  4       9   ;'       d8    RT;'       g    RP                  4       9   ;'       d    RV9   ;'       g    RV9   # )	zŽTrue only for the narrow Z.AI Coding Plan overload shape (429 + code
1305 / "temporarily overloaded"), so ordinary quota 429s still fail fast.Ústatus_codeNi­  zapi.z.ai/api/coding/paas/v4Ú zglm-5.2Ú1305ztemporarily overloaded)rr   r   r3   )rt   ru   rf   r'   s   $$$ r   Úis_zai_coding_overload_errorrz   �   s�   € ô �uÓ€Dä��} dÓ+¨sÑ2÷ 	Að 	AØ)¨h¯n¨n¸"×-CÑ-CÓ-EÑE÷	Að 	Aà˜%Ÿ+˜+ 2×,Ñ,Ó.Ñ.÷	Að 	Að �t‰^×?Ð?Ð7¸4Ñ?ð	r   Úshort_attemptsc                ó¸   € V ^8„  d   QhR\         R\        R,          R\        R,          R\        R\        R\         R\        \        \        R,          3,          /# )	r   rU   rt   Nru   rf   Údefault_waitr{   r   )r   r   r   r   Útuple)r   s   "r   r   r   ›   se   € ÷ zñ zÜðzÜ" T�zðzÜ25¸µ*ðzÜEHðzÜX]ðzäðzô Œ5”#˜•*ÐÕñzr   c               óØ   € \        WVR7      '       g   VR3# W8:  d   VR3# \        W,
          ^,
          \        \        4      ^,
          4      p\        V,          p\	        ^WwRR7      R3# )uÏ   ``(wait_seconds, reason_label)``: ``default_wait`` for most providers; Z.AI Coding GLM-5.2 overloads keep
``short_attempts`` short retries, then 30â†’60â†’90â†’120s with light jitter. ``attempt`` is 1-based.)rt   ru   rf   NÚzai_coding_overload_shortgš™™™™™É?)rQ   rR   rS   Úzai_coding_overload_long)rz   rY   ÚlenÚ!_ZAI_CODING_OVERLOAD_LONG_BACKOFFrc   )rU   rt   ru   rf   r}   r{   ÚidxrQ   s   &$$$$$  r   Úadaptive_rate_limit_backoffr…   ›   sn   € ô (°Èe×TÓTØ˜TÐ!Ð!ØÔ ØÐ8Ð8Ð8Ü
ˆgÕ&¨Õ*¬CÔ0QÓ,RÐUVÕ,VÓ
W€CÜ2°3Õ7€JÜ˜A¨*ÐY\Ô]Ð_yÐyÐyr   c                ó0   € V ^8„  d   QhR\         R\         /# )r   r{   r   rG   )r   s   "r   r   r   ª   s   € ÷ Gñ G´cð GÔdgñ Gr   c                ó<   € V \        \        4      ,           ^,           # )zøRetry-loop ceiling for the full Z.AI overload schedule: one past the last long entry,
because the loop gives up when ``retry_count >= ceiling`` BEFORE computing the attempt's
backoff (the default ``api_max_retries`` of 3 equals ``short_attempts``).)r‚   rƒ   )r{   s   &r   Ú!zai_coding_overload_retry_ceilingrˆ   ª   s   € ð œCÔ AÓBÕBÀQÕFÐFr   g     À‚@c                óF   € V ^8„  d   QhR\         R\        \        ,          /# re   r   )r   s   "r   r   r   ¹   s   € ÷ 
>ñ 
>¬ð 
>´¼µñ 
>r   c           	     ó6  € \        \        \        V RR4      RR4      4      pVfg   \        V RR4      p\        V\        4      '       dD   VP	                  R4      p\        \        V\        4      '       d   TMTP	                  R4      4      pVe
   V^ 8”  d   V# R# )a  Provider-declared cooldown: the ``Retry-After`` header, else a ``retry_after`` body field
(top level or nested under ``error``). None when absent, unparseable or zero: a zero or expired
cooldown carries no usable wait, and treating it as one would hot-loop the provider.ri   NÚheadersrh   rf   Úretry_after)r)   r   r   Údictr   )rf   r4   rh   Únesteds   &   r   Úprovider_retry_after_secondsr�   ¹   s‹   € ô &¤g¬g°e¸ZÈÓ.NÐPYÐ[_Ó&`Óa€EØ‚}Ü�u˜f dÓ+ˆÜ�dœD×!Ò!Ø—X‘X˜gÓ&ˆFÜ-¼ÀFÌD×9QÒ9Q©vÐW[×.`Ñ.`ÐanÓ.oÓpˆEØÒ%¨%°!¬)ˆ5Ð=¸Ð=r   )g      >@r   g     €V@r	   )&Ú__doc__r\   r-   Ú	threadingrZ   r   r   r   Úemail.utilsr   Útypingr   r   rX   ÚLockrW   rƒ   Ú#_ZAI_CODING_OVERLOAD_SHORT_ATTEMPTSr)   ÚcompileÚ
IGNORECASEÚ_QUOTA_RESET_DELAY_REÚ_RESETS_IN_REÚ_RETRY_AFTER_SECONDS_REÚ_RESETS_IN_SECONDS_FIELD_REr5   r<   rL   rH   rP   rc   rr   rz   r…   rˆ   ÚLIVE_RETRY_WAIT_CAP_SÚRETRY_AFTER_CAP_Sr�   © r   r   Ú<module>rŸ      sY  ðñó Û 	Û Û ß ,Ñ ,Ý -ß  ð €Ø�~Š~Ó€ð %>Ð !Ø&'Ð #õ"@ðN Ÿ
š
Ð#RÐTV×TaÑTaÓbÐ à—
’
ð>ð @B¿}¹}ó	€ð Ÿ*š*Ð%gÐik×ivÑivÓwÐ à ŸjšjÐ)SÐUW×UbÑUbÓcÐ õCõ
`ð Ð0Ð1ØÑ9Ð:Ø Ñ"=Ð>ØÐ&Ð'ð	Ð õZõðH¸#ð HÐRWð HÐor÷ Hõ Mõ	ðzà=÷zð =`÷ Gð Ð ð Ð ÷
>r   