Packages

agents

0.29.0 · 20 Oct 2026MIT1.5M / weekRepositorynpmAtom feed

205 stable releases, newest first, by release line. Notes are quoted as the maintainers published them.

  1. 0.29.x · latest line
  2. 0.29.0

    20 Oct 2026
    • deprecated

      Chat recovery now seals a turn after chatRecovery.maxInterruptedAttempts interrupted attempts (default 5), so a turn that exceeds the Durable Object memory limit on every run no longer retries forever; maxOomRetries is deprecated. See Stream Recovery.

    • Agent Skills read and write a @cloudflare/computer Workspace, for both projection and skills.runner(). See Upgrading to a Computer workspace.

    • Browser creates and closes its Browser Run sessions with the binding's typed acquire() and closeSession(), falling back to the HTTP API in fully local dev. See Browser.

  3. 0.28.x
  4. 0.28.1

    13 Oct 2026
  5. 0.28.0

    9 Oct 2026
    • Add browserTool() to agents/browser/pi. See Persistent browser.

    • Make agents/lifecycle stable along with the Scheduler (agents/schedules), State (agents/state), WebSockets (agents/websockets) and MCPClientManager (agents/mcp/client) capabilities. See Lifecycle.

    • ThinkHarness now keeps its sessions and operations in the shared agents/harness/store. Migrations are performed on first run. See ThinkHarness: Recovery.

  6. 0.27.x
  7. 0.27.0

    7 Oct 2026
    • 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.

    • 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.

  8. 0.26.x
  9. 0.26.0

    2 Oct 2026
    • Update pi-durable and pi-ai to ^1.0.0. See Pi harness docs for details.

  10. 0.25.x
  11. 0.25.0

    2 Oct 2026
    • deprecated

      Keep assistant messages and tool outputs attached to the correct turn when a provider reuses a toolCallId; resolveToolMergeId is deprecated in favour of reconcileMessages. See Chat agents.

    • Native RPC calls to async Agent and Think methods now start lifecycle initialization first; address Agents by name because raw IDs from newUniqueId() and idFromString() now fail their first async RPC. See Lifecycle.

    • Report a failed agent-tool child as failed even when it was evicted before recording the failure. See Agent tools.

  12. 0.24.x
  13. 0.24.0

    18 Sep 2026
    • WebSockets speaks the Agent protocol for plain hosts, and gains a Cap'n Web transport.

    • Add the Queue Lifecycle capability (agents/queue) for durable background work. Each pushed item is a job in the Lifecycle job queue, due immediately, run from the alarm loop one at a time in push order with Lifecycle's retry, deadman, and memory-limit policy. Callbacks are registered in the constructor and typed at declaration and push; push() accepts a stable id (upsert) and per-item retry.

      Agent.queue() and friends now delegate to the capability. Queued callbacks run from the alarm loop in a fresh invocation, so they no longer see the enqueuing request's connection or request through getCurrentAgent() (the agent itself is still available). The cf_agents_queues table and the in-isolate drain are gone; legacy rows migrate into the job queue on the next start. queue() accepts options.id; dequeue, dequeueAll, dequeueAllByCallback, getQueue, and getQueues are now asynchronous; and QueueItem.created_at is renamed createdAt. LifecycleServices.starting() is replaced by status(), which returns "zero" | "starting" | "started".

      Think's workflow-notification outbox and submission drain now run as queue items; the cf_think_workflow_notifications table migrates and is dropped on start.

      Both one-shot migrations (cf_agents_queues in Queue, cf_think_workflow_notifications in Think) are temporary upgrade paths and will be removed in the next minor release, by which point every started object has migrated. Deployments skipping this release should upgrade through it. Workflow-notification delivery retries with backoff capped at ten minutes (previously five) and gives up after twelve hours of continuous failure (previously never), reporting the failure through onError.

    • Move agent state into the opt-in State Lifecycle capability.

      State was one method doing four jobs inside Agent — validate,
      persist, broadcast, notify. It moves wholesale into a State
      capability that owns storage and change ordering, so any Lifecycle
      host gets durable, validated state without inheriting Agent:

      new State({
        initialState: { count: 0 },
        validateStateChange: (next, source) => validate(next, source),
        onChanged: (state, source) => notify(state, source),
      });

      The capability owns the cf_agents_state state row, lazy load with an
      in-memory cache, initial-state seeding, and validated persistence. It
      runs only the onStart hook (versioned schema init under its own
      cf_agents:state_schema_version key) and reaches Lifecycle only for
      storage — no alarm, no request path. It never touches connections.

      Host-owned behavior is injected, not moved: validateStateChange
      stays an overridable Agent method and the post-change onChanged
      hook is passed into State as a plain option. Synchronous and
      asynchronous notification hooks are both supported. Agent keeps its
      initialState field and seeds it from the state getter (standalone
      hosts pass initialState to State directly). Broadcast and the
      notification hook stay on Agent, and the onMessage state branch
      stays too; only its inner write delegates to the capability.

      State is the only owner of cf_agents_state: it creates the table,
      holds the state row, and runs the legacy cf_state_was_changed
      cleanup in its own versioned migration. Agent used to keep its
      global schema version as a row in that table; it now lives under the
      cf_agents:schema_version KV key like every other capability's
      version. A DO created under the old layout has the row read once,
      moved to the key, and deleted on its next construction.

      Agent's public API and wire protocol are unchanged: state,
      setState(), onStateChanged, and the CF_AGENT_STATE frames behave
      identically.

  14. 0.23.x
  15. 0.23.0

    11 Sep 2026
    • Extract facet ("sub-agent") machinery into packages/agents/src/dynamic-agents/, add the this.dynamicAgents capability facade, and reposition facets as an isolation primitive rather than the recommended way to model many chat sessions.

      Agent's facet routing, WebSocket forwarding, virtual connections, and registry (~2,400 of index.ts's ~12,150 lines) move into a dedicated module registered as a Lifecycle capability (capabilityId: "dynamic-agents"); its hot paths stay composition-root wired since the capability-runner hook contract can't express request-rewrite-and-continue or post-claim WebSocket forwarding. No wire- or storage-visible identifier changes.

      The public surface gains this.dynamicAgents.{get,abort,delete,has,list} plus the DynamicAgentClass and DynamicAgentStub type names. SubAgentClass and SubAgentStub remain as compatibility aliases. subAgent() / abortSubAgent() / deleteSubAgent() / hasSubAgent() / listSubAgents() are unchanged in behavior and now delegate to the same capability — @deprecated in place, not removed. /sub/ URLs, useAgent({ sub }), parentAgent(), and onBeforeSubAgent are untouched.

      docs/agents/sub-agents.md is rewritten: verified workerd facet semantics (separate isolate, own SQLite, no independent alarms, bounded nesting depth, machine-pinned tree), a corrected claim about WebSocket frame forwarding (every frame wakes the root parent — it was never true that frames go directly to the child post-upgrade), and an explicit decision rule for facets vs. independent Durable Objects. Two new examples: examples/next/dynamic-agents (a supervisor running user-submitted Durable Object code as facets via Worker Loader — what facets are for) and examples/next/chats (one top-level DO per chat plus a per-user push-based index — the recommended many-chats pattern), both with a React + Vite UI and workers-pool tests.

    • Lifecycle owns a durable job queue, driven as an alarm event loop.

      The thing in the queue is a job: a serialisable callback address — the
      owning capability plus a function name — with a due time and a payload.
      Capabilities and the host push jobs through the scoped jobs surface;
      Lifecycle drives due jobs in timestamp order when the alarm fires, owns
      dispatch retries and platform-failure deferral, arms a deadman pre-alarm
      before driving so an isolate death mid-drive still wakes the object, and
      derives the physical alarm purely from queue state (queue mutations re-arm
      automatically; an exclusive job suppresses ordinary candidates).

      class Cleanup extends LifecycleCapability {
        async scheduleSweep(time: number) {
          await this.lifecycle.jobs.push({ id: "sweep", fn: "sweep", time });
        }
        onJob({ job }: LifecycleJobContext) {
          // drive result: nothing = complete, { rescheduleAt } = suspend,
          // "yield" = leave due and wake again immediately
        }
      }

      The pull-based alarm-contribution model is removed: capability
      getNextAlarm()/onAlarm(), host getNextAlarm(),
      LifecycleServices.alarms (rearm/disabled), and AlarmContribution
      are gone. Host onAlarm() remains and runs once per alarm invocation
      after due jobs are driven. Terminal application failures reach the
      owner's onJobError(), whose drive result decides advancement.

      The alarm memory-limit circuit breaker (#1825) moves from Agent.alarm()
      into the Lifecycle event loop, targeting the exact executing job; Agent
      contributes domain policy through the new onAlarmMemoryLimit() host
      hook, and Scheduler's __DO_NOT_USE_WILL_BREAK__handleAlarmMemoryLimit
      escape hatch is gone. After recording a strike the breaker now finishes by
      resetting the isolate with ctx.abort(reason, { retryAlarm: false })
      (retry of the handled alarm suppressed; the backoff alarm owns the next
      wake), and Agent.destroy() uses the same no-retry abort so a completed
      teardown's alarm cannot be retried into a fresh constructor that recreates
      the deleted schema.

      Scheduler keeps its entire public API and loses its storage and due-row
      loop: a schedule is one job whose fn is the callback name, and interval
      schedules are single-flight jobs. Existing cf_agents_schedules rows are
      migrated into the cf_agents_jobs queue on startup and the legacy table
      is dropped. Agent's public scheduling and keepAlive() APIs are
      unchanged; its keep-alive, fiber-recovery/facet housekeeping, and
      deferred-destroy wakes are now host jobs, and Think's
      workflow-notification wake replaces the removed _getExtensionAlarm().

    • Add RoutedAgents (agents/routing), a Lifecycle capability that codifies the "user hub with one Durable Object per chat" topology: an owning Agent keeps a durable catalog of independent top-level Agents and routes to them by public ID.

      class UserAgent extends Agent<Env> {
        readonly chats = new RoutedAgents<ChatAgent, { title: string }>({
          namespace: this.env.ChatAgent,
          route: "chats",
        });
      
        constructor(ctx: DurableObjectState, env: Env) {
          super(ctx, env);
          this.lifecycle.use(this.chats);
        }
      }

      create(), list(), and setMetadata() never wake a target; get() returns an initialized typed stub; delete() hides the entry, condemns the target through Agent's deferred teardown, then drops the row, so a failed call is retryable and a clean teardown never surfaces as an abort error. Requests and WebSocket upgrades under /agents/user-agent/{user}/chats/{id} are forwarded to the target with the suffix preserved, and the target owns the upgraded socket, so chat frames never wake the user hub. Physical Durable Object names are opaque UUIDs held only in the catalog. create() returns the same JSON round-trip of metadata that list() does, and list() breaks equal-timestamp ties by write order rather than by the random entry ID — derived from a MAX(seq) read of the route's own entries each write, a deliberate trade for a route sized like one owner's catalog: DO SQLite bills ~1000 writes for the cost of 1000 reads, so this is cheaper than a maintained counter row (or an index on seq, which would cost a write on every call too) until a route holds several thousand entries.

      Destroying the hub retries condemning every remaining entry (active or still deleting) before its own storage is wiped — this is best-effort, not a durability guarantee: the platform wipes the hub's storage right after disposal regardless of outcome, so a target still unreachable after retries is orphaned, with no catalog row left to retry from later. That tradeoff is documented on the class and in the docs.

      Two documented sharp edges: pick a route that can't collide with the hub's own path segments (a coincidental match with no active entry behind it 404s instead of reaching the hub), and a routed suffix can't address a target's own dynamic agents — Agent.fetch() resolves a /sub/{class}/{name} marker against the hub's exported classes before this capability ever sees the request, so it is served as a facet of the hub instead of being forwarded. Both are called out on the class and in the docs; the second is pinned by a regression test.

      examples/next/chats is rebuilt on RoutedAgents: the hub creates, lists, searches, and deletes chats through the capability, the browser reaches each chat through the hub's route, a failed init() handshake rolls back the catalog entry instead of leaving an ownerless chat, malformed message bodies get a 400 instead of an uncaught exception, and pushed activity is fenced by each message's own strictly-increasing ordinal (not a wall-clock timestamp, which can tie within a millisecond and silently discard a genuinely newer push) inside blockConcurrencyWhile, so neither a delayed push nor two concurrent ones can overwrite one that already landed.

      Lifecycle.use() accepts { fallback: true } to dispatch a capability after every non-fallback one regardless of installation order. Agent installs its WebSockets capability as a fallback, so middleware a subclass installs from its constructor runs before the upgrade catch-all.

  16. 0.22.x
  17. 0.22.0

    27 Aug 2026
    • removed

      Remove the published agents command-line binary. Its advertised init, dev, deploy, and mcp commands were placeholders that printed "not implemented yet" and exited successfully. Use the documented C3 starter, Vite and Wrangler commands, and MCP APIs instead.

    • Make durable chat recovery unconditional for AIChatAgent and Think.

      Every chat turn now runs in a recovery fiber, including WebSocket, programmatic, retry, and continuation paths. chatRecovery accepts true or a configuration object; false is no longer supported. Previously compiled JavaScript that still supplies false safely receives the default recovery configuration.

      To keep durable bookkeeping while preventing automatic inference after an interruption, return { continue: false } from onChatRecovery(). Use durable cancellation, side-effect, or spend state in that hook and tune chatRecovery budgets when retries must be bounded.

    • Vendor the required PartyServer runtime into agents/lifecycle and add a reusable Durable Object lifecycle for startup, request interception, alarms, and WebSockets. Agent now directly extends Cloudflare's DurableObject and composes the same lifecycle used by standalone objects; standalone hosts use the explicit Lifecycle.install(this) factory (or the expanded new ... plus installHandlers() form). Both Agent subclasses and standalone hosts use the existing routeAgentRequest() API and /agents URL prefix; the lifecycle entry point does not introduce a second public router.

      Lifecycle WebSockets always use Cloudflare's Hibernation API; the static options.hibernate switch and in-memory connection mode are removed. Named Durable Objects use native ctx.id.name, while a read-only __ps_name fallback migrates objects created by older releases without writing new compatibility state.

  18. 0.21.x
  19. 0.21.0

    18 Aug 2026
    • Expose WebSocketChatTransport and its connection types from the framework-neutral agents/chat/transport entry point. React peers are now optional for framework-neutral clients and servers.

      Existing users of agents/chat/react or @cloudflare/ai-chat/react must continue to declare compatible react and @ai-sdk/react dependencies explicitly.

    • Accept AI SDK flexible schemas in agentTool, including Valibot adapters, while preserving schema-driven input inference and structured output validation. Zod is no longer a peer requirement of @cloudflare/ai-chat.

      Existing custom schemas that no longer type-check as AI SDK FlexibleSchema must use the schema library's AI SDK adapter or wrap raw JSON Schema with jsonSchema(). Validation-only Standard Schema implementations are insufficient because tool inputs must expose JSON Schema to the model.

    • Add connection-scoped Kitesurf support to Browser Tools through the browser: "kitesurf" session option. Unsupported durable session, Live View, recording, pause/resume, and Kitesurf-backed Quick Action surfaces remain unavailable.

      Existing Browser Tools users should note:

  20. 0.20.x
  21. 0.20.1

    28 Jul 2026
    • Update the MCP dependencies to stable @modelcontextprotocol/client@2.0.0 and @modelcontextprotocol/server@2.0.0, and update the retained SDK v1 compatibility dependency to @modelcontextprotocol/sdk@1.30.0. Delegate SDK-backed SSE keepalives to the upstream transports so each stream has one timer, while preserving the Agents-owned keepalive on the legacy McpAgent WebSocket bridge.

    • Fix AI SDK v7 telemetry, which produced spans with no token counts, no finish reason, no tool results and zero durations.

      Spans that must not outlive their invocation now close at the end of it rather than at the first await. Closing at the handoff ended every WebSocket-turn span before its result existed, so every finish-time attribute was dropped. A span still open when its invocation ends is closed and marked cloudflare.agents.span.truncated instead of passing as complete, approval spans decided asynchronously included. A chat turn owns its own boundary rather than its caller's, so a turn that is not awaited — an ack-and-return submit, or an auto-continuation fired from a timer — is no longer cut short by the handler that started it. generateText is bounded on the same terms as streamText, and a turn that fails or is cancelled keeps the usage it already reported.

      chat and execute_tool spans sit under their invoke_agent operation span on v7, where they were previously emitted as unrelated roots, and tool_approval segments sit under execute_tool.

      v7 has no telemetry metadata bag, so identity and turn context arrive through runtimeContext and telemetry.includeRuntimeContext. Reserved keys project onto the attributes v6 already emits, so a query written against v6 traces still matches v7 ones; other included keys pass through as cloudflare.agents.runtime_context.{key}, and context the caller did not mark stays off the span.

  22. 0.20.0

    27 Jul 2026
    • Add MCP SDK v2 client and server support. MCPClientConnection now uses the exact-pinned @modelcontextprotocol/client@2.0.0-beta.5. It probes for stateless MCP with server/discover, then falls back to the legacy initialize handshake on the same connection when needed. The SDK auto-fulfills stateless elicitation input_required results through the existing form and URL elicitation handlers while callTool, getPrompt, and readResource remain pending. OAuth reauthorization discards redirect-scoped discovery after token issuance and preserves discovery-triggered authentication, allowing a changed authorization server to be rediscovered and registered without reusing the prior issuer's credentials. Legacy pushed elicitation, Streamable HTTP, SSE, RPC, OAuth, and hibernation recovery remain supported. Codemode's MCP connector now uses an SDK-neutral structural boundary compatible with both MCP client generations.

      Add MCP SDK v2 support to createMcpHandler. Pass a factory returning McpServer or Server from the exact-pinned @modelcontextprotocol/server@2.0.0-beta.5 peer dependency to serve stateless MCP with legacy compatibility by default. The new agents/mcp/server entry exports the stateless Agents handler without retaining McpAgent, WorkerTransport, MCP client transports, PartyServer, or SDK v1 modules. The returned handler remains callable for Worker dispatch and exposes the lower-level SDK fetch(request, options?) method plus typed notify methods; upstream close and event-bus internals are not part of the Agents surface. The retained v1 server APIs use the exact-pinned @modelcontextprotocol/sdk@1.29.0 peer dependency.

      The legacy compatibility fallback now uses SDK v2's web-standard transport, including fail-fast handling for unsupported server-to-client requests, active-request teardown, and the same 25-second Cloudflare SSE keepalive previously supplied by WorkerTransport. It returns 405 for session-only GET and DELETE requests without constructing an application server. createLegacyMcpHandler remains an explicit public API for SDK v1 servers and complete WorkerTransport options.

      The MCP client storage codec now preserves stateless discovery data with resumed HTTP sessions and preserves the binding name and props required to restore RPC servers. Stored HTTP session IDs from older Agents versions have no associated protocol version. The upgraded client discards those IDs and reconnects instead of sending an unsafe resumed request, so in-flight work tied to an old remote session does not resume.

      The v2 callable handler maps verified provider-issued metadata from compatible @cloudflare/workers-oauth-provider releases to standard MCP AuthInfo while preserving getMcpAuthContext().props.

      The Workers handler rejects malformed, opaque, and non-HTTP browser Origins. Its default allowlist includes localhost-class Origins, the endpoint's workers.dev hostname, and a concrete corsOptions.origin hostname. It applies matching Host checks to localhost and workers.dev endpoints. Custom-domain deployments with wildcard CORS can set allowedHostnames and allowedOriginHostnames explicitly, or set allowedOriginHostnames: "*" when trusted upstream middleware already enforces the required Origin policy. Requests without Origin remain valid for non-browser MCP clients. Default CORS preflights allow the stateless Mcp-Method and Mcp-Name request headers.

      @cloudflare/codemode is now an optional peer. Applications that import agents/skills or agents/browser install Codemode explicitly; MCP-only applications no longer install it transitively.

      Deprecations in this release:

      experimental_createMcpHandler was already deprecated and remains scheduled for removal in the next major release. Its warning now directs users to an SDK v2 factory first and names createLegacyMcpHandler only as a temporary bridge for sessionful SDK v1 behavior.

    • Recycle reusable Browser Run sessions after the platform reports HTTP 410 for an expired session.

  23. 0.19.x
  24. 0.19.0

    23 Jul 2026

    Reading the note…

  25. 0.18.x
  26. 0.18.0

    22 Jul 2026

    Reading the note…

  27. 0.17.x
  28. 0.17.4

    13 Jul 2026

    Reading the note…

  29. 0.17.3

    30 Jun 2026

    Reading the note…

  30. 0.17.1

    28 Jun 2026

    Reading the note…

  31. 0.17.0

    26 Jun 2026

    Reading the note…

  32. 0.16.x
  33. 0.16.2

    17 Jun 2026

    Reading the note…

  34. 0.16.1

    16 Jun 2026

    Reading the note…

  35. 0.16.0

    12 Jun 2026

    Reading the note…

  36. 0.15.x
  37. 0.15.0

    8 Jun 2026

    Reading the note…

  38. 0.14.x
  39. 0.14.5

    7 Jun 2026

    Reading the note…

  40. 0.14.4

    7 Jun 2026

    Reading the note…

  41. 0.14.3

    5 Jun 2026

    Reading the note…

  42. 0.14.2

    5 Jun 2026

    Reading the note…

  43. 0.14.1

    3 Jun 2026

    Reading the note…

  44. 0.14.0

    2 Jun 2026

    Reading the note…

  45. 0.13.x
  46. 0.13.3

    26 May 2026

    Reading the note…

  47. 0.13.2

    21 May 2026

    Reading the note…

  48. 0.13.1

    20 May 2026

    Reading the note…

  49. 0.13.0

    19 May 2026

    Reading the note…

  50. 0.12.x
  51. 0.12.4

    13 May 2026

    Reading the note…

  52. 0.12.3

    2 May 2026

    Reading the note…

  53. 0.12.2

    1 May 2026

    Reading the note…

  54. 0.12.1

    1 May 2026

    Reading the note…

  55. 0.12.0

    30 Apr 2026

    Reading the note…

  56. 0.11.x
  57. 0.11.9

    29 Apr 2026

    Reading the note…

  58. 0.11.8

    28 Apr 2026

    Reading the note…

  59. 0.11.7

    28 Apr 2026

    Reading the note…

  60. 0.11.6

    27 Apr 2026

    Reading the note…

  61. 0.11.5

    23 Apr 2026

    Reading the note…

  62. 0.11.4

    18 Apr 2026

    Reading the note…

  63. 0.11.3

    18 Apr 2026

    Reading the note…

  64. 0.11.2

    17 Apr 2026

    Reading the note…

  65. 0.11.1

    16 Apr 2026

    Reading the note…

  66. 0.11.0

    14 Apr 2026

    Reading the note…

  67. 0.10.x
  68. 0.10.2

    13 Apr 2026

    Reading the note…

  69. 0.10.1

    11 Apr 2026

    Reading the note…

  70. 0.10.0

    7 Apr 2026

    Reading the note…