From 74d36bbb18fa015ddd8eebe097efb1c28adb70dd Mon Sep 17 00:00:00 2001 From: Giuseppe Cocomazzi Date: Mon, 22 Dec 2025 18:58:49 +0100 Subject: [PATCH 1/2] Added parameter to `grep_files` to return the content of matching lines. --- tools/vfs.py | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/tools/vfs.py b/tools/vfs.py index 55bdea5..ee9d57d 100644 --- a/tools/vfs.py +++ b/tools/vfs.py @@ -261,28 +261,39 @@ class GrepFileSchema(BaseModel): Search for a specific string in the files on the VFS. Returns a list of file names which contain the query somewhere in their contents. Matching file names are output one per line. Empty lines should be ignored. + When invoked with the argument `matching_line_only` set to `True`, returns + a list of pairs of the form `(file_name, matching_line_content)`, i.e. + the file names are paired with the content of the entire line matching the query after the filename. """ search_string: str = Field(description="The query string to search for provided as a python regex. Thus, you must escape any special characters (like [, |, etc.)") + matching_line_only: bool = Field(description="Specify whether the content of the line matching the query should be returned with the filename") @tool(args_schema=GrepFileSchema) def grep_files( state: Annotated[InputType, InjectedState], - search_string: str - ) -> str: + search_string: str, + matching_line_only: bool + ) -> list[tuple[str, str]] | list[str]: comp: re.Pattern try: comp = re.compile(search_string) except Exception: return "Illegal pattern name, check your syntax and try again." - matches: list[str] = [] + matches: list[tuple[str, str]] | list[str] = [] for (k, v) in state["vfs"].items(): if not get_filter(k): continue - if comp.search(v) is not None: - matches.append(k) + + if matching_line_only: + for line in v.splitlines(): + if comp.search(line) is not None: + matches.append((k, line)) + else: + if comp.search(v) is not None: + matches.append(k) if (layer := conf.get("fs_layer", None)) is not None: p = pathlib.Path(layer) @@ -294,11 +305,18 @@ def grep_files( continue if rel_name in state["vfs"]: continue - if not comp.search(f.read_text()): - continue - matches.append(rel_name) - return "\n".join(matches) + content = f.read_text() + if matching_line_only: + for line in content.splitlines(): + if comp.search(line) is not None: + matches.append((rel_name, line)) + else: + if comp.search(content): + matches.append(rel_name) + + return matches + tools: list[BaseTool] = [get_file, list_files, grep_files] if not conf["immutable"]: From b5e8f96b3e6903086891ad96956d46c9d5250359 Mon Sep 17 00:00:00 2001 From: Giuseppe Cocomazzi Date: Mon, 22 Dec 2025 19:44:51 +0100 Subject: [PATCH 2/2] Mypy munging. --- tools/vfs.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tools/vfs.py b/tools/vfs.py index ee9d57d..8c4dc1d 100644 --- a/tools/vfs.py +++ b/tools/vfs.py @@ -262,8 +262,9 @@ class GrepFileSchema(BaseModel): file names which contain the query somewhere in their contents. Matching file names are output one per line. Empty lines should be ignored. When invoked with the argument `matching_line_only` set to `True`, returns - a list of pairs of the form `(file_name, matching_line_content)`, i.e. - the file names are paired with the content of the entire line matching the query after the filename. + pairs of the form `file_name: matching_line_content`, i.e. + the file names are paired with the content of the entire line matching + the query after the filename. """ search_string: str = Field(description="The query string to search for provided as a python regex. Thus, you must escape any special characters (like [, |, etc.)") @@ -274,14 +275,14 @@ def grep_files( state: Annotated[InputType, InjectedState], search_string: str, matching_line_only: bool - ) -> list[tuple[str, str]] | list[str]: + ) -> str: comp: re.Pattern try: comp = re.compile(search_string) except Exception: return "Illegal pattern name, check your syntax and try again." - matches: list[tuple[str, str]] | list[str] = [] + matches: list[str] = [] for (k, v) in state["vfs"].items(): if not get_filter(k): @@ -290,7 +291,7 @@ def grep_files( if matching_line_only: for line in v.splitlines(): if comp.search(line) is not None: - matches.append((k, line)) + matches.append(f"{k}: {line}") else: if comp.search(v) is not None: matches.append(k) @@ -310,13 +311,12 @@ def grep_files( if matching_line_only: for line in content.splitlines(): if comp.search(line) is not None: - matches.append((rel_name, line)) + matches.append(f"{rel_name}: {line}") else: if comp.search(content): matches.append(rel_name) - return matches - + return "\n".join(matches) tools: list[BaseTool] = [get_file, list_files, grep_files] if not conf["immutable"]: