From 1c7ceace238b701e73d5fb1b91e23493db683307 Mon Sep 17 00:00:00 2001 From: robert Date: Wed, 3 Jun 2026 21:49:08 -0300 Subject: [PATCH] Compat fix workspace grep globs --- agent_builder/builder.py | 34 ++++++++++++++++++++++++-- tests/test_builder_prompt.py | 47 ++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 2 deletions(-) diff --git a/agent_builder/builder.py b/agent_builder/builder.py index 22fa4df..f9aee55 100644 --- a/agent_builder/builder.py +++ b/agent_builder/builder.py @@ -368,7 +368,7 @@ def _build_project_backend(ctx: BuilderContext, *, settings: Settings) -> Any | except Exception: # noqa: BLE001 return _with_builder_skills(StateBackend()) return _with_builder_skills( - WorkspaceBackend(ctx.workspace), + _workspace_backend_with_grep_compat(WorkspaceBackend, ctx.workspace), artifacts_root=f"/{prefix}/{_BUILDER_ARTIFACT_DIR}", ) try: @@ -404,11 +404,41 @@ def _build_project_backend(ctx: BuilderContext, *, settings: Settings) -> Any | ) ) return _with_builder_skills( - WorkspaceBackend(workspace), + _workspace_backend_with_grep_compat(WorkspaceBackend, workspace), artifacts_root=f"/{prefix}/{_BUILDER_ARTIFACT_DIR}", ) +def _workspace_backend_with_grep_compat(workspace_backend_cls: Any, workspace: Any) -> Any: + """Patch older a2a-pack WorkspaceBackend grep glob behavior. + + Older ``WorkspaceBackend.grep`` only matched ``glob`` against the full + workspace key. DeepAgents commonly calls ``grep(path="/agents/name", + glob="agent.py")``, which should match ``agents/name/agent.py``. + """ + + class BuilderWorkspaceBackend(workspace_backend_cls): # type: ignore[misc, valid-type] + def grep( + self, + pattern: str, + path: str | None = None, + glob: str | None = None, + ) -> Any: + result = super().grep(pattern, path=path, glob=glob) + if not glob or not path or getattr(result, "matches", None): + return result + norm = getattr(self, "_norm", None) + base = norm(path) if callable(norm) else path.strip("/") + if not base: + return result + scoped_glob = f"{base.rstrip('/')}/{glob.lstrip('/')}" + if scoped_glob == glob: + return result + return super().grep(pattern, path=path, glob=scoped_glob) + + return BuilderWorkspaceBackend(workspace) + + def _with_builder_skills(default_backend: Any, *, artifacts_root: str = "/") -> Any: skill_store = InMemoryStore() for path, content in _builder_skill_files().items(): diff --git a/tests/test_builder_prompt.py b/tests/test_builder_prompt.py index 8bbee11..c537c8d 100644 --- a/tests/test_builder_prompt.py +++ b/tests/test_builder_prompt.py @@ -10,6 +10,7 @@ from agent_builder.builder import ( _build_project_backend, _builder_skill_files, _with_builder_skills, + _workspace_backend_with_grep_compat, ) from agent_builder.config import Settings from agent_builder.tools import A2A_PACK_MIN_VERSION, _strip_unsupported_pricing_fields @@ -209,3 +210,49 @@ inline = Pricing(price_per_call_usd=0.01, compute={"runtime_seconds": 600}, tota backend.artifacts_root, "/agents/svgwrite-agent/.agent-builder", ) + + def test_project_backend_grep_compat_qualifies_relative_glob(self) -> None: + class _LegacyBackend: + def __init__(self, workspace: object) -> None: + self.workspace = workspace + self.calls: list[tuple[str | None, str | None]] = [] + + def _norm(self, path: str | None) -> str: + return (path or "").strip("/") + + def grep( + self, + pattern: str, + path: str | None = None, + glob: str | None = None, + ): + self.calls.append((path, glob)) + matches = ( + [{"path": "/agents/github-repo-inspector/agent.py"}] + if glob == "agents/github-repo-inspector/agent.py" + else [] + ) + return type("GrepResult", (), {"error": None, "matches": matches})() + + backend = _workspace_backend_with_grep_compat(_LegacyBackend, object()) + + result = backend.grep( + "_github_client", + path="/agents/github-repo-inspector", + glob="agent.py", + ) + + self.assertEqual( + backend.calls, + [ + ("/agents/github-repo-inspector", "agent.py"), + ( + "/agents/github-repo-inspector", + "agents/github-repo-inspector/agent.py", + ), + ], + ) + self.assertEqual( + result.matches, + [{"path": "/agents/github-repo-inspector/agent.py"}], + )