{"id":231,"date":"2026-02-17T00:00:00","date_gmt":"2026-02-17T00:00:00","guid":{"rendered":"https:\/\/wordpress.securinsight.ca\/index.php\/2026\/02\/17\/agents-workers-agents-sdk-v0-5-0-protocol-message-control-retry-utilities-data-parts-and-cloudflare-ai-chat-v0-1-0\/"},"modified":"2026-02-17T00:00:00","modified_gmt":"2026-02-17T00:00:00","slug":"agents-workers-agents-sdk-v0-5-0-protocol-message-control-retry-utilities-data-parts-and-cloudflare-ai-chat-v0-1-0","status":"publish","type":"post","link":"https:\/\/wordpress.securinsight.ca\/index.php\/2026\/02\/17\/agents-workers-agents-sdk-v0-5-0-protocol-message-control-retry-utilities-data-parts-and-cloudflare-ai-chat-v0-1-0\/","title":{"rendered":"Agents, Workers &#8211; Agents SDK v0.5.0: Protocol message control, retry utilities, data parts, and @cloudflare\/ai-chat v0.1.0"},"content":{"rendered":"<p>The latest release of the <a href=\"https:\/\/github.com\/cloudflare\/agents\" target=\"_blank\">Agents SDK<\/a> adds built-in retry utilities, per-connection protocol message control, and a fully rewritten <code>@cloudflare\/ai-chat<\/code> with data parts, tool approval persistence, and zero breaking changes.<\/p>\n<h4>Retry utilities<\/h4>\n<p>A new <code>this.retry()<\/code> method lets you retry any async operation with exponential backoff and jitter. You can pass an optional <code>shouldRetry<\/code> predicate to bail early on non-retryable errors.<\/p>\n<ul>\n<li>\n<p>JavaScript<\/p>\n<div>\n<div>\n<figure>\n<pre data-language=\"js\"><code class=\"language-js\"><div><div><span>class<\/span><span> <\/span><span>MyAgent<\/span><span> <\/span><span>extends<\/span><span> <\/span><span>Agent<\/span><span> <\/span><span>{<\/span><\/div><\/div><div><div><span>  <\/span><span>async<\/span><span> <\/span><span>onRequest<\/span><span>(<\/span><span>request<\/span><span>)<\/span><span> <\/span><span>{<\/span><\/div><\/div><div><div><span>    <\/span><span>const<\/span><span> <\/span><span>result<\/span><span> <\/span><span>=<\/span><span> <\/span><span>await<\/span><span> <\/span><span>this<\/span><span>.<\/span><span>retry<\/span><span>(<\/span><span>()<\/span><span> <\/span><span>=&gt;<\/span><span> <\/span><span>fetch<\/span><span>(<\/span><span>\"https:\/\/example.com\/api\"<\/span><span>)<\/span><span>,<\/span><span> <\/span><span>{<\/span><\/div><\/div><div><div><span><span>      <\/span><\/span><span>maxRetries<\/span><span>:<\/span><span> <\/span><span>3<\/span><span>,<\/span><\/div><\/div><div><div><span>      <\/span><span>shouldRetry<\/span><span>:<\/span><span> <\/span><span>(<\/span><span>error<\/span><span>)<\/span><span> <\/span><span>=&gt;<\/span><span> <\/span><span>error<\/span><span>.<\/span><span>status<\/span><span> <\/span><span>!==<\/span><span> <\/span><span>404<\/span><span>,<\/span><\/div><\/div><div><div><span>    <\/span><span>}<\/span><span>)<\/span><span>;<\/span><\/div><\/div><div><div><span>    <\/span><span>return<\/span><span> <\/span><span>result<\/span><span>;<\/span><\/div><\/div><div><div><span>  <\/span><span>}<\/span><\/div><\/div><div><div><span>}<\/span><\/div><\/div><\/code><\/pre>\n<div>\n<div><\/div>\n<\/div>\n<\/figure>\n<\/div><\/div>\n<\/li>\n<li>\n<p>TypeScript<\/p>\n<div>\n<div>\n<figure>\n<pre data-language=\"ts\"><code class=\"language-ts\"><div><div><span>class<\/span><span> <\/span><span>MyAgent<\/span><span> <\/span><span>extends<\/span><span> <\/span><span>Agent<\/span><span> <\/span><span>{<\/span><\/div><\/div><div><div><span>  <\/span><span>async<\/span><span> <\/span><span>onRequest<\/span><span>(<\/span><span>request<\/span><span>:<\/span><span> <\/span><span>Request<\/span><span>)<\/span><span> <\/span><span>{<\/span><\/div><\/div><div><div><span>    <\/span><span>const<\/span><span> <\/span><span>result<\/span><span> <\/span><span>=<\/span><span> <\/span><span>await<\/span><span> <\/span><span>this<\/span><span>.<\/span><span>retry<\/span><span>(<\/span><span>()<\/span><span> <\/span><span>=&gt;<\/span><span> <\/span><span>fetch<\/span><span>(<\/span><span>\"https:\/\/example.com\/api\"<\/span><span>)<\/span><span>,<\/span><span> <\/span><span>{<\/span><\/div><\/div><div><div><span><span>      <\/span><\/span><span>maxRetries<\/span><span>:<\/span><span> <\/span><span>3<\/span><span>,<\/span><\/div><\/div><div><div><span>      <\/span><span>shouldRetry<\/span><span>:<\/span><span> <\/span><span>(<\/span><span>error<\/span><span>)<\/span><span> <\/span><span>=&gt;<\/span><span> <\/span><span>error<\/span><span>.<\/span><span>status<\/span><span> <\/span><span>!==<\/span><span> <\/span><span>404<\/span><span>,<\/span><\/div><\/div><div><div><span>    <\/span><span>}<\/span><span>)<\/span><span>;<\/span><\/div><\/div><div><div><span>    <\/span><span>return<\/span><span> <\/span><span>result<\/span><span>;<\/span><\/div><\/div><div><div><span>  <\/span><span>}<\/span><\/div><\/div><div><div><span>}<\/span><\/div><\/div><\/code><\/pre>\n<div>\n<div><\/div>\n<\/div>\n<\/figure>\n<\/div><\/div>\n<\/li>\n<\/ul>\n<p>Retry options are also available per-task on <code>queue()<\/code>, <code>schedule()<\/code>, <code>scheduleEvery()<\/code>, and <code>addMcpServer()<\/code>:<\/p>\n<ul>\n<li>\n<p>JavaScript<\/p>\n<div>\n<div>\n<figure>\n<pre data-language=\"js\"><code class=\"language-js\"><div><div><span>\/\/ Per-task retry configuration, persisted in SQLite alongside the task<\/span><\/div><\/div><div><div><span>await<\/span><span> <\/span><span>this<\/span><span>.<\/span><span>schedule<\/span><span>(<\/span><span>\"sendReport\"<\/span><span>,<\/span><span> <\/span><span>Date<\/span><span>.<\/span><span>now<\/span><span>() <\/span><span>+<\/span><span> <\/span><span>60_000<\/span><span>,<\/span><span> <\/span><span>{<\/span><\/div><\/div><div><div><span><span>  <\/span><\/span><span>retry<\/span><span>:<\/span><span> <\/span><span>{<\/span><span> maxRetries<\/span><span>:<\/span><span> <\/span><span>5<\/span><span> <\/span><span>},<\/span><\/div><\/div><div><div><span>}<\/span><span>)<\/span><span>;<\/span><\/div><\/div><div><div>\n<\/div><\/div><div><div><span>\/\/ Class-level retry defaults<\/span><\/div><\/div><div><div><span>class<\/span><span> <\/span><span>MyAgent<\/span><span> <\/span><span>extends<\/span><span> <\/span><span>Agent<\/span><span> <\/span><span>{<\/span><\/div><\/div><div><div><span>  <\/span><span>static<\/span><span> options <\/span><span>=<\/span><span> <\/span><span>{<\/span><\/div><\/div><div><div><span><span>    <\/span><\/span><span>retry<\/span><span>:<\/span><span> <\/span><span>{<\/span><span> maxRetries<\/span><span>:<\/span><span> <\/span><span>3<\/span><span> <\/span><span>},<\/span><\/div><\/div><div><div><span>  <\/span><span>};<\/span><\/div><\/div><div><div><span>}<\/span><\/div><\/div><\/code><\/pre>\n<div>\n<div><\/div>\n<\/div>\n<\/figure>\n<\/div><\/div>\n<\/li>\n<li>\n<p>TypeScript<\/p>\n<div>\n<div>\n<figure>\n<pre data-language=\"ts\"><code class=\"language-ts\"><div><div><span>\/\/ Per-task retry configuration, persisted in SQLite alongside the task<\/span><\/div><\/div><div><div><span>await<\/span><span> <\/span><span>this<\/span><span>.<\/span><span>schedule<\/span><span>(<\/span><span>\"sendReport\"<\/span><span>,<\/span><span> <\/span><span>Date<\/span><span>.<\/span><span>now<\/span><span>() <\/span><span>+<\/span><span> <\/span><span>60_000<\/span><span>,<\/span><span> <\/span><span>{<\/span><\/div><\/div><div><div><span><span>  <\/span><\/span><span>retry<\/span><span>:<\/span><span> <\/span><span>{<\/span><span> maxRetries<\/span><span>:<\/span><span> <\/span><span>5<\/span><span> <\/span><span>},<\/span><\/div><\/div><div><div><span>}<\/span><span>)<\/span><span>;<\/span><\/div><\/div><div><div>\n<\/div><\/div><div><div><span>\/\/ Class-level retry defaults<\/span><\/div><\/div><div><div><span>class<\/span><span> <\/span><span>MyAgent<\/span><span> <\/span><span>extends<\/span><span> <\/span><span>Agent<\/span><span> <\/span><span>{<\/span><\/div><\/div><div><div><span>  <\/span><span>static<\/span><span> options <\/span><span>=<\/span><span> <\/span><span>{<\/span><\/div><\/div><div><div><span><span>    <\/span><\/span><span>retry<\/span><span>:<\/span><span> <\/span><span>{<\/span><span> maxRetries<\/span><span>:<\/span><span> <\/span><span>3<\/span><span> <\/span><span>},<\/span><\/div><\/div><div><div><span>  <\/span><span>};<\/span><\/div><\/div><div><div><span>}<\/span><\/div><\/div><\/code><\/pre>\n<div>\n<div><\/div>\n<\/div>\n<\/figure>\n<\/div><\/div>\n<\/li>\n<\/ul>\n<p>Retry options are validated eagerly at enqueue\/schedule time, and invalid values throw immediately. Internal retries have also been added for workflow operations (<code>terminateWorkflow<\/code>, <code>pauseWorkflow<\/code>, and others) with Durable Object-aware error detection.<\/p>\n<h4>Per-connection protocol message control<\/h4>\n<p>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 \u2014 binary-only devices, MQTT clients, or lightweight embedded systems.<\/p>\n<ul>\n<li>\n<p>JavaScript<\/p>\n<div>\n<div>\n<figure>\n<pre data-language=\"js\"><code class=\"language-js\"><div><div><span>class<\/span><span> <\/span><span>MyAgent<\/span><span> <\/span><span>extends<\/span><span> <\/span><span>Agent<\/span><span> <\/span><span>{<\/span><\/div><\/div><div><div><span>  <\/span><span>shouldSendProtocolMessages<\/span><span>(<\/span><span>connection<\/span><span>,<\/span><span> <\/span><span>ctx<\/span><span>)<\/span><span> <\/span><span>{<\/span><\/div><\/div><div><div><span>    <\/span><span>\/\/ Suppress protocol messages for MQTT clients<\/span><\/div><\/div><div><div><span>    <\/span><span>const<\/span><span> <\/span><span>subprotocol<\/span><span> <\/span><span>=<\/span><span> <\/span><span>ctx<\/span><span>.<\/span><span>request<\/span><span>.<\/span><span>headers<\/span><span>.<\/span><span>get<\/span><span>(<\/span><span>\"Sec-WebSocket-Protocol\"<\/span><span>)<\/span><span>;<\/span><\/div><\/div><div><div><span>    <\/span><span>return<\/span><span> <\/span><span>subprotocol<\/span><span> <\/span><span>!==<\/span><span> <\/span><span>\"mqtt\"<\/span><span>;<\/span><\/div><\/div><div><div><span>  <\/span><span>}<\/span><\/div><\/div><div><div><span>}<\/span><\/div><\/div><\/code><\/pre>\n<div>\n<div><\/div>\n<\/div>\n<\/figure>\n<\/div><\/div>\n<\/li>\n<li>\n<p>TypeScript<\/p>\n<div>\n<div>\n<figure>\n<pre data-language=\"ts\"><code class=\"language-ts\"><div><div><span>class<\/span><span> <\/span><span>MyAgent<\/span><span> <\/span><span>extends<\/span><span> <\/span><span>Agent<\/span><span> <\/span><span>{<\/span><\/div><\/div><div><div><span>  <\/span><span>shouldSendProtocolMessages<\/span><span>(<\/span><span>connection<\/span><span>:<\/span><span> <\/span><span>Connection<\/span><span>,<\/span><span> <\/span><span>ctx<\/span><span>:<\/span><span> <\/span><span>ConnectionContext<\/span><span>)<\/span><span> <\/span><span>{<\/span><\/div><\/div><div><div><span>    <\/span><span>\/\/ Suppress protocol messages for MQTT clients<\/span><\/div><\/div><div><div><span>    <\/span><span>const<\/span><span> <\/span><span>subprotocol<\/span><span> <\/span><span>=<\/span><span> <\/span><span>ctx<\/span><span>.<\/span><span>request<\/span><span>.<\/span><span>headers<\/span><span>.<\/span><span>get<\/span><span>(<\/span><span>\"Sec-WebSocket-Protocol\"<\/span><span>)<\/span><span>;<\/span><\/div><\/div><div><div><span>    <\/span><span>return<\/span><span> <\/span><span>subprotocol<\/span><span> <\/span><span>!==<\/span><span> <\/span><span>\"mqtt\"<\/span><span>;<\/span><\/div><\/div><div><div><span>  <\/span><span>}<\/span><\/div><\/div><div><div><span>}<\/span><\/div><\/div><\/code><\/pre>\n<div>\n<div><\/div>\n<\/div>\n<\/figure>\n<\/div><\/div>\n<\/li>\n<\/ul>\n<p>Connections with protocol messages disabled still fully participate in RPC and regular messaging. Use <code>isConnectionProtocolEnabled(connection)<\/code> to check a connection&#8217;s status at any time. The flag persists across Durable Object hibernation.<\/p>\n<p>See <a href=\"https:\/\/developers.cloudflare.com\/agents\/api-reference\/protocol-messages\/\">Protocol messages<\/a> for full documentation.<\/p>\n<h4><code>@cloudflare\/ai-chat<\/code> v0.1.0<\/h4>\n<p>The first stable release of <code>@cloudflare\/ai-chat<\/code> ships alongside this release with a major refactor of <code>AIChatAgent<\/code> internals \u2014 new <code>ResumableStream<\/code> class, WebSocket <code>ChatTransport<\/code>, and simplified SSE parsing \u2014 with zero breaking changes. Existing code using <code>AIChatAgent<\/code> and <code>useAgentChat<\/code> works as-is.<\/p>\n<p>Key new features:<\/p>\n<ul>\n<li><strong>Data parts<\/strong> \u2014 Attach typed JSON blobs (<code>data-*<\/code>) to messages alongside text. Supports reconciliation (type+id updates in-place), append, and transient parts (ephemeral via <code>onData<\/code> callback). See <a href=\"https:\/\/developers.cloudflare.com\/agents\/api-reference\/chat-agents\/#data-parts\">Data parts<\/a>.<\/li>\n<li><strong>Tool approval persistence<\/strong> \u2014 The <code>needsApproval<\/code> approval UI now survives page refresh and DO hibernation. The streaming message is persisted to SQLite when a tool enters <code>approval-requested<\/code> state.<\/li>\n<li><strong><code>maxPersistedMessages<\/code><\/strong> \u2014 Cap SQLite message storage with automatic oldest-message deletion.<\/li>\n<li><strong><code>body<\/code> option on <code>useAgentChat<\/code><\/strong> \u2014 Send custom data with every request (static or dynamic).<\/li>\n<li><strong>Incremental persistence<\/strong> \u2014 Hash-based cache to skip redundant SQL writes.<\/li>\n<li><strong>Row size guard<\/strong> \u2014 Automatic two-pass compaction when messages approach the SQLite 2 MB limit.<\/li>\n<li><strong><code>autoContinueAfterToolResult<\/code> defaults to <code>true<\/code><\/strong> \u2014 Client-side tool results and tool approvals now automatically trigger a server continuation, matching server-executed tool behavior. Set <code>autoContinueAfterToolResult: false<\/code> in <code>useAgentChat<\/code> to restore the previous behavior.<\/li>\n<\/ul>\n<p>Notable bug fixes:<\/p>\n<ul>\n<li>Resolved stream resumption race conditions<\/li>\n<li>Resolved an issue where <code>setMessages<\/code> functional updater sent empty arrays<\/li>\n<li>Resolved an issue where client tool schemas were lost after DO hibernation<\/li>\n<li>Resolved <code>InvalidPromptError<\/code> after tool approval (<code>approval.id<\/code> was dropped)<\/li>\n<li>Resolved an issue where message metadata was not propagated on broadcast\/resume paths<\/li>\n<li>Resolved an issue where <code>clearAll()<\/code> did not clear in-memory chunk buffers<\/li>\n<li>Resolved an issue where <code>reasoning-delta<\/code> silently dropped data when <code>reasoning-start<\/code> was missed during stream resumption<\/li>\n<\/ul>\n<h4>Synchronous queue and schedule getters<\/h4>\n<p><code>getQueue()<\/code>, <code>getQueues()<\/code>, <code>getSchedule()<\/code>, <code>dequeue()<\/code>, <code>dequeueAll()<\/code>, and <code>dequeueAllByCallback()<\/code> were unnecessarily <code>async<\/code> despite only performing synchronous SQL operations. They now return values directly instead of wrapping them in Promises. This is backward compatible \u2014 existing code using <code>await<\/code> on these methods will continue to work.<\/p>\n<h4>Other improvements<\/h4>\n<ul>\n<li><strong>Fix TypeScript &#8220;excessively deep&#8221; error<\/strong> \u2014 A depth counter on <code>CanSerialize<\/code> and <code>IsSerializableParam<\/code> types bails out to <code>true<\/code> after 10 levels of recursion, preventing the &#8220;Type instantiation is excessively deep&#8221; error with deeply nested types like AI SDK <code>CoreMessage[]<\/code>.<\/li>\n<li><strong>POST SSE keepalive<\/strong> \u2014 The POST SSE handler now sends <code>event: ping<\/code> every 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.<\/li>\n<li><strong>Widened peer dependency ranges<\/strong> \u2014 Peer dependency ranges across packages have been widened to prevent cascading major bumps during 0.x minor releases. <code>@cloudflare\/ai-chat<\/code> and <code>@cloudflare\/codemode<\/code> are now marked as optional peer dependencies.<\/li>\n<\/ul>\n<h4>Upgrade<\/h4>\n<p>To update to the latest version:<\/p>\n<div>\n<figure>\n<pre data-language=\"sh\"><code class=\"language-sh\"><div><div><span>npm<\/span><span> <\/span><span>i<\/span><span> <\/span><span>agents@latest<\/span><span> <\/span><span>@cloudflare\/ai-chat@latest<\/span><\/div><\/div><\/code><\/pre>\n<div>\n<div><\/div>\n<\/div>\n<\/figure>\n<\/div>","protected":false},"excerpt":{"rendered":"<p>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. Retry utilities A new this.retry() method lets you retry any async operation with exponential backoff and jitter. You can pass an optional shouldRetry predicate to [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-231","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/wordpress.securinsight.ca\/index.php\/wp-json\/wp\/v2\/posts\/231","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wordpress.securinsight.ca\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wordpress.securinsight.ca\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.securinsight.ca\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/wordpress.securinsight.ca\/index.php\/wp-json\/wp\/v2\/comments?post=231"}],"version-history":[{"count":0,"href":"https:\/\/wordpress.securinsight.ca\/index.php\/wp-json\/wp\/v2\/posts\/231\/revisions"}],"wp:attachment":[{"href":"https:\/\/wordpress.securinsight.ca\/index.php\/wp-json\/wp\/v2\/media?parent=231"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wordpress.securinsight.ca\/index.php\/wp-json\/wp\/v2\/categories?post=231"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wordpress.securinsight.ca\/index.php\/wp-json\/wp\/v2\/tags?post=231"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}