§
    ÷žyj    ã                   óN  — d 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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dS )uè   Retry utilities â€” jittered backoff for decorrelated retries.

Replaces fixed exponential backoff with jittered delays to prevent
thundering-herd retry spikes when multiple 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                 ót  — | }|�rt          |t          t          t          f¦  «        sPt	          |dd¦  «        }t          |¦  «        r.	  |d¦  «        }|€ |d¦  «        }n# t          $ r Y dS w xY w|}ndS |€dS t          |t          ¦  «        rdS t          |t          t          f¦  «        rt          dt          |¦  «        ¦  «        S t          |¦  «         	                    ¦   «         }|sdS 	 t          dt          |¦  «        ¦  «        S # t          t          f$ r Y nw xY w	 t          |¦  «        }n# t          t          f$ r Y dS w xY w|€dS |j        € |                     t          j        ¬¦  «        }t          d|t#          j        t          j        ¦  «        z
                       ¦   «         ¦  «        S )a  Parse a ``Retry-After`` value into non-negative seconds.

    Accepts either a raw header value (numeric string / HTTP-date / number)
    or a headers mapping, in which case the ``Retry-After`` key is looked up
    case-insensitively (``.get`` on dict-like objects tries both common
    casings; real HTTP header containers like httpx/requests are already
    case-insensitive).

    Returns:
        Seconds as a ``float`` (negative deltas clamped to ``0.0``), or
        ``None`` when the header is absent or 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ÚvalueÚtextÚwhens         ú7/home/ragecks/.hermes/hermes-agent/agent/retry_utils.pyÚparse_retry_after_secondsr%   &   sÙ  € ð €CØ
€�z¨#µµS½%Ð/@ÑAÔA€å˜˜e TÑ*Ô*ˆÝ�FÑÔð 		ðØ˜˜}Ñ-Ô-�Ø�=Ø"˜F =Ñ1Ô1�EøøÝð ð ð Ø�t�tðøøøàˆCˆCà�4Ø
€{ØˆtÝ�#•tÑÔð ØˆtÝ�#��U�|Ñ$Ô$ð $Ý�3�˜c™
œ
Ñ#Ô#Ð#Ýˆs‰8Œ8�>Š>ÑÔ€DØð ØˆtðÝ�3�˜d™œÑ$Ô$Ð$øÝ•zÐ"ð ð ð ØˆðøøøðÝ$ TÑ*Ô*ˆˆøÝ•zÐ"ð ð ð Øˆtˆtðøøøà€|ØˆtØ„{ÐØ�|Š|¥8¤<ˆ|Ñ0Ô0ˆÝˆs�T�HœL­¬Ñ6Ô6Ñ6×EÒEÑGÔGÑHÔHÐHs6   ÁA! Á!
A/Á.A/Ã1D ÄD"Ä!D"Ä&D6 Ä6EÅ
Eg      @r   g      à?©Ú
base_delayÚ	max_delayÚjitter_ratioÚattemptr'   r(   r)   c                ón  — t           5  t          dz  at          }ddd¦  «         n# 1 swxY w Y   t          d| dz
  ¦  «        }|dk    s|dk    r|}nt          |d|z  z  |¦  «        }t	          j        ¦   «         |dz  z  dz  }t          j        |¦  «        }|                     d||z  ¦  «        }	||	z   S )aC  Compute a jittered exponential backoff delay.

    Args:
        attempt: 1-based retry attempt number.
        base_delay: Base delay in seconds for attempt 1.
        max_delay: Maximum delay cap in seconds.
        jitter_ratio: Fraction of computed delay to use as random jitter
            range.  0.5 means jitter is uniform in [0, 0.5 * delay].

    Returns:
        Delay in seconds: min(base * 2^(attempt-1), max_delay) + jitter.

    The jitter decorrelates concurrent retries so multiple sessions
    hitting the same provider don't all retry at the same instant.
    é   Nr   é?   é   l   ¹yn< l   ÿÿ )	Ú_jitter_lockÚ_jitter_counterr   ÚminÚtimeÚtime_nsÚrandomÚRandomÚuniform)
r*   r'   r(   r)   ÚtickÚexponentÚdelayÚseedÚrngÚjitters
             r$   Újittered_backoffr=   Z   s   € õ. 
ð ð Ý˜1ÑˆÝˆðð ð ñ ô ð ð ð ð ð ð øøøð ð ð ð õ �1�g ‘kÑ"Ô"€HØ�2‚~€~˜ qš˜Øˆˆå�J ! x¡-Ñ0°)Ñ<Ô<ˆõ ŒL‰NŒN˜d ZÑ/Ñ0°JÑ>€DÝ
Œ-˜Ñ
Ô
€CØ�[Š[˜˜L¨5Ñ0Ñ1Ô1€Fà�6‰>Ðs   ˆ&¦*­*Úerrorc                 óÊ   — | t          | dd¦  «        t          | dd¦  «        t          | dd¦  «        g}d                     d„ |D ¦   «         ¦  «                             ¦   «         S )zCBest-effort flattened provider error text for retry classification.ÚmessageNÚbodyÚresponseÚ c              3   ó8   K  — | ]}|®t          |¦  «        V — Œd S )N)r   )Ú.0Úparts     r$   ú	<genexpr>z_error_text.<locals>.<genexpr>‹   s-   è è € ÐDÐD $°4Ð3C•C˜‘I”IÐ3CÐ3CÐ3CÐ3CÐDÐDó    )r   ÚjoinÚlower)r>   Úpartss     r$   Ú_error_textrL   ƒ   sj   € ð 	Ý��y $Ñ'Ô'Ý��v˜tÑ$Ô$Ý��z 4Ñ(Ô(ð	€Eð �8Š8ÐDÐD¨%ÐDÑDÔDÑDÔD×JÒJÑLÔLÐLrH   Úbase_urlÚmodelc                 óÆ   — | pd                      ¦   «         }|pd                      ¦   «         }t          |dd¦  «        }t          |¦  «        }|dk    od|v od|v od|v pd|v S )	aL  Return True for Z.AI Coding Plan transient overload 429s.

    The coding-plan endpoint reports overload as HTTP 429 with body code 1305
    and message "The service may be temporarily overloaded...". Treat only
    that narrow shape specially so ordinary quota/billing 429s still fail fast
    through the existing classifier.
    Ú Ústatus_codeNi­  zapi.z.ai/api/coding/paas/v4zglm-5.2Ú1305ztemporarily overloaded)rJ   r   rL   )rM   rN   r>   ÚbaseÚ
model_nameÚstatusr"   s          r$   Úis_zai_coding_overload_errorrV   Ž   sŽ   € ð ˆN˜×!Ò!Ñ#Ô#€DØ�+˜2×$Ò$Ñ&Ô&€JÝ�U˜M¨4Ñ0Ô0€FÝ�uÑÔ€Dà�#Šð 	AØ)¨TÐ1ð	Aà˜Ð#ð	Að �tˆ^Ð?Ð7¸4Ð?ð	rH   ©Úshort_attemptsÚdefault_waitrX   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 )u7  Provider-aware rate-limit backoff.

    For most providers this returns ``default_wait`` unchanged. For Z.AI
    Coding Plan GLM-5.2 overloads, keep the first ``short_attempts`` retries on
    the normal short exponential schedule, then switch to progressively longer
    waits (30s â†’ 60s â†’ 90s â†’ 120s, capped) plus light jitter.

    ``attempt`` is 1-based, matching the retry loop's logged attempt number.
    Returns ``(wait_seconds, reason_label)`` where ``reason_label`` is suitable
    for status/log decoration when a provider-specific policy fired.
    )rM   rN   r>   NÚzai_coding_overload_shortr,   gš™™™™™É?r&   Úzai_coding_overload_long)rV   r1   ÚlenÚ!_ZAI_CODING_OVERLOAD_LONG_BACKOFFr=   )r*   rM   rN   r>   rY   rX   Úidxr'   s           r$   Úadaptive_rate_limit_backoffr`   ¢   s�   € õ( (°ÀÈeÐTÑTÔTð "Ø˜TÐ!Ð!Ø�.Ò Ð ØÐ8Ð8Ð8å
ˆg˜Ñ&¨Ñ*­CÕ0QÑ,RÔ,RÐUVÑ,VÑ
WÔ
W€CÝ2°3Ô7€Jõ ˜A¨*À
ÐY\Ð]Ñ]Ô]Ð_yÐyÐyrH   c                 ó6   — | t          t          ¦  «        z   dz   S )uú  Retry-loop ceiling needed for the full Z.AI overload backoff schedule.

    The adaptive policy runs ``short_attempts`` short retries, then walks the
    long-backoff table one entry per subsequent attempt. The retry loop gives
    up as soon as ``retry_count >= ceiling`` â€” and that check runs *before* the
    attempt's backoff is computed â€” so the ceiling must sit one past the final
    long-backoff entry for every long tier to actually execute.

    With the default ``api_max_retries`` (3) equal to ``short_attempts`` (3),
    the loop always gave up before reaching the long tier, leaving the whole
    long-backoff schedule as dead code. Callers extend the ceiling to this
    value for Z.AI Coding overload 429s so the 30/60/90/120s waits run.
    r,   )r]   r^   rW   s    r$   Ú!zai_coding_overload_retry_ceilingrb   Â   s   € ð �CÕ AÑBÔBÑBÀQÑFÐFrH   )Ú__doc__r4   Ú	threadingr2   r   r   Úemail.utilsr   Útypingr   r   r0   ÚLockr/   r^   Ú#_ZAI_CODING_OVERLOAD_SHORT_ATTEMPTSr   r%   r   r=   r   rL   r   rV   Útupler`   rb   © rH   r$   ú<module>rk      sL  ððð ð €€€Ø Ð Ð Ð Ø €€€Ø 'Ð 'Ð 'Ð 'Ð 'Ð 'Ð 'Ð 'Ø -Ð -Ð -Ð -Ð -Ð -Ø  Ð  Ð  Ð  Ð  Ð  Ð  Ð  ð
 €ØˆyŒ~ÑÔ€ð %>Ð !ð '(Ð #ð1I°ð 1I¸À¼ð 1Ið 1Ið 1Ið 1Iðn ØØð&ð &ð &Øð&ð ð&ð ð	&ð
 ð&ð ð&ð &ð &ð &ðRM�sð M˜sð Mð Mð Mð Mð¨c°D©jð ÀÀtÁð ÐTWð Ð\`ð ð ð ð ð6 >ðzð zð zØðzð �D‰jðzð �‰:ð	zð
 ðzð ðzð ðzð ˆ5�#˜‘*ÐÔðzð zð zð zð@ =`ð Gð G°cð GÐdgð Gð Gð Gð Gð Gð GrH   