Ë
    áß²jW  ã                  ón   — d Z ddlmZ ddlmZmZ dZdZdZdZ	ddeeee	d	œ	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dd
„Z
y)a«  Send-path image eviction policy shared by both stateless outbound passes.

Two passes retire old tool-result images from the per-request copy of the conversation:
``agent.context_compressor.evict_stale_outbound_tool_images`` on the OpenAI-shaped list and
``agent.anthropic_message_convert._evict_old_screenshots`` on the Anthropic wire list. Both run
from scratch on a fresh clone every request, so they must agree on one policy or the second
pass re-evicts on a different frontier than the first (#113517). This module is stdlib-only so
the wire converter, a leaf, can import it without dragging in the compaction stack.

Why the trigger is a provider limit, not a keep-newest count: retiring an image edits a message
the provider has already cached, and Anthropic matches its prompt cache on an exact byte prefix.
A keep-newest-N window retires one more message on every new image, so every turn is a
full-prefix miss. Holding images until the request would cross a real API limit and then
retiring a batch costs one slower turn per batch and nothing below the limit.

20 is the documented threshold at which Anthropic applies a stricter per-image dimension cap
(2000 px) to EVERY image in the request, counting images nested in tool_result content. The hard
ceilings are higher (100 images per request on 200K-context models, 600 otherwise) but the 32 MB
request-size limit usually binds first, which the byte budget guards with headroom for text.
é    )Úannotations)ÚOptionalÚSequenceé   i 6né   é   N)Úcarrier_bytes_newest_firstÚreserved_bytesÚlimitÚbudgetÚbatchÚfloorc               ó8  ‡‡‡‡‡‡‡‡‡— t        | «      }|Šdg|dz   z  Šdg|dz   z  Št        |«      D ](  }	‰|	   | |	   z   ‰|	dz   <   ‰|	   ‰�‰|	   ndz   ‰|	dz   <   Œ* dˆˆˆˆfd„Šdˆˆˆˆfd„Š ‰|«      ryt        t        |d«      |«      } ‰d«      s ‰|«      r||z
  n|}
|
dk  ry ‰d«      r t        ˆfd„t        |dz   «      D «       «      nd}t        dt        |||z
  «      «      }d}||
k  r#t        ||z   |
«      } ‰||z
  «      r	 |S ||
k  rŒ#|S )uó  How many of the OLDEST image-bearing tool results to retire.

    ``carrier_blocks_newest_first`` is the image-block count per image-bearing tool result,
    newest first; ``reserved_blocks`` counts images the pass must never rewrite (user
    uploads). The byte dimension is active only when ``carrier_bytes_newest_first`` is
    given (the wire pass has no sizes).

    The retire count must be a STEP FUNCTION of the overshoot, because the pass is recomputed
    on every request: an exact ``count - limit`` target moves the frontier on every new image,
    and a fixed one-batch retire stops enforcing the limit after the first batch. So the count
    advances in quanta until the request fits.

    The quantum is ``batch`` capped at ``window - floor``, where ``window`` is how many newest
    carriers fit under the ceiling. A quantum wider than that would step past the newest frames
    on every advance; cutting each step back to exactly ``total - floor`` instead makes the
    retire count track ``total`` again â€” the per-image frontier this policy exists to avoid,
    visible whenever a tool result carries several images or uploads fill most of the ceiling.
    Holding for ``window - floor`` turns per advance is the most the floor allows.

    The floor is a SATISFIABILITY floor: it shelters the newest frames only when reserved
    uploads alone breach the block ceiling (no retirement can fix that), and never under byte
    pressure â€” the request-size limit is hard and the provider answers 413.
    r   é   c                ó&   •— ‰d u xs ‰‰|    z   ‰k  S ©N© )Úkeptr   Ú
bytes_keptr
   Úsizess    €€€€ú@/home/ubuntu/.hermes/hermes-agent/agent/image_eviction_policy.pyÚ
_bytes_fitz/outbound_image_retire_count.<locals>._bytes_fitK   s!   ø€ Ø˜ˆ}ÒK °¸DÑ1AÑ AÀVÑ KÐKó    c                ó.   •— ‰‰|    z   ‰k  xr  ‰| «      S r   r   )r   r   Úblocks_keptr   Úreserved_blockss    €€€€r   Ú_fitsz*outbound_image_retire_count.<locals>._fitsN   s"   ø€ Ø ¨TÑ!2Ñ2°eÑ;ÒPÁ
È4Ó@PÐPr   c              3  ó4   •K  — | ]  } ‰|«      sŒ|–— Œ y ­wr   r   )Ú.0Úkr   s     €r   ú	<genexpr>z.outbound_image_retire_count.<locals>.<genexpr>X   s   øè ø€ Ò9�q±°aµ”Ñ9ùs   ƒ‘)r   ÚintÚreturnÚbool)ÚlenÚrangeÚminÚmax)Úcarrier_blocks_newest_firstr   r	   r
   r   r   r   r   ÚtotalÚiÚ
max_retireÚwindowÚquantumÚretirer   r   r   r   r   s    ` ```        @@@@@r   Úoutbound_image_retire_countr0   !   s_  ÿø€ ôD Ð+Ó,€EØ&€EØ�#˜ ™Ñ#€KØ�˜ ™	Ñ"€JÜ�5‹\ò SˆØ(¨™^Ð.IÈ!Ñ.LÑLˆ�A˜‘EÑØ& q™M¸Ð9J¨U°1ªXÐPQÑRˆ
�1�q‘5ÒðS÷Lð L÷Qð Qñ ˆU„|Øä”�E˜1“˜uÓ%€EÙ&+¨A¤h±:¸eÔ3D�˜’È%€JØ�Q‚ØÙ=BÀ1¼XŒSÓ9œE %¨!¡)Ó,Ô9Ô9È1€FÜ�!”S˜ ¨¡Ó/Ó0€Gà€FØ
�:Ò
Ü�V˜gÑ% zÓ2ˆÙ�˜‘Ô ØØ€Mð	 �:Ó
ð €Mr   )r)   zSequence[int]r   r"   r	   zOptional[Sequence[int]]r
   r"   r   r"   r   r"   r   r"   r   r"   r#   r"   )Ú__doc__Ú
__future__r   Útypingr   r   ÚOUTBOUND_IMAGE_LIMITÚOUTBOUND_IMAGE_BUDGET_BYTESÚIMAGE_EVICTION_BATCHÚOUTBOUND_IMAGE_FLOORr0   r   r   r   ú<module>r8      s™   ðñõ* #ç %àÐ Ø(Ð ØÐ àÐ ð ;?ØØ%Ø-Ø%Ø%ñ?Ø!.ð?àð?ð !8ð	?ð
 ð?ð ð?ð ð?ð ð?ð ð?ð 	ô?r   