@lansenger-pm/openclaw-lansenger-channel 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.fr.md +301 -0
- package/README.md +299 -0
- package/README.zhHans.md +301 -0
- package/README.zhHant.md +301 -0
- package/README.zhHantHK.md +301 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/setup-entry.js +4 -0
- package/dist/setup-entry.js.map +1 -0
- package/dist/src/bindings.js +81 -0
- package/dist/src/bindings.js.map +1 -0
- package/dist/src/channel.js +511 -0
- package/dist/src/channel.js.map +1 -0
- package/dist/src/channel.test.js +295 -0
- package/dist/src/channel.test.js.map +1 -0
- package/dist/src/client.js +759 -0
- package/dist/src/client.js.map +1 -0
- package/dist/src/runtime.js +320 -0
- package/dist/src/runtime.js.map +1 -0
- package/index.ts +29 -0
- package/openclaw.plugin.json +145 -0
- package/package.json +85 -0
- package/setup-entry.ts +4 -0
- package/skills/lansenger-messaging/SKILL.md +212 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Lansenger OpenClaw Channel
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.fr.md
ADDED
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
[English](README.md) | [简体中文](README.zhHans.md) | [繁体中文](README.zhHant.md) | [繁体中文香港](README.zhHantHK.md) | [Français](README.fr.md)
|
|
2
|
+
|
|
3
|
+
# @lansenger/openclaw-lansenger-channel
|
|
4
|
+
|
|
5
|
+
> 💠 Plugin de canal Lansenger (蓝信) pour OpenClaw — WebSocket en entrée, HTTP API en sortie.
|
|
6
|
+
|
|
7
|
+
Connecte OpenClaw à Lansenger — une plateforme de messagerie d'entreprise — via une connexion longue WebSocket pour la réception de messages en temps réel et via l'API HTTP pour l'envoi de messages.
|
|
8
|
+
|
|
9
|
+
[](https://opensource.org/licenses/MIT)
|
|
10
|
+
[](https://www.typescriptlang.org/)
|
|
11
|
+
|
|
12
|
+
## Fonctionnalités
|
|
13
|
+
|
|
14
|
+
- **Messagerie en temps réel** via connexion longue WebSocket
|
|
15
|
+
- **Support multi-bot** — lier plusieurs bots Lansenger à différents agents OpenClaw
|
|
16
|
+
- **Support Markdown** utilisant le msgType `formatText` (par défaut)
|
|
17
|
+
- **Fichiers/Images/Vocaux** via le msgType `text` avec upload de médias
|
|
18
|
+
- **Cartes d'approbation** — workflow d'approbation interactif avec mises à jour de statut en place (en attente → approuvé/refusé)
|
|
19
|
+
- **Détection de langue** — détection automatique de la langue de l'utilisateur pour des réponses localisées
|
|
20
|
+
- **Routage des messages de groupe** — détection automatique et routage vers les API groupe/privé
|
|
21
|
+
- **@Mentions** — support @tout et @utilisateurs spécifiques dans les chats de groupe
|
|
22
|
+
- **Traitement des médias entrants** — téléchargement d'images/fichiers/vocaux, détection d'extension, chemins de fichiers pour l'agent
|
|
23
|
+
- **Révocation de messages** — révoquer les messages précédemment envoyés
|
|
24
|
+
- **Démarrage automatique** — la passerelle connecte automatiquement tous les comptes de bots configurés au démarrage
|
|
25
|
+
- **Zéro modification du core** — mode plugin pur, `git diff HEAD` reste INTACT
|
|
26
|
+
|
|
27
|
+
## Matrice de capacités des types de messages
|
|
28
|
+
|
|
29
|
+
| msgType | Markdown | @mention | Pièces jointes |
|
|
30
|
+
|-------------|----------|----------|-----------------|
|
|
31
|
+
| `text` | ✗ | ✓ | ✓ |
|
|
32
|
+
| `formatText`| ✓ | ✗ | ✗ |
|
|
33
|
+
|
|
34
|
+
**Stratégie par défaut** : utiliser `formatText` en priorité pour les réponses Markdown. Revenir à `text` pour les pièces jointes.
|
|
35
|
+
|
|
36
|
+
## Installation rapide
|
|
37
|
+
|
|
38
|
+
### Via npm (recommandé)
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npm install -g @lansenger/openclaw-lansenger-channel
|
|
42
|
+
openclaw plugins enable lansenger
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Installation manuelle
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
cd ~/.openclaw/npm
|
|
49
|
+
npm install @lansenger/openclaw-lansenger-channel
|
|
50
|
+
openclaw plugins enable lansenger
|
|
51
|
+
openclaw gateway restart
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Installation de développement (lien local)
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
cd /path/to/openclaw-lansenger-channel
|
|
58
|
+
npm install
|
|
59
|
+
openclaw plugins install --link
|
|
60
|
+
openclaw plugins enable lansenger
|
|
61
|
+
openclaw gateway restart
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Configuration
|
|
65
|
+
|
|
66
|
+
### Variables d'environnement requises
|
|
67
|
+
|
|
68
|
+
Ajoutez ces variables à `~/.openclaw/.env` ou à votre environnement :
|
|
69
|
+
|
|
70
|
+
| Variable | Description | Exemple |
|
|
71
|
+
|----------|-------------|---------|
|
|
72
|
+
| `LANSENGER_APP_ID` | App ID du bot personnel | `your-appid` |
|
|
73
|
+
| `LANSENGER_APP_SECRET` | App Secret du bot personnel | `57E718CA1CAC20F2...` |
|
|
74
|
+
| `LANSENGER_API_GATEWAY_URL` | URL de la passerelle API Lansenger (remplacement) | `https://open.e.lanxin.cn/open/apigw` |
|
|
75
|
+
|
|
76
|
+
### Obtenir les identifiants
|
|
77
|
+
|
|
78
|
+
**Client Lansenger (desktop)** → **Contacts** → **Bots** → **Bots personnels** → cliquer sur l'icône **ℹ️**
|
|
79
|
+
|
|
80
|
+
> ⚠️ **Le client mobile ne permet pas de voir les identifiants.** Utilisez uniquement le client desktop.
|
|
81
|
+
|
|
82
|
+
### Configuration optionnelle
|
|
83
|
+
|
|
84
|
+
```json
|
|
85
|
+
{
|
|
86
|
+
"channels": {
|
|
87
|
+
"lansenger": {
|
|
88
|
+
"appId": "your-appid",
|
|
89
|
+
"appSecret": "your-secret",
|
|
90
|
+
"apiGatewayUrl": "https://open.e.lanxin.cn/open/apigw",
|
|
91
|
+
"homeChannel": "lansenger",
|
|
92
|
+
"enabled": true,
|
|
93
|
+
"allowFrom": ["your-appid"],
|
|
94
|
+
"dmSecurity": "allowlist",
|
|
95
|
+
"accounts": {
|
|
96
|
+
"your-appid": {
|
|
97
|
+
"appId": "your-appid",
|
|
98
|
+
"appSecret": "...",
|
|
99
|
+
"agentId": "main",
|
|
100
|
+
"apiGatewayUrl": "https://open.e.lanxin.cn/open/apigw"
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
| Champ | Description | Valeur par défaut |
|
|
109
|
+
|-------|-------------|-------------------|
|
|
110
|
+
| `appId` | App ID du bot personnel | — |
|
|
111
|
+
| `appSecret` | App Secret du bot personnel | — |
|
|
112
|
+
| `apiGatewayUrl` | URL de la passerelle API | `https://open.e.lanxin.cn/open/apigw` |
|
|
113
|
+
| `homeChannel` | Canal par défaut pour le routage de l'agent | `lansenger` |
|
|
114
|
+
| `enabled` | Activer/désactiver le canal | `true` |
|
|
115
|
+
| `allowFrom` | IDs d'utilisateurs autorisés en DM | `[]` |
|
|
116
|
+
| `dmSecurity` | Politique DM : `allowlist`, `open`, `paired` | `allowlist` |
|
|
117
|
+
| `accounts` | Configuration multi-bot | — |
|
|
118
|
+
|
|
119
|
+
### Configuration multi-bot
|
|
120
|
+
|
|
121
|
+
Chaque bot peut être lié à un agent OpenClaw différent :
|
|
122
|
+
|
|
123
|
+
```json
|
|
124
|
+
{
|
|
125
|
+
"channels": {
|
|
126
|
+
"lansenger": {
|
|
127
|
+
"accounts": {
|
|
128
|
+
"bot1-appid": {
|
|
129
|
+
"appId": "your-appid",
|
|
130
|
+
"appSecret": "...",
|
|
131
|
+
"agentId": "main-agent",
|
|
132
|
+
"apiGatewayUrl": "https://open.e.lanxin.cn/open/apigw"
|
|
133
|
+
},
|
|
134
|
+
"bot2-appid": {
|
|
135
|
+
"appId": "your-other-appid",
|
|
136
|
+
"appSecret": "...",
|
|
137
|
+
"agentId": "test-agent"
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
"bindings": [
|
|
143
|
+
{ "match": { "channel": "lansenger", "accountId": "bot1-appid" }, "agentId": "main-agent" }
|
|
144
|
+
]
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Utilisation
|
|
149
|
+
|
|
150
|
+
La passerelle démarre automatiquement tous les comptes configurés au démarrage. La méthode `lansenger.start` est disponible pour démarrer dynamiquement des comptes supplémentaires.
|
|
151
|
+
|
|
152
|
+
### Démarrer la passerelle (dynamique)
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
openclaw gateway call lansenger.start
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Arrêter la passerelle
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
openclaw gateway call lansenger.stop
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Vérifier le statut
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
openclaw channels status
|
|
168
|
+
# ou
|
|
169
|
+
openclaw gateway call lansenger.status
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Lier un bot à un agent (dynamique)
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
openclaw gateway call lansenger.bind '{"botId":"your-appid","agentId":"main"}'
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Liste des liaisons
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
openclaw gateway call lansenger.bindings
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Délier un bot
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
openclaw gateway call lansenger.unbind '{"botId":"your-appid"}'
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## Types de messages supportés
|
|
191
|
+
|
|
192
|
+
| Type | Description | Méthode API | Direction |
|
|
193
|
+
|------|-------------|-------------|-----------|
|
|
194
|
+
| `text` | Texte brut avec @mentions et pièces jointes optionnelles | `sendText()` | Sortant |
|
|
195
|
+
| `formatText` | Texte au format Markdown (par défaut) | `sendFormatText()` | Sortant |
|
|
196
|
+
| `image` | Image avec légende optionnelle | `sendFile()` | Sortant |
|
|
197
|
+
| `file` | Tout fichier joint | `sendFile()` | Sortant |
|
|
198
|
+
| `video` | Vidéo jointe | `sendFile()` | Sortant |
|
|
199
|
+
| `voice` | Message vocal | `sendFile()` | Sortant |
|
|
200
|
+
| `linkCard` | Carte de prévisualisation de lien enrichi | `sendLinkCard()` | Sortant |
|
|
201
|
+
| `i18nAppCard` | Réservé pour usage futur ; carte 5 langues | `sendI18nAppCard()` | Sortant |
|
|
202
|
+
| `appCard` | Cartes d'approbation avec mises à jour de statut | `sendAppCard()` | Sortant |
|
|
203
|
+
| `appArticles` | Carte multi-articles | `sendAppArticles()` | Sortant |
|
|
204
|
+
| `position` | Message de localisation/position | — | Entrant uniquement |
|
|
205
|
+
| `card` | Message de carte générique | — | Entrant uniquement |
|
|
206
|
+
| `sticker` | Message sticker/emoji | — | Entrant uniquement |
|
|
207
|
+
|
|
208
|
+
## Traitement des médias entrants
|
|
209
|
+
|
|
210
|
+
Lorsque les utilisateurs envoient des images, vidéos, fichiers ou messages vocaux, le plugin :
|
|
211
|
+
|
|
212
|
+
1. Télécharge tous les `mediaIds` via l'API média Lansenger
|
|
213
|
+
2. Détecte l'extension de fichier depuis les en-têtes Content-Type/Content-Disposition (repli : octets magiques)
|
|
214
|
+
3. Enregistre dans des fichiers temporaires et attache les chemins à `InboundEvent.mediaPaths[]`
|
|
215
|
+
4. Ajoute un indice dans le texte de l'agent : « Fichiers joints sauvegardés localement — utilisez l'outil de lecture pour visualiser »
|
|
216
|
+
|
|
217
|
+
## Flux d'approbation
|
|
218
|
+
|
|
219
|
+
Le plugin supporte les cartes d'approbation :
|
|
220
|
+
- Les demandes d'approbation sont envoyées via **appCard** avec `isDynamic=true`
|
|
221
|
+
- Les mises à jour de statut (en attente → approuvé/refusé) mettent à jour la carte en place via **DynamicMsg**
|
|
222
|
+
- La langue détectée automatiquement détermine la langue de la carte (chinois ou anglais)
|
|
223
|
+
- **i18nAppCard** (5 langues) est réservé pour un usage futur et n'est pas utilisé pour l'approbation
|
|
224
|
+
|
|
225
|
+
## Développement
|
|
226
|
+
|
|
227
|
+
### Compilation
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
npm install
|
|
231
|
+
npx tsc
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### Tests
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
npx vitest run
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### Vérification de types
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
npx tsc --noEmit
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### Structure du projet
|
|
247
|
+
|
|
248
|
+
```
|
|
249
|
+
openclaw-lansenger-channel/
|
|
250
|
+
├── src/
|
|
251
|
+
│ ├── client.ts # Client API Lansenger (WS, HTTP, médias)
|
|
252
|
+
│ ├── channel.ts # Plugin de canal OpenClaw
|
|
253
|
+
│ ├── channel.test.ts # Tests du plugin de canal
|
|
254
|
+
│ ├── runtime.ts # Runtime passerelle (méthodes, handler entrant)
|
|
255
|
+
│ └── bindings.ts # Gestionnaire de liaisons multi-bot
|
|
256
|
+
├── skills/
|
|
257
|
+
│ └── lansenger-messaging/
|
|
258
|
+
│ └── SKILL.md # Stratégie de messagerie de l'agent
|
|
259
|
+
├── dist/ # JavaScript compilé
|
|
260
|
+
├── index.ts # Point d'entrée du plugin
|
|
261
|
+
├── setup-entry.ts # Point d'entrée de l'assistant de configuration
|
|
262
|
+
├── openclaw.plugin.json # Métadonnées du plugin & configuration GUI
|
|
263
|
+
├── package.json
|
|
264
|
+
└── tsconfig.json
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
## Dépannage
|
|
268
|
+
|
|
269
|
+
### "Le client mobile ne permet pas de voir les identifiants"
|
|
270
|
+
|
|
271
|
+
Utilisez uniquement le **client Lansenger (desktop)**. L'application mobile n'affiche pas les identifiants du bot.
|
|
272
|
+
|
|
273
|
+
### "No binding for botId"
|
|
274
|
+
|
|
275
|
+
Exécutez `lansenger.bind` pour lier le bot à un agent, ou configurez `agentId` dans la configuration du compte.
|
|
276
|
+
|
|
277
|
+
### Déconnexions WebSocket
|
|
278
|
+
|
|
279
|
+
Le plugin inclut une reconnexion automatique avec un backoff exponentiel (2s, 5s, 10s, 30s, 60s) et un heartbeat (ping toutes les 30s).
|
|
280
|
+
|
|
281
|
+
### formatText vs text
|
|
282
|
+
|
|
283
|
+
- Utilisez `formatText` pour les réponses Markdown (par défaut)
|
|
284
|
+
- Utilisez `text` pour les @mentions ou pièces jointes
|
|
285
|
+
- Pour les deux, envoyez deux messages distincts
|
|
286
|
+
|
|
287
|
+
### Échec de mise à jour dynamique de carte
|
|
288
|
+
|
|
289
|
+
Les mises à jour de statut d'approbation utilisent le format DynamicMsg appCard. La méthode `updateCardStatus()` gère cela automatiquement.
|
|
290
|
+
|
|
291
|
+
## Licence
|
|
292
|
+
|
|
293
|
+
MIT — voir [LICENSE](LICENSE).
|
|
294
|
+
|
|
295
|
+
## Contribuer
|
|
296
|
+
|
|
297
|
+
1. Fork le dépôt
|
|
298
|
+
2. Créer une branche de fonctionnalité
|
|
299
|
+
3. Effectuer vos modifications
|
|
300
|
+
4. Exécuter les tests : `npx vitest run`
|
|
301
|
+
5. Soumettre une pull request
|
package/README.md
ADDED
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
[English](README.md) | [简体中文](README.zhHans.md) | [繁体中文](README.zhHant.md) | [繁体中文香港](README.zhHantHK.md) | [Français](README.fr.md)
|
|
2
|
+
|
|
3
|
+
# @lansenger/openclaw-lansenger-channel
|
|
4
|
+
|
|
5
|
+
Lansenger (蓝信) channel plugin for OpenClaw — WebSocket inbound, HTTP API outbound.
|
|
6
|
+
|
|
7
|
+
[](https://opensource.org/licenses/MIT)
|
|
8
|
+
[](https://www.typescriptlang.org/)
|
|
9
|
+
|
|
10
|
+
## Features
|
|
11
|
+
|
|
12
|
+
- **Real-time messaging** via WebSocket long-connection
|
|
13
|
+
- **Multi-bot support** — bind multiple Lansenger bots to different OpenClaw agents
|
|
14
|
+
- **Markdown support** using `formatText` msgType (default)
|
|
15
|
+
- **File/Image/Voice attachments** via `text` msgType with media upload
|
|
16
|
+
- **Approval cards** — interactive approval workflow with in-place status updates (pending → approved/denied)
|
|
17
|
+
- **Language detection** — auto-detect user language from messages for localized responses
|
|
18
|
+
- **Group message routing** — auto-detect and route to group/private chat APIs
|
|
19
|
+
- **@Mentions** — support @all and @specific users in group chats
|
|
20
|
+
- **Inbound media processing** — download images/files/voice, detect extension, provide file paths to agent
|
|
21
|
+
- **Message revocation** — revoke previously sent messages
|
|
22
|
+
- **Auto-start** — gateway automatically connects all configured bot accounts on boot
|
|
23
|
+
- **Zero core modification** — pure plugin mode, `git diff HEAD` stays PRISTINE
|
|
24
|
+
|
|
25
|
+
## Message Type Capability Matrix
|
|
26
|
+
|
|
27
|
+
| msgType | Markdown | @mention | Attachments |
|
|
28
|
+
|-------------|----------|----------|-------------|
|
|
29
|
+
| `text` | ✗ | ✓ | ✓ |
|
|
30
|
+
| `formatText`| ✓ | ✗ | ✗ |
|
|
31
|
+
|
|
32
|
+
**Default strategy**: Use `formatText` first for Markdown replies. Fall back to `text` for attachments.
|
|
33
|
+
|
|
34
|
+
## Quick Install
|
|
35
|
+
|
|
36
|
+
### Via npm (recommended)
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
npm install -g @lansenger/openclaw-lansenger-channel
|
|
40
|
+
openclaw plugins enable lansenger
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Manual install
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
cd ~/.openclaw/npm
|
|
47
|
+
npm install @lansenger/openclaw-lansenger-channel
|
|
48
|
+
openclaw plugins enable lansenger
|
|
49
|
+
openclaw gateway restart
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Development install (linked)
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
cd /path/to/openclaw-lansenger-channel
|
|
56
|
+
npm install
|
|
57
|
+
openclaw plugins install --link
|
|
58
|
+
openclaw plugins enable lansenger
|
|
59
|
+
openclaw gateway restart
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Configuration
|
|
63
|
+
|
|
64
|
+
### Required Environment Variables
|
|
65
|
+
|
|
66
|
+
Add these to `~/.openclaw/.env` or your environment:
|
|
67
|
+
|
|
68
|
+
| Variable | Description | Example |
|
|
69
|
+
|----------|-------------|---------|
|
|
70
|
+
| `LANSENGER_APP_ID` | Personal bot App ID | `your-appid` |
|
|
71
|
+
| `LANSENGER_APP_SECRET` | Personal bot App Secret | `57E718CA1CAC20F2...` |
|
|
72
|
+
| `LANSENGER_API_GATEWAY_URL` | Lansenger API Gateway URL override | `https://open.e.lanxin.cn/open/apigw` |
|
|
73
|
+
|
|
74
|
+
### Get Credentials
|
|
75
|
+
|
|
76
|
+
**Lansenger Desktop** → **Contacts** → **Bots** → **Personal Bots** → click **ℹ️** icon
|
|
77
|
+
|
|
78
|
+
> ⚠️ **Mobile client does NOT support viewing credentials.** Use the desktop client only.
|
|
79
|
+
|
|
80
|
+
### Optional Configuration
|
|
81
|
+
|
|
82
|
+
```json
|
|
83
|
+
{
|
|
84
|
+
"channels": {
|
|
85
|
+
"lansenger": {
|
|
86
|
+
"appId": "your-appid",
|
|
87
|
+
"appSecret": "your-secret",
|
|
88
|
+
"apiGatewayUrl": "https://open.e.lanxin.cn/open/apigw",
|
|
89
|
+
"homeChannel": "lansenger",
|
|
90
|
+
"enabled": true,
|
|
91
|
+
"allowFrom": ["your-appid"],
|
|
92
|
+
"dmSecurity": "allowlist",
|
|
93
|
+
"accounts": {
|
|
94
|
+
"your-appid": {
|
|
95
|
+
"appId": "your-appid",
|
|
96
|
+
"appSecret": "...",
|
|
97
|
+
"agentId": "main",
|
|
98
|
+
"apiGatewayUrl": "https://open.e.lanxin.cn/open/apigw"
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
| Field | Description | Default |
|
|
107
|
+
|-------|-------------|---------|
|
|
108
|
+
| `appId` | Personal bot App ID | — |
|
|
109
|
+
| `appSecret` | Personal bot App Secret | — |
|
|
110
|
+
| `apiGatewayUrl` | API Gateway URL | `https://open.e.lanxin.cn/open/apigw` |
|
|
111
|
+
| `homeChannel` | Default channel for agent routing | `lansenger` |
|
|
112
|
+
| `enabled` | Enable/disable the channel | `true` |
|
|
113
|
+
| `allowFrom` | User IDs allowed to DM the bot | `[]` |
|
|
114
|
+
| `dmSecurity` | DM policy: `allowlist`, `open`, `paired` | `allowlist` |
|
|
115
|
+
| `accounts` | Multi-bot configuration | — |
|
|
116
|
+
|
|
117
|
+
### Multi-Bot Configuration
|
|
118
|
+
|
|
119
|
+
Each bot can be bound to a different OpenClaw agent:
|
|
120
|
+
|
|
121
|
+
```json
|
|
122
|
+
{
|
|
123
|
+
"channels": {
|
|
124
|
+
"lansenger": {
|
|
125
|
+
"accounts": {
|
|
126
|
+
"bot1-appid": {
|
|
127
|
+
"appId": "your-appid",
|
|
128
|
+
"appSecret": "...",
|
|
129
|
+
"agentId": "main-agent",
|
|
130
|
+
"apiGatewayUrl": "https://open.e.lanxin.cn/open/apigw"
|
|
131
|
+
},
|
|
132
|
+
"bot2-appid": {
|
|
133
|
+
"appId": "your-other-appid",
|
|
134
|
+
"appSecret": "...",
|
|
135
|
+
"agentId": "test-agent"
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
"bindings": [
|
|
141
|
+
{ "match": { "channel": "lansenger", "accountId": "bot1-appid" }, "agentId": "main-agent" }
|
|
142
|
+
]
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Usage
|
|
147
|
+
|
|
148
|
+
The gateway auto-starts all configured accounts on boot. The `lansenger.start` method is available for dynamic start of additional accounts.
|
|
149
|
+
|
|
150
|
+
### Start the gateway (dynamic)
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
openclaw gateway call lansenger.start
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Stop the gateway
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
openclaw gateway call lansenger.stop
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Check status
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
openclaw channels status
|
|
166
|
+
# or
|
|
167
|
+
openclaw gateway call lansenger.status
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Bind a bot to an agent (dynamic)
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
openclaw gateway call lansenger.bind '{"botId":"your-appid","agentId":"main"}'
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### List bindings
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
openclaw gateway call lansenger.bindings
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Unbind a bot
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
openclaw gateway call lansenger.unbind '{"botId":"your-appid"}'
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Supported Message Types
|
|
189
|
+
|
|
190
|
+
| Type | Description | API Method | Direction |
|
|
191
|
+
|------|-------------|------------|-----------|
|
|
192
|
+
| `text` | Plain text with optional @mentions and attachments | `sendText()` | Outbound |
|
|
193
|
+
| `formatText` | Markdown-formatted text (default) | `sendFormatText()` | Outbound |
|
|
194
|
+
| `image` | Image with optional caption | `sendFile()` | Outbound |
|
|
195
|
+
| `file` | Any file attachment | `sendFile()` | Outbound |
|
|
196
|
+
| `video` | Video attachment | `sendFile()` | Outbound |
|
|
197
|
+
| `voice` | Voice message | `sendFile()` | Outbound |
|
|
198
|
+
| `linkCard` | Rich link preview card | `sendLinkCard()` | Outbound |
|
|
199
|
+
| `i18nAppCard` | Reserved for future use; 5-language card | `sendI18nAppCard()` | Outbound |
|
|
200
|
+
| `appCard` | Approval cards with status updates | `sendAppCard()` | Outbound |
|
|
201
|
+
| `appArticles` | Multi-article card | `sendAppArticles()` | Outbound |
|
|
202
|
+
| `position` | Location/position message | — | Inbound-only |
|
|
203
|
+
| `card` | Generic card message | — | Inbound-only |
|
|
204
|
+
| `sticker` | Sticker/emoji message | — | Inbound-only |
|
|
205
|
+
|
|
206
|
+
## Inbound Media Handling
|
|
207
|
+
|
|
208
|
+
When users send images, videos, files, or voice messages, the plugin:
|
|
209
|
+
|
|
210
|
+
1. Downloads all `mediaIds` via the Lansenger media API
|
|
211
|
+
2. Detects file extension from Content-Type/Content-Disposition headers (fallback: magic bytes)
|
|
212
|
+
3. Saves to temp files and attaches paths to `InboundEvent.mediaPaths[]`
|
|
213
|
+
4. Adds a hint in agent text: "Attached files saved locally — use the read tool to view"
|
|
214
|
+
|
|
215
|
+
## Approval Workflow
|
|
216
|
+
|
|
217
|
+
The plugin supports approval workflow cards:
|
|
218
|
+
- Approval requests are sent as **appCard** with `isDynamic=true`
|
|
219
|
+
- Status updates (pending → approved/denied) update the card in-place via **DynamicMsg**
|
|
220
|
+
- Language detection: the card is sent in the user's detected language (Chinese or English)
|
|
221
|
+
- **i18nAppCard** (5-language) is reserved for future use but not currently used for approval
|
|
222
|
+
|
|
223
|
+
## Development
|
|
224
|
+
|
|
225
|
+
### Build
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
npm install
|
|
229
|
+
npx tsc
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### Test
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
npx vitest run
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### Typecheck
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
npx tsc --noEmit
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### Project Structure
|
|
245
|
+
|
|
246
|
+
```
|
|
247
|
+
openclaw-lansenger-channel/
|
|
248
|
+
├── src/
|
|
249
|
+
│ ├── client.ts # Lansenger API client (WS, HTTP, media)
|
|
250
|
+
│ ├── channel.ts # OpenClaw channel plugin
|
|
251
|
+
│ ├── channel.test.ts # Channel plugin tests
|
|
252
|
+
│ ├── runtime.ts # Gateway runtime (methods, inbound handler)
|
|
253
|
+
│ └── bindings.ts # Multi-bot binding manager
|
|
254
|
+
├── skills/
|
|
255
|
+
│ └── lansenger-messaging/
|
|
256
|
+
│ └── SKILL.md # Agent messaging strategy
|
|
257
|
+
├── dist/ # Compiled JavaScript
|
|
258
|
+
├── index.ts # Plugin entry point
|
|
259
|
+
├── setup-entry.ts # Setup wizard entry
|
|
260
|
+
├── openclaw.plugin.json # Plugin metadata & GUI config
|
|
261
|
+
├── package.json
|
|
262
|
+
└── tsconfig.json
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
## Troubleshooting
|
|
266
|
+
|
|
267
|
+
### "Mobile client does NOT support viewing credentials"
|
|
268
|
+
|
|
269
|
+
Use the **Lansenger Desktop** client only. The mobile app does not display bot credentials.
|
|
270
|
+
|
|
271
|
+
### "No binding for botId"
|
|
272
|
+
|
|
273
|
+
Run `lansenger.bind` to bind the bot to an agent, or configure `agentId` in the account config.
|
|
274
|
+
|
|
275
|
+
### WebSocket disconnects
|
|
276
|
+
|
|
277
|
+
The plugin includes automatic reconnection with exponential backoff (2s, 5s, 10s, 30s, 60s) and heartbeat (ping every 30s).
|
|
278
|
+
|
|
279
|
+
### formatText vs text
|
|
280
|
+
|
|
281
|
+
- Use `formatText` for Markdown replies (default)
|
|
282
|
+
- Use `text` for @mentions or attachments
|
|
283
|
+
- For both, send two separate messages
|
|
284
|
+
|
|
285
|
+
### Dynamic card update fails
|
|
286
|
+
|
|
287
|
+
Approval status updates use the DynamicMsg appCard format. The `updateCardStatus()` method handles this automatically.
|
|
288
|
+
|
|
289
|
+
## License
|
|
290
|
+
|
|
291
|
+
MIT — see [LICENSE](LICENSE).
|
|
292
|
+
|
|
293
|
+
## Contributing
|
|
294
|
+
|
|
295
|
+
1. Fork the repository
|
|
296
|
+
2. Create a feature branch
|
|
297
|
+
3. Make your changes
|
|
298
|
+
4. Run tests: `npx vitest run`
|
|
299
|
+
5. Submit a pull request
|