@aexhq/sdk 0.38.1 → 0.40.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 -17
- package/dist/_contracts/api-key.d.ts +49 -0
- package/dist/_contracts/api-key.js +87 -0
- package/dist/_contracts/bundle-manifest.d.ts +86 -0
- package/dist/_contracts/bundle-manifest.js +157 -0
- package/dist/_contracts/error-codes.d.ts +26 -0
- package/dist/_contracts/error-codes.js +79 -0
- package/dist/_contracts/error-factory.d.ts +32 -0
- package/dist/_contracts/error-factory.js +142 -0
- package/dist/_contracts/event-envelope.d.ts +33 -10
- package/dist/_contracts/event-envelope.js +46 -10
- package/dist/_contracts/event-view.d.ts +123 -0
- package/dist/_contracts/event-view.js +120 -0
- package/dist/_contracts/http.js +12 -3
- package/dist/_contracts/index.d.ts +8 -4
- package/dist/_contracts/index.js +11 -7
- package/dist/_contracts/models.d.ts +15 -0
- package/dist/_contracts/models.js +33 -0
- package/dist/_contracts/operations.d.ts +70 -2
- package/dist/_contracts/operations.js +143 -7
- package/dist/_contracts/run-config.d.ts +35 -10
- package/dist/_contracts/run-config.js +17 -5
- package/dist/_contracts/run-record.d.ts +3 -2
- package/dist/_contracts/runtime-types.d.ts +148 -36
- package/dist/_contracts/runtime-types.js +33 -1
- package/dist/_contracts/sdk-errors.d.ts +61 -2
- package/dist/_contracts/sdk-errors.js +83 -3
- package/dist/_contracts/sdk-secrets.js +31 -6
- package/dist/_contracts/stable.d.ts +14 -0
- package/dist/_contracts/stable.js +14 -0
- package/dist/_contracts/status.d.ts +28 -1
- package/dist/_contracts/status.js +48 -3
- package/dist/_contracts/submission.d.ts +157 -14
- package/dist/_contracts/submission.js +319 -55
- package/dist/_contracts/suggest.d.ts +15 -0
- package/dist/_contracts/suggest.js +54 -0
- package/dist/asset-upload.d.ts +27 -1
- package/dist/asset-upload.js +219 -4
- package/dist/asset-upload.js.map +1 -1
- package/dist/bundle.d.ts +23 -14
- package/dist/bundle.js +39 -20
- package/dist/bundle.js.map +1 -1
- package/dist/canonical-zip.d.ts +68 -0
- package/dist/canonical-zip.js +307 -0
- package/dist/canonical-zip.js.map +1 -0
- package/dist/cli.mjs +1927 -326
- package/dist/cli.mjs.sha256 +1 -1
- package/dist/client.d.ts +273 -70
- package/dist/client.js +885 -335
- package/dist/client.js.map +1 -1
- package/dist/fetch-archive.js +14 -14
- package/dist/fetch-archive.js.map +1 -1
- package/dist/file.d.ts +33 -6
- package/dist/file.js +120 -54
- package/dist/file.js.map +1 -1
- package/dist/index.d.ts +23 -14
- package/dist/index.js +31 -14
- package/dist/index.js.map +1 -1
- package/dist/node-fs.d.ts +26 -9
- package/dist/node-fs.js +13 -38
- package/dist/node-fs.js.map +1 -1
- package/dist/node-walk.d.ts +69 -0
- package/dist/node-walk.js +146 -0
- package/dist/node-walk.js.map +1 -0
- package/dist/retry.d.ts +9 -13
- package/dist/retry.js +18 -17
- package/dist/retry.js.map +1 -1
- package/dist/skill.d.ts +151 -0
- package/dist/skill.js +298 -0
- package/dist/skill.js.map +1 -0
- package/dist/tool.d.ts +14 -2
- package/dist/tool.js +33 -7
- package/dist/tool.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/docs/authentication.md +29 -5
- package/docs/billing.md +6 -0
- package/docs/concepts/agent-tools.md +11 -0
- package/docs/concepts/composition.md +3 -3
- package/docs/defaults.md +1 -0
- package/docs/errors.md +64 -4
- package/docs/events.md +84 -49
- package/docs/limits-and-quotas.md +24 -0
- package/docs/mcp.md +3 -2
- package/docs/networking.md +7 -1
- package/docs/outputs.md +36 -7
- package/docs/provider-runtime-capabilities.md +1 -1
- package/docs/quickstart.md +17 -7
- package/docs/run-config.md +3 -3
- package/docs/secrets.md +14 -0
- package/docs/skills.md +74 -44
- package/docs/vision-skills.md +3 -3
- package/examples/feature-tour.ts +4 -6
- package/examples/spike-settle-latency.ts +125 -0
- package/package.json +4 -3
- package/dist/_contracts/event-guards.d.ts +0 -67
- package/dist/_contracts/event-guards.js +0 -36
- package/dist/skill-tool.d.ts +0 -102
- package/dist/skill-tool.js +0 -190
- package/dist/skill-tool.js.map +0 -1
package/docs/skills.md
CHANGED
|
@@ -5,76 +5,106 @@ title: Skills
|
|
|
5
5
|
# Skills
|
|
6
6
|
|
|
7
7
|
A skill is a bundle of instructional or executable content (`SKILL.md` plus any
|
|
8
|
-
supporting files) that the agent can pull into context on demand.
|
|
9
|
-
|
|
10
|
-
`
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
Build a skill
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
- **Local directory:** `
|
|
19
|
-
|
|
20
|
-
|
|
8
|
+
supporting files) that the agent can pull into context on demand. Skills are a
|
|
9
|
+
**first-class concept, separate from tools**: you pass them on the session's own
|
|
10
|
+
`skills` input (not `tools`), and the run gets a single `skills` meta-tool the
|
|
11
|
+
model uses to list and load them.
|
|
12
|
+
|
|
13
|
+
Build a skill with the `Skill.from*` factories. Each reads a bundle, lifts the
|
|
14
|
+
`name` and `description` from the `SKILL.md` YAML frontmatter (an explicit
|
|
15
|
+
`{ name }` overrides the frontmatter), canonically zips + hashes the bytes, and
|
|
16
|
+
returns a `Skill`:
|
|
17
|
+
|
|
18
|
+
- **Local directory:** `Skill.fromDir(rootDir, { name? })` reads a folder with
|
|
19
|
+
`SKILL.md` at its root. With no `{ name }` and no frontmatter `name:`, the
|
|
20
|
+
slugified directory basename is used (Bun/Node filesystem runtimes).
|
|
21
|
+
- **Signed URL:** `Skill.fromUrl(url, { name?, sha256?, timeoutMs?, fetch? })`
|
|
21
22
|
fetches a zip archive with `SKILL.md` at the archive root (universal — needs a
|
|
22
23
|
global `fetch`, or pass one).
|
|
24
|
+
- **In-memory:** `Skill.fromFiles({ name?, files })` from a path→bytes map,
|
|
25
|
+
`Skill.fromContent(skillMd, { name? })` from a single `SKILL.md` string, or
|
|
26
|
+
`Skill.fromBytes({ name?, zip })` from a pre-zipped bundle.
|
|
27
|
+
|
|
28
|
+
Names must match the skill-name pattern (`^[a-z0-9][a-z0-9_-]{0,127}$`), must not
|
|
29
|
+
contain `__` (reserved for MCP tools), and must not be the reserved names
|
|
30
|
+
`skills` / `skill`. The frontmatter `description` (max 2048 chars) is required.
|
|
23
31
|
|
|
24
32
|
```ts
|
|
25
|
-
import { Aex, Models,
|
|
33
|
+
import { Aex, Models, Skill } from "@aexhq/sdk";
|
|
26
34
|
|
|
27
35
|
const aex = new Aex({ apiKey });
|
|
28
36
|
|
|
29
37
|
await aex.run({
|
|
30
38
|
model: Models.CLAUDE_HAIKU_4_5,
|
|
31
39
|
message,
|
|
32
|
-
|
|
40
|
+
skills: [await Skill.fromDir("./skills/rules", { name: "rules" })],
|
|
33
41
|
apiKeys: { anthropic: apiKey }
|
|
34
42
|
});
|
|
35
43
|
```
|
|
36
44
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
45
|
+
## By-name, mutable binding
|
|
46
|
+
|
|
47
|
+
A skill is bound to the workspace **by name**. `skill.upload(client)` UPSERTS the
|
|
48
|
+
workspace skill under its name; a re-upload under the same name changes what
|
|
49
|
+
every future run referencing that name sees. The wire ref is name-only —
|
|
50
|
+
`{ kind:"skill", name }` — with no `assetId` and no hash, so the idempotency hash
|
|
51
|
+
of two runs that reference the same skill name is identical even if the skill's
|
|
52
|
+
bytes changed between them.
|
|
53
|
+
|
|
54
|
+
Passing a **draft** `Skill` in `skills:` auto-upserts it on submit (the same
|
|
55
|
+
ergonomic as a draft `Tool` / `File`). To upsert explicitly and reuse the name
|
|
56
|
+
across many runs:
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
const rules = await Skill.fromDir("./skills/rules", { name: "rules" });
|
|
60
|
+
await rules.upload(aex); // stage bytes + PUT /skills/rules
|
|
61
|
+
await aex.run({ model, message, skills: [rules], apiKeys });
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
`upload()` is idempotent on an instance (it caches the resolved name, so reuse
|
|
65
|
+
across submits skips the round-trip) and identical bytes are a server no-op.
|
|
42
66
|
|
|
43
|
-
|
|
67
|
+
### How a skill rides on the wire
|
|
44
68
|
|
|
45
|
-
Before the session lands, `openSession` / `run` walks the `
|
|
46
|
-
|
|
69
|
+
Before the session lands, `openSession` / `run` walks the `skills` array and, for
|
|
70
|
+
each draft, upserts it by name:
|
|
47
71
|
|
|
48
72
|
1. `POST /assets/presign` checks for a dedup hit and, when needed, returns a
|
|
49
73
|
signed upload URL.
|
|
50
74
|
2. The SDK PUTs bytes directly to object storage with the signed checksum headers.
|
|
51
75
|
3. `POST /assets/finalize` confirms the object exists.
|
|
76
|
+
4. `PUT /skills/{name}` binds that content hash to the mutable workspace skill
|
|
77
|
+
name (identical `contentHash` ⇒ no-op).
|
|
78
|
+
|
|
79
|
+
The submission then carries only `submission.skills: [{ kind:"skill", name }]`.
|
|
80
|
+
The four prepare passes (tools, skills, agentsMd, files) upload with bounded
|
|
81
|
+
concurrency and run concurrently with each other.
|
|
82
|
+
|
|
83
|
+
## The `skills` meta-tool
|
|
52
84
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
the same bundle is a no-op upload; a `SkillTool` instance also caches its resolved
|
|
56
|
-
asset id, so reusing the same instance across sessions skips the re-upload. A URL
|
|
57
|
-
is an ingestion source, not a persistent reference — the SDK snapshots the fetched
|
|
58
|
-
bytes into the asset store, and the hosted platform never fetches the
|
|
59
|
-
caller-controlled URL.
|
|
85
|
+
When a run references at least one skill, the platform injects a single `skills`
|
|
86
|
+
meta-tool:
|
|
60
87
|
|
|
61
|
-
|
|
88
|
+
- `skills({ action: "list" })` returns each skill's `name` + `description`
|
|
89
|
+
(cheap — do this first).
|
|
90
|
+
- `skills({ action: "load", name: "<skill>"})` reads that skill's full `SKILL.md`
|
|
91
|
+
instructions into context.
|
|
62
92
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
93
|
+
A skill's supporting files are staged to disk under `/workspace/skills/<name>/`
|
|
94
|
+
from the first turn, so `load` pulls the instructions while `read_file` / `bash`
|
|
95
|
+
read the rest. The run resolves each referenced name to the workspace skill's
|
|
96
|
+
current bytes at submit time and snapshots them into durable run asset storage
|
|
97
|
+
(`runs/<runId>/assets/<hash>`); run-scoped copies are removed by run deletion or
|
|
98
|
+
retention cleanup.
|
|
67
99
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
100
|
+
## Workspace skill admin
|
|
101
|
+
|
|
102
|
+
`client.skills` is the metadata surface for the named registry:
|
|
103
|
+
|
|
104
|
+
- `client.skills.list()` — skill metadata (never bytes).
|
|
105
|
+
- `client.skills.get(name)` — one skill's metadata.
|
|
106
|
+
- `client.skills.delete(name)` — remove a workspace skill.
|
|
74
107
|
|
|
75
108
|
Skills that call external HTTP APIs should read credentials from
|
|
76
109
|
`environment.secrets` and use the normal client for that service. See
|
|
77
110
|
[Credentials](credentials.md) for the secret model.
|
|
78
|
-
|
|
79
|
-
Run-scoped asset copies are part of the run record and are removed by run deletion
|
|
80
|
-
or retention cleanup.
|
package/docs/vision-skills.md
CHANGED
|
@@ -16,14 +16,14 @@ per-noun "does the frame depict X?" verdict.
|
|
|
16
16
|
## Submit the run
|
|
17
17
|
|
|
18
18
|
```ts
|
|
19
|
-
import { Aex, Models, Secret,
|
|
19
|
+
import { Aex, Models, Secret, Skill } from "@aexhq/sdk";
|
|
20
20
|
|
|
21
21
|
const aex = new Aex({ apiKey: process.env.AEX_API_KEY! });
|
|
22
22
|
|
|
23
23
|
const result = await aex.run({
|
|
24
24
|
model: Models.CLAUDE_HAIKU_4_5,
|
|
25
25
|
message: "Read skills/frame-vision-gate/SKILL.md, then caption and verify the frame.",
|
|
26
|
-
|
|
26
|
+
skills: [await Skill.fromDir("./vision-skill", { name: "frame-vision-gate" })],
|
|
27
27
|
environment: {
|
|
28
28
|
secrets: {
|
|
29
29
|
DOUBAO_API_KEY: Secret.value(process.env.DOUBAO_API_KEY!)
|
|
@@ -39,7 +39,7 @@ const result = await aex.run({
|
|
|
39
39
|
console.log(result.runId, result.text);
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
-
`
|
|
42
|
+
`Skill.fromDir("./vision-skill", ...)` is resolved relative to the process
|
|
43
43
|
CWD. Run the script from the directory that contains `vision-skill/` (in this
|
|
44
44
|
repo, `examples/`).
|
|
45
45
|
|
package/examples/feature-tour.ts
CHANGED
|
@@ -22,7 +22,6 @@ import {
|
|
|
22
22
|
BuiltinTools,
|
|
23
23
|
File,
|
|
24
24
|
isRateLimited,
|
|
25
|
-
isTextMessage,
|
|
26
25
|
McpServer,
|
|
27
26
|
Models,
|
|
28
27
|
Providers,
|
|
@@ -200,12 +199,11 @@ for (;;) {
|
|
|
200
199
|
break;
|
|
201
200
|
}
|
|
202
201
|
const event = next.value;
|
|
203
|
-
if (isTextMessage(
|
|
202
|
+
if (event.isTextMessage()) {
|
|
204
203
|
process.stdout.write(event.data.text);
|
|
205
|
-
} else if (event.
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
} else if (event.type === "TOOL_CALL_RESULT") {
|
|
204
|
+
} else if (event.isToolCallStart()) {
|
|
205
|
+
process.stdout.write(`\n[tool:start] ${event.data.name}\n`);
|
|
206
|
+
} else if (event.isToolCallResult()) {
|
|
209
207
|
process.stdout.write("[tool:result]\n");
|
|
210
208
|
}
|
|
211
209
|
}
|
|
@@ -0,0 +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
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aexhq/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.40.0",
|
|
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": {
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
],
|
|
28
28
|
"scripts": {
|
|
29
29
|
"build": "bun ../../scripts/with-generated-dist-lock.mjs bun run build:unlocked",
|
|
30
|
-
"build:unlocked": "bun ./scripts/clean-dist.mjs && bun run --cwd ../.. --filter @aexhq/contracts build && bun run --cwd ../.. --filter @aexhq/cli build &&
|
|
30
|
+
"build:unlocked": "bun ./scripts/clean-dist.mjs && bun run --cwd ../.. --filter @aexhq/contracts build && tsc -p tsconfig.build.json && bun run --cwd ../.. --filter @aexhq/cli build && bun ./scripts/bundle-cli.mjs && bun ./scripts/inline-contracts.mjs",
|
|
31
31
|
"lint": "bun ../../scripts/with-generated-dist-lock.mjs bun run lint:unlocked",
|
|
32
32
|
"lint:unlocked": "tsc --noEmit",
|
|
33
33
|
"test": "bun run test:unit",
|
|
@@ -47,6 +47,7 @@
|
|
|
47
47
|
"bun": ">=1.3.14"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"fflate": "0.8.2"
|
|
50
|
+
"fflate": "0.8.2",
|
|
51
|
+
"ignore": "7.0.5"
|
|
51
52
|
}
|
|
52
53
|
}
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Type-narrowing guards over the loose {@link RunEvent} `listEvents` shape.
|
|
3
|
-
*
|
|
4
|
-
* The envelope guards in `event-envelope.ts` operate on the coordinator
|
|
5
|
-
* {@link import("./event-envelope.js").AexEvent} and return a plain `boolean`.
|
|
6
|
-
* These mirror the same AG-UI discriminants but operate on the {@link RunEvent}
|
|
7
|
-
* snapshot shape returned by `listEvents` / `RunResult.events` and NARROW
|
|
8
|
-
* `event.data` to the fields that event type carries, so a consumer reads
|
|
9
|
-
* `event.data.text` (etc.) without a manual cast.
|
|
10
|
-
*
|
|
11
|
-
* They are DISCRIMINANT-only at runtime (they test `event.type`), matching the
|
|
12
|
-
* envelope guards: the narrowed `data` shape is a typing convenience, not a deep
|
|
13
|
-
* runtime validation. Parse/verify the payload fields before trusting them when
|
|
14
|
-
* the producer is untrusted.
|
|
15
|
-
*
|
|
16
|
-
* The parameter is the minimal `{ type }` discriminant both the {@link RunEvent}
|
|
17
|
-
* snapshot and the coordinator `AexEvent` envelope satisfy, so the guards accept
|
|
18
|
-
* either shape while narrowing to the {@link RunEvent}-typed payloads.
|
|
19
|
-
*/
|
|
20
|
-
import type { RunEvent } from "./runtime-types.js";
|
|
21
|
-
/** A `TEXT_MESSAGE_CONTENT` run event with its assistant-text payload narrowed. */
|
|
22
|
-
export interface TextMessageRunEvent extends RunEvent {
|
|
23
|
-
readonly type: "TEXT_MESSAGE_CONTENT";
|
|
24
|
-
readonly data: {
|
|
25
|
-
readonly text: string;
|
|
26
|
-
readonly messageId?: string;
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
/** A `TOOL_CALL_START` run event with the tool-call id/name/args narrowed. */
|
|
30
|
-
export interface ToolCallStartRunEvent extends RunEvent {
|
|
31
|
-
readonly type: "TOOL_CALL_START";
|
|
32
|
-
readonly data: {
|
|
33
|
-
readonly id: string;
|
|
34
|
-
readonly name: string;
|
|
35
|
-
readonly arguments?: Record<string, unknown>;
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
/** A `TOOL_CALL_RESULT` run event with the correlating id + result narrowed. */
|
|
39
|
-
export interface ToolCallResultRunEvent extends RunEvent {
|
|
40
|
-
readonly type: "TOOL_CALL_RESULT";
|
|
41
|
-
readonly data: {
|
|
42
|
-
readonly id: string;
|
|
43
|
-
readonly content?: unknown;
|
|
44
|
-
readonly isError?: boolean;
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
/** A terminal `RUN_FINISHED` run event. */
|
|
48
|
-
export interface RunFinishedRunEvent extends RunEvent {
|
|
49
|
-
readonly type: "RUN_FINISHED";
|
|
50
|
-
readonly data: Record<string, unknown>;
|
|
51
|
-
}
|
|
52
|
-
/** True for an assistant text event; narrows `event.data.text` to `string`. */
|
|
53
|
-
export declare function isTextMessage(event: {
|
|
54
|
-
readonly type: string;
|
|
55
|
-
}): event is TextMessageRunEvent;
|
|
56
|
-
/** True for a tool-call start event; narrows `event.data` to `{ id, name }`. */
|
|
57
|
-
export declare function isToolCallStart(event: {
|
|
58
|
-
readonly type: string;
|
|
59
|
-
}): event is ToolCallStartRunEvent;
|
|
60
|
-
/** True for a tool-call result event; narrows `event.data` to `{ id, content }`. */
|
|
61
|
-
export declare function isToolCallResult(event: {
|
|
62
|
-
readonly type: string;
|
|
63
|
-
}): event is ToolCallResultRunEvent;
|
|
64
|
-
/** True for the terminal success event; narrows `event.data` to a record. */
|
|
65
|
-
export declare function isRunFinished(event: {
|
|
66
|
-
readonly type: string;
|
|
67
|
-
}): event is RunFinishedRunEvent;
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Type-narrowing guards over the loose {@link RunEvent} `listEvents` shape.
|
|
3
|
-
*
|
|
4
|
-
* The envelope guards in `event-envelope.ts` operate on the coordinator
|
|
5
|
-
* {@link import("./event-envelope.js").AexEvent} and return a plain `boolean`.
|
|
6
|
-
* These mirror the same AG-UI discriminants but operate on the {@link RunEvent}
|
|
7
|
-
* snapshot shape returned by `listEvents` / `RunResult.events` and NARROW
|
|
8
|
-
* `event.data` to the fields that event type carries, so a consumer reads
|
|
9
|
-
* `event.data.text` (etc.) without a manual cast.
|
|
10
|
-
*
|
|
11
|
-
* They are DISCRIMINANT-only at runtime (they test `event.type`), matching the
|
|
12
|
-
* envelope guards: the narrowed `data` shape is a typing convenience, not a deep
|
|
13
|
-
* runtime validation. Parse/verify the payload fields before trusting them when
|
|
14
|
-
* the producer is untrusted.
|
|
15
|
-
*
|
|
16
|
-
* The parameter is the minimal `{ type }` discriminant both the {@link RunEvent}
|
|
17
|
-
* snapshot and the coordinator `AexEvent` envelope satisfy, so the guards accept
|
|
18
|
-
* either shape while narrowing to the {@link RunEvent}-typed payloads.
|
|
19
|
-
*/
|
|
20
|
-
/** True for an assistant text event; narrows `event.data.text` to `string`. */
|
|
21
|
-
export function isTextMessage(event) {
|
|
22
|
-
return event.type === "TEXT_MESSAGE_CONTENT";
|
|
23
|
-
}
|
|
24
|
-
/** True for a tool-call start event; narrows `event.data` to `{ id, name }`. */
|
|
25
|
-
export function isToolCallStart(event) {
|
|
26
|
-
return event.type === "TOOL_CALL_START";
|
|
27
|
-
}
|
|
28
|
-
/** True for a tool-call result event; narrows `event.data` to `{ id, content }`. */
|
|
29
|
-
export function isToolCallResult(event) {
|
|
30
|
-
return event.type === "TOOL_CALL_RESULT";
|
|
31
|
-
}
|
|
32
|
-
/** True for the terminal success event; narrows `event.data` to a record. */
|
|
33
|
-
export function isRunFinished(event) {
|
|
34
|
-
return event.type === "RUN_FINISHED";
|
|
35
|
-
}
|
|
36
|
-
//# sourceMappingURL=event-guards.js.map
|
package/dist/skill-tool.d.ts
DELETED
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
import { type FetchLike, type SkillToolRef } from "./_contracts/index.js";
|
|
2
|
-
import { type SkillFiles } from "./bundle.js";
|
|
3
|
-
/**
|
|
4
|
-
* A skill re-expressed as a TOOL. `Tools.fromSkillDir` / `Tools.fromSkillUrl`
|
|
5
|
-
* read a skill folder/zip, lift the tool `name` + `description` from the
|
|
6
|
-
* `SKILL.md` YAML frontmatter, and canonically bundle+hash the bytes. The
|
|
7
|
-
* result rides in the session's `tools` array (next to builtin names and custom
|
|
8
|
-
* {@link Tool} bundles); `client.run` / `openSession` uploads the bundle as an
|
|
9
|
-
* asset before the run lands, and the wire ref becomes a
|
|
10
|
-
* `{ kind:"skill", assetId, name, description }` {@link SkillToolRef}.
|
|
11
|
-
*
|
|
12
|
-
* At run time the model calls the no-arg load-tool to pull the skill's
|
|
13
|
-
* `SKILL.md` body into context; the bundle's files are eagerly staged to
|
|
14
|
-
* `/workspace/skills/<name>/`.
|
|
15
|
-
*
|
|
16
|
-
* Asset deduplication makes the same bytes a no-op upload on subsequent runs.
|
|
17
|
-
* A URL is an ingestion source, not a persistent reference.
|
|
18
|
-
*/
|
|
19
|
-
export declare class SkillTool {
|
|
20
|
-
#private;
|
|
21
|
-
/** Internal constructor. Use the `Tools.fromSkill*` factories. */
|
|
22
|
-
private constructor();
|
|
23
|
-
/**
|
|
24
|
-
* The wire-level reference. Returns the SDK-private draft shape for
|
|
25
|
-
* un-uploaded skill-tools (kind:"draft", with name + description +
|
|
26
|
-
* contentHash). `client.run` / `openSession` walks these and uploads them
|
|
27
|
-
* before the run lands.
|
|
28
|
-
*/
|
|
29
|
-
get ref(): SkillToolRef | DraftSkillToolRef;
|
|
30
|
-
/** True for local-bytes skill-tools that haven't been uploaded yet. */
|
|
31
|
-
get isDraft(): boolean;
|
|
32
|
-
/** Internal: the asset id resolved on a prior use, or undefined. */
|
|
33
|
-
get _cachedAssetId(): string | undefined;
|
|
34
|
-
/** Internal: remember the asset id resolved for this draft's bytes. */
|
|
35
|
-
_rememberAsset(assetId: string): void;
|
|
36
|
-
/** Internal: build a draft from an already-loaded skill files map. */
|
|
37
|
-
static _fromFiles(source: string, files: SkillFiles, nameOverride: string | undefined): Promise<SkillTool>;
|
|
38
|
-
/**
|
|
39
|
-
* Internal: yield the draft's bytes + metadata so `client.run` / `openSession`
|
|
40
|
-
* can upload the asset. Idempotent (non-consuming): a SkillTool is reusable
|
|
41
|
-
* across sessions — the first use caches the resolved asset id (see
|
|
42
|
-
* `_rememberAsset`) so later uses reuse it instead of re-uploading.
|
|
43
|
-
*
|
|
44
|
-
* Returns undefined for already-uploaded skill-tools.
|
|
45
|
-
*/
|
|
46
|
-
_takeDraftBundle(): {
|
|
47
|
-
name: string;
|
|
48
|
-
description: string;
|
|
49
|
-
contentHash: string;
|
|
50
|
-
bytes: Uint8Array;
|
|
51
|
-
} | undefined;
|
|
52
|
-
toJSON(): SkillToolRef;
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* SDK-internal draft skill-tool marker. Never reaches the wire; the
|
|
56
|
-
* materialize step inside `client.run` / `openSession` converts these to
|
|
57
|
-
* `kind:"skill"` refs once the bundle is uploaded.
|
|
58
|
-
*/
|
|
59
|
-
export interface DraftSkillToolRef {
|
|
60
|
-
readonly kind: "draft";
|
|
61
|
-
readonly name: string;
|
|
62
|
-
readonly description: string;
|
|
63
|
-
readonly contentHash: string;
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Factory namespace for skill-tools. Each factory reads a skill bundle, lifts
|
|
67
|
-
* `name` + `description` from the `SKILL.md` frontmatter (an explicit `name`
|
|
68
|
-
* argument overrides the frontmatter), and produces a {@link SkillTool} to pass
|
|
69
|
-
* in the session's `tools` array.
|
|
70
|
-
*/
|
|
71
|
-
export declare const Tools: {
|
|
72
|
-
/**
|
|
73
|
-
* Read a local skill directory and build a skill-tool. The directory must
|
|
74
|
-
* contain `SKILL.md` at its root, whose YAML frontmatter provides the tool
|
|
75
|
-
* `name` (unless overridden via `args.name`) and `description`. Symlinks and
|
|
76
|
-
* non-regular files are skipped. Bun/Node filesystem runtimes only.
|
|
77
|
-
*/
|
|
78
|
-
readonly fromSkillDir: (rootDir: string, args?: {
|
|
79
|
-
readonly name?: string;
|
|
80
|
-
}) => Promise<SkillTool>;
|
|
81
|
-
/**
|
|
82
|
-
* Fetch a zip-archived skill from a URL and build a skill-tool. The archive is
|
|
83
|
-
* downloaded in the SDK process, so the URL is caller-controlled — host the
|
|
84
|
-
* skill yourself and pass a temporary signed URL (e.g. an S3 presigned URL).
|
|
85
|
-
* Its bytes are optionally integrity-checked against `sha256`, unzipped, and
|
|
86
|
-
* reduced to the same files map as `Tools.fromSkillDir`, so a URL-sourced
|
|
87
|
-
* skill and the identical local skill produce the same canonical asset and
|
|
88
|
-
* dedup against each other.
|
|
89
|
-
*
|
|
90
|
-
* The archive must contain `SKILL.md` at its root, or inside a single
|
|
91
|
-
* top-level folder (which is stripped). The signed URL only needs to be valid
|
|
92
|
-
* for this call; `client.run` / `openSession` snapshots the bytes into the run.
|
|
93
|
-
*
|
|
94
|
-
* Universal (Bun / Node 18+ / browser): requires a global `fetch`, or pass one.
|
|
95
|
-
*/
|
|
96
|
-
readonly fromSkillUrl: (url: string, args?: {
|
|
97
|
-
readonly name?: string;
|
|
98
|
-
readonly sha256?: string;
|
|
99
|
-
readonly timeoutMs?: number;
|
|
100
|
-
readonly fetch?: FetchLike;
|
|
101
|
-
}) => Promise<SkillTool>;
|
|
102
|
-
};
|