@peopl-health/nexus 3.2.1 → 3.2.3

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.
@@ -46,11 +46,12 @@ class NexusMessaging {
46
46
  this.activeRequests = new Map(); // Track active AI requests per chat
47
47
  this.abandonedRuns = new Set(); // Track runs that should be ignored
48
48
  this.batchingConfig = {
49
- enabled: config.messageBatching?.enabled ?? true, // Enabled by default with check-after
50
- abortOnNewMessage: config.messageBatching?.abortOnNewMessage ?? true, // Abort ongoing AI calls when new messages arrive
51
- immediateRestart: config.messageBatching?.immediateRestart ?? true, // Start new processing immediately without waiting
52
- batchWindowMs: config.messageBatching?.batchWindowMs ?? 2000, // Wait up to 2s for message bursts
53
- maxBatchWait: config.messageBatching?.maxBatchWait ?? 5000 // Maximum time to wait for batching
49
+ enabled: config.messageBatching?.enabled ?? true,
50
+ abortOnNewMessage: config.messageBatching?.abortOnNewMessage ?? true,
51
+ immediateRestart: config.messageBatching?.immediateRestart ?? true,
52
+ batchWindowMs: config.messageBatching?.batchWindowMs ?? 2000,
53
+ maxBatchWait: config.messageBatching?.maxBatchWait ?? 5000,
54
+ typingIndicator: config.messageBatching?.typingIndicator ?? false
54
55
  };
55
56
  }
56
57
 
@@ -825,7 +826,7 @@ class NexusMessaging {
825
826
  * Start typing indicator refresh interval
826
827
  */
827
828
  async _startTypingRefresh(chatId) {
828
- if (!this.provider || typeof this.provider.sendTypingIndicator !== 'function') {
829
+ if (!this.batchingConfig.typingIndicator || !this.provider || typeof this.provider.sendTypingIndicator !== 'function') {
829
830
  return null;
830
831
  }
831
832
 
@@ -59,15 +59,15 @@ async function getLastMessages(code) {
59
59
  }
60
60
  }
61
61
 
62
- // Create a variable to use as a chackpoint
63
- async function getLastNMessages(code, n, before=null) {
62
+ async function getLastNMessages(code, n, before = null, options = {}) {
64
63
  try {
65
- const query = { numero: code };
64
+ const query = { numero: code, ...options.query };
66
65
 
67
66
  if (before) query.createdAt = { $lte: before };
68
67
 
69
68
  const lastMessages = await Message.find(query)
70
- .sort({ createdAt: -1 })
69
+ .select(options.select || null)
70
+ .sort(options.sort || { createdAt: -1 })
71
71
  .limit(n)
72
72
  .lean();
73
73
 
@@ -16,21 +16,25 @@ class DefaultMemoryManager extends MemoryManager {
16
16
 
17
17
  try {
18
18
  const beforeCheckpoint = message ? message.createdAt : null;
19
- const allMessages = await getLastNMessages(thread.code, this.maxHistoricalMessages, beforeCheckpoint);
20
-
19
+ const allMessages = await getLastNMessages(thread.code, this.maxHistoricalMessages, beforeCheckpoint, {
20
+ query: { origin: { $ne: 'instruction' } }
21
+ });
22
+ const additionalMessages = config.additionalMessages || [];
23
+
21
24
  if (!allMessages?.length) {
22
- return [];
25
+ return additionalMessages;
23
26
  }
24
27
 
28
+ const roleMap = { system: 'system', patient: 'user' };
25
29
  const messageContext = allMessages.reverse().flatMap(msg => {
26
30
  const formattedContents = formatMessage(msg);
27
31
  return formattedContents.map(content => ({
28
- role: msg.origin === 'instruction' ? 'developer' : msg.origin === 'patient' ? 'user' : 'assistant',
32
+ role: roleMap[msg.origin] || 'assistant',
29
33
  content: content || msg.body || msg.content || ''
30
34
  }));
31
35
  }).filter(msg => msg.content);
32
36
 
33
- return messageContext;
37
+ return [...messageContext, ...additionalMessages];
34
38
  } catch (error) {
35
39
  logger.error('[DefaultMemoryManager] Context building failed', {
36
40
  threadCode: thread.code,
@@ -231,10 +231,7 @@ class OpenAIResponsesProvider {
231
231
  await this.conversationManager.processResponse(result, thread, config);
232
232
 
233
233
  const completed = result.status === 'completed';
234
- const output = await this.getRunText({
235
- runId: result.id,
236
- fallback: ''
237
- });
234
+ const output = result.output_text || result.output?.find(o => o.type === 'message')?.content?.[0]?.text || '';
238
235
 
239
236
  if (filter) {
240
237
  await Thread.updateOne(filter, { $set: { run_id: null } });
@@ -243,6 +240,9 @@ class OpenAIResponsesProvider {
243
240
  logger.info('[OpenAIResponsesProvider] Run complete', {
244
241
  runId: result.id,
245
242
  completed,
243
+ outputLength: output?.length || 0,
244
+ hasOutputText: !!result.output_text,
245
+ outputTypes: result.output?.map(o => o.type) || [],
246
246
  toolsExecuted: result.tools_executed?.length || 0
247
247
  });
248
248
 
@@ -338,21 +338,6 @@ class OpenAIResponsesProvider {
338
338
  }
339
339
  }
340
340
 
341
- async getRun({ threadId, runId }) {
342
- const id = this._ensureResponseId(runId);
343
- return await this.client.responses.retrieve(id);
344
- }
345
-
346
- async getRunText({ runId, messageIndex = 0, contentIndex = 0, fallback = '' } = {}) {
347
- const response = await this.client.responses.retrieve(this._ensureResponseId(runId));
348
- if (!response) return fallback;
349
-
350
- if (response.output_text) return response.output_text;
351
-
352
- const text = response.output?.[messageIndex]?.content?.[contentIndex]?.text;
353
- return text || fallback;
354
- }
355
-
356
341
  /**
357
342
  * Generic helpers
358
343
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@peopl-health/nexus",
3
- "version": "3.2.1",
3
+ "version": "3.2.3",
4
4
  "description": "Core messaging and assistant library for WhatsApp communication platforms",
5
5
  "keywords": [
6
6
  "whatsapp",