@aexhq/sdk 0.56.0 → 0.57.1
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 +85 -20
- package/dist/index.d.ts +13 -3
- package/dist/index.js +15 -2
- package/dist/resources.d.ts +157 -0
- package/dist/resources.js +438 -0
- package/dist/session.d.ts +43 -14
- package/dist/session.js +160 -28
- package/dist/tools.d.ts +1 -1
- package/dist/transport.d.ts +16 -7
- package/dist/transport.js +599 -51
- package/package.json +4 -3
package/dist/session.js
CHANGED
|
@@ -1,17 +1,38 @@
|
|
|
1
|
+
import { CustomerHand } from "@aexhq/brain";
|
|
1
2
|
import * as z from "zod";
|
|
2
3
|
import { AbortError, OutputRefusalError, OutputSchemaError, OutputValidationError, SessionError, abortError, errorFromApi, } from "./errors.js";
|
|
3
4
|
import { canonicalize, jcsSha256, randomIdempotencyKey } from "./json.js";
|
|
4
5
|
import { compileTools } from "./tools.js";
|
|
6
|
+
import { SessionChildren, SessionSandbox, SessionStorage } from "./resources.js";
|
|
5
7
|
export class Sessions {
|
|
6
8
|
#transport;
|
|
7
|
-
|
|
9
|
+
#webSocketFactory;
|
|
10
|
+
#clientId;
|
|
11
|
+
#customerHand;
|
|
12
|
+
#customerHandInstance;
|
|
13
|
+
#closed = false;
|
|
14
|
+
constructor(transport, webSocketFactory, clientId) {
|
|
8
15
|
this.#transport = transport;
|
|
16
|
+
this.#webSocketFactory = webSocketFactory;
|
|
17
|
+
this.#clientId = clientId;
|
|
18
|
+
}
|
|
19
|
+
/** @internal Called by `Aex.close()`. */
|
|
20
|
+
close() {
|
|
21
|
+
if (this.#closed)
|
|
22
|
+
return;
|
|
23
|
+
this.#closed = true;
|
|
24
|
+
this.#customerHandInstance?.close();
|
|
25
|
+
this.#customerHandInstance = undefined;
|
|
26
|
+
this.#customerHand = undefined;
|
|
9
27
|
}
|
|
10
28
|
async create(options, request = {}) {
|
|
29
|
+
if (this.#closed)
|
|
30
|
+
throw new SessionError("Aex client is closed");
|
|
11
31
|
const compiledTools = await compileTools(options.tools);
|
|
12
|
-
if (
|
|
13
|
-
throw new TypeError("
|
|
32
|
+
if (options.client?.submitRetries !== undefined && this.#clientId === undefined) {
|
|
33
|
+
throw new TypeError("client.submitRetries requires Aex({ client: { id } })");
|
|
14
34
|
}
|
|
35
|
+
await this.#ensureCustomerHand(compiledTools.clientRegistrations, request.signal);
|
|
15
36
|
const body = {
|
|
16
37
|
model: {
|
|
17
38
|
provider: options.model.provider,
|
|
@@ -21,6 +42,9 @@ export class Sessions {
|
|
|
21
42
|
...(options.model.maxOutputTokens === undefined
|
|
22
43
|
? {}
|
|
23
44
|
: { max_output_tokens: options.model.maxOutputTokens }),
|
|
45
|
+
...(options.model.contextWindowTokens === undefined
|
|
46
|
+
? {}
|
|
47
|
+
: { context_window_tokens: options.model.contextWindowTokens }),
|
|
24
48
|
...(options.model.temperature === undefined ? {} : { temperature: options.model.temperature }),
|
|
25
49
|
...(options.model.reasoningEffort === undefined
|
|
26
50
|
? {}
|
|
@@ -28,31 +52,42 @@ export class Sessions {
|
|
|
28
52
|
},
|
|
29
53
|
tools: {
|
|
30
54
|
items: compiledTools.items,
|
|
31
|
-
...(options.mcp === undefined
|
|
32
|
-
? {}
|
|
33
|
-
: {
|
|
34
|
-
mcp: options.mcp.map((server) => ({
|
|
35
|
-
name: server.name,
|
|
36
|
-
url: server.url,
|
|
37
|
-
...(server.headers === undefined ? {} : { headers: server.headers }),
|
|
38
|
-
...(server.protocol === undefined ? {} : { protocol: server.protocol }),
|
|
39
|
-
...(server.allowedTools === undefined
|
|
40
|
-
? {}
|
|
41
|
-
: { allowed_tools: [...server.allowedTools] }),
|
|
42
|
-
})),
|
|
43
|
-
}),
|
|
44
55
|
},
|
|
45
56
|
...(compiledTools.bundles.length === 0 ? {} : { tool_bundles: compiledTools.bundles }),
|
|
46
|
-
...(options.
|
|
57
|
+
...(options.secrets === undefined ? {} : { secrets: options.secrets }),
|
|
58
|
+
...(options.systemPrompt === undefined ? {} : { system_prompt: options.systemPrompt }),
|
|
59
|
+
...(options.metadata === undefined ? {} : { metadata: options.metadata }),
|
|
60
|
+
...(options.network === undefined
|
|
61
|
+
? {}
|
|
62
|
+
: { network: options.network }),
|
|
63
|
+
...(options.providerRecoveryRetries === undefined
|
|
64
|
+
? {}
|
|
65
|
+
: { provider_recovery_retries: options.providerRecoveryRetries }),
|
|
66
|
+
...(this.#clientId === undefined
|
|
47
67
|
? {}
|
|
48
68
|
: {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
...(options.
|
|
69
|
+
client: {
|
|
70
|
+
id: this.#clientId,
|
|
71
|
+
...(options.client?.submitRetries === undefined
|
|
72
|
+
? {}
|
|
73
|
+
: { submit_retries: options.client.submitRetries }),
|
|
74
|
+
},
|
|
75
|
+
}),
|
|
76
|
+
...(options.children === undefined
|
|
77
|
+
? {}
|
|
78
|
+
: {
|
|
79
|
+
children: {
|
|
80
|
+
...(options.children.maxDepth === undefined
|
|
81
|
+
? {}
|
|
82
|
+
: { max_depth: options.children.maxDepth }),
|
|
83
|
+
...(options.children.maxDirectChildren === undefined
|
|
84
|
+
? {}
|
|
85
|
+
: { max_direct_children: options.children.maxDirectChildren }),
|
|
86
|
+
...(options.children.maxDescendants === undefined
|
|
87
|
+
? {}
|
|
88
|
+
: { max_descendants: options.children.maxDescendants }),
|
|
52
89
|
},
|
|
53
90
|
}),
|
|
54
|
-
...(options.systemPrompt === undefined ? {} : { system_prompt: options.systemPrompt }),
|
|
55
|
-
...(options.metadata === undefined ? {} : { metadata: options.metadata }),
|
|
56
91
|
};
|
|
57
92
|
const data = await this.#transport.json("POST", "/v1/sessions", {
|
|
58
93
|
body,
|
|
@@ -84,13 +119,87 @@ export class Sessions {
|
|
|
84
119
|
...(list.next_cursor === undefined ? {} : { nextCursor: list.next_cursor }),
|
|
85
120
|
};
|
|
86
121
|
}
|
|
122
|
+
async #ensureCustomerHand(registrations, signal) {
|
|
123
|
+
if (this.#closed)
|
|
124
|
+
throw new SessionError("Aex client is closed");
|
|
125
|
+
if (registrations.length === 0)
|
|
126
|
+
return;
|
|
127
|
+
if (this.#clientId === undefined) {
|
|
128
|
+
throw new TypeError("Customer-app Tools require Aex({ client: { id } })");
|
|
129
|
+
}
|
|
130
|
+
if (this.#webSocketFactory === undefined) {
|
|
131
|
+
throw new TypeError("This runtime does not provide WebSocket; pass webSocketFactory to Aex");
|
|
132
|
+
}
|
|
133
|
+
if (this.#customerHand === undefined) {
|
|
134
|
+
let partial;
|
|
135
|
+
const starting = (async () => {
|
|
136
|
+
try {
|
|
137
|
+
partial = new CustomerHand(async () => {
|
|
138
|
+
const grant = await this.#transport.customerHandGrant(this.#clientId);
|
|
139
|
+
return {
|
|
140
|
+
request: { url: grant.url, protocol: grant.protocol },
|
|
141
|
+
observe: (observation) => this.#transport.customerHandObserve(grant.observationUrl, grant.observationToken, observation),
|
|
142
|
+
};
|
|
143
|
+
}, registrations, this.#webSocketFactory, { clientId: this.#clientId });
|
|
144
|
+
this.#customerHandInstance = partial;
|
|
145
|
+
await partial.ready;
|
|
146
|
+
if (this.#closed) {
|
|
147
|
+
partial.close();
|
|
148
|
+
throw new SessionError("Aex client is closed");
|
|
149
|
+
}
|
|
150
|
+
return partial;
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
partial?.close();
|
|
154
|
+
throw error;
|
|
155
|
+
}
|
|
156
|
+
})();
|
|
157
|
+
this.#customerHand = starting;
|
|
158
|
+
void starting.catch(() => {
|
|
159
|
+
if (this.#customerHand === starting) {
|
|
160
|
+
this.#customerHand = undefined;
|
|
161
|
+
if (this.#customerHandInstance === partial)
|
|
162
|
+
this.#customerHandInstance = undefined;
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
// The request may stop waiting, but the process-scoped runner remains reconnectable for
|
|
166
|
+
// later sessions. Its grant/reconnect lifetime must never inherit one create signal.
|
|
167
|
+
await waitWithSignal(starting, signal);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
const hand = await waitWithSignal(this.#customerHand, signal);
|
|
171
|
+
if (this.#closed)
|
|
172
|
+
throw new SessionError("Aex client is closed");
|
|
173
|
+
await waitWithSignal(hand.register(registrations), signal);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
function waitWithSignal(promise, signal) {
|
|
177
|
+
if (signal === undefined)
|
|
178
|
+
return promise;
|
|
179
|
+
if (signal.aborted)
|
|
180
|
+
return Promise.reject(abortError(signal.reason));
|
|
181
|
+
return new Promise((resolve, reject) => {
|
|
182
|
+
const cleanup = () => signal.removeEventListener("abort", onAbort);
|
|
183
|
+
const onAbort = () => {
|
|
184
|
+
cleanup();
|
|
185
|
+
reject(abortError(signal.reason));
|
|
186
|
+
};
|
|
187
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
188
|
+
promise.then((value) => { cleanup(); resolve(value); }, (error) => { cleanup(); reject(error); });
|
|
189
|
+
});
|
|
87
190
|
}
|
|
88
191
|
export class Session {
|
|
89
192
|
#transport;
|
|
90
193
|
#data;
|
|
194
|
+
sandbox;
|
|
195
|
+
storage;
|
|
196
|
+
children;
|
|
91
197
|
constructor(transport, data) {
|
|
92
198
|
this.#transport = transport;
|
|
93
199
|
this.#data = data;
|
|
200
|
+
this.sandbox = new SessionSandbox(transport, data.id);
|
|
201
|
+
this.storage = new SessionStorage(transport, data.id);
|
|
202
|
+
this.children = new SessionChildren(transport, data.id);
|
|
94
203
|
}
|
|
95
204
|
get id() {
|
|
96
205
|
return this.#data.id;
|
|
@@ -98,11 +207,24 @@ export class Session {
|
|
|
98
207
|
get state() {
|
|
99
208
|
return this.#data.state;
|
|
100
209
|
}
|
|
210
|
+
get turnState() {
|
|
211
|
+
return this.#data.turn_state;
|
|
212
|
+
}
|
|
213
|
+
get parentId() {
|
|
214
|
+
return this.#data.parent_id;
|
|
215
|
+
}
|
|
216
|
+
get rootId() {
|
|
217
|
+
return this.#data.root_id;
|
|
218
|
+
}
|
|
219
|
+
get depth() {
|
|
220
|
+
return this.#data.depth;
|
|
221
|
+
}
|
|
101
222
|
get model() {
|
|
102
223
|
return {
|
|
103
224
|
provider: this.#data.model.provider,
|
|
104
225
|
name: this.#data.model.name,
|
|
105
226
|
...(this.#data.model.base_url === undefined ? {} : { baseUrl: this.#data.model.base_url }),
|
|
227
|
+
contextWindowTokens: this.#data.model.context_window_tokens,
|
|
106
228
|
};
|
|
107
229
|
}
|
|
108
230
|
get createdAt() {
|
|
@@ -200,21 +322,31 @@ export class Session {
|
|
|
200
322
|
}
|
|
201
323
|
throw new SessionError("The Aex event stream ended before the session finished its work");
|
|
202
324
|
}
|
|
325
|
+
/**
|
|
326
|
+
* Raw, attempt-aware event stream. Provisional frames have no durable cursor and may later be
|
|
327
|
+
* superseded; consumers rendering them must key by `attempt_id` and process
|
|
328
|
+
* `model.attempt_superseded`. Use `send()` when only the durable winning answer is needed.
|
|
329
|
+
*/
|
|
203
330
|
events(options = {}) {
|
|
204
331
|
return this.#transport.events(this.id, options);
|
|
205
332
|
}
|
|
206
333
|
async cancel(options = {}) {
|
|
207
|
-
this.#data = await this.#transport.json("POST", `/v1/sessions/${encodeURIComponent(this.id)}/cancel`, { signal: options.signal });
|
|
334
|
+
this.#data = await this.#transport.json("POST", `/v1/sessions/${encodeURIComponent(this.id)}/cancel`, { signal: options.signal, retry: true });
|
|
335
|
+
return this;
|
|
336
|
+
}
|
|
337
|
+
async end(options = {}) {
|
|
338
|
+
this.#data = await this.#transport.json("POST", `/v1/sessions/${encodeURIComponent(this.id)}/end`, { signal: options.signal, retry: true });
|
|
208
339
|
return this;
|
|
209
340
|
}
|
|
210
341
|
async delete(options = {}) {
|
|
211
|
-
await this.#transport.
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
342
|
+
await this.#transport.deleteSession(this.id, options.queue !== true, options.signal);
|
|
343
|
+
this.#data = {
|
|
344
|
+
...this.#data,
|
|
345
|
+
state: options.queue === true ? "deleting" : "deleted",
|
|
346
|
+
};
|
|
215
347
|
}
|
|
216
348
|
markIdle() {
|
|
217
|
-
this.#data = { ...this.#data,
|
|
349
|
+
this.#data = { ...this.#data, turn_state: "idle" };
|
|
218
350
|
}
|
|
219
351
|
}
|
|
220
352
|
function isOutputOptions(options) {
|
package/dist/tools.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { compileTools } from "@aexhq/brain";
|
|
2
|
-
export type { CompiledTools, Tool } from "@aexhq/brain";
|
|
2
|
+
export type { ClientRegistration, CompiledTools, Tool } from "@aexhq/brain";
|
package/dist/transport.d.ts
CHANGED
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
import type { Event } from "@aexhq/brain/session";
|
|
2
|
+
import type { JsonRequestOptions, TransferTicket } from "@aexhq/brain";
|
|
2
3
|
export type Fetch = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
|
|
3
|
-
interface JsonRequestOptions {
|
|
4
|
-
body?: unknown;
|
|
5
|
-
headers?: Record<string, string>;
|
|
6
|
-
signal?: AbortSignal | undefined;
|
|
7
|
-
retry?: boolean;
|
|
8
|
-
}
|
|
9
4
|
export interface EventOptions {
|
|
10
5
|
after?: number;
|
|
11
6
|
follow?: boolean;
|
|
@@ -15,8 +10,22 @@ export declare class Transport {
|
|
|
15
10
|
#private;
|
|
16
11
|
readonly baseUrl: string;
|
|
17
12
|
constructor(apiKey: string, baseUrl: string, fetchImplementation: Fetch);
|
|
13
|
+
customerHandGrant(clientId: string, signal?: AbortSignal): Promise<{
|
|
14
|
+
url: string;
|
|
15
|
+
protocol: string;
|
|
16
|
+
expiresAt: string;
|
|
17
|
+
observationUrl: string;
|
|
18
|
+
observationToken: string;
|
|
19
|
+
}>;
|
|
20
|
+
customerHandObserve(url: string, token: string, observation: unknown): Promise<void>;
|
|
21
|
+
downloadTransfer(ticket: TransferTicket, signal?: AbortSignal, expectedBytes?: number): Promise<Uint8Array>;
|
|
22
|
+
downloadTransferStream(ticket: TransferTicket, signal?: AbortSignal, expectedBytes?: number): Promise<ReadableStream<Uint8Array>>;
|
|
23
|
+
uploadTransfer(ticket: TransferTicket, content: Uint8Array | (() => ReadableStream<Uint8Array>), bytes: number, signal?: AbortSignal): Promise<void>;
|
|
18
24
|
json<T>(method: "GET" | "POST" | "DELETE", path: string, options?: JsonRequestOptions): Promise<T>;
|
|
25
|
+
/** Accept one durable deletion job; strict callers poll its short status resource client-side. */
|
|
26
|
+
deleteSession(sessionId: string, waitForCompletion: boolean, signal?: AbortSignal): Promise<void>;
|
|
19
27
|
events(sessionId: string, options?: EventOptions): AsyncGenerator<Event>;
|
|
20
28
|
private responseError;
|
|
21
29
|
}
|
|
22
|
-
|
|
30
|
+
/** @internal Incremental, constant-space decoder for Brain's bounded public SSE events. */
|
|
31
|
+
export declare function parseEventStream(stream: ReadableStream<Uint8Array>): AsyncGenerator<Event>;
|