@aexhq/sdk 0.40.6 → 0.40.7
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 +159 -159
- package/dist/_contracts/stable.d.ts +10 -5
- package/dist/_contracts/stable.js +10 -5
- package/dist/client.js +5 -11
- package/dist/client.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/docs/authentication.md +125 -125
- package/docs/billing.md +118 -118
- package/docs/concepts/agent-tools.md +66 -66
- package/docs/concepts/composition.md +37 -37
- package/docs/concepts/providers-and-runtimes.md +54 -54
- package/docs/concepts/runs.md +49 -49
- package/docs/concepts/subagents.md +88 -88
- package/docs/credentials.md +125 -125
- package/docs/defaults.md +64 -64
- package/docs/errors.md +196 -196
- package/docs/events.md +243 -243
- package/docs/limits-and-quotas.md +144 -144
- package/docs/limits.md +50 -50
- package/docs/mcp.md +44 -44
- package/docs/networking.md +163 -163
- package/docs/outputs.md +267 -267
- package/docs/public-surface.json +77 -77
- package/docs/quickstart.md +119 -119
- package/docs/release.md +38 -38
- package/docs/retries.md +129 -129
- package/docs/run-config.md +58 -58
- package/docs/run-record.md +55 -55
- package/docs/secrets.md +125 -125
- package/docs/testing.md +35 -35
- package/docs/vision-skills.md +91 -91
- package/docs/webhooks.md +127 -127
- package/examples/feature-tour.ts +282 -282
- package/examples/spike-settle-latency.ts +125 -125
- package/package.json +1 -1
|
@@ -1,125 +1,125 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* SPIKE (throwaway): measure the real park-event -> record-idle gap for interactive
|
|
3
|
-
* session turns. This is the extra wall-clock Option B (settle-consistent turn stream)
|
|
4
|
-
* would force onto EVERY turn: the turn stream currently ends on the RUN_FINISHED park
|
|
5
|
-
* event, but the session RECORD flips running->idle later, in the async settle lambda.
|
|
6
|
-
*
|
|
7
|
-
* AEX_API_KEY=... DEEPSEEK_API_KEY=... AEX_API_URL=... bun packages/sdk/examples/spike-settle-latency.ts
|
|
8
|
-
*
|
|
9
|
-
* Optional: SPIKE_TURNS=8 (samples), SPIKE_POLL_MS=120 (record poll interval).
|
|
10
|
-
*
|
|
11
|
-
* Method per turn:
|
|
12
|
-
* 1) send a tiny prompt, stream events, capture t_runFinished at the RUN_FINISHED event
|
|
13
|
-
* (this is where the default turn stream ends), then stop consuming.
|
|
14
|
-
* 2) tight-poll session.refresh() until status === "idle"; capture t_idle.
|
|
15
|
-
* 3) settleGapMs = t_idle - t_runFinished <-- the Option B tax.
|
|
16
|
-
* The next turn is only sent AFTER idle, so each measurement is isolated (no reconcile).
|
|
17
|
-
*/
|
|
18
|
-
import { Aex, Models, Providers, Sizes } from "@aexhq/sdk";
|
|
19
|
-
|
|
20
|
-
const apiKey = required("AEX_API_KEY");
|
|
21
|
-
const deepseekKey = required("DEEPSEEK_API_KEY");
|
|
22
|
-
const apiUrl = process.env.AEX_API_URL;
|
|
23
|
-
const turns = Number(process.env.SPIKE_TURNS ?? "8");
|
|
24
|
-
const pollMs = Number(process.env.SPIKE_POLL_MS ?? "120");
|
|
25
|
-
|
|
26
|
-
const aex = new Aex({
|
|
27
|
-
apiKey,
|
|
28
|
-
...(apiUrl ? { baseUrl: apiUrl } : {}),
|
|
29
|
-
retry: { maxAttempts: 4, initialDelayMs: 500, maxDelayMs: 10_000, maxElapsedMs: 90_000 }
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
console.log(`opening session (dev)...`);
|
|
33
|
-
const session = await aex.openSession({
|
|
34
|
-
provider: Providers.DEEPSEEK,
|
|
35
|
-
model: Models.DEEPSEEK_V4_FLASH,
|
|
36
|
-
system: "Reply with a single short sentence. Never use tools or write files.",
|
|
37
|
-
includeBuiltinTools: false,
|
|
38
|
-
tools: [],
|
|
39
|
-
runtime: Sizes.SHARED_0_25X_1GB,
|
|
40
|
-
overrides: { idleTtl: "10m", timeout: "5m", maxSpendUsd: 1 },
|
|
41
|
-
apiKeys: { deepseek: deepseekKey }
|
|
42
|
-
});
|
|
43
|
-
console.log(`session: ${session.id}`);
|
|
44
|
-
|
|
45
|
-
type Sample = { turn: number; turnMs: number; settleGapMs: number; polls: number; timedOut: boolean };
|
|
46
|
-
const samples: Sample[] = [];
|
|
47
|
-
|
|
48
|
-
for (let i = 0; i < turns; i++) {
|
|
49
|
-
const stream = session.send(`Say hello #${i + 1} in one short sentence.`);
|
|
50
|
-
const tStart = performance.now();
|
|
51
|
-
let tRunFinished = 0;
|
|
52
|
-
let errored = false;
|
|
53
|
-
for await (const event of stream) {
|
|
54
|
-
if (event.isRunError()) {
|
|
55
|
-
errored = true;
|
|
56
|
-
tRunFinished = performance.now();
|
|
57
|
-
break;
|
|
58
|
-
}
|
|
59
|
-
if (event.isRunFinished()) {
|
|
60
|
-
tRunFinished = performance.now();
|
|
61
|
-
break; // default turn stream would end HERE
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
if (tRunFinished === 0) tRunFinished = performance.now();
|
|
65
|
-
const turnMs = tRunFinished - tStart;
|
|
66
|
-
|
|
67
|
-
// Tight-poll the authoritative record until it leaves running.
|
|
68
|
-
let polls = 0;
|
|
69
|
-
let tIdle = 0;
|
|
70
|
-
let timedOut = false;
|
|
71
|
-
const deadline = performance.now() + 90_000;
|
|
72
|
-
for (;;) {
|
|
73
|
-
polls++;
|
|
74
|
-
const rec = await session.refresh().catch(() => undefined);
|
|
75
|
-
const status = rec?.status;
|
|
76
|
-
if (status === "idle" || status === "suspended" || status === "error") {
|
|
77
|
-
tIdle = performance.now();
|
|
78
|
-
break;
|
|
79
|
-
}
|
|
80
|
-
if (performance.now() >= deadline) {
|
|
81
|
-
tIdle = performance.now();
|
|
82
|
-
timedOut = true;
|
|
83
|
-
break;
|
|
84
|
-
}
|
|
85
|
-
await sleep(pollMs);
|
|
86
|
-
}
|
|
87
|
-
const settleGapMs = tIdle - tRunFinished;
|
|
88
|
-
samples.push({ turn: i + 1, turnMs, settleGapMs, polls, timedOut });
|
|
89
|
-
console.log(
|
|
90
|
-
`turn ${String(i + 1).padStart(2)} turn=${fmt(turnMs)} settleGap=${fmt(settleGapMs)} polls=${polls}` +
|
|
91
|
-
(errored ? " (RUN_ERROR)" : "") +
|
|
92
|
-
(timedOut ? " (TIMEOUT>90s)" : "")
|
|
93
|
-
);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const gaps = samples.map((s) => s.settleGapMs).sort((a, b) => a - b);
|
|
97
|
-
console.log("\n=== settle-gap distribution (park event -> record idle) ===");
|
|
98
|
-
console.log(`n=${gaps.length}`);
|
|
99
|
-
console.log(`min ${fmt(gaps[0])}`);
|
|
100
|
-
console.log(`median ${fmt(pct(gaps, 50))}`);
|
|
101
|
-
console.log(`p90 ${fmt(pct(gaps, 90))}`);
|
|
102
|
-
console.log(`max ${fmt(gaps[gaps.length - 1])}`);
|
|
103
|
-
console.log(`mean ${fmt(gaps.reduce((a, b) => a + b, 0) / gaps.length)}`);
|
|
104
|
-
console.log("\nInterpretation: settleGap is the per-turn latency Option B adds before the");
|
|
105
|
-
console.log("caller regains control (the turn stream would block until the record is idle).");
|
|
106
|
-
|
|
107
|
-
function pct(sorted: number[], p: number): number {
|
|
108
|
-
if (sorted.length === 0) return 0;
|
|
109
|
-
const idx = Math.min(sorted.length - 1, Math.floor((p / 100) * sorted.length));
|
|
110
|
-
return sorted[idx];
|
|
111
|
-
}
|
|
112
|
-
function fmt(ms: number): string {
|
|
113
|
-
return ms >= 1000 ? `${(ms / 1000).toFixed(2)}s` : `${Math.round(ms)}ms`;
|
|
114
|
-
}
|
|
115
|
-
function sleep(ms: number): Promise<void> {
|
|
116
|
-
return new Promise((r) => setTimeout(r, ms));
|
|
117
|
-
}
|
|
118
|
-
function required(name: string): string {
|
|
119
|
-
const v = process.env[name];
|
|
120
|
-
if (!v) {
|
|
121
|
-
console.error(`Missing env var ${name}`);
|
|
122
|
-
process.exit(1);
|
|
123
|
-
}
|
|
124
|
-
return v;
|
|
125
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* SPIKE (throwaway): measure the real park-event -> record-idle gap for interactive
|
|
3
|
+
* session turns. This is the extra wall-clock Option B (settle-consistent turn stream)
|
|
4
|
+
* would force onto EVERY turn: the turn stream currently ends on the RUN_FINISHED park
|
|
5
|
+
* event, but the session RECORD flips running->idle later, in the async settle lambda.
|
|
6
|
+
*
|
|
7
|
+
* AEX_API_KEY=... DEEPSEEK_API_KEY=... AEX_API_URL=... bun packages/sdk/examples/spike-settle-latency.ts
|
|
8
|
+
*
|
|
9
|
+
* Optional: SPIKE_TURNS=8 (samples), SPIKE_POLL_MS=120 (record poll interval).
|
|
10
|
+
*
|
|
11
|
+
* Method per turn:
|
|
12
|
+
* 1) send a tiny prompt, stream events, capture t_runFinished at the RUN_FINISHED event
|
|
13
|
+
* (this is where the default turn stream ends), then stop consuming.
|
|
14
|
+
* 2) tight-poll session.refresh() until status === "idle"; capture t_idle.
|
|
15
|
+
* 3) settleGapMs = t_idle - t_runFinished <-- the Option B tax.
|
|
16
|
+
* The next turn is only sent AFTER idle, so each measurement is isolated (no reconcile).
|
|
17
|
+
*/
|
|
18
|
+
import { Aex, Models, Providers, Sizes } from "@aexhq/sdk";
|
|
19
|
+
|
|
20
|
+
const apiKey = required("AEX_API_KEY");
|
|
21
|
+
const deepseekKey = required("DEEPSEEK_API_KEY");
|
|
22
|
+
const apiUrl = process.env.AEX_API_URL;
|
|
23
|
+
const turns = Number(process.env.SPIKE_TURNS ?? "8");
|
|
24
|
+
const pollMs = Number(process.env.SPIKE_POLL_MS ?? "120");
|
|
25
|
+
|
|
26
|
+
const aex = new Aex({
|
|
27
|
+
apiKey,
|
|
28
|
+
...(apiUrl ? { baseUrl: apiUrl } : {}),
|
|
29
|
+
retry: { maxAttempts: 4, initialDelayMs: 500, maxDelayMs: 10_000, maxElapsedMs: 90_000 }
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
console.log(`opening session (dev)...`);
|
|
33
|
+
const session = await aex.openSession({
|
|
34
|
+
provider: Providers.DEEPSEEK,
|
|
35
|
+
model: Models.DEEPSEEK_V4_FLASH,
|
|
36
|
+
system: "Reply with a single short sentence. Never use tools or write files.",
|
|
37
|
+
includeBuiltinTools: false,
|
|
38
|
+
tools: [],
|
|
39
|
+
runtime: Sizes.SHARED_0_25X_1GB,
|
|
40
|
+
overrides: { idleTtl: "10m", timeout: "5m", maxSpendUsd: 1 },
|
|
41
|
+
apiKeys: { deepseek: deepseekKey }
|
|
42
|
+
});
|
|
43
|
+
console.log(`session: ${session.id}`);
|
|
44
|
+
|
|
45
|
+
type Sample = { turn: number; turnMs: number; settleGapMs: number; polls: number; timedOut: boolean };
|
|
46
|
+
const samples: Sample[] = [];
|
|
47
|
+
|
|
48
|
+
for (let i = 0; i < turns; i++) {
|
|
49
|
+
const stream = session.send(`Say hello #${i + 1} in one short sentence.`);
|
|
50
|
+
const tStart = performance.now();
|
|
51
|
+
let tRunFinished = 0;
|
|
52
|
+
let errored = false;
|
|
53
|
+
for await (const event of stream) {
|
|
54
|
+
if (event.isRunError()) {
|
|
55
|
+
errored = true;
|
|
56
|
+
tRunFinished = performance.now();
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
if (event.isRunFinished()) {
|
|
60
|
+
tRunFinished = performance.now();
|
|
61
|
+
break; // default turn stream would end HERE
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (tRunFinished === 0) tRunFinished = performance.now();
|
|
65
|
+
const turnMs = tRunFinished - tStart;
|
|
66
|
+
|
|
67
|
+
// Tight-poll the authoritative record until it leaves running.
|
|
68
|
+
let polls = 0;
|
|
69
|
+
let tIdle = 0;
|
|
70
|
+
let timedOut = false;
|
|
71
|
+
const deadline = performance.now() + 90_000;
|
|
72
|
+
for (;;) {
|
|
73
|
+
polls++;
|
|
74
|
+
const rec = await session.refresh().catch(() => undefined);
|
|
75
|
+
const status = rec?.status;
|
|
76
|
+
if (status === "idle" || status === "suspended" || status === "error") {
|
|
77
|
+
tIdle = performance.now();
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
if (performance.now() >= deadline) {
|
|
81
|
+
tIdle = performance.now();
|
|
82
|
+
timedOut = true;
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
await sleep(pollMs);
|
|
86
|
+
}
|
|
87
|
+
const settleGapMs = tIdle - tRunFinished;
|
|
88
|
+
samples.push({ turn: i + 1, turnMs, settleGapMs, polls, timedOut });
|
|
89
|
+
console.log(
|
|
90
|
+
`turn ${String(i + 1).padStart(2)} turn=${fmt(turnMs)} settleGap=${fmt(settleGapMs)} polls=${polls}` +
|
|
91
|
+
(errored ? " (RUN_ERROR)" : "") +
|
|
92
|
+
(timedOut ? " (TIMEOUT>90s)" : "")
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const gaps = samples.map((s) => s.settleGapMs).sort((a, b) => a - b);
|
|
97
|
+
console.log("\n=== settle-gap distribution (park event -> record idle) ===");
|
|
98
|
+
console.log(`n=${gaps.length}`);
|
|
99
|
+
console.log(`min ${fmt(gaps[0])}`);
|
|
100
|
+
console.log(`median ${fmt(pct(gaps, 50))}`);
|
|
101
|
+
console.log(`p90 ${fmt(pct(gaps, 90))}`);
|
|
102
|
+
console.log(`max ${fmt(gaps[gaps.length - 1])}`);
|
|
103
|
+
console.log(`mean ${fmt(gaps.reduce((a, b) => a + b, 0) / gaps.length)}`);
|
|
104
|
+
console.log("\nInterpretation: settleGap is the per-turn latency Option B adds before the");
|
|
105
|
+
console.log("caller regains control (the turn stream would block until the record is idle).");
|
|
106
|
+
|
|
107
|
+
function pct(sorted: number[], p: number): number {
|
|
108
|
+
if (sorted.length === 0) return 0;
|
|
109
|
+
const idx = Math.min(sorted.length - 1, Math.floor((p / 100) * sorted.length));
|
|
110
|
+
return sorted[idx];
|
|
111
|
+
}
|
|
112
|
+
function fmt(ms: number): string {
|
|
113
|
+
return ms >= 1000 ? `${(ms / 1000).toFixed(2)}s` : `${Math.round(ms)}ms`;
|
|
114
|
+
}
|
|
115
|
+
function sleep(ms: number): Promise<void> {
|
|
116
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
117
|
+
}
|
|
118
|
+
function required(name: string): string {
|
|
119
|
+
const v = process.env[name];
|
|
120
|
+
if (!v) {
|
|
121
|
+
console.error(`Missing env var ${name}`);
|
|
122
|
+
process.exit(1);
|
|
123
|
+
}
|
|
124
|
+
return v;
|
|
125
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aexhq/sdk",
|
|
3
|
-
"version": "0.40.
|
|
3
|
+
"version": "0.40.7",
|
|
4
4
|
"description": "TypeScript SDK for running autonomous agent sessions across providers (Anthropic, OpenAI, DeepSeek, Gemini, Mistral) behind one interface.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|