DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

amaji61 /

amaji61/dsh-pet-extras

Verified

DSH 桌宠扩展:让桌宠看你的屏幕、把画面交给一条真实会话来判断,再用桌宠的声音说出来。零第三方依赖。

★ 0 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHubProject homepage
READMESource: main@cae40aa0

dsh-pet-extras

给 DeepSeek Harness(DSH)的桌面桌宠 dsh-pet 加装的扩展能力。

它本身不提供桌宠。 没装 dsh-pet 这个插件就没有使用意义——请先装 dsh-pet,再加这个。

这是个人开发者的业余项目,不是官方扩展,与 dsh-pet 作者无关。 现在是 0.2.3 早期版本,作者第一次用 GitHub 发布插件,功能上仍可能有 bug,遇到问题欢迎提 issue,我会尽力修。

英文说明见 README.en.md。


⚠️ 先读这个:它会截你的整个屏幕

如果这一节看完你接受不了,请不要安装。

它做什么 你要知道的
按你设的间隔截取主显示器整屏 截图里可能出现聊天记录、密码框、别人的隐私
默认只存在本地磁盘 $DSH_HOME/dsh-pet/screenshots/,插件自己不上传任何地方
只有在你自己打开「看屏幕」之后,图才会发给模型 发给你自己在 DSH 里配置的模型提供方,用你自己的 API Key,费用你自己承担

默认状态:「看屏幕」是关的——不截图、不联网、不调用任何模型。什么都不开的话,它只是个躺在磁盘上的插件。

不想让图离开电脑,就永远别打开 screenshotEnabled。

完整的数据流图表见下面的 隐私与数据处理。


接宿主智能体:这个插件的底座,不是可选项

先讲清楚原理,后面所有功能都建在这上面。

dsh-pet 原本有个自己的小脑:它拿一个默认模型单独聊,读的是自己那份精简记忆,跟你界面里那条会话完全是两个脑子。你说过的事它不知道,它说过的事你也查不到。

这个插件做的事,是把这个小脑拆掉,让它改用你界面里的真脑子。

你说的话 / 屏幕画面
      ↓
  投递给 DSH 里的一条真实会话  ← 就是你平时在用的那条
      ↓
  那条会话用它自己的上下文和记忆回答
      ↓
  回答再回到桌宠,用它的声音逐句说出来

这样一来得到什么:

  • 一个脑子。桌宠不会另开一套记忆,它说的就是你那条会话说的。你在界面里交代过的事,桌宠那边也知道。
  • 能接着聊。桌宠不再是一问一答的玩具,它会带着前面几十轮的上下文接你的话,能延续、能追问。
  • 能替你干活。投进去的是真消息,那条会话会真的去调工具、读文件、跑命令——桌宠于是从「会说话的挂件」变成了「能动手的入口」。
  • 屏幕也归它看。看图播报是同一个机制:截图作为附件投进去,会话真的看见画面再回话,而不是拿一句话去猜。

代价也得说清楚:

  • 桌宠每说一句、每看一眼,都占那条会话的 token。开得越勤,撞上下文上限越快。
  • 投递是串行排队的:那条会话正在跑你的任务时,桌宠得等。
  • 它是真的进你的会话,所以别指望它「只是个宠物」——它做的事跟你自己发消息是一回事。

这也是为什么下面「看屏幕」必须走这条路:如果只发一句「你抬头看一眼屏幕」却不带图,会话看不见画面,只能凭空编。要播报就是投图,不播报就别投。

和 dsh-pet 自带的对话有什么区别

dsh-pet 自带 开了接智能体后
谁在回答 单独调的默认模型 你界面里那条真实会话
记忆 自己那份精简记忆 会话的完整上下文和记忆
你说过的事它知道吗 不知道 知道
能调工具干活吗 不能 能(那就是真消息)
占谁的 token 单独的调用 那条会话的额度

功能

功能 说明 默认
接宿主智能体 底座。桌宠的话投递给 DSH 里的一条真实会话,回答再用桌宠的声音逐句说出来。共享那条会话的上下文和记忆。关掉它,下面两个都用不了 关
看屏幕 一个开关管到底:每隔 N 秒抓一张主屏(本地 PNG),并把这张投给接的那条会话看一眼,会话按自己的上下文和记忆回一两句,显示在桌宠头顶气泡里。开了就一定会调模型、耗 token;关了就全停。没有「只截不投」这一档 关
视野档案 每次看图的原图 + 会话的原始分析存进 dsh-pet/视野/(按天分目录,留 7 天)。平时不进上下文,要查「昨天下午我在干嘛」时再翻 开
锁在屏幕内 把 confineToScreen 开关下发到 dsh-pet,防止宠物窗口跑出屏幕边界。默认不管:只有你在 /dsh-pet-extras/confine 里明确设过,插件才接管,不会装完就擅自改 dsh-pet 的配置 关(不管)

设置页

装好后,DSH 设置里会多出一节 「桌宠扩展」,里面是插件自己的旋钮:看屏幕开关 + 看屏幕间隔(秒),改完点保存即刻生效。

为什么单独开一节:这些键存在本插件自己的配置文件里,dsh-pet 的设置页不认识它们。之前只能改 JSON 或 curl,现在有了图形入口。

注意:官方 dsh-pet 的设置页里没有这个开关,别去找。以前这里写着「两个是同一个键、保存会同步」——那是我们早期往 dsh-pet 里塞私有键留下的错觉,官方版根本没有这些键,那套同步代码也删了。插件的旋钮只在这一节里。


安装

前置:先装 dsh-pet(本插件是它的外挂,不提供桌宠本身)。

桌面版:一键装(推荐,不用改任何 JSON)

  1. 打开 设置 → 插件 → 添加插件
  2. 在「包名或地址」里填包文件的绝对路径,二选一:
    • .tgz 包:D:\某个目录\dsh-pet-extras-0.2.3.tgz
    • 解压出来的文件夹:D:\某个目录\package
  3. 确认安装,按提示重启 DSH

这条路不需要手动改 package.json:DSH 的插件管理器在安装时会读包里的 dsh.bundle 字段,自动把包名写进 dsh.profile.bundles(dsh-plugin-manager 的 reconcile() 负责这一步)。

装完第一件事:设置 → 桌宠扩展 → 在「接哪条会话」里选一条会话,再打开「看屏幕」。

不选会话时插件不截屏、也不投递——这是故意的。早先版本会在你没选的时候「挑消息最多的那条会话」投递,实测会把整屏截图灌进一个毫不相干的会话里,所以现在改成:没选就什么都不做。

手动装(pnpm add / 离线 tgz):必须改两处

DSH 只加载 package.json 的 dsh.profile.bundles 里列出的包。pnpm add 只写 dependencies,不写 bundles——文件装好了、重启了,设置页里却什么都没有、接口全 404,就是这个原因。

以 profile 目录 $DSH_PROFILE(桌面版通常是 $DSH_HOME/profiles/desktop)为例,改 $DSH_PROFILE/package.json:

{
  "dependencies": {
    "dsh-pet": "0.3.8",
    "dsh-pet-extras": "0.2.3"      // ① pnpm add 会自动加这一行
  },
  "dsh": {
    "profile": {
      "bundles": [
        "@deepseek-ai/dsh-base",
        // ... 其他 bundle
        "dsh-pet",
        "dsh-pet-extras"            // ② 这一行必须手动加,否则插件不加载
      ]
    }
  }
}

改完重启 DSH。卸载时两处都要删。

怎么确认真的加载了

# 返回 ok/enabled/minGapSec 就是加载成功;404 就是没加载(bundles 没加、或没重启)
curl http://127.0.0.1:<PORT>/dsh-pet-extras/sight-share

预期返回 {"ok":true,"enabled":true,"minGapSec":60}。若是 404 / no such route,回到上面检查 bundles 那一行。

端口每次重启都会变,从 DSH 窗口标题栏或者启动日志里看。

这个版本不再改 dsh-pet 的任何文件

0.1.0/0.1.x 早期版本靠读 dsh-pet 配置文件里的 screenshotEnabled / agentBridgeEnabled 工作,而这几个键是我们自己塞进 dsh-pet 的私有配置里的——官方 0.3.8 根本没有,官方更新也会覆盖掉。别人装了之后开关永远是关的,就是因为这个。

现在插件的配置全部自给自足($DSH_HOME/dsh-pet/extras-config.json),不读 dsh-pet 的配置,也不需要改 dsh-pet 的 assets/config.jsonc。

唯一还会动 dsh-pet 的是「工作状态气泡」那个可选补丁,见 工作状态气泡与桌宠对话冲突。它打不上会自己跳过,不影响其它功能。

配置

推荐在 DSH 设置 → 桌宠扩展 里改(有开关和数字框,保存即生效)。

配置文件在 $DSH_HOME/dsh-pet/extras-config.json,也可以走 HTTP 接口:

# 看当前配置
curl http://127.0.0.1:<PORT>/dsh-pet-extras/config

# 改配置(只传要改的字段)
curl -X PUT http://127.0.0.1:<PORT>/dsh-pet-extras/config \
  -H 'content-type: application/json' \
  -d '{"screenshotEnabled": true, "sightShareMinGap": 60}'

<PORT> 是 DSH 的 Web 端口,和地址栏里的一致。

键 类型 默认 说明
targetSessionId string "" 接哪条会话(权威键):完整会话 id,如 session-1d86…。空 = 不投递、也不截屏。填错(那条会话已经关了)同样不投,不会偷偷改投别的会话
agentBridgeTarget string "" 兼容键:会话标题。设置页保存时会自动跟 targetSessionId 一起写。只在配置文件里根本没有 targetSessionId 这个键时(从老版本升上来的配置)才当兜底用;这个键一旦存在,标题就彻底不参与匹配——哪怕值是空串,也算你亲手清空的,空就是空
screenshotEnabled bool false 看屏幕总开关:开 = 定时截屏 + 每张交给接的那条会话(要投图,每张会花 token);关 = 全停。还需要在下面选一条目标会话,没选就什么都不投
sightShareMinGap number 60 唯一的节奏:两次投图之间至少隔多少秒(最小 5)。这是闸门不是节拍器——实际触发还会被截图助手的 20 秒轮询对齐、会话生成耗时、以及偶发的跳过一格影响,详见下面「实际节奏」一节。想让节奏稳,设成 20 的整数倍
screenshotIntervalSec number 20 已废弃:间隔统一由上面的 sightShareMinGap 决定。代码里留着这个默认值只为读老配置文件,改了没有任何效果
confineToScreen bool true 想让窗口锁在屏幕工作区时填的值。只有 confineManaged 是 true 才起作用(通过 /dsh-pet-extras/confine 设置会自动置上)
confineManaged bool false 插件是否接管 dsh-pet 的 confineToScreen。默认 false = 不碰,装完绝不擅自改 dsh-pet 的配置
screenshotKeep number 60 截图文件保留张数(1~2000),超了删最旧的
lookLearnEnabled bool false 看图播报的自学习(见下)
lookRulesMaxChars number 1200 学到多少字就停止采用(0~4000)
看图播报的额外要求 文件 — 写在 $DSH_HOME/dsh-pet/看图播报要求.md 里(不是配置键;首次启用时自动生成一份说明)

必须两件事都有:①「看屏幕」打开;②「接哪条会话」选了一条正在用的会话。只开开关不选会话,一张都不会投(这是故意的:宁可不动,也不往不相干的会话里塞图)。

以前这里写着「开关会同步到 dsh-pet 的设置页」——那是不存在的功能,现已删除。这个插件的配置只住在自己的 extras-config.json 里,只在本插件的设置页(设置 → 桌宠扩展)里改,两边不会再打架。


HTTP 接口

全部挂在 /dsh-pet-extras 下:

方法 路径 说明
GET /ping 探活,返回插件名、版本、DSH_HOME
GET /config 读当前配置 + 默认值
PUT/POST /config 改配置(只传要改的键)
GET /screenshot 列出最近截图和开关状态
POST /screenshot 立刻抓一张(会拉起截图 helper)
GET /agent 桥接状态:目标会话、队列深度、可选会话列表
POST/PUT /agent body {"sessionId": "..."} 换目标;{"text": "..."} 直接投递一句话;加 "async": true 立刻返回、后台播报
GET /confine 读屏幕锁定开关
PUT/POST /confine body {"value": true},立刻下发给 dsh-pet
GET /sights?limit=N 取最近 N 条看图记录(默认 50,上限 500)
DELETE /sights 清空看图记录
POST /rate body {"index": 0, "rate": "good"|"bad"|""},给某条播报打标
GET /learn 自学习状态与学到的规则
POST /learn 跑一次自学习(需要 lookLearnEnabled: true)

工作方式

截图

DSH 宿主进程拉不起 desktopCapturer(那是 Electron 渲染进程的能力),所以本插件会自己 spawn 一个最小化的 Electron 进程专门截图:

  • 进程入口 runtime/electron-helper/main.cjs
  • 它在 127.0.0.1:随机端口 起一个只监听本机的 HTTP 服务,启动时把地址打到 stdout
  • 宿主从 stdout 正则抓到端口,之后通过 POST /shot 让它截图
  • 图片落在 $DSH_HOME/dsh-pet/screenshots/,默认保留最近 60 张

为什么不用 IPC/stdin:实测 Electron 被 spawn 起来之后 stdin 不通,写进去的行收不到。所以走了本机 HTTP。

接智能体

投递不是「复制一遍上下文」,是真的进入那条会话:

  1. 按 agentBridgeTarget(或自动规则)挑一条宿主会话
  2. 等它空闲
  3. 把桌宠的话 followup 投递进去
  4. 等这一轮跑完,从会话事件流里抽出 assistant/message 的正文
  5. 用桌宠逐句气泡说出来

好处是共享那条会话的完整上下文和记忆,不需要额外维护一份。代价是必须排队——那条会话正在忙的时候,桌宠得等。

桌宠的回复怎么和你在界面里说的话区分开:投递的文本前面会加三个零宽空格作为围栏,扫回复时只认围栏之后的那一段,所以你自己的对话不会被误当成桌宠的回答念出来。

看图播报

看图播报和聊天是同一条路(这是本插件的核心要求,别改成两条):

有新截图 → 存成附件 → followup 投进接的那条会话(等于你自己贴了张图)
        → 会话按它自己的上下文和记忆回一句
        → 这句话显示在桌宠气泡里

好处是它说的就是会话说的,看的也是会话看的,不用额外维护第二份记忆。 代价是每看一次图都要占那条会话的 token——所以有间隔和「画面没变就闭嘴」两道闸。

具体规矩:

  • 请求里明确要求不要用「屏幕上」「画面里」这类报幕腔开头,也不要每次同一个开头
  • 认不准就笼统说,宁可笼统也不猜错
  • 投之前先缩图:整屏原图 2561×1601 约 1.1MB,缩到长边 1568 后约 520KB(省一半以上),模型理解力不掉
  • 缩图是零依赖自己实现的(lib/png-shrink.js,只用 Node 自带 zlib),不引任何第三方库
  • sightShareMinGap(默认 60 秒)内不重复投
  • 投之前先在本地比像素:把画面压成 32×20 个格子算平均色,跟「上一次真正投出去的那一屏」比。变化格占比 < 5% 就判成同一屏,整轮跳过——不进会话、不花 token、不出声。鼠标移动、时钟跳字、弹幕、进度条这些只占很小一块,滤得掉;切窗口、翻页会让大面积同时变,占比一下就上去
  • 本地判定跑在 lib/screen-diff.js(零依赖,复用 png-shrink.js 的像素解码),一张图约 100ms。阈值用 60 张真实截图 + 8 个合成场景校准:噪声最高 3.1%、真变化最低 9.8%
  • 兜底:万一会话还是回了「没变」这类短句,也闭嘴(主判据已经是本地像素比对,这道只防模型不听话)
  • 代码层还有一道只删不改的过滤:整句里出现三个以上「截图 / 画面 / 右侧 / 弹幕 / 进度条」这类描述性词汇,这句丢掉不播;一句人话都没有时这一轮就闭嘴

气泡停留时间按字数算(5.5 字/秒 × 2.6 余量,夹在 845 秒),不是一刀切的固定时长。短句至少 8 秒,20 字左右的常规句约 1314 秒,长句最多 45 秒。

实际节奏:设的间隔 ≠ 两次播报的间隔

看屏幕间隔 是闸门(两次投图之间至少隔这么久),不是节拍器(每隔这么久必然播一次)。真实两次播报之间的时间 = 间隔 + 下面几项:

项 典型多出 说明
截图助手的轮询对齐 0~20 秒 助手每 20 秒检查一次有没有新图,所以实际触发点会对齐到下一个 20 秒刻度
会话生成回答 1~6 秒 会话要真的跑一轮才有话可说
跳过一格 最多一个间隔 某一轮被判 too-soon 或赶不上节奏时,会整体后移一格

所以设 120 秒,实际大约是 2 分 05 秒 ~ 2 分 25 秒一次;偶尔会遇到 3 分半以上的空档(跳过一格时)。设 60 秒则大约 1 分 05 秒 ~ 1 分 25 秒一次。

想让节奏更准,把间隔设成 20 的整数倍(20 秒是助手轮询的最小粒度),比如 60 / 120 / 180,抖动最小。

想看真实节奏,翻 $DSH_HOME/dsh-pet/extras.log,搜 准备播报 或 这一轮跳过(too-soon),每行都带毫秒时间戳。

这一版之前的做法是把截图交给默认模型单独跑一次(describeShot):那条链路和主会话毫无关系, 桌宠等于自带一套脑子,说的不是会话说的、记忆也不共享。2026-10-24 已整条拆掉。

看图播报的自学习(默认关)

打开 lookLearnEnabled 后,你可以用 POST /rate 给每次播报打「好 / 差」标记。之后 POST /learn 会把标记过的样本交给模型,总结出「什么样的说法像人话」,写进 $DSH_HOME/dsh-pet/look-rules.txt,后续播报会参考这些规则。

它不会联网学习,也不会改变桌宠的性格:

  • 唯一的输入是本地 dsh-pet/视野/index.jsonl,不抓取任何外部内容
  • 性格不由本插件决定:播报是从你那条会话里出来的,用的是什么人设、什么口吻,跟你在那条会话里聊天的调子一致。插件只负责「别说成说明书」这一层措辞,管不到人格——这一条是 2026-10-24 大改的结果,以前插件里写死过一段人格(LOOK_PERSONA_CORE),已经删掉了
  • 学到的规则里如果出现「你是谁 / 你的身份 / 你其实是」这类改写人格的内容,会被直接拒用,整份规则作废
  • 规则超过 lookRulesMaxChars 就整段不采用(不截断——截断留半句话更容易学歪)

兼容性

  • 直接依赖:只有 Node.js 内置模块(node:fs / node:http / node:child_process 等),不 import 任何 @deepseek-ai/* 包,所以版本对不上也不会炸
  • 通过 inject 声明获取宿主服务:webServer、attachments、agentDefaultModel、agents、llm
  • 与 dsh-pet 的耦合只有 HTTP 接口:POST /dsh-pet-7340/broadcast(播报)、POST /dsh-pet-7340/anim(动作)、GET /dsh-pet-7340/config(读宠物配置)。这些都是 dsh-pet 原版就公开的路由,不需要安装任何改版
  • 路径全部走 DSH_HOME 环境变量,没有写死任何绝对路径
  • 窗口定位按 screen.getPrimaryDisplay().workArea 实时计算

系统通知

dsh-pet 自带系统通知(对话完成 / 生成失败 / 输出截断 / 权限申请 / 需要你选择), 在窗口失焦时弹到右下角。

如果觉得烦,改 $DSH_HOME/dsh-pet/main-config.jsonc 里的 notificationsEnabled 为 false。 这是总开关,一次关掉全部通知。本插件没有自己的通知,也不改这个键。


隐私与数据处理(请务必读完这一节再安装)

这个插件会截你的整个主屏幕。截图里可能包含聊天记录、密码框、别人的隐私。请确认你能接受这几点。

截什么、存在哪

  • 截的是主显示器整屏,按你设的间隔抓,存到 $DSH_HOME/dsh-pet/screenshots/ 下的 PNG
  • 默认只在本地落盘,插件不往任何服务器上传
  • 文件数量按 screenshotKeep 滚动,默认只留 60 张;随时可以手动删目录

什么时候数据会离开你的电脑

只有一个条件:你主动打开 screenshotEnabled(默认关闭)。

打开之后,每次产生新截图,插件会把它交给你自己在 DSH 里配置的模型分析一次。这意味着:

  • 图片内容会作为请求发到那个模型的提供方(DeepSeek 或你配置的其它 provider)
  • 用的是你自己的 API Key,计费和授权都由你承担
  • 插件不经过第三方中转,没有任何隐藏上报端点(可自行 grep 验证:全文只有本地 127.0.0.1 和宿主提供的 ctx.llm 调用)

不想让图离开电脑,就保持 screenshotEnabled: false。 此时截图只躺在本地磁盘里。

它还会写什么

路径 内容 控制
$DSH_HOME/dsh-pet/screenshots/*.png 原始截图 screenshotKeep 控制张数
$DSH_HOME/dsh-pet/视野/index.jsonl 每次看图的索引:时间、原图路径、体积、会话的原始分析 保留 7 天,DELETE /sights 清索引
$DSH_HOME/dsh-pet/视野/YYYY-MM-DD/*.png 当时的原图(整屏无损) 超过 7 天的目录自动删
$DSH_HOME/dsh-pet/memory.json dsh-pet 自己的对话记忆,本插件不再往里写看图记录 —
$DSH_HOME/dsh-pet/extras-config.json 插件自己的配置 —
$DSH_HOME/dsh-pet/look-rules.txt 自学习写出的规则(没开自学习就没有这个文件) lookLearnEnabled

看图播报只有一条路:截图投给主会话。

投什么 主会话能看到什么 花多少
(早期版本的 sightingInject,已删) 一句话 转述(只知道「在刷抖音」,没看见画面) 很少
现在的看图播报 截图本身 真的看见,能自己判断、能记进对话 每投一次约 7.6 万 token(其中 97% 是那条会话的历史上下文,图本身只占 1~2K)

投之前有两道闸:距上次投图超过 sightShareMinGap 秒 + 本地判定这一屏跟上次不一样(像素对比,变化格占比 < 5% 就整轮跳过,不进会话也不出声)。

为什么没有「投图开关」了:早期有个 sightShareEnabled 只管「投的时候带不带图」,关掉就变成「发一句话、不带图」——主会话收到「你抬头看一眼屏幕」却看不见屏幕,只能凭空编。开关合并后:要播报就是投图,不播报就别投,统一由 screenshotEnabled 决定。sightShareMinGap 仍然留着,因为「多久看一次」是个真需要调的旋钮。

迁移说明:早期版本的 sightingInject / sightingKeep / lookPersonaOwner / sightShareEnabled 四个键已经删除,screenshotWatchEnabled 也随开关合并一起删了(2026-10-24:以前是「定时截屏」+「定时看图」两个开关,用户分不清该开哪个,现在合成一个 screenshotEnabled,开 = 截屏 + 投图,关 = 全停)。老配置文件里留着也不会报错——插件启动时会自动把它们擦掉。

⚠️ 成本估算:每次约 7.6 万 token(见上表)。按间隔 120 秒、连续用 8 小时算,约 240 次 ≈ 1800 万 token;按 60 秒算翻倍到 ≈ 3600 万。这是「按小时」的实打实开销——间隔调大一倍,钱就省一半,比任何图片压缩都管用。

权限说明(供安全扫描参考)

  • 用 child_process.spawn 启动一个 Electron 子进程跑截图 helper。启动的只有本插件包内的固定文件 runtime/electron-helper/main.cjs,不接受任何外部传入的命令或参数,不存在远程命令执行
  • helper 自己起一个 127.0.0.1 随机端口的 HTTP 服务,只监听本机回环地址,不对局域网开放
  • 通过 inject 申请的宿主服务是功能必需:attachments(存图)、llm(分析图)、agents(注入会话)、webServer(提供接口)
  • 不读环境变量里的密钥,不写注册表,不安装任何依赖,没有任何 postinstall 脚本

已知问题(老实说,这个版本不完美)

  • 只在桌面模式(display: desktop)有效。web 模式下没有 Electron 进程,截图功能不可用
  • 改 sightShareMinGap 之后自动生效——间隔一变 helper 自己重启,不用手动干预
  • 接智能体是串行的:桌面宠物和你说话时,目标会话很可能正在忙(就是你自己正在用的那条),这时候桌宠要排队。聊天等空闲最多 90 秒,等不到就回一句「在忙」;看图只等 10 秒就当场让位(截屏 20 秒一张,等 90 秒会让攒下的图全被新图顶掉)。这是个设计取舍,不是 bug:想立刻有回应,就指定一条空闲会话
  • 播报依赖 dsh-pet:没装或版本太老时,看图分析照跑但说不出话(返回 pet-unavailable)
  • 0.2.3 版本,作者第一次用 GitHub 发布,代码里可能还有我没想到的边界情况。 遇到问题请提 issue,附上 $DSH_HOME/dsh-pet/extras.log 会好排查很多
  • 只测过 Windows + DSH 桌面版。其它平台理论可行(路径都走 DSH_HOME),但没有实测过

工作状态气泡与桌宠对话冲突

dsh-pet 投递消息时用的是普通用户消息形状(source.id 以 dsh-pet- 开头),宿主分不出「主人手敲」和「桌宠投的」,于是桌宠那几轮也会触发头顶气泡上的「思考中 / 工具调用」。

0.1.0/0.1.x 早期版本在别人的机器上报 anchor-miss:fence:它的锚点依赖一个只有我们本机那份被改过的 dsh-pet 才有的常量,官方 0.3.8 里根本没有。现已重写成 v2,锚点全部落在官方原版代码上,并在干净的 0.3.8 副本上跑过 12 项安装测试 + 10 项行为测试。

这个插件会改 dsh-pet 的文件——两段补丁,说清楚改了哪、为什么

先声明:本插件会修改你装的 dsh-pet 的一份源码文件(node_modules/dsh-pet/lib/index.js)。这一节把所有改动摊开讲。

为什么非得改它:工作状态(头顶那个「思考中 / 工具调用」气泡)是 dsh-pet 自己算的,它监听宿主所有会话事件,按事件类型往上翻状态。桌宠投递的消息形状是 {kind:"user", id:"dsh-pet-<时间戳>"},跟主人手敲结构上完全一样,dsh-pet 自己分不出来,于是桌宠那几轮也会被当成「正在干活」,气泡乱跳。插件这边没法拦——事件是宿主发给 dsh-pet 的,插件不在那条链路上。

一共两段补丁:

  • 补丁 A|工作状态守卫(4 处插入)——不让桌宠的轮次点亮「思考中 / 工具调用」气泡
  • 补丁 B|接智能体钩子(2 处插入)——让桌宠说的话能交给主会话回答

补丁 B 为什么必须有:插件改不到 dsh-pet 的 chatWithPet,所以聊天那条路只能在 dsh-pet 里留一个调用点。这个调用点做的事情非常小——把一句话 POST 给插件,插件回过来说了话就拿回来念。插件没装 / 补丁没打上 / 开关关着,dsh-pet 的行为跟官方原版一模一样(钩子返回空,直接走原来的 generateChat)。

补丁 A 的具体位置(4 处插入,全部锚在官方 0.3.8 的原有代码上):

# 锚点(官方原版就有) 干了什么
1 const dispose = ctx.on("session/event", …) 之后 新增 petPending / petTurn 两个记账变量
2 if (type === "user/message") { 分支 认出桌宠投的消息(source.kind 或 source.id 以 dsh-pet 开头)就打标记;排除 runtime-context / time-context / dsh-mnemon 三种宿主注入后清标记
3 if (type === "turn/start") { 分支 把「这一轮是桌宠发起的吗」记到一起,跟着排队语义走
4 const next = reduceWorkStatus(…); 之前 桌宠那一轮的事件直接 return,不进工作状态;turn/end 时清标记并 workStatus.clear

补丁 B 的具体位置(2 处插入):

# 锚点(官方原版就有) 干了什么
1 const chatWithPet = async (petId, text 那一行之前 插入 bridgeChatViaExtras():把话 POST 给插件的 /dsh-pet-extras/agent,返回会话的回答;连不上就返回空
2 const generated = await generateChat(…) 那一行之前 先问插件;插件管就直接念答案(并且补写气泡,不然会话答了桌宠不出声);插件不管就往下走原来的 generateChat

补丁 B 的锚点只认前半段(const chatWithPet = async (petId, text),因为官方 0.3.8 的签名是 (petId, text)、没有 images 参数。只看前缀是为了兼容带不带 images 的各版本。

没改的地方(一并说清):消息投递、截图、缩图、视野档案、会话内容、任何数据文件——一律不碰。补丁只动「事件该怎么算工作状态」这一件事。

怎么保证不打坏:

  • 只在新版本第一次启动时动手,打完记进 $DSH_HOME/dsh-pet/extras-state.json,版本没变就不再介入
  • 状态里还记了「补丁方案代号」(现在是 ws+bridge):方案升级(比如以后加了第三段补丁)会自动重跑一次,不会因为版本号没变就漏打
  • 两段补丁各自独立判断:只缺一段就只补那一段,不会重复插
  • 打之前备份成 lib/index.js.bak-workstatus-guard(只备份一次,留最原始那份)
  • 只在 0.x 系列上打;结构大改导致锚点对不上就放弃并记日志,绝不硬改
  • 改完强制校验指纹齐全(补丁 A 4 处、补丁 B 2 处),少一处就整体放弃、不写文件
  • 改的是磁盘源码,下次启动 DSH 才生效

想撤销:

# 用备份覆盖回去,再删掉状态记录,下次启动就不打了
cp "$DSH_HOME/profiles/desktop/node_modules/dsh-pet/lib/index.js.bak-workstatus-guard"    "$DSH_HOME/profiles/desktop/node_modules/dsh-pet/lib/index.js"

然后删掉 $DSH_HOME/dsh-pet/extras-state.json 里的 petWorkStatusPatch 那段(文件里只有这一项,直接删文件也行)。

不想让它改? 卸载本插件(或在 extras.log 里看补丁是否 anchor-miss 主动放弃)即可。如果自动补丁没生效,extras.log 里会有 dsh-pet 补丁没打上(原因) 这样一行说明原因。常见原因:anchor-miss:*(新版 dsh-pet 结构变了)、series-mismatch(不是 0.x)。


卸载

dsh plugin remove dsh-pet-extras

然后重启 DSH。

卸载不会自动删你的数据,想清干净就手动删这几个(都在 $DSH_HOME/dsh-pet/):

路径 是什么
screenshots/ 截图 PNG,可能很大
视野/ 视野档案:原图 + 会话原始分析(按天分目录)
extras-config.json 插件配置
extras.log 运行日志
extras-state.json 补丁器记录(哪个 dsh-pet 版本打过补丁)
look-rules.txt 自学习写出的规则
extras-state.json 插件自己的状态(目前只记 dsh-pet 补丁打到哪个版本了)

memory.json 是 dsh-pet 自己的,别删——里面是桌宠的对话记忆,跟本插件无关。


常见问题

看不见设置项? 本插件有自己的设置页:设置 → 桌宠扩展(dsh-pet-extras 提供的「看屏幕」开关和间隔;没装 dsh-pet 时这一节不显示)。

先分清是哪种「看不见」:

现象 原因 怎么办
设置里连「桌宠扩展」这一节都没有 插件根本没被加载(最常见:bundles 没加) 翻回上面的 「⚠️ 手动安装」 那节,检查 dsh.profile.bundles 里有没有 dsh-pet-extras,改完重启
有「桌宠扩展」这节,但找不到「接哪条会话」 它在本插件设置页里,往下滚就能看到 设置 → 桌宠扩展,在「看屏幕」下面选一条会话;不选就不投
开关显示「关」,点开保存后又变回关 配置文件写不进去,或读的是另一份 $DSH_HOME 看 $DSH_HOME/dsh-pet/extras-config.json 里的实际值;C 盘 C:\Users\<你>\.dsh 和 D 盘 D:\dsh-home 可能是两份不同的 home

这些键只存在于本插件的 extras-config.json,跟 dsh-pet 的设置页没有任何关系(早期版本说「同一个键」是错的,相关代码已删除)。

开了「看屏幕」,截图目录没动静? 确认三点:①桌宠的显示模式是 desktop(web 模式没有 Electron 进程);②「接哪条会话」选了一条正在运行的会话——没选就不投;③GET /dsh-pet-extras/screenshot 返回的 enabled 是 true。间隔改完会自动重启 helper,不用手动干预。

两次播报间隔比设的时间长? 正常。设置的是闸门不是节拍器,实际会比设定值多出 5 秒到 1 个间隔。详见上面「看图播报」一节的 「实际节奏」。

桌宠说话很久才回,或者干脆回「在忙」? 接智能体是串行的:目标会话正在跑任务时,桌宠得排队。聊天等空闲最多 90 秒;看图只等 10 秒(截屏是 20 秒一张,等 90 秒会让中间攒的图全被新图顶掉,等于盯着屏幕什么都没看见)。想让它立刻有回应,就把目标会话改成一条空闲的。

清空了「接哪条会话」,图还在往旧会话里投? 0.2.0 早期版本有这个坑:配置里同时存着 targetSessionId(id)和 agentBridgeTarget(标题),只清 id 的话标题会静默接管,照样按标题匹配。现在改掉了——targetSessionId 这个键一旦存在(哪怕值是空串),标题就彻底退出匹配。如果你的配置是从老版本升上来的(文件里根本没有 targetSessionId 这个键),标题仍然会当兜底用,那是为了迁移;随便在设置页保存一次就会写上这个键,之后标题就退休了。

换了显示器 / 改了缩放,宠物窗口又跑到屏幕外了? 默认插件不管这事。想让它管,调 PUT /dsh-pet-extras/confine 传 {"value":true}——这样会置上 confineManaged,之后插件启动和改配置时才下发。不调它就完全不碰 dsh-pet 的 confineToScreen。

看图播报有一阵子不说话了? 这是故意的。模型偶尔会吐出「屏幕上是一张截图,画面里有…」这种说明书体,插件会把这句丢掉不播,而不是念给你听。连续几次都不说话,说明那段时间屏幕内容确实不好说人话。

换了显示器 / 改了缩放,宠物窗口又跑到屏幕外了? 把 confineToScreen 打开,插件会在启动时和每次改配置时把它下发到 dsh-pet。


致谢

  • 桌宠本体来自 PC2005-cloud/dsh-pet(MIT)。本项目只是调用它的公开 HTTP 接口,没有复制它的代码。桌宠可爱是作者的功劳,本插件只是给它加了几件事
  • 宿主框架 DeepSeek Harness

许可

MIT,见 LICENSE。

本项目与 dsh-pet 的作者没有隶属关系,也不代表其立场。dsh-pet 的版权归 PC2005-cloud 所有。

—/ 5

No ratings yet

Verified DSH bundle

Commit cae40aa062f6

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout