跟进 desirecore/desirecore#1741 与 #1756(均已合入 dev,随 10.0.100 发布)。
## 变更 / Changes
- **截图像素直接给**:现在作为 image 块进工具结果,视觉模型当场就能看。补一节说明什么时候才需要再 `Read`
一次(结果明确写了未附带像素、或需要原始分辨率),避免同一张图在上下文里占两份。同时说明非视觉模型下会明确告知「你看不到它的内容」,此时不要凭空描述画面。
- **元素级裁剪不再需要 `cdp.raw`**:`BrowserSnapshot` 的
`options.clip={x,y,width,height,scale}` 直接支持,`scale` 最大 4(已对照
`command-params.ts:333` 核实)。
- **artifact 改用 `result.artifact.absolutePath`**:原文教的
`${DESIRECORE_ROOT}/...` 在路径展开里根本不认(只认 `~` / `$HOME` /
`$USERPROFILE`),拼出来是相对路径、`Read`
报「文件不存在」;原文给的还是目录,照抄会撞上「路径不是文件」。真机实测两条都踩过。
## 刻意未改 / Deliberately unchanged
「用户真实鼠标会抢控制权」一条**保持原样**——修它的 desirecore/desirecore#1740 尚未合并,现状描述仍然准确。
## 版本门控 / Version gating
`required_client_version` 10.0.98 → **10.0.100**(含上述两个 PR 的最早版本)。market
是运行时拉取的,不提门槛会让老客户端拿到教它们用不存在能力的说明。
---
Follows desirecore/desirecore#1741 and #1756 (both merged to dev,
shipping in 10.0.100). Screenshot pixels now arrive as an image block
directly; element-level cropping no longer needs raw CDP; artifact reads
use the absolute path from the receipt. The 'real mouse steals control'
note is intentionally left as-is because its fix (#1740) is not merged
yet.
---------
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
12 KiB
内置受管浏览器工具速查(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站 / 微博 / 飞书 / 知乎) | 内置浏览器(登录态优先走 L3-fallback CDP;仅在已授予 browser.import.* 时才用 BrowserImport 导入 Cookie) |
| 抽取登录态站点的长正文 | Python Playwright(内置浏览器没有批量取文通道,见下) |
| 简单点击 / 滚动 / 截图 | 内置浏览器 |
| 多个任务要互不串扰地并行 | 内置浏览器(一任务一 Space) |
| 需要复杂等待逻辑(wait_for_selector + race condition) | Python Playwright(cdp-browser.md) |
| 需要在浏览器内运行长时间脚本(>30 s) | Python Playwright(内置浏览器单条命令 30 s deadline) |
| 需要对元素做放大裁剪截图 | Python Playwright(内置浏览器只有整页截图) |
前置条件
- 客户端 v10.0.98+,
~/.desirecore/config/browser.json里electron-embedded或standalone-managedProvider 处于enabled(默认即开启) - 无需用户手工启动调试 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=查完即弃,不落 Profile;persistent=保留登录态
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.pointer.wheel # 要滚动加载就必须带上,漏了 input.wheel 会被策略拒绝
- browser.input.keyboard
显式传 capabilities 就是在做减法:不传时按 agentDefault 全量签发租约,传了就只签这一份
列表。所以别照抄示例——把你这次真正要用的动作对应的能力都列全。
create_space 会触发一次用户确认。任务收尾用 close_session 释放。
BrowserSnapshot
读页面的主通道。返回可交互元素及其 ref 句柄、rect、disabled 状态。
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。
前置条件(先看这里,别直接试):
browser.import.discover/browser.import.cookies.inspect/browser.import.cookies三个能力不在agentDefault里, 而BrowserManage(create_space)建的 Agent grant 就是按agentDefault签的。也就是说 仅靠 create_space / start_session 走不通 BrowserImport,必须由 Host/用户侧另行授予 import 能力(agentElevated或 Workbench 路径)。没有这层授权就别在这条路上耗——直接回落 L3-fallback(Python Playwright 连用户已登录的 Chrome),那是当前更稳的登录态复用方式。
动作枚举只有这 6 个:discover | create_plan | dry_run | apply | rollback | list_plans
(没有 plan)。完整流程是 discover → create_plan → dry_run → apply:
BrowserImport:
action: discover # 列出可导入的来源,返回不透明 sourceProfileId
BrowserImport:
action: create_plan # 域名授权、来源、冲突策略都在这一步定死
sourceKind: chromium-profile # chromium-profile | firefox-profile | safari-profile
# | browser-extension | cookie-file
sourceProfileId: <discover 返回的 ID>
domains: [xiaohongshu.com] # 必须逐域显式授权
conflictStrategy: newer-wins # keep-target | replace-target | newer-wins | fail-on-conflict
BrowserImport:
action: dry_run # 先看命中多少条,再决定要不要真的写入
planId: bimp_xxx # create_plan 返回的 ID,前缀是 bimp_
BrowserImport:
action: apply # 只认 planId;域名/策略在 create_plan 时已固化
planId: bimp_xxx
写坏了用 action: rollback + 同一个 planId 回退;list_plans 查当前 Space 的历史 plan。
解密与过滤全在 Host 侧完成,Cookie 值不会进入 Agent 上下文或审计日志。
BrowserShare
把 Space / Session 委派给另一个 Agent,shareMode 可选 snapshot(只读副本)、
copy-on-write(写时复制)、live-shared(实时共享)、handoff(移交控制权)。
截图:像素直接给你,通常不需要再 Read
BrowserSnapshot mode: visual 与 BrowserAct page.screenshot 会把截图像素作为
image 块直接放进工具结果——视觉模型当场就能看,不必再调 Read。
只有这几种情况才需要走 result.artifact.absolutePath 再 Read 一次:
- 结果里明确写了「截图已保存,但…未附带像素」(超出单图预算、或体积过大)
- 你需要的是原始分辨率,而附带的像素被压缩过
对同一张图既看 image 块又 Read 一遍,只会让它在上下文里占两份。
当前模型不支持视觉输入时,结果会明说「你看不到它的内容」——此时不要凭空描述画面,
改用 semantic / accessibility 快照拿页面信息。
已知边界(照做,别试探)
| 边界 | 说明 |
|---|---|
截图前必须 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.* 属于永远人工闸门的能力,无人值守流程用不了。元素级裁剪不必走它——BrowserSnapshot 的 options.clip={x,y,width,height,scale} 直接支持(scale 最大 4):先用 semantic 快照拿到元素坐标,再截那一块并放大。验证码、小按钮在整页截图里只有几十像素,看不清时用它 |
| 没有批量取文通道 | semantic 不含正文,accessibility 在真实页面上超限,page.evaluate 被审批+脱敏。要正文请回落 Jina / Playwright |
| 单条命令 30 s deadline | 超时即判 browser.host.gone,会话作废 |
| 用户真实操作会抢控制权 | 在可见标签页上点击、按键、滚轮、触摸会触发 trusted-user-input 并递增 control epoch,打断 Agent 的租约。鼠标只是划过不会(默认策略 intentional-input),所以用户看着页面移动光标是安全的 |
artifact 不要走 /save |
该接口会弹系统「另存为」对话框等人点。用回执里的 result.artifact.absolutePath(工具会把它登记进本次会话的可读白名单),不要自己拼路径——${DESIRECORE_ROOT} 这类变量在路径展开里不认(只认 ~ / $HOME / $USERPROFILE),拼出来是相对路径、Read 会报「文件不存在」。默认保留 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 MB(accessibility 快照最常见) |
改用 semantic 快照 + 截图;取正文回落 Jina / Playwright |
调用链路
Agent → BrowserManage/Snapshot/Act → browser-use service(Capability/Grant/Lease/Policy 校验)
→ BrowserHost(electron-embedded 或 standalone-managed)→ Chromium
↑ 每步产出带 digest 的回执,写入审计事件流