From 9d2e2ddcf77135171939f720ed3db676073436cf Mon Sep 17 00:00:00 2001 From: Christian Gick Date: Sun, 1 Mar 2026 16:41:37 +0200 Subject: [PATCH] fix(MAT-13): Add DNS fallback via web search for browse_url When browse_url fails with DNS resolution error (common with STT-misrecognized domain names like "klicksports" instead of "clicksports"), automatically try a web search to find the correct domain and retry. Applied to both text and voice bot. Co-Authored-By: Claude Opus 4.6 --- bot.py | 19 +++++++++++++++++-- voice.py | 18 ++++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/bot.py b/bot.py index 37f9c6a..b6de7d4 100644 --- a/bot.py +++ b/bot.py @@ -2099,9 +2099,24 @@ class Bot: if tool_name == "web_search": return await self._brave_search(args.get("query", ""), args.get("count", 5)) - # Browse URL — no auth needed + # Browse URL — no auth needed, with DNS fallback via web search if tool_name == "browse_url": - return await self._fetch_webpage(args.get("url", "")) + url = args.get("url", "") + result = await self._fetch_webpage(url) + if "Name or service not known" in result or "Failed to fetch" in result: + from urllib.parse import urlparse + domain = urlparse(url).netloc or url + logger.info("Browse DNS fail for %s — trying web search", domain) + search_result = await self._brave_search(f"{domain} website", count=3) + if search_result and "No results" not in search_result: + url_match = re.search(r'https?://[^\s\)]+', search_result) + if url_match: + corrected_url = url_match.group(0).rstrip('.,;') + retry = await self._fetch_webpage(corrected_url) + if "Failed to fetch" not in retry: + return f"[Original URL {url} unreachable. Found correct site at {corrected_url}]\n\n{retry}" + return f"Could not reach {url}. The domain may be misspelled — ask the user to clarify." + return result # Atlassian tools — need per-user token token = await self.atlassian.get_token(sender) if sender else None diff --git a/voice.py b/voice.py index e1a931b..a3d77f9 100644 --- a/voice.py +++ b/voice.py @@ -893,6 +893,24 @@ class VoiceSession: Returns the page text content.""" logger.info("BROWSE: %s", url) result = await _fetch_webpage(url) + # On DNS failure, try to find the correct URL via web search + if "Name or service not known" in result or "Failed to fetch" in result: + from urllib.parse import urlparse + domain = urlparse(url).netloc or url + logger.info("BROWSE_DNS_FAIL: %s — trying web search for correct domain", domain) + search_result = await _brave_search(f"{domain} website") + if search_result and "No results" not in search_result: + # Extract first URL from search results + import re as _re + url_match = _re.search(r'https?://[^\s\)]+', search_result) + if url_match: + corrected_url = url_match.group(0).rstrip('.,;') + logger.info("BROWSE_RETRY: trying %s (from search)", corrected_url) + result = await _fetch_webpage(corrected_url) + if "Failed to fetch" not in result: + logger.info("BROWSE_OK: %d chars from %s (corrected)", len(result), corrected_url) + return f"[Note: Original URL {url} was unreachable. Found correct site at {corrected_url}]\n\n{result}" + return f"Could not reach {url} and web search did not find an alternative. The domain name may be misspelled — ask the user to clarify." logger.info("BROWSE_OK: %d chars from %s", len(result), url) return result