Skip to content

feat(onboard): add Tavily web search providers - #6165

Merged
cv merged 6 commits into
mainfrom
codex/tavily-web-search
Jul 3, 2026
Merged

feat(onboard): add Tavily web search providers#6165
cv merged 6 commits into
mainfrom
codex/tavily-web-search

Conversation

@cv

@cv cv commented Jul 2, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds first-class Tavily web-search onboarding for OpenClaw and Hermes, including provider-aware credentials, runtime configuration, network policy, rebuild/resume reconciliation, and live post-create verification. This revives the useful concepts from #2105 on the current architecture while preserving Brave compatibility and fail-closed behavior.

Related Issue

Advances #2718.

Revives and supersedes #2105. The original Tavily contribution from @lakshyaag-tavily is preserved through co-author and sign-off trailers.

Changes

  • Add shared brave, tavily, and none web-search selection with credential-store precedence, secure credential validation, provider-scoped resources, and legacy Brave migration.
  • Configure OpenClaw's bundled Tavily extension and Hermes' native Tavily backend, including managed-tool conflict suppression and provider-specific runtime verification.
  • Add least-privilege Tavily network policies, Hermes request-body credential rewriting, and coverage in both agent-specific and global permissive policies.
  • Reconcile provider changes across rebuild and resume without widening intentionally restricted policy state, and clean up stale provider config, credentials, and policies.
  • Document interactive and non-interactive setup, provider switching, policy behavior, troubleshooting, and credential handling.

Type of Change

  • Code change (feature, bug fix, or refactor)
  • Code change with doc updates
  • Doc only (prose changes, no code sample modifications)
  • Doc only (includes code sample changes)

Quality Gates

  • Tests added or updated for changed behavior
  • Existing tests cover changed behavior — justification:
  • Tests not applicable — justification:
  • Docs updated for user-facing behavior changes
  • Docs not applicable — justification:
  • Sensitive paths changed (security, policy, credentials, preflight, onboarding, inference, runner, sandbox, or messaging)
  • Sensitive-path review completed or maintainer-approved waiver recorded — reviewer/approval link/justification: focused reviews covered credential handling, policy egress and body rewrites, provider switching, resume reconciliation, and runtime verification; no findings remain.
  • Non-success, skipped, or missing CI check accepted by maintainer — check name, approval link, and follow-up issue:

Verification

  • PR description includes the DCO sign-off declaration and every commit appears as Verified in GitHub
  • Git hooks passed during commit and push, or npx prek run --from-ref main --to-ref HEAD passes
  • Targeted tests pass for changed behavior
  • Full npm test passes (broad runtime changes only)
  • Quality Gates section completed with required justifications or waivers
  • No secrets, API keys, or credentials committed
  • npm run docs builds without warnings (doc changes only)
  • Doc pages follow the style guide (doc changes only)
  • New doc pages include SPDX header and frontmatter (new pages only)

Additional verification:

  • npm test: 946 files passed, 10,852 tests passed, 34 expected skips.
  • make check: passed, including coverage ratchets, source-shape and test-size budgets, gitleaks, ShellCheck, Hadolint, and plugin tests.
  • Post-rebase focused suite: 179 tests passed; npm run typecheck:cli passed.
  • npm run docs: 0 errors; the two existing Fern upgrade warnings remain.
  • Pinned OpenClaw and Hermes runtime contracts were inspected for the bundled extension and native backend behavior.

Signed-off-by: Carlos Villela cvillela@nvidia.com

Summary by CodeRabbit

  • New Features
    • Added provider selection for web search during onboarding (Brave or Tavily), including provider-specific API key handling and sandbox recreation when changing providers.
    • Hermes now supports Tavily web search with correct backend routing and request credential rewriting; Tavily selection can replace the managed web gateway when applicable.
    • Added Tavily network policies/provider profiles with least-privilege access limited to POST /search and POST /extract.
  • Bug Fixes
    • Improved resume/reconciliation to correctly swap or remove stale web-search provider and related gateway selections.
    • Web-search verification now validates the active provider/backend and warns on misconfiguration without blocking completion.
  • Documentation
    • Updated onboarding quickstarts, references, and runtime controls to reflect the new provider variables, defaults, and rebuild/verification behavior.

Revive Tavily onboarding from #2105 for the current OpenClaw and Hermes architectures.

Co-authored-by: Lakshya Agarwal <lakshya.agarwal@tavily.com>

Signed-off-by: Lakshya Agarwal <lakshya.agarwal@tavily.com>

Signed-off-by: Carlos Villela <cvillela@nvidia.com>
@cv cv added integration: openclaw OpenClaw integration behavior integration: hermes Hermes integration behavior area: docs Documentation, examples, guides, or docs build area: integrations Third-party service integration behavior area: onboarding Onboarding FSM, provider setup, sandbox launch, or first-run flow area: policy Network policy, egress rules, presets, or sandbox policy area: providers Inference provider integrations and provider behavior feature PR adds or expands user-visible functionality labels Jul 2, 2026
@cv cv self-assigned this Jul 2, 2026
@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR makes web-search handling provider-aware for Brave and Tavily across build-time config, onboarding, sandbox state, persistence, policy reconciliation, and documentation. It also adds Tavily-specific policy/profile artifacts and expands validation coverage.

Changes

Web Search Provider Generalization

Layer / File(s) Summary
Web-search provider contract
src/lib/inference/web-search.ts, src/lib/inference/web-search.test.ts, src/lib/onboard/web-search-support.ts, src/lib/onboard/web-search-support.test.ts
Adds shared provider types and normalization helpers, plus support-detection tests for Brave and Tavily.
Build-time provider selection
Dockerfile, agents/hermes/Dockerfile, scripts/generate-openclaw-config.mts, scripts/install.sh, src/lib/onboard/dockerfile-patch.ts, src/lib/messaging/applier/build/messaging-build-applier.mts, test/*
Adds provider-aware build args, config generation, env wiring, and doctor overrides for Brave and Tavily.
Hermes runtime config
agents/hermes/config/*, agents/hermes/seed-dashboard-config.py, agents/hermes/policy-permissive.yaml, test/generate-hermes-config.test.ts, test/hermes-gateway-wrapper.test.ts, test/seed-hermes-dashboard-config.test.ts
Carries Tavily through Hermes build settings, gateway filtering, env seeding, and related runtime tests/policies.
Onboarding credential flow
src/lib/onboard/web-search-flow.ts, src/lib/onboard/brave-provider-profile.ts, src/lib/onboard/messaging-prep.ts, src/lib/onboard/sandbox-messaging-preflight.ts, src/lib/onboard/web-search-verify.ts, src/lib/onboard/sandbox-provider-cleanup.ts, src/lib/onboard.ts, test/*
Generalizes provider validation, profile import, token preparation, preflight handling, egress verification, and cleanup across Brave and Tavily.
Sandbox state and policies
src/lib/onboard/machine/*, src/lib/onboard/policy-*.ts, src/lib/policy/index.ts, src/lib/state/*, test/*
Tracks provider changes through sandbox resume/recreate, policy suggestion/reconciliation, session normalization, and OpenClaw restore merging.
Policies, profiles, and docs
agents/*.yaml, nemoclaw-blueprint/*, docs/*, ci/platform-matrix.json, test/*
Adds Tavily policy/profile YAMLs and updates documentation plus validation fixtures to describe the provider-specific behavior.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant WebSearchFlow
  participant CurlProbe
  participant MessagingPrep
  User->>WebSearchFlow: choose brave or tavily
  WebSearchFlow->>CurlProbe: validate provider API key
  CurlProbe-->>WebSearchFlow: validation result
  WebSearchFlow->>MessagingPrep: prepare sandbox messaging
Loading

Possibly related PRs

  • NVIDIA/NemoClaw#4133: Both PRs touch web-search onboarding; that PR hardens saved-credential fallback while this one adds provider-aware Brave/Tavily flow.
  • NVIDIA/NemoClaw#4571: Both PRs modify the OpenClaw config generation pipeline; this one extends it with provider selection.

Suggested reviewers: cjagwani, ericksoa

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding Tavily web search support in onboarding.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/tavily-web-search

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

@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

PR Review Advisor (Nemotron Ultra) — Changes requested

Merge posture: Do not merge yet
Primary next action: Fix PRA-2: Hermes Tavily provider profile credential rewrite mismatch; then add or justify PRA-T1.
Open items: 1 required · 7 warnings · 2 suggestions · 8 test follow-ups
Since last review: 0 prior items resolved · 7 still apply · 2 new items found

Action checklist

  • PRA-2 Fix: Hermes Tavily provider profile credential rewrite mismatch in nemoclaw-blueprint/provider-profiles/tavily-hermes-v1.yaml:10
  • PRA-1 Resolve or justify: Source-of-truth review needed: isStaleBuiltinWebSearchPolicyPreset in policy-selection.ts
  • PRA-3 Resolve or justify: Dual credential rewrite mechanisms across provider profiles and verification in src/lib/onboard/web-search-verify.ts:55
  • PRA-4 Resolve or justify: Monolith growth in security-critical web search flow in src/lib/onboard/web-search-flow.ts:1
  • PRA-5 Resolve or justify: Monolith growth in sandbox handler with web search threading in src/lib/onboard/machine/handlers/sandbox.ts:1
  • PRA-6 Resolve or justify: Monolith growth in policy selection with stale preset filtering in src/lib/onboard/policy-selection.ts:1
  • PRA-7 Resolve or justify: No runtime integration test for Hermes Tavily body credential rewrite in test/sandbox-provisioning-tavily.test.ts:1
  • PRA-8 Resolve or justify: Verification probes only test one rewrite path per agent in src/lib/onboard/web-search-verify.test.ts:1
  • PRA-T1 Add or justify test follow-up: Runtime validation
  • PRA-T2 Add or justify test follow-up: Runtime validation
  • PRA-T3 Add or justify test follow-up: Runtime validation
  • PRA-T4 Add or justify test follow-up: Runtime validation
  • PRA-T5 Add or justify test follow-up: No runtime integration test for Hermes Tavily body credential rewrite
  • PRA-T6 Add or justify test follow-up: Verification probes only test one rewrite path per agent
  • PRA-T7 Add or justify test follow-up: Acceptance clause
  • PRA-T8 Add or justify test follow-up: Acceptance clause
  • PRA-9 In-scope improvement: Web search support module could be consolidated in src/lib/onboard/web-search-support.ts:1
  • PRA-10 In-scope improvement: Stale preset filtering is a localized workaround for provider/policy drift in src/lib/onboard/policy-selection.ts:47

Findings index

ID Severity Category Location Required action
PRA-1 Resolve/justify architecture Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
PRA-2 Required security nemoclaw-blueprint/provider-profiles/tavily-hermes-v1.yaml:10 Change `tavily-hermes-v1.yaml` credentials to use body rewrite auth style (e.g., `auth_style: body`, `body_field: api_key`) if OpenShell supports it, OR confirm OpenShell applies both rewrite mechanisms for Hermes traffic. Add integration test verifying body rewrite works end-to-end for Hermes.
PRA-3 Resolve/justify security src/lib/onboard/web-search-verify.ts:55 Standardize on one rewrite mechanism per provider per agent. For Hermes, prefer body rewrite (matches Hermes native `api_key` JSON field). For OpenClaw, verify which mechanism the OpenClaw Tavily plugin actually uses and align provider profile + verification accordingly. Document the chosen mechanism in provider profile comments.
PRA-4 Resolve/justify architecture src/lib/onboard/web-search-flow.ts:1 Extract into separate modules: `web-search-provider-selection.ts` (prompting, non-interactive resolution), `web-search-credential-validation.ts` (API key validation, curl probes), `web-search-recovery.ts` (retry/skip prompts), `web-search-sandbox-verification.ts` (post-create probes). Keep security-critical credential handling in minimal, auditable units.
PRA-5 Resolve/justify architecture src/lib/onboard/machine/handlers/sandbox.ts:1 Extract `resolveWebSearchForCreation`, `effectiveHermesToolGatewaysForWebSearch`, and `prepareWebSearchSupport` into dedicated `sandbox-web-search.ts` helper. Keep `sandbox.ts` focused on state machine orchestration.
PRA-6 Resolve/justify architecture src/lib/onboard/policy-selection.ts:1 Extract stale preset filtering into dedicated `web-search-policy-presets.ts` with clear contract. Keep `policy-selection.ts` focused on tier/preset selection flow.
PRA-7 Resolve/justify tests test/sandbox-provisioning-tavily.test.ts:1 Add integration test that builds Hermes image with Tavily, starts sandbox, executes search via Hermes Python runtime, captures egress, and verifies placeholder is rewritten in JSON body.
PRA-8 Resolve/justify tests src/lib/onboard/web-search-verify.test.ts:1 Add cross-path verification tests: test Hermes with header rewrite probe and OpenClaw with body rewrite probe. Document which path is expected to work for each agent.
PRA-9 Improvement scope src/lib/onboard/web-search-support.ts:1 Consolidate agent web search support checks into single `agent-web-search-support.ts` if separation is not intentional for test isolation. Or confirm this separation is intentional.
PRA-10 Improvement architecture src/lib/onboard/policy-selection.ts:47 Document the workaround with source-of-truth answers: invalid state = provider/policy drift; source boundary = separate build-time (Dockerfile ARGs) vs runtime (policy presets) config; why not fix here = would require unified config model across image build and runtime; regression test = `onboard-policy-suggestions.test.ts` stale preset tests; removal condition = unified web search config in openclaw.json/hermes config.yaml.

🚨 Required before merge

Address these before merging unless a maintainer explicitly overrides the advisor with rationale.

PRA-2 Required — Hermes Tavily provider profile credential rewrite mismatch

  • Location: nemoclaw-blueprint/provider-profiles/tavily-hermes-v1.yaml:10
  • Category: security
  • Problem: Provider profile declares `auth_style: bearer` + `header_name: authorization` (header rewrite) but network policy preset and Hermes runtime expect JSON body rewrite (`request_body_credential_rewrite: true` with `api_key` field). Verification code tests body rewrite path. If OpenShell only consults provider profile credentials section, body rewrite won't activate for Hermes traffic.
  • Impact: Tavily search requests from Hermes will fail with 401/403 because the resolver placeholder is sent literally in the JSON body instead of being rewritten. No credential leak (placeholder is invalid), but feature is non-functional for Hermes users.
  • Required action: Change `tavily-hermes-v1.yaml` credentials to use body rewrite auth style (e.g., `auth_style: body`, `body_field: api_key`) if OpenShell supports it, OR confirm OpenShell applies both rewrite mechanisms for Hermes traffic. Add integration test verifying body rewrite works end-to-end for Hermes.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: Check OpenShell provider profile schema for body rewrite support; run Hermes sandbox with Tavily and capture egress request to verify placeholder is rewritten in JSON body (not Authorization header).
  • Missing regression test: Add runtime test: build Hermes image with Tavily, start sandbox, execute search request, verify request body contains real API key (not placeholder) and response returns results.
  • Done when: The required change is committed and verification passes: Check OpenShell provider profile schema for body rewrite support; run Hermes sandbox with Tavily and capture egress request to verify placeholder is rewritten in JSON body (not Authorization header).
  • Evidence: tavily.yaml:14 `request_body_credential_rewrite: true`; tavily-hermes-v1.yaml:10-11 `auth_style: bearer`, `header_name: authorization`; web-search-verify.ts:114-124 `buildTavilyBodyEgressProbeCommand` sends placeholder in JSON body
Review findings by urgency: 1 required fix, 7 items to resolve/justify, 2 in-scope improvements

⚠️ Resolve or justify before merge

Investigate these in the current review; either fix them, explain why they are not applicable, or document the accepted risk.

PRA-1 Resolve/justify — Source-of-truth review needed: isStaleBuiltinWebSearchPolicyPreset in policy-selection.ts

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: onboard-policy-suggestions.test.ts: 'selects Tavily and removes the stale Brave tier default', 'adds all Hermes Nous tool policy presets for Hermes open tier only', 'restricted suppression list ⊇ env-gated additions (drift invariant)'
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: policy-selection.ts:47 isStaleBuiltinWebSearchPolicyPreset called in mergeRequiredSetupPolicyPresets, computeSetupPresetSuggestions, and setupPoliciesWithSelectionInner

PRA-3 Resolve/justify — Dual credential rewrite mechanisms across provider profiles and verification

  • Location: src/lib/onboard/web-search-verify.ts:55
  • Category: security
  • Problem: Both `tavily.yaml` and `tavily-hermes-v1.yaml` declare `auth_style: bearer` + `header_name: authorization` in credentials section, but `request_body_credential_rewrite: true` in endpoints section. Verification uses body rewrite for Hermes (`buildTavilyBodyEgressProbeCommand`) and header rewrite for OpenClaw (`buildTavilyEgressProbeCommand`). Only one path tested per agent.
  • Impact: Uncertainty about which rewrite mechanism OpenShell enforces at runtime. If the untested path is the one used, Tavily requests may fail silently or send placeholders.
  • Recommended action: Standardize on one rewrite mechanism per provider per agent. For Hermes, prefer body rewrite (matches Hermes native `api_key` JSON field). For OpenClaw, verify which mechanism the OpenClaw Tavily plugin actually uses and align provider profile + verification accordingly. Document the chosen mechanism in provider profile comments.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect provider profile credentials vs endpoints sections; run verification probes for both agents and confirm the tested path matches actual runtime behavior.
  • Missing regression test: Add verification probes that test both rewrite paths for each agent, or document why only one path is needed per agent.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect provider profile credentials vs endpoints sections; run verification probes for both agents and confirm the tested path matches actual runtime behavior.
  • Evidence: tavily.yaml:13 `auth_style: bearer`; tavily-hermes-v1.yaml:16 `auth_style: bearer`; web-search-verify.ts:55 `buildTavilyEgressProbeCommand` (header) vs :75 `buildTavilyBodyEgressProbeCommand` (body)

PRA-4 Resolve/justify — Monolith growth in security-critical web search flow

  • Location: src/lib/onboard/web-search-flow.ts:1
  • Category: architecture
  • Problem: File grew by 197 lines (from 302 to 499). Contains provider prompting, credential validation, curl probes, recovery prompts, non-interactive resolution, and sandbox verification — all security-critical credential handling in one file. Reduced auditability and maintainability; harder to verify no credential interpolation into executable source occurs.
  • Impact: Reduced auditability and maintainability of security-critical code. Increases cognitive load for reviewers. Harder to verify no credential interpolation into executable source occurs.
  • Recommended action: Extract into separate modules: `web-search-provider-selection.ts` (prompting, non-interactive resolution), `web-search-credential-validation.ts` (API key validation, curl probes), `web-search-recovery.ts` (retry/skip prompts), `web-search-sandbox-verification.ts` (post-create probes). Keep security-critical credential handling in minimal, auditable units.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Verify each extracted module has a single responsibility and tests cover its boundaries.
  • Missing regression test: Ensure existing tests pass after extraction; add tests for module boundaries.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Verify each extracted module has a single responsibility and tests cover its boundaries.
  • Evidence: File grew from 302 to 499 lines (+197). Contains 6 distinct responsibilities mixed together.

PRA-5 Resolve/justify — Monolith growth in sandbox handler with web search threading

  • Location: src/lib/onboard/machine/handlers/sandbox.ts:1
  • Category: architecture
  • Problem: File grew by 113 lines (from 458 to 571). Contains `resolveWebSearchForCreation`, `effectiveHermesToolGatewaysForWebSearch`, and `prepareWebSearchSupport` mixed with state machine orchestration logic.
  • Impact: Sandbox state machine logic intertwined with web search provider resolution. Harder to verify sandbox creation correctness independently of web search logic.
  • Recommended action: Extract `resolveWebSearchForCreation`, `effectiveHermesToolGatewaysForWebSearch`, and `prepareWebSearchSupport` into dedicated `sandbox-web-search.ts` helper. Keep `sandbox.ts` focused on state machine orchestration.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Verify extracted helper has clear contract and sandbox.ts imports it cleanly.
  • Missing regression test: Ensure sandbox handler tests pass after extraction.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Verify extracted helper has clear contract and sandbox.ts imports it cleanly.
  • Evidence: File grew from 458 to 571 lines (+113). Three web-search functions embedded in state machine handler.

PRA-6 Resolve/justify — Monolith growth in policy selection with stale preset filtering

  • Location: src/lib/onboard/policy-selection.ts:1
  • Category: architecture
  • Problem: File grew by 54 lines (from 447 to 501). Contains stale preset filtering logic (`isStaleBuiltinWebSearchPolicyPreset`) mixed with tier/preset selection flow.
  • Impact: Policy selection logic coupled to web search provider drift handling. Stale preset filter is a workaround for build-time vs runtime config separation.
  • Recommended action: Extract stale preset filtering into dedicated `web-search-policy-presets.ts` with clear contract. Keep `policy-selection.ts` focused on tier/preset selection flow.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Verify extracted module has clear contract and policy-selection.ts imports it cleanly.
  • Missing regression test: Ensure policy selection tests pass after extraction.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Verify extracted module has clear contract and policy-selection.ts imports it cleanly.
  • Evidence: File grew from 447 to 501 lines (+54). `isStaleBuiltinWebSearchPolicyPreset` used in multiple places across the file.

PRA-7 Resolve/justify — No runtime integration test for Hermes Tavily body credential rewrite

  • Location: test/sandbox-provisioning-tavily.test.ts:1
  • Category: tests
  • Problem: Test file only covers OpenClaw bundled Tavily plugin path (inspects plugin, runs doctor with `TAVILY_API_KEY=openshell:resolve:env:TAVILY_API_KEY`). No runtime integration test for Hermes Tavily body credential rewrite — Hermes uses native Python runtime, not OpenClaw plugin.
  • Impact: Hermes Tavily body rewrite path is untested at runtime. The blocker PRA-1 could exist in production without detection.
  • Recommended action: Add integration test that builds Hermes image with Tavily, starts sandbox, executes search via Hermes Python runtime, captures egress, and verifies placeholder is rewritten in JSON body.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Run the new integration test and verify it passes with real Tavily API key.
  • Missing regression test: Add Hermes Tavily runtime integration test covering body credential rewrite end-to-end.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Run the new integration test and verify it passes with real Tavily API key.
  • Evidence: test/sandbox-provisioning-tavily.test.ts only mocks `openclaw plugins inspect tavily` and `doctor` — no Hermes sandbox creation or Python runtime execution.

PRA-8 Resolve/justify — Verification probes only test one rewrite path per agent

  • Location: src/lib/onboard/web-search-verify.test.ts:1
  • Category: tests
  • Problem: Tests verify Hermes with body rewrite probe and OpenClaw with header rewrite probe, but no cross-path tests: no test for Hermes with header rewrite probe, no test for OpenClaw with body rewrite probe. Leaves untested path per agent.
  • Impact: If OpenShell uses the untested rewrite path for either agent, the verification would pass but actual traffic would fail. No coverage for the mismatch identified in PRA-1.
  • Recommended action: Add cross-path verification tests: test Hermes with header rewrite probe and OpenClaw with body rewrite probe. Document which path is expected to work for each agent.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Run verification tests with both rewrite paths for each agent.
  • Missing regression test: Add test cases for the cross-path probes in web-search-verify.test.ts.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Run verification tests with both rewrite paths for each agent.
  • Evidence: web-search-verify.test.ts has 12 test cases but all use `buildTavilyBodyEgressProbeCommand` for Hermes and `buildTavilyEgressProbeCommand` for OpenClaw — no cross-testing.

💡 In-scope improvements

These are lower-risk, not throwaway. Prefer fixing them in this PR when they are local to changed code; defer only with rationale or a linked follow-up.

PRA-9 Improvement — Web search support module could be consolidated

  • Location: src/lib/onboard/web-search-support.ts:1
  • Category: scope
  • Problem: Two separate modules (`web-search-support.ts` and `web-search-support.test.ts`) exist for agent web search support checks. Could be consolidated into single `agent-web-search-support.ts` if separation is not intentional for test isolation.
  • Impact: Minor — duplication of file structure without clear separation of concerns.
  • Suggested action: Consolidate agent web search support checks into single `agent-web-search-support.ts` if separation is not intentional for test isolation. Or confirm this separation is intentional.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Check if the two modules serve distinct purposes or can be merged.
  • Missing regression test: N/A - refactoring only.
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: web-search-support.ts exports `agentSupportsWebSearch` and `agentSupportsWebSearchProvider`; test file tests both. No other consumers of the separation.

PRA-10 Improvement — Stale preset filtering is a localized workaround for provider/policy drift

  • Location: src/lib/onboard/policy-selection.ts:47
  • Category: architecture
  • Problem: `isStaleBuiltinWebSearchPolicyPreset` filters stale `brave`/`tavily`/`nous-web` presets based on current web search config. This handles the invalid state where provider selection (build-time) and policy presets (runtime) can drift. Root cause: separate build-time vs runtime config model.
  • Impact: Workaround masks the underlying config model issue. If provider selection and policy application were unified, this filter would be unnecessary.
  • Suggested action: Document the workaround with source-of-truth answers: invalid state = provider/policy drift; source boundary = separate build-time (Dockerfile ARGs) vs runtime (policy presets) config; why not fix here = would require unified config model across image build and runtime; regression test = `onboard-policy-suggestions.test.ts` stale preset tests; removal condition = unified web search config in openclaw.json/hermes config.yaml.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Review `onboard-policy-suggestions.test.ts` tests for stale preset filtering behavior.
  • Missing regression test: Existing `onboard-policy-suggestions.test.ts` covers stale preset filtering — ensure it remains passing.
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: policy-selection.ts:47 `isStaleBuiltinWebSearchPolicyPreset` called in `mergeRequiredSetupPolicyPresets`, `computeSetupPresetSuggestions`, and `setupPoliciesWithSelectionInner`.
Test follow-ups to resolve or justify

If these cover changed behavior, prefer adding them in this PR; otherwise state why existing coverage is enough or link the follow-up.

  • PRA-T1 Runtime validation — Hermes Tavily runtime body rewrite integration test: build Hermes image with NEMOCLAW_WEB_SEARCH_PROVIDER=tavily, start sandbox, execute search via Hermes Python runtime, capture egress, verify JSON body contains real API key. Runtime/sandbox/infrastructure paths need behavioral runtime validation: Dockerfile, agents/hermes/Dockerfile, agents/hermes/config/build-env.ts, agents/hermes/config/hermes-config.ts, agents/hermes/config/hermes-env.ts, agents/hermes/config/managed-tool-gateway.ts, agents/hermes/policy-permissive.yaml, agents/hermes/seed-dashboard-config.py. Missing Hermes Tavily runtime integration test and cross-path verification probes.
  • PRA-T2 Runtime validation — Cross-path verification probes: test Hermes with header rewrite probe, test OpenClaw with body rewrite probe, document expected behavior per agent. Runtime/sandbox/infrastructure paths need behavioral runtime validation: Dockerfile, agents/hermes/Dockerfile, agents/hermes/config/build-env.ts, agents/hermes/config/hermes-config.ts, agents/hermes/config/hermes-env.ts, agents/hermes/config/managed-tool-gateway.ts, agents/hermes/policy-permissive.yaml, agents/hermes/seed-dashboard-config.py. Missing Hermes Tavily runtime integration test and cross-path verification probes.
  • PRA-T3 Runtime validation — Non-interactive implicit provider selection with both BRAVE_API_KEY and TAVILY_API_KEY set: verify OpenClaw selects Brave (legacy compat), Hermes selects Tavily (only supported). Runtime/sandbox/infrastructure paths need behavioral runtime validation: Dockerfile, agents/hermes/Dockerfile, agents/hermes/config/build-env.ts, agents/hermes/config/hermes-config.ts, agents/hermes/config/hermes-env.ts, agents/hermes/config/managed-tool-gateway.ts, agents/hermes/policy-permissive.yaml, agents/hermes/seed-dashboard-config.py. Missing Hermes Tavily runtime integration test and cross-path verification probes.
  • PRA-T4 Runtime validation — Resume with web search config change + tier switch: recorded tier restricted with no web search, resume with Tavily + balanced tier, verify stale preset filter uses new tier. Runtime/sandbox/infrastructure paths need behavioral runtime validation: Dockerfile, agents/hermes/Dockerfile, agents/hermes/config/build-env.ts, agents/hermes/config/hermes-config.ts, agents/hermes/config/hermes-env.ts, agents/hermes/config/managed-tool-gateway.ts, agents/hermes/policy-permissive.yaml, agents/hermes/seed-dashboard-config.py. Missing Hermes Tavily runtime integration test and cross-path verification probes.
  • PRA-T5 No runtime integration test for Hermes Tavily body credential rewrite — Add integration test that builds Hermes image with Tavily, starts sandbox, executes search via Hermes Python runtime, captures egress, and verifies placeholder is rewritten in JSON body.
  • PRA-T6 Verification probes only test one rewrite path per agent — Add cross-path verification tests: test Hermes with header rewrite probe and OpenClaw with body rewrite probe. Document which path is expected to work for each agent.
  • PRA-T7 Acceptance clause — Configure OpenClaw's bundled Tavily extension and Hermes' native Tavily backend, including managed-tool conflict suppression and provider-specific runtime verification — add test evidence or identify existing coverage. OpenClaw: generate-openclaw-config.mts writes plugin config with placeholder. Hermes: hermes-config.ts writes web.backend: tavily, hermes-env.ts writes TAVILY_API_KEY placeholder. Conflict suppression: managed-tool-gateway.ts filters nous-web when Tavily selected. Gap: Hermes provider profile uses header auth instead of body rewrite (PRA-1)
  • PRA-T8 Acceptance clause — Add least-privilege Tavily network policies, Hermes request-body credential rewriting, and coverage in both agent-specific and global permissive policies — add test evidence or identify existing coverage. Policies added to tavily.yaml, agents/hermes/policy-permissive.yaml, agents/openclaw/policy-permissive.yaml with request_body_credential_rewrite: true and narrow POST rules. Gap: Hermes provider profile doesn't match body rewrite (PRA-1)
Since last review details

Current findings, using the urgency labels above:

PRA-1 Resolve/justify — Source-of-truth review needed: isStaleBuiltinWebSearchPolicyPreset in policy-selection.ts

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: onboard-policy-suggestions.test.ts: 'selects Tavily and removes the stale Brave tier default', 'adds all Hermes Nous tool policy presets for Hermes open tier only', 'restricted suppression list ⊇ env-gated additions (drift invariant)'
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: policy-selection.ts:47 isStaleBuiltinWebSearchPolicyPreset called in mergeRequiredSetupPolicyPresets, computeSetupPresetSuggestions, and setupPoliciesWithSelectionInner

PRA-2 Required — Hermes Tavily provider profile credential rewrite mismatch

  • Location: nemoclaw-blueprint/provider-profiles/tavily-hermes-v1.yaml:10
  • Category: security
  • Problem: Provider profile declares `auth_style: bearer` + `header_name: authorization` (header rewrite) but network policy preset and Hermes runtime expect JSON body rewrite (`request_body_credential_rewrite: true` with `api_key` field). Verification code tests body rewrite path. If OpenShell only consults provider profile credentials section, body rewrite won't activate for Hermes traffic.
  • Impact: Tavily search requests from Hermes will fail with 401/403 because the resolver placeholder is sent literally in the JSON body instead of being rewritten. No credential leak (placeholder is invalid), but feature is non-functional for Hermes users.
  • Required action: Change `tavily-hermes-v1.yaml` credentials to use body rewrite auth style (e.g., `auth_style: body`, `body_field: api_key`) if OpenShell supports it, OR confirm OpenShell applies both rewrite mechanisms for Hermes traffic. Add integration test verifying body rewrite works end-to-end for Hermes.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: Check OpenShell provider profile schema for body rewrite support; run Hermes sandbox with Tavily and capture egress request to verify placeholder is rewritten in JSON body (not Authorization header).
  • Missing regression test: Add runtime test: build Hermes image with Tavily, start sandbox, execute search request, verify request body contains real API key (not placeholder) and response returns results.
  • Done when: The required change is committed and verification passes: Check OpenShell provider profile schema for body rewrite support; run Hermes sandbox with Tavily and capture egress request to verify placeholder is rewritten in JSON body (not Authorization header).
  • Evidence: tavily.yaml:14 `request_body_credential_rewrite: true`; tavily-hermes-v1.yaml:10-11 `auth_style: bearer`, `header_name: authorization`; web-search-verify.ts:114-124 `buildTavilyBodyEgressProbeCommand` sends placeholder in JSON body

PRA-3 Resolve/justify — Dual credential rewrite mechanisms across provider profiles and verification

  • Location: src/lib/onboard/web-search-verify.ts:55
  • Category: security
  • Problem: Both `tavily.yaml` and `tavily-hermes-v1.yaml` declare `auth_style: bearer` + `header_name: authorization` in credentials section, but `request_body_credential_rewrite: true` in endpoints section. Verification uses body rewrite for Hermes (`buildTavilyBodyEgressProbeCommand`) and header rewrite for OpenClaw (`buildTavilyEgressProbeCommand`). Only one path tested per agent.
  • Impact: Uncertainty about which rewrite mechanism OpenShell enforces at runtime. If the untested path is the one used, Tavily requests may fail silently or send placeholders.
  • Recommended action: Standardize on one rewrite mechanism per provider per agent. For Hermes, prefer body rewrite (matches Hermes native `api_key` JSON field). For OpenClaw, verify which mechanism the OpenClaw Tavily plugin actually uses and align provider profile + verification accordingly. Document the chosen mechanism in provider profile comments.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect provider profile credentials vs endpoints sections; run verification probes for both agents and confirm the tested path matches actual runtime behavior.
  • Missing regression test: Add verification probes that test both rewrite paths for each agent, or document why only one path is needed per agent.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect provider profile credentials vs endpoints sections; run verification probes for both agents and confirm the tested path matches actual runtime behavior.
  • Evidence: tavily.yaml:13 `auth_style: bearer`; tavily-hermes-v1.yaml:16 `auth_style: bearer`; web-search-verify.ts:55 `buildTavilyEgressProbeCommand` (header) vs :75 `buildTavilyBodyEgressProbeCommand` (body)

PRA-4 Resolve/justify — Monolith growth in security-critical web search flow

  • Location: src/lib/onboard/web-search-flow.ts:1
  • Category: architecture
  • Problem: File grew by 197 lines (from 302 to 499). Contains provider prompting, credential validation, curl probes, recovery prompts, non-interactive resolution, and sandbox verification — all security-critical credential handling in one file. Reduced auditability and maintainability; harder to verify no credential interpolation into executable source occurs.
  • Impact: Reduced auditability and maintainability of security-critical code. Increases cognitive load for reviewers. Harder to verify no credential interpolation into executable source occurs.
  • Recommended action: Extract into separate modules: `web-search-provider-selection.ts` (prompting, non-interactive resolution), `web-search-credential-validation.ts` (API key validation, curl probes), `web-search-recovery.ts` (retry/skip prompts), `web-search-sandbox-verification.ts` (post-create probes). Keep security-critical credential handling in minimal, auditable units.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Verify each extracted module has a single responsibility and tests cover its boundaries.
  • Missing regression test: Ensure existing tests pass after extraction; add tests for module boundaries.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Verify each extracted module has a single responsibility and tests cover its boundaries.
  • Evidence: File grew from 302 to 499 lines (+197). Contains 6 distinct responsibilities mixed together.

PRA-5 Resolve/justify — Monolith growth in sandbox handler with web search threading

  • Location: src/lib/onboard/machine/handlers/sandbox.ts:1
  • Category: architecture
  • Problem: File grew by 113 lines (from 458 to 571). Contains `resolveWebSearchForCreation`, `effectiveHermesToolGatewaysForWebSearch`, and `prepareWebSearchSupport` mixed with state machine orchestration logic.
  • Impact: Sandbox state machine logic intertwined with web search provider resolution. Harder to verify sandbox creation correctness independently of web search logic.
  • Recommended action: Extract `resolveWebSearchForCreation`, `effectiveHermesToolGatewaysForWebSearch`, and `prepareWebSearchSupport` into dedicated `sandbox-web-search.ts` helper. Keep `sandbox.ts` focused on state machine orchestration.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Verify extracted helper has clear contract and sandbox.ts imports it cleanly.
  • Missing regression test: Ensure sandbox handler tests pass after extraction.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Verify extracted helper has clear contract and sandbox.ts imports it cleanly.
  • Evidence: File grew from 458 to 571 lines (+113). Three web-search functions embedded in state machine handler.

PRA-6 Resolve/justify — Monolith growth in policy selection with stale preset filtering

  • Location: src/lib/onboard/policy-selection.ts:1
  • Category: architecture
  • Problem: File grew by 54 lines (from 447 to 501). Contains stale preset filtering logic (`isStaleBuiltinWebSearchPolicyPreset`) mixed with tier/preset selection flow.
  • Impact: Policy selection logic coupled to web search provider drift handling. Stale preset filter is a workaround for build-time vs runtime config separation.
  • Recommended action: Extract stale preset filtering into dedicated `web-search-policy-presets.ts` with clear contract. Keep `policy-selection.ts` focused on tier/preset selection flow.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Verify extracted module has clear contract and policy-selection.ts imports it cleanly.
  • Missing regression test: Ensure policy selection tests pass after extraction.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Verify extracted module has clear contract and policy-selection.ts imports it cleanly.
  • Evidence: File grew from 447 to 501 lines (+54). `isStaleBuiltinWebSearchPolicyPreset` used in multiple places across the file.

PRA-7 Resolve/justify — No runtime integration test for Hermes Tavily body credential rewrite

  • Location: test/sandbox-provisioning-tavily.test.ts:1
  • Category: tests
  • Problem: Test file only covers OpenClaw bundled Tavily plugin path (inspects plugin, runs doctor with `TAVILY_API_KEY=openshell:resolve:env:TAVILY_API_KEY`). No runtime integration test for Hermes Tavily body credential rewrite — Hermes uses native Python runtime, not OpenClaw plugin.
  • Impact: Hermes Tavily body rewrite path is untested at runtime. The blocker PRA-1 could exist in production without detection.
  • Recommended action: Add integration test that builds Hermes image with Tavily, starts sandbox, executes search via Hermes Python runtime, captures egress, and verifies placeholder is rewritten in JSON body.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Run the new integration test and verify it passes with real Tavily API key.
  • Missing regression test: Add Hermes Tavily runtime integration test covering body credential rewrite end-to-end.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Run the new integration test and verify it passes with real Tavily API key.
  • Evidence: test/sandbox-provisioning-tavily.test.ts only mocks `openclaw plugins inspect tavily` and `doctor` — no Hermes sandbox creation or Python runtime execution.

PRA-8 Resolve/justify — Verification probes only test one rewrite path per agent

  • Location: src/lib/onboard/web-search-verify.test.ts:1
  • Category: tests
  • Problem: Tests verify Hermes with body rewrite probe and OpenClaw with header rewrite probe, but no cross-path tests: no test for Hermes with header rewrite probe, no test for OpenClaw with body rewrite probe. Leaves untested path per agent.
  • Impact: If OpenShell uses the untested rewrite path for either agent, the verification would pass but actual traffic would fail. No coverage for the mismatch identified in PRA-1.
  • Recommended action: Add cross-path verification tests: test Hermes with header rewrite probe and OpenClaw with body rewrite probe. Document which path is expected to work for each agent.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Run verification tests with both rewrite paths for each agent.
  • Missing regression test: Add test cases for the cross-path probes in web-search-verify.test.ts.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Run verification tests with both rewrite paths for each agent.
  • Evidence: web-search-verify.test.ts has 12 test cases but all use `buildTavilyBodyEgressProbeCommand` for Hermes and `buildTavilyEgressProbeCommand` for OpenClaw — no cross-testing.

PRA-9 Improvement — Web search support module could be consolidated

  • Location: src/lib/onboard/web-search-support.ts:1
  • Category: scope
  • Problem: Two separate modules (`web-search-support.ts` and `web-search-support.test.ts`) exist for agent web search support checks. Could be consolidated into single `agent-web-search-support.ts` if separation is not intentional for test isolation.
  • Impact: Minor — duplication of file structure without clear separation of concerns.
  • Suggested action: Consolidate agent web search support checks into single `agent-web-search-support.ts` if separation is not intentional for test isolation. Or confirm this separation is intentional.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Check if the two modules serve distinct purposes or can be merged.
  • Missing regression test: N/A - refactoring only.
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: web-search-support.ts exports `agentSupportsWebSearch` and `agentSupportsWebSearchProvider`; test file tests both. No other consumers of the separation.

PRA-10 Improvement — Stale preset filtering is a localized workaround for provider/policy drift

  • Location: src/lib/onboard/policy-selection.ts:47
  • Category: architecture
  • Problem: `isStaleBuiltinWebSearchPolicyPreset` filters stale `brave`/`tavily`/`nous-web` presets based on current web search config. This handles the invalid state where provider selection (build-time) and policy presets (runtime) can drift. Root cause: separate build-time vs runtime config model.
  • Impact: Workaround masks the underlying config model issue. If provider selection and policy application were unified, this filter would be unnecessary.
  • Suggested action: Document the workaround with source-of-truth answers: invalid state = provider/policy drift; source boundary = separate build-time (Dockerfile ARGs) vs runtime (policy presets) config; why not fix here = would require unified config model across image build and runtime; regression test = `onboard-policy-suggestions.test.ts` stale preset tests; removal condition = unified web search config in openclaw.json/hermes config.yaml.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Review `onboard-policy-suggestions.test.ts` tests for stale preset filtering behavior.
  • Missing regression test: Existing `onboard-policy-suggestions.test.ts` covers stale preset filtering — ensure it remains passing.
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: policy-selection.ts:47 `isStaleBuiltinWebSearchPolicyPreset` called in `mergeRequiredSetupPolicyPresets`, `computeSetupPresetSuggestions`, and `setupPoliciesWithSelectionInner`.

Workflow run details

This is an automated, non-binding review; it still expects maintainers and agents to respond to each required or warning item. Treat suggestions as current-PR improvements when they touch changed code; defer only with maintainer rationale or a linked follow-up. A human maintainer must make the final merge decision.

@github-code-quality

github-code-quality Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Overview

Languages: TypeScript

TypeScript / code-coverage/plugin

The overall coverage in the codex/tavily-web-sea... branch is 96%. Coverage data for the main branch is not yet available.

Show a code coverage summary of the most covered files.
File main codex/tavily-web-sea... e86fb6e +/-
nemoclaw/src/se...cret-scanner.ts 100%
nemoclaw/src/commands/slash.ts 100%
nemoclaw/src/bl...eprint/state.ts 98%
nemoclaw/src/onboard/config.ts 98%
nemoclaw/src/bl...int/snapshot.ts 97%
nemoclaw/src/blueprint/ssrf.ts 97%
nemoclaw/src/bl...print/runner.ts 95%
nemoclaw/src/co...ration-state.ts 94%
nemoclaw/src/bl...ate-networks.ts 94%
nemoclaw/src/index.ts 94%

TypeScript / code-coverage/cli

The overall coverage in the codex/tavily-web-sea... branch is 70%. Coverage data for the main branch is not yet available.

Show a code coverage summary of the most covered files.
File main codex/tavily-web-sea... e86fb6e +/-
src/lib/actions...all/run-plan.ts 81%
src/lib/actions...dbox/rebuild.ts 80%
src/lib/state/o...oard-session.ts 78%
src/lib/shields/index.ts 75%
src/lib/state/sandbox.ts 74%
src/lib/policy/index.ts 70%
src/lib/onboard...er-gpu-patch.ts 69%
src/lib/onboard/preflight.ts 69%
src/lib/actions...licy-channel.ts 57%
src/lib/onboard.ts 20%

Updated July 03, 2026 19:27 UTC
Code Coverage is in Public Preview. Learn more and provide us with your feedback.

@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

E2E Advisor Recommendation

Required E2E: onboard-resume, onboard-repair, cloud-onboard, full-e2e, brave-search, network-policy, hermes-e2e, hermes-dashboard, security-posture
Optional E2E: rebuild-openclaw, rebuild-hermes, messaging-providers, state-backup-restore

Dispatch hint: onboard-resume,onboard-repair,cloud-onboard,full-e2e,brave-search,network-policy,hermes-e2e,hermes-dashboard,security-posture

Workflow run

Full advisor summary

E2E Recommendation Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required E2E

  • onboard-resume (medium): Required by the onboarding resume rule: live onboarding machine/resume state handling and session persistence changed, so the interruption/resume path must be validated end-to-end.
  • onboard-repair (medium): Required by the onboarding resume rule: sandbox lifecycle repair and resume conflict handling changed through onboarding machine handlers/session state, so missing-sandbox repair must run live.
  • cloud-onboard (high): Installer, hosted onboarding, OpenClaw Dockerfile/config, policy presets, and web-search onboarding changed; validate the public installer and full hosted onboarding path with a real sandbox.
  • full-e2e (high): OpenClaw Dockerfile, generated config, onboarding flow, sandbox lifecycle, inference routing, and ready-summary behavior changed; run the default OpenClaw real assistant flow.
  • brave-search (medium): The existing OpenClaw web-search E2E is Brave-specific and should catch regressions from the new provider abstraction in config generation, provider registration, policy application, credential hiding, and real search execution.
  • network-policy (high): Tavily policy assets, permissive policy files, policy preset selection, and request-body credential rewrite boundaries changed; run live allow/deny and policy-add probes.
  • hermes-e2e (high): Hermes image build args, generated config/env, managed tool gateway selection, policy, gateway startup, and hosted inference path changed; validate a full Hermes onboard/runtime flow.
  • hermes-dashboard (high): agents/hermes/seed-dashboard-config.py changed privilege-boundary mirroring for routing, web backend, and env placeholders; run the Hermes dashboard-enabled live path.
  • security-posture (high): Credential/secret-boundary behavior changed through Hermes dashboard env mirroring, Tavily resolver placeholders, Dockerfile runtime env, and policy credential rewrite; validate hardened OpenClaw and Hermes postures live.

Optional E2E

  • rebuild-openclaw (high): Useful adjacent confidence because web-search provider selection and OpenClaw config merge are build-time inputs and changing provider requires recreate/rebuild behavior.
  • rebuild-hermes (high): Useful adjacent confidence for Hermes config/env generation and state preservation across rebuilds after adding Tavily web backend and managed-tool preset filtering.
  • messaging-providers (high): Messaging prep and build-applier code changed near provider placeholder handling; run if maintainers want extra confidence that existing channel credential/provider rendering still works.
  • state-backup-restore (medium): Optional coverage for sandbox recreation/state preservation paths mentioned by the new web-search-provider change flow and touched OpenClaw config merge/session state code.

New E2E recommendations

  • OpenClaw Tavily web search (high): Existing web-search live coverage is Brave-only. This PR adds Tavily provider profiles, policy preset, OpenClaw config generation, credential registration, and request-body/header rewrite behavior that are not exercised by an existing OpenClaw Tavily E2E.
    • Suggested test: Add a free-standing tavily-search or parameterized web-search E2E that onboards OpenClaw with NEMOCLAW_WEB_SEARCH_PROVIDER=tavily, asserts policy includes only Tavily /search and /extract, verifies openclaw.json selects Tavily without raw TAVILY_API_KEY, and performs a real search through the sandbox egress path.
  • Hermes Tavily web backend (high): No existing Hermes E2E enables Tavily or validates web.backend: tavily, .env resolver placeholder handling, dashboard config seeding of the web backend, or conflict handling with the Nous managed web gateway.
    • Suggested test: Add a hermes-tavily-search E2E that onboards Hermes with NEMOCLAW_WEB_SEARCH_PROVIDER=tavily, validates gateway and dashboard configs/env contain only the resolver placeholder, confirms nous-web is removed from effective managed-tool presets when both are selected, and performs Tavily search/extract through OpenShell request-body credential rewrite.
  • Tavily credential rewrite security (medium): The new Tavily policy relies on JSON request-body credential rewrite, a different secret injection surface from the existing Brave header-token E2E.
    • Suggested test: Add a focused egress-policy E2E using a controlled Tavily-compatible test endpoint or live Tavily call to assert the sandbox sees only openshell:resolve:env:TAVILY_API_KEY, the gateway rewrites the request body at egress, and raw keys are absent from sandbox env/config/logs.

Dispatch hint

  • Workflow: .github/workflows/e2e.yaml
  • jobs input: onboard-resume,onboard-repair,cloud-onboard,full-e2e,brave-search,network-policy,hermes-e2e,hermes-dashboard,security-posture

@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

E2E Target Recommendation

Required E2E targets: ubuntu-repo-cloud-openclaw, onboard-resume, onboard-repair, brave-search
Optional E2E targets: ubuntu-repo-cloud-langchain-deepagents-code

Dispatch required E2E targets:

  • gh workflow run e2e.yaml --ref <pr-head-ref> --field targets=ubuntu-repo-cloud-openclaw
  • gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=onboard-resume
  • gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=onboard-repair
  • gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=brave-search

Workflow run

Full E2E target advisor summary

E2E Target Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required E2E targets

  • ubuntu-repo-cloud-openclaw: OpenClaw Dockerfile/config generation, onboarding web-search selection, policy presets, and sandbox provisioning paths changed; the live-supported Ubuntu OpenClaw cloud target is the smallest registry target that exercises the default onboard/build/runtime path.
    • Dispatch: gh workflow run e2e.yaml --ref <pr-head-ref> --field targets=ubuntu-repo-cloud-openclaw
  • onboard-resume: Changes under src/lib/onboard/machine, src/lib/state/onboard-session.ts, and onboarding flow/policy selection code affect resume state handling and onboarding state transitions; the onboarding resume rule requires this live job.
    • Dispatch: gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=onboard-resume
  • onboard-repair: The same onboarding state-machine and persisted-session changes can affect repair/backstop execution from saved sessions, so repair is required alongside resume for these paths.
    • Dispatch: gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=onboard-repair
  • brave-search: The PR changes OpenClaw web-search provider selection, generated config, credential placeholder handling, verification, Docker image behavior, and policy presets. The wired web-search live job is the focused dispatch available in e2e.yaml.
    • Dispatch: gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=brave-search

Optional E2E targets

  • ubuntu-repo-cloud-langchain-deepagents-code: The PR updates Tavily policy/provider-profile material and a Deep Agents Code Tavily opt-in E2E check, but the primary changed onboarding and image surfaces are OpenClaw/Hermes. Run this adjacent live-supported target if you want extra confidence for the terminal-agent Tavily policy surface.
    • Dispatch: gh workflow run e2e.yaml --ref <pr-head-ref> --field targets=ubuntu-repo-cloud-langchain-deepagents-code

Relevant changed files

  • Dockerfile
  • agents/hermes/Dockerfile
  • agents/hermes/config/build-env.ts
  • agents/hermes/config/hermes-config.ts
  • agents/hermes/config/hermes-env.ts
  • agents/hermes/config/managed-tool-gateway.ts
  • agents/hermes/policy-permissive.yaml
  • agents/hermes/seed-dashboard-config.py
  • agents/openclaw/policy-permissive.yaml
  • nemoclaw-blueprint/policies/openclaw-sandbox-permissive.yaml
  • nemoclaw-blueprint/policies/presets/tavily.yaml
  • nemoclaw-blueprint/provider-profiles/tavily-hermes-v1.yaml
  • nemoclaw-blueprint/provider-profiles/tavily.yaml
  • scripts/generate-openclaw-config.mts
  • scripts/install.sh
  • src/lib/inference/web-search.ts
  • src/lib/messaging/applier/build/messaging-build-applier.mts
  • src/lib/onboard.ts
  • src/lib/onboard/brave-provider-profile.ts
  • src/lib/onboard/dockerfile-patch.ts
  • src/lib/onboard/extra-placeholder-keys.ts
  • src/lib/onboard/machine/core-flow-phases.ts
  • src/lib/onboard/machine/final-flow-phases.ts
  • src/lib/onboard/machine/flow-context.ts
  • src/lib/onboard/machine/handlers/policies.ts
  • src/lib/onboard/machine/handlers/sandbox.ts
  • src/lib/onboard/messaging-prep.ts
  • src/lib/onboard/policy-presets.ts
  • src/lib/onboard/policy-resume-selection.ts
  • src/lib/onboard/policy-selection.ts
  • src/lib/onboard/sandbox-messaging-preflight.ts
  • src/lib/onboard/sandbox-provider-cleanup.ts
  • src/lib/onboard/summary.ts
  • src/lib/onboard/web-search-flow.ts
  • src/lib/onboard/web-search-support.ts
  • src/lib/onboard/web-search-verify.ts
  • src/lib/policy/index.ts
  • src/lib/state/onboard-session.ts
  • src/lib/state/openclaw-config-merge.ts
  • test/e2e/e2e-cloud-experimental/checks/09-deepagents-code-tavily-opt-in.sh

@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

PR Review Advisor — No blocking findings

Merge posture: No blocking advisor findings
Primary next action: Add or justify PRA-T1 and any related test follow-ups.
Open items: 0 required · 0 warnings · 1 suggestion · 5 test follow-ups
Since last review: 0 prior items resolved · 1 still applies · 0 new items found

Action checklist

  • PRA-T1 Add or justify test follow-up: Runtime validation
  • PRA-T2 Add or justify test follow-up: Runtime validation
  • PRA-T3 Add or justify test follow-up: Runtime validation
  • PRA-T4 Add or justify test follow-up: Runtime validation
  • PRA-T5 Add or justify test follow-up: Acceptance clause
  • PRA-1 In-scope improvement: Shrink provider-specific web-search request builders out of the flow in src/lib/onboard/web-search-flow.ts:35

Findings index

ID Severity Category Location Required action
PRA-1 Improvement architecture src/lib/onboard/web-search-flow.ts:35 In this PR, consider extracting `WEB_SEARCH_PROVIDER_SPECS`, provider-specific curl header construction, and provider-specific validation argument construction into a narrow web-search provider registry/helper imported by the flow and tests. Keep prompting, credential persistence, redaction, sandbox verification dispatch, and all existing validation boundaries unchanged.
Review findings by urgency: 0 required fixes, 0 items to resolve/justify, 1 in-scope improvement

⚠️ Resolve or justify before merge

Investigate these in the current review; either fix them, explain why they are not applicable, or document the accepted risk.

  • None.

💡 In-scope improvements

These are lower-risk, not throwaway. Prefer fixing them in this PR when they are local to changed code; defer only with rationale or a linked follow-up.

PRA-1 Improvement — Shrink provider-specific web-search request builders out of the flow

  • Location: src/lib/onboard/web-search-flow.ts:35
  • Category: architecture
  • Problem: `web-search-flow.ts` still owns provider specs, help URLs, curl auth-header construction, validation request construction, prompting, credential staging, non-interactive resolution, and sandbox verification dispatch. The behavior is covered and the security controls appear intact, but keeping provider-specific request builders inside the orchestration module increases drift risk for the next provider.
  • Impact: Future provider additions or edits could duplicate request-shape logic and accidentally bypass CR/LF/NUL rejection, the temporary 0600 curl config path, provider allowlisting, credential redaction, or placeholder-only sandbox verification because those boundaries are mixed with interactive flow control.
  • Suggested action: In this PR, consider extracting `WEB_SEARCH_PROVIDER_SPECS`, provider-specific curl header construction, and provider-specific validation argument construction into a narrow web-search provider registry/helper imported by the flow and tests. Keep prompting, credential persistence, redaction, sandbox verification dispatch, and all existing validation boundaries unchanged.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Read `src/lib/onboard/web-search-flow.ts` around the provider spec table and `curlConfigHeaders`/`validationArgs`, then confirm the extracted helper is the only place mapping provider names to credential env keys, auth headers, help URLs, and validation probe args.
  • Missing regression test: Existing tests in `src/lib/onboard/web-search-flow.test.ts` already cover CR/LF rejection, keys staying out of curl argv, Tavily POST validation, provider precedence, saved credential precedence, unsupported Hermes Brave selection, and interactive provider selection. Keep those passing after extraction; add a focused helper test only if the registry/helper becomes separately exported.
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: `src/lib/onboard/web-search-flow.ts` defines `BRAVE_SEARCH_HELP_URL`, `TAVILY_SEARCH_HELP_URL`, `CURL_CONFIG_PREFIX`, `WEB_SEARCH_PROVIDER_SPECS`, `curlConfigHeaders`, `validationArgs`, prompt handling, credential staging, non-interactive resolution, and verification dispatch in one module that now grew substantially.
Simplification opportunities: 1 possible cut

These are safe simplification checks only. Do not remove validation, security controls, data-loss prevention, or required tests.

  • PRA-1 shrink (src/lib/onboard/web-search-flow.ts:35): Provider-specific metadata and curl validation builders from `src/lib/onboard/web-search-flow.ts`.
    • Replacement: A narrow provider registry/helper used by `createWebSearchFlowHelpers` and existing flow tests.
    • Safety boundary: Do not remove provider allowlisting, credential redaction, CR/LF/NUL rejection, temporary 0600 curl config use, OpenShell resolver placeholders, or raw-secret refusal in sandbox verification.
Test follow-ups to resolve or justify

If these cover changed behavior, prefer adding them in this PR; otherwise state why existing coverage is enough or link the follow-up.

  • PRA-T1 Runtime validation — OpenClaw Tavily runtime provider rewrite and denial: create a Tavily-enabled OpenClaw sandbox, verify `<sandbox>-tavily-search` is attached, `openclaw.json` contains only `openshell:resolve:env:TAVILY_API_KEY`, `POST /search` succeeds through Tavily header rewrite, and an unlisted Tavily method/path is denied.. Static and spawned-script coverage is broad for provider selection, credential validation, Dockerfile config generation, policy/profile shape, Hermes dashboard seeding, stale provider cleanup, and restore/recreate reconciliation. The remaining confidence gap is built-image/OpenShell behavior: real provider attachment, live L7 header/body credential rewrite, and live policy method/path denial.
  • PRA-T2 Runtime validation — Hermes Tavily runtime body rewrite: create a Tavily-enabled Hermes sandbox, verify the `tavily-hermes-v1` provider is attached, `/sandbox/.hermes/config.yaml` contains `web.backend: tavily`, `/sandbox/.hermes/.env` contains only the resolver placeholder, and a JSON `api_key` body placeholder is rewritten for `POST /search` without exposing the raw key in process argv or config files.. Static and spawned-script coverage is broad for provider selection, credential validation, Dockerfile config generation, policy/profile shape, Hermes dashboard seeding, stale provider cleanup, and restore/recreate reconciliation. The remaining confidence gap is built-image/OpenShell behavior: real provider attachment, live L7 header/body credential rewrite, and live policy method/path denial.
  • PRA-T3 Runtime validation — Provider switch/disable live cleanup: re-onboard from Tavily to `NEMOCLAW_WEB_SEARCH_PROVIDER=none` or Brave and accept recreation, then verify stale Tavily/Brave generated config, policy suggestions, and provider attachments are removed while unrelated managed Nous tools and custom user plugins remain.. Static and spawned-script coverage is broad for provider selection, credential validation, Dockerfile config generation, policy/profile shape, Hermes dashboard seeding, stale provider cleanup, and restore/recreate reconciliation. The remaining confidence gap is built-image/OpenShell behavior: real provider attachment, live L7 header/body credential rewrite, and live policy method/path denial.
  • PRA-T4 Runtime validation — Acceptance issue mapping: obtain issue feat(onboard): extend web search onboarding to Gemini and Tavily providers #2718 body and comments from a trusted source and map each literal clause to this PR's diff/tests, adding focused tests for any uncovered acceptance clause.. Static and spawned-script coverage is broad for provider selection, credential validation, Dockerfile config generation, policy/profile shape, Hermes dashboard seeding, stale provider cleanup, and restore/recreate reconciliation. The remaining confidence gap is built-image/OpenShell behavior: real provider attachment, live L7 header/body credential rewrite, and live policy method/path denial.
  • PRA-T5 Acceptance clause — PR body references issue feat(onboard): extend web search onboarding to Gemini and Tavily providers #2718, but no deterministic linked issue body or comments were provided. — add test evidence or identify existing coverage. `linkedIssues` is empty in the deterministic validation context, and PR body text is untrusted evidence only. The diff and tests show Tavily web-search implementation paths, but literal issue feat(onboard): extend web search onboarding to Gemini and Tavily providers #2718 clauses/comments were not available to map.
Since last review details

Current findings, using the urgency labels above:

PRA-1 Improvement — Shrink provider-specific web-search request builders out of the flow

  • Location: src/lib/onboard/web-search-flow.ts:35
  • Category: architecture
  • Problem: `web-search-flow.ts` still owns provider specs, help URLs, curl auth-header construction, validation request construction, prompting, credential staging, non-interactive resolution, and sandbox verification dispatch. The behavior is covered and the security controls appear intact, but keeping provider-specific request builders inside the orchestration module increases drift risk for the next provider.
  • Impact: Future provider additions or edits could duplicate request-shape logic and accidentally bypass CR/LF/NUL rejection, the temporary 0600 curl config path, provider allowlisting, credential redaction, or placeholder-only sandbox verification because those boundaries are mixed with interactive flow control.
  • Suggested action: In this PR, consider extracting `WEB_SEARCH_PROVIDER_SPECS`, provider-specific curl header construction, and provider-specific validation argument construction into a narrow web-search provider registry/helper imported by the flow and tests. Keep prompting, credential persistence, redaction, sandbox verification dispatch, and all existing validation boundaries unchanged.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Read `src/lib/onboard/web-search-flow.ts` around the provider spec table and `curlConfigHeaders`/`validationArgs`, then confirm the extracted helper is the only place mapping provider names to credential env keys, auth headers, help URLs, and validation probe args.
  • Missing regression test: Existing tests in `src/lib/onboard/web-search-flow.test.ts` already cover CR/LF rejection, keys staying out of curl argv, Tavily POST validation, provider precedence, saved credential precedence, unsupported Hermes Brave selection, and interactive provider selection. Keep those passing after extraction; add a focused helper test only if the registry/helper becomes separately exported.
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: `src/lib/onboard/web-search-flow.ts` defines `BRAVE_SEARCH_HELP_URL`, `TAVILY_SEARCH_HELP_URL`, `CURL_CONFIG_PREFIX`, `WEB_SEARCH_PROVIDER_SPECS`, `curlConfigHeaders`, `validationArgs`, prompt handling, credential staging, non-interactive resolution, and verification dispatch in one module that now grew substantially.

Workflow run details

This is an automated, non-binding review; it still expects maintainers and agents to respond to each required or warning item. Treat suggestions as current-PR improvements when they touch changed code; defer only with maintainer rationale or a linked follow-up. A human maintainer must make the final merge decision.

Comment thread src/lib/onboard/web-search-flow.test.ts Fixed

@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.

Actionable comments posted: 3

🧹 Nitpick comments (8)
scripts/generate-openclaw-config.mts (1)

76-80: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Reuse the shared web-search provider contract here. scripts/generate-openclaw-config.mts can import src/lib/inference/web-search.ts under node --experimental-strip-types, so the brave/tavily literals and local WebSearchProvider alias don’t need to be redefined in this script; keeping them in one place avoids drift.

🤖 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/generate-openclaw-config.mts` around lines 76 - 80, The web-search
provider contract is being duplicated in the config generation script, which can
drift from the shared source of truth. Update generate-openclaw-config.mts to
import and reuse the provider definitions from src/lib/inference/web-search.ts
instead of redefining WEB_SEARCH_PROVIDERS and WebSearchProvider locally, and
make sure the script continues to reference the shared provider symbols when
building the config.
test/sandbox-provisioning-tavily.test.ts (1)

12-36: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Duplicated dockerRunCommandBetween helper.

This function is identical to the one in test/sandbox-provisioning.test.ts (lines 27-57 per provided context). Consider extracting it to a shared test helper module to avoid drift between the two copies.

🤖 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/sandbox-provisioning-tavily.test.ts` around lines 12 - 36, The
dockerRunCommandBetween helper is duplicated and should be shared to avoid
divergence. Move the logic currently in dockerRunCommandBetween into a common
test utility module and update both sandbox provisioning tests to import and use
that shared helper, keeping the existing behavior and error messages intact.
src/lib/onboard/web-search-flow.ts (1)

252-262: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

stageValidatedCredential always writes to the real process.env, defeating test isolation.

process.env[envKey] = apiKey at Line 261 runs unconditionally, even when a test injects a custom env object and a mocked saveCredential. This is why web-search-flow.test.ts needs manual delete process.env.TAVILY_API_KEY cleanup in multiple tests — without it, credentials leak into the real environment for the remainder of the test run.

♻️ Proposed fix: only touch the real env when no override is injected
   function stageValidatedCredential(provider: WebSearchProvider, apiKey: string): void {
     const envKey = webSearchEnvFor(provider);
     persistCredential(envKey, apiKey);
     env[envKey] = apiKey;
-    process.env[envKey] = apiKey;
+    if (env !== process.env) process.env[envKey] = apiKey;
   }
🤖 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 `@src/lib/onboard/web-search-flow.ts` around lines 252 - 262,
stageValidatedCredential currently mutates the real process.env on every call,
which breaks test isolation when a custom env override is injected. Update
stageValidatedCredential to continue persisting and updating the local env
object, but only assign to process.env[envKey] when the function is running
without an injected override (or otherwise detect that env is the real
process.env). Use the existing symbols stageValidatedCredential,
configuredCredential, env, and process.env to keep the fix scoped and avoid
credential leakage across tests.
src/lib/state/openclaw-config-merge.ts (1)

24-27: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Wire managedWebSearchConfigPaths into mergeOpenClawTools, or remove the unused contract. managedWebSearchConfigPaths is declared but never read, while mergeOpenClawTools still hardcodes tools.web.search; keeping both invites drift between the documented ownership contract and the actual merge behavior.

🤖 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 `@src/lib/state/openclaw-config-merge.ts` around lines 24 - 27,
`managedWebSearchConfigPaths` is declared in the openclaw config merge contract
but never used, while `mergeOpenClawTools` still hardcodes the web search path.
Update `mergeOpenClawTools` in `openclaw-config-merge` to consume
`managedWebSearchConfigPaths` when deciding which config paths are owned by a
fresh web-search selection, or remove `managedWebSearchConfigPaths` from the
contract if it is not intended to drive merge behavior. Keep the behavior and
the documented ownership fields in sync with `managedWebSearchPluginEntries` and
`mergeOpenClawTools`.
src/lib/onboard/web-search-verify.ts (1)

255-265: 🚀 Performance & Scalability | 🔵 Trivial

Tavily 401/403 gets no remediation hint, unlike Brave.

The provider === "brave" guard means Tavily auth failures (401/403) only get the generic "returned HTTP {status}" warning, without the recreate-sandbox guidance Brave gets for the equivalent "stale profile type" failure mode. If Tavily can hit the same legacy-profile-type failure class, consider extending the hint.

🤖 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 `@src/lib/onboard/web-search-verify.ts` around lines 255 - 265, The 401/403
remediation hint in web-search verification is only applied for the brave
provider, so Tavily failures fall back to the generic warning. Update the
conditional in onboard/web-search-verify.ts around the provider/status check to
include Tavily where the same legacy-profile-type failure can occur, and keep
the existing recreate-sandbox guidance in the shared warn path so both providers
get the same hint.
src/lib/onboard/messaging-prep.ts (1)

81-90: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

src/lib/onboard/messaging-prep.ts:50,90-100 Remove the deprecated missingBraveApiKey alias and switch the remaining tests to missingWebSearchCredentialEnv; it has no runtime readers, and there’s no retirement link or exit criteria for keeping it.

🤖 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 `@src/lib/onboard/messaging-prep.ts` around lines 81 - 90, Remove the
deprecated missingBraveApiKey alias from messaging-prep logic and keep using
missingWebSearchCredentialEnv as the single source of truth. Update any related
branching in the onboarding flow and adjust the tests/fixtures that still assert
the old alias so they reference the remaining symbol instead. Ensure the cleanup
is applied around braveProviderProfile.shouldEnableWebSearch and
webSearch.webSearchEnvFor usage so there are no dead reads left.
src/lib/onboard/machine/handlers/sandbox.ts (2)

173-180: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Inject env instead of reading process.env directly.

resolveRequestedWebSearchConfig reads process.env[WEB_SEARCH_PROVIDER_ENV] directly, unlike every other capability in SandboxStateFlow, which goes through this.deps.*, and unlike web-search-flow.ts's equivalent helpers, which resolve env = deps.env ?? process.env and thread it through. This couples sandbox state resolution to the global process object and is inconsistent with the DI pattern used elsewhere in this file.

♻️ Suggested refactor
-function resolveRequestedWebSearchConfig<WebSearchConfig>(
-  current: WebSearchConfig | null,
-): WebSearchConfig | null {
-  const explicit = parseExplicitWebSearchProvider(process.env[WEB_SEARCH_PROVIDER_ENV]);
+function resolveRequestedWebSearchConfig<WebSearchConfig>(
+  current: WebSearchConfig | null,
+  env: NodeJS.ProcessEnv = process.env,
+): WebSearchConfig | null {
+  const explicit = parseExplicitWebSearchProvider(env[WEB_SEARCH_PROVIDER_ENV]);
🤖 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 `@src/lib/onboard/machine/handlers/sandbox.ts` around lines 173 - 180,
resolveRequestedWebSearchConfig currently reads process.env directly, which
breaks the dependency-injection pattern used by SandboxStateFlow and the
web-search helpers. Update the function to accept an env source (or use the
existing deps.env pattern from the surrounding flow), then pass that env through
to parseExplicitWebSearchProvider instead of accessing
process.env[WEB_SEARCH_PROVIDER_ENV] inline. Keep the change localized to
resolveRequestedWebSearchConfig and its call sites so the sandbox state
resolution stays consistent with the rest of the file.

506-518: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Note text can be misleading when no other Hermes tools remain.

When hermesToolGateways was originally just ["nous-web"], the filtered result is empty, but the note still says "keeping the other selected Nous tools," which is inaccurate in that case.

💬 Suggested fix
     if (
       this.options.hermesToolGateways.includes("nous-web") &&
       !hermesToolGateways.includes("nous-web")
     ) {
-      this.deps.note(
-        "  Tavily Search replaces Hermes managed Web search/extract; keeping the other selected Nous tools.",
-      );
+      this.deps.note(
+        hermesToolGateways.length > 0
+          ? "  Tavily Search replaces Hermes managed Web search/extract; keeping the other selected Nous tools."
+          : "  Tavily Search replaces Hermes managed Web search/extract.",
+      );
     }
🤖 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 `@src/lib/onboard/machine/handlers/sandbox.ts` around lines 506 - 518, The note
in sandbox.ts is too broad because when
effectiveHermesToolGatewaysForWebSearch() filters out the only selected Hermes
gateway ("nous-web"), there are no remaining Nous tools to keep. Update the
conditional around this.deps.note so it distinguishes between “some Hermes tools
remain” and “none remain,” and change the message accordingly using
hermesToolGateways, this.options.hermesToolGateways, and the existing note call
to avoid misleading text.
🤖 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.

Inline comments:
In `@docs/reference/commands-nemohermes.mdx`:
- Around line 1969-1971: The environment-variable table in the Hermes-only
reference still describes OpenClaw-specific Brave/Tavily behavior, which
conflicts with the Hermes-only prose. Update the rows for
NEMOCLAW_WEB_SEARCH_PROVIDER and BRAVE_API_KEY in the command reference so they
only describe Hermes-supported web search behavior, remove Brave-first/OpenClaw
precedence wording, and ensure the table matches the existing Hermes-only
guidance elsewhere in the page.

In `@nemoclaw-blueprint/policies/presets/tavily.yaml`:
- Around line 21-26: The Tavily allowlist comment in the binaries block is
inaccurate because it says both Python paths are exact, but the entry in the
policy uses a glob for the managed interpreter. Update the comment near the
binaries entries to reflect the real invariant in this preset, keeping the
wording aligned with the actual path patterns used in the Tavily egress boundary
and referring to the path entries themselves rather than implying both are
exact.

In `@src/lib/state/openclaw-config-merge.ts`:
- Around line 130-147: The early return in mergeOpenClawTools bypasses the
fresh-generator ownership rule for tools.web.search, so a missing currentTools
can restore stale backup web-search settings. Update mergeOpenClawTools to
always apply the search-preservation/omission logic after choosing the fallback
source, ensuring the merged result never reintroduces backup tools.web.search
when currentTools omits it. Use the mergeJsonObjects, cloneJson, and
isPlainJsonObject handling in mergeOpenClawTools to preserve unrelated web
settings while forcing search to follow the currentTools state.

---

Nitpick comments:
In `@scripts/generate-openclaw-config.mts`:
- Around line 76-80: The web-search provider contract is being duplicated in the
config generation script, which can drift from the shared source of truth.
Update generate-openclaw-config.mts to import and reuse the provider definitions
from src/lib/inference/web-search.ts instead of redefining WEB_SEARCH_PROVIDERS
and WebSearchProvider locally, and make sure the script continues to reference
the shared provider symbols when building the config.

In `@src/lib/onboard/machine/handlers/sandbox.ts`:
- Around line 173-180: resolveRequestedWebSearchConfig currently reads
process.env directly, which breaks the dependency-injection pattern used by
SandboxStateFlow and the web-search helpers. Update the function to accept an
env source (or use the existing deps.env pattern from the surrounding flow),
then pass that env through to parseExplicitWebSearchProvider instead of
accessing process.env[WEB_SEARCH_PROVIDER_ENV] inline. Keep the change localized
to resolveRequestedWebSearchConfig and its call sites so the sandbox state
resolution stays consistent with the rest of the file.
- Around line 506-518: The note in sandbox.ts is too broad because when
effectiveHermesToolGatewaysForWebSearch() filters out the only selected Hermes
gateway ("nous-web"), there are no remaining Nous tools to keep. Update the
conditional around this.deps.note so it distinguishes between “some Hermes tools
remain” and “none remain,” and change the message accordingly using
hermesToolGateways, this.options.hermesToolGateways, and the existing note call
to avoid misleading text.

In `@src/lib/onboard/messaging-prep.ts`:
- Around line 81-90: Remove the deprecated missingBraveApiKey alias from
messaging-prep logic and keep using missingWebSearchCredentialEnv as the single
source of truth. Update any related branching in the onboarding flow and adjust
the tests/fixtures that still assert the old alias so they reference the
remaining symbol instead. Ensure the cleanup is applied around
braveProviderProfile.shouldEnableWebSearch and webSearch.webSearchEnvFor usage
so there are no dead reads left.

In `@src/lib/onboard/web-search-flow.ts`:
- Around line 252-262: stageValidatedCredential currently mutates the real
process.env on every call, which breaks test isolation when a custom env
override is injected. Update stageValidatedCredential to continue persisting and
updating the local env object, but only assign to process.env[envKey] when the
function is running without an injected override (or otherwise detect that env
is the real process.env). Use the existing symbols stageValidatedCredential,
configuredCredential, env, and process.env to keep the fix scoped and avoid
credential leakage across tests.

In `@src/lib/onboard/web-search-verify.ts`:
- Around line 255-265: The 401/403 remediation hint in web-search verification
is only applied for the brave provider, so Tavily failures fall back to the
generic warning. Update the conditional in onboard/web-search-verify.ts around
the provider/status check to include Tavily where the same legacy-profile-type
failure can occur, and keep the existing recreate-sandbox guidance in the shared
warn path so both providers get the same hint.

In `@src/lib/state/openclaw-config-merge.ts`:
- Around line 24-27: `managedWebSearchConfigPaths` is declared in the openclaw
config merge contract but never used, while `mergeOpenClawTools` still hardcodes
the web search path. Update `mergeOpenClawTools` in `openclaw-config-merge` to
consume `managedWebSearchConfigPaths` when deciding which config paths are owned
by a fresh web-search selection, or remove `managedWebSearchConfigPaths` from
the contract if it is not intended to drive merge behavior. Keep the behavior
and the documented ownership fields in sync with `managedWebSearchPluginEntries`
and `mergeOpenClawTools`.

In `@test/sandbox-provisioning-tavily.test.ts`:
- Around line 12-36: The dockerRunCommandBetween helper is duplicated and should
be shared to avoid divergence. Move the logic currently in
dockerRunCommandBetween into a common test utility module and update both
sandbox provisioning tests to import and use that shared helper, keeping the
existing behavior and error messages intact.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 09448491-9438-40d0-bb5e-4d2209c92b16

📥 Commits

Reviewing files that changed from the base of the PR and between bdaecbc and f9261cc.

📒 Files selected for processing (82)
  • Dockerfile
  • agents/hermes/Dockerfile
  • agents/hermes/config/build-env.ts
  • agents/hermes/config/hermes-config.ts
  • agents/hermes/config/hermes-env.ts
  • agents/hermes/config/managed-tool-gateway.ts
  • agents/hermes/policy-permissive.yaml
  • agents/hermes/seed-dashboard-config.py
  • agents/openclaw/policy-permissive.yaml
  • ci/platform-matrix.json
  • docs/deployment/deploy-to-remote-gpu.mdx
  • docs/get-started/quickstart-hermes.mdx
  • docs/get-started/quickstart.mdx
  • docs/manage-sandboxes/runtime-controls.mdx
  • docs/network-policy/customize-network-policy.mdx
  • docs/network-policy/integration-policy-examples.mdx
  • docs/reference/commands-nemohermes.mdx
  • docs/reference/commands.mdx
  • docs/reference/network-policies.mdx
  • docs/reference/platform-support.mdx
  • docs/reference/troubleshooting.mdx
  • docs/security/best-practices.mdx
  • docs/security/credential-storage.mdx
  • nemoclaw-blueprint/policies/openclaw-sandbox-permissive.yaml
  • nemoclaw-blueprint/policies/presets/tavily.yaml
  • nemoclaw-blueprint/provider-profiles/tavily-hermes-v1.yaml
  • scripts/generate-openclaw-config.mts
  • scripts/install.sh
  • src/lib/inference/web-search.test.ts
  • src/lib/inference/web-search.ts
  • src/lib/messaging/applier/build/messaging-build-applier.mts
  • src/lib/onboard.ts
  • src/lib/onboard/brave-provider-profile.test.ts
  • src/lib/onboard/brave-provider-profile.ts
  • src/lib/onboard/dockerfile-patch.test.ts
  • src/lib/onboard/dockerfile-patch.ts
  • src/lib/onboard/extra-placeholder-keys.test.ts
  • src/lib/onboard/extra-placeholder-keys.ts
  • src/lib/onboard/machine/core-flow-phases.test.ts
  • src/lib/onboard/machine/core-flow-phases.ts
  • src/lib/onboard/machine/final-flow-phases.ts
  • src/lib/onboard/machine/flow-context.test.ts
  • src/lib/onboard/machine/flow-context.ts
  • src/lib/onboard/machine/handlers/policies.ts
  • src/lib/onboard/machine/handlers/sandbox.test.ts
  • src/lib/onboard/machine/handlers/sandbox.ts
  • src/lib/onboard/messaging-prep.test.ts
  • src/lib/onboard/messaging-prep.ts
  • src/lib/onboard/policy-presets.ts
  • src/lib/onboard/policy-resume-selection.test.ts
  • src/lib/onboard/policy-resume-selection.ts
  • src/lib/onboard/policy-selection.ts
  • src/lib/onboard/sandbox-messaging-preflight.test.ts
  • src/lib/onboard/sandbox-messaging-preflight.ts
  • src/lib/onboard/sandbox-provider-cleanup.ts
  • src/lib/onboard/summary.test.ts
  • src/lib/onboard/summary.ts
  • src/lib/onboard/web-search-flow.test.ts
  • src/lib/onboard/web-search-flow.ts
  • src/lib/onboard/web-search-support.test.ts
  • src/lib/onboard/web-search-support.ts
  • src/lib/onboard/web-search-verify.test.ts
  • src/lib/onboard/web-search-verify.ts
  • src/lib/policy/index.ts
  • src/lib/state/onboard-session.test.ts
  • src/lib/state/onboard-session.ts
  • src/lib/state/openclaw-config-merge.test.ts
  • src/lib/state/openclaw-config-merge.ts
  • test/cli/destroy-detach-order.test.ts
  • test/generate-hermes-config.test.ts
  • test/generate-openclaw-config-web-search.test.ts
  • test/generate-openclaw-config.test.ts
  • test/hermes-gateway-wrapper.test.ts
  • test/messaging-build-applier.test.ts
  • test/onboard-brave-validation.test.ts
  • test/onboard-policy-suggestions.test.ts
  • test/sandbox-provider-cleanup.test.ts
  • test/sandbox-provisioning-tavily.test.ts
  • test/sandbox-provisioning.test.ts
  • test/seed-hermes-dashboard-config.test.ts
  • test/tavily-preset.test.ts
  • test/validate-blueprint.test.ts

Comment thread docs/reference/commands-nemohermes.mdx Outdated
Comment thread nemoclaw-blueprint/policies/presets/tavily.yaml
Comment thread src/lib/state/openclaw-config-merge.ts
cv added 2 commits July 2, 2026 10:01
Tighten Tavily egress and preserve fresh OpenClaw search ownership.
Isolate injected environment state and correct agent-specific documentation.

Signed-off-by: Carlos Villela <cvillela@nvidia.com>
Apply exact search and extract rules to provider-derived policy.
Document the shields-down exception and keep provisioning tests branch-free.

Signed-off-by: Carlos Villela <cvillela@nvidia.com>
@cv

cv commented Jul 2, 2026

Copy link
Copy Markdown
Collaborator Author

Automated-review triage for final head 892993a:

  • Nemotron PRA-1/PRA-2 are not applicable to the pinned OpenShell behavior. Providers v2 accepts basic, bearer, header, query, and path auth styles; body is not a valid auth style. Static placement metadata is stored and validated, while runtime static injection resolves environment placeholders. request_body_credential_rewrite is an independent REST endpoint option that rewrites placeholders in textual request bodies. Both Tavily profiles enable it on the exact POST /search and POST /extract endpoints, and the Hermes post-create verifier is implemented against that JSON-body path. See the official Providers v2 and policy schema references.
  • PRA-9 is factually stale: Tavily is supported for both OpenClaw and Hermes; Brave is OpenClaw-only. The current quickstarts already document that matrix.
  • PRA-3 through PRA-8 and the test follow-ups are non-blocking refactor/live-E2E suggestions. Deterministic profile, preset, and probe coverage is present; the selected sandbox E2Es, all five CLI shards, growth guardrails, and CodeQL are green. A live third-party search remains a follow-up because it requires external API credentials.

No code change is warranted for these findings.

@cv cv added the v0.0.74 label Jul 2, 2026
Signed-off-by: Apurv Kumaria <akumaria@nvidia.com>
Signed-off-by: Apurv Kumaria <akumaria@nvidia.com>

@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)
src/lib/policy/index.ts (2)

1265-1274: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Redundant try/catch around a call that already fails soft.

runCapture(..., { ignoreError: true }) never throws — per its implementation, every error branch (result.error, non-zero status, and the catch block) returns "" when ignoreError is set. Wrapping this specific call in an outer try/catch that also returns null is dead defensive code around a boundary with no realistic throw path.

Based on learnings, avoid adding defensive error handling (try/catch wrappers, fallbacks) around internal helper logic when there is no realistic throwing path; only add it at boundaries where failures can realistically occur.

♻️ Simplify
 function getGatewayPresets(sandboxName: string): string[] | null {
-  let rawPolicy = "";
-  try {
-    rawPolicy = runCapture(buildPolicyGetFullCommand(sandboxName), { ignoreError: true });
-  } catch {
-    return null;
-  }
+  const rawPolicy = runCapture(buildPolicyGetFullCommand(sandboxName), { ignoreError: true });
🤖 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 `@src/lib/policy/index.ts` around lines 1265 - 1274, The try/catch in
getGatewayPresets is redundant because runCapture(..., { ignoreError: true })
already fails soft and returns an empty string instead of throwing. Remove the
outer try/catch and keep the existing null return path based on
parseCurrentPolicyOrEmpty(rawPolicy), using getGatewayPresets and runCapture as
the key symbols to locate the logic.

Source: Learnings


273-280: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate sandboxAgent lookup — extract a shared helper.

The try { sandboxAgent = registry.getSandbox(sandboxName)?.agent ?? null; } catch { sandboxAgent = null; } block is duplicated verbatim at Line 273-280 (loadPresetForSandbox), Line 379-384 (listSetupPolicyPresets), and Line 1294-1299 (getGatewayPresets). Extracting a getSandboxAgentSafe(sandboxName) helper would avoid drift if the fallback logic ever needs to change.

♻️ Proposed helper extraction
+function getSandboxAgentSafe(sandboxName: string): string | null {
+  try {
+    return registry.getSandbox(sandboxName)?.agent ?? null;
+  } catch {
+    return null;
+  }
+}
+
 function loadPresetForSandbox(sandboxName: string, presetName: string): string | null {
-  let sandboxAgent: string | null = null;
-  try {
-    sandboxAgent = registry.getSandbox(sandboxName)?.agent ?? null;
-  } catch {
-    sandboxAgent = null;
-  }
+  const sandboxAgent = getSandboxAgentSafe(sandboxName);

Apply the same substitution at the other two call sites.

🤖 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 `@src/lib/policy/index.ts` around lines 273 - 280, The sandbox agent lookup
logic is duplicated in loadPresetForSandbox, listSetupPolicyPresets, and
getGatewayPresets. Extract the try/catch fallback into a shared
getSandboxAgentSafe(sandboxName) helper that returns
registry.getSandbox(sandboxName)?.agent ?? null and swallows lookup errors, then
replace all three inline blocks with calls to that helper to keep the fallback
behavior consistent.
🤖 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 `@src/lib/policy/index.ts`:
- Around line 1265-1274: The try/catch in getGatewayPresets is redundant because
runCapture(..., { ignoreError: true }) already fails soft and returns an empty
string instead of throwing. Remove the outer try/catch and keep the existing
null return path based on parseCurrentPolicyOrEmpty(rawPolicy), using
getGatewayPresets and runCapture as the key symbols to locate the logic.
- Around line 273-280: The sandbox agent lookup logic is duplicated in
loadPresetForSandbox, listSetupPolicyPresets, and getGatewayPresets. Extract the
try/catch fallback into a shared getSandboxAgentSafe(sandboxName) helper that
returns registry.getSandbox(sandboxName)?.agent ?? null and swallows lookup
errors, then replace all three inline blocks with calls to that helper to keep
the fallback behavior consistent.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 05956f9e-1943-45b0-bc37-f3c03687fa75

📥 Commits

Reviewing files that changed from the base of the PR and between f2a222e and e86fb6e.

📒 Files selected for processing (23)
  • Dockerfile
  • ci/platform-matrix.json
  • docs/get-started/quickstart-hermes.mdx
  • docs/get-started/quickstart-langchain-deepagents-code.mdx
  • docs/get-started/quickstart.mdx
  • docs/network-policy/customize-network-policy.mdx
  • docs/network-policy/integration-policy-examples.mdx
  • docs/reference/commands-nemohermes.mdx
  • docs/reference/commands.mdx
  • docs/reference/network-policies.mdx
  • docs/reference/platform-support.mdx
  • docs/reference/troubleshooting.mdx
  • docs/security/best-practices.mdx
  • scripts/install.sh
  • src/lib/onboard.ts
  • src/lib/onboard/dockerfile-patch.ts
  • src/lib/onboard/policy-resume-selection.ts
  • src/lib/onboard/policy-selection.ts
  • src/lib/onboard/web-search-flow.test.ts
  • src/lib/onboard/web-search-flow.ts
  • src/lib/policy/index.ts
  • test/langchain-deepagents-code-image.test.ts
  • test/onboard-policy-suggestions.test.ts
💤 Files with no reviewable changes (2)
  • test/langchain-deepagents-code-image.test.ts
  • test/onboard-policy-suggestions.test.ts
✅ Files skipped from review due to trivial changes (10)
  • docs/reference/platform-support.mdx
  • docs/get-started/quickstart-langchain-deepagents-code.mdx
  • docs/network-policy/customize-network-policy.mdx
  • docs/reference/network-policies.mdx
  • ci/platform-matrix.json
  • docs/reference/commands-nemohermes.mdx
  • docs/network-policy/integration-policy-examples.mdx
  • scripts/install.sh
  • docs/reference/commands.mdx
  • docs/reference/troubleshooting.mdx
🚧 Files skipped from review as they are similar to previous changes (10)
  • src/lib/onboard/dockerfile-patch.ts
  • docs/security/best-practices.mdx
  • docs/get-started/quickstart-hermes.mdx
  • docs/get-started/quickstart.mdx
  • Dockerfile
  • src/lib/onboard.ts
  • src/lib/onboard/web-search-flow.test.ts
  • src/lib/onboard/policy-resume-selection.ts
  • src/lib/onboard/web-search-flow.ts
  • src/lib/onboard/policy-selection.ts

@cv
cv merged commit 489e521 into main Jul 3, 2026
47 checks passed
@cv
cv deleted the codex/tavily-web-search branch July 3, 2026 19:37
Hadar301 pushed a commit to Hadar301/NemoClaw-OpenShift that referenced this pull request Jul 12, 2026
<!-- markdownlint-disable MD041 -->
## Summary

Adds first-class Tavily web-search onboarding for OpenClaw and Hermes,
including provider-aware credentials, runtime configuration, network
policy, rebuild/resume reconciliation, and live post-create
verification. This revives the useful concepts from NVIDIA#2105 on the current
architecture while preserving Brave compatibility and fail-closed
behavior.

## Related Issue

Advances NVIDIA#2718.

Revives and supersedes NVIDIA#2105. The original Tavily contribution from
@lakshyaag-tavily is preserved through co-author and sign-off trailers.

## Changes

- Add shared `brave`, `tavily`, and `none` web-search selection with
credential-store precedence, secure credential validation,
provider-scoped resources, and legacy Brave migration.
- Configure OpenClaw's bundled Tavily extension and Hermes' native
Tavily backend, including managed-tool conflict suppression and
provider-specific runtime verification.
- Add least-privilege Tavily network policies, Hermes request-body
credential rewriting, and coverage in both agent-specific and global
permissive policies.
- Reconcile provider changes across rebuild and resume without widening
intentionally restricted policy state, and clean up stale provider
config, credentials, and policies.
- Document interactive and non-interactive setup, provider switching,
policy behavior, troubleshooting, and credential handling.

## Type of Change

- [ ] Code change (feature, bug fix, or refactor)
- [x] Code change with doc updates
- [ ] Doc only (prose changes, no code sample modifications)
- [ ] Doc only (includes code sample changes)

## Quality Gates

- [x] Tests added or updated for changed behavior
- [ ] Existing tests cover changed behavior — justification:
- [ ] Tests not applicable — justification:
- [x] Docs updated for user-facing behavior changes
- [ ] Docs not applicable — justification:
- [x] Sensitive paths changed (security, policy, credentials, preflight,
onboarding, inference, runner, sandbox, or messaging)
- [x] Sensitive-path review completed or maintainer-approved waiver
recorded — reviewer/approval link/justification: focused reviews covered
credential handling, policy egress and body rewrites, provider
switching, resume reconciliation, and runtime verification; no findings
remain.
- [ ] Non-success, skipped, or missing CI check accepted by maintainer —
check name, approval link, and follow-up issue:

## Verification

- [x] PR description includes the DCO sign-off declaration and every
commit appears as `Verified` in GitHub
- [x] Git hooks passed during commit and push, or `npx prek run
--from-ref main --to-ref HEAD` passes
- [x] Targeted tests pass for changed behavior
- [x] Full `npm test` passes (broad runtime changes only)
- [x] Quality Gates section completed with required justifications or
waivers
- [x] No secrets, API keys, or credentials committed
- [ ] `npm run docs` builds without warnings (doc changes only)
- [x] Doc pages follow the [style
guide](https://github.com/NVIDIA/NemoClaw/blob/main/docs/CONTRIBUTING.md)
(doc changes only)
- [ ] New doc pages include SPDX header and frontmatter (new pages only)

Additional verification:

- `npm test`: 946 files passed, 10,852 tests passed, 34 expected skips.
- `make check`: passed, including coverage ratchets, source-shape and
test-size budgets, gitleaks, ShellCheck, Hadolint, and plugin tests.
- Post-rebase focused suite: 179 tests passed; `npm run typecheck:cli`
passed.
- `npm run docs`: 0 errors; the two existing Fern upgrade warnings
remain.
- Pinned OpenClaw and Hermes runtime contracts were inspected for the
bundled extension and native backend behavior.

---
Signed-off-by: Carlos Villela <cvillela@nvidia.com>


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added provider selection for web search during onboarding (Brave or
Tavily), including provider-specific API key handling and sandbox
recreation when changing providers.
* Hermes now supports Tavily web search with correct backend routing and
request credential rewriting; Tavily selection can replace the managed
web gateway when applicable.
* Added Tavily network policies/provider profiles with least-privilege
access limited to `POST /search` and `POST /extract`.
* **Bug Fixes**
* Improved resume/reconciliation to correctly swap or remove stale
web-search provider and related gateway selections.
* Web-search verification now validates the active provider/backend and
warns on misconfiguration without blocking completion.
* **Documentation**
* Updated onboarding quickstarts, references, and runtime controls to
reflect the new provider variables, defaults, and rebuild/verification
behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: Carlos Villela <cvillela@nvidia.com>
Signed-off-by: Apurv Kumaria <akumaria@nvidia.com>
Co-authored-by: Apurv Kumaria <akumaria@nvidia.com>
cv pushed a commit that referenced this pull request Jul 18, 2026
## Summary

`nemoclaw rebuild --yes` failed preflight with `Brave Search credential
is invalid. Brave Search requires BRAVE_API_KEY or a saved Brave Search
credential in non-interactive mode.` for sandboxes whose web search
works. `saveCredential` stages web-search keys to the process env only —
the OpenShell gateway provider is the durable system of record — so a
fresh rebuild process holds no host key, and the preflight demanded one
it would never use: the OpenClaw recreate path already reuses the
gateway-registered credential (`messaging-prep`
`requiresExactOpenClawProviderBinding`). After this change the preflight
accepts that same gateway credential-only provider binding, and rebuild
succeeds without re-exporting `BRAVE_API_KEY`.

## Related Issue

Fixes #7097

## Changes

- `src/lib/actions/sandbox/rebuild-target-runtime.ts`: before demanding
a host key, `preflightRebuildWebSearchCredential` accepts a matching
gateway credential-only provider binding (`<sandbox>-<provider>-search`,
provider type, recorded credential key) read via
`readGatewayProviderMetadata`, scoped to the sandbox's resolved gateway.
The reuse is gated to the OpenClaw agent (`target.agentDefinition ===
null`) — the only recreate path that reuses the binding — and only when
no host key is staged; a staged key and non-OpenClaw agents keep the
existing validation path, and a missing/mismatched binding still fails
closed.
- `src/lib/actions/sandbox/rebuild-target-runtime.test.ts`: cover
gateway-binding reuse, fail-closed on missing binding, staged-host-key
validation, and the non-OpenClaw validation path.

Scope note: issue #7097 also reports the balanced tier creating a global
`brave` provider profile as a side effect. The `provider profile import`
in NemoClaw has tolerated `already exists` since #6165, and decoupling
the egress preset from the provider profile is a design decision (the
profile drives the L7 proxy token rewrite), so it is not changed here;
details on the issue.

## Type of Change

- [x] Code change (feature, bug fix, or refactor)
- [ ] Code change with doc updates
- [ ] Doc only (prose changes, no code sample modifications)
- [ ] Doc only (includes code sample changes)

## Quality Gates

- [x] Tests added or updated for changed behavior
- [ ] Existing tests cover changed behavior — justification:
- [ ] Tests not applicable — justification:
- [ ] Docs updated for user-facing behavior changes
- [x] Docs not applicable — justification: no doc page documents a
host-key requirement for rebuild; this removes an incorrect preflight
failure so behavior matches the existing quickstart web-search docs.
- [x] Sensitive paths changed (security, policy, credentials, preflight,
onboarding, inference, runner, sandbox, or messaging)
- [x] Sensitive-path review completed or maintainer-approved waiver
recorded — reviewer/approval link/justification: author review — the
reuse check reads provider identity metadata only
(`readGatewayProviderMetadata` never reads or exports credential
values), requires the exact recorded name/type/credential-key binding
with no config keys, is scoped to the sandbox's resolved gateway, and
fails closed for mismatches, staged host keys, and non-OpenClaw agents.
- [ ] Non-success, skipped, or missing CI check accepted by maintainer —
check name, approval link, and follow-up issue:

## Verification

- [x] PR description includes a `Signed-off-by:` line and every commit
appears as `Verified` in GitHub
- [x] Normal `pre-commit`, `commit-msg`, and `pre-push` hooks passed, or
`npm run check:diff` passed when hooks were skipped or unavailable
- [x] Targeted behavior tests pass for the current change set, or tests
are marked not applicable above — command/result: `npx vitest run
--project cli src/lib/actions/sandbox/rebuild-target-runtime.test.ts` (7
passed); `npm run test:changed` (60 passed); `npx vitest run --project
integration test/rebuild-credential-preflight.test.ts
test/rebuild-stale-recovery.test.ts
test/rebuild-shields-auto-unlock.test.ts` (13 passed); `npm run
typecheck:cli` clean.
- [ ] Applicable broad gate passed — `npm test` for broad
runtime/test-harness changes; `npm run check` for repo-wide
validation/coverage changes — command/result:
- [x] Quality Gates section completed with required justifications or
waivers
- [x] No secrets, API keys, or credentials committed
- [ ] `npm run docs` builds without warnings (doc changes only)
- [ ] Doc pages follow the [style
guide](https://github.com/NVIDIA/NemoClaw/blob/main/docs/CONTRIBUTING.md)
(doc changes only)
- [ ] New doc pages include SPDX header and frontmatter (new pages only)

---
Signed-off-by: Shawn Xie <shaxie@nvidia.com>

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Web-search credentials can now be reused during sandbox runtime
recreation when an existing gateway credential matches the configured
web-search provider.

- **Bug Fixes**
- Improved credential preflight logic: correctly revalidates when a
staged host key is present, fails when neither a valid gateway
credential nor host key is available, and preserves the expected
behavior for non-OpenClaw agent configurations.

- **Tests**
- Added coverage for the new web-search credential reuse and failure
scenarios during runtime preflight.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: Shawn Xie <shaxie@nvidia.com>
Signed-off-by: Apurv Kumaria <akumaria@nvidia.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Apurv Kumaria <akumaria@nvidia.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: docs Documentation, examples, guides, or docs build area: integrations Third-party service integration behavior area: onboarding Onboarding FSM, provider setup, sandbox launch, or first-run flow area: policy Network policy, egress rules, presets, or sandbox policy area: providers Inference provider integrations and provider behavior feature PR adds or expands user-visible functionality integration: hermes Hermes integration behavior integration: openclaw OpenClaw integration behavior

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants