前言¶
在 DSH 里跑 Agent,多数时间你盯着的是 Web GUI:任务跑到哪一步、这一步调用了什么工具、今天烧了多少 Token,都需要切回页面看。网页窗口也没法做一个始终浮在桌面、点击可交互的角色。dsh-desktop-pet-naiwa 是 Night-maze 维护的一个 Windows 客户端插件,做的事是把这些信息投影到一个透明、无边框、置顶的原生窗口里,同时让这个窗口可以单击互动、长按拖拽、贴边半隐藏,并支持把文件拖进去移动到回收站。
下面介绍这个插件:先讲它为什么必须拆成两层,再讲功能、安装命令和可用配置。
这是什么东西¶
一句话定位:基于 DeepSeek Harness 插件机制的 Windows 桌面宠物(桌宠),维护者 Night-maze,分类为客户端,许可证 MIT,GitHub 仓库创建于 2026-11-05,当前星标 0。npm 包名 dsh-desktop-pet-naiwa,版本 1.0.0。
它解决的问题:Agent 运行时状态在原生桌面上缺席。现有的 DSH client plugin 只能渲染 Web GUI 内的 React 界面,不能创建任意 OS 窗口。
为什么要 Host 插件加 WPF 子进程¶
DSH 的 client plugin 跑在浏览器 sandbox 里,没有创建原生窗口的权限。要做出透明、无边框、置顶、可拖拽的窗口,必须有一个独立的原生进程。插件因此拆成两层:
- Host 插件
lib/index.js(Cordis bundle),订阅session/event,维护按天回填的 Token 账本,读取真实余额,并负责拉起和守护子进程; - WPF 子进程
pet/DesktopPet.ps1+DesktopPet.cs,自己画窗口、做手势和动画; - 两者之间通过 127.0.0.1 loopback 上的 newline-delimited JSON 通信,并带随机 token 鉴权。
职责也有明确边界:Host 不把 Token、余额、进度写死;WPF 子进程不访问网络、不读 DSH 内部状态,只消费宿主发来的 JSON。
核心功能¶
Agent 进度投影¶
按事件投影:turn/start 表示任务开始,step/start 和 tool/call 提供进度,assistant/message 与 assistant/attempt 提供 Token 用量,turn/end 给出完成、失败或取消,agent/error 作为失败兜底。
默认显示不确定进度条加「第 N 步 · 工具名」文本。插件明确不使用编造的 0–100% 数字,避免出现一个看着像进度、其实没有依据的百分比。
Token 花费估算与真实余额¶
「今日花费」是真实 Token 用量 × 公开列表单价,UI 里用 ≈ 标注,这是估算值。利用率账本按 sessionId:seq 去重;同一个 turn/step 的成功消息会替换失败的 attempt;llm/retry-started 之后允许重试 attempt 再次计入。启动时从 ctx.sessionPersistence 回填当天数据。
「余额」来自 ctx.deepseekAccount.getBalance,是平台钱包的真实值,不估算、不伪造。读取失败时保留上一次的值并标记为 stale,刷新带指数退避,绝不用 0 冒充。
价格默认内置 deepseek-flash、deepseek-v4-pro 的 CNY/USD 公开列表价,并区分峰时(北京时间工作日 9–12、14–18)与非峰时。没有配单价的模型只显示 Token,不计金额。
交互行为¶
- 单击:按权重随机选一条
interactions配置,内置 6 种(blink、jump、shake、heart、random line、dance),可配权重、动画、台词和对应精灵。 - 长按提起:按下后超过
longPressMs(默认 450ms)算提起,之后是钟摆/弹簧拖拽,松手自然落回。 - 贴边半隐藏:拖到屏幕边缘释放后,按当前显示器
WorkingArea和edgeThreshold判断方向,滑到只露edgeVisibleRatio;鼠标移入滑出,移出延迟滑回。 - 点击穿透:
WM_NCHITTEST按当前精灵 alpha 判断,透明像素返回HTTRANSPARENT,不挡住桌面其他操作。
拖拽文件到回收站¶
通过 IFileOperation 加 FOF_ALLOWUNDO | FOFX_RECYCLEONDELETE 实现,强制「回收或失败」,没有 File.Delete / Directory.Delete 回退。路径受限:盘符根、系统目录、符号链接/目录联接、无权限、文件被占用、跨盘或网络回收失败,都会保留原文件并弹出明确错误。AppContainer 或低完整性进程会被拒绝执行。
客户端侧¶
client 侧注册侧边栏 🐾 桌宠 入口和设置页,可调缩放、音量、统计显示、长按/拖拽阈值,并支持刷新统计、重启、显示/隐藏。设置写入数据目录 ui-config.json,覆盖 profile 同名字段;删掉该文件并重启插件可恢复 profile 配置。
安装与启用¶
前置:Windows 10/11,系统自带 Windows PowerShell 5.1 和 .NET Framework 4.x(WPF 组件)。不需要额外 npm 依赖,Host 只用 Node 内置模块。插件声明基于 DSH 0.2.1-rc.5 的 Cordis 插件/服务 API。
推荐方式是用 bundle 安装。先在 DSH Web GUI 打开 Plugins,执行:
dsh plugin --profile desktop add dsh-desktop-pet-naiwa
或者指向本地源码目录:
dsh plugin --profile desktop add link:F:\path\to\dsh-desktop-pet-naiwa
package.json 里已经声明了 bundle patch 和 client 注入:
"dsh": {
"bundle": { "patch": "./cordis.patch.yml" },
"client": { "platform": "web", "inject": ["..."] }
}
接下来的步骤:
- 在 Plugins 页面把「桌宠-奶娃小时候」这个 bundle 打开,或把它加入 profile 的
dsh.profile.bundles。 - 移除任何指向绝对路径的开发行,避免同一插件加载两次。
- 刷新 DSH 页面,侧边栏应出现 🐾 桌宠。若没有,重启 DSH 一次,让 client graph 重新扫描
dsh.client。
另有一种开发行方式,只在 %USERPROFILE%\.dsh\profiles\<profile>\cordis.patch.yml 追加绝对路径条目。它没有 bundle 身份,Plugins 页面没有开关,也没有 client 设置页,只适合临时调试,日常应删掉。
配置¶
完整字段和注释见仓库的 config.example.yml。常用项:
| 字段 | 默认 | 说明 |
|---|---|---|
enabled |
true |
插件总开关 |
imagePath |
'' |
单张自定义形象;留空用内置 12 精灵 |
spriteDir / soundDir |
内置 assets | 相对插件目录或绝对路径 |
scale |
1.0 |
整体缩放 0.5–2,窗口、UI、形象一起缩放 |
volume |
0.7 |
音效音量 0–1 |
topmost |
true |
置顶 |
avoidFullscreen |
true |
全屏应用时隐藏 |
statsDisplay |
always |
always / hover / off |
longPressMs |
450 |
长按提起阈值 |
dragStartPx |
10 |
拖拽启动阈值 |
edgeThreshold |
24 |
贴边触发距离(物理像素) |
edgeVisibleRatio |
0.38 |
半隐藏后可见比例 |
currency |
auto |
CNY / USD / auto(跟钱包) |
costPrecision |
4 |
花费小数位 |
balanceRefreshMs |
60000 |
余额刷新,最小 30s,失败指数退避到 5min |
statsRefreshMs |
30000 |
统计推送间隔 |
pricing |
公开价表 | 峰时、节假日、模型单价(每百万 Token) |
interactions |
6 种 | 单击随机互动的权重/动画/台词/精灵 |
protectPaths |
系统目录 | 拒绝回收的路径前缀 |
backfill |
开启 | 启动回填的数量/字节/超时上限 |
pricing.holidays 默认是空数组:中国法定节假日每年变化,插件不内置易过期日历;需要精确峰谷账单就手动填 YYYY-MM-DD。
配置里的数组是整体替换,不是逐项合并。单击是从 interactions 里抽一条,再用该条的 sprite 指定显示哪张图(文件名去掉 .png)。想保留哪几条就全部列出来,未列出的不会再出现。
数据与日志¶
默认目录 $DSH_HOME/storages/desktop-pet/:
| 文件 | 说明 |
|---|---|
pet-config.json |
Host 写给 WPF 的合并配置 |
usage.json |
今日 + 最近 14 天 Token 账本,含模型、时间、四个桶 |
host.log |
Host 插件诊断 |
pet.log |
WPF / 启动器诊断 |
launcher.log |
启动器编译与启动诊断 |
window.json |
上次窗口位置,用于多显示器恢复 |
日志可能轮转为 pet.log.old.<timestamp>,插件不会删除用户文件。
测试与验证¶
node test/run-tests.mjs # host 单元测试
node test/mock-host.mjs # 真实 WPF + mock Cordis 集成
powershell -STA -File scripts/demo.ps1
回收站那条测试必须在普通用户进程里跑,不能在 DSH workspace sandbox 里:
powershell -STA -File scripts/test-recycle.ps1
适用场景与注意¶
适合在 Windows 上跑 DSH Agent 的开发者:希望进度和成本留在桌面上可见,同时接受一个常驻子进程。全屏演示场景下 avoidFullscreen 会把它藏起来,不会打断展示。
几点需要留意:
- 插件以当前 dsh 进程权限运行。它确实会调用平台余额接口,并在收到文件拖入时操作回收站,所以安装前应先审一遍源码,确认
ctx.deepseekAccount.getBalance调用和IFileOperation调用符合你的预期。许可证是 MIT,来源是 npm 包和 GitHub 仓库。 - 唯一会删除文件的路径是 Shell 回收 API。如果 Shell 无法回收,操作直接失败,原文件保留,没有永久删除的回退。
- 「今日花费」只是估算,金额按公开列表价算,不等于已结算金额。
- 进度条刻意不显示百分比,如果需要确切的数字,仍应回到 Web GUI 或日志里看。
结论¶
这个插件把 Agent 运行时状态从 Web 页面搬到了原生窗口,关键取舍是:用估算值标花费、用真实值标余额、用不确定进度条代替伪造百分比。两层结构(Host 插件 + WPF 子进程)是它绕开 client plugin sandbox 限制的方式,也是安装和排障时需要看清的地方。
目录页:https://www.skillhub.cn/plugins/Night-maze/dsh-desktop-pet-naiwa
仓库:https://github.com/Night-maze/dsh-desktop-pet-naiwa
npm:https://www.npmjs.com/package/dsh-desktop-pet-naiwa