Skip to main content
@opencomputer/react provides one hook, useAgent. It renders a session’s messages, streams new turns and sends input. The session comes from one of two places:
  • Attach to a session your server created. This is the pattern for any application that keeps its API key on the server and chooses what a session may do there, including every application that binds memory.
  • Create a session from the browser during development, through the authenticated development bridge.

Attach to a server-created session

Three pieces: your server creates the session, your server proxies three routes under its own authentication, and the browser attaches with the session id.

1. Create the session on the server

Create the session where the API key lives. With memory, that is also where the bindings are chosen; the browser can neither see the key nor change what the session may read or write. startSessionOnDocument from @opencomputer/sdk creates the document if it does not exist yet, then the session bound to it, both converging under one idempotency key (details):
Without memory, POST /api/managed-agents/sessions with x-api-key and { "agentId": "<agent-id>@development" } returns { session: { id } }. Both are management API calls.

2. Proxy three routes

The hook needs exactly these management API routes, relative to its basePath: Expose them under your own authentication, check that the signed-in user may use that session, and forward to OpenComputer with the API key. A Next.js route handler that serves all three:
The turn body carries an idempotencyKey the hook generates per send, so a retried request does not start a second turn. Forward request bodies and responses unchanged; the hook reads { events }, { turnId } and the error envelope { error: { message } }.

3. Attach in the browser

On mount the hook reads the whole event log from after (default 0) and reduces it to messages, so a reopened page shows the conversation as it stands, including turns that ran while the tab was closed. It then keeps polling from its cursor. A failed poll sets error, backs off, and resumes from the same cursor; nothing is replayed twice, and error clears when the log answers again. Changing sessionId replays the new session; a send still in flight for the previous session settles for its caller but never changes what the new session shows. after is a position, not a snapshot: the hook applies only events after it, so messages and running state from before that position are not reconstructed. Pass after to skip history you have already rendered from your own store, otherwise start at 0. Turns sent while one is running are queued by the platform. stop interrupts the running turn without spending a model turn.

What send returns

send(text) resolves once the platform has admitted the input as a turn, with a receipt { sessionId, turnId, status } where status is queued or running. The input appears in messages at that point; the log’s own record of it confirms that message rather than adding a second one. isRunning is true from admission until the log settles the turn, and a reply that arrives after the log has already shown the turn completed changes nothing. send rejects with a SendError when no turn was admitted, so a composer can keep the draft: The hook’s error is set to the same message either way. A turn that fails after admission is not a rejection: the receipt was returned, the failure arrives through the log as a turn.failed event and sets error. The hook never suspends, resumes or ends an attached session. Its lifecycle belongs to the server that created it.

Refresh notes on save

Every memory.saved event the session records (document memory) is appended to memorySaves and passed to onMemorySaved with its resource, documentId, revision and bytes. Re-read the document through your own owner route when one arrives. Saves are reported best-effort: a document can change without an event, so also refresh when the user opens the panel. Every event is available through onEvent, for example tool activity for an activity view; the types are listed on Session events.

Create a session from the browser

For a local application against Development, pass agent-id@alias and the first send creates the session through the development bridge:
Each send resumes the session, streams one turn and suspends it again; the promise settles when the turn ends, with the same receipt and rejections as in attach mode. Sessions created this way have no memory bindings. Run the watched agent deployment and the web application separately:
The first command deploys agent changes and provides the authenticated development bridge at the hook’s default basePath. The second starts only the web application. Credentials are not bundled into browser code.

Hook result

Options

For the durable conversation model, see Sessions and turns.