From 79b2694b9a02806592ea5cf6aeaa272a2e9d4028 Mon Sep 17 00:00:00 2001 From: Teknium <127238744+teknium1@users.noreply.github.com> Date: Tue, 31 Mar 2026 03:16:40 -0700 Subject: [PATCH] fix: _allow_private_urls name collision + stale OPENAI_BASE_URL test (#4217) 1. browser_tool.py: _allow_private_urls() used 'global _allow_private_urls' then assigned a bool to it, replacing the function in the module namespace. After first call, subsequent calls hit TypeError: 'bool' object is not callable. Renamed cache variable to _cached_allow_private_urls. 2. test_provider_parity.py: test_custom_endpoint_when_no_nous relied on OPENAI_BASE_URL env var (removed in config refactor). Mock _resolve_custom_runtime directly instead. --- tests/test_provider_parity.py | 9 ++++++++- tools/browser_tool.py | 12 ++++++------ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/tests/test_provider_parity.py b/tests/test_provider_parity.py index b34c9cd70..deb657340 100644 --- a/tests/test_provider_parity.py +++ b/tests/test_provider_parity.py @@ -559,11 +559,18 @@ class TestAuxiliaryClientProviderPriority: assert model == "google/gemini-3-flash-preview" def test_custom_endpoint_when_no_nous(self, monkeypatch): + """Custom endpoint is used when no OpenRouter/Nous keys are available. + + Since the March 2026 config refactor, OPENAI_BASE_URL env var is no + longer consulted — base_url comes from config.yaml via + resolve_runtime_provider. Mock _resolve_custom_runtime directly. + """ monkeypatch.delenv("OPENROUTER_API_KEY", raising=False) - monkeypatch.setenv("OPENAI_BASE_URL", "http://localhost:1234/v1") monkeypatch.setenv("OPENAI_API_KEY", "local-key") from agent.auxiliary_client import get_text_auxiliary_client with patch("agent.auxiliary_client._read_nous_auth", return_value=None), \ + patch("agent.auxiliary_client._resolve_custom_runtime", + return_value=("http://localhost:1234/v1", "local-key")), \ patch("agent.auxiliary_client.OpenAI") as mock: client, model = get_text_auxiliary_client() assert mock.call_args.kwargs["base_url"] == "http://localhost:1234/v1" diff --git a/tools/browser_tool.py b/tools/browser_tool.py index 03aa6106b..1861152e3 100644 --- a/tools/browser_tool.py +++ b/tools/browser_tool.py @@ -238,7 +238,7 @@ _PROVIDER_REGISTRY: Dict[str, type] = { _cached_cloud_provider: Optional[CloudBrowserProvider] = None _cloud_provider_resolved = False _allow_private_urls_resolved = False -_allow_private_urls: Optional[bool] = None +_cached_allow_private_urls: Optional[bool] = None def _get_cloud_provider() -> Optional[CloudBrowserProvider]: @@ -273,12 +273,12 @@ def _allow_private_urls() -> bool: Reads ``config["browser"]["allow_private_urls"]`` once and caches the result for the process lifetime. Defaults to ``False`` (SSRF protection active). """ - global _allow_private_urls, _allow_private_urls_resolved + global _cached_allow_private_urls, _allow_private_urls_resolved if _allow_private_urls_resolved: - return _allow_private_urls + return _cached_allow_private_urls _allow_private_urls_resolved = True - _allow_private_urls = False # safe default + _cached_allow_private_urls = False # safe default try: hermes_home = Path(os.environ.get("HERMES_HOME", Path.home() / ".hermes")) config_path = hermes_home / "config.yaml" @@ -286,10 +286,10 @@ def _allow_private_urls() -> bool: import yaml with open(config_path) as f: cfg = yaml.safe_load(f) or {} - _allow_private_urls = bool(cfg.get("browser", {}).get("allow_private_urls")) + _cached_allow_private_urls = bool(cfg.get("browser", {}).get("allow_private_urls")) except Exception as e: logger.debug("Could not read allow_private_urls from config: %s", e) - return _allow_private_urls + return _cached_allow_private_urls def _socket_safe_tmpdir() -> str: