Aex Brain

Quickstart

Run an agent that looks up an order and tells you whether it has shipped.

Connect an AI model to an order lookup function in your app. You need Docker, Node.js 22 or newer and an OpenAI API key. Your provider bills model calls separately. Prefer hosting? Use the Aex quickstart.

1. Start Brain

docker run --rm -p 127.0.0.1:8080:8080 \
  -e BRAIN_LISTEN=0.0.0.0:8080 -e BRAIN_API_TOKEN=quickstart \
  -v brain-data:/var/lib/brain ghcr.io/aexhq/brain:latest

Leave this terminal running. The volume keeps saved sessions between restarts. The example token is for local use; see deployment before exposing a server. The commands below use Bash; in PowerShell, put multiline shell commands on one line.

2. Install the client

In another terminal:

mkdir brain-example
cd brain-example
npm init -y
npm pkg set type=module
npm install @aexhq/brain@0.38.0 @aexhq/agentloop-pi@9.0.0 zod@4.4.3

Install the compiler and runner:

npm install --save-dev typescript@5.9.2 tsx@4 @types/node@22

Set your model key in this terminal:

export OPENAI_API_KEY="your-key"

In PowerShell, use $env:OPENAI_API_KEY = "your-key". Keep keys out of source control.

3. Add a tool and send a message

Save as order.ts. This is the complete order example; its source also runs unchanged as JavaScript. The input schema supplies the tool's argument types.

import { Brain, tool } from "@aexhq/brain";
import { pi } from "@aexhq/agentloop-pi";
import { z } from "zod";

const apiKey = process.env.OPENAI_API_KEY;
if (!apiKey) throw new Error("OPENAI_API_KEY is required");

const lookupOrder = tool({
  name: "lookup_order",
  description: "Look up an order by id.",
  input: z.object({ id: z.string() }),
  run: ({ id }, ctx) => ctx.finish({ id, status: "shipped" }),
});

const brain = new Brain({ baseUrl: "http://127.0.0.1:8080", token: "quickstart" });
brain.sessions.create({
  model: { provider: "openai", name: "gpt-5-mini", apiKey },
  agentloop: pi(),
  tools: [lookupOrder()],
}).then(async session => {
  const after = session.state.lastSequence;
  await session.send("Look up order A-1001. Has it shipped?");
  for await (const event of session.events(after)) {
    if (event.type === "turn_failed") throw new Error(JSON.stringify(event.data));
  }
  console.log(JSON.stringify(await session.transcript(), null, 2));
  console.log("Session:", session.id);
}).catch(error => {
  console.error(error);
  process.exitCode = 1;
});

4. Run it

npx tsc --noEmit --strict --module NodeNext --target ES2023 order.ts
npx tsx order.ts

The transcript includes a lookup_order result and an answer saying order A-1001 has shipped. The wording depends on the model. Replace the sample return value with your own backend lookup.

Pi runs on the Brain server by default; the lookup runs in this application's process. ctx.finish(value) returns a tool result and completes the call. After five idle seconds, the client releases its tool connection so this script can exit. The session and history remain. Add another send() in the callback to keep chatting. A later send through the same live client reconnects before starting work.

Use connectionIdleTimeoutMs: 0 on new Brain(...) when other callers or future autonomous events must reach these tools. Event subscriptions stay open until you stop them. Explicit brain.close() permanently disposes of the client; session.end() finishes the conversation and session.delete() removes its history. See sessions.

Next steps

On this page