Browser automation via CDP; codemode with durable execution log
The latest release of the Agents SDK makes it easier to build agents that can safely interact with real systems and keep working through interruptions.
Agents can now browse websites through Browser Run, write code against external tools through Codemode, use client-provided tools when delegating to Think sub-agents, and recover more reliably from deploys, Durable Object evictions, and connection churn.
Safer browser automation
Agents can now use Browser Run through a single durable browser_execute tool. Instead of choosing from a fixed list of actions, the model writes code against the Chrome DevTools Protocol (CDP) and can inspect pages, capture screenshots, read rendered content, debug frontend behavior, and interact with live browser sessions.
-
JavaScript
<div><div><span>const</span><span> </span><span>browserTools</span><span> </span><span>=</span><span> </span><span>createBrowserTools</span><span>(</span><span>{</span></div></div><div><div><span><span> </span></span><span>ctx</span><span>:</span><span> </span><span>this</span><span>.</span><span>ctx</span><span>,</span></div></div><div><div><span><span> </span></span><span>browser</span><span>:</span><span> </span><span>this</span><span>.</span><span>env</span><span>.</span><span>BROWSER</span><span>,</span></div></div><div><div><span><span> </span></span><span>loader</span><span>:</span><span> </span><span>this</span><span>.</span><span>env</span><span>.</span><span>LOADER</span><span>,</span></div></div><div><div><span><span> </span></span><span>session</span><span>:</span><span> </span><span>{</span><span> mode</span><span>:</span><span> </span><span>"dynamic"</span><span> </span><span>},</span></div></div><div><div><span>}</span><span>)</span><span>;</span></div></div> -
TypeScript
<div><div><span>const</span><span> </span><span>browserTools</span><span> </span><span>=</span><span> </span><span>createBrowserTools</span><span>(</span><span>{</span></div></div><div><div><span><span> </span></span><span>ctx</span><span>:</span><span> </span><span>this</span><span>.</span><span>ctx</span><span>,</span></div></div><div><div><span><span> </span></span><span>browser</span><span>:</span><span> </span><span>this</span><span>.</span><span>env</span><span>.</span><span>BROWSER</span><span>,</span></div></div><div><div><span><span> </span></span><span>loader</span><span>:</span><span> </span><span>this</span><span>.</span><span>env</span><span>.</span><span>LOADER</span><span>,</span></div></div><div><div><span><span> </span></span><span>session</span><span>:</span><span> </span><span>{</span><span> mode</span><span>:</span><span> </span><span>"dynamic"</span><span> </span><span>},</span></div></div><div><div><span>}</span><span>)</span><span>;</span></div></div>
Browser sessions can be one-time, reused, or promoted from one-time to persistent during a run. This is useful when an agent needs a human to log in, complete MFA, or approve a sensitive action. The run can pause, keep the same tabs and cookies, and resume after approval.
The browser tools also add Live View URLs, optional session recording, and quick actions such as browser_markdown, browser_extract, browser_links, and browser_scrape for one-shot browsing tasks.
Resumable code execution with approvals
Codemode now uses createCodemodeRuntime, connectors, and a durable execution log. This lets you give a model one codemode tool instead of a large prompt full of tool definitions. The model can discover the capabilities it needs, write code against typed globals, and reuse saved snippets.
-
JavaScript
<div><div><span>const</span><span> </span><span>runtime</span><span> </span><span>=</span><span> </span><span>createCodemodeRuntime</span><span>(</span><span>{</span></div></div><div><div><span><span> </span></span><span>ctx</span><span>:</span><span> </span><span>this</span><span>.</span><span>ctx</span><span>,</span></div></div><div><div><span><span> </span></span><span>executor</span><span>:</span><span> </span><span>new</span><span> </span><span>DynamicWorkerExecutor</span><span>(</span><span>{</span><span> loader</span><span>:</span><span> </span><span>this</span><span>.</span><span>env</span><span>.</span><span>LOADER</span><span> </span><span>}</span><span>)</span><span>,</span></div></div><div><div><span><span> </span></span><span>connectors</span><span>:</span><span> [</span><span>new</span><span> </span><span>GithubConnector</span><span>(</span><span>this</span><span>.</span><span>ctx</span><span>,</span><span> </span><span>this</span><span>.</span><span>env</span><span>,</span><span> </span><span>connection</span><span>)]</span><span>,</span></div></div><div><div><span>}</span><span>)</span><span>;</span></div></div><div><div> </div></div><div><div><span>const</span><span> </span><span>result</span><span> </span><span>=</span><span> </span><span>streamText</span><span>(</span><span>{</span></div></div><div><div><span> </span><span>model</span><span>,</span></div></div><div><div><span> </span><span>messages</span><span>,</span></div></div><div><div><span><span> </span></span><span>tools</span><span>:</span><span> </span><span>{</span><span> codemode</span><span>:</span><span> </span><span>runtime</span><span>.</span><span>tool</span><span>() </span><span>},</span></div></div><div><div><span>}</span><span>)</span><span>;</span></div></div> -
TypeScript
<div><div><span>const</span><span> </span><span>runtime</span><span> </span><span>=</span><span> </span><span>createCodemodeRuntime</span><span>(</span><span>{</span></div></div><div><div><span><span> </span></span><span>ctx</span><span>:</span><span> </span><span>this</span><span>.</span><span>ctx</span><span>,</span></div></div><div><div><span><span> </span></span><span>executor</span><span>:</span><span> </span><span>new</span><span> </span><span>DynamicWorkerExecutor</span><span>(</span><span>{</span><span> loader</span><span>:</span><span> </span><span>this</span><span>.</span><span>env</span><span>.</span><span>LOADER</span><span> </span><span>}</span><span>)</span><span>,</span></div></div><div><div><span><span> </span></span><span>connectors</span><span>:</span><span> [</span><span>new</span><span> </span><span>GithubConnector</span><span>(</span><span>this</span><span>.</span><span>ctx</span><span>,</span><span> </span><span>this</span><span>.</span><span>env</span><span>,</span><span> </span><span>connection</span><span>)]</span><span>,</span></div></div><div><div><span>}</span><span>)</span><span>;</span></div></div><div><div> </div></div><div><div><span>const</span><span> </span><span>result</span><span> </span><span>=</span><span> </span><span>streamText</span><span>(</span><span>{</span></div></div><div><div><span> </span><span>model</span><span>,</span></div></div><div><div><span> </span><span>messages</span><span>,</span></div></div><div><div><span><span> </span></span><span>tools</span><span>:</span><span> </span><span>{</span><span> codemode</span><span>:</span><span> </span><span>runtime</span><span>.</span><span>tool</span><span>() </span><span>},</span></div></div><div><div><span>}</span><span>)</span><span>;</span></div></div>
When the code reaches an approval-gated action, the runtime pauses execution and returns a pending approval. After approval, completed calls replay from the durable log, the approved action runs, and the same code continues. This makes it practical to build agents that create issues, update external systems, or perform other side effects without custom pause-and-resume logic for every tool.
Better Think delegation
Think sub-agents can now use client-defined tools over the RPC chat() path. A parent agent can pass tool schemas with clientTools and resolve tool calls through onClientToolCall. This lets delegated agents use caller-provided capabilities without requiring a browser WebSocket.
-
JavaScript
<div><div><span>await</span><span> </span><span>child</span><span>.</span><span>chat</span><span>(</span><span>message</span><span>,</span><span> </span><span>callback</span><span>,</span><span> </span><span>{</span></div></div><div><div><span> </span><span>signal</span><span>,</span></div></div><div><div><span><span> </span></span><span>clientTools</span><span>:</span><span> [</span></div></div><div><div><span> </span><span>{</span></div></div><div><div><span><span> </span></span><span>name</span><span>:</span><span> </span><span>"get_user_timezone"</span><span>,</span></div></div><div><div><span><span> </span></span><span>description</span><span>:</span><span> </span><span>"Get the caller's timezone"</span><span>,</span></div></div><div><div><span><span> </span></span><span>parameters</span><span>:</span><span> </span><span>{</span><span> type</span><span>:</span><span> </span><span>"object"</span><span> </span><span>},</span></div></div><div><div><span> </span><span>},</span></div></div><div><div><span><span> </span></span><span>]</span><span>,</span></div></div><div><div><span> </span><span>onClientToolCall</span><span>:</span><span> </span><span>async</span><span> </span><span>({</span><span> </span><span>toolName</span><span>,</span><span> </span><span>input</span><span> </span><span>})</span><span> </span><span>=></span><span> </span><span>{</span></div></div><div><div><span> </span><span>return</span><span> </span><span>runClientTool</span><span>(</span><span>toolName</span><span>,</span><span> </span><span>input</span><span>)</span><span>;</span></div></div><div><div><span> </span><span>},</span></div></div><div><div><span>}</span><span>)</span><span>;</span></div></div> -
TypeScript
<div><div><span>await</span><span> </span><span>child</span><span>.</span><span>chat</span><span>(</span><span>message</span><span>,</span><span> </span><span>callback</span><span>,</span><span> </span><span>{</span></div></div><div><div><span> </span><span>signal</span><span>,</span></div></div><div><div><span><span> </span></span><span>clientTools</span><span>:</span><span> [</span></div></div><div><div><span> </span><span>{</span></div></div><div><div><span><span> </span></span><span>name</span><span>:</span><span> </span><span>"get_user_timezone"</span><span>,</span></div></div><div><div><span><span> </span></span><span>description</span><span>:</span><span> </span><span>"Get the caller's timezone"</span><span>,</span></div></div><div><div><span><span> </span></span><span>parameters</span><span>:</span><span> </span><span>{</span><span> type</span><span>:</span><span> </span><span>"object"</span><span> </span><span>},</span></div></div><div><div><span> </span><span>},</span></div></div><div><div><span><span> </span></span><span>]</span><span>,</span></div></div><div><div><span> </span><span>onClientToolCall</span><span>:</span><span> </span><span>async</span><span> </span><span>({</span><span> </span><span>toolName</span><span>,</span><span> </span><span>input</span><span> </span><span>})</span><span> </span><span>=></span><span> </span><span>{</span></div></div><div><div><span> </span><span>return</span><span> </span><span>runClientTool</span><span>(</span><span>toolName</span><span>,</span><span> </span><span>input</span><span>)</span><span>;</span></div></div><div><div><span> </span><span>},</span></div></div><div><div><span>}</span><span>)</span><span>;</span></div></div>
Think Workflows also improve step.prompt(). A prompt step now runs a full agentic turn before returning structured output, so the agent can call tools before producing the typed result. This makes Workflow steps more useful for durable triage, research, and approval flows.
The unified Think execute tool can also include cdp.* browser capabilities alongside state.* and tools.* when Browser Run is bound.
Voice output device selection
Voice clients can route assistant audio to a specific output device. Use outputDeviceId with useVoiceAgent, or call client.setOutputDevice() from the framework-agnostic client.
-
JavaScript
<div><div><span>const</span><span> </span><span>voice</span><span> </span><span>=</span><span> </span><span>useVoiceAgent</span><span>(</span><span>{</span></div></div><div><div><span><span> </span></span><span>agent</span><span>:</span><span> </span><span>"MyVoiceAgent"</span><span>,</span></div></div><div><div><span><span> </span></span><span>outputDeviceId</span><span>:</span><span> </span><span>selectedSpeakerId</span><span>,</span></div></div><div><div><span>}</span><span>)</span><span>;</span></div></div> -
TypeScript
<div><div><span>const</span><span> </span><span>voice</span><span> </span><span>=</span><span> </span><span>useVoiceAgent</span><span>(</span><span>{</span></div></div><div><div><span><span> </span></span><span>agent</span><span>:</span><span> </span><span>"MyVoiceAgent"</span><span>,</span></div></div><div><div><span><span> </span></span><span>outputDeviceId</span><span>:</span><span> </span><span>selectedSpeakerId</span><span>,</span></div></div><div><div><span>}</span><span>)</span><span>;</span></div></div>
Browsers without speaker-selection support continue playing through the default output device and report a non-fatal outputDeviceError.
Reliability fixes
This release includes several fixes for production agents:
useAgentandAgentClienthandle WebSocket replacement more reliably during reconnects and configuration changes.- Chat stream replay is more reliable after reconnects, deploys, and provider errors.
- Fiber recovery continues across multi-pass scans and backs off when recovery hooks keep failing.
- Agent teardown continues even when the request that started teardown is canceled.
- Large session histories use byte-budgeted reads to reduce memory pressure during startup.
Upgrade
To update to the latest version:
<span>npm</span><span> i agents@latest @cloudflare/think@latest @cloudflare/codemode@latest @cloudflare/ai-chat@latest @cloudflare/voice@latest</span>
<span>yarn</span><span> add agents@latest @cloudflare/think@latest @cloudflare/codemode@latest @cloudflare/ai-chat@latest @cloudflare/voice@latest</span>
<span>pnpm</span><span> add agents@latest @cloudflare/think@latest @cloudflare/codemode@latest @cloudflare/ai-chat@latest @cloudflare/voice@latest</span>
<span>bun</span><span> add agents@latest @cloudflare/think@latest @cloudflare/codemode@latest @cloudflare/ai-chat@latest @cloudflare/voice@latest</span>
Refer to the Codemode documentation, Browser tools documentation, Think tools documentation, and Voice documentation for more information.
Fetched June 16, 2026




