dsh-speak-plus: Vocalizing DSH's Answers and Intermediate Steps

Preface

In the DSH plugin system, text output is a basic capability, but “listening” is still blank. When developers run local agents, they often need to leave the screen to confirm results, or listen to task progress while doing other things. The upstream of dsh-speak already does “reading out the answer,” but it defaults to processing only the final text. Once the intermediate process is enabled, the fragments the model spits out between tool calls will be read out one by one, resulting in a poor listening experience.

The m0yun/dsh-speak-plus introduced below is an enhancement branch targeting this problem. The maintainer, M0Yun, belongs to the DSH client-side plugin category; see the end of the article for the GitHub repository address. Its positioning is an enhancement branch of dsh-speak 1.8.4. All upstream features like reading, queueing, settings page, and WebSocket status synchronization are retained, plus added behaviors such as merging intermediate processes, priority queuing for approvals/questions, handover for new content, and Alt + S to stop. All new behaviors are disabled or set to conservative values by default; without configuration, it is consistent with the upstream.

What is it

One-sentence positioning: Add Chinese voice broadcasting to DSH, and read the intermediate process after merging it into segments, rather than reading it out sentence by sentence.

  • Repository: https://github.com/M0Yun/dsh-speak-plus
  • Directory Page: https://www.skillhub.cn/plugins/M0Yun/dsh-speak-plus
  • Upstream: Alan2Z/dsh-speak (1.8.4)
  • License: MIT, inherits upstream LICENSE
  • Maintainer: M0Yun
  • Category: Client

The core problem it solves is: After enabling queueAllMessages, every assistant message immediately enqueues and reads independently. The model often only spits out a sentence or two between tool calls, so what you hear are fragments like “Received -” (cut), “Then you restart yourself.” (cut), “All 6 scenarios passed.” (cut). This branch first accumulates consecutive arriving text into a segment before reading it, while also specifying when to interrupt and when not to.

Core Features

The table below lists the comparison with the README, writing only the verified capabilities.

Capability Upstream 1.8.4 This Branch
Read final reply Supported Supported
Read intermediate process Item-by-item, easily chopped up Merged into segments, read in order
New content interrupting current reading Not supported Configurable (defaults to switching hands only when new round content is produced)
Approval / Question priority Not supported (gets pushed out by main text) Queues with protection
Stop broadcasting shortcut key Not supported Alt + S
Config reading Depends on settings schema Falls back to reading profile config when schema is unavailable
Queue / Status sync / Settings page / Manual replay Supported All retained

The five new capabilities are the increments relative to the upstream. The README lists the key names and default values for each item in the configuration section below.

Installation and Enablement

The plugin mounts as a DSH bundle, configured in the profile’s cordis.patch.yml. The snippet below is an example given in the README; <你> in the path needs to be replaced with the actual username:

- id: dsh-speak
  name: dsh-speak-plus
  config:
    queueAllMessages: true
    interruptOnNewMessage: true
    interimMode: queue
    interimMergeMs: 800
    interimMaxBacklog: 180
    engine: 'C:\Users\<你>\.dsh\profiles\desktop\data\dsh-speak-edge\speak-edge.ps1'  # Optional: Custom engine
    rate: 8

What this step does: Use id: dsh-speak to declare the mount point consistent with upstream, and use name: dsh-speak-plus to point to this branch; keys in config determine reading behavior, and engine is the optional custom engine script path.

At the platform level, Windows uses system SAPI voices (NaturalVoiceSAPIAdapter can be used for natural tones), and macOS uses system say. The engine scripts are consistent with the upstream (engine/speak.ps1, engine/speak.sh), or you can point engine to your own script.

Configuration Items

New (This Branch)

Key Default Description
interruptOnNewMessage false Total switch: When enabled, enables this branch’s interrupt/merge logic
interruptOnNewTurn false false: Don’t interrupt on message submission, wait for actual content in the new round to switch hands; true: Cut off as soon as send is pressed
interimMode queue queue: Queues segments within a turn to be read without interrupting each other; replace: New content immediately overrides the one currently being played
interimMergeMs 800 How long of silence to merge fragments into one segment, 0 = no merging
interimMaxBacklog 180 Max characters of pending text to backlog, discard oldest if exceeded

Inherited from Upstream (Common)

Key Default Description
enabled true Total switch, silence completely when off
automaticSpeech true Auto read; manual replay always available
queueAllMessages false Enqueue every assistant message (intermediate process)
throttleMs 1500 Merge delay for default mode
engine empty Override engine script path
rate / volume 0 / 50 SAPI scale for Windows (-10~10)
maxChars Safe value Only read fixed prompt if exceeded
longTextMode / longTextMessage message Handling of long text
announceApprovals / announceQuestions true Approval / Question broadcasting
announceTurnEnd / announceCommandDone / announceGoalChange / announceToolErrors / announceTodoWrite false Optional event broadcasting

See the upstream documentation docs/UPSTREAM-README.zh-CN.md for the complete list.

Typical Usage

First, let’s look at a reproducible minimal configuration. If you only want to merge intermediate processes and don’t need interruption, keep the defaults:

- id: dsh-speak
  name: dsh-speak-plus
  config:
    queueAllMessages: true
    interruptOnNewMessage: true

This segment means: interruptOnNewMessage is enabled, enabling merge and interrupt logic; when interruptOnNewMessage is not enabled, all new behaviors remain consistent with upstream.

The shortcut key is unified as Alt + S: Stop broadcasting immediately, while also clearing the pending queue and the buffer fragments not yet broadcast. The README specifically notes that the “shortcut key” list in DSH core only lists core’s own actions and does not reserve a registration entry for plugins, so this key is monitored by the plugin itself and will not appear in that list; it is also effective when the input box has focus.

There are two points to clarify regarding behavior, which are easy to trip over during integration or troubleshooting:

  1. Intermediate processes within a turn are merged into segments based on interimMergeMs, segments are queued, read the next segment after the previous one is finished; discard the oldest when pending backlog exceeds interimMaxBacklog characters.
  2. Switching rules: Do not interrupt current reading when you send a message; interrupt the text being read in the previous round only when the first content of the new round is ready to be played; when reading approvals/questions, new text queues and waits, not preempting.

Additionally, in some DSH builds, plugins cannot load the settings schema; in this case, it will directly read cordis.patch.yml from the profile (cached by modification time, only taking known keys) and merge it with runtime configuration, with runtime taking priority. It will print a line 生效配置: … during mounting for troubleshooting.

Use Cases and Notes

Suitable for these types of people: Developers using Windows SAPI or macOS say for local reading who need to confirm task progress by listening; users already using upstream dsh-speak but dislike having intermediate processes chopped up; and teams wanting to add sound prompts for approvals and questions. It is not suitable for scenarios requiring commercial-grade TTS voices or hard requirements on broadcast latency—it calls system built-in engines.

Several limitations must be clearly stated:

  1. The plugin runs with the permissions of the current DSH process. Before installing, you should check the source code and license (MIT) and ensure the content of cordis.patch.yml conforms to your profile’s conventions.
  2. The settings page depends on the Config schema; if the build fails, the settings page may not display, in which case you can modify the YAML.
  3. New round content will cut off text being played in other sessions (same speaker), regardless of source.
  4. Modifying plugin files directly in node_modules will be overwritten on reinstall/upgrade.

According to the directory page information, this plugin is categorized as client-side and belongs to the community ecosystem project. One point needs to be emphasized: The community directory is an independent site with no official affiliation to DeepSeek or Fangyuan, it is simply an aggregation and display.

Conclusion

The value of dsh-speak-plus lies in handling the upstream legacy problem of “not recognizing intermediate processes”: fragments are merged into segments and read in order, approvals and questions are queued with protection, Alt + S provides one-click stopping, and new behaviors are disabled by default. For those already using dsh-speak, changes are centralized in one cordis.patch.yml, concentrating risk in configuration rather than code.

  • Directory Page: https://www.skillhub.cn/plugins/M0Yun/dsh-speak-plus
  • GitHub: https://github.com/M0Yun/dsh-speak-plus
羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

Xiaoye