@xiongtao.xt/tau-plugins 0.25.0 → 0.27.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 CHANGED
@@ -1,8 +1,49 @@
1
1
  # AI 服务
2
2
 
3
- 此能力需要 SDK 0.7.0 及以上,以及支持插件 AI 服务的 Tau 客户端。
3
+ 自定义 AI 功能需要 SDK 0.7.0;申请应用已有的模型分配需要 SDK 0.27.0。两者都需要包含对应实现的 Tau 客户端。
4
4
 
5
- 插件声明 AI 功能,由用户在插件详情的「设置 → AI 配置」分配已有模型并开启授权。全局「大语言模型」设置管理服务商和密钥;插件只能通过 `ctx.ai` 请求模型,接口不返回密钥、连接地址或用户的聊天历史。
5
+ 自定义 AI 功能由插件声明,用户在插件详情的「设置 → AI 配置」分配已有模型并开启授权。全局「大语言模型」设置管理服务商和密钥;这类功能通过 `ctx.ai` 请求模型,接口不返回密钥、连接地址或用户的聊天历史。
6
+
7
+ ## 使用应用已有模型分配
8
+
9
+ 无需声明 `ai.features` 或另配模型。先在 manifest 中声明 `ai:<能力名>` 权限,再申请对应客户端:
10
+
11
+ ```json
12
+ { "permissions": ["ai:titleSummary"] }
13
+ ```
14
+
15
+ ```ts
16
+ const model = await context.ai.requestCapability("titleSummary");
17
+ const result = await model.chat({
18
+ messages: [{ role: "user", content: "为这段文字拟一个简短标题:……" }],
19
+ });
20
+ console.log(result.text);
21
+ ```
22
+
23
+ 申请时由用户选择允许或拒绝;能力分别授权,未声明的申请会被拒绝。返回客户端提供 `chat(request)` 和 `stream(request)`,参数与下文自定义 AI 相同,但不传 `feature`。每次调用复核权限,撤权、停用或切库取消在途生成;额度、并发和用量审计按插件统计。缺少应用模型分配时明确失败,不自动选择其他模型。
24
+
25
+ 当前全部 12 项大模型功能分配均可申请,能力清单也可从 `PLUGIN_AI_CAPABILITIES` 导入:
26
+
27
+ | 能力名 | 沿用的应用分配 |
28
+ | ------------------------------ | -------------- |
29
+ | `chat` | 对话功能 |
30
+ | `titleSummary` | 标题总结 |
31
+ | `webClip` | 网页剪藏 |
32
+ | `podcastGeneration` | 播客生成 |
33
+ | `flashcardGeneration` | 闪卡生成 |
34
+ | `aiJudgement` | 答案评判 |
35
+ | `transcriptionOptimization` | 转录断句优化 |
36
+ | `videoSummary` | 视频总结 |
37
+ | `videoEbookRewrite` | 视频电子书重写 |
38
+ | `vibeLearningImageDescription` | 图片理解 |
39
+ | `contentMetadata` | 笔记元信息 |
40
+ | `contentInsights` | AI 洞见 |
41
+
42
+ 这里复用模型分配,不自动执行宿主的业务流程或读取业务数据;插件传入自己的消息。已有闪卡业务流程由 `context.flashcards` 提供,它内部调用同一通用机制,需声明 `ai:flashcardGeneration`,详见 [FLASHCARDS.md](FLASHCARDS.md)。
43
+
44
+ 图片理解可在 user 消息中传入 `images: [{ data: imageBase64, mimeType: "image/png" }]`。`data` 不带 data: 前缀;支持 PNG、JPEG、WebP、GIF,每条消息最多 10 张,整次请求的 Base64 总长最多 20 MiB,模型须支持图片。图片与消息正文不会写入用量审计。
45
+
46
+ ## 声明自定义 AI 功能
6
47
 
7
48
  ```ts
8
49
  import { definePlugin } from "@tau/plugins";
package/API.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  本文介绍编写命令、页面、侧边栏、设置、数据存储、网络请求和摘录所需的接口。插件接口从 `@tau/plugins` 导入,界面组件从 `@tau/ui` 导入。所述能力需要 Tau 0.59.0 或更高版本。
4
4
 
5
- 本文对应 SDK 0.25.0;最低客户端版本只负责版本门槛,使用新领域接口时仍需包含对应实现的客户端构建。SDK 升级步骤见 [DEVELOPMENT.md](DEVELOPMENT.md#升级-sdk-与同步旧模板)。独立后台与双入口构建见 [BACKEND.md](BACKEND.md)。
5
+ 本文对应 SDK 0.27.0;最低客户端版本只负责版本门槛,使用新领域接口时仍需包含对应实现的客户端构建。SDK 升级步骤见 [DEVELOPMENT.md](DEVELOPMENT.md#升级-sdk-与同步旧模板)。独立后台与双入口构建见 [BACKEND.md](BACKEND.md)。
6
6
 
7
7
  博客发布提供方见 [PUBLISH.md](PUBLISH.md),需要 SDK 0.21.0 和包含该能力的客户端;独立博客站点读取数据见 [PUBLISH-DATA.md](PUBLISH-DATA.md)。
8
8
 
@@ -10,6 +10,8 @@
10
10
 
11
11
  AI 功能声明、用户模型分配、流式对话、取消与统一用量审计见 [AI.md](AI.md)(SDK 0.7.0 及以上)。
12
12
 
13
+ 创建闪卡、卡组、打开宿主手动/AI 制卡窗口及显式自动保存见 [FLASHCARDS.md](FLASHCARDS.md),需要 SDK 0.27.0 和包含该能力的客户端构建。
14
+
13
15
  白板扩展契约见 [WHITEBOARD.md](WHITEBOARD.md),需要 SDK 0.8.0 及以上。
14
16
 
15
17
  同步存储插件见 [SYNC.md](SYNC.md),需要 SDK 0.10.0 及以上。
@@ -105,6 +107,7 @@ export default definePlugin({
105
107
  | `commands` | `PluginContext["commands"]` | 注册命令 |
106
108
  | `storage` | `PluginStorage` | 保存当前插件在当前工作区的数据 |
107
109
  | `permissions` | `PluginPermissions` | 查询与申请业务数据权限 |
110
+ | `flashcards` | `PluginFlashcards` | 闪卡创建与 AI 制卡,见 FLASHCARDS.md |
108
111
  | `data` | `PluginData` | 读取与修改卡片、文章、项目文档、待办和日程 |
109
112
  | `content` | `PluginContent` | 读取与修改正文 |
110
113
  | `events` | `PluginEvents` | 订阅业务数据变化 |
@@ -515,6 +518,8 @@ function NoteActions({ context, target }: { context: PluginContext; target: Plug
515
518
  | `cards:delete` / `articles:delete` | `delete` |
516
519
  | `todos:read` / `todos:write` / `todos:delete` | `context.data.todos` 的查询、新建与修改、删除 |
517
520
  | `calendar:read` / `calendar:write` / `calendar:delete` | `context.data.calendar` 的查询、新建与修改、删除 |
521
+ | `flashcards:read` / `flashcards:write` | 查询卡组 / 创建卡组与闪卡、自动保存,见 FLASHCARDS.md |
522
+ | `ai:<能力名>` | 申请应用已有 AI 模型分配,全部能力及用法见 AI.md |
518
523
 
519
524
  插件第一次调用某个接口时,Tau 会弹窗询问用户:「仅这次」在插件停用或应用重启前有效,「始终允许」保存到用户撤销为止,「拒绝」在本次运行内不再询问,连续拒绝 3 次后转为已阻止。应用不在前台时不弹窗,请求会记在插件详情页的「权限」中等待用户处理。用户可以随时在那里撤销。
520
525
 
package/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # 更新记录
2
2
 
3
+ ## 0.27.0
4
+
5
+ - 新增通用 `context.ai.requestCapability(name)`,开放应用全部 12 项大模型功能分配。每项声明 `ai:<能力名>` 并由用户独立授权,返回 `chat/stream` 客户端,不需要另配模型或声明自定义 AI 功能。
6
+ - 闪卡 AI 制作使用此通用入口,权限为 `ai:flashcardGeneration`;不再要求传入 `feature`。支持在 user 消息中附带图片,图片不进入用量审计。
7
+ - 宿主模型仍经插件额度、并发限制与用量审计执行;撤销闪卡 AI 权限会取消在途请求,应用未配模型或分配变化时明确失败。
8
+ - 插件自定义 AI 的原有声明、授权与模型分配保持独立;闪卡读写权限和 `contentRef` 来源校验沿用 0.26.0。
9
+
10
+ ## 0.26.0
11
+
12
+ - 新增 `context.flashcards`:查询与创建卡组、创建闪卡、宿主制卡窗口、AI 草稿与自动保存;直接读写经 `flashcards:read/write` 授权。
13
+ - 插件 AI 制卡使用声明的 AI 功能及用户分配的模型,受插件授权、额度与用量审计约束。宿主制卡窗口要求用户操作,保存由用户确认。
14
+ - 现有正文引用使用不透明 `contentRef`,校验正文身份及读取权限;停用、切库取消在途任务,自动保存保留已提交结果。
15
+
3
16
  ## 0.25.0
4
17
 
5
18
  - 新增独立本机后台:格式 2 插件声明 `backend`,通过 `@tau/plugins/backend` 的 `defineBackend` 注册方法,界面经 `context.backend.call/subscribe` 调用与订阅。支持按需或随作用域启动、取消、受监督的外部工具与本机执行授权;构建脚本生成双入口及完整性摘要,详见 BACKEND.md。普通插件继续使用格式 1。
package/DEVELOPMENT.md CHANGED
@@ -8,7 +8,7 @@
8
8
  - pnpm 11.9.0
9
9
  - Tau 桌面客户端 0.59.0 或更高版本
10
10
 
11
- 模板锁定公开 SDK `@xiongtao.xt/tau-plugins@0.25.0` 和 UI `@xiongtao.xt/tau-ui@0.1.1`,通过 npm 别名安装为 `@tau/plugins`、`@tau/ui`。SDK 提供类型契约,运行实现由 Tau 注入;新领域能力还需包含相应实现的客户端构建,不能只依据客户端版本号判断。
11
+ 模板锁定公开 SDK `@xiongtao.xt/tau-plugins@0.27.0` 和 UI `@xiongtao.xt/tau-ui@0.1.1`,通过 npm 别名安装为 `@tau/plugins`、`@tau/ui`。SDK 提供类型契约,运行实现由 Tau 注入;新领域能力还需包含相应实现的客户端构建,不能只依据客户端版本号判断。
12
12
 
13
13
  ## 跑通示例
14
14
 
@@ -44,6 +44,7 @@ pnpm install:local
44
44
  | `AI.md` | AI 功能声明、用户模型分配、流式对话和统一用量审计 |
45
45
  | `MCP.md` | 注册 MCP、聊天工具渲染,复用工具开关与服务器管理 |
46
46
  | `BACKEND.md` | 显式声明本机后台、启动策略与独立产物构建 |
47
+ | `FLASHCARDS.md` | 闪卡读写权限、宿主制卡窗口、插件 AI 与正文来源引用 |
47
48
  | `WHITEBOARD.md` | 静态白板扩展、工具与发布边界 |
48
49
  | `SYNC.md` | 同步存储提供方、配置视图与取消 |
49
50
  | `UPLOAD.md` | 图片与附件上传、上传提供方与配置 |
@@ -62,10 +63,10 @@ pnpm install:local
62
63
 
63
64
  GitHub 模板创建的仓库不会自动跟随模板更新。已有项目先提交或备份自己的改动,再按需同步 [上游模板](https://github.com/LastKnightCoder/tau-plugin-template) 的构建脚本、开发文档和 `.github/workflows/release.yml`,保留自己的插件 ID、入口、用户说明与版本记录。
64
65
 
65
- 先在 `pnpm-workspace.yaml` 的 `minimumReleaseAgeExclude` 中增加新 SDK 的精确例外 `@xiongtao.xt/tau-plugins@0.25.0`,暂时保留旧锁文件所需的已核实例外,再更新依赖及锁文件:
66
+ 先在 `pnpm-workspace.yaml` 的 `minimumReleaseAgeExclude` 中增加新 SDK 的精确例外 `@xiongtao.xt/tau-plugins@0.27.0`,暂时保留旧锁文件所需的已核实例外,再更新依赖及锁文件:
66
67
 
67
68
  ```sh
68
- pnpm add @tau/plugins@npm:@xiongtao.xt/tau-plugins@0.25.0 --save-exact
69
+ pnpm add @tau/plugins@npm:@xiongtao.xt/tau-plugins@0.27.0 --save-exact
69
70
  pnpm install --frozen-lockfile
70
71
  pnpm build
71
72
  ```
@@ -74,16 +75,18 @@ pnpm build
74
75
 
75
76
  从旧 SDK 升级时,重点核对:
76
77
 
77
- | 版本 | 变化与对应文档 |
78
- | ------------- | ---------------------------------------------------------------------------- |
79
- | 0.17.0 | 行内源码接口,见 EDITOR.md |
80
- | 0.18.0 | 图片生成与编辑提供方,见 IMAGES.md |
81
- | 0.19.0–0.20.0 | 发布数据子入口、站点级数据归清单、分类与关键词,见 PUBLISH-DATA.md 与 API.md |
82
- | 0.21.0 | 博客发布提供方、配置与 Git 快照服务,见 PUBLISH.md |
83
- | 0.22.0 | 视频提供方与视频页面信息查询,见 VIDEO.md |
84
- | 0.23.0 | 删除 `ffmpeg.probe` 与 `MediaInfo`;`ffmpeg.run` 保留,见 SERVICES.md |
85
- | 0.24.0 | 删除 `services.typst`;Typst 编译由独立插件实现,见 SERVICES.md |
86
- | 0.25.0 | 数据读写与权限、正文组件、插件实体、宿主动作、存储随库同步,见 API.md;本机后台双入口见 BACKEND.md |
78
+ | 版本 | 变化与对应文档 |
79
+ | ------------- | ------------------------------------------------------------------------------------------------------ |
80
+ | 0.17.0 | 行内源码接口,见 EDITOR.md |
81
+ | 0.18.0 | 图片生成与编辑提供方,见 IMAGES.md |
82
+ | 0.19.0–0.20.0 | 发布数据子入口、站点级数据归清单、分类与关键词,见 PUBLISH-DATA.md 与 API.md |
83
+ | 0.21.0 | 博客发布提供方、配置与 Git 快照服务,见 PUBLISH.md |
84
+ | 0.22.0 | 视频提供方与视频页面信息查询,见 VIDEO.md |
85
+ | 0.23.0 | 删除 `ffmpeg.probe` 与 `MediaInfo`;`ffmpeg.run` 保留,见 SERVICES.md |
86
+ | 0.24.0 | 删除 `services.typst`;Typst 编译由独立插件实现,见 SERVICES.md |
87
+ | 0.25.0 | 数据读写与权限、正文组件、插件实体、宿主动作、存储随库同步,见 API.md;本机后台双入口见 BACKEND.md |
88
+ | 0.26.0 | 闪卡创建、读写授权、插件 AI 制卡与 contentRef 来源引用,见 FLASHCARDS.md |
89
+ | 0.27.0 | 通用 requestCapability 开放全部内置大模型功能分配,分别以 ai:<能力名> 授权;闪卡复用同一机制,见 AI.md |
87
90
 
88
91
  更早版本的完整变更见已安装包的 `node_modules/@tau/plugins/CHANGELOG.md`。需要本地媒体元数据时自行实现,不能把视频页面解析当作本地文件探测。SDK 根入口、白板/同步契约、UI 和 React 由 Tau 提供,保持模板的 external 配置;普通第三方库由构建打入 ZIP。独立站点数据子入口的用途另见 PUBLISH-DATA.md。
89
92
 
package/FLASHCARDS.md ADDED
@@ -0,0 +1,92 @@
1
+ # 闪卡能力
2
+
3
+ 本文对应 SDK 0.27.0 和支持闪卡接口的 Tau 0.59.0 客户端构建。能力通过激活时的 `context.flashcards` 使用,绑定本次激活的数据库;停用、切库后旧调用失效。旧客户端可用 `if (!context.flashcards)` 检查是否支持。
4
+
5
+ ## 权限与 AI 配置
6
+
7
+ 直接查询卡组需在 manifest 声明 `flashcards:read`,直接创建卡组、闪卡及自动保存需声明 `flashcards:write`;使用时由用户授权,可在插件详情页撤销。引用已有正文还需对应实体的读取权限;本插件自有正文沿用免业务权限规则。打开宿主窗口必须来自用户点击或按键,窗口内的创建由用户确认,不需要闪卡读写权限。
8
+
9
+ AI 制卡直接复用应用「闪卡生成」已分配的模型,不需要声明插件自己的 AI 功能或再次选择模型。在 manifest 中声明要申请的能力:
10
+
11
+ ```json
12
+ { "permissions": ["flashcards:read", "flashcards:write", "ai:flashcardGeneration"] }
13
+ ```
14
+
15
+ 内部通过通用的 `context.ai.requestCapability("flashcardGeneration")` 申请“使用闪卡制作 AI”,可在插件的「权限」页撤销,撤权会取消在途生成。主进程读取应用现有模型分配,按插件身份记录用量并限制并发和每日额度;额度可在插件 AI 设置中调整。应用未配置闪卡模型时明确报错。申请其他内置模型分配或声明自己的 AI 功能见 AI.md。
16
+
17
+ ## 打开宿主制卡窗口
18
+
19
+ ```ts
20
+ const result = await context.flashcards.openCreate({
21
+ mode: "ai", // manual 为手动制卡,缺省为 manual
22
+ content: "牛顿第二定律:F = ma。", // Markdown 或 Descendant[]
23
+ title: "力学笔记",
24
+ // deckId: 123, // 可选;省略时先选择卡组,也可以现场新建卡组
25
+ });
26
+
27
+ // result.status 为 completed 或 cancelled;cards 包含本次窗口已经保存的记录。
28
+ // 取消不会撤销「保存并新建」等已提交的记录。
29
+ console.log(
30
+ result.status,
31
+ result.cards.map(card => card.id)
32
+ );
33
+ ```
34
+
35
+ AI 模式自动开始生成并展示预览,可选择、编辑后保存;手动模式预填题干和参考资料,支持连续创建。未指定 references 时,content 作为自定义参考资料保存,title 用于来源标题;指定 `references: []` 可省略来源。
36
+
37
+ 引用 Tau 中已有正文时,显式传入来源,避免复制正文作为参考资料:
38
+
39
+ ```ts
40
+ await context.flashcards.openCreate({
41
+ mode: "ai",
42
+ content: sourceContent,
43
+ references: [{ refType: "content", contentRef: sourceContentRef, title: "原文" }],
44
+ });
45
+ ```
46
+
47
+ `sourceContentRef` 来自 `context.data` 的实体或 `context.entities`,不可解析或用正文数字 ID 代替。宿主核对正文身份与读取权限,失效或未获准的引用拒绝保存。
48
+
49
+ 窗口操作返回的 Promise 等待用户完成。必须在按钮或其他用户操作中调用;后台和定时器调用会被拒绝,不要在 `activate()` 中等待用户操作。同一窗口仅允许一个制卡会话,重复打开明确报错。
50
+
51
+ 所有创建方式返回的卡片都沿用 `PluginFlashcardDraft` 的字段:自定义参考正文为 `references[].customContent`,已有正文引用为 `references[].contentRef`。可以将返回卡片传给 `createCard` 创建副本,仍需写入和来源读取权限;已失效的引用不会出现在返回结果中。创建后来源窗口的卡组、闪卡和计数会自动刷新。
52
+
53
+ ## 直接创建卡组与闪卡
54
+
55
+ ```ts
56
+ const decks = await context.flashcards.listDecks();
57
+ const deck = await context.flashcards.createDeck({ name: "力学", description: "基础概念" });
58
+ const card = await context.flashcards.createCard({
59
+ deckId: deck.id,
60
+ type: "qa",
61
+ prompt: [{ type: "paragraph", children: [{ text: "牛顿第二定律的表达式是什么?" }] }],
62
+ data: { answer: "F = ma" },
63
+ tags: ["力学"],
64
+ difficulty: "foundation",
65
+ });
66
+ ```
67
+
68
+ 题型包括 `qa/boolean/cloze/single-choice/multiple-choice`,答案结构见 `PluginFlashcardData`。调用前必须确认用户意图;这些方法直接写入用户当前数据库,记录属于用户,不随插件卸载删除。API 不提供删除或修改已有闪卡的权限。
69
+
70
+ ## 生成草稿与自动保存
71
+
72
+ ```ts
73
+ // 只生成,插件可进一步筛选,再逐张 createCard。
74
+ const drafts = await context.flashcards.generate({
75
+ content: "需要学习的内容",
76
+ title: "资料",
77
+ });
78
+
79
+ // 只有明确调用此方法才绕过预览,直接保存。
80
+ const result = await context.flashcards.generateAndSave({
81
+ content: "需要学习的内容",
82
+ title: "资料",
83
+ deckId: deck.id,
84
+ });
85
+ // result.cards:成功保存的记录;result.failed:失败项的零基下标和 message。
86
+ ```
87
+
88
+ AI 沿用应用的闪卡制作模型,不读取或导出密钥。没有模型配置、未授权、额度不足或内容为空时明确失败,不自动选择其他模型;AI 模型变更后下一次调用使用新分配,已经进入准备过程的请求若发现分配改变会拒绝并要求重试。
89
+
90
+ 自动保存先校验全部草稿,再逐张写入;不承诺整批事务。不要对整个自动保存调用盲目重试,否则会重复创建成功项。需要精确重试时,使用 `generate` 保留草稿并逐张 `createCard`。取消与切库阻止后续写入,已发出的写入可能已在原库提交,不能将取消理解为事务回滚。
91
+
92
+ 这些 API 面向已激活的桌面插件;静态内容组件、博客与移动端没有此宿主能力。
@@ -85,7 +85,27 @@ function readCatalogFields(item, strict) {
85
85
  };
86
86
  }
87
87
 
88
+ // packages/plugins/src/ai.ts
89
+ var PLUGIN_AI_CAPABILITIES = {
90
+ chat: { name: "\u5BF9\u8BDD\u529F\u80FD" },
91
+ titleSummary: { name: "\u6807\u9898\u603B\u7ED3" },
92
+ webClip: { name: "\u7F51\u9875\u526A\u85CF" },
93
+ podcastGeneration: { name: "\u64AD\u5BA2\u751F\u6210" },
94
+ flashcardGeneration: { name: "\u95EA\u5361\u5236\u4F5C" },
95
+ aiJudgement: { name: "\u7B54\u6848\u8BC4\u5224" },
96
+ transcriptionOptimization: { name: "\u8F6C\u5F55\u65AD\u53E5\u4F18\u5316" },
97
+ videoSummary: { name: "\u89C6\u9891\u603B\u7ED3" },
98
+ videoEbookRewrite: { name: "\u89C6\u9891\u7535\u5B50\u4E66\u91CD\u5199" },
99
+ vibeLearningImageDescription: { name: "\u56FE\u7247\u7406\u89E3" },
100
+ contentMetadata: { name: "\u7B14\u8BB0\u5143\u4FE1\u606F" },
101
+ contentInsights: { name: "AI \u6D1E\u89C1" }
102
+ };
103
+ var isPluginAICapability = (value) => typeof value === "string" && Object.hasOwn(PLUGIN_AI_CAPABILITIES, value);
104
+
88
105
  // packages/plugins/src/permissions.ts
106
+ var aiPermissions = Object.keys(PLUGIN_AI_CAPABILITIES).map(
107
+ (capability) => `ai:${capability}`
108
+ );
89
109
  var PLUGIN_PERMISSIONS = [
90
110
  "cards:read",
91
111
  "cards:write",
@@ -100,7 +120,10 @@ var PLUGIN_PERMISSIONS = [
100
120
  "todos:delete",
101
121
  "calendar:read",
102
122
  "calendar:write",
103
- "calendar:delete"
123
+ "calendar:delete",
124
+ "flashcards:read",
125
+ "flashcards:write",
126
+ ...aiPermissions
104
127
  ];
105
128
  var permissionIds = new Set(PLUGIN_PERMISSIONS);
106
129
  var isPluginPermission = (value) => typeof value === "string" && permissionIds.has(value);
@@ -271,6 +294,8 @@ export {
271
294
  PLUGIN_KEYWORD_LIMIT,
272
295
  PLUGIN_KEYWORD_MAX_LENGTH,
273
296
  isPluginCategory,
297
+ PLUGIN_AI_CAPABILITIES,
298
+ isPluginAICapability,
274
299
  PLUGIN_PERMISSIONS,
275
300
  isPluginPermission,
276
301
  PLUGIN_SYSTEM_ACCESS,
package/package.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import {
2
+ PLUGIN_AI_CAPABILITIES,
2
3
  PLUGIN_CATEGORIES,
3
4
  PLUGIN_KEYWORD_LIMIT,
4
5
  PLUGIN_KEYWORD_MAX_LENGTH,
@@ -8,12 +9,14 @@ import {
8
9
  assertLocalId,
9
10
  comparePluginVersions,
10
11
  isContentPlugin,
12
+ isPluginAICapability,
11
13
  isPluginCategory,
12
14
  isPluginPermission,
13
15
  validateBackendManifest,
14
16
  validatePluginManifest
15
- } from "./client/chunk-GQO6J7O3.js";
17
+ } from "./client/chunk-R3YIHOWT.js";
16
18
  export {
19
+ PLUGIN_AI_CAPABILITIES,
17
20
  PLUGIN_CATEGORIES,
18
21
  PLUGIN_KEYWORD_LIMIT,
19
22
  PLUGIN_KEYWORD_MAX_LENGTH,
@@ -23,6 +26,7 @@ export {
23
26
  assertLocalId,
24
27
  comparePluginVersions,
25
28
  isContentPlugin,
29
+ isPluginAICapability,
26
30
  isPluginCategory,
27
31
  isPluginPermission,
28
32
  validateBackendManifest,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xiongtao.xt/tau-plugins",
3
- "version": "0.25.0",
3
+ "version": "0.27.0",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  PLUGIN_SHARED_MODULES,
3
3
  validatePluginManifest
4
- } from "./client/chunk-GQO6J7O3.js";
4
+ } from "./client/chunk-R3YIHOWT.js";
5
5
 
6
6
  // packages/plugins/src/rendering.ts
7
7
  var PLUGIN_RENDER_VERSION = 1;
@@ -3,12 +3,62 @@ export interface PluginAIFeature {
3
3
  name: string;
4
4
  description?: string;
5
5
  }
6
+ export declare const PLUGIN_AI_CAPABILITIES: {
7
+ readonly chat: {
8
+ readonly name: "对话功能";
9
+ };
10
+ readonly titleSummary: {
11
+ readonly name: "标题总结";
12
+ };
13
+ readonly webClip: {
14
+ readonly name: "网页剪藏";
15
+ };
16
+ readonly podcastGeneration: {
17
+ readonly name: "播客生成";
18
+ };
19
+ readonly flashcardGeneration: {
20
+ readonly name: "闪卡制作";
21
+ };
22
+ readonly aiJudgement: {
23
+ readonly name: "答案评判";
24
+ };
25
+ readonly transcriptionOptimization: {
26
+ readonly name: "转录断句优化";
27
+ };
28
+ readonly videoSummary: {
29
+ readonly name: "视频总结";
30
+ };
31
+ readonly videoEbookRewrite: {
32
+ readonly name: "视频电子书重写";
33
+ };
34
+ readonly vibeLearningImageDescription: {
35
+ readonly name: "图片理解";
36
+ };
37
+ readonly contentMetadata: {
38
+ readonly name: "笔记元信息";
39
+ };
40
+ readonly contentInsights: {
41
+ readonly name: "AI 洞见";
42
+ };
43
+ };
44
+ export type PluginAICapability = keyof typeof PLUGIN_AI_CAPABILITIES;
45
+ export declare const isPluginAICapability: (value: unknown) => value is PluginAICapability;
46
+ export interface PluginAIImage {
47
+ /** 不带 data: 前缀的 Base64 图片字节。 */
48
+ data: string;
49
+ mimeType: "image/png" | "image/jpeg" | "image/webp" | "image/gif";
50
+ }
51
+ export type PluginAIMessage = {
52
+ role: "system" | "assistant";
53
+ content: string;
54
+ } | {
55
+ role: "user";
56
+ content: string;
57
+ images?: readonly PluginAIImage[];
58
+ };
6
59
  export interface PluginAIRequest {
7
60
  feature: string;
8
- messages: readonly {
9
- role: "system" | "user" | "assistant";
10
- content: string;
11
- }[];
61
+ messages: readonly PluginAIMessage[];
12
62
  maxOutputTokens?: number;
13
63
  signal?: AbortSignal;
14
64
  }
@@ -28,7 +78,7 @@ export type PluginAIEvent = {
28
78
  type: "done";
29
79
  result: PluginAIResult;
30
80
  };
31
- export interface PluginAI {
81
+ export interface PluginAIFeatures {
32
82
  getStatus(feature: string): Promise<{
33
83
  configured: boolean;
34
84
  enabled: boolean;
@@ -37,4 +87,13 @@ export interface PluginAI {
37
87
  chat(request: PluginAIRequest): Promise<PluginAIResult>;
38
88
  stream(request: PluginAIRequest): AsyncIterable<PluginAIEvent>;
39
89
  }
90
+ export type PluginAICapabilityRequest = Omit<PluginAIRequest, "feature">;
91
+ export interface PluginAICapabilityClient {
92
+ chat(request: PluginAICapabilityRequest): Promise<PluginAIResult>;
93
+ stream(request: PluginAICapabilityRequest): AsyncIterable<PluginAIEvent>;
94
+ }
95
+ export interface PluginAI extends PluginAIFeatures {
96
+ /** 申请使用应用已有模型分配的 AI 能力;需在 manifest 声明对应 ai:<能力名> 权限。 */
97
+ requestCapability(capability: PluginAICapability): Promise<PluginAICapabilityClient>;
98
+ }
40
99
  export declare const unavailableAI: PluginAI;
@@ -23,6 +23,7 @@ import type { PluginContent, PluginData } from "./data";
23
23
  import type { PluginEvents } from "./events";
24
24
  import type { PluginApp } from "./app";
25
25
  import type { PluginOwnEntities } from "./entities";
26
+ import type { PluginFlashcards } from "./flashcards";
26
27
  import type { JsonValue } from "./json";
27
28
  export type { JsonValue } from "./json";
28
29
  export interface Disposable {
@@ -77,6 +78,7 @@ export interface PluginContext {
77
78
  readonly app: PluginApp;
78
79
  /** 插件自建、各带一份正文的内容;读写自己的内容不需要业务数据权限 */
79
80
  readonly entities: PluginOwnEntities;
81
+ readonly flashcards: PluginFlashcards;
80
82
  /** 将订阅等资源交给宿主,在停用或激活失败时逆序回收。 */
81
83
  register(resource: Disposable): Disposable;
82
84
  }
@@ -0,0 +1,89 @@
1
+ import type { Descendant } from "slate";
2
+ import type { PluginContentRef } from "./data";
3
+ export type PluginFlashcardType = "single-choice" | "multiple-choice" | "cloze" | "qa" | "boolean";
4
+ export interface PluginFlashcardData {
5
+ options?: {
6
+ id: string;
7
+ label: string;
8
+ isCorrect: boolean;
9
+ explanation?: string;
10
+ }[];
11
+ blanks?: {
12
+ id: string;
13
+ placeholder: string;
14
+ answer: string;
15
+ alternativeAnswers?: string[];
16
+ }[];
17
+ answer?: string;
18
+ booleanAnswer?: boolean;
19
+ explanation?: string;
20
+ hint?: string;
21
+ referenceNotes?: string;
22
+ }
23
+ export type PluginFlashcardReference = {
24
+ refType: "content";
25
+ contentRef: PluginContentRef;
26
+ title: string;
27
+ } | {
28
+ refType: "custom";
29
+ customContent: Descendant[];
30
+ title: string;
31
+ };
32
+ export interface PluginFlashcardDraft {
33
+ type: PluginFlashcardType;
34
+ prompt: Descendant[];
35
+ detail?: Descendant[];
36
+ data: PluginFlashcardData;
37
+ tags?: string[];
38
+ difficulty?: "foundation" | "standard" | "advanced";
39
+ references?: PluginFlashcardReference[];
40
+ }
41
+ export interface PluginFlashcardDeckInput {
42
+ name: string;
43
+ description?: string;
44
+ emoji?: string;
45
+ }
46
+ export interface PluginFlashcardDeck extends PluginFlashcardDeckInput {
47
+ id: number;
48
+ }
49
+ export interface PluginCreatedFlashcard extends PluginFlashcardDraft {
50
+ id: number;
51
+ deckId: number;
52
+ }
53
+ export interface PluginFlashcardCreateOptions {
54
+ mode?: "manual" | "ai";
55
+ /** 字符串按 Markdown 导入;富文本按当前编辑器节点协议传入。 */
56
+ content?: string | Descendant[];
57
+ title?: string;
58
+ deckId?: number;
59
+ references?: PluginFlashcardReference[];
60
+ }
61
+ export interface PluginFlashcardCreateResult {
62
+ status: "completed" | "cancelled";
63
+ /** 包含关闭前已保存的闪卡,取消不会撤销已完成的保存。 */
64
+ cards: PluginCreatedFlashcard[];
65
+ }
66
+ export interface PluginFlashcardBatchResult {
67
+ cards: PluginCreatedFlashcard[];
68
+ failed: {
69
+ index: number;
70
+ message: string;
71
+ }[];
72
+ }
73
+ export interface PluginFlashcards {
74
+ listDecks(): Promise<PluginFlashcardDeck[]>;
75
+ createDeck(input: PluginFlashcardDeckInput): Promise<PluginFlashcardDeck>;
76
+ createCard(input: PluginFlashcardDraft & {
77
+ deckId: number;
78
+ }): Promise<PluginCreatedFlashcard>;
79
+ /** 打开宿主窗口,等待保存或取消;不应在 activate 中等待用户完成。 */
80
+ openCreate(options?: PluginFlashcardCreateOptions): Promise<PluginFlashcardCreateResult>;
81
+ /** 仅生成草稿;自动落库须显式调用 generateAndSave。 */
82
+ generate(options: Omit<PluginFlashcardCreateOptions, "mode" | "deckId"> & {
83
+ content: string | Descendant[];
84
+ }): Promise<PluginFlashcardDraft[]>;
85
+ generateAndSave(options: Omit<PluginFlashcardCreateOptions, "mode"> & {
86
+ content: string | Descendant[];
87
+ deckId: number;
88
+ }): Promise<PluginFlashcardBatchResult>;
89
+ }
@@ -25,6 +25,7 @@ export { PLUGIN_EVENT_TYPES } from "./events";
25
25
  export type { PluginDomainEvent, PluginEventOrigin, PluginEventType, PluginEvents } from "./events";
26
26
  export { PLUGIN_PERMISSIONS, PluginPermissionError, isPluginPermission } from "./permissions";
27
27
  export type { PluginPermission, PluginPermissions, PluginPermissionState, PluginPermissionDenial, } from "./permissions";
28
+ export type * from "./flashcards";
28
29
  export type * from "./services";
29
30
  export { usePluginServices } from "./service-access";
30
31
  export type { PluginSkill } from "./skills";
@@ -33,4 +34,5 @@ export type { PluginMCPToolResult } from "./mcp";
33
34
  export type { PluginChat, PluginToolRendererDefinition, PluginToolRendererProps, ToolCallExecutionState, } from "./chat";
34
35
  export type { PluginPageDefinition, PluginPageHandle, PluginPageParams, PluginPageProps, PluginPages, } from "./pages";
35
36
  export declare function definePlugin(definition: Omit<PluginDefinition, "apiVersion" | "create"> & Partial<Pick<PluginDefinition, "create">>): PluginDefinition;
36
- export type { PluginAI, PluginAIFeature, PluginAIRequest, PluginAIResult, PluginAIEvent, } from "./ai";
37
+ export type { PluginAI, PluginAIFeature, PluginAIRequest, PluginAIResult, PluginAIEvent, PluginAIFeatures, PluginAICapability, PluginAICapabilityClient, PluginAICapabilityRequest, PluginAIImage, PluginAIMessage, } from "./ai";
38
+ export { PLUGIN_AI_CAPABILITIES, isPluginAICapability } from "./ai";
@@ -6,6 +6,7 @@ export { validateBackendManifest, PLUGIN_SYSTEM_ACCESS, type PluginBackendManife
6
6
  export { comparePluginVersions } from "./version";
7
7
  export { PLUGIN_CATEGORIES, PLUGIN_KEYWORD_LIMIT, PLUGIN_KEYWORD_MAX_LENGTH, isPluginCategory, type PluginCategory, } from "./categories";
8
8
  export { PLUGIN_PERMISSIONS, isPluginPermission, type PluginPermission } from "./permissions";
9
+ export { PLUGIN_AI_CAPABILITIES, isPluginAICapability } from "./ai";
9
10
  export declare const PLUGIN_SHARED_MODULES: readonly ["@tau/plugins", "@tau/plugins/whiteboard", "@tau/plugins/sync", "@tau/ui", "react", "react-dom", "react-dom/client", "react/jsx-runtime", "react/jsx-dev-runtime"];
10
11
  export interface PluginManifest {
11
12
  formatVersion: 1 | 2;
@@ -1,9 +1,4 @@
1
- /**
2
- * 业务数据权限:manifest 的 permissions 声明插件可申请的上限,首次调用对应接口时由宿主
3
- * 弹窗询问用户。read 读取,write 新建与修改(含正文),delete 删除(可在插件详情页恢复)。
4
- * 插件与应用运行在同一环境,权限约束的是 SDK 接口,不是安全隔离。
5
- */
6
- export declare const PLUGIN_PERMISSIONS: readonly ["cards:read", "cards:write", "cards:delete", "articles:read", "articles:write", "articles:delete", "documents:read", "documents:write", "todos:read", "todos:write", "todos:delete", "calendar:read", "calendar:write", "calendar:delete"];
1
+ export declare const PLUGIN_PERMISSIONS: readonly ["cards:read", "cards:write", "cards:delete", "articles:read", "articles:write", "articles:delete", "documents:read", "documents:write", "todos:read", "todos:write", "todos:delete", "calendar:read", "calendar:write", "calendar:delete", "flashcards:read", "flashcards:write", ...("ai:chat" | "ai:titleSummary" | "ai:webClip" | "ai:podcastGeneration" | "ai:flashcardGeneration" | "ai:aiJudgement" | "ai:transcriptionOptimization" | "ai:videoSummary" | "ai:videoEbookRewrite" | "ai:vibeLearningImageDescription" | "ai:contentMetadata" | "ai:contentInsights")[]];
7
2
  export type PluginPermission = (typeof PLUGIN_PERMISSIONS)[number];
8
3
  export declare const isPluginPermission: (value: unknown) => value is PluginPermission;
9
4
  /** granted:可直接调用;prompt:调用时会询问用户;denied:本次运行已拒绝或已被阻止 */