ttmouse/dsh-dingtalk-channel ↗★ 0
dsh-dingtalk-channel
DingTalk IM bot channel for DeepSeek Harness: each chat drives its own agent, replies and thinking come back as messages over the Stream-mode long connection.
安装
npx -p @deepseek-ai/dsh dsh plugin --profile web add github:ttmouse/dsh-dingtalk-channel说明文档
阅读完整 README ↗dsh-dingtalk-channel
DeepSeek Harness 的钉钉 IM 机器人 channel——每条单聊/群聊背后都是一个真正带工具的 agent,消息即入口,回复回到对话里。
通过钉钉官方 Stream 模式(WebSocket 长连接)把钉钉「机器人」接入 dsh。不需要公网回调地址、不需要服务器配置 webhook,机器人私聊或群里 @ 它即可驱动完整 agent(带 bash、read、edit、skills 等工具,按 preset 挂载)。
架构沿袭 dsh-lark-channel(BSD-3-Clause)的 channel 设计:窄宿主契约 + 传输层端口 + 会话爬梯 + 事件渲染。
✨ 特性
- 🤖 一会话一 agent——会话 id 由会话键确定性派生(
ding-),跨重启稳定;sessionScope: chat-sender可让共享群里每人一个 agent - ⚡ 即时反馈——每条消息先回执「🤔 已收到」,再流式到达最终答案(钉钉无打字指示,回执是唯一即时反馈)
- 🤫 静默过程——中间过程只在回执/思考表情里暗示,agent 调用 bash/read/edit 等工具不发聊天消息,只把最终答案发成 markdown
- 🛡️ 访问策略——单聊/群聊各自
senderAllowlist/groupAllowlist,群聊requireMention;审批按聊天回复「允许一次 / 拒绝」结算 - 📡 长连接自愈——SDK 自动重连,断线事件落在操作台
- 💬 命令——
/ping/help/status/stop/new,未知/命令下传给宿主commands运行时(有/compact等时可用) - 🩺 可观测——拒绝/失败/断线全部 notify 到进程 stderr + 宿主日志
🚀 快速开始
1. 钉钉侧准备(一次性)
- 打开 钉钉开发者后台,创建企业内部应用,记下 ClientID(AppKey) 与 ClientSecret(AppSecret)。
- 应用能力 → 添加应用能力 → 机器人,完善机器人信息,消息接收模式选 Stream 模式,发布应用。
- 把机器人拉进目标群(或让成员私聊它)。群聊中机器人默认只收到 @ 它的消息。
2. 安装插件
# 从 npm
dsh plugin --profile web add dsh-dingtalk-channel
# 或从 GitHub(自动构建)
dsh plugin --profile web add github:ttmouse/dsh-dingtalk-channel
# 或从源码/本地目录(先 npm install && npm run build 产出 lib/)
dsh plugin --profile web add /绝对路径/dsh-dingtalk-channel
3. 配置凭证
~/.dsh/profiles/web/cordis.patch.yml 里覆盖该行(也可用 !!js process.env.… 走环境变量):
- id: dingtalk-channel
name: 'dsh-dingtalk-channel'
config:
clientId: !!js process.env.DINGTALK_CLIENT_ID
clientSecret: !!js process.env.DINGTALK_CLIENT_SECRET
botName: 我的助手 # 用于剥离群消息 @ 前缀(不配则剥离首个 @… 词元)
# preset: standard # 挂进会话 agent 的 preset(部署组合了 roster 时)
# cwd: /path/to/workspace # 默认宿主进程 cwd
# sessionScope: chat # chat-sender 让共享群里每人一个 agent
# sendReceipt: true
# emotion: true # 消息上贴 🤔思考中 表情,回复完成自动撤回(替代文字回执)
requireMention: true