@chbo297/infoflow 2026.3.17 → 2026.5.4
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/README.md +24 -528
- package/dist/index.js +21 -0
- package/dist/src/accounts.js +110 -0
- package/dist/src/actions.js +386 -0
- package/dist/src/bot.js +1010 -0
- package/dist/src/channel.js +385 -0
- package/dist/src/infoflow-req-parse.js +394 -0
- package/dist/src/logging.js +102 -0
- package/dist/src/markdown-local-images.js +65 -0
- package/dist/src/media.js +318 -0
- package/dist/src/monitor.js +145 -0
- package/dist/src/reply-dispatcher.js +301 -0
- package/dist/src/runtime.js +10 -0
- package/dist/src/send.js +820 -0
- package/dist/src/sent-message-store.js +190 -0
- package/dist/src/targets.js +90 -0
- package/dist/src/types.js +4 -0
- package/dist/src/ws-receiver.js +378 -0
- package/openclaw.plugin.json +194 -0
- package/package.json +18 -3
- package/scripts/deploy.sh +215 -0
- package/src/accounts.ts +25 -3
- package/src/actions.ts +9 -3
- package/src/bot.ts +63 -20
- package/src/channel.ts +64 -45
- package/src/infoflow-req-parse.ts +58 -2
- package/src/infoflow-sdk.d.ts +12 -0
- package/src/monitor.ts +21 -2
- package/src/reply-dispatcher.ts +2 -5
- package/src/types.ts +11 -0
- package/src/ws-receiver.ts +482 -0
- package/tsconfig.build.json +6 -0
package/README.md
CHANGED
|
@@ -1,547 +1,43 @@
|
|
|
1
|
-
|
|
1
|
+
## OpenClaw Infoflow 插件(适配 OpenClaw 2026.5.4)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
这是一个 OpenClaw Channel Plugin,用于对接百度如流(Infoflow)消息平台。
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
### 目录结构
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
- `index.ts`: OpenClaw 插件入口(注册 channel + webhook 路由)
|
|
8
|
+
- `openclaw.plugin.json`: 插件 manifest(包含 `channelConfigs`,用于配置 schema/setup surfaces)
|
|
9
|
+
- `src/channel.ts`: ChannelPlugin 实现(account/config/security/groups/outbound/actions)
|
|
10
|
+
- `src/actions.ts`: message tool 的动作适配(send/delete 等)
|
|
11
|
+
- `src/monitor.ts`: webhook 入口与 account monitor(webhook / websocket 两种接收模式)
|
|
12
|
+
- `src/ws-receiver.ts`: WebSocket 接收器(动态加载 `@baidu/infoflow-sdk-nodejs`)
|
|
8
13
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
📦 **[npm](https://www.npmjs.com/package/@chbo297/infoflow)**
|
|
12
|
-
|
|
13
|
-
## 特性
|
|
14
|
-
|
|
15
|
-
- **私聊 & 群聊**消息接收与回复
|
|
16
|
-
- 群内 **@机器人** 检测,被 @提及 时自动回复
|
|
17
|
-
- **watchMentions(关注提及)**:监控指定人员被 @ 时,机器人作为其助手判断是否代为回复
|
|
18
|
-
- **watchRegex(正则匹配)**:按正则匹配群内聊天内容,命中时触发机器人回复
|
|
19
|
-
- **followUp(跟进回复)**:机器人回复后,在时间窗口内智能判断后续消息是否为追问,无需再次 @
|
|
20
|
-
- 五种 **replyMode(回复模式)**:从完全忽略到主动参与,灵活控制群内行为
|
|
21
|
-
- **按群独立配置**:每个群可设置不同的回复策略和系统提示词
|
|
22
|
-
- **多账号支持**:一个实例管理多个如流机器人
|
|
23
|
-
- **Agent 主动/定时发送**:LLM Agent 可主动或定时发送私聊消息、往群里发消息,支持 @指定用户或 @全员
|
|
24
|
-
- **Markdown 本地图片**:回复内容中的本地图片路径会自动转为图片消息发送
|
|
25
|
-
|
|
26
|
-
## 安装
|
|
27
|
-
|
|
28
|
-
### 通过 npm
|
|
14
|
+
### 构建与测试
|
|
29
15
|
|
|
30
16
|
```bash
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
```bash
|
|
37
|
-
openclaw plugins install ./path/to/openclaw-infoflow
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
## 环境要求
|
|
41
|
-
|
|
42
|
-
- OpenClaw **>= 2026.3.2**
|
|
43
|
-
|
|
44
|
-
## 快速开始
|
|
45
|
-
|
|
46
|
-
```json5
|
|
47
|
-
{
|
|
48
|
-
channels: {
|
|
49
|
-
infoflow: {
|
|
50
|
-
enabled: true,
|
|
51
|
-
apiHost: "https://apiin.im.baidu.com",
|
|
52
|
-
checkToken: "your-check-token",
|
|
53
|
-
encodingAESKey: "your-encoding-aes-key",
|
|
54
|
-
appKey: "your-app-key",
|
|
55
|
-
appSecret: "your-app-secret",
|
|
56
|
-
robotName: "MyBot", // 用于群内 @提及 检测
|
|
57
|
-
},
|
|
58
|
-
},
|
|
59
|
-
}
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
### Webhook 地址
|
|
63
|
-
|
|
64
|
-
将如流机器人的 webhook URL 配置为:
|
|
65
|
-
|
|
66
|
-
```
|
|
67
|
-
https://your-domain/webhook/infoflow
|
|
17
|
+
npm install
|
|
18
|
+
npm run typecheck
|
|
19
|
+
npm run test
|
|
20
|
+
npm run build
|
|
68
21
|
```
|
|
69
22
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
## 回复模式 (replyMode)
|
|
73
|
-
|
|
74
|
-
通过 `replyMode` 控制机器人在群聊中的参与程度,默认值为 `mention-and-watch`。
|
|
75
|
-
|
|
76
|
-
| 模式 | 行为 |
|
|
77
|
-
|------|------|
|
|
78
|
-
| `ignore` | 丢弃消息,不保存、不思考、不回复 |
|
|
79
|
-
| `record` | 仅保存到会话历史,不思考、不回复 |
|
|
80
|
-
| `mention-only` | 仅在机器人被 @提及 时回复 |
|
|
81
|
-
| `mention-and-watch` | 机器人被 @、或被关注的人被 @、或在跟进窗口内时回复 **(默认)** |
|
|
82
|
-
| `proactive` | 始终参与思考,可能主动回复所有消息 |
|
|
83
|
-
|
|
84
|
-
## 关注提及 (watchMentions)
|
|
85
|
-
|
|
86
|
-
配置需要关注的人员列表。当群内有人 @提及 列表中的人时,机器人作为其助手判断是否能代为回答。
|
|
87
|
-
|
|
88
|
-
```json5
|
|
89
|
-
{
|
|
90
|
-
channels: {
|
|
91
|
-
infoflow: {
|
|
92
|
-
watchMentions: ["alice01", "bob02"],
|
|
93
|
-
// 需配合 replyMode 为 "mention-and-watch" 或 "proactive"
|
|
94
|
-
},
|
|
95
|
-
},
|
|
96
|
-
}
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
**匹配优先级**:`userid` > `robotid`(数字)> 显示名称
|
|
100
|
-
|
|
101
|
-
**行为**:
|
|
102
|
-
- 机器人通过 LLM 判断是否有能力代为回答
|
|
103
|
-
- 如果有把握 → 直接回复
|
|
104
|
-
- 如果无法帮助 → 静默不回复
|
|
105
|
-
|
|
106
|
-
## 正则匹配 (watchRegex)
|
|
107
|
-
|
|
108
|
-
通过正则表达式匹配群内聊天内容,当消息文本命中任一正则时,会触发机器人参与并回复(需配合 `replyMode` 为 `mention-and-watch` 或 `proactive`)。`watchRegex` 可配置为**字符串**或**字符串数组**(多条正则,命中其一即触发)。可在顶层、账号或按群单独配置。
|
|
109
|
-
|
|
110
|
-
```json5
|
|
111
|
-
{
|
|
112
|
-
channels: {
|
|
113
|
-
infoflow: {
|
|
114
|
-
watchRegex: ["^(帮忙|请帮我)", "\\?$"], // 顶层:数组形式,多条正则
|
|
115
|
-
groups: {
|
|
116
|
-
"123456": {
|
|
117
|
-
watchRegex: "\\?$|怎么|如何", // 该群:单条正则,匹配以问号结尾或含「怎么」「如何」的消息
|
|
118
|
-
},
|
|
119
|
-
},
|
|
120
|
-
},
|
|
121
|
-
},
|
|
122
|
-
}
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
**说明**:正则采用 JavaScript 标准语法;与 watchMentions、@提及 等条件并列,任一满足即可触发回复判断。
|
|
126
|
-
|
|
127
|
-
## 跟进回复 (followUp)
|
|
128
|
-
|
|
129
|
-
机器人回复后,在 `followUpWindow` 时间窗口内(默认 300 秒),后续消息即使没有 @机器人 也会触发智能判断:
|
|
130
|
-
|
|
131
|
-
- 如果是同一话题的追问 → 继续回复
|
|
132
|
-
- 如果是无关的新话题 → 静默不回复
|
|
133
|
-
|
|
134
|
-
```json5
|
|
135
|
-
{
|
|
136
|
-
channels: {
|
|
137
|
-
infoflow: {
|
|
138
|
-
followUp: true, // 默认 true
|
|
139
|
-
followUpWindow: 300, // 秒,默认 300
|
|
140
|
-
},
|
|
141
|
-
},
|
|
142
|
-
}
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
## 按群配置 (groups)
|
|
146
|
-
|
|
147
|
-
可以为每个群设置独立的回复策略,覆盖全局默认值。
|
|
148
|
-
|
|
149
|
-
```json5
|
|
150
|
-
{
|
|
151
|
-
channels: {
|
|
152
|
-
infoflow: {
|
|
153
|
-
replyMode: "mention-and-watch", // 全局默认
|
|
154
|
-
groups: {
|
|
155
|
-
"123456": {
|
|
156
|
-
replyMode: "mention-and-watch",
|
|
157
|
-
watchMentions: ["team-lead01"],
|
|
158
|
-
watchRegex: "^(帮忙|求助)",
|
|
159
|
-
followUp: true,
|
|
160
|
-
followUpWindow: 600,
|
|
161
|
-
systemPrompt: "你是这个项目组的技术助手。",
|
|
162
|
-
},
|
|
163
|
-
"789012": {
|
|
164
|
-
replyMode: "record", // 此群仅记录不回复
|
|
165
|
-
},
|
|
166
|
-
},
|
|
167
|
-
},
|
|
168
|
-
},
|
|
169
|
-
}
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
**配置优先级**:群级别 > 账号级别 > 顶层默认值
|
|
173
|
-
|
|
174
|
-
## 访问控制
|
|
175
|
-
|
|
176
|
-
### 私聊策略 (dmPolicy)
|
|
177
|
-
|
|
178
|
-
| 值 | 说明 |
|
|
179
|
-
|---|------|
|
|
180
|
-
| `open` | 允许所有用户私聊(默认) |
|
|
181
|
-
| `pairing` | 需配对确认 |
|
|
182
|
-
| `allowlist` | 仅允许 `allowFrom` 列表中的用户 |
|
|
183
|
-
|
|
184
|
-
### 群聊策略 (groupPolicy)
|
|
185
|
-
|
|
186
|
-
| 值 | 说明 |
|
|
187
|
-
|---|------|
|
|
188
|
-
| `open` | 允许所有群触发(默认) |
|
|
189
|
-
| `allowlist` | 仅允许 `groupAllowFrom` 列表中的群 |
|
|
190
|
-
| `disabled` | 禁用群聊 |
|
|
191
|
-
|
|
192
|
-
## 多账号支持
|
|
193
|
-
|
|
194
|
-
```json5
|
|
195
|
-
{
|
|
196
|
-
channels: {
|
|
197
|
-
infoflow: {
|
|
198
|
-
enabled: true,
|
|
199
|
-
replyMode: "mention-and-watch", // 所有账号的默认值
|
|
200
|
-
accounts: {
|
|
201
|
-
work: {
|
|
202
|
-
checkToken: "token-1",
|
|
203
|
-
encodingAESKey: "key-1",
|
|
204
|
-
appKey: "app-key-1",
|
|
205
|
-
appSecret: "secret-1",
|
|
206
|
-
robotName: "WorkBot",
|
|
207
|
-
replyMode: "mention-and-watch",
|
|
208
|
-
watchMentions: ["manager01"],
|
|
209
|
-
},
|
|
210
|
-
personal: {
|
|
211
|
-
checkToken: "token-2",
|
|
212
|
-
encodingAESKey: "key-2",
|
|
213
|
-
appKey: "app-key-2",
|
|
214
|
-
appSecret: "secret-2",
|
|
215
|
-
robotName: "PersonalBot",
|
|
216
|
-
},
|
|
217
|
-
},
|
|
218
|
-
defaultAccount: "work",
|
|
219
|
-
},
|
|
220
|
-
},
|
|
221
|
-
}
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
## 完整配置参考
|
|
225
|
-
|
|
226
|
-
| 字段 | 类型 | 默认值 | 说明 |
|
|
227
|
-
|------|------|--------|------|
|
|
228
|
-
| `enabled` | `boolean` | `true` | 是否启用 |
|
|
229
|
-
| `apiHost` | `string` | — | 如流 API 地址 |
|
|
230
|
-
| `checkToken` | `string` | — | 验证 token **(必填)** |
|
|
231
|
-
| `encodingAESKey` | `string` | — | 消息加密密钥 **(必填)** |
|
|
232
|
-
| `appKey` | `string` | — | 应用 Key **(必填)** |
|
|
233
|
-
| `appSecret` | `string` | — | 应用 Secret **(必填)** |
|
|
234
|
-
| `robotName` | `string` | — | 机器人名称,用于 @提及 检测 |
|
|
235
|
-
| `appAgentId` | `number` | — | 如流企业后台的应用 ID,私聊消息撤回依赖此字段 |
|
|
236
|
-
| `replyMode` | `string` | `"mention-and-watch"` | 回复模式 |
|
|
237
|
-
| `followUp` | `boolean` | `true` | 是否启用跟进回复 |
|
|
238
|
-
| `followUpWindow` | `number` | `300` | 跟进窗口(秒) |
|
|
239
|
-
| `watchMentions` | `string[]` | `[]` | 关注提及的人员列表 |
|
|
240
|
-
| `watchRegex` | `string` \| `string[]` | — | 正则或正则数组,匹配群消息内容时触发回复 |
|
|
241
|
-
| `dmPolicy` | `string` | `"open"` | 私聊策略 |
|
|
242
|
-
| `allowFrom` | `string[]` | `[]` | 私聊白名单 |
|
|
243
|
-
| `groupPolicy` | `string` | `"open"` | 群聊策略 |
|
|
244
|
-
| `groupAllowFrom` | `string[]` | `[]` | 群聊白名单 |
|
|
245
|
-
| `groups` | `object` | — | 按群配置,key 为群 ID |
|
|
246
|
-
| `accounts` | `object` | — | 多账号配置 |
|
|
247
|
-
| `defaultAccount` | `string` | — | 默认账号 ID |
|
|
248
|
-
|
|
249
|
-
### groups.\<groupId\> 子字段
|
|
250
|
-
|
|
251
|
-
| 字段 | 类型 | 说明 |
|
|
252
|
-
|------|------|------|
|
|
253
|
-
| `replyMode` | `string` | 覆盖该群的回复模式 |
|
|
254
|
-
| `watchMentions` | `string[]` | 覆盖该群的关注列表 |
|
|
255
|
-
| `watchRegex` | `string` \| `string[]` | 覆盖该群的正则匹配规则(可为单条或数组),匹配群消息内容时触发回复 |
|
|
256
|
-
| `followUp` | `boolean` | 覆盖该群的跟进开关 |
|
|
257
|
-
| `followUpWindow` | `number` | 覆盖该群的跟进窗口 |
|
|
258
|
-
| `systemPrompt` | `string` | 该群专属系统提示词 |
|
|
259
|
-
|
|
260
|
-
## Agent 主动发送 (Actions)
|
|
261
|
-
|
|
262
|
-
LLM Agent 可通过 `send` action 主动发送消息:
|
|
263
|
-
|
|
264
|
-
| 参数 | 类型 | 说明 |
|
|
265
|
-
|------|------|------|
|
|
266
|
-
| `to` | `string` | **必填**。目标:用户名(私聊)或 `group:<groupId>`(群聊) |
|
|
267
|
-
| `message` | `string` | 消息文本内容 |
|
|
268
|
-
| `atAll` | `boolean` | 群消息中 @所有人 |
|
|
269
|
-
| `mentionUserIds` | `string` | 群消息中 @指定用户,逗号分隔 |
|
|
270
|
-
| `media` | `string` | 附带链接 URL |
|
|
271
|
-
|
|
272
|
-
## 许可证
|
|
23
|
+
OpenClaw 运行时会加载编译产物 `dist/index.js`(由 `tsconfig.build.json` 输出到 `dist/`)。
|
|
273
24
|
|
|
274
|
-
|
|
25
|
+
### 本地部署到 OpenClaw
|
|
275
26
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
<a id="english"></a>
|
|
279
|
-
|
|
280
|
-
# @chbo297/infoflow
|
|
281
|
-
|
|
282
|
-
Baidu Infoflow (如流) enterprise messaging platform — OpenClaw channel plugin.
|
|
283
|
-
|
|
284
|
-
📦 **[npm](https://www.npmjs.com/package/@chbo297/infoflow)**
|
|
285
|
-
|
|
286
|
-
## Features
|
|
287
|
-
|
|
288
|
-
- **Direct & group** message receiving and replying
|
|
289
|
-
- **@mention detection** in groups — auto-reply when the bot is @mentioned
|
|
290
|
-
- **watchMentions**: monitor specified people; when they are @mentioned, the bot acts as their assistant and decides whether to reply on their behalf
|
|
291
|
-
- **watchRegex**: match group chat content by regex; when a message matches, trigger the bot to reply
|
|
292
|
-
- **followUp**: after the bot replies, intelligently judge whether subsequent messages are follow-up questions within a time window — no need to @mention again
|
|
293
|
-
- Five **replyMode** levels: from fully ignoring to proactively engaging, flexibly control group behavior
|
|
294
|
-
- **Per-group config**: each group can have its own reply strategy and system prompt
|
|
295
|
-
- **Multi-account support**: manage multiple Infoflow bots from a single instance
|
|
296
|
-
- **Agent-initiated / scheduled sending**: LLM Agent can proactively or on a schedule send DMs, post messages to groups, @specific users, or @all members
|
|
297
|
-
- **Markdown local images**: local image paths in reply content are converted and sent as image messages
|
|
298
|
-
|
|
299
|
-
## Install
|
|
300
|
-
|
|
301
|
-
### Via npm
|
|
27
|
+
仓库内置一键部署脚本,会把插件同步到 `~/.openclaw/extensions/infoflow`,并确保 build 完成后重启 gateway:
|
|
302
28
|
|
|
303
29
|
```bash
|
|
304
|
-
|
|
30
|
+
bash scripts/deploy.sh
|
|
305
31
|
```
|
|
306
32
|
|
|
307
|
-
|
|
33
|
+
当配置里检测到 `connectionMode=websocket`(包含账号级配置)时,脚本会自动安装 `@baidu/infoflow-sdk-nodejs`。
|
|
34
|
+
默认私有源为 `http://registry.npm.baidu-int.com`,也可通过环境变量覆盖:
|
|
308
35
|
|
|
309
36
|
```bash
|
|
310
|
-
|
|
311
|
-
```
|
|
312
|
-
|
|
313
|
-
## Requirements
|
|
314
|
-
|
|
315
|
-
- OpenClaw **>= 2026.3.2**
|
|
316
|
-
|
|
317
|
-
## Quick Start
|
|
318
|
-
|
|
319
|
-
```json5
|
|
320
|
-
{
|
|
321
|
-
channels: {
|
|
322
|
-
infoflow: {
|
|
323
|
-
enabled: true,
|
|
324
|
-
apiHost: "https://apiin.im.baidu.com",
|
|
325
|
-
checkToken: "your-check-token",
|
|
326
|
-
encodingAESKey: "your-encoding-aes-key",
|
|
327
|
-
appKey: "your-app-key",
|
|
328
|
-
appSecret: "your-app-secret",
|
|
329
|
-
robotName: "MyBot", // used for @mention detection in groups
|
|
330
|
-
},
|
|
331
|
-
},
|
|
332
|
-
}
|
|
333
|
-
```
|
|
334
|
-
|
|
335
|
-
### Webhook URL
|
|
336
|
-
|
|
337
|
-
Configure your Infoflow bot webhook URL to:
|
|
338
|
-
|
|
339
|
-
```
|
|
340
|
-
https://your-domain/webhook/infoflow
|
|
341
|
-
```
|
|
342
|
-
|
|
343
|
-
Restart the gateway after config changes.
|
|
344
|
-
|
|
345
|
-
## Reply Modes (replyMode)
|
|
346
|
-
|
|
347
|
-
Control how the bot participates in group chats via `replyMode`. Default: `mention-and-watch`.
|
|
348
|
-
|
|
349
|
-
| Mode | Behavior |
|
|
350
|
-
|------|----------|
|
|
351
|
-
| `ignore` | Discard messages — no saving, no thinking, no reply |
|
|
352
|
-
| `record` | Save to session history only — no thinking, no reply |
|
|
353
|
-
| `mention-only` | Reply only when the bot is directly @mentioned |
|
|
354
|
-
| `mention-and-watch` | Reply when bot is @mentioned, a watched person is @mentioned, or within follow-up window **(default)** |
|
|
355
|
-
| `proactive` | Always think and potentially reply to all messages |
|
|
356
|
-
|
|
357
|
-
## Watch Mentions (watchMentions)
|
|
358
|
-
|
|
359
|
-
Configure a list of people to watch. When someone in the group @mentions a person on this list, the bot acts as their assistant and decides whether to answer on their behalf.
|
|
360
|
-
|
|
361
|
-
```json5
|
|
362
|
-
{
|
|
363
|
-
channels: {
|
|
364
|
-
infoflow: {
|
|
365
|
-
watchMentions: ["alice01", "bob02"],
|
|
366
|
-
// Requires replyMode "mention-and-watch" or "proactive"
|
|
367
|
-
},
|
|
368
|
-
},
|
|
369
|
-
}
|
|
370
|
-
```
|
|
371
|
-
|
|
372
|
-
**Matching priority**: `userid` > `robotid` (numeric) > display name
|
|
373
|
-
|
|
374
|
-
**Behavior**:
|
|
375
|
-
- The bot uses LLM to judge whether it can answer on behalf
|
|
376
|
-
- Confident it can help → replies directly
|
|
377
|
-
- Cannot help → stays silent (NO_REPLY)
|
|
378
|
-
|
|
379
|
-
## Regex Match (watchRegex)
|
|
380
|
-
|
|
381
|
-
Match group chat content with a regular expression; when a message matches any pattern, the bot is triggered to participate and reply (requires `replyMode` `mention-and-watch` or `proactive`). `watchRegex` can be a **string** or **string array** (multiple patterns; any match triggers). Can be set at top level, per account, or per group.
|
|
382
|
-
|
|
383
|
-
```json5
|
|
384
|
-
{
|
|
385
|
-
channels: {
|
|
386
|
-
infoflow: {
|
|
387
|
-
watchRegex: ["^(help|please)", "\\?$"], // Top-level: array of patterns
|
|
388
|
-
groups: {
|
|
389
|
-
"123456": {
|
|
390
|
-
watchRegex: "\\?$|how to|what is", // This group: single pattern
|
|
391
|
-
},
|
|
392
|
-
},
|
|
393
|
-
},
|
|
394
|
-
},
|
|
395
|
-
}
|
|
37
|
+
BAIDU_NPM_REGISTRY=http://registry.npm.baidu-int.com bash scripts/deploy.sh
|
|
396
38
|
```
|
|
397
39
|
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
## Follow-Up (followUp)
|
|
401
|
-
|
|
402
|
-
After the bot replies, any subsequent message within the `followUpWindow` (default 300 seconds) triggers intelligent judgment — even without @mentioning the bot:
|
|
403
|
-
|
|
404
|
-
- Same topic / follow-up question → continue replying
|
|
405
|
-
- Unrelated new topic → stay silent
|
|
406
|
-
|
|
407
|
-
```json5
|
|
408
|
-
{
|
|
409
|
-
channels: {
|
|
410
|
-
infoflow: {
|
|
411
|
-
followUp: true, // Default: true
|
|
412
|
-
followUpWindow: 300, // Seconds, default: 300
|
|
413
|
-
},
|
|
414
|
-
},
|
|
415
|
-
}
|
|
416
|
-
```
|
|
417
|
-
|
|
418
|
-
## Per-Group Config (groups)
|
|
419
|
-
|
|
420
|
-
Set independent reply strategies for each group, overriding the global defaults.
|
|
421
|
-
|
|
422
|
-
```json5
|
|
423
|
-
{
|
|
424
|
-
channels: {
|
|
425
|
-
infoflow: {
|
|
426
|
-
replyMode: "mention-only", // Global default
|
|
427
|
-
groups: {
|
|
428
|
-
"123456": {
|
|
429
|
-
replyMode: "mention-and-watch",
|
|
430
|
-
watchMentions: ["team-lead01"],
|
|
431
|
-
watchRegex: "^(help|urgent)",
|
|
432
|
-
followUp: true,
|
|
433
|
-
followUpWindow: 600,
|
|
434
|
-
systemPrompt: "You are the tech assistant for this project team.",
|
|
435
|
-
},
|
|
436
|
-
"789012": {
|
|
437
|
-
replyMode: "record", // This group records only, no replies
|
|
438
|
-
},
|
|
439
|
-
},
|
|
440
|
-
},
|
|
441
|
-
},
|
|
442
|
-
}
|
|
443
|
-
```
|
|
444
|
-
|
|
445
|
-
**Config priority**: group-level > account-level > top-level defaults
|
|
446
|
-
|
|
447
|
-
## Access Control
|
|
448
|
-
|
|
449
|
-
### DM Policy (dmPolicy)
|
|
450
|
-
|
|
451
|
-
| Value | Description |
|
|
452
|
-
|-------|-------------|
|
|
453
|
-
| `open` | Allow all users to DM (default) |
|
|
454
|
-
| `pairing` | Require pairing confirmation |
|
|
455
|
-
| `allowlist` | Only allow users in `allowFrom` list |
|
|
456
|
-
|
|
457
|
-
### Group Policy (groupPolicy)
|
|
458
|
-
|
|
459
|
-
| Value | Description |
|
|
460
|
-
|-------|-------------|
|
|
461
|
-
| `open` | Allow all groups to trigger the bot (default) |
|
|
462
|
-
| `allowlist` | Only allow groups in `groupAllowFrom` list |
|
|
463
|
-
| `disabled` | Disable group messaging |
|
|
464
|
-
|
|
465
|
-
## Multi-Account
|
|
466
|
-
|
|
467
|
-
```json5
|
|
468
|
-
{
|
|
469
|
-
channels: {
|
|
470
|
-
infoflow: {
|
|
471
|
-
enabled: true,
|
|
472
|
-
replyMode: "mention-only", // Default for all accounts
|
|
473
|
-
accounts: {
|
|
474
|
-
work: {
|
|
475
|
-
checkToken: "token-1",
|
|
476
|
-
encodingAESKey: "key-1",
|
|
477
|
-
appKey: "app-key-1",
|
|
478
|
-
appSecret: "secret-1",
|
|
479
|
-
robotName: "WorkBot",
|
|
480
|
-
replyMode: "mention-and-watch",
|
|
481
|
-
watchMentions: ["manager01"],
|
|
482
|
-
},
|
|
483
|
-
personal: {
|
|
484
|
-
checkToken: "token-2",
|
|
485
|
-
encodingAESKey: "key-2",
|
|
486
|
-
appKey: "app-key-2",
|
|
487
|
-
appSecret: "secret-2",
|
|
488
|
-
robotName: "PersonalBot",
|
|
489
|
-
},
|
|
490
|
-
},
|
|
491
|
-
defaultAccount: "work",
|
|
492
|
-
},
|
|
493
|
-
},
|
|
494
|
-
}
|
|
495
|
-
```
|
|
496
|
-
|
|
497
|
-
## Full Config Reference
|
|
498
|
-
|
|
499
|
-
| Field | Type | Default | Description |
|
|
500
|
-
|-------|------|---------|-------------|
|
|
501
|
-
| `enabled` | `boolean` | `true` | Enable/disable the channel |
|
|
502
|
-
| `apiHost` | `string` | — | Infoflow API base URL |
|
|
503
|
-
| `checkToken` | `string` | — | Verification token **(required)** |
|
|
504
|
-
| `encodingAESKey` | `string` | — | AES encryption key **(required)** |
|
|
505
|
-
| `appKey` | `string` | — | Application key **(required)** |
|
|
506
|
-
| `appSecret` | `string` | — | Application secret **(required)** |
|
|
507
|
-
| `robotName` | `string` | — | Bot name for @mention detection |
|
|
508
|
-
| `appAgentId` | `number` | — | Infoflow app ID (enterprise console); required for DM message recall |
|
|
509
|
-
| `replyMode` | `string` | `"mention-and-watch"` | Reply mode |
|
|
510
|
-
| `followUp` | `boolean` | `true` | Enable follow-up replies |
|
|
511
|
-
| `followUpWindow` | `number` | `300` | Follow-up window (seconds) |
|
|
512
|
-
| `watchMentions` | `string[]` | `[]` | List of people to watch for @mentions |
|
|
513
|
-
| `watchRegex` | `string` \| `string[]` | — | Regex or array of regexes; when matched, trigger reply |
|
|
514
|
-
| `dmPolicy` | `string` | `"open"` | DM access policy |
|
|
515
|
-
| `allowFrom` | `string[]` | `[]` | DM allowlist |
|
|
516
|
-
| `groupPolicy` | `string` | `"open"` | Group access policy |
|
|
517
|
-
| `groupAllowFrom` | `string[]` | `[]` | Group allowlist |
|
|
518
|
-
| `groups` | `object` | — | Per-group config, keyed by group ID |
|
|
519
|
-
| `accounts` | `object` | — | Multi-account config |
|
|
520
|
-
| `defaultAccount` | `string` | — | Default account ID |
|
|
521
|
-
|
|
522
|
-
### groups.\<groupId\> fields
|
|
523
|
-
|
|
524
|
-
| Field | Type | Description |
|
|
525
|
-
|-------|------|-------------|
|
|
526
|
-
| `replyMode` | `string` | Override reply mode for this group |
|
|
527
|
-
| `watchMentions` | `string[]` | Override watch list for this group |
|
|
528
|
-
| `watchRegex` | `string` \| `string[]` | Override regex for this group (single or array); match group content to trigger reply |
|
|
529
|
-
| `followUp` | `boolean` | Override follow-up toggle for this group |
|
|
530
|
-
| `followUpWindow` | `number` | Override follow-up window for this group |
|
|
531
|
-
| `systemPrompt` | `string` | Custom system prompt for this group |
|
|
532
|
-
|
|
533
|
-
## Actions (Agent-Initiated Sending)
|
|
534
|
-
|
|
535
|
-
LLM Agent can proactively send messages via the `send` action:
|
|
536
|
-
|
|
537
|
-
| Parameter | Type | Description |
|
|
538
|
-
|-----------|------|-------------|
|
|
539
|
-
| `to` | `string` | **Required**. Target: username (DM) or `group:<groupId>` (group) |
|
|
540
|
-
| `message` | `string` | Message text content |
|
|
541
|
-
| `atAll` | `boolean` | @all members in group messages |
|
|
542
|
-
| `mentionUserIds` | `string` | @specific users in group, comma-separated |
|
|
543
|
-
| `media` | `string` | Attached link URL |
|
|
544
|
-
|
|
545
|
-
## License
|
|
40
|
+
### WebSocket 模式(可选)
|
|
546
41
|
|
|
547
|
-
|
|
42
|
+
当 `connectionMode="websocket"` 时,插件会动态 `import("@baidu/infoflow-sdk-nodejs")`。
|
|
43
|
+
该依赖在 `peerDependencies` 中标记为 optional:不使用 websocket 模式时无需安装。
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk";
|
|
2
|
+
import { infoflowPlugin } from "./src/channel.js";
|
|
3
|
+
import { handleInfoflowWebhookRequest } from "./src/monitor.js";
|
|
4
|
+
import { setInfoflowRuntime } from "./src/runtime.js";
|
|
5
|
+
const plugin = {
|
|
6
|
+
id: "infoflow",
|
|
7
|
+
name: "Infoflow",
|
|
8
|
+
description: "OpenClaw Infoflow channel plugin",
|
|
9
|
+
configSchema: emptyPluginConfigSchema(),
|
|
10
|
+
register(api) {
|
|
11
|
+
setInfoflowRuntime(api.runtime);
|
|
12
|
+
api.registerChannel({ plugin: infoflowPlugin });
|
|
13
|
+
api.registerHttpRoute({
|
|
14
|
+
path: "/webhook/infoflow",
|
|
15
|
+
auth: "plugin",
|
|
16
|
+
match: "exact",
|
|
17
|
+
handler: handleInfoflowWebhookRequest,
|
|
18
|
+
});
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
export default plugin;
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Infoflow account resolution and configuration helpers.
|
|
3
|
+
* Handles multi-account support with config merging.
|
|
4
|
+
*/
|
|
5
|
+
import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "openclaw/plugin-sdk/core";
|
|
6
|
+
const DEFAULT_INFOFLOW_WS_GATEWAY = "infoflow-open-gateway.weiyun.baidu.com";
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
// Config Access Helpers
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
/**
|
|
11
|
+
* Get the raw Infoflow channel section from config.
|
|
12
|
+
*/
|
|
13
|
+
export function getChannelSection(cfg) {
|
|
14
|
+
return cfg.channels?.["infoflow"];
|
|
15
|
+
}
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
// Account ID Resolution
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
/**
|
|
20
|
+
* List all configured Infoflow account IDs.
|
|
21
|
+
* Returns [DEFAULT_ACCOUNT_ID] if no accounts are configured (backward compatibility).
|
|
22
|
+
*/
|
|
23
|
+
export function listInfoflowAccountIds(cfg) {
|
|
24
|
+
const accounts = getChannelSection(cfg)?.accounts;
|
|
25
|
+
if (!accounts || typeof accounts !== "object") {
|
|
26
|
+
return [DEFAULT_ACCOUNT_ID];
|
|
27
|
+
}
|
|
28
|
+
const ids = Object.keys(accounts).filter(Boolean);
|
|
29
|
+
return ids.length === 0 ? [DEFAULT_ACCOUNT_ID] : ids.toSorted((a, b) => a.localeCompare(b));
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Resolve the default account ID for Infoflow.
|
|
33
|
+
*/
|
|
34
|
+
export function resolveDefaultInfoflowAccountId(cfg) {
|
|
35
|
+
const channel = getChannelSection(cfg);
|
|
36
|
+
if (channel?.defaultAccount?.trim()) {
|
|
37
|
+
return channel.defaultAccount.trim();
|
|
38
|
+
}
|
|
39
|
+
const ids = listInfoflowAccountIds(cfg);
|
|
40
|
+
if (ids.includes(DEFAULT_ACCOUNT_ID)) {
|
|
41
|
+
return DEFAULT_ACCOUNT_ID;
|
|
42
|
+
}
|
|
43
|
+
return ids[0] ?? DEFAULT_ACCOUNT_ID;
|
|
44
|
+
}
|
|
45
|
+
// ---------------------------------------------------------------------------
|
|
46
|
+
// Config Merging
|
|
47
|
+
// ---------------------------------------------------------------------------
|
|
48
|
+
/**
|
|
49
|
+
* Merge top-level Infoflow config with account-specific overrides.
|
|
50
|
+
* Account fields override base fields.
|
|
51
|
+
*/
|
|
52
|
+
function mergeInfoflowAccountConfig(cfg, accountId) {
|
|
53
|
+
const raw = getChannelSection(cfg) ?? {};
|
|
54
|
+
const { accounts: _ignored, defaultAccount: _ignored2, ...base } = raw;
|
|
55
|
+
const account = raw.accounts?.[accountId] ?? {};
|
|
56
|
+
return { ...base, ...account };
|
|
57
|
+
}
|
|
58
|
+
function normalizeWatchRegex(v) {
|
|
59
|
+
if (v == null)
|
|
60
|
+
return [];
|
|
61
|
+
return Array.isArray(v) ? v : [v];
|
|
62
|
+
}
|
|
63
|
+
// ---------------------------------------------------------------------------
|
|
64
|
+
// Account Resolution
|
|
65
|
+
// ---------------------------------------------------------------------------
|
|
66
|
+
/**
|
|
67
|
+
* Resolve a complete Infoflow account with merged config.
|
|
68
|
+
*/
|
|
69
|
+
export function resolveInfoflowAccount(params) {
|
|
70
|
+
const accountId = normalizeAccountId(params.accountId);
|
|
71
|
+
const baseEnabled = getChannelSection(params.cfg)?.enabled !== false;
|
|
72
|
+
const merged = mergeInfoflowAccountConfig(params.cfg, accountId);
|
|
73
|
+
const accountEnabled = merged.enabled !== false;
|
|
74
|
+
const enabled = baseEnabled && accountEnabled;
|
|
75
|
+
const apiHost = merged.apiHost ?? "";
|
|
76
|
+
const checkToken = merged.checkToken ?? "";
|
|
77
|
+
const encodingAESKey = merged.encodingAESKey ?? "";
|
|
78
|
+
const appKey = merged.appKey ?? "";
|
|
79
|
+
const appSecret = merged.appSecret ?? "";
|
|
80
|
+
const effectiveConnectionMode = merged.connectionMode ?? "webhook";
|
|
81
|
+
const wsGateway = merged.wsGateway?.trim() || DEFAULT_INFOFLOW_WS_GATEWAY;
|
|
82
|
+
const wsConnectDomain = merged.wsConnectDomain?.trim() || undefined;
|
|
83
|
+
const configured = effectiveConnectionMode === "websocket"
|
|
84
|
+
? Boolean(appKey) && Boolean(appSecret)
|
|
85
|
+
: Boolean(checkToken) && Boolean(encodingAESKey) && Boolean(appKey) && Boolean(appSecret);
|
|
86
|
+
return {
|
|
87
|
+
accountId,
|
|
88
|
+
name: merged.name?.trim() || undefined,
|
|
89
|
+
enabled,
|
|
90
|
+
configured,
|
|
91
|
+
config: {
|
|
92
|
+
enabled: merged.enabled,
|
|
93
|
+
name: merged.name,
|
|
94
|
+
apiHost,
|
|
95
|
+
connectionMode: effectiveConnectionMode,
|
|
96
|
+
wsGateway,
|
|
97
|
+
wsConnectDomain,
|
|
98
|
+
checkToken,
|
|
99
|
+
encodingAESKey,
|
|
100
|
+
appKey,
|
|
101
|
+
appSecret,
|
|
102
|
+
robotName: merged.robotName?.trim() || undefined,
|
|
103
|
+
robotId: merged.robotId?.trim() || undefined,
|
|
104
|
+
requireMention: merged.requireMention,
|
|
105
|
+
watchMentions: merged.watchMentions,
|
|
106
|
+
watchRegex: normalizeWatchRegex(merged.watchRegex),
|
|
107
|
+
appAgentId: merged.appAgentId,
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
}
|