Skip to content

fix(web_tools): delegate _is_backend_available to provider registry for plugin backends - #31829

Closed
ngsalmon wants to merge 1 commit into
NousResearch:mainfrom
ngsalmon:fix/plugin-backend-availability
Closed

ngsalmon wants to merge 1 commit into
NousResearch:mainfrom
ngsalmon:fix/plugin-backend-availability

Conversation

@ngsalmon

Copy link
Copy Markdown

Summary

_is_backend_available() in tools/web_tools.py uses a hardcoded switch that only knows about the built-in backends (brave-free, ddgs, xai, etc.). For any other backend name, it returns False. This silently breaks plugin-registered web search/extract backends: even when a plugin correctly registers a provider with agent.web_search_registry, the dispatcher sees is_backend_available == False and falls back to brave-free. From the user's perspective, the plugin is fully loaded ("Plugin 'web-foo' registered web provider: foo" appears in the agent log) but web_extract still routes to the default — confusing to debug.

Fix

When the hardcoded switch doesn't recognize a backend name, fall through to the provider registry and ask its is_available() method. This makes plugins authoritative about their own availability, which matches how the rest of the plugin system already works.

Eleven lines, no new dependencies, no behavior change for any of the built-in backends. The registry import is intentionally local to the function so it doesn't introduce an import-time circular dep, and the try/except is broad on purpose because _is_backend_available runs on every web_search/web_extract dispatch and must never raise.

Repro (before this patch)

  1. Write a plugin under ~/.hermes/plugins/web/<name>/ that calls ctx.register_web_search_provider(MyProvider()) where MyProvider.name == "myname" and MyProvider.supports_extract() == True.
  2. Set web.extract_backend: myname in ~/.hermes/config.yaml.
  3. Restart the gateway. The startup log shows Plugin 'web-myname' registered web provider: myname.
  4. Run web_extract against any URL.

Expected: the plugin handles the extract.
Actual (without patch): falls back to brave-free and returns the Brave search-only error.

After this patch, step 4 correctly routes through the plugin.

Test

Tested locally on a real plugin (web-crawl4ai, a Crawl4AI wrapper) on a Hermes deployment in production use. web.extract_backend: crawl4ai now routes correctly; built-in backends (brave-free, ddgs, xai) behave identically to before.

No new unit tests added because the change is a fall-through path inside a private helper that's only exercised through the existing dispatch tests. Happy to add a focused test if you'd like — point me at the right file and I'll follow up.

Notes for reviewers

  • The from agent.web_search_registry import get_provider is intentionally inside the function. Module-level imports of agent.* from tools/* historically tangle import order on this codebase; the local import keeps things tidy.
  • This is the minimal fix. A larger refactor would lift the hardcoded switch entirely and ask the registry for everything, but that touches the bootstrap path for built-in providers and felt out of scope here.

…or plugin backends

The hardcoded switch in _is_backend_available() only knew about the
built-in backends (brave-free, ddgs, xai, etc.) and returned False for
any other name. Plugin-registered backends like crawl4ai were
properly loaded into agent.web_search_registry but the dispatcher
treated them as unavailable, then silently fell back to brave-free.

Fix: when the hardcoded switch doesn't recognize a backend, ask the
provider registry's own is_available() method. This makes plugins
authoritative about their own availability — which is also the
correct design.

Tested locally: with a 'crawl4ai' plugin registered in
agent.web_search_registry, setting web.extract_backend: crawl4ai in
config.yaml now correctly routes web_extract through the plugin
instead of falling back to brave-free.
@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.

3 participants