neoagent 2.1.18-beta.20 → 2.1.18-beta.21
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/server/public/flutter_bootstrap.js +1 -1
- package/server/services/messaging/automation.js +61 -18
- package/server/services/messaging/discord.js +19 -17
- package/server/services/messaging/http_platforms.js +34 -5
- package/server/services/messaging/manager.js +14 -1
- package/server/services/messaging/telegram.js +35 -12
- package/server/services/messaging/whatsapp.js +36 -1
package/package.json
CHANGED
|
@@ -37,6 +37,6 @@ _flutter.buildConfig = {"engineRevision":"425cfb54d01a9472b3e81d9e76fd63a4a44cfb
|
|
|
37
37
|
|
|
38
38
|
_flutter.loader.load({
|
|
39
39
|
serviceWorkerSettings: {
|
|
40
|
-
serviceWorkerVersion: "
|
|
40
|
+
serviceWorkerVersion: "3528621237" /* Flutter's service worker is deprecated and will be removed in a future Flutter release. */
|
|
41
41
|
}
|
|
42
42
|
});
|
|
@@ -125,6 +125,7 @@ async function processQueuedMessage({
|
|
|
125
125
|
queue.running = true;
|
|
126
126
|
let stopTypingKeepalive = async () => {};
|
|
127
127
|
try {
|
|
128
|
+
const runId = randomUUID();
|
|
128
129
|
await messagingManager
|
|
129
130
|
.markRead(userId, msg.platform, msg.chatId, msg.messageId, { agentId })
|
|
130
131
|
.catch(() => {});
|
|
@@ -132,6 +133,7 @@ async function processQueuedMessage({
|
|
|
132
133
|
messagingManager,
|
|
133
134
|
userId,
|
|
134
135
|
agentId,
|
|
136
|
+
runId,
|
|
135
137
|
platform: msg.platform,
|
|
136
138
|
chatId: msg.chatId
|
|
137
139
|
});
|
|
@@ -139,6 +141,7 @@ async function processQueuedMessage({
|
|
|
139
141
|
const prompt = buildIncomingPrompt(msg);
|
|
140
142
|
const conversationId = ensureConversation(userId, msg);
|
|
141
143
|
const runOptions = {
|
|
144
|
+
runId,
|
|
142
145
|
agentId,
|
|
143
146
|
triggerSource: 'messaging',
|
|
144
147
|
conversationId,
|
|
@@ -180,6 +183,7 @@ function startTypingKeepalive({
|
|
|
180
183
|
messagingManager,
|
|
181
184
|
userId,
|
|
182
185
|
agentId,
|
|
186
|
+
runId,
|
|
183
187
|
platform,
|
|
184
188
|
chatId,
|
|
185
189
|
intervalMs = 4000
|
|
@@ -187,6 +191,26 @@ function startTypingKeepalive({
|
|
|
187
191
|
let stopped = false;
|
|
188
192
|
let timer = null;
|
|
189
193
|
let releaseWait = null;
|
|
194
|
+
let stopPromise = null;
|
|
195
|
+
|
|
196
|
+
const matchesRunDelivery = (event) => (
|
|
197
|
+
event?.runId
|
|
198
|
+
&& runId
|
|
199
|
+
&& event.runId === runId
|
|
200
|
+
&& event.userId === userId
|
|
201
|
+
&& event.platform === platform
|
|
202
|
+
&& event.to === chatId
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
const onMessageSent = (event) => {
|
|
206
|
+
if (matchesRunDelivery(event)) {
|
|
207
|
+
stop().catch(() => {});
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
if (typeof messagingManager?.on === 'function' && typeof messagingManager?.off === 'function') {
|
|
212
|
+
messagingManager.on('message_sent', onMessageSent);
|
|
213
|
+
}
|
|
190
214
|
|
|
191
215
|
const wait = () =>
|
|
192
216
|
new Promise((resolve) => {
|
|
@@ -205,21 +229,30 @@ function startTypingKeepalive({
|
|
|
205
229
|
}
|
|
206
230
|
})();
|
|
207
231
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
232
|
+
const stop = async () => {
|
|
233
|
+
if (stopPromise) return stopPromise;
|
|
234
|
+
stopPromise = (async () => {
|
|
235
|
+
if (typeof messagingManager?.off === 'function') {
|
|
236
|
+
messagingManager.off('message_sent', onMessageSent);
|
|
237
|
+
}
|
|
238
|
+
stopped = true;
|
|
239
|
+
if (timer) {
|
|
240
|
+
clearTimeout(timer);
|
|
241
|
+
timer = null;
|
|
242
|
+
}
|
|
243
|
+
if (releaseWait) {
|
|
244
|
+
releaseWait();
|
|
245
|
+
releaseWait = null;
|
|
246
|
+
}
|
|
247
|
+
await loop.catch(() => {});
|
|
248
|
+
await messagingManager
|
|
249
|
+
.sendTyping(userId, platform, chatId, false, { agentId })
|
|
250
|
+
.catch(() => {});
|
|
251
|
+
})();
|
|
252
|
+
return stopPromise;
|
|
222
253
|
};
|
|
254
|
+
|
|
255
|
+
return stop;
|
|
223
256
|
}
|
|
224
257
|
|
|
225
258
|
function ensureConversation(userId, msg) {
|
|
@@ -331,7 +364,12 @@ async function isAllowedMessagingSender({ io, userId, msg }) {
|
|
|
331
364
|
const shouldCheckWhitelist = whitelist.length > 0;
|
|
332
365
|
|
|
333
366
|
if (!shouldCheckWhitelist) {
|
|
334
|
-
return true;
|
|
367
|
+
if (!msg.isGroup) return true;
|
|
368
|
+
console.log(
|
|
369
|
+
`[Messaging] Blocked ${msg.platform} group message from ${msg.sender} (no group allowlist configured)`
|
|
370
|
+
);
|
|
371
|
+
emitBlockedSenderSuggestion({ io, userId, msg });
|
|
372
|
+
return false;
|
|
335
373
|
}
|
|
336
374
|
|
|
337
375
|
const candidates = messagingAllowlistCandidates(msg).map(normalize).filter(Boolean);
|
|
@@ -346,6 +384,11 @@ async function isAllowedMessagingSender({ io, userId, msg }) {
|
|
|
346
384
|
console.log(
|
|
347
385
|
`[Messaging] Blocked ${msg.platform} message from ${msg.sender} (not in whitelist)`
|
|
348
386
|
);
|
|
387
|
+
emitBlockedSenderSuggestion({ io, userId, msg });
|
|
388
|
+
return false;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
function emitBlockedSenderSuggestion({ io, userId, msg }) {
|
|
349
392
|
const suggestions = [];
|
|
350
393
|
if (msg.platform === 'whatsapp') {
|
|
351
394
|
const normalizedSender = normalizeWhatsAppId(msg.sender || msg.chatId);
|
|
@@ -367,7 +410,7 @@ async function isAllowedMessagingSender({ io, userId, msg }) {
|
|
|
367
410
|
if (chatId && chatId !== sender) {
|
|
368
411
|
suggestions.push({
|
|
369
412
|
label: `Add chat (${chatId})`,
|
|
370
|
-
prefixedId: msg.isGroup ? `
|
|
413
|
+
prefixedId: msg.isGroup ? `group:${chatId}` : chatId
|
|
371
414
|
});
|
|
372
415
|
}
|
|
373
416
|
}
|
|
@@ -378,10 +421,10 @@ async function isAllowedMessagingSender({ io, userId, msg }) {
|
|
|
378
421
|
senderName: msg.senderName || null,
|
|
379
422
|
suggestions: suggestions.length > 0 ? suggestions : null
|
|
380
423
|
});
|
|
381
|
-
return false;
|
|
382
424
|
}
|
|
383
425
|
|
|
384
426
|
module.exports = {
|
|
385
427
|
isAllowedMessagingSender,
|
|
386
|
-
registerMessagingAutomation
|
|
428
|
+
registerMessagingAutomation,
|
|
429
|
+
startTypingKeepalive
|
|
387
430
|
};
|
|
@@ -10,7 +10,7 @@ const {
|
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Whitelist entry format (prefixed strings):
|
|
13
|
-
* "user:SNOWFLAKE" →
|
|
13
|
+
* "user:SNOWFLAKE" → allow DMs; allow guild messages only when @mentioned
|
|
14
14
|
* "guild:SNOWFLAKE" → respond in any channel of this server when @mentioned
|
|
15
15
|
* "channel:SNOWFLAKE" → respond in this channel when @mentioned
|
|
16
16
|
* "SNOWFLAKE" → legacy plain ID, treated as "user"
|
|
@@ -112,23 +112,25 @@ class DiscordPlatform extends BasePlatform {
|
|
|
112
112
|
|
|
113
113
|
/** Returns {allowed, requireMention} */
|
|
114
114
|
_checkAccess(message) {
|
|
115
|
-
|
|
116
|
-
if (this.allowedEntries.size === 0) {
|
|
117
|
-
const isDM = message.channel.type === ChannelType.DM;
|
|
118
|
-
return { allowed: true, requireMention: !isDM };
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// Check prefixed entries
|
|
115
|
+
const isDM = message.channel.type === ChannelType.DM;
|
|
122
116
|
const userId = message.author.id;
|
|
123
117
|
const guildId = message.guildId || null;
|
|
124
118
|
const channelId = message.channelId;
|
|
119
|
+
const userAllowed = super._checkAccess(`user:${userId}`) || super._checkAccess(userId);
|
|
125
120
|
|
|
126
|
-
if (
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
121
|
+
if (isDM) {
|
|
122
|
+
return {
|
|
123
|
+
allowed: this.allowedEntries.size === 0 || userAllowed,
|
|
124
|
+
requireMention: false,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
130
127
|
|
|
131
|
-
return {
|
|
128
|
+
return {
|
|
129
|
+
allowed: userAllowed
|
|
130
|
+
|| (guildId && super._checkAccess(`guild:${guildId}`))
|
|
131
|
+
|| super._checkAccess(`channel:${channelId}`),
|
|
132
|
+
requireMention: true,
|
|
133
|
+
};
|
|
132
134
|
}
|
|
133
135
|
|
|
134
136
|
_isMentioned(message) {
|
|
@@ -171,6 +173,8 @@ class DiscordPlatform extends BasePlatform {
|
|
|
171
173
|
|
|
172
174
|
const { allowed, requireMention } = this._checkAccess(message);
|
|
173
175
|
|
|
176
|
+
if (requireMention && !this._isMentioned(message)) return;
|
|
177
|
+
|
|
174
178
|
if (!allowed) {
|
|
175
179
|
const suggestions = [
|
|
176
180
|
{ label: `Add user (${message.author.username})`, prefixedId: `user:${userId}` },
|
|
@@ -188,9 +192,6 @@ class DiscordPlatform extends BasePlatform {
|
|
|
188
192
|
return;
|
|
189
193
|
}
|
|
190
194
|
|
|
191
|
-
// guild/channel entries require @mention to activate
|
|
192
|
-
if (requireMention && !this._isMentioned(message)) return;
|
|
193
|
-
|
|
194
195
|
let content = requireMention ? this._stripMention(message.content) : (message.content || '');
|
|
195
196
|
if (message.attachments.size > 0) {
|
|
196
197
|
const urls = [...message.attachments.values()].map(a => a.url).join(', ');
|
|
@@ -241,8 +242,9 @@ class DiscordPlatform extends BasePlatform {
|
|
|
241
242
|
return { success: true };
|
|
242
243
|
}
|
|
243
244
|
|
|
244
|
-
async sendTyping(chatId,
|
|
245
|
+
async sendTyping(chatId, isTyping) {
|
|
245
246
|
if (!this._client || this.status !== 'connected') return;
|
|
247
|
+
if (!isTyping) return;
|
|
246
248
|
try {
|
|
247
249
|
if (chatId.startsWith('dm_')) {
|
|
248
250
|
const user = await this._client.users.fetch(chatId.slice(3));
|
|
@@ -282,19 +282,34 @@ class SlackPlatform extends BasePlatform {
|
|
|
282
282
|
|
|
283
283
|
const event = body.event || body;
|
|
284
284
|
if (event.type !== 'message' || event.subtype || !event.text) {
|
|
285
|
+
if (event.type !== 'app_mention') {
|
|
286
|
+
return { handled: true, status: 202, body: 'ignored' };
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
if (event.subtype || !event.text) {
|
|
285
290
|
return { handled: true, status: 202, body: 'ignored' };
|
|
286
291
|
}
|
|
287
292
|
if (this._botUserId && event.user === this._botUserId) {
|
|
288
293
|
return { handled: true, status: 202, body: 'ignored' };
|
|
289
294
|
}
|
|
295
|
+
const isGroup = String(event.channel_type || '') !== 'im';
|
|
296
|
+
const wasMentioned = event.type === 'app_mention'
|
|
297
|
+
|| (this._botUserId && String(event.text || '').includes(`<@${this._botUserId}>`));
|
|
298
|
+
if (isGroup && !wasMentioned) {
|
|
299
|
+
return { handled: true, status: 202, body: 'ignored' };
|
|
300
|
+
}
|
|
301
|
+
const content = this._botUserId
|
|
302
|
+
? String(event.text).replace(new RegExp(`<@${this._botUserId}>`, 'g'), '').trim()
|
|
303
|
+
: String(event.text);
|
|
304
|
+
if (!content) return { handled: true, status: 202, body: 'ignored' };
|
|
290
305
|
this.emit('message', {
|
|
291
306
|
platform: 'slack',
|
|
292
307
|
chatId: String(event.channel || 'slack'),
|
|
293
308
|
sender: String(event.user || event.bot_id || 'slack'),
|
|
294
309
|
senderName: event.username || null,
|
|
295
|
-
content
|
|
310
|
+
content,
|
|
296
311
|
mediaType: null,
|
|
297
|
-
isGroup
|
|
312
|
+
isGroup,
|
|
298
313
|
messageId: String(event.client_msg_id || event.ts || crypto.randomUUID()),
|
|
299
314
|
timestamp: event.event_ts ? new Date(Number(event.event_ts) * 1000).toISOString() : new Date().toISOString(),
|
|
300
315
|
threadTs: event.thread_ts || null,
|
|
@@ -431,12 +446,17 @@ class MatrixPlatform extends BasePlatform {
|
|
|
431
446
|
if (event.sender && this.userId && event.sender === this.userId) continue;
|
|
432
447
|
const content = event.content?.body || '';
|
|
433
448
|
if (!content) continue;
|
|
449
|
+
if (this.userId && !content.includes(this.userId)) continue;
|
|
450
|
+
const cleanContent = this.userId
|
|
451
|
+
? String(content).replaceAll(this.userId, '').trim()
|
|
452
|
+
: String(content);
|
|
453
|
+
if (!cleanContent) continue;
|
|
434
454
|
this.emit('message', {
|
|
435
455
|
platform: 'matrix',
|
|
436
456
|
chatId: roomId,
|
|
437
457
|
sender: String(event.sender || roomId),
|
|
438
458
|
senderName: event.sender || null,
|
|
439
|
-
content:
|
|
459
|
+
content: cleanContent,
|
|
440
460
|
mediaType: null,
|
|
441
461
|
isGroup: true,
|
|
442
462
|
messageId: String(event.event_id || crypto.randomUUID()),
|
|
@@ -739,14 +759,23 @@ class IrcPlatform extends BasePlatform {
|
|
|
739
759
|
if (!match) continue;
|
|
740
760
|
const [, nick, target, content] = match;
|
|
741
761
|
if (nick === this.nick) continue;
|
|
762
|
+
const isGroup = target.startsWith('#');
|
|
763
|
+
if (isGroup) {
|
|
764
|
+
const escaped = this.nick.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
765
|
+
if (!new RegExp(`(^|\\s)${escaped}[:,]?\\b`, 'i').test(content)) continue;
|
|
766
|
+
}
|
|
767
|
+
const cleanContent = isGroup
|
|
768
|
+
? content.replace(new RegExp(`(^|\\s)${this.nick.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}[:,]?\\s*`, 'i'), ' ').trim()
|
|
769
|
+
: content;
|
|
770
|
+
if (!cleanContent) continue;
|
|
742
771
|
this.emit('message', {
|
|
743
772
|
platform: this.name,
|
|
744
773
|
chatId: target,
|
|
745
774
|
sender: nick,
|
|
746
775
|
senderName: nick,
|
|
747
|
-
content,
|
|
776
|
+
content: cleanContent,
|
|
748
777
|
mediaType: null,
|
|
749
|
-
isGroup
|
|
778
|
+
isGroup,
|
|
750
779
|
messageId: crypto.randomUUID(),
|
|
751
780
|
timestamp: new Date().toISOString(),
|
|
752
781
|
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
const EventEmitter = require('events');
|
|
1
2
|
const db = require('../../db/database');
|
|
2
3
|
const fs = require('fs');
|
|
3
4
|
const path = require('path');
|
|
@@ -62,8 +63,9 @@ class IMessageMessagingPlatform extends BlueBubblesPlatform {
|
|
|
62
63
|
constructor(config = {}) { super('imessage', config); }
|
|
63
64
|
}
|
|
64
65
|
|
|
65
|
-
class MessagingManager {
|
|
66
|
+
class MessagingManager extends EventEmitter {
|
|
66
67
|
constructor(io) {
|
|
68
|
+
super();
|
|
67
69
|
this.io = io;
|
|
68
70
|
this.platforms = new Map();
|
|
69
71
|
this.messageHandlers = [];
|
|
@@ -342,6 +344,17 @@ class MessagingManager {
|
|
|
342
344
|
runId
|
|
343
345
|
});
|
|
344
346
|
|
|
347
|
+
this.emit('message_sent', {
|
|
348
|
+
userId,
|
|
349
|
+
agentId,
|
|
350
|
+
platform: platformName,
|
|
351
|
+
to,
|
|
352
|
+
content,
|
|
353
|
+
mediaPath,
|
|
354
|
+
runId,
|
|
355
|
+
result
|
|
356
|
+
});
|
|
357
|
+
|
|
345
358
|
return { success: true, result };
|
|
346
359
|
}
|
|
347
360
|
|
|
@@ -100,33 +100,55 @@ class TelegramPlatform extends BasePlatform {
|
|
|
100
100
|
const userId = String(msg.from.id);
|
|
101
101
|
const chatId = String(msg.chat.id);
|
|
102
102
|
const isPrivate = msg.chat.type === 'private';
|
|
103
|
+
const userAllowed = super._checkAccess(`user:${userId}`) || super._checkAccess(userId);
|
|
103
104
|
|
|
104
|
-
if (
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
105
|
+
if (isPrivate) {
|
|
106
|
+
return {
|
|
107
|
+
allowed: this.allowedEntries.size === 0 || userAllowed,
|
|
108
|
+
requireMention: false,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
109
111
|
|
|
110
|
-
return {
|
|
112
|
+
return {
|
|
113
|
+
allowed: userAllowed || super._checkAccess(`group:${chatId}`),
|
|
114
|
+
requireMention: true,
|
|
115
|
+
};
|
|
111
116
|
}
|
|
112
117
|
|
|
113
118
|
_isMentioned(msg) {
|
|
114
119
|
if (!this._botUser) return false;
|
|
115
120
|
const text = msg.text || msg.caption || '';
|
|
116
121
|
const entities = msg.entities || msg.caption_entities || [];
|
|
122
|
+
const botId = String(this._botUser.id || '');
|
|
123
|
+
const botUsername = String(this._botUser.username || '').toLowerCase();
|
|
124
|
+
const botMention = `@${botUsername}`;
|
|
117
125
|
for (const e of entities) {
|
|
126
|
+
const value = text.slice(e.offset, e.offset + e.length).toLowerCase();
|
|
118
127
|
if (e.type === 'mention') {
|
|
119
|
-
|
|
120
|
-
|
|
128
|
+
if (value === botMention) return true;
|
|
129
|
+
}
|
|
130
|
+
if (e.type === 'bot_command') {
|
|
131
|
+
if (value.endsWith(botMention)) return true;
|
|
121
132
|
}
|
|
133
|
+
if (e.type === 'text_mention' && String(e.user?.id || '') === botId) {
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (msg.reply_to_message?.from && String(msg.reply_to_message.from.id || '') === botId) {
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
if (botUsername) {
|
|
141
|
+
const escaped = botUsername.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
142
|
+
if (new RegExp(`(^|\\s)@${escaped}\\b`, 'i').test(text)) return true;
|
|
122
143
|
}
|
|
123
144
|
return false;
|
|
124
145
|
}
|
|
125
146
|
|
|
126
147
|
_stripMention(text) {
|
|
127
148
|
if (!this._botUser) return (text || '').trim();
|
|
149
|
+
const username = String(this._botUser.username || '').replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
128
150
|
return (text || '')
|
|
129
|
-
.replace(new RegExp(`@${
|
|
151
|
+
.replace(new RegExp(`@${username}`, 'gi'), '')
|
|
130
152
|
.replace(/\s{2,}/g, ' ')
|
|
131
153
|
.trim();
|
|
132
154
|
}
|
|
@@ -168,6 +190,8 @@ class TelegramPlatform extends BasePlatform {
|
|
|
168
190
|
|
|
169
191
|
const { allowed, requireMention } = this._checkAccess(msg);
|
|
170
192
|
|
|
193
|
+
if (requireMention && !this._isMentioned(msg)) return;
|
|
194
|
+
|
|
171
195
|
if (!allowed) {
|
|
172
196
|
const suggestions = [
|
|
173
197
|
{ label: `Add user (${senderName})`, prefixedId: `user:${userId}` },
|
|
@@ -187,8 +211,6 @@ class TelegramPlatform extends BasePlatform {
|
|
|
187
211
|
return;
|
|
188
212
|
}
|
|
189
213
|
|
|
190
|
-
if (requireMention && !this._isMentioned(msg)) return;
|
|
191
|
-
|
|
192
214
|
let content = requireMention ? this._stripMention(text) : text;
|
|
193
215
|
if (!content && msg.photo) content = `[photo]`;
|
|
194
216
|
if (!content && msg.document) content = `[document: ${msg.document.file_name || 'file'}]`;
|
|
@@ -235,8 +257,9 @@ class TelegramPlatform extends BasePlatform {
|
|
|
235
257
|
return { success: true };
|
|
236
258
|
}
|
|
237
259
|
|
|
238
|
-
async sendTyping(chatId,
|
|
260
|
+
async sendTyping(chatId, isTyping) {
|
|
239
261
|
if (!this._bot || this.status !== 'connected') return;
|
|
262
|
+
if (!isTyping) return;
|
|
240
263
|
try {
|
|
241
264
|
const id = chatId.startsWith('dm_') ? chatId.slice(3) : chatId;
|
|
242
265
|
await this._bot.telegram.sendChatAction(id, 'typing');
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const { BasePlatform } = require('./base');
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const fs = require('fs');
|
|
4
|
-
const { toWhatsAppJid } = require('../../utils/whatsapp');
|
|
4
|
+
const { normalizeWhatsAppId, toWhatsAppJid } = require('../../utils/whatsapp');
|
|
5
5
|
const { DATA_DIR } = require('../../../runtime/paths');
|
|
6
6
|
|
|
7
7
|
const AUTH_DIR = path.join(DATA_DIR, 'whatsapp-auth');
|
|
@@ -18,6 +18,40 @@ class WhatsAppPlatform extends BasePlatform {
|
|
|
18
18
|
this.authDir = config.authDir || AUTH_DIR;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
_ownIds() {
|
|
22
|
+
return new Set([
|
|
23
|
+
this.sock?.user?.id,
|
|
24
|
+
this.sock?.user?.jid,
|
|
25
|
+
]
|
|
26
|
+
.map(normalizeWhatsAppId)
|
|
27
|
+
.filter(Boolean));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
_contextInfo(message = {}) {
|
|
31
|
+
return message.extendedTextMessage?.contextInfo
|
|
32
|
+
|| message.imageMessage?.contextInfo
|
|
33
|
+
|| message.videoMessage?.contextInfo
|
|
34
|
+
|| message.documentMessage?.contextInfo
|
|
35
|
+
|| message.audioMessage?.contextInfo
|
|
36
|
+
|| message.conversation?.contextInfo
|
|
37
|
+
|| null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
_isGroupAddressedToBot(message = {}) {
|
|
41
|
+
const ownIds = this._ownIds();
|
|
42
|
+
if (ownIds.size === 0) return false;
|
|
43
|
+
const contextInfo = this._contextInfo(message);
|
|
44
|
+
const mentions = Array.isArray(contextInfo?.mentionedJid) ? contextInfo.mentionedJid : [];
|
|
45
|
+
if (mentions.some((jid) => ownIds.has(normalizeWhatsAppId(jid)))) return true;
|
|
46
|
+
if (ownIds.has(normalizeWhatsAppId(contextInfo?.participant))) return true;
|
|
47
|
+
const text = message.conversation
|
|
48
|
+
|| message.extendedTextMessage?.text
|
|
49
|
+
|| message.imageMessage?.caption
|
|
50
|
+
|| message.videoMessage?.caption
|
|
51
|
+
|| '';
|
|
52
|
+
return [...ownIds].some((id) => text.includes(`@${id}`));
|
|
53
|
+
}
|
|
54
|
+
|
|
21
55
|
async connect() {
|
|
22
56
|
if (!fs.existsSync(this.authDir)) fs.mkdirSync(this.authDir, { recursive: true });
|
|
23
57
|
|
|
@@ -133,6 +167,7 @@ class WhatsAppPlatform extends BasePlatform {
|
|
|
133
167
|
}
|
|
134
168
|
|
|
135
169
|
if (!content && !mediaType) continue;
|
|
170
|
+
if (isGroup && !this._isGroupAddressedToBot(msg.message || {})) continue;
|
|
136
171
|
|
|
137
172
|
let localMediaPath = null;
|
|
138
173
|
if (mediaType && mediaType !== 'sticker') {
|