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.
This commit is contained in:
@@ -27,19 +27,39 @@ class RedditChannel(Channel):
|
|||||||
proxy = config.get("reddit_proxy") if config else None
|
proxy = config.get("reddit_proxy") if config else None
|
||||||
proxies = {"http": proxy, "https": proxy} if proxy else None
|
proxies = {"http": proxy, "https": proxy} if proxy else None
|
||||||
|
|
||||||
# Ensure URL ends with .json
|
# Clean URL: remove query params, trailing slash, then add .json
|
||||||
json_url = url.rstrip("/")
|
parsed = urlparse(url)
|
||||||
if not json_url.endswith(".json"):
|
clean_path = parsed.path.rstrip("/")
|
||||||
json_url += ".json"
|
# 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()
|
data = resp.json()
|
||||||
|
|
||||||
if isinstance(data, list) and len(data) >= 1:
|
if isinstance(data, list) and len(data) >= 1:
|
||||||
|
|||||||
@@ -27,9 +27,14 @@ class XiaoHongShuChannel(Channel):
|
|||||||
cookie = config.get("xhs_cookie") if config else None
|
cookie = config.get("xhs_cookie") if config else None
|
||||||
|
|
||||||
if not cookie:
|
if not cookie:
|
||||||
# Fallback to Jina Reader (works for some public notes)
|
return ReadResult(
|
||||||
from agent_eyes.channels.web import WebChannel
|
title="XiaoHongShu",
|
||||||
return await WebChannel().read(url, config)
|
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
|
# Extract note ID from URL
|
||||||
note_id = self._extract_note_id(url)
|
note_id = self._extract_note_id(url)
|
||||||
|
|||||||
+6
-2
@@ -311,7 +311,7 @@ def _cmd_configure(args):
|
|||||||
import requests
|
import requests
|
||||||
resp = requests.get(
|
resp = requests.get(
|
||||||
"https://www.reddit.com/r/test.json?limit=1",
|
"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},
|
proxies={"http": value, "https": value},
|
||||||
timeout=10,
|
timeout=10,
|
||||||
)
|
)
|
||||||
@@ -539,9 +539,13 @@ async def _cmd_read(args):
|
|||||||
async def _cmd_search(args):
|
async def _cmd_search(args):
|
||||||
from agent_eyes.core import AgentEyes
|
from agent_eyes.core import AgentEyes
|
||||||
eyes = AgentEyes()
|
eyes = AgentEyes()
|
||||||
query = " ".join(args.query)
|
query = " ".join(args.query).strip()
|
||||||
num = args.num
|
num = args.num
|
||||||
|
|
||||||
|
if not query:
|
||||||
|
print("Please provide a search query.", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if args.command == "search":
|
if args.command == "search":
|
||||||
results = await eyes.search(query, num_results=num)
|
results = await eyes.search(query, num_results=num)
|
||||||
|
|||||||
Reference in New Issue
Block a user