+
    i&                     l   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t^ RI	t	^ RI
t
^ RIt^ RIt^ RIt]P                  ! 4       R8H  t^ RIHtHtHtHt ]P*                  ! ]4      t]	P
                  R8g  t]! . R0O4      tRt^2tRtRtR R ltRR1RR2RR3RR4R	R5R
R6RR7/t R8R R llt!Rt"R]",           R,           t#R]",           R,           t$0 R9mt%R R lt&R R lt'R R lt(R R lt)R  R! lt*R:R" R# llt+R;R$ R% llt,R& R' lt-. R<Ot.R=R( R) llt/]/! 4       t0^ R*I1H2t2 ]2Pf                  ! R+R,]0R- ]R.R/7       R# )>a  
Code Execution Tool -- Programmatic Tool Calling (PTC)

Lets the LLM write a Python script that calls Hermes tools via RPC,
collapsing multi-step tool chains into a single inference turn.

Architecture (two transports):

  **Local backend (UDS):**
  1. Parent generates a `hermes_tools.py` stub module with UDS RPC functions
  2. Parent opens a Unix domain socket and starts an RPC listener thread
  3. Parent spawns a child process that runs the LLM's script
  4. Tool calls travel over the UDS back to the parent for dispatch

  **Remote backends (file-based RPC):**
  1. Parent generates `hermes_tools.py` with file-based RPC stubs
  2. Parent ships both files to the remote environment
  3. Script runs inside the terminal backend (Docker/SSH/Modal/Daytona/etc.)
  4. Tool calls are written as request files; a polling thread on the parent
     reads them via execute_oneshot(), dispatches, and writes response files
  5. The script polls for response files and continues

In both cases, only the script's stdout is returned to the LLM; intermediate
tool results never enter the context window.

Platform: Linux / macOS only (Unix domain sockets for local). Disabled on Windows.
Remote execution additionally requires Python 3 in the terminal backend.
NWindows)AnyDictListOptionalwin32
web_searchweb_extract	read_file
write_filesearch_filespatchterminal,  iP  i'  c                $    V ^8  d   QhR\         /#    returnbool)formats   "6/home/ubuntu/hermes-agent/tools/code_execution_tool.py__annotate__r   H   s      D     c                     \         # )zCCode execution sandbox requires a POSIX OS for Unix domain sockets.)SANDBOX_AVAILABLE r   r   check_sandbox_requirementsr   H   s    r   c                R    V ^8  d   QhR\         \        ,          R\        R\        /# )r   enabled_tools	transportr   )r   str)r   s   "r   r   r      s'      .  .S	  .,/ .<? .r   c                R   \        \        \        V 4      ,          4      p. p. pV FS  pV\        9  d   K  \        V,          w  rgrVP	                  RV RV RV RV: RV	 R24       VP	                  V4       KU  	  VR8X  d   \
        p
M\        p
V
RP                  V4      ,           # )	aK  
Build the source code for the hermes_tools.py stub module.

Only tools in both SANDBOX_ALLOWED_TOOLS and enabled_tools get stubs.

Args:
    enabled_tools: Tool names enabled in the current session.
    transport: ``"uds"`` for Unix domain socket (local backend) or
               ``"file"`` for file-based RPC (remote backends).
zdef (z):
    z
    return _call(, z)
file
)sortedSANDBOX_ALLOWED_TOOLSset_TOOL_STUBSappend_FILE_TRANSPORT_HEADER_UDS_TRANSPORT_HEADERjoin)r   r    tools_to_generatestub_functionsexport_names	tool_name	func_namesigdoc	args_exprheaders   &&         r   generate_hermes_tools_moduler8      s     4s=7IIJNL&	K')4Y)?&	9+Qse $%   )}Byk>	

 	I& ' F'&DIIn---r   a  
# ---------------------------------------------------------------------------
# Convenience helpers (avoid common scripting pitfalls)
# ---------------------------------------------------------------------------

def json_parse(text: str):
    """Parse JSON tolerant of control characters (strict=False).
    Use this instead of json.loads() when parsing output from terminal()
    or web_extract() that may contain raw tabs/newlines in strings."""
    return json.loads(text, strict=False)


def shell_quote(s: str) -> str:
    """Shell-escape a string for safe interpolation into commands.
    Use this when inserting dynamic content into terminal() commands:
        terminal(f"echo {shell_quote(user_input)}")
    """
    return shlex.quote(s)


def retry(fn, max_attempts=3, delay=2):
    """Retry a function up to max_attempts times with exponential backoff.
    Use for transient failures (network errors, API rate limits):
        result = retry(lambda: terminal("gh issue list ..."))
    """
    last_err = None
    for attempt in range(max_attempts):
        try:
            return fn()
        except Exception as e:
            last_err = e
            if attempt < max_attempts - 1:
                time.sleep(delay * (2 ** attempt))
    raise last_err

z`"""Auto-generated Hermes tools RPC stubs."""
import json, os, socket, shlex, time

_sock = None
a  
def _connect():
    global _sock
    if _sock is None:
        _sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
        _sock.connect(os.environ["HERMES_RPC_SOCKET"])
        _sock.settimeout(300)
    return _sock

def _call(tool_name, args):
    """Send a tool call to the parent process and return the parsed result."""
    conn = _connect()
    request = json.dumps({"tool": tool_name, "args": args}) + "\n"
    conn.sendall(request.encode())
    buf = b""
    while True:
        chunk = conn.recv(65536)
        if not chunk:
            raise RuntimeError("Agent process disconnected")
        buf += chunk
        if buf.endswith(b"\n"):
            break
    raw = buf.decode().strip()
    result = json.loads(raw)
    if isinstance(result, str):
        try:
            return json.loads(result)
        except (json.JSONDecodeError, TypeError):
            return result
    return result

z"""Auto-generated Hermes tools RPC stubs (file-based transport)."""
import json, os, shlex, time

_RPC_DIR = os.environ.get("HERMES_RPC_DIR", "/tmp/hermes_rpc")
_seq = 0
a  
def _call(tool_name, args):
    """Send a tool call request via file-based RPC and wait for response."""
    global _seq
    _seq += 1
    seq_str = f"{_seq:06d}"
    req_file = os.path.join(_RPC_DIR, f"req_{seq_str}")
    res_file = os.path.join(_RPC_DIR, f"res_{seq_str}")

    # Write request atomically (write to .tmp, then rename)
    tmp = req_file + ".tmp"
    with open(tmp, "w") as f:
        json.dump({"tool": tool_name, "args": args, "seq": _seq}, f)
    os.rename(tmp, req_file)

    # Wait for response with adaptive polling
    deadline = time.monotonic() + 300  # 5-minute timeout per tool call
    poll_interval = 0.05  # Start at 50ms
    while not os.path.exists(res_file):
        if time.monotonic() > deadline:
            raise RuntimeError(f"RPC timeout: no response for {tool_name} after 300s")
        time.sleep(poll_interval)
        poll_interval = min(poll_interval * 1.2, 0.25)  # Back off to 250ms

    with open(res_file) as f:
        raw = f.read()

    # Clean up response file
    try:
        os.unlink(res_file)
    except OSError:
        pass

    result = json.loads(raw)
    if isinstance(result, str):
        try:
            return json.loads(result)
        except (json.JSONDecodeError, TypeError):
            return result
    return result

c                t    V ^8  d   QhR\         P                   R\        R\        R\        R\        R\        /# )r   server_socktask_idtool_call_logtool_call_countermax_tool_callsallowed_tools)socketr!   listint	frozenset)r   s   "r   r   r   2  sP     u< u<u<u< u< 	u<
 u< u<r   c                	   ^ RI Hp Rp V P                  ^4       V P                  4       w  rxVP                  R4       Rp	  VP	                  R4      p
T
'       g   EMY,          p	RT	9   g   K.  T	P                  R^4      w  rTP                  4       pT'       g   K7  \        P                  ! 4       p \        P                  ! TP                  4       4      pTP'                  RR4      pTP'                  R/ 4      pTT9  da   RP)                  \+        T4      4      p\        P                   ! RRT RT 2/4      pTP#                  TR
,           P%                  4       4       K  T^ ,          T8  dF   \        P                   ! RRT R2/4      pTP#                  TR
,           P%                  4       4       EKO  TR8X  d6   \-        T\.        4      '       d    \0         F  pTP3                  TR4       K  	   \4        P6                  \4        P8                  pp\;        \<        P>                  R4      p T\4        n        T\4        n        T! TTTR7      pTTu\4        n        \4        n        TPA                  4        T^ ;;,          ^,          uu&   \        P                  ! 4       T,
          p\I        T4      R,          pTPK                  RTRTR\M        T^4      /4       TP#                  TR
,           P%                  4       4       EK  T'       d    TPA                  4        R# R#   \
        P                   d     K5  i ; i  \        P                  \        3 dN   p\        P                   ! RR	T 2/4      pTP#                  TR
,           P%                  4       4        Rp?EK8  Rp?ii ; i  TTu\4        n        \4        n        TPA                  4        i ; i  \B         dE   p\D        PG                  RTRR7       \        P                   ! R\I        T4      /4      p Rp?ELRp?ii ; i  \
        P                   d    \D        PO                  R4        ELO\P         d$   p\D        PO                  RTRR7        Rp?ELwRp?ii ; i  \P         d"   p\D        PO                  RT4        Rp?R# Rp?ii ; i  T'       dA    TPA                  4        i   \P         d!   p\D        PO                  RT4        Rp?i Rp?ii ; ii ; i)zy
Accept one client connection and dispatch tool-call requests until
the client disconnects or the call limit is reached.
handle_function_callNr   r   Ti      
errorzInvalid RPC request: r&   tool argsr$   Tool '/' is not available in execute_code. Available: Tool call limit reached (0). No more tool calls allowed in this execution.r   wr;   zTool call failed in sandbox: %sexc_infoNP   Nargs_previewdurationzRPC listener socket timeoutzRPC listener socket error: %szRPC conn close error: %s))model_toolsrF   
settimeoutacceptrecvr@   timeoutsplitstriptime	monotonicjsonloadsdecodeJSONDecodeErrorUnicodeDecodeErrordumpssendallencodegetr.   r'   
isinstancedict_TERMINAL_BLOCKED_PARAMSpopsysstdoutstderropenosdevnullclose	ExceptionloggerrH   r!   r+   rounddebugOSError)r:   r;   r<   r=   r>   r?   rF   conn_bufchunkline
call_startrequestexcrespr2   	tool_args	availableparam_real_stdout_real_stderrrs   resultcall_durationrV   es   &&&&&&                     r   _rpc_server_loopr   2  s    1Df<q!$$&		%( LC 3,IIeQ/	zz|!^^-
"jj7G $KK3	#KK3	 M1 $		&*? @I::$YK 0**36' D LL$+!5!5!78 %Q'>9::77G HL L' D LL$+!5!5!78 
*z)T/J/J!9!eT2 ":=14SZZ,L"2::s3G(%,
%,
!5%y'" 2>|.
CJ
 "!$)$ $ 0: =  #9~c2$$I"LmQ 7&  ftm3356 <

 s >>   ,,.@A ::w2Gu0M&NODLL$+!5!5!78b 2>|.
CJ  =LL!BCRVLW!ZZ#c((;<F=" >> 423 H4a$GGH  <7;;< <

 <7;;< s)  7P# L P# R/ P# .AP# 2$L: DP# 1:O ,!N% 'O 4BP# 
R  L73P# 4R/ 6L77P# :N"ANP# N""P# %)OO P 9PP# P  P# #*Q=R/ Q=Q=Q82R/ 8Q==R/  R,R''R,/	S99S
	S9
S5S0+S90S55S9c                $    V ^8  d   QhR\         /# )r   r;   r!   )r   s   "r   r   r     s     a a ar   c                   ^ RI HpHpHpHpHpHpHpHpH	p	 T ;'       g    Rp
T;_uu_ 4        W9   d8   \        P                  ! 4       WZ&   W,          V! 4       R,          3uuRRR4       #  RRR4       T;_uu_ 4        W9  d   \        P                  ! 4       Wz&   Wz,          pRRR4       X;_uu_ 4        T;_uu_ 4        W9   dB   \        P                  ! 4       WZ&   W,          V! 4       R,          3uuRRR4       uuRRR4       #  RRR4       V! 4       pVR,          pV	P                  V
/ 4      pVR8X  d$   VP                  R4      ;'       g
    VR,          pMVR8X  d$   VP                  R4      ;'       g
    VR,          pMVVR	8X  d$   VP                  R
4      ;'       g
    VR
,          pM,VR8X  d$   VP                  R4      ;'       g
    VR,          pMRpVP                  R4      ;'       g
    VR,          pRpVR+9   d]   RVP                  R^4      RVP                  RR4      RVP                  RR4      RVP                  RR4      RVP                  R. 4      /pRpVR8X  d]   RVP                  RR4      RVP                  RR4      RVP                  R^4      RVP                  RR4      R VP                  R!R"4      /pRpVR#8X  d   R VP                  R$R"4      /p\        P                  R%WR&,          4       V! VVVVR',          VVVV
VP                  R(4      R)7	      pV;_uu_ 4        VW&   \        P                  ! 4       WZ&   RRR4       V! 4        \        P                  R*WR&,          4       VV3uuRRR4       #   + '       g   i     EL(; i  + '       g   i     EL; i  + '       g   i     EL; i  + '       g   i     L~; i  + '       g   i     R# ; i),zGet or create the terminal environment for *task_id*.

Reuses the same environment (container/sandbox/SSH session) that the
terminal and file tools use, creating one if it doesn't exist yet.
Returns ``(env, env_type)`` tuple.
)	_active_environments	_env_lock_create_environment_get_env_config_last_activity_start_cleanup_thread_creation_locks_creation_locks_lock_task_env_overridesdefaultenv_typeNdockerdocker_imagesingularitysingularity_imagemodalmodal_imagedaytonadaytona_imagerJ   cwdcontainer_cpucontainer_memoryi   container_diski   container_persistentTdocker_volumessshhostssh_hostuserssh_userportssh_portkeyssh_key
persistentssh_persistentFlocallocal_persistentz7Creating new %s environment for execute_code task %s...N   Nr\   host_cwd)	r   imager   r\   
ssh_configcontainer_configlocal_configr;   r   z-%s environment ready for execute_code task %s)r   r   r   r   )tools.terminal_toolr   r   r   r   r   r   r   r   r   r_   	threadingLockri   rv   info)r;   r   r   r   r   r   r   r   r   r   effective_task_id	task_lockconfigr   	overridesr   r   r   r   r   envs   &                    r   _get_or_create_envr     sp       ,,9 
404		N-':O<Mj<YY 
4 
 
	31:1AO.#6	 

 
Y 848IIK1+>@QR\@]] Y 
8 
 !"*%'++,=rB	xMM.1KKVN5KE&MM"56UU&AT:UE MM-0IIF=4IE"MM/2MMf_6MEEmmE"33fUmDDOQ!?"FJJ/A4$H &**-=u"E&

3I4(P &**-=r"B  
u

:r2

:r2

:r2vzz)R0fjj)95AJ wfjj);UCL 	M4	6!9%!-%%ZZ
+

 Y69 304		N-  	C4	6H}M 
 
 
		 YY| Y 
sy   3N>&N6O3N3	4
O
AO)O=)O')O$O6D?O5O	/ON	N0	3O>	OOOO+	c                4    V ^8  d   QhR\         R\         RR/# )r   remote_pathcontentr   Nr   )r   s   "r   r   r     s!      3   r   c                    \         P                  ! VP                  R4      4      P                  R4      pV P	                  RV RV 2R^R7       R# )u  Write *content* to *remote_path* on the remote environment.

Uses ``echo … | base64 -d`` rather than stdin piping because some
backends (Modal) don't reliably deliver stdin_data to chained
commands.  Base64 output is shell-safe ([A-Za-z0-9+/=]) so single
quotes are fine.
utf-8asciiecho '' | base64 -d > /r   r\   N)base64	b64encoderh   rc   execute_oneshot)r   r   r   encodeds   &&& r   _ship_file_to_remoter     sR     w~~g67>>wGG
	)+7  r   c                    V ^8  d   QhR\         R\         R\        R\        R\        R\        R\        P
                  /# )r   rpc_dirr;   r<   r=   r>   r?   
stop_event)r!   rA   rB   rC   r   Event)r   s   "r   r   r   "  s]     H+ H+H+ H+ 	H+
 H+ H+ H+ H+r   c                	   ^ RI Hp Rp	VP                  4       '       Eg    V P                  RV R2R^
R7      p
V
P	                  RR4      P                  4       pV'       g   VP                  V	4       Kk  \        VP                  R	4       Uu. uFi  pVP                  4       '       g   K  VP                  4       P                  R
4      '       d   KB  RVP                  4       9   g   KY  VP                  4       NKk  	  up4      pV EF  pVP                  4       '       d    EM\        P                  ! 4       pV P                  RV 2R^
R7      p \        P                  ! VP	                  RR4      4      pTP	                  RR4      pTP	                  R/ 4      pTP	                  R^ 4      pTR pT RT 2pTT9  d;   RP%                  \        T4      4      p\        P&                  ! RRT RT 2/4      pEMNT^ ,          T8  d   \        P&                  ! RRT R2/4      pEM"TR8X  d6   \)        T\*        4      '       d    \,         F  pTP/                  TR4       K  	   \0        P2                  \0        P4                  pp\7        \8        P:                  R4      p T\0        n        T\0        n        T! TTTR7      pTTu\0        n        \0        n        TP=                  4        T^ ;;,          ^,          uu&   \        P                  ! 4       T,
          pTPE                  RTR!\C        T4      R",          R#\G        T^4      /4       \H        PJ                  ! TPM                  R$4      4      PO                  R%4      pT P                  R&T R'T R(T R)T 2R^<R7       T P                  RT 2R^R7       EK  	   VP                  4       '       d   EK  VP                  V	4       EK  R# u upi   \        P                  \        3 d3    \         P#                  RT4       T P                  RT 2R^R7        EK1  i ; i  TTu\0        n        \0        n        TP=                  4        i ; i  \>         dE   p\         PA                  RTRR 7       \        P&                  ! R\C        T4      /4      p Rp?ELRp?ii ; i  \>         d:   p TP                  4       '       g   \         P#                  R*T RR 7        Rp ? ELARp ? ii ; i)+a  Poll the remote filesystem for tool call requests and dispatch them.

Runs in a background thread.  Uses ``env.execute_oneshot()`` so it can
operate concurrently with the script-execution thread that holds
``env.execute()`` (important for persistent-shell backends like SSH).
rE   g?zls -1 z/req_* 2>/dev/null || truer   r   outputrJ   r&   z.tmpz/req_zcat zMalformed RPC request in %szrm -f rI   rK   seq06dz/res_r$   rH   rL   rM   rN   rO   r   NrP   rQ   z&Tool call failed in remote sandbox: %sTrR   rV   rT   rW   r   r   r   r   z.tmp && mv z.tmp zRPC poll error: %s)(rX   rF   is_setr   ri   r^   waitr'   r]   endswithr_   r`   ra   rb   rd   
ValueErrorrv   rx   r.   rf   rj   rk   rl   rm   rn   ro   rp   rq   rr   rs   rt   ru   rH   r!   r+   rw   r   r   rh   rc   )!r   r   r;   r<   r=   r>   r?   r   rF   poll_interval	ls_resultr   f	req_filesreq_filer   read_resultr   r2   r   r   seq_strres_filer   tool_resultr   r   r   rs   r   r   encoded_resultr   s!   &&&&&&&&                         r   _rpc_poll_loopr   "  s     1M!!p	E++	!;< , I
 ]]8R0668F.#)<<#5 #5a779 	**62  qwwy( 	#5  I &$$&&!^^-
 "118*% 2 
"jj2)FGG $KK3	#KK3	kk%+ I%YeG95 M1 $		&*? @I"&**$YK 0**36. #K 'q)^;"&**77G HL L. #K !J.:i3N3N%=E%MM%6 &>F58ZZl"&rzz3"7,)0CJ)0CJ*> )9g+K 6B<2CJ
#MMO &a(A-($(NN$4z$AM!((	&Is(;"E-$;*  "(!1!1&&w/"&/  ##^,,<XJ G&ZuXJ8	 $  ##fXJ$7S!#Ls &~   ""OOM*i " * ,,j9 LL!>I''&
(;a'P	\ 6B<2CJ
#MMO$ F%M%(4 % 9&*jj'3s81D&EF:  	E$$&&11tD	Es   ?R7 !R7 4R7 O$)"O$O$'O$;$R7 !,R7 &O)4C*R7 :Q%!P9;'Q%"CR7 $R7 )AP61R7 5P66R7 9)Q""Q%%R409R/)R7 /R44R7 7S;.S66S;c                    V ^8  d   QhR\         R\        \         ,          R\        \        \         ,          ,          R\         /# r   coder;   r   r   r!   r   r   )r   s   "r   r   r     sC     o2 o2
o2c]o2 DI&o2 		o2r   c                   ^ RI Hp \        4       pVP                  R\        4      pVP                  R\
        4      pV'       d   \        V4      M	\        4       p\        \        V,          4      pV'       g   \        pT;'       g    Rp	\        V	4      w  r\        P                  ! 4       P                  R,          pRV 2p. p^ .p\        P                  ! 4       p\        P                   ! 4       pRp V
P#                  RR	^R
7      pRVP                  RR4      9  da   \$        P&                  ! RRRRV R2R^ R^ /4      VP                  4        Ve   VP)                  ^R7        V
P#                  RV 2R	^R
7       # V
P#                  RV R2R	^
R
7       \1        \3        V4      RR7      p\5        W R2V4       \5        W R2V 4       \        P6                  ! \8        W R2V	WVVV3RR7      pVP;                  4        RV R 2p\<        P>                  ! R!R4      PA                  4       pV'       d   VR"V 2,          p\,        PC                  R#WR$,          4       V
PE                  R%V R&V R'2VR7      pVP                  RR4      pVP                  R(R:4      pR)pV^|8X  d   RpM	V^8X  d   R*pVP                  4        Ve   VP)                  ^R7        V
P#                  RV 2R	^R
7       \G        \        P                  ! 4       T,
          ^4      p\Q        T4      \R        8  d|   \U        \R        R/,          4      p\R        T,
          pTRT pTT) R p \Q        T4      \Q        T4      ,
          \Q        T 4      ,
          p!TR0T!R1 R2\Q        T4      R1 R32,           T ,           p^ R4I+H,p" T"! T4      p^ R5I-H.p# T#! T4      pRTRTRT^ ,          RT/p$TR8X  d   R6T R72T$R&   M(TR*8X  d   TR8,           T$R&   MT^ 8w  d   RT$R&   R9T 2T$R&   \$        P&                  ! T$R-R.7      #   \*         d    \,        P/                  RT4        # i ; i  \*         d   p\G        \        P                  ! 4       T,
          ^4      p\,        PI                  R+TT^ ,          \K        T4      PL                  TRR,7       \$        P&                  ! RRR\O        T4      RT^ ,          RT/R-R.7      u Rp?TP                  4        Te   TP)                  ^R7        T
P#                  RT 2R	^R
7       #   \*         d    \,        P/                  RT4        # i ; iRp?ii ; i  \*         d    \,        P/                  RT4        ELi ; i  TP                  4        Te   TP)                  ^R7        T
P#                  RT 2R	^R
7       i   \*         d    \,        P/                  RT4        i i ; i; i);zRun a script on the remote terminal backend via file-based RPC.

The script and the generated hermes_tools.py module are shipped to
the remote environment, and tool calls are proxied through a polling
thread that communicates via request/response files.
_interrupt_eventr\   r>   r   :N   Nz/tmp/hermes_exec_Nz-command -v python3 >/dev/null 2>&1 && echo OKr   r   OKr   rJ   statusrH   z!Python 3 is not available in the zO terminal environment. Install Python to use execute_code with remote backends.tool_calls_madeduration_secondsr\   zrm -rf z$Failed to clean up remote sandbox %sz	mkdir -p z/rpcr%   )r    z/hermes_tools.pyz
/script.pyTtargetrK   daemonzHERMES_RPC_DIR=z/rpc PYTHONDONTWRITEBYTECODE=1HERMES_TIMEZONEz TZ=z)Executing code on %s backend (task %s)...r   zcd z && z python3 script.py
returncodesuccessinterruptedz?execute_code remote failed after %ss with %d tool calls: %s: %srR   Fensure_ascii皙?

... [OUTPUT TRUNCATED - , chars omitted out of  total] ...


strip_ansiredact_sensitive_textScript timed out after s and was killed.4   
[execution interrupted — user sent a new message]Script exited with code )/r   r   _load_configri   DEFAULT_TIMEOUTDEFAULT_MAX_TOOL_CALLSr)   rC   r(   r   uuiduuid4hexr_   r`   r   r   r   ra   rf   r.   ru   rv   rx   r8   rA   r   Threadr   startrr   getenvr^   r   executerw   rH   type__name__r!   lenMAX_STDOUT_BYTESrB   tools.ansi_stripr  agent.redactr
  )%r   r;   r   r   _cfgr\   r>   session_toolssandbox_toolsr   r   r   
sandbox_idsandbox_dirr<   r=   
exec_startr   
rpc_threadpy_check	tools_src
env_prefixtzscript_resultstdout_text	exit_coder   r   rW   
head_bytes
tail_bytesheadtailomittedr  r
  r   s%   &&&                                  r   _execute_remoter3    s<    5>Dhhy/2GXX.0FGN*7C&SUM3mCDM-,,9&'89MC!!#&J%j\2KM!J"JJ_N&&;R ' 
 x||Hb11::'7z B' ' "1"A	 	\ 	!OOAO&	N+'S"   Q 	}D)sB 	 	

 16
	 	SM1A"BINSM"<dC %%!}D)+<.z
 

 	 k] +( ) 	 YY("-335D+%J 	?4	6+d:,.@A $ 

 $''"5!%%lB7	 F#"F$ 	!OOAO&	N+'S"    T^^%
2A6H
 ;**)C/0
%
2
;J'J;<(k"SY.T:,WQK 8+&q)::  	 ,[)K 3'4K 	&+,Q/H	F 3G9<MNw	=	 QQ 	x 
a"x4YK@w::f511_  	NLL?M	N3  )J6:M'*DI,>,> 	 	

 zzgSX03	

  	 	!OOAO&	N+'S"     	NLL?M	N32  	NLL?M	N 	!OOAO&	N+'S"     	NLL?M	Ns   4AQ 'P!?D'Q &U8 '	Q U !!QQUB
UUU8 	T!!!UUUU8 !U54U58'W V87W8!WWWWc                    V ^8  d   QhR\         R\        \         ,          R\        \        \         ,          ,          R\         /# r   r   )r   s   "r   r   r   c  sC     B B
Bc]B DI&B 		Br   c                <  a9 \         '       g   \        P                  ! RR/4      # V '       d   V P                  4       '       g   \        P                  ! RR/4      # ^ RIHp V! 4       R,          pVR8w  d   \        WV4      # ^ RIHp \        4       pVP                  R\        4      pVP                  R	\        4      pV'       d   \        V4      M	\        4       p	\        \        V	,          4      p
V
'       g   \        p
\        P                   ! R
R7      p\"        P$                  R8X  d   RM\        P&                  ! 4       p\(        P*                  P-                  VR\.        P0                  ! 4       P2                   R24      p. p^ .p\4        P6                  ! 4       pRp \9        \;        V
4      4      p\=        \(        P*                  P-                  VR4      R4      ;_uu_ 4       pVP?                  V4       RRR4       \=        \(        P*                  P-                  VR4      R4      ;_uu_ 4       pVP?                  V 4       RRR4       \@        P@                  ! \@        PB                  \@        PD                  4      pVPG                  V4       VPI                  ^4       \J        PL                  ! \N        VWWV
3RR7      pVPQ                  4        RCpRDp ^ RI)H*p / p\(        PX                  P[                  4        F  w  o9pV! S94      '       d   VVS9&   K  \\        ;QJ d    V93R lV 4       F  '       g   K   RM	  RM! V93R lV 4       4      '       d   K]  \\        ;QJ d    V93R lV 4       F  '       g   K   RM	  RM! V93R lV 4       4      '       g   K  VVS9&   K  	  VVR&   RVR&   \(        P*                  P_                  \(        P*                  P_                  \(        P*                  Pa                  \b        4      4      4      pVP                  RR4      pTV'       d   \(        Pd                  V,           MR,           VR&   \(        Pf                  ! R R4      P                  4       pV'       d   VVR!&   \h        Pj                  ! \"        Pl                  R.TT\h        Pn                  \h        Pn                  \h        Pp                  \r        '       d   RM\(        Pt                  R"7      p\4        P6                  ! 4       V,           p. p\w        \x        R#,          4      p \x        V ,
          p!R$ p"^ .p#R% p$. p%. p&\J        PL                  ! V$VPz                  V%V&V V!V#3RR7      p'\J        PL                  ! V"VP|                  V\~        3RR7      p(V'PQ                  4        V(PQ                  4        R&p)VP                  4       fg   VP                  4       '       d   \        V4       R'p)MB\4        P6                  ! 4       V8  d   \        VRR(7       Rp)M\4        P                  ! R)4       Kx  V'P-                  ^R*7       V(P-                  ^R*7       R+P-                  V%4      P                  R,R-R.7      p*R+P-                  V&4      P                  R,R-R.7      p+R+P-                  V4      P                  R,R-R.7      p,V#^ ,          p-V-\x        8  dG   V+'       d?   V-\        V*4      ,
          \        V+4      ,
          p.R/V.R0 R1V-R0 R22p/V*V/,           V+,           p0M	V*V+,           p0VP                  e   VP                  MREp1\        \4        P6                  ! 4       V,
          ^4      p2VP                  4        RpVP-                  ^R*7       ^ R3IIHJp3 V3! V04      p0V3! V,4      p,^ R4IKHLp4 V4! V04      p0V4! V,4      p,R5V)R6V0R7V^ ,          R8V2/p5V)R8X  d   R9V R:2V5R&   MMV)R'8X  d   V0R;,           V5R6&   M9V1^ 8w  d3   RV5R5&   T,;'       g    R<V1 2V5R&   V,'       d   V0R=,           V,,           V5R6&   \        P                  ! V5RR>7      Ve    VP                  4        ^ RIPp7V7P                  VRR@7        \(        P                  ! V4       #   + '       g   i     EL; i  + '       g   i     ELK; i  \V         d    R p ELi ; i  \         d!   p6\        P                  R?T64        Rp6?6LRp6?6ii ; i  \         d     # i ; i  \V         Ed   p8\        \4        P6                  ! 4       T,
          ^4      p2\        P                  RAT2T^ ,          \        T84      P                  T8RRB7       \        P                  ! R5RR\        T84      R7T^ ,          R8T2/RR>7      u Rp8?8TeA    TP                  4        M.  \         d!   p6\        P                  R?T64        Rp6?6MRp6?6ii ; i^ RIPp7T7P                  TRR@7        \(        P                  ! T4       #   \         d     # i ; iRp8?8ii ; i  TeA    TP                  4        M.  \         d!   p6\        P                  R?T64        Rp6?6MRp6?6ii ; i^ RIPp7T7P                  TRR@7        \(        P                  ! T4       i   \         d     i i ; i; i)Fa  
Run a Python script in a sandboxed child process with RPC access
to a subset of Hermes tools.

Dispatches to the local (UDS) or remote (file-based RPC) path
depending on the configured terminal backend.

Args:
    code:          Python source code to execute.
    task_id:       Session task ID for tool isolation (terminal env, etc.).
    enabled_tools: Tool names enabled in the current session. The sandbox
                   gets the intersection with SANDBOX_ALLOWED_TOOLS.

Returns:
    JSON string with execution results.
rH   zHexecute_code is not available on Windows. Use normal tool calls instead.zNo code provided.)r   r   r   r   r\   r>   hermes_sandbox_)prefixdarwinz/tmphermes_rpc_z.sockNzhermes_tools.pyrP   z	script.pyTr   
PYTHONPATH)is_env_passthroughc                     R # Fr   )r{   s   &r   <lambda>execute_code.<locals>.<lambda>  s    r   c              3   H   <"   T F  qSP                  4       9   x  K  	  R # 5iN)upper).0sks   & r   	<genexpr>execute_code.<locals>.<genexpr>  s     >+=a	>+=s   "Fc              3   F   <"   T F  pSP                  V4      x  K  	  R # 5irA  )
startswith)rC  prE  s   & r   rF  rG    s     ?,>q1<<??,>s   !HERMES_RPC_SOCKET1PYTHONDONTWRITEBYTECODErJ   r   TZ)r   r   ro   rp   stdin
preexec_fnr  c                   ^ p  V P                  R4      pV'       g   R# W28  d   W#,
          pVP                  VRV 4       V\        V4      ,          pKR    \        \        3 d$   p\
        P                  RTRR7        Rp?R# Rp?ii ; i)z)Simple head-only drain (used for stderr).T   Nz Error reading process output: %srR   )readr+   r  r   ry   rv   rx   )pipechunks	max_bytestotaldatakeepr   s   &&&    r   _drainexecute_code.<locals>._drain  s~    E
S99T?D((0d5Dk2SY&E( S?TRRSs   A 6A B
'BB
c                4   ^ p^ RI Hp V! 4       p^ p	  V P                  R4      p
V
'       g   MV^ ;;,          \        V
4      ,          uu&   Wc8  dF   \	        \        V
4      W6,
          4      pVP                  V
RV 4       Wk,          pWR p
V
'       g   K  VP                  V
4       V	\        V
4      ,          p	W8  g   K  V'       g   K  VP                  4       pV	\        V4      ,          p	K6  VP                  V4       R#   \        \        3 d     L&i ; i)z-Drain stdout keeping both head and tail data.)dequerR  N)
collectionsr]  rS  r  minr+   popleftr   ry   extend)rT  head_chunkstail_chunksr.  r/  	total_refhead_collectedr]  tail_buftail_collectedrX  rY  oldests   &&&&&&       r   _drain_head_tail&execute_code.<locals>._drain_head_tail  s    N)wHN99T?DaLCI-L%2"3t9j.IJ#**4;7&.#E{#$OOD)"c$i/N(5((!)!1!1!3&#f+5 x( ( s#   D BD D $D DDr   r   )escalateg?r   r   r   replace)errorsr  r  r  r  r  r	  r   r   r   r   r  r  r  r  z
--- stderr ---
r   zServer socket close error: %s)ignore_errorsz8execute_code failed after %ss with %d tool calls: %s: %srR   )PATHHOMEUSERLANGLC_TERMTMPDIRTMPTEMPSHELLLOGNAMEXDG_r:  VIRTUAL_ENVCONDA)KEYTOKENSECRETPASSWORD
CREDENTIALPASSWDAUTHr  )Wr   ra   rf   r^   r   r   r3  r   r  ri   r  r  r)   rC   r(   tempfilemkdtemprn   platform
gettempdirrr   pathr.   r  r  r  r_   r`   r8   rA   rq   writer@   AF_UNIXSOCK_STREAMbindlistenr   r  r   r  tools.env_passthroughr;  ru   environitemsanydirnameabspath__file__pathsepr  
subprocessPopen
executablePIPEDEVNULL_IS_WINDOWSsetsidrB   r  ro   rp   MAX_STDERR_BYTESpollr   _kill_process_groupsleeprc   r  r   rw   rt   r  r  r  r
  ry   rv   rx   shutilrmtreeunlinkrH   r  r  r!   ):r   r;   r   r   r   r   r   r\   r>   r!  r"  tmpdir_sock_tmpdir	sock_pathr<   r=   r%  r:   r(  r   r&  _SAFE_ENV_PREFIXES_SECRET_SUBSTRINGS_is_passthrough	child_envv_hermes_root_existing_pp_tz_nameprocdeadlinestderr_chunks_STDOUT_HEAD_BYTES_STDOUT_TAIL_BYTESrZ  stdout_total_bytesri  stdout_head_chunksstdout_tail_chunksstdout_readerstderr_readerr   stdout_headstdout_tailstderr_texttotal_stdoutr2  truncated_noticer,  r-  rW   r  r
  r   r   r  r   rE  s:   &&&                                                      @r   execute_coder  c  s	   * zz_
  	 tzz||zz7$7899 4 ,H7tm<<
 5 >Dhhy/2GXX.0FGN +8C&SUM3mCDM- %67F !\\X568;N;N;PL\[9I9I8J%+PQIM!JKA 1m1DE	"'',,v'893??1GGI @ "'',,v{3S99QGGDM : mmFNNF4F4FG#1%%#W!= 

 	L0	.S 	JJ$$&DAqq!! 	!s>+=>sss>+=>>>s?,>?sss?,>??? 	! ' *3	%&/2	+, wwrwwrwwx7P'QR }}\26".|"**|2Kac"d	, 99.399;&IdO^^[)????$$*{t		
 >>#g-  !!1C!78-0BB	S  S	)@ $&#%!((#++13E$&8:LN	
 "((m=M NW[
 	iik!&&((#D)&~~(*#D48"JJsO 	1%1%hh1299')9Thh1299')9Thh}-44WY4O *!,**{"S%55K8HHG.wqk :&q):  &(88;FK%3K'+'BDOO	)J6: 	" 	0 - - 	7+K8+K8 fk03	"
 Y 7y@QRF7O}$*-ddF8!^&F8)SS/G	{-SF7O#.1E#E#Sx zz&u5* "A!!# 	fD1	IIi u @?? :99@  	.-O	.b  A<a@@A  		9  )J6:Fa I 	 	
 zzgSX03	

  	 "A!!# A<a@@AfD1	IIi  		9& "A!!# A<a@@AfD1	IIi  		s~  !Ac/ 'a39:c/ 3bBc/ b Ac/ $c/ ;c/ c/ &c/ =c/ B
c/ (Ac/ 7A c/ Dc/ C5c/ D#c/ 4c/ *c/ 4b0c3b	>	c/ b		c/ b-)c/ ,b--c/ 0c;ccc,+c,/h;B
hhh f  g+gg&g==h
hhh jh-,j-i8ijij3j
	j
jjjjc                $    V ^8  d   QhR\         /# )r   rk  r   )r   s   "r   r   r     s     R R Rr   c           	         \         '       d   V P                  4        MD\        P                  ! \        P                  ! V P
                  4      \        P                  4        V'       d    V P                  ^R7       R# R#   \        \        3 dh   p\        P                  RTRR7        T P                  4         Rp?L^  \         d'   p\        P                  RTRR7        Rp? Rp?LRp?ii ; iRp?ii ; i  \        P                    d     \         '       d   T P                  4         R# \        P                  ! \        P                  ! T P
                  4      \        P"                  4        R#   \        \        3 dl   p\        P                  RTRR7        T P                  4         Rp? R#   \         d)   p\        P                  RTRR7        Rp? Rp? R# Rp?ii ; iRp?ii ; ii ; i)z,Kill the child and its entire process group.z Could not kill process group: %sTrR   zCould not kill process: %sNr   z-Could not kill process group with SIGKILL: %s)r  	terminaterr   killpggetpgidpidsignalSIGTERMProcessLookupErrorPermissionErrorrv   rx   killru   r   r  TimeoutExpiredSIGKILL)r  rk  r   e2s   &&  r   r  r    sf   
J;NNIIbjj*FNN; 	RIIaI   0 J7TJ	JIIKK 	JLL5rDLII	J	J (( 	R
R;IIKIIbjj2FNNC&8 RLaZ^_RIIKK  RLL!=rDLQQR	R	Rs   B B AB ,C= C:C5,CC2C-$C5-C22C55C:=G8E8E82AE88G4	G/"F92G89G,G'G/ G8'G,,G//G44G8c                $    V ^8  d   QhR\         /# r   )rk   )r   s   "r   r   r     s      d r   c                 Z     ^ RI Hp  V P                  R/ 4      #   \         d    / u # i ; i)z8Load code_execution config from CLI_CONFIG if available.
CLI_CONFIGcode_execution)clir  ri   ru   r  s    r   r  r    s0    "~~.33 	s    **c                0    V ^8  d   QhR\         R\        /# )r   enabled_sandbox_toolsr   )r)   rk   )r   s   "r   r   r     s     ? ?S ?D ?r   c                J  a  S f   \         o RP                  V 3R l\         4       4      pR Uu. uF  q"S 9   g   K  VNK  	  ppV'       g   \        S 4      R,          pV'       d   RP                  V4      R,           pMRpRV R2pR	R
RVRRRRRRRRRV R2//RR.//# u upi )u&  Build the execute_code schema with description listing only enabled tools.

When tools are disabled via ``hermes tools`` (e.g. web is turned off),
the schema description should NOT mention web_search / web_extract —
otherwise the model thinks they are available and keeps trying to use them.
r&   c              3   >   <"   T F  w  rVS9   g   K  Vx  K  	  R # 5irA  r   )rC  namer5   r  s   &  r   rF  ,build_execute_code_schema.<locals>.<genexpr>  s       ,	8M0M_s   
:Nr   Nr$   z, ...z...a,  Run a Python script that can call Hermes tools programmatically. Use this when you need 3+ tool calls with processing logic between them, need to filter/reduce large tool outputs before they enter your context, need conditional branching (if X then Y else Z), or need to loop (fetch N pages, process N files, retry on failure).

Use normal tool calls instead when: single tool call with no processing, you need to see the full result and apply complex reasoning, or the task requires interactive user input.

Available via `from hermes_tools import ...`:

u  

Limits: 5-minute timeout, 50KB stdout cap, max 50 tool calls per script. terminal() is foreground-only (no background or pty). If the session uses a cloud sandbox backend, treat it as resumable task state rather than a durable always-on machine.

Print your final result to stdout. Use Python stdlib (json, re, math, csv, datetime, collections, etc.) for processing between tool calls.

Also available (no import needed — built into hermes_tools):
  json_parse(text: str) — json.loads with strict=False; use for terminal() output with control chars
  shell_quote(s: str) — shlex.quote(); use when interpolating dynamic strings into shell commands
  retry(fn, max_attempts=3, delay=2) — retry with exponential backoff for transient failuresr  r  description
parametersr  object
propertiesr   stringzDPython code to execute. Import tools with `from hermes_tools import z(` and print your final result to stdout.required)r   r   )r(   r.   _TOOL_DOC_LINESr'   )r  
tool_linesnimport_examples
import_strr  s   f     r   build_execute_code_schemar    s     $ 5  , J
 #=["<QEZ@Zqq"<O[ !67;YY/'9

	< , 	i	i . 	{HH!55?L AAA	 
 = \s
   B B )registryr  r  c                 z    \        V P                  R R4      VP                  R4      VP                  R4      R7      # )r   rJ   r;   r   )r   r;   r   )r  ri   )rK   kws   &,r   r>  r>  =  s/    |XXfb!y!ff_- /r   u   🐍)r  toolsetschemahandlercheck_fnemoji)r   r	   r
   r   r   r   r   )r   zquery: str, limit: int = 5zS"""Search the web. Returns dict with data.web list of {url, title, description}."""z {"query": query, "limit": limit})r	   z
urls: listz`"""Extract content from URLs. Returns dict with results list of {url, title, content, error}."""z{"urls": urls})r
   z,path: str, offset: int = 1, limit: int = 500zS"""Read a file (1-indexed lines). Returns dict with "content" and "total_lines"."""z0{"path": path, "offset": offset, "limit": limit})r   zpath: str, content: strzL"""Write content to a file (always overwrites). Returns dict with status."""z"{"path": path, "content": content})r   zpattern: str, target: str = "content", path: str = ".", file_glob: str = None, limit: int = 50, offset: int = 0, output_mode: str = "content", context: int = 0zr"""Search file contents (target="content") or find files by name (target="files"). Returns dict with "matches"."""z{"pattern": pattern, "target": target, "path": path, "file_glob": file_glob, "limit": limit, "offset": offset, "output_mode": output_mode, "context": context})r   zpath: str = None, old_string: str = None, new_string: str = None, replace_all: bool = False, mode: str = "replace", patch: str = Nonezt"""Targeted find-and-replace (mode="replace") or V4A multi-file patches (mode="patch"). Returns dict with status."""z|{"path": path, "old_string": old_string, "new_string": new_string, "replace_all": replace_all, "mode": mode, "patch": patch})r   z6command: str, timeout: int = None, workdir: str = NonezX"""Run a shell command (foreground only). Returns dict with "output" and "exit_code"."""z<{"command": command, "timeout": timeout, "workdir": workdir})uds>   pty
backgroundcheck_interval)NNr=  ))r   zv  web_search(query: str, limit: int = 5) -> dict
    Returns {"data": {"web": [{"url", "title", "description"}, ...]}})r	   z  web_extract(urls: list[str]) -> dict
    Returns {"results": [{"url", "title", "content", "error"}, ...]} where content is markdown)r
   z  read_file(path: str, offset: int = 1, limit: int = 500) -> dict
    Lines are 1-indexed. Returns {"content": "...", "total_lines": N})r   zT  write_file(path: str, content: str) -> dict
    Always overwrites the entire file.)r   z  search_files(pattern: str, target="content", path=".", file_glob=None, limit=50) -> dict
    target: "content" (search inside files) or "files" (find files by name). Returns {"matches": [...]})r   z  patch(path: str, old_string: str, new_string: str, replace_all: bool = False) -> dict
    Replaces old_string with new_string in the file.)r   z  terminal(command: str, timeout=None, workdir=None) -> dict
    Foreground only (no background/pty). Returns {"output": "...", "exit_code": N}rA  )4__doc__r   ra   loggingrr   r  r  r@   r  rn   r  r   r_   r  systemr  typingr   r   r   r   	getLoggerr  rv   r   rC   r(   r  r  r  r  r   r*   r8   _COMMON_HELPERSr-   r,   rl   r   r   r   r   r3  r  r  r  r  r  EXECUTE_CODE_SCHEMAtools.registryr  registerr   r   r   <module>r     s  :    	     
    oo9, , , 
		8	$LLG+  " #                    K+\ .J$P
 
 % R *0 p C u<xaH H+Vo2lBJ
R@2?F 01  $   	/ (

r   