dsh-dingtalk-self
Replies to DingTalk direct messages as your own account — reads the bound DSH workspace, writes the answer, and sends it back through the dws CLI.
Install
dsh plugin --profile web add dsh-dingtalk-self
Sandbox test
This plugin has not been tested yet. Submit a test →
README
dsh-dingtalk-self
English TL;DR — A DeepSeek Harness (dsh) plugin that answers DingTalk direct messages as your own account. It watches the chats you pick, asks the agent (bound to a DSH workspace) to look the answer up, and sends it back through thedwsCLI with an opt-out marker line. No bot account, no forwarded questions. Requires macOS +dws auth login; replies are Markdown, and tables/charts/flow diagrams can be rendered to PNG by the host.
DSH 插件:钉钉代答。别人在钉钉问你,agent 自己去你绑定的工作区里查资料,然后以你本人身份直接答复对方——
你不用把问题转发给 agent,对方收到的也是「你」发的普通消息,不是机器人、不是数字员工账号。
它和普通钉钉插件的区别
· 机器人 / 自建应用插件 · 本插件
发送身份 · 机器人 · 你本人
读取范围 · 机器人被拉进的群 · 你的私聊
AI 角标 · 有 · 关闭(--ai-tag=false)
回复内容来源 · 插件自带 prompt · 你绑定的 DSH 工作区
权限 · 插件的权限 · 工作区只读(仅可查看)
链路:
对方私聊你 ↓ dws chat message list --open-dingtalk-id (以你身份读) 过滤 / 去重 / 合并 ↓ 投递到绑定的 DSH 工作区(仅可查看) 生成回复 ↓ 出站护栏(禁代码 / 禁路径 / 禁内网地址) dws chat message send --ai-tag=false --idempotency-key ↓ 对方看到「你」发的普通消息
安装
# 1. 装进你的 profile(路径改成你的实际目录;日常用桌面版就是 desktop) dsh plugin --profile desktop add ~/projects/dsh-dingtalk-self # 2. 重启 DSH App,然后刷新页面 # 3. 打开 设置 → 钉钉代答(设置侧栏里,order=45)
装好后检查两处(缺一不可):
python3 -c "import json;d=json.load(open('$HOME/.dsh/profiles/desktop/package.json'));print('deps:', 'dsh-dingtalk-self' in d['dependencies'], 'bundles:', 'dsh-dingtalk-self' in d['dsh']['profile']['bundles'])"
cat ~/.dsh/data/dsh-dingtalk-self/boot.log # 应有一行 version=0.2.0 ... schema=yes
- 客户端半边(设置页)由
package.json的dsh.client声明,普通 JS、无需构建;
重装/改代码后必须重启 App 才会重新装配(实测 Host 侧改代码不会热重载插件)。
卸载:
dsh plugin --profile web remove dsh-dingtalk-self
dsh 不在 PATH 时用全路径:
/Applications/DeepSeek\ Harness.app/Contents/Resources/runtime/cli/bin/dsh
前置条件(缺一不可)
1. dws 已安装(dws --version 有输出)
2. 已完成个人 OAuth 登录:
dws auth login # 扫码授权 dws auth status # 应返回 "authenticated": true
⚠️ dws auth login 必须在你自己的终端里执行 —— 在 Agent 沙箱里跑会因无法写 ~/.dws 而 EPERM。
3. 有一个可绑定的 DSH 工作区(侧栏里那个,例如 my-workspace)
设置页(client 半边)
设置 → 钉钉代答 一页完成全部操作,不需要手改配置文件:
区块 · 内容
运行状态 · dws 登录态 / 本人 userId、急停开关、立即检查一次、上次检查(读了几条 / 新私聊几条 / 出了什么)、重新诊断、刷新、版本、配置来源、计数
监听分组 · 一个工作区挂多位联系人:每组一张卡 = 工作区下拉 + 成员列表(从钉钉通讯录搜索选人,姓名/ID 只读)+ 组级「允许真实发送」。每位联系人使用独立会话,互不串上下文
行为设置 · 总开关、三档模式、轮询间隔、每小时上限、回复字数上限、静默时段
模拟回答 · 粘贴一条对方可能发来的消息,走真实生成通道跑一遍但不发送,看它会怎么答(可能耗时 1–3 分钟)
待确认草稿 · 每条可「发送」/「丢弃」
最近草稿 / 最近审计 · 新的在前,用于回看为什么回/为什么没回
自检 · 一键六项:Node、状态目录、dws 可执行、个人身份登录、工作区、联系人绑定
数据通道(契约见 [docs/client-host-api.md](docs/client-host-api.md)):客户端不直连宿主服务,
而是访问插件自己注册的五个同源 HTTP 端点:
GET /dsh-dingtalk-self/api/state
POST /dsh-dingtalk-self/api/config { patch }
POST /dsh-dingtalk-self/api/pause { paused }
POST /dsh-dingtalk-self/api/confirm { contact, action }
POST /dsh-dingtalk-self/api/diagnose
POST /dsh-dingtalk-self/api/contacts/search { query }
POST /dsh-dingtalk-self/api/cycle {} // 立即检查一次
POST /dsh-dingtalk-self/api/test-reply { message } // 模拟回答,不发送
配置存放位置(当前 DSH 版本):本机 settings 服务没有 register,describe() 也不返回插件条目,
所以配置落在 ~/.dsh/data/dsh-dingtalk-self/config.json,设置页里「配置来源」会显示这一点。
宿主若提供可写的 settings.update,代码会优先走 DSH 原生 settings(响应里的 configSource: "settings")。
配置
设置页里的字段与含义(同一份 schema 也是 lib/settings.js 里的 Config):
字段 · 默认 · 说明
enabled · false · 总开关,默认关
mode · draft · draft 只出草稿 / confirm 等人工确认 / auto 直接发
selfUserId · 空 · 你的 userId,用于过滤自己发的消息
contacts[] · [] · 监控名单,空 = 什么都不做
contacts[].name · — · 联系人名,用于日志与会话标题
contacts[].openDingTalkId · — · 对方 ID(设置页从通讯录选人时自动带入,发送时免反查)
contacts[].workspaceId · — · 绑定到哪个 DSH 工作区(存工作区 id,界面显示标题;同一个人一个条目,同一工作区多人 = 多条 workspaceId 相同的联系人)
contacts[].autoReply · false · 是否允许真实发送
contacts[].sessionId · 空 · 指定要接管的会话;留空时由插件在首次生成后自动记录(state.sessions),每人的上下文互相隔离
pollIntervalSeconds · 60 · 轮询间隔(≥10)
initialLookbackSeconds · 900 · 首次启用(还没有游标)时回看多久的私聊;之后只看 overlapSeconds
mergeWindowSeconds · 20 · 连发合并窗口
quietHours · 关 · 静默时段,命中转草稿
limits.maxRepliesPerHour · 10 · 每人每小时上限
limits.minSecondsBetweenReplies · 30 · 两条之间最小间隔
limits.maxReplyChars · 1200 · 回复长度上限;超过会被截断并在末尾加「…」
replyFormat · markdown · 回复格式:markdown(钉钉渲染加粗/列表/小标题)/ text(纯文本 • 列表)
replyMarker · (本条由助手代答) · 出站标识:附在每条发出去的消息末尾,让对方知道不是本人手打;留空则不加
guard.* · 全开 · 出站护栏开关与禁用词
agent.kind · headless · headless(默认,已验证)/ session(宿主内,待适配)
agent.provider / agent.model · 空 · 生成回复用的模型;留空 = 跟随 DSH 当前默认模型(设置页可下拉选择)
agent.reasoningEffort · 空 · 推理档位(low/medium/high/max),留空用模型默认
agent.readOnly · true · 只读:生成回复时只在工作区查资料,不改文件(子进程注入 DSH_PERMISSION_MODE=read-only)
agent.profile · headless · headless 用的 profile
agent.persona · 简洁自然 · 口吻补充说明
agent.timeoutSeconds · 240 · 单次生成超时(秒)。查资料型回答通常要 1–2 分钟,别调太小
开起来的最小步骤:enabled=true → 加一条 contacts → mode=draft → 先看草稿。
回复排版(Markdown 优先)
dws chat message send 的默认消息类型就是纯文本 / Markdown,钉钉客户端会渲染加粗、列表、小标题,所以默认按 Markdown 发。
config.replyFormat 可选 markdown(默认)/ text,两层处理:
层 · 做法
提示词 · markdown 模式:先一句结论 → ### 小标题分组 → - 列表、关键名词 加粗;text 模式:结论 + • 要点
出站整理 · lib/core/format.js:markdown 模式只归一化(标题统一 ###、列表统一 - 、1)→1.、压缩空行);text 模式才去记号、• 列表、长段落按句折行
实测同一个接口问题的输出(markdown 模式,钉钉会渲染成加粗/列表/小标题):
APP 端提交工单的接口,写入工单主表并推进状态。 ### 主要作用 - 接收 APP 提交的工单,写入 **work_order** - 含工单号、客户信息、处理意见与附件 - 按入参把工单状态推进到 **DONE** ### 顺带做的事 - 把联系人回写到对应主体 - 生成一条待发通知记录 - 异步重新生成这张工单的 **PDF** ### 几个规则 - 按租户配置 **SIGN_MODE** 校验附件:**1** 电子签、**2** 纸质签、**3** 双要求 - 附件不齐不报错:先保存,状态不动,提示待补齐 - 同一工单重复调用只补录,一单只留 **1** 条记录 注意:通知只写待发记录,状态为未发,本接口不同步 …(truncated)
Rendered from the README published on npm. Formatted only, not edited.
Versions
Published on npm::2,最后更新 2026-10-30