---
read_when:
    - Ви створюєте Plugin, якому потрібні before_tool_call, before_agent_reply, хуки повідомлень або хуки життєвого циклу
    - Потрібно блокувати, переписувати або вимагати схвалення для викликів інструментів із Plugin
    - Ви обираєте між внутрішніми хуками та хуками Plugin
summary: 'Хуки Plugin: перехоплюйте події життєвого циклу агента, інструмента, повідомлення, сесії та Gateway'
title: Хуки Plugin
x-i18n:
    generated_at: "2026-05-11T20:48:00Z"
    model: gpt-5.5
    provider: openai
    source_hash: b363b8ed7452f0d8bdb267d3eaa38f579d6d7cfb7ace2085ac35baf9b253b575
    source_path: plugins/hooks.md
    workflow: 16
---

Хуки Plugin є внутрішньопроцесними точками розширення для плагінів OpenClaw. Використовуйте їх,
коли плагіну потрібно перевіряти або змінювати запуски агента, виклики інструментів, потік повідомлень,
життєвий цикл сесії, маршрутизацію субагентів, встановлення або запуск Gateway.

Натомість використовуйте [внутрішні хуки](/uk/automation/hooks), коли вам потрібен невеликий
встановлений оператором скрипт `HOOK.md` для подій команд і Gateway, як-от
`/new`, `/reset`, `/stop`, `agent:bootstrap` або `gateway:startup`.

## Швидкий старт

Зареєструйте типізовані хуки плагіна за допомогою `api.on(...)` з точки входу вашого плагіна:

```typescript
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";

export default definePluginEntry({
  id: "tool-preflight",
  name: "Tool Preflight",
  register(api) {
    api.on(
      "before_tool_call",
      async (event) => {
        if (event.toolName !== "web_search") {
          return;
        }

        return {
          requireApproval: {
            title: "Run web search",
            description: `Allow search query: ${String(event.params.query ?? "")}`,
            severity: "info",
            timeoutMs: 60_000,
            timeoutBehavior: "deny",
          },
        };
      },
      { priority: 50 },
    );
  },
});
```

Обробники хуків виконуються послідовно у спадному порядку `priority`. Хуки з однаковим пріоритетом
зберігають порядок реєстрації.

`api.on(name, handler, opts?)` приймає:

- `priority` - порядок обробників (вищий виконується першим).
- `timeoutMs` - необов’язковий бюджет для окремого хука. Якщо його задано, виконавець хуків перериває цей
  обробник після завершення бюджету й переходить до наступного, замість того щоб
  дозволити повільному налаштуванню або відновленню даних використати налаштований для викликача тайм-аут моделі.
  Не вказуйте його, щоб використати стандартний тайм-аут спостереження/рішення, який
  виконавець хуків застосовує загально.

Оператори також можуть задавати бюджети хуків без виправлення коду плагіна:

```json
{
  "plugins": {
    "entries": {
      "my-plugin": {
        "hooks": {
          "timeoutMs": 30000,
          "timeouts": {
            "before_prompt_build": 90000,
            "agent_end": 60000
          }
        }
      }
    }
  }
}
```

`hooks.timeouts.<hookName>` перевизначає `hooks.timeoutMs`, який перевизначає
задане автором плагіна значення `api.on(..., { timeoutMs })`. Кожне налаштоване значення має
бути додатним цілим числом не більше ніж 600000 мілісекунд. Надавайте перевагу перевизначенням
для окремих хуків, якщо відомо, що вони повільні, щоб один плагін не отримував довший бюджет
усюди.

Кожен хук отримує `event.context.pluginConfig`, розв’язану конфігурацію для
плагіна, який зареєстрував цей обробник. Використовуйте її для рішень хука, яким потрібні
поточні параметри плагіна; OpenClaw впроваджує її для кожного обробника, не змінюючи
спільний об’єкт події, який бачать інші плагіни.

## Каталог хуків

Хуки згруповано за поверхнею, яку вони розширюють. Назви, виділені **жирним**, приймають
результат рішення (заблокувати, скасувати, перевизначити або вимагати схвалення); усі інші
призначені лише для спостереження.

**Хід агента**

- `before_model_resolve` - перевизначити провайдера або модель до завантаження повідомлень сесії
- `agent_turn_prepare` - спожити поставлені в чергу ін’єкції ходу плагіна й додати контекст того самого ходу перед хуками запиту
- `before_prompt_build` - додати динамічний контекст або текст системного запиту перед викликом моделі
- `before_agent_start` - комбінована фаза лише для сумісності; надавайте перевагу двом хукам вище
- **`before_agent_run`** - перевірити фінальний запит і повідомлення сесії перед надсиланням моделі та за потреби заблокувати запуск
- **`before_agent_reply`** - перервати хід моделі синтетичною відповіддю або тишею
- **`before_agent_finalize`** - перевірити природну фінальну відповідь і запросити ще один прохід моделі
- `agent_end` - спостерігати фінальні повідомлення, стан успіху та тривалість запуску
- `heartbeat_prompt_contribution` - додати контекст лише для Heartbeat для фонових моніторів і плагінів життєвого циклу

**Спостереження за розмовою**

- `model_call_started` / `model_call_ended` - спостерігати санітизовані метадані виклику провайдера/моделі, час, результат і обмежені хеші ідентифікаторів запитів без вмісту запиту чи відповіді
- `llm_input` - спостерігати вхідні дані провайдера (системний запит, запит, історія)
- `llm_output` - спостерігати вихідні дані провайдера

**Інструменти**

- **`before_tool_call`** - переписати параметри інструмента, заблокувати виконання або вимагати схвалення
- `after_tool_call` - спостерігати результати інструмента, помилки й тривалість
- **`tool_result_persist`** - переписати повідомлення асистента, створене з результату інструмента
- **`before_message_write`** - перевірити або заблокувати запис повідомлення, що виконується (рідко)

**Повідомлення й доставлення**

- **`inbound_claim`** - перехопити вхідне повідомлення перед маршрутизацією агента (синтетичні відповіді)
- `message_received` - спостерігати вхідний вміст, відправника, гілку та метадані
- **`message_sending`** - переписати вихідний вміст або скасувати доставлення
- `message_sent` - спостерігати успішне або невдале доставлення вихідного повідомлення
- **`before_dispatch`** - перевірити або переписати вихідне відправлення перед передаванням каналу
- **`reply_dispatch`** - брати участь у фінальному конвеєрі відправлення відповіді

**Сесії та Compaction**

- `session_start` / `session_end` - відстежувати межі життєвого циклу сесії. `reason` події є одним із `new`, `reset`, `idle`, `daily`, `compaction`, `deleted`, `shutdown`, `restart` або `unknown`. Значення `shutdown` і `restart` спрацьовують із фіналізатора завершення роботи Gateway, коли процес зупиняється або перезапускається, поки сесії ще активні, щоб нижчі плагіни (наприклад, сховища пам’яті або транскриптів) могли фіналізувати привидні рядки, які інакше залишилися б у відкритому стані після перезапусків. Фіналізатор обмежений, тому повільний плагін не може заблокувати SIGTERM/SIGINT.
- `before_compaction` / `after_compaction` - спостерігати або анотувати цикли Compaction
- `before_reset` - спостерігати події скидання сесії (`/reset`, програмні скидання)

**Субагенти**

- `subagent_spawning` / `subagent_delivery_target` / `subagent_spawned` / `subagent_ended` - координувати маршрутизацію субагентів і доставлення завершення

**Життєвий цикл**

- `gateway_start` / `gateway_stop` - запускати або зупиняти сервіси, що належать плагіну, разом із Gateway
- `cron_changed` - спостерігати зміни життєвого циклу Cron, що належать Gateway (додано, оновлено, видалено, запущено, завершено, заплановано)
- **`before_install`** - перевірити сканування встановлення навички або плагіна та за потреби заблокувати

## Політика викликів інструментів

`before_tool_call` отримує:

- `event.toolName`
- `event.params`
- необов’язкове `event.derivedPaths`, що містить найкращі можливі підказки цільових шляхів, отримані від хоста,
  для добре відомих оболонок інструментів, як-от `apply_patch`; коли вони присутні,
  ці шляхи можуть бути неповними або можуть надмірно приблизно описувати те, чого інструмент
  фактично торкнеться (наприклад, із некоректними або частковими вхідними даними)
- необов’язкове `event.runId`
- необов’язкове `event.toolCallId`
- поля контексту, як-от `ctx.agentId`, `ctx.sessionKey`, `ctx.sessionId`,
  `ctx.runId`, `ctx.jobId` (задається для запусків, керованих Cron), і діагностичне `ctx.trace`

Він може повернути:

```typescript
type BeforeToolCallResult = {
  params?: Record<string, unknown>;
  block?: boolean;
  blockReason?: string;
  requireApproval?: {
    title: string;
    description: string;
    severity?: "info" | "warning" | "critical";
    timeoutMs?: number;
    timeoutBehavior?: "allow" | "deny";
    pluginId?: string;
    onResolution?: (
      decision: "allow-once" | "allow-always" | "deny" | "timeout" | "cancelled",
    ) => Promise<void> | void;
  };
};
```

Правила:

- `block: true` є термінальним і пропускає обробники з нижчим пріоритетом.
- `block: false` трактується як відсутність рішення.
- `params` переписує параметри інструмента для виконання.
- `requireApproval` призупиняє запуск агента й запитує користувача через схвалення плагінів. Команда `/approve` може схвалювати як exec, так і схвалення плагінів.
- `block: true` з нижчим пріоритетом усе ще може заблокувати після того, як хук із вищим пріоритетом
  запросив схвалення.
- `onResolution` отримує розв’язане рішення схвалення - `allow-once`,
  `allow-always`, `deny`, `timeout` або `cancelled`.

Вбудовані плагіни, яким потрібна політика рівня хоста, можуть реєструвати довірені політики інструментів
за допомогою `api.registerTrustedToolPolicy(...)`. Вони виконуються перед звичайними
хуками `before_tool_call` і перед рішеннями зовнішніх плагінів. Використовуйте їх лише
для довірених хосту шлюзів, як-от політика робочого простору, контроль бюджету або
безпека зарезервованого робочого процесу. Зовнішні плагіни мають використовувати звичайні
хуки `before_tool_call`.

### Збереження результатів інструментів

Результати інструментів можуть містити структуровані `details` для рендерингу UI, діагностики,
маршрутизації медіа або метаданих, що належать плагіну. Розглядайте `details` як метадані виконання,
а не як вміст запиту:

- OpenClaw вилучає `toolResult.details` перед повторним відтворенням у провайдера та вхідними даними Compaction,
  щоб метадані не ставали контекстом моделі.
- Збережені записи сесії залишають лише обмежені `details`. Надмірно великі деталі
  замінюються компактним підсумком і `persistedDetailsTruncated: true`.
- `tool_result_persist` і `before_message_write` виконуються перед фінальним
  обмеженням збереження. Хуки все одно мають тримати повернені `details` малими й уникати
  розміщення тексту, релевантного для запиту, лише в `details`; розміщуйте видимий для моделі вихід інструмента
  в `content`.

## Хуки запитів і моделі

Використовуйте фазоспецифічні хуки для нових плагінів:

- `before_model_resolve`: отримує лише поточний запит і метадані вкладень.
  Повертає `providerOverride` або `modelOverride`.
- `agent_turn_prepare`: отримує поточний запит, підготовлені повідомлення сесії
  та будь-які одноразові поставлені в чергу ін’єкції, вилучені для цієї сесії. Повертає
  `prependContext` або `appendContext`.
- `before_prompt_build`: отримує поточний запит і повідомлення сесії.
  Повертає `prependContext`, `appendContext`, `systemPrompt`,
  `prependSystemContext` або `appendSystemContext`.
- `heartbeat_prompt_contribution`: виконується лише для ходів Heartbeat і повертає
  `prependContext` або `appendContext`. Він призначений для фонових моніторів,
  яким потрібно підсумовувати поточний стан, не змінюючи ходи, ініційовані користувачем.

`before_agent_start` залишається для сумісності. Надавайте перевагу явним хукам вище,
щоб ваш плагін не залежав від застарілої комбінованої фази.

`before_agent_run` виконується після побудови запиту й перед будь-якими вхідними даними моделі,
зокрема завантаженням локальних для запиту зображень і спостереженням `llm_input`. Він отримує
поточний користувацький ввід як `prompt`, а також завантажену історію сесії в `messages`
і активний системний запит. Поверніть `{ outcome: "block", reason, message? }`,
щоб зупинити запуск до того, як модель зможе прочитати запит. `reason` є внутрішнім;
`message` є заміною, видимою користувачу. Єдині підтримувані результати -
`pass` і `block`; непідтримувані форми рішень завершуються закрито.

Коли запуск заблоковано, OpenClaw зберігає лише текст заміни в
`message.content` плюс нечутливі метадані блокування, як-от ідентифікатор плагіна, що блокує,
і мітку часу. Оригінальний текст користувача не зберігається в транскрипті або майбутньому
контексті. Внутрішні причини блокування вважаються чутливими й виключаються з
транскрипта, історії, трансляції, журналу та діагностичних корисних навантажень. Для спостережуваності
слід використовувати санітизовані поля, як-от ідентифікатор блокувальника, результат, мітка часу або безпечна
категорія.

`before_agent_start` і `agent_end` містять `event.runId`, коли OpenClaw може
ідентифікувати активний запуск. Те саме значення також доступне в `ctx.runId`.
Запуски, керовані Cron, також надають `ctx.jobId` (ідентифікатор вихідного завдання Cron), щоб
хуки плагінів могли прив’язувати метрики, побічні ефекти або стан до конкретного запланованого
завдання.

Для запусків, що походять із каналу, `ctx.messageProvider` є поверхнею провайдера, як-от
`discord` або `telegram`, тоді як `ctx.channelId` є цільовим ідентифікатором розмови,
коли OpenClaw може вивести його з ключа сесії або метаданих доставлення.

`agent_end` є хуком спостереження й виконується за принципом fire-and-forget після ходу. Виконавець
хуків застосовує тайм-аут 30 секунд, щоб завислий плагін або кінцева точка вбудовування
не могли залишити проміс хука в очікуванні назавжди. Тайм-аут записується в журнал, і
OpenClaw продовжує роботу; він не скасовує мережеву роботу, що належить плагіну, якщо
плагін також не використовує власний сигнал переривання.

Використовуйте `model_call_started` і `model_call_ended` для телеметрії викликів провайдера, яка не повинна отримувати сирі prompts, історію, відповіді, заголовки, тіла запитів або ідентифікатори запитів провайдера. Ці хуки містять стабільні метадані, як-от `runId`, `callId`, `provider`, `model`, необов’язкові `api`/`transport`, кінцеві `durationMs`/`outcome` і `upstreamRequestIdHash`, коли OpenClaw може вивести обмежений hash ідентифікатора запиту провайдера.

`before_agent_finalize` запускається лише тоді, коли harness ось-ось прийме природну фінальну відповідь assistant. Це не шлях скасування `/stop`, і він не запускається, коли користувач перериває turn. Поверніть `{ action: "revise", reason }`, щоб попросити harness виконати ще один прохід моделі перед фіналізацією, `{ action:
"finalize", reason? }`, щоб примусово виконати фіналізацію, або не повертайте результат, щоб продовжити. Нативні хуки Codex `Stop` передаються в цей хук як рішення OpenClaw `before_agent_finalize`.

Коли повертається `action: "revise"`, plugins можуть включити метадані `retry`, щоб зробити додатковий прохід моделі обмеженим і безпечним для повторного відтворення:

```typescript
type BeforeAgentFinalizeRetry = {
  instruction: string;
  idempotencyKey?: string;
  maxAttempts?: number;
};
```

`instruction` додається до причини ревізії, надісланої до harness.
`idempotencyKey` дає хосту змогу рахувати повторні спроби для того самого запиту plugin у межах еквівалентних рішень фіналізації, а `maxAttempts` обмежує кількість додаткових проходів, які хост дозволить перед продовженням із природною фінальною відповіддю.

Non-bundled plugins, яким потрібні хуки сирої розмови (`before_model_resolve`,
`before_agent_reply`, `llm_input`, `llm_output`, `before_agent_finalize`,
`agent_end` або `before_agent_run`), мають задати:

```json
{
  "plugins": {
    "entries": {
      "my-plugin": {
        "hooks": {
          "allowConversationAccess": true
        }
      }
    }
  }
}
```

Хуки, що змінюють prompt, і тривалі ін’єкції наступного turn можна вимкнути для кожного plugin за допомогою `plugins.entries.<id>.hooks.allowPromptInjection=false`.

### Розширення сесії та ін’єкції наступного turn

Workflow plugins можуть зберігати невеликий JSON-сумісний стан сесії за допомогою `api.registerSessionExtension(...)` і оновлювати його через метод Gateway `sessions.pluginPatch`. Рядки сесій проєктують зареєстрований стан розширення через `pluginExtensions`, даючи Control UI та іншим клієнтам змогу відображати статус, яким володіє plugin, без знання внутрішньої реалізації plugin.

Використовуйте `api.enqueueNextTurnInjection(...)`, коли plugin потрібен тривалий контекст, який має потрапити в наступний turn моделі рівно один раз. OpenClaw вичерпує поставлені в чергу ін’єкції перед prompt-хуками, відкидає прострочені ін’єкції та дедуплікує за `idempotencyKey` для кожного plugin. Це правильний seam для відновлень після схвалення, підсумків політик, дельт фонового монітора та продовжень команд, які мають бути видимі моделі на наступному turn, але не повинні ставати постійним текстом system prompt.

Семантика очищення є частиною контракту. Колбеки очищення розширень сесії та очищення життєвого циклу runtime отримують `reset`, `delete`, `disable` або `restart`. Хост видаляє persistent стан розширення сесії plugin-власника та pending ін’єкції наступного turn для reset/delete/disable; restart зберігає тривалий стан сесії, тоді як колбеки очищення дають plugins змогу звільнити завдання планувальника, контекст виконання та інші позасмугові ресурси для старої генерації runtime.

## Хуки повідомлень

Використовуйте хуки повідомлень для routing на рівні каналу та політики доставлення:

- `message_received`: спостерігає вхідний вміст, відправника, `threadId`, `messageId`,
  `senderId`, необов’язкову кореляцію run/session і метадані.
- `message_sending`: переписує `content` або повертає `{ cancel: true }`.
- `message_sent`: спостерігає фінальний успіх або помилку.

Для TTS-відповідей лише з audio `content` може містити прихований озвучений transcript, навіть коли payload каналу не має видимого тексту/підпису. Переписування цього `content` оновлює лише transcript, видимий хуку; він не рендериться як media caption.

Контексти хуків повідомлень надають стабільні поля кореляції, коли вони доступні:
`ctx.sessionKey`, `ctx.runId`, `ctx.messageId`, `ctx.senderId`, `ctx.trace`,
`ctx.traceId`, `ctx.spanId`, `ctx.parentSpanId` і `ctx.callDepth`. Надавайте перевагу цим first-class полям перед читанням legacy metadata.

Надавайте перевагу typed полям `threadId` і `replyToId` перед використанням metadata, специфічних для каналу.

Правила ухвалення рішень:

- `message_sending` з `cancel: true` є terminal.
- `message_sending` з `cancel: false` вважається відсутністю рішення.
- Переписаний `content` продовжує передаватися хукам нижчого пріоритету, якщо пізніший хук не скасує доставлення.
- `message_sending` може повернути `cancelReason` і обмежені `metadata` разом зі скасуванням. Нові API життєвого циклу повідомлень показують це як suppressed результат доставлення з причиною `cancelled_by_message_sending_hook`; legacy direct delivery і надалі повертає порожній масив результатів для сумісності.
- `message_sent` призначений лише для спостереження. Помилки handler логуються й не змінюють результат доставлення.

## Хуки встановлення

`before_install` запускається після вбудованого сканування для встановлень skill і plugin. Поверніть додаткові знахідки або `{ block: true, blockReason }`, щоб зупинити встановлення.

`block: true` є terminal. `block: false` вважається відсутністю рішення.

## Життєвий цикл Gateway

Використовуйте `gateway_start` для сервісів plugin, яким потрібен стан, що належить Gateway. Контекст надає `ctx.config`, `ctx.workspaceDir` і `ctx.getCron?.()` для перевірки й оновлень cron. Використовуйте `gateway_stop`, щоб очистити довготривалі ресурси.

Не покладайтеся на внутрішній хук `gateway:startup` для runtime-сервісів, якими володіє plugin.

`cron_changed` спрацьовує для подій життєвого циклу cron, якими володіє gateway, з typed payload події, що охоплює причини `added`, `updated`, `removed`, `started`, `finished` і `scheduled`. Подія несе snapshot `PluginHookGatewayCronJob` (включно з `state.nextRunAtMs`, `state.lastRunStatus` і `state.lastError`, коли вони наявні) плюс `PluginHookGatewayCronDeliveryStatus` зі значенням `not-requested` | `delivered` | `not-delivered` | `unknown`. Події видалення все одно несуть snapshot видаленого завдання, щоб зовнішні планувальники могли узгодити стан. Використовуйте `ctx.getCron?.()` і `ctx.config` з runtime-контексту під час синхронізації зовнішніх wake schedulers, і тримайте OpenClaw як джерело істини для перевірок due та виконання.

## Майбутні припинення підтримки

Кілька поверхонь, суміжних із хуками, deprecated, але все ще підтримуються. Мігруйте до наступного major release:

- **Plaintext channel envelopes** у handler `inbound_claim` і `message_received`.
  Читайте `BodyForAgent` і структуровані блоки user-context замість parsing flat envelope text. Див.
  [Plaintext channel envelopes → BodyForAgent](/uk/plugins/sdk-migration#active-deprecations).
- **`before_agent_start`** зберігається для сумісності. Нові plugins мають використовувати
  `before_model_resolve` і `before_prompt_build` замість combined phase.
- **`onResolution` у `before_tool_call`** тепер використовує typed union
  `PluginApprovalResolution` (`allow-once` / `allow-always` / `deny` /
  `timeout` / `cancelled`) замість free-form `string`.

Повний список - реєстрація memory capability, provider thinking profile, external auth providers, provider discovery types, task runtime accessors і перейменування `command-auth` → `command-status` - див.
[Міграція Plugin SDK → Активні припинення підтримки](/uk/plugins/sdk-migration#active-deprecations).

## Пов’язане

- [Міграція Plugin SDK](/uk/plugins/sdk-migration) - активні припинення підтримки та графік видалення
- [Створення plugins](/uk/plugins/building-plugins)
- [Огляд Plugin SDK](/uk/plugins/sdk-overview)
- [Точки входу Plugin](/uk/plugins/sdk-entrypoints)
- [Внутрішні хуки](/uk/automation/hooks)
- [Внутрішня архітектура Plugin](/uk/plugins/architecture-internals)
