@capybara-hq/plugin-sdk 0.1.0-rc.2 → 0.1.0-rc.4
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 +1 -1
- package/agent-docs/agent-templates.md +47 -0
- package/agent-docs/concepts.md +58 -0
- package/agent-docs/connector-templates.md +47 -0
- package/agent-docs/extension-points/channel.md +15 -0
- package/agent-docs/extension-points/config-source.md +15 -0
- package/agent-docs/extension-points/connector.md +15 -0
- package/agent-docs/extension-points/counter.md +15 -0
- package/agent-docs/extension-points/directory.md +15 -0
- package/agent-docs/extension-points/file-preview.md +15 -0
- package/agent-docs/extension-points/identity-source.md +15 -0
- package/agent-docs/extension-points/model-provider.md +15 -0
- package/agent-docs/extension-points/object-store.md +15 -0
- package/agent-docs/extension-points/sandbox.md +15 -0
- package/agent-docs/extension-points/secret-store.md +15 -0
- package/agent-docs/extension-points/web-fetch.md +15 -0
- package/agent-docs/extension-points/web-search.md +15 -0
- package/agent-docs/extensions.md +63 -0
- package/agent-docs/plugin-format.md +60 -0
- package/agent-docs/skills.md +44 -0
- package/agent-docs/tool-naming.md +21 -0
- package/dist/agent-template.d.ts +85 -0
- package/dist/agent-template.js +361 -2
- package/dist/config-ui.d.ts +2 -1
- package/dist/config-ui.js +25 -7
- package/dist/ctx.d.ts +65 -1
- package/dist/directory.d.ts +11 -2
- package/dist/extension-point.d.ts +4 -0
- package/dist/extension-point.js +16 -14
- package/dist/file-preview.d.ts +8 -0
- package/dist/hooks.d.ts +73 -14
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/marketplace.d.ts +29 -2
- package/dist/marketplace.js +30 -2
- package/dist/model.d.ts +60 -2
- package/dist/model.js +22 -0
- package/dist/org-access.d.ts +27 -0
- package/dist/org-access.js +35 -0
- package/dist/permissions.d.ts +4 -1
- package/dist/plugin-manifest.d.ts +15 -2
- package/dist/plugin-manifest.js +11 -1
- package/dist/sandbox.d.ts +140 -60
- package/dist/sandbox.js +30 -6
- package/dist/skill-invocation.d.ts +8 -5
- package/dist/skill-invocation.js +17 -8
- package/dist/skill.d.ts +20 -3
- package/dist/skill.js +28 -6
- package/dist/tool.d.ts +8 -0
- package/dist/ui.d.ts +8 -0
- package/dist/web.d.ts +30 -5
- package/package.json +4 -2
- package/schemas/marketplace.v1.schema.json +36 -0
- package/schemas/plugin.v1.schema.json +29 -4
package/dist/directory.d.ts
CHANGED
|
@@ -15,11 +15,20 @@ export interface Directory {
|
|
|
15
15
|
* treats the directory as "not configured": the hourly scan, `directory_changed` and the
|
|
16
16
|
* pre-removal recheck are skipped silently (no job, no audit, no warning), and a manual sync by an
|
|
17
17
|
* admin returns 409 `directory.not_configured`. When not implemented, any config that satisfies
|
|
18
|
-
* the schema counts as configured. Must be a pure function (no requests, never throws).
|
|
18
|
+
* the schema counts as configured. Must be a pure function (no requests, never throws). `config`
|
|
19
|
+
* is the effective deployment config for the org (see `listMembers`' `config`).
|
|
19
20
|
*/
|
|
20
|
-
configured?(orgConfig: unknown): boolean;
|
|
21
|
+
configured?(orgConfig: unknown, config?: unknown): boolean;
|
|
21
22
|
listMembers(args: {
|
|
22
23
|
orgConfig: unknown;
|
|
24
|
+
/**
|
|
25
|
+
* The extension's effective deployment config for this org: the platform's deployment config
|
|
26
|
+
* with the org's copy applied to the overridable fields (`orgAccess(…, "override")`), or the
|
|
27
|
+
* platform's config (equal to `ctx.config`) while the org follows it. Use it, not `ctx.config`,
|
|
28
|
+
* for work done for this org. Optional in the type so older extensions compile; the kernel
|
|
29
|
+
* always passes it.
|
|
30
|
+
*/
|
|
31
|
+
config?: unknown;
|
|
23
32
|
cursor?: string;
|
|
24
33
|
signal: AbortSignal;
|
|
25
34
|
}): Promise<{
|
|
@@ -4,11 +4,15 @@ export type ExtensionPointRef = `${string}@${number}`;
|
|
|
4
4
|
export type Cardinality = "single" | "multi";
|
|
5
5
|
/** Registry entry of an extension point. */
|
|
6
6
|
export interface ExtensionPointInfo {
|
|
7
|
+
/** What the extension point is for, in one sentence (served to agents by the Platform tool). */
|
|
8
|
+
description: string;
|
|
7
9
|
cardinality: Cardinality;
|
|
8
10
|
/** Brokered by the platform API (extensions may not `requires` it; they use it only through `ctx`). */
|
|
9
11
|
brokered: boolean;
|
|
10
12
|
/** Enabled per org (consumers may pass `orgId` to check that the org enabled the provider). */
|
|
11
13
|
orgScoped: boolean;
|
|
14
|
+
/** The majors of this point the kernel accepts; a plugin providing any other major is refused. */
|
|
15
|
+
majors: readonly number[];
|
|
12
16
|
/**
|
|
13
17
|
* How the kernel picks one provider among several: `org-default` means each org chooses its
|
|
14
18
|
* default provider (absent: no selection, every enabled provider is used).
|
package/dist/extension-point.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
const info = (cardinality, brokered = false, orgScoped = false, selection) => ({
|
|
1
|
+
const info = (majors, description, cardinality, brokered = false, orgScoped = false, selection) => ({
|
|
2
|
+
majors,
|
|
3
|
+
description,
|
|
2
4
|
cardinality,
|
|
3
5
|
brokered,
|
|
4
6
|
orgScoped,
|
|
@@ -6,19 +8,19 @@ const info = (cardinality, brokered = false, orgScoped = false, selection) => ({
|
|
|
6
8
|
});
|
|
7
9
|
/** The registered extension points. */
|
|
8
10
|
export const EXTENSION_POINTS = {
|
|
9
|
-
sandbox: info("single", true),
|
|
10
|
-
"config-source": info("single"),
|
|
11
|
-
"secret-store": info("single", true),
|
|
12
|
-
"object-store": info("single", true),
|
|
13
|
-
channel: info("multi", false, true),
|
|
14
|
-
"model-provider": info("multi", true),
|
|
15
|
-
"identity-source": info("multi"),
|
|
16
|
-
directory: info("multi", false, true),
|
|
17
|
-
counter: info("multi"),
|
|
18
|
-
connector: info("multi", true),
|
|
19
|
-
"file-preview": info("multi", false, true),
|
|
20
|
-
"web-search": info("multi", true, true, "org-default"),
|
|
21
|
-
"web-fetch": info("multi", true, true, "org-default"),
|
|
11
|
+
sandbox: info([2], "Runs an environment's instance and keeps its files for agents' commands (Docker, E2B).", "single", true),
|
|
12
|
+
"config-source": info([1], "Supplies deployment configuration from an external store such as Nacos.", "single"),
|
|
13
|
+
"secret-store": info([1], "Stores and resolves secrets (connector credentials, secret config) outside the database.", "single", true),
|
|
14
|
+
"object-store": info([1], "Stores files and artifacts in S3-compatible object storage, with presigned uploads.", "single", true),
|
|
15
|
+
channel: info([1], "Connects an instant-messaging platform (Slack, Lark): inbound events, replies and cards.", "multi", false, true),
|
|
16
|
+
"model-provider": info([1, 2], "Calls a model vendor's API and streams the result back to the runtime.", "multi", true),
|
|
17
|
+
"identity-source": info([1], "Signs people in through an external identity provider (SSO).", "multi"),
|
|
18
|
+
directory: info([1], "Syncs members and departments from an external company directory.", "multi", false, true),
|
|
19
|
+
counter: info([1], "Counts usage so quotas and reports can be built on it.", "multi"),
|
|
20
|
+
connector: info([1], "Speaks one protocol (MCP, OpenAPI) to external systems and exposes their tools to agents.", "multi", true),
|
|
21
|
+
"file-preview": info([1], "Renders previews of files of given types in the conversation UI.", "multi", false, true),
|
|
22
|
+
"web-search": info([1], "Searches the web for the WebSearch tool; each org picks a default provider.", "multi", true, true, "org-default"),
|
|
23
|
+
"web-fetch": info([1], "Fetches and extracts web pages for the WebFetch tool; each org picks a default provider.", "multi", true, true, "org-default"),
|
|
22
24
|
};
|
|
23
25
|
/** Cardinality of the registered extension points (derived from EXTENSION_POINTS). */
|
|
24
26
|
export const EXTENSION_POINT_CARDINALITY = Object.fromEntries(Object.entries(EXTENSION_POINTS).map(([k, v]) => [k, v.cardinality]));
|
package/dist/file-preview.d.ts
CHANGED
|
@@ -53,6 +53,14 @@ export interface FilePreviewArgs {
|
|
|
53
53
|
* rejects a file over the previewer's `maxBytes`. The extension never gets a storage key or URL.
|
|
54
54
|
*/
|
|
55
55
|
read(): Promise<Uint8Array>;
|
|
56
|
+
/**
|
|
57
|
+
* The extension's effective deployment config for this org: the platform's deployment config
|
|
58
|
+
* with the org's copy applied to the overridable fields (`orgAccess(…, "override")`), or the
|
|
59
|
+
* platform's config (equal to `ctx.config`) while the org follows it. Use it, not `ctx.config`,
|
|
60
|
+
* for work done for this org. Optional in the type so older extensions compile; the kernel
|
|
61
|
+
* always passes it.
|
|
62
|
+
*/
|
|
63
|
+
config?: unknown;
|
|
56
64
|
}
|
|
57
65
|
/** Checks a `file-preview@1` provider; returns the problems (empty = valid). */
|
|
58
66
|
export declare function validateFilePreviewProvider(p: unknown): string[];
|
package/dist/hooks.d.ts
CHANGED
|
@@ -39,8 +39,12 @@ export interface HookScope {
|
|
|
39
39
|
* `WebFetch` tool.
|
|
40
40
|
*/
|
|
41
41
|
export type ModelCallPurpose = "step" | "compaction" | "title" | "web_fetch";
|
|
42
|
-
/**
|
|
43
|
-
|
|
42
|
+
/**
|
|
43
|
+
* What a reported or requested model call was for: the {@link ModelCallPurpose} values, or
|
|
44
|
+
* `embedding` for an embedding call an extension made through `ctx.models` (`usage.report`, and
|
|
45
|
+
* `model.request` with {@link EmbeddingRequestHookPayload}; never `model.response`).
|
|
46
|
+
*/
|
|
47
|
+
export type UsagePurpose = ModelCallPurpose | "embedding";
|
|
44
48
|
/**
|
|
45
49
|
* An image or document of a `model.request` payload. Hook payloads never carry media bytes or
|
|
46
50
|
* attachment ids: each image or document block is replaced by this placeholder.
|
|
@@ -74,14 +78,15 @@ export type HookModelRequest = Omit<ModelRequest, "messages"> & {
|
|
|
74
78
|
messages: HookModelMessage[];
|
|
75
79
|
};
|
|
76
80
|
/**
|
|
77
|
-
* `model.request
|
|
78
|
-
* step (`purpose: "step"`), once for each compaction call (`purpose: "compaction"`, `attempt` 1)
|
|
81
|
+
* `model.request` of a chat model call (see {@link ModelRequestHookPayload}): once per attempt of a
|
|
82
|
+
* step (`purpose: "step"`), once for each compaction call (`purpose: "compaction"`, `attempt` 1),
|
|
79
83
|
* once for each conversation title call (`purpose: "title"`, `runId` "", `step` 0, `attempt` 1; a
|
|
80
|
-
* denial skips the title and is recorded only in the audit log)
|
|
84
|
+
* denial skips the title and is recorded only in the audit log) and once for each `WebFetch`
|
|
85
|
+
* extraction call (`purpose: "web_fetch"`).
|
|
81
86
|
* `request` is the request as sent, except that images and documents are placeholders
|
|
82
87
|
* ({@link HookMediaPlaceholder}): no media bytes, no attachment ids.
|
|
83
88
|
*/
|
|
84
|
-
export interface
|
|
89
|
+
export interface ModelCallRequestHookPayload extends HookScope {
|
|
85
90
|
purpose: ModelCallPurpose;
|
|
86
91
|
step: number;
|
|
87
92
|
attempt: number;
|
|
@@ -89,6 +94,45 @@ export interface ModelRequestHookPayload extends HookScope {
|
|
|
89
94
|
model: string;
|
|
90
95
|
request: Readonly<HookModelRequest>;
|
|
91
96
|
}
|
|
97
|
+
/**
|
|
98
|
+
* `model.request` of an embedding call an extension made through `ctx.models.embed`
|
|
99
|
+
* (`purpose: "embedding"`): fired once per `embed` call, before the first batch is sent, with every
|
|
100
|
+
* text of the call (the kernel splits them into batches afterwards). A call with no input sends
|
|
101
|
+
* nothing and fires nothing. There is no conversation: the conversation fields of a chat model call
|
|
102
|
+
* (`accountId`, `agentId`, `agentVersion`, `conversationId`, `runId`, `parent`, `step`, `attempt`,
|
|
103
|
+
* `request`) are absent. A policy denial makes `embed` reject (`model.hook_denied`); nothing is sent
|
|
104
|
+
* to the provider and no usage is recorded.
|
|
105
|
+
*/
|
|
106
|
+
export interface EmbeddingRequestHookPayload {
|
|
107
|
+
purpose: "embedding";
|
|
108
|
+
orgId: string;
|
|
109
|
+
/** The extension that called `ctx.models.embed`. */
|
|
110
|
+
extension: string;
|
|
111
|
+
/** The embedding purpose the extension called with (one it declared in `permissions.models`). */
|
|
112
|
+
embeddingPurpose: string;
|
|
113
|
+
provider: string;
|
|
114
|
+
model: string;
|
|
115
|
+
/** The texts of the call, in order (text only). */
|
|
116
|
+
input: readonly string[];
|
|
117
|
+
/** The dimensions the extension asked for, when it asked. */
|
|
118
|
+
dimensions?: number;
|
|
119
|
+
/** The input type the extension gave, when it gave one. */
|
|
120
|
+
inputType?: "query" | "document";
|
|
121
|
+
accountId?: undefined;
|
|
122
|
+
agentId?: undefined;
|
|
123
|
+
agentVersion?: undefined;
|
|
124
|
+
conversationId?: undefined;
|
|
125
|
+
runId?: undefined;
|
|
126
|
+
parent?: undefined;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* `model.request`: before a model call is sent. A policy hook may deny it. Either a chat model call
|
|
130
|
+
* ({@link ModelCallRequestHookPayload}: steps, compaction, titles, `WebFetch`) or an extension's
|
|
131
|
+
* embedding call ({@link EmbeddingRequestHookPayload}, `purpose: "embedding"`); tell them apart by
|
|
132
|
+
* `purpose`. Handlers must accept the absent conversation fields of an embedding call (a policy
|
|
133
|
+
* hook that throws on one denies the call). Payloads carry no media bytes.
|
|
134
|
+
*/
|
|
135
|
+
export type ModelRequestHookPayload = ModelCallRequestHookPayload | EmbeddingRequestHookPayload;
|
|
92
136
|
/**
|
|
93
137
|
* `model.response`: after a sent model call finished or failed, with its usage when known (step
|
|
94
138
|
* attempts, compaction and title calls, see `purpose`). Not fired for a call the user aborted (the run was
|
|
@@ -138,12 +182,18 @@ export interface UsageReportPayload {
|
|
|
138
182
|
*/
|
|
139
183
|
purpose: UsagePurpose;
|
|
140
184
|
orgId: string;
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
185
|
+
/** Absent for `embedding`. */
|
|
186
|
+
accountId?: string;
|
|
187
|
+
/** Absent for `embedding`. */
|
|
188
|
+
agentId?: string;
|
|
189
|
+
/** Absent for `embedding`. */
|
|
190
|
+
conversationId?: string;
|
|
191
|
+
/** A sub-agent's calls report `chat`; `parent` tells them apart. Absent for `embedding`. */
|
|
192
|
+
conversationKind?: "chat" | "eval";
|
|
193
|
+
/** Absent for `embedding`. */
|
|
194
|
+
runId?: string;
|
|
195
|
+
/** The calling extension; set for `embedding`. */
|
|
196
|
+
extension?: string;
|
|
147
197
|
/** Set when the call belongs to a sub-agent: where it was dispatched from. */
|
|
148
198
|
parent?: HookParentScope;
|
|
149
199
|
provider: string;
|
|
@@ -169,9 +219,18 @@ export type HookVerdict = void | {
|
|
|
169
219
|
};
|
|
170
220
|
/**
|
|
171
221
|
* A hook handler. The payload is a deep-frozen copy (mutating it throws). `signal` aborts when the
|
|
172
|
-
* hook runs past `hooks.timeoutMs` or the call it observes is aborted.
|
|
222
|
+
* hook runs past `hooks.timeoutMs` or the call it observes is aborted. `call.config` is the
|
|
223
|
+
* extension's effective deployment config for the payload's org (the platform's config with the
|
|
224
|
+
* org's copy applied to the overridable fields, or `ctx.config` while the org follows it); the
|
|
225
|
+
* kernel always passes it, and never calls a hook for an org where that config is not valid
|
|
226
|
+
* (observe hooks are skipped, policy hooks deny).
|
|
173
227
|
*/
|
|
174
|
-
export type HookHandler<K extends AvailableHook> = (payload: HookPayloads[K], signal: AbortSignal) => Promise<HookVerdict> | HookVerdict;
|
|
228
|
+
export type HookHandler<K extends AvailableHook> = (payload: HookPayloads[K], signal: AbortSignal, call?: HookCall) => Promise<HookVerdict> | HookVerdict;
|
|
229
|
+
/** The per-call context of a hook handler (see {@link HookHandler}). */
|
|
230
|
+
export interface HookCall {
|
|
231
|
+
/** The extension's effective deployment config for the payload's org. */
|
|
232
|
+
config: unknown;
|
|
233
|
+
}
|
|
175
234
|
/**
|
|
176
235
|
* - `policy` (only on {@link POLICY_HOOKS}): policy hooks run serially by plugin name (registration
|
|
177
236
|
* order within a plugin) before the call; the first `{ deny }`, error or timeout blocks the call and
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const SDK_VERSION = "0.1.0-rc.
|
|
1
|
+
export declare const SDK_VERSION = "0.1.0-rc.4";
|
|
2
2
|
export * from "./agent-template.js";
|
|
3
3
|
export * from "./bootstrap.js";
|
|
4
4
|
export * from "./cards.js";
|
|
@@ -16,6 +16,7 @@ export * from "./identity.js";
|
|
|
16
16
|
export * from "./marketplace.js";
|
|
17
17
|
export * from "./model.js";
|
|
18
18
|
export * from "./model-params.js";
|
|
19
|
+
export * from "./org-access.js";
|
|
19
20
|
export * from "./permissions.js";
|
|
20
21
|
export * from "./plugin-manifest.js";
|
|
21
22
|
export * from "./plugin-package.js";
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const SDK_VERSION = "0.1.0-rc.
|
|
1
|
+
export const SDK_VERSION = "0.1.0-rc.4";
|
|
2
2
|
export * from "./agent-template.js";
|
|
3
3
|
export * from "./bootstrap.js";
|
|
4
4
|
export * from "./cards.js";
|
|
@@ -16,6 +16,7 @@ export * from "./identity.js";
|
|
|
16
16
|
export * from "./marketplace.js";
|
|
17
17
|
export * from "./model.js";
|
|
18
18
|
export * from "./model-params.js";
|
|
19
|
+
export * from "./org-access.js";
|
|
19
20
|
export * from "./permissions.js";
|
|
20
21
|
export * from "./plugin-manifest.js";
|
|
21
22
|
export * from "./plugin-package.js";
|
package/dist/marketplace.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
/**
|
|
3
3
|
* The marketplace manifest `marketplace.json` (package ecosystem spec §5.2): a list of plugins,
|
|
4
|
-
* each with one source. One entry is one version
|
|
5
|
-
*
|
|
4
|
+
* each with one source. One entry is one version. `capybara-plugin marketplace --write` lists one
|
|
5
|
+
* entry per plugin, its current version (plugin component management spec §13.2); readers still
|
|
6
|
+
* accept several versions of a plugin (marketplaces written in the older form), so
|
|
7
|
+
* `(name, marketplaceEntryVersion)` is unique in a manifest.
|
|
6
8
|
*
|
|
7
9
|
* Sources: a same-repo `path`, a `git` repo, an `npm` package (exact version + sha512, downloads
|
|
8
10
|
* are verified against it, never npm metadata) or an `archive` URL (sha512 or sha256 SRI).
|
|
@@ -19,6 +21,10 @@ export declare const MARKETPLACE_MANIFEST_SCHEMA_VERSION = 1;
|
|
|
19
21
|
export declare const MARKETPLACE_LIMITS: {
|
|
20
22
|
readonly nameChars: 100;
|
|
21
23
|
readonly summaryChars: 280;
|
|
24
|
+
/** Characters of each `displayName` language (as `plugin.json`'s). */
|
|
25
|
+
readonly displayNameChars: 100;
|
|
26
|
+
/** Characters of a `deprecated.reason`. */
|
|
27
|
+
readonly deprecationReasonChars: 280;
|
|
22
28
|
readonly plugins: 5000;
|
|
23
29
|
readonly permissionKeys: 500;
|
|
24
30
|
readonly urlChars: 2000;
|
|
@@ -53,6 +59,11 @@ export interface MarketplaceEntry {
|
|
|
53
59
|
en: string;
|
|
54
60
|
zh?: string;
|
|
55
61
|
};
|
|
62
|
+
/** Display name (the plugin's `plugin.json` `displayName`); lists show it, else the name. */
|
|
63
|
+
displayName?: {
|
|
64
|
+
zh: string;
|
|
65
|
+
en: string;
|
|
66
|
+
};
|
|
56
67
|
/** Exact semver; defaults to the npm source's version, otherwise the plugin's own. */
|
|
57
68
|
version?: string;
|
|
58
69
|
/** Exact semver. */
|
|
@@ -64,6 +75,15 @@ export interface MarketplaceEntry {
|
|
|
64
75
|
};
|
|
65
76
|
/** https URL. */
|
|
66
77
|
homepage?: string;
|
|
78
|
+
/**
|
|
79
|
+
* This version is deprecated (`true`, or with a reason shown to admins): browsing lists it under
|
|
80
|
+
* the plugin's other versions, never as the one to import, and the kernel refuses importing it
|
|
81
|
+
* (`marketplace.entry_deprecated`). Set by hand on the entry by the marketplace maintainer;
|
|
82
|
+
* `capybara-plugin marketplace --write` keeps it. `false` is the same as absent.
|
|
83
|
+
*/
|
|
84
|
+
deprecated?: boolean | {
|
|
85
|
+
reason?: string;
|
|
86
|
+
};
|
|
67
87
|
source: MarketplaceSource;
|
|
68
88
|
}
|
|
69
89
|
/** `marketplace.json`. */
|
|
@@ -97,3 +117,10 @@ export declare function parseMarketplaceManifest(json: unknown, opts?: Marketpla
|
|
|
97
117
|
};
|
|
98
118
|
/** The entry's version: `version`, else the npm source's version, else `null` (the plugin's own). */
|
|
99
119
|
export declare function marketplaceEntryVersion(e: MarketplaceEntry): string | null;
|
|
120
|
+
/**
|
|
121
|
+
* The entry's deprecation (see {@link MarketplaceEntry.deprecated}): `null` when it is not
|
|
122
|
+
* deprecated (absent or `false`), else its reason (`null` without one).
|
|
123
|
+
*/
|
|
124
|
+
export declare function marketplaceEntryDeprecation(e: MarketplaceEntry): {
|
|
125
|
+
reason: string | null;
|
|
126
|
+
} | null;
|
package/dist/marketplace.js
CHANGED
|
@@ -2,8 +2,10 @@ import { z } from "zod";
|
|
|
2
2
|
import { CATALOG_ITEM_NAME_RE, isSafePackagePath, NPM_PACKAGE_NAME_RE, SEMVER_VERSION_RE, SHA512_INTEGRITY_RE, } from "./plugin-package.js";
|
|
3
3
|
/**
|
|
4
4
|
* The marketplace manifest `marketplace.json` (package ecosystem spec §5.2): a list of plugins,
|
|
5
|
-
* each with one source. One entry is one version
|
|
6
|
-
*
|
|
5
|
+
* each with one source. One entry is one version. `capybara-plugin marketplace --write` lists one
|
|
6
|
+
* entry per plugin, its current version (plugin component management spec §13.2); readers still
|
|
7
|
+
* accept several versions of a plugin (marketplaces written in the older form), so
|
|
8
|
+
* `(name, marketplaceEntryVersion)` is unique in a manifest.
|
|
7
9
|
*
|
|
8
10
|
* Sources: a same-repo `path`, a `git` repo, an `npm` package (exact version + sha512, downloads
|
|
9
11
|
* are verified against it, never npm metadata) or an `archive` URL (sha512 or sha256 SRI).
|
|
@@ -20,6 +22,10 @@ export const MARKETPLACE_MANIFEST_SCHEMA_VERSION = 1;
|
|
|
20
22
|
export const MARKETPLACE_LIMITS = {
|
|
21
23
|
nameChars: 100,
|
|
22
24
|
summaryChars: 280,
|
|
25
|
+
/** Characters of each `displayName` language (as `plugin.json`'s). */
|
|
26
|
+
displayNameChars: 100,
|
|
27
|
+
/** Characters of a `deprecated.reason`. */
|
|
28
|
+
deprecationReasonChars: 280,
|
|
23
29
|
plugins: 5000,
|
|
24
30
|
permissionKeys: 500,
|
|
25
31
|
urlChars: 2000,
|
|
@@ -123,6 +129,12 @@ function buildSchema(opts) {
|
|
|
123
129
|
en: z.string().min(1).max(M.summaryChars),
|
|
124
130
|
zh: z.string().min(1).max(M.summaryChars).optional(),
|
|
125
131
|
}),
|
|
132
|
+
displayName: z
|
|
133
|
+
.object({
|
|
134
|
+
zh: z.string().min(1).max(M.displayNameChars),
|
|
135
|
+
en: z.string().min(1).max(M.displayNameChars),
|
|
136
|
+
})
|
|
137
|
+
.optional(),
|
|
126
138
|
version: exactVersion("version").optional(),
|
|
127
139
|
minKernel: exactVersion("minKernel").optional(),
|
|
128
140
|
permissions: z
|
|
@@ -132,6 +144,12 @@ function buildSchema(opts) {
|
|
|
132
144
|
})
|
|
133
145
|
.optional(),
|
|
134
146
|
homepage: urlString(HTTPS_URL_RE).optional(),
|
|
147
|
+
deprecated: z
|
|
148
|
+
.union([
|
|
149
|
+
z.boolean(),
|
|
150
|
+
z.object({ reason: z.string().min(1).max(M.deprecationReasonChars).optional() }),
|
|
151
|
+
])
|
|
152
|
+
.optional(),
|
|
135
153
|
source,
|
|
136
154
|
});
|
|
137
155
|
return z
|
|
@@ -254,3 +272,13 @@ export function marketplaceEntryVersion(e) {
|
|
|
254
272
|
return e.source.npm.version;
|
|
255
273
|
return null;
|
|
256
274
|
}
|
|
275
|
+
/**
|
|
276
|
+
* The entry's deprecation (see {@link MarketplaceEntry.deprecated}): `null` when it is not
|
|
277
|
+
* deprecated (absent or `false`), else its reason (`null` without one).
|
|
278
|
+
*/
|
|
279
|
+
export function marketplaceEntryDeprecation(e) {
|
|
280
|
+
const d = e.deprecated;
|
|
281
|
+
if (d === undefined || d === false)
|
|
282
|
+
return null;
|
|
283
|
+
return { reason: d === true ? null : (d.reason ?? null) };
|
|
284
|
+
}
|
package/dist/model.d.ts
CHANGED
|
@@ -4,9 +4,32 @@
|
|
|
4
4
|
* 见 `model-params.ts`);旧契约 `model-provider@1`(`ModelProviderV1` 等)由内核经适配层继续支持。
|
|
5
5
|
*/
|
|
6
6
|
import type { Effort, ModelParameter, ParamValue } from "./model-params.js";
|
|
7
|
+
import type { LocalizedName } from "./plugin-package.js";
|
|
8
|
+
/** What a model does. Absent on a `ModelInfo` means `chat`. */
|
|
9
|
+
export type ModelKind = "chat" | "embedding" | "rerank" | "image_generation" | "video_generation" | "speech_to_text" | "text_to_speech";
|
|
10
|
+
/** Embedding facts of a model whose `kind` is `embedding`. */
|
|
11
|
+
export interface ModelEmbeddingInfo {
|
|
12
|
+
/** The output dimensions the model can produce (a single entry when not adjustable). */
|
|
13
|
+
dimensions: number[];
|
|
14
|
+
defaultDimensions: number;
|
|
15
|
+
/** Most tokens one input may hold. */
|
|
16
|
+
maxInputTokens: number;
|
|
17
|
+
/** Most inputs one `embed` call may carry. */
|
|
18
|
+
maxBatch: number;
|
|
19
|
+
}
|
|
7
20
|
export interface ModelInfo {
|
|
8
21
|
id: string;
|
|
9
22
|
displayName: string;
|
|
23
|
+
/** Defaults to `chat`. Chat-only fields below stay required for every kind. */
|
|
24
|
+
kind?: ModelKind;
|
|
25
|
+
/** Who made the model (display only). */
|
|
26
|
+
publisher?: string;
|
|
27
|
+
/** Display only. */
|
|
28
|
+
description?: LocalizedName | string;
|
|
29
|
+
/** ISO date after which the model is retired (display only). */
|
|
30
|
+
retiresAt?: string;
|
|
31
|
+
/** Set when `kind` is `embedding`. */
|
|
32
|
+
embedding?: ModelEmbeddingInfo;
|
|
10
33
|
contextWindow: number;
|
|
11
34
|
maxOutputTokens: number;
|
|
12
35
|
capabilities: {
|
|
@@ -206,14 +229,49 @@ export declare class ModelError extends Error {
|
|
|
206
229
|
/** rate_limited / overloaded / server / timeout / network 为 true。 */
|
|
207
230
|
get retryable(): boolean;
|
|
208
231
|
}
|
|
232
|
+
/**
|
|
233
|
+
* Options of a model call made for an organization.
|
|
234
|
+
* `config` is the extension's effective deployment config for this org: the platform's deployment
|
|
235
|
+
* config with the org's copy applied to the overridable fields (`orgAccess(…, "override")`), or the
|
|
236
|
+
* platform's config (equal to `ctx.config`) while the org follows it. Use it, not `ctx.config`, for
|
|
237
|
+
* work done for this org. Optional in the type so older providers compile; the kernel always passes
|
|
238
|
+
* both.
|
|
239
|
+
*/
|
|
240
|
+
export interface ModelCallOptions {
|
|
241
|
+
orgId?: string;
|
|
242
|
+
config?: unknown;
|
|
243
|
+
}
|
|
244
|
+
export interface EmbedRequest {
|
|
245
|
+
model: string;
|
|
246
|
+
input: string[];
|
|
247
|
+
/** One of the model's `embedding.dimensions`; the model's default when absent. */
|
|
248
|
+
dimensions?: number;
|
|
249
|
+
inputType?: "query" | "document";
|
|
250
|
+
}
|
|
251
|
+
export interface EmbedResult {
|
|
252
|
+
/** One vector per input, in input order. */
|
|
253
|
+
vectors: number[][];
|
|
254
|
+
usage: {
|
|
255
|
+
inputTokens: number;
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Checks an embedding result against its request and the model's embedding facts. Returns null when
|
|
260
|
+
* valid, else the reason: wrong vector count, wrong dimension, or a non-finite number.
|
|
261
|
+
*/
|
|
262
|
+
export declare function validateEmbedResult(req: EmbedRequest, info: ModelEmbeddingInfo, res: EmbedResult): string | null;
|
|
209
263
|
/** `model-provider@2` 的实现。 */
|
|
210
264
|
export interface ModelProvider {
|
|
211
265
|
/** 每个模型的 `parameters` 须通过 `assertValidDeclarations`,否则内核不使用该供应商。 */
|
|
212
|
-
listModels(): Promise<ModelInfo[]>;
|
|
266
|
+
listModels(opts?: ModelCallOptions): Promise<ModelInfo[]>;
|
|
213
267
|
/** 事件序列必须以且仅以一个 message_complete 结束;出错抛 ModelError。 */
|
|
214
268
|
stream(req: ModelRequest, opts: {
|
|
215
269
|
signal: AbortSignal;
|
|
216
|
-
}): AsyncIterable<ModelStreamEvent>;
|
|
270
|
+
} & ModelCallOptions): AsyncIterable<ModelStreamEvent>;
|
|
271
|
+
/** Present only on a provider that lists `embedding` models. */
|
|
272
|
+
embed?(req: EmbedRequest, opts: {
|
|
273
|
+
signal: AbortSignal;
|
|
274
|
+
} & ModelCallOptions): Promise<EmbedResult>;
|
|
217
275
|
}
|
|
218
276
|
/** `model-provider@1` 的实现(旧契约,内核经适配层接入:effort 由 `capabilities.effort` 推导)。 */
|
|
219
277
|
export interface ModelProviderV1 {
|
package/dist/model.js
CHANGED
|
@@ -148,5 +148,27 @@ export class ModelError extends Error {
|
|
|
148
148
|
return isRetryableKind(this.kind);
|
|
149
149
|
}
|
|
150
150
|
}
|
|
151
|
+
/**
|
|
152
|
+
* Checks an embedding result against its request and the model's embedding facts. Returns null when
|
|
153
|
+
* valid, else the reason: wrong vector count, wrong dimension, or a non-finite number.
|
|
154
|
+
*/
|
|
155
|
+
export function validateEmbedResult(req, info, res) {
|
|
156
|
+
if (res.vectors.length !== req.input.length) {
|
|
157
|
+
return `vector count ${res.vectors.length} does not match input count ${req.input.length}`;
|
|
158
|
+
}
|
|
159
|
+
const dims = req.dimensions ?? info.defaultDimensions;
|
|
160
|
+
for (let i = 0; i < res.vectors.length; i++) {
|
|
161
|
+
const v = res.vectors[i];
|
|
162
|
+
if (v.length !== dims) {
|
|
163
|
+
return `vector ${i} has dimension ${v.length}, expected ${dims}`;
|
|
164
|
+
}
|
|
165
|
+
for (const x of v) {
|
|
166
|
+
if (typeof x !== "number" || !Number.isFinite(x)) {
|
|
167
|
+
return `vector ${i} holds a non-finite number`;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
151
173
|
export const MODEL_PROVIDER_EXTENSION_POINT = "model-provider@1";
|
|
152
174
|
export const MODEL_PROVIDER_EXTENSION_POINT_V2 = "model-provider@2";
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* How an org may treat a deployment config field: `readonly` (the org sees it, never sets it) or
|
|
4
|
+
* `override` (an org may set its own value). A field without a level is deployment-only.
|
|
5
|
+
*/
|
|
6
|
+
export type OrgAccess = "readonly" | "override";
|
|
7
|
+
/**
|
|
8
|
+
* Marks a deployment config field with an org access level (Zod 4 meta `{ org: access }`), merging
|
|
9
|
+
* with existing meta (`secret`, `hot`, `ui`), so `orgAccess(secret(x), …)` and
|
|
10
|
+
* `secret(orgAccess(x, …))` are the same. `configJsonSchema` publishes it as `"x-org"`.
|
|
11
|
+
*
|
|
12
|
+
* The author's promise for `override`: the extension reads the field from the per-call `config`
|
|
13
|
+
* the kernel passes with each request, not from `ctx.config`, and the field may be absent from
|
|
14
|
+
* `ctx.config` (the deployment value is the default, which an org may replace per call).
|
|
15
|
+
*
|
|
16
|
+
* The per-call config of an org that has its own copy still contains the platform's hidden
|
|
17
|
+
* (platform-only) secrets, which an org cannot set; it never contains an overridable platform
|
|
18
|
+
* secret. Never send a hidden secret to an endpoint taken from an overridable field: an org could
|
|
19
|
+
* point that endpoint at a server it controls.
|
|
20
|
+
*/
|
|
21
|
+
export declare function orgAccess<T extends z.ZodTypeAny>(schema: T, access: OrgAccess): T;
|
|
22
|
+
/**
|
|
23
|
+
* The org access level of a schema's meta, or undefined when it has none. It sees through
|
|
24
|
+
* `.optional()`, `.default()`, `.nullable()`, `.prefault()`, `.catch()` and `.readonly()` (the
|
|
25
|
+
* outermost level wins), so it agrees with the `"x-org"` that `configJsonSchema` publishes.
|
|
26
|
+
*/
|
|
27
|
+
export declare function orgAccessOf(schema: z.ZodTypeAny): OrgAccess | undefined;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Marks a deployment config field with an org access level (Zod 4 meta `{ org: access }`), merging
|
|
3
|
+
* with existing meta (`secret`, `hot`, `ui`), so `orgAccess(secret(x), …)` and
|
|
4
|
+
* `secret(orgAccess(x, …))` are the same. `configJsonSchema` publishes it as `"x-org"`.
|
|
5
|
+
*
|
|
6
|
+
* The author's promise for `override`: the extension reads the field from the per-call `config`
|
|
7
|
+
* the kernel passes with each request, not from `ctx.config`, and the field may be absent from
|
|
8
|
+
* `ctx.config` (the deployment value is the default, which an org may replace per call).
|
|
9
|
+
*
|
|
10
|
+
* The per-call config of an org that has its own copy still contains the platform's hidden
|
|
11
|
+
* (platform-only) secrets, which an org cannot set; it never contains an overridable platform
|
|
12
|
+
* secret. Never send a hidden secret to an endpoint taken from an overridable field: an org could
|
|
13
|
+
* point that endpoint at a server it controls.
|
|
14
|
+
*/
|
|
15
|
+
export function orgAccess(schema, access) {
|
|
16
|
+
return schema.meta({ ...(schema.meta() ?? {}), org: access });
|
|
17
|
+
}
|
|
18
|
+
/** The wrappers a field's org level is read through, as `configJsonSchema` inherits meta. */
|
|
19
|
+
const WRAPPERS = new Set(["default", "prefault", "optional", "nullable", "readonly", "catch"]);
|
|
20
|
+
/**
|
|
21
|
+
* The org access level of a schema's meta, or undefined when it has none. It sees through
|
|
22
|
+
* `.optional()`, `.default()`, `.nullable()`, `.prefault()`, `.catch()` and `.readonly()` (the
|
|
23
|
+
* outermost level wins), so it agrees with the `"x-org"` that `configJsonSchema` publishes.
|
|
24
|
+
*/
|
|
25
|
+
export function orgAccessOf(schema) {
|
|
26
|
+
let node = schema;
|
|
27
|
+
while (node) {
|
|
28
|
+
const v = node.meta()?.org;
|
|
29
|
+
if (v === "readonly" || v === "override")
|
|
30
|
+
return v;
|
|
31
|
+
const def = node._zod.def;
|
|
32
|
+
node = WRAPPERS.has(def.type) ? def.innerType : undefined;
|
|
33
|
+
}
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
package/dist/permissions.d.ts
CHANGED
|
@@ -22,7 +22,10 @@ export interface ExtensionPermissions {
|
|
|
22
22
|
* on a replica, calls on these mount points fail closed there.
|
|
23
23
|
*/
|
|
24
24
|
policyHooks?: PolicyHook[];
|
|
25
|
-
/**
|
|
25
|
+
/**
|
|
26
|
+
* Model purposes (`ctx.models`): each key must be `<extension name>.<name>`; an org admin maps
|
|
27
|
+
* each to a model of its `kind`. `ctx.models.embed` / `describe` accept the `embedding` ones.
|
|
28
|
+
*/
|
|
26
29
|
models?: {
|
|
27
30
|
purpose: string;
|
|
28
31
|
kind: "chat" | "embedding";
|
|
@@ -85,6 +85,19 @@ export interface PluginExtensionSection {
|
|
|
85
85
|
org?: JsonSchema;
|
|
86
86
|
};
|
|
87
87
|
}
|
|
88
|
+
/**
|
|
89
|
+
* A plugin's description: a string (English) or `{ en, zh? }`, each ≤ 1024 characters. Read it
|
|
90
|
+
* through {@link pluginDescription}.
|
|
91
|
+
*/
|
|
92
|
+
export type PluginDescription = string | {
|
|
93
|
+
en: string;
|
|
94
|
+
zh?: string;
|
|
95
|
+
};
|
|
96
|
+
/** A plugin description as `{ en, zh? }` (a plain string is the English text). */
|
|
97
|
+
export declare function pluginDescription(d: PluginDescription): {
|
|
98
|
+
en: string;
|
|
99
|
+
zh?: string;
|
|
100
|
+
};
|
|
88
101
|
/** `.capybara-plugin/plugin.json`. */
|
|
89
102
|
export interface PluginManifest {
|
|
90
103
|
$schema?: string;
|
|
@@ -94,8 +107,8 @@ export interface PluginManifest {
|
|
|
94
107
|
/** Exact semver version. */
|
|
95
108
|
version: string;
|
|
96
109
|
publisher: string;
|
|
97
|
-
/** ≤ 1024 characters. */
|
|
98
|
-
description:
|
|
110
|
+
/** A string (English) or `{ en, zh? }`, each ≤ 1024 characters; see {@link pluginDescription}. */
|
|
111
|
+
description: PluginDescription;
|
|
99
112
|
displayName?: LocalizedName;
|
|
100
113
|
/** `./…` .svg / .png inside the plugin. */
|
|
101
114
|
icon?: string;
|
package/dist/plugin-manifest.js
CHANGED
|
@@ -48,6 +48,10 @@ export const PLUGIN_MANIFEST_LIMITS = {
|
|
|
48
48
|
displayNameChars: 100,
|
|
49
49
|
pathChars: 512,
|
|
50
50
|
};
|
|
51
|
+
/** A plugin description as `{ en, zh? }` (a plain string is the English text). */
|
|
52
|
+
export function pluginDescription(d) {
|
|
53
|
+
return typeof d === "string" ? { en: d } : { en: d.en, ...(d.zh !== undefined && { zh: d.zh }) };
|
|
54
|
+
}
|
|
51
55
|
const L = PLUGIN_MANIFEST_LIMITS;
|
|
52
56
|
const MAX_ERRORS = 50;
|
|
53
57
|
const ICON_RE = /\.(?:svg|png)$/i;
|
|
@@ -116,7 +120,13 @@ const schema = z
|
|
|
116
120
|
.max(256)
|
|
117
121
|
.regex(SEMVER_VERSION_RE, { message: "version must be an exact semver version" }),
|
|
118
122
|
publisher: text(L.publisherChars, "publisher"),
|
|
119
|
-
description:
|
|
123
|
+
description: z.union([
|
|
124
|
+
text(L.descriptionChars, "description"),
|
|
125
|
+
z.strictObject({
|
|
126
|
+
en: text(L.descriptionChars, "description.en"),
|
|
127
|
+
zh: text(L.descriptionChars, "description.zh").optional(),
|
|
128
|
+
}),
|
|
129
|
+
]),
|
|
120
130
|
displayName: localized.optional(),
|
|
121
131
|
icon: dotPath("icon")
|
|
122
132
|
.regex(ICON_RE, { message: "icon must be a .svg or .png file" })
|