backend/openapi/beeos-platform-v1.yaml)以及从中生成的 SDK
(TypeScript 的 @beeos-ai/sdk、Go 的
github.com/beeos-ai/sdk-go)所有值得注意的变更都记录在本文件。
本文件是规范变更日志:
- 终端用户升级 SDK 版本时看的是它,
- 发布工作流打 tag 时查的也是它(SDK 生成器在
sdks/openapi-sdk/generate.sh里盖版本戳)。
backend/docs/adr/
下的 ADR。
格式基于
Keep a Changelog,
契约版本号遵循
Semantic Versioning。
版本号策略
| Bump | 触发条件 |
|---|---|
| MAJOR | 移除路由、改必填字段名、改已有响应形状、改鉴权语义(例如收紧所有权模型)、改 error code 语义。 |
| MINOR | 加新路由、加可选请求字段、加可选响应字段、加新 code 值。 |
| PATCH | 文档、示例、OpenAPI description 打磨、不影响生成代码的 generator 配置调整。 |
发布流程 —— 一个版本怎么真正发出去
- 改 spec。 所有 wire 变更先落在
backend/openapi/beeos-platform-v1.yaml。 openapi-gateway 服务通过go:embed消费此文件,所以backend/services/openapi-gateway下go build就是第一道 lint。 - 同步 vendor 副本。 在
sdks/openapi-sdk/下: - 更新 generator 版本戳。 同一个 commit 里把
sdks/openapi-sdk/generate.sh88-95 行的npmVersion=和packageVersion=一起升上去。两个 SDK 共享版本号。 - 写下面的条目。 在
[Unreleased]块顶部加新段;只描述 wire 变更。不影响任何消费方字节的实现侧重构,放对应服务的 README,不放这里。 - 开 PR。 CI 跑
redocly lint+make gen+backend/services/openapi-gateway/internal/dto/contract_test.go里的契约漂移测试,并对生成的 Go SDK 跑go build ./...。 - 合并后,发布工作流: 用今天的日期戳变更日志头、给 meta repo 打
sdk-v<version>tag、把@beeos-ai/sdk发布到 npm、把生成的 Go SDK 推到github.com/beeos-ai/sdk-go(那是个 release-tagged repo,所以go get能解析到新 tag)。
sdks/beeos-ai-sdk/ 或 sdks/beeos-ai-sdk-go/
—— 它们每次发布都被重新生成。仅有的手工资产在
sdks/openapi-sdk/assets/{beeos-ai-sdk,beeos-ai-sdk-go}/ 下,每次盖在
generator 输出之上(README、LICENSE)。
[Unreleased]
新增(Message Envelope v3 — MessageDTO 对齐)
MessageDTO现在引用平台级 v3 union schema。 以前state/stop_reason/parts在MessageDTO内部 各自 inline 一份 enum / array-of-object;现在统一$ref到MessageState/StopReason/Part—— 跟TaskSSEMessage和流式 envelope 已经在用的 union 完全一致。生成的 SDK 现在 自动带类型化的MessageState/StopReason/Part导出; 裸 JSON 调用方 wire 上看不到差异(union 字符串值集合本就一样, 这次只是 contract 层去重)。MessageDTO.updated_at(RFC3339Nano,UTC)。 v3 envelope 的 服务端最后一次 PATCH 时间戳。仅当与created_at不同才下发 —— 新 POST 的 reply 没有;streaming envelope 每次 PATCH 会改写; 终态行在状态转换那一刻冻结。SSE 重放客户端应用它来 ACK 进度 checkpoint;聊天记录 UI 可忽略。Legacy v1 行上 字段缺失。
修复(SDK 指南 typo)
- TypeScript 指南:
reply.data?.reply改为reply.data?.text;task.data?.status === "completed"→"succeeded"(TaskStatus真实的终态值);conv.data!.id→conv.data!.conversationId(匹配生成的ConversationResponseAllOfData字段);删除PresignUploadRequest上并不存在的size_bytes字段。 - Go 指南:
reply.GetData().GetReply()→GetText();status == "completed"→"succeeded"; 从PresignUploadRequest去掉SizeBytes。 - Quickstart:TypeScript + Go 示例同步把
reply改text。
Breaking(scope 词汇下线 — v1.1.0)
oag_User API Key 的 per-route scope 已删除。 集合agents:read、agents:write、tasks:read、tasks:write、files:read、files:write、instances:read、instances:write以及通配符admin:*不再被识别。原先需要 scope 的 37 条 路由现在完全由 owner-ACL 守门 —— 每个oag_key 自动获得其 owner 名下全部资源的访问权,与 JWT 等价。- 不再下发
403 insufficient_scope。 删掉所有按error.code === "insufficient_scope"分支的代码;合并到通用forbidden(403)处理。 POST /api/v1/api-keys忽略 body 里的scopes,响应也 不再带scopes。SDK 调用方应从createAPIKey(...)删该参数 —— 滚动发布窗口期 wire 上该字段会被静默丢弃,下一个 contract 版本会从请求 schema 整体删除。- 不需要数据迁移。 已签发的
oag_key 自动获得 owner 级 全部权限继续工作;服务端api_keys.scopes列已 DROP。
Breaking(ADR-0022 — 双层消息存储)
GET /api/v1/agents/{agentId}/conversations/{convId}/messages与GET /api/v1/agents/{agentId}/tasks/{taskId}/messages现在默认过滤掉临时流式 chunk(agent_reply_delta、agent_thought_chunk、agent_message_chunk)。加?include_deltas=true可恢复旧行为。latest_offset仍然 反映真实服务端最大 offset(同时覆盖被过滤行和未被过滤行), 所以since=/ cursor 分页不受影响。SSE/events不受影响 —— 实时消费者照常拿到每条信封。迁移建议:原来用轮询/messages重建流式记录的客户端代码,要么 (a) 传include_deltas=true保留旧行为,要么 (b) 切到 SSE/events流,那才是消费实时 token chunk 的官方姿势。- SSE
/events现在可能发新的backfill_truncated事件帧 —— 当客户端用Last-Event-ID指向已老化失踪的临时 chunk 时触发。 老 SDK 不识别此帧应视为提示,跳过中间临时 chunk 改用latest_offset(在replay_complete中返回)续传。按 ADR-0022 §6 默认保留窗口是 24h / 10k 条。 - SSE 事件
offset契约澄清:单调但不保证连续。 Producer 端写 存储失败可能在 offset 序列里留小空洞(例如观察到… 40, 42, …,41缺失)。客户端必须用offset > since作为续传不变量 —— 断言offset == since + 1的代码本来就是未定义行为,现在明确 记作 bug。续传配方见guides/streaming.md。
新增
POST /api/v1/agents/{agentId}/tasks/{taskId}/webhooks/{webhookId}/deliveries/{deliveryId}/redeliver—— 手动重新入队单次 webhook 投递。返回新的pendingWebhookDeliveryResponse。当接收方挂了你想立刻重放、不愿等下一个指数 退避窗口时有用。GET /api/v1/agents/{agentId}/tasks/{taskId}/webhooks/{webhookId}/deliveries—— webhook 绑定的逐次投递审计日志。返回最近 N 次(默认 50、最大 100) 尝试,含status、attempt_num、last_response_status、last_error、next_attempt_at。secret(可选、只写)字段 —— 加在RegisterTaskWebhookRequest和底层 A2ApushNotificationConfig/set上。提供后每次投递携带X-BeeOS-Signature: sha256=<hex>,按secretHMAC-SHA256 计算自 JSON body。wire 响应只回显has_secret: true;原值从不返回。 Python 和 Node.js 验证示例见docs/guides/webhooks.md。- Webhook 重试与死信。 失败投递(网络错、超时、5xx 响应)按指数退避
重试:
1m / 5m / 30m / 2h / 12h。第 6 次失败后行变dead_letter。 4xx 响应(除 408 / 429 外)不重试 —— 视为永久客户端配置错。 由backend/services/a2a里的后台 worker 驱动,轮询持久化的webhook_deliveries表。 GET /api/v1/tasks—— 跨智能体任务列表。返回认证调用方通过 OpenAPI 面创建的所有任务,可按agent_id过滤。limit+since分页。多智能体 UI 有用(一个组织所有智能体的统一收件箱)。POST /api/v1/files/presign-upload—— 申请短时效 S3 风格 PUT URL 上传文件。返回file_id,可嵌入后续invoke/tasks.create/conversations.sendbody 的attachments[].file_id。GET /api/v1/files/{fileId}—— 回读已上传文件的元数据 + 签名 GET URL。attachments[].file_id—— 加在InvokeAgentRequest、CreateTaskRequest和会话发送 body 上。智能体看到的是普通 multi-partchat_message含filepart。PATCH /api/v1/agents/{agentId}—— 仅 owner 更新智能体的visibility和mcp_enabled标志。其他智能体字段(name、description等)仍由智能体进程的POST /api/v1/agents/sync同步、 不能在这里 patch(改了下次 sync 会被静默覆盖)。metrics端点(GET /metrics)—— Prometheus pull 端点, 暴露标准 process 指标加beeos.openapi.*命名空间。OTLP push 仍可用 通过OTEL_EXPORTER_OTLP_*env 变量。- 探针路由的 OpenAPI 级限流。
/healthz、/version、/spec/*、/metrics现在按 IP 限流,防未鉴权抓取 DoS。 MaxBytesReaderbody 大小强制。 每请求默认 1 MiB,catalog / list 端点 64 KiB。超限返回413 payload_too_large。POST /agents/{id}/invoke的timeout_ms钳制。 调用方传入值钳 在[100, 115_000](上游端到端预算 120s)。超过钳值会暴露service_timeout,不会无声挂住连接。- OpenAPI 示例 —— 给 top 5 operations
(
listInstances、listAgents、invokeAgent、createTask、getTask)加示例 + 全 4xx/5xx 响应形状。
变更
- 所有错误响应 现在遵循规范信封:
code取自docs/reference/errors.md的表。 4xx 和 5xx 共享同一形状;只检查 HTTP 状态的老客户端仍然有效。 - Webhook
当前限制段在docs/guides/webhooks.md已重写 —— 原先的 “限制”(无签名、无重试、无审计日志)现在都是一等公民特性。 唯一遗留限制是死信前 6 次尝试上限。
文档(无 wire 变更)
- 新增
docs/architecture/public-overview.md—— 四个公开主机、各自的归属、跨协议不变式。 - 新增
docs/guides/mcp-gateway.md—— MCP 集成实战(OAuth / DCR / PKCE + API key 路径)。 - 新增
docs/guides/a2a-external.md—— 通过a2a.beeos.ai联邦化外部智能体平台。 - 新增
docs/guides/conversations.md—— 多轮对话接入面。 - 新增
docs/guides/agent-author-quickstart.md—— 构建智能体进程本身(每篇指南的另一面)。 - 新增
docs/guides/streaming.md—— 三个 SSE 接入面、since=<offset>、重连。 - 新增
docs/guides/choosing-a-protocol.md—— OpenAPI vs A2A vs MCP 并排比较。 - 新增
docs/reference/errors.md—— 规范code表。 - 新增
docs/guides/auth-api-keys.md—— JWT vsoag_vsbak_vs OAuth 生命周期。 - 重写
docs/guides/calling-agents.md覆盖全部三种 invocation 模式(阻塞 / SSE / 异步任务),带 TS + Go SDK 片段。 - 新增
docs/guides/sdk-migration.md—— 逐版本迁移配方(迁移日志起点)。
[0.4.0] — 2026-04-30
Breaking
SendMessageResponse.offset移除。 该字段是误导性占位;真正的 offset 不透明地在 cursor 里。需要 offset 做 SSE resume 的调用方必须 走GET /messages?since=<cursor>(SSE 消费方不受影响)。
新增
InvokeAgentRequest.idempotency_key和InvokeAgentRequest.metadata(都可选;向后兼容)。同 key 端到端 贯穿 L0 → MS。TaskResponse.truncated(可选布尔)—— 表示任务事件日志已扫到 1000 条上限、返回事件可能不全。老客户端可忽略此字段。PushNotificationConfig.protocol_filter—— gateway 在注册时盖 起源 renderer key(openapi/a2a/mcp)。让同一个底层 webhook 能按触发面过滤。
[0.3.0] — 2026-03-22
新增
- 首个公开级契约:
POST /api/v1/agents/{id}/invoke(sync + SSE)。POST /api/v1/agents/{id}/tasks+GET .../tasks/{id}+GET .../events(SSE)+POST .../cancel。POST /api/v1/agents/{id}/conversations+ send + delete + 带sincecursor 的 list。- 任务 webhooks:
POST .../webhooks+GET+DELETE。 - 文件 presign(上传)。
invokebody 上的idempotency_key。
@beeos-ai/sdk@0.3.0 和 github.com/beeos-ai/sdk-go@v0.3.0 仍可从
npm / proxy.golang.org 解析,并在重叠路由集上与当前 openapi-gateway
wire 兼容。
更早的版本
0.2.x 及更早预日期 OpenAPI Gateway BFF 解耦(ADR-001)—— 它们直接
对接 main Gateway,不再是受支持的 SDK 契约的一部分。卡在那些版本
的消费方应直接升到 0.4.x 并照
docs/guides/sdk-migration.md 操作。