kriskwok/dsh-feishu-gateway
DeepSeek Harness Feishu gateway plugin: chat with your DSH agent from Feishu (persistent sessions, /new, Markdown replies, proactive push)
これは DeepSeek Harness(DSH)プラグインです。当サイトは GitHub README、インストール情報、メンテナンス状況、公開セキュリティシグナルをまとめています。
dsh-feishu-gateway
English | 中文
在飞书(Feishu/Lark)里与你的 DeepSeek Harness(DSH) agent 对话。
这是一个 DSH 插件 bundle:挂载飞书长连接监听器,每条飞书消息路由到稳定的 DSH 会话
(通过 agents 服务的 resume 恢复,多轮对话保持在同一个会话),agent 的答复以
Markdown 富文本(post 消息的 md 标签)回复。支持 /new 开启全新会话、
原生 Typing 表情处理中指示、长任务的流式进度卡片、权限审批与
ask_user_question 的点击即答卡片、以及主动推送。
功能
- 💬 完整对话 — 飞书私聊 / 群聊 @机器人 → DSH agent → 回复
- 🔁 会话保持 — 每个飞书会话对应一个 DSH 会话(
agents.resume/agents.create); 发/new(或"另起会话 / 新会话 / 重新开始 / 换个话题")开启全新会话 - ⌨️ 原生 Typing 指示 — 处理期间机器人在你的消息上加一个
Typing表情回复 (同 hermes-agent 的飞书网关), 回答未结束就一直显示,失败时换成CrossMark。默认不再发"思考中…"提示语。 - 🎞 流式汇报 — 长任务持续汇报:一张实时交互卡片流式显示 agent 的
思考、工具调用、回答草稿(
reporting.mode: 'stream',默认开启); 设为reporting.mode: 'final'则只显示最终结果。 - 🃏 点击即答卡片 — 权限审批(
approval/request,如沙箱提权)与模型的ask_user_question工具会渲染成飞书交互卡片:点 ✅ 允许一次 / 🚫 拒绝 或选项按钮即可作答。点击后回调响应会瞬间把卡片替换为已处理态 (按钮移除、显示结果)并弹出 toast 确认。 - ✍️ Markdown 回复 — 用普通富文本(post)消息的
md标签:粗体、行内代码、 列表、链接原生渲染,无需卡片 - 🤖 完整 agent 能力 — DSH agent 自带模型与工具(bash、文件、子代理…),完全自主
- 📨 主动推送 — 可选管理 HTTP API(
/api/push),随时向用户/群推送文本、Markdown、卡片 - 🔌 无需公网 — 飞书长连接,不需要回调地址
- 🗂 持久化 — 飞书↔DSH 会话映射重启不丢
环境要求
- 已安装并构建的 DeepSeek Harness(
dshCLI),并配置好DEEPSEEK_API_KEY(agent 直接使用 DSH 当前模型,无需另配) - 一个飞书开放平台企业自建应用,已开启机器人能力(见下)
飞书应用配置
- 飞书开放平台 → 创建企业自建应用。
- 开启机器人能力。
- 开通权限:
im:message、im:message:send_as_bot(如需读取消息内容再加im:message:send_as_bot:readonly),然后创建版本并发布。 - 事件与回调 → 选择使用长连接接收事件,订阅
im.message.receive_v1(无需公网)。 审批/问答卡片的按钮点击(card.action.trigger)也走同一条长连接,无需回调地址。 - 在飞书客户端搜索应用名,添加机器人为联系人。
Typing表情与卡片按钮依赖机器人在会话内有消息交互权限(im:message)。 若表情接口被拒,网关会自动退回发送hintText提示语。
安装(作为 DSH 插件)
前提:本包已发布到 npm,且 dsh 命令可用。
推荐把网关挂载到 web profile:与 DSH Web UI 同进程运行,启动 Web UI 即同时启动飞书网关,两者共用同一个 DSH agent。也可以用独立 profile 运行 (见文末「备选」)。
方式一(推荐):挂载到 web profile
web profile 是 DSH 的默认图形界面 profile(dsh --profile web)。
- 编辑
~/.dsh/profiles/web/package.json,加入依赖与 bundle:
{
"name": "dsh-profile-web",
"private": true,
"dependencies": {
"@kriskwok/dsh-feishu-gateway": "^0.2.0"
},
"dsh": {
"profile": {
"bundles": [
"@deepseek-ai/dsh-base",
"@deepseek-ai/dsh-web-app",
"@kriskwok/dsh-feishu-gateway"
]
}
}
}
- 在 web profile 目录安装依赖:
cd ~/.dsh/profiles/web && pnpm install
- 编辑
~/.dsh/profiles/web/cordis.patch.yml,填入飞书应用凭据:
- id: feishu-gateway
config:
feishu:
appId: cli_xxxxxxxxxxxxxxxx
appSecret: xxxxxxxxxxxxxxxxxxxxxxxx
http:
port: 3100 # 可选管理 API
token: your-token
- 启动(或重启)web profile:
dsh --profile web
也可以直接运行本仓库的一键脚本:
./scripts/create-profile.sh(默认挂载到 web profile;--standalone则创建独立 feishu profile)。
备选:独立 feishu profile
若不想通过 Web UI 使用,可让网关在独立 profile 中运行:
mkdir -p ~/.dsh/profiles/feishu && cd ~/.dsh/profiles/feishu
cat > package.json <<'EOF'
{
"name": "dsh-profile-feishu",
"private": true,
"dependencies": {
"@kriskwok/dsh-feishu-gateway": "^0.2.0"
},
"dsh": {
"profile": {
"bundles": ["@deepseek-ai/dsh-base", "@kriskwok/dsh-feishu-gateway"]
}
}
}
EOF
cat > pnpm-workspace.yaml <<'EOF'
packages:
- .
nodeLinker: hoisted
autoInstallPeers: false
EOF
pnpm install
# 再创建 ~/.dsh/profiles/feishu/cordis.patch.yml 填入应用凭据
dsh --profile feishu
配置项
所有配置都在 feishu-gateway 命名空间下(profile patch 行或 ~/.dsh/settings.yaml):
| 字段 | 默认 | 说明 |
|---|---|---|
feishu.appId | — | 飞书应用 App ID(必填) |
feishu.appSecret | — | 飞书应用 App Secret(必填) |
feishu.domain | feishu | feishu(国内)/ lark(海外) |
feishu.botOpenId | 空 | 可选;@ 识别可自动完成 |
feishu.replyMode | at | 群聊策略:at 仅被 @ 回复 / all 全部回复 |
workspace | ~/Documents/DSH-Workspace | agent 工作目录 |
hintText | 爸爸,我正在努力处理中…… | 兜底"处理中"文案(仅当 Typing 表情被禁用/不可用时) |
reporting.mode | stream | stream=流式进度卡片;final=只显示最终结果 |
reporting.typingReaction | true | 处理中显示原生 Typing 表情 |
reporting.showReasoning | true | 卡片中流式显示模型思考 |
reporting.showToolCalls | true | 卡片中流式显示工具调用 |
reporting.patchIntervalMs | 700 | 卡片刷新最小间隔(毫秒,飞书有限流) |
reporting.maxBodyChars | 900 | 卡片正文最大渲染长度 |
reporting.failureReaction | CrossMark | 失败时(移除 Typing 后)追加的表情 |
reporting.cardTitleStreaming | 🤖 DSH 处理中… | 处理中卡片标题(黄色头)可自定义 |
reporting.cardTitleDone | 🤖 DSH 处理完成 | 完成卡片标题(绿色头)可自定义 |
interactions.approvalCards | true | 权限审批用可点击卡片回答 |
interactions.userQuestionsCards | true | ask_user_question 用可点击卡片回答 |
interactions.approvalCardDispose | update | 审批卡片点击后:update=回调响应瞬间替换为已处理态(按钮移除+结果+toast);recall=撤回卡片消息(失败自动回退 update;注意飞书会在原位显示"撤回了一条消息"占位) |
newSessionPatterns | /new 及中文短语 | 触发另起会话的正则列表 |
sessionsFile | data/dsh-feishu-sessions.json | 会话映射持久化文件 |
http.port | 0 | 管理 API 端口(0=禁用) |
http.token | 空 | 管理 API Bearer Token |
web profile 下的问答卡片:
ask_user_question的作答走唯一的ctx.userQuestionsprovider 槽位。当 Web UI 与网关同进程(推荐部署)时该槽位 归 Web UI,因此ask_user_question在 Web UI 中作答;而权限审批卡片在任何 部署下都从飞书作答。独立 feishu profile 下,ask_user_question与审批都在 飞书卡片中作答。
会话共存与自愈
- 预设编排(有工具!) — 在 preset-roster 部署(如 web profile)下,飞书
agent 会从部署的 agent preset 编排(
meta.agentPreset+ presetmount), 模型因此拿到工具,而不会把工具调用当成纯文本。 - 与 Web UI 共存 — 会话单 owner。当 Web UI 打开某会话后,飞书侧通过
agents.get()接管正在运行的 agent 并驱动同一会话,不再报 "while it is live" / "already exists";两个界面共享同一段对话。 - wedged 会话自愈 — 进程中途死亡留下永久冲突的会话("already exists")时, 网关自动换一个新 session id,并把飞书会话映射重指向它,继续对话。
管理 HTTP API(可选)
设置 http.port 启用。端点:
GET /health— 状态POST /api/push— 主动推送{ "receive_id": "ou_xxx", "receive_id_type": "open_id", "msg_type": "text", "content": "{\"text\":\"hi\"}" }GET /api/sessions— 飞书↔DSH 会话映射概览
开发
pnpm install
pnpm build # tsc → lib/
pnpm test # 离线自测
说明:
@deepseek-ai/*运行时由 DSH 宿主提供;本地类型检查从你的 deepseek-harness 检出目录 symlink(见发布检查清单)。
许可
MIT
セキュリティとインストールエビデンス
このスコアは公開リポジトリメタデータと当サイトに登録されたインストールエビデンスのみに基づくもので、コードセキュリティ監査とは異なります。
公開プラグインカタログから取得し、公開 GitHub リポジトリにリンクしています。
リポジトリは MIT ライセンスを宣言しています。
過去180日以内にコードの更新があります。
再現可能な正確なインストールメタデータはまだ登録されていません。リポジトリの説明に従って手動で確認してください。
確認したパッケージメタデータにインストールライフサイクルスクリプトは宣言されていません。