@aexhq/sdk 0.57.5 → 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 +12 -55
- package/dist/resources.js +17 -124
- package/dist/session.d.ts +16 -25
- package/dist/session.js +64 -56
- 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/dist/session.js
CHANGED
|
@@ -1,38 +1,38 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CustomerEnvironment } from "@aexhq/session-protocol";
|
|
2
|
+
import { inspectEnvironment } from "@aexhq/environment";
|
|
2
3
|
import * as z from "zod";
|
|
3
4
|
import { AbortError, OutputRefusalError, OutputSchemaError, OutputValidationError, SessionError, abortError, errorFromApi, } from "./errors.js";
|
|
4
5
|
import { canonicalize, jcsSha256, randomIdempotencyKey } from "./json.js";
|
|
5
6
|
import { compileTools } from "./tools.js";
|
|
6
|
-
import { encodeBase64, SessionChildren,
|
|
7
|
+
import { encodeBase64, SessionChildren, SessionStorage } from "./resources.js";
|
|
7
8
|
export class Sessions {
|
|
8
9
|
#transport;
|
|
9
10
|
#webSocketFactory;
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
#customerHandInstance;
|
|
11
|
+
#customerEnvironments = new Map();
|
|
12
|
+
#customerEnvironmentInstances = new Map();
|
|
13
13
|
#closed = false;
|
|
14
|
-
constructor(transport, webSocketFactory
|
|
14
|
+
constructor(transport, webSocketFactory) {
|
|
15
15
|
this.#transport = transport;
|
|
16
16
|
this.#webSocketFactory = webSocketFactory;
|
|
17
|
-
this.#clientId = clientId;
|
|
18
17
|
}
|
|
19
18
|
/** @internal Called by `Aex.close()`. */
|
|
20
19
|
close() {
|
|
21
20
|
if (this.#closed)
|
|
22
21
|
return;
|
|
23
22
|
this.#closed = true;
|
|
24
|
-
this.#
|
|
25
|
-
|
|
26
|
-
this.#
|
|
23
|
+
for (const environment of this.#customerEnvironmentInstances.values())
|
|
24
|
+
environment.close();
|
|
25
|
+
this.#customerEnvironmentInstances.clear();
|
|
26
|
+
this.#customerEnvironments.clear();
|
|
27
27
|
}
|
|
28
28
|
async create(options, request = {}) {
|
|
29
29
|
if (this.#closed)
|
|
30
30
|
throw new SessionError("Aex client is closed");
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
await this.#
|
|
31
|
+
if (options.loop === undefined)
|
|
32
|
+
throw new TypeError("sessions.create requires an imported loop");
|
|
33
|
+
const compiledTools = await compileTools(options.tools, options.environments, options.secrets);
|
|
34
|
+
await Promise.all(compiledTools.layers.map((layer) => this.#transport.ensureArtifactLayer(layer.checksum, layer.media_type, layer.content, request.signal)));
|
|
35
|
+
await this.#ensureCustomerEnvironment(compiledTools.callbackClientId, compiledTools.clientRegistrations, request.signal);
|
|
36
36
|
const body = {
|
|
37
37
|
model: {
|
|
38
38
|
provider: options.model.provider,
|
|
@@ -45,26 +45,20 @@ export class Sessions {
|
|
|
45
45
|
...(options.model.contextWindowTokens === undefined
|
|
46
46
|
? {}
|
|
47
47
|
: { context_window_tokens: options.model.contextWindowTokens }),
|
|
48
|
-
...(options.model.temperature === undefined ? {} : { temperature: options.model.temperature }),
|
|
49
|
-
...(options.model.reasoningEffort === undefined
|
|
50
|
-
? {}
|
|
51
|
-
: { reasoning_effort: options.model.reasoningEffort }),
|
|
52
48
|
},
|
|
53
49
|
tools: {
|
|
54
50
|
items: compiledTools.items,
|
|
55
51
|
},
|
|
56
|
-
...(compiledTools.
|
|
57
|
-
...(options.agentloop === undefined
|
|
52
|
+
...(Object.keys(compiledTools.environments).length === 0
|
|
58
53
|
? {}
|
|
59
|
-
: {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
54
|
+
: { environments: compiledTools.environments }),
|
|
55
|
+
...(compiledTools.bundles.length === 0 ? {} : { tool_bundles: compiledTools.bundles }),
|
|
56
|
+
agentloop: {
|
|
57
|
+
source_bundle_sha256: options.loop.sha256,
|
|
58
|
+
toolchain: options.loop.toolchain,
|
|
59
|
+
bundle_base64: encodeBase64(new TextEncoder().encode(options.loop.source)),
|
|
60
|
+
},
|
|
66
61
|
...(options.secrets === undefined ? {} : { secrets: options.secrets }),
|
|
67
|
-
...(options.systemPrompt === undefined ? {} : { system_prompt: options.systemPrompt }),
|
|
68
62
|
...(options.metadata === undefined ? {} : { metadata: options.metadata }),
|
|
69
63
|
...(options.network === undefined
|
|
70
64
|
? {}
|
|
@@ -72,14 +66,11 @@ export class Sessions {
|
|
|
72
66
|
...(options.providerRecoveryRetries === undefined
|
|
73
67
|
? {}
|
|
74
68
|
: { provider_recovery_retries: options.providerRecoveryRetries }),
|
|
75
|
-
...(
|
|
69
|
+
...(compiledTools.callbackClientId === undefined
|
|
76
70
|
? {}
|
|
77
71
|
: {
|
|
78
72
|
client: {
|
|
79
|
-
id:
|
|
80
|
-
...(options.client?.submitRetries === undefined
|
|
81
|
-
? {}
|
|
82
|
-
: { submit_retries: options.client.submitRetries }),
|
|
73
|
+
id: compiledTools.callbackClientId,
|
|
83
74
|
},
|
|
84
75
|
}),
|
|
85
76
|
...(options.children === undefined
|
|
@@ -104,7 +95,7 @@ export class Sessions {
|
|
|
104
95
|
signal: request.signal,
|
|
105
96
|
retry: true,
|
|
106
97
|
});
|
|
107
|
-
return new Session(this.#transport, data);
|
|
98
|
+
return new Session(this.#transport, data, compiledTools.environmentNames);
|
|
108
99
|
}
|
|
109
100
|
async get(id, options = {}) {
|
|
110
101
|
const data = await this.#transport.json("GET", `/v1/sessions/${encodeURIComponent(id)}`, { signal: options.signal });
|
|
@@ -128,29 +119,29 @@ export class Sessions {
|
|
|
128
119
|
...(list.next_cursor === undefined ? {} : { nextCursor: list.next_cursor }),
|
|
129
120
|
};
|
|
130
121
|
}
|
|
131
|
-
async #
|
|
122
|
+
async #ensureCustomerEnvironment(clientId, registrations, signal) {
|
|
132
123
|
if (this.#closed)
|
|
133
124
|
throw new SessionError("Aex client is closed");
|
|
134
125
|
if (registrations.length === 0)
|
|
135
126
|
return;
|
|
136
|
-
if (
|
|
137
|
-
throw new TypeError("
|
|
138
|
-
}
|
|
127
|
+
if (clientId === undefined)
|
|
128
|
+
throw new TypeError("Callback Tools require an app() environment");
|
|
139
129
|
if (this.#webSocketFactory === undefined) {
|
|
140
130
|
throw new TypeError("This runtime does not provide WebSocket; pass webSocketFactory to Aex");
|
|
141
131
|
}
|
|
142
|
-
|
|
132
|
+
const existing = this.#customerEnvironments.get(clientId);
|
|
133
|
+
if (existing === undefined) {
|
|
143
134
|
let partial;
|
|
144
135
|
const starting = (async () => {
|
|
145
136
|
try {
|
|
146
|
-
partial = new
|
|
147
|
-
const grant = await this.#transport.
|
|
137
|
+
partial = new CustomerEnvironment(async () => {
|
|
138
|
+
const grant = await this.#transport.customerEnvironmentGrant(clientId);
|
|
148
139
|
return {
|
|
149
140
|
request: { url: grant.url, protocol: grant.protocol },
|
|
150
|
-
observe: (observation) => this.#transport.
|
|
141
|
+
observe: (observation) => this.#transport.customerEnvironmentObserve(grant.observationUrl, grant.observationToken, observation),
|
|
151
142
|
};
|
|
152
|
-
}, registrations, this.#webSocketFactory, { clientId
|
|
153
|
-
this.#
|
|
143
|
+
}, registrations, this.#webSocketFactory, { clientId });
|
|
144
|
+
this.#customerEnvironmentInstances.set(clientId, partial);
|
|
154
145
|
await partial.ready;
|
|
155
146
|
if (this.#closed) {
|
|
156
147
|
partial.close();
|
|
@@ -163,12 +154,13 @@ export class Sessions {
|
|
|
163
154
|
throw error;
|
|
164
155
|
}
|
|
165
156
|
})();
|
|
166
|
-
this.#
|
|
157
|
+
this.#customerEnvironments.set(clientId, starting);
|
|
167
158
|
void starting.catch(() => {
|
|
168
|
-
if (this.#
|
|
169
|
-
this.#
|
|
170
|
-
if (this.#
|
|
171
|
-
this.#
|
|
159
|
+
if (this.#customerEnvironments.get(clientId) === starting) {
|
|
160
|
+
this.#customerEnvironments.delete(clientId);
|
|
161
|
+
if (this.#customerEnvironmentInstances.get(clientId) === partial) {
|
|
162
|
+
this.#customerEnvironmentInstances.delete(clientId);
|
|
163
|
+
}
|
|
172
164
|
}
|
|
173
165
|
});
|
|
174
166
|
// The request may stop waiting, but the process-scoped runner remains reconnectable for
|
|
@@ -176,10 +168,10 @@ export class Sessions {
|
|
|
176
168
|
await waitWithSignal(starting, signal);
|
|
177
169
|
return;
|
|
178
170
|
}
|
|
179
|
-
const
|
|
171
|
+
const environment = await waitWithSignal(existing, signal);
|
|
180
172
|
if (this.#closed)
|
|
181
173
|
throw new SessionError("Aex client is closed");
|
|
182
|
-
await waitWithSignal(
|
|
174
|
+
await waitWithSignal(environment.register(registrations), signal);
|
|
183
175
|
}
|
|
184
176
|
}
|
|
185
177
|
function waitWithSignal(promise, signal) {
|
|
@@ -200,16 +192,32 @@ function waitWithSignal(promise, signal) {
|
|
|
200
192
|
export class Session {
|
|
201
193
|
#transport;
|
|
202
194
|
#data;
|
|
203
|
-
sandbox;
|
|
204
195
|
storage;
|
|
205
196
|
children;
|
|
206
|
-
|
|
197
|
+
#environmentNames;
|
|
198
|
+
#environmentHandles = new Map();
|
|
199
|
+
constructor(transport, data, environmentNames = new Map()) {
|
|
207
200
|
this.#transport = transport;
|
|
208
201
|
this.#data = data;
|
|
209
|
-
this
|
|
210
|
-
this.storage = new SessionStorage(transport, data.id);
|
|
202
|
+
this.#environmentNames = environmentNames;
|
|
203
|
+
this.storage = new SessionStorage(transport, data.id, environmentNames);
|
|
211
204
|
this.children = new SessionChildren(transport, data.id);
|
|
212
205
|
}
|
|
206
|
+
environment(environment) {
|
|
207
|
+
const name = this.#environmentNames.get(environment);
|
|
208
|
+
if (name === undefined)
|
|
209
|
+
throw new TypeError("EnvironmentRef does not belong to this Session");
|
|
210
|
+
const existing = this.#environmentHandles.get(environment);
|
|
211
|
+
if (existing !== undefined)
|
|
212
|
+
return existing;
|
|
213
|
+
const handle = inspectEnvironment(environment).createHandle({
|
|
214
|
+
sessionId: this.id,
|
|
215
|
+
environment: name,
|
|
216
|
+
request: async (method, path, body) => await this.#transport.json(method, path, body === undefined ? {} : { body }),
|
|
217
|
+
});
|
|
218
|
+
this.#environmentHandles.set(environment, handle);
|
|
219
|
+
return handle;
|
|
220
|
+
}
|
|
213
221
|
get id() {
|
|
214
222
|
return this.#data.id;
|
|
215
223
|
}
|
package/dist/tools.d.ts
CHANGED
|
@@ -1,2 +1,100 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { type ComputerProfile, type EnvironmentRef } from "@aexhq/environment";
|
|
2
|
+
import * as z from "zod";
|
|
3
|
+
export type JsonSchema = Record<string, unknown>;
|
|
4
|
+
export interface ToolContext {
|
|
5
|
+
readonly signal: AbortSignal;
|
|
6
|
+
readonly operationId: string;
|
|
7
|
+
readonly sessionId: string;
|
|
8
|
+
readonly deadlineMs: number;
|
|
9
|
+
readonly workspace?: string;
|
|
10
|
+
}
|
|
11
|
+
export type ToolHandler<Input extends z.ZodType, Output = unknown> = (input: z.output<Input>, context: ToolContext) => Output | Promise<Output>;
|
|
12
|
+
export type ToolSetupHandler = () => void | Promise<void>;
|
|
13
|
+
export interface ToolRequirements {
|
|
14
|
+
readonly env?: readonly string[];
|
|
15
|
+
readonly workspace?: boolean;
|
|
16
|
+
readonly processes?: boolean;
|
|
17
|
+
readonly network?: readonly {
|
|
18
|
+
readonly host: string;
|
|
19
|
+
readonly port: number;
|
|
20
|
+
}[];
|
|
21
|
+
readonly streaming?: boolean;
|
|
22
|
+
readonly recovery?: "retained" | "connection" | "replay-safe";
|
|
23
|
+
}
|
|
24
|
+
export interface PreparedArtifact {
|
|
25
|
+
readonly digest: string;
|
|
26
|
+
readonly target: ComputerProfile["platform"];
|
|
27
|
+
readonly bytes: number;
|
|
28
|
+
readonly execute: string;
|
|
29
|
+
readonly setup?: string;
|
|
30
|
+
readonly layers: readonly PreparedArtifactLayer[];
|
|
31
|
+
}
|
|
32
|
+
export interface PreparedArtifactLayer {
|
|
33
|
+
readonly digest: string;
|
|
34
|
+
readonly bytes: number;
|
|
35
|
+
readonly mediaType: "application/javascript+esm" | "application/x-xz";
|
|
36
|
+
readonly mountPath: string;
|
|
37
|
+
readonly unpack: "file" | "tar.xz";
|
|
38
|
+
readonly source: URL;
|
|
39
|
+
}
|
|
40
|
+
export interface ToolContract {
|
|
41
|
+
readonly name: string;
|
|
42
|
+
readonly description?: string;
|
|
43
|
+
readonly inputSchema: JsonSchema;
|
|
44
|
+
readonly outputSchema?: JsonSchema;
|
|
45
|
+
readonly contractDigest: string;
|
|
46
|
+
}
|
|
47
|
+
export interface Tool<Input extends z.ZodType = z.ZodType, Output = unknown> {
|
|
48
|
+
readonly kind: "aex.tool";
|
|
49
|
+
readonly name?: string;
|
|
50
|
+
readonly description?: string;
|
|
51
|
+
readonly input: Input;
|
|
52
|
+
readonly output?: z.ZodType;
|
|
53
|
+
readonly requirements: ToolRequirements;
|
|
54
|
+
readonly handler: ToolHandler<Input, Output>;
|
|
55
|
+
readonly setupHandler?: ToolSetupHandler;
|
|
56
|
+
readonly artifact?: PreparedArtifact;
|
|
57
|
+
describe(description: string): Tool<Input, Output>;
|
|
58
|
+
named(name: string): Tool<Input, Output>;
|
|
59
|
+
returns<Schema extends z.ZodType>(schema: Schema): Tool<Input, z.output<Schema>>;
|
|
60
|
+
needs(requirements: ToolRequirements): Tool<Input, Output>;
|
|
61
|
+
setup(handler: ToolSetupHandler): Tool<Input, Output>;
|
|
62
|
+
bind<Environment extends EnvironmentRef>(environment: Environment): BoundTool<Environment, Input, Output>;
|
|
63
|
+
}
|
|
64
|
+
export interface BoundTool<Environment extends EnvironmentRef = EnvironmentRef, Input extends z.ZodType = z.ZodType, Output = unknown> {
|
|
65
|
+
readonly kind: "aex.bound-tool";
|
|
66
|
+
readonly tool: Tool<Input, Output>;
|
|
67
|
+
readonly environment: Environment;
|
|
68
|
+
}
|
|
69
|
+
declare const EMPTY_INPUT: z.ZodObject<{}, z.core.$strip>;
|
|
70
|
+
export declare function tool<Output>(handler: ToolHandler<typeof EMPTY_INPUT, Output>): Tool<typeof EMPTY_INPUT, Output>;
|
|
71
|
+
export declare function tool<Input extends z.ZodType, Output>(input: Input, handler: ToolHandler<Input, Output>): Tool<Input, Output>;
|
|
72
|
+
export declare function withPreparedArtifact<Input extends z.ZodType, Output>(value: Tool<Input, Output>, artifact: PreparedArtifact): Tool<Input, Output>;
|
|
73
|
+
export type EnvironmentMap = Record<string, EnvironmentRef>;
|
|
74
|
+
export type EnvironmentValue<Environments extends EnvironmentMap> = Environments[keyof Environments];
|
|
75
|
+
export type ToolSelection<Environment extends EnvironmentRef = EnvironmentRef> = Tool | BoundTool<Environment>;
|
|
76
|
+
export interface ClientRegistration {
|
|
77
|
+
readonly registration: string;
|
|
78
|
+
readonly name: string;
|
|
79
|
+
readonly contractDigest: string;
|
|
80
|
+
readonly input: z.ZodType;
|
|
81
|
+
readonly output?: z.ZodType;
|
|
82
|
+
readonly handler: ToolHandler<z.ZodType>;
|
|
83
|
+
}
|
|
84
|
+
export interface CompiledTools {
|
|
85
|
+
readonly items: readonly unknown[];
|
|
86
|
+
readonly bundles: readonly unknown[];
|
|
87
|
+
readonly layers: readonly CompiledArtifactLayer[];
|
|
88
|
+
readonly clientRegistrations: readonly ClientRegistration[];
|
|
89
|
+
readonly environments: Readonly<Record<string, unknown>>;
|
|
90
|
+
readonly environmentNames: ReadonlyMap<EnvironmentRef, string>;
|
|
91
|
+
readonly callbackClientId?: string;
|
|
92
|
+
}
|
|
93
|
+
export interface CompiledArtifactLayer {
|
|
94
|
+
readonly checksum: string;
|
|
95
|
+
readonly bytes: number;
|
|
96
|
+
readonly media_type: string;
|
|
97
|
+
readonly content: Uint8Array;
|
|
98
|
+
}
|
|
99
|
+
export declare function compileTools(selections: readonly ToolSelection[] | undefined, declared: EnvironmentMap | undefined, secrets?: Readonly<Record<string, string>>): Promise<CompiledTools>;
|
|
100
|
+
export {};
|