
    Ki~                     :   d 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ZddlZddl	Z	ddl
Z
ddlZddlZ ej                    dk    ZddlmZmZmZmZ  ej        e          Zej        dk    Z eg d          ZdZdZd	Zd
ZdefdZddddddddZ dee!         de!fdZ"h dZ#dej        de!de$de$de%defdZ&	 	 d-de!dee!         deee!                  de!fdZ'd.d!efd"Z(de)fd#Z*g d$Z+d/d%e,de)fd&Z- e-            Z.dd'l/m0Z0  e0j1        d(d)e.d* ed+,           dS )0a  
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:
  1. Parent generates a `hermes_tools.py` stub module with 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. When the script calls a tool function, the call travels over the UDS
     back to the parent, which dispatches through handle_function_call
  5. 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). Disabled on Windows.
    NWindows)AnyDictListOptionalwin32)
web_searchweb_extract	read_file
write_filesearch_filespatchterminal,  2   iP  i'  returnc                      t           S )zCCode execution sandbox requires a POSIX OS for Unix domain sockets.)SANDBOX_AVAILABLE     6/home/ubuntu/hermes-agent/tools/code_execution_tool.pycheck_sandbox_requirementsr   <   s    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}enabled_toolsc                 <   t          t          t          |           z            }g }g }|D ]X}|t          vrt          |         \  }}}}|                    d| d| d| d|d| d           |                    |           Yd}	|	d                    |          z   S )	z
    Build the source code for the hermes_tools.py stub module.

    Only tools in both SANDBOX_ALLOWED_TOOLS and enabled_tools get stubs.
    zdef (z):
    z
    return _call(, z)
a  """Auto-generated Hermes tools RPC stubs."""
import json, os, socket, shlex, time

_sock = None


# ---------------------------------------------------------------------------
# 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

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


)sortedSANDBOX_ALLOWED_TOOLSset_TOOL_STUBSappendjoin)
r   tools_to_generatestub_functionsexport_names	tool_name	func_namesigdoc	args_exprheaders
             r   generate_hermes_tools_moduler-   u   s     4s=7I7IIJJNL& 	' 	'	K'')4Y)?&	3Y>9 > >s > >> > )> >/8> > >	
 	
 	

 	I&&&&GFR DIIn----r   >   pty
backgroundcheck_intervalserver_socktask_idtool_call_logtool_call_countermax_tool_callsallowed_toolsc                 H
   ddl m} d}	 |                     d           |                                 \  }}|                    d           d}		 	 |                    d          }
n# t
          j        $ r Y nw xY w|
sn|	|
z  }	d	|	v r|	                    d	d
          \  }}	|                                }|s5t          j
                    }	 t          j        |                                          }nf# t          j        t          f$ rM}t          j        dd| i          }|                    |dz                                              Y d}~d}~ww xY w|                    dd          }|                    di           }||vrjd                    t+          |                    }t          j        dd| d| i          }|                    |dz                                              p|d         |k    rFt          j        dd| di          }|                    |dz                                              |dk    r5t-          |t.                    r t0          D ]}|                    |d           	 t4          j        t4          j        }}t;          t<          j        d          }	 |t4          _        |t4          _         ||||          }||ct4          _        t4          _        |                                  n2# ||ct4          _        t4          _        |                                  w xY wnW# tB          $ rJ}tD          #                    d|d           t          j        dtI          |          i          }Y d}~nd}~ww xY w|dxx         d
z  cc<   t          j
                    |z
  }tI          |          dd         }|%                    ||tM          |d          d           |                    |dz                                              d	|	v n^# t
          j        $ r tD          '                    d           Y n3tP          $ r'}tD          '                    d|d           Y d}~nd}~ww xY w|rJ	 |                                  dS # tP          $ r&}tD          '                    d |           Y d}~dS d}~ww xY wdS # |rH	 |                                  w # tP          $ r%}tD          '                    d |           Y d}~w d}~ww xY ww xY w)!z
    Accept one client connection and dispatch tool-call requests until
    the client disconnects or the call limit is reached.
    r   )handle_function_callN   r   r   Ti      
   errorzInvalid RPC request: r   tool argsr   zTool 'z/' is not available in execute_code. Available: zTool call limit reached (z0). No more tool calls allowed in this execution.r   w)r2   zTool call failed in sandbox: %sexc_infoP      )r=   args_previewdurationzRPC listener socket timeoutzRPC listener socket error: %szRPC conn close error: %s))model_toolsr8   
settimeoutacceptrecvsocket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loggerr<   strr"   rounddebugOSError)r1   r2   r3   r4   r5   r6   r8   conn_bufchunkline
call_startrequestexcrespr'   	tool_args	availableparam_real_stdout_real_stderrrc   resultcall_durationrE   es                              r   _rpc_server_loopr|      s    100000Df<q!!!$$&&aU	7		%((>    5LC 3,,IIeQ//	czz|| !^--
"j77GG,.@A   :w0M0M0M&NOODLL$+!5!5!7!7888HHHH
 $KK33	#KK33	 M11 $		&*?*? @ @I:6Y 6 6*36 6'  D LL$+!5!5!7!7888 %Q'>99:L L L L'  D LL$+!5!5!7!7888 
**z)T/J/J*!9 3 3!eT2222
=14SZ,L"2:s33G(%,
%,
!5!5%y'" " " 2>|.
CJ 2>|.
CJ  = = =LL!BCRVLWWW!Z#c(((;<<FFFFFF= "!$$$)$$$ $ 0 0: =  #9~~crc2$$%$0 %mQ 7 7& &    ftm3355666W 3,,U	7n > 4 4 4233333 H H H4a$GGGGGGGGH  	<<

 < < <7;;;;;;;;;<	< 	<4 	<<

 < < <7;;;;;;;;<	<s  AP) A% $P) %A84P) 7A88AP) &C4 3P) 4E
AEP) ED*P) 2L< 5&L	 .L< 	/L88L< ;P) <
NA NP) NBP) (S ))RS 	RQ?:S ?RS 
R   
S*SST!S.-T!.
T8TT!TT!codec           	        7 t           st          j        ddi          S | r|                                 st          j        ddi          S ddlm} t                      }|                    dt                    }|                    dt                    }|rt          |          nt                      }t          t          |z            }|st          }t          j        d	          }	t          j        d
k    rdnt          j                    }
t$          j                            |
dt+          j                    j         d          }g }dg}t1          j                    }d}	 t5          t7          |                    }t9          t$          j                            |	d          d          5 }|                    |           ddd           n# 1 swxY w Y   t9          t$          j                            |	d          d          5 }|                    |            ddd           n# 1 swxY w Y   t=          j        t<          j        t<          j                   }|!                    |           |"                    d           tG          j$        tJ          ||||||fd          }|&                                 d}d}	 ddl'm(} n# tR          $ r d }Y nw xY wi }t$          j*        +                                D ]R\  7} |7          r||7<   tY          7fd|D                       r2tY          7fd|D                       r||7<   S||d<   d|d<   t$          j        -                    t$          j        -                    t$          j        .                    t^                                        }|                    dd          }||rt$          j0        |z   ndz   |d<   t%          j1        d d                                          }|r||d!<   te          j3        t          j4        dg|	|td          j5        td          j5        td          j6        tn          rdnt$          j8        "          }t1          j                    |z   }g }ts          tt          d#z            }tt          |z
  }d$ } dg}!d% }"g }#g }$tG          j$        |"|j;        |#|$|||!fd          }%tG          j$        | |j<        |tz          fd          }&|%&                                 |&&                                 d&}'|>                                y|?                                rt          |           d'}'nSt1          j                    |k    rt          |d(           d}'n(t1          jA        d)           |>                                y|%                    d*+           |&                    d*+           d,                    |#          B                    d-d./          }(d,                    |$          B                    d-d./          })d,                    |          B                    d-d./          }*|!d         }+|+tt          k    r8|)r6|+t          |(          z
  t          |)          z
  },d0|,d1d2|+d1d3}-|(|-z   |)z   }.n|(|)z   }.|jD        |jD        nd4}/t          t1          j                    |z
  d5          }0|F                                 d}|                    d*+           dd6lGmH}1  |1|.          }. |1|*          }*dd7lImJ}2  |2|.          }. |2|*          }*|'|.|d         |0d8}3|'dk    r
d9| d:|3d<   n1|'d'k    r	|.d;z   |3d<<   n"|/dk    rd|3d=<   |*pd>|/ |3d<   |*r|.d?z   |*z   |3d<<   t          j        |3d@A          |H	 |F                                 n2# t          $ r%}4t          M                    dB|4           Y d}4~4nd}4~4ww xY wddlN}5|5O                    |	dC           	 t%          jP        |           S # t          $ r Y S w xY w# tR          $ r}6t          t1          j                    |z
  d5          }0t          Q                    dD|0|d         t          |6          jS        |6dE           t          j        dt          |6          |d         |0dFd@A          cY d}6~6|H	 |F                                 n2# t          $ r%}4t          M                    dB|4           Y d}4~4nd}4~4ww xY wddlN}5|5O                    |	dC           	 t%          jP        |           S # t          $ r Y S w xY wd}6~6ww xY w# |H	 |F                                 n2# t          $ r%}4t          M                    dB|4           Y d}4~4nd}4~4ww xY wddlN}5|5O                    |	dC           	 t%          jP        |           w # t          $ r Y w w xY wxY w)Ga  
    Run a Python script in a sandboxed child process with RPC access
    to a subset of Hermes tools.

    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.
    r<   zHexecute_code is not available on Windows. Use normal tool calls instead.zNo code provided.r   )_interrupt_eventrL   r5   hermes_sandbox_)prefixdarwinz/tmphermes_rpc_z.sockNzhermes_tools.pyr@   z	script.pyr;   T)targetr?   daemon)PATHHOMEUSERLANGLC_TERMTMPDIRTMPTEMPSHELLLOGNAMEXDG_
PYTHONPATHVIRTUAL_ENVCONDA)KEYTOKENSECRETPASSWORD
CREDENTIALPASSWDAUTH)is_env_passthroughc                     dS )NFr   )rl   s    r   <lambda>zexecute_code.<locals>.<lambda>  s     r   c              3   D   K   | ]}|                                 v V  d S N)upper).0sks     r   	<genexpr>zexecute_code.<locals>.<genexpr>  s/      >>a1		>>>>>>>r   c              3   B   K   | ]}                     |          V  d S r   )
startswith)r   pr   s     r   r   zexecute_code.<locals>.<genexpr>  s-      ??q1<<????????r   HERMES_RPC_SOCKET1PYTHONDONTWRITEBYTECODEr   r>   HERMES_TIMEZONETZ)cwdenvr_   r`   stdin
preexec_fng?c                 *   d}	 	 |                      d          }|sdS ||k     r"||z
  }|                    |d|                    |t          |          z  }T# t          t          f$ r(}t
                              d|d           Y d}~dS d}~ww xY w)z)Simple head-only drain (used for stderr).r   T   Nz Error reading process output: %srA   )readr"   len
ValueErrorrj   rf   ri   )pipechunks	max_bytestotaldatakeepr{   s          r   _drainzexecute_code.<locals>._drain  s    E
S'99T??D y(((50d5D5k222SYY&E' ( S S S?TRRRRRRRRRSs   A ;A B*BBc                 \   d}ddl m}  |            }d}		 	 |                     d          }
|
sn|dxx         t          |
          z  cc<   ||k     rOt	          t          |
          ||z
            }|                    |
d|                    ||z  }|
|d         }
|
s|                    |
           |	t          |
          z  }	|	|k    r0|r.|                                }|	t          |          z  }	|	|k    r|.n# t          t          f$ r Y nw xY w|	                    |           dS )z-Drain stdout keeping both head and tail data.r   )dequeTr   N)
collectionsr   r   r   minr"   popleftr   rj   extend)r   head_chunkstail_chunks
head_bytes
tail_bytes	total_refhead_collectedr   tail_buftail_collectedr   r   oldests                r   _drain_head_tailz&execute_code.<locals>._drain_head_tail  s~   N))))))uwwHN699T??D aLLLCII-LLL%
22"3t99j>.IJJ#**4;777&$.#DEE{# %$OOD)))"c$ii/N(:55(5!)!1!1!3!3&#f++5 ):55(5#6 " (    x(((((s   C)D   DDsuccessinterrupted)escalateg?   rL   r   zutf-8replace)errorsz

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

rD   )
strip_ansi)redact_sensitive_text)statusoutputtool_calls_madeduration_secondszScript timed out after zs and was killed.u4   
[execution interrupted — user sent a new message]r   r   zScript exited with code z
--- stderr ---
F)ensure_asciizServer socket close error: %s)ignore_errorsz8execute_code failed after %ss with %d tool calls: %s: %srA   )r   r<   r   r   )Ur   rQ   rV   rN   tools.terminal_toolr   _load_configrY   DEFAULT_TIMEOUTDEFAULT_MAX_TOOL_CALLSr    	frozensetr   tempfilemkdtempr^   platform
gettempdirrb   pathr#   uuiduuid4hexrO   rP   r-   listra   writerK   AF_UNIXSOCK_STREAMbindlisten	threadingThreadr|   starttools.env_passthroughr   re   environitemsanydirnameabspath__file__pathsepgetenv
subprocessPopen
executablePIPEDEVNULL_IS_WINDOWSsetsidintMAX_STDOUT_BYTESr_   r`   MAX_STDERR_BYTESpollis_set_kill_process_groupsleeprS   r   
returncoderh   rd   tools.ansi_stripr   agent.redactr   rj   rf   ri   shutilrmtreeunlinkr<   type__name__rg   )8r}   r2   r   r   _cfgrL   r5   session_toolssandbox_toolstmpdir_sock_tmpdir	sock_pathr3   r4   
exec_startr1   	tools_srcf
rpc_thread_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_BYTESr   stdout_total_bytesr   stdout_head_chunksstdout_tail_chunksstdout_readerstderr_readerr   stdout_headstdout_tailstderr_texttotal_stdoutomittedtruncated_noticestdout_text	exit_coderF   r   r   ry   r{   r  rr   r   s8                                                          @r   execute_coder8  Z  s"   $  z_
   	  :tzz|| :z7$78999 544444 >>Dhhy/22GXX.0FGGN +8BC&&&SUUM3mCDDM .- %6777F !\X55668;N;P;PL\+P9I+P+P+PQQIM!!JKA 1m1D1DEE	"',,v'8993?? 	1GGI	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 "',,v{33S99 	QGGDMMM	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 mFNF4FGG###1%#Wm!>= 
 
 

 	L0	.SSSSSSS 	. 	. 	.-oOOO	.	J$$&& 
	! 
	!DAqq!!  	!>>>>+=>>>>> ????,>????? ! 	!)2	%&/2	+, wrwrwx7P7P'Q'QRR }}\266".|2c"*|2K2Kac"d	, 9.3399;; 	'&IdO^[)??$*9tt	
 
 
 >##g-  !!1C!788-0BB	S 	S 	S  S	) 	) 	)@ $&#%!(#+13E$&8:LN	
 
 
 "(m=M NW[
 
 
 	iikk!&&(( #D)))&~(**#D48888"JsOOO iikk! 	1%%%1%%%hh12299')9TThh12299')9TThh}--44WY4OO *!,***{*"S%5%55K8H8HHG:wI : :&9: : :  &(88;FKK%3K'+'BDOO	))J6:: 	""" 	0///// j-- j-- 	766666++K88++K88 !03 (	"
 "
 YRRRRF7OO}$$*-ddF8!^^&F8)S-S	-S-SF7O T#.1E#E#Sx z&u555* "A!!#### A A A<a@@@@@@@@AfD111	Ii     	 	 	D	9    ))J6::Fa II 	 	
 	
 	
 zXX03 (	
 

    	 	 	 	 	 "A!!#### A A A<a@@@@@@@@AfD111	Ii     	 	 	D	9& "A!!#### A A A<a@@@@@@@@AfD111	Ii     	 	 	D	sB  #A
`0 -G`0 G`0 G1`0 H*`0 *H..`0 1H.2B`0 K
 	`0 
K`0 KS`0 (^==
_,_''_,`  
`-,`-0e;B	eee c!!
d+dd/e
eeee g( e54g(5
f$?fg(f$$g(gg(
g%"g($g%%g(Fr   c                    	 t           r|                                  n6t          j        t          j        | j                  t          j                   n# t          t          f$ rq}t                              d|d           	 |                                  n4# t          $ r'}t                              d|d           Y d}~nd}~ww xY wY d}~nd}~ww xY w|r	 |                     d           dS # t          j        $ r 	 t           r|                                  n9t          j        t          j        | j                  t          j                   Y dS Y dS # t          t          f$ rz}t                              d|d           	 |                                  n4# t          $ r'}t                              d|d           Y d}~nd}~ww xY wY d}~Y dS Y d}~Y dS d}~ww xY ww xY wdS )	z,Kill the child and its entire process group.z Could not kill process group: %sTrA   zCould not kill process: %sNr9   r   z-Could not kill process group with SIGKILL: %s)r  	terminaterb   killpggetpgidpidsignalSIGTERMProcessLookupErrorPermissionErrorrf   ri   killre   waitr   TimeoutExpiredSIGKILL)r&  r   r{   e2s       r   r
  r
    s]   
J 	<NNIbj**FN;;;0 J J J7TJJJ	JIIKKKK 	J 	J 	JLL5rDLIIIIIIII	J	J  R	RIIaI     ( 	R 	R 	R
R DIIKKKKIbj22FNCCCCCC  KK '8 R R RLaZ^___RIIKKKK  R R RLL!=rDLQQQQQQQQR  KKKKKKQQQQQQQR	R	R Rs   AA C&CBC
C
#C CC

CCC6 6G-AEG)/G$F"!G$"
G,G	G$GG$G-G-$G))G-c                  `    	 ddl m}  |                     di           S # t          $ r i cY S w xY w)z8Load code_execution config from CLI_CONFIG if available.r   
CLI_CONFIGcode_execution)clirI  rY   re   rH  s    r   r   r     sR    """"""~~.333   			s    --))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}enabled_sandbox_toolsc                      t            d                     fdt          D                       } fddD             }|st                     dd         }|rd                    |          dz   }nd	}d
| d}d|dddd| ddidgddS )u6  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.
    Nr   c              3   *   K   | ]\  }}|v 	|V  d S r   r   )r   namer*   rL  s      r   r   z,build_execute_code_schema.<locals>.<genexpr>  s;        c8M0M0M0M0M0M0M r   c                     g | ]}|v |	S r   r   )r   nrL  s     r   
<listcomp>z-build_execute_code_schema.<locals>.<listcomp>  s$    [[[QEZ@Z@Zq@Z@Z@Zr   )r	   r   rD   r   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 failuresr8  objectr}   stringzDPython code to execute. Import tools with `from hermes_tools import z(` and print your final result to stdout.)r  description)r  
propertiesrequired)rO  rU  
parameters)r   r#   _TOOL_DOC_LINESr   )rL  
tool_linesimport_examples
import_strrU  s   `    r   build_execute_code_schemar]    s*    $ 5     ,    J
 \[[["<[[[O < !677; YY//'9


	i 	i 	i 	i . "$A5?A A A 	  
 
  r   )registryr8  rJ  c                     t          |                     dd          |                    d          |                    d                    S )Nr}   r>   r2   r   )r}   r2   r   )r8  rY   )r?   kws     r   r   r   )  sD    |XXfb!!y!!ff_-- /  /  / r   u   🐍)rO  toolsetschemahandlercheck_fnemoji)NN)Fr   )2__doc__rQ   loggingrb   r   r>  rK   r   r^   r   r   rO   r   systemr  typingr   r   r   r   	getLoggerr  rf   r   r   r   r   r   r  r  boolr   r!   rg   r-   r\   r   r  r|   r8  r
  r[   r   rY  r    r]  EXECUTE_CODE_SCHEMAtools.registryr^  registerr   r   r   <module>ro     s6   $   				        



       ho9, , , , , , , , , , , , , 
	8	$	$LG+  "	 # # #       D    K+ +\^.S	 ^.c ^. ^. ^. ^.L CBB u<u<u< u< 	u<
 u< u< u< u< u<| ")-w w
wc]w DI&w 		w w w wt	R R R R R R@d      2? ?S ?D ? ? ? ?F 0/11  $ # # # # #  	/ / (

 
 
 
 
 
r   