Spaces:
Running
Running
| """ | |
| Lightweight web tools for the agent: DuckDuckGo instant answers and Wikipedia search. | |
| These do not require API keys and are suitable for Level-1 GAIA tasks that need quick factual | |
| retrieval. They are intentionally simple and return concise text. | |
| """ | |
| from typing import Optional | |
| import requests | |
| import logging | |
| logger = logging.getLogger(__name__) | |
| try: | |
| from smolagents import tool | |
| except Exception: | |
| tool = None | |
| def duckduckgo_search(query: str, region: str = "wt-wt") -> str: | |
| """Use DuckDuckGo Instant Answer API to fetch a brief summary for a query. | |
| Returns a short text summarizing the AbstractText and some related topics. | |
| """ | |
| if not query: | |
| return "(no query provided)" | |
| try: | |
| params = {"q": query, "format": "json", "no_html": 1, "skip_disambig": 1} | |
| resp = requests.get("https://api.duckduckgo.com/", params=params, timeout=10) | |
| resp.raise_for_status() | |
| data = resp.json() | |
| parts = [] | |
| if data.get("AbstractText"): | |
| parts.append(data.get("AbstractText")) | |
| # include first related topic text if present | |
| related = data.get("RelatedTopics") or [] | |
| if related: | |
| # RelatedTopics may have nested structure | |
| first = related[0] | |
| if isinstance(first, dict) and first.get("Text"): | |
| parts.append(first.get("Text")) | |
| if parts: | |
| return " \n".join(parts) | |
| # fallback to heading | |
| return data.get("Heading") or "(no summary found)" | |
| except Exception as e: | |
| return f"(duckduckgo error) {e}" | |
| # Export a smolagents-wrapped tool if available so the agent's interpreter | |
| # can call `duckduckgo_search` directly when executing parsed code. | |
| if tool is not None: | |
| try: | |
| def duckduckgo_search_tool(query: str, region: str = "wt-wt") -> str: | |
| return duckduckgo_search(query, region) | |
| except Exception: | |
| duckduckgo_search_tool = duckduckgo_search | |
| else: | |
| duckduckgo_search_tool = duckduckgo_search | |
| def wikipedia_search(query: str) -> str: | |
| """Search Wikipedia for a query and return the page summary for the top hit. | |
| This function first searches for pages via the MediaWiki API, then fetches the summary | |
| for the top search result using the REST summary endpoint. | |
| """ | |
| if not query: | |
| return "(no query provided)" | |
| try: | |
| # Use browser-like headers to reduce chance of 403/blocks | |
| headers = { | |
| "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0 Safari/537.36", | |
| "Accept": "application/json, text/javascript, */*; q=0.01", | |
| } | |
| search_params = {"action": "query", "list": "search", "srsearch": query, "format": "json", "srlimit": 1} | |
| r = requests.get("https://en.wikipedia.org/w/api.php", params=search_params, timeout=10, headers=headers) | |
| # If API returns 403 or other non-200, fallback to DuckDuckGo | |
| if r.status_code != 200: | |
| logger.warning("wikipedia_search API returned status %s, falling back to DuckDuckGo", r.status_code) | |
| return duckduckgo_search(query) | |
| r.raise_for_status() | |
| sr = r.json().get("query", {}).get("search", []) | |
| if not sr: | |
| return "(no wiki result)" | |
| title = sr[0].get("title") | |
| # fetch summary | |
| summary_url = f"https://en.wikipedia.org/api/rest_v1/page/summary/{requests.utils.requote_uri(title)}" | |
| summary_resp = requests.get(summary_url, timeout=10, headers=headers) | |
| if summary_resp.status_code != 200: | |
| logger.warning("wikipedia summary endpoint returned status %s for %s, falling back to DuckDuckGo", summary_resp.status_code, title) | |
| return duckduckgo_search(query) | |
| summary_resp.raise_for_status() | |
| summary = summary_resp.json() | |
| return summary.get("extract") or summary.get("description") or "(no summary)" | |
| except Exception as e: | |
| logger.warning("wikipedia_search failed: %s; falling back to DuckDuckGo", e) | |
| try: | |
| return duckduckgo_search(query) | |
| except Exception: | |
| return f"(wikipedia error) {e}" | |
| # Export a smolagents-wrapped tool if available so the agent's interpreter | |
| # can call `wikipedia_search` directly when executing parsed code. | |
| if tool is not None: | |
| try: | |
| def wikipedia_search_tool(query: str) -> str: | |
| return wikipedia_search(query) | |
| except Exception: | |
| wikipedia_search_tool = wikipedia_search | |
| else: | |
| wikipedia_search_tool = wikipedia_search | |
| __all__ = [ | |
| "duckduckgo_search", | |
| "duckduckgo_search_tool", | |
| "wikipedia_search", | |
| "wikipedia_search_tool", | |
| ] | |