← Back
Cloudflare
Cloudflare Agents SDK v0.8.0 adds readable state, idempotent schedules, and typed AgentClient

Readable State Property

Both useAgent (React) and AgentClient (vanilla JS) now expose a state property that reflects the current agent state in real-time. Previously, accessing state required manual tracking through the onStateUpdate callback. The new state property is reactive—components re-render automatically when state changes from either server updates or client-side setState() calls.

For React components, use agent.state directly without separate useState setup:

const agent = useAgent<GameAgent, GameState>({ agent: "game-agent", name: "room-123" });
return <div>Score: {agent.state?.score}</div>;
agent.setState({ ...agent.state, score: (agent.state?.score ?? 0) + 10 });

For vanilla JavaScript, AgentClient state is populated on server connect (from initialState) or when setState() is called:

const client = new AgentClient<GameAgent>({ agent: "game-agent", name: "room-123", host: "your-worker.workers.dev" });
console.log(client.state); // { score: 100 }

The existing onStateUpdate callback remains unchanged and continues to work alongside the new property.

Idempotent Schedule Deduplication

schedule() now prevents duplicate rows from accumulating across Durable Object restarts with a new idempotent option. Cron schedules are idempotent by default—calling schedule("0 * * * *", "tick") multiple times with identical parameters returns the existing row instead of creating a new one.

Delayed and date-scheduled types support opt-in idempotency:

async onStart() {
  // Safe across restarts—only one row is created
  await this.schedule(60, "maintenance", undefined, { idempotent: true });
}

The SDK emits helpful warnings to catch common mistakes:

  • A console.warn appears when schedule() is called inside onStart() without { idempotent: true }
  • If 10+ stale one-shot rows accumulate for the same callback, the SDK warns via console and a schedule:duplicate_warning diagnostics event

Full TypeScript Inference for AgentClient

AgentClient now accepts an optional agent type parameter for complete type inference on RPC calls, matching the typed experience of useAgent:

const client = new AgentClient<MyAgent>({ agent: "my-agent", host: window.location.host });

// Method names autocomplete, args and return types inferred
const value = await client.call("getValue");

// New stub proxy for direct RPC-style calls
await client.stub.getValue();
await client.stub.add(1, 2);

// State is automatically typed in callbacks
const client = new AgentClient<MyAgent>({
  agent: "my-agent",
  host: window.location.host,
  onStateUpdate: (state) => { /* state typed as MyAgent's state type */ }
});

The RPC type utilities (AgentMethods, AgentStub, RPCMethods) are now exported from agents/client for advanced typing scenarios.

Additional Improvements

Zod 4 Migration: The agents, @cloudflare/ai-chat, and @cloudflare/codemode packages now require zod ^4.0.0; Zod v3 is no longer supported.

@cloudflare/ai-chat Fixes:

  • Turn serialization now queues work to prevent concurrent streaming of user requests, tool continuations, and saveMessages()
  • Clicking stop during an active stream no longer splits assistant messages into multiple entries
  • Orphaned client IDs no longer leak into persistent storage

keepAlive() Stabilization: keepAlive() and keepAliveWhile() are no longer experimental. The functions now use lightweight in-memory ref counting instead of schedule rows, allowing multiple concurrent callers to share a single alarm cycle.

TanStack AI Integration: A new entry point @cloudflare/codemode/tanstack-ai adds support for TanStack AI's chat() as an alternative to the Vercel AI SDK's streamText().