from typing import Any from smolagents.tools import Tool from ddgs import DDGS import json class DuckDuckGoSearchTool(Tool): name = "web_search" description = "Performs a DuckDuckGo web search based on your query and returns an array of {title, url, snippet}" inputs: dict[str, dict[str, Any]] = { "query": {"type": "string", "description": "The search query to perform."} } output_type = "string" # switched to "json" as this smolagents version supports it def __init__(self, max_results: int = 10, **kwargs: Any) -> None: super().__init__() self.max_results = max_results self.ddgs = DDGS(**kwargs) def forward(self, query: str) -> list[dict[str, str]]: q = (query or "").strip() if not q: raise ValueError("Query must be a non-empty string.") items = list( self.ddgs.text( keywords=q, region="wt-wt", safesearch="moderate", timelimit=None, max_results=self.max_results, ) ) if not items: raise RuntimeError("No results found. Try a broader/simpler query.") results: list[dict[str, str]] = [] for it in items: href = (it.get("href") or "").strip() if not href: continue results.append( { "title": str(it.get("title", "")), "url": href, "snippet": str(it.get("body", "")), } ) if not results: raise RuntimeError("Results were returned but none contained valid URLs.") return json.dumps(results)