@peopl-health/nexus 2.5.3 → 2.5.5

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.
@@ -28,9 +28,9 @@ const addInsAssistantController = async (req, res) => {
28
28
  const variant = process.env.VARIANT || 'assistants';
29
29
  const role = variant === 'responses' ? 'developer' : 'user';
30
30
 
31
- const ans = await addInsAssistant(code, instruction, role);
32
- if (ans) await sendMessage({code, body: ans, fileType: 'text', origin: 'assistant'});
33
- return res.status(200).send({ message: 'Add instruction to the assistant' });
31
+ const assistantReply = await addInsAssistant(code, instruction, role);
32
+ if (assistantReply) await sendMessage({code, body: assistantReply, fileType: 'text', origin: 'assistant'});
33
+ return res.status(200).send({ message: 'Instruction added to assistant', success: true });
34
34
  } catch (error) {
35
35
  logger.error('[addInsAssistantController] Error', { error: error.message, code });
36
36
  res.status(500).send({ message: 'Failed to add instruction to assistant', error });
@@ -41,9 +41,9 @@ const addMsgAssistantController = async (req, res) => {
41
41
  const { code, messages, role = 'user', reply = false } = req.body;
42
42
 
43
43
  try {
44
- const ans = await addMsgAssistant(code, messages, role, reply);
45
- if (ans) await sendMessage({code, body: ans, fileType: 'text', origin: 'assistant'});
46
- return res.status(200).send({ message: 'Add message to the assistant' });
44
+ const assistantReply = await addMsgAssistant(code, messages, role, reply);
45
+ if (assistantReply) await sendMessage({code, body: assistantReply, fileType: 'text', origin: 'assistant'});
46
+ return res.status(200).send({ message: 'Message added to assistant', success: true });
47
47
  } catch (error) {
48
48
  logger.error('[addMsgAssistantController] Error', { error: error.message, code, role });
49
49
  res.status(500).send({ message: 'Failed to add message assistant', error });
@@ -349,10 +349,42 @@ const getLastInteractionController = async (req, res) => {
349
349
  }
350
350
  };
351
351
 
352
+ const checkScheduledMessageStatusController = async (req, res) => {
353
+ const { contentSid, code } = req.query;
354
+ if (!contentSid || !code) return res.status(400).send({ message: 'contentSid and code are required' });
355
+ if (!ensureDependency(res, dependencies.ScheduledMessage, 'ScheduledMessage model not configured.')) return;
356
+
357
+ try {
358
+ const msg = await dependencies.ScheduledMessage.findOne({ contentSid, code: normalizeCode(code) });
359
+ if (!msg) return res.status(404).send({ message: 'ScheduledMessage not found' });
360
+ return res.status(200).send({ message: 'ScheduledMessage status retrieved successfully.', sent: msg?.status === 'sent', status: msg?.status || null });
361
+ } catch (error) {
362
+ logger.error('Error checking scheduled message status:', error);
363
+ return res.status(500).send({ message: 'Failed to check scheduled message status', error });
364
+ }
365
+ };
366
+
367
+ const checkMessageStatusController = async (req, res) => {
368
+ const { contentSid, code } = req.query;
369
+ if (!contentSid || !code) return res.status(400).send({ message: 'contentSid and code are required' });
370
+
371
+ try {
372
+ const msg = await Message.findOne({ content_sid: contentSid, numero: normalizeCode(code) });
373
+ if (!msg) return res.status(404).send({ message: 'Message not found' });
374
+ const sent = msg?.statusInfo?.status === 'sent' || msg?.statusInfo?.status === 'delivered' || msg?.statusInfo?.status === 'read';
375
+ return res.status(200).send({ message: 'Message status retrieved successfully.', sent, status: msg?.statusInfo?.status || null });
376
+ } catch (error) {
377
+ logger.error('Error checking message status:', error);
378
+ return res.status(500).send({ message: 'Failed to check message status', error });
379
+ }
380
+ };
381
+
352
382
  module.exports = {
353
383
  sendMessageController,
354
384
  sendBulkMessageController,
355
385
  sendBulkMessageAirtableController,
356
386
  getLastInteractionController,
387
+ checkScheduledMessageStatusController,
388
+ checkMessageStatusController,
357
389
  configureMessageController
358
390
  };
package/lib/index.js CHANGED
@@ -14,7 +14,7 @@ const {
14
14
  registerAssistant,
15
15
  overrideGetAssistantById,
16
16
  configureAssistants: setAssistantsConfig
17
- } = require('./services/assistantService');
17
+ } = require('./services/assistantResolver');
18
18
  const { TwilioProvider } = require('./adapters/TwilioProvider');
19
19
  const { BaileysProvider } = require('./adapters/BaileysProvider');
20
20
  const { BaseAssistant } = require('./assistants/BaseAssistant');
@@ -36,6 +36,8 @@ const messageRouteDefinitions = {
36
36
  'POST /send-bulk': 'sendBulkMessageController',
37
37
  'POST /send-bulk-airtable': 'sendBulkMessageAirtableController',
38
38
  'GET /last': 'getLastInteractionController',
39
+ 'GET /scheduled-status': 'checkScheduledMessageStatusController',
40
+ 'GET /status': 'checkMessageStatusController',
39
41
  'POST /quality': 'addQualityVoteController',
40
42
  'GET /quality/:message_id': 'getQualityVotesByMessageController',
41
43
  'GET /quality/:message_id/voter/:voter_username': 'getQualityVoteByMessageAndVoterController',
@@ -130,6 +132,8 @@ const builtInControllers = {
130
132
  sendBulkMessageController: messageController.sendBulkMessageController,
131
133
  sendBulkMessageAirtableController: messageController.sendBulkMessageAirtableController,
132
134
  getLastInteractionController: messageController.getLastInteractionController,
135
+ checkScheduledMessageStatusController: messageController.checkScheduledMessageStatusController,
136
+ checkMessageStatusController: messageController.checkMessageStatusController,
133
137
  addQualityVoteController: qualityMessageController.addQualityVoteController,
134
138
  getQualityVotesByMessageController: qualityMessageController.getQualityVotesByMessageController,
135
139
  getQualityVoteByMessageAndVoterController: qualityMessageController.getQualityVoteByMessageAndVoterController,
@@ -0,0 +1,105 @@
1
+ const llmConfig = require('../config/llmConfig');
2
+ const { BaseAssistant } = require('../assistants/BaseAssistant');
3
+
4
+ let assistantConfig = null;
5
+ let assistantRegistry = {};
6
+ let customGetAssistantById = null;
7
+
8
+ const configureAssistants = (config) => {
9
+ if (!config) {
10
+ throw new Error('Assistant configuration is required');
11
+ }
12
+ assistantConfig = config;
13
+ };
14
+
15
+ const registerAssistant = (assistantId, definition) => {
16
+ if (!assistantId || typeof assistantId !== 'string') {
17
+ throw new Error('registerAssistant requires a string assistantId');
18
+ }
19
+
20
+ if (typeof definition === 'function') {
21
+ assistantRegistry[assistantId] = definition;
22
+ return definition;
23
+ }
24
+
25
+ if (definition && typeof definition === 'object') {
26
+ const {
27
+ extends: ParentClass = BaseAssistant,
28
+ create,
29
+ tools = [],
30
+ setup
31
+ } = definition;
32
+
33
+ class ConfiguredAssistant extends ParentClass {
34
+ constructor(options = {}) {
35
+ const provider = options.provider || llmConfig.getOpenAIProvider({ instantiate: false });
36
+ const sharedClient = options.client
37
+ || provider?.getClient?.()
38
+ || llmConfig.openaiClient
39
+ || null;
40
+
41
+ super({
42
+ ...options,
43
+ assistantId,
44
+ client: sharedClient,
45
+ provider,
46
+ tools: [...tools, ...(options.tools || [])]
47
+ });
48
+
49
+ if (typeof setup === 'function') {
50
+ setup.call(this, {
51
+ assistantId,
52
+ thread: this.thread,
53
+ options
54
+ });
55
+ }
56
+ }
57
+ }
58
+
59
+ if (typeof create === 'function') {
60
+ ConfiguredAssistant.prototype.create = async function(code, context) {
61
+ return await create.call(this, code, context);
62
+ };
63
+ }
64
+
65
+ assistantRegistry[assistantId] = ConfiguredAssistant;
66
+ return ConfiguredAssistant;
67
+ }
68
+
69
+ throw new Error('registerAssistant expects a class/function or configuration object');
70
+ };
71
+
72
+ const overrideGetAssistantById = (resolverFn) => {
73
+ if (typeof resolverFn === 'function') {
74
+ customGetAssistantById = resolverFn;
75
+ }
76
+ };
77
+
78
+ const getAssistantById = (assistant_id, thread) => {
79
+ if (customGetAssistantById) {
80
+ return customGetAssistantById(assistant_id, thread);
81
+ }
82
+
83
+ if (assistantRegistry[assistant_id]) {
84
+ const AssistantClass = assistantRegistry[assistant_id];
85
+ return new AssistantClass({ thread });
86
+ }
87
+
88
+ if (assistantConfig && assistantConfig[assistant_id]) {
89
+ const config = assistantConfig[assistant_id];
90
+ return new BaseAssistant({
91
+ ...config,
92
+ assistantId: assistant_id,
93
+ thread
94
+ });
95
+ }
96
+
97
+ throw new Error(`Assistant with ID "${assistant_id}" not found`);
98
+ };
99
+
100
+ module.exports = {
101
+ getAssistantById,
102
+ configureAssistants,
103
+ registerAssistant,
104
+ overrideGetAssistantById
105
+ };
@@ -1,6 +1,5 @@
1
1
  const { withTracing } = require('../utils/tracingDecorator.js');
2
- const llmConfig = require('../config/llmConfig');
3
- const { BaseAssistant } = require('../assistants/BaseAssistant');
2
+ const { runAssistantAndWait } = require('../helpers/assistantHelper');
4
3
  const {
5
4
  createAssistantCore,
6
5
  addMsgAssistantCore,
@@ -8,105 +7,15 @@ const {
8
7
  replyAssistantCore,
9
8
  switchAssistantCore
10
9
  } = require('./assistantServiceCore');
11
-
12
- let assistantConfig = null;
13
- let assistantRegistry = {};
14
- let customGetAssistantById = null;
15
-
16
- const configureAssistants = (config) => {
17
- if (!config) {
18
- throw new Error('Assistant configuration is required');
19
- }
20
- assistantConfig = config;
21
- };
22
-
23
- const registerAssistant = (assistantId, definition) => {
24
- if (!assistantId || typeof assistantId !== 'string') {
25
- throw new Error('registerAssistant requires a string assistantId');
26
- }
27
-
28
- if (typeof definition === 'function') {
29
- assistantRegistry[assistantId] = definition;
30
- return definition;
31
- }
32
-
33
- if (definition && typeof definition === 'object') {
34
- const {
35
- extends: ParentClass = BaseAssistant,
36
- create,
37
- tools = [],
38
- setup
39
- } = definition;
40
-
41
- class ConfiguredAssistant extends ParentClass {
42
- constructor(options = {}) {
43
- const provider = options.provider || llmConfig.getOpenAIProvider({ instantiate: false });
44
- const sharedClient = options.client
45
- || provider?.getClient?.()
46
- || llmConfig.openaiClient
47
- || null;
48
-
49
- super({
50
- ...options,
51
- assistantId,
52
- client: sharedClient,
53
- provider,
54
- tools: [...tools, ...(options.tools || [])]
55
- });
56
-
57
- if (typeof setup === 'function') {
58
- setup.call(this, {
59
- assistantId,
60
- thread: this.thread,
61
- options
62
- });
63
- }
64
- }
65
- }
66
-
67
- if (typeof create === 'function') {
68
- ConfiguredAssistant.prototype.create = async function(code, context) {
69
- return await create.call(this, code, context);
70
- };
71
- }
72
-
73
- assistantRegistry[assistantId] = ConfiguredAssistant;
74
- return ConfiguredAssistant;
75
- }
76
-
77
- throw new Error('registerAssistant expects a class/function or configuration object');
78
- };
79
-
80
- const overrideGetAssistantById = (resolverFn) => {
81
- if (typeof resolverFn === 'function') {
82
- customGetAssistantById = resolverFn;
83
- }
84
- };
85
-
86
- const getAssistantById = (assistant_id, thread) => {
87
- if (customGetAssistantById) {
88
- return customGetAssistantById(assistant_id, thread);
89
- }
90
-
91
- if (assistantRegistry[assistant_id]) {
92
- const AssistantClass = assistantRegistry[assistant_id];
93
- return new AssistantClass({ thread });
94
- }
95
-
96
- if (assistantConfig && assistantConfig[assistant_id]) {
97
- const config = assistantConfig[assistant_id];
98
- return new BaseAssistant({
99
- ...config,
100
- assistantId: assistant_id,
101
- thread
102
- });
103
- }
104
-
105
- throw new Error(`Assistant with ID "${assistant_id}" not found`);
106
- };
10
+ const {
11
+ getAssistantById,
12
+ configureAssistants,
13
+ registerAssistant,
14
+ overrideGetAssistantById
15
+ } = require('./assistantResolver');
107
16
 
108
17
  const createAssistant = withTracing(
109
- (code, assistant_id) => createAssistantCore(code, assistant_id, getAssistantById),
18
+ createAssistantCore,
110
19
  'create_assistant',
111
20
  (code, assistant_id) => ({
112
21
  'assistant.thread_code': code,
@@ -138,7 +47,7 @@ const addInsAssistant = withTracing(
138
47
  );
139
48
 
140
49
  const replyAssistant = withTracing(
141
- (code, message_, thread_, runOptions) => replyAssistantCore(code, message_, thread_, runOptions, getAssistantById),
50
+ replyAssistantCore,
142
51
  'assistant_reply',
143
52
  (code, message_, thread_, runOptions) => ({
144
53
  'assistant.thread_code': code,
@@ -159,13 +68,14 @@ const switchAssistant = withTracing(
159
68
  );
160
69
 
161
70
  module.exports = {
162
- getAssistantById,
163
71
  createAssistant,
164
72
  replyAssistant,
165
73
  addMsgAssistant,
166
74
  addInsAssistant,
167
75
  switchAssistant,
76
+ getAssistantById,
168
77
  configureAssistants,
169
78
  registerAssistant,
170
- overrideGetAssistantById
79
+ overrideGetAssistantById,
80
+ runAssistantAndWait
171
81
  };
@@ -13,9 +13,10 @@ const { processThreadMessage } = require('../helpers/processHelper.js');
13
13
  const { getLastMessages, updateMessageRecord } = require('../helpers/messageHelper.js');
14
14
  const { withThreadRecovery } = require('../helpers/threadRecoveryHelper.js');
15
15
  const { combineImagesToPDF, cleanupFiles } = require('../helpers/filesHelper.js');
16
+ const { getAssistantById } = require('./assistantResolver');
16
17
  const { logger } = require('../utils/logger');
17
18
 
18
- const createAssistantCore = async (code, assistant_id, getAssistantById) => {
19
+ const createAssistantCore = async (code, assistant_id) => {
19
20
  const thread = await getThread(code);
20
21
  if (!thread) return null;
21
22
 
@@ -32,7 +33,7 @@ const createAssistantCore = async (code, assistant_id, getAssistantById) => {
32
33
  }
33
34
  };
34
35
 
35
- const addMsgAssistantCore = async (code, message, role = 'user') => {
36
+ const addMsgAssistantCore = async (code, message, role = 'user', reply = false) => {
36
37
  const thread = await getThread(code);
37
38
  if (!thread) return null;
38
39
 
@@ -42,10 +43,17 @@ const addMsgAssistantCore = async (code, message, role = 'user') => {
42
43
  try {
43
44
  await provider.addMessage({ threadId, messages: [{ role, content: message }] });
44
45
  await insertMessage({ code, message, role });
45
- return { success: true };
46
+
47
+ if (reply) {
48
+ const assistant = getAssistantById(thread.getAssistantId(), thread);
49
+ const runResult = await runAssistantWithRetries(thread, assistant, {});
50
+ return runResult?.output || null;
51
+ }
52
+
53
+ return null;
46
54
  } catch (error) {
47
55
  logger.error('[addMsgAssistantCore] Error adding message', { error: error.message, code, role });
48
- return { success: false, error: error.message };
56
+ return null;
49
57
  }
50
58
  };
51
59
 
@@ -58,14 +66,16 @@ const addInstructionCore = async (code, instruction, role = 'user') => {
58
66
 
59
67
  try {
60
68
  await provider.addMessage({ threadId, messages: [{ role, content: instruction }] });
61
- return { success: true };
69
+ const assistant = getAssistantById(thread.getAssistantId(), thread);
70
+ const runResult = await runAssistantWithRetries(thread, assistant, {});
71
+ return runResult?.output || null;
62
72
  } catch (error) {
63
73
  logger.error('[addInstructionCore] Error adding instruction', { error: error.message, code, role });
64
- return { success: false, error: error.message };
74
+ return null;
65
75
  }
66
76
  };
67
77
 
68
- const replyAssistantCore = async (code, message_ = null, thread_ = null, runOptions = {}, getAssistantById) => {
78
+ const replyAssistantCore = async (code, message_ = null, thread_ = null, runOptions = {}) => {
69
79
  const timings = {};
70
80
  const startTotal = Date.now();
71
81
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@peopl-health/nexus",
3
- "version": "2.5.3",
3
+ "version": "2.5.5",
4
4
  "description": "Core messaging and assistant library for WhatsApp communication platforms",
5
5
  "keywords": [
6
6
  "whatsapp",