返回目录
其他 待识别

dsh-narrative-voice

TellToday/dsh-narrative-voice

该仓库暂未提供项目说明。

Stars
1
Forks
0
Issues
0
更新
今天

PROJECT TOPICS

项目标签

PROJECT README

README

dsh-narrative-voice

English · Chinese

A DSH (DeepSeek Harness) bundle plugin that keeps the questions and options generated by the ask_user_question tool pronoun-consistent. At prompt-assembly time it rewrites the tool's questions.description in full into a description carrying a fixed narrative-voice rule, and you can turn it on and off anytime with the /voice command.

Why this plugin exists

The ask_user_question tool asks the human a concise question and offers a few clickable options. Without a fixed rule, the model drifts pronouns inside a single option:

  • a label in the answerer's voice ("I'll restart it myself" — "I" = the person answering) paired with a description that drifts into the AI's voice ("I'll walk you through the restart" — "I" = the AI);
  • the word "user" also leaks in ("…so the user has less to worry about"), referring to the very person reading it in the third person.

Two different "I"s in one option, and the user cannot tell them apart: who is providing the action? whose perspective is "I"?

This plugin fixes it at the prompt level: it writes a fixed narrative-voice rule into the tool's own description, so the model keeps question, header, label, and description in one consistent perspective throughout, and never calls the answerer "the user".

What it does

The rule splits the tool's fields into two groups:

  • question and headeridentical in both schemes, always written from the AI's point of view: "I" = the AI, "You" = the person answering (the user).
  • label and description — follow the selected scheme:
    • Scheme B (default, voice: "user") — the answerer narrates: "I" = the person answering, "You" = the AI.
    • Scheme A (voice: "ai") — the AI narrates: "I" = the AI, "You" = the person answering.

Why this design? Why split the tool's fields into two groups?

question and header — this is the AI asking the user a question. The asker naturally speaks in the first person: "I (the AI) would like to ask you (the user) a question". So these two fields are fixed in the AI's point of view: "I" = the AI, "You" = the user, identical in both schemes and never changed — otherwise an "I" referring to the user would appear inside a question, and the reader would think the user is asking themselves.

label and description — this is the answer the user is about to give. An option is essentially a reply that the AI guessed in advance and wrote on the user's behalf. But whose voice should that reply use? There are two equally reasonable views — this is exactly where Scheme A and Scheme B diverge:

  • Scheme B (the answerer narrates): the user treats the option as a reply typed with their own hand — the first person is in the user's hands, and the AI merely guesses what the user would type and hands it back as an option. So inside an option: "I" = the user ("I'll restart it myself…"), "You" = the AI ("you'll guide me…").

  • Scheme A (the AI narrates): the user treats the option as a multiple-choice question handed to them by the AI — like the AI saying "I've run into a problem, here are two options, you pick: A, I'll handle it this way; B, I'll handle it that way". So inside an option: "I" = the AI ("I'll handle it for you…"), "You" = the user.

The rule applies only inside the ask_user_question tool (ordinary replies and other tools are never affected), and only where pronouns actually appear — it never forces pronouns into a question or option that does not naturally need them.

How it works

Before every model request, DSH runs SystemPrompt.assemble(), puts the assembled prompt into an assembly object, and dispatches it through the Cordis waterfall event system-prompt/assemblethe waterfall's return value is what is actually sent to the model.

This plugin registers a global: true listener on the waterfall: while enabled, it finds ask_user_question in assembly.tools and rewrites parameters.properties.questions.description (the real assembled shape is JSON-Schema) in place, then return next() lets it through. Only the per-request clone is touched — the registry schema and the parameter-validation closure are unaffected.

assemble() runs once per message, so the /voice toggle takes effect from the next message — the same in any conversation, including ones already in progress.

Install

One command, straight from this GitHub repo (verified in practice):

dsh plugin --profile <profile> add "github:TellToday/dsh-narrative-voice#main"
  • #main tracks the latest commit;
  • after installing, restart the profile's process (for the web profile, that's dsh web).

Equivalent alternatives:

# full git URL
dsh plugin --profile <profile> add "git+https://github.com/TellToday/dsh-narrative-voice.git"
# or a local directory (for development)
dsh plugin --profile <profile> add "C:\path\to\dsh-narrative-voice"

The package declares dsh.bundle.patch, so dsh plugin add automatically appends it to dsh.profile.bundles as a bundle layer. Uninstall: dsh plugin --profile <profile> remove @dsh-user/narrative-voice.

Prerequisite: pnpm on PATH. A git-hosted install clones the repo through your system git (honoring your git proxy settings).

Usage

Command Effect
/voice on enable the rewrite (effective from the next message)
/voice off disable it (the tool description is restored)
/voice user switch to Scheme B (the answerer narrates) and enable
/voice ai switch to Scheme A (the AI narrates) and enable
/voice show the current state (on/off + the active scheme)

The command is handled by the host's commands service (not by the model), so it takes effect instantly — no HMR dependency, no restart.

Default configuration

Key Default Meaning
voice user (Scheme B) which narrative scheme to use
defaultActive true enabled right after install

To change the defaults (instead of switching at runtime with /voice), override the row by id in the profile's patch file $DSH_HOME/profiles/<profile>/cordis.patch.yml. The patch replaces the whole config, so list every key:

- id: narrative-voice
  config:
    voice: user          # user (Scheme B: the answerer narrates) | ai (Scheme A: the AI narrates)
    defaultActive: true  # false = disabled by default, until /voice on

The config is validated by Config (a dependency-free Standard Schema implementation): an invalid value fails the plugin load with a clear error.

Project layout

dsh-narrative-voice/
├── lib/index.js          # plugin body: Config, the assemble listener, the /voice command
├── cordis.patch.yml      # bundle patch: inserts the plugin row into the host plane
├── test/
│   ├── functional.mjs    # isolated functional tests (39 assertions)
│   └── run-test.ps1      # runs the tests directly (no install, no junction)
├── package.json          # bundle metadata (dsh.bundle.patch; zero deps)
├── LICENSE               # MIT
└── README.md / README.zh-CN.md

Development

pwsh ./test/run-test.ps1

The plugin has no bare imports, so the tests run with plain node — nothing to install, nothing to clean up.

License

MIT — see LICENSE.

CLASSIFICATION EVIDENCE

分类依据

项目类型待识别
功能分类其他
规则置信度

系统优先读取 GitHub Topics,再与站内分类词典和词根规则比对。当前命中: 无有效分类标签。