{"id":305,"date":"2026-03-23T00:00:00","date_gmt":"2026-03-23T00:00:00","guid":{"rendered":"https:\/\/wordpress.securinsight.ca\/index.php\/2026\/03\/23\/agents-workers-agents-sdk-v0-8-0-readable-state-idempotent-schedules-typed-agentclient-and-zod-4\/"},"modified":"2026-03-23T00:00:00","modified_gmt":"2026-03-23T00:00:00","slug":"agents-workers-agents-sdk-v0-8-0-readable-state-idempotent-schedules-typed-agentclient-and-zod-4","status":"publish","type":"post","link":"https:\/\/wordpress.securinsight.ca\/index.php\/2026\/03\/23\/agents-workers-agents-sdk-v0-8-0-readable-state-idempotent-schedules-typed-agentclient-and-zod-4\/","title":{"rendered":"Agents, Workers &#8211; Agents SDK v0.8.0: readable state, idempotent schedules, typed AgentClient, and Zod 4"},"content":{"rendered":"<p>The latest release of the <a href=\"https:\/\/github.com\/cloudflare\/agents\" target=\"_blank\">Agents SDK<\/a> exposes agent state as a readable property, prevents duplicate schedule rows across Durable Object restarts, brings full TypeScript inference to <code>AgentClient<\/code>, and migrates to Zod 4.<\/p>\n<h4>Readable <code>state<\/code> on <code>useAgent<\/code> and <code>AgentClient<\/code><\/h4>\n<p>Both <code>useAgent<\/code> (React) and <code>AgentClient<\/code> (vanilla JS) now expose a <code>state<\/code> property that reflects the current agent state. Previously, reading state required manually tracking it through the <code>onStateUpdate<\/code> callback.<\/p>\n<p><strong>React (<code>useAgent<\/code>)<\/strong><\/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>const<\/span><span> <\/span><span>agent<\/span><span> <\/span><span>=<\/span><span> <\/span><span>useAgent<\/span><span>(<\/span><span>{<\/span><\/div><\/div><div><div><span><span>  <\/span><\/span><span>agent<\/span><span>:<\/span><span> <\/span><span>\"game-agent\"<\/span><span>,<\/span><\/div><\/div><div><div><span><span>  <\/span><\/span><span>name<\/span><span>:<\/span><span> <\/span><span>\"room-123\"<\/span><span>,<\/span><\/div><\/div><div><div><span>}<\/span><span>)<\/span><span>;<\/span><\/div><\/div><div><div>\n<\/div><\/div><div><div><span>\/\/ Read state directly \u2014 no separate useState + onStateUpdate needed<\/span><\/div><\/div><div><div><span>return<\/span><span> <\/span><span>&lt;<\/span><span>div<\/span><span>&gt;Score: {<\/span><span>agent<\/span><span>.<\/span><span>state<\/span><span>?.<\/span><span>score<\/span><span>}&lt;\/<\/span><span>div<\/span><span>&gt;;<\/span><\/div><\/div><div><div>\n<\/div><\/div><div><div><span>\/\/ Spread for partial updates<\/span><\/div><\/div><div><div><span>agent<\/span><span>.<\/span><span>setState<\/span><span>(<\/span><span>{<\/span><span> <\/span><span>...<\/span><span>agent<\/span><span>.<\/span><span>state<\/span><span>,<\/span><span> score<\/span><span>:<\/span><span> (<\/span><span>agent<\/span><span>.<\/span><span>state<\/span><span>?.<\/span><span>score<\/span><span> <\/span><span>??<\/span><span> <\/span><span>0<\/span><span>) <\/span><span>+<\/span><span> <\/span><span>10<\/span><span> <\/span><span>}<\/span><span>)<\/span><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>const<\/span><span> <\/span><span>agent<\/span><span> <\/span><span>=<\/span><span> <\/span><span>useAgent<\/span><span>&lt;<\/span><span>GameAgent<\/span><span>,<\/span><span> <\/span><span>GameState<\/span><span>&gt;<\/span><span>(<\/span><span>{<\/span><\/div><\/div><div><div><span><span>  <\/span><\/span><span>agent<\/span><span>:<\/span><span> <\/span><span>\"game-agent\"<\/span><span>,<\/span><\/div><\/div><div><div><span><span>  <\/span><\/span><span>name<\/span><span>:<\/span><span> <\/span><span>\"room-123\"<\/span><span>,<\/span><\/div><\/div><div><div><span>}<\/span><span>)<\/span><span>;<\/span><\/div><\/div><div><div>\n<\/div><\/div><div><div><span>\/\/ Read state directly \u2014 no separate useState + onStateUpdate needed<\/span><\/div><\/div><div><div><span>return<\/span><span> &lt;<\/span><span>div<\/span><span>&gt;<\/span><span>Score<\/span><span>: <\/span><span>{<\/span><span>agent.state?.<\/span><span>score<\/span><span>}<\/span><span><span>&lt;\/<\/span><span>div<\/span><span>&gt;<\/span><\/span><span>;<\/span><\/div><\/div><div><div>\n<\/div><\/div><div><div><span>\/\/ Spread for partial updates<\/span><\/div><\/div><div><div><span>agent<\/span><span>.<\/span><span>setState<\/span><span>(<\/span><span>{<\/span><span> <\/span><span>...<\/span><span>agent<\/span><span>.<\/span><span>state<\/span><span>,<\/span><span> score<\/span><span>:<\/span><span> (<\/span><span>agent<\/span><span>.<\/span><span>state<\/span><span>?.<\/span><span>score<\/span><span> <\/span><span>??<\/span><span> <\/span><span>0<\/span><span>) <\/span><span>+<\/span><span> <\/span><span>10<\/span><span> <\/span><span>}<\/span><span>)<\/span><span>;<\/span><\/div><\/div><\/code><\/pre>\n<div>\n<div><\/div>\n<\/div>\n<\/figure>\n<\/div><\/div>\n<\/li>\n<\/ul>\n<p><code>agent.state<\/code> is reactive \u2014 the component re-renders when state changes from either the server or a client-side <code>setState()<\/code> call.<\/p>\n<p><strong>Vanilla JS (<code>AgentClient<\/code>)<\/strong><\/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>const<\/span><span> <\/span><span>client<\/span><span> <\/span><span>=<\/span><span> <\/span><span>new<\/span><span> <\/span><span>AgentClient<\/span><span>(<\/span><span>{<\/span><\/div><\/div><div><div><span><span>  <\/span><\/span><span>agent<\/span><span>:<\/span><span> <\/span><span>\"game-agent\"<\/span><span>,<\/span><\/div><\/div><div><div><span><span>  <\/span><\/span><span>name<\/span><span>:<\/span><span> <\/span><span>\"room-123\"<\/span><span>,<\/span><\/div><\/div><div><div><span><span>  <\/span><\/span><span>host<\/span><span>:<\/span><span> <\/span><span>\"your-worker.workers.dev\"<\/span><span>,<\/span><\/div><\/div><div><div><span>}<\/span><span>)<\/span><span>;<\/span><\/div><\/div><div><div>\n<\/div><\/div><div><div><span>client<\/span><span>.<\/span><span>setState<\/span><span>(<\/span><span>{<\/span><span> score<\/span><span>:<\/span><span> <\/span><span>100<\/span><span> <\/span><span>}<\/span><span>)<\/span><span>;<\/span><\/div><\/div><div><div><span>console<\/span><span>.<\/span><span>log<\/span><span>(<\/span><span>client<\/span><span>.<\/span><span>state<\/span><span>)<\/span><span>;<\/span><span> <\/span><span>\/\/ { score: 100 }<\/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>const<\/span><span> <\/span><span>client<\/span><span> <\/span><span>=<\/span><span> <\/span><span>new<\/span><span> <\/span><span>AgentClient<\/span><span>&lt;<\/span><span>GameAgent<\/span><span>&gt;<\/span><span>(<\/span><span>{<\/span><\/div><\/div><div><div><span><span>  <\/span><\/span><span>agent<\/span><span>:<\/span><span> <\/span><span>\"game-agent\"<\/span><span>,<\/span><\/div><\/div><div><div><span><span>  <\/span><\/span><span>name<\/span><span>:<\/span><span> <\/span><span>\"room-123\"<\/span><span>,<\/span><\/div><\/div><div><div><span><span>  <\/span><\/span><span>host<\/span><span>:<\/span><span> <\/span><span>\"your-worker.workers.dev\"<\/span><span>,<\/span><\/div><\/div><div><div><span>}<\/span><span>)<\/span><span>;<\/span><\/div><\/div><div><div>\n<\/div><\/div><div><div><span>client<\/span><span>.<\/span><span>setState<\/span><span>(<\/span><span>{<\/span><span> score<\/span><span>:<\/span><span> <\/span><span>100<\/span><span> <\/span><span>}<\/span><span>)<\/span><span>;<\/span><\/div><\/div><div><div><span>console<\/span><span>.<\/span><span>log<\/span><span>(<\/span><span>client<\/span><span>.<\/span><span>state<\/span><span>)<\/span><span>;<\/span><span> <\/span><span>\/\/ { score: 100 }<\/span><\/div><\/div><\/code><\/pre>\n<div>\n<div><\/div>\n<\/div>\n<\/figure>\n<\/div><\/div>\n<\/li>\n<\/ul>\n<p>State starts as <code>undefined<\/code> and is populated when the server sends the initial state on connect (from <code>initialState<\/code>) or when <code>setState()<\/code> is called. Use optional chaining (<code>agent.state?.field<\/code>) for safe access. The <code>onStateUpdate<\/code> callback continues to work as before \u2014 the new <code>state<\/code> property is additive.<\/p>\n<h4>Idempotent <code>schedule()<\/code><\/h4>\n<p><code>schedule()<\/code> now supports an <code>idempotent<\/code> option that deduplicates by <code>(type, callback, payload)<\/code>, preventing duplicate rows from accumulating when called in places that run on every Durable Object restart such as <code>onStart()<\/code>.<\/p>\n<p><strong>Cron schedules are idempotent by default.<\/strong> Calling <code>schedule(\"0 * * * *\", \"tick\")<\/code> multiple times with the same callback, expression, and payload returns the existing schedule row instead of creating a new one. Pass <code>{ idempotent: false }<\/code> to override.<\/p>\n<p>Delayed and date-scheduled types support opt-in idempotency:<\/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>import <\/span><span>{<\/span><span><span> <\/span><span>Agent<\/span><span> <\/span><\/span><span>}<\/span><span> from <\/span><span>\"agents\"<\/span><span>;<\/span><\/div><\/div><div><div>\n<\/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>async<\/span><span> <\/span><span>onStart<\/span><span>()<\/span><span> <\/span><span>{<\/span><\/div><\/div><div><div><span>    <\/span><span>\/\/ Safe across restarts \u2014 only one row is created<\/span><\/div><\/div><div><div><span>    <\/span><span>await<\/span><span> <\/span><span>this<\/span><span>.<\/span><span>schedule<\/span><span>(<\/span><span>60<\/span><span>,<\/span><span> <\/span><span>\"maintenance\"<\/span><span>,<\/span><span> <\/span><span>undefined<\/span><span>,<\/span><span> <\/span><span>{<\/span><span> idempotent<\/span><span>:<\/span><span> <\/span><span>true<\/span><span> <\/span><span>}<\/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>import <\/span><span>{<\/span><span><span> <\/span><span>Agent<\/span><span> <\/span><\/span><span>}<\/span><span> from <\/span><span>\"agents\"<\/span><span>;<\/span><\/div><\/div><div><div>\n<\/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>async<\/span><span> <\/span><span>onStart<\/span><span>()<\/span><span> <\/span><span>{<\/span><\/div><\/div><div><div><span>    <\/span><span>\/\/ Safe across restarts \u2014 only one row is created<\/span><\/div><\/div><div><div><span>    <\/span><span>await<\/span><span> <\/span><span>this<\/span><span>.<\/span><span>schedule<\/span><span>(<\/span><span>60<\/span><span>,<\/span><span> <\/span><span>\"maintenance\"<\/span><span>,<\/span><span> <\/span><span>undefined<\/span><span>,<\/span><span> <\/span><span>{<\/span><span> idempotent<\/span><span>:<\/span><span> <\/span><span>true<\/span><span> <\/span><span>}<\/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>Two new warnings help catch common foot-guns:<\/p>\n<ul>\n<li>Calling <code>schedule()<\/code> inside <code>onStart()<\/code> without <code>{ idempotent: true }<\/code> emits a <code>console.warn<\/code> with actionable guidance (once per callback; skipped for cron and when <code>idempotent<\/code> is set explicitly).<\/li>\n<li>If an alarm cycle processes 10 or more stale one-shot rows for the same callback, the SDK emits a <code>console.warn<\/code> and a <code>schedule:duplicate_warning<\/code> diagnostics channel event.<\/li>\n<\/ul>\n<h4>Typed <code>AgentClient<\/code> with <code>call<\/code> inference and <code>stub<\/code> proxy<\/h4>\n<p><code>AgentClient<\/code> now accepts an optional agent type parameter for full type inference on RPC calls, matching the typed experience already available with <code>useAgent<\/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>const<\/span><span> <\/span><span>client<\/span><span> <\/span><span>=<\/span><span> <\/span><span>new<\/span><span> <\/span><span>AgentClient<\/span><span>(<\/span><span>{<\/span><\/div><\/div><div><div><span><span>  <\/span><\/span><span>agent<\/span><span>:<\/span><span> <\/span><span>\"my-agent\"<\/span><span>,<\/span><\/div><\/div><div><div><span><span>  <\/span><\/span><span>host<\/span><span>:<\/span><span> <\/span><span>window<\/span><span>.<\/span><span>location<\/span><span>.<\/span><span>host<\/span><span>,<\/span><\/div><\/div><div><div><span>}<\/span><span>)<\/span><span>;<\/span><\/div><\/div><div><div>\n<\/div><\/div><div><div><span>\/\/ Typed call \u2014 method name autocompletes, args and return type inferred<\/span><\/div><\/div><div><div><span>const<\/span><span> <\/span><span>value<\/span><span> <\/span><span>=<\/span><span> <\/span><span>await<\/span><span> <\/span><span>client<\/span><span>.<\/span><span>call<\/span><span>(<\/span><span>\"getValue\"<\/span><span>)<\/span><span>;<\/span><\/div><\/div><div><div>\n<\/div><\/div><div><div><span>\/\/ Typed stub \u2014 direct RPC-style proxy<\/span><\/div><\/div><div><div><span>await<\/span><span> <\/span><span>client<\/span><span>.<\/span><span>stub<\/span><span>.<\/span><span>getValue<\/span><span>()<\/span><span>;<\/span><\/div><\/div><div><div><span>await<\/span><span> <\/span><span>client<\/span><span>.<\/span><span>stub<\/span><span>.<\/span><span>add<\/span><span>(<\/span><span>1<\/span><span>,<\/span><span> <\/span><span>2<\/span><span>)<\/span><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>const<\/span><span> <\/span><span>client<\/span><span> <\/span><span>=<\/span><span> <\/span><span>new<\/span><span> <\/span><span>AgentClient<\/span><span>&lt;<\/span><span>MyAgent<\/span><span>&gt;<\/span><span>(<\/span><span>{<\/span><\/div><\/div><div><div><span><span>  <\/span><\/span><span>agent<\/span><span>:<\/span><span> <\/span><span>\"my-agent\"<\/span><span>,<\/span><\/div><\/div><div><div><span><span>  <\/span><\/span><span>host<\/span><span>:<\/span><span> <\/span><span>window<\/span><span>.<\/span><span>location<\/span><span>.<\/span><span>host<\/span><span>,<\/span><\/div><\/div><div><div><span>}<\/span><span>)<\/span><span>;<\/span><\/div><\/div><div><div>\n<\/div><\/div><div><div><span>\/\/ Typed call \u2014 method name autocompletes, args and return type inferred<\/span><\/div><\/div><div><div><span>const<\/span><span> <\/span><span>value<\/span><span> <\/span><span>=<\/span><span> <\/span><span>await<\/span><span> <\/span><span>client<\/span><span>.<\/span><span>call<\/span><span>(<\/span><span>\"getValue\"<\/span><span>)<\/span><span>;<\/span><\/div><\/div><div><div>\n<\/div><\/div><div><div><span>\/\/ Typed stub \u2014 direct RPC-style proxy<\/span><\/div><\/div><div><div><span>await<\/span><span> <\/span><span>client<\/span><span>.<\/span><span>stub<\/span><span>.<\/span><span>getValue<\/span><span>()<\/span><span>;<\/span><\/div><\/div><div><div><span>await<\/span><span> <\/span><span>client<\/span><span>.<\/span><span>stub<\/span><span>.<\/span><span>add<\/span><span>(<\/span><span>1<\/span><span>,<\/span><span> <\/span><span>2<\/span><span>)<\/span><span>;<\/span><\/div><\/div><\/code><\/pre>\n<div>\n<div><\/div>\n<\/div>\n<\/figure>\n<\/div><\/div>\n<\/li>\n<\/ul>\n<p>State is automatically inferred from the agent type, so <code>onStateUpdate<\/code> is also typed:<\/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>const<\/span><span> <\/span><span>client<\/span><span> <\/span><span>=<\/span><span> <\/span><span>new<\/span><span> <\/span><span>AgentClient<\/span><span>(<\/span><span>{<\/span><\/div><\/div><div><div><span><span>  <\/span><\/span><span>agent<\/span><span>:<\/span><span> <\/span><span>\"my-agent\"<\/span><span>,<\/span><\/div><\/div><div><div><span><span>  <\/span><\/span><span>host<\/span><span>:<\/span><span> <\/span><span>window<\/span><span>.<\/span><span>location<\/span><span>.<\/span><span>host<\/span><span>,<\/span><\/div><\/div><div><div><span>  <\/span><span>onStateUpdate<\/span><span>:<\/span><span> <\/span><span>(<\/span><span>state<\/span><span>)<\/span><span> <\/span><span>=&gt;<\/span><span> <\/span><span>{<\/span><\/div><\/div><div><div><span>    <\/span><span>\/\/ state is typed as MyAgent's state type<\/span><\/div><\/div><div><div><span>  <\/span><span>},<\/span><\/div><\/div><div><div><span>}<\/span><span>)<\/span><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>const<\/span><span> <\/span><span>client<\/span><span> <\/span><span>=<\/span><span> <\/span><span>new<\/span><span> <\/span><span>AgentClient<\/span><span>&lt;<\/span><span>MyAgent<\/span><span>&gt;<\/span><span>(<\/span><span>{<\/span><\/div><\/div><div><div><span><span>  <\/span><\/span><span>agent<\/span><span>:<\/span><span> <\/span><span>\"my-agent\"<\/span><span>,<\/span><\/div><\/div><div><div><span><span>  <\/span><\/span><span>host<\/span><span>:<\/span><span> <\/span><span>window<\/span><span>.<\/span><span>location<\/span><span>.<\/span><span>host<\/span><span>,<\/span><\/div><\/div><div><div><span>  <\/span><span>onStateUpdate<\/span><span>:<\/span><span> <\/span><span>(<\/span><span>state<\/span><span>)<\/span><span> <\/span><span>=&gt;<\/span><span> <\/span><span>{<\/span><\/div><\/div><div><div><span>    <\/span><span>\/\/ state is typed as MyAgent's state type<\/span><\/div><\/div><div><div><span>  <\/span><span>},<\/span><\/div><\/div><div><div><span>}<\/span><span>)<\/span><span>;<\/span><\/div><\/div><\/code><\/pre>\n<div>\n<div><\/div>\n<\/div>\n<\/figure>\n<\/div><\/div>\n<\/li>\n<\/ul>\n<p>Existing untyped usage continues to work without changes. The RPC type utilities (<code>AgentMethods<\/code>, <code>AgentStub<\/code>, <code>RPCMethods<\/code>) are now exported from <code>agents\/client<\/code> for advanced typing scenarios.<br \/>\n<code>agents<\/code>, <code>@cloudflare\/ai-chat<\/code>, and <code>@cloudflare\/codemode<\/code> now require <code>zod ^4.0.0<\/code>. Zod v3 is no longer supported.<\/p>\n<h4><code>@cloudflare\/ai-chat<\/code> fixes<\/h4>\n<ul>\n<li><strong>Turn serialization<\/strong> \u2014 <code>onChatMessage()<\/code> and <code>_reply()<\/code> work is now queued so user requests, tool continuations, and <code>saveMessages()<\/code> never stream concurrently.<\/li>\n<li><strong>Duplicate messages on stop<\/strong> \u2014 Clicking stop during an active stream no longer splits the assistant message into two entries.<\/li>\n<li><strong>Duplicate messages after tool calls<\/strong> \u2014 Orphaned client IDs no longer leak into persistent storage.<\/li>\n<\/ul>\n<h4><code>keepAlive()<\/code> and <code>keepAliveWhile()<\/code> are no longer experimental<\/h4>\n<p><code>keepAlive()<\/code> now uses a lightweight in-memory ref count instead of schedule rows. Multiple concurrent callers share a single alarm cycle. The <code>@experimental<\/code> tag has been removed from both <code>keepAlive()<\/code> and <code>keepAliveWhile()<\/code>.<\/p>\n<h4><code>@cloudflare\/codemode<\/code>: TanStack AI integration<\/h4>\n<p>A new entry point <code>@cloudflare\/codemode\/tanstack-ai<\/code> adds support for <a href=\"https:\/\/tanstack.com\/ai\" target=\"_blank\">TanStack AI&#8217;s<\/a> <code>chat()<\/code> as an alternative to the Vercel AI SDK&#8217;s <code>streamText()<\/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>import <\/span><span>{<\/span><\/div><\/div><div><div><span><span>  <\/span><\/span><span>createCodeTool<\/span><span>,<\/span><\/div><\/div><div><div><span><span>  <\/span><\/span><span>tanstackTools<\/span><span>,<\/span><\/div><\/div><div><div><span>}<\/span><span> from <\/span><span>\"@cloudflare\/codemode\/tanstack-ai\"<\/span><span>;<\/span><\/div><\/div><div><div><span>import <\/span><span>{<\/span><span><span> <\/span><span>chat<\/span><span> <\/span><\/span><span>}<\/span><span> from <\/span><span>\"@tanstack\/ai\"<\/span><span>;<\/span><\/div><\/div><div><div>\n<\/div><\/div><div><div><span>const<\/span><span> <\/span><span>codeTool<\/span><span> <\/span><span>=<\/span><span> <\/span><span>createCodeTool<\/span><span>(<\/span><span>{<\/span><\/div><\/div><div><div><span><span>  <\/span><\/span><span>tools<\/span><span>:<\/span><span> [<\/span><span>tanstackTools<\/span><span>(<\/span><span>myServerTools<\/span><span>)]<\/span><span>,<\/span><\/div><\/div><div><div><span>  <\/span><span>executor<\/span><span>,<\/span><\/div><\/div><div><div><span>}<\/span><span>)<\/span><span>;<\/span><\/div><\/div><div><div>\n<\/div><\/div><div><div><span>const<\/span><span> <\/span><span>stream<\/span><span> <\/span><span>=<\/span><span> <\/span><span>chat<\/span><span>(<\/span><span>{<\/span><span> <\/span><span>adapter<\/span><span>,<\/span><span> tools<\/span><span>:<\/span><span> [<\/span><span>codeTool<\/span><span>]<\/span><span>,<\/span><span> <\/span><span>messages<\/span><span> <\/span><span>}<\/span><span>)<\/span><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>import <\/span><span>{<\/span><span><span> <\/span><span>createCodeTool<\/span><\/span><span>,<\/span><span><span> <\/span><span>tanstackTools<\/span><span> <\/span><\/span><span>}<\/span><span> from <\/span><span>\"@cloudflare\/codemode\/tanstack-ai\"<\/span><span>;<\/span><\/div><\/div><div><div><span>import <\/span><span>{<\/span><span><span> <\/span><span>chat<\/span><span> <\/span><\/span><span>}<\/span><span> from <\/span><span>\"@tanstack\/ai\"<\/span><span>;<\/span><\/div><\/div><div><div>\n<\/div><\/div><div><div><span>const<\/span><span> <\/span><span>codeTool<\/span><span> <\/span><span>=<\/span><span> <\/span><span>createCodeTool<\/span><span>(<\/span><span>{<\/span><\/div><\/div><div><div><span><span>  <\/span><\/span><span>tools<\/span><span>:<\/span><span> [<\/span><span>tanstackTools<\/span><span>(<\/span><span>myServerTools<\/span><span>)]<\/span><span>,<\/span><\/div><\/div><div><div><span>  <\/span><span>executor<\/span><span>,<\/span><\/div><\/div><div><div><span>}<\/span><span>)<\/span><span>;<\/span><\/div><\/div><div><div>\n<\/div><\/div><div><div><span>const<\/span><span> <\/span><span>stream<\/span><span> <\/span><span>=<\/span><span> <\/span><span>chat<\/span><span>(<\/span><span>{<\/span><span> <\/span><span>adapter<\/span><span>,<\/span><span> tools<\/span><span>:<\/span><span> [<\/span><span>codeTool<\/span><span>]<\/span><span>,<\/span><span> <\/span><span>messages<\/span><span> <\/span><span>}<\/span><span>)<\/span><span>;<\/span><\/div><\/div><\/code><\/pre>\n<div>\n<div><\/div>\n<\/div>\n<\/figure>\n<\/div><\/div>\n<\/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 exposes agent state as a readable property, prevents duplicate schedule rows across Durable Object restarts, brings full TypeScript inference to AgentClient, and migrates to Zod 4. Readable state on useAgent and AgentClient Both useAgent (React) and AgentClient (vanilla JS) now expose a state property that reflects the current [&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-305","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/wordpress.securinsight.ca\/index.php\/wp-json\/wp\/v2\/posts\/305","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=305"}],"version-history":[{"count":0,"href":"https:\/\/wordpress.securinsight.ca\/index.php\/wp-json\/wp\/v2\/posts\/305\/revisions"}],"wp:attachment":[{"href":"https:\/\/wordpress.securinsight.ca\/index.php\/wp-json\/wp\/v2\/media?parent=305"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wordpress.securinsight.ca\/index.php\/wp-json\/wp\/v2\/categories?post=305"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wordpress.securinsight.ca\/index.php\/wp-json\/wp\/v2\/tags?post=305"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}