Run your first agent on Aex

Aex hosts the agent session while your application supplies a model key and tools. This example asks an agent to look up an order and prints its answer.

1. Get your keys

You need Node.js 22 or newer and an OpenAI API key. Sign in to the dashboard and create an Aex API key. Save it when it appears; the secret is shown only once.

export AEX_API_KEY="your-aex-key"
export OPENAI_API_KEY="your-openai-key"

In PowerShell, use $env:AEX_API_KEY = "your-aex-key" and $env:OPENAI_API_KEY = "your-openai-key". Keep keys on your server and out of source control. Your model provider bills calls separately.

2. Install

mkdir aex-example
cd aex-example
npm init -y
npm install @aexhq/sdk@0.88.0 @aexhq/agentloop-pi@9.0.0 zod@4.4.3

3. Add a tool and run the agent

Save this as order.mjs. The same API works in TypeScript.

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

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 aex = new Aex({ apiKey: process.env.AEX_API_KEY });
aex.sessions.create({
  model: { provider: "openai", name: "gpt-4.1-mini", apiKey: process.env.OPENAI_API_KEY },
  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;
});
node order.mjs

The transcript includes the lookup result and an answer that order A-1001 has shipped. Replace the sample lookup with your own data. Add more session.send(...)calls in the callback to continue the conversation.

The loop runs on Aex and the lookup runs in your application. After five idle seconds, the client releases its tool connection so this script can exit. A later send through the same live client reconnects automatically. The session and its history remain available.

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

Build your application

Aex uses Brain's session and extension APIs. Import shared helpers from @aexhq/sdk when following the Brain guides.

Use session.submit() when your request must return before the work finishes. Save its turn sequence and use session.outcome(sequence) from a later request. Declare your backend with aex.environments.application() and place ordinary tools there. Aex admits the endpoint when you call sessions.create(); saved conversations can call it again on later turns. Your app hosts its business functions and checks current user access. Inline hostEnv tools need their process connected.

Prepare code before requests arrive

Aex prepares hosted loop and tool code during session setup. To move that work into application startup, await preparation once and reuse the returned loop:

const loop = await aex.prepare(pi());
const session = await aex.sessions.create({ model, agentloop: loop, tools });

Pi and Codex share a runtime and load their smaller program bundles separately. Preparation can serve several sessions; ending a conversation does not unload it. Imports remain passive, and preparation failures reject before session creation.

Read the Environment preparation reference for startup configuration, worker readiness and custom programs.

Structured output

Use a typed answer when your application needs data it can validate and use directly. Inside the callback, pass a Zod schema with the message:

const answer = await session.send("Return the order status", {
  output: { type: z.object({ id: z.string(), status: z.string() }), maxRetries: 2 },
});
console.log(answer.status);

Aex adds schema instructions to the prompt, parses the completed turn's assistant answer as JSON and validates it locally. The return type follows the schema. Ordinary sends return session state. Pi and Codex emit the assistant output this needs.

maxRetries counts additional correction turns and defaults to two. Zero checks one answer. Invalid JSON or schema issues trigger a request for a complete corrected answer; Markdown fences and surrounding prose fail parsing. Zod defaults, transforms and async refinements apply to the returned value. Exhaustion throws StructuredOutputError with attempts, lastOutput and issues. Provider and transport failures do not trigger corrections.

Keep the calling process alive and coordinate exclusive sends during the operation. Each attempt is a separate durable turn, can call tools and remains visible in history and streams. Local validation does not change a completed server turn. A top-level signal cancels active work and stops further corrections. An idempotencyKey lets unchanged requests and validation feedback reuse their completed turns; the whole operation is not atomic.

For a short-lived caller using submit(), configure output validation in the hosted Agentloop instead. That separate policy uses JSON Schema and cannot run your local Zod refinements. See the SDK guidefor both contracts, error handling, replay and a complete example.

Starting with Brain SDK 0.34 and Aex SDK 0.84, this prompt and correction policy belongs to Aex. Existing Aex typed sends keep their syntax. Import their types and errors from @aexhq/sdk. Aex clients and handles now use composition; use AexSessionHandle for explicit handle types. The migration guidealso shows how to wrap an existing standalone Brain handle.

Use the CLI

npm install -g @aexhq/cli@0.50.5
aex login
aex keys create "My application"
aex usage

Login opens your browser on the same computer. See the command guidefor keys, account management and billing.

Hosting prices and limits

Model hosting is offered at $0.22 per million input + output tokens. Managed compute, attachment storage and downloads have separate prices. You supply your model key and pay that provider separately.

The dashboard shows your exact offered and accepted prices. Existing preview accounts stay in preview until they accept a pricebook. Prepaid services require accepted prices and credits. Set a monthly spending limit; there are no automatic topups.

Spending controls can interrupt work but do not cap your separate model-provider bill. Read the billing guidefor charges, estimates and refunds.

Aex is in early preview. APIs and limits may change. Maintenance can interrupt work; saved history remains available, and uncertain actions are not automatically retried.