@capybara-hq/plugin-sdk 0.0.0-stage → 0.1.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +2 -0
  3. package/README.md +27 -2
  4. package/dist/agent-template.d.ts +47 -0
  5. package/dist/agent-template.js +123 -0
  6. package/dist/bootstrap.d.ts +67 -0
  7. package/dist/bootstrap.js +109 -0
  8. package/dist/cards.d.ts +64 -0
  9. package/dist/cards.js +217 -0
  10. package/dist/channel.d.ts +230 -0
  11. package/dist/channel.js +26 -0
  12. package/dist/connector-auth.d.ts +64 -0
  13. package/dist/connector-auth.js +96 -0
  14. package/dist/connector.d.ts +154 -0
  15. package/dist/connector.js +1 -0
  16. package/dist/ctx.d.ts +176 -0
  17. package/dist/ctx.js +1 -0
  18. package/dist/define-extension.d.ts +41 -0
  19. package/dist/define-extension.js +85 -0
  20. package/dist/directory.d.ts +29 -0
  21. package/dist/directory.js +1 -0
  22. package/dist/extension-point.d.ts +29 -0
  23. package/dist/extension-point.js +36 -0
  24. package/dist/file-preview.d.ts +64 -0
  25. package/dist/file-preview.js +72 -0
  26. package/dist/frontmatter.d.ts +12 -0
  27. package/dist/frontmatter.js +36 -0
  28. package/dist/hooks.d.ts +195 -0
  29. package/dist/hooks.js +14 -0
  30. package/dist/identity.d.ts +44 -0
  31. package/dist/identity.js +1 -0
  32. package/dist/index.d.ts +28 -0
  33. package/dist/index.js +28 -0
  34. package/dist/marketplace.d.ts +99 -0
  35. package/dist/marketplace.js +256 -0
  36. package/dist/model-params.d.ts +82 -0
  37. package/dist/model-params.js +222 -0
  38. package/dist/model.d.ts +227 -0
  39. package/dist/model.js +152 -0
  40. package/dist/permissions.d.ts +67 -0
  41. package/dist/permissions.js +271 -0
  42. package/dist/plugin-manifest.d.ts +141 -0
  43. package/dist/plugin-manifest.js +322 -0
  44. package/dist/plugin-package.d.ts +139 -0
  45. package/dist/plugin-package.js +448 -0
  46. package/dist/sandbox.d.ts +152 -0
  47. package/dist/sandbox.js +96 -0
  48. package/dist/secret.d.ts +5 -0
  49. package/dist/secret.js +8 -0
  50. package/dist/semver-range.d.ts +6 -0
  51. package/dist/semver-range.js +12 -0
  52. package/dist/skill-invocation.d.ts +83 -0
  53. package/dist/skill-invocation.js +201 -0
  54. package/dist/skill-keys.d.ts +9 -0
  55. package/dist/skill-keys.js +16 -0
  56. package/dist/skill.d.ts +77 -0
  57. package/dist/skill.js +244 -0
  58. package/dist/storage.d.ts +96 -0
  59. package/dist/storage.js +9 -0
  60. package/dist/tool-key.d.ts +28 -0
  61. package/dist/tool-key.js +40 -0
  62. package/dist/tool.d.ts +154 -0
  63. package/dist/tool.js +218 -0
  64. package/dist/ui.d.ts +265 -0
  65. package/dist/ui.js +358 -0
  66. package/dist/url.d.ts +2 -0
  67. package/dist/url.js +12 -0
  68. package/package.json +40 -3
  69. package/schemas/bootstrap.v1.schema.json +125 -0
  70. package/schemas/connector-template.v1.schema.json +116 -0
  71. package/schemas/marketplace.v1.schema.json +270 -0
  72. package/schemas/plugin.v1.schema.json +330 -0
@@ -0,0 +1,227 @@
1
+ /**
2
+ * 与供应商无关的模型契约;原生协议留在各供应商插件内部。
3
+ * 当前契约为 `model-provider@2`(`ModelProvider` / `ModelInfo` / `ModelRequest`,参数由插件按模型声明,
4
+ * 见 `model-params.ts`);旧契约 `model-provider@1`(`ModelProviderV1` 等)由内核经适配层继续支持。
5
+ */
6
+ import type { Effort, ModelParameter, ParamValue } from "./model-params.js";
7
+ export interface ModelInfo {
8
+ id: string;
9
+ displayName: string;
10
+ contextWindow: number;
11
+ maxOutputTokens: number;
12
+ capabilities: {
13
+ tools: boolean;
14
+ vision: boolean;
15
+ reasoning: boolean;
16
+ caching: boolean;
17
+ midConversationSystem: boolean;
18
+ /**
19
+ * 是否接受 `document` 块(缺省为 false)。图片看 `vision`。模型不支持时内核把媒体块换成英文文字占位
20
+ * (如 `[Attached image "<name>" — this model cannot view images.]`;`text/*` 文档改为内联截断后的文本),
21
+ * 绝不把字节发给它。
22
+ */
23
+ documents?: boolean;
24
+ /**
25
+ * @deprecated `model-provider@1` 用:是否支持 `ModelRequestV1.effort`。`@2` 插件不填,改在
26
+ * `parameters` 中声明 `effort` 旋钮;内核的 `@1` 适配层据此推导 `parameters`。
27
+ */
28
+ effort?: boolean;
29
+ };
30
+ /** 流空闲看门狗阈值;推理类模型应更长。未给时内核用配置默认值。 */
31
+ streamIdleTimeoutMs?: number;
32
+ /** 该模型支持的参数(`@2` 必填,可为空数组;须通过 `assertValidDeclarations`)。 */
33
+ parameters: ModelParameter[];
34
+ }
35
+ /** `model-provider@1` 的模型信息:没有 `parameters`,effort 支持由 `capabilities.effort` 表示。 */
36
+ export type ModelInfoV1 = Omit<ModelInfo, "parameters" | "capabilities"> & {
37
+ capabilities: Omit<ModelInfo["capabilities"], "effort"> & {
38
+ effort: boolean;
39
+ };
40
+ };
41
+ /** 供应商私有数据:只回放给同一供应商(如 Anthropic 思考块签名、OpenAI 加密推理项)。 */
42
+ export interface ProviderOpaque {
43
+ provider: string;
44
+ model: string;
45
+ data: unknown;
46
+ }
47
+ /** 图片块接受的类型。 */
48
+ export declare const IMAGE_MEDIA_TYPES: readonly ["image/png", "image/jpeg", "image/gif", "image/webp"];
49
+ /** 文档块接受的类型。 */
50
+ export declare const DOCUMENT_MEDIA_TYPES: readonly ["application/pdf", "text/plain", "text/markdown", "text/csv"];
51
+ export type ImageMediaType = (typeof IMAGE_MEDIA_TYPES)[number];
52
+ export type DocumentMediaType = (typeof DOCUMENT_MEDIA_TYPES)[number];
53
+ /**
54
+ * 媒体内容的来源:`base64` 是字节本身,`ref` 是内核附件的引用。
55
+ * 事件日志里只存 `ref`(字节不进日志);内核构建请求时把 `ref` 解析成 `base64`,插件只会收到 `base64`。
56
+ */
57
+ export type MediaSource = {
58
+ kind: "base64";
59
+ data: string;
60
+ } | {
61
+ kind: "ref";
62
+ attachmentId: string;
63
+ };
64
+ /** 单个媒体块解码后的字节上限(按主流供应商的较小值取)。 */
65
+ export declare const MEDIA_LIMITS: {
66
+ readonly imageBytes: 5242880;
67
+ readonly documentBytes: 33554432;
68
+ };
69
+ export type ContentBlock =
70
+ /** text 的 opaque:供应商需要随文本回放的私有数据(如 OpenAI message 输出项的 id)。 */
71
+ {
72
+ type: "text";
73
+ text: string;
74
+ opaque?: ProviderOpaque;
75
+ } | {
76
+ type: "thinking";
77
+ text: string;
78
+ opaque?: ProviderOpaque;
79
+ } | {
80
+ type: "tool_call";
81
+ id: string;
82
+ name: string;
83
+ input: unknown;
84
+ opaque?: ProviderOpaque;
85
+ } | {
86
+ type: "tool_result";
87
+ callId: string;
88
+ content: string;
89
+ isError: boolean;
90
+ }
91
+ /**
92
+ * 图片(只出现在 user 消息里)。模型不支持 `vision` 时内核换成文字占位,插件不用把关;
93
+ * 不认识此块的旧插件会跳过它。
94
+ */
95
+ | {
96
+ type: "image";
97
+ mediaType: ImageMediaType;
98
+ source: MediaSource;
99
+ name?: string;
100
+ }
101
+ /** 文档(只出现在 user 消息里),由 `capabilities.documents` 把关,规则同 image。 */
102
+ | {
103
+ type: "document";
104
+ mediaType: DocumentMediaType;
105
+ source: MediaSource;
106
+ name?: string;
107
+ };
108
+ /** 媒体块 `name` 的最大长度(字符)。 */
109
+ export declare const MEDIA_NAME_MAX_CHARS = 255;
110
+ /** 供应商请求里文件名 / 标题的建议上限(码点),{@link clipMediaName} 的默认值。 */
111
+ export declare const PROVIDER_MEDIA_NAME_MAX = 200;
112
+ /**
113
+ * 把附件名截到 `max` 个码点以内(供应商映射用:有的接口对 filename / title 有长度限制,补后缀后还会更长)。
114
+ * 尽量保留扩展名(不超过 16 个字符的 `.ext`),中间用 `…` 表示截掉的部分。纯函数。
115
+ */
116
+ export declare function clipMediaName(name: string, max?: number): string;
117
+ /** 是否含控制字符(C0、DEL 与 C1)。 */
118
+ export declare function hasControlChars(s: string): boolean;
119
+ /** 附件 id 是否为 UUID(任意版本,大小写不限)。 */
120
+ export declare function isAttachmentId(s: unknown): s is string;
121
+ /**
122
+ * 校验一个 image / document 块,返回错误列表(空表示合法):类型在列表里;`base64` 是标准、带填充、
123
+ * 不含空白的 base64,解码后不超过 {@link MEDIA_LIMITS};`ref` 的 `attachmentId` 是 UUID;`name` 若有须是字符串、
124
+ * 不超过 {@link MEDIA_NAME_MAX_CHARS} 个字符且不含控制字符。
125
+ */
126
+ export declare function validateMediaBlock(b: unknown): string[];
127
+ export type ModelMessage = {
128
+ role: "user";
129
+ content: ContentBlock[];
130
+ } | {
131
+ role: "assistant";
132
+ content: ContentBlock[];
133
+ }
134
+ /** 对话中途的系统提醒;模型不支持时由插件转成 user 文本块(以 "[system] " 开头)。 */
135
+ | {
136
+ role: "system";
137
+ content: string;
138
+ };
139
+ export interface ToolDefinition {
140
+ name: string;
141
+ description: string;
142
+ inputSchema: Record<string, unknown>;
143
+ }
144
+ export interface ModelRequest {
145
+ model: string;
146
+ /** 稳定内容在前;cache 为 true 的块之后打缓存断点(由插件按原生协议实现)。 */
147
+ system: {
148
+ text: string;
149
+ cache: boolean;
150
+ }[];
151
+ messages: ModelMessage[];
152
+ tools: ToolDefinition[];
153
+ /**
154
+ * `@2`:模型可否调用工具。`"none"` = 本次只能回复文本、不得调用工具(`tools` 仍照常带上:历史里有工具调用时
155
+ * 部分供应商要求请求声明工具,且保持缓存前缀稳定);缺省或 `"auto"` = 由模型决定。
156
+ * 插件映射到原生字段(如 Anthropic `tool_choice: {type: "none"}`);`tools` 为空时插件不发送该字段。
157
+ */
158
+ toolChoice?: "auto" | "none";
159
+ maxOutputTokens: number;
160
+ /** `@2`:本次调用的参数(已按该模型的 `parameters` 处理过),由插件映射到原生请求。 */
161
+ params: Record<string, ParamValue>;
162
+ /** @deprecated `model-provider@1` 用;`@2` 插件读 `params.effort`。 */
163
+ effort?: Effort;
164
+ }
165
+ /** `model-provider@1` 的请求:没有 `params` 与 `toolChoice`。 */
166
+ export type ModelRequestV1 = Omit<ModelRequest, "params" | "toolChoice">;
167
+ export type StopReason = "end_turn" | "tool_use" | "max_tokens" | "refusal" | "other";
168
+ /**
169
+ * 一次调用的 token 用量。三类输入互不重叠:本次请求的输入总量 =
170
+ * `inputTokens + cacheReadTokens + cacheWriteTokens`(内核据此校正上下文估算、决定何时压缩)。
171
+ * 供应商 API 的输入计数若已包含缓存命中 / 写入的 token(如 OpenAI 的 `prompt_tokens`),插件必须先减掉。
172
+ */
173
+ export interface ModelUsage {
174
+ /** 未命中缓存、也未写入缓存的输入 token(只是未缓存部分,不是输入总量)。 */
175
+ inputTokens: number;
176
+ outputTokens: number;
177
+ /** 从提示词缓存读取的输入 token。 */
178
+ cacheReadTokens: number;
179
+ /** 本次写入提示词缓存的输入 token。 */
180
+ cacheWriteTokens: number;
181
+ }
182
+ export type ModelStreamEvent = {
183
+ type: "text_delta";
184
+ text: string;
185
+ } | {
186
+ type: "thinking_delta";
187
+ text: string;
188
+ } | {
189
+ type: "message_complete";
190
+ content: ContentBlock[];
191
+ stopReason: StopReason;
192
+ usage: ModelUsage;
193
+ };
194
+ export type ModelErrorKind = "rate_limited" | "overloaded" | "server" | "timeout" | "network" | "auth" | "invalid_request" | "context_overflow" | "aborted";
195
+ /** rate_limited / overloaded / server / timeout / network 为 true。 */
196
+ export declare function isRetryableKind(kind: ModelErrorKind): boolean;
197
+ /** 鸭子类型判断(不用 instanceof),兼容插件自带另一份 plugin-sdk 副本的情况。 */
198
+ export declare function isModelError(e: unknown): e is ModelError;
199
+ export declare class ModelError extends Error {
200
+ readonly kind: ModelErrorKind;
201
+ readonly retryAfterMs?: number;
202
+ constructor(kind: ModelErrorKind, message: string, opts?: {
203
+ retryAfterMs?: number;
204
+ cause?: unknown;
205
+ });
206
+ /** rate_limited / overloaded / server / timeout / network 为 true。 */
207
+ get retryable(): boolean;
208
+ }
209
+ /** `model-provider@2` 的实现。 */
210
+ export interface ModelProvider {
211
+ /** 每个模型的 `parameters` 须通过 `assertValidDeclarations`,否则内核不使用该供应商。 */
212
+ listModels(): Promise<ModelInfo[]>;
213
+ /** 事件序列必须以且仅以一个 message_complete 结束;出错抛 ModelError。 */
214
+ stream(req: ModelRequest, opts: {
215
+ signal: AbortSignal;
216
+ }): AsyncIterable<ModelStreamEvent>;
217
+ }
218
+ /** `model-provider@1` 的实现(旧契约,内核经适配层接入:effort 由 `capabilities.effort` 推导)。 */
219
+ export interface ModelProviderV1 {
220
+ listModels(): Promise<ModelInfoV1[]>;
221
+ /** 事件序列必须以且仅以一个 message_complete 结束;出错抛 ModelError。 */
222
+ stream(req: ModelRequestV1, opts: {
223
+ signal: AbortSignal;
224
+ }): AsyncIterable<ModelStreamEvent>;
225
+ }
226
+ export declare const MODEL_PROVIDER_EXTENSION_POINT = "model-provider@1";
227
+ export declare const MODEL_PROVIDER_EXTENSION_POINT_V2 = "model-provider@2";
package/dist/model.js ADDED
@@ -0,0 +1,152 @@
1
+ /** 图片块接受的类型。 */
2
+ export const IMAGE_MEDIA_TYPES = ["image/png", "image/jpeg", "image/gif", "image/webp"];
3
+ /** 文档块接受的类型。 */
4
+ export const DOCUMENT_MEDIA_TYPES = [
5
+ "application/pdf",
6
+ "text/plain",
7
+ "text/markdown",
8
+ "text/csv",
9
+ ];
10
+ /** 单个媒体块解码后的字节上限(按主流供应商的较小值取)。 */
11
+ export const MEDIA_LIMITS = { imageBytes: 5_242_880, documentBytes: 33_554_432 };
12
+ const B64_RE = /^[A-Za-z0-9+/]*={0,2}$/;
13
+ const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
14
+ /** 媒体块 `name` 的最大长度(字符)。 */
15
+ export const MEDIA_NAME_MAX_CHARS = 255;
16
+ /** 供应商请求里文件名 / 标题的建议上限(码点),{@link clipMediaName} 的默认值。 */
17
+ export const PROVIDER_MEDIA_NAME_MAX = 200;
18
+ /**
19
+ * 把附件名截到 `max` 个码点以内(供应商映射用:有的接口对 filename / title 有长度限制,补后缀后还会更长)。
20
+ * 尽量保留扩展名(不超过 16 个字符的 `.ext`),中间用 `…` 表示截掉的部分。纯函数。
21
+ */
22
+ export function clipMediaName(name, max = PROVIDER_MEDIA_NAME_MAX) {
23
+ const cps = [...name];
24
+ if (cps.length <= max)
25
+ return name;
26
+ const dot = name.lastIndexOf(".");
27
+ const ext = dot > 0 ? [...name.slice(dot)] : [];
28
+ const keep = ext.length > 0 && ext.length <= 16 && ext.length < max - 1 ? ext : [];
29
+ const head = cps.slice(0, max - 1 - keep.length);
30
+ return `${head.join("")}…${keep.join("")}`;
31
+ }
32
+ /** 是否含控制字符(C0、DEL 与 C1)。 */
33
+ export function hasControlChars(s) {
34
+ for (let i = 0; i < s.length; i++) {
35
+ const c = s.charCodeAt(i);
36
+ if (c < 0x20 || (c >= 0x7f && c <= 0x9f))
37
+ return true;
38
+ }
39
+ return false;
40
+ }
41
+ /** 附件 id 是否为 UUID(任意版本,大小写不限)。 */
42
+ export function isAttachmentId(s) {
43
+ return typeof s === "string" && UUID_RE.test(s);
44
+ }
45
+ const MEDIA = {
46
+ image: { types: IMAGE_MEDIA_TYPES, limit: MEDIA_LIMITS.imageBytes },
47
+ document: { types: DOCUMENT_MEDIA_TYPES, limit: MEDIA_LIMITS.documentBytes },
48
+ };
49
+ /**
50
+ * 校验一个 image / document 块,返回错误列表(空表示合法):类型在列表里;`base64` 是标准、带填充、
51
+ * 不含空白的 base64,解码后不超过 {@link MEDIA_LIMITS};`ref` 的 `attachmentId` 是 UUID;`name` 若有须是字符串、
52
+ * 不超过 {@link MEDIA_NAME_MAX_CHARS} 个字符且不含控制字符。
53
+ */
54
+ export function validateMediaBlock(b) {
55
+ if (typeof b !== "object" || b === null || Array.isArray(b))
56
+ return ["block must be an object"];
57
+ const o = b;
58
+ const spec = typeof o.type === "string" && Object.hasOwn(MEDIA, o.type) ? MEDIA[o.type] : undefined;
59
+ if (!spec)
60
+ return ['block type must be "image" or "document"'];
61
+ const errs = [];
62
+ if (typeof o.mediaType !== "string" || !spec.types.includes(o.mediaType)) {
63
+ errs.push(`${o.type} mediaType must be one of ${spec.types.join(", ")}`);
64
+ }
65
+ if (o.name !== undefined) {
66
+ if (typeof o.name !== "string")
67
+ errs.push(`${o.type} name must be a string`);
68
+ else if (o.name.length > MEDIA_NAME_MAX_CHARS) {
69
+ errs.push(`${o.type} name must be at most ${MEDIA_NAME_MAX_CHARS} characters`);
70
+ }
71
+ else if (hasControlChars(o.name)) {
72
+ errs.push(`${o.type} name must not contain control characters`);
73
+ }
74
+ }
75
+ const src = o.source;
76
+ if (typeof src !== "object" || src === null) {
77
+ errs.push(`${o.type} source must be an object`);
78
+ return errs;
79
+ }
80
+ const source = src;
81
+ if (source.kind === "ref") {
82
+ if (!isAttachmentId(source.attachmentId)) {
83
+ errs.push(`${o.type} source.attachmentId must be a UUID`);
84
+ }
85
+ }
86
+ else if (source.kind === "base64") {
87
+ const data = source.data;
88
+ if (typeof data !== "string" || data === "" || data.length % 4 !== 0) {
89
+ errs.push(`${o.type} source.data must be non-empty padded base64`);
90
+ return errs;
91
+ }
92
+ // 先按长度算解码后的大小,超限就不再逐字符校验
93
+ const pad = data.endsWith("==") ? 2 : data.endsWith("=") ? 1 : 0;
94
+ const bytes = (data.length / 4) * 3 - pad;
95
+ if (bytes > spec.limit) {
96
+ errs.push(`${o.type} is ${bytes} bytes, over the limit of ${spec.limit} bytes`);
97
+ }
98
+ else if (!B64_RE.test(data)) {
99
+ errs.push(`${o.type} source.data is not valid base64`);
100
+ }
101
+ }
102
+ else {
103
+ errs.push(`${o.type} source.kind must be "base64" or "ref"`);
104
+ }
105
+ return errs;
106
+ }
107
+ const ALL_KINDS = new Set([
108
+ "rate_limited",
109
+ "overloaded",
110
+ "server",
111
+ "timeout",
112
+ "network",
113
+ "auth",
114
+ "invalid_request",
115
+ "context_overflow",
116
+ "aborted",
117
+ ]);
118
+ const RETRYABLE = new Set([
119
+ "rate_limited",
120
+ "overloaded",
121
+ "server",
122
+ "timeout",
123
+ "network",
124
+ ]);
125
+ /** rate_limited / overloaded / server / timeout / network 为 true。 */
126
+ export function isRetryableKind(kind) {
127
+ return RETRYABLE.has(kind);
128
+ }
129
+ /** 鸭子类型判断(不用 instanceof),兼容插件自带另一份 plugin-sdk 副本的情况。 */
130
+ export function isModelError(e) {
131
+ if (!(e instanceof Error))
132
+ return false;
133
+ const kind = e.kind;
134
+ return typeof kind === "string" && ALL_KINDS.has(kind);
135
+ }
136
+ export class ModelError extends Error {
137
+ kind;
138
+ retryAfterMs;
139
+ constructor(kind, message, opts) {
140
+ super(message, opts && "cause" in opts ? { cause: opts.cause } : undefined);
141
+ this.name = "ModelError";
142
+ this.kind = kind;
143
+ if (opts?.retryAfterMs !== undefined)
144
+ this.retryAfterMs = opts.retryAfterMs;
145
+ }
146
+ /** rate_limited / overloaded / server / timeout / network 为 true。 */
147
+ get retryable() {
148
+ return isRetryableKind(this.kind);
149
+ }
150
+ }
151
+ export const MODEL_PROVIDER_EXTENSION_POINT = "model-provider@1";
152
+ export const MODEL_PROVIDER_EXTENSION_POINT_V2 = "model-provider@2";
@@ -0,0 +1,67 @@
1
+ import { type PolicyHook } from "./hooks.js";
2
+ /** Extension permission manifest: governance, not a sandbox; using an undeclared platform API throws ExtensionPermissionError. */
3
+ export interface ExtensionPermissions {
4
+ /** ctx.secrets */
5
+ secrets?: boolean;
6
+ /** ctx.http.route 注册的路由(`public` 表示免登录)。 */
7
+ http?: {
8
+ method: "GET" | "POST" | "PUT" | "DELETE";
9
+ path: string;
10
+ public?: boolean;
11
+ }[];
12
+ /** ctx.tools.register 的工具名。 */
13
+ tools?: string[];
14
+ /**
15
+ * Hook mount points (`ctx.hooks.on`). From M7, five mount points are registrable; see
16
+ * `HOOKS_AVAILABLE`.
17
+ */
18
+ hooks?: HookMountPoint[];
19
+ /**
20
+ * Mount points where the plugin registers `policy` hooks (each must also be in `hooks`; only
21
+ * `POLICY_HOOKS`). Deployment state reads it: while the plugin is enabled and approved but not loaded
22
+ * on a replica, calls on these mount points fail closed there.
23
+ */
24
+ policyHooks?: PolicyHook[];
25
+ /** 预留:模型用途,键须为 `<插件名>.<名称>`。 */
26
+ models?: {
27
+ purpose: string;
28
+ kind: "chat" | "embedding";
29
+ label: {
30
+ zh: string;
31
+ en: string;
32
+ };
33
+ }[];
34
+ /** ctx.storage(对象存储,键限定在 `plugins/<插件名>/<orgId>/` 下)。 */
35
+ storage?: boolean;
36
+ /** 访问的域名,只展示不拦截。 */
37
+ network?: string[];
38
+ /**
39
+ * 界面贡献的 id(与清单 `ui` 一一对应):`views` 记入快照但不卡加载;
40
+ * `embeds` 卡加载、需批准,并标为敏感项。
41
+ */
42
+ ui?: {
43
+ views?: string[];
44
+ embeds?: string[];
45
+ };
46
+ }
47
+ /** hook 挂载点(封闭列表,见总设计 2.4)。 */
48
+ export declare const HOOK_MOUNT_POINTS: readonly ["session.start", "session.end", "agent.preStep", "model.request", "model.response", "tool.preExecute", "tool.postExecute", "usage.report"];
49
+ /** hook 挂载点名。 */
50
+ export type HookMountPoint = (typeof HOOK_MOUNT_POINTS)[number];
51
+ /** A platform API not declared in the manifest was used. */
52
+ export declare class ExtensionPermissionError extends Error {
53
+ constructor(plugin: string, what: string);
54
+ }
55
+ /** The consumed extension point is unavailable (not installed, not enabled, or not enabled in that org). */
56
+ export declare class ExtensionPointUnavailableError extends Error {
57
+ constructor(message: string);
58
+ }
59
+ /** 校验权限清单,返回错误列表(空表示合法)。 */
60
+ export declare function validatePermissions(plugin: string, p: unknown): string[];
61
+ /**
62
+ * 校验清单 `ui` 并与权限清单交叉核对,返回错误列表(空表示合法):
63
+ * 每个贡献的 id 恰好出现在 `permissions.ui.views`(kind view)或 `permissions.ui.embeds`(kind embed)里,
64
+ * `permissions.ui` 里也不能有清单 `ui` 没有的 id;embed 的 path 以 `/ui/` 开头并在 `permissions.http` 中声明为 GET。
65
+ * 假定 `permissions` 已经过 {@link validatePermissions}。
66
+ */
67
+ export declare function validateUiContributions(ui: unknown, permissions: unknown): string[];