+
    lHàj€  ã                  óÞ  a € 0 t $ R t^ RIHt ^ RIt^ RIt^ RIt^ RIt^ RIt^ RI	t	^ RI
Ht ^ RIHt ^ RIHtHtHt ^ RIHt R'tR(tR)t^tRt/ tR]R	&   ]	P6                  ! 4       tR*R
 R lltR R ltR R ltR R lt R R lt!R R lt"R R lt#R R lt$R R lt%]PL                  ! R]PN                  4      t(]! R])! 4       R7      t*R]R &   R! R" lt+]PX                  R# R$ l4       t-R% R& lt.R# )+aò  History-reuse budgets for native vision embeds (config section ``vision``).

A native ``vision_analyze`` result bakes the image into conversation history, where it is
re-sent on every later API call. Two knobs bound that cost: ``vision.embed_target_bytes``
(how large one embed may be) and ``vision.max_calls_per_image`` (how often the same image
may be embedded per session). See #112095: a delegated subagent re-loaded five screenshots
158 times in 15 minutes because nothing refused the repeat.
)ÚannotationsN)Ú
ContextVar)ÚPath)ÚAnyÚIteratorÚOptional)Ú
tool_errori   zdict[tuple[str, str], int]Ú_repeat_countsc               ó   € V ^8„  d   QhRR/# )é   ÚkeyÚstr© )Úformats   "ÚF/home/ubuntu/.hermes/hermes-agent/tools/vision_tools_history_budget.pyÚ__annotate__r   &   s   € ÷ ñ �Sñ ó    c                óZ   €  ^ RI HpHp V! V! 4       RWR7      #   \         d    Tu # i ; i)zJ``vision.<key>`` from config.yaml; ``default`` when config is unavailable.)Úcfg_getÚload_configÚvision©Údefault)Úhermes_cli.configr   r   Ú	Exception)r   r   r   r   s   &&  r   Ú_cfg_visionr   &   s/   € ðß:Ù‘{“} h°ÔEÐEøÜô ØŠðús   ‚ š*©*c               ó   € V ^8„  d   QhRR/# ©r   ÚreturnÚintr   )r   s   "r   r   r   /   s   € ÷ 	Nñ 	N Cñ 	Nr   c                 óþ   € \        R\        R7      p  \        V \        4      '       d   \	        R4      h\        V 4      p\        \        T\        4      \        4      #   \        \        \        3 d
    \        u # i ; i)zZ``vision.embed_target_bytes`` clamped to 64 KiB..4 MiB; the 256 KB default on a bad value.Úembed_target_bytesr   zboolean is not a byte budget)r   Ú_DEFAULT_EMBED_TARGET_BYTESÚ
isinstanceÚboolÚ
ValueErrorr   Ú	TypeErrorÚOverflowErrorÚminÚmaxÚ_MIN_EMBED_TARGET_BYTESÚ_MAX_EMBED_TARGET_BYTES)ÚrawÚtargets     r   Úresolve_embed_target_bytesr.   /   sm   € ä
Ð*Ô4OÔ
P€Cð+Ü�cœ4× Ò ÜÐ;Ó<Ð<Ü�S“ˆô Œs�6Ô2Ó3Ô5LÓMÐMøô ”z¤=Ð1ô +Ü*Ò*ð+ús   “,A ÁA<Á;A<c               ó   € V ^8„  d   QhRR/# r   r   )r   s   "r   r   r   ;   s   € ÷ Oñ O˜Cñ Or   c                 óê   € \        R4      p  V e3   V R8w  d,   \        V \        4      '       g   \        \	        V 4      ^ 4      # ^ RIHp T! 4       '       d   \        # ^ #   \
        \        3 d     L.i ; i)uê   Per-image embed cap for this session; 0 = unlimited.

``vision.max_calls_per_image`` unset (or unparseable) â†’ ``_SUBAGENT_REPEAT_CAP`` inside a
delegated subagent, unlimited for the main agent. An explicit value applies everywhere.
Úmax_calls_per_imageÚ )Ú"is_delegated_child_process_context)
r   r#   r$   r)   r   r&   r%   Úagent.delegation_contextr3   Ú_SUBAGENT_REPEAT_CAP)r,   r3   s     r   Úresolve_repeat_capr6   ;   so   € ô Ð+Ó
,€CðØŠ?˜s bœy´¸CÄ×1FÒ1FÜ”s˜3“x Ó#Ð#õ LÙ#E×#GÒ#GÔÐNÈQÐNøô ”zÐ"ô Ùðús   �5A ÁA2Á1A2c               ó    € V ^8„  d   QhRRRR/# )r   Ú	image_urlr   r   r   )r   s   "r   r   r   K   s   € ÷ 	Gñ 	G˜#ð 	G #ñ 	Gr   c                ó°  € V P                  R4      '       dC   R\        P                  ! V P                  RR4      4      P	                  4       R,          ,           # V P                  R^4      ^ ,          P                  R4      pRV9   d
   RV,           # R	\        \        \        P                  P                  V4      4      P                  4       4      ,           # )
u  Stable identity for an image source: local paths resolve (symlinks, ``~``, ``file://``),
URLs drop their fragment, data URLs hash. Region crops are NOT part of the key â€” the incident
loop alternated full loads and crops of the same files, and both re-embed the image.zdata:zutf-8Úignore:Né    NÚ#zfile://z://zurl:zfile:)Ú
startswithÚhashlibÚsha256ÚencodeÚ	hexdigestÚsplitÚremoveprefixr   r   ÚosÚpathÚ
expanduserÚresolve)r8   Ústrippeds   & r   Ú
_image_keyrI   K   s¥   € ð ×Ñ˜G×$Ò$ØœŸš¨	×(8Ñ(8¸À(Ó(KÓL×VÑVÓXÐY\Õ]Õ]Ð]Ø�‰˜s AÓ& qÕ)×6Ñ6°yÓA€HØ�ÔØ˜Õ Ð Ø”SœœbŸg™g×0Ñ0°Ó:Ó;×CÑCÓEÓFÕFÐFr   c               ó    € V ^8„  d   QhRRRR/# )r   r8   r   r   útuple[str, str]r   )r   s   "r   r   r   W   s   € ÷ Kñ K˜#ð K /ñ Kr   c                ó6   € ^ RI Hp V! RR4      \        V 4      3# )é    )Úget_session_envÚHERMES_SESSION_IDr2   )Úgateway.session_contextrN   rI   )r8   rN   s   & r   Ú
_count_keyrQ   W   s   € Ý7ÙÐ.°Ó3´ZÀ	Ó5JÐJÐJr   c               ó    € V ^8„  d   QhRRRR/# )r   r8   r   r   úOptional[str]r   )r   s   "r   r   r   \   s   € ÷ ñ ˜cð  mñ r   c                ó   € \        4       pV^ 8:  d   R# \        V 4      p\        ;_uu_ 4        \        P	                  V^ 4      pW18  d   \        V4        RRR4       R#  RRR4       \        RX RV R2RR7      #   + '       g   i     L$; i)ap  Reserve one native embed of ``image_url`` for the current session; tool-error JSON when the
per-session cap is already spent, else ``None``. Check and count are ONE lock section: a
parallel tool batch on the same image (the incident's 4 concurrent calls) must not all pass a
check taken before any of them recorded. Callers ``release_embed`` when the embed then fails.NzHvision_analyze refused: this image has already been loaded into context zß time(s) in this session (region crops of the same file count too), and every native load re-sends the full image on each later API call. Answer from what you can already see, or ask the user. (vision.max_calls_per_image = z; 0 = unlimited)F)Úsuccess)r6   rQ   Ú_repeat_lockr	   ÚgetÚ_record_embed_lockedr   )r8   Úcapr   Úcounts   &   r   Úrepeat_refusalr[   \   s‘   € ô
 Ó
€CØ
ˆa„xÙÜ
�YÓ
€Cß	ŽÜ×"Ñ" 3¨Ó*ˆØŒ;Ü  Ô%Ø÷	 
‰à÷ 
ô
 Ø
RÐSXÐRYð Z/ð 03¨eÐ3Cð	Eð ôð ÷ 
�ús   ­)A=Á=B	c               ó    € V ^8„  d   QhRRRR/# )r   r   rK   r   ÚNoner   )r   s   "r   r   r   s   s   € ÷ 7ñ 7˜oð 7°$ñ 7r   c                óØ   € \         P                  V ^ 4      ^,           \         V &   \        \         4      \        8”  d.   \         P	                  \        \        \         4      4      4       KE  R# )rM   N)r	   rW   ÚlenÚ_REPEAT_COUNTS_MAX_KEYSÚpopÚnextÚiter)r   s   &r   rX   rX   s   sI   € Ü(×,Ñ,¨S°!Ó4°qÕ8„N�3Ñä
ŒnÓ
Ô 7Ô
7Ü×Ñœ4¤¤^Ó 4Ó5Ö6ñ 8r   c               ó    € V ^8„  d   QhRRRR/# ©r   r8   r   r   r]   r   )r   s   "r   r   r   z   s   € ÷ 4ñ 4˜Cð 4 Dñ 4r   c                ó„   € \         ;_uu_ 4        \        \        V 4      4       RRR4       R#   + '       g   i     R# ; i)u­   Count one successful native embed of ``image_url`` for the current session (uncapped
sessions only â€” capped ones are counted by the reservation in :func:`repeat_refusal`).N)rV   rX   rQ   )r8   s   &r   Úrecord_embedrg   z   s"   € ÷ 
ŽÜœZ¨	Ó2Ô3÷ 
��Šús   �.®?	c               ó    € V ^8„  d   QhRRRR/# re   r   )r   s   "r   r   r   �   s   € ÷ *ñ *˜Sð * Tñ *r   c                óú   € \        V 4      p\        ;_uu_ 4        \        P                  V^ 4      pV^8”  d   V^,
          \        V&   M\        P	                  VR4       RRR4       R#   + '       g   i     R# ; i)zRGive back a slot reserved by :func:`repeat_refusal` when the embed did not happen.N)rQ   rV   r	   rW   ra   )r8   r   rZ   s   &  r   Úrelease_embedrj   �   sT   € ä
�YÓ
€Cß	ŽÜ×"Ñ" 3¨Ó*ˆØ�1Œ9Ø"'¨!¥)ŒN˜3Òä×Ñ˜s DÔ)÷ 
��Šús   šAA)Á)A:	z&^\[Image attached(?: at)?: (.+?)\]\s*$Úvision_native_turn_imagesr   zContextVar[frozenset[str]]Ú_native_turn_imagesc               ó    € V ^8„  d   QhRRRR/# )r   Úuser_messager   r   zfrozenset[str]r   )r   s   "r   r   r   •   s   € ÷ bñ b Cð b¨Nñ br   c                ó0  € \        V \        4      '       d;   \        ;QJ d    R  V  4       F  '       g   K   RM	  RM! R  V  4       4      '       g   \        4       # RP	                  R V  4       4      p\        R \
        P                  V4       4       4      # )c              3  óz   "  € T F1  p\        V\        4      ;'       d    VP                  R 4      R8H  x € K3  	  R# 5i)Útyper8   N©r#   ÚdictrW   ©Ú.0Úps   & r   Ú	<genexpr>Ú$_native_turn_keys.<locals>.<genexpr>–   s2   é € ð 5ÙFRÀŒ
�1”dÓ×<Ð< §¡ f£°Ñ <Ô<Ãlùs   ‚;ž;TFÚ
c              3  ó¦   "  € T FG  p\        V\        4      '       g   K  VP                  R 4      R8X  g   K3  VP                  RR4      x € KI  	  R# 5i)rq   Útextr2   Nrr   rt   s   & r   rw   rx   š   sB   é € Ðp±¨1Ä
È1Ìd×@SÔ&ÐXY×X]ÑX]Ð^dÓXeÐioÑXoÔ&�Q—U‘U˜6 2×&Ð&³ùs   ‚AŸA·Ac              3  ó‚   "  € T F5  qP                  4       '       g   K  \        VP                  4       4      x € K7  	  R # 5i©N)ÚstriprI   )ru   Úms   & r   rw   rx   ›   s,   é € ÐaÑ4S¨q×W^ÑW^×W`Ô*”Z §¡£	×*Ð*Ó4Sùs   ‚?ž!?)r#   ÚlistÚanyÚ	frozensetÚjoinÚ_NATIVE_HANDLE_REÚfindall)rn   r{   s   & r   Ú_native_turn_keysr†   •   sx   € Ü�l¤D×)Ò)·³ñ 5ÙFRó5··²ñ 5ÙFRó5÷ 2ò 2ô ‹{ÐØ�9‰9Ñp±ÓpÓp€DÜÑaÔ4E×4MÑ4MÈdÔ4SÓaÓaÐar   c               ó    € V ^8„  d   QhRRRR/# )r   rn   r   r   zIterator[None]r   )r   s   "r   r   r   Ÿ   s   € ÷ )ñ ) Sð )¨^ñ )r   c              #  ó²   "  € \         P                  \        V 4      4      p Rx € \         P                  V4       R#   \         P                  T4       i ; i5i)zKScope the images natively attached to ``user_message`` to the running turn.N)rl   Úsetr†   Úreset)rn   Útokens   & r   Únative_turn_imagesrŒ   ž   sB   é € ô  ×#Ñ#Ô$5°lÓ$CÓD€Eð)Ûä×!Ñ! %Ö(øÔ×!Ñ! %Õ(üs   ‚A¢= ¦A½AÁAc               ó$   € V ^8„  d   QhRRRRRR/# )r   r8   r   ÚregionzOptional[list]r   rS   r   )r   s   "r   r   r   ¨   s!   € ÷ ñ  Sð °.ð À]ñ r   c                óŠ   € Vf#   \        V 4      \        P                  4       9  d   R# \        P                  ! RRRRRR/4      # )a	  Text tool result when ``image_url`` already rides the active user turn natively, else
``None``. A native re-embed would put the identical pixels into the same request twice
(the Telegram case in #76411); a ``region`` crop still embeds because it returns new detail.NrU   TÚalready_in_contextÚmessageu¦   This image is already attached natively to the current user message â€” you can see it now. Answer with your built-in vision; pass a `region` to zoom into part of it.)rI   rl   rW   ÚjsonÚdumps)r8   rŽ   s   &&r   Únative_turn_duplicater”   ¨   sL   € ð ÒœZ¨	Ó2Ô:M×:QÑ:QÓ:SÔSÙÜ�:Š:Ø�4Ø˜dØð^ð	ó ð r   i   i   i  @ r}   )/Ú__conditional_annotations__Ú__doc__Ú
__future__r   Ú
contextlibr>   r’   rD   ÚreÚ	threadingÚcontextvarsr   Úpathlibr   Útypingr   r   r   Útools.registryr   r"   r*   r+   r5   r`   r	   Ú__annotations__ÚLockrV   r   r.   r6   rI   rQ   r[   rX   rg   rj   ÚcompileÚ	MULTILINEr„   r‚   rl   r†   ÚcontextmanagerrŒ   r”   )r•   s   @r   Ú<module>r¤      sð   øðôõ #ã Û Û Û 	Û 	Û Ý "Ý ß *Ñ *å %ð )Ð Ø#Ð Ø)Ð ð Ð ØÐ à-/€Ð*Ó /Ø�~Š~Ó€÷õ	NõOõ 	GõKõ
õ.7õ4õ*ð  —J’JÐHÈ"Ï,É,ÓWÐ Ù2<Ð=XÑbkÓbmÔ2nÐ Ð/Ó nõbð ×Ñô)ó ð)÷r   