Treat grep no matches as nonfatal

This commit is contained in:
mirivlad 2026-05-11 00:27:44 +08:00
parent fcee065231
commit 717e931a5e
4 changed files with 31 additions and 7 deletions

View File

@ -24,10 +24,12 @@ class Tool(BaseTool):
stdin_data=str(stdin_secret) if stdin_secret is not None else None,
)
output = completed.stdout if completed.returncode == 0 else completed.stderr or completed.stdout
grep_no_matches = "grep" in command and completed.returncode == 1 and not completed.stderr
ok = completed.returncode == 0 or grep_no_matches
return ToolResult(
tool=self.name,
ok=completed.returncode == 0,
ok=ok,
output=output,
error=None if completed.returncode == 0 else f"Command failed with exit code {completed.returncode}",
metadata={"exit_code": completed.returncode},
error=None if ok else f"Command failed with exit code {completed.returncode}",
metadata={"exit_code": completed.returncode, "no_matches": grep_no_matches},
)

View File

@ -29,6 +29,8 @@ class ShellExecTool(BaseTool):
)
output = completed.stdout if completed.returncode == 0 else completed.stderr or completed.stdout
error_output = completed.stderr or completed.stdout
grep_no_matches = "grep" in command and completed.returncode == 1 and not completed.stderr
ok = completed.returncode == 0 or grep_no_matches
is_sudo_error = (
completed.returncode != 0 and
@ -40,8 +42,8 @@ class ShellExecTool(BaseTool):
return ToolResult(
tool=self.name,
ok=completed.returncode == 0,
ok=ok,
output=output,
error=None if completed.returncode == 0 else f"Command failed with exit code {completed.returncode}",
metadata={"exit_code": completed.returncode, "needs_sudo": is_sudo_error},
error=None if ok else f"Command failed with exit code {completed.returncode}",
metadata={"exit_code": completed.returncode, "needs_sudo": is_sudo_error, "no_matches": grep_no_matches},
)

View File

@ -14,6 +14,9 @@ INSTRUCTIONS:
4. If the user asks about the current local machine, filesystem, processes,
packages, logs, runtime state, or anything that must be observed rather than
answered from general knowledge, use an appropriate tool.
5. For exploratory tasks, prefer one robust inspection command over many brittle
dependent checks. Missing optional files should be treated as information, not
as a fatal failure.
MODE: {mode_hint}
- If mode is "execution": create a plan with TOOL STEPS (shell_exec, file_write, etc)

View File

@ -112,6 +112,23 @@ def test_shell_exec_allows_safe_command(tmp_path: Path) -> None:
assert str(tmp_path) in result["result"]["output"]
def test_shell_exec_treats_grep_no_matches_as_information(tmp_path: Path) -> None:
_write_config_tree(tmp_path)
controller = RuntimeController(base_dir=tmp_path)
result = controller.handle_task(
UserTask(
input="run grep with no matches",
context={
"requested_tool": "shell_exec",
"tool_args": {"command": "printf 'abc\\n' | grep definitely_missing"},
},
)
)
assert result["status"] == "completed"
assert result["result"]["metadata"]["exit_code"] == 1
assert result["result"]["metadata"]["no_matches"] is True
def test_permission_resolution_can_resume_task(tmp_path: Path) -> None:
_write_config_tree(tmp_path)
controller = RuntimeController(base_dir=tmp_path)