Skip to content

fix(web): honor plugin-registered search providers in availability gate - #31887

Closed
hclsys wants to merge 1 commit into
NousResearch:mainfrom
hclsys:fix/web-api-key-plugin-providers-31873
Closed

hclsys wants to merge 1 commit into
NousResearch:mainfrom
hclsys:fix/web-api-key-plugin-providers-31873

Conversation

@hclsys

@hclsys hclsys commented May 25, 2026

Copy link
Copy Markdown

Fixes #31873.

Summary

check_web_api_key() only knew the hardcoded built-in backends, so a third-party web search plugin — registered via PluginContext.register_web_search_provider() (e.g. a Kagi provider keyed on KAGI_API_KEY) — was silently disabled: web_search/web_extract were filtered out of the tool registry because the availability gate returned False, even though the plugin registered successfully and its is_available() returns True.

After the built-in checks, this now consults agent.web_search_registry.get_active_search_provider() and returns True when a registered provider is available. The registry already backs the actual web_search dispatch in this module (it's imported at tools/web_tools.py:806), so the gate now matches real runtime availability.

Pre-implement audit

  • Existing-helper check: reused agent.web_search_registry.get_active_search_provider (already imported elsewhere in web_tools.py for dispatch) — no new registry/lookup logic.
  • Shared-helper caller check: check_web_api_key is a tool-availability check_fn; the change only widens False → True when a provider is genuinely available, so no caller is regressed. Built-in path unchanged.
  • Broader-fix rival scan: no competing PR for [Bug]: check_web_api_key() hardcodes built-in backends — third-party web search plugins silently disabled #31873.
  • Registry import/availability failures are caught and logged at debug so the gate can never hard-fail.

Real-behavior proof

$ python -c "<backend=kagi plugin, no built-in keys>"
backend=kagi (plugin), no builtin keys -> check_web_api_key(): True
PROOF: third-party web plugin no longer gated off
nothing available -> False

Test plan

uv sync --extra dev
.venv/bin/python -m pytest tests/tools/test_web_api_key_plugin_providers.py tests/tools/test_web_tools_config.py -q
# 54 passed

New tests/tools/test_web_api_key_plugin_providers.py: available plugin → True; no plugin → False; plugin present but unavailable → False; registry exception → False (no crash); built-in backend still short-circuits to True.

check_web_api_key() only recognized the hardcoded built-in backends, so a
third-party web search plugin (registered via
PluginContext.register_web_search_provider, e.g. a Kagi provider keyed on
KAGI_API_KEY) was silently disabled: the web_search/web_extract tools were
filtered out of the registry because the availability check returned False
even though the plugin provider registered successfully and reports
is_available() == True.

After the built-in checks, consult agent.web_search_registry via
get_active_search_provider(); return True when a registered provider is
available. Registry import/availability failures are swallowed so the gate
can never hard-fail. Built-in backend behavior is unchanged.

Fixes NousResearch#31873
@alt-glitch alt-glitch added type/bug Something isn't working P3 Low — cosmetic, nice to have comp/tools Tool registry, model_tools, toolsets comp/plugins Plugin system and bundled plugins tool/web Web search and extraction labels May 25, 2026
@hadsie

hadsie commented Jun 6, 2026

Copy link
Copy Markdown

Thanks for posting this. It looks like there's a second half to it that's also needed because the dispatch is routing to the wrong provider.

web_search_tool selects via _get_search_backend() => _get_backend(), which only knows the hardcoded built-ins. So web.backend: kagi falls through to the firecrawl default, and since the firecrawl provider is registered and supports_search(), the existing get_active_search_provider() fallback never fires. firecrawl is called instead of Kagi.

Something like this will solve the issue:

diff --git a/tools/web_tools.py b/tools/web_tools.py
index e46841540..8e331c48e 100644
--- a/tools/web_tools.py
+++ b/tools/web_tools.py
@@ -142,6 +142,14 @@ def _get_backend() -> str:
     configured = (_load_web_config().get("backend") or "").lower().strip()
     if configured in {"parallel", "firecrawl", "tavily", "exa", "searxng", "brave-free", "ddgs", "xai"}:
         return configured
+    if configured:
+        try:
+            from agent.web_search_registry import get_provider
+
+            if get_provider(configured) is not None:
+                return configured
+        except Exception as exc:
+            logger.debug("web_search_registry backend lookup failed: %s", exc)

     # Fallback for manual / legacy config — pick the highest-priority
     # available backend. Firecrawl also counts as available when the managed

I've tested it against my Kagi plugin and it's working well with this fix. Additionally those hardcoded backends should probably be replaced by your _BUILTIN_BACKENDS as well.

EDIT:
Actually, here backends includes xai which is missing from the check_web_api_key() function, so it can't be re-used as-is.

@kshitijk4poor

Copy link
Copy Markdown
Contributor

Superseded by #57779, which fixes this same bug class (plugin-registered web providers invisible to the tool-availability gate) as a single chokepoint in _is_backend_available() on current main — cascading to _get_backend(), _get_capability_backend(), and check_web_api_key().

Your PR targeted the same gate and informed the approach — thanks for the contribution, credited in the merged PR body. Closing as superseded. #57779

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/plugins Plugin system and bundled plugins comp/tools Tool registry, model_tools, toolsets P3 Low — cosmetic, nice to have tool/web Web search and extraction type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: check_web_api_key() hardcodes built-in backends — third-party web search plugins silently disabled

4 participants