OpenHands / OpenHands/software-agent-sdk
[Bug]: system grep fallbacks misinterpret extended regular expressions
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 1.1k
- Forks
- 539
- Avg merge
- 1d 19h
- Merged PRs (30d)
- 137
Description
Is there an existing issue for the same bug?
- I have searched existing issues and this is not a duplicate.
Bug Description
When ripgrep is unavailable, GrepExecutor and the SDK terminal-compatibility fallback invoke system grep without -E. They therefore interpret patterns as basic regular expressions, although the same patterns work with the normal ripgrep backend. This silently loses valid matches and can also return the wrong files for escaped literal punctuation. Reproduced against current main at 9c3571a694547734002518bd94b3cb41a187f9b6.
Expected Behavior
The system grep fallbacks should support common extended regular expressions consistently with the ripgrep path:
- Pattern
^(foo|bar)+[0-9]{2}$should findmatching.txtcontainingFooBAR12(the tool searches case-insensitively). - Pattern
^foo\(bar\)\+$should findmatching.txtcontaining the literal textfoo(bar)+, and notother.txtcontainingfoobar.
Full equivalence between all regex dialects is outside this issue's scope.
Actual Behavior
The first pattern returns no matches. The second pattern returns other.txt instead of matching.txt. Neither result is reported as an error. Both production fallback command builders omit the extended-regex flag.
After setting up the base checkout and copying the reproduction script as described below, run this SDK reproduction from the repository root:
.venv/bin/python repro_grep_regex.py
It exits with status 1 and reports:
case=extended expected=[matching.txt] actual=[] is_error=false passed=false
case=escaped expected=[matching.txt] actual=[other.txt] is_error=false passed=false
Steps to Reproduce
- Check out main at 9c3571a694547734002518bd94b3cb41a187f9b6 and run
make buildto install the workspace packages. - Copy the standalone reproduction linked under Minimal Code Sample to
repro_grep_regex.pyin that base checkout. - Run
.venv/bin/python repro_grep_regex.py. System grep must be installed. The script temporarily uses a PATH containing only system grep, so ripgrep is definitely absent; it restores PATH afterward. It uses real files and subprocesses, with no mocked production functions. - Observe two failed cases and exit status 1. Adding
-Eto both system grep fallbacks makes both cases pass; regression tests also exercise the SDK terminal-compatibility path.
Acceptance Criteria
- With ripgrep absent, GrepExecutor finds only matching.txt for both the extended-regex and escaped-literal cases above.
- The SDK terminal-compatibility system grep command supports the same extended-regex syntax.
- Regression tests execute actual system grep and cover the negative files, not only command construction.
- Existing ripgrep behavior, case-insensitive search, result limits, and file filtering remain covered by the existing tests.
Installation Method
Source checkout; make build (uv workspace, editable local packages).
If you selected "Other", please specify
No response
SDK Version
1.47.0; main commit 9c3571a694547734002518bd94b3cb41a187f9b6 (fetched again before reporting).
Version Confirmation
- I have confirmed this bug exists on the LATEST version of OpenHands SDK
Python Version
3.13.13
Model Name (if applicable)
Not applicable; this is a deterministic tool execution bug and requires no LLM.
Operating System
MacOS
Logs and Error Messages
Before the fix:
grep_available=true, rg=null
case=extended expected=[matching.txt] actual=[] is_error=false passed=false
case=escaped expected=[matching.txt] actual=[other.txt] is_error=false passed=false
After adding -E, both actual results are [matching.txt] and both pass.
Recorded evidence: baseline log, fixed log, validation commands and results. The focused grep and compatibility suite passed 85 tests after the fix.
Minimal Code Sample
The complete standalone reproduction is repro_grep_regex.py. Copy that script into the base checkout to reproduce the bug; the linked branch also contains the proposed production fix. The script creates both fixture files, hides ripgrep from PATH, invokes the public GrepAction/GrepExecutor entry point, checks both expected results, restores PATH, and exits nonzero when either case fails.
Screenshots and Additional Context
Affected command builders: openhands-tools/openhands/tools/grep/impl.py and openhands-sdk/openhands/sdk/agent/utils.py. The intended fix is to enable extended regular expressions using the portable grep -E option in both paths. A small tested patch and the evidence linked above are ready for a linked PR. No UI screenshots or model API calls are needed for this reproduction.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with openhands-tools/openhands/tools/grep/impl.py and openhands-sdk/openhands/sdk/agent/utils.py, then run .venv/bin/python repro_grep_regex.py from the repository root with ripgrep unavailable. Add regression coverage using actual system grep for both fixture cases and verify the focused grep and terminal-compatibility suites pass while existing ripgrep behavior remains covered.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python, shell
- Domain
- cli, tooling
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 75/100