DSH Plugins Marketplace

DSH Plugins

Plugins

/

dsh-wecom-plugin

z

dsh-wecom-plugin

Manifest valid

DSH's WeChat Work plugin

hasBundlePatch

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 降级/分块)✅ 43 项全过(含媒体)
node test/live-demo.mjs真机隔离 DSH 实例 + 插件 + mock 企微 + 真 LLM✅ 端到端通过

版本兼容

DSH 版本状态
0.1.2-rc.1✅ 历史验证通过;DEPLOYMENT_PERSONA 精确匹配(旧基线,仍兼容)
0.1.5-rc.2✅ 当前基准版本(2026-09 起);DEPLOYMENT_PERSONA_PREFIX 精确匹配;隔离真机端到端验证通过(含真实 LLM)
  • peerDependencies:只保留 @deepseek-ai/cordis / @deepseek-ai/schemastery / ws(均 optional)。 @deepseek-ai/dsh-agent / dsh-llm / dsh-session 三个运行时包不再声明为 peer:每个 dsh profile 都必然引导 @deepseek-ai/dsh-base(其依赖链保证这三个包以宿主版本存在),且 -rc.N 预发布的严格 semver 元组规则使 ^ 范围无法跨 rc 版本表达(^0.1.2-rc.1 不匹配 0.1.5-rc.2,^0.1.5-rc.2 又不匹配 0.1.6+),保留只会得到过时/误导的版本契约。插件在 bridge.js 里以动态 import('@deepseek-ai/dsh-session') 等从宿主解析,运行不受影响(实测端到端通过)。
  • systemPrompt 章节次序:代码精确使用 DEPLOYMENT_PERSONA_PREFIX(DSH 0.1.5+ 的键,order 0; 0.1.2-rc.1 时代的 DEPLOYMENT_PERSONA 已不再依赖)。保留 ?? 0 仅作有限数值兜底 (section() 对非有限 order 会抛错),键本身是权威的。
  • source 标记:0.1.2-rc.1 的中继消息带 source.plugin: 'dsh-wecom-plugin';该标记在 0.1.5+ 的 released session 格式(v0/v1)中会被拒绝(user source 只允许 rpcId/clientTimeZone),v0→v1 迁移会拒载整份会话,因此插件已改为中继不带标记、 以 GUI 输入携带的 rpcId 区分(与 DSH 自身回显去重同源)。
  • 安装:生产用 file:,开发用裸路径(见「接入真实企业微信」)。

快速验证(无需企微凭据、无需 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

接入真实企业微信

  1. 打开 企业微信管理后台 → 应用管理 → 创建智能机器人 (或复用已有机器人),拿到 bot_id 和 secret。

  2. 把插件装进你的 dsh web profile:

    # 生产 / 正式部署:用 file: 前缀,把插件拷贝进 profile(真实路径在 profile 树内,模块回退可达)
    dsh plugin --profile web add "file:<本插件仓库路径>"
    
    # 开发 / 迭代:直接裸路径,link: 到源码 checkout,改代码后重启 dsh web 即生效
    dsh plugin --profile web add <本插件仓库路径>
    

    ⚠️ 为什么生产必须 file:、开发裸路径有条件:裸路径会被 pnpm 做成 link: 符号链接,插件真实路径 落在 DSH home 之外,Node ESM 从源码路径向上解析 @deepseek-ai/* 时够不到 DSH 的模块回退 ($DSH_HOME/profiles/node_modules 只对 profile 目录内的真实路径可见),会报 ERR_MODULE_NOT_FOUND(如 Cannot find package '@deepseek-ai/schemastery')直接崩溃。

    • 生产:file: 让 pnpm 把包放进 profile 内 .pnpm 虚拟仓库(自包含、任何机器都能起); 已发布到 registry 时直接 dsh plugin --profile web add <包名> 即可。
    • 开发:裸路径要想能跑,仓库根目录的 node_modules 必须已链到 DSH 安装 (含 @deepseek-ai/schemastery 等,见本仓库 .gitignore 注释),否则同样报错。

    或在 ~/.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: /你的/工作目录
    
  3. 重启 dsh web,把插件行 disabled: false(或在 profile patch 里启用)。

  4. 在企微里给机器人发消息即可对话;支持 /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
logFile插件诊断日志文件(DSH journal 不承载插件日志,连接/发送失败都写这里)$DSH_HOME/dsh-wecom-plugin.log
reconnectAfterKick被网关踢下线后自动重连(见"连接韧性");连续被踢 3 次才放弃true
kickReconnectDelayMs被踢后的重连等待毫秒数10000
sendRetryMs最终回复发送在连接掉线时的有界重试时长(自动重连通常 10s 内完成,此值需更大)30000
syncUserPrefixGUI 消息同步到企微时的标注前缀(协议只能以机器人身份发送,标签标明是你发的;空=不标注)📱 你在 Web GUI 发送:
approval.enabled企微内授权总开关:DSH 权限请求(如沙箱升级)转发到企微会话里,聊天内批准/拒绝,无需回 Web 后端true
approval.timeoutMs授权提示等待回复的毫秒数,超时按拒绝处理(fail-closed)60000
approval.approveWords视为"同意"的回复关键词(需带一次性授权码才生效)['同意','批准','允许','yes','approve','allow']
approval.rejectWords视为"拒绝"的回复关键词(优先匹配,避免"不同意"误命中"同意")['拒绝','不同意','不允许','不批准','no','reject','deny']
pluginVersionenter_check_update 版本探针应答0.1.0
subscribeExtra订阅帧额外字段(如 scene/plug_version),原样合并进 aibot_subscribe body{}
welcomeTextenter_chat 事件欢迎语,空=不发''
agent.presetagent preset''(profile 默认)
agent.cwd默认工作目录(可用 /cd 切换)dsh 进程 cwd
agent.provider/model覆盖模型路由,空=部署默认''
agent.reasoningEffort企微 agent 推理等级;空=跟随部署默认(settings 的 agent-default-model.reasoningEffort,与 GUI 一致)''
agent.conciseOutput企微 agent 注册"只输出结论" system-prompt sectiontrue
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'(等价 OpenClaw session.dmScope: "per-channel-peer"),每个(群,成员)独立会话与上下文,群里不同成员互不串扰、互不可见对方的对话历史。
  • 群聊 @提及 门控:设 agent.groupMention: 'at' 或 'at-or-quote' + agent.botName(机器人显示名),群里只有 @机器人(或引用/回复消息)才触发回复,其余消息忽略,避免刷屏。检测基于文本 @机器人名,提及标记会在送给 agent 前剥离。斜杠命令(/help 等)不受门控,始终响应。语义对齐 OpenClaw 的 requireMention(@提及 / 引用机器人 / 控制命令放行)。
  • 白名单:分享时 allowedUserIds 通常留空(放行所有人)——这意味着任何能给机器人发消息的人都能驱动你本机 agent(跑代码、读文件)。务必想清楚风险:只分享给可信的群,或考虑给 agent.cwd 指向受限工作区。
  • 切换 sessionScope 会改变会话 id:旧会话保留为历史记录,新消息会创建新会话(可用 GUI 归档旧的)。

企微内授权(approval)

DSH 的权限机制(如 sandbox 升级:sandbox_permissions + justification)默认只在 Web GUI 里弹 审批框;只通过企微使用时没有应答者会 fail-closed。本插件实现了企微内授权:DSH 为 企微专属 agent 发起的权限请求,会以机器人身份推送到对应会话,你在聊天里直接批准/拒绝即可, 完全不需要回 Web 后端。

工作方式(与 DSH 官方 ACP 应答器同一机制,注册为 approval/request waterfall 参与方):

  1. 企微 agent 执行需要授权的操作时,DSH 触发审批请求;
  2. 插件向该会话推一条授权提示,带一次性授权码(如 同意 3F9A):
    🔐 需要你的授权(60 秒内有效)
    
    操作:bash
    说明:escalate sandbox to danger-full-access: 需要写 /etc 下的配置
    
    回复「同意 3F9A」允许这一次;
    回复「拒绝 3F9A」拒绝。
    
  3. 在企微里回复「同意 3F9A」→ 本次操作放行(outcome allowed-once);回复「拒绝 3F9A」→ 终止(rejected);
  4. 超时未回复 → fail-closed 按拒绝处理(unavailable);请求被取消 → cancelled。

设计要点:

  • 一次性授权码:每条请求带随机码(4 位大写十六进制),必须连同关键词一起回复才生效, 防止群聊里随手一句"同意"误批准高危操作。
  • 拒绝词优先匹配:rejectWords 在 approveWords 之前检查,不同意 不会被当成 同意。
  • 只接管企微会话:仅应答 sessionChat 里有路由(即插件创建的 wecom-* 会话)的请求; GUI 会话的审批仍由 Web GUI 应答(本插件 next() 让路)。
  • 白名单仍生效:allowedUserIds 之外的用户发来的审批回复不会被消费(在 isAllowed 之后才进入审批分支)。

配置示例(全部可选,默认即开启):

config:
  approval:
    enabled: true          # 总开关
    timeoutMs: 60000       # 60 秒内有效
    approveWords: ['同意', '批准', '允许', 'yes', 'approve', 'allow']
    rejectWords: ['拒绝', '不同意', '不允许', '不批准', 'no', 'reject', 'deny']

安全提示:授权会放行真实的高危操作(如沙箱升级到 danger-full-access)。在共享群里使用 本功能时,任何能回复的成员都能批准——建议配合 allowedUserIds 白名单使用,或仅在私聊/可信群 中开启。

企微发图与连接韧性(重要)

为什么要 wecom_send_image 工具:agent 截屏后如果自己写脚本、开第二条 aibot 连接去发图, 网关会把插件的常驻连接踢下线(新连接接管同一 botId),之后插件所有发送都静默失败—— 表现就是你看到的"图片收到了、文字没收到"。这是实测踩过的坑。

修复后,插件注册了原生工具 wecom_send_image:

  • agent 只需调用 wecom_send_image(path)(本地图片文件路径),插件用自己的常驻连接 上传并发图,绝不产生第二条连接;
  • 工具按调用者 agent 路由到对应企微会话;只接受 PNG/JPEG/WebP/GIF 魔数;非企微会话拒绝;
  • 工具注册在企微专属 agent 的作用域(agent/created 时注入),GUI 会话/子代理的目录 保持干净;GUI 里打开的企微会话(含冷恢复)同样可用——工具是否存在只取决于会话是否 企微路由,与从哪个界面驱动无关;
  • 截图流程现在应是:bash 截屏存工作区 → wecom_send_image 发图 → 文字结论照常走 stream 回复。
  • 每个企微专属 agent 还会注入一条系统提示纪律(wecom-image-send-discipline section): 明确禁止自写 aibot 脚本/开第二条连接,强制要求发图走 wecom_send_image——因为模型有 "写脚本也能发出图"的历史习惯,仅注册工具不够,必须从提示源头约束。

连接韧性(三层防御,全部默认开启):

  1. 被踢自动重连(reconnectAfterKick: true):网关踢掉常驻连接后,等待 kickReconnectDelayMs(默认 10s)自动重连,不再永久离线;连续被踢 3 次(说明有真正 的第二个实例在抢)才放弃,需重启服务恢复。
  2. 文字发送兜底 + 有界重试:最终回复的 stream 发送任何失败都会降级为主动 markdown 发送(aibot_send_msg);若连接掉线则每 3s 重试,最长 sendRetryMs(默认 30s),等 自动重连落地后把文字补发出去,不再静默丢失。
  3. 诊断日志文件:$DSH_HOME/dsh-wecom-plugin.log(可用 logFile 覆盖)记录连接生命周期、 发送成败、工具调用与可见性,DSH journal 里看不到插件日志时的排障入口。

排查"企微只收到图/只收到字"这类问题,先看 ~/.dsh/dsh-wecom-plugin.log:如果出现 kicked by server 或 final stream reply failed,原因和上面的机制一一对应。

多工作区(不同项目目录)

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 + reset 纪元 确定性派生,插件 热重载/重启后同一对话继续使用同一个 session(自动 agents.resume),不会重复创建;路由表 持久化在 stateFile。
  • /reset 真正清空上下文:发送 /reset 会递增该会话的 reset 纪元,下一条消息生成全新的 空会话(新 session id),旧会话保留在 GUI 作为历史。适用于想让 agent"忘掉旧习惯"的场景 (例如它学会了某个不想要的工具调用模式)。
  • 企微 → 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 普通会话。
  • 桥自己转发进会话的消息是 kind:'user' 且不带 rpcId,不会被再次回显到企微,避免回环 (DSH 0.1.5+ 的 released session 格式只允许 user source 携带 rpcId/clientTimeZone, 旧版 source.plugin 标记已被移除;GUI 输入以 rpcId 识别,与 DSH 自身的回显去重一致)。

安全注意

  • allowedUserIds 默认空 = 放行所有企微用户(含群聊成员)——任何能给机器人发消息的人都能驱动 你本机 agent,生产必须配白名单。官方插件还有独立的群组策略(groupPolicy)与私聊策略 (dmPolicy/pairing),本 demo 未实现,群聊受同一 allowedUserIds 约束。
  • 插件在 DSH 进程内运行,拥有 dsh 的权限;不要给不信任的会话开全权限 preset。
  • 媒体下载仅接受来自企微网关的签名 URL(5 分钟有效),不解析用户提供的任意 URL。

媒体支持

  • 入站图片(视觉):用户发图 → 下载 + AES-256-CBC 解密 → 经 DSH attachment 服务准入 → agent 以 image 内容块看到图片(模型需支持 image 输入)。
  • 入站文件/视频:下载解密后保存到工作区 .dsh-wecom-media/,并把路径以附件说明交给 agent 读取。
  • 语音输入:企微自动转写,voice.content 文本直接进入对话(无需额外处理)。
  • 出站媒体:agent 输出的图片(assistant 消息中的 image 块)→ 三步分片上传 (aibot_upload_media_init/chunk/finish)→ aibot_send_msg 发回企微。
  • 大小限制:图片/视频 10MB、语音 2MB、文件 20MB(超出拒绝)。

部署与迭代注意

  • 配置变更热更新:改 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

Comments

Loading…

Similar plugins

dsh-WeCom-notify

by GuZhengSVT

DeepSeek Harness (dsh) 插件:事件驱动的企业微信(WeCom)群机器人通知 — goal 完成/阻塞与每轮对话自动推送,另含 wechat_notify 工具;走官方 webhook,零封号风险。

Terminal & ClientsManifest valid

★ 3

MIT

TypeScript

Aug 15, 2026

dsh plugin --profile web add dsh-wecom-notify

by lanbaolu

DeepSeek Harness (DSH) 微信桥接插件:三端通用,host 工具 + Web 管理面板

Notifications & IntegrationsDevelopment & InfrastructureManifest valid

★ 5

↓ 201/wk

MIT

TypeScript

Sep 29, 2026

dsh plugin --profile web add @lanbaolu/dsh-wechat-bridge

by sxylvlv

微信通道插件 for DSH:把微信消息接成 DSH 会话(文本/图片/文件/语音/视频双向,出站可推文档)

Manifest valid

★ 0

JavaScript

Sep 14, 2026

dsh plugin --profile web add dsh-weixin-channel

by Carl-5535

微信 × DeepSeek Harness (DSH):进程内插件,扫码即用,双向消息/文件,wechat_notify 主动推送

Notifications & IntegrationsManifest valid

★ 8

NOASSERTION

TypeScript

Sep 29, 2026

dsh plugin --profile web add dsh-wechat-gateway

by br1nosense

dsh-wxauto-plugin — DSH 微信汇报与监听插件

Notifications & IntegrationsTerminal & ClientsManifest valid

★ 3

MIT

Python

Aug 17, 2026

dsh plugin --profile web add @dsh-user/dsh-wxauto

by CMD128

微信桥接 DSH 插件:扫码绑定官方 ClawBot(iLink 协议),私聊驱动 DeepSeek Harness 会话 — WeChat bridge plugin for DSH

Terminal & ClientsTools & CapabilitiesManifest valid

★ 1

MIT

JavaScript

Sep 2, 2026

dsh plugin --profile web add dsh-wx-bridge