@aexhq/sdk 0.24.0 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -125
- package/dist/_contracts/models.js +1 -2
- package/dist/_contracts/operations.d.ts +2 -2
- package/dist/_contracts/operations.js +4 -4
- package/dist/_contracts/provider-support.d.ts +23 -23
- package/dist/_contracts/provider-support.js +7 -14
- package/dist/_contracts/run-config.d.ts +24 -0
- package/dist/_contracts/run-config.js +6 -0
- package/dist/_contracts/run-unit.js +3 -1
- package/dist/_contracts/runtime-types.d.ts +2 -2
- package/dist/_contracts/submission.d.ts +2 -1
- package/dist/_contracts/submission.js +66 -1
- package/dist/bundle.d.ts +13 -0
- package/dist/bundle.js +51 -0
- package/dist/bundle.js.map +1 -1
- package/dist/cli.mjs +12 -18
- package/dist/cli.mjs.sha256 +1 -1
- package/dist/client.d.ts +6 -4
- package/dist/client.js +37 -6
- package/dist/client.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/tool.d.ts +41 -0
- package/dist/tool.js +138 -0
- package/dist/tool.js.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/docs/concepts/agent-tools.md +48 -0
- package/docs/concepts/composition.md +43 -0
- package/docs/concepts/providers-and-runtimes.md +53 -0
- package/docs/concepts/runs.md +40 -0
- package/docs/credentials.md +3 -1
- package/docs/limits.md +44 -0
- package/docs/provider-runtime-capabilities.md +52 -54
- package/docs/public-surface.json +81 -0
- package/docs/quickstart.md +28 -105
- package/docs/run-config.md +1 -1
- package/docs/secrets.md +123 -0
- package/docs/vision-skills.md +3 -6
- package/package.json +2 -2
- package/docs/product-boundaries.md +0 -57
package/README.md
CHANGED
|
@@ -2,163 +2,74 @@
|
|
|
2
2
|
title: aex
|
|
3
3
|
---
|
|
4
4
|
|
|
5
|
-
#
|
|
5
|
+
# @aexhq/sdk
|
|
6
6
|
|
|
7
|
-
aex is
|
|
7
|
+
aex is an agent execution platform for launching autonomous agents from a simple TypeScript SDK and CLI.
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
import {
|
|
11
|
-
AgentExecutor, // the only client class — submits durable runs to aex
|
|
12
|
-
RunModels, // closed public model id constants
|
|
13
|
-
Skill, // local, URL, and catalog skill bundles normalized to assets
|
|
14
|
-
McpServer, // MCP server declarations (headers split into secrets server-side)
|
|
15
|
-
ProxyEndpoint, // per-run managed HTTP proxy endpoint
|
|
16
|
-
AgentsMd, // AGENTS.md / CLAUDE.md uploads
|
|
17
|
-
File, // arbitrary workspace files mounted into the session
|
|
18
|
-
validateProxyAuth // helper that fails fast on policy/auth mismatch
|
|
19
|
-
} from "@aexhq/sdk";
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
```bash
|
|
23
|
-
aex run --config ./run.json --api-token ant_… \
|
|
24
|
-
--anthropic-api-key sk-ant-… --follow
|
|
25
|
-
aex status <run-id> --api-token …
|
|
26
|
-
aex wait <run-id> [--timeout 8m] [--interval 2s] --api-token …
|
|
27
|
-
aex events <run-id> [--follow] [--timeout 8m] --api-token …
|
|
28
|
-
aex outputs <run-id> --api-token …
|
|
29
|
-
aex download <run-id> [--only outputs|events|metadata] [--out path] --api-token …
|
|
30
|
-
aex cancel <run-id> --api-token …
|
|
31
|
-
aex delete <run-id> --api-token …
|
|
32
|
-
aex whoami --api-token …
|
|
33
|
-
aex skills <upload|list|get|delete> [flags] --api-token …
|
|
34
|
-
aex delete-asset <assetId|hash> --api-token …
|
|
35
|
-
```
|
|
9
|
+
The package ships:
|
|
36
10
|
|
|
37
|
-
|
|
11
|
+
- `AgentExecutor` for submit, run, wait, stream, inspect, download, cancel, and delete.
|
|
12
|
+
- Typed run primitives: `Models`, `Providers`, `RuntimeSizes`, `Skill`, `AgentsMd`, `File`, `McpServer`, `ProxyEndpoint`, and `Secret`.
|
|
13
|
+
- A bundled `aex` CLI with the same run, status, events, outputs, download, cancel, delete, whoami, and skills operations.
|
|
38
14
|
|
|
39
|
-
|
|
15
|
+
## Install
|
|
40
16
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
regardless of provider:
|
|
45
|
-
- omit `runtime` or pass `runtime: "managed"`; every provider uses the
|
|
46
|
-
managed runtime and BYOK provider-proxy.
|
|
47
|
-
- `provider: "anthropic" | "deepseek" | "openai" | "gemini" | "mistral"`.
|
|
48
|
-
- See [provider/runtime capabilities](docs/provider-runtime-capabilities.md)
|
|
49
|
-
for the generated matrix.
|
|
50
|
-
- BYO provider key + MCP credentials + skill references — passed inline on every submission and held in run-scoped custody, with cleanup/revocation attempted at terminal. Cross-provider keys are rejected loudly at submission time.
|
|
51
|
-
- Workspace is the tenant boundary. Workspace identity is derived server-side from the API token (1:1 binding); the SDK / CLI never name it.
|
|
52
|
-
- No SDK-side storage of provider keys, MCP credentials, or output file contents.
|
|
53
|
-
- Cleanup runs by default for tracked runtime resources.
|
|
54
|
-
- Product boundaries are explicit: see [product capabilities and boundaries](docs/product-boundaries.md) for what aex owns, inherits, and does not support.
|
|
17
|
+
```bash
|
|
18
|
+
npm install @aexhq/sdk
|
|
19
|
+
```
|
|
55
20
|
|
|
56
|
-
##
|
|
21
|
+
## First Run
|
|
57
22
|
|
|
58
23
|
```ts
|
|
59
|
-
import { AgentExecutor,
|
|
24
|
+
import { AgentExecutor, Models, Providers } from "@aexhq/sdk";
|
|
60
25
|
|
|
61
26
|
const aex = new AgentExecutor({
|
|
62
|
-
apiToken: process.env.AEX_API_TOKEN
|
|
63
|
-
// baseUrl defaults to https://api.aex.dev - set it for local or staging planes.
|
|
27
|
+
apiToken: process.env.AEX_API_TOKEN!
|
|
64
28
|
});
|
|
65
29
|
|
|
66
30
|
const runId = await aex.submit({
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
prompt: "Write
|
|
31
|
+
provider: Providers.ANTHROPIC,
|
|
32
|
+
model: Models.CLAUDE_HAIKU_4_5,
|
|
33
|
+
prompt: "Write the report and save outputs.",
|
|
70
34
|
secrets: { apiKey: process.env.ANTHROPIC_API_KEY! }
|
|
71
35
|
});
|
|
72
36
|
|
|
73
|
-
const
|
|
74
|
-
console.log(
|
|
75
|
-
|
|
76
|
-
for (const output of await aex.outputs(runId)) {
|
|
77
|
-
console.log(output.id, output.filename);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const report = await aex.downloadOutput(runId, { path: "report.txt", match: "suffix" });
|
|
81
|
-
console.log(new TextDecoder().decode(report));
|
|
82
|
-
|
|
83
|
-
await aex.downloadOutputs(runId, { to: "./outputs.zip" });
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
Reusable, credential-free configs can be ordinary functions:
|
|
87
|
-
|
|
88
|
-
```ts
|
|
89
|
-
function summarise(topic: string) {
|
|
90
|
-
return {
|
|
91
|
-
model: RunModels.CLAUDE_HAIKU_4_5,
|
|
92
|
-
system: "You are a concise automation agent.",
|
|
93
|
-
prompt: `Write a short answer about ${topic}.`
|
|
94
|
-
};
|
|
37
|
+
for await (const event of aex.stream(runId)) {
|
|
38
|
+
console.log(event.type);
|
|
95
39
|
}
|
|
96
40
|
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
secrets: { apiKey: process.env.ANTHROPIC_API_KEY! }
|
|
100
|
-
});
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
Stream events live with `aex.stream(runId)`:
|
|
41
|
+
const run = await aex.wait(runId);
|
|
42
|
+
console.log(run.status);
|
|
104
43
|
|
|
105
|
-
|
|
106
|
-
for await (const event of aex.stream(runId)) {
|
|
107
|
-
if (event.type === "TEXT_MESSAGE_CONTENT") {
|
|
108
|
-
// typed event helpers live under `aex`'s event guard exports.
|
|
109
|
-
}
|
|
110
|
-
}
|
|
44
|
+
await aex.download(runId, { to: "./run.zip" });
|
|
111
45
|
```
|
|
112
46
|
|
|
113
|
-
The same
|
|
47
|
+
The same request can run from the CLI:
|
|
114
48
|
|
|
115
49
|
```bash
|
|
116
50
|
aex run \
|
|
117
51
|
--api-token "$AEX_API_TOKEN" \
|
|
118
52
|
--anthropic-api-key "$ANTHROPIC_API_KEY" \
|
|
119
53
|
--model claude-haiku-4-5 \
|
|
120
|
-
--
|
|
121
|
-
--prompt "Write a short answer about agent-first SDK design." \
|
|
122
|
-
--follow
|
|
123
|
-
|
|
124
|
-
aex run \
|
|
125
|
-
--api-token "$AEX_API_TOKEN" \
|
|
126
|
-
--anthropic-api-key "$ANTHROPIC_API_KEY" \
|
|
127
|
-
--config ./run.json \
|
|
54
|
+
--prompt "Write the report and save outputs." \
|
|
128
55
|
--follow
|
|
129
56
|
```
|
|
130
57
|
|
|
131
|
-
|
|
58
|
+
## Feature Areas
|
|
132
59
|
|
|
133
|
-
|
|
60
|
+
- **Agent runtime:** managed autonomous runs with shell, filesystem, editing, notebook, web fetch/search, background command, and post-hook repair tools.
|
|
61
|
+
- **Durable infrastructure:** run records, status, wait/cancel/delete, idempotency, typed events, output capture, downloads, timeouts, and runtime sizes.
|
|
62
|
+
- **Agent composition:** skills, files, AGENTS.md, remote MCP servers, proxy endpoints, environment variables, packages, and networking controls.
|
|
63
|
+
- **Subagents:** typed parent/child lineage for async child runs, output handoff, and bounded agent delegation.
|
|
64
|
+
- **Models and providers:** Anthropic, DeepSeek, OpenAI, Gemini, Mistral, OpenRouter, Doubao, and Doubao China behind one submission shape.
|
|
65
|
+
- **Typed control surface:** strongly typed SDK inputs, CLI parity, BYOK secrets, scoped proxy auth, redaction, and output modes.
|
|
134
66
|
|
|
135
|
-
##
|
|
136
|
-
|
|
137
|
-
```text
|
|
138
|
-
pnpm test # unit (deterministic; uses fakes/snapshots)
|
|
139
|
-
pnpm test:user:offline # clean install of packed/published SDK, no live API
|
|
140
|
-
pnpm test:user # live hosted API user tests
|
|
141
|
-
pnpm test:user:heavy # explicit heavy live canary
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
User tests auto-pack the current SDK when no artifact env is set. CI can pin a
|
|
145
|
-
specific artifact with exactly one of `AEX_USER_TEST_TARBALL` or
|
|
146
|
-
`AEX_USER_TEST_VERSION`; live runs also need `AEX_API_URL`,
|
|
147
|
-
`AEX_API_TOKEN`, and `DEEPSEEK_API_KEY`.
|
|
148
|
-
|
|
149
|
-
## Guides
|
|
67
|
+
## Docs
|
|
150
68
|
|
|
151
69
|
- [Quickstart](docs/quickstart.md)
|
|
152
|
-
- [Run
|
|
153
|
-
- [
|
|
154
|
-
- [
|
|
70
|
+
- [Run configuration](docs/run-config.md)
|
|
71
|
+
- [Agent tools](docs/concepts/agent-tools.md)
|
|
72
|
+
- [Composition](docs/concepts/composition.md)
|
|
73
|
+
- [Secrets](docs/secrets.md)
|
|
74
|
+
- [Limits](docs/limits.md)
|
|
155
75
|
- [Provider/runtime capabilities](docs/provider-runtime-capabilities.md)
|
|
156
|
-
- [Credentials](docs/credentials.md)
|
|
157
|
-
- [MCP](docs/mcp.md)
|
|
158
|
-
- [Skills](docs/skills.md)
|
|
159
|
-
- [Outputs](docs/outputs.md)
|
|
160
|
-
- [Events](docs/events.md)
|
|
161
|
-
- [Cleanup](docs/cleanup.md)
|
|
162
|
-
- [Testing](docs/testing.md)
|
|
163
|
-
- [Release](docs/release.md)
|
|
164
|
-
|
|
@@ -37,8 +37,7 @@ export const MODEL_PROVIDER_IDS = {
|
|
|
37
37
|
// China Volcengine Ark gateway (`doubao-cn`). Ark accepts the API-format
|
|
38
38
|
// model NAME directly in the chat-completions `model` field (no `ep-…`
|
|
39
39
|
// inference-endpoint id). The native strings are the same Ark catalog ids on
|
|
40
|
-
// both gateways
|
|
41
|
-
// (both providers ship `live-unverified` until then — provider-support.ts).
|
|
40
|
+
// both gateways.
|
|
42
41
|
// pro — Doubao Seed 1.8 (flagship, 256K context).
|
|
43
42
|
// flash — Doubao Seed 1.6 Flash (fast/cheap, 256K context).
|
|
44
43
|
"doubao-seed-pro": { doubao: "doubao-seed-1-8-251228", "doubao-cn": "doubao-seed-1-8-251228" },
|
|
@@ -215,8 +215,8 @@ export declare function createSecret(http: HttpClient, args: {
|
|
|
215
215
|
export declare function listSecrets(http: HttpClient): Promise<readonly SecretRecord[]>;
|
|
216
216
|
/** Metadata for one workspace secret by name. Never returns the value. */
|
|
217
217
|
export declare function getSecret(http: HttpClient, name: string): Promise<SecretRecord>;
|
|
218
|
-
/** Audited value read — the
|
|
219
|
-
export declare function
|
|
218
|
+
/** Audited value read — the preferred path that returns a workspace secret value. */
|
|
219
|
+
export declare function getSecretValue(http: HttpClient, name: string): Promise<SecretReveal>;
|
|
220
220
|
/** Replace the value of an existing workspace secret; bumps its version. */
|
|
221
221
|
export declare function rotateSecret(http: HttpClient, args: {
|
|
222
222
|
readonly name: string;
|
|
@@ -547,7 +547,7 @@ function unwrapFile(result) {
|
|
|
547
547
|
// Value-bearing requests (create/rotate) carry the value in the JSON BODY,
|
|
548
548
|
// never the URL/query, so it never lands in logs or the request line. Reads
|
|
549
549
|
// split by sensitivity: `getSecret`/`listSecrets` return METADATA only;
|
|
550
|
-
// `
|
|
550
|
+
// `getSecretValue` is the audited value read (POST so it's a logged action).
|
|
551
551
|
// ===========================================================================
|
|
552
552
|
/** Create a named workspace secret. The value travels in the body. */
|
|
553
553
|
export async function createSecret(http, args) {
|
|
@@ -569,9 +569,9 @@ export async function getSecret(http, name) {
|
|
|
569
569
|
const result = await http.request(`/api/secrets/${encodeURIComponent(name)}`);
|
|
570
570
|
return unwrapSecret(result);
|
|
571
571
|
}
|
|
572
|
-
/** Audited value read — the
|
|
573
|
-
export async function
|
|
574
|
-
return http.request(`/api/secrets/${encodeURIComponent(name)}/
|
|
572
|
+
/** Audited value read — the preferred path that returns a workspace secret value. */
|
|
573
|
+
export async function getSecretValue(http, name) {
|
|
574
|
+
return http.request(`/api/secrets/${encodeURIComponent(name)}/get_value`, {
|
|
575
575
|
method: "POST"
|
|
576
576
|
});
|
|
577
577
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { RunProvider, RuntimeKind } from "./submission.js";
|
|
2
|
-
export declare const PROVIDER_SUPPORT_STATUSES: readonly ["supported", "
|
|
2
|
+
export declare const PROVIDER_SUPPORT_STATUSES: readonly ["supported", "rejected"];
|
|
3
3
|
export type ProviderSupportStatus = (typeof PROVIDER_SUPPORT_STATUSES)[number];
|
|
4
4
|
export interface SupportPointer {
|
|
5
5
|
readonly label: string;
|
|
@@ -45,8 +45,8 @@ export declare const PROVIDER_PUBLIC_SUPPORT: {
|
|
|
45
45
|
readonly status: "supported";
|
|
46
46
|
readonly docsAnchor: "anthropic";
|
|
47
47
|
readonly docs: readonly [{
|
|
48
|
-
readonly label: "
|
|
49
|
-
readonly href: "
|
|
48
|
+
readonly label: "Secrets";
|
|
49
|
+
readonly href: "secrets.md";
|
|
50
50
|
}, {
|
|
51
51
|
readonly label: "Events";
|
|
52
52
|
readonly href: "events.md";
|
|
@@ -82,8 +82,8 @@ export declare const PROVIDER_PUBLIC_SUPPORT: {
|
|
|
82
82
|
readonly status: "supported";
|
|
83
83
|
readonly docsAnchor: "deepseek";
|
|
84
84
|
readonly docs: readonly [{
|
|
85
|
-
readonly label: "
|
|
86
|
-
readonly href: "
|
|
85
|
+
readonly label: "Secrets";
|
|
86
|
+
readonly href: "secrets.md";
|
|
87
87
|
}, {
|
|
88
88
|
readonly label: "Events";
|
|
89
89
|
readonly href: "events.md";
|
|
@@ -122,11 +122,11 @@ export declare const PROVIDER_PUBLIC_SUPPORT: {
|
|
|
122
122
|
};
|
|
123
123
|
readonly openai: {
|
|
124
124
|
readonly displayName: "OpenAI";
|
|
125
|
-
readonly status: "
|
|
125
|
+
readonly status: "supported";
|
|
126
126
|
readonly docsAnchor: "openai";
|
|
127
127
|
readonly docs: readonly [{
|
|
128
|
-
readonly label: "
|
|
129
|
-
readonly href: "
|
|
128
|
+
readonly label: "Secrets";
|
|
129
|
+
readonly href: "secrets.md";
|
|
130
130
|
}, {
|
|
131
131
|
readonly label: "Events";
|
|
132
132
|
readonly href: "events.md";
|
|
@@ -156,11 +156,11 @@ export declare const PROVIDER_PUBLIC_SUPPORT: {
|
|
|
156
156
|
};
|
|
157
157
|
readonly gemini: {
|
|
158
158
|
readonly displayName: "Gemini";
|
|
159
|
-
readonly status: "
|
|
159
|
+
readonly status: "supported";
|
|
160
160
|
readonly docsAnchor: "gemini";
|
|
161
161
|
readonly docs: readonly [{
|
|
162
|
-
readonly label: "
|
|
163
|
-
readonly href: "
|
|
162
|
+
readonly label: "Secrets";
|
|
163
|
+
readonly href: "secrets.md";
|
|
164
164
|
}, {
|
|
165
165
|
readonly label: "Events";
|
|
166
166
|
readonly href: "events.md";
|
|
@@ -190,11 +190,11 @@ export declare const PROVIDER_PUBLIC_SUPPORT: {
|
|
|
190
190
|
};
|
|
191
191
|
readonly mistral: {
|
|
192
192
|
readonly displayName: "Mistral";
|
|
193
|
-
readonly status: "
|
|
193
|
+
readonly status: "supported";
|
|
194
194
|
readonly docsAnchor: "mistral";
|
|
195
195
|
readonly docs: readonly [{
|
|
196
|
-
readonly label: "
|
|
197
|
-
readonly href: "
|
|
196
|
+
readonly label: "Secrets";
|
|
197
|
+
readonly href: "secrets.md";
|
|
198
198
|
}, {
|
|
199
199
|
readonly label: "Events";
|
|
200
200
|
readonly href: "events.md";
|
|
@@ -224,11 +224,11 @@ export declare const PROVIDER_PUBLIC_SUPPORT: {
|
|
|
224
224
|
};
|
|
225
225
|
readonly openrouter: {
|
|
226
226
|
readonly displayName: "OpenRouter";
|
|
227
|
-
readonly status: "
|
|
227
|
+
readonly status: "supported";
|
|
228
228
|
readonly docsAnchor: "openrouter";
|
|
229
229
|
readonly docs: readonly [{
|
|
230
|
-
readonly label: "
|
|
231
|
-
readonly href: "
|
|
230
|
+
readonly label: "Secrets";
|
|
231
|
+
readonly href: "secrets.md";
|
|
232
232
|
}, {
|
|
233
233
|
readonly label: "Events";
|
|
234
234
|
readonly href: "events.md";
|
|
@@ -258,11 +258,11 @@ export declare const PROVIDER_PUBLIC_SUPPORT: {
|
|
|
258
258
|
};
|
|
259
259
|
readonly doubao: {
|
|
260
260
|
readonly displayName: "Doubao";
|
|
261
|
-
readonly status: "
|
|
261
|
+
readonly status: "supported";
|
|
262
262
|
readonly docsAnchor: "doubao";
|
|
263
263
|
readonly docs: readonly [{
|
|
264
|
-
readonly label: "
|
|
265
|
-
readonly href: "
|
|
264
|
+
readonly label: "Secrets";
|
|
265
|
+
readonly href: "secrets.md";
|
|
266
266
|
}, {
|
|
267
267
|
readonly label: "Events";
|
|
268
268
|
readonly href: "events.md";
|
|
@@ -292,11 +292,11 @@ export declare const PROVIDER_PUBLIC_SUPPORT: {
|
|
|
292
292
|
};
|
|
293
293
|
readonly "doubao-cn": {
|
|
294
294
|
readonly displayName: "Doubao (China)";
|
|
295
|
-
readonly status: "
|
|
295
|
+
readonly status: "supported";
|
|
296
296
|
readonly docsAnchor: "doubao-cn";
|
|
297
297
|
readonly docs: readonly [{
|
|
298
|
-
readonly label: "
|
|
299
|
-
readonly href: "
|
|
298
|
+
readonly label: "Secrets";
|
|
299
|
+
readonly href: "secrets.md";
|
|
300
300
|
}, {
|
|
301
301
|
readonly label: "Events";
|
|
302
302
|
readonly href: "events.md";
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
export const PROVIDER_SUPPORT_STATUSES = [
|
|
2
2
|
"supported",
|
|
3
|
-
"live-unverified",
|
|
4
3
|
"rejected"
|
|
5
4
|
];
|
|
6
5
|
const COMMON_DOCS = [
|
|
7
|
-
{ label: "
|
|
6
|
+
{ label: "Secrets", href: "secrets.md" },
|
|
8
7
|
{ label: "Events", href: "events.md" }
|
|
9
8
|
];
|
|
10
9
|
const COMMON_EVIDENCE = [
|
|
@@ -72,7 +71,7 @@ export const PROVIDER_PUBLIC_SUPPORT = {
|
|
|
72
71
|
},
|
|
73
72
|
openai: {
|
|
74
73
|
displayName: "OpenAI",
|
|
75
|
-
status: "
|
|
74
|
+
status: "supported",
|
|
76
75
|
docsAnchor: "openai",
|
|
77
76
|
docs: COMMON_DOCS,
|
|
78
77
|
evidence: COMMON_EVIDENCE,
|
|
@@ -82,7 +81,7 @@ export const PROVIDER_PUBLIC_SUPPORT = {
|
|
|
82
81
|
},
|
|
83
82
|
gemini: {
|
|
84
83
|
displayName: "Gemini",
|
|
85
|
-
status: "
|
|
84
|
+
status: "supported",
|
|
86
85
|
docsAnchor: "gemini",
|
|
87
86
|
docs: COMMON_DOCS,
|
|
88
87
|
evidence: COMMON_EVIDENCE,
|
|
@@ -92,7 +91,7 @@ export const PROVIDER_PUBLIC_SUPPORT = {
|
|
|
92
91
|
},
|
|
93
92
|
mistral: {
|
|
94
93
|
displayName: "Mistral",
|
|
95
|
-
status: "
|
|
94
|
+
status: "supported",
|
|
96
95
|
docsAnchor: "mistral",
|
|
97
96
|
docs: COMMON_DOCS,
|
|
98
97
|
evidence: COMMON_EVIDENCE,
|
|
@@ -102,7 +101,7 @@ export const PROVIDER_PUBLIC_SUPPORT = {
|
|
|
102
101
|
},
|
|
103
102
|
openrouter: {
|
|
104
103
|
displayName: "OpenRouter",
|
|
105
|
-
status: "
|
|
104
|
+
status: "supported",
|
|
106
105
|
docsAnchor: "openrouter",
|
|
107
106
|
docs: COMMON_DOCS,
|
|
108
107
|
evidence: COMMON_EVIDENCE,
|
|
@@ -111,13 +110,9 @@ export const PROVIDER_PUBLIC_SUPPORT = {
|
|
|
111
110
|
}
|
|
112
111
|
},
|
|
113
112
|
// Doubao (ByteDance) via the official Ark API — international BytePlus gateway.
|
|
114
|
-
// Wired + parser/routing-verified but not yet proven against a live BytePlus
|
|
115
|
-
// account, so `live-unverified`. Promote to `supported` (and swap COMMON_EVIDENCE
|
|
116
|
-
// for a DOUBAO_MANAGED_EVIDENCE pointer to live-sdk-doubao.test.ts) once the
|
|
117
|
-
// live run passes.
|
|
118
113
|
doubao: {
|
|
119
114
|
displayName: "Doubao",
|
|
120
|
-
status: "
|
|
115
|
+
status: "supported",
|
|
121
116
|
docsAnchor: "doubao",
|
|
122
117
|
docs: COMMON_DOCS,
|
|
123
118
|
evidence: COMMON_EVIDENCE,
|
|
@@ -126,11 +121,9 @@ export const PROVIDER_PUBLIC_SUPPORT = {
|
|
|
126
121
|
}
|
|
127
122
|
},
|
|
128
123
|
// Doubao (ByteDance) via the official Ark API — China Volcengine gateway.
|
|
129
|
-
// Same wiring as `doubao`; additionally gated on CF Worker egress reaching the
|
|
130
|
-
// Beijing host (see apps/egress-probe). `live-unverified` until proven live.
|
|
131
124
|
"doubao-cn": {
|
|
132
125
|
displayName: "Doubao (China)",
|
|
133
|
-
status: "
|
|
126
|
+
status: "supported",
|
|
134
127
|
docsAnchor: "doubao-cn",
|
|
135
128
|
docs: COMMON_DOCS,
|
|
136
129
|
evidence: COMMON_EVIDENCE,
|
|
@@ -47,6 +47,12 @@ export declare const SKILL_ID_PATTERN: RegExp;
|
|
|
47
47
|
* surface so callers fail at the boundary rather than in the BFF.
|
|
48
48
|
*/
|
|
49
49
|
export declare const SKILL_NAME_PATTERN: RegExp;
|
|
50
|
+
/**
|
|
51
|
+
* Provider-safe submitted tool name. Tool names share the same lowercase
|
|
52
|
+
* kebab/underscore envelope as skills. Submission parsing rejects `__`
|
|
53
|
+
* because SessionDO reserves that separator for MCP namespace routing.
|
|
54
|
+
*/
|
|
55
|
+
export declare const TOOL_NAME_PATTERN: RegExp;
|
|
50
56
|
/**
|
|
51
57
|
* Hard caps applied at upload time. The SDK enforces these before
|
|
52
58
|
* computing the zip hash so a clearly-too-big bundle never wastes
|
|
@@ -87,6 +93,23 @@ export interface AssetRef {
|
|
|
87
93
|
readonly name: string;
|
|
88
94
|
readonly mountPath?: string;
|
|
89
95
|
}
|
|
96
|
+
type ToolJsonPrimitive = string | number | boolean | null;
|
|
97
|
+
type ToolJsonValue = ToolJsonPrimitive | ToolJsonValue[] | {
|
|
98
|
+
readonly [key: string]: ToolJsonValue;
|
|
99
|
+
};
|
|
100
|
+
export type ToolInputSchema = {
|
|
101
|
+
readonly [key: string]: ToolJsonValue;
|
|
102
|
+
};
|
|
103
|
+
/**
|
|
104
|
+
* User-supplied executable tool bundle. The bytes are addressed by the same
|
|
105
|
+
* content-addressed asset ref used by Skills/Files, while the provider-visible
|
|
106
|
+
* manifest rides as value-free metadata on the submission.
|
|
107
|
+
*/
|
|
108
|
+
export interface ToolRef extends AssetRef {
|
|
109
|
+
readonly description: string;
|
|
110
|
+
readonly input_schema: ToolInputSchema;
|
|
111
|
+
readonly entry: string;
|
|
112
|
+
}
|
|
90
113
|
export interface ProviderSkillRef {
|
|
91
114
|
readonly kind: "provider";
|
|
92
115
|
readonly vendor: "anthropic" | "custom";
|
|
@@ -330,3 +353,4 @@ export interface NormalisedRunRequestConfig {
|
|
|
330
353
|
}>;
|
|
331
354
|
}
|
|
332
355
|
export declare function normaliseRunRequestConfig(config: RunRequestConfig): NormalisedRunRequestConfig;
|
|
356
|
+
export {};
|
|
@@ -48,6 +48,12 @@ export const SKILL_ID_PATTERN = /^skl_[A-Za-z0-9_-]{8,128}$/;
|
|
|
48
48
|
* surface so callers fail at the boundary rather than in the BFF.
|
|
49
49
|
*/
|
|
50
50
|
export const SKILL_NAME_PATTERN = /^[a-z0-9][a-z0-9_-]{0,127}$/;
|
|
51
|
+
/**
|
|
52
|
+
* Provider-safe submitted tool name. Tool names share the same lowercase
|
|
53
|
+
* kebab/underscore envelope as skills. Submission parsing rejects `__`
|
|
54
|
+
* because SessionDO reserves that separator for MCP namespace routing.
|
|
55
|
+
*/
|
|
56
|
+
export const TOOL_NAME_PATTERN = SKILL_NAME_PATTERN;
|
|
51
57
|
// ---------------------------------------------------------------------------
|
|
52
58
|
// Skill bundle limits (uploaded bundles)
|
|
53
59
|
// ---------------------------------------------------------------------------
|
|
@@ -64,6 +64,7 @@ function parseFlatProjection(value) {
|
|
|
64
64
|
agentsMd: [],
|
|
65
65
|
files: [],
|
|
66
66
|
mcpServers: toMcpServerRefArray(submissionRaw.mcpServers),
|
|
67
|
+
tools: [],
|
|
67
68
|
...(parseEnvironment(submissionRaw.environment)
|
|
68
69
|
? { environment: parseEnvironment(submissionRaw.environment) }
|
|
69
70
|
: {}),
|
|
@@ -109,7 +110,8 @@ function fallbackFlat() {
|
|
|
109
110
|
skills: [],
|
|
110
111
|
agentsMd: [],
|
|
111
112
|
files: [],
|
|
112
|
-
mcpServers: []
|
|
113
|
+
mcpServers: [],
|
|
114
|
+
tools: []
|
|
113
115
|
}
|
|
114
116
|
};
|
|
115
117
|
}
|
|
@@ -250,8 +250,8 @@ export interface SecretRecord {
|
|
|
250
250
|
readonly [key: string]: unknown;
|
|
251
251
|
}
|
|
252
252
|
/**
|
|
253
|
-
* Value-bearing result of an audited `aex.secrets.
|
|
254
|
-
* that carries a workspace secret value back to the caller.
|
|
253
|
+
* Value-bearing result of an audited `aex.secrets.get_value`. The ONLY wire shape
|
|
254
|
+
* that carries a workspace secret value back to the caller. Value read is a logged
|
|
255
255
|
* action (POST, not GET) so a value read is always attributable.
|
|
256
256
|
*/
|
|
257
257
|
export interface SecretReveal {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { PROXY_ENDPOINT_DEFAULTS, type ProxyAuthShape, type ProxyMethod, type ProxyRetryPolicy, type ProxyResponseMode } from "./proxy-protocol.js";
|
|
2
2
|
export { PROXY_ENDPOINT_DEFAULTS };
|
|
3
|
-
import type { AgentsMdRef, FileRef, McpServerRef, SkillRef } from "./run-config.js";
|
|
3
|
+
import type { AgentsMdRef, FileRef, McpServerRef, SkillRef, ToolRef } from "./run-config.js";
|
|
4
4
|
import { type RuntimeSize } from "./runtime-sizes.js";
|
|
5
5
|
import { type PlatformPostHook, type PlatformPostHookInput } from "./post-hook.js";
|
|
6
6
|
import { type RunModel } from "./models.js";
|
|
@@ -298,6 +298,7 @@ export interface PlatformSubmission {
|
|
|
298
298
|
readonly system?: string;
|
|
299
299
|
readonly prompt: readonly string[];
|
|
300
300
|
readonly skills: readonly SkillRef[];
|
|
301
|
+
readonly tools?: readonly ToolRef[];
|
|
301
302
|
readonly agentsMd: readonly AgentsMdRef[];
|
|
302
303
|
readonly files: readonly FileRef[];
|
|
303
304
|
readonly mcpServers: readonly McpServerRef[];
|
|
@@ -4,7 +4,7 @@ import { authShapeHeaderName, PROXY_ALLOWED_METHODS, PROXY_ENDPOINT_DEFAULTS, PR
|
|
|
4
4
|
// existing `@aexhq/contracts` consumers of `PROXY_ENDPOINT_DEFAULTS` are
|
|
5
5
|
// unaffected by the move.
|
|
6
6
|
export { PROXY_ENDPOINT_DEFAULTS };
|
|
7
|
-
import { parseAssetRefFields, parseMcpServerRef, parseSkillRef } from "./run-config.js";
|
|
7
|
+
import { TOOL_NAME_PATTERN, normaliseSkillBundlePath, parseAssetRefFields, parseMcpServerRef, parseSkillRef } from "./run-config.js";
|
|
8
8
|
import { parseRunTimeout, parseRuntimeSize } from "./runtime-sizes.js";
|
|
9
9
|
import { parsePostHook } from "./post-hook.js";
|
|
10
10
|
import { assertRunModelMatchesProvider, parseRunModel } from "./models.js";
|
|
@@ -1113,6 +1113,7 @@ export function parseSubmission(input) {
|
|
|
1113
1113
|
"system",
|
|
1114
1114
|
"prompt",
|
|
1115
1115
|
"skills",
|
|
1116
|
+
"tools",
|
|
1116
1117
|
"agentsMd",
|
|
1117
1118
|
"files",
|
|
1118
1119
|
"mcpServers",
|
|
@@ -1134,6 +1135,7 @@ export function parseSubmission(input) {
|
|
|
1134
1135
|
const system = optionalString(value.system, "submission.system");
|
|
1135
1136
|
const prompt = parsePrompt(value.prompt);
|
|
1136
1137
|
const skills = parseSkills(value.skills);
|
|
1138
|
+
const tools = parseTools(value.tools);
|
|
1137
1139
|
const agentsMd = parseAgentsMd(value.agentsMd);
|
|
1138
1140
|
const files = parseFiles(value.files);
|
|
1139
1141
|
const mcpServers = parseMcpServers(value.mcpServers);
|
|
@@ -1150,6 +1152,7 @@ export function parseSubmission(input) {
|
|
|
1150
1152
|
...(system ? { system } : {}),
|
|
1151
1153
|
prompt,
|
|
1152
1154
|
skills,
|
|
1155
|
+
tools,
|
|
1153
1156
|
agentsMd,
|
|
1154
1157
|
files,
|
|
1155
1158
|
mcpServers,
|
|
@@ -1505,6 +1508,68 @@ function parseSkills(input) {
|
|
|
1505
1508
|
return ref;
|
|
1506
1509
|
});
|
|
1507
1510
|
}
|
|
1511
|
+
function parseTools(input) {
|
|
1512
|
+
if (input === undefined) {
|
|
1513
|
+
return [];
|
|
1514
|
+
}
|
|
1515
|
+
if (!Array.isArray(input)) {
|
|
1516
|
+
throw new Error("submission.tools must be an array of ToolRef objects");
|
|
1517
|
+
}
|
|
1518
|
+
const seenNames = new Set();
|
|
1519
|
+
const seenAssetIds = new Set();
|
|
1520
|
+
return input.map((item, index) => {
|
|
1521
|
+
const path = `submission.tools[${index}]`;
|
|
1522
|
+
const raw = requireRecord(item, path);
|
|
1523
|
+
for (const key of Object.keys(raw)) {
|
|
1524
|
+
if (key !== "kind" &&
|
|
1525
|
+
key !== "assetId" &&
|
|
1526
|
+
key !== "name" &&
|
|
1527
|
+
key !== "description" &&
|
|
1528
|
+
key !== "input_schema" &&
|
|
1529
|
+
key !== "entry") {
|
|
1530
|
+
throw new Error(`${path}.${key} is not an allowed field for ToolRef; permitted: kind, assetId, name, description, input_schema, entry`);
|
|
1531
|
+
}
|
|
1532
|
+
}
|
|
1533
|
+
if (raw.kind !== "asset") {
|
|
1534
|
+
throw new Error(`${path}.kind must be 'asset' (got ${JSON.stringify(raw.kind)})`);
|
|
1535
|
+
}
|
|
1536
|
+
const fields = parseAssetRefFields({ kind: raw.kind, assetId: raw.assetId, name: raw.name }, path);
|
|
1537
|
+
if (!TOOL_NAME_PATTERN.test(fields.name)) {
|
|
1538
|
+
throw new Error(`${path}.name must match ${TOOL_NAME_PATTERN.source}`);
|
|
1539
|
+
}
|
|
1540
|
+
if (fields.name.includes("__")) {
|
|
1541
|
+
throw new Error(`${path}.name must not contain "__"; that separator is reserved for MCP tools`);
|
|
1542
|
+
}
|
|
1543
|
+
if (seenNames.has(fields.name)) {
|
|
1544
|
+
throw new Error(`submission.tools duplicate name: ${fields.name}`);
|
|
1545
|
+
}
|
|
1546
|
+
seenNames.add(fields.name);
|
|
1547
|
+
if (seenAssetIds.has(fields.assetId)) {
|
|
1548
|
+
throw new Error(`submission.tools duplicate assetId: ${fields.assetId}`);
|
|
1549
|
+
}
|
|
1550
|
+
seenAssetIds.add(fields.assetId);
|
|
1551
|
+
const description = requireString(raw.description, `${path}.description`);
|
|
1552
|
+
if (description.trim().length === 0 || description.length > 2048) {
|
|
1553
|
+
throw new Error(`${path}.description must be non-empty and <= 2048 chars`);
|
|
1554
|
+
}
|
|
1555
|
+
const inputSchema = requireRecord(raw.input_schema, `${path}.input_schema`);
|
|
1556
|
+
if (!isJsonValue(inputSchema)) {
|
|
1557
|
+
throw new Error(`${path}.input_schema must be JSON-serializable`);
|
|
1558
|
+
}
|
|
1559
|
+
if (inputSchema.type !== "object") {
|
|
1560
|
+
throw new Error(`${path}.input_schema.type must be "object"`);
|
|
1561
|
+
}
|
|
1562
|
+
const entry = normaliseSkillBundlePath(requireString(raw.entry, `${path}.entry`));
|
|
1563
|
+
return {
|
|
1564
|
+
kind: "asset",
|
|
1565
|
+
assetId: fields.assetId,
|
|
1566
|
+
name: fields.name,
|
|
1567
|
+
description,
|
|
1568
|
+
input_schema: inputSchema,
|
|
1569
|
+
entry
|
|
1570
|
+
};
|
|
1571
|
+
});
|
|
1572
|
+
}
|
|
1508
1573
|
function parseAgentsMd(input) {
|
|
1509
1574
|
if (input === undefined)
|
|
1510
1575
|
return [];
|