diff --git a/src/open_deep_research/configuration.py b/src/open_deep_research/configuration.py index 1c5bac9e9..e9004ee91 100644 --- a/src/open_deep_research/configuration.py +++ b/src/open_deep_research/configuration.py @@ -117,6 +117,18 @@ class Configuration(BaseModel): } } ) + tavily_timeout: int = Field( + default=60, + metadata={ + "x_oap_ui_config": { + "type": "number", + "default": 60, + "min": 1, + "max": 300, + "description": "Timeout for Tavily search in seconds." + } + } + ) # Model Configuration summarization_model: str = Field( default="openai:gpt-4.1-mini", diff --git a/src/open_deep_research/utils.py b/src/open_deep_research/utils.py index 4828b8888..7a83a5bcc 100644 --- a/src/open_deep_research/utils.py +++ b/src/open_deep_research/utils.py @@ -169,8 +169,13 @@ async def tavily_search_async( ] # Execute all search queries in parallel and return results - search_results = await asyncio.gather(*search_tasks) - return search_results + configurable = Configuration.from_runnable_config(config) + try: + search_results = await asyncio.wait_for(asyncio.gather(*search_tasks), timeout=configurable.tavily_timeout) + return search_results + except asyncio.TimeoutError: + logging.warning(f"Tavily search timed out after {configurable.tavily_timeout} seconds") + return [] async def summarize_webpage(model: BaseChatModel, webpage_content: str) -> str: """Summarize webpage content using AI model with timeout protection.