dsh-tts-service: Connecting DSH Agents to Multi-vendor Voice Synthesis

Introduction

The philosophy of DSH (DeepSeek Harness) is “everything is a plugin”; messages, tools, and outputs can all be taken over by plugins. However, getting an agent to speak directly still involves many engineering challenges: TTS interfaces from different vendors are not unified, where to store keys, how to select voices, what tone to use for each segment, and other plugins needing to reuse the same voice service—all of this needs to be pieced together. The dsh-tts-service plugin is designed to solve these problems. Maintained by loveandbeepbrother, it provides multiple TTS vendors and a unified voice service in a single package. Below, I introduce its structure, installation method, and typical usage.

Positioning

dsh-tts-service is a multi-vendor Text-to-Speech service for DeepSeek Harness (DSH). It registers Doubao TTS 2.0, Alibaba Cloud Bailian (Model Studio, including CosyVoice, Qwen-Audio-TTS, and Qwen3-TTS), and any OpenAI-compatible endpoint that supports POST /audio/speech, allowing users to select voices themselves and enabling agents to specify tone per-segment.

It is also a service that can be reused by other plugins: other plugins can call the same ctx.ttsService without needing to integrate TTS themselves.

A single package is divided into multiple plugin entries, which can be toggled on or off in the DSH plugin page:

Entry ID Function Enabled by Default
tts-service Provides the service ctx.ttsService: vendor registration, selection (vendor, voice, language), synthesis, and voice list. Yes
tts-doubao Vendor: Doubao (Volcengine) TTS 2.0. No
tts-bailian Vendor: Alibaba Cloud Bailian / Model Studio. No
tts-openai-compatible Vendor: Any endpoint compatible with POST /audio/speech. No
tts-say Agent tools tts_service_say, tts_service_voices, tts_service_select, and the output registry ctx.ttsSay. Yes
tts-speaker-windows Output method: Play through PC speakers when at the computer (Windows only). Yes

A note to make: the plugin has no default vendor or default voice. Until you select one, tts_service_say will fail with VOICE_NOT_SELECTED and inform the agent where to make the selection. Additionally, the current version synthesizes full segments and does not support streaming output.

Installation and Enablement

Installation commands are taken from the project README:

dsh plugin add @loveandbeepbrother/dsh-tts-service

It can also be installed from GitHub:

dsh plugin add github:loveandbeepbrother/dsh-tts-service

Runtime environment requirements:

  • DSH >=0.2.1-rc.3 <0.3.0-0 (including pre-release versions; the project is tested against 0.2.1-rc.5).
  • Node.js 22 or higher; the version included with DSH is sufficient.
  • At least one vendor’s account and API Key; synthesis fees are billed by the vendor.
  • When using speaker output, Windows and Windows PowerShell (powershell.exe, built into the system by default) are required.

Enabling steps:

  1. Open a vendor entry (e.g., tts-doubao, tts-bailian, or tts-openai-compatible) in the plugin page and fill out its form.
  2. Store the API Key in DSH’s credential store.
  3. Select a voice: let the agent “list available voices” then “use a specific voice”, or directly fill in provider and voices in the Text-to-Speech Service (tts-service) settings.
  4. Ask the agent to say a sentence.

Key Management

The configuration file does not store key values, only key names. Key values come from DSH’s credential service (ctx.credentials, i.e., the key store on the settings page); if the credential service is not loaded, they come from the process environment variables when starting DSH. Keys are read on every request, so changes take effect immediately after rotation. The settings page only indicates whether the key has been configured.

Entry Config Field Default Key Name Purpose
tts-doubao apiKeyEnv VOLCENGINE_TTS_API_KEY Synthesis (the API Key from the “API Key Management” in the Volcengine console).
tts-doubao accessKeyEnv, secretKeyEnv VOLCENGINE_ACCESS_KEY, VOLCENGINE_SECRET_KEY Optional: Volcengine account AK/SK, used only to list the complete voice directory.
tts-bailian apiKeyEnv DASHSCOPE_API_KEY Synthesis and listing cloned voices (same name as the official DashScope SDK).
tts-openai-compatible apiKeyEnv OPENAI_COMPATIBLE_TTS_API_KEY Sent as Authorization: Bearer. You can leave the key field empty for local endpoints that do not require a key.

These field names can be renamed. For example, if you need to connect to two endpoints of the same type, use different key names to distinguish them.

Selecting Voices

Voice selection is stored in the settings of tts-service and persisted to the user profile; no restart is required. The settings include:

Field Meaning
provider Default vendor ID, empty means none.
voices Default voice for each vendor: Vendor ID -> Voice ID. Voice IDs only make sense within their respective vendor, so switching from Doubao to Bailian and back will preserve the selection on both sides.
language Default language code, defaults to auto, must be a value declared as supported by the vendor.

There are three ways to set this, all writing to the same settings and taking effect immediately:

  1. Settings page: Modify provider and voices in the Text-to-Speech Service settings.
  2. Agent commands: First ask “What voices are available” (tts_service_voices), then “Switch to…” (tts_service_select). The agent’s reply will indicate the old voice, the new voice, and how to switch back.
  3. Calling from plugin code:
await ctx.ttsService.configure({ provider: 'doubao', voices: { doubao: 'voice-id' } })

tts_service_voices (corresponding to ctx.ttsService.voices(id) in the plugin) lists voices, their supported languages, and whether they follow tone descriptions. If the list is incomplete, it will be clearly marked as such, and voice IDs can also be entered manually.

Error handling is explicit: if the vendor is not registered, the language is not supported, the text exceeds maxChars, or the format cannot be generated, the operation will fail directly. The service will not silently switch to another vendor.

Vendor Details

Doubao TTS 2.0 (tts-doubao, Vendor ID doubao)

Field Default Value Description
providerId doubao Can be changed if you need to run two instances.
resourceId seed-tts-2.0 Sent as X-Api-Resource-Id.
apiKeyEnv, accessKeyEnv, secretKeyEnv See above
sampleRate 24000 16-bit mono PCM.
maxChars 300 Character limit per request.
timeoutMs 60000

There are a few details to note. Tone descriptions and “context” (the user’s previous sentence) are merged into a single voice instruction and sent via additions.context_texts. Only Doubao 2.0 system voices (IDs containing uranus) follow this instruction; cloned voices do not. Regarding the voice list: without AK/SK, a static table of 2.0 system voices transcribed from the official voice table is returned, marked as incomplete; with AK/SK, the plugin calls the official ListSpeakers API (HMAC-SHA256 signature, service is speech_saas_prod, region is cn-beijing). Language support includes auto, zh, en, ja, sent via explicit_language.

Alibaba Bailian (tts-bailian, Vendor ID bailian)

Field Default Value Description
model cosyvoice-v3-flash Can also be cosyvoice-v3-plus, cosyvoice-v2, cosyvoice-v3.5-flash, qwen-audio-3.1-tts-flash, qwen3-tts-flash, etc. Voices only match the same model.
region cn-beijing Optional: ap-southeast-1, cn-hongkong, us-east-1, eu-central-1, ap-northeast-1. Keys, workspace, and models are isolated by region.
workspaceId — The first segment of the API host tag (e.g., llm-xxx). Once set, the workspace domain {workspaceId}.{region}.maas.aliyuncs.com is used; otherwise, the old DashScope domain is used. eu-central-1 and ap-northeast-1 must have this set. Alibaba Cloud indicates that the DashScope domain will no longer receive new features starting from 2026-09-30, so it is recommended to set this.
apiKeyEnv DASHSCOPE_API_KEY
sampleRate 24000 CosyVoice / Qwen-Audio-TTS; Qwen3-TTS is fixed at 24000.
maxChars Qwen3-TTS is 600, others are 2000
timeoutMs 60000 Covers synthesis calls and audio downloads.

At the API level, CosyVoice and Qwen-Audio-TTS use /api/v1/services/audio/tts/SpeechSynthesizer, while Qwen3-TTS uses /api/v1/services/aigc/multimodal-generation/generation; both return an audio URL valid for 24 hours, and the plugin is responsible for downloading it. Whether free-form tone descriptions (instruction) are followed depends on the model:

Model Follows Free-form Tone Description
qwen-audio-* Yes, system, cloned, and designed voices are all supported (except for a few English voices).
cosyvoice-v3.5-* Yes (this model only has cloned and designed voices).
cosyvoice-v3-flash Only cloned and designed voices; system voices only accept fixed instruction templates.

OpenAI Compatible Endpoint (tts-openai-compatible)

Any endpoint compatible with POST /audio/speech can be connected directly. Keys are sent as Authorization: Bearer, and the key field can be left empty for local endpoints that do not require a key.

Reusing Service from Plugins

This package is an ES Module; main in package.json points to ./src/service.js, and types points to ./index.d.ts. In addition to the default export, the exports field also exports various entries via subpaths: ./doubao, ./bailian, ./openai-compatible, ./say, ./speaker-windows, with corresponding locale files having matching subpaths. To call the voice service directly in your own plugin, you can use ctx.ttsService.configure(...) (see above) or ctx.ttsService.voices(id).

Even if the tts-say entry is not enabled in other plugins, they can still reuse the same ctx.ttsService. This reduces the risk of multiple plugins each integrating TTS, voice selection, and key management strategies inconsistently.

Applicable Scenarios and Notes

Suitable for the following types of people:

  • Developers who want an agent to speak directly in DSH and control tone per-segment.
  • People already using multiple TTS vendors who want unified voice selection and key management.
  • People who want to create a plugin that requires broadcasting or voice reminders and want to reuse the same voice service.

Notes when using:

  • First open a vendor entry in the plugin page and configure the key, then select a voice; otherwise, synthesis will fail.
  • Synthesis is billed by the vendor. Keys are read on every request and take effect immediately after rotation.
  • Only use scenarios that require a full segment and do not require streaming playback; the current version does not support streaming synthesis.
  • Whether tone descriptions take effect depends on the vendor and the voice model. When listing voices, check if they are marked as “following tone description”.
  • The plugin runs with the permissions of the current DSH process. You should check the source code and license (package.json declares MIT License) yourself before installing.
  • The community directory site is an independent site with no official affiliation with DeepSeek or Hanhuan.

Summary

The value of dsh-tts-service lies in consolidating “which TTS to connect to, which voice to select, tone per-segment, and reusing by other plugins” into a single plugin: one package, multiple entries, vendors can be toggled on demand, voices are saved in the profile, and keys are stored only by name. For those who need to make DSH agents speak, this is currently the most convenient path.

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

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

Xiaoye