@@ -114,7 +114,7 @@ def json_schema(self) -> dict:
114114 return {
115115 "name" : "find_text" ,
116116 "description" : f"""\
117- Tool to find text in a file using a pattern based on the Unix shell style.
117+ Tool to find text in a file or files in a directory using a pattern based on the Unix shell style.
118118The current working directory is always { self .__working_dir } .
119119The path provided should either be absolute or relative to the current working directory.
120120
@@ -124,10 +124,6 @@ def json_schema(self) -> dict:
124124 "input_schema" : {
125125 "type" : "object" ,
126126 "properties" : {
127- "path" : {
128- "description" : "The path to the file to find text in." ,
129- "type" : "string" ,
130- },
131127 "pattern" : {
132128 "description" : """\
133129 The Unix shell style pattern to match files using.
@@ -141,6 +137,14 @@ def json_schema(self) -> dict:
141137Example:
142138* '*macs' will match the file '.emacs'
143139* '*.py' will match all files with the '.py' extension
140+ """ ,
141+ "type" : "string" ,
142+ },
143+ "path" : {
144+ "description" : """\
145+ The path to the file to find text in.
146+ If not given, will search all file content in the current working directory.
147+ If the path is a directory, will search all file content in the directory.
144148""" ,
145149 "type" : "string" ,
146150 },
@@ -149,22 +153,22 @@ def json_schema(self) -> dict:
149153 "type" : "boolean" ,
150154 },
151155 },
152- "required" : ["path" , " pattern" ],
156+ "required" : ["pattern" ],
153157 },
154158 }
155159
156160 def execute (
157- self ,
158- path : Optional [Path ] = None ,
159- pattern : Optional [str ] = None ,
160- is_case_sensitive : bool = False ,
161+ self ,
162+ pattern : Optional [str ] = None ,
163+ path : Optional [Path ] = None ,
164+ is_case_sensitive : bool = False ,
161165 ) -> str :
162- if path is None :
163- raise ValueError ("Path argument is required!" )
164-
165166 if pattern is None :
166167 raise ValueError ("pattern argument is required!" )
167168
169+ if path is None :
170+ path = Path (self .__working_dir )
171+
168172 matcher = fnmatch .fnmatch
169173 if is_case_sensitive :
170174 matcher = fnmatch .fnmatchcase
@@ -173,15 +177,34 @@ def execute(
173177 if not path .is_relative_to (self .__working_dir ):
174178 raise ValueError ("Path must be relative to working dir" )
175179
176- matches = []
177- with path .open ("r" ) as f :
178- for i , line in enumerate (f .readlines ()):
179- if not matcher (line , pattern ):
180- continue
180+ if path .is_file ():
181+ paths = [path ]
182+ else :
183+ paths = [p for p in path .iterdir () if p .is_file ()]
184+
185+ from collections import defaultdict
186+ file_matches = defaultdict (list )
187+ for path in paths :
188+ with path .open ("r" ) as f :
189+ for i , line in enumerate (f .readlines ()):
190+ if not matcher (line , pattern ):
191+ continue
192+
193+ content = f"Line { i + 1 } : { line } "
194+ if len (line ) > self .__CHAR_LIMIT :
195+ content = f"Line { i + 1 } : { self .__CHAR_LIMIT_TEXT } "
196+
197+ file_matches [str (path )].append (content )
198+
199+ total_file_matches = ""
200+ for path_str , matches in file_matches .items ():
201+ total_file_matches += f"\n Pattern matches found in '{ path } ':\n " + "\n " .join (matches )
202+
203+ if len (total_file_matches ) <= 5000 :
204+ return total_file_matches
181205
182- content = f"Line { i + 1 } : { line } "
183- if len (line ) > self .__CHAR_LIMIT :
184- content = f"Line { i + 1 } : { self .__CHAR_LIMIT_TEXT } "
206+ total_file_matches = ""
207+ for path_str , matches in file_matches .items ():
208+ total_file_matches += f"\n { len (matches )} Pattern matches found in '{ path } ': <TRUNCATED>\n "
209+ return total_file_matches
185210
186- matches .append (content )
187- return f"Pattern matches found in '{ path } ':\n " + "\n " .join (matches )
0 commit comments