Начало работы с расширением Pi Agent
Расширения — самый мощный способ настройки Pi Agent: вы можете писать собственные инструменты, команды и обработчики событий на TypeScript.
Что такое расширение
Расширение — это модуль TypeScript, который может делать следующее.
| Способность | Описание | Типичное использование |
|---|---|---|
| Регистрацияпользовательских инструментов | Добавление новых вызываемых функций для ИИ | Запрашивать внутренние системы, читать/писать базы данных, оборачивать сторонние API |
| Регистрацияпользовательских команд | Вызывается пользователями через /command-name | Оборачивать типовые промпты, выполнять фиксированные рабочие процессы одним щелчком |
| Слушайтесобытия жизненного цикла | Вставляйте логику на различных этапах работы ИИ | Перехватывайте опасные команды, внедряйте контекст, записывайте журналы аудита |
| Регистрируйтегорячие клавиши | Привязывайте клавиши в терминальном интерфейсе | Быстро переключайте панели, запускайте часто используемые операции |
| Отображайтепользовательский интерфейс | Отрисовывайте интерактивные интерфейсы в терминале | Компоненты, такие как индикаторы выполнения, списки и диалоги подтверждения |
Ваше первое расширение: Hello World
Следующее расширение демонстрирует три возможности одновременно: прослушивание событий, регистрацию инструментов и регистрацию команд.
Пример
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
import { Type } from "typebox";
export default function (pi: ExtensionAPI) {
// Срабатывает при запуске сессии
pi.on("session_start", async (_event, ctx) => {
ctx.ui.notify("Моё расширение загружено!", "info");
});
// Перехват опасных команд
pi.on("tool_call", async (event, ctx) => {
if (event.toolName === "bash"
&& event.input.command?.includes("rm -rf")) {
const ok = await ctx.ui.confirm("Опасная операция!", "Вы уверены, что хотите выполнить rm -rf?");
if (!ok) return { block: true, reason: "Заблокировано пользователем" };
}
});
// Регистрация пользовательского инструмента
pi.registerTool({
name: "greet",
label: "Приветствие",
description: "Поприветствовать указанного человека",
parameters: Type.Object({
name: Type.String({ description: "Имя человека, которого нужно поприветствовать" }),
}),
async execute(toolCallId, params) {
return {
content: [{ type: "text", text:`Hello, ${params.name}!` }],
details: {},
};
},
});
// Зарегистрировать пользовательскую команду
pi.registerCommand("hello", {
description: "Поприветствовать мир",
handler: async (args, ctx) => {
ctx.ui.notify(`Hello ${args || "World"}!`, "info");
},
});
}
Проверка события в строке 13 использует простейшийevent.toolNameподход; вы также можете использовать type guards, чтобы сузить событие до конкретного типа события, см. главу «Система событий».
Запустите Pi Agent с параметром pi -e, чтобы загрузить это расширение для тестирования:
$ pi -e ~/.pi/agent/extensions/my-extension.ts Loading extension: /Users/example/.pi/agent/extensions/my-extension.ts my-extension 加载成功(1 个工具、1 个命令) 我的扩展已加载!
Последняя строка — это уведомление, появившееся в результате ctx.ui.notify в событии session_start, что указывает на то, что расширение вступило в силу.
Места загрузки расширений
Pi Agent автоматически обнаруживает расширения в нескольких фиксированных каталогах, а также вы можете явно указать пути.
| Расположение | Область действия | Описание |
|---|---|---|
| ~/.pi/agent/extensions/*.ts | Глобальный | Действует для всех проектов, обнаруживается автоматически |
| ~/.pi/agent/extensions/*/index.ts | Глобальный | Расширения с index.ts в подкаталогах |
| .pi/extensions/*.ts | Проект | Только текущий проект, требуется доверие к проекту |
| .pi/extensions/*/index.ts | Проект | Расширения в подкаталогах проекта |
Помимо аргументов командной строки, вы также можете записать массив путей в поле extensions файла settings.json; пути к каталогам разворачиваются по правилам каталогов расширений.
Пример
"extensions": [
"/Users/example/.pi/agent/extensions/quick-notify.ts",
"/Users/example/.pi/agent/extensions/team-tools"
]
}
Первый элемент — это однофайловое расширение, а второй — расширение в виде каталога; при фактическом использовании замените их на свои собственные расположения расширений.
Структура файлов расширения
Расширение может быть одним .ts-файлом или каталогом с входным файлом.
Однофайловое расширение
Простейшая форма, подходящая для небольших расширений:
~/.pi/agent/extensions/ └── my-extension.ts
Расширение в виде каталога (с index.ts)
Подходит для многофайловых расширений:
~/.pi/agent/extensions/
└── my-extension/
├── index.ts # 入口文件(导出默认函数)
├── tools.ts # 辅助模块
└── utils.ts # 工具函数
Расширение с зависимостями
Подходит для больших расширений, требующих пакетов npm:
~/.pi/agent/extensions/
└── my-extension/
├── package.json # 声明依赖和入口
├── node_modules/ # npm install 后生成
└── src/
└── index.ts
Расширения запускаются с вашими системными разрешениями и могут выполнять произвольный код.
Устанавливайте расширения только из надежных источников.。
Механизм загрузки расширений
Расширения загружаются через загрузчикjiti; код TypeScript может выполняться напрямую без компиляции.
Если ваша фабричная функция возвращает Promise, Pi Agent ждёт её завершения, прежде чем продолжить процесс запуска.
Это означает, что вы можете выполнять асинхронные операции во время инициализации расширения, например получение удалённой конфигурации.
Доступные пакеты для импорта
Эти пакеты встроены в Pi Agent и могут импортироваться напрямую в расширениях.
| Название пакета | Назначение |
|---|---|
| @earendil-works/pi-coding-agent | Типы расширений (ExtensionAPI, ExtensionContext и различные типы событий) |
| typebox | Определение схемы для параметров инструмента |
| @earendil-works/pi-ai | AI-инструменты (например, StringEnum, для перечислений, совместимых с Google) |
| @earendil-works/pi-tui | Компоненты TUI для пользовательского рендеринга |
Эти встроенные основные пакеты предоставляются самим Pi; просто перечислите их в peerDependencies и не включайте их в ваше расширение.
Ваши собственные runtime-зависимости должны быть указаны в поле dependencies файла package.json.
Когда Pi устанавливает пакеты расширений, по умолчанию выполняется production-установка (npm install --omit=dev), поэтому devDependencies недоступны во время выполнения.
Можно также использовать другие npm-пакеты — добавьте package.json в каталог расширения и выполните npm install.
Советы по разработке
Эти наработки помогут вам избежать лишних сложностей, особенно при выборе способа загрузки.
| Подход | Причина |
|---|---|
| Поместите расширение в каталог~/.pi/agent/extensions/the directory | Поддерживает горячую перезагрузку /reload, не нужно перезапускать сессию после изменений |
| pi -e ./path.tsТолько для временного тестирования | Для долгосрочного использования поместите расширение в каталог ~/.pi/agent/extensions/ и позвольте Pi Agent автоматически его обнаружить. |
| Не запускайте фоновые ресурсы в фабричной функции расширения | Процессы, сокеты, наблюдатели за файлами, таймеры и т. д. следует запускать в событии session_start |
| Очищайте ресурсы уровня сессии в событии session_shutdown | Избегайте оставшихся дескрипторов и слушателей после переключения сессий |
Дальнейшая интеграция
Помимо написания расширений, официальная команда также предоставляет два способа программной интеграции.
Проекты Node или TypeScript могут напрямую использовать экспортируемый SDK из@earendil-works/pi-coding-agent: используйте createAgentSession для создания сессий, подписки на события, а prompt — для отправки сообщений.
Этот подход выполняется в том же процессе, что и Pi, и имеет полные определения типов.
Для межъязыковых вызовов или когда требуется изоляция процессов, переключитесь наpi --mode rpcи взаимодействуйте с процессом Pi через протокол JSONL.
Оба способа используют ту же событийную модель, что и расширения; какой из них выбрать, в основном зависит от того, нужен ли вам независимый процесс.
Другие расширения