钩子、原始钩子与加载
钩子按插件加载顺序运行。下一个钩子看到前一个替换。同一条流水线包裹内置工具、其他插件和外部工具。抛出的钩子带着英文说明被跳过。
| 钩子 | 可以 | 不可以 |
|---|---|---|
OnSessionStartedAsync / OnSessionEndedAsync |
读取工作区根、会话 id 和审批模式 | 提示操作者,或写入 config.json |
OnPrompt |
向指令块追加文本 | 替换 Work、Plan 或 Review |
OnUserMessageAsync |
在用户消息存储前替换它 | 让已存储的消息为空,或为附带问题运行 |
OnTurnStartedAsync / OnTurnFinishedAsync |
读取已存储的用户文本、模式,以及回合结束时的停止原因 | 改变记录 |
TransformModelAsync |
为一次出站调用更改用户、助手或工具结果文本,或丢弃项上已有的图像引用 | 重排、添加或丢弃项,编辑系统消息,添加图像,或写入存档 |
OnModelResponseAsync |
读取一次已完成的 work、plan、side 或 compaction 调用的用途、结束原因、返回项和用量 | 改变记录、存档,或宿主使用的响应 |
OnToolCallAsync |
替换名称或参数 | 改变调用 id,跳过调用,或跳过审批 |
OnToolResultAsync |
替换文本结果,并在支持图像的回合上替换其图像 | 把审批标为已通过 |
OnApproval |
提高风险,或要求另一次提示 | 降低宿主风险,或自动放行 |
OnCompaction |
向摘要提示或摘要正文追加事实 | 丢弃历史,或替换压缩器 |
改写后的工具调用在运行前再次分类和审批。仅文本的回合忽略 OnToolResultAsync 返回的图像。图像类型是 image/png、image/jpeg、image/gif 和 image/webp。
TransformModelAsync 在每个原始钩子运行之后,看到 work、plan 或 side 请求的模型记录,以及即将被总结的较早回合。它看不到审批审查。返回的图像列表只能点名该项上已有的附件。已存储的记录和存档保持原样,OnUserMessageAsync 替换的文本除外。
OnModelResponseAsync 在这些调用之一返回之后、宿主提交该候选或运行其工具之前运行。审批审查不调用它。宿主保留它收到的候选。
TransformModelAsync 只改变那一次调用发送的项。已存储的记录和存档保持原样。改写用户、助手或工具结果文本可以使模型根据操作者并未存储的对话作答。重排、添加或丢弃项、改变角色或工具调用、或编辑系统消息的替换会带着英文说明被跳过。结构更改属于原始钩子。
会话开始在插件加载之后运行,并在另一个编码会话变为活动时再次运行。会话结束在会话关闭时、/clear、/resume 或 /fork 替换它时,以及 /cd 或 /space 重新加载之前运行。结束回调仍携带正在离开的工作区和会话。同时更改工作区的恢复是一次结束和一次开始。crystal run 在进程结束时关闭会话。
原始钩子是特权的低级扩展点。IPluginRawHook 是单独的接口。插件在 PluginContribution.RawHooks 上注册原始钩子,与 Hooks 分开。操作者不批准它们。宿主为每个注册了一个的插件写一条说明,例如 Plugin 'Acme' registered a raw hook.
原始钩子按插件加载顺序运行。下一个原始钩子看到前一个替换。抛出的原始钩子带着英文说明被跳过。宿主不把原始钩子约束在约束普通钩子的规则上。它只拒绝自己无法表示的内容。
| 原始钩子 | 可以 | 不可以 |
|---|---|---|
RebuildModelAsync |
对一次出站调用,丢弃、重排、添加或改写任何种类的项。这包括活动系统提示、角色、工具调用、工具结果和推理,并可以把调用与其结果拆开 | 重复项 id,返回空推理文本,点名会话不持有的图像,向无法携带图像的请求添加图像,或写入存档 |
RewritePrompt |
用任意字符串(包括空字符串)替换为 work、plan、review 或 compaction 组合的系统文本。Work 和 plan 文本成为活动系统消息并被存档 |
写入 ~/.crystal/prompts |
RewriteCompaction |
用任意字符串(包括空字符串)替换压缩用户提示,或被存储的摘要正文 | 选择折叠哪段历史,或替换压缩器 |
RewriteApproval |
在普通审批钩子之后,设置任意风险、任意权限、任意摘要,以及任一提示要求。审批策略随后使用该分类 | 跳过该策略 |
RebuildModelAsync 看到与 TransformModelAsync 相同的请求,并先运行。已存储的记录和存档保持原样。
- Id。 项保留宿主给它的 id。新项需要请求未使用的 id。以不同种类的项返回的 id 是新项。
- 新项。 新工具结果忽略其
Name,宿主从调用派生它。新推理只携带文本,没有提供商状态。改写已有推理的文本也会丢弃该状态。 - 图像。 宿主把图像字节存在会话中,并用标记引用它们。原始钩子可以保留、丢弃或移动请求中已有的附件,媒体类型相同。它不能创建图像。
PluginModelImage不携带字节。对新图像的支持已在计划中。只有用户消息和工具结果向模型携带图像。助手和系统消息上的图像变成纯文本。PluginModelRequest.AcceptsImages只对支持图像的模型上的 work 或 plan 调用为 true。仅文本的回合、附带问题和压缩从不发送图像,因此宿主跳过在那里添加图像的替换。 - 提供商规则。 宿主不检查提供商接受什么。把工具调用与其结果拆开,或移动系统提示的请求,可能被提供商拒绝。work 或 plan 调用在原始钩子更改其请求后失败时,宿主写一条说明,例如
Raw hook 'Acme' changed this model request. The failure may be related.该说明是提示,不是诊断。 - 提示文本。
OnPrompt仍然只追加。RewritePrompt然后替换该模式已组合的系统文本。任何返回的字符串都会被使用,包括空字符串。Work 和 plan 文本是会话存储的内容。~/.crystal/prompts下的文件保持操作者保存的样子。RebuildModelAsync之后仍可以更改一次出站调用的系统项,而不写入存档。 - 压缩文本。
OnCompaction仍然只追加。RewriteCompaction然后替换完整的压缩用户提示或已存储的摘要正文。空替换被保留。 - 审批。
OnApproval仍然只能提高风险或要求另一次提示。RewriteApproval然后替换分类,并可以降低风险、改变权限、改变摘要或清除提示要求。审批策略使用该结果。
之后会添加更多钩子方法。新方法在其行为被定义时加入 IPluginHook 或 IPluginRawHook。此构建不为它们预留空方法。插件是否彼此声明依赖,以及相关的加载问题,仍在考虑中,尚未决定。
每个插件得到一个不可收集的 AssemblyLoadContext。
共享程序集来自宿主:Crystal、Crystal.Tools、CrystalCode.Tools 和 CrystalCode.Plugins。其他依赖必须在插件目录内解析。宿主不探测 NuGet 缓存或工作区。
CrystalCode、CrystalCode.Engine、CrystalCode.Display 和 CrystalCode.Providers 被拒绝,包括作为入口程序集。该上下文不可收集。没有热重载、签名检查或市场。
- MCP。
- 可收集卸载和热重载。
- 替换内置协议、内置工具或内置斜杠动词。
- 外部工具集上的钩子。
- 插件和原始钩子之下的模块系统。以后的系统可能通过反射或其他机制触及宿主。其行为和所有权未定义,此构建不为它预留类型。