@aexhq/sdk 0.55.1 → 0.57.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 +96 -15
- package/dist/errors.d.ts +7 -1
- package/dist/index.d.ts +13 -1
- package/dist/index.js +15 -1
- package/dist/resources.d.ts +157 -0
- package/dist/resources.js +438 -0
- package/dist/session.d.ts +53 -5
- package/dist/session.js +295 -79
- package/dist/tools.d.ts +2 -0
- package/dist/tools.js +1 -0
- package/dist/transport.d.ts +17 -8
- package/dist/transport.js +599 -51
- package/package.json +6 -5
package/dist/session.js
CHANGED
|
@@ -1,12 +1,38 @@
|
|
|
1
|
+
import { CustomerHand } from "@aexhq/brain";
|
|
1
2
|
import * as z from "zod";
|
|
2
|
-
import { AbortError, OutputSchemaError, OutputValidationError, SessionError, abortError, errorFromApi, } from "./errors.js";
|
|
3
|
-
import { jcsSha256, randomIdempotencyKey } from "./json.js";
|
|
3
|
+
import { AbortError, OutputRefusalError, OutputSchemaError, OutputValidationError, SessionError, abortError, errorFromApi, } from "./errors.js";
|
|
4
|
+
import { canonicalize, jcsSha256, randomIdempotencyKey } from "./json.js";
|
|
5
|
+
import { compileTools } from "./tools.js";
|
|
6
|
+
import { SessionChildren, SessionSandbox, SessionStorage } from "./resources.js";
|
|
4
7
|
export class Sessions {
|
|
5
8
|
#transport;
|
|
6
|
-
|
|
9
|
+
#webSocketFactory;
|
|
10
|
+
#clientId;
|
|
11
|
+
#customerHand;
|
|
12
|
+
#customerHandInstance;
|
|
13
|
+
#closed = false;
|
|
14
|
+
constructor(transport, webSocketFactory, clientId) {
|
|
7
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;
|
|
8
27
|
}
|
|
9
28
|
async create(options, request = {}) {
|
|
29
|
+
if (this.#closed)
|
|
30
|
+
throw new SessionError("Aex client is closed");
|
|
31
|
+
const compiledTools = await compileTools(options.tools);
|
|
32
|
+
if (options.client?.submitRetries !== undefined && this.#clientId === undefined) {
|
|
33
|
+
throw new TypeError("client.submitRetries requires Aex({ client: { id } })");
|
|
34
|
+
}
|
|
35
|
+
await this.#ensureCustomerHand(compiledTools.clientRegistrations, request.signal);
|
|
10
36
|
const body = {
|
|
11
37
|
model: {
|
|
12
38
|
provider: options.model.provider,
|
|
@@ -16,13 +42,52 @@ export class Sessions {
|
|
|
16
42
|
...(options.model.maxOutputTokens === undefined
|
|
17
43
|
? {}
|
|
18
44
|
: { max_output_tokens: options.model.maxOutputTokens }),
|
|
45
|
+
...(options.model.contextWindowTokens === undefined
|
|
46
|
+
? {}
|
|
47
|
+
: { context_window_tokens: options.model.contextWindowTokens }),
|
|
19
48
|
...(options.model.temperature === undefined ? {} : { temperature: options.model.temperature }),
|
|
20
49
|
...(options.model.reasoningEffort === undefined
|
|
21
50
|
? {}
|
|
22
51
|
: { reasoning_effort: options.model.reasoningEffort }),
|
|
23
52
|
},
|
|
53
|
+
tools: {
|
|
54
|
+
items: compiledTools.items,
|
|
55
|
+
},
|
|
56
|
+
...(compiledTools.bundles.length === 0 ? {} : { tool_bundles: compiledTools.bundles }),
|
|
57
|
+
...(options.secrets === undefined ? {} : { secrets: options.secrets }),
|
|
24
58
|
...(options.systemPrompt === undefined ? {} : { system_prompt: options.systemPrompt }),
|
|
25
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
|
|
67
|
+
? {}
|
|
68
|
+
: {
|
|
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 }),
|
|
89
|
+
},
|
|
90
|
+
}),
|
|
26
91
|
};
|
|
27
92
|
const data = await this.#transport.json("POST", "/v1/sessions", {
|
|
28
93
|
body,
|
|
@@ -54,13 +119,87 @@ export class Sessions {
|
|
|
54
119
|
...(list.next_cursor === undefined ? {} : { nextCursor: list.next_cursor }),
|
|
55
120
|
};
|
|
56
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
|
+
});
|
|
57
190
|
}
|
|
58
191
|
export class Session {
|
|
59
192
|
#transport;
|
|
60
193
|
#data;
|
|
194
|
+
sandbox;
|
|
195
|
+
storage;
|
|
196
|
+
children;
|
|
61
197
|
constructor(transport, data) {
|
|
62
198
|
this.#transport = transport;
|
|
63
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);
|
|
64
203
|
}
|
|
65
204
|
get id() {
|
|
66
205
|
return this.#data.id;
|
|
@@ -68,11 +207,24 @@ export class Session {
|
|
|
68
207
|
get state() {
|
|
69
208
|
return this.#data.state;
|
|
70
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
|
+
}
|
|
71
222
|
get model() {
|
|
72
223
|
return {
|
|
73
224
|
provider: this.#data.model.provider,
|
|
74
225
|
name: this.#data.model.name,
|
|
75
226
|
...(this.#data.model.base_url === undefined ? {} : { baseUrl: this.#data.model.base_url }),
|
|
227
|
+
contextWindowTokens: this.#data.model.context_window_tokens,
|
|
76
228
|
};
|
|
77
229
|
}
|
|
78
230
|
get createdAt() {
|
|
@@ -89,15 +241,35 @@ export class Session {
|
|
|
89
241
|
return this;
|
|
90
242
|
}
|
|
91
243
|
async send(input, options = {}) {
|
|
244
|
+
const outputOptions = isOutputOptions(options) ? options : undefined;
|
|
245
|
+
const compiled = outputOptions === undefined
|
|
246
|
+
? undefined
|
|
247
|
+
: await compileOutputSchema(outputOptions.output, outputOptions.outputRetries);
|
|
92
248
|
const accepted = await this.#transport.json("POST", `/v1/sessions/${encodeURIComponent(this.id)}/messages`, {
|
|
93
249
|
body: {
|
|
94
250
|
content: input,
|
|
95
251
|
...(options.metadata === undefined ? {} : { metadata: options.metadata }),
|
|
252
|
+
...(compiled === undefined
|
|
253
|
+
? {}
|
|
254
|
+
: {
|
|
255
|
+
output: {
|
|
256
|
+
schema: compiled.jsonSchema,
|
|
257
|
+
schema_hash: compiled.schemaHash,
|
|
258
|
+
...(compiled.retries === undefined ? {} : { retries: compiled.retries }),
|
|
259
|
+
},
|
|
260
|
+
}),
|
|
96
261
|
},
|
|
97
262
|
headers: { "Idempotency-Key": options.idempotencyKey ?? randomIdempotencyKey() },
|
|
98
263
|
signal: options.signal,
|
|
99
264
|
retry: true,
|
|
100
265
|
});
|
|
266
|
+
if (compiled !== undefined) {
|
|
267
|
+
if (accepted.session_id !== this.id ||
|
|
268
|
+
accepted.output_id === undefined ||
|
|
269
|
+
accepted.schema_hash !== compiled.schemaHash) {
|
|
270
|
+
throw new SessionError("Aex returned an inconsistent typed-output admission");
|
|
271
|
+
}
|
|
272
|
+
}
|
|
101
273
|
let answer = "";
|
|
102
274
|
try {
|
|
103
275
|
for await (const event of this.events({ after: Math.max(0, accepted.seq - 1), signal: options.signal })) {
|
|
@@ -105,79 +277,39 @@ export class Session {
|
|
|
105
277
|
answer = event.text;
|
|
106
278
|
}
|
|
107
279
|
else if (event.type === "turn.failed" && event.turn_id === accepted.turn_id) {
|
|
108
|
-
throw errorFromApi(event.error);
|
|
280
|
+
throw errorFromApi(event.error, undefined, outputIssues(event.error));
|
|
109
281
|
}
|
|
110
282
|
else if (event.type === "turn.completed" && event.turn_id === accepted.turn_id) {
|
|
111
283
|
this.markIdle();
|
|
112
284
|
if (event.stop_reason === "cancelled")
|
|
113
285
|
throw new AbortError();
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
if (jsonSchema.type !== "object") {
|
|
140
|
-
throw new OutputSchemaError("session.output() requires a Zod object schema");
|
|
141
|
-
}
|
|
142
|
-
const schemaHash = await jcsSha256(jsonSchema);
|
|
143
|
-
const body = {
|
|
144
|
-
schema: jsonSchema,
|
|
145
|
-
schema_hash: schemaHash,
|
|
146
|
-
...(input === undefined ? {} : { input }),
|
|
147
|
-
...(options.metadata === undefined ? {} : { metadata: options.metadata }),
|
|
148
|
-
};
|
|
149
|
-
const accepted = await this.#transport.json("POST", `/v1/sessions/${encodeURIComponent(this.id)}/output`, {
|
|
150
|
-
body,
|
|
151
|
-
headers: { "Idempotency-Key": options.idempotencyKey ?? randomIdempotencyKey() },
|
|
152
|
-
signal: options.signal,
|
|
153
|
-
retry: true,
|
|
154
|
-
});
|
|
155
|
-
if (accepted.session_id !== this.id || accepted.schema_hash !== schemaHash) {
|
|
156
|
-
throw new SessionError("Aex returned an inconsistent output admission");
|
|
157
|
-
}
|
|
158
|
-
try {
|
|
159
|
-
for await (const event of this.events({ after: Math.max(0, accepted.seq - 1), signal: options.signal })) {
|
|
160
|
-
if (event.type === "output.failed" && event.output_id === accepted.output_id) {
|
|
161
|
-
if (event.schema_hash !== schemaHash) {
|
|
162
|
-
throw new SessionError("Aex returned an output failure for a different schema");
|
|
163
|
-
}
|
|
164
|
-
this.markIdle();
|
|
165
|
-
throw outputEventError(event.error, event.issues);
|
|
166
|
-
}
|
|
167
|
-
if (event.type === "output.completed" && event.output_id === accepted.output_id) {
|
|
168
|
-
if (event.output.schema_hash !== schemaHash) {
|
|
169
|
-
throw new SessionError("Aex returned an output value for a different schema");
|
|
170
|
-
}
|
|
171
|
-
this.markIdle();
|
|
172
|
-
const parsed = await schema.safeParseAsync(event.output.value);
|
|
173
|
-
if (!parsed.success) {
|
|
174
|
-
throw new OutputValidationError("The output passed the wire schema but failed the original Zod schema", parsed.error.issues.map((issue) => ({
|
|
175
|
-
path: jsonPointer(issue.path),
|
|
176
|
-
message: issue.message,
|
|
177
|
-
keyword: issue.code,
|
|
178
|
-
})));
|
|
286
|
+
if (compiled !== undefined && outputOptions !== undefined) {
|
|
287
|
+
if (event.result === undefined) {
|
|
288
|
+
if (event.stop_reason === "refusal") {
|
|
289
|
+
throw new OutputRefusalError("The model refused the structured-output request");
|
|
290
|
+
}
|
|
291
|
+
throw new OutputValidationError("The model ended the turn without submitting the requested structured output", [{
|
|
292
|
+
path: "",
|
|
293
|
+
message: "The model did not call aex_submit_output",
|
|
294
|
+
keyword: "missing_output",
|
|
295
|
+
}]);
|
|
296
|
+
}
|
|
297
|
+
if (event.result.name !== "aex_submit_output" ||
|
|
298
|
+
event.result.metadata?.output_id !== accepted.output_id ||
|
|
299
|
+
event.result.metadata?.schema_hash !== compiled.schemaHash) {
|
|
300
|
+
throw new SessionError("Aex returned a typed result for a different request");
|
|
301
|
+
}
|
|
302
|
+
const parsed = await outputOptions.output.safeParseAsync(event.result.value);
|
|
303
|
+
if (!parsed.success) {
|
|
304
|
+
throw new OutputValidationError("The output passed the wire schema but failed the original Zod schema", parsed.error.issues.map((issue) => ({
|
|
305
|
+
path: jsonPointer(issue.path),
|
|
306
|
+
message: issue.message,
|
|
307
|
+
keyword: issue.code,
|
|
308
|
+
})));
|
|
309
|
+
}
|
|
310
|
+
return parsed.data;
|
|
179
311
|
}
|
|
180
|
-
return
|
|
312
|
+
return answer;
|
|
181
313
|
}
|
|
182
314
|
}
|
|
183
315
|
}
|
|
@@ -188,27 +320,111 @@ export class Session {
|
|
|
188
320
|
}
|
|
189
321
|
throw error;
|
|
190
322
|
}
|
|
191
|
-
throw new SessionError("The Aex event stream ended before the
|
|
323
|
+
throw new SessionError("The Aex event stream ended before the session finished its work");
|
|
192
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
|
+
*/
|
|
193
330
|
events(options = {}) {
|
|
194
331
|
return this.#transport.events(this.id, options);
|
|
195
332
|
}
|
|
196
333
|
async cancel(options = {}) {
|
|
197
|
-
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 });
|
|
198
339
|
return this;
|
|
199
340
|
}
|
|
200
341
|
async delete(options = {}) {
|
|
201
|
-
await this.#transport.
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
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
|
+
};
|
|
205
347
|
}
|
|
206
348
|
markIdle() {
|
|
207
|
-
this.#data = { ...this.#data,
|
|
349
|
+
this.#data = { ...this.#data, turn_state: "idle" };
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
function isOutputOptions(options) {
|
|
353
|
+
return "output" in options;
|
|
354
|
+
}
|
|
355
|
+
async function compileOutputSchema(schema, retries) {
|
|
356
|
+
let jsonSchema;
|
|
357
|
+
try {
|
|
358
|
+
assertPortableOutputSchema(schema);
|
|
359
|
+
jsonSchema = z.toJSONSchema(schema, {
|
|
360
|
+
target: "draft-2020-12",
|
|
361
|
+
unrepresentable: "throw",
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
catch (cause) {
|
|
365
|
+
throw new OutputSchemaError(messageOf(cause, "The Zod schema cannot be represented as JSON Schema"), {
|
|
366
|
+
cause,
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
if (jsonSchema.type !== "object") {
|
|
370
|
+
throw new OutputSchemaError("session.send() output requires a Zod object schema");
|
|
208
371
|
}
|
|
372
|
+
assertSupportedJsonSchema(jsonSchema);
|
|
373
|
+
return { jsonSchema, schemaHash: await jcsSha256(jsonSchema), retries };
|
|
374
|
+
}
|
|
375
|
+
function assertSupportedJsonSchema(schema) {
|
|
376
|
+
const bytes = new TextEncoder().encode(canonicalize(schema));
|
|
377
|
+
if (bytes.byteLength > 64 * 1024) {
|
|
378
|
+
throw new OutputSchemaError("The output schema exceeds the 65536-byte service limit");
|
|
379
|
+
}
|
|
380
|
+
let nodes = 0;
|
|
381
|
+
const visit = (value, depth) => {
|
|
382
|
+
if (depth > 64)
|
|
383
|
+
throw new OutputSchemaError("The output schema exceeds the service depth limit");
|
|
384
|
+
nodes += 1;
|
|
385
|
+
if (nodes > 4096)
|
|
386
|
+
throw new OutputSchemaError("The output schema exceeds the service node limit");
|
|
387
|
+
if (Array.isArray(value)) {
|
|
388
|
+
for (const child of value)
|
|
389
|
+
visit(child, depth + 1);
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
if (value === null || typeof value !== "object")
|
|
393
|
+
return;
|
|
394
|
+
const object = value;
|
|
395
|
+
if ("pattern" in object || "patternProperties" in object) {
|
|
396
|
+
throw new OutputSchemaError("Regular-expression JSON Schema keywords are not supported for Aex structured output");
|
|
397
|
+
}
|
|
398
|
+
for (const keyword of ["$ref", "$dynamicRef", "$recursiveRef"]) {
|
|
399
|
+
const reference = object[keyword];
|
|
400
|
+
if (typeof reference === "string" && !reference.startsWith("#")) {
|
|
401
|
+
throw new OutputSchemaError("Remote JSON Schema references are not supported for Aex structured output");
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
for (const child of Object.values(object))
|
|
405
|
+
visit(child, depth + 1);
|
|
406
|
+
};
|
|
407
|
+
visit(schema, 0);
|
|
209
408
|
}
|
|
210
|
-
function
|
|
211
|
-
|
|
409
|
+
function outputIssues(error) {
|
|
410
|
+
const details = error.details;
|
|
411
|
+
if (details === undefined || details === null || typeof details !== "object")
|
|
412
|
+
return [];
|
|
413
|
+
const issues = details.issues;
|
|
414
|
+
if (!Array.isArray(issues))
|
|
415
|
+
return [];
|
|
416
|
+
return issues.flatMap((issue) => {
|
|
417
|
+
if (issue === null || typeof issue !== "object")
|
|
418
|
+
return [];
|
|
419
|
+
const value = issue;
|
|
420
|
+
if (typeof value.path !== "string" || typeof value.message !== "string")
|
|
421
|
+
return [];
|
|
422
|
+
return [{
|
|
423
|
+
path: value.path,
|
|
424
|
+
message: value.message,
|
|
425
|
+
...(typeof value.keyword === "string" ? { keyword: value.keyword } : {}),
|
|
426
|
+
}];
|
|
427
|
+
});
|
|
212
428
|
}
|
|
213
429
|
function jsonPointer(path) {
|
|
214
430
|
if (path.length === 0)
|
package/dist/tools.d.ts
ADDED
package/dist/tools.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { compileTools } from "@aexhq/brain";
|
package/dist/transport.d.ts
CHANGED
|
@@ -1,11 +1,6 @@
|
|
|
1
|
-
import type { Event } from "@aexhq/
|
|
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>;
|