cloudflare/agents agents@0.16.0
cloudflare/agents
Captured source
source ↗agents@0.16.0
Repository: cloudflare/agents
Tag: agents@0.16.0
Published: 2026-06-12T16:46:18Z
Prerelease: no
Release notes:
Minor Changes
- #1656 `4c2d1a7` Thanks @cjol! - Rebuild
agents/browseron the codemode connector runtime (experimental).
The browser tool surface is now a single durable tool, `browser_execute`: the model writes sandboxed code against a cdp connector (cdp.send, cdp.attachToTarget, cdp.spec, cdp.getDebugLog, …) instead of picking from several flat tools. Executions are recorded on a CodemodeRuntime Durable Object facet with abort-and-replay, so a run can pause for approval and resume with its browser session, tabs, and cookies intact.
- `BrowserConnector` — a
CodemodeConnector(namecdp) that owns CDP sockets keyed by execution id. Sockets are released at the end of every execution pass (onPassEnd); browser sessions are torn down on terminal status (disposeExecution) — never on pause. - Session modes —
one-shot(default, fresh session per execution),reuse(named shared session), anddynamic(starts one-shot; the model can promote withcdp.startSession()after e.g. logging in). Shared sessions are tracked in durable storage and survive hibernation;connector.sweep()reclaims expired ones from a scheduled task. - Safe sweeping — per-execution entries are touched on use and only swept after
maxExecIdleMs(default 24h, matching the runtime's paused TTL), so a run awaiting approval keeps its browser. A swept entry leaves a tombstone so a later resume fails with a clear "expired or was swept" error instead of silently continuing in a fresh browser. Concurrent CDP calls share one in-flight socket connect instead of leaking the loser's WebSocket. Session-store locks wrap storage operations only — liveness probes and session create/delete happen outside the lock (with a commit re-check; a racing create's redundant session is deleted), so a hung Browser Rendering call can't serialize other session operations. - Stable attach handles —
cdp.attachToTargetreturns{ sessionId }where the id is a stable handle bound to the target (not a raw CDP session id), so handles recorded before a pause still work after the resume reconnects. The object shape mirrors the realTarget.attachToTargetresponse, which is what models expect. - Model-actionable CDP errors — a "method wasn't found" failure on a
sendwithout a sessionId explains that page-scoped commands needcdp.attachToTargetfirst, and a missingtargetIdexplains how to list/create targets. - `createBrowserTools({ ctx, browser, loader, session? })` (AI SDK and TanStack AI variants) now requires the hosting Durable Object's
ctxand returns{ browser_execute };createBrowserRuntimeadditionally exposes the runtime handle and connector for host-side wiring (approvals,sessionInfo/closeSession/sweep). The previousbrowser_search/flat-tool surface andcreateBrowserProviderare removed. - Worker entries must export the facet class:
export { CodemodeRuntime } from "agents/browser".
agents/chat gains pausedExecutionUpdate, a tool-part update that replaces a paused execution's output in the transcript with its resolved outcome (completed / rejected / paused again) — the transcript-side half of human-in-the-loop approvals for durable executions.
- #1746 `e45b5ec` Thanks @threepointone! - Fix RPC calls hanging forever during connection churn (#1738).
useAgent's RPC layer now survives socket replacement. usePartySocket creates a brand-new socket whenever connection options change (async query refresh, enabled toggle, path change) — previously, a call issued against a stale agent reference was buffered inside the permanently-closed old socket and its promise never settled, and a call transmitted just before replacement lost its response with no rejection either.
agent.call()(andagent.stub/agent.setState) now route through the live socket, so stale references captured by mount-time effects keep working.- RPC requests are only handed to a socket once it's open. Until then they're queued by the hook and flushed on the next open — including on a replacement socket. This is safe: queued requests were never transmitted, so they can't double-execute.
- Calls whose request was already transmitted are rejected with
Connection closedwhen their socket closes or is replaced (the response is connection-bound and can never arrive). Calls in flight on a newer socket are no longer spuriously rejected by a stale close event from an old socket. - Queued calls only follow the connection to the _same_ agent instance. If the hook is re-pointed at a different address (the
agent,name,basePath, or path props change) before a queued call could be transmitted, the call is rejected instead of executing against an instance it wasn't composed for. AgentClientsimilarly keeps buffered (untransmitted) calls pending across transient disconnects — PartySocket re-sends them on reconnect — and only rejects calls the server actually received.- Non-streaming calls now have a default 30s timeout as a backstop so lost responses reject instead of hanging. Configure per client via
defaultCallTimeout(0 disables) onuseAgent/AgentClient, or per call via the existingtimeoutoption (timeout: 0opts out). Streaming calls are exempt. - RPC responses that arrive with no matching pending call (e.g. after a timeout) now log a
console.warninstead of being silently discarded.
Patch Changes
- #1742 `4b201a9` Thanks @threepointone! - Fix duplicated assistant text parts when a stream resume is replayed twice (#1733).
The server intentionally sends CF_AGENT_STREAM_RESUMING for the same request from both onConnect and its CF_AGENT_STREAM_RESUME_REQUEST handler. When both offers reached the useAgentChat...
Excerpt shown — open the source for the full document.
Notability
notability 3.0/10Routine minor version release of agents library.