@riemannre3/dsh-roleplay 0.1.3 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +142 -8
- package/THIRD_PARTY_NOTICES.md +17 -0
- package/cordis.patch.yml +1 -1
- package/lib/assistant-stream.js +24 -0
- package/lib/card-runtime.js +1 -1
- package/lib/client.js +1056 -66
- package/lib/ejs-runtime.js +5 -1
- package/lib/frontend-runtime.js +32 -16
- package/lib/index.js +118 -46
- package/lib/preset-runtime.js +62 -6
- package/lib/prompt-compiler.js +32 -3
- package/lib/rich-message.js +169 -4
- package/lib/split-mvu.js +9 -0
- package/package.json +3 -3
- package/demo.png +0 -0
- package/plugin-settings.png +0 -0
package/README.md
CHANGED
|
@@ -1,10 +1,118 @@
|
|
|
1
1
|
# DSH RolePlay
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> 让 Tavern 角色卡进入 DeepSeek Harness,而不是把你带去另一套聊天系统。
|
|
4
4
|
|
|
5
|
-
`@riemannre3/dsh-roleplay` 是一个 DSH Web
|
|
5
|
+
`@riemannre3/dsh-roleplay` 是一个 DSH Web 插件:导入 Tavern Character Card V2/V3 PNG/JSON,从卡片开场创建原生 DSH Session,再在原生 Conversation 里继续游玩。
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
卡片仍然是卡片;模型调用、上下文、Token 状态、分支和 Session Log 仍然属于 DSH。
|
|
8
|
+
|
|
9
|
+
[](https://www.npmjs.com/package/@riemannre3/dsh-roleplay)
|
|
10
|
+
[](https://github.com/RiemannRe3/DSH-RolePlay/releases/latest)
|
|
11
|
+
[](LICENSE)
|
|
12
|
+
|
|
13
|
+

|
|
14
|
+
|
|
15
|
+
主演示卡是《玄净》的 DSH 适配版:原作由 Foreverse Team 在 [character-card-skills](https://github.com/foreverse-app/character-card-skills/tree/dab0da437810b2ea4b5eec414c10c8fa35e779f8) 中以 [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/) 发布;RiemannRe3 重整了世界引入、持续状态与「云山长卷」,并使用 OpenAI 图像生成工具制作了新封面。截图中同屏的其他角色卡来自同一上游固定版本。独立角色卡文件不随插件分发;完整署名、修改说明与分项许可见 [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md)。
|
|
16
|
+
|
|
17
|
+
## 为什么它更舒服
|
|
18
|
+
|
|
19
|
+
DSH RolePlay 的重点不是再做一层聊天外壳,而是把 Tavern 资产接入 DSH 已有的运行链路。
|
|
20
|
+
|
|
21
|
+
| 设计取向 | 带来的体验 |
|
|
22
|
+
| --- | --- |
|
|
23
|
+
| 对话留在原生 Conversation | 沿用 DSH 的模型选择、消息操作、Token 状态、分支与 Session Log,不维护第二份聊天记录 |
|
|
24
|
+
| 上下文可以逐项检查 | 世界书命中、提示词顺序、Persona、角色字段和示例对话不再藏在一个黑盒 Prompt 里 |
|
|
25
|
+
| 复杂能力分面板呈现 | 世界书、预设、Regex、前端、卡片和 Persona 各自有清楚入口,排查问题不必直接翻 JSON |
|
|
26
|
+
| 兼容边界直接显示 | “能导入”“能开始对话”和“卡内能力完整运行”是三件事;界面展示实际规则数、运行事件、权限和错误 |
|
|
27
|
+
| 插件关闭可逆 | 关闭插件会卸载界面与运行时扩展,但角色卡和 Session 数据仍保存在当前 DSH Web Profile |
|
|
28
|
+
|
|
29
|
+
我们不会用一句“兼容 Tavern 卡”掩盖卡与卡之间的差异。没有载入的 Regex、前端脚本或运行时能力会如实显示,方便你判断这张卡适合直接游玩,还是需要补齐兼容层。
|
|
30
|
+
|
|
31
|
+
## 对话留在 DSH,卡片能力随时展开
|
|
32
|
+
|
|
33
|
+
角色卡在左侧“酒馆”中管理,实际游玩发生在 DSH 原生 Conversation。需要查看卡片怎么工作时,右侧能力栏随时可以展开,不会离开当前 Session。
|
|
34
|
+
|
|
35
|
+
### 卡片内容与世界书
|
|
36
|
+
|
|
37
|
+
<table>
|
|
38
|
+
<tr>
|
|
39
|
+
<td width="50%">
|
|
40
|
+
<strong>角色字段、封面与多个开场</strong><br>
|
|
41
|
+
<a href="https://github.com/RiemannRe3/DSH-RolePlay/blob/v0.1.4/media/readme/04-card.jpg"><img src="https://raw.githubusercontent.com/RiemannRe3/DSH-RolePlay/v0.1.4/media/readme/04-card.jpg" alt="角色卡字段、封面与开场" width="100%"></a>
|
|
42
|
+
</td>
|
|
43
|
+
<td width="50%">
|
|
44
|
+
<strong>真实一轮命中 6 条世界书</strong><br>
|
|
45
|
+
<a href="https://github.com/RiemannRe3/DSH-RolePlay/blob/v0.1.4/media/readme/02-worldbook.jpg"><img src="https://raw.githubusercontent.com/RiemannRe3/DSH-RolePlay/v0.1.4/media/readme/02-worldbook.jpg" alt="世界书条目、命中状态与注入位置" width="100%"></a>
|
|
46
|
+
</td>
|
|
47
|
+
</tr>
|
|
48
|
+
</table>
|
|
49
|
+
|
|
50
|
+
导入后可以直接查看角色描述、性格、场景和多个开场。世界书面板区分全部条目、本轮命中与当前范围,并显示条目的插入位置、执行顺序和真实命中依据。
|
|
51
|
+
|
|
52
|
+
### 模型最终看见了什么
|
|
53
|
+
|
|
54
|
+
<table>
|
|
55
|
+
<tr>
|
|
56
|
+
<td width="50%">
|
|
57
|
+
<strong>提示词槽位、顺序与 revision</strong><br>
|
|
58
|
+
<a href="https://github.com/RiemannRe3/DSH-RolePlay/blob/v0.1.4/media/readme/03-preset.jpg"><img src="https://raw.githubusercontent.com/RiemannRe3/DSH-RolePlay/v0.1.4/media/readme/03-preset.jpg" alt="对话补全预设和提示词顺序" width="100%"></a>
|
|
59
|
+
</td>
|
|
60
|
+
<td width="50%">
|
|
61
|
+
<strong>本轮发送给模型的上下文装配</strong><br>
|
|
62
|
+
<a href="https://github.com/RiemannRe3/DSH-RolePlay/blob/v0.1.4/media/readme/08-context-assembly.jpg"><img src="https://raw.githubusercontent.com/RiemannRe3/DSH-RolePlay/v0.1.4/media/readme/08-context-assembly.jpg" alt="本轮上下文装配结果" width="100%"></a>
|
|
63
|
+
</td>
|
|
64
|
+
</tr>
|
|
65
|
+
</table>
|
|
66
|
+
|
|
67
|
+
预设定义提示词槽位;“酒馆”上下文视图则按实际发送顺序列出 Main Prompt、世界书、Persona、角色字段、示例对话和历史消息,并给出各部分的 Token 估算。这样,“为什么角色突然这样回答”会变成一个可以检查的问题。
|
|
68
|
+
|
|
69
|
+
### Persona 与卡内运行时
|
|
70
|
+
|
|
71
|
+
<table>
|
|
72
|
+
<tr>
|
|
73
|
+
<td width="50%">
|
|
74
|
+
<strong>Persona 作用域与当前绑定</strong><br>
|
|
75
|
+
<a href="https://github.com/RiemannRe3/DSH-RolePlay/blob/v0.1.4/media/readme/05-persona.jpg"><img src="https://raw.githubusercontent.com/RiemannRe3/DSH-RolePlay/v0.1.4/media/readme/05-persona.jpg" alt="Persona 作用范围与当前 Session 绑定" width="100%"></a>
|
|
76
|
+
</td>
|
|
77
|
+
<td width="50%">
|
|
78
|
+
<strong>前端、iframe 与 MVU 运行状态</strong><br>
|
|
79
|
+
<a href="https://github.com/RiemannRe3/DSH-RolePlay/blob/v0.1.4/media/readme/06-frontend-mvu.jpg"><img src="https://raw.githubusercontent.com/RiemannRe3/DSH-RolePlay/v0.1.4/media/readme/06-frontend-mvu.jpg" alt="卡内前端和 MVU 变量运行状态" width="100%"></a>
|
|
80
|
+
</td>
|
|
81
|
+
</tr>
|
|
82
|
+
</table>
|
|
83
|
+
|
|
84
|
+
Persona 可以按全局、当前角色卡或当前 Session 生效。前端面板分别呈现消息 HTML/CSS、iframe、后台脚本、独立前端和 MVU 变量状态,不会把“页面看起来正常”冒充成运行时已经完整工作。
|
|
85
|
+
|
|
86
|
+
### Regex 与插件生命周期
|
|
87
|
+
|
|
88
|
+
<table>
|
|
89
|
+
<tr>
|
|
90
|
+
<td width="50%">
|
|
91
|
+
<strong>Regex 规则、作用域与诚实边界</strong><br>
|
|
92
|
+
<a href="https://github.com/RiemannRe3/DSH-RolePlay/blob/v0.1.4/media/readme/07-regex.jpg"><img src="https://raw.githubusercontent.com/RiemannRe3/DSH-RolePlay/v0.1.4/media/readme/07-regex.jpg" alt="Regex 规则、作用域与设置状态" width="100%"></a>
|
|
93
|
+
</td>
|
|
94
|
+
<td width="50%">
|
|
95
|
+
<strong>随时关闭或重新开启</strong><br>
|
|
96
|
+
<a href="https://github.com/RiemannRe3/DSH-RolePlay/blob/v0.1.4/media/readme/09-plugin-settings.jpg"><img src="https://raw.githubusercontent.com/RiemannRe3/DSH-RolePlay/v0.1.4/media/readme/09-plugin-settings.jpg" alt="在 DSH 插件设置中关闭或开启 DSH RolePlay" width="100%"></a>
|
|
97
|
+
</td>
|
|
98
|
+
</tr>
|
|
99
|
+
</table>
|
|
100
|
+
|
|
101
|
+
Regex 面板把全局、预设和当前卡片规则分开,并将屏幕显示视为可重建投影,不污染 Session 中的正式消息。插件本身可以从 DSH 设置中关闭或重新开启,已有角色卡和 Session 不会因此消失。
|
|
102
|
+
|
|
103
|
+
## 支持范围
|
|
104
|
+
|
|
105
|
+
当前支持:
|
|
106
|
+
|
|
107
|
+
- 导入 Tavern Character Card V2/V3 PNG 或 JSON。
|
|
108
|
+
- 浏览角色描述、性格、场景、示例对话和多个开场。
|
|
109
|
+
- 从角色卡开场创建 DSH 原生 Session,并在原生 Conversation 中继续对话、分支和导出 Session Log。
|
|
110
|
+
- 检查世界书条目、本轮命中、插入位置和执行顺序。
|
|
111
|
+
- 查看与编辑对话补全预设,检查实际上下文装配结果。
|
|
112
|
+
- 管理 Persona,并按全局、角色卡或 Session 绑定。
|
|
113
|
+
- 查看 Regex、富消息、卡内前端、iframe、后台脚本和 MVU 的实际运行状态。
|
|
114
|
+
|
|
115
|
+
不同角色卡可能依赖不同版本的世界书、Regex、脚本框架或前端协议。导入成功不等于所有扩展能力都已支持;请以兼容报告、能力面板状态和真实运行证据为准。
|
|
8
116
|
|
|
9
117
|
## 环境要求
|
|
10
118
|
|
|
@@ -45,12 +153,18 @@ dsh plugin --profile web add @riemannre3/dsh-roleplay
|
|
|
45
153
|
dsh web
|
|
46
154
|
```
|
|
47
155
|
|
|
156
|
+
## 开始使用
|
|
157
|
+
|
|
158
|
+
1. 打开 DSH Web,进入左侧“酒馆”。
|
|
159
|
+
2. 点击“导入”,选择 Tavern Character Card V2/V3 PNG 或 JSON。
|
|
160
|
+
3. 查看卡片的兼容状态、角色字段、世界书和可用开场。
|
|
161
|
+
4. 选择开场并创建新对话。
|
|
162
|
+
5. 在原生 Conversation 中游玩;需要排查上下文时,从右侧展开对应能力面板。
|
|
163
|
+
|
|
48
164
|
## 临时关闭与重新开启
|
|
49
165
|
|
|
50
166
|
打开“设置 → 插件 → 插件配置”,展开 **DSH RolePlay**,点击右侧复选框即可关闭或重新开启。
|
|
51
167
|
|
|
52
|
-

|
|
53
|
-
|
|
54
168
|
关闭是可逆的运行时卸载:酒馆侧栏、对话适配、输入区扩展、Host 路由、事件监听和运行时资源会被移除;角色卡与 Session 数据仍保存在当前 DSH Web Profile 中。重新开启后,插件会恢复这些界面和运行时能力。
|
|
55
169
|
|
|
56
170
|
## 从 Web Profile 移除
|
|
@@ -61,7 +175,7 @@ dsh web
|
|
|
61
175
|
dsh plugin --profile web remove @riemannre3/dsh-roleplay
|
|
62
176
|
```
|
|
63
177
|
|
|
64
|
-
这会从 Web Profile 移除 npm
|
|
178
|
+
这会从 Web Profile 移除 npm 包,不会主动删除插件已保存的角色卡和 Session。重新安装到同一个 Profile 后仍可恢复;不要为了卸载插件删除整个 DSH 数据目录。
|
|
65
179
|
|
|
66
180
|
GitHub Release 中的 `.tgz` 只用于离线安装或 npm Registry 暂时不可用时的故障备用,不是推荐安装方式。
|
|
67
181
|
|
|
@@ -80,10 +194,30 @@ dsh web
|
|
|
80
194
|
|
|
81
195
|
`npm run build` 会编译 Host 代码,并生成 DSH Web 加载的单文件 Client Bundle。修改源码后,重新执行构建和 `dsh plugin --profile web add .`,再重启 DSH。
|
|
82
196
|
|
|
197
|
+
## 截图与第三方内容
|
|
198
|
+
|
|
199
|
+
本 README 的 9 张原始实机截图使用了 Foreverse Team 发布的开源角色卡,以及基于其中《玄净》制作的 DSH 适配版:
|
|
200
|
+
|
|
201
|
+
- 来源:[foreverse-app/character-card-skills](https://github.com/foreverse-app/character-card-skills/tree/dab0da437810b2ea4b5eec414c10c8fa35e779f8)
|
|
202
|
+
- 固定版本:`dab0da437810b2ea4b5eec414c10c8fa35e779f8`
|
|
203
|
+
- 原作作者:Foreverse Team([foreverse.app](https://foreverse.app/))
|
|
204
|
+
- 原作内容许可:[CC BY 4.0](https://creativecommons.org/licenses/by/4.0/)
|
|
205
|
+
- 上游许可文件:[LICENSE-CONTENT](https://github.com/foreverse-app/character-card-skills/blob/dab0da437810b2ea4b5eec414c10c8fa35e779f8/LICENSE-CONTENT)
|
|
206
|
+
- 《玄净》适配与新封面:RiemannRe3;保留原作的两条开场与师徒修行核心,补写世界与玩家来处,重整时间线、持续状态、「云山长卷」和行动选择;新封面使用 OpenAI 图像生成工具制作
|
|
207
|
+
- 适配新增贡献许可:与原作内容一同按 [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/) 提供
|
|
208
|
+
- 截图过程:在隔离 Profile 中导入并渲染卡片,创建虚构 Persona 与一轮演示 Session,再以浏览器默认视口捕获页面
|
|
209
|
+
- 分发边界:第三方角色卡原文件不随 npm 包、GitHub Release 或本仓库公开快照分发
|
|
210
|
+
|
|
211
|
+
Foreverse Team 未参与 DSH RolePlay 的开发,也不代表其认可或为本项目背书。完整说明见 [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md)。
|
|
212
|
+
|
|
83
213
|
## 问题反馈
|
|
84
214
|
|
|
85
|
-
项目源码与问题反馈:[RiemannRe3/DSH-RolePlay](https://github.com/RiemannRe3/DSH-RolePlay)
|
|
215
|
+
项目源码与问题反馈:[RiemannRe3/DSH-RolePlay](https://github.com/RiemannRe3/DSH-RolePlay)。
|
|
216
|
+
|
|
217
|
+
请勿在 Issue 中公开 API Key、Token、私有角色卡或完整 Session Log。兼容问题最好附上卡片规范版本、能力面板状态和经过脱敏的最小复现信息。
|
|
86
218
|
|
|
87
219
|
## License
|
|
88
220
|
|
|
89
|
-
|
|
221
|
+
DSH RolePlay 的第一方代码使用 [MIT License](LICENSE)。
|
|
222
|
+
|
|
223
|
+
README 截图中的 Foreverse 原作内容与原始封面依照上游 [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/) 使用;《玄净》适配新增内容与 RiemannRe3 制作的新封面也按 CC BY 4.0 提供。详见 [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md)。
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Third-Party Notices
|
|
2
|
+
|
|
3
|
+
DSH RolePlay 的第一方代码使用 [MIT License](LICENSE)。本文件记录公开 README 截图中出现的第三方演示内容;这些内容不因出现在本仓库中而改用 MIT License。
|
|
4
|
+
|
|
5
|
+
## Foreverse character-card-skills 与《玄净》DSH 适配
|
|
6
|
+
|
|
7
|
+
公开截图中的上游演示角色卡来自 Foreverse Team 的 [character-card-skills](https://github.com/foreverse-app/character-card-skills),固定于提交 [`dab0da437810b2ea4b5eec414c10c8fa35e779f8`](https://github.com/foreverse-app/character-card-skills/commit/dab0da437810b2ea4b5eec414c10c8fa35e779f8)。上游的 [LICENSE-CONTENT](https://github.com/foreverse-app/character-card-skills/blob/dab0da437810b2ea4b5eec414c10c8fa35e779f8/LICENSE-CONTENT) 明确将 `cards/` 下的卡源文件、转换后的 JSON/PNG 与封面以 [Creative Commons Attribution 4.0 International(CC BY 4.0)](https://creativecommons.org/licenses/by/4.0/) 发布。
|
|
8
|
+
|
|
9
|
+
- 原作作者与署名:Foreverse Team([foreverse.app](https://foreverse.app))。
|
|
10
|
+
- 截图中可见的卡片包括《玄净》以及同一上游卡库中的其他中英文原创卡;其他卡片按上游固定版本导入。
|
|
11
|
+
- 《玄净》修改说明:RiemannRe3 基于 Foreverse Team 原卡制作 DSH 适配版,保留两条原始开场与师徒修行核心,补写世界、宗门与玩家来处,重整时间线、持续状态、「云山长卷」和行动选择;适配版新封面由 RiemannRe3 使用 OpenAI 图像生成工具制作。
|
|
12
|
+
- 适配新增贡献许可:RiemannRe3 对《玄净》适配新增内容与新封面所作的贡献按 CC BY 4.0 提供;复用时应同时保留 Foreverse Team 原作署名、本项目修改说明与 RiemannRe3 署名。
|
|
13
|
+
- 截图过程与分发边界:卡片在隔离的 DSH Web Profile 中渲染,并创建了虚构 Persona 与一轮演示 Session;截图为浏览器原始页面捕获。独立角色卡文件和独立封面不随 npm 包、GitHub Release 或本仓库公开快照分发。
|
|
14
|
+
- README 截图不是单一许可资产:其中的角色卡内容与封面按上述 CC BY 4.0 条款提供;本项目对截图中第一方 DSH RolePlay 界面的贡献以及界面与运行时代码按 MIT License 提供。
|
|
15
|
+
- Foreverse Team 未参与、赞助或背书 DSH RolePlay 及本次适配。
|
|
16
|
+
|
|
17
|
+
如需复用角色卡、卡片封面或截图中包含这些内容的部分,请保留原作与适配作者署名、原始来源链接、CC BY 4.0 链接和上述修改说明,并同时遵守截图中其他组成部分各自适用的许可。
|
package/cordis.patch.yml
CHANGED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export async function* captureAssistantTextStream(stream, onComplete) {
|
|
2
|
+
let body = "";
|
|
3
|
+
for await (const chunk of stream) {
|
|
4
|
+
if (chunk?.type === "text-delta" && typeof chunk.text === "string")
|
|
5
|
+
body += chunk.text;
|
|
6
|
+
if (chunk?.type === "finish" && chunk.reason?.kind === "stop" && body.trim().length === 0) {
|
|
7
|
+
yield {
|
|
8
|
+
...chunk,
|
|
9
|
+
reason: {
|
|
10
|
+
kind: "error",
|
|
11
|
+
failure: {
|
|
12
|
+
name: "EmptyAssistantResponseError",
|
|
13
|
+
code: "empty_assistant_response",
|
|
14
|
+
message: "模型已结束生成,但没有返回可显示的正文,请重试。",
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
yield chunk;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
onComplete(body);
|
|
24
|
+
}
|
package/lib/card-runtime.js
CHANGED
|
@@ -308,7 +308,7 @@ export async function parseCard(bytes, sourceName, inflate) {
|
|
|
308
308
|
if (unsupportedWorldbookFields.size > 0)
|
|
309
309
|
compatibilityRows.push({ capability: "世界书未执行字段", disposition: "仅保留", evidence: `原件完整保存;纯文字运行时不解释:${Array.from(unsupportedWorldbookFields).slice(0, 12).join("、")}${unsupportedWorldbookFields.size > 12 ? "…" : ""}` });
|
|
310
310
|
if (Array.isArray(data.group_only_greetings) && data.group_only_greetings.length > 0)
|
|
311
|
-
compatibilityRows.push({ capability: "群组专用开场", disposition: "仅保留", evidence: `${data.group_only_greetings.length} 个 group_only_greetings
|
|
311
|
+
compatibilityRows.push({ capability: "群组专用开场", disposition: "仅保留", evidence: `${data.group_only_greetings.length} 个 group_only_greetings 保留在原件;当前版本只建立单角色会话` });
|
|
312
312
|
const unsupportedMacros = new Set();
|
|
313
313
|
for (const match of JSON.stringify(data).matchAll(/\{\{\s*([a-z_][a-z0-9_-]*)(?::[^{}]*)?\s*\}\}/giu)) {
|
|
314
314
|
const name = match[1].toLocaleLowerCase();
|