+
    lHàj´Ì  ã                   ój  € R t ^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt^ RIH	t	 ^ RI
HtHtHtHtHt ^ RIHt ^ RIHt ^ RIHt ^ RIHt ^ RIHt ^ R	IHt ^ R
IHt ^ RIH t! ^ RIH"t# ^ RIH$t% Rt&Rt'R]& 2t(R]' 2t)Rrt*R R lt+R R lt,R R lt-RsR R llt.R R lt/R R lt0R R lt1R  R! lt2R" R# lt3R$ R% lt4R& R' lt5R( R) lt6Rtt7R* R+ lt8R, R- lt9R. R/ lt:RsR0 R1 llt;R2 R3 lt<R4 R5 lt=RuR6 R7 llt>R8 R9 lt?R: R; lt@R< R= ltAR> R? ltBR@ RA ltC^tDRsRB RC lltERD RE ltFRF RG ltGRH RI ltHRvRJ RK lltIRL RM ltJRN RO ltKRP RQ ltLRR RS ltMRT RU ltNRVRw/RW RX lltORY RZ ltPR[ R\ ltQR]tRRxtSR^ R_ ltTR` Ra ltURb Rc ltVRsRd Re lltWRf Rg ltXRh Ri ltYRj Rk ltZRl Rm lt[Rn Ro lt\RyRp Rq llt]R# )zu:  agent-browser session management: daemon spawn, per-backend session creation
(local/lightpanda/cdp/cloud), cached lookup, command execution + output interpretation.

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)ÚAnyÚCallableÚDictÚListÚOptional)Úwindows_hide_flags)Úhermes_home_key)Úorigin)Úbrowser_tool_cdp)Úbrowser_tool_cloud)Úbrowser_tool_install)Úbrowser_tool_lifecycle)Ú browser_tool_lightpanda_fallback)Úbrowser_tool_real_profile)Úbrowser_tool_snapshotz4docker pull ghcr.io/nousresearch/hermes-agent:latestzShermes pm install chromium (system libraries: npx playwright install-deps chromium)um   Chromium browser is missing. You're running in Docker â€” pull the latest image to get the bundled Chromium: z.Chromium browser is missing. Install it with: c                ó$   € V ^8„  d   QhR\         /# ©é   Úreturn©Úbool)Úformats   "Ú?/home/ubuntu/.hermes/hermes-agent/tools/browser_tool_session.pyÚ__annotate__r   )   s   € ÷ ñ ´ñ ó    c                 óÒ   €  \        RRR7      ;_uu_ 4       p V P                  4       P                  4       R8H  uuRRR4       #   + '       g   i     R# ; i  \         d     R# i ; i)z°Ubuntu 23.10+ default: unprivileged user namespaces are denied, so a Chromium whose
``chrome_sandbox`` helper is not setuid (Playwright's bundle) dies with 'No usable sandbox'.z6/proc/sys/kernel/apparmor_restrict_unprivileged_usernsúutf-8©ÚencodingÚ1NF)ÚopenÚreadÚstripÚOSError)Úfs    r   Ú&apparmor_restricts_unprivileged_usernsr&   )   sO   € ðÜÐJÐU\×]Õ]ÐabØ—6‘6“8—>‘>Ó# sÑ*÷ ^×]×]Ó]ûäô Úðús-   ‚A —!A¸
A ÁA	ÁA ÁA ÁA&Á%A&c                ó$   € V ^8„  d   QhR\         /# r   r   )r   s   "r   r   r   3   s   € ÷ 4ñ 4¬ñ 4r   c                 ó´   € \        \        R4      '       d   \        P                  ! 4       ^ 8X  d   R# \        P                  ! 4       '       d   R# \        4       # )zXTrue when Chromium needs --no-sandbox to start reliably (root, Docker, AppArmor userns).ÚgeteuidT)ÚhasattrÚosr)   Ú_installÚ_running_in_dockerr&   © r   r   Ú_needs_chromium_sandbox_bypassr/   3   s:   € äŒr�9×Ò¤"§*¢*£,°!Ô"3ÙÜ×"Ò"×$Ò$ÙÜ1Ó3Ð3r   c                óJ   € V ^8„  d   QhR\         \        \        3,          RR/# )r   Úbrowser_envr   N)ÚdictÚstr)r   s   "r   r   r   <   s&   € ÷ Sñ S¬d´3¼°8­nð SÀñ Sr   c                ó¼   € RV 9  dU   RV 9  dL   \        4       '       d:   \        P                  P                  R4       RP	                  \
        4      V R&   R# R# R# R# )zEAdd required Chromium sandbox flags without overriding user settings.ÚAGENT_BROWSER_ARGSÚAGENT_BROWSER_CHROME_FLAGSuW   browser: sandbox bypass needed (root/docker/AppArmor userns) â€” injecting --no-sandboxÚ,N)r/   Ú_btÚloggerÚdebugÚjoinÚCHROMIUM_SANDBOX_BYPASS_ARGS)r1   s   &r   Ú_apply_chromium_sandbox_argsr=   <   sR   € à KÔ/Ð4PÐXcÔ4cÜ.×0Ò0Ü�
‰
×ÑÐrÔsØ,/¯H©HÔ5QÓ,RˆÐ(Ó)ñ 1ñ 5dÑ/r   c                ó–   € V ^8„  d   QhR\         \        \        3,          R\        \        ,          R\         \        \        3,          /# )r   r1   Ú
is_windowsr   )r2   r3   r   r   )r   s   "r   r   r   D   s:   € ÷ <ñ <´$´s¼C°xµ.ð <Ü19¼$µð<ÜKOÔPSÔUXÐPXÍ>ñ<r   c                ób   € Vf   \         P                  R8H  pV'       d   RV 9   d   V # / V CRR/C# )u’  (#64867) Pin local Chromium headless on Windows.

Local mode is documented as zero-cost headless Chromium, but the agent-browser
daemon inherits this env, and anything that resolves its ``--headed`` setting
to a window (``--headed`` is agent-browser's documented boolean flag; this env
var is its documented equivalent) turns a browser-tool turn into a blank
top-level window over the Windows Desktop chat. Pure in ``(options, is_windows)``
so the invariant is testable on any host; call sites pass nothing (they resolve
``os.name``) and skip non-Windows hosts entirely. Never overrides an explicit
``AGENT_BROWSER_HEADED`` â€” the opt-out stays the user's.
ÚntÚAGENT_BROWSER_HEADEDÚfalse)r+   Úname)r1   r?   s   &&r   Ú windows_headless_browser_optionsrE   D   s;   € ð ÒÜ—W‘W ‘_ˆ
ßÐ/°;Ô>ØÐØ;ˆkÐ;Ð1°7Ñ;Ð;r   c                ó^   € V ^8„  d   QhR\         R\         R\        \         \         3,          /# )r   Ústdout_pathÚstderr_pathr   )r3   Útuple)r   s   "r   r   r   X   s*   € ÷ 	ñ 	¬Cð 	¼cð 	ÄeÌCÔQTÈHÅoñ 	r   c                óF  € . pW3 FP  p \        VRRR7      ;_uu_ 4       pVP                  VP                  4       P                  4       4       RRR4       KR  	  V^ ,          V^,          3#   + '       g   i     Kw  ; i  \         d    TP                  R4        K™  i ; i)z;Best-effort read of agent-browser stdout/stderr temp files.Úrú	utf-8-sigr   NÚ )r!   Úappendr"   r#   r$   )rG   rH   ÚoutÚpathr%   s   &&   r   Ú_read_command_output_filesrQ   X   s„   € à
€CØÓ*ˆð	Ü�d˜C¨+×6Õ6¸!Ø—
‘
˜1Ÿ6™6›8Ÿ>™>Ó+Ô,÷ 7Ñ6ñ +ð ˆq�6�3�q•6ˆ>Ð÷	 7×6Ð6ûäô 	Ø�J‰J�r�Nð	ús.   ŠB  .A,ÁB Á,A=Á7B Á=B Â B ÂB c                ó(   € V ^8„  d   QhR\         RR/# )r   Úpathsr   N©r3   )r   s   "r   r   r   d   s   € ÷ ñ ¬ð °ñ r   c                  ój   € V  F  p \         P                  ! V4       K  	  R #   \         d     K.  i ; i©N)r+   Úunlinkr$   )rS   rP   s   * r   Ú_unlink_command_output_filesrX   d   s0   € Ûˆð	Ü�IŠI�dŽOó øô ô 	Úð	ús   ‡#£2±2c          
      óT   € V ^8„  d   QhR\         R\        R\         R\         R\         /# )r   ÚcommandÚtimeoutÚstdoutÚstderrr   )r3   Úint)r   s   "r   r   r   l   s4   € ÷ ñ ÜðÜðÜ(+ðÜ58ðäñr   c                óî  € RV R2.pT;'       g    T;'       g    RP                  4       pV'       d   VP                  VR,          4       RV RV 2P                  4       9   d   VP                  R4       MnV R8X  dh   \        P                  ! 4       '       dM   \
        P                  ! 4       '       d   VP                  R	\         24       MVP                  R
\         24       RP                  V4      # )z7Actionable timeout message from captured daemon output.zCommand timed out after z secondsrM   :NiÜ  NÚsandboxÚ
zŸChromium sandbox launch failed. Set AGENT_BROWSER_ARGS='--no-sandbox,--disable-dev-shm-usage' in your environment, or run: npx playwright install-deps chromiumr!   z\The browser daemon may still be starting or Chromium may be missing. Pull the latest image: zlThe browser daemon may still be starting, or Chromium may be missing system libraries. Install/repair with: )
r#   rN   ÚlowerÚ_cloudÚ_is_local_moder,   r-   Ú_DOCKER_PULLÚ_CHROMIUM_INSTALLr;   )rZ   r[   r\   r]   ÚpartsÚdetails   &&&&  r   Ú_format_browser_timeout_errorri   l   sé   € ð (¨ y°Ð9Ð:€EØ×$Ð$˜×$Ð$ "×+Ñ+Ó-€FßØ�‰�V˜E•]Ô#à�v�h˜b  Ð)×/Ñ/Ó1Ô1Ø�‰ð Dõ 	Eð 
�FÔ	œv×4Ò4×6Ò6Ü×&Ò&×(Ò(Ø�L‰Lð <Ü<H¸>ðKõ Lð �L‰Lð KÜK\ÐJ]ð_ô `à�9‰9�UÓÐr   c                ó0   € V ^8„  d   QhR\         R\        /# )r   Úbrowser_cmdr   )r3   Úlist)r   s   "r   r   r   ƒ   s   € ÷ ñ ¤Sð ¬Tñ r   c                ó   € V .# )zBKeep the selected executable, including spaces, as one argv entry.r.   )rk   s   &r   Ú_agent_browser_argvrn   ƒ   s
   € àˆ=Ðr   c                ó¶   € V ^8„  d   QhR\         R\         R\        \         ,          R\        \         \        \         ,          \        \        ,          3,          /# )r   Úargv0rZ   Úargsr   )r3   rl   rI   r   Úbytes)r   s   "r   r   r   ˆ   sJ   € ÷ Gñ Gœ3ð G¬ð G´D¼µIð GÄ%ÌÌTÔRUÍYÔX`ÔafÕXgÐHgÕBhñ Gr   c                óÐ  € V'       d&   V P                  4       P                  R
4      '       g   WR3# VR8X  d?   Vvr4VR\        P                  ! VP	                  R4      4      P                  R4      .VOR3# VR8X  g;   \        ;QJ d    R V 4       F  '       g   K   RM	  R	M! R V 4       4      '       g   WR3# R. \        P                  ! V.VO.4      P	                  R4      3# )u  ``(spawn_command, spawn_args, stdin_payload)`` for one CLI command. Arguments that reach a
``.cmd``/``.bat`` shim (``npx.cmd``, npm's ``agent-browser.cmd`` on Windows) go through cmd.exe,
which re-parses the child command line: a newline ends the argument and ``%VAR%`` expands even
inside quotes, so a multi-line ``eval`` script arrives as its first line only (``SyntaxError:
Unexpected end of input``) and multi-line ``fill`` text is truncated the same way. ``eval``
scripts are sent base64-encoded (``agent-browser eval -b``); any other command whose argv carries
a newline or ``%`` is wrapped as ``batch`` with the command as a JSON array on stdin â€” cmd.exe
never sees the text (both forms present since the 0.26 floor). Every other spawn gets the raw
argv and no stdin.NÚevalz--base64r   ÚasciiÚbatchc              3   ó<   "  € T F  pR  F	  q"V9   x € K  	  K  	  R# 5i)z
%Nr.   )Ú.0ÚargÚchs   &  r   Ú	<genexpr>Ú"_shim_safe_args.<locals>.<genexpr>—   s   é € Ð$Q¹$°3ËÀ2¨3¦YÉ¡Y»$ùs   ‚TF)z.cmdz.bat)	rb   ÚendswithÚbase64Ú	b64encodeÚencodeÚdecodeÚanyÚjsonÚdumps)rp   rZ   rq   ÚscriptÚrests   &&&  r   Ú_shim_safe_argsr‡   ˆ   sÐ   € ÷ �u—{‘{“}×-Ñ-Ð.>×?Ò?Ø˜dÐ"Ð"Ø�&ÔØˆˆØ˜¤V×%5Ò%5°f·m±mÀGÓ6LÓ%M×%TÑ%TÐU\Ó%]ÐeÐ`dÐeÐgkÐkÐkØ�'Ô§£Ñ$Q¹$Ó$Q§§¢Ñ$Q¹$Ó$Q×!QÒ!QØ˜dÐ"Ð"Ø�BœŸ
š
 WÐ$4¨tÐ$4Ð#5Ó6×=Ñ=¸gÓFÐFÐFr   c                ó^   € V ^8„  d   QhR\         R\        R\        \        \         3,          /# )r   ÚresultrZ   r   )r   r3   r2   )r   s   "r   r   r   œ   s.   € ÷ mñ m¤ð m¬sð m´t¼CÄ¸Hµ~ñ mr   c           	     óh  € \        V \        4      '       g   V # \        V 4      ^8w  g   \        V ^ ,          \        4      '       g(   RRRRV R\        P
                  ! V 4      R,           2/# V ^ ,          pR\        VP                  R4      4      RVP                  R4      RVP                  R4      /# )	z¹``batch --json`` prints ``[{command, success, result, error}]``; reshape the single entry
into the ``{success, data, error}`` dict every other command returns. Error dicts pass through.ÚsuccessFÚerrorzUnexpected batch output for 'ú': ºNi,  NÚdatar‰   )Ú
isinstancerl   Úlenr2   rƒ   r„   r   Úget)r‰   rZ   Úentrys   && r   Ú_unwrap_batch_resultr”   œ   s¥   € ô �fœd×#Ò#ØˆÜ
ˆ6ƒ{�aÔœz¨&°­)´T×:Ò:Ø˜5 'Ð-JÈ7È)ÐSVÔW[×WaÒWaÐbhÓWiÐjnÕWoÐVpÐ+qÐrÐrØ�1�I€EØ”t˜EŸI™I iÓ0Ó1°6¸5¿9¹9ÀXÓ;NÐPWÐY^×YbÑYbÐcjÓYkÐlÐlr   c                ó0   € V ^8„  d   QhR\         R\         /# )r   Úsession_namer   rT   )r   s   "r   r   r   §   s   € ÷ ñ ¬cð ´cñ r   c                óÐ   € \         P                  P                  \        P                  ! 4       RV  24      p\         P
                  ! VRRR7       \        P                  ! W4       V# )uÞ   Create the per-session socket dir (parallel workers must not share one) and claim it
with our PID BEFORE first use â€” another hermes process's orphan reaper rmtree's any
ownerless agent-browser-* dir in the shared tmpdir.zagent-browser-iÀ  T)ÚmodeÚexist_ok)r+   rP   r;   r8   Ú_socket_safe_tmpdirÚmakedirsÚ
_lifecycleÚ_write_owner_pid)r–   Ú
socket_dirs   & r   Ú_prepare_session_socket_dirrŸ   §   sL   € ô —‘—‘œc×5Ò5Ó7¸>È,ÈÐ9XÓY€JÜ‡K‚K�
 °Õ6Ü×Ò 
Ô9ØÐr   c                óR   € V ^8„  d   QhR\         R\        \         \         3,          /# )r   rž   r   ©r3   r2   )r   s   "r   r   r   ±   s"   € ÷ ñ ¬3ð ´4¼¼S¸µ>ñ r   c                ó$  € ^ RI Hp \        P                  ! 4       p\        P
                  ! VP                  RR4      4      VR&   V! RVR7      p^ RIHp V! 4       pV'       d   WBR&   WR&   R	V9  d   \        \        4       R
,          4      VR	&   V# )zëCredential-scrubbed env for one command: PATH fallbacks, the session socket dir, and
daemon-side idle self-termination (agent-browser 0.24+) mirroring the Python janitor
unless the user set ``AGENT_BROWSER_IDLE_TIMEOUT_MS`` explicitly.)Úenv_forÚPATHrM   úagent-browser)Úbase_env)Úchromium_executableÚAGENT_BROWSER_EXECUTABLE_PATHÚAGENT_BROWSER_SOCKET_DIRÚAGENT_BROWSER_IDLE_TIMEOUT_MSiè  )Úpmr£   r8   Ú_build_browser_envr,   Ú_merge_browser_pathr’   Úhermes_cli.browser_runtimer§   r3   Ú_daemon_idle_timeout_seconds)rž   r£   Úenvr§   Ú
executables   &    r   Ú_agent_browser_command_envr²   ±   s‡   € õ ä
×
 Ò
 Ó
"€CÜ×.Ò.¨s¯w©w°v¸rÓ/BÓC€Cˆ�KÙ
�/¨CÔ
0€CÝ>á$Ó&€JßØ/9Ð+Ñ,Ø&0Ð"Ñ#Ø&¨cÔ1Ü/2Ô3OÓ3QÐTXÕ3XÓ/YˆÐ+Ñ,Ø€Jr   c                ó$   € V ^8„  d   QhR\         /# r   )r^   )r   s   "r   r   r   È   s   € ÷ 	2ñ 	2¤cñ 	2r   c                 ó¨   € \         P                  ! 4       '       d)   ^ RIHp  V ! 4       P	                  R4      '       d   \
        # \        P                  # )a}  The daemon's self-termination idle timer. The bot's headed Chromium on the Bot Desktop screen is
shared with a human who may take the lease to log in: the agent is idle by definition then, so the
daemon's own timer must not decide (it cannot see the lease); the lease-aware Python janitor owns that
browser's lifetime, and a crashed hermes leaves it to the orphan reaper (#110064).©Úpublished_envÚDISPLAY)rc   Ú_is_headed_modeÚtools.bot_desktop.runtimer¶   r’   Ú"_SHARED_HEADED_DAEMON_IDLE_SECONDSr8   Ú"BROWSER_SESSION_INACTIVITY_TIMEOUTrµ   s    r   r¯   r¯   È   s;   € ô
 ×Ò×ÒÝ;Ù‹?×Ñ˜y×)Ò)Ü5Ð5Ü×1Ñ1Ð1r   c                óR   € V ^8„  d   QhR\         \        \        3,          R\        /# ©r   Úsession_infor   ©r2   r3   r   r   )r   s   "r   r   r   Ô   s"   € ÷ #ñ #¬T´#´s°(­^ð #Äñ #r   c                óT   € \        V 4      '       g   R# ^ RIHp VP                  4       # )zõTrue while a human holds the Bot Desktop lease over the browser ``session_info`` shares with them.
The janitor treats that as activity: reaping the browser mid-login is the human's session dying under
them, not an idle agent's cleanup (#110064).F©Úlease)Ú_shares_bot_desktop_browserÚtools.bot_desktoprÂ   Úhuman_holds)r¾   Ú	_bd_leases   & r   Úhuman_holds_shared_browserrÇ   Ô   s$   € ô ' |×4Ò4ÙÝ4Ø× Ñ Ó"Ð"r   c                ó   € V ^8„  d   QhRR/# )r   r   Nr.   )r   s   "r   r   r   Þ   s   € ÷ "ñ "¨Dñ "r   c                 óZ   € \         P                  ! 4       '       d   ^ RIHp  V ! 4        R# R# )a.  Tool-call boundary for ``bot_desktop.auto_start`` (mirrors computer_use dispatch): a headed Chromium is
about to be spawned for a real browser action, so a fresh headless profile gets its screen first. Headless
browsing, Lightpanda and the env-only callers of ``_build_browser_env`` never bring one up.©Úensure_started_for_toolN)rc   r¸   r¹   rË   rÊ   s    r   Ú"_ensure_screen_for_headed_chromiumrÌ   Þ   s!   € ô ×Ò×ÒÝEÙÖ!ñ  r   c                óÂ   € V ^8„  d   QhR\         \        ,          R\        \        \        3,          R\        R\        R\        \        ,          R\
        P                  /# )r   Úargvr°   rž   ÚtagÚstdin_payloadr   )rl   r3   r2   r   rr   Ú
subprocessÚPopen)r   s   "r   r   r   ç   sO   € ÷ ñ œt¤C�yð ¬t´C¼°H­~ð Ì3ð ÔUXð Ü(0´­ðÜCM×CSÑCSñr   c                ó&  € R Uu. uFw  p\         P                  ! \         P                  P                  VRV RV 24      \         P                  \         P
                  ,          \         P                  ,          R4      NKy  	  pp\        P                  pVe�   \         P                  P                  VRV 24      p\        VR4      ;_uu_ 4       p	V	P                  V4       RRR4       VP                  \         P                  ! V\         P                  4      4       VR,          p / p
\         P                  R8X  dM   \        P                  ! 4       pV;P                  \        P                  ,          un        R	\!        4       R
RRV/p
\        P"                  ! V 3RV^ ,          RV^,          RVRV/V
B V F  p\         P$                  ! V4       K  	  # u upi   + '       g   i     EL; i  T F  p\         P$                  ! T4       K  	  i ; i)a  Spawn agent-browser with stdout/stderr redirected to ``socket_dir/_std{out,err}_<tag>``;
``stdin_payload`` (a ``batch`` JSON body) is served from ``_stdin_<tag>`` the same way.

Temp files, not pipes: the CLI forks a daemon that inherits its fds, so pipes never
see EOF until the timeout. Windows: CREATE_NO_WINDOW only (CREATE_NEW_PROCESS_GROUP
cancels asyncio's running task on 3.11), STARTF_USESTDHANDLES + close_fds so the child
gets ONLY our three handles (leaked console handles kill the Rust daemon grandchild).
r\   r]   Ú_i€  NÚ_stdin_ÚwbrA   ÚcreationflagsÚ	close_fdsTÚstartupinfoÚstdinr°   )r\   r]   éÿÿÿÿ)r+   r!   rP   r;   ÚO_WRONLYÚO_CREATÚO_TRUNCrÑ   ÚDEVNULLÚwriterN   ÚO_RDONLYrD   ÚSTARTUPINFOÚdwFlagsÚSTARTF_USESTDHANDLESr   rÒ   Úclose)rÎ   r°   rž   rÏ   rÐ   ÚslotÚfdsrÚ   Ú
stdin_pathr%   Ú_popen_extraÚ_siÚfds   &&&&&        r   Ú_popen_agent_browserrì   ç   s•  € ñ ,ó-Ù+ˆtô �7Š7”2—7‘7—<‘< 
¨a°¨v°Q°s°eÐ,<Ó=¼r¿{¹{ÌRÏZÉZÕ?WÔZ\×ZdÑZdÕ?dÐfkÖlÙ+ð ð -ä×#Ñ#€EØÒ Ü—W‘W—\‘\ *°¸°u¨oÓ>ˆ
Ü�*˜d×#Ô# qØ�G‰G�MÔ"÷ $à�
‰
”2—7’7˜:¤r§{¡{Ó3Ô4Ø�B•ˆð	ØˆÜ�7‰7�dŒ?Ü×(Ò(Ó*ˆCØ�KŠKœ:×:Ñ:Õ:�KØ+Ô-?Ó-AÀ;ÐPTÐVcÐehÐiˆLÜ×Ò Ñi¨S°­VÐi¸CÀ½FÐiÈ%ÐiÐUXÐiÐ\hÑiãˆBÜ�HŠH�RŽLò ùò#-÷
 $×#Ð#ûó ˆBÜ�HŠH�RŽLò ús   …A=GÃGÄ'BG/ ÇG,	Ç/!Hc          
      ó¢   € V ^8„  d   QhR\         R\        \         ,          R\        \         \        3,          R\        \         \        3,          /# )r   ÚprefixÚcdp_urlÚfeaturesr   )r3   r   r2   r   )r   s   "r   r   r     sA   € ÷ 6ñ 6œCð 6¬(´3­-ð 6Ä4ÌÌSÈÅ>ð 6ÔVZÔ[^Ô`cÐ[cÕVdñ 6r   c                óh   € RV  R\         P                  ! 4       P                  R,           2RRRVRV/# )zCFresh session dict with a random ``<prefix>_<hex10>`` session name.r–   rÔ   ºNé
   NÚbb_session_idNrï   rð   )ÚuuidÚuuid4Úhex)rî   rï   rð   s   &&&r   Ú_session_recordrø     s<   € à˜v˜h a¬¯
ª
«×(8Ñ(8¸Õ(=Ð'>Ð?ÀÐRVØ�w 
¨Hð6ð 6r   c                óF   € V ^8„  d   QhR\         R\        \         ,          /# ©r   Útask_idr   )r3   r   )r   s   "r   r   r     s"   € ÷ Yñ Yœsð Y¤x´¥}ñ Yr   c                óà   € \         P                  ;_uu_ 4        \         P                  P                  V 4      ;'       g    / P                  R4      uuRRR4       #   + '       g   i     R# ; i)z_The real-profile fallback note on ``task_id``'s existing session; never creates or touches one.Úreal_profile_unavailableN)r8   Ú_cleanup_lockÚ_active_sessionsr’   )rû   s   &r   Úreal_profile_noter     sE   € ä	×	×	Ó	Ü×$Ñ$×(Ñ(¨Ó1×7Ð7°R×<Ñ<Ð=WÓX÷ 
×	×	Ó	ús   ™8AÁA-	c                ó^   € V ^8„  d   QhR\         R\        R\        \         \         3,          /# )r   rû   Úallow_real_profiler   )r3   r   r2   )r   s   "r   r   r     s,   € ÷ ñ ¤3ð ¼Dð ÌDÔQTÔVYÐQYÍNñ r   c                ó~  € RpV'       d®   \         P                  ! 4       w  r4V'       d8   \        P                  P	                  RW4       \         P
                  ! V4      pMWV'       dP   \        R\        P                  ! V4      RRRR/4      p\        P                  P                  RVR,          V 4       V# \        P                  ! 4       '       d(   \        P                  ! 4       '       d   \        V 4      pM7\        R	RRR/4      p\        P                  P                  R
VR,          V 4       V'       d   W%R&   V# )aã  Local Chromium session; consented real-profile CDP attach when allowed.

When the real profile can't be loaded (browser holding its cookies, non-Chromium default,
launch failure) the session falls back to a fresh browser and carries the reason as
``real_profile_unavailable`` so the first navigation tells the model it is signed out. The
hybrid private-URL sidecar passes ``allow_real_profile=False``: the user's cookie jar must
not reach an arbitrary internal host the model chose.
Nz?real-profile unavailable for task %s, using a fresh browser: %sÚrpÚlocalTÚreal_profilez1Created real-profile local session %s for task %sr–   Úhz,Created local browser session %s for task %srý   )Ú_real_profileÚ_real_profile_cdpr8   r9   ÚwarningÚreal_profile_fallback_noterø   Ú_cdpÚ_resolve_cdp_overrideÚinfoÚ_is_browser_use_cli_modeÚ_lpÚ_using_lightpanda_engineÚ_create_lightpanda_session)rû   r  Úfallback_noterï   Úerrr  s   &&    r   Ú_create_local_sessionr    sö   € ð €MßÜ$×6Ò6Ó8‰ˆßÜ�J‰J×ÑÐ`ÐbiÔoÜ)×DÒDÀSÓI‰MßÜ" 4¬×)CÒ)CÀGÓ)LÈwÐX\Ð^lÐnrÐNsÓtˆDÜ�J‰J�O‰OÐOÐQUÐVdÕQeÐgnÔoØˆKô ×#Ò#×%Ò%¬#×*FÒ*F×*HÒ*HÜ)¨'Ó2‰ä˜s D¨7°D¨/Ó:ˆÜ�
‰
�‰ÐFÈÈ^ÕH\Ð^eÔfßØ+8Ð'Ñ(Ø€Kr   c                óR   € V ^8„  d   QhR\         R\        \         \        3,          /# rú   ©r3   r2   r   )r   s   "r   r   r   2  s"   € ÷ 
ñ 
¬ð 
´´S¼#°Xµñ 
r   c                ó4  € ^ RI Hp \        RRRRRR/4      pV! VR,          \        P                  ! 4       '       * R7      w  r4V'       d   \        V4      hVP                  VR	&   \        P                  P                  R
VR,          VP                  V 4       V# )zCSpawn ``lightpanda serve`` for this session key (Browser Use mode).)Úlaunch_lightpandaÚlpNr  TÚ
lightpandar–   )Úblock_private_networksrï   z3Created Lightpanda session %s (port %s) for task %s)Útools.browser_lightpandar  rø   rc   Ú_is_local_backendÚRuntimeErrorrï   r8   r9   r  Úport)rû   r  r  Úserverr  s   &    r   r  r  2  s�   € å:ä˜4 ¨°°|ÀTÐ'JÓK€DÙ# D¨Õ$8ÔU[×UmÒUmÓUoÔQoÔp�K€Fß
Ü˜3ÓÐØ—n‘n€Dˆ�OÜ‡J�J‡O�OÐIÈ4ÐP^ÕK_Ðag×alÑalÐnuÔvØ€Kr   c                óR   € V ^8„  d   QhR\         \        \        3,          R\        /# r½   r¿   )r   s   "r   r   r   ?  s"   € ÷ 3ñ 3¬d´3¼°8­nð 3Äñ 3r   c                óä   € V P                  R4      ;'       g    / P                  R4      '       g   R# ^ RIHp V! V P                  RR4      4      pVRJ ;'       g    VP                  4       '       * # )zATrue for a Lightpanda session whose ``lightpanda serve`` is gone.rð   r  F)Ú
get_serverr–   rM   N)r’   r  r$  Úis_alive)r¾   r$  r!  s   &  r   Ú_local_backend_process_deadr&  ?  s_   € à×Ñ˜ZÓ(×.Ð.¨B×3Ñ3°L×AÒAÙÝ3á˜×(Ñ(¨¸Ó<Ó=€FØ�Tˆ>×2Ð2 §¡Ó!2Ô2Ð2r   c                ó^   € V ^8„  d   QhR\         R\         R\        \         \         3,          /# )r   rû   rï   r   r¡   )r   s   "r   r   r   I  s)   € ÷ ñ ¤ð ¬sð ´t¼CÄ¸Hµ~ñ r   c                óž   € \        RVRR/4      p\        P                  P                  RVR,          \        P                  ! V4      V 4       V# )z3Session connecting to a user-supplied CDP endpoint.ÚcdpÚcdp_overrideTu1   Created CDP browser session %s â†’ %s for task %sr–   )rø   r8   r9   r  Ú_sanitize_url_for_logs)rû   rï   r  s   && r   Ú_create_cdp_sessionr,  I  sE   € ä˜5 '¨N¸DÐ+AÓB€DÜ‡J�J‡O�OÐGØ�^Õ$¤c×&@Ò&@ÀÓ&IÈ7ôTà€Kr   c                óR   € V ^8„  d   QhR\         R\        \         \        3,          /# rú   r  )r   s   "r   r   r   Q  s"   € ÷ ñ ¬sð ÄÄcÌ3ÀhÅñ r   c                ó€  €  VP                  V 4      pV'       d   \        V\        4      '       g   \        RV: 24      hVP	                  R4      '       d5   \        V4      p\
        P                  ! \        VR,          4      4      VR&   V#   \         d¦   p\        T4      P                  p\        P                  P                  RYCT RR7        \        T 4      pM)  \         d   p\        RT RT RT R	24      ThR
p?ii ; i\        T\        4      '       d   / TCRRR\        T4      RT/CpTu R
p?# R
p?ii ; i)z«Cloud session; fall back to local Chromium (marked degraded) on failure. ``cdp_url``
is resolved here because some providers return an HTTP discovery URL, not a websocket.z)Cloud provider returned invalid session: rï   zPCloud provider %s failed (%s); attempting fallback to local Chromium for task %sT©Úexc_infozCloud provider z	 failed (z") and local fallback also failed (Ú)NÚfallback_from_cloudÚfallback_reasonÚfallback_provider)Úcreate_sessionr�   r2   Ú
ValueErrorr’   r  r  r3   Ú	ExceptionÚtypeÚ__name__r8   r9   r
  r  r  )rû   Úproviderr¾   ÚeÚprovider_nameÚlocal_errors   &&    r   Ú!_create_cloud_session_or_fallbackr>  Q  sP  € ðØ×.Ñ.¨wÓ7ˆß¤:¨l¼D×#AÒ#AÜÐHÈÑHXÐYÓZÐZØ×Ñ˜I×&Ò&Ü Ó-ˆLÜ&*×&@Ò&@ÄÀ\ÐR[ÕE\ÓA]Ó&^ˆL˜Ñ#ØÐøÜô Ü˜X›×/Ñ/ˆÜ�
‰
×ÑÐmØ(¨W¸tð 	ô 	Eð	OÜ0°Ó9‰LøÜô 	OÜ °°¸yÈÈð L8Ø8C°}ÀAð Gó HØMNðOûð	Oúô �l¤D×)Ò)ð@˜lð @Ð,AÀ4ÐIZÔ\_Ð`aÓ\bØ/°ñ@ˆLàÕûðúsL   ‚B ›;B Á5B ÂD=Â8D8ÃCÃD8ÃDÃ(C>Ã>DÄ/D8Ä2D=Ä8D=c                ó^   € V ^8„  d   QhR\         R\        R\        \         \        3,          /# )r   rû   Úforce_localr   )r3   r   r2   r   )r   s   "r   r   r   k  s.   € ÷ @ñ @¤Sð @´tð @ÄÄSÌ#ÀXÅñ @r   c                óê   € \         P                  ! 4       pV'       d   V'       g   \        W4      # V'       d   \        V RR7      # \        P
                  ! 4       pVf   \        V 4      # \        W4      # )z­Fresh session for ``task_id`` (runs OUTSIDE the lock: cloud mode makes a network call).
Precedence: CDP override > hybrid local sidecar (never real-profile) > cloud > local.F)r  )r  Ú_get_cdp_overrider,  r  rc   Ú_get_cloud_providerr>  )rû   r@  r*  r:  s   &&  r   Ú_create_session_for_keyrD  k  s\   € ô ×)Ò)Ó+€LßŸKÜ" 7Ó9Ð9ßÜ$ WÀÔGÐGÜ×)Ò)Ó+€HØÒÜ$ WÓ-Ð-Ü,¨WÓ?Ð?r   c                óh   € V ^8„  d   QhR\         \        ,          R\        \        \        3,          /# rú   )r   r3   r2   r   )r   s   "r   r   r   ~  s*   € ÷ Bñ Bœx¬�}ð B¼¼SÄ#¸X½ñ Br   c           	     ó–  a a	€ S f   Ro \         P                  ! 4        \         P                  ! S 4       \        P                  ;_uu_ 4        \        P
                  P                  S 4      o	RRR4       R V	V 3R llpS	e­   \        P                  ! S 4      P                  4       '       g   V! 4       pVe   V# Ro	Mr\         P                  ! S	4      '       g   \        S	4      '       g   S	# \        P                  P                  RS 4       \         P                  ! S 4       V! 4       pVe   V# \        P                  ! S 4      p\        4       p\!        \"        ^,           4       EFk  p\$        P&                  ! V4      p\)        S V4      p\        P                  ;_uu_ 4        S \        P
                  9   d$   \        P
                  S ,          uuRRR4       u # \$        P&                  ! V4      V8g  pV'       d   V\"        8X  d”   \+        V4      pVP-                  RS 4       VP-                  R\        P.                  ! S 4      4       VP-                  RV4       V\        P
                  S &   \        P0                  P3                  S R4        RRR4        M: RRR4       \        P                  P                  R	S 4       \5        S V4       EKn  	  V'       gG   XP                  R
4      ;'       g    / P                  R4      '       g   \$        P6                  ! S 4       X#   + '       g   i     ELÁ; i  + '       g   i     L¥; i)zÂGet or create session info for a session key (thread-safe); also starts the
inactivity thread and touches activity. A ``::local`` key forces local Chromium
even with a cloud provider configured.NÚdefaultc                ó\   € V ^8„  d   QhR\         \        \        \        3,          ,          /# r   )r   r2   r3   r   )r   s   "r   r   Ú'_get_session_info.<locals>.__annotate__‹  s#   € ÷ hñ h¬´$´s¼C°xµ.Õ)Añ hr   c                  óò   <€ \         P                  ! S4       \        P                  ;_uu_ 4        \        P                  P                  S4      p R R R 4       X e	   V SJd   V # R #   + '       g   i     L; irV   )rœ   Ú_update_session_activityr8   rþ   rÿ   r’   )ÚreplacementÚexisting_sessionrû   s    €€r   Ú_replacement_after_teardownÚ6_get_session_info.<locals>._replacement_after_teardown‹  s\   ø€ ô 	×+Ò+¨GÔ4Ü××ÓÜ×.Ñ.×2Ñ2°7Ó;ˆK÷ à)Ò5¸+ÐM]Ó:]ˆ{ÐgÐcgÐg÷ ×ús   ° A&Á&A6	z5Replacing expired or dead browser session for task %sÚsession_keyÚowner_task_idÚhome_keyzCBrowser endpoint changed during session creation for %s; recreatingrð   r  )rœ   Ú_start_browser_cleanup_threadrK  r8   rþ   rÿ   r’   Ú_browser_session_backendÚensure_healthyÚ_session_has_expiredr&  r9   r  Ú_cleanup_single_browser_sessionÚ_is_local_sidecar_keyr	   ÚrangeÚ_STALE_ENDPOINT_RETRIESr  Úlive_cdp_generationrD  r2   Ú
setdefaultÚ_bare_task_id_for_session_keyÚ_suspect_browser_sessionsÚpopÚ_close_unpublished_sessionÚ_ensure_cdp_supervisor)
rû   rN  rL  r@  rR  ÚattemptÚ
generationr¾   ÚstalerM  s
   f        @r   Ú_get_session_infore  ~  s„  ù€ ð ‚Øˆä×,Ò,Ô.Ü×'Ò'¨Ô0ä	×	×	Ó	Ü×/Ñ/×3Ñ3°GÓ<Ð÷ 
÷hñ hð Ò#ô ×+Ò+¨GÓ4×CÑC×EÒEÙ5Ó7ˆKØÒ&Ø"Ð"Ø#ÑÜ×0Ò0Ð1A×BÒBÔKfÐgw×KxÒKxØ#Ð#ä�J‰J�O‰OÐSÐU\Ô]Ü×6Ò6°wÔ?Ù5Ó7ˆKØÒ&Ø"Ð"ä×+Ò+¨GÓ4€KÜÓ €HÜÔ0°1Õ4×5ˆÜ×-Ò-¨hÓ7ˆ
Ü.¨w¸ÓDˆÜ××ÓØœ#×.Ñ.Ô.Ü×+Ñ+¨GÕ4÷ Ôô ×,Ò,¨XÓ6¸*ÑDˆEß˜GÔ'>Ô>Ü# LÓ1�Ø×'Ñ'¨°wÔ?Ø×'Ñ'¨¼×9ZÒ9ZÐ[bÓ9cÔdØ×'Ñ'¨
°HÔ=Ø0<”×$Ñ$ WÑ-Ü×-Ñ-×1Ñ1°'¸4Ô@Ø÷ Ñð ?÷ ô 	�
‰
�‰Ð]Ð_fÔgÜ" 7¨L×9ñ' 6÷.  × 0Ñ 0°Ó <× BÐ BÀ×GÑGÈ×UÒUÜ×#Ò# GÔ,àÐ÷q 
×	Ð	ú÷B ×ús%   Á L$Æ",L8Ç L8Ç<BL8Ì$L5	Ì8Mc                óV   € V ^8„  d   QhR\         R\        \         \        3,          RR/# )r   rû   r¾   r   Nr  )r   s   "r   r   r   Ã  s)   € ÷ ?ñ ?¬ð ?¼4ÄÄSÀ½>ð ?Èdñ ?r   c                ó  a aa€ SP                  R4      ;'       g    / P                  R4      '       d    ^ RIHp V! SP                  RR4      4       M#\        4       oRS9   d   \	        SVVV 3R l4       \
        P                  ! S S4       R# )	z¹Close a session that was never put in ``_active_sessions``, by object: its backend ``close``
and resources only, never a lookup by key (that entry, if any, is another caller's session).rð   r  )Ústop_lightpandar–   rM   rk   c            	      ó4   <€ \        SSS R ,          R. ^
R4      # )rk   rå   N©Ú_dispatch_browser_command)Ú	preflightr¾   rû   s   €€€r   Ú<lambda>Ú,_close_unpublished_session.<locals>.<lambda>Ì  s!   ø€ Ô2KØ˜ y°Õ'?ÀÈ"ÈbÐRVô3Xr   N)r’   r  rh  Ú_browser_command_preflightÚrun_fenced_pairrœ   Ú_release_session_backend)rû   r¾   rh  rl  s   ff @r   r`  r`  Ã  sr   ú€ ð 	×Ñ˜Ó$×*Ð*¨×/Ñ/°×=Ò=Ý<Ù˜×(Ñ(¨¸Ó<Õ=ä.Ó0ˆ	Ø˜IÔ%Ü˜Lö +Xô Yä×'Ò'¨°Ö>r   c                ób   € V ^8„  d   QhR\         R\        \         \        3,          R\         RR/# ©r   rû   r¾   Útask_socket_dirr   Nr  )r   s   "r   r   r   Ñ  s2   € ÷ $7ñ $7´ð $7Ä4ÌÌSÈÅ>ð $7Ôdgð $7Ðlpñ $7r   c                óž  € \         P                  ;_uu_ 4        \         P                  P                  V 4      VJd    RRR4       R# \        P
                  ! V 4       VP                  R4      '       g   VP                  R4      '       d^   \        V4      pR\        P                  ! 4       P                  R,           2VR&   VP                  RR4       V\         P                  V &   M@\         P                  P                  V R4       \         P                  P                  V R4       \         P                  ! V 4      p\         P                  P                  V4      V 8X  d!   \         P                  P                  VR4       RRR4       \        VP                  R4      ;'       g    R4      pV'       d®   \        P                   P#                  \        P                   P%                  W% R	24      4      '       di   \'        W%4      pVf#   \         P(                  P+                  R
V4       R# \,        P.                  ! WbV4      '       g   R#  ^ RIHp VP5                  V4       \<        P>                  ! VRR7       R#   + '       g   i     EL; i  \6        \8        \:        3 d%    \         P(                  P+                  R
T4        R# i ; i)zBDrop a stuck client generation without losing cloud cleanup state.Nrô   rï   Úh_rò   r–   Ú
_first_navrM   ú.pidz.Could not kill timed-out browser daemon for %s)ÚdeadlineT)Úignore_errors) r8   rþ   rÿ   r’   r  Ú_stop_cdp_supervisorr2   rõ   rö   r÷   r_  Ú_session_last_activityr]  Ú_last_active_session_keyr3   r+   rP   Úisfiler;   Ú_read_browser_daemon_pidr9   r:   rœ   Ú_verify_reapable_browser_daemonÚagentry  Úkill_process_treeÚProcessLookupErrorÚPermissionErrorr$   ÚshutilÚrmtree)rû   r¾   rt  rL  Úbare_task_idr–   Ú
daemon_pidÚ	_deadlines   &&&     r   Ú"_discard_timed_out_browser_sessionrŠ  Ñ  s
  € ä	×	×	Ó	Ü×Ñ×#Ñ# GÓ,°LÓ@Ø÷ 
Ñ	ô 	×!Ò! 'Ô*Ø×Ñ˜O×,Ò,°×0@Ñ0@À×0KÒ0KÜ˜|Ó,ˆKØ,.¬t¯zªz«|×/?Ñ/?ÀÕ/DÐ.EÐ*FˆK˜Ñ'Ø�O‰O˜L¨$Ô/Ø,7ŒC× Ñ  Ò)ä× Ñ ×$Ñ$ W¨dÔ3Ü×&Ñ&×*Ñ*¨7°DÔ9ä×8Ò8¸ÓAˆÜ×'Ñ'×+Ñ+¨LÓ9¸WÔDÜ×(Ñ(×,Ñ,¨\¸4Ô@÷ 
ô" �|×'Ñ'¨Ó7×=Ð=¸2Ó>€LßœŸ™Ÿ™¤r§w¡w§|¡|°OÀ~ÐUYÐEZÓ'[×\Ò\Ü-¨oÓLˆ
ØÒÜ�J‰J×ÑÐMÈ|Ô\ÙÜ×9Ò9¸*ÐWc×dÒdÙð	õ 4à×'Ñ'¨
Ô3ô ‡M‚M�/°×6÷E 
×	Ð	ûô> #¤O´WÐ=ô 	Ü�J‰J×ÑÐMÈ|Ô\Úð	ús0   ™%I>Á,I>Á5I>ÂC7I>ÉJ É>J	Ê6KËKc                óR   € V ^8„  d   QhR\         R\         R\        \        ,          /# )r   rt  r–   r   )r3   r   r^   )r   s   "r   r   r   ø  s&   € ÷ ñ ¬cð Äð ÌÔRUÍñ r   c                óÜ   € \         P                  P                  W R24      p \        \	        V4      P                  RR7      P                  4       4      #   \        \        3 d     R# i ; i)z>Read the agent-browser daemon PID for a session (best-effort).rx  rL   r   N)	r+   rP   r;   r^   r   Ú	read_textr#   r$   r6  )rt  r–   Úpid_files   && r   r  r  ø  s]   € ä�w‰w�|‰|˜O¨~¸TÐ-BÓC€HðÜ”4˜“>×+Ñ+°[Ð+ÓA×GÑGÓIÓJÐJøÜ”ZÐ ô Úðús   ¤1A ÁA+Á*A+c                ó<   € V ^8„  d   QhR\         R\        R\        /# )r   rt  Úprobe_timeout_sr   )r3   Úfloatr   )r   s   "r   r   r     s"   € ÷ ñ ´ð Äeð ÔVZñ r   c           	     ó  € \         P                  R8X  d   R# ^ RIp\        VR4      '       g   R#  \         P                  ! V 4      pR T 4        F|  p TP                  TP                  TP                  4      ;_uu_ 4       pTP                  T4       TP                  \         P                  P                  Y4      4        RRR4        R# 	  R#   \
         d     R# i ; i  + '       g   i     K¥  ; i  \
         d     K¶  i ; i)uï   Cheap liveness probe: a connect to the daemon's unix control socket proves the accept
loop is alive (the command wedged page/CDP-side). Windows named pipes can't be probed â†’
report unresponsive (tree-kill + respawn is the safe recovery).rA   FNÚAF_UNIXc              3   óV   "  € T F  qP                  R 4      '       g   K  Vx € K!  	  R# 5i)z.sockN)r}   )rx   r;  s   & r   r{   Ú-_browser_daemon_responsive.<locals>.<genexpr>  s   é € Ð<™W˜¯
©
°7×(;—!’!›Wùs   ‚)Ÿ
)T)r+   rD   Úsocketr*   Úlistdirr$   r“  ÚSOCK_STREAMÚ
settimeoutÚconnectrP   r;   )rt  r�  Ú
socket_modÚentriesr“   Úss   &&    r   Ú_browser_daemon_responsiverž    sÚ   € ô 
‡w�w�$„ÙÛä�:˜y×)Ò)ÙðÜ—*’*˜_Ó-ˆñ =™WÖ<ˆð	Ø×"Ñ" :×#5Ñ#5°z×7MÑ7M×NÔNÐRSØ—‘˜_Ô-Ø—	‘	œ"Ÿ'™'Ÿ,™, Ó>Ô?Ø÷ OÒNñ =ñ øô ô Úðú÷ O×NÐNûô ô 	Úð	úsB   ±C Á.C8ÂAC$ÃC8ÃC!Ã C!Ã$C5Ã/C8Ã5C8Ã8DÄDc                ób   € V ^8„  d   QhR\         R\        \         \        3,          R\         RR/# rs  r  )r   s   "r   r   r     s8   € ÷ 
yñ 
y¬Sð 
yÄÄSÌ#ÀXÅð 
yÔadð 
yÐimñ 
yr   c                ó˜   € VP                  R4      '       g   VP                  R4      '       d   \        WV4       R# \        WVR4       R# )uê   Recover session state after a command timeout.

Cloud/CDP: no daemon to probe â€” replace the stuck client generation now (same
``bb_session_id`` so cloud cleanup works). Local: ``_recycle_local_session``.
See #68139, #72205, #72206.
rô   rï   Nz2browser command timed out; session may be poisoned)r’   rŠ  Ú_recycle_local_session)rû   r¾   rt  s   &&&r   Ú_handle_browser_command_timeoutr¢    s?   € ð ×Ñ˜×(Ò(¨L×,<Ñ,<¸Y×,GÒ,GÜ*¨7À/ÔRÙÜ˜7°/ÐCwÖxr   c          
      ón   € V ^8„  d   QhR\         R\        \         \        3,          R\         R\         RR/# )r   rû   r¾   rt  Úreasonr   Nr  )r   s   "r   r   r   '  s:   € ÷ &5ñ &5¤Cð &5´t¼CÄ¸Hµ~ð &5ÔX[ð &5Ôehð &5Ðmqñ &5r   c                ó   € \         P                  ! V 4      P                  V4       \        VP	                  R4      ;'       g    R4      p\        4       '       d²   \        V4       \         P                  ;_uu_ 4        \         P                  P	                  V 4      VJ dA   \         P                  P                  V R4       \         P                  P                  V R4       RRR4       \         P                  P                  V R4       R# V'       d   \        W$4      MRpVRJ;'       dI    \        P                  ! V4      ;'       d+    \        P                  ! WRV4      ;'       d    \!        V4      pV'       d#   \         P"                  P%                  RW4       R# \         P"                  P%                  RW4       \'        WV4       \         P                  P                  V R4       R#   + '       g   i     EL; i)uÅ  Stop handing out a poisoned local session record (timeout or protocol-level failure).

Daemon alive (PID live, verified as ours, control socket accepts): only the *command*
wedged â€” mark suspect, recycle at next use through ``ensure_healthy``. Daemon wedged or
dead: tree-kill and evict now (Chromium children would leak). Both branches
``mark_suspect`` first so the poisoned-cache invariant holds even if eviction races
another thread's replacement.
r–   rM   Nz\browser daemon for %s is alive (%s); session marked suspect and will be recycled at next usezSbrowser daemon for %s is wedged or dead (%s); tree-killing and evicting the session)r8   rT  Úmark_suspectr3   r’   Ú_browser_in_sandboxÚ_sandbox_close_daemonrþ   rÿ   r_  r|  r^  r  rœ   Ú_pid_existsr€  rž  r9   r
  rŠ  )rû   r¾   rt  r¤  r–   rˆ  Údaemon_alives   &&&&   r   r¡  r¡  '  s‰  € ô × Ò  Ó)×6Ñ6°vÔ>ä�|×'Ñ'¨Ó7×=Ð=¸2Ó>€LÜ×Òä˜lÔ+Ü××ÓÜ×#Ñ#×'Ñ'¨Ó0°LÓ@Ü×$Ñ$×(Ñ(¨°$Ô7Ü×*Ñ*×.Ñ.¨w¸Ô=÷ ô 	×%Ñ%×)Ñ)¨'°4Ô8ÙßLXÔ)¨/ÔHÐ^b€Jà˜$Ð÷ 	8ð 	8Ü×"Ò" :Ó.÷	8ð 	8ä×6Ò6°zÐT`Óa÷	8ð 	8ô ' Ó7ð	 ÷ Ü�
‰
×Ñð 2Ø3:ô	Dáä‡J�J×ÑÐlØô(ä& w¸oÔNô ×!Ñ!×%Ñ% g¨tÖ4÷/ ×Ðús   Á=A$G,Ç,G=	c                ó(   € V ^8„  d   QhR\         RR/# )r   r–   r   NrT   )r   s   "r   r   r   P  s   € ÷ Wñ W¬ð W°ñ Wr   c                óf  € ^ RI HpHp ^ RIHp VP                  RR7      pVe	   V '       g   R#  VP                  V\        RV R.R\        V4      /VP                  V4      ^R	7       R#   \        \        P                  3 d,   p\        P                  P                  R
Y4        Rp?R# Rp?ii ; i)z•``agent-browser --session <name> close`` inside the sandbox (best effort; the daemon's own idle timer and
the sandbox's lifetime bound it otherwise).©ÚruntimeÚsandbox_host©ÚstreamsF©ÚcreateNú	--sessionrå   r©   )Ú	child_envÚuserr[   z'sandbox browser close for %s failed: %s)rÄ   r®  r¯  Útools.environmentsr±  Ú_sandbox_envÚrun_inÚ_SANDBOX_AGENT_BROWSERÚ_sandbox_socket_dirÚ	_user_forr$   rÑ   ÚSubprocessErrorr8   r9   r:   )r–   Ú_bd_runtimer¯  r±  r°   Úexcs   &     r   r¨  r¨  P  s¦   € ÷ GÝ*Ø
×
"Ñ
"¨%Ð
"Ó
0€CØ
‚{Ÿ,ÙðWØ�‰�sÔ3°[À,ÐPWÐXØ"<Ô>QÐRUÓ>VÐ!WÐ^j×^tÑ^tÐuxÓ^yØ!ð 	ö 	#øô ”Z×/Ñ/Ð0ô WÜ�
‰
×ÑÐBÀL×VÒVûðWús   °8A* Á*B0Â B+Â+B0c                ó$   € V ^8„  d   QhR\         /# r   rT   )r   s   "r   r   r   `  s   € ÷ [ñ [¤ñ [r   c                 óT   € ^ RI Hp VP                  V 4      P                  R4       R2# )é    r°  Ú/z!/hermes-bot-desktop/agent-browser)r·  r±  Úsandbox_temp_dirÚrstrip)r°   r±  s   & r   r»  r»  `  s*   € Ý*Ø×&Ñ& sÓ+×2Ñ2°3Ó7Ð8Ð8YÐZÐZr   c                óF   € V ^8„  d   QhR\         R\        \        ,          /# )r   Ú	host_pathr   )r   r   r3   )r   s   "r   r   r   e  s"   € ÷ 	dñ 	d¤tð 	d´¼µñ 	dr   c                óÌ   € \        4       '       g   R# ^ RIHp VP                  RR7      pVf   R# ^ RIHp VP                  V4      P                  R4       RV P                   2# )zeWhere the sandboxed CLI should write a screenshot (its own tmp), or None on a gateway-hosted browser.N©r®  Fr²  r°  rÃ  z/hermes-bot-desktop/shots/)	r§  rÄ   r®  r¸  r·  r±  rÄ  rÅ  rD   )rÇ  r¾  r°   r±  s   &   r   Úsandbox_screenshot_pathrÊ  e  s`   € ä× Ò ÙÝ8Ø
×
"Ñ
"¨%Ð
"Ó
0€CØ
‚{ÙÝ*Ø×&Ñ& sÓ+×2Ñ2°3Ó7Ð8Ð8RÐS\×SaÑSaÐRbÐcÐcr   Ú	max_bytesc                óH   € V ^8„  d   QhR\         R\        R\        R\        /# )r   Úremote_pathÚ
local_destrË  r   )r3   r   r^   r   )r   s   "r   r   r   q  s)   € ÷ 	ñ 	¤Cð 	´Tð 	Ìð 	Ôdhñ 	r   c               óŒ   € \        4       '       g   R# ^ RIHp VP                  RR7      pVf   R# VP	                  WVR7       R# )zcCopy a file the sandboxed browser wrote (a screenshot) to the host; False when not in sandbox mode.FrÉ  r²  )rË  T)r§  rÄ   r®  r¸  Ú
fetch_file)rÍ  rÎ  rË  r¾  r°   s   &&$  r   Úfetch_sandbox_filerÑ  q  s?   € ä× Ò ÙÝ8Ø
×
"Ñ
"¨%Ð
"Ó
0€CØ
‚{ÙØ‡N�N�;°i€NÔ@Ùr   c                ó€   € V ^8„  d   QhR\         \        \        3,          R\         \        \        3,          R\        /# )r   r¾   r‰   r   r¿   )r   s   "r   r   r   }  s<   € ÷ Nñ N¼¼SÄ#¸X½ð NÔPTÔUXÔZ]ÐU]ÕP^ð NÔcgñ Nr   c                óˆ  € V P                  R4      ;'       g    / pVP                  R4      '       d/   VP                  R4      '       g   VP                  R4      '       d   R# V P                  R4      '       g   V P                  R4      '       d   R# VP                  R4      R	J;'       d    VP                  R
4      '       * # )u–  True when a finished command failed at the agent-browser level â€” nonzero exit (101 =
the CLI panicked against a stale session daemon), or empty/non-JSON output from a dead
daemon â€” on a plain local Chromium session. Parsed-JSON failures carry no ``returncode``
(the backend answered; the page said no) and must not recycle; cloud/CDP/real-profile/
Lightpanda sessions have their own recovery (#115184).rð   r  r  r  Frï   rô   Ú
returncodeNr‹   )r’   )r¾   r‰   Úfeatss   && r   Ú%_is_recoverable_local_backend_failurerÖ  }  s–   € ð ×Ñ˜ZÓ(×.Ð.¨B€EØ�9‰9�W×Ò §¡¨<×!8Ò!8¸E¿I¹IÀn×<UÒ<UÙØ×Ñ˜	×"Ò" l×&6Ñ&6°×&GÒ&GÙØ�:‰:�lÓ#¨4Ð/×MÐM¸¿
¹
À9Ó8MÔ4MÐMr   c                óv   € V ^8„  d   QhR\         R\         R\         R\        R\        \         \        3,          /# )r   rZ   r\   r]   rÔ  r   )r3   r^   r2   r   )r   s   "r   r   r   ‹  s=   € ÷ &ñ &¬sð &¼Cð &Ìð &ÔZ]ð &ÔbfÔgjÔloÐgoÕbpñ &r   c                ó‚  € V'       dt   VP                  4       '       d^   V^ 8w  d   \        P                  M\        P                  p\        P
                  P                  VRWP                  4       R,          4       VP                  4       pV'       gœ   V^ 8w  dN   V'       d   VP                  4       MRV 2p\        P
                  P                  RWVR,          4       RRRVR	V/# V \        P                  9  d-   \        P
                  P                  R
V 4       RRRRV  R2R	V/# RRR/ /#  \        P                  ! V4      pT R8X  dx   TP%                  R4      '       da   TP%                  R/ 4      pTP%                  R4      '       g8   TP%                  R4      '       g!   \        P
                  P                  RT4       T#   \        P                   dä    TR,          p\        P
                  P                  RYTR,          4       T R8X  d›   RP                  R YR;'       g    RP                  4       3 4       4      p	\        P                  ! T	4      p
T
'       dL   \        T
4      P!                  4       '       d-   \        P
                  P#                  RT
4       RRRRT
RT//u # RRRRT  RT 2R	T/u # i ; i)uü   Finished agent-browser process output â†’ result dict. Empty stdout with rc=0 is a
broken state (stale daemon) reported as failure except for ``_EMPTY_OK_COMMANDS``;
non-JSON output is an error except ``screenshot``, whose path is recovered from prose.zbrowser '%s' stderr: %sºNiô  NzCommand failed with code zbrowser '%s' failed (rc=%s): %srŽ   r‹   FrŒ   rÔ  z)browser '%s' returned empty output (rc=0)zBrowser command 'z' returned no outputTr�   :NiÐ  Nz1browser '%s' returned non-JSON output (rc=%s): %sÚ
screenshotra   c              3   ó8   "  € T F  q'       g   K  Vx € K  	  R # 5irV   r.   )rx   Úparts   & r   r{   Ú4_interpret_browser_command_output.<locals>.<genexpr>¤  s   é € Ð%eÑ7\¨tÓ`d§d¢dÓ7\ùs   ‚	�
rM   z<browser 'screenshot' recovered file from non-JSON output: %srP   Úrawz(Non-JSON output from agent-browser for 'r�   ÚsnapshotÚrefsz]snapshot returned empty content. Possible stale daemon or CDP connection issue. returncode=%s)r#   ÚloggingÚWARNINGÚDEBUGr8   r9   Úlogr
  Ú_EMPTY_OK_COMMANDSrƒ   ÚloadsÚJSONDecodeErrorr;   Ú	_snapshotÚ"_extract_screenshot_path_from_textr   Úexistsr  r’   )rZ   r\   r]   rÔ  ÚlevelÚstdout_textÚ	error_msgÚparsedrÞ  Úcombined_textÚrecovered_pathÚ	snap_datas   &&&&        r   Ú!_interpret_browser_command_outputrò  ‹  sf  € ÷ �&—,‘,—.’.Ø#-°¤?”—’¼¿¹ˆÜ�
‰
�‰�uÐ7¸Ç,Á,Ã.ÐQUÕBVÔWà—,‘,“.€KßØ˜Œ?ß*0˜Ÿ™œÐ8QÐR\ÐQ]Ð6^ˆIÜ�J‰J×ÑÐ@À'ÐW`ÐaeÕWfÔgØ˜u g¨y¸,È
ÐSÐSØœ#×0Ñ0Ô0Ü�J‰J×ÑÐJÈGÔTØ˜u gÐ1BÀ7À)ÐK_Ð/`ÐbnÐpzÐ{Ð{Ø˜4 ¨Ð,Ð,ðCÜ—’˜KÓ(ˆð �*Ô §¡¨I×!6Ò!6Ø—J‘J˜v rÓ*ˆ	Ø�}‰}˜Z×(Ò(°·±¸v×1FÒ1FÜ�J‰J×Ñð  /Ø0:ô<à€Møô# ×Ñô 	CØ˜%Õ ˆÜ�
‰
×ÑÐNÐPWÐehÐimÕenÔoØ�lÔ"Ø ŸI™IÑ%e¸ÇlÀlÐPR×EYÑEYÓE[Ñ7\Ó%eÓeˆMÜ&×IÒIÈ-ÓXˆNß¤$ ~Ó"6×"=Ñ"=×"?Ò"?Ü—
‘
—‘Ð ^Ð`nÔoØ! 4¨°&¸.È%ÐQTÐ1UÐVÒVØ˜5 'Ð-UÐV]ÐU^Ð^aÐbeÐafÐ+gÐiuð  xBð  Cò  	Cð	Cús&   Ä0G ÇA"J>È)8J>É"A	J>Ê-J>Ê=J>r¥   c                ó$   € V ^8„  d   QhR\         /# r   r   )r   s   "r   r   r   º  s   € ÷ ;ñ ;œTñ ;r   c                 ó\   € ^ RI Hp  V P                  4       P                  V P                  8H  # )uq  The bot's browser runs INSIDE the terminal backend when its screen is PLACED there (policy, not
liveness: same Chromium a human takes over in the pane, same profile, and the host is never touched by a
page the model chose â€” whether or not the screen happens to be up right now). ``_browser_command_preflight``
is where the screen is brought up or the command refused.©Ú	placement)rÄ   rö  ÚresolveÚwhereÚTERMINALrõ  s    r   r§  r§  º  s'   € õ
 ,Ø×ÑÓ×$Ñ$¨	×(:Ñ(:Ñ:Ð:r   c                óÚ   € V ^8„  d   QhR\         \        ,          R\        \        \        3,          R\        R\        \         \        ,          \        \        \        3,          3,          /# )r   Ú	cmd_partsr1   rt  r   )rl   r3   r2   rI   )r   s   "r   r   r   Ã  sT   € ÷ "ñ "œT¤#�Yð "´T¼#¼s¸(µ^ð "ÔVYð "Ô^cÔdhÔilÕdmÔosÔtwÔy|Ðt|Õo}Ðd}Õ^~ñ "r   c           	     ó˜  € \        4       '       g   W3# ^ RIHpHp ^ RIHp VP                  RR7      pVf   \        R4      hVP                  4       pVP                  R4      '       g   \        R4      hVP                  4        UU	u/ uF  w  r‰V\        9   g   K  W‰bK  	  p
pp	V
P                  V4       \        V4      V
R	&   V
P                  R
R4       VP                  V4      V
R&   VP!                  V4      V
R&   \#        VRR4      '       gZ   VP%                  VRR\        V4      V
R,          P'                  R4       R2V
R,          .VP)                  V4      ^R7       RVn        RP-                  \.        4      V
R&   V \1        \3        V ^ ,          4      4      R pVP5                  V\6        .VOV
VP)                  V4      RR7      pVf"   \        \9        V4      P:                   R24      hRVP                  R\<        P>                  P                  RR4      4      R\<        P>                  P                  RR4      /pWÍ3# u up	pi )a8  Rewrite one agent-browser invocation to run inside the sandbox: exec prefix + the CLI by name, with the
browser-relevant variables exported there (the daemon's socket dir mirrors the host path so the host-side
liveness probes keep their shape) and a screen-published DISPLAY. Identity on a gateway-hosted screen.r­  r°  Tr²  NzUthe terminal backend's sandbox is not running, so there is nowhere to run the browserr·   zHthe screen inside the terminal backend's sandbox is gone; start it againr©   r¨   ÚAGENT_BROWSER_PROFILEÚTMPDIRÚ_bd_browser_dirs_readyFÚmkdirz-prÃ  z/hermes-bot-desktop/shots)r¶  r[   r7   r5   )rµ  r¶  Úinteractivez cannot host the browserr¤   rM   ÚHOME) r§  rÄ   r®  r¯  r·  r±  r¸  r  r¶   r’   ÚitemsÚ_SANDBOX_ENV_KEYSÚupdater»  r_  Úbrowser_profile_dirrÄ  Úgetattrr¹  rÅ  r¼  rÿ  r;   r<   r‘   rn   Úremote_commandrº  r8  r9  r+   Úenviron)rû  r1   rt  r¾  r¯  r±  r°   Ú	publishedÚkÚvÚ
remote_envÚtailÚwrappedÚhost_envs   &&&           r   Ú_sandbox_wrapr  Ã  sF  € ô × Ò ØÐ%Ð%ßFÝ*Ø
×
"Ñ
"¨$Ð
"Ó
/€CØ
‚{ÜÐrÓsÐsØ×)Ñ)Ó+€IØ�=‰=˜×#Ò#ô ÐeÓfÐfØ#.×#4Ñ#4Ô#6ÔQÑ#6™4˜1¸!Ô?PÑ:P”$�!’$Ñ#6€JÑQØ×Ñ�iÔ Ü-@ÀÓ-E€JÐ)Ñ*Ø‡N�NÐ2°DÔ9Ø*6×*JÑ*JÈ3Ó*O€JÐ&Ñ'Ø"×3Ñ3°CÓ8€JˆxÑÜ�3Ð0°%×8Ò8Ø�‰�s˜W dÔ,?ÀÓ,DÈÐT\ÕI]×IdÑIdÐehÓIiÐHjð  kDð  GEØ'Ð(?Õ@ðBØHT×H^ÑH^Ð_bÓHcÐmoð 	ô 	qà%)ˆÔ"Ø'*§x¡xÔ0LÓ'M€JÐ#Ñ$à”SÔ,¨Y°q­\Ó:Ó;Ð<Ð=€DØ×$Ñ$ SÔ+AÐ*IÀDÐ*IÐU_Ø*6×*@Ñ*@ÀÓ*EÐSWð %ó Y€Gà‚Üœd 3›i×0Ñ0Ð1Ð1IÐJÓKÐKØ˜Ÿ™¨´·
±
·±¸vÀrÓ0JÓKÈVÔUW×U_ÑU_×UcÑUcÐdjÐlnÓUoÐp€HØÐÐùó% Rs   ÂIÂIc                óF   € V ^8„  d   QhR\         \        \        3,          /# r   ©r2   r3   r   )r   s   "r   r   r   è  s   € ÷ !(ñ !(¤D¬¬c¨¥Nñ !(r   c                 ó<  € ^ RI Hp Hp  VP                  4       pY P
                  8X  d"   ^ RIHp T! 4       '       d   RRRR/# R	\        /#  \        P                  ! 4       p\         P"                  ! 4       '       dž   \        P$                  ! 4       '       gƒ   \         P&                  ! 4       R8w  di   \        P(                  ! 4       '       gN   \        P*                  ! 4       '       d   \,        M\.        p\        P                  P                  RT4       RRRT/# ^ RIHp T! 4       '       d   RRRR/# R	T/#   \         d   pRRRRT 2/u Rp?# Rp?ii ; i  \         d:   p\        P                  P                  R
T4       RRR\        T4      /u Rp?# Rp?ii ; i)u´   Fail fast before spawning (missing CLI, Termux gap, interrupt, no Chromium in local
mode â€” else every call hangs for command_timeout). Error result, or ``{"browser_cmd": path}``.)rö  r®  r‹   FrŒ   zThe browser cannot run here: N)Úis_interruptedÚInterruptedrk   zagent-browser CLI not found: %sr  zbrowser command blocked: %s)rÄ   rö  r®  Útool_placementr  rù  Útools.interruptr  rº  r,   Ú_find_agent_browserÚFileNotFoundErrorr8   r9   r
  r3   rc   rd   Ú_chromium_installedÚ_get_browser_engineÚ_maybe_autoinstall_chromiumr-   Ú_CHROMIUM_MISSING_DOCKER_HINTÚ_CHROMIUM_MISSING_HINT)rö  r¾  rø  r;  r  rk   Úhints          r   ro  ro  è  si  € ÷ DðPØ×*Ñ*Ó,ˆð ×"Ñ"Ô"Ý2Ù×ÒØ˜u g¨}Ð=Ð=ØÔ5Ð6Ð6ð3Ü×2Ò2Ó4ˆô 	×Ò×ÒÜ×,Ò,×.Ò.Ü×&Ò&Ó(¨LÔ8Ü×4Ò4×6Ò6ä08×0KÒ0K×0MÒ0MÕ,ÔSiˆÜ�
‰
×ÑÐ8¸$Ô?Ø˜5 '¨4Ð0Ð0å.Ù×ÒØ˜5 '¨=Ð9Ð9Ø˜;Ð'Ð'øô7 ô PØ˜5 'Ð-JÈ1È#Ð+NÐOÕOûðPûô ô 3Ü�
‰
×ÑÐ<¸aÔ@Ø˜5 '¬3¨q«6Ð2Õ2ûð3ús;   ŠD6 ÁE Ä6EÅEÅ	EÅEÅFÅ".FÆFÆFc                óè   € V ^8„  d   QhR\         R\        \         \        3,          R\        \         ,          R\         R\         R\        R\
        \        ,          R\        \         \        3,          /# )	r   rû   r¾   rû  rZ   Úenginer[   rÐ   r   )r3   r2   r   rl   r^   r   rr   )r   s   "r   r   r     sp   € ÷ 2Wñ 2WÜð2WÜ $¤S¬# X¥ð2WÜ;?Ä½9ð2Wäð2Wäð2Wä(+ð2Wä<DÄU½Oð2Wô 
Œ#Œsˆ(…^ñ2Wr   c           
     óR  € \        VR,          4      p\        P                  P                  RW0V\	        V4      4       VR8w  d   \        4        \        V4      pVR8X  d|   R U	u. uF  q˜P                  V	R4      NK  	  p
p	\        ;QJ d    R V
 4       F  '       g   K   RM	  RM! R V
 4       4      '       d!   \        P                  P                  RV4       MH\        V4       VP                  R	4      '       g'   \        P                  ! 4       '       g   \        V4      p\        P                  P!                  VR
V 24      p\        P                  P!                  VRV 24      p\#        W(V4      w  r(\%        W(WsV4      p VP'                  VR7       \;        TRRR7      ;_uu_ 4       pTP=                  4       pRRR4       \;        TRRR7      ;_uu_ 4       pTP=                  4       pRRR4       \1        Y¼4       \?        TXXTP@                  4      # u up	i   \(        P*                   dÌ    TP-                  4        TP'                  4        \/        Y¼4      w  rï\1        Y¼4       \3        YT4       T'       dL   TP5                  4       '       d6   \        P                  P7                  RY?P5                  4       R,          4       \        P                  P7                  RY5Y4       RRR\9        Y5Yï4      /u # i ; i  + '       g   i     ELK; i  + '       g   i     EL0; i)zTRun the prepared agent-browser argv once and interpret its output (handles timeout).r–   z/browser cmd=%s task=%s socket_dir=%s (%d chars)r  Nc              3   ó(   "  € T F  qR Jx € K
  	  R # 5irV   r.   )rx   r  s   & r   r{   Ú%_spawn_and_collect.<locals>.<genexpr>  s   é € Ð/¡h ˜�}£hùs   ‚TFz�browser: stripped Chromium-only AGENT_BROWSER_ARGS/AGENT_BROWSER_CHROME_FLAGS for Lightpanda command %s (agent-browser rejects them with --engine lightpanda)rï   Ú_stdout_Ú_stderr_)r[   z%browser '%s' stderr after timeout: %srÙ  z9browser '%s' timed out after %ds (task=%s, socket_dir=%s)r‹   rŒ   rK   rL   r   )r5   r6   )!rŸ   r8   r9   r:   r‘   rÌ   r²   r_  r‚   r=   r’   rc   r¸   rE   r+   rP   r;   r  rì   ÚwaitrÑ   ÚTimeoutExpiredÚkillrQ   rX   r¢  r#   r
  ri   r!   r"   rò  rÔ  )rû   r¾   rû  rZ   r"  r[   rÐ   rt  r1   r  ÚstrippedrG   rH   Úprocr\   r]   r%   s   &&&&&&&          r   Ú_spawn_and_collectr-    s{  € ô
 2°,¸~Õ2NÓO€OÜ‡J�J×ÑÐFØ ?´C¸Ó4HôJà�ÔÜ*Ô,Ü,¨_Ó=€Kð �ÔÙ6jÓkÑ6j°—O‘O A tÖ,Ñ6jˆÐkß‹3Ñ/¡hÓ/�3�3Š3Ñ/¡hÓ/×/Ò/Ü�J‰J×Ñð oà$ô&øô 	% [Ô1ð ×Ñ 	×*Ò*´6×3IÒ3I×3KÒ3KÜ:¸;ÓGˆKä—'‘'—,‘,˜°(¸7¸)Ð0DÓE€KÜ—'‘'—,‘,˜°(¸7¸)Ð0DÓE€KÜ*¨9À?ÓSÑ€IÜ 	¸ÐR_Ó`€DðlØ�	‰	˜'ˆ	Ô"ô 
ˆk˜3¨×	5Õ	5¸Ø—‘“ˆ÷ 
6ä	ˆk˜3¨×	5Õ	5¸Ø—‘“ˆ÷ 
6ä  Ô:Ü,¨W°f¸fÀdÇoÁoÓVÐVùòG løô& ×$Ñ$ô 
lØ�	‰	ŒØ�	‰	ŒÜ3°KÓM‰ˆÜ$ [Ô>Ü'¨¸ÔOß�f—l‘l—n’nÜ�J‰J×ÑÐFÈ×Q]ÑQ]ÓQ_Ð`dÕQeÔfÜ�
‰
×ÑÐVØ¨ô	Cà˜5 'Ô+HÈÐ[aÓ+jÐkÒkð
lú÷ 
6×	5Ð	5úç	5×	5Ð	5ús8   Á%HÆH Æ.LÇLÈA6K>ÊA&K>Ë=K>ÌL	ÌL&	c                ó¼   € V ^8„  d   QhR\         \        \        3,          R\        . \         \        \        3,          3,          R\         \        \        3,          /# ©r   r¾   Úfnr   )r2   r3   r   r   )r   s   "r   r   r   A  sH   € ÷ ñ œT¤#¤s (�^ð ´¸"¼dÄ3ÌÀ8½nÐ:LÕ1Mð ÔRVÔWZÔ\_ÐW_ÕR`ñ r   c                ó2  € \        V 4      '       g   V! 4       # ^ RIHp  VP                  4       pT! 4       pTP                  4       P                  TP                  8w  d	   RRRRRR/# T#   TP                   d   pRRR\        T4      RR/u Rp?# Rp?ii ; i)	aU  Run ``fn`` under the Bot Desktop lease fence when ``session_info`` is the bot's LOCAL browser.

That browser lives on the Bot Desktop screen, in the same profile a human who took over is typing
into. While the human holds the lease every action AND read against it is refused (the page may show
their credential); the fence brackets the whole run so a takeover mid-command also voids the result.
Cloud / user-supplied CDP sessions are a different browser and run unfenced. This is THE fence: every
path that reaches the page (agent-browser subprocess, CDP supervisor fast path) goes through here.
rÁ   r‹   FrŒ   ÚcodeÚhuman_has_controlNz”A human took over the bot's screen while this browser command ran; its result was discarded. Tell the user what you need; retry once they hand back.)rÃ   rÄ   rÂ   Úassert_agent_may_actÚHumanHasControlr3   r’   Úepoch)r¾   r0  rÆ   Úadmittedr;  r‰   s   &&    r   Ú
run_fencedr8  A  s¦   € ô ' |×4Ò4Ù‹tˆÝ4ðPØ×1Ñ1Ó3ˆñ ‹T€FØ‡}�}ƒ×Ñ §¡Ô.Ø˜5 &Ð*=Øð ^ð_ð 	_ð €Møð ×$Ñ$ô PØ˜5 '¬3¨q«6°6Ð;NÐOÕOûðPús    A* Á*BÁ;BÂBÂBc          
      ó   € V ^8„  d   QhR\         \        \        3,          R\        . \        \        \         \        \        3,          3,          3,          R\        \        \         \        \        3,          3,          /# r/  )r2   r3   r   r   rI   )r   s   "r   r   r   Y  sa   € ÷ 
=ñ 
=¤$¤s¬C x¥.ð 
=´h¸rÄ5ÌÌdÔSVÔX[ÐS[ÍnÐI\ÕC]Ð?]Õ6^ð 
=ÔchÔilÔnrÔsvÔx{Ðs{Õn|Ði|Õc}ñ 
=r   c                ób   aa€ . oR VV3R llp\        W4      pS'       d   S^ ,          V3# RV3# )zd``run_fenced`` for the dispatch shape ``(engine, result)``; a refusal carries no engine (never ran).c                óF   € V ^8„  d   QhR\         \        \        3,          /# r   r  )r   s   "r   r   Ú%run_fenced_pair.<locals>.__annotate__]  s   € ÷ ñ ”4œœS˜•>ñ r   c                  ó<   <€ S! 4       w  rSP                  V 4       V# rV   )rN   )r"  r‰   Ú
engine_boxr0  s     €€r   Ú_callÚrun_fenced_pair.<locals>._call]  s   ø€ Ù›‰ˆØ×Ñ˜&Ô!Øˆr   Úauto)r8  )r¾   r0  r?  r‰   r>  s   &f  @r   rp  rp  Y  s9   ù€ à€J÷ñ ô
 ˜Ó,€Fß'ˆJ�q�M°fÐ<Ð<¨V°fÐ<Ð<r   c                óR   € V ^8„  d   QhR\         \        \        3,          R\        /# r½   r¿   )r   s   "r   r   r   f  s&   € ÷ Wñ W¬d´3¼°8­nð WÄñ Wr   c                óö   € V P                  R4      ;'       g    / P                  R4      '       g   R# ^ RIHpHp \	        VP                  4       P                  R4      4      ;'       g    VP                  4       # )u�  Decided by provenance, not transport: every LOCAL session (plain ``--session``, real-profile CDP
attach, Lightpanda) is a browser Hermes launched with this profile's Bot Desktop DISPLAY, so it is the
screen a human who took over is typing into. Cloud / user-supplied CDP sessions are another browser.
A human lease with the screen already gone (dead Xvnc) still fences â€” computer_use does the same.rð   r  F)rÂ   r®  r·   )r’   rÄ   rÂ   r®  r   r¶   rÅ   )r¾   rÆ   r¾  s   &  r   rÃ   rÃ   f  s^   € ð
 ×Ñ˜ZÓ(×.Ð.¨B×3Ñ3°G×<Ò<ÙßLÜ�×)Ñ)Ó+×/Ñ/°	Ó:Ó;×VÐV¸y×?TÑ?TÓ?VÐVr   c                óh   € V ^8„  d   QhR\         \        \        3,          R\        \        ,          /# r½   )r2   r3   r   r   r^   )r   s   "r   r   r   q  s*   € ÷ _ñ _¬4´´S°­>ð _¼hÄs½mñ _r   c                ó–   € \        V 4      '       g   R# ^ RIHp VP                  \	        VP                  4       4      V R,          R7      # )z]DevTools port of a human-started Chromium on the Bot Desktop's shared profile, else ``None``.N)Úbrowserr–   )Úexclude_session)rÃ   rÄ   rF  Úrunning_instance_cdp_portr3   Úprofile_dir)r¾   Ú_bd_browsers   & r   Ú_bot_desktop_attach_portrK  q  sE   € ä& |×4Ò4ÙÝ8Ø×0Ñ0´°[×5LÑ5LÓ5NÓ1OØAMÈnÕA]ð 1ó _ð _r   c                ó
  € V ^8„  d   QhR\         R\        \         \        3,          R\         R\         R\        \         ,          R\        R\
        \         ,          R\        \         \        \         \        3,          3,          /# )	r   rû   r¾   rk   rZ   rq   r[   Ú_engine_overrider   )r3   r2   r   rl   r^   r   rI   )r   s   "r   r   r   z  sr   € ÷ (ñ (Üð(Ü $¤S¬# X¥ð(Ü=@ð(ÜKNð(ÜVZÔ[^ÕV_ð(äð(ä$,¬S¥Mð(ô Œ3””Sœ#�X•ÐÕñ(r   c                óL  € VR8w  d.   VP                  R4      '       d   \        P                  ! V 4       T;'       g    \        P                  ! 4       pRVR,          .pVP                  R4      '       d   VRVR,          .,          pM|\        V4      ;p	e   VR\        V	4      .,          p\        P                  ! 4       '       d   VP                  R4       VR8w  d'   \        P                  ! 4       '       g   VR	V.,          p\        V4      p
\        V
^ ,          W44      w  r¼pW¨,           R
V.,           V,           p \        \        WWãWuV4      V4      pW3#   \         d?   p\        P                   P#                  RTTRR7       RRR\        T4      /p Rp?Y3# Rp?ii ; i)u[   Build the agent-browser argv for ``session_info`` and run it once â†’ ``(engine, result)``.rå   rï   r´  r–   z--cdpNz--headedrA  z--enginez--jsonzbrowser '%s' exception: %sTr/  r‹   FrŒ   )r’   r  ra  rc   r  rK  r3   r¸   rN   r8   Ú_is_camofox_modern   r‡   r”   r-  r7  r9   r
  )rû   r¾   rk   rZ   rq   r[   rM  r"  Úbackend_argsÚbd_portrÎ   Úspawn_commandÚ
spawn_argsrÐ   rû  r‰   r;  s   &&&&&&&          r   rk  rk  z  s‡  € ð �'Ô˜l×.Ñ.¨y×9Ò9Ü×#Ò# GÔ,ð ×=Ð=¤×!;Ò!;Ó!=€FØ ¨nÕ!=Ð>€LØ×Ñ˜	×"Ò"Ø˜ ,¨yÕ"9Ð:Õ:‰ä/°Ó=Ð=ˆGÒJð
 ˜W¤c¨'£lÐ3Õ3ˆLÜ×!Ò!×#Ò#Ø×Ñ 
Ô+Ø�VÔ¤C×$8Ò$8×$:Ò$:Ø˜Z¨Ð0Õ0ˆLä˜{Ó+€DÜ/>¸tÀA½wÈÓ/VÑ,€M˜}ØÕ# x°Ð&?Õ?À*ÕL€Ið5Ü%Ü˜w°iÈ&Ð[hÓiÐkrótˆð
 ˆ>Ðøô ô 5Ü�
‰
×ÑÐ7¸À!ÈdÐÔSØ˜U G¬S°«VÐ4ŒØˆ>Ðûð5ús   Ä?E ÅF#Å%2FÆF#c                óÒ   € V ^8„  d   QhR\         R\         R\        \         ,          R,          R\        \        ,          R\        \         ,          R\        \         \
        3,          /# )r   rû   rZ   rq   Nr[   rM  r   )r3   rl   r   r^   r2   r   )r   s   "r   r   r   ¥  s]   € ÷ 5ñ 5Üð5äð5ô Œs�)�dÕ
ð5ô ”c�]ð	5ô
 œs•mð5ô 
Œ#Œsˆ(…^ñ5r   c                ó  a aaaaaa€ Sf   \         P                  ! 4       oS;'       g    . o\        4       pRV9  d   V# VR,          o\        ^4       FÇ  p \	        S 4      o\        STTTTTT T3R l4      w  r‰T	P                  R	4      R
8X  d   T	u # T^ 8X  d€   SR8w  dy   \        ST	4      '       dg   \         P                  P                  RSS T	P                  R4      4       \        S S\        SR,          4      RS RT	P                  R4       24       KÇ   M	  \        P                  ! XSX	4      p
V
'       d|   \         P                  P                  RSS V
4       SR8X  d$   \        P                   ! S S;'       g    . S4      pM\        P"                  ! S SSS4      p\        P$                  ! Wº4      # V	#   \
         d8   p\         P                  P                  RS T4       RRRRT: 2/u Rp?u # Rp?ii ; i)a  Run one agent-browser CLI command against the task's session; returns its parsed JSON.
``timeout=None`` reads ``browser.command_timeout``; ``_engine_override`` forces an engine
for this call only (Lightpanda fallback retries with Chrome without touching global state).Nrk   z0Failed to create browser session for task=%s: %sr‹   FrŒ   z"Failed to create browser session: c            	      ó&   <€ \        SSSSSSS 4      # rV   rj  )rM  rq   rk   rZ   r¾   rû   r[   s   €€€€€€€r   rm  Ú&_run_browser_command.<locals>.<lambda>¾  s   ø€ Ô?XØ�\ ;°¸¸wÐHXô@Zr   r2  r3  rå   zbbrowser '%s' failed at the backend level (task=%s, rc=%s); recycling the session and retrying oncerÔ  r–   zagent-browser 'z	' exited z<Lightpanda fallback: retrying '%s' with Chrome (task=%s): %srÚ  )r8   Ú_safe_command_timeoutro  rY  re  r7  r9   r
  rp  r’   rÖ  r¡  rŸ   r  Ú_lightpanda_fallback_reasonr  Ú_chrome_fallback_screenshotÚ_run_chrome_fallback_commandÚ_annotate_lightpanda_fallback)rû   rZ   rq   r[   rM  rl  rb  r;  r"  r‰   r3  Úfallback_resultrk   r¾   s   fffff       @@r   Ú_run_browser_commandr^  ¥  sä  þ€ ð ‚Ü×+Ò+Ó-ˆØ�:ˆ:�2€Dä*Ó,€IØ˜IÔ%ØÐØ˜MÕ*€Kä˜–8ˆð	[Ü,¨WÓ5ˆLô )¨÷ 8Zò 8Zó [‰ˆà�:‰:�fÓÐ!4Ô4ØŠMð �aŒ<˜G wÔ.Ô3XÐYeÐgm×3nÒ3nÜ�J‰J×Ñð  3Ø4;¸WÀfÇjÁjÐQ]ÓF^ô`ä" 7¨LÔ:UÐVbÐcqÕVrÓ:sØ%4°W°I¸YÀvÇzÁzÐR^ÓG_ÐF`Ð#aôcáÙñ+ ô2 ×5Ò5°f¸gÀvÓN€OßÜ�
‰
�‰ÐVÐX_ÐahÐjyÔzØ�lÔ"Ü!×=Ò=¸gÀtÇzÀzÈrÐSZÓ[‰Oä!×>Ò>¸wÈÐQUÐW^Ó_ˆOÜ×0Ò0°ÓRÐRà€Møô? ô 	[Ü�J‰J×ÑÐQÐSZÐ\]Ô^Ø˜u gÐ1SÐTUÑSXÐ/YÐZ×Zûð	[ús   ÁF<Æ<G>Ç*G9Ç1G>Ç9G>)z--no-sandboxz--disable-dev-shm-usagerV   i€Q )T)g      ð?i   )r©   rª   r5   rý  r¨   rB   r·   Ú
XAUTHORITYÚDBUS_SESSION_BUS_ADDRESSÚANONYMIZED_TELEMETRYrþ  )NNN)^Ú__doc__r~   rƒ   rá  r+   r…  rÑ   rõ   Úpathlibr   Útypingr   r   r   r   r   Úhermes_cli._subprocess_compatr   Úhermes_constantsr	   Útools.browser_tool_originr
   r8   Útoolsr   r  r   rc   r   r,   r   rœ   r   r  r   r  r   rè  re   rf   r  r  r<   r&   r/   r=   rE   rQ   rX   ri   rn   r‡   r”   rŸ   r²   rº   r¯   rÇ   rÌ   rì   rø   r   r  r  r&  r,  r>  rD  rZ  re  r`  rŠ  r  rž  r¢  r¡  r¨  r»  rÊ  rÑ  rÖ  rò  rº  r  r§  r  ro  r-  r8  rp  rÃ   rK  rk  r^  r.   r   r   Ú<module>ri     s¯  ðñó Û Û Û 	Û Û Û Ý ß 6Õ 6å <Ý ,Ý 3Ý *Ý .Ý 2Ý 6Ý 9Ý <Ý 4àE€ØiÐ ð"AØAMÀð"PÐ àIÐJ[ÐI\Ð]Ð ð  KÐ õõ4õS÷<õ(	õõõ.õ
Gõ(mõõð( &/Ð "õ	2õ#õ"÷õ>6õY÷õ@
õ3õõõ4@ð  Ð ÷BõJ?õ$7õN÷õ2
yõ&5õRWõ [õ
	dð	ÐO_÷ 	õNõ&ðR )Ð ðlÐ õ
;õ"õJ!(÷H2Wõjõ0
=õWõ_õ(÷V5ñ 5r   