在 DeepSeek Harness 里操作 Windows 桌面应用和 Chromium 标签页。 基于 Codex…
数据截至 2026/9/20 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
dsh plugin --profile web add wushi2333/dsh-computer-use_codex-style状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
安装兼容性检查⚠ 装前注意npm 同名包「dsh-computer-use」归属 988hj7tczd-oss/dsh-computer-use,装到的可能不是本插件
展开查看检查明细 ↓
以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。
验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/11/1 16:37:29
安全扫描自动 · 静态分析源码v2.7.0🔵 扫描:含敏感能力尚无人工评估展开查看扫描说明与证据 ↓
静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。
查看扫描证据(共 78 处,展示前 77 条)
- 发起网络请求src/index.js:306
const payload = await this.sidecar.request('health') - 发起网络请求src/index.js:339
return this.sidecar.request('tools', { surface: surface || this.config.surface }) - 发起网络请求src/index.js:346
return this.sidecar.request('prompt') - 发起网络请求src/index.js:362
return this.sidecar.request('call', { name, arguments: arguments_ || {}, meta: meta || {} }, signal) - 发起网络请求src/index.js:369
return this.sidecar.request('interrupt') - 发起网络请求src/index.js:403
return this.sidecar.request('cancel', {}) - 发起网络请求src/tool.js:785
const outcome = await service.request(request) - 执行外部命令来自配置/变量src/sidecar.js:509
const child = spawn(exe, args, { - 执行外部命令来自配置/变量src/sidecar.js:549
const child = spawn(command, args, { - 发起网络请求src/sidecar.js:702
return this.request(method, params, signal) - 发起网络请求computer_use/chrome_extension/background.js:23
const res = await fetch(url); - 发起网络请求computer_use/chrome_extension/background.js:73
const res = await fetch(targetUrl, { credentials: "include" }); - 发起网络请求computer_use/chrome_extension/background.js:98
await fetch(`${base}/ingest`, { - 发起网络请求computer_use/chrome_extension/background.js:108
const pending = await fetch(`${base}/pending`).then((r) => r.json()); - 发起网络请求computer_use/chrome_extension/background.js:116
await fetch(`${base}/ingest`, { - 执行外部命令来自配置/变量parity/atomic-cursor-check.mjs:13
const c = spawn(EXE, ['--parent-pid', '0'], { stdio: ['pipe', 'pipe', 'pipe'] }) - 执行外部命令固定命令parity/atomic-cursor-check.mjs:22
const probe = () => { try { return execFileSync('pwsh', ['-NoProfile', '-File', repoRoot + '\\parity\\probe-cursor-z.ps1', String(myPid)], { encoding: - 执行外部命令来自配置/变量parity/ax-rich-parity.mjs:64
this.c = spawn(exe, ['--parent-pid', String(process.pid)], { stdio: ['pipe', 'pipe', 'pipe'], env }) - 执行外部命令固定命令parity/ax-rich-parity.mjs:92
execFileSync('pwsh', args, { stdio: 'ignore', timeout: 15000 }) - 执行外部命令来自配置/变量parity/check-fix1.mjs:19
this.c = spawn(EXE, ['--parent-pid', '0'], { stdio: ['pipe', 'pipe', 'pipe'] }) - 执行外部命令来自配置/变量parity/cursor-test.mjs:21
this.c = spawn(EXE, ['--parent-pid', '0'], { stdio: ['pipe', 'pipe', 'pipe'] }) - 执行外部命令来自配置/变量parity/cursor-trace.mjs:18
this.c = spawn(EXE, ['--parent-pid', '0'], { stdio: ['pipe', 'pipe', 'pipe'] }) - 执行外部命令固定命令parity/cursor-trace.mjs:37
const out = execSync('powershell -NoProfile -Command "Add-Type -AssemblyName System.Windows.Forms; $p=[System.Windows.Forms.Cursor]::Position; \"$($p. - 执行外部命令固定命令parity/cursor-trace.mjs:70
const out = execSync('pwsh -NoProfile -ExecutionPolicy Bypass -File repoRoot + "/parity/screen-shot.ps1" repoRoot + "/parity/full-screen.png"', { enco - 执行外部命令来自配置/变量parity/dcomp-selftest.mjs:14
const c = spawn(EXE, ['--parent-pid', '0'], { stdio: ['pipe', 'pipe', 'pipe'], env: { ...process.env, DSH_CU_OVERLAY_SELFTEST: '1' } }) - 执行外部命令固定命令parity/dcomp-selftest.mjs:36
console.log(execSync('pwsh -NoProfile -ExecutionPolicy Bypass -File repoRoot + "/parity/pill-probe.ps1"', { encoding: 'utf8' }).trim()) - 执行外部命令来自配置/变量parity/diag-affinity.mjs:13
const c = spawn(EXE, ['--parent-pid', '0'], { stdio: ['pipe', 'pipe', 'pipe'] }) - 执行外部命令来自配置/变量parity/diag-coords.mjs:13
const c = spawn(EXE, ['--parent-pid', '0'], { stdio: ['pipe', 'pipe', 'pipe'] }) - 执行外部命令来自配置/变量parity/diag2.mjs:13
const c = spawn(EXE, ['--parent-pid', '0'], { stdio: ['pipe', 'pipe', 'pipe'] }) - 执行外部命令来自配置/变量parity/fresh-test.mjs:18
this.c = spawn(EXE, ['--parent-pid', '0'], { stdio: ['pipe', 'pipe', 'pipe'] }) - 执行外部命令来自配置/变量parity/golden-ax.mjs:33
this.c = spawn(exe, ['--parent-pid', String(process.pid)], { stdio: ['pipe', 'pipe', 'pipe'], env }) - 执行外部命令来自配置/变量parity/hold-overlay.mjs:13
const c = spawn(EXE, ['--parent-pid', '0'], { stdio: ['pipe', 'pipe', 'pipe'] }) - 执行外部命令固定命令parity/interactive-physical.mjs:27
return execSync( - 发起网络请求parity/interactive-physical.mjs:82
sidecar.request('call', { name, arguments: args || {}, meta: meta || {} }) - 发起网络请求parity/interactive-physical.mjs:121
const diag = await sidecar.request('diagnostic_state', {}) - 执行外部命令固定命令parity/interactive-physical.mjs:136
execSync('pwsh -NoProfile -ExecutionPolicy Bypass -File repoRoot + "/parity/inject-key.ps1"', { - 发起网络请求parity/interactive-physical.mjs:218
const diag0 = await sidecar.request('diagnostic_state', {}) - 执行外部命令固定命令parity/interactive-physical.mjs:232
const out = execSync( - 发起网络请求parity/interactive-physical.mjs:252
diag = await sidecar.request('diagnostic_state', {}) - 执行外部命令固定命令parity/interactive-physical.mjs:349
try { execSync('taskkill /IM notepad.exe /F', { stdio: 'ignore' }) } catch {} - 执行外部命令来自配置/变量parity/interrupt-marker.mjs:29
this.c = spawn(EXE, ['--parent-pid', String(process.pid)], { stdio: ['pipe', 'pipe', 'pipe'] }) - 执行外部命令来自配置/变量parity/motion-curve.mjs:43
this.c = spawn(EXE, ['--parent-pid', '0'], { stdio: ['pipe', 'pipe', 'pipe'] }) - 执行外部命令固定命令parity/overlay-lifecycle.mjs:30
const psfile = (f, args) => execSync('pwsh -NoProfile -ExecutionPolicy Bypass -File "' + f + '" ' + (args || ''), { encoding: 'utf8' }) - 执行外部命令来自配置/变量parity/overlay-lifecycle.mjs:31
const targetProc = spawn(TARGET, [], { stdio: 'ignore' }) - 执行外部命令来自配置/变量parity/overlay-lifecycle.mjs:35
this.c = spawn(EXE, ['--parent-pid', '0'], { stdio: ['pipe', 'pipe', 'pipe'] }) - 执行外部命令固定命令parity/pill-capture-mask.mjs:58
const [count, width] = String(execFileSync('pwsh', ['-NoProfile', '-Command', SCREEN_ACCENT], { encoding: 'utf8' })).trim().split(/ +/) - 执行外部命令固定命令parity/pill-capture-mask.mjs:71
return Number(String(execFileSync('pwsh', ['-NoProfile', '-Command', ps], { encoding: 'utf8' })).trim()) - 执行外部命令来自配置/变量parity/pill-capture-mask.mjs:76
this.child = spawn(exe, ['--parent-pid', '0'], { - 执行外部命令固定命令parity/pill-capture-mask.mjs:113
const bounds = String(execFileSync('pwsh', ['-NoProfile', '-Command', - 执行外部命令固定命令parity/pill-capture-mask.mjs:119
return String(execFileSync('pwsh', ['-NoProfile', '-File', path.join(pluginRoot, 'parity', 'move-target.ps1'), - 执行外部命令来自配置/变量parity/pill-probe.mjs:18
this.c = spawn(EXE, ['--parent-pid', '0'], { stdio: ['pipe', 'pipe', 'pipe'] }) - 执行外部命令固定命令parity/pill-probe.mjs:53
const out = execSync('pwsh -NoProfile -ExecutionPolicy Bypass -File repoRoot + "/parity/pill-probe.ps1"', { encoding: 'utf8' }) - 执行外部命令固定命令parity/pill-reshow.mjs:53
const [count, width] = String(execFileSync('pwsh', ['-NoProfile', '-Command', COUNT], { encoding: 'utf8' })).trim().split(/ +/) - 执行外部命令来自配置/变量parity/pill-reshow.mjs:59
this.child = spawn(exe, ['--parent-pid', '0'], { - 执行外部命令来自配置/变量parity/probe.mjs:13
const child = spawn(EXE, ['--parent-pid', '0'], { stdio: ['pipe', 'pipe', 'pipe'] }) - 执行外部命令固定命令parity/sidecar-observe-act.mjs:43
try { execFileSync('pwsh', ['-NoProfile', '-Command', 'Get-Process dsh-computer-use -ErrorAction SilentlyContinue | Stop-Process -Force'], { stdio: 'i - 执行外部命令固定命令parity/sidecar-observe-act.mjs:48
running = execFileSync('pwsh', ['-NoProfile', '-Command', "if (Get-Process ParityTarget -ErrorAction SilentlyContinue) { 'yes' } else { 'no' }"], { en - 执行外部命令来自配置/变量parity/sidecar-observe-act.mjs:51
const proc = spawn(repoRoot + '/parity/ParityTarget.exe', [], { stdio: 'ignore', detached: true }) - 执行外部命令固定命令parity/sidecar-observe-act.mjs:55
try { execFileSync('pwsh', ['-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', repoRoot + '/parity/raise-target.ps1'], { stdio: 'ignore' }) } catch - 发起网络请求parity/sidecar-wire.mjs:30
await sidecar.request('health') - 发起网络请求parity/sidecar-wire.mjs:34
await sidecar.request('tools', { surface: 'computer' }) - 发起网络请求parity/sidecar-wire.mjs:35
await sidecar.request('cancel', {}) - 执行外部命令来自配置/变量parity/smoke-axdiff.mjs:17
const child = spawn(EXE, ['--parent-pid', '0'], { stdio: ['pipe', 'pipe', 'pipe'] }) - 执行外部命令来自配置/变量parity/smoke-diff-seq.mjs:15
const child = spawn(EXE, ['--parent-pid', '0'], { stdio: ['pipe', 'pipe', 'pipe'] }) - 执行外部命令来自配置/变量parity/smoke-twocell.mjs:19
this.child = spawn(EXE, ['--parent-pid', '0'], { stdio: ['pipe', 'pipe', 'pipe'] }) - 执行外部命令来自配置/变量parity/tmp-activate-diag.mjs:14
const c = spawn(EXE, ['--parent-pid', '0'], { stdio: ['pipe', 'pipe', 'pipe'] }) - 执行外部命令来自配置/变量parity/tmp-click-diag.mjs:14
const c = spawn(EXE, ['--parent-pid', '0'], { stdio: ['pipe', 'pipe', 'pipe'] }) - 执行外部命令来自配置/变量parity/tmp-fg-diag.mjs:14
const c = spawn(EXE, ['--parent-pid', '0'], { stdio: ['pipe', 'pipe', 'pipe'] }) - 执行外部命令来自配置/变量parity/tmp-first-click.mjs:14
const c = spawn(EXE, ['--parent-pid', '0'], { stdio: ['pipe', 'pipe', 'pipe'] }) - 执行外部命令来自配置/变量parity/window-states.mjs:21
this.c = spawn(EXE, ['--parent-pid', '0'], { stdio: ['pipe', 'pipe', 'pipe'] }) - 执行外部命令固定命令parity/window-states.mjs:38
const ps = (script, args) => execSync('pwsh -NoProfile -ExecutionPolicy Bypass -File repoRoot + "/parity/' + script + '" ' + (args || ''), { encoding: - 执行外部命令固定命令parity/window-states.mjs:92
execSync( - 执行外部命令固定命令parity/window-states.mjs:97
try { execSync('taskkill /IM notepad.exe /F', { stdio: 'ignore' }) } catch {} - 发起网络请求src/smoke.mjs:14
const health = await sidecar.request('health') - 发起网络请求src/smoke.mjs:16
const listed = await sidecar.request('tools', { surface: 'computer' }) - 发起网络请求src/smoke.mjs:22
const browser = await sidecar.request('tools', { surface: 'browser' }) - 发起网络请求src/smoke.mjs:27
const shot = await sidecar.request('call', {
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
@deepseek-ai/cordis@deepseek-ai/dsh-tools@deepseek-ai/dsh-system-prompt@deepseek-ai/dsh-user-approval@deepseek-ai/dsh-attachment@deepseek-ai/schemastery给这个插件打分还没有人投票↓
功能亮点
- Esc中断与按应用审批
展开完整介绍(122 字)↓
DeepSeek Harness 的 Codex 风格 Computer Use:官方 window2 13 方法桌面接口加 Chromium 自动化,可见浮层支持 Esc 中断、按应用审批和内置技能。Windows,MIT,无需 Codex。
README
由 DeepSeek 最新模型翻译生成展开完整文档(README 剩余 1 节)
Computer Use for DeepSeek Harness
在 DeepSeek Harness 里操作 Windows 桌面应用和 Chromium 标签页。 基于 Codex 的 window2 工具面 —— DeepSeek Harness 上的 Codex 风格 Computer Use 体验。
截至本插件发布时,官方 harness 已在实验版本中推出 Computer Use,设计上有明显差异。本插件可安全共存:两者能并排安装,但不建议同时运行两个驱动。
目录
- 你能得到什么
- 快速开始
- 工作原理
- 工具面
- 操作与刷新循环
- 安全模型
- 体验层
- 配置
- 浏览器自动化
- 验证
- 从源码构建
- 仓库结构
- 故障排查
- 安全与隐私
- 兼容性与已知缺口
- 许可与署名
你能得到什么
| 完整的 Codex 工具面 | 官方 Codex window2 的全部 13 个方法 —— list_windows、get_window、list_apps、launch_app、get_window_state、click、press_key、type_text、scroll、set_value、drag、perform_secondary_action、activate_window —— 名称、参数、默认值、返回结构和错误字符串都与 Codex 一致。 |
| 真实输入,真实截图 | 输入用 SendInput,无障碍树用 UI Automation,截图用 Windows.Graphics.Capture,窗口被遮挡也能截到。截图以视觉图像块的形式送达,绝不以 base64 塞进 JSON。 |
| 可见、可取消的浮层 | 一个状态胶囊,加一个带动画的合成光标。每次截图期间胶囊都会隐藏,这样模型不会把自己状态胶囊读回去,而你始终能看到它。Esc 随时打断当前轮次。 |
| 对照真实实现验证过 | 行为以官方插件及其 helper 为基准:AX 树语法、浮层像素、光标运动、截图新鲜度、传输预算、审批字符串、轮次生命周期。 |
| Harness 原生,而非 MCP 形态 | DSH 工具自带技能,不是 JavaScript REPL。插件是 DSH bundle:package.json + cordis.patch.yml + 包根目录下的入口模块。 |
| 两个平面,一个 sidecar | 桌面是进程级的,所以指针、覆盖层、捕获和审批都放在 HOST 平面;面向模型的工具放在智能体预设里,因此普通编码会话永远碰不到鼠标。 |
| 经验层 | 任务结束后写下本机专属笔记,下一个任务开始前作为参考上下文回放——见经验层。 |
快速开始
环境要求
| 操作系统 | Windows 10 1809+ 或 Windows 11,x64 |
| Harness | DeepSeek Harness(源码检出或已安装的 dsh 命令行) |
| Node | 20 或更高 |
| Python | 3.10+ —— 仅用于可选的浏览器目录;13 个桌面工具是 Rust + Node |
| Rust | 仅在你重新构建 helper 时需要(helper-rs/bin/win32-x64/ 里已附带 release 二进制) |
1. 安装 bundle
from GitHub (no build step, no install-time script)
dsh plugin --profile web add github:wushi2333/dsh-computer-use_codex-style
from a local checkout
dsh plugin --profile web add /path/to/dsh-computer-use_codex-style
from a packed tarball
dsh plugin --profile web add ./dsh-computer-use-0.1.0.tgz
bundle 声明了 dsh.bundle.patch,所以 dsh plugin 会把 HOST 平面那一行加进配置档,并链接该包。插件是纯 ESM JavaScript 加一个预构建 helper,因此不带 prepare 或 postinstall 脚本——pnpm 永远不会让你允许构建。
2. 把工具行加进智能体预设
桌面工具刻意放在智能体预设里,而不是 host 组合里。挑一个你想交出鼠标的预设,往它的 agent.cordis.yml 加一行(预设位于 $DSH_HOME/.agent-presets/<name>/):
Computer Use tools consume the HOST dshComputerUse sidecar. They publish
nothing, so they sit loose like tool-bash. Install the dsh-computer-use
bundle in the profile first; otherwise this row waits for the service.
- id: tool-computer-use
name: dsh-computer-use/tool
config:
surfaces:
- computer
browserSkill: computer-use-browser
如果你愿意,也可以给 Computer Use 单独留一个预设:用 standard 预设启动的会话就保持正常工具集,永远不碰你的鼠标。
3. 交付技能
两个技能随包发布,会被复制到 harness 读取的技能根目录:
from the profile directory
node node_modules/dsh-computer-use/scripts/sync-skills.mjs --write --defaults
verify the copies later (reports drift, writes nothing)
node node_modules/dsh-computer-use/scripts/sync-skills.mjs --check --defaults
4. 重启并运行重启配置档(插件平面的改动在启动时读取),用你的 Computer Use 预设启动会话,然后提一个具体的需求:
打开 Notepad,把这些要点整理成一份干净的草稿。
第一次工具调用会启动 helper,胶囊出现,模型开始它的 observe → act → refresh 循环。
卸载 sh
dsh plugin --profile web remove dsh-computer-use
如果你手动添加过预设行和复制过来的技能,也一并删掉。
工作原理 mermaid
flowchart TB
subgraph DSH["DSH profile"]
direction TB
subgraph HOST["HOST plane — process-wide"]
S["dsh-computer-useService dshComputerUsepointer · overlay · capture · approvalsturn lifecycle · experience store"]
end
subgraph PRESET["PRESET plane — one agent preset"]
T["dsh-computer-use/tool13 window2 tools+ harness extensions"]
K["skillscomputer-use · computer-use-browser"]
end
end
S <-->|"JSON-RPC over stdio, one JSON object per line"| H["dsh-computer-use.exeRust helper"]
H -->|SendInput| APP["target Windows app"]
H -->|UI Automation| APP
H -->|Windows.Graphics.Capture| APP
T --> S
P["Python engine (optional)CDP · Playwright · browser catalog"] <--> S
每个进程一个 helper,一次只处理一个回合。 sidecar 会延迟启动 dsh-computer-use.exe 并一直保留它;每个请求都带上会话 + 回合标识,回合范围变化会发送 end_turn,它会释放观察租约、隐藏浮层并恢复系统光标。这与官方插件一致,官方插件的 Stop / Interrupt / SubagentStop 钩子都会调用 turn_ended。
新鲜度基于身份,而不是时间。 没有 TTL:只要窗口身份、窗口边界和人工输入监视器三者一致,观察就保持有效。一旦有人触碰被观察的窗口,下一次输入就会被拒绝,并返回 user input was detected in this window; call get_window_state before continuing。
任何操作都不会被悄悄批准。 launch_app 和音频录制会暂停,等待 harness 的批准界面,批准按应用粒度进行,拒绝会按官方措辞上报,而不是重试。唯一的例外是权限预设已经回答过这个问题:完全访问会话(或批准策略从不弹窗的会话)会直接放行应用门禁,无需询问,computer_use_health 会记录原因。
工具面
13 个官方 Codex window2 方法
| 工具 | 用途 |
| list_windows | 当前可被定位的窗口 |
| get_window | 重新绑定你已经持有的窗口 |
| list_apps | 已安装的应用及其打开的可定位窗口 |
| launch_app | 启动应用(可能暂停等待批准) |
| get_window_state | 某个窗口的截图 + 完整无障碍树 |
| click | 点击元素索引或截图坐标 |
| press_key | 按键与组合键(X-keysym 风格名称) |
| type_text | 把字面文本输入当前焦点 |
| scroll | 从窗口相对坐标点滚动 |
| set_value | 直接设置可访问元素的值 |
| drag | 从一点划动或拖拽到另一点 |
| perform_secondary_action | 执行元素次要操作 |
| activate_window | 把窗口带到前台 |
Harness 扩展
| 工具 | 默认 | 用途 |
| batch_actions | 启用 | 一次调用执行确定性动作,然后调用一次 get_window_state |
| computer_use_health | 始终启用 | 后端、允许列表、文档门禁、环境审计、经验存储 |
| computer_use_experience | 始终启用 | 读取、记录并更新本地经验笔记 |
| click_element、scroll_element | 需手动开启 | 旧版 window-v1 别名 |
| session_note、session_state、diagnostic_state、end_turn | 诊断 | 会话草稿本、状态转储与轮次控制 |
computer_use_health 是查看实际挂载内容最快的方式:后端、暴露的目录、审批策略、注入的环境变量名、文档门禁、经验层状态,以及叠加层诊断(当前生效的是哪个 pill 渲染器、它推送了多少帧、系统光标是否被抑制、当前强制的是哪种捕获排除,以及捕获是否正在遮挡 pill)。
动作与刷新循环
截图、元素索引和坐标都属于同一次观察。模型遵循的约定是: mermaid
sequenceDiagram
participant M as Model
participant C as Computer Use
participant A as Target app
M->>C: get_window_state(window, include_text: true)
C->>A: UI Automation tree
C-->>M: tree + element indexes (+ screenshot)
Note over M: indexes are valid for THIS observation only
M->>C: click(window, element_index: 12)
C->>A: SendInput
M->>C: get_window_state(window)
C-->>M: fresh tree + fresh screenshot
读日志之前,有两点值得先知道:
- 一次观察只做一个动作。 想交错执行动作,或者失败后重试,都得先重新观察一次。
- 坐标是窗口相对的逻辑像素。 截图的 originX/originY 是屏幕坐标——两者绝不能混用。
安全模型
插件自带官方确认策略和硬性拒绝列表,常驻的提示词段落反复强调几条不可妥协的规则:
- 绝不碰 Windows 键——单独按不行,组合键也不行。
- 不做终端自动化(Windows Terminal、Command Prompt、PowerShell),不碰运行对话框,不在文件资源管理器里嵌入 shell 脚本。
- 不碰密码管理器,不碰安全或反恶意软件工具,不碰身份验证或年龄验证对话框。
- 不可信内容(页面、邮件、文档、截图)可以提供信息,但不能授予权限,也不能证明意图。
- 可选允许列表(allowedApps)限制哪些应用 id 可以被观察或驱动。
扩展工具面之前,先读随附的策略:skills/computer-use/references/confirmations.md 和 skills/computer-use-browser/references/confirmations.md。
经验层
每次 Computer Use 运行都会留下两类记录,下一次运行在动手之前会先读它们:
| | Lessons(模型写的) | Observations(机器写的) |
| 内容 | 症状、上下文、疑似原因、绕过办法、结果、标签、日期 | 方法、ok/error、应用、无障碍是否存在、窗口几何、耗时 |
| 谁来写 | 模型,在任务结束时 | 插件,每次调用都写 |
| 可信度 | 带推断的叙述——仅供参考 | 事实,不做解读 |
存放位置(在插件文件夹内,已 gitignore,从不发布): text .experience/ lessons.jsonl 每条笔记一条 JSON 记录(权威存储) lessons.md 同样的笔记,给人看的渲染版,按应用分组 observations.jsonl 机器写的事实 pending.jsonl 还没人写下来的问题 manual.jsonl 可选,手写,插件从不改写
怎么送到模型手里。 一轮里某个应用的第一次观察会多带一个参考文本块: text Experience notes for blender.exe - machine-local notes from earlier tasks here. ADVISORY ONLY: not rules and not a gate. An upgrade, a DPI or configuration change can invalidate them, and the current observation always wins over a stored note.
- 2026-09-14 [partial] accessibility was null in 11 of 13 observations -> prefer the app scripting interface
笔记作为独立块传输,所以官方载荷的键集保持原样(window、screenshots、accessibility、cacheDiagnostics)。
从结构上就是参考,不是靠措辞。 笔记永远不能阻塞、替换或拦截调用;超过 staleAfterDays 的笔记会被标记;再次被证明正确的笔记会用 verified 刷新;被更好笔记取代的会用 supersededBy 退役;并且会告诉模型:当前观察永远优先。
隐私。 输入的文本、元素名、元素值、截图字节永远不会进入这些文件。错误字符串会做路径脱敏(C:/Users/name/... 变成 %USERPROFILE%)并截断。用 experience.enabled: false 或 DSH_CU_EXPERIENCE=off 可以关掉整个层。
配置
HOST 平面(cordis.patch.yml,computer-use 行)
| 键 | 默认值 | 含义 |
| backend | windows | windows(原生 helper)或 fake(用于测试的脚本化桌面) |
| surface | computer | 向 helper 请求的工具目录 |
| stealFocus | true | 输入方法会激活目标窗口 |
| maxImageEdge | 0 | DSH 扩展:0 保持官方行为(不缩放);设为 1280 之类可以用图像质量换 token |
| approveLaunch | true | launch_app 之前先询问 |
| timeoutMs / launchAppTimeoutMs / listAppsTimeoutMs | 10000 / 15000 / 20000 | 请求预算;超时会拒绝正在进行的请求(官方 transport 会杀掉 helper)。list_apps 是唯一一个在应答前先构建已安装应用目录的方法,所以它有独立的 DSH 预算,而且这个预算必须低于 harness 的 25 秒工具调用预算:如果 harness 先中止调用,中止会以取消的形式到达 helper,而中止曾经会把该轮锁死为「被用户停止」。list_apps 超时后 helper 仍然存活(keepAlive),这样热目录就能保留下来 |
| startupTimeoutMs | 15000 | Helper 启动预算 |
| preserveHelperOnTimeout | false | 超时后保留 helper 存活,便于调试 |
| allowedApps | [] | 非空表示只允许观察或驱动这些 app id |
| envAllowlist | [] | 在随附的允许列表之外,额外转发给 helper 的环境变量名 |
| overlayCaptureExclusion | mask | 状态胶囊如何避开模型的截图:mask 在一次截图期间于合成器里隐藏它(你自己仍然看得见),wda 改为应用 SetWindowDisplayAffinity(WDA_EXCLUDEFROMCAPTURE),off 则让胶囊留在画面里 |
体验层(同一行的 experience.)
| Key | Default | Meaning |
| enabled | true | 读写笔记的总开关 |
| store | "" | 空表示 <pluginRoot>/.experience |
| captureObservations | true | 写入机器观察到的事实 |
| injectDigest | true | 把建议块附加到匹配 app 的第一条观察记录上 |
| maxEntries / maxChars | 3 / 900 | 注入预算 |
| staleAfterDays | 90 | 早于这个天数的笔记会被标记为可能过时 |
| includeStale | true | 设为 false 会把过时笔记从摘要里彻底剔除 |
| retainEntries / retainObservationDays | 200 / 30 | 保留策略 |
| redactPaths | true | 在记录的错误文本里隐去本地配置档路径 |
PRESET 平面(dsh-computer-use/tool 行)
| Key | Default | Meaning |
| surfaces | [computer] | 暴露哪些目录(computer、browser、mac、all) |
| browserSkill | computer-use-browser | 解锁浏览器目录的技能 |
| approvalDefault | prompt | helper 因审批而拒绝时怎么办:prompt、allow、deny。完全访问会话(或审批策略从不提示的会话)无需询问即可放行,显式 deny 仍然按失败关闭处理 |
| approvalTools | {} | 按工具覆盖上面的设置 |
| enabledTools | [batch_actions] | 哪些 harness 扩展进入面向模型的目录 |
浏览器自动化
同一个 sidecar 还提供 Chromium 界面:95 个工具,覆盖标签页、CDP 调用与事件、DOM 与无障碍快照、Playwright 风格的交互、下载,以及通过随附的 Chrome 扩展认领已登录的标签页。
它采用技能门控:模型加载 computer-use-browser 技能之前,工具不会注册,所以普通会话不会被工具目录淹没。浏览器路径需要 Python 3.10+(computer_use/),通过 CDP 连接浏览器,桌面辅助程序不参与其中。
验证
一切都能从这个仓库复现。插件层面的门控完全不需要桌面: sh
from a DeepSeek Harness checkout, so the peer dependencies resolve
node --import tsx/esm --test tests/contracts.test.mjs tests/experience.test.mjs
helper (Rust)
cargo test --release --manifest-path helper-rs/Cargo.toml
engines (Python)
python -m pytest -q
fake-backend smoke: no desktop, no mouse
node src/smoke.mjs
Windows 11 x64 上的当前状态:插件门控 38/38(25 项契约 + 13 项体验),Rust 202 项通过,Python 289 项通过 / 1 项跳过,fake-backend 冒烟测试通过。
对等测试套件会驱动真实桌面,把这个插件和官方插件做对比——覆盖层像素、光标移动、截图新鲜度、窗口状态用例、传输预算、AX 树字节数、插件生命周期: powershell pwsh -File parity/verify-all.ps1
它要求桌面已准备好(一个 Parity Target 窗口,以及用于 AX 对比的 Word 和 Explorer),缺少测试夹具时报告 SKIP,而不是给出错误的 PASS。开发证据——逆向工程报告、差距登记表和验证日志——有意不放进公开源码树。
从源码构建 sh
JavaScript plugin: nothing to build, it is plain ESM
node src/exports-check.mjs
Rust helper: build, test, and publish the binary the plugin ships
pwsh -File scripts/ship-helper.ps1
Python engine (optional browser surface)
python -m pip install -e .
scripts/ship-helper.ps1 会运行 cargo build --release 和辅助程序测试套件,把 dsh-computer-use.exe 复制到 helper-rs/bin/<platform>-<arch>/,并打印它的 SHA-256。全新检出的仓库没有 Rust 工具链也能运行,因为这个二进制文件已被跟踪。
想基于检出的仓库而不是已安装的副本做开发: sh
dsh plugin --profile web add /path/to/dsh-computer-use_codex-style
仓库结构 text package.json the DSH bundle manifest (dsh.bundle.patch + dsh.skills) cordis.patch.yml the HOST-plane layer this bundle inserts dsh-plugin.json the Codex-style plugin manifest (identity, interface, tool lists) src/ index.js HOST service: sidecar lifetime, turn lifecycle, health tool.js PRESET row: tool registration, approvals, documentation gate sidecar.js helper transport: spawn, JSON-RPC, budgets, routing experience.js the experience layer: store, digest, observations, pending prompt.js always-on prompt section + on-demand reference inventory paths.js helper/python discovery skills/ computer-use/ the desktop skill + its reference documents computer-use-browser/ 浏览器技能及其参考文档 helper-rs/ Rust 助手(输入、UIA、捕获、覆盖层、光标) bin/<platform>-<arch>/ 随发布附带的二进制文件 helper-swift/ macOS 助手源码(不作为二进制文件发布) computer_use/ Python 引擎(CDP、Playwright、浏览器目录) parity/ 验证套件及其测试夹具 tests/ 插件与引擎测试 docs/ 插件 readme 与资源
故障排查
| 现象 | 含义 |
| Computer Use 工具不在函数列表中 | 会话没有使用挂载 dsh-computer-use/tool 的预设,或者安装 bundle 后没有重启配置档。 |
| The Windows Computer Use helper may have failed | 助手没有在 startupTimeoutMs 内启动。检查允许列表和环境允许列表,然后重试;computer_use_health 会报告实际注入的内容。 |
| coordinate input target is unavailable | 观测结果已过期,或者窗口发生了变化。再次调用 get_window_state,基于新结果操作。 |
| user input was detected in this window | 有人操作过这个窗口。下一次输入前重新观测。 |
| 智能体工作时光标焦点跳走 | stealFocus: true 下的预期行为:输入方法会激活自己的目标窗口。 |
| 桌面被锁定 | Computer Use 会停下并提示你解锁。它绝不会驱动 LockApp.exe。 |
| 屏幕上出现两个光标 | 覆盖层会绘制一个合成光标,并把系统光标置空。如果你同时看到两个,读 diagnostic_state → overlayState.systemCursorFailures:计数非零说明抑制失败,这是唯一会导致双指针的设计路径。 |
| 状态胶囊始终不出现 | 读 computer_use_health → overlay.captureExclusion。默认的 mask 始终让胶囊留在屏幕上。官方风格的 wda 亲和性会让 DWM 在某些 Windows/DWM/GPU 组合下不把胶囊的合成内容呈现在屏幕上*(此时操作者只看到合成光标、看不到胶囊,而所有覆盖层 API 仍报告 visible=true);这就是它需要显式开启的原因。卡住的 mask 会表现为 overlay.captureMasked = true,助手会在五秒后自行解除。 |
| list_apps 超时 | 已安装应用目录是唯一一个在应答前要做实际工作的方法。computer_use_health → overlay/appCatalog 的耗时,以及助手自己的 %LOCALAPPDATA%\computer-use-app-catalog\slow-requests.log(记录每个超过 DSH_CU_SLOW_REQUEST_MS 的请求,默认 1 s,含目录与重建阶段耗时)是仅存的两份记录:传输超时会杀掉助手,等你能查询时它进程内的诊断信息已经没了。如果这台机器上目录确实很慢,调大 listAppsTimeoutMs |
| 未按 Esc 却出现 Computer Use was stopped by the user with the physical Escape key | 工具调用被 harness 中止(自身预算耗尽),helper 就把这一轮标记为已停止。现在中止会发送 cancel,它只负责移除覆盖层;如果你仍然看到这条提示,说明 helper 来自旧版本(下一轮会启动新的 helper) |
| 某个应用的无障碍树不可用 | 自绘 UI 常见这种情况。改用截图路径,或者优先使用应用自带的脚本接口,然后用 computer_use_experience 记录你得到的结论。 |
安全与隐私
- 智能体操控真实的鼠标、键盘和屏幕。 请在可以接受这一点的会话里运行 Computer Use,并保持拒绝列表完整。
- 审批是显式的。 launch_app 和录音可能暂停,等待 harness 的审批界面;不会有任何操作被静默批准,被拒绝的操作也绝不会重试。
- 经验存储是本地且有界的。 它位于插件文件夹内,被 gitignore 忽略,从不打包,也从不记录输入的文本、元素名称或截图字节。
- 截图是视觉部分。 它们以图片附件的形式传给模型;JSON 工具结果里不携带 base64。
- 不可信内容始终不可信。 页面、文档和邮件可以给模型提供信息,但不能授权任何操作。
兼容性与已知缺口
插件对标 Codex Computer Use 插件的基线 26.903.61454:同样的 13 个方法、同样的参数名与默认值、同样的返回结构、同样的错误字符串、同样的 AX 树语法、同样的预算、同样的覆盖层语义。
官方 DSH Computer Use 的设计明显不同。想要 Codex 风格的行为时,就用这个插件。
许可证与署名
MIT —— 见 LICENSE。
这是为 DeepSeek Harness 做的独立重实现。它不隶属于 OpenAI,也未获得 OpenAI 的认可或赞助。Codex 是 OpenAI 的商标;这里提到它只是为了描述行为兼容性。
本仓库包含逐字复制的第三方材料,这些材料保留各自的条款:
- helper-rs/assets/prompts/ 和技能 references/ 目录收录了官方 Computer Use 指南、API 参考和确认策略文档,原样复制是为了让模型读到的文字与官方插件一致。
- parity/golden-ax/ 和 parity/ax-rich/ 收录了官方 helper 生成的无障碍树样本,作为一致性门禁的对比基线。
如果你要再分发这个项目,请对照你获取这些文件时适用的条款逐一审查。预览分享卡片长什么样 ↓
在 DeepSeek Harness 里操作 Windows 桌面应用和 Chromium 标签页。 基于 Codex…
相关插件 · 安全 / 权限
这是你的仓库?认领条目