Add multi-provider web search support: Brave (default), Tavily, DuckDuckGo, and SearXNG. Falls back to DuckDuckGo when provider credentials are missing. Providers are dispatched via a map with register_provider() for plugin extensibility. - WebSearchConfig with env-var resolution and from_legacy() bridge - Config migration for legacy flat keys (tavilyApiKey, searxngBaseUrl) - SearXNG URL validation, explicit error for unknown providers - ddgs package (replaces deprecated duckduckgo-search) - 16 tests covering all providers, fallback, env resolution, edge cases - docs/web-search.md with full config reference Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1.9 KiB
1.9 KiB
Web Search Providers
NanoBot supports multiple web search providers. Configure in ~/.nanobot/config.json under tools.web.search.
| Provider | Key | Env var |
|---|---|---|
brave (default) |
apiKey |
BRAVE_API_KEY |
tavily |
apiKey |
TAVILY_API_KEY |
searxng |
baseUrl |
SEARXNG_BASE_URL |
duckduckgo |
— | — |
Each provider uses the same apiKey field — set the provider and key together. If no provider is specified but apiKey is given, Brave is assumed.
When credentials are missing and fallbackToDuckduckgo is true (the default), searches fall back to DuckDuckGo automatically.
Examples
Brave (default — just set the key):
{
"tools": {
"web": {
"search": {
"apiKey": "BSA..."
}
}
}
}
Tavily:
{
"tools": {
"web": {
"search": {
"provider": "tavily",
"apiKey": "tvly-..."
}
}
}
}
SearXNG (self-hosted, no API key needed):
{
"tools": {
"web": {
"search": {
"provider": "searxng",
"baseUrl": "https://searx.example"
}
}
}
}
DuckDuckGo (no credentials required):
{
"tools": {
"web": {
"search": {
"provider": "duckduckgo"
}
}
}
}
Options
| Key | Type | Default | Description |
|---|---|---|---|
provider |
string | "brave" |
Search backend |
apiKey |
string | "" |
API key for the selected provider |
baseUrl |
string | "" |
Base URL for SearXNG (appends /search) |
maxResults |
integer | 5 |
Default results per search |
fallbackToDuckduckgo |
boolean | true |
Fall back to DuckDuckGo when credentials are missing |
Custom providers
Plugins can register additional providers at runtime via the dispatch dict:
async def my_search(query: str, n: int) -> str:
...
tool._provider_dispatch["my-engine"] = my_search