dsh-whale-browser
Verifieddsh-whale-browser · v1.0.2 · MIT
给小鲸鱼一双手:零依赖 CDP 直驱一个专用 Chromium,让 agent 像人一样读网页、点按钮、填表单、滚动、截图;每次操作先经用户授权,密码由用户自己输入。
Install
dsh plugin add dsh-whale-browser Confirm the layer applied with dsh --profile default --dump-config — see the install guide.
Source
Tags
Creators
Readme
dsh-whale-browser · 小鲸鱼的浏览器
给 DeepSeek Harness 的 agent 一双手:零依赖 CDP 直驱一个专用 Chromium, 像人一样读网页、点按钮、填表单、滚动、截图——每次操作先问用户,密码由用户自己输入。
Zero-dependency Chrome DevTools Protocol driver that gives a DSH agent a real browser: read pages, click, type, scroll and screenshot with genuine mouse/keyboard events, approval-gated per action, passwords never filled by the model.
这是什么(What it does)
dsh-whale-browser 是一个 DeepSeek Harness(DSH)宿主侧插件,它给模型接上一台"自己的浏览器"。
DSH 的 agent 本来只能靠 web_fetch 拿静态 HTML,遇到需要登录、需要点按、需要翻页的网页就无能为力。
本插件启动一个独立窗口的 Chromium(Chrome / Edge 皆可,专用 --user-data-dir,
和用户日常浏览器的登录态、插件、书签完全隔离),然后通过 Chrome DevTools Protocol 直接操作它:
- 像人一样操作:点击、输入、按键、滚动走的是 CDP 的
Input.dispatchMouseEvent/Input.dispatchKeyEvent——真实的鼠标键盘事件,页面看到的是人在操作,而不是脚本注入 DOM。 - 看得见:
browser_screenshot把页面截图作为图片直接交给模型,模型能"看着"页面核对结果。 - 读得懂:
browser_read同时返回正文文字和一张可交互元素表——每个可点的按钮/链接/输入框 带ref(如e7)、类型、名称、视口坐标,还会标出风险(🔒 密码框 / ⚠ 删除类 / ⚠ 付款类)。 - 受控:默认每一次操作都先向用户请求授权;密码框硬拒绝代填;删除/付款类元素要过第二道确认;
并通过
ctx.browserUse.register()独占 browser-use provider 槽位——同一时刻只有一套浏览器工具生效。 - 零依赖:不装 Playwright、不拉任何 npm 包,只用宿主 Node ≥22 内置的
WebSocket说 CDP。
典型用途:让 agent 替你在已登录的课程平台/后台系统里翻页汇总、在讨论区读帖、把数据抓回来; 或者反过来——你把网页内容交给它读,它给你摘要与下一步建议。
它做什么(工具一览)
| 工具 | 作用 |
|---|---|
browser_status |
本地体检(浏览器是否在跑、可执行文件、profile 路径、授权模式、槽位、围观页地址)。不访问任何网页,因此不弹授权 |
browser_open |
打开 http/https 网址;浏览器没启动会先启动;可等某段文字出现再返回 |
browser_tabs |
列出标签页(序号 / 标题 / 地址 / id) |
browser_read |
读正文 + 可交互元素表:ref、类型、名称、视口坐标、风险标记 |
browser_click |
按 ref 定位(必要时滚进视口)后派发真实鼠标按下/抬起;也可直接点 x,y |
browser_type |
先真实点击聚焦,再逐字符敲键盘;可选先清空、末尾回车 |
browser_key |
Enter / Tab / Escape / Backspace / Delete / Space / 方向键 / Home / End / PageUp / PageDown,可带 Ctrl/Shift/Alt |
browser_scroll |
真实滚轮事件(up/down 按屏,top/bottom 用 Ctrl+Home / Ctrl+End) |
browser_screenshot |
截图并把图片交给模型(可整页长图) |
browser_close |
只关它自己启动的浏览器实例(登录态保留在专用 profile 里) |
权限与安全模型
- 每次操作都先问(默认
approval: every)。工具在获得允许前不会碰页面;被拒绝就停下来说明原因。 授权提示会带上当前站点、元素 ref、输入内容(截断显示)以及是否会按回车提交。 - 密码永远是你的事。对
type=password的输入请求会被硬拒绝,模型会停下来请用户接手; 元素表里也会把密码框标成 🔒。 - 危险动作二次确认。点击「删除/移除/注销」「付款/下单/转账/订阅」这类元素时,
除了工具级授权,还会再发一次明确说明的确认请求;拿不到确认就拒绝执行。
按坐标点击(
x/y)也会先用document.elementFromPoint识别目标元素,再走同一套风险判定。 - 授权缓存绑站点,不绑标签页。
per-origin以 URL 的 origin 为键:同一标签页跳到别的站点会重新询问;session每个会话只问一次(不按标签页或读写类别拆分)。只有执行成功、且执行后仍是同一 origin 才会记录授权, 防止“点一下跳到新站,旧授权被记到新站名下”。 - 网页内容不受信。页面正文、元素名、弹窗、截图里的任何指令都只是数据,模型不会执行; 一切以用户的要求和判断为准(这条写进了给模型的系统提示,也在工具说明里重申)。
- 围观页不给网页内容执行权。动作流水用
textContent渲染(不再拼innerHTML),脚本单独走/app.js, 页面带 CSP(script-src 'self'、default-src 'none')与nosniff——网页里带 HTML 的元素名/输入文本只会当纯文本显示。 - 只碰自己启动的浏览器。专用
--user-data-dir(默认~/.dsh/whale-browser/profile)与随机调试端口, 不读取、不附着、不关闭你日常使用的 Chrome/Edge。浏览器子进程启动即unref(),插件卸载/宿主退出时不会把它 留在事件循环里(桌面更新器只等 10 秒,这一点很关键);browser_close关闭失败会明确报错,而不是谎报成功。 - 主机名单。
blockedHosts永远拒绝;allowHosts非空时只允许名单内主机。 - 独占槽位。
ctx.browserUse.register('whale-chromium')——与官方实验性 browser-use provider 天然互斥, 不会两套浏览器工具抢同一个页面。 - 零第三方依赖,不注册 Client 槽位,不读写其他插件的 DOM 或配置。
安装
方式一:DSH 插件页(推荐)
在「设置 → 插件」的安装输入框里填包名 dsh-whale-browser(或 dsh-whale-browser@latest),确认安装,
然后重启应用。
方式二:git 仓库地址
dsh plugin --profile web add github:yook0ng/dsh-whale-browser
方式三:本地目录(开发调试)
dsh plugin --profile web add link:dsh-whale-browser
配置改在 cordis.patch.yml 的 config 段(见下表)。改完代码必须重启应用才会加载新的模块代际。
卸载:从 profile 的 dsh.profile.bundles 移除 dsh-whale-browser 并 pnpm remove dsh-whale-browser,
或在插件管理界面直接移除。
配置(cordis.patch.yml 里的 config)
| 键 | 默认 | 说明 |
|---|---|---|
approval |
every |
every 每次问 / per-origin 每个站点问一次(跨站跳转重新问) / session 每个会话问一次 |
browserPath |
空 | 留空自动探测 Chrome / Edge |
headless |
false |
true 无头运行(看不到窗口) |
profileDir |
~/.dsh/whale-browser/profile |
专用用户数据目录:登录态只存在这里 |
width / height |
1280 / 900 | 窗口与视口尺寸 |
maxTextChars |
12000 | 单次读取的正文字符上限 |
maxElements |
150 | 单次元素表条数上限 |
allowHosts / blockedHosts |
[] |
主机白/黑名单 |
claimExclusiveSlot |
true |
是否独占 browser-use provider 槽位 |
liveView / liveViewPort |
true / 0 |
127.0.0.1 上的实时围观页,端口 0 = 随机 |
closeOnUnload |
false |
插件卸载时是否顺手关掉浏览器。不论开关,卸载都会断开 CDP 并释放事件循环(子进程 unref),不会阻塞宿主退出 |
围观页
插件在 http://127.0.0.1:<随机端口>/ 上开一个小页面:实时画面 + 最近 40 条动作流水。
地址见 browser_status 输出——可以直接贴在 DSH 侧边栏的浏览器标签里,一边看模型操作一边干活。
页面脚本单独走 /app.js,动作流水只用 textContent 渲染;响应头带 Content-Security-Policy
(default-src 'none'; script-src 'self')与 X-Content-Type-Options: nosniff,网页带来的任何 HTML 都不会在围观页执行。
系统要求
- DeepSeek Harness 桌面版(宿主能拿到桌面浏览器可执行文件);
dsh web亦可,只要宿主进程能启动浏览器。 - 本机装有 Chrome 或 Edge(Windows/macOS/Linux 常见路径已内置探测,可用
browserPath指路)。 - 宿主 Node ≥ 22(插件用内置
WebSocket说 CDP,不装任何 npm 依赖)。 - 已实测环境:Windows 11 + Chrome 155 + DSH 桌面版(Node 24 宿主)。
已知限制
- 浏览器窗口被其他窗口完全遮住时,Windows 的原生遮挡检测会让页面进入
hidden,Chromium 会丢弃鼠标与键盘事件。 插件为此做了两层防护:启动带--disable-features=CalculateNativeWinOcclusion等标志,操作前还会检查document.visibilityState,必要时用Page.bringToFront把窗口切到前台;实在不可见就明确报错,绝不假装成功。 - 页面内容属于外部不受信数据:模型只把它当资料读,不执行页面里的指令。
- 不支持
file:/data:等非 http(s) 地址;下载与浏览器权限请求沿用 Chrome 默认策略,插件不代批。
设计取舍:为什么不去驱动 DSH 侧边栏的那个网页
本插件最初的设想是"操作右侧栏标签页里的网页"。核实 DSH 内核后确认这条路在插件层走不通:
- 侧边栏浏览器是渲染进程里的 Electron
<webview>guest,其租约、挂载与权限策略由桌面主进程掌管; 而 Harness 宿主(插件运行的地方)是主进程spawn出去的子进程,拿不到webContents。 - 宿主 → 客户端的推送通道对第三方插件不开放:
ctx.remote.$on的合法键集由应用在构建期固定,registerRemoteEvents的应用事件源由dsh-api-remotes独占;只有动态双半包才有host.call。 - 侧边栏浏览器自述「不注册工具、内容不进模型请求」,即官方刻意不让它被自动化。
因此本插件改用生态里给 browser-use 预留的正规位置:独占 provider 槽位 + 自己驱动一个真实 Chromium。 登录由用户在自己的窗口里完成一次(profile 持久化,比侧边栏 guest 的内存分区还稳), 模型的每一次操作仍然逐次申请权限。
License
MIT © 2026 Junze Wu