Ë
    áß²jõ  ã                   ó   — d Z ddlZddlZddlZddlZddlmZmZ ddlmZ ddl	m
Z
mZ da ej                  «       ZdZdZde
d	ee   fd
„Z ej&                  dej(                  «      Z ej&                  dej(                  «      Z ej&                  dej(                  «      Z ej&                  dej(                  «      Zddd	efd„Zddd	ee   fd„Zeefed„ fed„ feeffZded	efd„Zded	ee   fd„Zddddœdededed ed	ef
d!„Z d"e
d	efd#„Z!d$edz  d%edz  d"e
d	e"fd&„Z#ed'œded$edz  d%edz  d"e
d(ed)ed	e$eedz  f   fd*„Z%efd)ed	efd+„Z&y),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)Úparsedate_to_datetime)ÚAnyÚOptional)g      >@g      N@g     €V@ç      ^@é   Úvalue_or_headersÚreturnc                 óÞ  — | }|�Gt        |t        t        t        f«      s,t	        |dd«      }t        |«      sy	  |d«      }|€ |d«      }|�t        |t        «      ryt        |t        t        f«      rt        dt        |«      «      S t        |«      j                  «       }|sy	 t        dt        |«      «      S # t        $ r Y yw xY w# t        t        f$ r Y nw xY w	 t        |«      }n# t        t        f$ r Y yw xY w|€y|j                  € |j                  t        j                   ¬«      }t        d|t#        j$                  t        j                   «      z
  j'                  «       «      S )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ÚintÚfloatÚgetattrÚcallableÚ	ExceptionÚboolÚmaxÚstripÚ	TypeErrorÚ
ValueErrorr   r   Úreplacer   Úutcr   ÚnowÚtotal_seconds)r
   ÚrawÚgetterÚtextÚwhens        ú6/home/ubuntu/.hermes/hermes-agent/agent/retry_utils.pyÚparse_retry_after_secondsr$      sS  € ð €CØ
€œz¨#´´S¼%Ð/@ÔAÜ˜˜e TÓ*ˆÜ˜ÔØð	Ù˜Ó'ˆCØˆ{Ù˜]Ó+�ð €{”j ¤dÔ+ØÜ�#œœU�|Ô$Ü�3œ˜c›
Ó#Ð#Üˆs‹8�>‰>Ó€DÙØðÜ�3œ˜d›Ó$Ð$øô ò 	Ùð	ûô ”zÐ"ò ÙðúðÜ$ TÓ*‰øÜ”zÐ"ò Ùðúà€|ØØ‡{�{ÐØ�|‰|¤8§<¡<ˆ|Ó0ˆÜˆs�TœHŸL™L¬¯©Ó6Ñ6×EÑEÓGÓHÐHs5   ºB< Â'C Â<	CÃCÃCÃCÃ!C- Ã-C?Ã>C?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+)?)Úmzre.Match[str]c                 óˆ   — t        | j                  d«      «      }| j                  d«      j                  «       dk(  r|dz  S |S )Né   é   Úmsg     @�@)r   ÚgroupÚlower)r%   Úvalues     r#   Ú_quota_reset_secondsr-   R   s;   € Ü�!—'‘'˜!“*Ó€EØŸW™W Q›Z×-Ñ-Ó/°4Ò7ˆ5�6‰>ÐB¸UÐBó    c                 óú   — t        | j                  «       «      sy t        | j                  d«      xs d«      dz  t        | j                  d«      xs d«      dz  z   t        | j                  d«      xs d«      z   S )Nr'   r   é  r(   é<   r	   )ÚanyÚgroupsr   r*   ©r%   s    r#   Ú_resets_in_secondsr5   W   sa   € Üˆq�x‰x‹zŒ?ØÜ�—‘˜“’˜qÓ! DÑ(¬5°·±¸³²¸qÓ+AÀBÑ+FÑFÌÈqÏwÉwÐWXËzÊÐ]^ÓI_Ñ_Ð_r.   c                 ó6   — t        | j                  d«      «      S ©Nr'   ©r   r*   r4   s    r#   ú<lambda>r9   b   s   € ¬¨a¯g©g°a«jÓ(9€ r.   c                 ó6   — t        | j                  d«      «      S r7   r8   r4   s    r#   r9   r9   c   s   € ¬E°!·'±'¸!³*Ó,=€ r.   Úsecondsc                 óN   — t        | «      } | dk\  rd|  dz   › d�S d|  dz   › d�S )zS``~9h`` / ``~45 min`` for chat copy naming when a quota window reopens (ceilinged).r0   Ú~Úhr1   z min)r   )r;   s    r#   Úformat_reset_windowr?   h   sE   € ä�'‹l€GØ)0°DªˆQ�'�˜TÑ!Ð"Ð# 1Ð%ÐYÀÀWÀHÐPRÁNÐBSÐATÐTXÐ>YÐYr.   Úmessagec                 ój   — | syt         D ]'  \  }}|j                  | «      }|sŒ ||«      x}€Œ%|c S  y)zKSeconds-until-reset parsed from free-text provider error messages, or None.N)ÚRETRY_DELAY_PATTERNSÚsearch)r@   ÚpatternÚ
to_secondsr%   r;   s        r#   Úreset_delay_from_messagerF   n   sE   € áØÜ3ò Ñˆ�Ø�N‰N˜7Ó#ˆÚ™Z¨›]Ð*�'Ñ7ØŠNðð r.   g      @r   g      à?©Ú
base_delayÚ	max_delayÚjitter_ratioÚattemptrH   rI   rJ   c                ó@  — t         5  t        dz  at        }ddd«       t        d| dz
  «      }|dk\  s|dk  r|nt        |d|z  z  |«      }t	        j
                  «       dz  z  dz  }|t        j                  |«      j                  d||z  «      z   S # 1 sw Y   Œ~xY w)zomin(base * 2^(attempt-1), max_delay) + uniform jitter in
    [0, jitter_ratio * delay]. ``attempt`` is 1-based.r'   Nr   é?   r(   l   ¹yn< l   ÿÿ )	Ú_jitter_lockÚ_jitter_counterr   ÚminÚtimeÚtime_nsÚrandomÚRandomÚuniform)rK   rH   rI   rJ   ÚtickÚexponentÚdelayÚseeds           r#   Újittered_backoffrZ   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   ‡BÂBÚerrorc                 óœ   — | t        | dd«      t        | dd«      t        | dd«      g}dj                  d„ |D «       «      j                  «       S )zCBest-effort flattened provider error text for retry classification.r@   NÚbodyÚresponseú c              3   ó8   K  — | ]  }|€Œt        |«      –— Œ y ­w)N)r   )Ú.0Úparts     r#   ú	<genexpr>z_error_text.<locals>.<genexpr>Œ   s   è ø€ ÒD $°4Ñ3C”C˜—IÑDùs   ‚Š)r   Újoinr+   )r[   Úpartss     r#   Ú_error_textrf   ‰   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.   Úbase_urlÚmodelc                 ó°   — t        |«      }t        |dd«      dk(  xr: d| xs dj                  «       v xr" d|xs dj                  «       v xr
 d|v xs d|v S )	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)rf   r   r+   )rg   rh   r[   r!   s       r#   Úis_zai_coding_overload_errorrm   �   st   € ô �uÓ€Dä��} dÓ+¨sÑ2ò 	AØ)¨hªn¸"×-CÑ-CÓ-EÐEò	Aà˜%š+ 2×,Ñ,Ó.Ð.ò	Að �tˆ^Ò?Ð7¸4Ð?ð	r.   ©Úshort_attemptsÚdefault_waitro   c                ó°   — t        |||¬«      s|dfS | |k  r|dfS t        | |z
  dz
  t        t        «      dz
  «      }t        |   }t	        d||d¬«      dfS )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.)rg   rh   r[   NÚzai_coding_overload_shortr'   gš™™™™™É?rG   Úzai_coding_overload_long)rm   rP   ÚlenÚ!_ZAI_CODING_OVERLOAD_LONG_BACKOFFrZ   )rK   rg   rh   r[   rp   ro   ÚidxrH   s           r#   Úadaptive_rate_limit_backoffrw   ›   ss   € ô (°ÀÈeÕTØ˜TÐ!Ð!Ø�.Ò ØÐ8Ð8Ð8Ü
ˆg˜Ñ&¨Ñ*¬CÔ0QÓ,RÐUVÑ,VÓ
W€CÜ2°3Ñ7€JÜ˜A¨*À
ÐY\Ô]Ð_yÐyÐyr.   c                 ó,   — | t        t        «      z   dz   S )a   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'   )rt   ru   rn   s    r#   Ú!zai_coding_overload_retry_ceilingry   ª   s   € ð œCÔ AÓBÑBÀQÑFÐFr.   )'Ú__doc__rS   ÚreÚ	threadingrQ   r   r   Úemail.utilsr   Útypingr   r   rO   ÚLockrN   ru   Ú#_ZAI_CODING_OVERLOAD_SHORT_ATTEMPTSr   r$   ÚcompileÚ
IGNORECASEÚ_QUOTA_RESET_DELAY_REÚ_RESETS_IN_REÚ_RETRY_AFTER_SECONDS_REÚ_RESETS_IN_SECONDS_FIELD_REr-   r5   rB   r   r?   rF   r   rZ   rf   r   rm   Útuplerw   ry   © r.   r#   ú<module>r‰      sZ  ðñó Û 	Û Û ß 'Ý -ß  ð €Øˆy�~‰~Ó€ð %>Ð !Ø&'Ð #ð"I°ð "I¸À¹ó "IðN #˜Ÿ
™
Ð#RÐTV×TaÑTaÓbÐ à�—
‘
ð>ð @B¿}¹}ó	€ð %˜"Ÿ*™*Ð%gÐik×ivÑivÓwÐ à(˜bŸj™jÐ)SÐUW×UbÑUbÓcÐ ðC˜Oð C°ó Cð
`˜/ð `¨h°u©oó `ð Ð0Ð1ØÑ9Ð:Ø Ñ"=Ð>ØÐ&Ð'ð	Ð ðZ ð Z¨3ó Zð cð ¨h°u©oó ð ;>ÐRWÐorò H˜cð H°%ð HÈ%ð HÐglð HÐw|ó Hð M�sð M˜só Mð	¨c°D©jð 	ÀÀtÁð 	ÐTWð 	Ð\`ó 	ð >òzØðzØ" T™zðzØ25¸±*ðzØEHðzØX]ðzàðzð ˆ5�#˜‘*ÐÑózð =`ñ G°cð GÐdgô Gr.   