@peopl-health/nexus 2.4.9-fix-mime-type → 2.4.10
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.
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
const mongoose = require('mongoose');
|
|
2
|
-
const { fetchConversationData, processConversations } = require('../services/conversationService');
|
|
3
|
-
const { sendMessage } = require('../core/NexusMessaging');
|
|
4
|
-
const { Thread } = require('../models/threadModel');
|
|
5
2
|
const llmConfig = require('../config/llmConfig');
|
|
6
3
|
const { Historial_Clinico_ID } = require('../config/airtableConfig');
|
|
4
|
+
const { Thread } = require('../models/threadModel');
|
|
5
|
+
const { withThreadRecovery } = require('../helpers/threadRecoveryHelper');
|
|
7
6
|
const { getRecordByFilter } = require('../services/airtableService');
|
|
7
|
+
const { fetchConversationData, processConversations } = require('../services/conversationService');
|
|
8
|
+
const { sendMessage } = require('../core/NexusMessaging');
|
|
8
9
|
const { logger } = require('../utils/logger');
|
|
9
10
|
|
|
10
11
|
const Message = mongoose.models.Message;
|
|
@@ -649,7 +650,7 @@ const getOpenAIThreadMessagesController = async (req, res) => {
|
|
|
649
650
|
});
|
|
650
651
|
}
|
|
651
652
|
|
|
652
|
-
|
|
653
|
+
let thread = await Thread.findOne({
|
|
653
654
|
code: phoneNumber,
|
|
654
655
|
active: true
|
|
655
656
|
}).sort({ createdAt: -1 });
|
|
@@ -662,7 +663,7 @@ const getOpenAIThreadMessagesController = async (req, res) => {
|
|
|
662
663
|
});
|
|
663
664
|
}
|
|
664
665
|
|
|
665
|
-
|
|
666
|
+
let conversationId = thread.conversation_id;
|
|
666
667
|
logger.info('Thread found - Conversation ID:', conversationId);
|
|
667
668
|
|
|
668
669
|
const provider = llmConfig.getOpenAIProvider({ instantiate: true, variant });
|
|
@@ -683,8 +684,23 @@ const getOpenAIThreadMessagesController = async (req, res) => {
|
|
|
683
684
|
logger.info('Including runId:', runId);
|
|
684
685
|
}
|
|
685
686
|
|
|
687
|
+
let messages;
|
|
688
|
+
let threadRecreated = false;
|
|
689
|
+
|
|
686
690
|
logger.info('Calling listMessages with params:', queryParams);
|
|
687
|
-
|
|
691
|
+
messages = await withThreadRecovery(
|
|
692
|
+
async (currentThread = thread) => {
|
|
693
|
+
if (currentThread !== thread) {
|
|
694
|
+
thread = currentThread;
|
|
695
|
+
conversationId = currentThread.getConversationId();
|
|
696
|
+
queryParams.threadId = conversationId;
|
|
697
|
+
threadRecreated = true;
|
|
698
|
+
}
|
|
699
|
+
return await provider.listMessages(queryParams);
|
|
700
|
+
},
|
|
701
|
+
thread,
|
|
702
|
+
variant
|
|
703
|
+
);
|
|
688
704
|
|
|
689
705
|
logger.info(`Retrieved ${messages?.data?.length || 0} messages from OpenAI`);
|
|
690
706
|
|
|
@@ -696,6 +712,7 @@ const getOpenAIThreadMessagesController = async (req, res) => {
|
|
|
696
712
|
assistantId: thread.assistant_id,
|
|
697
713
|
messages: messages.data || messages,
|
|
698
714
|
hasMore: messages.has_more || false,
|
|
715
|
+
threadRecreated,
|
|
699
716
|
pagination: {
|
|
700
717
|
limit: parseInt(limit),
|
|
701
718
|
order
|
|
@@ -3,6 +3,7 @@ const llmConfig = require('../config/llmConfig.js');
|
|
|
3
3
|
const { Thread } = require('../models/threadModel.js');
|
|
4
4
|
const { createProvider } = require('../providers/createProvider.js');
|
|
5
5
|
const { withTracing } = require('../utils/tracingDecorator');
|
|
6
|
+
const { withThreadRecovery } = require('./threadRecoveryHelper');
|
|
6
7
|
|
|
7
8
|
const { getRecordByFilter } = require('../services/airtableService.js');
|
|
8
9
|
const { logger } = require('../utils/logger');
|
|
@@ -62,37 +63,43 @@ const runAssistantAndWait = async ({
|
|
|
62
63
|
? { ...conversationConfig, assistant }
|
|
63
64
|
: conversationConfig;
|
|
64
65
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
66
|
+
return await withThreadRecovery(
|
|
67
|
+
async (currentThread = thread) => {
|
|
68
|
+
let run = await provider.runConversation({
|
|
69
|
+
threadId: currentThread.getConversationId(),
|
|
70
|
+
assistantId: currentThread.getAssistantId(),
|
|
71
|
+
tools: tools.length > 0 ? tools : undefined,
|
|
72
|
+
...runConfigWithAssistant,
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
const filter = currentThread.code ? { code: currentThread.code, active: true } : null;
|
|
76
|
+
if (filter) {
|
|
77
|
+
await Thread.updateOne(filter, { $set: { run_id: run.id } });
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const maxRetries = polling?.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
81
|
+
let completed = false;
|
|
82
|
+
|
|
83
|
+
try {
|
|
84
|
+
logger.info('[runAssistantAndWait] Run started', { runId: run.id, threadId: currentThread.getConversationId(), assistantId: currentThread.getAssistantId() });
|
|
85
|
+
({run, completed} = await provider.checkRunStatus(assistant, currentThread.getConversationId(), run.id, 0, maxRetries));
|
|
86
|
+
} finally {
|
|
87
|
+
if (filter) {
|
|
88
|
+
await Thread.updateOne(filter, { $set: { run_id: null } });
|
|
89
|
+
}
|
|
90
|
+
}
|
|
88
91
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
+
if (!completed) {
|
|
93
|
+
return { run: run, completed: false, output: '' };
|
|
94
|
+
}
|
|
92
95
|
|
|
93
|
-
|
|
96
|
+
const output = await provider.getRunText({ threadId: currentThread.getConversationId(), runId: run.id, fallback: '' });
|
|
94
97
|
|
|
95
|
-
|
|
98
|
+
return { completed: true, output };
|
|
99
|
+
},
|
|
100
|
+
thread,
|
|
101
|
+
variant
|
|
102
|
+
);
|
|
96
103
|
};
|
|
97
104
|
|
|
98
105
|
const executeAssistantAttempt = async (thread, assistant, runConfig, attemptNumber) => {
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
const { Thread } = require('../models/threadModel');
|
|
2
|
+
const { createProvider } = require('../providers/createProvider');
|
|
3
|
+
const { logger } = require('../utils/logger');
|
|
4
|
+
|
|
5
|
+
const isThreadNotFoundError = (error) => {
|
|
6
|
+
return error?.status === 404 ||
|
|
7
|
+
error?.code === 'thread_not_found' ||
|
|
8
|
+
error?.code === 'invalid_thread_id' ||
|
|
9
|
+
(error?.message && (
|
|
10
|
+
error.message.includes('No thread found') ||
|
|
11
|
+
error.message.includes('thread does not exist') ||
|
|
12
|
+
error.message.includes('Invalid thread')
|
|
13
|
+
));
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const recreateThread = async (thread, variant = 'assistants') => {
|
|
17
|
+
const provider = createProvider({ variant });
|
|
18
|
+
const newConversation = await provider.createConversation({
|
|
19
|
+
metadata: { phoneNumber: thread.code, recreated: true }
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
await Thread.updateOne(
|
|
23
|
+
{ code: thread.code, active: true },
|
|
24
|
+
{ $set: { conversation_id: newConversation.id } }
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
const updatedThread = await Thread.findOne({ code: thread.code, active: true });
|
|
28
|
+
logger.info('[threadRecovery] Thread recreated', {
|
|
29
|
+
oldId: thread.conversation_id,
|
|
30
|
+
newId: newConversation.id,
|
|
31
|
+
code: thread.code
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
return updatedThread;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const withThreadRecovery = async (operation, thread, variant = 'assistants') => {
|
|
38
|
+
try {
|
|
39
|
+
return await operation();
|
|
40
|
+
} catch (error) {
|
|
41
|
+
if (isThreadNotFoundError(error) && thread) {
|
|
42
|
+
logger.warn('[threadRecovery] Thread not found, recreating', {
|
|
43
|
+
conversationId: thread.getConversationId?.() || thread.conversation_id,
|
|
44
|
+
code: thread.code
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
const recoveredThread = await recreateThread(thread, variant);
|
|
48
|
+
return await operation(recoveredThread);
|
|
49
|
+
}
|
|
50
|
+
throw error;
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
module.exports = {
|
|
55
|
+
isThreadNotFoundError,
|
|
56
|
+
recreateThread,
|
|
57
|
+
withThreadRecovery
|
|
58
|
+
};
|
|
@@ -14,6 +14,7 @@ const { getThread, getThreadInfo } = require('../helpers/threadHelper.js');
|
|
|
14
14
|
const { withTracing } = require('../utils/tracingDecorator.js');
|
|
15
15
|
const { processThreadMessage } = require('../helpers/processHelper.js');
|
|
16
16
|
const { getLastMessages, updateMessageRecord } = require('../helpers/messageHelper.js');
|
|
17
|
+
const { withThreadRecovery } = require('../helpers/threadRecoveryHelper.js');
|
|
17
18
|
const { combineImagesToPDF, cleanupFiles } = require('../helpers/filesHelper.js');
|
|
18
19
|
const { logger } = require('../utils/logger');
|
|
19
20
|
|
|
@@ -137,13 +138,19 @@ const getAssistantById = (assistant_id, thread) => {
|
|
|
137
138
|
const createAssistant = async (code, assistant_id, messages=[], force=false) => {
|
|
138
139
|
const findThread = await Thread.findOne({ code: code });
|
|
139
140
|
logger.info('[createAssistant] findThread', findThread);
|
|
140
|
-
if (findThread && findThread.getConversationId()) {
|
|
141
|
+
if (findThread && findThread.getConversationId() && !force) {
|
|
141
142
|
logger.info('[createAssistant] Thread already exists');
|
|
142
143
|
const updateFields = { active: true, stopped: false };
|
|
143
144
|
Thread.setAssistantId(updateFields, assistant_id);
|
|
144
145
|
await Thread.updateOne({ code: code }, { $set: updateFields });
|
|
145
146
|
return findThread;
|
|
146
147
|
}
|
|
148
|
+
|
|
149
|
+
if (force && findThread?.getConversationId()) {
|
|
150
|
+
const provider = createProvider({ variant: process.env.VARIANT || 'assistants' });
|
|
151
|
+
await provider.deleteConversation(findThread.getConversationId());
|
|
152
|
+
logger.info('[createAssistant] Deleted old conversation, will create new one');
|
|
153
|
+
}
|
|
147
154
|
|
|
148
155
|
const curRow = await getCurRow(Historial_Clinico_ID, code);
|
|
149
156
|
logger.info('[createAssistant] curRow', curRow[0]);
|
|
@@ -153,7 +160,6 @@ const createAssistant = async (code, assistant_id, messages=[], force=false) =>
|
|
|
153
160
|
const assistant = getAssistantById(assistant_id, null);
|
|
154
161
|
const initialThread = await assistant.create(code, curRow[0]);
|
|
155
162
|
|
|
156
|
-
// Add new messages to memory
|
|
157
163
|
const provider = createProvider({ variant: process.env.VARIANT || 'assistants' });
|
|
158
164
|
for (const message of messages) {
|
|
159
165
|
await provider.addMessage({
|
|
@@ -177,29 +183,32 @@ const createAssistant = async (code, assistant_id, messages=[], force=false) =>
|
|
|
177
183
|
const updatedThread = await Thread.findOneAndUpdate(condition, {run_id: null, ...thread}, options);
|
|
178
184
|
logger.info('[createAssistant] Updated thread:', updatedThread);
|
|
179
185
|
|
|
180
|
-
// Delete previous thread
|
|
181
|
-
if (force) {
|
|
182
|
-
await provider.deleteConversation(findThread.getConversationId());
|
|
183
|
-
}
|
|
184
|
-
|
|
185
186
|
return thread;
|
|
186
187
|
};
|
|
187
188
|
|
|
188
189
|
const addMsgAssistant = async (code, inMessages, role = 'user', reply = false) => {
|
|
189
190
|
try {
|
|
190
|
-
|
|
191
|
+
let thread = await Thread.findOne({ code: code });
|
|
191
192
|
logger.info(thread);
|
|
192
193
|
if (thread === null) return null;
|
|
193
194
|
|
|
194
195
|
const provider = createProvider({ variant: process.env.VARIANT || 'assistants' });
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
196
|
+
|
|
197
|
+
await withThreadRecovery(
|
|
198
|
+
async (recoveredThread = thread) => {
|
|
199
|
+
thread = recoveredThread;
|
|
200
|
+
for (const message of inMessages) {
|
|
201
|
+
logger.info(message);
|
|
202
|
+
await provider.addMessage({
|
|
203
|
+
threadId: thread.getConversationId(),
|
|
204
|
+
role: role,
|
|
205
|
+
content: message
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
thread,
|
|
210
|
+
process.env.VARIANT || 'assistants'
|
|
211
|
+
);
|
|
203
212
|
|
|
204
213
|
if (!reply) return null;
|
|
205
214
|
|
|
@@ -322,9 +331,15 @@ const replyAssistantCore = async (code, message_ = null, thread_ = null, runOpti
|
|
|
322
331
|
const allTempFiles = processResults.flatMap(r => r.tempFiles || []);
|
|
323
332
|
|
|
324
333
|
if (allMessagesToAdd.length > 0) {
|
|
325
|
-
const threadId = finalThread.getConversationId();
|
|
326
334
|
logger.info(`[replyAssistantCore] Adding ${allMessagesToAdd.length} messages to thread in batch`);
|
|
327
|
-
await
|
|
335
|
+
await withThreadRecovery(
|
|
336
|
+
async (thread = finalThread) => {
|
|
337
|
+
const threadId = thread.getConversationId();
|
|
338
|
+
await provider.addMessage({ threadId, messages: allMessagesToAdd });
|
|
339
|
+
},
|
|
340
|
+
finalThread,
|
|
341
|
+
process.env.VARIANT || 'assistants'
|
|
342
|
+
);
|
|
328
343
|
}
|
|
329
344
|
|
|
330
345
|
await Promise.all(processResults.map(r => updateMessageRecord(r.reply, finalThread)));
|