feat(browser): complete camofox BrowserProvider with tabs, interaction, download capture and control lease

Contracts for browser API and browser.* agent capabilities; adapter implements
close/list/restore sessions, tabs + reconcile, history, click/type/select/scroll/press,
extract, waitForDownload (staged via DownloadSink, sha256), stale-ref guard and
automation/human actor check. testkit mock camofox gains an interactive site
(login redirect, captcha, click-driven page changes, downloads, PNG screenshots).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-09-28 20:17:46 +08:00
1 parent 62290d4477
commit c17d4b90bd
12 files changed
+1832 -101

No files matched your search

+9 -14
View File
@@ -8,19 +8,14 @@
- `profile-lock.ts`:同一 profile 串行锁(进程内内存实现;多进程部署换持久化实现,接口不变)。
- `budget.ts`:导航域名白名单(含子域),非 http(s) 拒绝。
## v0.1 已实现
## 已实现(C1-E,仅对 mock 与上游文档验证)
`health`(`/health`,免认证,503 → degraded)、`capabilities`(静态声明;`probe: true` 读上游 `/openapi.json` 推导,缺端点即降级)、`openSession`(`POST /tabs`)、`navigate`(`POST /tabs/{id}/navigate`,预算内重试 5xx/超时/网络错误)、`snapshot`(`GET /tabs/{id}/snapshot?format=text`,字节预算截断 + 脱敏)、`screenshot`(`GET /tabs/{id}/screenshot`,JSON base64 或二进制图片;登录页/含凭据地址标 `modelSafe: false`)。
- 会话:`openSession`(`POST /tabs`)、`closeSession`(`DELETE /sessions/{userId}`)、`listSessions`(内存镜像;服务层以数据库为准)、`restoreSession`(重启后按 DB 恢复,旧引用失效)。
- 标签页:`openTab`、`closeTab`(`DELETE /tabs/{id}`)、`reconcileTabs`(`GET /tabs?userId`,上游已回收的标 `lost`)。
- 导航:`navigate`(白名单 / 超时 / 预算内重试 5xx·超时·网络)、`history`(`/back` `/forward` `/refresh`)。
- 读取:`snapshot`(字节预算截断 + 脱敏)、`screenshot`(JSON base64 或 image/*;登录页 / 含凭据地址 `modelSafe: false`)、`extract`(`POST /extract`,需先快照)。
- 交互:`click`(ref / selector / 视口坐标)、`type`(明文或凭证引用,凭证经 `BrowserSecretResolver` 解出后直接下发)、`select`、`scroll`、`press`。
- 下载:`waitForDownload` 轮询 `GET /tabs/{id}/downloads?includeData&consume&maxBytes`,字节交 `DownloadSink` 暂存、算 sha256,只返回引用。
- 控制权:`TabRef.as` 标明发起方(automation / human),与会话 controller 不符报 `control_conflict`;`setController` 任何变更都让旧 `eN` 引用失效(`stale_ref`);`acquireControl` / `releaseControl` 为内存版,服务层用 `browser_control_lease` 持久化。
## M2(当前抛 `BrowserError('not_implemented')`)
| 方法 | 上游候选端点 | 待办 |
| --- | --- | --- |
| `closeSession` | `DELETE /sessions/{userId}` | 与 browser_session 持久化、租约释放一起落地 |
| `listSessions` | `GET /tabs?userId=` | 上游只列标签页,会话清单以 DB 为准,需对账 |
| `click` / `type` | `POST /tabs/{id}/click` / `type` / `select` | 接凭证代理(`TypeInput.kind = 'secret'`);README 示例 `pressEnter` 与 OpenAPI `submit` 字段名不一致,需核验 |
| `extract` | `POST /tabs/{id}/extract`(JSON Schema + `x-ref`) | 需先 snapshot 建 ref 表 |
| `waitForDownload` | `GET /tabs/{id}/downloads?includeData&consume&maxBytes` | 产物落 blob 暂存 + sha256,交后端核验 |
| `acquireControl` / `releaseControl` | 无(上游无接管 API) | 服务层以 `browser_control_lease` 持久化;画面/输入通道待 VNC 原型 |
仅对 mock 与上游文档验证,未连接真实实例。
未核验的上游行为(坐标点击、无目标输入、scroll / press / back 等端点、downloads 字段形状)见 `docs/runbook/browser.md` 第 6 节。