DeepSeek Harness 插件

dsh-narrative-voice

A DSH (DeepSeek Harness) bundle plugin that rewrites the ask_user_question tool description at prompt-assembly time with a fixed narrative-voice rule (default: the answerer narrates), toggled live(英文原文)

跳到安装方式

来源信息

GitHub 仓库
TellToday/dsh-narrative-voice
最近更新
2026年8月20日
分类
工具与能力
GitHub stars
1
载体类型
plugin
目录证据
上游声明已找到 dsh.bundle
证据路径
package.json#dsh.bundle
核对版本
0.1.0-rc.8
上游核对日期
2026-08-21

该证据由上游目录提供。本站没有安装、运行或安全审核这个插件。

安装

默认先复制一段 Prompt,让 Agent 读 GitHub 仓库和源码;需要自己装时再切到命令。

复制这段 Prompt,发给 DSH、Codex 或其他 Agent,让它先读 GitHub 仓库和源码。

请先不要安装或执行任何命令。阅读这个插件的 GitHub 仓库、README 和关键源码,然后用清楚、直接的方式回答以下问题,帮助我判断它是否适合我的需求:

1. 这个插件是什么,解决什么问题;
2. 适合哪些用户和典型使用场景;
3. 安装后如何使用,并给出一个最小使用示例;
4. 有哪些已知限制,以及隐私、安全、兼容性或维护风险;
5. 给出“推荐 / 有条件推荐 / 不推荐”的明确建议和理由。

请区分仓库明确说明、根据源码推断和未知信息。证据不足时请明确说明,不要猜测或照抄 README。

GitHub:https://github.com/TellToday/dsh-narrative-voice
插件名:dsh-narrative-voice
作者:TellToday

检查来源文件

安装前先看这个插件目录里的 README 和其他文件。

文件资源管理器4 个文件
README.zh-CN.md来源说明 · 只读预览
README 语言

dsh-narrative-voice

English · 中文版

一个 DSH(DeepSeek Harness)bundle 插件:让 ask_user_question 工具生成的问题和选项人称始终一致。它在提示词组装阶段把该工具的 questions.description 整句改写为带固定叙述人称规则的描述,并可用 /voice 命令随时开关

为什么会有这个插件

ask_user_question 工具负责向人类问一个简洁的问题,并给出几个可点击的选项。没有固定规则时,模型会在同一个选项内部漂移人称

  • 选项标签用回答者口吻("我自己重启"——"我"=被问的人),选项描述却漂移到 AI 口吻("我会指导你如何重启"——"我"=AI);
  • 还会漏出"用户"这个词("…让你更省心"),把正在读这句话的人用第三人称指代。

同一个选项里出现两个不同的"我",用户根本分不清:提供动作的是谁?"我"到底是谁的视角?

本插件在提示词层面解决:把一条固定的人称规则写进工具自身的描述里,让模型生成的问题(question)、标题(header)、选项标签(label)、选项描述(description)始终用同一种视角,并且永远不称呼回答者为"用户"

它做什么

规则把工具的字段分成两组:

  • question(问题)和 header(标题)——两套方案都一样,固定从 AI 视角写:"我"/"I" = AI,"你"/"You" = 被问的人(用户)。
  • label(选项标签)和 description(选项描述)——跟着所选方案走:

- 方案B(默认,voice: "user"——回答者叙述:"我"/"I" = 被问的人,"你"/"You" = AI。 - 方案A(voice: "ai"——AI 叙述:"我"/"I" = AI,"你"/"You" = 被问的人。

为什么这样设计?为什么要把该工具的字段分成两组?

question(问题)和 header(标题)——这是 AI 在向用户提问。 提问的人当然用第一人称:"我(AI)想问你(用户)一个问题"。所以这两项固定用 AI 视角:"我" = AI,"你" = 用户,两套方案都一样,永远不变——否则问题里冒出指代用户的"我",读者会以为是用户在自己问自己。

label(选项标签)和 description(选项描述)——这是用户将要给出的答复。选项本质上是 AI 预先猜好、替用户写成的回复。但这句答复该用谁的口气说,存在两种合情合理的看法,也就是方案A/B的分野:

  • 方案B(回答者叙述):用户把选项当成自己亲口打出的回复——第一人称在用户手上,AI 只是把用户想打的字猜好、以选项的形式还给他。所以选项里:"我" = 用户("我重启…"),"你" = AI("你会指导我…")。
  • 方案A(AI 叙述):用户把选项当成 AI 递给自己的一道选择题——就像 AI 在说"我遇到个问题,给你两个选项,你选吧:A 我这样处理,B 我那样处理"。所以选项里:"我" = AI("我帮你处理…"),"你" = 用户。

规则只在 ask_user_question 这一个工具内生效(普通回复、其它工具完全不受影响),并且只在确实用到人称时才适用——不强迫本来用不到人称的问题或选项硬塞。

原理

DSH 每次发模型请求前执行 SystemPrompt.assemble(),把拼好的提示词放进一个 assembly 对象,派发到 system-prompt/assemble 这个 Cordis 瀑布事件——瀑布的返回值才是真正发给模型的提示词

本插件在瀑布上注册一个 global: true 的监听器:开启时,在 assembly.tools 里找到 ask_user_question,把 parameters.properties.questions.description(组装后的真实形态是 JSON-Schema)原地替换,再 return next() 放行。只改每请求的克隆——注册表 schema 和参数校验闭包都不受影响。

assemble() 每条消息执行一次,所以 /voice 开关下一条消息就生效,任何对话(包括已经开始的老对话)里都一样。

安装

一条命令,直接从本 GitHub 仓库安装(已实测可用):

dsh plugin --profile <profile> add "github:TellToday/dsh-narrative-voice#main"
  • #main 跟随最新提交;
  • 装完要重启该 profile 的进程(web profile 就是 dsh web)。

等效的其它写法:

# 完整 git URL
dsh plugin --profile <profile> add "git+https://github.com/TellToday/dsh-narrative-voice.git"
# 或用本地目录(开发用)
dsh plugin --profile <profile> add "C:\path\to\dsh-narrative-voice"

包声明了 dsh.bundle.patchdsh plugin add 会自动把它追加到 dsh.profile.bundles 成为一层 bundle。卸载:dsh plugin --profile <profile> remove @dsh-user/narrative-voice

> 前置:pnpm 在 PATH 上。git 托管安装会通过系统 git 克隆仓库(遵循你的 git 代理设置)。

用法

命令作用
/voice on开启改写(下一条消息起生效)
/voice off关闭改写(工具描述恢复原样)
/voice user切到方案B(回答者叙述)并开启
/voice ai切到方案A(AI 叙述)并开启
/voice查看当前状态(开关 + 当前方案)

命令由宿主的 commands 服务处理(不经过模型),即时生效——不依赖 HMR、无需重启。

默认配置

默认值含义
voiceuser(方案B)用哪种叙述方案
defaultActivetrue装好后默认开启

想改默认值(而不是运行时用 /voice 切),在 profile 的 patch 文件里按 id 覆盖(路径 $DSH_HOME/profiles/<profile>/cordis.patch.yml)。patch 是整体替换 config,键要写全:

- id: narrative-voice
  config:
    voice: user          # user(方案B:回答者叙述)| ai(方案A:AI 叙述)
    defaultActive: true  # false = 默认关闭,直到 /voice on

配置由 Config 校验(零依赖的 Standard Schema 实现):非法值会让插件加载失败并报明确错误。

目录结构

dsh-narrative-voice/
├── lib/index.js          # 插件本体:Config、assemble 监听器、/voice 命令
├── cordis.patch.yml      # bundle patch:把插件行插入 host 平面
├── test/
│   ├── functional.mjs    # 隔离功能测试(39 项断言)
│   └── run-test.ps1      # 直接跑测试(无需安装、无需 junction)
├── package.json          # bundle 元数据(dsh.bundle.patch;零依赖)
├── LICENSE               # MIT
└── README.md / README.zh-CN.md

开发

pwsh ./test/run-test.ps1

插件没有任何裸 import,测试直接用 node 跑——不用装任何东西、不用清理任何东西。

License

MIT——见 [LICENSE](./LICENSE)。