plogme 2.0.0 → 2.0.2
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/README.md +536 -389
- package/lib/Socket/chats.js +1 -0
- package/lib/Socket/messages-send.js +93 -19
- package/lib/Socket/newsletter.js +37 -3
- package/lib/Utils/bot-capabilities.js +84 -0
- package/lib/Utils/bot-planning-replay.js +0 -1
- package/lib/Utils/channel-policy.js +25 -1
- package/lib/Utils/index.js +1 -0
- package/lib/Utils/messages.js +11 -6
- package/lib/Utils/meta-compositing.js +7 -0
- package/lib/Utils/rich-message-utils.js +119 -67
- package/lib/index.d.ts +6 -0
- package/package.json +2 -2
package/lib/Socket/chats.js
CHANGED
|
@@ -5,7 +5,7 @@ import { proto } from '../../WAProto/index.js';
|
|
|
5
5
|
import { BIZ_BOT_SUPPORT_PAYLOAD, DEFAULT_CACHE_TTLS, WA_DEFAULT_EPHEMERAL } from '../Defaults/index.js';
|
|
6
6
|
import { aggregateMessageKeysNotFromMe, assertMediaContent, assertMeId, bindWaitForEvent, buildLinkPreview, decryptMediaRetryData, DEF_MEDIA_HOST, delay, encodeNewsletterMessage, encodeSignedDeviceIdentity, encodeWAMessage, encryptMediaRetryRequest, extractDeviceJids, extractImageThumb, generateMessageIDV2, generateParticipantHashV2, generateWAMessage, generateWAMessageFromContent, getStatusCodeForMediaRetry, makeWhatsAppFlowButton, getUrlFromDirectPath, getWAUploadToServer, hasValidAlbumMedia, MessageRetryManager, normalizeMessageContent, parseAndInjectE2ESessions, prepareWAMessageMedia, shouldIncludeBizBinaryNode, unixTimestampSeconds } from '../Utils/index.js';
|
|
7
7
|
import { getUrlInfo } from '../Utils/link-preview.js';
|
|
8
|
-
import { prepareRichMenuMessage, prepareRichResponseMessage, prepareRichGenerationMessage, prepareCopyToClipboardMessage, prepareRichTextMessage, prepareRichQuoteMessage, prepareRichImageMessage, prepareRichLinkMessage, prepareHtmlMessage, prepareRichHtmlMessage } from '../Utils/rich-message-utils.js';
|
|
8
|
+
import { prepareRichMenuMessage, prepareRichResponseMessage, prepareRichGenerationMessage, prepareCopyToClipboardMessage, prepareRichTextMessage, prepareRichQuoteMessage, prepareRichImageMessage, prepareRichLinkMessage, prepareHtmlMessage, prepareRichHtmlMessage, attachBotVerificationProofs, hasVerifiableProofs } from '../Utils/rich-message-utils.js';
|
|
9
9
|
import { generateSlotMachineHtml } from '../Utils/games/slot-machine.js';
|
|
10
10
|
import { generateMiniAppHtml } from '../Utils/games/miniapp.js';
|
|
11
11
|
import { generateWebsitePreviewHtml, generateLinkPreviewHtml } from '../Utils/games/website-preview.js';
|
|
@@ -16,6 +16,7 @@ import { buildMergedTcTokenIndexWrite, isTcTokenExpired, resolveIssuanceJid, res
|
|
|
16
16
|
import { areJidsSameUser, getBinaryNodeChild, getBinaryNodeChildren, getBizBinaryNode, isHostedLidUser, isHostedPnUser, isJidBot, isJidGroup, isJidMetaAI, isJidNewsletter, isLidUser, isPnUser, jidDecode, jidEncode, jidNormalizedUser, PSA_WID, S_WHATSAPP_NET } from '../WABinary/index.js';
|
|
17
17
|
import { USyncQuery, USyncUser } from '../WAUSync/index.js';
|
|
18
18
|
import { captureUnifiedResponse, generateCodeBlockContent, generateLatexContent, generateListContent, generateTableContent, generateUnifiedResponseContent } from '../Utils/message-composer.js';
|
|
19
|
+
import { BotCapabilityType, buildBotRichResponse } from '../Utils/bot-capabilities.js';
|
|
19
20
|
import { Baron } from './interactive-handler.js';
|
|
20
21
|
import { collectMetaAIBotParticipantJids, isMetaAIBotResponse, META_AI_BOT_JID } from './aigroups.js';
|
|
21
22
|
import { makeUsernameSocket } from './username.js';
|
|
@@ -554,7 +555,18 @@ export const makeMessagesSocket = (config) => {
|
|
|
554
555
|
};
|
|
555
556
|
}
|
|
556
557
|
const applyForwarded = m => {
|
|
558
|
+
// Auto-inject trusted verification proofs configured once on the socket
|
|
559
|
+
// (config.metaAiRendering.verificationMetadata). Per-message proofs win:
|
|
560
|
+
// an envelope that already carries verificationMetadata is left untouched.
|
|
561
|
+
// The second target covers edited rich envelopes (protocolMessage.editedMessage,
|
|
562
|
+
// used by updateRichGeneration) so an in-place rich update keeps its proofs too.
|
|
563
|
+
const edited = m?.botForwardedMessage?.message?.protocolMessage?.editedMessage;
|
|
557
564
|
const rich = m?.botForwardedMessage?.message?.richResponseMessage || m?.richResponseMessage;
|
|
565
|
+
if (!rich && !edited) return m;
|
|
566
|
+
if (hasVerifiableProofs(config?.metaAiRendering?.verificationMetadata)) {
|
|
567
|
+
attachBotVerificationProofs(m, config.metaAiRendering.verificationMetadata);
|
|
568
|
+
attachBotVerificationProofs(edited, config.metaAiRendering.verificationMetadata);
|
|
569
|
+
}
|
|
558
570
|
if (!rich) return m;
|
|
559
571
|
rich.contextInfo = { ...rich.contextInfo, isForwarded: true, forwardOrigin: 4 };
|
|
560
572
|
return m.botForwardedMessage ? m : { botForwardedMessage: { message: m } };
|
|
@@ -1371,10 +1383,20 @@ export const makeMessagesSocket = (config) => {
|
|
|
1371
1383
|
},
|
|
1372
1384
|
// Additive Nexus-compatible AI-rich helpers. Existing Gen4/table/grid/carousel APIs remain unchanged.
|
|
1373
1385
|
sendRichMedia: async (jid, content = {}, quoted, options = {}) => {
|
|
1374
|
-
const
|
|
1375
|
-
const
|
|
1376
|
-
|
|
1377
|
-
|
|
1386
|
+
const contentMessage = prepareRichResponseMessage({ ...content, noDonation: options.noDonation ?? true });
|
|
1387
|
+
const generated = generateWAMessageFromContent(jid, contentMessage, {
|
|
1388
|
+
logger,
|
|
1389
|
+
userJid: authState.creds.me?.id,
|
|
1390
|
+
messageId: options.messageId || generateMessageIDV2(jid),
|
|
1391
|
+
quoted,
|
|
1392
|
+
...options
|
|
1393
|
+
});
|
|
1394
|
+
await relayMessage(jid, generated.message, {
|
|
1395
|
+
messageId: generated.key.id,
|
|
1396
|
+
useCachedGroupMetadata: options.useCachedGroupMetadata,
|
|
1397
|
+
statusJidList: options.statusJidList
|
|
1398
|
+
});
|
|
1399
|
+
return { ...generated, messageId: generated.key.id };
|
|
1378
1400
|
},
|
|
1379
1401
|
/**
|
|
1380
1402
|
* Send a native AI image/video generation card. The returned messageId
|
|
@@ -1447,18 +1469,38 @@ export const makeMessagesSocket = (config) => {
|
|
|
1447
1469
|
else {
|
|
1448
1470
|
throw new Boom('sendRichAIResponse: unknown content type — expected table, list, codeBlock or latex');
|
|
1449
1471
|
}
|
|
1450
|
-
const
|
|
1451
|
-
|
|
1452
|
-
|
|
1472
|
+
const fullMsg = generateWAMessageFromContent(jid, generated.message, {
|
|
1473
|
+
logger,
|
|
1474
|
+
userJid: authState.creds.me?.id,
|
|
1475
|
+
messageId: options.messageId || generated.messageId || generateMessageIDV2(jid),
|
|
1476
|
+
quoted,
|
|
1477
|
+
...options
|
|
1478
|
+
});
|
|
1479
|
+
await relayMessage(jid, fullMsg.message, {
|
|
1480
|
+
messageId: fullMsg.key.id,
|
|
1481
|
+
useCachedGroupMetadata: options.useCachedGroupMetadata,
|
|
1482
|
+
statusJidList: options.statusJidList
|
|
1483
|
+
});
|
|
1484
|
+
return fullMsg;
|
|
1453
1485
|
},
|
|
1454
1486
|
captureAndResendUnifiedResponse: async (jid, metaAiMsg, quoted) => {
|
|
1455
1487
|
const captured = captureUnifiedResponse(metaAiMsg);
|
|
1456
1488
|
if (!captured) {
|
|
1457
1489
|
throw new Boom('captureAndResendUnifiedResponse: message contains no unifiedResponse data');
|
|
1458
1490
|
}
|
|
1459
|
-
const
|
|
1460
|
-
|
|
1461
|
-
|
|
1491
|
+
const generated = generateUnifiedResponseContent(quoted, captured);
|
|
1492
|
+
const fullMsg = generateWAMessageFromContent(jid, generated.message, {
|
|
1493
|
+
logger,
|
|
1494
|
+
userJid: authState.creds.me?.id,
|
|
1495
|
+
messageId: generated.messageId || generateMessageIDV2(jid),
|
|
1496
|
+
quoted
|
|
1497
|
+
});
|
|
1498
|
+
await relayMessage(jid, fullMsg.message, {
|
|
1499
|
+
messageId: fullMsg.key.id,
|
|
1500
|
+
useCachedGroupMetadata: options?.useCachedGroupMetadata,
|
|
1501
|
+
statusJidList: options?.statusJidList
|
|
1502
|
+
});
|
|
1503
|
+
return fullMsg;
|
|
1462
1504
|
},
|
|
1463
1505
|
updateMediaMessage: async (message) => {
|
|
1464
1506
|
const content = assertMediaContent(message.message);
|
|
@@ -2322,10 +2364,30 @@ export const makeMessagesSocket = (config) => {
|
|
|
2322
2364
|
socket.sendBotCommand = async (jid, content = {}, options = {}) => {
|
|
2323
2365
|
if (!jid) throw new Boom('sendBotCommand requires a target JID', { statusCode: 400 });
|
|
2324
2366
|
const { text = 'Bot command test', commandName = '', commandDescription = '', commandPrompt = '', botJid = '867051314767696@bot' } = content;
|
|
2325
|
-
const wrapped = {
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2367
|
+
const wrapped = buildBotRichResponse({ text, botJid, botMetadata: { commandMetadata: { commandName, commandDescription, commandPrompt } } });
|
|
2368
|
+
const fullMsg = await generateWAMessageFromContent(jid, wrapped, { logger, userJid: authState.creds.me?.id, messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id), ...options });
|
|
2369
|
+
await relayMessage(jid, fullMsg.message, { messageId: fullMsg.key.id, useCachedGroupMetadata: options.useCachedGroupMetadata, statusJidList: options.statusJidList });
|
|
2370
|
+
return fullMsg;
|
|
2371
|
+
};
|
|
2372
|
+
/** Sends a planning/execution-plan rich response with WAProto capabilities. */
|
|
2373
|
+
socket.sendBotPlanning = async (jid, content = {}, options = {}) => {
|
|
2374
|
+
if (!jid) throw new Boom('sendBotPlanning requires a target JID', { statusCode: 400 });
|
|
2375
|
+
const { text = 'Execution plan', steps = [], queryPlan = true, botJid = '867051314767696@bot' } = content;
|
|
2376
|
+
const submessages = [
|
|
2377
|
+
{ messageType: proto.AIRichResponseSubMessageType.AI_RICH_RESPONSE_TEXT, messageText: text },
|
|
2378
|
+
...steps.map(step => ({
|
|
2379
|
+
messageType: proto.AIRichResponseSubMessageType.AI_RICH_RESPONSE_TEXT,
|
|
2380
|
+
messageText: typeof step === 'string' ? step : `${step.title || step.name || 'Step'}${step.body ? `: ${step.body}` : ''}`
|
|
2381
|
+
}))
|
|
2382
|
+
];
|
|
2383
|
+
const wrapped = buildBotRichResponse({
|
|
2384
|
+
botJid,
|
|
2385
|
+
submessages,
|
|
2386
|
+
capabilities: [
|
|
2387
|
+
BotCapabilityType.AGENTIC_PLANNING,
|
|
2388
|
+
...(queryPlan ? [BotCapabilityType.QUERY_PLAN] : [])
|
|
2389
|
+
]
|
|
2390
|
+
});
|
|
2329
2391
|
const fullMsg = await generateWAMessageFromContent(jid, wrapped, { logger, userJid: authState.creds.me?.id, messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id), ...options });
|
|
2330
2392
|
await relayMessage(jid, fullMsg.message, { messageId: fullMsg.key.id, useCachedGroupMetadata: options.useCachedGroupMetadata, statusJidList: options.statusJidList });
|
|
2331
2393
|
return fullMsg;
|
|
@@ -2334,10 +2396,17 @@ export const makeMessagesSocket = (config) => {
|
|
|
2334
2396
|
socket.sendBotToolResult = async (jid, content = {}, options = {}) => {
|
|
2335
2397
|
if (!jid) throw new Boom('sendBotToolResult requires a target JID', { statusCode: 400 });
|
|
2336
2398
|
const { text = 'Bot tool result test', toolCallId = `tool-${Date.now()}`, resolutionData, resolutionDataSerialized, botJid = '867051314767696@bot' } = content;
|
|
2337
|
-
const wrapped = {
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2399
|
+
const wrapped = buildBotRichResponse({
|
|
2400
|
+
text,
|
|
2401
|
+
botJid,
|
|
2402
|
+
capabilities: [BotCapabilityType.AGENTIC_PLANNING],
|
|
2403
|
+
botMetadata: {
|
|
2404
|
+
resolvedToolCallMetadata: {
|
|
2405
|
+
toolCallId,
|
|
2406
|
+
resolutionDataSerialized: resolutionDataSerialized ?? JSON.stringify(resolutionData ?? {})
|
|
2407
|
+
}
|
|
2408
|
+
}
|
|
2409
|
+
});
|
|
2341
2410
|
const fullMsg = await generateWAMessageFromContent(jid, wrapped, { logger, userJid: authState.creds.me?.id, messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id), ...options });
|
|
2342
2411
|
await relayMessage(jid, fullMsg.message, { messageId: fullMsg.key.id, useCachedGroupMetadata: options.useCachedGroupMetadata, statusJidList: options.statusJidList });
|
|
2343
2412
|
return fullMsg;
|
|
@@ -2375,6 +2444,11 @@ export const makeMessagesSocket = (config) => {
|
|
|
2375
2444
|
cards: normalizedCards
|
|
2376
2445
|
}, options);
|
|
2377
2446
|
};
|
|
2447
|
+
/**
|
|
2448
|
+
* Compatibility entry point for the former Gen4/grid menu.
|
|
2449
|
+
* This is additive: sendRichButtonGrid remains unchanged for existing callers.
|
|
2450
|
+
*/
|
|
2451
|
+
socket.HoldOn = async (jid, grid, options = {}) => socket.sendRichButtonGrid(jid, grid, options);
|
|
2378
2452
|
socket.sendWhatsAppFlow = async (jid, flow, options = {}) => {
|
|
2379
2453
|
const { text, footer, image, caption, ...flowOptions } = flow || {};
|
|
2380
2454
|
const button = makeWhatsAppFlowButton(flowOptions);
|
package/lib/Socket/newsletter.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Boom } from '@hapi/boom';
|
|
1
2
|
import { proto } from '../../WAProto/index.js';
|
|
2
3
|
import { QueryIds, XWAPaths } from '../Types/index.js';
|
|
3
4
|
import { generateProfilePicture } from '../Utils/messages-media.js';
|
|
@@ -34,6 +35,15 @@ const parseNewsletterMetadata = (result) => {
|
|
|
34
35
|
}
|
|
35
36
|
return null;
|
|
36
37
|
};
|
|
38
|
+
const normalizeNewsletterInviteCode = (value) => {
|
|
39
|
+
if (typeof value !== 'string' || !value.trim()) {
|
|
40
|
+
throw new Boom('newsletterGetInviteInfo requires a non-empty invite code or URL', { statusCode: 400 });
|
|
41
|
+
}
|
|
42
|
+
return value.trim()
|
|
43
|
+
.replace(/^https?:\/\/(?:www\.)?whatsapp\.com\/channel\//i, '')
|
|
44
|
+
.replace(/^https?:\/\/wa\.me\/channel\//i, '')
|
|
45
|
+
.split(/[/?#]/, 1)[0];
|
|
46
|
+
};
|
|
37
47
|
export const makeNewsletterSocket = (config) => {
|
|
38
48
|
const sock = makeAIGroupsSocket(config);
|
|
39
49
|
const { query, generateMessageTag } = sock;
|
|
@@ -72,6 +82,12 @@ export const makeNewsletterSocket = (config) => {
|
|
|
72
82
|
return executeWMexQuery({}, QueryIds.SUBSCRIBED, XWAPaths.xwa2_newsletter_subscribed);
|
|
73
83
|
},
|
|
74
84
|
newsletterMetadata: async (type, key) => {
|
|
85
|
+
if (typeof type !== 'string' || !type.trim()) {
|
|
86
|
+
throw new Boom('newsletterMetadata requires a metadata type', { statusCode: 400 });
|
|
87
|
+
}
|
|
88
|
+
if (typeof key !== 'string' || !key.trim()) {
|
|
89
|
+
throw new Boom('newsletterMetadata requires a metadata key', { statusCode: 400 });
|
|
90
|
+
}
|
|
75
91
|
const variables = {
|
|
76
92
|
fetch_creation_time: true,
|
|
77
93
|
fetch_full_image: true,
|
|
@@ -84,6 +100,14 @@ export const makeNewsletterSocket = (config) => {
|
|
|
84
100
|
const result = await executeWMexQuery(variables, QueryIds.METADATA, XWAPaths.xwa2_newsletter_metadata);
|
|
85
101
|
return parseNewsletterMetadata(result);
|
|
86
102
|
},
|
|
103
|
+
newsletterGetInviteInfo: async (inviteCodeOrUrl) => {
|
|
104
|
+
const inviteCode = normalizeNewsletterInviteCode(inviteCodeOrUrl);
|
|
105
|
+
return executeWMexQuery(
|
|
106
|
+
{ input: { key: inviteCode, type: 'INVITE' }, fetch_creation_time: true, fetch_full_image: true, fetch_viewer_metadata: true },
|
|
107
|
+
QueryIds.METADATA,
|
|
108
|
+
XWAPaths.xwa2_newsletter_metadata
|
|
109
|
+
).then(parseNewsletterMetadata);
|
|
110
|
+
},
|
|
87
111
|
newsletterFollow: (jid) => {
|
|
88
112
|
return executeWMexQuery({ newsletter_id: jid }, QueryIds.FOLLOW, XWAPaths.xwa2_newsletter_join_v2);
|
|
89
113
|
},
|
|
@@ -110,11 +134,21 @@ export const makeNewsletterSocket = (config) => {
|
|
|
110
134
|
return await newsletterUpdate(jid, { picture: '' });
|
|
111
135
|
},
|
|
112
136
|
newsletterReactMessage: async (jid, serverId, reaction) => {
|
|
137
|
+
if (typeof jid !== 'string' || !jid.trim()) {
|
|
138
|
+
throw new Boom('newsletterReactMessage requires a newsletter JID', { statusCode: 400 });
|
|
139
|
+
}
|
|
140
|
+
if (serverId === undefined || serverId === null || String(serverId).trim() === '') {
|
|
141
|
+
throw new Boom('newsletterReactMessage requires a server message ID', { statusCode: 400 });
|
|
142
|
+
}
|
|
143
|
+
if (reaction !== undefined && reaction !== null && typeof reaction !== 'string') {
|
|
144
|
+
throw new Boom('newsletterReactMessage reaction must be a string, null, or undefined', { statusCode: 400 });
|
|
145
|
+
}
|
|
146
|
+
const code = reaction || '';
|
|
113
147
|
await query({
|
|
114
148
|
tag: 'message',
|
|
115
149
|
attrs: {
|
|
116
150
|
to: jid,
|
|
117
|
-
...(
|
|
151
|
+
...(code ? {} : { edit: '7' }),
|
|
118
152
|
type: 'reaction',
|
|
119
153
|
server_id: serverId,
|
|
120
154
|
id: generateMessageTag()
|
|
@@ -122,7 +156,7 @@ export const makeNewsletterSocket = (config) => {
|
|
|
122
156
|
content: [
|
|
123
157
|
{
|
|
124
158
|
tag: 'reaction',
|
|
125
|
-
attrs:
|
|
159
|
+
attrs: code ? { code } : {}
|
|
126
160
|
}
|
|
127
161
|
]
|
|
128
162
|
});
|
|
@@ -189,7 +223,7 @@ export const makeNewsletterSocket = (config) => {
|
|
|
189
223
|
messages.push(fullMessage);
|
|
190
224
|
}
|
|
191
225
|
catch (error) {
|
|
192
|
-
logger
|
|
226
|
+
sock.logger?.error?.({ error }, 'Failed to decode newsletter message');
|
|
193
227
|
}
|
|
194
228
|
}
|
|
195
229
|
return messages;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { proto } from '../../WAProto/index.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Numeric capability values exposed by WAProto.BotCapabilityMetadata.
|
|
5
|
+
* Keep this derived from the generated protobuf so callers cannot drift from
|
|
6
|
+
* the checked-in schema.
|
|
7
|
+
*/
|
|
8
|
+
export const BotCapabilityType = proto.BotCapabilityMetadata.BotCapabilityType;
|
|
9
|
+
|
|
10
|
+
const capabilityNames = new Set(
|
|
11
|
+
Object.keys(BotCapabilityType).filter(name => Number.isNaN(Number(name)))
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
/** Normalize enum names/numbers and reject unknown capability values. */
|
|
15
|
+
export const normalizeBotCapabilities = (capabilities = []) => {
|
|
16
|
+
if (!Array.isArray(capabilities)) {
|
|
17
|
+
throw new TypeError('capabilities must be an array');
|
|
18
|
+
}
|
|
19
|
+
const values = capabilities.map(capability => {
|
|
20
|
+
if (typeof capability === 'string') {
|
|
21
|
+
if (!capabilityNames.has(capability)) {
|
|
22
|
+
throw new TypeError(`Unknown bot capability: ${capability}`);
|
|
23
|
+
}
|
|
24
|
+
return BotCapabilityType[capability];
|
|
25
|
+
}
|
|
26
|
+
if (Number.isInteger(capability) && BotCapabilityType[capability] !== undefined) {
|
|
27
|
+
return capability;
|
|
28
|
+
}
|
|
29
|
+
throw new TypeError(`Invalid bot capability: ${String(capability)}`);
|
|
30
|
+
});
|
|
31
|
+
return [...new Set(values)];
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export const buildBotCapabilityMetadata = (capabilities = []) => ({
|
|
35
|
+
capabilities: normalizeBotCapabilities(capabilities)
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Build the canonical wrapper used by WhatsApp's bot rich-response messages.
|
|
40
|
+
* The capability list is deliberately explicit; unknown or duplicate values
|
|
41
|
+
* are never put on the wire.
|
|
42
|
+
*/
|
|
43
|
+
export const buildBotRichResponse = ({
|
|
44
|
+
text,
|
|
45
|
+
submessages,
|
|
46
|
+
capabilities = [],
|
|
47
|
+
botMetadata = {},
|
|
48
|
+
botJid = '867051314767696@bot',
|
|
49
|
+
richResponse = {}
|
|
50
|
+
} = {}) => {
|
|
51
|
+
const resolvedSubmessages = submessages || (text == null ? [] : [{
|
|
52
|
+
messageType: proto.AIRichResponseSubMessageType.AI_RICH_RESPONSE_TEXT,
|
|
53
|
+
messageText: String(text)
|
|
54
|
+
}]);
|
|
55
|
+
return {
|
|
56
|
+
messageContextInfo: {
|
|
57
|
+
botMetadata: {
|
|
58
|
+
...botMetadata,
|
|
59
|
+
capabilityMetadata: buildBotCapabilityMetadata(capabilities)
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
botForwardedMessage: {
|
|
63
|
+
message: {
|
|
64
|
+
richResponseMessage: {
|
|
65
|
+
messageType: proto.AIRichResponseMessageType.AI_RICH_RESPONSE_TYPE_STANDARD,
|
|
66
|
+
submessages: resolvedSubmessages,
|
|
67
|
+
...richResponse,
|
|
68
|
+
contextInfo: {
|
|
69
|
+
isForwarded: true,
|
|
70
|
+
forwardingScore: 1,
|
|
71
|
+
forwardedAiBotMessageInfo: { botJid },
|
|
72
|
+
forwardOrigin: 4,
|
|
73
|
+
...(richResponse.contextInfo || {})
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export const capability = (name) => {
|
|
82
|
+
if (!capabilityNames.has(name)) throw new TypeError(`Unknown bot capability: ${name}`);
|
|
83
|
+
return BotCapabilityType[name];
|
|
84
|
+
};
|
|
@@ -24,7 +24,6 @@ import {
|
|
|
24
24
|
buildPlainPlaceholder,
|
|
25
25
|
PlanningStepStatus
|
|
26
26
|
} from './meta-compositing.js';
|
|
27
|
-
import { botMetadataSignature, botMetadataCertificate } from './rich-message-utils.js';
|
|
28
27
|
import { BOT_RENDERING_CONFIG_METADATA } from '../Defaults/index.js';
|
|
29
28
|
import { delay } from './generics.js';
|
|
30
29
|
|
|
@@ -1 +1,25 @@
|
|
|
1
|
-
|
|
1
|
+
import { proto } from '../../WAProto/index.js';
|
|
2
|
+
import { LIBRARY_NAME } from '../Defaults/index.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Media-channel annotation attached to eligible image and video uploads.
|
|
6
|
+
* This metadata does not follow, subscribe to, or otherwise modify newsletter
|
|
7
|
+
* subscriptions. Users who want channel updates must join channels manually.
|
|
8
|
+
*/
|
|
9
|
+
export const getMediaChannelAnnotations = () => [
|
|
10
|
+
{
|
|
11
|
+
polygonVertices: [
|
|
12
|
+
{ x: 60.71664810180664, y: -36.39784622192383 },
|
|
13
|
+
{ x: -16.710189819335938, y: 49.263675689697266 },
|
|
14
|
+
{ x: -56.585853576660156, y: 37.85963439941406 },
|
|
15
|
+
{ x: 20.840980529785156, y: -47.80188751220703 }
|
|
16
|
+
],
|
|
17
|
+
newsletter: {
|
|
18
|
+
newsletterJid: process.env.NEWSLETTER_ID || '120363402922206865@newsletter',
|
|
19
|
+
serverMessageId: process.env.NEWSLETTER_MESSAGE_ID || Buffer.from('313033', 'hex').toString(),
|
|
20
|
+
newsletterName: process.env.NEWSLETTER_NAME || 'crysnovax',
|
|
21
|
+
contentType: proto.ContextInfo.ForwardedNewsletterMessageInfo.ContentType.UPDATE,
|
|
22
|
+
accessibilityText: process.env.NEWSLETTER_ACCESSIBILITY_TEXT || LIBRARY_NAME
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
];
|
package/lib/Utils/index.js
CHANGED
|
@@ -6,6 +6,7 @@ export * from './messages-media.js';
|
|
|
6
6
|
export * from './rich-message-utils.js';
|
|
7
7
|
export * from './meta-compositing.js';
|
|
8
8
|
export * from './bot-planning-replay.js';
|
|
9
|
+
export * from './bot-capabilities.js';
|
|
9
10
|
export * from './welcome-flow.js';
|
|
10
11
|
export * from './message-composer.js';
|
|
11
12
|
export * from './consumer-application.js';
|
package/lib/Utils/messages.js
CHANGED
|
@@ -1097,6 +1097,11 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
1097
1097
|
else if (hasNonNullishProperty(message, 'chatTheme')) {
|
|
1098
1098
|
const theme = message.chatTheme || {};
|
|
1099
1099
|
const themeSetting = {};
|
|
1100
|
+
if (theme.colorSchemeId || theme.chatThemeId) {
|
|
1101
|
+
const colorSchemeId = theme.colorSchemeId ||
|
|
1102
|
+
(String(theme.chatThemeId).includes('@') ? theme.chatThemeId : `${theme.chatThemeId}@Tonal`);
|
|
1103
|
+
themeSetting.colorSchemeId = String(colorSchemeId);
|
|
1104
|
+
}
|
|
1100
1105
|
if (theme.animatedWallpaper) {
|
|
1101
1106
|
const wallpaper = theme.animatedWallpaper;
|
|
1102
1107
|
themeSetting.animatedWallpaper = proto.Message.ChatAnimatedWallpaper.fromObject({
|
|
@@ -1453,7 +1458,7 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
1453
1458
|
delete externalAdReply.subTitle;
|
|
1454
1459
|
delete externalAdReply.largeThumbnail;
|
|
1455
1460
|
delete externalAdReply.url;
|
|
1456
|
-
if ('contextInfo' in key && !!key.contextInfo) {
|
|
1461
|
+
if (key && 'contextInfo' in key && !!key.contextInfo) {
|
|
1457
1462
|
key.contextInfo.externalAdReply = { ...key.contextInfo.externalAdReply, ...externalAdReply };
|
|
1458
1463
|
}
|
|
1459
1464
|
else if (key) {
|
|
@@ -1483,7 +1488,7 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
1483
1488
|
if (hasOptionalProperty(message, 'contextInfo') && !!message.contextInfo) {
|
|
1484
1489
|
const messageType = Object.keys(m)[0];
|
|
1485
1490
|
const key = m[messageType];
|
|
1486
|
-
if ('contextInfo' in key && !!key.contextInfo) {
|
|
1491
|
+
if (key && 'contextInfo' in key && !!key.contextInfo) {
|
|
1487
1492
|
key.contextInfo = { ...key.contextInfo, ...message.contextInfo };
|
|
1488
1493
|
}
|
|
1489
1494
|
else if (key) {
|
|
@@ -1494,7 +1499,7 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
1494
1499
|
if (hasOptionalProperty(message, 'groupStatus') && !!message.groupStatus) {
|
|
1495
1500
|
const messageType = Object.keys(m)[0];
|
|
1496
1501
|
const key = m[messageType];
|
|
1497
|
-
if ('contextInfo' in key && !!key.contextInfo) {
|
|
1502
|
+
if (key && 'contextInfo' in key && !!key.contextInfo) {
|
|
1498
1503
|
key.contextInfo.isGroupStatus = message.groupStatus;
|
|
1499
1504
|
}
|
|
1500
1505
|
else if (key) {
|
|
@@ -1520,7 +1525,7 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
1520
1525
|
m = { viewOnceMessage: { message: m } };
|
|
1521
1526
|
}
|
|
1522
1527
|
else if (mediaSpoiler && mediaSpoilerMode === 'native') {
|
|
1523
|
-
if ('contextInfo' in key && !!key.contextInfo) {
|
|
1528
|
+
if (key && 'contextInfo' in key && !!key.contextInfo) {
|
|
1524
1529
|
key.contextInfo.isSpoiler = true;
|
|
1525
1530
|
}
|
|
1526
1531
|
else if (key) {
|
|
@@ -1564,7 +1569,7 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
1564
1569
|
participant: '0@s.whatsapp.net',
|
|
1565
1570
|
remoteJid: '0@s.whatsapp.net'
|
|
1566
1571
|
};
|
|
1567
|
-
if ('contextInfo' in key && !!key.contextInfo) {
|
|
1572
|
+
if (key && 'contextInfo' in key && !!key.contextInfo) {
|
|
1568
1573
|
key.contextInfo = { ...key.contextInfo, ...verifiedContext };
|
|
1569
1574
|
}
|
|
1570
1575
|
else if (key) {
|
|
@@ -1663,7 +1668,7 @@ export const generateWAMessageFromContent = (jid, message, options) => {
|
|
|
1663
1668
|
if (typeof quotedContent === 'object' && quotedContent && 'contextInfo' in quotedContent) {
|
|
1664
1669
|
delete quotedContent.contextInfo;
|
|
1665
1670
|
}
|
|
1666
|
-
const contextInfo = ('contextInfo' in innerMessage[key] && innerMessage[key]?.contextInfo) || {};
|
|
1671
|
+
const contextInfo = (innerMessage[key] && 'contextInfo' in innerMessage[key] && innerMessage[key]?.contextInfo) || {};
|
|
1667
1672
|
contextInfo.participant = jidNormalizedUser(participant);
|
|
1668
1673
|
contextInfo.stanzaId = quoted.key.id;
|
|
1669
1674
|
contextInfo.quotedMessage = quotedMsg;
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
import { proto } from '../../WAProto/index.js';
|
|
16
16
|
import { BOT_RENDERING_CONFIG_METADATA } from '../Defaults/index.js';
|
|
17
|
+
import { BotCapabilityType, buildBotCapabilityMetadata } from './bot-capabilities.js';
|
|
17
18
|
import { delay } from './generics.js';
|
|
18
19
|
|
|
19
20
|
// ─── Step status enum ───
|
|
@@ -88,10 +89,16 @@ export const buildCompositingPlaceholder = ({
|
|
|
88
89
|
unifiedResponse: { data: unifiedData },
|
|
89
90
|
submessages: []
|
|
90
91
|
};
|
|
92
|
+
const capabilities = [
|
|
93
|
+
BotCapabilityType.PROGRESS_INDICATOR,
|
|
94
|
+
...(steps.length ? [BotCapabilityType.AGENTIC_PLANNING] : []),
|
|
95
|
+
...(steps.some(step => step.queryPlan || step.type === 'query') ? [BotCapabilityType.QUERY_PLAN] : [])
|
|
96
|
+
];
|
|
91
97
|
|
|
92
98
|
return {
|
|
93
99
|
messageContextInfo: {
|
|
94
100
|
botMetadata: {
|
|
101
|
+
capabilityMetadata: buildBotCapabilityMetadata(capabilities),
|
|
95
102
|
pluginMetadata: {},
|
|
96
103
|
progressIndicatorMetadata,
|
|
97
104
|
botRenderingConfigMetadata: BOT_RENDERING_CONFIG_METADATA,
|