manus-backend / backend /utils /browser.py
OpenHands
feat: Full Manus AI Agent with autonomous capabilities
507d4dd
Raw
History Blame Contribute Delete
6.94 kB
"""Browser automation using Playwright for Manus AI agent."""
from typing import Optional, Dict, Any
import asyncio
import json
class BrowserAutomation:
"""
Browser automation tool using Playwright.
Can work with E2B sandbox browser or standalone.
"""
def __init__(self, playwright=None):
self.playwright = playwright
self.browser = None
self.context = None
self.page = None
self._initialized = False
async def initialize(self):
"""Initialize Playwright and browser."""
if self._initialized:
return
try:
from playwright.async_api import async_playwright
self.playwright = await async_playwright().start()
self.browser = await self.playwright.chromium.launch(headless=True)
self.context = await self.browser.new_context(
viewport={"width": 1920, "height": 1080}
)
self.page = await self.context.new_page()
self._initialized = True
except ImportError:
raise Exception("Playwright not installed. Run: pip install playwright && playwright install")
except Exception as e:
raise Exception(f"Failed to initialize browser: {e}")
async def navigate(self, url: str) -> Dict[str, Any]:
"""Navigate to a URL."""
if not self._initialized:
await self.initialize()
try:
response = await self.page.goto(url, wait_until="domcontentloaded", timeout=30000)
title = await self.page.title()
return {
"success": True,
"url": str(self.page.url),
"title": title,
"status_code": response.status if response else None
}
except Exception as e:
return {"success": False, "error": str(e)}
async def click(self, selector: str, timeout: int = 5000) -> Dict[str, Any]:
"""Click an element by CSS selector."""
if not self._initialized:
await self.initialize()
try:
await self.page.click(selector, timeout=timeout)
return {"success": True, "selector": selector}
except Exception as e:
return {"success": False, "error": str(e)}
async def type(self, selector: str, text: str, delay: int = 50) -> Dict[str, Any]:
"""Type text into an input field."""
if not self._initialized:
await self.initialize()
try:
await self.page.fill(selector, text)
return {"success": True, "selector": selector, "text": text}
except Exception as e:
return {"success": False, "error": str(e)}
async def get_content(self, selector: Optional[str] = None) -> Dict[str, Any]:
"""Get page content or element content."""
if not self._initialized:
await self.initialize()
try:
if selector:
content = await self.page.text_content(selector)
else:
content = await self.page.content()
return {"success": True, "content": content}
except Exception as e:
return {"success": False, "error": str(e)}
async def screenshot(self, path: Optional[str] = None, full_page: bool = False) -> Dict[str, Any]:
"""Take a screenshot."""
if not self._initialized:
await self.initialize()
try:
if path:
await self.page.screenshot(path=path, full_page=full_page)
return {"success": True, "path": path}
else:
# Return base64 encoded screenshot
encoded = await self.page.screenshot()
return {"success": True, "screenshot": encoded}
except Exception as e:
return {"success": False, "error": str(e)}
async def evaluate(self, script: str) -> Dict[str, Any]:
"""Execute JavaScript on the page."""
if not self._initialized:
await self.initialize()
try:
result = await self.page.evaluate(script)
return {"success": True, "result": result}
except Exception as e:
return {"success": False, "error": str(e)}
async def wait_for_selector(self, selector: str, timeout: int = 5000) -> Dict[str, Any]:
"""Wait for an element to appear."""
if not self._initialized:
await self.initialize()
try:
await self.page.wait_for_selector(selector, timeout=timeout)
return {"success": True, "selector": selector}
except Exception as e:
return {"success": False, "error": str(e)}
async def close(self):
"""Close the browser."""
if self.browser:
await self.browser.close()
if self.playwright:
await self.playwright.stop()
self._initialized = False
# Standalone browser tool for use without E2B
async def create_browser_tool() -> BrowserAutomation:
"""Create a standalone browser automation tool."""
return BrowserAutomation()
# Integration with E2B sandbox
class E2BBrowserTool:
"""Browser tool that runs in E2B sandbox with Playwright installed."""
def __init__(self, sandbox):
self.sandbox = sandbox
async def execute(self, action: str, **params) -> Dict[str, Any]:
"""Execute browser action in E2B sandbox."""
try:
if action == "install":
# Install Playwright in sandbox
result = await self.sandbox.commands.run(
"pip install playwright && playwright install chromium --with-deps",
timeout=300
)
return {"success": True, "output": result.stdout}
elif action == "navigate":
# For E2B, we'd need to run a script
script = f"""
import asyncio
from playwright.async_api import async_playwright
async def main():
async with async_playwright() as p:
browser = await p.chromium.launch(headless=True)
page = await browser.new_page()
await page.goto("{params.get('url', '')}")
title = await page.title()
await browser.close()
return title
result = asyncio.run(main())
print(result)
"""
result = await self.sandbox.commands.run(
f"python3 -c '{script.replace(chr(39), chr(39)*3)}'",
timeout=60
)
return {"success": True, "output": result.stdout, "url": params.get("url")}
else:
return {"success": False, "error": f"Unknown action: {action}"}
except Exception as e:
return {"success": False, "error": str(e)}