agents@0.27.0

cloudflare/agentsagents@0.27.0Oct 7, 2026by github-actions[bot]

Upgrading?

AI Summary

This release introduces four new experimental harnesses (AiSdkHarness, ThinkHarness, ContainerHarness, OpenCodeHarness), a new web search tool, and reorganizes the Channels API into an experimental module.

Key Highlights

  • Adds four new experimental harnesses (AiSdkHarness, ThinkHarness, ContainerHarness, OpenCodeHarness) compatible with the PiHarness interface.
  • Introduces `agents/websearch` for a web search tool using Cloudflare's Web Search API.
  • Reorganizes Channels API: moved to `agents/experimental/channels`, removing old entry points like `ChannelHost` and `fallback`/`fanout` composites.
  • Adds `npx agents tui` for a terminal client and new components like `ChannelGateway` and Web Channel client.

Breaking Changes

  • The `agents/channels` entry point has been removed.
  • Slack, Telegram, and Email channels have been moved to `agents/experimental/channels/` subdirectories.
  • The `fallback` and `fanout` composites have been removed.

New Features

  • AiSdkHarness for running messages with streamText
  • ThinkHarness for running Think's agent loop as a Lifecycle capability
  • ContainerHarness for running Claude Code or Codex in a Cloudflare Container
  • OpenCodeHarness for hosting OpenCode v2
  • Web search tool for pi, AI SDK, and TanStack AI
  • ChannelGateway for webhook verification and routing
  • Web Channel client for browsers and terminals
  • AI SDK chat transport over the Web Channel

Full Release Notes

This release adds four new experimental harnesses and a `web_search` tool, and reorganizes the experimental Channels API.

-   **New experimental harnesses:** `AiSdkHarness`, `ThinkHarness`, `ContainerHarness` (which runs Claude Code or Codex in a Container) and `OpenCodeHarness`, all with the same shape as `PiHarness`.
-   **New `agents/websearch`:** a `web_search` tool over Cloudflare's Web Search API for pi, the AI SDK and TanStack AI.
-   **Channels moved to `agents/experimental/channels`:** Channels is being rebuilt around conversations and turns, and the old `agents/channels` entry point has been removed. The new API includes `ChannelGateway`, the Web Channel and its client, an AI SDK chat transport, and a new `npx agents tui` terminal client.
-   **Fixes:** Streams, Tasks, `useAgentChat` reconnects, `WebChannelClient`, MCP credential cleanup on `removeServer()`, and x402 with MCP SDK v2.

### Minor Changes

-   [#2434](https://github.com/cloudflare/agents/pull/2434) [`0ebeae5`](https://github.com/cloudflare/agents/commit/0ebeae52a7897cd04ae8921663a92dfd52f04c49) Thanks [@cjol](https://github.com/cjol)! - Add `AiSdkHarness` from the new `agents/harness/ai-sdk` entry point, which runs each message with `streamText` and keeps sessions and transcripts in the Durable Object, so `Channels.forHarness` can serve an AI SDK model. The same entry point exports the AI SDK message conversions it is built on and `createSendMessageTool`, an AI SDK tool that sends a message to a surface through the gateway.

-   [#2431](https://github.com/cloudflare/agents/pull/2431) [`6393265`](https://github.com/cloudflare/agents/commit/6393265469703cb6d094368dfa3fbadc43742057) Thanks [@cjol](https://github.com/cjol)! - Add `Channels` to `agents/experimental/channels`: a Lifecycle capability that serves an agent harness's sessions as conversations to every surface that joins them, with durable, resumable responses on `Streams`. Connect a harness with `Channels.forHarness(harness, { channels })`. The entry point also exports the turn protocol types and a draft harness interface (`AgentHarness`), which may change.

-   [#2429](https://github.com/cloudflare/agents/pull/2429) [`df4cbd6`](https://github.com/cloudflare/agents/commit/df4cbd69d777ed240c69da7fb2791fee567a6d62) Thanks [@cjol](https://github.com/cjol)! - Breaking: remove the first pass of `agents/channels` and move Channels to `agents/experimental/channels`.

    The `agents/channels` entry points are gone, along with `ChannelHost`, the `fallback` and `fanout` composites, and the AI SDK, TanStack AI and Voice helpers from the first pass. Slack, Telegram and Email move to `agents/experimental/channels/slack`, `agents/experimental/channels/telegram` and `agents/experimental/channels/email`, and keep verified ingress and normalization. Channels is being rebuilt around conversations and turns; the new API is experimental and may change between releases.

-   [#2432](https://github.com/cloudflare/agents/pull/2432) [`752cdc3`](https://github.com/cloudflare/agents/commit/752cdc30451302a0f44b1fc33661bf26034b5f64) Thanks [@cjol](https://github.com/cjol)! - Add `ChannelGateway` to `agents/experimental/channels`: the Worker entry point that verifies channel webhooks, takes Web Channel upgrades through `web()` from `agents/experimental/channels/web`, routes each to the agent object that holds its conversation, and delivers outbound messages. Every Channel that takes ingress needs a `participant` callback, where the application says who the sender is; Channels never picks an identity. The agent object is the authorization boundary: by default each participant gets one of their own, and a `route` callback can share one between participants or refuse them.

-   [#2436](https://github.com/cloudflare/agents/pull/2436) [`062d091`](https://github.com/cloudflare/agents/commit/062d0911b307249fa1a7cae7eb8628e9c1bee0e7) Thanks [@cjol](https://github.com/cjol)! - Add `WebChannelChatTransport` (`agents/experimental/channels/web/ai-sdk`), an AI SDK `ChatTransport` over the Web Channel, so AI SDK UIs can join a Channels conversation.

-   [#2433](https://github.com/cloudflare/agents/pull/2433) [`6e6c58a`](https://github.com/cloudflare/agents/commit/6e6c58a195502336bc75d0535baf71d3f293dcfb) Thanks [@cjol](https://github.com/cjol)! - Add the Web Channel (`agents/experimental/channels/web`) and its client (`agents/experimental/channels/web/client`), which connect browsers and terminals to a conversation over the agent's WebSockets: live transcript and turns, approvals, client tool results, and creating, forking, resetting, listing and following conversations. `WebSockets` gains `use` for protocol handlers that run before the configured ones.

-   [#2502](https://github.com/cloudflare/agents/pull/2502) [`66ae955`](https://github.com/cloudflare/agents/commit/66ae9558f2fe1cc7471aca74a978cf0f121993a5) Thanks [@ben-reitz](https://github.com/ben-reitz)! - Add `agents/websearch`, a `web_search` tool over Cloudflare's [Web Search API](https://developers.cloudflare.com/web-search/) for the pi harness, the AI SDK, and TanStack AI. See [Search the Web](https://github.com/cloudflare/agents/blob/main/docs/agents/search-the-web.md).

### Patch Changes

-   [#2480](https://github.com/cloudflare/agents/pull/2480) [`1923625`](https://github.com/cloudflare/agents/commit/192362588225e78231cefe7a8bdc8aeacda6d223) Thanks [@cjol](https://github.com/cjol)! - `AiSdkHarness`: `session.wait(operationId, signal)` now rejects straight away when `signal` is already aborted, instead of staying pending until the operation settles.

-   [#2463](https://github.com/cloudflare/agents/pull/2463) [`1e97e11`](https://github.com/cloudflare/agents/commit/1e97e11768205e3a81749e4547d60bcc35613203) Thanks [@cjol](https://github.com/cjol)! - `AiSdkHarness` no longer fails to start when it has stored sessions. `onStart` listed sessions while listing each one's pending work, and Durable Object storage allows one open `kv.list()` at a time, so a restarted agent stopped acknowledging messages.

-   [#2502](https://github.com/cloudflare/agents/pull/2502) [`66ae955`](https://github.com/cloudflare/agents/commit/66ae9558f2fe1cc7471aca74a978cf0f121993a5) Thanks [@ben-reitz](https://github.com/ben-reitz)! - `AiSdkHarness` passes its tools to `convertToModelMessages`, so a tool's `toModelOutput` also shapes its results on later turns instead of the model getting the raw output as JSON.

-   [#2488](https://github.com/cloudflare/agents/pull/2488) [`98ec934`](https://github.com/cloudflare/agents/commit/98ec934206a9ae0460d2bccadd4f5c17a1909a1d) Thanks [@ben-reitz](https://github.com/ben-reitz)! - `browserTool` now has its own tool description instead of codemode's generic one. It covers the `cdp` API, common CDP mistakes, and the run time limit, so the model no longer runs `codemode.search` first. It also explains how to take a smaller screenshot when one is over the 1 MB result limit. See [Persistent browser](https://github.com/cloudflare/agents/blob/main/docs/agents/browse-the-web.md#persistent-browser).

-   [#2437](https://github.com/cloudflare/agents/pull/2437) [`5a7643e`](https://github.com/cloudflare/agents/commit/5a7643e1260e03f523609e06a0a8d7744a6ff84a) Thanks [@cjol](https://github.com/cjol)! - Add `npx agents tui <url>`, a terminal client for a conversation's Web Channel.

    It streams the transcript with highlighted Markdown, collapsible reasoning and tool cards, and shows messages and turns from every surface live. It answers approvals inline, lets a person type a client tool's result, and cancels the running turn with Esc. `--header` adds headers to the WebSocket upgrade, and `CF_ACCESS_CLIENT_ID` / `CF_ACCESS_CLIENT_SECRET` are sent as an Access service token. Its dependencies are bundled into `dist/cli.js`, so installing `agents` adds none.

-   [#2514](https://github.com/cloudflare/agents/pull/2514) [`1203bdd`](https://github.com/cloudflare/agents/commit/1203bdd1c5c98443e3b5c77abdeb6961435a37fd) Thanks [@mattzcarey](https://github.com/mattzcarey)! - Add experimental `agents/harness/container`, `agents/harness/container/daemon`, `agents/harness/container/runtime` and `agents/harness/store`. Everything in them may change before it stabilizes.

    `ContainerHarness` runs an agent CLI such as Claude Code or Codex in a Cloudflare Container (`ctx.container`) and drives it from a Durable Object, with the same interface as `PiHarness` (`prompt`, `submit`, `wait`, `abort`, `messages`, `pending`, `session(id)`, `sessions`). Typed presets (`claudeCode()`, `codex()`, `containerAgent()`) say what runs: the harness builds the container from `cloudflare/debian-trixie` at runtime and snapshots it, so there is no image to build, and `ContainerEgress` adds credentials (`apiKey`, `baseUrl`, `headers`) outside the container, which only ever sees a placeholder key. The container stops after an idle timeout (five minutes by default) and the next prompt starts a new one in which the CLI resumes its own session; a container lost mid-run settles that run as `container_lost` (or reruns it with `onContainerLost: "retry"`), and an object evicted mid-run reattaches and replays what it missed. `agents/harness/container/runtime` is the daemon's Node runtime with `cliAdapter`, for images that bring their own CLI; `agents/harness/container/daemon` is its runtime-agnostic core; and `agents/harness/store` is a session store on the object's SQLite that any harness can use.

-   [#2475](https://github.com/cloudflare/agents/pull/2475) [`7a4c6c0`](https://github.com/cloudflare/agents/commit/7a4c6c0329efc44abe557a6052c9a1dab91359ef) Thanks [@mattzcarey](https://github.com/mattzcarey)! - `MCPClientManager.removeServer()` (and `Agent.removeMcpServer()`) now clears the server's saved OAuth state from Durable Object storage: tokens and client information (including those under earlier client IDs), verifiers, pending states and discovery state. This also works when the server's connection was already closed. Other servers' credentials are untouched, and tokens are not revoked at the OAuth provider. Custom auth providers get `invalidateCredentials("all")`.

-   [#2513](https://github.com/cloudflare/agents/pull/2513) [`f2f745b`](https://github.com/cloudflare/agents/commit/f2f745b58a4fa651472cd0921b466945cba4f62f) Thanks [@mattzcarey](https://github.com/mattzcarey)! - Add experimental `agents/harness/opencode` and `agents/models/opencode`. `OpenCodeHarness` hosts OpenCode v2 (`@opencode/sdk/workerd`) in a Durable Object behind the same interface as `PiHarness`: OpenCode's tables are kept under an `opencode_` prefix, a Lifecycle wake job per session brings runs back after eviction, and the harness closes OpenCode when it is idle so the object can hibernate. `createAI({ binding })` from `agents/models/opencode` returns an OpenCode plugin that serves Workers AI models through the `AI` binding. Both APIs are experimental and will change.

-   [#2458](https://github.com/cloudflare/agents/pull/2458) [`6bf0378`](https://github.com/cloudflare/agents/commit/6bf03781e5486f72952772ebee44f82519998bf4) Thanks [@cjol](https://github.com/cjol)! - Streams: a live `read`/`readBatches` no longer misses chunks appended while the consumer is still handling the previous batch. It re-polls before waiting for the next append, so a reader no longer stalls until a later append or the stream's end.

-   [#2512](https://github.com/cloudflare/agents/pull/2512) [`bda70b5`](https://github.com/cloudflare/agents/commit/bda70b520422ee65e80f02f0300f424e1c990954) Thanks [@mattzcarey](https://github.com/mattzcarey)! - `Streams` rechecks that the v1 chunk table still exists before using it. Two Streams instances on one object, such as a host's own and the one `ThinkHarness` keeps, each remembered the table separately, so after one folded the last v1 rows and dropped the table the other failed its next append with `no such table`.

-   [#2476](https://github.com/cloudflare/agents/pull/2476) [`9f92f6f`](https://github.com/cloudflare/agents/commit/9f92f6f8aa47ec21d6384fbbeb17145362d1c973) Thanks [@mattzcarey](https://github.com/mattzcarey)! - A routed Task wake whose owner facet is no longer in the root's registry now ends quietly instead of throwing `Invalid job outcome` on the alarm.

-   [#2512](https://github.com/cloudflare/agents/pull/2512) [`bda70b5`](https://github.com/cloudflare/agents/commit/bda70b520422ee65e80f02f0300f424e1c990954) Thanks [@mattzcarey](https://github.com/mattzcarey)! - Add `ThinkHarness` from the new experimental `agents/harness/think` entry point. It runs Think's agent loop as a Lifecycle capability with the same shape as `PiHarness` (`prompt`, `submit`, `wait`, `abort`, `sessions`, `session(id)`), and implements the shared harness interface Channels serves.

    The harness owns its storage: transcripts in the Sessions tables, with `branches()`, `search()` and `compact()` on each session, and in-flight model output in the Streams tables, so a host installs only the harness. Each session has one Lifecycle wake job, so a turn interrupted by an eviction picks up from its last durable write: a cut-short model call is rebuilt from its stream and continued in the same message, and a cut-short tool call is reported to the model, or rerun when the tool carries `recovery: "rerun"`. `ThinkChat` serves a session over Think's `useAgentChat` WebSocket protocol. See [Think harness](https://github.com/cloudflare/agents/blob/main/docs/agents/harnesses/think.md).

-   [#2462](https://github.com/cloudflare/agents/pull/2462) [`2f3176b`](https://github.com/cloudflare/agents/commit/2f3176b9fa03c6429c805b560c8dc14371c15f64) Thanks [@cjol](https://github.com/cjol)! - `agents tui` now handles Cloudflare Access: for a URL behind Access, it gets a token from `cloudflared` (logging in through the browser the first time) and sends it on the WebSocket upgrade. `CF_ACCESS_CLIENT_ID` / `CF_ACCESS_CLIENT_SECRET` and explicit `--header` credentials still take precedence.

-   [#2481](https://github.com/cloudflare/agents/pull/2481) [`fcc23f4`](https://github.com/cloudflare/agents/commit/fcc23f422a66dc3445f0114b808ea43ff1596e7b) Thanks [@cjol](https://github.com/cjol)! - `agents tui` drops a `#fragment` from the URL it is given, since a WebSocket URL cannot carry one. Previously such a URL made the client exit before connecting.

-   [#2496](https://github.com/cloudflare/agents/pull/2496) [`cf7c9e3`](https://github.com/cloudflare/agents/commit/cf7c9e3cd06a9250434fabf87b26d29b3485b9cc) Thanks [@ben-reitz](https://github.com/ben-reitz)! - `useAgentChat` replaces a cut-off assistant reply with the server's copy after the WebSocket drops mid-stream. Think sends that copy on reconnect; AIChatAgent doesn't yet.

-   [#2479](https://github.com/cloudflare/agents/pull/2479) [`f3d13e9`](https://github.com/cloudflare/agents/commit/f3d13e91badd99536f962628afc0464cb7b544d8) Thanks [@cjol](https://github.com/cjol)! - `WebChannelClient`: `send()` and `listConversations()` now reject once the client is closed instead of waiting forever. `follow()` and `close()` also cancel a reconnect still waiting after a dropped connection, so it no longer opens a second socket that replaces the followed one or reconnects a closed client.

-   [#2494](https://github.com/cloudflare/agents/pull/2494) [`04922ec`](https://github.com/cloudflare/agents/commit/04922ec512b3ae8d0d2b526f295be9774d70d201) Thanks [@ben-reitz](https://github.com/ben-reitz)! - `withX402(...).paidTool` now reads the payment from MCP SDK v2 servers, and matches the `PAYMENT-SIGNATURE` / `X-PAYMENT` headers case-insensitively.

Related Repositories