@aexhq/sdk 0.34.0 → 0.36.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.
Files changed (63) hide show
  1. package/README.md +16 -15
  2. package/dist/_contracts/index.d.ts +3 -4
  3. package/dist/_contracts/index.js +1 -4
  4. package/dist/_contracts/operations.d.ts +2 -1
  5. package/dist/_contracts/operations.js +10 -0
  6. package/dist/_contracts/run-config.d.ts +1 -3
  7. package/dist/_contracts/run-config.js +2 -7
  8. package/dist/_contracts/run-trace.d.ts +0 -86
  9. package/dist/_contracts/run-trace.js +1 -184
  10. package/dist/_contracts/run-unit.d.ts +2 -25
  11. package/dist/_contracts/run-unit.js +1 -2
  12. package/dist/_contracts/runtime-manifest.d.ts +1 -1
  13. package/dist/_contracts/runtime-security-profile.d.ts +0 -2
  14. package/dist/_contracts/runtime-security-profile.js +0 -9
  15. package/dist/_contracts/runtime-types.d.ts +25 -4
  16. package/dist/_contracts/stable.d.ts +1 -1
  17. package/dist/_contracts/stable.js +1 -1
  18. package/dist/_contracts/submission.d.ts +62 -95
  19. package/dist/_contracts/submission.js +59 -482
  20. package/dist/cli.mjs +99 -442
  21. package/dist/cli.mjs.sha256 +1 -1
  22. package/dist/client.d.ts +49 -25
  23. package/dist/client.js +341 -70
  24. package/dist/client.js.map +1 -1
  25. package/dist/index.d.ts +9 -15
  26. package/dist/index.js +11 -17
  27. package/dist/index.js.map +1 -1
  28. package/dist/retry.d.ts +162 -0
  29. package/dist/retry.js +320 -0
  30. package/dist/retry.js.map +1 -0
  31. package/dist/secret.d.ts +2 -2
  32. package/dist/secret.js +1 -1
  33. package/dist/version.d.ts +1 -1
  34. package/dist/version.js +1 -1
  35. package/docs/concepts/composition.md +8 -14
  36. package/docs/credentials.md +59 -101
  37. package/docs/defaults.md +0 -8
  38. package/docs/events.md +8 -9
  39. package/docs/limits-and-quotas.md +1 -4
  40. package/docs/limits.md +2 -6
  41. package/docs/mcp.md +4 -5
  42. package/docs/networking.md +6 -16
  43. package/docs/outputs.md +0 -4
  44. package/docs/public-surface.json +3 -3
  45. package/docs/quickstart.md +3 -7
  46. package/docs/retries.md +129 -0
  47. package/docs/run-config.md +6 -3
  48. package/docs/secrets.md +1 -1
  49. package/docs/skills.md +3 -3
  50. package/docs/vision-skills.md +52 -101
  51. package/examples/feature-tour.ts +284 -0
  52. package/package.json +1 -1
  53. package/dist/_contracts/proxy-protocol.d.ts +0 -305
  54. package/dist/_contracts/proxy-protocol.js +0 -297
  55. package/dist/_contracts/proxy-validation.d.ts +0 -19
  56. package/dist/_contracts/proxy-validation.js +0 -51
  57. package/dist/data-tools.d.ts +0 -82
  58. package/dist/data-tools.js +0 -251
  59. package/dist/data-tools.js.map +0 -1
  60. package/dist/proxy-endpoint.d.ts +0 -131
  61. package/dist/proxy-endpoint.js +0 -144
  62. package/dist/proxy-endpoint.js.map +0 -1
  63. package/examples/chat-corpus.ts +0 -84
package/dist/retry.js ADDED
@@ -0,0 +1,320 @@
1
+ /**
2
+ * Built-in transport resilience for the aex SDK.
3
+ *
4
+ * Every BFF-bound request the SDK makes goes through one {@link FetchLike}. This
5
+ * module wraps that fetch so a transient failure — an HTTP 429 (rate limited),
6
+ * a 500/502/503/504 (server hiccup), a 529 (upstream overloaded), or a network
7
+ * error — is retried with BOUNDED exponential backoff + full jitter, honoring
8
+ * the server's `Retry-After` header when present. Non-retryable 4xx responses
9
+ * (400/401/403/404/…) fail fast — retrying them only wastes the caller's time.
10
+ *
11
+ * Retries are SAFE to enable by default because the billable submits
12
+ * (`createSession` / `sendSessionMessage`) carry a stable `Idempotency-Key`
13
+ * header: re-sending the identical request de-duplicates server-side, so a retry
14
+ * never creates a duplicate billable turn.
15
+ *
16
+ * When retries are exhausted on a rate-limit / overloaded status the wrapper
17
+ * surfaces an {@link AexRateLimitError} — a structured, non-leaky throttle error
18
+ * carrying the parsed `retryAfterMs`, the attempt count, and (when the runtime
19
+ * supplies it) an upstream {@link ProviderFault}. All other exhausted retries
20
+ * fall through to the transport's usual `AexApiError` / network rejection.
21
+ */
22
+ import { AexApiError } from "./_contracts/index.js";
23
+ /**
24
+ * HTTP statuses that are transient and worth retrying. The billable submits
25
+ * carry an idempotency key, so re-issuing them is safe. Everything not in this
26
+ * set (400/401/403/404/409/422/…) is a definitive client error and fails fast.
27
+ */
28
+ export const RETRYABLE_STATUS = [429, 500, 502, 503, 504, 529];
29
+ /**
30
+ * The subset of {@link RETRYABLE_STATUS} the platform / upstream provider uses to
31
+ * say "slow down": 429 rate-limit, 503 unavailable, 529 overloaded. When retries
32
+ * for one of these run out, the wrapper raises an {@link AexRateLimitError}.
33
+ */
34
+ export const RATE_LIMIT_STATUS = [429, 503, 529];
35
+ const DEFAULT_RETRY = {
36
+ maxAttempts: 4,
37
+ initialDelayMs: 500,
38
+ maxDelayMs: 20_000,
39
+ maxElapsedMs: 120_000
40
+ };
41
+ /** Resolve caller options over the defaults, clamping to sane bounds. */
42
+ export function resolveRetryConfig(options) {
43
+ const maxAttempts = Math.max(1, Math.floor(options?.maxAttempts ?? DEFAULT_RETRY.maxAttempts));
44
+ const initialDelayMs = Math.max(0, options?.initialDelayMs ?? DEFAULT_RETRY.initialDelayMs);
45
+ const maxDelayMs = Math.max(initialDelayMs, options?.maxDelayMs ?? DEFAULT_RETRY.maxDelayMs);
46
+ const maxElapsedMs = Math.max(0, options?.maxElapsedMs ?? DEFAULT_RETRY.maxElapsedMs);
47
+ return { maxAttempts, initialDelayMs, maxDelayMs, maxElapsedMs };
48
+ }
49
+ export function isRetryableStatus(status) {
50
+ return RETRYABLE_STATUS.includes(status);
51
+ }
52
+ export function isRateLimitStatus(status) {
53
+ return RATE_LIMIT_STATUS.includes(status);
54
+ }
55
+ /**
56
+ * Parse an HTTP `Retry-After` header into milliseconds. Per RFC 7231 the value
57
+ * is either a non-negative integer number of seconds or an HTTP-date; both are
58
+ * handled. Returns `undefined` for a missing or unparseable value.
59
+ */
60
+ export function parseRetryAfterMs(headerValue, now = Date.now()) {
61
+ if (headerValue === null || headerValue === undefined)
62
+ return undefined;
63
+ const trimmed = headerValue.trim();
64
+ if (trimmed.length === 0)
65
+ return undefined;
66
+ if (/^\d+$/.test(trimmed)) {
67
+ return Number(trimmed) * 1000;
68
+ }
69
+ const dateMs = Date.parse(trimmed);
70
+ if (!Number.isNaN(dateMs)) {
71
+ return Math.max(0, dateMs - now);
72
+ }
73
+ return undefined;
74
+ }
75
+ /**
76
+ * Full-jitter exponential backoff (AWS-style): the nominal wait doubles per
77
+ * retry up to `maxDelayMs`, and the actual wait is a uniform sample in
78
+ * `[0, nominal]` to de-correlate concurrent clients. `attemptNumber` is the
79
+ * 1-based number of the attempt that just failed.
80
+ */
81
+ export function computeBackoffDelayMs(config, attemptNumber, random) {
82
+ const exponent = Math.max(0, attemptNumber - 1);
83
+ const nominal = Math.min(config.maxDelayMs, config.initialDelayMs * 2 ** exponent);
84
+ return Math.round(random() * nominal);
85
+ }
86
+ /** Combine the server's `Retry-After` (a floor) with our jittered backoff. */
87
+ function nextDelayMs(config, attemptNumber, random, retryAfterMs) {
88
+ const backoff = computeBackoffDelayMs(config, attemptNumber, random);
89
+ return retryAfterMs === undefined ? backoff : Math.max(retryAfterMs, backoff);
90
+ }
91
+ const THROTTLE_KINDS = new Set(["rate_limit", "overloaded", "quota_exceeded"]);
92
+ /** True when a {@link ProviderFault} represents a "back off and retry" signal. */
93
+ export function isThrottleFault(fault) {
94
+ return THROTTLE_KINDS.has(fault.kind);
95
+ }
96
+ /**
97
+ * Structured throttle error. Extends {@link AexApiError} so existing
98
+ * `catch (err instanceof AexApiError)` sites keep working, while callers that
99
+ * want the details narrow with {@link isRateLimited} and read `retryAfterMs`,
100
+ * `attempts`, `source`, and `providerFault`. The `message` is a fixed,
101
+ * non-leaky summary — it never echoes the raw error body (which is still
102
+ * available, redacted, on `.body`).
103
+ */
104
+ export class AexRateLimitError extends AexApiError {
105
+ /** Milliseconds the server/provider asked us to wait, when known. */
106
+ retryAfterMs;
107
+ /** How many attempts were made before giving up. */
108
+ attempts;
109
+ /** Whether the throttle came from the aex API plane or the upstream provider. */
110
+ source;
111
+ /** The upstream provider fault, when the throttle originated there. */
112
+ providerFault;
113
+ constructor(args) {
114
+ super(args.status, args.message ?? defaultThrottleMessage(args), args.body);
115
+ this.attempts = args.attempts;
116
+ this.source = args.source ?? "api";
117
+ if (args.retryAfterMs !== undefined)
118
+ this.retryAfterMs = args.retryAfterMs;
119
+ if (args.providerFault !== undefined)
120
+ this.providerFault = args.providerFault;
121
+ }
122
+ }
123
+ /** Type guard for {@link AexRateLimitError}. */
124
+ export function isRateLimited(err) {
125
+ return err instanceof AexRateLimitError;
126
+ }
127
+ function defaultThrottleMessage(args) {
128
+ const who = args.source === "provider" ? "upstream provider" : "aex API";
129
+ const label = args.status === 529 ? "overloaded" : "rate limit reached";
130
+ const attempts = `${args.attempts} attempt${args.attempts === 1 ? "" : "s"}`;
131
+ const wait = args.retryAfterMs !== undefined
132
+ ? `; retry after ~${Math.ceil(args.retryAfterMs / 1000)}s`
133
+ : "";
134
+ return `${who} ${label} (HTTP ${args.status}) after ${attempts}${wait}`;
135
+ }
136
+ /**
137
+ * Best-effort parse of an unknown value into a {@link ProviderFault}. Tolerant
138
+ * of two shapes so the SDK consumes the runtime fault the moment it starts
139
+ * emitting one, without a contracts change:
140
+ *
141
+ * 1. The canonical `{ provider?, kind, status?, retryAfterMs?, message? }`
142
+ * (optionally nested under a `providerFault` key), OR
143
+ * 2. A raw upstream error `{ type: "rate_limit_error" | "overloaded_error"
144
+ * | ..., message?, retry_after? | retryAfter? }` — `type` maps to `kind`
145
+ * and `retry_after` (seconds) maps to `retryAfterMs`.
146
+ *
147
+ * Returns `undefined` when the value carries no recognizable fault.
148
+ */
149
+ export function parseProviderFault(value) {
150
+ if (value === null || typeof value !== "object")
151
+ return undefined;
152
+ const record = value;
153
+ const nested = record.providerFault ?? record.provider_fault;
154
+ if (nested !== undefined && nested !== value) {
155
+ const fromNested = parseProviderFault(nested);
156
+ if (fromNested)
157
+ return fromNested;
158
+ }
159
+ const kind = coerceFaultKind(record.kind ?? record.type ?? record.code);
160
+ if (kind === undefined)
161
+ return undefined;
162
+ const provider = typeof record.provider === "string" ? record.provider : undefined;
163
+ const status = coerceStatus(record.status ?? record.statusCode ?? record.httpStatus);
164
+ const retryAfterMs = coerceRetryAfterMs(record.retryAfterMs ?? record.retry_after_ms ?? record.retryAfter ?? record.retry_after);
165
+ const message = typeof record.message === "string" ? record.message : undefined;
166
+ return {
167
+ kind,
168
+ ...(provider !== undefined ? { provider } : {}),
169
+ ...(status !== undefined ? { status } : {}),
170
+ ...(retryAfterMs !== undefined ? { retryAfterMs } : {}),
171
+ ...(message !== undefined ? { message } : {})
172
+ };
173
+ }
174
+ function coerceFaultKind(raw) {
175
+ if (typeof raw !== "string")
176
+ return undefined;
177
+ const value = raw.toLowerCase();
178
+ if (value.includes("rate_limit") || value.includes("rate limit") || value === "429")
179
+ return "rate_limit";
180
+ if (value.includes("overload") || value === "529")
181
+ return "overloaded";
182
+ if (value.includes("quota") || value.includes("insufficient"))
183
+ return "quota_exceeded";
184
+ if (value.includes("provider_error") || value.includes("provider error") || value.includes("api_error")) {
185
+ return "provider_error";
186
+ }
187
+ return undefined;
188
+ }
189
+ function coerceStatus(raw) {
190
+ if (typeof raw === "number" && Number.isFinite(raw))
191
+ return raw;
192
+ if (typeof raw === "string" && /^\d+$/.test(raw.trim()))
193
+ return Number(raw.trim());
194
+ return undefined;
195
+ }
196
+ /** Accept a ms number, a `<digits>` string, or seconds under a `retry_after` alias. */
197
+ function coerceRetryAfterMs(raw) {
198
+ if (typeof raw === "number" && Number.isFinite(raw)) {
199
+ // Heuristic: small integers are seconds (the upstream convention), large
200
+ // ones are already milliseconds.
201
+ return raw > 0 && raw < 1000 ? raw * 1000 : raw;
202
+ }
203
+ if (typeof raw === "string" && /^\d+$/.test(raw.trim())) {
204
+ const n = Number(raw.trim());
205
+ return n > 0 && n < 1000 ? n * 1000 : n;
206
+ }
207
+ return undefined;
208
+ }
209
+ const defaultSleep = (ms, signal) => new Promise((resolve, reject) => {
210
+ if (signal?.aborted) {
211
+ reject(signal.reason instanceof Error ? signal.reason : new DOMException("Aborted", "AbortError"));
212
+ return;
213
+ }
214
+ const timer = setTimeout(() => {
215
+ signal?.removeEventListener("abort", onAbort);
216
+ resolve();
217
+ }, ms);
218
+ const onAbort = () => {
219
+ clearTimeout(timer);
220
+ reject(signal?.reason instanceof Error ? signal.reason : new DOMException("Aborted", "AbortError"));
221
+ };
222
+ signal?.addEventListener("abort", onAbort, { once: true });
223
+ });
224
+ function isAbortError(err) {
225
+ return err instanceof Error && err.name === "AbortError";
226
+ }
227
+ async function drain(response) {
228
+ try {
229
+ if (response.body && typeof response.body.cancel === "function") {
230
+ await response.body.cancel();
231
+ return;
232
+ }
233
+ await response.text();
234
+ }
235
+ catch {
236
+ // Draining is best-effort; a discarded retryable response never surfaces.
237
+ }
238
+ }
239
+ async function readBodyForError(response) {
240
+ try {
241
+ const text = await response.text();
242
+ if (text.length === 0)
243
+ return {};
244
+ try {
245
+ return JSON.parse(text);
246
+ }
247
+ catch {
248
+ return { raw: text };
249
+ }
250
+ }
251
+ catch {
252
+ return {};
253
+ }
254
+ }
255
+ /**
256
+ * Wrap a {@link FetchLike} with the bounded-retry loop. `retry === false`
257
+ * disables the layer entirely (the input fetch is returned unchanged). Otherwise
258
+ * the returned fetch retries transient failures per {@link RetryOptions} and, on
259
+ * an exhausted rate-limit/overloaded status, throws {@link AexRateLimitError}.
260
+ */
261
+ export function withRetry(fetchImpl, retry, deps = {}) {
262
+ if (retry === false)
263
+ return fetchImpl;
264
+ const config = resolveRetryConfig(retry);
265
+ const sleep = deps.sleep ?? defaultSleep;
266
+ const random = deps.random ?? Math.random;
267
+ const now = deps.now ?? Date.now;
268
+ return async (input, init) => {
269
+ const startedAt = now();
270
+ const signal = init?.signal ?? undefined;
271
+ let attempt = 0;
272
+ for (;;) {
273
+ attempt += 1;
274
+ let response;
275
+ try {
276
+ response = await fetchImpl(input, init);
277
+ }
278
+ catch (err) {
279
+ // A caller-initiated abort is terminal, never transient.
280
+ if (isAbortError(err))
281
+ throw err;
282
+ if (attempt >= config.maxAttempts)
283
+ throw err;
284
+ const delay = computeBackoffDelayMs(config, attempt, random);
285
+ if (now() - startedAt + delay > config.maxElapsedMs)
286
+ throw err;
287
+ await sleep(delay, signal ?? undefined);
288
+ continue;
289
+ }
290
+ // Success or a definitive (non-retryable) response — hand straight back so
291
+ // the transport reads/throws exactly as it does without the retry layer.
292
+ if (!isRetryableStatus(response.status)) {
293
+ return response;
294
+ }
295
+ const retryAfterMs = parseRetryAfterMs(response.headers.get("retry-after"), now());
296
+ const willRetry = attempt < config.maxAttempts &&
297
+ now() - startedAt + nextDelayMs(config, attempt, random, retryAfterMs) <= config.maxElapsedMs;
298
+ if (willRetry) {
299
+ await drain(response);
300
+ await sleep(nextDelayMs(config, attempt, random, retryAfterMs), signal ?? undefined);
301
+ continue;
302
+ }
303
+ // Retries exhausted (or budget spent). A rate-limit/overloaded status
304
+ // becomes a structured throttle error; any other transient status falls
305
+ // through to the transport's normal AexApiError.
306
+ if (isRateLimitStatus(response.status)) {
307
+ const body = await readBodyForError(response);
308
+ throw new AexRateLimitError({
309
+ status: response.status,
310
+ attempts: attempt,
311
+ source: "api",
312
+ ...(retryAfterMs !== undefined ? { retryAfterMs } : {}),
313
+ body
314
+ });
315
+ }
316
+ return response;
317
+ }
318
+ };
319
+ }
320
+ //# sourceMappingURL=retry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry.js","sourceRoot":"","sources":["../src/retry.ts"],"names":[],"mappings":"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"}
package/dist/secret.d.ts CHANGED
@@ -12,7 +12,7 @@ export type SecretEnvSubmissionEntry = {
12
12
  };
13
13
  /**
14
14
  * Minimal client surface `secret.upload` needs to promote an ephemeral secret
15
- * into the workspace store. `AgentExecutor` satisfies it via its `secrets`
15
+ * into the workspace store. `Aex` satisfies it via its `secrets`
16
16
  * client; defined structurally here so `secret.ts` does not import `client.ts`
17
17
  * (which would be circular — `client.ts` imports `Secret`). Mirrors
18
18
  * {@link SkillUploader}.
@@ -88,7 +88,7 @@ export declare class Secret {
88
88
  /**
89
89
  * Split `secretEnv: Record<envName, Secret>` into the value-free declarations
90
90
  * (`submission.secretEnv`) and the per-run vaulted values
91
- * (`secrets.envSecrets`). Mirrors {@link splitProxyEndpoints}: declarations ride
91
+ * (`secrets.envSecrets`). Secret declarations ride
92
92
  * the hashed submission, ephemeral values ride the secrets channel
93
93
  * (hash-excluded). Refs contribute only a declaration.
94
94
  *
package/dist/secret.js CHANGED
@@ -116,7 +116,7 @@ export class Secret {
116
116
  /**
117
117
  * Split `secretEnv: Record<envName, Secret>` into the value-free declarations
118
118
  * (`submission.secretEnv`) and the per-run vaulted values
119
- * (`secrets.envSecrets`). Mirrors {@link splitProxyEndpoints}: declarations ride
119
+ * (`secrets.envSecrets`). Secret declarations ride
120
120
  * the hashed submission, ephemeral values ride the secrets channel
121
121
  * (hash-excluded). Refs contribute only a declaration.
122
122
  *
package/dist/version.d.ts CHANGED
@@ -6,4 +6,4 @@
6
6
  *
7
7
  * Used by the (future) User-Agent header on outbound SDK requests.
8
8
  */
9
- export declare const SDK_VERSION = "0.34.0";
9
+ export declare const SDK_VERSION = "0.36.0";
package/dist/version.js CHANGED
@@ -6,5 +6,5 @@
6
6
  *
7
7
  * Used by the (future) User-Agent header on outbound SDK requests.
8
8
  */
9
- export const SDK_VERSION = "0.34.0";
9
+ export const SDK_VERSION = "0.36.0";
10
10
  //# sourceMappingURL=version.js.map
@@ -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, ProxyEndpoint, Tools } from "@aexhq/sdk";
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
- proxyEndpoints: [
31
- ProxyEndpoint.bearer({
32
- name: "internal-api",
33
- baseUrl: "https://api.example.com",
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; MCP auth rides on each `McpServer` instance and proxy auth on each
45
- `ProxyEndpoint` instance the SDK splits them into the vaulted secrets channel
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.
@@ -4,142 +4,100 @@ title: Credentials
4
4
 
5
5
  # Credentials
6
6
 
7
- aex treats provider keys, MCP credentials, and proxy endpoint auth as per-run
8
- credentials. Reusable env secrets are documented separately in
9
- [Secrets](secrets.md).
7
+ aex uses explicit, per-session credentials:
10
8
 
11
- The caller passes a workspace-scoped SDK token and the provider key inline on every `openSession` / `run` call. aex holds the bundle in run-scoped custody for the session lifecycle and attempts terminal cleanup/revocation for the aex-controlled references. MCP credentials and proxy endpoint auth values travel the same way.
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
- A session selects one upstream `provider` (default `anthropic`) and must carry a BYOK
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
- | Field | Required secret |
18
- | --- | --- |
19
- | Provider API keys | `apiKeys` (top-level, keyed by provider) |
16
+ ## Provider keys
17
+
18
+ A session selects one upstream provider and must carry a BYOK key for it. Include
19
+ additional provider keys only when subagents may use those providers.
20
20
 
21
21
  ```ts
22
- // The session's own provider key, plus extra keys its subagents can use.
23
- apiKeys: {
24
- anthropic: process.env.ANTHROPIC_API_KEY!, // the session's provider
25
- deepseek: process.env.DEEPSEEK_API_KEY! // for a cross-provider subagent
26
- }
22
+ const result = await aex.run({
23
+ model: Models.CLAUDE_HAIKU_4_5,
24
+ message: "Write a short report and save it as a file.",
25
+ apiKeys: {
26
+ anthropic: process.env.ANTHROPIC_API_KEY!
27
+ }
28
+ });
27
29
  ```
28
30
 
29
- A `subagent` spawned with a different-family model **inherits the parent's keys
30
- server-side** from the session's vaulted bundle — the keys never transit the
31
- container. If the parent holds no key for the child's provider, the child is
32
- rejected with `parent_missing_provider_key`.
33
-
34
- MCP credential types:
35
-
36
- - `static_bearer`;
37
- - `oauth_access_token`.
31
+ Provider keys are used by the managed runtime for model calls. They are not saved
32
+ as client defaults.
38
33
 
39
- Unsupported:
34
+ ## Runtime secrets
40
35
 
41
- - arbitrary headers;
42
- - OAuth refresh;
43
- - persisted aex vault.
44
-
45
- For managed-runtime 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.
46
-
47
- ## Proxy endpoints (per-run custom HTTP credentials)
48
-
49
- 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.
50
-
51
- The platform's managed HTTP proxy is the agent-first alternative. Declare each endpoint with a `ProxyEndpoint.*` constructor: the instance carries the non-secret **policy** (hashed for idempotency) and its **auth token** together at the call site. The SDK splits the token into the vaulted secrets channel server-side (not hashed, so key rotation does not collapse onto a stale run), and the raw credential value never enters the container.
36
+ Use `environment.secrets` for credentials your code needs at runtime. The value
37
+ can be ephemeral with `Secret.value(...)` or a workspace secret reference with
38
+ `Secret.ref(...)`.
52
39
 
53
40
  ```ts
54
- import { Aex, Models, ProxyEndpoint } from "@aexhq/sdk";
41
+ import { Aex, Models, Secret } from "@aexhq/sdk";
55
42
 
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
- });
43
+ const aex = new Aex({ apiToken: process.env.AEX_API_TOKEN! });
80
44
 
81
45
  await aex.run({
82
46
  model: Models.CLAUDE_HAIKU_4_5,
83
- message: "",
84
- proxyEndpoints: [stripe],
47
+ message: "Call https://api.example.com/v1/status with INTERNAL_API_TOKEN and summarize it.",
48
+ environment: {
49
+ secrets: {
50
+ INTERNAL_API_TOKEN: Secret.value(process.env.INTERNAL_API_TOKEN!)
51
+ },
52
+ networking: {
53
+ mode: "limited",
54
+ allowedHosts: ["api.example.com"]
55
+ }
56
+ },
85
57
  apiKeys: { anthropic: process.env.ANTHROPIC_API_KEY! }
86
58
  });
87
59
  ```
88
60
 
89
- The five constructors — `ProxyEndpoint.none` / `bearer` / `header` / `basic` / `query` — put the auth secret on the same call as the policy, so any drift (wrong `responseMode`, misnamed auth field) is a TypeScript error at the call site instead of an HTTP 400 a round-trip later.
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`):
61
+ Inside the run, use normal HTTP code for the service:
92
62
 
93
63
  ```bash
94
- bun /mnt/session/uploads/aex/aex proxy stripe \
95
- --method GET \
96
- --path /v1/charges/ch_123 \
97
- --response-mode headers_only
64
+ curl -sS \
65
+ -H "Authorization: Bearer $INTERNAL_API_TOKEN" \
66
+ https://api.example.com/v1/status
98
67
  ```
99
68
 
100
- The CLI reads the per-run bearer from `/mnt/session/uploads/aex/run-token`, attaches the `X-Aex-Proxy-Protocol` header, and the hosted proxy 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.
69
+ ## Workspace secrets
101
70
 
102
- Retries are declaration-based. Add `retry` to the endpoint policy when safe for that upstream; runs without `retry` keep single-attempt behavior. `maxAttempts` counts the initial request, and defaults apply only when `retry` is present: `maxAttempts: 3`, `initialDelayMs: 250`, `maxDelayMs: 5000`, `jitter: "full"`, `retryOnStatuses: [408, 425, 429, 500, 502, 503, 504]`, `retryOnMethods: ["GET", "HEAD"]`, and `respectRetryAfter: true`. There are no per-call `aex proxy` retry flags.
103
-
104
- #### Keyless upstreams (`authShape: { type: "none" }`)
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:
71
+ Store reusable values once, then reference them by name:
107
72
 
108
73
  ```ts
109
- import { ProxyEndpoint } from "@aexhq/sdk";
110
-
111
- const wikimedia = ProxyEndpoint.none({
112
- name: "wikimedia",
113
- baseUrl: "https://commons.wikimedia.org",
114
- allowMethods: ["GET"],
115
- allowPathPrefixes: ["/wiki/", "/w/api.php"]
74
+ await aex.secrets.set({
75
+ name: "internal-api-token",
76
+ value: process.env.INTERNAL_API_TOKEN!
116
77
  });
117
78
 
118
79
  await aex.run({
119
80
  model: Models.CLAUDE_HAIKU_4_5,
120
- message: "",
121
- proxyEndpoints: [wikimedia],
81
+ message: "Use INTERNAL_API_TOKEN for the status request.",
82
+ environment: {
83
+ secrets: {
84
+ INTERNAL_API_TOKEN: Secret.ref("internal-api-token")
85
+ }
86
+ },
122
87
  apiKeys: { anthropic: process.env.ANTHROPIC_API_KEY! }
123
88
  });
124
89
  ```
125
90
 
126
- The keyless endpoint still routes through the aex managed proxy: every call is allow-listed, audited, and redacted. The hosted proxy injects no `Authorization` header and no query-string credential.
91
+ Secret reads return metadata only; they never return the stored value.
127
92
 
128
- `bun /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.
93
+ ## Networking
129
94
 
130
- ### Networking
131
-
132
- Networking is open by default. When a run explicitly uses `limited` networking,
133
- the platform host must appear in `allowed_hosts`. aex injects it
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
- ```
95
+ Networking is open by default. Use `environment.networking.mode: "limited"` with
96
+ `allowedHosts` when you want a run to reach only named public hosts. See
97
+ [Networking](networking.md).
142
98
 
143
- ### Secrets are always explicit at the call site
99
+ ## Explicit call-site rule
144
100
 
145
- There is no `defaultSecrets` and no client-held secret state. Every `openSession` / `run` call carries its own credentials at the call site: the top-level `apiKeys` map (one provider key, plus any subagent keys), MCP auth on each `McpServer` instance, and proxy auth on each `ProxyEndpoint` instance. This is the agent-first invariant: the credentials being used on any given call are visible in the same code that opens the session.
101
+ There is no `defaultSecrets` and no client-held secret state. Each
102
+ `openSession(...)` or `run(...)` call should show the provider keys, MCP auth, and
103
+ runtime secrets needed for that call.
package/docs/defaults.md CHANGED
@@ -39,14 +39,6 @@ For the hard ceilings and who can raise them, see
39
39
  | MCP connect timeout (register + initialize + discover) | 30 seconds | Per-port via `connectTimeoutMs`. | `RUN_DEFAULT_MCP_CONNECT_TIMEOUT_MS` |
40
40
  | MCP `tools/call` timeout | 30 minutes | Per-port via `callTimeoutMs`. | `RUN_DEFAULT_MCP_CALL_TIMEOUT_MS` |
41
41
 
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
42
  ## Links (signed URLs and tickets)
51
43
 
52
44
  | Option | Default | How to override | Source |