Aex Brain
Reference

Session history and recovery

Event ordering, delivery, persistence and restart behavior.

Use Sessions for application examples. This page defines what saved history, event delivery and interruption mean for your app.

Saved history

session.transcript() returns the current model messages and through_sequence. session.events(after) reads committed events in sequence order; session.stream(after) reads those events and then follows new ones. Reads do not require an active agent turn.

The loop chooses which tool observations become model messages. A model call alone does not change the saved transcript. Transcript/state changes are saved independently before returning to the loop, so a failed turn may contain completed writes and external actions.

Every committed lifecycle, model/tool call, transcript and loop-state change has one session sequence. (sessionId, sequence) identifies a record. transcript_delta carries { keep, append }; kv_set carries { key, value }; kv_delete carries { key }. A consumer can reconstruct those projections by processing the events in order and persisting its cursor.

Reading events

This continuation assumes the quickstart's session. handle and saveCursor are your own consumer and durable cursor store:

let cursor = 0;
for await (const event of session.events(cursor)) {
  await handle(event);
  cursor = event.sequence;
  await saveCursor(cursor);
}

Finite HTTP pages contain at most 1,000 events and normally at most 8 MiB of records. An oversized next event is returned alone so the cursor can advance. The SDK follows pages for you.

For live HTTP delivery, send Accept: text/event-stream to GET /v1/sessions/{id}/events?after={cursor} with your API bearer token. SSE first catches up from saved history, then follows new commits. Model token deltas are live-only and have no sequence; reconnect to recover the completed model result, not missed deltas. Historical telemetry needs a configured sink.

Your application owns reconnection, cursor persistence, retries and deduplication when forwarding events elsewhere. Processing an event and saving its cursor separately can cause redelivery after a crash. The event stream is not an external queue or backup.

Event origin

Recorded events expose their payload as event.data and, where present, Brain-assigned provenance as event.origin. Origins can identify an agent loop, tool or environment. Extension-supplied payload fields cannot override that origin. Older events may lack origin; do not infer authorship from an event's name. Origin identifies its source, not the truth of its contents or human approval.

Turns, results and failure

session.submit() returns the committed turn_started sequence. session.outcome(sequence) reads that turn as pending, ended or failed. Terminal outcomes include the original event and, when the loop emitted one, an assistant answer. An idle session does not prove a successful turn; an ended turn does not prove every tool or background job succeeded.

Brain saves a model/tool/environment operation before dispatch and sends it once. It saves the observation before returning it to the loop. Tool events distinguish emitted results, synchronous return and final completion; returning need not finish background work.

OutcomeMeaning
errorA known validation, execution or protocol failure
timeoutThe tool's original deadline expired
cancelledWork was explicitly interrupted
unknownDispatch may have occurred, but no reliable result is available

These tool failures have is_error: true. None promises rollback or automatic retry. Inspect the external resource before deciding whether an uncertain action should be attempted again.

Background tools retain their original deadlines and emission budgets after a turn ends. Later results or actionable environment observations can activate the loop without a user message. The loop saves its decisions; successful return completes its delivered event batch; see the loop API.

Suspension and recovery

Brain can release inactive execution while keeping sessions readable. idleTtlMs changes how long execution is retained; explicit zero retains it indefinitely. Releasing execution does not detach environments or end the session. Provider expiry and cleanup rules still apply to their resources.

With storage intact, a server restart preserves committed history. First access after restart records an interrupted turn as failed; Brain never reruns it. An effect with no recorded terminal result becomes an ambiguous failure. Interrupted creation fails, and interrupted ending is closed without allowing new messages. A failed detach does not prevent ending.

Teardown is separate. If it fails, the environment record remains; an explicit session delete with a new idempotency key can request another attempt. There is no automatic retry.

Idempotency claims survive restart. Completed request responses are retained for 24 hours. If a claimed request has no recorded response, reusing its key returns an ambiguous error and does not execute again. Inspect session history before choosing a new operation key.

Committed records survive process and power failure when the local filesystem and storage honor flushes. Storage loss and lost provider resources are outside this guarantee. Follow the backup and upgrade procedure to protect stored sessions.

Lifecycle and cleanup

interrupt() requests cancellation of the turn and unfinished tools, including background tools while the loop is idle. It keeps the session open. Cancellation is forwarded to executors; cleanup can extend response time beyond the turn deadline. The configuration reference defines model-call, turn and tool limits.

end() refuses new messages, cancels unfinished tools and waits for their cleanup before detaching environments. History remains. delete() requires an ended or failed session and removes history, tears down environments and forgets credentials.

brain.close() closes this client's connections and local handlers. It is idempotent and rejects later client operations, but does not interrupt or end stored sessions. It does not wait for application code that ignores cancellation. A client created by withToken() has its own lifetime.

Environment turn-end cleanup can finish after the answer is available. Cleanup failure does not replace that answer; read its events to inspect the result. Graceful server shutdown drains admitted work and cleanup while callbacks remain available, then closes workers and subscriptions. Forced termination or deadlines can still leave partial progress.

On this page