From 0bbeb7ca9c4ac186365de1e01f94e07332f8e8d7 Mon Sep 17 00:00:00 2001 From: T0mSIlver Date: Sat, 27 Jun 2026 00:42:09 +0000 Subject: [PATCH] fix(grep): make 'content' the explicit default output mode The schema description claimed output_mode defaults to 'files_with_matches', while grep.md said 'content' is the default and the code fell through to ripgrep's content default without applying -n. Reconcile on 'content' (matching grep.md): set it as the explicit default so line numbers apply, fix the schema description, and add a test asserting the default behavior and documentation. --- src/fastcontext/agent/tool/grep.py | 4 ++-- tests/test_grep_default_mode.py | 31 ++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 tests/test_grep_default_mode.py diff --git a/src/fastcontext/agent/tool/grep.py b/src/fastcontext/agent/tool/grep.py index 4ee161f..96fd78a 100644 --- a/src/fastcontext/agent/tool/grep.py +++ b/src/fastcontext/agent/tool/grep.py @@ -26,7 +26,7 @@ class GrepTool(Tool): "output_mode": { "type": "string", "enum": ["content", "files_with_matches", "count"], - "description": 'Output mode: "content" shows matching lines (supports -A/-B/-C context, -n line numbers, head_limit), "files_with_matches" shows file paths (supports head_limit), "count" shows match counts (supports head_limit). Defaults to "files_with_matches".', + "description": 'Output mode: "content" shows matching lines (supports -A/-B/-C context, -n line numbers, head_limit), "files_with_matches" shows file paths (supports head_limit), "count" shows match counts (supports head_limit). Defaults to "content".', }, "-B": { "type": "number", @@ -72,7 +72,7 @@ async def call(self, parameters: str, **kwargs) -> str: pattern = params.get("pattern") path = params.get("path", cwd) glob = params.get("glob") - output_mode = params.get("output_mode") + output_mode = params.get("output_mode", "content") before_context = params.get("-B") after_context = params.get("-A") context = params.get("-C", 3) diff --git a/tests/test_grep_default_mode.py b/tests/test_grep_default_mode.py new file mode 100644 index 0000000..6ecbf8c --- /dev/null +++ b/tests/test_grep_default_mode.py @@ -0,0 +1,31 @@ +import asyncio +import json +import re +import tempfile +from pathlib import Path + +from fastcontext.agent.tool.grep import GrepTool + + +def test_grep_defaults_to_content(): + """With output_mode omitted, Grep must behave as 'content' (matching lines + with line numbers), not as files_with_matches and not as a flag-less rg + call that drops -n.""" + grep = GrepTool() + with tempfile.TemporaryDirectory() as cwd: + (Path(cwd) / "haystack.txt").write_text("alpha\nMATCH here\nbeta\n", encoding="utf-8") + + out = asyncio.run(grep.call(json.dumps({"pattern": "MATCH"}), cwd=cwd)) + lines = out.splitlines() + + # Content mode with -n emits ":" rows for matches. + assert any(re.match(r"\d+:.*MATCH", ln) for ln in lines), f"expected line-numbered match, got: {out!r}" + # files_with_matches would emit only the bare path with no match text. + assert "MATCH here" in out + + +def test_grep_schema_documents_content_default(): + schema = GrepTool().schema() + desc = schema["function"]["parameters"]["properties"]["output_mode"]["description"] + assert 'Defaults to "content"' in desc + assert "files_with_matches" not in desc.split("Defaults to")[1]