Appearance
6.4 扩展系统
@pi/coding-agent 允许第三方通过**扩展(Extension)**增强功能:自定义工具、监听事件、注入系统提示、自定义 UI 组件等。这一节讲扩展的两种形态和核心机制。
两种形态
- 内联扩展(InlineExtension):代码里直接定义,随应用一起加载。
- 文件扩展:从
extensions/目录发现并加载(.ts/.js),可独立分发(discoverAndLoadExtensions、loader.ts)。
Extension 的组织
一个扩展主要由两部分组成:
- 工具:通过
defineTool定义的ToolDefinition。 - 事件处理器:监听
ExtensionEvent(见下)。
ts
import { defineTool, type Extension } from "@earendil-works/pi-coding-agent";
import { Type } from "@earendil-works/pi-ai";
const myExtension: Extension = {
name: "my-extension",
config: { tools: [myTool] }, // 注册工具
// 或 handlers: { ... } 监听事件
};defineTool:定义自定义工具
defineTool(types.ts:509)让你用类型安全的方式定义 ToolDefinition:
ts
const myTool = defineTool({
name: "hello",
label: "问好",
description: "向指定的人问好",
parameters: Type.Object({ name: Type.String() }),
async execute(toolCallId, params) {
return { content: [{ type: "text", text: `你好,${params.name}` }], details: {} };
},
});ToolDefinition(types.ts:449)比 @pi/agent-core 的 AgentTool 多了**渲染(render)和状态(state)**能力,因为它要跑在 TUI/RPC 等具体 UI 里。
事件处理器:扩展能做什么
扩展通过 ExtensionEvent 事件总线挂接生命周期。常见事件(types.ts:562-646):
| 事件 | 时机 |
|---|---|
session_start / session_shutdown | 会话开始/结束 |
message_start / message_update / message_end | 消息生命周期 |
tool_call | 工具被调用前(可拦截/改写) |
session_compact / session_before_compact | 上下文压缩前后 |
session_before_fork / session_before_switch | 分支/切换前 |
before_provider_request / before_provider_headers | 发给模型前,可改请求/头 |
扩展可以:
- 自定义工具,模型可调用。
- 监听/改写会话事件(如自动记录、注入上下文)。
- 改系统提示(
BuildSystemPromptOptions)。 - 自定义 UI(
ExtensionUIDialogOptions、WidgetPlacement、mdx组件)。 - 定义斜杠命令(
/命令)。
runner.ts:事件的编排
ExtensionRunner(runner.ts)负责:
- 维护所有已加载扩展的处理器。
- 按事件类型分发给对应处理器。
- 处理返回结果(如
tool_call的拦截决定)。
前面 sdk.ts 里能看到 runner 的注入点:
ts
// sdk.ts
transformContext: async (messages) => runner.emitContext(messages), // 扩展可改上下文
transformHeaders: async (headers) => runner.emitBeforeProviderHeaders(headers), // 可改请求头与 @pi/agent-core 事件的关系
两层事件是叠加的,不是替代:
@pi/agent-core的AgentEvent:内核级,无 UI 概念。@pi/coding-agent的ExtensionEvent:产品级,含 UI/会话/压缩等。
AgentSession 订阅内核的 AgentEvent,翻译成产品级事件再分发给扩展。扩展一般只需关心产品级事件。
扩展的配置与发现
ts
// loader.ts
discoverAndLoadExtensions(agentDir) // 从 ~/.pi/agent/extensions 加载扩展可通过 Extension.meta 声明依赖、图标等。错误加载单个扩展不会使整个应用崩溃(有 LoadExtensionsResult 上报错误)。
小结
- 扩展 = 自定义工具 + 事件处理器,有内联/文件两种形态。
defineTool类型安全地定义工具。ExtensionEvent覆盖会话/消息/工具/压缩/请求全生命周期。ExtensionRunner负责分发与编排。- 扩展事件是内核事件的"产品化"包装。
真实源码位置
- 扩展类型:
packages/coding-agent/src/core/extensions/types.ts defineTool:types.ts:509- 事件定义:
types.ts:562-646 - 编排:
core/extensions/runner.ts - 加载:
core/extensions/loader.ts
下一步看 Demo:SDK 最小调用。