in src/nova_act/impl/playwright.py [0:0]
def start(self, session_logs_directory: str | None) -> None:
"""Start and attach the Browser"""
if self._context is not None:
_LOGGER.warning("Playwright already attached, to start over, stop the client")
return
if self._record_video:
assert session_logs_directory is not None, "Started without a logs dir when record_video is True"
self._session_logs_directory = session_logs_directory
try:
# Start a new playwright instance if one was not provided by the user
if self._playwright is None:
try:
self._playwright = sync_playwright().start()
except RuntimeError as e:
if "It looks like you are using Playwright Sync API inside the asyncio loop" in str(e):
raise StartFailed(
"Each NovaAct must have its own execution context. "
"To parallelize, dedicate one thread per NovaAct instance."
) from e
raise
# Attach to a context or create one.
if self._cdp_endpoint_url is not None:
browser = self._playwright.chromium.connect_over_cdp(self._cdp_endpoint_url)
if not browser.contexts:
raise InvalidPlaywrightState("No contexts found in the browser")
context = browser.contexts[0]
trusted_page = context.new_page()
else:
if not os.environ.get("NOVA_ACT_SKIP_PLAYWRIGHT_INSTALL"):
with_deps = should_install_chromium_dependencies()
if not install(self._playwright.chromium, with_deps=with_deps):
raise StartFailed(
"Failed to install Playwright browser binaries. If you have "
"already installed these, you may skip this step by specifying the "
"NOVA_ACT_SKIP_PLAYWRIGHT_INSTALL environment variable. Otherwise, "
"the binaries can be installed with "
f"`python -m playwright install {'--with-deps ' if with_deps else ''}chromium`. "
"For more information, please consult Playwright's documentation: "
"https://playwright.dev/python/docs/browsers"
)
user_browser_args = os.environ.get("NOVA_ACT_BROWSER_ARGS", "").split()
launch_args = [
f"--disable-extensions-except={self._extension_path}",
f"--load-extension={self._extension_path}",
f"--window-size={self.screen_width},{self.screen_height}",
"--disable-blink-features=AutomationControlled", # Suppress navigator.webdriver flag
*(["--headless=new"] if self._headless else []),
*([] if not self._profile_directory else [f"--profile-directory={self._profile_directory}"]),
"--silent-debugger-extension-api",
*user_browser_args,
]
context_options = {
"headless": self._headless,
"args": launch_args,
"ignore_default_args": [
"--enable-automation"
], # Disable infobar with automated test software message
# If you set viewport any user changes to the browser size will skew screenshots
"no_viewport": True,
"channel": self._chrome_channel,
}
if self.user_agent:
context_options["user_agent"] = self.user_agent
else:
# Detect user agent by launching a headless browser, and add suffix.
browser = self._playwright.chromium.launch(
headless=True, args=["--headless=new", *user_browser_args]
)
page = browser.new_page()
original_user_agent = page.evaluate("() => navigator.userAgent")
browser.close()
# Replace the headless chrome bit since it's a detection artifact.
original_user_agent = original_user_agent.replace("HeadlessChrome/", "Chrome/")
context_options["user_agent"] = original_user_agent + _DEFAULT_USER_AGENT_SUFFIX
if self._record_video:
assert self._session_logs_directory is not None
context_options["record_video_dir"] = self._session_logs_directory
context_options["record_video_size"] = {"width": self.screen_width, "height": self.screen_height}
context = self._launch_browser(context_options)
trusted_page = context.pages[0]
self._init_browser_context(context, trusted_page)
self._context = context
except StartFailed:
raise
except Exception as e:
self.stop()
raise StartFailed("Failed to start and initialize Playwright for NovaAct") from e