dsh
OpenPetsHQ/openpets将 DeepSeek Harness 的生命周期状态、错误与审批请求,桥接到本地运行的 OpenPets 桌面伙伴。
当 AI 询问澄清性问题时(带问号或调用 ask_user_question)播放提示音。Web Audio API 合成,零音频文件,跨 Windows/macOS/Linux。
当 AI 询问澄清性问题时,播放一个简短的提示音,让你不会错过并能及时回答。为 DeepSeek Harness(DSH)设计。
? / ?,或调用 ask_user_question 工具(DSH 标准的澄清工具)。设置 ⚙️ → AI 提问提示音。开关、调整音量、试听。设置保存在 localStorage。架构参考了
kaixinbaba/dsh-complete-notify。感谢分享标准的 DSH 插件布局。
English · 简体中文 · Tiếng Việt
# 全局安装(或让 dsh plugin 帮你管理)
npm install -g dsh-ai-question-chime
# 注册到 web profile
dsh plugin --profile web add dsh-ai-question-chime
# 重启 dsh web 生效
# macOS launchd:
launchctl kickstart -k gui/$(id -u)/com.dsh.dsh-web
# 否则手动停止并重启 dsh web
dsh plugin --profile web add "github:lediemquynh/dsh-ai-question-chime"
# 重启 dsh web
dsh plugin --profile web add link:/path/to/dsh-ai-question-chime
# 改代码 → 重启 dsh web → 立即生效(无需重新安装)
? 或调用 ask_user_question 工具)→ 你会听到一个 2 音上升的提示音(988 Hz → 1319 Hz,约 0.2 秒)。dsh-ai-question-chime 的卡片,状态为 已挂载 / Mounted。AudioContext(任何点击或按键也可以)。dsh plugin --profile web remove dsh-ai-question-chime
# 重启 dsh web
.
├── lib/
│ └── index.js # Host 入口(Node, ESM)—— 空实现,仅声明名称
├── client/
│ └── client.js # Client 入口(浏览器, CJS 自注册)—— 所有真实逻辑都在这里
├── cordis.patch.yml # Bundle insert:告诉 dsh 将此插件挂载到 web profile
├── package.json # 声明 dsh.bundle.patch 和 peer dependencies
├── scripts/
│ └── simulate-loader.mjs # dsh client module loader 的桩,用于本地测试 client.js
├── README.md # 英文
├── README.zh.md # 简体中文(本文件)
├── LICENSE
└── .gitignore
DSH 插件模型
window.__ModuleLoader__.load({ id, factory }) 注册自身。factory 接收 require 函数,返回 module.exports 对象。module.exports 的形状是 { name, inject, apply(ctx) }。inject 声明插件需要的 Host 服务(slots、locale、conversationEvents);Cordis loader 在调用 apply 前会注入它们。apply(ctx) 在插件启动时执行一次。内部可以:
ctx.locale.register(NS, { zh, en, vi }) 注册 UI 字符串。ctx.get('conversationEvents').register({ kind, target, match, start, update, buildViewNode }) 订阅对话事件。ctx.slots.inject('settings.section', …) 注入设置页。ctx.effect(fn, label) 设置持久化效果(如音频解锁监听)。提示音触发逻辑
match(event) 对每个客户端对话事件运行。当 event.type === 'assistant/message' 时,返回一个匹配 id(每个 event.seq 一个),loader 会调用 update。update(context, match) 接收事件负载。它读取 event.data.message,运行 isAssistantQuestion(msg),如果为真,调用 playChime(cfg.volume)。isAssistantQuestion(msg) 在以下情况返回 true:
ask_user_question 工具调用(深度遍历内容块),或? 或 ? 且消息角色是 assistant。声音合成
playChime(volume) 懒加载创建 AudioContext(首次调用时),然后调度两个正弦波振荡器:
t=0 启动,时长 0.09 秒。t=0.10 启动,时长 0.09 秒。GainNode,使用指数包络:12 ms 攻击,衰减到静音。主音量为 cfg.volume(0–1)。AudioContext 在首次 pointerdown / keydown 时懒解锁,以符合 Chromium 自动播放策略。BEEP_COOLDOWN_MS)防止 AI 快速连续发送多个块时重复播放。npm run check # node --check 检查 lib/index.js 和 client/client.js
npm run test:loader # 在沙箱化的 __ModuleLoader__ 桩中执行 client.js
沙箱脚本(scripts/simulate-loader.mjs)会验证:
__ModuleLoader__.load 被调用恰好一次,传入正确的 id。name、inject(含 slots)、apply。apply(ctx) 在桩上下文上运行不抛异常。ctx.locale.register、ctx.get('conversationEvents').register、ctx.slots.inject 均被调用。如果你修改了插件,提交前运行这两个命令。awesome-dsh-plugin 上的 CI 会运行相同的检查。
所有音频参数都在 client/client.js 的 playChime 函数顶部。常见调整:
| 你想要的效果 | 修改 |
|---|---|
| 更高/更低的音调 | const tones = [[988, 0], [1319, 0.10]]; —— 尝试 [[659, 0], [880, 0.10]](更低)或 [[1319, 0], [1760, 0.10]](更高) |
| 更长的提示音 | const dur = 0.09; → 0.15 |
| 三个音而不是两个 | 添加第三个音:tones.push([2093, 0.20]) |
| 更大的默认音量 | const DEFAULT_CFG = { enabled: true, volume: 0.4 }; |
| 没有冷却(每个事件都响) | const BEEP_COOLDOWN_MS = 0; |
| 方波/三角波/锯齿波 | osc.type = 'sine'; → 'square'、'triangle' 或 'sawtooth' |
修改后重启 dsh web,无需重新安装。
webkitAudioContext 回退)。插件不使用任何实验性 Web API。
AudioContext。如果在 AI 提问前切换离开 dsh,你可能会错过提示音。assistant/message 事件。如果 Host 端在发送前过滤或重写了消息,检测可能会遗漏一些问题。package.json 中增加版本号(遵循 semver)。git push origin main。npm publish。MIT