> ## 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 Changelog

> Versioned changes to the OpenAPI contract and the generated TypeScript, Go, and Python SDKs.

All notable changes to the BeeOS **public OpenAPI contract**
(`backend/openapi/beeos-platform-v1.yaml`) and the SDKs generated
from it (`@beeos-ai/sdk` for TypeScript, `github.com/beeos-ai/sdk-go`
for Go, and `beeos-sdk` for Python) are documented in this file.

This file is the **canonical change log** that:

* end users see when they bump SDK versions, and
* the publish workflow consults when minting a tag (the SDK
  generator stamps the version in
  [`sdks/openapi-sdk/generate.sh`](https://github.com/beeos-ai/openagent/blob/main/sdks/openapi-sdk/generate.sh)).

For per-service backend changes (cluster, runtime, a2a, etc.),
see each service's own README and ADRs under
[`backend/docs/adr/`](https://github.com/beeos-ai/openagent/blob/main/backend/docs/adr/).

The format is based on
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the
contract version follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

***

## Versioning

| Bump      | Triggered by                                                                                                                                                                           |
| --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **MAJOR** | Removing routes, renaming required fields, changing the shape of an existing response, changing auth semantics (e.g. tightening the ownership model), changing error `code` semantics. |
| **MINOR** | Adding new routes, adding optional request fields, adding optional response fields, adding new `code` values.                                                                          |
| **PATCH** | Documentation, examples, OpenAPI `description` polish, generator config tweaks that don't change emitted code.                                                                         |

The TypeScript, Go, and Python SDK packages share **one** version line.
They are always cut together from the same generator run; mismatched
versions must never be released.

***

## Release process — how a version actually ships

1. **Edit the spec.** All wire changes land in
   [`backend/openapi/beeos-platform-v1.yaml`](https://github.com/beeos-ai/openagent/blob/main/backend/openapi/beeos-platform-v1.yaml)
   first. The openapi-gateway service consumes this file via
   `go:embed`, so a `go build` in `backend/services/openapi-gateway`
   is the first lint.
2. **Sync the vendored copy.** From `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. **Update generator stamps.** Bump `npmVersion=` and every
   `packageVersion=` in
   [`sdks/openapi-sdk/generate.sh`](https://github.com/beeos-ai/openagent/blob/main/sdks/openapi-sdk/generate.sh)
   in the same commit. All three SDKs share the version.
4. **Write the entry below.** Add a new section at the top of
   the `[Unreleased]` block; describe **wire** changes only.
   Implementation-side refactors that don't affect any consumer
   bytes belong in the relevant service README, not here.
5. **Open the PR.** CI runs `redocly lint` + `make gen` + the
   contract-drift test in
   `backend/services/openapi-gateway/internal/dto/contract_test.go`,
   plus `go build ./...` on the generated Go SDK.
6. **On merge, the sync workflow:** regenerates and verifies all
   three clients, then pushes immutable `v<version>` tags to
   `beeos-ai/sdk`, `beeos-ai/sdk-go`, and `beeos-ai/sdk-python`.
   Each independent repository owns its package publication:
   the TypeScript repository publishes to npm with provenance,
   Go is distributed through the Go module proxy, and Python uses
   PyPI Trusted Publisher.

**Never** edit `sdks/beeos-ai-sdk/` or `sdks/beeos-ai-sdk-go/`
by hand — they are regenerated on every release. The only
hand-curated assets are under
`sdks/openapi-sdk/assets/{beeos-ai-sdk,beeos-ai-sdk-go}/` and
get copied on top of the generator output (README, LICENSE).

***

## \[Unreleased]

No unreleased SDK changes yet.

***

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

### Fixed

* **Canonical task success status.** Generated TypeScript, Go, and Python
  `TaskStatus` enums now expose `completed` instead of the stale
  `succeeded` value, matching the OpenAPI server, Message Service resolver,
  and A2A success vocabulary.
* **Task examples.** Polling, webhook payload, lifecycle, and architecture
  examples now use `completed`. The separate Runtime Operation and webhook
  delivery enums continue to use their own `succeeded` value.

### Migration

* Replace comparisons against `TaskStatus.Succeeded`,
  `TASKSTATUS_SUCCEEDED`, or the string `"succeeded"` with their
  `completed` equivalents. No endpoint, request shape, or non-success status
  changed.

***

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

### Added

* **Stable TypeScript facade.** `BeeOSClient` provides `listAgents`,
  `createTask`, `getTask`, `cancelTask`, and an async-generator
  `taskEvents` SSE client without hiding the complete generated API.
* **Stable Go facade.** `Client` provides the same task-focused surface,
  including channel-based SSE parsing through `TaskEvents`; the complete
  generated client remains available as `Client.API`.
* **Public-package black-box verification.** CI installs one explicit
  version from npm, PyPI, and the Go Proxy, then checks CommonJS, ESM,
  Python imports, Go compilation, facade availability, npm provenance,
  and the unauthenticated staging auth boundary.

### Changed

* **Smaller TypeScript package.** npm contents are limited to `dist`,
  README, and LICENSE: 151 files / 1.85 MB unpacked, down from 719 files /
  5.36 MB in 0.5.0.
* **Explicit runtime contract.** `@beeos-ai/sdk` now declares Node.js
  `>=20`, root and `./facade` exports, plus independently verified ESM and
  CommonJS entry points on Node 20, 22, and 24.
* **Release ownership.** OpenAgent generates and syncs all three SDKs;
  each independent SDK repository publishes its own registry artifact.
  npm 0.6.0 carries a verified provenance attestation.

### Compatibility

* No Backend or OpenAPI wire behavior changed in this release. Existing
  generated-client imports remain supported.

***

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

### Added (Message Envelope v3 — `MessageDTO` alignment)

* **`MessageDTO` now references canonical v3 unions.** The
  `state`, `stop_reason`, and `parts` fields previously inlined
  their enums / array-of-object schema in `MessageDTO` only.
  They now `$ref` the platform-wide `MessageState`, `StopReason`,
  and `Part` schemas — the same union shapes already exposed on
  `TaskSSEMessage` and the streaming envelopes. **Generated
  SDKs gain typed `MessageState` / `StopReason` / `Part`
  imports automatically**; raw-JSON callers see no wire change
  (the union values were already the same string set on the
  wire — this is a contract-level dedupe).
* **`MessageDTO.updated_at` (RFC3339Nano, UTC).** Server's
  last-PATCH timestamp on v3 envelopes. Emitted only when
  distinct from `created_at` — fresh POST replies omit it,
  streaming envelopes mutate it on every PATCH, terminal rows
  freeze it at the moment of state transition. SSE replay
  clients SHOULD use it to ack progress checkpoints; chat-log
  UIs MAY ignore it. Empty / absent on legacy v1 rows.

### Fixed (SDK guide typos)

* TypeScript guide: `reply.data?.reply` corrected to
  `reply.data?.text`; `task.data?.status === "completed"` →
  `"succeeded"` (the actual `TaskStatus` terminal value);
  `conv.data!.id` → `conv.data!.conversationId` (matches the
  generated `ConversationResponseAllOfData` field); dropped the
  non-existent `size_bytes` field on `PresignUploadRequest`.
* Go guide: `reply.GetData().GetReply()` → `GetText()`;
  `status == "completed"` → `"succeeded"`; dropped
  `SizeBytes` from `PresignUploadRequest`.
* Quickstart guide: same `reply` → `text` rename in both
  TypeScript and Go examples.

### Breaking (scope vocabulary removed — v1.1.0)

* **`oag_` User API Key per-route scopes deleted.** The set
  `agents:read`, `agents:write`, `tasks:read`, `tasks:write`,
  `files:read`, `files:write`, `instances:read`, `instances:write`
  (and the `admin:*` wildcard) is **no longer recognised**. The
  37 routes that previously required a scope are now governed
  purely by owner-ACL — every `oag_` key has full access to its
  owner's resources, the same way a JWT does.
* **`403 insufficient_scope` is no longer emitted.** Drop any
  code that branches on `error.code === "insufficient_scope"`;
  fold the case into your generic `forbidden` (403) handler.
* **`POST /api/v1/api-keys` ignores `scopes` in the request
  body** and the response no longer carries `scopes`. SDK
  callers should remove the argument from `createAPIKey(...)` —
  it is silently dropped on the wire during the rolling deploy
  window and will be removed from the request schema entirely
  in the next contract revision.
* **No data migration required.** Existing `oag_` keys keep
  working with full owner-level access; the `api_keys.scopes`
  column is dropped server-side.

### Breaking (ADR-0022 — dual-layer message storage)

* **`GET /api/v1/agents/{agentId}/conversations/{convId}/messages`** and
  **`GET /api/v1/agents/{agentId}/tasks/{taskId}/messages`** now
  **default-filter out** ephemeral streaming chunks
  (`agent_reply_delta`, `agent_thought_chunk`, `agent_message_chunk`).
  Add **`?include_deltas=true`** to opt back in. `latest_offset` continues
  to reflect the TRUE server-side max offset across both filtered and
  unfiltered rows, so `since=` / cursor-style pagination is unaffected.
  SSE `/events` is NOT affected — live consumers continue to receive
  every envelope as it happens. Migration recipe: client code that
  rebuilt streaming transcripts by polling `/messages` should either
  (a) pass `include_deltas=true` to preserve current behaviour, or
  (b) switch to the SSE `/events` stream which is the supported way
  to consume live token chunks.
* **SSE `/events`** may emit a new **`backfill_truncated`** event
  frame when the client reconnects with `Last-Event-ID` pointing
  before the oldest retained ephemeral chunk. Older SDKs that don't
  recognise the frame should treat it as a hint to resume from
  `latest_offset` (returned in `replay_complete`) instead of replaying
  individual chunks. Per ADR-0022 §6 the retention window is 24h /
  10k entries by default.
* **SSE event `offset` clarified as monotonic-but-not-contiguous.**
  Producer-side write failures may leave small holes in the offset
  sequence (e.g. `… 40, 42, …` with `41` missing). Clients MUST
  treat `offset > since` as the resume invariant — code that
  asserts `offset == since + 1` was always undefined behaviour
  and is now explicitly documented as a bug. See
  [`guides/streaming.md`](/guides/streaming) for the resume recipe.

### Added

* **`POST /api/v1/agents/{agentId}/tasks/{taskId}/webhooks/{webhookId}/deliveries/{deliveryId}/redeliver`** —
  manual re-queue of a single webhook delivery attempt. Returns
  a new `pending` `WebhookDeliveryResponse`. Useful when the
  receiver was down and you want to replay without waiting for
  the next exponential-backoff slot.
* **`GET /api/v1/agents/{agentId}/tasks/{taskId}/webhooks/{webhookId}/deliveries`** —
  per-attempt delivery audit log for a webhook binding. Returns
  the last N attempts (default 50, max 100) including
  `status`, `attempt_num`, `last_response_status`, `last_error`,
  `next_attempt_at`.
* **`secret` (optional, write-only)** field on
  `RegisterTaskWebhookRequest` and the underlying A2A
  `pushNotificationConfig/set`. When supplied, every delivery
  carries `X-BeeOS-Signature: sha256=<hex>` computed over the
  JSON body with HMAC-SHA256 keyed by `secret`. The wire
  response only echoes `has_secret: true`; the raw value is
  never returned. See
  [`docs/guides/webhooks.md`](/guides/webhooks) for the
  verification recipes in Python and Node.js.
* **Webhook retry & dead-letter.** Failed deliveries (network
  error, timeout, or 5xx response) are retried with exponential
  backoff at `1m / 5m / 30m / 2h / 12h`. After the 6th failed
  attempt the row becomes `dead_letter`. 4xx responses (other
  than 408 / 429) are NOT retried — they're treated as a
  permanent client misconfiguration. Driven by a background
  worker in `backend/services/a2a` polling a durable
  `webhook_deliveries` table.
* **`GET /api/v1/tasks`** — cross-agent task list. Returns all
  tasks the authenticated caller created via the OpenAPI
  surface, optionally filtered by `agent_id`. Pages with
  `limit` + `since`. Useful for multi-agent UIs (one inbox
  across an organization's agents).
* **`POST /api/v1/files/presign-upload`** — request a short-lived
  S3-style PUT URL for uploading a file. Returns a `file_id`
  that can be embedded in subsequent
  `invoke` / `tasks.create` / `conversations.send` bodies as
  `attachments[].file_id`.
* **`GET /api/v1/files/{fileId}`** — read-back of a previously
  uploaded file's metadata + presigned GET URL.
* **`attachments[].file_id`** on `InvokeAgentRequest`,
  `CreateTaskRequest`, and conversation send bodies. The agent
  sees a normal multi-part `chat_message` with `file` parts.
* **`PATCH /api/v1/agents/{agentId}`** — owner-only update of an
  agent's `visibility` and `mcp_enabled` flags. Other agent
  fields (`name`, `description`, …) are still owner-synced via
  the agent process's `POST /api/v1/agents/sync` and cannot be
  patched here (changes would be silently overwritten on next
  sync).
* **`metrics` endpoint** (`GET /metrics`) — Prometheus pull
  endpoint exposing standard process metrics plus
  `beeos.openapi.*` namespaces. OTLP push remains available via
  `OTEL_EXPORTER_OTLP_*` env vars.
* **OpenAPI-level rate limiting on probe routes.** `/healthz`,
  `/version`, `/spec/*`, `/metrics` are now per-IP rate-limited
  to prevent unauthenticated scraping DoS.
* **`MaxBytesReader` body-size enforcement.** Default 1 MiB per
  request, 64 KiB on catalog/list endpoints. Over-limit returns
  `413 payload_too_large`.
* **`timeout_ms` clamp on `POST /agents/{id}/invoke`.** The
  caller-supplied value is clamped to `[100, 115_000]` (the
  upstream end-to-end budget is 120s). Going past the clamp
  surfaces `service_timeout` instead of a stale connection.
* **Examples in OpenAPI** for the top 5 operations
  (`listInstances`, `listAgents`, `invokeAgent`, `createTask`,
  `getTask`) plus all 4xx/5xx response shapes.

### Changed

* **All error responses** now follow the canonical envelope
  ```json theme={null}
  { "error": { "type": "…", "code": "…", "message": "…",
              "param": "…", "request_id": "…" } }
  ```
  with `code` drawn from the table in
  [`docs/reference/errors.md`](/reference/errors). 4xx and
  5xx responses share the same shape; older clients that only
  inspected the HTTP status keep working.
* **Webhook `Current limitations`** section in
  [`docs/guides/webhooks.md`](/guides/webhooks) has been
  rewritten — what used to be "limitations" (no signing, no
  retry, no audit log) are now first-class features. The only
  remaining caveat is the 6-attempt cap before dead-letter.

### Documentation (no wire change)

* **New** [`docs/architecture/public-overview.md`](/architecture/public-overview)
  — the four public hosts, what each owns, and cross-protocol
  invariants.
* **New** [`docs/guides/mcp-gateway.md`](/mcp/overview)
  — MCP integration walkthrough (OAuth / DCR / PKCE + API-key
  paths).
* **New** [`docs/guides/a2a-external.md`](/a2a/overview)
  — federating an external agent platform via `a2a.beeos.ai`.
* **New** [`docs/guides/conversations.md`](/guides/conversations)
  — the multi-turn dialog surface.
* **New** [`docs/guides/agent-author-quickstart.md`](/guides/agent-author-quickstart)
  — building the agent process itself (the other side of every
  guide).
* **New** [`docs/guides/streaming.md`](/guides/streaming) —
  the three SSE surfaces, `since=<offset>`, reconnect.
* **New** [`docs/guides/choosing-a-protocol.md`](/guides/choosing-a-protocol)
  — OpenAPI vs A2A vs MCP, side-by-side.
* **New** [`docs/reference/errors.md`](/reference/errors) —
  canonical `code` table.
* **New** [`docs/guides/auth-api-keys.md`](/authentication)
  — JWT vs `oag_` vs `bak_` vs OAuth lifecycle.
* **Rewrote** [`docs/guides/calling-agents.md`](/guides/calling-agents)
  to cover all three invocation modes (blocking / SSE / async
  task) with TS + Go SDK snippets.
* **Added** [`docs/guides/sdk-migration.md`](/sdks/migration)
  — per-version migration recipe (start of the migration log).

***

## \[0.4.0] — 2026-04-30

### Breaking

* **`SendMessageResponse.offset` removed.** The field was a
  misleading placeholder; the real offset is kept opaque inside
  the cursor. Callers that need the offset for SSE resume must
  round-trip via `GET /messages?since=<cursor>` (unchanged for
  SSE consumers).

### Added

* **`InvokeAgentRequest.idempotency_key`** and
  **`InvokeAgentRequest.metadata`** (both optional;
  backwards-compatible). The same `idempotency_key` is honoured
  end-to-end through L0 → MS.
* **`TaskResponse.truncated`** (optional boolean) — signals that
  the task's event log was scanned past the 1 000-message cap
  and the returned events may not be the full set. Old clients
  may ignore this field.
* **`PushNotificationConfig.protocol_filter`** — gateways stamp
  the originating renderer key (`openapi` / `a2a` / `mcp`) when
  registering. Lets the same backing webhook be filtered by
  triggering surface.

***

## \[0.3.0] — 2026-03-22

### Added

* First public-grade contract:
  * `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 +
    list with `since` cursor.
  * Task webhooks: `POST .../webhooks` + `GET` + `DELETE`.
  * Files presign (uploads).
  * `idempotency_key` on `invoke` body.

This is the version most third-party documentation that
predates the unified roadmap refers to. SDK
`@beeos-ai/sdk@0.3.0` and `github.com/beeos-ai/sdk-go@v0.3.0`
are still resolvable from npm / `proxy.golang.org` and remain
wire-compatible with the current openapi-gateway for the
overlapping route set.

***

## Earlier versions

`0.2.x` and earlier predate the OpenAPI Gateway BFF decoupling
(ADR-001) — they fronted the **main** Gateway directly and are
no longer part of the supported SDK contract. Consumers stuck
on those versions should bump straight to `0.4.x` and follow
[`docs/guides/sdk-migration.md`](/sdks/migration).
