Skip to content
OpenComputer
Build an application

Session events

The durable event log every session keeps and every consumer reads

Every session appends what happens to one durable log: the turns it accepted, the text the model produced, the tools it called, the memory it saved and the runtime that ran it. The log is what opencomputer sessions tail --json prints, what useAgent reduces to messages, what the dashboard’s session view shows, and what GET /sessions/<id>/events returns.

Shape and ordering

Each event is one JSON object:

FieldMeaning
seqPosition in the log, starting at 1 and increasing with every event
idA unique event ID
timestampWhen the event was recorded
sessionIdThe session
turnIdThe turn the event belongs to; absent on session-level events
typeOne of the types below
dataFields specific to the type

seq is the cursor. A read with after=<seq> returns events with a greater seq, in ascending order, up to 500 at a time; repeat from the last seq you received until a page is empty, and keep polling from there to follow a live session. Because the log is durable and seq only grows, a consumer that stops can resume from its cursor without missing anything, and a page that overlaps one already read is harmless: apply events whose seq is greater than what you have applied. The React hook and the CLI work this way.

Events at or below the cursor never change. New types can appear; treat an unknown type as informational and keep reading.

Event types

Session lifecycle

TypeWhendata
session.createdThe session exists. Always the first event.agentId, deploymentId
session.status_changedThe session moved between new, connecting, idle, running, stopping, waiting_runtime, suspending, suspended, resuming, failed and endedfrom, to
session.endedThe session accepts no more turns; queued and running turns were marked cancelled. Memory revocation and remote cleanup may still be pending.none
session.failedThe session cannot continuecode, message: a public failure

When the session was created with an external reference, every session.* event’s data also carries it as externalReference.

stopping follows an interrupt or an interrupt-mode turn: the session stays there until the stopped turn’s commands are confirmed stopped or its computer is terminated, then idle follows and the next turn can start. See the API’s compatibility note for sessions that cancel immediately instead.

session.ended is not a command-settlement or memory-revocation receipt. The end response confirms memory revocation; remote cleanup continues in the background.

Turns

TypeWhendata
message.receivedA turn was accepted; its input is recorded before anything runsinput: the user text; mode: queue, steer or interrupt; payload: the structured value the turn was sent with, when there was one
turn.queuedThe turn waits for earlier turnsmode
turn.steeredThe input was delivered into the running turnactiveTurnId
turn.interruptedThis turn requested interruption of the running turnsinterruptedTurnIds
turn.startedThe runtime began the turnnone
turn.completedThe turn finished and the session is idle againnone, or outcome: "question" and questionId when the turn ended by asking
turn.failedThe turn stopped with an errorcode, message, and model or tool when named: a public failure
turn.cancelledThe turn was cancelled by an interrupt or session end, held behind a question, or stopped from Linearreason: interrupted, session_ended, held or stopped; optional replacementTurnId, settledAfterMs, operationsSettled, computerTerminated; questionId with held; discarded: true on a queued turn a stop discarded

For an interrupt that waits for commands, settledAfterMs records the wait, operationsSettled counts the settled commands, and computerTerminated says whether stopping required terminating the computer. Cancellation with reason: "session_ended" has no settlement fields: it records the session’s decision to end, before remote cleanup finishes. Immediate-cancellation sessions also omit these fields; see End and interrupt.

A turn that was queued behind a turn that asked a question is cancelled with reason: "held" and the questionId: its input did not run on its own and is delivered with the answer as steering.

Public failures

A failure’s data is a stable code, a fixed message for that code, and at most one parameter. The runtime’s own error text is never sent; a failure no rule recognizes is agent_failed.

A model call that fails in flight may be retried inside the turn before the turn fails. The runtime retries provider errors, rate limits, incomplete response streams and transport failures that interrupt a started response on its own schedule, per model call; the host adds one retry for a transport failure or an invalid response the runtime would not retry on its own. The agent’s own calls are covered; the runtime’s auxiliary calls (compacting the conversation, titling it) are not retried. Each retry appears in the log as a runtime.log milestone with phase: "model_retry", the attempt and the failure’s class (for example provider.transport), never the provider’s own text. A rejection is not retried: credentials, quota, content policy and an invalid request are model_rejected at once. A model_stream_failed message names its retry only when one happened.

codeMeaningParameter
interruptedThe turn was stopped before it finished
session_endedThe session ended while the turn ran
runtime_lostThe runtime stopped responding and the turn was abandoned
runtime_failedThe runtime failed before the turn finished
deployment_invalidThe runtime could not load the deployment
model_unavailableThe requested model is not available to this agentmodel: the requested model id
model_rejectedThe model provider rejected the request: credentials, rate limit or quota
context_too_longThe conversation exceeds the model’s context window
tool_failedA tool failedtool: the tool id, when the runtime named it
sandbox_timeoutA sandbox command did not finish in time
sandbox_failedThe sandbox could not run the turn
model_stream_failedThe model call failed before it finished, or its response stream broke; when it was retried, the retry failed toomodel: the model id, when known
agent_failedAny other failure

Questions

TypeWhendata
question.askedThe agent called ask; the asking turn completes with outcome: "question"questionId, text, options: { label, value } choices, empty for free text
question.answeredA turn answering the question was admittedquestionId, answer: { questionId, text, value? }
question.closedThe question closed without an answerquestionId, reason: stopped, dismissed, ended or undeliverable
message.heldAn input sent without answers was held behind the open questionheldId, questionId, input, payload?, receivedAt
message.deliveredA held input reached the agentheldId, answerTurnId (the turn that carried it), as: steering, answer or turn
message.discardedA held input will not runheldId, reason: stopped or ended

turn.completed with outcome: "question" is the turn’s terminal event, so a consumer that knows only completed turns reads an asking turn correctly, and outcome subscriptions deliver it as a completed turn. The open question is also on the session as question, where each closure reason is explained. A held input is recorded once, however often its key is repeated, so a client can rebuild held messages after a reload.

Messages

TypeWhendata
message.deltaThe model produced a fragment of its replytext: the fragment; concatenate deltas of one turn
message.completedThe reply is completetext: the whole reply
reasoning.deltaThe model produced a fragment of reasoning, when the model exposes ittext
reasoning.completedThe reasoning is completetext

Tools

TypeWhendata
tool.startedThe model called a tooltool: its name; callId; title; input: the arguments as a JSON value
tool.progressThe tool reported progressruntime-defined
tool.completedThe tool returnedtool, callId, title, output: what the tool returned as a JSON value; result: true when the output became the session’s result
tool.failedThe tool raised an error, or its turn ended before it completedtool, callId, title, message; settledBy when the turn’s end settled the call: turn.completed, turn.failed or turn.cancelled

The exact fields come from the runtime’s tool record; read them as optional and key a tool call on callId when it is present. The memory tools (memory_save, memory_read, memory_list) appear here like any other tool; the save itself is reported separately.

input and output are JSON values, never JSON text: an object comes as an object, and a consumer reads it without parsing. Tool events recorded before these fields were introduced keep the shape they were recorded with, so the React hook’s turns shows those calls unnamed and without output; messages is unaffected.

A successful call of the agent’s result tool is recorded with result: true; its output is the validated value, the same JSON value GET /sessions/<id> returns as result.data. The session writes this event when it commits the result, before the model sees the call succeed, and there is one per call.

Every tool call ends in the log. The runtime reports a tool.completed or tool.failed per call; when a turn ends with a call still open, whether the turn completed, failed or was cancelled, the session records a tool.failed for that call ahead of the terminal turn event, in the same write, with settledBy naming the terminal event (turn.completed, turn.failed or turn.cancelled) and a message saying the turn ended first. A consumer therefore never sees a settled turn with a running call; one that keys rows on callId needs no rule of its own for the turn’s end. This settles the call in the log; it does not strengthen the command-stop guarantees of the terminal turn event.

Memory

TypeWhendata
memory.savedA memory_save the session observed succeedingresource, documentId, revision, bytes

Delivery is best-effort. A save commits independently of the event: a runtime that loses its connection can commit without ever reporting it, and the same event can be reported once or twice after a reconnect. Treat the event as a hint to re-read the document, and also re-read when attaching, reconnecting and completing work. See Document memory.

Model and usage

TypeWhendata
model.route_resolvedA model call is about to be sentproviderCallId; requested and effective as { provider, model }; runtime; access
model.access_fallbackA call planned on a connected model account fell back to managed accessproviderCallId, requested, from, reason
usage.recordedA model call finishedprovider, model, inputTokens, outputTokens, reasoningTokens, cachedTokens, cacheWriteTokens, costUsd, payer

Outbound requests

TypeWhendata
egress.requestA declared connection sent a requestconnectionId, method, path
egress.responseThe destination answeredconnectionId, method, path, status, durationMs
egress.failedThe request did not completeconnectionId, method, path, message

Runtime

TypeWhendata
runtime.connectedAn agent runtime attached to the sessionnone
runtime.disconnectedThe runtime connection closed; running turns return to the queue to await a runtimenone
runtime.suspendedThe runtime was suspended between turnsnone
runtime.resumedThe runtime was resumednone
runtime.logA line of runtime output or a platform milestonelevel, stream, message for output; phase and message for milestones such as the runtime starting

A runtime disconnect does not prove that a command stopped or that its effects were undone. Follow the subsequent turn events to learn whether work continued or failed; see Durability and recovery.

Agent renders

TypeWhendata
agent.renderedYour agent function was rendered for a model steprenderId, instructions, model, enabledTools, enabledMcpServers, requiredConnections, input, tools, renderedAt

One turn can carry several renders, one per model step. The debug inspector in the playground shows the same data.

Reading the log

From the CLI, with one NDJSON record per event:

opencomputer sessions tail <session-id> --after 0 --json

From an application, poll the events route or attach useAgent, which turns message.received, message.delta and message.completed into messages, turn.* and session.* into isRunning and ended, and memory.saved into memorySaves; every event, these included, also reaches onEvent.