dsh-plugin-browserskill
Tencent/BrowserSkillBrowserSkill 的 DeepSeek Harness 浏览器自动化桥接插件,通过原生浏览器工具控制可见的 Chrome 和 Edge Agent Window,支持可访问性与 VOM 页面观察、截图、隔离的多会话控制和 Web UI 实时观察浮层。
新增「浏览器操作」Agent 预设(基于 Playwright MCP 工具集的导航、填表、点击与截图规程),并加门禁:其他预设里的浏览器工具调用一律拒绝,直到用户通过内置的 browser_access 工具授权该会话。插件自带 Playwright MCP provider,插件页的设置页与 browser_source 工具都能在运行时把浏览器来源切换为 Microsoft Edge(默认)、Playwright 内置 Chromium 或 CDP 地址。需在 profile 里保留共享的 browser-use 注册表行(一个进程只能有一个 provider)。
中文 | English
DeepSeek Harness(DSH)插件包:新增一个「浏览器操作」会话模式,浏览器来源可在运行时切换(默认 Edge),其它会话在用户明确同意前无法打开浏览器。
依赖对齐 DSH 0.2.1-rc.3(Windows 11 + Edge)。
headless: false,能看着它操作,也能随时接管。permission denied。DSH 插件管理器的安装框接受 git 地址。把下面这一行粘贴到「包名或地址」:
github:Shad0wwa1ker/dsh-browser-mode等价的工具调用:
plugin_manager install_bundle target:github:Shad0wwa1ker/dsh-browser-mode安装会写入 profile 依赖 "@local/dsh-browser-mode": "github:Shad0wwa1ker/dsh-browser-mode",并自动启用包内三行:预设 preset-browser、来源 browser-source、门禁 browser-gate。
在 $DSH_PROFILE_DIR/cordis.patch.yml 里保留共享的 browserUse 注册表行(若已存在则跳过):
- insert:
- id: browser-use
name: "@deepseek-ai/dsh-browser-use"Playwright MCP provider 由本插件的 browser-source 行负责挂载,不需要单独的 provider 行。这样浏览器来源才能在运行时切换。
[!IMPORTANT]
从 1.5.1 或更早版本升级:请删掉browser-use-playwright-mcp那一行(browser-use保留)。一个进程里只能有一个 provider;旧行还在时browser-source只打印一条迁移提示,不会接管。
插件市场对 github:owner/repo 这种浮动源会读取仓库默认分支的 package.json 版本号做比较,所以每次发版只要改版本号并 push:
git tag v1.6.0
git push && git push --tags已安装的用户在插件市场点「更新」,或手工执行下面两条(pnpm 会把 GitHub 依赖重新解析到默认分支最新提交):
pnpm add "github:Shad0wwa1ker/dsh-browser-mode"plugin_manager set_bundle enabled:false target:@local/dsh-browser-mode
plugin_manager set_bundle enabled:true target:@local/dsh-browser-modeplugin_manager list_pluginsinclude:preset-browser、include:browser-source、include:browser-gate 三行都应是 enabled: true、fiberPhase: "active"。
方式一:浏览器模式会话(整段网页任务)
新建会话时把模式选为「浏览器操作」。该会话内模型直接调用 browser_navigate 等工具,不再询问。
方式二:当前会话里申请
直接说「用浏览器打开这个页面并填好」。模型第一次调用浏览器工具时会被拦下,随后调用 browser_access,界面弹出:
允许使用浏览器
是否允许我在这个会话里打开浏览器?用途:……
[允许] [不允许]点「允许」后,该会话后续的浏览器调用全部放行;点「不允许」,模型改用 web_search、web_fetch、文件与命令行继续。
默认用 Microsoft Edge。三种来源:
source · 行为 edge · 启动本机 Edge(找不到时退回 Playwright 内置 Chromium) builtin · 启动 Playwright 自带的 Chromium(~/AppData/Local/ms-playwright/chromium-*) endpoint · 连接一个已经启动、开了调试端口的浏览器(--cdp-endpoint),此时独占,多会话不能共用
「插件」页里本插件卡片上的设置页可以直接选来源、填 CDP 地址、改 Edge 路径、切换无头,保存后立即生效(和工具一样,已打开会话的浏览器工具会失效)。这个页面与 browser_source 工具读写同一份配置,两种方式可以混用。
在任意会话里说「换成内置浏览器」「连接我开着的浏览器」,模型会调用 browser_source:
browser_source({ source: "builtin" })
browser_source({ source: "endpoint", endpoint: "http://127.0.0.1:9222" })不带参数时只回显当前配置。切换会立刻重挂 provider:已经打开的浏览器会话里的工具会失效,请新开一个「浏览器操作」会话再打开页面。
切换结果保存在 $DSH_PROFILE_DIR/browser-source.json(Windows 上是 %USERPROFILE%.dsh\profiles\\browser-source.json)。用文件而不是 Loader 配置,是因为重装或管理插件时 Loader 的配置文档会被重写,而这个文件不会。删除它即回到默认(Edge)。
也可以在 profile 的 cordis.patch.yml 里覆盖本行:文件里记录着写入时的行配置快照,你事后手改过的字段优先,没改过的字段继续用文件里的选择(用 browser_source 切换会刷新快照)。
- id: browser-source
name: "@local/dsh-browser-mode/browser-source"
config:
source: builtin # edge | builtin | endpoint
endpoint: "" # source=endpoint 时必填
executablePath: "" # source=edge 时可自定义路径
headless: false接远程浏览器时,先让浏览器以调试端口启动,例如:
& "C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe" --remote-debugging-port=9222 --user-data-dir="$env:TEMP\edge-cdp"把 provider 塞进预设的三条路都试过,全部失败:
做法 · 结果 provider 行放进预设 · 加载报错 Preset services require isolate realms: browserUse 放进 isolate: { browserUse: true } 组 · 预设能加载,但 provider 收不到 agent/created,会话里没有 browser_* 工具 预设里再挂一个 provider · 与 profile 的那个重名,调用时报 playwright-mcp: browser tool belongs to another Session
所以 provider 只能挂在 profile 层。本插件用 browser-source 这一行代挂,好处是:provider 的启动参数由插件自己算,改来源时销毁旧 fiber 再挂新的,不用重启 DSH。代价是 provider 会给每个会话注册浏览器工具,所以需要门禁。
@deepseek-ai/dsh-tools 的 tools.restrict() 只过滤一个作用域继承来的工具(全局层与祖先层):
Restrictions filter what a scope inherits … never what its OWN layer registers.
而 provider 用 createScope(ctx, agent) 把工具注册进该 Agent 自己的层,任何 restrict() 都过滤不到(实测:普通会话仍能看到 24 个 mcp__playwright-mcp__* 工具名)。
唯一有效的杠杆是 tools.guard():它在调用管线里同步执行,返回字符串即拒绝,且没有监听器能把拒绝改回放行。
决策顺序:
浏览器工具调用
├─ 名字不以 mcp__playwright-mcp__ 开头 → 不处理
├─ 是 browser_access → 不处理
├─ Agent 的预设是 browser → 放行
├─ Agent 已被用户授权 → 放行
└─ 其它 → 返回中文拒绝语browser_access 调用 ctx.userQuestions.ask({ questions, agent, signal });用户选「允许」后,把该 Agent 的 id 记进插件内存的 Set。不落盘,不跨会话,不跨重启。
browser-source,bundle 内)字段 · 默认 · 说明 source · edge · edge / builtin / endpoint endpoint · 空 · source: endpoint 时连接的目标地址 executablePath · 空 · 自定义浏览器路径;空则用 Edge 默认安装位置 headless · false · 改为 true 则隐藏窗口,调试时建议保持可见
browser-gate.js 顶部常量:
const TOOL_PREFIX = 'mcp__playwright-mcp__' // provider 的工具前缀
const BROWSER_PRESET = 'browser' // 直接用浏览器的预设 id
const ACCESS_TOOL = 'browser_access' // 申请授权用的工具名
const DENIED = '……' // 拒绝时给模型看的文字改 preset-browser 的 id 时,BROWSER_PRESET 必须一起改,否则门禁永远不认这个模式。
browser_source({ source: "builtin" }):下一次打开页面应换成 Playwright 自带 Chromium。现象 · 原因 · 处理 预设列表里没有「浏览器操作」 · bundle 未启用或预设行失败 · 看 list_plugins 里 include:preset-browser 是否 active 加载报 Preset services require isolate realms: browserUse · provider 行被放进了预设 · 把 provider 留在 profile 层,由 browser-source 挂载 会话里完全没有 browser_* 工具 · browser-source 未 active,或旧 browser-use-playwright-mcp 行还在 · 看 include:browser-source;删掉旧 provider 行后重载 报 browser tool belongs to another Session · 一个进程里有两个 Playwright provider · 只保留 browser-source 这一个 切换来源后浏览器没变 · 旧会话持有旧的 MCP 连接 · 在会话里重新调用一次浏览器工具 普通会话能直接开浏览器 · 门禁未生效 · 看 include:browser-gate 是否 active;改过代码需重载 点「允许」没反应,或报 human interaction is unavailable · 在子 Agent 里调用 · 授权只能在主会话完成 报 content.some is not a function · 旧版 browser_access 的 output.render 返回值不合规 · 升级到 ≥ 1.5.1 browser_source 一直 pending (waiting for service: browserUse),或安装时报这句话 · profile 里的 @deepseek-ai/dsh-browser-use 与当前 DSH 版本不一致,启动时被兼容性检查置为 disabled · 把 profile 里该依赖升到与 DSH 相同的版本,重启后重试
0.2.1-rc.3、Windows 11、Edge。@deepseek-ai/dsh-browser-use、@deepseek-ai/dsh-experimental-browser-use-playwright-mcp 与 @deepseek-ai/schemastery,版本在 package.json 中声明;DSH 升级后同步调整。@deepseek-ai/dsh-browser-use 的版本必须和 DSH 运行时一致:profile 兼容性检查会把 peer 与运行时不符的行直接置为 disabled,该行一被禁用,browserUse 服务就没人提供,browser-source 会一直 pending。tools.guard()、tools.register()、agentPresets.composedPreset()、sessionProjections.stateOf()、userQuestions.ask()。其中任何一个改名,browser-gate 会掉出 active,此时浏览器恢复为所有会话可用(门禁失效但不会破坏会话),升级后请重跑验证清单。settings.update() 写 volatile 字段 + loader/volatile-update 事件;DSH 去掉 volatile 通道时,切换会退化为报错并提示手工改 YAML(浏览器本身不受影响)。mcp__playwright-mcp__* 工具名,只是调用会被拒绝。browser_access,而不是切模式。