Skip to content

feat: add Tavily web search as parallel option to DuckDuckGo#33

Open
tavily-integrations wants to merge 1 commit into
hoangsonww:masterfrom
Tavily-FDE:feat/tavily-migration/main-app-duckduckgo
Open

feat: add Tavily web search as parallel option to DuckDuckGo#33
tavily-integrations wants to merge 1 commit into
hoangsonww:masterfrom
Tavily-FDE:feat/tavily-migration/main-app-duckduckgo

Conversation

@tavily-integrations

Copy link
Copy Markdown

Summary

Adds Tavily as a configurable search provider alongside the existing DuckDuckGo integration (additive/parallel strategy). Users can switch between providers via the SEARCH_PROVIDER environment variable. DuckDuckGo remains the default.

Changes

  • src/agentic_ai/tools/webtools.py: Added TavilyWebSearch LangChain BaseTool class that returns the same {title, url, snippet} JSON schema as the existing WebSearch tool. Added get_web_search_tool() factory function that reads SEARCH_PROVIDER env var to select the active tool at runtime.
  • src/agentic_ai/layers/tools.py: Updated registry() to use get_web_search_tool() factory instead of directly instantiating WebSearch.
  • requirements.txt: Added tavily-python>=0.3.0.
  • .env.example: Added SEARCH_PROVIDER and TAVILY_API_KEY configuration entries.

Dependency changes

  • Added tavily-python>=0.3.0 to requirements.txt

Environment variable changes

  • SEARCH_PROVIDER — optional, defaults to duckduckgo, set to tavily to use Tavily
  • TAVILY_API_KEY — required when SEARCH_PROVIDER=tavily

Notes for reviewers

  • The existing WebSearch (DuckDuckGo) class is completely unchanged
  • tavily-python is imported lazily inside TavilyWebSearch._run() to avoid import errors when Tavily is not the active provider
  • Both tools share the same name (web_search) so they are interchangeable in the agent pipeline

Automated Review

  • Passed after 1 attempt(s)
  • Final review: The migration correctly adds Tavily as a configurable parallel search provider alongside DuckDuckGo. All four reported files are modified appropriately: TavilyWebSearch tool class is implemented with consistent retry logic and output normalization, a get_web_search_tool() factory reads SEARCH_PROVIDER env var (defaulting to duckduckgo), layers/tools.py is updated to use the factory, tavily-python>=0.3.0 is added to requirements.txt, and both new env vars are documented in .env.example. No regressions introduced — existing WebSearch class and DuckDuckGo path are fully preserved. Code style is consistent with the codebase. Only one minor issue noted.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a new web search provider, Tavily, as an alternative to DuckDuckGo, configurable via the SEARCH_PROVIDER environment variable. The changes include adding the necessary dependency, updating the tool registry, and implementing the TavilyWebSearch class. The review feedback highlights a need for better configuration validation in the factory function to ensure the Tavily API key is present when selected and to provide explicit errors for unsupported providers instead of silent fallbacks.

Comment on lines +51 to +56
def get_web_search_tool() -> BaseTool:
"""Return the active web search tool based on SEARCH_PROVIDER env var."""
provider = os.environ.get("SEARCH_PROVIDER", "duckduckgo").lower()
if provider == "tavily":
return TavilyWebSearch()
return WebSearch()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

The current implementation of this factory function has two robustness issues:

  1. It doesn't validate that TAVILY_API_KEY is set when SEARCH_PROVIDER is 'tavily', leading to a runtime error instead of a configuration error.
  2. It silently falls back to DuckDuckGo for any unsupported SEARCH_PROVIDER value, which can hide misconfigurations.

It would be better to fail fast with clear error messages for invalid configurations.

def get_web_search_tool() -> BaseTool:
    """Return the active web search tool based on SEARCH_PROVIDER env var."""
    provider = os.environ.get("SEARCH_PROVIDER", "duckduckgo").lower()
    if provider == "tavily":
        if not os.environ.get("TAVILY_API_KEY"):
            raise ValueError(
                "SEARCH_PROVIDER is 'tavily', but TAVILY_API_KEY environment variable is not set."
            )
        return TavilyWebSearch()
    elif provider == "duckduckgo":
        return WebSearch()
    else:
        raise ValueError(
            f"Unsupported SEARCH_PROVIDER: '{provider}'. Supported values are 'duckduckgo' and 'tavily'."
        )

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant