Начало работы с расширением Pi Agent

Расширения — самый мощный способ настройки Pi Agent: вы можете писать собственные инструменты, команды и обработчики событий на TypeScript.


Что такое расширение

Расширение — это модуль TypeScript, который может делать следующее.

СпособностьОписаниеТипичное использование
Регистрацияпользовательских инструментовДобавление новых вызываемых функций для ИИЗапрашивать внутренние системы, читать/писать базы данных, оборачивать сторонние API
Регистрацияпользовательских командВызывается пользователями через /command-nameОборачивать типовые промпты, выполнять фиксированные рабочие процессы одним щелчком
Слушайтесобытия жизненного циклаВставляйте логику на различных этапах работы ИИПерехватывайте опасные команды, внедряйте контекст, записывайте журналы аудита
Регистрируйтегорячие клавишиПривязывайте клавиши в терминальном интерфейсеБыстро переключайте панели, запускайте часто используемые операции
Отображайтепользовательский интерфейсОтрисовывайте интерактивные интерфейсы в терминалеКомпоненты, такие как индикаторы выполнения, списки и диалоги подтверждения

Ваше первое расширение: Hello World

Следующее расширение демонстрирует три возможности одновременно: прослушивание событий, регистрацию инструментов и регистрацию команд.

Пример

// Путь к файлу: ~/.pi/agent/extensions/my-extension.ts
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-aiAI-инструменты (например, 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.

Оба способа используют ту же событийную модель, что и расширения; какой из них выбрать, в основном зависит от того, нужен ли вам независимый процесс.

Другие расширения