antpath 0.6.2 → 0.8.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/dist/_shared/blueprint.d.ts +66 -7
- package/dist/_shared/blueprint.js +53 -8
- package/dist/_shared/operations.d.ts +52 -0
- package/dist/_shared/operations.js +83 -0
- package/dist/_shared/proxy-protocol.d.ts +10 -2
- package/dist/_shared/proxy-protocol.js +3 -2
- package/dist/_shared/runtime-types.d.ts +19 -0
- package/dist/_shared/submission.d.ts +21 -0
- package/dist/_shared/submission.js +102 -4
- package/dist/blueprint.d.ts +15 -6
- package/dist/blueprint.js.map +1 -1
- package/dist/bundle.d.ts +16 -1
- package/dist/bundle.js +32 -0
- package/dist/bundle.js.map +1 -1
- package/dist/cli.mjs +169 -38
- package/dist/cli.mjs.sha256 +1 -1
- package/dist/client.d.ts +119 -24
- package/dist/client.js +198 -52
- package/dist/client.js.map +1 -1
- package/dist/index.d.ts +8 -6
- package/dist/index.js +5 -4
- package/dist/index.js.map +1 -1
- package/dist/proxy-endpoint.d.ts +131 -0
- package/dist/proxy-endpoint.js +147 -0
- package/dist/proxy-endpoint.js.map +1 -0
- package/dist/skill.d.ts +203 -31
- package/dist/skill.js +277 -30
- package/dist/skill.js.map +1 -1
- package/docs/credentials.md +34 -0
- package/docs/events.md +7 -0
- package/docs/mcp.md +28 -0
- package/docs/outputs.md +92 -12
- package/docs/quickstart.md +37 -0
- package/docs/skills.md +49 -0
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAQlE,yBAAyB;AACzB,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAQlE,yBAAyB;AACzB,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAQpD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAGhE,SAAS;AACT,OAAO,EACL,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,yBAAyB,EACzB,aAAa,EACb,aAAa,EACd,MAAM,iBAAiB,CAAC;AAEzB,yBAAyB;AACzB,OAAO,EACL,uBAAuB,EACvB,mBAAmB,EACnB,0BAA0B,EAC1B,yBAAyB,EACzB,wBAAwB,EACxB,wBAAwB,EACxB,2BAA2B,EAC3B,iBAAiB,EAClB,MAAM,iBAAiB,CAAC;AA2CzB,oBAAoB;AACpB,OAAO,EACL,oBAAoB,EACpB,YAAY,EACZ,oBAAoB,EACpB,iBAAiB,EACjB,cAAc,EACd,eAAe,EACf,iBAAiB,EACjB,cAAc,EACd,cAAc,EACd,cAAc,EACd,mBAAmB,EACnB,0BAA0B,EAC1B,sBAAsB,EACtB,yBAAyB,EACzB,WAAW,EACX,WAAW,EACX,aAAa,EACd,MAAM,iBAAiB,CAAC;AAEzB,mBAAmB;AACnB,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { type PlatformProxyAuthValue, type PlatformProxyEndpoint, type PlatformProxyEndpointAuth, type ProxyMethod, type ProxyResponseMode } from "./_shared/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Constructor-only surface for declaring a per-run HTTP proxy endpoint.
|
|
4
|
+
*
|
|
5
|
+
* Why a class rather than a raw object literal: the raw
|
|
6
|
+
* `PlatformProxyEndpoint` + `PlatformProxyEndpointAuth` shape lets the
|
|
7
|
+
* caller assemble two halves of one logical thing (the auth shape and
|
|
8
|
+
* the auth value), and they often drift — agents writing freeform
|
|
9
|
+
* objects regularly hit runtime rejections with `responseMode: "json"`
|
|
10
|
+
* (real values are `status_only | headers_only | full`) or
|
|
11
|
+
* `authShape: { type: "header", header: "X-Api-Key" }` (real field is
|
|
12
|
+
* `name`). The constructor signatures here put the auth secret on the
|
|
13
|
+
* same call as the shape, so any drift becomes a TypeScript error at
|
|
14
|
+
* the call site, not an HTTP 400 a round-trip later.
|
|
15
|
+
*
|
|
16
|
+
* Wire-format unchanged: the SDK splits each `ProxyEndpoint` instance
|
|
17
|
+
* into a `PlatformProxyEndpoint` (the non-secret declaration) plus a
|
|
18
|
+
* `PlatformProxyEndpointAuth` entry (the per-request secret) at
|
|
19
|
+
* `submitRun` time, exactly the way `McpServer` already splits
|
|
20
|
+
* `headers` into `secrets.mcpServers`.
|
|
21
|
+
*
|
|
22
|
+
* Five named constructors:
|
|
23
|
+
*
|
|
24
|
+
* - `ProxyEndpoint.none ({ name, baseUrl, ... })` — keyless upstream
|
|
25
|
+
* - `ProxyEndpoint.bearer({ name, baseUrl, token, ... })`
|
|
26
|
+
* - `ProxyEndpoint.header({ name, baseUrl, header, value, ... })`
|
|
27
|
+
* - `ProxyEndpoint.basic ({ name, baseUrl, username, password, ... })`
|
|
28
|
+
* - `ProxyEndpoint.query ({ name, baseUrl, query, value, ... })`
|
|
29
|
+
*
|
|
30
|
+
* All five share the same allow-list / response-mode / cap parameters.
|
|
31
|
+
* The four authenticated variants split into `secrets.proxyEndpointAuth[].value`
|
|
32
|
+
* at submit time; `none` produces only a declaration (no secret).
|
|
33
|
+
*/
|
|
34
|
+
export interface ProxyEndpointCommonOptions {
|
|
35
|
+
/**
|
|
36
|
+
* Endpoint name. Lowercase letters, digits, `_`, `-`, up to 63
|
|
37
|
+
* chars. Matches the BFF's `PROXY_ENDPOINT_NAME_PATTERN`. Used as
|
|
38
|
+
* the path segment in `/api/runs/:runId/proxy/:name` and as the
|
|
39
|
+
* cross-reference key in `secrets.proxyEndpointAuth`.
|
|
40
|
+
*/
|
|
41
|
+
readonly name: string;
|
|
42
|
+
/** Upstream base URL. Must be an absolute `https://` URL. */
|
|
43
|
+
readonly baseUrl: string;
|
|
44
|
+
/** HTTP methods the in-container caller is allowed to use. */
|
|
45
|
+
readonly allowMethods: readonly ProxyMethod[];
|
|
46
|
+
/** Path prefixes the in-container caller is allowed to hit. */
|
|
47
|
+
readonly allowPathPrefixes: readonly string[];
|
|
48
|
+
/**
|
|
49
|
+
* Caller-supplied headers permitted to pass through the proxy. The
|
|
50
|
+
* auth header (Bearer/Basic/custom-name) is enforced by the proxy
|
|
51
|
+
* itself and MUST NOT appear here.
|
|
52
|
+
*/
|
|
53
|
+
readonly allowHeaders?: readonly string[];
|
|
54
|
+
/** Default narrowest response disclosure mode. */
|
|
55
|
+
readonly responseMode?: ProxyResponseMode;
|
|
56
|
+
readonly maxRequestBytes?: number;
|
|
57
|
+
readonly maxResponseBytes?: number;
|
|
58
|
+
readonly timeoutMs?: number;
|
|
59
|
+
readonly perCallBudget?: number;
|
|
60
|
+
readonly responseByteBudget?: number;
|
|
61
|
+
}
|
|
62
|
+
export interface BearerProxyEndpointOptions extends ProxyEndpointCommonOptions {
|
|
63
|
+
/** Bearer token sent as `Authorization: Bearer <token>`. */
|
|
64
|
+
readonly token: string;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Options for `ProxyEndpoint.none` — keyless upstream. Same shape as
|
|
68
|
+
* `ProxyEndpointCommonOptions`; declared as an empty extension so the
|
|
69
|
+
* call site reads symmetrically with the other constructors and stays
|
|
70
|
+
* a stable extension point if a future field becomes auth-shape-only.
|
|
71
|
+
*/
|
|
72
|
+
export interface NoneProxyEndpointOptions extends ProxyEndpointCommonOptions {
|
|
73
|
+
}
|
|
74
|
+
export interface BasicProxyEndpointOptions extends ProxyEndpointCommonOptions {
|
|
75
|
+
readonly username: string;
|
|
76
|
+
readonly password: string;
|
|
77
|
+
}
|
|
78
|
+
export interface HeaderProxyEndpointOptions extends ProxyEndpointCommonOptions {
|
|
79
|
+
/** Header name the upstream expects the auth value in. */
|
|
80
|
+
readonly header: string;
|
|
81
|
+
/** Header value (the actual secret). */
|
|
82
|
+
readonly value: string;
|
|
83
|
+
}
|
|
84
|
+
export interface QueryProxyEndpointOptions extends ProxyEndpointCommonOptions {
|
|
85
|
+
/** Query parameter name the upstream expects the auth value in. */
|
|
86
|
+
readonly query: string;
|
|
87
|
+
/** Query parameter value (the actual secret). */
|
|
88
|
+
readonly value: string;
|
|
89
|
+
}
|
|
90
|
+
export declare class ProxyEndpoint {
|
|
91
|
+
/** Non-secret half of the wire shape — declaration only. */
|
|
92
|
+
readonly declaration: PlatformProxyEndpoint;
|
|
93
|
+
/**
|
|
94
|
+
* Per-request secret half — auth value keyed by the same `name`.
|
|
95
|
+
* `null` for keyless (`ProxyEndpoint.none`) endpoints; `splitProxyEndpoints`
|
|
96
|
+
* filters those out so they never land in `secrets.proxyEndpointAuth`.
|
|
97
|
+
*/
|
|
98
|
+
readonly auth: PlatformProxyEndpointAuth | null;
|
|
99
|
+
private constructor();
|
|
100
|
+
/**
|
|
101
|
+
* Keyless endpoint. Routes through the antpath managed proxy for
|
|
102
|
+
* unified egress, audit, and budget enforcement, but the BFF injects
|
|
103
|
+
* no auth header or query parameter. Use for public APIs (Wikimedia
|
|
104
|
+
* Commons, NASA Images, Library of Congress, NARA, GDELT, etc.).
|
|
105
|
+
*/
|
|
106
|
+
static none(options: NoneProxyEndpointOptions): ProxyEndpoint;
|
|
107
|
+
/** Bearer-token endpoint. */
|
|
108
|
+
static bearer(options: BearerProxyEndpointOptions): ProxyEndpoint;
|
|
109
|
+
/** Basic-auth endpoint. */
|
|
110
|
+
static basic(options: BasicProxyEndpointOptions): ProxyEndpoint;
|
|
111
|
+
/** Custom-header endpoint. */
|
|
112
|
+
static header(options: HeaderProxyEndpointOptions): ProxyEndpoint;
|
|
113
|
+
/** Query-string-auth endpoint. */
|
|
114
|
+
static query(options: QueryProxyEndpointOptions): ProxyEndpoint;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Split a list of `ProxyEndpoint` instances into the public declarations
|
|
118
|
+
* (`proxyEndpoints[]`) and the per-request auth bundle
|
|
119
|
+
* (`secrets.proxyEndpointAuth[]`). Mirrors the way `submitRun` already
|
|
120
|
+
* splits `McpServer.headers` into `secrets.mcpServers[]`.
|
|
121
|
+
*
|
|
122
|
+
* Throws on duplicate endpoint names — names are the cross-reference
|
|
123
|
+
* key between the two halves and the BFF rejects collisions; failing
|
|
124
|
+
* here gives the caller a precise message at the call site instead of
|
|
125
|
+
* an opaque HTTP error.
|
|
126
|
+
*/
|
|
127
|
+
export declare function splitProxyEndpoints(inputs: readonly ProxyEndpoint[]): {
|
|
128
|
+
endpoints: readonly PlatformProxyEndpoint[];
|
|
129
|
+
auth: readonly PlatformProxyEndpointAuth[];
|
|
130
|
+
};
|
|
131
|
+
export type { PlatformProxyAuthValue as ProxyAuthValue };
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { authShapeHeaderName, PROXY_RESPONSE_MODES } from "./_shared/index.js";
|
|
2
|
+
export class ProxyEndpoint {
|
|
3
|
+
/** Non-secret half of the wire shape — declaration only. */
|
|
4
|
+
declaration;
|
|
5
|
+
/**
|
|
6
|
+
* Per-request secret half — auth value keyed by the same `name`.
|
|
7
|
+
* `null` for keyless (`ProxyEndpoint.none`) endpoints; `splitProxyEndpoints`
|
|
8
|
+
* filters those out so they never land in `secrets.proxyEndpointAuth`.
|
|
9
|
+
*/
|
|
10
|
+
auth;
|
|
11
|
+
constructor(declaration, auth) {
|
|
12
|
+
this.declaration = declaration;
|
|
13
|
+
this.auth = auth;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Keyless endpoint. Routes through the antpath managed proxy for
|
|
17
|
+
* unified egress, audit, and budget enforcement, but the BFF injects
|
|
18
|
+
* no auth header or query parameter. Use for public APIs (Wikimedia
|
|
19
|
+
* Commons, NASA Images, Library of Congress, NARA, GDELT, etc.).
|
|
20
|
+
*/
|
|
21
|
+
static none(options) {
|
|
22
|
+
const common = buildCommonDeclaration(options, { type: "none" });
|
|
23
|
+
return new ProxyEndpoint(common, null);
|
|
24
|
+
}
|
|
25
|
+
/** Bearer-token endpoint. */
|
|
26
|
+
static bearer(options) {
|
|
27
|
+
const common = buildCommonDeclaration(options, { type: "bearer" });
|
|
28
|
+
requireNonEmpty(options.token, "ProxyEndpoint.bearer: token is required");
|
|
29
|
+
return new ProxyEndpoint(common, {
|
|
30
|
+
name: common.name,
|
|
31
|
+
value: { type: "bearer", token: options.token }
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
/** Basic-auth endpoint. */
|
|
35
|
+
static basic(options) {
|
|
36
|
+
const common = buildCommonDeclaration(options, { type: "basic" });
|
|
37
|
+
requireNonEmpty(options.username, "ProxyEndpoint.basic: username is required");
|
|
38
|
+
requireNonEmpty(options.password, "ProxyEndpoint.basic: password is required");
|
|
39
|
+
return new ProxyEndpoint(common, {
|
|
40
|
+
name: common.name,
|
|
41
|
+
value: { type: "basic", username: options.username, password: options.password }
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
/** Custom-header endpoint. */
|
|
45
|
+
static header(options) {
|
|
46
|
+
requireNonEmpty(options.header, "ProxyEndpoint.header: header is required");
|
|
47
|
+
const common = buildCommonDeclaration(options, { type: "header", name: options.header });
|
|
48
|
+
requireNonEmpty(options.value, "ProxyEndpoint.header: value is required");
|
|
49
|
+
return new ProxyEndpoint(common, {
|
|
50
|
+
name: common.name,
|
|
51
|
+
value: { type: "header", value: options.value }
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
/** Query-string-auth endpoint. */
|
|
55
|
+
static query(options) {
|
|
56
|
+
requireNonEmpty(options.query, "ProxyEndpoint.query: query is required");
|
|
57
|
+
const common = buildCommonDeclaration(options, { type: "query", name: options.query });
|
|
58
|
+
requireNonEmpty(options.value, "ProxyEndpoint.query: value is required");
|
|
59
|
+
return new ProxyEndpoint(common, {
|
|
60
|
+
name: common.name,
|
|
61
|
+
value: { type: "query", value: options.value }
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Split a list of `ProxyEndpoint` instances into the public declarations
|
|
67
|
+
* (`proxyEndpoints[]`) and the per-request auth bundle
|
|
68
|
+
* (`secrets.proxyEndpointAuth[]`). Mirrors the way `submitRun` already
|
|
69
|
+
* splits `McpServer.headers` into `secrets.mcpServers[]`.
|
|
70
|
+
*
|
|
71
|
+
* Throws on duplicate endpoint names — names are the cross-reference
|
|
72
|
+
* key between the two halves and the BFF rejects collisions; failing
|
|
73
|
+
* here gives the caller a precise message at the call site instead of
|
|
74
|
+
* an opaque HTTP error.
|
|
75
|
+
*/
|
|
76
|
+
export function splitProxyEndpoints(inputs) {
|
|
77
|
+
if (inputs.length === 0) {
|
|
78
|
+
return { endpoints: [], auth: [] };
|
|
79
|
+
}
|
|
80
|
+
const endpoints = [];
|
|
81
|
+
const auth = [];
|
|
82
|
+
const seen = new Set();
|
|
83
|
+
for (let i = 0; i < inputs.length; i++) {
|
|
84
|
+
const entry = inputs[i];
|
|
85
|
+
if (!(entry instanceof ProxyEndpoint)) {
|
|
86
|
+
throw new TypeError(`proxyEndpoints[${i}] must be a ProxyEndpoint built via ProxyEndpoint.none / bearer / header / basic / query`);
|
|
87
|
+
}
|
|
88
|
+
if (seen.has(entry.declaration.name)) {
|
|
89
|
+
throw new Error(`proxyEndpoints duplicate name: ${entry.declaration.name}`);
|
|
90
|
+
}
|
|
91
|
+
seen.add(entry.declaration.name);
|
|
92
|
+
endpoints.push(entry.declaration);
|
|
93
|
+
if (entry.auth !== null) {
|
|
94
|
+
auth.push(entry.auth);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return { endpoints, auth };
|
|
98
|
+
}
|
|
99
|
+
function buildCommonDeclaration(options, authShape) {
|
|
100
|
+
requireNonEmpty(options.name, "ProxyEndpoint: name is required");
|
|
101
|
+
requireNonEmpty(options.baseUrl, "ProxyEndpoint: baseUrl is required");
|
|
102
|
+
if (!Array.isArray(options.allowMethods) || options.allowMethods.length === 0) {
|
|
103
|
+
throw new Error("ProxyEndpoint: allowMethods must be a non-empty array");
|
|
104
|
+
}
|
|
105
|
+
if (!Array.isArray(options.allowPathPrefixes) || options.allowPathPrefixes.length === 0) {
|
|
106
|
+
throw new Error("ProxyEndpoint: allowPathPrefixes must be a non-empty array");
|
|
107
|
+
}
|
|
108
|
+
if (options.responseMode !== undefined && !PROXY_RESPONSE_MODES.includes(options.responseMode)) {
|
|
109
|
+
throw new Error(`ProxyEndpoint: responseMode must be one of ${PROXY_RESPONSE_MODES.join(" | ")}`);
|
|
110
|
+
}
|
|
111
|
+
// Defence in depth: don't let the caller list the auth carrier
|
|
112
|
+
// header in `allowHeaders`. The BFF rejects this too, but a precise
|
|
113
|
+
// SDK-side error message is clearer.
|
|
114
|
+
if (options.allowHeaders) {
|
|
115
|
+
const carrier = authShapeHeaderName(authShape);
|
|
116
|
+
if (carrier) {
|
|
117
|
+
for (const h of options.allowHeaders) {
|
|
118
|
+
if (h.toLowerCase() === carrier) {
|
|
119
|
+
throw new Error(`ProxyEndpoint: allowHeaders MUST NOT include the auth header "${h}" — ` +
|
|
120
|
+
`it's set by the proxy on every request`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return {
|
|
126
|
+
name: options.name,
|
|
127
|
+
baseUrl: options.baseUrl,
|
|
128
|
+
authShape,
|
|
129
|
+
allowMethods: options.allowMethods,
|
|
130
|
+
allowPathPrefixes: options.allowPathPrefixes,
|
|
131
|
+
...(options.allowHeaders ? { allowHeaders: options.allowHeaders } : {}),
|
|
132
|
+
...(options.responseMode ? { responseMode: options.responseMode } : {}),
|
|
133
|
+
...(options.maxRequestBytes !== undefined ? { maxRequestBytes: options.maxRequestBytes } : {}),
|
|
134
|
+
...(options.maxResponseBytes !== undefined ? { maxResponseBytes: options.maxResponseBytes } : {}),
|
|
135
|
+
...(options.timeoutMs !== undefined ? { timeoutMs: options.timeoutMs } : {}),
|
|
136
|
+
...(options.perCallBudget !== undefined ? { perCallBudget: options.perCallBudget } : {}),
|
|
137
|
+
...(options.responseByteBudget !== undefined
|
|
138
|
+
? { responseByteBudget: options.responseByteBudget }
|
|
139
|
+
: {})
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
function requireNonEmpty(value, message) {
|
|
143
|
+
if (typeof value !== "string" || !value) {
|
|
144
|
+
throw new Error(message);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=proxy-endpoint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy-endpoint.js","sourceRoot":"","sources":["../src/proxy-endpoint.ts"],"names":[],"mappings":"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"}
|
package/dist/skill.d.ts
CHANGED
|
@@ -1,40 +1,80 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type ProviderSkillRef, type Skill as SkillRecord, type SkillRef } from "./_shared/index.js";
|
|
2
|
+
import { type SkillFiles } from "./bundle.js";
|
|
2
3
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* -
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
4
|
+
* One `Skill` class, one mental model, three usage modes:
|
|
5
|
+
*
|
|
6
|
+
* - **Workspace** — uploaded to the antpath platform and reused across
|
|
7
|
+
* runs.
|
|
8
|
+
* ```ts
|
|
9
|
+
* const persisted = await Skill.fromFiles({ name, files }).upload(client);
|
|
10
|
+
* // or
|
|
11
|
+
* const ref = Skill.fromId("skl_abc123");
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* - **Provider built-in** — references a provider-side skill (e.g.
|
|
15
|
+
* Anthropic web-search). Not uploaded to your workspace.
|
|
16
|
+
* ```ts
|
|
17
|
+
* const websearch = Skill.provider({ vendor: "anthropic", skillId: "web-search" });
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* - **Transient (per-run)** — built from local files, never persisted.
|
|
21
|
+
* The bytes ride alongside `submitRun` as a multipart part and the
|
|
22
|
+
* BFF tears them down at run terminal.
|
|
23
|
+
* ```ts
|
|
24
|
+
* const rules = await Skill.fromFiles({ name: "rules", files: {...} });
|
|
25
|
+
* await client.submitRun({ skills: [rules], ... });
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* ## Lifecycle of an unstaged transient Skill
|
|
29
|
+
*
|
|
30
|
+
* After `Skill.fromFiles(...)` returns, the Skill is "unstaged transient":
|
|
31
|
+
*
|
|
32
|
+
* 1. Passing it to `submitRun` uploads the bytes for that one run only
|
|
33
|
+
* and assigns a positional slot id (`transient-0`, `transient-1`, …).
|
|
34
|
+
* The same instance may be passed to multiple `submitRun` calls
|
|
35
|
+
* until it is consumed by `.upload(...)`.
|
|
36
|
+
*
|
|
37
|
+
* 2. Calling `await skill.upload(client)` persists the bundle to the
|
|
38
|
+
* workspace skill store and returns a **new** `Skill` instance
|
|
39
|
+
* whose `.ref.kind === "workspace"`. The **original** is marked
|
|
40
|
+
* **consumed**:
|
|
41
|
+
* - any further use in `submitRun` throws a clear validation error,
|
|
42
|
+
* - `.upload(...)` on the consumed instance throws,
|
|
43
|
+
* - `JSON.stringify` / `toJSON()` on the consumed instance throws.
|
|
44
|
+
*
|
|
45
|
+
* Use the returned (workspace) Skill from then on. The consumed
|
|
46
|
+
* reference exists only to surface the mistake loudly the first
|
|
47
|
+
* time the user re-uses it; it never silently re-uploads as
|
|
48
|
+
* transient.
|
|
49
|
+
*
|
|
50
|
+
* Unstaged transient Skills do NOT round-trip through JSON (the bytes
|
|
51
|
+
* cannot be serialised back). `toJSON()` throws in that state too —
|
|
52
|
+
* persist via `.upload(client)` first, or pass the unstaged Skill
|
|
53
|
+
* directly to `submitRun`.
|
|
54
|
+
*
|
|
55
|
+
* The Skill class is the only public way to build a transient bundle;
|
|
56
|
+
* the SDK never accepts a raw `TransientSkillRef` object from user code.
|
|
27
57
|
*/
|
|
28
58
|
export declare class Skill {
|
|
59
|
+
#private;
|
|
29
60
|
/** Workspace skill record returned by the BFF (only set for workspace-uploaded skills). */
|
|
30
61
|
readonly record: SkillRecord | undefined;
|
|
31
|
-
readonly ref: SkillRef;
|
|
32
62
|
/**
|
|
33
|
-
* Internal constructor. Use `Skill.fromId`, `Skill.provider`,
|
|
34
|
-
* `
|
|
35
|
-
|
|
63
|
+
* Internal constructor. Use `Skill.fromId`, `Skill.provider`,
|
|
64
|
+
* `Skill.fromFiles`, or `Skill.fromPath` to create instances.
|
|
65
|
+
*/
|
|
66
|
+
constructor(ref: SkillRef, record?: SkillRecord, transientBytes?: Uint8Array);
|
|
67
|
+
/**
|
|
68
|
+
* The wire-level reference. For workspace and provider skills this is
|
|
69
|
+
* stable. For unstaged transient skills it carries the placeholder
|
|
70
|
+
* `slot: "(unstaged)"` — `submitRun` rewrites the slot to a real
|
|
71
|
+
* positional id (`transient-0`, …) before sending.
|
|
72
|
+
*
|
|
73
|
+
* For consumed Skills, the getter still returns the original
|
|
74
|
+
* transient ref so error messages can be precise — but using a
|
|
75
|
+
* consumed Skill in any submit/serialise path throws.
|
|
36
76
|
*/
|
|
37
|
-
|
|
77
|
+
get ref(): SkillRef;
|
|
38
78
|
/**
|
|
39
79
|
* Reference an existing workspace skill by its id (e.g. `skl_abc123`).
|
|
40
80
|
* Does NOT validate the skill exists — that check happens on the next
|
|
@@ -52,8 +92,140 @@ export declare class Skill {
|
|
|
52
92
|
readonly skillId: string;
|
|
53
93
|
readonly version?: string;
|
|
54
94
|
}): Skill;
|
|
55
|
-
/**
|
|
95
|
+
/**
|
|
96
|
+
* Build an unstaged transient Skill from an inline files map. The SDK
|
|
97
|
+
* validates basic safety (no path traversal, size caps, has
|
|
98
|
+
* `SKILL.md`), deterministically zips the bundle, and computes the
|
|
99
|
+
* `sha256:<hex>` content hash that travels in the wire ref.
|
|
100
|
+
*
|
|
101
|
+
* The returned Skill carries the bytes privately. Pass it to
|
|
102
|
+
* `submitRun` for transient (per-run) use, or call `.upload(client)`
|
|
103
|
+
* to persist it as a workspace skill.
|
|
104
|
+
*/
|
|
105
|
+
static fromFiles(args: {
|
|
106
|
+
readonly name: string;
|
|
107
|
+
readonly files: SkillFiles;
|
|
108
|
+
}): Promise<Skill>;
|
|
109
|
+
/**
|
|
110
|
+
* Read a local directory and build an unstaged transient Skill.
|
|
111
|
+
* Symlinks and non-regular files are skipped. Node-only.
|
|
112
|
+
*
|
|
113
|
+
* The returned Skill behaves identically to one built via
|
|
114
|
+
* `Skill.fromFiles` — pass it to `submitRun` for transient use, or
|
|
115
|
+
* call `.upload(client)` to persist as a workspace skill.
|
|
116
|
+
*/
|
|
117
|
+
static fromPath(rootDir: string, args: {
|
|
118
|
+
readonly name: string;
|
|
119
|
+
}): Promise<Skill>;
|
|
120
|
+
/**
|
|
121
|
+
* Persist this unstaged transient Skill as a workspace skill and
|
|
122
|
+
* return a new `Skill` instance backed by the resulting `skl_*`
|
|
123
|
+
* record. After `upload` resolves successfully, the original
|
|
124
|
+
* instance is marked **consumed** — any further use throws a clear
|
|
125
|
+
* validation error.
|
|
126
|
+
*
|
|
127
|
+
* Only unstaged transient Skills can be uploaded. Calling this on a
|
|
128
|
+
* workspace-ref Skill, a provider-ref Skill, or a previously
|
|
129
|
+
* consumed Skill throws.
|
|
130
|
+
*
|
|
131
|
+
* Accepts either an `AntpathClient` (preferred) or its
|
|
132
|
+
* `SkillsClient` if the caller already has a handle to it.
|
|
133
|
+
*/
|
|
134
|
+
upload(client: SkillUploader): Promise<Skill>;
|
|
135
|
+
/**
|
|
136
|
+
* Persist this unstaged transient Skill as a workspace skill **only
|
|
137
|
+
* if** an existing skill with the same `(name, contentHash)` is not
|
|
138
|
+
* already live.
|
|
139
|
+
*
|
|
140
|
+
* Flow:
|
|
141
|
+
*
|
|
142
|
+
* 1. Hash is already known from `Skill.fromFiles` / `fromPath`.
|
|
143
|
+
* 2. Call `client.skills.findByHash({ name, contentHash })`. If a
|
|
144
|
+
* live row exists, mark this instance consumed and return a
|
|
145
|
+
* new `Skill` backed by that record.
|
|
146
|
+
* 3. Otherwise call `upload(client)`.
|
|
147
|
+
*
|
|
148
|
+
* Returns either the existing or newly-created workspace Skill;
|
|
149
|
+
* callers do not need to branch.
|
|
150
|
+
*
|
|
151
|
+
* Only unstaged transient Skills can be `uploadIfChanged`. Calling
|
|
152
|
+
* this on a workspace-ref Skill, a provider-ref Skill, or a
|
|
153
|
+
* previously consumed Skill throws.
|
|
154
|
+
*/
|
|
155
|
+
uploadIfChanged(client: SkillUploader & SkillLookup): Promise<Skill>;
|
|
156
|
+
/** True for `Skill.fromId(...)` and skills returned by `.upload(...)`. */
|
|
56
157
|
get isWorkspace(): boolean;
|
|
57
158
|
/** True for `Skill.provider(...)`. */
|
|
58
159
|
get isProvider(): boolean;
|
|
160
|
+
/** True for any transient Skill (unstaged or consumed). */
|
|
161
|
+
get isTransient(): boolean;
|
|
162
|
+
/**
|
|
163
|
+
* True only while the transient Skill still carries bytes and has
|
|
164
|
+
* not been consumed by `.upload(...)`. Unstaged Skills can be passed
|
|
165
|
+
* to `submitRun` or `.upload(client)`; consumed ones cannot.
|
|
166
|
+
*/
|
|
167
|
+
get isUnstaged(): boolean;
|
|
168
|
+
/** True after a successful `.upload(...)` — using this instance further throws. */
|
|
169
|
+
get isConsumed(): boolean;
|
|
170
|
+
/**
|
|
171
|
+
* Internal: yield the unstaged transient bundle's payload so the
|
|
172
|
+
* client's `submitRun` can build a multipart part. Returns undefined
|
|
173
|
+
* for non-transient or consumed skills. Throws if the instance is
|
|
174
|
+
* marked consumed (a stronger signal than "no bytes").
|
|
175
|
+
*
|
|
176
|
+
* NOT part of the public API — the `_` prefix is a "do not call from
|
|
177
|
+
* user code" marker. Callers within the SDK pass the returned bytes
|
|
178
|
+
* into the multipart body once per `submitRun` invocation.
|
|
179
|
+
*/
|
|
180
|
+
_takeUnstagedBundle(): {
|
|
181
|
+
name: string;
|
|
182
|
+
bytes: Uint8Array;
|
|
183
|
+
contentHash: string;
|
|
184
|
+
} | undefined;
|
|
185
|
+
/**
|
|
186
|
+
* JSON serialisation guard. Workspace and provider Skills serialise
|
|
187
|
+
* to their `ref`. Unstaged transient Skills throw — the bytes are not
|
|
188
|
+
* in the JSON, so a round-trip would silently drop them. Consumed
|
|
189
|
+
* Skills also throw, to surface the "you forgot to use the returned
|
|
190
|
+
* Skill from `.upload(...)`" mistake at the point it happens.
|
|
191
|
+
*/
|
|
192
|
+
toJSON(): SkillRef;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Anything that can persist a skill bundle. Both `AntpathClient` and
|
|
196
|
+
* the internal `SkillsClient` satisfy this shape — `Skill.upload`
|
|
197
|
+
* accepts either, but the SDK consumer only ever sees the
|
|
198
|
+
* `AntpathClient`-based path.
|
|
199
|
+
*/
|
|
200
|
+
export interface SkillUploader {
|
|
201
|
+
readonly _uploadSkillBundle?: (args: {
|
|
202
|
+
readonly name: string;
|
|
203
|
+
readonly body: Uint8Array;
|
|
204
|
+
}) => Promise<SkillRecord>;
|
|
205
|
+
readonly skills?: {
|
|
206
|
+
readonly _uploadSkillBundle?: (args: {
|
|
207
|
+
readonly name: string;
|
|
208
|
+
readonly body: Uint8Array;
|
|
209
|
+
}) => Promise<SkillRecord>;
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Anything that can look up an existing workspace skill by hash. Used
|
|
214
|
+
* by `Skill.uploadIfChanged` — both `AntpathClient` (via
|
|
215
|
+
* `.skills.findByHash`) and the internal `SkillsClient` satisfy this
|
|
216
|
+
* shape. The lookup is optional so test doubles for `upload` need not
|
|
217
|
+
* implement it; in that case `uploadIfChanged` simply falls back to
|
|
218
|
+
* a plain `upload`.
|
|
219
|
+
*/
|
|
220
|
+
export interface SkillLookup {
|
|
221
|
+
readonly skills?: {
|
|
222
|
+
readonly findByHash?: (args: {
|
|
223
|
+
readonly name: string;
|
|
224
|
+
readonly contentHash: string;
|
|
225
|
+
}) => Promise<SkillRecord | null>;
|
|
226
|
+
};
|
|
227
|
+
readonly findByHash?: (args: {
|
|
228
|
+
readonly name: string;
|
|
229
|
+
readonly contentHash: string;
|
|
230
|
+
}) => Promise<SkillRecord | null>;
|
|
59
231
|
}
|