Ë
    ãß²jŸ>  ã                   ó  — d Z ddlZddlZddl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 ddlmZ ddlmZmZmZmZ ddlmZ ddlmZ dd	lmZ dd
lmZ ddlmZ  ej@                  d¬«      de!e"df   fd„«       Z#de$e"   fd„Z%d,de"de"fd„Z&de"fd„Z'de"de(fd„Z)de"de(fd„Z*de"fd„Z+de"dz  de(fd„Z,dee"   fd„Z-de"fd„Z.ddœd e(de"fd!„Z/d-d"e0de(fd#„Z1de
e"   fd$„Z2d%e"de(fd&„Z3de(fd'„Z4de(fd(„Z5de(fd)„Z6de(fd*„Z7de(fd+„Z8y).u-  agent-browser / Chromium discovery and install: PATH merging, npx resolution, candidate binaries, Chromium detection + auto-install, requirement checks.

Split out of ``tools/browser_tool.py``. Facade-owned state is read through ``_bt`` (``tools.browser_tool``, resolved per call) â€” no import cycle.é    N)ÚPath)ÚListÚOptional)Úwindows_hide_flags)Úagent_browser_runnableÚget_hermes_homeÚ	is_termuxÚnode_tool_runnable)Úorigin_module)Úbrowser_tool_cdp)Úbrowser_tool_cloud)Úbrowser_tool_lifecycle)Ú browser_tool_lightpanda_fallbacké   )ÚmaxsizeÚreturn.c                  óÄ   ‡‡— dŠ	 t         j                  j                  ‰«      rt        j                  ‰«      ng } t        ˆˆfd„| D «       «      S # t        $ r g } Y Œ"w xY w)zbHomebrew versioned Node bin dirs (node@20, ...) that ``brew`` may not link into /opt/homebrew/bin.z/opt/homebrew/optc              3   óÎ   •K  — | ]\  }|j                  d «      rI|d k7  rDt        j                  j                  t        j                  j	                  ‰|d«      xŠ«      r‰–— Œ^ y­w)ÚnodeÚbinN)Ú
startswithÚosÚpathÚisdirÚjoin)Ú.0ÚentryÚbin_dirÚhomebrew_opts     €€ú?/home/ubuntu/.hermes/hermes-agent/tools/browser_tool_install.pyú	<genexpr>z/_discover_homebrew_node_dirs.<locals>.<genexpr>   sS   øè ø€ ò àØ×Ñ˜FÔ#¨°ªÜ�7‰7�=‰=¤B§G¡G§L¡L°¸uÀeÓ$LÐL˜ÔMô 	ñùs   ƒA"A%)r   r   r   ÚlistdirÚOSErrorÚtuple)Úentriesr   r   s    @@r    Ú_discover_homebrew_node_dirsr&      s`   ù€ ð '€LðÜ.0¯g©g¯m©m¸LÔ.I”"—*‘*˜\Ô*Èrˆô ô àôó ð øô ò ØŠðús   †6A ÁAÁAc                  ó¢   — t        «       } t        «       }|dz  dz  |dz  |dz  dz  f}g t        t        |«      ¢t	        «       ¢| j
                  ¢S )zMReturn ordered browser CLI PATH candidates shared by discovery and execution.r   r   Únode_modulesú.bin)Ú_originr   ÚmapÚstrr&   Ú_SANE_PATH_DIRS)Ú_btÚhomeÚmanageds      r    Ú_browser_candidate_path_dirsr1   '   sZ   € ä
‹)€CÜÓ€DØ�f‰}˜uÑ$ d¨V¡m°T¸NÑ5JÈVÑ5SÐT€GØVŒS”�gÓÐVÔ!=Ó!?ÐVÀ#×BUÑBUÐVÐVó    Úexisting_pathc                 óT  — | xs dj                  t        j                  «      D �cg c]  }|sŒ|‘Œ	 }}g }t        «       D ]@  }|sŒ||vsŒ||vsŒt        j                  j                  |«      sŒ0|j                  |«       ŒB t        j                  j                  ||z   «      S c c}w )zLPrepend browser-specific PATH fallbacks without reordering existing entries.Ú )Úsplitr   Úpathsepr1   r   r   Úappendr   )r3   ÚpÚ
path_partsÚprefix_partsÚparts        r    Ú_merge_browser_pathr=   /   s‘   € à+Ò1¨r×8Ñ8¼¿¹ÓDÖJ˜Ê’!ÐJ€JÐJØ €LÜ,Ó.ò &ˆÚ�D 
Ò*¨t¸<Ò/GÌBÏGÉGÏMÉMÐZ^ÕL_Ø×Ñ Õ%ð&ô �:‰:�?‰?˜<¨*Ñ4Ó5Ð5ùò Ks
   ¦B%®B%c                  ó(   — dt        «       rdz   S dz   S )Nz5npm install -g agent-browser && agent-browser installr5   z --with-deps)Ú_is_termux_environment© r2   r    Ú_browser_install_hintrA   9   s   € ØBÔLbÔLdÀbÑyÐyÐjxÑyÐyr2   Úbrowser_cmdc                 óL   — | j                  «       t        «       j                  k(  S ©N)Ústripr*   ÚNPX_AGENT_BROWSER_SENTINEL©rB   s    r    Ú_is_npx_agent_browser_sentinelrH   =   s   € Ø×ÑÓ¤'£)×"FÑ"FÑFÐFr2   c                 ó\   — t        «       xr! t        j                  «       xr t        | «      S rD   )r?   Ú_cloudÚ_is_local_moderH   rG   s    r    Ú%_requires_real_termux_browser_installrL   A   s%   € Ü!Ó#Òo¬×(=Ñ(=Ó(?ÒoÔDbÐcnÓDoÐor2   c                  ó   — dt        «       › �S )NzqLocal browser automation on Termux cannot rely on the bare npx fallback. Install agent-browser explicitly first: )rA   r@   r2   r    Ú_termux_browser_install_errorrN   E   s&   € Ø~ô  @Uó  @Wð  Xð  Yð  Yr2   r   c                 ó
  — | syd| v r#| j                  «       d   j                  d«      ryt        j                  j	                  | «      xr9 t        j
                  dk(  xs$ t        j                  | t        j                  «      S )NFÚ r   ÚnpxTÚnt)r6   Úendswithr   r   ÚexistsÚnameÚaccessÚX_OK©r   s    r    Ú _agent_browser_candidate_presentrY   I   s]   € ÙØØ
ˆd�{�t—z‘z“| A‘×/Ñ/°Ô6ØÜ�7‰7�>‰>˜$ÓÒQ¤R§W¡W°¡_Ò%P¼¿	¹	À$ÌÏÉÓ8PÐQr2   c                  óŒ   — t        d«      } | r| gng dgz   D ]+  }t        j                  d|¬«      }|sŒt        |«      sŒ)|c S  y)zèResolve a runnable npx, extended (Hermes-managed/Homebrew) PATH first.

    Bare PATH first would let a broken system npx shadow a healthy managed one,
    so every candidate is validated with ``node_tool_runnable`` before use.
    r5   NrQ   rX   )r=   ÚshutilÚwhichr
   )Úextended_pathr   rQ   s      r    Ú_resolve_npx_binr^   Q   sO   € ô (¨Ó+€MÙ$1�-‘°r¸d¸VÑCò ˆÜ�l‰l˜5 tÔ,ˆÚÔ% cÕ*ØŠJðð r2   r]   c              #   ó(  K  — t        j                  d«      –— | rt        j                  d| ¬«      –— t        t        «      j                  j                  dz  dz  }|j                  «       r#t        j                  dt        |«      ¬«      –— yy­w)u+  Yield agent-browser lookup candidates lazily: ambient PATH â†’ extended PATH â†’ repo-local node_modules/.bin.

    The local lookup uses ``shutil.which`` with an explicit path so Windows resolves the ``.cmd`` shim
    (CreateProcess cannot run npm's extensionless POSIX shim â€” WinError 193).
    úagent-browserrX   r(   r)   N)r[   r\   r   Ú__file__ÚparentÚis_dirr,   )r]   Úlocal_bin_dirs     r    Ú_agent_browser_candidatesre   _   sq   è ø€ ô �,‰,�Ó
'Ò'ÙÜ�l‰l˜?°Ô?Ò?Üœ“N×)Ñ)×0Ñ0°>ÑAÀFÑJ€MØ×ÑÔÜ�l‰l˜?´°]Ó1CÔDÓDð ùs   ‚BBT©Úvalidaterg   c                 ó¾  ‡ ‡— t        «       Šdt        dt        fd„}dt        dt        fˆˆ fd„}‰j                  r!‰j
                  €	 |d¬«      ‚‰j
                  S ‰ rt        nt        }t        d	«      }t        |«      D ]  }|sŒ ||«      sŒ ||«      c S  t        «       r |‰j                  «      S ‰ st        d
«      ‚	 ddlm}  |d«      rmt        «       }|dz  dz  |dz  dz  |dz  f}dg|r|gng ¢t        t        |«      ¢­D ]1  }	t!        j"                  d|	¬«      }
|
sŒt        |
«      sŒ) ||
«      c S  d‰_         |d¬«      ‚# t$        $ r Y Œw xY w)az  Find the agent-browser CLI: PATH, Homebrew/managed dirs, local node_modules/.bin, npx fallback, lazy install.

    A bare ``shutil.which`` hit is NOT trusted: agent-browser's npm postinstall re-points a global symlink at our
    local node_modules binary, which vanishes on the next ``hermes update`` and leaves a dangling link ``which``
    still reports (exec fails with 127). Candidates are validated with ``agent_browser_runnable`` before caching
    so a dead one falls through. ``validate=False`` (schema-time check_fn) only tests presence and never caches.
    Raises FileNotFoundError when agent-browser is not installed.
    Úcachedr   c                 ó>   — t        d| rdnd› dt        «       › d�«      S )Núagent-browser CLI not foundz	 (cached)r5   z. Install it with: z)
Or ensure npx is available in your PATH.)ÚFileNotFoundErrorrA   ©ri   s    r    Ú
_not_foundz'_find_agent_browser.<locals>._not_foundx   s3   € Ü Ð#>Éf¹{ÐZ\Ð>]Ð]pÜ$9Ó$;Ð#<Ð<fð"hó ið 	ir2   Ú	candidatec                 ó(   •— ‰r| ‰_         d‰_        | S )NT)Ú_cached_agent_browserÚ_agent_browser_resolved)ro   r.   rg   s    €€r    Ú_acceptz$_find_agent_browser.<locals>._accept|   s   ø€ ñ Ø(1ˆCÔ%Ø*.ˆCÔ'ØÐr2   NTrm   r5   rk   r   )Úensure_dependencyÚbrowserr(   r)   r   r   r`   rX   F)r*   Úboolrl   r,   rr   rq   r   rY   r=   re   r^   rF   Úhermes_cli.dep_ensurert   r   r+   r[   r\   Ú	Exception)rg   rn   rs   Úokr]   ro   rt   r/   r0   r   Úrecheckr.   s   `          @r    Ú_find_agent_browserr{   m   s  ù€ ô ‹)€Cðiœ4ð iÔ$5ó iðœ3ð ¤3ö ð ×"Ò"Ø×$Ñ$Ð,Ù DÔ)Ð)Ø×(Ñ(Ð(Ù#+Õ	Ô1Q€BÜ'¨Ó+€MÜ.¨}Ó=ò &ˆ	Ú™˜I�Ù˜9Ó%Ò%ð&ô ÔÙ�s×5Ñ5Ó6Ð6ÙÜÐ =Ó>Ð>ð
Ý;Ù˜YÔ'Ü"Ó$ˆDØ˜nÑ,¨vÑ5°t¸f±}ÀuÑ7LÈdÐU[ÉmÐ\ˆGØÐ_±M -¡ÀrÐ_ÌSÔQTÐV]ÓM^Ñ_ò ,�Ü Ÿ,™, ¸TÔB�ÚÔ5°gÕ>Ù" 7Ó+Ò+ð,ð #'€CÔÙ
˜EÔ
"Ð"øô ò Ùðús%   ÃA#E Ä)E Ä5	E Ä?E Å	EÅEÚtimeoutc                 óN  — t        «       }t        «       }|sy|j                  «       }t        |j	                  dd«      «      |d<   t
        j                  t
        j                  d|dœ}t        j                  dk(  r|j                  t        «       d¬«       nt        «       t        t
        dd	«      z  |d
<   |ddd|j                  dg}	 t        j                  |fdt
        j                  i|¤Ž}	 |j!                  | ¬«       |j"                  d	k(  S # t        $ r Y yw xY w# t        $ rz}t%        j&                  |«       t)        |t
        j*                  «      rAt-        j.                  t        «      5  |j!                  d¬«       ddd«       n# 1 sw Y   nxY wY d}~yd}~ww xY w)u  Best-effort pre-fetch of the agent-browser npm package via npx (``hermes update`` / ``doctor --fix``).

    Runs with the credential-scrubbed env every other agent-browser spawn uses (registry-fetched npm code must
    never see the operator keyring), in its own process group, and tree-kills on timeout so a surviving
    descendant cannot hold the capture pipe open. Never raises; True only when npx exited 0.

    agent-browser is no longer a root package.json dependency (#43564) â€” it resolves lazily via ``npx
    agent-browser`` instead, which keeps it out of the npm workspace install graph entirely (nothing to
    prune it anymore) but means the first real invocation in a session would otherwise pay npx's
    registry-lookup/fetch cost. Calling this during ``hermes update`` (or ``hermes doctor --fix``) warms
    npx's own cache ahead of time, restoring the "available before any session starts" property
    agent-browser had while it was an eager root dependency â€” without re-entangling it with the workspace
    graph.
    FÚPATHr5   T)ÚstdoutÚstderrÚtextÚenvÚposix)ÚcreationflagsÚstart_new_sessionÚCREATE_NEW_PROCESS_GROUPr   r„   ú--ignore-scriptsz--prefer-offlineú-yz	--versionÚstdin)r|   é   N)r*   r^   Ú_build_browser_envr=   ÚgetÚ
subprocessÚPIPEr   rU   Úupdater   ÚgetattrÚAGENT_BROWSER_NPX_SPECÚPopenÚDEVNULLrx   ÚcommunicateÚ
returncodeÚ
_lifecycleÚ_kill_process_treeÚ
isinstanceÚTimeoutExpiredÚ
contextlibÚsuppress)r|   r.   Únpx_binr‚   Úpopen_kwargsÚcmdÚprocÚexcs           r    Úwarm_agent_browser_npx_cacher¡   ¡   sz  € ô ‹)€CÜÓ €GÙØØ
×
 Ñ
 Ó
"€CÜ% c§g¡g¨f°bÓ&9Ó:€Cˆ�KÜ$.§O¡O¼z¿¹ÐX\ÐehÑi€LÜ	‡w�w�'ÒØ×ÑÔ*<Ó*>ÐRVÐÕWä(:Ó(<¼wÄzÐSmÐopÓ?qÑ(qˆ�_Ñ%ð Ð&Ð(:¸DÀ#×B\ÑB\Ð^iÐ
j€CðÜ×Ñ ÑN¬:×+=Ñ+=ÐNÀÑNˆðØ×Ñ ÐÔ)Ø�‰ !Ñ#Ð#øô	 ò Ùðûô
 ò Ü×%Ñ% dÔ+Ü�cœ:×4Ñ4Ô5Ü×$Ñ$¤YÓ/ñ ,Ø× Ñ ¨Ð Ô+÷,÷ ,ñ ,úäûðúsC   Ã
&D Ã1 D! Ä	DÄDÄ!	F$Ä*AFÅ2FÆ	FÆF	ÆFÆF$c                  ó¨  — t         j                  j                  dd«      j                  «       } t         j                  j                  d«      }| r| dk7  r| gng }|j                  t         j                  j                  |dd«      «       t        j                  dk(  r1|j                  t         j                  j                  |dd	d«      «       t        j                  d
k(  rqt         j                  j                  d«      xs! t         j                  j                  |dd«      }|j                  t         j                  j                  |d«      «       |S )zŠChromium / headless-shell scan roots in agent-browser/Playwright probe order: ``PLAYWRIGHT_BROWSERS_PATH``, then the per-OS default cache.ÚPLAYWRIGHT_BROWSERS_PATHr5   Ú~Ú0z.cachezms-playwrightÚdarwinÚLibraryÚCachesÚwin32ÚLOCALAPPDATAÚAppDataÚLocal)
r   ÚenvironrŒ   rE   r   Ú
expanduserr8   r   ÚsysÚplatform)Úenv_pathr/   ÚrootsÚlocals       r    Ú_chromium_search_rootsr´   Í   sâ   € ä�z‰z�~‰~Ð8¸"Ó=×CÑCÓE€HÜ�7‰7×Ñ˜cÓ"€DÙ%-°(¸c²/˜‘zÀr€EØ	‡L�L”—‘—‘˜d H¨oÓ>Ô?Ü
‡|�|�xÒØ�‰”R—W‘W—\‘\ $¨	°8¸_ÓMÔNÜ
‡|�|�wÒÜ—
‘
—‘˜~Ó.ÒX´"·'±'·,±,¸tÀYÐPWÓ2XˆØ�‰”R—W‘W—\‘\ %¨Ó9Ô:Ø€Lr2   Úrootc                 ól   — 	 t        d„ t        j                  | «      D «       «      S # t        $ r Y yw xY w)zxTrue when ``root`` holds a Playwright ``chromium-*`` / ``chromium_headless_shell-*`` dir (agent-browser accepts either).c              3   ó>   K  — | ]  }|j                  d «      –— Œ y­w))z	chromium-zchromium_headless_shell-N)r   )r   Úes     r    r!   z&_has_chromium_build.<locals>.<genexpr>Þ   s   è ø€ ÒeÈq�1—<‘<Ð I×JÑeùs   ‚F)Úanyr   r"   r#   )rµ   s    r    Ú_has_chromium_buildrº   Û   s7   € ðÜÑeÔTV×T^ÑT^Ð_cÓTdÔeÓeÐeøÜò Ùðús   ‚$' §	3²3c                  óª  — t        «       } | j                  �| j                  S t        j                  j	                  dd«      j                  «       }t        |xr6 t        j                  j                  |«      xs t        j                  |«      xs. t        d„ dD «       «      xs t        d„ t        «       D «       «      «      | _        | j                  S )a0  True when a usable Chromium (or headless-shell) build is on disk; cached.

    Checks ``AGENT_BROWSER_EXECUTABLE_PATH``, then system Chrome/Chromium on PATH, then Playwright's cache.
    Without a binary the CLI hangs on first use until the command timeout fires, so the tool must not be advertised.
    ÚAGENT_BROWSER_EXECUTABLE_PATHr5   c              3   óF   K  — | ]  }t        j                  |«      –— Œ y ­wrD   )r[   r\   )r   rU   s     r    r!   z&_chromium_installed.<locals>.<genexpr>ï   s   è ø€ Òj dŒv�|‰|˜D×!Ñjùs   ‚!)zgoogle-chromeÚchromiumzchromium-browserÚchromec              3   ó|   K  — | ]4  }|xr, t         j                  j                  |«      xr t        |«      –— Œ6 y ­wrD   )r   r   r   rº   )r   rµ   s     r    r!   z&_chromium_installed.<locals>.<genexpr>ð   s0   è ø€ ÒoÈdˆtÒIœŸ™Ÿ™ dÓ+ÒIÔ0CÀDÓ0IÓIÑoùs   ‚:<)r*   Ú_cached_chromium_installedr   r­   rŒ   rE   rv   r   Úisfiler[   r\   r¹   r´   )r.   Úab_paths     r    Ú_chromium_installedrÄ   ã   s¬   € ô ‹)€CØ
×%Ñ%Ð1Ø×-Ñ-Ð-Ü�j‰j�n‰nÐ<¸bÓA×GÑGÓI€GÜ%)Ø	Ò	G”b—g‘g—n‘n WÓ-ÒF´·±¸gÓ1Fò 	pÜÑjÐ.iÔjÓjò	päÑoÔVlÓVnÔoÓoó&€CÔ"ð
 ×)Ñ)Ð)r2   c            
      ó*  — t        «       } | j                  r
t        «       S d| _        t        «       ryddlm}  |«       sy	 t        «       }|dg}t        |«      rt        «       xs ddd| j                  dg}| j                  j                  d	«       	 t        j                  |ddd
dd| j                  «       t        j                   ¬«      }|j(                  dk7  rW|j*                  xs |j,                  xs dj/                  «       dd }| j                  j'                  d|j(                  |«       yd| _        t        «       S # t        $ r Y yw xY w# t"        t        j$                  f$ r&}| j                  j'                  d|«       Y d}~yd}~ww xY w)u6  Best-effort, gated download of the Chromium *binary* on local cold start.

    Binary only (``agent-browser install``), never ``--with-deps`` â€” that shells ``apt`` and needs root. Gated by
    ``security.allow_lazy_installs``, skipped in Docker (Chromium ships in the image), attempted once per process.
    TFr   )Ú_allow_lazy_installsÚinstallrQ   r‡   rˆ   u|   browser: Chromium missing â€” auto-installing the browser binary (one-time ~170MB; disable via security.allow_lazy_installs)úutf-8ÚreplaceiX  )Úcapture_outputr�   ÚencodingÚerrorsr|   r‚   r‰   z2browser: Chromium auto-install failed to start: %sNr5   iÔþÿÿz,browser: Chromium auto-install exited %s: %s)r*   Ú_chromium_autoinstall_attemptedrÄ   Ú_running_in_dockerÚtools.lazy_depsrÆ   r{   rl   rH   r^   r‘   ÚloggerÚinfor�   Úrunr‹   r“   r#   ÚSubprocessErrorÚwarningr•   r€   r   rE   rÁ   )r.   rÆ   rB   Úinstall_cmdrŸ   r¸   Útails          r    Ú_maybe_autoinstall_chromiumr×   õ   sw  € ô ‹)€CØ
×*Ò*Ü"Ó$Ð$Ø*.€CÔ'ÜÔØÝ4ÙÔ!ØðÜ)Ó+ˆð  	Ð*€KÜ% kÔ2Ü'Ó)Ò2¨UÐ4FÈÈc×NhÑNhÐjsÐtˆà‡J�J‡O�Oð  Sô  TðÜ�~‰~˜k¸$ÀTÐT[ÐdmÐwzØ"%×"8Ñ"8Ó":Ä*×BTÑBTôVˆð
 ‡�˜!ÒØ—‘Ò0˜tŸ{™{Ò0¨b×7Ñ7Ó9¸$¸%Ð@ˆØ�
‰
×ÑÐIÈ4Ï?É?Ð\`ÔaØØ%)€CÔ"ÜÓ Ð øô% ò Ùðûô ”Z×/Ñ/Ð0ò Ø�
‰
×ÑÐOÐQRÔSÜûðús*   Á
E Â9E Å	EÅEÅFÅ,FÆFc                  óÎ   — t         j                  j                  d«      ry	 t        ddd¬«      5 } d| j	                  «       v cddd«       S # 1 sw Y   yxY w# t
        $ r Y y	w xY w)
zABest-effort detection of whether we're inside a Docker container.z/.dockerenvTz/proc/1/cgroupÚrtrÈ   )rË   ÚdockerNF)r   r   rT   ÚopenÚreadr#   )Úfps    r    rÎ   rÎ     s]   € ä	‡w�w‡~�~�mÔ$ØðÜÐ" D°7Ô;ð 	)¸rØ˜rŸw™w›yÐ(÷	)÷ 	)ò 	)ûäò Ùðús.   ¢A °AÁ	A ÁAÁA ÁA Á	A$Á#A$c                  ó^  — t        «       } | j                  «       ry| j                  «       ryt        j                  «       ry	 t        d¬«      }t        |«      ryt        j                  «       }|�|j                  «       S t        j                  «       ryt        «       S # t        $ r Y yw xY w)a  Whether the browser tools should be advertised.

    Local mode needs the ``agent-browser`` CLI plus a Chromium build (except Lightpanda-only text workflows);
    cloud mode needs the CLI plus provider credentials (the provider hosts its own Chromium).
    FTrf   )r*   Ú_is_browser_use_cli_modeÚ_is_camofox_modeÚ_cdpÚ_get_cdp_override_rawr{   rl   rL   rJ   Ú_get_cloud_providerÚis_availableÚ_lpÚ_using_lightpanda_enginerÄ   )r.   rB   Úproviders      r    Úcheck_browser_requirementsrè   &  s£   € ô ‹)€Cà
×#Ñ#Ô%Øà
×ÑÔØä×!Ñ!Ô#ØðÜ)°5Ô9ˆô -¨[Ô9Øä×)Ñ)Ó+€HØÐØ×$Ñ$Ó&Ð&ä
×#Ñ#Ô%ØäÓ Ð øô ò Ùðús   ÁB  Â 	B,Â+B,c                  ó2   — t        «       syddlm}   | «       S )aT  Advertise ``browser_vision`` only with BOTH a working browser AND a vision backend.

    Without the vision check, the tool stays in the model's tool list even when no vision provider is
    configured, then fails at call time with a cryptic provider-side error like ``unknown variant
    `image_url`, expected `text``` (issue #31179).
    Fr   ©Úcheck_vision_requirements)rè   Útools.vision_toolsrë   rê   s    r    Ú!check_browser_vision_requirementsrí   I  s   € ô &Ô'ØÝ<Ù$Ó&Ð&r2   )r5   )g      N@)9Ú__doc__rš   Ú	functoolsr   r[   r�   r¯   Úpathlibr   Útypingr   r   Úhermes_cli._subprocess_compatr   Úhermes_constantsr   r   r	   r?   r
   Útools.browser_tool_originr   r*   Útoolsr   rá   r   rJ   r   r–   r   rå   Ú	lru_cacher$   r,   r&   Úlistr1   r=   rA   rv   rH   rL   rN   rY   r^   re   r{   Úfloatr¡   r´   rº   rÄ   r×   rÎ   rè   rí   r@   r2   r    ú<module>rù      s   ðñWó Û Û 	Û Û Û 
Ý ß !å <ß }Ó }Ý >Ý *Ý .Ý 6Ý 9ð €×Ñ˜QÔð e¨C°¨H¡oò ó  ððW d¨3¡ió Wñ6 sð 6°Có 6ðz˜só zðG°ð G¸ó Gðp°sð p¸tó pðY só YðR¨3°©:ð R¸$ó Rð˜( 3™-ó ðE¨Só Eð -1ò 1# Tð 1#°Só 1#ñh)¨%ð )¸4ó )ðX  S¡	ó ð˜cð  dó ð*˜Tó *ð$#! Tó #!ðL˜Dó ð ! Dó  !ðF
'¨4ô 
'r2   