
    i                        U 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mZ ddlm	Z	 ddl
mZ ddlmZ  ej        e          Zej        ej        ej        hZdZdaedz  ed<   d	efd
ZdZ eh d          Zded	efdZdZ ddhZ!ded	edz  fdZ"de#d	efdZ$ ej%                    Z&i Z'e(ed<    ej%                    Z)i Z*e(ed<   dpded	efdZ+dqdefdZ,drdedededed	ef
d Z-dqdefd!Z.dpdefd"Z/deded	dfd#Z0deded	edz  fd$Z1dpded%eded	efd&Z2	 	 	 dsd)eded*ed+ed,ed-eded	efd.Z3	 	 	 	 dtd1ed2eded3ededed4ed5eded	efd6Z4dd7l5m6Z6m7Z7 d8 Z8d9d:d;d<d=d>d?d@dddAd?dBddCdDdEdgdFdGZ9dHdId;d<dJd>d<dKd>dLdd%gdFdGZ:d-dMd;d<d'd-gdNd'dOd<dPd>d<dQd>d<dRd>dSdTd(dUd<dVd>dWd)gdFdGZ;dXdYd;d<dZd>d<d%d[gd\d%dOd<d]d/dUd<d^d>d?d_d0dUd?d`ddUd<g dadbd%dOd?dcddUddd1gdFdGZ<de Z=df Z>dg Z?dh Z@ e6jA        d9die9e=e8dj eBdk          l            e6jA        dHdie:e>e8dmdl            e6jA        d-die;e?e8dndl            e6jA        dXdie<e@e8dodl           dS )uz6File Tools Module - LLM agent file manipulation tools.    N)Path)has_binary_extension)ShellFileOperations)redact_sensitive_texti _max_read_chars_cachedreturnc                     t           t           S 	 ddlm}   |             }|                    d          }t	          |t
          t          f          r|dk    rt          |          a t           S n# t          $ r Y nw xY wt          a t           S )zReturn the configured max characters per file read.

    Reads ``file_read_max_chars`` from config.yaml on first call, caches
    the result for the lifetime of the process.  Falls back to the
    built-in default if the config is missing or invalid.
    Nr   )load_configfile_read_max_chars)	r   hermes_cli.configr
   get
isinstanceintfloat	Exception_DEFAULT_MAX_READ_CHARS)r
   cfgvals      8/home/agentuser/.hermes/hermes-agent/tools/file_tools.py_get_max_read_charsr       s     )%%111111kmmgg+,,cC<(( 	*S1WW%(XX"))   4!!s   AA. .
A;:A;i  >   /dev/tty	/dev/fd/0	/dev/fd/1	/dev/fd/2	/dev/full	/dev/zero
/dev/stdin/dev/random/dev/stderr/dev/stdout/dev/console/dev/urandomfilepathc                     t           j                            |           }|t          v rdS |                    d          r|                    d          rdS dS )uG  Return True if the path would hang the process (infinite output or blocking input).

    Uses the *literal* path — no symlink resolution — because the model
    specifies paths directly and realpath follows symlinks all the way
    through (e.g. /dev/stdin → /proc/self/fd/0 → /dev/pts/0), defeating
    the check.
    Tz/proc/)z/fd/0z/fd/1z/fd/2F)ospath
expanduser_BLOCKED_DEVICE_PATHS
startswithendswith)r#   
normalizeds     r   _is_blocked_devicer,   J   sf     ##H--J***tX&& :+>+>#, ,  t5    )z/etc/z/boot/z/usr/lib/systemd/z/private/etc/z/private/var/z/var/run/docker.sockz/run/docker.sockc                    	 t           j                            t           j                            |                     }n# t          t
          f$ r | }Y nw xY wt           j                            t           j                            |                     }d|  d}t          D ]0}|                    |          s|                    |          r|c S 1|t          v s	|t          v r|S dS )zHReturn an error message if the path targets a sensitive system location.z,Refusing to write to sensitive system path: zD
Use the terminal tool with sudo if you need to modify system files.N)
r%   r&   realpathr'   OSError
ValueErrornormpath_SENSITIVE_PATH_PREFIXESr)   _SENSITIVE_EXACT_PATHS)r#   resolvedr+   _errprefixs        r   _check_sensitive_pathr8   f   s   7##BG$6$6x$@$@AAZ    !!"'"4"4X">">??J	Nx 	N 	N 	N 	 +  v&& 	**?*?*G*G 	KKK	)))Z;Q-Q-Q4s   <? AAexcc                 ~    t          | t                    rdS t          | t                    r| j        t          v rdS dS )zFReturn True for expected write denials that should not hit error logs.TF)r   PermissionErrorr0   errno_EXPECTED_WRITE_ERRNOS)r9   s    r   _is_expected_write_exceptionr>   y   sB    #'' t#w CI1G$G$Gt5r-   _file_ops_cache_read_trackerdefaulttask_idc                 x   ddl m}m}m}m}m}m}m}m} ddl	}	t          5  t                              |           }
ddd           n# 1 swxY w Y   |
}|5  | |v r%|		                                || <   |
cddd           S t          5  t                              | d           ddd           n# 1 swxY w Y   ddd           n# 1 swxY w Y   |5  | |vrt          j                    || <   ||          }ddd           n# 1 swxY w Y   |5  |5  | |v r |		                                || <   ||          }nd}ddd           n# 1 swxY w Y   |ddl m}  |            }|d         }|                    | i           }|dk    r|                    d          p|d         }nn|dk    r|                    d	          p|d	         }nJ|d
k    r|                    d          p|d         }n&|dk    r|                    d          p|d         }nd}|                    d          p|d         }t"                              d|| dd                    d}|dv rl|                    dd          |                    dd          |                    dd          |                    dd          |                    dg           d}d}|dk    rl|                    dd          |                    dd          |                    d d!          |                    d"d          |                    d#d$          d%}d}|d&k    rd'|                    d(d$          i} |||||d)         |||| |                    d*          +	  	        }|5  ||| <   |		                                || <   ddd           n# 1 swxY w Y    |             t"                              d,|| dd                    ddd           n# 1 swxY w Y   t'          |          }t          5  |t          | <   ddd           n# 1 swxY w Y   |S )-a  Get or create ShellFileOperations for a terminal environment.

    Respects the TERMINAL_ENV setting -- if the task_id doesn't have an
    environment yet, creates one using the configured backend (local, docker,
    modal, etc.) rather than always defaulting to local.

    Thread-safe: uses the same per-task creation locks as terminal_tool to
    prevent duplicate sandbox creation from concurrent tool calls.
    r   )_active_environments	_env_lock_create_environment_get_env_config_last_activity_start_cleanup_thread_creation_locks_creation_locks_lockN)_task_env_overridesenv_typedockerdocker_imagesingularitysingularity_imagemodalmodal_imagedaytonadaytona_image cwdz*Creating new %s environment for task %s...   )rN   rP   rR   rT   container_cpu   container_memoryi   container_diski   container_persistentTdocker_volumes)rY   r[   r\   r]   r^   sshssh_hostssh_userssh_port   ssh_keyssh_persistentF)hostuserportkey
persistentlocalrj   local_persistenttimeouthost_cwd)	rM   imagerW   rm   
ssh_configcontainer_configlocal_configrB   rn   z %s environment ready for task %s)tools.terminal_toolrD   rE   rF   rG   rH   rI   rJ   rK   time_file_ops_lockr?   r   pop	threadingLockrL   loggerinfor   )rB   rD   rE   rF   rG   rH   rI   rJ   rK   rt   cached	task_lockterminal_envrL   configrM   	overridesro   rW   rq   rp   rr   file_opss                          r   _get_file_opsr      s9                       KKK 
 . . $$W--. . . . . . . . . . . . . . . 	7 	7...*.))++w'	7 	7 	7 	7 	7 	7 	7 	7 $ 7 7#''6667 7 7 7 7 7 7 7 7 7 7 7 7 7 7	7 	7 	7 	7 	7 	7 	7 	7 	7 	7 	7 	7 	7 	7 	7 
 - -/))'0~'7'7OG$#G,	- - - - - - - - - - - - - - -
 
 IS IS 	$ 	$...*.))++w'3G<#	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ ??????$_&&Fj)H+//<<I8##!n55O9O]**!&9::YfEX>YW$$!m44M}8MY&&!o66Q&:Q--&&7&-CKKDhPWXZYZXZP[\\\#HHH%+ZZ%C%C(.

3Et(L(L&,jj1A5&I&I,2JJ7Mt,T,T&,jj1A2&F&F$ $  J5  "JJz266"JJz266"JJz266!::i44"(**-=u"E"E 
  L7"" &**-?"G"G  /.!y)%!1)J//
 
 
L  6 60<$W-*.))++w'6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 "!###KK:HgbqbkRRRSIS IS IS IS IS IS IS IS IS IS IS IS IS IS ISX #<00H	 , ,#+ , , , , , , , , , , , , , , ,Os   AAAC CB/#C/B3	3C6B3	7CC
C
#DD	DO7'E9O7E			O7E		H<O7	N2&O72N6	6O79N6	:1O77O;>O;P//P36P3c                     t           5  | rt                              | d           nt                                           ddd           dS # 1 swxY w Y   dS )z Clear the file operations cache.N)ru   r?   rv   clear)rB   s    r   clear_file_ops_cacher     s    	 $ $ 	$....!!###	$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $s   8AAArZ     r&   offsetlimitc           	         	 t          |           rt          j        dd|  di          S t          |                                                                           }t          t          |                    r6|j        	                                }t          j        dd|  d| di          S ddl
m}  |                                            }|d	z  d
z  dz  |d	z  d
z  g}|D ]C}		 |                    |	           t          j        dd|  di          c S # t          $ r Y @w xY wt          |          }
|
||f}t          5  t                              |ddt#                      i d          }|                    di                               |          }ddd           n# 1 swxY w Y   |Q	 t&          j                            |
          }||k    rt          j        d| ddd          S n# t,          $ r Y nw xY wt/          |          }|                    | ||          }|                                }t5          |j        pd          }|                    dd          }t9                      }||k    r=|                    dd          }t          j        d|dd|dd| d| ||dd          S |j        r#t;          |j                  |_        |j        |d <   |rA|t<          k    r6|d!k    r0|                    d"          r|                    d#d$|dd%           d&| ||f}t          5  d|vri |d<   |d'                             | ||f           |d(         |k    r|d)xx         d*z  cc<   n
||d(<   d*|d)<   |d)         }	 t&          j                            |
          }||d         |<   ||                    d+i           |
<   n# t,          $ r Y nw xY wddd           n# 1 swxY w Y   |d,k    rt          j        d-| d.| |d/d          S |d0k    r	d1| d2|d3<   t          j        |d          S # t@          $ r&}tC          t          |                    cY d}~S d}~ww xY w)4z-Read a file with pagination and line numbers.errorzCannot read 'zE': this is a device file that would block or produce infinite output.zCannot read binary file 'z' (zF). Use vision_analyze for images, or terminal to inspect binary files.r   )get_hermes_homeskillsz.hubzindex-cachezAccess denied: z is an internal Hermes cache file and cannot be read directly to prevent prompt injection. Use the skills_list or skill_view tools instead.N)last_keyconsecutiveread_historydedupr   u   File unchanged since last read. The content from the earlier read_file result in this conversation is still current — refer to that instead of re-reading.T)contentr&   r   Fensure_asciirV   	file_sizetotal_linesunknownzRead produced ,z, characters which exceeds the safety limit (zD chars). Use offset and limit to read a smaller range. The file has z lines total.)r   r&   r   r   r      	truncated_hintzThis file is large (zj bytes). Consider reading only the section you need with offset and limit to keep context usage efficient.readr   r   r   rZ   read_timestamps   z.BLOCKED: You have read this exact file region z| times in a row. The content has NOT changed. You already have this information. STOP re-reading and proceed with your task.)r   r&   already_read   z%You have read this exact file region z times consecutively. The content has not changed since your last read. Use the information you already have. If you are stuck in a loop, stop reading and proceed with writing or responding._warning)"r,   jsondumpsr   r'   resolver   strsuffixlowerhermes_constantsr   relative_tor1   _read_tracker_lockr@   
setdefaultsetr   r%   r&   getmtimer0   r   	read_fileto_dictlenr   r   r   _LARGE_FILE_HINT_BYTESaddr   
tool_error)r&   r   r   rB   	_resolved_ext_get_hh_hermes_home_blocked_dirs_blockedresolved_str	dedup_key	task_datacached_mtimecurrent_mtimer   resultresult_dictcontent_lenr   	max_charsr   read_keycount
_mtime_nowes                             r   read_file_toolr     s   e" d## 	:8D 8 8 8    JJ))++3355	  I// 	#))++D:Z Z Z Z Z Z    	@?????wyy((**8#f,}<8#f,
 & 	 	H
%%h///zK$ K K K#          9~~!651	 	E 	E%00  #; ;  I %=="5599)DDL	E 	E 	E 	E 	E 	E 	E 	E 	E 	E 	E 	E 	E 	E 	E # " 0 0 > > L00:U !%!%' ' %*+ + + + 1     !))##D&%88nn&& &..B//OOK33	'))	""%//-CCK:?[N ? ?)2?? ? %0? ? ?
 *&
 
 "
# 
# 
# 
# > 	426>BBFN%+^K	"  	)&<<<CKKOOK00  ""73y= 3 3 3   D&%0 	 	i''%'	'"n%))4*?@@@$00-(((A-(((((0	*%+,	-(m,EW--l;;
0:	'"9-LV	$$%6;;LII   )	 	 	 	 	 	 	 	 	 	 	 	 	 	 	. A:::BU B B B  %  "# # # # aZZc c c c 
# z+E:::: " " "#a&&!!!!!!!!"s   (Q BQ 09Q *.DQ 
D(%Q 'D((Q AF(Q (F,,Q /F,0Q 6>G6 5Q 6
H Q HB9Q =A:Q 7AO/AOO/
O O/O  O/#Q /O33Q 6O37&Q $Q 
Q3Q.(Q3.Q3c                 4   t           5  | r;t                              |           }|rd|v r|d                                          n:t                                          D ] }d|v r|d                                          !ddd           dS # 1 swxY w Y   dS )u  Clear the deduplication cache for file reads.

    Called after context compression — the original read content has been
    summarised away, so the model needs the full content if it reads the
    same file again.  Without this, reads after compression would return
    a "file unchanged" stub pointing at content that no longer exists in
    context.

    Call with a task_id to clear just that task, or without to clear all.
    r   N)r   r@   r   r   valuesrB   r   s     r   reset_file_dedupr     s     
 / / 	/%))'22I +W	11'"((****1133 / /	i''g&,,.../ / / / / / / / / / / / / / / / / /s   A8BBBc                     t           5  t                              |           }|r
d|d<   d|d<   ddd           dS # 1 swxY w Y   dS )u  Reset consecutive read/search counter for a task.

    Called by the tool dispatcher (model_tools.py) whenever a tool OTHER
    than read_file / search_files is executed.  This ensures we only warn
    or block on *truly consecutive* repeated reads — if the agent does
    anything else in between (write, patch, terminal, etc.) the counter
    resets and the next read is treated as fresh.
    Nr   r   r   )r   r@   r   r   s     r   notify_other_tool_callr     s     
 ) )!%%g..	 	)$(Ij!'(Im$	) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) )s   '<A A c                    	 t          t          |                                                                                     }t          j                            |          }n# t          t          f$ r Y dS w xY wt          5  t                              |          }|||                    di           |<   ddd           dS # 1 swxY w Y   dS )u  Record the file's current modification time after a successful write.

    Called after write_file and patch so that consecutive edits by the
    same task don't trigger false staleness warnings — each write
    refreshes the stored timestamp to match the file's new state.
    Nr   )r   r   r'   r   r%   r&   r   r0   r1   r   r@   r   r   )r#   rB   r5   r   r   s        r   _update_read_timestampr     s"   tH~~0022::<<==((22Z    	 R R!%%g..	 DQI  !2B77AR R R R R R R R R R R R R R R R R Rs$   AA" "A76A76CCCc                 "   	 t          t          |                                                                                     }n# t          t
          f$ r Y dS w xY wt          5  t                              |          }|s	 ddd           dS |                    di                               |          }ddd           n# 1 swxY w Y   |dS 	 t          j
                            |          }n# t          $ r Y dS w xY w||k    rd|  dS dS )u  Check whether a file was modified since the agent last read it.

    Returns a warning string if the file is stale (mtime changed since
    the last read_file call for this task), or None if the file is fresh
    or was never read.  Does not block — the write still proceeds.
    Nr   z	Warning: z was modified since you last read it (external edit or concurrent agent). The content you read may be stale. Consider re-reading the file to verify before writing.)r   r   r'   r   r0   r1   r   r@   r   r%   r&   r   )r#   rB   r5   r   
read_mtimer   s         r   _check_file_stalenessr     s   tH~~0022::<<==Z    tt	 H H!%%g..	 	H H H H H H H H ]]#4b99==hGG
	H H H H H H H H H H H H H H H
 t((22   tt
""L L L L	

 4s<   A A AA"C)CC	CC2 2
D ?D r   c                 r   t          |           }|rt          |          S 	 t          | |          }t          |          }|                    | |          }|                                }|r||d<   t          | |           t          j        |d          S # t          $ r}t          |          r/t                              dt          |          j        |           n0t                              dt          |          j        |d           t          t!          |                    cY d}~S d}~ww xY w)	zWrite content to a file.r   Fr   z"write_file expected denial: %s: %szwrite_file error: %s: %sT)exc_infoN)r8   r   r   r   
write_filer   r   r   r   r   r>   ry   debugtype__name__r   r   )	r&   r   rB   sensitive_errstale_warningr   r   r   r   s	            r   write_file_toolr     s?   )$//M )-((("-dG<< ))$$T733nn&& 	4&3K
# 	tW---z+E:::: " " "'** 	YLL=tAww?OQRSSSSLL3T!WW5EqSWLXXX#a&&!!!!!!!!"s   A5B 
D6"B	D1+D61D6replaceFmode
old_string
new_stringreplace_allpatchc                    g }|r|                     |           | dk    r_|r]ddl}|                    d||j                  D ]<}	|                     |	                    d                                                     =|D ]$}
t          |
          }|rt          |          c S %	 g }|D ])}
t          |
|          }|r|                     |           *t          |          }| dk    r=|st          d          S ||t          d          S |
                    ||||          }n?| dk    r'|st          d	          S |                    |          }nt          d
|            S |                                }|r3t          |          dk    r|d         nd                    |          |d<   |                    d          s|D ]}
t!          |
|           t#          j        |d          }|                    d          rdt'          |d                   v r|dz  }|S # t(          $ r&}t          t'          |                    cY d}~S d}~ww xY w)z4Patch a file using replace mode or V4A patch format.r   r   Nz/^\*\*\*\s+(?:Update|Add|Delete)\s+File:\s*(.+)$rZ   r   zpath requiredz"old_string and new_string requiredzpatch content requiredzUnknown mode: z | r   r   Fr   zCould not findzp

[Hint: old_string not found. Use read_file to verify the current content, or search_files to locate the text.])appendrefinditer	MULTILINEgroupstripr8   r   r   r   patch_replace	patch_v4ar   r   joinr   r   r   r   r   r   )r   r&   r   r   r   r   rB   _paths_to_check_re_m_pr   stale_warnings_swr   r   r   result_jsonr   s                      r   
patch_toolr   5  s   
 O %t$$$w5,,QSXZ]Zghh 	8 	8B""288A;;#4#4#6#67777 - --b11 	-m,,,,,	-&"! 	+ 	+B'G44C +%%c*** ))9 3!/222!Z%7!"FGGG++D*j+VVFFW__ <!":;;;''..FF5t55666nn&& 	t;>~;N;NRS;S;SnQ&7&7Y^YcYcdrYsYsK
# w'' 	4% 4 4&r73333j5AAA ??7## 	P(8CG@T<U<U(U(U  P  PK " " "#a&&!!!!!!!!"s8   'AH" ;H" /H" >'H" &B;H" "
I,III.2   patterntarget	file_globoutput_modecontextc	           
      |   	 d| |t          |          |pd||f}	t          5  t                              |ddt	                      d          }
|
d         |	k    r|
dxx         dz  cc<   n
|	|
d<   d|
d<   |
d         }ddd           n# 1 swxY w Y   |d	k    rt          j        d
| d| |dd          S t          |          }|                    | |||||||          }t          |d          r:|j
        D ]2}t          |d          r |j        rt          |j                  |_        3|                                }|dk    r	d| d|d<   t          j        |d          }|                    d          r||z   }|d| dz  }|S # t          $ r&}t!          t          |                    cY d}~S d}~ww xY w)zSearch for content or files.searchrV   Nr   )r   r   r   r   r   rZ   r   z(BLOCKED: You have run this exact search z times in a row. The results have NOT changed. You already have this information. STOP re-searching and proceed with your task.)r   r   already_searchedFr   )r   r&   r   r   r   r   r   r   matchesr   r   zYou have run this exact search zY times consecutively. The results have not changed. Use the information you already have.r   r   z'

[Hint: Results truncated. Use offset=zC to see more, or narrow with a more specific pattern or file_glob.])r   r   r@   r   r   r   r   r   r   hasattrr   r   r   r   r   r   r   )r   r   r&   r   r   r   r   r   rB   
search_keyr   r   r   r   mr   r   next_offsetr   s                      r   search_toolr  n  s   
<"
 IIO

   		- 		-%00 CEE; ;  I $
22-(((A-(((((2	*%+,	-(m,E		- 		- 		- 		- 		- 		- 		- 		- 		- 		- 		- 		- 		- 		- 		- A:::Du D D D #$)  "# # # # !))$vK ! 
 
 69%% 	A^ A A1i(( AQY A 5ai @ @AInn&&A::V% V V V 
#
 j5AAA ??;'' 	X 5.K  X{  X  X  X  XK " " "#a&&!!!!!!!!"sH   F AB<F BF B&F 7CF 
F;F60F;6F;)registryr   c                  "    ddl m}   |             S )z=Lazy wrapper to avoid circular import with tools/__init__.py.r   check_file_requirements)toolsr  r  s    r   _check_file_reqsr    s#    ------""$$$r-   r   u  Read a text file with line numbers and pagination. Use this instead of cat/head/tail in terminal. Output format: 'LINE_NUM|CONTENT'. Suggests similar filenames if not found. Use offset and limit for large files. Reads exceeding ~100K characters are rejected; use offset and limit to read specific sections of large files. NOTE: Cannot read images or binary files — use vision_analyze for images.objectstringz8Path to the file to read (absolute, relative, or ~/path))r   descriptionintegerz9Line number to start reading from (1-indexed, default: 1))r   r
  rA   minimumz9Maximum number of lines to read (default: 500, max: 2000)i  )r   r
  rA   maximum)r&   r   r   )r   
propertiesrequired)namer
  
parametersr   u   Write content to a file, completely replacing existing content. Use this instead of echo/cat heredoc in terminal. Creates parent directories automatically. OVERWRITES the entire file — use 'patch' for targeted edits.zWPath to the file to write (will be created if it doesn't exist, overwritten if it does)z%Complete content to write to the file)r&   r   ai  Targeted find-and-replace edits in files. Use this instead of sed/awk in terminal. Uses fuzzy matching (9 strategies) so minor whitespace/indentation differences won't break it. Returns a unified diff. Auto-runs syntax checks after editing.

Replace mode (default): find a unique string and replace it.
Patch mode: apply V4A multi-file patches for bulk changes.zVEdit mode: 'replace' for targeted find-and-replace, 'patch' for V4A multi-file patches)r   enumr
  rA   z/File path to edit (required for 'replace' mode)zText to find in the file (required for 'replace' mode). Must be unique in the file unless replace_all=true. Include enough surrounding context to ensure uniqueness.z_Replacement text (required for 'replace' mode). Can be empty string to delete the matched text.booleanzLReplace all occurrences instead of requiring a unique match (default: false))r   r
  rA   zV4A format patch content (required for 'patch' mode). Format:
*** Begin Patch
*** Update File: path/to/file
@@ context hint @@
 context line
-removed line
+added line
*** End Patch)r   r&   r   r   r   r   search_filesu  Search file contents or find files by name. Use this instead of grep/rg/find/ls in terminal. Ripgrep-backed, faster than shell equivalents.

Content search (target='content'): Regex search inside files. Output modes: full matches with line numbers, file paths only, or match counts.

File search (target='files'): Find files by glob pattern (e.g., '*.py', '*config*'). Also use this instead of ls — results sorted by modification time.zPRegex pattern for content search, or glob pattern (e.g., '*.py') for file searchfileszK'content' searches inside file contents, 'files' searches for files by namezCDirectory or file to search in (default: current working directory)zOFilter files by pattern in grep mode (e.g., '*.py' to only search Python files)z1Maximum number of results to return (default: 50)z0Skip first N results for pagination (default: 0))r   
files_onlyr   zOutput format for grep mode: 'content' shows matching lines with line numbers, 'files_only' lists file paths, 'count' shows match counts per filezDNumber of context lines before and after each match (grep mode only))r   r   r&   r   r   r   r   r   c                     |                     d          pd}t          |                      dd          |                      dd          |                      dd          |	          S )
NrB   rA   r&   rV   r   rZ   r   r   )r&   r   r   rB   )r   r   argskwtids      r   _handle_read_filer    s_    
&&


(yCtxx33DHHXq<Q<QY]YaYabiknYoYoy|}}}}r-   c                     |                     d          pd}t          |                      dd          |                      dd          |          S )NrB   rA   r&   rV   r   )r&   r   rB   )r   r   r  s      r   _handle_write_filer    sK    
&&


(yC 4 4dhhyRT>U>U_bccccr-   c           
      D   |                     d          pd}t          |                      dd          |                      d          |                      d          |                      d          |                      dd	          |                      d
          |          S )NrB   rA   r   r   r&   r   r   r   Fr   )r   r&   r   r   r   r   rB   )r   r   r  s      r   _handle_patchr   	  s    
&&


(yCXXfi((txx/?/?88L))dhh|6L6LHH]E22$((7:K:KUXZ Z Z Zr-   c                    |                     d          pd}ddd}|                      dd          }|                     ||          }t          |                      dd          ||                      d	d
          |                      d          |                      dd          |                      dd          |                      dd          |                      dd          |	  	        S )NrB   rA   r   r  )grepfindr   r   rV   r&   r   r   r   r   r   r   r   r   )	r   r   r&   r   r   r   r   r   rB   )r   r  )r  r  r  
target_map
raw_targetr   s         r   _handle_search_filesr&    s    
&&


(yC#W55J(I..J^^J
33FB''TXXfc=R=R((;''txx/D/DTXXV^`aMbMbHH]I66TU@V@V`ce e e er-   fileu   📖inf)r  toolsetschemahandlercheck_fnemojimax_result_size_charsu   ✍️u   🔧u   🔎)rA   )N)rZ   r   rA   )r   NNNFNrA   )r   r   Nr   r   r   r   rA   )C__doc__r<   r   loggingr%   rw   pathlibr   tools.binary_extensionsr   tools.file_operationsr   agent.redactr   	getLoggerr   ry   EACCESEPERMEROFSr=   r   r   r   __annotations__r   r   	frozensetr(   r   boolr,   r3   r4   r8   r   r>   rx   ru   r?   dictr   r@   r   r   r   r   r   r   r   r   r   r  tools.registryr  r   r  READ_FILE_SCHEMAWRITE_FILE_SCHEMAPATCH_SCHEMASEARCH_FILES_SCHEMAr  r  r   r&  registerr    r-   r   <module>rD     sU   < < <    				           8 8 8 8 8 8 5 5 5 5 5 5 . . . . . .		8	$	$  ,U[A  " %) d
 ) ) )"S " " " "0 !  "	 	# 	# 	# 	 	      *  12DE C C$J    &i D      !!   " $Y^%% t   v v3 v/B v v v vr$ $# $ $ $ $g" g" g"c g"c g"# g"^a g" g" g" g"X/ /c / / / /,) )C ) ) ) ) RS R3 R4 R R R R$C # #*    >" "# " "c "# " " " "0 KOOS'6" 6"S 6"C 6"C 6"6"486"IL6"6",/6" 6" 6" 6"r DGFG=>(A" A" A"c A"S A"A".1A"@CA" A"7:A" A" .1A" A" A" A"R 0 / / / / / / /% % %  c%6pqq(9t  BC  PQ  R  R'8s  AD  QU  V  V
 

 H     p%  7P  Q  Q (9`aa
 
 Y'     B%	7/C  Um  zC  D  D%6ghh#+  =c  d  d#+  =^  _  _$-  ?M  Z_  `  `&  8u  v  v
 
 H  $  O (  :L  M  M')W1E  Wd  qz  {  {%6{  IL  M  M"*  <M  N  N'8kxz{{(9kxyzz$,6X6X6X  j}  JS  T  T )  ;A  NO  P  P	
 	
 K   (~ ~ ~
d d d
Z Z Ze e e  {F;KUf  rB  JP  hm  hm  ns  ht  ht  u  u  u  u  |V<MWi  uE  MU  mt  u  u  u  u  w|]eu  ~D  \c  d  d  d  d  ~v>Q[o  {K  SY  qx  y  y  y  y  y  yr-   