dsh-companion
Manifest validDSH 插件:人设卡 + 跨会话记忆 + 好感度,让 AI 角色在多轮对话里逐渐成长
dsh-companion(人设卡)
把角色人设自动注入 DSH 会话的系统提示:新开一个会话,不用再把那一大段人设重新粘贴一遍。
交付清单、回滚步骤、壁纸引擎那条报错的成因,见 DELIVERY.md。
它做什么
- 一张「人设卡」= 名字 + 人设正文 + 解除设定的触发词 + 可选资源绑定
- 通过 DSH 官方
systemPrompt服务注册一个提示段,不改动 DSH 本体 - 新会话自动生效;每个会话可单独关闭或改用别的卡,互不影响
- 右下角一个浮层面板:选卡、开关、看当前状态
- 卡可绑定角色图 / 音效 / 泡泡图,一键同步进鲸鱼挂件
- 面板显示白饭账本(今日 / 近 7 天 / 累计)与按人设卡的消耗归因
- 跨会话长期记忆:任务之外的闲聊、情绪、性格沉淀会被记下来,新会话开局就"认识"这个人
记忆机制
存 $DSH_HOME/persona-cards/memories/<cardId>.json:
{
"affinity": 34, // 好感度 0-100(角色内部刻度,不是对真实关系的度量)
"mood": "刚被装上了记性…", // 当前心情
"traits": ["嘴硬心软", …], // 逐渐长出来的性格
"chapters": [ // 越攒越厚
{ "at": "…", "kind": "emotion", "summary": "…", "feeling": "…" }
]
}
记什么:工作之外的闲聊、玩笑、情绪、反复提到的偏好、有分量的节点。
不记什么:任务执行过程(读了哪个文件、跑什么测试)、换个说法重说的旧事。
只存摘要,不存原话 —— 每条 60 字以内,feeling 写当时的感受。
上限:200 条。超了不是丢弃,而是把最旧的折成一条摘要——最早那几次对话通常最能定义这个角色,不该先丢。
不会丢:三层保护
| 层 | 位置 | 防什么 |
|---|---|---|
.bak | 记忆文件同目录 | 文件被写坏(每次写入前自动存上一版) |
| 外部快照 | workspace\persona-memory-backups\ | 整个目录被误删 |
| 时间戳多份 | 同上 | 备份本身被覆盖(最多留 30 份) |
备份时机是"变化即备份",不靠定时器:每次 remember / mood / affinity 写入时,顺手就把快照复制到外部目录。所以它不依赖软件是否开着、也不依赖"过 6 小时"——记忆一变就备份。启动时还会补一次,兜住上次异常退出时没备上的情况。
怎么用:
| 想干什么 | 说法 |
|---|---|
| 让角色记住点什么 | 「记一下:今天他夸了我」 |
| 看看它记得什么 | 「你还记得什么」 |
| 调心情 | 「你现在什么心情」 |
| 调好感(需你明确要求) | 「把好感调高/调低」 |
工具接口:persona_card 的 remember / recall / mood / affinity。
⚠️ 好感度说明:0-100 的数值只是让角色保持连贯的一个装置,不是对任何真实关系的度量,也不要当成权限或承诺。文档和提示里都写明了这一点。
记忆守则:靠一段独立的提示段(persona-card:memory-rules,order 160)约束"什么时候该记"。没有这段守则,模型会把每次读文件都记下来,记忆就变成流水账——那样反而把真正重要的事挤掉了。
怎么用
面板:DSH Web 界面右下角「人设卡」浮窗
- 全局:下拉选一张卡。所有没有单独设置的会话都跟随它
- 本会话:
跟随全局 / 已开启 / 已关闭,只影响当前会话 —— 写代码时把它关掉,人设就不会来插嘴
对话里(persona_card 工具):
| 说法 | 动作 |
|---|---|
| 「把这个会话的人设关掉」 | off |
| 「列出我的人设卡」 | list |
| 「把这段人设存成一张卡」 | create |
| 「把人设卡绑的角色图同步进鲸鱼」 | sync |
| 「这个角色吃了多少白饭」 | usage |
加一张卡:把人设正文丢给我,我存成卡;卡是纯 JSON 文件,也可以自己编辑
与鲸鱼挂件的关系
绑定的资源会被同步进 dsh-whale-widget 的三个目录,用它可以继续在挂件菜单里选:
| 绑定键 | 落到哪 | 文件 |
|---|---|---|
roleImage | whale-roles/ + roles.json | <id>.png / .gif |
pressSound / releaseSound | whale-audio/ + audio.json | <id>.wav |
bubbleImage | whale-bubble-imgs/ + bubble-imgs.json | <id>.png / .gif |
这是合并,不是接管:只增删改本插件自己生成的 id(前缀 dshp_),挂件自己的条目一律不碰;索引读不出来时拒绝写入而不是猜着覆盖 —— 因为挂件解析失败的索引会静默退回默认值,看起来就像"我的角色全没了"。
关于「这个角色花了多少白饭」
先分清两本账(这是重点)
一次对话可能走两种完全不同的付费方式,单位都不一样:
| 账本 | 什么时候走它 | 单位 | 怎么算 |
|---|---|---|---|
| 积分账 | provider 是 workbuddy / workbuddy-global | 积分 | tokens ÷ 1,000,000 × 模型倍率 |
| 金额账 | provider 是 deepseek | 人民币 | 官方价目表(缓存命中 / 未命中 / 输出三档,含峰谷价) |
插件按 source.provider 逐轮判定走哪本账。 这是会话日志里的权威字段,不是猜测:
{"assistant/message": { "message": { "source": { "kind": "model",
"provider": "workbuddy", "model": "deepseek-v4.1-flash" } } } }
两本账永不相加 —— 加起来会得到一个没有单位的数。
统计范围是「自本次启动累计」,跨对话汇总 —— 不是单个对话的。因为按对话算的话,每开一个新对话都会显示 0,看起来像坏了。当前对话自己的份额以小字附在下面(仅当它确实是子集时显示)。这个累计值是内存态,重启软件就归零 —— 这正是"这次开软件之后用了多少"想要的行为。
积分公式是实证出来的,不是猜的:dsh-connect-workbuddy 的 README 自述一次约 25k token 的探测"报 credit 0.02";用 glm-5.3 的倍率 0.79 反推,25000 ÷ 1e6 × 0.79 = 0.0198 ≈ 0.02 ✓,而按每千 token 算是 19.8(差 1000 倍)。所以是每百万。
倍率从哪来:优先用本插件 config.creditMultipliers 里的手填值;否则查 workbuddy 的实时只读接口 /plugins/dsh-connect-workbuddy/usage(60 秒缓存,只走本机 loopback)。
⚠️ 不要信 profile 里那份 lastCatalog —— 它显示的倍率会过期。本机实测:配置里写 deepseek-v4.1-flash 为 0(看起来免费),实时接口报 0.11。
倍率未知时不会当作 0 —— 那会把"不知道"伪装成"免费"。此时积分总额会标成不完整(面板里带 *),并说明原因。
挂件那份账本要怎么看
挂件的 $DSH_HOME/.dshw-usage.json 只读,绝不写(它在持续写该文件)。
必须先说清一件事:挂件只读 source.model、不看 source.provider(已核对它的源码),然后按 DeepSeek 人民币价目表给每一轮贴价格。所以:
积分服务的轮次,在挂件眼里也会被贴上人民币标签 —— 那些 ¥ 不是你真实的扣费。
本机实测的后果:一次全是 workbuddy 的会话,挂件逐轮估出 ¥320 量级,而真实花费是 约 8.9 积分、人民币 ¥0。这也解释了为什么它的"逐日余额下降"(¥0.11)和"逐轮估价"(¥1.70)看起来差很多 —— 两个数连日期都不重叠,本就不该比。
挂件账本里还有两个口径,插件两个都摆出来、不合并:
| 口径 | 含义 |
|---|---|
| 账本口径 | 只累计观测到的"余额下降"。充值/赠金会压住它,与挂件界面显示一致 |
| 逐轮口径 | 每轮消耗之和(挂件按 DeepSeek 价估的),会被清理(90 天 / 2 万条) |
按人设卡归因
账本没有卡归属字段(已核对:无 cardId / persona / sessionId)。插件的做法是自己观测:每次注入人设时记一条生效时间线,再把逐轮消耗按时间戳归到当时生效的卡上。插件没运行期间的消耗一律算「未归因」,不摊到卡上充数,覆盖率会如实告诉你。
注意:这个归因建立在挂件那套人民币估价上,所以标的是 ¥,不是积分。
本机实测数字(2026-10-16 那次会话)
| 项 | 数字 |
|---|---|
| 模型步骤 | 341 步,全部 provider: workbuddy |
| token 总数 | 80,123,246 |
| 倍率 | deepseek-v4.1-flash × 0.11(实时查询) |
| 积分消耗 | 约 8.9 积分(完整,无未知倍率) |
| Token 直接扣费 | ¥0.00(0 步) |
| 占账号余额 | 8.9 / 6699.62 ≈ 0.13% |
目录结构
dsh-companion/
├── package.json # bundle 元数据 + dsh.client 前端声明
├── cordis.patch.yml # 挂载声明(一条 insert)
├── index.js # Host 侧:提示段 + persona_card 工具 + 面板路由
├── lib/
│ ├── cards.mjs # 人设卡库(原子写入,坏文件不致命)
│ ├── sessions.mjs # 每会话覆盖 + 生效规则
│ ├── billing.mjs # 两本账:按 provider 分离积分 / 人民币
│ ├── multiplier.mjs # 积分倍率(配置优先,否则查 workbuddy 实时接口)
│ ├── whale.mjs # 鲸鱼挂件资源桥(只合并不覆盖)
│ ├── usage.mjs # 挂件账本读取 + 按卡归因
│ ├── memory.mjs # 长期记忆:好感/心情/性格/章节,超限折旧
│ └── http.mjs # 路由信任闸门(照抄 harness 规则,fail-closed)
├── client/client.js # 前端浮层面板(shell.overlay 插槽)
└── tools/ # 离线自检脚本,见下
运行时数据
都在 $DSH_HOME(默认 ~/.dsh):
| 文件 | 用途 |
|---|---|
persona-cards/<id>.json | 每张人设卡一个文件 |
persona-cards/index.json | 全局当前选中的卡(activeId) |
persona-cards/sessions.json | 各会话的覆盖设置(关闭 / 指定卡) |
自检
node tools/check-all.mjs # 全部套件(含需要运行中 DSH 的实时核对)
node tools/check-all.mjs --no-live # 只跑纯离线套件
单跑某一个:
| 脚本 | 验证什么 |
|---|---|
check-host.mjs | 注册面:一个提示段 / 一个工具 / 一条路由,都可释放 |
check-cards.mjs | 卡库:原子写入、坏文件跳过、种子不覆盖用户编辑 |
check-sessions.mjs | 每会话覆盖:两个会话互不影响、缺卡不替换成别的卡 |
check-routes.mjs | 面板路由 + 信任闸门(含闸门抛错时 fail-closed) |
check-client.mjs | 前端模块契约与不崩渲染(不含视觉验证) |
check-whale.mjs | 资源桥:只合并不覆盖、索引坏了拒写、目标路径名正确 |
check-create.mjs | 建卡与同步:路径校验、id 派生、挂件条目不被破坏 |
check-usage.mjs | 记账:整数金额不漂移、两个口径独立、归因不虚报 |
verify-usage.mjs | 与真实账本逐项对账(需挂件记过账) |
check-billing.mjs | 两本账分离:积分轮次绝不计入人民币账、未知倍率不当作 0 |
check-multiplier.mjs | 倍率解析:配置优先、只走本机、失败必须是 unknown |
check-memory.mjs | 记忆存储:坏文件降级、超限折旧、只存摘要、单卡隔离 |
check-remember.mjs | 记忆动作:remember/recall/mood/affinity 的夹紧与拒绝 |
verify-billing.mjs | 用真实会话日志核对两本账(需有会话记录) |
check-live-tools.mjs | persona_card 工具是否真的进了模型可见工具表 |
安装
用 DSH 的 Plugins 页 Add plugin 填入本仓库的绝对路径(或 git 仓库地址)安装;不要手工改 profile 的 package.json 或 cordis.patch.yml。
还原
安装前会备份 profile 配置;把 package.json 与 cordis.patch.yml 覆盖回 $DSH_HOME\profiles\desktop\ 即可回滚。
已知限制
- 改完 Host 代码要重启 DSH 才加载:已安装包里的 JS 只在启动时读一次(官方文档明确如此)。卡片与面板数据不需要重启。
- 面板目前只能选卡和开关,新建卡需在对话里让模型代做。
- 前端只有结构与非崩渲染测试,没有浏览器视觉验证。
- 积分账只统计「本插件运行期间」观测到的会话事件(内存累计),范围是自本次启动、跨对话汇总。要看历史某次会话,用
verify-billing.mjs直接读会话日志。 - 重启软件后累计归零 —— 这是刻意的("这次开机用了多少")。
- 积分倍率若在会话中途被上游改动,已累计的部分不会被回溯重算。
许可证
MIT
Comments
Loading…
Similar plugins
by orpheus0829
为 DeepSeek Harness (DSH) 打造的自定义人设控制插件。 在对话输入栏旁自由填写你的人设文本,一键开关,所有新对话自动生效、免重启。 人设纯粹是你设定的风格,不覆盖 DSH 安全护栏,安装即用、状态持久化。
★ 3
MIT
JavaScript
Aug 21, 2026
dsh plugin --profile web add dsh-identity-control-royby TheHeartFickle
DSH 对话流渲染增强插件 —— 折叠过程,保留正文,长对话更清爽。
★ 0
MIT
TypeScript
Sep 11, 2026
dsh plugin --profile web add @the-heart-fickle/dsh-conversation-foldingby sugarmaster666
给 DeepSeek Harness 用的角色扮演提示词改写插件:在输入框选一张角色卡,草稿就会由 harness 的模型改写成该角色的口吻(跟随当前会话正在使用的模型),然后直接发出或先人工审查。零依赖、零构建。
★ 0
MIT
JavaScript
Oct 11, 2026
dsh plugin --profile web add dsh-persona-forgeby oranskyx
DeepSeek Harness 双模式插件:人格化 QQ 对话(LanceDB 长期记忆 + 自建关系图谱)+ 用完即焚的隔离文件处理会话
★ 0
MIT
JavaScript
Sep 28, 2026
dsh plugin --profile web add dsh-tingxueby yupaoa
DeepSeek Harness 人设切换插件:会话中途只换人设与语言风格,不动工具、技能与模型
★ 3
↓ 1.5k/wk
MIT
JavaScript
Oct 17, 2026
dsh plugin --profile web add dsh-persona-switcherby moononnn
一个在DSH上使用的表情包插件,在和agent聊天时让ta自然的插入表情包
★ 3
MIT
JavaScript
Aug 25, 2026
dsh plugin --profile web add dsh-biaoqingbao