> ## Documentation Index
> Fetch the complete documentation index at: https://docs.beeos.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# SDK 变更日志

> OpenAPI 契约以及 TypeScript、Go、Python 三个生成 SDK 的版本变更。

BeeOS **公开 OpenAPI 契约**
（`backend/openapi/beeos-platform-v1.yaml`）以及从中生成的 SDK
（TypeScript 的 `@beeos-ai/sdk`、Go 的 `github.com/beeos-ai/sdk-go`、
Python 的 `beeos-sdk`）所有值得注意的变更都记录在本文件。

本文件是**规范变更日志**：

* 终端用户升级 SDK 版本时看的是它，
* 发布工作流打 tag 时查的也是它（SDK 生成器在
  [`sdks/openapi-sdk/generate.sh`](https://github.com/beeos-ai/openagent/blob/main/sdks/openapi-sdk/generate.sh)
  里盖版本戳）。

每服务的 backend 变更（cluster、runtime、a2a 等）见各服务自己的
README 与
[`backend/docs/adr/`](https://github.com/beeos-ai/openagent/blob/main/backend/docs/adr/)
下的 ADR。

格式基于
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/)，
契约版本号遵循
[Semantic Versioning](https://semver.org/spec/v2.0.0.html)。

***

## 版本号策略

| Bump      | 触发条件                                                    |
| --------- | ------------------------------------------------------- |
| **MAJOR** | 移除路由、改必填字段名、改已有响应形状、改鉴权语义（例如收紧所有权模型）、改 error `code` 语义。 |
| **MINOR** | 加新路由、加可选请求字段、加可选响应字段、加新 `code` 值。                       |
| **PATCH** | 文档、示例、OpenAPI `description` 打磨、不影响生成代码的 generator 配置调整。 |

TypeScript、Go 和 Python SDK package 共享**同一条**版本线。它们总是
从同一次 generator run 一起切，不能发布版本不一致的组合。

***

## 发布流程 —— 一个版本怎么真正发出去

1. **改 spec。** 所有 wire 变更先落在
   [`backend/openapi/beeos-platform-v1.yaml`](https://github.com/beeos-ai/openagent/blob/main/backend/openapi/beeos-platform-v1.yaml)。
   openapi-gateway 服务通过 `go:embed` 消费此文件，所以
   `backend/services/openapi-gateway` 下 `go build` 就是第一道 lint。
2. **同步 vendor 副本。** 在 `sdks/openapi-sdk/` 下：
   ```bash theme={null}
   make sync-spec     # copy → spec/beeos-platform-v1.yaml
   make validate      # openapi-generator-cli validate
   make gen           # regenerate both SDKs
   ```
3. **更新 generator 版本戳。** 同一个 commit 里把
   [`sdks/openapi-sdk/generate.sh`](https://github.com/beeos-ai/openagent/blob/main/sdks/openapi-sdk/generate.sh)
   `npmVersion=` 和所有 `packageVersion=` 一起升上去。三个 SDK
   共享版本号。
4. **写下面的条目。** 在 `[Unreleased]` 块顶部加新段；只描述 **wire**
   变更。不影响任何消费方字节的实现侧重构，放对应服务的 README，不放这里。
5. **开 PR。** CI 跑 `redocly lint` + `make gen` +
   `backend/services/openapi-gateway/internal/dto/contract_test.go`
   里的契约漂移测试，并对生成的 Go SDK 跑 `go build ./...`。
6. **合并后，同步工作流：** 重新生成并验证三个客户端，然后向
   `beeos-ai/sdk`、`beeos-ai/sdk-go` 和 `beeos-ai/sdk-python` 推送不可变的
   `v<version>` tag。各独立仓库负责自己的包发布：TypeScript 发布到 npm
   并携带 provenance，Go 通过 Go Module Proxy 分发，Python 使用 PyPI
   Trusted Publisher。

**不要**手动改 `sdks/beeos-ai-sdk/` 或 `sdks/beeos-ai-sdk-go/`
—— 它们每次发布都被重新生成。仅有的手工资产在
`sdks/openapi-sdk/assets/{beeos-ai-sdk,beeos-ai-sdk-go}/` 下，每次盖在
generator 输出之上（README、LICENSE）。

***

## \[Unreleased]

当前没有尚未发布的 SDK 变更。

***

## \[0.6.1] — 2026-08-20

### 修复

* **规范任务成功状态。** 生成的 TypeScript、Go、Python `TaskStatus`
  enum 现在使用 `completed`，不再使用过时的 `succeeded`；它与
  OpenAPI 服务端、Message Service resolver 和 A2A 成功语义一致。
* **任务示例。** 轮询、webhook payload、生命周期和架构示例统一使用
  `completed`。Runtime Operation 与 webhook delivery 是独立枚举，仍保留
  各自的 `succeeded`。

### 迁移

* 将 `TaskStatus.Succeeded`、`TASKSTATUS_SUCCEEDED` 或字符串
  `"succeeded"` 的判断替换为对应的 `completed`。接口、请求结构和其他
  非成功状态均未改变。

***

## \[0.6.0] — 2026-08-18

### 新增

* **稳定 TypeScript facade。** `BeeOSClient` 提供 `listAgents`、
  `createTask`、`getTask`、`cancelTask`，以及 async-generator 形式的
  `taskEvents` SSE 客户端；完整生成 API 仍保留。
* **稳定 Go facade。** `Client` 提供同一组任务能力，并通过
  `TaskEvents` channel 解析 SSE；完整生成客户端保留在 `Client.API`。
* **公开包黑盒验证。** CI 从 npm、PyPI 和 Go Proxy 安装同一个指定版本，
  检查 CommonJS、ESM、Python import、Go 编译、facade、npm provenance，
  以及 staging 未鉴权请求边界。

### 变更

* **缩小 TypeScript 包体。** npm 只包含 `dist`、README 和 LICENSE：
  151 files / 1.85 MB unpacked；0.5.0 为 719 files / 5.36 MB。
* **明确运行时契约。** `@beeos-ai/sdk` 声明 Node.js `>=20`，提供 root
  与 `./facade` exports，并在 Node 20、22、24 上分别验证 ESM/CJS。
* **发布职责清晰化。** OpenAgent 生成并同步三个 SDK，各独立 SDK 仓库
  发布自己的 registry artifact；npm 0.6.0 带已验证 provenance attestation。

### 兼容性

* 本版本不改变 Backend 或 OpenAPI wire 行为；原有生成客户端 import
  继续受支持。

***

## \[0.5.0] — 2026-08-18

### 新增（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`](/zh/guides/streaming)。

### 新增

* **`POST /api/v1/agents/{agentId}/tasks/{taskId}/webhooks/{webhookId}/deliveries/{deliveryId}/redeliver`**
  —— 手动重新入队单次 webhook 投递。返回新的 `pending`
  `WebhookDeliveryResponse`。当接收方挂了你想立刻重放、不愿等下一个指数
  退避窗口时有用。
* **`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`
  和底层 A2A `pushNotificationConfig/set` 上。提供后每次投递携带
  `X-BeeOS-Signature: sha256=<hex>`，按 `secret` HMAC-SHA256 计算自
  JSON body。wire 响应只回显 `has_secret: true`；原值从不返回。
  Python 和 Node.js 验证示例见
  [`docs/guides/webhooks.md`](/zh/guides/webhooks)。
* **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.send` body 的
  `attachments[].file_id`。
* **`GET /api/v1/files/{fileId}`** —— 回读已上传文件的元数据 + 签名
  GET URL。
* **`attachments[].file_id`** —— 加在 `InvokeAgentRequest`、
  `CreateTaskRequest` 和会话发送 body 上。智能体看到的是普通
  multi-part `chat_message` 含 `file` part。
* **`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。
* **`MaxBytesReader` body 大小强制。** 每请求默认 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 响应形状。

### 变更

* **所有错误响应** 现在遵循规范信封：
  ```json theme={null}
  { "error": { "type": "…", "code": "…", "message": "…",
              "param": "…", "request_id": "…" } }
  ```
  `code` 取自 [`docs/reference/errors.md`](/zh/reference/errors) 的表。
  4xx 和 5xx 共享同一形状；只检查 HTTP 状态的老客户端仍然有效。
* **Webhook `当前限制`** 段在
  [`docs/guides/webhooks.md`](/zh/guides/webhooks) 已重写 —— 原先的
  "限制"（无签名、无重试、无审计日志）现在都是一等公民特性。
  唯一遗留限制是死信前 6 次尝试上限。

### 文档（无 wire 变更）

* **新增** [`docs/architecture/public-overview.md`](/zh/architecture/public-overview)
  —— 四个公开主机、各自的归属、跨协议不变式。
* **新增** [`docs/guides/mcp-gateway.md`](/zh/mcp/overview)
  —— MCP 集成实战（OAuth / DCR / PKCE + API key 路径）。
* **新增** [`docs/guides/a2a-external.md`](/zh/a2a/overview)
  —— 通过 `a2a.beeos.ai` 联邦化外部智能体平台。
* **新增** [`docs/guides/conversations.md`](/zh/guides/conversations)
  —— 多轮对话接入面。
* **新增** [`docs/guides/agent-author-quickstart.md`](/zh/guides/agent-author-quickstart)
  —— 构建智能体进程本身（每篇指南的另一面）。
* **新增** [`docs/guides/streaming.md`](/zh/guides/streaming)
  —— 三个 SSE 接入面、`since=<offset>`、重连。
* **新增** [`docs/guides/choosing-a-protocol.md`](/zh/guides/choosing-a-protocol)
  —— OpenAPI vs A2A vs MCP 并排比较。
* **新增** [`docs/reference/errors.md`](/zh/reference/errors)
  —— 规范 `code` 表。
* **新增** [`docs/guides/auth-api-keys.md`](/zh/authentication)
  —— JWT vs `oag_` vs `bak_` vs OAuth 生命周期。
* **重写** [`docs/guides/calling-agents.md`](/zh/guides/calling-agents)
  覆盖全部三种 invocation 模式（阻塞 / SSE / 异步任务），带 TS + Go
  SDK 片段。
* **新增** [`docs/guides/sdk-migration.md`](/zh/sdks/migration)
  —— 逐版本迁移配方（迁移日志起点）。

***

## \[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 +
    带 `since` cursor 的 list。
  * 任务 webhooks：`POST .../webhooks` + `GET` + `DELETE`。
  * 文件 presign（上传）。
  * `invoke` body 上的 `idempotency_key`。

这是统一路线图之前大多数第三方文档引用的版本。SDK
`@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`](/zh/sdks/migration) 操作。
