186 lines
9.6 KiB
Markdown
186 lines
9.6 KiB
Markdown
# agent-browser 集成设计
|
||
|
||
本文描述 PicoBot 1.3.1 的浏览器工具实现。目标是在保持模型侧单一 `browser` 工具协议的同时,用 agent-browser 完全替代 Fantoccini、ChromeDriver 和 WebDriver,并让浏览器状态、并发、产物和健康检查服从 PicoBot 的 Session 生命周期。
|
||
|
||
## 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 包装层可统一绑定 dialog、限制并发和输出、校验 URL、控制截图目录,并把图片接入现有 `ToolResultWithMedia`。
|
||
- 直接暴露 MCP 会让 session ID、文件路径、输出规模和安全策略落到模型参数中,也难以自动绑定当前 PicoBot dialog。
|
||
|
||
这不是把浏览器逻辑重新实现一遍。元素定位、accessibility snapshot、页面交互、Chrome 启动、CDP 通信和 daemon 生命周期均由 agent-browser 负责;PicoBot 只负责编排和边界控制。
|
||
|
||
## 2. 分层
|
||
|
||
```text
|
||
AgentLoop
|
||
│ ToolExecutionContext(session_id, turn_id)
|
||
▼
|
||
BrowserTool 模型侧单一 browser schema
|
||
▼
|
||
BrowserManager dialog → opaque session;并发/空闲/产物
|
||
├─ 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`:工具 schema 与入口。
|
||
- `src/tools/browser/action.rs`:严格参数解析和 argv 映射。
|
||
- `src/tools/browser/manager.rs`:会话表、per-session mutex、空闲回收、截图媒体。
|
||
- `src/tools/browser/runner.rs`:无 Shell 的子进程调用、硬超时、JSON/错误解析。
|
||
- `src/tools/browser/security.rs`:导航策略。
|
||
- `src/tools/traits.rs`:向有状态工具提供 `ToolExecutionContext`;其他工具沿用默认实现。
|
||
|
||
## 3. 会话与并发
|
||
|
||
`SessionManager` 为每次 AgentLoop 执行传入完整 PicoBot session ID。BrowserManager 第一次看到该 ID 时生成随机、不透明的 `picobot-<uuid>` agent-browser session,模型不能选择或猜测底层 session。
|
||
|
||
- 同一个 dialog:所有浏览器 action 由该 session 的 mutex 串行,cookie、storage、历史和当前页面连续。
|
||
- 不同 dialog:使用不同 agent-browser session,可并发执行。
|
||
- 子 Agent:若显式获准使用 `browser`,沿用发起任务的 PicoBot session,因此与主 Agent 共享同一浏览器并受同一 mutex 保护。
|
||
- Scheduler:使用 `cron:<job-id/name>` 隔离,不与交互 dialog 混用。
|
||
- `close`:先从 PicoBot 映射表移除,再调用 agent-browser close;重复关闭幂等。
|
||
- 空闲回收:创建新会话前移除超过 `idle_timeout_secs` 的映射并尽力关闭底层 session。
|
||
- 容量:达到 `max_sessions` 且没有可回收会话时明确失败,不静默复用别人的浏览器。
|
||
|
||
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。
|
||
|
||
Runner 固定传入 `--session`、`--json` 和明确的 headed 状态,并设置:
|
||
|
||
- `AGENT_BROWSER_EXECUTABLE_PATH`(配置后)
|
||
- `AGENT_BROWSER_CONTENT_BOUNDARIES`
|
||
- `AGENT_BROWSER_MAX_OUTPUT`
|
||
- `AGENT_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 再验证文件存在、是普通文件且非空,然后返回:
|
||
|
||
```text
|
||
ToolResultWithMedia {
|
||
result: ToolResult { output: "Screenshot saved: ..." },
|
||
media_refs: [MediaRef { media_type: "image", path: "..." }]
|
||
}
|
||
```
|
||
|
||
因此多模态 Provider 可在下一轮直接看到图片,历史中仍只保存短路径清单,不产生 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。
|
||
- 截图有单独的产物目录,不能用来覆盖任意文件。
|
||
|
||
`allowed_domains=[]` 表示不启用 agent-browser 域名过滤,适合通用浏览;这不是 OS 网络沙箱。需要强隔离时,应同时设置明确域名表和容器/主机 egress 策略。允许私网浏览是显式配置,适合本地应用测试,但会扩大 SSRF 风险。
|
||
|
||
## 7. 安装
|
||
|
||
验证版本为 `0.33.0`:
|
||
|
||
```bash
|
||
npm install -g agent-browser@0.33.0
|
||
agent-browser install
|
||
```
|
||
|
||
Linux 自动补系统依赖:
|
||
|
||
```bash
|
||
agent-browser install --with-deps
|
||
```
|
||
|
||
不使用 npm 时:
|
||
|
||
```bash
|
||
cargo install agent-browser --version 0.33.0 --locked
|
||
agent-browser install
|
||
```
|
||
|
||
macOS 也可执行:
|
||
|
||
```bash
|
||
brew install agent-browser
|
||
agent-browser install
|
||
```
|
||
|
||
`agent-browser install` 下载 Chrome for Testing。已有浏览器时设置:
|
||
|
||
```json
|
||
"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. 使用
|
||
|
||
1. 浏览器工具默认启用;从旧配置删除 `webdriver_url`、`chrome_path`,加入新的 browser 字段。缺少依赖不会阻止 Gateway 启动,只会让 health 和实际浏览器调用失败。
|
||
2. 运行 `picobot health`;应看到 agent-browser CLI 版本和 offline quick doctor 通过。
|
||
3. 启动或重载 Gateway。
|
||
4. 对 Agent 说“使用浏览器打开 …”。模型的推荐动作序列是:
|
||
|
||
```text
|
||
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,不能长期缓存旧引用。
|
||
|
||
## 9. Health 三入口
|
||
|
||
`src/health.rs` 的 `HealthService` 是唯一检查实现:
|
||
|
||
- `picobot health [--json]`:本机运维入口;核心/配置必需项失败时退出 `1`。
|
||
- `/health`:当前 Gateway 配置的聊天入口。
|
||
- `health` Tool:Agent 可调用的只读入口,支持 `json=true`。
|
||
|
||
检查项包括 workspace、Bash、内容/文件搜索后端、可选 systemctl、配置中的 stdio MCP 命令,以及浏览器启用时的 agent-browser 版本、显式浏览器路径和 `doctor --offline --quick --json`。检查不安装软件、不执行 `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`;不要让多个 dialog 共享同一底层 ID。
|
||
- domain blocked:补充站点和必要 CDN 域名;不要用空白 allowlist 绕过生产隔离策略。
|
||
- command timeout:确认页面/浏览器未卡死,再按部署风险调整 `command_timeout_secs`。
|
||
- 截图不存在:视为工具失败,不构造失效 MediaRef。
|
||
|
||
Fantoccini crate、旧 `src/tools/browser.rs` WebDriver 实现、ChromeDriver Docker 包和相关配置已全部删除。Cargo 不链接 agent-browser;它是由 health 管理的外部运行依赖。
|