Skip to content

fix(onboard): pin Brave web-search plugin to OPENCLAW_VERSION#4955

Open
johnellison wants to merge 1 commit into
NVIDIA:mainfrom
johnellison:fix/pin-brave-web-search-plugin
Open

fix(onboard): pin Brave web-search plugin to OPENCLAW_VERSION#4955
johnellison wants to merge 1 commit into
NVIDIA:mainfrom
johnellison:fix/pin-brave-web-search-plugin

Conversation

@johnellison

@johnellison johnellison commented Jun 8, 2026

Copy link
Copy Markdown

Summary

The Brave web-search provider is an external plugin (@openclaw/brave-plugin) — exactly like the messaging-channel plugins and the diagnostics-OTEL exporter that scripts/openclaw-build-messaging-plugins.py already pins to OPENCLAW_VERSION. But the Brave plugin was never pinned. openclaw doctor --fix installs it from the official catalog's unversioned npmSpec, so it resolves to npm latest.

Once OpenClaw publishes a release the NemoClaw OPENCLAW_VERSION pin hasn't caught up to, latest drifts ahead of the host. The newer plugin imports plugin-SDK symbols the older host doesn't export, so web_search fails at runtime with:

(0 , _providerWebSearch.readPositiveIntegerParam) is not a function

Because it only breaks once latest has drifted past the pin, it reproduces intermittently — which matches the back-and-forth in #3948.

Concrete timeline

package 2026.5.22 published 2026.6.1 published
core openclaw May 24 Jun 3
@openclaw/brave-plugin May 24 Jun 3

@openclaw/brave-plugin@latest is now 2026.6.1 (peerDependencies.openclaw: ">=2026.6.1"). main currently pins OPENCLAW_VERSION=2026.5.27 → host 2026.5.27 + plugin 2026.6.1 = incompatible. Every web-search onboard since Jun 3 is affected.

Fix

Pin and install @openclaw/brave-plugin@$OPENCLAW_VERSION when NEMOCLAW_WEB_SEARCH_ENABLED is set, mirroring the existing messaging-channel and diagnostics-OTEL handling in the same script. NEMOCLAW_WEB_SEARCH_ENABLED is already an ARG exported into the build ENV block this script runs under (Dockerfile), so no Dockerfile change is needed. The plugin publishes a build for every core calver (e.g. @openclaw/brave-plugin@2026.5.27 exists), so the pin always resolves.

Tests

Added cases mirroring the diagnostics-OTEL tests:

  • pins @openclaw/brave-plugin@$OPENCLAW_VERSION when web search is enabled
  • does not install it when web search is disabled
  • requires OPENCLAW_VERSION when web search is enabled

Verified the script's --dry-run output and the --pin install ordering against each new assertion locally; the existing messaging/OTEL cases are unaffected.

Verification

On a live sandbox, swapping the drifted 2026.6.1 plugin for the OPENCLAW_VERSION-matched build makes web_search return real Brave results with no SDK error. A direct curl to api.search.brave.com was already returning 200 throughout — i.e. the API key and network policy were never the problem; only the plugin/host version skew.

Scope

Deliberately limited to the version-pin root cause. While investigating I also checked whether the build-time doctor --fix (which runs without BRAVE_API_KEY in its env) strips the tools.web.search.apiKey placeholder. On current OpenClaw I could not reproduce that — doctor preserves/relocates the placeholder rather than dropping it — so I left it out rather than bundle an unverified change. Happy to revisit if maintainers have seen the apiKey actually go missing.

Addresses #3948.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Chores

    • Extended build-time plugin installer to treat the Brave web-search provider as an external, pinned plugin when enabled.
    • Added validation to require a matching release version when web-search is enabled and to surface configuration errors.
  • Tests

    • Added tests covering web-search enablement, install spec generation, reporting in dry-run output, and error handling when version is missing.

@copy-pr-bot

copy-pr-bot Bot commented Jun 8, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@coderabbitai

coderabbitai Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: b077a829-de66-447b-8964-59b3af925564

📥 Commits

Reviewing files that changed from the base of the PR and between 25389e0 and b57664b.

📒 Files selected for processing (2)
  • scripts/openclaw-build-messaging-plugins.py
  • test/openclaw-build-messaging-plugins.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • scripts/openclaw-build-messaging-plugins.py
  • test/openclaw-build-messaging-plugins.test.ts

📝 Walkthrough

Walkthrough

The PR extends the build-time plugin installer to treat the Brave web-search provider as an external plugin that must be pinned to OPENCLAW_VERSION when enabled; it adds a WEB_SEARCH_PLUGIN_PACKAGE constant, threads a web_search_enabled flag through validation and spec generation, and adds tests and a webSearchEnabled dry-run field.

Changes

Web-search plugin support

Layer / File(s) Summary
Web-search plugin contract and core implementation
scripts/openclaw-build-messaging-plugins.py
Module docstring clarifies Brave web-search provider must be pinned to OPENCLAW_VERSION. New WEB_SEARCH_PLUGIN_PACKAGE constant introduced. require_openclaw_version and plugin_specs gain web_search_enabled parameters; when enabled, OPENCLAW_VERSION is required and the Brave npm install spec is appended. main reads NEMOCLAW_WEB_SEARCH_ENABLED and threads it through; --dry-run JSON includes webSearchEnabled.
Web-search plugin functional tests
test/openclaw-build-messaging-plugins.test.ts
Tests verify enabling web-search includes the Brave plugin pinned to the provided version and sets webSearchEnabled true; disabling omits the Brave plugin and sets the flag false; enabling without OPENCLAW_VERSION exits non-zero with OPENCLAW_VERSION is required error.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • NVIDIA/NemoClaw#4591: Earlier PR that introduced the npm:-prefixed install spec pattern and OPENCLAW_VERSION pinning logic extended here to the Brave web-search plugin.

Suggested labels

bug, integration: openclaw, fix, area: integrations

Suggested reviewers

  • cv
  • prekshivyas

Poem

🐰 A brave plugin hops in with a version to keep,
Pinned to the trunk so the runtimes don't weep,
Flags in the env tell the build what to send,
Tests check the install and errors if not pinned.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: pinning the Brave web-search plugin to OPENCLAW_VERSION in the onboarding/build script, which directly matches the primary objective of fixing version drift issues.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
scripts/openclaw-build-messaging-plugins.py (1)

136-140: ⚡ Quick win

Include Brave API key placeholder in doctor env overrides when web search is enabled.

doctor_env_overrides(...) is still channel-only. With NEMOCLAW_WEB_SEARCH_ENABLED=1, the generated config uses openshell:resolve:env:BRAVE_API_KEY; not passing that placeholder into openclaw doctor --fix risks doctor mutating the web-search block unexpectedly.

Suggested patch
-def doctor_env_overrides(channels: Iterable[str]) -> dict[str, str]:
+def doctor_env_overrides(
+    channels: Iterable[str],
+    *,
+    web_search_enabled: bool,
+) -> dict[str, str]:
     overrides: dict[str, str] = {}
     for channel in channels:
         overrides.update(DOCTOR_ENV_BY_CHANNEL.get(channel, {}))
+    if web_search_enabled:
+        overrides["BRAVE_API_KEY"] = "openshell:resolve:env:BRAVE_API_KEY"
     return overrides
@@
-    env_overrides = doctor_env_overrides(channels)
+    env_overrides = doctor_env_overrides(
+        channels, web_search_enabled=web_search_enabled
+    )

Also applies to: 173-197

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/openclaw-build-messaging-plugins.py` around lines 136 - 140,
doctor_env_overrides currently only aggregates channel-specific entries
(DOCTOR_ENV_BY_CHANNEL) and omits the Brave API key placeholder when web search
is enabled; update doctor_env_overrides to also inject the BRAVE_API_KEY
placeholder into the returned dict when the environment flag
NEMOCLAW_WEB_SEARCH_ENABLED (or equivalent config) is truthy so that
openshell:resolve:env:BRAVE_API_KEY is present for openclaw doctor --fix; modify
the same logic area referenced further down (the other doctor env aggregation
block) to apply the same addition so both places include the Brave key
placeholder when web search is enabled, using the existing symbols
doctor_env_overrides, DOCTOR_ENV_BY_CHANNEL, and the BRAVE_API_KEY placeholder
name.
test/openclaw-build-messaging-plugins.test.ts (1)

141-153: ⚡ Quick win

Add a doctorEnv assertion for BRAVE_API_KEY in the web-search-enabled test.

This test already validates install pinning; adding a doctorEnv assertion will lock the end-to-end contract and prevent regressions in doctor --fix input shaping.

Suggested assertion
   it("pins the Brave web-search plugin to OPENCLAW_VERSION when web search is enabled", () => {
@@
     expect(payload.webSearchEnabled).toBe(true);
+    expect(payload.doctorEnv).toMatchObject({
+      BRAVE_API_KEY: "openshell:resolve:env:BRAVE_API_KEY",
+    });
     expect(payload.installSpecs).toEqual([
       "npm:`@openclaw/slack`@2026.5.22",
       "npm:`@openclaw/brave-plugin`@2026.5.22",
     ]);
   });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/openclaw-build-messaging-plugins.test.ts` around lines 141 - 153, The
test "pins the Brave web-search plugin to OPENCLAW_VERSION when web search is
enabled" currently checks install pinning but omits verifying doctorEnv; modify
that test (the one constructing payload via parseDryRun and asserting
payload.webSearchEnabled/installSpecs) to also assert that payload.doctorEnv
includes a BRAVE_API_KEY entry when NEMOCLAW_WEB_SEARCH_ENABLED is set, e.g.,
add an assertion on payload.doctorEnv (using payload.doctorEnv or
payload.doctorEnv.BRAVE_API_KEY) to ensure BRAVE_API_KEY is present and
non-empty to lock the doctor --fix contract.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@scripts/openclaw-build-messaging-plugins.py`:
- Around line 136-140: doctor_env_overrides currently only aggregates
channel-specific entries (DOCTOR_ENV_BY_CHANNEL) and omits the Brave API key
placeholder when web search is enabled; update doctor_env_overrides to also
inject the BRAVE_API_KEY placeholder into the returned dict when the environment
flag NEMOCLAW_WEB_SEARCH_ENABLED (or equivalent config) is truthy so that
openshell:resolve:env:BRAVE_API_KEY is present for openclaw doctor --fix; modify
the same logic area referenced further down (the other doctor env aggregation
block) to apply the same addition so both places include the Brave key
placeholder when web search is enabled, using the existing symbols
doctor_env_overrides, DOCTOR_ENV_BY_CHANNEL, and the BRAVE_API_KEY placeholder
name.

In `@test/openclaw-build-messaging-plugins.test.ts`:
- Around line 141-153: The test "pins the Brave web-search plugin to
OPENCLAW_VERSION when web search is enabled" currently checks install pinning
but omits verifying doctorEnv; modify that test (the one constructing payload
via parseDryRun and asserting payload.webSearchEnabled/installSpecs) to also
assert that payload.doctorEnv includes a BRAVE_API_KEY entry when
NEMOCLAW_WEB_SEARCH_ENABLED is set, e.g., add an assertion on payload.doctorEnv
(using payload.doctorEnv or payload.doctorEnv.BRAVE_API_KEY) to ensure
BRAVE_API_KEY is present and non-empty to lock the doctor --fix contract.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 8e553946-5bdc-4c80-9630-a6015daf3ec6

📥 Commits

Reviewing files that changed from the base of the PR and between ec408c8 and 25389e0.

📒 Files selected for processing (2)
  • scripts/openclaw-build-messaging-plugins.py
  • test/openclaw-build-messaging-plugins.test.ts

The Brave web-search provider is an external plugin (@openclaw/brave-plugin),
like the messaging channels and diagnostics OTEL exporter — but it was never
pinned. `openclaw doctor --fix` installs it from the official catalog's
unversioned npmSpec, so it resolves to npm `latest`. Once OpenClaw publishes a
release the NemoClaw OPENCLAW_VERSION pin has not caught up to, `latest` drifts
ahead of the host: the newer plugin imports plugin-SDK symbols the older host
does not export, so web_search fails at runtime with

    (0 , _providerWebSearch.readPositiveIntegerParam) is not a function

This is timing-dependent — it only breaks once `latest` has drifted past the
pin — which is why it reproduces intermittently.

Pin and build-install @openclaw/brave-plugin to OPENCLAW_VERSION when
NEMOCLAW_WEB_SEARCH_ENABLED is set, mirroring the existing messaging-channel and
diagnostics-OTEL handling. NEMOCLAW_WEB_SEARCH_ENABLED is already plumbed into
this build step (Dockerfile ARG + ENV), so no Dockerfile change is needed. The
plugin publishes a build for every core calver, so the pin always resolves.

Addresses NVIDIA#3948

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: John Ellison <john@john-ellison.com>
@johnellison johnellison force-pushed the fix/pin-brave-web-search-plugin branch from 25389e0 to b57664b Compare June 8, 2026 12:00
@wscurran wscurran added bug-fix PR fixes a bug or regression integration: brave Brave integration behavior labels Jun 8, 2026
@wscurran

wscurran commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

✨ Thanks for submitting this detailed PR about pinning the Brave web-search plugin to OPENCLAW_VERSION. This proposes a way to fix the intermittent failure in the onboarding flow.


Related open issues:

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

Labels

bug-fix PR fixes a bug or regression integration: brave Brave integration behavior

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants