diff --git a/nanobot/agent/tools/web.py b/nanobot/agent/tools/web.py index 35c5c3b..89c9a40 100644 --- a/nanobot/agent/tools/web.py +++ b/nanobot/agent/tools/web.py @@ -60,7 +60,7 @@ class WebSearchTool(Tool): def __init__( self, - provider: str = "brave", + provider: str | None = None, api_key: str | None = None, base_url: str | None = None, max_results: int = 5, @@ -87,7 +87,11 @@ class WebSearchTool(Tool): @property def base_url(self) -> str: """Resolve SearXNG base URL at call time so env/config changes are picked up.""" - return (self._init_base_url or os.environ.get("SEARXNG_BASE_URL", "")).strip() + return ( + self._init_base_url + or os.environ.get("WEB_SEARCH_BASE_URL", "") + or os.environ.get("SEARXNG_BASE_URL", "") + ).strip() async def execute(self, query: str, count: int | None = None, **kwargs: Any) -> str: provider = self.provider @@ -134,7 +138,7 @@ class WebSearchTool(Tool): if not self.base_url: return ( "Error: SearXNG base URL not configured. Set tools.web.search.baseUrl " - 'in ~/.nanobot/config.json (or export SEARXNG_BASE_URL), e.g. "http://localhost:8080".' + 'in ~/.nanobot/config.json (or export WEB_SEARCH_BASE_URL), e.g. "http://localhost:8080".' ) is_valid, error_msg = _validate_url(self.base_url) diff --git a/tests/test_web_tools.py b/tests/test_web_tools.py index 2d7c8cd..5c48e20 100644 --- a/tests/test_web_tools.py +++ b/tests/test_web_tools.py @@ -148,3 +148,57 @@ def test_web_search_config_accepts_searxng_fields() -> None: assert config.tools.web.search.provider == "searxng" assert config.tools.web.search.base_url == "http://localhost:8080" assert config.tools.web.search.max_results == 7 + + +@pytest.mark.asyncio +async def test_web_search_tool_uses_env_provider_and_base_url( + monkeypatch: pytest.MonkeyPatch, +) -> None: + calls: list[dict[str, Any]] = [] + payload = { + "results": [ + { + "title": "Nanobot Env", + "url": "https://example.com/env", + "content": "Resolved from environment variables.", + } + ] + } + + class _FakeAsyncClient: + def __init__(self, *args: Any, **kwargs: Any) -> None: + self.proxy = kwargs.get("proxy") + + async def __aenter__(self) -> "_FakeAsyncClient": + return self + + async def __aexit__(self, exc_type, exc, tb) -> None: + return None + + async def get( + self, + url: str, + *, + params: dict[str, Any] | None = None, + headers: dict[str, str] | None = None, + timeout: float | None = None, + ) -> _FakeResponse: + calls.append({"url": url, "params": params, "headers": headers, "timeout": timeout}) + return _FakeResponse(payload) + + monkeypatch.setattr(web_module.httpx, "AsyncClient", _FakeAsyncClient) + monkeypatch.setenv("WEB_SEARCH_PROVIDER", "searxng") + monkeypatch.setenv("WEB_SEARCH_BASE_URL", "http://localhost:9090") + + tool = WebSearchTool() + result = await tool.execute(query="nanobot", count=2) + + assert "Nanobot Env" in result + assert calls == [ + { + "url": "http://localhost:9090/search", + "params": {"q": "nanobot", "format": "json"}, + "headers": {"Accept": "application/json"}, + "timeout": 10.0, + } + ]