主动消息 API 标准:让纯前端项目(小手机类)也能可靠地推定时 / 即时消息。端到端加密、Serverless 部署、三包接入。一个数据库就能持续跑,全程免费。
| 包 | 用途 |
|---|---|
@rei-standard/amsg-shared |
推送 schema(AmsgPush 判别联合 + builders + 类型守卫) |
@rei-standard/amsg-instant |
一次性即时推送(SSE 默认传输、always-on Web Push backup) |
@rei-standard/amsg-server |
定时 / 周期消息,多租户 Blob 配置 + token 鉴权 |
@rei-standard/amsg-client |
浏览器 SDK:加密、请求封装、Push 订阅、deliver() 送达裁决 / SSE consumer |
@rei-standard/amsg-sw |
Service Worker:推送展示、离线队列、delivery dedupe |
amsg-shared 是依赖图最底层:其他四个包都依赖它,反过来不行;它本身零运行时依赖。
怎么挑服务端包:只发"按钮点了就立刻推一条" → amsg-instant;要定时或周期任务 → amsg-server;两种都要就都装,共用同一套 VAPID 与 masterKey。
版本号、CHANGELOG 与发布由 Changesets 管理。五个包各自独立版本(不绑成同一个号)。发布流程见 RELEASING.md:写 changeset → 合到 main → CI 开「Version Packages」PR,合并该 PR 即发版。
安装最新版(latest dist-tag):
npm install @rei-standard/amsg-shared @rei-standard/amsg-instant @rei-standard/amsg-server @rei-standard/amsg-sw @rei-standard/amsg-client每条推送用三个互不影响的维度描述:"用什么方式发出去"(dispatch)、"属于哪个业务"(business)、"载荷里装的是什么"(content)。三者拆开,给某一个维度加新值时,另外两个不用动。
| 轴 | 字段 | 取值 | 由谁定 |
|---|---|---|---|
| Dispatch | messageType |
instant / fixed / prompted / auto |
包(固定枚举) |
| Business | messageSubtype |
任意字符串 | 调用方(自由命名) |
| Content | messageKind |
content / reasoning / tool_request / error |
包(固定枚举) |
外加一个 source: 'instant' | 'scheduled' —— 路由来源(instant 来自 amsg-instant,scheduled 来自 amsg-server 的任何输出)。
messageKind 四种值(载荷里到底是什么):
content—— 最终面向用户的文本片段。携带message、可选messageIndex/totalMessages(N 段分句 burst 用)、title、contactName、avatarUrl等。reasoning—— LLM 的思考过程(choices[0].message.reasoning_content)。携带reasoningContent。不带messageIndex/totalMessages,因为推理是一轮 LLM 一条,不是分句 burst。tool_request—— Agentic loop 钩子返回的工具调用请求。携带toolCalls(OpenAItool_calls透传形状),客户端执行后通过/continue恢复。error—— 生产端诊断错误(如HOOK_THREW/LOOP_EXCEEDED)。携带code、message、可选iteration。取代了 0.7.x 那个{ type: 'error', code: '...' }旧信封。
messageType 四种值(怎么发出来的):
instant—— 一次性即时推送(amsg-instant一发即走,无 DB、无 cron)。总是配source: 'instant'。fixed—— 固定文本的定时任务(amsg-server,无 LLM)。prompted—— LLM 生成 + 定时调度(amsg-server的 prompted 路径)。auto—— LLM 生成 + 自动周期(amsg-server的 auto 路径)。
后三种 messageType 总是配 source: 'scheduled'。
messageSubtype 是调用方自有命名空间,框架不解读、不强约束格式(producers 默认填 'chat')。业务侧爱怎么切就怎么切。
sessionId 不变性:同一个 LLM 轮次内自动发出的 ReasoningPush 和后续 ContentPush burst 共享同一个 sessionId;agentic-loop 路径下,同一个 /instant 请求的所有 iteration 也共享一个 sessionId。客户端可以靠 sessionId 把"思考中"UI 和真正回复拼回到同一条消息上。
字段表、builders(buildContentPush / buildReasoningPush / buildToolRequestPush / buildErrorPush)、类型守卫(isContentPush / isReasoningPush / …)与常量(MESSAGE_KIND / MESSAGE_TYPE / PUSH_SOURCE)的完整说明见 packages/rei-standard-amsg/shared/README.md。
- 服务端:按你选的包打开它的 README,里面有环境变量、
createReiServer/createInstantHandler用法、各平台 (Netlify / Vercel / Cloudflare / Node) 的适配器。 - 浏览器:装
amsg-client和amsg-sw,按 Service Worker 规范第 0 章 的最小示例接。
# 服务端选其一(或都装)
npm install @rei-standard/amsg-server
npm install @rei-standard/amsg-instant
# 浏览器
npm install @rei-standard/amsg-client @rei-standard/amsg-sw数据库驱动按 amsg-server README 提示二选一(@neondatabase/serverless 或 pg)。
ReiStandard/
├── standards/ # 权威规范文本(端点、字段、错误码)
├── packages/rei-standard-amsg/ # 5 个发布到 npm 的 SDK 包
│ ├── shared/ # 推送 schema(最底层,其他包都依赖)
│ ├── server/ # 定时 / 周期消息(多租户 Blob + token)
│ ├── instant/ # 一次性即时推送(无 DB / 无 cron)
│ ├── client/ # 浏览器 SDK(加密、请求封装、Push 订阅)
│ └── sw/ # Service Worker(推送展示、离线队列)
├── examples/ # 手动接入示例(不用 SDK 包时的备用路径)
└── docs/ # 本地测试、生产监控
- API 技术规范 — 端点、字段、错误码、鉴权
- Service Worker 规范 — SW 行为、消息协议、兼容性
- 手动接入示例 — 不用 SDK 包的备用路径(滞后于最新 SDK 字段,新接入请用包)
- 本地测试 · 生产监控
本仓库是技术标准仓库。字段名、端点路径、数据结构、错误代码一旦定下来,除非修 bug 或经过评审,不应随意更改。发现问题请提 Issue 或在群里讨论。
CC BY-NC-SA 4.0(署名 - 非商业 - 相同方式共享)。
本标准基于 Whale 小手机、糯米机 的主动消息实现经验。特别感谢:汤圆、脆脆机、koko、糯米机、33 小手机、Raven、toufu、菲洛图等老师的小手机项目的积极参与和支持。