Files
market/skills/web-access/references/browser-tools.md
Yige af4176bbd7 feat(web-access): 迁移到内置受管浏览器工具(v2.1.0) (#72)
## 变更说明 / Description

### 中文

客户端 v10.0.98(desirecore/desirecore#1596)停用了旧的 `BrowserListTabs` /
`BrowserNavigate` / `BrowserEval` / `BrowserClick` / `BrowserScreenshot`
/ `BrowserScroll` / `BrowserSetFiles` / `BrowserCloseTab` 及其 cdp-proxy
后端,调用会直接返回「该旧 BrowserXxx/cdp-proxy 入口已停用」。而 web-access v2.0.2 的
`provides.tools` 仍声明这批工具——技能激活后注入的是一组必然失败的工具。

本次把 `provides.tools` 换成统一浏览器工具,并同步正文与参考文档:

- `provides.tools`:`BrowserManage` / `BrowserSnapshot` / `BrowserAct` /
`BrowserImport` / `BrowserShare` + 保留 `SitePatternRead` /
`SitePatternWrite` / `LocalBookmarks`
- 中英文 SKILL 正文同步改写(L0 / 能力描述 / 决策树 / 四层策略表 / L3-fast 速查 / 反模式)
- `references/browser-tools.md` 整篇重写为新 API + 实测边界
- 5 份站点经验(小红书 / B站 / 微博 / 知乎 / 飞书)的流程改用新工具
- 版本 2.0.2 → 2.1.0,`updated_at` 更新,i18n `source_hash` 重算

**L3-fast 的定位相应收窄**:内置浏览器负责「到达 + 交互 + 截图 + 隔离」,抽取长正文仍回落 Jina
Reader(公开页)或 Playwright(登录态)——理由见下方实测。

### English

Client v10.0.98 retired the legacy `BrowserXxx` tools and the cdp-proxy
behind them, so web-access v2.0.2 was injecting a set of tools that
always fail. This PR migrates `provides.tools` to the unified browser
tools and rewrites the body, the browser-tools reference, and the five
site-pattern playbooks accordingly. L3-fast is re-scoped to
navigation/interaction/screenshots; bulk text extraction still falls
back to Jina Reader or Playwright.

## 测试方式 / Test Plan

在客户端 v10.0.98 + `electron-embedded` Provider 上实测:

- [x] `provides.tools` 里 8 个工具 ID 全部在 builtin registry 中存在
- [x] 把本 PR 的技能装进 dev 实例,带 `skillIds:['web-access']` 驱动智能体:真实调用
`BrowserManage(create_space)` → `BrowserManage(start_session)` →
`BrowserAct(tab.navigate)` → `BrowserManage(close_session)`,全部 success
- [x] `scripts/i18n/validate-i18n.py` 全仓库通过(中英文标题数一致、source_hash 一致)

文档中记录的边界均来自实测,而非推测:

| 边界 | 实测现象 |
|------|---------|
| 截图前必须 `tab.activate` | 标签页默认停在 `(-10000,-10000,1x1)`,直接截图卡满 30s
deadline 并触发 `browser.host.gone`,之后全部 `BROWSER_TAB_HOST_NOT_FOUND` |
| `page.evaluate` 不是取文通道 | 每次调用需人工审批;字符串/对象返回值被替换为
`[REDACTED:browser-runtime-value]`,仅 number/boolean/null 穿透 |
| `accessibility` 快照真实页面不可用 | example.com 正常返回 StaticText;维基百科条目一律
`BROWSER_RESULT_TOO_LARGE`(2 MB 上限,且 `depth` 参数被宿主忽略) |
| `semantic` 快照不含正文 | 只列 button / input / a 等可交互元素 |

## 风险与回滚 / Risk and rollback

- 纯技能内容变更,无脚本或清单结构改动
- 需要客户端 v10.0.98+;旧客户端装到本版会拿到一组不存在的工具名(旧客户端上原本那批工具也已失效,不构成回退)
- 回滚即 revert 本 PR
2026-08-07 23:53:28 +08:00

8.7 KiB
Raw Blame History

内置受管浏览器工具速查L3-fast

v2.1 起本层从「cdp-proxy 驱动用户自己的 Chrome」改为「DesireCore 内置受管浏览器」。 每个任务跑在独立 BrowserSpace 里Cookie / Storage / 缓存互不串扰),每个动作都经过 Capability → Grant → Lease → Origin → Host fencing 校验并留下可审计回执。

要求客户端 v10.0.98+。旧的 BrowserListTabs / BrowserNavigate / BrowserEval / BrowserClick / BrowserScreenshot / BrowserScroll / BrowserSetFiles / BrowserCloseTab 与其背后的 cdp-proxy 已停用,调用会直接返回 「该旧 BrowserXxx/cdp-proxy 入口已停用;请改用 BrowserManage、BrowserSnapshot 或 BrowserAct」。

何时用内置浏览器 vs Python Playwright

场景 推荐
到达并操作登录态站点(小红书 / B站 / 微博 / 飞书 / 知乎) 内置浏览器(配合 BrowserImport 导入 Cookie
抽取登录态站点的长正文 Python Playwright内置浏览器没有批量取文通道见下
简单点击 / 滚动 / 截图 内置浏览器
多个任务要互不串扰地并行 内置浏览器(一任务一 Space
需要复杂等待逻辑wait_for_selector + race condition Python Playwrightcdp-browser.md
需要在浏览器内运行长时间脚本(>30 s Python Playwright内置浏览器单条命令 30 s deadline
需要对元素做放大裁剪截图 Python Playwright内置浏览器只有整页截图

前置条件

  1. 客户端 v10.0.98+~/.desirecore/config/browser.jsonelectron-embeddedstandalone-managed Provider 处于 enabled(默认即开启)
  2. 无需用户手工启动调试 Chrome也无需 Python / Playwright

工具一览

每个工具默认 hidden: true只有 web-access 技能被激活后才暴露给 LLM

BrowserManage

Space / Session / Tab 的生命周期。

BrowserManage:
  action: create_space          # list_spaces | create_space | start_session | join_session
                                # | leave_session | list_sessions | list_tabs | create_tab
                                # | freeze_session | resume_session | close_session
  name: xhs-note                # create_space 用
  persistence: ephemeral        # ephemeral=查完即弃,不落 Profilepersistent=保留登录态
  providerPreference: [electron-embedded]
BrowserManage:
  action: start_session
  spaceId: bsp_xxx
  capabilities:                 # 只申请你真正要用的,最小权限
    - browser.observe.tabs
    - browser.observe.snapshot
    - browser.observe.screenshot
    - browser.navigate.create-tab
    - browser.navigate.url
    - browser.navigate.activate-tab
    - browser.input.pointer.click
    - browser.input.keyboard

create_space 会触发一次用户确认。任务收尾用 close_session 释放。

BrowserSnapshot

读页面的主通道。返回可交互元素及其 ref 句柄、rectdisabled 状态。

BrowserSnapshot:
  mode: semantic        # semantic默认| accessibility | visual
  sessionId: bss_xxx    # 当前 Agent 有多个会话时用于消歧
  tabId: btab_xxx

提示:

  • semantic 只列 button / input / a 等可交互元素,不含图片和正文文本节点
  • 元素 name 往往是 placeholder如「请输入」无标签时只能靠 rect.y 排序定位
  • 页面重排后旧 ref 会失效——每次交互前重新取快照
  • accessibility 能拿到 StaticText 正文,但只在很简单的页面上可用:实测 example.com 正常返回,维基百科条目一律 BROWSER_RESULT_TOO_LARGE(回执上限 2 MB 且 schema 里的 depth 参数目前被宿主忽略(硬编码 depth=50调小也没用
  • 因此取真实页面正文仍要靠 L2 Jina Reader公开页或 L3-fallback Playwright登录态

BrowserAct

一次调用一个受管动作。完整 action 见工具 schema常用的

BrowserAct:
  action: tab.navigate
  params: { url: https://www.xiaohongshu.com/explore/... }
BrowserAct:
  action: input.click
  params: { ref: bref_xxx }     # 用快照 ref坐标会因页面重排失效
BrowserAct:
  action: input.text
  params: { text: 搜索关键词 }
BrowserAct:
  action: input.wheel
  params: { deltaX: 0, deltaY: 720, x: 640, y: 400 }
BrowserAct:
  action: tab.activate          # 截图前必须先做这一步
  params: { bounds: { x: 0, y: 0, width: 1280, height: 900 } }
BrowserAct:
  action: page.screenshot
  params: { format: png }       # 结果落 artifact store回执给 artifact.id / sha256 / bytes

BrowserImport需人工审批

把用户浏览器里的登录态 Cookie 导入当前 Space替代旧版「attach 用户已登录的 Chrome」。

BrowserImport:
  action: discover              # discover | plan | apply | ...
BrowserImport:
  action: apply
  planId: bip_xxx
  domains: [xiaohongshu.com]    # 必须逐域显式授权
  conflictStrategy: newer-wins

解密与过滤全在 Host 侧完成,Cookie 值不会进入 Agent 上下文或审计日志

BrowserShare

把 Space / Session 委派给另一个 AgentshareMode 可选 snapshot(只读副本)、 copy-on-write(写时复制)、live-shared(实时共享)、handoff(移交控制权)。

已知边界(照做,别试探)

边界 说明
截图前必须 tab.activate 标签页默认停在 (-10000,-10000,1x1),没有合成表面。直接截图会卡满 30 s deadline并把标签页宿主打掉,之后全部报 BROWSER_TAB_HOST_NOT_FOUND
同时只有一个可见标签页 tab.activate 绑定主窗口、全局互斥。多 Space 可以并发导航/快照/输入,但截图必须逐个 activate 串行
page.evaluate 基本不可用 每次调用需人工审批;返回的字符串/对象被替换为 [REDACTED:browser-runtime-value](只有 number/boolean/null 穿透);反调试站点会把它挂起几十秒。读页面用 BrowserSnapshot
cdp.raw 需人工审批 browser.raw_cdp.* 属于永远人工闸门的能力,无人值守流程用不了(元素级裁剪截图因此不可用)
没有批量取文通道 semantic 不含正文,accessibility 在真实页面上超限,page.evaluate 被审批+脱敏。要正文请回落 Jina / Playwright
单条命令 30 s deadline 超时即判 browser.host.gone,会话作废
用户真实鼠标会抢控制权 鼠标划过可见标签页会触发 trusted-user-input 并递增 control epoch可能打断 Agent 的租约
artifact 不要走 /save 该接口会弹系统「另存为」对话框等人点。artifact 文件在 ${DESIRECORE_ROOT}/browser/artifacts/<bart_id>/,直接读即可,默认保留 24 小时

SitePatternRead / SitePatternWrite

参见 SKILL.md 的"站点经验积累"章节。任务结束如果发现新陷阱、新选择器,调用:

SitePatternWrite:
  domain: xiaohongshu.com
  scope: agent           # agent=共享(受 Git 管理可发布user=私有
  mode: merge            # 默认 merge 追加replace 覆盖
  content: |
    ## 已知陷阱
    - 2026-08: ...

含 cookie/token/手机号/邮箱时会自动降级 scope='user'。

错误处理

错误 原因 解决
该旧 BrowserXxx/cdp-proxy 入口已停用 还在调 v2.0 的旧工具 改用 BrowserManage / BrowserSnapshot / BrowserAct
BROWSER_TAB_HOST_NOT_FOUND 标签页宿主已销毁(多因上一条命令超时) 重建 Session检查是否漏了 tab.activate
BROWSER_COMMAND_DEADLINE_EXCEEDED 单条命令超 30 s 截图先 activate避免 page.evaluate
BROWSER_TOOL_SESSION_FORBIDDEN 会话已关闭/崩溃,或不属于当前 Agent 重新 list_sessions,必要时重建
BROWSER_TOOL_SESSION_AMBIGUOUS 当前 Agent 有多个会话且未传 sessionId 显式传 sessionId
BROWSER_HUMAN_APPROVAL_REQUIRED 触到人工闸门能力evaluate / raw_cdp / 上传下载 / Cookie 导入等) 向用户说明用途并等待审批,或换用无需审批的路径
BROWSER_RESULT_TOO_LARGE 回执超过 2 MBaccessibility 快照最常见) 改用 semantic 快照 + 截图;取正文回落 Jina / Playwright

调用链路

Agent → BrowserManage/Snapshot/Act → browser-use serviceCapability/Grant/Lease/Policy 校验)
      → BrowserHostelectron-embedded 或 standalone-managed→ Chromium
                                    ↑ 每步产出带 digest 的回执,写入审计事件流