Trình giám sát CDP của trình duyệt - Thiết kế
Trạng thái: Đã giao hàng (PR 14540) Cập nhật lần cuối: 2026-04-23 Tác giả: @teknium1
Vấn đề
Các hộp thoại JS gốc (alert/confirm/prompt/Beforeunload) và iframe là
hai lỗ hổng lớn nhất trong công cụ trình duyệt của chúng tôi:
- Hộp thoại chặn luồng JS. Mọi thao tác trên trang đều bị đình trệ cho đến khi hộp thoại được xử lý. Trước công việc này, tác nhân không có cách nào để biết hộp thoại đã mở - các lệnh gọi công cụ tiếp theo sẽ bị treo hoặc đưa ra các lỗi không rõ ràng.
- Iframe là vô hình. Tác nhân có thể thấy các nút iframe trong DOM ảnh chụp nhanh nhưng không thể nhấp, nhập hoặc đánh giá bên trong chúng - đặc biệt là iframe có nguồn gốc chéo (OOPIF) tồn tại trong các quy trình Chrome riêng biệt.
PR #12550 đã đề xuất một
trình bao bọc browser_dialog không trạng thái. Điều đó không giải quyết được việc phát hiện - đó là một
lệnh gọi CDP sạch hơn khi tác nhân đã biết (thông qua các triệu chứng) rằng hộp thoại
đang mở. Đóng như thay thế.
Ma trận khả năng phụ trợ (được xác minh trực tiếp vào ngày 23-04-2026)
Sử dụng tập lệnh thăm dò dùng một lần đối với trang URL dữ liệu kích hoạt cảnh báo trong
khung chính và trong iframe srcdoc có cùng nguồn gốc, cộng với một nguồn gốc chéo
https://example.com iframe:
| Backend | Dialog detect | Dialog respond | Frame tree | OOPIF Runtime.evaluate via browser_cdp(frame_id=...) |
|---|---|---|---|---|
Local Chrome (--remote-debugging-port) / /browser connect | ✓ | ✓ full workflow | ✓ | ✓ |
| Browserbase | ✓ (via bridge) | ✓ full workflow (via bridge) | ✓ | ✓ (document.title = "Example Domain" verified on real cross-origin iframe) |
| Camofox | ✗ no CDP (REST-only) | ✗ | partial via DOM snapshot | ✗ |
Cách phản hồi của Browserbase hoạt động. Proxy CDP của Browserbase sử dụng Playwright
nội bộ và tự động loại bỏ các hộp thoại gốc trong vòng ~10 mili giây, vì vậy
Page.handleJavaScriptDialog không thể theo kịp. Để giải quyết vấn đề này,
người giám sát chèn một kịch bản cầu nối thông qua
Page.addScriptToEvaluateOnNewDocument ghi đè
window.alert/confirm/prompt với XHR đồng bộ với máy chủ ma thuật
(hermes-dialog-bridge.invalid). Fetch.enable chặn các XHR đó
trước khi họ chạm vào mạng — hộp thoại sẽ trở thành Fetch.requestPaused
sự kiện mà người giám sát nắm bắt và respond_to_dialog thực hiện thông qua
Fetch.fulfillRequest với nội dung JSON mà tập lệnh được chèn sẽ giải mã.
Kết quả thực: từ góc nhìn của trang, prompt() vẫn trả về
chuỗi do đại lý cung cấp. Từ góc độ của đại lý, nó giống nhau
Dù sao đi nữa, API `browser_dialog(action=...)``. Đã được thử nghiệm từ đầu đến cuối
phiên cơ sở trình duyệt thực - 4/4 (cảnh báo/nhắc/xác nhận-chấp nhận/xác nhận-loại bỏ)
chuyển bao gồm cả giá trị ngắt vòng trở lại trang JS.
Camofox vẫn không được hỗ trợ cho hoạt động PR này; vấn đề tiếp theo được lên kế hoạch tại
jo-inc/camofox-browser yêu cầu điểm cuối thăm dò hộp thoại.
Ngành kiến trúc
CDPGiám sát viên
Một asyncio.Task chạy trong chuỗi daemon nền trên mỗi task_id của Hermes.
Giữ một WebSocket liên tục cho điểm cuối CDP của chương trình phụ trợ. Duy trì:
- Hàng đợi hộp thoại —
List[PendingDialog]với{id, type, message, default_prompt, session_id, open_at} - Cây khung —
Dict[frame_id, FrameInfo]với các mối quan hệ gốc, URL, nguồn gốc, cho dù phiên con có nhiều nguồn gốc hay không - Bản đồ phiên —
Dict[session_id, SessionInfo]để các công cụ tương tác có thể định tuyến đến phiên đính kèm phù hợp cho các hoạt động OOPIF - Lỗi bảng điều khiển gần đây — vòng đệm của 50 vòng cuối cùng (đối với chẩn đoán PR 2)
Đăng ký trên tệp đính kèm:
Page.enable—javascriptDialogOpening,frameAttached,frameNavigated,frameDetachedRuntime.enable—executionContextCreated,consoleAPICalled,ExceptionThrownTarget.setAutoAttach {autoAttach: true, Flatten: true}— hiển thị các mục tiêu OOPIF con; người giám sát kích hoạtTrang+Runtimetrên mỗi trang
Truy cập trạng thái an toàn theo luồng thông qua khóa chụp nhanh; trình xử lý công cụ (đồng bộ) đọc ảnh chụp nhanh bị đóng băng mà không cần chờ đợi.
Vòng đời
- Bắt đầu:
SupervisorRegistry.get_or_start(task_id, cdp_url)— được gọi bởibrowser_navigate, tạo phiên Browserbase,/browser connect. Bình thường. - Dừng: ngắt phiên hoặc
/ngắt kết nối trình duyệt. Hủy asyncio tác vụ, đóng WebSocket, loại bỏ trạng thái. - Rebind: nếu URL CDP thay đổi (người dùng kết nối lại với Chrome mới), hãy dừng người giám sát cũ và bắt đầu mới - không bao giờ sử dụng lại trạng thái trên các điểm cuối.
Chính sách đối thoại
Có thể định cấu hình thông qua config.yaml trong browser.dialog_policy:
must_respond(mặc định) — chụp, hiển thị trongbrowser_snapshot, đợi cho lệnh gọibrowser_dialog(action=...)rõ ràng. Sau thời gian chờ an toàn 300 giây không có phản hồi, tự động loại bỏ và đăng nhập. Ngăn chặn tác nhân gây lỗi bị đình trệ mãi mãi.auto_dismiss— ghi lại và loại bỏ ngay lập tức; đại lý nhìn thấy nó sau khi thực tế thông quabrowser_statebên trongbrowser_snapshot.auto_accept— ghi lại và chấp nhận (hữu ích chotrước khi tảikhi người dùng muốn điều hướng đi một cách rõ ràng).
Chính sách là cho mỗi nhiệm vụ; không có phần ghi đè trên mỗi hộp thoại trong v1.
Bề mặt tác nhân (PR 1)
Một công cụ mới
browser_dialog(action, prompt_text=None, dialog_id=None)
action="accept"/"dismiss"→ phản hồi hộp thoại được chỉ định hoặc duy nhất đang chờ xử lý (bắt buộc)prompt_text=...→ văn bản để cung cấp cho hộp thoạiprompt()dialog_id=...→ phân biệt khi có nhiều hộp thoại xếp hàng (hiếm)
Công cụ chỉ có tính năng phản hồi. Tác nhân đọc các hộp thoại đang chờ xử lý từ browser_snapshot
đầu ra trước khi gọi.
tiện ích mở rộng browser_snapshot
Thêm ba trường tùy chọn vào đầu ra ảnh chụp nhanh hiện có khi người giám sát được đính kèm:
{
"pending_dialogs": [
{"id": "d-1", "type": "alert", "message": "Hello", "opened_at": 1650000000.0}
],
"recent_dialogs": [
{"id": "d-1", "type": "alert", "message": "...", "opened_at": 1650000000.0,
"closed_at": 1650000000.1, "closed_by": "remote"}
],
"frame_tree": {
"top": {"frame_id": "FRAME_A", "url": "https://example.com/", "origin": "https://example.com"},
"children": [
{"frame_id": "FRAME_B", "url": "about:srcdoc", "is_oopif": false},
{"frame_id": "FRAME_C", "url": "https://ads.example.net/", "is_oopif": true, "session_id": "SID_C"}
],
"truncated": false
}
}
-
pending_dialogs: các hộp thoại hiện đang chặn chuỗi JS của trang. Tác nhân phải gọibrowser_dialog(action=...)để phản hồi. trống trên Cơ sở trình duyệt vì proxy CDP của họ tự động loại bỏ trong vòng ~ 10 mili giây. -
recent_dialogs: bộ đệm vòng lên tới 20 hộp thoại đã đóng gần đây với thẻclosed_by—"agent"(chúng tôi đã phản hồi),"auto_policy"(địa phương auto_dismiss/auto_accept),"watchdog"(lần truy cập hết thời gian chờ must_respond) hoặc"remote"(trình duyệt/phụ trợ đã đóng nó đối với chúng tôi, ví dụ: Browserbase). Đây là cách các đặc vụ trên Browserbase vẫn có thể nhìn thấy được những gì đã xảy ra. -
frame_tree: cấu trúc khung bao gồm các phần tử con có nguồn gốc chéo (OOPIF). Giới hạn ở 30 mục + OOPIF độ sâu 2 đến kích thước ảnh chụp nhanh giới hạn trên quảng cáo nặng trang.bị cắt ngắn: đúnghiển thị khi đạt đến giới hạn; đại lý cần cây đầy đủ có thể sử dụngbrowser_cdpvớiPage.getFrameTree.
Không có sơ đồ công cụ mới nào cho bất kỳ công cụ nào trong số này — tác nhân đọc ảnh chụp nhanh nó đã yêu cầu rồi.
Kiểm soát tính khả dụng
Cổng cả hai bề mặt trên _browser_cdp_check (người giám sát chỉ có thể chạy khi CDP
điểm cuối có thể truy cập được). Trên các phiên Camofox/không có phụ trợ, công cụ hộp thoại là
ẩn và ảnh chụp nhanh bỏ qua các trường mới — không có sơ đồ phình to.
Tương tác iframe nhiều nguồn gốc
Mở rộng công việc phát hiện hộp thoại, browser_cdp(frame_id=...) định tuyến CDP
các cuộc gọi (đặc biệt là Runtime.evaluate) thông qua người giám sát đã được kết nối
WebSocket sử dụng sessionId con của OOPIF. Đại lý chọn frame_ids trong số
browser_snapshot.frame_tree.children[] trong đó is_oopif=true và chuyển chúng
tới browser_cdp. Đối với các iframe có cùng nguồn gốc (không có phiên CDP chuyên dụng),
tác nhân sử dụng contentWindow/contentDocument từ cấp cao nhất
Thay vào đó, Runtime.evaluate — người giám sát đưa ra lỗi khi chỉ vào đó
dự phòng khi frame_id thuộc về một không phải OOPIF.
Trên Browserbase, đây là đường dẫn đáng tin cậy DUY NHẤT cho tương tác iframe —
kết nối CDP không trạng thái (được mở cho mỗi lệnh gọi browser_cdp) nhấn vào URL đã ký
hết hạn, trong khi kết nối lâu dài của người giám sát vẫn giữ phiên hợp lệ.
Camofox (tiếp theo)
Vấn đề được lên kế hoạch chống lại jo-inc/camofox-browser thêm:
- Nhà viết kịch
page.on('dialog', handler)mỗi phiên - Điểm cuối thăm dò
GET /tabs/:tabId/dialogs POST /tabs/:tabId/dialogs/:idđể chấp nhận/bỏ qua- Điểm cuối xem xét nội tâm cây khung
Đã chạm vào tệp (PR 1)
Mới
tools/browser_supervisor.py—CDPSupervisor,SupervisorRegistry,PendingDialog,FrameInfotools/browser_dialog_tool.py— trình xử lý công cụbrowser_dialogtests/tools/test_browser_supervisor.py— mô phỏng máy chủ CDP WebSocket + kiểm tra vòng đời/trạng tháiwebsite/docs/developer-guide/browser-supervisor.md— tập tin này
Đã sửa đổi
toolsets.py— đăng kýbrowser_dialogtrongbrowser,hermes-acp,hermes-api-server, bộ công cụ cốt lõi (được kiểm soát dựa trên khả năng tiếp cận CDP)tools/browser_tool.pybrowser_navigatestart-hook: nếu URL CDP có thể phân giải được,SupervisorRegistry.get_or_start(task_id, cdp_url)browser_snapshot(tại ~line 1536): hợp nhất trạng thái giám sát vào tải trọng trả về- Trình xử lý
/browser connect: khởi động lại trình giám sát với điểm cuối mới - Móc phân tách phiên trong
_cleanup_browser_session
hermes_cli/config.py— thêmbrowser.dialog_policyvàbrowser.dialog_timeout_svàoDEFAULT_CONFIG- Tài liệu:
website/docs/user-guide/features/browser.md,website/docs/reference/tools-reference.md,website/docs/reference/toolsets-reference.md
Không có mục tiêu
- Phát hiện/tương tác với Camofox (khoảng cách ngược dòng; được theo dõi riêng)
- Truyền trực tiếp các sự kiện hộp thoại/khung tới người dùng (sẽ yêu cầu móc nối cổng)
- Lịch sử hộp thoại liên tục qua các phiên (chỉ trong bộ nhớ)
- Chính sách hộp thoại trên mỗi khung nội tuyến (tác nhân có thể thể hiện điều này thông qua
dialog_id) - Thay thế
browser_cdp— nó vẫn là lối thoát cho phần đuôi dài (cookie, khung nhìn, điều chỉnh mạng)
##Thử nghiệm
Các bài kiểm tra đơn vị sử dụng máy chủ CDP giả asyncio để nói đủ về giao thức
để thực hiện tất cả các chuyển đổi trạng thái: đính kèm, kích hoạt, điều hướng, kích hoạt hộp thoại,
loại bỏ hộp thoại, đính kèm/tách khung, đính kèm mục tiêu con, phá bỏ phiên.
E2E phụ trợ thực (Browserbase + Chrome cục bộ) là thủ công - tập thể dục qua
/trình duyệt kết nối với Chrome trực tiếp và chạy các trường hợp kiểm tra hộp thoại/khung
được mô tả ở trên.