ARTICLE · 989291
硬核拆解Pi Agent插件内核架构
掌握零侵入拦截大模型输入输出与工具调用的底层机制,轻松打造专属AIAgent插件。
1 最小扩展全流程实战

编写一个扩展只需导出一个默认工厂函数,函数接收pi(ExtensionAPI)实例完成事件监听与指令注册。以下示例实现斜杠命令、文本替换与高危工具拦截:

从加载到生效经历完整闭环:• 1. Agent 启动时扫描并加载该扩展文件,注册对应的事件处理器与命令。
• 2. 用户输入 /hello 时触发命令处理器,调用 UI 通知。
• 3. 模型生成回复后触发message_end,输出被自动替换为规范大写。
• 4. 模型尝试调用 Shell 执行删除指令时触发tool_call,返回 block=true 立即阻断操作。
2 扩展发现与沙箱加载

扩展加载流程由 discoverAndLoadExtensions 驱动,分为四个严密步骤:

系统首先创建运行时沙箱环境createExtensionRuntime()。初始阶段所有 Action 方法均为抛出异常的 Stub 占位函数,防止扩展在加载初始化阶段提前调用核心功能。
接着通过 jiti 动态加载扩展 TypeScript 模块,执行默认工厂函数,传入 API 实例:• pi.on() 注册的处理器被写入对应扩展的 handlers: Map<事件名,函数数组>。
• pi.registerCommand() 注册的命令被存入 commands: Map<命令名,命令定义>。
• pi.registerProvider() 注册的模型提供商存入 pendingProviderRegistrations 队列。
加载完成后,ExtensionRunner接收全部扩展实例,执行 bindCore() 将 Stub 替换为真实核心功能,同时清空并注册所有待处理的提供商。
3 核心分发器架构设计

ExtensionRunner 是事件分发与结果收集的核心协调器。内部存储结构高度精简:每个已加载扩展维护自己的事件映射表,ExtensionRunner按扩展加载顺序持有扩展实例列表。
每次调用 emit* 分发事件遵循通用执行链路:• 1.构建全新上下文:创建懒加载的ExtensionContext,包含当前工作目录、模型、UI句柄与会话管理器,通过 Getter 动态取值避免上下文过期。
• 2.两级有序遍历:优先按扩展加载顺序遍历实例,再按注册顺序遍历该扩展对应的 Handler 列表。
• 3.隔离执行:每个 Handler 包裹在独立 try/catch 块中。
• 4.无状态分发:分发器自身不保留事件执行状态,每次触发均从头按序推导最新状态。
4 输入拦截与三态流转

用户输入进入主流程前,首先经过 emitInput 拦截管道:

输入拦截支持三种明确的流转动作:

典型应用如自动解析 Issue 链接:

5 短路返回与安全拦截

短路返回模式适用于权限校验、危险动作阻断与关键决策事件。执行过程中一旦某个 Handler 返回终止信号,立即停止后续所有 Handler 及扩展的执行并输出结果。
涵盖事件与触发条件:• tool_call:Handler返回 { block: true, reason: string },立刻阻断工具调用。
• session_before_*:返回 { cancel: true },取消当前会话生命周期操作。
• user_bash:任意 Handler 返回非空结果即停止后续执行。
• project_trust:返回决策结果 trusted !==“undecided”时立即生效。
• input:返回 action:“handled”终止主链路调度。
此模式保证了安全策略的高优先级,任意安全拦截扩展均可在第一时间掐断高危链路。
6 链式修改与数据管道

链式修改模式将事件处理构造为标准管道流。前一个 Handler 的输出直接作为后一个 Handler 的输入,实现增量变更。
涵盖事件与修改规则:• message_end:依次修改生成消息的内容。要求返回消息的角色(Role)与原消息完全一致,否则自动丢弃该修改。
• tool_result:增量修正工具执行产物,支持修改 content、details、isError 及 usage 字段,修正值透传给下游。
• context / before_provider_request:全量替换上下文消息列表或请求Payload,后置插件基于前置插件的产物继续改造。
• input (transform):按序迭代修改输入文本与图片集。
7 聚合收集与原地修改

针对需要多方协同贡献数据的场景,分发器提供聚合收集与原地修改机制。
聚合收集模式:遍历所有 Handler 执行完成后集中归并数据。• before_agent_start:收集所有 Handler 返回的附加消息数组,系统提示词(SystemPrompt)采用最后一次非空修改值。
• resources_discover:聚合所有扩展声明的skillPaths、promptPaths、themePaths,同时绑定扩展自身物理路径。
原地修改与无结果触发:• before_provider_headers:采用原地修改设计,分发器不读取返回值,Handler直接修改传入的 headers 引用对象。
• session_shutdown:纯事件通知,遍历触发所有清理钩子,不收集任何返回值。
8 错误隔离与故障兜底

扩展运行稳定性由统一的异常隔离机制保障。单个 Handler 发生未捕获异常时,分发器执行如下兜底逻辑:

异常被封装为结构化的 ExtensionError 并推送给全局 onError 监听器。异常被完全局限在当前 Handler 内部,不会中断同事件的其他Handler,更不会导致主进程崩溃。
9 独立顶层特殊事件处理

在 ExtensionRunner 完整初始化之前,存在两个独立的顶层辅助函数处理特殊生命周期:
emitSessionShutdownEvent 在分发前调用 hasHandlers 检查。若无任何扩展注册监听器,直接返回跳过,避免在系统退出阶段创建无意义的上下文实例。
emitProjectTrustEvent 直接遍历扩展扫描结果LoadExtensionsResult。该函数用于扩展加载阶段的项目信任评估,只要遇到第一个非 undecided 的决策结果立即返回,从源头决定是否允许加载项目级扩展。
10 扩展优先的系统哲学

系统遵循扩展优于修改核心的设计理念,主工程保持轻量与高内聚,所有定制需求均可通过插件标准接口实现:
•功能注入:通过 pi.registerTool 与 pi.registerCommand 扩充 Agent 能力库与交互指令。
•链路干预:利用 before_provider_request 与 message_end 动态注入提示词、清洗上下文与过滤敏感输出。
•界面增强:利用上下文中的 ctx.ui.setWidget 与 ctx.ui.setStatus 渲染自定义交互控件。
•安全守护:在 project_trust 与 tool_call 注入鉴权规则,构筑安全沙箱。
开发者无需侵入核心代码库,即可构建出高度可控、安全可靠的专属 AI 协同工作流。