@chbo297/infoflow 2026.3.16 → 2026.3.18
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 +11 -0
- package/README.md +4 -0
- package/package.json +1 -1
- package/src/bot.ts +109 -24
- package/src/infoflow-req-parse.ts +56 -0
- package/src/types.ts +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2026.3.17
|
|
4
|
+
|
|
5
|
+
### 修复与优化
|
|
6
|
+
|
|
7
|
+
#### follow-up(跟进回复)策略
|
|
8
|
+
|
|
9
|
+
- **他人被 @ 时仅记录不派发**:在 follow-up 时间窗口内,若新消息 @ 了其他人或机器人(而非本 bot),则仅写入会话历史、不派发 LLM,避免误判为对机器人的追问。
|
|
10
|
+
- **LLM 可见 body 含 robotid**:群消息中 @ 提及会以「@名称 (robotid:N)」形式呈现给模型,便于区分不同机器人并做出更准确的回复判断。
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
3
14
|
## 2026.3.15
|
|
4
15
|
|
|
5
16
|
### 新功能
|
package/README.md
CHANGED
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
|
|
9
9
|
百度如流 (Infoflow) 企业消息平台 — OpenClaw 频道插件。
|
|
10
10
|
|
|
11
|
+
📦 **[npm](https://www.npmjs.com/package/@chbo297/infoflow)**
|
|
12
|
+
|
|
11
13
|
## 特性
|
|
12
14
|
|
|
13
15
|
- **私聊 & 群聊**消息接收与回复
|
|
@@ -279,6 +281,8 @@ MIT
|
|
|
279
281
|
|
|
280
282
|
Baidu Infoflow (如流) enterprise messaging platform — OpenClaw channel plugin.
|
|
281
283
|
|
|
284
|
+
📦 **[npm](https://www.npmjs.com/package/@chbo297/infoflow)**
|
|
285
|
+
|
|
282
286
|
## Features
|
|
283
287
|
|
|
284
288
|
- **Direct & group** message receiving and replying
|
package/package.json
CHANGED
package/src/bot.ts
CHANGED
|
@@ -194,6 +194,38 @@ function hasOtherMentions(mentionIds?: InfoflowMentionIds): boolean {
|
|
|
194
194
|
return mentionIds.userIds.length > 0 || mentionIds.agentIds.length > 0;
|
|
195
195
|
}
|
|
196
196
|
|
|
197
|
+
/**
|
|
198
|
+
* When in follow-up window and message has other @mentions (not this bot): record only and
|
|
199
|
+
* return "record_only" (no LLM dispatch). Otherwise return "dispatch".
|
|
200
|
+
*/
|
|
201
|
+
function resolveFollowUpOtherMentioned(params: {
|
|
202
|
+
mentionIds: InfoflowMentionIds | undefined;
|
|
203
|
+
groupId: number | undefined;
|
|
204
|
+
bodyForAgent: string;
|
|
205
|
+
senderName: string;
|
|
206
|
+
fromuser: string;
|
|
207
|
+
}): "record_only" | "dispatch" {
|
|
208
|
+
const { mentionIds, groupId, bodyForAgent, senderName, fromuser } = params;
|
|
209
|
+
if (!hasOtherMentions(mentionIds)) return "dispatch";
|
|
210
|
+
const groupIdStr = groupId != null ? String(groupId) : undefined;
|
|
211
|
+
if (groupIdStr) {
|
|
212
|
+
recordPendingHistoryEntryIfEnabled({
|
|
213
|
+
historyMap: chatHistories,
|
|
214
|
+
historyKey: groupIdStr,
|
|
215
|
+
entry: {
|
|
216
|
+
sender: senderName || fromuser,
|
|
217
|
+
body: bodyForAgent,
|
|
218
|
+
timestamp: Date.now(),
|
|
219
|
+
},
|
|
220
|
+
limit: DEFAULT_GROUP_HISTORY_LIMIT,
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
logVerbose(
|
|
224
|
+
`[infoflow:bot] skip dispatch: from=${fromuser}, group=${groupId}, reason=followUp-other-mentioned (record only, no LLM)`,
|
|
225
|
+
);
|
|
226
|
+
return "record_only";
|
|
227
|
+
}
|
|
228
|
+
|
|
197
229
|
// ---------------------------------------------------------------------------
|
|
198
230
|
// Reply-to-bot detection (引用回复机器人消息)
|
|
199
231
|
// ---------------------------------------------------------------------------
|
|
@@ -347,18 +379,6 @@ function buildFollowUpPrompt(isReplyToBot: boolean): string {
|
|
|
347
379
|
return lines.join("\n");
|
|
348
380
|
}
|
|
349
381
|
|
|
350
|
-
/**
|
|
351
|
-
* Build a GroupSystemPrompt for follow-up messages that @mention another person or bot.
|
|
352
|
-
* Uses the conservative ReplyJudgmentRules since the message is likely directed at someone else.
|
|
353
|
-
*/
|
|
354
|
-
function buildFollowUpOtherMentionedPrompt(): string {
|
|
355
|
-
return [
|
|
356
|
-
"You recently replied in this group. A new message has arrived, but it @mentions another person or bot — it is likely directed at them, not at you.",
|
|
357
|
-
"",
|
|
358
|
-
buildReplyJudgmentRules(),
|
|
359
|
-
].join("\n");
|
|
360
|
-
}
|
|
361
|
-
|
|
362
382
|
/**
|
|
363
383
|
* Build a GroupSystemPrompt for proactive mode.
|
|
364
384
|
* Instructs the agent to think about the message and reply when helpful.
|
|
@@ -585,9 +605,11 @@ export async function handleGroupChatMessage(params: HandleGroupChatParams): Pro
|
|
|
585
605
|
// Extract non-bot mention IDs (userIds + agentIds) for LLM-driven @mentions
|
|
586
606
|
const mentionIds = extractMentionIds(bodyItems, robotName);
|
|
587
607
|
|
|
588
|
-
// Build
|
|
608
|
+
// Build three versions: mes (for CommandBody, no @xxx), rawMes (for RawBody, with @xxx),
|
|
609
|
+
// and bodyForAgent (for LLM: @name with robotid when present so model sees "@地图不打烊 (robotid:N)")
|
|
589
610
|
let textContent = "";
|
|
590
611
|
let rawTextContent = "";
|
|
612
|
+
let agentVisibleText = "";
|
|
591
613
|
const replyContextItems: string[] = [];
|
|
592
614
|
const imageUrls: string[] = [];
|
|
593
615
|
if (Array.isArray(bodyItems)) {
|
|
@@ -601,17 +623,21 @@ export async function handleGroupChatMessage(params: HandleGroupChatParams): Pro
|
|
|
601
623
|
} else if (item.type === "TEXT" || item.type === "MD") {
|
|
602
624
|
textContent += item.content ?? "";
|
|
603
625
|
rawTextContent += item.content ?? "";
|
|
626
|
+
agentVisibleText += item.content ?? "";
|
|
604
627
|
} else if (item.type === "LINK") {
|
|
605
628
|
const label = item.label ?? "";
|
|
606
629
|
if (label) {
|
|
607
630
|
textContent += ` ${label} `;
|
|
608
631
|
rawTextContent += ` ${label} `;
|
|
632
|
+
agentVisibleText += ` ${label} `;
|
|
609
633
|
}
|
|
610
634
|
} else if (item.type === "AT") {
|
|
611
|
-
// AT elements only go into rawTextContent, not textContent
|
|
635
|
+
// AT elements only go into rawTextContent and agentVisibleText, not textContent
|
|
612
636
|
const name = item.name ?? "";
|
|
613
637
|
if (name) {
|
|
614
638
|
rawTextContent += `@${name} `;
|
|
639
|
+
agentVisibleText +=
|
|
640
|
+
item.robotid != null ? `@${name} (robotid:${item.robotid}) ` : `@${name} `;
|
|
615
641
|
}
|
|
616
642
|
} else if (item.type === "IMAGE") {
|
|
617
643
|
// 提取图片下载地址
|
|
@@ -623,6 +649,7 @@ export async function handleGroupChatMessage(params: HandleGroupChatParams): Pro
|
|
|
623
649
|
// Fallback: for any other item types with string content, treat content as text.
|
|
624
650
|
textContent += item.content;
|
|
625
651
|
rawTextContent += item.content;
|
|
652
|
+
agentVisibleText += item.content;
|
|
626
653
|
}
|
|
627
654
|
}
|
|
628
655
|
}
|
|
@@ -643,6 +670,8 @@ export async function handleGroupChatMessage(params: HandleGroupChatParams): Pro
|
|
|
643
670
|
if (!mes && replyContext) {
|
|
644
671
|
mes = "(引用回复)";
|
|
645
672
|
}
|
|
673
|
+
// Body for LLM: include @mentions with robotid so model sees e.g. "@地图不打烊 (robotid:N)"
|
|
674
|
+
const bodyForAgent = agentVisibleText.trim() || rawMes || mes;
|
|
646
675
|
|
|
647
676
|
// Extract sender name from header or fallback to fromuser
|
|
648
677
|
const senderName = String(header?.username ?? header?.nickname ?? msgData.username ?? fromuser);
|
|
@@ -657,6 +686,7 @@ export async function handleGroupChatMessage(params: HandleGroupChatParams): Pro
|
|
|
657
686
|
fromuser,
|
|
658
687
|
mes,
|
|
659
688
|
rawMes,
|
|
689
|
+
bodyForAgent,
|
|
660
690
|
chatType: "group",
|
|
661
691
|
groupId: groupid,
|
|
662
692
|
senderName,
|
|
@@ -682,6 +712,8 @@ export async function handleGroupChatMessage(params: HandleGroupChatParams): Pro
|
|
|
682
712
|
export async function handleInfoflowMessage(params: HandleInfoflowMessageParams): Promise<void> {
|
|
683
713
|
const { cfg, event, accountId, statusSink } = params;
|
|
684
714
|
const { fromuser, mes, chatType, groupId, senderName } = event;
|
|
715
|
+
// Single source for "body shown to LLM": already computed in group handler (line ~666)
|
|
716
|
+
const bodyForAgent = event.bodyForAgent ?? mes;
|
|
685
717
|
|
|
686
718
|
const account = resolveInfoflowAccount({ cfg, accountId });
|
|
687
719
|
const core = getInfoflowRuntime();
|
|
@@ -729,7 +761,7 @@ export async function handleInfoflowMessage(params: HandleInfoflowMessageParams)
|
|
|
729
761
|
timestamp: Date.now(),
|
|
730
762
|
previousTimestamp,
|
|
731
763
|
envelope: envelopeOptions,
|
|
732
|
-
body:
|
|
764
|
+
body: bodyForAgent,
|
|
733
765
|
});
|
|
734
766
|
|
|
735
767
|
// Inject accumulated group chat history into the body for context
|
|
@@ -844,6 +876,7 @@ export async function handleInfoflowMessage(params: HandleInfoflowMessageParams)
|
|
|
844
876
|
Body: combinedBody,
|
|
845
877
|
RawBody: event.rawMes ?? mes,
|
|
846
878
|
CommandBody: mes,
|
|
879
|
+
BodyForAgent: bodyForAgent,
|
|
847
880
|
From: fromAddress,
|
|
848
881
|
To: toAddress,
|
|
849
882
|
SessionKey: route.sessionKey,
|
|
@@ -866,6 +899,14 @@ export async function handleInfoflowMessage(params: HandleInfoflowMessageParams)
|
|
|
866
899
|
...mediaPayload,
|
|
867
900
|
});
|
|
868
901
|
|
|
902
|
+
// Ensure BodyForAgent stays set for group messages (with @ and robotid) so the LLM sees full context
|
|
903
|
+
if (isGroup && bodyForAgent !== mes) {
|
|
904
|
+
(ctxPayload as Record<string, unknown>).BodyForAgent = bodyForAgent;
|
|
905
|
+
logVerbose(
|
|
906
|
+
`[infoflow] group: BodyForAgent set for LLM (${bodyForAgent.length} chars, includes @/robotid)`,
|
|
907
|
+
);
|
|
908
|
+
}
|
|
909
|
+
|
|
869
910
|
// Record session using recordInboundSession for proper session tracking
|
|
870
911
|
await core.channel.session.recordInboundSession({
|
|
871
912
|
storePath,
|
|
@@ -894,7 +935,11 @@ export async function handleInfoflowMessage(params: HandleInfoflowMessageParams)
|
|
|
894
935
|
recordPendingHistoryEntryIfEnabled({
|
|
895
936
|
historyMap: chatHistories,
|
|
896
937
|
historyKey: groupIdStr,
|
|
897
|
-
entry: {
|
|
938
|
+
entry: {
|
|
939
|
+
sender: senderName || fromuser,
|
|
940
|
+
body: bodyForAgent,
|
|
941
|
+
timestamp: Date.now(),
|
|
942
|
+
},
|
|
898
943
|
limit: DEFAULT_GROUP_HISTORY_LIMIT,
|
|
899
944
|
});
|
|
900
945
|
}
|
|
@@ -917,8 +962,17 @@ export async function handleInfoflowMessage(params: HandleInfoflowMessageParams)
|
|
|
917
962
|
isWithinFollowUpWindow(groupIdStr, groupCfg.followUpWindow)
|
|
918
963
|
) {
|
|
919
964
|
if (hasOtherMentions(event.mentionIds)) {
|
|
920
|
-
|
|
921
|
-
|
|
965
|
+
if (
|
|
966
|
+
resolveFollowUpOtherMentioned({
|
|
967
|
+
mentionIds: event.mentionIds,
|
|
968
|
+
groupId,
|
|
969
|
+
bodyForAgent,
|
|
970
|
+
senderName: senderName || fromuser,
|
|
971
|
+
fromuser,
|
|
972
|
+
}) === "record_only"
|
|
973
|
+
) {
|
|
974
|
+
return;
|
|
975
|
+
}
|
|
922
976
|
} else {
|
|
923
977
|
triggerReason = "followUp";
|
|
924
978
|
ctxPayload.GroupSystemPrompt = buildFollowUpPrompt(event.isReplyToBot === true);
|
|
@@ -931,7 +985,11 @@ export async function handleInfoflowMessage(params: HandleInfoflowMessageParams)
|
|
|
931
985
|
recordPendingHistoryEntryIfEnabled({
|
|
932
986
|
historyMap: chatHistories,
|
|
933
987
|
historyKey: groupIdStr,
|
|
934
|
-
entry: {
|
|
988
|
+
entry: {
|
|
989
|
+
sender: senderName || fromuser,
|
|
990
|
+
body: bodyForAgent,
|
|
991
|
+
timestamp: Date.now(),
|
|
992
|
+
},
|
|
935
993
|
limit: DEFAULT_GROUP_HISTORY_LIMIT,
|
|
936
994
|
});
|
|
937
995
|
}
|
|
@@ -969,8 +1027,17 @@ export async function handleInfoflowMessage(params: HandleInfoflowMessageParams)
|
|
|
969
1027
|
isWithinFollowUpWindow(groupIdStr, groupCfg.followUpWindow)
|
|
970
1028
|
) {
|
|
971
1029
|
if (hasOtherMentions(event.mentionIds)) {
|
|
972
|
-
|
|
973
|
-
|
|
1030
|
+
if (
|
|
1031
|
+
resolveFollowUpOtherMentioned({
|
|
1032
|
+
mentionIds: event.mentionIds,
|
|
1033
|
+
groupId,
|
|
1034
|
+
bodyForAgent,
|
|
1035
|
+
senderName: senderName || fromuser,
|
|
1036
|
+
fromuser,
|
|
1037
|
+
}) === "record_only"
|
|
1038
|
+
) {
|
|
1039
|
+
return;
|
|
1040
|
+
}
|
|
974
1041
|
} else {
|
|
975
1042
|
triggerReason = "followUp";
|
|
976
1043
|
ctxPayload.GroupSystemPrompt = buildFollowUpPrompt(event.isReplyToBot === true);
|
|
@@ -983,7 +1050,11 @@ export async function handleInfoflowMessage(params: HandleInfoflowMessageParams)
|
|
|
983
1050
|
recordPendingHistoryEntryIfEnabled({
|
|
984
1051
|
historyMap: chatHistories,
|
|
985
1052
|
historyKey: groupIdStr,
|
|
986
|
-
entry: {
|
|
1053
|
+
entry: {
|
|
1054
|
+
sender: senderName || fromuser,
|
|
1055
|
+
body: bodyForAgent,
|
|
1056
|
+
timestamp: Date.now(),
|
|
1057
|
+
},
|
|
987
1058
|
limit: DEFAULT_GROUP_HISTORY_LIMIT,
|
|
988
1059
|
});
|
|
989
1060
|
}
|
|
@@ -1038,8 +1109,22 @@ export async function handleInfoflowMessage(params: HandleInfoflowMessageParams)
|
|
|
1038
1109
|
}
|
|
1039
1110
|
}
|
|
1040
1111
|
|
|
1112
|
+
const mentionIdsLog =
|
|
1113
|
+
isGroup && event.mentionIds
|
|
1114
|
+
? `, mentionIds={userIds:[${event.mentionIds.userIds.join(",")}], agentIds:[${event.mentionIds.agentIds.join(",")}]}`
|
|
1115
|
+
: "";
|
|
1116
|
+
const bodyPreview =
|
|
1117
|
+
(ctxPayload as Record<string, unknown>).Body != null
|
|
1118
|
+
? String((ctxPayload as Record<string, unknown>).Body)
|
|
1119
|
+
: "";
|
|
1120
|
+
const bodyLog = `bodyLen=${bodyPreview.length} bodyPreview=${bodyPreview.length > 5000 ? bodyPreview.slice(0, 5000) + "..." : bodyPreview}`;
|
|
1121
|
+
const sysPrompt =
|
|
1122
|
+
(ctxPayload as Record<string, unknown>).GroupSystemPrompt != null
|
|
1123
|
+
? String((ctxPayload as Record<string, unknown>).GroupSystemPrompt)
|
|
1124
|
+
: "";
|
|
1125
|
+
const sysPromptLog = `groupSystemPromptLen=${sysPrompt.length} groupSystemPromptPreview=${sysPrompt.length > 5000 ? sysPrompt.slice(0, 5000) + "..." : sysPrompt}`;
|
|
1041
1126
|
logVerbose(
|
|
1042
|
-
`[infoflow:bot] dispatching to LLM: from=${fromuser}, group=${groupId ?? "N/A"}, trigger=${triggerReason}, replyMode=${groupCfg?.replyMode ?? "N/A"}`,
|
|
1127
|
+
`[infoflow:bot] dispatching to LLM: from=${fromuser}, group=${groupId ?? "N/A"}, trigger=${triggerReason}, replyMode=${groupCfg?.replyMode ?? "N/A"}${mentionIdsLog} | ${bodyLog} | ${sysPromptLog}`,
|
|
1043
1128
|
);
|
|
1044
1129
|
|
|
1045
1130
|
const { dispatcherOptions, replyOptions } = createInfoflowReplyDispatcher({
|
|
@@ -1054,7 +1139,7 @@ export async function handleInfoflowMessage(params: HandleInfoflowMessageParams)
|
|
|
1054
1139
|
mentionIds: isGroup ? event.mentionIds : undefined,
|
|
1055
1140
|
// Pass inbound messageId for outbound reply-to (group only)
|
|
1056
1141
|
replyToMessageId: isGroup ? event.messageId : undefined,
|
|
1057
|
-
replyToPreview: isGroup ?
|
|
1142
|
+
replyToPreview: isGroup ? bodyForAgent : undefined,
|
|
1058
1143
|
mediaLocalRoots: getAgentScopedMediaLocalRoots(cfg, route.agentId),
|
|
1059
1144
|
});
|
|
1060
1145
|
|
|
@@ -9,6 +9,55 @@ import { handlePrivateChatMessage, handleGroupChatMessage } from "./bot.js";
|
|
|
9
9
|
import type { ResolvedInfoflowAccount } from "./channel.js";
|
|
10
10
|
import { getInfoflowParseLog, formatInfoflowError, logVerbose } from "./logging.js";
|
|
11
11
|
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
// Large-integer precision protection
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
|
|
16
|
+
// Infoflow message IDs (e.g. 1859713223686736431) exceed Number.MAX_SAFE_INTEGER (2^53-1).
|
|
17
|
+
// JSON.parse silently truncates these to imprecise values.
|
|
18
|
+
// We extract precise strings from raw JSON text via regex and patch the parsed object.
|
|
19
|
+
const ID_KEYS = ["messageid", "msgid", "MsgId", "msgkey"] as const;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Patches large integer ID fields in `obj` with precise string values
|
|
23
|
+
* extracted from `rawText` via regex, bypassing JSON.parse precision loss.
|
|
24
|
+
* Only patches values with 16+ digits (smaller integers are safe).
|
|
25
|
+
*/
|
|
26
|
+
function patchPreciseIds(rawText: string, obj: Record<string, unknown>): void {
|
|
27
|
+
for (const key of ID_KEYS) {
|
|
28
|
+
const re = new RegExp(`"${key}"\\s*:\\s*(\\d{16,})`, "g");
|
|
29
|
+
const preciseValues: string[] = [];
|
|
30
|
+
let m;
|
|
31
|
+
while ((m = re.exec(rawText)) !== null) {
|
|
32
|
+
preciseValues.push(m[1]);
|
|
33
|
+
}
|
|
34
|
+
if (preciseValues.length > 0) {
|
|
35
|
+
patchField(obj, key, preciseValues, 0);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Recursively walks `obj` and replaces numeric fields named `key` with precise strings (in order). */
|
|
41
|
+
function patchField(obj: unknown, key: string, values: string[], idx: number): number {
|
|
42
|
+
if (obj == null || typeof obj !== "object") return idx;
|
|
43
|
+
if (Array.isArray(obj)) {
|
|
44
|
+
for (const item of obj) {
|
|
45
|
+
idx = patchField(item, key, values, idx);
|
|
46
|
+
}
|
|
47
|
+
return idx;
|
|
48
|
+
}
|
|
49
|
+
const rec = obj as Record<string, unknown>;
|
|
50
|
+
if (key in rec && typeof rec[key] === "number" && idx < values.length) {
|
|
51
|
+
rec[key] = values[idx++];
|
|
52
|
+
}
|
|
53
|
+
for (const v of Object.values(rec)) {
|
|
54
|
+
if (v != null && typeof v === "object") {
|
|
55
|
+
idx = patchField(v, key, values, idx);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return idx;
|
|
59
|
+
}
|
|
60
|
+
|
|
12
61
|
const DEDUP_TTL_MS = 5 * 60 * 1000; // 5 minutes
|
|
13
62
|
const DEDUP_MAX_SIZE = 1000;
|
|
14
63
|
|
|
@@ -309,10 +358,13 @@ function tryDecryptAndDispatch(params: DecryptDispatchParams): ParseResult {
|
|
|
309
358
|
continue; // Try next account
|
|
310
359
|
}
|
|
311
360
|
|
|
361
|
+
logVerbose(`[infoflow] ${chatType}: decryptedContent=(${decryptedContent})`);
|
|
362
|
+
|
|
312
363
|
// Parse as JSON first, then try fallback parser (XML for private)
|
|
313
364
|
let msgData: Record<string, unknown> | null = null;
|
|
314
365
|
try {
|
|
315
366
|
msgData = JSON.parse(decryptedContent) as Record<string, unknown>;
|
|
367
|
+
patchPreciseIds(decryptedContent, msgData);
|
|
316
368
|
} catch {
|
|
317
369
|
if (fallbackParser) {
|
|
318
370
|
msgData = fallbackParser(decryptedContent);
|
|
@@ -357,6 +409,7 @@ function handlePrivateMessage(messageJsonStr: string, targets: WebhookTarget[]):
|
|
|
357
409
|
let messageJson: Record<string, unknown>;
|
|
358
410
|
try {
|
|
359
411
|
messageJson = JSON.parse(messageJsonStr) as Record<string, unknown>;
|
|
412
|
+
patchPreciseIds(messageJsonStr, messageJson);
|
|
360
413
|
} catch {
|
|
361
414
|
getInfoflowParseLog().error(`[infoflow] private: invalid messageJson`);
|
|
362
415
|
return { handled: true, statusCode: 400, body: "invalid messageJson" };
|
|
@@ -430,3 +483,6 @@ export const _parseXmlMessage = parseXmlMessage;
|
|
|
430
483
|
export function _resetMessageCache(): void {
|
|
431
484
|
messageCache.clear();
|
|
432
485
|
}
|
|
486
|
+
|
|
487
|
+
/** @internal */
|
|
488
|
+
export const _patchPreciseIds = patchPreciseIds;
|
package/src/types.ts
CHANGED
|
@@ -191,6 +191,8 @@ export type InfoflowMessageEvent = {
|
|
|
191
191
|
timestamp?: number;
|
|
192
192
|
/** Raw message text preserving @mentions (for RawBody) */
|
|
193
193
|
rawMes?: string;
|
|
194
|
+
/** Message text for the LLM including @mentions and robotid (BodyForAgent) */
|
|
195
|
+
bodyForAgent?: string;
|
|
194
196
|
/** Raw body items from group message (for watch-mention detection) */
|
|
195
197
|
bodyItems?: InfoflowInboundBodyItem[];
|
|
196
198
|
/** Non-bot mention IDs extracted from AT items in group messages (excluding bot itself) */
|