13 KiB
agent-browser 集成设计
本文描述 PicoBot 1.4.0 的浏览器工具实现。目标是在保持模型侧稳定 browser 协议的同时,用 agent-browser 完全替代 Fantoccini、ChromeDriver 和 WebDriver,并让临时会话、单用户多持久 Profile、管理操作、产物和健康检查拥有明确边界。
1. 选择与边界
PicoBot 使用 agent-browser CLI 的 --json 协议,不直接链接其内部 crate,也不把 agent-browser MCP Server 原样暴露给模型。
原因:
- agent-browser 是原生 Rust CLI + daemon,daemon 通过 Chrome CDP 驱动浏览器;CLI 进程很短,浏览器状态跨命令保存在 daemon 中。
- CLI 是项目的稳定公开边界,PicoBot 不需要依赖 agent-browser 的内部 Rust 模块布局。
- PicoBot 包装层可统一管理个人浏览器身份、限制并发和输出、校验 URL、控制 Profile/截图目录,并把图片接入统一
ToolOutput后处理管线。 - 直接暴露 MCP 会让 session ID、文件路径、输出规模和安全策略落到模型参数中,也难以自动绑定当前 PicoBot dialog。
这不是把浏览器逻辑重新实现一遍。元素定位、accessibility snapshot、页面交互、Chrome 启动、CDP 通信和 daemon 生命周期均由 agent-browser 负责;PicoBot 只负责编排和边界控制。
2. 分层
AgentLoop
│ ToolExecutionContext(session_id, turn_id)
▼
BrowserTool / BrowserProfilesTool 浏览与持久 Profile 管理 schema
▼
BrowserManager 临时 dialog session / 共享持久 Profile
├─ security URL、DNS、私网与 allowlist 前置校验
├─ action browser action → CLI argv
└─ AgentBrowserRunner timeout、env、--json、错误与输出解析
▼
agent-browser CLI → Rust daemon → Chrome/Chromium CDP
源文件:
src/tools/browser/mod.rs:browser、browser_profilesschema 与入口。src/tools/browser/action.rs:严格参数解析和 argv 映射。src/tools/browser/manager.rs:临时会话表、按 ID 管理的持久 Profile、并发、回收和截图媒体。src/tools/browser/runner.rs:无 Shell 的子进程调用、硬超时、JSON/错误解析。src/tools/browser/security.rs:导航策略。src/tools/traits.rs:向有状态工具提供ToolExecutionContext;其他工具沿用默认实现。
3. 会话、持久 ID 与并发
BrowserManager 按每次调用是否携带 persistent_id 分流,两种浏览器可在同一个 Gateway 中同时使用:
-
省略
persistent_id时使用普通临时浏览器。SessionManager传入完整 PicoBot session ID,BrowserManager 第一次看到该 ID 时生成随机、不透明的picobot-<uuid>agent-browser session。同一 dialog 串行、不同 dialog 可并发;空闲会话按idle_timeout_secs回收,数量受max_sessions限制。 -
需要长期保留登录或站点状态时,Agent 可以自主调用
browser_profiles(action=create,label=...)创建持久身份,并在后续相关的每个browseraction 中显式传入返回的persistent_id。 -
用户可以拥有多个
picobot-profile-<32 hex>ID。browser_profiles(action=create,label=...)创建persistence.profile_dir/<id>专用目录和可选语义标签;标签可通过set_label重命名,ID 保持不变。 -
PicoBot 不保存默认 ID,也不按 dialog 自动选择或绑定持久 Profile。没有 ID 的调用始终回到该 dialog 的临时浏览器,不会隐式选中任何持久身份。
-
每个 ID 分别映射 agent-browser
--session、Chrome--profile路径和 mutex。同一 ID 可从不同 dialog、子 Agent 或 Scheduler 使用并保持串行;不同 ID 的浏览器状态和锁相互独立,可以并发。 -
ID 与 Profile 目录跨 Gateway 重启、配置重载和 agent-browser daemon 空闲退出保持不变;Cookie、localStorage、IndexedDB、Service Worker 和缓存由各 Chrome Profile 自身保存。
-
close关闭显式选择的浏览器进程但保留 ID、标签和 Profile;下一次使用该 ID 时从相同目录重新打开。 -
browser_profiles(action=list)返回每个合法 ID 的标签、完整目录和当前 Manager 是否 active。 -
browser_profiles(action=set_label,id=...,label=...)写入语义标签并同步当前活动实例;标签去除首尾空白,限制为 1–80 个非控制字符。 -
browser_profiles(action=delete,id=...)只接受create/list返回的完整格式 ID。删除时持有管理锁、等待该 ID 的活动 action、尝试关闭其浏览器,再递归删除对应目录。
Profile 根目录和每个生成目录在 Unix 上收敛为 0700,目录内 .picobot-label 标签文件为 0600。列表忽略格式非法的目录和符号链接,选择、改标签和删除拒绝路径穿越、符号链接及非目录目标。Gateway 配置重载会构造新的 ToolRegistry/BrowserManager;旧运行代按现有 drain 规则退出。agent-browser daemon 的空闲退出时间通过 AGENT_BROWSER_IDLE_TIMEOUT_MS 同步设置。
4. Action 映射
| PicoBot action | agent-browser 命令 |
|---|---|
open |
open <url> |
snapshot |
snapshot --interactive --compact [--depth N] |
click / fill / type |
同名命令;无 selector 的 type 使用 keyboard type |
get_text / get_title / get_url |
get text/title/url |
focus / wait / press / hover / scroll |
对应原生命令 |
click_at |
mouse move + mouse down left + mouse up left |
screenshot |
screenshot <controlled-path> [--full] [--annotate] |
close |
close |
每次调用都使用 argv 数组直接启动进程,不经过 Shell。fill / type 的内容不会写入 PicoBot 日志;日志只记录 action 名、是否绑定 session 和所选持久 ID。
Runner 固定传入 --session、--json 和明确的 headed 状态;携带持久 ID 的调用额外传入由 Manager 生成的 --profile <controlled-path>。Runner 还设置:
AGENT_BROWSER_EXECUTABLE_PATH(配置后)AGENT_BROWSER_CONTENT_BOUNDARIESAGENT_BROWSER_MAX_OUTPUTAGENT_BROWSER_ALLOWED_DOMAINS(非空时)AGENT_BROWSER_IDLE_TIMEOUT_MS
非零退出码、JSON 中 success=false、无效 JSON和超时都转换为工具失败。stdout/stderr 在返回模型前有长度上限;页面类结果保留 agent-browser _boundary 元数据。
5. 截图与媒体
截图绝不返回 Base64。调用方可省略 path 自动生成文件名,也可提供单个 .png 文件名;绝对路径、目录分隔、. 和 .. 均拒绝。实际文件始终位于 browser.artifact_dir。
命令成功后 PicoBot 再验证文件存在、是普通文件且非空,然后返回:
ToolOutput {
result: ToolResult { output: "Screenshot saved: ..." },
artifacts: [ToolArtifact {
media_ref: MediaRef { media_type: "image", path: "..." },
audience: ModelAndUser
}]
}
统一处理器会把截图同时交给下一轮多模态 Provider,并附到本 Turn 最终 assistant 回复供用户查看。present_to_user 默认为 true;显式设为 false 时 audience 改为 Model,适用于无需展示的内部视觉检查。历史中仍只保存短路径清单,不产生 Base64 上下文膨胀。
6. 安全模型
默认策略:
- 只允许
http://和https://,拒绝 URL userinfo。 allow_private_hosts=false时拒绝 localhost、.local、回环、私网、link-local、未指定和组播地址;域名会先解析 DNS,任一结果为私网即拒绝。allowed_domains非空时 PicoBot 先校验首个 URL,agent-browser 再对导航、重定向、子资源、WebSocket、EventSource、sendBeacon 和受支持 Chromium 的 WebRTC 实施域名边界。- 默认开启 content boundaries,并把页面文本限制为 50,000 字符。
- 包装层没有
eval、上传、下载、cookie/storage 写入或任意 agent-browser 命令透传,模型只能使用 allowlisted action。 - 截图有单独的产物目录,不能用来覆盖任意文件。
browser_profiles只允许创建受控 ID,或按格式严格的 ID 设置受限标签、列出和删除persistence.profile_dir的直接子目录;模型不能提交任意 Profile 路径。
allowed_domains=[] 表示不启用 agent-browser 域名过滤,适合通用浏览;这不是 OS 网络沙箱。需要强隔离时,应同时设置明确域名表和容器/主机 egress 策略。允许私网浏览是显式配置,适合本地应用测试,但会扩大 SSRF 风险。
agent-browser 0.33.0 明确拒绝在 allowed_domains 启用时复用 Chrome Profile,因为无法保证页面脚本执行前完整安装同等域名约束。PicoBot 因此允许受域名限制的普通临时浏览器继续工作,但会拒绝创建或使用持久 Profile,并在 health 中给出可选能力警告;列表、改标签和删除仍可用于管理已有目录。Profile 包含可直接代表用户身份的登录信息,目录必须视作敏感凭据,不得提交版本控制或跨用户共享。
7. 安装
验证版本为 0.33.0:
npm install -g agent-browser@0.33.0
agent-browser install
Linux 自动补系统依赖:
agent-browser install --with-deps
不使用 npm 时:
cargo install agent-browser --version 0.33.0 --locked
agent-browser install
macOS 也可执行:
brew install agent-browser
agent-browser install
agent-browser install 下载 Chrome for Testing。已有浏览器时设置:
"browser_executable_path": "/usr/bin/chromium"
或设置环境变量 AGENT_BROWSER_EXECUTABLE_PATH。agent-browser 的 daemon 与 CDP 路径不需要 Node.js;npm 安装方式只需要 npm 用来放置预编译 CLI。Dockerfile 安装 Debian Chromium、agent-browser@0.33.0 并设置 executable path。
8. 使用
- 浏览器工具默认启用;从旧配置删除
webdriver_url、chrome_path,仅在需要改变持久目录位置时配置persistence.profile_dir。没有持久化模式开关。缺少依赖不会阻止 Gateway 启动,只会让 health 和实际浏览器调用失败。 - 运行
picobot health;应看到 agent-browser CLI 版本和 offline quick doctor 通过。 - 启动或重载 Gateway。
- 对 Agent 说“使用浏览器打开 …”。模型的推荐动作序列是:
browser(open, url)
browser(snapshot, interactive_only=true, compact=true)
browser(click/fill/type, selector=@eN)
browser(snapshot) # 页面改变后刷新 refs
browser(screenshot, annotate=true) # 需要视觉上下文时
browser(close)
agent-browser 的 @e 引用属于当前页面快照。导航、弹窗或 DOM 大幅变化后必须重新 snapshot,不能长期缓存旧引用。
持久 Profile 管理:
browser_profiles(create, label="工作账号") # 返回 persistent ID
browser_profiles(list)
browser_profiles(set_label, id=picobot-profile-..., label="个人账号")
browser(open, url, persistent_id=picobot-profile-...)
browser(snapshot, persistent_id=picobot-profile-...)
browser_profiles(delete, id=picobot-profile-...)
同一个持久操作链必须持续传入同一 persistent_id;一旦省略,调用会明确转到当前 dialog 的普通临时浏览器。不同对话可以同时操作不同 ID。标签用于识别,不能代替 ID 选择浏览器;删除会清除该 ID 的全部浏览器数据、标签和登录态,调用前必须有用户要求并使用 create/list 返回的精确 ID。
9. Health 三入口
src/health.rs 的 HealthService 是唯一检查实现:
picobot health [--json]:本机运维入口;核心/配置必需项失败时退出1。/health:当前 Gateway 配置的聊天入口。healthTool:Agent 可调用的只读入口,支持json=true。
检查项包括 workspace、Bash、内容/文件搜索后端、可选 systemctl、配置中的 stdio MCP 命令,以及浏览器启用时的持久 Profile 可用性、agent-browser 版本、显式浏览器路径和 doctor --offline --quick --json。检查不创建或删除 Profile、不安装软件、不执行 doctor --fix、不访问 Provider API,也不输出配置密钥。
10. 迁移和故障处理
- 配置使用
deny_unknown_fields;遗留 WebDriver 字段会在加载时失败,而不是被静默忽略。 failed to start 'agent-browser':CLI 不在 PATH,或browser.command错误;运行 health。- doctor 失败:运行
agent-browser doctor查看完整诊断,再安装浏览器/系统库。 - session limit:仅临时模式适用;关闭不再使用的 dialog 浏览器,或调整
max_sessions。 - persistence policy:非空
allowed_domains下普通临时浏览器仍可用,但创建或使用持久 Profile 会失败;根据需求选择个人登录态复用或严格域名隔离。 - Profile 删除失败:先确认没有外部 Chrome 使用该目录,再用
browser_profiles(list)核对精确 ID 后重试;不要手工扩大删除路径。 - domain blocked:补充站点和必要 CDN 域名;不要用空白 allowlist 绕过生产隔离策略。
- command timeout:确认页面/浏览器未卡死,再按部署风险调整
command_timeout_secs。 - 截图不存在:视为工具失败,不构造失效 MediaRef。
Fantoccini crate、旧 src/tools/browser.rs WebDriver 实现、ChromeDriver Docker 包和相关配置已全部删除。Cargo 不链接 agent-browser;它是由 health 管理的外部运行依赖。