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
2 changes: 1 addition & 1 deletion deepworm/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ def build_parser() -> argparse.ArgumentParser:
parser.add_argument(
"--search-provider",
type=str,
choices=["duckduckgo", "brave", "searxng"],
choices=["duckduckgo", "brave", "searxng", "tavily"],
default=None,
help="Search engine provider (default: duckduckgo)",
)
Expand Down
4 changes: 2 additions & 2 deletions deepworm/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class Config:
# Search settings
search_region: str = "wt-wt"
search_max_results: int = 8
search_provider: str = "duckduckgo" # duckduckgo, brave, searxng
search_provider: str = "duckduckgo" # duckduckgo, brave, searxng, tavily

# Rate limiting
max_requests_per_minute: int = 60 # LLM API rate limit
Expand Down Expand Up @@ -124,7 +124,7 @@ def validate(self) -> None:
"""
VALID_PROVIDERS = {"openai", "anthropic", "google", "openrouter", "ollama"}
VALID_FORMATS = {"markdown", "html", "text", "json", "pdf"}
VALID_SEARCH_PROVIDERS = {"duckduckgo", "brave", "searxng"}
VALID_SEARCH_PROVIDERS = {"duckduckgo", "brave", "searxng", "tavily"}

if self.provider not in VALID_PROVIDERS:
raise ValueError(
Expand Down
38 changes: 36 additions & 2 deletions deepworm/search.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Web search with multiple providers.

Supports DuckDuckGo (default), Brave Search API, and SearXNG.
Supports DuckDuckGo (default), Brave Search API, SearXNG, and Tavily.
"""

from __future__ import annotations
Expand Down Expand Up @@ -41,7 +41,7 @@ def search_web(
) -> list[SearchResult]:
"""Search the web using the specified provider.

Providers: duckduckgo (default), brave, searxng
Providers: duckduckgo (default), brave, searxng, tavily
"""
# Check cache first
if cache is not None:
Expand All @@ -62,6 +62,11 @@ def search_web(
results = _search_searxng(query, max_results)
except Exception as e:
logger.debug("SearXNG search failed: %s", e)
elif provider == "tavily":
try:
results = _search_tavily(query, max_results)
except Exception as e:
logger.debug("Tavily search failed: %s", e)

# Default/fallback: DuckDuckGo
if not results:
Expand Down Expand Up @@ -287,3 +292,32 @@ def _search_searxng(query: str, max_results: int) -> list[SearchResult]:
snippet=item.get("content", ""),
))
return results


def _search_tavily(query: str, max_results: int) -> list[SearchResult]:
"""Search using Tavily API. Requires TAVILY_API_KEY env var."""
import os

api_key = os.getenv("TAVILY_API_KEY", "")
if not api_key:
raise ValueError("TAVILY_API_KEY not set")

from tavily import TavilyClient

client = TavilyClient(api_key=api_key)
response = client.search(
query=query,
max_results=max_results,
search_depth="advanced",
include_raw_content=True,
)

results = []
for item in response.get("results", [])[:max_results]:
results.append(SearchResult(
title=item.get("title", ""),
url=item.get("url", ""),
snippet=item.get("content", ""),
body=item.get("raw_content", None),
))
return results
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ dependencies = [
"rich>=13.0.0",
"openai>=1.0.0",
"ddgs>=6.0.0",
"tavily-python>=0.3.0",
]

[project.optional-dependencies]
Expand Down