Minor Changes
-
#1024
e9ae070Thanks @threepointone! - Overhaul observability:diagnostics_channel, leaner events, error tracking.Breaking changes to
agents/observabilitytypesBaseEvent: RemovedidanddisplayMessagefields. Events now contain onlytype,payload, andtimestamp. Thepayloadtype is now strict — accessing undeclared fields is a type error. Narrow onevent.typebefore accessing payload properties.Observability.emit(): Removed the optionalctxsecond parameter.AgentObservabilityEvent: Split combined union types so each event has its own discriminant (enables properExtract-based type narrowing). Added new error event types.
If you have a custom
Observabilityimplementation, update youremitsignature toemit(event: ObservabilityEvent): void.diagnostics_channel replaces console.log
The default
genericObservabilityimplementation no longer logs every event to the console. Instead, events are published to named diagnostics channels using the Node.jsdiagnostics_channelAPI. Publishing to a channel with no subscribers is a no-op, eliminating logspam.Seven named channels, one per event domain:
agents:state— state sync eventsagents:rpc— RPC method calls and errorsagents:message— message request/response/clear/cancel/error + tool result/approvalagents:schedule— schedule and queue create/execute/cancel/retry/error eventsagents:lifecycle— connection and destroy eventsagents:workflow— workflow start/event/approve/reject/terminate/pause/resume/restartagents:mcp— MCP client connect/authorize/discover events
New error events
Error events are now emitted at failure sites instead of (or alongside)
console.error:rpc:error— RPC method failures (includes method name and error message)schedule:error— schedule callback failures after all retries exhaustedqueue:error— queue callback failures after all retries exhausted
Reduced boilerplate
All 20+ inline
emitblocks in the Agent class have been replaced with a private_emit()helper that auto-generates timestamps, reducing each call site from ~10 lines to 1.Typed subscribe helper
A new
subscribe()function is exported fromagents/observabilitywith full type narrowing per channel:import { subscribe } from "agents/observability"; const unsub = subscribe("rpc", (event) => { // event is fully typed as rpc | rpc:error console.log(event.payload.method); });
Tail Worker integration
In production, all diagnostics channel messages are automatically forwarded to Tail Workers via
event.diagnosticsChannelEvents— no subscription needed in the agent itself.TracingChannel potential
The
diagnostics_channelAPI also providesTracingChannelfor start/end/error spans withAsyncLocalStorageintegration, opening the door to end-to-end tracing of RPC calls, workflow steps, and schedule executions. -
#1029
c898308Thanks @threepointone! - Add experimentalkeepAlive()andkeepAliveWhile()methods to the Agent class. Keeps the Durable Object alive via alarm heartbeats (every 30 seconds), preventing idle eviction during long-running work.keepAlive()returns a disposer function;keepAliveWhile(fn)runs an async function and automatically cleans up the heartbeat when it completes.AIChatAgentnow automatically callskeepAliveWhile()during_reply()streaming, preventing idle eviction during long LLM generations.
Patch Changes
-
#1020
70ebb05Thanks @threepointone! - udpate dependencies -
#1035
24cf279Thanks @threepointone! - MCP protocol handling improvements:- JSON-RPC error responses:
RPCServerTransport.handle()now returns a proper JSON-RPC-32600 Invalid Requesterror response for malformed messages instead of throwing an unhandled exception. This aligns with the JSON-RPC 2.0 spec requirement that servers respond with error objects. - McpAgent protocol message suppression:
McpAgentnow overridesshouldSendProtocolMessages()to suppressCF_AGENT_IDENTITY,CF_AGENT_STATE, andCF_AGENT_MCP_SERVERSframes on MCP transport connections (detected via thecf-mcp-methodheader). Regular WebSocket connections to a hybrid McpAgent are unaffected. - CORS warning removed: Removed the one-time warning about
AuthorizationinAccess-Control-Allow-Headerswith wildcard origin. The warning was noisy and unhelpful — the combination is valid for non-credentialed requests and does not pose a real security risk.
- JSON-RPC error responses:
-
#996
baf6751Thanks @threepointone! - Fix race condition where MCP tools are intermittently unavailable in onChatMessage after hibernation.agents: AddedMCPClientManager.waitForConnections(options?)which awaits all in-flight connection and discovery operations. Accepts an optional{ timeout }in milliseconds. Background restore promises fromrestoreConnectionsFromStorage()are now tracked so callers can wait for them to settle.@cloudflare/ai-chat: AddedwaitForMcpConnectionsopt-in config onAIChatAgent. Set totrueto wait indefinitely, or{ timeout: 10_000 }to cap the wait. Default isfalse(non-blocking, preserving existing behavior). For lower-level control, callthis.mcp.waitForConnections()directly in youronChatMessage. -
#1035
24cf279Thanks @threepointone! - Fixthis.sqlto throwSqlErrordirectly instead of routing throughonErrorPreviously, SQL errors from
this.sqlwere passed tothis.onError(), which by default logged the error and re-threw it. This caused confusing double error logs and made it impossible to catch SQL errors with a simple try/catch aroundthis.sqlcalls ifonErrorwas overridden to swallow errors.Now,
this.sqlwraps failures inSqlError(which includes the query string for debugging) and throws directly. TheonErrorlifecycle hook is reserved for WebSocket connection errors and unhandled server errors, not SQL errors. -
#1022
c2bfd3cThanks @threepointone! - Remove redundant unawaitedupdatePropscalls in MCP transport handlers that caused sporadic "Failed to pop isolated storage stack frame" errors in test environments. Props are already delivered throughgetAgentByName→onStart, making the extra calls unnecessary. Also removes the RPC experimental warning fromaddMcpServer. -
#1003
d24936cThanks @threepointone! - Fix:throw new Error()in AgentWorkflow now triggersonWorkflowErroron the AgentPreviously, throwing an error inside a workflow's
run()method would halt the workflow but never notify the Agent viaonWorkflowError. Only explicitstep.reportError()calls triggered the callback, but those did not halt the workflow.Now, unhandled errors in
run()are automatically caught and reported to the Agent before re-throwing. A double-notification guard (_errorReportedflag) ensures that ifstep.reportError()was already called before the throw, the auto-report is skipped. -
#1040
766f20bThanks @threepointone! - ChangedaddMcpServerdedup logic to match on both server name AND URL for HTTP transport. Previously, callingaddMcpServerwith the same name but a different URL would silently return the stale connection. Now each unique (name, URL) pair is treated as a separate connection. RPC transport continues to dedup by name only. -
#997
a570ea5Thanks @threepointone! - Security hardening for Agent and MCP subsystems:- SSRF protection: MCP client now validates URLs before connecting, blocking private/internal IP addresses (RFC 1918, loopback, link-local, cloud metadata endpoints, IPv6 unique local and link-local ranges)
- OAuth log redaction: Removed OAuth state parameter value from
consumeStatewarning logs to prevent sensitive data leakage - Error sanitization: MCP server error strings are now sanitized (control characters stripped, truncated to 500 chars) before broadcasting to clients to mitigate XSS risk
sendIdentityOnConnectwarning: When using custom routing (where the instance name is not visible in the URL), a one-time console warning now informs developers that the instance name is being sent to clients. Setstatic options = { sendIdentityOnConnect: false }to opt out, ortrueto silence the warning.
-
#992
4fcf179Thanks @Muhammad-Bin-Ali! - Fix email routing to handle lowercased agent names from email infrastructureEmail servers normalize addresses to lowercase, so
SomeAgent+id@domain.comarrives assomeagent+id@domain.com. The router now registers a lowercase key in addition to the original binding name and kebab-case version, so all three forms resolve correctly.