diff --git a/src/agent_tools.py b/src/agent_tools.py index 987501d..ff87051 100644 --- a/src/agent_tools.py +++ b/src/agent_tools.py @@ -2169,10 +2169,15 @@ print("\n".join(matches) if matches else "(no matches)") if result.exit_code != 0: raise ToolExecutionError(result.stdout.strip() or 'remote glob_search failed') return result.stdout.strip() or '(no matches)' + root_resolved = context.root.resolve() + if Path(pattern).is_absolute(): + try: + pattern = str(Path(pattern).resolve().relative_to(root_resolved)) + except ValueError: + return '(no matches)' matches = sorted(context.root.glob(pattern)) if not matches: return '(no matches)' - root_resolved = context.root.resolve() validated: list[str] = [] for path in matches: try: diff --git a/tests/test_extended_tools.py b/tests/test_extended_tools.py index 6704f94..8dccf6b 100644 --- a/tests/test_extended_tools.py +++ b/tests/test_extended_tools.py @@ -99,6 +99,45 @@ class ExtendedToolTests(unittest.TestCase): self.assertIn('[line truncated,', result.content) self.assertLess(len(result.content), 1200) + def test_glob_search_accepts_absolute_path_inside_workspace(self) -> None: + registry = default_tool_registry() + with tempfile.TemporaryDirectory() as tmp_dir: + workspace = Path(tmp_dir) + target_dir = workspace / 'output' + target_dir.mkdir() + (target_dir / 'records.jsonl').write_text('{}\n', encoding='utf-8') + context = build_tool_context( + AgentRuntimeConfig(cwd=workspace), + tool_registry=registry, + ) + result = execute_tool( + registry, + 'glob_search', + {'pattern': str(target_dir / '*.jsonl')}, + context, + ) + + self.assertTrue(result.ok) + self.assertIn('output/records.jsonl', result.content) + + def test_glob_search_external_absolute_path_returns_no_matches(self) -> None: + registry = default_tool_registry() + with tempfile.TemporaryDirectory() as workspace_dir, tempfile.TemporaryDirectory() as external_dir: + external = Path(external_dir) / '*.jsonl' + context = build_tool_context( + AgentRuntimeConfig(cwd=Path(workspace_dir)), + tool_registry=registry, + ) + result = execute_tool( + registry, + 'glob_search', + {'pattern': str(external)}, + context, + ) + + self.assertTrue(result.ok) + self.assertEqual(result.content, '(no matches)') + def test_read_file_can_read_explicit_external_path(self) -> None: registry = default_tool_registry() with tempfile.TemporaryDirectory() as workspace_dir, tempfile.TemporaryDirectory() as external_dir: