Back to Devoured - October 27, 2026
DEVOURED
Cloudflare Computer now helps agents recover from interruptions and wait for approval

Cloudflare Computer now helps agents recover from interruptions and wait for approval

AI Cloudflare
Cloudflare Computer v0.7.0 adds durable state recovery and human-in-the-loop interruption support for autonomous agents.
What: The update introduces `onInterrupt: "replay"` to allow agent code to resume seamlessly after crashes or deployments, and a `ctx.interrupt()` function that pauses execution until an external approval is provided.
Why it matters: Reliable execution is the primary hurdle for production-grade agents; this feature bridges the gap between ephemeral script execution and long-running, interruptible business processes.
Takeaway: Use `ctx.interrupt()` in your Cloudflare Computer agents if you need to gate tool calls or agent actions with human approval.
Decoder
  • Durable Object: A Cloudflare Workers primitive that provides stateful storage and compute, allowing code and memory to persist across HTTP requests.
  • Idempotency Key: A unique identifier used to ensure that a request can be repeated safely without side effects (e.g., posting a comment twice).
Original article

Cloudflare Computer now helps agents recover from interruptions and wait for approval

@cloudflare/computer ↗︎ gives your agent a workspace to run code in. From v0.7.0, that code can resume after a deploy or crash, and pause on an external action, for example to approve a tool call.

Resume interrupted runs

Set onInterrupt: "replay" on WorkerJavaScriptBackend, or on a single run.

import { DurableObject } from "cloudflare:workers";
import { Workspace } from "@cloudflare/computer";
import { WorkerJavaScriptBackend } from "@cloudflare/computer/backends/worker-javascript";

export class MyAgent extends DurableObject {
	workspace = new Workspace({
		storage: this.ctx.storage,
		backends: [
			new WorkerJavaScriptBackend({
				loader: this.env.LOADER,
				onInterrupt: "replay",
			}),
		],
	});
}

When recovery is triggered, the JavaScript runs again from the beginning, reusing recorded results for completed calls without printing previously recorded output again. If a call's result was not recorded before the interruption, recovery may repeat the call — even if its action already succeeded. For retry handling, including unsafeToRepeat() for operations that cannot safely repeat, refer to Calls that must not run twice.

Recovery starts on the next call to workspace.runtime. To recover without waiting for traffic, call workspace.runtime.recover() from a Durable Object alarm.

Wait for approvals

Expose your application functions through custom modules. A function can call ctx.interrupt() to pause the run until your application supplies an approval decision.

Require approval before posting a comment

For example, to provide a GitHub module that allows an agent to post a comment on an issue with approval, an implementation of postComment could look like this:

new WorkerJavaScriptBackend({
	loader: this.env.LOADER,
	onInterrupt: "replay",
	modules: {
		// The agent's code imports this with `import { postComment } from "ws:github"`.
		"ws:github": {
			postComment: async ([issue, body], ctx) => {
				const { approved } = await ctx.interrupt({
					issue,
					body,
				});
				if (!approved) throw new Error("The comment was rejected.");
				return github.comment(issue, body, { idempotencyKey: ctx.callId });
			},
		},
	},
});

Call it from agent code

When the agent's code calls postComment(), the run pauses at ctx.interrupt() until your app responds. The agent's code calls it like any other function:

import { postComment } from "ws:github";

export default async function ({ issue }) {
	return postComment(issue, "Hello world");
}

Respond to the approval request

The time spent waiting does not count toward its timeout. The wait also survives deploys. Fetch the pending calls with workspace.runtime.pending() and resolve them with respond():

for (const call of await workspace.runtime.pending()) {
	await workspace.runtime.respond(call.id, call.callId, { approved: true });
}

The run continues once all pending calls are resolved.

For setup, current limitations, and how replay works, refer to Resume runs after a restart.

Explore all 40 articles in today's digest

Fresh dev news, AI-digested daily. Never miss a trend at devoured.fyi