@aexhq/sdk 0.75.3 → 0.77.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,5 +1,16 @@
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.
8
+
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.
13
+
3
14
  Install `@aexhq/sdk`. Create an API key at https://aex.dev/dashboard.
4
15
 
5
16
  ```ts
@@ -10,8 +21,8 @@ console.log(await aex.account.get());
10
21
  ```
11
22
 
12
23
  `Aex` extends the pinned Brain client. Its sessions, registration, Events, Components and
13
- extension builders are Brain's implementations. SDK 0.75 uses Brain SDK 0.24 and Pi/Codex/Tools
14
- 6.1. Images and PDFs use HTTPS URLs; Aex owns attachment publication and expiry. Deploy the matching
24
+ extension builders are Brain's implementations. SDK 0.77 uses Brain SDK 0.27 and Pi/Codex
25
+ 6.2. Images and PDFs use HTTPS URLs; Aex owns attachment publication and expiry. Deploy the matching
15
26
  runtime and extensions together. Retained sessions require a compatibility check before upgrading.
16
27
  See https://aex.dev/docs
17
28
  for a complete session example.
@@ -42,8 +53,10 @@ standalone Brain and require operator deployment. See [official extensions](http
42
53
 
43
54
  Place uploaded Wasm Agentloops and Tools in `brainEnv` for hosted execution. `hostEnv`
44
55
  executes application functions in your process. Native hosted Components receive no server
45
- secrets, filesystem or network grants. Customer-selected HTTP Environments are not enabled
46
- on the initial deployment. Hosted `brainEnv` configuration must be empty; resource access
56
+ secrets, filesystem or network grants. `await aex.environments.list()` lists your account's
57
+ published configurations. Import `modal` from `@aexhq/env-modal` and pass the catalog URL and
58
+ granted profile name; [managed execution](../../docs/environments.md) reserves credits at creation.
59
+ Customer-selected HTTP endpoints are denied. Hosted `brainEnv` configuration must be empty; resource access
47
60
  is configured by each Environment, not declared through extension `needs`. Prepare dependencies
48
61
  for `hostEnv` Tools in your application before registering them. Supply your model key per session.
49
62
 
@@ -53,6 +66,12 @@ not grant authority to create more credentials. New key secrets are returned onc
53
66
 
54
67
  ## Structured output
55
68
 
69
+ For asynchronous hosted work, configure the official loop with
70
+ `output: {schema: z.toJSONSchema(answerType), maxCorrections: 2}` and use `session.submit()`.
71
+ Validation and bounded corrections run inside that turn. Corrections cannot dispatch Tools;
72
+ only a schema-valid final answer emits an assistant message. Business refinements belong in
73
+ your Tools or application, and are not encoded by JSON Schema.
74
+
56
75
  Pass `output: { type: z.object({ name: z.string() }), maxRetries: 2 }` in the second
57
76
  argument to `session.send`. The SDK prompts for JSON, validates with Zod locally,
58
77
  and returns the inferred parsed value. Two additional correction turns are allowed
@@ -3,7 +3,30 @@ import type { Media } from "@aexhq/brain";
3
3
  * This interface was referenced by `AexContracts`'s JSON-Schema
4
4
  * via the `definition` "Billing".
5
5
  */
6
- export type Billing = "preview_customer_model_keys";
6
+ export type Billing = "preview_customer_model_keys" | "prepaid_customer_model_keys";
7
+ /**
8
+ * This interface was referenced by `AexContracts`'s JSON-Schema
9
+ * via the `definition` "BillingMode".
10
+ */
11
+ export type BillingMode = "preview" | "prepaid";
12
+ /**
13
+ * This interface was referenced by `AexContracts`'s JSON-Schema
14
+ * via the `definition` "Mode".
15
+ */
16
+ export type Mode = "test" | "live";
17
+ /**
18
+ * This interface was referenced by `AexContracts`'s JSON-Schema
19
+ * via the `definition` "SyncPayment".
20
+ */
21
+ export type SyncPayment = {
22
+ checkout_id?: string | null;
23
+ id: string;
24
+ kind: "topup";
25
+ } | {
26
+ id: string;
27
+ kind: "refund";
28
+ refund_id?: string | null;
29
+ };
7
30
  export interface AexContracts {
8
31
  }
9
32
  /**
@@ -123,3 +146,137 @@ export interface AccountSession {
123
146
  expires: number;
124
147
  token: string;
125
148
  }
149
+ /**
150
+ * This interface was referenced by `AexContracts`'s JSON-Schema
151
+ * via the `definition` "Pricebook".
152
+ */
153
+ export interface Pricebook {
154
+ id: string;
155
+ rates: {
156
+ attachment_byte_secs?: Rate;
157
+ egress_bytes?: Rate;
158
+ sandbox_ms?: Rate;
159
+ turn_ms?: Rate;
160
+ };
161
+ }
162
+ /**
163
+ * A rational price in micro-USD. Rating rounds once over cumulative resource usage.
164
+ *
165
+ * This interface was referenced by `AexContracts`'s JSON-Schema
166
+ * via the `definition` "Rate".
167
+ */
168
+ export interface Rate {
169
+ micro_usd: number;
170
+ units: number;
171
+ }
172
+ /**
173
+ * This interface was referenced by `AexContracts`'s JSON-Schema
174
+ * via the `definition` "Wallet".
175
+ */
176
+ export interface Wallet {
177
+ accepted_pricebook?: string | null;
178
+ available_micro_usd: number;
179
+ balance_micro_usd: number;
180
+ currency: string;
181
+ mode: BillingMode;
182
+ offered_pricebook?: Pricebook | null;
183
+ payment_mode?: Mode | null;
184
+ reserved_micro_usd: number;
185
+ spend_limit_micro_usd?: number | null;
186
+ spent_this_month_micro_usd: number;
187
+ suspended: boolean;
188
+ topup_amounts_cents: number[];
189
+ }
190
+ /**
191
+ * This interface was referenced by `AexContracts`'s JSON-Schema
192
+ * via the `definition` "BillingSettings".
193
+ */
194
+ export interface BillingSettings {
195
+ pricebook: string;
196
+ spend_limit_micro_usd: number;
197
+ }
198
+ /**
199
+ * This interface was referenced by `AexContracts`'s JSON-Schema
200
+ * via the `definition` "LedgerEntry".
201
+ */
202
+ export interface LedgerEntry {
203
+ created: number;
204
+ delta_micro_usd: number;
205
+ description: string;
206
+ id: number;
207
+ kind: string;
208
+ reference: string;
209
+ }
210
+ /**
211
+ * This interface was referenced by `AexContracts`'s JSON-Schema
212
+ * via the `definition` "LedgerPage".
213
+ */
214
+ export interface LedgerPage {
215
+ entries: LedgerEntry[];
216
+ next_before?: number | null;
217
+ }
218
+ /**
219
+ * This interface was referenced by `AexContracts`'s JSON-Schema
220
+ * via the `definition` "TopupInput".
221
+ */
222
+ export interface TopupInput {
223
+ amount_cents: number;
224
+ }
225
+ /**
226
+ * This interface was referenced by `AexContracts`'s JSON-Schema
227
+ * via the `definition` "Topup".
228
+ */
229
+ export interface Topup {
230
+ amount_cents: number;
231
+ checkout_url?: string | null;
232
+ created: number;
233
+ id: string;
234
+ receipt_url?: string | null;
235
+ refunded_cents: number;
236
+ state: string;
237
+ }
238
+ /**
239
+ * This interface was referenced by `AexContracts`'s JSON-Schema
240
+ * via the `definition` "RefundInput".
241
+ */
242
+ export interface RefundInput {
243
+ amount_cents: number;
244
+ topup: string;
245
+ }
246
+ /**
247
+ * This interface was referenced by `AexContracts`'s JSON-Schema
248
+ * via the `definition` "Refund".
249
+ */
250
+ export interface Refund {
251
+ amount_cents: number;
252
+ created: number;
253
+ id: string;
254
+ state: string;
255
+ topup: string;
256
+ }
257
+ /**
258
+ * This interface was referenced by `AexContracts`'s JSON-Schema
259
+ * via the `definition` "EnvironmentProfile".
260
+ */
261
+ export interface EnvironmentProfile {
262
+ maxLifetimeMs: number;
263
+ [k: string]: unknown;
264
+ }
265
+ /**
266
+ * This interface was referenced by `AexContracts`'s JSON-Schema
267
+ * via the `definition` "EnvironmentCatalog".
268
+ */
269
+ export interface EnvironmentCatalog {
270
+ driver_url: string;
271
+ profiles: {
272
+ [k: string]: EnvironmentProfile;
273
+ };
274
+ }
275
+ /**
276
+ * This interface was referenced by `AexContracts`'s JSON-Schema
277
+ * via the `definition` "EnvironmentSelection".
278
+ */
279
+ export interface EnvironmentSelection {
280
+ lifetimeMs: number;
281
+ profile: string;
282
+ }
package/dist/index.d.ts CHANGED
@@ -1,11 +1,14 @@
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 { Attachment, Account, Usage, ApiKey, IssuedKey, KeyInput, LoginGrantInput, LoginGrant, LoginExchange, AccountSession } from "./generated.js";
4
+ import type { EnvironmentCatalog } from "./generated.js";
5
+ import type { Attachment, Account, Usage, ApiKey, IssuedKey, KeyInput, LoginGrantInput, LoginGrant, LoginExchange, AccountSession, Wallet, BillingSettings, LedgerPage, Topup, TopupInput, Refund, RefundInput, SyncPayment } from "./generated.js";
5
6
  export type AexConnection = Omit<BrainOptions, "token" | "baseUrl"> & {
6
7
  baseUrl?: string;
7
8
  };
8
- export type AexOptions = AexConnection & ({
9
+ export type AexOptions = AexConnection & {
10
+ maxCostMicroUsd?: number;
11
+ } & ({
9
12
  apiKey: string;
10
13
  accountToken?: never;
11
14
  } | {
@@ -13,13 +16,18 @@ export type AexOptions = AexConnection & ({
13
16
  apiKey?: never;
14
17
  });
15
18
  export declare class Aex extends Brain {
16
- constructor({ apiKey, accountToken, ...options }: AexOptions);
19
+ private readonly maxCostMicroUsd?;
20
+ constructor({ apiKey, accountToken, maxCostMicroUsd, ...options }: AexOptions);
21
+ /** The ceiling applies separately to each admitted operation. Model BYOK charges remain with the provider. */
22
+ request<T>(method: string, path: string, body?: unknown, idempotencyKey?: string, contentType?: string, signal?: AbortSignal, extraHeaders?: HeadersInit): Promise<T>;
17
23
  static exchangeLogin(input: LoginExchange, options?: AexConnection): Promise<AccountSession>;
18
24
  readonly attachments: {
19
25
  upload: (sessionId: string, bytes: Uint8Array, options: {
20
26
  contentType: string;
21
27
  expiresAt?: number;
22
28
  idempotencyKey: string;
29
+ downloadBudgetBytes?: number;
30
+ maxCostMicroUsd?: number;
23
31
  signal?: AbortSignal;
24
32
  }) => Promise<Attachment>;
25
33
  delete: (sessionId: string, id: string) => Promise<void>;
@@ -30,6 +38,19 @@ export declare class Aex extends Brain {
30
38
  logout: () => Promise<void>;
31
39
  authorizeLogin: (input: LoginGrantInput) => Promise<LoginGrant>;
32
40
  };
41
+ readonly billing: {
42
+ get: () => Promise<Wallet>;
43
+ update: (input: BillingSettings) => Promise<Wallet>;
44
+ ledger: (before?: number) => Promise<LedgerPage>;
45
+ topups: () => Promise<Topup[]>;
46
+ topup: (input: TopupInput, idempotencyKey: string) => Promise<Topup>;
47
+ refunds: () => Promise<Refund[]>;
48
+ refund: (input: RefundInput, idempotencyKey: string) => Promise<Refund>;
49
+ sync: (input: SyncPayment) => Promise<Wallet>;
50
+ };
51
+ readonly environments: {
52
+ list: () => Promise<EnvironmentCatalog>;
53
+ };
33
54
  /** Key management requires an account session; workload API keys cannot create credentials. */
34
55
  readonly keys: {
35
56
  list: () => Promise<ApiKey[]>;
package/dist/index.js CHANGED
@@ -1,10 +1,25 @@
1
1
  export * from "@aexhq/brain";
2
2
  import { Brain } from "@aexhq/brain";
3
+ function nonnegativeInteger(value, name) {
4
+ if (!Number.isSafeInteger(value) || value < 0)
5
+ throw new TypeError(`${name} must be a nonnegative safe integer`);
6
+ }
3
7
  export class Aex extends Brain {
4
- constructor({ apiKey, accountToken, ...options }) {
8
+ maxCostMicroUsd;
9
+ constructor({ apiKey, accountToken, maxCostMicroUsd, ...options }) {
5
10
  if (!(apiKey || accountToken) || (apiKey && accountToken))
6
11
  throw new TypeError("one apiKey or accountToken is required");
7
12
  super({ baseUrl: "https://api.aex.dev", ...options, token: apiKey ?? accountToken });
13
+ if (maxCostMicroUsd !== undefined)
14
+ nonnegativeInteger(maxCostMicroUsd, "maxCostMicroUsd");
15
+ this.maxCostMicroUsd = maxCostMicroUsd;
16
+ }
17
+ /** The ceiling applies separately to each admitted operation. Model BYOK charges remain with the provider. */
18
+ request(method, path, body, idempotencyKey, contentType = "application/json", signal, extraHeaders) {
19
+ const headers = new Headers(extraHeaders);
20
+ if (this.maxCostMicroUsd !== undefined && !headers.has("x-aex-max-cost-micro-usd"))
21
+ headers.set("x-aex-max-cost-micro-usd", String(this.maxCostMicroUsd));
22
+ return super.request(method, path, body, idempotencyKey, contentType, signal, headers);
8
23
  }
9
24
  static exchangeLogin(input, options = {}) {
10
25
  return new Brain({ baseUrl: "https://api.aex.dev", ...options }).request("POST", "/v1/auth/exchange", input);
@@ -13,7 +28,18 @@ export class Aex extends Brain {
13
28
  upload: (sessionId, bytes, options) => {
14
29
  if (options.expiresAt !== undefined && (!Number.isSafeInteger(options.expiresAt) || options.expiresAt <= 0))
15
30
  throw new TypeError("expiresAt must be positive Unix seconds");
16
- return this.request("POST", `/v1/sessions/${encodeURIComponent(sessionId)}/attachments`, bytes, options.idempotencyKey, options.contentType, options.signal, options.expiresAt === undefined ? undefined : { "x-aex-expires-at": String(options.expiresAt) });
31
+ const headers = {};
32
+ if (options.expiresAt !== undefined)
33
+ headers["x-aex-expires-at"] = String(options.expiresAt);
34
+ if (options.maxCostMicroUsd !== undefined) {
35
+ nonnegativeInteger(options.maxCostMicroUsd, "maxCostMicroUsd");
36
+ headers["x-aex-max-cost-micro-usd"] = String(options.maxCostMicroUsd);
37
+ }
38
+ if (options.downloadBudgetBytes !== undefined) {
39
+ nonnegativeInteger(options.downloadBudgetBytes, "downloadBudgetBytes");
40
+ headers["x-aex-download-budget-bytes"] = String(options.downloadBudgetBytes);
41
+ }
42
+ return this.request("POST", `/v1/sessions/${encodeURIComponent(sessionId)}/attachments`, bytes, options.idempotencyKey, options.contentType, options.signal, headers);
17
43
  },
18
44
  delete: (sessionId, id) => this.request("DELETE", `/v1/sessions/${encodeURIComponent(sessionId)}/attachments/${encodeURIComponent(id)}`),
19
45
  };
@@ -23,6 +49,23 @@ export class Aex extends Brain {
23
49
  logout: () => this.request("DELETE", "/v1/account/session"),
24
50
  authorizeLogin: (input) => this.request("POST", "/v1/auth/grants", input),
25
51
  };
52
+ billing = {
53
+ get: () => this.request("GET", "/v1/billing"),
54
+ update: (input) => this.request("PUT", "/v1/billing", input),
55
+ ledger: (before) => {
56
+ if (before !== undefined)
57
+ nonnegativeInteger(before, "before");
58
+ return this.request("GET", `/v1/billing/ledger${before === undefined ? "" : `?before=${before}`}`);
59
+ },
60
+ topups: () => this.request("GET", "/v1/billing/topups"),
61
+ topup: (input, idempotencyKey) => this.request("POST", "/v1/billing/topups", input, idempotencyKey),
62
+ refunds: () => this.request("GET", "/v1/billing/refunds"),
63
+ refund: (input, idempotencyKey) => this.request("POST", "/v1/billing/refunds", input, idempotencyKey),
64
+ sync: (input) => this.request("POST", "/v1/billing/sync", input),
65
+ };
66
+ environments = {
67
+ list: () => this.request("GET", "/v1/environments"),
68
+ };
26
69
  /** Key management requires an account session; workload API keys cannot create credentials. */
27
70
  keys = {
28
71
  list: () => this.request("GET", "/v1/keys"),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aexhq/sdk",
3
- "version": "0.75.3",
3
+ "version": "0.77.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.24.4"
31
+ "@aexhq/brain": "0.27.0"
32
32
  },
33
33
  "scripts": {
34
34
  "gen": "node ../../tools/sdk-contracts.mjs",