pi-webhook0.1.3
Configurable, privacy-first webhook notifications for Pi and pi-web
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.
Reports 0
No reports yet.
Readme
Pi Webhook
独立、通用的 Pi / pi-web 通知扩展,接收端实现 HTTP JSON POST 即可。没有运行时第三方依赖,不启动 HTTP 服务,不提供远程执行或审批能力。
安装
需要 Node.js >= 22.18,Pi 提供 agent_settled、agent_before_settle、ui_prompt_start/end 事件(已使用 Pi 1.5.0 类型和生命周期验证)。
pi install npm:pi-webhook
在已有会话执行 /reload,或重启会话。使用同一个 Pi agent 配置目录的 Pi CLI 和 pi-web 共用安装与配置。若 pi-web 使用另一用户或 PI_CODING_AGENT_DIR,需在对应环境安装;远程 pi-web 的 localhost 指向服务器,不是浏览器所在电脑。
使用 pi remove npm:pi-webhook 可移除安装,通知配置需按需自行删除。也可通过 pi install git:github.com/YHQY-Dev/pi-webhook 安装 GitHub 版本(不要同时安装两份)。开发时可使用 pi install /absolute/path/to/pi-webhook 安装本地目录,安装后不要移动或删除该目录。
默认目标 http://127.0.0.1:24527/ 是接收端地址,不是扩展监听端口。 缺少配置文件时使用内置默认配置并开始发送;接收端没启动会有限重试,失败仅计数,不弹窗、不阻塞 Agent。接收端需实现下文定义的通用 JSON 协议。
配置和命令
全局配置:~/.pi/agent/webhook.json;设置 PI_CODING_AGENT_DIR 后使用该目录下的 webhook.json。不加载项目配置,避免不可信仓库改变外发目标。初次可使用 /webhook config 保存配置,或复制 config.example.json 到上述位置。
| 命令 | 作用 |
|---|---|
/webhook 或 /webhook status |
显示启用状态、订阅、成功/失败/待发/丢弃/过期计数及配置路径,不显示 URL 或鉴权信息 |
/webhook config |
编辑完整 JSON;保存前校验,取消不保存 |
/webhook on / /webhook off |
持久化启用/禁用 |
/webhook events default completed,error,waiting |
设置指定接收端的事件列表 |
/webhook events default none |
清空该接收端事件列表 |
/webhook test [接收端名称] |
给启用的接收端发送 test 事件,显示 HTTP 结果;不受事件订阅过滤,最长等待约 10 秒 |
/webhook reload |
重新读取配置 |
命令反馈通过 Pi UI 输出;配置编辑使用标准 editor UI,可由支持它的 RPC 客户端(包括 pi-web)展示。json/print 等无 UI 模式请直接编辑配置文件。配置编辑器不会触发自身的等待通知。
每个会话独立读取配置。保存只更新当前会话,其他会话执行 /webhook reload 或重启。无效配置在加载时停止发送,不静默回退到旧目标;无效编辑不会覆盖文件。禁用只阻止后续入队,已入队请求仍可能送达。配置不覆盖 Pi 的 settings.json 或其他扩展。
可订阅事件
| 事件 | 默认订阅 | 含义 |
|---|---|---|
completed |
是 | 整次运行真正结束,不再自动重试、压缩续跑或处理队列 |
error |
是 | 最终以错误结束;恢复成功的临时错误不会误报 |
waiting |
是 | 扩展 UI 开始阻塞等待用户(select / confirm / input / editor / custom) |
resumed |
否 | UI 等待结束;不表示批准,也不保证 Agent 开始运行 |
started |
否 | 一次完整运行开始;自动续跑不重复发送 |
cancelled |
否 | 用户取消或运行中止,不再发送 completed |
tool_error |
否 | 单个工具失败,不等于整次任务失败 |
session_started |
否 | 会话加载,也可能来自切换或扩展重载 |
session_closed |
否 | 会话退出、切换或扩展重载,尽力发送 |
waiting 只表示 Pi 真实发出的 UI 等待事件,不分析普通文本中的问句;没有调用阻塞 UI 的权限插件、普通助手提问、浏览器断连不一定产生这个事件。不通过 Webhook 接收用户的批准响应。
多目标与鉴权
{
"enabled": true,
"timeoutMs": 3000,
"retries": 2,
"webhooks": [
{
"name": "local",
"url": "http://127.0.0.1:24527/",
"enabled": true,
"events": ["completed", "error", "waiting", "resumed"],
"headers": {},
"includeMessage": false,
"includeCwd": false
},
{
"name": "service",
"url": "https://example.com/pi-events",
"events": ["error"],
"headers": { "Authorization": "Bearer ${PI_WEBHOOK_TOKEN}" }
}
]
}
请求头中的 ${ENV_NAME} 在发送时从 Pi 服务进程环境读取;变量缺失则该目标发送失败。不要把令牌直接放进 URL。支持本机/内网 HTTP 与 HTTPS;跨机器建议 HTTPS + Authorization。禁止重定向,避免把敏感头转发到其他地址。服务应自行鉴权,不要在公网裸露无鉴权接收端。
配置严格校验未知字段。最多 16 个目标;名字唯一,只含字母、数字、_、.、-,最长 64 字符。timeoutMs 为 100–30000;retries 为 0–5。enabled 默认 true;两个 include 选项默认 false。webhooks: [] 合法,不发送任何通知。
HTTP 协议 v1
POST / HTTP/1.1
Content-Type: application/json
X-Pi-Event-Id: <UUID>
X-Pi-Event-Type: completed
{
"schemaVersion": 1,
"id": "a-unique-event-uuid",
"type": "completed",
"timestamp": "2026-11-06T00:00:00.000Z",
"source": "pi",
"session": {
"id": "pi-session-id",
"name": "修复登录问题",
"navigation": { "kind": "web", "url": "http://127.0.0.1:30141/?session=pi-session-id" }
},
"data": { "runId": "a-run-uuid", "durationMs": 1234 }
}
session.id区分同一个 pi-web 进程下的多会话;不要用 PID 识别会话。session.name优先使用发送时读取的正式会话名称;没有名称时,直接读取当前会话分支的首条用户消息文本作为兜底标题,不调用模型生成摘要。兜底标题合并空白后最多取 30 格(中文/全角/emoji 算 2 格,英文/数字/半角算 1 格),超出追加…,不拆开 emoji 或组合字符;正式名称不截断。两者都没有时省略名称,由接收端显示未命名。名称或首条消息的标题片段属于默认发送的会话元数据,不受includeMessage控制,其中的敏感信息也会发送;自动生成的正式名称可能晚于完成事件。session.navigation提供尽力跳转信息:扩展启动或/webhook reload时读取<agentDir>/pi-web-run/*.json,只有nextPid与当前进程匹配才使用该实例 URL,构造?session=<id>会话链接;不修改 pi-web。未匹配(含记录缺失/损坏/自定义启动)时按终端尝试,发送{ "kind": "terminal", "pid": 1234 }。PID 指向 Pi 进程,仅供同机接收端捕获父进程链,不代表有可聚焦窗口,更不能精准选择终端标签页。- 网页跳转地址为服务器本机运行记录里的地址,不保证适用于远程接收端、反向代理或自定义部署;浏览器打开链接也不保证复用已有标签页。元数据不包含登录凭据。
- 运行相关事件包含
data.runId,方便关联 started / waiting / completed;非运行中事件可不包含。 - completed / error / cancelled 包含
durationMs;waiting 包含reason: "ui_prompt"、kind;tool_error 包含toolName、toolCallId。 includeCwd: true时额外发送session.cwd;includeMessage: true时最终运行通知可附带data.message,内容为最后一条助手回复的纯文本(最多 2000 字符)。不保证错误时有回复正文。- 默认不发送完整提示词、回复正文、思考、工具参数/结果、错误堆栈、会话文件路径、阻塞交互框标题(会话名称、首条用户消息的兜底标题片段与跳转元数据除外)。开启正文或目录后可能泄露敏感信息,请谨慎配置。
- 自定义头不能覆盖 Content-Type、Host、Content-Length、Connection、Transfer-Encoding 或
X-Pi-*。
这是通用 JSON 协议,不自动转换 Discord / Slack 等专用消息格式;需要相应适配服务。
可靠性边界
每个会话对每个目标维护独立顺序队列(最多 100 个含正在发送的事件,超量丢弃新事件)。不同目标并行;包括配置重载后尚未排空的旧目标,最多同时保留 16 个目标队列。空队列自动释放。Agent 事件处理只入队,不等待网络;只有启用正文且订阅最终运行通知时才读取回复,并最多复制 2000 字符。
网络错误、429、5xx 有限指数退避重试,其他非 2xx 不重试。超时按每次请求计算;事件从入队开始最多存活 30 秒(包含等待、请求和重试),过期队列事件直接丢弃,正在发送的请求也会取消。接收端慢或离线时可能丢通知,而不是无限积压旧状态。原生 Node HTTP(S) 复用 keep-alive 连接,不跟随重定向;响应正文不保存,最多消费 64 KiB 后关闭连接,慢响应体仍受请求超时约束。
同一个事件的重试保持相同 ID,接收端应按 id 去重;由于超时可能发生在接收成功后,可能重复送达。配置保存在事件入队时的快照中。此扩展是内存中的尽力通知,不保证进程崩溃、强制结束、系统休眠期间的送达,不持久化消息;正常关闭最多等待 2 秒再取消剩余请求。status 的成功/失败按目标事件计数,不是 HTTP 尝试次数;丢弃包含超量、过期和关闭时未开始发送的事件,过期是其中的子集。已开始但超时或被取消的发送计入失败。不记录响应正文或凭据。
开发
npm ci
npm run check
npm test
npm run bench -- --long
npm pack --dry-run
压测脚本仅启动随机端口的临时接收端,不读取实际通知配置;--long 增加 30 秒过期/离线积压场景。性能报告 记录基线、优化数据和适用边界。报告是当前工作区结果,不表示所有优化已发布到 npm。
职责划分:src/config.ts 配置/校验/存储;src/http.ts 原生 HTTP(S) 与有界响应消费;src/delivery.ts 协议、隐私裁剪、重试和有界队列;src/navigation.ts 运行实例识别和会话跳转元数据;src/title.ts 会话名称优先级、首条消息标题和显示宽度截断;src/index.ts Pi 生命周期和命令桥接。宿主 SDK 仅作为 peer/dev 依赖,不打包为运行时副本。
许可证
MIT © 2026 YHQY-Dev