From c2b68cdce7e3e613768eaa457cb2f2ab9645f9b0 Mon Sep 17 00:00:00 2001 From: openhands Date: Tue, 4 Nov 2025 14:55:34 +0530 Subject: [PATCH 1/7] Add Windows browser path checks to Chromium detection Enhanced _check_chromium_available to check common Windows installation paths for Chrome and Edge executables. Also added support for Playwright cache detection on Windows using LOCALAPPDATA. --- .../openhands/tools/browser_use/impl.py | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/openhands-tools/openhands/tools/browser_use/impl.py b/openhands-tools/openhands/tools/browser_use/impl.py index cbe6aebf1b..71377a7309 100644 --- a/openhands-tools/openhands/tools/browser_use/impl.py +++ b/openhands-tools/openhands/tools/browser_use/impl.py @@ -35,11 +35,27 @@ def _check_chromium_available() -> str | None: if path := shutil.which(binary): return path + # Check common Windows installation paths + if os.name == "nt": + windows_chrome_paths = [ + Path(os.environ.get("PROGRAMFILES", "C:\\Program Files")) / "Google" / "Chrome" / "Application" / "chrome.exe", + Path(os.environ.get("PROGRAMFILES(X86)", "C:\\Program Files (x86)")) / "Google" / "Chrome" / "Application" / "chrome.exe", + Path(os.environ.get("LOCALAPPDATA", "")) / "Google" / "Chrome" / "Application" / "chrome.exe", + Path(os.environ.get("PROGRAMFILES", "C:\\Program Files")) / "Microsoft" / "Edge" / "Application" / "msedge.exe", + Path(os.environ.get("PROGRAMFILES(X86)", "C:\\Program Files (x86)")) / "Microsoft" / "Edge" / "Application" / "msedge.exe", + ] + for chrome_path in windows_chrome_paths: + if chrome_path.exists(): + return str(chrome_path) + # Check Playwright-installed Chromium playwright_cache_candidates = [ - Path.home() / ".cache" / "ms-playwright", - Path.home() / "Library" / "Caches" / "ms-playwright", + Path.home() / ".cache" / "ms-playwright", # Linux + Path.home() / "Library" / "Caches" / "ms-playwright", # macOS ] + if os.name == "nt" and os.environ.get("LOCALAPPDATA"): + playwright_cache_candidates.append(Path(os.environ["LOCALAPPDATA"]) / "ms-playwright") + for playwright_cache in playwright_cache_candidates: if playwright_cache.exists(): chromium_dirs = list(playwright_cache.glob("chromium-*")) From 87938d3b97b920e569b56ef506df93ae0d341902 Mon Sep 17 00:00:00 2001 From: openhands Date: Thu, 6 Nov 2025 10:22:31 +0530 Subject: [PATCH 2/7] format --- .../openhands/tools/browser_use/impl.py | 36 +++++++++++++++---- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/openhands-tools/openhands/tools/browser_use/impl.py b/openhands-tools/openhands/tools/browser_use/impl.py index d2d37035aa..3ca35d0fcf 100644 --- a/openhands-tools/openhands/tools/browser_use/impl.py +++ b/openhands-tools/openhands/tools/browser_use/impl.py @@ -38,11 +38,31 @@ def _check_chromium_available() -> str | None: # Check common Windows installation paths if os.name == "nt": windows_chrome_paths = [ - Path(os.environ.get("PROGRAMFILES", "C:\\Program Files")) / "Google" / "Chrome" / "Application" / "chrome.exe", - Path(os.environ.get("PROGRAMFILES(X86)", "C:\\Program Files (x86)")) / "Google" / "Chrome" / "Application" / "chrome.exe", - Path(os.environ.get("LOCALAPPDATA", "")) / "Google" / "Chrome" / "Application" / "chrome.exe", - Path(os.environ.get("PROGRAMFILES", "C:\\Program Files")) / "Microsoft" / "Edge" / "Application" / "msedge.exe", - Path(os.environ.get("PROGRAMFILES(X86)", "C:\\Program Files (x86)")) / "Microsoft" / "Edge" / "Application" / "msedge.exe", + Path(os.environ.get("PROGRAMFILES", "C:\\Program Files")) + / "Google" + / "Chrome" + / "Application" + / "chrome.exe", + Path(os.environ.get("PROGRAMFILES(X86)", "C:\\Program Files (x86)")) + / "Google" + / "Chrome" + / "Application" + / "chrome.exe", + Path(os.environ.get("LOCALAPPDATA", "")) + / "Google" + / "Chrome" + / "Application" + / "chrome.exe", + Path(os.environ.get("PROGRAMFILES", "C:\\Program Files")) + / "Microsoft" + / "Edge" + / "Application" + / "msedge.exe", + Path(os.environ.get("PROGRAMFILES(X86)", "C:\\Program Files (x86)")) + / "Microsoft" + / "Edge" + / "Application" + / "msedge.exe", ] for chrome_path in windows_chrome_paths: if chrome_path.exists(): @@ -54,8 +74,10 @@ def _check_chromium_available() -> str | None: Path.home() / "Library" / "Caches" / "ms-playwright", # macOS ] if os.name == "nt" and os.environ.get("LOCALAPPDATA"): - playwright_cache_candidates.append(Path(os.environ["LOCALAPPDATA"]) / "ms-playwright") - + playwright_cache_candidates.append( + Path(os.environ["LOCALAPPDATA"]) / "ms-playwright" + ) + for playwright_cache in playwright_cache_candidates: if playwright_cache.exists(): chromium_dirs = list(playwright_cache.glob("chromium-*")) From 87718f51cf713de39494f7e2183ceb13e928a003 Mon Sep 17 00:00:00 2001 From: openhands Date: Fri, 7 Nov 2025 03:27:11 +0530 Subject: [PATCH 3/7] Refactor Windows Chromium path checks in impl.py Removed redundant os.name check and always define Windows Chromium and Edge paths. Simplified Playwright cache candidate logic by unconditionally including the Windows path. --- .../openhands/tools/browser_use/impl.py | 66 +++++++++---------- 1 file changed, 31 insertions(+), 35 deletions(-) diff --git a/openhands-tools/openhands/tools/browser_use/impl.py b/openhands-tools/openhands/tools/browser_use/impl.py index 3ca35d0fcf..5969d8a8c1 100644 --- a/openhands-tools/openhands/tools/browser_use/impl.py +++ b/openhands-tools/openhands/tools/browser_use/impl.py @@ -36,47 +36,43 @@ def _check_chromium_available() -> str | None: return path # Check common Windows installation paths - if os.name == "nt": - windows_chrome_paths = [ - Path(os.environ.get("PROGRAMFILES", "C:\\Program Files")) - / "Google" - / "Chrome" - / "Application" - / "chrome.exe", - Path(os.environ.get("PROGRAMFILES(X86)", "C:\\Program Files (x86)")) - / "Google" - / "Chrome" - / "Application" - / "chrome.exe", - Path(os.environ.get("LOCALAPPDATA", "")) - / "Google" - / "Chrome" - / "Application" - / "chrome.exe", - Path(os.environ.get("PROGRAMFILES", "C:\\Program Files")) - / "Microsoft" - / "Edge" - / "Application" - / "msedge.exe", - Path(os.environ.get("PROGRAMFILES(X86)", "C:\\Program Files (x86)")) - / "Microsoft" - / "Edge" - / "Application" - / "msedge.exe", - ] - for chrome_path in windows_chrome_paths: - if chrome_path.exists(): - return str(chrome_path) + windows_chrome_paths = [ + Path(os.environ.get("PROGRAMFILES", "C:\\Program Files")) + / "Google" + / "Chrome" + / "Application" + / "chrome.exe", + Path(os.environ.get("PROGRAMFILES(X86)", "C:\\Program Files (x86)")) + / "Google" + / "Chrome" + / "Application" + / "chrome.exe", + Path(os.environ.get("LOCALAPPDATA", "")) + / "Google" + / "Chrome" + / "Application" + / "chrome.exe", + Path(os.environ.get("PROGRAMFILES", "C:\\Program Files")) + / "Microsoft" + / "Edge" + / "Application" + / "msedge.exe", + Path(os.environ.get("PROGRAMFILES(X86)", "C:\\Program Files (x86)")) + / "Microsoft" + / "Edge" + / "Application" + / "msedge.exe", + ] + for chrome_path in windows_chrome_paths: + if chrome_path.exists(): + return str(chrome_path) # Check Playwright-installed Chromium playwright_cache_candidates = [ Path.home() / ".cache" / "ms-playwright", # Linux Path.home() / "Library" / "Caches" / "ms-playwright", # macOS + Path(os.environ.get("LOCALAPPDATA", "")) / "ms-playwright", # Windows ] - if os.name == "nt" and os.environ.get("LOCALAPPDATA"): - playwright_cache_candidates.append( - Path(os.environ["LOCALAPPDATA"]) / "ms-playwright" - ) for playwright_cache in playwright_cache_candidates: if playwright_cache.exists(): From aa05bf0a9d973b565e1ce2ef7077ed43f8d608e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E0=AE=AE=E0=AE=A9=E0=AF=8B=E0=AE=9C=E0=AF=8D=E0=AE=95?= =?UTF-8?q?=E0=AF=81=E0=AE=AE=E0=AE=BE=E0=AE=B0=E0=AF=8D=20=E0=AE=AA?= =?UTF-8?q?=E0=AE=B4=E0=AE=A9=E0=AE=BF=E0=AE=9A=E0=AF=8D=E0=AE=9A=E0=AE=BE?= =?UTF-8?q?=E0=AE=AE=E0=AE=BF?= Date: Thu, 20 Nov 2025 10:30:08 +0530 Subject: [PATCH 4/7] Refactor Windows browser path detection logic Simplifies and generalizes the construction of Windows browser executable paths by iterating over environment variables and browser definitions. This reduces code duplication and improves maintainability. --- .../openhands/tools/browser_use/impl.py | 46 ++++++++----------- 1 file changed, 20 insertions(+), 26 deletions(-) diff --git a/openhands-tools/openhands/tools/browser_use/impl.py b/openhands-tools/openhands/tools/browser_use/impl.py index 5969d8a8c1..bcd6a35783 100644 --- a/openhands-tools/openhands/tools/browser_use/impl.py +++ b/openhands-tools/openhands/tools/browser_use/impl.py @@ -36,33 +36,27 @@ def _check_chromium_available() -> str | None: return path # Check common Windows installation paths - windows_chrome_paths = [ - Path(os.environ.get("PROGRAMFILES", "C:\\Program Files")) - / "Google" - / "Chrome" - / "Application" - / "chrome.exe", - Path(os.environ.get("PROGRAMFILES(X86)", "C:\\Program Files (x86)")) - / "Google" - / "Chrome" - / "Application" - / "chrome.exe", - Path(os.environ.get("LOCALAPPDATA", "")) - / "Google" - / "Chrome" - / "Application" - / "chrome.exe", - Path(os.environ.get("PROGRAMFILES", "C:\\Program Files")) - / "Microsoft" - / "Edge" - / "Application" - / "msedge.exe", - Path(os.environ.get("PROGRAMFILES(X86)", "C:\\Program Files (x86)")) - / "Microsoft" - / "Edge" - / "Application" - / "msedge.exe", + windows_chrome_paths = [] + env_vars = [ + ("PROGRAMFILES", "C:\\Program Files"), + ("PROGRAMFILES(X86)", "C:\\Program Files (x86)"), + ("LOCALAPPDATA", ""), ] + browsers = [ + ("Google", "Chrome", "Application", "chrome.exe"), + ("Microsoft", "Edge", "Application", "msedge.exe"), + ] + + for env_var, default in env_vars: + for vendor, browser, app_dir, executable in browsers: + # Skip LOCALAPPDATA for Edge + if env_var == "LOCALAPPDATA" and vendor == "Microsoft": + continue + base_path = Path(os.environ.get(env_var, default)) + if base_path: + windows_chrome_paths.append( + base_path / vendor / browser / app_dir / executable + ) for chrome_path in windows_chrome_paths: if chrome_path.exists(): return str(chrome_path) From 38306394b504fa79344771fc4d1b4a1493a082ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E0=AE=AE=E0=AE=A9=E0=AF=8B=E0=AE=9C=E0=AF=8D=E0=AE=95?= =?UTF-8?q?=E0=AF=81=E0=AE=AE=E0=AE=BE=E0=AE=B0=E0=AF=8D=20=E0=AE=AA?= =?UTF-8?q?=E0=AE=B4=E0=AE=A9=E0=AE=BF=E0=AE=9A=E0=AF=8D=E0=AE=9A=E0=AE=BE?= =?UTF-8?q?=E0=AE=AE=E0=AE=BF?= Date: Thu, 20 Nov 2025 10:31:38 +0530 Subject: [PATCH 5/7] Remove trailing whitespace in impl.py Cleaned up unnecessary trailing whitespace in the _check_chromium_available function for improved code style. --- openhands-tools/openhands/tools/browser_use/impl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openhands-tools/openhands/tools/browser_use/impl.py b/openhands-tools/openhands/tools/browser_use/impl.py index bcd6a35783..bcb97d6e40 100644 --- a/openhands-tools/openhands/tools/browser_use/impl.py +++ b/openhands-tools/openhands/tools/browser_use/impl.py @@ -46,7 +46,7 @@ def _check_chromium_available() -> str | None: ("Google", "Chrome", "Application", "chrome.exe"), ("Microsoft", "Edge", "Application", "msedge.exe"), ] - + for env_var, default in env_vars: for vendor, browser, app_dir, executable in browsers: # Skip LOCALAPPDATA for Edge From 0fa0e43cf12def905bce5161b6e6ed0e43bc09f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E0=AE=AE=E0=AE=A9=E0=AF=8B=E0=AE=9C=E0=AF=8D=E0=AE=95?= =?UTF-8?q?=E0=AF=81=E0=AE=AE=E0=AE=BE=E0=AE=B0=E0=AF=8D=20=E0=AE=AA?= =?UTF-8?q?=E0=AE=B4=E0=AE=A9=E0=AE=BF=E0=AE=9A=E0=AF=8D=E0=AE=9A=E0=AE=BE?= =?UTF-8?q?=E0=AE=AE=E0=AE=BF?= Date: Thu, 20 Nov 2025 12:40:15 +0530 Subject: [PATCH 6/7] fix: allow detection of per-user Edge installations in LOCALAPPDATA Remove incorrect skip logic that prevented checking %LOCALAPPDATA% for Microsoft Edge installations. While Edge is typically installed system-wide, it can also be installed per-user in enterprise environments at %LOCALAPPDATA%\Microsoft\Edge\Application\msedge.exe. This fix ensures the browser detection can find Edge in both installation scenarios. --- openhands-tools/openhands/tools/browser_use/impl.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/openhands-tools/openhands/tools/browser_use/impl.py b/openhands-tools/openhands/tools/browser_use/impl.py index bcb97d6e40..db72f7b549 100644 --- a/openhands-tools/openhands/tools/browser_use/impl.py +++ b/openhands-tools/openhands/tools/browser_use/impl.py @@ -49,9 +49,6 @@ def _check_chromium_available() -> str | None: for env_var, default in env_vars: for vendor, browser, app_dir, executable in browsers: - # Skip LOCALAPPDATA for Edge - if env_var == "LOCALAPPDATA" and vendor == "Microsoft": - continue base_path = Path(os.environ.get(env_var, default)) if base_path: windows_chrome_paths.append( From cb7086e24786fc3475a5826d14db7f3b6452dd05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E0=AE=AE=E0=AE=A9=E0=AF=8B=E0=AE=9C=E0=AF=8D=E0=AE=95?= =?UTF-8?q?=E0=AF=81=E0=AE=AE=E0=AE=BE=E0=AE=B0=E0=AF=8D=20=E0=AE=AA?= =?UTF-8?q?=E0=AE=B4=E0=AE=A9=E0=AE=BF=E0=AE=9A=E0=AF=8D=E0=AE=9A=E0=AE=BE?= =?UTF-8?q?=E0=AE=AE=E0=AE=BF?= Date: Fri, 21 Nov 2025 07:32:40 +0530 Subject: [PATCH 7/7] Rename browsers list to windows_browsers Renamed the 'browsers' variable to 'windows_browsers' for clarity and updated its usage in the Chromium availability check function. --- openhands-tools/openhands/tools/browser_use/impl.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openhands-tools/openhands/tools/browser_use/impl.py b/openhands-tools/openhands/tools/browser_use/impl.py index db72f7b549..7aedbb4fba 100644 --- a/openhands-tools/openhands/tools/browser_use/impl.py +++ b/openhands-tools/openhands/tools/browser_use/impl.py @@ -42,13 +42,13 @@ def _check_chromium_available() -> str | None: ("PROGRAMFILES(X86)", "C:\\Program Files (x86)"), ("LOCALAPPDATA", ""), ] - browsers = [ + windows_browsers = [ ("Google", "Chrome", "Application", "chrome.exe"), ("Microsoft", "Edge", "Application", "msedge.exe"), ] for env_var, default in env_vars: - for vendor, browser, app_dir, executable in browsers: + for vendor, browser, app_dir, executable in windows_browsers: base_path = Path(os.environ.get(env_var, default)) if base_path: windows_chrome_paths.append(