@aexhq/sdk 0.13.6
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/LICENSE +201 -0
- package/README.md +160 -0
- package/dist/_contracts/connection-ticket.d.ts +21 -0
- package/dist/_contracts/connection-ticket.js +49 -0
- package/dist/_contracts/event-envelope.d.ts +276 -0
- package/dist/_contracts/event-envelope.js +324 -0
- package/dist/_contracts/event-stream-client.d.ts +47 -0
- package/dist/_contracts/event-stream-client.js +141 -0
- package/dist/_contracts/http.d.ts +35 -0
- package/dist/_contracts/http.js +114 -0
- package/dist/_contracts/index.d.ts +28 -0
- package/dist/_contracts/index.js +29 -0
- package/dist/_contracts/managed-key.d.ts +74 -0
- package/dist/_contracts/managed-key.js +110 -0
- package/dist/_contracts/operations.d.ts +237 -0
- package/dist/_contracts/operations.js +632 -0
- package/dist/_contracts/provider-support.d.ts +220 -0
- package/dist/_contracts/provider-support.js +90 -0
- package/dist/_contracts/proxy-protocol.d.ts +257 -0
- package/dist/_contracts/proxy-protocol.js +234 -0
- package/dist/_contracts/proxy-validation.d.ts +19 -0
- package/dist/_contracts/proxy-validation.js +51 -0
- package/dist/_contracts/run-artifacts.d.ts +47 -0
- package/dist/_contracts/run-artifacts.js +101 -0
- package/dist/_contracts/run-config.d.ts +304 -0
- package/dist/_contracts/run-config.js +659 -0
- package/dist/_contracts/run-cost.d.ts +125 -0
- package/dist/_contracts/run-cost.js +616 -0
- package/dist/_contracts/run-custody.d.ts +226 -0
- package/dist/_contracts/run-custody.js +465 -0
- package/dist/_contracts/run-record.d.ts +127 -0
- package/dist/_contracts/run-record.js +177 -0
- package/dist/_contracts/run-retention.d.ts +213 -0
- package/dist/_contracts/run-retention.js +484 -0
- package/dist/_contracts/run-unit.d.ts +194 -0
- package/dist/_contracts/run-unit.js +215 -0
- package/dist/_contracts/runner-event.d.ts +114 -0
- package/dist/_contracts/runner-event.js +187 -0
- package/dist/_contracts/runtime-manifest.d.ts +106 -0
- package/dist/_contracts/runtime-manifest.js +98 -0
- package/dist/_contracts/runtime-security-profile.d.ts +27 -0
- package/dist/_contracts/runtime-security-profile.js +82 -0
- package/dist/_contracts/runtime-sizes.d.ts +144 -0
- package/dist/_contracts/runtime-sizes.js +136 -0
- package/dist/_contracts/runtime-types.d.ts +212 -0
- package/dist/_contracts/runtime-types.js +2 -0
- package/dist/_contracts/sdk-errors.d.ts +34 -0
- package/dist/_contracts/sdk-errors.js +52 -0
- package/dist/_contracts/sdk-secrets.d.ts +31 -0
- package/dist/_contracts/sdk-secrets.js +220 -0
- package/dist/_contracts/side-effect-audit.d.ts +129 -0
- package/dist/_contracts/side-effect-audit.js +494 -0
- package/dist/_contracts/sse.d.ts +74 -0
- package/dist/_contracts/sse.js +0 -0
- package/dist/_contracts/stable.d.ts +26 -0
- package/dist/_contracts/stable.js +44 -0
- package/dist/_contracts/status.d.ts +19 -0
- package/dist/_contracts/status.js +61 -0
- package/dist/_contracts/submission.d.ts +383 -0
- package/dist/_contracts/submission.js +1380 -0
- package/dist/agents-md.d.ts +46 -0
- package/dist/agents-md.js +83 -0
- package/dist/agents-md.js.map +1 -0
- package/dist/asset-upload.d.ts +66 -0
- package/dist/asset-upload.js +168 -0
- package/dist/asset-upload.js.map +1 -0
- package/dist/bundle.d.ts +33 -0
- package/dist/bundle.js +89 -0
- package/dist/bundle.js.map +1 -0
- package/dist/cli.mjs +4140 -0
- package/dist/cli.mjs.sha256 +1 -0
- package/dist/client.d.ts +460 -0
- package/dist/client.js +857 -0
- package/dist/client.js.map +1 -0
- package/dist/fetch-archive.d.ts +16 -0
- package/dist/fetch-archive.js +170 -0
- package/dist/fetch-archive.js.map +1 -0
- package/dist/file.d.ts +57 -0
- package/dist/file.js +153 -0
- package/dist/file.js.map +1 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.js +34 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-server.d.ts +84 -0
- package/dist/mcp-server.js +114 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/node-fs.d.ts +12 -0
- package/dist/node-fs.js +44 -0
- package/dist/node-fs.js.map +1 -0
- package/dist/proxy-endpoint.d.ts +131 -0
- package/dist/proxy-endpoint.js +147 -0
- package/dist/proxy-endpoint.js.map +1 -0
- package/dist/skill.d.ts +117 -0
- package/dist/skill.js +169 -0
- package/dist/skill.js.map +1 -0
- package/dist/version.d.ts +9 -0
- package/dist/version.js +10 -0
- package/dist/version.js.map +1 -0
- package/docs/cleanup.md +38 -0
- package/docs/credentials.md +153 -0
- package/docs/events.md +76 -0
- package/docs/mcp.md +47 -0
- package/docs/outputs.md +157 -0
- package/docs/product-boundaries.md +57 -0
- package/docs/provider-runtime-capabilities.md +103 -0
- package/docs/quickstart.md +110 -0
- package/docs/release.md +99 -0
- package/docs/run-config.md +53 -0
- package/docs/run-record.md +39 -0
- package/docs/skills.md +139 -0
- package/docs/testing.md +29 -0
- package/package.json +47 -0
package/dist/skill.js
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { SKILL_NAME_PATTERN } from "./_contracts/index.js";
|
|
2
|
+
import { bundleSkillFiles, hashSkillBundle } from "./bundle.js";
|
|
3
|
+
import { fetchSkillArchive } from "./fetch-archive.js";
|
|
4
|
+
import { readDirectoryAsFiles } from "./node-fs.js";
|
|
5
|
+
/**
|
|
6
|
+
* One `Skill` class for skill bytes. `client.submitRun` materializes the bytes
|
|
7
|
+
* as an uploaded asset before the run lands; the wire ref becomes
|
|
8
|
+
* `kind:"asset"`.
|
|
9
|
+
*
|
|
10
|
+
* Build from an inline files map (`Skill.fromFiles`), a local directory
|
|
11
|
+
* (`Skill.fromPath`), or a remote zip archive over a signed URL
|
|
12
|
+
* (`Skill.fromUrl`). All three converge on the same canonical bundle, so
|
|
13
|
+
* identical content dedups across sources.
|
|
14
|
+
*
|
|
15
|
+
* Asset deduplication makes the same bytes a no-op upload on subsequent runs.
|
|
16
|
+
* There is no `Skill.fromId(...)` and no `.upload(client)` — a URL is an
|
|
17
|
+
* ingestion source, not a persistent reference.
|
|
18
|
+
*/
|
|
19
|
+
export class Skill {
|
|
20
|
+
#ref;
|
|
21
|
+
#inlineBytes;
|
|
22
|
+
#consumed = false;
|
|
23
|
+
/**
|
|
24
|
+
* Internal constructor. Use `Skill.fromFiles` or `Skill.fromPath` to create
|
|
25
|
+
* instances.
|
|
26
|
+
*/
|
|
27
|
+
constructor(ref, inlineBytes) {
|
|
28
|
+
this.#ref = ref;
|
|
29
|
+
this.#inlineBytes = inlineBytes;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The wire-level reference. Returns the SDK-private draft shape for
|
|
33
|
+
* un-materialized skills (kind:"draft", with name + contentHash).
|
|
34
|
+
* `client.submitRun` walks these and uploads them before the run
|
|
35
|
+
* lands.
|
|
36
|
+
*/
|
|
37
|
+
get ref() {
|
|
38
|
+
return this.#ref;
|
|
39
|
+
}
|
|
40
|
+
/** True for local-bytes Skills that haven't been uploaded yet. */
|
|
41
|
+
get isDraft() {
|
|
42
|
+
return this.#ref.kind === "draft" && !this.#consumed;
|
|
43
|
+
}
|
|
44
|
+
get isConsumed() {
|
|
45
|
+
return this.#consumed;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Build a draft Skill from an inline files map. The SDK validates
|
|
49
|
+
* basic safety (no path traversal, size caps, has `SKILL.md`),
|
|
50
|
+
* deterministically zips the bundle, and computes the
|
|
51
|
+
* `sha256:<hex>` content hash. `client.submitRun` materializes
|
|
52
|
+
* these before the run lands.
|
|
53
|
+
*/
|
|
54
|
+
static async fromFiles(args) {
|
|
55
|
+
if (!args || typeof args !== "object") {
|
|
56
|
+
throw new Error("Skill.fromFiles: args is required");
|
|
57
|
+
}
|
|
58
|
+
if (typeof args.name !== "string" || !SKILL_NAME_PATTERN.test(args.name)) {
|
|
59
|
+
throw new Error(`Skill.fromFiles: name must match ${SKILL_NAME_PATTERN.source}`);
|
|
60
|
+
}
|
|
61
|
+
const bundled = bundleSkillFiles(args.files);
|
|
62
|
+
const contentHash = await hashSkillBundle(bundled.zip);
|
|
63
|
+
const ref = {
|
|
64
|
+
kind: "draft",
|
|
65
|
+
name: args.name,
|
|
66
|
+
contentHash
|
|
67
|
+
};
|
|
68
|
+
return new Skill(ref, bundled.zip);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Read a local directory and build a draft Skill. Symlinks and
|
|
72
|
+
* non-regular files are skipped. Node-only.
|
|
73
|
+
*/
|
|
74
|
+
static async fromPath(rootDir, args) {
|
|
75
|
+
const files = await readDirectoryAsFiles(rootDir);
|
|
76
|
+
return Skill.fromFiles({ name: args.name, files });
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Fetch a zip-archived skill from a URL and build a draft Skill. The archive
|
|
80
|
+
* is downloaded in the SDK process, so the URL is caller-controlled — host
|
|
81
|
+
* the skill yourself and pass a temporary signed URL (e.g. an S3 presigned
|
|
82
|
+
* URL). Its bytes are optionally integrity-checked against `sha256`, unzipped,
|
|
83
|
+
* and reduced to the same files map as `Skill.fromFiles` — so a URL-sourced
|
|
84
|
+
* skill and the identical local skill produce the same canonical asset and
|
|
85
|
+
* dedup against each other.
|
|
86
|
+
*
|
|
87
|
+
* The archive must contain `SKILL.md` at its root, or inside a single
|
|
88
|
+
* top-level folder (which is stripped). The signed URL only needs to be valid
|
|
89
|
+
* for this call; `client.submitRun` snapshots the bytes into the run.
|
|
90
|
+
*
|
|
91
|
+
* Universal (Node 18+ / browser): requires a global `fetch`, or pass one.
|
|
92
|
+
*/
|
|
93
|
+
static async fromUrl(url, args) {
|
|
94
|
+
if (!args || typeof args !== "object") {
|
|
95
|
+
throw new Error("Skill.fromUrl: args is required");
|
|
96
|
+
}
|
|
97
|
+
if (typeof args.name !== "string" || !SKILL_NAME_PATTERN.test(args.name)) {
|
|
98
|
+
throw new Error(`Skill.fromUrl: name must match ${SKILL_NAME_PATTERN.source}`);
|
|
99
|
+
}
|
|
100
|
+
const files = await fetchSkillArchive(url, {
|
|
101
|
+
...(args.sha256 !== undefined ? { sha256: args.sha256 } : {}),
|
|
102
|
+
...(args.timeoutMs !== undefined ? { timeoutMs: args.timeoutMs } : {}),
|
|
103
|
+
...(args.fetch !== undefined ? { fetch: args.fetch } : {})
|
|
104
|
+
});
|
|
105
|
+
return Skill.fromFiles({ name: args.name, files });
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Reference a skill already uploaded to the workspace catalog
|
|
109
|
+
* (`aex skills upload` / `operations.createSkillBundle`) in a run.
|
|
110
|
+
*
|
|
111
|
+
* A catalog skill's bytes are a content-addressed asset, so referencing it
|
|
112
|
+
* is just an `{ kind:"asset" }` ref — once a run snapshots the bytes, it is
|
|
113
|
+
* the identical normalized flow as an inline or file-sourced skill. Pass the
|
|
114
|
+
* `Skill` record returned by `client.skills.list()` / `.get()`:
|
|
115
|
+
*
|
|
116
|
+
* const [s] = await client.skills.list();
|
|
117
|
+
* await client.submitRun({ ..., skills: [Skill.fromCatalog(s)] });
|
|
118
|
+
*
|
|
119
|
+
* The record must be `ready` (it has a content hash). Unlike the draft
|
|
120
|
+
* builders this performs no upload — the bytes already live in the catalog.
|
|
121
|
+
*/
|
|
122
|
+
static fromCatalog(record) {
|
|
123
|
+
if (!record || typeof record !== "object") {
|
|
124
|
+
throw new Error("Skill.fromCatalog: a catalog skill record is required");
|
|
125
|
+
}
|
|
126
|
+
if (typeof record.name !== "string" || !SKILL_NAME_PATTERN.test(record.name)) {
|
|
127
|
+
throw new Error(`Skill.fromCatalog: record.name must match ${SKILL_NAME_PATTERN.source}`);
|
|
128
|
+
}
|
|
129
|
+
const rawHash = typeof record.hash === "string" ? record.hash : "";
|
|
130
|
+
const hashHex = rawHash.startsWith("sha256:") ? rawHash.slice("sha256:".length) : rawHash;
|
|
131
|
+
if (!/^[0-9a-f]{64}$/.test(hashHex)) {
|
|
132
|
+
throw new Error("Skill.fromCatalog: record.hash must be a sha256 digest — only `ready` catalog skills are referenceable");
|
|
133
|
+
}
|
|
134
|
+
const ref = { kind: "asset", assetId: `asset_${hashHex}`, name: record.name };
|
|
135
|
+
return new Skill(ref);
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Internal: yield the draft's bytes + metadata so `client.submitRun`
|
|
139
|
+
* can upload the asset. After this returns, the Skill is marked consumed
|
|
140
|
+
* so a second submitRun call against the same instance throws
|
|
141
|
+
* (avoid silently re-uploading; explicit re-construction is the
|
|
142
|
+
* supported retry pattern).
|
|
143
|
+
*
|
|
144
|
+
* Returns undefined for already-materialized Skills.
|
|
145
|
+
*/
|
|
146
|
+
_takeDraftBundle() {
|
|
147
|
+
if (this.#consumed) {
|
|
148
|
+
throw new Error("Skill: cannot reuse a consumed Skill in submitRun. Build a fresh Skill via " +
|
|
149
|
+
"Skill.fromPath(...) / Skill.fromFiles(...) per submitRun call.");
|
|
150
|
+
}
|
|
151
|
+
if (this.#ref.kind !== "draft" || !this.#inlineBytes) {
|
|
152
|
+
return undefined;
|
|
153
|
+
}
|
|
154
|
+
this.#consumed = true;
|
|
155
|
+
return {
|
|
156
|
+
name: this.#ref.name,
|
|
157
|
+
contentHash: this.#ref.contentHash,
|
|
158
|
+
bytes: this.#inlineBytes
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
toJSON() {
|
|
162
|
+
if (this.#ref.kind === "draft") {
|
|
163
|
+
throw new Error("Skill: draft Skills cannot be JSON-serialised — they only become wire refs when " +
|
|
164
|
+
"client.submitRun uploads the bytes as an asset.");
|
|
165
|
+
}
|
|
166
|
+
return this.#ref;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
//# sourceMappingURL=skill.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill.js","sourceRoot":"","sources":["../src/skill.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Single source of truth for the SDK version exposed at runtime.
|
|
3
|
+
*
|
|
4
|
+
* Must match `packages/sdk/package.json`'s `version` field — a unit
|
|
5
|
+
* test asserts this. Bump both on every release.
|
|
6
|
+
*
|
|
7
|
+
* Used by the (future) User-Agent header on outbound SDK requests.
|
|
8
|
+
*/
|
|
9
|
+
export declare const SDK_VERSION = "0.13.6";
|
package/dist/version.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Single source of truth for the SDK version exposed at runtime.
|
|
3
|
+
*
|
|
4
|
+
* Must match `packages/sdk/package.json`'s `version` field — a unit
|
|
5
|
+
* test asserts this. Bump both on every release.
|
|
6
|
+
*
|
|
7
|
+
* Used by the (future) User-Agent header on outbound SDK requests.
|
|
8
|
+
*/
|
|
9
|
+
export const SDK_VERSION = "0.13.6";
|
|
10
|
+
//# sourceMappingURL=version.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,QAAQ,CAAC"}
|
package/docs/cleanup.md
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Cleanup
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Cleanup
|
|
6
|
+
|
|
7
|
+
aex schedules cleanup after a run reaches a terminal status. There is no
|
|
8
|
+
opt-out for aex-owned cleanup attempts: tracked runtime resources such as
|
|
9
|
+
Fly machines, scratch state, cached files, and run-scoped secret references are
|
|
10
|
+
reclaimed when possible or surfaced through `cleanupStatus` when cleanup cannot
|
|
11
|
+
complete.
|
|
12
|
+
|
|
13
|
+
The hosted product uses managed runtimes for all supported providers. Reusable
|
|
14
|
+
provider-session retention is not a supported run option, and the removed
|
|
15
|
+
retention field is rejected if supplied.
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
const runId = await client.submitRun({
|
|
19
|
+
model: "claude-haiku-4-5",
|
|
20
|
+
prompt: "...",
|
|
21
|
+
secrets: { anthropic: { apiKey: process.env.ANTHROPIC_API_KEY! } }
|
|
22
|
+
});
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## `cleanupStatus` values
|
|
26
|
+
|
|
27
|
+
`cleanupStatus` reports the aggregate state of our cleanup work across the
|
|
28
|
+
run's tracked resources. It is one of:
|
|
29
|
+
|
|
30
|
+
- `not_started` - terminal not yet reached, or no resources to clean.
|
|
31
|
+
- `pending` / `running` - cleanup is queued or in progress.
|
|
32
|
+
- `succeeded` - tracked cleanup work completed for the resources aex
|
|
33
|
+
controls.
|
|
34
|
+
- `failed_retryable` - a step failed in a way the cleanup worker will retry.
|
|
35
|
+
- `failed_terminal` - a step failed past retries; manual intervention may be
|
|
36
|
+
needed.
|
|
37
|
+
- `skipped` - cleanup was not applicable for a tracked resource, or the
|
|
38
|
+
resource was already absent.
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Credentials
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Credentials
|
|
6
|
+
|
|
7
|
+
aex does not store provider keys or MCP credential values across runs.
|
|
8
|
+
|
|
9
|
+
The caller passes a workspace-scoped SDK token and exactly one matching provider key inline on every `submitRun` call. aex holds the bundle in run-scoped custody for the run lifecycle and attempts terminal cleanup/revocation for the aex-controlled references. MCP credentials and proxy endpoint auth values travel the same way.
|
|
10
|
+
|
|
11
|
+
Provider keys are coupled to the submitted `provider`:
|
|
12
|
+
|
|
13
|
+
| `provider` | Required secret |
|
|
14
|
+
| --- | --- |
|
|
15
|
+
| `anthropic` | `secrets.anthropic.apiKey` |
|
|
16
|
+
| `deepseek` | `secrets.deepseek.apiKey` |
|
|
17
|
+
| `openai` | `secrets.openai.apiKey` |
|
|
18
|
+
| `gemini` | `secrets.gemini.apiKey` |
|
|
19
|
+
| `mistral` | `secrets.mistral.apiKey` |
|
|
20
|
+
|
|
21
|
+
Supplying a key for any other provider is rejected at submission time.
|
|
22
|
+
|
|
23
|
+
MCP credential types:
|
|
24
|
+
|
|
25
|
+
- `static_bearer`;
|
|
26
|
+
- `oauth_access_token`.
|
|
27
|
+
|
|
28
|
+
Unsupported:
|
|
29
|
+
|
|
30
|
+
- arbitrary headers;
|
|
31
|
+
- OAuth refresh;
|
|
32
|
+
- persisted aex vault.
|
|
33
|
+
|
|
34
|
+
For Goose Managed runs, aex injects the matching BYOK provider key at the hosted provider-proxy. Provider-side sessions and data remain subject to the selected provider account's retention and deletion policies.
|
|
35
|
+
|
|
36
|
+
## Proxy endpoints (per-run custom HTTP credentials)
|
|
37
|
+
|
|
38
|
+
Some skills need to call non-MCP HTTP services (e.g. Stripe, internal APIs). Embedding the credential in the skill content puts the raw secret on disk in the agent container and in the model's context — both prompt-injection-readable.
|
|
39
|
+
|
|
40
|
+
The platform's managed HTTP proxy is the agent-first alternative. The caller declares **policy** at the top level of the submission (hashed for idempotency) and supplies the matching **auth value** inside `secrets` (not hashed, so key rotation does not collapse onto a stale run). The raw credential value never enters the container.
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
import {
|
|
44
|
+
AexClient,
|
|
45
|
+
validateProxyAuth,
|
|
46
|
+
buildPlatformAllowedHosts
|
|
47
|
+
} from "@aexhq/sdk";
|
|
48
|
+
|
|
49
|
+
const client = new AexClient({
|
|
50
|
+
apiToken: "ant_..."
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const proxyEndpoints = [
|
|
54
|
+
{
|
|
55
|
+
name: "stripe",
|
|
56
|
+
baseUrl: "https://api.stripe.com",
|
|
57
|
+
authShape: { type: "bearer" },
|
|
58
|
+
allowMethods: ["GET", "POST"],
|
|
59
|
+
allowPathPrefixes: ["/v1/charges", "/v1/refunds"],
|
|
60
|
+
maxRequestBytes: 65_536,
|
|
61
|
+
maxResponseBytes: 65_536,
|
|
62
|
+
timeoutMs: 10_000,
|
|
63
|
+
responseMode: "headers_only",
|
|
64
|
+
perCallBudget: 60,
|
|
65
|
+
responseByteBudget: 1_048_576
|
|
66
|
+
}
|
|
67
|
+
] as const;
|
|
68
|
+
|
|
69
|
+
const proxyEndpointAuth = [
|
|
70
|
+
{
|
|
71
|
+
name: "stripe",
|
|
72
|
+
value: { type: "bearer", token: process.env.STRIPE_API_KEY! }
|
|
73
|
+
}
|
|
74
|
+
] as const;
|
|
75
|
+
|
|
76
|
+
// Fail fast at submission time when policy and auth disagree.
|
|
77
|
+
validateProxyAuth(proxyEndpoints, proxyEndpointAuth);
|
|
78
|
+
|
|
79
|
+
const runId = await client.submitRun({
|
|
80
|
+
model: "claude-haiku-4-5",
|
|
81
|
+
prompt: "…",
|
|
82
|
+
proxyEndpoints,
|
|
83
|
+
secrets: {
|
|
84
|
+
anthropic: { apiKey: process.env.ANTHROPIC_API_KEY! },
|
|
85
|
+
proxyEndpointAuth
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Inside the run container, every session has the platform CLI mounted at `/mnt/session/uploads/aex/aex` (a Node ESM bundle) and a manifest at `/mnt/session/uploads/aex/index.json` describing the declared endpoints. The skill invokes the CLI through `node` (the mount has no execute permission so direct invocation fails with `bad interpreter: Permission denied`):
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
node /mnt/session/uploads/aex/aex proxy stripe \
|
|
94
|
+
--method GET \
|
|
95
|
+
--path /v1/charges/ch_123 \
|
|
96
|
+
--response-mode headers_only
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
The CLI reads the per-run bearer from `/mnt/session/uploads/aex/run-token`, attaches the `X-Aex-Proxy-Protocol` header, and the BFF injects the bearer/header/query/basic credential before dispatching the outbound call. Only the response (subject to `responseMode` and `maxResponseBytes`) reaches the container. `--response-mode` can only narrow below the policy ceiling.
|
|
100
|
+
|
|
101
|
+
#### Keyless upstreams (`authShape: { type: "none" }`)
|
|
102
|
+
|
|
103
|
+
For public APIs that take no credential (Wikimedia Commons, Internet Archive, Library of Congress, NASA Images, NARA, GDELT, etc.), declare the endpoint with `authShape: { type: "none" }` and omit the matching `proxyEndpointAuth[]` entry entirely:
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
const proxyEndpoints = [
|
|
107
|
+
{
|
|
108
|
+
name: "wikimedia",
|
|
109
|
+
baseUrl: "https://commons.wikimedia.org",
|
|
110
|
+
authShape: { type: "none" },
|
|
111
|
+
allowMethods: ["GET"],
|
|
112
|
+
allowPathPrefixes: ["/wiki/", "/w/api.php"]
|
|
113
|
+
}
|
|
114
|
+
] as const;
|
|
115
|
+
|
|
116
|
+
const runId = await client.submitRun({
|
|
117
|
+
model: "claude-haiku-4-5",
|
|
118
|
+
prompt: "…",
|
|
119
|
+
proxyEndpoints,
|
|
120
|
+
secrets: { anthropic: { apiKey: process.env.ANTHROPIC_API_KEY! } }
|
|
121
|
+
});
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
The keyless endpoint still routes through the aex managed proxy: every call is allow-listed, audited, redacted, and counted against per-run budgets. The BFF injects no `Authorization` header and no query-string credential. Shipping a `proxyEndpointAuth` entry for a `none`-shape endpoint is rejected at submission time. Equivalent class-based form:
|
|
125
|
+
|
|
126
|
+
```ts
|
|
127
|
+
import { ProxyEndpoint } from "@aexhq/sdk";
|
|
128
|
+
|
|
129
|
+
ProxyEndpoint.none({
|
|
130
|
+
name: "wikimedia",
|
|
131
|
+
baseUrl: "https://commons.wikimedia.org",
|
|
132
|
+
allowMethods: ["GET"],
|
|
133
|
+
allowPathPrefixes: ["/wiki/", "/w/api.php"]
|
|
134
|
+
});
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
`node /mnt/session/uploads/aex/aex --help` reads endpoint details from `/mnt/session/uploads/aex/index.json`. Runs that do not declare any `proxyEndpoints` still have the CLI and an empty manifest mounted, so agents never need to introspect whether the surface exists.
|
|
138
|
+
|
|
139
|
+
### Networking
|
|
140
|
+
|
|
141
|
+
When a run uses `limited` networking, the platform host must appear in `allowed_hosts`. The worker injects it automatically; for advance validation use:
|
|
142
|
+
|
|
143
|
+
```ts
|
|
144
|
+
const allowedHosts = buildPlatformAllowedHosts({
|
|
145
|
+
baseUrl: "https://api.aex.dev",
|
|
146
|
+
extraHosts: ["api.stripe.com"]
|
|
147
|
+
});
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Secrets are always explicit at the call site
|
|
151
|
+
|
|
152
|
+
There is no `defaultSecrets` and no client-held secret state. Every `submitRun` call carries its full `secrets` bundle (one provider key + optional MCP credentials + optional `proxyEndpointAuth`). This is the agent-first invariant: the credentials being used on any given call are visible in the same line of code that submits the run.
|
|
153
|
+
|
package/docs/events.md
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Events
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Events
|
|
6
|
+
|
|
7
|
+
aex runs agent sessions on Goose Managed. Runs are **non-blocking**: the managed runtime advances the agent while aex observes lifecycle state, maps runtime output into one event shape, and persists every captured event. The SDK and CLI observe the durable event timeline from aex — there is no in-process tool-approval hook.
|
|
8
|
+
|
|
9
|
+
## Two ways to consume events
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
// Pull a snapshot of every event captured so far.
|
|
13
|
+
const events = await client.events(runId);
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
// Stream the RunEvent snapshot shape: yields each event once, stops when the
|
|
18
|
+
// run reaches a terminal status. Backed by polling the aex events endpoint.
|
|
19
|
+
for await (const event of client.stream(runId, { intervalMs: 1000 })) {
|
|
20
|
+
if (event.type === "agent.message") {
|
|
21
|
+
// ...
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
For the canonical event envelope, use the coordinator WebSocket stream:
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
for await (const event of client.streamEnvelopes(runId, { from: 0 })) {
|
|
30
|
+
console.log(event.sequence, event.type, event.source);
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
`streamEnvelopes()` uses a short-lived ticket minted by the hosted API, then subscribes directly to the per-run coordinator. Subscribe means read-from-cursor plus tail: reconnects resume from the last sequence.
|
|
35
|
+
|
|
36
|
+
The CLI mirrors the same surface:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
aex events <run-id> --api-token … [--aex-url …] # snapshot
|
|
40
|
+
aex events <run-id> --follow [--timeout 8m] --api-token … [--aex-url …] # stream until terminal
|
|
41
|
+
aex wait <run-id> [--timeout 8m] [--interval 2s] --api-token … # block, print final run
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
`aex wait` is the host mirror of `client.wait(runId)` / `client.waitForRun(runId)`:
|
|
45
|
+
it polls until the run reaches a terminal status and prints the final `Run`
|
|
46
|
+
record. Exit `0` when the run `succeeded`, `1` for any other terminal status,
|
|
47
|
+
and `3` when `--timeout` elapses first (a `--timeout` on `events --follow` /
|
|
48
|
+
`run --follow` uses the same exit-`3` convention). Durations accept `ms`/`s`/`m`/`h`
|
|
49
|
+
suffixes or a bare millisecond integer.
|
|
50
|
+
|
|
51
|
+
Both surfaces observe the same events. A subscriber attached after `submitRun()` returns replays the events it missed, then continues live.
|
|
52
|
+
|
|
53
|
+
## Event shape
|
|
54
|
+
|
|
55
|
+
Events are typed as the discriminated `RunEvent` union for compatibility and as the versioned coordinator envelope for live consumers. aex records raw runtime/provider payloads **after** secret redaction and structural sanitization, so the bytes you see never contain the provider key, MCP credentials, or proxy bearer that were supplied to `submitRun`.
|
|
56
|
+
|
|
57
|
+
## Typed helpers
|
|
58
|
+
|
|
59
|
+
The package exports conservative type guards that narrow normalized aex event envelopes:
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
import {
|
|
63
|
+
isRunStarted,
|
|
64
|
+
isRunFinished,
|
|
65
|
+
isRunError,
|
|
66
|
+
isRunTerminal,
|
|
67
|
+
isTextMessage,
|
|
68
|
+
isToolCallStart,
|
|
69
|
+
isToolCallResult,
|
|
70
|
+
isCustom,
|
|
71
|
+
isLog,
|
|
72
|
+
isEventChannel
|
|
73
|
+
} from "@aexhq/sdk";
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
They narrow only the discriminant. Payload field shapes stay `unknown` until callers parse them, and provider-specific payloads remain behind the normalized envelope.
|
package/docs/mcp.md
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: MCP
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# MCP
|
|
6
|
+
|
|
7
|
+
MCP support is remote HTTPS/SSE only. Stdio MCP servers are rejected because aex is a remote session dispatcher, not a local process supervisor.
|
|
8
|
+
|
|
9
|
+
Rules:
|
|
10
|
+
|
|
11
|
+
- MCP servers are declared in the run request config (`mcpServers`).
|
|
12
|
+
- Runtime HITL is disabled.
|
|
13
|
+
- Tool policy must be configured before session start.
|
|
14
|
+
- Enabled MCP tools use `always_allow` provider permissions.
|
|
15
|
+
- `always_ask` is not used by aex MVP.
|
|
16
|
+
- Bearer/OAuth-style auth is passed in the per-run `secrets.mcpServers` bundle.
|
|
17
|
+
|
|
18
|
+
Use allowlists for sensitive servers whenever possible.
|
|
19
|
+
|
|
20
|
+
## Large-payload responses
|
|
21
|
+
|
|
22
|
+
aex is a session dispatcher, not an MCP runtime. We intentionally do
|
|
23
|
+
**not** interpose on the transport between Claude and an upstream MCP
|
|
24
|
+
server, so we cannot elide MCP responses or write them to the session
|
|
25
|
+
filesystem on the user's behalf. Anything an MCP tool returns lands
|
|
26
|
+
directly in the model's context.
|
|
27
|
+
|
|
28
|
+
For ingestion-style tools that return large JSON blobs (search results,
|
|
29
|
+
catalogue dumps, bulk reads), use the **CLI-as-skill + managed proxy**
|
|
30
|
+
pattern instead of MCP:
|
|
31
|
+
|
|
32
|
+
1. Package the upstream as a `Skill` — a CLI binary the agent invokes
|
|
33
|
+
with its bash tool.
|
|
34
|
+
2. Route every upstream HTTPS call through a per-run `ProxyEndpoint`
|
|
35
|
+
(audit, byte caps, budget enforcement).
|
|
36
|
+
3. Have the CLI write the full payload to the session filesystem. By default,
|
|
37
|
+
files it creates or modifies are captured automatically; pass
|
|
38
|
+
`outputs.allowedDirs` only when you want to narrow capture to specific roots.
|
|
39
|
+
Return only a small handle (path, item count, summary) to the model.
|
|
40
|
+
|
|
41
|
+
The agent sees the handle in context; the bytes ride out through
|
|
42
|
+
`download()` as a normal captured output.
|
|
43
|
+
|
|
44
|
+
If you genuinely want everything in context (small responses, code
|
|
45
|
+
search, etc.), use MCP. If the payload would blow your context budget,
|
|
46
|
+
the CLI-as-skill pattern is the supported answer — there is no platform
|
|
47
|
+
flag to elide MCP responses.
|