Skip to content

web_search reports 'no provider available' from first-class assistant tools when capability + runtime succeed #77073

@joeykrug

Description

@joeykrug

Symptom

The first-class assistant web_search tool fails with:

web_search is disabled or no provider is available

…even though the same machine resolves the configured Brave plugin successfully via:

  • openclaw capability web search
  • Direct runtime provider execution (the gateway's web search runtime path)

Affected Surface

  • src/agents/tools/web-search.tscreateWebSearchTool with lateBindRuntimeConfig: true
  • src/plugins/web-provider-runtime-shared.tsresolvePluginWebProviders / resolveRuntimeWebProviders

The bug only reproduces when the assistant tool is built with lateBindRuntimeConfig: true from src/agents/openclaw-tools.ts and the agent context does not share the gateway's in-process runtime snapshot (e.g. embedded subagents, scoped runtime plugin loads).

Probable Cause

Two interacting regressions:

  1. The active gateway plugin registry is intentionally scoped to channels, memory, harnesses, and sidecars on startup. It can be otherwise compatible with the active OpenClaw config while contributing zero web-provider entries (e.g. when Brave/web providers live in a separately-loaded plugin set). The current resolver treats that empty active-registry result as authoritative and short-circuits to [] instead of falling back to a scoped provider plugin load. First-class tools then see no providers.

  2. When the late-bound createWebSearchTool execute lambda runs in an agent context where neither getActiveRuntimeWebToolsMetadata() nor getActiveSecretsRuntimeSnapshot() is populated, the local runtimeWebSearch and config both resolve to undefined. With no provider id and no config, preferRuntimeProviders cannot route to the configured plugin, and the tool ultimately reports "no provider available". The configured provider id from config.tools.web.search.provider is never consulted.

Proposed Fix Scope

Source-only fixes in src/agents/tools/web-search.ts and src/plugins/web-provider-runtime-shared.ts:

  • Late-bind config / runtime fallback in createWebSearchTool:
    • runtimeWebSearch = getActiveRuntimeWebToolsMetadata()?.search ?? options?.runtimeWebSearch
    • config = getActiveSecretsRuntimeSnapshot()?.config ?? options?.config
    • Derive configuredProviderId from config.tools.web.search.provider.
    • Compose providerSelectionId = runtimeProviderId || configuredProviderId and use that for preferRuntimeProviders, so an explicit Brave/Perplexity selection still resolves the configured plugin when no runtime provider id is bound.
  • Web provider runtime registry fallback:
    • When the compatible/runtime active plugin registry maps to zero web providers, fall through to a scoped provider plugin load instead of returning [].
    • Preserve explicit onlyPluginIds: [] semantics: an explicitly empty scope still returns [].

Targeted regression tests:

  • src/plugins/web-provider-runtime-shared.test.ts — fall-through under empty active registry, no fall-through under explicit empty scope, both for resolvePluginWebProviders and resolveRuntimeWebProviders.
  • src/agents/tools/web-search.late-bind.test.ts (new) — ?? fallbacks for runtime metadata and config; configured-provider-only routing; no preferRuntimeProviders when nothing is selected; bundled-manifest owner takes priority over runtime preference.

A PR implementing these fixes will follow.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions