@chbo297/infoflow 2026.3.6 → 2026.3.7
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/package.json +1 -1
- package/src/actions.ts +10 -14
- package/src/bot.ts +6 -161
- package/src/channel.ts +1 -0
- package/src/infoflow-req-parse.ts +2 -2
- package/src/media.ts +3 -1
- package/src/send.ts +15 -14
- package/src/sent-message-store.ts +34 -5
- package/src/types.ts +0 -6
package/package.json
CHANGED
package/src/actions.ts
CHANGED
|
@@ -22,6 +22,12 @@ import {
|
|
|
22
22
|
import { normalizeInfoflowTarget } from "./targets.js";
|
|
23
23
|
import type { InfoflowMessageContentItem, InfoflowOutboundReply } from "./types.js";
|
|
24
24
|
|
|
25
|
+
// Recall result hint constants — reused across single/batch, group/private recall paths
|
|
26
|
+
const RECALL_OK_HINT = "Recall succeeded. output only NO_REPLY with no other text.";
|
|
27
|
+
const RECALL_FAIL_HINT = "Recall failed. Send a brief reply stating only the failure reason.";
|
|
28
|
+
const RECALL_PARTIAL_HINT =
|
|
29
|
+
"Some recalls failed. Send a brief reply stating only the failure reason(s).";
|
|
30
|
+
|
|
25
31
|
export const infoflowMessageActions: ChannelMessageActionAdapter = {
|
|
26
32
|
listActions: (): ChannelMessageActionName[] => ["send", "delete"],
|
|
27
33
|
|
|
@@ -91,9 +97,7 @@ export const infoflowMessageActions: ChannelMessageActionAdapter = {
|
|
|
91
97
|
channel: "infoflow",
|
|
92
98
|
to,
|
|
93
99
|
...(result.error ? { error: result.error } : {}),
|
|
94
|
-
_hint: result.ok
|
|
95
|
-
? "Recall succeeded. Do NOT send any follow-up reply message to the user."
|
|
96
|
-
: "Recall failed. Send a brief reply stating only the failure reason.",
|
|
100
|
+
_hint: result.ok ? RECALL_OK_HINT : RECALL_FAIL_HINT,
|
|
97
101
|
});
|
|
98
102
|
}
|
|
99
103
|
|
|
@@ -171,10 +175,7 @@ export const infoflowMessageActions: ChannelMessageActionAdapter = {
|
|
|
171
175
|
failed,
|
|
172
176
|
total: recallable.length,
|
|
173
177
|
details,
|
|
174
|
-
_hint:
|
|
175
|
-
failed === 0
|
|
176
|
-
? "Recall succeeded. Do NOT send any follow-up reply message to the user."
|
|
177
|
-
: "Some recalls failed. Send a brief reply stating only the failure reason(s).",
|
|
178
|
+
_hint: failed === 0 ? RECALL_OK_HINT : RECALL_PARTIAL_HINT,
|
|
178
179
|
});
|
|
179
180
|
}
|
|
180
181
|
} else {
|
|
@@ -210,9 +211,7 @@ export const infoflowMessageActions: ChannelMessageActionAdapter = {
|
|
|
210
211
|
channel: "infoflow",
|
|
211
212
|
to,
|
|
212
213
|
...(result.error ? { error: result.error } : {}),
|
|
213
|
-
_hint: result.ok
|
|
214
|
-
? "Recall succeeded. Do NOT send any follow-up reply message to the user."
|
|
215
|
-
: "Recall failed. Send a brief reply stating only the failure reason.",
|
|
214
|
+
_hint: result.ok ? RECALL_OK_HINT : RECALL_FAIL_HINT,
|
|
216
215
|
});
|
|
217
216
|
}
|
|
218
217
|
|
|
@@ -286,10 +285,7 @@ export const infoflowMessageActions: ChannelMessageActionAdapter = {
|
|
|
286
285
|
failed,
|
|
287
286
|
total: recallable.length,
|
|
288
287
|
details,
|
|
289
|
-
_hint:
|
|
290
|
-
failed === 0
|
|
291
|
-
? "Recall succeeded. Do NOT send any follow-up reply message to the user."
|
|
292
|
-
: "Some recalls failed. Send a brief reply stating only the failure reason(s).",
|
|
288
|
+
_hint: failed === 0 ? RECALL_OK_HINT : RECALL_PARTIAL_HINT,
|
|
293
289
|
});
|
|
294
290
|
}
|
|
295
291
|
}
|
package/src/bot.ts
CHANGED
|
@@ -5,23 +5,15 @@ import {
|
|
|
5
5
|
type HistoryEntry,
|
|
6
6
|
recordPendingHistoryEntryIfEnabled,
|
|
7
7
|
buildAgentMediaPayload,
|
|
8
|
-
type OpenClawConfig,
|
|
9
|
-
type ReplyPayload,
|
|
10
8
|
} from "openclaw/plugin-sdk";
|
|
11
9
|
import { resolveInfoflowAccount } from "./accounts.js";
|
|
12
10
|
import { getInfoflowBotLog, formatInfoflowError, logVerbose } from "./logging.js";
|
|
13
11
|
import { createInfoflowReplyDispatcher } from "./reply-dispatcher.js";
|
|
14
12
|
import { getInfoflowRuntime } from "./runtime.js";
|
|
15
|
-
import {
|
|
16
|
-
sendInfoflowMessage,
|
|
17
|
-
recallInfoflowGroupMessage,
|
|
18
|
-
recallInfoflowPrivateMessage,
|
|
19
|
-
} from "./send.js";
|
|
20
13
|
import type {
|
|
21
14
|
InfoflowChatType,
|
|
22
15
|
InfoflowMessageEvent,
|
|
23
16
|
InfoflowMentionIds,
|
|
24
|
-
InfoflowOutboundReply,
|
|
25
17
|
InfoflowReplyMode,
|
|
26
18
|
InfoflowGroupConfig,
|
|
27
19
|
HandleInfoflowMessageParams,
|
|
@@ -262,7 +254,6 @@ type ResolvedGroupConfig = {
|
|
|
262
254
|
followUpWindow: number;
|
|
263
255
|
watchMentions: string[];
|
|
264
256
|
systemPrompt?: string;
|
|
265
|
-
thinkingIndicator: boolean;
|
|
266
257
|
};
|
|
267
258
|
|
|
268
259
|
/** Infer replyMode from legacy requireMention + watchMentions fields */
|
|
@@ -287,104 +278,9 @@ function resolveGroupConfig(
|
|
|
287
278
|
followUpWindow: groupCfg?.followUpWindow ?? account.config.followUpWindow ?? 300,
|
|
288
279
|
watchMentions: groupCfg?.watchMentions ?? account.config.watchMentions ?? [],
|
|
289
280
|
systemPrompt: groupCfg?.systemPrompt,
|
|
290
|
-
thinkingIndicator: groupCfg?.thinkingIndicator ?? account.config.thinkingIndicator ?? true,
|
|
291
281
|
};
|
|
292
282
|
}
|
|
293
283
|
|
|
294
|
-
// ---------------------------------------------------------------------------
|
|
295
|
-
// Thinking indicator (收到🤔...)
|
|
296
|
-
// ---------------------------------------------------------------------------
|
|
297
|
-
|
|
298
|
-
type ThinkingIndicatorHandle = {
|
|
299
|
-
messageid: string;
|
|
300
|
-
msgseqid: string;
|
|
301
|
-
};
|
|
302
|
-
|
|
303
|
-
/**
|
|
304
|
-
* Sends a "收到🤔..." thinking indicator message.
|
|
305
|
-
* Returns message IDs needed for recall, or undefined on failure.
|
|
306
|
-
*/
|
|
307
|
-
async function sendThinkingIndicator(params: {
|
|
308
|
-
cfg: OpenClawConfig;
|
|
309
|
-
to: string;
|
|
310
|
-
accountId: string;
|
|
311
|
-
replyTo?: InfoflowOutboundReply;
|
|
312
|
-
}): Promise<ThinkingIndicatorHandle | undefined> {
|
|
313
|
-
const { cfg, to, accountId, replyTo } = params;
|
|
314
|
-
try {
|
|
315
|
-
const result = await sendInfoflowMessage({
|
|
316
|
-
cfg,
|
|
317
|
-
to,
|
|
318
|
-
contents: [{ type: "text", content: "收到🤔..." }],
|
|
319
|
-
accountId,
|
|
320
|
-
replyTo,
|
|
321
|
-
});
|
|
322
|
-
if (result.ok && result.messageId) {
|
|
323
|
-
logVerbose(
|
|
324
|
-
`[infoflow] thinking indicator sent: to=${to}, messageId=${result.messageId}, msgseqid=${result.msgseqid ?? "n/a"}`,
|
|
325
|
-
);
|
|
326
|
-
return { messageid: result.messageId, msgseqid: result.msgseqid ?? "" };
|
|
327
|
-
}
|
|
328
|
-
if (!result.ok) {
|
|
329
|
-
logVerbose(`[infoflow] thinking indicator send failed: ${result.error}`);
|
|
330
|
-
}
|
|
331
|
-
return undefined;
|
|
332
|
-
} catch (err) {
|
|
333
|
-
logVerbose(`[infoflow] thinking indicator exception: ${formatInfoflowError(err)}`);
|
|
334
|
-
return undefined;
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
/**
|
|
339
|
-
* Recalls a previously sent thinking indicator (group or private).
|
|
340
|
-
* Silently swallows errors to avoid disrupting the reply flow.
|
|
341
|
-
*/
|
|
342
|
-
async function recallThinkingIndicator(params: {
|
|
343
|
-
cfg: OpenClawConfig;
|
|
344
|
-
accountId: string;
|
|
345
|
-
handle: ThinkingIndicatorHandle;
|
|
346
|
-
groupId?: number;
|
|
347
|
-
isPrivate?: boolean;
|
|
348
|
-
}): Promise<void> {
|
|
349
|
-
const { cfg, accountId, handle, groupId, isPrivate } = params;
|
|
350
|
-
try {
|
|
351
|
-
const account = resolveInfoflowAccount({ cfg, accountId });
|
|
352
|
-
if (isPrivate) {
|
|
353
|
-
const appAgentId = account.config.appAgentId;
|
|
354
|
-
if (!appAgentId) {
|
|
355
|
-
logVerbose(
|
|
356
|
-
`[infoflow] thinking indicator private recall skipped: appAgentId not configured`,
|
|
357
|
-
);
|
|
358
|
-
return;
|
|
359
|
-
}
|
|
360
|
-
const result = await recallInfoflowPrivateMessage({
|
|
361
|
-
account,
|
|
362
|
-
msgkey: handle.messageid,
|
|
363
|
-
appAgentId,
|
|
364
|
-
});
|
|
365
|
-
if (result.ok) {
|
|
366
|
-
logVerbose(`[infoflow] thinking indicator recalled (private)`);
|
|
367
|
-
} else {
|
|
368
|
-
logVerbose(`[infoflow] thinking indicator private recall failed: ${result.error}`);
|
|
369
|
-
}
|
|
370
|
-
} else if (groupId !== undefined) {
|
|
371
|
-
const result = await recallInfoflowGroupMessage({
|
|
372
|
-
account,
|
|
373
|
-
groupId,
|
|
374
|
-
messageid: handle.messageid,
|
|
375
|
-
msgseqid: handle.msgseqid,
|
|
376
|
-
});
|
|
377
|
-
if (result.ok) {
|
|
378
|
-
logVerbose(`[infoflow] thinking indicator recalled: groupId=${groupId}`);
|
|
379
|
-
} else {
|
|
380
|
-
logVerbose(`[infoflow] thinking indicator recall failed: ${result.error}`);
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
} catch (err) {
|
|
384
|
-
logVerbose(`[infoflow] thinking indicator recall exception: ${formatInfoflowError(err)}`);
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
|
|
388
284
|
/**
|
|
389
285
|
* Handles an incoming private chat message from Infoflow.
|
|
390
286
|
* Receives the raw decrypted message data and dispatches to the agent.
|
|
@@ -886,21 +782,6 @@ export async function handleInfoflowMessage(params: HandleInfoflowMessageParams)
|
|
|
886
782
|
// Build unified target: "group:<id>" for group chat, username for private chat
|
|
887
783
|
const to = isGroup && groupId !== undefined ? `group:${groupId}` : fromuser;
|
|
888
784
|
|
|
889
|
-
// --- Thinking indicator ("收到🤔...") ---
|
|
890
|
-
const thinkingEnabled = groupCfg?.thinkingIndicator ?? account.config.thinkingIndicator ?? true;
|
|
891
|
-
let thinkingHandle: ThinkingIndicatorHandle | undefined;
|
|
892
|
-
if (thinkingEnabled) {
|
|
893
|
-
thinkingHandle = await sendThinkingIndicator({
|
|
894
|
-
cfg,
|
|
895
|
-
to,
|
|
896
|
-
accountId: account.accountId,
|
|
897
|
-
replyTo:
|
|
898
|
-
isGroup && event.messageId
|
|
899
|
-
? { messageid: event.messageId, preview: mes.slice(0, 100) }
|
|
900
|
-
: undefined,
|
|
901
|
-
});
|
|
902
|
-
}
|
|
903
|
-
|
|
904
785
|
// Provide mention context to the LLM so it can decide who to @mention
|
|
905
786
|
if (isGroup && event.mentionIds) {
|
|
906
787
|
const parts: string[] = [];
|
|
@@ -930,48 +811,12 @@ export async function handleInfoflowMessage(params: HandleInfoflowMessageParams)
|
|
|
930
811
|
replyToPreview: isGroup ? mes : undefined,
|
|
931
812
|
});
|
|
932
813
|
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
await recallThinkingIndicator({
|
|
940
|
-
cfg,
|
|
941
|
-
accountId: account.accountId,
|
|
942
|
-
handle: thinkingHandle!,
|
|
943
|
-
groupId: isGroup ? groupId : undefined,
|
|
944
|
-
isPrivate: !isGroup,
|
|
945
|
-
});
|
|
946
|
-
};
|
|
947
|
-
|
|
948
|
-
const originalDeliver = dispatcherOptions.deliver;
|
|
949
|
-
const wrappedDispatcherOptions = {
|
|
950
|
-
...dispatcherOptions,
|
|
951
|
-
deliver: async (payload: ReplyPayload) => {
|
|
952
|
-
await doRecallThinking();
|
|
953
|
-
return originalDeliver(payload);
|
|
954
|
-
},
|
|
955
|
-
onCleanup: () => {
|
|
956
|
-
void doRecallThinking();
|
|
957
|
-
},
|
|
958
|
-
};
|
|
959
|
-
|
|
960
|
-
// Wrap dispatch in try/finally to guarantee the thinking indicator bound to
|
|
961
|
-
// this message is always recalled — even when queue policy drops/enqueues the
|
|
962
|
-
// message before typing activates (typing.cleanup skips onCleanup when inactive).
|
|
963
|
-
// doRecallThinking is idempotent (thinkingRecalled flag), so duplicate calls are no-ops.
|
|
964
|
-
let dispatchResult;
|
|
965
|
-
try {
|
|
966
|
-
dispatchResult = await core.channel.reply.dispatchReplyWithBufferedBlockDispatcher({
|
|
967
|
-
ctx: ctxPayload,
|
|
968
|
-
cfg,
|
|
969
|
-
dispatcherOptions: wrappedDispatcherOptions,
|
|
970
|
-
replyOptions,
|
|
971
|
-
});
|
|
972
|
-
} finally {
|
|
973
|
-
await doRecallThinking();
|
|
974
|
-
}
|
|
814
|
+
const dispatchResult = await core.channel.reply.dispatchReplyWithBufferedBlockDispatcher({
|
|
815
|
+
ctx: ctxPayload,
|
|
816
|
+
cfg,
|
|
817
|
+
dispatcherOptions,
|
|
818
|
+
replyOptions,
|
|
819
|
+
});
|
|
975
820
|
|
|
976
821
|
const didReply = dispatchResult?.queuedFinal ?? false;
|
|
977
822
|
|
package/src/channel.ts
CHANGED
|
@@ -52,6 +52,7 @@ export const infoflowPlugin: ChannelPlugin<ResolvedInfoflowAccount> = {
|
|
|
52
52
|
agentPrompt: {
|
|
53
53
|
messageToolHints: () => [
|
|
54
54
|
'Infoflow group @mentions: set atAll=true to @all members, or mentionUserIds="user1,user2" (comma-separated uuapName) to @mention specific users. Only effective for group targets (group:<id>).',
|
|
55
|
+
'Infoflow supports message recall (撤回): use action="delete" to recall the most recent message, or specify messageId to recall a specific message. Works for both private and group messages.',
|
|
55
56
|
],
|
|
56
57
|
},
|
|
57
58
|
config: {
|
|
@@ -61,9 +61,9 @@ function isDuplicateMessage(msgData: Record<string, unknown>): boolean {
|
|
|
61
61
|
* Called after successfully sending a message to prevent
|
|
62
62
|
* the bot from processing its own outbound messages as inbound.
|
|
63
63
|
*/
|
|
64
|
-
export function recordSentMessageId(messageId: string |
|
|
64
|
+
export function recordSentMessageId(messageId: string | null): void {
|
|
65
65
|
if (messageId == null) return;
|
|
66
|
-
messageCache.check(
|
|
66
|
+
messageCache.check(messageId);
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
// ---------------------------------------------------------------------------
|
package/src/media.ts
CHANGED
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
INFOFLOW_PRIVATE_SEND_PATH,
|
|
16
16
|
INFOFLOW_GROUP_SEND_PATH,
|
|
17
17
|
} from "./send.js";
|
|
18
|
-
import { recordSentMessage } from "./sent-message-store.js";
|
|
18
|
+
import { recordSentMessage, buildAgentFrom } from "./sent-message-store.js";
|
|
19
19
|
import type { ResolvedInfoflowAccount, InfoflowOutboundReply } from "./types.js";
|
|
20
20
|
|
|
21
21
|
/** Infoflow API image size limit: 1MB raw bytes */
|
|
@@ -225,6 +225,7 @@ export async function sendInfoflowGroupImage(params: {
|
|
|
225
225
|
try {
|
|
226
226
|
recordSentMessage(account.accountId, {
|
|
227
227
|
target: `group:${groupId}`,
|
|
228
|
+
from: buildAgentFrom(account.config.appAgentId),
|
|
228
229
|
messageid,
|
|
229
230
|
msgseqid: msgseqid ?? "",
|
|
230
231
|
digest: "image",
|
|
@@ -313,6 +314,7 @@ export async function sendInfoflowPrivateImage(params: {
|
|
|
313
314
|
try {
|
|
314
315
|
recordSentMessage(account.accountId, {
|
|
315
316
|
target: toUser,
|
|
317
|
+
from: buildAgentFrom(account.config.appAgentId),
|
|
316
318
|
messageid: msgkey,
|
|
317
319
|
msgseqid: "",
|
|
318
320
|
digest: "image",
|
package/src/send.ts
CHANGED
|
@@ -8,7 +8,7 @@ import type { OpenClawConfig } from "openclaw/plugin-sdk";
|
|
|
8
8
|
import { resolveInfoflowAccount } from "./accounts.js";
|
|
9
9
|
import { recordSentMessageId } from "./infoflow-req-parse.js";
|
|
10
10
|
import { getInfoflowSendLog, formatInfoflowError, logVerbose } from "./logging.js";
|
|
11
|
-
import { recordSentMessage, buildMessageDigest } from "./sent-message-store.js";
|
|
11
|
+
import { recordSentMessage, buildMessageDigest, buildAgentFrom } from "./sent-message-store.js";
|
|
12
12
|
import type {
|
|
13
13
|
InfoflowGroupMessageBodyItem,
|
|
14
14
|
InfoflowMessageContentItem,
|
|
@@ -375,6 +375,7 @@ export async function sendInfoflowPrivateMessage(params: {
|
|
|
375
375
|
try {
|
|
376
376
|
recordSentMessage(account.accountId, {
|
|
377
377
|
target: toUser,
|
|
378
|
+
from: buildAgentFrom(account.config.appAgentId),
|
|
378
379
|
messageid: msgkey,
|
|
379
380
|
msgseqid: "",
|
|
380
381
|
digest: buildMessageDigest(contents),
|
|
@@ -576,18 +577,18 @@ export async function sendInfoflowGroupMessage(params: {
|
|
|
576
577
|
result: { messageid?: string; msgseqid?: string },
|
|
577
578
|
digestContents: InfoflowMessageContentItem[],
|
|
578
579
|
) => {
|
|
579
|
-
if (result.messageid)
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
|
|
580
|
+
if (!result.messageid) return;
|
|
581
|
+
try {
|
|
582
|
+
recordSentMessage(account.accountId, {
|
|
583
|
+
target: `group:${groupId}`,
|
|
584
|
+
from: buildAgentFrom(account.config.appAgentId),
|
|
585
|
+
messageid: result.messageid,
|
|
586
|
+
msgseqid: result.msgseqid ?? "",
|
|
587
|
+
digest: buildMessageDigest(digestContents),
|
|
588
|
+
sentAt: Date.now(),
|
|
589
|
+
});
|
|
590
|
+
} catch {
|
|
591
|
+
// Do not block sending
|
|
591
592
|
}
|
|
592
593
|
};
|
|
593
594
|
|
|
@@ -774,7 +775,7 @@ export async function recallInfoflowPrivateMessage(params: {
|
|
|
774
775
|
|
|
775
776
|
const bodyStr = JSON.stringify({ msgkey, agentid: appAgentId });
|
|
776
777
|
|
|
777
|
-
logVerbose(`[infoflow:recallPrivate] POST body: ${bodyStr}`);
|
|
778
|
+
logVerbose(`[infoflow:recallPrivate] POST auth: ${tokenResult.token} body: ${bodyStr}`);
|
|
778
779
|
|
|
779
780
|
const res = await fetch(`${ensureHttps(apiHost)}${INFOFLOW_PRIVATE_RECALL_PATH}`, {
|
|
780
781
|
method: "POST",
|
|
@@ -51,6 +51,7 @@ function getDb(): DatabaseSync {
|
|
|
51
51
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
52
52
|
account_id TEXT NOT NULL,
|
|
53
53
|
target TEXT NOT NULL,
|
|
54
|
+
from_id TEXT NOT NULL DEFAULT '',
|
|
54
55
|
messageid TEXT NOT NULL,
|
|
55
56
|
msgseqid TEXT NOT NULL DEFAULT '',
|
|
56
57
|
digest TEXT NOT NULL DEFAULT '',
|
|
@@ -62,6 +63,13 @@ function getDb(): DatabaseSync {
|
|
|
62
63
|
ON sent_messages(account_id, target, sent_at DESC);
|
|
63
64
|
`);
|
|
64
65
|
|
|
66
|
+
// Migration: add from_id column to existing databases
|
|
67
|
+
try {
|
|
68
|
+
db.exec(`ALTER TABLE sent_messages ADD COLUMN from_id TEXT NOT NULL DEFAULT ''`);
|
|
69
|
+
} catch {
|
|
70
|
+
// Column already exists — ignore
|
|
71
|
+
}
|
|
72
|
+
|
|
65
73
|
return db;
|
|
66
74
|
}
|
|
67
75
|
|
|
@@ -71,6 +79,7 @@ function getDb(): DatabaseSync {
|
|
|
71
79
|
|
|
72
80
|
export type SentMessageRecord = {
|
|
73
81
|
target: string;
|
|
82
|
+
from: string;
|
|
74
83
|
messageid: string;
|
|
75
84
|
msgseqid: string;
|
|
76
85
|
digest: string;
|
|
@@ -85,11 +94,12 @@ export function recordSentMessage(accountId: string, record: SentMessageRecord):
|
|
|
85
94
|
try {
|
|
86
95
|
const d = getDb();
|
|
87
96
|
d.prepare(
|
|
88
|
-
`INSERT INTO sent_messages (account_id, target, messageid, msgseqid, digest, sent_at)
|
|
89
|
-
VALUES (?, ?, ?, ?, ?, ?)`,
|
|
97
|
+
`INSERT INTO sent_messages (account_id, target, from_id, messageid, msgseqid, digest, sent_at)
|
|
98
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)`,
|
|
90
99
|
).run(
|
|
91
100
|
accountId,
|
|
92
101
|
record.target,
|
|
102
|
+
record.from,
|
|
93
103
|
record.messageid,
|
|
94
104
|
record.msgseqid,
|
|
95
105
|
record.digest,
|
|
@@ -117,7 +127,7 @@ export function querySentMessages(
|
|
|
117
127
|
const d = getDb();
|
|
118
128
|
const rows = d
|
|
119
129
|
.prepare(
|
|
120
|
-
`SELECT target, messageid, msgseqid, digest, sent_at
|
|
130
|
+
`SELECT target, from_id, messageid, msgseqid, digest, sent_at
|
|
121
131
|
FROM sent_messages
|
|
122
132
|
WHERE account_id = ? AND target = ?
|
|
123
133
|
ORDER BY sent_at DESC
|
|
@@ -125,6 +135,7 @@ export function querySentMessages(
|
|
|
125
135
|
)
|
|
126
136
|
.all(accountId, params.target, params.count) as Array<{
|
|
127
137
|
target: string;
|
|
138
|
+
from_id: string;
|
|
128
139
|
messageid: string;
|
|
129
140
|
msgseqid: string;
|
|
130
141
|
digest: string;
|
|
@@ -133,6 +144,7 @@ export function querySentMessages(
|
|
|
133
144
|
|
|
134
145
|
return rows.map((r) => ({
|
|
135
146
|
target: r.target,
|
|
147
|
+
from: r.from_id,
|
|
136
148
|
messageid: r.messageid,
|
|
137
149
|
msgseqid: r.msgseqid,
|
|
138
150
|
digest: r.digest,
|
|
@@ -150,18 +162,26 @@ export function findSentMessage(
|
|
|
150
162
|
const d = getDb();
|
|
151
163
|
const row = d
|
|
152
164
|
.prepare(
|
|
153
|
-
`SELECT target, messageid, msgseqid, digest, sent_at
|
|
165
|
+
`SELECT target, from_id, messageid, msgseqid, digest, sent_at
|
|
154
166
|
FROM sent_messages
|
|
155
167
|
WHERE account_id = ? AND messageid = ?
|
|
156
168
|
LIMIT 1`,
|
|
157
169
|
)
|
|
158
170
|
.get(accountId, messageid) as
|
|
159
|
-
| {
|
|
171
|
+
| {
|
|
172
|
+
target: string;
|
|
173
|
+
from_id: string;
|
|
174
|
+
messageid: string;
|
|
175
|
+
msgseqid: string;
|
|
176
|
+
digest: string;
|
|
177
|
+
sent_at: number;
|
|
178
|
+
}
|
|
160
179
|
| undefined;
|
|
161
180
|
|
|
162
181
|
if (!row) return undefined;
|
|
163
182
|
return {
|
|
164
183
|
target: row.target,
|
|
184
|
+
from: row.from_id,
|
|
165
185
|
messageid: row.messageid,
|
|
166
186
|
msgseqid: row.msgseqid,
|
|
167
187
|
digest: row.digest,
|
|
@@ -181,6 +201,15 @@ export function removeRecalledMessages(accountId: string, messageids: string[]):
|
|
|
181
201
|
).run(accountId, ...messageids);
|
|
182
202
|
}
|
|
183
203
|
|
|
204
|
+
// ---------------------------------------------------------------------------
|
|
205
|
+
// From-ID builder
|
|
206
|
+
// ---------------------------------------------------------------------------
|
|
207
|
+
|
|
208
|
+
/** Builds a `from` identifier for self-sent (agent) messages. */
|
|
209
|
+
export function buildAgentFrom(appAgentId: number | undefined): string {
|
|
210
|
+
return appAgentId != null ? `agent:${appAgentId}` : "agent:unknown";
|
|
211
|
+
}
|
|
212
|
+
|
|
184
213
|
// ---------------------------------------------------------------------------
|
|
185
214
|
// Digest builder
|
|
186
215
|
// ---------------------------------------------------------------------------
|
package/src/types.ts
CHANGED
|
@@ -25,8 +25,6 @@ export type InfoflowGroupConfig = {
|
|
|
25
25
|
followUp?: boolean;
|
|
26
26
|
followUpWindow?: number;
|
|
27
27
|
systemPrompt?: string;
|
|
28
|
-
/** Enable thinking indicator ("收到🤔...") before processing (default: true) */
|
|
29
|
-
thinkingIndicator?: boolean;
|
|
30
28
|
};
|
|
31
29
|
|
|
32
30
|
// ---------------------------------------------------------------------------
|
|
@@ -120,8 +118,6 @@ export type InfoflowAccountConfig = {
|
|
|
120
118
|
followUp?: boolean;
|
|
121
119
|
/** Follow-up window in seconds after last bot reply (default: 300) */
|
|
122
120
|
followUpWindow?: number;
|
|
123
|
-
/** Enable thinking indicator ("收到🤔...") before processing (default: true) */
|
|
124
|
-
thinkingIndicator?: boolean;
|
|
125
121
|
/** 如流企业后台的应用ID(私聊消息撤回依赖此字段) */
|
|
126
122
|
appAgentId?: number;
|
|
127
123
|
/** Per-group configuration overrides, keyed by group ID */
|
|
@@ -159,8 +155,6 @@ export type ResolvedInfoflowAccount = {
|
|
|
159
155
|
followUp?: boolean;
|
|
160
156
|
/** Follow-up window in seconds after last bot reply (default: 300) */
|
|
161
157
|
followUpWindow?: number;
|
|
162
|
-
/** Enable thinking indicator ("收到🤔...") before processing (default: true) */
|
|
163
|
-
thinkingIndicator?: boolean;
|
|
164
158
|
/** 如流企业后台的应用ID(私聊消息撤回依赖此字段) */
|
|
165
159
|
appAgentId?: number;
|
|
166
160
|
/** Per-group configuration overrides, keyed by group ID */
|