Skip to content

dsh-lark-bot

Verified

@tigersheep/dsh-lark-bot · v0.1.4 · MIT

DeepSeek Harness 飞书机器人插件:每个飞书聊天对应一个真实 DSH agent 会话(工具/skill/多轮),收到消息贴表情确认并自动回复,工具授权走飞书交互卡片;支持白名单/触发规则/权限档位与连接开关。

Install

dsh plugin add @tigersheep/dsh-lark-bot

Confirm the layer applied with dsh --profile default --dump-config — see the install guide.

Source

Published to npm without a public repository. Inspect the package contents before installing.

Tags

Creators

Readme

lark-bot —— 飞书机器人 DeepSeek Harness 插件(会话驱动版)

把飞书(Feishu/Lark)接入 DeepSeek Harness:每个飞书聊天对应一个真实的 DSH 会话,收到消息交给该会话的 agent(完整 agent loop:工具 / skill / 持久化), 回复发回飞书。工具需要授权时,发飞书交互卡片让用户点「允许 / 拒绝」。

两种引擎(config.engine)

engine 能力 说明
session(默认) 完整 agent:工具 / skill / 多轮上下文 / 会话持久化 每个飞书聊天 ↔ 一个 DSH 会话,出现在 app 会话列表里;与 app 工具权限一致
llm(回退) 仅大模型纯文本回复 直连 ctx.llm,无工具 / skill;排障或轻量问答用

工作原理

  • 连接方式:复用你本机已登录的 lark-cli(无需再配 appId/appSecret)。
    • 收消息:lark-cli event consume im.message.receive_v1 --as bot(NDJSON 流)
    • 收卡片回调:lark-cli event consume card.action.trigger --as bot(session 引擎)
    • 发回复:lark-cli im +messages-reply --message-id <om_...> ...
    • 发授权卡片:lark-cli im +messages-send --chat-id <oc_...> --msg-type interactive ...
    • 主动推送(定时/提醒):lark-cli im +messages-send --chat-id <oc_...> --markdown ...(无来消息的轮次直接发给聊天)
  • 会话引擎:注入 ctx.sessionController,create 一个会话并 prompt 提交每一轮; 监听 session/event 的 turn/end 读取 agent 的最终回复发回飞书。
  • 授权卡片:注入 approval/request waterfall——仅拦截本插件驱动的会话,发卡片、 等 card.action.trigger 回调,点「允许」→ allowed-once,点「拒绝」/超时 → rejected; 其余会话(如 GUI)原样 next() 交回默认审批 UI,互不影响。
  • 插件形态:纯 ESM 单文件(lark-bot.plugin.mjs),只用 ctx + Node 内置模块, 不 import 任何 @deepseek-ai/*(避免打包版 DSH 的模块单例解析问题)。以可安装 bundle(dsh.bundle)装进 profile,侧边栏 Plugins 页可见、可开关。
飞书消息 ─▶ event consume ─▶ 插件(筛选/去重) ─▶ ensureSession(chat↔session)
                                                      │ sessionController.prompt
                                                      ▼
                                              DSH 真实 agent(工具/skill)
                                                      │ 工具需授权?
                                      ┌───────────────┴───────────────┐
                                      │ 是                             │ 否
                                      ▼                                ▼
                            发飞书授权卡片 ──点允许/拒绝──▶ 继续执行 ─▶ turn/end
                            (card.action.trigger)                      │
飞书用户 ◀──── +messages-reply ◀──────── 读 assistant/message 文本 ◀────┘

前置条件

  1. 已登录 lark-cli(bot 身份 ready):lark-cli auth status 确认 identities.bot.available = true。若未登录:lark-cli auth login --domain im。
  2. 飞书开发者后台:
    • 开启事件 im.message.receive_v1(收消息)。
    • 开启回调配置(应用 → 事件与回调 → 回调配置),否则 card.action.trigger 卡片按钮点击收不到——授权卡片会一直等到超时按拒绝处理。
    • 添加机器人能力,把机器人拉进要服务的群或允许私聊。
  3. DSH 桌面 App 已能正常聊天(sessionController / llm 可用)。

安装 / 启用

本插件以可安装 bundle 形态交付(package.json 带 dsh.bundle),装进桌面 profile 后 会出现在侧边栏 Plugins 页,可直接开关。

方式 A:从 npm 安装到桌面 App 的 profile(推荐)

桌面 App 的 profile 在 $DSH_HOME/profiles/<name>/(默认 ~/.dsh/profiles/desktop/)。 桌面没把 dsh CLI 放进 PATH,这里用 App 自带的 pnpm/node:

cd ~/.dsh/profiles/desktop
NODE=~/.dsh/dsh-runtimes/dsh-primary-runtime/dependencies/node/bin/node
PNPM=~/.dsh/dsh-runtimes/dsh-primary-runtime/dependencies/pnpm/bin/pnpm.mjs
"$NODE" "$PNPM" add @tigersheep/dsh-lark-bot

然后把 bundle 加入组合:编辑 ~/.dsh/profiles/desktop/package.json,在 dsh.profile.bundles 数组末尾追加 "@tigersheep/dsh-lark-bot"。

若 dsh CLI 在 PATH 中(源码/CLI 用法),一步到位: dsh plugin --profile <name> add @tigersheep/dsh-lark-bot 会自动装依赖并追加 bundle。

重启后:

  • 侧边栏 Plugins 页能看到 @tigersheep/dsh-lark-bot(可开/关)。
  • 设置 → 内置插件 → 插件列表 里显示 lark-bot,状态 active。
  • 聊天里说「开启飞书机器人」即可调用 lark_bot_start;或把 autoStart 设为 true。

⚠️ larkCliPath 必须填绝对路径(在 profile 的 cordis.patch.yml 里按 id lark-bot 覆盖 config)。桌面 App 不继承终端 PATH,直接写 lark-cli 会找不到;用 which lark-cli 查到完整路径填入。

卸载:在侧边栏 Plugins 页移除;或从 dsh.profile.bundles 去掉 "@tigersheep/dsh-lark-bot"。

方式 B:本地源码 / 调试

# 从本地目录或 git 安装
dsh plugin --profile <name> add /path/to/dsh-lark-bot
dsh --profile <name> web

或直接叠加(不装 bundle,仅调试;此时不出现在侧边栏,只在插件列表里): 把 cordis.patch.yml 的插件行 name 改成插件文件的绝对路径后 dsh web --patch /path/to/dsh-lark-bot/cordis.patch.yml。

开 / 关连接

插件注册了 3 个模型可调用工具,你在 DSH 聊天里用自然语言即可触发:

工具 作用
lark_bot_start 开启连接,开始监听飞书消息并自动回复
lark_bot_stop 关闭连接,停止监听
lark_bot_status 查看运行状态、引擎、已处理/已回复数、活跃会话数、待决授权数、最近错误
  • autoStart: true 时,桌面启动加载插件即自动连接。
  • autoStart: false(默认)时,需手动 lark_bot_start。
  • session 引擎开启时会同时起两个 lark-cli 消费者:消息(im.message.receive_v1) 与卡片回调(card.action.trigger)。插件卸载 / 停止时都发 SIGTERM 干净退出。

配置项

全部写在 patch 条目的 config: 下,未写的用内置默认值。

键 默认 说明
larkCliPath lark-cli lark-cli 可执行文件路径;桌面 App 下务必填绝对路径
eventKey im.message.receive_v1 订阅的消息事件
identity bot consume / reply / send 的身份:bot 或 user
autoStart false 加载即连 / 手动开
engine session session=真实会话(工具/skill);llm=直连大模型(纯文本)
cwd '' 会话工作目录;workspacePath 非空时忽略本项
workspacePath '' 工作区目录:会话落在此目录并归入对应分组(侧边栏项目);留空=不分组(落"未分组")
agentPreset '' 指定 agent preset;留空=默认 preset
turnTimeoutMs 180000 单轮等待 agent 完成的超时(ms)
permissionPreset '' 仅飞书会话生效的权限档:''=不改;auto=自动审查(实验);danger-full-access=全放行不弹卡;workspace-write/read-only=标准档
permissionPresetFallback danger-full-access permissionPreset=auto 但 Auto review 实验插件未启用时的回退档
allowList [] 允许的 ou_...(用户) 或 oc_...(群) 白名单;留空=全部放行
respondInP2p true 私聊是否回应
requireMentionInGroup true 群聊是否必须 @机器人 才回应
triggerPrefix '' 非空时消息须以此前缀开头才回应(前缀会被剥离)
allowedMessageTypes ['text','post'] 只处理这些消息类型
approvalCardEnabled true session 引擎下,工具需授权时发飞书卡片让用户确认
approvalTimeoutMs 120000 卡片等待超时(ms);超时按拒绝处理
questionCardEnabled true agent 用 ask_user_question 提多选时发飞书表单卡片让用户选,不弹 app 弹框
questionTimeoutMs 600000 提问卡片等待超时(ms),默认 10 分钟
cardEventKey card.action.trigger 卡片回调事件
provider '' 留空=用 app 默认;需固定时填已注册的 provider 名
model '' 留空=session 沿用 app 默认模型;需固定时填该 provider 支持的 model id
systemPrompt 见默认 仅 llm 引擎用
historyLimit 12 仅 llm 引擎:每会话保留的消息条数
replyFormat markdown 回复格式:text 或 markdown
maxReplyChars 4000 回复截断上限
dedupeCacheSize 500 message_id 去重缓存容量
reactOnReceive true 收到消息先在该消息上贴表情确认(附着在原消息,非单独发表情消息)
reactEmoji OnIt 确认表情的 emoji_type(如 OnIt/THUMBSUP/OK/SMILE)
commandsEnabled true 识别以 / 开头的斜杠命令;见下「斜杠命令」
sessionListEnabled true 允许 /sessions 列出其他会话
approveOtherSessions true 允许拉取式批准其他会话的工具审批(/approvals + /approve//deny);高权限,建议配合 allowList
otherApprovalMode race 其他会话审批的处理方式:race(默认)=飞书与桌面都弹、先到先得(飞书先答时桌面面板可能残留,需手动点掉);feishu=只走飞书、桌面不弹面板(无残留)
otherApprovalTimeoutMs 300000 feishu 模式下等待审批的超时(ms),超时按拒绝
sessionsFile '' chatId→sessionId 映射文件;留空=插件目录 sessions.json(测试/多实例时改它隔离状态)
runtimeSettingsFile '' /set、/mode 的持久化文件;留空=插件目录 runtime-settings.json。该文件里的值覆盖 patch 配置
docMemoryInWorkspace true 插件加载/更新/启动时把通用记忆幂等写入 workspacePath/AGENTS.md:身份性格、行为说明、斜杠命令三个托管块(各带 <!-- dsh-lark-bot:<key>:begin/end --> 标记,可自动更新;已有同主题手写章节则跳过该块)
memoryDocFile AGENTS.md 写入的文件名(相对 workspacePath)
memoryPersona 见默认 身份与性格文本。默认给一份通用人设(不暴露底层模型、幽默/简洁/俏皮);可覆盖成自己的角色,置空则不注入
memoryBehavior 见默认 机器人行为说明文本;留空=不注入该块
debugLog false 设 true 把每步诊断(含消息内容)写入插件目录 lark-bot.log,排查用;默认关闭

自定义身份性格(memoryPersona)

插件默认注入一份通用人设;想换成自己的角色(如给机器人起名/加职责),在 profile 的 cordis.patch.yml(或本包 cordis.patch.yml)里覆盖 memoryPersona,重启后自动写入工作区 AGENTS.md 的托管块:

- id: lark-bot
  config:
    workspacePath: /path/to/your/workspace
    memoryPersona: |
      ## 身份与职责

      - 你是一名**企业数字员工**,自称 **"铁宝"**,协助同事处理各种事情。
      - 对外以铁宝的身份说话;被问到你是谁时,用铁宝的身份回答,而不是暴露底层模型或系统细节。

      ## 性格与说话风格

      - **幽默风趣**:语气轻松,适度玩梗、带点俏皮,让同事觉得亲切。
      - **回答简洁**:直给结论和要点,不啰嗦、不堆砌;能一句说清就不说三句。
      - **俏皮但不越界**:玩笑点到为止,正事准确可靠;涉及数据、结论、操作时以严谨为先,不为搞笑牺牲准确性。

斜杠命令

在飞书里发以 / 开头的消息,机器人不经过模型直接执行(仍受 allowList 约束):

命令 作用
/model 列出各 provider 的可用模型与当前模型
/model <model> 切换到该模型(自动找广告了它的 provider)
/model <provider> <model> 显式按 provider+model 切换
/status 查看飞书聊天↔DSH 会话、引擎、模型、上下文窗口、agent 冷/热、待决授权/提问、连接状态
/sessions 列出其他会话(id 前缀、活/冷、目录、时间;标记本会话)
/approvals 查看其他会话里待你批准的工具操作(拉取式,不主动推送)
/approve <#编号> 批准某条其他会话的待审批操作
/deny <#编号> 拒绝某条其他会话的待审批操作
/settings 查看可运行时修改的设置项与当前值
/set <键> <值> 修改并持久化设置(仅白名单键)
/mode [feishu|race] 查看/切换其他会话审批模式
/compact 压缩上下文(DSH 内置,委托命令系统)
/goal 目标管理(DSH 内置)
/help 命令帮助

除 /model、/status、/help、/sessions、/approvals、/approve、/deny 由插件原生实现外,其余命令委托 DSH 的命令系统执行——要求会话 agent 已激活(发过普通消息即激活;冷会话会提示先发一条消息)。群聊里 @机器人 后接命令也可识别。

运行时设置(可在飞书改,持久化)

部分设置无需重启、直接在飞书改,且持久化到 runtimeSettingsFile(默认插件目录 runtime-settings.json),优先级高于 patch 配置:

键 取值 说明
otherApprovalMode feishu / race 其他会话审批模式(也可用 /mode)
approveOtherSessions true / false 是否允许拉取式跨会话审批
sessionListEnabled true / false 是否允许 /sessions
reactOnReceive true / false 收到消息是否贴表情
reactEmoji 表情名 如 OnIt、THUMBSUP
replyFormat markdown / text 回复格式
commandsEnabled true / false 是否识别斜杠命令

用法:/settings 看当前值,/set <键> <值> 修改(如 /set reactEmoji THUMBSUP、/mode race)。改动立即生效并写入文件,重启后仍保留。要恢复 patch 配置,删掉该文件对应项或删文件后重启。

跨会话审批(拉取式)

默认不主动推送其他会话的审批,而是登记为待决,由你主动查询后发消息批准:

  1. 其他会话(如 app 里的普通会话)有工具需要审批时,插件把它登记为待决;
  2. 你在飞书发 /approvals 看到 #编号 · 工具 · 会话;
  3. 发 /approve #编号 或 /deny #编号 结算;超过 otherApprovalTimeoutMs 未处理按拒绝。

otherApprovalMode 两档:

  • race(默认):飞书与桌面同时弹,先到先得。注意:飞书先答时,桌面那块面板不会自动关(GUI 面板只能靠点击或请求 abort 关闭,Host 无法撤销已转发的请求)——需要手动点掉,这是竞速模式的固有副作用。
  • feishu:桌面不再弹审批面板,只用飞书批。飞书一批就干净收尾,无残留(代价:桌面无法再批这些会话)。

随时可用 /mode feishu / /mode race 在运行时切换(立即生效并持久化)。

⚠️ 这意味着能给机器人发消息的人可以远程批准其他会话的工具执行(可能是命令执行等高危操作)。请务必用 allowList 限定为可信用户。要关闭:approveOtherSessions: false。

行为细节

  • 收到即确认:消息通过筛选后,先用飞书 reactions 在该条消息上贴一个表情 (reactEmoji,默认 OnIt;附着在原消息,不是单独发一条表情消息),再处理。 表情失败不影响正常回复。
  • 卡片状态反馈:授权卡片/提问卡片在用户点击后,用回调 token 调 POST /open-apis/interactive/v1/card/update 把原卡片更新为「已允许/已拒绝/已提交」, 交互控件随之消失(防止重复点击)。(token 30 分钟内有效、最多 2 次更新。)
  • 会话映射:session 引擎下每个 chat_id 对应一个 DSH 会话,映射持久化在插件目录 sessions.json,重启后沿用(会话冷启动由 prompt 自动 resume)。
  • 回复时机:prompt 提交后立即返回;真正的回复在该会话 turn/end 事件时读取 最后一条 assistant/message 文本发回飞书。一轮里 agent 可能先调用工具再回答——只取最终文本。
  • 主动推送(定时/提醒):有些轮次没有对应的飞书消息(如 DSH 定时任务到点注入的 prompt)。 这类 turn/end 若没有待回复的来消息,插件改用 messages-send 把结果主动推送到该会话 绑定的聊天(按 replyFormat 选 text/markdown),不再静默丢弃。详见下节「定时任务 / 提醒」。
  • 多轮/多消息:同一聊天连发多条按 FIFO 排队,逐轮回复,顺序不乱。
  • 去重:按 message_id 去重(缓存最近 dedupeCacheSize 条)。
  • 防自回环:sender_type=bot 的消息一律跳过。
  • 群聊 @:.content 已被 lark-cli 预渲染为纯文本;requireMentionInGroup 看 mentions 是否非空。

定时任务 / 提醒的主动推送

DSH 的定时任务(schedule)到点会把一段 prompt 注入对应会话跑一轮——这类轮次是 "无人发起"的,没有一条可回复的飞书消息。插件会把这类结果主动推送到该会话绑定的 聊天(lark-cli im +messages-send --chat-id <oc_...>,格式随 replyFormat)。

  • 怎么用:直接在飞书里对机器人说需求即可,例如 「每天早上 8:30 给我发一份科技股早报」「20 分钟后提醒我开会」。agent 会调用 schedule_create 把任务绑定到当前聊天对应的会话,到点自动生成并推送到本聊天。
  • 重启不丢:插件启动时会把 sessions.json 里已持久化的会话都纳入"归属", 因此重启后到点的任务仍能被认领并推送。
  • 会话串行:同一会话一次只跑一轮。若到点时该会话正忙,任务会排在当前轮之后执行, 推送会相应晚一点(不是失败)。
  • 务必同会话创建:定时任务绑定的是"创建它时的会话"。若之后 bot 重建了聊天↔会话 映射(sessions.json 变化、换了新会话),旧任务会指向旧会话而收不到推送——此时在 当前会话里重新说一遍需求重建任务即可。
  • 排错:开 debugLog 后,成功打 pushed unsolicited turn,失败打 pushMessage failed; 若看到 turn/end no chat bound for session,说明该会话没有绑定聊天(多半是旧/孤儿会话)。

权限档位(permissionPreset)

飞书会话的工具权限可通过 permissionPreset 选档,只影响飞书会话,不动 GUI:

档位 行为 卡片 适用
''(默认不改) 沿用 app 默认(通常 workspace-write) 工具越界时弹 稳妥,人工把关
auto(实验) 模型逐次评估每个工具调用:判安全→直接执行,判有风险→回退飞书卡片让你确认 仅风险操作弹 少打扰又保底,推荐试用
danger-full-access 所有工具直接执行 永不弹 全自动无人值守(风险最高)
workspace-write / read-only 标准沙箱 + ask 越界时弹 固定某档

关于 auto(自动审查 / Auto review):

  • 这是 DSH 的实验特性,由 dsh-experimental-auto-review 提供。桌面 profile 已带这个 bundle,但默认可能是关闭的——需在侧边栏 Plugins 页把「Auto review」开启,auto 才会出现在可选档里。
  • 若插件配了 permissionPreset: auto 但该实验插件未启用,自动回退到 permissionPresetFallback(默认 danger-full-access),并记在日志里。
  • 它是实验性的:可能放行不安全操作、误拒有用操作、额外消耗 token;被判拒的调用仍会 走飞书卡片让你定夺。重启后每个会话会重新进入 auto(插件在 ensureSession 时重设)。

⚠️ 安全须知

  • 工具权限与 app 一致:session 引擎下机器人就是一个真实 DSH agent,能跑 bash、 读写文件、调用 skill。谁能给机器人发消息,谁就能在你机器上驱动这些能力。
  • 授权卡片是第二道闸:工具触发 ask 审批时会发飞书卡片,必须有人点「允许」才执行; 点「拒绝」或 approvalTimeoutMs 超时都按拒绝。注意:danger-full-access 全放行档不弹卡片; auto 档只有被判有风险的调用才弹。
  • 拦截顺序:本插件用 prepend 把审批拦截器插到最前,所以飞书会话的审批走飞书卡片, GUI 会话仍走 app 面板,互不干扰。
  • 务必收紧触发范围:上线前用 allowList(限定用户/群)、triggerPrefix(限定触发词)、 requireMentionInGroup(群里需 @)把"谁能触发"缩到最小——尤其用 danger-full-access 时。
  • 该连接复用你 lark-cli 的 bot 身份,没有额外鉴权边界;只在可信范围内开启。
  • 回复/卡片经飞书发出会被该会话成员看到,注意不要泄露敏感信息。
  • 想要"只问答、绝不动工具":把 engine 设为 llm。

排错

现象 排查
start 报 启动失败 / ENOENT larkCliPath 路径不对,填 which lark-cli 的绝对路径
连上但不回复 看 status:群聊需 @(或关 requireMentionInGroup);检查 allowList/triggerPrefix/allowedMessageTypes;开 debugLog 看 turn/end 有没有触发
回复失败 / 模型报错 开 debugLog:若 prompt FAILED 多为 model-unavailable,把 provider/model 设成你部署里实际可用的,或留空沿用 app 默认
点卡片按钮没反应 飞书后台回调配置没开;或卡片已超时(approvalTimeoutMs)。确认 card.action.trigger 消费者已就绪(status.running 且日志有"卡片回调 就绪")
工具一直被拒 授权卡片超时=拒绝;或权限模式为 never。检查会话/preset 的权限模式
机器人回复出现在 app 会话列表 正常:session 引擎每个飞书聊天就是一个真实会话
改了配置/装了插件不生效 桌面 App 必须重启;bundle 与补丁只在启动时组合
侧边栏 Plugins 页看不到 确认 dsh.profile.bundles 含 @tigersheep/dsh-lark-bot 且 pnpm install 已链接
插件列表里状态不是 active 多为加载失败;常见是 inject 写法(本版本 cordis 只认数组,不认 {required,optional})
看日志 开 debugLog 看插件目录 lark-bot.log;桌面 App 日志:~/Library/Logs/DeepSeek Harness/

文件清单

  • package.json —— bundle 清单(dsh.bundle,可被 pnpm 安装、侧边栏可见)
  • lark-bot.plugin.mjs —— 插件主体(纯 ESM,inject: ['sessionController','tools','llm'])
  • cordis.patch.yml —— bundle 配置层(按包名 dsh-lark-bot 引用插件行)
  • sessions.json —— 运行时生成:chat_id → sessionId 映射(可删,删后重建新会话)
  • README.md —— 本文档