@peopl-health/nexus 1.7.7 → 1.7.9
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/lib/adapters/TwilioProvider.js +5 -0
- package/lib/config/mongoAuthConfig.js +3 -3
- package/lib/controllers/assistantController.js +3 -3
- package/lib/controllers/messageController.js +12 -3
- package/lib/core/NexusMessaging.js +15 -6
- package/lib/helpers/assistantHelper.js +9 -3
- package/lib/helpers/baileysHelper.js +6 -1
- package/lib/index.d.ts +14 -0
- package/lib/index.js +9 -1
- package/lib/services/assistantService.js +1 -1
- package/lib/services/preprocessingHooks.js +28 -0
- package/lib/storage/MongoStorage.js +1 -1
- package/package.json +5 -5
|
@@ -218,6 +218,11 @@ class TwilioProvider extends MessageProvider {
|
|
|
218
218
|
// Convert Mongoose document to plain object if needed
|
|
219
219
|
const payload = scheduledMessage.toObject ? scheduledMessage.toObject() : { ...scheduledMessage };
|
|
220
220
|
delete payload.__nexusSend;
|
|
221
|
+
|
|
222
|
+
// Map message field to body for consistency (scheduled messages use 'message' field)
|
|
223
|
+
if (payload.message && !payload.body) {
|
|
224
|
+
payload.body = payload.message;
|
|
225
|
+
}
|
|
221
226
|
console.log('[TwilioProvider] Timer fired', {
|
|
222
227
|
code: payload.code,
|
|
223
228
|
hasMessage: Boolean(payload.message || payload.body),
|
|
@@ -100,7 +100,7 @@ async function useMongoDBAuthState(uri, dbName, sessionId) {
|
|
|
100
100
|
}
|
|
101
101
|
};
|
|
102
102
|
|
|
103
|
-
const creds = (await readData('creds')) ||
|
|
103
|
+
const creds = (await readData('creds')) || await initAuthCreds();
|
|
104
104
|
|
|
105
105
|
return {
|
|
106
106
|
state: {
|
|
@@ -110,8 +110,8 @@ async function useMongoDBAuthState(uri, dbName, sessionId) {
|
|
|
110
110
|
const data = {};
|
|
111
111
|
await Promise.all(ids.map(async (id) => {
|
|
112
112
|
let value = await readData(`${type}-${id}`);
|
|
113
|
-
if (type === 'app-state-sync-key') {
|
|
114
|
-
value = proto.Message.AppStateSyncKeyData.fromObject(
|
|
113
|
+
if (type === 'app-state-sync-key' && value) {
|
|
114
|
+
value = proto.Message.AppStateSyncKeyData.fromObject(value);
|
|
115
115
|
}
|
|
116
116
|
data[id] = value;
|
|
117
117
|
}));
|
|
@@ -25,7 +25,7 @@ const addInsAssistantController = async (req, res) => {
|
|
|
25
25
|
|
|
26
26
|
try {
|
|
27
27
|
const ans = await addInsAssistant(code, instruction);
|
|
28
|
-
if (ans) await sendMessage({code,
|
|
28
|
+
if (ans) await sendMessage({code, body: ans, fileType: 'text'});
|
|
29
29
|
return res.status(200).send({ message: 'Add instruction to the assistant' });
|
|
30
30
|
} catch (error) {
|
|
31
31
|
console.log(error);
|
|
@@ -38,7 +38,7 @@ const addMsgAssistantController = async (req, res) => {
|
|
|
38
38
|
|
|
39
39
|
try {
|
|
40
40
|
const ans = await addMsgAssistant(code, messages, reply);
|
|
41
|
-
if (ans) await sendMessage({code,
|
|
41
|
+
if (ans) await sendMessage({code, body: ans, fileType: 'text'});
|
|
42
42
|
return res.status(200).send({ message: 'Add message to the assistant' });
|
|
43
43
|
} catch (error) {
|
|
44
44
|
console.log(error);
|
|
@@ -66,7 +66,7 @@ const createAssistantController = async (req, res) => {
|
|
|
66
66
|
console.log('messages', messages);
|
|
67
67
|
for (const message of messages) {
|
|
68
68
|
console.log('message', message);
|
|
69
|
-
await sendMessage({code, message, fileType: 'text'});
|
|
69
|
+
await sendMessage({code, body: message, fileType: 'text'});
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
res.status(200).send({ message: 'Create the assistant' });
|
|
@@ -120,7 +120,10 @@ const sendMessageController = async (req, res) => {
|
|
|
120
120
|
const scheduledRecord = await persistScheduledMessage(ScheduledMessageModel, payload);
|
|
121
121
|
const result = hasScheduler
|
|
122
122
|
? await dependencies.sendScheduledMessage(scheduledRecord)
|
|
123
|
-
: await dependencies.sendMessage(
|
|
123
|
+
: await dependencies.sendMessage({
|
|
124
|
+
...payload,
|
|
125
|
+
body: payload.message
|
|
126
|
+
});
|
|
124
127
|
|
|
125
128
|
res.status(200).json({
|
|
126
129
|
status: 200,
|
|
@@ -185,7 +188,10 @@ const sendBulkMessageController = async (req, res) => {
|
|
|
185
188
|
const savedMessage = await persistScheduledMessage(ScheduledMessageModel, payload);
|
|
186
189
|
const result = hasScheduler
|
|
187
190
|
? await dependencies.sendScheduledMessage(savedMessage)
|
|
188
|
-
: await dependencies.sendMessage(
|
|
191
|
+
: await dependencies.sendMessage({
|
|
192
|
+
...payload,
|
|
193
|
+
body: payload.message
|
|
194
|
+
});
|
|
189
195
|
return { result, scheduled: savedMessage };
|
|
190
196
|
})
|
|
191
197
|
);
|
|
@@ -289,7 +295,10 @@ const sendBulkMessageAirtableController = async (req, res) => {
|
|
|
289
295
|
const savedMessage = await persistScheduledMessage(ScheduledMessageModel, payload);
|
|
290
296
|
const result = hasScheduler
|
|
291
297
|
? await dependencies.sendScheduledMessage(savedMessage)
|
|
292
|
-
: await dependencies.sendMessage(
|
|
298
|
+
: await dependencies.sendMessage({
|
|
299
|
+
...payload,
|
|
300
|
+
body: payload.message
|
|
301
|
+
});
|
|
293
302
|
return { result, scheduled: savedMessage };
|
|
294
303
|
})
|
|
295
304
|
);
|
|
@@ -2,6 +2,7 @@ const { airtable, getBase } = require('../config/airtableConfig');
|
|
|
2
2
|
const { replyAssistant } = require('../services/assistantService');
|
|
3
3
|
const { createProvider } = require('../adapters/registry');
|
|
4
4
|
const runtimeConfig = require('../config/runtimeConfig');
|
|
5
|
+
const { hasPreprocessingHandler, invokePreprocessingHandler } = require('../services/preprocessingHooks');
|
|
5
6
|
|
|
6
7
|
const mongoose = require('mongoose');
|
|
7
8
|
const OpenAI = require('openai');
|
|
@@ -324,7 +325,16 @@ class NexusMessaging {
|
|
|
324
325
|
}
|
|
325
326
|
|
|
326
327
|
const chatId = messageData.from || messageData.From;
|
|
327
|
-
|
|
328
|
+
|
|
329
|
+
if (chatId && hasPreprocessingHandler()) {
|
|
330
|
+
const stop = await invokePreprocessingHandler({
|
|
331
|
+
code: chatId,
|
|
332
|
+
context: 'incomingMessage',
|
|
333
|
+
message: messageData
|
|
334
|
+
});
|
|
335
|
+
if (stop) return;
|
|
336
|
+
}
|
|
337
|
+
|
|
328
338
|
// Handle immediate response messages (interactive, flows, etc.)
|
|
329
339
|
if (messageData.interactive) {
|
|
330
340
|
return await this.handleInteractive(messageData);
|
|
@@ -624,11 +634,10 @@ class NexusMessaging {
|
|
|
624
634
|
|
|
625
635
|
// Get assistant response
|
|
626
636
|
const botResponse = await replyAssistant(chatId);
|
|
627
|
-
if (botResponse
|
|
628
|
-
await this.
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
type: 'text',
|
|
637
|
+
if (botResponse) {
|
|
638
|
+
await this.sendMessage({
|
|
639
|
+
code: chatId,
|
|
640
|
+
message: botResponse,
|
|
632
641
|
processed: true
|
|
633
642
|
});
|
|
634
643
|
}
|
|
@@ -31,12 +31,18 @@ async function checkRunStatus(assistant, thread_id, run_id, retryCount = 0, maxR
|
|
|
31
31
|
return true;
|
|
32
32
|
} else if (run.status === 'requires_action') {
|
|
33
33
|
console.log('requires_action');
|
|
34
|
-
if (retryCount
|
|
34
|
+
if (retryCount >= maxRetries) {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
await assistant.handleRequiresAction(run);
|
|
35
38
|
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
36
|
-
return checkRunStatus(assistant, thread_id, run_id,
|
|
39
|
+
return checkRunStatus(assistant, thread_id, run_id, retryCount + 1, maxRetries);
|
|
37
40
|
} else if (run.status !== 'completed') {
|
|
41
|
+
if (retryCount >= maxRetries) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
38
44
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
39
|
-
return checkRunStatus(assistant, thread_id, run_id);
|
|
45
|
+
return checkRunStatus(assistant, thread_id, run_id, retryCount + 1, maxRetries);
|
|
40
46
|
} else {
|
|
41
47
|
console.log('Run completed.');
|
|
42
48
|
return true;
|
|
@@ -6,7 +6,12 @@ const { downloadMediaMessage } = require('baileys');
|
|
|
6
6
|
async function processMessage(message, messageType) {
|
|
7
7
|
try {
|
|
8
8
|
const { content, reply } = extractMessageContent(message, messageType);
|
|
9
|
-
if (content
|
|
9
|
+
if (typeof content === 'string' && content.trim().length === 0) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
if (content == null) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
10
15
|
|
|
11
16
|
const values = getMessageValues(message, content, reply, false);
|
|
12
17
|
await insertMessage(values);
|
package/lib/index.d.ts
CHANGED
|
@@ -130,6 +130,13 @@ declare module '@peopl-health/nexus' {
|
|
|
130
130
|
setup?: (this: BaseAssistant, context: { assistantId: string; thread?: any; options?: any }) => void;
|
|
131
131
|
}
|
|
132
132
|
|
|
133
|
+
export interface IncomingPreprocessingPayload {
|
|
134
|
+
code: string;
|
|
135
|
+
context?: string;
|
|
136
|
+
message: MessageData;
|
|
137
|
+
[key: string]: any;
|
|
138
|
+
}
|
|
139
|
+
|
|
133
140
|
export class BaseAssistant {
|
|
134
141
|
constructor(options?: {
|
|
135
142
|
assistantId?: string;
|
|
@@ -176,6 +183,13 @@ declare module '@peopl-health/nexus' {
|
|
|
176
183
|
export function configureAssistantsLLM(client: any): void;
|
|
177
184
|
export function overrideGetAssistantById(resolver: (assistantId: string, thread?: any) => any): void;
|
|
178
185
|
export function configureAssistants(config: any): void;
|
|
186
|
+
export function setPreprocessingHandler(
|
|
187
|
+
handler: (payload: IncomingPreprocessingPayload) => any | Promise<any>
|
|
188
|
+
): void;
|
|
189
|
+
export function hasPreprocessingHandler(): boolean;
|
|
190
|
+
export function invokePreprocessingHandler(
|
|
191
|
+
payload: IncomingPreprocessingPayload
|
|
192
|
+
): Promise<boolean>;
|
|
179
193
|
|
|
180
194
|
export class TwilioProvider extends MessageProvider {
|
|
181
195
|
constructor(config: TwilioConfig);
|
package/lib/index.js
CHANGED
|
@@ -17,6 +17,11 @@ const {
|
|
|
17
17
|
const { TwilioProvider } = require('./adapters/TwilioProvider');
|
|
18
18
|
const { BaileysProvider } = require('./adapters/BaileysProvider');
|
|
19
19
|
const { BaseAssistant: CoreBaseAssistant } = require('./assistants/BaseAssistant');
|
|
20
|
+
const {
|
|
21
|
+
setPreprocessingHandler,
|
|
22
|
+
hasPreprocessingHandler,
|
|
23
|
+
invokePreprocessingHandler
|
|
24
|
+
} = require('./services/preprocessingHooks');
|
|
20
25
|
|
|
21
26
|
/**
|
|
22
27
|
* Main Nexus class that orchestrates all components
|
|
@@ -230,7 +235,7 @@ class Nexus {
|
|
|
230
235
|
* Send a scheduled message
|
|
231
236
|
* @param {Object} scheduledMessage - Scheduled message data
|
|
232
237
|
* @param {string} scheduledMessage.code - Recipient phone number
|
|
233
|
-
* @param {string} scheduledMessage.
|
|
238
|
+
* @param {string} scheduledMessage.body - Message text
|
|
234
239
|
* @param {Date|string} scheduledMessage.sendAt - When to send the message
|
|
235
240
|
* @returns {Promise<Object>} Scheduled message result
|
|
236
241
|
*/
|
|
@@ -332,6 +337,9 @@ module.exports = {
|
|
|
332
337
|
configureAssistantsLLM,
|
|
333
338
|
overrideGetAssistantById,
|
|
334
339
|
configureAssistants: setAssistantsConfig,
|
|
340
|
+
setPreprocessingHandler,
|
|
341
|
+
hasPreprocessingHandler,
|
|
342
|
+
invokePreprocessingHandler,
|
|
335
343
|
routes,
|
|
336
344
|
setupDefaultRoutes: routes.setupDefaultRoutes,
|
|
337
345
|
createRouter: routes.createRouter,
|
|
@@ -339,7 +339,7 @@ const getThread = async (code, message = null) => {
|
|
|
339
339
|
|
|
340
340
|
const getThreadInfo = async (code) => {
|
|
341
341
|
try {
|
|
342
|
-
let thread = await Thread.findOne({ code: code
|
|
342
|
+
let thread = await Thread.findOne({ code: code });
|
|
343
343
|
return thread;
|
|
344
344
|
} catch (error) {
|
|
345
345
|
console.log(error);
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
let preprocessingHandler = null;
|
|
2
|
+
|
|
3
|
+
const setPreprocessingHandler = (handler) => {
|
|
4
|
+
if (typeof handler === 'function') {
|
|
5
|
+
preprocessingHandler = handler;
|
|
6
|
+
} else {
|
|
7
|
+
preprocessingHandler = null;
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const hasPreprocessingHandler = () => typeof preprocessingHandler === 'function';
|
|
12
|
+
|
|
13
|
+
const invokePreprocessingHandler = async (payload) => {
|
|
14
|
+
if (!hasPreprocessingHandler()) return false;
|
|
15
|
+
try {
|
|
16
|
+
const result = await preprocessingHandler(payload);
|
|
17
|
+
return Boolean(result);
|
|
18
|
+
} catch (error) {
|
|
19
|
+
console.warn('[PreprocessingHooks] Handler threw an error:', error?.message || error);
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
module.exports = {
|
|
25
|
+
setPreprocessingHandler,
|
|
26
|
+
hasPreprocessingHandler,
|
|
27
|
+
invokePreprocessingHandler
|
|
28
|
+
};
|
|
@@ -137,7 +137,7 @@ class MongoStorage {
|
|
|
137
137
|
fileUrl: undefined,
|
|
138
138
|
fileType: mediaPayload.mediaType || messageData.fileType,
|
|
139
139
|
isMedia: true,
|
|
140
|
-
|
|
140
|
+
body: messageData.body || rawMessage.Body || primary.caption || '',
|
|
141
141
|
caption: primary.caption || messageData.caption
|
|
142
142
|
};
|
|
143
143
|
} catch (error) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@peopl-health/nexus",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.9",
|
|
4
4
|
"description": "Core messaging and assistant library for WhatsApp communication platforms",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"whatsapp",
|
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
"mongoose": "^7.5.0",
|
|
79
79
|
"multer": "1.4.5-lts.1",
|
|
80
80
|
"pdf-lib": "1.17.1",
|
|
81
|
-
"pino": "
|
|
81
|
+
"pino": "10.0.0",
|
|
82
82
|
"pino-pretty": "^10.2.0",
|
|
83
83
|
"uuid": "^9.0.0"
|
|
84
84
|
},
|
|
@@ -90,11 +90,11 @@
|
|
|
90
90
|
"typescript": "^5.1.6"
|
|
91
91
|
},
|
|
92
92
|
"peerDependencies": {
|
|
93
|
+
"@anthropic-ai/sdk": "^0.32.0",
|
|
93
94
|
"baileys": "^6.4.0",
|
|
94
95
|
"express": "4.21.2",
|
|
95
96
|
"openai": "^4.0.0",
|
|
96
|
-
"twilio": "5.6.0"
|
|
97
|
-
"@anthropic-ai/sdk": "^0.32.0"
|
|
97
|
+
"twilio": "5.6.0"
|
|
98
98
|
},
|
|
99
99
|
"engines": {
|
|
100
100
|
"node": ">=20.0.0"
|
|
@@ -102,4 +102,4 @@
|
|
|
102
102
|
"publishConfig": {
|
|
103
103
|
"access": "public"
|
|
104
104
|
}
|
|
105
|
-
}
|
|
105
|
+
}
|