@aexhq/sdk 0.15.2 → 0.16.1

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 (40) hide show
  1. package/README.md +11 -8
  2. package/dist/_contracts/index.d.ts +2 -0
  3. package/dist/_contracts/index.js +2 -0
  4. package/dist/_contracts/internal.d.ts +2 -0
  5. package/dist/_contracts/internal.js +2 -0
  6. package/dist/_contracts/managed-key.d.ts +3 -2
  7. package/dist/_contracts/models.d.ts +33 -0
  8. package/dist/_contracts/models.js +59 -0
  9. package/dist/_contracts/post-hook.d.ts +28 -0
  10. package/dist/_contracts/post-hook.js +68 -0
  11. package/dist/_contracts/proxy-protocol.d.ts +14 -18
  12. package/dist/_contracts/proxy-protocol.js +16 -15
  13. package/dist/_contracts/run-config.d.ts +15 -17
  14. package/dist/_contracts/run-config.js +17 -19
  15. package/dist/_contracts/run-unit.d.ts +4 -4
  16. package/dist/_contracts/run-unit.js +17 -6
  17. package/dist/_contracts/submission.d.ts +12 -4
  18. package/dist/_contracts/submission.js +9 -9
  19. package/dist/cli.mjs +164 -46
  20. package/dist/cli.mjs.sha256 +1 -1
  21. package/dist/client.d.ts +12 -2
  22. package/dist/client.js +8 -0
  23. package/dist/client.js.map +1 -1
  24. package/dist/index.d.ts +2 -2
  25. package/dist/index.js +1 -1
  26. package/dist/index.js.map +1 -1
  27. package/dist/proxy-endpoint.d.ts +1 -3
  28. package/dist/proxy-endpoint.js +2 -6
  29. package/dist/proxy-endpoint.js.map +1 -1
  30. package/dist/version.d.ts +1 -1
  31. package/dist/version.js +1 -1
  32. package/docs/cleanup.md +3 -1
  33. package/docs/credentials.md +3 -3
  34. package/docs/outputs.md +3 -1
  35. package/docs/provider-runtime-capabilities.md +1 -1
  36. package/docs/quickstart.md +17 -7
  37. package/docs/run-config.md +12 -7
  38. package/docs/skills.md +102 -117
  39. package/docs/testing.md +9 -4
  40. package/package.json +2 -2
@@ -20,6 +20,7 @@
20
20
  * detail response stays bounded). The archive zip carries the bytes.
21
21
  */
22
22
  import { parseMcpServerRef, parseSkillRef } from "./run-config.js";
23
+ import { RunModels, parseRunModel } from "./models.js";
23
24
  import { PLATFORM_PACKAGE_ECOSYSTEMS } from "./submission.js";
24
25
  // ---------------------------------------------------------------------------
25
26
  // Submission parser
@@ -29,10 +30,10 @@ import { PLATFORM_PACKAGE_ECOSYSTEMS } from "./submission.js";
29
30
  * submission. Never throws on minor unknown keys so we can
30
31
  * forward-compat with worker-side enrichment.
31
32
  *
32
- * Returns a typed shape even for malformed snapshots the worst case
33
- * is `{kind: "submission", submission: {model: "", ...}}` with empty
34
- * defaults — because the dashboard must still render *something* for a
35
- * buggy historical row rather than 500ing the whole detail page.
33
+ * Returns a typed shape even for malformed snapshots by falling back to the
34
+ * default public model and empty collection defaults, because the dashboard
35
+ * must still render *something* for a buggy historical row rather than 500ing
36
+ * the whole detail page.
36
37
  */
37
38
  export function parseRunUnitSubmission(input) {
38
39
  if (!input || typeof input !== "object" || Array.isArray(input)) {
@@ -52,7 +53,7 @@ function parseFlatProjection(value) {
52
53
  const allowedDirs = toOptionalStringArray(outputsRaw.allowedDirs);
53
54
  const deniedDirs = toOptionalStringArray(outputsRaw.deniedDirs);
54
55
  const submission = {
55
- model: typeof submissionRaw.model === "string" ? submissionRaw.model : "",
56
+ model: coerceRunUnitModel(submissionRaw.model),
56
57
  ...(typeof submissionRaw.system === "string" ? { system: submissionRaw.system } : {}),
57
58
  prompt: toStringArray(submissionRaw.prompt),
58
59
  skills: toSkillRefArray(submissionRaw.skills),
@@ -87,7 +88,7 @@ function fallbackFlat() {
87
88
  return {
88
89
  kind: "submission",
89
90
  submission: {
90
- model: "",
91
+ model: RunModels.CLAUDE_HAIKU_4_5,
91
92
  prompt: [],
92
93
  skills: [],
93
94
  agentsMd: [],
@@ -104,6 +105,16 @@ function fallbackFlat() {
104
105
  function isRecord(value) {
105
106
  return typeof value === "object" && value !== null && !Array.isArray(value);
106
107
  }
108
+ function coerceRunUnitModel(value) {
109
+ if (typeof value !== "string")
110
+ return RunModels.CLAUDE_HAIKU_4_5;
111
+ try {
112
+ return parseRunModel(value, "run unit submission.model");
113
+ }
114
+ catch {
115
+ return RunModels.CLAUDE_HAIKU_4_5;
116
+ }
117
+ }
107
118
  function isJsonRecord(value) {
108
119
  return isRecord(value);
109
120
  }
@@ -2,6 +2,8 @@ import { PROXY_ENDPOINT_DEFAULTS, type ProxyAuthShape, type ProxyMethod, type Pr
2
2
  export { PROXY_ENDPOINT_DEFAULTS };
3
3
  import type { AgentsMdRef, FileRef, McpServerRef, SkillRef } from "./run-config.js";
4
4
  import { type RuntimeSize } from "./runtime-sizes.js";
5
+ import { type PlatformPostHook, type PlatformPostHookInput } from "./post-hook.js";
6
+ import { type RunModel } from "./models.js";
5
7
  import { type RuntimeSecurityProfileName } from "./runtime-security-profile.js";
6
8
  import { type CredentialMode, type ManagedKeyPolicyV1 } from "./managed-key.js";
7
9
  export type JsonPrimitive = string | number | boolean | null;
@@ -188,8 +190,6 @@ export interface PlatformProxyEndpoint {
188
190
  readonly maxRequestBytes?: number;
189
191
  readonly maxResponseBytes?: number;
190
192
  readonly timeoutMs?: number;
191
- readonly perCallBudget?: number;
192
- readonly responseByteBudget?: number;
193
193
  }
194
194
  export declare const SECRETS_KEY = "secrets";
195
195
  export declare const PROXY_ENDPOINT_NAME_PATTERN: RegExp;
@@ -228,7 +228,7 @@ export declare function optionalPositiveInt(input: unknown, field: string): numb
228
228
  * into `run_skill_snapshots`), provider refs pass through unchanged.
229
229
  */
230
230
  export interface PlatformSubmission {
231
- readonly model: string;
231
+ readonly model: RunModel;
232
232
  readonly system?: string;
233
233
  readonly prompt: readonly string[];
234
234
  readonly skills: readonly SkillRef[];
@@ -335,6 +335,13 @@ export interface PlatformRunSubmissionRequest {
335
335
  * terminal wait window and self-kill deadline.
336
336
  */
337
337
  readonly timeoutMs?: number;
338
+ /**
339
+ * Optional post-agent-run verifier. Parsed from the public `postHook`
340
+ * duration/string shape into fixed runner budgets. The runner executes it
341
+ * after a successful agent process and sends failures back through the model
342
+ * for repair until this budget is exhausted.
343
+ */
344
+ readonly postHook?: PlatformPostHook;
338
345
  }
339
346
  /**
340
347
  * Wire shape posted by the SDK and CLI. `workspaceId` is **omitted by
@@ -349,7 +356,7 @@ export interface PlatformRunSubmissionRequest {
349
356
  * {@link DEFAULT_RUN_PROVIDER} (`anthropic`). The parser fills it in
350
357
  * before the value enters the run snapshot.
351
358
  */
352
- export type PlatformRunSubmissionInput = Omit<PlatformRunSubmissionRequest, "workspaceId" | "credentialMode" | "provider" | "runtime" | "timeoutMs"> & {
359
+ export type PlatformRunSubmissionInput = Omit<PlatformRunSubmissionRequest, "workspaceId" | "credentialMode" | "provider" | "runtime" | "timeoutMs" | "postHook"> & {
353
360
  readonly workspaceId?: string;
354
361
  readonly credentialMode?: CredentialMode;
355
362
  readonly provider?: RunProvider;
@@ -365,6 +372,7 @@ export type PlatformRunSubmissionInput = Omit<PlatformRunSubmissionRequest, "wor
365
372
  * {@link PlatformRunSubmissionRequest.timeoutMs}. Absent ⇒ 1h default.
366
373
  */
367
374
  readonly timeout?: string;
375
+ readonly postHook?: PlatformPostHookInput;
368
376
  };
369
377
  export interface ParseRunSubmissionOptions {
370
378
  readonly managedKeyPolicy?: ManagedKeyPolicyV1;
@@ -6,6 +6,8 @@ import { authShapeHeaderName, PROXY_ALLOWED_METHODS, PROXY_ENDPOINT_DEFAULTS, PR
6
6
  export { PROXY_ENDPOINT_DEFAULTS };
7
7
  import { parseAssetRefFields, parseMcpServerRef, parseSkillRef } from "./run-config.js";
8
8
  import { parseRunTimeout, parseRuntimeSize } from "./runtime-sizes.js";
9
+ import { parsePostHook } from "./post-hook.js";
10
+ import { assertRunModelMatchesProvider, parseRunModel } from "./models.js";
9
11
  import { parseRuntimeSecurityProfile } from "./runtime-security-profile.js";
10
12
  import { assertManagedKeyAdmissionAllowed, parseCredentialMode } from "./managed-key.js";
11
13
  /**
@@ -323,9 +325,7 @@ function parseProxyEndpoint(input, path) {
323
325
  "responseMode",
324
326
  "maxRequestBytes",
325
327
  "maxResponseBytes",
326
- "timeoutMs",
327
- "perCallBudget",
328
- "responseByteBudget"
328
+ "timeoutMs"
329
329
  ]);
330
330
  for (const key of Object.keys(value)) {
331
331
  if (!allowed.has(key)) {
@@ -348,8 +348,6 @@ function parseProxyEndpoint(input, path) {
348
348
  const maxRequestBytes = optionalPositiveInt(value.maxRequestBytes, `${path}.maxRequestBytes`);
349
349
  const maxResponseBytes = optionalPositiveInt(value.maxResponseBytes, `${path}.maxResponseBytes`);
350
350
  const timeoutMs = optionalPositiveInt(value.timeoutMs, `${path}.timeoutMs`);
351
- const perCallBudget = optionalPositiveInt(value.perCallBudget, `${path}.perCallBudget`);
352
- const responseByteBudget = optionalPositiveInt(value.responseByteBudget, `${path}.responseByteBudget`);
353
351
  return {
354
352
  name,
355
353
  baseUrl,
@@ -360,9 +358,7 @@ function parseProxyEndpoint(input, path) {
360
358
  ...(responseMode ? { responseMode } : {}),
361
359
  ...(maxRequestBytes !== undefined ? { maxRequestBytes } : {}),
362
360
  ...(maxResponseBytes !== undefined ? { maxResponseBytes } : {}),
363
- ...(timeoutMs !== undefined ? { timeoutMs } : {}),
364
- ...(perCallBudget !== undefined ? { perCallBudget } : {}),
365
- ...(responseByteBudget !== undefined ? { responseByteBudget } : {})
361
+ ...(timeoutMs !== undefined ? { timeoutMs } : {})
366
362
  };
367
363
  }
368
364
  function parseProxyBaseUrl(input, field) {
@@ -788,6 +784,7 @@ export function parseRunSubmissionRequest(input, options = {}) {
788
784
  "submission",
789
785
  "runtimeSize",
790
786
  "timeout",
787
+ "postHook",
791
788
  "proxyEndpoints",
792
789
  SECRETS_KEY
793
790
  ]);
@@ -821,11 +818,13 @@ export function parseRunSubmissionRequest(input, options = {}) {
821
818
  }
822
819
  const runtimeSize = parseRuntimeSize(value.runtimeSize);
823
820
  const timeoutMs = parseRunTimeout(value.timeout);
821
+ const postHook = parsePostHook(value.postHook, "submission.postHook");
824
822
  const proxyEndpoints = parseProxyEndpoints(value.proxyEndpoints);
825
823
  const secrets = parseInlineSecrets(value.secrets);
826
824
  enforceCredentialSecretPolicy(credentialMode, secrets);
827
825
  crossValidateProxyEndpointsAndAuth(proxyEndpoints, secrets.proxyEndpointAuth);
828
826
  const submission = parseSubmission(value.submission);
827
+ assertRunModelMatchesProvider(provider, submission.model);
829
828
  // mcpServers names must agree across the submission half and the
830
829
  // secrets half — every secrets.mcpServers[i].name MUST resolve to a
831
830
  // submission.mcpServers entry (no orphan secrets) AND the URL must
@@ -867,6 +866,7 @@ export function parseRunSubmissionRequest(input, options = {}) {
867
866
  submission,
868
867
  ...(runtimeSize ? { runtimeSize } : {}),
869
868
  ...(timeoutMs !== undefined ? { timeoutMs } : {}),
869
+ ...(postHook !== undefined ? { postHook } : {}),
870
870
  ...(proxyEndpoints ? { proxyEndpoints } : {}),
871
871
  secrets
872
872
  };
@@ -933,7 +933,7 @@ export function parseSubmission(input) {
933
933
  throw new Error(`submission.${key} is not an allowed field; permitted: ${[...allowed].join(", ")}`);
934
934
  }
935
935
  }
936
- const model = requireString(value.model, "submission.model");
936
+ const model = parseRunModel(value.model, "submission.model");
937
937
  const system = optionalString(value.system, "submission.system");
938
938
  const prompt = parsePrompt(value.prompt);
939
939
  const skills = parseSkills(value.skills);
package/dist/cli.mjs CHANGED
@@ -15,8 +15,6 @@ var PROXY_PROTOCOL_HEADER = "x-aex-proxy-protocol";
15
15
  var PROXY_RESP_STATUS_HEADER = "x-aex-proxy-status";
16
16
  var PROXY_RESP_MODE_HEADER = "x-aex-proxy-effective-mode";
17
17
  var PROXY_RESP_TRUNCATED_HEADER = "x-aex-proxy-truncated";
18
- var PROXY_RESP_REMAINING_CALLS_HEADER = "x-aex-proxy-remaining-calls";
19
- var PROXY_RESP_REMAINING_BYTES_HEADER = "x-aex-proxy-remaining-bytes";
20
18
  var PROXY_RESP_UPSTREAM_HEADERS_HEADER = "x-aex-proxy-upstream-headers";
21
19
  var PROXY_METHOD_HEADER = "x-aex-method";
22
20
  var PROXY_PATH_HEADER = "x-aex-path";
@@ -28,10 +26,10 @@ var PROXY_ENDPOINT_DEFAULTS = {
28
26
  allowHeaders: [],
29
27
  responseMode: "headers_only",
30
28
  maxRequestBytes: 64 * 1024,
31
- maxResponseBytes: 1024 * 1024,
32
- timeoutMs: 1e4,
33
- perCallBudget: 60,
34
- responseByteBudget: 1024 * 1024
29
+ // Unlimited (0). The request body is buffered to enforce its cap, so that
30
+ // stays finite; the response is streamed, so it does not need one.
31
+ maxResponseBytes: 0,
32
+ timeoutMs: 1e4
35
33
  };
36
34
 
37
35
  // ../contracts/dist/provider-support.js
@@ -121,6 +119,52 @@ var PROVIDER_PUBLIC_SUPPORT = {
121
119
  }
122
120
  };
123
121
 
122
+ // ../contracts/dist/models.js
123
+ var RUN_MODELS = [
124
+ "claude-haiku-4-5",
125
+ "claude-3-5-haiku-latest",
126
+ "claude-3-5-sonnet-latest",
127
+ "deepseek-chat",
128
+ "gpt-4.1",
129
+ "gpt-4o-mini",
130
+ "gemini-2.0-flash",
131
+ "gemini-2.5-flash",
132
+ "mistral-large-latest",
133
+ "mistral-small-latest"
134
+ ];
135
+ var RunModels = {
136
+ CLAUDE_HAIKU_4_5: "claude-haiku-4-5",
137
+ CLAUDE_3_5_HAIKU_LATEST: "claude-3-5-haiku-latest",
138
+ CLAUDE_3_5_SONNET_LATEST: "claude-3-5-sonnet-latest",
139
+ DEEPSEEK_CHAT: "deepseek-chat",
140
+ GPT_4_1: "gpt-4.1",
141
+ GPT_4O_MINI: "gpt-4o-mini",
142
+ GEMINI_2_0_FLASH: "gemini-2.0-flash",
143
+ GEMINI_2_5_FLASH: "gemini-2.5-flash",
144
+ MISTRAL_LARGE_LATEST: "mistral-large-latest",
145
+ MISTRAL_SMALL_LATEST: "mistral-small-latest"
146
+ };
147
+ var RUN_MODELS_BY_PROVIDER = {
148
+ anthropic: [
149
+ RunModels.CLAUDE_HAIKU_4_5,
150
+ RunModels.CLAUDE_3_5_HAIKU_LATEST,
151
+ RunModels.CLAUDE_3_5_SONNET_LATEST
152
+ ],
153
+ deepseek: [RunModels.DEEPSEEK_CHAT],
154
+ openai: [RunModels.GPT_4_1, RunModels.GPT_4O_MINI],
155
+ gemini: [RunModels.GEMINI_2_0_FLASH, RunModels.GEMINI_2_5_FLASH],
156
+ mistral: [RunModels.MISTRAL_LARGE_LATEST, RunModels.MISTRAL_SMALL_LATEST]
157
+ };
158
+ function isRunModel(input) {
159
+ return typeof input === "string" && RUN_MODELS.includes(input);
160
+ }
161
+ function parseRunModel(input, field = "submission.model") {
162
+ if (!isRunModel(input)) {
163
+ throw new Error(`${field} must be one of: ${RUN_MODELS.join(", ")}`);
164
+ }
165
+ return input;
166
+ }
167
+
124
168
  // ../contracts/dist/status.js
125
169
  var TERMINAL_RUN_STATUSES = [
126
170
  "succeeded",
@@ -133,15 +177,113 @@ var TERMINAL_RUN_STATUSES = [
133
177
  ];
134
178
  var terminalRunStatuses = new Set(TERMINAL_RUN_STATUSES);
135
179
 
180
+ // ../contracts/dist/runtime-sizes.js
181
+ var RUNTIME_SIZE_PRESETS = {
182
+ "shared-1x-256mb": { cpus: 1, memoryMb: 256 },
183
+ "shared-1x-512mb": { cpus: 1, memoryMb: 512 },
184
+ "shared-1x-1gb": { cpus: 1, memoryMb: 1024 },
185
+ "shared-1x-2gb": { cpus: 1, memoryMb: 2048 },
186
+ "shared-2x-512mb": { cpus: 2, memoryMb: 512 },
187
+ "shared-2x-1gb": { cpus: 2, memoryMb: 1024 },
188
+ "shared-2x-2gb": { cpus: 2, memoryMb: 2048 },
189
+ "shared-2x-4gb": { cpus: 2, memoryMb: 4096 },
190
+ "shared-4x-1gb": { cpus: 4, memoryMb: 1024 },
191
+ "shared-4x-2gb": { cpus: 4, memoryMb: 2048 },
192
+ "shared-4x-4gb": { cpus: 4, memoryMb: 4096 },
193
+ "shared-4x-8gb": { cpus: 4, memoryMb: 8192 },
194
+ "shared-8x-2gb": { cpus: 8, memoryMb: 2048 },
195
+ "shared-8x-4gb": { cpus: 8, memoryMb: 4096 },
196
+ "shared-8x-8gb": { cpus: 8, memoryMb: 8192 },
197
+ "shared-8x-16gb": { cpus: 8, memoryMb: 16384 }
198
+ };
199
+ var RUNTIME_SIZES = Object.keys(RUNTIME_SIZE_PRESETS);
200
+ var DEFAULT_RUN_TIMEOUT_MS = 60 * 60 * 1e3;
201
+ var MAX_RUN_TIMEOUT_MS = 6 * 60 * 60 * 1e3;
202
+ var MIN_RUN_TIMEOUT_MS = 60 * 1e3;
203
+ var DURATION_PATTERN = /^(\d+(?:\.\d+)?)(ms|s|m|h)?$/;
204
+ function parseDurationToMs(input) {
205
+ const match = DURATION_PATTERN.exec(input.trim());
206
+ if (!match) {
207
+ throw new Error(`invalid duration ${JSON.stringify(input)} (expected e.g. "1h", "90m", "30s", "500ms", or a bare ms integer)`);
208
+ }
209
+ const value = Number(match[1]);
210
+ if (!Number.isFinite(value) || value < 0) {
211
+ throw new Error(`invalid duration ${JSON.stringify(input)} (must be a non-negative number)`);
212
+ }
213
+ const unit = match[2] ?? "ms";
214
+ const factor = unit === "h" ? 36e5 : unit === "m" ? 6e4 : unit === "s" ? 1e3 : 1;
215
+ return Math.round(value * factor);
216
+ }
217
+ var RUN_PROCESS_KILL_GRACE_MS = 60 * 1e3;
218
+ var RUN_TERMINAL_GRACE_MS = 90 * 1e3;
219
+
220
+ // ../contracts/dist/post-hook.js
221
+ var DEFAULT_POST_HOOK_TIMEOUT_MS = 5 * 60 * 1e3;
222
+ var DEFAULT_POST_HOOK_MAX_TURNS = 10;
223
+ function parsePostHook(input, path = "postHook") {
224
+ if (input === void 0 || input === null) {
225
+ return void 0;
226
+ }
227
+ const value = requirePostHookRecord(input, path);
228
+ const allowed = /* @__PURE__ */ new Set(["command", "timeout", "maxTurns", "maxChars"]);
229
+ for (const key of Object.keys(value)) {
230
+ if (!allowed.has(key)) {
231
+ throw new Error(`${path}.${key} is not an allowed field; permitted: command, timeout, maxTurns, maxChars`);
232
+ }
233
+ }
234
+ if (typeof value.command !== "string") {
235
+ throw new Error(`${path}.command must be a string`);
236
+ }
237
+ if (value.command.trim().length === 0) {
238
+ return void 0;
239
+ }
240
+ const timeoutMs = parsePostHookTimeout(value.timeout, `${path}.timeout`);
241
+ const maxTurns = parseNonNegativeInteger(value.maxTurns, `${path}.maxTurns`, DEFAULT_POST_HOOK_MAX_TURNS);
242
+ const maxChars = value.maxChars === null ? null : parseNonNegativeInteger(value.maxChars, `${path}.maxChars`, null);
243
+ return {
244
+ command: value.command,
245
+ timeoutMs,
246
+ maxTurns,
247
+ maxChars
248
+ };
249
+ }
250
+ function parsePostHookTimeout(input, path) {
251
+ if (input === void 0) {
252
+ return DEFAULT_POST_HOOK_TIMEOUT_MS;
253
+ }
254
+ if (typeof input !== "string") {
255
+ throw new Error(`${path} must be a duration string (e.g. "5m", "30s"); got ${JSON.stringify(input)}`);
256
+ }
257
+ const ms = parseDurationToMs(input);
258
+ if (ms <= 0) {
259
+ throw new Error(`${path} must be greater than 0ms; got ${ms}ms`);
260
+ }
261
+ return ms;
262
+ }
263
+ function parseNonNegativeInteger(input, path, defaultValue) {
264
+ if (input === void 0) {
265
+ return defaultValue;
266
+ }
267
+ if (typeof input !== "number" || !Number.isSafeInteger(input) || input < 0) {
268
+ throw new Error(`${path} must be a non-negative integer`);
269
+ }
270
+ return input;
271
+ }
272
+ function requirePostHookRecord(input, path) {
273
+ if (input === null || typeof input !== "object" || Array.isArray(input)) {
274
+ throw new Error(`${path} must be an object`);
275
+ }
276
+ return input;
277
+ }
278
+
136
279
  // ../contracts/dist/run-config.js
137
280
  var SKILL_BUNDLE_LIMITS = {
138
281
  /** Compressed (.zip) ceiling. */
139
282
  maxCompressedBytes: 10 * 1024 * 1024,
140
283
  /**
141
- * Hard ceiling for the direct-to-storage (presigned PUT) upload path, where
142
- * bytes never transit the hosted API so its memory/request-payload limits no
143
- * longer cap the bundle. Kept well under the object store's 5 GiB single-PUT
144
- * limit; objects above this would need S3 multipart, which is out of scope.
284
+ * Hard ceiling for the direct-to-storage upload path. Bytes never transit the
285
+ * hosted API, so its memory/request-payload limits do not cap accepted
286
+ * bundles; objects above this product cap are rejected before upload.
145
287
  */
146
288
  maxBytes: 2 * 1024 * 1024 * 1024,
147
289
  /** Sum of uncompressed file sizes. */
@@ -448,6 +590,7 @@ function parseRunRequestConfig(input) {
448
590
  "environment",
449
591
  "runtimeSize",
450
592
  "timeout",
593
+ "postHook",
451
594
  "proxyEndpoints",
452
595
  "metadata"
453
596
  ]);
@@ -456,10 +599,7 @@ function parseRunRequestConfig(input) {
456
599
  throw new Error(`run request config contains unexpected field: ${key}`);
457
600
  }
458
601
  }
459
- const model = record.model;
460
- if (typeof model !== "string" || model.length === 0) {
461
- throw new Error("run request config model must be a non-empty string");
462
- }
602
+ const model = parseRunModel(record.model, "run request config model");
463
603
  const system = record.system;
464
604
  if (system !== void 0 && typeof system !== "string") {
465
605
  throw new Error("run request config system, when provided, must be a string");
@@ -467,6 +607,7 @@ function parseRunRequestConfig(input) {
467
607
  const prompt = parseRunRequestConfigPrompt(record.prompt);
468
608
  const skills = parseRunRequestConfigSkills(record.skills);
469
609
  const mcpServers = parseRunRequestConfigMcpServers(record.mcpServers);
610
+ const postHook = parsePostHook(record.postHook, "run request config postHook");
470
611
  return {
471
612
  model,
472
613
  ...system !== void 0 ? { system } : {},
@@ -480,6 +621,7 @@ function parseRunRequestConfig(input) {
480
621
  ...record.environment !== void 0 ? { environment: record.environment } : {},
481
622
  ...record.runtimeSize !== void 0 ? { runtimeSize: record.runtimeSize } : {},
482
623
  ...record.timeout !== void 0 ? { timeout: record.timeout } : {},
624
+ ...postHook !== void 0 ? { postHook: record.postHook } : {},
483
625
  ...record.proxyEndpoints !== void 0 ? { proxyEndpoints: record.proxyEndpoints } : {},
484
626
  ...record.metadata !== void 0 ? { metadata: record.metadata } : {}
485
627
  };
@@ -534,32 +676,6 @@ function parseRunRequestConfigMcpServers(value) {
534
676
  });
535
677
  }
536
678
 
537
- // ../contracts/dist/runtime-sizes.js
538
- var RUNTIME_SIZE_PRESETS = {
539
- "shared-1x-256mb": { cpus: 1, memoryMb: 256 },
540
- "shared-1x-512mb": { cpus: 1, memoryMb: 512 },
541
- "shared-1x-1gb": { cpus: 1, memoryMb: 1024 },
542
- "shared-1x-2gb": { cpus: 1, memoryMb: 2048 },
543
- "shared-2x-512mb": { cpus: 2, memoryMb: 512 },
544
- "shared-2x-1gb": { cpus: 2, memoryMb: 1024 },
545
- "shared-2x-2gb": { cpus: 2, memoryMb: 2048 },
546
- "shared-2x-4gb": { cpus: 2, memoryMb: 4096 },
547
- "shared-4x-1gb": { cpus: 4, memoryMb: 1024 },
548
- "shared-4x-2gb": { cpus: 4, memoryMb: 2048 },
549
- "shared-4x-4gb": { cpus: 4, memoryMb: 4096 },
550
- "shared-4x-8gb": { cpus: 4, memoryMb: 8192 },
551
- "shared-8x-2gb": { cpus: 8, memoryMb: 2048 },
552
- "shared-8x-4gb": { cpus: 8, memoryMb: 4096 },
553
- "shared-8x-8gb": { cpus: 8, memoryMb: 8192 },
554
- "shared-8x-16gb": { cpus: 8, memoryMb: 16384 }
555
- };
556
- var RUNTIME_SIZES = Object.keys(RUNTIME_SIZE_PRESETS);
557
- var DEFAULT_RUN_TIMEOUT_MS = 60 * 60 * 1e3;
558
- var MAX_RUN_TIMEOUT_MS = 6 * 60 * 60 * 1e3;
559
- var MIN_RUN_TIMEOUT_MS = 60 * 1e3;
560
- var RUN_PROCESS_KILL_GRACE_MS = 60 * 1e3;
561
- var RUN_TERMINAL_GRACE_MS = 90 * 1e3;
562
-
563
679
  // ../contracts/dist/runtime-security-profile.js
564
680
  var RUNTIME_SECURITY_PROFILE_CONFIG = Object.freeze({
565
681
  strict: Object.freeze({
@@ -2642,7 +2758,7 @@ async function printProxyHelp(io2) {
2642
2758
  if (manifest && manifest.endpoints.length > 0) {
2643
2759
  io2.stdout("Declared endpoints:\n");
2644
2760
  for (const ep of manifest.endpoints) {
2645
- io2.stdout(` \u2022 ${ep.name}: ${ep.allowMethods.join(",")} ${ep.allowPathPrefixes.join(",")} (mode=${ep.responseMode}, budget=${ep.perCallBudget}/run)
2761
+ io2.stdout(` \u2022 ${ep.name}: ${ep.allowMethods.join(",")} ${ep.allowPathPrefixes.join(",")} (mode=${ep.responseMode})
2646
2762
  `);
2647
2763
  }
2648
2764
  }
@@ -2801,8 +2917,6 @@ function emitError(io2, body) {
2801
2917
  async function readStreamedEnvelope(response, endpointName) {
2802
2918
  const effectiveResponseMode = response.headers.get(PROXY_RESP_MODE_HEADER) ?? "headers_only";
2803
2919
  const upstreamStatus = Number.parseInt(response.headers.get(PROXY_RESP_STATUS_HEADER) ?? "0", 10);
2804
- const remainingCalls = Number.parseInt(response.headers.get(PROXY_RESP_REMAINING_CALLS_HEADER) ?? "0", 10);
2805
- const remainingResponseBytes = Number.parseInt(response.headers.get(PROXY_RESP_REMAINING_BYTES_HEADER) ?? "0", 10);
2806
2920
  let upstreamHeaders = {};
2807
2921
  const rawHeaders = response.headers.get(PROXY_RESP_UPSTREAM_HEADERS_HEADER);
2808
2922
  if (rawHeaders) {
@@ -2825,8 +2939,6 @@ async function readStreamedEnvelope(response, endpointName) {
2825
2939
  // isn't carried back); the effective mode is authoritative for the
2826
2940
  // agent and matches what v1 surfaced for an un-clamped call.
2827
2941
  modeClamped: false,
2828
- remainingCalls,
2829
- remainingResponseBytes,
2830
2942
  ...effectiveResponseMode === "full" && bytes.byteLength > 0 ? { upstreamBodyBase64: Buffer.from(bytes).toString("base64") } : {},
2831
2943
  ...truncatedRaw === "true" ? { truncated: true } : {}
2832
2944
  };
@@ -3058,6 +3170,11 @@ async function runRunCmd(io2, argv) {
3058
3170
  io2.stderr("--model is required when --config is not provided\n");
3059
3171
  return USAGE_ERR;
3060
3172
  }
3173
+ if (!RUN_MODELS.includes(modelFlag.value)) {
3174
+ io2.stderr(`--model must be one of: ${RUN_MODELS.join(", ")} (got: ${modelFlag.value})
3175
+ `);
3176
+ return USAGE_ERR;
3177
+ }
3061
3178
  if (promptFlags.values.length === 0) {
3062
3179
  io2.stderr("--prompt is required (repeatable)\n");
3063
3180
  return USAGE_ERR;
@@ -3186,6 +3303,7 @@ async function runRunCmd(io2, argv) {
3186
3303
  secrets,
3187
3304
  ...runtimeSizeFlag.value ? { runtimeSize: runtimeSizeFlag.value } : runConfig.runtimeSize ? { runtimeSize: runConfig.runtimeSize } : {},
3188
3305
  ...runTimeoutFlag.value ? { timeout: runTimeoutFlag.value } : runConfig.timeout ? { timeout: runConfig.timeout } : {},
3306
+ ...runConfig.postHook ? { postHook: runConfig.postHook } : {},
3189
3307
  ...proxyEndpoints.length > 0 ? { proxyEndpoints } : {}
3190
3308
  };
3191
3309
  const http = makeHttpClient(io2, common.flags);
@@ -4080,7 +4198,7 @@ Protocol version: ${manifest.protocolVersion}
4080
4198
  io2.stdout(" aex wait <run-id> [--timeout 8m] [--interval 2s] --api-token T\n");
4081
4199
  io2.stdout(" aex events <run-id> [--follow] [--timeout 8m] --api-token T\n");
4082
4200
  io2.stdout(" aex outputs <run-id> --api-token T\n");
4083
- io2.stdout(" aex download <run-id> [--out path] --api-token T\n");
4201
+ io2.stdout(" aex download <run-id> [--only outputs|events|metadata] [--out path] --api-token T\n");
4084
4202
  io2.stdout(" aex cancel <run-id> --api-token T\n");
4085
4203
  io2.stdout(" aex delete <run-id> --api-token T\n");
4086
4204
  io2.stdout(" aex delete-asset <assetId|hash> --api-token T\n");
@@ -1 +1 @@
1
- 9219ad7c8ff381c3e9916e5f312e110d9546cedb035b5a2f65bbbd07f5e27d4f cli.mjs
1
+ 0867878a9456f95c87fe93ca1aac5879b7c44ab5f3d1c7f110c8cab2259540a3 cli.mjs
package/dist/client.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { HttpClient, type AexEvent, type AgentsMdRecord, type CredentialMode, type DebugSink, type FetchLike, type FileRecord, type Output, type OutputMode, type PlatformEnvironmentInput, type PlatformSubmission, type PlatformInlineSecrets, type PlatformProxyEndpoint, type PlatformProxyEndpointAuth, type Run, type RunEvent, type RunProvider, type RunUnit, type RuntimeSize, type RuntimeKind, type SignedOutputLink, type Skill as SkillRecord, type WhoAmI } from "./_contracts/index.js";
1
+ import { HttpClient, type AexEvent, type AgentsMdRecord, type CredentialMode, type DebugSink, type FetchLike, type FileRecord, type Output, type OutputMode, type PlatformEnvironmentInput, type PlatformSubmission, type PlatformInlineSecrets, type PlatformProxyEndpoint, type PlatformProxyEndpointAuth, type PlatformPostHookInput, type Run, type RunModel, type RunEvent, type RunProvider, type RunUnit, type RuntimeSize, type RuntimeKind, type SignedOutputLink, type Skill as SkillRecord, type WhoAmI } from "./_contracts/index.js";
2
2
  import { AgentsMd } from "./agents-md.js";
3
3
  import { type UploadedAsset } from "./asset-upload.js";
4
4
  import { File } from "./file.js";
@@ -66,7 +66,11 @@ export interface SubmitRunOptions {
66
66
  * is no longer accepted.
67
67
  */
68
68
  readonly runtime?: RuntimeKind;
69
- readonly model: string;
69
+ /**
70
+ * Closed public model id. Prefer {@link RunModels}, e.g.
71
+ * `RunModels.CLAUDE_HAIKU_4_5`.
72
+ */
73
+ readonly model: RunModel;
70
74
  readonly system?: string;
71
75
  readonly prompt: string | readonly string[];
72
76
  readonly skills?: readonly Skill[];
@@ -86,6 +90,12 @@ export interface SubmitRunOptions {
86
90
  * [1m, 6h]; omit for the 1h default. Applies to both runtimes.
87
91
  */
88
92
  readonly timeout?: string;
93
+ /**
94
+ * Command to run after the agent process exits successfully. A non-zero exit
95
+ * or timeout is sent back to the model as a repair prompt until `maxTurns`
96
+ * is exhausted. Empty commands are treated as omitted.
97
+ */
98
+ readonly postHook?: PlatformPostHookInput;
89
99
  readonly proxyEndpoints?: readonly ProxyEndpoint[];
90
100
  /**
91
101
  * Output capture policy for the run's output files.
package/dist/client.js CHANGED
@@ -320,6 +320,7 @@ export class AgentExecutor {
320
320
  ...(mergedMcpSecrets.length > 0 ? { mcpServers: mergedMcpSecrets } : {}),
321
321
  ...(mergedProxyAuth.length > 0 ? { proxyEndpointAuth: mergedProxyAuth } : {})
322
322
  };
323
+ const postHook = postHookForWire(options.postHook);
323
324
  const request = {
324
325
  idempotencyKey: options.idempotencyKey ?? generateIdempotencyKey(),
325
326
  // Always include `provider` on the wire so dashboard / proxy
@@ -335,6 +336,7 @@ export class AgentExecutor {
335
336
  submission,
336
337
  ...(options.runtimeSize ? { runtimeSize: options.runtimeSize } : {}),
337
338
  ...(options.timeout ? { timeout: options.timeout } : {}),
339
+ ...(postHook ? { postHook } : {}),
338
340
  secrets,
339
341
  ...(proxyEndpointDeclarations.length > 0
340
342
  ? { proxyEndpoints: proxyEndpointDeclarations }
@@ -633,6 +635,12 @@ function normalisePrompt(input) {
633
635
  }
634
636
  return [...input];
635
637
  }
638
+ function postHookForWire(input) {
639
+ if (input === undefined || typeof input.command !== "string" || input.command.trim().length === 0) {
640
+ return undefined;
641
+ }
642
+ return input;
643
+ }
636
644
  /** Walk Skill[], eagerly upload drafts as assets, and return plain asset refs. */
637
645
  async function prepareSkills(skills, uploader) {
638
646
  const refs = [];