-
Notifications
You must be signed in to change notification settings - Fork 2
Browser Design
📑 本页目录
对标并四点超越 Operit(
com.ai.assistance.operit)。 来源:docs/web-browser-automation-final.md、docs/web-browser-chrome.md。
| 维度 | 2024 旧范式 | 本项目 |
|---|---|---|
| 元素引用 | 顺序索引 bid=1,2,3(SPA 局部刷新即失效) |
语义哈希 r_<hash> |
| 事件触发 |
element.click() 合成事件 |
DOM 定位 → Android dispatchTouchEvent 物理触摸 |
| DOM 传输 | 每次全量快照 | JS 层启发式剪枝 + 字符预算(增量 Diff 为 P2 储备) |
| 人工接管 | 简单浮窗 | 状态机驱动的显式握手 |
| 截图 | 全页长图 | 仅当前视口 |
四点超越:语义哈希稳定 Ref(抗 SPA 局部刷新)、物理触摸注入(抗 isTrusted 校验)、
JS 层启发式剪枝(省 token)、显式握手人工接管(状态机 + 全局工具锁,零歧义)。
ref = "r_" + hash(role + text + domPath + 相对位置)
快照时打 data-apex-hash → 定位用 querySelector('[data-apex-hash="..."]')
DOM 重绘导致 hash 失效时的降级链:
① 精确 data-apex-hash
② 按快照保存的 role + text 在可视区模糊匹配
③ 按相对坐标在父容器内做空间邻近度匹配
暂不做跨 iframe(P2;当前把 iframe 视为整体交互块)。
clickElement(ref)
= JS 取 BoundingRect
→ 换算 WebView 屏幕坐标(叠加浮窗绝对偏移)
→ 构造 MotionEvent(DOWN/UP),DOWN~UP 之间 30~80ms 随机延迟模拟按压
→ webView.dispatchTouchEvent()
为什么不用 el.click():React/Vue 与 Cloudflare/Akamai 会校验 isTrusted 与完整的
touchstart → touchmove → touchend 轨迹。
evaluateJavascript 经 CountDownLatch / suspendCancellableCoroutine 同步化。
-
SNAPSHOT_JS过滤:display:none/visibility:hidden/offsetParent === null/ 不可见非交互无文本节点 / 超深非交互子树; - Kotlin 层
DomParser.buildSummary再按字符预算裁剪折叠; - 单次快照元素数 ≤ 50(token 预算保护);
- 摘要不引 BPE(真 BPE 耗 CPU、增包体),用轻量启发式。
Important
原设计的"上下文感知自动探针监控"已被彻底废弃(隐式推断在复杂生产环境不稳定: 误判输入中/已放弃、页面成功标志各异、易误夺控制权)。 改为人类在浮窗点「我已完成操作」按钮触发显式握手,交还 Agent。
-
WAITING_HUMAN状态锁定所有 Agent 自动化工具(前置守卫assertAgentControl()抛HandoffLockedException/ 返回SYSTEM_LOCKED); -
completeHandoff()后自动 snapshot 一次作为隐式上下文回灌 Agent。
HIDDEN → AGENT_DRIVING → WAITING_HUMAN → HANDOFF_COMPLETE
核心工具:browser_navigate(url, new_tab?)、browser_snapshot、browser_click(ref)、
browser_input(ref, text)、browser_scroll(delta_y?)、browser_screenshot(PNG base64 视口)、
browser_show(expand? 默认 true)。
| # | 缺口 | 做法 |
|---|---|---|
| 1 | 页面加载等待 |
onPageFinished + 可选 wait_for 轮询 10s + 15s 超时兜底 |
| 2 | 动作后验证 |
probePage / PostActionState 对比 URL / 标题 / 可交互元素数 |
| 3 | JS 弹窗 | 接管 onJsAlert/Confirm/Prompt 自动 confirm,文本存 lastDialog 注入下次 snapshot |
| 4 | 渲染进程崩溃 |
onRenderProcessGone 销毁重建 WebView,置 RECOVERING,返回 true 不 crash 宿主 |
| 5 | 动作空间补全 |
selectOption / toggle / respondFileChooser + 三个对应工具 |
| 11 | 安全加固 | 禁 allowFileAccess / allowContentAccess / file-from-URL(防 UXSS 与路径穿越) |
| # | 内容 |
|---|---|
| 7 |
RetryPolicy:指数退避 500ms × 2^n、上限 5s、最多 3 次;ElementNotFoundException / TimeoutException / WebViewNotRespondingException 可重试,语义错误(HandoffLockedException)不重试;连续 5 次失败熔断 30s
|
| 9 |
BrowserTracer:内存环形缓冲 100 条(工具/参数/结果/耗时/URL/状态)+ browser_debug_dump(limit)
|
| 8 | 上下文管理轻量版:最近 3 步保留详情,更早压成单行,始终保留 URL 关键帧 |
权限请求、反爬隐身、下载、内存维护、多标签并发上限、Accessibility Tree、网络拦截、任务规划、可编程剪枝。
chrome/ 引擎无关 UI 层(BrowserChromeController + SnapshotComposer,不 import 任何 WebView/引擎类型 → 可 @Preview、可 JVM 单测)
↓
BrowserEngineGateway ← 唯一边界契约
↓
chrome/bridge/ ApexChromeWiring(真实接线器)、NeonChromeWiring、ChainingClients、
DialogRequestRouter、AgentDialogPolicy + 权限记忆
↓
TabOperations 六个一行方法
↓
BrowserEngine 零行为改动,仅增量接口
-
ChainingClients 链式接管:包一层并转发,保留引擎已有的
onPageFinished注入 / scheme 白名单 / SSL 拦截 / 渲染进程恢复,只接管 JS 弹窗 / 网页权限 / 地理定位 / 进度标题采集; -
快照频率分层:TabSet 低频 resync + Live 高频回调 →
SnapshotComposer合成单一EngineSnapshot,UI 只消费一个 StateFlow。
地址胶囊即进度条 · 多标签(单标签自动隐藏)· 撤销式关闭(4s 宽限期 Snackbar) ·
前进/后退/刷新/停止 · 页内查找(findAllAsync + 匹配计数)· 桌面模式(UA 切换 + reload)·
JS 弹窗人机双通道 · 网页权限三档(拒绝 / 仅此一次 / 总是允许,按 origin 持久化)·
下载(DownloadShelf,系统 DownloadManager 轮询,回写 engine.lastDownload 保持 Agent 可读)· 溢出菜单。
| 状态 | 弹窗 | 权限 |
|---|---|---|
| WAITING_HUMAN(人在) | 弹窗/权限由人裁决 | 人定;接管横幅常驻「我已完成操作,交还 Agent」 |
| AGENT(无人值守) | ALERT 自动确认(不承载选择、无副作用);CONFIRM 默认拒绝;PROMPT 不接管按取消 | 一律安全拒绝 |
任何裁决回写 engine.lastDialog,Agent snapshot 注入语义不变。
-
不使用
AlertDialog/ModalBottomSheet—— 底层创建android.app.Dialog需要宿主窗口 token, overlay 用 app context 无 token →BadTokenException;全部浮层改自绘(ChromeScrimDialog/ChromeBottomSheet); -
BackHandler在浮窗中先探测LocalOnBackPressedDispatcherOwner; - overlay 窗口加
SOFT_INPUT_ADJUST_RESIZE,WebView 容器 topMargin 由 chrome 头部onGloballyPositioned实测高度实时驱动。
| 项 | 结果 |
|---|---|
:app:compileDebugKotlin |
BUILD SUCCESSFUL(全模块 + Hilt KSP) |
| 单测 | 56 用例 0 失败:ChromeLogicTest 15 / JsDialogBookkeepingTest 12 / SnapshotComposerTest 7 / AgentDialogPolicyTest 10 / PermissionGateTest 12 |
DomParserTest |
已加"ref 来自语义哈希、不随顺序偏移"意图测试 |
| CI 目标 | 5 个重型页(淘宝 / X / GitHub / 知乎 / 银行登录)快照 ≤ 4096 tokens |
端侧 VLM「零 DOM 注入」自动化:完全不注入 JS(100% 隐身)、端侧量化 VLM 直接推理 WebView 截图、
输出 {"action":"click","target_visual_desc":"...","coordinates":[540,1200]}。
限制:端侧模型对密集小文本识别率不如直读 DOM 且发热 →
当前坚持"DOM 为主、视觉为辅"双模态。
-
MCP 生态总览
新 - (沙箱 MCP · 官方 Hub · 逆向 Host · 门控语义)
- 终端运行时
- 终端 API 契约
- SDK 边界
- Termux 能力矩阵
- Ubuntu rootfs 供给
- Ubuntu 生命周期
- PRoot 二进制溯源
- VT100/ANSI 模拟器
- 终端性能
- 终端迁移
- 原生层 C++/JNI