§
    ‰eîi6T  ã                  óæ  — U d Z ddlmZ ddlZddlZddlZddlZddlZddlZddl	m
Z
mZmZ ddlZddlmZ ddlmZ ddlmZ  ej        e¦  «        ZdZd	Zdad
ed<   dad?d„Zd@d„Zd@d„ZdAd„Zd@d„Z i Z!ded<    ej"        ¦   «         Z#dBd„Z$dCdDd„Z%dEd„Z&dFdGd„Z'efdHd%„Z(defdId'„Z)defdJd)„Z*defdHd*„Z+dFdKd+„Z,	 	 dLdMd.„Z-dFdNd0„Z.dFdOd2„Z/dFdPd4„Z0dFdQd5„Z1dFdRd7„Z2dFdQd8„Z3dFdQd9„Z4	 	 dSdTd<„Z5dSdUd>„Z6dS )VuA  Camofox browser backend â€” local anti-detection browser via REST API.

Camofox-browser is a self-hosted Node.js server wrapping Camoufox (Firefox
fork with C++ fingerprint spoofing).  It exposes a REST API that maps 1:1
to our browser tool interface: accessibility snapshots with element refs,
click/type/scroll by ref, screenshots, etc.

When ``CAMOFOX_URL`` is set (e.g. ``http://localhost:9377``), the browser
tools route through this module instead of the ``agent-browser`` CLI.

Setup::

    # Option 1: npm
    git clone https://github.com/jo-inc/camofox-browser && cd camofox-browser
    npm install && npm start   # downloads Camoufox (~300MB) on first run

    # Option 2: Docker
    docker run -p 9377:9377 -e CAMOFOX_PORT=9377 jo-inc/camofox-browser

Then set ``CAMOFOX_URL=http://localhost:9377`` in ``~/.hermes/.env``.
é    )ÚannotationsN)ÚAnyÚDictÚOptional)Úload_config)Úget_camofox_identity)Ú
tool_erroré   i€8 úOptional[str]Ú_vnc_urlFÚreturnÚstrc                 óR   — t          j        dd¦  «                             d¦  «        S )z:Return the configured Camofox server URL, or empty string.ÚCAMOFOX_URLÚ ú/)ÚosÚgetenvÚrstrip© ó    ú7/home/div/.hermes/hermes-agent/tools/browser_camofox.pyÚget_camofox_urlr   3   s"   € åŒ9�] BÑ'Ô'×.Ò.¨sÑ3Ô3Ð3r   Úboolc                 óŠ   — t          j        dd¦  «                             ¦   «         rdS t          t	          ¦   «         ¦  «        S )aq  True when Camofox backend is configured and no CDP override is active.

    When the user has explicitly connected to a live Chrome instance via
    ``/browser connect`` (which sets ``BROWSER_CDP_URL``), the CDP connection
    takes priority over Camofox so the browser tools operate on the real
    browser instead of being silently routed to the Camofox backend.
    ÚBROWSER_CDP_URLr   F)r   r   Ústripr   r   r   r   r   Úis_camofox_moder   8   s>   € õ 
„yÐ" BÑ'Ô'×-Ò-Ñ/Ô/ð ØˆuÝ•Ñ!Ô!Ñ"Ô"Ð"r   c                 óÌ  — t          ¦   «         } | sdS 	 t          j        | › d�d¬¦  «        }|j        dk    r’t          s‹	 |                     ¦   «         }|                     d¦  «        }t          |t          ¦  «        r2d|cxk    rdk    r%n n"d	d
lm	}  || ¦  «        }|j
        pd}d|› d|› �an# t          t          f$ r Y nw xY wda|j        dk    S # t          $ r Y dS w xY w)z'Verify the Camofox server is reachable.Fz/healthé   ©ÚtimeoutéÈ   ÚvncPorté   iÿÿ  r   )ÚurlparseÚ	localhostzhttp://ú:T)r   ÚrequestsÚgetÚstatus_codeÚ_vnc_url_checkedÚjsonÚ
isinstanceÚintÚurllib.parser&   Úhostnamer   Ú
ValueErrorÚKeyErrorÚ	Exception)ÚurlÚrespÚdataÚvnc_portr&   ÚparsedÚhosts          r   Úcheck_camofox_availabler;   E   sA  € õ Ñ
Ô
€CØð ØˆuðÝŒ|˜s˜O˜O˜O°QÐ7Ñ7Ô7ˆØÔ˜sÒ"Ð"Õ+;Ð"ð	Ø—y’y‘{”{�ØŸ8š8 IÑ.Ô.�Ý˜h­Ñ,Ô,ð ;°°hÐ1GÐ1GÒ1GÐ1GÀ%Ò1GÐ1GÐ1GÐ1GÐ1GØ5Ð5Ð5Ð5Ð5Ð5Ø%˜X c™]œ]�FØ!œ?Ð9¨k�DØ:¨Ð:Ð:°Ð:Ð:�HøøÝ¥Ð)ð ð ð Ø�ðøøøà#ÐØÔ 3Ò&Ð&øÝð ð ð Øˆuˆuðøøøs6   ”+C Á A0B1 Â0C Â1CÃC ÃCÃC Ã
C#Ã"C#c                 ó:   — t           st          ¦   «          t          S )z>Return the VNC URL if the Camofox server exposes one, or None.)r,   r;   r   r   r   r   Úget_vnc_urlr=   ^   s   € åð "ÝÑ!Ô!Ð!Ý€Or   c                 ó  — 	 t          ¦   «                              di ¦  «                             di ¦  «        } n3# t          $ r&}t                               d|¦  «         Y d}~dS d}~ww xY wt          |                      d¦  «        ¦  «        S )al  Return whether Hermes-managed persistence is enabled for Camofox.

    When enabled, sessions use a stable profile-scoped userId so the
    Camofox server can map it to a persistent browser profile directory.
    When disabled (default), each session gets a random userId (ephemeral).

    Controlled by ``browser.camofox.managed_persistence`` in config.yaml.
    ÚbrowserÚcamofoxz<managed_persistence check failed, defaulting to disabled: %sNFÚmanaged_persistence)r   r*   r4   ÚloggerÚwarningr   )Úcamofox_cfgÚexcs     r   Ú_managed_persistence_enabledrF   e   s‘   € ðÝ!‘m”m×'Ò'¨	°2Ñ6Ô6×:Ò:¸9ÀbÑIÔIˆˆøÝð ð ð Ý�ŠÐUÐWZÑ[Ô[Ð[Øˆuˆuˆuˆuˆuøøøøðøøøõ �—’Ð 5Ñ6Ô6Ñ7Ô7Ð7s   ‚69 ¹
A)ÁA$Á$A)zDict[str, Dict[str, Any]]Ú	_sessionsÚtask_idúDict[str, Any]c                óp  — | pd} t           5  | t          v rt          |          cddd¦  «         S t          ¦   «         r#t          | ¦  «        }|d         d|d         ddœ}n3dt	          j        ¦   «         j        dd…         › �dd	| dd
…         › �ddœ}|t          | <   |cddd¦  «         S # 1 swxY w Y   dS )zÿGet or create a camofox session for the given task.

    When managed persistence is enabled, uses a deterministic userId
    derived from the Hermes profile so the Camofox server can map it
    to the same persistent browser profile across restarts.
    ÚdefaultNÚuser_idÚsession_keyT)rL   Útab_idrM   ÚmanagedÚhermes_é
   Útask_é   F)Ú_sessions_lockrG   rF   r   ÚuuidÚuuid4Úhex)rH   ÚidentityÚsessions      r   Ú_get_sessionrZ   ~   sG  € ð Ð"˜€GÝ	ð ð Ø•iÐÐÝ˜WÔ%ðð ð ð ñ ô ð ð õ (Ñ)Ô)ð 	Ý+¨GÑ4Ô4ˆHà# IÔ.ØØ'¨Ô6Øð	ð ˆGˆGð =¥T¤Z¡\¤\Ô%5°c°r°cÔ%:Ð<Ð<ØØ5 w¨s°¨s¤|Ð5Ð5Ø ð	ð ˆGð %�	�'ÑØð'ð ð ð ñ ô ð ð ð ð ð ð øøøð ð ð ð ð ð s   ŒB+¯A/B+Â+B/Â2B/úabout:blankr5   c                ó2  — t          | ¦  «        }|d         r|S t          ¦   «         }t          j        |› d�|d         |d         |dœt          ¬¦  «        }|                     ¦   «          |                     ¦   «         }|                     d¦  «        |d<   |S )z<Ensure a tab exists for the session, creating one if needed.rN   z/tabsrL   rM   )ÚuserIdÚ
sessionKeyr5   ©r-   r"   ÚtabId)rZ   r   r)   ÚpostÚ_DEFAULT_TIMEOUTÚraise_for_statusr-   r*   )rH   r5   rY   Úbaser6   r7   s         r   Ú_ensure_tabre   œ   s©   € å˜7Ñ#Ô#€GØˆxÔð ØˆÝÑÔ€DÝŒ=Øˆˆˆà˜iÔ(Ø! -Ô0Øð
ð 
õ
 !ðñ ô €Dð 	×ÒÑÔÐØ�9Š9‰;Œ;€DØŸš Ñ)Ô)€GˆHÑØ€Nr   úOptional[Dict[str, Any]]c                ó‚   — | pd} t           5  t                               | d¦  «        cddd¦  «         S # 1 swxY w Y   dS )zRemove and return session info.rK   N)rT   rG   Úpop©rH   s    r   Ú_drop_sessionrj   ±   s‡   € àÐ"˜€GÝ	ð ,ð ,Ý�}Š}˜W dÑ+Ô+ð,ð ,ð ,ð ,ñ ,ô ,ð ,ð ,ð ,ð ,ð ,ð ,øøøð ,ð ,ð ,ð ,ð ,ð ,s   Œ4´8»8c                óz   — t          ¦   «         r,t          | ¦  «         t                               d| ¦  «         dS dS )aœ  Release the in-memory session without destroying the server-side context.

    When managed persistence is enabled the browser profile (and its cookies)
    must survive across agent tasks.  This helper drops only the local tracking
    entry and returns ``True``.  When managed persistence is *not* enabled it
    does nothing and returns ``False`` so the caller can fall back to
    :func:`camofox_close`.
    z6Camofox soft cleanup for task %s (managed persistence)TF)rF   rj   rB   Údebugri   s    r   Úcamofox_soft_cleanuprm   ¸   s?   € õ $Ñ%Ô%ð Ý�gÑÔÐÝ�ŠÐMÈwÑWÔWÐWØˆtØˆ5r   ÚpathÚbodyÚdictr"   r/   c                ó¤   — t          ¦   «         › | › �}t          j        |||¬¦  «        }|                     ¦   «          |                     ¦   «         S )z0POST JSON to camofox and return parsed response.r_   )r   r)   ra   rc   r-   ©rn   ro   r"   r5   r6   s        r   Ú_postrs   Ì   sN   € åÑÔÐ
& Ð
&Ð
&€CÝŒ=˜ 4°Ð9Ñ9Ô9€DØ×ÒÑÔÐØ�9Š9‰;Œ;Ðr   Úparamsc                ó¤   — t          ¦   «         › | › �}t          j        |||¬¦  «        }|                     ¦   «          |                     ¦   «         S )z,GET from camofox and return parsed response.©rt   r"   )r   r)   r*   rc   r-   ©rn   rt   r"   r5   r6   s        r   Ú_getrx   Ô   sN   € åÑÔÐ
& Ð
&Ð
&€CÝŒ<˜ F°GÐ<Ñ<Ô<€DØ×ÒÑÔÐØ�9Š9‰;Œ;Ðr   úrequests.Responsec                ó€   — t          ¦   «         › | › �}t          j        |||¬¦  «        }|                     ¦   «          |S )z;GET from camofox and return raw response (for binary data).rv   )r   r)   r*   rc   rw   s        r   Ú_get_rawr{   Ü   sE   € åÑÔÐ
& Ð
&Ð
&€CÝŒ<˜ F°GÐ<Ñ<Ô<€DØ×ÒÑÔÐØ€Kr   c                ó¤   — t          ¦   «         › | › �}t          j        |||¬¦  «        }|                     ¦   «          |                     ¦   «         S )z-DELETE to camofox and return parsed response.r_   )r   r)   Údeleterc   r-   rr   s        r   Ú_deleter~   ä   sN   € åÑÔÐ
& Ð
&Ð
&€CÝŒ?˜3 T°7Ð;Ñ;Ô;€DØ×ÒÑÔÐØ�9Š9‰;Œ;Ðr   c                ó¬  — 	 t          |¦  «        }|d         st          || ¦  «        }d| dœ}n%t          d|d         › d�|d         | dœd¬	¦  «        }d|                     d
| ¦  «        |                     dd¦  «        dœ}t	          ¦   «         }|r
||d<   d|d<   	 t          d|d         › d�d|d         i¬¦  «        }|                     dd¦  «        }ddlm}m}	 t          |¦  «        |k    r |	|¦  «        }||d<   |                     dd¦  «        |d<   n# t          $ r Y nw xY wt          j        |¦  «        S # t          j        $ r}
t          d|
› �d¬¦  «        cY d}
~
S d}
~
wt          j        $ r* t          j        ddt#          ¦   «         › d�dœ¦  «        cY S t          $ r(}
t          t%          |
¦  «        d¬¦  «        cY d}
~
S d}
~
ww xY w) zNavigate to a URL via Camofox.rN   T)Úokr5   ú/tabs/z	/navigaterL   )r]   r5   é<   r!   r5   Útitler   )Úsuccessr5   rƒ   Úvnc_urlz]Browser is visible via VNC. Share this link with the user so they can watch the browser live.Úvnc_hintú	/snapshotr]   ©rt   Úsnapshotr   )ÚSNAPSHOT_SUMMARIZE_THRESHOLDÚ_truncate_snapshotÚ	refsCountÚelement_countzNavigation failed: F©r„   NzCannot connect to Camofox at z�. Is the server running? Start with: npm start (in camofox-browser dir) or: docker run -p 9377:9377 -e CAMOFOX_PORT=9377 jo-inc/camofox-browser)r„   Úerror)rZ   re   rs   r*   r=   rx   Útools.browser_toolrŠ   r‹   Úlenr4   r-   Údumpsr)   Ú	HTTPErrorr	   ÚConnectionErrorr   r   )r5   rH   rY   r7   ÚresultÚvncÚ	snap_dataÚsnapshot_textrŠ   r‹   Úes              r   Úcamofox_navigaterš   ð   s¾  € ð71Ý˜wÑ'Ô'ˆØ�xÔ ð 
	å! '¨3Ñ/Ô/ˆGØ sÐ+Ð+ˆDˆDõ Ø5˜ Ô*Ð5Ð5Ð5Ø" 9Ô-°cÐ:Ð:Øðñ ô ˆDð Ø—8’8˜E 3Ñ'Ô'Ø—X’X˜g rÑ*Ô*ð
ð 
ˆõ
 ‰mŒmˆØð 	Ø #ˆF�9ÑðTð �:Ñð	ÝØ5˜ Ô*Ð5Ð5Ð5Ø  '¨)Ô"4Ð5ðñ ô ˆIð &ŸMšM¨*°bÑ9Ô9ˆMðð ð ð ð ð ð ð õ �=Ñ!Ô!Ð$@Ò@Ð@Ø 2Ð 2°=Ñ AÔ A�Ø!.ˆF�:ÑØ&/§m¢m°KÀÑ&CÔ&CˆF�?Ñ#Ð#øÝð 	ð 	ð 	ØˆDð	øøøõ Œz˜&Ñ!Ô!Ð!øÝÔð Dð Dð DÝÐ3°Ð3Ð3¸UÐCÑCÔCÐCÐCÐCÐCÐCÐCøøøøÝÔ#ð ð ð ÝŒzØð_µ_Ñ5FÔ5Fð _ð _ð _ð
ð 
ñ ô ð 	ð 	ð 	õ ð 1ð 1ð 1Ý�#˜a™&œ&¨%Ð0Ñ0Ô0Ð0Ð0Ð0Ð0Ð0Ð0øøøøð1øøøs[   ‚BD? ÂA=D ÄD? Ä
D(Ä%D? Ä'D(Ä(D? Ä?GÅE'Å!GÅ'9GÆ"	GÆ+GÇGÇGÚfullÚ	user_taskc                óú  — 	 t          |¦  «        }|d         st          dd¬¦  «        S t          d|d         › d�d|d         i¬	¦  «        }|                     d
d¦  «        }|                     dd¦  «        }ddlm}m}m}	 t          |¦  «        |k    r|r |||¦  «        }n |	|¦  «        }t          j
        d||dœ¦  «        S # t          $ r(}
t          t          |
¦  «        d¬¦  «        cY d}
~
S d}
~
ww xY w)z-Get accessibility tree snapshot from Camofox.rN   ú0No browser session. Call browser_navigate first.FrŽ   r�   r‡   r]   rL   rˆ   r‰   r   rŒ   r   )rŠ   Ú_extract_relevant_contentr‹   T)r„   r‰   r�   N)rZ   r	   rx   r*   r�   rŠ   rŸ   r‹   r‘   r-   r’   r4   r   )r›   rH   rœ   rY   r7   r‰   Ú
refs_countrŠ   rŸ   r‹   r™   s              r   Úcamofox_snapshotr¡   ,  su  € ð 1Ý˜wÑ'Ô'ˆØ�xÔ ð 	aÝÐPÐZ_Ð`Ñ`Ô`Ð`åØ1�W˜XÔ&Ð1Ð1Ð1Ø˜g iÔ0Ð1ð
ñ 
ô 
ˆð
 —8’8˜J¨Ñ+Ô+ˆØ—X’X˜k¨1Ñ-Ô-ˆ
ð	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
õ ˆx‰=Œ=Ð7Ò7Ð7Øð 8Ø4Ð4°X¸yÑIÔI��à-Ð-¨hÑ7Ô7�åŒzØØ Ø'ð
ð 
ñ ô ð 	øõ
 ð 1ð 1ð 1Ý�#˜a™&œ&¨%Ð0Ñ0Ô0Ð0Ð0Ð0Ð0Ð0Ð0øøøøð1øøøs#   ‚'C ªBC Ã
C:ÃC5Ã/C:Ã5C:Úrefc                ó†  — 	 t          |¦  «        }|d         st          dd¬¦  «        S |                      d¦  «        }t          d|d         › d�|d         |d	œ¦  «        }t	          j        d
||                     dd¦  «        dœ¦  «        S # t          $ r(}t          t          |¦  «        d¬¦  «        cY d}~S d}~ww xY w)z$Click an element by ref via Camofox.rN   rž   FrŽ   ú@r�   z/clickrL   )r]   r¢   Tr5   r   )r„   Úclickedr5   N)	rZ   r	   Úlstriprs   r-   r’   r*   r4   r   )r¢   rH   rY   Ú	clean_refr7   r™   s         r   Úcamofox_clickr¨   R  sú   € ð1Ý˜wÑ'Ô'ˆØ�xÔ ð 	aÝÐPÐZ_Ð`Ñ`Ô`Ð`ð —J’J˜s‘O”Oˆ	åØ.�W˜XÔ&Ð.Ð.Ð.Ø˜yÔ)°)Ð<Ð<ñ
ô 
ˆõ ŒzØØ Ø—8’8˜E 2Ñ&Ô&ð
ð 
ñ ô ð 	øõ
 ð 1ð 1ð 1Ý�#˜a™&œ&¨%Ð0Ñ0Ô0Ð0Ð0Ð0Ð0Ð0Ð0øøøøð1øøøs#   ‚'B ªA#B Â
C ÂB;Â5C Â;C Útextc                ó`  — 	 t          |¦  «        }|d         st          dd¬¦  «        S |                      d¦  «        }t          d|d         › d�|d         ||d	œ¦  «         t	          j        d
||dœ¦  «        S # t          $ r(}t          t          |¦  «        d¬¦  «        cY d}~S d}~ww xY w)z-Type text into an element by ref via Camofox.rN   rž   FrŽ   r¤   r�   z/typerL   )r]   r¢   r©   T)r„   ÚtypedÚelementN)rZ   r	   r¦   rs   r-   r’   r4   r   )r¢   r©   rH   rY   r§   r™   s         r   Úcamofox_typer­   i  sï   € ð1Ý˜wÑ'Ô'ˆØ�xÔ ð 	aÝÐPÐZ_Ð`Ñ`Ô`Ð`à—J’J˜s‘O”Oˆ	åØ-�W˜XÔ&Ð-Ð-Ð-Ø˜yÔ)°)ÀTÐJÐJñ	
ô 	
ð 	
õ ŒzØØØ ð
ð 
ñ ô ð 	øõ
 ð 1ð 1ð 1Ý�#˜a™&œ&¨%Ð0Ñ0Ô0Ð0Ð0Ð0Ð0Ð0Ð0øøøøð1øøøs#   ‚'A; ªAA; Á;
B-ÂB(Â"B-Â(B-Ú	directionc                ó2  — 	 t          |¦  «        }|d         st          dd¬¦  «        S t          d|d         › d�|d         | dœ¦  «         t          j        d	| d
œ¦  «        S # t
          $ r(}t          t          |¦  «        d¬¦  «        cY d}~S d}~ww xY w)zScroll the page via Camofox.rN   rž   FrŽ   r�   z/scrollrL   )r]   r®   T)r„   ÚscrolledN©rZ   r	   rs   r-   r’   r4   r   )r®   rH   rY   r™   s       r   Úcamofox_scrollr²     sÍ   € ð1Ý˜wÑ'Ô'ˆØ�xÔ ð 	aÝÐPÐZ_Ð`Ñ`Ô`Ð`åØ/�W˜XÔ&Ð/Ð/Ð/Ø˜yÔ)¸	ÐBÐBñ	
ô 	
ð 	
õ Œz d¸	ÐBÐBÑCÔCÐCøÝð 1ð 1ð 1Ý�#˜a™&œ&¨%Ð0Ñ0Ô0Ð0Ð0Ð0Ð0Ð0Ð0øøøøð1øøøó"   ‚'A$ ª9A$ Á$
BÁ.BÂBÂBc                óX  — 	 t          | ¦  «        }|d         st          dd¬¦  «        S t          d|d         › d�d|d         i¦  «        }t          j        d	|                     d
d¦  «        dœ¦  «        S # t          $ r(}t          t          |¦  «        d¬¦  «        cY d}~S d}~ww xY w)zNavigate back via Camofox.rN   rž   FrŽ   r�   z/backr]   rL   Tr5   r   )r„   r5   N)rZ   r	   rs   r-   r’   r*   r4   r   )rH   rY   r7   r™   s       r   Úcamofox_backrµ   �  sÕ   € ð1Ý˜wÑ'Ô'ˆØ�xÔ ð 	aÝÐPÐZ_Ð`Ñ`Ô`Ð`åØ-�W˜XÔ&Ð-Ð-Ð-Ø�w˜yÔ)Ð*ñ
ô 
ˆõ Œz d°4·8²8¸EÀ2Ñ3FÔ3FÐGÐGÑHÔHÐHøÝð 1ð 1ð 1Ý�#˜a™&œ&¨%Ð0Ñ0Ô0Ð0Ð0Ð0Ð0Ð0Ð0øøøøð1øøøs#   ‚'A7 ªAA7 Á7
B)ÂB$ÂB)Â$B)Úkeyc                ó2  — 	 t          |¦  «        }|d         st          dd¬¦  «        S t          d|d         › d�|d         | dœ¦  «         t          j        d	| d
œ¦  «        S # t
          $ r(}t          t          |¦  «        d¬¦  «        cY d}~S d}~ww xY w)z!Press a keyboard key via Camofox.rN   rž   FrŽ   r�   z/pressrL   )r]   r¶   T)r„   ÚpressedNr±   )r¶   rH   rY   r™   s       r   Úcamofox_pressr¹   Ÿ  sÍ   € ð1Ý˜wÑ'Ô'ˆØ�xÔ ð 	aÝÐPÐZ_Ð`Ñ`Ô`Ð`åØ.�W˜XÔ&Ð.Ð.Ð.Ø˜yÔ)°#Ð6Ð6ñ	
ô 	
ð 	
õ Œz d°sÐ;Ð;Ñ<Ô<Ð<øÝð 1ð 1ð 1Ý�#˜a™&œ&¨%Ð0Ñ0Ô0Ð0Ð0Ð0Ð0Ð0Ð0øøøøð1øøør³   c                ó*  — 	 t          | ¦  «        }|st          j        dddœ¦  «        S t          d|d         › �¦  «         t          j        dddœ¦  «        S # t          $ r/}t          j        ddt          |¦  «        dœ¦  «        cY d}~S d}~ww xY w)z&Close the browser session via Camofox.T)r„   Úclosedz
/sessions/rL   )r„   r»   rC   N)rj   r-   r’   r~   r4   r   )rH   rY   r™   s      r   Úcamofox_closer¼   ¯  sÄ   € ð
PÝ Ñ(Ô(ˆØð 	AÝ”:¨$¸$Ð?Ð?Ñ@Ô@Ð@åØ-˜ Ô+Ð-Ð-ñ	
ô 	
ð 	
õ Œz d°dÐ;Ð;Ñ<Ô<Ð<øÝð Pð Pð PÝŒz d°dÅsÈ1ÁvÄvÐNÐNÑOÔOÐOÐOÐOÐOÐOÐOøøøøðPøøøs"   ‚'A ª.A Á
BÁ#$BÂBÂBc                ó‚  — 	 t          | ¦  «        }|d         st          dd¬¦  «        S ddl}t          d|d         › d�d	|d
         i¬¦  «        }|                     dd¦  «        }g }|                     d¦  «        }t          |¦  «        D ]Ù\  }}|                     ¦   «         }	|	                     d¦  «        r«| 	                    d|	¦  «        }
|
r|
 
                    d¦  «        nd}d}|dz   t          |¦  «        k     rH| 	                    d||dz                                 ¦   «         ¦  «        }|r| 
                    d¦  «        }|s|r|                     ||dœ¦  «         ŒÚt          j        d|t          |¦  «        dœ¦  «        S # t          $ r(}t          t!          |¦  «        d¬¦  «        cY d}~S d}~ww xY w)z¶Get images on the current page via Camofox.

    Extracts image information from the accessibility tree snapshot,
    since Camofox does not expose a dedicated /images endpoint.
    rN   rž   FrŽ   r   Nr�   r‡   r]   rL   rˆ   r‰   r   Ú
)z- img zimg zimg\s+"([^"]*)"r%   z/url:\s*(\S+))ÚsrcÚaltT)r„   ÚimagesÚcount)rZ   r	   Úrerx   r*   ÚsplitÚ	enumerater   Ú
startswithÚsearchÚgroupr‘   Úappendr-   r’   r4   r   )rH   rY   rÃ   r7   r‰   rÁ   ÚlinesÚiÚlineÚstrippedÚ	alt_matchrÀ   r¿   Ú	url_matchr™   s                  r   Úcamofox_get_imagesrÐ   ¾  s
  € ð&1Ý˜wÑ'Ô'ˆØ�xÔ ð 	aÝÐPÐZ_Ð`Ñ`Ô`Ð`àˆ	ˆ	ˆ	åØ1�W˜XÔ&Ð1Ð1Ð1Ø˜g iÔ0Ð1ð
ñ 
ô 
ˆð —8’8˜J¨Ñ+Ô+ˆð
 ˆØ—’˜tÑ$Ô$ˆÝ  Ñ'Ô'ð 	<ð 	<‰GˆAˆtØ—z’z‘|”|ˆHØ×"Ò"Ð#5Ñ6Ô6ð 
<ØŸIšIÐ&8¸(ÑCÔC�	Ø,5Ð=�i—o’o aÑ(Ô(Ð(¸2�à�Ø�q‘5�3˜u™:œ:Ò%Ð%Ø "§	¢	Ð*:¸EÀ!ÀaÁ%¼L×<NÒ<NÑ<PÔ<PÑ QÔ Q�IØ ð 1Ø'Ÿošo¨aÑ0Ô0˜Øð <˜#ð <Ø—M’M¨#°cÐ":Ð":Ñ;Ô;Ð;øåŒzØØÝ˜‘[”[ð
ð 
ñ ô ð 	øõ
 ð 1ð 1ð 1Ý�#˜a™&œ&¨%Ð0Ñ0Ô0Ð0Ð0Ð0Ð0Ð0Ð0øøøøð1øøøs#   ‚'F ªE!F Æ
F>ÆF9Æ3F>Æ9F>ÚquestionÚannotatec                ó®  — 	 t          |¦  «        }|d         st          dd¬¦  «        S t          d|d         › d�d|d         i¬	¦  «        }d
dlm}  |¦   «         dz  }|                     dd¬¦  «         t          |dt          j        ¦   «         j	        dd…         › d�z  ¦  «        }t          |d¦  «        5 }|                     |j        ¦  «         ddd¦  «         n# 1 swxY w Y   t          j        |j        ¦  «                             d¦  «        }	d}
|rV	 t!          d|d         › d�d|d         i¬	¦  «        }d|                     dd¦  «        dd…         › �}
n# t$          $ r Y nw xY wd
dlm}  ||
¦  «        }
d
dlm} d| › |
› �}	 t/          ¦   «         }|                     di ¦  «                             di ¦  «        }t1          |                     dd ¦  «        ¦  «        }t1          |                     d!d"¦  «        ¦  «        }n# t$          $ r d#}d"}Y nw xY w |d$d%|d&œd'd(d)|	› �id*œgd+œgd||¬,¦  «        }|j        r+|j        d
         j        j        pd                     ¦   «         nd}d
dlm}  ||¦  «        }t9          j        d||d-œ¦  «        S # t$          $ r(}t          t          |¦  «        d¬¦  «        cY d}~S d}~ww xY w).z<Take a screenshot and analyze it with vision AI via Camofox.rN   rž   FrŽ   r�   z/screenshotr]   rL   rˆ   r   )Úget_hermes_homeÚbrowser_screenshotsT)ÚparentsÚexist_okÚbrowser_screenshot_Né   z.pngÚwbzutf-8r   r‡   z5

Accessibility tree (element refs for interaction):
r‰   i¸  )Úredact_sensitive_text)Úcall_llmz,Analyze this browser screenshot and answer: Ú	auxiliaryÚvisionr"   éx   Útemperaturegš™™™™™¹?g      ^@Úuserr©   )Útyper©   Ú	image_urlr5   zdata:image/png;base64,)râ   rã   )ÚroleÚcontent)ÚmessagesÚtaskrà   r"   )r„   ÚanalysisÚscreenshot_path)rZ   r	   r{   Úhermes_constantsrÔ   Úmkdirr   rU   rV   rW   ÚopenÚwriterå   Úbase64Ú	b64encodeÚdecoderx   r*   r4   Úagent.redactrÛ   Úagent.auxiliary_clientrÜ   r   ÚfloatÚchoicesÚmessager   r-   r’   )rÑ   rÒ   rH   rY   r6   rÔ   Úscreenshots_dirré   ÚfÚimg_b64Úannotation_contextr—   rÛ   rÜ   Úvision_promptÚ_cfgÚ_vision_cfgÚ_vision_timeoutÚ_vision_temperatureÚresponserè   r™   s                         r   Úcamofox_visionr   í  sI  € ðW1Ý˜wÑ'Ô'ˆØ�xÔ ð 	aÝÐPÐZ_Ð`Ñ`Ô`Ð`õ Ø3�W˜XÔ&Ð3Ð3Ð3Ø˜g iÔ0Ð1ð
ñ 
ô 
ˆð 	5Ð4Ð4Ð4Ð4Ð4Ø)˜/Ñ+Ô+Ð.CÑCˆØ×Ò d°TÐÑ:Ô:Ð:Ý˜oÐ0`ÅdÄjÁlÄlÔFVÐWYÐXYÐWYÔFZÐ0`Ð0`Ð0`Ñ`ÑaÔaˆå�/ 4Ñ(Ô(ð 	"¨AØ�GŠG�D”LÑ!Ô!Ð!ð	"ð 	"ð 	"ñ 	"ô 	"ð 	"ð 	"ð 	"ð 	"ð 	"ð 	"øøøð 	"ð 	"ð 	"ð 	"õ Ô" 4¤<Ñ0Ô0×7Ò7¸Ñ@Ô@ˆð  ÐØð 	ðÝ Ø9˜W XÔ.Ð9Ð9Ð9Ø$ g¨iÔ&8Ð9ðñ ô �	ð &GÐ`i×`mÒ`mÐnxÐz|Ñ`}Ô`}ð  Dð  @Dð  Dô  aEð  &Gð  &GÐ"Ð"øÝð ð ð Ø�ðøøøð 	7Ð6Ð6Ð6Ð6Ð6Ø2Ð2Ð3EÑFÔFÐð 	4Ð3Ð3Ð3Ð3Ð3ð$¸8ð $Ø!ð$ð $ð 	ð
	&Ý‘=”=ˆDØŸ(š( ;°Ñ3Ô3×7Ò7¸À"ÑEÔEˆKÝ# K§O¢O°I¸sÑ$CÔ$CÑDÔDˆOÝ"'¨¯ª¸ÀsÑ(KÔ(KÑ"LÔ"LÐÐøÝð 	&ð 	&ð 	&Ø#ˆOØ"%ÐÐÐð	&øøøð �8àà#¨]Ð;Ð;à +à!Ð#E¸GÐ#EÐ#Eð&ðð ððð ð ð Ø+Ø#ð
ñ 
ô 
ˆð" KSÔJZÐb�HÔ$ QÔ'Ô/Ô7Ð=¸2×DÒDÑFÔFÐFÐ`bˆð 	7Ð6Ð6Ð6Ð6Ð6Ø(Ð(¨Ñ2Ô2ˆåŒzØØ Ø.ð
ð 
ñ ô ð 	øõ
 ð 1ð 1ð 1Ý�#˜a™&œ&¨%Ð0Ñ0Ô0Ð0Ð0Ð0Ð0Ð0Ð0øøøøð1øøøs’   ‚'J" ªBJ" Â;C"ÃJ" Ã"C&Ã&J" Ã)C&Ã*3J" ÄAE# Å"J" Å#
E0Å-J" Å/E0Å0!J" ÆA>H ÈJ" ÈH"ÈJ" È!H"È"A?J" Ê"
KÊ,KË	KËKÚclearc           	     ó8   — t          j        dg g ddddœ¦  «        S )u¤   Get console output â€” limited support in Camofox.

    Camofox does not expose browser console logs via its REST API.
    Returns an empty result with a note.
    Tr   z|Console log capture is not available with the Camofox backend. Use browser_snapshot or browser_vision to inspect page state.)r„   Úconsole_messagesÚ	js_errorsÚtotal_messagesÚtotal_errorsÚnote)r-   r’   )r  rH   s     r   Úcamofox_consoler  J  s7   € õ Œ:ØØØØØðPðð ñ ô ð r   )r   r   )r   r   )r   r   )rH   r   r   rI   )r[   )rH   r   r5   r   r   rI   )rH   r   r   rf   )N)rH   r   r   r   )rn   r   ro   rp   r"   r/   r   rp   )rn   r   rt   rp   r"   r/   r   rp   )rn   r   rt   rp   r"   r/   r   ry   )r5   r   rH   r   r   r   )FNN)r›   r   rH   r   rœ   r   r   r   )r¢   r   rH   r   r   r   )r¢   r   r©   r   rH   r   r   r   )r®   r   rH   r   r   r   )rH   r   r   r   )r¶   r   rH   r   r   r   )FN)rÑ   r   rÒ   r   rH   r   r   r   )r  r   rH   r   r   r   )7Ú__doc__Ú
__future__r   rî   r-   Úloggingr   Ú	threadingrU   Útypingr   r   r   r)   Úhermes_cli.configr   Útools.browser_camofox_stater   Útools.registryr	   Ú	getLoggerÚ__name__rB   rb   Ú_SNAPSHOT_MAX_CHARSr   Ú__annotations__r,   r   r   r;   r=   rF   rG   ÚLockrT   rZ   re   rj   rm   rs   rx   r{   r~   rš   r¡   r¨   r­   r²   rµ   r¹   r¼   rÐ   r   r  r   r   r   ú<module>r     s”  ððð ð ð, #Ð "Ð "Ð "Ð "Ð "à €€€Ø €€€Ø €€€Ø 	€	€	€	Ø Ð Ð Ð Ø €€€Ø &Ð &Ð &Ð &Ð &Ð &Ð &Ð &Ð &Ð &à €€€à )Ð )Ð )Ð )Ð )Ð )Ø <Ð <Ð <Ð <Ð <Ð <Ø %Ð %Ð %Ð %Ð %Ð %à	ˆÔ	˜8Ñ	$Ô	$€ð Ð ØÐ Ø€Ð Ð Ð Ñ ØÐ ð4ð 4ð 4ð 4ð

#ð 
#ð 
#ð 
#ðð ð ð ð2ð ð ð ð8ð 8ð 8ð 8ð* (*€	Ð )Ð )Ð )Ñ )Ø�”Ñ!Ô!€ðð ð ð ð<ð ð ð ð ð*,ð ,ð ,ð ,ðð ð ð ð ð( 1Að ð ð ð ð ð $(Ð8Hð ð ð ð ð ð (,Ð<Lð ð ð ð ð ð %)Ð9Ið ð ð ð ð ð91ð 91ð 91ð 91ð 91ðx CGØ04ð#1ð #1ð #1ð #1ð #1ðL1ð 1ð 1ð 1ð 1ð.1ð 1ð 1ð 1ð 1ð,1ð 1ð 1ð 1ð 1ð 1ð 1ð 1ð 1ð 1ð 1ð 1ð 1ð 1ð 1ð Pð Pð Pð Pð Pð,1ð ,1ð ,1ð ,1ð ,1ð^ 49Ø,0ðZ1ð Z1ð Z1ð Z1ð Z1ðzð ð ð ð ð ð r   