dsh-feishu
中文 | English
DeepSeek Harness (dsh) 的飞书 (Lark) 长连接频道插件:把一个 dsh Agent 桥接到飞书机器人,在聊天里直接派任务、收结果、批权限。
零 npm 依赖 —— Node >= 22 内置 WebSocket + 手写 protobuf Frame 编解码(字段号与官方 oapi-sdk-go WS 模块一致),整个插件就是一个 index.js。
特性
- WS 长连接:走飞书官方 WebSocket 回调(
callback/ws/endpoint),无需公网 IP、无需端口映射、无需自建回调服务 - 一个 chat 一个 Agent:每个会话独立上下文,空闲超时自动回收(默认 30 分钟)
- 审批转交互卡片:dsh 的 approval 请求转成飞书卡片按钮(✅ 允许 / ❌ 拒绝),点按钮或回复
y/n均可;处理完原地更新卡片 - 插话转向 (steer):任务运行中直接发消息即插入当前 turn,下一步生效,不打断任务;
/stop才是硬中断 - 模式切换:
/mode切换 agent preset(极简 / 标准 / PTC / 创造),与权限档正交 - 命令桥接:dsh 内置命令(
/permission/plan/compact/goal/export…)全部可用 - 自动重连(onclose 后 5s)、心跳保活、事件 ack(防飞书重推)、resume 后 seq 封位防重发
要求
- Node >= 22(内置 WebSocket;开发用 23)
- 一个可用的 dsh 部署(
npx @deepseek-ai/dsh) - 一个飞书开放平台应用(企业自建应用即可),开通:
- 事件与回调 → 长连接模式(WebSocket) - 机器人 能力 - 权限:im:message(收发消息)等
安装
npx @deepseek-ai/dsh plugin --profile feishu add /path/to/dsh-feishu凭据不进配置文件,走环境变量(写入 profile 的 .env,或全局 ~/.dsh/.env):
FEISHU_APP_ID=cli_xxxxxxxx
FEISHU_APP_SECRET=xxxxxxxx
# 可选: Agent 工作目录
DSH_FEISHU_CWD=/your/workspace验证组合层并启动:
npx @deepseek-ai/dsh --profile feishu --dump-config # 验证
npx @deepseek-ai/dsh --profile feishu # 启动配置项 (cordis.patch.yml)
| 键 | 默认 | 说明 |
|---|---|---|
appId | 必填 | 飞书 App ID(FEISHU_APP_ID) |
appSecret | 必填 | 飞书 App Secret(FEISHU_APP_SECRET) |
domain | https://open.feishu.cn | API 域名,国际版用 https://open.larksuite.com |
cwd | process.cwd() | Agent 的工作目录 |
allowUsers | [] | open_id 允许列表;空 = 不限制,建议生产环境配置 |
allowChats | [] | chat_id 允许列表;空 = 不限制 |
sessionTimeoutMs | 1800000 | 会话空闲回收时间 |
defaultMode | standard | 新会话默认 agent preset |
modeAliases | 见 patch | 模式别名(默认含中文别名 极简/标准/ptc/创造) |
> 安全提示:allowUsers/allowChats 为空时,任何能跟机器人对话的人都能驱动你的 Agent(在你机器上执行任务)。公开分享前务必配置。
斜杠命令
原生命令(本插件处理)
| 命令 | 参数 | 行为 |
|---|---|---|
/new | — | 销毁当前会话:上下文清空、Agent 释放,下一条消息自动创建全新 Agent。用于有历史会话切换 /mode 后生效,或开始新任务。 |
/mode | — | 列出全部 agent preset(含描述),当前项标 ✅;broken 的 preset 会注明原因(如 code 需要宿主 runtime,基础 bundle 未含)。 |
/mode <preset> | id 或别名 | 切换本 chat 的 agent preset:minimal(极简)/ standard(标准)/ code(ptc)/ cordis(创造)。空白会话 → 立即生效;已有历史的会话 → 记录选择(回 📌),/new 后生效(preset 在 Agent 创建时锁定)。未知名称会列出可用 id。 |
/status | — | 当前模型(provider/model)、模式、chat id、Agent 状态(running/idle)、最近活跃分钟数、空闲回收倒计时、待审批提示。 |
/stop | — | 硬中断当前 turn:取消进行中的工作,并清空未执行的排队输入。无任务时回复 "agent idle"。 |
/help | — | 内置帮助文本。 |
审批应答(非斜杠命令)
有待审批卡片时,裸发 y = 允许、n = 拒绝(大小写不敏感)。点卡片按钮效果相同;两种方式处理后卡片都会原地更新。
桥接的 dsh 命令
其余所有 / 开头的命令都转发给 dsh 命令服务,即内置命令全部可在聊天中使用。常用的:
| 命令 | 行为 |
|---|---|
/permission | 查看当前权限档 |
/permission <preset> | 切换:read-only(文件只读,免审批)/ workspace-write(工作区可写,越权需审批,默认)/ danger-full-access(完整权限,免审批) |
/plan | 计划模式:Agent 先规划、你批准后再执行 |
/compact | 压缩会话历史,回收上下文 |
/goal | 设置/查看长任务目标 |
/export | 导出会话日志 |
/feedback | 记录反馈 |
未知命令会回复全部可用命令列表。
普通消息(无斜杠)
- 任务运行中 → 消息被 steer 插入当前 turn:回
📌确认,下一步生效,任务不中断;要彻底打断用/stop。 - Agent 空闲 → 正常开启新 turn。
群聊中需 @机器人 触发以上任意操作。
开发
node test.mjs # 离线单测: protobuf 编解码 roundtrip + Config 校验
node debug.mjs # 调试帧编码字节test.mjs 从 index.js 提取纯函数区块做 roundtrip 测试,无需启动 dsh、无需真实凭据。
协议实现说明
飞书 WS 长连接协议(源自 larksuite/oapi-sdk-go v3 ws 模块):
1. POST /callback/ws/endpoint(body 携带 AppID/AppSecret)换取 WS URL + PingInterval 2. 二进制帧 = protobuf Frame:1=SeqID 2=LogID 3=service 4=method(0控制/1数据) 5=headers 8=payload 3. 心跳:按 PingInterval 发 method=0 + headers[{type:ping}] 4. 数据帧 headers type=event,payload 为事件 JSON(核心 im.message.receive_v1) 5. 收到事件必须 ack(原 headers + biz_rt + {"code":200}),否则飞书会重推
编解码器手写在 index.js 顶部(encodeFrame/decodeFrame),无 protobufjs 依赖。
License
MIT