@aexhq/sdk 0.57.4 → 0.58.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 +43 -88
- package/dist/errors.d.ts +1 -1
- package/dist/index.d.ts +8 -10
- package/dist/index.js +3 -7
- package/dist/internal.d.ts +2 -0
- package/dist/internal.js +1 -0
- package/dist/resources.d.ts +13 -55
- package/dist/resources.js +18 -125
- package/dist/session.d.ts +28 -18
- package/dist/session.js +64 -47
- package/dist/tools.d.ts +100 -2
- package/dist/tools.js +424 -1
- package/dist/transport.d.ts +5 -4
- package/dist/transport.js +44 -12
- package/package.json +7 -2
package/README.md
CHANGED
|
@@ -1,105 +1,60 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @aexhq/sdk
|
|
2
2
|
|
|
3
|
-
TypeScript
|
|
3
|
+
TypeScript SDK for Aex sessions and tool extensions.
|
|
4
4
|
|
|
5
5
|
```ts
|
|
6
|
-
import { Aex
|
|
7
|
-
import {
|
|
6
|
+
import { Aex } from "@aexhq/sdk";
|
|
7
|
+
import { awsMicrovm } from "@aexhq/env-aws-microvm";
|
|
8
|
+
import { pi } from "@aexhq/loop-pi";
|
|
9
|
+
import { bash, read, write } from "@aexhq/tools";
|
|
8
10
|
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
async function lookup({ id }) {
|
|
12
|
-
return database.customers.find(id);
|
|
13
|
-
},
|
|
14
|
-
).client();
|
|
11
|
+
const aex = new Aex({ apiKey: process.env.AEX_API_KEY! });
|
|
12
|
+
const workspace = awsMicrovm();
|
|
15
13
|
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
const session = await aex.sessions.create({
|
|
15
|
+
model: {
|
|
16
|
+
provider: "openai",
|
|
17
|
+
name: "gpt-5.4",
|
|
18
|
+
apiKey: process.env.OPENAI_API_KEY!,
|
|
19
|
+
},
|
|
20
|
+
loop: pi({ instructions: "Work carefully and verify changes." }),
|
|
21
|
+
environments: { workspace },
|
|
22
|
+
tools: [bash(), read(), write()],
|
|
19
23
|
});
|
|
20
|
-
const model = {
|
|
21
|
-
provider: "openai" as const,
|
|
22
|
-
name: "gpt-5.4",
|
|
23
|
-
apiKey: process.env.OPENAI_API_KEY!,
|
|
24
|
-
};
|
|
25
|
-
const session = await aex.sessions.create({ model, tools: [lookup] });
|
|
26
24
|
|
|
27
|
-
|
|
28
|
-
output: z.object({ answer: z.string() }),
|
|
29
|
-
});
|
|
25
|
+
console.log(await session.send("Inspect the workspace."));
|
|
30
26
|
```
|
|
31
27
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
level `session.events()` stream is raw and attempt-aware: provisional frames have no durable cursor
|
|
36
|
-
and can later be superseded, so live renderers must key them by `attempt_id` and process
|
|
37
|
-
`model.attempt_superseded` instead of concatenating attempts.
|
|
38
|
-
The SDK always generates and reuses an `Idempotency-Key` for root/child creation and messages; pass
|
|
39
|
-
`idempotencyKey` explicitly when the application must recover the same operation across its own
|
|
40
|
-
process restart. Raw hosted REST calls must supply that header for those operations.
|
|
28
|
+
There is no default loop or environment. Every tool is bound to one declared environment before
|
|
29
|
+
the request is sent. An unbound tool is bound automatically only when exactly one declared
|
|
30
|
+
environment satisfies it; otherwise creation fails with the eligible or missing capabilities.
|
|
41
31
|
|
|
42
|
-
|
|
43
|
-
selector. Child sessions and managed sandboxes inherit the root's physical seal.
|
|
32
|
+
## Tools
|
|
44
33
|
|
|
45
|
-
|
|
46
|
-
`.server(import.meta.url)` bundles a module whose default export is the completed Tool value for the
|
|
47
|
-
session's shared managed computer. One customer-app socket is shared across sessions; call
|
|
48
|
-
`aex.close()` during graceful process shutdown to stop it and interrupt process-local work. A
|
|
49
|
-
closed `Aex` instance cannot create another session. The
|
|
50
|
-
default `.client()` registration
|
|
51
|
-
is derived from its contract. If one application intentionally has different closures with the
|
|
52
|
-
same name and schemas, give each a stable `.client({ registration: "..." })`; a live runner rejects
|
|
53
|
-
a registration collision instead of invoking the wrong closure. Sessions grant no execution
|
|
54
|
-
capabilities by default. Add only the official capabilities needed. Aex's reserved output protocol is
|
|
55
|
-
present but inert unless a particular `send({ output })` request arms it:
|
|
56
|
-
|
|
57
|
-
Hosted `.server()` bindings use distinct generation-lifetime unprivileged users, separate from the
|
|
58
|
-
ordinary shell, while sharing the workspace through a group. Declared environment secrets are not
|
|
59
|
-
written by Aex to the workspace, arguments, results, or logs. This blocks ordinary sibling reads,
|
|
60
|
-
not guest-root compromise or a Tool deliberately writing the value. Use `.client()` or an external
|
|
61
|
-
service for that stronger boundary; local mode is intentionally unsandboxed.
|
|
34
|
+
`tool()` creates an immutable tool extension from a Zod input schema and a handler:
|
|
62
35
|
|
|
63
36
|
```ts
|
|
64
|
-
import {
|
|
65
|
-
|
|
66
|
-
const session = await aex.sessions.create({
|
|
67
|
-
model,
|
|
68
|
-
tools: [bash(), read(), write(), edit(), storage(), sandbox(), subagents()],
|
|
69
|
-
network: { outbound: "none" },
|
|
70
|
-
});
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
Omitting `tools` and passing `tools: []` are equivalent. Zod schemas must be representable as JSON
|
|
74
|
-
Schema; process-local refinements and transforms fail before model work starts. Temporary files are
|
|
75
|
-
available through `session.sandbox.files`; durable objects use `session.storage`. Large transfers
|
|
76
|
-
automatically bypass the Brain actor. Durable direct children use `session.children`.
|
|
77
|
-
Sandbox file operations honor guest permissions; they do not bypass a `.server()` binding's
|
|
78
|
-
deliberate mode-0600 files. The binding must explicitly export or relax those permissions.
|
|
79
|
-
|
|
80
|
-
Buffered `upload()` and `download()` are convenient for small objects. Large transfers can stay
|
|
81
|
-
O(1)-heap with `downloadStream()` and a replayable declared source:
|
|
82
|
-
|
|
83
|
-
```ts
|
|
84
|
-
import { createReadStream } from "node:fs";
|
|
85
|
-
import { Readable } from "node:stream";
|
|
37
|
+
import { tool } from "@aexhq/sdk";
|
|
38
|
+
import { z } from "zod";
|
|
86
39
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
|
|
40
|
+
export default tool(
|
|
41
|
+
z.object({ orderId: z.string() }),
|
|
42
|
+
async function lookupOrder({ orderId }) {
|
|
43
|
+
return database.lookup(orderId);
|
|
44
|
+
},
|
|
45
|
+
)
|
|
46
|
+
.describe("Look up an order")
|
|
47
|
+
.returns(z.object({ status: z.string() }))
|
|
48
|
+
.needs({ env: ["ORDERS_TOKEN"], network: [{ host: "orders.example.com", port: 443 }] })
|
|
49
|
+
.setup(async function prepareIndex() {
|
|
50
|
+
await database.prepareIndex();
|
|
51
|
+
});
|
|
93
52
|
```
|
|
94
53
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
retry an ambiguous completion or recover a ticket after Brain restart or expiry. Inspect the
|
|
99
|
-
generation and path, then prepare a fresh transfer. Put bytes in `session.storage` and copy them to
|
|
100
|
-
or from the sandbox when the transfer itself must be recovery-safe.
|
|
54
|
+
Use `tool.bind(environmentRef)` when more than one environment is compatible. Source tools run
|
|
55
|
+
through an `app()` callback environment. `aex tools build` prepares computer tools with their
|
|
56
|
+
runtime and dependencies; tool authors do not pass `import.meta.url` or choose a provider.
|
|
101
57
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
open while sandbox and storage cleanup runs.
|
|
58
|
+
Environment references are opaque values returned by environment-extension factories. A created
|
|
59
|
+
session preserves their types, so `session.environment(ref)` returns that extension's typed handle.
|
|
60
|
+
Durable objects remain available through `session.storage`, independently of environment lifetime.
|
package/dist/errors.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ApiError, ApiErrorCode } from "@aexhq/
|
|
1
|
+
import type { ApiError, ApiErrorCode } from "@aexhq/session-protocol/session";
|
|
2
2
|
/** One Aex trusted-output validation failure, expressed as a JSON Pointer. */
|
|
3
3
|
export interface OutputValidationIssue {
|
|
4
4
|
path: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,24 +1,22 @@
|
|
|
1
1
|
import { Sessions } from "./session.js";
|
|
2
2
|
import type { Fetch } from "./transport.js";
|
|
3
|
-
import type { WebSocketFactory } from "@aexhq/
|
|
3
|
+
import type { WebSocketFactory } from "@aexhq/session-protocol";
|
|
4
4
|
export { AbortError, AexError, OutputRefusalError, OutputSchemaError, OutputValidationError, SessionError, } from "./errors.js";
|
|
5
5
|
export type { AexErrorOptions, OutputValidationIssue } from "./errors.js";
|
|
6
6
|
export { Session, Sessions, } from "./session.js";
|
|
7
|
-
export type { CreateSessionOptions, ListSessionsOptions, ModelSummary, ModelOptions, OutputOptions, RequestOptions, SessionInput, SessionList, SessionSummary, } from "./session.js";
|
|
8
|
-
export {
|
|
9
|
-
export type { BinarySource, ChildSummary, IdempotentOperationOptions, OperationOptions, PageOptions,
|
|
7
|
+
export type { CreateSessionOptions, ListSessionsOptions, Loop, ModelSummary, ModelOptions, OutputOptions, RequestOptions, SessionInput, SessionList, SessionSummary, } from "./session.js";
|
|
8
|
+
export { SessionChild, SessionChildren, SessionStorage, } from "./resources.js";
|
|
9
|
+
export type { BinarySource, ChildSummary, EnvironmentFile, IdempotentOperationOptions, OperationOptions, PageOptions, StorageObject, StoragePage, StreamingUploadSource, UploadSource, } from "./resources.js";
|
|
10
10
|
export type { EventOptions } from "./transport.js";
|
|
11
|
-
export { tool } from "
|
|
12
|
-
export type {
|
|
11
|
+
export { tool } from "./tools.js";
|
|
12
|
+
export type { BoundTool, EnvironmentMap, EnvironmentValue, PreparedArtifact, Tool, ToolContract, ToolContext, ToolHandler, ToolRequirements, ToolSelection, ToolSetupHandler, } from "./tools.js";
|
|
13
|
+
export type { NetworkPolicy, WebSocketFactory } from "@aexhq/session-protocol";
|
|
14
|
+
export type { EnvironmentRef, HandleOf } from "@aexhq/environment";
|
|
13
15
|
export interface AexOptions {
|
|
14
16
|
apiKey: string;
|
|
15
17
|
baseUrl?: string;
|
|
16
18
|
fetch?: Fetch;
|
|
17
19
|
webSocketFactory?: WebSocketFactory;
|
|
18
|
-
/** Stable tenant-scoped identity for this exact customer-application runner. */
|
|
19
|
-
client?: {
|
|
20
|
-
id: string;
|
|
21
|
-
};
|
|
22
20
|
}
|
|
23
21
|
export declare class Aex {
|
|
24
22
|
readonly sessions: Sessions;
|
package/dist/index.js
CHANGED
|
@@ -2,8 +2,8 @@ import { Sessions } from "./session.js";
|
|
|
2
2
|
import { Transport } from "./transport.js";
|
|
3
3
|
export { AbortError, AexError, OutputRefusalError, OutputSchemaError, OutputValidationError, SessionError, } from "./errors.js";
|
|
4
4
|
export { Session, Sessions, } from "./session.js";
|
|
5
|
-
export {
|
|
6
|
-
export { tool } from "
|
|
5
|
+
export { SessionChild, SessionChildren, SessionStorage, } from "./resources.js";
|
|
6
|
+
export { tool } from "./tools.js";
|
|
7
7
|
const DEFAULT_API_URL = "https://api.aex.dev";
|
|
8
8
|
export class Aex {
|
|
9
9
|
sessions;
|
|
@@ -14,16 +14,12 @@ export class Aex {
|
|
|
14
14
|
if (fetchImplementation === undefined) {
|
|
15
15
|
throw new TypeError("This runtime does not provide fetch; pass a fetch implementation to Aex");
|
|
16
16
|
}
|
|
17
|
-
if (options.client !== undefined &&
|
|
18
|
-
!/^[A-Za-z0-9_.:-]{1,128}$/u.test(options.client.id)) {
|
|
19
|
-
throw new TypeError("Aex client.id must contain 1 through 128 letters, digits, dots, colons, underscores, or hyphens");
|
|
20
|
-
}
|
|
21
17
|
const transport = new Transport(options.apiKey, options.baseUrl ?? DEFAULT_API_URL, fetchImplementation);
|
|
22
18
|
const webSocketFactory = options.webSocketFactory ??
|
|
23
19
|
(globalThis.WebSocket === undefined
|
|
24
20
|
? undefined
|
|
25
21
|
: (request) => new globalThis.WebSocket(request.url, request.protocol));
|
|
26
|
-
this.sessions = new Sessions(transport, webSocketFactory
|
|
22
|
+
this.sessions = new Sessions(transport, webSocketFactory);
|
|
27
23
|
}
|
|
28
24
|
/** Stop customer-app execution permanently; this Aex instance cannot create another session. */
|
|
29
25
|
close() {
|
package/dist/internal.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { withPreparedArtifact } from "./tools.js";
|
package/dist/resources.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { SessionChildren as BrainChildren
|
|
2
|
-
import type {
|
|
3
|
-
import type { Event, Session as BrainSession } from "@aexhq/
|
|
1
|
+
import { SessionChildren as BrainChildren } from "@aexhq/session-protocol";
|
|
2
|
+
import type { EnvironmentFileEntry as BrainEnvironmentFileEntry } from "@aexhq/session-protocol";
|
|
3
|
+
import type { Event, Session as BrainSession } from "@aexhq/session-protocol/session";
|
|
4
|
+
import type { EnvironmentRef } from "@aexhq/environment";
|
|
4
5
|
import type { EventOptions } from "./transport.js";
|
|
5
6
|
import { Transport } from "./transport.js";
|
|
6
7
|
export type BinarySource = string | ArrayBuffer | ArrayBufferView | Blob;
|
|
@@ -22,57 +23,13 @@ export interface PageOptions extends OperationOptions {
|
|
|
22
23
|
cursor?: string;
|
|
23
24
|
limit?: number;
|
|
24
25
|
}
|
|
25
|
-
export interface
|
|
26
|
-
state: BrainSandboxStatus["state"];
|
|
27
|
-
generation?: string;
|
|
28
|
-
reason?: string;
|
|
29
|
-
changedAt?: string;
|
|
30
|
-
expiresAt?: string;
|
|
31
|
-
}
|
|
32
|
-
export interface SandboxFile {
|
|
26
|
+
export interface EnvironmentFile {
|
|
33
27
|
path: string;
|
|
34
|
-
kind:
|
|
28
|
+
kind: BrainEnvironmentFileEntry["kind"];
|
|
35
29
|
bytes: number;
|
|
36
30
|
sha256?: string;
|
|
37
31
|
modifiedAt: string;
|
|
38
32
|
}
|
|
39
|
-
export interface SandboxFilePage {
|
|
40
|
-
data: SandboxFile[];
|
|
41
|
-
hasMore: boolean;
|
|
42
|
-
nextCursor?: string;
|
|
43
|
-
generation: string;
|
|
44
|
-
}
|
|
45
|
-
export interface SandboxFileOptions extends OperationOptions {
|
|
46
|
-
generation: string;
|
|
47
|
-
}
|
|
48
|
-
export interface SandboxFilePageOptions extends SandboxFileOptions, PageOptions {
|
|
49
|
-
}
|
|
50
|
-
export declare class SandboxFiles {
|
|
51
|
-
#private;
|
|
52
|
-
constructor(inner: BrainSandbox["files"], transport: Transport);
|
|
53
|
-
list(path: string, options: SandboxFilePageOptions): Promise<SandboxFilePage>;
|
|
54
|
-
stat(path: string, options: SandboxFileOptions): Promise<SandboxFile>;
|
|
55
|
-
download(path: string, options: SandboxFileOptions): Promise<Uint8Array>;
|
|
56
|
-
downloadStream(path: string, options: SandboxFileOptions): Promise<ReadableStream<Uint8Array>>;
|
|
57
|
-
upload(path: string, source: UploadSource, options: SandboxFileOptions & {
|
|
58
|
-
overwrite?: boolean;
|
|
59
|
-
}): Promise<SandboxFile>;
|
|
60
|
-
find(input: {
|
|
61
|
-
path: string;
|
|
62
|
-
glob: string;
|
|
63
|
-
}, options: SandboxFilePageOptions): Promise<SandboxFilePage>;
|
|
64
|
-
grep(input: {
|
|
65
|
-
path: string;
|
|
66
|
-
query: string;
|
|
67
|
-
}, options: SandboxFilePageOptions): Promise<SandboxFilePage>;
|
|
68
|
-
}
|
|
69
|
-
export declare class SessionSandbox {
|
|
70
|
-
#private;
|
|
71
|
-
readonly files: SandboxFiles;
|
|
72
|
-
constructor(transport: Transport, sessionId: string);
|
|
73
|
-
status(options?: OperationOptions): Promise<SandboxStatus>;
|
|
74
|
-
create(options?: OperationOptions): Promise<SandboxStatus>;
|
|
75
|
-
}
|
|
76
33
|
export interface StorageObject {
|
|
77
34
|
key: string;
|
|
78
35
|
bytes: number;
|
|
@@ -88,7 +45,7 @@ export interface StoragePage {
|
|
|
88
45
|
}
|
|
89
46
|
export declare class SessionStorage {
|
|
90
47
|
#private;
|
|
91
|
-
constructor(transport: Transport, sessionId: string);
|
|
48
|
+
constructor(transport: Transport, sessionId: string, environmentNames?: ReadonlyMap<EnvironmentRef, string>);
|
|
92
49
|
list(options?: PageOptions & {
|
|
93
50
|
prefix?: string;
|
|
94
51
|
}): Promise<StoragePage>;
|
|
@@ -100,18 +57,18 @@ export declare class SessionStorage {
|
|
|
100
57
|
overwrite?: boolean;
|
|
101
58
|
}): Promise<StorageObject>;
|
|
102
59
|
delete(key: string, options?: OperationOptions): Promise<void>;
|
|
103
|
-
|
|
60
|
+
copyFromEnvironment(environment: EnvironmentRef, input: {
|
|
104
61
|
key: string;
|
|
105
62
|
path: string;
|
|
106
|
-
|
|
63
|
+
generation: string;
|
|
107
64
|
overwrite?: boolean;
|
|
108
65
|
}, options?: OperationOptions): Promise<StorageObject>;
|
|
109
|
-
|
|
66
|
+
copyToEnvironment(environment: EnvironmentRef, input: {
|
|
110
67
|
key: string;
|
|
111
68
|
path: string;
|
|
112
|
-
|
|
69
|
+
generation: string;
|
|
113
70
|
overwrite?: boolean;
|
|
114
|
-
}, options?: OperationOptions): Promise<
|
|
71
|
+
}, options?: OperationOptions): Promise<EnvironmentFile>;
|
|
115
72
|
}
|
|
116
73
|
export interface ChildSummary {
|
|
117
74
|
id: string;
|
|
@@ -155,3 +112,4 @@ export declare class SessionChildren {
|
|
|
155
112
|
}>;
|
|
156
113
|
get(childId: string): SessionChild;
|
|
157
114
|
}
|
|
115
|
+
export declare function encodeBase64(bytes: Uint8Array): string;
|
package/dist/resources.js
CHANGED
|
@@ -1,110 +1,14 @@
|
|
|
1
|
-
import { MAX_INLINE_FILE_BYTES, SessionChildren as BrainChildren,
|
|
1
|
+
import { MAX_INLINE_FILE_BYTES, SessionChildren as BrainChildren, SessionStorage as BrainStorage, } from "@aexhq/session-protocol";
|
|
2
2
|
import { SessionError, abortError } from "./errors.js";
|
|
3
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) {
|
|
92
|
-
this.#inner = new BrainSandbox(transport, sessionId);
|
|
93
|
-
this.files = new SandboxFiles(this.#inner.files, transport);
|
|
94
|
-
}
|
|
95
|
-
async status(options = {}) {
|
|
96
|
-
return sandboxStatus(await this.#inner.status(request(options)));
|
|
97
|
-
}
|
|
98
|
-
async create(options = {}) {
|
|
99
|
-
return sandboxStatus(await this.#inner.create(intrinsicRequest(options)));
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
4
|
export class SessionStorage {
|
|
103
5
|
#inner;
|
|
104
6
|
#transport;
|
|
105
|
-
|
|
7
|
+
#environmentNames;
|
|
8
|
+
constructor(transport, sessionId, environmentNames = new Map()) {
|
|
106
9
|
this.#inner = new BrainStorage(transport, sessionId);
|
|
107
10
|
this.#transport = transport;
|
|
11
|
+
this.#environmentNames = environmentNames;
|
|
108
12
|
}
|
|
109
13
|
async list(options = {}) {
|
|
110
14
|
const page = await this.#inner.list({
|
|
@@ -158,22 +62,28 @@ export class SessionStorage {
|
|
|
158
62
|
delete(key, options = {}) {
|
|
159
63
|
return this.#inner.delete(key, request(options));
|
|
160
64
|
}
|
|
161
|
-
async
|
|
162
|
-
return storageObject(await this.#inner.
|
|
65
|
+
async copyFromEnvironment(environment, input, options = {}) {
|
|
66
|
+
return storageObject(await this.#inner.copyFromEnvironment(this.#environmentName(environment), {
|
|
163
67
|
key: input.key,
|
|
164
68
|
path: input.path,
|
|
165
|
-
|
|
69
|
+
environment_generation: input.generation,
|
|
166
70
|
...(input.overwrite === undefined ? {} : { overwrite: input.overwrite }),
|
|
167
71
|
}, request(options)));
|
|
168
72
|
}
|
|
169
|
-
async
|
|
170
|
-
return
|
|
73
|
+
async copyToEnvironment(environment, input, options = {}) {
|
|
74
|
+
return environmentFile(await this.#inner.copyToEnvironment(this.#environmentName(environment), {
|
|
171
75
|
key: input.key,
|
|
172
76
|
path: input.path,
|
|
173
|
-
|
|
77
|
+
environment_generation: input.generation,
|
|
174
78
|
...(input.overwrite === undefined ? {} : { overwrite: input.overwrite }),
|
|
175
79
|
}, request(options)));
|
|
176
80
|
}
|
|
81
|
+
#environmentName(environment) {
|
|
82
|
+
const name = this.#environmentNames.get(environment);
|
|
83
|
+
if (name === undefined)
|
|
84
|
+
throw new TypeError("EnvironmentRef does not belong to this Session");
|
|
85
|
+
return name;
|
|
86
|
+
}
|
|
177
87
|
}
|
|
178
88
|
export class SessionChild {
|
|
179
89
|
#inner;
|
|
@@ -249,16 +159,7 @@ function idempotentRequest(options) {
|
|
|
249
159
|
retry: true,
|
|
250
160
|
};
|
|
251
161
|
}
|
|
252
|
-
function
|
|
253
|
-
return {
|
|
254
|
-
state: value.state,
|
|
255
|
-
...(value.generation == null ? {} : { generation: value.generation }),
|
|
256
|
-
...(value.reason == null ? {} : { reason: value.reason }),
|
|
257
|
-
...(value.changed_at_ms == null ? {} : { changedAt: timestamp(value.changed_at_ms) }),
|
|
258
|
-
...(value.expires_at_ms == null ? {} : { expiresAt: timestamp(value.expires_at_ms) }),
|
|
259
|
-
};
|
|
260
|
-
}
|
|
261
|
-
function file(value) {
|
|
162
|
+
function environmentFile(value) {
|
|
262
163
|
return {
|
|
263
164
|
path: value.path,
|
|
264
165
|
kind: value.kind,
|
|
@@ -267,14 +168,6 @@ function file(value) {
|
|
|
267
168
|
modifiedAt: timestamp(value.modified_at_ms),
|
|
268
169
|
};
|
|
269
170
|
}
|
|
270
|
-
function filePage(value) {
|
|
271
|
-
return {
|
|
272
|
-
data: value.data.map(file),
|
|
273
|
-
hasMore: value.has_more,
|
|
274
|
-
...(value.next_cursor === undefined ? {} : { nextCursor: value.next_cursor }),
|
|
275
|
-
generation: value.generation,
|
|
276
|
-
};
|
|
277
|
-
}
|
|
278
171
|
function storageObject(value) {
|
|
279
172
|
return {
|
|
280
173
|
key: value.key,
|
|
@@ -413,7 +306,7 @@ async function collectDeclared(source, signal) {
|
|
|
413
306
|
}
|
|
414
307
|
return result;
|
|
415
308
|
}
|
|
416
|
-
function encodeBase64(bytes) {
|
|
309
|
+
export function encodeBase64(bytes) {
|
|
417
310
|
let binary = "";
|
|
418
311
|
for (let offset = 0; offset < bytes.byteLength; offset += 32_768) {
|
|
419
312
|
binary += String.fromCharCode(...bytes.subarray(offset, offset + 32_768));
|
package/dist/session.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import type { Event, Provider, Session as SessionData, SessionState } from "@aexhq/
|
|
2
|
-
import type
|
|
1
|
+
import type { Event, Provider, Session as SessionData, SessionState } from "@aexhq/session-protocol/session";
|
|
2
|
+
import { type EnvironmentRef, type HandleOf } from "@aexhq/environment";
|
|
3
|
+
import type { NetworkPolicy, WebSocketFactory } from "@aexhq/session-protocol";
|
|
3
4
|
import * as z from "zod";
|
|
4
5
|
import type { EventOptions } from "./transport.js";
|
|
5
6
|
import { Transport } from "./transport.js";
|
|
6
|
-
import type {
|
|
7
|
-
import { SessionChildren,
|
|
7
|
+
import type { EnvironmentMap, EnvironmentValue, ToolSelection } from "./tools.js";
|
|
8
|
+
import { SessionChildren, SessionStorage } from "./resources.js";
|
|
8
9
|
export type SessionInput = string;
|
|
9
10
|
export interface ModelOptions {
|
|
10
11
|
provider: Provider;
|
|
@@ -14,24 +15,33 @@ export interface ModelOptions {
|
|
|
14
15
|
maxOutputTokens?: number;
|
|
15
16
|
/** Immutable context capacity used for admission and compaction; Brain never guesses by name. */
|
|
16
17
|
contextWindowTokens?: number;
|
|
17
|
-
temperature?: number;
|
|
18
|
-
reasoningEffort?: "low" | "medium" | "high";
|
|
19
18
|
}
|
|
20
|
-
|
|
19
|
+
/**
|
|
20
|
+
* A built agentloop implementation, as exported by a loop package or produced by
|
|
21
|
+
* `buildLoopBundle` from `@aexhq/agentloop`. Assignment is by import, never by name:
|
|
22
|
+
* the sealed identity is the content digest plus the pinned toolchain.
|
|
23
|
+
*/
|
|
24
|
+
export interface Loop {
|
|
25
|
+
/** The complete deterministic ESM source bundle — the exact bytes sealed and uploaded. */
|
|
26
|
+
source: string;
|
|
27
|
+
/** SHA-256 hex of the UTF-8 source bytes. */
|
|
28
|
+
sha256: string;
|
|
29
|
+
/** The pinned loop-toolchain identity the bundle was built for. */
|
|
30
|
+
toolchain: string;
|
|
31
|
+
}
|
|
32
|
+
export interface CreateSessionOptions<Environments extends EnvironmentMap = EnvironmentMap> {
|
|
21
33
|
model: ModelOptions;
|
|
34
|
+
/** The imported agent loop that drives this session and every child unless spawn overrides it. */
|
|
35
|
+
loop: Loop;
|
|
22
36
|
/** Omitted or empty grants no tools. A non-empty list is the exact grant. */
|
|
23
|
-
|
|
24
|
-
|
|
37
|
+
environments?: Environments;
|
|
38
|
+
tools?: readonly ToolSelection<EnvironmentValue<Environments>>[];
|
|
25
39
|
/** Write-only values for environment names declared by managed Tools. */
|
|
26
40
|
secrets?: Record<string, string>;
|
|
27
41
|
/** Maximum direct outbound network authority sealed for managed sandboxes. Omission is deny-all. */
|
|
28
42
|
network?: NetworkPolicy;
|
|
29
43
|
/** Replacement attempts after an unrecoverable provider outcome. Defaults to one. */
|
|
30
44
|
providerRecoveryRetries?: 0 | 1;
|
|
31
|
-
client?: {
|
|
32
|
-
/** Replacement sends to the same customer process and operation. Defaults to one. */
|
|
33
|
-
submitRetries?: 0 | 1;
|
|
34
|
-
};
|
|
35
45
|
/** Optional ceilings for durable child sessions. Omitted fields use the hosted defaults. */
|
|
36
46
|
children?: {
|
|
37
47
|
maxDepth?: number;
|
|
@@ -81,19 +91,19 @@ export interface SessionSummary {
|
|
|
81
91
|
}
|
|
82
92
|
export declare class Sessions {
|
|
83
93
|
#private;
|
|
84
|
-
constructor(transport: Transport, webSocketFactory?: WebSocketFactory
|
|
94
|
+
constructor(transport: Transport, webSocketFactory?: WebSocketFactory);
|
|
85
95
|
/** @internal Called by `Aex.close()`. */
|
|
86
96
|
close(): void;
|
|
87
|
-
create(options: CreateSessionOptions
|
|
97
|
+
create<Environments extends EnvironmentMap>(options: CreateSessionOptions<Environments>, request?: RequestOptions): Promise<Session<Environments>>;
|
|
88
98
|
get(id: string, options?: Pick<RequestOptions, "signal">): Promise<Session>;
|
|
89
99
|
list(options?: ListSessionsOptions): Promise<SessionList>;
|
|
90
100
|
}
|
|
91
|
-
export declare class Session implements SessionSummary {
|
|
101
|
+
export declare class Session<Environments extends EnvironmentMap = EnvironmentMap> implements SessionSummary {
|
|
92
102
|
#private;
|
|
93
|
-
readonly sandbox: SessionSandbox;
|
|
94
103
|
readonly storage: SessionStorage;
|
|
95
104
|
readonly children: SessionChildren;
|
|
96
|
-
constructor(transport: Transport, data: SessionData);
|
|
105
|
+
constructor(transport: Transport, data: SessionData, environmentNames?: ReadonlyMap<EnvironmentRef, string>);
|
|
106
|
+
environment<Environment extends EnvironmentValue<Environments>>(environment: Environment): HandleOf<Environment>;
|
|
97
107
|
get id(): string;
|
|
98
108
|
get state(): SessionState;
|
|
99
109
|
get turnState(): SessionData["turn_state"];
|