# 插件能力参考

> 按目标查找 ctx 上的界面、对话、Agent、文件、网络、浏览器、模型、媒体与存储 API 及其权限边界。

Canonical page: /plugins/capabilities



插件 API 由 `@astravia-org/plugin-sdk` 提供，构建由 `@astravia-org/plugin-vite` 提供，脚手架与安装命令由 `@astravia-org/plugin-cli` 提供。插件代码运行在 Desktop renderer 进程的共享 JavaScript realm 内；权限声明用于知情同意和宿主 API 门控，不是 iframe、Worker 或恶意代码沙箱。

`activate(ctx)` 拿到的 `ctx` 是所有能力的唯一出口。宿主在主进程一侧并不认识「插件」这个概念，只认识一个带授权清单的能力会话，因此每一次调用都会被重新校验、约束到本插件的命名空间，并留下审计记录。

## 能力地图 [#能力地图]

| 目标           | 常用入口                                                          | 权限                                                          | 需要注意                                               |
| ------------ | ------------------------------------------------------------- | ----------------------------------------------------------- | -------------------------------------------------- |
| 上报错误与提示      | `ctx.ui.notify`                                               | 无                                                           | 任何可能失败的路径都应在 catch 里带上原始 error                     |
| 增加界面与页面      | `ctx.ui.register*`                                            | 各槽位独立权限                                                     | 注册返回的 `Disposable` 要在停用时释放                         |
| 扩展文件浏览器      | `ctx.fileExplorer.*`                                          | `ui.file-explorer.*`、`workspace.read`                       | 解析失败要返回可理解的错误状态                                    |
| 读对话与订阅事件     | `ctx.conversation.on` 及对话 hook                                | `agent.session.read`                                        | 事件是宿主状态的只读视图                                       |
| 驾驶当前对话       | `ctx.conversation.sendPrompt`、`insertText`、`abort`            | `agent.session.write`                                       | 不要在用户没有触发的情况下自动发起提问                                |
| 注册工具与 Hook   | `ctx.agent.registerTool`、`registerHook`                       | `agent.tools.register` / `agent.hooks.register` 及对应 execute | 输入使用结构化 schema，执行错误要稳定返回                           |
| 干预系统提示词与续跑   | `registerSystemPromptProvider`、`registerContinuationProvider` | `agent.systemPrompt.write`、`agent.continuation.register`    | Provider 每个 Turn 开始时求值一次，本 Turn 内不会因插件状态变化重跑       |
| 执行宿主命令       | `ctx.command.run`、`ctx.command.spawn`                         | `agent.command.run` / `agent.command.spawn`                 | 清单必须声明 `commands`，不要把密钥放进参数                        |
| 在终端里替用户跑命令   | 底部面板里的 `useBottomPanel().openTerminal`                        | `terminal.run`                                              | 命令敲进用户自己的 shell、全程可见；cwd 只能在会话目录之内                 |
| 离屏渲染截图       | `ctx.capture.offscreen`                                       | `capture.offscreen`                                         | 旧宿主上为 `undefined`，使用前判空                            |
| 读写文件         | `ctx.fs.*`                                                    | `fs.read` / `fs.write`                                      | 大文件先 `stat` 再决定读取方式                                |
| 调用外部网络       | `ctx.network.request`                                         | `network.fetch`                                             | 清单声明最小 `network.allowedHosts`                      |
| 浏览器自动化       | `ctx.browser.*`                                               | `browser.open` / `read` / `interact` 等                      | 使用逻辑 profile；不获得 Cookie、Token 或任意 JS 执行权           |
| 插件私有持久化      | `ctx.storage.*`                                               | `storage.read` / `storage.write`                            | 按插件 id 隔离；多文件一致性用一次 `commit()` 而不是连续 `writeFile()` |
| 保存密钥         | `ctx.secrets.*`                                               | `secrets.read` / `secrets.write`                            | 宿主加密凭据库，不要把 Key 写进普通存储                             |
| 调用用户已配置模型    | `ctx.ai.listModels`、`complete`、`stream`、`chat`                | `ai.models.list` / `ai.complete`                            | 使用用户配置的凭据，不自行保存 Key                                |
| 维护自有模型服务商    | `ctx.models.replaceOwnedProviders`、`listOwnedProviders`       | `models.manage`                                             | 写入是原子快照，省略即删除；先读回对账，读到的 apiKey 是掩码                 |
| 生成与注册媒体能力    | `ctx.media.submit`、`registerProvider`                         | `media.generate` / `media.provider.register`                | 长任务通过 `ctx.jobs` 观察进度与取消                           |
| 识别与注册 OCR 能力 | `ctx.ocr.recognize`、`registerProvider`                        | `ai.ocr.recognize` / `ai.ocr.provider.register`             | 消费与提供是两个独立权限                                       |
| 管理 CLI 与本地服务 | `ctx.cliProviders.*`、`ctx.services.*`                         | 由清单 `providers` 声明                                          | 宿主负责探测、安装、启停与健康检查                                  |
| 注册可发现动作      | `ctx.appActions.register`                                     | `app.actions.register` + `app.actionHandler.execute`        | 高影响文件和网络操作仍需确认                                     |
| 提供技能或 MCP    | `plugin.json` 的 `agent` 字段                                    | `agent.skills.control` / `agent.mcp.control`                | 安装、启用和重载都要重新验证来源与权限                                |
| 贡献智能体与团队     | `plugin.json` 的 `agent.agents`、`agent.teams`                  | 无                                                           | 宿主铺成普通档案；成员可跨插件引用，队长必须是本插件自己的                      |
| 在新会话页摆素材     | `ctx.ui.registerNewSessionContext`                            | `ui.slot.new-session-context`                               | 激活条件只能写本插件自己的智能体或能力，拿不到用户逐键输入                      |
| 提供多语言文案      | `ctx.i18n` 与包内 `locales/`                                     | 无                                                           | 文案 key 和 `defaultLocale` 要与清单一致                    |

<Callout title="有两个字段必须判空" type="warn">
  `ctx.capture` 在不支持离屏截图的旧宿主上是 `undefined`；`ctx.gateway` 只对内置官方插件可用，第三方插件一律读到 `undefined`。使用前先判空，不要假设它们存在。
</Callout>

## 网络请求的实际边界 [#网络请求的实际边界]

`ctx.network.request` 由主进程代理，除了主机白名单还有一组固定约束：默认超时 120 秒、上限 300 秒，请求体与响应体各自上限 32 MB，最多 5 次重定向，只允许 http 与 https。

重定向逐跳重新校验白名单，非 GET 与 HEAD 的重定向直接拒绝，跨源跳转时会剥掉 `authorization` 和 `cookie` 头。失败原因是枚举值而不是笼统的网络错误，可以据此区分是主机未声明、超出体积、超时还是传输失败。

## 选择 API 的原则 [#选择-api-的原则]

* 只增加 Agent 方法时，优先技能或插件的 Agent 贡献，不要先创建复杂界面。
* 只连接外部服务时，优先独立 MCP；插件内聚 MCP 适合与插件生命周期强绑定的服务。
* 只需要颜色、表面和组件替换时，使用主题系统。
* 需要完整页面、文件预览、消息卡片或宿主动作时，才使用插件。
* 需要给宿主补一类能力（模型服务商、媒体生成、OCR、本地服务）时，用对应的 Provider 扩展点而不是自己在界面里另起一套。

## 权限与生命周期 [#权限与生命周期]

一个完整的插件能力需要同时通过三层：清单声明意图和最小权限，安装时由用户确认，宿主在运行时再次校验并在插件重载或停用时清理注册项。

`activate()` 可以返回一个清理函数或 `Disposable`，把资源所有权绑定到这一次激活上。热更新时新旧激活会短暂共存，各自的清理互不干扰，所以有状态资源优先用这种写法，而不是模块级的 `deactivate()`。

系统内置插件与外置插件的授权策略不同：系统插件随应用发布并自动全量授权，外置插件仍应按不可信代码审查。详见[清单与权限](/plugins/manifest-and-permissions/)。

## 发布前验收 [#发布前验收]

<Checklist title="至少验证这些情况">
  <li>
    全新安装时清单字段、入口、样式和构建产物路径一致。
  </li>

  <li>
    权限提示只包含完成任务所需的权限。
  </li>

  <li>
    停用、重载和再次启用不会重复注册界面、工具或事件监听。
  </li>

  <li>
    撤销任一可选权限后，插件其余能力仍然可用。
  </li>

  <li>
    无权限、外部网络失败、文件解析失败和模型失败都能显示可恢复的错误。
  </li>

  <li>
    发布 ZIP 与开发链接都经过验证；开发链接成功不能代替 ZIP 安装测试。
  </li>
</Checklist>

<Callout title="插件不是安全沙箱" type="warn">
  共享 renderer realm 意味着插件来源本身就是安全边界。只安装可信来源，审查构建产物和更新内容，并授予最小权限。
</Callout>
