import json import httpx from langchain_core.tools import tool from langchain_community.utilities import WikipediaAPIWrapper _REST_BASE = "https://en.wikipedia.org/api/rest_v1/page/summary" _HEADERS = {"User-Agent": "logic-assistant/1.0 (educational tool)"} _TIMEOUT = 8 _wrapper = WikipediaAPIWrapper(top_k_results=1, doc_content_chars_max=1500, lang="en") def _rest_summary(concept: str) -> str | None: """ Try the Wikipedia REST summary endpoint. Returns extract text, or None if the page isn't found. Raises on network/server errors so the caller can fall back. """ slug = concept.strip().replace(" ", "_") url = f"{_REST_BASE}/{httpx.URL(slug)}" resp = httpx.get(url, headers=_HEADERS, timeout=_TIMEOUT, follow_redirects=True) if resp.status_code == 404: return None resp.raise_for_status() return resp.json().get("extract") or None @tool def wikipedia(query: str) -> str: """Fetch a public-domain definition of a logic or philosophy concept from Wikipedia. Input must be the English concept name (e.g. 'hasty generalization', 'ad hominem'). Call this for every key concept found by search_graph so we have an external definition.""" # 1. Try REST summary API — fast, reliable, no JSONDecodeError risk try: text = _rest_summary(query) if text: return text except (httpx.HTTPStatusError, httpx.RequestError): pass # fall through to wrapper # 2. Fallback: WikipediaAPIWrapper (search-based, handles fuzzy titles) try: return _wrapper.run(query) except json.JSONDecodeError: raise RuntimeError( f"Wikipedia API returned an empty response for '{query}' " "(transient network issue). Use tavily_search as fallback." )