Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,10 @@ ARG NEMOCLAW_PROXY_PORT=3128
# The actual API key is injected at runtime via openshell:resolve:env, never
# baked into the image.
ARG NEMOCLAW_WEB_SEARCH_ENABLED=0
# Web search provider selected during onboard ("brave" or "tavily"). The
# Python script falls back to "brave" if unset or unrecognized; the env var
# is patched to the user's choice by the CLI before docker build.
ARG NEMOCLAW_WEB_SEARCH_PROVIDER=brave

# SECURITY: Promote build-args to env vars so the Python script reads them
# via os.environ, never via string interpolation into Python source code.
Expand All @@ -329,7 +333,8 @@ ENV NEMOCLAW_MODEL=${NEMOCLAW_MODEL} \
NEMOCLAW_DISABLE_DEVICE_AUTH=${NEMOCLAW_DISABLE_DEVICE_AUTH} \
NEMOCLAW_PROXY_HOST=${NEMOCLAW_PROXY_HOST} \
NEMOCLAW_PROXY_PORT=${NEMOCLAW_PROXY_PORT} \
NEMOCLAW_WEB_SEARCH_ENABLED=${NEMOCLAW_WEB_SEARCH_ENABLED}
NEMOCLAW_WEB_SEARCH_ENABLED=${NEMOCLAW_WEB_SEARCH_ENABLED} \
NEMOCLAW_WEB_SEARCH_PROVIDER=${NEMOCLAW_WEB_SEARCH_PROVIDER}

WORKDIR /sandbox
USER sandbox
Expand Down
21 changes: 21 additions & 0 deletions nemoclaw-blueprint/policies/presets/tavily.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

preset:
name: tavily
description: "Tavily Search API access"

network_policies:
tavily:
name: tavily
endpoints:
- host: api.tavily.com
port: 443
protocol: rest
enforcement: enforce
rules:
- allow: { method: GET, path: "/**" }
- allow: { method: POST, path: "/**" }
binaries:
- { path: /usr/local/bin/node }
- { path: /usr/bin/node }
2 changes: 2 additions & 0 deletions nemoclaw-blueprint/policies/tiers.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ tiers:
- { name: huggingface, access: read-write }
- { name: brew, access: read-write }
- { name: brave, access: read-write }
- { name: tavily, access: read-write }

- name: open
label: Open
Expand All @@ -36,6 +37,7 @@ tiers:
- { name: huggingface, access: read-write }
- { name: brew, access: read-write }
- { name: brave, access: read-write }
- { name: tavily, access: read-write }
- { name: slack, access: read-write }
- { name: discord, access: read-write }
- { name: telegram, access: read-write }
Expand Down
16 changes: 13 additions & 3 deletions scripts/generate-openclaw-config.py
Original file line number Diff line number Diff line change
Expand Up @@ -608,14 +608,24 @@ def _placeholder(channel: str, env_key: str) -> str:
}

if env.get("NEMOCLAW_WEB_SEARCH_ENABLED", "") == "1":
_ws_provider = env.get("NEMOCLAW_WEB_SEARCH_PROVIDER", "brave")
if _ws_provider not in ("brave", "tavily"):
_ws_provider = "brave"
_ws_env_key = {"brave": "BRAVE_API_KEY", "tavily": "TAVILY_API_KEY"}[
_ws_provider
]
Comment thread
lakshyaag-tavily marked this conversation as resolved.
# Route web_fetch through Tavily Extract when Tavily is the search provider.
fetch_cfg: dict = {"enabled": True}
if _ws_provider == "tavily":
fetch_cfg["provider"] = "tavily"
config["tools"] = {
"web": {
"search": {
"enabled": True,
"provider": "brave",
"apiKey": "openshell:resolve:env:BRAVE_API_KEY",
"provider": _ws_provider,
"apiKey": f"openshell:resolve:env:{_ws_env_key}",
},
"fetch": {"enabled": True},
"fetch": fetch_cfg,
}
}

Expand Down
11 changes: 10 additions & 1 deletion src/lib/inference/web-search.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,19 @@

import { describe, expect, it } from "vitest";

import { BRAVE_API_KEY_ENV } from "./web-search";
import { BRAVE_API_KEY_ENV, TAVILY_API_KEY_ENV, webSearchEnvFor } from "./web-search";

describe("web-search module", () => {
it("exports BRAVE_API_KEY_ENV constant", () => {
expect(BRAVE_API_KEY_ENV).toBe("BRAVE_API_KEY");
});

it("exports TAVILY_API_KEY_ENV constant", () => {
expect(TAVILY_API_KEY_ENV).toBe("TAVILY_API_KEY");
});

it("webSearchEnvFor maps providers to env var names", () => {
expect(webSearchEnvFor("brave")).toBe("BRAVE_API_KEY");
expect(webSearchEnvFor("tavily")).toBe("TAVILY_API_KEY");
});
});
8 changes: 8 additions & 0 deletions src/lib/inference/web-search.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

export type WebSearchProvider = "brave" | "tavily";

export interface WebSearchConfig {
fetchEnabled: boolean;
provider: WebSearchProvider;
}

export const BRAVE_API_KEY_ENV = "BRAVE_API_KEY";
export const TAVILY_API_KEY_ENV = "TAVILY_API_KEY";

export function webSearchEnvFor(provider: WebSearchProvider): string {
return provider === "tavily" ? TAVILY_API_KEY_ENV : BRAVE_API_KEY_ENV;
}
Loading