Agents SDK v0.5.0: Protocol message control, retry utilities, data parts, and @cloudflare/ai-chat v0.1.0
The latest release of the Agents SDK ↗ adds built-in retry utilities, per-connection protocol message control, and a fully rewritten @cloudflare/ai-chat with data parts, tool approval persistence, and zero breaking changes.
A new this.retry() method lets you retry any async operation with exponential backoff and jitter. You can pass an optional shouldRetry predicate to bail early on non-retryable errors.
class MyAgent extends Agent { async onRequest(request) { const result = await this.retry(() => fetch("https://example.com/api"), { maxRetries: 3, shouldRetry: (error) => error.status !== 404, }); return result; }}class MyAgent extends Agent { async onRequest(request: Request) { const result = await this.retry(() => fetch("https://example.com/api"), { maxRetries: 3, shouldRetry: (error) => error.status !== 404, }); return result; }}Retry options are also available per-task on queue(), schedule(), scheduleEvery(), and addMcpServer():
// Per-task retry configuration, persisted in SQLite alongside the taskawait this.schedule("sendReport", Date.now() + 60_000, { retry: { maxRetries: 5 },});
// Class-level retry defaultsclass MyAgent extends Agent { static options = { retry: { maxRetries: 3 }, };}// Per-task retry configuration, persisted in SQLite alongside the taskawait this.schedule("sendReport", Date.now() + 60_000, { retry: { maxRetries: 5 },});
// Class-level retry defaultsclass MyAgent extends Agent { static options = { retry: { maxRetries: 3 }, };}Retry options are validated eagerly at enqueue/schedule time, and invalid values throw immediately. Internal retries have also been added for workflow operations (terminateWorkflow, pauseWorkflow, and others) with Durable Object-aware error detection.
Agents automatically send JSON text frames (identity, state, MCP server lists) to every WebSocket connection. You can now suppress these per-connection for clients that cannot handle them — binary-only devices, MQTT clients, or lightweight embedded systems.
class MyAgent extends Agent { shouldSendProtocolMessages(connection, ctx) { // Suppress protocol messages for MQTT clients const subprotocol = ctx.request.headers.get("Sec-WebSocket-Protocol"); return subprotocol !== "mqtt"; }}class MyAgent extends Agent { shouldSendProtocolMessages(connection: Connection, ctx: ConnectionContext) { // Suppress protocol messages for MQTT clients const subprotocol = ctx.request.headers.get("Sec-WebSocket-Protocol"); return subprotocol !== "mqtt"; }}Connections with protocol messages disabled still fully participate in RPC and regular messaging. Use isConnectionProtocolEnabled(connection) to check a connection's status at any time. The flag persists across Durable Object hibernation.
See Protocol messages for full documentation.
The first stable release of @cloudflare/ai-chat ships alongside this release with a major refactor of AIChatAgent internals — new ResumableStream class, WebSocket ChatTransport, and simplified SSE parsing — with zero breaking changes. Existing code using AIChatAgent and useAgentChat works as-is.
Key new features:
- Data parts — Attach typed JSON blobs (
data-*) to messages alongside text. Supports reconciliation (type+id updates in-place), append, and transient parts (ephemeral viaonDatacallback). See Data parts. - Tool approval persistence — The
needsApprovalapproval UI now survives page refresh and DO hibernation. The streaming message is persisted to SQLite when a tool entersapproval-requestedstate. maxPersistedMessages— Cap SQLite message storage with automatic oldest-message deletion.bodyoption onuseAgentChat— Send custom data with every request (static or dynamic).- Incremental persistence — Hash-based cache to skip redundant SQL writes.
- Row size guard — Automatic two-pass compaction when messages approach the SQLite 2 MB limit.
autoContinueAfterToolResultdefaults totrue— Client-side tool results and tool approvals now automatically trigger a server continuation, matching server-executed tool behavior. SetautoContinueAfterToolResult: falseinuseAgentChatto restore the previous behavior.
Notable bug fixes:
- Resolved stream resumption race conditions
- Resolved an issue where
setMessagesfunctional updater sent empty arrays - Resolved an issue where client tool schemas were lost after DO hibernation
- Resolved
InvalidPromptErrorafter tool approval (approval.idwas dropped) - Resolved an issue where message metadata was not propagated on broadcast/resume paths
- Resolved an issue where
clearAll()did not clear in-memory chunk buffers - Resolved an issue where
reasoning-deltasilently dropped data whenreasoning-startwas missed during stream resumption
getQueue(), getQueues(), getSchedule(), dequeue(), dequeueAll(), and dequeueAllByCallback() were unnecessarily async despite only performing synchronous SQL operations. They now return values directly instead of wrapping them in Promises. This is backward compatible — existing code using await on these methods will continue to work.
- Fix TypeScript "excessively deep" error — A depth counter on
CanSerializeandIsSerializableParamtypes bails out totrueafter 10 levels of recursion, preventing the "Type instantiation is excessively deep" error with deeply nested types like AI SDKCoreMessage[]. - POST SSE keepalive — The POST SSE handler now sends
event: pingevery 30 seconds to keep the connection alive, matching the existing GET SSE handler behavior. This prevents POST response streams from being silently dropped by proxies during long-running tool calls. - Widened peer dependency ranges — Peer dependency ranges across packages have been widened to prevent cascading major bumps during 0.x minor releases.
@cloudflare/ai-chatand@cloudflare/codemodeare now marked as optional peer dependencies.
To update to the latest version:
npm i agents@latest @cloudflare/ai-chat@latest