test(web_tools): regression for plugin-registered provider availability
A plugin-registered WebSearchProvider with no built-in provider credentials must light up web_search / web_extract and be discoverable by the backend selectors. Covers check_web_api_key(), _get_backend(), _is_backend_available() registry delegation, per-capability extract selection (#32698), and that the web_search / web_extract tool registry entries are not filtered out. Tests contributed by @m0n5t3r (PR #28652, issue #28651).
This commit is contained in:
parent
0a9d42ce40
commit
e4105a2ffd
1 changed files with 119 additions and 0 deletions
|
|
@ -668,3 +668,122 @@ def test_web_requires_env_includes_exa_key():
|
|||
from tools.web_tools import _web_requires_env
|
||||
|
||||
assert "EXA_API_KEY" in _web_requires_env()
|
||||
|
||||
|
||||
class TestNonBuiltinProviderAvailability:
|
||||
"""Regression: a plugin-registered WebSearchProvider with no built-in
|
||||
provider credentials must still light up web_search / web_extract tools.
|
||||
|
||||
The web_tools availability gate delegates non-legacy backend names to the
|
||||
web_search_registry's provider ``is_available()``. This class verifies
|
||||
that a custom (non-built-in) provider discovered via the registry is
|
||||
sufficient to make check_web_api_key() return True, _get_backend() return
|
||||
the custom name, the per-capability selection honor it (issue #32698), and
|
||||
the tool registry entries remain active.
|
||||
|
||||
Original tests contributed by @m0n5t3r (PR #28652 / issue #28651).
|
||||
"""
|
||||
|
||||
# All env vars that could make a built-in provider available.
|
||||
_WEB_ENV_KEYS = (
|
||||
"EXA_API_KEY",
|
||||
"PARALLEL_API_KEY",
|
||||
"FIRECRAWL_API_KEY",
|
||||
"FIRECRAWL_API_URL",
|
||||
"FIRECRAWL_GATEWAY_URL",
|
||||
"TOOL_GATEWAY_DOMAIN",
|
||||
"TOOL_GATEWAY_SCHEME",
|
||||
"TOOL_GATEWAY_USER_TOKEN",
|
||||
"TAVILY_API_KEY",
|
||||
"SEARXNG_URL",
|
||||
"BRAVE_SEARCH_API_KEY",
|
||||
"XAI_API_KEY",
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _create_fake_provider(*, search=True, extract=True):
|
||||
"""Dynamically create a WebSearchProvider subclass.
|
||||
|
||||
Uses a local class definition (not a nested class) to avoid
|
||||
Python 3.13 __bases__ deallocator issue with nested class
|
||||
reassignment.
|
||||
"""
|
||||
from agent.web_search_provider import WebSearchProvider
|
||||
|
||||
class FakePluginProvider(WebSearchProvider):
|
||||
@property
|
||||
def name(self):
|
||||
return "fake-plugin-prov"
|
||||
|
||||
def is_available(self):
|
||||
return True
|
||||
|
||||
def supports_search(self):
|
||||
return search
|
||||
|
||||
def supports_extract(self):
|
||||
return extract
|
||||
|
||||
return FakePluginProvider()
|
||||
|
||||
def setup_method(self):
|
||||
"""Strip all built-in web provider env vars and reset the registry."""
|
||||
for key in self._WEB_ENV_KEYS:
|
||||
os.environ.pop(key, None)
|
||||
from agent.web_search_registry import _reset_for_tests, register_provider
|
||||
_reset_for_tests()
|
||||
register_provider(self._create_fake_provider())
|
||||
|
||||
def teardown_method(self):
|
||||
"""Reset the registry and restore env after each test."""
|
||||
from agent.web_search_registry import _reset_for_tests
|
||||
_reset_for_tests()
|
||||
for key in self._WEB_ENV_KEYS:
|
||||
os.environ.pop(key, None)
|
||||
|
||||
def test_check_web_api_key_returns_true_for_custom_provider(self):
|
||||
"""With only a custom provider registered (no built-in creds),
|
||||
check_web_api_key() must return True."""
|
||||
with patch("tools.web_tools._ddgs_package_importable", return_value=False), \
|
||||
patch("tools.web_tools._peek_nous_access_token", return_value=None):
|
||||
from tools.web_tools import check_web_api_key
|
||||
assert check_web_api_key() is True
|
||||
|
||||
def test_get_backend_discovers_custom_provider(self):
|
||||
"""_get_backend() must return the custom provider name when it's
|
||||
the only available provider."""
|
||||
with patch("tools.web_tools._ddgs_package_importable", return_value=False), \
|
||||
patch("tools.web_tools._peek_nous_access_token", return_value=None):
|
||||
from tools.web_tools import _get_backend
|
||||
assert _get_backend() == "fake-plugin-prov"
|
||||
|
||||
def test_is_backend_available_delegates_to_registry(self):
|
||||
"""_is_backend_available() must consult the registry for a
|
||||
non-legacy backend name."""
|
||||
from tools.web_tools import _is_backend_available
|
||||
assert _is_backend_available("fake-plugin-prov") is True
|
||||
# Unknown, unregistered name -> False (no legacy probe matches).
|
||||
assert _is_backend_available("totally-unknown-backend") is False
|
||||
|
||||
def test_capability_backend_honors_custom_extract_provider(self):
|
||||
"""Per-capability selection (_get_extract_backend) must resolve the
|
||||
custom provider when configured, instead of dead-ending — issue #32698."""
|
||||
with patch("tools.web_tools._ddgs_package_importable", return_value=False), \
|
||||
patch("tools.web_tools._peek_nous_access_token", return_value=None), \
|
||||
patch("tools.web_tools._load_web_config",
|
||||
return_value={"extract_backend": "fake-plugin-prov"}):
|
||||
from tools.web_tools import _get_extract_backend
|
||||
assert _get_extract_backend() == "fake-plugin-prov"
|
||||
|
||||
def test_tool_registry_entries_not_filtered_out(self):
|
||||
"""web_search and web_extract tool entries must remain in the
|
||||
registry when only a custom provider is available."""
|
||||
with patch("tools.web_tools._ddgs_package_importable", return_value=False), \
|
||||
patch("tools.web_tools._peek_nous_access_token", return_value=None):
|
||||
import tools.web_tools
|
||||
web_search_entry = tools.web_tools.registry.get_entry("web_search")
|
||||
web_extract_entry = tools.web_tools.registry.get_entry("web_extract")
|
||||
assert web_search_entry is not None, \
|
||||
"web_search tool was filtered out despite custom provider being available"
|
||||
assert web_extract_entry is not None, \
|
||||
"web_extract tool was filtered out despite custom provider being available"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue