dsh-voice-call

voicetested: passnpmMIT

agent 主动打来的语音电话:`offer_call` 向人类振铃(接听/拒接/稍后再说),接听后由本地 CrispASR + Qwen3-TTS 合成并播放(9 个音色,含 2 个中文方言);拒接则把决定返回给 agent。

下载量 / Downloads
2,813
依赖体积 / node_modules
24.95 MB
测试时间 / Tested
2026-11-06
DSH 版本 / Version
0.2.2-rc.1

Install

dsh plugin --profile web add dsh-voice-call

Sandbox test results

StageResult
1 install✓
2 list✓
3 mount✓
4 boot—

Four stages run in an isolated sandbox: install (network on) → list → mount → boot (last three with no network).

README

dsh-voice-call —— agent 拥有的声音,由它主动打给你

<p align="center">

<img src="docs/logo.svg" width="120" alt="dsh-voice-call 标志 —— 一声向外荡开的振铃" />

</p>

<p align="center">

<a href="https://github.com/PandaPolo/dsh-voice-call/actions/workflows/ci.yml"><img src="https://github.com/PandaPolo/dsh-voice-call/actions/workflows/ci.yml/badge.svg" alt="CI" /></a>

<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue" alt="License: MIT" /></a>

<a href="https://www.npmjs.com/package/dsh-voice-call"><img src="https://img.shields.io/npm/v/dsh-voice-call" alt="npm version" /></a>

<img src="https://img.shields.io/badge/harness-0.1.7--rc.2-5b5bd6" alt="DSH 0.1.7-rc.2" />

<img src="https://img.shields.io/badge/harness-0.2.2--rc.1-5b5bd6" alt="DSH 0.2.0-rc.1 / 0.2.0-rc.2 / 0.2.1-rc.2 / 0.2.1-rc.3 / 0.2.2-rc.1,声明范围 ^0.2.0-rc.1" />

<img src="https://img.shields.io/badge/desktop-DeepSeek%20Harness-5b5bd6" alt="桌面版(dsh-desktop)运行时 0.2.2-rc.1 已逐文件哈希核对" />

<img src="https://img.shields.io/badge/tests-302%20green-1f883d" alt="302 个测试全绿" />

</p>

<p align="center">

<img src="promo/demo-small.gif" width="720" alt="dsh-voice-call 演示 —— 自动放映:旁白、翻页、字幕同步" />

</p>

<p align="center">

<strong>中文</strong> · <a href="README.en.md">English</a>

</p>

"这个项目的开始是朴素的——我想知道如果 Agent 知道自己可以发出声音,他会说什么?"
—— 人类伙伴,关于这个项目如何开始

给 DeepSeek Harness 的 agent 一个它拥有的声音。 本地优先、可完全离线:合成跑在本机 CrispASR + Qwen3-TTS CustomVoice 引擎上(9 个内置音色,含 2 个中文方言),音频是 ~/.dsh/voice/ 下的普通文件。任何声音都不会自动响起——必须由模型调用工具,或者你接听一次来电。

三条规矩,整个项目围着它们转:

  • agent 拥有拨号权 —— 它在自己觉得值得说的时候调用 offer_call:一个完成的念头、一个里程碑、一句想大声说出来的话。
  • 人类拥有接听权 —— 来电以专属来电卡片呈现(默认;接听 / 拒接 / 稍后再说),未经同意绝不播放。没有卡片客户端连着的时候自动退回弹窗询问,不会变成"这通电话没人能接"。
  • 拒接也是教育 —— 被拒接或推迟时,工具把你的决定原样返回给 agent,它学会改用文字写下来,或者只在真正重要时再试一次。

🚀 安装(桌面版)

1. 打开 DeepSeek Harness 桌面版 → 「插件」页面(设置里的插件管理)。

2. 在插件市场搜索 dsh-voice-call 并安装;装好后在同一页让它生效(本插件不热加载,可能需要重载插件或重启桌面版)。

3. 首次使用在插件自己的设置页里配置。

旧版的命令行安装(npm install -g @deepseek-ai/dsh,然后 dsh plugin --profile web add dsh-voice-call)随全局 CLI 一起退役了——本机已卸载全局 DSH,插件管理请走桌面版界面。
版本要求:需要 DSH 0.1.7-rc.2 / 0.2.0-rc.1 / 0.2.0-rc.2 / 0.2.1-rc.2 / 0.2.1-rc.3 / 0.2.2-rc.1(桌面版当前带的运行时就是 0.2.2-rc.1,npm 的 latest 与 next 也指到同一版——这个项目历史上两份发行物头一回同版)。

装完到 DSH 的插件设置页,「运行环境」区点一下就把引擎和模型装齐。然后开个会话,对 agent 说:「你有 offer_call 工具——有什么值得说的就打电话给我。」

从零到能听见声音的完整步骤(手动下载路径、全字段配置、故障排查、信任边界)在 [docs/deployment.md](docs/deployment.md)。

🤖 如果是 agent 在替人类装

1. 装完插件,让用户重载该插件或重启桌面版。 插件不热加载,配置也不会在跑着的实例里生效——这一步没有替代。

2. 重启后带用户进「插件 → dsh-voice-call → 设置」,在「运行环境」区点那一个按钮,引擎与模型由它装齐。不要替用户手写 crispasr 的路径,除非他明确要走手动装配。

3. 用户要是让你把环境整个装完:先摸清他所在的网络,再决定从哪儿取。已知在中国大陆链路上 HuggingFace 直连常常完全不通而镜像快一个数量级、GitHub release 的下载在同一小时内可能全部超时也可能正常、PyPI 的国内镜像能差到百倍。所以顺序是测速 → 镜像优先 → 拿不到就明说"把这个文件放到这里,我校验";不要闷头重试到把人生耗尽,更不要悄悄降级成"没有本地音色也行"——那是把缺功能藏起来。

4. 别碰用户已有的手写路径配置(D:\crispasr、D:\tts 那一类)。它们的优先级永远高于插件自己创建的目录,清理也碰不到它们。

5. 装完带用户跑一次验收:/voice 看状态,再让它 speak 一句"你好"——听到声音才算装好,配置项全绿不算。

✨ 你能得到什么

  • 一键装配运行环境 —— 在插件设置页点一下就把需要的引擎与模型装好,不用你自己配。它先探测这台机器(系统 + 引擎自己报的显卡/显存),默认值取自目录里实际装着的东西;断点续传、多路并行、多源测速择优、镜像优先。GitHub / HuggingFace 拉不动时,它给的是"放这儿,我校验",不是一句失败。
  • 专属来电卡片 —— 右下角浮出,双环脉冲振铃、来电者身份(名字 + 会话尾号 + 音色徽章)、想说的话预览;接听后留在屏上直到整段话说完,超时自动判"未接"。
  • 11 条可选铃声 + 试听 —— 全部由仓库脚本在本机合成,不含任何第三方音频(微信铃声那类是别人的版权物,不用)。默认那条 classic 是下行小调五声拨弦,刻意避开高铁/登机广播那种上行大三和弦。试听按来电时的真实音量循环播你选的那一条,再点停。
  • 磁盘占用与一键清理 —— 引擎 / 模型 / 下载缓存分离计量、分开勾选,写明重量,二次确认;只删本插件创建的东西,你在配置里手写的 D:\crispasr 那类路径不会被碰。
  • 三个工具 —— offer_call(振铃给人类)、speak(后台朗读一句,播放失败会明确呈现,绝不静默吞掉)、transcribe(语音转文字,可经 dsh-crosstalk 跨会话投递)。
  • 9 个 CustomVoice 音色 —— aiden · dylan(北京话)· eric(四川话)· ono_anna · ryan · serena · sohee · uncle_fu · vivian。
  • /voice 命令 —— 状态查询、on|off 朗读开关、speak <文本> 直接说话。
  • 等问题振铃(0.3.7,实验性,默认关) —— 见下一节。

🔔 0.3.7:等你的问题,它会打给你

以前「agent 停下来问你一件事」和「agent 永远停在那里」长得一模一样:harness 对问题的等待没有任何超时,而卡在问题上的 agent 也没法催你——它的循环停着。于是你走开五分钟,它就在那儿等五分钟。这一版让插件替它看一眼表。

你会碰到什么 · 现在

问题弹出来,你走开了 · 到点(默认 5 分钟,可调 1/5/10/30)弹一张来电卡片:「有 2 个关于「部署方案」的问题在等你回答,已经等了 5 分钟」

你想听它念一遍 · 按接听,它念一句「有两个关于「部署方案」的问题需要你回答」,念完卡片自己退

你回到对话里把题答了 · 卡片自己收掉,不需要你去关

你担心它替你回答 · 它从不替你回答。在卡片上按任何键都只是让卡片安静,问题还在原地等你

默认关着:设置卡里「等问题振铃(实验性新功能)」打开才生效。这一版其余改动——包括两处"插件能把宿主带走"的围栏——见 [docs/changelog.md](docs/changelog.md)。

🖥 跑在新基线上:0.2.2-rc.1,桌面版与 npm 这次是同一版

dsh 0.2.0-rc.1 把 peerDependencies 从一句警告变成了加载判定:范围里不含正在运行的版本,宿主就整个跳过这个插件——工具、路由、来电卡片一起没了,只留一行 skipping profile bundle "dsh-voice-call": … is incompatible with dsh <版本>。0.3.7 正是这样消失的,而它 284 个测试全绿:没有一条测试读过清单。从 0.3.8 起范围写成 ^0.1.7-rc.2 || ^0.2.0-rc.1(这一条臂覆盖整段 0.2.x),并把宿主自己的判定函数请进测试(test/harness-compat.test.ts 跑真清单)。

0.3.14 把基线抬到 0.2.2-rc.1;发出去的两份产物还是 0.3.13 那两份字节(lib/index.js 19781、lib/client.js 70144,与 npm 上 0.3.13 的 tarball 回算的 sha256 一字不差)。这一版和 rc.3 那轮不同:harness 自己动了——比对的 24 个 harness 包里 15 个的服务端 JS 变了(cordis 4.0.5 → 4.1.0 自己也动了 lib/index.js),dsh-app-boot/lib/index.js 从 203572 长到 225678 字节,每个包都新增 locale/{de,es,fr,ja,pt,ru}.json,dsh-tools 的 lib/types/ 重排(ptc、ptc-calls、py-types、ts-types、testing、types 六个文件没了,contracts、executor、pipeline、batch、events 顶上),dsh-api-session-controller 把 history / state / web 拆成了 controller+listener。我们这边仍然一行源码没改:迁移面查过了,符号都还在原地(defineTool、GenericCallView、SessionEventLike、MessageId、JobOutcome 逐个在两份树里回查过)。

加载判定这条链一步没动:把 evaluatePluginCompatibility(630 字节)、它调用的 unmetRequirements(1033 字节)、satisfies(147 字节)从两份桌面 asar 里各自抠出来对比——逐字节相同。判定文件变胖是别的原因(profile 模板那批常量搬了家,外加 locale)。所以 peer 依旧一个字没改:^0.1.7-rc.2 || ^0.2.0-rc.1 本来就含 0.2.2-rc.1。devDependencies 里 22 个 harness 包抬到 0.2.2-rc.1,@deepseek-ai/cordis 从 ~4.0.5 抬到 ~4.1.0——运行时那份现在就是 cordis 4.1.0 / schemastery 3.19.0 / cosmokit 1.9.0。声称的基线六条:0.1.7-rc.2 / 0.2.0-rc.1 / 0.2.0-rc.2 / 0.2.1-rc.2 / 0.2.1-rc.3 / 0.2.2-rc.1,三份依赖树各跑一遍(三份 tsc + 302 个用例全绿):新基线一份;0.1.7-rc.2 一份(只把 dsh-app-boot 抬到 0.2.2-rc.1,因为判定本身是 0.2.0-rc.1 才有的东西);再加一份把 schemastery 钉在

…(truncated)

Rendered from the README published on npm. Formatted only, not edited.

Versions

Published on npm::14,最后更新 2026-11-06

Links

GitHub · Homepage · npm

Same category