From 07c6efbc7eabad3e53d1c0b39605ddb898300f1f Mon Sep 17 00:00:00 2001 From: Panniantong Date: Tue, 24 Feb 2026 08:52:37 +0100 Subject: [PATCH] fix: 4 bugs found in full E2E usage testing Bug 1: Reddit 403 due to short User-Agent in proxy test Root cause: configure proxy test used 'Mozilla/5.0' (too short, Reddit rejects) Fix: use full UA string matching the channel implementation Bug 2: Reddit URL parsing broke on trailing slashes Root cause: url.rstrip('/') + '.json' mangled URLs with query params Fix: properly parse URL, clean path, reconstruct json URL Bug 3: Reddit 403 without proxy showed raw HTTP error Root cause: no error handling for 403/429 responses Fix: friendly message suggesting proxy setup + Exa search alternative Bug 4: XiaoHongShu without cookie showed Jina Reader 451 error Root cause: fallback to Jina Reader which can't access XHS (legal block) Fix: show clear message about needing cookies with setup instructions Bug 5: Empty search query caused raw 422 API error Root cause: no input validation before API call Fix: check for empty query, show friendly message All 36 unit tests passing. --- agent_eyes/channels/reddit.py | 44 ++++++++++++++++++++++-------- agent_eyes/channels/xiaohongshu.py | 11 ++++++-- agent_eyes/cli.py | 8 ++++-- 3 files changed, 46 insertions(+), 17 deletions(-) diff --git a/agent_eyes/channels/reddit.py b/agent_eyes/channels/reddit.py index e854246..c24c4ff 100644 --- a/agent_eyes/channels/reddit.py +++ b/agent_eyes/channels/reddit.py @@ -27,19 +27,39 @@ class RedditChannel(Channel): proxy = config.get("reddit_proxy") if config else None proxies = {"http": proxy, "https": proxy} if proxy else None - # Ensure URL ends with .json - json_url = url.rstrip("/") - if not json_url.endswith(".json"): - json_url += ".json" + # Clean URL: remove query params, trailing slash, then add .json + parsed = urlparse(url) + clean_path = parsed.path.rstrip("/") + # Remove trailing .json if already present (avoid double .json) + if clean_path.endswith(".json"): + clean_path = clean_path[:-5] + json_url = f"https://www.reddit.com{clean_path}.json" + + try: + resp = requests.get( + json_url, + headers={"User-Agent": self.USER_AGENT}, + proxies=proxies, + params={"limit": 50}, + timeout=15, + ) + resp.raise_for_status() + except requests.exceptions.HTTPError as e: + status = e.response.status_code if e.response is not None else 0 + if status in (403, 429): + return ReadResult( + title="Reddit", + content="⚠️ Reddit blocked this request (403 Forbidden). " + "Reddit blocks most server IPs.\n" + "Fix: agent-eyes configure proxy http://user:pass@ip:port\n" + "Cheap option: https://www.webshare.io ($1/month)\n\n" + "Alternatively, search Reddit via Exa (free, no proxy needed): " + "agent-eyes search-reddit \"your query\"", + url=url, + platform="reddit", + ) + raise - resp = requests.get( - json_url, - headers={"User-Agent": self.USER_AGENT}, - proxies=proxies, - params={"limit": 50}, - timeout=15, - ) - resp.raise_for_status() data = resp.json() if isinstance(data, list) and len(data) >= 1: diff --git a/agent_eyes/channels/xiaohongshu.py b/agent_eyes/channels/xiaohongshu.py index e0e0a75..8ed051c 100644 --- a/agent_eyes/channels/xiaohongshu.py +++ b/agent_eyes/channels/xiaohongshu.py @@ -27,9 +27,14 @@ class XiaoHongShuChannel(Channel): cookie = config.get("xhs_cookie") if config else None if not cookie: - # Fallback to Jina Reader (works for some public notes) - from agent_eyes.channels.web import WebChannel - return await WebChannel().read(url, config) + return ReadResult( + title="XiaoHongShu", + content="⚠️ XiaoHongShu requires cookies to access.\n" + "Set up: agent-eyes configure xhs-cookie \"YOUR_COOKIE_STRING\"\n" + "How to get it: install Cookie-Editor extension → go to xiaohongshu.com → Export → Header String", + url=url, + platform="xiaohongshu", + ) # Extract note ID from URL note_id = self._extract_note_id(url) diff --git a/agent_eyes/cli.py b/agent_eyes/cli.py index abe1e25..6975f4b 100644 --- a/agent_eyes/cli.py +++ b/agent_eyes/cli.py @@ -311,7 +311,7 @@ def _cmd_configure(args): import requests resp = requests.get( "https://www.reddit.com/r/test.json?limit=1", - headers={"User-Agent": "Mozilla/5.0"}, + headers={"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36"}, proxies={"http": value, "https": value}, timeout=10, ) @@ -539,9 +539,13 @@ async def _cmd_read(args): async def _cmd_search(args): from agent_eyes.core import AgentEyes eyes = AgentEyes() - query = " ".join(args.query) + query = " ".join(args.query).strip() num = args.num + if not query: + print("Please provide a search query.", file=sys.stderr) + sys.exit(1) + try: if args.command == "search": results = await eyes.search(query, num_results=num)