-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathchrome_cdp.py
More file actions
168 lines (135 loc) · 5.17 KB
/
chrome_cdp.py
File metadata and controls
168 lines (135 loc) · 5.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
"""
Chrome CDP via Extension Relay
Instead of launching Chrome with --remote-debugging-port (which Chrome blocks
on the default profile), we use a Chrome extension + local relay server:
Browser Use <--CDP WebSocket--> Relay (:9222) <--WebSocket--> Extension
|
chrome.debugger
|
Your real Chrome
The relay server (relay.py) sits on port 9222 and speaks CDP to Browser Use
while forwarding commands to the extension via a separate WebSocket.
Requirements:
- The Chrome extension (extension/) must be loaded in Chrome
- Chrome must be running normally (user's real profile)
- The relay server is started by this module
"""
import asyncio
import os
import subprocess
import sys
import time
from pathlib import Path
import requests
RELAY_PORT = 9222
CDP_URL = f"http://127.0.0.1:{RELAY_PORT}"
CDP_PORT = RELAY_PORT
RELAY_SCRIPT = Path(__file__).parent / "relay.py"
EXTENSION_DIR = Path(__file__).parent / "extension"
_relay_proc = None
def is_cdp_alive() -> bool:
"""Check if the relay is responding on the CDP port."""
try:
r = requests.get(f"{CDP_URL}/json/version", timeout=2)
return r.status_code == 200
except Exception:
return False
def is_extension_connected() -> bool:
"""Check if the Chrome extension has connected to the relay."""
try:
r = requests.get(f"{CDP_URL}/json/version", timeout=2)
if r.status_code == 200:
return r.json().get("extensionConnected", False)
except Exception:
pass
return False
def start_relay() -> subprocess.Popen:
"""Start the relay server as a background process."""
global _relay_proc
if is_cdp_alive():
print("[CDP] Relay already running on port", RELAY_PORT)
return _relay_proc
print(f"[CDP] Starting relay server on port {RELAY_PORT}...")
_relay_proc = subprocess.Popen(
[sys.executable, str(RELAY_SCRIPT)],
cwd=str(RELAY_SCRIPT.parent),
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
creationflags=(subprocess.CREATE_NO_WINDOW)
if sys.platform == "win32" else 0,
)
# Wait for relay to start
for _ in range(20):
time.sleep(0.5)
if is_cdp_alive():
print("[CDP] Relay server ready")
return _relay_proc
if _relay_proc.poll() is not None:
out = _relay_proc.stdout.read().decode("utf-8", errors="replace")
raise RuntimeError(f"Relay server exited unexpectedly:\n{out}")
raise TimeoutError("Relay server did not start within 10 seconds")
def stop_relay():
"""Stop the relay server."""
global _relay_proc
if _relay_proc and _relay_proc.poll() is None:
_relay_proc.terminate()
try:
_relay_proc.wait(timeout=5)
except subprocess.TimeoutExpired:
_relay_proc.kill()
print("[CDP] Relay server stopped")
_relay_proc = None
def launch() -> str:
"""
Start the relay server and wait for the extension to connect.
Chrome should already be running with the extension installed.
Returns the CDP WebSocket URL for Browser Use.
"""
start_relay()
if is_extension_connected():
print("[CDP] Extension already connected")
return f"ws://127.0.0.1:{RELAY_PORT}/devtools/browser"
print("[CDP] Waiting for Chrome extension to connect...")
print("[CDP] Make sure Chrome is running with the Agent CDP Relay extension loaded.")
print(f"[CDP] Extension dir: {EXTENSION_DIR}")
for i in range(60): # 30 seconds
time.sleep(0.5)
if is_extension_connected():
print("[CDP] Extension connected!")
return f"ws://127.0.0.1:{RELAY_PORT}/devtools/browser"
raise TimeoutError(
"Extension did not connect within 30 seconds.\n"
"Make sure:\n"
" 1. Chrome is running\n"
" 2. The Agent CDP Relay extension is loaded (chrome://extensions)\n"
f" Extension folder: {EXTENSION_DIR}\n"
)
def shutdown():
"""Stop the relay server."""
stop_relay()
print("[CDP] Shutdown complete.")
if __name__ == "__main__":
import argparse
import json
parser = argparse.ArgumentParser(description="Chrome CDP relay manager")
parser.add_argument(
"command",
choices=["launch", "status", "shutdown"],
help="launch=start relay & wait for extension, status=check, shutdown=stop relay",
)
args = parser.parse_args()
if args.command == "launch":
ws_url = launch()
print(f"CDP WebSocket: {ws_url}")
elif args.command == "status":
if is_cdp_alive():
info = requests.get(f"{CDP_URL}/json/version").json()
print(json.dumps(info, indent=2))
if info.get("extensionConnected"):
print("\nExtension: CONNECTED")
else:
print("\nExtension: NOT CONNECTED")
else:
print("Relay not running.")
elif args.command == "shutdown":
shutdown()