dsh-wecom-plugin
DSH 的企业微信插件
- Stars
- 0
- Language
- JavaScript
- Created
- Sep 8, 2026
- Updated
- Sep 8, 2026
Introduction
dsh-wecom-plugin
把 企业微信(智能机器人 aibot WebSocket) 与 DeepSeek Harness(DSH) 双向连通的 最小可行性插件(demo)。无公网入口,长连接常驻,每个企微会话对应一个持久的 DSH agent 会话。
状态:可行性验证 demo。企微 wire 协议已按官方
@wecom/aibot-node-sdk对齐(流式回复、 回执/心跳 ack、事件回调、846608 降级),协议 + DSH 会话打通已在本仓库自动化测试验证; 接入真实企业微信只需按下文创建智能机器人并填入凭据。
架构
企业微信 App ──WS──> openws.work.weixin.qq.com ──WS──> dsh-wecom-plugin 插件(本机 dsh web 内)
aibot_subscribe / aibot_msg_callback / aibot_event_callback
aibot_respond_msg(stream) / aibot_send_msg
│
┌────────────┴────────────┐
│ Bridge(每个 chat 一个 agent)│
│ inbound → followup() │
│ outbound ← session/event │
└────────────┬────────────┘
│
DSH agent(LLM)
src/aibot-client.js— 企微智能机器人 WebSocket 客户端(官方协议对齐: 流式回复 thinking→finish、回执等待、心跳 ack 健康检查、认证失败/网络断线分离重试、 disconnected_event 防互踢、enter_check_update 版本应答、引用消息兜底)src/bridge.js— 会话路由:一条企微消息 → 一个 DSH agent 会话,回复采集+分块+流式回推src/index.js— Cordis 插件入口(apply(ctx)+ Config schema)test/mock-wecom.js— 本地模拟企微网关(仅测试用,无 cmd 的 ack 帧,与真实网关一致)
验证结果
| 测试 | 内容 | 结果 |
|---|---|---|
npm test(test/smoke.mjs) | 协议(订阅/流式回复/quote/鉴权拒绝/事件回调/防互踢)+ 桥(建会话/多轮/dedup/白名单/846608 降级/分块) | ✅ 30 项全过 |
node test/live-demo.mjs | 真机隔离 DSH 实例 + 插件 + mock 企微 + 真 LLM | ✅ 端到端通过 |
快速验证(无需企微凭据、无需 LLM)
node test/smoke.mjs
真机端到端(需要本机 DSH 和一个可用的 LLM 提供方)
test/live-demo.mjs 会在一个隔离的 DSH 环境里加载插件并连接本地 mock 企微网关,
验证「企微消息 → 插件 → 真实 agent → 真实 LLM → 回复」的完整链路,不影响你正在运行的 profile。
# 1. 确保本机 DSH 已配置一个可用的 LLM 提供方(即你的 DSH 默认模型),
# 并导出该提供方所需的环境变量(你的 settings 里 provider 对应的 key):
export <你的LLM_API_KEY环境变量名>=... # 例:DEEPSEEK_API_KEY=sk-...
# 2. 运行端到端(隔离环境位置可用 DSH_DEMO_HOME 覆盖):
node test/live-demo.mjs
接入真实企业微信
- 打开 企业微信管理后台 → 应用管理 → 创建智能机器人
(或复用已有机器人),拿到
bot_id和secret。 - 把插件装进你的 dsh web profile:
或在cd ~/.dsh/profiles/web pnpm add <本插件仓库路径>~/.dsh/profiles/web/cordis.patch.yml里插入(本地源码路径也可以):- insert: - id: dsh-wecom-plugin name: 'dsh-wecom-plugin' config: botId: '你的-bot-id' secret: '你的-secret' allowedUserIds: [] # 企微 userid 白名单;空 = 所有人 agent: preset: '' # 留空用 profile 默认 cwd: /你的/工作目录 - 重启 dsh web,把插件行
disabled: false(或在 profile patch 里启用)。 - 在企微里给机器人发消息即可对话;支持
/help、/reset、/status。
配置项
| 键 | 含义 | 默认 |
|---|---|---|
botId / secret | 企微智能机器人凭据 | '' |
websocketUrl | 网关地址(本地 mock 测试时改) | wss://openws.work.weixin.qq.com |
allowedUserIds | 允许对话的企微 userid,空=放行所有 | [] |
workspaces | 工作区别名表(/cd <名字> 用),如 { web: /path/a, api: /path/b } | {} |
stateFile | 会话路由状态文件(chatId→sessionId,热重载不丢路由) | $DSH_HOME/dsh-wecom-plugin-state.json |
syncUserPrefix | GUI 消息同步到企微时的标注前缀(协议只能以机器人身份发送,标签标明是你发的;空=不标注) | 📱 你在 Web GUI 发送: |
pluginVersion | enter_check_update 版本探针应答 | 0.1.0 |
subscribeExtra | 订阅帧额外字段(如 scene/plug_version),原样合并进 aibot_subscribe body | {} |
welcomeText | enter_chat 事件欢迎语,空=不发 | '' |
agent.preset | agent preset | ''(profile 默认) |
agent.cwd | 默认工作目录(可用 /cd 切换) | dsh 进程 cwd |
agent.provider/model | 覆盖模型路由,空=部署默认 | '' |
agent.reasoningEffort | 企微 agent 推理等级;空=跟随部署默认(settings 的 agent-default-model.reasoningEffort,与 GUI 一致) | '' |
agent.conciseOutput | 企微 agent 注册"只输出结论" system-prompt section | true |
agent.cdAllowPaths | 允许 /cd <裸路径>;默认 false 只允许配置的 workspaces 别名(防 IM 用户把 agent 指向任意目录) | false |
agent.sessionScope | 会话隔离:chat(每群一个,成员共享)/ chat-user 或 per-channel-peer(OpenClaw session.dmScope 同义,每群每成员一个,推荐共享用)/ user(每成员一个跨群) | chat |
agent.groupMention | 群聊提及门控:none(每条都回)/ at(仅 @机器人 时回)/ at-or-quote(@ 或 引用/回复消息时回);斜杠命令始终放行 | none |
agent.botName | 机器人显示名,用于 @提及 检测(如 你的机器人名) | '' |
agent.maxMessageLength | 单条回复上限,超出分块 | 4000 |
agent.idleTimeoutMs | 会话闲置回收,0=不回收 | 30min |
多用户 / 群共享
把助手分享给群和其他人时:
- 会话隔离:设
agent.sessionScope: 'chat-user'(等价 OpenClawsession.dmScope: "per-channel-peer"),每个(群,成员)独立会话与上下文,群里不同成员互不串扰、互不可见对方的对话历史。 - 群聊 @提及 门控:设
agent.groupMention: 'at'或'at-or-quote'+agent.botName(机器人显示名),群里只有 @机器人(或引用/回复消息)才触发回复,其余消息忽略,避免刷屏。检测基于文本@机器人名,提及标记会在送给 agent 前剥离。斜杠命令(/help等)不受门控,始终响应。语义对齐 OpenClaw 的 requireMention(@提及 / 引用机器人 / 控制命令放行)。 - 白名单:分享时
allowedUserIds通常留空(放行所有人)——这意味着任何能给机器人发消息的人都能驱动你本机 agent(跑代码、读文件)。务必想清楚风险:只分享给可信的群,或考虑给agent.cwd指向受限工作区。 - 切换
sessionScope会改变会话 id:旧会话保留为历史记录,新消息会创建新会话(可用 GUI 归档旧的)。
多工作区(不同项目目录)
agent.cwd 只是默认工作目录。每个企微会话可以随时用 /cd 切换工作目录:
/cd web # 切到配置别名 workspaces.web 对应的目录
/cd /path/to/other # 切到任意绝对路径(也支持 ~ 和相对路径)
/cd # 查看当前工作目录
/status # 状态里也会显示当前工作目录
配置示例:
config:
agent:
cwd: /home/you/project-a # 默认工作区
workspaces:
web: /home/you/project-b # /cd web → 切到 project-b
api: /home/you/project-c # /cd api → 切到 project-c
切换后,该会话的 agent 会用新目录作为工作区(bash 默认 cwd、相对路径、文件工具范围等),
并清空上下文重新开始(相当于先 /reset 再换目录)。切换前后是两个独立的 DSH 会话,
各自持久化,可随时切回。
会话稳定性与 Web GUI 双向同步
- 会话稳定:每个企微会话的 DSH session id 由
chatId + cwd确定性派生,插件热重载/重启后 同一对话继续使用同一个 session(自动agents.resume),不会重复创建;路由表持久化在stateFile。 - 企微 → GUI:企微里发的消息以
kind:'user'中继进wecom-*会话,在 Web GUI 里显示为 你自己的用户气泡(而非灰色上下文注记),可点开查看完整轨迹。 - GUI → 企微:在 Web GUI 里打开某个
wecom-*会话继续对话,你发送的消息和 agent 的回复会 自动镜像回企微。由于 aibot 协议只能以机器人身份发送,你发的那条会带syncUserPrefix标注 (默认📱 你在 Web GUI 发送:),回复则正常以机器人身份出现。 - 只同步结论:两条原则,不做输出解析:
- 结构纪律:只取每轮最后一条 assistant 消息的
text块(DSH 原生区分reasoning=思考 /text=回答,中间步骤与思考块天然被排除)。 - 源头约束:插件为企微专属 agent 注册一个 scoped system-prompt section
(
agent.conciseOutput,默认开启),要求模型把分析放在reasoning、可见文本只写结论。 该 section 只作用于企微 agent,不影响 GUI 普通会话。
- 结构纪律:只取每轮最后一条 assistant 消息的
- 桥自己转发的消息(
source.plugin: 'dsh-wecom-plugin')不会被再次回显,避免回环。
安全注意
allowedUserIds默认空 = 放行所有企微用户(含群聊成员)——任何能给机器人发消息的人都能驱动 你本机 agent,生产必须配白名单。官方插件还有独立的群组策略(groupPolicy)与私聊策略 (dmPolicy/pairing),本 demo 未实现,群聊受同一allowedUserIds约束。- 插件在 DSH 进程内运行,拥有 dsh 的权限;不要给不信任的会话开全权限 preset。
- 本项目为可行性 demo:无富媒体入站(图片/文件 url+aeskey 解密上传未实现,
mixed/voice/appmsg文本已提取)、无模板卡片、无群聊 @ 提及过滤。生产化可参考官方 OpenClaw 插件补齐。
部署与迭代注意
- 配置变更热更新:改
cordis.patch.yml(如 botId/secret/白名单)会自动热重载,无需重启。 - 源码变更必须重启:DSH 的 loader 只在插件行
name/inject/group变化时才重新 import 模块;修改src/*.js后仅靠热重载不会生效,需重启 dsh web。这是 DSH 的设计(配置热更新、 代码需重启),迭代插件时务必记住。 agent.reasoningEffort建议显式设置(如max),避免依赖上游默认导致行为不一致。
参考
- 官方 DSH 插件开发文档:
docs/user/develop/basic、docs/cookbook/extension-cookbook.md - 企微智能机器人官方 SDK/文档:https://open.work.weixin.qq.com