diff --git a/evoagentx/tools/browser_use.py b/evoagentx/tools/browser_use.py index 392c0de8..05c470f0 100644 --- a/evoagentx/tools/browser_use.py +++ b/evoagentx/tools/browser_use.py @@ -40,9 +40,10 @@ def __init__(self, model: str = "gpt-4o-mini", api_key: str = os.getenv("OPENAI_ try: # Try importing from the standard browser-use package (Python 3.11+) - from browser_use import Agent + from browser_use import Agent, BrowserProfile from browser_use.llm import ChatOpenAI, ChatAnthropic self.Agent = Agent + self.BrowserProfile = BrowserProfile self.ChatOpenAI = ChatOpenAI self.ChatAnthropic = ChatAnthropic except ImportError: @@ -51,6 +52,7 @@ def __init__(self, model: str = "gpt-4o-mini", api_key: str = os.getenv("OPENAI_ from browser_use_py310x import Agent from browser_use_py310x.llm import ChatOpenAI, ChatAnthropic self.Agent = Agent + self.BrowserProfile = None self.ChatOpenAI = ChatOpenAI self.ChatAnthropic = ChatAnthropic except ImportError as e: @@ -61,15 +63,15 @@ def __init__(self, model: str = "gpt-4o-mini", api_key: str = os.getenv("OPENAI_ self.api_key = api_key self.browser_type = browser_type self.headless = headless + + if self.BrowserProfile is not None and browser_type != "chromium": + raise ValueError("browser-use supports Chromium only; set browser_type='chromium'") # Initialize LLM based on model type self.llm = self._setup_llm() # Browser configuration - self.browser_config = { - "browser_type": browser_type, - "headless": headless - } + self.browser_config = {"browser_type": browser_type, "headless": headless} def _setup_llm(self): """Setup the appropriate LLM based on model name.""" @@ -109,11 +111,17 @@ async def execute_task(self, task: str) -> Dict[str, Any]: """ try: # Create agent with configuration - agent = self.Agent( - task=task, - llm=self.llm, - **self.browser_config - ) + agent_kwargs = {"task": task, "llm": self.llm} + if self.BrowserProfile is not None: + # Current browser-use configures the browser through BrowserProfile. + # Extra Agent kwargs are accepted but ignored, which previously made + # headless=True silently launch a visible browser. + agent_kwargs["browser_profile"] = self.BrowserProfile(headless=self.headless) + else: + # Keep the legacy Python 3.10 compatibility package on its old API. + agent_kwargs.update(self.browser_config) + + agent = self.Agent(**agent_kwargs) # Execute the task logger.info(f"Executing browser task: {task}") diff --git a/tests/test_browser_use.py b/tests/test_browser_use.py new file mode 100644 index 00000000..1ee94fde --- /dev/null +++ b/tests/test_browser_use.py @@ -0,0 +1,55 @@ +import asyncio +import sys +from types import ModuleType + +import pytest + +from evoagentx.tools.browser_use import BrowserUseBase + + +def install_fake_browser_use(monkeypatch, captured): + browser_use = ModuleType("browser_use") + browser_use_llm = ModuleType("browser_use.llm") + + class FakeAgent: + def __init__(self, **kwargs): + captured.update(kwargs) + + async def run(self): + return "done" + + class FakeBrowserProfile: + def __init__(self, **kwargs): + self.headless = kwargs["headless"] + + class FakeChatOpenAI: + def __init__(self, **kwargs): + self.kwargs = kwargs + + browser_use.Agent = FakeAgent + browser_use.BrowserProfile = FakeBrowserProfile + browser_use_llm.ChatOpenAI = FakeChatOpenAI + browser_use_llm.ChatAnthropic = FakeChatOpenAI + + monkeypatch.setitem(sys.modules, "browser_use", browser_use) + monkeypatch.setitem(sys.modules, "browser_use.llm", browser_use_llm) + + +def test_current_browser_use_receives_headless_profile(monkeypatch): + captured = {} + install_fake_browser_use(monkeypatch, captured) + + browser = BrowserUseBase(api_key="test-key", headless=True) + result = asyncio.run(browser.execute_task("Open example.com")) + + assert result == {"success": True, "result": "done"} + assert captured["browser_profile"].headless is True + assert "headless" not in captured + assert "browser_type" not in captured + + +def test_current_browser_use_rejects_unsupported_browser(monkeypatch): + install_fake_browser_use(monkeypatch, {}) + + with pytest.raises(ValueError, match="supports Chromium only"): + BrowserUseBase(api_key="test-key", browser_type="firefox")