Ë
    áß²jÙ  ã                  ól   — d Z ddlmZ ddlZddlmZmZmZmZ erddl	m
Z
 dZdd„Zdd„Z G d	„ d
«      Zy)a±  Model-scoped rate-limit cooldowns for pooled credentials.

Anthropic enforces its API rate limits (requests / tokens per minute) per
model, so a generic 429 for one Claude model says nothing about the same
credential's standing for its sibling models. Such a 429 is recorded as a
cooldown on the requested model only, beside the credential-wide status that
auth, billing and payment failures keep benching the whole credential with.
é    )ÚannotationsN)ÚAnyÚDictÚOptionalÚTYPE_CHECKING)ÚPooledCredentiali€3ác                ó$  — | j                   xs i }|s|j                  «       n|j                  |«      f}t        j                  «       }|D �cg c]*  }t	        |t
        t        f«      sŒ||kD  sŒ t        |«      ‘Œ, }}|rt        |«      S dS c c}w )z×Active cooldown blocking *entry* for *model*, or ``None``.

    Callers that do not know the model stay conservative: any active model
    cooldown blocks them, so an unscoped route cannot reuse the credential.
    N)Úmodel_cooldownsÚvaluesÚgetÚtimeÚ
isinstanceÚintÚfloatÚmax)ÚentryÚmodelÚ	cooldownsr   ÚnowÚuntilÚactives          úJ/home/ubuntu/.hermes/hermes-agent/agent/credential_pool_model_cooldowns.pyÚmodel_cooldown_untilr      s�   € ð ×%Ñ%Ò+¨€IÙ',ˆY×ÑÔ°9·=±=ÀÓ3GÐ2I€FÜ
�)‰)‹+€CØ(.Öb˜u´*¸UÄSÌ%ÀLÕ2QÐV[Ð^aÓVaŒe�E�lÐb€FÐbÙ Œ3ˆv‹;Ð* dÐ*ùò cs   ÁBÁ)BÁ/Bc            	     óè   — i }| D ]j  }t        |t        «      sŒ|j                  «       D ]D  \  }}t        |t        t        f«      sŒt        t	        |«      |j                  |d«      «      ||<   ŒF Œl |S )uT   Latest reset per model across snapshots â€” each writer only observed its own model.g        )r   ÚdictÚitemsr   r   r   r   )ÚmapsÚmergedr   r   r   s        r   Úmerge_model_cooldownsr   #   su   € à!€FØò Jˆ	Ü˜)¤TÔ*ØØ%ŸO™OÓ-ò 	J‰LˆE�5Ü˜%¤#¤u Õ.Ü #¤E¨%£L°&·*±*¸UÀCÓ2HÓ I��u’ñ	JðJð €Mó    c                  óP   — e Zd Zddœdd„Z	 	 	 	 	 	 	 	 dd„Z	 d	 	 	 	 	 	 	 	 	 d	d„Zy)
Ú CredentialPoolModelCooldownMixinN)r   c               óˆ   ‡‡— | j                   5  t        ˆˆfd„| j                  D «       «      cddd«       S # 1 sw Y   yxY w)a   Whether a pool cooldown blocks *token* for *model*.

        Closes the paths that hand out a native Anthropic token without
        selecting it from the pool (env / borrowed credentials). Tokens the
        pool does not know fail open: no row can attribute a cooldown to them.
        c              3  ó\   •K  — | ]#  }|j                   ‰k(  xr t        |‰«      d u–— Œ% y ­w©N)Úruntime_api_keyr   )Ú.0r   r   Útokens     €€r   ú	<genexpr>zDCredentialPoolModelCooldownMixin.token_is_blocked.<locals>.<genexpr>8   s:   øè ø€ ò àð ×%Ñ%¨Ñ.ÒaÔ3GÈÈuÓ3UÐ]aÐ3aÓañùs   ƒ),N)Ú_lockÚanyÚ_entries)Úselfr(   r   s    ``r   Útoken_is_blockedz1CredentialPoolModelCooldownMixin.token_is_blocked0   s:   ù€ ð �Z‰Zñ 	Üô à!Ÿ]™]ôó ÷	÷ 	ò 	ús	   �8¸Ac                ó`   — ddl m}m} |sy|dk(  ry| j                  dk(  xr |dk(  xr |||fvS )z³Anthropic per-model 429s, and a Codex ChatGPT-account model entitlement 400: the
        account cannot use *model*, but the credential stays valid for every other model (#71970).r   )ÚFAILURE_REASON_BILLINGÚ!FAILURE_REASON_BILLING_UNVERIFIEDFÚmodel_entitlementTÚ	anthropicé­  )Úagent.credential_poolr0   r1   Úprovider)r-   Ústatus_coder   Úfailure_reasonr0   r1   s         r   Ú_is_model_scoped_failurez9CredentialPoolModelCooldownMixin._is_model_scoped_failure=   sM   € ÷
 	dáØØÐ0Ò0Øà�M‰M˜[Ñ(ò b¨[¸CÑ-?ò bØÐ'=Ð?`Ð&aÐað	
r    c                óü  — ddl m}m} |dk(  rt        j                  «       t        z   }nF ||«      j                  d«      xs- t        j                  «        |d| j                  «       ¬«      z   }|j                  }t        | j                  «      D ]Y  }	|	j                  |j                  k7  r|r|	j                  |k(  sŒ.t        |	j                  ||i«      }
| j                  |	d|
¬«       Œ[ | j                  «        y	)
a   Record a cooldown for *model* on *entry* and every sibling sharing its key.

        Same TTL policy as a credential-wide 429 (provider ``reset_at`` wins, a
        sole credential keeps its short bench), except a ``model_entitlement``
        rejection, which stays benched until the explicit reset path clears it.
        Siblings matter because a ``model_config`` twin seeded from the same key
        would otherwise be re-selected for the very model that just failed.
        Caller holds the lock.
        r   )Ú_exhausted_ttlÚ_normalize_error_contextr2   Úreset_atr4   )Úsole_credentialF)Úpersistr
   N)r5   r;   r<   r   ÚMODEL_ENTITLEMENT_BENCH_SECONDSr   Ú_is_sole_credentialr&   Úlistr,   Úidr   r
   Ú_adoptÚ_persist)r-   r   r   Úerror_contextr8   r;   r<   r   Ú
failed_keyÚscopedr   s              r   Ú_cool_down_modelz1CredentialPoolModelCooldownMixin._cool_down_modelM   sÚ   € ÷ 	SàÐ0Ò0Ü—I‘I“KÔ"AÑA‰Eá,¨]Ó;×?Ñ?À
ÓKò Ü—	‘	“™n¨SÀ$×BZÑBZÓB\Ô]Ñ]ð ð ×*Ñ*ˆ
Ü˜4Ÿ=™=Ó)ò 	JˆFØ�y‰y˜EŸH™HÒ$©j¸V×=SÑ=SÐWaÒ=aØÜ-¨f×.DÑ.DÀuÈeÀnÓUˆIØ�K‰K˜¨¸yˆKÕIð		Jð
 	�‰�r    )r(   Ústrr   úOptional[str]ÚreturnÚbool)r7   zOptional[int]r   rK   r8   rK   rL   rM   r%   )
r   ú'PooledCredential'r   rJ   rF   zOptional[Dict[str, Any]]r8   rK   rL   ÚNone)Ú__name__Ú
__module__Ú__qualname__r.   r9   rI   © r    r   r"   r"   /   sc   „ ØEIõ ð
Ø(ð
Ø1>ð
ØP]ð
à	ó
ð$ )-ðØ'ðØ03ðØD\ðà%ðð 
ôr    r"   )r   rN   r   rK   rL   zOptional[float])r   r   rL   zDict[str, float])Ú__doc__Ú
__future__r   r   Útypingr   r   r   r   r5   r   r@   r   r   r"   rS   r    r   ú<module>rW      s:   ðñõ #ã ß 5Ó 5áÝ6ð #5Ð ó
+ó	÷9ò 9r    