feat: add Tavily web search as parallel option to DuckDuckGo#33
feat: add Tavily web search as parallel option to DuckDuckGo#33tavily-integrations wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
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.
| 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() |
There was a problem hiding this comment.
The current implementation of this factory function has two robustness issues:
- It doesn't validate that
TAVILY_API_KEYis set whenSEARCH_PROVIDERis'tavily', leading to a runtime error instead of a configuration error. - It silently falls back to DuckDuckGo for any unsupported
SEARCH_PROVIDERvalue, 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'."
)
Summary
Adds Tavily as a configurable search provider alongside the existing DuckDuckGo integration (additive/parallel strategy). Users can switch between providers via the
SEARCH_PROVIDERenvironment variable. DuckDuckGo remains the default.Changes
src/agentic_ai/tools/webtools.py: AddedTavilyWebSearchLangChainBaseToolclass that returns the same{title, url, snippet}JSON schema as the existingWebSearchtool. Addedget_web_search_tool()factory function that readsSEARCH_PROVIDERenv var to select the active tool at runtime.src/agentic_ai/layers/tools.py: Updatedregistry()to useget_web_search_tool()factory instead of directly instantiatingWebSearch.requirements.txt: Addedtavily-python>=0.3.0..env.example: AddedSEARCH_PROVIDERandTAVILY_API_KEYconfiguration entries.Dependency changes
tavily-python>=0.3.0torequirements.txtEnvironment variable changes
SEARCH_PROVIDER— optional, defaults toduckduckgo, set totavilyto use TavilyTAVILY_API_KEY— required whenSEARCH_PROVIDER=tavilyNotes for reviewers
WebSearch(DuckDuckGo) class is completely unchangedtavily-pythonis imported lazily insideTavilyWebSearch._run()to avoid import errors when Tavily is not the active providername(web_search) so they are interchangeable in the agent pipelineAutomated Review
TavilyWebSearchtool class is implemented with consistent retry logic and output normalization, aget_web_search_tool()factory readsSEARCH_PROVIDERenv var (defaulting toduckduckgo),layers/tools.pyis updated to use the factory,tavily-python>=0.3.0is added torequirements.txt, and both new env vars are documented in.env.example. No regressions introduced — existingWebSearchclass and DuckDuckGo path are fully preserved. Code style is consistent with the codebase. Only one minor issue noted.