OpenComputer Durable Agent Sessions
Skip to content
Preview
Durable Agent Sessions
Resumable, steerable agent sessions
OpenComputer handles session state, runtime lifecycle, streaming, and<br>webhooks, so your app code stays small enough to run on an edge worker.
Start with the quickstart<br>Get API key
Example:<br>PR-review agent repo
Built into every session
Use sessions<br>for durable agents; use<br>sandboxes<br>for one-shot commands.
runtime
Self-healing runtime
Runtime crashes restart automatically.
Idle sessions hibernate and wake on the next message.
Hung runs stop cleanly instead of staying stuck.
sandbox
Brain / hands sandboxing
Brain : agent loop. Hands : files and commands.
Untrusted work stays contained in the hands sandbox.
Your model key stays in the secret store, never in a sandbox.
stream
Live streaming and steering
Stream events directly from the browser with a session token.
Reconnect from any seq without gaps.
Send follow-up messages without exposing your org key.
webhook
Reliable backend delivery
Deliver user-level events to your webhook.
Requests are signed when the destination has a secret.
Deliveries are retried, dead-lettered, inspectable, and redeliverable.
Build a managed coding agent in three steps
Create an<br>agent,<br>start a session,<br>then stream the<br>event log<br>and steer<br>follow-up work.
1. Create an agent
An agent<br>stores name,<br>runtime,<br>model, prompt, and model credential.
TypeScript SDK<br>Copy
import { OpenComputer } from "@opencomputer/sdk";
const oc = new OpenComputer({<br>apiKey: process.env.OPENCOMPUTER_API_KEY,<br>});
const agent = await oc.agents.create({<br>name: "quickstart-coder",<br>runtime: "claude",<br>model: "anthropic/claude-opus-4-8",<br>prompt: "Work in /workspace. Say progress. Ask only when blocked.",<br>key: process.env.ANTHROPIC_API_KEY,<br>limits: { turns: 4, turnSeconds: 600 },<br>});
2. Start a session
A session<br>starts work and returns a browser-safe<br>client_token<br>scoped to that session.
Start work<br>Copy
const session = await oc.sessions.create({<br>agent: agent.id,<br>input: "Create a todo app with local storage.",<br>metadata: {<br>projectId: "proj_123",<br>taskId: "task_456",<br>},<br>idempotencyKey: "task_456",<br>destinations: [{<br>url: "https://your.app/oc-webhook",<br>level: "user",<br>types: ["turn.completed"],<br>}],<br>});
// session.id + session.clientToken
3. Stream and steer
Use the session token in the browser.<br>EventSource<br>resumes after dropped connections.
Browser client<br>Copy
import { connectSession } from "@opencomputer/sdk";
const live = await connectSession({ sessionId, clientToken });
for await (const event of live.events({ level: "progress" })) {<br>render(event);
await live.steer("Add a completed-task filter.", {<br>idempotencyKey: "msg_01",<br>});
Session lifecycle
A session<br>is the durable unit of an agent at work: an append-only<br>event log,<br>pinned agent snapshot, and lifecycle status. Compute attaches, hibernates,<br>and wakes on the next<br>message.
Status<br>Meaning
queuedScheduled; a turn has not started running yet.<br>runningA turn is executing.<br>awaiting_inputA turn ended asking a question. Reply by steering.<br>idleDone for now, quiescent and steerable. The sandbox is hibernated.<br>failedThe session errored out.<br>archivedClosed and read-only.
Fetch the result<br>Copy
const session = await oc.sessions.get("ses_...");<br>const { lastTurn, result } = await session.result();
// lastTurn.yieldReason: "completed", "needs_input",<br>// "deadline_exceeded", "budget_exceeded", "max_turns", "canceled"
Event log
Each session has ordered<br>events.<br>Use seq to resume and type to handle structured events.
Turn event sequence<br>Copy
turn.started<br>tool.call npm test<br>exec.completed exit 1<br>agent.message "3 tests fail" level: user<br>turn.completed needs_input
Event field<br>Use it for
typeStable discriminator: agent.message, turn.completed, tool.call, exec.completed, errors.<br>levelVisibility filter: user, progress, or internal.<br>seqMonotonic cursor for ordering and resume.<br>bodyTyped payload for that event.<br>actorWho produced the event: human, agent, or system.
Webhooks deliver committed events
Register a<br>destination<br>and user-level events are delivered at least once and retried.<br>Deliveries are signed when the destination has a secret. The envelope includes the session<br>metadata<br>you set at create time.
Delivery envelope<br>Copy
"type": "turn.completed",<br>"sessionId": "ses_...",<br>"eventId": "evt_...",<br>"metadata": {<br>"projectId": "proj_123",<br>"taskId": "task_456"<br>},<br>"event": {<br>"id": "evt_...",<br>"seq": 12,<br>"type": "turn.completed",<br>"level": "user",<br>"body": { "yield_reason": "completed" }
Signed destination<br>Copy
const session = await oc.sessions.get("ses_...");
await session.destinations.create({<br>url: "https://your.app/oc-webhook",<br>secret: "whsec_...",<br>level: "user",<br>types: ["turn.completed"],<br>});
Dedupe on webhook-id. Verify the raw body with a<br>Standard Webhooks<br>library when a destination secret is set. A<br>delivery<br>succeeds on any HTTP 2xx.
The PR-review agent<br>stores GitHub PR IDs in metadata. Completion webhooks carry them<br>back,...