Créer des plugins de canal
Ce guide vous accompagne dans la création d’un plugin de canal qui connecte OpenClaw à une plateforme de messagerie. À la fin, vous disposerez d’un canal fonctionnel avec sécurité des DM, appairage, threading des réponses, et messagerie sortante.Si vous n’avez encore créé aucun plugin OpenClaw, lisez d’abord
Getting Started pour la structure de package
de base et la configuration du manifeste.
Fonctionnement des plugins de canal
Les plugins de canal n’ont pas besoin de leurs propres outils send/edit/react. OpenClaw conserve un outilmessage partagé dans le core. Votre plugin possède :
- Config — résolution des comptes et assistant de configuration
- Security — politique DM et listes d’autorisation
- Pairing — flux d’approbation des DM
- Session grammar — manière dont les ids de conversation propres au fournisseur se mappent aux chats de base, aux ids de thread, et aux fallbacks parents
- Outbound — envoi de texte, médias, et sondages vers la plateforme
- Threading — manière dont les réponses sont threadées
:thread:, et la répartition.
Si votre plateforme stocke une portée supplémentaire dans les ids de conversation, conservez cette analyse
dans le plugin avec messaging.resolveSessionConversation(...). C’est le hook canonique pour mapper
rawId vers l’id de conversation de base, l’id de thread optionnel, baseConversationId explicite,
et tout parentConversationCandidates.
Lorsque vous renvoyez parentConversationCandidates, gardez-les ordonnés du parent
le plus étroit vers la conversation parente/la conversation de base la plus large.
Les plugins intégrés qui ont besoin de la même analyse avant le démarrage du registre de canaux
peuvent aussi exposer un fichier session-key-api.ts de premier niveau avec un export
resolveSessionConversation(...) correspondant. Le core utilise cette surface sûre au bootstrap
uniquement lorsque le registre de plugins runtime n’est pas encore disponible.
messaging.resolveParentConversationCandidates(...) reste disponible comme fallback de compatibilité
hérité lorsqu’un plugin n’a besoin que de fallbacks parents au-dessus de l’id générique/brut.
Si les deux hooks existent, le core utilise d’abord
resolveSessionConversation(...).parentConversationCandidates et ne retombe sur
resolveParentConversationCandidates(...) que lorsque le hook canonique
les omet.
Approbations et capacités des canaux
La plupart des plugins de canal n’ont pas besoin de code spécifique aux approbations.- Le core possède
/approvedans le même chat, les payloads partagés des boutons d’approbation, et la livraison de fallback générique. - Préférez un seul objet
approvalCapabilitysur le plugin de canal lorsque le canal a besoin d’un comportement spécifique aux approbations. ChannelPlugin.approvalsest supprimé. Placez les faits d’approbation de livraison/natifs/rendu/authentification surapprovalCapability.plugin.authsert uniquement à login/logout ; le core ne lit plus les hooks d’authentification d’approbation depuis cet objet.approvalCapability.authorizeActorActionetapprovalCapability.getActionAvailabilityStatesont la couture canonique pour l’authentification des approbations.- Utilisez
approvalCapability.getActionAvailabilityStatepour la disponibilité de l’authentification des approbations dans le même chat. - Si votre canal expose des approbations d’exécution natives, utilisez
approvalCapability.getExecInitiatingSurfaceStatepour l’état de la surface initiatrice/du client natif lorsqu’il diffère de l’authentification des approbations dans le même chat. Le core utilise ce hook spécifique à l’exécution pour distinguerenableddedisabled, décider si le canal initiateur prend en charge les approbations d’exécution natives, et inclure le canal dans les indications de fallback du client natif.createApproverRestrictedNativeApprovalCapability(...)remplit ce point pour le cas courant. - Utilisez
outbound.shouldSuppressLocalPayloadPromptououtbound.beforeDeliverPayloadpour le comportement du cycle de vie des payloads spécifique au canal, par exemple masquer les prompts d’approbation locale en double ou envoyer des indicateurs de frappe avant la livraison. - Utilisez
approvalCapability.deliveryuniquement pour le routage d’approbation natif ou la suppression de fallback. - Utilisez
approvalCapability.nativeRuntimepour les faits d’approbation native appartenant au canal. Gardez-le lazy sur les points d’entrée chauds du canal aveccreateLazyChannelApprovalNativeRuntimeAdapter(...), qui peut importer votre module runtime à la demande tout en laissant le core assembler le cycle de vie des approbations. - Utilisez
approvalCapability.renderuniquement lorsqu’un canal a réellement besoin de payloads d’approbation personnalisés au lieu du moteur de rendu partagé. - Utilisez
approvalCapability.describeExecApprovalSetuplorsque le canal veut que la réponse du chemin désactivé explique les paramètres de configuration exacts nécessaires pour activer les approbations d’exécution natives. Le hook reçoit{ channel, channelLabel, accountId }; les canaux à compte nommé doivent afficher des chemins à portée de compte tels quechannels.<channel>.accounts.<id>.execApprovals.*au lieu de valeurs par défaut de niveau supérieur. - Si un canal peut déduire des identités DM stables de type propriétaire à partir de la configuration existante, utilisez
createResolvedApproverActionAuthAdapterdepuisopenclaw/plugin-sdk/approval-runtimepour restreindre/approvedans le même chat sans ajouter de logique core spécifique aux approbations. - Si un canal a besoin d’une livraison d’approbation native, gardez le code du canal centré sur la normalisation de la cible ainsi que sur les faits de transport/présentation. Utilisez
createChannelExecApprovalProfile,createChannelNativeOriginTargetResolver,createChannelApproverDmTargetResolver, etcreateApproverRestrictedNativeApprovalCapabilitydepuisopenclaw/plugin-sdk/approval-runtime. Placez les faits spécifiques au canal derrièreapprovalCapability.nativeRuntime, idéalement viacreateChannelApprovalNativeRuntimeAdapter(...)oucreateLazyChannelApprovalNativeRuntimeAdapter(...), afin que le core puisse assembler le gestionnaire et posséder le filtrage des requêtes, le routage, la déduplication, l’expiration, l’abonnement gateway, et les avis « routed elsewhere ».nativeRuntimeest divisé en quelques coutures plus petites : availability— si le compte est configuré et si une requête doit être traitéepresentation— mapper le modèle de vue d’approbation partagé en payloads natifs en attente/résolus/expirés ou en actions finalestransport— préparer les cibles plus envoyer/mettre à jour/supprimer les messages d’approbation natifsinteractions— hooks optionnels de bind/unbind/clear-action pour les boutons ou réactions natifsobserve— hooks optionnels de diagnostic de livraison- Si le canal a besoin d’objets possédés par le runtime comme un client, un jeton, une app Bolt, ou un récepteur webhook, enregistrez-les via
openclaw/plugin-sdk/channel-runtime-context. Le registre générique de contexte runtime permet au core de bootstrapper des gestionnaires pilotés par capacité à partir de l’état de démarrage du canal sans ajouter de glue wrapper spécifique aux approbations. - Recourez à
createChannelApprovalHandleroucreateChannelNativeApprovalRuntimede niveau inférieur uniquement lorsque la couture pilotée par capacité n’est pas encore assez expressive. - Les canaux d’approbation native doivent router à la fois
accountIdetapprovalKindvia ces helpers.accountIdconserve la portée de la politique d’approbation multi-comptes sur le bon compte bot, etapprovalKindconserve le comportement d’approbation d’exécution vs plugin disponible pour le canal sans branches codées en dur dans le core. - Le core possède désormais aussi les avis de reroutage d’approbation. Les plugins de canal ne doivent pas envoyer leurs propres messages de suivi « approval went to DMs / another channel » depuis
createChannelNativeApprovalRuntime; exposez plutôt un routage précis de l’origine + DM de l’approbateur via les helpers partagés de capacité d’approbation et laissez le core agréger les livraisons réelles avant de publier tout avis dans le chat initiateur. - Préservez le type d’id d’approbation livré de bout en bout. Les clients natifs ne doivent pas deviner ni réécrire le routage d’approbation d’exécution vs plugin à partir d’un état local au canal.
- Différents types d’approbation peuvent intentionnellement exposer différentes surfaces natives.
Exemples intégrés actuels :
- Slack conserve le routage d’approbation natif disponible pour les ids d’exécution et de plugin.
- Matrix conserve le même routage DM/canal natif et la même UX par réaction pour les approbations d’exécution et de plugin, tout en permettant à l’authentification de différer selon le type d’approbation.
createApproverRestrictedNativeApprovalAdapterexiste toujours comme wrapper de compatibilité, mais le nouveau code doit préférer le builder de capacité et exposerapprovalCapabilitysur le plugin.
openclaw/plugin-sdk/approval-auth-runtimeopenclaw/plugin-sdk/approval-client-runtimeopenclaw/plugin-sdk/approval-delivery-runtimeopenclaw/plugin-sdk/approval-gateway-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/setup-runtime,
openclaw/plugin-sdk/setup-adapter-runtime,
openclaw/plugin-sdk/reply-runtime,
openclaw/plugin-sdk/reply-dispatch-runtime,
openclaw/plugin-sdk/reply-reference, et
openclaw/plugin-sdk/reply-chunking lorsque vous n’avez pas besoin de la surface
ombrelle plus large.
Pour la configuration en particulier :
openclaw/plugin-sdk/setup-runtimecouvre les helpers de configuration sûrs au runtime : adaptateurs de patch de configuration import-safe (createPatchedAccountSetupAdapter,createEnvPatchedAccountSetupAdapter,createSetupInputPresenceValidator), sortie de note de lookup,promptResolvedAllowFrom,splitSetupEntries, et les builders délégués de setup-proxyopenclaw/plugin-sdk/setup-adapter-runtimeest la couture étroite d’adaptateur sensible à l’environnement pourcreateEnvPatchedAccountSetupAdapteropenclaw/plugin-sdk/channel-setupcouvre les builders de configuration à installation optionnelle ainsi que quelques primitives sûres pour la configuration :createOptionalChannelSetupSurface,createOptionalChannelSetupAdapter,
channelEnvVars. Conservez les envVars runtime du canal ou les constantes locales
uniquement pour le texte destiné aux opérateurs.
createOptionalChannelSetupWizard, DEFAULT_ACCOUNT_ID,
createTopLevelChannelDmPolicy, setSetupChannelEnabled, et
splitSetupEntries
- utilisez la couture plus large
openclaw/plugin-sdk/setupuniquement lorsque vous avez aussi besoin des helpers partagés plus lourds de configuration/setup tels quemoveSingleAccountChannelSectionToDefaultAccount(...)
createOptionalChannelSetupSurface(...). L’adaptateur/l’assistant généré
échoue de manière fermée sur les écritures de configuration et la finalisation, et ils réutilisent
le même message d’installation requise dans la validation, la finalisation, et le texte du lien vers la documentation.
Pour les autres chemins chauds du canal, préférez les helpers étroits aux surfaces héritées plus larges :
openclaw/plugin-sdk/account-core,openclaw/plugin-sdk/account-id,openclaw/plugin-sdk/account-resolution, etopenclaw/plugin-sdk/account-helperspour la configuration multi-comptes et le fallback de compte par défautopenclaw/plugin-sdk/inbound-envelopeetopenclaw/plugin-sdk/inbound-reply-dispatchpour le câblage de route/enveloppe entrante et d’enregistrement-et-répartitionopenclaw/plugin-sdk/messaging-targetspour l’analyse/la correspondance des ciblesopenclaw/plugin-sdk/outbound-mediaetopenclaw/plugin-sdk/outbound-runtimepour le chargement des médias ainsi que les délégués d’identité/envoi sortantsopenclaw/plugin-sdk/thread-bindings-runtimepour le cycle de vie des liaisons de thread et l’enregistrement des adaptateursopenclaw/plugin-sdk/agent-media-payloaduniquement lorsqu’une disposition héritée des champs de payload agent/média est encore requiseopenclaw/plugin-sdk/telegram-command-configpour la normalisation des commandes personnalisées Telegram, la validation des doublons/conflits, et un contrat de configuration de commandes stable en fallback
Politique de mention entrante
Conservez la gestion des mentions entrantes séparée en deux couches :- collecte des preuves appartenant au plugin
- évaluation partagée de la politique
openclaw/plugin-sdk/channel-inbound pour la couche partagée.
Bon cas d’usage pour la logique locale au plugin :
- détection des réponses au bot
- détection des citations du bot
- vérifications de participation au thread
- exclusions des messages de service/système
- caches natifs à la plateforme nécessaires pour prouver la participation du bot
requireMention- résultat de mention explicite
- liste d’autorisation de mention implicite
- contournement de commande
- décision finale d’ignorer
- Calculez les faits de mention locaux.
- Transmettez ces faits à
resolveInboundMentionDecision({ facts, policy }). - Utilisez
decision.effectiveWasMentioned,decision.shouldBypassMention, etdecision.shouldSkipdans votre garde d’entrée.
api.runtime.channel.mentions expose les mêmes helpers partagés de mention pour
les plugins de canal intégrés qui dépendent déjà de l’injection runtime :
buildMentionRegexesmatchesMentionPatternsmatchesMentionWithExplicitimplicitMentionKindWhenresolveInboundMentionDecision
resolveMentionGating* restent sur
openclaw/plugin-sdk/channel-inbound uniquement comme exports de compatibilité. Le nouveau code
doit utiliser resolveInboundMentionDecision({ facts, policy }).
Procédure pas à pas
Package et manifeste
Créez les fichiers de plugin standard. Le champ
channel dans package.json est
ce qui en fait un plugin de canal. Pour la surface complète des métadonnées de package,
voir Plugin Setup and Config :Construire l’objet plugin de canal
L’interface
ChannelPlugin dispose de nombreuses surfaces d’adaptateur optionnelles. Commencez par
le minimum — id et setup — puis ajoutez des adaptateurs selon vos besoins.Créez src/channel.ts :src/channel.ts
Ce que createChatChannelPlugin fait pour vous
Ce que createChatChannelPlugin fait pour vous
Au lieu d’implémenter manuellement des interfaces d’adaptateur de bas niveau, vous transmettez
des options déclaratives et le builder les compose :
Vous pouvez aussi transmettre des objets d’adaptateur bruts à la place des options déclaratives
si vous avez besoin d’un contrôle total.
| Option | Ce qu’elle câble |
|---|---|
security.dm | Résolveur de sécurité DM à portée, dérivé des champs de configuration |
pairing.text | Flux d’appairage DM basé sur du texte avec échange de code |
threading | Résolveur de mode de réponse threadée (fixe, à portée de compte, ou personnalisé) |
outbound.attachedResults | Fonctions d’envoi qui renvoient des métadonnées de résultat (ids de message) |
Câbler le point d’entrée
Créez Placez les descripteurs CLI appartenant au canal dans
index.ts :index.ts
registerCliMetadata(...) afin qu’OpenClaw
puisse les afficher dans l’aide racine sans activer le runtime complet du canal,
tandis que les chargements complets normaux récupèrent toujours les mêmes descripteurs pour le véritable enregistrement des commandes.
Conservez registerFull(...) pour le travail réservé au runtime.
Si registerFull(...) enregistre des méthodes RPC gateway, utilisez un
préfixe spécifique au plugin. Les espaces de noms d’administration core (config.*,
exec.approvals.*, wizard.*, update.*) restent réservés et
se résolvent toujours vers operator.admin.
defineChannelPluginEntry gère automatiquement la séparation des modes d’enregistrement. Voir
Entry Points pour toutes les
options.Ajouter une entrée de configuration
Créez OpenClaw charge ceci au lieu du point d’entrée complet lorsque le canal est désactivé
ou non configuré. Cela évite de charger du code runtime lourd pendant les flux de configuration.
Voir Setup and Config pour plus de détails.
setup-entry.ts pour un chargement léger pendant l’onboarding :setup-entry.ts
Gérer les messages entrants
Votre plugin doit recevoir les messages de la plateforme et les transmettre à
OpenClaw. Le modèle typique est un webhook qui vérifie la requête et
la répartit via le gestionnaire entrant de votre canal :
La gestion des messages entrants est spécifique à chaque canal. Chaque plugin de canal possède
son propre pipeline entrant. Regardez les plugins de canal intégrés
(par exemple le package de plugin Microsoft Teams ou Google Chat) pour voir des modèles réels.
Tester
Écrivez des tests colocalisés dans Pour les helpers de test partagés, voir Testing.
src/channel.test.ts :src/channel.test.ts
Structure des fichiers
Sujets avancés
Options de threading
Modes de réponse fixes, à portée de compte, ou personnalisés
Intégration de l’outil message
describeMessageTool et découverte d’actions
Résolution de cible
inferTargetChatType, looksLikeId, resolveTarget
Helpers runtime
TTS, STT, média, sous-agent via api.runtime
Certaines coutures helper intégrées existent encore pour la maintenance des plugins intégrés et
la compatibilité. Elles ne constituent pas le modèle recommandé pour les nouveaux plugins de canal ;
préférez les sous-chemins génériques channel/setup/reply/runtime de la surface
commune du SDK, sauf si vous maintenez directement cette famille de plugins intégrés.
Étapes suivantes
- Provider Plugins — si votre plugin fournit aussi des modèles
- SDK Overview — référence complète des imports de sous-chemins
- SDK Testing — utilitaires de test et tests de contrat
- Plugin Manifest — schéma complet du manifeste