@aexhq/sdk 0.33.0 → 0.34.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 +19 -27
- package/dist/_contracts/operations.d.ts +2 -54
- package/dist/_contracts/operations.js +2 -87
- package/dist/_contracts/run-config.d.ts +19 -13
- package/dist/_contracts/run-config.js +6 -33
- package/dist/_contracts/run-unit.d.ts +1 -33
- package/dist/_contracts/run-unit.js +2 -21
- package/dist/_contracts/runtime-sizes.d.ts +2 -2
- package/dist/_contracts/runtime-sizes.js +2 -2
- package/dist/_contracts/status.d.ts +2 -2
- package/dist/_contracts/status.js +3 -0
- package/dist/_contracts/submission.d.ts +22 -18
- package/dist/_contracts/submission.js +60 -42
- package/dist/agents-md.d.ts +5 -5
- package/dist/agents-md.js +7 -7
- package/dist/agents-md.js.map +1 -1
- package/dist/asset-upload.d.ts +4 -4
- package/dist/asset-upload.js +4 -4
- package/dist/bundle.d.ts +2 -2
- package/dist/bundle.js +2 -2
- package/dist/cli.mjs +354 -12982
- package/dist/cli.mjs.sha256 +1 -1
- package/dist/client.d.ts +218 -386
- package/dist/client.js +375 -645
- package/dist/client.js.map +1 -1
- package/dist/data-tools.d.ts +25 -22
- package/dist/data-tools.js +75 -62
- package/dist/data-tools.js.map +1 -1
- package/dist/fetch-archive.js +16 -16
- package/dist/fetch-archive.js.map +1 -1
- package/dist/file.d.ts +5 -5
- package/dist/file.js +7 -7
- package/dist/file.js.map +1 -1
- package/dist/index.d.ts +9 -9
- package/dist/index.js +14 -13
- package/dist/index.js.map +1 -1
- package/dist/mcp-server.d.ts +4 -4
- package/dist/mcp-server.js +4 -4
- package/dist/proxy-endpoint.d.ts +4 -4
- package/dist/proxy-endpoint.js +1 -1
- package/dist/secret.d.ts +8 -8
- package/dist/secret.js +8 -8
- package/dist/secret.js.map +1 -1
- package/dist/skill-tool.d.ts +102 -0
- package/dist/skill-tool.js +190 -0
- package/dist/skill-tool.js.map +1 -0
- package/dist/tool.d.ts +1 -1
- package/dist/tool.js +3 -3
- package/dist/tool.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/docs/cleanup.md +3 -3
- package/docs/concepts/agent-tools.md +6 -25
- package/docs/concepts/composition.md +15 -12
- package/docs/concepts/providers-and-runtimes.md +3 -3
- package/docs/concepts/runs.md +27 -22
- package/docs/credentials.md +52 -84
- package/docs/defaults.md +6 -6
- package/docs/events.md +65 -44
- package/docs/limits-and-quotas.md +3 -4
- package/docs/mcp.md +3 -3
- package/docs/networking.md +8 -8
- package/docs/outputs.md +44 -40
- package/docs/provider-runtime-capabilities.md +1 -1
- package/docs/public-surface.json +2 -2
- package/docs/quickstart.md +20 -10
- package/docs/run-config.md +12 -14
- package/docs/run-record.md +8 -8
- package/docs/secrets.md +16 -26
- package/docs/skills.md +55 -110
- package/docs/vision-skills.md +29 -40
- package/examples/chat-corpus.ts +8 -9
- package/package.json +1 -1
- package/dist/skill.d.ts +0 -149
- package/dist/skill.js +0 -198
- package/dist/skill.js.map +0 -1
package/docs/skills.md
CHANGED
|
@@ -4,132 +4,77 @@ title: Skills
|
|
|
4
4
|
|
|
5
5
|
# Skills
|
|
6
6
|
|
|
7
|
-
A skill is
|
|
8
|
-
the
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
- **
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
All three sources normalize to the same content-addressed asset. Identical bytes
|
|
24
|
-
dedup by hash, so repeated submissions of the same bundle are no-op uploads.
|
|
25
|
-
There is no per-run auto-suffixed `skl_*` row for inline skills.
|
|
26
|
-
|
|
27
|
-
## Materialization
|
|
28
|
-
|
|
29
|
-
For each run, the platform copies referenced skill assets into durable run asset
|
|
30
|
-
storage (`runs/<runId>/assets/<hash>`) and the runner downloads them into the
|
|
31
|
-
workspace under `skills/<name>/`.
|
|
32
|
-
|
|
33
|
-
A bundle's `SKILL.md` is mounted at `skills/<name>/SKILL.md`, and the agent's
|
|
34
|
-
instructions list each mounted skill with that path. The full skill body stays
|
|
35
|
-
on disk, so prompts or `AGENTS.md` guidance that rely on a skill should tell the
|
|
36
|
-
agent when to read or use it. Bundles without `SKILL.md` are still mounted as
|
|
37
|
-
files at `skills/<name>/`, but nothing prompts the agent to read them; reference
|
|
38
|
-
them explicitly from the prompt or your `AGENTS.md`.
|
|
39
|
-
|
|
40
|
-
The platform also mounts the `aex` CLI and a per-run manifest into every run.
|
|
41
|
-
Skills call managed HTTP proxy endpoints through the mounted CLI
|
|
42
|
-
(`aex proxy ...`); see `credentials.md` for the policy and auth model.
|
|
43
|
-
|
|
44
|
-
Run-scoped asset copies are part of the run record and are removed by run deletion
|
|
45
|
-
or retention cleanup. Catalog assets are separate workspace records: deleting a
|
|
46
|
-
catalog skill hard-deletes its metadata and removes the shared asset object only
|
|
47
|
-
when no other catalog row still references those bytes. Existing run snapshots
|
|
48
|
-
keep their run-scoped copy.
|
|
49
|
-
|
|
50
|
-
## Inline And Local Drafts
|
|
51
|
-
|
|
52
|
-
`Skill.fromFiles({ name, files })`, `Skill.fromPath(rootDir, { name })`, and
|
|
53
|
-
`Skill.fromUrl(url, { name })` build an unstaged `Skill`. The instance carries
|
|
54
|
-
canonical zip bytes and a `sha256:<hex>` content hash.
|
|
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. In the SDK a
|
|
9
|
+
skill is expressed as a per-skill **load-tool**: it rides in the session's
|
|
10
|
+
`tools` array next to builtin tool names and custom `Tool` bundles, and the model
|
|
11
|
+
loads it by calling it.
|
|
12
|
+
|
|
13
|
+
Build a skill-tool with the `Tools.fromSkill*` factories. Each factory reads a
|
|
14
|
+
skill bundle, lifts the tool `name` and `description` from the `SKILL.md` YAML
|
|
15
|
+
frontmatter (an explicit `{ name }` overrides the frontmatter), canonically
|
|
16
|
+
zips + hashes the bytes, and returns a `SkillTool`:
|
|
17
|
+
|
|
18
|
+
- **Local directory:** `Tools.fromSkillDir(rootDir, { name? })` reads a folder
|
|
19
|
+
that has `SKILL.md` at its root (Bun/Node filesystem runtimes).
|
|
20
|
+
- **Signed URL:** `Tools.fromSkillUrl(url, { name?, sha256?, timeoutMs?, fetch? })`
|
|
21
|
+
fetches a zip archive with `SKILL.md` at the archive root (universal — needs a
|
|
22
|
+
global `fetch`, or pass one).
|
|
55
23
|
|
|
56
24
|
```ts
|
|
57
|
-
import {
|
|
25
|
+
import { Aex, Models, Tools } from "@aexhq/sdk";
|
|
58
26
|
|
|
59
|
-
const aex = new
|
|
27
|
+
const aex = new Aex({ apiToken });
|
|
60
28
|
|
|
61
|
-
await aex.
|
|
29
|
+
await aex.run({
|
|
62
30
|
model: Models.CLAUDE_HAIKU_4_5,
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
31
|
+
message,
|
|
32
|
+
tools: [await Tools.fromSkillDir("./skills/rules", { name: "rules" })],
|
|
33
|
+
apiKeys: { anthropic: apiKey }
|
|
66
34
|
});
|
|
67
35
|
```
|
|
68
36
|
|
|
69
|
-
|
|
70
|
-
|
|
37
|
+
`Tools.fromSkillDir("./skills/rules", …)` resolves relative to the process CWD,
|
|
38
|
+
so run the script from the directory that *contains* `skills/`. The `SKILL.md`
|
|
39
|
+
frontmatter must supply a `description` (max 2048 chars) and, unless you pass
|
|
40
|
+
`{ name }`, a `name`. Names must match the tool-name pattern and must not contain
|
|
41
|
+
`__` (that separator is reserved for MCP tools).
|
|
42
|
+
|
|
43
|
+
## How a skill-tool rides on the wire
|
|
44
|
+
|
|
45
|
+
Before the session lands, `openSession` / `run` walks the `tools` array and
|
|
46
|
+
uploads each draft skill-tool's bundle through the asset upload flow:
|
|
71
47
|
|
|
72
48
|
1. `POST /assets/presign` checks for a dedup hit and, when needed, returns a
|
|
73
49
|
signed upload URL.
|
|
74
50
|
2. The SDK PUTs bytes directly to object storage with the signed checksum headers.
|
|
75
51
|
3. `POST /assets/finalize` confirms the object exists.
|
|
76
52
|
|
|
77
|
-
The
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
```ts
|
|
85
|
-
const draft = await Skill.fromFiles({ name: "rules", files });
|
|
86
|
-
const uploaded = await draft.upload(aex);
|
|
87
|
-
|
|
88
|
-
await aex.submit({
|
|
89
|
-
model: Models.CLAUDE_HAIKU_4_5,
|
|
90
|
-
prompt,
|
|
91
|
-
skills: [uploaded],
|
|
92
|
-
secrets: { apiKeys: { anthropic: apiKey } }
|
|
93
|
-
});
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
The returned `uploaded` skill carries a plain `kind:"asset"` ref. Submitting it
|
|
97
|
-
does not upload bytes again.
|
|
98
|
-
|
|
99
|
-
## Fetch From A Signed URL
|
|
100
|
-
|
|
101
|
-
When your app runs in the cloud with limited local storage, host the skill
|
|
102
|
-
yourself as a zip archive with `SKILL.md` at the archive root and pass a
|
|
103
|
-
temporary signed URL:
|
|
104
|
-
|
|
105
|
-
```ts
|
|
106
|
-
const skill = await Skill.fromUrl(signedUrl, {
|
|
107
|
-
name: "rules",
|
|
108
|
-
sha256: "sha256:<hex>"
|
|
109
|
-
});
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
`Skill.fromUrl` fetches the archive in the SDK process. The hosted platform does
|
|
113
|
-
not fetch the caller-controlled URL. The signed URL only needs to be valid for
|
|
114
|
-
this call; the SDK snapshots the bytes into the asset store before the run is
|
|
115
|
-
submitted.
|
|
53
|
+
The wire ref then becomes a `{ kind:"skill", assetId, name, description }` entry
|
|
54
|
+
inside `submission.tools`. Identical bytes dedup by content hash, so re-submitting
|
|
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.
|
|
116
60
|
|
|
117
|
-
##
|
|
61
|
+
## Loading and materialization
|
|
118
62
|
|
|
119
|
-
|
|
120
|
-
|
|
63
|
+
The skill-tool's `name` and `description` are what the agent sees in its tool
|
|
64
|
+
list. At run time the model calls the **no-arg load-tool** to pull the skill's
|
|
65
|
+
`SKILL.md` body into context — the description tells the agent when that is worth
|
|
66
|
+
doing.
|
|
121
67
|
|
|
122
|
-
|
|
123
|
-
|
|
68
|
+
Independently of whether the model calls the load-tool, the platform copies the
|
|
69
|
+
referenced skill asset into durable run asset storage
|
|
70
|
+
(`runs/<runId>/assets/<hash>`) and the runner **eagerly stages** the bundle's
|
|
71
|
+
files into the workspace under `/workspace/skills/<name>/`. So the `SKILL.md` body
|
|
72
|
+
and every supporting file are on disk from the first turn; the load-tool call is
|
|
73
|
+
how that body enters the model's context, not how the files get written.
|
|
124
74
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
skills: [Skill.fromCatalog(record)],
|
|
129
|
-
secrets: { apiKeys: { anthropic: apiKey } }
|
|
130
|
-
});
|
|
131
|
-
```
|
|
75
|
+
The platform also mounts the `aex` CLI and a per-run manifest into every run.
|
|
76
|
+
Skills call managed HTTP proxy endpoints through the mounted CLI
|
|
77
|
+
(`aex proxy ...`); see [Credentials](credentials.md) for the policy and auth model.
|
|
132
78
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
the catalog.
|
|
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
|
@@ -8,8 +8,8 @@ aex has no built-in vision tool. The agent's `provider`/`model` selects the
|
|
|
8
8
|
*reasoning* model — it is not an endpoint a skill can POST an image to mid-run.
|
|
9
9
|
To give a run image understanding (or to call any other model/HTTP API), ship a
|
|
10
10
|
**skill** that POSTs to the provider's OpenAI-compatible endpoint **through the
|
|
11
|
-
managed proxy**, with the key supplied
|
|
12
|
-
key never enters the container.
|
|
11
|
+
managed proxy**, with the key supplied on a `ProxyEndpoint.bearer(...)` instance.
|
|
12
|
+
The raw key never enters the container.
|
|
13
13
|
|
|
14
14
|
This is the same proxy described in `credentials.md` — this page is the worked
|
|
15
15
|
recipe for the model-API case, which has two wrinkles a plain JSON call does not:
|
|
@@ -18,54 +18,44 @@ large enough to need a raised `maxRequestBytes`.
|
|
|
18
18
|
|
|
19
19
|
The canonical, runnable example lives in the repo at
|
|
20
20
|
[`examples/vision-skill/`](../../../examples/vision-skill) (`SKILL.md`,
|
|
21
|
-
`caption_frame.py`, `verify_frame.py`, `
|
|
21
|
+
`caption_frame.py`, `verify_frame.py`, `run_with_vision_skill.mjs`). It
|
|
22
22
|
captions a frame with ByteDance Doubao Seed Vision (Ark) and returns a per-noun
|
|
23
23
|
"does the frame depict X?" verdict. Everything below is taken from it.
|
|
24
24
|
|
|
25
25
|
## 1. Declare the model endpoint as a proxy endpoint
|
|
26
26
|
|
|
27
|
-
The vision provider's API is just an HTTPS host. Declare it
|
|
28
|
-
|
|
29
|
-
settings are `responseMode: "full"` (so the skill gets the upstream
|
|
30
|
-
a raised `maxRequestBytes` (so the base64 image fits):
|
|
27
|
+
The vision provider's API is just an HTTPS host. Declare it with
|
|
28
|
+
`ProxyEndpoint.bearer(...)`, which carries the key on the instance. The two
|
|
29
|
+
model-specific settings are `responseMode: "full"` (so the skill gets the upstream
|
|
30
|
+
JSON back) and a raised `maxRequestBytes` (so the base64 image fits):
|
|
31
31
|
|
|
32
32
|
```ts
|
|
33
|
-
import {
|
|
34
|
-
|
|
35
|
-
const aex = new
|
|
36
|
-
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
];
|
|
48
|
-
|
|
49
|
-
const proxyEndpointAuth = [
|
|
50
|
-
{ name: "doubao-ark", value: { type: "bearer", token: process.env.DOUBAO_API_KEY! } }
|
|
51
|
-
];
|
|
52
|
-
|
|
53
|
-
validateProxyAuth(proxyEndpoints, proxyEndpointAuth); // fail fast at submit time
|
|
33
|
+
import { Aex, Models, Tools, ProxyEndpoint } from "@aexhq/sdk";
|
|
34
|
+
|
|
35
|
+
const aex = new Aex({ apiToken: process.env.AEX_API_TOKEN! });
|
|
36
|
+
|
|
37
|
+
const doubaoArk = ProxyEndpoint.bearer({
|
|
38
|
+
name: "doubao-ark",
|
|
39
|
+
baseUrl: "https://ark.ap-southeast.bytepluses.com", // intl BytePlus gateway
|
|
40
|
+
token: process.env.DOUBAO_API_KEY!,
|
|
41
|
+
allowMethods: ["POST"],
|
|
42
|
+
allowPathPrefixes: ["/api/v3/chat/completions"],
|
|
43
|
+
maxRequestBytes: 2_000_000, // base64 image POSTs — see note below
|
|
44
|
+
responseMode: "full",
|
|
45
|
+
timeoutMs: 60_000
|
|
46
|
+
});
|
|
54
47
|
|
|
55
|
-
|
|
48
|
+
await aex.run({
|
|
56
49
|
model: Models.CLAUDE_HAIKU_4_5,
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
proxyEndpoints,
|
|
60
|
-
|
|
61
|
-
apiKeys: { anthropic: process.env.ANTHROPIC_API_KEY! },
|
|
62
|
-
proxyEndpointAuth
|
|
63
|
-
}
|
|
50
|
+
message: "…read skills/frame-vision-gate/SKILL.md, then caption + verify the frame…",
|
|
51
|
+
tools: [await Tools.fromSkillDir("./vision-skill", { name: "frame-vision-gate" })],
|
|
52
|
+
proxyEndpoints: [doubaoArk],
|
|
53
|
+
apiKeys: { anthropic: process.env.ANTHROPIC_API_KEY! }
|
|
64
54
|
});
|
|
65
55
|
```
|
|
66
56
|
|
|
67
|
-
`
|
|
68
|
-
run the
|
|
57
|
+
`Tools.fromSkillDir("./vision-skill", …)` is resolved relative to the process CWD, so
|
|
58
|
+
run the script from the directory that *contains* `vision-skill/` (in the
|
|
69
59
|
repo, that is `examples/`). The same pattern works for OpenAI, Gemini's
|
|
70
60
|
OpenAI-compatible endpoint, or any other OpenAI-chat-shaped vision API — only
|
|
71
61
|
`baseUrl` and the path prefix change.
|
|
@@ -147,8 +137,7 @@ so full-res frames do not add payload and model cost without useful signal.
|
|
|
147
137
|
- **Host selection.** Use the provider endpoint that matches your account and
|
|
148
138
|
declare it as the proxy endpoint `baseUrl`.
|
|
149
139
|
- **Keyless model hosts.** If the upstream takes no credential, declare the
|
|
150
|
-
endpoint with `
|
|
151
|
-
entry (see `credentials.md`).
|
|
140
|
+
endpoint with `ProxyEndpoint.none(...)` (see `credentials.md`).
|
|
152
141
|
- **Response size.** `responseMode: "full"` is required to read the model's reply
|
|
153
142
|
back. Leave `maxResponseBytes` at its default (`0` = unlimited, streamed) unless
|
|
154
143
|
you want a truncation cap.
|
package/examples/chat-corpus.ts
CHANGED
|
@@ -3,10 +3,9 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Combines the public `@aexhq/sdk` corpus read-tools (`createCorpusTools`) with a
|
|
5
5
|
* direct Claude chat loop (`@anthropic-ai/sdk`). The importable `@aexhq/sdk` stays
|
|
6
|
-
* LLM-vendor-free; the vendor dependency lives only here in the example
|
|
7
|
-
* the bundled `aex chat` CLI command).
|
|
6
|
+
* LLM-vendor-free; the vendor dependency lives only here in the example.
|
|
8
7
|
*
|
|
9
|
-
* Run (Bun): ANTHROPIC_API_KEY=…
|
|
8
|
+
* Run (Bun): ANTHROPIC_API_KEY=… AEX_API_TOKEN=… bun examples/chat-corpus.ts <sessionId> [sessionId…]
|
|
10
9
|
*
|
|
11
10
|
* The model answers ONLY from the named runs' outputs (read via the corpus
|
|
12
11
|
* tools); a run outside the corpus is refused by the tool layer.
|
|
@@ -14,17 +13,17 @@
|
|
|
14
13
|
import Anthropic from "@anthropic-ai/sdk";
|
|
15
14
|
import { AgentExecutor, createCorpusTools, DataToolError } from "@aexhq/sdk";
|
|
16
15
|
|
|
17
|
-
const
|
|
18
|
-
if (
|
|
19
|
-
console.error("usage: bun examples/chat-corpus.ts <
|
|
16
|
+
const sessionIds = process.argv.slice(2);
|
|
17
|
+
if (sessionIds.length === 0) {
|
|
18
|
+
console.error("usage: bun examples/chat-corpus.ts <sessionId> [sessionId…]");
|
|
20
19
|
process.exit(2);
|
|
21
20
|
}
|
|
22
21
|
|
|
23
22
|
const aex = new AgentExecutor({
|
|
24
|
-
apiToken: process.env.
|
|
25
|
-
...(process.env.
|
|
23
|
+
apiToken: process.env.AEX_API_TOKEN!,
|
|
24
|
+
...(process.env.AEX_API_URL ? { baseUrl: process.env.AEX_API_URL } : {})
|
|
26
25
|
});
|
|
27
|
-
const tools = createCorpusTools(aex, {
|
|
26
|
+
const tools = createCorpusTools(aex, { sessionIds });
|
|
28
27
|
const anthropic = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY! });
|
|
29
28
|
|
|
30
29
|
const SYSTEM =
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aexhq/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.34.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": {
|
package/dist/skill.d.ts
DELETED
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
import { type AssetRef, type FetchLike, type SkillRef } from "./_contracts/index.js";
|
|
2
|
-
import { type SkillFiles } from "./bundle.js";
|
|
3
|
-
/**
|
|
4
|
-
* One `Skill` class for skill bytes. `client.submit` materializes the bytes
|
|
5
|
-
* as an uploaded asset before the run lands; the wire ref becomes
|
|
6
|
-
* `kind:"asset"`.
|
|
7
|
-
*
|
|
8
|
-
* Build from an inline files map (`Skill.fromFiles`), a local directory
|
|
9
|
-
* (`Skill.fromPath`), or a remote zip archive over a signed URL
|
|
10
|
-
* (`Skill.fromUrl`). All three converge on the same canonical bundle, so
|
|
11
|
-
* identical content dedups across sources.
|
|
12
|
-
*
|
|
13
|
-
* Asset deduplication makes the same bytes a no-op upload on subsequent runs.
|
|
14
|
-
* There is no `Skill.fromId(...)`. A URL is an ingestion source, not a
|
|
15
|
-
* persistent reference.
|
|
16
|
-
*
|
|
17
|
-
* An inline draft is auto-staged to the content-addressable asset store at
|
|
18
|
-
* submit time (the bytes upload before `POST /runs`; the wire ref becomes
|
|
19
|
-
* `kind:"asset"`). Call `await skill.upload(client)` to pre-stage the bytes
|
|
20
|
-
* explicitly — useful when you want to reuse the resulting `kind:"asset"`
|
|
21
|
-
* Skill across multiple runs.
|
|
22
|
-
*/
|
|
23
|
-
export declare class Skill {
|
|
24
|
-
#private;
|
|
25
|
-
/**
|
|
26
|
-
* Internal constructor. Use `Skill.fromFiles` or `Skill.fromPath` to create
|
|
27
|
-
* instances.
|
|
28
|
-
*/
|
|
29
|
-
private constructor();
|
|
30
|
-
/**
|
|
31
|
-
* The wire-level reference. Returns the SDK-private draft shape for
|
|
32
|
-
* un-materialized skills (kind:"draft", with name + contentHash).
|
|
33
|
-
* `client.submit` walks these and uploads them before the run
|
|
34
|
-
* lands.
|
|
35
|
-
*/
|
|
36
|
-
get ref(): AssetRef | DraftSkillRef;
|
|
37
|
-
/** True for local-bytes Skills that haven't been uploaded yet. */
|
|
38
|
-
get isDraft(): boolean;
|
|
39
|
-
/** Internal: the asset id resolved on a prior submit, or undefined. */
|
|
40
|
-
get _cachedAssetId(): string | undefined;
|
|
41
|
-
/** Internal: remember the asset id resolved for this draft's bytes. */
|
|
42
|
-
_rememberAsset(assetId: string): void;
|
|
43
|
-
/**
|
|
44
|
-
* Build a draft Skill from an inline files map. The SDK validates
|
|
45
|
-
* basic safety (no path traversal, size caps, has `SKILL.md`),
|
|
46
|
-
* deterministically zips the bundle, and computes the
|
|
47
|
-
* `sha256:<hex>` content hash. `client.submit` materializes
|
|
48
|
-
* these before the run lands.
|
|
49
|
-
*/
|
|
50
|
-
static fromFiles(args: {
|
|
51
|
-
readonly name: string;
|
|
52
|
-
readonly files: SkillFiles;
|
|
53
|
-
}): Promise<Skill>;
|
|
54
|
-
/**
|
|
55
|
-
* Read a local directory and build a draft Skill. Symlinks and
|
|
56
|
-
* non-regular files are skipped. Bun/Node filesystem runtimes only.
|
|
57
|
-
*/
|
|
58
|
-
static fromPath(rootDir: string, args: {
|
|
59
|
-
readonly name: string;
|
|
60
|
-
}): Promise<Skill>;
|
|
61
|
-
/**
|
|
62
|
-
* Fetch a zip-archived skill from a URL and build a draft Skill. The archive
|
|
63
|
-
* is downloaded in the SDK process, so the URL is caller-controlled — host
|
|
64
|
-
* the skill yourself and pass a temporary signed URL (e.g. an S3 presigned
|
|
65
|
-
* URL). Its bytes are optionally integrity-checked against `sha256`, unzipped,
|
|
66
|
-
* and reduced to the same files map as `Skill.fromFiles` — so a URL-sourced
|
|
67
|
-
* skill and the identical local skill produce the same canonical asset and
|
|
68
|
-
* dedup against each other.
|
|
69
|
-
*
|
|
70
|
-
* The archive must contain `SKILL.md` at its root, or inside a single
|
|
71
|
-
* top-level folder (which is stripped). The signed URL only needs to be valid
|
|
72
|
-
* for this call; `client.submit` snapshots the bytes into the run.
|
|
73
|
-
*
|
|
74
|
-
* Universal (Bun / Node 18+ / browser): requires a global `fetch`, or pass one.
|
|
75
|
-
*/
|
|
76
|
-
static fromUrl(url: string, args: {
|
|
77
|
-
readonly name: string;
|
|
78
|
-
readonly sha256?: string;
|
|
79
|
-
readonly timeoutMs?: number;
|
|
80
|
-
readonly fetch?: FetchLike;
|
|
81
|
-
}): Promise<Skill>;
|
|
82
|
-
/**
|
|
83
|
-
* Reference a skill already uploaded to the workspace catalog
|
|
84
|
-
* (`aex skills upload`) in a run.
|
|
85
|
-
*
|
|
86
|
-
* A catalog skill's bytes are a content-addressed asset, so referencing it
|
|
87
|
-
* is just an `{ kind:"asset" }` ref — once a run snapshots the bytes, it is
|
|
88
|
-
* the identical normalized flow as an inline or file-sourced skill. Pass the
|
|
89
|
-
* `Skill` record returned by `client.skills.list()` / `.get()`:
|
|
90
|
-
*
|
|
91
|
-
* const [s] = await client.skills.list();
|
|
92
|
-
* await client.submit({ ..., skills: [Skill.fromCatalog(s)] });
|
|
93
|
-
*
|
|
94
|
-
* The record must be `ready` (it has a content hash). Unlike the draft
|
|
95
|
-
* builders this performs no upload — the bytes already live in the catalog.
|
|
96
|
-
*/
|
|
97
|
-
static fromCatalog(record: {
|
|
98
|
-
readonly name: string;
|
|
99
|
-
readonly hash?: string | null;
|
|
100
|
-
}): Skill;
|
|
101
|
-
/**
|
|
102
|
-
* Internal: yield the draft's bytes + metadata so `client.submit` can upload
|
|
103
|
-
* the asset. Idempotent (non-consuming): a Skill is reusable across submits —
|
|
104
|
-
* the first submit caches the resolved asset id (see `_rememberAsset`) so
|
|
105
|
-
* later submits reuse it instead of re-uploading.
|
|
106
|
-
*
|
|
107
|
-
* Returns undefined for already-materialized Skills.
|
|
108
|
-
*/
|
|
109
|
-
_takeDraftBundle(): {
|
|
110
|
-
name: string;
|
|
111
|
-
contentHash: string;
|
|
112
|
-
bytes: Uint8Array;
|
|
113
|
-
} | undefined;
|
|
114
|
-
/**
|
|
115
|
-
* Pre-upload a draft Skill's bytes to the workspace asset store and return a
|
|
116
|
-
* NEW materialized Skill carrying a `kind:"asset"` ref. Blocking: the upload
|
|
117
|
-
* completes before this resolves. Submitting the returned Skill sends a plain
|
|
118
|
-
* asset ref and the run pulls the bytes from storage.
|
|
119
|
-
*
|
|
120
|
-
* Consumes this draft (a draft becomes an asset exactly once); call only on a
|
|
121
|
-
* draft built via `Skill.fromFiles` / `Skill.fromPath` / `Skill.fromUrl`.
|
|
122
|
-
*/
|
|
123
|
-
upload(client: SkillUploader): Promise<Skill>;
|
|
124
|
-
toJSON(): SkillRef;
|
|
125
|
-
}
|
|
126
|
-
/**
|
|
127
|
-
* SDK-internal draft skill marker. Never reaches the wire; the
|
|
128
|
-
* materialize step inside `client.submit` converts these to
|
|
129
|
-
* `kind:"asset"` refs.
|
|
130
|
-
*/
|
|
131
|
-
export interface DraftSkillRef {
|
|
132
|
-
readonly kind: "draft";
|
|
133
|
-
readonly name: string;
|
|
134
|
-
readonly contentHash: string;
|
|
135
|
-
}
|
|
136
|
-
/**
|
|
137
|
-
* Minimal client surface `Skill.upload` needs. `AgentExecutor` satisfies it via
|
|
138
|
-
* its internal `_uploadAsset`; defined structurally here so `skill.ts` does not
|
|
139
|
-
* import `client.ts` (which would be circular — `client.ts` imports `Skill`).
|
|
140
|
-
*/
|
|
141
|
-
export interface SkillUploader {
|
|
142
|
-
_uploadAsset(args: {
|
|
143
|
-
readonly bytes: Uint8Array;
|
|
144
|
-
readonly hash: string;
|
|
145
|
-
readonly contentType?: string;
|
|
146
|
-
}): Promise<{
|
|
147
|
-
readonly assetId: string;
|
|
148
|
-
}>;
|
|
149
|
-
}
|