omp packages

@hwj123weijian/pi-feishu0.12.1

Feishu private-chat and managed-group bridge for Pi

hwj123weijian Published 24 days ago MIT ~2.4K downloads/mo

Untested on omp

This is a pi package. No one has reported whether it works on omp yet. If you try it, add your result below.

Did it work for you?

Result

One report per person. A new report replaces your old one.

Reports 0

No reports yet.

Readme

pi-feishu

一个独立的 Pi 飞书扩展。它通过飞书官方 Node SDK 的 WebSocket 长连接,把飞书私聊和已绑定群聊的文本转发到对应的 Pi 会话,并以持续更新的交互卡片展示 Pi 的回复和执行状态。

设计边界

当前版本聚焦一条可靠的私聊 + 项目群链路:

  • 处理飞书私聊(p2p)文本消息,以及已绑定群聊中的文本消息
  • 首次启动生成一次性绑定码,只允许一个 Owner;绑定码只能在私聊中使用
  • Owner 可以把授权成员加入 allowlist(/allow @成员),授权成员在私聊和已绑定群里与 Owner 权限一致
  • 收到消息后立刻在原消息上添加“思考中”表情作为已读回执,回复送达后自动移除
  • 以 / 开头的消息走远程命令快速通道,不排队、不进入 LLM 上下文
  • 私聊消息进入主 Pi 会话;每个绑定的群聊拥有独立 Pi session,群之间、群与主对话之间不共享上下文
  • 群消息会带上说话人上下文(如 [飞书群聊] 张三:…)再发给 Pi;bot 识别 @ 他人、@ 自己
  • 消息需要排队时发送“排队中(第 N 位)”提示,轮到处理时自动撤回;队列变化时提示自动改写为新位数
  • Owner 在排队中的消息上点 ❌(CrossMark)表情即可取消该消息
  • 未绑定的群里被 @ 时,bot 会回复绑定引导而不是沉默;非授权成员的普通群消息完全不会触发回复
  • Bot 被拉进新群时,会私聊 Owner 发送绑定引导和群聊权限体检结果;启动成功后也会私聊 Owner 发送欢迎语和权限体检
  • Assistant 文本通过 Pi 的 message_update 增量渲染到同一张飞书卡片
  • 工具执行时仅显示安全的状态摘要,不展示参数、命令、文件内容或工具输出
  • SDK 以 500ms / 120 字符节流卡片更新;完成、失败、中止都会收尾卡片,失败原因(脱敏后)会写进回复
  • 消息串行处理(Pi 是单会话进程,跨群并行会互相打断),按飞书 message_id 去重且受理记录落盘(48 小时窗口),重启后飞书重推不会重复执行
  • 长连接由跨会话的全局控制器保管:本地 /new、远程 /new 等会话切换不会断开;/feishu stop、/feishu logout 或 Pi 进程退出时释放
  • 凭据优先从环境变量读取,也可保存到本地凭据文件

支持在飞书私聊中请求创建群聊;扩展会把 Owner 拉入新群、发送欢迎消息,并在绑定群与私聊中协同使用。图片、文件、卡片、语音、多用户并发执行、进程级沙箱仍不支持。Pi 本身仍拥有当前本地进程的权限。

环境要求

  • Node.js 22.19 或更高版本
  • Pi 0.83.0 或兼容版本
  • 一个启用了机器人能力的飞书企业自建应用

飞书后台配置

在飞书开放平台创建企业自建应用,然后完成以下配置:

  1. 在“添加应用能力”中启用机器人。
  2. 在“权限管理”中申请:
    • im:message.p2p_msg:readonly:接收私聊消息
    • im:message.group_at_msg:readonly:接收群内 @机器人 的消息(群聊必需,缺了群里 @bot 会完全没有响应)
    • im:message:send_as_bot:以机器人身份回复
    • im:chat:创建群聊并邀请 Owner、读取群信息
    • im:message:update:持续更新机器人发出的交互卡片
    • application:application:self_manage:启动/建群后读取应用已授权 scope,用于自动提示缺失权限
    • 表情回复相关权限:在原消息上添加/移除“思考中”已读回执
  3. 在“事件与回调”中选择“使用长连接接收事件”。
  4. 添加事件 im.message.receive_v1;建议同时添加 im.chat.member.bot.added_v1(被拉进新群时私聊你发送绑定引导)。
  5. 创建并发布一个应用版本,使权限和事件订阅在企业内生效。

这个扩展不需要公网回调地址,也不需要加密密钥或 Verification Token。若未授予 im:message:update,扩展仍可工作,但会降级为最终文本一次性回复。若未授予表情回复权限,扩展同样可工作,只是原消息上不会出现已读表情。若希望已绑定项目群里无需 @ 机器人即可触发,需要额外申请敏感权限 im:message.group_msg(需人工审核 1-3 天);未开通时请在群里使用 @机器人 你的问题。

安装

在项目目录安装依赖:

cd D:\ai_study\pi-feishu
npm install --ignore-scripts

开发时可以仅为本次启动加载:

pi -e D:\ai_study\pi-feishu

也可以把本地包注册到 Pi:

pi install D:\ai_study\pi-feishu
pi

发布版本可直接从 npm 安装:

pi install npm:@hwj123weijian/pi-feishu
pi

配置与首次绑定

推荐用环境变量提供敏感凭据:

$env:FEISHU_APP_ID = "cli_xxxxxxxxxxxxx"
$env:FEISHU_APP_SECRET = "xxxxxxxxxxxxxxxx"
pi -e D:\ai_study\pi-feishu

进入 Pi 后依次执行:

/feishu setup
/feishu start

start 会在本地 Pi 中显示六位一次性绑定码。若已配置凭据但启动 Pi 后尚未连接,扩展会在会话开始时提示执行 /feishu start;如需 Pi 启动后自动连接,可设置 PI_FEISHU_AUTO_START=1(或 FEISHU_AUTO_START=1)。使用计划作为 Owner 的飞书账号私聊机器人:

/bind 123456

绑定成功后,直接私聊机器人即可驱动当前 Pi 会话。原消息会立刻出现“思考中”表情(已读回执),处理过程中先显示“正在思考”,随后持续更新正文;Pi 调用工具时卡片会显示“正在执行工具”,最终状态变为“已完成”,同时已读表情自动移除。

也支持手动参数:

/feishu setup cli_xxxxxxxxxxxxx xxxxxxxxxxxxxxxx

这种方式可能让 App Secret 出现在终端历史中,因此环境变量更合适。验证成功后,凭据默认保存到:

~/.pi/agent/feishu/credentials.json

文件通过临时文件原子替换写入;在支持 POSIX 权限的平台上会限制为 0600。

命令

命令 作用
/feishu 显示帮助和当前状态
/feishu setup [appId appSecret] 验证并保存飞书应用凭据
/feishu start 建立 WebSocket 长连接并显示绑定码
/feishu stop 停止长连接,保留凭据与 Owner
/feishu status 查看配置、连接、Owner 和队列状态
/feishu logout 停止连接并清除本地凭据和 Owner

环境变量优先于凭据文件。如果环境变量中的 App ID 与已保存的 App ID 不同,旧 Owner 绑定不会被继承。

飞书远程命令

在飞书私聊或已绑定的群里直接发送以下命令,会走高优先级快速通道:不进入消息队列排队,也不会作为提问发给 Pi。

命令 作用
/help 显示远程命令帮助
/new 新建 Pi 会话;在群里发送时重置该群绑定的会话,不影响主会话
/stop 中止当前任务,并跳过队列中剩余消息
/status 查看连接、队列、模型与上下文占用
/compact 压缩当前会话上下文
/thinking 查看思考档位,或切换:`/thinking off
/model 查看当前模型,或模糊匹配切换:/model <模型ID或名称>
/bind (群聊)把当前群绑定到 Pi,创建独立会话;仅 Owner
/allow (仅 Owner)授权成员:/allow @成员;无参数时列出授权列表
/deny (仅 Owner)移除授权:/deny @成员
/allowlist (仅 Owner)查看当前授权成员

在飞书私聊中也可直接说“帮我拉个 XX 群”或“创建飞书群 XX”。机器人会创建群聊、邀请已绑定的 Owner 并发送欢迎消息;建群后会私聊 Owner 做一次权限体检(含免 @ 权限申请链接)。已创建群聊和 session 绑定保存在本地凭据文件中,Pi 重启后仍可继续使用。

群聊使用

  • 绑定已有群:把机器人加进现有项目群后,Owner 在群里发送 /bind 即可绑定;之后该群获得独立 Pi session,与其他群和主对话互不串上下文。机器人被拉进新群时也会私聊 Owner 提醒绑定。
  • 独立群引擎:群消息由独立的 pi -p 子进程处理(不再复用你本地 TUI 的 Pi 会话)——每个群有独立的会话历史(~/.pi/agent/feishu/group-sessions/<chatId>.jsonl),互不串上下文,不同群可以同时对话,也不会打断或依赖你本地终端里正在跑的任务。
  • 绑定项目目录(推荐):发送 /bind /path/to/project 把群锚定到项目目录——群子进程直接在该目录下启动,bot 的读写、bash 都在这个项目里执行;Owner 显式绑定的目录会自动加入 Pi 的项目信任。私聊里说“帮我拉个群 /path/to/project”也可以在建群时一并锚定。
  • 触发方式:默认在群里 @机器人 你的问题。飞书只向 bot 推送 @bot 的群消息;普通消息直接触发需要敏感权限 im:message.group_msg。
  • 授权成员:默认只有 Owner 能使用。Owner 私聊发送 /allow @张三 后,张三即可在私聊和已绑定群里与机器人协作;/deny @张三 撤销。
  • 分寸感:未绑定的群里被 @ 时回复绑定引导;非授权成员被 @ 时回复一次“未授权”;其余群内消息完全静默,不会刷屏。
  • 说话人上下文:群消息发给 Pi 前会加上 [飞书群聊] 说话人: 前缀,@ 其他人会被改写成 @名字,模型知道在和谁对话。
  • 群内 /new:删除该群的会话文件,下一条群消息以全新历史开始。

已知限制:私聊仍驱动本地 TUI 所在的 Pi 进程(与本地终端共享引擎,排队提示如实显示位数;本地繁忙时私聊消息会等待,不会打断你)。同一群里任务运行中继续发消息会排队(群子进程按会话文件串行,保证对话顺序)。远程命令 /model、/thinking、/compact 作用于本地 Pi 进程,对群子进程不生效;群内 /new 用于重置群会话。

与本地使用共存

群聊走独立子进程后与本地使用完全解耦:你在终端 TUI 里跑任何任务都不会被飞书消息打断,也不需要先跑完才能处理群消息。私聊仍在本地 Pi 进程内驱动——本地繁忙时私聊消息会等待(收到提示“本地 Pi 正在执行任务”),超过 15 分钟则取消处理并通知你重发;若在本地 Pi 手动切换过会话,私聊路由的会话控制会过期一次:按提示在本地执行 /feishu status 刷新即可恢复。

群子进程从 PATH 中查找 pi 可执行文件;如不在 PATH 中,可设置 PI_BIN 环境变量指向 pi 的完整路径。

未知命令会返回提示,不会发给 Pi。/model 的候选来自本地 Pi 的 scoped models(未配置时为全部已授权模型);/model 无参数时展示当前模型。注意:任何以 / 开头的消息都会先被当作命令解析,想发给 Pi 的提问请勿以 / 开头。

取消排队中的消息

消息排队期间,Owner 直接在自己的这条消息上点 ❌(CrossMark)表情即可取消:排队提示与已读表情立即清理,消息不会发给 Pi,后面消息的排队提示自动前移。仅 Owner 的取消表情生效,已开工的消息不能取消(用 /stop 中止)。

飞书的“消息撤回”事件未被官方 Node SDK 的 channel 抽象透出(长连接也不允许挂第二条连接分流事件),因此这里以 ❌ 表情作为取消入口,效果等价于撤回后移出队列。

常见问题

setup 或 start 连接失败

检查 App ID 和 App Secret 是否来自同一个应用,并确认应用版本已经发布。setup 会实际建立一次临时 WebSocket 连接来验证凭据,而不只是检查字符串格式。

机器人收不到私聊消息

确认已启用机器人能力、订阅 im.message.receive_v1、接收方式为长连接,并已发布包含这些配置的应用版本。

能收到消息但不能回复

确认已申请并发布 im:message:send_as_bot 权限。

只能收到最终文本,没有流式卡片

确认已申请并发布 im:message:update。卡片初始化或更新失败时,扩展会自动改为最终文本回复,避免用户没有任何反馈。

没有已读表情

确认已申请并发布表情回复相关权限。该权限缺失时扩展自动降级:消息照常收发,只是原消息上不会出现“思考中”表情。

群里 @机器人 没反应

按顺序排查:

  1. 群聊接收权限:确认已申请并发布 im:message.group_at_msg:readonly(缺了这个飞书不会推送任何群消息事件)。
  2. 应用版本:权限变更后需在权限管理页发布新版本才生效。
  3. 群是否绑定:只有扩展创建的群和 /bind 绑定过的群会处理消息。在被 @ 而无响应的群里,让 Owner 发送 /bind;如果连 @ 后的引导都没出现,通常是第 1、2 步的问题。
  4. 被 @ 的是否是机器人本身(@ 错了人不会触发)。
  5. 用 /feishu status 查看缺失 scope 的自检结果。

群里必须 @ 才有响应

飞书默认只向 Bot 推送群内 @bot 消息。若希望绑定群内普通消息也触发,需要额外申请并发布敏感权限 im:message.group_msg。本扩展已关闭 SDK 侧的强制 @ 过滤;权限生效后,已绑定群内普通消息会直接进入 Pi。

远程 /new 提示暂不可用

远程会话切换依赖本地 Pi 提供的命令上下文。先在本地 Pi 执行任意 /feishu 子命令(例如 /feishu status),再从飞书发送 /new。切换完成后长连接自动延续,无需重新执行 /feishu start。

Bot 提示“未授权”

该 Bot 已绑定其他 Owner。若要重新绑定,先在本地 Pi 执行 /feishu logout,再重新 setup、start 和 /bind。

重复消息

飞书事件可能重投。扩展按 message_id 去重,并把受理记录落盘到 ~/.pi/agent/feishu/processed-messages.json(48 小时滚动窗口、上限 5000 条),Pi 重启后飞书重推的旧消息也不会再次驱动 Pi。

开发

npm run check
npm test
npm run build

测试使用 Fake Gateway 和 Fake Agent,不需要真实飞书凭据,覆盖凭据处理、Owner 绑定、私聊过滤、串行队列、排队提示改位与撤回、❌ 取消、/stop 按条跳过、去重(含落盘恢复)、已读表情回执、远程命令快速通道、群绑定(/bind)与未托管群引导、allowlist 授权与撤销、群聊说话人上下文注入、mention 元数据透传、botAdded 引导、思考档位与模型切换、Pi 增量文本、工具状态、流式卡片收尾、降级、错误脱敏和清理行为。

许可证

MIT