---
title: AI Changelog
image: https://developers.cloudflare.com/cf-twitter-card.png
---

> Documentation Index  
> Fetch the complete documentation index at: https://developers.cloudflare.com/changelog/llms.txt  
> Use this file to discover all available pages before exploring further. 

[Skip to content](#%5Ftop) 

# Changelog

New updates and improvements at Cloudflare.

[ Subscribe to RSS ](https://developers.cloudflare.com/changelog/rss/index.xml) [ View RSS feeds ](https://developers.cloudflare.com/fundamentals/new-features/available-rss-feeds/) 

AI

![hero image](https://developers.cloudflare.com/_astro/hero.CVYJHPAd_26AMqX.svg) 

Mar 02, 2026
1. ### [Get started with AI Gateway automatically](https://developers.cloudflare.com/changelog/post/2026-03-02-default-gateway/)  
[ AI Gateway ](https://developers.cloudflare.com/ai-gateway/)  
You can now start using AI Gateway with a single API call — no setup required. Use `default` as your gateway ID, and AI Gateway creates one for you automatically on the first request.  
To try it out, [create an API token](https://developers.cloudflare.com/fundamentals/api/get-started/create-token/) with `AI Gateway - Read`, `AI Gateway - Edit`, and `Workers AI - Read` permissions, then run:  
Terminal window  
```  
curl -X POST https://gateway.ai.cloudflare.com/v1/$CLOUDFLARE_ACCOUNT_ID/default/compat/chat/completions \  --header "cf-aig-authorization: Bearer $CLOUDFLARE_API_TOKEN" \  --header 'Content-Type: application/json' \  --data '{    "model": "workers-ai/@cf/meta/llama-3.3-70b-instruct-fp8-fast",    "messages": [      {        "role": "user",        "content": "What is Cloudflare?"      }    ]  }'  
```  
AI Gateway gives you logging, caching, rate limiting, and access to multiple AI providers through a single endpoint. For more information, refer to [Get started](https://developers.cloudflare.com/ai-gateway/get-started/).

Feb 25, 2026
1. ### [Agents SDK v0.6.0: RPC transport for MCP, optional OAuth, hardened schema conversion, and @cloudflare/ai-chat fixes](https://developers.cloudflare.com/changelog/post/2026-02-25-agents-sdk-v060/)  
[ Agents ](https://developers.cloudflare.com/agents/)[ Workers ](https://developers.cloudflare.com/workers/)  
The latest release of the [Agents SDK ↗](https://github.com/cloudflare/agents) lets you define an Agent and an McpAgent in the same Worker and connect them over RPC — no HTTP, no network overhead. It also makes OAuth opt-in for simple MCP connections, hardens the schema converter for production workloads, and ships a batch of `@cloudflare/ai-chat` reliability fixes.  
#### RPC transport for MCP  
You can now connect an Agent to an McpAgent in the same Worker using a Durable Object binding instead of an HTTP URL. The connection stays entirely within the Cloudflare runtime — no network round-trips, no serialization overhead.  
Pass the Durable Object namespace directly to `addMcpServer`:

  * [  JavaScript ](#tab-panel-3496)
  * [  TypeScript ](#tab-panel-3497)  
JavaScript  
```  
import { Agent } from "agents";  
export class MyAgent extends Agent {  async onStart() {    // Connect via DO binding — no HTTP, no network overhead    await this.addMcpServer("counter", env.MY_MCP);  
    // With props for per-user context    await this.addMcpServer("counter", env.MY_MCP, {      props: { userId: "user-123", role: "admin" },    });  }}  
```  
TypeScript  
```  
import { Agent } from "agents";  
export class MyAgent extends Agent {  async onStart() {    // Connect via DO binding — no HTTP, no network overhead    await this.addMcpServer("counter", env.MY_MCP);  
    // With props for per-user context    await this.addMcpServer("counter", env.MY_MCP, {      props: { userId: "user-123", role: "admin" },    });  }}  
```  
The `addMcpServer` method now accepts `string | DurableObjectNamespace` as the second parameter with full TypeScript overloads, so HTTP and RPC paths are type-safe and cannot be mixed.  
Key capabilities:

  * **Hibernation support** — RPC connections survive Durable Object hibernation automatically. The binding name and props are persisted to storage and restored on wake-up, matching the behavior of HTTP MCP connections.
  * **Deduplication** — Calling `addMcpServer` with the same server name returns the existing connection instead of creating duplicates. Connection IDs are stable across hibernation restore.
  * **Smaller surface area** — The RPC transport internals have been rewritten and reduced from 609 lines to 245 lines. `RPCServerTransport` now uses `JSONRPCMessageSchema` from the MCP SDK for validation instead of hand-written checks.  
Note  
RPC transport is experimental. The API may change based on feedback. Refer to [the tracking issue ↗](https://github.com/cloudflare/agents/issues/565) for updates.  
#### Optional OAuth for MCP connections  
`addMcpServer()` no longer eagerly creates an OAuth provider for every connection. For servers that do not require authentication, a simple call is all you need:

  * [  JavaScript ](#tab-panel-3494)
  * [  TypeScript ](#tab-panel-3495)  
JavaScript  
```  
// No callbackHost, no OAuth config — just worksawait this.addMcpServer("my-server", "https://mcp.example.com");  
```  
TypeScript  
```  
// No callbackHost, no OAuth config — just worksawait this.addMcpServer("my-server", "https://mcp.example.com");  
```  
If the server responds with a 401, the SDK throws a clear error: `"This MCP server requires OAuth authentication. Provide callbackHost in addMcpServer options to enable the OAuth flow."` The restore-from-storage flow also handles missing callback URLs gracefully, skipping auth provider creation for non-OAuth servers.  
#### Hardened JSON Schema to TypeScript converter  
The schema converter used by `generateTypes()` and `getAITools()` now handles edge cases that previously caused crashes in production:

  * **Depth and circular reference guards** — Prevents stack overflows on recursive or deeply nested schemas
  * **`$ref` resolution** — Supports internal JSON Pointers (`#/definitions/...`, `#/$defs/...`, `#`)
  * **Tuple support** — `prefixItems` (JSON Schema 2020-12) and array `items` (draft-07)
  * **OpenAPI 3.0 `nullable: true`** — Supported across all schema branches
  * **Per-tool error isolation** — One malformed schema cannot crash the full pipeline in `generateTypes()` or `getAITools()`
  * **Missing `inputSchema` fallback** — `getAITools()` falls back to `{ type: "object" }` instead of throwing  
#### `@cloudflare/ai-chat` fixes

  * **Tool denial flow** — Denied tool approvals (`approved: false`) now transition to `output-denied` with a `tool_result`, fixing Anthropic provider compatibility. Custom denial messages are supported via `state: "output-error"` and `errorText`.
  * **Abort/cancel support** — Streaming responses now properly cancel the reader loop when the abort signal fires and send a done signal to the client.
  * **Duplicate message persistence** — `persistMessages()` now reconciles assistant messages by content and order, preventing duplicate rows when clients resend full history.
  * **`requestId` in `OnChatMessageOptions`** — Handlers can now send properly-tagged error responses for pre-stream failures.
  * **`redacted_thinking` preservation** — The message sanitizer no longer strips Anthropic `redacted_thinking` blocks.
  * **`/get-messages` reliability** — Endpoint handling moved from a prototype `onRequest()` override to a constructor wrapper, so it works even when users override `onRequest` without calling `super.onRequest()`.
  * **Client tool APIs undeprecated** — `createToolsFromClientSchemas`, `clientTools`, `AITool`, `extractClientToolSchemas`, and the `tools` option on `useAgentChat` are restored for SDK use cases where tools are defined dynamically at runtime.
  * **`jsonSchema` initialization** — Fixed `jsonSchema not initialized` error when calling `getAITools()` in `onChatMessage`.  
#### Upgrade  
To update to the latest version:  
Terminal window  
```  
npm i agents@latest @cloudflare/ai-chat@latest  
```

Feb 23, 2026
1. ### [Backup and restore API for Sandbox SDK](https://developers.cloudflare.com/changelog/post/2026-02-23-sandbox-backup-restore-api/)  
[ Agents ](https://developers.cloudflare.com/agents/)[ R2 ](https://developers.cloudflare.com/r2/)[ Containers ](https://developers.cloudflare.com/containers/)  
[Sandboxes](https://developers.cloudflare.com/sandbox/) now support `createBackup()` and `restoreBackup()` methods for creating and restoring point-in-time snapshots of directories.  
This allows you to restore environments quickly. For instance, in order to develop in a sandbox, you may need to include a user's codebase and run a build step. Unfortunately `git clone` and `npm install` can take minutes, and you don't want to run these steps every time the user starts their sandbox.  
Now, after the initial setup, you can just call `createBackup()`, then `restoreBackup()` the next time this environment is needed. This makes it practical to pick up exactly where a user left off, even after days of inactivity, without repeating expensive setup steps.  
TypeScript  
```  
const sandbox = getSandbox(env.Sandbox, "my-sandbox");  
// Make non-trivial changes to the file systemawait sandbox.gitCheckout(endUserRepo, { targetDir: "/workspace" });await sandbox.exec("npm install", { cwd: "/workspace" });  
// Create a point-in-time backup of the directoryconst backup = await sandbox.createBackup({ dir: "/workspace" });  
// Store the handle for later useawait env.KV.put(`backup:${userId}`, JSON.stringify(backup));  
// ... in a future session...  
// Restore instead of re-cloning and reinstallingawait sandbox.restoreBackup(backup);  
```  
Backups are stored in [R2](https://developers.cloudflare.com/r2) and can take advantage of [R2 object lifecycle rules](https://developers.cloudflare.com/sandbox/guides/backup-restore/#configure-r2-lifecycle-rules-for-automatic-cleanup) to ensure they do not persist forever.  
Key capabilities:

  * **Persist and reuse across sandbox sessions** — Easily store backup handles in KV, D1, or Durable Object storage for use in subsequent sessions
  * **Usable across multiple instances** — Fork a backup across many sandboxes for parallel work
  * **Named backups** — Provide optional human-readable labels for easier management
  * **TTLs** — Set time-to-live durations so backups are automatically removed from storage once they are no longer needed  
Note  
Backup and restore currently uses a FUSE overlay. Soon, native snapshotting at a lower level will be added to Containers and Sandboxes, improving speed and ergonomics. The current backup functionality provides a significant speed improvement over manually recreating a file system, but it will be further optimized in the future. The new snapshotting system will use a similar API, so changing to this system will be simple once it is available.  
To get started, refer to the [backup and restore guide](https://developers.cloudflare.com/sandbox/guides/backup-restore/) for setup instructions and usage patterns, or the [Backups API reference](https://developers.cloudflare.com/sandbox/api/backups/) for full method documentation.

Feb 20, 2026
1. ### [@cloudflare/codemode v0.1.0: a new runtime agnostic modular architecture](https://developers.cloudflare.com/changelog/post/2026-02-20-codemode-sdk-rewrite/)  
[ Agents ](https://developers.cloudflare.com/agents/)[ Workers ](https://developers.cloudflare.com/workers/)  
The [@cloudflare/codemode ↗](https://www.npmjs.com/package/@cloudflare/codemode) package has been rewritten into a modular, runtime-agnostic SDK.  
[Code Mode ↗](https://blog.cloudflare.com/code-mode/) enables LLMs to write and execute code that orchestrates your tools, instead of calling them one at a time. This can (and does) yield significant token savings, reduces context window pressure and improves overall model performance on a task.  
The new `Executor` interface is runtime agnostic and comes with a prebuilt `DynamicWorkerExecutor` to run generated code in a [Dynamic Worker Loader](https://developers.cloudflare.com/workers/runtime-apis/bindings/worker-loader/).  
#### Breaking changes

  * Removed `experimental_codemode()` and `CodeModeProxy` — the package no longer owns an LLM call or model choice
  * New import path: `createCodeTool()` is now exported from `@cloudflare/codemode/ai`  
#### New features

  * **`createCodeTool()`** — Returns a standard AI SDK `Tool` to use in your AI agents.
  * **`Executor` interface** — Minimal `execute(code, fns)` contract. Implement for any code sandboxing primitive or runtime.  
#### `DynamicWorkerExecutor`  
Runs code in a [Dynamic Worker](https://developers.cloudflare.com/workers/runtime-apis/bindings/worker-loader/). It comes with the following features:

  * **Network isolation** — `fetch()` and `connect()` blocked by default (`globalOutbound: null`) when using `DynamicWorkerExecutor`
  * **Console capture** — `console.log/warn/error` captured and returned in `ExecuteResult.logs`
  * **Execution timeout** — Configurable via `timeout` option (default 30s)  
#### Usage

  * [  JavaScript ](#tab-panel-3500)
  * [  TypeScript ](#tab-panel-3501)  
JavaScript  
```  
import { createCodeTool } from "@cloudflare/codemode/ai";import { DynamicWorkerExecutor } from "@cloudflare/codemode";import { streamText } from "ai";  
const executor = new DynamicWorkerExecutor({ loader: env.LOADER });const codemode = createCodeTool({ tools: myTools, executor });  
const result = streamText({  model,  tools: { codemode },  messages,});  
```  
TypeScript  
```  
import { createCodeTool } from "@cloudflare/codemode/ai";import { DynamicWorkerExecutor } from "@cloudflare/codemode";import { streamText } from "ai";  
const executor = new DynamicWorkerExecutor({ loader: env.LOADER });const codemode = createCodeTool({ tools: myTools, executor });  
const result = streamText({  model,  tools: { codemode },  messages,});  
```  
#### Wrangler configuration

  * [  wrangler.jsonc ](#tab-panel-3492)
  * [  wrangler.toml ](#tab-panel-3493)  
JSONC  
```  
{  "worker_loaders": [{ "binding": "LOADER" }],}  
```  
TOML  
```  
[[worker_loaders]]binding = "LOADER"  
```  
See the [Code Mode documentation](https://developers.cloudflare.com/agents/tools/codemode/) for full API reference and examples.  
#### Upgrade  
Terminal window  
```  
npm i @cloudflare/codemode@latest  
```

Feb 19, 2026
1. ### [AI dashboard experience improvements](https://developers.cloudflare.com/changelog/post/2026-02-19-ai-dashboard-experience-improvements/)  
[ AI Gateway ](https://developers.cloudflare.com/ai-gateway/)[ Workers AI ](https://developers.cloudflare.com/workers-ai/)  
[Workers AI](https://developers.cloudflare.com/workers-ai/) and [AI Gateway](https://developers.cloudflare.com/ai-gateway/) have received a series of dashboard improvements to help you get started faster and manage your AI workloads more easily.

**Navigation and discoverability**  
AI now has its own top-level section in the Cloudflare dashboard sidebar, so you can find AI features without digging through menus.  
![AI sidebar navigation in the Cloudflare dashboard](https://developers.cloudflare.com/_astro/sidebar-navigation.BQNFBmAk_1GqV9H.webp)  

**Onboarding and getting started**  
[Getting started](https://developers.cloudflare.com/ai-gateway/get-started/) with AI Gateway is now simpler. When you create your first gateway, we now show your gateway's OpenAI-compatible endpoint and step-by-step guidance to help you configure it. The Playground also includes helpful prompts, and usage pages have clear next steps if you have not made any requests yet.  
![AI Gateway onboarding flow](https://developers.cloudflare.com/_astro/onboarding-flow.DZ7aMcHa_Z2hyg1I.webp)  
We've also combined the previously separate code example sections into one view with dropdown selectors for API type, provider, SDK, and authentication method so you can now customize the exact code snippet you need from one place.

**Dynamic Routing**

  * The [route builder](https://developers.cloudflare.com/ai-gateway/features/dynamic-routing/) is now more performant and responsive.
  * You can now copy route names to your clipboard with a single click.
  * Code examples use the [Universal Endpoint](https://developers.cloudflare.com/ai-gateway/usage/universal/) format, making it easier to integrate routes into your application.

**Observability and analytics**

  * Small monetary values now display correctly in [cost analytics](https://developers.cloudflare.com/ai-gateway/observability/costs/) charts, so you can accurately track spending at any scale.

**Accessibility**

  * Improvements to keyboard navigation within the AI Gateway, specifically when exploring usage by [provider](https://developers.cloudflare.com/ai-gateway/usage/providers/).
  * Improvements to sorting and filtering components on the [Workers AI](https://developers.cloudflare.com/workers-ai/models/) models page.  
For more information, refer to the [AI Gateway documentation](https://developers.cloudflare.com/ai-gateway/).

Feb 17, 2026
1. ### [Agents SDK v0.5.0: Protocol message control, retry utilities, data parts, and @cloudflare/ai-chat v0.1.0](https://developers.cloudflare.com/changelog/post/2026-02-17-agents-sdk-v050/)  
[ Agents ](https://developers.cloudflare.com/agents/)[ Workers ](https://developers.cloudflare.com/workers/)  
The latest release of the [Agents SDK ↗](https://github.com/cloudflare/agents) 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 bail early on non-retryable errors.

  * [  JavaScript ](#tab-panel-3498)
  * [  TypeScript ](#tab-panel-3499)  
JavaScript  
```  
class MyAgent extends Agent {  async onRequest(request) {    const data = await this.retry(() => callUnreliableService(), {      maxAttempts: 4,      shouldRetry: (err) => !(err instanceof PermanentError),    });    return Response.json(data);  }}  
```  
TypeScript  
```  
class MyAgent extends Agent {  async onRequest(request: Request) {    const data = await this.retry(() => callUnreliableService(), {      maxAttempts: 4,      shouldRetry: (err) => !(err instanceof PermanentError),    });    return Response.json(data);  }}  
```  
Retry options are also available per-task on `queue()`, `schedule()`, `scheduleEvery()`, and `addMcpServer()`:

  * [  JavaScript ](#tab-panel-3512)
  * [  TypeScript ](#tab-panel-3513)  
JavaScript  
```  
// Per-task retry configuration, persisted in SQLite alongside the taskawait this.schedule(  Date.now() + 60_000,  "sendReport",  { userId: "abc" },  {    retry: { maxAttempts: 5 },  },);  
// Class-level retry defaultsclass MyAgent extends Agent {  static options = {    retry: { maxAttempts: 3 },  };}  
```  
TypeScript  
```  
// Per-task retry configuration, persisted in SQLite alongside the taskawait this.schedule(Date.now() + 60_000, "sendReport", { userId: "abc" }, {  retry: { maxAttempts: 5 },});  
// Class-level retry defaultsclass MyAgent extends Agent {  static options = {    retry: { maxAttempts: 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.  
#### Per-connection protocol message control  
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.

  * [  JavaScript ](#tab-panel-3502)
  * [  TypeScript ](#tab-panel-3503)  
JavaScript  
```  
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";  }}  
```  
TypeScript  
```  
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](https://developers.cloudflare.com/agents/runtime/communication/protocol-messages/) for full documentation.  
#### `@cloudflare/ai-chat` v0.1.0  
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 via `onData` callback). See [Data parts](https://developers.cloudflare.com/agents/communication-channels/chat/chat-agents/#data-parts).
  * **Tool approval persistence** — The `needsApproval` approval UI now survives page refresh and DO hibernation. The streaming message is persisted to SQLite when a tool enters `approval-requested` state.
  * **`maxPersistedMessages`** — Cap SQLite message storage with automatic oldest-message deletion.
  * **`body` option on `useAgentChat`** — 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.
  * **`autoContinueAfterToolResult` defaults to `true`** — Client-side tool results and tool approvals now automatically trigger a server continuation, matching server-executed tool behavior. Set `autoContinueAfterToolResult: false` in `useAgentChat` to restore the previous behavior.  
Notable bug fixes:

  * Resolved stream resumption race conditions
  * Resolved an issue where `setMessages` functional updater sent empty arrays
  * Resolved an issue where client tool schemas were lost after DO hibernation
  * Resolved `InvalidPromptError` after tool approval (`approval.id` was 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-delta` silently dropped data when `reasoning-start` was missed during stream resumption  
#### Synchronous queue and schedule getters  
`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.  
#### Other improvements

  * **Fix TypeScript "excessively deep" error** — A depth counter on `CanSerialize` and `IsSerializableParam` types bails out to `true` after 10 levels of recursion, preventing the "Type instantiation is excessively deep" error with deeply nested types like AI SDK `CoreMessage[]`.
  * **POST SSE keepalive** — The POST SSE handler now sends `event: ping` 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.
  * **Widened peer dependency ranges** — Peer dependency ranges across packages have been widened to prevent cascading major bumps during 0.x minor releases. `@cloudflare/ai-chat` and `@cloudflare/codemode` are now marked as optional peer dependencies.  
#### Upgrade  
To update to the latest version:  
Terminal window  
```  
npm i agents@latest @cloudflare/ai-chat@latest  
```

Feb 13, 2026
1. ### [Introducing GLM-4.7-Flash on Workers AI, @cloudflare/tanstack-ai, and workers-ai-provider v3.1.1](https://developers.cloudflare.com/changelog/post/2026-02-13-glm-47-flash-workers-ai/)  
[ Workers ](https://developers.cloudflare.com/workers/)[ Agents ](https://developers.cloudflare.com/agents/)[ Workers AI ](https://developers.cloudflare.com/workers-ai/)  
We're excited to announce **GLM-4.7-Flash** on Workers AI, a fast and efficient text generation model optimized for multilingual dialogue and instruction-following tasks, along with the brand-new [**@cloudflare/tanstack-ai** ↗](https://www.npmjs.com/package/@cloudflare/tanstack-ai) package and [**workers-ai-provider v3.1.1** ↗](https://www.npmjs.com/package/workers-ai-provider).  
You can now run AI agents entirely on Cloudflare. With GLM-4.7-Flash's multi-turn tool calling support, plus full compatibility with TanStack AI and the Vercel AI SDK, you have everything you need to build agentic applications that run completely at the edge.  
#### GLM-4.7-Flash — Multilingual Text Generation Model  
[@cf/zai-org/glm-4.7-flash](https://developers.cloudflare.com/workers-ai/models/glm-4.7-flash/) is a multilingual model with a 131,072 token context window, making it ideal for long-form content generation, complex reasoning tasks, and multilingual applications.

**Key Features and Use Cases:**

  * **Multi-turn Tool Calling for Agents**: Build AI agents that can call functions and tools across multiple conversation turns
  * **Multilingual Support**: Built to handle content generation in multiple languages effectively
  * **Large Context Window**: 131,072 tokens for long-form writing, complex reasoning, and processing long documents
  * **Fast Inference**: Optimized for low-latency responses in chatbots and virtual assistants
  * **Instruction Following**: Excellent at following complex instructions for code generation and structured tasks  
Use GLM-4.7-Flash through the [Workers AI binding](https://developers.cloudflare.com/workers-ai/configuration/bindings/) (`env.AI.run()`), the REST API at `/run` or `/v1/chat/completions`, [AI Gateway](https://developers.cloudflare.com/ai-gateway/), or via [workers-ai-provider](https://developers.cloudflare.com/workers-ai/configuration/ai-sdk/) for the Vercel AI SDK.  
Pricing is available on the [model page](https://developers.cloudflare.com/workers-ai/models/glm-4.7-flash/) or [pricing page](https://developers.cloudflare.com/workers-ai/platform/pricing/).  
#### @cloudflare/tanstack-ai v0.1.1 — TanStack AI adapters for Workers AI and AI Gateway  
We've released `@cloudflare/tanstack-ai`, a new package that brings Workers AI and AI Gateway support to [TanStack AI ↗](https://tanstack.com/ai). This provides a framework-agnostic alternative for developers who prefer TanStack's approach to building AI applications.

**Workers AI adapters** support four configuration modes — plain binding (`env.AI`), plain REST, AI Gateway binding (`env.AI.gateway(id)`), and AI Gateway REST — across all capabilities:

  * **Chat** (`createWorkersAiChat`) — Streaming chat completions with tool calling, structured output, and reasoning text streaming.
  * **Image generation** (`createWorkersAiImage`) — Text-to-image models.
  * **Transcription** (`createWorkersAiTranscription`) — Speech-to-text.
  * **Text-to-speech** (`createWorkersAiTts`) — Audio generation.
  * **Summarization** (`createWorkersAiSummarize`) — Text summarization.

**AI Gateway adapters** route requests from third-party providers — OpenAI, Anthropic, Gemini, Grok, and OpenRouter — through Cloudflare AI Gateway for caching, rate limiting, and unified billing.  
To get started:  
Terminal window  
```  
npm install @cloudflare/tanstack-ai @tanstack/ai  
```  
#### workers-ai-provider v3.1.1 — transcription, speech, reranking, and reliability  
The Workers AI provider for the [Vercel AI SDK ↗](https://ai-sdk.dev) now supports three new capabilities beyond chat and image generation:

  * **Transcription** (`provider.transcription(model)`) — Speech-to-text with automatic handling of model-specific input formats across binding and REST paths.
  * **Text-to-speech** (`provider.speech(model)`) — Audio generation with support for voice and speed options.
  * **Reranking** (`provider.reranking(model)`) — Document reranking for RAG pipelines and search result ordering.  
TypeScript  
```  
import { createWorkersAI } from "workers-ai-provider";import {  experimental_transcribe,  experimental_generateSpeech,  rerank,} from "ai";  
const workersai = createWorkersAI({ binding: env.AI });  
const transcript = await experimental_transcribe({  model: workersai.transcription("@cf/openai/whisper-large-v3-turbo"),  audio: audioData,  mediaType: "audio/wav",});  
const speech = await experimental_generateSpeech({  model: workersai.speech("@cf/deepgram/aura-1"),  text: "Hello world",  voice: "asteria",});  
const ranked = await rerank({  model: workersai.reranking("@cf/baai/bge-reranker-base"),  query: "What is machine learning?",  documents: ["ML is a branch of AI.", "The weather is sunny."],});  
```  
This release also includes a comprehensive reliability overhaul (v3.0.5):

  * **Fixed streaming** — Responses now stream token-by-token instead of buffering all chunks, using a proper `TransformStream` pipeline with backpressure.
  * **Fixed tool calling** — Resolved issues with tool call ID sanitization, conversation history preservation, and a heuristic that silently fell back to non-streaming mode when tools were defined.
  * **Premature stream termination detection** — Streams that end unexpectedly now report `finishReason: "error"` instead of silently reporting `"stop"`.
  * **AI Search support** — Added `createAISearch` as the canonical export (renamed from AutoRAG). `createAutoRAG` still works with a deprecation warning.  
To upgrade:  
Terminal window  
```  
npm install workers-ai-provider@latest ai  
```  
#### Resources

  * [@cloudflare/tanstack-ai on npm ↗](https://www.npmjs.com/package/@cloudflare/tanstack-ai)
  * [workers-ai-provider on npm ↗](https://www.npmjs.com/package/workers-ai-provider)
  * [GitHub repository ↗](https://github.com/cloudflare/ai)

Feb 09, 2026
1. ### [Agents SDK v0.4.0: Readonly connections, MCP security improvements, x402 v2 migration, and custom MCP OAuth providers](https://developers.cloudflare.com/changelog/post/2026-02-09-agents-sdk-v040/)  
[ Agents ](https://developers.cloudflare.com/agents/)[ Workers ](https://developers.cloudflare.com/workers/)  
The latest release of the [Agents SDK ↗](https://github.com/cloudflare/agents) brings readonly connections, MCP protocol and security improvements, x402 payment protocol v2 migration, and the ability to customize OAuth for MCP server connections.  
#### Readonly connections  
Agents can now restrict WebSocket clients to read-only access, preventing them from modifying agent state. This is useful for dashboards, spectator views, or any scenario where clients should observe but not mutate.  
New hooks: `shouldConnectionBeReadonly`, `setConnectionReadonly`, `isConnectionReadonly`. Readonly connections block both client-side `setState()` and mutating `@callable()` methods, and the readonly flag survives hibernation.

  * [  JavaScript ](#tab-panel-3504)
  * [  TypeScript ](#tab-panel-3505)  
JavaScript  
```  
class MyAgent extends Agent {  shouldConnectionBeReadonly(connection) {    // Make spectators readonly    return connection.url.includes("spectator");  }}  
```  
TypeScript  
```  
class MyAgent extends Agent {  shouldConnectionBeReadonly(connection) {    // Make spectators readonly    return connection.url.includes("spectator");  }}  
```  
#### Custom MCP OAuth providers  
The new `createMcpOAuthProvider` method on the `Agent` class allows subclasses to override the default OAuth provider used when connecting to MCP servers. This enables custom authentication strategies such as pre-registered client credentials or mTLS, beyond the built-in dynamic client registration.

  * [  JavaScript ](#tab-panel-3508)
  * [  TypeScript ](#tab-panel-3509)  
JavaScript  
```  
class MyAgent extends Agent {  createMcpOAuthProvider(callbackUrl) {    return new MyCustomOAuthProvider(this.ctx.storage, this.name, callbackUrl);  }}  
```  
TypeScript  
```  
class MyAgent extends Agent {  createMcpOAuthProvider(callbackUrl: string): AgentMcpOAuthProvider {    return new MyCustomOAuthProvider(this.ctx.storage, this.name, callbackUrl);  }}  
```  
#### MCP SDK upgrade to 1.26.0  
Upgraded the MCP SDK to 1.26.0 to prevent cross-client response leakage. Stateless MCP Servers should now create a new `McpServer` instance per request instead of sharing a single instance. A guard is added in this version of the MCP SDK which will prevent connection to a Server instance that has already been connected to a transport. Developers will need to modify their code if they declare their `McpServer` instance as a global variable.  
#### MCP OAuth callback URL security fix  
Added `callbackPath` option to `addMcpServer` to prevent instance name leakage in MCP OAuth callback URLs. When `sendIdentityOnConnect` is `false`, `callbackPath` is now required — the default callback URL would expose the instance name, undermining the security intent. Also fixes callback request detection to match via the `state` parameter instead of a loose `/callback` URL substring check, enabling custom callback paths.  
#### Deprecate `onStateUpdate` in favor of `onStateChanged`  
`onStateChanged` is a drop-in rename of `onStateUpdate` (same signature, same behavior). `onStateUpdate` still works but emits a one-time console warning per class. `validateStateChange` rejections now propagate a `CF_AGENT_STATE_ERROR` message back to the client.  
#### x402 v2 migration  
Migrated the x402 MCP payment integration from the legacy `x402` package to `@x402/core` and `@x402/evm` v2.

**Breaking changes for x402 users:**

  * Peer dependencies changed: replace `x402` with `@x402/core` and `@x402/evm`
  * `PaymentRequirements` type now uses v2 fields (e.g. `amount` instead of `maxAmountRequired`)
  * `X402ClientConfig.account` type changed from `viem.Account` to `ClientEvmSigner` (structurally compatible with `privateKeyToAccount()`)  
Terminal window  
```  
npm uninstall x402npm install @x402/core @x402/evm  
```  
Network identifiers now accept both legacy names and CAIP-2 format:  
TypeScript  
```  
// Legacy name (auto-converted){  network: "base-sepolia",}  
// CAIP-2 format (preferred){  network: "eip155:84532",}  
```

**Other x402 changes:**

  * `X402ClientConfig.network` is now optional — the client auto-selects from available payment requirements
  * Server-side lazy initialization: facilitator connection is deferred until the first paid tool invocation
  * Payment tokens support both v2 (`PAYMENT-SIGNATURE`) and v1 (`X-PAYMENT`) HTTP headers
  * Added `normalizeNetwork` export for converting legacy network names to CAIP-2 format
  * Re-exports `PaymentRequirements`, `PaymentRequired`, `Network`, `FacilitatorConfig`, and `ClientEvmSigner` from `agents/x402`  
#### Other improvements

  * Fix `useAgent` and `AgentClient` crashing when using `basePath` routing
  * CORS handling delegated to partyserver's native support (simpler, more reliable)
  * Client-side `onStateUpdateError` callback for handling rejected state updates  
#### Upgrade  
To update to the latest version:  
Terminal window  
```  
npm i agents@latest  
```

Feb 09, 2026
1. ### [Interactive browser terminals in Sandboxes](https://developers.cloudflare.com/changelog/post/2026-02-09-pty-terminal-support/)  
[ Agents ](https://developers.cloudflare.com/agents/)  
The [Sandbox SDK ↗](https://github.com/cloudflare/sandbox-sdk) now supports PTY (pseudo-terminal) passthrough, enabling browser-based terminal UIs to connect to sandbox shells via WebSocket.  
#### `sandbox.terminal(request)`  
The new `terminal()` method proxies a WebSocket upgrade to the container's PTY endpoint, with output buffering for replay on reconnect.

  * [  JavaScript ](#tab-panel-3506)
  * [  TypeScript ](#tab-panel-3507)  
JavaScript  
```  
// Worker: proxy WebSocket to container terminalreturn sandbox.terminal(request, { cols: 80, rows: 24 });  
```  
TypeScript  
```  
// Worker: proxy WebSocket to container terminalreturn sandbox.terminal(request, { cols: 80, rows: 24 });  
```  
#### Multiple terminals per sandbox  
Each session can have its own terminal with an isolated working directory and environment, so users can run separate shells side-by-side in the same container.

  * [  JavaScript ](#tab-panel-3510)
  * [  TypeScript ](#tab-panel-3511)  
JavaScript  
```  
// Multiple isolated terminals in the same sandboxconst dev = await sandbox.getSession("dev");return dev.terminal(request);  
```  
TypeScript  
```  
// Multiple isolated terminals in the same sandboxconst dev = await sandbox.getSession("dev");return dev.terminal(request);  
```  
#### xterm.js addon  
The new `@cloudflare/sandbox/xterm` export provides a `SandboxAddon` for [xterm.js ↗](https://xtermjs.org/) with automatic reconnection (exponential backoff + jitter), buffered output replay, and resize forwarding.

  * [  JavaScript ](#tab-panel-3514)
  * [  TypeScript ](#tab-panel-3515)  
JavaScript  
```  
import { SandboxAddon } from "@cloudflare/sandbox/xterm";  
const addon = new SandboxAddon({  getWebSocketUrl: ({ sandboxId, origin }) =>    `${origin}/ws/terminal?id=${sandboxId}`,  onStateChange: (state, error) => updateUI(state),});terminal.loadAddon(addon);addon.connect({ sandboxId: "my-sandbox" });  
```  
TypeScript  
```  
import { SandboxAddon } from "@cloudflare/sandbox/xterm";  
const addon = new SandboxAddon({  getWebSocketUrl: ({ sandboxId, origin }) =>    `${origin}/ws/terminal?id=${sandboxId}`,  onStateChange: (state, error) => updateUI(state),});terminal.loadAddon(addon);addon.connect({ sandboxId: "my-sandbox" });  
```  
#### Upgrade  
To update to the latest version:  
Terminal window  
```  
npm i @cloudflare/sandbox@latest  
```

Feb 09, 2026
1. ### [Analytics enhancements](https://developers.cloudflare.com/changelog/post/2026-02-09-analytics-enhancements/)  
[ AI Crawl Control ](https://developers.cloudflare.com/ai-crawl-control/)  
AI Crawl Control metrics have been enhanced with new views, improved filtering, and better data visualization.  
![AI Crawl Control path patterns](https://developers.cloudflare.com/_astro/ai-crawl-control-path-patterns.0xT_lucE_1Png6i.webp)  

**Path pattern grouping**

  * In the **Metrics** tab > **Most popular paths** table, use the new **Patterns** tab that groups requests by URI pattern (`/blog/*`, `/api/v1/*`, `/docs/*`) to identify which site areas crawlers target most. Refer to the screenshot above.

**Enhanced referral analytics**

  * Destination patterns show which site areas receive AI-driven referral traffic.
  * In the **Metrics** tab, a new **Referrals over time** chart shows trends by operator or source.

**Data transfer metrics**

  * In the **Metrics** tab > **Allowed requests over time** chart, toggle **Bytes** to show bandwidth consumption.
  * In the **Crawlers** tab, a new **Bytes Transferred** column shows bandwidth per crawler.

**Image exports**

  * Export charts and tables as images for reports and presentations.  
Learn more about [analyzing AI traffic](https://developers.cloudflare.com/ai-crawl-control/features/analyze-ai-traffic/).

Feb 09, 2026
1. ### [AI Search now with more granular controls over indexing](https://developers.cloudflare.com/changelog/post/2026-02-09-indexing-improvements/)  
[ AI Search ](https://developers.cloudflare.com/ai-search/)  
Get your content updates into [AI Search](https://developers.cloudflare.com/ai-search/) faster and avoid a full rescan when you do not need it.  
#### Reindex individual files without a full sync  
Updated a file or need to retry one that errored? When you know exactly which file changed, you can now [reindex it directly](https://developers.cloudflare.com/ai-search/configuration/indexing/syncing/#controls) instead of rescanning your entire data source.  
Go to **Overview** \> **Indexed Items** and select the sync icon next to any file to reindex it immediately.  
![Sync individual files from Indexed Items](https://developers.cloudflare.com/_astro/individual-file-indexing.CQgoIj85_ZIBUBg.webp)  
#### Crawl only the sitemap you need  
By default, AI Search crawls all sitemaps listed in your `robots.txt`, up to the [maximum files per index limit](https://developers.cloudflare.com/ai-search/platform/limits-pricing/#limits). If your site has multiple sitemaps but you only want to index a specific set, you can now [specify a single sitemap URL](https://developers.cloudflare.com/ai-search/configuration/data-source/website/#sitemap) to limit what the crawler visits.  
For example, if your `robots.txt` lists both `blog-sitemap.xml` and `docs-sitemap.xml`, you can specify just `https://example.com/docs-sitemap.xml` to index only your documentation.  
Configure your selection anytime in **Settings** \> **Parsing options** \> **Specific sitemaps**, then trigger a sync to apply the changes.  
![Specify a sitemap in Parsinh options](https://developers.cloudflare.com/_astro/specify-sitemap.pLCkwmJ-_2vbphB.webp)  
Learn more about [indexing controls](https://developers.cloudflare.com/ai-search/configuration/indexing/syncing/#controls) and [website crawling configuration](https://developers.cloudflare.com/ai-search/configuration/data-source/website/#sitemap).

Feb 04, 2026
1. ### [New reference documentation](https://developers.cloudflare.com/changelog/post/2026-02-09-reference-documentation/)  
[ AI Crawl Control ](https://developers.cloudflare.com/ai-crawl-control/)  
New reference documentation is now available for AI Crawl Control:

  * **[GraphQL API reference](https://developers.cloudflare.com/ai-crawl-control/reference/graphql-api/)** — Query examples for crawler requests, top paths, referral traffic, and data transfer. Includes key filters for detection IDs, user agents, and referrer domains.
  * **[Bot reference](https://developers.cloudflare.com/ai-crawl-control/reference/bots/)** — Detection IDs and user agents for major AI crawlers from OpenAI, Anthropic, Google, Meta, and others.
  * **[Worker templates](https://developers.cloudflare.com/ai-crawl-control/reference/worker-templates/)** — Deploy the x402 Payment-Gated Proxy to monetize crawler access or charge bots while letting humans through free.

Feb 03, 2026
1. ### [Agents SDK v0.3.7: Workflows integration, synchronous state, and scheduleEvery()](https://developers.cloudflare.com/changelog/post/2026-02-03-agents-workflows-integration/)  
[ Agents ](https://developers.cloudflare.com/agents/)[ Workflows ](https://developers.cloudflare.com/workflows/)  
The latest release of the [Agents SDK ↗](https://github.com/cloudflare/agents) brings first-class support for [Cloudflare Workflows](https://developers.cloudflare.com/workflows/), synchronous state management, and new scheduling capabilities.  
#### Cloudflare Workflows integration  
Agents excel at real-time communication and state management. Workflows excel at durable execution. Together, they enable powerful patterns where Agents handle WebSocket connections while Workflows handle long-running tasks, retries, and human-in-the-loop flows.  
Use the new `AgentWorkflow` class to define workflows with typed access to your Agent:

  * [  JavaScript ](#tab-panel-3524)
  * [  TypeScript ](#tab-panel-3525)  
JavaScript  
```  
import { AgentWorkflow } from "agents/workflows";  
export class ProcessingWorkflow extends AgentWorkflow {  async run(event, step) {    // Call Agent methods via RPC    await this.agent.updateStatus(event.payload.taskId, "processing");  
    // Non-durable: progress reporting to clients    await this.reportProgress({ step: "process", percent: 0.5 });    this.broadcastToClients({ type: "update", taskId: event.payload.taskId });  
    // Durable via step: idempotent, won't repeat on retry    await step.mergeAgentState({ taskProgress: 0.5 });  
    const result = await step.do("process", async () => {      return processData(event.payload.data);    });  
    await step.reportComplete(result);    return result;  }}  
```  
TypeScript  
```  
import { AgentWorkflow } from "agents/workflows";import type { AgentWorkflowEvent, AgentWorkflowStep } from "agents/workflows";  
export class ProcessingWorkflow extends AgentWorkflow<MyAgent, TaskParams> {  async run(event: AgentWorkflowEvent<TaskParams>, step: AgentWorkflowStep) {    // Call Agent methods via RPC    await this.agent.updateStatus(event.payload.taskId, "processing");  
    // Non-durable: progress reporting to clients    await this.reportProgress({ step: "process", percent: 0.5 });    this.broadcastToClients({ type: "update", taskId: event.payload.taskId });  
    // Durable via step: idempotent, won't repeat on retry    await step.mergeAgentState({ taskProgress: 0.5 });  
    const result = await step.do("process", async () => {      return processData(event.payload.data);    });  
    await step.reportComplete(result);    return result;  }}  
```  
Start workflows from your Agent with `runWorkflow()` and handle lifecycle events:

  * [  JavaScript ](#tab-panel-3526)
  * [  TypeScript ](#tab-panel-3527)  
JavaScript  
```  
export class MyAgent extends Agent {  async startTask(taskId, data) {    const instanceId = await this.runWorkflow("PROCESSING_WORKFLOW", {      taskId,      data,    });    return { instanceId };  }  
  async onWorkflowProgress(workflowName, instanceId, progress) {    this.broadcast(JSON.stringify({ type: "progress", progress }));  }  
  async onWorkflowComplete(workflowName, instanceId, result) {    console.log(`Workflow ${instanceId} completed`);  }  
  async onWorkflowError(workflowName, instanceId, error) {    console.error(`Workflow ${instanceId} failed:`, error);  }}  
```  
TypeScript  
```  
export class MyAgent extends Agent {  async startTask(taskId: string, data: string) {    const instanceId = await this.runWorkflow("PROCESSING_WORKFLOW", {      taskId,      data,    });    return { instanceId };  }  
  async onWorkflowProgress(    workflowName: string,    instanceId: string,    progress: unknown,  ) {    this.broadcast(JSON.stringify({ type: "progress", progress }));  }  
  async onWorkflowComplete(    workflowName: string,    instanceId: string,    result?: unknown,  ) {    console.log(`Workflow ${instanceId} completed`);  }  
  async onWorkflowError(    workflowName: string,    instanceId: string,    error: unknown,  ) {    console.error(`Workflow ${instanceId} failed:`, error);  }}  
```  
Key workflow methods on your Agent:

  * `runWorkflow(workflowName, params, options?)` — Start a workflow with optional metadata
  * `getWorkflow(workflowId)` / `getWorkflows(criteria?)` — Query workflows with cursor-based pagination
  * `approveWorkflow(workflowId)` / `rejectWorkflow(workflowId)` — Human-in-the-loop approval flows
  * `pauseWorkflow()`, `resumeWorkflow()`, `terminateWorkflow()` — Workflow control  
#### Synchronous setState()  
State updates are now synchronous with a new `validateStateChange()` validation hook:

  * [  JavaScript ](#tab-panel-3518)
  * [  TypeScript ](#tab-panel-3519)  
JavaScript  
```  
export class MyAgent extends Agent {  validateStateChange(oldState, newState) {    // Return false to reject the change    if (newState.count < 0) return false;    // Return modified state to transform    return { ...newState, lastUpdated: Date.now() };  }}  
```  
TypeScript  
```  
export class MyAgent extends Agent<Env, State> {  validateStateChange(oldState: State, newState: State): State | false {    // Return false to reject the change    if (newState.count < 0) return false;    // Return modified state to transform    return { ...newState, lastUpdated: Date.now() };  }}  
```  
#### scheduleEvery() for recurring tasks  
The new `scheduleEvery()` method enables fixed-interval recurring tasks with built-in overlap prevention:

  * [  JavaScript ](#tab-panel-3516)
  * [  TypeScript ](#tab-panel-3517)  
JavaScript  
```  
// Run every 5 minutesawait this.scheduleEvery("syncData", 5 * 60 * 1000, { source: "api" });  
```  
TypeScript  
```  
// Run every 5 minutesawait this.scheduleEvery("syncData", 5 * 60 * 1000, { source: "api" });  
```  
#### Callable system improvements

  * **Client-side RPC timeout** — Set timeouts on callable method invocations
  * **`StreamingResponse.error(message)`** — Graceful stream error signaling
  * **`getCallableMethods()`** — Introspection API for discovering callable methods
  * **Connection close handling** — Pending calls are automatically rejected on disconnect

  * [  JavaScript ](#tab-panel-3520)
  * [  TypeScript ](#tab-panel-3521)  
JavaScript  
```  
await agent.call("method", [args], {  timeout: 5000,  stream: { onChunk, onDone, onError },});  
```  
TypeScript  
```  
await agent.call("method", [args], {  timeout: 5000,  stream: { onChunk, onDone, onError },});  
```  
#### Email and routing enhancements

**Secure email reply routing** — Email replies are now secured with HMAC-SHA256 signed headers, preventing unauthorized routing of emails to agent instances.

**Routing improvements:**

  * `basePath` option to bypass default URL construction for custom routing
  * Server-sent identity — Agents send `name` and `agent` type on connect
  * New `onIdentity` and `onIdentityChange` callbacks on the client

  * [  JavaScript ](#tab-panel-3522)
  * [  TypeScript ](#tab-panel-3523)  
JavaScript  
```  
const agent = useAgent({  basePath: "user",  onIdentity: (name, agentType) => console.log(`Connected to ${name}`),});  
```  
TypeScript  
```  
const agent = useAgent({  basePath: "user",  onIdentity: (name, agentType) => console.log(`Connected to ${name}`),});  
```  
#### Upgrade  
To update to the latest version:  
Terminal window  
```  
npm i agents@latest  
```  
For the complete Workflows API reference and patterns, see [Run Workflows](https://developers.cloudflare.com/agents/runtime/execution/run-workflows/).

Jan 28, 2026
1. ### [Launching FLUX.2 \[klein\] 9B on Workers AI](https://developers.cloudflare.com/changelog/post/2026-01-28-flux-2-klein-9b-workers-ai/)  
[ Workers AI ](https://developers.cloudflare.com/workers-ai/)  
We have partnered with Black Forest Labs (BFL) again to bring their optimized FLUX.2 \[klein\] 9B model to Workers AI. This distilled model offers enhanced quality compared to the 4B variant, while maintaining cost-effective pricing. With a fixed 4-step inference process, Klein 9B is ideal for rapid prototyping and real-time applications where both speed and quality matter.  
Read the [BFL blog ↗](https://bfl.ai/blog) to learn more about the model itself, or try it out yourself on our [multi modal playground ↗](https://multi-modal.ai.cloudflare.com/).  
Pricing documentation is available on the [model page](https://developers.cloudflare.com/workers-ai/models/flux-2-klein-9b/) or [pricing page](https://developers.cloudflare.com/workers-ai/platform/pricing/).  
#### Workers AI platform specifics  
The model hosted on Workers AI is optimized for speed with a **fixed 4-step inference process** and supports up to 4 image inputs. Since this is a distilled model, the `steps` parameter is fixed at 4 and cannot be adjusted. Like FLUX.2 \[dev\] and FLUX.2 \[klein\] 4B, this image model uses multipart form data inputs, even if you just have a prompt.  
With the REST API, the multipart form data input looks like this:  
Terminal window  
```  
curl --request POST \  --url 'https://api.cloudflare.com/client/v4/accounts/{ACCOUNT}/ai/run/@cf/black-forest-labs/flux-2-klein-9b' \  --header 'Authorization: Bearer {TOKEN}' \  --header 'Content-Type: multipart/form-data' \  --form 'prompt=a sunset at the alps' \  --form width=1024 \  --form height=1024  
```  
With the Workers AI binding, you can use it as such:  
JavaScript  
```  
const form = new FormData();form.append("prompt", "a sunset with a dog");form.append("width", "1024");form.append("height", "1024");  
// FormData doesn't expose its serialized body or boundary. Passing it to a// Request (or Response) constructor serializes it and generates the Content-Type// header with the boundary, which is required for the server to parse the multipart fields.const formResponse = new Response(form);const formStream = formResponse.body;const formContentType = formResponse.headers.get('content-type');  
const resp = await env.AI.run("@cf/black-forest-labs/flux-2-klein-9b", {  multipart: {    body: formStream,    contentType: formContentType,  },});  
```  
The parameters you can send to the model are detailed here:  
JSON Schema for Model **Required Parameters**
  * `prompt` (string) - Text description of the image to generate

**Optional Parameters**

  * `input_image_0` (string) - Binary image
  * `input_image_1` (string) - Binary image
  * `input_image_2` (string) - Binary image
  * `input_image_3` (string) - Binary image
  * `guidance` (float) - Guidance scale for generation. Higher values follow the prompt more closely
  * `width` (integer) - Width of the image, default `1024` Range: 256-1920
  * `height` (integer) - Height of the image, default `768` Range: 256-1920
  * `seed` (integer) - Seed for reproducibility

**Note:** Since this is a distilled model, the `steps` parameter is fixed at 4 and cannot be adjusted.  
#### Multi-reference images  
The FLUX.2 klein-9b model supports generating images based on reference images, just like FLUX.2 \[dev\] and FLUX.2 \[klein\] 4B. You can use this feature to apply the style of one image to another, add a new character to an image, or iterate on past generated images. You would use it with the same multipart form data structure, with the input images in binary. The model supports up to 4 input images.  
For the prompt, you can reference the images based on the index, like `take the subject of image 1 and style it like image 0` or even use natural language like `place the dog beside the woman`.  
You must name the input parameter as `input_image_0`, `input_image_1`, `input_image_2`, `input_image_3` for it to work correctly. All input images must be smaller than 512x512.  
Terminal window  
```  
curl --request POST \  --url 'https://api.cloudflare.com/client/v4/accounts/{ACCOUNT}/ai/run/@cf/black-forest-labs/flux-2-klein-9b' \  --header 'Authorization: Bearer {TOKEN}' \  --header 'Content-Type: multipart/form-data' \  --form 'prompt=take the subject of image 1 and style it like image 0' \  --form input_image_0=@/Users/johndoe/Desktop/icedoutkeanu.png \  --form input_image_1=@/Users/johndoe/Desktop/me.png \  --form width=1024 \  --form height=1024  
```  
Through Workers AI Binding:  
JavaScript  
```  
//helper function to convert ReadableStream to Blobasync function streamToBlob(stream: ReadableStream, contentType: string): Promise<Blob> {  const reader = stream.getReader();  const chunks = [];  
  while (true) {    const { done, value } = await reader.read();    if (done) break;    chunks.push(value);  }  
  return new Blob(chunks, { type: contentType });}  
const image0 = await fetch("http://image-url");const image1 = await fetch("http://image-url");const form = new FormData();  
const image_blob0 = await streamToBlob(image0.body, "image/png");const image_blob1 = await streamToBlob(image1.body, "image/png");form.append('input_image_0', image_blob0)form.append('input_image_1', image_blob1)form.append('prompt', 'take the subject of image 1 and style it like image 0')  
// FormData doesn't expose its serialized body or boundary. Passing it to a// Request (or Response) constructor serializes it and generates the Content-Type// header with the boundary, which is required for the server to parse the multipart fields.const formResponse = new Response(form);const formStream = formResponse.body;const formContentType = formResponse.headers.get('content-type');  
const resp = await env.AI.run("@cf/black-forest-labs/flux-2-klein-9b", {    multipart: {        body: formStream,        contentType: formContentType    }})  
```

Jan 23, 2026
1. ### [Vectorize indexes now support up to 10 million vectors](https://developers.cloudflare.com/changelog/post/2026-01-23-increased-index-capacity/)  
[ Vectorize ](https://developers.cloudflare.com/vectorize/)  
You can now store up to 10 million vectors in a single Vectorize index, doubling the previous limit of 5 million vectors. This enables larger-scale semantic search, recommendation systems, and retrieval-augmented generation (RAG) applications without splitting data across multiple indexes.  
Vectorize continues to support indexes with up to 1,536 dimensions per vector at 32-bit precision. Refer to the [Vectorize limits documentation](https://developers.cloudflare.com/vectorize/platform/limits/) for complete details.

Jan 20, 2026
1. ### [AI Search path filtering for website and R2 data sources](https://developers.cloudflare.com/changelog/post/2026-01-20-ai-search-path-filtering/)  
[ AI Search ](https://developers.cloudflare.com/ai-search/)  
[AI Search](https://developers.cloudflare.com/ai-search/) now includes [path filtering](https://developers.cloudflare.com/ai-search/configuration/indexing/path-filtering/) for both [website](https://developers.cloudflare.com/ai-search/configuration/data-source/website/#path-filtering) and [R2](https://developers.cloudflare.com/ai-search/configuration/data-source/r2/#path-filtering) data sources. You can now control which content gets indexed by defining include and exclude rules for paths.  
By controlling what gets indexed, you can improve the relevance and quality of your search results. You can also use path filtering to split a single data source across multiple AI Search instances for specialized search experiences.  
![Path filtering configuration in AI Search](https://developers.cloudflare.com/_astro/path-filtering.BCH7HN-Q_vEVaf.webp)  
Path filtering uses [micromatch ↗](https://github.com/micromatch/micromatch) patterns, so you can use `*` to match within a directory and `**` to match across directories.

| Use case                        | Include        | Exclude               |
| ------------------------------- | -------------- | --------------------- |
| Index docs but skip drafts      | \*\*/docs/\*\* | \*\*/docs/drafts/\*\* |
| Keep admin pages out of results | —              | \*\*/admin/\*\*       |
| Index only English content      | \*\*/en/\*\*   | —                     |  
Configure path filters when creating a new instance or update them anytime from **Settings**. Check out [path filtering](https://developers.cloudflare.com/ai-search/configuration/indexing/path-filtering/) to learn more.

Jan 20, 2026
1. ### [Create AI Search instances programmatically via REST API](https://developers.cloudflare.com/changelog/post/2026-01-20-ai-search-simplified-api/)  
[ AI Search ](https://developers.cloudflare.com/ai-search/)  
You can now create [AI Search](https://developers.cloudflare.com/ai-search/) instances programmatically using the [API](https://developers.cloudflare.com/ai-search/get-started/api/). For example, use the API to create instances for each customer in a multi-tenant application or manage AI Search alongside your other infrastructure.  
If you have created an AI Search instance via the [dashboard](https://developers.cloudflare.com/ai-search/get-started/dashboard/) before, you already have a [service API token](https://developers.cloudflare.com/ai-search/configuration/indexing/service-api-token/) registered and can start creating instances programmatically right away. If not, follow the [API guide](https://developers.cloudflare.com/ai-search/get-started/api/) to set up your first instance.  
For example, you can now create separate search instances for each language on your website:  
Terminal window  
```  
for lang in en fr es de; do  curl -X POST "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/ai-search/instances" \    -H "Authorization: Bearer $API_TOKEN" \    -H "Content-Type: application/json" \    --data '{      "id": "docs-'"$lang"'",      "type": "web-crawler",      "source": "example.com",      "source_params": {        "path_include": ["**/'"$lang"'/**"]      }    }'done  
```  
Refer to the [REST API reference](https://developers.cloudflare.com/api/resources/ai%5Fsearch/subresources/instances/methods/create/) for additional configuration options.

Jan 15, 2026
1. ### [Launching FLUX.2 \[klein\] 4B on Workers AI](https://developers.cloudflare.com/changelog/post/2026-01-15-flux-2-klein-4b-workers-ai/)  
[ Workers AI ](https://developers.cloudflare.com/workers-ai/)  
We've partnered with Black Forest Labs (BFL) again to bring their optimized FLUX.2 \[klein\] 4B model to Workers AI! This distilled model offers faster generation and cost-effective pricing, while maintaining great output quality. With a fixed 4-step inference process, Klein 4B is ideal for rapid prototyping and real-time applications where speed matters.  
Read the [BFL blog ↗](https://bfl.ai/blog) to learn more about the model itself, or try it out yourself on our [multi modal playground ↗](https://multi-modal.ai.cloudflare.com/).  
Pricing documentation is available on the [model page](https://developers.cloudflare.com/workers-ai/models/flux-2-klein-4b/) or [pricing page](https://developers.cloudflare.com/workers-ai/platform/pricing/).  
#### Workers AI Platform specifics  
The model hosted on Workers AI is optimized for speed with a **fixed 4-step inference process** and supports up to 4 image inputs. Since this is a distilled model, the `steps` parameter is fixed at 4 and cannot be adjusted. Like FLUX.2 \[dev\], this image model uses multipart form data inputs, even if you just have a prompt.  
With the REST API, the multipart form data input looks like this:  
Terminal window  
```  
curl --request POST \  --url 'https://api.cloudflare.com/client/v4/accounts/{ACCOUNT}/ai/run/@cf/black-forest-labs/flux-2-klein-4b' \  --header 'Authorization: Bearer {TOKEN}' \  --header 'Content-Type: multipart/form-data' \  --form 'prompt=a sunset at the alps' \  --form width=1024 \  --form height=1024  
```  
With the Workers AI binding, you can use it as such:  
JavaScript  
```  
const form = new FormData();form.append("prompt", "a sunset with a dog");form.append("width", "1024");form.append("height", "1024");  
// FormData doesn't expose its serialized body or boundary. Passing it to a// Request (or Response) constructor serializes it and generates the Content-Type// header with the boundary, which is required for the server to parse the multipart fields.const formResponse = new Response(form);const formStream = formResponse.body;const formContentType = formResponse.headers.get('content-type');  
const resp = await env.AI.run("@cf/black-forest-labs/flux-2-klein-4b", {  multipart: {    body: formStream,    contentType: formContentType,  },});  
```  
The parameters you can send to the model are detailed here:  
JSON Schema for Model **Required Parameters**
  * `prompt` (string) - Text description of the image to generate

**Optional Parameters**

  * `input_image_0` (string) - Binary image
  * `input_image_1` (string) - Binary image
  * `input_image_2` (string) - Binary image
  * `input_image_3` (string) - Binary image
  * `guidance` (float) - Guidance scale for generation. Higher values follow the prompt more closely
  * `width` (integer) - Width of the image, default `1024` Range: 256-1920
  * `height` (integer) - Height of the image, default `768` Range: 256-1920
  * `seed` (integer) - Seed for reproducibility

**Note:** Since this is a distilled model, the `steps` parameter is fixed at 4 and cannot be adjusted.  
```  
## Multi-Reference Images  
The FLUX.2 klein-4b model supports generating images based on reference images, just like FLUX.2 [dev]. You can use this feature to apply the style of one image to another, add a new character to an image, or iterate on past generated images. You would use it with the same multipart form data structure, with the input images in binary. The model supports up to 4 input images.  
For the prompt, you can reference the images based on the index, like `take the subject of image 1 and style it like image 0` or even use natural language like `place the dog beside the woman`.  
Note: you have to name the input parameter as `input_image_0`, `input_image_1`, `input_image_2`, `input_image_3` for it to work correctly. All input images must be smaller than 512x512.  
```bashcurl --request POST \  --url 'https://api.cloudflare.com/client/v4/accounts/{ACCOUNT}/ai/run/@cf/black-forest-labs/flux-2-klein-4b' \  --header 'Authorization: Bearer {TOKEN}' \  --header 'Content-Type: multipart/form-data' \  --form 'prompt=take the subject of image 1 and style it like image 0' \  --form input_image_0=@/Users/johndoe/Desktop/icedoutkeanu.png \  --form input_image_1=@/Users/johndoe/Desktop/me.png \  --form width=1024 \  --form height=1024  
```  
Through Workers AI Binding:  
JavaScript  
```  
//helper function to convert ReadableStream to Blobasync function streamToBlob(stream: ReadableStream, contentType: string): Promise<Blob> {  const reader = stream.getReader();  const chunks = [];  
  while (true) {    const { done, value } = await reader.read();    if (done) break;    chunks.push(value);  }  
  return new Blob(chunks, { type: contentType });}  
const image0 = await fetch("http://image-url");const image1 = await fetch("http://image-url");const form = new FormData();  
const image_blob0 = await streamToBlob(image0.body, "image/png");const image_blob1 = await streamToBlob(image1.body, "image/png");form.append('input_image_0', image_blob0)form.append('input_image_1', image_blob1)form.append('prompt', 'take the subject of image 1 and style it like image 0')  
// FormData doesn't expose its serialized body or boundary. Passing it to a// Request (or Response) constructor serializes it and generates the Content-Type// header with the boundary, which is required for the server to parse the multipart fields.const formResponse = new Response(form);const formStream = formResponse.body;const formContentType = formResponse.headers.get('content-type');  
const resp = await env.AI.run("@cf/black-forest-labs/flux-2-klein-4b", {    multipart: {        body: formStream,        contentType: formContentType    }})  
```

Jan 13, 2026
1. ### [AI Crawl Control Read Only role now available](https://developers.cloudflare.com/changelog/post/2026-01-13-ai-crawl-control-read-only-role/)  
[ AI Crawl Control ](https://developers.cloudflare.com/ai-crawl-control/)  
Account administrators can now assign the **AI Crawl Control Read Only** role to provide read-only access to AI Crawl Control at the domain level.  
Users with this role can view the **Overview**, **Crawlers**, **Metrics**, **Robots.txt**, and **Settings** tabs but cannot modify crawler actions or settings.  
This role is specific for AI Crawl Control. You still require correct permissions to access other areas / features of the dashboard.  
To assign, go to **Manage Account** \> **Members** and add a policy with the **AI Crawl Control Read Only** role scoped to the desired domain.

Dec 22, 2025
1. ### [Agents SDK v0.3.0, workers-ai-provider v3.0.0, and ai-gateway-provider v3.0.0 with AI SDK v6 support](https://developers.cloudflare.com/changelog/post/2025-12-22-agents-sdk-ai-sdk-v6/)  
[ Agents ](https://developers.cloudflare.com/agents/)[ Workers ](https://developers.cloudflare.com/workers/)  
We've shipped a new release for the [Agents SDK ↗](https://github.com/cloudflare/agents) v0.3.0 bringing full compatibility with [AI SDK v6 ↗](https://ai-sdk.dev/docs/introduction) and introducing the unified tool pattern, dynamic tool approval, and enhanced React hooks with improved tool handling.  
This release includes improved streaming and tool support, dynamic tool approval (for "human in the loop" systems), enhanced React hooks with `onToolCall` callback, improved error handling for streaming responses, and seamless migration from v5 patterns.  
This makes it ideal for building production AI chat interfaces with Cloudflare Workers AI models, agent workflows, human-in-the-loop systems, or any application requiring reliable tool execution and approval workflows.  
Additionally, we've updated **workers-ai-provider v3.0.0**, the official provider for Cloudflare Workers AI models, and **ai-gateway-provider v3.0.0**, the provider for Cloudflare AI Gateway, to be compatible with AI SDK v6.  
#### Agents SDK v0.3.0  
#### Unified Tool Pattern  
AI SDK v6 introduces a unified tool pattern where all tools are defined on the server using the `tool()` function. This replaces the previous client-side `AITool` pattern.  
#### Server-Side Tool Definition  
TypeScript  
```  
import { tool } from "ai";import { z } from "zod";  
// Server: Define ALL tools on the serverconst tools = {  // Server-executed tool  getWeather: tool({    description: "Get weather for a city",    inputSchema: z.object({ city: z.string() }),    execute: async ({ city }) => fetchWeather(city)  }),  
  // Client-executed tool (no execute = client handles via onToolCall)  getLocation: tool({    description: "Get user location from browser",    inputSchema: z.object({})    // No execute function  }),  
  // Tool requiring approval (dynamic based on input)  processPayment: tool({    description: "Process a payment",    inputSchema: z.object({ amount: z.number() }),    needsApproval: async ({ amount }) => amount > 100,    execute: async ({ amount }) => charge(amount)  })};  
```  
#### Client-Side Tool Handling  
TypeScript  
```  
// Client: Handle client-side tools via onToolCall callbackimport { useAgentChat } from "agents/ai-react";  
const { messages, sendMessage, addToolOutput } = useAgentChat({  agent,  onToolCall: async ({ toolCall, addToolOutput }) => {    if (toolCall.toolName === "getLocation") {      const position = await new Promise((resolve, reject) => {        navigator.geolocation.getCurrentPosition(resolve, reject);      });      addToolOutput({        toolCallId: toolCall.toolCallId,        output: {          lat: position.coords.latitude,          lng: position.coords.longitude        }      });    }  }});  
```

**Key benefits of the unified tool pattern:**

  * **Server-defined tools**: All tools are defined in one place on the server
  * **Dynamic approval**: Use `needsApproval` to conditionally require user confirmation
  * **Cleaner client code**: Use `onToolCall` callback instead of managing tool configs
  * **Type safety**: Full TypeScript support with proper tool typing  
#### useAgentChat(options)  
Creates a new chat interface with enhanced v6 capabilities.  
TypeScript  
```  
// Basic chat setup with onToolCallconst { messages, sendMessage, addToolOutput } = useAgentChat({  agent,  onToolCall: async ({ toolCall, addToolOutput }) => {    // Handle client-side tool execution    await addToolOutput({      toolCallId: toolCall.toolCallId,      output: { result: "success" }    });  }});  
```  
#### Dynamic Tool Approval  
Use `needsApproval` on server tools to conditionally require user confirmation:  
TypeScript  
```  
const paymentTool = tool({  description: "Process a payment",  inputSchema: z.object({    amount: z.number(),    recipient: z.string()  }),  needsApproval: async ({ amount }) => amount > 1000,  execute: async ({ amount, recipient }) => {    return await processPayment(amount, recipient);  }});  
```  
#### Tool Confirmation Detection  
The `isToolUIPart` and `getToolName` functions now check both static and dynamic tool parts:  
TypeScript  
```  
import { isToolUIPart, getToolName } from "ai";  
const pendingToolCallConfirmation = messages.some((m) =>  m.parts?.some(    (part) => isToolUIPart(part) && part.state === "input-available",  ),);  
// Handle tool confirmationif (pendingToolCallConfirmation) {  await addToolOutput({    toolCallId: part.toolCallId,    output: "User approved the action"  });}  
```  
If you need the v5 behavior (static-only checks), use the new functions:  
TypeScript  
```  
import { isStaticToolUIPart, getStaticToolName } from "ai";  
```  
#### convertToModelMessages() is now async  
The `convertToModelMessages()` function is now asynchronous. Update all calls to await the result:  
TypeScript  
```  
import { convertToModelMessages } from "ai";  
const result = streamText({  messages: await convertToModelMessages(this.messages),  model: openai("gpt-4o")});  
```  
#### ModelMessage type  
The `CoreMessage` type has been removed. Use `ModelMessage` instead:  
TypeScript  
```  
import { convertToModelMessages, type ModelMessage } from "ai";  
const modelMessages: ModelMessage[] = await convertToModelMessages(messages);  
```  
#### generateObject mode option removed  
The `mode` option for `generateObject` has been removed:  
TypeScript  
```  
// Before (v5)const result = await generateObject({  mode: "json",  model,  schema,  prompt});  
// After (v6)const result = await generateObject({  model,  schema,  prompt});  
```  
#### Structured Output with generateText  
While `generateObject` and `streamObject` are still functional, the recommended approach is to use `generateText`/`streamText` with the `Output.object()` helper:  
TypeScript  
```  
import { generateText, Output, stepCountIs } from "ai";  
const { output } = await generateText({  model: openai("gpt-4"),  output: Output.object({    schema: z.object({ name: z.string() })  }),  stopWhen: stepCountIs(2),  prompt: "Generate a name"});  
```  
> **Note**: When using structured output with `generateText`, you must configure multiple steps with `stopWhen` because generating the structured output is itself a step.  
#### workers-ai-provider v3.0.0  
Seamless integration with Cloudflare Workers AI models through the updated workers-ai-provider v3.0.0 with AI SDK v6 support.  
#### Model Setup with Workers AI  
Use Cloudflare Workers AI models directly in your agent workflows:  
TypeScript  
```  
import { createWorkersAI } from "workers-ai-provider";import { useAgentChat } from "agents/ai-react";  
// Create Workers AI model (v3.0.0 - enhanced v6 internals)const model = createWorkersAI({  binding: env.AI,})("@cf/meta/llama-3.2-3b-instruct");  
```  
#### Enhanced File and Image Support  
Workers AI models now support v6 file handling with automatic conversion:  
TypeScript  
```  
// Send images and files to Workers AI modelssendMessage({  role: "user",  parts: [    { type: "text", text: "Analyze this image:" },    {      type: "file",      data: imageBuffer,      mediaType: "image/jpeg",    },  ],});  
// Workers AI provider automatically converts to proper format  
```  
#### Streaming with Workers AI  
Enhanced streaming support with automatic warning detection:  
TypeScript  
```  
// Streaming with Workers AI modelsconst result = await streamText({  model: createWorkersAI({ binding: env.AI })("@cf/meta/llama-3.2-3b-instruct"),  messages: await convertToModelMessages(messages),  onChunk: (chunk) => {    // Enhanced streaming with warning handling    console.log(chunk);  },});  
```  
#### ai-gateway-provider v3.0.0  
The ai-gateway-provider v3.0.0 now supports AI SDK v6, enabling you to use Cloudflare AI Gateway with multiple AI providers including Anthropic, Azure, AWS Bedrock, Google Vertex, and Perplexity.  
#### AI Gateway Setup  
Use Cloudflare AI Gateway to add analytics, caching, and rate limiting to your AI applications:  
TypeScript  
```  
import { createAIGateway } from "ai-gateway-provider";  
// Create AI Gateway provider (v3.0.0 - enhanced v6 internals)const model = createAIGateway({  gatewayUrl: "https://gateway.ai.cloudflare.com/v1/your-account-id/gateway",  headers: {    "Authorization": `Bearer ${env.AI_GATEWAY_TOKEN}`  }})({  provider: "openai",  model: "gpt-4o"});  
```  
#### Migration from v5  
#### Deprecated APIs  
The following APIs are deprecated in favor of the unified tool pattern:

| Deprecated                            | Replacement                                      |
| ------------------------------------- | ------------------------------------------------ |
| AITool type                           | Use AI SDK's tool() function on server           |
| extractClientToolSchemas()            | Define tools on server, no client schemas needed |
| createToolsFromClientSchemas()        | Define tools on server with tool()               |
| toolsRequiringConfirmation option     | Use needsApproval on server tools                |
| experimental\_automaticToolResolution | Use onToolCall callback                          |
| tools option in useAgentChat          | Use onToolCall for client-side execution         |
| addToolResult()                       | Use addToolOutput()                              |  
#### Breaking Changes Summary

  1. **Unified Tool Pattern**: All tools must be defined on the server using `tool()`
  2. **`convertToModelMessages()` is async**: Add `await` to all calls
  3. **`CoreMessage` removed**: Use `ModelMessage` instead
  4. **`generateObject` mode removed**: Remove `mode` option
  5. **`isToolUIPart` behavior changed**: Now checks both static and dynamic tool parts  
#### Installation  
Update your dependencies to use the latest versions:  
Terminal window  
```  
npm install agents@^0.3.0 workers-ai-provider@^3.0.0 ai-gateway-provider@^3.0.0 ai@^6.0.0 @ai-sdk/react@^3.0.0 @ai-sdk/openai@^3.0.0  
```  
#### Resources

  * [Migration Guide ↗](https://github.com/cloudflare/agents/blob/main/docs/migration-to-ai-sdk-v6.md) \- Comprehensive migration documentation from v5 to v6
  * [AI SDK v6 Documentation ↗](https://ai-sdk.dev/docs/migration-guides/migration-guide-6-0) \- Official AI SDK migration guide
  * [AI SDK v6 Announcement ↗](https://vercel.com/blog/ai-sdk-6) \- Learn about new features in v6
  * [AI SDK Documentation ↗](https://sdk.vercel.ai/docs) \- Complete AI SDK reference
  * [GitHub Issues ↗](https://github.com/cloudflare/agents/issues) \- Report bugs or request features  
#### Feedback Welcome  
We'd love your feedback! We're particularly interested in feedback on:

  * **Migration experience** \- How smooth was the upgrade from v5 to v6?
  * **Unified tool pattern** \- How does the new server-defined tool pattern work for you?
  * **Dynamic tool approval** \- Does the `needsApproval` feature meet your needs?
  * **AI Gateway integration** \- How well does the new provider work with your setup?

Dec 18, 2025
1. ### [New AI Crawl Control Overview tab](https://developers.cloudflare.com/changelog/post/2025-12-18-overview-tab/)  
[ AI Crawl Control ](https://developers.cloudflare.com/ai-crawl-control/)  
The **Overview** tab is now the default view in AI Crawl Control. The previous default view with controls for individual AI crawlers is available in the **Crawlers** tab.  
#### What's new

  * **Executive summary** — Monitor total requests, volume change, most common status code, most popular path, and high-volume activity
  * **Operator grouping** — Track crawlers by their operating companies (OpenAI, Microsoft, Google, ByteDance, Anthropic, Meta)
  * **Customizable filters** — Filter your snapshot by date range, crawler, operator, hostname, or path  
![AI Crawl Control Overview tab showing executive summary, metrics, and crawler groups](https://developers.cloudflare.com/_astro/ai-crawl-control-overview-tab.Duwqq4bm_ZmNhCs.webp)  
#### Get started

  1. Log in to the Cloudflare dashboard and select your account and domain.
  2. Go to **AI Crawl Control**, where the **Overview** tab opens by default with your activity snapshot.
  3. Use filters to customize your view by date range, crawler, operator, hostname, or path.
  4. Navigate to the **Crawlers** tab to manage controls for individual crawlers.  
Learn more about [analyzing AI traffic](https://developers.cloudflare.com/ai-crawl-control/features/analyze-ai-traffic/) and [managing AI crawlers](https://developers.cloudflare.com/ai-crawl-control/features/manage-ai-crawlers/).

Dec 10, 2025
1. ### [Pay Per Crawl (Private beta) - Discovery API, custom pricing, and advanced configuration](https://developers.cloudflare.com/changelog/post/2025-12-10-pay-per-crawl-enhancements/)  
[ AI Crawl Control ](https://developers.cloudflare.com/ai-crawl-control/)  
Pay Per Crawl is introducing enhancements for both AI crawler operators and site owners, focusing on programmatic discovery, flexible pricing models, and granular configuration control.  
#### For AI crawler operators  
#### Discovery API  
A new authenticated API endpoint allows verified crawlers to programmatically discover domains participating in Pay Per Crawl. Crawlers can use this to build optimized crawl queues, cache domain lists, and identify new participating sites. This eliminates the need to discover payable content through trial requests.  
The API endpoint is `GET https://crawlers-api.ai-audit.cfdata.org/charged_zones` and requires Web Bot Auth authentication. Refer to [Discover payable content](https://developers.cloudflare.com/ai-crawl-control/features/pay-per-crawl/use-pay-per-crawl-as-ai-owner/discover-payable-content/) for authentication steps, request parameters, and response schema.  
#### Payment header signature requirement  
Payment headers (`crawler-exact-price` or `crawler-max-price`) must now be included in the Web Bot Auth `signature-input` header components. This security enhancement prevents payment header tampering, ensures authenticated payment intent, validates crawler identity with payment commitment, and protects against replay attacks with modified pricing. Crawlers must add their payment header to the list of signed components when [constructing the signature-input header](https://developers.cloudflare.com/ai-crawl-control/features/pay-per-crawl/use-pay-per-crawl-as-ai-owner/crawl-pages/#22-sign-your-request-with-web-bot-auth).  
#### New `crawler-error` header  
Pay Per Crawl error responses now include a new `crawler-error` header with 11 specific [error codes](https://developers.cloudflare.com/ai-crawl-control/features/pay-per-crawl/use-pay-per-crawl-as-ai-owner/error-codes/) for programmatic handling. Error response bodies remain unchanged for compatibility. These codes enable robust error handling, automated retry logic, and accurate spending tracking.  
#### For site owners  
#### Configure free pages  
Site owners can now offer free access to specific pages like homepages, navigation, or discovery pages while charging for other content. Create a [Configuration Rule](https://developers.cloudflare.com/ai-crawl-control/features/pay-per-crawl/use-pay-per-crawl-as-site-owner/advanced-configuration/#disable-pay-per-crawl-by-uri-pattern) in **Rules** \> **Configuration Rules**, set your URI pattern using wildcard, exact, or prefix matching on the **URI Full** field, and enable the **Disable Pay Per Crawl** setting. When disabled for a URI pattern, crawler requests pass through without blocking or charging.  
Some paths are always free to crawl. These paths are: `/robots.txt`, `/sitemap.xml`, `/security.txt`, `/.well-known/security.txt`, `/crawlers.json`.  
#### Get started

**AI crawler operators**: [Discover payable content](https://developers.cloudflare.com/ai-crawl-control/features/pay-per-crawl/use-pay-per-crawl-as-ai-owner/discover-payable-content/) | [Crawl pages](https://developers.cloudflare.com/ai-crawl-control/features/pay-per-crawl/use-pay-per-crawl-as-ai-owner/crawl-pages/)

**Site owners**: [Advanced configuration](https://developers.cloudflare.com/ai-crawl-control/features/pay-per-crawl/use-pay-per-crawl-as-site-owner/advanced-configuration/)

Nov 26, 2025
1. ### [Agents SDK v0.2.24 with resumable streaming, MCP improvements, and schedule fixes](https://developers.cloudflare.com/changelog/post/2025-11-26-agents-resumable-streaming/)  
[ Agents ](https://developers.cloudflare.com/agents/)[ Workers ](https://developers.cloudflare.com/workers/)  
The latest release of [@cloudflare/agents ↗](https://github.com/cloudflare/agents) brings resumable streaming, significant MCP client improvements, and critical fixes for schedules and Durable Object lifecycle management.  
#### Resumable streaming  
`AIChatAgent` now supports resumable streaming, allowing clients to reconnect and continue receiving streamed responses without losing data. This is useful for:

  * Long-running AI responses
  * Users on unreliable networks
  * Users switching between devices mid-conversation
  * Background tasks where users navigate away and return
  * Real-time collaboration where multiple clients need to stay in sync  
Streams are maintained across page refreshes, broken connections, and syncing across open tabs and devices.  
#### Other improvements

  * Default JSON schema validator added to MCP client
  * [Schedules ↗](https://developers.cloudflare.com/agents/runtime/execution/schedule-tasks/) can now safely destroy the agent  
#### MCP client API improvements  
The `MCPClientManager` API has been redesigned for better clarity and control:

  * **New `registerServer()` method**: Register MCP servers without immediately connecting
  * **New `connectToServer()` method**: Establish connections to registered servers
  * **Improved reconnect logic**: `restoreConnectionsFromStorage()` now properly handles failed connections  
TypeScript  
```  
// Register a server to Agentconst { id } = await this.mcp.registerServer({  name: "my-server",  url: "https://my-mcp-server.example.com",});  
// Connect when readyawait this.mcp.connectToServer(id);  
// Discover tools, prompts and resourcesawait this.mcp.discoverIfConnected(id);  
```  
The SDK now includes a formalized `MCPConnectionState` enum with states: `idle`, `connecting`, `authenticating`, `connected`, `discovering`, and `ready`.  
#### Enhanced MCP discovery  
MCP discovery fetches the available tools, prompts, and resources from an MCP server so your agent knows what capabilities are available. The `MCPClientConnection` class now includes a dedicated `discover()` method with improved reliability:

  * Supports cancellation via AbortController
  * Configurable timeout (default 15s)
  * Discovery failures now throw errors immediately instead of silently continuing  
#### Bug fixes

  * Fixed a bug where [schedules ↗](https://developers.cloudflare.com/agents/runtime/execution/schedule-tasks/) meant to fire immediately with this.schedule(0, ...) or `this.schedule(new Date(), ...)` would not fire
  * Fixed an issue where schedules that took longer than 30 seconds would occasionally time out
  * Fixed SSE transport now properly forwards session IDs and request headers
  * Fixed AI SDK stream events conversion to UIMessageStreamPart  
#### Upgrade  
To update to the latest version:  
Terminal window  
```  
npm i agents@latest  
```

Nov 25, 2025
1. ### [Launching FLUX.2 \[dev\] on Workers AI](https://developers.cloudflare.com/changelog/post/2025-11-25-flux-2-dev-workers-ai/)  
[ Workers AI ](https://developers.cloudflare.com/workers-ai/)  
We've partnered with Black Forest Labs (BFL) to bring their latest FLUX.2 \[dev\] model to Workers AI! This model excels in generating high-fidelity images with physical world grounding, multi-language support, and digital asset creation. You can also create specific super images with granular controls like JSON prompting.  
Read the [BFL blog ↗](https://bfl.ai/flux2) to learn more about the model itself. Read our [Cloudflare blog ↗](https://blog.cloudflare.com/flux-2-workers-ai) to see the model in action, or try it out yourself on our [multi modal playground ↗](https://multi-modal.ai.cloudflare.com/).  
Pricing documentation is available on the [model page](https://developers.cloudflare.com/workers-ai/models/flux-2-dev/) or [pricing page](https://developers.cloudflare.com/workers-ai/platform/pricing/). Note, we expect to drop pricing in the next few days after iterating on the model performance.  
#### Workers AI Platform specifics  
The model hosted on Workers AI is able to support up to 4 image inputs (512x512 per input image). Note, this image model is one of the most powerful in the catalog and is expected to be slower than the other image models we currently support. One catch to look out for is that this model takes multipart form data inputs, even if you just have a prompt.  
With the REST API, the multipart form data input looks like this:  
Terminal window  
```  
curl --request POST \  --url 'https://api.cloudflare.com/client/v4/accounts/{ACCOUNT}/ai/run/@cf/black-forest-labs/flux-2-dev' \  --header 'Authorization: Bearer {TOKEN}' \  --header 'Content-Type: multipart/form-data' \  --form 'prompt=a sunset at the alps' \  --form steps=25  --form width=1024  --form height=1024  
```  
With the Workers AI binding, you can use it as such:  
JavaScript  
```  
const form = new FormData();form.append('prompt', 'a sunset with a dog');form.append('width', '1024');form.append('height', '1024');  
//this dummy request is temporary hack//we're pushing a change to address this soonconst formRequest = new Request('http://dummy', {  method: 'POST',  body: form});const formStream = formRequest.body;const formContentType = formRequest.headers.get('content-type') || 'multipart/form-data';  
const resp = await env.AI.run("@cf/black-forest-labs/flux-2-dev", {  multipart: {    body: formStream,    contentType: formContentType  }});  
```  
The parameters you can send to the model are detailed here:  
JSON Schema for Model **Required Parameters**
  * `prompt` (string) - Text description of the image to generate

**Optional Parameters**

  * `input_image_0` (string) - Binary image
  * `input_image_1` (string) - Binary image
  * `input_image_2` (string) - Binary image
  * `input_image_3` (string) - Binary image
  * `steps` (integer) - Number of inference steps. Higher values may improve quality but increase generation time
  * `guidance` (float) - Guidance scale for generation. Higher values follow the prompt more closely
  * `width` (integer) - Width of the image, default `1024` Range: 256-1920
  * `height` (integer) - Height of the image, default `768` Range: 256-1920
  * `seed` (integer) - Seed for reproducibility  
```  
## Multi-Reference Images  
The FLUX.2 model is great at generating images based on reference images. You can use this feature to apply the style of one image to another, add a new character to an image, or iterate on past generate images. You would use it with the same multipart form data structure, with the input images in binary.  
For the prompt, you can reference the images based on the index, like `take the subject of image 1 and style it like image 0` or even use natural language like `place the dog beside the woman`.  
Note: you have to name the input parameter as `input_image_0`, `input_image_1`, `input_image_2` for it to work correctly. All input images must be smaller than 512x512.  
```bashcurl --request POST \  --url 'https://api.cloudflare.com/client/v4/accounts/{ACCOUNT}/ai/run/@cf/black-forest-labs/flux-2-dev' \  --header 'Authorization: Bearer {TOKEN}' \  --header 'Content-Type: multipart/form-data' \  --form 'prompt=take the subject of image 1 and style it like image 0' \  --form input_image_0=@/Users/johndoe/Desktop/icedoutkeanu.png \  --form input_image_1=@/Users/johndoe/Desktop/me.png \  --form steps=25  --form width=1024  --form height=1024  
```  
Through Workers AI Binding:  
JavaScript  
```  
//helper function to convert ReadableStream to Blobasync function streamToBlob(stream: ReadableStream, contentType: string): Promise<Blob> {  const reader = stream.getReader();  const chunks = [];  
  while (true) {    const { done, value } = await reader.read();    if (done) break;    chunks.push(value);  }  
  return new Blob(chunks, { type: contentType });}  
const image0 = await fetch("http://image-url");const image1 = await fetch("http://image-url");const form = new FormData();  
const image_blob0 = await streamToBlob(image0.body, "image/png");const image_blob1 = await streamToBlob(image1.body, "image/png");form.append('input_image_0', image_blob0)form.append('input_image_1', image_blob1)form.append('prompt', 'take the subject of image 1and style it like image 0')  
//this dummy request is temporary hack//we're pushing a change to address this soonconst formRequest = new Request('http://dummy', {  method: 'POST',  body: form});const formStream = formRequest.body;const formContentType = formRequest.headers.get('content-type') || 'multipart/form-data';  
const resp = await env.AI.run("@cf/black-forest-labs/flux-2-dev", {    multipart: {        body: form,        contentType: "multipart/form-data"    }})  
```  
#### JSON Prompting  
The model supports prompting in JSON to get more granular control over images. You would pass the JSON as the value of the 'prompt' field in the multipart form data. See the JSON schema below on the base parameters you can pass to the model.  
JSON Prompting Schema  
```  
{  "type": "object",  "properties": {    "scene": {      "type": "string",      "description": "Overall scene setting or location"    },    "subjects": {      "type": "array",      "items": {        "type": "object",        "properties": {          "type": {            "type": "string",            "description": "Type of subject (e.g., desert nomad, blacksmith, DJ, falcon)"          },          "description": {            "type": "string",            "description": "Physical attributes, clothing, accessories"          },          "pose": {            "type": "string",            "description": "Action or stance"          },          "position": {            "type": "string",            "enum": ["foreground", "midground", "background"],            "description": "Depth placement in scene"          }        },        "required": ["type", "description", "pose", "position"]      }    },    "style": {      "type": "string",      "description": "Artistic rendering style (e.g., digital painting, photorealistic, pixel art, noir sci-fi, lifestyle photo, wabi-sabi photo)"    },    "color_palette": {      "type": "array",      "items": { "type": "string" },      "minItems": 3,      "maxItems": 3,      "description": "Exactly 3 main colors for the scene (e.g., ['navy', 'neon yellow', 'magenta'])"    },    "lighting": {      "type": "string",      "description": "Lighting condition and direction (e.g., fog-filtered sun, moonlight with star glints, dappled sunlight)"    },    "mood": {      "type": "string",      "description": "Emotional atmosphere (e.g., harsh and determined, playful and modern, peaceful and dreamy)"    },    "background": {      "type": "string",      "description": "Background environment details"    },    "composition": {      "type": "string",      "enum": [        "rule of thirds",        "circular arrangement",        "framed by foreground",        "minimalist negative space",        "S-curve",        "vanishing point center",        "dynamic off-center",        "leading leads",        "golden spiral",        "diagonal energy",        "strong verticals",        "triangular arrangement"      ],      "description": "Compositional technique"    },    "camera": {      "type": "object",      "properties": {        "angle": {          "type": "string",          "enum": ["eye level", "low angle", "slightly low", "bird's-eye", "worm's-eye", "over-the-shoulder", "isometric"],          "description": "Camera perspective"        },        "distance": {          "type": "string",          "enum": ["close-up", "medium close-up", "medium shot", "medium wide", "wide shot", "extreme wide"],          "description": "Framing distance"        },        "focus": {          "type": "string",          "enum": ["deep focus", "macro focus", "selective focus", "sharp on subject", "soft background"],          "description": "Focus type"        },        "lens": {          "type": "string",          "enum": ["14mm", "24mm", "35mm", "50mm", "70mm", "85mm"],          "description": "Focal length (wide to telephoto)"        },        "f-number": {          "type": "string",          "description": "Aperture (e.g., f/2.8, the smaller the number the more blurry the background)"        },        "ISO": {          "type": "number",          "description": "Light sensitivity value (comfortable range between 100 & 6400, lower = less sensitivity)"        }      }    },    "effects": {      "type": "array",      "items": { "type": "string" },      "description": "Post-processing effects (e.g., 'lens flare small', 'subtle film grain', 'soft bloom', 'god rays', 'chromatic aberration mild')"    }  },  "required": ["scene", "subjects"]}  
```  
#### Other features to try

  * The model also supports the most common latin and non-latin character languages
  * You can prompt the model with specific hex codes like `#2ECC71`
  * Try creating digital assets like landing pages, comic strips, infographics too!

Nov 19, 2025
1. ### [AI Search support for crawling login protected website content](https://developers.cloudflare.com/changelog/post/2025-11-19-add-extra-headers-for-website-crawling/)  
[ AI Search ](https://developers.cloudflare.com/ai-search/)  
[AI Search](https://developers.cloudflare.com/ai-search/) now supports [custom HTTP headers](https://developers.cloudflare.com/ai-search/configuration/data-source/website/#extra-headers-for-access-protected-content) for website crawling, solving a common problem where valuable content behind authentication or access controls could not be indexed.  
Previously, AI Search could only crawl publicly accessible pages, leaving knowledge bases, documentation, and other protected content out of your search results. With custom headers support, you can now include authentication credentials that allow the crawler to access this protected content.  
This is particularly useful for indexing content like:

  * **Internal documentation** behind corporate login systems
  * **Premium content** that requires users to provide access to unlock
  * **Sites protected by Cloudflare Access** using service tokens  
To add custom headers when creating an AI Search instance, select **Parse options**. In the **Extra headers** section, you can add up to five custom headers per Website data source.  
![Custom headers configuration in AI Search](https://developers.cloudflare.com/_astro/ai-search-extra-headers.B7A2spby_lEmuv.webp)  
For example, to crawl a site protected by [Cloudflare Access](https://developers.cloudflare.com/cloudflare-one/access-controls/), you can add service token credentials as custom headers:  
```  
CF-Access-Client-Id: your-token-id.accessCF-Access-Client-Secret: your-token-secret  
```  
The crawler will automatically include these headers in all requests, allowing it to access protected pages that would otherwise be blocked.  
Learn more about [configuring custom headers for website crawling](https://developers.cloudflare.com/ai-search/configuration/data-source/website/#extra-headers-for-access-protected-content) in AI Search.

```json
{"@context":"https://schema.org","@type":"BlogPosting","@id":"https://developers.cloudflare.com/changelog/product-group/ai/3/#page","headline":"AI Changelog | Cloudflare Docs","url":"https://developers.cloudflare.com/changelog/product-group/ai/3/","inLanguage":"en","image":"https://developers.cloudflare.com/cf-twitter-card.png","publisher":{"@type":"Organization","name":"Cloudflare","url":"https://www.cloudflare.com/"},"isPartOf":{"@type":"WebSite","@id":"https://developers.cloudflare.com/#website","name":"Cloudflare Docs","url":"https://developers.cloudflare.com/"}}
```
