@chbo297/infoflow 2026.3.7 → 2026.3.9
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/CHANGELOG.md +20 -0
- package/README.md +53 -1
- package/openclaw.plugin.json +6 -6
- package/package.json +1 -1
- package/src/accounts.ts +3 -0
- package/src/bot.ts +56 -3
- package/src/channel.ts +1 -1
- package/src/reply-dispatcher.ts +2 -2
- package/src/types.ts +5 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2026.3.8
|
|
4
|
+
|
|
5
|
+
### 新功能
|
|
6
|
+
|
|
7
|
+
#### watchRegex(正则匹配群消息)
|
|
8
|
+
|
|
9
|
+
- 支持 `watchRegex` 配置:按正则表达式匹配群内聊天内容,命中时触发机器人参与并回复
|
|
10
|
+
- 可在顶层、账号级别或按群(`groups.<groupId>.watchRegex`)单独配置
|
|
11
|
+
- 需配合 `replyMode` 为 `mention-and-watch` 或 `proactive` 使用
|
|
12
|
+
|
|
13
|
+
#### 撤回消息
|
|
14
|
+
|
|
15
|
+
- 支持私聊消息撤回能力,需在配置中填写如流企业后台的 `appAgentId`(应用 ID)
|
|
16
|
+
|
|
17
|
+
### Bug 修复
|
|
18
|
+
|
|
19
|
+
- 修复了一些消息回复失败的问题
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
3
23
|
## 2026.2.28
|
|
4
24
|
|
|
5
25
|
### 新功能
|
package/README.md
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
- **私聊 & 群聊**消息接收与回复
|
|
14
14
|
- 群内 **@机器人** 检测,被 @提及 时自动回复
|
|
15
15
|
- **watchMentions(关注提及)**:监控指定人员被 @ 时,机器人作为其助手判断是否代为回复
|
|
16
|
+
- **watchRegex(正则匹配)**:按正则匹配群内聊天内容,命中时触发机器人回复
|
|
16
17
|
- **followUp(跟进回复)**:机器人回复后,在时间窗口内智能判断后续消息是否为追问,无需再次 @
|
|
17
18
|
- 五种 **replyMode(回复模式)**:从完全忽略到主动参与,灵活控制群内行为
|
|
18
19
|
- **按群独立配置**:每个群可设置不同的回复策略和系统提示词
|
|
@@ -49,7 +50,7 @@ openclaw plugins install ./path/to/openclaw-infoflow
|
|
|
49
50
|
encodingAESKey: "your-encoding-aes-key",
|
|
50
51
|
appKey: "your-app-key",
|
|
51
52
|
appSecret: "your-app-secret",
|
|
52
|
-
robotName: "MyBot", //
|
|
53
|
+
robotName: "MyBot", // 用于群内 @提及 检测
|
|
53
54
|
},
|
|
54
55
|
},
|
|
55
56
|
}
|
|
@@ -99,6 +100,27 @@ https://your-domain/webhook/infoflow
|
|
|
99
100
|
- 如果有把握 → 直接回复
|
|
100
101
|
- 如果无法帮助 → 静默不回复
|
|
101
102
|
|
|
103
|
+
## 正则匹配 (watchRegex)
|
|
104
|
+
|
|
105
|
+
通过正则表达式匹配群内聊天内容,当消息文本命中正则时,会触发机器人参与并回复(需配合 `replyMode` 为 `mention-and-watch` 或 `proactive`)。可在顶层、账号或按群单独配置。
|
|
106
|
+
|
|
107
|
+
```json5
|
|
108
|
+
{
|
|
109
|
+
channels: {
|
|
110
|
+
infoflow: {
|
|
111
|
+
watchRegex: "^(帮忙|请帮我|求助)", // 顶层:匹配以这些词开头的消息
|
|
112
|
+
groups: {
|
|
113
|
+
"123456": {
|
|
114
|
+
watchRegex: "\\?$|怎么|如何", // 该群:匹配以问号结尾或含「怎么」「如何」的消息
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**说明**:正则采用 JavaScript 标准语法;与 watchMentions、@提及 等条件并列,任一满足即可触发回复判断。
|
|
123
|
+
|
|
102
124
|
## 跟进回复 (followUp)
|
|
103
125
|
|
|
104
126
|
机器人回复后,在 `followUpWindow` 时间窗口内(默认 300 秒),后续消息即使没有 @机器人 也会触发智能判断:
|
|
@@ -130,6 +152,7 @@ https://your-domain/webhook/infoflow
|
|
|
130
152
|
"123456": {
|
|
131
153
|
replyMode: "mention-and-watch",
|
|
132
154
|
watchMentions: ["team-lead01"],
|
|
155
|
+
watchRegex: "^(帮忙|求助)",
|
|
133
156
|
followUp: true,
|
|
134
157
|
followUpWindow: 600,
|
|
135
158
|
systemPrompt: "你是这个项目组的技术助手。",
|
|
@@ -206,10 +229,12 @@ https://your-domain/webhook/infoflow
|
|
|
206
229
|
| `appKey` | `string` | — | 应用 Key **(必填)** |
|
|
207
230
|
| `appSecret` | `string` | — | 应用 Secret **(必填)** |
|
|
208
231
|
| `robotName` | `string` | — | 机器人名称,用于 @提及 检测 |
|
|
232
|
+
| `appAgentId` | `number` | — | 如流企业后台的应用 ID,私聊消息撤回依赖此字段 |
|
|
209
233
|
| `replyMode` | `string` | `"mention-and-watch"` | 回复模式 |
|
|
210
234
|
| `followUp` | `boolean` | `true` | 是否启用跟进回复 |
|
|
211
235
|
| `followUpWindow` | `number` | `300` | 跟进窗口(秒) |
|
|
212
236
|
| `watchMentions` | `string[]` | `[]` | 关注提及的人员列表 |
|
|
237
|
+
| `watchRegex` | `string` | — | 正则表达式,匹配群消息内容时触发回复 |
|
|
213
238
|
| `dmPolicy` | `string` | `"open"` | 私聊策略 |
|
|
214
239
|
| `allowFrom` | `string[]` | `[]` | 私聊白名单 |
|
|
215
240
|
| `groupPolicy` | `string` | `"open"` | 群聊策略 |
|
|
@@ -224,6 +249,7 @@ https://your-domain/webhook/infoflow
|
|
|
224
249
|
|------|------|------|
|
|
225
250
|
| `replyMode` | `string` | 覆盖该群的回复模式 |
|
|
226
251
|
| `watchMentions` | `string[]` | 覆盖该群的关注列表 |
|
|
252
|
+
| `watchRegex` | `string` | 覆盖该群的正则匹配规则,匹配群消息内容时触发回复 |
|
|
227
253
|
| `followUp` | `boolean` | 覆盖该群的跟进开关 |
|
|
228
254
|
| `followUpWindow` | `number` | 覆盖该群的跟进窗口 |
|
|
229
255
|
| `systemPrompt` | `string` | 该群专属系统提示词 |
|
|
@@ -257,6 +283,7 @@ Baidu Infoflow (如流) enterprise messaging platform — OpenClaw channel plugi
|
|
|
257
283
|
- **Direct & group** message receiving and replying
|
|
258
284
|
- **@mention detection** in groups — auto-reply when the bot is @mentioned
|
|
259
285
|
- **watchMentions**: monitor specified people; when they are @mentioned, the bot acts as their assistant and decides whether to reply on their behalf
|
|
286
|
+
- **watchRegex**: match group chat content by regex; when a message matches, trigger the bot to reply
|
|
260
287
|
- **followUp**: after the bot replies, intelligently judge whether subsequent messages are follow-up questions within a time window — no need to @mention again
|
|
261
288
|
- Five **replyMode** levels: from fully ignoring to proactively engaging, flexibly control group behavior
|
|
262
289
|
- **Per-group config**: each group can have its own reply strategy and system prompt
|
|
@@ -343,6 +370,27 @@ Configure a list of people to watch. When someone in the group @mentions a perso
|
|
|
343
370
|
- Confident it can help → replies directly
|
|
344
371
|
- Cannot help → stays silent (NO_REPLY)
|
|
345
372
|
|
|
373
|
+
## Regex Match (watchRegex)
|
|
374
|
+
|
|
375
|
+
Match group chat content with a regular expression; when a message matches, the bot is triggered to participate and reply (requires `replyMode` `mention-and-watch` or `proactive`). Can be set at top level, per account, or per group.
|
|
376
|
+
|
|
377
|
+
```json5
|
|
378
|
+
{
|
|
379
|
+
channels: {
|
|
380
|
+
infoflow: {
|
|
381
|
+
watchRegex: "^(help|please|urgent)", // Top-level: match messages starting with these
|
|
382
|
+
groups: {
|
|
383
|
+
"123456": {
|
|
384
|
+
watchRegex: "\\?$|how to|what is", // This group: match messages ending with ? or containing "how to"/"what is"
|
|
385
|
+
},
|
|
386
|
+
},
|
|
387
|
+
},
|
|
388
|
+
},
|
|
389
|
+
}
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
**Note**: Regex uses standard JavaScript syntax. It works alongside watchMentions and @mention; any condition can trigger reply evaluation.
|
|
393
|
+
|
|
346
394
|
## Follow-Up (followUp)
|
|
347
395
|
|
|
348
396
|
After the bot replies, any subsequent message within the `followUpWindow` (default 300 seconds) triggers intelligent judgment — even without @mentioning the bot:
|
|
@@ -374,6 +422,7 @@ Set independent reply strategies for each group, overriding the global defaults.
|
|
|
374
422
|
"123456": {
|
|
375
423
|
replyMode: "mention-and-watch",
|
|
376
424
|
watchMentions: ["team-lead01"],
|
|
425
|
+
watchRegex: "^(help|urgent)",
|
|
377
426
|
followUp: true,
|
|
378
427
|
followUpWindow: 600,
|
|
379
428
|
systemPrompt: "You are the tech assistant for this project team.",
|
|
@@ -450,10 +499,12 @@ Set independent reply strategies for each group, overriding the global defaults.
|
|
|
450
499
|
| `appKey` | `string` | — | Application key **(required)** |
|
|
451
500
|
| `appSecret` | `string` | — | Application secret **(required)** |
|
|
452
501
|
| `robotName` | `string` | — | Bot name for @mention detection |
|
|
502
|
+
| `appAgentId` | `number` | — | Infoflow app ID (enterprise console); required for DM message recall |
|
|
453
503
|
| `replyMode` | `string` | `"mention-and-watch"` | Reply mode |
|
|
454
504
|
| `followUp` | `boolean` | `true` | Enable follow-up replies |
|
|
455
505
|
| `followUpWindow` | `number` | `300` | Follow-up window (seconds) |
|
|
456
506
|
| `watchMentions` | `string[]` | `[]` | List of people to watch for @mentions |
|
|
507
|
+
| `watchRegex` | `string` | — | Regex to match group message content; when matched, trigger reply |
|
|
457
508
|
| `dmPolicy` | `string` | `"open"` | DM access policy |
|
|
458
509
|
| `allowFrom` | `string[]` | `[]` | DM allowlist |
|
|
459
510
|
| `groupPolicy` | `string` | `"open"` | Group access policy |
|
|
@@ -468,6 +519,7 @@ Set independent reply strategies for each group, overriding the global defaults.
|
|
|
468
519
|
|-------|------|-------------|
|
|
469
520
|
| `replyMode` | `string` | Override reply mode for this group |
|
|
470
521
|
| `watchMentions` | `string[]` | Override watch list for this group |
|
|
522
|
+
| `watchRegex` | `string` | Override regex for this group; match group content to trigger reply |
|
|
471
523
|
| `followUp` | `boolean` | Override follow-up toggle for this group |
|
|
472
524
|
| `followUpWindow` | `number` | Override follow-up window for this group |
|
|
473
525
|
| `systemPrompt` | `string` | Custom system prompt for this group |
|
package/openclaw.plugin.json
CHANGED
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"followUp": { "type": "boolean", "default": true },
|
|
31
31
|
"followUpWindow": { "type": "number", "default": 300 },
|
|
32
32
|
"watchMentions": { "type": "array", "items": { "type": "string" } },
|
|
33
|
-
"
|
|
33
|
+
"watchRegex": { "type": "string" },
|
|
34
34
|
"groups": {
|
|
35
35
|
"type": "object",
|
|
36
36
|
"additionalProperties": {
|
|
@@ -41,10 +41,10 @@
|
|
|
41
41
|
"enum": ["ignore", "record", "mention-only", "mention-and-watch", "proactive"]
|
|
42
42
|
},
|
|
43
43
|
"watchMentions": { "type": "array", "items": { "type": "string" } },
|
|
44
|
+
"watchRegex": { "type": "string" },
|
|
44
45
|
"followUp": { "type": "boolean" },
|
|
45
46
|
"followUpWindow": { "type": "number" },
|
|
46
|
-
"systemPrompt": { "type": "string" }
|
|
47
|
-
"thinkingIndicator": { "type": "boolean" }
|
|
47
|
+
"systemPrompt": { "type": "string" }
|
|
48
48
|
},
|
|
49
49
|
"additionalProperties": false
|
|
50
50
|
}
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
"followUp": { "type": "boolean" },
|
|
78
78
|
"followUpWindow": { "type": "number" },
|
|
79
79
|
"watchMentions": { "type": "array", "items": { "type": "string" } },
|
|
80
|
-
"
|
|
80
|
+
"watchRegex": { "type": "string" },
|
|
81
81
|
"groups": {
|
|
82
82
|
"type": "object",
|
|
83
83
|
"additionalProperties": {
|
|
@@ -88,10 +88,10 @@
|
|
|
88
88
|
"enum": ["ignore", "record", "mention-only", "mention-and-watch", "proactive"]
|
|
89
89
|
},
|
|
90
90
|
"watchMentions": { "type": "array", "items": { "type": "string" } },
|
|
91
|
+
"watchRegex": { "type": "string" },
|
|
91
92
|
"followUp": { "type": "boolean" },
|
|
92
93
|
"followUpWindow": { "type": "number" },
|
|
93
|
-
"systemPrompt": { "type": "string" }
|
|
94
|
-
"thinkingIndicator": { "type": "boolean" }
|
|
94
|
+
"systemPrompt": { "type": "string" }
|
|
95
95
|
},
|
|
96
96
|
"additionalProperties": false
|
|
97
97
|
}
|
package/package.json
CHANGED
package/src/accounts.ts
CHANGED
|
@@ -71,6 +71,7 @@ function mergeInfoflowAccountConfig(
|
|
|
71
71
|
robotName?: string;
|
|
72
72
|
requireMention?: boolean;
|
|
73
73
|
watchMentions?: string[];
|
|
74
|
+
watchRegex?: string;
|
|
74
75
|
appAgentId?: number;
|
|
75
76
|
} {
|
|
76
77
|
const raw = getChannelSection(cfg) ?? {};
|
|
@@ -87,6 +88,7 @@ function mergeInfoflowAccountConfig(
|
|
|
87
88
|
robotName?: string;
|
|
88
89
|
requireMention?: boolean;
|
|
89
90
|
watchMentions?: string[];
|
|
91
|
+
watchRegex?: string;
|
|
90
92
|
appAgentId?: number;
|
|
91
93
|
};
|
|
92
94
|
}
|
|
@@ -131,6 +133,7 @@ export function resolveInfoflowAccount(params: {
|
|
|
131
133
|
robotName: merged.robotName?.trim() || undefined,
|
|
132
134
|
requireMention: merged.requireMention,
|
|
133
135
|
watchMentions: merged.watchMentions,
|
|
136
|
+
watchRegex: merged.watchRegex,
|
|
134
137
|
appAgentId: merged.appAgentId,
|
|
135
138
|
},
|
|
136
139
|
};
|
package/src/bot.ts
CHANGED
|
@@ -103,6 +103,15 @@ function checkWatchMentioned(
|
|
|
103
103
|
return undefined;
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
+
/** Check if message content matches the configured watchRegex regex pattern. Uses "s" (dotAll) so that . matches newlines in multi-line messages. */
|
|
107
|
+
function checkWatchRegex(mes: string, pattern: string): boolean {
|
|
108
|
+
try {
|
|
109
|
+
return new RegExp(pattern, "is").test(mes);
|
|
110
|
+
} catch {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
106
115
|
/**
|
|
107
116
|
* Extract non-bot mention IDs from inbound group message body items.
|
|
108
117
|
* Returns human userIds and robot agentIds (excluding the bot itself, matched by robotName).
|
|
@@ -194,6 +203,19 @@ function buildWatchMentionPrompt(mentionedId: string): string {
|
|
|
194
203
|
].join("\n");
|
|
195
204
|
}
|
|
196
205
|
|
|
206
|
+
/**
|
|
207
|
+
* Build a GroupSystemPrompt for watch-content triggered messages.
|
|
208
|
+
* Instructs the agent to reply only when confident, otherwise use NO_REPLY.
|
|
209
|
+
*/
|
|
210
|
+
function buildWatchRegexPrompt(pattern: string): string {
|
|
211
|
+
return [
|
|
212
|
+
`The message content matched the configured watch pattern (${pattern}).`,
|
|
213
|
+
"As the group assistant, you observed this message. Decide whether you can provide help or a valuable reply.",
|
|
214
|
+
"",
|
|
215
|
+
buildReplyJudgmentRules(),
|
|
216
|
+
].join("\n");
|
|
217
|
+
}
|
|
218
|
+
|
|
197
219
|
/**
|
|
198
220
|
* Build a GroupSystemPrompt for follow-up replies after bot's last response.
|
|
199
221
|
* Instructs the agent to reply only if the message is a follow-up on the same topic.
|
|
@@ -253,6 +275,7 @@ type ResolvedGroupConfig = {
|
|
|
253
275
|
followUp: boolean;
|
|
254
276
|
followUpWindow: number;
|
|
255
277
|
watchMentions: string[];
|
|
278
|
+
watchRegex?: string;
|
|
256
279
|
systemPrompt?: string;
|
|
257
280
|
};
|
|
258
281
|
|
|
@@ -277,6 +300,7 @@ function resolveGroupConfig(
|
|
|
277
300
|
followUp: groupCfg?.followUp ?? account.config.followUp ?? true,
|
|
278
301
|
followUpWindow: groupCfg?.followUpWindow ?? account.config.followUpWindow ?? 300,
|
|
279
302
|
watchMentions: groupCfg?.watchMentions ?? account.config.watchMentions ?? [],
|
|
303
|
+
watchRegex: groupCfg?.watchRegex ?? account.config.watchRegex,
|
|
280
304
|
systemPrompt: groupCfg?.systemPrompt,
|
|
281
305
|
};
|
|
282
306
|
}
|
|
@@ -676,6 +700,7 @@ export async function handleInfoflowMessage(params: HandleInfoflowMessageParams)
|
|
|
676
700
|
|
|
677
701
|
// Reply mode gating for group messages
|
|
678
702
|
// Session is already recorded above for context history
|
|
703
|
+
let triggerReason = "direct-message";
|
|
679
704
|
if (isGroup && groupCfg) {
|
|
680
705
|
const { replyMode } = groupCfg;
|
|
681
706
|
const groupIdStr = groupId !== undefined ? String(groupId) : undefined;
|
|
@@ -683,6 +708,9 @@ export async function handleInfoflowMessage(params: HandleInfoflowMessageParams)
|
|
|
683
708
|
// "record" mode: save to session only, no think, no reply
|
|
684
709
|
if (replyMode === "record") {
|
|
685
710
|
if (groupIdStr) {
|
|
711
|
+
logVerbose(
|
|
712
|
+
`[infoflow:bot] pending: from=${fromuser}, group=${groupId}, reason=record-mode`,
|
|
713
|
+
);
|
|
686
714
|
recordPendingHistoryEntryIfEnabled({
|
|
687
715
|
historyMap: chatHistories,
|
|
688
716
|
historyKey: groupIdStr,
|
|
@@ -699,16 +727,22 @@ export async function handleInfoflowMessage(params: HandleInfoflowMessageParams)
|
|
|
699
727
|
if (replyMode === "mention-only") {
|
|
700
728
|
// Only reply if bot was @mentioned
|
|
701
729
|
const shouldReply = canDetectMention && wasMentioned;
|
|
702
|
-
if (
|
|
730
|
+
if (shouldReply) {
|
|
731
|
+
triggerReason = "bot-mentioned";
|
|
732
|
+
} else {
|
|
703
733
|
// Check follow-up window: if bot recently replied, allow LLM to decide
|
|
704
734
|
if (
|
|
705
735
|
groupCfg.followUp &&
|
|
706
736
|
groupIdStr &&
|
|
707
737
|
isWithinFollowUpWindow(groupIdStr, groupCfg.followUpWindow)
|
|
708
738
|
) {
|
|
739
|
+
triggerReason = "followUp";
|
|
709
740
|
ctxPayload.GroupSystemPrompt = buildFollowUpPrompt();
|
|
710
741
|
} else {
|
|
711
742
|
if (groupIdStr) {
|
|
743
|
+
logVerbose(
|
|
744
|
+
`[infoflow:bot] pending: from=${fromuser}, group=${groupId}, reason=mention-only-not-mentioned`,
|
|
745
|
+
);
|
|
712
746
|
recordPendingHistoryEntryIfEnabled({
|
|
713
747
|
historyMap: chatHistories,
|
|
714
748
|
historyKey: groupIdStr,
|
|
@@ -722,7 +756,9 @@ export async function handleInfoflowMessage(params: HandleInfoflowMessageParams)
|
|
|
722
756
|
} else if (replyMode === "mention-and-watch") {
|
|
723
757
|
// Reply if bot @mentioned, or if watched person @mentioned, or follow-up
|
|
724
758
|
const botMentioned = canDetectMention && wasMentioned;
|
|
725
|
-
if (
|
|
759
|
+
if (botMentioned) {
|
|
760
|
+
triggerReason = "bot-mentioned";
|
|
761
|
+
} else {
|
|
726
762
|
// Check watch-mention
|
|
727
763
|
const watchMentions = groupCfg.watchMentions;
|
|
728
764
|
const matchedWatchId =
|
|
@@ -731,17 +767,26 @@ export async function handleInfoflowMessage(params: HandleInfoflowMessageParams)
|
|
|
731
767
|
: undefined;
|
|
732
768
|
|
|
733
769
|
if (matchedWatchId) {
|
|
770
|
+
triggerReason = `watchMentions(${matchedWatchId})`;
|
|
734
771
|
// Watch-mention triggered: instruct agent to reply only if confident
|
|
735
772
|
ctxPayload.GroupSystemPrompt = buildWatchMentionPrompt(matchedWatchId);
|
|
773
|
+
} else if (groupCfg.watchRegex && checkWatchRegex(mes, groupCfg.watchRegex)) {
|
|
774
|
+
triggerReason = `watchRegex(${groupCfg.watchRegex})`;
|
|
775
|
+
// Watch-content triggered: message matched configured regex pattern
|
|
776
|
+
ctxPayload.GroupSystemPrompt = buildWatchRegexPrompt(groupCfg.watchRegex);
|
|
736
777
|
} else if (
|
|
737
778
|
groupCfg.followUp &&
|
|
738
779
|
groupIdStr &&
|
|
739
780
|
isWithinFollowUpWindow(groupIdStr, groupCfg.followUpWindow)
|
|
740
781
|
) {
|
|
782
|
+
triggerReason = "followUp";
|
|
741
783
|
// Follow-up window: let LLM decide if this is a follow-up
|
|
742
784
|
ctxPayload.GroupSystemPrompt = buildFollowUpPrompt();
|
|
743
785
|
} else {
|
|
744
786
|
if (groupIdStr) {
|
|
787
|
+
logVerbose(
|
|
788
|
+
`[infoflow:bot] pending: from=${fromuser}, group=${groupId}, reason=mention-and-watch-no-trigger`,
|
|
789
|
+
);
|
|
745
790
|
recordPendingHistoryEntryIfEnabled({
|
|
746
791
|
historyMap: chatHistories,
|
|
747
792
|
historyKey: groupIdStr,
|
|
@@ -755,7 +800,9 @@ export async function handleInfoflowMessage(params: HandleInfoflowMessageParams)
|
|
|
755
800
|
} else if (replyMode === "proactive") {
|
|
756
801
|
// Always think and potentially reply
|
|
757
802
|
const botMentioned = canDetectMention && wasMentioned;
|
|
758
|
-
if (
|
|
803
|
+
if (botMentioned) {
|
|
804
|
+
triggerReason = "bot-mentioned";
|
|
805
|
+
} else {
|
|
759
806
|
// Check watch-mention first (higher priority prompt)
|
|
760
807
|
const watchMentions = groupCfg.watchMentions;
|
|
761
808
|
const matchedWatchId =
|
|
@@ -763,8 +810,10 @@ export async function handleInfoflowMessage(params: HandleInfoflowMessageParams)
|
|
|
763
810
|
? checkWatchMentioned(event.bodyItems, watchMentions)
|
|
764
811
|
: undefined;
|
|
765
812
|
if (matchedWatchId) {
|
|
813
|
+
triggerReason = `watchMentions(${matchedWatchId})`;
|
|
766
814
|
ctxPayload.GroupSystemPrompt = buildWatchMentionPrompt(matchedWatchId);
|
|
767
815
|
} else {
|
|
816
|
+
triggerReason = "proactive";
|
|
768
817
|
ctxPayload.GroupSystemPrompt = buildProactivePrompt();
|
|
769
818
|
}
|
|
770
819
|
}
|
|
@@ -796,6 +845,10 @@ export async function handleInfoflowMessage(params: HandleInfoflowMessageParams)
|
|
|
796
845
|
}
|
|
797
846
|
}
|
|
798
847
|
|
|
848
|
+
logVerbose(
|
|
849
|
+
`[infoflow:bot] dispatching to LLM: from=${fromuser}, group=${groupId ?? "N/A"}, trigger=${triggerReason}, replyMode=${groupCfg?.replyMode ?? "N/A"}`,
|
|
850
|
+
);
|
|
851
|
+
|
|
799
852
|
const { dispatcherOptions, replyOptions } = createInfoflowReplyDispatcher({
|
|
800
853
|
cfg,
|
|
801
854
|
agentId: route.agentId,
|
package/src/channel.ts
CHANGED
|
@@ -207,7 +207,7 @@ export const infoflowPlugin: ChannelPlugin<ResolvedInfoflowAccount> = {
|
|
|
207
207
|
outbound: {
|
|
208
208
|
deliveryMode: "direct",
|
|
209
209
|
chunkerMode: "markdown",
|
|
210
|
-
textChunkLimit:
|
|
210
|
+
textChunkLimit: 2048,
|
|
211
211
|
chunker: (text, limit) => getInfoflowRuntime().channel.text.chunkText(text, limit),
|
|
212
212
|
sendText: async ({ cfg, to, text, accountId }) => {
|
|
213
213
|
logVerbose(`[infoflow:sendText] to=${to}, accountId=${accountId}`);
|
package/src/reply-dispatcher.ts
CHANGED
|
@@ -148,8 +148,8 @@ export function createInfoflowReplyDispatcher(params: CreateInfoflowReplyDispatc
|
|
|
148
148
|
messageText = atPrefix + text;
|
|
149
149
|
}
|
|
150
150
|
|
|
151
|
-
// Chunk text to
|
|
152
|
-
const chunks = core.channel.text.chunkText(messageText,
|
|
151
|
+
// Chunk text to 2048 chars max (Infoflow limit)
|
|
152
|
+
const chunks = core.channel.text.chunkText(messageText, 2048);
|
|
153
153
|
// Only include @mentions in the first chunk (avoid duplicate @s)
|
|
154
154
|
let isFirstChunk = true;
|
|
155
155
|
|
package/src/types.ts
CHANGED
|
@@ -22,6 +22,7 @@ export type InfoflowReplyMode =
|
|
|
22
22
|
export type InfoflowGroupConfig = {
|
|
23
23
|
replyMode?: InfoflowReplyMode;
|
|
24
24
|
watchMentions?: string[];
|
|
25
|
+
watchRegex?: string;
|
|
25
26
|
followUp?: boolean;
|
|
26
27
|
followUpWindow?: number;
|
|
27
28
|
systemPrompt?: string;
|
|
@@ -112,6 +113,8 @@ export type InfoflowAccountConfig = {
|
|
|
112
113
|
/** Names to watch for @mentions; when someone @mentions a person in this list,
|
|
113
114
|
* the bot analyzes the message and replies only if confident. */
|
|
114
115
|
watchMentions?: string[];
|
|
116
|
+
/** Regex pattern to watch for in message content; triggers bot activation when matched */
|
|
117
|
+
watchRegex?: string;
|
|
115
118
|
/** Reply mode controlling bot engagement level in groups */
|
|
116
119
|
replyMode?: InfoflowReplyMode;
|
|
117
120
|
/** Enable follow-up replies after bot responds to a mention (default: true) */
|
|
@@ -149,6 +152,8 @@ export type ResolvedInfoflowAccount = {
|
|
|
149
152
|
/** Names to watch for @mentions; when someone @mentions a person in this list,
|
|
150
153
|
* the bot analyzes the message and replies only if confident. */
|
|
151
154
|
watchMentions?: string[];
|
|
155
|
+
/** Regex pattern to watch for in message content; triggers bot activation when matched */
|
|
156
|
+
watchRegex?: string;
|
|
152
157
|
/** Reply mode controlling bot engagement level in groups */
|
|
153
158
|
replyMode?: InfoflowReplyMode;
|
|
154
159
|
/** Enable follow-up replies after bot responds to a mention (default: true) */
|