Skip to main content
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) 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).
For per-service backend changes (cluster, runtime, a2a, etc.), see each service’s own README and ADRs under backend/docs/adr/. The format is based on Keep a Changelog and the contract version follows Semantic Versioning.

Versioning

BumpTriggered by
MAJORRemoving routes, renaming required fields, changing the shape of an existing response, changing auth semantics (e.g. tightening the ownership model), changing error code semantics.
MINORAdding new routes, adding optional request fields, adding optional response fields, adding new code values.
PATCHDocumentation, examples, OpenAPI description polish, generator config tweaks that don’t change emitted code.
The TypeScript and Go SDK packages share one version line. They are always cut together from the same generator run; a mismatched pair 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 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/:
    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 packageVersion= in sdks/openapi-sdk/generate.sh in the same commit (lines 88–95). Both 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 publish workflow: stamps the changelog header with today’s date, tags the meta repo sdk-v<version>, publishes @beeos-ai/sdk to npm, and pushes the generated Go SDK to github.com/beeos-ai/sdk-go (which is itself a release-tagged repo so go get resolves the new tag).
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]

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!.idconv.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 replytext 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 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 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
    { "error": { "type": "…", "code": "…", "message": "…",
                "param": "…", "request_id": "…" } }
    
    with code drawn from the table in docs/reference/errors.md. 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 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)


[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.