@peopl-health/nexus 3.2.0 → 3.2.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.
|
@@ -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,
|
|
50
|
-
abortOnNewMessage: config.messageBatching?.abortOnNewMessage ?? true,
|
|
51
|
-
immediateRestart: config.messageBatching?.immediateRestart ?? true,
|
|
52
|
-
batchWindowMs: config.messageBatching?.batchWindowMs ?? 2000,
|
|
53
|
-
maxBatchWait: config.messageBatching?.maxBatchWait ?? 5000
|
|
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
|
|
|
@@ -695,7 +696,9 @@ class NexusMessaging {
|
|
|
695
696
|
async _processWithLock(chatId, existingTypingInterval = null) {
|
|
696
697
|
this.processingLocks.set(chatId, true);
|
|
697
698
|
let typingInterval = existingTypingInterval;
|
|
698
|
-
|
|
699
|
+
|
|
700
|
+
const runId = `run_${Date.now()}_${Math.random().toString(36).substring(7)}`;
|
|
701
|
+
this.activeRequests.set(chatId, runId);
|
|
699
702
|
|
|
700
703
|
try {
|
|
701
704
|
if (!typingInterval) {
|
|
@@ -707,6 +710,12 @@ class NexusMessaging {
|
|
|
707
710
|
let lastCount = messageCount;
|
|
708
711
|
|
|
709
712
|
while (Date.now() - startTime < this.batchingConfig.batchWindowMs) {
|
|
713
|
+
if (this.abandonedRuns.has(runId)) {
|
|
714
|
+
logger.info(`[Batching] Run ${runId} abandoned during batching for ${chatId}`);
|
|
715
|
+
this.abandonedRuns.delete(runId);
|
|
716
|
+
return;
|
|
717
|
+
}
|
|
718
|
+
|
|
710
719
|
await new Promise(resolve => setTimeout(resolve, 500));
|
|
711
720
|
const newCount = await this._getUnprocessedMessageCount(chatId);
|
|
712
721
|
|
|
@@ -721,11 +730,14 @@ class NexusMessaging {
|
|
|
721
730
|
}
|
|
722
731
|
}
|
|
723
732
|
|
|
733
|
+
if (this.abandonedRuns.has(runId)) {
|
|
734
|
+
logger.info(`[CheckAfter] Run ${runId} abandoned before AI call for ${chatId}`);
|
|
735
|
+
this.abandonedRuns.delete(runId);
|
|
736
|
+
return;
|
|
737
|
+
}
|
|
738
|
+
|
|
724
739
|
logger.info(`[CheckAfter] Processing ${lastCount} messages for ${chatId} after batching`);
|
|
725
740
|
|
|
726
|
-
runId = `run_${Date.now()}_${Math.random().toString(36).substring(7)}`;
|
|
727
|
-
this.activeRequests.set(chatId, runId);
|
|
728
|
-
|
|
729
741
|
const result = await this._processMessages(chatId, () => replyAssistant(chatId, null, null, { runId }));
|
|
730
742
|
|
|
731
743
|
if (this.abandonedRuns.has(runId)) {
|
|
@@ -814,7 +826,7 @@ class NexusMessaging {
|
|
|
814
826
|
* Start typing indicator refresh interval
|
|
815
827
|
*/
|
|
816
828
|
async _startTypingRefresh(chatId) {
|
|
817
|
-
if (!this.provider || typeof this.provider.sendTypingIndicator !== 'function') {
|
|
829
|
+
if (!this.batchingConfig.typingIndicator || !this.provider || typeof this.provider.sendTypingIndicator !== 'function') {
|
|
818
830
|
return null;
|
|
819
831
|
}
|
|
820
832
|
|
|
@@ -16,6 +16,7 @@ function getCurRow(baseID, code) {
|
|
|
16
16
|
const runAssistantAndWait = async ({
|
|
17
17
|
thread,
|
|
18
18
|
assistant,
|
|
19
|
+
message = null,
|
|
19
20
|
runConfig = {}
|
|
20
21
|
}) => {
|
|
21
22
|
if (!thread || !thread.getConversationId()) {
|
|
@@ -34,6 +35,7 @@ const runAssistantAndWait = async ({
|
|
|
34
35
|
async (currentThread = thread) => {
|
|
35
36
|
return await provider.executeRun({
|
|
36
37
|
thread: currentThread,
|
|
38
|
+
message,
|
|
37
39
|
assistant,
|
|
38
40
|
tools,
|
|
39
41
|
config,
|
|
@@ -58,7 +60,7 @@ const runAssistantWithRetries = async (thread, assistant, runConfig, patientRepl
|
|
|
58
60
|
'thread.id': thread.getConversationId(),
|
|
59
61
|
'assistant.id': thread.getAssistantId()
|
|
60
62
|
})
|
|
61
|
-
)({ thread, assistant, runConfig });
|
|
63
|
+
)({ thread, assistant, runConfig, message: patientReply });
|
|
62
64
|
|
|
63
65
|
const predictionTimeMs = Date.now() - startTime;
|
|
64
66
|
|
|
@@ -11,26 +11,26 @@ class DefaultMemoryManager extends MemoryManager {
|
|
|
11
11
|
this.maxHistoricalMessages = parseInt(process.env.MAX_HISTORICAL_MESSAGES || '50', 10);
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
async buildContext({ thread, config = {} }) {
|
|
14
|
+
async buildContext({ thread, message = null, config = {} }) {
|
|
15
15
|
this._logActivity('Building context', { threadCode: thread.code });
|
|
16
16
|
|
|
17
17
|
try {
|
|
18
|
-
const
|
|
19
|
-
const
|
|
18
|
+
const beforeCheckpoint = message ? message.createdAt : null;
|
|
19
|
+
const allMessages = await getLastNMessages(thread.code, this.maxHistoricalMessages, beforeCheckpoint);
|
|
20
20
|
|
|
21
21
|
if (!allMessages?.length) {
|
|
22
|
-
return
|
|
22
|
+
return [];
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
const messageContext = allMessages.reverse().flatMap(msg => {
|
|
26
26
|
const formattedContents = formatMessage(msg);
|
|
27
27
|
return formattedContents.map(content => ({
|
|
28
|
-
role: msg.origin === 'patient' ? 'user' : 'assistant',
|
|
28
|
+
role: msg.origin === 'instruction' ? 'developer' : msg.origin === 'patient' ? 'user' : 'assistant',
|
|
29
29
|
content: content || msg.body || msg.content || ''
|
|
30
30
|
}));
|
|
31
31
|
}).filter(msg => msg.content);
|
|
32
32
|
|
|
33
|
-
return
|
|
33
|
+
return messageContext;
|
|
34
34
|
} catch (error) {
|
|
35
35
|
logger.error('[DefaultMemoryManager] Context building failed', {
|
|
36
36
|
threadCode: thread.code,
|
|
@@ -173,7 +173,7 @@ class OpenAIResponsesProvider {
|
|
|
173
173
|
/**
|
|
174
174
|
* Main entry point for running assistant
|
|
175
175
|
*/
|
|
176
|
-
async executeRun({ thread, assistant, tools = [], config = {} }) {
|
|
176
|
+
async executeRun({ thread, assistant, message = null, tools = [], config = {} }) {
|
|
177
177
|
const { conversationId, assistantId } = this._normalizeThread(thread);
|
|
178
178
|
const promptVersion = thread?.version || null;
|
|
179
179
|
|
|
@@ -187,6 +187,7 @@ class OpenAIResponsesProvider {
|
|
|
187
187
|
// Delegate context building to conversation manager
|
|
188
188
|
const context = await this.conversationManager.buildContext({
|
|
189
189
|
thread,
|
|
190
|
+
message,
|
|
190
191
|
config: {
|
|
191
192
|
...config,
|
|
192
193
|
threadId: conversationId,
|
|
@@ -112,14 +112,8 @@ const addInstructionCore = async (code, instruction, role = 'system') => {
|
|
|
112
112
|
|
|
113
113
|
try {
|
|
114
114
|
const assistant = getAssistantById(thread.getAssistantId(), thread);
|
|
115
|
-
const runResult = await runAssistantWithRetries(thread, assistant, {
|
|
116
|
-
additionalInstructions: instruction,
|
|
117
|
-
additionalMessages: [
|
|
118
|
-
{ role: role, content: instruction }
|
|
119
|
-
]
|
|
120
|
-
});
|
|
121
115
|
|
|
122
|
-
// Save instruction message to database
|
|
116
|
+
// Save instruction message to database
|
|
123
117
|
try {
|
|
124
118
|
const message_id = `instruction_${Date.now()}_${Math.random().toString(36).substring(7)}`;
|
|
125
119
|
await insertMessage({
|
|
@@ -137,6 +131,13 @@ const addInstructionCore = async (code, instruction, role = 'system') => {
|
|
|
137
131
|
logger.error('[addInstructionCore] Error saving instruction message', { err });
|
|
138
132
|
}
|
|
139
133
|
|
|
134
|
+
const runResult = await runAssistantWithRetries(thread, assistant, {
|
|
135
|
+
additionalInstructions: instruction,
|
|
136
|
+
additionalMessages: [
|
|
137
|
+
{ role: role, content: instruction }
|
|
138
|
+
]
|
|
139
|
+
});
|
|
140
|
+
|
|
140
141
|
logger.info('[addInstructionCore] Run response', { output: runResult?.output });
|
|
141
142
|
return runResult?.output || null;
|
|
142
143
|
} catch (error) {
|