+
    iHàj/g  ã                  óº  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	H
t
 ^ RIHt ^ RIHt ^ RIHtHtHtHtHtHtHt ]P.                  ! ]4      t]! 0 R`m4      tRatRP;                  R ] 4       4      t]P>                  ! R],           R,           ]P@                  4      t!]P>                  ! R],           R,           ]P@                  4      t"]P>                  ! R]PF                  4      ]P>                  ! R4      3t$R R lt%R R lt&R R lt'/ ](PS                  RbR4      C](PS                  RcR4      Ct*R R lt+R R  lt,R! R" lt-R# R$ lt.R% R& lt/R' R( lt0R) R* lt1R+R,/R- R. llt2R/ R0 lt3R1 R2 lt4R3 R4 lt5RdR5 R6 llt6R7 R8 lt7R9 R: lt8R; R< lt9R= R> lt:R? R@ lt;RA]93RB]:3RC];33t<RD]=RE&   ReR+R,/RF RG lllt>R+R,/RH RI llt?/ ](PS                  RfRJ4      C](PS                  RgRK4      Ct@. RhORQ ]@Pƒ                  4        4       ORiNRjNRkN5tBRR]=RS&   RT RU ltC]! 0 Rlm4      tDRV RW ltERRMR	RMRRLR
RNRRORRP/tFReRX RY lltGRZ R[ ltHR\ R] ltIReR^ R_ lltJ. RmOtKR# )naR  Routing helpers for inbound user-attached images.

``native`` attaches images as OpenAI-style ``image_url`` parts; ``text`` runs
``vision_analyze`` up-front and prepends the lossy description (right for
non-vision models). :func:`decide_image_input_mode` picks once per turn from
``agent.image_input_mode`` (``auto`` | ``native`` | ``text``): in ``auto`` an
explicit ``auxiliary.vision`` backend forces ``text`` even for vision-capable
main models (``native`` is the absolute override); else ``supports_vision``
(config override or catalog) decides. ``vision_analyze`` stays a tool regardless.
)ÚannotationsN)Úsuppress)ÚBytesIO)ÚPath)ÚAnyÚCallableÚDictÚIterableÚListÚOptionalÚTupleú.pngú.jpgú.jpegú.gifú.webpú.bmpÚ|c              #  óB   "  € T F  qP                  R 4      x € K  	  R# 5i)Ú.N)Úlstrip)Ú.0Úes   & Ú8/home/ubuntu/.hermes/hermes-agent/agent/image_routing.pyÚ	<genexpr>r   !   s   é € ÐA±[°Ÿh™h sŸm˜m³[ùó   ‚zB(?<![/:\w.])(?:~/|/|[A-Za-z]:[\\/])(?:[\w.\-]+[\\/])*[\w.\-]+\.(?:z)\bzhttps?://[^\s<>\"']+?\.(?:z)(?:\?[^\s<>\"']*)?z```[^\n]*\n.*?```z	`[^`\n]+`c               ó$   € V ^8„  d   QhRRRRRR/# )é   Úpatternz
re.PatternÚtextÚstrÚreturnúIterable[str]© )Úformats   "r   Ú__annotate__r%   3   s&   € ÷ iñ i :ð i°Sð i¸]ñ ió    c                óÞ   a€ \          UUu. uF9  q"P                  V4       F"  q3P                  4       VP                  4       3NK$  	  K;  	  uppoV3R lV P                  V4       4       # u uppi )zWYield ``pattern`` matches whose start is not inside a fenced block or inline backticks.c              3  óÌ   <a"  € T FX  o\         ;QJ d    V3R  lS 4       F  '       g   K   RM	  RM! V3R  lS 4       4      '       d   KE  SP                  ^ 4      x € KZ  	  R# 5i)c              3  óp   <"  € T F+  w  rVSP                  4       u;8*  ;'       d    V8  Mu x € K-  	  R # 5i©N)Ústart)r   Úsr   Úms   &  €r   r   Ú2_matches_outside_code.<locals>.<genexpr>.<genexpr>6   s.   øé € ÐAgÑafÑY]ÐYZÀ!ÀqÇwÁwÃy×BTÔBTÐST×BTÑBTÓafùs   ƒ36TFN)ÚanyÚgroup)r   r-   Úspanss   &@€r   r   Ú(_matches_outside_code.<locals>.<genexpr>6   s>   ùé € ÐhÑ 6˜1¿c»cÔAgÑafÓAg¿c¿cºcÔAgÑafÓAg×>gŒJˆA�G‰G�A�JˆJÓ 6ùs   „A$”A$«A$ÁA$)Ú_CODE_SPAN_RESÚfinditerr+   Úend)r   r   Úpr-   r1   s   &&  @r   Ú_matches_outside_coder7   3   sS   ø€ å+9ÔT©> aÇ:Á:ÈdÖCS¸a�g‰g‹i˜Ÿ™›Ó!ÑCSÑ!©>ÒT€EÜh × 0Ñ 0°Ô 6ÓhÐhùó Us   ‹?A)c               ó    € V ^8„  d   QhRRRR/# )r   Ú	candidater    r!   úOptional[str]r#   )r$   s   "r   r%   r%   9   s   € ÷ 	ñ 	˜cð 	 mñ 	r&   c                óò   € \         P                  P                  V 4      p \         P                  P                  V4      '       d    \         P                  P	                  V4      # R#   \
         d     R# i ; i)ub  Normalized path when it is a regular file; None otherwise (incl. OSError on pathological input).
The return value is the OS-canonical spelling of the real file (same norm class as
``str(Path(...))``), so callers can compare it against actual paths â€” ``~`` expansion
alone would leave the textual ``/`` separators of the source text in place on Windows.N)ÚosÚpathÚ
expanduserÚisfileÚnormpathÚOSError)r9   Úexpandeds   & r   Ú_existing_filerC   9   s[   € ô
 �w‰w×!Ñ! )Ó,€HðÜ-/¯W©W¯^©^¸H×-EÒ-EŒr�w‰w×Ñ Ó)ÐOÈ4ÐOøÜô Úðús   ¡$A' ÁA' Á%A' Á'A6Á5A6c               ó    € V ^8„  d   QhRRRR/# )r   r   r    r!   ztuple[list[str], list[str]]r#   )r$   s   "r   r%   r%   E   s   € ÷ )ñ )˜Sð )Ð%@ñ )r&   c           
     ó6  € \        V \        4      '       d	   V '       g   . . 3# \        P                  R \	        \
        \        \        V 4      4       4       4      p\        P                  R \        \        V 4       4       4      p\        V4      \        V4      3# )u*  Scan free-form text for image references â†’ ``(local_paths, urls)``, each
ordered and deduplicated. Local paths must exist as files; URLs are not
validated (the provider fetches them). Code spans are skipped so pasted
snippets aren't live attachments (mirrors ``BaseAdapter.extract_local_files``).c              3  ó8   "  € T F  q'       g   K  Vx € K  	  R # 5ir*   r#   )r   r6   s   & r   r   Ú%extract_image_refs.<locals>.<genexpr>L   s   é € ð  ÙYˆaÓ]^�ŠÓYùó   ‚	�
c              3  óB   "  € T F  qP                  R 4      x € K  	  R# 5i)z	.,;:!?)]>N)Úrstrip©r   Úus   & r   r   rG   P   s   é € ÐcÑ8b°1Ÿ™ +×.Ð.Ó8bùr   )
Ú
isinstancer    ÚdictÚfromkeysÚmaprC   r7   Ú_LOCAL_IMAGE_PATH_REÚ_IMAGE_URL_REÚlist)r   Úlocal_pathsÚurlss   &  r   Úextract_image_refsrV   E   s{   € ô
 �dœC× Ò ¯Ø�2ˆvˆÜ—-‘-ñ  Ü”~Ô'<Ô=QÐSWÓ'XÔYó ó €Kô �=‰=ÑcÔ8MÌmÐ]aÔ8bÓcÓc€DÜ�Óœd 4›jÐ(Ð(r&   TFc               ó    € V ^8„  d   QhRRRR/# )r   Úrawr   r!   úOptional[bool]r#   )r$   s   "r   r%   r%   Z   s   € ÷ 	Sñ 	S ð 	S¨ñ 	Sr&   c                ó  € \        V \        4      '       d   V # \        V \        4      '       d   V R9   d   \        V 4      # R# \        V \        4      '       d2   \        P                  V P                  4       P                  4       4      # R# )a4  Strict boolean coercion for capability overrides: real bools, 0/1 and YAML
boolean tokens only; anything else is None so the caller falls through to
models.dev. ``bool("false")`` is True, so a quoted ``supports_vision: "false"``
would otherwise silently enable native routing on a model that can't handle it.N)é    é   )rM   ÚboolÚintr    Ú_BOOL_TOKENSÚgetÚstripÚlower©rX   s   &r   Ú_coerce_capability_boolrd   Z   si   € ô
 �#”t×ÒØˆ
Ü�#”s×ÒØ 6œMŒt�C‹yÐ3¨tÐ3Ü4>¸sÄC×4HÒ4HŒ<×Ñ˜CŸI™I›K×-Ñ-Ó/Ó0ÐRÈdÐRr&   c               ó    € V ^8„  d   QhRRRR/# )r   rX   r   r!   údict[str, Any]r#   )r$   s   "r   r%   r%   f   s   € ÷ 0ñ 0˜ð 0 ñ 0r&   c                ó6   € \        V \        4      '       d   V # / # r*   )rM   rN   rc   s   &r   Ú_dict_or_emptyrh   f   s   € Ü˜S¤$×'Ò'ˆ3Ð/¨RÐ/r&   c               ó    € V ^8„  d   QhRRRR/# ©r   rX   r   r!   r    r#   )r$   s   "r   r%   r%   j   s   € ÷ "ñ "�Cð "˜Cñ "r&   c                óH   € \        T ;'       g    R 4      P                  4       # ©Ú )r    ra   rc   s   &r   Ú
_clean_strrn   j   s   € Üˆs�yˆy�b‹>×ÑÓ!Ð!r&   c               ó    € V ^8„  d   QhRRRR/# )r   Úkeyr    r!   r   r#   )r$   s   "r   r%   r%   n   s   € ÷ ñ �sð ˜sñ r&   c                ól   €  ^ RI Hp V! V 4      pV R8X  d   V# \        V4      #   \         d     R# i ; i)zNContext-local credential source or stripped runtime text; "" when unavailable.©Ú_runtime_main_valueÚapi_keyrm   )Úagent.auxiliary_clientrs   rn   Ú	Exception)rp   rs   Úvalues   &  r   Ú_runtime_mainrx   n   s=   € ðÝ>á# CÓ(ˆØ˜yÔ(ˆuÐ?¬j¸Ó.?Ð?øÜô Úðús   ‚$ ™
$ ¤3²3c               ó$   € V ^8„  d   QhRRRRRR/# )r   Ú
models_cfgr   Úmodelr    r!   rY   r#   )r$   s   "r   r%   r%   y   s&   € ÷ ^ñ ^°ð ^¸Cð ^ÀNñ ^r&   c                óœ   € \        \        V 4      P                  V4      4      p\        VP                  RVP                  R4      4      4      # )zNPer-model ``supports_vision`` (or ``vision`` alias) from a ``models`` mapping.Úsupports_visionÚvision)rh   r`   rd   )rz   r{   Ú	per_models   && r   Ú_model_supports_vision_overrider€   y   s=   € äœ~¨jÓ9×=Ñ=¸eÓDÓE€IÜ" 9§=¡=Ð1BÀIÇMÁMÐRZÓD[Ó#\Ó]Ð]r&   c               ó$   € V ^8„  d   QhRRRRRR/# )r   Úcfgrf   Únamesr"   r!   zIterable[dict[str, Any]]r#   )r$   s   "r   r%   r%      s'   € ÷ Wñ W .ð W¸ð WÐKcñ Wr&   c              #  ór   a"  € \        V 4      pR V 4        F  oV3R lV 4        Rj  x€L
  K  	  R#  L
5i)z°Yield legacy ``custom_providers`` entries matching ``names`` (case-insensitive);
``names`` is the outer loop so list order cannot let a persisted default shadow the live route.c              3  ó\   "  € T F"  qP                  4       P                  4       x € K$  	  R # 5ir*   )ra   rb   )r   Úns   & r   r   Ú+_custom_provider_entries.<locals>.<genexpr>ƒ   s   é € Ð4©e¨—7‘7“9—?‘?×$Ð$«eùs   ‚*,c              3  ó†   <"  € T F6  p\        VP                  R 4      4      P                  4       S8X  g   K2  Vx € K8  	  R# 5i)ÚnameN)rn   r`   rb   )r   r   Úwanteds   & €r   r   r‡   „   s0   øé € ÐV™w˜!¬*°Q·U±U¸6³]Ó*C×*IÑ*IÓ*KÈvÑ*U—A’A›wùs
   ƒ/A·
AN)Ú_custom_provider_list)r‚   rƒ   ÚentriesrŠ   s   && @r   Ú_custom_provider_entriesr�      s2   øé € ô $ CÓ(€GÙ4©eÖ4ˆÜV™wÓV×VÒVó 5ÙVùs   ƒ'7ª5«7c               ó    € V ^8„  d   QhRRRR/# )r   r‚   rf   r!   zlist[dict[str, Any]]r#   )r$   s   "r   r%   r%   ‡   s   € ÷ Tñ T˜~ð TÐ2Fñ Tr&   c                ó²   € V P                  R4      p\        V\        4      '       d+   V Uu. uF  p\        V\        4      '       g   K  VNK  	  up# . # u upi )zSDict entries of the legacy ``custom_providers`` list (empty when absent/malformed).Úcustom_providers)r`   rM   rS   rN   )r‚   rX   r   s   &  r   r‹   r‹   ‡   sF   € à
�'‰'Ð$Ó
%€CÜ6@ÀÄd×6KÒ6K‘sÓ2‘s�!œj¨¬D×1�AˆA‘sÑ2ÐSÐQSÐSùÒ2s   ¬AÁ	AÚrequested_providerrm   c          
     ó,   € V ^8„  d   QhRRRRRRRRRR/# )	r   r‚   úOptional[dict[str, Any]]Úproviderr    r{   r‘   r!   rY   r#   )r$   s   "r   r%   r%   �   sA   € ÷  uñ  uØ	!ð uàð uð ð uð
 ð uð ñ ur&   c          
     óN  a€ \        V \        4      '       g   R# \        V P                  R4      4      p\	        VP                  R4      4      pVe   V# . p\        RW1\        VP                  R4      4      34       F`  pVP                  V4       VP                  R4      '       g   K-  V\        R4      R '       g   KC  VP                  V\        R4      R 4       Kb  	  \        \        P                  V4      4      p\        V P                  R4      4      pV U	u. uF,  p	\        VP                  V	4      4      P                  R4      NK.  	  p
p	T
\        W4       Uu. uF  q»P                  R4      NK  	  up,          p
\        R V3R	 lV
 4        4       R4      # u up	i u upi )
uÅ  Resolve user-declared vision capability from config.yaml; None when unset.

First hit wins: ``model.supports_vision`` â†’ ``providers.<p>.models.<model>``
â†’ legacy ``custom_providers[].models.<model>``. Named custom providers are
rewritten to ``provider="custom"`` at runtime while config keeps the user's
name under ``model.provider``, so the requested, runtime and config
identities are all tried, plus the bare ``<name>`` of any ``custom:<name>``.
Nr{   r}   r”   úcustom:Ú	providersÚmodelsc              3  ó0   "  € T F  qf   K  Vx € K  	  R # 5ir*   r#   ©r   Úvs   & r   r   Ú,_supports_vision_override.<locals>.<genexpr>­   s   é € ÐmÑ[�q—’Ó[ùs   ‚Œ
c              3  ó<   <"  € T F  p\        VS4      x € K  	  R # 5ir*   )r€   )r   r-   r{   s   & €r   r   rœ   ­   s   øé € Ð[ÑPZÈ1Ô<¸QÀ×FÐFÓPZùs   ƒ)rM   rN   rh   r`   rd   Úfilterrn   ÚappendÚ
startswithÚlenrS   rO   r�   Únext)r‚   r”   r{   r‘   Ú	model_cfgÚtopÚ
candidatesr9   Úproviders_cfgr6   Ú
model_mapsÚentrys   &&f$        r   Ú_supports_vision_overrider©   �   s]  ø€ ô �cœ4× Ò ÙÜ˜sŸw™w wÓ/Ó0€IÜ
! )§-¡-Ð0AÓ"BÓ
C€CØ
‚Øˆ
à€JÜ˜DÐ#5ÄÈIÏMÉMÐZdÓLeÓAfÐ"gÖhˆ	Ø×Ñ˜)Ô$Ø×Ñ 	×*Ô*¨y¼¸Y»¸×/IÑ/IØ×Ñ˜i¬¨I«¨Ð8Ö9ñ iô ”d—m‘m JÓ/Ó0€Jä" 3§7¡7¨;Ó#7Ó8€MÙNXÓYÉjÈ”. ×!2Ñ!2°1Ó!5Ó6×:Ñ:¸8ÖDÉj€JÐYØÔ4LÈSÔ4]Ó^Ñ4]¨5—9‘9˜XÖ&Ñ4]Ñ^Õ^€JÜÑmÔ[ÑPZÔ[ÓmÐosÓtÐtùò ZùÚ^s   Ä2FÅF"c          
     ó,   € V ^8„  d   QhRRRRRRRRRR/# )	r   r‚   r“   r”   r    rp   Ú
runtime_okzCallable[[str], bool]r!   r#   )r$   s   "r   r%   r%   °   sA   € ÷ &Qñ &QØ	!ð&Qàð&Qð 
ð&Qð
 &ð&Qð 	ñ&Qr&   c          	     ó¨  a€ \        S4      pSR8X  d(   ^ RIHp \        V4      '       d	   V! V4      # V! V4      pV'       d   V! V4      '       d   V# \	        V \
        4      '       g   R# \        V P                  R4      4      p\        VP                  S4      4      pV'       d   V# \        4       p\        RV\        VP                  R4      4      34       Ff  p	VP                  V	4       TP                  V	P                  4       P                  R4      '       d   V	P                  R^4      ^,          MRV	 24       Kh  	  V U
u0 uF  qªP                  4       kK  	  pp
\        V P                  R	4      4      p\        VP                  V4       Uu. uF  p\	        V\
        4      '       g   K  VNK  	  ppT\!        V 4       Uu. uFS  p\        VP                  R
4      4      V9   g0   \        VP                  R
4      4      P                  4       V9   g   KQ  VNKU  	  up,          p\#        R V3R lV 4        4       R4      # u up
i u upi u upi )u,  ``base_url`` / ``api_key`` of the active inference provider. Order: runtime
value (when ``runtime_ok`` accepts it) â†’ ``model.<key>`` â†’ ``providers.<name>.<key>``
â†’ ``custom_providers[].<key>``, ``<name>`` covering the provider and
``model.provider`` in both bare and ``custom:``-prefixed forms.rt   )Úmaterialize_probe_api_keyrm   r{   Nr”   r–   Ú:r—   r‰   c              3  ó8   "  € T F  q'       g   K  Vx € K  	  R # 5ir*   r#   rš   s   & r   r   Ú+_resolve_inference_value.<locals>.<genexpr>Ö   s   é € ÐKÑE�qË—’ÓEùrH   c              3  óX   <"  € T F  p\        VP                  S4      4      x € K!  	  R # 5ir*   )rn   r`   )r   r   rp   s   & €r   r   r°   Ö   s!   øé € ÐE¹W¸œZ¨¯©¨c«
×3Ð3»Wùs   ƒ'*)rx   Úagent.command_token_sourcer­   ÚcallablerM   rN   rh   r`   rn   Úsetrž   Úaddrb   r    ÚsplitrP   r‹   r¢   )r‚   r”   rp   r«   Úruntimer­   r£   rw   rƒ   r6   r†   Úloweredr¦   r   rŒ   s   &&f$           r   Ú_resolve_inference_valuer¹   °   sÞ  ø€ ô ˜CÓ €Gà
ˆiÔÝHÜ�G×ÒÙ,¨WÓ5Ð5Ù+¨GÓ4ˆß‘:˜g×&Ò&ØˆÜ�cœ4× Ò ÙÜ˜sŸw™w wÓ/Ó0€IÜ�y—}‘} SÓ)Ó*€EßØˆä“e€EÜ�D˜8¤Z°	·±¸jÓ0IÓ%JÐKÖLˆØ�	‰	�!ŒØ�	‰	¨¯©«	×(<Ñ(<¸Y×(GÒ(G�!—'‘'˜#˜q“/ !Ö$ÈwÐWXÐVYÈ]Ö[ñ Mñ #(Ó(¡%˜Q�w‰wŽy¡%€GÐ(Ü" 3§7¡7¨;Ó#7Ó8€MÜ˜m×/Ñ/°Ô7ÓOÑ7�Q¼:ÀaÌ×;N�qˆqÑ7€GÐOØÜ(¨Ô-óÙ-ˆaÜ�a—e‘e˜F“mÓ$¨Ô-´¸A¿E¹EÀ&»MÓ1J×1PÑ1PÓ1RÐV]Ñ1]÷ 	
ˆÑ-ñõ €Gô ÑKÔE¹WÔEÓKÈRÓPÐPùò )ùâOùòs   ÅIÆI
Æ0I
ÇAIÈIc               ó$   € V ^8„  d   QhRRRRRR/# ©r   r‚   r“   r”   r    r!   r#   )r$   s   "r   r%   r%   Ù   s#   € ÷ ñ Ð%=ð Èð ÐQTñ r&   c                óZ   a€ \        V4      P                  4       o\        WRV3R lR7      # )zœBest-effort base URL for the active inference provider; the runtime value is
only trusted when it belongs to the requested provider (or none was requested).Úbase_urlc                óZ   <€ S'       * ;'       g    S\        R 4      P                  4       8H  # )r”   )rx   rb   )Ú_Ú	requesteds   &€r   Ú<lambda>Ú-_resolve_inference_base_url.<locals>.<lambda>ß   s%   ø€  œ]×\Ð\¨i¼=ÈÓ;T×;ZÑ;ZÓ;\Ñ.\Ð\r&   ©r«   )rn   rb   r¹   )r‚   r”   rÀ   s   &&@r   Ú_resolve_inference_base_urlrÄ   Ù   s-   ø€ ô ˜8Ó$×*Ñ*Ó,€IÜ#Ø�zÜ\ôð r&   c               ó$   € V ^8„  d   QhRRRRRR/# r»   r#   )r$   s   "r   r%   r%   ã   s(   € ÷ Yñ YÐ$<ð YÈð YÐPSñ Yr&   c                ó    € \        WRR R7      # )a·  Best-effort API key, resolved like :func:`_resolve_inference_base_url` so it
matches the base URL actually probed; otherwise the local server-type probe hits
a keyed remote endpoint without Authorization and sprays 401s on every image turn.

Mirrors :func:`_resolve_inference_base_url`'s resolution order (runtime value, then ``model.api_key``,
then the providers blocks) so the key matches the base URL actually being probed. See #89863.
rt   c                ó   € R # )Tr#   )r¿   s   &r   rÁ   Ú,_resolve_inference_api_key.<locals>.<lambda>ë   s   € ÑSWr&   rÃ   )r¹   )r‚   r”   s   &&r   Ú_resolve_inference_api_keyrÉ   ã   s   € ô $ C°9ÉÔXÐXr&   c               ó(   € V ^8„  d   QhRRRRRRRR/# )r   r”   r    r½   rt   r!   r]   r#   )r$   s   "r   r%   r%   î   s)   € ÷ ñ ¨#ð ¸ð Àsð ÐTXñ r&   c                óÖ   € \        V 4      P                  4       R8X  d   R# V'       g   R#  ^ RIHpHp \        V! V4      4      ;'       d    V! WR7      R8H  #   \         d     R# i ; i)a  True when the active provider likely fronts a local Ollama server. Fingerprint
probing is only valid for LOCAL endpoints: remote OpenAI-compatible APIs (sglang,
vLLM) expose Ollama-compat routes that can misidentify, and probing them without
an api_key returns 401 on every leg.ÚollamaTF)Údetect_local_server_typeÚis_local_endpoint©rt   )rn   rb   Úagent.model_metadatarÍ   rÎ   r]   rv   )r”   r½   rt   rÍ   rÎ   s   &&&  r   Ú_should_probe_ollama_visionrÑ   î   sd   € ô
 �(Ó×!Ñ!Ó# xÔ/ÙßÙðßTô Ñ% hÓ/Ó0×tÐtÑ5MÈhÔ5hÐltÑ5tÐtøÜô Úðús   ¬A ÁA ÁA(Á'A(c               ó    € V ^8„  d   QhRRRR/# rj   r#   )r$   s   "r   r%   r%      s   € ÷ 4ñ 4�cð 4˜cñ 4r&   c                óŒ   € \        V \        4      '       d   V P                  4       P                  4       MRpV\        9   d   V# R# )zHNormalize a config value into one of the valid modes (default ``auto``).rm   Úauto)rM   r    ra   rb   Ú_VALID_MODES)rX   Úmodes   & r   Ú_coerce_moder×      s6   € ä",¨S´#×"6Ò"6ˆ3�9‰9‹;×ÑÔ¸B€DØœ<Ô'ˆ4Ð3¨VÐ3r&   c               ó    € V ^8„  d   QhRRRR/# )r   r‚   r“   r!   r]   r#   )r$   s   "r   r%   r%     s   € ÷ 	ñ 	Ð'?ð 	ÀDñ 	r&   c                óš  € \        \        \        V 4      P                  R4      4      P                  R4      4      p\        V4      ;'       d    \        VP                  R4      4      P	                  4       R9   ;'       dG    \        VP                  R4      4      '       * ;'       d     \        VP                  R4      4      '       * '       * # )uæ   True when the user configured a specific ``auxiliary.vision`` backend â€” the
de-facto image route in ``auto`` mode even when the main model has native vision.
``auto``/empty provider with no model and no base_url is not explicit.Ú	auxiliaryr~   r”   r{   r½   >   rm   rÔ   )rh   r`   r]   rn   rb   )r‚   r~   s   & r   Ú_explicit_aux_vision_overriderÛ     s¥   € ô œN¬>¸#Ó+>×+BÑ+BÀ;Ó+OÓP×TÑTÐU]Ó^Ó_€FÜ�‹<÷ ð Ü�6—:‘:˜jÓ)Ó*×0Ñ0Ó2°lÑB÷ 	3ð 	3Ü˜6Ÿ:™: gÓ.Ó/Ô/÷	3ð 	3ä˜6Ÿ:™: jÓ1Ó2Ô2ôð r&   c               ó(   € V ^8„  d   QhRRRRRRRR/# ©r   r”   r    r{   r‚   r“   r!   rY   r#   )r$   s   "r   r%   r%     s0   € ÷ Eñ E Sð E°ð EÐ;Sð EÐXfñ Er&   c                ón   € ^ RI HpHp T! T \        W 4      ;'       g    R4      pV'       d	   V! V4      # R# )a  Managed local runtime verdict: the server receiving the image is the authority
on whether it can see (its /props reports modalities). Cloud catalogs have never
heard of a local GGUF, so without this every local model reads as text-only and
screenshots detour to a cloud auxiliary.)Úis_managed_providerÚmanaged_model_supports_visionrm   N)Ú%hermes_cli.local_runtime.capabilitiesrß   rà   rÄ   )r”   r{   r‚   rß   rà   Úmanageds   &&&   r   Ú_probe_managed_runtimerã     s6   € ÷
 iá! (Ô,GÈÓ,V×,\Ð,\ÐZ\Ó]€Gß3:Ñ(¨Ó/ÐDÀÐDr&   c               ó(   € V ^8„  d   QhRRRRRRRR/# rÝ   r#   )r$   s   "r   r%   r%     s*   € ÷ :ñ : ð :¨Cð :Ð6Nð :ÐSañ :r&   c                ó¼   € ^ RI Hp T ;'       g    RP                  4       P                  4       R8X  d   ^ RIHp V! V4      pV! WRR7      pVf   R# VP                  # )u  models.dev catalog verdict. ``allow_network=True`` on purpose: this runs only
when an image needs routing, and the text-only-main guard depends on catalog
data â€” a cold cache returning "unknown" would reintroduce attempting the call.
The fetch is cached (4h TTL) and backoff-limited.)Úget_model_capabilitiesrm   zopenai-codex)Ú"strip_codex_context_variant_suffixT)Úallow_networkN)Úagent.models_devræ   ra   rb   rÐ   rç   r}   )r”   r{   r‚   ræ   rç   Úcapss   &&&   r   Ú_probe_models_devrë     sZ   € õ
 8ð 	�ˆ�B×ÑÓ×%Ñ%Ó'¨>Ô9õ 	Lá2°5Ó9ˆÙ! (ÀÔF€DØ’<ˆ4Ð9 T×%9Ñ%9Ð9r&   c               ó(   € V ^8„  d   QhRRRRRRRR/# rÝ   r#   )r$   s   "r   r%   r%   4  s/   € ÷ 
Jñ 
J˜Cð 
J¨ð 
JÐ2Jð 
JÈ~ñ 
Jr&   c                óÈ   € \        W 4      pV'       g!   \        V 4      P                  4       R8X  d   Rp\        W 4      p\	        WVR7      '       g   R# ^ RIHp V! WVR7      # )z[Ollama ``/api/show`` verdict for local endpoints (see :func:`_should_probe_ollama_vision`).rÌ   zhttp://localhost:11434/v1rÏ   N)Úquery_ollama_supports_vision)rÄ   rn   rb   rÉ   rÑ   rÐ   rî   )r”   r{   r‚   r½   rt   rî   s   &&&   r   Ú_probe_ollamarï   4  sS   € ä*¨3Ó9€Hßœ
 8Ó,×2Ñ2Ó4¸Ô@Ø.ˆÜ(¨Ó7€GÜ& xÀ7×KÓKÙÝAá'¨ÀÔIÐIr&   zmanaged-runtime caps lookupzcaps lookupzollama vision probez5tuple[tuple[str, Callable[..., Optional[bool]]], ...]Ú_VISION_PROBESc          
     ó,   € V ^8„  d   QhRRRRRRRRRR/# )	r   r”   r    r{   r‚   r“   r‘   r!   rY   r#   )r$   s   "r   r%   r%   J  s:   € ÷ *ñ *Øð*àð*ð 
"ð*ð
 ð*ð ñ*r&   c          	     ó´  € V'       gZ   \        R4      P                  4       \        V 4      P                  4       8X  d%   \        R4      \        V4      8X  d   \        R4      p\        W WR7      pVe   V# V '       d	   V'       g   R# \         F  w  rV V! WV4      pTf   K  Tu # 	  R#   \
         d#   p\        P                  RYPY4        Rp?KE  Rp?ii ; i)uW  Return True/False if vision capability can be resolved, None if unknown.

Order: config ``supports_vision`` override â†’ :data:`_VISION_PROBES`
(managed local runtime â†’ models.dev catalog â†’ Ollama probe). A plugin's
per-model ``ProviderProfile.model_capabilities`` reaches this through the
catalog probe. The provider-wide ``ProviderProfile.supports_vision`` flag is
deliberately NOT consulted: it declares that tool-result messages may carry
images (``tools.vision_tools``), not that every model on the provider can see
user attachments â€” relays such as ``router`` set it for mixed catalogs.
r”   r{   r‘   )r‘   Nu)   image_routing: %s failed for %s:%s â€” %s)rx   rb   rn   r©   rð   rv   ÚloggerÚdebug)	r”   r{   r‚   r‘   ÚoverrideÚlabelÚprobeÚverdictÚexcs	   &&&$     r   Ú_lookup_supports_visionrú   J  s¾   € ÷, Ü˜*Ó%×+Ñ+Ó-´¸HÓ1E×1KÑ1KÓ1MÔMÜ˜'Ó"¤j°Ó&7Ô7ä*Ð+?Ó@Ðä(¨¸Ôe€HØÒØˆßŸ5Ùç&‰ˆð	Ù˜H¨SÓ1ˆGð ÔØŠNñ 'ñ øô ô 	Ü�L‰LÐDÀeÐW\ÔbÝûð	ús   Â	B*Â*CÂ5CÃCc          
     ó,   € V ^8„  d   QhRRRRRRRRRR/# )r   r”   r    r{   r‚   r“   r‘   r!   r#   )r$   s   "r   r%   r%   w  sA   € ÷ bñ bØðbàðbð 
"ðbð
 ðbð 	ñbr&   c               óö   € \        \        \        V4      P                  R4      4      P                  R4      4      pVR8w  d   V# \        V4      '       d   R# V'       d   RV/M/ p\	        WV3/ VB RJ d   R# R# )zœReturn ``"native"`` or ``"text"`` for the given turn (``cfg`` None behaves as
auto; ``requested_provider`` is the identity before runtime canonicalization).ÚagentÚimage_input_moderÔ   r   r‘   TÚnative)r×   rh   r`   rÛ   rú   )r”   r{   r‚   r‘   Úmode_cfgÚextras   &&&$  r   Údecide_image_input_moder  w  s{   € ô œN¬>¸#Ó+>×+BÑ+BÀ7Ó+KÓL×PÑPÐQcÓdÓe€HØ�6ÔØˆÜ$ S×)Ò)Ùç:LÐ!Ð#5Ñ6ÐRT€EÜ.¨xÀÑMÀuÑMÐQUÓUˆ8ÐaÐ[aÐar&   z
image/avifz
image/heicú	image/pngú
image/jpegú	image/gifú
image/webpú	image/bmpc              #  ó6   "  € T F  w  rR^V33V3x € K  	  R# 5i)é   N)r	  s   ftypr#   )r   ÚbrandÚmimes   &  r   r   r   �  s"   é € ÐQÑ<P©[¨Uˆ�q˜%�jÐ! 4Õ(Ó<Pùs   ‚z5tuple[tuple[tuple[tuple[int, bytes], ...], str], ...]Ú_MAGICc               ó    € V ^8„  d   QhRRRR/# )r   rX   Úbytesr!   r:   r#   )r$   s   "r   r%   r%   £  s   € ÷ 	añ 	a ð 	a¨-ñ 	ar&   c                óL  a € S '       g   R# \          FI  w  r\        ;QJ d    V 3R lV 4       F  '       d   K   RM	  RM! V 3R lV 4       4      '       g   KG  Vu # 	  S R,          P                  4       P                  4       pVP	                  R4      '       d
   RV9   d   R# R# )	z9Detect image MIME from magic bytes; None if unrecognised.Nc              3  óV   <"  € T F  w  rSW\        V4      ,            V8H  x € K   	  R # 5ir*   )r¡   )r   ÚoffÚsigrX   s   &  €r   r   Ú)_sniff_mime_from_bytes.<locals>.<genexpr>¨  s%   øé € ÐI¹j±(°#ˆs�3œS ›X•~Ð&¨#Ö-»jùs   ƒ&)FT:Ni   Nó   <svgzimage/svg+xml)s   <?xmlr  )r  Úallr   rb   r    )rX   Ú
conditionsr  Úheads   f   r   Ú_sniff_mime_from_bytesr  £  s{   ø€ çÙß"Ñˆ
ß‹3ÔI¹jÓI�3�3Š3ÔI¹jÓI×IÔIØŠKñ #ð ˆt�9×ÑÓ×#Ñ#Ó%€DØ"Ÿo™oÐ.A×BÒBÀwÐRVÄˆ?Ð`Ð\`Ð`r&   c               ó    € V ^8„  d   QhRRRR/# )r   rX   r  r!   úOptional[bytes]r#   )r$   s   "r   r%   r%   ¶  s   € ÷ ñ ˜5ð  _ñ r&   c                óÜ  €  ^ RI Hp \        \        4      ;_uu_ 4        ^ RIpTP                  4        RRR4       \        \        4      ;_uu_ 4        ^ RI	pRRR4        TP                  \        T 4      4      ;_uu_ 4       pTP                  R	9  d   TP                  R4      p\        4       pTP                  TRRR7       TP                  4       uuRRR4       #   \         d    \        P	                  R4        R# i ; i  + '       g   i     LÙ; i  + '       g   i     LÈ; i  + '       g   i     R# ; i  \         d"   p\        P	                  RT4        Rp?R# Rp?ii ; i)
zêDecode with Pillow and re-encode as PNG; None when impossible. HEIC/HEIF and
AVIF need optional Pillow plugins, registered on demand; a missing plugin just
looks like "can't decode" so the caller skips the image and the turn proceeds.)ÚImagez°image_routing: Pillow not installed; cannot transcode non-standard image format to PNG. Run `hermes pm repair` to restore Pillow, or convert the image to PNG before sending it.NÚRGBAÚPNGF)r$   Úoptimizez<image_routing: Pillow could not transcode image to PNG -- %s>   ÚLÚPÚLAÚRGBr  )ÚPILr  ÚImportErrorró   Úinfor   rv   Úpillow_heifÚregister_heif_openerÚpillow_avifÚopenr   rÖ   ÚconvertÚsaveÚgetvalue)rX   r  r'  r)  ÚimÚbufrù   s   &      r   Ú_transcode_to_pngr0  ¶  s  € ðÝô 
”)×	Õ	Ûà×(Ñ(Ô*÷ 
ô 
”)×	Õ	Û÷ 
ð
Ø�Z‰Zœ ›×%Ô%¨à�w‰wÐ=Ô=Ø—Z‘Z Ó'�Ü“)ˆCØ�G‰G�C °ˆGÔ6Ø—<‘<“>÷ &Ò%øô ô Ü�‰ð=ô	
ò
 ðú÷ 
×	ú÷ 
×	ú÷ &×%Ð%ûô ô Ü�‰ÐRÐTWÔXÝûðús_   ‚C ŸDÁDÁ!"D? ÂAD+Ã
D? Ã DÄDÄD	ÄD(	Ä+D<	Ä6D? Ä<D? Ä?E+Å
E&Å&E+c               ó$   € V ^8„  d   QhRRRRRR/# )r   r=   r   rX   r  r!   r    r#   )r$   s   "r   r%   r%   Ü  s&   € ÷ @ñ @�dð @ ð @¸Cñ @r&   c                ó"  € Ve   \        V4      MRpT;'       g'    \        P                  ! \        V 4      4      ^ ,          pV'       d   VP	                  R4      '       d   V# \
        P                  V P                  P                  4       R4      # )uY   Image MIME for *path*: magic bytes (authoritative) â†’ ``mimetypes`` â†’ suffix â†’ jpeg.Nzimage/r  )	r  Ú	mimetypesÚ
guess_typer    r    Ú_SUFFIX_MIMESr`   Úsuffixrb   )r=   rX   Úsniffedr  s   &&  r   Ú_guess_mimer8  Ü  sj   € à-0ª_Ô$ SÔ)À$€GØ×8Ð8”i×*Ò*¬3¨t«9Ó5°aÕ8€Dß�—‘ ×)Ò)Øˆä×Ñ˜TŸ[™[×.Ñ.Ó0°,Ó?Ð?r&   c               ó   € V ^8„  d   QhRR/# )r   r!   Ú	frozensetr#   )r$   s   "r   r%   r%   æ  s   € ÷ (ñ (˜ñ (r&   c                 óà   €  ^ RI Hp  ^ RIHpHp T! \        V ! R4      ;'       g    R4      \        V ! R4      ;'       g    R4      4      '       d   V#  \        #   \         d	     \        # i ; i)uæ   Provider-accepted MIME set for the current main runtime. The managed local
server decodes fewer formats (no WebP â€” and a WebP part fails SILENTLY: the model
confabulates a description), so its narrower set transcodes those here.rr   )ÚACCEPTED_IMAGE_MIMESrß   r”   rm   r½   )ru   rs   rá   r<  rß   r    rv   Ú_UNIVERSALLY_SUPPORTED_MIMES)rs   r<  rß   s      r   Ú_accepted_mimesr>  æ  sp   € ðÝ>ßcáœsÑ#6°zÓ#B×#HÐ#HÀbÓIÌ3ÑObÐcmÓOn×OtÐOtÐrtÓKu×vÒvØ'Ð'ð wô (Ð'øô ô ØÜ'Ð'ðús"   ‚#A ¦A Á A ÁA ÁA-Á,A-c               ó    € V ^8„  d   QhRRRR/# )r   r=   r   r!   r:   r#   )r$   s   "r   r%   r%   õ  s   € ÷ Iñ I˜Dð I ]ñ Ir&   c                óJ  €  ^ RI Hp V! \        V 4      4        T P                  4       p\        YR7      pT\        4       9  dL   \        T4      ;pf   \        P                  RY4       R# \        P                  RT P                  T4       TRrCR	T R
\        P                  ! T4      P                  R4       2#   \         d"   p\        P                  RY4        Rp?R# Rp?i\         d     LÙi ; i  \         d"   p\        P                  RY4        Rp?R# Rp?ii ; i)u2  Encode a local image as a base64 data URL at native size (the agent retry
loop shrinks on rejection, so lenient providers pay no silent quality tax);
MIMEs outside the accepted set are transcoded to PNG. None when unreadable,
blocked by the read guard, or untranscodable â€” the caller reports ``skipped``.)Úraise_if_read_blockedz6image_routing: blocked local image attachment %s -- %sNu'   image_routing: failed to read %s â€” %src   z‚image_routing: %s is %s which is not accepted by the active provider and could not be transcoded to PNG; skipping this attachment.zIimage_routing: transcoded %s (%s) -> image/png for provider compatibilityr  zdata:z;base64,Úascii)Úagent.file_safetyrA  r    Ú
ValueErrorró   Úwarningrv   Ú
read_bytesr8  r>  r0  r&  r‰   Úbase64Ú	b64encodeÚdecode)r=   rA  rù   rX   r  Ú
transcodeds   &     r   Ú_file_to_data_urlrK  õ  s  € ð
Ý;áœc $›iÔ(ðØ�o‰oÓˆô �tÔ%€DØ”?Ó$Ô$Ü+¨CÓ0Ð0ˆJÒ9Ü�N‰NðPØQUôñ Ü�‰Ð_Ðae×ajÑajÐlpÔqØ ˆTØ�4�&˜¤×!1Ò!1°#Ó!6×!=Ñ!=¸gÓ!FÐ GÐHÐHøô) ô Ü�‰ÐOÐQUÔ[ÝûÜô Ùðûô ô Ü�‰Ð@À$ÔLÝûðús:   ‚B; šC6 Â;C3ÃC"Ã"C3Ã/C3Ã2C3Ã6D"ÄDÄD"c               ó(   € V ^8„  d   QhRRRRRRRR/# )	r   Ú	user_textr    Úimage_pathsz	list[str]Ú
image_urlszOptional[list[str]]r!   z&tuple[list[dict[str, Any]], list[str]]r#   )r$   s   "r   r%   r%     s6   € ÷ Lñ LØðLàðLð $ðLð ,ñ	Lr&   c           	     ó´  € . p. pV F‚  p\        V4      pVP                  4       '       d"   VP                  4       '       d   \        V4      MRpV'       d   VP	                  VRV R234       Kh  VP	                  \        V4      4       K„  	  TR T;'       g    .  4        Uu. uF  qˆ'       g   K  VRV R23NK  	  up,          pT ;'       g    RP                  4       p	V'       g   V	'       d
   RRRV	/.V3# . V3# T	;'       g    R	 R
2RP                  R V 4       4      ,           p
V UUu. uF  w  r‹RRRRV//NK  	  pppRRRV
/.VOV3# u upi u uppi )u   Build an OpenAI-style ``content`` list for a user turn.

Local paths become base64 ``data:`` URLs; remote URLs pass through verbatim.
When any image attaches, one text part combines the caption (or a neutral
default) with a ``[Image attached at: <path>]`` / ``[Image attached: <url>]``
hint per image â€” a string handle for tools taking an image path/URL, mirroring
``Runner._enrich_message_with_vision``. Returns ``(content_parts, skipped)``;
``skipped`` holds unreadable local paths (URLs are never skipped).
Nz[Image attached at: Ú]c              3  óT   "  € T F  q;'       g    R P                  4       x € K   	  R# 5i)rm   N)ra   rK   s   & r   r   Ú-build_native_content_parts.<locals>.<genexpr>,  s    é € Ð8eÑTdÈq¿'¸'¸r¿¹×9JÐ9JÓTdùs   ‚(�(z[Image attached: rm   Útyper   zWhat do you see in this image?z

Ú
c              3  ó*   "  € T F	  w  rVx € K  	  R # 5ir*   r#   )r   r¿   Úhs   &  r   r   rS  1  s   é € ÐQiÑ`hÑX\ÐXYÕRSÓ`hùs   ‚Ú	image_urlÚurl)r   ÚexistsÚis_filerK  rŸ   r    ra   Újoin)rM  rN  rO  ÚskippedÚattachedÚraw_pathr6   Údata_urlrL   r   Úcombined_textr¿   Úimage_partss   &&&          r   Úbuild_native_content_partsrc    se  € ð €GØ&(€HÛˆÜ�‹NˆØ+,¯8©8¯:ª:¸!¿)¹)¿+º+Ô$ QÔ'È4ˆßØ�O‰O˜XÐ)=¸h¸ZÀqÐ'IÐJÖKà�N‰Nœ3˜x›=Ö)ñ  ð Ñ8eÐT^×TdÐTdÐbdÐTdÔ8eÓkÑ8e°1ÓijÔ.�!Ð(¨¨¨1Ð-Ó.Ñ8eÑkÕk€Hà�OˆO˜×"Ñ"Ó$€Dßß48�&˜& &¨$Ð/Ð0À7ÐJÐJ¸bÀ7ÐJÐJØ×?Ð?Ð?Ð@ÀÐEÈÏ	É	ÑQiÑ`hÓQiÓHiÕi€MÙNVÔWÉhÁdÀa�F˜K¨°u¸a°jÓAÉh€KÑWØ�V˜V ]Ð3ÐB°kÐBÀGÐKÐKùò lùó Xs   Â#	EÂ1EÄ.E>   rÔ   r   rÿ   )	r   r   r   r   r   r   z.tiffz.tifz.heic)ÚtrueÚyesÚonÚ1)ÚfalseÚnor  Ú0rl   r*   )s   avifs   avis)s   heics   heixs   hevcs   hevxs   mif1s   msf1s   heims   heis))))r[   s   ‰PNG

r  )))r[   s   ÿØÿr  )))r[   s   GIF87ar  )))r[   s   GIF89ar  )))r[   s   RIFF)é   s   WEBPr  )))r[   s   BMr  )))r[   s   II* ú
image/tiff)))r[   s   MM *rl  )))r[   s      zimage/x-icon>   r  r  r  r  )rc  r  rV   )LÚ__conditional_annotations__Ú__doc__Ú
__future__r   rG  Úloggingr3  r<   ÚreÚ
contextlibr   Úior   Úpathlibr   Útypingr   r   r   r	   r
   r   r   Ú	getLoggerÚ__name__ró   r:  rÕ   Ú_IMAGE_EXTSr\  Ú_IMAGE_EXT_PATTERNÚcompileÚ
IGNORECASErQ   rR   ÚDOTALLr3   r7   rC   rV   rN   rO   r_   rd   rh   rn   rx   r€   r�   r‹   r©   r¹   rÄ   rÉ   rÑ   r×   rÛ   rã   rë   rï   rð   Ú__annotations__rú   r  Ú_FTYP_BRANDSÚitemsr  r  r=  r0  r5  r8  r>  rK  rc  Ú__all__)rm  s   @r   Ú<module>r�     s»  øðô	õ #ã Û Û Û 	Û 	Ý Ý Ý ß G× GÑ Gà	×	Ò	˜8Ó	$€ñ Ò3Ó4€ð
 [€Ø—X‘XÑA±[ÓAÓAÐ ð —z’zØIØõàõð ‡M�Mó	Ð ð —
’
Ø!Ð$6Õ6Ð9OÕOÐQS×Q^ÑQ^ó€ð —*’*Ð1°2·9±9Ó=¸r¿zºzÈ,Ó?WÐX€õiõ	õ)ðØ
‡m�mÐ.°Ó5ðà
‡m�mÐ/°Ó7ð€õ	Sõ0õ"õõ^õWõTð uð
 !÷ uõF&QõRõY÷õ$4õ	õEõ:õ.
Jð  #Ð$:Ð;ØÐ%Ð&Ø˜MÐ*ðI€ÐEó ñ*ð
 !÷*ð *ðZbð
 !÷bð8Ø
‡m�mÐ&¨Ó5ðà
‡m�mÐ\Ð^jÓkð€ò	Añ R¸L×<NÑ<NÔ<PÓQð	Að 'ð	Að )Kð	Að 2ñ	A€Ð=ó 	õ	añ   )Ò)_Ó`Ð õðB ˆL˜' <°¸Ø
ˆK˜ ,°¸ð€÷@õ(õI÷@LòB Z‚r&   