它是什么
DSH-IM 把即时通讯平台接到 DeepSeek Harness 上,让 agent 在聊天窗口里而不是浏览器标签页里回答。你给机器人发一条普通消息,插件为这个会话创建或复用一个 Harness Session,把消息当提示词转发进去,再按平台能给的方式把回答送回来——原生流式、卡片更新,或者反复编辑同一条消息。
最需要读对的一件事是这个机器人随后会听谁的。当某个渠道处于插件的 open 访问模式时,任何平台能报出标识符的发送者都可以驱动这个会话,包括在聊天里回答 agent 的追问、批准或拒绝工具调用。插件自己的文档把访问策略定义为“一道共享门禁”,不接管渠道原生路由,所以群聊必须 @ 机器人这类平台规则仍然叠加在上面。接任何渠道之前,请先看下面的「访问控制」一节。
有一处文档不一致:GitHub 仓库描述写的是「9 个渠道」,但当前 README 记录的是十个 IM 平台——飞书、微信、钉钉、企业微信、QQ、Slack、Telegram、Discord、WhatsApp 与 iMessage——外加第十一个独立的 AI Office Connector 页面。这十个当中,设置面板把 iMessage 与 AI Office 标注为「(实验功能)」。仓库描述只是落后于代码。
「扫码接入」扫的到底是什么
每个渠道的接入方式都不一样,而且多数情况下扫的并不是一个消费者登录。按 README 的渠道表:
- 飞书、钉钉、企业微信、QQ——扫码流程是代你在对应开放平台上创建并注册一个机器人应用。飞书、钉钉、企业微信也接受已有应用的凭据(App ID + App Secret、Client ID + Client Secret、Bot ID + Secret);QQ 接受 AppID + AppSecret。
- 微信——README 写的是「扫码绑定一个微信机器人」,走腾讯 iLink 长轮询。这里绑定的是一个账号,不是注册一个机器人应用。
- WhatsApp——「用手机 WhatsApp 扫码以链接设备」,也就是 WhatsApp Web 的已链接设备配对。README 没有声称这里用的是官方 WhatsApp Business API。
- Slack——没有扫码。你用仓库里自带的 App Manifest 创建一个应用,然后填入 Bot Token(
xoxb-)与 App Token(xapp-)。 - Telegram、Discord——没有扫码。填入由 @BotFather 或 Discord Developer Portal 生成的 Bot Token。
也就是说,没有任何一个渠道的二维码是登录 DSH 本身;其中四个渠道的扫码是在注册一个归你所有的机器人应用,另外两个是在绑定账号或链接设备。飞书还要求应用具备相应 tenant scope:群聊中其他机器人 @ 当前机器人需要 im:message.group_at_msg.include_bot:readonly,下载用户消息里的图片或文件需要 im:message:readonly,上传机器人发出的图片或文件需要 im:resource。README 记录了设置页的 Complete permissions 按钮与 /repair 命令,可再次扫码增量补齐这些权限。
凭据存在哪里
README 声明:密钥与 Token 只送往本机 Harness Host,并通过它受保护的凭据提供方(protected credential provider)保存;状态响应与机器人列表从不回传它们。读源码与之一致:微信的配置存储从账号 id 推导出形如 DSH_WEIXIN_BOT_TOKEN_<24 位大写十六进制> 的 token 引用,配置里只保存这个引用,控制器通过 DSH 凭据提供方的 resolve / set / unset 读写真实值。README 还写明连接器「只返回二维码、公开的 Slack Manifest、脱敏后的状态数据,以及显式保存的访问模式或白名单标识」,任何 RPC 响应都不会返回各渠道原始的 App Secret、bot token、client_secret 或已链接设备密钥。
本机状态落在 DSH_HOME/integrations/dsh-im/ 以及各渠道目录,例如 DSH_HOME/integrations/dsh-weixin/(DSH_HOME 未设置时回落到 ~/.dsh/...),README 为界面语言镜像文件和微信配置明确点出了这些位置。本次条目的撰写没有实际执行安装,所以「凭据提供方」这一条是按 README 与源码的描述转述,而不是在本地安装后验证过的事实。
访问控制
访问控制是读者最需要弄对的部分。插件为每个机器人单独保存一份策略,分成 direct 与 group 两个场景。每个场景要么是 open(任何能识别出标识符的发送者都放行,再由 defaultCanExecuteCommands 这个布尔值决定谁能执行命令),要么是 allowlist(只有名单内的用户 id 被放行,每行自带 canExecuteCommands)。此外还有一类不可编辑的特权旁路,对应渠道本来就已知的身份:微信的 ownerUserId、飞书的 ownerOpenIds、钉钉的 approvedSenders[].staffId、QQ 的 ownerUserOpenid、WhatsApp 已绑定的 accountJid。Telegram 与 Discord 的配置里没有人类 owner 字段,插件也没有为它们臆造特权身份。
初始默认值并不统一,而是在一个机器人第一次获得策略时,按该渠道升级前的既有行为推导一次:
| 渠道 | 私聊初始值 | 群聊初始值 |
|---|---|---|
| 微信 | allowlist 空名单(owner 由特权放行) | allowlist 空名单 |
| 飞书 | 仅当 owner id 为 * 时 open,否则 allowlist |
同私聊 |
owner 为 * 时 open,否则 allowlist |
open |
|
| Telegram | open(既有 allowedUsers 会灌入其中) |
open |
| 除旧模式曾是私聊白名单外,均为 allowlist 空名单 | allowlist 空名单 | |
| 钉钉、企业微信、Slack、Discord、iMessage | open |
open |
这张表来自项目自己的初始化代码,请照此理解:在钉钉、企业微信、Slack、Discord 与 iMessage 上,策略初始就是向任何能识别的发送者开放;QQ 的群聊也是开放的。判定顺序是:平台事件基本校验与回声过滤 → 渠道现有触发规则 → 特权 owner 旁路 → direct/group 访问策略 → 单独的命令权限检查,而且这一整套都发生在下载图片、创建 Session、执行本地命令、回答问题、审批或发起模型请求之前。被拒绝的消息静默忽略。
Telegram 与 WhatsApp 还有排在这一切之前的渠道原生模式,另有文档记载:Telegram 默认「兼容模式」(私聊直接响应,群聊需提及或回复),可切换到「安全模式(私聊白名单)」;WhatsApp 默认「仅自己」(只响应自聊),另有「指定联系人」与「开放响应」。指定联系人模式下白名单为空,行为等同于仅自己。
把安全后果直说: 只要一条消息能被放行,它就等价于在「按该机器人的工作区、模型与 Agent Preset 配置的会话」上发出的一段提示词。文档列为命令(额外权限位唯一保护的东西)的范围,不包含普通文字、对 agent 追问的回答、以及对工具审批的批准或拒绝——这几类只受访问策略约束。来源里没有任何一处描述独立的沙箱、按用户隔离的工作区或速率限制;工作区、Agent Preset 与模型是按机器人配置的,不是按发送者配置的。
长连接怎么跑
所有渠道都是出站连接;README 说明不需要公网 IP、端口转发或 WebSocket 服务端。文档点名的传输方式包括:飞书与企业微信的 WebSocket 长连接、钉钉 Stream、Slack Socket Mode、Discord Gateway v10、Telegram Bot API 长轮询、WhatsApp Web、微信的腾讯 iLink 长轮询、iMessage 的 chat.db 只读轮询加 /usr/bin/osascript,以及 AI Office Connector 的 SSE(它还带心跳,并按 90 秒租约、每 30 秒续租)。
它不是另一个常驻进程。包里的 bundle 补丁(一份 cordis.patch.yml,唯一动作是 insert 一行 xmanrui-dsh-im)把这些渠道运行时挂载在 Host 进程里,README 也说插件默认复用当前 Host 的内部服务,不需要 Harness 地址或 loopback HTTP 跳转。默认配置下不会为每个渠道拉起子进程;只有保留给旧版远程 HTTP/WebSocket harnessBaseUrl 的那条路径,客户端才会 spawn 一个受管的 dsh web 进程。重连由监督器管理,退避上限为 250, 1000, 3000, 5000, 10000, 30000 毫秒,另加 15 秒一次的健康检查;超时任务跟踪在插件重启或重连后会继续,把迟到的最终回复补发回原来的聊天或话题串。
运行要求
- Node
>=22.19,来自package.json的engines.node。README 另有一处说明:依赖NODE_USE_ENV_PROXY的 Telegram 代理路径需要 Node 22.21 或更新。 - Harness——包清单的
dsh.compatibility只把五个版本标为compatible:0.1.2-alpha.4、0.1.2-alpha.5、0.1.2-rc.1、0.1.3-alpha.1、0.1.5-alpha.1,并声明profiles: ["web"]。README 的本地开发一节重复了同样五个版本,作为 Web profile 验证过的版本。本条 frontmatter 里的dshTarget就是把这五个版本逐字记录下来;其中最旧的一个是版本下限。 - 运行依赖是六个锁定版本:
@tencent-connect/qqbot-connector、@tencent-connect/qqbot-nodejs、@wecom/aibot-node-sdk、dingtalk-stream、qrcode、undici。微信、飞书、WhatsApp、iMessage 那些更重的库(@whiskeysockets/baileys、@larksuiteoapi/node-sdk、React)放在devDependencies,因为发布包里是预构建好的lib/。 - 声明的 seam:
dsh块共三个键——bundle、client、compatibility。bundle指向一份cordis.patch.yml,唯一动作是 insert 一行xmanrui-dsh-im;client声明web平台并注入五个@deepseek-ai/dsh-client-*包。没有 headless 或纯 CLI 模式的声明。 - 没有安装期脚本。
scripts只有build、test、check,没有preinstall/install/postinstall/prepare,安装已发布包不会执行项目代码。GitHub 源码安装路径(npx -y github:xmanrui/dsh-im install)会从源码构建,README 提醒 pnpm 10 及以上可能需要为它加一条allowBuilds。 - 遥测:没有描述,已发布代码与源码里也找不到任何遥测或统计客户端。唯一非平台类的网络端点是
registry.npmjs.org(按更新指南,只在你点 Check for updates 时才访问)与https://dsh-im-random-badge.xmanrui-dsh-im.workers.dev——同一个仓库里那个提供静态 SVG 徽章的 Cloudflare Worker,README 的图片引用了它。
已知限制
- 各渠道能力不均。 文件与图片回传受各平台自身的权限、配额与账号等级约束:微信文件回传取决于绑定的协议与会话是否支持原生文件消息,QQ 受每日上传配额限制,飞书上传 API 上限 30 MB。入站图片为 JPEG/PNG/WebP(GIF 按图片文件发送),单张 5 MB、单条消息合计 20 MB。
- iMessage 是首版 MVP。 只支持文本私聊——没有群聊、附件、富文本、引用回复、reaction、编辑与撤回。它需要 macOS、与 Host 处于同一用户会话且已登录的 Messages.app、读取
chat.db的完全磁盘访问权限,以及控制 Messages 的自动化权限。每个 macOS 用户账户只暴露一个 iMessage 身份(macos-messages);渠道说明指出chat.db是私有且不稳定的数据库、不是公开 API。 - 回复长度是分段处理的。 微信把最终回复按 1,800 字符分片发送,WhatsApp 会自动切分长回复;平台支持流式或编辑消息时插件就用,不支持时用一条最终消息收口。
/stop的作用域有限。 它停止的是当前聊天提交的那一轮任务,不是整个会话;解绑聊天后,旧结果也不会再被投递到那里。- 若干渠道的访问默认值是宽松的,而且是按机器人单独保存的。接了钉钉、企业微信、Slack、Discord 或 iMessage 之后如果不去动访问设置页,它就保持对任何能识别的发送者开放。
- 机器人、凭据、工作区、Agent Preset 与会话绑定在升级后会保留,但渠道之间不会互相迁移;修改机器人的模型、推理等级或 Preset 只对之后新建的会话生效,已有聊天要先发
/new。
什么时候用它、什么时候不要用
当你希望 agent 出现在你本来就在说话的地方时用它:自己的微信或飞书、小团队的 Slack 或 Telegram、或者一个 Discord 服务器。除了一问一答,比较有意思的是会话层面的那些入口——/session 把某个聊天绑到已有会话、/sessions 与 /history 用来翻看、/workspace 与 /preset 决定新会话在哪、以什么方式跑、/steer 与 /batch 干预进行中的任务,以及按机器人配置的文件回传:任何 Harness 能读的文件都能走渠道原生的附件能力送出去。
不要把它当成「把 agent 开放给别人用」的方案。它通向的是你自己的本机 Harness:来源里没有记录按用户隔离的工作区、没有审批隔离,而且十个渠道里有五个的初始策略是放行平台能叫出名字的所有人。如果你确实要接一个支持群聊的渠道,请把访问设置页当作必做配置而不是可选加固,并且先弄清你的平台会把什么身份交给机器人,再假设某条白名单记录能匹配得上。如果你只是想要通知或定期摘要,一个单向推送集成比双向机器人小得多——dsh-notifier 覆盖 27 个出站渠道并带审批,而 dsh-notification 连凭证都不需要;如果你要的是官方 WhatsApp Business API,那它不是这个。
FAQ
给机器人发一条消息,等于在驱动一个能执行工具的 agent 吗?
机制上是的,但有一个区别。插件把消息转发进一个按该机器人的工作区、模型与 Agent Preset 配置的 Harness Session,所以 agent 可以为那个工作区动用它的工具。这条消息不能做的是:除非发送者被授权为可执行命令的用户,否则不能运行 /new、/workspace、/model、/preset、/compact 这类插件命令。普通文字、对 agent 追问的回答、以及工具审批,只受访问策略约束,不受命令权限布尔值约束——项目自己的设计文档把它们明确列为「不是命令」。
默认情况下谁能给机器人发消息?
取决于渠道,而且答案来自初始化代码而不是 README。微信从空白名单开始,扫码接入的 owner 走特权放行;飞书与 QQ 默认从白名单开始,除非 owner id 被配成 *;Telegram 默认开放,并把已有的 allowedUsers 灌进去;WhatsApp 默认只响应自聊。钉钉、企业微信、Slack、Discord 与 iMessage 默认开放给任何能识别的发送者,QQ 的群聊也是开放的。Telegram 与 WhatsApp 自身的模式(兼容/安全,仅自己/指定联系人/开放响应)排在这套共享策略之前。
入站消息有鉴权或白名单机制吗?
有,两层,文档都写到了。每个渠道保留自己的原生触发规则——群聊提及要求、回复、Thread、以及各平台的群消息权限。它们后面是共享访问策略:direct 与 group 两个场景,各自可选 open 或 allowlist,加上每用户一个 canExecuteCommands 标志,以及不可编辑的 owner 旁路。设置页按机器人管理这些。来源里没有描述的是:对平台标识符背后那个人的鉴权、入站消息上的共享密钥,或者速率限制。
需要我自己创建机器人应用吗?
多数渠道需要。飞书、钉钉、企业微信与 QQ 要么通过扫码流程代你注册一个,要么接受你已有应用的凭据。Slack 一定需要你用仓库自带的 Manifest 创建应用,并提供 Bot Token 与 App Token。Telegram 与 Discord 需要你先在平台上生成 Bot Token。微信与 WhatsApp 则是绑定账号或链接设备。你接入的应用或账号归你所有、也由你负责,包括平台侧的权限范围、配额与审核。
需要公网 IP、端口转发或常驻服务器吗?
不需要公网 IP 或端口转发:所有渠道都是向外连接。但 Host 进程必须在运行,因为这些渠道运行时挂载在它内部,而不是跑在另一个守护进程里;iMessage 渠道尤其要求 Host 与已登录的 Messages.app 处于同一个 macOS 用户会话。
Token 存在哪里?
按 README:密钥与 Token 只送往本机 Harness Host,并通过它受保护的凭据提供方保存,任何 RPC 响应都不会回传。源码一致:微信的配置存储只保留形如 DSH_WEIXIN_BOT_TOKEN_<24 位十六进制> 的派生 token 引用,真实值通过凭据提供方读取。README 还写明更新安装器只保留该 profile 最近一次任务与 manifest 备份,不会复制机器人凭据。
