open_Deep-Research / tools.py
spagestic's picture
Add UnavailableWebSearchTool to handle missing EXA_API_KEY gracefully
85c5d51
Raw
History Blame Contribute Delete
3.76 kB
"""Tool factory for the agent."""
import os
from exa_py import Exa
from smolagents import Tool
from scripts.text_inspector_tool import TextInspectorTool
from scripts.text_web_browser import (
ArchiveSearchTool,
FinderTool,
FindNextTool,
PageDownTool,
PageUpTool,
SimpleTextBrowser,
VisitTool,
)
from scripts.visual_qa import visualizer
from config import BROWSER_CONFIG, TEXT_LIMIT
class ExaSearchTool(Tool):
name = "web_search"
description = (
"Perform a web search and return relevant results with key excerpts. "
"Use a natural language query. Optionally filter by year."
)
inputs = {
"query": {"type": "string", "description": "The natural language search query."},
"filter_year": {
"type": "string",
"description": "[Optional]: Filter results to a specific year, e.g. '2024'.",
"nullable": True,
},
}
output_type = "string"
def __init__(self, api_key: str):
super().__init__()
self.exa = Exa(api_key=api_key)
def forward(self, query: str, filter_year: str = None) -> str:
kwargs = {
"num_results": 10,
"contents": {"highlights": True},
}
if filter_year:
kwargs["start_published_date"] = f"{filter_year}-01-01"
kwargs["end_published_date"] = f"{filter_year}-12-31"
results = self.exa.search(query, **kwargs)
if not results.results:
return f"No results found for '{query}'."
lines = [f"Exa search for '{query}' returned {len(results.results)} results:\n"]
for i, r in enumerate(results.results, 1):
date = f"\nDate published: {r.published_date}" if r.published_date else ""
highlights = ""
if r.highlights:
highlights = "\n" + "\n".join(f" • {h}" for h in r.highlights)
lines.append(f"{i}. [{r.title}]({r.url}){date}{highlights}")
return "\n\n".join(lines)
class UnavailableWebSearchTool(Tool):
name = "web_search"
description = (
"Web search is currently unavailable because EXA_API_KEY is not set. "
"This tool returns a helpful message instead of raising an error."
)
inputs = {
"query": {"type": "string", "description": "The natural language search query."},
"filter_year": {
"type": "string",
"description": "[Optional]: Filter results to a specific year, e.g. '2024'.",
"nullable": True,
},
}
output_type = "string"
def forward(self, query: str, filter_year: str = None) -> str:
year_note = f" for {filter_year}" if filter_year else ""
return (
f"Web search{year_note} is unavailable because EXA_API_KEY is not set. "
"Set EXA_API_KEY in your environment or Space secrets to enable search."
)
def _create_web_search_tool() -> Tool:
api_key = os.getenv("EXA_API_KEY")
if not api_key:
print(
"Warning: EXA_API_KEY not set. Web search will be disabled until it is configured."
)
return UnavailableWebSearchTool()
return ExaSearchTool(api_key=api_key)
def build_tools(model):
web_search = _create_web_search_tool()
browser = SimpleTextBrowser(**BROWSER_CONFIG)
ti_tool = TextInspectorTool(model, TEXT_LIMIT)
web_tools = [
web_search,
VisitTool(browser),
PageUpTool(browser),
PageDownTool(browser),
FinderTool(browser),
FindNextTool(browser),
ArchiveSearchTool(browser),
ti_tool,
]
document_inspection_tool = TextInspectorTool(model, TEXT_LIMIT)
return web_tools, document_inspection_tool, visualizer