dsh
OpenPetsHQ/openpets将 DeepSeek Harness 的生命周期状态、错误与审批请求,桥接到本地运行的 OpenPets 桌面伙伴。
钉钉 IM 双向 channel(Stream 模式):每条单聊/群聊驱动一个 agent,思考与回复通过 WebSocket 长连接回流消息,免公网回调。
DeepSeek Harness 的钉钉 IM 机器人 channel——每条单聊/群聊背后都是一个真正带工具的 agent,消息即入口,回复回到对话里。
通过钉钉官方 Stream 模式(WebSocket 长连接)把钉钉「机器人」接入 dsh。不需要公网回调地址、不需要服务器配置 webhook,机器人私聊或群里 @ 它即可驱动完整 agent(带 bash、read、edit、skills 等工具,按 preset 挂载)。
架构沿袭 dsh-lark-channel(BSD-3-Clause)的 channel 设计:窄宿主契约 + 传输层端口 + 会话爬梯 + 事件渲染。
ding-<chatId>),跨重启稳定;sessionScope: chat-sender 可让共享群里每人一个 agentsenderAllowlist / groupAllowlist,群聊 requireMention;审批按聊天回复「允许一次 / 拒绝」结算/ping /help /status /stop /new,未知 / 命令下传给宿主 commands 运行时(有 /compact 等时可用)# 从 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
~/.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
export DINGTALK_CLIENT_ID='ding...'
export DINGTALK_CLIENT_SECRET='...'
dsh web
dsh web 启动日志里出现 dsh-dingtalk-channel 的凭证校验通过(无缺凭证告警)后,私聊机器人发 /ping 应收到 pong。
| 字段 | 默认 | 含义 |
|---|---|---|
clientId / clientSecret | — | 钉钉应用凭证(必填) |
botName | — | 机器人昵称;配置后只在群消息首个 @ 匹配时才剥离 |
cwd | 宿主 cwd | 会话 agent 工作目录 |
workspaceRoots | [] | /cd 可达目录前缀(空=任意) |
provider / model | 宿主默认 | 会话 agent 模型路由 |
preset | roster 默认 | 会话 agent 挂载的 preset |
sessionScope | chat | chat / chat-thread(=chat) / chat-sender |
sendReceipt | true | 每条消息先发回执(emotion 开启时被替代) |
emotion | true | 消息上贴 🤔思考中 表情表示已读/处理中,回复完成自动撤回 |
denyTools | [ask_user_question, exit_plan_mode] | 会话 agent 禁用的工具 |
requireMention | true | 群聊仅被 @ 时响应 |
senderAllowlist | [] | 单聊 staffId 白名单(空=应用可见范围内任何人) |
groupAllowlist | [] | 群会话白名单(空=任何群) |
approvers | [] | 可回答审批的 staffId(空=能驱动该会话的人) |
| 命令 | 作用 |
|---|---|
/ping | 连通性检查 |
/help | 列出命令 |
/status | 会话/目录/模型/运行状态 |
/stop | 取消当前生成 |
/new | 开启新会话(历史保留) |
agent 需要批准时(approval/request),channel 在对话里发审批消息,回复「允许一次」放行一次、「拒绝」取消;abort 时结算为取消。默认 denyTools 已禁用 ask_user_question / exit_plan_mode(答案到不了本渠道的人类交互工具),模型会被引导直接在回复里提问。
attachImages 未实现(钉钉图片需先下载,v0.1 不做)。/cd / /model use / /ws:工作区切换与模型热切换 v0.1 未实现(配置层字段已预留)。botName 配置后只在首个 @ 匹配时剥离;不配置则剥离首个 @… 词元。dsh 会话能做的,聊天里都能做。请把机器人只加进可信的人/群。senderAllowlist 限单聊发送者、groupAllowlist 限群会话、approvers 限审批人;最终以钉钉应用的可见范围为准。ask_user_question / exit_plan_mode(答案到不了本渠道的人类交互工具),审批改为对话内回复「允许一次 / 拒绝」。dsh.profile.bundles 移除 dsh-dingtalk-channel,重启 dsh web 即不再连接钉钉。dsh plugin --profile web rm dsh-dingtalk-channel(或 pnpm remove dsh-dingtalk-channel),重启。MIT —— 见 LICENSE。
npm install
npm run typecheck # tsc --noEmit
npm run build # tsc → lib/
npm test # vitest