Ë
    ãß²jÊÒ  ã                   ó�  — U d Z ddlZddlZddlZddlmZ ddlmZ ddlZddl	Z	ddl
Z
ddlmZ ddlmZmZmZmZmZmZ ddlmZ ddlZdaeed<   daeed	<   d°d„ZddlmZ ddlmZ ddlm Z  ddl!m"Z#m$Z%m&Z'm(Z)m*Z+m,Z- ddl.m/Z/m0Z0m1Z1m2Z2m3Z3m4Z4m5Z5  ejl                  e7«      Z8 edd¬«      Z9ddœde:fd„Z;d±de:de:fd„Z< e<dde=«      Z>e>€dZ>dZ?d
e@fd„ZAd
e@fd„ZB eB«       ZC eeCd ¬!«      ZDd"„ ZEd#e:d
eFfd$„ZGd%eHd
eFfd&„ZId'ZJd(„ ZKd#e:d)ed*e@d+e:d,e:d-e@d.e=d/eFd
efd0„ZLd²d1e:d)ed*e@d
efd2„ZMd±d3ed4ee:   d
e:fd5„ZNd6ZOd7ZPd8ZQd9ZRd%eHd
eFfd:„ZSd;eeT   d<eeT   d
ee:   fd=„ZUd>„ ZVdeQddd?fd3ed4ee:   d@e@dAee@   dBeeT   dCeFd
e:fdD„ZW eXh dE£«      ZY eXh dF£«      ZZd³dGe:dHe:d
eFfdI„Z[dGe:dHe:d
eFfdJ„Z\dGe:dHe:dKeee:ef      d
eFfdL„Z]d
eFfdM„Z^	 d±d1e:dNe:dOe:dPe@dQee:   d
ee:ef   fdR„Z_dSee   d
dfdT„Z` G dU„ dVea«      Zb G dW„ dXe«      Zcd1e:dYee:   dZeed   d[eFd
ecf
d\„ZedOe:d
e:fd]„Zfd^ecd;eTd
e:fd_„Zg	 d´d1e:dNe:dYee:   dZeed   d
ef
d`„ZhddaœdbeddHee:   dce=ddee=   d
eTf
de„Zidfe:dge:dhe:d
edfdi„ZjdjZkekdkfdldmfZlekeld   dn   fdoeRdpffZmdqelfdremfdsœZndte:due:dfe:d
eTfdv„Zod±dweTdxe:fdy„Zpdte:due:dfe:dHee:   dzee:eTedgeeq   f   d
e:fd{„Zr	 	 dµd1e:dfe:dHe:dYee:   dZeed   d
e:fd|„Zsd
eFfd}„Ztd
eFfd~„ZuddlvmwZwmxZx d€d�d‚dƒd„d…œdƒd†d…œd‡dˆd‰idŠdŠd‹dŒœd�œd1dNgdŽœd�œZyd�eqd‘eqd
ee:   fd’„Zzd“ee:ef   d”ed
e:fd•„Z{ ewjø                  d€d–eye{eud—d˜¬™«       dšd›dœdšdšd�d�džœZ}dZ~d6ZdŸed
ee:   fd „Z€d¡e:d
e:fd¢„Z�d±dŸed4ee:   d
e:fd£„Z‚d¤e:dYee:   d¥edd
efd¦„Zƒ	 d´d¤e:dfe:dHe:dYee:   d
e:f
d§„Z„d¨d©d‚dƒdªd…œdƒd«d…œd¬œd¤dNgdŽœd�œZ…d“ee:ef   d”ed
ee:   fd­„Z† ewjø                  d¨d®e…e†etd—d¯¬™«       ddl‡Z‡ddlˆZˆddl‰Z‰y)¶a[  Vision tools: ``vision_analyze`` (image) and ``video_analyze``.

Images resolve through :mod:`tools.image_source`, are normalized to a provider-supported format
(:mod:`tools.vision_tools_image_prep`), then either attach natively to a vision-capable main
model (multimodal tool-result envelope) or are described by the auxiliary vision LLM router.
é    N)ÚThreadPoolExecutor)ÚBytesIO)ÚPath)ÚAnyÚ	AwaitableÚCallableÚDictÚ
NamedTupleÚOptional)ÚurlparseÚasync_call_llmÚextract_content_or_reasoningÚreturnc                  óz   — t         �t        €/ddlm}  t         xs | j                   a t        xs | j                  ay y )Nr   )Úauxiliary_client)r   r   Úagentr   )Ú_auxs    ú7/home/ubuntu/.hermes/hermes-agent/tools/vision_tools.pyÚ_load_auxiliary_clientr      s8   € äÐÔ!=Ð!EÝ2Ü'Ò>¨4×+>Ñ+>ˆÜ'CÒ'hÀt×GhÑGhÑ$ð "Fó    )Úget_hermes_dir)ÚDebugSession)Úcheck_website_access)Únative_turn_duplicateÚrecord_embedÚrelease_embedÚrepeat_refusalÚresolve_repeat_capÚresolve_embed_target_bytes)Ú&_VISION_MAX_VALIDATED_AGGREGATE_PIXELSÚ!_VISION_MAX_VALIDATED_FRAME_COUNTÚ_crop_image_regionÚ_determine_mime_typeÚ_image_exceeds_dimensionÚ_normalize_to_supported_imageÚ _validate_raster_image_decodableÚvision_toolsÚVISION_TOOLS_DEBUG)Úenv_var©ÚdefaultÚkeysc                 óZ   — 	 ddl m}m}  | |«       dg|¢­d| iŽS # t        $ r | cY S w xY w)zQ``auxiliary.<keys...>`` from config.yaml; ``default`` when config is unavailable.r   )Úcfg_getÚload_configÚ	auxiliaryr+   )Úhermes_cli.configr.   r/   Ú	Exception)r+   r,   r.   r/   s       r   Ú_cfg_auxiliaryr3   =   s7   € ðß:Ù‘{“} kÐJ°DÒJÀ'ÑJÐJøÜò ØŠðús   ‚ œ*©*r)   Úkeyc                 óš   ‡‡— ˆˆfd„} |t        j                  | d«      j                  «       xs d«      }|�|S  |t        d|«      «      S )u¾   Env var â†’ ``auxiliary.vision.<key>`` â†’ None. Values that fail ``cast`` or fall below
    ``minimum`` are skipped in favor of the next source (a cap can never be disabled by a bad value).c                 óV   •— 	  ‰| «      }‰�|‰k\  r|S d S # t         t        f$ r Y y w xY w©N)Ú	TypeErrorÚ
ValueError)ÚrawÚvalÚcastÚminimums     €€r   Ú_acceptz%_read_vision_setting.<locals>._acceptI   sA   ø€ ð	Ù�s“)ˆCð �o¨°ªˆsÐA¸TÐAøô œ:Ð&ò 	Ùð	ús   ƒ –(§(Ú NÚvision)ÚosÚgetenvÚstripr3   )r)   r4   r<   r=   r>   r;   s     ``  r   Ú_read_vision_settingrD   F   sI   ù€ õBñ ”"—)‘)˜G RÓ(×.Ñ.Ó0Ò8°DÓ
9€CØ�/ˆ3ÐM¡w¬~¸hÈÓ/LÓ'MÐMr   ÚHERMES_VISION_DOWNLOAD_TIMEOUTÚdownload_timeoutg      >@i   c                  óÂ   — 	 t        dt        t        j                  d«      «      «      S # t        t
        f$ r% t        dt        j                  «       xs d«      cY S w xY w)zKUsable CPU count (``sched_getaffinity`` honors cpuset pinning), at least 1.é   r   )ÚmaxÚlenrA   Úsched_getaffinityÚAttributeErrorÚOSErrorÚ	cpu_count© r   r   Ú_detect_host_cpusrP   b   sP   € ð+Ü�1”cœ"×.Ñ.¨qÓ1Ó2Ó3Ð3øÜœGÐ$ò +Ü�1”b—l‘l“nÒ)¨Ó*Ò*ð+ús   ‚'* ª1AÁAc                  óD   — t        ddt        d¬«      } | xs
 t        «       S )ud   HERMES_VISION_MAX_CONCURRENCY â†’ ``auxiliary.vision.max_concurrency`` â†’ host cores (< 1 ignored).ÚHERMES_VISION_MAX_CONCURRENCYÚmax_concurrencyrH   )r=   )rD   ÚintrP   )r;   s    r   Ú_resolve_vision_cpu_workersrU   j   s%   € ä
Ð>Ð@QÔSVÐ`aÔ
b€CØÒ%Ô#Ó%Ð%r   zvision-encode)Úmax_workersÚthread_name_prefixc              �   ó¢   K  — ddl }t        j                  «       }|j                  t         |j
                  | g|¢­i |¤Ž«      ƒ d{  –—† S 7 Œ­w)zZRun a sync encode/resize callable on the bounded vision CPU executor (never the LLM call).r   N)Ú	functoolsÚasyncioÚget_running_loopÚrun_in_executorÚ_vision_cpu_executorÚpartial)ÚfnÚargsÚkwargsrY   Úloops        r   Ú_run_encode_on_cpu_executorrc   w   sK   è ø€ ãÜ×#Ñ#Ó%€DØ×%Ñ%Ô&:Ð<M¸I×<MÑ<MÈbÐ<bÐSWÒ<bÐ[aÑ<bÓc×cÐcÐcús   ‚AAÁAÁ	AÚurlc              ƒ   ó¨   K  — t        | t        «      r&| j                  d«      rt        | «      j                  syddlm}  || «      ƒ d{  –—† S 7 Œ­w)zpHTTP(S) shape check (scheme, netloc; extension-less CDN URLs pass) + SSRF guard with DNS
    off the event loop.)úhttp://úhttps://Fr   )Úasync_is_safe_urlN)Ú
isinstanceÚstrÚ
startswithr   ÚnetlocÚtools.url_safetyrh   )rd   rh   s     r   Ú_validate_image_url_asyncrn   ~   sD   è ø€ ô �sœCÔ  S§^¡^Ð4KÔ%LÔQYÐZ]ÓQ^×QeÒQeØÝ2Ù" 3Ó'×'Ð'Ð'ús   ‚A	AÁAÁAÚerrorc                 óÂ   — t        | t        t        f«      ryt        | t        j                  «      r.| j
                  j                  }|dk(  xs d|cxk  xr dk  nc  S y)z½Transient failures only: 429, 5xx, transport errors and anything unclassified. Fail-fast on
    other 4xx, PermissionError (policy/SSRF block) and ValueError (too large / blocked redirect).Fi­  i�  iô  T)ri   ÚPermissionErrorr9   ÚhttpxÚHTTPStatusErrorÚresponseÚstatus_code)ro   Ústatuss     r   Ú_is_retryable_download_errorrw   ‡   sT   € ô �%œ/¬:Ð6Ô7ØÜ�%œ×.Ñ.Ô/Ø—‘×+Ñ+ˆØ˜‰}Ò7 C¨6Ö$7°CÔ$7Ð 7Ð7Ør   zoMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36c              ƒ   ór   K  — ddl m}m}  || «      }|r ||«      ƒ d{  –—† st        d|› �«      ‚yy7 Œ­w)z¨Re-validate each redirect target (a public URL 302ing to 169.254.169.254 would otherwise
    bypass the pre-flight check). Async because httpx.AsyncClient awaits hooks.r   )rh   Úredirect_target_from_responseNz.Blocked redirect to private/internal address: )rm   rh   ry   r9   )rt   rh   ry   Úredirect_urls       r   Ú_ssrf_redirect_guardr{   ˜   sE   è ø€ ÷ RÙ0°Ó:€LÙÑ"3°LÓ"A×AÐAÜÐIÈ,ÈÐXÓYÐYð B€|ÐAús   ‚7 5¡7ÚdestinationÚmax_retriesÚmedia_labelÚacceptÚ	max_bytesÚtimeoutÚ	retry_allc             ƒ   ó  K  — ddl m} ddlm}	 |j                  j                  dd¬«       d}
t        |«      D �]ˆ  }	 t        | «      }|rt        |d   «      ‚ |	|ddt        gi¬	«      4 ƒd{  –—† }|j                  d
| t        |dœ¬«      4 ƒd{  –—† }|j                  «        |j                  j                  d«      }	 |rt        |«      nd}|�||kD  rt!        |› d|› d|› d�«      ‚t        t#        |j$                  «      «      }|rt        |d   «      ‚|j'                  d|j(                  › dt+        j,                  «       j.                  › d�«      }d}	 |j1                  d«      5 }|j3                  «       2 3 d{  –—† }|sŒ|t5        |«      z  }||kD  rt!        |› d|› d|› d�«      ‚|j7                  |«       ŒE |
�|
‚tM        d|jO                  «       › d|› d�«      ‚7 �Œz7 �ŒY# t         $ r d}Y �Œ*w xY w7 Œ}6 	 ddd«       n# 1 sw Y   nxY w |||«       nH# t8        $ r< 	 |j;                  d¬«       ‚ # t<        $ r t>        jA                  d|d¬«       Y ‚ w xY ww xY wddd«      ƒd{  –—†7   n# 1 ƒd{  –—†7  sw Y   nxY wddd«      ƒd{  –—†7   n# 1 ƒd{  –—†7  sw Y   nxY w|c S # t8        $ r»}|}
||dz
  k\  s|s>tC        |«      s3t>        jE                  d||dz   t#        |«      dd d¬«       |s‚ Y d}~ �ŒLd|dz   z  }t>        jG                  d||dz   |t#        |«      dd «       |st>        jG                  d|«       tI        jJ                  |«      ƒ d{  –—†7   Y d}~�ŒDd}~ww xY w­w) uÂ   SSRF-safe streaming download with exponential backoff (2s/4s/8s). ``retry_all=False`` (images)
    retries only :func:`_is_retryable_download_error` errors â€” a 404/403 never succeeds on retry.r   )Úatomic_replace)Úcreate_ssrf_safe_async_clientT©ÚparentsÚexist_okNÚmessagert   )r�   Úfollow_redirectsÚevent_hooksÚGET)z
User-AgentÚAccept)Úheaderszcontent-lengthz too large (z bytes, max ú)ú.z.tmpÚwb©Ú
missing_okz%Could not delete partial download: %s©Úexc_inforH   z*%s download failed after %s attempt(s): %séd   é   z&%s download failed (attempt %s/%s): %sé2   zRetrying in %ss...Ú
_download_z3 exited retry loop without attempting (max_retries=)(Úutilsr„   rm   r…   ÚparentÚmkdirÚranger   rq   r{   ÚstreamÚ_DOWNLOAD_USER_AGENTÚraise_for_statusrŽ   ÚgetrT   r9   rj   rd   Ú	with_nameÚnameÚuuidÚuuid4ÚhexÚopenÚaiter_bytesrJ   Úwriter2   ÚunlinkrM   ÚloggerÚdebugrw   ro   ÚwarningrZ   ÚsleepÚRuntimeErrorÚlower)rd   r|   r}   r~   r   r€   r�   r‚   r„   r…   Ú
last_errorÚattemptÚblockedÚclientrt   ÚclÚdeclared_sizeÚtmp_destinationÚbytes_writtenÚfÚchunkÚeÚ	wait_times                          r   Ú_download_mediar½   ¡   sÑ  è ø€ õ
 %Ý>Ø×Ñ×Ñ T°DÐÔ9Ø€JÜ˜Ó%ó ?+ˆð>	+Ü*¨3Ó/ˆGÙÜ% g¨iÑ&8Ó9Ð9ñ 5Ø°$ÀZÔRfÐQgÐDhô÷ (ð (à˜Ÿ™Ø�sÔ3GÐSYÑ$Zð 'ó ÷(ð (ð Ø×)Ñ)Ô+ð ×%Ñ%×)Ñ)Ð*:Ó;�ð)Ù/1¤C¨¤G°t�Mð !Ð,°ÀÒ1JÜ$¨ }°LÀÀÈ|Ð\eÐ[fÐfgÐ%hÓiÐiÜ.¬s°8·<±<Ó/@ÓA�ÙÜ)¨'°)Ñ*<Ó=Ð=ð #.×"7Ñ"7¸!¸K×<LÑ<LÐ;MÈQÌtÏzÉzË|×O_ÑO_ÐN`Ð`dÐ8eÓ"f�Ø !�ðØ(×-Ñ-¨dÓ3ð 	+°qØ+3×+?Ñ+?Ó+A÷ +ð + %Ù#(Ø (Ø)¬S°«ZÑ7˜MØ,¨yÒ8Ü&0Ø'2 m°<À¸ÈlÐ[dÐZeÐefÐ$gó'"ð !"ð ŸG™G E�NðS?+ðB ÐØÐÜ
Ø
�[×&Ñ&Ó(Ð)Ð)\Ð]hÐ\iÐijÐkómð mðw(ùð (úô "ò )Ø$(“Mð)úð+øÑ+A÷	+÷ 	+ñ 	+úñ # ?°KÕ@øÜ ò ðnØ'×.Ñ.¸$Ð.Ô?ð øô #ò nÜŸ™Ð%LÈoÐhl˜ÕmØðnúðú÷G(÷ (÷ (÷ (ó (ú÷ (÷ (÷ (÷ (ó (úðR ÒøÜò 	+ØˆJØ˜+¨™/Ò)±)ÔD`ÐabÔDcÜ—‘ÐIØ(¨'°A©+´s¸1³v¸d¸s°|Èdð ô Tá ØÞØ˜g¨™kÑ*ˆIÜ�N‰NÐCØ&¨°!©°[Ä#ÀaÃ&ÈÈ"À+ôOáÜ—‘Ð3°YÔ?Ü—-‘- 	Ó*×*×*ûð	+üso  ‚;N¾1J>Á/G)Á0J>Á3 J%ÂG,
ÂJ%Â,I>ÃG/ÃB	I>ÅH$Å.H	Å?H
ÆHÆH
Æ=H	Ç%NÇ)J>Ç,J%Ç/G>	Ç:I>Ç=G>	Ç>I>ÈH
ÈH	È	H$ÈHÈH$È#I>È$	I)	È.IÉ I)	É!I%É"I)	É$I%É%I)	É)I>É,J%É7I:É8J%É>JÊJÊJÊJ%ÊJ>ÊJ!ÊJ>Ê%J7	Ê+J.Ê,J7	Ê3J>Ê;NÊ>	NËAM=Ì
NÌA M=Í1M4Í2M=Í7NÍ=NÎNÚ	image_urlc           
   ƒ   óT   K  — t        | ||ddt        t        d¬«      ƒ d{  –—† S 7 Œ­w)zCDownload an image with SSRF protection and error-class-aware retry.ÚImagezimage/*,*/*;q=0.8F©r~   r   r€   r�   r‚   N)r½   Ú_VISION_MAX_DOWNLOAD_BYTESÚ_VISION_DOWNLOAD_TIMEOUT)r¾   r|   r}   s      r   Ú_download_imagerÄ   ñ   s7   è ø€ ä Ø�; ØÐ$7Ü,Ô6NÐZ_ôa÷ að að aús   ‚(¡&¢(Ú
image_pathÚ	mime_typec                 ó�   — |xs t        | «      }d|› dt        j                  | j                  «       «      j	                  d«      › �S )zK``data:<mime>;base64,...`` for a file (MIME from extension when not given).údata:ú;base64,Úascii)r#   Úbase64Ú	b64encodeÚ
read_bytesÚdecode)rÅ   rÆ   Úmimes      r   Ú_image_to_base64_data_urlrÐ   ù   sF   € àÒ8Ô,¨ZÓ8€DØ�4�&˜¤×!1Ñ!1°*×2GÑ2GÓ2IÓ!J×!QÑ!QÐRYÓ!ZÐ [Ð\Ð\r   i  @i   i  P )z	too largeÚpayloadÚ413Úcontent_too_largeÚrequest_too_largeÚexceedsz
size limitc                 ól   ‡— t        | «      j                  «       Št        ˆfd„t        dz   D «       «      S )z;Detect if an API error is related to image or payload size.c              3   ó&   •K  — | ]  }|‰v –— Œ
 y ­wr7   rO   ©Ú.0ÚhintÚerr_strs     €r   ú	<genexpr>z'_is_image_size_error.<locals>.<genexpr>  s   øè ø€ Ò` 4ˆt�wŒÑ`ùó   ƒ)r¾   Úinvalid_request)rj   r°   ÚanyÚ_SIZE_ERROR_HINTS)ro   rÛ   s    @r   Ú_is_image_size_errorrá     s-   ø€ ä�%‹j×ÑÓ €GÜÓ`Ô+<Ð?_Ñ+_Ô`Ó`Ð`r   Ú
scale_infoÚcrop_offsetc                 ó4  — g }| r`| d   | d   }}| d   | d   }}|r||z  nd|r||z  nd}}|d›|d›k(  rd|d›�n	d|d›d	|d›�}	|j                  d
|› d|› d|› d|› d|	› d�«       |r|j                  d|d   › d|d   › d�«       |rdj                  |«      S dS )z^Coordinate-mapping disclosure for downscale and/or region crop; ``None`` when neither applied.Ú
orig_widthÚorig_heightÚ	new_widthÚ
new_heightg      ð?z.2fzany coordinates you report by z any x coordinates you report by z and any y coordinates by zImage downscaled from Úxz to z for vision; multiply z# to map back to the original image.zUAnalysis was performed on a cropped region of the original image starting at offset (ú, Úyua   ); coordinates are relative to that crop origin â€” add the offset to map back to the full image.Ú N)ÚappendÚjoin)
râ   rã   ÚpartsÚowÚohÚnwÚnhÚfxÚfyÚaxess
             r   Ú_build_scale_noter÷     s  € à€EÙØ˜LÑ)¨:°mÑ+DˆBˆØ˜KÑ(¨*°\Ñ*BˆBˆÙ�"�r’' S±r¨B°ªG¸sˆBˆØ@BÀ3¸xÈrÐRUÈhÒ=WÐ0°°C°Ñ9Ø7¸¸3°xÐ?YÐZ\Ð]`ÐYaÐbð 	à�‰Ð-¨b¨T°°2°$°d¸2¸$¸aÀ¸tð D!Ø!% Ð&IðKô 	LáØ�‰ð)Ø)4°SÑ)9Ð(:¸"Ø˜3ÑÐ ð !GðHô	Iñ
 $ˆ3�8‰8�E‹?Ð-¨Ð-r   c                  ó‚   — 	 ddl m}  | S # t        $ r+ 	 ddlm}  |dd¬«       ddl m}  Y | S # t
        $ r Y Y yw xY ww xY w)zêReturn ``PIL.Image`` or None (Pillow is a lazy-installable soft dependency). ``prompt=False``:
    a blocking input() deadlocks the CLI where prompt_toolkit owns stdin; the install is already
    gated by security.allow_lazy_installs.r   )rÀ   )Úensureztool.visionF)ÚpromptN)ÚPILrÀ   ÚImportErrorÚtools.lazy_depsrù   r2   )rÀ   Ú_ensure_deps     r   Ú_import_pillow_for_resizerÿ   0  sT   € ðÝð €Løô ò 	ð	Ý=ñ ˜¨eÕ4Þ!ð €Løô ò 	Úð	úð	ús   ‚
 Š	>”-­	:¶>¹:º>FÚmax_base64_bytesÚmax_dimensionÚ	scale_outÚ
force_jpegc           	      óÂ  ‡ ‡‡‡‡— ‰ j                  «       j                  }|dz  dz  dz   }dŠ||k  r+|�t        ‰ |«      st        ‰ ‰¬«      Št	        ‰«      |k  r‰S dt
        fˆˆ ˆfd„}t        «       }	|	€t        j                  d«        |«       S t        j                  d	|d
z  |d
z  |d
z  |«       ‰xs t        ‰ «      dk(  xr | }
|
rdnd\  }}	 |	j                  ‰ «      }|
s|j                  dvr|j                  d«      }|
rdnd}|j                  |j                  fxŠ}d}dt         dt         ddfˆˆfd„}t#        d«      D �]  }|dkD  �rt%        t!        |j                  dz  «      d«      t%        t!        |j                  dz  «      d«      }}|dk(  r?|j                  dkD  r0t%        t!        |j                  d|j                  z  z  «      d«      }nC|dk(  r>|j                  dkD  r/t%        t!        |j                  d|j                  z  z  «      d«      }||f|k(  r �n7|j'                  ||f|	j(                  «      }||f}t        j                  d|||«       |du xs# t%        |j                  |j                  «      |k  }|D ]Ì  }t+        «       } |j,                  |fd|i|€i nd|i¤Ž d|› dt/        j0                  |j3                  «       «      j5                  d«      › �}t	        |«      |k  sŒo|sŒrt        j                  d t	        |«      d
z  ||j                  |j                  «        ||j                  |j                  «       |c c S  �Œ |€ |«       S t        j7                  d!|d
z  t	        |«      d
z  «        ||j                  |j                  «       |S # t        $ r'}t        j                  d|«        |«       cY d}~S d}~ww xY w)"u]  Base64 data URL, progressively downscaled with Pillow while over budget.

    Halves dimensions (aspect-preserving, 64px floor) up to 4 times; JPEG also walks a
    quality ladder (85/70/50) per step. Without Pillow, or if it still doesn't fit, returns
    the best attempt (or raw bytes) and lets the caller apply the size check.
    ``max_dimension``: force a downscale above this long edge even when bytes fit
    (Anthropic's 8000px cap is independent of bytes). ``force_jpeg``: re-encode PNG as JPEG
    when resizing â€” halving PNG dimensions destroys text legibility on dense screenshots.

    Args: max_dimension: If set, images whose longest side exceeds this pixel count are forcibly downscaled
    even if they're under the byte budget. Anthropic enforces an 8000 px per-side cap independently of the 5
    MB byte cap. force_jpeg: Re-encode as JPEG even for PNG input when a resize is needed. History-reuse
    embeds (#92699) opt in so a text-heavy screenshot keeps its readable resolution and shrinks via JPEG
    quality instead. Images already under both caps are returned unchanged (still PNG).
    é   é   r–   N©rÆ   r   c                  ó&   •— ‰ xs t        ‰‰¬«      S )Nr  )rÐ   )Údata_urlrÅ   rÆ   s   €€€r   Ú_rawz&_resize_image_for_vision.<locals>._rawa  s   ø€ ØÒUÔ4°ZÈ9ÔUÐUr   u;   Pillow not installed â€” cannot auto-resize oversized imagezcImage file is %.1f MB (estimated base64 %.1f MB, limit %.1f MB, max_dimension=%s), auto-resizing...é   ú	image/png)ÚPNGr  )ÚJPEGz
image/jpegz)Pillow cannot open image for resizing: %s>   ÚLÚRGBr  r7   )éU   éF   r˜   ÚwÚhc                 óR   •— ‰�$| |f‰k7  r‰j                  ‰d   ‰d   | |¬«       y y y )Nr   rH   )rå   ræ   rç   rè   )Úupdate)r  r  Ú	orig_dimsr  s     €€r   Ú_record_scalez/_resize_image_for_vision.<locals>._record_scalez  s=   ø€ ØÐ  a¨ V¨yÒ%8Ø×Ñ¨	°!©À)ÈAÁ,ÐZ[ÐhiÐÕjð &9Ð r   é   r   g      à?é@   zResized to %dx%d (attempt %d)ÚformatÚqualityrÈ   rÉ   rÊ   z4Auto-resized image fits: %.1f MB (quality=%s, %dx%d)z=Auto-resize could not fit image under %.1f MB (best: %.1f MB))ÚstatÚst_sizer$   rÐ   rJ   rj   rÿ   r«   Úinfor#   r§   r2   ÚmodeÚconvertÚwidthÚheightrT   r�   rI   ÚresizeÚLANCZOSr   ÚsaverË   rÌ   ÚgetvaluerÎ   r­   )rÅ   rÆ   r   r  r  r  Ú	file_sizeÚestimated_b64r
  rÀ   Úis_pngÚ
pil_formatÚout_mimeÚimgÚexcÚquality_stepsÚ	prev_dimsÚ	candidater  r²   Únew_wÚnew_hÚdims_okÚqÚbufr	  r  s   ``  `                    @@r   Ú_resize_image_for_visionr7  C  sª  ü€ ð( —‘Ó!×)Ñ)€IØ ‘] qÑ(¨3Ñ.€MØ€HØÐ(Ò(ØÐ!Ô&>¸zÈ=Ô&Yä,¨ZÀ9ÔMˆÜˆx‹=Ð,Ò,ØˆOðV”#÷ Vä%Ó'€EØ€}Ü�‰ÐQÔRÙ‹vˆÜ
‡K�KÐuØ˜[Ñ)¨=¸KÑ+HØ  KÑ0°-ôAð Ò;Ô/°
Ó;ÀÑKÒ^ÐT^ÐP^€FÙ39Ñ/Ð?UÑ€J�ðØ�j‰j˜Ó$ˆñ �c—h‘h lÑ2Ø�k‰k˜%Ó ˆÙ%‘G¨<€MØ ŸY™Y¨¯
©
Ð3Ð3€I�	Ø€Iðkœð k¤ð k¨ö kô ˜“8ó !ˆØ�Q‹;äœs 3§9¡9¨s¡?Ó3°RÓ8¼#¼cÀ#Ç*Á*ÈsÑBRÓ>SÐUWÓ:X�5ˆEØ˜Š{˜sŸy™y¨1š}ÜœC §
¡
¨b°3·9±9©nÑ =Ó>ÀÓC‘Ø˜"’ §¡¨a¢ÜœC §	¡	¨R°#·*±*©_Ñ =Ó>ÀÓC�Ø�uˆ~ Ò*ÚØ—*‘*˜e U˜^¨U¯]©]Ó;ˆCØ ˜ˆIÜ�K‰KÐ7¸ÀÀwÔOØ 4Ð'ÒV¬3¨s¯y©y¸#¿*¹*Ó+EÈÑ+VˆØò 	!ˆAÜ“)ˆCØˆC�H‰H�SÑU ÐU°a°i±ÀiÐQRÀ^ÒUØ ˜z¨´&×2BÑ2BÀ3Ç<Á<Ã>Ó2R×2YÑ2YÐZaÓ2bÐ1cÐdˆIÜ�9‹~Ð!1Ó1²gÜ—‘ÐRÜ 	›N¨kÑ:¸A¸s¿y¹yÈ#Ï*É*ôVá˜cŸi™i¨¯©Ô4Ø Ô ò	!ð!ð. ÐÙ‹vˆÜ
‡N�NÐRØ# {Ñ3´S¸³^À{Ñ5SôUá�#—)‘)˜SŸZ™ZÔ(ØÐøôU ò Ü�‰Ð?ÀÔEÙ‹v�ûðús   ÃN. Î.	OÎ7OÏOÏO>   úopenai-chatúazure-openaiúopenai-codexúgoogle-vertexúanthropic-directúanthropic-vertexÚnousÚclaudeÚopenaiÚvertexÚbedrockÚ	anthropicÚ
openrouter>   úgoogle-geminiúgoogle-vertex-geminiÚgeminiÚgoogleÚproviderÚmodelc                 ó@   — 	 ddl m}  || |«      S # t        $ r Y yw xY w)uŽ  Hard veto: the provider's ``ProviderProfile`` declares
    ``supports_vision_tool_messages=False`` â€” images are accepted in user
    messages but list-type tool-result content is rejected with 400
    (xiaomi/MiMo "text is not set"). ``supports_vision`` alone must not
    override this, or the multimodal tool-result envelope 400s every turn
    and the image never enters context (#89981).
    r   )Ú)routed_model_rejects_vision_tool_messagesF)Ú	providersrL  r2   )rI  rJ  rL  s      r   Ú_profile_rejects_tool_mediarN  ©  s)   € ðÝGÙ8¸À5ÓIÐIøÜò Ùðús   ‚ ‘	œc                 óž  ‡— t        | t        «      r| j                  «       j                  «       nd}|rt	        ||«      ry|t
        v ry|t        v rDt        |t        «      r|j                  «       j                  «       ndŠt        ˆfd„dD «       «      S 	 ddlm	}  ||«      }|duxr t        |j                  «      S # t        $ r Y yw xY w)	a	  Whether provider+model accepts image content inside a tool-result message. Unknown
    providers are False (caller falls back to aux-LLM text) unless their ``ProviderProfile``
    declares ``supports_vision``; ``supports_vision_tool_messages=False`` is a hard veto.r?   FTc              3   ó&   •K  — | ]  }|‰v –— Œ
 y ­wr7   rO   )rÙ   ÚtagÚms     €r   rÜ   z2_supports_media_in_tool_results.<locals>.<genexpr>Ã  s   øè ø€ ÒV �3˜!”8ÑVùrÝ   )zgemini-3zgemini-pro-3zgemini-flash-3r   )Úget_provider_profileN)ri   rj   rC   r°   rN  Ú_TOOL_RESULT_MEDIA_PROVIDERSÚ_GEMINI_PROVIDERSrß   rM  rS  ÚboolÚsupports_visionr2   )rI  rJ  ÚprS  ÚprofilerR  s        @r   Ú_supports_media_in_tool_resultsrZ  ¸  sº   ø€ ô %/¨x¼Ô$=ˆ�‰Ó×ÑÔ À2€AÙÔ+¨A¨uÔ5ØØÔ(Ñ(ØØÔÑÜ%/°´sÔ%;ˆE�K‰K‹M×ÑÔ!ÀˆÜÓVÐ'UÔVÓVÐVðÝ2Ù& qÓ)ˆØ˜dÐ"ÒD¤t¨G×,CÑ,CÓ'DÐDøÜò Ùðús   Â(C  Ã 	CÃCÚcfgc                 óZ   — t        | |«      ryt        | |«      ryddlm}  || ||«      du S )uw  One gate for both native lanes â€” the ``vision_analyze`` fast path and the ``computer_use`` capture route
    (#115248): the profile's ``supports_vision_tool_messages=False`` veto first, then either the provider's tool
    results are known to carry media or the capability lookup (config override â†’ catalog â†’ probes â†’ profile)
    attests the model as vision-capable.FTr   )Ú_lookup_supports_vision)rN  rZ  Úagent.image_routingr]  )rI  rJ  r[  r]  s       r   Ú_accepts_tool_result_imagesr_  Ì  s5   € ô
 # 8¨UÔ3ØÜ& x°Ô7ØÝ;Ù" 8¨U°CÓ8¸DÐ@Ð@r   c                  óä   — 	 ddl m} m} ddlm} ddlm}  | «       } |«       } |«       } ||||«      dk7  ryt        |||«      S # t        $ r }t        j                  d|«       Y d}~yd}~ww xY w)	uà   True when image routing resolves to ``native`` AND the provider accepts images in tool
    results, or the user set the ``model.supports_vision`` override (escape hatch for
    custom/local providers). Any failure â†’ False.r   )Ú_read_main_providerÚ_read_main_model)Údecide_image_input_mode)r/   ÚnativeFz(Native vision fast-path check failed: %sN)Úagent.auxiliary_clientra  rb  r^  rc  r1   r/   r_  r2   r«   r¬   )ra  rb  rc  r/   rI  rJ  r[  r.  s           r   Ú#_should_use_native_vision_fast_pathrf  Ù  sl   € ðßPÝ?Ý1Ù&Ó(ˆÙ Ó"ˆÙ‹mˆÙ" 8¨U°CÓ8¸HÒDØÜ*¨8°U¸CÓ@Ð@øÜò Ü�‰Ð?ÀÔEÜûðús   ‚6A ¹A Á	A/ÁA*Á*A/ÚquestionÚimage_data_urlÚimage_size_bytesÚ
scale_notec                 óÆ   — d}t        |t        «      r&|j                  «       r|d|j                  «       › �z  }|r|d|› �z  }dd|dœdd|id	œgd
|dz  d›d�| dd |ddœdœS )zÁMultimodal tool-result envelope. The text part is intentionally minimal (the model already
    has the question); ``text_summary`` is the fallback for providers without multimodal tool results.ul   Image loaded into your context â€” you can see it natively now. Use your built-in vision to answer the user.z

Question: z

Note: TÚtext©Útyperl  r¾   rd   )rn  r¾   z,Image attached natively for the main model (é   ú.1fz# KB). Answer using built-in vision.NéÈ   )r¾   Ú
size_bytesÚnative_vision)Ú_multimodalÚcontentÚtext_summaryÚmeta)ri   rj   rC   )r¾   rg  rh  ri  rj  Ú	text_parts         r   Ú _build_native_vision_tool_resultry  ì  s¨   € ð	7ð ô �(œCÔ  X§^¡^Ô%5Ø�~ h§n¡nÓ&6Ð%7Ð8Ñ8ˆ	ÙØ�z * Ð.Ñ.ˆ	àà YÑ/Ø °°~Ð/FÑGðIð ;Ð;KÈdÑ;RÐSVÐ:Wð X,ð ,à'¨¨˜oÐ=MÐ`dÑeñgð gr   Úpathc                 óN   — | �	 | j                  d¬«       y y # t        $ r Y y w xY w)NTr’   )rª   r2   )rz  s    r   Ú_unlink_quietlyr|    s4   € ØÐð	Ø�K‰K 4ˆKÕ(ð øô ò 	Ùð	ús   „ ˜	$£$c                   ó   — e Zd ZdZy)Ú_ImagePrepErrorz=Raised by :func:`_prepare_image`; the message is user-facing.N)Ú__name__Ú
__module__Ú__qualname__Ú__doc__rO   r   r   r~  r~    s   „ ÚGr   r~  c                   ó@   — e Zd ZU dZeed<   ee   ed<   eed<   e	ed<   y)Ú_PreparedImagezHTemp image ready to encode; ``path`` is owned by the caller (delete it).rz  rÏ   rr  rã   N)
r  r€  r�  r‚  r   Ú__annotations__r   rj   rT   ÚdictrO   r   r   r„  r„    s   … ÙRØ
ƒJØ
�3‰-ÓØƒOØÔr   r„  Útask_idÚregionÚvalidate_decodec             ƒ   ó  K  — ddl m}m}m} 	  ||  ||¬«      «      ƒ d{  –—† }t        dd«      }	|	j                  dd¬«       |	d	t        j                  «       › d
�z  }
t        j                  |
j                  |j                  «      ƒ d{  –—†  |j                  t        |j                  «      i }}}	 t        j                  t         |
|«      ƒ d{  –—† \  }}}|s|€t	        |xs d«      ‚||
k7  r't#        |
«       |}
|
j%                  «       j&                  }|r/t)        t*        |
t,        t.        «      ƒ d{  –—† }|rt	        |«      ‚|�et        j                  t0        |
||¬«      ƒ d{  –—† \  }}}|s|€t	        |xs d«      ‚t#        |
«       |||j%                  «       j&                  }}}
t5        |
|||«      S 7 �Œ¡# |$ r}t	        t        |«      «      |‚d}~ww xY w7 �ŒZ7 �Œ7 Œ±7 Œ# t2        $ r t#        |
«       ‚ w xY w­w)uj  Resolve â†’ materialize â†’ normalize â†’ (validate) â†’ (crop). Raises ``_ImagePrepError``.
    Unsupported formats (SVG, BMP) become PNG BEFORE encoding â€” an unsupported media_type baked
    into immutable history would 400 on every resume. The crop runs BEFORE any downscale so the
    region keeps the full resolution budget. On error no temp file is left.r   )ÚImageResolutionErrorÚResolveContextÚresolve_image_source©r‡  Nzcache/visionÚtemp_vision_imagesTr†   Útemp_image_z.imgzImage normalization failed.)Ú
offset_outzRegion crop failed.)Útools.image_sourcer‹  rŒ  r�  r~  rj   r   rœ   r¤   r¥   rZ   Ú	to_threadÚwrite_bytesÚdatarÏ   rJ   r%   r|  r  r  rc   r&   r!   r    r"   ÚBaseExceptionr„  )r¾   r‡  rˆ  r‰  r‹  rŒ  r�  Úresolvedr.  Útemp_dirrz  rÏ   rr  rã   Únormalized_pathÚnorm_errÚdecode_errorÚcropped_pathÚcropped_mimeÚcrop_errs                       r   Ú_prepare_imagerŸ    s	  è ø€ ÷ ^Ñ]ð1Ù-¨i¹ÐPWÔ9XÓY×Yˆô ˜nÐ.BÓC€HØ‡N�N˜4¨$€NÔ/Ø˜¤D§J¡J£L >°Ð6Ñ6€DÜ
×
Ñ
˜D×,Ñ,¨h¯m©mÓ
<×<Ð<Ø$,§M¡M´3°x·}±}Ó3EÀr�kˆ*€DðÜ07×0AÑ0AÔB_ÐaeÐgkÓ0l×*lÑ'ˆ˜˜xÙ�Ð.Ü! (Ò"KÐ.KÓLÐLØ˜dÒ"Ü˜DÔ!Ø"ˆDØŸ™›×,Ñ,ˆJÙÜ!<Ü0°$Ü1Ô3Yó"[÷ [ˆLñ Ü% lÓ3Ð3ØÐÜ9@×9JÑ9JÜ" D¨&¸[ô:J÷ 4JÑ0ˆL˜,¨á˜<Ð/Ü% hÒ&GÐ2GÓHÐHÜ˜DÔ!Ø%1°<À×ARÑARÓAT×A\ÑA\˜
�$ˆDô ˜$  j°+Ó>Ð>ðA ZúØò 1Üœc #›hÓ'¨SÐ0ûð1úð
 =ùð +mùð[øð4Jùô ò Ü˜ÔØðüs”   ‚H
ŽG ¡G¢G ¦A'H
ÂG'Â'H
Â6G1 ÃG*ÃA&G1 Ä;G-Ä<3G1 Å/G/Å0AG1 Æ4H
ÇG ÇG$Ç
GÇG$Ç$H
Ç*G1 Ç-G1 Ç/G1 Ç1HÈH
c                 ó>   — dt        | «      dz  d›dt        dz  d›d�S )Nz2Image too large for vision API: base64 payload is r  rp  ú MB (limit ú.0fzw MB) even after resizing. Install Pillow (`pip install Pillow`) for better auto-resize, or compress the image manually.)rJ   Ú_MAX_BASE64_BYTES)rh  s    r   Ú_too_large_messager¤  D  s=   € à
<¼SÀÓ=PÐT_Ñ=`ÐadÐ<eð fÜ# {Ñ3°CÐ8ð 9Yð	Zð[r   Úpreparedc              ‹   ón   K  — t        t        | j                  f| j                  |dœ|¤Žƒ d{  –—† S 7 Œ­w)zNRun :func:`_resize_image_for_vision` on the CPU executor for a prepared image.)rÆ   r  N)rc   r7  rz  rÏ   )r¥  râ   ra   s      r   Ú_resize_preparedr§  K  s=   è ø€ ä,Ü  (§-¡-ðØ;C¿=¹=ÐT^ñØbhñ÷ ð ð ús   ‚,5®3¯5c              ƒ   óä  K  — t        | t        «      r| j                  «       st        dd¬«      S t	        | |«      }|�|S t        | «      }|�|S t        «       dkD  }d}d}	 ddlm}	  |	«       r4t        dd¬«      |r|st        | «       |�t        |j                  «       S S 	 t        | ||d¬	«      ƒ d{  –—† }t        t        |j                  |j                   ¬
«      ƒ d{  –—† }i }t#        «       }t        t$        |j                  t&        «      ƒ d{  –—† }t)        |«      |kD  s|rkt+        |||t&        d¬«      ƒ d{  –—† }t)        |«      t,        kD  r=t        t/        |«      d¬«      |r|st        | «       |�t        |j                  «       S S d}|st1        | «       t3        | |||j4                  t7        |xs d|j8                  xs d«      ¬«      |r|st        | «       |�t        |j                  «       S S 7 �ŒM# t        $ rG}
t        t        |
«      d¬«      cY d}
~
|r|st        | «       |�t        |j                  «       S S d}
~
ww xY w7 �Œu7 �ŒE7 �Œ# t:        $ rW}
t<        j?                  d|
«       t        d|
› �d¬«      cY d}
~
|r|st        | «       |�t        |j                  «       S S d}
~
ww xY w# |r|st        | «       |�t        |j                  «       w w xY w­w)zžFast path for vision-capable main models: a ``_multimodal`` envelope dict on success,
    or a JSON error string (the normal tool-result contract) on failure.zimage_url is requiredF©ÚsuccessNr   ©Úis_interruptedÚInterruptedT©r‰  r  )r   r  r  )r¾   rg  rh  ri  rj  z"Native vision fast path failed: %szNative vision failed: ) ri   rj   rC   Ú
tool_errorÚ_native_turn_duplicateÚ_repeat_refusalÚ_resolve_repeat_capÚtools.interruptr¬  Ú_release_embedr|  rz  rŸ  r~  rc   rÐ   rÏ   Ú_resolve_embed_target_bytesr$   Ú_EMBED_MAX_DIMENSIONrJ   r§  r£  r¤  Ú_record_embedry  rr  r÷   rã   r2   r«   r­   )r¾   rg  r‡  rˆ  Úalready_nativeÚrefusalÚreservedr¥  Úembeddedr¬  r.  rh  Ú_scale_infoÚembed_target_bytesÚ
_over_dimss                  r   Ú_vision_analyze_nativer¿  R  sÝ  è ø€ ô
 �i¤Ô%¨Y¯_©_Ô->ÜÐ1¸5ÔAÐAÜ+¨I°vÓ>€NØÐ!ØÐä˜iÓ(€GØÐØˆÜ"Ó$ qÑ(€HØ)-€HØ€Hð)+Ý2ÙÔÜ˜m°UÔ;ñD ™HÜ˜9Ô%àÐÜ˜HŸM™MÕ*ð  ðI	7Ü+¨I°wÀÐX\Ô]×]ˆHô  ;Ü% x§}¡}ÀÇÁô O÷ Oˆð ˆô 9Ó:ÐÜ6Ü$ h§m¡mÔ5IóK÷ Kˆ
äˆ~ÓÐ!3Ò3±zÜ#3Ø˜+Ø!3ÔCWÐdhô$j÷ jˆNô �>Ó"Ô%6Ò6Ü!Ô"4°^Ó"DÈeÔTñ ™HÜ˜9Ô%àÐÜ˜HŸM™MÕ*ð  ð ˆÙÜ˜)Ô$Ü/Ø¨(À>Ø%×0Ñ0Ü(¨Ò)<¸¸h×>RÑ>RÒ>ZÐVZÓ[ô]ñ ™HÜ˜9Ô%àÐÜ˜HŸM™MÕ*ð  ðG ^úÜò 	7Üœc #›h°Ô6Ô6ñ< ™HÜ˜9Ô%àÐÜ˜HŸM™MÕ*ð  ûðE	7úðOùðKùðjúô ò IÜ�‰Ð;¸SÔAÜÐ2°3°%Ð8À%ÔHÔHá™HÜ˜9Ô%àÐÜ˜HŸM™MÕ*ð  ûðIûñ ™HÜ˜9Ô%àÐÜ˜HŸM™MÕ*ð  üsÓ   ‚AK0Á!I! Á:(K0Â#H Â5HÂ6H Â:)I! Ã#IÃ$2I! ÄIÄ+I! ÅIÅ+I! Å.(K0ÆAI! Ç(K0ÈH È	IÈIÈ#IÈ$I! È((K0ÉIÉI! ÉI! ÉI! É!	KÉ*%J<ÊKÊK Ê(K0Ê<KËK Ë)K-Ë-K0©Úmin_timeoutÚmessagesÚdefault_timeoutrÁ  c                ó  — |d}}	 t        di ¬«      xs i }|j                  d«      �%t        t        |d   «      |€t        d«      n|«      }|j                  d«      �t        |d   «      }d| ||dœ|rd|i¥S i ¥S # t        $ r Y Œw xY w)	zú``async_call_llm`` kwargs with ``auxiliary.vision.timeout`` / ``.temperature`` from config.
    Local vision models (llama.cpp, ollama) can take well over 30s, hence generous defaults
    (temperature 0.1); ``min_timeout`` lets video enforce a floor.gš™™™™™¹?r@   r*   r�   z-infÚtemperature)ÚtaskrÂ  rÅ  r�   rJ  )r3   r¡   rI   Úfloatr2   )rÂ  rJ  rÃ  rÁ  r�   rÅ  Ú_vision_cfgs          r   Ú_aux_call_kwargsrÉ  �  s¸   € ð
 +¨Cˆ[€GðÜ$ X°rÔ:Ò@¸bˆØ�?‰?˜9Ó%Ð1Üœ% ¨IÑ 6Ó7È+ÐJ]¼¸v¼ÐcnÓoˆGØ�?‰?˜=Ó)Ð5Ü ¨MÑ :Ó;ˆKð ¨(À;Ð[bñ 3Ù#(�˜Ðð3ð 3Ø.0ð3ð 3øô ò Ùðús   †A&A< Á<	BÂBÚuser_promptÚ	part_typer	  c                 ó$   — dd| dœd||d|iigdœgS )zJSingle user message: text + one ``image_url``/``video_url`` data-URL part.Úuserrl  rm  rn  rd   )Úroleru  rO   )rÊ  rË  r	  s      r   Ú_media_messagesrÏ  ¡  s6   € àØ Ñ-°¸	À9ÈuÐV^ÐN_Ð/`ð)bñ cð dð dr   )Ú402Úinsufficientzpayment requiredÚcreditsÚbillingzkInsufficient credits or payment required. Please top up your API provider account and try again. Error: {e}))údoes not supportznot support imageÚcontent_policyÚ
multimodalúunrecognized request argumentzimage inputzY{model} does not support vision or our request was not accepted by the server. Error: {e}))rÞ   r¾   z¼The vision API rejected the image. This can happen when the image is in an unsupported format, corrupted, or still too large after auto-resize. Try a smaller JPEG/PNG and retry. Error: {e}rH   ))rÔ  znot support videorÕ  rÖ  r×  zvideo inputÚ	video_urlz›The model does not support video analysis or the request was rejected. Ensure you're using a video-capable model (e.g. google/gemini-2.5-flash). Error: {e}zbThe video is too large for the API. Try compressing or trimming the video (max ~50 MB). Error: {e}Úvision_analyze_toolÚvideo_analyze_tool)ÚimageÚvideoÚkindÚsourcec                 óf   — t        |«      dkD  r|d d dz   n|}d| › d�|d|d|idd dd	d
dd|| › d�diS )Nrq  z...Ú
parametersÚ_urlrÊ  rJ  ro   rª  FÚanalysis_lengthr   Ú
model_usedÚ_size_bytes)rJ   )rÝ  rÞ  rÊ  rJ  rú   s        r   Ú_debug_call_datarå  È  sf   € Ü*-¨kÓ*:¸SÒ*@ˆ[˜˜#Ð Ò&Àk€Fà˜$˜˜t�} f¨m¸VÀWÈeÐTØ��y %Ð):¸A¸|ÈUÐW[ÐV\Ð\gÐThÐjkðmð mr   Úcall_kwargsÚ	empty_logc              ƒ   óÐ   K  — t        «        |€t        di | ¤Žƒ d{  –—† }t        |«      }|s1t        j	                  |«       t        t        di | ¤Žƒ d{  –—† «      }|S 7 ŒD7 Œ­w)z¸Aux vision LLM analysis text, retrying once on empty content (reasoning-only response).
    ``response``: an already-made first call (the image path handles size-error retries itself).NrO   )r   r   r   r«   r­   )ræ  rç  rt   Úanalysiss       r   Ú_call_vision_llmrê  Ï  sc   è ø€ ô ÔØÐÜ'Ñ6¨+Ñ6×6ˆÜ+¨HÓ5€HÙÜ�‰�yÔ!Ü/´nÑ6SÀ{Ñ6S×0SÓTˆØ€Oð 7øð 1Tús!   ‚A&�A"ž9A&ÁA$ÁA&Á$A&Ústagec           	   ƒ   ó
  ‡‡‡K  — t         |    \  Š}t        |t        «      s|�t        |«      nd}t        | |||«      Šg }dt        dt        fˆˆfd„}	 ddlm}  |«       rOt        dd	¬
«      |D ]=  }	|	sŒ|	j                  «       sŒ	 |	j                  «        t        j                  d| «       Œ? S t        j                  d| |dd «       t        j                  d|dd «        ||‰|«      ƒ d{  –—† \  }}|rt        |«      nd}t        j                  d| j!                  «       |«       |xs d| › d�}d|rd|› d|› �n|dœ}|r||d<   ‰j#                  d|¬«        ||«      |D ]=  }	|	sŒ|	j                  «       sŒ	 |	j                  «        t        j                  d| «       Œ? S # t        $ r#}
t        j                  d|
d¬«       Y d}
~
�Œad}
~
ww xY w7 Œç# t        $ r"}
t        j                  d|
d¬«       Y d}
~
Œ˜d}
~
ww xY w# t        $ rù}d| › dt        |«      › �}t        j%                  d|d¬«       t        |«      j'                  «       Št)        ˆfd„|D «       d| › d�«      }|j+                  ||¬ «      }|‰d!<    |d	||d"œ«      cY d}~|D ]k  }	|	sŒ|	j                  «       sŒ	 |	j                  «        t        j                  d| «       Œ?# t        $ r"}
t        j                  d|
d¬«       Y d}
~
Œed}
~
ww xY w S d}~ww xY w# |D ]k  }	|	sŒ|	j                  «       sŒ	 |	j                  «        t        j                  d| «       Œ?# t        $ r"}
t        j                  d|
d¬«       Y d}
~
Œed}
~
ww xY w w xY w­w)#ut  Aux-LLM analysis skeleton for image/video: interrupt check â†’ ``stage`` â†’ JSON result.

    ``stage(user_prompt, debug_call_data, temp_paths)`` returns ``(analysis, scale_note)``; temp
    files it appends to ``temp_paths`` are deleted in ``finally``. Returns JSON
    ``{"success": bool, "analysis": str}`` (``analysis`` carries the error explanation on failure).
    Nr?   Úresultr   c                 óˆ   •— t         j                  ‰‰«       t         j                  «        t        j                  | dd¬«      S )Nr—   F)ÚindentÚensure_ascii)Ú_debugÚlog_callr&  ÚjsonÚdumps)rí  Údebug_call_dataÚ	tool_names    €€r   Úfinishz_run_analysis.<locals>.finishë  s-   ø€ Ü�‰˜	 ?Ô3Ü�‰ŒÜ�z‰z˜&¨¸Ô?Ð?r   r   r«  r­  Fr©  zCleaned up temporary %s filez#Could not delete temporary file: %sTr”   zAnalyzing %s: %sé<   zUser prompt: %sr–   z%%s analysis completed (%s characters)z-There was a problem with the request and the z could not be analyzed.ú[z] )rª  ré  rj  )rª  râ  zError analyzing z: z%sc              3   óR   •K  — | ]  \  }}t        ˆfd „|D «       «      sŒ|–— Œ  y­w)c              3   ó&   •K  — | ]  }|‰v –— Œ
 y ­wr7   rO   rØ   s     €r   rÜ   z*_run_analysis.<locals>.<genexpr>.<genexpr>  s   øè ø€ Ò/RÀD°¸´Ñ/RùrÝ   N)rß   )rÙ   ÚhintsÚtplrÛ   s      €r   rÜ   z _run_analysis.<locals>.<genexpr>  s"   øè ø€ ÒS‘Z�U˜C¬CÓ/RÈEÔ/RÕ,RŒSÑSùs   ƒ' 'z" could not be analyzed. Error: {e})r»   rJ  ro   )rª  ro   ré  )Ú_ANALYSIS_KINDSri   rj   rå  r†  r³  r¬  r¯  Úexistsrª   r«   r¬   r2   r­   r  rJ   Ú
capitalizer  ro   r°   Únextr  )rÝ  rÞ  rÊ  rJ  rë  ÚrulesÚ
temp_pathsr÷  r¬  rz  Úcleanup_errorré  rj  râ  rí  r»   Ú	error_msgÚtemplaterõ  rÛ   rö  s                     @@@r   Ú_run_analysisr  Ü  sp  úè ø€ ô ' tÑ,Ñ€IˆuÜ�k¤3Ô'Ø*5Ð*A”c˜+Ô&ÀrˆÜ& t¨V°[À%ÓH€OØ€Jð@”tð @¤ö @ð
 hÝ2ÙÔÜ˜m°UÔ;ð. ò 	hˆDÚ˜Ÿ™�ðhØ—K‘K”MÜ—L‘LÐ!?ÀÕFñ		hô- 	�‰Ð&¨¨f°S°b¨kÔ:Ü�‰Ð% {°4°CÐ'8Ô9Ù%*¨;¸ÈÓ%T×TÑˆ�*Ù+3œ#˜hœ-¸ˆÜ�‰Ð;¸T¿_¹_Ó=NÐP_Ô`ØÒlÐ!NÈtÈfÐTkÐlˆØ!Éz°°:°,¸bÀÀ
Ñ/KÐ_gÑhˆÙØ#-ˆF�<Ñ Ø×Ñ t¸_ÐÔMÙ�f‹~ð ò 	hˆDÚ˜Ÿ™�ðhØ—K‘K”MÜ—L‘LÐ!?ÀÕFñ		høô
 !ò hÜ—N‘NÐ#HÈ-Ðbf�N×gÒgûðhúð3  Uùô2 !ò hÜ—N‘NÐ#HÈ-Ðbf�N×gÑgûðhûô! ò 	TØ& t f¨B¬s°1«v¨hÐ7ˆ	Ü�‰�T˜9¨tˆÔ4Ü�a“&—,‘,“.ˆÜÛS 5ÔSØ;¸D¸6ÐAeÐfóhˆð —?‘? Q¨e�?Ó4ˆØ#,ˆ˜Ñ Ù %°)ÈÑRÓSÔSàò 	hˆDÚ˜Ÿ™�ðhØ—K‘K”MÜ—L‘LÐ!?ÀÕFøÜ ò hÜ—N‘NÐ#HÈ-Ðbf�N×gÑgûðhúñ	hûð	Tûð ò 	hˆDÚ˜Ÿ™�ðhØ—K‘K”MÜ—L‘LÐ!?ÀÕFøÜ ò hÜ—N‘NÐ#HÈ-Ðbf�N×gÑgûðhúñ	hüs)  …ANÁH	 Á.NÁ6NÂ&F*Â.NÂ1A H	 Ã1GÃ2A5H	 Å'NÅ/NÆ&GÆ'NÆ*	GÆ3GÇNÇGÇNÇH	 Ç	HÇ$HÇ<NÈHÈNÈ		LÈA>LÊLÊL ÊNÊNÊ/&KËNË	LËK<Ë7NË<LÌNÌLÌL ÌN ÌN Ì)&MÍN Í	M;	ÍM6	Í1N Í6M;	Í;N Î Nc              ƒ   ó†   ‡ ‡‡‡K  — dt         dt        dt        dt        fˆ ˆˆˆfd„}t	        d‰ |‰|«      ƒ d{  –—† S 7 Œ­w)z´Describe an image (URL, local path, data: URL) with the auxiliary vision LLM. ``user_prompt``
    is pre-formatted by the caller. Temp images live under $HERMES_HOME/cache/vision/.rú   rõ  r  r   c              “   ó†  •K  — t        ‰‰‰d¬«      ƒ d {  –—† }|j                  |j                  «       t        j	                  d|j
                  dz  «       t        j	                  d«       t        t        |j                  |j                  ¬«      ƒ d {  –—† }t        j	                  dt        |«      dz  «       i }t        |«      t        kD  r:t        ||«      ƒ d {  –—† }t        |«      t        kD  rt        t        |«      «      ‚|j
                  |d<   t        | d	|«      }t        j	                  d
«       t        |‰d«      }t!        «        	 t#        di |¤Žƒ d {  –—† }t+        |d|«      ƒ d {  –—† }
|
t-        |xs d |j.                  xs d «      fS 7 �Œ‡7 �Œ	7 ŒÁ7 ŒA# t$        $ rŒ}	t'        |	«      rt        |«      t(        kD  s‚ t        j	                  dt        |«      dz  t(        dz  «       t        ||«      ƒ d {  –—†7  }||d   d   d   d	   d<   t#        di |¤Žƒ d {  –—†7  }Y d }	~	ŒÏd }	~	ww xY w7 ŒÆ­w)NFr®  zImage ready (%.1f KB)ro  zConverting image to base64...r  z#Image converted to base64 (%.1f KB)ri  r¾   z%Processing image with vision model...g      ^@zYAPI rejected image (%.1f MB, likely too large); auto-resizing to ~%.0f MB and retrying...r  r   ru  rH   rd   z0Vision LLM returned empty content, retrying oncerO   )rŸ  rí   rz  r«   r  rr  rc   rÐ   rÏ   rJ   r£  r§  r9   r¤  rÏ  rÉ  r   r   r2   rá   Ú_RESIZE_TARGET_BYTESrê  r÷   rã   )rú   rõ  r  r¥  rh  r¼  rÂ  ræ  rt   Ú_api_errré  r¾   rJ  rˆ  r‡  s              €€€€r   rë  z"vision_analyze_tool.<locals>.stage  s  øè ø€ Ü'¨	°7¸FÐTYÔZ×ZˆØ×Ñ˜(Ÿ-™-Ô(Ü�‰Ð+¨X×-@Ñ-@À4Ñ-GÔHä�‰Ð3Ô4Ü:Ü% x§}¡}ÀÇÁô O÷ Oˆä�‰Ð9¼3¸~Ó;NÐQUÑ;UÔVØˆÜˆ~ÓÔ!2Ò2Ü#3°H¸kÓ#J×JˆNÜ�>Ó"Ô%6Ò6Ü Ô!3°NÓ!CÓDÐDØ.6×.AÑ.AˆÐ*Ñ+Ü" 6¨;¸ÓGˆÜ�‰Ð;Ô<Ü& x°¸Ó>ˆÜÔ ð
	;Ü+Ñ:¨kÑ:×:ˆHô *ØÐKÈXóW÷ WˆàÔ*¨;Ò+>¸$À×@TÑ@TÒ@\ÐX\Ó]Ð]Ð]ð? [ùð
Oùð
 Køð ;ùÜò 	;Ü(¨Ô2´s¸>Ó7JÔMaÒ7aØÜ�K‰KØkÜ�NÓ# {Ñ3Ô5IÈ[Ñ5Yô[ô $4°H¸kÓ#J×JÐJˆNØ<JˆH�Q‰K˜	Ñ" 1Ñ% kÑ2°5Ñ9Ü+Ñ:¨kÑ:×:Ð:�Hûð	;úðWús—   ƒI–F—B IÂF ÂA	IÃ!F#Ã"A2IÅF' Å#F%Å$F' Å(IÅ8H?Å9%IÆ IÆ#IÆ%F' Æ'	H<Æ0AH7ÈH
È$H7È,H/È-H7È2IÈ7H<È<IrÛ  N©rj   r†  ÚlistÚtupler  )r¾   rÊ  rJ  r‡  rˆ  rë  s   ` ``` r   rÙ  rÙ    sO   ûè ø€ ð
 ^œCð  ^´$ð  ^ÄDð  ^ÌU÷  ^ð  ^ôB ˜w¨	°;ÀÀuÓM×MÐMÐMús   †4Aº?»Ac                  ó~   ‡— ddl m} mŠ  | «       5  t        ˆfd„i ddifD «       «      cddd«       S # 1 sw Y   yxY w)ub  True when ``call_llm(task="vision")`` could resolve a client.

    Mirrors its fallback chain: explicit ``auxiliary.vision.provider``, then auto (main
    provider â†’ openrouter â†’ nous) â€” without the auto step the tool would vanish whenever
    the explicit name was unresolvable. Probe mode skips real SDK client construction.

    See #31179.
    r   ©Úaux_probe_modeÚresolve_vision_provider_clientc              3   ó8   •K  — | ]  } ‰di |¤Žd    du–— Œ y­w)rH   NrO   rO   )rÙ   Úkwr  s     €r   rÜ   z+check_video_requirements.<locals>.<genexpr>I  s)   øè ø€ ò 
ØDFÑ*Ñ0¨RÑ0°Ñ3¸4Ô?ñ
ùs   ƒrI  ÚautoN)re  r  r  rß   r  s    @r   Úcheck_video_requirementsr  <  sG   ø€ ÷ Vñ 
Ó	ñ 
Üó 
ØKMÐPZÐ\bÐOcÐJdô
ó 
÷
÷ 
ò 
ús   ‘3³<c                  ó.   — t        «       xs
 t        «       S )u~  Image gate (``vision_analyze``, ``browser_vision``): an aux vision client OR the native fast
    path. Both handlers attach pixels straight to a vision-capable main model, so a main model on a
    provider the aux resolver does not know (OAuth, local vLLM) must not hide a working tool (#47149).
    ``video_analyze`` keeps the aux-only gate â€” its handler has no native path.
    )rf  r  rO   r   r   Úcheck_vision_requirementsr  N  s   € ô /Ó0ÒNÔ4LÓ4NÐNr   )Úregistryr¯  Úvision_analyzeu‡   Load an image into the conversation so you can see it. Call it any time the user references an image â€” then answer from what you see.ÚobjectÚstringz>Image URL (http/https), local file path, or data: URL to load.)rn  Údescriptionz)Your question or request about the image.Úarrayrn  Úintegerr  uä   Optional [x1, y1, x2, y2] crop in ORIGINAL-image pixel coordinates, applied before any downscaling â€” the crop keeps full resolution. Load the full image first, then re-call with a region to zoom into small text or fine detail.)rn  ÚitemsÚminItemsÚmaxItemsr  )r¾   rg  rˆ  )rn  Ú
propertiesÚrequired)r£   r  rà  ÚsectionsÚenv_varsc                 óÌ   — | D ]F  }t        |d«      }|sŒt        |«      j                  «       rt        |«      j                  «       c S  n t        d„ d„ |D «       D «       d«      S )z‚First non-empty ``auxiliary.<section>.model`` from config.yaml, else the first non-empty
    env var (legacy override), else None.rJ  c              3   ó&   K  — | ]	  }|sŒ|–— Œ y ­wr7   rO   )rÙ   Úvs     r   rÜ   z(_configured_aux_model.<locals>.<genexpr>�  s   è ø€ ÒN�qÊA”ÑNùs   ‚Šc              3   ód   K  — | ](  }t        j                  |d «      j                  «       –— Œ* y­w)r?   N)rA   rB   rC   )rÙ   r»   s     r   rÜ   z(_configured_aux_model.<locals>.<genexpr>�  s$   è ø€ ÒH¸!œRŸY™Y q¨"Ó-×3Ñ3×5ÑHùs   ‚.0N)r3   rj   rC   r  )r%  r&  ÚsectionÚ_vmodels       r   Ú_configured_aux_modelr-  „  sd   € ð ò ˆÜ  ¨'Ó2ˆÚÜ�7‹|×!Ñ!Ô#Ü˜7“|×)Ñ)Ó+Ò+Ùðô ÑNÑH¸xÔHÔNÐPTÓUÐUr   r`   r  c              ‹   ó\  K  — | j                  dd«      | j                  dd«      | j                  d«      }}}|j                  d«      }t        «       r,t        j                  d«       t	        ||||¬«      ƒ d {  –—† S d|› �}t        d	d
«      }t        |||||¬«      ƒ d {  –—† S 7 Œ-7 Œ­w)Nr¾   r?   rg  rˆ  r‡  z vision_analyze: native fast path)r‡  rˆ  z]Fully describe and explain everything about this image, then answer the following question:

)r@   )ÚAUXILIARY_VISION_MODEL)r¡   rf  r«   r  r¿  r-  rÙ  )r`   r  r¾   rg  rˆ  r‡  Úfull_promptrJ  s           r   Ú_handle_vision_analyzer1  �  s¶   è ø€ Ø"&§(¡(¨;¸Ó";¸T¿X¹XÀjÐRTÓ=UÐW[×W_ÑW_Ð`hÓWi˜ˆx€IØ�f‰f�YÓ€Gô +Ô,Ü�‰Ð6Ô7Ü+¨I°xÈÐY_Ô`×`Ð`ð	"Ø"* ð	-ð ô " +Ð/JÓK€EÜ$ Y°¸UÈGÐ\bÔc×cÐcð aøð dús$   ‚A8B,Á:B(Á;(B,Â#B*Â$B,Â*B,r@   Tu   ðŸ‘�ï¸�)r£   ÚtoolsetÚschemaÚhandlerÚcheck_fnÚis_asyncÚemojiú	video/mp4z
video/webmz	video/movz
video/mpeg)ú.mp4z.webmz.movz.aviz.mkvz.mpegz.mpgÚ
video_pathc                 ó\   — t         j                  | j                  j                  «       «      S )z7Video MIME type from extension, or None if unsupported.)Ú_VIDEO_MIME_TYPESr¡   Úsuffixr°   )r:  s    r   Ú_detect_video_mime_typer>  »  s"   € ä× Ñ  ×!2Ñ!2×!8Ñ!8Ó!:Ó;Ð;r   r=  c           	      óf   — d| › ddj                  t        t        j                  «       «      «      › �S )NzUnsupported video format: 'z'. Supported: rê   )rî   Úsortedr<  r,   )r=  s    r   Ú_unsupported_video_formatrA  À  s.   € Ø(¨¨°¸t¿y¹yÌÔPa×PfÑPfÓPhÓIiÓ?jÐ>kÐlÐlr   c                 ó˜   — |xs t        | «      xs d}d|› dt        j                  | j                  «       «      j	                  d«      › �S )Nr8  rÈ   rÉ   rÊ   )r>  rË   rÌ   rÍ   rÎ   )r:  rÆ   rÏ   s      r   Ú_video_to_base64_data_urlrC  Ä  sK   € ØÒJÔ/°
Ó;ÒJ¸{€DØ�4�&˜¤×!1Ñ!1°*×2GÑ2GÓ2IÓ!J×!QÑ!QÐRYÓ!ZÐ [Ð\Ð\r   rØ  r  c           
   ƒ   ó¾  K  — ddl m}m}m}m} | j                  d«      }t        t        j                  j                  |«      «      }| xs dj                  «       j                  «       }	t        |	«      xr |	j                  d«       }
 |«       sÛ|
rÙt        j                  d| «       t        |«      j                   j                  «       }|t"        vrt%        t'        |«      «      ‚	  ||  ||¬«      d¬	«      ƒ d
{  –—† }t)        dd«      }|j+                  dd¬«       |dt-        j.                  «       › |› �z  }|j1                  |j2                  «       |j5                  |«       |S |j7                  «       r/ddlm}  |t=        |«      «       t        j                  d| «       |S t?        | «      ƒ d
{  –—† rrtA        | «      }|rtC        |d   «      ‚t)        dd«      dt-        j.                  «       › d�z  }|j5                  |«       tE        | |dddtF        dd¬«      ƒ d
{  –—†  |S t%        d«      ‚7 �Œ=# |$ r}t%        d|› �«      |‚d
}~ww xY w7 Œ 7 Œ2­w)u‚  Local video path for a terminal-backend path, local file, or HTTP(S) URL. Only files created
    here are appended to ``temp_paths`` â€” never user-provided paths. Terminal-backend reads use the
    shared media resolver with ``permitted=("video",)`` â€” the exact pipeline vision_analyze uses
    (media-cache host reads, bounded in-sandbox exec-read, credential-read guard, 50MB cap).r   )r‹  rŒ  Ú_is_local_terminal_backendr�  zfile://r?   )rf   rg   rÈ   z-Reading video source via terminal backend: %srŽ  )rÜ  )Ú	permittedNz,Could not read video from terminal backend: zcache/videoÚtemp_video_filesTr†   Úterminal_video_)Úraise_if_read_blockedzUsing local video file: %sr‰   Útemp_video_r9  r  ÚVideozvideo/*,*/*;q=0.8g      N@rÁ   zKInvalid video source. Provide an HTTP/HTTPS URL or a valid local file path.)$r’  r‹  rŒ  rE  r�  Úremoveprefixr   rA   rz  Ú
expanduserrC   r°   rV  rk   r«   r  r=  r<  r9   rA  r   rœ   r¤   r¥   r”  r•  rí   Úis_fileÚagent.file_safetyrI  rj   rn   r   rq   r½   Ú_MAX_VIDEO_BASE64_BYTES)rØ  r‡  r  r‹  rŒ  rE  r�  rÞ  Ú
local_pathÚloweredÚ	path_liker=  r—  r.  r˜  rz  rI  r³   s                     r   Ú_materialize_videorT  É  sC  è ø€ ÷
ó ð ×#Ñ# IÓ.€FÜ”b—g‘g×(Ñ(¨Ó0Ó1€JØŠ˜B×%Ñ%Ó'×-Ñ-Ó/€GÜ�W“ÒZ g×&8Ñ&8Ð9YÓ&ZÐ"Z€IÙ%Ô'©IÜ�‰ÐCÀYÔOÜ�f“×$Ñ$×*Ñ*Ó,ˆØÔ*Ñ*ÜÔ6°vÓ>Ó?Ð?ð	\Ù1Ø™>°'Ô:ÀjôR÷ RˆHô " -Ð1CÓDˆØ�‰˜t¨dˆÔ3Ø˜O¬D¯J©J«L¨>¸&¸ÐBÑBˆØ×Ñ˜Ÿ™Ô'Ø×Ñ˜$ÔØˆØ×ÑÔÝ;Ùœc *›oÔ.Ü�‰Ð0°)Ô<ØÐÜ& yÓ1×1Ð1Ü& yÓ1ˆÙÜ! '¨)Ñ"4Ó5Ð5Ü˜mÐ-?Ó@À[ÔQU×Q[ÑQ[ÓQ]ÐP^Ð^bÐCcÑcˆØ×Ñ˜$ÔäØ�t˜Q¨GÐ<OÜ-°tÀtôM÷ 	Mð 	Mð ˆÜ
ÐbÓ
cÐcð5Rúà#ò 	\ÜÐKÈCÈ5ÐQÓRÐX[Ð[ûð	\úð 2øð	Mús\   ‚C%IÃ(H= Ã=H:Ã>H= ÄB6IÆ8IÆ9A/IÈ(IÈ)IÈ:H= È=IÉIÉIÉIÉIc              ƒ   ó‚   ‡ ‡‡K  — dt         dt        dt        dt        fˆˆˆ fd„}t	        d‰ |‰|«      ƒ d{  –—† S 7 Œ­w)zEAnalyze a video via multimodal LLM. Returns JSON {success, analysis}.rú   rõ  r  r   c              “   ó<  •K  — t        ‰‰|«      ƒ d {  –—† }|j                  «       j                  }|dz  }t        j	                  d|«       t        |«      }|st        t        |j                  «      «      ‚|t        kD  rt        j                  d|«       t        ||¬«      }t        |«      t        kD  r't        dt        |«      dz  d›dt        dz  d›d	�«      ‚||d
<   t        | d|«      }t        |‰dd¬«      }	t!        |	d«      ƒ d {  –—† }
|
d fS 7 �Œ7 Œ­w)Nr  zVideo ready (%.1f MB)u,   Video is %.1f MB â€” may be slow or rejectedr  z+Video too large for API: base64 payload is rp  r¡  r¢  z+ MB). Compress or trim the video and retry.Úvideo_size_bytesrØ  g     €f@rÀ  z#Empty video response, retrying once)rT  r  r  r«   r  r>  r9   rA  r=  Ú_VIDEO_SIZE_WARN_BYTESr­   rC  rJ   rP  rÏ  rÉ  rê  )rú   rõ  r  Útemp_video_pathrW  Úvideo_size_mbÚdetected_mimeÚvideo_data_urlrÂ  ræ  ré  rJ  r‡  rØ  s              €€€r   rë  z!video_analyze_tool.<locals>.stageû  s/  øè ø€ Ü 2°9¸gÀzÓ R×RˆØ*×/Ñ/Ó1×9Ñ9ÐØ(¨KÑ8ˆÜ�‰Ð+¨]Ô;Ü/°Ó@ˆÙÜÔ6°×7MÑ7MÓNÓOÐOØÔ4Ò4Ü�N‰NÐIÈ=ÔYÜ2°?ÈmÔ\ˆÜˆ~ÓÔ!8Ò8ÜØ=¼cÀ.Ó>QÐU`Ñ>aÐbeÐ=fð gÜ1°[ÑAÀ#ÐFð G8ð9ó:ð :ð /?ˆÐ*Ñ+Ü" 6¨;¸ÓGˆÜ& x°¸È5ÔQˆÜ)¨+Ð7\Ó]×]ˆØ˜ˆ~Ðð' Sùð$ ^ús"   ƒD”D•C9DÄDÄ	DÄDrÜ  Nr  )rØ  rÊ  rJ  r‡  rë  s   ` `` r   rÚ  rÚ  ø  sC   úè ø€ ðœCð ´$ð ÄDð ÌU÷ ô* ˜w¨	°;ÀÀuÓM×MÐMÐMús   …3?¸=¹?Úvideo_analyzeu?  Analyze a video from a URL or local file path using a multimodal AI model. Sends the video to a video-capable model (e.g. Gemini) for understanding. Use this for video files â€” for images, use vision_analyze instead. Supports mp4, webm, mov, avi, mkv, mpeg formats. Note: large videos (>20 MB) may be slow; max ~50 MB.z5Video URL (http/https) or local file path to analyze.zpYour specific question about the video. The AI will describe what happens in the video and answer your question.)rØ  rg  c                 ó¨   — | j                  dd«      | j                  dd«      }}d|› �}t        dd«      }t        ||||j                  d«      ¬«      S )	NrØ  r?   rg  z¸Fully describe and explain everything happening in this video, including visual content, motion, audio cues, text overlays, and scene transitions. Then answer the following question:

)rÜ  r@   )ÚAUXILIARY_VIDEO_MODELr/  r‡  rŽ  )r¡   r-  rÚ  )r`   r  rØ  rg  r0  rJ  s         r   Ú_handle_video_analyzer`  -  s`   € ØŸ(™( ;°Ó3°T·X±X¸jÈ"Ó5Mˆx€Ið	?à?G¸jð	Jð ô "Ð"5Ð7jÓk€EÜ˜i¨°eÀRÇVÁVÈIÓEVÔWÐWr   rÜ  u   ðŸŽ¬)r   Nr7   )r  )r?   )NN)NNN)Šr‚  rË   rZ   ró  Úconcurrent.futuresr   Úior   ÚloggingrA   r¤   Úpathlibr   Útypingr   r   r   r	   r
   r   Úurllib.parser   rr   r   r…  r   r   Úhermes_constantsr   Útools.debug_helpersr   Útools.website_policyr   Ú!tools.vision_tools_history_budgetr   r°  r   r·  r   r´  r   r±  r   r²  r   rµ  Útools.vision_tools_image_prepr    r!   r"   r#   r$   r%   r&   Ú	getLoggerr  r«   rñ  rj   r3   rD   rÇ  rÃ   rÂ   rT   rP   rU   Ú_VISION_CPU_WORKERSr]   rc   rV  rn   r2   rw   rŸ   r{   r½   rÄ   rÐ   r£  r¶  r
  rà   rá   r†  r÷   rÿ   r7  Ú	frozensetrT  rU  rN  rZ  r_  rf  ry  r|  r9   r~  r„  r  rŸ  r¤  r§  r¿  rÉ  rÏ  Ú_BILLING_HINTSÚ_IMAGE_ERROR_RULESÚ_VIDEO_ERROR_RULESrþ  rå  rê  r  r  rÙ  r  r  Útools.registryr  r¯  ÚVISION_ANALYZE_SCHEMAr-  r1  Úregisterr<  rP  rX  r>  rA  rC  rT  rÚ  ÚVIDEO_ANALYZE_SCHEMAr`  Ú
contextlibÚsysÚ	threadingrO   r   r   ú<module>ry     s°  ðòó Û Û Ý 1Ý Û Û 	Û Ý ß G× GÝ !Û ð €�Ó Ø$(Ð ˜cÓ (óiõ ,Ý ,Ý 5÷÷ ÷&÷ &ñ &ð 
ˆ×	Ñ	˜8Ó	$€á	�nÐ.BÔ	C€ð (,ò ˜#ó ñ
N #ð 
N¨Có 
Nñ 0Ð0PÐRdÐfkÓlÐ ØÐ#Ø#Ðð .Ð ð+˜3ó +ð& Só &ñ 2Ó3Ð á)Ø#¸ôÐ ò
dð(¨ð (°ó (ð¨	ð °dó ð9ð òZðMmØ	ðMmØðMmØ.1ðMmàðMmà!ðMmà.1ðMmà<AðMmàNRðMmàW[óMmñ`a Sð a°tð aÈ#ð aÐVZó añ]¨$ð ]¸8ÀC¹=ð ]ÐTWó ]ð %Ð ð Ð ð 'Ð ðÐ ða 	ð a¨dó að. (¨4¡.ð .¸xÈ¹~ð .ÐRZÐ[^ÑR_ó .ò(ð& KOØ6JØ=AØ:>Ø16ñ	V¨ð V¸(À3¹-ð VØ03ðVà-5°c©]ðVð *2°$©ðVð +/ð	Vð <?ó	Vñ|  )ò *ó  Ð ñ
 Ò[Ó\Ð ñ¨#ð °cð À4ó ð¨cð ¸#ð À$ó ð(
A¨#ð 
A°cð 
AÀÈÈcÐSVÈhÉÑ@Xð 
AÐ]aó 
Að¨Tó ð* !%ñgØðgØ!ðgØ36ðgØJMðgà˜‘ðgð 
ˆ#ˆsˆ(�^ógð0˜( 4™.ð ¨Tó ôH�jô Hô�Zô ð)?Øð)?Ø% c™]ð)?Ø4<¸T±Nð)?ØX\ð)?àó)?ðX[ sð [¨só [ð ^ð Àð ÐTWó ð \`ñ:+Øð:+Ø!ð:+Ø,4°S©Mð:+ØJRÐSWÉ.ð:+àó:+ð| 59ò3˜tð 3¨H°S©Mð 3ÈEð 3Ø"*¨5¡/ð3Ø=Aó3ð$d ð d°ð dÀð dÈó dð S€àð6ð7ð+ððÐ ð Ð'¨Ñ*¨1Ñ-Ð.ð3ð
 ð*ð+ð
Ð ð $Ð%7Ð8Ø"Ð$6Ð7ñ9€ð
m˜3ð m¨ð m¸#ð mÈó mñ
¨ð 
¸ó 
ð4hØ
ð4hØð4hØ),ð4hØ5=¸c±]ð4hà�S˜$ Ð% y°Ñ'7Ð7Ñ8ð4hà=@ó4hðp 48Ø<@ñ&NØð&NØ!$ð&NØ-0ð&Nà�c‰]ð&Nà+3°D©>ð&NàEHó&NðR
 $ó 
ð$O 4ó O÷ 0ð ð	ð
 ð !Ø_ñð
 !ØJñð
  Ø  )Ð,ØØðññ
ð. ! *Ð-ñ3ñ(Ð ðV	V Eð 	V°Uð 	V¸xÈ¹}ó 	Vðd t¨C°¨H¡~ð d¸Sð dÀSó dð" €× Ñ Ø	ØØ Ø"Ø&ØØ
õð ØØØØØØñÐ ð +Ð Ø)Ð ð<¨ð <°¸#±ó <ð
m cð m¨có mñ]¨$ð ]¸8ÀC¹=ð ]ÐTWó ]ð
,d¨ð ,d°h¸s±mð ,dÐQUð ,dÐZ^ó ,dð` SWñNØðNØ!$ðNØ-0ðNØBJÈ3Á-ðNØ[^óNð8 ð	?ð ð !ØVñð
 !ð  Rññ	
ð ! *Ð-ññÐ ð4X  S¨# X¡ð X°cð X¸iÈ¹nó Xð €× Ñ Ø	ØØØ!Ø%ØØ
õó Û 
Ü r   