Building plugins
Створення плагінів каналів
Цей посібник описує створення плагіна каналу, який підключає OpenClaw до платформи обміну повідомленнями: безпека особистих повідомлень, сполучення, ланцюжки відповідей і вихідні повідомлення.
За що відповідає ваш плагін
Плагіни каналів не реалізують інструменти надсилання, редагування чи реакцій; ядро надає один
спільний інструмент message. Ваш плагін відповідає за:
- Конфігурацію — визначення облікового запису й майстер налаштування
- Безпеку — політику особистих повідомлень і списки дозволених користувачів
- Сполучення — процес схвалення особистих повідомлень
- Граматику сеансів — відображення ідентифікаторів розмов постачальника на базові чати, ідентифікатори гілок і резервні батьківські варіанти
- Вихідні повідомлення — надсилання тексту, медіафайлів і опитувань на платформу
- Гілки — спосіб упорядкування відповідей у гілки
- Індикатор введення Heartbeat — необов’язкові сигнали введення/зайнятості для цілей доставки Heartbeat
Ядро відповідає за спільний інструмент повідомлень, підключення промптів, зовнішню форму ключа сеансу,
загальний облік :thread: і диспетчеризацію.
Адаптер повідомлень
Надайте адаптер message з defineChannelMessageAdapter із
openclaw/plugin-sdk/channel-outbound. Оголошуйте лише довготривалі можливості
остаточного надсилання, які фактично підтримує ваш нативний транспорт, і підкріпіть їх контрактним
тестом, що підтверджує нативний побічний ефект і повернену квитанцію. Спрямуйте надсилання тексту й медіафайлів
до тих самих транспортних функцій, які використовує застарілий адаптер outbound. Повний
контракт API, матрицю можливостей, правила квитанцій, фіналізацію попереднього перегляду наживо,
політику підтвердження отримання, тести й таблицю міграції див. у
API вихідних повідомлень каналу.
Якщо ваш наявний адаптер outbound уже має належні методи надсилання й
метадані можливостей, створіть адаптер message за допомогою
createChannelMessageAdapterFromOutbound(...), а не пишіть ще один
міст вручну. Надсилання через адаптер повертає значення MessageReceipt. Для застарілих ідентифікаторів отримуйте
їх за допомогою listMessageReceiptPlatformIds(...) або
resolveMessageReceiptPrimaryId(...), а не зберігайте паралельні поля messageIds.
Оголошуйте можливості передавання наживо й фіналізатора точно — ядро використовує їх, щоб визначити, що може робити канал, а розбіжність між оголошеною та фактичною поведінкою означає помилку контрактного тесту:
| Поверхня | Значення |
|---|---|
message.live.capabilities |
draftPreview, previewFinalization, progressUpdates, nativeStreaming, quietFinalization |
message.live.finalizer.capabilities |
finalEdit, normalFallback, discardPending, previewReceipt, retainOnAmbiguousFailure |
Канали, які фіналізують чернетку попереднього перегляду на місці, мають спрямовувати логіку середовища виконання
через defineFinalizableLivePreviewAdapter(...) разом із
deliverWithFinalizableLivePreviewAdapter(...) і підкріплювати оголошені
можливості тестами verifyChannelMessageLiveCapabilityAdapterProofs(...)
та verifyChannelMessageLiveFinalizerProofs(...), щоб нативний попередній перегляд,
перебіг, редагування, резервний варіант/збереження, очищення й поведінка квитанцій не могли непомітно
розійтися.
Обробники вхідних повідомлень, які відкладають підтвердження платформи, мають оголошувати
message.receive.defaultAckPolicy і supportedAckPolicies, а не приховувати
час підтвердження в локальному стані монітора. Охопіть кожну оголошену політику за допомогою
verifyChannelMessageReceiveAckPolicyAdapterProofs(...).
Застарілі допоміжні засоби відповідей, як-от dispatchInboundReplyWithBase і
recordInboundSessionAndDispatchReply, залишаються доступними для сумісних
диспетчерів. Не використовуйте їх у новому коді каналу; починайте з адаптера message,
квитанцій і допоміжних засобів життєвого циклу отримання/надсилання в
openclaw/plugin-sdk/channel-outbound.
Вхідне приймання (експериментальне)
Канали, що переносять авторизацію вхідних повідомлень, можуть використовувати експериментальний
підшлях openclaw/plugin-sdk/channel-ingress-runtime зі шляхів отримання
середовища виконання. Він приймає факти платформи, необроблені списки дозволених користувачів, дескриптори маршрутів, факти
команд і конфігурацію груп доступу, а потім повертає проєкції відправника, маршруту, команди й активації
разом із упорядкованим графом приймання, тоді як пошук на платформі й побічні
ефекти залишаються в плагіні. Зберігайте нормалізацію ідентичності плагіна в
дескрипторі, який передаєте засобу визначення; не серіалізуйте необроблені значення збігів із
визначеного стану чи рішення. Дизайн API,
межі відповідальності й вимоги до тестів див. у
API вхідних повідомлень каналу.
Індикатори введення
Якщо ваш канал підтримує індикатори введення поза відповідями на вхідні повідомлення, надайте
heartbeat.sendTyping(...) у плагіні каналу. Ядро викликає його з
визначеною ціллю доставки Heartbeat перед початком виконання моделі Heartbeat і
використовує спільний життєвий цикл підтримання активності та очищення індикатора введення. Додайте
heartbeat.clearTyping(...), якщо платформі потрібен явний сигнал зупинки.
Параметри джерел медіафайлів
Якщо ваш канал додає параметри інструмента повідомлень, що містять джерела медіафайлів, надайте
назви цих параметрів через plugin.actions.describeMessageTool(...).mediaSourceParams.
Ядро використовує цей явний список для нормалізації шляхів пісочниці й політики доступу до
вихідних медіафайлів, тому плагінам не потрібні спільні особливі випадки в ядрі для
параметрів аватарів, вкладень або обкладинок, специфічних для постачальника.
Надавайте перевагу мапі з ключами дій, як-от { "set-profile": ["avatarUrl", "avatarPath"] },
щоб непов’язані дії не успадковували аргументи медіафайлів іншої дії. Плоский масив
також підходить для параметрів, навмисно спільних для всіх наданих дій.
Канали, які мають надавати тимчасову публічну URL-адресу для отримання медіафайлу
на боці платформи, можуть використовувати createHostedOutboundMediaStore(...) із
openclaw/plugin-sdk/outbound-media зі сховищами стану плагіна. Зберігайте розбір
маршрутів платформи й контроль токенів у плагіні каналу; спільний допоміжний засіб
відповідає лише за завантаження медіафайлів, метадані строку дії, рядки фрагментів і очищення.
Формування нативного корисного навантаження
Якщо вашому каналу потрібне специфічне для постачальника формування message(action="send"),
надавайте перевагу actions.prepareSendPayload(...). Розміщуйте нативні картки, блоки, вбудовані об’єкти чи
інші довготривалі дані в payload.channelData.<channel>, а ядро нехай надсилає
їх через адаптер вихідних повідомлень/повідомлень. Використовуйте actions.handleAction(...) для надсилання
лише як резервний варіант сумісності для корисних навантажень, які неможливо серіалізувати й
повторно надіслати.
Граматика розмов сеансу
Якщо ваша платформа зберігає додаткову область видимості в ідентифікаторах розмов, залишайте такий розбір
у плагіні за допомогою messaging.resolveSessionConversation(...). Це
канонічний хук для відображення rawId на базовий ідентифікатор розмови, необов’язковий
ідентифікатор гілки, явний baseConversationId і будь-які
parentConversationCandidates. Повертаючи parentConversationCandidates,
упорядковуйте їх від найвужчої батьківської розмови до найширшої/базової.
messaging.resolveParentConversationCandidates(...) — це застарілий
резервний варіант сумісності для плагінів, яким потрібні лише батьківські резервні варіанти поверх
загального/необробленого ідентифікатора. Якщо існують обидва хуки, ядро спочатку використовує
resolveSessionConversation(...).parentConversationCandidates і переходить до
resolveParentConversationCandidates(...), лише якщо канонічний
хук їх не надає.
Вбудовані плагіни, яким потрібен такий самий розбір до запуску реєстру каналів,
можуть надавати файл верхнього рівня session-key-api.ts із відповідним
експортом resolveSessionConversation(...) (див. плагіни Feishu й Telegram).
Ядро використовує цю безпечну для початкового завантаження поверхню, лише коли реєстр плагінів
середовища виконання ще недоступний.
Використовуйте openclaw/plugin-sdk/channel-route, коли коду плагіна потрібно нормалізувати
поля, подібні до маршрутів, порівняти дочірню гілку з її батьківським маршрутом або створити
стабільний ключ дедуплікації з { channel, to, accountId, threadId }. Допоміжний засіб
нормалізує числові ідентифікатори гілок так само, як ядро, тому віддавайте йому перевагу над ситуативними
порівняннями String(threadId). Плагіни зі специфічною для постачальника граматикою цілей
мають надавати messaging.resolveOutboundSessionRoute(...), щоб ядро отримувало
нативну для постачальника ідентичність сеансу й гілки без обхідних засобів парсера.
Підтримка прив’язки розмов у межах облікового запису
Установіть conversationBindings.supportsCurrentConversationBinding, якщо канал
підтримує загальні прив’язки поточної розмови. createChatChannelPlugin(...)
за замовчуванням установлює цю статичну можливість у true.
Якщо підтримка відрізняється залежно від налаштованого облікового запису, також реалізуйте
conversationBindings.isCurrentConversationBindingSupported({ accountId }).
Ядро обчислює цей синхронний хук лише після ввімкнення статичної можливості.
Повернення false робить загальні операції визначення можливостей поточної розмови,
прив’язування, пошуку, переліку, оновлення й відв’язування недоступними для цього облікового запису.
Якщо хук не вказано, статична можливість застосовується до кожного облікового запису.
Визначайте відповідь із уже завантаженої конфігурації облікового запису або стану середовища виконання. Цей
хук керує лише загальними прив’язками поточної розмови; він не замінює
налаштовані правила прив’язки чи маршрутизацію сеансів, за яку відповідає плагін. Контрактні тести
мають охоплювати принаймні один підтримуваний і один непідтримуваний обліковий запис за допомогою
контракту ChannelPlugin["conversationBindings"], експортованого з
openclaw/plugin-sdk/channel-core.
Схвалення й можливості каналу
Більшості плагінів каналів не потрібен спеціальний код для схвалень. Ядро відповідає за
/approve у тому самому чаті, спільні корисні навантаження кнопок схвалення й загальну резервну доставку.
ChannelPlugin.approvals видалено; натомість розміщуйте факти доставки, нативного представлення, візуалізації та автентифікації
схвалень в одному об’єкті approvalCapability. plugin.auth призначено лише для входу й виходу —
ядро більше не зчитує з цього об’єкта хуки автентифікації схвалень.
Використовуйте approvalCapability.delivery лише для нативної маршрутизації схвалень або придушення
резервного варіанта, а approvalCapability.render — лише коли каналу справді потрібні
власні корисні навантаження схвалень замість спільного засобу візуалізації.
Автентифікація схвалень
approvalCapability.authorizeActorActionіapprovalCapability.getActionAvailabilityStateє канонічним інтерфейсом автентифікації схвалень.- Використовуйте
getActionAvailabilityStateдля доступності автентифікації схвалень у тому самому чаті. Зберігайте налаштованих схвалювачів доступними для/approve, навіть коли нативну доставку вимкнено; натомість використовуйте стан нативної початкової поверхні для вказівок щодо доставки/налаштування. - Якщо ваш канал надає нативні схвалення виконання, використовуйте
approvalCapability.getExecInitiatingSurfaceStateдля стану початкової поверхні/нативного клієнта, коли він відрізняється від автентифікації схвалень у тому самому чаті. Ядро використовує цей хук, специфічний для виконання, щоб розрізнятиenabledіdisabled, визначати, чи підтримує початковий канал нативні схвалення виконання, і включати канал до резервних указівок для нативного клієнта.createApproverRestrictedNativeApprovalCapability(...)заповнює це для типового випадку. - Якщо канал може визначати стабільні, подібні до власника ідентичності особистих повідомлень із наявної конфігурації,
використовуйте
createResolvedApproverActionAuthAdapterізopenclaw/plugin-sdk/approval-runtime, щоб обмежити/approveу тому самому чаті без додавання до ядра логіки, специфічної для схвалень. - Якщо власна автентифікація схвалень навмисно дозволяє лише резервний варіант у тому самому чаті, поверніть
markImplicitSameChatApprovalAuthorization({ authorized: true })ізopenclaw/plugin-sdk/approval-auth-runtime; інакше ядро вважатиме результат явною авторизацією схвалювача. - Якщо нативний зворотний виклик, за який відповідає канал, безпосередньо виконує схвалення, використовуйте
isImplicitSameChatApprovalAuthorization(...)перед виконанням, щоб неявний резервний варіант усе одно проходив через звичайну авторизацію суб’єкта каналу.
Життєвий цикл корисного навантаження й указівки з налаштування
- Використовуйте
outbound.shouldSuppressLocalPayloadPromptабоoutbound.beforeDeliverPayloadдля специфічної для каналу поведінки життєвого циклу корисного навантаження, як-от приховування дубльованих локальних запитів на схвалення або надсилання індикаторів введення перед доставкою. - Використовуйте
approvalCapability.describeExecApprovalSetup, коли канал хоче, щоб відповідь для вимкненого шляху пояснювала точні параметри конфігурації, потрібні для ввімкнення нативних схвалень виконання. Хук отримує{ channel, channelLabel, accountId }; канали з іменованими обліковими записами мають виводити шляхи в межах облікового запису, як-отchannels.<channel>.accounts.<id>.execApprovals.*, замість значень верхнього рівня за замовчуванням. - Використовуйте
approvalCapability.describePluginApprovalSetup, коли вказівки плагіна щодо помилки схвалення можна безпечно показувати для помилок відсутності маршруту й завершення часу очікування схвалення плагіна.createApproverRestrictedNativeApprovalCapability(...)не визначає цього зdescribeExecApprovalSetup; передавайте той самий допоміжний засіб явно, лише коли схвалення плагіна й виконання справді використовують однакове нативне налаштування.
Нативна доставка схвалень
Якщо каналу потрібна нативна доставка схвалень, зосередьте код каналу на
нормалізації цілі та фактах транспорту/представлення. Використовуйте
createChannelExecApprovalProfile, createChannelNativeOriginTargetResolver,
createChannelApproverDmTargetResolver і
createApproverRestrictedNativeApprovalCapability із
openclaw/plugin-sdk/approval-runtime. Розмістіть специфічні для каналу факти за
approvalCapability.nativeRuntime, бажано через
createChannelApprovalNativeRuntimeAdapter(...) або
createLazyChannelApprovalNativeRuntimeAdapter(...), щоб ядро могло зібрати
обробник і відповідати за фільтрування запитів, маршрутизацію, дедуплікацію, завершення строку дії, підписку
Gateway і сповіщення про маршрутизацію в інше місце.
nativeRuntime розділено на кілька менших інтерфейсів:
availability— чи налаштовано обліковий запис і чи слід обробляти запитpresentation— перетворення спільної моделі подання схвалення на нативні корисні навантаження зі станами очікування/вирішено/прострочено або кінцеві діїtransport— підготовка цілей, а також надсилання/оновлення/видалення нативних повідомлень про схваленняinteractions— необов’язкові обробники прив’язування/відв’язування/очищення дій для нативних кнопок або реакцій, а також необов’язковий обробникcancelDelivered. РеалізуйтеcancelDelivered, колиdeliverPendingреєструє внутрішньопроцесний або постійний стан (наприклад, сховище цілей реакцій), щоб цей стан можна було звільнити, якщо зупинка обробника скасовує доставлення до виконанняbindPending, або колиbindPendingне повертає дескрипторobserve— необов’язкові обробники діагностики доставлення
Інші допоміжні засоби схвалення:
- Використовуйте
createNativeApprovalChannelRouteGatesзopenclaw/plugin-sdk/approval-native-runtime, коли канал підтримує як нативне доставлення з джерела сеансу, так і явні цілі пересилання схвалень. Цей допоміжний засіб централізує вибір конфігурації схвалень, обробкуmode, фільтри агентів/сеансів, прив’язування облікового запису, зіставлення цілі сеансу та зіставлення списку цілей, тоді як виклики і надалі відповідають за ідентифікатор каналу, типовий режим пересилання, пошук облікового запису, перевірку ввімкнення транспорту, нормалізацію цілі та визначення цілі джерела ходу. Не використовуйте його для створення належних ядру типових політик каналу; явно передавайте задокументований типовий режим каналу. createChannelNativeOriginTargetResolverтипово використовує спільний засіб зіставлення маршрутів каналів для цілей{ to, accountId, threadId }. ПередавайтеtargetsMatchлише тоді, коли канал має специфічні для провайдера правила еквівалентності, як-от зіставлення префіксів часових позначок Slack. ПередавайтеnormalizeTargetForMatch, коли каналу потрібно канонізувати ідентифікатори провайдера до запуску типового засобу зіставлення маршрутів або спеціального зворотного викликуtargetsMatch, зберігаючи початкову ціль для доставлення. ВикористовуйтеnormalizeTargetлише тоді, коли потрібно канонізувати саму визначену ціль доставлення.- Якщо каналу потрібні належні середовищу виконання об’єкти, як-от клієнт, токен, застосунок Bolt
або приймач webhook, реєструйте їх через
openclaw/plugin-sdk/channel-runtime-context. Загальний реєстр контексту середовища виконання дає ядру змогу ініціалізувати керовані можливостями обробники зі стану запуску каналу без додавання спеціалізованих обгорток для схвалень. - Звертайтеся до низькорівневих
createChannelApprovalHandlerабоcreateChannelNativeApprovalRuntimeлише тоді, коли межа, керована можливостями, ще недостатньо виразна. - Нативні канали схвалення мають спрямовувати і
accountId, іapprovalKindчерез ці допоміжні засоби.accountIdобмежує політику схвалення для кількох облікових записів відповідним обліковим записом бота, аapprovalKindнадає каналу поведінку схвалення для exec і plugin без жорстко закодованих розгалужень у ядрі. - Ядро також відповідає за сповіщення про переспрямування схвалень. Плагіни каналів не повинні
надсилати власні подальші повідомлення «схвалення надіслано в особисті повідомлення / інший канал» із
createChannelNativeApprovalRuntime; натомість надавайте точну маршрутизацію від джерела + до особистих повідомлень особи, яка схвалює, через спільні допоміжні засоби можливостей схвалення й дозвольте ядру агрегувати фактичні доставлення, перш ніж публікувати будь-яке сповіщення назад у чат, що ініціював запит. - Зберігайте вид ідентифікатора доставленого схвалення наскрізно. Нативні клієнти не повинні вгадувати або переписувати маршрутизацію схвалень exec і plugin на основі локального стану каналу.
- Передайте цей явний
approvalKindдоresolveApprovalOverGateway. Це використовує канонічний сервісapproval.resolveі повертає зареєстрованого переможця, коли інша поверхня відповідає першою. Старіший явний вхідresolveMethodзалишається для елементів керування на основі команд; нові нативні дії не повинні використовувати його або визначати вид з ідентифікатора. - Різні види схвалень можуть навмисно надавати різні нативні поверхні. Поточні вбудовані приклади: Matrix зберігає однакову нативну маршрутизацію особистих повідомлень/каналів і взаємодію з реакціями для схвалень exec і plugin, водночас дозволяючи автентифікації відрізнятися за видом схвалення; Slack зберігає доступність нативної маршрутизації схвалень як для ідентифікаторів exec, так і для ідентифікаторів plugin.
createApproverRestrictedNativeApprovalAdapterдосі існує як обгортка сумісності, але новий код має віддавати перевагу конструктору можливостей і надаватиapprovalCapabilityу плагіні.
Вужчі підшляхи середовища виконання схвалень
Для гарячих точок входу каналів віддавайте перевагу цим вужчим підшляхам замість ширшого
бареля approval-runtime, коли потрібна лише одна частина цього сімейства:
openclaw/plugin-sdk/approval-auth-runtimeopenclaw/plugin-sdk/approval-client-runtimeopenclaw/plugin-sdk/approval-delivery-runtimeopenclaw/plugin-sdk/approval-gateway-runtimeopenclaw/plugin-sdk/approval-reference-runtimeopenclaw/plugin-sdk/approval-handler-adapter-runtimeopenclaw/plugin-sdk/approval-handler-runtimeopenclaw/plugin-sdk/approval-native-runtimeopenclaw/plugin-sdk/approval-reply-runtimeopenclaw/plugin-sdk/channel-runtime-context
Так само віддавайте перевагу openclaw/plugin-sdk/reply-runtime,
openclaw/plugin-sdk/reply-dispatch-runtime,
openclaw/plugin-sdk/reply-reference і
openclaw/plugin-sdk/reply-chunking замість ширших узагальнювальних поверхонь, коли
вони не потрібні всі одночасно.
Підшляхи налаштування
openclaw/plugin-sdk/setup-runtimeохоплює безпечні для середовища виконання допоміжні засоби налаштування:createSetupTranslator, безпечні для імпорту адаптери виправлень налаштування (createPatchedAccountSetupAdapter,createEnvPatchedAccountSetupAdapter,createSetupInputPresenceValidator), виведення приміток пошуку,promptResolvedAllowFrom,splitSetupEntriesі делеговані конструктори проксі налаштування.openclaw/plugin-sdk/channel-setupохоплює конструктори налаштування необов’язкового встановлення, а також кілька безпечних для налаштування примітивів:createOptionalChannelSetupSurface,createOptionalChannelSetupAdapter,createOptionalChannelSetupWizard,DEFAULT_ACCOUNT_ID,createTopLevelChannelDmPolicy,setSetupChannelEnabledіsplitSetupEntries.- Використовуйте ширшу межу
openclaw/plugin-sdk/setupлише тоді, коли також потрібні важчі спільні допоміжні засоби налаштування/конфігурації, як-отmoveSingleAccountChannelSectionToDefaultAccount(...).
Якщо ваш канал лише має повідомляти «спочатку встановіть цей плагін» у поверхнях
налаштування, віддавайте перевагу createOptionalChannelSetupSurface(...). Згенеровані
адаптер/майстер безпечно припиняють роботу під час записування конфігурації та завершення, а також повторно використовують
те саме повідомлення про необхідність встановлення під час перевірки, завершення та копіювання
посилання на документацію.
Якщо ваш канал підтримує налаштування або автентифікацію через змінні середовища й загальні потоки
запуску/конфігурації мають знати назви цих змінних до завантаження середовища виконання, оголосіть їх у
маніфесті плагіна за допомогою channelEnvVars. Зберігайте envVars середовища виконання каналу або локальні
константи лише для тексту, призначеного операторам.
Якщо ваш канал може з’являтися в status, channels list, channels status або
скануваннях SecretRef до запуску середовища виконання плагіна, додайте openclaw.setupEntry у
package.json. Цю точку входу має бути безпечно імпортувати в шляхах команд
лише для читання, і вона має повертати метадані каналу, безпечний для налаштування адаптер
конфігурації, адаптер стану та метадані цілі секрету каналу, потрібні для цих
зведень. Не запускайте клієнти, слухачі або транспортні середовища виконання з точки
входу налаштування.
Також зберігайте вузьким шлях імпорту основної точки входу каналу. Виявлення може обчислювати
точку входу та модуль плагіна каналу для реєстрації можливостей без
активації каналу. Файли на кшталт channel-plugin-api.ts мають експортувати
об’єкт плагіна каналу без імпорту майстрів налаштування, транспортних
клієнтів, слухачів сокетів, засобів запуску підпроцесів або модулів запуску служб.
Розміщуйте ці частини середовища виконання в модулях, що завантажуються з registerFull(...), сетерах
середовища виконання або лінивих адаптерах можливостей.
Інші вузькі підшляхи каналів
Для інших гарячих шляхів каналів віддавайте перевагу вузьким допоміжним засобам замість ширших застарілих поверхонь:
openclaw/plugin-sdk/account-core,openclaw/plugin-sdk/account-id,openclaw/plugin-sdk/account-resolutionіopenclaw/plugin-sdk/account-helpersдля конфігурації кількох облікових записів і резервного вибору типового облікового записуopenclaw/plugin-sdk/inbound-envelopeіopenclaw/plugin-sdk/channel-inboundдля вхідного маршруту/конверта та зв’язування записування й диспетчеризаціїopenclaw/plugin-sdk/channel-targetsдля допоміжних засобів розбору цілейopenclaw/plugin-sdk/outbound-mediaдля завантаження медіафайлів іopenclaw/plugin-sdk/channel-outboundдля делегатів вихідної ідентичності/надсилання та планування корисного навантаженняbuildThreadAwareOutboundSessionRoute(...)зopenclaw/plugin-sdk/channel-core, коли вихідний маршрут має зберігати явнийreplyToId/threadIdабо відновлювати поточний сеанс:thread:після того, як базовий ключ сеансу все ще збігається. Плагіни провайдерів можуть перевизначати пріоритет, поведінку суфікса та нормалізацію ідентифікатора гілки, коли їхня платформа має нативну семантику доставлення в гілки.openclaw/plugin-sdk/thread-bindings-runtimeдля життєвого циклу прив’язування гілок і реєстрації адаптерівopenclaw/plugin-sdk/agent-media-payloadлише тоді, коли застаріле компонування полів корисного навантаження агента/медіафайлів усе ще потрібнеopenclaw/plugin-sdk/telegram-command-config(застаріле: жоден вбудований плагін не використовує його у робочому середовищі) для нормалізації спеціальних команд Telegram, перевірки дублікатів/конфліктів і контракту конфігурації команд зі стабільним резервним варіантом; для нового коду плагінів віддавайте перевагу локальній для плагіна обробці конфігурації команд
Каналам лише з автентифікацією зазвичай достатньо типового шляху: ядро обробляє схвалення, а плагін лише надає можливості вихідного надсилання/автентифікації. Нативні канали схвалення, як-от Matrix, Slack, Telegram і спеціальні транспортні засоби чатів, мають використовувати спільні нативні допоміжні засоби замість реалізації власного життєвого циклу схвалення.
Політика вхідних згадок
Розділяйте обробку вхідних згадок на два рівні:
- збирання доказів, що належить плагіну
- оцінювання спільної політики
Використовуйте openclaw/plugin-sdk/channel-mention-gating для рішень політики згадок.
Використовуйте openclaw/plugin-sdk/channel-inbound лише тоді, коли потрібен ширший
барель допоміжних засобів для вхідних даних.
Доцільно для локальної логіки плагіна:
- виявлення відповіді боту
- виявлення цитування бота
- перевірки участі в гілці
- виключення службових/системних повідомлень
- нативні для платформи кеші, потрібні для підтвердження участі бота
Доцільно для спільного допоміжного засобу:
requireMention- результат явної згадки
- список дозволених неявних згадок
- обхід для команд
- остаточне рішення про пропуск
Рекомендований потік:
- Обчисліть локальні факти про згадки.
- Передайте ці факти до
resolveInboundMentionDecision({ facts, policy }). - Використовуйте
decision.effectiveWasMentioned,decision.shouldBypassMentionіdecision.shouldSkipу вашому вхідному шлюзі.
implicitMentionKindWhen, matchesMentionWithExplicit, resolveInboundMentionDecision,} from "openclaw/plugin-sdk/channel-inbound"; const wasMentioned = matchesMentionWithExplicit({ text, mentionRegexes, explicit: { hasAnyMention, isExplicitlyMentioned, canResolveExplicit, },}); const facts = { canDetectMention: true, wasMentioned, hasAnyMention, implicitMentionKinds: [ ...implicitMentionKindWhen("reply_to_bot", isReplyToBot), ...implicitMentionKindWhen("quoted_bot", isQuoteOfBot), ],}; const decision = resolveInboundMentionDecision({ facts, policy: { isGroup, requireMention, allowedImplicitMentionKinds: requireExplicitMention ? [] : ["reply_to_bot", "quoted_bot"], allowTextCommands, hasControlCommand, commandAuthorized, },}); if (decision.shouldSkip) return;matchesMentionWithExplicit(...) повертає логічне значення. hasAnyMention,
isExplicitlyMentioned і canResolveExplicit надходять із власних нативних
метаданих згадок каналу (сутностей повідомлень, ознак відповіді боту тощо);
передавайте значення false/undefined, коли ваша платформа не може їх виявити.
api.runtime.channel.mentions надає ті самі спільні допоміжні засоби згадок для
вбудованих плагінів каналів, які вже залежать від ін’єкції середовища виконання:
buildMentionRegexes, matchesMentionPatterns, matchesMentionWithExplicit,
implicitMentionKindWhen, resolveInboundMentionDecision.
Якщо потрібні лише implicitMentionKindWhen і resolveInboundMentionDecision,
імпортуйте з openclaw/plugin-sdk/channel-mention-gating, щоб уникнути завантаження
непов’язаних допоміжних засобів середовища виконання для вхідних даних.
Покроковий огляд
Пакет і маніфест
Створіть стандартні файли плагіна. Поле channels у
openclaw.plugin.json (а не поле kind) позначає маніфест як
власника каналу. Повний перелік метаданих пакета див. у розділі
Налаштування та конфігурація плагіна:
{"name": "@myorg/openclaw-acme-chat","version": "1.0.0","type": "module","openclaw": { "extensions": ["./index.ts"], "setupEntry": "./setup-entry.ts", "channel": { "id": "acme-chat", "label": "Чат Acme", "blurb": "Підключіть OpenClaw до чату Acme." }}}{"id": "acme-chat","channels": ["acme-chat"],"name": "Чат Acme","description": "Плагін каналу чату Acme","configSchema": { "type": "object", "additionalProperties": false, "properties": {}},"channelConfigs": { "acme-chat": { "schema": { "type": "object", "additionalProperties": false, "properties": { "token": { "type": "string" }, "allowFrom": { "type": "array", "items": { "type": "string" } } } }, "uiHints": { "token": { "label": "Токен бота", "sensitive": true } } }}}configSchema перевіряє plugins.entries.acme-chat.config. Використовуйте його для
налаштувань, що належать плагіну й не є конфігурацією облікового запису каналу.
channelConfigs.acme-chat.schema перевіряє channels.acme-chat і є
джерелом холодного шляху, яке використовується схемою конфігурації, налаштуванням та інтерфейсом до
завантаження середовища виконання плагіна. Повний опис полів верхнього рівня
див. у розділі Маніфест плагіна.
Створення об’єкта плагіна каналу
Інтерфейс ChannelPlugin має багато необов’язкових поверхонь адаптера. Почніть із
мінімального набору — id, config і setup — та додавайте адаптери за
потреби.
Створіть src/channel.ts:
import { createChatChannelPlugin, createChannelPluginBase,} from "openclaw/plugin-sdk/channel-core";import type { OpenClawConfig } from "openclaw/plugin-sdk/channel-core";import { acmeChatApi } from "./client.js"; // клієнт API вашої платформи type ResolvedAccount = { accountId: string | null; token: string; allowFrom: string[]; dmPolicy: string | undefined;}; function resolveAccount( cfg: OpenClawConfig, accountId?: string | null,): ResolvedAccount { const section = (cfg.channels as Record<string, any>)?.["acme-chat"]; const token = section?.token; if (!token) throw new Error("acme-chat: токен обов’язковий"); return { accountId: accountId ?? null, token, allowFrom: section?.allowFrom ?? [], dmPolicy: section?.dmSecurity, };} export const acmeChatPlugin = createChatChannelPlugin<ResolvedAccount>({ base: createChannelPluginBase({ id: "acme-chat", // Визначення та перевірка облікового запису належать до `config`, а не до `setup`. // `setup` охоплює записи під час початкового налаштування (applyAccountConfig, validateInput). config: { listAccountIds: () => ["default"], resolveAccount, inspectAccount(cfg, accountId) { const section = (cfg.channels as Record<string, any>)?.["acme-chat"]; return { enabled: Boolean(section?.token), configured: Boolean(section?.token), tokenStatus: section?.token ? "available" : "missing", }; }, }, setup: { applyAccountConfig: ({ cfg, input }) => ({ ...cfg, channels: { ...cfg.channels, "acme-chat": { ...(cfg.channels as any)?.["acme-chat"], ...input }, }, }), }, }), // Безпека особистих повідомлень: хто може надсилати повідомлення боту security: { dm: { channelKey: "acme-chat", resolvePolicy: (account) => account.dmPolicy, resolveAllowFrom: (account) => account.allowFrom, defaultPolicy: "allowlist", }, }, // Сполучення: процес схвалення нових контактів для особистих повідомлень pairing: { text: { idLabel: "Ім’я користувача чату Acme", message: "Надішліть цей код, щоб підтвердити свою особу:", notify: async ({ target, code }) => { await acmeChatApi.sendDm(target, `Код сполучення: ${code}`); }, }, }, // Гілки: спосіб доставлення відповідей threading: { topLevelReplyToMode: "reply" }, // Вихідні повідомлення: надсилання повідомлень на платформу outbound: { attachedResults: { channel: "acme-chat", sendText: async (params) => { const result = await acmeChatApi.sendMessage( params.to, params.text, ); return { messageId: result.id }; }, }, base: { sendMedia: async (params) => { await acmeChatApi.sendFile(params.to, params.filePath); }, }, },});Для каналів, які приймають як канонічні ключі особистих повідомлень верхнього рівня, так і застарілі вкладені ключі, використовуйте допоміжні функції з plugin-sdk/channel-config-helpers: resolveChannelDmAccess, resolveChannelDmPolicy, resolveChannelDmAllowFrom і normalizeChannelDmPolicy надають локальним значенням облікового запису пріоритет над успадкованими кореневими значеннями. Поєднайте той самий засіб визначення з виправленням через doctor за допомогою normalizeLegacyDmAliases, щоб середовище виконання та міграція читали той самий контракт.
Що createChatChannelPlugin робить за вас
Замість реалізації низькорівневих інтерфейсів адаптерів вручну ви передаєте декларативні параметри, а побудовник їх компонуватиме:
| Параметр | Що він підключає |
|---|---|
security.dm |
Обмежений областю засіб визначення безпеки особистих повідомлень із полів конфігурації |
pairing.text |
Текстовий процес сполучення через особисті повідомлення з обміном кодом |
threading |
Засіб визначення режиму відповіді (фіксований, обмежений обліковим записом або власний) |
outbound.attachedResults |
Функції надсилання, що повертають метадані результату (ідентифікатори повідомлень); потребує сусіднього ідентифікатора channel, щоб ядро могло позначити повернений результат доставлення |
Якщо потрібен повний контроль, замість декларативних параметрів також можна передавати необроблені об’єкти адаптерів.
Необроблені вихідні адаптери можуть визначати функцію chunker(text, limit, ctx).
Необов’язковий ctx.formatting містить рішення щодо форматування під час доставлення,
як-от maxLinesPerMessage; застосуйте його перед надсиланням, щоб гілкування відповідей
і межі фрагментів одноразово визначалися спільним механізмом вихідного доставлення.
Контексти надсилання також містять replyToIdSource (implicit або explicit),
коли визначено нативну ціль відповіді, щоб допоміжні функції корисного навантаження могли зберігати
явні теги відповіді, не використовуючи неявний одноразовий слот відповіді.
Підключення точки входу
Створіть index.ts:
import { defineChannelPluginEntry } from "openclaw/plugin-sdk/channel-core";import { acmeChatPlugin } from "./src/channel.js"; export default defineChannelPluginEntry({ id: "acme-chat", name: "Чат Acme", description: "Плагін каналу чату Acme", plugin: acmeChatPlugin, registerCliMetadata(api) { api.registerCli( ({ program }) => { program .command("acme-chat") .description("Керування чатом Acme"); }, { descriptors: [ { name: "acme-chat", description: "Керування чатом Acme", hasSubcommands: false, }, ], }, ); }, registerFull(api) { api.registerGatewayMethod(/* ... */); },});Розміщуйте дескриптори CLI, що належать каналу, у registerCliMetadata(...), щоб OpenClaw
міг показувати їх у кореневій довідці без активації повного середовища виконання каналу,
тоді як звичайне повне завантаження й надалі використовуватиме ті самі дескриптори для фактичної
реєстрації команд. Залиште registerFull(...) для роботи лише під час виконання.
defineChannelPluginEntry автоматично обробляє поділ режимів реєстрації.
Якщо registerFull(...) реєструє методи RPC Gateway, використовуйте
префікс, специфічний для плагіна. Простори імен адміністрування ядра (config.*,
exec.approvals.*, wizard.*, update.*) залишаються зарезервованими та завжди
визначаються як operator.admin. Усі параметри див. у розділі
Точки входу.
Додавання точки входу налаштування
Створіть setup-entry.ts для полегшеного завантаження під час початкового налаштування:
import { defineSetupPluginEntry } from "openclaw/plugin-sdk/channel-core";import { acmeChatPlugin } from "./src/channel.js"; export default defineSetupPluginEntry(acmeChatPlugin);OpenClaw завантажує її замість повної точки входу, коли канал вимкнений або не налаштований. Це дає змогу не завантажувати важкий код середовища виконання під час процесів налаштування. Докладніше див. у розділі Налаштування та конфігурація.
Вбудовані канали робочого простору, які відокремлюють безпечні для налаштування експорти в допоміжні
модулі, можуть використовувати defineBundledChannelSetupEntry(...) з
openclaw/plugin-sdk/channel-entry-contract, коли їм також потрібен
явний засіб установлення середовища виконання під час налаштування.
Оброблення вхідних повідомлень
Плагін має отримувати повідомлення з платформи й переспрямовувати їх до OpenClaw. Типовий шаблон — Webhook, який перевіряє запит і передає його обробнику вхідних повідомлень каналу:
registerFull(api) { api.registerHttpRoute({ path: "/acme-chat/webhook", auth: "plugin", // автентифікація, керована плагіном (перевіряйте підписи самостійно) handler: async (req, res) => { const event = parseWebhookPayload(req); // Ваш обробник вхідних повідомлень передає повідомлення до OpenClaw. // Точне підключення залежить від SDK вашої платформи — // див. реальний приклад у пакеті вбудованого плагіна Microsoft Teams або Google Chat. await handleAcmeChatInbound(api, event); res.statusCode = 200; res.end("ok"); return true; }, });}Тестування
Пишіть тести поруч із кодом у src/channel.test.ts:
import { describe, it, expect } from "vitest";import { acmeChatPlugin } from "./channel.js"; describe("плагін acme-chat", () => { it("визначає обліковий запис із конфігурації", () => { const cfg = { channels: { "acme-chat": { token: "test-token", allowFrom: ["user1"] }, }, } as any; const account = acmeChatPlugin.config.resolveAccount(cfg, undefined); expect(account.token).toBe("test-token"); }); it("перевіряє обліковий запис без матеріалізації секретів", () => { const cfg = { channels: { "acme-chat": { token: "test-token" } }, } as any; const result = acmeChatPlugin.config.inspectAccount!(cfg, undefined); expect(result.configured).toBe(true); expect(result.tokenStatus).toBe("available"); }); it("повідомляє про відсутню конфігурацію", () => { const cfg = { channels: {} } as any; const result = acmeChatPlugin.config.inspectAccount!(cfg, undefined); expect(result.configured).toBe(false); });});pnpm test <bundled-plugin-root>/acme-chat/Спільні допоміжні засоби для тестування описано в розділі Тестування.
Структура файлів
<bundled-plugin-root>/acme-chat/├── package.json # метадані openclaw.channel├── openclaw.plugin.json # Маніфест зі схемою конфігурації├── index.ts # defineChannelPluginEntry├── setup-entry.ts # defineSetupPluginEntry├── api.ts # Загальнодоступні експорти (необов’язково)├── runtime-api.ts # Внутрішні експорти середовища виконання (необов’язково)└── src/ ├── channel.ts # ChannelPlugin через createChatChannelPlugin ├── channel.test.ts # Тести ├── client.ts # Клієнт API платформи └── runtime.ts # Сховище середовища виконання (за потреби)Розширені теми
Фіксовані, прив’язані до облікового запису або власні режими відповідей
describeMessageTool і виявлення дій
inferTargetChatType, looksLikeId, reservedLiterals, resolveTarget
TTS, STT, медіа, підагент через api.runtime
Спільний життєвий цикл вхідної події: отримання, визначення, запис, передавання, завершення
Наступні кроки
- Плагіни постачальників — якщо ваш плагін також надає моделі
- Огляд SDK — повний довідник імпорту підшляхів
- Тестування SDK — утиліти тестування та контрактні тести
- Маніфест плагіна — повна схема маніфесту