+
    lHàj3  ã                  óF  € R t ^ RIHt ^ RIt^ RIHtHt ^ RIHt	 ^ RI
Ht ^ RIHtHt ^ RIHt ^ RIHt ^ R	IHt ^ R
IHt R R ltR R ltR R ltR R ltR R ltR R ltR R lt R R lt!R R lt"R R lt#R R  lt$R! R" lt%R# R$ lt&R% R& lt'R' R( lt(R) R* lt)R# )+u)  Cloud browser provider resolution (explicit browser.cloud_provider, auto-detect, per-profile cache), backend/engine selection and headed-mode flags.

Split out of ``tools/browser_tool.py``. Facade-owned state is read through ``_bt`` (``tools.browser_tool``, resolved per call) â€” no import cycle.)ÚannotationsN)ÚCallableÚOptional)ÚBrowserProvider)Úget_provider)Úget_hermes_home_overrideÚhermes_home_key)Ú normalize_browser_cloud_provider©Úis_truthy_value)Úorigin_module)Úbrowser_tool_cdpc               ó$   € V ^8„  d   QhRRRRRR/# )é   Úresolved_attrÚstrÚ
cache_attrÚcomputezCallable[[], object]© )Úformats   "Ú=/home/ubuntu/.hermes/hermes-agent/tools/browser_tool_cloud.pyÚ__annotate__r      s"   € ÷ $ñ $˜cð $¨sð $Ð=Qñ $ó    c                óš   € \        4       e   V! 4       # \        W4      '       g   \        WR4       \        WV! 4       4       \        W4      # )a   Process-lifetime cache on ``_bt``: the resolved flag is set BEFORE computing, then the final value is stored.

Under a routed profile (HERMES_HOME override, multiplexed gateway) the slot is NOT consulted: every
``_memo`` here caches a ``browser.*`` config read, and one process-wide slot would hand the launch
profile's engine/headed/private-URL policy to every other profile (same rule as ``_allow_private_urls``).
T)r   ÚgetattrÚsetattr)Ú_btr   r   r   s   &&&&r   Ú_memor      sA   € ô  Ó!Ò-Ù‹yÐÜ�3×&Ò&Ü� DÔ)Ü�¡£Ô+Ü�3Ó#Ð#r   c               ó   € V ^8„  d   QhRR/# )r   ÚreturnÚNoner   )r   s   "r   r   r   "   s   € ÷ Wñ W¨ñ Wr   c                 óœ   €  ^ RI Hp  V ! 4        R#   \         d0   p\        4       P                  P                  RT4        Rp?R# Rp?ii ; i)zbIdempotently trigger plugin discovery (standalone scripts/tests may never import ``model_tools``).)Ú_ensure_plugins_discoveredz/Browser plugin discovery failed (non-fatal): %sN)Úhermes_cli.pluginsr"   Ú	ExceptionÚ_originÚloggerÚdebug)r"   Úexcs     r   Ú_ensure_browser_plugins_loadedr)   "   s@   € ðWÝAÙ"Ö$øÜô WÜ‹	×Ñ×ÑÐPÐRU×VÒVûðWús   ‚ ‘Aœ$AÁAc               ó   € V ^8„  d   QhRR/# ©r   r   úOptional[CloudBrowserProvider]r   )r   s   "r   r   r   +   s   € ÷ ñ Ð;ñ r   c                 ó  € \        4       p \        4       pV P                  ;_uu_ 4        V P                  '       g"   RV n        V P
                  P                  4         V P                  VR7      pW3pW0P
                  9   d<   V P
                  V,          V n        RV n        Wn        V P                  uuRRR4       # RV n        RV n        \        4       pV P                  VR7      pW%8w  d   K“  V P                  '       dc   Wn        V P
                   Uu. uF  qf^ ,          V8X  g   K  VNK  	  up F  pV P
                  P                  VR4       K!  	  W@P
                  V&   VuuRRR4       # u upi   + '       g   i     R# ; i)z9Return the provider cached for the active Hermes profile.NT)ÚscopeF)r%   r   Ú_cloud_provider_cache_lockÚ_cloud_provider_resolvedÚ_cached_cloud_provider_scopeÚ_cached_cloud_providersÚclearÚ_browser_registry_generationÚ_cached_cloud_providerÚ _resolve_cloud_provider_uncachedÚpop)r   r.   Úbefore_generationÚ	cache_keyÚresolvedÚafter_generationÚkeyÚ	stale_keys           r   Ú_get_cloud_providerr>   +   sZ  € ä
‹)€CÜÓ€EØ	×	'×	'Ó	'à×+×+Ð+Ø/3ˆCÔ,Ø×'Ñ'×-Ñ-Ô/ØØ #× @Ñ @ÀuÐ @Ó MÐØÐ2ˆIØ×7Ñ7Ô7Ø-0×-HÑ-HÈÕ-S�Ô*Ø/3�Ô,Ø38Ô0Ø×1Ñ1÷ 
(Ò	'ð *.ˆCÔ&Ø+0ˆCÔ(Ü7Ó9ˆHØ"×?Ñ?ÀeÐ?ÓLÐØ Ô4ÙØ×+×+Ð+Ø38Ô0Ø14×1LÒ1LÓ!`Ñ1L¨#ÐTUÕPVÐZ_ÑP_§# #Ñ1LÔ!`�IØ×/Ñ/×3Ñ3°I¸tÖDñ "aà9A×+Ñ+¨IÑ6Ø÷1 
(Ò	'ùò* "a÷+ 
(×	'Ð	'ús1   ©B
E5Â>AE5ÄE5ÄE0Ä*E0Ä05E5Å0E5Å5F	c               ó    € V ^8„  d   QhRRRR/# )r   Úprovider_keyr   r   r,   r   )r   s   "r   r   r   J   s   € ÷ ñ °sð Ð?]ñ r   c                óþ   € \        4       p \        4        \        V 4      pVf   ^ RIHp \        V! RRV  R2R4      4      hV#   \
         d    h \         d#    TP                  P                  RT RR7        R# i ; i)	zçBuild the provider named by ``browser.cloud_provider``.

Strict: an unregistered name raises ``ValueError`` (never a silent reroute to auto-detect); any
other instantiation error is logged and yields None so the next call retries.
N)Úselection_errorÚbrowserÚ'zlno registered browser plugin has that name (install the corresponding plugin or fix the config key spelling)zIFailed to instantiate explicit cloud_provider %r; will retry on next callT©Úexc_info)	r%   r)   Ú_registry_get_browser_providerÚtools.tool_backend_helpersrB   Ú
ValueErrorr$   r&   Úwarning)r@   r   r:   rB   s   &   r   Ú$_instantiate_explicit_cloud_providerrK   J   s•   € ô ‹)€CðÜ&Ô(Ü1°,Ó?ˆØÒÝBÜ™_Ø˜Q˜|˜n¨AÐ.Ø~óó ð ð ˆøÜô ØÜô Ø�
‰
×ÑÐfÐhtð  @DÐô  	EÚðús   Œ7A ÁA<ÁA<Á;A<c               ó   € V ^8„  d   QhRR/# r+   r   )r   s   "r   r   r   b   s   € ÷ ñ Ð$Bñ r   c                 óè   € \        4       p ^ RIHp ^ RIHp  W3 F$  pV! 4       pVP                  4       '       g   K"  Vu # 	  R#   \         d"    T P                  P                  RRR7        R# i ; i)z“Auto-detect: Browser Use, then Browserbase; never raises.

Third-party plugins are only reachable via explicit ``browser.cloud_provider: <name>``.
)ÚBrowserUseBrowserProvider)ÚBrowserbaseBrowserProviderz!Cloud provider auto-detect failedTrE   N)	r%   Ú$plugins.browser.browser_use.providerrN   Ú$plugins.browser.browserbase.providerrO   Úis_availabler$   r&   r'   )r   rN   rO   ÚclsÚfallback_providers        r   Ú_autodetect_cloud_providerrU   b   sx   € ô
 ‹)€Cõ OÝOðMØ-ÓJˆCÙ #£ÐØ ×-Ñ-×/Ô/Ø(Ò(ñ Kñ øô ô MØ�
‰
×ÑÐ<ÀtÐÕLÙðMús   ˜ A ½A ÁA Á(A1Á0A1c               ó   € V ^8„  d   QhRR/# r+   r   )r   s   "r   r   r   v   s   € ÷ '&ñ '&Ð*Hñ '&r   c                 ó  € \        4       p RpRp ^ RIHp V! 4       P                  R/ 4      p\	        V\
        4      '       dB   RV9   d;   \        VP                  R4      4      pVR	9   d   RV n        RV n        R# VR8X  d   RpV'       d   \        V4      pVf   R# Tf   Tf   \        4       pTf   R# Yn        RT n        T P                  #   \         d    h \         d'   pT P                  P                  RT4        Rp?LhRp?ii ; i)
a;  Return the configured cloud browser provider, or None for local mode.

Pins the cache only when definitive (explicit ``local``/``camofox`` or a resolved provider); a transient None
(unreadable config, missing credentials) is NOT cached so it can self-heal. Auto-detect runs only when no
selection was ever written.
N)Úread_raw_configrC   Úcloud_providerTÚnouszbrowser-usez-Could not read cloud_provider from config: %s)ÚlocalÚcamofox)r%   Úhermes_cli.configrX   ÚgetÚ
isinstanceÚdictr	   r5   r0   rK   rI   r$   r&   r'   rU   )r   r:   r@   rX   Úbrowser_cfgÚes         r   r6   r6   v   s
  € ô ‹)€CØ/3€HØ€LðMÝ5Ù%Ó'×+Ñ+¨I°rÓ:ˆÜ�k¤4×(Ò(Ð-=ÀÔ-LÜ;¸K¿O¹OÐL\Ó<]Ó^ˆLØÐ3Ô3à-1�Ô*Ø/3�Ô,ÙØ˜vÔ%à,�ßÜ;¸LÓIˆHØÒÙð Ò˜LÒ0Ü-Ó/ˆØÒÙØ!)ÔØ#'€CÔ Ø×%Ñ%Ð%øô ô ØÜô Mà�
‰
×ÑÐHÈ!×LÑLûðMús*   �A)C Á;C ÂC ÃD
Ã#D
Ã$DÄD
c               ó   € V ^8„  d   QhRR/# ©r   r   Úboolr   )r   s   "r   r   r       s   € ÷ Nñ N˜ñ Nr   c                 ór   € \        4       p \        P                  ! 4       '       * ;'       d    \        4       RJ # )zCReturn True when the browser tool will use a local browser backend.N)r%   Ú_cdpÚ_get_cdp_override_rawr>   ©r   s    r   Ú_is_local_moderj       s,   € ä
‹)€CÜ×)Ò)Ó+Ô+×MÐMÔ0CÓ0EÈÐ0MÐMr   c               ó   € V ^8„  d   QhRR/# rd   r   )r   s   "r   r   r   ¦   s   € ÷ Rñ R˜4ñ Rr   c                 óø   € \        4       p \        P                  ! 4       '       d   R# V P                  4       '       d   R# \	        4       e   R# ^ RIHp V! RR4      P                  4       P                  4       R9   # )u“  True when the browser runs locally AND the terminal is also local.

SSRF protection only matters when the browser can reach networks the terminal cannot (cloud backends,
containerized terminals). A CDP override is never trusted as local (that Chrome may live off-host) and MUST
be checked before the Camofox short-circuit; ``_is_local_mode`` treats overrides the same way â€” keep the two
in agreement.
FT)Úterminal_envÚTERMINAL_ENVr[   )r[   Ú )	r%   rg   rh   Ú_is_camofox_moder>   Útools.terminal_scoperm   ÚstripÚlower)r   rm   s     r   Ú_is_local_backendrt   ¦   sd   € ô ‹)€CÜ×!Ò!×#Ò#ÙØ
×Ñ×ÒÙÜÓÒ(Ùõ 2Ù˜¨Ó0×6Ñ6Ó8×>Ñ>Ó@ÀMÑQÐQr   c               ó   € V ^8„  d   QhRR/# ©r   r   r   r   )r   s   "r   r   r   ¼   s   € ÷ Nñ N˜cñ Nr   c                 ó  € \        4       p \        P                  ! 4       '       d   R# V P                  4       '       d   R# \	        4       pVe!   \        \        VRR4      ;'       g    R4      # \        4       R8X  d   R# R# )zÐShared-metrics label for the backend legacy browser calls use in the active profile, in session-creation
precedence (CDP override > Camofox > cloud provider > local engine). Config reads only, no network I/O.Úcdpr\   Únamero   ÚotherÚ
lightpandar[   )r%   rg   rh   rp   r>   r   r   Ú_get_browser_engine)r   Úproviders     r   Úbrowser_backend_namer~   ¼   sn   € ô ‹)€CÜ×!Ò!×#Ò#ÙØ
×Ñ×ÒÙÜ"Ó$€HØÒÜ”7˜8 V¨RÓ0×;Ð;°GÓ<Ð<Ü.Ó0°LÔ@ˆ<ÐMÀgÐMr   c               ó   € V ^8„  d   QhRR/# rv   r   )r   s   "r   r   r   Ê   s   € ÷ Uñ U˜Sñ Ur   c                 óF   a€ \        4       oR V3R llp \        SRRV 4      # )zþReturn the browser engine: ``auto`` (no ``--engine`` flag), ``lightpanda`` or ``chrome``.

``browser.engine`` first, then ``AGENT_BROWSER_ENGINE``, then ``auto``; cached. Lightpanda is faster on
navigation but has no graphical renderer (no screenshots).
c               ó   € V ^8„  d   QhRR/# rv   r   )r   s   "r   r   Ú)_get_browser_engine.<locals>.__annotate__Ñ   s   € ÷ 	ñ 	�Sñ 	r   c            	     óN  <€ SP                  R RR R4      p V R8X  dG   \        P                  P                  RR4      P	                  4       P                  4       ;'       g    T p 0 RmpW9  d8   SP                  P                  RV RP                  \        V4      4      4       Rp V # )	ÚengineÚautoc                ó¢   € V '       dG   \        V 4      P                  4       '       d(   \        V 4      P                  4       P                  4       # R # )r…   ©r   rr   rs   ©Úvs   &r   Ú<lambda>Ú6_get_browser_engine.<locals>.compute.<locals>.<lambda>Ò   s8   € ×XYÔ^aÐbcÓ^d×^jÑ^j×^lÒ^l¼cÀ!»f¿l¹l»n×>RÑ>RÓ>TÐ>xÐrxÐ>xr   zbrowser.engine from configÚAGENT_BROWSER_ENGINEro   z=Unknown browser engine %r (valid: %s), falling back to 'auto'z, >   r…   Úchromer{   )
Ú_browser_cfgÚosÚenvironr^   rr   rs   r&   rJ   ÚjoinÚsorted)r„   Ú_VALID_ENGINESr   s     €r   r   Ú$_get_browser_engine.<locals>.computeÑ   s©   ø€ Ø×!Ñ! (¨FÑ4xð  {Wó  XˆØ�VÔÜ—Z‘Z—^‘^Ð$:¸BÓ?×EÑEÓG×MÑMÓO×YÐYÐSYˆFâ9ˆØÔ'Ø�J‰J×ÑÐ^Ð`fÐhl×hqÑhqÔrxð  zHó  sIó  iJô  KØˆFØˆr   Ú_browser_engine_resolvedÚ_cached_browser_engine©r%   r   ©r   r   s    @r   r|   r|   Ê   s+   ø€ ô ‹)€C÷	ð 	ô �Ð0Ð2JÈGÓTÐTr   c               ó   € V ^8„  d   QhRR/# rd   r   )r   s   "r   r   r   Þ   s   € ÷ Oñ O˜ñ Or   c                 óF   a€ \        4       oR V3R llp \        SRRV 4      # )zfTrue when the browser should launch headed: ``browser.headed``, else ``AGENT_BROWSER_HEADED``; cached.c               ó   € V ^8„  d   QhRR/# rd   r   )r   s   "r   r   Ú%_is_headed_mode.<locals>.__annotate__á   s   € ÷ lñ l�Tñ lr   c                 óÀ   <€ SP                  R RR R4      p T ;'       g@    \        P                  P                  RR4      P	                  4       P                  4       R9   # )ÚheadedFc                ób   € V f   R# \        V 4      P                  4       P                  4       R9   # )NF©ÚtrueÚ1Úyesr‡   rˆ   s   &r   rŠ   Ú2_is_headed_mode.<locals>.compute.<locals>.<lambda>â   s=   € ÀaÂi¸Uð  >DÔUXÐYZÓU[×UaÑUaÓUc×UiÑUiÓUkð  pDñ  VDð  >Dr   zbrowser.headed from configÚAGENT_BROWSER_HEADEDro   r    )rŽ   r�   r�   r^   rr   rs   )rž   r   s    €r   r   Ú _is_headed_mode.<locals>.computeá   s[   ø€ Ø×!Ñ! (¨Eñ  4Dð  Fbó  cˆØ×kÐkœŸ™Ÿ™Ð(>ÀÓC×IÑIÓK×QÑQÓSÐWkÑkÐkr   Ú_headed_mode_resolvedÚ_cached_headed_moder—   r˜   s    @r   Ú_is_headed_moder©   Þ   s+   ø€ ä
‹)€C÷lð lô �Ð-Ð/DÀgÓNÐNr   c               ó    € V ^8„  d   QhRRRR/# )r   r„   r   r   re   r   )r   s   "r   r   r   ç   s   € ÷ Pñ P #ð P¨$ñ Pr   c                ó~   € \        4       pV R8g  ;'       d(    VP                  4       '       * ;'       d    \        4       # )zqTrue when ``--engine`` should be added: explicit (non-``auto``) engine on a non-cloud, non-camofox local session.r…   )r%   rp   rj   )r„   r   s   & r   Ú_should_inject_enginer¬   ç   s3   € ä
‹)€CØ�VÑ×OÐO C×$8Ñ$8Ó$:Ô :×OÐO¼~Ó?OÐOr   c               ó   € V ^8„  d   QhRR/# rd   r   )r   s   "r   r   r   í   s   € ÷ ñ  dñ r   c                 ó<   a € \        4       o \        S RRV 3R l4      # )z…``browser.auto_local_for_private_urls`` (default True), cached: route private/LAN URLs to a local sidecar even with a cloud provider.Ú%_auto_local_for_private_urls_resolvedÚ#_cached_auto_local_for_private_urlsc                 óH   <€ S P                  R S P                  \        R4      # )Úauto_local_for_private_urlsz'auto_local_for_private_urls from config)rŽ   r°   re   ri   s   €r   rŠ   Ú._auto_local_for_private_urls.<locals>.<lambda>ò   s&   ø€ �× Ñ Ð!>À×@gÑ@gÔimð  pYô  Zr   r—   ri   s   @r   Ú_auto_local_for_private_urlsr´   í   s&   ø€ ä
‹)€CÜØÐ4Ð6[ô 	Zóð r   c               ó   € V ^8„  d   QhRR/# rd   r   )r   s   "r   r   r   ö   s   € ÷ cñ c˜4ñ cr   c                 óB   € \        4       P                  RR\        R4      # )a  Whether the user consented to real-profile local browsing.

Read on EVERY call: it is a consent switch (flipping it off must not need a restart) and each multiplexed
profile must decide for itself. One YAML load per local session creation, so no hot-path cost.
Úuse_real_profileFzuse_real_profile from config)r%   rŽ   re   r   r   r   Ú_use_real_profiler¸   ö   s   € ô ‹9×!Ñ!Ð"4°e¼TÐCaÓbÐbr   c               ó   € V ^8„  d   QhRR/# rd   r   )r   s   "r   r   r   ÿ   s   € ÷ 	qñ 	q˜Tñ 	qr   c                 óf   € \        4       p \        4       e   \        4       # \        V RR\        4      # )a  Whether the browser may navigate to private/internal addresses (default False: SSRF protection on).

Single-profile calls cache for the process lifetime; multiplexed profile turns (ContextVar-scoped config)
resolve on every call so one profile's opt-out is never reused by another.
Ú_allow_private_urls_resolvedÚ_cached_allow_private_urls)r%   r   Ú_resolve_allow_private_urlsr   ri   s    r   Ú_allow_private_urlsr¾   ÿ   s1   € ô ‹)€CÜÓ!Ò-Ü*Ó,Ð,Ü�Ð4Ð6RÔToÓpÐpr   c               ó   € V ^8„  d   QhRR/# rd   r   )r   s   "r   r   r     s   € ÷ Hñ H Tñ Hr   c                 ó@   € \        4       p V P                  RRR R4      # )zARead the browser private-URL toggle from the active config scope.Úallow_private_urlsFc                ó   € \        V R R7      # )F)Údefaultr
   rˆ   s   &r   rŠ   Ú-_resolve_allow_private_urls.<locals>.<lambda>  s   € Ä?ÐSTÐ^cÕCdr   zallow_private_urls from config)r%   rŽ   ri   s    r   r½   r½     s-   € ä
‹)€CØ×ÑÐ0°%Ñ9dð  gGó  Hð  Hr   )*Ú__doc__Ú
__future__r   r�   Útypingr   r   Úagent.browser_providerr   ÚCloudBrowserProviderÚagent.browser_registryr   rG   Úhermes_constantsr   r   rH   r	   Úutilsr   Útools.browser_tool_originr   r%   Útoolsr   rg   r   r)   r>   rK   rU   r6   rj   rt   r~   r|   r©   r¬   r´   r¸   r¾   r½   r   r   r   Ú<module>rÏ      s†   ðñWõ #ã 	ß %å JÝ Qß FÝ GÝ !Ý >Ý *õ$õWõõ>õ0õ('&õTNõRõ,NõUõ(OõPõõcõ	q÷Hr   