@aexhq/sdk 0.62.1 → 0.63.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 +12 -51
- package/dist/index.d.ts +9 -16
- package/dist/index.js +12 -19
- package/dist/session.d.ts +16 -131
- package/dist/session.js +24 -640
- package/package.json +3 -8
- package/dist/errors.d.ts +0 -39
- package/dist/errors.js +0 -69
- package/dist/json.d.ts +0 -4
- package/dist/json.js +0 -46
- package/dist/resources.d.ts +0 -162
- package/dist/resources.js +0 -442
- package/dist/tools.d.ts +0 -48
- package/dist/tools.js +0 -119
- package/dist/transport.d.ts +0 -31
- package/dist/transport.js +0 -744
package/dist/resources.js
DELETED
|
@@ -1,442 +0,0 @@
|
|
|
1
|
-
import { MAX_INLINE_FILE_BYTES, SessionChildren as BrainChildren, SessionSandbox as BrainSandbox, SessionStorage as BrainStorage, } from "@aexhq/brain";
|
|
2
|
-
import { SessionError, abortError } from "./errors.js";
|
|
3
|
-
import { randomIdempotencyKey } from "./json.js";
|
|
4
|
-
export class SandboxFiles {
|
|
5
|
-
#inner;
|
|
6
|
-
#transport;
|
|
7
|
-
constructor(inner, transport) {
|
|
8
|
-
this.#inner = inner;
|
|
9
|
-
this.#transport = transport;
|
|
10
|
-
}
|
|
11
|
-
async list(path, options) {
|
|
12
|
-
const page = await this.#inner.list({
|
|
13
|
-
path,
|
|
14
|
-
generation: options.generation,
|
|
15
|
-
...(options.cursor === undefined ? {} : { cursor: options.cursor }),
|
|
16
|
-
...(options.limit === undefined ? {} : { limit: options.limit }),
|
|
17
|
-
}, request(options));
|
|
18
|
-
return filePage(page);
|
|
19
|
-
}
|
|
20
|
-
async stat(path, options) {
|
|
21
|
-
return file(await this.#inner.stat({ path, generation: options.generation }, request(options)));
|
|
22
|
-
}
|
|
23
|
-
async download(path, options) {
|
|
24
|
-
return collect(await this.downloadStream(path, options));
|
|
25
|
-
}
|
|
26
|
-
async downloadStream(path, options) {
|
|
27
|
-
const entry = await this.#inner.stat({ path, generation: options.generation }, request(options));
|
|
28
|
-
if (entry.bytes <= MAX_INLINE_FILE_BYTES) {
|
|
29
|
-
const result = await this.#inner.readInline({ path, generation: options.generation }, request(options));
|
|
30
|
-
return byteStream(decodeBase64(result.content_base64));
|
|
31
|
-
}
|
|
32
|
-
const ticket = await this.#inner.prepareDownload({ path, generation: options.generation }, request(options));
|
|
33
|
-
return this.#transport.downloadTransferStream(ticket, options.signal, entry.bytes);
|
|
34
|
-
}
|
|
35
|
-
async upload(path, source, options) {
|
|
36
|
-
const base = {
|
|
37
|
-
path,
|
|
38
|
-
generation: options.generation,
|
|
39
|
-
...(options.overwrite === undefined ? {} : { overwrite: options.overwrite }),
|
|
40
|
-
};
|
|
41
|
-
let entry;
|
|
42
|
-
if (isStreamingSource(source)) {
|
|
43
|
-
assertStreamingSource(source);
|
|
44
|
-
entry = source.bytes <= MAX_INLINE_FILE_BYTES
|
|
45
|
-
? await this.#inner.writeInline({ ...base, content_base64: encodeBase64(await collectDeclared(source, options.signal)) }, request(options))
|
|
46
|
-
: await this.#uploadStream(base, source, options);
|
|
47
|
-
}
|
|
48
|
-
else {
|
|
49
|
-
const content = await bytesOf(source);
|
|
50
|
-
entry = content.byteLength <= MAX_INLINE_FILE_BYTES
|
|
51
|
-
? await this.#inner.writeInline({ ...base, content_base64: encodeBase64(content) }, request(options))
|
|
52
|
-
: await this.#upload(base, content, options);
|
|
53
|
-
}
|
|
54
|
-
return file(entry);
|
|
55
|
-
}
|
|
56
|
-
async #upload(input, content, options) {
|
|
57
|
-
const ticket = await this.#inner.prepareUpload({ ...input, bytes: content.byteLength, sha256: await sha256(content) }, request(options));
|
|
58
|
-
await this.#transport.uploadTransfer(ticket, content, content.byteLength, options.signal);
|
|
59
|
-
// Direct sandbox transfers are intentionally happy-path only. Do not automatically replay an
|
|
60
|
-
// ambiguous import: surface the error so the caller can inspect the generation/path and
|
|
61
|
-
// prepare a fresh transfer. Durable storage completion has separate retry-safe semantics.
|
|
62
|
-
return this.#inner.completeUpload(ticket.transfer_id, request(options));
|
|
63
|
-
}
|
|
64
|
-
async #uploadStream(input, source, options) {
|
|
65
|
-
const ticket = await this.#inner.prepareUpload({ ...input, bytes: source.bytes, sha256: source.sha256 }, request(options));
|
|
66
|
-
await this.#transport.uploadTransfer(ticket, () => source.stream(), source.bytes, options.signal);
|
|
67
|
-
return this.#inner.completeUpload(ticket.transfer_id, request(options));
|
|
68
|
-
}
|
|
69
|
-
async find(input, options) {
|
|
70
|
-
const page = await this.#inner.find({
|
|
71
|
-
...input,
|
|
72
|
-
generation: options.generation,
|
|
73
|
-
...(options.cursor === undefined ? {} : { cursor: options.cursor }),
|
|
74
|
-
...(options.limit === undefined ? {} : { limit: options.limit }),
|
|
75
|
-
}, request(options));
|
|
76
|
-
return filePage(page);
|
|
77
|
-
}
|
|
78
|
-
async grep(input, options) {
|
|
79
|
-
const page = await this.#inner.grep({
|
|
80
|
-
...input,
|
|
81
|
-
generation: options.generation,
|
|
82
|
-
...(options.cursor === undefined ? {} : { cursor: options.cursor }),
|
|
83
|
-
...(options.limit === undefined ? {} : { limit: options.limit }),
|
|
84
|
-
}, request(options));
|
|
85
|
-
return filePage(page);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
export class SessionSandbox {
|
|
89
|
-
#inner;
|
|
90
|
-
files;
|
|
91
|
-
constructor(transport, sessionId, environment) {
|
|
92
|
-
this.#inner = new BrainSandbox(transport, sessionId, environment);
|
|
93
|
-
this.files = new SandboxFiles(this.#inner.files, transport);
|
|
94
|
-
}
|
|
95
|
-
/** The declared Environment name this sandbox addresses. */
|
|
96
|
-
get environment() {
|
|
97
|
-
return this.#inner.environment;
|
|
98
|
-
}
|
|
99
|
-
async status(options = {}) {
|
|
100
|
-
return sandboxStatus(await this.#inner.status(request(options)));
|
|
101
|
-
}
|
|
102
|
-
async create(options = {}) {
|
|
103
|
-
return sandboxStatus(await this.#inner.create(intrinsicRequest(options)));
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
export class SessionStorage {
|
|
107
|
-
#inner;
|
|
108
|
-
#transport;
|
|
109
|
-
constructor(transport, sessionId) {
|
|
110
|
-
this.#inner = new BrainStorage(transport, sessionId);
|
|
111
|
-
this.#transport = transport;
|
|
112
|
-
}
|
|
113
|
-
async list(options = {}) {
|
|
114
|
-
const page = await this.#inner.list({
|
|
115
|
-
...(options.prefix === undefined ? {} : { prefix: options.prefix }),
|
|
116
|
-
...(options.cursor === undefined ? {} : { cursor: options.cursor }),
|
|
117
|
-
...(options.limit === undefined ? {} : { limit: options.limit }),
|
|
118
|
-
}, request(options));
|
|
119
|
-
return {
|
|
120
|
-
data: page.data.map(storageObject),
|
|
121
|
-
hasMore: page.has_more,
|
|
122
|
-
...(page.next_cursor === undefined ? {} : { nextCursor: page.next_cursor }),
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
async stat(key, options = {}) {
|
|
126
|
-
return storageObject(await this.#inner.stat(key, request(options)));
|
|
127
|
-
}
|
|
128
|
-
async download(key, options = {}) {
|
|
129
|
-
return collect(await this.downloadStream(key, options));
|
|
130
|
-
}
|
|
131
|
-
async downloadStream(key, options = {}) {
|
|
132
|
-
const object = await this.#inner.stat(key, request(options));
|
|
133
|
-
if (object.bytes <= MAX_INLINE_FILE_BYTES) {
|
|
134
|
-
return byteStream(decodeBase64((await this.#inner.readInline(key, request(options))).content_base64));
|
|
135
|
-
}
|
|
136
|
-
const ticket = await this.#inner.prepareDownload(key, request(options));
|
|
137
|
-
return this.#transport.downloadTransferStream(ticket, options.signal, object.bytes);
|
|
138
|
-
}
|
|
139
|
-
async upload(key, source, options = {}) {
|
|
140
|
-
const base = {
|
|
141
|
-
key,
|
|
142
|
-
...(options.contentType === undefined ? {} : { content_type: options.contentType }),
|
|
143
|
-
...(options.overwrite === undefined ? {} : { overwrite: options.overwrite }),
|
|
144
|
-
};
|
|
145
|
-
if (isStreamingSource(source)) {
|
|
146
|
-
assertStreamingSource(source);
|
|
147
|
-
if (source.bytes <= MAX_INLINE_FILE_BYTES) {
|
|
148
|
-
return storageObject(await this.#inner.writeInline({ ...base, content_base64: encodeBase64(await collectDeclared(source, options.signal)) }, request(options)));
|
|
149
|
-
}
|
|
150
|
-
const ticket = await this.#inner.prepareUpload({ ...base, bytes: source.bytes, sha256: source.sha256 }, request(options));
|
|
151
|
-
await this.#transport.uploadTransfer(ticket, () => source.stream(), source.bytes, options.signal);
|
|
152
|
-
return storageObject(await this.#inner.completeUpload(ticket.transfer_id, intrinsicRequest(options)));
|
|
153
|
-
}
|
|
154
|
-
const content = await bytesOf(source);
|
|
155
|
-
if (content.byteLength <= MAX_INLINE_FILE_BYTES) {
|
|
156
|
-
return storageObject(await this.#inner.writeInline({ ...base, content_base64: encodeBase64(content) }, request(options)));
|
|
157
|
-
}
|
|
158
|
-
const ticket = await this.#inner.prepareUpload({ ...base, bytes: content.byteLength, sha256: await sha256(content) }, request(options));
|
|
159
|
-
await this.#transport.uploadTransfer(ticket, content, content.byteLength, options.signal);
|
|
160
|
-
return storageObject(await this.#inner.completeUpload(ticket.transfer_id, intrinsicRequest(options)));
|
|
161
|
-
}
|
|
162
|
-
delete(key, options = {}) {
|
|
163
|
-
return this.#inner.delete(key, request(options));
|
|
164
|
-
}
|
|
165
|
-
async copyFromSandbox(input, options = {}) {
|
|
166
|
-
return storageObject(await this.#inner.copyFromEnvironment(input.environment, {
|
|
167
|
-
key: input.key,
|
|
168
|
-
path: input.path,
|
|
169
|
-
environment_generation: input.sandboxGeneration,
|
|
170
|
-
...(input.overwrite === undefined ? {} : { overwrite: input.overwrite }),
|
|
171
|
-
}, request(options)));
|
|
172
|
-
}
|
|
173
|
-
async copyToSandbox(input, options = {}) {
|
|
174
|
-
return file(await this.#inner.copyToEnvironment(input.environment, {
|
|
175
|
-
key: input.key,
|
|
176
|
-
path: input.path,
|
|
177
|
-
environment_generation: input.sandboxGeneration,
|
|
178
|
-
...(input.overwrite === undefined ? {} : { overwrite: input.overwrite }),
|
|
179
|
-
}, request(options)));
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
export class SessionChild {
|
|
183
|
-
#inner;
|
|
184
|
-
constructor(inner) {
|
|
185
|
-
this.#inner = inner;
|
|
186
|
-
}
|
|
187
|
-
get id() {
|
|
188
|
-
return this.#inner.id;
|
|
189
|
-
}
|
|
190
|
-
async info(options = {}) {
|
|
191
|
-
return child(await this.#inner.get(request(options)));
|
|
192
|
-
}
|
|
193
|
-
async send(message, options = {}) {
|
|
194
|
-
await this.#inner.send(message, idempotentRequest(options));
|
|
195
|
-
}
|
|
196
|
-
async followUp(message, options = {}) {
|
|
197
|
-
return child(await this.#inner.followUp(message, idempotentRequest(options)));
|
|
198
|
-
}
|
|
199
|
-
async wait(options = {}) {
|
|
200
|
-
return child(await this.#inner.wait(options.timeoutMs === undefined ? {} : { timeout_ms: options.timeoutMs }, request(options)));
|
|
201
|
-
}
|
|
202
|
-
async interrupt(options = {}) {
|
|
203
|
-
return child(await this.#inner.interrupt(intrinsicRequest(options)));
|
|
204
|
-
}
|
|
205
|
-
async end(options = {}) {
|
|
206
|
-
return child(await this.#inner.end(intrinsicRequest(options)));
|
|
207
|
-
}
|
|
208
|
-
events(options = {}) {
|
|
209
|
-
return this.#inner.events(options);
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
export class SessionChildren {
|
|
213
|
-
#inner;
|
|
214
|
-
constructor(transport, sessionId) {
|
|
215
|
-
this.#inner = new BrainChildren(transport, sessionId);
|
|
216
|
-
}
|
|
217
|
-
async create(input, options = {}) {
|
|
218
|
-
const handle = await this.#inner.create({
|
|
219
|
-
prompt: input.prompt,
|
|
220
|
-
...(input.name === undefined ? {} : { name: input.name }),
|
|
221
|
-
...(input.forkTurns === undefined ? {} : { fork_turns: input.forkTurns }),
|
|
222
|
-
}, idempotentRequest(options));
|
|
223
|
-
return new SessionChild(handle);
|
|
224
|
-
}
|
|
225
|
-
async list(options = {}) {
|
|
226
|
-
const page = await this.#inner.list({
|
|
227
|
-
...(options.cursor === undefined ? {} : { cursor: options.cursor }),
|
|
228
|
-
...(options.limit === undefined ? {} : { limit: options.limit }),
|
|
229
|
-
}, request(options));
|
|
230
|
-
return {
|
|
231
|
-
data: page.data.map(child),
|
|
232
|
-
hasMore: page.has_more,
|
|
233
|
-
...(page.next_cursor === undefined ? {} : { nextCursor: page.next_cursor }),
|
|
234
|
-
};
|
|
235
|
-
}
|
|
236
|
-
get(childId) {
|
|
237
|
-
return new SessionChild(this.#inner.get(childId));
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
function request(options) {
|
|
241
|
-
return options.signal === undefined ? {} : { signal: options.signal };
|
|
242
|
-
}
|
|
243
|
-
function intrinsicRequest(options) {
|
|
244
|
-
return {
|
|
245
|
-
...(options.signal === undefined ? {} : { signal: options.signal }),
|
|
246
|
-
retry: true,
|
|
247
|
-
};
|
|
248
|
-
}
|
|
249
|
-
function idempotentRequest(options) {
|
|
250
|
-
return {
|
|
251
|
-
...(options.signal === undefined ? {} : { signal: options.signal }),
|
|
252
|
-
headers: { "Idempotency-Key": options.idempotencyKey ?? randomIdempotencyKey() },
|
|
253
|
-
retry: true,
|
|
254
|
-
};
|
|
255
|
-
}
|
|
256
|
-
function sandboxStatus(value) {
|
|
257
|
-
return {
|
|
258
|
-
state: value.state,
|
|
259
|
-
...(value.generation == null ? {} : { generation: value.generation }),
|
|
260
|
-
...(value.reason == null ? {} : { reason: value.reason }),
|
|
261
|
-
...(value.changed_at_ms == null ? {} : { changedAt: timestamp(value.changed_at_ms) }),
|
|
262
|
-
...(value.expires_at_ms == null ? {} : { expiresAt: timestamp(value.expires_at_ms) }),
|
|
263
|
-
};
|
|
264
|
-
}
|
|
265
|
-
function file(value) {
|
|
266
|
-
return {
|
|
267
|
-
path: value.path,
|
|
268
|
-
kind: value.kind,
|
|
269
|
-
bytes: value.bytes,
|
|
270
|
-
...(value.sha256 == null ? {} : { sha256: value.sha256 }),
|
|
271
|
-
modifiedAt: timestamp(value.modified_at_ms),
|
|
272
|
-
};
|
|
273
|
-
}
|
|
274
|
-
function filePage(value) {
|
|
275
|
-
return {
|
|
276
|
-
data: value.data.map(file),
|
|
277
|
-
hasMore: value.has_more,
|
|
278
|
-
...(value.next_cursor === undefined ? {} : { nextCursor: value.next_cursor }),
|
|
279
|
-
generation: value.generation,
|
|
280
|
-
};
|
|
281
|
-
}
|
|
282
|
-
function storageObject(value) {
|
|
283
|
-
return {
|
|
284
|
-
key: value.key,
|
|
285
|
-
bytes: value.bytes,
|
|
286
|
-
sha256: value.sha256,
|
|
287
|
-
...(value.content_type === undefined ? {} : { contentType: value.content_type }),
|
|
288
|
-
createdAt: value.created_at,
|
|
289
|
-
updatedAt: value.updated_at,
|
|
290
|
-
};
|
|
291
|
-
}
|
|
292
|
-
function child(value) {
|
|
293
|
-
if (value.parent_id === undefined) {
|
|
294
|
-
throw new SessionError(`Aex returned root session ${value.id} from a direct-child resource`);
|
|
295
|
-
}
|
|
296
|
-
return {
|
|
297
|
-
id: value.id,
|
|
298
|
-
parentId: value.parent_id,
|
|
299
|
-
rootId: value.root_id,
|
|
300
|
-
...(value.name === undefined ? {} : { name: value.name }),
|
|
301
|
-
depth: value.depth,
|
|
302
|
-
state: value.state,
|
|
303
|
-
turnState: value.turn_state,
|
|
304
|
-
...(value.turn_phase === undefined ? {} : { turnPhase: value.turn_phase }),
|
|
305
|
-
shape: value.shape,
|
|
306
|
-
createdAt: value.created_at,
|
|
307
|
-
updatedAt: value.updated_at,
|
|
308
|
-
};
|
|
309
|
-
}
|
|
310
|
-
function timestamp(value) {
|
|
311
|
-
if (!Number.isSafeInteger(value) || value < 0) {
|
|
312
|
-
throw new SessionError("Aex returned an invalid sandbox timestamp");
|
|
313
|
-
}
|
|
314
|
-
try {
|
|
315
|
-
return new Date(value).toISOString();
|
|
316
|
-
}
|
|
317
|
-
catch (cause) {
|
|
318
|
-
throw new SessionError("Aex returned an invalid sandbox timestamp", { cause });
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
async function bytesOf(source) {
|
|
322
|
-
if (typeof source === "string")
|
|
323
|
-
return new TextEncoder().encode(source);
|
|
324
|
-
if (source instanceof ArrayBuffer)
|
|
325
|
-
return new Uint8Array(source);
|
|
326
|
-
if (typeof Blob !== "undefined" && source instanceof Blob) {
|
|
327
|
-
return new Uint8Array(await source.arrayBuffer());
|
|
328
|
-
}
|
|
329
|
-
if (ArrayBuffer.isView(source)) {
|
|
330
|
-
return new Uint8Array(source.buffer, source.byteOffset, source.byteLength);
|
|
331
|
-
}
|
|
332
|
-
throw new TypeError("Unsupported binary source");
|
|
333
|
-
}
|
|
334
|
-
function isStreamingSource(source) {
|
|
335
|
-
return typeof source === "object" && source !== null && "stream" in source &&
|
|
336
|
-
"bytes" in source && "sha256" in source && !(typeof Blob !== "undefined" && source instanceof Blob);
|
|
337
|
-
}
|
|
338
|
-
function assertStreamingSource(source) {
|
|
339
|
-
if (!Number.isSafeInteger(source.bytes) || source.bytes < 0) {
|
|
340
|
-
throw new TypeError("Streaming upload bytes must be a non-negative safe integer");
|
|
341
|
-
}
|
|
342
|
-
if (!/^[0-9a-f]{64}$/u.test(source.sha256)) {
|
|
343
|
-
throw new TypeError("Streaming upload sha256 must be 64 lowercase hexadecimal characters");
|
|
344
|
-
}
|
|
345
|
-
if (typeof source.stream !== "function") {
|
|
346
|
-
throw new TypeError("Streaming upload source must provide stream()");
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
function byteStream(bytes) {
|
|
350
|
-
return new ReadableStream({
|
|
351
|
-
start(controller) {
|
|
352
|
-
if (bytes.byteLength !== 0)
|
|
353
|
-
controller.enqueue(bytes);
|
|
354
|
-
controller.close();
|
|
355
|
-
},
|
|
356
|
-
});
|
|
357
|
-
}
|
|
358
|
-
async function collect(stream) {
|
|
359
|
-
const chunks = [];
|
|
360
|
-
let bytes = 0;
|
|
361
|
-
const reader = stream.getReader();
|
|
362
|
-
try {
|
|
363
|
-
while (true) {
|
|
364
|
-
const item = await reader.read();
|
|
365
|
-
if (item.done)
|
|
366
|
-
break;
|
|
367
|
-
chunks.push(item.value);
|
|
368
|
-
bytes += item.value.byteLength;
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
finally {
|
|
372
|
-
reader.releaseLock();
|
|
373
|
-
}
|
|
374
|
-
const result = new Uint8Array(bytes);
|
|
375
|
-
let offset = 0;
|
|
376
|
-
for (const chunk of chunks) {
|
|
377
|
-
result.set(chunk, offset);
|
|
378
|
-
offset += chunk.byteLength;
|
|
379
|
-
}
|
|
380
|
-
return result;
|
|
381
|
-
}
|
|
382
|
-
async function collectDeclared(source, signal) {
|
|
383
|
-
if (signal?.aborted === true)
|
|
384
|
-
throw abortError(signal.reason);
|
|
385
|
-
const reader = source.stream().getReader();
|
|
386
|
-
const result = new Uint8Array(source.bytes);
|
|
387
|
-
let offset = 0;
|
|
388
|
-
let aborted = false;
|
|
389
|
-
const abort = () => {
|
|
390
|
-
aborted = true;
|
|
391
|
-
void reader.cancel(signal?.reason).catch(() => undefined);
|
|
392
|
-
};
|
|
393
|
-
signal?.addEventListener("abort", abort, { once: true });
|
|
394
|
-
try {
|
|
395
|
-
while (true) {
|
|
396
|
-
const item = await reader.read();
|
|
397
|
-
if (aborted)
|
|
398
|
-
throw abortError(signal?.reason);
|
|
399
|
-
if (item.done)
|
|
400
|
-
break;
|
|
401
|
-
if (!(item.value instanceof Uint8Array) || offset + item.value.byteLength > result.byteLength) {
|
|
402
|
-
throw new TypeError("Streaming upload exceeded its declared byte length");
|
|
403
|
-
}
|
|
404
|
-
result.set(item.value, offset);
|
|
405
|
-
offset += item.value.byteLength;
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
finally {
|
|
409
|
-
signal?.removeEventListener("abort", abort);
|
|
410
|
-
reader.releaseLock();
|
|
411
|
-
}
|
|
412
|
-
if (offset !== result.byteLength) {
|
|
413
|
-
throw new TypeError(`Streaming upload produced ${offset} bytes; expected ${result.byteLength}`);
|
|
414
|
-
}
|
|
415
|
-
if (await sha256(result) !== source.sha256) {
|
|
416
|
-
throw new TypeError("Streaming upload content does not match its declared sha256");
|
|
417
|
-
}
|
|
418
|
-
return result;
|
|
419
|
-
}
|
|
420
|
-
export function encodeBase64(bytes) {
|
|
421
|
-
let binary = "";
|
|
422
|
-
for (let offset = 0; offset < bytes.byteLength; offset += 32_768) {
|
|
423
|
-
binary += String.fromCharCode(...bytes.subarray(offset, offset + 32_768));
|
|
424
|
-
}
|
|
425
|
-
return btoa(binary);
|
|
426
|
-
}
|
|
427
|
-
function decodeBase64(value) {
|
|
428
|
-
const binary = atob(value);
|
|
429
|
-
const bytes = new Uint8Array(binary.length);
|
|
430
|
-
for (let index = 0; index < binary.length; index += 1)
|
|
431
|
-
bytes[index] = binary.charCodeAt(index);
|
|
432
|
-
return bytes;
|
|
433
|
-
}
|
|
434
|
-
async function sha256(value) {
|
|
435
|
-
const input = value.buffer instanceof ArrayBuffer
|
|
436
|
-
? value
|
|
437
|
-
: Uint8Array.from(value);
|
|
438
|
-
const digest = await crypto.subtle.digest("SHA-256", input);
|
|
439
|
-
return [...new Uint8Array(digest)]
|
|
440
|
-
.map((byte) => byte.toString(16).padStart(2, "0"))
|
|
441
|
-
.join("");
|
|
442
|
-
}
|
package/dist/tools.d.ts
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import type { ComponentExtension } from "@aexhq/brain";
|
|
2
|
-
import type { ToolDefinition } from "@aexhq/brain/session";
|
|
3
|
-
import * as z from "zod";
|
|
4
|
-
export type JsonSchema = Record<string, unknown>;
|
|
5
|
-
export interface ToolContext {
|
|
6
|
-
readonly signal: AbortSignal;
|
|
7
|
-
readonly operationId: string;
|
|
8
|
-
readonly sessionId: string;
|
|
9
|
-
readonly deadlineMs: number;
|
|
10
|
-
}
|
|
11
|
-
export type ToolHandler<Input extends z.ZodType, Output = unknown> = (input: z.output<Input>, context: ToolContext) => Output | Promise<Output>;
|
|
12
|
-
export interface ToolContract {
|
|
13
|
-
readonly name: string;
|
|
14
|
-
readonly description?: string;
|
|
15
|
-
readonly inputSchema: JsonSchema;
|
|
16
|
-
readonly outputSchema?: JsonSchema;
|
|
17
|
-
readonly contractDigest: string;
|
|
18
|
-
}
|
|
19
|
-
export interface Tool<Input extends z.ZodType = z.ZodType, Output = unknown> {
|
|
20
|
-
readonly kind: "aex.tool";
|
|
21
|
-
readonly name?: string;
|
|
22
|
-
readonly description?: string;
|
|
23
|
-
readonly input: Input;
|
|
24
|
-
readonly output?: z.ZodType;
|
|
25
|
-
readonly handler: ToolHandler<Input, Output>;
|
|
26
|
-
describe(description: string): Tool<Input, Output>;
|
|
27
|
-
named(name: string): Tool<Input, Output>;
|
|
28
|
-
returns<Schema extends z.ZodType>(schema: Schema): Tool<Input, z.output<Schema>>;
|
|
29
|
-
}
|
|
30
|
-
declare const EMPTY_INPUT: z.ZodObject<{}, z.core.$strip>;
|
|
31
|
-
export declare function tool<Output>(handler: ToolHandler<typeof EMPTY_INPUT, Output>): Tool<typeof EMPTY_INPUT, Output>;
|
|
32
|
-
export declare function tool<Input extends z.ZodType, Output>(input: Input, handler: ToolHandler<Input, Output>): Tool<Input, Output>;
|
|
33
|
-
export interface ClientRegistration {
|
|
34
|
-
readonly registration: string;
|
|
35
|
-
readonly name: string;
|
|
36
|
-
readonly contractDigest: string;
|
|
37
|
-
readonly input: z.ZodType;
|
|
38
|
-
readonly output?: z.ZodType;
|
|
39
|
-
readonly handler: ToolHandler<z.ZodType>;
|
|
40
|
-
}
|
|
41
|
-
export interface CompiledCallbacks {
|
|
42
|
-
readonly components: readonly ComponentExtension<"tool", Readonly<Record<string, unknown>> & {
|
|
43
|
-
readonly definition: ToolDefinition;
|
|
44
|
-
}>[];
|
|
45
|
-
readonly registrations: readonly ClientRegistration[];
|
|
46
|
-
}
|
|
47
|
-
export declare function compileCallbacks(selections: readonly Tool[]): Promise<CompiledCallbacks>;
|
|
48
|
-
export {};
|
package/dist/tools.js
DELETED
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
import { callback as callbackComponent } from "@aexhq/env-app";
|
|
2
|
-
import * as z from "zod";
|
|
3
|
-
import { jcsSha256 } from "./json.js";
|
|
4
|
-
const EMPTY_INPUT = z.object({});
|
|
5
|
-
const TOOL_NAME = /^[A-Za-z_][A-Za-z0-9_-]{0,63}$/u;
|
|
6
|
-
export function tool(inputOrHandler, maybeHandler) {
|
|
7
|
-
if (typeof inputOrHandler === "function") {
|
|
8
|
-
return makeTool({
|
|
9
|
-
...(inputOrHandler.name === "" ? {} : { name: inputOrHandler.name }),
|
|
10
|
-
input: EMPTY_INPUT,
|
|
11
|
-
handler: inputOrHandler,
|
|
12
|
-
});
|
|
13
|
-
}
|
|
14
|
-
if (typeof maybeHandler !== "function")
|
|
15
|
-
throw new TypeError("tool(schema, handler) requires a function");
|
|
16
|
-
return makeTool({
|
|
17
|
-
...(maybeHandler.name === "" ? {} : { name: maybeHandler.name }),
|
|
18
|
-
input: inputOrHandler,
|
|
19
|
-
handler: maybeHandler,
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
function makeTool(draft) {
|
|
23
|
-
return Object.freeze({
|
|
24
|
-
kind: "aex.tool",
|
|
25
|
-
...(draft.name === undefined ? {} : { name: draft.name }),
|
|
26
|
-
...(draft.description === undefined ? {} : { description: draft.description }),
|
|
27
|
-
input: draft.input,
|
|
28
|
-
...(draft.output === undefined ? {} : { output: draft.output }),
|
|
29
|
-
handler: draft.handler,
|
|
30
|
-
describe(description) {
|
|
31
|
-
if (description.trim() === "" || description.length > 4096) {
|
|
32
|
-
throw new TypeError("Tool description must contain 1 through 4096 characters");
|
|
33
|
-
}
|
|
34
|
-
return makeTool({ ...draft, description });
|
|
35
|
-
},
|
|
36
|
-
named(name) {
|
|
37
|
-
assertToolName(name);
|
|
38
|
-
return makeTool({ ...draft, name });
|
|
39
|
-
},
|
|
40
|
-
returns(output) {
|
|
41
|
-
schemaOf(output, `${draft.name ?? "Tool"} output`);
|
|
42
|
-
return makeTool({ ...draft, output });
|
|
43
|
-
},
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
export async function compileCallbacks(selections) {
|
|
47
|
-
const components = [];
|
|
48
|
-
const registrations = [];
|
|
49
|
-
const names = new Set();
|
|
50
|
-
for (const value of selections) {
|
|
51
|
-
assertTool(value);
|
|
52
|
-
const contract = await compileContract(value);
|
|
53
|
-
if (names.has(contract.name)) {
|
|
54
|
-
throw new TypeError(`Tool ${JSON.stringify(contract.name)} was selected twice`);
|
|
55
|
-
}
|
|
56
|
-
names.add(contract.name);
|
|
57
|
-
const definition = {
|
|
58
|
-
name: contract.name,
|
|
59
|
-
...(contract.description === undefined ? {} : { description: contract.description }),
|
|
60
|
-
input_schema: contract.inputSchema,
|
|
61
|
-
output_schema: contract.outputSchema ?? {},
|
|
62
|
-
contract_digest: contract.contractDigest,
|
|
63
|
-
};
|
|
64
|
-
const registration = `tool:${contract.contractDigest}`;
|
|
65
|
-
components.push(callbackComponent(definition, registration));
|
|
66
|
-
registrations.push(Object.freeze({
|
|
67
|
-
registration,
|
|
68
|
-
name: contract.name,
|
|
69
|
-
contractDigest: contract.contractDigest,
|
|
70
|
-
input: value.input,
|
|
71
|
-
...(value.output === undefined ? {} : { output: value.output }),
|
|
72
|
-
handler: value.handler,
|
|
73
|
-
}));
|
|
74
|
-
}
|
|
75
|
-
return {
|
|
76
|
-
components: Object.freeze(components),
|
|
77
|
-
registrations: Object.freeze(registrations),
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
async function compileContract(value) {
|
|
81
|
-
const name = value.name;
|
|
82
|
-
if (name === undefined)
|
|
83
|
-
throw new TypeError("Tool functions must be named; use .named(name) when build tooling removes the name");
|
|
84
|
-
assertToolName(name);
|
|
85
|
-
const inputSchema = schemaOf(value.input, `${name} input`);
|
|
86
|
-
const outputSchema = value.output === undefined ? undefined : schemaOf(value.output, `${name} output`);
|
|
87
|
-
const canonical = {
|
|
88
|
-
name,
|
|
89
|
-
...(value.description === undefined ? {} : { description: value.description }),
|
|
90
|
-
input_schema: inputSchema,
|
|
91
|
-
...(outputSchema === undefined ? {} : { output_schema: outputSchema }),
|
|
92
|
-
};
|
|
93
|
-
return {
|
|
94
|
-
name,
|
|
95
|
-
...(value.description === undefined ? {} : { description: value.description }),
|
|
96
|
-
inputSchema,
|
|
97
|
-
...(outputSchema === undefined ? {} : { outputSchema }),
|
|
98
|
-
contractDigest: await jcsSha256(canonical),
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
function schemaOf(schema, label) {
|
|
102
|
-
try {
|
|
103
|
-
const value = z.toJSONSchema(schema, { target: "draft-2020-12", unrepresentable: "throw" });
|
|
104
|
-
if (Object.keys(value).length === 0)
|
|
105
|
-
throw new TypeError(`${label} schema is empty`);
|
|
106
|
-
return value;
|
|
107
|
-
}
|
|
108
|
-
catch (cause) {
|
|
109
|
-
throw new TypeError(`${label} cannot be represented as JSON Schema`, { cause });
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
function assertTool(value) {
|
|
113
|
-
if (value?.kind !== "aex.tool")
|
|
114
|
-
throw new TypeError("Tool selection is invalid");
|
|
115
|
-
}
|
|
116
|
-
function assertToolName(name) {
|
|
117
|
-
if (!TOOL_NAME.test(name))
|
|
118
|
-
throw new TypeError(`Invalid Tool name ${JSON.stringify(name)}`);
|
|
119
|
-
}
|
package/dist/transport.d.ts
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import type { Event } from "@aexhq/brain/session";
|
|
2
|
-
import type { JsonRequestOptions, TransferTicket } from "@aexhq/brain";
|
|
3
|
-
export type Fetch = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
|
|
4
|
-
export interface EventOptions {
|
|
5
|
-
after?: number;
|
|
6
|
-
follow?: boolean;
|
|
7
|
-
signal?: AbortSignal | undefined;
|
|
8
|
-
}
|
|
9
|
-
export declare class Transport {
|
|
10
|
-
#private;
|
|
11
|
-
readonly baseUrl: string;
|
|
12
|
-
constructor(apiKey: string, baseUrl: string, fetchImplementation: Fetch);
|
|
13
|
-
customerEnvironmentGrant(clientId: string, signal?: AbortSignal): Promise<{
|
|
14
|
-
url: string;
|
|
15
|
-
protocol: string;
|
|
16
|
-
expiresAt: string;
|
|
17
|
-
observationUrl: string;
|
|
18
|
-
observationToken: string;
|
|
19
|
-
}>;
|
|
20
|
-
customerEnvironmentObserve(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>;
|
|
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>;
|
|
27
|
-
events(sessionId: string, options?: EventOptions): AsyncGenerator<Event>;
|
|
28
|
-
private responseError;
|
|
29
|
-
}
|
|
30
|
-
/** @internal Incremental, constant-space decoder for Brain's bounded public SSE events. */
|
|
31
|
-
export declare function parseEventStream(stream: ReadableStream<Uint8Array>): AsyncGenerator<Event>;
|