@qihoo/tuitui-openclaw-channel 1.0.6 → 1.0.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/channel.ts +82 -116
- package/src/utils.ts +11 -10
package/package.json
CHANGED
package/src/channel.ts
CHANGED
|
@@ -48,7 +48,58 @@ const isConfigured = (account: any)=> Boolean(
|
|
|
48
48
|
);
|
|
49
49
|
|
|
50
50
|
const isToGroup = (chatId: string) => /^\d+$/.test(chatId);
|
|
51
|
-
|
|
51
|
+
const arrLowerCaseTrim = (arr: any[]) => arr.filter((v: any) => !!v).map((v: any) => String(v).toLowerCase().trim())
|
|
52
|
+
const configSchema = buildChannelConfigSchema(
|
|
53
|
+
z
|
|
54
|
+
.object({
|
|
55
|
+
enabled: z.boolean().optional().describe('开启或关闭'),
|
|
56
|
+
appId: z.string().min(1).describe('推推机器人身份 AppId(你可以推推搜索【推推机器人助手】,和它聊天自助申请推推机器人)'),
|
|
57
|
+
appSecret: z.string().min(1).describe('推推机器人密钥 Secret'),
|
|
58
|
+
// 私聊策略(默认 pairing)
|
|
59
|
+
dmPolicy: z
|
|
60
|
+
.enum(['pairing', 'allowlist', 'open', 'disabled'])
|
|
61
|
+
.optional()
|
|
62
|
+
.default('pairing')
|
|
63
|
+
.describe('私聊策略:pairing=配对(默认);allowlist=白名单;open=允许所有(不安全);disabled=禁用私聊',),
|
|
64
|
+
// 私聊允许列表(当 dmPolicy=allowlist 生效;pairing 下也可显式允许)
|
|
65
|
+
allowFrom: z
|
|
66
|
+
.array(z.string())
|
|
67
|
+
.optional()
|
|
68
|
+
.describe('私聊白名单(dmPolicy=allowlist 时生效;pairing 下可用于显式放行用户)'),
|
|
69
|
+
|
|
70
|
+
// 群组策略
|
|
71
|
+
groupPolicy: z
|
|
72
|
+
.enum(['allowlist', 'disabled'])
|
|
73
|
+
.default('allowlist')
|
|
74
|
+
.describe('群聊策略:allowlist=白名单;disabled=禁用群聊',),
|
|
75
|
+
// 仅在 allowlist 生效的群组 ID 列表
|
|
76
|
+
groupAllowFrom: z
|
|
77
|
+
.array(z.string())
|
|
78
|
+
.optional()
|
|
79
|
+
.describe('群组白名单(仅在 groupPolicy=allowlist 生效)'),
|
|
80
|
+
// 每个群组的覆盖配置
|
|
81
|
+
/*
|
|
82
|
+
groups: z
|
|
83
|
+
.record(
|
|
84
|
+
z.string(),
|
|
85
|
+
z
|
|
86
|
+
.object({
|
|
87
|
+
requireMention: z
|
|
88
|
+
.boolean()
|
|
89
|
+
.optional()
|
|
90
|
+
.describe('该群组是否需要 @ 机器人才触发 Agent(默认 true)'),
|
|
91
|
+
shouldReply: z
|
|
92
|
+
.boolean()
|
|
93
|
+
.optional()
|
|
94
|
+
.describe('该群组是否允许 Agent 回复(默认 true)'),
|
|
95
|
+
})
|
|
96
|
+
.passthrough(),
|
|
97
|
+
)
|
|
98
|
+
.optional()
|
|
99
|
+
.describe('群组级覆盖配置'),
|
|
100
|
+
*/
|
|
101
|
+
}) as any,
|
|
102
|
+
);
|
|
52
103
|
export function createTuiTuiChannelPlugin(apiRuntime: any) {
|
|
53
104
|
return {
|
|
54
105
|
id: CHANNEL_ID,
|
|
@@ -77,57 +128,7 @@ export function createTuiTuiChannelPlugin(apiRuntime: any) {
|
|
|
77
128
|
|
|
78
129
|
reload: { configPrefixes: [`channels.${CHANNEL_ID}`] },
|
|
79
130
|
|
|
80
|
-
configSchema
|
|
81
|
-
z
|
|
82
|
-
.object({
|
|
83
|
-
enabled: z.boolean().optional().describe('开启或关闭'),
|
|
84
|
-
appId: z.string().min(1).describe('推推机器人身份 AppId(你可以推推搜索【推推机器人助手】,和它聊天自助申请推推机器人)'),
|
|
85
|
-
appSecret: z.string().min(1).describe('推推机器人密钥 Secret'),
|
|
86
|
-
// 私聊策略(默认 pairing)
|
|
87
|
-
dmPolicy: z
|
|
88
|
-
.enum(['pairing', 'allowlist', 'open', 'disabled'])
|
|
89
|
-
.optional()
|
|
90
|
-
.default('pairing')
|
|
91
|
-
.describe('私聊策略:pairing=配对(默认);allowlist=白名单;open=允许所有(不安全);disabled=禁用私聊',),
|
|
92
|
-
// 私聊允许列表(当 dmPolicy=allowlist 生效;pairing 下也可显式允许)
|
|
93
|
-
allowFrom: z
|
|
94
|
-
.array(z.string())
|
|
95
|
-
.optional()
|
|
96
|
-
.describe('私聊白名单(dmPolicy=allowlist 时生效;pairing 下可用于显式放行用户)'),
|
|
97
|
-
|
|
98
|
-
// 群组策略
|
|
99
|
-
groupPolicy: z
|
|
100
|
-
.enum(['allowlist', 'disabled'])
|
|
101
|
-
.default('allowlist')
|
|
102
|
-
.describe('群聊策略:allowlist=白名单;disabled=禁用群聊',),
|
|
103
|
-
// 仅在 allowlist 生效的群组 ID 列表
|
|
104
|
-
groupAllowFrom: z
|
|
105
|
-
.array(z.string())
|
|
106
|
-
.optional()
|
|
107
|
-
.describe('群组白名单(仅在 groupPolicy=allowlist 生效)'),
|
|
108
|
-
// 每个群组的覆盖配置
|
|
109
|
-
/*
|
|
110
|
-
groups: z
|
|
111
|
-
.record(
|
|
112
|
-
z.string(),
|
|
113
|
-
z
|
|
114
|
-
.object({
|
|
115
|
-
requireMention: z
|
|
116
|
-
.boolean()
|
|
117
|
-
.optional()
|
|
118
|
-
.describe('该群组是否需要 @ 机器人才触发 Agent(默认 true)'),
|
|
119
|
-
shouldReply: z
|
|
120
|
-
.boolean()
|
|
121
|
-
.optional()
|
|
122
|
-
.describe('该群组是否允许 Agent 回复(默认 true)'),
|
|
123
|
-
})
|
|
124
|
-
.passthrough(),
|
|
125
|
-
)
|
|
126
|
-
.optional()
|
|
127
|
-
.describe('群组级覆盖配置'),
|
|
128
|
-
*/
|
|
129
|
-
}) as any,
|
|
130
|
-
),
|
|
131
|
+
configSchema,
|
|
131
132
|
|
|
132
133
|
config: {
|
|
133
134
|
listAccountIds: (cfg: any) => {
|
|
@@ -273,7 +274,7 @@ export function createTuiTuiChannelPlugin(apiRuntime: any) {
|
|
|
273
274
|
return { channel: CHANNEL_ID, messageId: `tuitui-text-${Date.now()}`, chatId };
|
|
274
275
|
},
|
|
275
276
|
|
|
276
|
-
sendCustom: async ({ cfg, to, payload, accountId, account, chatType, groupId
|
|
277
|
+
sendCustom: async ({ cfg, to, payload, accountId, account, chatType, groupId }: any) => {
|
|
277
278
|
account = account || resolveAccount(cfg, accountId);
|
|
278
279
|
checkAccount(account, 'send custom message');
|
|
279
280
|
|
|
@@ -292,13 +293,13 @@ export function createTuiTuiChannelPlugin(apiRuntime: any) {
|
|
|
292
293
|
return { channel: CHANNEL_ID, messageId: `tuitui-page-${Date.now()}`, chatId };
|
|
293
294
|
},
|
|
294
295
|
|
|
295
|
-
sendMedia: async ({ cfg, to, mediaUrl, accountId, account
|
|
296
|
+
sendMedia: async ({ cfg, to, payload, mediaUrl, accountId, account }: any) => {
|
|
296
297
|
account = account || resolveAccount(cfg, accountId);
|
|
297
298
|
checkAccount(account, 'send media');
|
|
298
299
|
|
|
299
300
|
const chatId = String(to || '').trim();
|
|
300
301
|
// Determine if this is a group message based on 'to' being all digits (group) or not (direct)
|
|
301
|
-
await sendMediaMsg(account, chatId, isToGroup(chatId), mediaUrl);
|
|
302
|
+
await sendMediaMsg(account, chatId, isToGroup(chatId), mediaUrl, 'tuitui.send.media');
|
|
302
303
|
|
|
303
304
|
return { channel: CHANNEL_ID, messageId: `tuitui-media-${Date.now()}`, chatId };
|
|
304
305
|
},
|
|
@@ -386,8 +387,8 @@ export function createTuiTuiChannelPlugin(apiRuntime: any) {
|
|
|
386
387
|
const msg = json.body as TuiTuiInboundMessage;
|
|
387
388
|
const msgData = msg.data;
|
|
388
389
|
let userAccount: string | undefined = msg.user_account;
|
|
389
|
-
let
|
|
390
|
-
let
|
|
390
|
+
let msgUid: string | undefined = msg.uid;
|
|
391
|
+
let msgUname: string | undefined = msg.user_name;
|
|
391
392
|
let chatType: 'direct' | 'group';
|
|
392
393
|
const chatTypeIsDirect = wsEvent === 'single_chat';
|
|
393
394
|
const chatTypeIsGroup = wsEvent === 'group_chat';
|
|
@@ -404,9 +405,7 @@ export function createTuiTuiChannelPlugin(apiRuntime: any) {
|
|
|
404
405
|
chatType = 'direct';
|
|
405
406
|
text = buildMessageBody(msgData);
|
|
406
407
|
|
|
407
|
-
log?.debug?.(
|
|
408
|
-
`[${CHANNEL_ID}] inbound single_chat user_account=${String(userAccount)} uid=${String(userUid)} user_name=${String(msg.user_name)}`,
|
|
409
|
-
);
|
|
408
|
+
log?.debug?.(`[${CHANNEL_ID}] inbound single_chat user_account=${userAccount} uid=${msgUid} user_name=${msgUname}`);
|
|
410
409
|
|
|
411
410
|
const msgType = msgData.msg_type;
|
|
412
411
|
// Extract media URLs for image/voice/file messages
|
|
@@ -423,7 +422,7 @@ export function createTuiTuiChannelPlugin(apiRuntime: any) {
|
|
|
423
422
|
replyToId = msgData.ref.msgid;
|
|
424
423
|
}
|
|
425
424
|
|
|
426
|
-
if (!userAccount && !
|
|
425
|
+
if (!userAccount && !msgUid) {
|
|
427
426
|
log?.info?.(`[${CHANNEL_ID}] Missing user_account or uid in single_chat event`);
|
|
428
427
|
return;
|
|
429
428
|
}
|
|
@@ -433,27 +432,16 @@ export function createTuiTuiChannelPlugin(apiRuntime: any) {
|
|
|
433
432
|
groupId = msgData.group_id;
|
|
434
433
|
groupName = msgData.group_name;
|
|
435
434
|
|
|
436
|
-
log?.debug?.(
|
|
437
|
-
`[${CHANNEL_ID}] inbound group_chat user_account=${String(userAccount)} uid=${String(userUid)} user_name=${String(msg.user_name)} group_id=${String(groupId)}`,
|
|
438
|
-
);
|
|
435
|
+
log?.debug?.(`[${CHANNEL_ID}] inbound group_chat user_account=${userAccount} uid=${msgUid} user_name=${msgUname} group_id=${groupId}`);
|
|
439
436
|
|
|
440
437
|
// Group policy gating and @mention requirements
|
|
441
438
|
const groupPolicy = String(account.groupPolicy ?? "allowlist").toLowerCase();
|
|
442
439
|
const groupAllowFromRaw = Array.isArray(account.groupAllowFrom) ? account.groupAllowFrom : [];
|
|
443
|
-
const normalizedGroupAllowFrom = groupAllowFromRaw
|
|
444
|
-
|
|
445
|
-
.map((v: unknown) => String(v).trim())
|
|
446
|
-
.filter(Boolean);
|
|
447
|
-
log?.debug?.(
|
|
448
|
-
`[${CHANNEL_ID}] groupPolicy=${groupPolicy} groupId=${String(groupId)} groupAllowFrom=${JSON.stringify(normalizedGroupAllowFrom)} at_me=${JSON.stringify(msgData.at_me)} at=${JSON.stringify(msgData.at)}`,
|
|
449
|
-
);
|
|
450
|
-
|
|
451
|
-
if (groupPolicy === 'disabled') {
|
|
452
|
-
log?.info?.('Groups disabled');
|
|
453
|
-
return;
|
|
454
|
-
}
|
|
455
|
-
|
|
440
|
+
const normalizedGroupAllowFrom = arrLowerCaseTrim(groupAllowFromRaw);
|
|
441
|
+
log?.debug?.(`[${CHANNEL_ID}] groupPolicy=${groupPolicy} groupId=${groupId} groupAllowFrom=${JSON.stringify(normalizedGroupAllowFrom)} at_me=${JSON.stringify(msgData.at_me)} at=${JSON.stringify(msgData.at)}`);
|
|
456
442
|
|
|
443
|
+
if (groupPolicy === 'disabled') return log?.info?.('Groups disabled');
|
|
444
|
+
|
|
457
445
|
// 群消息处理策略
|
|
458
446
|
const groupCfg = account.groups?.[String(groupId)];
|
|
459
447
|
|
|
@@ -515,14 +503,10 @@ export function createTuiTuiChannelPlugin(apiRuntime: any) {
|
|
|
515
503
|
// DM access gating (pairing/allowlist/open/disabled)
|
|
516
504
|
const dmPolicy = String(account.dmPolicy ?? 'pairing').toLowerCase();
|
|
517
505
|
const configuredAllowFrom = Array.isArray(account.allowFrom) ? account.allowFrom : [];
|
|
518
|
-
const normalizedAllowFrom = configuredAllowFrom
|
|
519
|
-
.filter((v: unknown) => !!v)
|
|
520
|
-
.map((v: unknown) => String(v).toLowerCase().trim());
|
|
506
|
+
const normalizedAllowFrom = arrLowerCaseTrim(configuredAllowFrom);
|
|
521
507
|
// 只使用 userAccount 作为匹配依据,因为用户希望 allowFrom 匹配 user_account
|
|
522
508
|
const senderForPolicy = userAccount ? String(userAccount).toLowerCase().trim() : '';
|
|
523
|
-
log?.debug?.(
|
|
524
|
-
`[${CHANNEL_ID}] dmPolicy=${dmPolicy} userAccount=${String(userAccount)} userUid=${String(userUid)} senderForPolicy=${senderForPolicy} allowFrom=${JSON.stringify(normalizedAllowFrom)}`,
|
|
525
|
-
);
|
|
509
|
+
log?.debug?.(`[${CHANNEL_ID}] dmPolicy=${dmPolicy} userAccount=${userAccount} msgUid=${msgUid} senderForPolicy=${senderForPolicy} allowFrom=${JSON.stringify(normalizedAllowFrom)}`);
|
|
526
510
|
|
|
527
511
|
if (chatTypeIsDirect) {
|
|
528
512
|
if (dmPolicy === 'disabled') {
|
|
@@ -533,20 +517,14 @@ export function createTuiTuiChannelPlugin(apiRuntime: any) {
|
|
|
533
517
|
if (dmPolicy !== 'open') {
|
|
534
518
|
// Merge pairing-store entries unless policy is allowlist-only
|
|
535
519
|
let storeAllowFrom: string[] = [];
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
const
|
|
520
|
+
if (dmPolicy !== 'allowlist') {
|
|
521
|
+
try {
|
|
522
|
+
const res = await apiRuntime?.channel?.pairing?.readAllowFromStore?.({
|
|
539
523
|
channel: CHANNEL_ID,
|
|
540
524
|
accountId: account.accountId,
|
|
541
525
|
});
|
|
542
|
-
if (Array.isArray(
|
|
543
|
-
|
|
544
|
-
.filter((v: unknown) => !!v)
|
|
545
|
-
.map((v: unknown) => String(v).toLowerCase().trim());
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
} catch {
|
|
549
|
-
storeAllowFrom = [];
|
|
526
|
+
if (Array.isArray(res)) storeAllowFrom = arrLowerCaseTrim(res);
|
|
527
|
+
} catch {}
|
|
550
528
|
}
|
|
551
529
|
|
|
552
530
|
// 只检查 userAccount 是否在 allowFrom 或 storeAllowFrom 中
|
|
@@ -556,9 +534,7 @@ export function createTuiTuiChannelPlugin(apiRuntime: any) {
|
|
|
556
534
|
if (!isAllowed) {
|
|
557
535
|
if (dmPolicy === 'pairing') {
|
|
558
536
|
try {
|
|
559
|
-
log?.debug?.(
|
|
560
|
-
`[${CHANNEL_ID}] pairing flow: checking if pairing request exists for sender=${senderForPolicy}`,
|
|
561
|
-
);
|
|
537
|
+
log?.debug?.(`[${CHANNEL_ID}] pairing flow: checking if pairing request exists for sender=${senderForPolicy}`);
|
|
562
538
|
const req = await apiRuntime?.channel?.pairing?.upsertPairingRequest?.({
|
|
563
539
|
channel: CHANNEL_ID,
|
|
564
540
|
accountId: account.accountId,
|
|
@@ -591,9 +567,7 @@ export function createTuiTuiChannelPlugin(apiRuntime: any) {
|
|
|
591
567
|
}
|
|
592
568
|
|
|
593
569
|
// dmPolicy=allowlist and sender not allowed
|
|
594
|
-
log?.warn?.(
|
|
595
|
-
`[${CHANNEL_ID}] Blocked unauthorized sender (allowlist): sender=${senderForPolicy} allowFrom=${JSON.stringify(normalizedAllowFrom)}`,
|
|
596
|
-
);
|
|
570
|
+
log?.warn?.(`[${CHANNEL_ID}] Blocked unauthorized sender (allowlist): sender=${senderForPolicy} allowFrom=${JSON.stringify(normalizedAllowFrom)}`);
|
|
597
571
|
return;
|
|
598
572
|
}
|
|
599
573
|
}
|
|
@@ -603,22 +577,13 @@ export function createTuiTuiChannelPlugin(apiRuntime: any) {
|
|
|
603
577
|
await tuituiEmojiReaction(account, chatTypeIsGroup ? groupId : userAccount, chatTypeIsGroup, msgData.msgid, '收到');
|
|
604
578
|
|
|
605
579
|
// Build MsgContext
|
|
606
|
-
// 优先使用 userAccount,如果为空则降级使用
|
|
607
|
-
const senderId = userAccount ||
|
|
580
|
+
// 优先使用 userAccount,如果为空则降级使用 msgUid
|
|
581
|
+
const senderId = userAccount || msgUid || 'unknown';
|
|
608
582
|
// 确保 accountId 有有效值,优先使用 account.accountId,其次使用 ctx 中的 accountId,最后使用 DEFAULT_ACCOUNT_ID
|
|
609
583
|
|
|
610
584
|
const effectiveAccountId = String(account.accountId || accountId || DEFAULT_ACCOUNT_ID || 'default');
|
|
611
|
-
const sessionKey = chatTypeIsGroup
|
|
612
|
-
|
|
613
|
-
: `${CHANNEL_ID}:${effectiveAccountId}:${senderId}`;
|
|
614
|
-
console.log(`[${CHANNEL_ID}] effectiveAccountId infos:
|
|
615
|
-
account.accountId : ${account.accountId},
|
|
616
|
-
accountId: ${accountId},
|
|
617
|
-
DEFAULT_ACCOUNT_ID: ${DEFAULT_ACCOUNT_ID},
|
|
618
|
-
chatType: ${chatType},
|
|
619
|
-
sessionKey: ${sessionKey},
|
|
620
|
-
effectiveAccountId: ${effectiveAccountId},
|
|
621
|
-
`);
|
|
585
|
+
const sessionKey = `${CHANNEL_ID}:${effectiveAccountId}:${chatTypeIsGroup ? groupId : userAccount}`;
|
|
586
|
+
console.log(`[${CHANNEL_ID}] effectiveAccountId infos: account.accountId : ${account.accountId}, accountId: ${accountId}, DEFAULT_ACCOUNT_ID: ${DEFAULT_ACCOUNT_ID}, chatType: ${chatType}, sessionKey: ${sessionKey}, effectiveAccountId: ${effectiveAccountId}`);
|
|
622
587
|
|
|
623
588
|
const msgCtx: any = {
|
|
624
589
|
Body: text || ' ',
|
|
@@ -632,7 +597,7 @@ export function createTuiTuiChannelPlugin(apiRuntime: any) {
|
|
|
632
597
|
ChatType: chatType,
|
|
633
598
|
Surface: CHANNEL_ID,
|
|
634
599
|
Provider: CHANNEL_ID,
|
|
635
|
-
SenderName:
|
|
600
|
+
SenderName: msgUname || String(senderId),
|
|
636
601
|
};
|
|
637
602
|
|
|
638
603
|
// Add group-specific fields
|
|
@@ -692,7 +657,8 @@ export function createTuiTuiChannelPlugin(apiRuntime: any) {
|
|
|
692
657
|
// Handle media messages
|
|
693
658
|
const mediaUrl = payload.mediaUrl || payload.mediaUrls?.[0];
|
|
694
659
|
if (mediaUrl) {
|
|
695
|
-
|
|
660
|
+
const at = chatTypeIsGroup ? [msgUname] : [];
|
|
661
|
+
await sendMediaMsg(account, chatTarget, chatTypeIsGroup, mediaUrl, 'tuitui.deliver.media', at);
|
|
696
662
|
}
|
|
697
663
|
return;
|
|
698
664
|
}
|
|
@@ -706,7 +672,7 @@ export function createTuiTuiChannelPlugin(apiRuntime: any) {
|
|
|
706
672
|
}
|
|
707
673
|
},
|
|
708
674
|
onReplyStart: () => {
|
|
709
|
-
log?.info?.(`[${CHANNEL_ID}] Agent reply started for ${userAccount ??
|
|
675
|
+
log?.info?.(`[${CHANNEL_ID}] Agent reply started for ${userAccount ?? msgUid}`);
|
|
710
676
|
},
|
|
711
677
|
},
|
|
712
678
|
});
|
package/src/utils.ts
CHANGED
|
@@ -225,10 +225,8 @@ export async function uploadFileToTuiTui(fileSrc: string, account: any, type: 'i
|
|
|
225
225
|
export function buildMessageBody(data: TuiTuiMessageData): string {
|
|
226
226
|
const parts: string[] = [];
|
|
227
227
|
|
|
228
|
-
const
|
|
229
|
-
const
|
|
230
|
-
const pushImgs = () => {
|
|
231
|
-
const imgs = data.images;
|
|
228
|
+
const pushTxt = () => parts.push(data.text || '');
|
|
229
|
+
const pushImgs = (imgs: string[] | undefined, parts: string[]) => {
|
|
232
230
|
if (!imgs) return;
|
|
233
231
|
const imgLen = imgs?.length || 0;
|
|
234
232
|
if (imgLen === 0) return;
|
|
@@ -246,10 +244,10 @@ export function buildMessageBody(data: TuiTuiMessageData): string {
|
|
|
246
244
|
break;
|
|
247
245
|
case 'mixed':
|
|
248
246
|
pushTxt();
|
|
249
|
-
pushImgs();
|
|
247
|
+
pushImgs(data.images, parts);
|
|
250
248
|
break;
|
|
251
249
|
case 'image':
|
|
252
|
-
pushImgs();
|
|
250
|
+
pushImgs(data.images, parts);
|
|
253
251
|
break;
|
|
254
252
|
case 'voice':
|
|
255
253
|
if (data.voice) parts.push(`[语音] ${data.voice}`);
|
|
@@ -262,14 +260,16 @@ export function buildMessageBody(data: TuiTuiMessageData): string {
|
|
|
262
260
|
// Handle reference/reply
|
|
263
261
|
const { ref } = data;
|
|
264
262
|
if (ref && ref.is_me) {
|
|
265
|
-
const { msg_type
|
|
263
|
+
const { msg_type } = ref;
|
|
266
264
|
let refContent = `[${msg_type}]`;
|
|
267
265
|
switch (msg_type) {
|
|
268
266
|
case 'text':
|
|
269
|
-
refContent = text || '';
|
|
267
|
+
refContent = ref.text || '';
|
|
270
268
|
break;
|
|
271
269
|
case 'image':
|
|
272
|
-
|
|
270
|
+
const refParts: string[] = [];
|
|
271
|
+
pushImgs(ref.images, refParts);
|
|
272
|
+
refContent = refParts.join("\n") || '[图片]';
|
|
273
273
|
break;
|
|
274
274
|
}
|
|
275
275
|
parts.unshift(`[引用机器人消息]\n> ${refContent}`);
|
|
@@ -367,6 +367,7 @@ export async function sendMediaMsg(
|
|
|
367
367
|
isGroup: boolean,
|
|
368
368
|
mediaUrl: string,
|
|
369
369
|
auditCtx: string = 'tuitui.send.media',
|
|
370
|
+
at?: string[],
|
|
370
371
|
): Promise<void> {
|
|
371
372
|
if (!target) return console.error(`[${CHANNEL_ID}] sendMediaMsg Error ${auditCtx}: Missing "target"`);
|
|
372
373
|
// Check if mediaUrl looks like an image
|
|
@@ -384,7 +385,7 @@ export async function sendMediaMsg(
|
|
|
384
385
|
isImage
|
|
385
386
|
? { ...targets, msgtype: 'image', image: { media_id } }
|
|
386
387
|
: { ...targets, msgtype: 'attachment', attachment: { media_id } };
|
|
387
|
-
|
|
388
|
+
if (at && at.length > 0) msg.at = at;
|
|
388
389
|
console.log(`[${CHANNEL_ID}] sendMediaMsg ${auditCtx} - `, msg);
|
|
389
390
|
|
|
390
391
|
await postTuituiMsg(account, msg, auditCtx);
|