@aexhq/sdk 0.40.4 → 0.40.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.
Files changed (77) hide show
  1. package/README.md +159 -159
  2. package/dist/_contracts/api-key.js +0 -1
  3. package/dist/_contracts/bundle-manifest.js +0 -1
  4. package/dist/_contracts/connection-ticket.js +0 -1
  5. package/dist/_contracts/error-codes.js +0 -1
  6. package/dist/_contracts/error-factory.js +0 -1
  7. package/dist/_contracts/event-envelope.js +0 -1
  8. package/dist/_contracts/event-stream-client.js +0 -1
  9. package/dist/_contracts/event-view.js +0 -1
  10. package/dist/_contracts/http.js +0 -1
  11. package/dist/_contracts/index.js +0 -1
  12. package/dist/_contracts/internal.d.ts +36 -0
  13. package/dist/_contracts/internal.js +155 -6
  14. package/dist/_contracts/models.js +0 -1
  15. package/dist/_contracts/operations.js +1 -2
  16. package/dist/_contracts/post-hook.js +0 -1
  17. package/dist/_contracts/provider-support.js +0 -1
  18. package/dist/_contracts/run-artifacts.js +0 -1
  19. package/dist/_contracts/run-config.js +0 -1
  20. package/dist/_contracts/run-cost.js +0 -1
  21. package/dist/_contracts/run-custody.js +0 -1
  22. package/dist/_contracts/run-record.js +0 -1
  23. package/dist/_contracts/run-retention.js +0 -1
  24. package/dist/_contracts/run-trace.js +0 -1
  25. package/dist/_contracts/run-unit.js +0 -1
  26. package/dist/_contracts/runner-event.js +0 -1
  27. package/dist/_contracts/runtime-manifest.js +0 -1
  28. package/dist/_contracts/runtime-security-profile.js +0 -1
  29. package/dist/_contracts/runtime-sizes.js +0 -1
  30. package/dist/_contracts/runtime-types.js +0 -1
  31. package/dist/_contracts/sdk-errors.js +0 -1
  32. package/dist/_contracts/sdk-secrets.js +0 -1
  33. package/dist/_contracts/side-effect-audit.js +0 -1
  34. package/dist/_contracts/sse.js +0 -0
  35. package/dist/_contracts/stable.js +0 -1
  36. package/dist/_contracts/status.js +0 -1
  37. package/dist/_contracts/submission.js +0 -1
  38. package/dist/_contracts/suggest.js +0 -1
  39. package/dist/_contracts/webhook-verify.js +0 -1
  40. package/dist/asset-upload.d.ts +3 -43
  41. package/dist/asset-upload.js +1 -109
  42. package/dist/asset-upload.js.map +1 -1
  43. package/dist/cli.mjs +354 -781
  44. package/dist/cli.mjs.sha256 +1 -1
  45. package/dist/fetch-archive.js +76 -16
  46. package/dist/fetch-archive.js.map +1 -1
  47. package/dist/version.d.ts +1 -1
  48. package/dist/version.js +1 -1
  49. package/docs/authentication.md +125 -125
  50. package/docs/billing.md +118 -118
  51. package/docs/concepts/agent-tools.md +66 -66
  52. package/docs/concepts/composition.md +37 -37
  53. package/docs/concepts/providers-and-runtimes.md +54 -54
  54. package/docs/concepts/runs.md +49 -49
  55. package/docs/concepts/subagents.md +88 -88
  56. package/docs/credentials.md +125 -125
  57. package/docs/defaults.md +64 -64
  58. package/docs/errors.md +196 -196
  59. package/docs/events.md +243 -243
  60. package/docs/limits-and-quotas.md +144 -144
  61. package/docs/limits.md +50 -50
  62. package/docs/mcp.md +44 -44
  63. package/docs/networking.md +163 -163
  64. package/docs/outputs.md +267 -267
  65. package/docs/public-surface.json +77 -77
  66. package/docs/quickstart.md +119 -119
  67. package/docs/release.md +38 -38
  68. package/docs/retries.md +129 -129
  69. package/docs/run-config.md +58 -58
  70. package/docs/run-record.md +55 -55
  71. package/docs/secrets.md +125 -130
  72. package/docs/testing.md +35 -35
  73. package/docs/vision-skills.md +91 -91
  74. package/docs/webhooks.md +127 -131
  75. package/examples/feature-tour.ts +282 -282
  76. package/examples/spike-settle-latency.ts +125 -125
  77. package/package.json +1 -1
package/docs/errors.md CHANGED
@@ -1,196 +1,196 @@
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.
9
-
10
- ## Typed errors in the SDK
11
-
12
- The SDK maps every non-2xx response through one factory to a typed exception. All
13
- inherit `AexApiError`, which carries the HTTP `status`, the redacted parsed
14
- `body`, the server's stable `apiCode` (a machine-branchable identity distinct
15
- from the human `message`), and a `requestId` for support correlation. The
16
- factory dispatches to a subclass by code/status:
17
-
18
- | Class | Fires for | Extra fields |
19
- | --- | --- | --- |
20
- | `AexAuthError` | `401` / `403` (unauthorized, forbidden, insufficient_scope, token_invalid/revoked/expired, malformed_token) | `requiredScope` (on `insufficient_scope`) |
21
- | `AexIdempotencyConflictError` | `409` `idempotency_conflict` | — |
22
- | `AexNotFoundError` | `404` `not_found` | — |
23
- | `AexRateLimitError` | `429` (rate_limited, workspace_concurrency_exceeded, workspace_submit_rate_exceeded) | `retryAfterMs` (when advertised) |
24
- | `AexApiError` (base) | every other stable code (session_busy, run_not_terminal, insufficient_balance, workspace_spend_cap_exceeded, upstream_error, internal_error, …) | — |
25
-
26
- Branch with the exported guards instead of parsing bodies or matching status
27
- codes: `isAuthError`, `isInsufficientScope`, `isIdempotencyConflict`,
28
- `isNotFound`, and `isRateLimited`.
29
-
30
- ```ts
31
- import { isInsufficientScope, isIdempotencyConflict } from "@aexhq/sdk";
32
-
33
- try {
34
- await aex.run(config);
35
- } catch (err) {
36
- if (isInsufficientScope(err)) {
37
- // err.requiredScope names the missing scope; mint a key that includes it.
38
- } else if (isIdempotencyConflict(err)) {
39
- // same key, different body — use a fresh key or resend the byte-identical body.
40
- }
41
- }
42
- ```
43
-
44
- The **stable** `apiCode` set the SDK types and dispatches on is: `unauthorized`,
45
- `forbidden`, `insufficient_scope`, `token_invalid`, `token_revoked`,
46
- `token_expired`, `malformed_token`, `not_found`, `idempotency_conflict`,
47
- `session_busy`, `run_not_terminal`, `unknown_workspace`,
48
- `workspace_concurrency_exceeded`, `workspace_submit_rate_exceeded`,
49
- `workspace_spend_cap_exceeded`, `insufficient_balance`, `rate_limited`,
50
- `upstream_error`, `internal_error`. A code outside this set (e.g. a validation
51
- `error` a route reports) still surfaces as an `AexApiError` with the `status` and
52
- `body.error` preserved; `apiCode` is then `undefined`.
53
-
54
- Transport failures with no HTTP response (DNS, connection refused, TLS reset)
55
- surface as `AexNetworkError`; client-side config validation surfaces as
56
- `RunConfigValidationError` (`err.code === "RUN_CONFIG_INVALID"`) before any
57
- request is sent.
58
-
59
- ## 401 — authentication
60
-
61
- | Code | Meaning |
62
- | --- | --- |
63
- | `unauthorized` | Missing or empty bearer token. |
64
- | `token_invalid` | Bearer token is structurally valid but does not match a live credential, has a bad signature, or belongs to an inactive workspace. |
65
- | `token_revoked` | Bearer token matched a revoked credential. |
66
- | `token_expired` | Short-lived internal writer token is past its expiry. |
67
-
68
- Check the token value and that it has not been deleted or revoked. `aex whoami`
69
- is the cheapest way to validate a credential. See
70
- [Authentication](authentication.md).
71
-
72
- ## 403 — authorization
73
-
74
- | Code | Meaning |
75
- | --- | --- |
76
- | `insufficient_scope` | The token is valid but lacks the route's required scope. The body's `requiredScope` field names the missing scope. |
77
- | `unknown_workspace` | The token does not route to a known workspace. |
78
- | `forbidden` | The authenticated workspace does not own the addressed resource. |
79
-
80
- ```json
81
- { "error": "insufficient_scope", "requiredScope": "runs:write" }
82
- ```
83
-
84
- ## 400 — validation
85
-
86
- | Code | Meaning |
87
- | --- | --- |
88
- | `bad_request` | Missing or unparseable request body. |
89
- | `invalid_submission` | The submission failed shape validation; `message` names the offending field. |
90
- | `missing_provider_key` | The submission names a provider but carries no BYOK key for it (`apiKeys[provider]`). |
91
- | `malformed_token` | The bearer value is not a structurally valid aex token. |
92
-
93
- 400s are permanent for that request — fix the input rather than retrying.
94
- The SDK's client-side validation (`RunConfigValidationError`) catches most of
95
- these before the request is sent.
96
-
97
- ## 402 — payment required
98
-
99
- Two distinct submit gates return 402; both bodies are self-describing.
100
-
101
- **`insufficient_balance`** — the workspace prepaid balance is at or below the
102
- effective submit floor. Top up the balance or bind a payment method.
103
-
104
- ```json
105
- {
106
- "error": "insufficient_balance",
107
- "message": "Workspace balance is depleted; top up your prepaid balance or bind a payment method to submit runs.",
108
- "balanceUsd": 0,
109
- "balanceGraceFloorUsd": 0,
110
- "paymentMethodStatus": "none",
111
- "planKey": "default"
112
- }
113
- ```
114
-
115
- `balanceGraceFloorUsd` is the payment-method-aware floor the gate compared
116
- against (`paymentMethodStatus: "active"` folds a bounded card overdraft into
117
- it, so the floor can be negative).
118
-
119
- **`workspace_spend_cap_exceeded`** — the workspace's monthly spend cap is
120
- reached. The cap resets at the start of the next UTC month; contact support to
121
- raise it.
122
-
123
- ```json
124
- {
125
- "error": "workspace_spend_cap_exceeded",
126
- "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.",
127
- "capUsd": 250,
128
- "accruedUsd": 251.13
129
- }
130
- ```
131
-
132
- ## 429 — rate limits
133
-
134
- **`workspace_concurrency_exceeded`** — admitting one more live run would exceed
135
- the workspace's concurrent-run cap. Wait for a run to finish, or contact
136
- support to raise the cap.
137
-
138
- ```json
139
- {
140
- "error": "workspace_concurrency_exceeded",
141
- "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.",
142
- "cap": 50,
143
- "observed": 50
144
- }
145
- ```
146
-
147
- **`workspace_submit_rate_exceeded`** — too many submits in the current
148
- one-minute window. Retry shortly.
149
-
150
- ```json
151
- {
152
- "error": "workspace_submit_rate_exceeded",
153
- "message": "Submit rate limit of 120/minute exceeded. Retry shortly, or contact support to raise your workspace limit.",
154
- "perMin": 120,
155
- "observed": 121
156
- }
157
- ```
158
-
159
- The `limit`-naming fields (`cap`/`perMin`) and the `observed` window value make
160
- each deny self-describing, so a client can back off proportionally. To
161
- anticipate both 429s and both 402s *before* submitting, read the effective caps
162
- from `aex.whoami().limits` — the values come from the same resolution code the
163
- gates enforce. See [Limits & quotas](limits-and-quotas.md).
164
-
165
- ## 404 — not found
166
-
167
- `not_found`: the id does not exist **or** belongs to another workspace (aex
168
- does not distinguish the two). The SDK raises `AexNotFoundError` (guard:
169
- `isNotFound(err)`).
170
-
171
- ## 409 — idempotency conflict
172
-
173
- `idempotency_conflict`: the `idempotencyKey` was already used with a **different**
174
- request body. The SDK raises `AexIdempotencyConflictError` (guard:
175
- `isIdempotencyConflict(err)`).
176
-
177
- **Remedy:** use a fresh idempotency key for a genuinely new request, or resubmit
178
- the byte-identical body to replay the original result (a matching retry returns
179
- the existing session rather than conflicting). Note that the SDK validates the
180
- key client-side first: an empty or whitespace-only `idempotencyKey` throws
181
- `RunConfigValidationError` before the request is sent — never pass `""`.
182
-
183
- ## 5xx — server errors
184
-
185
- | Code | Meaning |
186
- | --- | --- |
187
- | `internal_error` (500) | Unexpected server fault. Retry with backoff; report persistent cases. |
188
- | `db_resuming` (503) | The database tier is resuming from idle. Transient — retry. |
189
-
190
- The SDK retries transient failures automatically: HTTP `429`, `5xx`, `529`, and
191
- network errors get bounded exponential backoff with full jitter, honoring any
192
- `Retry-After` header. Tune or disable this with the client `retry` option; use
193
- `isRateLimited(err)` / `AexRateLimitError` to handle persistent throttling
194
- without parsing raw bodies. Idempotent submit retries are safe — the SDK
195
- attaches a stable idempotency key to billable session create/send requests, so
196
- a retried request never double-submits.
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.
9
+
10
+ ## Typed errors in the SDK
11
+
12
+ The SDK maps every non-2xx response through one factory to a typed exception. All
13
+ inherit `AexApiError`, which carries the HTTP `status`, the redacted parsed
14
+ `body`, the server's stable `apiCode` (a machine-branchable identity distinct
15
+ from the human `message`), and a `requestId` for support correlation. The
16
+ factory dispatches to a subclass by code/status:
17
+
18
+ | Class | Fires for | Extra fields |
19
+ | --- | --- | --- |
20
+ | `AexAuthError` | `401` / `403` (unauthorized, forbidden, insufficient_scope, token_invalid/revoked/expired, malformed_token) | `requiredScope` (on `insufficient_scope`) |
21
+ | `AexIdempotencyConflictError` | `409` `idempotency_conflict` | — |
22
+ | `AexNotFoundError` | `404` `not_found` | — |
23
+ | `AexRateLimitError` | `429` (rate_limited, workspace_concurrency_exceeded, workspace_submit_rate_exceeded) | `retryAfterMs` (when advertised) |
24
+ | `AexApiError` (base) | every other stable code (session_busy, run_not_terminal, insufficient_balance, workspace_spend_cap_exceeded, upstream_error, internal_error, …) | — |
25
+
26
+ Branch with the exported guards instead of parsing bodies or matching status
27
+ codes: `isAuthError`, `isInsufficientScope`, `isIdempotencyConflict`,
28
+ `isNotFound`, and `isRateLimited`.
29
+
30
+ ```ts
31
+ import { isInsufficientScope, isIdempotencyConflict } from "@aexhq/sdk";
32
+
33
+ try {
34
+ await aex.run(config);
35
+ } catch (err) {
36
+ if (isInsufficientScope(err)) {
37
+ // err.requiredScope names the missing scope; mint a key that includes it.
38
+ } else if (isIdempotencyConflict(err)) {
39
+ // same key, different body — use a fresh key or resend the byte-identical body.
40
+ }
41
+ }
42
+ ```
43
+
44
+ The **stable** `apiCode` set the SDK types and dispatches on is: `unauthorized`,
45
+ `forbidden`, `insufficient_scope`, `token_invalid`, `token_revoked`,
46
+ `token_expired`, `malformed_token`, `not_found`, `idempotency_conflict`,
47
+ `session_busy`, `run_not_terminal`, `unknown_workspace`,
48
+ `workspace_concurrency_exceeded`, `workspace_submit_rate_exceeded`,
49
+ `workspace_spend_cap_exceeded`, `insufficient_balance`, `rate_limited`,
50
+ `upstream_error`, `internal_error`. A code outside this set (e.g. a validation
51
+ `error` a route reports) still surfaces as an `AexApiError` with the `status` and
52
+ `body.error` preserved; `apiCode` is then `undefined`.
53
+
54
+ Transport failures with no HTTP response (DNS, connection refused, TLS reset)
55
+ surface as `AexNetworkError`; client-side config validation surfaces as
56
+ `RunConfigValidationError` (`err.code === "RUN_CONFIG_INVALID"`) before any
57
+ request is sent.
58
+
59
+ ## 401 — authentication
60
+
61
+ | Code | Meaning |
62
+ | --- | --- |
63
+ | `unauthorized` | Missing or empty bearer token. |
64
+ | `token_invalid` | Bearer token is structurally valid but does not match a live credential, has a bad signature, or belongs to an inactive workspace. |
65
+ | `token_revoked` | Bearer token matched a revoked credential. |
66
+ | `token_expired` | Short-lived internal writer token is past its expiry. |
67
+
68
+ Check the token value and that it has not been deleted or revoked. `aex whoami`
69
+ is the cheapest way to validate a credential. See
70
+ [Authentication](authentication.md).
71
+
72
+ ## 403 — authorization
73
+
74
+ | Code | Meaning |
75
+ | --- | --- |
76
+ | `insufficient_scope` | The token is valid but lacks the route's required scope. The body's `requiredScope` field names the missing scope. |
77
+ | `unknown_workspace` | The token does not route to a known workspace. |
78
+ | `forbidden` | The authenticated workspace does not own the addressed resource. |
79
+
80
+ ```json
81
+ { "error": "insufficient_scope", "requiredScope": "runs:write" }
82
+ ```
83
+
84
+ ## 400 — validation
85
+
86
+ | Code | Meaning |
87
+ | --- | --- |
88
+ | `bad_request` | Missing or unparseable request body. |
89
+ | `invalid_submission` | The submission failed shape validation; `message` names the offending field. |
90
+ | `missing_provider_key` | The submission names a provider but carries no BYOK key for it (`apiKeys[provider]`). |
91
+ | `malformed_token` | The bearer value is not a structurally valid aex token. |
92
+
93
+ 400s are permanent for that request — fix the input rather than retrying.
94
+ The SDK's client-side validation (`RunConfigValidationError`) catches most of
95
+ these before the request is sent.
96
+
97
+ ## 402 — payment required
98
+
99
+ Two distinct submit gates return 402; both bodies are self-describing.
100
+
101
+ **`insufficient_balance`** — the workspace prepaid balance is at or below the
102
+ effective submit floor. Top up the balance or bind a payment method.
103
+
104
+ ```json
105
+ {
106
+ "error": "insufficient_balance",
107
+ "message": "Workspace balance is depleted; top up your prepaid balance or bind a payment method to submit runs.",
108
+ "balanceUsd": 0,
109
+ "balanceGraceFloorUsd": 0,
110
+ "paymentMethodStatus": "none",
111
+ "planKey": "default"
112
+ }
113
+ ```
114
+
115
+ `balanceGraceFloorUsd` is the payment-method-aware floor the gate compared
116
+ against (`paymentMethodStatus: "active"` folds a bounded card overdraft into
117
+ it, so the floor can be negative).
118
+
119
+ **`workspace_spend_cap_exceeded`** — the workspace's monthly spend cap is
120
+ reached. The cap resets at the start of the next UTC month; contact support to
121
+ raise it.
122
+
123
+ ```json
124
+ {
125
+ "error": "workspace_spend_cap_exceeded",
126
+ "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.",
127
+ "capUsd": 250,
128
+ "accruedUsd": 251.13
129
+ }
130
+ ```
131
+
132
+ ## 429 — rate limits
133
+
134
+ **`workspace_concurrency_exceeded`** — admitting one more live run would exceed
135
+ the workspace's concurrent-run cap. Wait for a run to finish, or contact
136
+ support to raise the cap.
137
+
138
+ ```json
139
+ {
140
+ "error": "workspace_concurrency_exceeded",
141
+ "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.",
142
+ "cap": 50,
143
+ "observed": 50
144
+ }
145
+ ```
146
+
147
+ **`workspace_submit_rate_exceeded`** — too many submits in the current
148
+ one-minute window. Retry shortly.
149
+
150
+ ```json
151
+ {
152
+ "error": "workspace_submit_rate_exceeded",
153
+ "message": "Submit rate limit of 120/minute exceeded. Retry shortly, or contact support to raise your workspace limit.",
154
+ "perMin": 120,
155
+ "observed": 121
156
+ }
157
+ ```
158
+
159
+ The `limit`-naming fields (`cap`/`perMin`) and the `observed` window value make
160
+ each deny self-describing, so a client can back off proportionally. To
161
+ anticipate both 429s and both 402s *before* submitting, read the effective caps
162
+ from `aex.whoami().limits` — the values come from the same resolution code the
163
+ gates enforce. See [Limits & quotas](limits-and-quotas.md).
164
+
165
+ ## 404 — not found
166
+
167
+ `not_found`: the id does not exist **or** belongs to another workspace (aex
168
+ does not distinguish the two). The SDK raises `AexNotFoundError` (guard:
169
+ `isNotFound(err)`).
170
+
171
+ ## 409 — idempotency conflict
172
+
173
+ `idempotency_conflict`: the `idempotencyKey` was already used with a **different**
174
+ request body. The SDK raises `AexIdempotencyConflictError` (guard:
175
+ `isIdempotencyConflict(err)`).
176
+
177
+ **Remedy:** use a fresh idempotency key for a genuinely new request, or resubmit
178
+ the byte-identical body to replay the original result (a matching retry returns
179
+ the existing session rather than conflicting). Note that the SDK validates the
180
+ key client-side first: an empty or whitespace-only `idempotencyKey` throws
181
+ `RunConfigValidationError` before the request is sent — never pass `""`.
182
+
183
+ ## 5xx — server errors
184
+
185
+ | Code | Meaning |
186
+ | --- | --- |
187
+ | `internal_error` (500) | Unexpected server fault. Retry with backoff; report persistent cases. |
188
+ | `db_resuming` (503) | The database tier is resuming from idle. Transient — retry. |
189
+
190
+ The SDK retries transient failures automatically: HTTP `429`, `5xx`, `529`, and
191
+ network errors get bounded exponential backoff with full jitter, honoring any
192
+ `Retry-After` header. Tune or disable this with the client `retry` option; use
193
+ `isRateLimited(err)` / `AexRateLimitError` to handle persistent throttling
194
+ without parsing raw bodies. Idempotent submit retries are safe — the SDK
195
+ attaches a stable idempotency key to billable session create/send requests, so
196
+ a retried request never double-submits.