neoagent 2.2.1-beta.7 → 2.3.0
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/docs/index.md +1 -0
- package/docs/migration.md +238 -0
- package/lib/manager.js +99 -2
- package/lib/migrations.js +409 -0
- package/package.json +1 -1
- package/server/catalog_sources/store-bundles/skills/productivity/migration/SKILL.md +173 -0
- package/server/public/assets/fonts/MaterialIcons-Regular.otf +0 -0
- package/server/public/flutter_bootstrap.js +1 -1
- package/server/public/main.dart.js +72170 -70842
- package/server/routes/auth.js +13 -5
- package/server/routes/integrations.js +22 -0
- package/server/routes/messaging.js +41 -5
- package/server/routes/settings.js +1 -0
- package/server/services/integrations/google/provider.js +20 -2
- package/server/services/integrations/manager.js +79 -8
- package/server/services/messaging/access_policy.js +703 -0
- package/server/services/messaging/access_policy.test.js +228 -0
- package/server/services/messaging/automation.js +32 -95
- package/server/services/messaging/base.js +39 -0
- package/server/services/messaging/discord.js +61 -46
- package/server/services/messaging/http_platforms.js +178 -15
- package/server/services/messaging/manager.js +136 -69
- package/server/services/messaging/telegram.js +54 -40
- package/server/services/messaging/telnyx.js +43 -14
- package/server/services/messaging/whatsapp.js +27 -0
|
@@ -19,6 +19,8 @@ class TelegramPlatform extends BasePlatform {
|
|
|
19
19
|
this._contextBuffers = new Map();
|
|
20
20
|
this._contextMaxSize = 25;
|
|
21
21
|
this._contextMaxChats = 200;
|
|
22
|
+
this._seenUsers = new Map();
|
|
23
|
+
this._seenGroups = new Map();
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
async connect() {
|
|
@@ -91,6 +93,8 @@ class TelegramPlatform extends BasePlatform {
|
|
|
91
93
|
this.status = 'disconnected';
|
|
92
94
|
this._botUser = null;
|
|
93
95
|
this._contextBuffers.clear();
|
|
96
|
+
this._seenUsers.clear();
|
|
97
|
+
this._seenGroups.clear();
|
|
94
98
|
this.emit('disconnected', { manual: true });
|
|
95
99
|
}
|
|
96
100
|
|
|
@@ -98,25 +102,6 @@ class TelegramPlatform extends BasePlatform {
|
|
|
98
102
|
getStatus() { return this.status; }
|
|
99
103
|
getAuthInfo() { return this._botUser ? { username: this._botUser.username, id: this._botUser.id } : null; }
|
|
100
104
|
|
|
101
|
-
_checkAccess(msg) {
|
|
102
|
-
const userId = String(msg.from.id);
|
|
103
|
-
const chatId = String(msg.chat.id);
|
|
104
|
-
const isPrivate = msg.chat.type === 'private';
|
|
105
|
-
const userAllowed = super._checkAccess(`user:${userId}`) || super._checkAccess(userId);
|
|
106
|
-
|
|
107
|
-
if (isPrivate) {
|
|
108
|
-
return {
|
|
109
|
-
allowed: this.allowedEntries.size === 0 || userAllowed,
|
|
110
|
-
requireMention: false,
|
|
111
|
-
};
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
return {
|
|
115
|
-
allowed: userAllowed || super._checkAccess(`group:${chatId}`),
|
|
116
|
-
requireMention: true,
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
|
|
120
105
|
_isMentioned(msg) {
|
|
121
106
|
if (!this._botUser) return false;
|
|
122
107
|
const text = msg.text || msg.caption || '';
|
|
@@ -195,6 +180,10 @@ class TelegramPlatform extends BasePlatform {
|
|
|
195
180
|
const senderDisplayName = [msg.from.first_name, msg.from.last_name].filter(Boolean).join(' ')
|
|
196
181
|
|| senderUsername || userId;
|
|
197
182
|
const senderName = senderDisplayName;
|
|
183
|
+
this._seenUsers.set(userId, senderDisplayName);
|
|
184
|
+
if (!isPrivate) {
|
|
185
|
+
this._seenGroups.set(rawChatId, msg.chat.title || rawChatId);
|
|
186
|
+
}
|
|
198
187
|
|
|
199
188
|
this._addToContext(rawChatId, {
|
|
200
189
|
author: senderName,
|
|
@@ -202,30 +191,30 @@ class TelegramPlatform extends BasePlatform {
|
|
|
202
191
|
mine: false,
|
|
203
192
|
});
|
|
204
193
|
|
|
205
|
-
const
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
194
|
+
const access = this._checkInboundAccess({
|
|
195
|
+
platform: 'telegram',
|
|
196
|
+
senderId: userId,
|
|
197
|
+
chatId: outputChatId,
|
|
198
|
+
isDirect: isPrivate,
|
|
199
|
+
isShared: !isPrivate,
|
|
200
|
+
groupId: !isPrivate ? rawChatId : '',
|
|
201
|
+
channelId: '',
|
|
202
|
+
serverId: '',
|
|
203
|
+
roomId: '',
|
|
204
|
+
roleIds: [],
|
|
205
|
+
phoneNumber: '',
|
|
206
|
+
wasMentioned: isPrivate ? false : this._isMentioned(msg),
|
|
207
|
+
}, {
|
|
208
|
+
senderName,
|
|
209
|
+
meta: msg.chat.title ? `Group: ${msg.chat.title}` : '',
|
|
210
|
+
groupLabel: msg.chat.title || rawChatId,
|
|
211
|
+
});
|
|
217
212
|
|
|
218
|
-
|
|
219
|
-
sender: userId,
|
|
220
|
-
chatId: outputChatId,
|
|
221
|
-
senderName,
|
|
222
|
-
groupName: msg.chat.title || null,
|
|
223
|
-
suggestions,
|
|
224
|
-
});
|
|
213
|
+
if (!access.allowed) {
|
|
225
214
|
return;
|
|
226
215
|
}
|
|
227
216
|
|
|
228
|
-
let content =
|
|
217
|
+
let content = (!isPrivate && this._isMentioned(msg)) ? this._stripMention(text) : text;
|
|
229
218
|
if (!content && msg.photo) content = `[photo]`;
|
|
230
219
|
if (!content && msg.document) content = `[document: ${msg.document.file_name || 'file'}]`;
|
|
231
220
|
if (!content) return;
|
|
@@ -234,7 +223,7 @@ class TelegramPlatform extends BasePlatform {
|
|
|
234
223
|
? senderName
|
|
235
224
|
: `${senderName} in ${msg.chat.title || rawChatId}`;
|
|
236
225
|
|
|
237
|
-
const channelContext = (!isPrivate &&
|
|
226
|
+
const channelContext = (!isPrivate && this._isMentioned(msg)) ? this._getContext(rawChatId) : null;
|
|
238
227
|
|
|
239
228
|
this.emit('message', {
|
|
240
229
|
platform: 'telegram',
|
|
@@ -282,6 +271,31 @@ class TelegramPlatform extends BasePlatform {
|
|
|
282
271
|
await this._bot.telegram.sendChatAction(id, 'typing');
|
|
283
272
|
} catch {}
|
|
284
273
|
}
|
|
274
|
+
|
|
275
|
+
async listAccessTargets() {
|
|
276
|
+
const targets = [];
|
|
277
|
+
for (const [userId, label] of this._seenUsers.entries()) {
|
|
278
|
+
targets.push({
|
|
279
|
+
source: 'live',
|
|
280
|
+
bucket: 'directRules',
|
|
281
|
+
scope: 'user',
|
|
282
|
+
value: userId,
|
|
283
|
+
label,
|
|
284
|
+
subtitle: 'Telegram user',
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
for (const [groupId, label] of this._seenGroups.entries()) {
|
|
288
|
+
targets.push({
|
|
289
|
+
source: 'live',
|
|
290
|
+
bucket: 'sharedSpaceRules',
|
|
291
|
+
scope: 'group',
|
|
292
|
+
value: groupId,
|
|
293
|
+
label,
|
|
294
|
+
subtitle: 'Telegram group',
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
return targets;
|
|
298
|
+
}
|
|
285
299
|
}
|
|
286
300
|
|
|
287
301
|
module.exports = { TelegramPlatform };
|
|
@@ -39,9 +39,7 @@ class TelnyxVoicePlatform extends BasePlatform {
|
|
|
39
39
|
this.ttsVoice = resolveTtsVoice(this.ttsProvider, config.ttsVoice);
|
|
40
40
|
this.ttsModel = resolveTtsModel(this.ttsProvider, config.ttsModel);
|
|
41
41
|
this.sttModel = resolveSttModel(this.sttProvider, config.sttModel);
|
|
42
|
-
this.allowedNumbers = Array.isArray(
|
|
43
|
-
? config.allowedNumbers
|
|
44
|
-
: [];
|
|
42
|
+
this.allowedNumbers = Array.isArray(this.allowedNumbers) ? this.allowedNumbers : [];
|
|
45
43
|
this.voiceSecret = String(config.voiceSecret || '').replace(/\D/g, '');
|
|
46
44
|
this.voiceRuntimeManager = config.voiceRuntimeManager || null;
|
|
47
45
|
this.userId = config.userId || null;
|
|
@@ -110,8 +108,21 @@ class TelnyxVoicePlatform extends BasePlatform {
|
|
|
110
108
|
getAuthInfo() { return { phoneNumber: this.phoneNumber }; }
|
|
111
109
|
|
|
112
110
|
setAllowedNumbers(numbers) {
|
|
113
|
-
this.
|
|
114
|
-
|
|
111
|
+
return this.setAccessPolicy({
|
|
112
|
+
directPolicy: Array.isArray(numbers) && numbers.length > 0 ? 'allowlist' : 'disabled',
|
|
113
|
+
directRules: (Array.isArray(numbers) ? numbers : []).map((value) => ({
|
|
114
|
+
scope: 'phone_number',
|
|
115
|
+
value,
|
|
116
|
+
})),
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
setAccessPolicy(policy) {
|
|
121
|
+
const normalized = super.setAccessPolicy(policy);
|
|
122
|
+
this.allowedNumbers = normalized.directRules
|
|
123
|
+
.filter((rule) => rule.scope === 'phone_number')
|
|
124
|
+
.map((rule) => rule.value);
|
|
125
|
+
return normalized;
|
|
115
126
|
}
|
|
116
127
|
|
|
117
128
|
setVoiceSecret(secret) {
|
|
@@ -160,13 +171,20 @@ class TelnyxVoicePlatform extends BasePlatform {
|
|
|
160
171
|
}
|
|
161
172
|
|
|
162
173
|
_isAllowed(number) {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
174
|
+
return this.evaluateAccess({
|
|
175
|
+
platform: 'telnyx',
|
|
176
|
+
senderId: this._normalizeNumber(number),
|
|
177
|
+
chatId: this._normalizeNumber(number),
|
|
178
|
+
isDirect: true,
|
|
179
|
+
isShared: false,
|
|
180
|
+
groupId: '',
|
|
181
|
+
channelId: '',
|
|
182
|
+
serverId: '',
|
|
183
|
+
roomId: '',
|
|
184
|
+
roleIds: [],
|
|
185
|
+
phoneNumber: this._normalizeNumber(number),
|
|
186
|
+
wasMentioned: false,
|
|
187
|
+
}).allowed;
|
|
170
188
|
}
|
|
171
189
|
|
|
172
190
|
_normalizeNumber(n) {
|
|
@@ -414,16 +432,27 @@ class TelnyxVoicePlatform extends BasePlatform {
|
|
|
414
432
|
if (payload.direction !== 'incoming') break;
|
|
415
433
|
const caller = payload.from;
|
|
416
434
|
if (!this._isAllowed(caller)) {
|
|
435
|
+
const blockedInfo = {
|
|
436
|
+
caller,
|
|
437
|
+
ccId,
|
|
438
|
+
meta: 'Caller is not allowed by the access policy.',
|
|
439
|
+
suggestions: [{
|
|
440
|
+
label: `Allow number (${caller})`,
|
|
441
|
+
prefixedId: caller,
|
|
442
|
+
bucket: 'directRules',
|
|
443
|
+
rule: { scope: 'phone_number', value: this._normalizeNumber(caller) },
|
|
444
|
+
}],
|
|
445
|
+
};
|
|
417
446
|
if (this._isBanned(caller)) {
|
|
418
447
|
console.log(`[TelnyxVoice] Rejecting banned caller: ${caller}`);
|
|
419
448
|
await this._rejectCall(ccId);
|
|
420
|
-
this.emit('blocked_caller',
|
|
449
|
+
this.emit('blocked_caller', blockedInfo);
|
|
421
450
|
break;
|
|
422
451
|
}
|
|
423
452
|
if (!this.voiceSecret) {
|
|
424
453
|
console.log(`[TelnyxVoice] Blocked non-whitelisted caller (no secret set): ${caller}`);
|
|
425
454
|
await this._rejectCall(ccId);
|
|
426
|
-
this.emit('blocked_caller',
|
|
455
|
+
this.emit('blocked_caller', blockedInfo);
|
|
427
456
|
break;
|
|
428
457
|
}
|
|
429
458
|
console.log(`[TelnyxVoice] Non-whitelisted caller ${caller} — awaiting secret code`);
|
|
@@ -341,6 +341,33 @@ class WhatsAppPlatform extends BasePlatform {
|
|
|
341
341
|
}
|
|
342
342
|
}
|
|
343
343
|
|
|
344
|
+
async listAccessTargets() {
|
|
345
|
+
const [contacts, chats] = await Promise.all([
|
|
346
|
+
this.getContacts(),
|
|
347
|
+
this.getChats(),
|
|
348
|
+
]);
|
|
349
|
+
return [
|
|
350
|
+
...contacts
|
|
351
|
+
.filter((item) => !item.isGroup)
|
|
352
|
+
.map((item) => ({
|
|
353
|
+
source: 'live',
|
|
354
|
+
bucket: 'directRules',
|
|
355
|
+
scope: 'phone_number',
|
|
356
|
+
value: String(item.id || '').split('@')[0],
|
|
357
|
+
label: item.name || String(item.id || '').split('@')[0],
|
|
358
|
+
subtitle: 'WhatsApp contact',
|
|
359
|
+
})),
|
|
360
|
+
...chats.map((chat) => ({
|
|
361
|
+
source: 'live',
|
|
362
|
+
bucket: 'sharedSpaceRules',
|
|
363
|
+
scope: 'group',
|
|
364
|
+
value: chat.id,
|
|
365
|
+
label: chat.name || chat.id,
|
|
366
|
+
subtitle: 'WhatsApp group',
|
|
367
|
+
})),
|
|
368
|
+
];
|
|
369
|
+
}
|
|
370
|
+
|
|
344
371
|
getAuthInfo() {
|
|
345
372
|
return { qrCode: this.qrCode, status: this.status };
|
|
346
373
|
}
|