DSH 插件,把蓝牙小玩具接入 AI agent,自动选择连接方式并施加时长强度上限,默认 30 秒自动停。
- 语言
- TypeScript
- License
- BSD-3-Clause
- 分支
- main
安装
$ dsh plugin --profile web add github:c3ll256/dsh-toy在终端中运行以上命令,通过 dsh CLI 安装此插件。可在右上角切换 Profile。 第一次用 dsh?看这篇新手教程
对话式安装
帮我安装 DeepSeek Harness 插件 c3ll256/dsh-toy:先查看仓库 https://github.com/c3ll256/dsh-toy.git 确认安全性,然后执行安装命令并验证插件加载成功。
把这段指令粘贴给 DSH Web GUI 里的助手,由它代你完成安装与验证。
一句话定位
dsh-toy 是一个 DSH 插件,用于把支持蓝牙、串口或 USB 的硬件玩具接入 AI agent,让 agent 能询问型号、自动选连接方式、施加时长和强度上限,30 秒后自动停。
核心能力
- 自动选择连接方式:用户报型号就按已知路径连接,不知道时在 macOS 上先做只读原始 BLE 扫描,再决定走 Intiface 还是分享链接通道
- 按需自动启动 Intiface Engine:本机没装时下载 Buttplug 官方固定版本并校验 SHA-256,有现成就复用
- 通过分享链接直接连接部分厂商设备:基于自有协议实现,支持安可尼、谜姬、醉清风等已知型号
- 强度受限的标量控制:仅暴露振动、摆动、收缩、充气、吸吮五类动作,数值限定在 0-100% 范围
- 强制性的自动停止:每条控制命令默认 30 秒后自动停,最长 300 秒,新命令会替换旧命令的计时器
- 一键紧急停止:可暂停单个设备,也可以一次性停掉全部设备
技术实现
- 语言: TypeScript
- 关键依赖: @deepseek-ai/schemastery(配置和 JSON Schema)、@deepseek-ai/dsh-tools(工具注册)、ws(WebSocket 客户端)
- 架构模式: 主入口注册 7 个工具,运行时层 ToyRuntime 把后端调用串行化并对每条命令做时长/强度边界检查,后端层 AutoToyBackend 按需组合 Buttplug、MonsterParty 两个连接实现
- 入口文件: src/index.ts
适用场景
当 DSH 用户希望让 agent 操控已持有的硬件玩具时,只需告诉 agent 品牌和型号,无需自己安装 Intiface、选择蓝牙协议或手动启动中转服务;插件会解决硬件接入、寻找设备、施加安全边界这些事,如果用户担心误操作,默认的 30 秒自动停和强度上限会把风险控制在合理范围。
前置依赖与兼容性
| 依赖 | 最低版本 | 说明 |
|---|---|---|
| DSH | >=0.1.0-rc.6 | peerDependencies 声明,作为可选依赖 |
| Node.js | >=22.19.0 | engines 字段要求 |
| 平台 | macOS / Linux / Windows | Intiface 自动下载覆盖 macOS ARM64、Linux x64/ARM64、Windows x64 |
| Xcode Command Line Tools | macOS 原始 BLE 扫描必需 | 提供 Swift 编译器,否则需走 Intiface 回退 |
| 原生模块 | 无 | 未引用本地原生依赖 |
安装方式
dsh plugin --profile web add github:c3ll256/dsh-toy
配置项
| 配置 | 类型 | 说明 | 默认值 |
|---|---|---|---|
| buttplugUrl | 字符串 | 本机 Intiface 的 WebSocket 地址 | ws://127.0.0.1:12345 |
| buttplugProtocolVersion | 3 或 4 | 旧版 Intiface 用 3 | 4 |
| monsterPartySessionToken | 字符串 | 分享链接里提取的临时控制凭据,只来自插件配置,不会出现在工具参数里 | 未设置 |
| monsterPartyApiUrl | 字符串 | 分享链接服务端的解析接口 | https://api.monsterparty.cc/main/v1/remote |
| monsterPartyOrigin | 字符串 | 分享链接请求的 Origin 头 | https://www.monsterparty.cn |
| clientName | 字符串 | 握手时向两端宣告的客户端身份 | dsh-toy |
| connectionTimeoutMs | 数字 | HTTP 或 WebSocket 建连超时 | 10000 |
| requestTimeoutMs | 数字 | 等待对方响应的单次请求超时 | 5000 |
| intifaceExecutable | 字符串 | Intiface 可执行文件名或绝对路径 | intiface-engine |
| intifaceStartupTimeoutMs | 数字 | 自动启动 Intiface 后等待它开始监听的超时 | 10000 |
| intifaceAutoDownload | 布尔 | 本机找不到 Intiface 时,是否下载官方固定版本 | true |
| readyTimeoutMs | 数字 | 分享链接通道等待设备就绪的超时 | 20000 |
| heartbeatIntervalMs | 数字 | 分享链接通道应用层心跳间隔 | 9000 |
| scanDurationMs | 数字 | Intiface 设备发现窗口 | 5000 |
| rawBleScanDurationMs | 数字 | macOS 原始 BLE 发现窗口 | 10000 |
| defaultDurationSeconds | 数字 | 玩具控制指令省略时长时使用的默认秒数 | 30 |
| maxDurationSeconds | 数字 | 命令时长的硬上限,超过会被拒绝 | 300 |
| maxIntensityPercent | 数字 | 强度百分比的硬上限,超过会被拒绝 | 100 |
| allowHold | 布尔 | 是否允许 duration 0 表示持续不停,默认拒绝 | false |
常见问题
Q: 这个插件能控制什么?
A: 支持蓝牙、串口、USB 类型的品牌玩具,以及部分使用分享链接的厂商(安可尼、谜姬、醉清风等)。macOS 上还能先做只读原始 BLE 扫描,再决定走哪条连接路径。
Q: 需要自己安装 Intiface Engine 吗?
A: 不需要。插件默认会自动从 Buttplug 官方 GitHub Release 下载固定版本并校验 SHA-256 后启动;如果已经手动运行着 Intiface,会优先复用现有实例而不是关闭它。
Q: 用起来安全吗?
A: 所有控制命令都会经过时长和强度上限检查,默认 30 秒后自动停止,最大强度 100%、最长 300 秒;只有显式开启 allowHold 才允许"开着不关",否则拒绝。
Q: MonsterParty 分享 token 怎么用?
A: 把它保存到插件配置里(常用环境变量读取),不要直接暴露给模型。分享 token 通常一次性使用,断线后需重新生成链接。
Q: 报错 spawn intiface-engine ENOENT 怎么办?
A: 说明 Intiface 没装,且自动下载没生效;更新到包含该能力的版本,把 intifaceAutoDownload 设为 true,并确认能访问 GitHub。
Q: 可以在 Windows / Linux 上用吗?
A: 可以。Intiface 自动下载支持 macOS ARM64、Linux x64/ARM64、Windows x64,其他平台需要通过 intifaceExecutable 指定自己准备好的引擎。
Q: 怎么彻底停掉?
A: 直接告诉 agent 停止全部设备,或调用玩具控制器,插件卸载或热更新时也会自动停输出并关闭由它启动的 Intiface 进程。
Q: 原始 BLE 扫描为什么只支持 macOS?
A: 它依赖 Xcode Command Line Tools 提供的 Swift 编译器,只做只读发现,不连接、不写特征;其他平台直接走 Intiface 回退路径。
上手难度
入门 — 用户告诉 agent 品牌型号即可,无需了解 Intiface、蓝牙协议或分享链接;唯一需要动手的是 macOS 用户首次扫描时授予蓝牙权限,以及 Linux 用户安装 Xcode Command Line Tools 这种罕见的依赖。
已知问题与限制
- 内置的 RoomFun 兼容映射仅对蓝牙名称
RoomFun、型号标识RF_CANNON_PT3、固件4.3加一个振动输出做过实机验证,其他 RoomFun 型号不能假定兼容 - 分享链接通道只实现了 Chemtrails 记录的 relay 行为和
AKN_DS_SUCKEGG映射,厂商协议若变化需要更新实现 - Intiface 仅暴露可映射为百分比的标量功能,位置、方向、传感器、原始访问、订阅能力不在当前范围
- 原始 BLE 扫描只支持 macOS,并依赖 Xcode Command Line Tools 提供的 Swift 编译器;它只做只读发现,不能作为未知设备的通用控制协议
- 设备重连后,设备 id 可能会变化,应重新调用
toy_list刷新 - 测试仅使用本地协议 fixture 进行,不连接真实硬件
- 分享链接 token 通常一次性使用,断线后失效,连接前需重新生成
English | 简体中文
dsh-toy is a DeepSeek Harness plugin for connecting small toys to DSH.
At connection time, the agent first asks for the brand and model, then selects the connection method automatically. If the user genuinely does not know, the agent starts unknown-hardware discovery:
- On macOS, unknown hardware first uses read-only raw CoreBluetooth advertisement discovery, without starting Intiface or connecting to devices.
- Regular Bluetooth, serial, and USB models use Buttplug / Intiface. The plugin starts local Intiface Engine automatically when needed.
- Known sharing-link models from Ankni (安可尼), MizzZee (谜姬), and Zuiqingfeng (醉清风) use MonsterParty. Known dual-output devices expose their channels separately.
Users do not need to understand or select an underlying connection method, or manually start Intiface.
Brand and model names are not an allowlist. The agent passes any user-reported name through unchanged; unfamiliar names still use local hardware discovery. The plugin also supplies a verified local compatibility mapping for RoomFun devices reporting model RF_CANNON_PT3, exposed as RoomFun Cannon with one vibration channel.
The implementation follows protocol observations from Chemtrails, together with the device model and message formats documented by Buttplug and the Buttplug Protocol Specification. This repository contains an independent TypeScript implementation; see NOTICE for attribution.
Guardrails
- Sharing tokens stay in plugin configuration and never appear in model-visible tool arguments or results.
- Raw BLE discovery is read-only: it scans connectable advertisements without connecting or writing characteristics.
- Output stops automatically after 30 seconds by default.
- Zero-duration holds are disabled unless
allowHold: trueis explicitly configured. maxIntensityPercentandmaxDurationSecondsare enforced before backend dispatch.- A newer command replaces the previous automatic-stop timer for the same device.
toy_stopwithout a device id performs a global stop.- Plugin unload, HMR, and
toy_disconnectstop output and await WebSocket shutdown.
Use only hardware you own or are explicitly authorized to control. Treat sharing tokens as temporary control credentials and keep them out of Git, logs, and conversations.
Install
Requirements: Node.js 22.19 or newer and pnpm on PATH. Raw macOS BLE discovery additionally uses the Swift compiler from Xcode Command Line Tools. Install pnpm once if needed with npm install --global pnpm@10, then add the plugin directly from GitHub:
npx -y @deepseek-ai/dsh plugin --profile web add github:c3ll256/dsh-toy
Start DSH with the same profile:
npx -y @deepseek-ai/dsh web
The first command installs and activates the bundle persistently in the web profile. Re-running DSH does not reinstall it. To inspect the composed configuration or remove the bundle:
npx -y @deepseek-ai/dsh --profile web --dump-config
npx -y @deepseek-ai/dsh plugin --profile web remove dsh-toy
Replace web with another profile name when needed.
Quick start
You can tell the agent directly:
My toy is a Lovense Lush 3. Connect it and scan for devices.
When the brand or model is unknown, say:
I do not know the brand or model. Try Bluetooth discovery directly.
On macOS, the agent first calls toy_scan_raw_ble. If the scan exposes a plausible advertised name, it uses that hardware-reported name for toy_connect; otherwise it falls back to unknown, connects Intiface automatically, and scans verified protocols. Before scanning, turn the toy on, keep it nearby, and make sure a phone app or another program is not holding the device connection.
Automatic selection and connection
Before calling toy_connect, the agent must ask for the model and pass it to the tool, together with the brand when known. When the user does not know, macOS first runs toy_scan_raw_ble directly through CoreBluetooth. A discovered advertisement name is hardware evidence and may be passed to toy_connect; raw BLE ids are never controllable device ids. If raw discovery is unavailable or inconclusive, the agent passes unknown and the system tries the Intiface fallback. The tool never asks the user to select an underlying protocol.
For a brand or model that is not already documented, the agent follows the same path: pass the reported text to toy_connect, then call toy_scan. It must not guess a protocol or write arbitrary BLE characteristics. Discovery returns only devices covered by an upstream Intiface definition or a compatibility mapping that has been verified against hardware. An empty scan means the device remains unsupported or unavailable, not that the agent should probe it destructively.
For local Bluetooth, serial, and USB devices, the system first tries an existing Intiface server. If 127.0.0.1:12345 refuses the connection, the plugin runs:
intiface-engine --websocket-port 12345 --use-bluetooth-le --use-serial --use-hid
The plugin first looks for Intiface Engine on PATH. If it is not installed, it downloads a pinned build from the official Buttplug GitHub Release, verifies its SHA-256 digest, caches it in the user cache directory, and starts it. Set intifaceAutoDownload: false to disable downloads or intifaceExecutable to use another path. On disconnect or unload, the plugin stops only the process it started; it does not stop an Intiface server that was already running.
When the plugin starts Intiface itself, it writes its verified compatibility mappings to a private temporary user-device-config file and removes that file on shutdown. An Intiface server that was already running keeps its own configuration; stop that server first if a built-in compatibility mapping is needed.
Automatic downloads currently support macOS ARM64, Linux x64/ARM64, and Windows x64. On other platforms, use intifaceExecutable to point to an installed engine. The first scan on macOS may request Bluetooth permission; allow the terminal or application running DSH to access Bluetooth.
The bundled defaults use:
- id: dsh-toy
config:
buttplugProtocolVersion: 4
intifaceExecutable: intiface-engine
intifaceAutoDownload: true
rawBleScanDurationMs: 10000
defaultDurationSeconds: 30
maxDurationSeconds: 300
maxIntensityPercent: 100
allowHold: false
Set buttplugProtocolVersion: 3 for an older Intiface server. The system exposes percentage-compatible scalar features advertised by the connected device.
MonsterParty
Store the token from a supported sharing link in an environment variable:
MONSTERPARTY_TOKEN=<TOKEN>
Then override the plugin row in the profile's cordis.patch.yml:
- id: dsh-toy
config:
monsterPartySessionToken: !!js process.env.MONSTERPARTY_TOKEN
defaultDurationSeconds: 30
maxDurationSeconds: 300
maxIntensityPercent: 100
allowHold: false
Sharing tokens are commonly single-use and expire after disconnection. Generate a new link before reconnecting.
Model-facing tools
| Tool | Purpose |
|---|---|
toy_scan_raw_ble | On macOS, discover connectable raw BLE advertisements without Intiface or device writes |
toy_connect | Connect from the reported model; use unknown when it is not known |
toy_scan | Discover available devices |
toy_list | List device ids and controllable features |
toy_control | Send a bounded scalar command |
toy_stop | Stop one device or all devices |
toy_disconnect | Stop output and close the connection |
Known model: toy_connect → toy_scan → toy_list → toy_control → toy_stop → toy_disconnect.
Unknown model on macOS: toy_scan_raw_ble → use an advertised name as evidence → toy_connect → toy_scan. If raw discovery is unavailable or inconclusive, continue with toy_connect(model: "unknown").
Troubleshooting
spawn intiface-engine ENOENT: update to a release with automatic download support, ensureintifaceAutoDownload: true, and confirm GitHub is reachable.- The scan is empty: enable system Bluetooth, charge and power on the nearby toy, and disconnect any phone app or other controller using it.
- Intiface starts but scanning fails: check that the operating system granted Bluetooth access to DSH or its terminal.
- Raw BLE discovery cannot build its helper: install Xcode Command Line Tools with
xcode-select --install, or use the Intiface fallback. - MonsterParty rejects the connection: the sharing token may be used or expired; generate a fresh link and reconnect.
Known limitations
- The MonsterParty connection implements the relay behavior and
AKN_DS_SUCKEGGmapping documented by Chemtrails. Vendor-side protocol changes may require an update. - The built-in RoomFun mapping is hardware-verified for BLE name
RoomFun, model identifierRF_CANNON_PT3, firmware4.3, and one vibration output. Other RoomFun models are not assumed compatible. - Raw BLE advertisement discovery is macOS-only and requires the Swift compiler from Xcode Command Line Tools. It is read-only discovery, not a generic unknown-device control protocol.
- The Buttplug connection currently exposes scalar features only; position, direction, sensors, raw access, and subscriptions are outside the current scope.
- Tests use local protocol fixtures rather than physical hardware.
- Device ids should be refreshed with
toy_listafter reconnection.
Development
pnpm install
pnpm run check
Acknowledgements
Thanks to Chemtrails and Buttplug for their protocol research, documentation, and open-source work.
License
BSD-3-Clause. See LICENSE.
收录徽章
[](https://deepseek-plugin.org/plugins/c3ll256/dsh-toy)把这段 markdown 粘贴到你的 GitHub README,链接回本插件详情页。徽章只声明已被本站收录,不代表安全认证。