import logging
import os
import asyncio
from protos import browser_pb2
logger = logging.getLogger(__name__)
class ResponseBuilder:
def __init__(self, shm_base):
self.shm_base = shm_base
async def build(self, page, session_id, status="success", error_message=None, **kwargs):
"""Helper to safely build a BrowserResponse."""
try:
url = page.url
except:
url = "about:blank"
try:
title = await page.title()
except:
title = "Unknown (Navigating)"
screenshot_path = kwargs.pop("screenshot_path", "")
if not screenshot_path:
try:
suffix = "error" if status != "success" else "screen"
screenshot_file = os.path.join(self.shm_base, f"{session_id}_{int(asyncio.get_event_loop().time())}_{suffix}.png")
await page.screenshot(path=screenshot_file, timeout=5000)
screenshot_path = screenshot_file
except Exception as se:
logger.warning(f"Auto-screenshot failed ({status}): {se}")
return browser_pb2.BrowserResponse(
session_id=session_id,
url=url,
title=title,
status=status,
error_message=error_message or "",
screenshot_path=screenshot_path,
dom_path=kwargs.get("dom_path", ""),
a11y_path=kwargs.get("a11y_path", ""),
eval_result=str(kwargs.get("eval_result", ""))
)
def error_to_ai_message(self, error, selector):
"""Translates technical errors into actionable AI advice."""
msg = str(error).lower()
if "timeout" in msg or "waiting for" in msg:
return f"Element '{selector}' not found or invisible after timeout. Try scrolling or checking if the page changed."
if "intercepts pointer events" in msg or "not interactable" in msg:
return f"Element '{selector}' is covered by an overlay or not clickable. Try closing popups or clicking elsewhere."
if "strict mode violation" in msg:
return f"Multiple elements found for '{selector}'. Use a more specific ref or run a new snapshot."
return str(error)