@aexhq/sdk 0.35.0 → 0.37.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 +17 -16
- package/dist/_contracts/event-envelope.d.ts +22 -1
- package/dist/_contracts/event-envelope.js +26 -2
- package/dist/_contracts/event-stream-client.js +7 -1
- package/dist/_contracts/index.d.ts +3 -4
- package/dist/_contracts/index.js +1 -4
- package/dist/_contracts/operations.d.ts +31 -1
- package/dist/_contracts/operations.js +64 -1
- package/dist/_contracts/run-config.d.ts +2 -4
- package/dist/_contracts/run-config.js +2 -7
- package/dist/_contracts/run-trace.d.ts +0 -86
- package/dist/_contracts/run-trace.js +1 -184
- package/dist/_contracts/run-unit.d.ts +14 -25
- package/dist/_contracts/run-unit.js +56 -2
- package/dist/_contracts/runtime-manifest.d.ts +1 -1
- package/dist/_contracts/runtime-security-profile.d.ts +0 -2
- package/dist/_contracts/runtime-security-profile.js +0 -9
- package/dist/_contracts/runtime-sizes.d.ts +2 -2
- package/dist/_contracts/runtime-sizes.js +5 -5
- package/dist/_contracts/runtime-types.d.ts +123 -4
- package/dist/_contracts/stable.d.ts +1 -1
- package/dist/_contracts/stable.js +1 -1
- package/dist/_contracts/submission.d.ts +8 -76
- package/dist/_contracts/submission.js +5 -472
- package/dist/cli.mjs +574 -511
- package/dist/cli.mjs.sha256 +1 -1
- package/dist/client.d.ts +69 -25
- package/dist/client.js +338 -68
- package/dist/client.js.map +1 -1
- package/dist/index.d.ts +8 -16
- package/dist/index.js +5 -17
- package/dist/index.js.map +1 -1
- package/dist/secret.d.ts +2 -2
- package/dist/secret.js +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/docs/authentication.md +92 -0
- package/docs/billing.md +112 -0
- package/docs/concepts/agent-tools.md +4 -4
- package/docs/concepts/composition.md +8 -14
- package/docs/concepts/providers-and-runtimes.md +4 -1
- package/docs/concepts/runs.md +2 -1
- package/docs/concepts/subagents.md +85 -0
- package/docs/credentials.md +78 -96
- package/docs/defaults.md +9 -15
- package/docs/errors.md +132 -0
- package/docs/events.md +44 -32
- package/docs/limits-and-quotas.md +30 -17
- package/docs/limits.md +4 -8
- package/docs/mcp.md +5 -6
- package/docs/networking.md +75 -59
- package/docs/outputs.md +4 -7
- package/docs/public-surface.json +4 -4
- package/docs/quickstart.md +12 -13
- package/docs/run-config.md +7 -4
- package/docs/secrets.md +6 -1
- package/docs/skills.md +3 -3
- package/docs/vision-skills.md +52 -101
- package/docs/webhooks.md +132 -0
- package/examples/feature-tour.ts +4 -21
- package/package.json +1 -1
- package/dist/_contracts/proxy-protocol.d.ts +0 -305
- package/dist/_contracts/proxy-protocol.js +0 -297
- package/dist/_contracts/proxy-validation.d.ts +0 -19
- package/dist/_contracts/proxy-validation.js +0 -51
- package/dist/data-tools.d.ts +0 -82
- package/dist/data-tools.js +0 -251
- package/dist/data-tools.js.map +0 -1
- package/dist/proxy-endpoint.d.ts +0 -131
- package/dist/proxy-endpoint.js +0 -144
- package/dist/proxy-endpoint.js.map +0 -1
- package/examples/chat-corpus.ts +0 -84
|
@@ -12,7 +12,7 @@ Managed runs inject the complete builtin tool set into the agent by default:
|
|
|
12
12
|
- `head`, `tail` — read bounded file slices
|
|
13
13
|
- `web_fetch`, `web_search` — fetch a URL / managed web search
|
|
14
14
|
- `todo_write` — maintain a todo list
|
|
15
|
-
- `subagent`, `subagent_result` — delegate to and read back from child runs
|
|
15
|
+
- `subagent`, `subagent_result` — delegate to and read back from child runs (see [Subagents](subagents.md))
|
|
16
16
|
- `bash_output`, `bash_kill` — manage background bash jobs
|
|
17
17
|
- `wait`, `git` — bounded idle-yield and first-class git
|
|
18
18
|
|
|
@@ -32,13 +32,13 @@ to pick a narrow subset alongside `includeBuiltinTools: false`.
|
|
|
32
32
|
The final tool list is ordered: resolved builtin tools, then custom tools, then
|
|
33
33
|
MCP tools.
|
|
34
34
|
|
|
35
|
-
Networking is open by default
|
|
36
|
-
fixed SSRF deny-list. `web_fetch` and `web_search` reach the network over a
|
|
35
|
+
Networking is open by default within the platform's managed egress ceiling and
|
|
36
|
+
a fixed SSRF deny-list. `web_fetch` and `web_search` reach the network over a
|
|
37
37
|
managed, SSRF-guarded path that is **not** governed by `environment.networking`,
|
|
38
38
|
so their hosts never need to be listed in a `limited` allowlist. Setting
|
|
39
39
|
`environment.networking.mode` to `limited` restricts only the agent's own
|
|
40
40
|
arbitrary egress (e.g. a `curl` in `bash`); the built-in web tools keep working.
|
|
41
|
-
See [Networking](../networking.md).
|
|
41
|
+
See [Networking](../networking.md) for the full two-layer model.
|
|
42
42
|
|
|
43
43
|
## Disable builtins
|
|
44
44
|
|
|
@@ -14,11 +14,11 @@ runtime before the first agent turn.
|
|
|
14
14
|
| Agent instructions | `AgentsMd.fromPath`, `AgentsMd.fromContent` |
|
|
15
15
|
| Reference files and folders | `File.fromPath`, `File.fromBytes` |
|
|
16
16
|
| Remote tools | `McpServer.remote`, `McpServer.fromId` |
|
|
17
|
-
| Credentialed HTTP APIs | `ProxyEndpoint.none`, `bearer`, `basic`, `header`, `query` |
|
|
18
17
|
| Non-secret runtime settings | `environment.variables`, `environment.packages`, `environment.networking` |
|
|
18
|
+
| Runtime secrets for your code | `Secret.value`, `Secret.ref`, `environment.secrets` |
|
|
19
19
|
|
|
20
20
|
```ts
|
|
21
|
-
import { AgentsMd, File, McpServer, Models,
|
|
21
|
+
import { AgentsMd, File, McpServer, Models, Secret, Tools } from "@aexhq/sdk";
|
|
22
22
|
|
|
23
23
|
await aex.run({
|
|
24
24
|
model: Models.CLAUDE_HAIKU_4_5,
|
|
@@ -27,20 +27,14 @@ await aex.run({
|
|
|
27
27
|
files: [await File.fromPath("./input")],
|
|
28
28
|
tools: [await Tools.fromSkillDir("./skills/report-writer", { name: "report-writer" })],
|
|
29
29
|
mcpServers: [McpServer.remote({ name: "github", url: "https://example.com/mcp" })],
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
token: process.env.INTERNAL_API_TOKEN!,
|
|
35
|
-
allowMethods: ["GET"],
|
|
36
|
-
allowPathPrefixes: ["/v1/"]
|
|
37
|
-
})
|
|
38
|
-
],
|
|
30
|
+
environment: {
|
|
31
|
+
secrets: { INTERNAL_API_TOKEN: Secret.value(process.env.INTERNAL_API_TOKEN!) },
|
|
32
|
+
networking: { mode: "limited", allowedHosts: ["api.example.com"] }
|
|
33
|
+
},
|
|
39
34
|
apiKeys: { anthropic: process.env.ANTHROPIC_API_KEY! }
|
|
40
35
|
});
|
|
41
36
|
```
|
|
42
37
|
|
|
43
38
|
Secrets stay out of reusable configs. Provider keys go in the top-level `apiKeys`
|
|
44
|
-
map;
|
|
45
|
-
|
|
46
|
-
server-side, so they never live in a shareable config object.
|
|
39
|
+
map; reusable or per-run values for your own code go in `environment.secrets`.
|
|
40
|
+
Your code then makes normal HTTP calls with the standard client for that service.
|
|
@@ -17,7 +17,10 @@ aex exposes one submission shape across supported providers:
|
|
|
17
17
|
| Doubao | `Providers.DOUBAO` |
|
|
18
18
|
| Doubao China | `Providers.DOUBAO_CN` |
|
|
19
19
|
|
|
20
|
-
All submissions run on the managed runtime.
|
|
20
|
+
All submissions run on the managed runtime. The optional `runtime` option picks
|
|
21
|
+
a managed machine-size preset — use `Sizes.*` in TypeScript (e.g.
|
|
22
|
+
`runtime: Sizes.SHARED_0_25X_1GB`) or `--runtime-size` in the CLI. Omit it for
|
|
23
|
+
the default size; there is no alternative runtime backend to select.
|
|
21
24
|
|
|
22
25
|
## Selection
|
|
23
26
|
|
package/docs/concepts/runs.md
CHANGED
|
@@ -38,7 +38,8 @@ The same durable record backs SDK and CLI reads. From the handle use `refresh`,
|
|
|
38
38
|
and `events().stream()` / `events().streamEnvelopes()` / `outputs().read(...)` for
|
|
39
39
|
streaming and byte-capped reads) — to inspect the session live or after it parks;
|
|
40
40
|
from the client, `aex.sessions.list()` / `aex.sessions.get(id)` read across the
|
|
41
|
-
workspace
|
|
41
|
+
workspace (CLI mirrors: `aex sessions` and `aex runs` list the workspace's
|
|
42
|
+
sessions/runs newest-first).
|
|
42
43
|
|
|
43
44
|
Use `idempotencyKey` when retrying `openSession` or `send` from your own
|
|
44
45
|
workflow. aex hashes the normalized non-secret submission, so a retry with the
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Subagents
|
|
3
|
+
description: Delegate bounded sub-tasks to child agent runs with the subagent tool.
|
|
4
|
+
icon: GitFork
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
A run can delegate bounded sub-tasks to **child agent runs** with the built-in
|
|
8
|
+
`subagent` tool. Delegation is agent-driven: the model decides to fan work out,
|
|
9
|
+
each child is a real run with its own record, and the parent collects results
|
|
10
|
+
as the children finish. There is no client-side parent/child API — lineage is
|
|
11
|
+
session-internal.
|
|
12
|
+
|
|
13
|
+
## How the tool works
|
|
14
|
+
|
|
15
|
+
The agent calls `subagent` with a `prompt` and a `model` (both required), plus
|
|
16
|
+
optional `system`, `provider`, `runtimeSize`, `timeout`,
|
|
17
|
+
`includeBuiltinTools`, `tools` (builtin-tool names for the child), `skills`,
|
|
18
|
+
and `files`. The call is **always async**: on a successful spawn it returns
|
|
19
|
+
immediately with the child run id, and the parent keeps working while the child
|
|
20
|
+
runs. When a child settles, the parent is notified in its loop, and it reads
|
|
21
|
+
the child's status and captured outputs on demand with the companion
|
|
22
|
+
`subagent_result` tool.
|
|
23
|
+
|
|
24
|
+
Children inherit the parent's vaulted BYOK provider keys server-side — the
|
|
25
|
+
child submission carries no secrets. Include a provider key for every provider
|
|
26
|
+
your subagents may use when you open the parent session (a parent holding no
|
|
27
|
+
key for the child's provider gets a clear `parent_missing_provider_key` tool
|
|
28
|
+
error). See [Credentials](../credentials.md).
|
|
29
|
+
|
|
30
|
+
## Depth and breadth limits
|
|
31
|
+
|
|
32
|
+
Delegation is bounded by two server-enforced lineage limits:
|
|
33
|
+
|
|
34
|
+
| Limit | Value | Behavior at the limit |
|
|
35
|
+
| --- | --- | --- |
|
|
36
|
+
| Max depth | **5** — the root run is depth 0 and may spawn down to depth 5; a depth-5 run may not spawn further | The spawn is rejected with a `depth_exceeded` tool error (the parent keeps running). |
|
|
37
|
+
| Concurrent children per lineage root | **1000** live (non-terminal) descendants by default; hard platform ceiling **4096** | Further spawns are refused until a child settles. |
|
|
38
|
+
|
|
39
|
+
The whole descendant subtree of one root shares a single depth and breadth
|
|
40
|
+
budget, enforced server-side at every level — a grandchild spawn counts against
|
|
41
|
+
the same root budget as a direct child. Values are mirrored in
|
|
42
|
+
[Limits & quotas](../limits-and-quotas.md).
|
|
43
|
+
|
|
44
|
+
## Where children run: `in-process` vs `container`
|
|
45
|
+
|
|
46
|
+
By default a child runs **in-process**: it executes as a sibling agent process
|
|
47
|
+
inside the parent's own machine, sharing the parent's CPU, memory, and
|
|
48
|
+
lifetime. This is the platform default shipped today.
|
|
49
|
+
|
|
50
|
+
- **No extra runtime cost.** The parent's machine is the billable unit, so
|
|
51
|
+
in-process children bill **$0 of additional runtime** — fan-out is priced by
|
|
52
|
+
the parent box, however many children it hosts. (Model-token spend is still
|
|
53
|
+
whatever each child's provider calls cost on your BYOK key.)
|
|
54
|
+
- **Shared capacity.** N children share the parent's fixed CPU/memory. For
|
|
55
|
+
large fan-outs, size the parent up (`runtime`) rather than assuming each
|
|
56
|
+
child gets its own machine.
|
|
57
|
+
- **Joined lifecycle.** The parent's terminal waits for its in-process children,
|
|
58
|
+
and their results are folded into the parent's per-child accounting. Platform
|
|
59
|
+
recovery re-spawns in-process children exactly once if the parent's machine
|
|
60
|
+
is replaced mid-run — settled children are never re-run.
|
|
61
|
+
|
|
62
|
+
The escape valve is `host: "container"`: the child is dispatched to its **own
|
|
63
|
+
isolated machine** with its own runtime size and its own runtime billing, and
|
|
64
|
+
the parent does not host it. Use it when a child needs guaranteed capacity,
|
|
65
|
+
isolation from the parent's filesystem/CPU, or a different machine size than
|
|
66
|
+
the parent can share.
|
|
67
|
+
|
|
68
|
+
## Lineage and observability
|
|
69
|
+
|
|
70
|
+
Every child — in-process or container — is a first-class run record:
|
|
71
|
+
|
|
72
|
+
- The parent's transcript logs each spawn with the child's run id.
|
|
73
|
+
- Each child has its own status, typed event timeline, and captured outputs,
|
|
74
|
+
readable by id like any other run (`aex.sessions.get(id)`, or the CLI's
|
|
75
|
+
`aex status` / `aex events` / `aex outputs` / `aex download`).
|
|
76
|
+
- The child's outputs are handed back to the parent via `subagent_result`, and
|
|
77
|
+
they remain independently downloadable after the lineage finishes.
|
|
78
|
+
|
|
79
|
+
## Bounding delegation
|
|
80
|
+
|
|
81
|
+
- Turn delegation off for a run by cherry-picking builtins without `subagent`
|
|
82
|
+
(see [Agent tools](agent-tools.md)) or setting `includeBuiltinTools: false`.
|
|
83
|
+
- A per-session spend cap (`overrides.maxSpendUsd`) bounds the parent's spend.
|
|
84
|
+
- The depth/breadth limits above are platform defaults and are not settable
|
|
85
|
+
per-session today.
|
package/docs/credentials.md
CHANGED
|
@@ -4,142 +4,124 @@ title: Credentials
|
|
|
4
4
|
|
|
5
5
|
# Credentials
|
|
6
6
|
|
|
7
|
-
aex
|
|
8
|
-
credentials. Reusable env secrets are documented separately in
|
|
9
|
-
[Secrets](secrets.md).
|
|
7
|
+
aex uses explicit, per-session credentials:
|
|
10
8
|
|
|
11
|
-
|
|
9
|
+
- `AEX_API_TOKEN` authenticates the SDK or CLI to aex.
|
|
10
|
+
- `apiKeys` carries BYOK provider keys for the model provider.
|
|
11
|
+
- `McpServer.remote(..., { headers })` carries MCP auth when a remote MCP server needs it.
|
|
12
|
+
- `environment.secrets` carries runtime secrets for your own code.
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
key for it. Keys are supplied per-provider so a session can also hold keys for the
|
|
15
|
-
**other** providers its subagents may use:
|
|
14
|
+
Secrets never belong in reusable run config, files, prompts, or examples.
|
|
16
15
|
|
|
17
|
-
|
|
18
|
-
| --- | --- |
|
|
19
|
-
| Provider API keys | `apiKeys` (top-level, keyed by provider) |
|
|
16
|
+
## The client credential
|
|
20
17
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
anthropic: process.env.ANTHROPIC_API_KEY!, // the session's provider
|
|
25
|
-
deepseek: process.env.DEEPSEEK_API_KEY! // for a cross-provider subagent
|
|
26
|
-
}
|
|
27
|
-
```
|
|
18
|
+
Pass your aex API token directly to the constructor — `new Aex(apiKey)` — or as
|
|
19
|
+
the `apiKey` option. The older `apiToken` option remains accepted as a
|
|
20
|
+
compatibility alias, so existing code keeps working:
|
|
28
21
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
container. If the parent holds no key for the child's provider, the child is
|
|
32
|
-
rejected with `parent_missing_provider_key`.
|
|
22
|
+
```ts
|
|
23
|
+
import { Aex } from "@aexhq/sdk";
|
|
33
24
|
|
|
34
|
-
|
|
25
|
+
const aex = new Aex(process.env.AEX_API_TOKEN!); // preferred shorthand
|
|
26
|
+
// equivalently:
|
|
27
|
+
// const aex = new Aex({ apiKey: process.env.AEX_API_TOKEN! });
|
|
28
|
+
// const aex = new Aex({ apiToken: process.env.AEX_API_TOKEN! }); // alias
|
|
29
|
+
```
|
|
35
30
|
|
|
36
|
-
|
|
37
|
-
|
|
31
|
+
See [Authentication](authentication.md) for how tokens are scoped, rotated, and
|
|
32
|
+
issued during the beta.
|
|
38
33
|
|
|
39
|
-
|
|
34
|
+
## Provider keys
|
|
40
35
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
- persisted aex vault.
|
|
36
|
+
A session selects one upstream provider and must carry a BYOK key for it. Include
|
|
37
|
+
additional provider keys only when subagents may use those providers.
|
|
44
38
|
|
|
45
|
-
|
|
39
|
+
```ts
|
|
40
|
+
const result = await aex.run({
|
|
41
|
+
model: Models.CLAUDE_HAIKU_4_5,
|
|
42
|
+
message: "Write a short report and save it as a file.",
|
|
43
|
+
apiKeys: {
|
|
44
|
+
anthropic: process.env.ANTHROPIC_API_KEY!
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
```
|
|
46
48
|
|
|
47
|
-
|
|
49
|
+
Provider keys are used by the managed runtime for model calls. They are not saved
|
|
50
|
+
as client defaults.
|
|
48
51
|
|
|
49
|
-
|
|
52
|
+
## Runtime secrets
|
|
50
53
|
|
|
51
|
-
|
|
54
|
+
Use `environment.secrets` for credentials your code needs at runtime. The value
|
|
55
|
+
can be ephemeral with `Secret.value(...)` or a workspace secret reference with
|
|
56
|
+
`Secret.ref(...)`.
|
|
52
57
|
|
|
53
58
|
```ts
|
|
54
|
-
import { Aex, Models,
|
|
59
|
+
import { Aex, Models, Secret } from "@aexhq/sdk";
|
|
55
60
|
|
|
56
|
-
const aex = new Aex({
|
|
57
|
-
apiToken: "ant_..."
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
const stripe = ProxyEndpoint.bearer({
|
|
61
|
-
name: "stripe",
|
|
62
|
-
baseUrl: "https://api.stripe.com",
|
|
63
|
-
token: process.env.STRIPE_API_KEY!,
|
|
64
|
-
allowMethods: ["GET", "POST"],
|
|
65
|
-
allowPathPrefixes: ["/v1/charges", "/v1/refunds"],
|
|
66
|
-
maxRequestBytes: 65_536,
|
|
67
|
-
maxResponseBytes: 65_536,
|
|
68
|
-
timeoutMs: 10_000,
|
|
69
|
-
responseMode: "headers_only",
|
|
70
|
-
retry: {
|
|
71
|
-
maxAttempts: 3,
|
|
72
|
-
initialDelayMs: 250,
|
|
73
|
-
maxDelayMs: 5000,
|
|
74
|
-
jitter: "full",
|
|
75
|
-
retryOnStatuses: [408, 425, 429, 500, 502, 503, 504],
|
|
76
|
-
retryOnMethods: ["GET", "HEAD"],
|
|
77
|
-
respectRetryAfter: true
|
|
78
|
-
}
|
|
79
|
-
});
|
|
61
|
+
const aex = new Aex({ apiToken: process.env.AEX_API_TOKEN! });
|
|
80
62
|
|
|
81
63
|
await aex.run({
|
|
82
64
|
model: Models.CLAUDE_HAIKU_4_5,
|
|
83
|
-
message: "
|
|
84
|
-
|
|
65
|
+
message: "Call https://api.example.com/v1/status with INTERNAL_API_TOKEN and summarize it.",
|
|
66
|
+
environment: {
|
|
67
|
+
secrets: {
|
|
68
|
+
INTERNAL_API_TOKEN: Secret.value(process.env.INTERNAL_API_TOKEN!)
|
|
69
|
+
},
|
|
70
|
+
networking: {
|
|
71
|
+
mode: "limited",
|
|
72
|
+
allowedHosts: ["api.example.com"]
|
|
73
|
+
}
|
|
74
|
+
},
|
|
85
75
|
apiKeys: { anthropic: process.env.ANTHROPIC_API_KEY! }
|
|
86
76
|
});
|
|
87
77
|
```
|
|
88
78
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
Inside the run container, every session has the platform CLI mounted at `/mnt/session/uploads/aex/aex` (a Bun-compatible ESM bundle) and a manifest at `/mnt/session/uploads/aex/index.json` describing the declared endpoints. The skill invokes the CLI through `bun` (the mount has no execute permission so direct invocation fails with `bad interpreter: Permission denied`):
|
|
79
|
+
Inside the run, use normal HTTP code for the service:
|
|
92
80
|
|
|
93
81
|
```bash
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
--response-mode headers_only
|
|
82
|
+
curl -sS \
|
|
83
|
+
-H "Authorization: Bearer $INTERNAL_API_TOKEN" \
|
|
84
|
+
https://api.example.com/v1/status
|
|
98
85
|
```
|
|
99
86
|
|
|
100
|
-
|
|
87
|
+
## Workspace secrets
|
|
101
88
|
|
|
102
|
-
|
|
89
|
+
> **Availability note:** workspace-secret `Secret.ref(...)` injection requires
|
|
90
|
+
> the next platform deploy — on the current hosted plane the referenced
|
|
91
|
+
> variable can resolve empty inside the run. Per-run `Secret.value(...)`
|
|
92
|
+
> secrets are unaffected.
|
|
103
93
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
For public APIs that take no credential (Wikimedia Commons, Internet Archive, Library of Congress, NASA Images, NARA, GDELT, etc.), declare the endpoint with `ProxyEndpoint.none(...)` — it produces only a declaration, no auth token:
|
|
94
|
+
Store reusable values once, then reference them by name:
|
|
107
95
|
|
|
108
96
|
```ts
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
name: "wikimedia",
|
|
113
|
-
baseUrl: "https://commons.wikimedia.org",
|
|
114
|
-
allowMethods: ["GET"],
|
|
115
|
-
allowPathPrefixes: ["/wiki/", "/w/api.php"]
|
|
97
|
+
await aex.secrets.set({
|
|
98
|
+
name: "internal-api-token",
|
|
99
|
+
value: process.env.INTERNAL_API_TOKEN!
|
|
116
100
|
});
|
|
117
101
|
|
|
118
102
|
await aex.run({
|
|
119
103
|
model: Models.CLAUDE_HAIKU_4_5,
|
|
120
|
-
message: "
|
|
121
|
-
|
|
104
|
+
message: "Use INTERNAL_API_TOKEN for the status request.",
|
|
105
|
+
environment: {
|
|
106
|
+
secrets: {
|
|
107
|
+
INTERNAL_API_TOKEN: Secret.ref("internal-api-token")
|
|
108
|
+
}
|
|
109
|
+
},
|
|
122
110
|
apiKeys: { anthropic: process.env.ANTHROPIC_API_KEY! }
|
|
123
111
|
});
|
|
124
112
|
```
|
|
125
113
|
|
|
126
|
-
|
|
114
|
+
Secret reads return metadata only; they never return the stored value.
|
|
127
115
|
|
|
128
|
-
|
|
116
|
+
## Networking
|
|
129
117
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
the
|
|
134
|
-
automatically; for advance validation use:
|
|
135
|
-
|
|
136
|
-
```ts
|
|
137
|
-
const allowedHosts = buildPlatformAllowedHosts({
|
|
138
|
-
baseUrl: "https://api.aex.dev",
|
|
139
|
-
extraHosts: ["api.stripe.com"]
|
|
140
|
-
});
|
|
141
|
-
```
|
|
118
|
+
Networking is open by default within the platform's managed egress ceiling. Use
|
|
119
|
+
`environment.networking.mode: "limited"` with `allowedHosts` when you want a
|
|
120
|
+
run's own code to reach only named hosts. See [Networking](networking.md) for
|
|
121
|
+
the two-layer enforcement model.
|
|
142
122
|
|
|
143
|
-
|
|
123
|
+
## Explicit call-site rule
|
|
144
124
|
|
|
145
|
-
There is no `defaultSecrets` and no client-held secret state.
|
|
125
|
+
There is no `defaultSecrets` and no client-held secret state. Each
|
|
126
|
+
`openSession(...)` or `run(...)` call should show the provider keys, MCP auth, and
|
|
127
|
+
runtime secrets needed for that call.
|
package/docs/defaults.md
CHANGED
|
@@ -5,10 +5,9 @@ title: Defaults
|
|
|
5
5
|
# Defaults
|
|
6
6
|
|
|
7
7
|
These are the values aex applies when you **omit** the corresponding option on a
|
|
8
|
-
run. Every value is mirrored from a single source-of-truth constant
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
the constant wins.
|
|
8
|
+
run. Every value is mirrored from a single source-of-truth constant in the
|
|
9
|
+
platform's limits module; this page is hand-maintained against those constants.
|
|
10
|
+
If a value here ever disagrees with the constant, the constant wins.
|
|
12
11
|
|
|
13
12
|
Each value below is named by its source-of-truth constant. The runtime-size
|
|
14
13
|
presets are defined in the public
|
|
@@ -21,7 +20,7 @@ For the hard ceilings and who can raise them, see
|
|
|
21
20
|
|
|
22
21
|
| Option | Default | How to override | Source |
|
|
23
22
|
| --- | --- | --- | --- |
|
|
24
|
-
| `timeout` (run deadline) |
|
|
23
|
+
| `timeout` (run deadline) | 8 hours (also the ceiling) | Per-session via `overrides.timeout` (e.g. `"30m"`, `"2h"`), clamped to the run-timeout floor/ceiling. | `RUN_DEFAULT_TIMEOUT_MS` |
|
|
25
24
|
| `runtime` (machine size) | `shared-0.25x-1gb` — 0.25 vCPU, 1 GB | Per-session via `runtime` (use `Sizes.*` in TypeScript). | `RUN_DEFAULT_RUNTIME_SIZE` |
|
|
26
25
|
| `overrides.maxSpendUsd` (per-session spend cap) | None — no spend cap (the session is still bounded by its `timeout` and any workspace-level cap) | Per-session via `overrides.maxSpendUsd` (a positive USD amount); the session is stopped once its spend would exceed the cap. | — |
|
|
27
26
|
|
|
@@ -39,14 +38,6 @@ For the hard ceilings and who can raise them, see
|
|
|
39
38
|
| MCP connect timeout (register + initialize + discover) | 30 seconds | Per-port via `connectTimeoutMs`. | `RUN_DEFAULT_MCP_CONNECT_TIMEOUT_MS` |
|
|
40
39
|
| MCP `tools/call` timeout | 30 minutes | Per-port via `callTimeoutMs`. | `RUN_DEFAULT_MCP_CALL_TIMEOUT_MS` |
|
|
41
40
|
|
|
42
|
-
## Proxy endpoints
|
|
43
|
-
|
|
44
|
-
| Option | Default | How to override | Source |
|
|
45
|
-
| --- | --- | --- | --- |
|
|
46
|
-
| `maxRequestBytes` | 10 MiB | Per-endpoint via the endpoint's `maxRequestBytes`. | `REQUEST_PROXY_DEFAULT_MAX_REQUEST_BYTES` |
|
|
47
|
-
| `maxResponseBytes` | `0` (unlimited — the response is streamed unbuffered) | Per-endpoint via the endpoint's `maxResponseBytes`. | `REQUEST_PROXY_DEFAULT_MAX_RESPONSE_BYTES` |
|
|
48
|
-
| `timeoutMs` (upstream) | 5 minutes | Per-endpoint via the endpoint's `timeoutMs`. | `REQUEST_PROXY_DEFAULT_TIMEOUT_MS` |
|
|
49
|
-
|
|
50
41
|
## Links (signed URLs and tickets)
|
|
51
42
|
|
|
52
43
|
| Option | Default | How to override | Source |
|
|
@@ -65,5 +56,8 @@ For the hard ceilings and who can raise them, see
|
|
|
65
56
|
|
|
66
57
|
| Option | Default | How to override | Source |
|
|
67
58
|
| --- | --- | --- | --- |
|
|
68
|
-
|
|
|
69
|
-
|
|
|
59
|
+
| Run submit rate (per minute) | 120 (`0` = disabled); past it `POST /runs` fails with `429 workspace_submit_rate_exceeded` | Per-plane via env `AEX_WORKSPACE_SUBMIT_RATE_PER_MIN`; per-workspace via support. | — |
|
|
60
|
+
| Max concurrent runs | 50 live root runs (hard ceiling 200) | Per-workspace override via support, clamped to the ceiling. | `WORKSPACE_DEFAULT_MAX_CONCURRENT_RUNS` |
|
|
61
|
+
| Monthly spend cap | $250 per UTC calendar month (`0` = unlimited) | Per-workspace override via support. | `WORKSPACE_DEFAULT_SPEND_CAP_USD` |
|
|
62
|
+
| Per-workspace mutation rate limits (per minute) | run cancel 30, run delete 30, signed link 120, API token create 10, API token delete 30 | Per-plane via the matching `AEX_RATE_LIMIT_<ACTION>_PER_MINUTE` env var. | `WORKSPACE_RATE_LIMIT_DEFAULTS` |
|
|
63
|
+
| Workspace storage cap | 500 GB (decimal) | Per-plane via env `AEX_WORKSPACE_STORAGE_CAP_BYTES`; admin workspaces are uncapped (not a customer entitlement). | `WORKSPACE_DEFAULT_STORAGE_CAP_BYTES` |
|
package/docs/errors.md
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Errors
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Errors
|
|
6
|
+
|
|
7
|
+
Every API error is a JSON body with a machine-readable `error` code; most also
|
|
8
|
+
carry a human `message` and the self-describing fields named below. The SDK
|
|
9
|
+
surfaces non-2xx responses as `AexApiError` (with the parsed body attached) and
|
|
10
|
+
throttling as `AexRateLimitError`.
|
|
11
|
+
|
|
12
|
+
## 401 — authentication
|
|
13
|
+
|
|
14
|
+
| Code | Meaning |
|
|
15
|
+
| --- | --- |
|
|
16
|
+
| `unauthorized` | Missing, invalid, or revoked bearer token. |
|
|
17
|
+
|
|
18
|
+
Check the token value and that it has not been deleted. `aex whoami` is the
|
|
19
|
+
cheapest way to validate a credential. See [Authentication](authentication.md).
|
|
20
|
+
|
|
21
|
+
## 403 — authorization
|
|
22
|
+
|
|
23
|
+
| Code | Meaning |
|
|
24
|
+
| --- | --- |
|
|
25
|
+
| `insufficient_scope` | The token is valid but lacks the route's required scope. The body's `requiredScope` field names the missing scope. |
|
|
26
|
+
| `unknown_workspace` | The token does not route to a known workspace. |
|
|
27
|
+
| `forbidden` | The authenticated workspace does not own the addressed resource. |
|
|
28
|
+
|
|
29
|
+
```json
|
|
30
|
+
{ "error": "insufficient_scope", "requiredScope": "runs:write" }
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## 400 — validation
|
|
34
|
+
|
|
35
|
+
| Code | Meaning |
|
|
36
|
+
| --- | --- |
|
|
37
|
+
| `bad_request` | Missing or unparseable request body. |
|
|
38
|
+
| `invalid_submission` | The submission failed shape validation; `message` names the offending field. |
|
|
39
|
+
| `missing_provider_key` | The submission names a provider but carries no BYOK key for it (`apiKeys[provider]`). |
|
|
40
|
+
| `malformed_token` | The bearer value is not a structurally valid aex token. |
|
|
41
|
+
|
|
42
|
+
400s are permanent for that request — fix the input rather than retrying.
|
|
43
|
+
The SDK's client-side validation (`RunConfigValidationError`) catches most of
|
|
44
|
+
these before the request is sent.
|
|
45
|
+
|
|
46
|
+
## 402 — payment required
|
|
47
|
+
|
|
48
|
+
Two distinct submit gates return 402; both bodies are self-describing.
|
|
49
|
+
|
|
50
|
+
**`insufficient_balance`** — the workspace prepaid balance is at or below the
|
|
51
|
+
effective submit floor. Top up the balance or bind a payment method.
|
|
52
|
+
|
|
53
|
+
```json
|
|
54
|
+
{
|
|
55
|
+
"error": "insufficient_balance",
|
|
56
|
+
"message": "Workspace balance is depleted; top up your prepaid balance or bind a payment method to submit runs.",
|
|
57
|
+
"balanceUsd": 0,
|
|
58
|
+
"balanceGraceFloorUsd": 0,
|
|
59
|
+
"paymentMethodStatus": "none",
|
|
60
|
+
"planKey": "default"
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
`balanceGraceFloorUsd` is the payment-method-aware floor the gate compared
|
|
65
|
+
against (`paymentMethodStatus: "active"` folds a bounded card overdraft into
|
|
66
|
+
it, so the floor can be negative).
|
|
67
|
+
|
|
68
|
+
**`workspace_spend_cap_exceeded`** — the workspace's monthly spend cap is
|
|
69
|
+
reached. The cap resets at the start of the next UTC month; contact support to
|
|
70
|
+
raise it.
|
|
71
|
+
|
|
72
|
+
```json
|
|
73
|
+
{
|
|
74
|
+
"error": "workspace_spend_cap_exceeded",
|
|
75
|
+
"message": "Monthly spend cap of $250 reached ($251.13 accrued this month). The cap resets at the start of the next UTC month; contact support to raise it.",
|
|
76
|
+
"capUsd": 250,
|
|
77
|
+
"accruedUsd": 251.13
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## 429 — rate limits
|
|
82
|
+
|
|
83
|
+
**`workspace_concurrency_exceeded`** — admitting one more live run would exceed
|
|
84
|
+
the workspace's concurrent-run cap. Wait for a run to finish, or contact
|
|
85
|
+
support to raise the cap.
|
|
86
|
+
|
|
87
|
+
```json
|
|
88
|
+
{
|
|
89
|
+
"error": "workspace_concurrency_exceeded",
|
|
90
|
+
"message": "Workspace concurrency limit reached: 50 live runs at the cap of 50. Wait for a run to finish, or contact support to raise your workspace limit.",
|
|
91
|
+
"cap": 50,
|
|
92
|
+
"observed": 50
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
**`workspace_submit_rate_exceeded`** — too many submits in the current
|
|
97
|
+
one-minute window. Retry shortly.
|
|
98
|
+
|
|
99
|
+
```json
|
|
100
|
+
{
|
|
101
|
+
"error": "workspace_submit_rate_exceeded",
|
|
102
|
+
"message": "Submit rate limit of 120/minute exceeded. Retry shortly, or contact support to raise your workspace limit.",
|
|
103
|
+
"perMin": 120,
|
|
104
|
+
"observed": 121
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
The `limit`-naming fields (`cap`/`perMin`) and the `observed` window value make
|
|
109
|
+
each deny self-describing, so a client can back off proportionally. To
|
|
110
|
+
anticipate both 429s and both 402s *before* submitting, read the effective caps
|
|
111
|
+
from `aex.whoami().limits` — the values come from the same resolution code the
|
|
112
|
+
gates enforce. See [Limits & quotas](limits-and-quotas.md).
|
|
113
|
+
|
|
114
|
+
## 404 — not found
|
|
115
|
+
|
|
116
|
+
`not_found`: the id does not exist **or** belongs to another workspace (aex
|
|
117
|
+
does not distinguish the two).
|
|
118
|
+
|
|
119
|
+
## 5xx — server errors
|
|
120
|
+
|
|
121
|
+
| Code | Meaning |
|
|
122
|
+
| --- | --- |
|
|
123
|
+
| `internal_error` (500) | Unexpected server fault. Retry with backoff; report persistent cases. |
|
|
124
|
+
| `db_resuming` (503) | The database tier is resuming from idle. Transient — retry. |
|
|
125
|
+
|
|
126
|
+
The SDK retries transient failures automatically: HTTP `429`, `5xx`, `529`, and
|
|
127
|
+
network errors get bounded exponential backoff with full jitter, honoring any
|
|
128
|
+
`Retry-After` header. Tune or disable this with the client `retry` option; use
|
|
129
|
+
`isRateLimited(err)` / `AexRateLimitError` to handle persistent throttling
|
|
130
|
+
without parsing raw bodies. Idempotent submit retries are safe — the SDK
|
|
131
|
+
attaches a stable idempotency key to billable session create/send requests, so
|
|
132
|
+
a retried request never double-submits.
|