Patch Changes
-
#1330
b4d3fcfThanks @threepointone! - FixsubAgent()cross-DO I/O errors on first use and drop the"experimental"compatibility flag requirement.subAgent()cross-DO I/O fixThree issues in the facet initialization path caused
"Cannot perform I/O on behalf of a different Durable Object"errors when spawning sub-agents in production:subAgent()constructed aRequestin the parent DO and passed it to the child viastub.fetch(). TheRequestcarried native I/O tied to the parent isolate, which the child rejected.- The facet flag was set after the first
onStart()ran, sobroadcastMcpServers()fired with_isFacet === falseon the initial boot. _broadcastProtocol(), the inheritedbroadcast(), and_workflow_broadcast()iterated the connection registry without an_isFacetguard, letting broadcasts reach into the parent DO's WebSocket registry from a child isolate.
Replaces the fetch-based handshake with a new
_cf_initAsFacet(name)RPC that runs entirely in the child isolate, sets_isFacetbefore init, and seeds partyserver's__ps_namekey directly. Adds_isFacetguards to_broadcastProtocol()and overridesbroadcast()to no-op on facets so downstream callers (chat-streaming paths, workflow broadcasts, userthis.broadcast(...)) are covered. Removes the previous internal_cf_markAsFacet()method —_cf_initAsFacet(name)is the correct entry point (it sets the flag before running the firstonStart(), which_cf_markAsFacetdid not)."experimental"compatibility flag no longer requiredctx.facets,ctx.exports, andenv.LOADER(Worker Loader) have graduated out of the"experimental"compatibility flag in workerd.agentsand@cloudflare/thinkno longer require it:subAgent()/abortSubAgent()/deleteSubAgent()— the@experimentalJSDoc tag and runtime error messages no longer reference the flag. The runtime guards onctx.facets/ctx.exportsstay in place and now nudge users toward updatingcompatibility_dateinstead.Think— the@experimentalJSDoc tag no longer references the flag.
No code change is required; remove
"experimental"from yourcompatibility_flagsinwrangler.jsoncif it was only there for these features. -
#1332
7cb8acfThanks @threepointone! - ExposecreatedAton fiber and chat recovery contexts so apps can suppress continuations for stale, interrupted turns.FiberRecoveryContext(fromagents) gainscreatedAt: number— epoch milliseconds whenrunFiberstarted, read from thecf_agents_runsrow that was already tracked internally.ChatRecoveryContext(from@cloudflare/ai-chatand@cloudflare/think) gains the samecreatedAtfield, threaded through from the underlying fiber.
With this, the stale-recovery guard pattern described in #1324 is a short override:
override async onChatRecovery(ctx: ChatRecoveryContext): Promise<ChatRecoveryOptions> { if (Date.now() - ctx.createdAt > 2 * 60 * 1000) return { continue: false }; return {}; }
No behavior change for existing callers. See
docs/chat-agents.md(new "Guarding against stale recoveries" section) for the full recipe, including a loop-protection pattern usingonChatResponse.