原始内容
pi-lark-notify
pi 主对话 ⇄ 飞书 双向桥。人在外面,用手机飞书就能远程指挥 pi 连续干活。
pi 完成任务 → 飞书收到通知(含完整回复原文)
→ 你长按通知回复"顺便把测试也跑了"
→ 该 pi 会话自动收到这句话并继续执行
→ 完成后又收到通知 → ……
功能
- 下行通知:主对话每次彻底完成(
agent_settled,自动重试/压缩不算)时,把项目名、完成时间、最后一条回复完整原文推送到飞书私聊或群聊 - 上行回注:监听飞书
im.message.receive_v1事件(WebSocket 长连接,无需公网 webhook),把你的回复通过pi.sendUserMessage注入对应会话继续执行(会话忙时自动排队) - 精确路由:回复某条通知 → 注入发出该通知的会话(按 message_id 匹配,多窗口不串话);直接发消息(非回复)→ 忽略,不注入任何会话
- 天然排除子 agent:subagent / workflow 运行在独立进程,不会触发主会话事件
- 安全边界:只接受指定用户(
userId)的单聊消息,他人给机器人发消息不会触发任何动作 - 多会话协调:跨会话共享状态文件(目录锁保护),
/reload后旧实例残留的事件消费者自动清理 - 单例消费者:pi-web 是单进程多 session,事件流是单例资源(一个 bot、一条连接),因此全局只起一个
lark-cli event consume子进程,各 session 通过subscribe注册回调,事件到达后广播。不再「每 session 一个 consumer」造成进程堆积 - 崩溃自愈:正常退出时 consumer 随最后一个订阅者优雅停止;仅当 pi 进程崩溃、consumer 变成孤儿时,新进程在 session_start 延迟 10 秒扫描本机所有
lark-cli event consume进程并清理
依赖
| 依赖 | 说明 | 安装 |
|---|---|---|
@amaster.ai/pi-lark |
提供 lark-cli 自动安装与凭证初始化 | pi install npm:@amaster.ai/pi-lark |
@larksuite/cli(lark-cli) |
飞书官方 CLI,发消息/事件监听都由它执行 | pi-lark 在会话启动时自动安装到 ~/.lark-cli,无需手动 |
新机器落地(完整步骤)
1. 安装两个包
pi install npm:@amaster.ai/pi-lark
pi install npm:pi-lark-notify
无需手动拷贝
~/.lark-cli:配好 settings.json(下一步)后,首次启动会话时 pi-lark 会自动完成两件事——① 检测不到 lark-cli 时自动npm install到~/.lark-cli(需联网,约十几秒);② 将pi-lark配置写入~/.lark-cli/config.json凭证文件(0600 权限)。
2. 飞书自建应用(可多台机器复用同一个)
在 飞书开放平台 创建企业自建应用,或复用已有的:
- 开启机器人能力(应用能力 → 机器人)
- 开通权限(权限管理):
im:message(获取与发送单聊、群组消息)im:message:send_as_bot(以应用的身份发消息)contact:user.id:readonly(可选,用于通过手机号/邮箱查 open_id)
- 创建版本并发布(版本管理与发布)——权限必须发布后才生效
事件接收走 WebSocket 长连接,不需要在控制台配置事件订阅,也不需要公网回调地址。
3. 配置 ~/.pi/agent/settings.json
{
"pi-lark": {
"appId": "cli_xxx",
"appSecret": "${LARK_APP_SECRET}",
"domain": "feishu"
},
"lark-notify": {
"enabled": true,
"userId": "ou_xxx"
}
}
appSecret支持${ENV_VAR}环境变量语法,避免明文- 复用同一个应用时 appId/appSecret/open_id 全部不变(open_id 是"应用 × 用户"维度,与机器无关),配置可直接照抄
- 不知道自己的 open_id?配好凭证后执行:
lark-cli api POST "/open-apis/contact/v3/users/batch_get_id?user_id_type=open_id" \
--data '{"mobiles":["你的手机号"]}' --as bot
4. 生效与验证
- pi 里执行
/reload(或重启会话) - 随便聊一句 → 对话完成后飞书应收到通知
- 长按通知 → 回复 → 该会话应自动收到
【飞书】...并继续执行,同时飞书收到"✅ 已转达"回执
配置项(lark-notify 一节)
| 键 | 默认 | 说明 |
|---|---|---|
enabled |
true |
总开关(下行 + 上行) |
userId |
— | 私聊接收人 open_id(与 chatId 二选一,优先) |
chatId |
— | 群聊 chat_id(需先把机器人拉进群) |
replyEnabled |
true |
上行回注开关(关闭则只发通知) |
receipt |
true |
转达后回执一条"已转达 ✅" |
全局配置在 ~/.pi/agent/settings.json,项目级可用 <项目>/.pi/settings.json 覆盖(例如不同项目发给不同群)。
注意事项
多机器同时使用
- 回复通知的路由是精确的(按 message_id 匹配),多机并存也安全
- 直接发消息(不回复通知)会被忽略,不注入任何会话。多机场景请养成回复具体通知的习惯
装了 hermes 的机器(可选)
lark-cli 检测到 HERMES_HOME 等环境变量会误判运行环境并报 config bind 错误。本扩展内部的调用已自动清洗环境变量,不受影响;但手动或让 agent 使用 lark 技能时,需要 lark-cli 包装脚本。该脚本在 npm 包中不包含,从 git 仓库获取:
# 从 git 仓库检出后,拷到 PATH 靠前的目录(如 ~/bin)
cp bin/lark-cli bin/lark-cli.cmd ~/bin/ # Windows git-bash + cmd 双版本
# macOS/Linux 只需 cp bin/lark-cli ~/bin/
平台支持
- 理论支持 Windows / macOS / Linux 三平台(lark-cli 依赖
@larksuite/cli声明os: ['darwin', 'linux', 'win32']) - 进程枚举跨平台:Windows 走 PowerShell
Get-CimInstance,macOS/Linux 走ps axww - 验证状态:Windows 已充分验证;macOS/Linux 的主流程(发消息、事件监听)应可用,但孤儿 consumer 自愈逻辑未经实测,若
ps不可用或输出格式异常会静默跳过(不影响主功能,仅失去自愈) - 若你在 macOS/Linux 上遇到问题,欢迎反馈
工作原理(简述)
session_start ─→ getLarkClient()(进程级单例)
│ subscribe(handleEvent)
▼
唯一 `lark-cli event consume` 子进程(NDJSON 事件流,崩溃自动重启,退避 3s→60s)
│ 事件广播给所有订阅者
agent_settled ─→ client.sendMessage() ─→ 记录 通知message_id → 本会话
事件到达 ─→ 过滤(本人/单聊/去重/防过期) ─→ 路由(仅 reply_to 精确匹配,非回复忽略)
─→ 跨会话认领(ClaimDedup 状态文件目录锁) ─→ pi.sendUserMessage(followUp)
session_shutdown ─→ unsubscribe();最后一个订阅者退出时停掉 consumer 进程
- 状态拆分(各自独立文件 + 目录锁,15s 死锁自动破除):
lark-notify-sessions.json— SessionRegistry:崩溃残留 session 条目清理(单例 consumer 后不再追踪 consumerPid)lark-notify-router.json— NotificationRouter:通知 message_id → 会话映射,查回复归属lark-notify-claims.json— ClaimDedup:跨会话事件认领去重,先到先得
- 会话身份:每个扩展实例随机 sid,注入前以 sid 认领事件,杜绝多窗口重复注入
文件结构
pi-lark-notify/
├── package.json # pi 包清单(extensions 声明)
├── extensions/
│ └── lark-notify.ts # 扩展本体(单文件,零依赖)
├── bin/ # 仅 git 仓库包含,npm 包不含
│ ├── lark-cli
│ └── lark-cli.cmd
├── LICENSE
└── README.md
卸载
pi remove pi-lark-notify
# 如不再需要 lark 能力:pi remove npm:@amaster.ai/pi-lark
删除 settings.json 中的 pi-lark / lark-notify 两节即可彻底清理。