@aexhq/sdk 0.16.0 → 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.
- package/README.md +11 -8
- package/dist/_contracts/index.d.ts +2 -0
- package/dist/_contracts/index.js +2 -0
- package/dist/_contracts/internal.d.ts +2 -0
- package/dist/_contracts/internal.js +2 -0
- package/dist/_contracts/managed-key.d.ts +3 -2
- package/dist/_contracts/models.d.ts +33 -0
- package/dist/_contracts/models.js +59 -0
- package/dist/_contracts/post-hook.d.ts +28 -0
- package/dist/_contracts/post-hook.js +68 -0
- package/dist/_contracts/run-config.d.ts +15 -17
- package/dist/_contracts/run-config.js +17 -19
- package/dist/_contracts/run-unit.d.ts +4 -4
- package/dist/_contracts/run-unit.js +17 -6
- package/dist/_contracts/submission.d.ts +12 -2
- package/dist/_contracts/submission.js +7 -1
- package/dist/cli.mjs +159 -35
- package/dist/cli.mjs.sha256 +1 -1
- package/dist/client.d.ts +12 -2
- package/dist/client.js +8 -0
- package/dist/client.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/docs/cleanup.md +3 -1
- package/docs/credentials.md +3 -3
- package/docs/outputs.md +3 -1
- package/docs/provider-runtime-capabilities.md +1 -1
- package/docs/quickstart.md +17 -7
- package/docs/run-config.md +12 -7
- package/docs/skills.md +102 -117
- package/docs/testing.md +9 -4
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -9,7 +9,8 @@ aex is a TypeScript-first SDK + CLI for running autonomous agent sessions across
|
|
|
9
9
|
```ts
|
|
10
10
|
import {
|
|
11
11
|
AgentExecutor, // the only client class — submits durable runs to aex
|
|
12
|
-
|
|
12
|
+
RunModels, // closed public model id constants
|
|
13
|
+
Skill, // local, URL, and catalog skill bundles normalized to assets
|
|
13
14
|
McpServer, // MCP server declarations (headers split into secrets server-side)
|
|
14
15
|
ProxyEndpoint, // per-run managed HTTP proxy endpoint
|
|
15
16
|
AgentsMd, // AGENTS.md / CLAUDE.md uploads
|
|
@@ -55,15 +56,15 @@ The aex URL defaults to `https://api.aex.dev`. Set `--aex-url` on the CLI or `ba
|
|
|
55
56
|
## Quickstart (SDK)
|
|
56
57
|
|
|
57
58
|
```ts
|
|
58
|
-
import { AgentExecutor } from "@aexhq/sdk";
|
|
59
|
+
import { AgentExecutor, RunModels } from "@aexhq/sdk";
|
|
59
60
|
|
|
60
61
|
const aex = new AgentExecutor({
|
|
61
|
-
apiToken: process.env.AEX_API_TOKEN
|
|
62
|
+
apiToken: process.env.AEX_API_TOKEN!,
|
|
62
63
|
// baseUrl defaults to https://api.aex.dev - set it for local or staging planes.
|
|
63
64
|
});
|
|
64
65
|
|
|
65
66
|
const runId = await aex.submitRun({
|
|
66
|
-
model:
|
|
67
|
+
model: RunModels.CLAUDE_HAIKU_4_5,
|
|
67
68
|
system: "You are a concise automation agent.",
|
|
68
69
|
prompt: "Write a short answer about agent-first SDK design.",
|
|
69
70
|
secrets: { apiKey: process.env.ANTHROPIC_API_KEY! }
|
|
@@ -87,9 +88,9 @@ Reusable, credential-free configs can be ordinary functions:
|
|
|
87
88
|
```ts
|
|
88
89
|
function summarise(topic: string) {
|
|
89
90
|
return {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
91
|
+
model: RunModels.CLAUDE_HAIKU_4_5,
|
|
92
|
+
system: "You are a concise automation agent.",
|
|
93
|
+
prompt: `Write a short answer about ${topic}.`
|
|
93
94
|
};
|
|
94
95
|
}
|
|
95
96
|
|
|
@@ -127,7 +128,9 @@ aex run \
|
|
|
127
128
|
--follow
|
|
128
129
|
```
|
|
129
130
|
|
|
130
|
-
`--config` accepts a plain run-config JSON file for a single run request: `{ model, system?, prompt, skills?, mcpServers?, environment?, proxyEndpoints?, metadata? }`. There is no saved-definition product or interpolation DSL — build the JSON at the call site.
|
|
131
|
+
`--config` accepts a plain run-config JSON file for a single run request: `{ model, system?, prompt, skills?, mcpServers?, environment?, runtimeSize?, timeout?, postHook?, proxyEndpoints?, metadata? }`. There is no saved-definition product or interpolation DSL — build the JSON at the call site. SDK code should use `RunModels`; config JSON is validated against the same `RUN_MODELS` allowlist.
|
|
132
|
+
|
|
133
|
+
Runtime controls: omit `builtins` to use the default `["developer"]` toolkit, pass `builtins: []` to disable builtins for a pure-MCP run, use `outputMode: "stream"` for per-token assistant text, prefer `RuntimeSizes` for `runtimeSize`, and use `postHook` to run a verifier command after the agent exits successfully.
|
|
131
134
|
|
|
132
135
|
## Test commands
|
|
133
136
|
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
export * from "./proxy-protocol.js";
|
|
2
2
|
export * from "./provider-support.js";
|
|
3
|
+
export * from "./models.js";
|
|
3
4
|
export * from "./status.js";
|
|
4
5
|
export * from "./submission.js";
|
|
5
6
|
export * from "./runtime-sizes.js";
|
|
7
|
+
export * from "./post-hook.js";
|
|
6
8
|
export * from "./runner-event.js";
|
|
7
9
|
export * from "./event-envelope.js";
|
|
8
10
|
export * from "./connection-ticket.js";
|
package/dist/_contracts/index.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
export * from "./proxy-protocol.js";
|
|
2
2
|
export * from "./provider-support.js";
|
|
3
|
+
export * from "./models.js";
|
|
3
4
|
export * from "./status.js";
|
|
4
5
|
export * from "./submission.js";
|
|
5
6
|
export * from "./runtime-sizes.js";
|
|
7
|
+
export * from "./post-hook.js";
|
|
6
8
|
export * from "./runner-event.js";
|
|
7
9
|
export * from "./event-envelope.js";
|
|
8
10
|
export * from "./connection-ticket.js";
|
|
@@ -4,5 +4,7 @@
|
|
|
4
4
|
// of validator code. NOT part of the public `@aexhq/contracts` surface — do
|
|
5
5
|
// NOT add this to the package `index`; consumers reach it via the explicit
|
|
6
6
|
// `@aexhq/contracts/internal` subpath.
|
|
7
|
+
export * from "./models.js";
|
|
8
|
+
export * from "./post-hook.js";
|
|
7
9
|
export * from "./submission.js";
|
|
8
10
|
//# sourceMappingURL=internal.js.map
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { RunProvider, RuntimeKind } from "./submission.js";
|
|
2
|
+
import type { RunModel } from "./models.js";
|
|
2
3
|
export declare const CREDENTIAL_MODES: readonly ["byok", "managed"];
|
|
3
4
|
export type CredentialMode = (typeof CREDENTIAL_MODES)[number];
|
|
4
5
|
export declare const DEFAULT_CREDENTIAL_MODE: CredentialMode;
|
|
@@ -31,7 +32,7 @@ export interface ManagedKeyPolicyV1 {
|
|
|
31
32
|
readonly billingRequired: true;
|
|
32
33
|
readonly providers: readonly RunProvider[];
|
|
33
34
|
readonly runtimes: readonly RuntimeKind[];
|
|
34
|
-
readonly models?: readonly
|
|
35
|
+
readonly models?: readonly RunModel[];
|
|
35
36
|
readonly features: ManagedKeyFeaturePolicyV1;
|
|
36
37
|
}
|
|
37
38
|
/**
|
|
@@ -75,7 +76,7 @@ export interface ManagedCredentialResolutionInput {
|
|
|
75
76
|
readonly runId: string;
|
|
76
77
|
readonly provider: RunProvider;
|
|
77
78
|
readonly runtime: RuntimeKind;
|
|
78
|
-
readonly model:
|
|
79
|
+
readonly model: RunModel;
|
|
79
80
|
readonly policy: ManagedKeyPolicyV1;
|
|
80
81
|
}
|
|
81
82
|
export interface ManagedCredentialLease {
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { RunProvider } from "./submission.js";
|
|
2
|
+
/**
|
|
3
|
+
* Closed set of model ids accepted by the public run-submission schema.
|
|
4
|
+
*
|
|
5
|
+
* The provider-proxy still sends the model id through to the selected upstream
|
|
6
|
+
* provider, but callers cannot submit arbitrary strings. Additions belong here
|
|
7
|
+
* first so SDK types, CLI validation, docs examples, and platform parsing move
|
|
8
|
+
* together.
|
|
9
|
+
*/
|
|
10
|
+
export declare const RUN_MODELS: readonly ["claude-haiku-4-5", "claude-3-5-haiku-latest", "claude-3-5-sonnet-latest", "deepseek-chat", "gpt-4.1", "gpt-4o-mini", "gemini-2.0-flash", "gemini-2.5-flash", "mistral-large-latest", "mistral-small-latest"];
|
|
11
|
+
export type RunModel = (typeof RUN_MODELS)[number];
|
|
12
|
+
export declare const RunModels: {
|
|
13
|
+
readonly CLAUDE_HAIKU_4_5: "claude-haiku-4-5";
|
|
14
|
+
readonly CLAUDE_3_5_HAIKU_LATEST: "claude-3-5-haiku-latest";
|
|
15
|
+
readonly CLAUDE_3_5_SONNET_LATEST: "claude-3-5-sonnet-latest";
|
|
16
|
+
readonly DEEPSEEK_CHAT: "deepseek-chat";
|
|
17
|
+
readonly GPT_4_1: "gpt-4.1";
|
|
18
|
+
readonly GPT_4O_MINI: "gpt-4o-mini";
|
|
19
|
+
readonly GEMINI_2_0_FLASH: "gemini-2.0-flash";
|
|
20
|
+
readonly GEMINI_2_5_FLASH: "gemini-2.5-flash";
|
|
21
|
+
readonly MISTRAL_LARGE_LATEST: "mistral-large-latest";
|
|
22
|
+
readonly MISTRAL_SMALL_LATEST: "mistral-small-latest";
|
|
23
|
+
};
|
|
24
|
+
export declare const RUN_MODELS_BY_PROVIDER: {
|
|
25
|
+
readonly anthropic: readonly ["claude-haiku-4-5", "claude-3-5-haiku-latest", "claude-3-5-sonnet-latest"];
|
|
26
|
+
readonly deepseek: readonly ["deepseek-chat"];
|
|
27
|
+
readonly openai: readonly ["gpt-4.1", "gpt-4o-mini"];
|
|
28
|
+
readonly gemini: readonly ["gemini-2.0-flash", "gemini-2.5-flash"];
|
|
29
|
+
readonly mistral: readonly ["mistral-large-latest", "mistral-small-latest"];
|
|
30
|
+
};
|
|
31
|
+
export declare function isRunModel(input: unknown): input is RunModel;
|
|
32
|
+
export declare function parseRunModel(input: unknown, field?: string): RunModel;
|
|
33
|
+
export declare function assertRunModelMatchesProvider(provider: RunProvider, model: RunModel, field?: string): void;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Closed set of model ids accepted by the public run-submission schema.
|
|
3
|
+
*
|
|
4
|
+
* The provider-proxy still sends the model id through to the selected upstream
|
|
5
|
+
* provider, but callers cannot submit arbitrary strings. Additions belong here
|
|
6
|
+
* first so SDK types, CLI validation, docs examples, and platform parsing move
|
|
7
|
+
* together.
|
|
8
|
+
*/
|
|
9
|
+
export const RUN_MODELS = [
|
|
10
|
+
"claude-haiku-4-5",
|
|
11
|
+
"claude-3-5-haiku-latest",
|
|
12
|
+
"claude-3-5-sonnet-latest",
|
|
13
|
+
"deepseek-chat",
|
|
14
|
+
"gpt-4.1",
|
|
15
|
+
"gpt-4o-mini",
|
|
16
|
+
"gemini-2.0-flash",
|
|
17
|
+
"gemini-2.5-flash",
|
|
18
|
+
"mistral-large-latest",
|
|
19
|
+
"mistral-small-latest"
|
|
20
|
+
];
|
|
21
|
+
export const RunModels = {
|
|
22
|
+
CLAUDE_HAIKU_4_5: "claude-haiku-4-5",
|
|
23
|
+
CLAUDE_3_5_HAIKU_LATEST: "claude-3-5-haiku-latest",
|
|
24
|
+
CLAUDE_3_5_SONNET_LATEST: "claude-3-5-sonnet-latest",
|
|
25
|
+
DEEPSEEK_CHAT: "deepseek-chat",
|
|
26
|
+
GPT_4_1: "gpt-4.1",
|
|
27
|
+
GPT_4O_MINI: "gpt-4o-mini",
|
|
28
|
+
GEMINI_2_0_FLASH: "gemini-2.0-flash",
|
|
29
|
+
GEMINI_2_5_FLASH: "gemini-2.5-flash",
|
|
30
|
+
MISTRAL_LARGE_LATEST: "mistral-large-latest",
|
|
31
|
+
MISTRAL_SMALL_LATEST: "mistral-small-latest"
|
|
32
|
+
};
|
|
33
|
+
export const RUN_MODELS_BY_PROVIDER = {
|
|
34
|
+
anthropic: [
|
|
35
|
+
RunModels.CLAUDE_HAIKU_4_5,
|
|
36
|
+
RunModels.CLAUDE_3_5_HAIKU_LATEST,
|
|
37
|
+
RunModels.CLAUDE_3_5_SONNET_LATEST
|
|
38
|
+
],
|
|
39
|
+
deepseek: [RunModels.DEEPSEEK_CHAT],
|
|
40
|
+
openai: [RunModels.GPT_4_1, RunModels.GPT_4O_MINI],
|
|
41
|
+
gemini: [RunModels.GEMINI_2_0_FLASH, RunModels.GEMINI_2_5_FLASH],
|
|
42
|
+
mistral: [RunModels.MISTRAL_LARGE_LATEST, RunModels.MISTRAL_SMALL_LATEST]
|
|
43
|
+
};
|
|
44
|
+
export function isRunModel(input) {
|
|
45
|
+
return typeof input === "string" && RUN_MODELS.includes(input);
|
|
46
|
+
}
|
|
47
|
+
export function parseRunModel(input, field = "submission.model") {
|
|
48
|
+
if (!isRunModel(input)) {
|
|
49
|
+
throw new Error(`${field} must be one of: ${RUN_MODELS.join(", ")}`);
|
|
50
|
+
}
|
|
51
|
+
return input;
|
|
52
|
+
}
|
|
53
|
+
export function assertRunModelMatchesProvider(provider, model, field = "submission.model") {
|
|
54
|
+
if (!RUN_MODELS_BY_PROVIDER[provider].includes(model)) {
|
|
55
|
+
throw new Error(`${field} ${JSON.stringify(model)} is not supported for provider ${provider}; ` +
|
|
56
|
+
`expected one of: ${RUN_MODELS_BY_PROVIDER[provider].join(", ")}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=models.js.map
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/** Default post-agent-run hook timeout (5 minutes). */
|
|
2
|
+
export declare const DEFAULT_POST_HOOK_TIMEOUT_MS: number;
|
|
3
|
+
/** Default number of repair turns after a failing hook. */
|
|
4
|
+
export declare const DEFAULT_POST_HOOK_MAX_TURNS = 10;
|
|
5
|
+
/**
|
|
6
|
+
* Customer-facing post-agent-run verifier shape. The SDK and run-config JSON
|
|
7
|
+
* send this form on the wire; the server parser normalizes it to
|
|
8
|
+
* {@link PlatformPostHook}.
|
|
9
|
+
*/
|
|
10
|
+
export interface PlatformPostHookInput {
|
|
11
|
+
readonly command: string;
|
|
12
|
+
readonly timeout?: string;
|
|
13
|
+
readonly maxTurns?: number;
|
|
14
|
+
readonly maxChars?: number | null;
|
|
15
|
+
}
|
|
16
|
+
/** Parsed post-agent-run verifier carried through dispatch to the runner. */
|
|
17
|
+
export interface PlatformPostHook {
|
|
18
|
+
readonly command: string;
|
|
19
|
+
readonly timeoutMs: number;
|
|
20
|
+
readonly maxTurns: number;
|
|
21
|
+
readonly maxChars: number | null;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Parse the public `postHook` option. An omitted hook, null hook, or hook with
|
|
25
|
+
* an empty/whitespace-only command is treated as omitted so callers can pre-fill
|
|
26
|
+
* configs without enabling the verifier accidentally.
|
|
27
|
+
*/
|
|
28
|
+
export declare function parsePostHook(input: unknown, path?: string): PlatformPostHook | undefined;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { parseDurationToMs } from "./runtime-sizes.js";
|
|
2
|
+
/** Default post-agent-run hook timeout (5 minutes). */
|
|
3
|
+
export const DEFAULT_POST_HOOK_TIMEOUT_MS = 5 * 60 * 1000;
|
|
4
|
+
/** Default number of repair turns after a failing hook. */
|
|
5
|
+
export const DEFAULT_POST_HOOK_MAX_TURNS = 10;
|
|
6
|
+
/**
|
|
7
|
+
* Parse the public `postHook` option. An omitted hook, null hook, or hook with
|
|
8
|
+
* an empty/whitespace-only command is treated as omitted so callers can pre-fill
|
|
9
|
+
* configs without enabling the verifier accidentally.
|
|
10
|
+
*/
|
|
11
|
+
export function parsePostHook(input, path = "postHook") {
|
|
12
|
+
if (input === undefined || input === null) {
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
const value = requirePostHookRecord(input, path);
|
|
16
|
+
const allowed = new Set(["command", "timeout", "maxTurns", "maxChars"]);
|
|
17
|
+
for (const key of Object.keys(value)) {
|
|
18
|
+
if (!allowed.has(key)) {
|
|
19
|
+
throw new Error(`${path}.${key} is not an allowed field; permitted: command, timeout, maxTurns, maxChars`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
if (typeof value.command !== "string") {
|
|
23
|
+
throw new Error(`${path}.command must be a string`);
|
|
24
|
+
}
|
|
25
|
+
if (value.command.trim().length === 0) {
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
const timeoutMs = parsePostHookTimeout(value.timeout, `${path}.timeout`);
|
|
29
|
+
const maxTurns = parseNonNegativeInteger(value.maxTurns, `${path}.maxTurns`, DEFAULT_POST_HOOK_MAX_TURNS);
|
|
30
|
+
const maxChars = value.maxChars === null
|
|
31
|
+
? null
|
|
32
|
+
: parseNonNegativeInteger(value.maxChars, `${path}.maxChars`, null);
|
|
33
|
+
return {
|
|
34
|
+
command: value.command,
|
|
35
|
+
timeoutMs,
|
|
36
|
+
maxTurns,
|
|
37
|
+
maxChars
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function parsePostHookTimeout(input, path) {
|
|
41
|
+
if (input === undefined) {
|
|
42
|
+
return DEFAULT_POST_HOOK_TIMEOUT_MS;
|
|
43
|
+
}
|
|
44
|
+
if (typeof input !== "string") {
|
|
45
|
+
throw new Error(`${path} must be a duration string (e.g. "5m", "30s"); got ${JSON.stringify(input)}`);
|
|
46
|
+
}
|
|
47
|
+
const ms = parseDurationToMs(input);
|
|
48
|
+
if (ms <= 0) {
|
|
49
|
+
throw new Error(`${path} must be greater than 0ms; got ${ms}ms`);
|
|
50
|
+
}
|
|
51
|
+
return ms;
|
|
52
|
+
}
|
|
53
|
+
function parseNonNegativeInteger(input, path, defaultValue) {
|
|
54
|
+
if (input === undefined) {
|
|
55
|
+
return defaultValue;
|
|
56
|
+
}
|
|
57
|
+
if (typeof input !== "number" || !Number.isSafeInteger(input) || input < 0) {
|
|
58
|
+
throw new Error(`${path} must be a non-negative integer`);
|
|
59
|
+
}
|
|
60
|
+
return input;
|
|
61
|
+
}
|
|
62
|
+
function requirePostHookRecord(input, path) {
|
|
63
|
+
if (input === null || typeof input !== "object" || Array.isArray(input)) {
|
|
64
|
+
throw new Error(`${path} must be an object`);
|
|
65
|
+
}
|
|
66
|
+
return input;
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=post-hook.js.map
|
|
@@ -3,17 +3,11 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Public composition concepts:
|
|
5
5
|
*
|
|
6
|
-
* - `SkillRef` is the wire-level reference to a skill
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* terminal). The three shapes are discriminated by `kind` so
|
|
12
|
-
* consumers branch mechanically and providers can never accidentally
|
|
13
|
-
* be looked up in `skill_bundles`. Transient refs do NOT round-trip
|
|
14
|
-
* through JSON (bytes can't be serialised back); `parseRunRequestConfig`
|
|
15
|
-
* therefore rejects them while the BFF multipart submission parser
|
|
16
|
-
* accepts them.
|
|
6
|
+
* - `SkillRef` is the wire-level reference to a skill. Public run
|
|
7
|
+
* configs use storage-neutral `kind:"asset"` refs produced by the SDK
|
|
8
|
+
* upload path or by workspace catalog records. Provider skill refs remain
|
|
9
|
+
* in the parser for wire compatibility, but the managed runtime rejects
|
|
10
|
+
* them at submission time.
|
|
17
11
|
*
|
|
18
12
|
* - `McpServerRef` is the non-secret part of an MCP server declaration:
|
|
19
13
|
* `name` and `url`. Bearer / cookie / per-request headers travel in
|
|
@@ -37,7 +31,9 @@
|
|
|
37
31
|
* boundary.
|
|
38
32
|
*/
|
|
39
33
|
import type { JsonValue, PlatformProxyEndpoint, PlatformEnvironment } from "./submission.js";
|
|
34
|
+
import { type RunModel } from "./models.js";
|
|
40
35
|
import type { RuntimeSize } from "./runtime-sizes.js";
|
|
36
|
+
import { type PlatformPostHookInput } from "./post-hook.js";
|
|
41
37
|
/**
|
|
42
38
|
* Mirrors the server-side CHECK constraint
|
|
43
39
|
* `skill_bundles_id_format_chk = check (id ~ '^skl_[A-Za-z0-9_-]{8,128}$')`
|
|
@@ -62,10 +58,9 @@ export declare const SKILL_BUNDLE_LIMITS: {
|
|
|
62
58
|
/** Compressed (.zip) ceiling. */
|
|
63
59
|
readonly maxCompressedBytes: number;
|
|
64
60
|
/**
|
|
65
|
-
* Hard ceiling for the direct-to-storage
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
* limit; objects above this would need S3 multipart, which is out of scope.
|
|
61
|
+
* Hard ceiling for the direct-to-storage upload path. Bytes never transit the
|
|
62
|
+
* hosted API, so its memory/request-payload limits do not cap accepted
|
|
63
|
+
* bundles; objects above this product cap are rejected before upload.
|
|
69
64
|
*/
|
|
70
65
|
readonly maxBytes: number;
|
|
71
66
|
/** Sum of uncompressed file sizes. */
|
|
@@ -259,7 +254,7 @@ export declare function rejectStdioMcpShape(record: Record<string, unknown>): vo
|
|
|
259
254
|
* into the normal `submitRun` request.
|
|
260
255
|
*/
|
|
261
256
|
export interface RunRequestConfig {
|
|
262
|
-
readonly model:
|
|
257
|
+
readonly model: RunModel;
|
|
263
258
|
readonly system?: string;
|
|
264
259
|
readonly prompt: string | readonly string[];
|
|
265
260
|
readonly skills?: readonly SkillRef[];
|
|
@@ -269,6 +264,8 @@ export interface RunRequestConfig {
|
|
|
269
264
|
readonly runtimeSize?: RuntimeSize;
|
|
270
265
|
/** Run deadline as a duration string (`"1h"`, `"30m"`); bounded [1m, 6h] server-side. */
|
|
271
266
|
readonly timeout?: string;
|
|
267
|
+
/** Post-agent-run verifier command. Empty command is treated as omitted. */
|
|
268
|
+
readonly postHook?: PlatformPostHookInput;
|
|
272
269
|
readonly proxyEndpoints?: readonly PlatformProxyEndpoint[];
|
|
273
270
|
readonly metadata?: Readonly<Record<string, JsonValue>>;
|
|
274
271
|
}
|
|
@@ -290,7 +287,7 @@ export declare function parseRunRequestConfig(input: unknown): RunRequestConfig;
|
|
|
290
287
|
* the audit log don't have to re-handle two shapes.
|
|
291
288
|
*/
|
|
292
289
|
export interface NormalisedRunRequestConfig {
|
|
293
|
-
readonly model:
|
|
290
|
+
readonly model: RunModel;
|
|
294
291
|
readonly system?: string;
|
|
295
292
|
readonly prompt: readonly string[];
|
|
296
293
|
readonly skills: readonly SkillRef[];
|
|
@@ -298,6 +295,7 @@ export interface NormalisedRunRequestConfig {
|
|
|
298
295
|
readonly environment?: PlatformEnvironment;
|
|
299
296
|
readonly proxyEndpoints?: readonly PlatformProxyEndpoint[];
|
|
300
297
|
readonly metadata?: Readonly<Record<string, JsonValue>>;
|
|
298
|
+
readonly postHook?: PlatformPostHookInput;
|
|
301
299
|
/**
|
|
302
300
|
* MCP servers whose run-config entry carried `headers`. Keyed by the `name`
|
|
303
301
|
* that appears in `mcpServers` so the BFF can pair them up.
|
|
@@ -3,17 +3,11 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Public composition concepts:
|
|
5
5
|
*
|
|
6
|
-
* - `SkillRef` is the wire-level reference to a skill
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* terminal). The three shapes are discriminated by `kind` so
|
|
12
|
-
* consumers branch mechanically and providers can never accidentally
|
|
13
|
-
* be looked up in `skill_bundles`. Transient refs do NOT round-trip
|
|
14
|
-
* through JSON (bytes can't be serialised back); `parseRunRequestConfig`
|
|
15
|
-
* therefore rejects them while the BFF multipart submission parser
|
|
16
|
-
* accepts them.
|
|
6
|
+
* - `SkillRef` is the wire-level reference to a skill. Public run
|
|
7
|
+
* configs use storage-neutral `kind:"asset"` refs produced by the SDK
|
|
8
|
+
* upload path or by workspace catalog records. Provider skill refs remain
|
|
9
|
+
* in the parser for wire compatibility, but the managed runtime rejects
|
|
10
|
+
* them at submission time.
|
|
17
11
|
*
|
|
18
12
|
* - `McpServerRef` is the non-secret part of an MCP server declaration:
|
|
19
13
|
* `name` and `url`. Bearer / cookie / per-request headers travel in
|
|
@@ -36,6 +30,8 @@
|
|
|
36
30
|
* Keep this as the public source of truth for the SDK/CLI composition
|
|
37
31
|
* boundary.
|
|
38
32
|
*/
|
|
33
|
+
import { parseRunModel } from "./models.js";
|
|
34
|
+
import { parsePostHook } from "./post-hook.js";
|
|
39
35
|
// ---------------------------------------------------------------------------
|
|
40
36
|
// Skill ID + name format
|
|
41
37
|
// ---------------------------------------------------------------------------
|
|
@@ -66,10 +62,9 @@ export const SKILL_BUNDLE_LIMITS = {
|
|
|
66
62
|
/** Compressed (.zip) ceiling. */
|
|
67
63
|
maxCompressedBytes: 10 * 1024 * 1024,
|
|
68
64
|
/**
|
|
69
|
-
* Hard ceiling for the direct-to-storage
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
* limit; objects above this would need S3 multipart, which is out of scope.
|
|
65
|
+
* Hard ceiling for the direct-to-storage upload path. Bytes never transit the
|
|
66
|
+
* hosted API, so its memory/request-payload limits do not cap accepted
|
|
67
|
+
* bundles; objects above this product cap are rejected before upload.
|
|
73
68
|
*/
|
|
74
69
|
maxBytes: 2 * 1024 * 1024 * 1024,
|
|
75
70
|
/** Sum of uncompressed file sizes. */
|
|
@@ -609,6 +604,7 @@ export function parseRunRequestConfig(input) {
|
|
|
609
604
|
"environment",
|
|
610
605
|
"runtimeSize",
|
|
611
606
|
"timeout",
|
|
607
|
+
"postHook",
|
|
612
608
|
"proxyEndpoints",
|
|
613
609
|
"metadata"
|
|
614
610
|
]);
|
|
@@ -617,10 +613,7 @@ export function parseRunRequestConfig(input) {
|
|
|
617
613
|
throw new Error(`run request config contains unexpected field: ${key}`);
|
|
618
614
|
}
|
|
619
615
|
}
|
|
620
|
-
const model = record.model;
|
|
621
|
-
if (typeof model !== "string" || model.length === 0) {
|
|
622
|
-
throw new Error("run request config model must be a non-empty string");
|
|
623
|
-
}
|
|
616
|
+
const model = parseRunModel(record.model, "run request config model");
|
|
624
617
|
const system = record.system;
|
|
625
618
|
if (system !== undefined && typeof system !== "string") {
|
|
626
619
|
throw new Error("run request config system, when provided, must be a string");
|
|
@@ -628,6 +621,7 @@ export function parseRunRequestConfig(input) {
|
|
|
628
621
|
const prompt = parseRunRequestConfigPrompt(record.prompt);
|
|
629
622
|
const skills = parseRunRequestConfigSkills(record.skills);
|
|
630
623
|
const mcpServers = parseRunRequestConfigMcpServers(record.mcpServers);
|
|
624
|
+
const postHook = parsePostHook(record.postHook, "run request config postHook");
|
|
631
625
|
return {
|
|
632
626
|
model,
|
|
633
627
|
...(system !== undefined ? { system } : {}),
|
|
@@ -647,6 +641,9 @@ export function parseRunRequestConfig(input) {
|
|
|
647
641
|
...(record.timeout !== undefined
|
|
648
642
|
? { timeout: record.timeout }
|
|
649
643
|
: {}),
|
|
644
|
+
...(postHook !== undefined
|
|
645
|
+
? { postHook: record.postHook }
|
|
646
|
+
: {}),
|
|
650
647
|
...(record.proxyEndpoints !== undefined
|
|
651
648
|
? { proxyEndpoints: record.proxyEndpoints }
|
|
652
649
|
: {}),
|
|
@@ -724,6 +721,7 @@ export function normaliseRunRequestConfig(config) {
|
|
|
724
721
|
...(config.environment !== undefined ? { environment: config.environment } : {}),
|
|
725
722
|
...(config.proxyEndpoints !== undefined ? { proxyEndpoints: config.proxyEndpoints } : {}),
|
|
726
723
|
...(config.metadata !== undefined ? { metadata: config.metadata } : {}),
|
|
724
|
+
...(config.postHook !== undefined ? { postHook: config.postHook } : {}),
|
|
727
725
|
mcpServerSecrets
|
|
728
726
|
};
|
|
729
727
|
}
|
|
@@ -185,9 +185,9 @@ export interface RunUnit {
|
|
|
185
185
|
* submission. Never throws on minor unknown keys so we can
|
|
186
186
|
* forward-compat with worker-side enrichment.
|
|
187
187
|
*
|
|
188
|
-
* Returns a typed shape even for malformed snapshots
|
|
189
|
-
*
|
|
190
|
-
*
|
|
191
|
-
*
|
|
188
|
+
* Returns a typed shape even for malformed snapshots by falling back to the
|
|
189
|
+
* default public model and empty collection defaults, because the dashboard
|
|
190
|
+
* must still render *something* for a buggy historical row rather than 500ing
|
|
191
|
+
* the whole detail page.
|
|
192
192
|
*/
|
|
193
193
|
export declare function parseRunUnitSubmission(input: unknown): RunUnitSubmission;
|
|
@@ -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
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
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:
|
|
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;
|
|
@@ -226,7 +228,7 @@ export declare function optionalPositiveInt(input: unknown, field: string): numb
|
|
|
226
228
|
* into `run_skill_snapshots`), provider refs pass through unchanged.
|
|
227
229
|
*/
|
|
228
230
|
export interface PlatformSubmission {
|
|
229
|
-
readonly model:
|
|
231
|
+
readonly model: RunModel;
|
|
230
232
|
readonly system?: string;
|
|
231
233
|
readonly prompt: readonly string[];
|
|
232
234
|
readonly skills: readonly SkillRef[];
|
|
@@ -333,6 +335,13 @@ export interface PlatformRunSubmissionRequest {
|
|
|
333
335
|
* terminal wait window and self-kill deadline.
|
|
334
336
|
*/
|
|
335
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;
|
|
336
345
|
}
|
|
337
346
|
/**
|
|
338
347
|
* Wire shape posted by the SDK and CLI. `workspaceId` is **omitted by
|
|
@@ -347,7 +356,7 @@ export interface PlatformRunSubmissionRequest {
|
|
|
347
356
|
* {@link DEFAULT_RUN_PROVIDER} (`anthropic`). The parser fills it in
|
|
348
357
|
* before the value enters the run snapshot.
|
|
349
358
|
*/
|
|
350
|
-
export type PlatformRunSubmissionInput = Omit<PlatformRunSubmissionRequest, "workspaceId" | "credentialMode" | "provider" | "runtime" | "timeoutMs"> & {
|
|
359
|
+
export type PlatformRunSubmissionInput = Omit<PlatformRunSubmissionRequest, "workspaceId" | "credentialMode" | "provider" | "runtime" | "timeoutMs" | "postHook"> & {
|
|
351
360
|
readonly workspaceId?: string;
|
|
352
361
|
readonly credentialMode?: CredentialMode;
|
|
353
362
|
readonly provider?: RunProvider;
|
|
@@ -363,6 +372,7 @@ export type PlatformRunSubmissionInput = Omit<PlatformRunSubmissionRequest, "wor
|
|
|
363
372
|
* {@link PlatformRunSubmissionRequest.timeoutMs}. Absent ⇒ 1h default.
|
|
364
373
|
*/
|
|
365
374
|
readonly timeout?: string;
|
|
375
|
+
readonly postHook?: PlatformPostHookInput;
|
|
366
376
|
};
|
|
367
377
|
export interface ParseRunSubmissionOptions {
|
|
368
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
|
/**
|
|
@@ -782,6 +784,7 @@ export function parseRunSubmissionRequest(input, options = {}) {
|
|
|
782
784
|
"submission",
|
|
783
785
|
"runtimeSize",
|
|
784
786
|
"timeout",
|
|
787
|
+
"postHook",
|
|
785
788
|
"proxyEndpoints",
|
|
786
789
|
SECRETS_KEY
|
|
787
790
|
]);
|
|
@@ -815,11 +818,13 @@ export function parseRunSubmissionRequest(input, options = {}) {
|
|
|
815
818
|
}
|
|
816
819
|
const runtimeSize = parseRuntimeSize(value.runtimeSize);
|
|
817
820
|
const timeoutMs = parseRunTimeout(value.timeout);
|
|
821
|
+
const postHook = parsePostHook(value.postHook, "submission.postHook");
|
|
818
822
|
const proxyEndpoints = parseProxyEndpoints(value.proxyEndpoints);
|
|
819
823
|
const secrets = parseInlineSecrets(value.secrets);
|
|
820
824
|
enforceCredentialSecretPolicy(credentialMode, secrets);
|
|
821
825
|
crossValidateProxyEndpointsAndAuth(proxyEndpoints, secrets.proxyEndpointAuth);
|
|
822
826
|
const submission = parseSubmission(value.submission);
|
|
827
|
+
assertRunModelMatchesProvider(provider, submission.model);
|
|
823
828
|
// mcpServers names must agree across the submission half and the
|
|
824
829
|
// secrets half — every secrets.mcpServers[i].name MUST resolve to a
|
|
825
830
|
// submission.mcpServers entry (no orphan secrets) AND the URL must
|
|
@@ -861,6 +866,7 @@ export function parseRunSubmissionRequest(input, options = {}) {
|
|
|
861
866
|
submission,
|
|
862
867
|
...(runtimeSize ? { runtimeSize } : {}),
|
|
863
868
|
...(timeoutMs !== undefined ? { timeoutMs } : {}),
|
|
869
|
+
...(postHook !== undefined ? { postHook } : {}),
|
|
864
870
|
...(proxyEndpoints ? { proxyEndpoints } : {}),
|
|
865
871
|
secrets
|
|
866
872
|
};
|
|
@@ -927,7 +933,7 @@ export function parseSubmission(input) {
|
|
|
927
933
|
throw new Error(`submission.${key} is not an allowed field; permitted: ${[...allowed].join(", ")}`);
|
|
928
934
|
}
|
|
929
935
|
}
|
|
930
|
-
const model =
|
|
936
|
+
const model = parseRunModel(value.model, "submission.model");
|
|
931
937
|
const system = optionalString(value.system, "submission.system");
|
|
932
938
|
const prompt = parsePrompt(value.prompt);
|
|
933
939
|
const skills = parseSkills(value.skills);
|