+
    iHàjû  ã                  ó  € R t ^ RIHt ^ RIt^ RIHtHt ^ RIHtH	t	H
t
 Rt] ! R R4      4       t] ! R R4      4       tR R	 R
 lltR!R R lltR R ltR R ltR"R R lltR R ltR R ltR#R R lltR$R R lltR R ltR R ltR# )%a  Rate limit tracking for inference API responses.

Captures ``x-ratelimit-{limit,remaining,reset}-{requests,tokens}[-1h]``
headers (Nous Portal format, also used by OpenRouter / OpenAI-compatible APIs)
and formats them for the /usage slash command. Reset values are seconds.
)ÚannotationsN)Ú	dataclassÚfield)ÚAnyÚMappingÚOptionalc                  ó–   € ] tR t^t$ Rt^ tR]R&   ^ tR]R&   RtR]R&   Rt	R]R&   ]
R	 R
 l4       t]
R R l4       t]
R R l4       tRtR# )ÚRateLimitBucketz1One rate-limit window (e.g. requests per minute).ÚintÚlimitÚ	remainingç        ÚfloatÚreset_secondsÚcaptured_atc               ó   € V ^8„  d   QhRR/# )é   Úreturnr
   © )Úformats   "Ú=/home/ubuntu/.hermes/hermes-agent/agent/rate_limit_tracker.pyÚ__annotate__ÚRateLimitBucket.__annotate__!   s   € ÷ 3ñ 3�cñ 3ó    c                	óP   € \        ^ V P                  V P                  ,
          4      # ©é    )Úmaxr   r   ©Úselfs   &r   ÚusedÚRateLimitBucket.used    s   € ä�1�d—j‘j 4§>¡>Õ1Ó2Ð2r   c               ó   € V ^8„  d   QhRR/# ©r   r   r   r   )r   s   "r   r   r   %   s   € ÷ Kñ K˜5ñ Kr   c                	óp   € V P                   ^ 8”  d%   V P                  V P                   ,          R,          # R# )r   ç      Y@r   )r   r    r   s   &r   Ú	usage_pctÚRateLimitBucket.usage_pct$   s)   € à37·:±:À´>�—	‘	˜DŸJ™JÕ&¨%Õ/ÐJÀsÐJr   c               ó   € V ^8„  d   QhRR/# r#   r   )r   s   "r   r   r   )   s   € ÷ Oñ O uñ Or   c                ó„   € \        RV P                  \        P                  ! 4       V P                  ,
          ,
          4      # )zCEstimated seconds remaining until reset, adjusted for elapsed time.r   )r   r   Útimer   r   s   &r   Úremaining_seconds_nowÚ%RateLimitBucket.remaining_seconds_now(   s-   € ô �3˜×*Ñ*¬d¯iªi«k¸D×<LÑ<LÕ.LÕMÓNÐNr   r   N)Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__Ú__doc__r   Ú__annotations__r   r   r   Úpropertyr    r&   r+   Ú__static_attributes__r   r   r   r	   r	      sj   ‡ á;à€Eˆ3ƒNØ€IˆsÓØ€M�5ÓØ€K�Óàô3ó ð3ð ôKó ðKð ôOó ôOr   r	   c                  óÔ   € ] tR t^.t$ Rt]! ]R7      tR]R&   ]! ]R7      t	R]R&   ]! ]R7      t
R]R&   ]! ]R7      tR]R&   RtR	]R
&   RtR]R&   ]R R l4       t]R R l4       tRtR# )ÚRateLimitStatez3Full rate-limit state parsed from response headers.)Údefault_factoryr	   Úrequests_minÚrequests_hourÚ
tokens_minÚtokens_hourr   r   r   Ú ÚstrÚproviderc               ó   € V ^8„  d   QhRR/# )r   r   Úboolr   )r   s   "r   r   ÚRateLimitState.__annotate__:   s   € ÷ $ñ $˜$ñ $r   c                	ó    € V P                   ^ 8„  # r   )r   r   s   &r   Úhas_dataÚRateLimitState.has_data9   s   € à×Ñ !Ñ#Ð#r   c               ó   € V ^8„  d   QhRR/# r#   r   )r   s   "r   r   rA   >   s   € ÷ Qñ Q˜Uñ Qr   c                	óˆ   € V P                   '       d'   \        P                  ! 4       V P                  ,
          # \        R 4      # )Úinf)rC   r*   r   r   r   s   &r   Úage_secondsÚRateLimitState.age_seconds=   s*   € à15··°Œt�yŠy‹{˜T×-Ñ-Õ-ÐPÄEÈ%ÃLÐPr   r   N)r-   r.   r/   r0   r1   r   r	   r8   r2   r9   r:   r;   r   r>   r3   rC   rH   r4   r   r   r   r6   r6   .   s}   ‡ á=á$)¸/Ô$J€L�/ÓJÙ%*¸?Ô%K€M�?ÓKÙ"'¸Ô"H€J�ÓHÙ#(¸Ô#I€K�ÓIØ€K�ÓØ€HˆcÓàô$ó ð$ð ôQó ôQr   r6   c               ó$   € V ^8„  d   QhRRRRRR/# ©r   Úvaluer   Údefaultr   r   )r   s   "r   r   r   B   s!   € ÷ ñ �sð  Sð °3ñ r   c                óL   €  \        V 4      #   \        \        3 d    Tu # i ; i©N)r   Ú	TypeErrorÚ
ValueError©rL   rM   s   &&r   Ú_safe_floatrS   B   s*   € ðÜ�U‹|ÐøÜ”zÐ"ô ØŠðús   ‚
 �#¢#c               ó$   € V ^8„  d   QhRRRRRR/# rK   r   )r   s   "r   r   r   I   s!   € ÷ ñ �Sð  3ð ¨sñ r   c                ó^   €  \        \        V 4      4      #   \        \        3 d    Tu # i ; irO   )r
   r   rP   rQ   rR   s   &&r   Ú	_safe_intrV   I   s/   € ðÜ”5˜“<Ó Ð øÜ”zÐ"ô ØŠðús   ‚ –,«,c               ó    € V ^8„  d   QhRRRR/# )r   ÚheaderszOptional[Mapping[str, str]]r   zdict[str, str]r   )r   s   "r   r   r   P   s   € ÷ Iñ IÐ6ð I¸>ñ Ir   c                óˆ   € V '       d4   V P                  4        UUu/ uF  w  rVP                  4       VbK  	  upp# / # u uppi )z@Lowercase header names (HTTP header names are case-insensitive).)ÚitemsÚlower)rX   ÚkÚvs   &  r   Úlower_headersr^   P   s3   € ç9@ W§]¡]¤_Ô5¡_™T˜QˆA�G‰G‹I�qŠL¡_Ò5ÐHÀbÐHùÓ5s   œ>c               ó    € V ^8„  d   QhRRRR/# )r   ÚloweredúMapping[str, str]r   r@   r   )r   s   "r   r   r   U   s   € ÷ >ñ >Ð$5ð >¸$ñ >r   c                ój   € \         ;QJ d    R  V  4       F  '       g   K   R# 	  R# ! R  V  4       4      # )c              3  óB   "  € T F  qP                  R 4      x € K  	  R# 5i)zx-ratelimit-N)Ú
startswith)Ú.0r\   s   & r   Ú	<genexpr>Ú)has_rate_limit_headers.<locals>.<genexpr>V   s   é € Ð=±W°�|‰|˜N×+Ð+³Wùs   ‚TF)Úany)r`   s   &r   Úhas_rate_limit_headersri   U   s+   € ß‹3Ñ=±WÓ=�3Œ3Ð=Š3Ð=ˆ3Ñ=±WÓ=Ó=Ð=r   c               ó$   € V ^8„  d   QhRRRRRR/# )r   rX   ra   r>   r=   r   zOptional[RateLimitState]r   )r   s   "r   r   r   Y   s(   € ÷ Iñ IÐ&7ð IÀ3ð IÐPhñ Ir   c                ó‚  € \        V 4      p\        V4      '       g   R# \        P                  ! 4       p\         UUu/ uFf  w  rEV\	        \        VP                  RV 24      4      \        VP                  RV 24      4      \        VP                  RV 24      4      VR7      bKh  	  ppp\        RRVRV/VB # u uppi )	zIParse x-ratelimit-* headers into a RateLimitState (None if none present).Nzx-ratelimit-limit-zx-ratelimit-remaining-zx-ratelimit-reset-)r   r   r   r   r   r>   r   )	r^   ri   r*   Ú_BUCKET_TAGSr	   rV   ÚgetrS   r6   )rX   r>   r`   ÚnowÚattrÚtagÚbucketss   &&     r   Úparse_rate_limit_headersrr   Y   sÆ   € ä˜GÓ$€GÜ! '×*Ò*Ùä
�)Š)‹+€Cõ &ôñ &‰IˆDð 	ŒoÜ˜GŸK™KÐ*<¸S¸EÐ(BÓCÓDÜ §¡Ð.DÀSÀEÐ,JÓ KÓLÜ% g§k¡kÐ4FÀsÀeÐ2LÓ&MÓNØô	
ò 	
ñ &ð ñ ô ÑH cÐH°HÐHÀÑHÐHùós   ½A,B;c               ó    € V ^8„  d   QhRRRR/# )r   Únr
   r   r=   r   )r   s   "r   r   r   o   s   € ÷ ñ �#ð ˜#ñ r   c                óh   € V R8¼  d   V R,          R R2# V R8¼  d   V R,          R R2# \        V 4      # )zIHuman-friendly number: 7999856 -> '8.0M', 33599 -> '33.6K', 799 -> '799'.i@B z.1fÚMiè  ÚK)r=   )rt   s   &r   Ú
_fmt_countrx   o   s@   € àˆI„~Ø�i•- Ð$ AÐ&Ð&ØˆE„zØ�e•)˜C� Ð"Ð"Üˆq‹6€Mr   c               ó    € V ^8„  d   QhRRRR/# )r   Úsecondsr   r   r=   r   )r   s   "r   r   r   x   s   € ÷ 
*ñ 
*˜%ð 
* Cñ 
*r   c                óð   € \        ^ \        V 4      4      pV^<8  d   V R2# VR8  d$   \        V^<4      w  r#V'       d	   V RV R2# V R2# \        VR4      w  rBV^<,          pV'       d	   V RV R2# V R2# )zHSeconds -> human-friendly duration: '58s', '2m 14s', '58m 57s', '1h 2m'.Úsi  zm Úmzh Úh)r   r
   Údivmod)rz   r|   r}   Úsecr~   s   &    r   Ú_fmt_secondsr�   x   sŒ   € äˆAŒs�7‹|Ó€AØˆ2„vØ��AˆwˆØˆ4„xÜ˜˜2“‰ˆß!$�!��B�s�e˜1ˆ~Ð1¨Q¨C¨q¨'Ð1Ü�!�T‹?�D€AØˆ"…H€AßˆaˆS��1�#�Qˆ<Ð) Q C q 'Ð)r   c               ó$   € V ^8„  d   QhRRRRRR/# )r   Úpctr   Úwidthr
   r   r=   r   )r   s   "r   r   r   …   s!   € ÷ ;ñ ;ˆeð ;˜Cð ;¨ñ ;r   c           
     ó”   € \        ^ \        V\        V R,          V,          4      4      4      pRRV,           RW,
          ,           R2# )uW   ASCII progress bar: [â–ˆâ–ˆâ–ˆâ–ˆâ–ˆâ–ˆâ–ˆâ–ˆâ–‘â–‘â–‘â–‘â–‘â–‘â–‘â–‘â–‘â–‘â–‘â–‘] 40%.r%   Ú[u   â–ˆu   â–‘Ú])r   Úminr
   )rƒ   r„   Úfilleds   && r   Ú_barrŠ   …   sC   € ä�”C˜œs 3¨¥;°Õ#6Ó7Ó8Ó9€FØˆu�v�~Ð˜u¨­Õ7Ð8¸Ð:Ð:r   c               ó(   € V ^8„  d   QhRRRRRRRR/# )r   Úlabelr=   Úbucketr	   Úlabel_widthr
   r   r   )r   s   "r   r   r   ‹   s/   € ÷ {ñ {˜ð { _ð {À3ð {ÐPSñ {r   c                ó.  € VP                   ^ 8:  d   RV RV 2 R2# VP                  p\        \        VP                  VP                   VP
                  34      w  rEp\        VP                  4      pRV RV 2 R\        V4       RVR RV RV RV R	V R
2# )z#Format one bucket as a single line.z  Ú<z  (no data)Ú z5.1fz%  Ú/z used  (z left, resets in Ú))	r   r&   Úmaprx   r    r   r�   r+   rŠ   )rŒ   r�   rŽ   rƒ   r    r   r   Úresets   &&&     r   Ú_bucket_liner–   ‹   s¯   € à‡|�|�qÔØ�E˜!˜K˜=˜Ð)¨Ð5Ð5Ø
×
Ñ
€CÜ ¤¨f¯k©k¸6¿<¹<È×IYÑIYÐ-ZÓ[Ñ€D�Ü˜×5Ñ5Ó6€EØ��a˜�}�_Ð% Q¤t¨C£y k°°3°t°*¸CÀ¸vÀQÀuÀgÈXÐV_ÐU`Ð`qÐrwÐqxÐxyÐzÐzr   c               ó    € V ^8„  d   QhRRRR/# ©r   Ústater6   r   r=   r   )r   s   "r   r   r   •   s   € ÷ ñ  ^ð ¸ñ r   c                ó�  € V P                   '       g   R# V P                  pV^8  d   RM"V^<8  d   \        V4       R2M\        V4       R2pV P                  '       d   V P                  P                  4       MRpRV P                  3RV P                  3RV P                  3R	V P                  3.pV R
V R2R.pYTR,           UUu. uF  w  rg\        Wg4      NK  	  upp,          pTR.VR,           UUu. uF  w  rg\        Wg4      NK  	  upp,           ,          pV UUu. uFb  w  rgVP                  ^ 8”  g   K  VP                  ^P8¼  g   K+  RVP                  4        RVP                  R R\        VP                  4       2NKd  	  pppV'       d   VR.V,           ,          pRP                  V4      # u uppi u uppi u uppi )z2Format rate limit state for terminal/chat display.u5   No rate limit data yet â€” make an API request first.zjust nowzs agoz agoÚProviderzRequests/minzRequests/hrz
Tokens/minz	Tokens/hrz Rate Limits (captured z):r<   :Nr   N:r   NNu     âš  z at z.0fu   % â€” resets in Ú
)rC   rH   r
   r�   r>   Útitler8   r9   r:   r;   r–   r   r&   r[   r+   Újoin)	r™   ÚageÚ	freshnessÚprovider_labelÚlabeledÚlinesrŒ   r�   Úwarningss	   &        r   Úformat_rate_limit_displayr¥   •   s²  € à�>�>ˆ>ÙFà
×
Ñ
€CØ! Aœg‘
ÀÀrÄ¬c°#«h¨Z°uÑ+=ÔR^Ð_bÓRcÐQdÐdhÐOi€Ià/4¯~¯~¨~�U—^‘^×)Ñ)Ô+À:€NØ × 2Ñ 2Ð3°mÀU×EXÑEXÐ5YØ˜e×.Ñ.Ð/°+¸u×?PÑ?PÐ1QðS€GàÐÐ6°y°kÀÐDÀbÐI€EØ	Àr¾{ÔK¹{©m¨eŒl˜5Ö)¹{ÒKÕK€EØ	ˆbˆTÀgÈbÆkÔRÁk±]°U”\ %Ö0ÁkÒRÕRÕR€Eñ %ôá$‰MˆEØ�<‰<˜!Ñô 	wà &× 0Ñ 0°BÑ 6ô 	wˆ&�—‘“�˜t F×$4Ñ$4°SÐ#9Ð9IÌ,ÐW]×WsÑWsÓJtÐIuÓvÙ$ð ñ ÷
 Ø�"�˜•Õ ˆØ�9‰9�UÓÐùó LùÛRùós   ÃF6Ã6F<
Ä!GÄ;GÅ;Gc               ó    € V ^8„  d   QhRRRR/# r˜   r   )r   s   "r   r   r   ®   s   € ÷ ñ  ^ð ¸ñ r   c                óö   € V P                   '       g   R# RV P                  \        R3RV P                  \        R3RV P
                  \        R3RV P                  \        R33pRP                  R	 V 4       4      # )
z<One-line compact summary for status bars / gateway messages.zNo rate limit data.ÚRPMFÚRPHTÚTPMÚTPHz | c              3  óò   "  € T Fm  w  rr4VP                   ^ 8”  g   K  V RV! VP                  4       RV! VP                   4       2V'       d   R\        VP                  4       R2MR,           x € Ko  	  R# 5i)r   z: r’   z	 (resets r“   r<   N)r   r   r�   r+   )re   rp   ÚbÚfmtr•   s   &    r   rf   Ú,format_rate_limit_compact.<locals>.<genexpr>º   sq   é € ð á")ÑˆC�C¨Q¯W©W°q©[ô 	~ˆ3ˆ%ˆr‘#�a—k‘kÓ"Ð# 1¡S¨¯©£\ NÐ3×ot¸Ä<ÐPQ×PgÑPgÓChÐBiÐijÑ7kÐz|×}Ò}Û")ùs   ‚A7�0A7Á)A7)rC   r8   r=   r9   rx   r:   r;   rž   )r™   Úwindowss   & r   Úformat_rate_limit_compactr±   ®   s   € à�>�>ˆ>Ù$ð 
�×"Ñ"¤C¨Ð/Ø	�×#Ñ#¤Z°Ð6Ø	�× Ñ ¤*¨eÐ4Ø	�×!Ñ!¤:¨tÐ4ð	€Gð �:‰:ñ á")óó ð r   ))r8   Úrequests)r9   zrequests-1h)r:   Útokens)r;   z	tokens-1h)r   r   )r<   )é   )é   )r1   Ú
__future__r   r*   Údataclassesr   r   Útypingr   r   r   rl   r	   r6   rS   rV   r^   ri   rr   rx   r�   rŠ   r–   r¥   r±   r   r   r   Ú<module>r¹      s”   ðñõ #ã ß (ß )Ñ )ð€ð ÷Oð Oó ðOð, ÷Qð Qó ðQ÷&÷õIõ
>÷Iõ,õ
*÷;÷{õ÷2r   