PicoBot/docs/AGENT_BROWSER_INTEGRATION.md

211 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 + daemondaemon 通过 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. 分层
```text
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_profiles` schema 与入口。
- `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 IDBrowserManager 第一次看到该 ID 时生成随机、不透明的 `picobot-<uuid>` agent-browser session。同一 dialog 串行、不同 dialog 可并发;空闲会话按 `idle_timeout_secs` 回收,数量受 `max_sessions` 限制。
- 需要长期保留登录或站点状态时Agent 可以自主调用 `browser_profiles(action=create,label=...)` 创建持久身份,并在后续相关的每个 `browser` action 中显式传入返回的 `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=...)` 写入语义标签并同步当前活动实例;标签去除首尾空白,限制为 180 个非控制字符。
- `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_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
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 先校验首个 URLagent-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`
```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.jsnpm 安装方式只需要 npm 用来放置预编译 CLI。Dockerfile 安装 Debian Chromium、`agent-browser@0.33.0` 并设置 executable path。
## 8. 使用
1. 浏览器工具默认启用;从旧配置删除 `webdriver_url``chrome_path`,仅在需要改变持久目录位置时配置 `persistence.profile_dir`。没有持久化模式开关。缺少依赖不会阻止 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不能长期缓存旧引用。
持久 Profile 管理:
```text
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 配置的聊天入口。
- `health` ToolAgent 可调用的只读入口,支持 `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 管理的外部运行依赖。