DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

Cyrene-xl /

Cyrene-xl/DSH-Cyrene

Verified

DeepSeek Harness 插件:增加「纯文本对话模式」agent 预设——整份替换系统提示词进行纯角色对话,只保留联网搜索与表情包。随包人设文本整理自开源项目 Cyrene-Agent(MIT)。

★ 21 Stars2 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHub
READMESource: main@dc2a4442

This project is an open-source preset plugin for DeepSeek Harness. It does NOT contain any game assets (Live2D models, artwork, audio). The bundled persona text is adapted from the open-source Cyrene-Agent project (MIT, Copyright (c) 2026 Playa). Cyrene (昔涟) and Honkai: Star Rail belong to HoYoverse/miHoYo. This is an unofficial fan tool — non-commercial use only.

使用前请读 风险提醒 —— 自定义风格与角色扮演模式都会影响模型输出,且与上游人设存在已知冲突。


dsh-cyrene

为 DeepSeek Harness(DSH)提供两套角色 agent 预设:

预设 显示名 能力
preset/chat/ 纯文本对话模式 整份替换系统提示词,纯以角色人格对话;只保留联网搜索与表情包,不挂文件 / Shell / 设备工具
preset/cyrene-work/ 昔涟工作模式 同样用角色人设整份替换系统提示词,但带全套工具(文件 / Shell / 计划 / 目标 / 子代理 / workflow);干活时也保持她的身份与说话方式

两者共享同一份长期记忆(<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 的 profile,那边靠它。

所以 0.2.0+ 用户不需要再手动跑 export-preset-declarations 再手贴。 装完重启 DSH 即可。

为什么声明不直接塞进本包的 cordis.patch.yml(那样"装插件即注册"更省事): 那一行在 0.1.x 上根本解析不到,实测会让整个 DSH 起不来 (ERR_MODULE_NOT_FOUND)。所以按代数分流,而不是一刀切。

手贴的路仍然保留(profile 在非默认位置时用)。注意生成的内容自带 - insert: 那层,别去掉 —— patch 里不带 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(默认)则写入「未授权」。这是硬开关:由状态决定,不靠模型猜你有没有点头; 档位本身的含义由你自己的风格文件定义。 ⚠️ 只写"怎么写",别在里面写"去做什么"——那已经越过风格的边界,也不是本插件 能替你兜住的东西。

  • 条件块(可选):风格文件里可以放一段只在特定开关下才注入的内容,用标记包起来:

    <!-- dsh-cyrene:trailblazer -->
    只在「角色扮演模式 + 默认对方是开拓者」都开着时注入的段落
    <!-- /dsh-cyrene:trailblazer -->
    

    标记行本身不会进入提示词;开关关着时整段被剥掉(一个字都不占上下文)。 条件块只对 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。

—/ 5

No ratings yet

Verified DSH bundle

Commit dc2a44420153

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