
    j:q                    F   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mZmZmZ ddlZddlmZ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 dPdZ!dQdZ"dQdZ#dRdZ$dSdZ%dQdZ&dTdZ'dUdZ(dVdZ)dVd Z*dWd!Z+dXd#Z,dYd&Z-i Z.d'ed(<    ej/                    Z0dZd*Z1d[d+Z2d\d]d-Z3d^d/Z4d_d`d0Z5efdad6Z6defdbd8Z7defdcd:Z8defdad;Z9d_ddd<Z:	 	 dedfd?Z;d_dgdAZ<d_dhdCZ=d_didEZ>d_djdFZ?d_dkdHZ@d_djdIZAd_djdJZB	 	 dldmdMZCdldndOZDdS )ou   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``.
For Docker Camofox, optionally set ``CAMOFOX_REWRITE_LOOPBACK_URLS=true``
so page URLs like ``http://127.0.0.1:3000`` are opened inside the
container as ``http://host.docker.internal:3000``.
    )annotationsN)AnyDictOptional)SplitResulturlsplit
urlunsplit)cfg_getload_config)get_camofox_identity)
tool_error   i8 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     :/home/ubuntu/.hermes/hermes-agent/tools/browser_camofox.pyget_camofox_urlr   7   s"    9]B''..s333r   boolc                     t          j        dd                                          rdS t          t	                                S )ay  True when Camofox backend is configured and no CDP override is active.

    When the user has explicitly connected to a live Chromium-family browser 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"   <   s>     
y"B''--// u!!"""r   c                    t                      } | sdS 	 t          j        |  dd          }|j        dk    rt          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?   I   sA    

C u|sOOOQ777s""+;"	yy{{88I..h,, ;h1G1G1G1G%1G1G1G1G1G555555%Xc]]F!?9kD:::::H)   #3&&   uu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.)r0   r?   r   r   r   r   get_vnc_urlrA   b   s     "!!!Or   Dict[str, Any]c                    	 t                                          di                               di           } n4# t          $ r'}t                              d|           i cY d}~S d}~ww xY wt          | t                    r| ni S )z>Return the ``browser.camofox`` config block, or an empty dict.browsercamofoxz7camofox config check failed, defaulting to disabled: %sN)r   r.   r8   loggerwarningr2   dict)camofox_cfgexcs     r   _get_camofox_configrK   i   s    !mm''	266::9bII   PRUVVV						 %[$77?;;R?s   69 
A*A%A*%A*c                 ^    t          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.
    managed_persistence)r   rK   r.   r   r   r   _managed_persistence_enabledrN   s   s(     #%%))*?@@AAAr   task_idrI   Optional[Dict[str, str]]c                   t          j        dd                                          p5t          |                    d          pd                                          }|sdS t          j        dd                                          pDt          |                    d          pd                                          pd| pddd	          }||d
S )zReturn an externally configured Camofox identity, if one is set.

    Integrations that own the visible Camofox browser can set a shared user ID
    so Hermes operates in the same browser profile instead of creating a
    separate private session.
    CAMOFOX_USER_IDr   user_idNCAMOFOX_SESSION_KEYsession_keytask_default   )rS   rU   r   r   r!   r   r.   )rO   rI   rS   rU   s       r   _camofox_identity_overriderZ      s     i)2..4466g#kooi>X>X>^\^:_:_:e:e:g:gG t 		',,2244 	1{}--344::<<	10G(y#2#.00 
 {;;;r   nameOptional[bool]c                    t          j        | d                                                                          }|sd S |dv rdS |dv rdS t                              d| |           d S )Nr   >   1onyestrueT>   0noofffalseFz"Ignoring invalid boolean env %s=%r)r   r   r!   lowerrF   debug)r[   raws     r   	_env_flagri      sv    
)D"


#
#
%
%
+
+
-
-C t
(((t
)))u
LL5tSAAA4r   c                l    t          d          }||S t          |                     d                    S )z@Return whether Hermes should recover an existing Camofox tab ID.CAMOFOX_ADOPT_EXISTING_TABNadopt_existing_tabri   r   r.   rI   	env_values     r   _adopt_existing_tab_enabledrp      s7    677I 455666r   c                l    t          d          }||S t          |                     d                    S )aL  Return whether loopback navigation URLs should be rewritten for Docker.

    ``CAMOFOX_URL`` itself often points at a host-published Docker port such as
    ``http://127.0.0.1:9377``.  That is correct for Hermes talking to the
    Camofox control API, but a page URL like ``http://127.0.0.1:3000`` is opened
    by the browser *inside* the Docker container.  In that context loopback
    points at the container, not the host running the web app.

    The rewrite is opt-in because non-Docker Camofox installs run the browser on
    the host, where loopback URLs are already correct.
    CAMOFOX_REWRITE_LOOPBACK_URLSNrewrite_loopback_urlsrm   rn   s     r   _loopback_rewrite_enabledrt      s9     9::I 788999r   c                    t          j        dd                                          p7t          |                     d          pd                                          pdS )z=Return the host alias used when rewriting loopback page URLs.CAMOFOX_LOOPBACK_HOST_ALIASr   loopback_host_aliaszhost.docker.internalrY   )rI   s    r   _loopback_rewrite_hostrx      s[     		/44::<< 	"{455;<<BBDD	"!r   r5   c                    | sdS |                                                       d                                          }|dv rdS 	 ddl}|                    |          j        S # t
          $ r Y dS w xY w)z:Return True for localhost/127.0.0.0/8/::1-style hostnames.Fz[]>   localhost.localdomainr+   Tr   N)r!   rf   	ipaddress
ip_addressis_loopbackr6   )r5   r>   r{   s      r   _is_loopback_hostnamer~      s     u>>!!$''--//D555t##D))55   uus   A# #
A10A1r9   $tuple[str, Optional[Dict[str, str]]]c           	     H   t                      }t          |          s| dfS 	 t          |           }n# t          $ r | dfcY S w xY w|j        dvst          |j                  s| dfS t          |          }|s| dfS d}|j        r |j        }|j	        r|d|j	         z  }|dz  }d|v r|
                    d          sd| dn|}|j        r
d|j         nd}t          t          |j        | | | |j        |j        |j                            }||j        pd|| |dfS )	zRewrite loopback page URLs for Docker-hosted Camofox, if configured.

    Returns ``(rewritten_url, metadata)``.  ``metadata`` is present only when a
    rewrite happened so the tool result can disclose the change to the model.
    N>   httphttpsr   r,   @[])fromtooriginal_urlrewritten_url)rK   rt   r   r6   schemer~   r5   rx   usernamepassword
startswithportr	   r   pathqueryfragment)r9   rI   r=   aliasuserinfo	host_part	port_part	rewrittens           r   !_rewrite_loopback_url_for_camofoxr      s    &''K$[11 Dy#   Dy }---5J6?5[5[-Dy";//E DyH ?? 	.-FO---HC #uU5E5Ec5J5JEPUI%+[8!FK!!!bIFMh#F	#F9#F#FU[Uacicrss I %2"	   s   3 AAzDict[str, Dict[str, Any]]	_sessionssessionc                
   |                      d          s|                      d          s| S t                      s| S 	 t          dd| d         id                               dg           }nH# t          $ r;}t                              d	|                      d          |           | cY d
}~S d
}~ww xY wt          |t                    r|s| S |                      d          fd|D             }|pd |D             }|r|d         nd
}t          |t                    r|                     d          nd
}t          |t                    r6|r4|| d<   t                              d||                      d                     | S )a0  Attach process-local state to an already-open managed Camofox tab.

    Some integrations own the visible Camofox tab outside Hermes. Gateway
    restarts can leave this module's in-memory session cache empty even though
    Camofox still has that tab, so rehydrate tab_id before creating a new tab.
    tab_idrl   /tabsuserIdrS   r$   paramsr&   tabsz&Camofox tab adoption failed for %s: %sNrU   c                p    g | ]2}t          |t                    r|                    d           k    0|3S )
listItemId)r2   rH   r.   ).0tabrU   s     r   
<listcomp>z'_adopt_existing_tab.<locals>.<listcomp>  sN       c4   &)WW\%:%:k%I%I 	%I%I%Ir   c                <    g | ]}t          |t                    |S r   )r2   rH   )r   r   s     r   r   z'_adopt_existing_tab.<locals>.<listcomp>  s'    "P"P"P3*S$:O:O"P3"P"P"Pr   tabIdz&Adopted existing Camofox tab %s for %s)
r.   r   _getr8   rF   rg   r2   listrH   r   )r   r   rJ   matching_tabs
candidateslatestr   rU   s          @r   _adopt_existing_tabr     s    {{8 GKK0D$E$E  GXwy/A$BANNNRRSY[]^^   =w{{9?U?UWZ[[[ dD!!  ++m,,K     M
 P"P"P$"P"P"PJ)3Z^^tF$.vt$<$<FVZZ   $F&# _6 _"=vw{{S\G]G]^^^Ns   .A. .
B380B.(B3.B3c                n   | pd} t           5  | t          v r&t          t          |                    cddd           S t                      }t	          | |          }|r"|d         d|d         dt          |          d}nt          |                    d                    r1t          |           }|d         d|d         dt          |          d}n4dt          j
                    j        dd	          dd
| dd          ddd}|t          | <   t          |          cddd           S # 1 swxY w Y   dS )zGet 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.
    rW   NrS   rU   T)rS   r   rU   managedrl   rM   hermes_
   rV   rX   F)_sessions_lockr   r   rK   rZ   rp   r   r.   r   uuiduuid4hex)rO   rI   identity_overrider   identitys        r   _get_sessionr   '  s    "G	  ,  ,i&y'9:: ,  ,  ,  ,  ,  ,  ,  , *++6wLL 	,Y70?&A+&N&N GG +//"78899 	+G44H#I.'6&A+&N&N GG =TZ\\%5crc%:<<5wss|55 &+ G %	'"7++A ,  ,  ,  ,  ,  ,  ,  ,  ,  ,  ,  ,  ,  ,  ,  ,  ,  ,s   #D*C!D**D.1D.about:blankc                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.r   r   rS   rU   )r   
sessionKeyr9   r1   r&   r   )r   r   r-   post_DEFAULT_TIMEOUTraise_for_statusr1   r.   )rO   r9   r   baser:   r;   s         r   _ensure_tabr   R  s    7##Gx D=i(!-0
 

 !  D 	99;;D))GH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.rW   N)r   r   pop)rO   s    r   _drop_sessionr   g  s    "G	 , ,}}Wd++, , , , , , , , , , , , , , , , , ,s   488c                    t                      }t          |                    d                    s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`.
    rM   z6Camofox soft cleanup for task %s (managed persistence)TF)rK   r   r.   rZ   r   rF   rg   )rO   rI   s     r   camofox_soft_cleanupr   n  sm     &''KKOO12233 7QRY[f7g7g gMwWWWt5r   r   bodyrH   r&   r3   c                    t                       |  }t          j        |||          }|                                 |                                S )z0POST JSON to camofox and return parsed response.r   )r   r-   r   r   r1   r   r   r&   r9   r:   s        r   _postr     sN    
&
&
&C=4999D99;;r   r   c                    t                       |  }t          j        |||          }|                                 |                                S )z,GET from camofox and return parsed response.r   )r   r-   r.   r   r1   r   r   r&   r9   r:   s        r   r   r     sN    
&
&
&C<FG<<<D99;;r   requests.Responsec                    t                       |  }t          j        |||          }|                                 |S )z;GET from camofox and return raw response (for binary data).r   )r   r-   r.   r   r   s        r   _get_rawr     sE    
&
&
&C<FG<<<DKr   c                    t                       |  }t          j        |||          }|                                 |                                S )z-DELETE to camofox and return parsed response.r   )r   r-   deleter   r1   r   s        r   _deleter     sN    
&
&
&C?3T7;;;D99;;r   c                   	 t          |           \  }}t          |          }|d         st          ||          }d|d}n%t          d|d          d|d         |dd	          }d|                    d
|          |                    dd          d}|r!| |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.r   T)okr9   /tabs/z	/navigaterS   )r   r9   <   r%   r9   titler   )successr9   r   requested_urlurl_rewritez0Rewrote loopback URL for Docker-hosted Camofox: r   z -> r   rG   vnc_urlz]Browser is visible via VNC. Share this link with the user so they can watch the browser live.vnc_hint	/snapshotr   r   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)r   r   r   r   r.   rA   r   tools.browser_toolr   r   lenr8   r1   dumpsr-   	HTTPErrorr   ConnectionErrorr   r   )r9   rO   browser_urlrewrite_infor   r;   resultvnc	snap_datasnapshot_textr   r   es                r   camofox_navigater     s&   ?1$Ec$J$J!\w''x  
	!';77G{33DD 5*555"9-kBB  D 88E;//XXgr**
 

  	&)F?#$0F=!B'B B-9$-?B B 9 mm 	 #F9T :	5*555 ')"45  I &MM*b99M        =!!$@@@ 2 2= A A!.F:&/mmK&C&CF?## 	 	 	D	 z&!!! D D D333UCCCCCCCCC#   z__5F5F _ _ _
 
   	 	 	  1 1 1#a&&%0000000001s[   CE4 A=E E4 
EE4 EE4 4HFH9H	H H=HH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.r   0No browser session. Call browser_navigate first.Fr   r   r   r   rS   r   r   r   r   r   )r   _extract_relevant_contentr   T)r   r   r   N)r   r   r   r.   r   r   r   r   r   r1   r   r8   r   )r   rO   r   r   r;   r   
refs_countr   r   r   r   s              r   camofox_snapshotr     su    1w''x  	aPZ_````1WX&111gi01
 
 

 88J++XXk1--
	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 x==777 844XyII--h77z '
 
   	
  1 1 1#a&&%0000000001s#   '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.r   r   Fr   r   r   z/clickrS   )r   r   Tr9   r   )r   clickedr9   N)	r   r   lstripr   r1   r   r.   r8   r   )r   rO   r   	clean_refr;   r   s         r   camofox_clickr    s    1w''x  	aPZ_```` JJsOO	.WX&...y))<<
 
 z 88E2&&
 
   	
  1 1 1#a&&%0000000001s#   '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.r   r   Fr   r   r   z/typerS   )r   r   r  T)r   typedelementN)r   r   r   r   r1   r   r8   r   )r   r  rO   r   r   r   s         r   camofox_typer  (  s    1w''x  	aPZ_````JJsOO	-WX&---y))TJJ	
 	
 	
 z 
 
   	
  1 1 1#a&&%0000000001s#   '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.r   r   Fr   r   z/scrollrS   )r   r  T)r   scrolledNr   r   r   r1   r   r8   r   )r  rO   r   r   s       r   camofox_scrollr  >  s    1w''x  	aPZ_````/WX&///y)	BB	
 	
 	
 zd	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.r   r   Fr   r   z/backr   rS   Tr9   r   )r   r9   N)r   r   r   r1   r   r.   r8   r   )rO   r   r;   r   s       r   camofox_backr  N  s    1w''x  	aPZ_````-WX&---wy)*
 
 zd488E23F3FGGHHH 1 1 1#a&&%0000000001s#   '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.r   r   Fr   r   z/pressrS   )r   r  T)r   pressedNr
  )r  rO   r   r   s       r   camofox_pressr  ^  s    1w''x  	aPZ_````.WX&...y)#66	
 	
 	
 zds;;<<< 1 1 1#a&&%0000000001r  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/rS   )r   r  rG   N)r   r1   r   r   r8   r   )rO   r   r   s      r   camofox_closer  n  s    
P(( 	A:$$??@@@-+--	
 	
 	
 zdd;;<<< P P Pzdds1vv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)zGet images on the current page via Camofox.

    Extracts image information from the accessibility tree snapshot,
    since Camofox does not expose a dedicated /images endpoint.
    r   r   Fr   r   Nr   r   r   rS   r   r   r   
)z- img zimg zimg\s+"([^"]*)"r)   z/url:\s*(\S+))srcaltT)r   imagescount)r   r   rer   r.   split	enumerater!   r   searchgroupr   appendr1   r   r8   r   )rO   r   r  r;   r   r  linesilinestripped	alt_matchr  r  	url_matchr   s                  r   camofox_get_imagesr(  }  s
   &1w''x  	aPZ_````			1WX&111gi01
 
 
 88J++
 t$$ '' 	< 	<GAtzz||H""#566 
<II&8(CC	,5=iooa(((2q53u::%% "		*:E!a%L<N<N<P<P Q QI  1'ooa00 <# <MM#c":":;;;z[[
 
   	
  1 1 1#a&&%0000000001s#   '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/                      }t1          |ddi           }t3          |                    d d!                    }t3          |                    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}  ||          }t;          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.r   r   Fr   r   z/screenshotr   rS   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vision)rW   r&   x   temperatureg?g      ^@userr  )typer  	image_urlr9   zdata:image/png;base64,)r:  r;  )rolecontent)messagestaskr8  r&   )r   analysisscreenshot_path)r   r   r   hermes_constantsr,  mkdirr   r   r   r   openwriter=  base64	b64encodedecoder   r.   r8   agent.redactr3  agent.auxiliary_clientr4  r   r
   floatchoicesmessager!   r1   r   )r)  r*  rO   r   r:   r,  screenshots_dirrA  fimg_b64annotation_contextr   r3  r4  vision_prompt_cfg_vision_cfg_vision_timeout_vision_temperatureresponser@  r   s                         r   camofox_visionrX    s<   W1w''x  	aPZ_```` 3WX&333gi01
 
 
 	544444)/++.CCdT:::o0`djllFVWYXYWYFZ0`0`0``aa/4(( 	"AGGDL!!!	" 	" 	" 	" 	" 	" 	" 	" 	" 	" 	" 	" 	" 	" 	" "4<0077@@   	 9WX.999$gi&89  	 &G`i`m`mnxz|`}`}  D  @D  D  aE  &G  &G""    	766666223EFF 	433333$8 $!$ $ 	
	&==D!$XrJJJK#KOOIs$C$CDDO"'s(K(K"L"L 	& 	& 	&#O"%	& 8#];; +!#EG#E#E&    +#
 
 
" KSJZbH$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1s   'J BJ ;C"J "C&&J )C&*3J AE# "J #
E0-J /E00!J A'G: 9J :HJ 
HA?J 
J=J82J=8J=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)r1   r   )rY  rO   s     r   camofox_consoler`  	  s7     :P    r   )r   r   )r   r   )r   r   )r   rB   )rO   r   rI   rB   r   rP   )r[   r   r   r\   )rI   rB   r   r   )rI   rB   r   r   )r5   r   r   r   )r9   r   r   r   )r   rB   r   rB   )rO   r   r   rB   )r   )rO   r   r9   r   r   rB   )rO   r   r   r   )N)rO   r   r   r   )r   r   r   rH   r&   r3   r   rH   )r   r   r   rH   r&   r3   r   rH   )r   r   r   rH   r&   r3   r   r   )r9   r   rO   r   r   r   )FNN)r   r   rO   r   r   r   r   r   )r   r   rO   r   r   r   )r   r   r  r   rO   r   r   r   )r  r   rO   r   r   r   )rO   r   r   r   )r  r   rO   r   r   r   )FN)r)  r   r*  r   rO   r   r   r   )rY  r   rO   r   r   r   )E__doc__
__future__r   rF  r1   loggingr   	threadingr   typingr   r   r   r4   r   r   r	   r-   hermes_cli.configr
   r   tools.browser_camofox_stater   tools.registryr   	getLogger__name__rF   r   _SNAPSHOT_MAX_CHARSr   __annotations__r0   r   r"   r?   rA   rK   rN   rZ   ri   rp   rt   rx   r~   r   r   Lockr   r   r   r   r   r   r   r   r   r   r   r   r  r  r  r  r  r  r(  rX  r`  r   r   r   <module>rn     s|    2 # " " " " "    				      & & & & & & & & & & : : : : : : : : : :  2 2 2 2 2 2 2 2 < < < < < < % % % % % %		8	$	$        4 4 4 4

# 
# 
# 
#   2   @ @ @ @	B 	B 	B 	B< < < <&	 	 	 	7 7 7 7: : : :$      & & & &Z (*	 ) ) ) )!!# # # #L(, (, (, (,V    *, , , ,    * 1A      $(8H      (,<L      %)9I     A1 A1 A1 A1 A1H CG04#1 #1 #1 #1 #1L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1z      r   