@aexhq/sdk 0.78.0 → 0.80.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,119 +1,87 @@
1
1
  # Aex SDK
2
2
 
3
- `aex.billing` reads credits and ledger entries, accepts a pricebook and spend limit, creates
4
- idempotent Stripe topups/refunds, and synchronizes provider status and receipt links. Mutations
5
- require an account credential. Configure `maxCostMicroUsd` on a prepaid workload client for its
6
- per-operation ceiling. Attachment uploads also accept `downloadBudgetBytes` and an optional
7
- operation-specific `maxCostMicroUsd`. See [billing](../../docs/billing.md) for units and recovery.
3
+ Run AI agents on [Aex](https://aex.dev) from JavaScript or TypeScript. Connect your model and
4
+ tools, send messages, and read saved conversations without operating a Brain server.
8
5
 
9
- `session.submit()` returns the saved turn's event sequence immediately. Hosted Tools keep running
10
- after client close; host Tools require their process online. Follow Events from that sequence and read
11
- the transcript when the turn terminates. Put structured correction policy in the hosted Agentloop
12
- when submitting from a short-lived Server Action.
6
+ ## Get started
13
7
 
14
- Install `@aexhq/sdk`. Create an API key at https://aex.dev/dashboard.
8
+ Create a key in the [dashboard](https://aex.dev/dashboard). With Node.js 22 or newer, install:
15
9
 
16
- ```ts
17
- import { Aex, agentloop, brainEnv, component, hostEnv, tool } from "@aexhq/sdk";
10
+ ```sh
11
+ npm install @aexhq/sdk@0.80.0 @aexhq/agentloop-pi@7.1.0 zod@4
12
+ ```
18
13
 
19
- const aex = new Aex({ apiKey: process.env.AEX_API_KEY! });
20
- console.log(await aex.account.get());
14
+ Set `AEX_API_KEY` and `OPENAI_API_KEY` in your server environment. Save as `order.mjs` and
15
+ run `node order.mjs`:
16
+
17
+ ```js
18
+ import { Aex, brainEnv, tool } from "@aexhq/sdk";
19
+ import { pi } from "@aexhq/agentloop-pi";
20
+ import { z } from "zod";
21
+
22
+ const lookupOrder = tool({
23
+ name: "lookup_order",
24
+ description: "Look up an order by id.",
25
+ input: z.object({ id: z.string() }),
26
+ run: ({ id }, ctx) => ctx.finish({ id, status: "shipped" }),
27
+ });
28
+
29
+ const aex = new Aex({ apiKey: process.env.AEX_API_KEY });
30
+ try {
31
+ const session = await aex.sessions.create({
32
+ model: { provider: "openai", name: "gpt-4.1-mini", apiKey: process.env.OPENAI_API_KEY },
33
+ agentloop: pi({ env: brainEnv({ name: "brain" }) }),
34
+ tools: [lookupOrder()],
35
+ });
36
+ try {
37
+ await session.send("Look up order A-1001. Has it shipped?");
38
+ console.log(JSON.stringify(await session.transcript(), null, 2));
39
+ console.log("Session:", session.id);
40
+ } finally {
41
+ await session.end();
42
+ }
43
+ } finally {
44
+ await aex.close();
45
+ }
21
46
  ```
22
47
 
23
- `Aex` extends the pinned Brain client. Its sessions, registration, Events, Components and
24
- extension builders are Brain's implementations. SDK 0.78 uses Brain SDK 0.28 and Pi/Codex
25
- 7.0. Images and PDFs use HTTPS URLs; Aex owns attachment publication and expiry. Deploy the matching
26
- runtime and extensions together. Retained sessions require a compatibility check before upgrading.
27
- See https://aex.dev/docs
28
- for a complete session example.
29
-
30
- Put client use, including session creation, inside `try/finally` and `await aex.close()` in
31
- `finally`. The client retains one shared host connection until close, even if creation fails.
32
- Close releases client I/O and local handlers while retaining stored sessions. Use
33
- `session.interrupt()` to stop the current turn, `session.end()` to finish the conversation,
34
- and `session.delete()` to remove an ended or failed session. `interrupt()` replaces SDK
35
- `cancel()`; the HTTP route is unchanged. See the [session example](../../examples/session.mjs).
36
-
37
- Tool schemas describe accepted inputs. Defaulted arguments are optional; Zod applies defaults
38
- and transforms before the handler. Ordinary objects strip extra properties and strict objects
39
- reject them. Pi dispatches in parallel; coordinate shared resources in their owning Tool or
40
- Environment. The official loops explain unanswered calls after interruption without replaying them.
41
-
42
- Tool return and completion are separate. `return ctx.finish(value)` emits an optional result
43
- and finishes an ordinary Tool. Returning a value alone emits it and releases the synchronous
44
- caller; the Tool remains open for `ctx.emitResult(value)` and `ctx.finish()` afterward.
45
- Background observations wake the Agentloop, which chooses whether to call the model and what
46
- to put in its transcript. Results and finish always enter the journal. Keep the host client
47
- connected until all its Tools finish. Interrupt cancels unfinished Tools even while idle.
48
- A forgotten finish stays open until the original deadline, cancellation or Environment loss;
49
- without a deadline it can remain open indefinitely.
50
-
51
- Host Tools accept ordinary successful output or a Brain `Outcome` directly. Structured errors retain
52
- code, message, retryable and details. The top-level statuses `ok`, `error`, `timeout`, `cancelled`
53
- and `unknown` declare outcomes; malformed envelopes fail validation, and only successful values
54
- pass through the output schema. Tool deadlines produce `timeout`, explicit cancellation produces
55
- `cancelled`, and missing reliable results after dispatch produce `unknown`. All are failed Tool
56
- results. Timeout and cancellation do not promise rollback. See
57
- [the full return contract](https://aex.dev/brain/docs/guides/write-a-tool#return-values-and-outcomes).
58
-
59
- `@aexhq/tools-mcp` runs selected MCP Tools in your application host, preserving structured failures
60
- and original JSON Schema constraints. The official Docker and browser HTTP Environments target
61
- standalone Brain and require operator deployment. See [official extensions](https://github.com/aexhq/extensions).
62
-
63
- Place uploaded Wasm Agentloops and Tools in `brainEnv` for hosted execution. `hostEnv`
64
- executes application functions in your process. Native hosted Components receive no server
65
- secrets, filesystem or network grants. `await aex.environments.list()` lists your account's
66
- published configurations. Import `modal` from `@aexhq/env-modal` and pass the catalog URL and
67
- granted profile name; [managed execution](../../docs/environments.md) reserves credits at creation.
68
- Customer-selected HTTP endpoints are denied. Hosted `brainEnv` configuration must be empty; resource access
69
- is configured by each Environment, not declared through extension `needs`. Prepare dependencies
70
- for `hostEnv` Tools in your application before registering them. Supply your model key per session.
71
-
72
- `account.get()` and `account.usage()` accept a workload API key. `keys` management requires
73
- an authenticated account session and is normally performed in the dashboard. API keys do
74
- not grant authority to create more credentials. New key secrets are returned once.
75
-
76
- ## Structured output
77
-
78
- For asynchronous hosted work, configure the official loop with
79
- `output: {schema: z.toJSONSchema(answerType), maxCorrections: 2}` and use `session.submit()`.
80
- Validation and bounded corrections run inside that turn. Corrections cannot dispatch Tools;
81
- only a schema-valid final answer emits an assistant message. Business refinements belong in
82
- your Tools or application, and are not encoded by JSON Schema.
83
-
84
- Pass `output: { type: z.object({ name: z.string() }), maxRetries: 2 }` in the second
85
- argument to `session.send`. The SDK prompts for JSON, validates with Zod locally,
86
- and returns the inferred parsed value. Two additional correction turns are allowed
87
- by default; set zero to disable retries. Ordinary sends keep returning session state;
88
- `idle` alone does not mean the turn succeeded. No terminal Tool is needed for structured output.
89
-
90
- See the [executable example](https://github.com/aexhq/aex/blob/main/examples/structured-output.mjs)
91
- and [full contract](https://aex.dev/brain/docs/guides/structured-output).
92
- Exhaustion throws `StructuredOutputError` with `attempts`, `lastOutput`, and `issues`.
93
- Retries run in your client and are ordinary turns with the session's existing tools.
94
- Use exclusive ownership of sends during the operation. An optional top-level
95
- `signal` cancels the active turn and stops corrections. Raw attempts remain visible
96
- in history and streams; validation does not change the Agentloop or provider format.
97
-
98
- ## Account management
99
-
100
- Use an account session obtained through browser login for account management. Workload
101
- API keys remain scoped to runtime operations and read-only account/usage access.
102
-
103
- ```ts
104
- const account = new Aex({ accountToken: process.env.AEX_ACCOUNT_TOKEN! });
105
- await account.keys.list();
106
- const issued = await account.keys.create({ name: "My app" });
107
- await account.keys.update(issued.key.id, { name: "Renamed app" });
108
- await account.keys.delete(issued.key.id);
109
- await account.account.get(); // includes billing status and limits
110
- await account.account.usage();
111
- await account.account.logout();
48
+ The transcript includes an order lookup and the agent's answer. The lookup function runs in your
49
+ process; keep it connected while the agent needs that tool. The [quickstart](https://aex.dev/docs)
50
+ explains setup and where other tools run.
51
+
52
+ ## Sessions and tools
53
+
54
+ The SDK uses Brain's session API and extension helpers. You can import `tool`, `agentloop`,
55
+ `brainEnv`, `hostEnv`, `component` and `environment` from `@aexhq/sdk`.
56
+
57
+ - [Sessions](https://aex.dev/brain/docs/concepts/sessions): send, submit, stream, reconnect and stop.
58
+ - [Tools](https://aex.dev/brain/docs/guides/write-a-tool): application functions and packaged tools.
59
+ - [Structured output](https://aex.dev/brain/docs/guides/structured-output): validated JSON answers.
60
+ - [Managed environments](https://github.com/aexhq/aex/blob/main/docs/environments.md): hosted tools and workspaces.
61
+ - [Attachments](https://github.com/aexhq/aex/blob/main/docs/attachments.md): upload images and PDFs.
62
+
63
+ Use `ctx.finish(value)` to complete a tool. Use `aex.close()` in `finally` to close client
64
+ connections. Closing the client keeps stored sessions; tools in your process still require it.
65
+
66
+ ## Account and usage
67
+
68
+ ```js
69
+ console.log(await aex.account.get());
70
+ console.log(await aex.account.usage());
71
+ console.log(await aex.account.modelUsage(sessionId));
72
+ console.log(await aex.environments.list());
112
73
  ```
113
74
 
114
- `account.account.authorizeLogin({code_challenge, redirect_uri})` and
115
- `Aex.exchangeLogin({code, code_verifier, redirect_uri})` expose the shared HTTP login
116
- contract for clients. The `@aexhq/cli` package handles opening the browser, PKCE,
117
- loopback callback and local credential storage.
75
+ Run these before closing the client. Workload keys can read account and usage information.
76
+ Creating keys, accepting prices, topups and refunds require an account login; use the
77
+ [dashboard](https://aex.dev/dashboard) or [CLI](https://www.npmjs.com/package/@aexhq/cli).
78
+
79
+ See the [billing guide](https://github.com/aexhq/aex/blob/main/docs/billing.md) for account API
80
+ methods and `maxCostMicroUsd`, the ceiling for a resource operation. Aex spending controls do
81
+ not cap your separate model-provider bill.
118
82
 
119
- Image and PDF uploads use the [attachment API](../../docs/attachments.md). `models(provider?)` forwards Brain's catalogue unchanged, with models.dev metadata when known. Brain validates model selections; Aex has no separate model allowlist.
83
+ Inline Tools default to the process registering them. Published libraries use Brain's generated
84
+ bindings and the selected Environment's prepared runtime. `ctx.finish(value, { content: summary })`
85
+ retains the structured result while offering concise model text. `ctx.model({ messages })` runs an
86
+ independent request within the invocation's lifetime and the session's model authority; hosted
87
+ usage and spending controls include those requests. The Agentloop owns the shared conversation.
@@ -63,6 +63,18 @@ export interface Limits {
63
63
  upstream_timeout_secs: number;
64
64
  usage_max_age_secs: number;
65
65
  }
66
+ /**
67
+ * This interface was referenced by `AexContracts`'s JSON-Schema
68
+ * via the `definition` "TokenUsage".
69
+ */
70
+ export interface TokenUsage {
71
+ charged_micro_usd: number;
72
+ pending_estimate_micro_usd: number;
73
+ rated_micro_usd: number;
74
+ reported_input_tokens: number;
75
+ reported_output_tokens: number;
76
+ unmeasured_calls: number;
77
+ }
66
78
  /**
67
79
  * This interface was referenced by `AexContracts`'s JSON-Schema
68
80
  * via the `definition` "Usage".
@@ -72,6 +84,7 @@ export interface Usage {
72
84
  attachment_bytes: number;
73
85
  attachments: number;
74
86
  measured_at?: number | null;
87
+ model: TokenUsage;
75
88
  retained_bytes: number;
76
89
  sessions: number;
77
90
  }
@@ -155,6 +168,7 @@ export interface Pricebook {
155
168
  rates: {
156
169
  attachment_byte_secs?: Rate;
157
170
  egress_bytes?: Rate;
171
+ model_tokens?: Rate;
158
172
  sandbox_ms?: Rate;
159
173
  turn_ms?: Rate;
160
174
  };
@@ -175,12 +189,14 @@ export interface Rate {
175
189
  */
176
190
  export interface Wallet {
177
191
  accepted_pricebook?: string | null;
192
+ accepted_rates?: Pricebook | null;
178
193
  available_micro_usd: number;
179
194
  balance_micro_usd: number;
180
195
  currency: string;
181
196
  mode: BillingMode;
182
197
  offered_pricebook?: Pricebook | null;
183
198
  payment_mode?: Mode | null;
199
+ pending_estimate_micro_usd: number;
184
200
  reserved_micro_usd: number;
185
201
  spend_limit_micro_usd?: number | null;
186
202
  spent_this_month_micro_usd: number;
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  export * from "@aexhq/brain";
2
2
  export type * from "./generated.js";
3
3
  import { Brain, type BrainOptions } from "@aexhq/brain";
4
- import type { EnvironmentCatalog } from "./generated.js";
4
+ import type { EnvironmentCatalog, TokenUsage } from "./generated.js";
5
5
  import type { Attachment, Account, Usage, ApiKey, IssuedKey, KeyInput, LoginGrantInput, LoginGrant, LoginExchange, AccountSession, Wallet, BillingSettings, LedgerPage, Topup, TopupInput, Refund, RefundInput, SyncPayment } from "./generated.js";
6
6
  export type AexConnection = Omit<BrainOptions, "token" | "baseUrl"> & {
7
7
  baseUrl?: string;
@@ -18,7 +18,7 @@ export type AexOptions = AexConnection & {
18
18
  export declare class Aex extends Brain {
19
19
  private readonly maxCostMicroUsd?;
20
20
  constructor({ apiKey, accountToken, maxCostMicroUsd, ...options }: AexOptions);
21
- /** The ceiling applies separately to each admitted operation. Model BYOK charges remain with the provider. */
21
+ /** Resource and legacy turn reservations use this ceiling; token hosting follows the account limit. */
22
22
  request<T>(method: string, path: string, body?: unknown, idempotencyKey?: string, contentType?: string, signal?: AbortSignal, extraHeaders?: HeadersInit): Promise<T>;
23
23
  static exchangeLogin(input: LoginExchange, options?: AexConnection): Promise<AccountSession>;
24
24
  readonly attachments: {
@@ -35,6 +35,7 @@ export declare class Aex extends Brain {
35
35
  readonly account: {
36
36
  get: () => Promise<Account>;
37
37
  usage: () => Promise<Usage>;
38
+ modelUsage: (sessionId: string) => Promise<TokenUsage>;
38
39
  logout: () => Promise<void>;
39
40
  authorizeLogin: (input: LoginGrantInput) => Promise<LoginGrant>;
40
41
  };
package/dist/index.js CHANGED
@@ -14,7 +14,7 @@ export class Aex extends Brain {
14
14
  nonnegativeInteger(maxCostMicroUsd, "maxCostMicroUsd");
15
15
  this.maxCostMicroUsd = maxCostMicroUsd;
16
16
  }
17
- /** The ceiling applies separately to each admitted operation. Model BYOK charges remain with the provider. */
17
+ /** Resource and legacy turn reservations use this ceiling; token hosting follows the account limit. */
18
18
  request(method, path, body, idempotencyKey, contentType = "application/json", signal, extraHeaders) {
19
19
  const headers = new Headers(extraHeaders);
20
20
  if (this.maxCostMicroUsd !== undefined && !headers.has("x-aex-max-cost-micro-usd"))
@@ -46,6 +46,7 @@ export class Aex extends Brain {
46
46
  account = {
47
47
  get: () => this.request("GET", "/v1/account"),
48
48
  usage: () => this.request("GET", "/v1/usage"),
49
+ modelUsage: (sessionId) => this.request("GET", `/v1/usage/${encodeURIComponent(sessionId)}`),
49
50
  logout: () => this.request("DELETE", "/v1/account/session"),
50
51
  authorizeLogin: (input) => this.request("POST", "/v1/auth/grants", input),
51
52
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aexhq/sdk",
3
- "version": "0.78.0",
3
+ "version": "0.80.0",
4
4
  "description": "Aex accounts and hosted sessions using the Brain SDK",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -28,7 +28,7 @@
28
28
  "tag": "next"
29
29
  },
30
30
  "dependencies": {
31
- "@aexhq/brain": "0.28.0"
31
+ "@aexhq/brain": "0.30.0"
32
32
  },
33
33
  "scripts": {
34
34
  "gen": "node ../../tools/sdk-contracts.mjs",