Build with sessions
Send messages, stream progress, retrieve results and reconnect your tools.
A session is one conversation and the work the agent does for it. It keeps the model, loop and tools you selected, along with messages and progress. Save its ID to open it later.
Complete the quickstart first. These TypeScript/JavaScript excerpts use
its brain and session inside the .then() callback. Keep the client alive to send more messages.
Send messages and read the answer
await session.send("Where is order A-1001?");
const { messages } = await session.transcript();
console.log(messages);Each message starts a turn: the loop can call the model and tools before finishing. send()
waits for that turn and returns session state, not the answer. Read the transcript for messages.
An idle session can have a failed turn; inspect turn_failed events as in the quickstart, or use
outcome(sequence) for a submitted turn. Request errors reject the promise; catch them at your
application boundary. Close the client when your application is finished with it.
Stream progress
Start reading before sending. This pattern prints events until the turn ends or fails and closes the subscription even if the request fails:
const subscription = new AbortController();
let cursor = session.state.lastSequence;
const watching = (async () => {
for await (const event of session.stream(cursor, subscription.signal)) {
console.log(event.type, event.data);
if (event.sequence !== undefined) cursor = event.sequence;
if (event.type === "turn_failed") throw new Error(JSON.stringify(event.data));
if (event.type === "turn_ended") return;
}
throw new Error("Stream closed before the turn finished");
})();
try {
await Promise.all([watching, session.send("Explain event streaming in one sentence.")]);
} finally {
subscription.abort();
await watching.catch(() => {});
}The complete streaming example
uses the quickstart's server, packages and model key. Run it with node streaming-session.mjs.
Aborting a subscription stops listening; it does not cancel the agent's work. To stop the turn,
call session.interrupt(). A send() signal requests cancellation of an exclusively owned turn;
do not send concurrently through another owner of that session.
Reconnect from a cursor
Save the last processed event's sequence. Open await brain.sessions.get(sessionId), then call
session.events(cursor) to read saved events and finish, or session.stream(cursor) to catch up
and continue listening. Neither method automatically reconnects after a broken stream; your app
opens the next subscription using its saved cursor.
Model deltas are live-only and have no sequence. Reconnection recovers saved events and the completed model response, not missed token deltas. See history for delivery and deduplication behavior.
Submit work and retrieve its outcome
const sequence = await session.submit("Summarize the conversation.", {
idempotencyKey: "summary-1",
});
console.log({ sessionId: session.id, sequence });submit() returns once Brain has saved the request. Persist the session ID and sequence. If you
lose that response, repeat the same request with the same key; do not reuse the key for new work.
Server-side work can continue after the client closes. Application tools still need their host
process; use HTTP or remote tools for independent execution.
Later, open the saved session with a new client:
const session = await brain.sessions.get(sessionId);
const outcome = await session.outcome(sequence);
if (outcome.status === "failed") {
throw new Error(JSON.stringify(outcome.terminal.data));
}
if (outcome.status === "ended") {
console.log(outcome.answer ?? await session.transcript());
}pending means check again later. ended means the loop finished; individual tool calls or
background jobs may still have failed or be running. answer is present only if the loop emitted
an assistant answer event. The complete submission example
closes the submitter, polls from another client, checks failure and keeps the transcript.
Let an idle client disconnect
The SDK releases its shared tool connection after five seconds without active turns,
unfinished tools or their follow-up work. Session handles, callbacks and history remain
available. A later send(), submit() or Environment operation through the same live
client reconnects before starting work. Reading history does not open the tool connection.
Configure the timeout when creating the client:
const brain = new Brain({
baseUrl: "http://127.0.0.1:8080", token: "quickstart",
connectionIdleTimeoutMs: 5_000,
});Use connectionIdleTimeoutMs: 0 when other callers or future autonomous events must
be able to invoke this client's tools. A disconnected browser cannot be woken by another
caller. Closing the tab or process loses its callbacks; restore them as described below.
The timeout does not end sessions or dispose of Environments. Event subscriptions remain
open until you stop iteration or abort their signal. Explicit brain.close() disposes of
the client permanently and later operations reject.
Reattach application tools
An open session handle alone does not restore your application's functions. Before stopping the
original application, save await brain.credentials() in your credential store together with the
session ID, then close that client. These are host credentials, separate from the Brain API token
and model key; protect them as secrets.
After restarting, restore the same tool definitions and pass the saved credentials:
const brain = new Brain({
baseUrl: "http://127.0.0.1:8080", token: "quickstart", credentials: savedCredentials,
});
try {
const session = await brain.sessions.get(sessionId, { tools: [lookupOrder()] });
await session.send("Look up order A-1002.");
console.log(await session.transcript());
} finally {
await brain.close();
}Here savedCredentials and sessionId come from your storage; lookupOrder is the quickstart's
function. Supply exactly the tools originally placed in that host, with identical schemas and
environment names. Changed contracts require a new session. Reattachment accepts future calls;
it does not replay interrupted calls or restore state captured in the old process.
Stop, finish or delete
| Call | Effect |
|---|---|
session.interrupt() | Stop the current turn and unfinished tools; allow later messages |
session.end() | Finish the conversation and keep its history |
session.delete() | Delete an ended or failed session and release its environments |
brain.close() | Close this client's connections; keep stored sessions |
Cancellation does not undo completed external actions. A server restart with storage intact preserves saved history but fails interrupted work without automatic retry. See history and recovery for the exact guarantees.