@xiongtao.xt/tau-plugins 0.6.0 → 0.7.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/AI.md ADDED
@@ -0,0 +1,75 @@
1
+ # AI 服务
2
+
3
+ 此能力需要 SDK 0.7.0 及以上,以及支持插件 AI 服务的 Tau 客户端。
4
+
5
+ 插件声明 AI 功能,由用户在插件详情的「设置 → AI 配置」分配已有模型并开启授权。全局「大语言模型」设置管理服务商和密钥;插件只能通过 `ctx.ai` 请求模型,接口不返回密钥、连接地址或用户的聊天历史。
6
+
7
+ ```ts
8
+ import { definePlugin } from "@tau/plugins";
9
+
10
+ declare const __PLUGIN_META__: { id: string; name: string; version: string };
11
+
12
+ export default definePlugin({
13
+ ...__PLUGIN_META__,
14
+ ai: {
15
+ features: [{ id: "summary", name: "文章摘要", description: "概括用户选择的文章" }],
16
+ },
17
+ create: () => ({
18
+ activate(ctx) {
19
+ ctx.commands.register({
20
+ id: "summary",
21
+ title: "生成摘要",
22
+ async run(input) {
23
+ const status = await ctx.ai.getStatus("summary");
24
+ if (!status.configured || !status.enabled) {
25
+ ctx.ai.openSettings("summary");
26
+ return null;
27
+ }
28
+ const result = await ctx.ai.chat({
29
+ feature: "summary",
30
+ messages: [
31
+ { role: "system", content: "概括主要内容,不添加原文以外的信息。" },
32
+ { role: "user", content: typeof input === "string" ? input : "请先选择正文。" },
33
+ ],
34
+ maxOutputTokens: 1024,
35
+ });
36
+ return result.text;
37
+ },
38
+ });
39
+ },
40
+ }),
41
+ });
42
+ ```
43
+
44
+ ## 接口
45
+
46
+ | 接口 | 返回与用途 |
47
+ | ------------------------ | ----------------------------------------------------------------------------------- |
48
+ | `getStatus(feature)` | `{ configured, enabled }`;模型被删除也视为未配置 |
49
+ | `openSettings(feature?)` | 打开当前插件设置,由用户分配模型、管理授权 |
50
+ | `chat(request)` | `{ text, usage }`;usage 未知时为 null |
51
+ | `stream(request)` | 异步迭代器,依次产生 `{ type: "text", delta }`,最后产生 `{ type: "done", result }` |
52
+
53
+ 请求字段:`feature` 必须是插件声明的功能 ID;`messages` 为 system/user/assistant 文本消息数组;`maxOutputTokens` 是可选的最大输出 Token;`signal` 为可选的取消信号。多轮历史由插件传入。多个 system 消息合并为系统提示,不提供工具调用或自动代理执行。
54
+
55
+ ```ts
56
+ const controller = new AbortController();
57
+ for await (const event of ctx.ai.stream({
58
+ feature: "summary",
59
+ messages: [{ role: "user", content: article }],
60
+ signal: controller.signal,
61
+ })) {
62
+ if (event.type === "text") appendText(event.delta);
63
+ else showUsage(event.result.usage);
64
+ }
65
+ ```
66
+
67
+ 退出迭代、取消 signal、停用插件或用户撤销 AI 授权都会请求取消。不要在模块顶层调用 AI,也不要在遇到额度不足或拒绝授权后自动循环重试。
68
+
69
+ ## 审计与额度
70
+
71
+ 所有模型调用由宿主归属到插件及功能,进入「大语言模型 → 用量统计」,插件设置的「查看用量」会跳转并筛选本插件。记录包含时间、模型、状态、Token、估算费用和耗时,不保存提示词或回复正文。运行中的请求可取消,也可一次关闭插件的 AI 授权。
72
+
73
+ 额度按本机自然日统计,所有窗口共用,并在重启后保留。每日请求次数、每日 Token 和并发限制由用户设置;并发达到上限直接拒绝,不排队。宿主按模型上下文容量加输出上限保守预占 Token,结束后按实际已知用量结算;未知用量保留预占。供应商未报告用量时不能当作零消费;费用为估算,不替代账单。取消无法撤销已经产生的消费。
74
+
75
+ 错误消息以稳定代码开头:`AI_NOT_CONFIGURED`(未配置)、`AI_DISABLED`(未授权或插件已停用)、`AI_UNDECLARED_FEATURE`(未声明)、`AI_QUOTA_EXCEEDED`(每日额度不足)、`AI_CONCURRENCY_LIMIT`(并发已满)、`AI_CONFIG_CHANGED`(模型分配变化)、`AI_ABORTED`(取消)、`AI_REQUEST_FAILED`(模型或审计失败)。本地 AbortSignal 取消也可能抛出标准 AbortError。
package/EDITOR.md CHANGED
@@ -1,8 +1,10 @@
1
- # 编辑器扩展与博客发布
1
+ # 编辑器扩展
2
2
 
3
- 本模板已锁定 SDK 0.6.0,需要 Tau 0.59.0 及支持编辑器插件的博客模板。基础计数页面示例没有使用本章接口;编写编辑器插件时,在 manifest 中加入 `"editor": true`。
3
+ 在文档中添加自己的块:比如交互演示、图表、特殊格式的卡片。本文还介绍源码预览块和插件 Skill。需要 Tau 0.59.0 或更高版本。
4
4
 
5
- ## 作者只定义一份扩展
5
+ ## 定义一个块
6
+
7
+ 先在 `manifest.json` 中加入 `"editor": true`(完整示例见下文),然后在插件定义里声明 `editorExtensions`:
6
8
 
7
9
  ```tsx
8
10
  import { useState } from "react";
@@ -56,17 +58,14 @@ export default definePlugin({
56
58
  });
57
59
  ```
58
60
 
59
- 节点数据中的 `initial` 是文档数据,示例中的 `useState` 计数仅属于本次展示,不会修改原文。编辑节点时使用编辑器扩展的操作协议;不要通过插件私有存储替代文档正文。
60
-
61
- `editorExtensions` 是静态贡献,与插件定义一起导出。纯编辑器插件可以省略 `create`;有命令、页面或设置时仍可提供 `create/activate`。博客只读取静态扩展,不调用这些桌面生命周期方法。
62
-
63
- 扩展可声明 `elements`、`commands`、`hotkeys`、`menu`、`blockPanel`、`behaviorsFor`。节点类型和扩展 ID 应使用自己的命名空间,不覆盖内置或其他插件的类型。块面板的 `onClick` 会收到当前编辑器,可使用其节点插入方法。当前不开放原始 Slate 包装器。
61
+ 几点说明:
64
62
 
65
- 本版针对带内容节点的插件,至少需要声明一个节点类型;纯快捷键或工具栏增强不属于本轮发布协议。
63
+ - 节点上的字段(如 `initial`)是文档数据,会随文档保存;组件里的 `useState` 只是本次显示的状态,不会改动原文。不要把文档内容放进插件私有存储。
64
+ - `editorExtensions` 与插件定义一起静态导出。只提供编辑器扩展的插件可以省略 `create`;同时有命令、页面或设置时照常提供 `create/activate`。
65
+ - 扩展可声明 `elements`、`commands`、`hotkeys`、`menu`、`blockPanel`、`behaviorsFor`,至少包含一个节点类型。`blockPanel` 的 `onClick` 会收到当前编辑器,可用来插入节点。
66
+ - 节点类型和扩展 ID 使用自己的命名空间(如 `yourname.chart`),不要与内置或其他插件的类型重名。
66
67
 
67
- `context.editor.register({ scene: "workbench", ... })` 仍只用于开发台实验,不参与正式正文或博客发布;正式扩展使用 `editorExtensions`。
68
-
69
- ## 清单与启停
68
+ 完整的 manifest 示例:
70
69
 
71
70
  ```json
72
71
  {
@@ -84,38 +83,30 @@ export default definePlugin({
84
83
  }
85
84
  ```
86
85
 
87
- 完整性摘要和样式入口由模板构建脚本生成。无需额外维护 `render.js` 或在清单里重复列出节点类型;Tau 从这份扩展定义取得节点归属。
88
-
89
- 编辑器插件的启用、停用及升级在完整重启后生效。所有窗口使用同一次启动的贡献快照,避免替换正在编辑的文档、撤销历史和协作实例。停用后旧节点由编辑器保留并显示不可用占位,不自动删除。当前窗口正在使用的编辑器插件需要先停用并重启,再卸载。
86
+ `styles`、`integrity` 由构建脚本生成,不用手写。
90
87
 
91
- 编辑器贡献不依赖 `activate` 的完成结果。共享渲染组件不得读取 `activate` 才赋值的上下文;否则博客和辅助编辑窗口无法独立展示它。
88
+ ## 启用、停用与卸载
92
89
 
93
- ## Markdown
94
-
95
- 可以在同一个定义中提供 `editorCodecs`,类型为 `EditorMarkdownCodec[]`,供桌面渲染端与博客的 Markdown 处理器装配。反序列化与序列化规则需要成对设计;声明一个输出函数不会自动获得导入能力。
96
-
97
- 已启用插件的 codec 会装配到桌面、主进程索引、转换线程与博客。后台读取同一个 main.js 中的定义,不调用 render/create/activate;codec 必须为纯转换函数,模块顶层不能依赖 window/document 或激活后的上下文。无需再提供 codec 文件或渲染入口。发布正文仍保留原始节点 JSON,不先转成 Markdown;发布搜索摘要等转换使用 codec。
90
+ - 编辑器插件的启用、停用和升级在完整重启 Tau 后生效。
91
+ - 停用后,文档里已有的节点会保留,并显示为不可用占位,不会被删除;重新启用后恢复显示。
92
+ - 卸载正在使用的编辑器插件前,需要先停用并重启。
98
93
 
99
- ## 发布时会发生什么
94
+ ## 块会在哪里显示
100
95
 
101
- 1. Tau 取得当前窗口启动时使用的插件版本、节点归属及 JS/CSS 摘要。
102
- 2. 发布器重新读取本地包;版本或摘要变化时要求重启,不悄悄换用新代码。
103
- 3. 从发布内容收集实际需要的插件,将同一个 main.js 和样式复制到站点的带版本与摘要的路径,向页面注入依赖清单。
104
- 4. 预编译博客模板先加载、验证这些文件,再创建 EditorKit 并显示原始节点。发布阶段不重编译模板。
96
+ 块除了显示在桌面编辑器里,还会出现在移动端、浏览器扩展和用户发布的网页中,这些地方都直接使用你在 `elements.render` 中写的同一个组件,不需要另写入口。因此渲染代码要满足:
105
97
 
106
- 没有对应扩展、包已变化或模板不支持协议时明确报错。已经发布的网站使用它携带的版本,不依赖读者安装 Tau,也不在访问时向插件中心请求最新版。
98
+ - 模块顶层和渲染组件能在浏览器中运行,不导入 Electron、Node 或 Tau 客户端内部路径。
99
+ - 不依赖 `activate` 中才赋值的变量,也不调用 `context` 的存储、页面、服务等桌面能力。
100
+ - React、ReactDOM、`@tau/plugins`、`@tau/ui` 由 Tau 提供,保持模板的 external 配置;其他浏览器兼容的 npm 依赖会打进 `main.js`。
101
+ - JS 与 CSS 自包含,图片等静态资源内联为 data URL。
102
+ - 样式使用插件自己的类名前缀,不覆盖 `body` 或 Tau 自身组件的样式。
103
+ - 只读场景下文档不可编辑,但组件自己的交互(按钮、图表缩放等)照常可用。
107
104
 
108
- ## 浏览器运行约束
105
+ ## Markdown
109
106
 
110
- - 模块顶层和内容渲染必须能在浏览器运行,不可直接导入 Electron、Node 或客户端内部路径。
111
- - 使用模板已有的 external 配置,React、ReactDOM、@tau/plugins、@tau/ui 由宿主共享。其他浏览器兼容 npm 依赖随 main.js 打包。
112
- - JS/CSS 需自包含;图片等静态资源可内联为 data URL。首期没有插件任意附件目录的发布协议。
113
- - 样式使用插件自己的类名,避免覆盖 body 或宿主组件的全局样式;不同页面只加载实际需要的插件。
114
- - 博客不提供桌面文件系统、私有存储、主进程编译服务和其他 PluginContext 能力。扩展不能通过渲染触发这些桌面调用。
115
- - 只读指文档不可编辑,不禁止组件自己的交互;图表、按钮等可维护自己的展示状态。
116
- - 当前 CJS 加载方式需要页面允许对应脚本求值。不要自行在站点配置中禁止它后假定插件仍可执行。
107
+ 在插件定义中提供 `editorCodecs`(类型为 `EditorMarkdownCodec[]`),让自定义节点支持 Markdown 导入导出、复制和搜索摘要。序列化与反序列化需要成对设计,只写输出函数不会自动获得导入能力。
117
108
 
118
- 跨端共用渲染组件和同一插件版本,但完整视觉一致性仍需要在相同主题、字体和尺寸条件下验收。移动端和浏览器扩展已支持由通用分发加载器装配编辑器插件包,目前没有新增下载管理界面。分发构建直接包装同一个 main.js,不要求作者维护另一个入口。
109
+ codec 会在后台转换时单独加载,不经过 `create/activate`,所以必须是纯转换函数,模块顶层不能访问 `window`、`document` 或激活后的上下文。
119
110
 
120
111
  ## 源码预览块
121
112
 
@@ -162,7 +153,7 @@ function SourceView({ element, children }: { element: SourceElement; children: R
162
153
  | `insertSourceBlock(editor, element, line?)` | 插入或替换空段落并聚焦源码,返回插入路径;不能插入时返回 undefined |
163
154
  | `sourceBlockParagraphBehavior(type)` | 放入扩展 `behaviorsFor.paragraph`,支持段首退格聚焦前一源码块 |
164
155
 
165
- `theme` 提供 `isDark` 和 `token(word)`;渲染应响应主题变化。桌面 `compiler.compile({source, language})` 返回 Tailwind CSS,language 为 html 或 tsx;博客不提供编译器,依赖发布阶段生成的 CSS。这些组件和 hook 由宿主提供,不要打包自己的编辑器、Slate React 或源码编辑器实例。
156
+ `theme` 提供 `isDark` 和 `token(word)`,渲染应响应主题变化。`compiler.compile({source, language})` 返回 Tailwind CSS,language 为 html 或 tsx;它只在桌面编辑器中可用,其他场景读不到编译器,需配合下文的 `styleSources` 使用。这些组件和 hook 由 Tau 提供,不要打包自己的编辑器、Slate React 或源码编辑器实例。
166
157
 
167
158
  ## 动态样式与静态导出
168
159
 
@@ -176,14 +167,22 @@ defineEditorExtension({
176
167
  });
177
168
  ```
178
169
 
179
- 发布器读取节点的 content 字段并编译 CSS;源码字段应为字符串。只有本插件声明的节点类型可登记,不需要另写发布回调。动态拼接类名仍无法被 Tailwind 静态扫描。
170
+ 在无法运行时编译的场景(如发布的网页),Tau 会据此读取这些节点的 `content` 字段,预先生成样式。源码字段须为字符串,只能登记本插件声明的节点类型。拼接出来的类名(如 `` `bg-${color}` ``)扫描不到,类名要完整写在源码里。
180
171
 
181
- 可选 `htmlSerializers: [{type, toHtml(element)}]` 用于复制 HTML、HTML/EPUB 等静态导出,返回 HTML 字符串并自行转义文本。它不参与博客渲染;博客始终使用原来的 `elements.render`。不声明时遵循宿主未知节点导出规则,不承诺交互式组件可在 EPUB 中执行。
172
+ 可选 `htmlSerializers: [{type, toHtml(element)}]` 用于复制 HTML、HTML/EPUB 等静态导出,返回 HTML 字符串并自行转义文本。它只用于静态导出,网页显示仍使用 `elements.render`。不声明时按未知节点的默认规则导出,交互式组件在 EPUB 中不会执行。
182
173
 
183
174
  ## 插件 Skill
184
175
 
185
- 在 `definePlugin` 的 `skills` 数组声明 `{id, name, description, content, invocation?}`。id 是插件内唯一标识,name 是显示名,description 用于 AI 判断何时加载,content 是完整 SKILL.md 文本;invocation 默认 auto,也可设 manual。
176
+ 在 `definePlugin` 的 `skills` 数组中声明 `{id, name, description, content, invocation?}`,为 AI 提供与你的插件配套的写作规范:
177
+
178
+ | 字段 | 说明 |
179
+ | ------------- | ------------------------------------------------------ |
180
+ | `id` | 插件内唯一标识;AI 以 `插件ID:技能ID` 引用 |
181
+ | `name` | Skill 页面显示的名称 |
182
+ | `description` | AI 据此判断何时加载,写清适用场景 |
183
+ | `content` | 完整的 SKILL.md 正文 |
184
+ | `invocation` | 默认 `auto`(AI 自行加载),设为 `manual` 则仅手动点名 |
186
185
 
187
- 技能在插件启用成功后可用,停用或激活失败时回收。技能页显示「插件」来源,允许用户调整调用模式、停用或复制到自己的技能目录。AI 使用 `插件ID:技能ID` 寻址,可读取 SKILL.md;首版只提供单文档,不声明脚本和附件能力。
186
+ 插件启用后 Skill 才可用,停用时自动移除。Skill 页面会标明它来自你的插件,用户可以调整调用方式、停用或复制到自己的 Skill 目录。目前每个 Skill 只有一份正文,不支持脚本和附件。
188
187
 
189
- 技能正文可以写在单独的 SKILL.md 中,构建时通过 esbuild 的 `.md: text` loader 导入到同一个 main.js。博客不会激活 Skill,不需要额外下载技能文件。
188
+ 正文可以写在单独的 SKILL.md 中,构建时用 esbuild 的 `.md: text` loader 作为字符串导入。
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
- # Tau plugins 作者契约
1
+ # Tau 插件开发包 @tau/plugins
2
2
 
3
- 通过 npm 别名安装为 `@tau/plugins`。运行时由 Tau 宿主提供,构建时必须 external;不可在普通 Node.js 程序中直接执行。
3
+ 开发 Tau 插件所需的类型与接口,通过 npm 别名安装为 `@tau/plugins`。实际实现由 Tau 客户端在运行时提供,构建时需设为 external,不能在普通 Node.js 程序中直接运行。
4
4
 
5
- 模板与使用说明:https://github.com/LastKnightCoder/tau-plugin-template
5
+ 从模板开始开发:https://github.com/LastKnightCoder/tau-plugin-template
6
6
 
7
- 编译与转换服务见 [SERVICES.md](SERVICES.md),编辑器扩展、源码预览与插件 Skill 见 [EDITOR.md](EDITOR.md),要求 Tau 0.59.0 及以上。
7
+ 编译与转换服务见 [SERVICES.md](SERVICES.md),编辑器扩展、源码预览与插件 Skill 见 [EDITOR.md](EDITOR.md),需要 Tau 0.59.0 及以上。AI 功能声明、模型分配与用量审计见 [AI.md](AI.md)。
package/SERVICES.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # 编译与转换服务
2
2
 
3
- 本文对应本模板锁定的 SDK 0.6.0,需要 Tau 0.59.0 或更高版本。编译与转换通过 `context.services` 调用,类型从 `@tau/plugins` 导入。基础计数示例不依赖这些服务,可按实际需求使用。
3
+ 需要在插件里编译 Tailwind、Typst、TikZ,转换 Markdown,或处理音视频时,可以使用这些服务。通过 `context.services` 调用,类型从 `@tau/plugins` 导入,需要 Tau 0.59.0 或更高版本。
4
4
 
5
5
  所有服务都是异步方法,只处理传入数据并返回结果,不读写笔记、不选择或保存文件、不自动注入样式。
6
6
 
@@ -47,13 +47,13 @@ const { css } = await context.services.tailwind.compile({
47
47
  });
48
48
  ```
49
49
 
50
- 使用 Tailwind 4,支持 Tau 语义类。返回 theme/utilities,不重复提供 preflight。源码只用于提取完整类名,不执行 TSX/JSX,也不编译 React。动态拼接类名不能保证被提取。Tau 语义类依赖宿主的 `--tau-*` 变量,离开 Tau 的页面需要自行提供相应主题变量。
50
+ 使用 Tailwind 4,支持 Tau 语义类。返回 theme/utilities,不重复提供 preflight。源码只用于提取完整类名,不执行 TSX/JSX,也不编译 React。动态拼接类名不能保证被提取。Tau 语义类依赖 Tau 提供的 `--tau-*` 变量,离开 Tau 的页面需要自行提供相应主题变量。
51
51
 
52
52
  固定插件界面通常在打包时编译样式;此服务主要用于运行时生成内容。返回 CSS 由插件自行使用并在停用时清理。
53
53
 
54
54
  ## Typst
55
55
 
56
- 首期仅支持 HTML,返回 HTML 正文片段。PDF/SVG 不属于本版本 API。`inputs` 对应 Typst 的 `sys.inputs`:
56
+ 目前只输出 HTML 正文片段,不支持 PDF 和 SVG。`inputs` 对应 Typst 的 `sys.inputs`:
57
57
 
58
58
  ```ts
59
59
  const { html } = await context.services.typst.compile({
@@ -113,7 +113,7 @@ const { svg } = await context.services.tikz.compile({
113
113
 
114
114
  ## FFmpeg
115
115
 
116
- `ServiceFile` 为 `{ name: string, data: Blob }`;文件名仅在任务内使用,不是客户端路径。输入输出名称不得重复,目录使用 `/`。文件整体经内存传输,适合可容纳于内存的素材;尚无大文件流式接口。
116
+ `ServiceFile` 为 `{ name: string, data: Blob }`;文件名仅在任务内使用,不是客户端路径。输入输出名称不得重复,目录使用 `/`。文件整体经内存传输,适合可以放进内存的素材,不支持大文件流式处理。
117
117
 
118
118
  ```ts
119
119
  const input = { name: "input.wav", data: audioBlob };
@@ -136,4 +136,4 @@ const outputBlob = result.files[0].data;
136
136
 
137
137
  `args` 不包含程序名;含空格的参数作为一个数组元素,不额外加 shell 引号。服务设置非交互、覆盖临时输出和进度通道,不要覆盖 `-progress` 或依赖交互 stdin。`outputs` 声明要取回的产物,名称与参数中的输出一致;文件未生成会报错,退出非零不会返回部分成功结果。
138
138
 
139
- `onProgress.time` 是已处理媒体时间(秒),不是百分比。FFmpeg 首次使用可能需要客户端准备或下载二进制文件,需要网络;已安装版本可复用。取消不删除共享编译器缓存。`log` 保留最后 64 KiB 诊断输出。返回 MIME 类型由 `outputs.mimeType` 指定,调用者须确保与实际格式一致。
139
+ `onProgress.time` 是已处理媒体时间(秒),不是百分比。首次使用 FFmpeg 时 Tau 可能需要联网下载,之后会复用;取消任务不会删除已下载的 FFmpeg。`log` 保留最后 64 KiB 诊断输出。返回 MIME 类型由 `outputs.mimeType` 指定,调用者须确保与实际格式一致。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xiongtao.xt/tau-plugins",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -0,0 +1,40 @@
1
+ export interface PluginAIFeature {
2
+ id: string;
3
+ name: string;
4
+ description?: string;
5
+ }
6
+ export interface PluginAIRequest {
7
+ feature: string;
8
+ messages: readonly {
9
+ role: "system" | "user" | "assistant";
10
+ content: string;
11
+ }[];
12
+ maxOutputTokens?: number;
13
+ signal?: AbortSignal;
14
+ }
15
+ export interface PluginAIResult {
16
+ text: string;
17
+ /** 供应商未报告用量时为 null。 */
18
+ usage: {
19
+ inputTokens: number;
20
+ outputTokens: number;
21
+ totalTokens: number;
22
+ } | null;
23
+ }
24
+ export type PluginAIEvent = {
25
+ type: "text";
26
+ delta: string;
27
+ } | {
28
+ type: "done";
29
+ result: PluginAIResult;
30
+ };
31
+ export interface PluginAI {
32
+ getStatus(feature: string): Promise<{
33
+ configured: boolean;
34
+ enabled: boolean;
35
+ }>;
36
+ openSettings(feature?: string): void;
37
+ chat(request: PluginAIRequest): Promise<PluginAIResult>;
38
+ stream(request: PluginAIRequest): AsyncIterable<PluginAIEvent>;
39
+ }
40
+ export declare const unavailableAI: PluginAI;
@@ -1,5 +1,6 @@
1
1
  import type { PluginPages } from "./pages";
2
2
  import type { PluginSkill } from "./skills";
3
+ import type { PluginAI, PluginAIFeature } from "./ai";
3
4
  import type { PluginServices } from "./services";
4
5
  import type { PluginEditor } from "./editor";
5
6
  import type { PluginEditorExtension } from "./editor";
@@ -40,6 +41,7 @@ export interface PluginContext {
40
41
  readonly materials: PluginMaterials;
41
42
  readonly fetch: typeof globalThis.fetch;
42
43
  readonly services: PluginServices;
44
+ readonly ai: PluginAI;
43
45
  /** 将订阅等资源交给宿主,在停用或激活失败时逆序回收。 */
44
46
  register(resource: Disposable): Disposable;
45
47
  }
@@ -56,6 +58,9 @@ export interface PluginDefinition {
56
58
  readonly editorExtensions?: readonly PluginEditorExtension[];
57
59
  readonly editorCodecs?: readonly MarkdownCodec[];
58
60
  readonly skills?: readonly PluginSkill[];
61
+ readonly ai?: {
62
+ readonly features: readonly PluginAIFeature[];
63
+ };
59
64
  /** 每次启用创建新实例,运行状态不放在定义对象上。 */
60
65
  create(): PluginInstance;
61
66
  }
@@ -10,3 +10,4 @@ export type * from "./services";
10
10
  export type { PluginSkill } from "./skills";
11
11
  export type { PluginPageDefinition, PluginPageHandle, PluginPageParams, PluginPageProps, PluginPages, } from "./pages";
12
12
  export declare function definePlugin(definition: Omit<PluginDefinition, "apiVersion" | "create"> & Partial<Pick<PluginDefinition, "create">>): PluginDefinition;
13
+ export type { PluginAI, PluginAIFeature, PluginAIRequest, PluginAIResult, PluginAIEvent, } from "./ai";