@aexhq/sdk 0.55.0 → 0.56.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 +23 -7
- package/dist/errors.d.ts +7 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.js +2 -1
- package/dist/session.d.ts +22 -3
- package/dist/session.js +157 -73
- package/dist/tools.d.ts +2 -0
- package/dist/tools.js +1 -0
- package/dist/transport.d.ts +1 -1
- package/dist/transport.js +5 -5
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -13,12 +13,28 @@ const session = await aex.sessions.create({
|
|
|
13
13
|
},
|
|
14
14
|
});
|
|
15
15
|
|
|
16
|
-
const result = await session.
|
|
17
|
-
z.object({ answer: z.string() }),
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
const result = await session.send("Answer the question.", {
|
|
17
|
+
output: z.object({ answer: z.string() }),
|
|
18
|
+
});
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
`send()` returns text by default. Passing `output` returns a normal typed Promise and uses
|
|
22
|
+
`https://api.aex.dev` by default. Zod schemas must be representable as JSON Schema; process-local
|
|
23
|
+
custom refinements and transforms fail before any model work is admitted.
|
|
24
|
+
|
|
25
|
+
Sessions start with no model tools. Configure the exact capabilities at creation:
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
import { bash, edit, read, subagents, write } from "@aexhq/tools";
|
|
29
|
+
|
|
30
|
+
const session = await aex.sessions.create({
|
|
31
|
+
model: {
|
|
32
|
+
provider: "anthropic",
|
|
33
|
+
name: "claude-sonnet-5",
|
|
34
|
+
apiKey: "sk-ant-...",
|
|
35
|
+
},
|
|
36
|
+
tools: [bash(), read(), write(), edit(), subagents()],
|
|
37
|
+
});
|
|
20
38
|
```
|
|
21
39
|
|
|
22
|
-
`
|
|
23
|
-
default. Zod schemas must be representable as JSON Schema; process-local custom refinements and
|
|
24
|
-
transforms fail before any model work is admitted.
|
|
40
|
+
Omitting `tools` and passing `tools: []` are equivalent.
|
package/dist/errors.d.ts
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import type { ApiError, ApiErrorCode
|
|
1
|
+
import type { ApiError, ApiErrorCode } from "@aexhq/brain/session";
|
|
2
|
+
/** One Aex trusted-output validation failure, expressed as a JSON Pointer. */
|
|
3
|
+
export interface OutputValidationIssue {
|
|
4
|
+
path: string;
|
|
5
|
+
message: string;
|
|
6
|
+
keyword?: string;
|
|
7
|
+
}
|
|
2
8
|
export interface AexErrorOptions {
|
|
3
9
|
code?: ApiErrorCode | undefined;
|
|
4
10
|
status?: number | undefined;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { Sessions } from "./session.js";
|
|
2
2
|
import type { Fetch } from "./transport.js";
|
|
3
3
|
export { AbortError, AexError, OutputRefusalError, OutputSchemaError, OutputValidationError, SessionError, } from "./errors.js";
|
|
4
|
-
export type { AexErrorOptions } from "./errors.js";
|
|
4
|
+
export type { AexErrorOptions, OutputValidationIssue } from "./errors.js";
|
|
5
5
|
export { Session, Sessions, } from "./session.js";
|
|
6
|
-
export type { CreateSessionOptions, ListSessionsOptions, ModelSummary, ModelOptions, OutputOptions, RequestOptions, SessionInput, SessionList, SessionSummary, } from "./session.js";
|
|
6
|
+
export type { CreateSessionOptions, ListSessionsOptions, McpServerOptions, ModelSummary, ModelOptions, OutputOptions, RequestOptions, SessionInput, SessionList, SessionSummary, } from "./session.js";
|
|
7
7
|
export type { EventOptions } from "./transport.js";
|
|
8
|
+
export { defineIntrinsicTool, definePreinstalledTool, defineServerTool, defineTool, } from "@aexhq/brain";
|
|
9
|
+
export type { DefineIntrinsicToolOptions, DefinePreinstalledToolOptions, DefineServerToolOptions, DefineToolOptions, Tool, ToolContext, ToolHandler, } from "@aexhq/brain";
|
|
8
10
|
export interface AexOptions {
|
|
9
11
|
apiKey: string;
|
|
10
12
|
baseUrl?: string;
|
package/dist/index.js
CHANGED
|
@@ -2,12 +2,13 @@ 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 { defineIntrinsicTool, definePreinstalledTool, defineServerTool, defineTool, } from "@aexhq/brain";
|
|
5
6
|
const DEFAULT_API_URL = "https://api.aex.dev";
|
|
6
7
|
export class Aex {
|
|
7
8
|
sessions;
|
|
8
9
|
constructor(options) {
|
|
9
10
|
if (options.apiKey.trim() === "")
|
|
10
|
-
throw new TypeError("
|
|
11
|
+
throw new TypeError("Aex apiKey cannot be empty");
|
|
11
12
|
const fetchImplementation = options.fetch ?? globalThis.fetch?.bind(globalThis);
|
|
12
13
|
if (fetchImplementation === undefined) {
|
|
13
14
|
throw new TypeError("This runtime does not provide fetch; pass a fetch implementation to Aex");
|
package/dist/session.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import type { Event, Provider, Session as SessionData, SessionState } from "@aexhq/
|
|
1
|
+
import type { Event, Provider, Session as SessionData, SessionState } from "@aexhq/brain/session";
|
|
2
2
|
import * as z from "zod";
|
|
3
3
|
import type { EventOptions } from "./transport.js";
|
|
4
4
|
import { Transport } from "./transport.js";
|
|
5
|
+
import type { Tool } from "./tools.js";
|
|
5
6
|
export type SessionInput = string;
|
|
6
7
|
export interface ModelOptions {
|
|
7
8
|
provider: Provider;
|
|
@@ -14,15 +15,33 @@ export interface ModelOptions {
|
|
|
14
15
|
}
|
|
15
16
|
export interface CreateSessionOptions {
|
|
16
17
|
model: ModelOptions;
|
|
18
|
+
/** Omitted or empty grants no tools. A non-empty list is the exact grant. */
|
|
19
|
+
tools?: readonly Tool[];
|
|
20
|
+
/** Optional remote MCP servers discovered and sealed by Brain at session creation. */
|
|
21
|
+
mcp?: readonly McpServerOptions[];
|
|
17
22
|
systemPrompt?: string;
|
|
23
|
+
hand?: {
|
|
24
|
+
enabled?: boolean;
|
|
25
|
+
env?: Record<string, string>;
|
|
26
|
+
};
|
|
18
27
|
metadata?: Record<string, string>;
|
|
19
28
|
}
|
|
29
|
+
export interface McpServerOptions {
|
|
30
|
+
name: string;
|
|
31
|
+
url: string;
|
|
32
|
+
headers?: Record<string, string>;
|
|
33
|
+
protocol?: "auto" | "2026-07" | "legacy";
|
|
34
|
+
allowedTools?: readonly string[];
|
|
35
|
+
}
|
|
20
36
|
export interface RequestOptions {
|
|
21
37
|
signal?: AbortSignal;
|
|
22
38
|
idempotencyKey?: string;
|
|
23
39
|
metadata?: Record<string, string>;
|
|
24
40
|
}
|
|
25
|
-
export interface OutputOptions extends RequestOptions {
|
|
41
|
+
export interface OutputOptions<Schema extends z.ZodType = z.ZodType> extends RequestOptions {
|
|
42
|
+
output: Schema;
|
|
43
|
+
/** Extra attempts after the first invalid candidate. Defaults to 1; maximum 2. */
|
|
44
|
+
outputRetries?: 0 | 1 | 2;
|
|
26
45
|
}
|
|
27
46
|
export interface ListSessionsOptions {
|
|
28
47
|
limit?: number;
|
|
@@ -66,7 +85,7 @@ export declare class Session implements SessionSummary {
|
|
|
66
85
|
get metadata(): Readonly<Record<string, string | undefined>>;
|
|
67
86
|
refresh(options?: Pick<RequestOptions, "signal">): Promise<this>;
|
|
68
87
|
send(input: SessionInput, options?: RequestOptions): Promise<string>;
|
|
69
|
-
|
|
88
|
+
send<Schema extends z.ZodType>(input: SessionInput, options: OutputOptions<Schema>): Promise<z.output<Schema>>;
|
|
70
89
|
events(options?: EventOptions): AsyncGenerator<Event>;
|
|
71
90
|
cancel(options?: Pick<RequestOptions, "signal">): Promise<this>;
|
|
72
91
|
delete(options?: Pick<RequestOptions, "signal">): Promise<void>;
|
package/dist/session.js
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
import * as z from "zod";
|
|
2
|
-
import { AbortError, OutputSchemaError, OutputValidationError, SessionError, abortError, errorFromApi, } from "./errors.js";
|
|
3
|
-
import { jcsSha256, randomIdempotencyKey } from "./json.js";
|
|
2
|
+
import { AbortError, OutputRefusalError, OutputSchemaError, OutputValidationError, SessionError, abortError, errorFromApi, } from "./errors.js";
|
|
3
|
+
import { canonicalize, jcsSha256, randomIdempotencyKey } from "./json.js";
|
|
4
|
+
import { compileTools } from "./tools.js";
|
|
4
5
|
export class Sessions {
|
|
5
6
|
#transport;
|
|
6
7
|
constructor(transport) {
|
|
7
8
|
this.#transport = transport;
|
|
8
9
|
}
|
|
9
10
|
async create(options, request = {}) {
|
|
11
|
+
const compiledTools = await compileTools(options.tools);
|
|
12
|
+
if (compiledTools.attached.size > 0) {
|
|
13
|
+
throw new TypeError("Attached-process Tools are not available through this Aex SDK revision; use the default Hand execution mode");
|
|
14
|
+
}
|
|
10
15
|
const body = {
|
|
11
16
|
model: {
|
|
12
17
|
provider: options.model.provider,
|
|
@@ -21,6 +26,31 @@ export class Sessions {
|
|
|
21
26
|
? {}
|
|
22
27
|
: { reasoning_effort: options.model.reasoningEffort }),
|
|
23
28
|
},
|
|
29
|
+
tools: {
|
|
30
|
+
items: compiledTools.items,
|
|
31
|
+
...(options.mcp === undefined
|
|
32
|
+
? {}
|
|
33
|
+
: {
|
|
34
|
+
mcp: options.mcp.map((server) => ({
|
|
35
|
+
name: server.name,
|
|
36
|
+
url: server.url,
|
|
37
|
+
...(server.headers === undefined ? {} : { headers: server.headers }),
|
|
38
|
+
...(server.protocol === undefined ? {} : { protocol: server.protocol }),
|
|
39
|
+
...(server.allowedTools === undefined
|
|
40
|
+
? {}
|
|
41
|
+
: { allowed_tools: [...server.allowedTools] }),
|
|
42
|
+
})),
|
|
43
|
+
}),
|
|
44
|
+
},
|
|
45
|
+
...(compiledTools.bundles.length === 0 ? {} : { tool_bundles: compiledTools.bundles }),
|
|
46
|
+
...(options.hand === undefined
|
|
47
|
+
? {}
|
|
48
|
+
: {
|
|
49
|
+
hand: {
|
|
50
|
+
...(options.hand.enabled === undefined ? {} : { enabled: options.hand.enabled }),
|
|
51
|
+
...(options.hand.env === undefined ? {} : { env: options.hand.env }),
|
|
52
|
+
},
|
|
53
|
+
}),
|
|
24
54
|
...(options.systemPrompt === undefined ? {} : { system_prompt: options.systemPrompt }),
|
|
25
55
|
...(options.metadata === undefined ? {} : { metadata: options.metadata }),
|
|
26
56
|
};
|
|
@@ -89,15 +119,35 @@ export class Session {
|
|
|
89
119
|
return this;
|
|
90
120
|
}
|
|
91
121
|
async send(input, options = {}) {
|
|
122
|
+
const outputOptions = isOutputOptions(options) ? options : undefined;
|
|
123
|
+
const compiled = outputOptions === undefined
|
|
124
|
+
? undefined
|
|
125
|
+
: await compileOutputSchema(outputOptions.output, outputOptions.outputRetries);
|
|
92
126
|
const accepted = await this.#transport.json("POST", `/v1/sessions/${encodeURIComponent(this.id)}/messages`, {
|
|
93
127
|
body: {
|
|
94
128
|
content: input,
|
|
95
129
|
...(options.metadata === undefined ? {} : { metadata: options.metadata }),
|
|
130
|
+
...(compiled === undefined
|
|
131
|
+
? {}
|
|
132
|
+
: {
|
|
133
|
+
output: {
|
|
134
|
+
schema: compiled.jsonSchema,
|
|
135
|
+
schema_hash: compiled.schemaHash,
|
|
136
|
+
...(compiled.retries === undefined ? {} : { retries: compiled.retries }),
|
|
137
|
+
},
|
|
138
|
+
}),
|
|
96
139
|
},
|
|
97
140
|
headers: { "Idempotency-Key": options.idempotencyKey ?? randomIdempotencyKey() },
|
|
98
141
|
signal: options.signal,
|
|
99
142
|
retry: true,
|
|
100
143
|
});
|
|
144
|
+
if (compiled !== undefined) {
|
|
145
|
+
if (accepted.session_id !== this.id ||
|
|
146
|
+
accepted.output_id === undefined ||
|
|
147
|
+
accepted.schema_hash !== compiled.schemaHash) {
|
|
148
|
+
throw new SessionError("Aex returned an inconsistent typed-output admission");
|
|
149
|
+
}
|
|
150
|
+
}
|
|
101
151
|
let answer = "";
|
|
102
152
|
try {
|
|
103
153
|
for await (const event of this.events({ after: Math.max(0, accepted.seq - 1), signal: options.signal })) {
|
|
@@ -105,79 +155,39 @@ export class Session {
|
|
|
105
155
|
answer = event.text;
|
|
106
156
|
}
|
|
107
157
|
else if (event.type === "turn.failed" && event.turn_id === accepted.turn_id) {
|
|
108
|
-
throw errorFromApi(event.error);
|
|
158
|
+
throw errorFromApi(event.error, undefined, outputIssues(event.error));
|
|
109
159
|
}
|
|
110
160
|
else if (event.type === "turn.completed" && event.turn_id === accepted.turn_id) {
|
|
111
161
|
this.markIdle();
|
|
112
162
|
if (event.stop_reason === "cancelled")
|
|
113
163
|
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");
|
|
164
|
+
if (compiled !== undefined && outputOptions !== undefined) {
|
|
165
|
+
if (event.result === undefined) {
|
|
166
|
+
if (event.stop_reason === "refusal") {
|
|
167
|
+
throw new OutputRefusalError("The model refused the structured-output request");
|
|
168
|
+
}
|
|
169
|
+
throw new OutputValidationError("The model ended the turn without submitting the requested structured output", [{
|
|
170
|
+
path: "",
|
|
171
|
+
message: "The model did not call aex_submit_output",
|
|
172
|
+
keyword: "missing_output",
|
|
173
|
+
}]);
|
|
174
|
+
}
|
|
175
|
+
if (event.result.name !== "aex_submit_output" ||
|
|
176
|
+
event.result.metadata?.output_id !== accepted.output_id ||
|
|
177
|
+
event.result.metadata?.schema_hash !== compiled.schemaHash) {
|
|
178
|
+
throw new SessionError("Aex returned a typed result for a different request");
|
|
179
|
+
}
|
|
180
|
+
const parsed = await outputOptions.output.safeParseAsync(event.result.value);
|
|
181
|
+
if (!parsed.success) {
|
|
182
|
+
throw new OutputValidationError("The output passed the wire schema but failed the original Zod schema", parsed.error.issues.map((issue) => ({
|
|
183
|
+
path: jsonPointer(issue.path),
|
|
184
|
+
message: issue.message,
|
|
185
|
+
keyword: issue.code,
|
|
186
|
+
})));
|
|
187
|
+
}
|
|
188
|
+
return parsed.data;
|
|
163
189
|
}
|
|
164
|
-
|
|
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
|
-
})));
|
|
179
|
-
}
|
|
180
|
-
return parsed.data;
|
|
190
|
+
return answer;
|
|
181
191
|
}
|
|
182
192
|
}
|
|
183
193
|
}
|
|
@@ -188,7 +198,7 @@ export class Session {
|
|
|
188
198
|
}
|
|
189
199
|
throw error;
|
|
190
200
|
}
|
|
191
|
-
throw new SessionError("The
|
|
201
|
+
throw new SessionError("The Aex event stream ended before the session finished its work");
|
|
192
202
|
}
|
|
193
203
|
events(options = {}) {
|
|
194
204
|
return this.#transport.events(this.id, options);
|
|
@@ -207,8 +217,82 @@ export class Session {
|
|
|
207
217
|
this.#data = { ...this.#data, state: "idle" };
|
|
208
218
|
}
|
|
209
219
|
}
|
|
210
|
-
function
|
|
211
|
-
return
|
|
220
|
+
function isOutputOptions(options) {
|
|
221
|
+
return "output" in options;
|
|
222
|
+
}
|
|
223
|
+
async function compileOutputSchema(schema, retries) {
|
|
224
|
+
let jsonSchema;
|
|
225
|
+
try {
|
|
226
|
+
assertPortableOutputSchema(schema);
|
|
227
|
+
jsonSchema = z.toJSONSchema(schema, {
|
|
228
|
+
target: "draft-2020-12",
|
|
229
|
+
unrepresentable: "throw",
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
catch (cause) {
|
|
233
|
+
throw new OutputSchemaError(messageOf(cause, "The Zod schema cannot be represented as JSON Schema"), {
|
|
234
|
+
cause,
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
if (jsonSchema.type !== "object") {
|
|
238
|
+
throw new OutputSchemaError("session.send() output requires a Zod object schema");
|
|
239
|
+
}
|
|
240
|
+
assertSupportedJsonSchema(jsonSchema);
|
|
241
|
+
return { jsonSchema, schemaHash: await jcsSha256(jsonSchema), retries };
|
|
242
|
+
}
|
|
243
|
+
function assertSupportedJsonSchema(schema) {
|
|
244
|
+
const bytes = new TextEncoder().encode(canonicalize(schema));
|
|
245
|
+
if (bytes.byteLength > 64 * 1024) {
|
|
246
|
+
throw new OutputSchemaError("The output schema exceeds the 65536-byte service limit");
|
|
247
|
+
}
|
|
248
|
+
let nodes = 0;
|
|
249
|
+
const visit = (value, depth) => {
|
|
250
|
+
if (depth > 64)
|
|
251
|
+
throw new OutputSchemaError("The output schema exceeds the service depth limit");
|
|
252
|
+
nodes += 1;
|
|
253
|
+
if (nodes > 4096)
|
|
254
|
+
throw new OutputSchemaError("The output schema exceeds the service node limit");
|
|
255
|
+
if (Array.isArray(value)) {
|
|
256
|
+
for (const child of value)
|
|
257
|
+
visit(child, depth + 1);
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
if (value === null || typeof value !== "object")
|
|
261
|
+
return;
|
|
262
|
+
const object = value;
|
|
263
|
+
if ("pattern" in object || "patternProperties" in object) {
|
|
264
|
+
throw new OutputSchemaError("Regular-expression JSON Schema keywords are not supported for Aex structured output");
|
|
265
|
+
}
|
|
266
|
+
for (const keyword of ["$ref", "$dynamicRef", "$recursiveRef"]) {
|
|
267
|
+
const reference = object[keyword];
|
|
268
|
+
if (typeof reference === "string" && !reference.startsWith("#")) {
|
|
269
|
+
throw new OutputSchemaError("Remote JSON Schema references are not supported for Aex structured output");
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
for (const child of Object.values(object))
|
|
273
|
+
visit(child, depth + 1);
|
|
274
|
+
};
|
|
275
|
+
visit(schema, 0);
|
|
276
|
+
}
|
|
277
|
+
function outputIssues(error) {
|
|
278
|
+
const details = error.details;
|
|
279
|
+
if (details === undefined || details === null || typeof details !== "object")
|
|
280
|
+
return [];
|
|
281
|
+
const issues = details.issues;
|
|
282
|
+
if (!Array.isArray(issues))
|
|
283
|
+
return [];
|
|
284
|
+
return issues.flatMap((issue) => {
|
|
285
|
+
if (issue === null || typeof issue !== "object")
|
|
286
|
+
return [];
|
|
287
|
+
const value = issue;
|
|
288
|
+
if (typeof value.path !== "string" || typeof value.message !== "string")
|
|
289
|
+
return [];
|
|
290
|
+
return [{
|
|
291
|
+
path: value.path,
|
|
292
|
+
message: value.message,
|
|
293
|
+
...(typeof value.keyword === "string" ? { keyword: value.keyword } : {}),
|
|
294
|
+
}];
|
|
295
|
+
});
|
|
212
296
|
}
|
|
213
297
|
function jsonPointer(path) {
|
|
214
298
|
if (path.length === 0)
|
|
@@ -238,7 +322,7 @@ function assertPortableOutputSchema(schema) {
|
|
|
238
322
|
definition.type === "file" ||
|
|
239
323
|
definition.check === "overwrite";
|
|
240
324
|
if (unsupported) {
|
|
241
|
-
throw new OutputSchemaError(`This Zod schema contains ${String(definition.type ?? definition.check)} behavior that cannot be enforced by the
|
|
325
|
+
throw new OutputSchemaError(`This Zod schema contains ${String(definition.type ?? definition.check)} behavior that cannot be enforced by the Aex output service`);
|
|
242
326
|
}
|
|
243
327
|
visit(definition);
|
|
244
328
|
return;
|
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
package/dist/transport.js
CHANGED
|
@@ -41,7 +41,7 @@ export class Transport {
|
|
|
41
41
|
lastError = error;
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
|
-
throw new SessionError("Could not reach the
|
|
44
|
+
throw new SessionError("Could not reach the Aex API", { cause: lastError });
|
|
45
45
|
}
|
|
46
46
|
async *events(sessionId, options = {}) {
|
|
47
47
|
let cursor = options.after ?? 0;
|
|
@@ -62,7 +62,7 @@ export class Transport {
|
|
|
62
62
|
if (!response.ok)
|
|
63
63
|
throw await this.responseError(response);
|
|
64
64
|
if (response.body === null)
|
|
65
|
-
throw new SessionError("The
|
|
65
|
+
throw new SessionError("The Aex event stream had no body");
|
|
66
66
|
let received = false;
|
|
67
67
|
for await (const event of parseEventStream(response.body)) {
|
|
68
68
|
if (event.seq <= cursor)
|
|
@@ -86,7 +86,7 @@ export class Transport {
|
|
|
86
86
|
if (consecutiveFailures > 5) {
|
|
87
87
|
if (error instanceof AexError)
|
|
88
88
|
throw error;
|
|
89
|
-
throw new SessionError("The
|
|
89
|
+
throw new SessionError("The Aex event stream disconnected", { cause: error });
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
92
|
await delay(Math.min(2_000, 100 * 2 ** (consecutiveFailures - 1)), options.signal);
|
|
@@ -102,7 +102,7 @@ export class Transport {
|
|
|
102
102
|
}
|
|
103
103
|
if (envelope?.error !== undefined)
|
|
104
104
|
return errorFromApi(envelope.error, response.status);
|
|
105
|
-
return new SessionError(`
|
|
105
|
+
return new SessionError(`Aex API request failed with HTTP ${response.status}`, {
|
|
106
106
|
status: response.status,
|
|
107
107
|
requestId: response.headers.get("x-request-id") ?? undefined,
|
|
108
108
|
});
|
|
@@ -124,7 +124,7 @@ async function* parseEventStream(stream) {
|
|
|
124
124
|
return JSON.parse(data);
|
|
125
125
|
}
|
|
126
126
|
catch (cause) {
|
|
127
|
-
throw new SessionError("
|
|
127
|
+
throw new SessionError("Aex sent an invalid event", { cause });
|
|
128
128
|
}
|
|
129
129
|
};
|
|
130
130
|
const line = (raw) => {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aexhq/sdk",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "TypeScript SDK for
|
|
3
|
+
"version": "0.56.0",
|
|
4
|
+
"description": "TypeScript SDK for Aex sessions",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://aex.dev",
|
|
7
7
|
"repository": {
|
|
@@ -33,13 +33,13 @@
|
|
|
33
33
|
"test": "tsc -p tsconfig.json && node --test"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@aexhq/
|
|
36
|
+
"@aexhq/brain": "0.1.0"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
|
-
"zod": "
|
|
39
|
+
"zod": "4.4.3"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"typescript": "^5.9.2",
|
|
43
|
-
"zod": "
|
|
43
|
+
"zod": "4.4.3"
|
|
44
44
|
}
|
|
45
45
|
}
|