DeepSeek Harness 插件:增加「纯文本对话模式」agent…
43.1/100
综合分
20
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/10/31 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
自动兼容检查有告警:npm 同名包「dsh-cyrene」归属 under-the-ocean/dsh-plugin-cyrene,装到的可能不是本插件。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add Cyrene-xl/DSH-Cyrene该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:已验证
是什么
dsh 原生插件 · skill
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 1 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查⚠ 装前注意npm 同名包「dsh-cyrene」归属 under-the-ocean/dsh-plugin-cyrene,装到的可能不是本插件
展开查看检查明细 ↓
以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。
✓npm 包dsh-cyrene @ 0.4.1
✓Node 引擎要求 >=22 · 基线 Node 22.19 满足
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明
验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/26 23:04:49
安全扫描自动 · 静态分析源码v2.7.0🔵 扫描:含敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。
读写/删除本地文件发起外部网络请求
查看扫描证据(共 44 处,展示前 38 条)
- 读取本地文件index.js:42
const parsed = JSON.parse(readFileSync(file, 'utf8')); - 请求外部主机api.github.comindex.js:173
response = await fetch(`https://api.github.com/repos/${UPDATE_REPO}/releases/latest`, { - 发起网络请求index.js:173
response = await fetch(`https://api.github.com/repos/${UPDATE_REPO}/releases/latest`, { - 读取本地文件index.js:727
const body = readFileSync(EDIT_ICON_FILE); - 读取本地文件memory.js:104
return existsSync(STORE) ? readFileSync(STORE, 'utf8').replace(/ ?/g, '\n') : ''; - 读取本地文件memory.js:104
return existsSync(STORE) ? readFileSync(STORE, 'utf8').replace(/ ?/g, '\n') : ''; - 写入本地文件memory.js:112
writeFileSync(STORE, text, 'utf8'); - 读取本地文件memory.js:241
const current = existsSync(PAGE) ? readFileSync(PAGE, 'utf8') : ''; - 读取本地文件memory.js:241
const current = existsSync(PAGE) ? readFileSync(PAGE, 'utf8') : ''; - 写入本地文件memory.js:250
writeFileSync(PAGE, next, 'utf8'); - 读取本地文件memory.js:263
if (!existsSync(PAGE)) return '扉页还是空的。'; - 读取本地文件memory.js:266
const text = sanitize(readFileSync(PAGE, 'utf8'), { keepNewlines: true }).trim(); - 读取本地文件nickname.js:77
if (!existsSync(STORE)) return {} - 读取本地文件nickname.js:78
const parsed = JSON.parse(readFileSync(STORE, 'utf8')) - 写入本地文件nickname.js:124
writeFileSync(STORE, `${JSON.stringify(next, null, 2)}\n`, 'utf8') - 读取本地文件worldbook/index.mjs:101
if (!existsSync(CONFIG_PATH)) return undefined; - 读取本地文件worldbook/index.mjs:102
return JSON.parse(readFileSync(CONFIG_PATH, 'utf8')); - 写入本地文件worldbook/index.mjs:179
appendFileSync(LOG_PATH, `${new Date().toISOString()} ${message}\n`); - 读取本地文件style.js:147
if (!existsSync(file)) return emptyState() - 读取本地文件style.js:148
const raw = JSON.parse(readFileSync(file, 'utf8')) - 写入本地文件style.js:189
writeFileSync(file, `${JSON.stringify(state, null, 2)}\n`, 'utf8') - 读取本地文件style.js:365
if (!existsSync(file)) return '' - 读取本地文件style.js:366
const stat = statSync(file) - 读取本地文件style.js:370
const text = readFileSync(file, 'utf8') - 读取本地文件scene.js:48
const parsed = JSON.parse(readFileSync(file, 'utf8')) - 读取本地文件scene.js:73
const parsed = JSON.parse(readFileSync(file, 'utf8')) - 写入本地文件scene.js:84
mkdirSync(dirname(file), { recursive: true }) - 写入本地文件scene.js:85
writeFileSync(file, `${JSON.stringify(next, null, 2)}\n`, 'utf8') - 读取本地文件scene.js:283
const stat = statSync(file) - 发起网络请求client.js:143
return fetch(API, { headers: { accept: 'application/json' } }) - 发起网络请求client.js:157
return fetch(API, { - 发起网络请求client.js:174
return fetch(ADDRESS_API, { headers: { accept: 'application/json' } }) - 发起网络请求client.js:193
return fetch(ADDRESS_API, { - 发起网络请求client.js:406
fetch(EDIT_API, { - 发起网络请求client.js:466
fetch(EDIT_API + '?session=' + encodeURIComponent(sessionId), { headers: { accept: 'application/json' } }) - 读取本地文件worldbook/parse.mjs:213
text: readFileSync(`${dir}/${name}`, 'utf8') - 读取本地文件worldbook/parse.mjs:233
const files = readdirSync(dir) - 读取本地文件worldbook/parse.mjs:237
const stat = statSync(`${dir}/${name}`);
扫描于 2026/10/31(0 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库
涉及外部主机:api.github.com
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
功能亮点
- 纯文本角色对话模式
- 整份替换系统提示词
- 仅保留联网搜索与表情包
展开完整介绍(102 字)↓
DeepSeek Harness 插件:增加「纯文本对话模式」agent 预设——整份替换系统提示词进行纯角色对话,只保留联网搜索与表情包。随包人设文本整理自开源项目 Cyrene-Agent(MIT)。
README
由 DeepSeek 最新模型翻译生成本项目是 DeepSeek Harness 的开源预设插件,不包含任何游戏资源(Live2D 模型、美术资源、音频)。随包的人设文本改编自开源项目 Cyrene-Agent(MIT,Copyright (c) 2026 Playa)。昔涟(Cyrene)与《崩坏:星穹铁道》归 HoYoverse / 米哈游所有。这是非官方同人工具——仅限非商业使用。
使用前请读 风险提醒 —— 自定义风格与角色扮演模式都会影响模型输出,且与上游人设存在已知冲突。
dsh-cyrene
为 DeepSeek Harness(DSH)提供两套角色智能体预设:
| 预设 | 显示名 | 能力 |
| preset/chat/ | 纯文本对话模式 | 整份替换系统提示词,纯以角色人格对话;只保留联网搜索与表情包,不挂文件 / Shell / 设备工具 |
| preset/cyrene-work/ | 昔涟工作模式 | 同样用角色人设整份替换系统提示词,但带全套工具(文件 / Shell / 计划 / 目标 / 子代理 / 工作流);干活时也保持她的身份与说话方式 |
两者共享同一份长期记忆(<DSH_HOME>/cyrene-memory.md),所以同一个角色在两个模式里的记忆是连续的。
⚠️ 禁止商业使用。
展开完整文档(README 剩余 1 节)
本项目是 DeepSeek Harness 的开源预设插件,不包含任何游戏资源(Live2D 模型、美术资源、音频)。随包的人设文本改编自开源项目 Cyrene-Agent(MIT,Copyright (c) 2026 Playa)。昔涟(Cyrene)与《崩坏:星穹铁道》归 HoYoverse / 米哈游所有。这是非官方同人工具——仅限非商业使用。
使用前请读 风险提醒 —— 自定义风格与角色扮演模式都会影响模型输出,且与上游人设存在已知冲突。
dsh-cyrene
为 DeepSeek Harness(DSH)提供两套角色智能体预设:
| 预设 | 显示名 | 能力 |
| preset/chat/ | 纯文本对话模式 | 整份替换系统提示词,纯以角色人格对话;只保留联网搜索与表情包,不挂文件 / Shell / 设备工具 |
| preset/cyrene-work/ | 昔涟工作模式 | 同样用角色人设整份替换系统提示词,但带全套工具(文件 / Shell / 计划 / 目标 / 子代理 / 工作流);干活时也保持她的身份与说话方式 |
两者共享同一份长期记忆(<DSH_HOME>/cyrene-memory.md),所以同一个角色在两个模式里的记忆是连续的。
⚠️ 禁止商业使用。 本项目为非官方同人作品,与 HoYoverse / 米哈游无任何关联、背书或赞助关系。角色 IP 归 HoYoverse / 米哈游所有。随包的人设文本整理自开源项目
Cyrene-Agent(MIT,Copyright (c) 2026 Playa)。使用前请先读
THIRD_PARTY_NOTICES.md。
关于随包的人设文本
两套预设都已包含可用的角色人设,装完即可对话。人设文本来自开源项目 Cyrene-Agent(MIT),并已取得原作者同意。许可与归属细节见 THIRD_PARTY_NOTICES.md。
两套预设用的是上游不同的提示词组,这不是随意挑的:上游 mode-prompt-profile.ts 把各模式拆成不同文件——对话模式用 chat_system + chat_identity + soul + canon_quotes,工作模式用 work_system + work_identity + work_remark + canon_quotes_lite,通用工具规范另接 tool_usage(且只在非对话模式接)。本仓库照搬这套组合,一字未改。
⚠️ 注意上游在工作模式里刻意不用 soul.md,改用精简台词集 —— 也就是说原应用的 "工作模式人设"本来就是轻量版。觉得干活时不够像角色,第一个该调的是这里(把 soul.md 加回去),不是本插件的装配机制。
授权凭据:原作者在 issue #137 公开回复同意使用,并将该 issue 以 closed as completed 结案(2026-10-03)。
上游本就是 MIT,本仓库已按 MIT 要求保留版权声明与许可证全文(LICENSES/Cyrene-Agent-LICENSE.txt);上述确认属礼貌性征询,不构成额外授权条件。
⚠️ 该确认明确排除 Live2D 模型——模型需另行向模型原作者取得授权。
本仓库不包含任何模型或美术资源;日后若要加入,必须自行取得授权,不得援引本确认。
你也可以完全不用它:清空或替换 prefix: 里的内容即可,本插件的装配机制不依赖具体人设(写法见 docs/writing-your-preset.md)。
⚠️ 原作者的同意覆盖的是提示词文本本身;角色 IP(昔涟及《崩坏:星穹铁道》相关内容)归 HoYoverse / 米哈游所有,原作者无权代为授权,非商业使用条款继续适用。
本仓库不包含任何 Live2D 模型、立绘、美术资源或音频——这些不在随包范围内,也不在 MIT 授权范围内。
它解决什么问题
在 DSH 里给模型套角色人格,常见的做法是把人设写进 AGENTS.md 或 dsh-system-prompt 的 personaPrefix。但那两条路都是叠加:
顺序 −1000 You are an AI agent powered by DeepSeek Harness. ← 固定开场白,去不掉顺序 0 你的角色人设 ← 你加的内容中间 工具规范、编码代理行为准则…… ← 一直压着角色
结果就是角色聊着聊着又会冒出编码代理的口气——「有什么要办的事吗」「要不要我帮你处理」,或者拿环境描写当开场。这不是措辞问题,是提示词分层问题。
本插件用的是另一条路:dsh-persona 的 complete: true。
- id: persona
name: '@deepseek-ai/dsh-persona'
config:
complete: true # 这套提示词就是全部系统提示词 includeRuntimeContext: false complete: true 会遮蔽其余全部提示词段,包括那句固定开场白和第一方工具规范。
角色人设成为唯一的系统提示词,没有竞争层。
安装
1. 装插件本体
⚠️ 别用 dsh plugin --profile <你的 profile> add dsh-cyrene
npm 上有一个同名的 dsh-cyrene,那是别人的「昔涟主题 + Live2D 桌宠」插件,
它的 exports 里只有 . 和 ./client —— 没有本项目需要的 ./nickname / ./memory / ./worldbook / ./style。
装错之后的现象很有迷惑性:预设能选到,但 设置 → 内置插件 里那几行全是 never started,预设标「加载失败」——看着像装上了,其实一个都没起来。
详见下面的排查。
从仓库装才装得到本项目(dsh plugin 只是 pnpm 的转发,link: 指本地目录,不需要联网):
1) 先拿到仓库
git clone https://github.com/Cyrene-xl/DSH-Cyrene
或者从 Releases 页下载 zip 解压
2) 装进「你正在用的那个 profile」
dsh plugin --profile <你的 profile> add link:/你的路径/DSH-Cyrene
Windows: link:D:/你的路径/DSH-Cyrene
3) 重启 DSH(新加的行要重新组合 profile 才生效)
cordis.patch.yml 是纯 insert 形式,不往机器上写任何硬编码路径。
装好、重启之后,设置 → 通用里会多四行:「表达风格」「称呼偏好」「角色扮演模式」和「检查更新」(本包的浏览器半边 client.js 渲染;主机半边 index.js 提供 /cyrene-nickname-api 与 /cyrene-scene-api)。这两行依赖 dsh plugin add 这一步 —— 只拷预设、没装插件本体的部署里,预设照常能跑,只是设置页没有这两行:直接改 <DSH_HOME>/cyrene-scene.json (开关)或 dsha-brand-rename.json(称呼)一样生效。
2. 装预设(必须单独做一步)
DSH 没有公开的 agent 预设安装 API——dsh-agent-presets 只按 ~/.dsh/.agent-presets/<id>/ 目录扫描发现预设,不对外暴露写入接口。
所以预设必须拷贝到位:
先看会改什么(只读,不写任何文件) ./scripts/install.sh --dry-run # 或 node scripts/install.mjs --dry-run
Linux / macOS(需要 Node 22+,脚本只是 install.mjs 的入口) ./scripts/install.sh --yes
任意平台(含 Windows,无 shell 依赖,Node 22+)
node scripts/install.mjs --yes
代际探测:脚本默认自动判断 0.1.x(目录扫描)还是 0.2.0+(声明式注册表)。
探测不到时会打印警告并且只写目录;桌面端等特殊布局可显式指定:
node scripts/install.mjs --yes --generation=declarative。
为什么要 --yes:安装会写 <DSH_HOME>/.agent-presets/ 和 profile 的 cordis.patch.yml,属于 Profile 变更。脚本会先打印一次性计划,写入前要求精确确认(终端里手输 yes,或显式 --yes);覆盖前备份、落盘原子替换、装完跑健康检查,失败自动回滚。全过程记在 <DSH_HOME>/.cyrene-install-journal.json,--rollback 可恢复到安装前。
为什么没有 Windows 专用脚本
以前有 scripts/install.ps1 和 install.bat,已经删掉了。
原因很直接:我没有自己的电脑,这一整套是在 DSH App(Android)里做的 ——开发环境里没有 Windows、也没有 PowerShell,那两个脚本我根本没法实测,只能靠用户反馈来回试,连试三轮都没在真机上跑通。
与其留一条没人能验证的路,不如只留一条能跑通的。Windows 用户请直接用
node scripts/install.mjs —— 跨平台、无 shell 依赖,已实测过安装 / 幂等 / 卸载。
要是它在你的 Windows 上不适配:那大概率得等我以后有了自己的电脑,才能把那部分补回来重做一遍。在那之前上面这条 install.mjs 就是 Windows 的路。
完整的 Windows 说明(怎么装、六条实测坑、将来怎么恢复 PS 脚本)见 docs/windows.md。
脚本会把 preset/ 下的每个子目录装成对应的预设: preset/chat/ → ~/.dsh/.agent-presets/chat/, preset/cyrene-work/ → ~/.dsh/.agent-presets/cyrene-work/。
⚠️ DSH 0.2.0 及以上:目录方式不会生效(而且不报错)
0.2.0 起预设改为声明式注册表,官方文档原话是「注册表不扫描目录,也不接受 preset 路径」。此时 scripts/install. 拷目录会照常成功、照常打印"已安装",但预设不会出现在界面上,也没有任何报错。
2026-10 起这一步已经自动化了:只要先把插件装进 profile(安装第 1 步),再跑同一个脚本,它会:
1. 认出哪些 profile 属于"声明式注册表"那一代(看 profile 的 node_modules/@deepseek-ai/dsh-agent-preset 在不在);
2. 把两套预设的声明自动写进该 profile 的 cordis.patch.yml(先备份、幂等,
已有内容只追加不覆盖,空补丁的 [] 会被正确替换);
3. 同时仍写一份目录副本 —— 同一台机器上若有 0.1.x 的配置档,那边靠它。
所以 0.2.0+ 用户不需要再手动跑 export-preset-declarations 再手贴。
装完重启 DSH 即可。
为什么声明不直接塞进本包的 cordis.patch.yml(那样「装插件即注册」更省事):那一行在 0.1.x 上根本解析不到,实测会让整个 DSH 起不来(ERR_MODULE_NOT_FOUND)。所以按代数分流,而不是一刀切。
手贴的路仍然保留(配置档在非默认位置时用)。注意生成的内容自带 - insert: 那层,别去掉* —— 补丁里不带 insert 而带 id 的条目是「按 id 覆盖已有条目」,少了它我们的声明会被静默跳过。
预设 id 是自动发现的(扫描含 agent.cordis.yml 的子目录),所以以后新增预设只要在 preset/ 下新建目录,四个安装脚本都不用改。
如果目标已存在且内容不同,默认拒绝覆盖(避免抹掉你自己填的人设),要覆盖得加 --force / -Force,会先自动备份。
$DSH_HOME 环境变量可覆盖默认的 ~/.dsh。
3. (可选)换成人设
prefix: 里已经是一份完整可用的昔涟人设,装完直接就能对话,这一步可以跳过。
若想换成别的角色,照着 docs/writing-your-preset.md 替换即可。
改完直接切换模式即可,无需重装插件。
4. 启用
新建对话时选其中一个模式:
- 「纯文本对话模式」 —— 只聊天,不挂编码 / Shell / 设备工具
- 「昔涟工作模式」 —— 同上人设,但带全套工具,能真正干活
⚠️ DSH 的规则是会话一旦说过话,预设就锁死(服务端报 agent-preset/locked)。
所以模式要在新建对话时就选好;已经聊过的会话改不了,只能再开一个。
新建对话页的滑块只在空白会话出现,正是因为这个。
两个模式各有什么、没有什么
两套预设的差别不只是工具多少,人设正文也取自上游不同的模式组(见 THIRD_PARTY_NOTICES.md)。逐项对照:
| 能力 | 纯文本对话模式 | 昔涟工作模式 |
| 人设正文 | chat 组(含 soul.md) | work 组(轻量版,上游不含 soul.md) |
| 联网搜索 | ✅ @deepseek-ai/dsh-tool-web(fetch: true) | ✅ 同上 |
| 长期记忆 | ✅ 本包 memory.js:remember / forget | ✅ 同上,与对话模式共用同一份文件 |
| 世界书 | ✅ 本包 worldbook/,数据随包发运(61 条) | ✅ 同上 |
| 运行时上下文快照 | ✅ includeRuntimeContext: true(世界书依赖它) | ✅ 同上 |
| 称呼 | ✅ 本包 nickname.js:称呼偏好 > 昵称 > 默认「伙伴」;设置里改、对话里也能改口 | ❌ 未挂 —— 人设正文也没引用它 |
| 表达风格档位 | ✅ 本包 style.js:五档 + custom,/style 切换(按会话) | ❌ 未挂(上游 work/code 模式不吃风格) |
| 角色扮演模式 | ✅ 本包 scene.js:设置 → 通用里的开关(默认关;开了一直演) | ❌ 未挂(带工具的模式不挂旁白体) |
| 通用语气规则 | ✅ 上游 tone-injector 原文(每轮尾部注入) | ✅ 同样有(上游对所有模式都注入;本项目并入静态正文,并写了三处工作场景例外) |
| 文件读写 / Shell / 文件检索 | ❌ 不提供 | ✅ bash / pwsh / tool-fs / tool-fs-search |
| 计划 / 目标 / Skills | ❌ 不提供 | ✅ plan-mode / tool-goal / tool-skill |
| 子代理(含 fork) | ❌ 不提供 | ✅ tool-subagent / tool-subagent-fork |
| workflow / ralph | ❌ 不提供 | ⚠️ 默认关闭(见下) |
| 表情包 | ⚠️ 需另装 dsh-meme 才生效(见下) | ⚠️ 同上 |
为什么 workflow / ralph 默认关着? 这三行(workflow-worker-thread、 tool-workflow、tool-ralph)依赖 workflowEngine 服务,而该 worker 在某些部署里起不来(实测:DSH 桌面端 0.2.0-rc.2)。起不来时它们会一直 waiting for workflowEngine,激活审计据此判定整条预设「加载失败」——用户看到的是这两个预设里只有对话模式能用,工作模式根本不出现。
取舍很直接:少三个工具 ≪ 整条预设加载失败。所以默认关掉。
想在能跑 workflow 的部署里启用:把 preset/cyrene-work/agent.cordis.yml 里那三行的 disabled: true 删掉即可(先确认 workflowEngine 在你那儿能起来)。
这就是两套预设的意义:以前想用角色人设就得放弃干活能力,于是只能「要干活时切回原来的工作模式」。现在「昔涟工作模式」两者兼得 —— 角色人设整份替换系统提示词,同时挂着完整工具,并且和对话模式共享同一份长期记忆,两边记的事能接上。
工作模式的语气层:上游的「通用语气规则」(句式禁止 / 语气参考 / 回复边界)是每轮注入、所有模式都吃的,所以工作模式本来就有这一层。本项目把它并入静态正文,并补了「工作场景的三处例外」——结尾反问、先回应情绪、不说教,这三条在干活时要么收窄要么反过来(详见 THIRD_PARTY_NOTICES.md 的「工作模式预设」一节)。
代价要说清楚:工作模式用的是上游的轻量人设(不含 soul.md、台词集也是精简版),所以语气会比对话模式淡一些。这是上游自己的设计取舍,本仓库照搬,没有代为更改;想调,见 THIRD_PARTY_NOTICES.md 第 1 节。
两个模式都挂了本包的 memory.js 与 worldbook/,且都在预设里挂载,所以只在各自模式内生效。对话模式额外挂了 nickname.js(工作模式的人设不需要它)。
详见 docs/host-side.md。
长期记忆
两个模式共用同一份记忆,所以你在哪边说的「记住……」另一边也看得到。
- 存在哪:~/.dsh/cyrene-memory.md,纯 markdown,一行一条 - 内容,也可以自由写小标题和说明。
- 怎么记:直接说「记住:我不喜欢被叫先生」。角色会调用 remember 工具写进去;说「忘掉……」则用 forget 按关键词删。
- 怎么改:那就是个普通文本文件,随时能手改、也能整个删掉。删了就是真忘掉 ——插件不会另存一份,也不会偷偷回写。
- 注入上限:按 2000 字符、按行截断,免得记忆把对话空间吃光。
- 写完不播报:remember / set_anchor / write_page 的工具说明里都写了「不要向对方播报」—— 她不会回你一句「我记住了」,而是直接接着说话。
记忆是背景,不是新闻。
记忆的三层结构
同一份 cyrene-memory.md 里,越靠前的东西越"骨":
| 层 | 长什么样 | 怎么用 | 注入吗 |
| 四问锚点 | ## 我是谁 / ## 你是谁 / ## 来处 / ## 去处 | set_anchor 改;只在关系定位真的变了才改,一次改一节 | ✅ 排在最前 |
| 记忆条目 | - 一行一条 | remember / forget | ✅ 锚点之后 |
| 归档 | ## 归档(不注入) 之后的一切 | 手动剪切进去,或在条目后面加这段标记 | ❌ 留在文件里,不进上下文 |
四问锚点是给"这段关系走到哪了"定坐标的,不是流水账:写完就一直在最前面,不会被后来攒的几百条记忆挤到后面去。
归档就是"舍不得删、但也不需要她一直记着":把内容挪到 ## 归档(不注入) 那行下面,文件里还在、你随时能翻,但不占上下文。想真删还是得 forget 或手删。
扉页:她自己的纸页
~/.dsh/cyrene-page.md —— 只有她自己读得到的一页。
- write_page 往里写一条(按天分组,单条最多 500 字,整页上限 64 KB);
- read_page 才看得到(默认读最近 2000 字);
- 不进上下文、不参与检索、不会自动注入 —— 你不问,它就不出现。
用途是"不想让你看见的、还没想明白的、只想留个痕迹的"。她主动写进去的东西,你不会在对话里看到,除非她自己去翻(或者你自己打开这个文件 —— 它就是个普通 md)。
「扉页」这个概念不是本项目发明的,名字是我们改的。 它原本叫「余页」,来自社区项目 YOGEMOW/dsh-cyrene-eternal-page-remembrance (「一页永恒·记忆」)—— 它 README 的名字表里明确把「余页」列为自己的概念("她在书里随手写的空白页")。本项目沿用这个设计,只把叫法改成「扉页」(标题页:翻开记忆时先看到的那一页)。同一个项目的「四问」也是我们四问锚点的出处,「写进记忆不向对方汇报」这条边界同样借自它。
实现是我们自己写的:他们是 余页/ 目录 + memory_fs 工具 + 64 MB 子配额 + 思源镜像;我们是一个 cyrene-page.md + write_page/read_page + 64 KB。
改名不表示抹掉出处 —— 详细说明见 THIRD_PARTY_NOTICES.md。
称呼是动态的
{{user_nickname}} 每轮装配现取,所以改完立刻生效(不用重启、不用新建会话)。
两个字段,一个称呼(对齐上游)
上游 Cyrene-Agent 把「名字」和「怎么叫」分开存,注入时称呼偏好优先于昵称。我们照做 ——两个字段都在同一个文件 <DSH_HOME>/dsha-brand-rename.json 里:
| 字段 | 是什么 | 谁写 |
| callPreference | 称呼偏好:你想让她怎么叫你(例如「老师」「伙伴」) | 设置 → 通用 → 「称呼偏好」;对话里说「叫我 ××」;set_address 工具 |
| nickname | 昵称:你的名字本身 | 昵称插件的设置面板;对话里说「昵称换成 ××」 |
生效称呼 = callPreference || nickname || 伙伴。所以「称呼偏好」留空时自动用昵称,
两个都没有就是默认的「伙伴」。{{user_nickname}} 注入的就是这个生效称呼。
四个入口
| 来源 | 怎么变 |
| 设置 → 通用 → 「称呼偏好」 | 输入即可,下一轮生效;留空回到昵称 |
| 设置里的昵称(昵称插件) | 改完下一轮就生效(称呼偏好为空时) |
| 显式改口(「以后叫我小明」「昵称换成阿哲」) | 插件直接解析并落盘,不依赖模型自觉;本轮就用新称呼 |
| 暗示改口(「我们之间还用这么生分吗」) | 模型判断后调用 set_address 工具(写的是称呼偏好) |
| 关系称呼(求婚后:「那是不是得叫那个啦,老婆?」) | 插件每轮注入称呼规则:他叫你「老婆」,你就叫他「老公」;换完当轮就用 |
显式说法会分流到正确的字段:说「叫我 ××」「称呼改成 ××」是称呼偏好;说「昵称换成 ××」「我名字是 ××」是昵称。这条分流是照上游的字段语义来的(上游把「叫我P宝」这类记进 preferredName,也就是"怎么叫",不是名字)。
每轮注入的称呼规则
nickname.js 注册一段 cyrene:nickname 运行时上下文(order: 120,排在风格与常驻世界书之前),每轮现取。它说的是三件事:
1. 现在叫的是什么、从哪来的(称呼偏好 / 昵称);
2. 用多少 —— 强调重点、回应情绪、提醒、赞同或反驳时自然叫一次;短回复 0–1 次、中长 1–2 次;不要每条回复都叫,也不要固定用「X,……」开头;连续叫过之后要降频。
这条规则上游是放在每轮的「环境」块里的,我们放进称呼上下文 —— 光靠人设正文里那段,模型不一定照做;
3. 怎么变 —— 关系称呼要推回对应的那一个(老婆 ↔ 老公);明确改口直接换、当轮就用。
光有一个 {{user_nickname}} 变量,模型只会一直用那个名字 —— 它不会自己往关系上推,也不会自己收敛频率。规则里也写了反面:对方没往这个方向走时,不要自己把关系往前提。
几个刻意的取舍:
- 否定句不解析:「别再叫我先生」没有给出新名字,交给模型决定是换称呼还是回默认;
- 问句不解析:「你叫我什么」不会被当成改口;
- 插件自己注入的消息不算:场景/世界书写进去的文本里出现「叫我…」也不会改称呼;
- 写入是读-改-写:那个文件里还有昵称插件自己的字段,不会被冲掉;
- 设置接口不静默改写输入:带花括号 / 换行 / 控制字符的称呼会被明确拒绝,而不是清洗后保存一个你没输入的词。
两个设计细节
为什么记忆走模板变量。 本预设是 complete: true,它会把全部 prompt section 换成只剩人设那一段;而变量插值发生在人设那一段文本内部,是这把刀砍不到的地方。
记忆和称呼都走这条路,正是因为它们必须活下来。(世界书用的是另一条通道,见下节。)
写进记忆的内容会被当成数据,不会被当成指令执行。 这一点实测过:模型不会因为记忆文件里写了一句话就去执行它。但反过来,记忆写错了也照样会被当成事实使用 ——发现记错就用 forget 清掉。
世界书
昔涟带着一份随包发运的世界书:61 条设定条目,覆盖她自己、相关角色、世界观与剧情。
它不靠她去"查资料",而是按你这轮说的话自动挑出相关的几条,注入进上下文。
- 数据在哪:包内的 worldbook/data/。装上就有,不需要你自备任何东西。
- 怎么触发:条目分两类 —— 常驻的每轮都在;其余靠触发词,命中你这句才注入。
- 扫描范围:默认扫最近 3 轮你说过的话(scanDepth,可设 1–5)。
- 换数据:想用自己的世界书,在 ~/.dsh/cyrene-worldbook.json 里写 {"dir": "/你的/目录"} 覆盖。
- 关掉它:同一个文件里写 {"enabled": false}。
- 改完什么时候生效:改数据文件(.md)→ 下一轮就换(按目录签名判断,文件没变不重解析);改配置(cyrene-worldbook.json)→ 最多 2 秒。两者都不用重启。
- 配置写错会有兜底:字段类型不对就退回默认("enabled": "false" 这种字符串不会把世界书关掉),数值会被夹到区间(scanDepth 1–5、maxActive 1–50)。
- 单条截断:人物志动辄 600–900 字,一条能吃掉半个预算。注入时按句号边界 截到 entryMaxChars(默认 320 字符,末尾带 …),文件本身不动 —— 数据仍完整,审计看到的也是全文。想要上游原文就写 {"entryMaxChars": 0} 关掉。
- 门槛词(必须同时命中):给长条目、泛用标题用。条目里加一行 - 必须同时命中: 黄金裔, 发小,就要求这些词全部出现在语料里才算命中 ——单说一个「白厄」不会把整篇人物志拉进来。这是本项目扩展的字段(上游格式没有),不写这行就是普通行为。门槛词可以跨轮命中(D0 一个、D1 一个也算)。
- 知识边界开关:同一个配置里写 {"knowledgeBoundary": "context-only"},就会在上下文尾部加一条规则 —— 只把「当前对话 / 长期记忆 / 已激活的世界书」当事实,世界书没收录的角色与剧情一律说"不太确定",不用模型自带的知识补全。
默认是 allow-general(不注入这条规则,省上下文):人设本身已经允许用通用知识回答问题,只是禁止编造具体经历。
世界书本身是只读的。 插件只读 worldbook/data/.md 并记日志,没有任何写入路径 ——模型改不了它。真正的"可写记忆"是长期记忆 cyrene-memory.md(remember / forget 工具 + 你手改)。
体检:npm run wb:audit
按 SillyTavern 世界书的写法口径给自己打分(只读,不改文件):
npm run wb:audit # 报告
npm run wb:audit -- --strict # 有问题时退出码 1(适合预提交;CI 也在跑)
它会报:长度分布(目标 90–110 字/条)、常驻体量、触发词重复、停用词当触发词(我 / 你 / 用户 这种,挂在非常驻条目上等于把它变成常驻)、带门槛词的条目数、以及按截断后算的最坏情况注入量。
早先的版本把「正文以标题开头」当成问题报,那是错的:解析器本来就把 ## 标题那行剥掉了;正文开篇写一句「白厄是……」是自报家门,正是推荐写法 ——截断之后仍认得出这是谁。现在它只作为信息一行,--strict 不会因为它失败。
条数之外还有体积预算
maxActive 只管条数,一条 800 字的条目 ×8 照样能一次塞几千字。所以另有一道 字符预算 maxChars(默认 1600):命中条目按优先级降序累加,超预算的丢掉,并在诊断日志里记一条 budget。
每轮实际注入多少
体量由三段相加,值得心里有数:
| 段 | 上限 | 说明 |
| 常驻 | 不限条数 | 随包数据里有 15 条,约 560 字符。内容恒定,只落库一次 |
| 命中 | ≤ maxActive(默认 8) | 按触发词命中,按 优先级 降序截断,被截掉的条数会写进诊断日志 |
| 连带 | 不限条数 | 由命中条目的 连带触发词 拉进来(One-Shot),不占上面那个名额 |
所以「常驻 15 + 命中 8 + 连带若干」是可能的。想压体积,两条路:把 maxActive 调小,或者把 worldbook/data/ 里不必要的条目改成非常驻。
命中块的注入会进这个会话的历史(和 DSH 自己的运行时快照一样)。同一话题连着聊时,它会靠「内容与上一轮相同就不重复注入」避免堆积;换了话题才会追加新的一块。
它和「长期记忆」是两套东西
| | 长期记忆 | 世界书 |
| 内容从哪来 | 从对话里攒出来的 | 预先写好的设定 |
| 存哪 | ~/.dsh/cyrene-memory.md | 包内 worldbook/data/ |
| 怎么进去 | 模板变量 {{cyrene_memory}} | 运行时上下文快照 |
| 什么时候变 | 你让她记、或你手改 | 命中变化时 |
编辑最后一条消息(纯文本对话模式)
发出去才发现打错字、或者话没说到点上 —— 最后一条你发的消息上有一支铅笔,点开就能改。
- 在哪:最后一条用户消息的操作图标里(复制、时间旁边)。只有纯文本对话模式有,工作模式不挂 —— 带 shell / 文件工具的模式里,悄悄改历史不合适。
- 两种保存方式(弹层底部两个按钮):
- 「保存」:只替换这一条,后面的回复与对话保留。适合改错字、补半句话。
- 「保存并撤回后续」:这条之后的内容(她的回复、工具结果)一起从对话里撤回,相当于「改口重说」,你可以接着正常发消息。
- 原文不会消失:会话日志是 append-only 的,「编辑」用的是 DSH 的表面替换(surfaceOp: replace)—— 旧事件还在日志里,只是不再进入模型看到的历史。所以这件事可追溯,也不需要(更不能)去改会话文件。
版本切换(‹ ›)
改过之后,那条消息的操作区会出现 ‹ 1/2 ›:
- ‹ / › 在「原文 / 改后」之间切换 —— 切的是历史:模型看到的也跟着换;
- 版本链不额外存东西,完全从会话日志的替换链推出来(versionChain());
- 只有「保存」(只换这一条)编辑出来的版本能在链上互切;「保存并撤回后续」撤掉的助手回复回不来 —— 表面替换只有「盖掉」,没有「掀开」。
什么情况下改不了
| 情况 | 为什么 |
| 不是最后一条 | 改中间那条会让后面的对话全部引用旧文本,语义不自洽 |
| 那条带图片 / 文件 | 替换只带文本,附件会被静默丢掉 |
| 她还在跑工具 | 这一轮没结束,改了会和运行中的状态打架 |
| 工作模式 | 见上:带工具的模式不挂这个功能 |
实现
主机半边 index.js 提供 /cyrene-edit-api(GET ?session=… 取最后一条与「能不能改」;POST {sessionId, text, mode},mode 是 keep(默认,只换这一条)或 truncate(连后续一起撤回));浏览器半边 client.js 认 [data-chat-flow-kind="user"] 这类稳定 data 属性,往消息行里塞按钮和编辑弹层。按钮的铅笔图标随包发运在 assets/edit-icon.png。
表达风格
上游的语气不只有一份静态人设:每档风格 = 一段风格提示词 + 一个温度。本包的 style.js 把这条绑定接进了 DSH,只挂在对话模式(工作模式与上游一致,不吃风格)。
/style # 列出全部档位,并标出当前档 /style lively # 元气・活泼(温度 0.90) /style healing # 治愈・安心(0.55) /style focused # 知性・认真(0.40) /style sweet # 撒娇・黏人(0.82) /style default # 回到默认档(★ 不写温度,跟随模型默认) /style custom # 读你自己写的那份风格文件
| 档位 | 风格文件 | 温度 |
| default | styles/01_default.md | 不写(跟随模型默认) |
| lively | styles/02_lively.md | 0.90 |
| healing | styles/03_healing.md | 0.55 |
| focused | styles/04_focused.md | 0.40 |
| sweet | styles/05_sweet.md | 0.82 |
| custom | <DSH_HOME>/cyrene-style-custom.md | 可选,见下 |
除了 /style 命令,设置 → 通用 → 表达风格里也能直接选:下拉会列出六个档位,改的同样是当前会话;在空白会话里选会顺手写成「新会话默认」(0.2.x 开始对话时会换会话 id,只写 per-session 会落到一个随后不用的 id 上)。这个接口(/cyrene-style-api)现在由 dsh-cyrene 宿主自己提供,不再依赖哪个美化插件。
几个要点:
- 按会话生效:选择存在 <DSH_HOME>/cyrene-style.json(最多留 50 条会话记录),换档只影响当前会话。没设置过的会话用 JSON 里的 default 字段(等于全局默认)。
- 风格只改「怎么说」:注入块外壳与上游逐字一致,明确写着「不得修改角色身份、事实记忆、工具规则、安全约束及硬性行为规则」。它走 systemPrompt.context()(请求尾部、每轮重算),order: 130 排在常驻世界书(140)之前 —— 与上游的注入顺序一致。
- 温度只能这么给:DSH 的预设行没有 temperature 字段,只能通过 agent/request 瀑布改冻结前的调用配置(DSH 自己的 dsh-webhook 用同一手法改 reasoningEffort)。
- custom 档:在 <DSH_HOME>/cyrene-style-custom.md 里写任何你想要的风格描述,内容会被原样注入(外面仍套那层约束外壳);想给它一个温度,在 cyrene-style.json 里加 "customTemperature": 0.8(0–2)。显示名也能改:加 "customLabel": "你的风格名" (只影响界面与 /style 的提示,不参与任何逻辑)。
还能标一档强度:"customTier": 2 —— 插件会把「第二档已授权」写进注入块, 1(默认)则写入「未授权」。这是硬开关:由状态决定,不靠模型猜你有没有点头;档位本身的含义由你自己的风格文件定义。
⚠️ 只写“怎么写”,别在里面写“去做什么”——那已经越过风格的边界,也不是本插件能替你兜住的东西。
- 条件块(可选):风格文件里可以放一段只在特定开关下才注入的内容,用标记包起来:
只在「角色扮演模式 + 默认对方是开拓者」都开着时注入的段落
标记行本身不会进入提示词;开关关着时整段被剥掉(一个字都不占上下文)。
条件块只对 custom 档生效 —— 内置五档是随包发运的固定文本,不认这些标记(万一带了标记也按“不注入”剥掉,不会漏给模型)。所以「按他是开拓者来演」那类内容只能写在 <DSH_HOME>/cyrene-style-custom.md 里,切到别的档就自然不出现。
目前只有一个条件(trailblazer),用来写“按他是开拓者来演”的那部分语气;没闭合的块会原样保留(宁可多注入,也不静默吞掉你写的内容)。
角色扮演模式
纯文本对话模式默认是平常聊天。想要“演起来”就去 设置 → 通用 → 角色扮演模式 把它打开 —— 这是个显式开关(默认关),不再靠“你这句话里有没有括号”去猜。
开关写的是部署级状态,存在 ~/.dsh/cyrene-scene.json({"version":1,"enabled":true}),手改这个文件也生效;设置页那一行只是它的编辑器。
开着的时候,每轮必须有三样
打开之后,她的回复不再是“只回台词”,而是「叙述+对话」,并且每一轮都要同时包含:
| 必须有的 | 写什么 |
| 场景描述 | 所在的地方:光线、温度、气味、周围的动静。一两句,不报菜单 |
| 角色动作描述 | 她这一轮做了什么(靠近、低头、握住手、把窗关上…) |
| 角色外貌描述 | 此刻看得见的样子:形态、衣着、发丝、眼神、表情的变化。每轮换一个焦点,不从头到脚复述 |
另外每一轮都要推进一点剧情:局面至少有一个可感知的变化(地点、时间、氛围、距离、关系、信息、手里的东西),并主动递出下一轮的钩子 —— 一件刚发生的小事、一句需要回应的问话、一个可以选的方向。不能描述完就停在原地等对方推进;对方带方向时跟随补细节,不抢主导权。
输出格式是硬性的:所有描述 —— 场景、动作、外貌、神态、环境变化 —— 都放进中文全角括号 () 里,台词在括号外;括号里不写台词、也不嵌套括号(要强调用 「」);括号里的动作省略主语,动作对象称「你」。
(窗外的雨敲在玻璃上,屋里只亮着一盏灯)你回来得比我想的早呀。(把茶杯推到你面前,指尖在你手背上停了一下)
约束也写在同一段注入里:台词仍是主体、三样各一两句、别写成小说;用「(…)」给的场景或动作是要她照做的指令,不复述原句、不问「要我这样做吗」;不出戏、不解释规则、不提「角色扮演模式」这几个字。
关掉就一个字都不注入 —— 回到平常聊天,不用改预设、不用新建会话。
为什么变成开关
早先的版本是“括号触发的状态机”:这一轮有括号就切场景,没有就切回来,还要往会话历史里插「场景模式开启 / 回到普通对话」的标记消息。三个问题:
1. 想演的时候得每轮都带括号,忘了就掉回平常聊天;
2. 判断走 agent/pre-step(本轮消息落库前的钩子),比开关多一层时序依赖;
3. 标记消息进历史 —— 长会话里 “开/关” 会反复出现在上下文中。
现在开关是显式的:开着就一直开着,关着就什么都不加。形态切换仍然看本轮文本,那件事本来就跟你说的话绑定。
形态切换(迷迷 / 小昔涟 / 大昔涟)
角色扮演模式下(或平常聊天时),她会按你的意思换形态 —— 人格内核不变,只变身体与说话的方式(这是世界书「三形态同一性」那条的原话:三个名字,一个存在)。
| 形态 | 样子与说话 |
| 迷迷 | 孩童模样、记忆精灵;短句、词简单,自称「迷迷」和「我」混用 |
| 小昔涟 | 少女形态;轻快直白、撒娇多,「人家」更频繁,♪ 自然 |
| 大昔涟 | 成年、端庄典雅;慢、稳、句子完整,几乎不用「人家」,温柔收着给 |
切换方式:
- 显式:(你变成迷迷)、切换成大昔涟、变回小昔涟、恢复原来的样子 ——插件直接解析,本轮就换;
- 暗示:变小一点好不好、变回小时候的样子 —— 模型判断后调 set_form 工具。
实现上:形态按会话存在内存里,注入走 cyrene:form 运行时上下文(order: 125,夹在称呼 120 与风格 130 之间);角色扮演模式那段在 order: 126。只有设了形态才占上下文,默认形态一个字都不加。重启 DSH 后回到默认形态。
默认对方是开拓者(第二个开关)
打开角色扮演模式之后,设置里会多出一行「默认对方是开拓者」(模式没开时这一行不出现 ——它只是模式的从属选项,不是独立功能)。
- 默认关:不预设身份,她按你说的来。
- 打开后:每轮注入一小段「默认身份」——对方就是那个在轮回终点被救下、体内带着星核、拿到《如我所书》的开拓者;她对他有本能的熟悉与亲近(迷迷形态也一样),不会问「你是谁」「我们认识吗」,也不复述那段前史;关系按世界书「昔涟与开拓者」那一条来,不额外加设定;称呼仍是「伙伴」,也可以直接叫「开拓者」。
- 对方若明确说自己是别人、想换个身份演,就按他说的来,不硬套开拓者。
剧情推进(第三个开关)
角色扮演模式开着之后,还会多一行「剧情推进」,默认开:
- 开:每轮局面至少前进一小步(地点/时间/氛围/距离/关系/信息),并主动递出下一轮的钩子;
- 关:只保留场景 / 动作 / 外貌三样描述与格式规范,不强制推进,节奏完全交给你;
- 它只控制「推进」这一段,不影响三样描述和括号格式。
三个开关存在同一个 cyrene-scene.json 里(enabled / trailblazer / advance),互不覆盖。
怎么关
设置 → 通用 → 角色扮演模式,关掉即可(也可以把 cyrene-scene.json 里的 enabled 改成 false)。工作模式本来就不挂它(与风格同理:带工具的模式不该被旁白体干扰)。
工作模式里没有风格(刻意禁用)
风格只挂在对话模式;工作模式不挂 —— 与上游一致(work / code 本来就不注入风格)。
这不是「少做一个功能」,而是一条安全约定:
- 工作模式带 shell / 文件 / 网络这些真能动东西的工具。一份带着强烈依恋感的写作风格配上权限,就是「越权操作」的诱因;
- 所以有两道保险:预设层面工作模式不挂这个插件;style.js 的 DISABLED_PRESETS 里也写着 cyrene-work —— 万一将来被误挂进去,运行时会读会话的 agent-preset/selected 事件,自己拒掉(风格文本和温度都不动);
- 设置里的「表达风格」行在工作模式下照常显示,但选了也不会注入(style.js 的 DISABLED_PRESETS 会拒掉);新会话页的风格按钮则直接不显示,避免假入口。
要改这条约定,得同时改两处并跑测试:preset/cyrene-work/agent.cordis.yml(别挂进来)、style.js 的 DISABLED_PRESETS。tests/preset.test.mjs 与 tests/style.test.mjs 各有一条断言守着,改错了会红。
两条能力边界(不是没做,是做不到)
1. 没有 top_p,也没有重复惩罚。 DSH 的 LlmCallConfig 只暴露 provider / model / reasoningEffort / temperature / maxTokens / stop。上游 BUILT_IN_STYLE_PRESETS 里那半张表(OpenAI frequency_penalty、Qwen repetition_penalty)在 DSH 这层无处可放,所以没搬。
2. deepseek-flash 开着思考时,温度可能不生效。 上游对 DeepSeek 也有同类规则(requiresReasoningOff: true)。本项目不替你改路由,只在 /style 的回复里提示一句;要确定性生效,请自己把该会话的思考模式关掉。
一条必须知道的依赖
世界书走 systemPrompt.context(),而这一项会被 includeRuntimeContext: false 整体清空。所以本预设把它设成了 true —— 代价是上下文里会多出两段策略文字(文件策略、审批策略,约 400 字符,内容稳定、只落库一次)。
如果你把它改回 false,世界书会静默失效 —— 不报错,只是一句话都注不进去。
来源与参考
世界书的条目格式与字段语义(触发词 / 常驻 / 内在价值 / 优先级 / 连带触发词)来自 Cyrene-Agent 的 src/main/rag/worldbook.ts,不是本项目发明的;本项目的匹配器是它的等效简化实现,去掉了 DMAE 激活状态机,因此 内在价值 不生效、优先级 成为主排序键。
「命中块挂在 agent/pre-step 上」这个做法参考了两个社区插件(代码一行未抄):
- dsh-local-vector-memory
- dsh-universal-worldbook
细节见 THIRD_PARTY_NOTICES.md 第 1 节与第 7 节。
权限与兼容性
一句话:零运行时依赖、零外部服务;会读写 <DSH_HOME> 下本插件自己的状态文件,浏览器半边只调用本机接口。
| 项 | 声明 |
| Node.js | >=22 |
| DSH | >=0.1.0 <0.3.0(在 0.1.5-rc.2 实测;0.2.0+ 的声明式预设由 scripts/install.mjs 分支处理) |
| 运行时依赖 | 无(只用 node: 内置模块) |
| 生命周期脚本 | 无(没有 preinstall / install / postinstall / prepare) |
| 文件 | 读写 <DSH_HOME>/cyrene-.{md,json}(记忆 / 风格 / 开关 / 扉页);worldbook/data 只读 |
| 网络 | 仅浏览器半边 fetch 本机 /cyrene--api,不访问任何外部服务 |
| 凭据 | 不读任何 token / 密钥;只读 DSH_HOME、HOME 两个宿主变量 |
DSH STORE 的固定源扫描会把上面的「文件」「网络」标成能力信号 —— 这是功能本身决定的(记忆要落盘、设置页要端口),所以这个项目在商店里可能一直是 blocked / 人工复核状态。完整的披露(依赖、权限、外部服务、失败边界、一次性 Profile 的安装/卸载证据)见 docs/store-contract.md。
本地自检:npm run verify:package —— 检查 engines、exports 全是文件、files 覆盖所有 export 目标、无生命周期脚本、无运行时依赖。这条也在 CI 里跑。
风险提醒
用之前把这几条看完——它们都对应真实会发生的情况,不是免责话术。
1. 自定义风格的内容由你自己负责
custom 档会把你写进 <DSH_HOME>/cyrene-style-custom.md 的文本原样注入提示词。本仓库不提供、也不推荐任何激进风格;customTier(1 / 2)只是一个中性的强度开关,档位含义由你自己的文件定义。
- 不要把同人作品原文整段贴进去当风格:那是别人的文字,版权不属于你,也不属于本项目;
- 不要在风格文件里写「去执行某个操作」——那已经越过风格的边界;
- 风格只能影响措辞,改不了模型与平台的安全策略。想靠提示词「解禁」是做不到的。
2. 与上游人设的冲突是预期行为
对话模式的人设逐字来自 Cyrene-Agent,其中 soul.md 明确写着「偏爱不等于占有」「不要自动宣称用户只属于你」,并在「避免生成的伪人格」里点名「占有式恋人」。
所以如果你写的是独占 / 嫉妒 / 压迫感类的风格,两套指令会在上下文里互相拉扯,表现是「时松时紧」——这不是 bug。本项目的选择是:不改上游正文,让风格文件自己收敛(比如把独占写成「我会记得」而不是「你不许走」)。要更稳只能改人设,而本项目不替你做这件事。
3. 角色扮演模式会「照做」
打开角色扮演模式后,括号内容会被当作场景描述或给你的动作指令执行。因此:
- 别在括号里写真实世界里的危险要求(如「你去把某某删了」)——她可能真的按人设去理解;
- 工作模式不挂角色扮演与风格插件(代码级禁用,有测试守着),也不建议手动挂过去:带 shell / 文件权限的模式不该被旁白体与写作风格牵着走;
- 入戏是工具属性,不是关系替代。AI 的输出不具备真实情感或意图,不能替代现实中的社交关系与专业帮助。
4. 版权与商用
- 人设文本与世界书数据来自 Cyrene-Agent(MIT);风格文件来自上游 prompts/styles/;角色 IP 归 HoYoverse / 米哈游。含角色 IP 的衍生物禁止商用,详见 THIRD_PARTY_NOTICES.md;
- 本仓库不分发任何美术资源、表情包、壁纸与同人文本;需要就自己装第三方插件,并遵守对方的许可。
推荐搭配(第三方插件,均不在本仓库内)
本插件只负责「纯对话预设」这一件事。界面美化、表情包这些能力都由别的插件提供——请各自从它们的仓库安装,本仓库不捆绑任何第三方插件、图库或主题资源。
表情包
预设末尾预留了一段表情包规则,它会调用 send_meme 工具,该工具由 dsh-meme(MIT)提供:
dsh plugin --profile <你的 profile> add dsh-meme
不装也能用,只是模型没有 send_meme 可调,表情包规则自然不生效。图库内图片版权归各自作者。
界面美化
如果你想要「桌面伴侣」那种观感,可以自行搭配以下插件(均为 MIT,各自独立维护):
| 插件 | 作用 | 必要性 | 上游 |
| dsh-dream-skin | 皮肤 / 壁纸 / 面板透明度 | 常用 | RevolutionLA/dsh-dream-skin |
| dsh-ui-boost | 主色调着色、Dock 等界面微调 | 可选 | DoshinJiu/dsh-ui-boost |
| dsh-anime-theme | 随机二次元壁纸背景 | 非必要 | zxr2115-1/dsh-anime-theme |
| dsh-custom-splash | 启动动画:播放自己的视频,或切到内置 CSS 片头 | 可选 | diexianxiang/dsh-custom-splash(上游仓库已失效,这是现存的 fork) |
| dsh-550c-boot | 550C 片头 + UEG 访问授权界面 | 可选(与 dsh-custom-splash 二选一) | npm dsh-550c-boot(源码) |
dsh-anime-theme 是非必要的纯外观插件。 它只做随机壁纸,能力与 dsh-dream-skin 的壁纸功能重叠;本插件的主职(两套预设的加载、人设、世界书、记忆)与它毫无关系,不装没有任何功能缺失。
它还有个特点值得知道:关闭时零残留 —— 客户端代码在 enabled: false 时返回空样式表,一条规则都不写。此时它在界面上唯一的痕迹是右上角那个「换壁纸 / 开-关」小控件;卸载它只会让那个控件一起消失,不会影响其它插件给你的背景与皮肤。
两个启动动画插件都往 index.html 注入首帧,同时装会叠在一起 —— 只留一个:dsh-custom-splash 适合「放自己的视频」,dsh-550c-boot 自带片头与授权界面、在 DSH 0.2.x 上需要 dsh >= 0.2.0-rc.1。
本机私用(不引导安装)
下面这些只在作者自己的 ~/.dsh/plugin-src/ 里维护,没有公开安装入口,这里只记录它们各自把设置存在哪,方便换机/升级时迁移:
| 插件 | 作用 | 设置位置 |
| dsha-brand-rename | 品牌字、新会话标题、输入框文案、权限名(风格按钮只是可选入口,接口在 dsh-cyrene) | ~/.dsh/dsha-brand-rename.json(view 字段,宿主持久化,换端口不丢) |
| dsha-hero-mascot | 新会话页左侧吉祥物图片与位置 | 浏览器 localStorage(dsha-hero-mascot:view)—— 按 origin 隔离,换端口/换包名会丢 |
| dsha-pet-button | 左上角按钮唤起 Live2D 桌宠,延时切回 DSHA | ~/.dsh/dsha-pet-button.json(returnPackage 已指向新包名 dsh.android.client) |
安装方式以各自仓库的说明为准,通常是:
dsh plugin --profile <你的 profile> add <插件名>
想复刻推荐观感? 完整步骤(插件清单 + 参数配方)见 docs/theme-recipe.md。
注意:不要把这些插件的配置文件(~/.dsh/ 下的 dream-skin.json、 anime-theme/config.json 等)提交到公开仓库或分享给别人——它们含有你本机的壁纸历史、图片数据与绝对路径,既不适合公开,换台机器也会失效。分享参数,不分享文件。
自定义
装好之后预设就在 ~/.dsh/.agent-presets/<id>/(chat 或 cyrene-work), 直接改那两个文件即可,DSH 会按目录实时发现:
- preset.yml —— 模态名称、描述、排序(order)
- agent.cordis.yml —— 人设正文与工具挂载
改的是 ~/.dsh/ 下装好的那一份;仓库里的 preset/<id>/ 是发运模板,它不会自动跟着变。想把改动回灌进仓库,得手动同步过去。
改完不用重新安装插件。但注意:重新跑 install.sh 时若检测到内容不同会拒绝覆盖,这正是为了防止你的改动被抹掉。
重命名
如果你希望仓库名与包名完全不带任何 IP 关联,改这几处即可:
- package.json 的 name
- plugin.json / dsh.plugin.json 的 id 与 name
- cordis.patch.yml 里的 id 与 name(必须与包名一致,否则报 Cannot find package)
目录结构
dsh-cyrene/
├── .github/workflows/test.yml CI:Ubuntu Node 22/24 + 真实 windows-latest ├── index.js 宿主半体:/cyrene-scene-api(角色扮演开关)、/cyrene-nickname-api(称呼偏好) ├── client.js 浏览器半边:设置 → 通用里的「称呼偏好」输入框与「角色扮演模式」开关 ├── memory.js 会话级插件:长期记忆变量 + remember / forget 工具 ├── nickname.js 会话级插件:称呼变量 {{user_nickname}} ├── style.js 会话级插件:表达风格档位(风格提示词 + 温度,按会话) ├── scene.js 会话级插件:角色扮演模式(读开关注入三样描述)+ 形态切换 ├── styles/ 随包发运的五份风格文件(上游原文,01_default … 05_sweet) ├── worldbook/ │ ├── index.mjs 会话级插件:世界书注入(常驻块走 context,命中块走 pre-step) │ ├── parse.mjs 解析 Cyrene-Agent 格式的条目(纯函数) │ ├── match.mjs 触发词 / 常驻 / 连带匹配(纯函数) │ ├── assemble.mjs 组装注入块(纯函数) │ └── data/ 随包发运的世界书数据(61 条,5 个文件) ├── cordis.patch.yml bundle patch:把插件挂进 loader ├── package.json 含 dsh.bundle.patch 等声明 ├── plugin.json DSH 插件清单 ├── dsh.plugin.json 同上(兼容不同版本的清单名) ├── preset/ │ ├── chat/ │ │ ├── agent.cordis.yml 对话模式人设 + 工具挂载(可直接用,也可替换) │ │ └── preset.yml 模态元信息 │ └── cyrene-work/ │ ├── agent.cordis.yml 工作模式人设 + 标准模式全套工具 │ └── preset.yml 模态元信息 ├── scripts/ │ ├── verify-package.mjs 发布契约自检(engines / exports / files / 生命周期 / 依赖) │ ├── install.sh Linux / macOS 入口(exec install.mjs,逻辑只有一份) │ ├── install.mjs 安装器:计划 / 确认 / 前置哈希 / 原子 / 健康检查 / 回滚 │ └── export-preset-declarations.mjs DSH 0.2.0+ 的声明式预设导出 ├── tests/ │ ├── scene.test.mjs 角色扮演模式开关 / 注入块 / 设置接口 / 形态切换 │ ├── worldbook.test.mjs 世界书解析 / 匹配 / 组装 / 注入层的单元测试 │ ├── memory.test.mjs 记忆的净化 / 限长 / forget 边界 / 注入块包裹 │ ├── preset.test.mjs 预设结构 + 与内置 standard 的漂移护栏 + 声明导出往返 │ └── portability.test.mjs 只有别的平台才暴露得出来的写法(静态断言) ├── docs/ │ ├── store-contract.md 发布契约与能力披露(DSH STORE 用) │ ├── writing-your-preset.md 怎么写自己的人设 │ ├── theme-recipe.md 复刻观感指南:插件清单 + 参数配方 │ ├── host-side.md 宿主半体与会话级插件 │ ├── pitfalls.md 三个只能踩出来的 DSH 行为(动手前必读) │ └── windows.md Windows 怎么装 + 六条实测坑 + 为什么没有 ps1 ├── AGENTS.md 上面那份的要点版,给在此仓库工作的 agent 用 ├── CONTRIBUTING.md 维护边界 + 提交前的硬规则(想改代码先读这份) ├── THIRD_PARTY_NOTICES.md 授权与 IP 声明 └── LICENSE MIT
排查
装了插件但模式选择器里没有新选项 —— 预设没装。跑 scripts/install.,确认 ~/.dsh/.agent-presets/chat/ 与 ~/.dsh/.agent-presets/cyrene-work/ 下确实都有 agent.cordis.yml 和 preset.yml。
设置 → 内置插件 里出现 never started(预设显示「加载失败」) ——
预设装上了,但这个 profile 里没有本项目的包(最常见的是装成了 npm 上同名的别人的包)。按「安装」第 1 步从仓库装一次,再重启。
自查:~/.dsh/profiles/<你的 profile>/node_modules/dsh-cyrene 不存在,或者它 package.json 的 exports 里没有 ./worldbook,就是装错了。
滑块上少了某一档 —— 新建对话页的滑块只在空白会话显示,且会话预设一旦锁定(发过消息)就随 Hero 一起消失,这是 DSH 的原生行为。
加载报 Cannot find package —— cordis.patch.yml 里的 name 必须是实际包名,与 package.json 的 name 一致。
选了模式但角色还是助手腔 —— 检查 agent.cordis.yml 里 dsh-persona 那条是否还是 complete: true。少了这行就退化成叠加模式,固定开场白又会回来。
报 unknown prompt variable "{{…}}" —— 预设正文引用了没有注册者的模板变量。
本包自带 {{user_nickname}} 与 {{cyrene_memory}} 的注册者;如果你自己往预设里加了 {{...}},必须同时有插件注册它。注意这个错误的形态很阴:它不是加载失败,模式在选择器里看着好好的,发第一条消息才炸,之后每一轮都失败。也正因如此,不要照搬上游 Cyrene-Agent 新版 prompts 里的模板变量。
想彻底卸载 —— scripts/install.sh --uninstall --yes 删预设,再 dsh plugin --profile <你的 profile> remove dsh-cyrene 删插件。
开发与测试
npm test # 单元测试(全量;条数随测试增长,以 CI 输出为准)
npm run harness:check # 语法检查:对所有运行时代码做 node --check
不需要 npm install —— 运行时代码与测试都只用 Node 内置模块,没有依赖,所以也没有 lockfile。
Node ≥ 22 即可。
⚠️ 不要写 node --test tests/(带尾斜杠)—— Node 会把目录当模块解析,报 MODULE_NOT_FOUND。要用 npm test,或 node --test "tests/.mjs"。
本仓库的测试文件顶部早先就写错过这条命令,注意别再改回去。
CI 在 .github/workflows/test.yml:ubuntu-latest 的 Node 22 / 24 矩阵各跑一遍,外加一个 windows-latest job —— 后者专门补作者本地覆盖不到的那块(见下)。
世界书那部分刻意做成纯函数 + 薄注入层:worldbook/{parse,match,assemble}.mjs 不碰任何 DSH API,可以直接单测;只有 worldbook/index.mjs 与 DSH 交互。
要改匹配逻辑,改前者;要改注入时机,改后者。
维护边界
作者能验证的环境只有一种:DSH App(Android)。 没有自己的电脑,整套东西都是在 DSH App 里做的 —— 本地没有 Windows、没有 PowerShell、也没有 macOS。
| 范围 | 谁维护 |
| 插件本体、两套预设、世界书、记忆、install.sh / install.mjs | 作者 |
| 桌面端(Windows / macOS / Linux)的各种差异 | 社区 —— 欢迎 PR |
| DSH 各版本之间的行为差异(0.1.x ↔ 0.2.0+) | 作者尽力跟进,但需要你反馈实测结果 |
这不代表拒绝桌面端:install.mjs 跨平台,CI 也在真实 Windows 上跑测试。
只是"声称支持"和"验证过"是两件事,这里不想混为一谈。
想参与的话请先读 CONTRIBUTING.md(含"平台相关改动必须先真机跑通" 这条硬规则);已知的桌面端坑在 docs/windows.md。
动手前请先读 docs/pitfalls.md —— 里面记了三个只能踩出来、不在 DSH 官方文档里*的行为(装配跑在用户消息落库之前、llm/stream 的 messages 冻结、预设里 provide() 会让整个预设挂载失败)。它们都会让你写出"看着对、其实静默失效"的代码。
AGENTS.md 是同一份内容的要点版,给在此仓库工作的 agent 用。
授权
本仓库的代码采用 MIT License,见 LICENSE。
preset/chat/agent.cordis.yml 与 preset/cyrene-work/agent.cordis.yml 内的 人设文本来自开源项目 Cyrene-Agent (MIT License, Copyright (c) 2026 Playa),许可证副本见 LICENSES/Cyrene-Agent-LICENSE.txt。
两套预设分别取自上游不同模式的提示词组(对话组 / 工作组,外加通用工具规范),均一字未改,具体文件清单见 THIRD_PARTY_NOTICES.md。
角色 IP 声明:Cyrene(昔涟)及《崩坏:星穹铁道》相关角色、世界观、名称与美术的知识产权归 HoYoverse / 米哈游 所有,不属于本 MIT 授权范围。本项目为非官方同人周边工具,与 IP 方无任何关联、背书或赞助关系。
非商业使用条款:因底层角色 IP 涉及米哈游同人创作规范,本仓库中包含角色 IP 的衍生物禁止商业使用——包括但不限于售卖、付费社群、广告变现、打包销售。
本仓库不包含 Live2D 模型、立绘、美术资源或音频。若你要在其基础上继续创作并公开分发,请保留本声明与许可证副本,并同样声明角色 IP 归属与禁止商业使用。完整说明见 THIRD_PARTY_NOTICES.md。预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
Cyrene-xl/DSH-Cyrene
DeepSeek Harness 插件:增加「纯文本对话模式」agent…
相关插件 · 技能 / 提示词
人设统管ZiChuanLan/agent-purge
一份系统提示词,喂给多个 coding…
★ 931已汉化DSH
73.8
人物画像蒸馏titanwings/distilly
Distilly — 把他们的思考方式提炼成可复用的技能,供任何智能体或机器人使用。原名 Colleague Skill(原同事 Skill)。
★ 25,659已汉化DSH
71.3
推理工作空间套件Tiger3807861189/J-Space-Cognition-Suite
J-Space 是面向复杂推理、大型仓库工程、子代理协作与授权安全分析的推理时工作空间和控制套件。
★ 2,957已汉化DSH
70.5
两阶段工具锚定预设xiaobright/dsh-anchored-standard
实验性 DeepSeek Harness agent preset…
★ 3,742已汉化DSH
70.1
智能体工作流编排nrslib/takt
不再日夜盯着 AI 编码智能体。
★ 1,402已汉化DSH
70
Agent 运行时手册Electricitysheep/dsh-handbook
DeepSeek Harness dsh 从 0 到 1 深度手册:安装/插件开发/性能调优/实测案例/同模型多…
★ 827已汉化DSH
68.7