Show HN: Durable Agent Sessions API (Preview)

igorzij2 pts0 comments

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,...

session agent turn completed event sessions

Related Articles