deepseek-harness
deepseek-ai
DeepSeek Harness: Everything is a Plugin.
PROJECT TOPICS
PROJECT README
English | 简体中文
为 DeepSeek Harness (dsh) 提供多 IM 通道接入的网关插件:钉钉 / QQ / 个人微信 / 飞书 / 企业微信,支持扫码绑定、流式回复、工具审批、交互提问、长文本分片、多段合并、双语界面。
ctx.imGateway 核心:会话管理、斜杠命令、流式回复、状态广播。qqbot-nodejs SDK),私聊(c2c)+ 群聊,扫码绑定机器人(免去开放平台手动创建),流式消息(c2c)。@larksuiteoapi/node-sdk 长连接(无需公网回调),扫码一键创建应用(权限与会话事件自动预填),私聊 + 群聊,CardKit 卡片流式输出,图片/文件收发。replyStream 原位替换,官方原生能力),图片/文件/语音收发。DSH_HOME 文件锁防止多个实例并发写坏 session log。ask_user_question 时,问题同步推送到 IM,用户回复选项编号/文字即可作答,与 Web 端竞速第一答生效。(1/3) 分段前缀,逐条发送。.. 续传合并、!! 立即提交。im_send_file 工具把工作区文件(图片/视频/文档)直接发送到当前 IM 会话。language: 'zh' | 'en' 切换所有用户可见回复的语言。/help、/model、/status、/new、/reset、/stop、/sessions、/continue、/workspaces、/workspace(见下文)。/sessions 列出最近会话(含标题),/continue <id> 恢复指定会话。[机器人名] 智能标题,一眼分辨会话来自哪个通道(机器人名取通道实例的 name,未填则回落到通道类型名)。标题沿用 dsh 官方生成的智能标题,只在前面加前缀;在 Web 端手动重命名后不再自动覆盖。/workspaces 列出所有工作区及会话数,/workspace <路径> 切换工作区(自动重置当前会话,下次消息在新工作区创建新会话)。allowAllUsers 或 allowedUserIds 精确控制谁可以使用机器人。需要 DeepSeek Harness (dsh)——本插件是标准 dsh bundle,通过官方插件通道安装。
dsh plugin --profile web add @lijian-ui/dsh-im-gateway
npm 包自带预构建的 lib/ — 无需构建授权(不需要 allowBuilds)。
npm pack @lijian-ui/dsh-im-gateway
dsh plugin --profile web add ./dsh-im-gateway-0.1.1.tgz
dsh plugin --profile web add github:lijian-ui/dsh-im-gateway
Git 安装拉取的是源码,首次安装需要批准包的
prepare构建脚本(pnpm ≥ 10)。按提示把包键加进 profile 的pnpm-workspace.yaml→allowBuilds即可。优先用 npm / tarball 方式可跳过此步。
dsh --profile web --dump-config # 应看到 "# == @lijian-ui/dsh-im-gateway" 配置层
dsh --profile web # 启动后浏览器打开设置 → 「IM 通道」
配置存储在
~/.dsh/settings.yaml(im-gateway.channels)。在 UI 保存配置会热重载通道(无需重启)。
在任何 IM 通道里发给机器人:
| 命令 | 说明 |
|---|---|
/help |
列出可用命令 |
/model |
用 emoji 编号列出模型;/model 1 或 /model <名称> 切换(无会话时 → 设为下次会话默认模型) |
/status |
通道 / cwd / 当前模型 / agent 状态 |
/new /reset /clear |
开启全新会话 |
/stop |
中止当前回复 |
/sessions |
列出最近 10 个会话(标记当前会话,显示标题) |
/continue <会话id> |
继续指定会话(用 /sessions 查看可用 id) |
/workspaces |
列出所有工作区(按最近活动排序,显示会话数) |
/workspace <路径> |
切换到指定工作区(重置当前会话,下次消息在新工作区创建新会话) |
/workspace |
不带参数时等同于 /workspaces |
| 后缀 | 说明 |
|---|---|
| (无) | 进入合并窗口,等待后续消息(默认 3 秒超时后自动提交) |
.. |
续传合并:把本条加入缓冲,继续等待 |
!! |
立即提交:把缓冲 + 本条合并后马上发给 agent |
当 agent 调用需要审批的工具时,直接回复:
| 回复 | 效果 |
|---|---|
批准 / 同意 / yes / y / allow |
放行工具执行 |
拒绝 / no / n / reject / deny |
拦截工具执行 |
超时后自动委托回 dsh 原生审批体系。
所有配置都可在设置页编辑;底层 schema 在 ~/.dsh/settings.yaml:
im-gateway:
language: zh # 界面语言:zh(中文)| en(英文)
approvalTimeoutSecs: 120 # 工具审批超时(秒)
questionTimeoutSecs: 600 # 交互提问超时(秒)
mergeTimeoutSecs: 3 # 多段输入合并窗口(秒)
allowAllUsers: false # 全局放行所有用户(仅开发用)
allowedUserIds: # 白名单:{ channelId: string[] } 或用 '*' 匹配任意渠道
"*":
- user-abc
channels:
- id: dingtalk-main
type: dingtalk
name: 主机器人
enabled: true
config:
clientId: "..."
clientSecret: "..."
# 其余字段按通道类型取用:callbackBaseUrl / appId / botAppId / baseUrl /
# botId / cdnBaseUrl / pollIntervalMs / domain(飞书)/ secret(企业微信)/
# groupPolicy / groupAllowFrom / groups
| 字段 | 默认值 | 含义 |
|---|---|---|
language |
zh |
界面语言(zh 中文 / en 英文),影响所有用户可见回复 |
streamThrottleMs |
800 |
流式推送节流间隔(毫秒) |
slashCommands |
true |
是否启用斜杠命令 |
approvalTimeoutSecs |
120 |
工具审批 IM 等待超时(秒),超时后委托回 dsh 原生审批 |
questionTimeoutSecs |
600 |
交互提问 IM 等待超时(秒),超时后转回 Web 端 |
mergeTimeoutSecs |
3 |
多段输入合并窗口(秒),用户连续发消息时合并为一条 |
allowAllUsers |
false |
全局放行所有用户(仅开发用,生产环境勿开) |
allowedUserIds |
{} |
白名单;key 为 channelId(* 匹配任意),value 为用户 ID 数组 |
| 字段 | 适用渠道 | 含义 |
|---|---|---|
clientId / clientSecret |
dingtalk | 钉钉应用 key / secret(Stream 模式) |
appId / clientSecret |
QQ 开放平台凭据(扫码绑定所得) | |
token / botId / baseUrl / cdnBaseUrl |
weixin | iLink 凭据(扫码绑定所得) |
appId / clientSecret / domain |
feishu | 飞书 / Lark 应用凭据(扫码创建所得);domain:feishu(中国版)或 lark(国际版) |
botId / secret |
wecom | 企业微信智能机器人 BotID + 长连接专用密钥(扫码创建所得) |
groupPolicy / groupAllowFrom / groups |
qq · feishu · wecom | 群消息策略:open 全响应 / allowlist 白名单 / disabled 不响应 |
enabled |
全部 | 该实例是否连接 |
IM 客户端 ──► 通道适配器 (dingtalk / qq / weixin / feishu / wecom)
│ ImInboundMessage
▼
ctx.imGateway(核心)
│ 多段合并 → 白名单检查 → 审批/提问拦截 → 斜杠命令
│ ensureSession → agent.followup
▼
dsh harness agent(LLM 循环)
│ 会话事件 (turn/start, assistant/message, tool/call, turn/end)
│ 实时流 (agent/assistant-stream: text-delta 增量)
▼
EventDispatcher → 流式回复 / 分片 / 工具提示
│ (AI 卡片 / stream_messages / 纯文本回退)
▼
IM 客户端
| 模块 | 职责 |
|---|---|
im-gateway.ts |
核心服务 ImGatewayService:会话管理、消息路由、工具注册 |
events.ts |
EventDispatcher:SessionEvent → IM 渠道操作(流式、分片、工具提示) |
session-title.ts |
prefixSessionTitle:给 IM 会话标题加 [机器人名] 前缀(走官方 sessionTitle.rename) |
commands.ts |
CommandHandler:斜杠命令处理(/help /reset /model /status /stop /sessions /continue /workspaces /workspace) |
stream.ts |
StreamThrottle:流式节流器,攒批 text-delta 后按间隔推送 |
approval.ts |
ApprovalBroker:工具审批桥,挂起 approval/request 等待 IM 回复 |
questions.ts |
QuestionBroker:交互提问桥,挂起 ask_user_question 等待 IM 回复 |
split.ts |
splitText:长文本分片,按句号/换行切分,带分段前缀 |
merge.ts |
SessionMerger:多段输入合并,支持 .. / !! 控制后缀 |
i18n.ts |
Translator:中英文双语翻译表 |
instance-lock.ts |
acquireInstanceLock:DSH_HOME 文件锁,防止并发写坏 session log |
types.ts |
接口定义:ImChannelAdapter、ImGatewayConfig、ImGateway 等 |
src/index.ts(apply)、src/gateway/(核心 + 上述模块)、src/channels/(dingtalk / qq / weixin / feishu / wecom + 协议助手)、src/remote.ts(设置页的 Typert RPC)、src/sync.ts(保存配置后热重载通道)。src/client/ — 设置页「IM 通道」(添加/编辑弹窗 + 扫码登录 + 状态点)。channels 是数组,同一 type 可多次出现。第三方可以不 fork 直接注册自己的通道:
import { ImChannelAdapter } from '@lijian-ui/dsh-im-gateway' // peerDependency 引用核心
class MyChannelAdapter implements ImChannelAdapter { /* ... */ }
ctx.imGateway.registerChannel(myAdapter)
ImChannelAdapter 接口可选方法:
| 方法 | 说明 |
|---|---|
sendText(convId, text) |
必需。发送纯文本消息 |
sendMedia(convId, filePath, caption?) |
可选。发送文件/图片/视频(im_send_file 工具使用) |
beginStream(convId) |
可选。开启流式回复(首个文本增量时调用) |
streamText(convId, text) |
可选。流式覆盖更新(节流推送) |
endStream(convId, fullText) |
可选。结束流式回复(turn/end 时调用) |
updateCard(convId, text) |
可选。遗留单次卡片更新 |
authorizes(userId) |
可选。渠道本地授权检查(返回 false 拦截) |
maxMessageChars |
可选。单条消息字符上限(默认 4000,用于分片) |
label |
可选。渠道显示名称(用于提问回执) |
git clone https://github.com/lijian-ui/dsh-im-gateway.git
cd dsh-im-gateway
npm install
npm run build # tsdown → lib/
npm run watch # 保存自动重编译
npm run typecheck
npm test # node --test tests/*.test.mjs
本地 link 进 dsh profile:
dsh plugin --profile web add ./ # 从本目录安装(link)
Windows 注意:dsh 子进程从
package.json的main加载lib/index.js— 修改src/后必须npm run build再重启 dsh 进程(它的 require 缓存会保留旧模块)。
测试使用 Node.js 内置测试运行器(node:test),位于 tests/ 目录:
| 测试文件 | 覆盖模块 | 测试数 |
|---|---|---|
approval.test.mjs |
ApprovalBroker | 8 |
questions.test.mjs |
QuestionBroker + parseQuestionReply + formatQuestionPrompt | 8 |
split.test.mjs |
splitText | 8 |
merge.test.mjs |
SessionMerger + stripControlSuffix | 9 |
ctx.logger.* 缓存进内存。本插件在 apply 时注册了 console exporter,日志会出现在 dsh 子进程 stderr(桌面壳会加 [dsh] 前缀)。turn/end 无条件收流(0.1.x 已修复)。stream_messages;微信本身没有流式概念)。这是设计行为。maxMessageChars 上限时自动分片,带 (1/3) 前缀。这是设计行为,不是 bug。!! 立即提交,或调大 mergeTimeoutSecs。approvalTimeoutSecs / questionTimeoutSecs。超时后会自动委托回 Web 端。formatAnswerSummary 中的分隔符(、 ;)和 (空) 目前固定中文,因为它们是格式符号而非自然语言。MIT © lijian-ui
为 DeepSeek Harness 构建 — 独立插件,与 DeepSeek 无隶属或背书关系。
CLASSIFICATION EVIDENCE
系统优先读取 GitHub Topics,再与站内分类词典和词根规则比对。当前命中: desktop-app。