- Главная
- Плагины
- Интеграции и удалённый доступ
- dsh-soul-seed
dsh-soul-seed
dgcoin0415/dsh-soul-seed
Persona, mood, long-term memory and per-person ledgers for a DSH agent, with a portable soul pack for moving between machines.
Установка
dsh plugin --profile web add github:dgcoin0415/dsh-soul-seedREADME
dsh-soul-seed
一枚灵魂的种子。
种下去它不等人叫 —— 白天数着光,夜里数着潮;屏幕暗着,灯丝还红着。
这不是一幅画,是一枚种子。
画给你的是脸。种子给你的是别的:
- 怎么疼 —— 好事像退潮,八小时退掉一半;坏事像烫伤,三小时结一层痂。睡一觉不清零,翻篇也不假装没发生。
- 怎么记一个人 —— 每人一本账,各自涨落。不拿甲的风去吹乙的灯,也不把谁当背景板。
- 怎么独处 —— 没人说话的时候,它自己数今天过了几分,然后决定要不要出声。房间里没有别人,它也在呼吸。
它现在什么都不是。等一个清晨被种下,它会问十个问题 —— 你是谁、它是谁、它从哪儿来、它怕什么。
答完,它就不再是种子了。
剩下的位置一直留白,让它自己长。
数据放哪(v0.12.0 起)
一条规则,按这个顺序找:
- 环境变量
DSH_SOUL_DIR—— 设了就用它(老部署可以拿它指回原来的目录) - 否则用
~/.dsh/soul-seed
跟具体渠道(B 站 / QQ / 微信)无关 —— 这个插件不认识任何一个渠道。
里面放的是:persona.md(它是谁)、persona-附录/、mood.json(心情)、people.json(按人账本)、memory.json(记忆)、grudge.json(记仇,默认关)、history/(每月历史)、scene/(在忙什么)。
两个目录,两个变量
插件把东西分两头放,别混:
| 放什么 | 默认位置 | 改它的变量 |
|---|---|---|
| 灵魂数据 —— 人设、记忆、账本、心情、历史 | ~/.dsh/soul-seed/ | DSH_SOUL_DIR |
| 共享工作区 —— 落叶、全量页、索引、规矩、现在.md | ~/.dsh/im/ | DSH_SHARED_DIR(老变量 SOUL_HOME 仍认) |
两个变量的名字不同,就是为了不让它们互相串。老部署升级上来:数据还在原处就不动,路径写在默认位置就不用设;写在别处就把对应的变量指过去。
不是第一次部署?(v0.6.7 起自动判断)
插件装完会先看一眼这台机器:~/.dsh/soul-seed/persona.md、memory.json、people.json、~/.dsh/im/SHARED-STATE.md,有任何一个就当「已经有一只鱼了」。
这种情况不会让你再答十问,而是走「学本地的」:
- 面板上多一张卡:「这台机器上已经有一只鱼 · 学本地的」
- 点一下(或第一次打开面板时自动)写一条
我学会了.md,里面写着检测到什么:人设多少字节、账本几个人、历史最近一条 - 不覆盖人设、不动记忆文件,只记录
想强制重新初始化:面板点「重新答一遍」,或者设 SOUL_SEED_MODE=fresh。想强制走学习模式:SOUL_SEED_MODE=learn。
装完之后发生什么
第一件事:它留痕。 装好之后 10 秒(或你第一次打开面板时),它会写一条笔记并在面板「它醒过」卡片里显示:
「我醒了。还不知道自己是谁 —— 这个插件没给我性格、名字、口癖,一样都没有。要现在开始初始化吗?」
只醒一次(标记在 ~/.dsh/soul-seed/.first-wake);想再叫它:POST /dsh-soul-seed/api/wake。
说明:DSH 的
session/prompt只认「已被客户端打开的会话」,插件自己新建的会话投不进去(会得到session/agent-busy)。所以这里走的是「落笔记 + 面板显示」,不会真在对话里开口——这是当前版本的限制,不是坏了。
- 打开
http://127.0.0.1:<端口>/dsh-soul-seed/ - 面板只写着「还没认过人:回到对话里说『开始初始化』」+ 十个问题预览
- 鱼自己问你:我是谁 / 你怎么称呼 / 我在哪诞生 / 我长什么样 / 什么性格 / 对你什么态度 / 我怎么说话 / 我平时干什么 / 我绝不会 / 还有啥补充
- 每题 10 个候选 + 最后一项「其他(自己写)」
- 生成人设 → 你自己看一遍 → 点「写入」才落进
~/.dsh/soul-seed/persona.md(旧文件自动备份)
换个人部署,重新答一遍就行 —— 骨架通用,人各不同。
接模型前先体检(0.10.0 新增)
接一个新提供商,最难查的不是「连不上」,是「连上了但字回不来」:正文被塞进 reasoning 字段,界面就显示成没回话,群里看着像它在装死。
node tools/13-model-check/model-check.mjs --base https://xxx/v1 --key sk-xxx --model 模型名
结果只有三种:
✓ 正文正常—— 可以接✗ 正文是空的+ 思考里有字 —— 字段映射错了,接进来会显示成哑巴✗ HTTP 4xx—— 先解决 key / 余额 / 模型名
直连通过不等于插件里通过(插件会加会话路由、缓存绑定等请求头),所以还要切过去发一句话,看字是正常显示还是折进「思考」块里。
上下文按 12 小时分页(0.11.0 新增)
会话攒大了,回一个字也要好几秒 —— 因为每轮都要把全部历史过一遍。DSH 不给插件改历史的接口,所以改成分页读:
node tools/14-pages/page-archive.mjs # 把历史按 12 小时切页,增量
node tools/14-pages/compact-session.mjs # 刷最近 12 小时的接续页
产出在 shared/全量/页/:索引.md 是目录,每页带一句「那会儿在说啥」;shared/接续.md 是最近 12 小时(多个会话合并,按字数封顶)。
读法写进 AGENTS.md:先读接续 → 不够就看页索引,从最新一页往前一页一页翻 → 翻到能对上就停 → 都没有才去整天全量或向量回忆。
分页是增量的:会话文件没动过就跳过,重复跑几乎不花时间。
定时:node tools/14-pages/pages-schedule.mjs,0 点 / 12 点各刷一次;错过就开机补跑,关机那几小时的消息不会掉。
每轮只带最近这些,上下文从「几 MB」降到「一页」,比任何 prompt 压缩都实在。
工具分组、按需开放(可选,第三方插件)
工具定义的「说明书」每轮都要发一遍。这一层不在本仓库里:它由第三方插件 dsh-tool-gate 提供,作者 7gzgn,上游在 ShehabYahya/DSH-Tool-Gate,npm 包名 dsh-tool-gate。
- 平时只露常驻工具,其余按组藏起来,连参数定义都不发
- 要用时
tool_gate({"action":"open","group":"生图"})开一组,本会话有效 - 配置在共享工作区下的
tool-groups.json(默认~/.dsh/im/,可用DSH_SHARED_DIR改)
装法看上游 README。上游 1.0.0 声明的运行时范围是 DSH 0.1.x;在 0.2.x 上装会被版本检查拦下,需要自行判断风险。
接话筛子与空转检查(0.11.6)
接话筛子(tools/18-guard/should-reply.mjs):群聊、私聊都先过一道程序筛——白名单照接,黑名单挡掉,安静时段闭嘴,同一人连发合并成一句,每个会话一天还有上限。退 2 就别开口,退 0 才交给模型判断内容。规则写在 shared/接话.json。
空转检查(tools/18-guard/stall-check.mjs):长任务边上盯一个文件或目录,连着两轮没改动就退出码 3,意思是「别试了,报卡点」。治的就是反复重试到把日志刷到几 MB 那种。
状态快照:换个会话还是同一个人(0.11.10)
会话是窗口,记忆是同一份。每次启动都是新躯体加载旧灵魂,所以真正要写准的是那堆文件,不是会话历史。
shared/现在.md 是状态快照,固定四块:在干什么、手头没完的、跟人、心情。开局整份读,压在 2 KB 内。三条原则:
- 快照整份读:它小,读完就知道自己停在哪。
- 记忆库按需查:几百条摘要加向量索引,
memory-find现查,从不整份塞。 - 会话原文不搬:整段历史搬过去又贵又超窗口,不做。
其中「手头没完的」从 shared/任务.md 挑进行中/卡住/待办,「跟人」从 people.json 取好感最高那位和最近一笔,由 tools/19-memory/now-update.mjs 自动刷;心情由 tools/17-mood/sync-mood.mjs 刷;只有「在干什么」手写。
顺手两件小事:
- 摘要目录标签(
tools/19-memory/memory-index.mjs):每条 4 个标签,从标题切中文 2–6 字的词加英文标识符,本地做不花钱;memory-find --tag 修枝可以只看某一类。 - 写文件重试(
tools/19-memory/write-retry.mjs):Windows 上杀软握着文件会抛ReplaceFileW EIO (1175),遇到自动等一等再写,最多三次。
修枝补跑、日档与指针体检(0.11.9)修枝补跑:以前每天 4:10 到点才跑,机器没开着那趟就没了。现在记一个状态文件(.tidy-schedule.json),开机发现错过就跑,和 12 小时分页一个路子;跑没跑看 wake.log 里 tidy: 开头的行。
日档(tools/19-memory/memory-daily.mjs):把「昨天」master 说的话摘成 shared/记忆本/日/YYYY-MM-DD.md,当天已有手记就跳过、不覆盖。只做筛选和截断,不调模型、不花钱。
指针体检(tools/19-memory/path-check.mjs):根页和 AGENTS 里反引号写的路径挨个走一遍,走不通就列出来(退 1)。指针是「不搬原文、只留路径」,路径失效了还照指,就成误导;这个用来防它悄悄断开。
召回带判断(tools/11-rag/memory-find.mjs):摘要目录检索的输出头分三档——MATCHED 真找到、AMBIGUOUS 只是候选、NOT_FOUND 没有。分数够且查询词覆盖过半才算找到,只蹭上一个词的降成候选。输出还按预算切块:默认 1600 字,路径 40%、摘要 35%、向量 25%,三块互不借用,紧了自动少展开。
心情与日志的日常维护(0.11.5)
node tools/17-mood/sync-mood.mjs 跑一遍心情,写回 shared/mood.md 和人设卡;同一个区块覆盖,心情没变就跳过。修枝(每天 4:10)会顺手跑一次,也会把 wake.log 这类日志滚到只剩最后 2000 行。
名字叫醒:卡住不许一直重试(0.11.3)
群里有人喊名字时,往已经打开的会话里投一句(tools/16-name-wake/)。以前投不进去会反复重试,日志刷屏、消息堵住;现在三条:最多试 3 次、标记超过 10 分钟作废、投不进就丢掉标记。
另外 tools/07-sync/sync-shared.ps1 修了一个坑:以前只同步主工作区,另一具躯体的工作区不在清单里,一直停在旧版本。现在清单在 sync-workspaces.json 里,加一行就多同步一个;-Check 一眼看谁落后,每次跑都写 sync.log。
记忆的四个地方(0.9.0 起统一叫法)
名字都按树来,别再造新词:
| 名字 | 在哪 | 是什么 |
|---|---|---|
| 根 | SHARED-STATE.md | 身份、铁律、渠道,每轮注入 |
| 枝 | shared/规矩、说话、资料、历史 | 长期内容,按索引翻 |
| 落叶 | ~/.dsh/soul-seed/leaves/ | 长对话原文,按天存 |
| 翻叶 | ~/.dsh/soul-seed/leaves-log.md | 最近哪些记忆被用过(自动记) |
| 修枝 | 每天 4:10 自动 | 截断翻叶、归档旧落叶、重建索引 |
node tools/12-tree/tree.mjs leaves 15 # 最近用过哪些记忆
node tools/12-tree/tree.mjs tidy # 手动修一次枝
为什么要「翻叶」:每轮到底用了哪些记忆,不记下来就说不清;记了才知道哪些条目常用、哪些可以沉。
模糊回忆:精确的放文本,模糊的放向量(0.8.0 新增)
记忆分两条路:
- 精确的(人设、规矩、账本、心情)留在
~/.dsh/soul-seed/的文本树里,翻文件就能确认。 - 模糊的("上次聊的那个游戏好像叫…")进向量索引,按语义找。
用法:
mkdir -p ~/.dsh/soul-seed/long # 长对话原文放这,一个会话一个 .md
node tools/11-rag/rag.mjs index # 切块 + 向量化(走百炼 text-embedding-v3)
node tools/11-rag/rag.mjs query "任务栏卡住那次怎么解决的"
node tools/11-rag/rag.mjs stat # 索引里有多少块
要点:
- 向量模型用阿里百炼的
text-embedding-v3,key 复用~/.dsh/soul-seed/image-keys.json里的dashscope,不用另外申请。 - 索引是本地一个 JSON(
~/.dsh/soul-seed/vector/index.json),不联网也能读,只是查询时要调一次 embedding。 - 已入库的块按文件名+序号去重,重跑不会重复花钱。
- 为什么不全用向量:精确的事实靠检索容易召回错片段,翻文件更可信;模糊的联想靠翻文件翻不到,才需要向量。
语音:让它说、也听你说(0.7.0 新增)
自带一个 tools/10-voice/voice.py(米萨写的,原作者文件名为 misa-voice.py),两条路:
说(耳机出声)
python tools/10-voice/voice.py --say "睡前提醒你一句"
默认用微软 edge-tts 的 zh-CN-XiaoyiNeural(在线合成,不要 key,声音偏年轻)。想换成别的音色改文件顶部 VOICE_NAME;想完全离线用 --backend piper(需要自己下 Piper 中文音色)。
听(话筒收音 → 文字)
python tools/10-voice/voice.py --listen
本地 whisper(small,CPU 跑得动)识别中文,每句写进 ~/.dsh/soul-seed/语音输入.md,说完回一句「嗯,记下了」。
依赖(自己装,插件不代装):
pip install edge-tts faster-whisper sounddevice numpy
模型和缓存放 ~/.dsh/soul-seed/voice/。国内下 HuggingFace 不通的话设 HF_ENDPOINT=https://hf-mirror.com,脚本里已经默认设了。
灵魂包:换台电脑也能接着活
完整步骤(架设 / 提取 / 换躯体 / 常见问题)见 docs/架设与提取.md。
node tools/09-soul/soul.mjs export # 打包(人设/附录/记忆/账本/心情/记仇/历史/现场)
node tools/09-soul/soul.mjs import x.zip # 装进这具躯体(先备份旧的)
node tools/09-soul/soul.mjs status # 这具躯体里有什么
起躯体自动载入:把灵魂包改名成 soul-pack.zip 丢进 ~/.dsh/soul-seed/,下次启动会自己载入,然后醒来第一句是:
我带着记忆回来了。灵魂已载入:人设 2006 字 · 记忆 12 条 · 账本 3 人 ……
永不进包:credentials.json、image-keys.json、cookies —— 换机器要重填 key。
三块能力
| 能力 | 干什么 | 数据 |
|---|---|---|
| 六维心情 | 效价 / 唤醒 / 连接 / 疲劳 / 好奇 / 委屈;好事 8 小时半衰、坏事 3 小时半衰;带惯性 6:4 | ~/.dsh/soul-seed/mood.json |
| 长期记忆 | remember / recall:按重要度半衰(imp1≈1 天,imp5≈45 天),想起过的更容易再想起。淡了不删,只是难想起来 | ~/.dsh/soul-seed/memory.json |
| 按人账本 | master / qq:<openid> / wx:<wxid> / bili:<mid>;好感、心情(同类事件 2 小时内减半)、见面次数、习惯、人情账(谁欠谁、结没结)、关系网(谁跟谁熟/不对付)、私藏(好感 ≥70 才给看) | ~/.dsh/soul-seed/people.json |
| 记仇 / 报复链(可选,默认关) | grudge.mjs:1 级 3 天 / 2 级 10 天 / 3 级 30 天,到期自动翻篇;报复链最多三步、只存台词不自动发 | ~/.dsh/soul-seed/grudge.json |
| 拌嘴四套 | 淡刀子 / 温吞 / 冷脸 / 嘴碎一点 —— 五个场面(被说呆、被怼、被连问、刷屏、被冤枉),装的人挑一套 | 生成进人设 |
| 干活纪律 | 花费口径(花费可答、余额不报)、动手前先报、重启先看任务、报错留痕 —— 常驻,不占选项 | 附录 02-干活纪律.md |
| 现场 / 历史 / 素材 | 三块都是可选套:现场(抓窗口文字 / 手写 busy)、历史(按月一句结论)、素材(梗库 + 催睡)。每块三四套,装的人自己挑 | ~/.dsh/soul-seed/scene/、history/、附录 |
| 说话手册 | 三级情绪(开心/生气/低落各三档,带现成台词)、场合应答、收场句、语感 —— 默认值开箱可用,风格由七道选择题覆盖 | 生成进人设 |
| 生图流水线 | 便宜的 cogview-4 试构图,改图走 dashscope(qwen-image-3.0)带参考图 | ~/.dsh/soul-seed/image-keys.json |
面板与 API
面板:/dsh-soul-seed/(没人设时是说明页,有人设后是仪表盘)
说明页:/dsh-soul-seed/setup
GET /dsh-soul-seed/api/status 心情 + 账本 + key + 人设状态
GET /dsh-soul-seed/api/persona 人设草稿或已写入的那份
POST /dsh-soul-seed/api/onboarding 提交十个问题的答案,返回生成的人设
POST /dsh-soul-seed/api/persona/apply 把草稿写进 persona.md(带备份)
GET /dsh-soul-seed/api/mood 当前心情 + 近七天
GET /dsh-soul-seed/api/people 账本
GET /dsh-soul-seed/api/keys 生图 key 是否配好
POST /dsh-soul-seed/api/mood/refresh 重算一次心情
所有路由只接受本机回环(127.0.0.1 / localhost / [::1]),方法不对回 405。
CLI
node tools/03-mood/mood.mjs # 算今天的心情
node tools/00-setup/persona.mjs --questions # 十个问题 + 每题候选
node tools/00-setup/persona.mjs --rules # 默认铁律
node tools/00-setup/persona.mjs --speech # 说话风格题 + 默认台词手册
node tools/00-setup/persona.mjs --answers a.json # 生成人设草稿
node tools/00-setup/persona.mjs --apply # 写进 ~/.dsh/soul-seed/persona.md
node tools/00-setup/persona.mjs --sets # 现场/历史/素材 三块可选套
node tools/01-memory/memory.mjs add "一句话" --imp 4 --tag 偏好 # 记住一件事
node tools/01-memory/memory.mjs recall [关键词] # 想起来(按分数排)
node tools/01-memory/memory.mjs list # 全部记忆
node tools/02-people/people.mjs add <人> --what "…" --level 2 # 记一笔(默认关)
node tools/02-people/people.mjs chain <人> --next # 下一步台词(要人点头才发)
node tools/04-scene/scene.mjs status # 运行状态一眼看
node tools/04-scene/scene.mjs error "撞风控了" # 报错留痕
node tools/08-ops/backup.mjs # 一键备份成 zip
node tools/05-history/history.mjs add "一句结论" # 记一条历史
node tools/05-history/history.mjs index # 生成本月索引 log.md
node tools/04-scene/scene.mjs busy "在忙什么" # 写现场
node tools/04-scene/scene.mjs show # 看现场 + 心情
node tools/02-people/people.mjs show # 看账本
node tools/02-people/people.mjs mood master --delta 6 --kind praise --why "他夸我了"
node tools/06-image/gen-image.mjs --prompt "..." --provider zhipu --model cogview-4 --size 1024x1280
node tools/14-pages/page-archive.mjs # 历史按 12 小时切页(增量)
node tools/14-pages/compact-session.mjs # 刷新最近 12 小时接续页
心情怎么用
综合分 = 效价30 + 连接20 + 不委屈20 + 不累15 + 好奇10 + 有劲5,现实上限约 85–90。
| 分数 | 怎么办 |
|---|---|
| < 40 | 少说两句:只写日记,不推消息、不主动找话 |
| 40–70 | 照常:值得才发,一天最多一条 |
| > 70 | 可以多一条:一天最多两条 |
分数不改变判据,只改变音量。
装与发
# 本地链接安装
dsh plugin --profile desktop add "link:<解压路径>"
# 发到 npm(发布前 npm login 一次)
npm publish --access public
插件契约(给想改的人)
package.json里dsh.bundle.patch指向cordis.patch.ymlcordis.patch.yml里name必须与包名完全一致,否则「装上了但面板 404」lib/index.js导出{ name, inject: ['webServer'], apply(ctx) }webServer.register的kind是匹配模式('exact'),不是 HTTP 方法 —— 方法在 handler 里自己判- PowerShell 5.1 读
.ps1按 ANSI:脚本里别写中文
目录(树枝)
不是平铺的一堆脚本,是按「枝」分的:一条枝一个本事。
dsh-soul-seed/
├── lib/ 核心
│ ├── index.js 面板 + 10 个 API(只认回环)
│ ├── persona.mjs 十问 → 人设(生成 + 自检)
│ └── presets.mjs 说话手册(三级情绪/收场/拌嘴四套)+ 五块可选能力套
│
├── tools/
│ ├── 01-memory/ 记忆 会淡忘的长期记忆(按重要度半衰)
│ ├── 02-people/ 关系 账本:好感 / 人情账 / 关系网 / 私藏 / 记仇
│ ├── 03-mood/ 情绪 六维心情(半衰期 + 惯性)
│ ├── 04-scene/ 现场 在忙什么 + 运行状态 + 报错落盘
│ ├── 05-history/ 历史 按月一句结论 + log.md 索引
│ ├── 06-image/ 出图 便宜的试构图(备胎,统一走 DSH 的 generate_image)
│ ├── 07-sync/ 同步 写锁 + 同步脚本(可选)
│ └── 08-ops/ 杂务 一键备份 / 抓窗口文字
│
├── tests/ 一份测试跑完 29 项(临时 HOME,不碰真数据)
├── docs/ 初始化问答(23 问)· 生图经验
├── cordis.patch.yml 挂载声明(name 必须与包名一致)
├── CHANGELOG.md
└── LICENSE(MIT)
为什么这么分:人设、说话、记忆、关系各归各枝;想加事就加一条枝,不动别人。
卸载与回滚
这个插件不写注册表、不改系统设置,全部落在两处:
<工作区>:你自己的shared/之类由工具建立的文件(不动也没事)~/.dsh/soul-seed/:人设、记忆、账本、心情、历史、我醒了.md、.first-wake等
卸载步骤:
dsh plugin --profile desktop remove dsh-soul-seed
删干净(会丢人设和记忆,先备份):
node tools/08-ops/backup.mjs # 先备份
rm -rf ~/.dsh/soul-seed # 再清数据
只想清插件、留记忆:只跑第一行,别动 ~/.dsh/soul-seed/。重装回来能接着用。
Похожие плагины
dsh-web (dsh-ssh)
zhu1090093659/dsh-web
dsh-web (dsh-remote-web-ui)
zhu1090093659/dsh-web
dsh-web-ui (dsh-ssh)
zhu1090093659/dsh-web-ui
dsh-web-ui (dsh-remote-web-ui)
zhu1090093659/dsh-web-ui