跳转到内容
Crystal CodeDocs
简简体中文

插件契约

引用 CrystalCode.Plugins。只有工具需要 ToolHostContext 时才引用 CrystalCode.Tools。不要引用 CrystalCode.Engine、CrystalCode、CrystalCode.Display 或 CrystalCode.Providers。

Contribute 返回工具、客户端工厂、分类器、命令、钩子、原始钩子、提示占位符和状态字段。空条目带着说明被省略。一个坏插件不会停止其他插件。

Attach 在 Contribute 之后运行,此时插件、外部工具和技能已加载,并在这些目录重新加载时再次运行。它在会话开始钩子之前运行。默认方法什么都不做。在 Contribute 内读取快照太早:宿主还没有完成其他目录。

工具实现 IPluginTool:面向模型的 Name、Catalogs、一个 ITool,以及可选的同名 IMultimodalTool。Catalogs 是 PluginToolCatalogs.Plan、Work 或 PlanAndWork。工具必须至少点名一个目录。同一选择适用于其多模态工具。

名称匹配 ^[A-Za-z][A-Za-z0-9_-]*$(1–64 个字符),且不得是内置名称。定义名称必须匹配 Name。之后的重复带着说明被省略。

目录顺序是内置插件工具、磁盘插件工具、外部工具,然后是启用时的 skill。磁盘工具名称相对外部工具被保留。

插件构造该工具。工具实现 IHostTool 或 IHostMultimodalTool 时,宿主事实按调用到达。工具不收到问题提示。

IPluginClientFactory.CanCreate 只对它拥有的协议返回 true。对 deepseek、openai、responses、anthropic、gemini 或 ollama 返回 true 的工厂被省略。内置适配器保持优先。自定义协议是 1–64 个字符的 token:一个字母,然后是字母、数字、_ 或 -。把该 token 作为 protocol 放进 providers.json。

PluginClientRequest 为该调用携带端点、模型采样和 API 密钥。不要记录密钥。它也携带声明的 audioInput 和 videoInput,以及这些槽已设置时的 ServiceTier 和 Speed。无法写入非空槽的工厂必须从 Create 或 CreateMultimodal 抛出 NotSupportedException。宿主在构建客户端时呈现这一点,包括第一次连接和之后的 /tier 或 /speed。这些标志不使 Create 或 CreateMultimodal 接受音频或视频。CreateMultimodal 只在所选模型接受图像输入且没有内置工厂拥有该协议时使用。

IPluginClassifier 只在内置分支未命中之后运行。它为未知工具分配风险和权限。它不重新分类 read、bash 或其他内置名称。

IPluginCommand 添加一个 /name 动词。内置动词及其别名优先。名称使用与工具名称相同的模式。IPluginOutput.Write 和 Fail 变成会话说明。

IPluginPlaceholder 添加一个 {{name}} token。名称是 1–64 个字符:一个字母,然后是字母、数字或 _。匹配不区分大小写。宿主拒绝它已经拥有的名称。两个插件不能共享一个名称;加载顺序中的第一个获胜,后面的带着说明被省略。

宿主每次绑定模板时调用 Resolve,包括附件、Review、压缩和图像描述。上下文携带模式、工作区、会话 id、审批模式、提供商、模型、当前目录快照,以及活动的会话和审查模型。宿主还没有的字符串为空。返回的文本按原样插入。该文本内的 token 不会再次展开。抛出或缺少返回会留下原始 token,并记录一条英文说明。

第一次 Attach 之前,该上下文上的快照为空。

IPluginStatusField 命名一个自定义状态行字段。用 PluginContribution.WithStatusFields 添加它。原来的构造函数保持不变。名称以字母开头,然后是字母、数字或单个连字符,至多 32 个字符。接纳不区分大小写,宿主存储小写形式。内置状态字段、on、off、reset、非法 token 或重复带着说明被省略。第一个加载的插件获胜。

宿主不把该字段放在自适应状态栏、进度行、/status 或 /stats 上。操作者把小写名称加到 statusLine 或 /statusline。插件未加载时已保存的名称被保留;自定义行省略它,/statusline 把它标为不可用。

数据目录之后,当此插件至少一个字段被接受时,宿主用 IPluginStatusUpdates 调用 AttachStatus。该调用对已加载实例发生一次。重新加载工具或更改工具审批不会再次调用它。之后的插件重新加载会先退役先前的汇。

Set 替换该字段的文本。Clear 或空白文本移除它。插件推送。宿主不轮询,也不运行状态计时器。插件可以从它已有的任何线程调用 Set,包括它拥有的计时器。宿主保留一行:控制字符和转义被丢弃,换行和制表符变成空格,超过 64 个字符的文本被截断。/statusline 显示的描述至多 80 个字符。相同文本不会再次发布。此插件未注册的名称被忽略,且该名称只被说明一次。来自较旧目录的汇忽略之后的调用。如果 AttachStatus 抛出,该汇被关闭,它已经发布的任何文本被移除。插件不选择颜色、标记或额外行。

IPluginEnvironment 是只读的。它不启用、禁用、调用或重排任何内容,也不声明加载依赖。

列表 包含
Plugins 每个已发现的插件目录,包括此插件。目录、来源(home 或 project)、显示名称、enabled、effective、loaded 和跳过原因。没有程序集路径、类型名或清单路径。
ToolSets 每个已发现的外部工具集,带相同的目录字段。
ExternalTools 已加载的工具:名称、集合、来源,以及工具在 Plan、Work 还是两者中。
Skills skill 工具现在可以加载的技能:名称和描述。每个名称一条。Skills 关闭时为空。没有文件正文,也没有路径。

清单无法说明时,enabled 为 null。该插件加载前显示名称为空。不列出内置工具。

AttachSession 与 Attach 一起运行,在 Contribute 之后,并在该插件实例再次加载时再次运行。对象保持活动。/model、/approval model、/approval thinking、/thinking、/tier 和 /speed 在下次读取时出现。宿主不为这些更改再次调用 AttachSession。

Session 携带提供商、协议、模型名称、上下文窗口、最大 token、temperature、top-p、图像输入、声明的音频输入、声明的视频输入、当前思考档位,以及所选服务层级和速度。音频和视频标志复制模型条目。它们不使回合、工具结果或 CreateMultimodal 接受音频或视频。default 和 off 是思考的宿主哨兵。其他思考值是模型列出的 effort token。Token 以小写存储并原样转发。max 和 maximum 是不同的 token。该槽未设置时,ServiceTier 和 Speed 为 null。列出的 default 是服务层级 token,不是思考哨兵。插件看到的是 token,不是 JSON 字段名。

Review.Independent 只在审查使用自己的模型时为 true。该模型的思考档位是其已存储的 thinkingEffort,未设置时为 default。其服务层级和速度是为该模型保存的 token。开关关闭时,审查使用会话模型,Model 为 null,已保存的提供商或模型名称被省略。事实不包括 API 密钥、端点、组织或项目。

PluginPlaceholderContext.Models 是同一活动视图。会话发布它之前为空。

模型调用花费操作者的凭据。它不进入记录、审批路径或回合预算。入口类型只在实现 IPluginModelClient 时收到客户端。宿主在加载时点名该插件,例如 Plugin 'Acme' can call the session and review models. 内置插件不收到这些客户端。

AttachClients 在 AttachSession 之后运行。客户端是同一提供商和模型上的新实例。它们与回合或审查内部的实例分开。

成员 含义
Session 会话模型的文本客户端。
Images 会话模型的图像客户端,该模型不接受图像时为 null。
IndependentReview 只在审查使用自己的模型时为 true。读取它不创建客户端。
Review IndependentReview 为 true 时审查模型的文本客户端。审查使用会话模型时为 null。

IndependentReview 为 true 且审查客户端无法创建时,读取 Review 失败。宿主让会话客户端留在原地。

第一次读取创建客户端。之后的读取返回该实例,直到宿主丢弃它。宿主在重建会话客户端时丢弃会话和图像客户端,并在重建审查客户端或开关关闭时丢弃审查客户端。那之后再次读取该属性。

IPluginClientFactory 仍是另一个方向。它为内置适配器不拥有的协议构建客户端。

保持自己运行时状态的插件实现 CrystalCode.Plugins.Data.IPluginDataDirectory。宿主在 Attach 之后调用 AttachDataDirectories(globalDataDirectory, projectDataDirectory),并在插件实例再次加载时再次调用。该接口是选择加入的,与 IPluginModelClient 相同。

全局目录是 {home}/data/plugins/<directory>,跨工作区共享。项目目录是 <workspace>/.crystal/data/plugins/<directory>,属于当前工作区。宿主在该调用前创建两者;无法创建的目录不会被报告,因此缺失时请自行创建。它们与 plugins/ 安装目录分开,也不是秘密存储:不要在那里写凭据,项目目录在工作区内。

实现 IHostTool 或 IHostMultimodalTool 的插件工具也在 ToolHostContext 上收到相同的两个目录。