dsh-cyrene-pet
昔涟桌面桌宠的 DeepSeek Harness(DSH)版:透明置顶窗口、拖拽贴边、点击穿透、气泡台词、状态面板、右键菜单,并接管对话提问、风险审批与任务进程。2.0 起加入九张内置背景、陪伴数据同步与设置合并,以及 QQ 官方机器人远程拍板;形象可换成单图 / GIF / 视频 / 多帧 sprite,也可以切成不加载立绘的卡片模式。但是必须注意,为了对轴,这版并不稳定
仓库名
dsh-cyrene-balance是它最早做余额插件时留下的,包名与插件目录已经改成dsh-cyrene-pet。安装时认包名和目录,不认仓库名。
- 作者:bestlike093
- 适用平台:Windows
- 当前版本:2.0.0
2.0 带来了什么
| 变化 | 说明 |
|---|---|
| 桌面背景 | 内置 9 张背景,支持自定义图片、遮罩浓度、定时轮换 |
| 陪伴数据同步 | 好感、身体状态、念头、开口账本、消费账本、小游戏战绩可按文件跨端合并 |
| 设置合并 | 网页设置与桌宠窗口同时改设置时按字段合并,不会互相覆盖 |
| QQ 远程拍板 | 审批和提问可以转到 QQ 官方机器人,在外面也能处理 |
| 发行形态 | 公开包不带 Live2D 模型与运行时,默认用图片形象;Live2D 需要自备 |
文档怎么看
| 你想做的事 | 看哪一节 |
|---|---|
| 先装起来 | 五分钟上手、安装 |
| 换形象、换背景、调配色 | 换形象、桌面背景、设置浮层 |
| 少被打扰、只看余额 | 常见场景怎么设、气泡模式 |
| 在手机上处理审批 | QQ 远程拍板 |
| 数据存在哪、怎么备份 | 数据文件、备份与恢复 |
| 想了解她怎么说话、怎么记事 | 架构总览、内部实现与审计结论 |
| 想了解已知问题与修复计划 | 内部实现与审计结论 |
| 出问题了 | 常见问题、Agent(dsh)升级后可能产生的后果 |
五分钟上手
下载
cyrene-pet-dsh-2.0.0.zip并解压到任意目录,例如D:\plugins\dsh-cyrene-pet。在终端执行:
dsh plugin --profile desktop add D:\plugins\dsh-cyrene-pet重启 dsh。
桌面上出现透明立绘,单击会说话,说明运行时部署成功。
右键立绘 →「换形象」→「数据」→「余额与 API Key」,填入 DeepSeek API Key;不填也可以,插件会依次读环境变量
DEEPSEEK_API_KEY和~/.dsh/.credentials.yaml。在「数据 → 余额与 API Key」里点「刷新余额」,状态面板出现数字,两边握手完成。
装完可以用这几件事自查:
| 检查 | 通过的样子 |
|---|---|
| 运行时 | 立绘出现,单击有台词和动作 |
| 宿主通信 | 状态面板有 CPU / 内存 / 余额数字,刷新余额会变化 |
| 三块接管 | Agent 提问弹在桌宠、越权审批弹在桌宠、长按立绘有任务播报 |
| 卡片模式 | 不加载立绘,桌面只剩审批与提问卡片,其余区域点击穿透 |
它现在能做什么
| 能力 | 状态 |
|---|---|
| 透明无边框置顶窗口 | ✅ |
| Live2D 模型渲染(moc3 + 物理 + 纹理) | ⚠️ 需自备模型与运行时,公开包不含 |
| 12 个表情 / 5 组动作 / 自动眨眼与呼吸 | ⚠️ 仅 Live2D 形象可用 |
| 视线跟随鼠标 | ✅(Live2D 形象可用) |
| 点击命中区域触发表情与动作 | ✅ |
| 鼠标拖拽移动、拖到屏幕边缘吸附贴边 | ✅ |
| 窗口位置与缩放记忆 | ✅ |
| 非立绘区域点击穿透,不挡桌面操作 | ✅ |
| 气泡台词轮换、说话时口型动画 | ✅ |
| 自定义形象:单图 / GIF / 视频 / 多帧 sprite / Live2D 五类 | ✅(Live2D 需自备) |
| 内置背景:9 张(7 张官方插画 + 夜色 / 樱两张),可固定、轮换或换成自己的图片 | ✅ |
| 陪伴数据同步:好感、身体状态、念头、开口 / 消费账本、小游戏战绩按文件合并 | ✅ |
| 设置合并:网页设置与桌宠窗口同时改,按字段合并,不互相覆盖 | ✅ |
| QQ 官方机器人远程拍板:审批与提问可以在 QQ 里处理 | ✅ |
| 好感与主动开口:会记住相处方式,也会在合适的时候先说话 | ✅ |
| 记忆注入:新会话会带上固定、常提、最近的几条记忆;日常发言里的自述与偏好也会自动记下 | ✅ |
| 陪伴状态概览:关系档 / 今日开口 / 记忆条数 | ✅ |
| 能力中心:石头剪刀布 + 本地战绩 | ✅ |
| 最近会话:标题列表 + 点开看最近十条(只读) | ✅ |
| 念出声:系统中文语音,只念主动开口 | ✅ |
| 状态面板(CPU / 内存 / GPU / 网速 / 电量 / 余额) | ✅ |
| 状态面板三档详细度 + 折叠 | ✅ |
| dsh 设置页「昔涟 · 桌宠」卡片:启动 / 重启 / 关闭、人格编辑、记忆管理、能力中心 | ✅ |
| 右键菜单(换形象 / 一键归位) | ✅ |
| 设置浮层(昵称 / 缩放 / 气泡 / 状态栏 / 提问 / 互动 / 余额) | ✅ |
| DeepSeek 余额与今日消费 | ✅ |
对话提问由桌宠逐题接管(ask_user_question,四种模式) |
✅ |
风险审批(approval/request):桌宠里「允许一次 / 拒绝」 |
✅ |
任务进程:读 todos 投影,长按播报当前进度 |
✅ |
| 系统托盘 | ✅(无托盘图标资源时自动跳过) |
架构总览
桌宠分成两层:lib/ 跑在 dsh 进程里,管设置、余额、会话桥、提问审批、QQ 通道;pet/ 是独立的 Electron 窗口,只管画立绘、接鼠标、气泡和设置面板。一次对话走五段:输入归一化 → 状态写入与存储 → 召回与拼装 → 模型 → 输出与回写。
下面三张图出自 2026-11-10 的全链路审计,按真实调用点绘制,不以注释和命名判断。实线是通的,虚线是空转或断点。
主链路
flowchart LR
subgraph IN[输入]
A1[桌面 IPC / 桌面 /send]
A2[QQ 桥 私聊 + 群]
A3[DSH 会话]
A4[识屏 / 天气 / IP / 余额]
A5[图片]
end
subgraph NORM[归一化]
B[text / spoken / scope / source / speaker]
end
subgraph STATE[状态写入]
C1[记忆抽取<br/>六类句式]
C2[结构化事实<br/>inner-state 断言]
C3[关系事件<br/>bond / closeness / irritation]
C4[精力结算<br/>body]
C5[日程 ensure<br/>agenda]
C6[情绪识别<br/>local-emotion]
C7[群画像 / 梗库]
end
subgraph STORE[存储]
D1[(memory.json<br/>明文)]
D2[(facts.json 加密)]
D3[(bond.json 加密)]
D4[(body.json 加密)]
D5[(agenda-runtime.json)]
D6[afterglow / needs]
D7[lastEmotionText]
end
subgraph RECALL[召回]
E1[memoryText<br/>默认关闭]
E2[factNote]
E3[affinityNote]
E4[bodyNote]
E5[companionNote<br/>心情/日程/话头/表情]
E6[reviewNote<br/>仅 QQ]
E7[intimacyNote<br/>仅桌面]
E8[socialNote<br/>随句变化]
end
subgraph PROMPT[开口拼装]
F[buildPromptSections<br/>stable + turn]
F1[stable:persona 无上限 + source 200 + social 300]
F2[turn:memory 600 / fact 400 / companion 500<br/>affinity 200 / review 200 / body 200<br/>intimacy 420 / proactive 200 / sticker 300]
end
subgraph MODEL[模型]
G[DeepSeek 请求<br/>7 路并发取数,memoryText 无超时]
end
subgraph OUT[输出]
H1[parseEmojiTag<br/>图:id]
H2[parseStickerTag<br/>表情:标签]
H3[guardReply<br/>清控制标签 / 并复读]
H4[群聊引用归属纠正]
H5[filterIntimacy 红线]
H6[气泡 / 立绘 / TTS]
H7[QQ splitReply<br/>≥90 字拆 2 条]
end
subgraph BACK[回流]
I1[historyTurns + persistTurn]
I2[onExchange 记忆写入]
I3[companion.endTurn<br/>话头 / 表情降权]
end
A1 --> B
A2 --> B
A3 --> B
A4 --> B
A5 -.不进模型.-> X1[空转:入表情库]
B --> C1 --> D1 --> E1
B --> C2 --> D2 --> E2
B --> C3 --> D3 --> E3
B --> C4 --> D4 --> E4
B --> C5 --> D5 --> E5
B --> C6 --> D6 --> E5
C6 --> D7 -.无读取.-> X2[空转]
B --> C7 --> E8
E1 --> F
E2 --> F
E3 --> F
E4 --> F
E5 --> F
E6 --> F
E7 --> F
E8 --> F1
F --> F1
F --> F2
F1 --> G
F2 --> G
G --> H1
G --> H2
H1 --> H3
H2 --> H3
H3 --> H4 --> H5
H5 --> H6
H5 --> H7
H5 --> I1
H5 --> I2
H5 --> I3
I3 -.下一轮.-> E5
memoryText 在早期草稿里被记成「恒空」,第四轮补审后修正为「默认关闭」:开关打开后链路是通的,只是回写不等待,也没有超时。图里其余断点(图片不进模型、lastEmotionText 无读取方)均在代码里可复核。
单轮数据流
同一轮对话拆得更细,标出了每一处断点在代码里的位置。
flowchart TB
subgraph IN[输入]
I1[桌面 IPC / send]
I2[QQ webhook / bridge]
I3[主动开口]
I4[图片]
end
subgraph GATE[入口与闸门]
G1[scopeOf<br/>desktop / qq:private / qq:group]
G2[enabled / provider / busy / rate / budget / key]
G3[matchWake → spoken]
end
subgraph READ[并行取数]
R1[historyTurns = bucketFor scope]
R2[getMemoryDigest<br/>BM25 + 可选向量]
R3[companion.beginTurn]
R4[fact / affinity / body / intimacy / social / sticker]
R5[getCompanionExtra<br/>日程 / 承接 / 穿搭 / 环境]
end
subgraph BUILD[拼装]
B1[buildPromptSections<br/>stable + turn]
B2[system + trimTurns history + user]
end
subgraph MODEL[模型]
M1[DeepSeek chat completions]
M2[工具轮循环<br/>共享 AbortController]
end
subgraph CLEAN[清洗]
C1[parseEmojiTag]
C2[parseStickerTag]
C3[guardReply]
C4[cleanVoice]
C5[fixMisattributedQuote]
C6[filterIntimacy]
end
subgraph SINK[输出与回写]
S1[气泡 / 立绘]
S2[TTS planSpeak]
S3[QQ splitReply]
S4[historyTurns.push]
S5[companion.endTurn]
S6[onExchange async 未 await]
S7[persistTurn 同步调用]
S8[QQ 主动开口不拆]
S9[stickerNote 混排]
end
subgraph AUX[支线数据流]
A1[社交画像 / 梗词典<br/>getSocialNote 每条群消息同步跑]
A2[B 站 API / 写动作 / 动态]
A3[设置同步 sync + syncCrypto]
A4[日程 daily-plan / agenda-runtime / moment-clock]
end
I1 --> G1
I2 --> G1
I3 --> G1
I4 -.不进模型.-> X1[stickerInbox]
G1 --> G2
G2 --> G3
G3 --> R1
G3 --> R2
G3 --> R3
G3 --> R4
G3 --> R5
R1 --> B2
R2 --> B1
R3 --> B1
R4 --> B1
R5 --> B1
B1 --> B2
B2 --> M1
M1 --> M2
M2 --> C1
C1 --> C2
C2 --> C3
C3 --> C4
C4 --> C5
C5 --> C6
C6 --> S1
C6 --> S2
C6 --> S3
C6 --> S4
C6 --> S5
C6 --> S6
C6 --> S7
S4 -.下一轮.-> R1
S5 -.下一轮.-> R3
S6 -.下一轮.-> R2
S7 -.重启.-> R1
G2 -.检查与置位之间有 6 个 await.-> X2[并发窗口]
R2 -.无超时.-> X3[整轮悬挂]
S6 -.async 未 await.-> X4[记忆写丢 / 异常逃逸]
R1 -.桶永不释放.-> X5[内存累积]
S7 -.hydrate 丢 scope.-> X6[assistant 归桌面]
R2 -.memoryEnabled 默认 false.-> X7[默认无长期记忆]
G1 -.openId 为空.-> X8[同类型会话共桶]
C6 -.主动开口.-> S8
S3 -.汇报拼在 reply 后.-> S9
S3 -.首条成功补发失败.-> X9[部分发送记成功]
R4 -.每条群消息.-> A1
A1 -.O(k²) 同步计算.-> X10[群消息阻塞主进程]
A1 -.重复 observe 同批样本.-> X11[词典 seen 虚高]
A2 -.policy 缺省.-> X12[写操作崩溃]
A3 -.apply 后才 ack.-> X13[崩溃窗口重复合并]
A4 -.质量闸只查总时长.-> X14[偏移的一天能过]
主链本身是通的,真正的断点在「等待与互斥」:busy 的检查与置位之间夹着 6 个 await;记忆摘要没有超时;onExchange 是 async 却没有 await。记忆链的默认状态是断的,因为 companion.memory.enabled 默认 false。
人格层链路
人格提示词确实在驱动参数,但这条管道是单向的:参数从不回流到提示词。七段决定「她是谁」,7 个参数只决定「她多久开口、多久消气、好感涨多快」。
flowchart LR
subgraph IN[人格输入]
P1[七段:身份 / 身世 / 世界观<br/>人生观 / 价值观 / 相处 / 表达]
P2[昵称]
P3[记忆 8 条 × 200 字]
P4[额外说明]
P5[此刻:心情 / 关系阶段<br/>烦躁 / 精力]
end
P1 --> B[buildPersonaPrompt]
P2 --> B
P3 --> B
P4 --> B
P5 --> B
B --> TXT[完整提示词文本]
TXT --> LLM[模型]
TXT --> D[deriveTraits<br/>5 类关键词]
D --> T8[7 个速度参数<br/>+ recallBias]
Q[六维问卷 24 题] --> QD[traitsFromDimensions]
QD --> T8
T8 --> R[runtime traitsNow]
R --> SCH[开口间隔 / 精力消耗<br/>好感涨速 / 消气 / 亲近门槛]
R --> NOW[烦躁档判定]
Q -.只显示草稿.-> UI[设置页 personaDraft]
P3 -.关键词污染.-> D
P4 -.关键词污染.-> D
P5 -.关键词污染.-> D
问卷六维被压成同一组参数,personaDraft 只显示、不回填。代码里的「8 个维度」是 7 个速度参数加 1 个念旧倾向,全部是节奏维度,没有表达形态维度。
反思 / 召回 / 筛选 / 选择 / 时间那张专题图更细,留在审计台账里。
开发与测试
lib/vault/ 是密钥仓库。它把 API Key 加密后存在本机,配置文件里只留解密不了的密文。仓库自带一份只依赖 node 原生模块的测试:
npm test
# 只跑单个文件
node --test test/vault.test.mjs
npm test 会依次跑六个文件:vault、persona、session-bridge、companion-sync、companion-runtime、ability。
测试覆盖 vault 加解密(写入取回、密文不含明文、空 key 拒绝、错误口令、密文篡改检测)、人格注入、会话桥、陪伴层同步、宿主节奏与能力中心。
公开安装包为控制体积不带 test/,要跑测试请从源码仓库检出完整目录。测试只依赖 Node 原生模块,Node 18 以上直接 npm test,不需要 npm install。
下载
| 来源 | 地址 |
|---|---|
| GitHub Release | cyrene-pet-dsh-2.0.0.zip |
| 源码包 | v2.0.0.zip |
| 夸克网盘 | 旧版安装包 |
- 安装包:cyrene-pet-dsh-2.0.0.zip(约 80 MB,含全套立绘表情素材)
- 打开方式:复制链接后在浏览器访问,或打开夸克 APP 自动识别。
- Release 附件即完整安装包,解压到任意目录后
dsh plugin --profile desktop add <目录>即可安装。 - Release 页同时提供 SHA-256,下载后可以核对完整性。
安装
方式一:从压缩包
解压后把整个 dsh-cyrene-pet/ 目录放到 dsh 的插件目录,再注册:
dsh plugin --profile desktop add <解压后的 dsh-cyrene-pet 目录>
方式二:从源码目录
dsh plugin --profile desktop add <本目录>
装好后需要重启 dsh,插件会在启动时自动部署桌宠运行时并拉起桌宠进程。
首次启动会做什么
桌宠复用 dsh 自带的 Electron 运行时,不额外下载一套。首次启动时自动执行:
- 在
~/.dsh/storages/cyrene-pet/runtime/下,用硬链接复制 dsh 安装目录里的 Electron 文件(必须与 dsh 同盘;跨盘时硬链接会被系统拒绝,改用复制) - 删除
resources/app.asar,把resources/app目录链接到本插件的pet/目录 - 用这个运行时启动
DeepSeek Harness.exe --no-sandbox
resources/app 是目录链接,所以改 pet/ 下的代码后重启桌宠进程即可生效,不需要重新部署运行时。
宿主若以 Node 模式运行(
ELECTRON_RUN_AS_NODE=1,用 Electron 二进制跑 Node),桌宠会被当成 Node 直接退出。宿主半在 spawn 时会把这个标记从子进程环境里摘掉;手动排查时也记得先Remove-Item Env:ELECTRON_RUN_AS_NODE。
卸载与重装
- 右键桌宠 →「换形象」→「数据」→「桌宠进程」→ 关掉桌宠。
- 在 dsh 里移除插件。
- 需要彻底清理时,再删除
~/.dsh/storages/cyrene-pet/(设置、账本、运行时都在里面)。
只删插件目录不会自动清掉 ~/.dsh/storages/cyrene-pet/,下次装回来设置还在。
安全边界
- 渲染层保持
contextIsolation: true、nodeIntegration: false,preload 只暴露窗口控制、背景图与命令 IPC,没有fs直通。 - 页面 CSP 只允许
'self' pet-media: data:,不加载远程脚本。 - 形象素材与 Live2D 模型走
pet-media://local受限协议,只映射plugin/与models/两个根,越界路径直接 404;渲染层sandbox: true、webSecurity: true。 - 宿主 Electron 本身若以
--no-sandbox启动,那是宿主启动参数,插件不再额外放开渲染层沙箱。 - API Key 存在 Vault 密文里,不写进
state.json,也不会出现在日志、备份说明或前端状态快照中。
日常怎么用
立绘与窗口
- 拖动立绘移动窗口,松手后自动贴边。
- 单击立绘:随机台词 + 动作。
- 长按立绘:说一遍当前任务进度。
- 立绘以外的透明区域点击会穿透,不挡桌面操作。
- 窗口位置和缩放会记住,下次启动还原。
换形象(单图 / GIF / 视频 / 多帧 / Live2D)
设置 →「她的样子」→「形象素材」。五种素材各有用处:
| 类型 | 适合什么 | 说明 |
|---|---|---|
| 单图 | 一张立绘 | 最省资源,静态显示 |
| GIF | 循环小动画 | 按原速循环播放 |
| 视频 | 更长的动作或氛围 | 跟随窗口尺寸铺满 |
| 多帧 sprite | 逐帧动画 | 按帧序列播放,适合手绘小动效 |
| Live2D | 手里已有模型的人 | 需要自备模型与运行时,公开包不含 |
- 素材通过
pet-media://local受限协议读取,只认plugin/与models/两个根,越界路径直接 404。 - 换形象会重新加载渲染层;切换前先把当前设置落盘,避免刚调的缩放或气泡样式被冲掉。
- 没有合适的图时,公开包里的
assets/default.png就是默认形象,不影响其他功能。
桌面背景
设置 →「她的样子」→「桌面背景」。背景是窗内壁纸,不会改系统桌面。
- 内置 9 张:
builtin-cyrene-01~07是官方插画,另外两张是builtin-night(夜色)与builtin-sakura(樱)。 - 自定义:上传的图片会复制进数据目录
backgrounds/,换版本、重装插件都不会丢。 - 淡化:遮罩浓度 0 ~ 0.85。数值越高,背景越淡,人物越突出。
- 轮换:填分钟数后按间隔自动换下一张;填
0表示不轮换。 - 「下一张」可以立即切到下一张,不用等轮换时间。
- 删除只删数据目录里的副本,内置图不受影响。
卡片模式(没有立绘也能用)
如果你已经有自己的桌宠形象,只想让 dsh 的审批和提问有个不占地方的落点,可以把界面模式切成「只显示审批卡片」:
- 右键 →「换形象」→「界面模式」→「只显示审批卡片」,保存后桌宠会自动重开。
- 窗口缩成 380 × 240 的透明小窗,不加载 Live2D,也不显示状态栏、气泡和右键菜单。
- 有审批或提问时,卡片出现在窗口里,点「允许一次 / 拒绝」即可;其余时间整窗点击穿透,不挡桌面操作。
- 卡片收起后窗口留在原地,不抢焦点,也不占任务栏。
- 想切回完整立绘:托盘图标 →「打开设置」→「界面模式」→「完整立绘」。卡片模式没有右键菜单,托盘是固定入口。
卡片模式仍然保留完整能力:对话提问接管、风险审批、托盘菜单和设置里的所有选项都能用,只是不再渲染立绘与状态面板。打开设置时窗口会临时放大到 480 × 560,关掉设置再缩回卡片大小。
右键菜单
右键立绘或状态面板,只有两个入口:
- 换形象:直接打开设置里的「她的样子」,换立绘、调背景都在这一页
- 一键归位:把桌宠拉回主屏右下角
其余互动收在设置页与长按里:长按立绘播报任务进度,单击说一句随机台词。
设置浮层
右键 →「换形象」,左侧五个分组。第一次打开会先显示三步引导(挑形象 / 填 Key / 调声音),点「知道啦」后不再出现:
| 组 | 设置项 |
|---|---|
| 概览 | 当前关系与状态、常用动作、三步上手 |
| 她的样子 | 界面模式(完整立绘 / 只显示审批卡片)、昵称、缩放、气泡字号 / 形状 / 不透明度、形象素材、状态栏、桌面背景(上传 / 淡化 / 删除 / 自动轮换 / 下一张) |
| 说话与互动 | 自动换姿势、音效、念出声、闲聊提问、对话与审批模式 |
| 人格 | 启用开关、七段(身份 / 来历 / 世界观 / 生活观 / 价值 / 说话方式 / 风格)、额外设定 |
| 数据 | 余额与 API Key、桌宠进程、备份与恢复 |
几条合并规则:
- 「开启提问 + 提问间隔」合并为一个下拉,选「关闭」即原来的关闭。
- 「自动换姿势 + 间隔」合并为一个下拉,选「关闭」即原来的关闭。
- 「音效开关 + 音量」合并为一个下拉,选「关闭」即静音。
- 念出声默认关闭;打开后只用系统中文语音念主动开口的气泡,余额、审批和任务提示不念。离线可用,之后接本地 TTS 时只换引擎。
- 气泡字号三档,气泡形状去掉了 2px 这一档,气泡模式去掉了「只显示余额数字」。
- 余额刷新固定 30 秒缓存,设置里不再单列。
- 旧的
avatar、x、y三个从未生效的字段已移除。
旧版 state.json 会在加载时自动迁移:askEnabled: false → askEveryMinutes: 0,idlePose: false → poseSeconds: 0,soundEnabled: false → soundVolume: 0。
API Key 的解析顺序:设置面板填写的 Key → 环境变量 DEEPSEEK_API_KEY → ~/.dsh/.credentials.yaml 里的 DEEPSEEK_API_KEY。已经用 dsh 登录过 DeepSeek 的机器不需要再填一次。
陪伴模块
她有一份自己的状态,不靠一个好感数字撑起来。数据落在 ~/.dsh/cyrene-pet/ 下的几个 JSON 里,分三层。
| 层 | 文件 | 管什么 |
|---|---|---|
| 好感 | bond.json |
三个维度、事件记录、每日上限、关系档 |
| 状态 | body.json、thoughts.json、inner-state |
身体状态、念头、情绪余韵 |
| 节奏 | opening.json |
今天主动开口几次、被接住几次、要不要安静几天 |
好感分三个维度
| 维度 | 范围 | 起始 | 会怎么变 |
|---|---|---|---|
亲近 affinity |
-100 ~ 100 | 0 | 你找她说话、贴近一会儿会涨;被冷落会掉,也能被哄回来 |
信任 trust |
0 ~ 100 | 50 | 安慰、道歉被接住、疲惫被体贴时涨,掉得很慢 |
熟悉 familiarity |
0 ~ 100 | 0 | 共同经历堆出来的,只增不减 |
关系档按熟悉度分四段:还陌生(0)、认识(15)、熟悉(40)、亲近(70)。
事件与每日上限
每次互动按事件表记一笔,不是想加就加:
| 事件 | 维度 | 单次 | 每日净上限 |
|---|---|---|---|
| 你主动找她说话 | 亲近 | +1 | +20 |
| 一起在 DSH 里忙了一阵 | 熟悉 | +1 | +3 |
| 贴近了一小会儿 | 亲近 | +2 | +6 |
| 她难过时你安慰了她 | 信任 | +2 | +6 |
| 她认错,你接住了 | 信任 | +2 | +4 |
| 她有点生气,你哄好了 | 亲近 | +2 | +4 |
上限管的是「每天净变化」:正向封顶,负向封底。规则放在可覆盖的 JSON 里,想调数值不必改代码。
会安静,也会自己回来
连续几次主动开口都没被接住,概览里会标「先安静几天」,她不会一直问。安静时段与作息由 quiet-hours、schedule 控制,避免半夜弹气泡。
记忆模块
dsh 设置页的「昔涟 · 桌宠」卡片里展开「她记住的事」,可以看四槽记忆(身份 / 偏好 / 事件 / 关系)、按槽新增、固定 / 取消固定,以及二次确认后忘掉一条。
固定条目不会随时间衰减,也不参与清理;普通条目按 30 天半衰期淡出。这里写入的 memory.json 同时供主动开口的记忆回访和会话里的记忆召回使用。
会话这边会把固定、常提、最近的记忆取前 8 条,拼成「你记得的事」放进人格提示词,所以新会话也能接住上次的话。记忆增删改后会马上重挂;内容没变化时不动系统提示,避免每轮都刷新 prompt。
除了手动添加,桌宠也会从最近的用户发言里自动挑出「我叫…… / 我喜欢…… / 我最近在……」这类明确自述,写进 memory.json。代码、问句和太长的句子会被跳过,同一句话只累计提及次数,不会重复入库。
记忆的进出规则
| 项目 | 行为 |
|---|---|
| 存储 | 本机 memory.json,不进 DSH 会话历史 |
| 衰减 | 普通条目按 30 天半衰期淡出 |
| 固定 | 不衰减、不参与清理,只有手动取消或删除 |
| 注入 | 只取固定、常提、最近的 8 条,不把全部记忆塞进提示词 |
写入有三条路:
- 设置页按槽新增、固定、取消固定,或二次确认后忘掉一条。
- 日常发言里的明确自述自动入库,就是上面那段规则。
- 对话里出现明确要记住的意图时,
memory-intent.mjs判断该不该写,memory-guard.mjs在落盘前再过滤一次,避免把一时的情绪或敏感内容当成长期事实。
检索分两条:memory-search.mjs 负责「她记不记得这件事」,memory-facts.mjs 负责「这件事具体是什么」。两者都不直接改写原始记忆,只读。
功能中心(能力中心)
入口在 dsh 设置页「昔涟 · 桌宠」卡片。
概览只放三件能一眼看懂的事:
| 显示 | 含义 |
|---|---|
| 关系档 | 还陌生 / 认识 / 熟悉 / 亲近 |
| 今日开口 | 今天主动说了几次 |
| 记忆条数 | 四槽里现在有多少条 |
连续几次没被接住时,会多一个「先安静几天」的标记,方便确认她为什么突然不说话了。
陪她玩一局
石头剪刀布。胜 / 负 / 平、胜率、当前连胜都写在本机 ability.json:
- 不进 DSH 会话,不占上下文。
- 不参与好感计算,输赢不改变关系档。
- 关掉桌宠后战绩还在;删掉
ability.json就清零。
陪伴数据同步与设置合并
这是两套不同的机制,别混在一起。
陪伴数据同步(sync-bridge.mjs)
| 项目 | 说明 |
|---|---|
| 同步范围 | bond.json(好感)、opening.json(开口账本)、body.json(身体状态)、thoughts.json(念头)、ledger.json(消费账本)、ability.json(小游戏战绩) |
| 不进入同步 | 密钥仓库、记忆密文、Live2D 模型、语音缓存、日志 |
| 时间基准 | 每条记录以文件 mtime 作为 HLC 的 wall |
| 冲突处理 | 按后写优先合并,冲突原样上报,不静默覆盖 |
| 文件完整性 | 只同步完整 JSON;写了一半的文件不参与,避免把坏文件推到别的端 |
同步桥本身不启动服务,目录、节点名和传输方式都由调用方注入。
设置合并(state-merge.mjs)
- 网页设置和桌宠窗口都能改设置,两边只提交自己改动的字段。
- 宿主按整份对象做浅合并,缺失字段保留原值,避免后写的一方抹掉先写的字段。
background、intimacy、persona、schedule是多属性对象,会再按属性合并一层。- 带
rev的客户端会做版本校验,版本过期直接拒绝;不带rev的旧客户端仍按兼容模式合并。
最近会话
设置卡片里还有一块「最近会话」:列出近期有标题的会话,点一条会在下面展开最近十条消息。这里只读,不会把内容发给第三方,也没有发送入口。当前会话由顶部任务卡单独展示,所以不会重复占位。
气泡模式
| 模式 | 内容 |
|---|---|
rotate |
台词与余额交替 |
info |
一直显示余额 |
talk |
只显示台词 |
today |
今日消费 |
状态面板与余额
状态面板默认显示 CPU、内存、GPU、网速、电量、余额。详细度三档,双击右上角 ··· 折叠。
余额来自 https://api.deepseek.com/user/balance,默认 30 秒缓存。今日消费由余额变化推断,充值不会冲掉已记录的消费。
对话提问接管
对话里 ask_user_question 的题目可以交给桌宠:宿主半把整批题目写进 live.json 的 ask 字段(带 source: "conversation"),桌宠用提问气泡逐题问,答完一次性回传。
「设置 → 提问 → 对话与审批」有四种模式(风险审批也按同一个模式走):
| 值 | 行为 |
|---|---|
pet-all(默认) |
桌宠逐题问。一批多题时气泡里显示「第 2/3 题」,答完整批一起交回;某题点「跳过」就记成空选项 |
pet-single |
桌宠只接单题批次,多题批次直接交给网页卡片 |
both |
网页卡片照常弹、桌宠也问,谁先答用谁的 |
web |
完全不接管,只走网页卡片 |
规则:
- 每题都带选项、且没有
intent的批次才会进桌宠;需要自由作答或plan-review审阅的整批仍交给网页卡片。 - 多选题在气泡里点选后按「答好了♪」提交;单选项点一下直接进下一题。
- 等待时长 = 题数 × 每题作答秒数(默认 30 秒,设置里可调);到时把请求
next()交还网页卡片。 - 桌宠没运行、被禁用,或已经有一批题在等回答时,新的请求直接走网页卡片。
- 回答通过
pet-command.json的{ action: "answer", askId, answers: [{ id, selected }] }回到宿主半。 - 提问到达时如果桌宠是收起状态,会自动显示出来(不抢焦点)。
风险审批
沙箱越权这类操作会走 dsh 的 approval/request waterfall,桌宠接在同一条链路的入口。
- 气泡显示「想请你批准一下」,正文是「工具名 + 想越权执行」和本地化理由(
displayReason优先中文,退回英文,再退回审计原因)。 - 只有两个决定:允许一次 / 拒绝,结果原样回给审批服务(
allowed-once/rejected)。 - 60 秒没决定、请求被撤回或桌宠没运行,就交还网页卡片;撤回按
cancelled结算。 - 审批和对话提问共用「设置 → 对话与审批」这一个模式开关。
- 同一时间只挂起一个审批,第二个请求会走网页卡片。
QQ 通道:远程拍板与提问
出门在外也能回一句「允许」,不用守着电脑。走 QQ 开放平台的官方机器人,不依赖任何第三方协议端。
这条通道只做两件事:把需要你拍板的请求推到 QQ,把你的回复带回来。它不是聊天窗口,下面会写清边界。
设置 → 说话与互动 → QQ 远程拍板:
| 字段 | 说明 |
|---|---|
| 启用官方通道 | 打开后才会监听 webhook |
| AppID | 开放平台机器人页面的 AppID |
| AppSecret | 只写进本机密文仓库 qq.vault.json,state.json 与设置页都不回显 |
| 主人 openid | 只有这几个 openid 能拍板,留空时谁都拍不了 |
| 发到哪 / 目标 openid | 私聊(c2c)或群聊(group)以及对应 openid |
| Webhook 端口 | 默认 17321,路径默认 /qq/webhook |
能做什么、做不到什么
| 能做 | 做不到 |
|---|---|
收到审批请求,回「允许 / 拒绝」或 1 / 2 |
自由聊天、主动闲聊 |
| 收到一批提问,逐题作答 | 发图片、表情包、文件 |
| 私聊(c2c)或群聊(group)二选一 | 在同一个群里分别跟不同人对话 |
| 最多 5 个主人 openid | 非主人拍板 |
- 服务只绑
127.0.0.1;要让 QQ 回调进来,自己用 cloudflared / frp 之类的隧道转发,开放平台里填隧道地址。 - 签名校验不过返回 401,非 POST 返回 405,请求体上限 256KB。
- 卡片只带「工具名 + 一句理由」,不复制 context、prompt、消息正文;回复会被亲密层过滤后再发出去。
- 主人回复「允许 / 拒绝」(或
1/2)才算数;非主人只能问,不能拍板。 - 超时或通道掉线,决定权原样交还桌宠与网页卡片,不会自行放行。
表情包
她有自己的表情包,也能把聊天里看到的图收进来。这一层在 packages/companion-core 里已经完整提供(sticker-library.mjs、sticker-inbox.mjs),dsh 插件当前还没有对应的界面入口,所以下面写的是能力本身和素材协议。
挑图与发送
表情清单汇总成一份,给聊天层挑图、预览页展示、QQ 发送共用。
- id 是「来源:相对路径」,渲染层只传 id,绝对路径由主进程自己还原,不接受任意路径。
- 扫描结果缓存 30 秒,一句话里问几次不会反复读盘。
chat=false的目录只用来兜底解析历史图片,不参与挑图。listed=false的目录不出现在预览页,避免把别人的图混进她的表情包。
收图与入库
QQ 里收到的图不会直接进素材包:
| 阶段 | 位置 | 说明 |
|---|---|---|
| 收到 | packs/.inbox |
先落待审核队列;以点开头,不会被当成素材包 |
| 审核 | 预览页 | 点「入库」才移动到 packs/<packId>/emoji |
| 自动收下 | packs/qq-auto/emoji |
满足条件的小图直接归到这个包,和手动入库分开 |
限制:
- 同一张图按内容指纹去重,只收一次;重复出现只累计
seenCount。 - 指纹表最多留 2000 张;待审核最多 200 张,超出从最旧的开始丢。
- 自动收下的上限是 1.6 MB、最长边 1024 px;更大的更像照片或截图,留给人工判断。
任务进程
桌宠宿主半读 dsh 的 todos 会话投影(dsh-tool-todo 写的那份),把最近一次活动的根会话里的任务写进 live.json 的 todos 字段。
- 任务面板列出任务清单(最多 6 条,
✓已完成 /▶进行中 /·待办),显示「任务进程 x/y 完成」。 - 长按立绘口头播报进度,例如「任务 2/5 完成,正在做『接入任务进程』,还排着 2 件…」。
- 面板会挡住气泡,所以完整清单放在右键菜单「任务进程」里看。
- 只跟根会话走:子代理的会话不会顶掉你正在做的任务。
常见场景怎么设
| 想要的效果 | 建议 |
|---|---|
| 专心工作,不想被桌宠打断 | 提问模式选 web,或把「闲聊提问」选「关闭」 |
| 边工作边顺手回答 Agent | 保持默认 pet-all,桌宠会逐题问 |
| 怕点错授权 | 保持 pet-all,审批只在桌宠里点「允许一次」或「拒绝」;不放心就选 web 回网页卡片 |
| 桌宠太挡视线 | 拖到屏幕边缘自动贴边,或在设置里改缩放;透明区点击穿透 |
| 只想看余额 | 气泡模式选 info 或 today |
| 觉得动作太频繁 | 「自动换姿势」调长或关闭 |
| 换电脑 | 插件目录可以直接带走;API Key 绑在本机,新机器上要重新填一次 |
| 已经有自己的桌宠形象 | 界面模式选「只显示审批卡片」,不加载立绘,只保留审批 / 提问卡片 |
| 切了卡片模式想换回来 | 托盘图标 →「打开设置」→「界面模式」→「完整立绘」 |
| 想让背景更自然 | 「她的样子 → 桌面背景」把遮罩浓度调低,直到人物边缘和背景不打架 |
| 背景想每天都不一样 | 桌面背景里填轮换分钟数(例如 1440 表示一天一换),填 0 关闭 |
| 在外面也想处理审批 | 「数据 → QQ 远程拍板」填 AppID / AppSecret,把隧道地址填进开放平台 |
| 换电脑保留好感与账本 | 「数据 → 备份与恢复」导出 JSON,新机器导入后再填一次 Key |
常见问题
装完桌宠没出现
- 确认 dsh 已经重启过,插件是在启动时拉起桌宠进程的。
- 看
~/.dsh/storages/cyrene-pet/有没有生成runtime/。没有生成说明宿主半没跑起来,先看 dsh 日志里插件有没有加载失败。 - 有
runtime/但进程刚起就退,删掉runtime/再启动 dsh 重新部署。 - 如果 dsh 是用 Electron 二进制跑 Node(
ELECTRON_RUN_AS_NODE=1),先清掉这个环境变量再试。
立绘出现但白屏
多半是 resources/app 链接失效,或者 app.asar 被 dsh 升级重建了。关掉 dsh,删 ~/.dsh/storages/cyrene-pet/runtime/,再启动。
状态面板没有数字
状态面板的数据来自宿主半挂在 dsh webServer 上的路由。先重启 dsh 和桌宠;仍然没有,就看 dsh 是否改了本地服务端口、路由前缀或鉴权方式。
余额一直不更新
- 余额默认 30 秒缓存,刚充值或刚跑完任务时会有延迟。
- Key 的解析顺序是:设置里填的 →
DEEPSEEK_API_KEY→~/.dsh/.credentials.yaml。三处都没有就会显示为空。 - 今日消费由余额变化推断,第一次启动当天从 0 开始累计,不是平台账单的实时数字。
提问没有弹在桌宠
- 检查「设置 → 说话与互动 → 对话与审批」是不是
web。 - 只有「每题都带选项、且没有
intent」的批次才会进桌宠;自由作答和plan-review会回网页卡片。 - 已经有一批题在等回答时,第二批直接走网页卡片。
- 每题作答时间默认 30 秒、可在设置里调,多题按题数累加;超时就交还网页卡片。
审批只有一个按钮能点
审批只提供一次性授权:允许一次 / 拒绝。没有「总是允许」,也没有规则记忆。同一时间只挂起一个审批。
换了背景没变化
- 确认点的是「保存」,不是只选了图。
- 遮罩浓度太高时背景会几乎看不见,把它调低。
- 轮换填
0时不会自动切;点「下一张」可以立即验证是否生效。
想彻底卸载
- 右键桌宠 →「换形象」→「数据」→ 关掉桌宠。
- 在 dsh 里移除插件。
- 手动删除
~/.dsh/storages/cyrene-pet/(设置、账本、背景、运行时都在里面)。
只删插件目录不会清掉数据目录,下次装回来设置还在。
换电脑能不能直接带走
插件目录可以带走,但 secret.vault.json 绑本机解锁,API Key 要重新填一次。陪伴数据可以走备份导出再导入。
记忆保存在哪,怎么删
记忆在 ~/.dsh/storages/cyrene-pet/ 下(memory.vault.json 与兼容用的 memory.json)。界面上在 dsh 设置页「昔涟 · 桌宠」→「她记住的事」里删;固定条目不会被时间衰减,需要先取消固定。
QQ 收不到审批消息
- 服务只绑
127.0.0.1,公网回调要靠 cloudflared / frp 之类的隧道,开放平台里填隧道地址。 - 签名校验不过会返回 401;确认 AppSecret 填的是当前机器人那一份。
- 只有「主人 openid」列表里的账号能拍板,留空时谁都拍不了。
- 通道掉线或超时,决定权会交还桌宠与网页卡片,不会自行放行。
Agent(dsh)升级后可能产生的后果
桌宠依赖 dsh 的内部结构和它自带的 Electron 运行时。dsh 升级不一定坏,但下面这些情况需要知道。
1. 运行时副本失效
现象:重启 dsh 后桌宠不出现,或进程刚起就退出。
原因:~/.dsh/storages/cyrene-pet/runtime/ 里的 Electron 是从旧安装目录硬链接/复制来的。dsh 换安装路径、换 Electron 主版本、或重装后,旧副本指向的文件已经不存在或版本不匹配。
处理:关掉 dsh,删除 ~/.dsh/storages/cyrene-pet/runtime/,再启动 dsh,插件会重新部署。
2. app.asar 结构变化
现象:桌宠启动后白屏,或 resources/app 链接指向错误位置。
原因:插件会把 resources/app.asar 删掉,换成指向 pet/ 的目录链接。dsh 升级如果重建了 app.asar,或改变了 resources 布局,链接会被覆盖。
处理:删除 runtime/ 重新部署;仍不行就检查 resources/ 下是否又出现了 app.asar。
3. 插件 API 或注入点变化
现象:设置页「昔涟 · 桌宠」卡片消失;提问/审批不再弹在桌宠;控制台报 ctx.tools、ctx.webServer、sessionProjections 之类找不到。
原因:宿主半用的是 dsh 的插件接口(tools、webServer、approval/request、sessionProjections)。这些接口在 dsh 大版本升级时可能改名或改签名。
处理:等插件适配新版本,或回退 dsh。升级前可以先看 dsh 的更新说明里有没有插件 API 变更。
4. 任务进程读不到
现象:长按立绘说「现在手上还没有任务卡呢」,但对话里明明有任务。
原因:todos 投影的字段或存放位置变了,或者 dsh 换了写投影的插件。
处理:这属于只读展示,不影响 Agent 本身;等适配即可。
5. 审批链路顺序变化
现象:审批不再弹在桌宠,或者网页卡片和桌宠同时弹。
原因:approval/request waterfall 的挂载顺序变了,或被别的插件抢先处理。
处理:把提问模式改成 both 观察谁在接;或临时用 web 回网页卡片。
6. 端口或 webServer 变化
现象:状态面板没数字、刷新余额没反应,但立绘正常。
原因:宿主半的 HTTP 路由挂在 dsh 的 webServer 上。dsh 改了端口、路由前缀或鉴权,桌宠轮询就会失败。
处理:重启 dsh 和桌宠;仍不行就看 dsh 是否改了本地服务的监听方式。
7. 升级时正在进行的提问或审批
现象:升级/重启 dsh 时,桌宠气泡里的问题突然消失。
原因:提问和审批都有超时,超时或进程退出会把请求交还网页卡片(审批按 cancelled 结算)。
处理:升级前先答完或取消挂起的请求,避免半途丢状态。
8. 数据兼容
state.json 的旧字段会在加载时自动迁移。但如果新版本删除了某个字段,旧值会被忽略,不会报错。ledger.json 的账本按天归档,跨版本一般能继续读。
9. 卸载或更换 dsh
桌宠运行时依赖 dsh 安装目录,卸载 dsh 后桌宠也会随之中断。重装 dsh 后需要重新部署运行时(删 runtime/ 再启动)。
10. 不保证向前兼容
插件会尽量跟着 dsh 更新,但不承诺每个 dsh 新版本都能直接用。升级 dsh 前,建议先备份 ~/.dsh/storages/cyrene-pet/。
数据文件
全部位于 ~/.dsh/storages/cyrene-pet/:
| 文件 | 作用 |
|---|---|
state.json |
插件设置(界面模式、昵称、阈值、缩放、背景、亲密层等,不含 API Key) |
secret.vault.json |
API Key 密文,绑本机解锁 |
memory.vault.json |
记忆密文(当前格式) |
memory.json |
旧格式记忆,加载时迁移到密文版本 |
live.json |
宿主半写给桌宠的实时数据(台词、余额、HUD、提问、任务) |
pet-status.json |
桌宠渲染层回报的状态(模型尺寸、HUD 位置、渲染像素统计) |
pet-window.json |
窗口位置与当前缩放 |
pet-command.json |
桌宠发回宿主半的命令(改设置、刷新余额、回答提问) |
client-seen.json |
网页客户端最后一次可见 / 心跳记录 |
heartbeat.json |
宿主半心跳 |
ledger.json |
本地消费账本(用于算今日消费) |
bond.json |
好感四维与每日事件记录(密文,绑本机) |
bonds-peers.json |
群友与陌生人的好感、烦躁(密文,绑本机) |
body.json |
身体状态(疲惫、精力等,密文,绑本机) |
thoughts.json |
念头池(密文,绑本机) |
intimacy.json |
亲密层阶段与解锁记录(密文,绑本机) |
opening.json |
主动开口账本(密文,绑本机) |
ability.json |
小游戏战绩(石头剪刀布的胜负、胜率、连胜) |
backgrounds/ |
自定义背景副本 |
speech/ |
语音缓存 |
runtime/ |
从 dsh 安装目录部署的 Electron 运行时 |
live.json 每 4 秒刷新一次,pet-command.json 每 1.2 秒轮询一次。
陪伴数据在落盘前会封装成 cyrene-sealed-v1 信封:AES-256-GCM,口令由本机 MachineGuid + 当前用户名派生,文件名也参与派生。文件被拷走、被网盘同步、被上传时都解不开;换机器或换 Windows 用户同样解不开。第一次读到旧明文时会先留一份 .plain.bak,再写密文,备份不会自动删除。备份导出与多端同步在这一层做翻译,读到/发出的是明文,落到各自机器上再按本机口令加密。
余额接口只访问 https://api.deepseek.com/user/balance,默认 30 秒缓存;今日消费由余额变化推断,充值不会冲掉已记录的消费。
备份与恢复
设置页 →「数据」→「导出备份」:
- 文件名形如
cyrene-pet-backup-2026-11-07.json,可选加密,加密后后缀是.enc.json。 - 只收陪伴数据:
bond、opening、body、thoughts、ledger、ability。 - 不收密钥仓库、记忆密文、Live2D 模型、语音缓存与日志,所以备份文件可以放心交给别人看。
- 恢复时导入同一份 JSON,按字段写回;目标版本没有的字段会被忽略,不会报错。
换机器时建议「备份 → 导入 → 重新填 API Key」三步走,比整个数据目录搬过去稳。
宿主接口
桌宠进程通过本地文件与宿主半通信,宿主半同时暴露这些 HTTP 路由(挂在 dsh 的 webServer 上):
GET /cyrene-pet/state/POST /cyrene-pet/statePOST /cyrene-pet/control(action: start | stop | restart)GET /cyrene-pet/balanceGET /cyrene-pet/hudGET /cyrene-pet/asset/:name
会话(只读)
GET /cyrene-pet/sessions:工作区与会话列表,只读文件元信息GET /cyrene-pet/sessions/recent:近期有标题的会话,供设置卡片列出来POST /cyrene-pet/sessions/bind:{ id },绑定当前会话GET /cyrene-pet/sessions/history?id=&limit=:历史消息GET /cyrene-pet/stream?id=:SSE 增量推送(ready/sync/messages/error)POST /cyrene-pet/send:固定501 { code: "send-unavailable" }
最后一条是能力边界,不是临时占位:DSH 0.2.1-rc.3 宿主侧没有可调用的发送入口,
session/prompt 是远端 claim,需要 owner peer。细节见 docs/会话接入结论.md。
桌宠的 live 数据里带 session 字段(标题、是否在生成、最后一条消息)。
陪伴(好感 / 记忆 / 开口)
GET /cyrene-pet/companion:好感概览、今日事件、记忆条数、开口账本POST /cyrene-pet/companion/bond:{ type, amount? },手动记一次好感事件GET /cyrene-pet/companion/memory:列出记忆POST /cyrene-pet/companion/memory:{ text, slot? },手动记一条POST /cyrene-pet/companion/memory/pin:{ id, pinned? },固定或取消固定一条POST /cyrene-pet/companion/memory/forget:{ id },忘掉一条
和 Cyrene 版桌宠的差别
| 能力 | Cyrene 版「昔涟 · 桌面桌宠」 | 本仓库(DSH 版) |
|---|---|---|
| 宿主 | Cyrene 客户端 | dsh + 独立的 Electron 渲染进程 |
| 立绘 | 8 种姿态、44 张小表情(静态素材) | Live2D 模型:12 个表情、5 组动作、眨眼呼吸、视线跟随(公开包需自备模型);也支持单图 / GIF / 视频 / 多帧 |
| 窗口 | 桌面透明立绘 | 透明无边框置顶、拖拽贴边、点击穿透 |
| 气泡 | 台词、提问卡、任务气泡 | 台词气泡 + 口型动画 + 四种气泡模式 |
| 状态面板 | 三档详细度 | CPU / 内存 / GPU / 网速 / 电量 / 余额,三档 + 折叠 |
| 余额 | 有 | 有(同一套 DeepSeek 接口,30 秒缓存) |
| 提问 | 提问卡 | 接管 ask_user_question,四种模式 |
| 风险审批 | — | 接管 approval/request,允许一次 / 拒绝 |
| 任务 | 任务气泡 | 读 todos 投影,长按播报 |
| 安装 | Cyrene 插件目录 | dsh plugin add 或解压到插件目录 |
和旧版 dsh-cyrene-balance 的差别
| 项目 | 旧版 | 现在 |
|---|---|---|
| 形态 | 纯工具插件,5 个余额工具 | 桌面桌宠 + 宿主半 |
| 界面 | 无 | 透明置顶窗口、Live2D、气泡、状态面板 |
| 余额 | deepseek_balance 等工具 |
桌宠显示,宿主半提供 /cyrene-pet/balance |
| 配置 | cordis.patch.yml |
设置浮层 + state.json |
| 提问 / 审批 / 任务 | 无 | 全部接管 |
| 包名 | dsh-cyrene-balance |
dsh-cyrene-pet |
内部实现与审计结论
这一节记录 2026-11-10 对 v2.0.0 的一次全链路审计。审计沿数据流逐格核对,只看真实调用点,不以注释和命名判断;问题编号分 IN-(输入)、MEM-(记忆与陪伴)、SYS-(系统)、OUT-(输出)四组,状态分「合格」「已确认」「待确认」。完整台账与逐条证据在源码仓库的 docs/audits/2026-11-10-项目审计总账.md。
总体判断
主链路是通的:输入 → 归一化 → 状态写入 → 召回拼装 → 模型 → 五道清洗 → 气泡 / TTS / QQ / 回写。问题集中在三处——同一语义有多套并行实现、默认值让闸门失效、回写是单向的。单条修能改善体感,不解决「谁是唯一真源」,下一轮还会长出同样的分叉。
六个系统性病灶
| 病灶 | 具体表现 |
|---|---|
| 同一语义多套实现 | 记忆三套、关系两套、情绪四套、时间四套、词库四套,接口之间没有唯一真源 |
| 衰减与裁剪方向反了 | decay 重复扣(越聊越淡)、trim 留归档丢活跃、clampSection 从头截、affinity 先丢对方态度 |
| 默认值让闸门失效 | confidence 默认 0.7 让 unsure 恒空;主人好感起点 60–70 让关系阶段只剩天数;dailyCap 让 minGapMs 形同虚设 |
| 写得多,读得少 | 13 槽只有 4 槽有写入入口、6 槽没有入口;反思只写不读;天气、识屏、余额只在主动开口出现 |
| 预算与优先级错位 | 11 段单项预算、没有总预算;affinity 200 字先截掉最有用的两行;companion 500 字先死表情候选 |
| 注释与代码脱节 | 「四维」实为三维;CUE_KINDS 说顺序即优先级,实际是加权随机;trim 注释与实现相反 |
修复顺序
P0:方向反了,先停损。
decay改成按「上次结算点到现在的增量」扣,不再每次调用都按总天数全量扣trim保留活跃条目,不再优先丢活跃的弱记忆- 主人好感起点降到阶段门槛以下,或把阶段分数改成归一化值
affinity与companion的裁剪顺序倒过来,先保「对方刚才的态度」和表情候选- 11 段单项预算之外补一个总预算,先定义「这一轮最该让她知道什么」
P1:接通断掉的通道。
- 人格参数推导不再读记忆、额外说明与「此刻」,避免关键词污染
deriveTraits - 六维问卷的结果回填到行为,不只改开口间隔
- 记忆回写加上
await与超时;memoryText开启后不再恒空 knowledge不再静默改名为preference- 反思结果接回下一轮,不再只落盘
- 情绪与身体状态接进开口闸门
P2:人格结构与契约。
补关系姿态(主人 / 熟人 / 生人 / 群聊的距离感)、冲突与修复(被冒犯后怎么冷、怎么道歉、怎么和好)、表达形态(句长、语气词、比喻、反问、标点)与知识边界句式;13 槽补齐或明确砍掉;两套 prompt 构建器与两套关系档表收敛。
P3:清洁与文档。
.bak 清理、注释口径统一(四轴 / 五轴、六段 / 七段)、过时文档结论、输出层 busy 与 QQ 连发策略。
审计时未确认的入口
台账里有 15 条「待确认」,需要打开真实入口才能定论。影响最大的几条:
| 编号 | 待确认 |
|---|---|
| MEM-055 | CompanionCore 是否真的导出 onUserMessage;不存在则桌面陪伴层整条静默失效 |
| OUT-001 | QQ 与桌面是否共用同一个 chatService 实例 |
| MEM-017 | 向量检索是否默认关闭,实际走意图还是向量 |
| MEM-097 | body 是否在别的层接进了开口闸 |
| MEM-127 | 桌宠 settings.json 与 DSH state 是否同一份人格参数 |
这一节记录的是审计基线,不随每次发版自动更新。已修复的条目会在台账里改成「合格」并保留原编号,方便对照。
已知限制
- 只支持 Windows 的透明置顶窗口行为
- 公开包不含 Live2D 模型与渲染运行时,默认用图片形象;要 Live2D 需自备模型
- 陪伴数据同步不覆盖
memory.vault.json,记忆不会跨端合并 - 自定义背景只存在本机数据目录,换机器要重新导入
- 运行时依赖 dsh 安装目录,卸载 dsh 后桌宠也会随之中断
- 余额接口受 DeepSeek 平台限流影响,默认 30 秒缓存一次
ledger.json只记录本插件运行期间的余额变化,首次启动时今日消费从 0 开始累计- 提问只支持「从选项里选」;需要自由输入的题、以及
plan-review审阅,仍要回网页卡片 - 同一时间只接管一批提问,第二批会走网页卡片
- 审批只提供一次性授权(
allowed-once),没有「总是允许」或规则记忆;需要长期放行请改会话的审批策略 - 卡片模式没有立绘,单击说话、表情、视线跟随、状态面板都不出现;需要这些请切回完整立绘
- 卡片模式切换会重启一次桌宠进程,正在挂起的审批会交还网页卡片
- QQ 通道目前只在本地契约、签名样例与模拟 webhook 上验证过,没有接真实开放平台账号做端到端实测;公网回调需要自己准备隧道
- QQ 通道一次只发一个目标会话,不做多群广播;换账号要重填 AppID / AppSecret
素材的最原始来源
素材分三层,从源头到本仓库:
第一层:官方原作
角色「昔涟」及《崩坏:星穹铁道》的名称、形象、服装与官方美术,著作权归 HoYoverse / 米哈游(miHoYo) 所有。本仓库与米哈游、HoYoverse 没有任何隶属、授权或合作关系。
第二层:Cyrene 客户端资源包
立绘、表情、状态面板头像等素材取自 Cyrene 客户端自带的「昔涟 · 桌面桌宠」资源包(resources/app.asar 内):
assets/ui/cyrene-thinking-loop/:情绪特写与状态面板立绘dist/renderer/stickers/:44 张小表情dist/renderer/icons/mimi.png:状态面板头像pet/assets/live2d/cyrene/:Live2D 模型(model.moc3、model.physics3.json、12 个表情、5 组动作、texture_0.png);公开包不含此目录
Live2D 模型由 B 站 UP 主 @是依七哒 制作,经 Cyrene 资源包引入。本仓库不主张该模型的著作权。
官方背景插画
assets/backgrounds/builtin-cyrene-01 ~ 07 是《崩坏:星穹铁道》官方宣传插画,著作权归 HoYoverse / miHoYo 所有,由项目作者收集后随包内置,仅作桌面背景使用。使用性质为非官方二创,禁止商用、转售、付费分发;公开分发前请自行确认授权范围。逐张来源说明见 assets/backgrounds/CREDITS.md。
第三层:本仓库的处理
本仓库只做了搬运、去白底、缩放、透明化与目录整理,没有重新绘制角色形象。逐项对照与处理记录见 cyrene-balance 的 MATERIALS.md。
素材与代码的授权范围不同:代码是 MIT,assets/ 与 pet/assets/ 不在 MIT 范围内,详见 LICENSE 的「素材例外(Assets Exception)」。
免责声明
- 非官方作品。 本项目是个人制作的第三方插件,与 DeepSeek、Live2D Inc.、miHoYo / HoYoverse 均无隶属、授权、赞助或合作关系。
- 素材版权归原权利人。 立绘、Live2D 模型、表情、头像等素材的著作权归 HoYoverse / 米哈游及 Live2D 模型制作者所有。本项目仅在个人学习与本机使用范围内引用,禁止商用、转售、付费分发或二次分发素材。
- 代码许可不等于素材许可。 源代码按 MIT 发布;
assets/、pet/assets/中的素材不受 MIT 授权,见LICENSE的素材例外条款。 - 使用风险自负。 桌宠会创建透明置顶窗口、改写
resources/app链接、启动独立 Electron 进程。由此产生的窗口异常、桌面操作受阻、系统资源占用等问题,作者不承担赔偿责任。 - 数据仅供参考。 余额、今日消费、今日充值由 DeepSeek 接口与本地账本推算,可能有延迟或误差,请以 DeepSeek 官方账单为准。
- API Key 由你保管。 Key 加密保存在本机
~/.dsh/storages/cyrene-pet/secret.vault.json,不会上传到本项目;因本机泄露、共享电脑或第三方插件读取造成的损失,作者不承担责任。 - 审批授权后果自负。 在桌宠上点「允许一次」等于授权 Agent 越权执行对应操作,可能修改文件、访问网络或执行命令。请确认工具名和理由后再点。
- 提问接管可能漏答。 桌宠只接管「带选项、无
intent」的批次;超时、桌宠未运行或已有挂起请求时,会交还网页卡片,不保证每次都弹在桌宠。 - 任务进度只读展示。 任务进程读取 dsh 的
todos投影,不修改任务状态,也不保证与实际执行进度完全同步。 - 升级兼容性不承诺。 dsh 升级、Electron 主版本变化、插件 API 调整都可能导致桌宠失效,详见「Agent(dsh)升级后可能产生的后果」。
- 无担保。 本项目按「现状」提供,不附带任何明示或暗示的担保,包括适销性、特定用途适用性和不侵权担保。
- 责任上限。 在适用法律允许的范围内,作者对因使用或无法使用本项目产生的任何直接、间接、附带或后果性损失不承担责任。
- 第三方冲突。 同时安装其他桌宠、窗口管理或自动化插件可能产生快捷键、托盘、窗口层级冲突,请自行排查。
- 删除不自动清理数据。 卸载插件不会自动删除
~/.dsh/storages/cyrene-pet/,需要手动清理。 - 作者保留权利。 作者可随时修改、停止分发或调整授权范围;已分发的副本仍受当时条款约束。
目录
dsh-cyrene-pet/
├─ lib/ 宿主半(在 dsh 进程里跑)
│ ├─ index.js 设置、余额、系统状态、提问、审批、任务、桌宠进程管理
│ ├─ client.js dsh 设置页「昔涟 · 桌宠」卡片
│ ├─ companion-runtime.mjs 好感 / 记忆 / 身体 / 念头 / 亲密层 / 开口账本
│ ├─ persona.mjs 人格与台词
│ ├─ ability.mjs 小游戏战绩
│ ├─ session-bridge.js 会话只读桥(列表、历史、SSE)
│ ├─ qq-host.mjs QQ 官方机器人回调、签名校验、远程拍板
│ ├─ sync-bridge.mjs 陪伴数据多端同步
│ ├─ state-merge.mjs 两份写入口的设置合并
│ └─ vault/ 加密仓库与同步引擎(hlc / syncEngine / contracts)
├─ pet/ Electron 渲染半
│ ├─ main.js 透明窗口、拖拽、贴边、托盘、背景落盘、诊断截图
│ ├─ preload.js IPC 桥
│ ├─ index.html 气泡 / 状态面板 / 菜单 / 设置
│ ├─ renderer.js 形象渲染、命中检测、交互、背景
│ ├─ style.css 气泡、面板与设置样式
│ ├─ model-pack.mjs 自备模型的清单解析
│ ├─ outline.js 描边处理
│ └─ assets/live2d/ 渲染库与 Live2D 模型(公开包不含)
├─ assets/ 默认形象、表情、气泡、音效、内置背景
│ ├─ backgrounds/ builtin-cyrene-01~07 / night / sakura + CREDITS.md
│ ├─ emoji/ 44 张小表情
│ └─ sound/ 问候、任务结束、费用等音效
├─ cordis.patch.yml 插件注入声明
├─ LICENSE MIT + 素材例外
└─ package.json
许可与作者
- 代码:MIT
- 素材:不在 MIT 范围内,著作权归原权利人
- 作者:bestlike093
- 问题反馈:GitHub Issues
表情 / 动作框架的出处与依赖
渲染层表情、动作框架的部分能力(中文动作名映射、emoji → 表情映射、七段触摸分区、临时表情墙钟回落、能力识别成文)出自遐蝶桌宠驱动 live2d-driver(2026-11-10 定版),原驱动自述「代码本仓自写,形态参考鲸语 jingyu-live2d(MIT)」。接入文件均保留出处署名,映射表与降级策略沿用原样,台词已按本桌宠角色改写。
相关依赖许可:
- pixi.js:MIT
- pixi-live2d-display:MIT
- Live2D Cubism Core / Cubism Web Framework:Live2D Inc. 授权(仅限本地个人使用;随包不含任何 Live2D SDK 文件,使用时请遵守 Live2D 发行许可条款)
- 模型素材(.moc3 等):不属于本仓库,著作权归各模型原权利人;本仓库不收录、不随发行包分发
No comments yet. Be the first to write one.