dsh-browser-cdp
DSH 浏览器插件(原 dsh-ego-browser):让 Agent 通过 CDP 接入真实 Chrome —— 远程目标序列与激活、实时视频/截图回传、登录导入。Remote-CDP agent browser for DeepSeek Harness.
- Stars
- 21
- Language
- TypeScript
- Created
- Sep 22, 2026
- Updated
- Oct 28, 2026
Introduction
dsh-browser-cdp — 看得见的 Agent 浏览器(CDP 接入)
简体中文 | Français | Deutsch | Italiano | Русский | Español
仓库:
github.com/drscrewdriver/dsh-browser-cdp|版本历史见 CHANGELOG.md
版本兼容矩阵
| 依赖 | 最低版本 | 推荐版本 | 说明 |
|---|---|---|---|
| DSH (DeepSeek Harness) | 0.1.7-rc.1 | 0.1.7-rc.1 ~ 0.2.1-rc.4(精确枚举) | 精确枚举 8 个 rc 版本,engines 与全部 dsh peer 同串(无区间/caret):`0.1.7-rc.1 |
| dsh-better-sidebar | 0.12.2(可选) | ≥ 0.17.1 | 未安装时自动回退浮动观察球;< 0.12.2 可运行但外部链接拦截(urlTarget)静默降级 |
| Node.js | 22 | — | harness 环境自带 |
DSH 全版本适配说明:本版本(1.2.1 起;1.2.2 起追加 0.2.1-rc.2)面向 DSH 0.1.7-rc.1 ~ 0.2.1-rc.4(精确枚举 8 个 rc):相对 0.1.7 线(v0.17.x)零代码改动,纯依赖/元数据换代——0.2.0 宿主对插件 API 向后兼容,本插件经 ctx.get('conversation').input 门面投递选区(不调 submit()、不 override),不在 0.2.0 变更影响面内。声明式设置面自 0.1.7 引入:插件不再注册任何设置节(ctx.settings 注册类 API 已被宿主删除),改为在 Config schema 上以 .volatile() 标记可配置字段,由宿主设置页自动生成表单;volatile 字段变更通过 loader/volatile-update 事件热生效,无需重载插件。核心宿主 API(defineTool、ctx.tools.register、ctx.subprocess.spawn、ctx.webServer.register、ctx.inject、ModuleLoader CJS factory、cordis.patch.yml)沿用 0.1.2 以来形态。DSH 0.1.2-rc.1 ~ 0.1.5-rc.3 请使用 0.17.x 版本线。
dsh-better-sidebar 适配说明:本插件通过 ctx.betterSidebar 服务(try-catch 防御性获取)注册侧边栏 Tab 并监听外部链接。关键 API 引入版本:
| API | 本插件用法 | better-sidebar 引入版本 |
|---|---|---|
registerTab() / openTab() / ctx.betterSidebar | Tab 注册 + 打开 | v0.9.0+ |
TabDescriptor.single | 单实例 Tab | v0.9.0+ |
TabDescriptor.urlTarget | 外部链接拦截 | v0.12.2+(低于此版本链接拦截静默失效) |
DSH 版本支持详情:v0.8.2 → v0.8.3 主要变更:合并 6 个社区 PR(root/xvfb/macOS headless 适配、rc.1 兼容、Windows 稳定性),修复无认证 /api/bcdp/* 路由安全漏洞、无 dsh-better-sidebar 宿主 client 启动失败(#29)、Windows 冷启动回归(#22 引入的 Xvfb 误判),并修复 gateway 设置白名单缺 runtimeArgs/chromeArgs。适配点:client 运行时改名(@deepseek-ai/dsh-client-store)、client 模块注册 id 与装载行名按声明包名、dsh.client.inject 仅声明真实模块图行、webServer 以嵌套注入交付(可选服务),并同步侧边栏 Tab(dsh-better-sidebar)模式。
侧边栏支持(dsh-better-sidebar):当宿主安装了 dsh-better-sidebar(推荐 ≥ v0.12.2)时,实时观察窗注册为侧边栏原生 Tab——「Agent 浏览器」出现在侧边栏「+」菜单中,点击即打开并随侧边栏抽屉固定展示;agent 首次调用 bcdp_* 工具时会自动打开该 Tab(v0.8.5 起按调用会话作用域打开,多会话不再弹错位置)。未安装 dsh-better-sidebar 时自动回退为右下角浮动观察球(#dsh-ego-fab)模式。两种形态共用同一套 SSE 实时推流 / 点击 / 输入 / 下载捕获能力。观察窗还提供一个「弹出窗口」按钮:无头(headless)运行的 agent 浏览器可一键替换为同 Profile 的有头窗口(标签页保留),方便手动接管。
登录态导入(v0.8.5 新增):工具 bcdp_login_import,把你日常 Chrome/Edge/Brave 里的登录 cookie 按域名复制进 agent 浏览器(真实二进制无头启动 + CDP 透传读取,兼容 Chrome 127+ 的 App-Bound Encryption,不做离线解密;源浏览器运行中可选择优雅关闭后导入,窗口下次启动自动恢复)。cookie 值不出现在任何日志与输出中;导入前自动备份源 cookie 库,异常清空自动还原。配合默认的磁盘持久化 Profile,导入的登录态跨重启永久保留。
一款 CDP 浏览器代理:内置 ego 兼容运行时(供 AI Agent 用的 Chromium,来源与许可逐文件见 THIRD_PARTY_NOTICES.md)接入 DeepSeek Harness,以 34 个结构化 bcdp_* 工具驱动浏览器,并配一套实时观察前端口——agent 后台操作网页时,你能像看直播一样看到它正在浏览的每个页面,还能直接操作它。
一点私藏的独特之处(self-observation):agent 用的就是这一个 Chromium——连它操作 DSH 自身(管理会话、任务看板、调设置)时,观察窗也实时显示、你能随时接手。不只是"看得见 agent 在网页上干活",连 agent 操作 DSH 界面本身都是全程可见、可掌控的。
开箱即用:插件包内置 ego 兼容运行时(runtime/,第三方 MIT,来源见 THIRD_PARTY_NOTICES.md)——无需额外浏览器、无需手动构建,--no-sandbox wrapper 随包自带,root / Docker / 无显示器一键跑。
我们的真正优势(不是口号,是能对照代码和竞品核实的能力)
同为把 ego 浏览器接进 DSH 的方案,市面上已有同类插件只做了 3 个工具——一个 run 脚本、一个 help 指南、一个 status 体检,浏览器仍是后台黑盒。本插件走的是另一条路:把黑盒打开,并且一上来就把"看"和"控"的能力做到位。
| 能力 | 本插件(本仓库) | 同类插件 |
|---|---|---|
| 结构化工具数 | 34 个,职责单一、可确定性调用 | 3 个(run/help/status) |
| 实时观察窗(CDP JPEG / FFmpeg H.264 双后端 + 标签条 + 历史抽屉) | ✅ 有 | ❌ 无 |
| 监控窗鼠标直接操作真实浏览器(点击/拖拽/滚动回传 CDP) | ✅ 有 | ❌ 无 |
观察窗点选元素 → 捕获并引用进对话输入框([CDP-PICKS] 结构化块,人工指认目标) | ✅ 有 | ❌ 无 |
| worker 单实例守卫 + 崩溃/重复自愈 | ✅ 有 | ❌ 无 |
下载捕获 bcdp_download / 人机验证检测 bcdp_captcha/bcdp_page_info | ✅ 有 | ❌ 无 |
平台自适应(Linux/macOS/Windows 自动探测 + root/无头/--no-sandbox 兜底) | ✅ 全平台 | 仅 Windows 预览宿主,需手动配 |
登录态落盘持久化 bcdp_auth_flush | ✅ 有 | ⚠️ 仅文档级说明 |
关键差异三条:
- 看得到:别家是"跑完告诉你结果"的黑盒;我们实时推流,你看着 agent 操作,卡在验证码/走岔立刻发现。
- 控得住:别家只读;我们监控窗直接驱动同一个 agent 浏览器,需要时你亲手接管(缩放/拖拽/点击),不必打断 agent 重来。
- 指得准:你在观察窗里点选页面元素,插件捕获其
backendNodeId/tag/id与语义描述,以[CDP-PICKS]结构化块并入对话输入框草稿(同页多元素自动合并编号)——agent 拿到的是精确目标,不用猜"你说的按钮是哪个"。
以上对比基于公开可见的可核实事实:本仓库代码(
bin/cdp-cast-worker.mjs实时推流 + CDP 输入回传、lib/index.js34 个注册工具、lib/cast-server.jshost 桥接、lib/client.js的deliverPickToConversation点选引用)与同类插件公开可见的源码/README。此文档不含对任何他人的贬低——我们只陈述自己多实现并验证了哪些能力。
相对内置运行时本体(一个无头 CLI),我们多做了这些(都可对照本仓库代码核实):
| 能力 | 说明(对应代码) |
|---|---|
| 观察窗前端口 | 内置运行时本体是无头 CLI(只有 heredoc 脚本 + 文本输出);我们在其上加了 SSE 实时推流 + 标签条 + 历史抽屉 + 监控窗鼠标直操 + 点选元素引用进输入框(bin/cdp-cast-worker.mjs、lib/cast-server.js、lib/client.js 的 createPickControl/deliverPickToConversation),让"看"、"控"、"指"成为一等能力 |
| 开箱即用 + 跨平台自足 | resolveEgoEnv 自动探测 Chrome/Edge/Brave,内置 --no-sandbox wrapper,root / Docker / 无显示器免配置(lib/index.js);不必先装一个 GUI 宿主 |
| 健壮性层 | 冷启动自动重试(只重试 CDP 瞬态,不吞真错)、worker 单实例守卫 + 崩溃自动重启、插件卸载 fire-and-forget 不阻塞宿主退出、前端帧缓存上限(withWarmupRetry / makeEnsureWorker / frameCache) |
| 运维型工具 | bcdp_doctor(环境体检)、bcdp_captcha(人机验证探测)、bcdp_auth_flush(登录落盘)、bcdp_login_import(系统浏览器登录态导入)、bcdp_http(浏览器上下文请求)等,是原生 CLI helper 没有的一层 |
| self-observation | agent 操作 DSH 自身界面时同样实时可见、可接手 |
我们不声称媲美原生 macOS App 的内核级快照或多窗口体验;本仓库解决的是"把同一套浏览器能力带进 DSH + Linux/WSL + 看得见"这件事。
它解决什么问题
通用浏览器不是为 agent 设计的,而 Web 上大量交互(登录态、验证码、动态渲染、表单、需真人会话的站点)只有真浏览器能面对——这正是 ego 浏览器 "让 agent 用你已登录的浏览器,而不打扰你" 的设计初衷。
本插件把它接进 DSH,并把最痛的一点——你看不见 agent 在干什么、也插不上手——用一套观察窗解决:
🌐 小球一点看直播;🟦 标签条切换/关闭;🕘 历史抽屉回看;🔍 缩放拖拽;🖱️ 监控窗直接接管真实浏览器。一句话:让 agent 在浏览器里干活,你在旁边既看得见、又随时能接手。
几个常见的上手场景
- 文献 / 数据抓取:让 agent 登录知网 / 谷歌学术翻页收集,你在观察窗看着它滚动、点下一页、下载 PDF,中途卡住立刻能发现。
- 表单与登录:agent 填表到一半,观察窗弹出验证码——你直接接管把验证码点了,再交还给 agent 继续。
- QA / 冒烟测试:让 agent 在自己产品上点一圈,观察窗等于一台"会说话的录屏",顺手还能回看历史轨迹。
- 看 agent 操作 DSH 自身(self-observation):agent 在管理会话 / 调设置时,观察窗同样全程可见、可接手。
前置条件
| 要求 | 说明 |
|---|---|
| Node ≥ 22 | harness 环境自带 |
| 任意 Chrome / Chromium / Brave / Edge | 自动发现,或 EGO_LINUX_CHROME 指定;root 下用自带 wrapper |
| DSH + dshx | 插件装载机制 |
| 带图形界面的 DSH Web(观察窗) | headless 会话仍可用 bcdp_* 工具,仅无观察窗 |
安装
方式一:GitHub 直装(推荐)
dsh plugin --profile web add github:drscrewdriver/dsh-browser-cdp
# 也可锁定到某个 commit / tag:
dsh plugin --profile web add github:drscrewdriver/dsh-browser-cdp#v0.9.0
github:安装由 pnpm 经codeload.github.com拉取仓库 tarball,无需向 npm registry 发包;直接使用仓库中预构建入库的lib/(files仅含lib/、bin/、runtime/、cordis.patch.yml、dsh-plugin.json),因此不触发任何构建脚本,也不需要 devDependencies。host 入口lib/index.js、客户端lib/client.js、workerbin/cdp-cast-worker.mjs均随仓库分发。
方式二:本地 tarball / git URL
dshx install dsh-browser-cdp <dsh-browser-cdp.tgz> # tarball 或 git URL 均可
dshx list # 应显示:[on] dsh-browser-cdp
包名迁移说明:本插件包名是
dsh-browser-cdp(曾用名dsh-ego-browser、别名@dsh-external/ego-browser)。DSH Desktop 2.0.5 起增加了「profile 依赖名 == 包实际 name」的一致性校验,若 profile 仍用旧名引用,启动会挂进恢复模式。升级后请把 profile 的package.json依赖键 和dsh.profile.bundles条目两处都改为dsh-browser-cdp:
- "dsh-ego-browser": "<旧 github 来源>",
+ "dsh-browser-cdp": "github:drscrewdriver/dsh-browser-cdp",
- "dsh-ego-browser",
+ "dsh-browser-cdp",
观察窗设置中可选 captureBackend=auto|cdp|ffmpeg(默认 auto,当前解析为 CDP)、画质档位、CDP FPS/JPEG 质量/最大宽度,以及 FFmpeg FPS/最大宽度/码率/编码器/自定义路径。插件先检测自定义路径、系统 PATH 和托管缓存;GitHub 下载可用 githubMirror 替换 https://github.com,例如 https://gh-proxy.com/github.com。FFmpeg 码率范围为 500-20000 kbps,低/平衡/高档默认 2000/4000/8000 kbps。
无需宿主侧任何配置:resolveEgoEnv 自动探测 root / 无显示器并兜底。观察窗 host 路由(/api/bcdp/spaces 等)仅在有 HTTP server 时注册,headless 是安全 no-op。
连接方式:CDP 端点 / 本机 ego CLI
连接目标直接在设置里增删改(0.18.1 起,与 0.17.x 线同源):设置卡有两处入口——「起子插件设置」family 区的本插件 tab(装了 dsh-thinking-levels 时),以及插件详情页的设置卡(plugins.bundle.config,不装 thinking-levels 时的独立入口);两处渲染同一份组件。每行支持:启用开关、激活、标签/端点/CLI 路径就位编辑、逐行探测、上移/下移、删除(删激活行会同时清空激活,绝不顺延);底部内联表单直接添加 CDP 端点或本机 ego CLI(第二条本机 CLI 会被拒绝)。写回落在活动 profile 的 cordis.patch.yml,跨重启保留。0.18.1 之前,连接序列只能在 profile 的 cordis.patch.yml links 中手工维护。
设置面板里的连接列表是有序的——顺序即优先级,被激活的那一项驱动每一次 bcdp_* 调用。列表元素有两种类型:
| 类型 | 它做什么 | 约束 |
|---|---|---|
| CDP 端点 | 把一个已开调试端口的浏览器地址交给内置运行时(注入 EGO_LINUX_CDP_URL),运行时附着上去 | 可多条 |
| 本机 ego CLI | 由本机 ego CLI 自己驱动它本机的 ego 浏览器——不注入任何端点 | 仅限本机,全局至多一条 |
为什么需要第二种:注入用的 EGO_LINUX_CDP_URL 是**内置运行时(Linux 线)**的私有契约,macOS 上用 ego lite app 附带的那个原生 ego-browser 根本不读它。所以在只有"CDP 端点"这一种类型时,macOS 用户无法用上自己那个已登录的 ego——只能连远端端口,或让内置运行时另起一个 stock Chromium。本机 CLI 类型补的就是这条路。
解析顺序(cliPath 留空时):显式路径 → PATH 上的 ego-browser → macOS app 包内 helper(/Applications/ego lite.app/…/Helpers/ego-browser)→ 插件内置运行时。
两个默认值值得知道:
useSdkPath默认关闭:关闭时用 CLI 自带的 harness(配套的那套);打开后,探测与每一次工具执行都会注入--sdk-path <插件内置 harness>。这一点很关键:只在探测时带、执行时不带,脚本首行就会崩ReferenceError: taskSpaces is not defined(1.2.4 修复的 P0)。若 CLI 不认这个旗标,探测会记一条提示并自动重试一次不带它;此时只有 CLI 自带的 harness 确实暴露taskSpaces/browser门面才算就绪,否则显式判失败并给出缺失的门面名——不再假阳性。- 就绪探测是
nodejs通道上的 facade 探针(与干活同一条通道):只检查注入后的taskSpaces/browser/page全局,不启动也不等待浏览器,实测约 300 ms;bcdp_status走同一判据。
双 API 面共存风险
本插件通过注入 SDK 使用 taskSpaces.*(插件侧 API),而 ego-browser skill 脚本使用原生 taskSpace()(app 侧 API)。二者驱动的是同一个 ego,task space 也是共享的:同时用插件工具和该 skill 脚本操作同一空间,可能互相抢控制权。建议二选一,以插件为准;确需跑该 skill 脚本时,先停用本插件的 ego-cli link。
与其它开关的关系:
cdpMode:auto按激活项(两种类型都行);remote只接受 CDP 端点,激活项是本机 CLI 时会显式报mode-kind-mismatch;local走受管本地启动器。remoteEnabled(远端总开关)只管远端 CDP,不影响本机 CLI 连接。allowLocalFallback/localHeadless/localUserDataDir只作用于 CDP 端点的回落与受管启动。allowProbeColdStart(默认关):就绪探测绝不拉起 ego 浏览器——--status证明浏览器已在跑才做 heredoc 验证,否则跳过,浏览器推迟到首个真实bcdp_*调用才启动(插件挂载/改设置不再弹浏览器窗口)。打开 = 挂载探测预先验证 SDK harness(可能当场弹出浏览器窗口)。
bcdp_doctor 会报告当前序列类型计数、CLI 实际解析到的路径与形态,以及(若同机装了旧版 dsh-ego-browser)一条共存提示。
Lightpanda 后端(可选引擎,beta)
Lightpanda 是面向 AI 的无头文本渲染浏览器(AGPL-3.0,本插件仅作 CDP 客户端使用)。它对插件来说就是一个普通 CDP 端点:设置面板添加并激活后,probe 会从 /json/version 的 Browser: Lightpanda/… 自动识别引擎,badge 与 bcdp_doctor 显示 engine,能力降级自动生效(无需任何配置)。
分系统安装
| 系统 | 方式 |
|---|---|
| Linux(建议本机直装测试) | curl -fsSL https://pkg.lightpanda.io/install.sh | bash(装入 ~/.local/bin,确保 PATH 含它)→ lightpanda serve --host 127.0.0.1 --port 9222 |
| macOS(建议本机直装测试) | 同上一键脚本(aarch64)→ 同 serve 命令 |
| Windows(内置方案 = WSL2,无原生版) | 管理员 PowerShell wsl --install → 重启 → wsl --install -d Ubuntu → WSL 内同 Linux 一键脚本 → WSL 内 lightpanda serve …;WSL2 自动把端口映射到 Windows localhost(二进制只存在于 WSL 内,宿主侧没有文件,属预期) |
| Docker(备选) | docker run -d --name lightpanda -p 127.0.0.1:9222:9222 lightpanda/browser:nightly |
装好后在本插件设置面板添加 CDP 端点 http://127.0.0.1:9222 并激活即可。可选:export LIGHTPANDA_DISABLE_TELEMETRY=true 关遥测。
能力降级矩阵(识别后自动生效)
| 能力 | Lightpanda 上的行为 |
|---|---|
| 导航 / JS / 点击 / 填表 / 键鼠 / 快照(AX 树)/ HTTP / 登录导入 / 等待族 | 无损可用 |
bcdp_screenshot | PNG 文本级渲染(无像素引擎,视觉保真低于 Chrome;runtime 本就发 png,零改动兼容) |
jev 视觉链(bcdp_jev_frame 等) | 投影自动改发 PNG;输出带 engine / rendering: text 元数据 |
| 观察窗实时画面 | 关闭——无 screencast 且无窗口,worker 不启动采集循环,面板显示降级提示 |
| 面板点选(inspect 路径) | 关闭——无 Overlay 域 / bindingCalled 事件,返回 engine-unsupported(i18n);坐标回退路径保留 |
bcdp_download | 关闭——无 Page 下载事件,调用即返回结构化错误(不会挂起超时) |
bcdp_auth_flush | 返回 degraded: true——引擎无 Storage.flushCookies,cookie 仅随引擎进程存活 |
识别失败的端点(engine: unknown)保持全能力——误判只应"少给",不应"错给"。
工具清单(34 个,前缀 bcdp_,完整索引见 bcdp_help)
| 类别 | 工具 |
|---|---|
| 任务空间 | bcdp_space(open / close / list / handoff / takeover) bcdp_status |
| 页面读取 | bcdp_snapshot(语义树) bcdp_page_info bcdp_read_element |
| 导航/标签/等待 | bcdp_navigate(复用 tab / reload) bcdp_tab(list/current/new/switch/close) bcdp_wait(duration / selector / url / response / load / function / request / event) |
| 交互 | bcdp_click bcdp_fill bcdp_hover bcdp_drag bcdp_select bcdp_check bcdp_key(type/insert) bcdp_scroll |
| 执行/调试 | bcdp_js(页面求值) bcdp_cdp(原始 CDP) bcdp_script(多步脚本;verbatim:true = 原 bcdp_cli 的裸 heredoc) |
| 输出 | bcdp_screenshot bcdp_download bcdp_upload |
| 会话/安全 | bcdp_auth_flush(登录落盘) bcdp_login_import(跨浏览器登录态导入) bcdp_captcha bcdp_dialog |
| 元工具 | bcdp_help bcdp_doctor bcdp_http |
| 评审(JEV/Laya,外接判定服务可选) | bcdp_jev_status bcdp_jev_frame bcdp_jev_ask bcdp_jev_run bcdp_jev_attempt |
1.5.0 迁移表(旧名 → 新调用)
wait / space / escape 三族已按 op 合并,旧工具名移除(不保留别名——别名同样吃 schema 预算,等于没省)。其余工具名不变。
| 旧调用 | 新调用 |
|---|---|
bcdp_wait {ms} | bcdp_wait {op:"duration", ms} |
bcdp_wait_for_selector {selector, state, timeout} | bcdp_wait {op:"selector", selector, state, timeout} |
bcdp_wait_for_url {pattern, timeout} | bcdp_wait {op:"url", pattern, timeout} |
bcdp_wait_for_response {url, body, timeout} | bcdp_wait {op:"response", url, body, timeout} |
bcdp_wait_page {op:"load"|"function"|"request"|"event", …} | bcdp_wait 同名 op(op 取值不变,直接搬家) |
bcdp_space_open {name} | bcdp_space {op:"open", name} |
bcdp_space_close {name, keep} | bcdp_space {op:"close", name, keep} |
bcdp_cli {script} | bcdp_script {script, verbatim:true} |
op合并后各 op 的必需参数写在工具描述里;缺参会返回带 op 名的reason(如bcdp_wait: selector is required for op=selector),不会静默降级。
工具注入分级(懒注册 / 分级 / 锁定)
34 个工具全量注册时,每个会话每一轮都要为它们的 schema 付费(挂载级实测 description + parameters 序列化 = 24,631 字符 ≈ 7.1K token,1.7.0;1.5.0 曾测为 22,224,增量主要来自分级文档与工具描述互斥引导)。而不碰浏览器的会话一个也用不上。插件因此把「谁能出现在模型面前」收成一处策略(src/toolTiers.ts),分八批注入。
8 批 ≠ 8 个开关。批次是注入时机,开关是用户面(§9.3「开关与批次解耦」)。当前 4 个开关管 8 批:
toolBrowse管 act+observe+wait 三批并按波次放行,toolExtended管 power+session,toolEscape、toolJudge各管一批。所以「toolBrowse= 19 个」指的是并集上限,实际第一波只放 13 个。
| 批次 | 成员 | schema | 何时出现 |
|---|---|---|---|
| core 常驻(1) | bcdp_status | 401 | 永远在场,不可封印——它是 lazy 唯一的解锁入口 |
| act 动手(13) | space / navigate / click / fill / key / hover / scroll / select / check / drag / tab / help / doctor | 8,762 | lazy 下首次活动放第一波 |
| observe 观察(5) | screenshot / page_info / read_element / js / snapshot | 3,109 | 第二次活动 |
| wait 等待(1) | bcdp_wait(duration / selector / url / response / load / function / request / event) | 1,976 | 第三次活动 |
| power 重量级(5) | raw CDP / http / upload / download / dialog | 3,692 | 首次活动(同 toolExtended) |
| session 登录态(3) | captcha / auth_flush / login_import | 1,864 | 首次活动(同 toolExtended) |
| escape 逃生舱(1) | bcdp_script(verbatim:true = 原 cli 的裸 heredoc) | 1,484 | 首次活动(1.7.0 起不再吃活动闸豁免,见下) |
| judge 评审链(5) | bcdp_jev_* | 3,343 | 除解锁外,还要求配了 JEV 或 Laya Key |
| 合计 | 34 | 24,631 | — |
表内 schema 与合计均为 1.7.0 挂载级实测(
tests/tier-mount.test.ts的度量用例打印),八批求和 = 24,631 与全量档逐字对齐。
设置项在插件设置页最上方的「工具封印」分块(全部 volatile,翻完当场生效,不重启插件)——一个开关管一组批次,形状照 dsh-prime-memory 的「工具封印」:
toolInjectionlazy(默认:只常驻bcdp_status——它是唯一的解锁入口,其余首次bcdp_*调用后按开关注入)/always(挂载即全量,历史行为)。toolBrowse(act + observe + wait = 19)/toolExtended(power + session = 8)/toolEscape(script = 1)/toolJudge(5):开 = 开放注册,关 = 该批从模型工具列表移除。四组各自独立,封一组不波及别组;core级不给开关(封了就没了活动入口)。
1.7.0 起 escape 不再吃活动闸的例外:bcdp_script 仍是唯一能在一次调用里干完任意多步任务的入口(page / browser / taskSpaces / fetch / cdp 全预置),但它不再常驻——先调一次常驻的 bcdp_status 即可拿到它。豁免的代价是它单独占 ≈1,700 字符/轮(比收窄后的整个常驻面还大四轮),而 lazy 会话里模型本来就要先调 status。如果你需要「冷启动直接写脚本」的旧行为,设 toolInjection = always(或留在 1.6.x)。
行为要点:
- 封印 = 反注册(工具从模型的工具列表里消失),不是执行期拒绝。解锁信号挂在
bcdp_*调用的公共出口上,工具体不知道分级存在;bcdp_status/bcdp_help/bcdp_doctor自身也算活动信号(读了指南就得有工具可用)——但后两者已属 act 批,冷启动下只能靠bcdp_status触发。 - 闲置自动收回:
lazy+idleTimeoutMin > 0时,空闲回收把后台浏览器停掉的同一刻收回扩展面;下次活动重新铺开。always模式不受影响。 legacyEgoToolNames的ego_*别名跟随其bcdp_*本体的级别。- 当前注入面写在
bcdp_doctor报告首行(例:tool injection: mode=lazy browse=open extended=open escape=open judge=open judgeKey=none active=yes → live 28 / sealed 6,即一次bcdp_status+ 一次doctor之后的面),不用猜。注意doctor本身已属 act 批,要先调bcdp_status才能拿到它;冷启动时模型面上只有bcdp_status(live 1 / sealed 33)。 - 默认档下不碰浏览器的会话只有 1 个工具在场(
bcdp_status= 401 字符 ≈115 tok,较 1.5.0 的 4,978 字符 −91.9%);它是解锁入口,调用即按批次铺开其余工具。要回到历史行为把toolInjection改成always(34 件全在场需再配一个评审 Key)。 - 各档实测注入面(挂载级口径,1.7.0;序列化工具的
name + description + parameters求和,token 按 3.48 字符/token 折算):默认 1 个 / 401 字符 ≈115 tok → 首次活动(act 批 + power + session + escape)23 个 / 16,203 ≈4,660 tok → 第 2 波(+observe)与第 3 波(+wait)后 29 个 / 21,288 ≈6,120 tok → 全量(always + 评审 Key)34 个 / 24,631 ≈7,080 tok。这些数字由tests/tier-mount.test.ts的度量用例当场打印,不靠估算。 - 五个字段都带 schema
.default():volatile 字段的表单描述符直接拿 schema 默认值,不写默认会出现「面板显示 A、运行时用 B」。
取舍提醒:窄工具(一个动作一个工具)是模型写对参数、少重试的护栏。1.5.0 只合并了 wait / space / escape 三族同源冗余(41 → 34,省 1,869 字符 schema):五个 wait 共用同一 preamble 与 timeout 语义、三个 space 本就是同一个 op 工具的碎片、cli/script 是同一 heredoc 运行时。代价是这三族的旧工具名不再存在(见上方迁移表);交互原子(click/fill/key…)不合并,因为它们是模型写对参数的护栏。
任务空间命名与并发隔离(1.6.0)
默认就是会话隔离:不传
space的调用落在本会话自己的任务空间dsh-agent-<会话id前8位>,两个会话永远不会共用或抢占同一个浏览上下文。只有显式写space: 'default'(或bcdp_space op=open name='default')才会用那个跨会话共享的具名槽。
| 你怎么写 | 落到哪个空间 |
|---|---|
省略 space(默认,defaultSpace 未设 = :auto) | dsh-agent-<会话id前8位>,每会话独立 |
space: 'default' / op=open name='default' | 共享具名槽 default(此后该会话固定用它) |
defaultSpace: 'default'(配置项改成具名) | 所有会话默认都用 default(退回旧行为,全局生效) |
无 session 的调用(__global__) | default,保证向后兼容 |
defaultSpace(A):volatile 标量,留空/缺失折叠为:auto(1.6.0 起,此前折叠为default),热更新不重注册。注意区分两个概念:配置值cfg.defaultSpace(schema 里那个,可以是:auto或具名)与运行时当前会话活值cfg.activeSpace(命令实际用的useSpace(...)入参);前者是设置,后者随会话与显式选择切换。:auto派生(C)::auto在两种模式下都派生dsh-agent-<sid8>—— 空间命名与isolateSpaces(那个只管 Profile 落盘还是内存沙箱)是两条独立的轴。会话 id 会先剥掉session-前缀再取 8 位:真实 DSH id 形如session-52adc205-…,直接slice(0,8)会得到session-,让所有会话撞成同一个空间——这正是隔离失效的经典坑,已用sessionSpaceToken()修掉并有回归测试。- 会话级隔离(B):活动空间追踪器按
sessionId键控成一张槽位表(Map<string,Slot>,无 session 的调用落__global__槽保持向后兼容)。每个bcdp_*调用一进来就setCurrentSession(callingSessionId(exec)),所以并发多会话各开各的空间互不漂移——A 会话重启空间不波及 B。 - 不要再手动建编号空间:不需要
#4/#5这类手工命名,隔离已经由会话派生自动完成;需要共享就走显式default。
跨调用稳定定位(D1)
bcdp_snapshot 现在带稳定 locator:输出里每个可交互节点除了 [ref=N] 还附 loc=css:… / loc=role:… / loc:href:…。跨调用请优先用 loc= 而非 @N——@N 每次快照重新编号且其 ref 映射只活在取快照的那个子进程里,而 loc= 稳定、能跨子进程命中(bcdp_click / bcdp_fill 直接吃 loc=...)。这是插件层解法,未改内置运行时 SDK 的 ref 编号生成。
navigate 卡死自愈(F)
bcdp_navigate 包了一层 watchdog:当一次导航因页面主线程挂死而 eval 超时 / no active tab 时,先开一个空白 tab 再关掉挂死那个(顺序关键:先关会触发末-tab 守卫留下死 tab),然后重试一次,结果附 recoveredFrom(正常路径为 null)。重试硬上限一次,二次仍卡如实返回,不用反复换 tab 掩盖真错误。
观察窗怎么用
右下角 🌐 常驻小球 → 点开:
- 主画面:agent 当前页面实况;点击/拖动/滚轮直接操作页面,Ctrl+滚轮缩放视图、Ctrl+拖动平移,双击复位。点击画面后可直接键盘输入,支持中文 IME、粘贴、Tab/Enter/方向键及 Ctrl/Cmd 快捷键。
- 选择元素(点选引用):点一下工具条进入点选模式,再点实时画面里的任意元素——插件捕获其
backendNodeId/tag/id与语义描述,以[CDP-PICKS]结构化块并入对话输入框草稿;同一页面的多次点选自动合并进同一块并依次编号,agent 按编号精确取用。浮动观察球与侧边栏 Tab 均可用。 - 标签页条:顶部横排,点选切换,
×关闭。 - 历史抽屉(🕘):按时间回看访问轨迹。
- 操作时下方网址行就地显示提示,2 秒后恢复。
- 面板关闭、sidebar Tab 隐藏或组件卸载后,1.5 秒宽限结束即停止画面生产。仅把 DSH 窗口切到后台不会停止串流,避免回前台时反复重建 WGC/FFmpeg;异常关闭由 120 秒 worker lease 超时兜底。
画面后端
cdp:Page.startScreencastJPEG,默认 20 FPS。每个源帧立即按 Chrome 提供的帧 ID ACK,只保留最新待发帧;仅捕获当前观看标签,静态页恢复截图默认 3 秒一次。ffmpeg:Windows 以gfxcapture(hwnd)直接采集目标 Chrome 窗口的 D3D11 surface;其他平台使用显示来源 crop。随后编码 H.264 fragmented MP4 → HTTP 二进制 chunk → MediaSource<video>,不经过 Base64/SSE。auto:默认选择 CDP,不检测成功也不会自动下载 FFmpeg。FFmpeg 安装并通过能力检查后才可选择;已保存的 FFmpeg 后端若后来失效,本次观察会回退 CDP 并展示原因。- Windows FFmpeg 必须包含
gfxcapture。插件按 browser PID、target title 和 CDP window bounds 匹配 HWND;窗口移动或被遮挡时仍捕获目标页面,并且不允许回退到桌面录制。若 target 是同一 Chrome 窗口里的后台 tab,会明确报错而不是展示当前可见 tab 或抢用户焦点。macOS 首次使用需要“屏幕录制”权限;X11 需要 Chromium 与 FFmpeg 共享DISPLAY;Wayland 缺少 Portal/PipeWire 输入时会提示切回 CDP。
托管 FFmpeg 安装到 ~/.dsh/cache/ego-browser/ffmpeg/,不会写入插件目录。Windows/Linux 使用固定 BtbN release tag;macOS 使用固定的 ffmpeg-static GitHub release 资产(其 Intel/Apple Silicon 二进制分别来源于 Evermeet/OSXExperts)。所有下载均固定资源 SHA-256,只提取 FFmpeg 主程序,不安装 ffprobe 或 ffplay。Windows/Linux 解包使用系统 tar;缺少时会在下载前明确报错。
登录态说明:多任务空间 Cookie 相互隔离,请在对应空间内登录。重启 DSH 后运行期登录态被清空(Chrome 运行期 Cookie 仅优雅关闭时落盘),需重登——扫码很快。
工作原理
- 工具层:每个工具把参数拼成 JS 脚本,经
ctx.subprocess用ego-browser nodejs喂给 stdin 运行,宿主经 CDP 驱动共享 Chromium。结果以@@DSH_RESULT@@哨兵行解析。所有bcdp_*经进程内互斥锁串行化,错误统一归一。 - 观察窗:
lib/client.js管理 watcher lease、JPEG<img>与 MSE<video>;lib/cast-server.js代理元数据 SSE、watch API 和带背压的二进制视频;worker 中CaptureManager保证同时只有一个活动后端和一个当前 target。CDP 控制面(标签、viewport、输入、验证码)独立于画面后端。
JEV 风格管道:让 LLM 把控浏览器循环(阶段 10)
把"一帧 ≡ 截图 + 编号 DOM + 意图 + 操作进度"这个帧契约,连同"判定只回编号、绝不给选择器"的判定接缝,落地成一套可跑、可测、可归档的管道。判定由外部的 Laya / JEV 判定服务承担(见下),循环由本插件驱动。
四个工具(宿主侧 defineTool,判定请求从插件进程发 HTTP,不经过 agent 会话):
| 工具 | 干什么 | 何时用 |
|---|---|---|
bcdp_jev_status | 先跑这个:判定链可用性 + 配置体检,不发任何请求 | 怀疑配置/链路问题时第一步 |
bcdp_jev_frame | 采一帧(截图 + 编号候选 + 意图),看判定器会看到什么 | 调试帧内容、核对候选编号 |
bcdp_jev_ask | 组装请求体;dryRun 默认 true,可指定 round=control|chapter|pick|evaluate 逐级看,确认无误再发 | 想先看清楚判定请求再发 |
bcdp_jev_run | 跑整条循环,返回逐步 trace(每步的候选数 / top / 预算 / 命中) | 真要让它动手 |
默认链路是 laya → rule。JEV 目前无法注册,所以默认不写它;将来可用时把 jev 加回 judgePrefer 跳序并填 jevUrl 即可。bcdp_jev_status 在缺 key 时会主动打印本地起法(ENGINE=laya … uvicorn laya_api.main:app,端口 8000 而非 7789,ALLOW_DEV_LOGIN=true 建 key)。不可用的跳跳过不调用(laya 强制鉴权无匿名分支,缺 key 必然 401),每一跳的跳过与失败都进 trace,绝不静默回落;refuse 是结果不是异常。
三级缩小(让 LLM 把控进程,而不是一次猜全部):
control—— 要不要动手(固定 5 项:pick_button/sleep/next/prev/done);chapter—— 哪个章节(按 AX 容器聚簇,从childIds父链挑最近的结构化祖先,如form#1/form#2;单章节时此轮跳过);pick—— 章节内选哪个编号 + 一个风险度score。
分章节不是装饰:阈值按候选数分桶,把 20 选 1 拆成「几选 1 × 几选 1」会让两轮都落进更严的桶(top≥0.5 且 top−second≥0.15),比一次性 20 选 1(top≥0.6)更可控。判定器只回编号,坐标/选择器由执行层每次重新量(DOM.getBoxModel + 点击前 DOM.getNodeForLocation 命中复核),帧里的矩形绝不作为点击依据。
判定上下文是隔离的:只允许 INTENT / PROGRESS / FRAME / HISTORY 四段,绝不带 agent 会话 session 前缀;多出任何一段都在组装时直接抛错(不靠约定,靠断言)。PROGRESS(步数 / 各章节尝试与结果 / 真正成功过的动作 / 剩余预算)由循环自己机械生成,不让模型写——模型写的进度是第二难发现的幻觉通道。
评估开关 jevEvaluate(默认开,设置面板可关):每一步执行后,判定器再判一遍进度是 inprogress / done / fail。fail 或「未验真的 done」不猜下一步,而是升级为 escalate——带一组有序的 RecoveryOption(如先 reload 刷新,因为陈旧渲染会藏住已写入的确认),交回 LLM 决定恢复还是停手。
循环终止态:done(对照 successCriteria 自验)/ blocked(预算拦)/ exhausted(预算耗尽,带 exhaustedKind)/ stuck(同锚同动作连续 3 次无变化)/ unavailable(无判定器)/ error / escalate。
现状诚实记录:本阶段已证明协议、阈值、终止、分章节、组装、隔离正确(
bcdp_jev_*单测覆盖),但尚未在真实浏览器上端到端跑过(T10.22 待做);判定准确率未经实测(阈值分桶是标定用的,不是选得对的证明)。存档的被操作元素会保留class等定位特征(只剥离检视器外壳 token),供 escalate 时回传给 LLM 恢复。
开发
源码在 src/(TypeScript),构建产物在 lib/(host + client bundle)与 bin/cdp-cast-worker.mjs(worker bundle)。
pnpm typecheck # tsc 类型门禁(tsconfig.json 主 + tsconfig.client.json 客户端)
pnpm test # vitest 单元测试
pnpm run build # tsdown 三 bundle:lib/index.js + lib/client.js + bin/cdp-cast-worker.mjs
直接改
src/(src/index.ts工具层、src/client/index.ts前端、src/worker/cdp-cast-worker.tsworker)。新工具在registerActionTools里按t({...})加,并在bcdp_help索引(src/help.ts)补一条,跑pnpm typecheck && pnpm test && pnpm run build。lib/与bin/cdp-cast-worker.mjs是构建产物(预构建入库),不要手改。
node_modules/ 仅含指向 DSH checkout 的符号链接(编译期类型解析);运行时由 harness 解析 @deepseek-ai/dsh-tools。
已知限制(诚实说明)
- Windows:插件层已做 v0.4.0 适配;内置运行时的宿主对 Windows 仍以社区适配为主,复杂多步流程稳定性可能弱于 macOS。
- FFmpeg 平台捕获:Windows 已使用
gfxcapture(HWND),需要包含该 filter 的新构建;PATH 中的旧 FFmpeg 会被跳过并提示下载兼容版本。Linux 使用x11grab、macOS 使用avfoundationdisplay crop;macOS ScreenCaptureKit、Wayland Portal helper 属后续增强。 - 安装环境:本仓库的 DSH peer 包不全在公共 npm registry。普通
pnpm install可能在解析@deepseek-ai/*peer 时失败;DSH profile 安装应提供这些 peer。CDP 不依赖 FFmpeg,也不会在插件安装阶段下载二进制。 - 快照质量:Linux 用 CDP
DOMSnapshot重建语义树,非 macOS 内核级,复杂 iframe/画布场景可能降级。 - 宿主可靠性(Linux):未合并的社区 PR,跨 CLI 调用间可能丢 tab/空间状态;插件已内置防御,简单流程稳定,复杂流程可能需重试。
- 登录态持久化:Chrome 运行期 Cookie 仅优雅关闭时落盘,强杀重启需重登。
- 输出 schema 为宽松
additionalProperties: true,客户端以实际返回值为准。
许可与署名
插件本体 MIT。内置运行时嵌入第三方 MIT 代码;可选下载的 FFmpeg 构建涉及 GPL-3.0-or-later 义务。使用或再分发前请阅读构建来源的许可证与源码获取信息,来源与署名详见 THIRD_PARTY_NOTICES.md。
供应链与权限说明
为目录收录与审查提供的确定性事实:
- 运行文件:
lib/(构建产物,由npm run build从src/TypeScript 以 tsdown 确定性生成)、bin/(worker 与 ffmpeg-probe 的可执行入口脚本)、cordis.patch.yml(装配层)、dsh-plugin.json(manifest)。*.map仅为调试用 sourcemap,不参与运行,已声明排除。 - 原生/可执行工件:
runtime/内置 ego 兼容运行时(第三方 MIT,来源与逐文件清单见 THIRD_PARTY_NOTICES.md)——它是本插件的核心功能(自带受管 Chrome/CDP 宿主),属有意携带的可执行工件,非构建副产物。runtime/PATCHES.md记录对内置运行时的全部本地补丁。 - 依赖:运行时依赖仅
@deepseek-ai/schemastery(由 DSH 宿主提供对等实现);peer 依赖全部为@deepseek-ai/dsh-*宿主服务。客户端 bundle 的外部模块由宿主模块表解析,不携带 npm 运行时依赖。 - 外部服务:无遥测、无外部 API 调用。唯一的网络行为是可选的 FFmpeg 安装器按用户指令从 GitHub(或用户配置的镜像)下载构建件,来源校验与许可义务见 THIRD_PARTY_NOTICES.md。
- 失败边界:宿主无 webServer(TUI/headless)时 watch 路由安全跳过;worker 启动失败时 watch 路由返回
ok:false的 JSON 而非挂起;浏览器进程随宿主 teardown 一并终止(--stopfire-and-forget,不阻塞宿主退出)。 - 权限:manifest
permissions为空——工具集的文件读写被限定在 ego 自管的空间目录与用户工作区,网络访问经由受管的 agent 浏览器而非宿主进程。
友链
同为 DeepSeek Harness 插件生态的作品,互相安利:

