Skip to content

fix(tavily): keep web_search contract executable#91110

Merged
vincentkoc merged 2 commits into
openclaw:mainfrom
extrasmall0:fix/tavily-web-search-registration
Jun 13, 2026
Merged

fix(tavily): keep web_search contract executable#91110
vincentkoc merged 2 commits into
openclaw:mainfrom
extrasmall0:fix/tavily-web-search-registration

Conversation

@extrasmall0

@extrasmall0 extrasmall0 commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

Fixes #91096.

Summary

  • Route Tavily's web-search-contract-api through the executable Tavily web search provider instead of returning a metadata-only provider.
  • Add a regression test proving the contract path can build and execute the generic web_search tool definition.

Why

The Tavily manifest advertises contracts.webSearchProviders: ["tavily"], and the plugin entrypoint registers a working provider. Some bundled web-search resolution paths can load web-search-contract-api.js directly, though. Tavily's contract facade previously returned createTool: () => null, so an explicit tools.web.search.provider: tavily configuration could resolve a provider descriptor but still have no executable provider available.

Verification

  • pnpm install after the first test run found missing local dependencies.
  • node scripts/run-vitest.mjs extensions/tavily/src/tavily-tools.test.ts
  • node scripts/run-vitest.mjs src/plugins/web-provider-public-artifacts.explicit-fast-path.test.ts
  • pnpm exec oxfmt --write extensions/tavily/web-search-contract-api.ts extensions/tavily/src/tavily-tools.test.ts
  • Runtime probe below.

Real behavior proof

Behavior addressed: Tavily's bundled web-search contract facade now creates an executable web_search provider instead of a metadata-only provider.
Real environment tested: Local OpenClaw checkout on macOS, branch fix/tavily-web-search-registration.
Exact steps or command run after this patch: pnpm exec tsx -e 'import { runWebSearch } from "./src/web-search/runtime.ts"; async function main() { try { await runWebSearch({ config: { plugins: { entries: { tavily: { enabled: true } } }, tools: { web: { search: { enabled: true, provider: "tavily" } } } }, preferInputConfig: true, preferRuntimeProviders: false, args: { query: "OpenClaw Tavily registration", count: 1 } }); console.log("unexpected success"); process.exit(1); } catch (error) { const message = error instanceof Error ? error.message : String(error); console.log(JSON.stringify({ providerReached: message.startsWith("web_search (tavily) needs a Tavily API key"), message }, null, 2)); if (!message.startsWith("web_search (tavily) needs a Tavily API key")) { process.exit(1); } } } main();'
Evidence after fix: The runtime probe loaded OpenClaw's runWebSearch with tools.web.search.provider: "tavily" and no Tavily API key. It reached Tavily's provider-specific missing-key message instead of web_search is disabled or no provider is available. Terminal output:

{
  "providerReached": true,
  "message": "web_search (tavily) needs a Tavily API key. Set TAVILY_API_KEY in the Gateway environment, or configure plugins.entries.tavily.config.webSearch.apiKey."
}

Observed result after fix: The command exited 0 with providerReached: true, proving the managed web_search path found Tavily's executable provider and dispatched into it.
What was not tested: A live Tavily API call was not run because this registration bug can be proven without a real API key.

@openclaw-barnacle openclaw-barnacle Bot added extensions: tavily size: XS triage: mock-only-proof Candidate: PR proof only shows tests, mocks, snapshots, lint, typecheck, or CI. labels Jun 7, 2026
@clawsweeper

clawsweeper Bot commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed June 13, 2026, 7:34 PM ET / 23:34 UTC.

Summary
The branch shares Tavily's generic web_search schema/description, makes extensions/tavily/web-search-contract-api.ts create an executable tool via lazy runtime-provider delegation, and adds a regression test for that contract path.

PR surface: Source +31, Tests +29. Total +60 across 4 files.

Reproducibility: yes. Source inspection shows current main and v2026.6.6 return null from Tavily's contract-provider createTool, while the configured plugin-owned selection path can route through that public artifact; I did not run tests because this review was read-only.

Review metrics: none identified.

Merge readiness
Overall: 🦞 diamond lobster
Proof: 🦞 diamond lobster
Patch quality: 🦞 diamond lobster
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Next step before merge

  • No ClawSweeper repair lane is needed because the PR has no actionable patch defect; maintainers should review and land or reject the open PR normally.

Security
Cleared: The diff changes only Tavily TypeScript provider wiring and tests, with no new dependencies, workflows, lockfiles, permissions, package scripts, or secret-storage behavior.

Review details

Best possible solution:

Land this narrow contract/runtime alignment, keep Tavily startup activation metadata unchanged, and let #91096 close after merge.

Do we have a high-confidence way to reproduce the issue?

Yes. Source inspection shows current main and v2026.6.6 return null from Tavily's contract-provider createTool, while the configured plugin-owned selection path can route through that public artifact; I did not run tests because this review was read-only.

Is this the best way to solve the issue?

Yes. The latest branch fixes the owner-local Tavily contract artifact by lazily delegating execution to the existing runtime provider, which is narrower and safer than the companion manifest startup change or a core resolver behavior change for this bug.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 47759c35063c.

Label changes

Label justifications:

  • P2: This fixes a normal-priority bundled plugin runtime bug where explicit Tavily web_search configuration can resolve a provider without an executable tool.
  • rating: 🦞 diamond lobster: Overall readiness is 🦞 diamond lobster; proof is 🦞 diamond lobster and patch quality is 🦞 diamond lobster.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (terminal): The PR body includes after-fix terminal proof that runWebSearch with provider: "tavily" reaches Tavily's provider-specific missing-key error instead of the generic no-provider error; a live Tavily API call is not needed to prove this registration path.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes after-fix terminal proof that runWebSearch with provider: "tavily" reaches Tavily's provider-specific missing-key error instead of the generic no-provider error; a live Tavily API call is not needed to prove this registration path.
Evidence reviewed

PR surface:

Source +31, Tests +29. Total +60 across 4 files.

View PR surface stats
Area Files Added Removed Net
Source 3 52 21 +31
Tests 1 29 0 +29
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 4 81 21 +60

What I checked:

  • Repository policy applied: Root, extensions, and plugin SDK scoped policies were read; the review applied the extension guidance to keep public artifacts narrow and the SDK guidance to avoid eager runtime imports in lightweight contract surfaces. (extensions/AGENTS.md:58, 47759c35063c)
  • Current main still has non-executable Tavily contract artifact: On current main, Tavily's public web-search contract artifact returns null from createTool, matching the linked bug's non-executable provider path. (extensions/tavily/web-search-contract-api.ts:8, 47759c35063c)
  • Latest release has the same non-executable facade: The latest release tag inspected still has createTool: () => null in Tavily's web-search contract artifact, so the central bug is not already shipped fixed. (extensions/tavily/web-search-contract-api.ts:8, 8c802aa68351)
  • Configured plugin-owned web_search selections can avoid runtime-preferred providers: The agent web-search tool sets preferRuntimeProviders to false when a configured provider is owned by a plugin manifest, which is the route this PR targets. (src/agents/tools/web-tool-runtime-context.ts:51, 47759c35063c)
  • Public artifact loader tries the contract artifact first: The bundled public-artifact fast path includes web-search-contract-api.js before runtime provider artifacts, explaining why Tavily's contract facade must not be metadata-only for this route. (src/plugins/web-provider-public-artifacts.explicit.ts:15, 47759c35063c)
  • Docs define Tavily as a generic web_search provider: The public Tavily docs say OpenClaw exposes Tavily as the web_search provider and document query/count support for the generic tool. Public docs: docs/tools/tavily.md. (docs/tools/tavily.md:13, 47759c35063c)

Likely related people:

  • vincentkoc: Blame on the current Tavily contract artifact points to this contributor for the metadata-only facade on main, and the latest PR branch also contains their lightweight contract rewrite. (role: recent area contributor; confidence: high; commits: eb1b640854bb, 6190b562614b; files: extensions/tavily/web-search-contract-api.ts, extensions/tavily/src/tavily-search-provider.ts, extensions/tavily/web-search-shared.ts)
  • gumadeiras: Live PR history shows this person merged the original Tavily bundled plugin and later authored the web-search provider-contract refactor that made Tavily provider metadata flow through plugin contracts. (role: original merger and adjacent web-search contract contributor; confidence: high; commits: b36e456b0916, 63dc83100479, d65a7533491d; files: extensions/tavily/index.ts, extensions/tavily/src/tavily-search-provider.ts, src/plugins/contracts/registry.ts)
  • lakshyaag-tavily: Live PR history for the original Tavily integration shows this contributor authored the bundled Tavily plugin, provider, tools, docs, and tests. (role: original feature contributor; confidence: medium; commits: 32b8ad0106e3, b36e456b0916; files: extensions/tavily/index.ts, extensions/tavily/openclaw.plugin.json, extensions/tavily/src/tavily-search-provider.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@openclaw-barnacle openclaw-barnacle Bot added proof: supplied External PR includes structured after-fix real behavior proof. and removed triage: mock-only-proof Candidate: PR proof only shows tests, mocks, snapshots, lint, typecheck, or CI. labels Jun 7, 2026
@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. P2 Normal backlog priority with limited blast radius. labels Jun 7, 2026
@extrasmall0
extrasmall0 force-pushed the fix/tavily-web-search-registration branch from d8733f4 to 839fe14 Compare June 7, 2026 07:49
@openclaw-barnacle openclaw-barnacle Bot added the scripts Repository scripts label Jun 7, 2026
@extrasmall0
extrasmall0 force-pushed the fix/tavily-web-search-registration branch from 839fe14 to c042500 Compare June 7, 2026 07:50
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 7, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 7, 2026
@extrasmall0
extrasmall0 force-pushed the fix/tavily-web-search-registration branch from c042500 to b87ce3f Compare June 8, 2026 01:22
@openclaw-barnacle openclaw-barnacle Bot removed the scripts Repository scripts label Jun 8, 2026
@clawsweeper clawsweeper Bot added rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. and removed rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. labels Jun 8, 2026
@vincentkoc vincentkoc self-assigned this Jun 13, 2026
@vincentkoc
vincentkoc force-pushed the fix/tavily-web-search-registration branch from b87ce3f to 6190b56 Compare June 13, 2026 23:22
@vincentkoc

Copy link
Copy Markdown
Member

Maintainer verification for current head 6190b562614b8e31d307e27bfdf5e81369491056:

  • Rebased on current origin/main before review.
  • Verified the Tavily public contract stays lightweight while web_search remains executable through the provider-backed lazy runtime path.
  • Focused proof: node scripts/run-vitest.mjs extensions/tavily/src/tavily-tools.test.ts src/plugins/web-provider-public-artifacts.explicit-fast-path.test.ts — passed, 19 tests.
  • Autoreview: .agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main --thinking high — clean after removing the runtime-graph eager export.
  • GitHub checks: current head is clean; the earlier checks-node-core-tooling failure was an unrelated temp-directory cleanup flake and passed on rerun.
  • Local broad build note: this shell has no pnpm, corepack, or blacksmith, so GitHub CI is the build/check gate for this PR.

Merging by squash.

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

Labels

extensions: tavily P2 Normal backlog priority with limited blast radius. proof: sufficient ClawSweeper judged the real behavior proof convincing. proof: supplied External PR includes structured after-fix real behavior proof. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. size: S status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Tavily plugin loads but web_search provider not registered at runtime

2 participants