@peopl-health/nexus 2.5.5 → 2.5.6
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/assistants/BaseAssistant.js +11 -5
- package/lib/controllers/assistantController.js +1 -4
- package/lib/controllers/conversationController.js +1 -2
- package/lib/helpers/assistantHelper.js +30 -117
- package/lib/models/messageModel.js +1 -0
- package/lib/providers/OpenAIAssistantsProvider.js +122 -121
- package/lib/providers/OpenAIResponsesProvider.js +168 -398
- package/lib/providers/OpenAIResponsesProviderTools.js +49 -96
- package/lib/services/airtableService.js +1 -1
- package/lib/services/assistantServiceCore.js +126 -38
- package/lib/templates/templateStructure.js +1 -1
- package/lib/utils/retryHelper.js +3 -2
- package/package.json +1 -1
|
@@ -230,12 +230,18 @@ class BaseAssistant {
|
|
|
230
230
|
|
|
231
231
|
async close() {
|
|
232
232
|
this.status = 'closed';
|
|
233
|
-
const assistantId =
|
|
233
|
+
const assistantId = this.thread?.getAssistantId();
|
|
234
234
|
if (this.thread?.code && assistantId) {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
235
|
+
await Thread.updateOne(
|
|
236
|
+
{
|
|
237
|
+
code: this.thread.code,
|
|
238
|
+
$or: [
|
|
239
|
+
{ assistant_id: assistantId },
|
|
240
|
+
{ prompt_id: assistantId }
|
|
241
|
+
]
|
|
242
|
+
},
|
|
243
|
+
{ $set: { active: false } }
|
|
244
|
+
);
|
|
239
245
|
}
|
|
240
246
|
|
|
241
247
|
if (this.assistantId) {
|
|
@@ -25,10 +25,7 @@ const addInsAssistantController = async (req, res) => {
|
|
|
25
25
|
const { code, instruction } = req.body;
|
|
26
26
|
|
|
27
27
|
try {
|
|
28
|
-
const
|
|
29
|
-
const role = variant === 'responses' ? 'developer' : 'user';
|
|
30
|
-
|
|
31
|
-
const assistantReply = await addInsAssistant(code, instruction, role);
|
|
28
|
+
const assistantReply = await addInsAssistant(code, instruction, 'developer');
|
|
32
29
|
if (assistantReply) await sendMessage({code, body: assistantReply, fileType: 'text', origin: 'assistant'});
|
|
33
30
|
return res.status(200).send({ message: 'Instruction added to assistant', success: true });
|
|
34
31
|
} catch (error) {
|
|
@@ -678,9 +678,8 @@ const getOpenAIThreadMessagesController = async (req, res) => {
|
|
|
678
678
|
limit: parseInt(limit)
|
|
679
679
|
};
|
|
680
680
|
|
|
681
|
-
if (
|
|
681
|
+
if (runId) {
|
|
682
682
|
queryParams.runId = runId;
|
|
683
|
-
logger.info('Including runId:', runId);
|
|
684
683
|
}
|
|
685
684
|
|
|
686
685
|
let messages;
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
const llmConfig = require('../config/llmConfig.js');
|
|
2
|
-
|
|
3
|
-
const { Thread } = require('../models/threadModel.js');
|
|
4
1
|
const { createProvider } = require('../providers/createProvider.js');
|
|
5
2
|
const { withTracing } = require('../utils/tracingDecorator');
|
|
6
3
|
const { withThreadRecovery } = require('./threadRecoveryHelper');
|
|
@@ -8,31 +5,6 @@ const { withThreadRecovery } = require('./threadRecoveryHelper');
|
|
|
8
5
|
const { getRecordByFilter } = require('../services/airtableService.js');
|
|
9
6
|
const { logger } = require('../utils/logger');
|
|
10
7
|
|
|
11
|
-
const DEFAULT_MAX_RETRIES = parseInt(process.env.MAX_RETRIES || '30', 10);
|
|
12
|
-
|
|
13
|
-
async function checkIfFinished(text) {
|
|
14
|
-
try {
|
|
15
|
-
const provider = llmConfig.requireOpenAIProvider();
|
|
16
|
-
const completion = await provider.createChatCompletion({
|
|
17
|
-
model: 'gpt-4o-mini',
|
|
18
|
-
messages: [
|
|
19
|
-
{
|
|
20
|
-
role: 'user',
|
|
21
|
-
content: `Dado el siguiente dialogo, determina si el paciente desea finalizar la conversación.
|
|
22
|
-
Considera que la conversación ha terminado si el paciente: 1)Agradece o se despide, usando expresiones como 'gracias', 'adiós', 'hasta luego', etc.
|
|
23
|
-
2)Indica explícitamente que no tiene más síntomas o preguntas, o que no necesita más ayuda.
|
|
24
|
-
3)Expresa que no desea continuar. O el asistente envia recomendaciones o se despide.
|
|
25
|
-
Responde solo con 'Si' si la conversación ha terminado, o 'No' si aún continúa: Texto: "${text}`
|
|
26
|
-
}
|
|
27
|
-
]
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
return completion.choices[0].message.content;
|
|
31
|
-
} catch (error) {
|
|
32
|
-
logger.error('[checkIfFinished] Error checking run status:', error);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
8
|
function getCurRow(baseID, code) {
|
|
37
9
|
if (code.endsWith('@g.us')) {
|
|
38
10
|
return getRecordByFilter(baseID, 'estado_general', `FIND("${code}", {Group ID})`);
|
|
@@ -55,116 +27,57 @@ const runAssistantAndWait = async ({
|
|
|
55
27
|
}
|
|
56
28
|
|
|
57
29
|
const provider = createProvider({ variant: process.env.VARIANT || 'assistants' });
|
|
58
|
-
const { polling, tools: configTools, ...
|
|
59
|
-
const variant = provider.getVariant ? provider.getVariant() : (process.env.VARIANT || 'assistants');
|
|
30
|
+
const { polling, tools: configTools, ...config } = runConfig || {};
|
|
60
31
|
const tools = assistant.getToolSchemas ? assistant.getToolSchemas() : (configTools || []);
|
|
61
32
|
|
|
62
33
|
return await withThreadRecovery(
|
|
63
34
|
async (currentThread = thread) => {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
threadId: currentThread.getConversationId(),
|
|
71
|
-
assistantId: currentThread.getAssistantId(),
|
|
72
|
-
tools: tools.length > 0 ? tools : undefined,
|
|
73
|
-
...runConfigWithAssistant,
|
|
35
|
+
return await provider.executeRun({
|
|
36
|
+
thread: currentThread,
|
|
37
|
+
assistant,
|
|
38
|
+
tools,
|
|
39
|
+
config,
|
|
40
|
+
polling
|
|
74
41
|
});
|
|
75
|
-
|
|
76
|
-
const filter = currentThread.code ? { code: currentThread.code, active: true } : null;
|
|
77
|
-
if (filter) {
|
|
78
|
-
await Thread.updateOne(filter, { $set: { run_id: run.id } });
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const maxRetries = polling?.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
82
|
-
let completed = false;
|
|
83
|
-
let tools_executed = run.tools_executed || [];
|
|
84
|
-
|
|
85
|
-
try {
|
|
86
|
-
logger.info('[runAssistantAndWait] Run started', { runId: run.id, threadId: currentThread.getConversationId(), assistantId: currentThread.getAssistantId() });
|
|
87
|
-
const result = await provider.checkRunStatus(assistant, currentThread.getConversationId(), run.id, 0, maxRetries, false, toolMetadata);
|
|
88
|
-
run = result.run;
|
|
89
|
-
completed = result.completed;
|
|
90
|
-
tools_executed = [...tools_executed, ...(result.tools_executed || [])];
|
|
91
|
-
} finally {
|
|
92
|
-
if (filter) {
|
|
93
|
-
await Thread.updateOne(filter, { $set: { run_id: null } });
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
if (!completed) {
|
|
98
|
-
return { run: run, completed: false, output: '', tools_executed };
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
const output = await provider.getRunText({ threadId: currentThread.getConversationId(), runId: run.id, fallback: '' });
|
|
102
|
-
|
|
103
|
-
return { completed: true, output, tools_executed };
|
|
104
42
|
},
|
|
105
|
-
thread
|
|
106
|
-
variant
|
|
43
|
+
thread
|
|
107
44
|
);
|
|
108
45
|
};
|
|
109
46
|
|
|
110
|
-
const executeAssistantAttempt = async (thread, assistant, runConfig, attemptNumber) => {
|
|
111
|
-
const result = await runAssistantAndWait({
|
|
112
|
-
thread,
|
|
113
|
-
assistant,
|
|
114
|
-
runConfig
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
logger.info(`[executeAssistantAttempt] Attempt ${attemptNumber}: completed=${result.completed}, output=${result.output || '(empty)'}`);
|
|
118
|
-
|
|
119
|
-
return result;
|
|
120
|
-
};
|
|
121
|
-
|
|
122
47
|
const runAssistantWithRetries = async (thread, assistant, runConfig, patientReply = null) => {
|
|
123
48
|
if (patientReply) {
|
|
124
49
|
assistant.setReplies(patientReply);
|
|
125
50
|
}
|
|
126
51
|
|
|
127
52
|
const startTime = Date.now();
|
|
128
|
-
let run, output, completed, tools_executed;
|
|
129
|
-
let retries = 0;
|
|
130
|
-
const maxRetries = DEFAULT_MAX_RETRIES;
|
|
131
53
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
'
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
})
|
|
142
|
-
)(thread, assistant, runConfig, retries));
|
|
143
|
-
|
|
144
|
-
if (completed && output) break;
|
|
145
|
-
|
|
146
|
-
if (retries < maxRetries) {
|
|
147
|
-
const delay = retries === 1
|
|
148
|
-
? 500
|
|
149
|
-
: Math.min(1000 * Math.pow(1.5, retries - 1), 5000);
|
|
150
|
-
logger.info(`[runAssistantWithRetries] Retry ${retries}, waiting ${delay}ms`);
|
|
151
|
-
await new Promise(resolve => setTimeout(resolve, delay));
|
|
152
|
-
}
|
|
153
|
-
} while (retries < maxRetries && (!completed || !output));
|
|
154
|
-
|
|
54
|
+
const result = await withTracing(
|
|
55
|
+
runAssistantAndWait,
|
|
56
|
+
'run_assistant_with_retries',
|
|
57
|
+
() => ({
|
|
58
|
+
'thread.id': thread.getConversationId(),
|
|
59
|
+
'assistant.id': thread.getAssistantId()
|
|
60
|
+
})
|
|
61
|
+
)({ thread, assistant, runConfig });
|
|
62
|
+
|
|
155
63
|
const predictionTimeMs = Date.now() - startTime;
|
|
156
|
-
|
|
157
|
-
if (run?.last_error) logger.warn('[runAssistantWithRetries] Run error', { error: run.last_error });
|
|
158
|
-
logger.info('[runAssistantWithRetries] Run completed', { completed, outputLength: output?.length || 0, toolsExecuted: tools_executed?.length || 0 });
|
|
159
|
-
logger.info('[runAssistantWithRetries] TIMING', { predictionTimeMs, retries });
|
|
160
64
|
|
|
161
|
-
|
|
65
|
+
logger.info('[runAssistantWithRetries] Run completed', {
|
|
66
|
+
completed: result.completed,
|
|
67
|
+
outputLength: result.output?.length || 0,
|
|
68
|
+
toolsExecuted: result.tools_executed?.length || 0,
|
|
69
|
+
predictionTimeMs
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
return {
|
|
73
|
+
...result,
|
|
74
|
+
retries: result.retries || 0,
|
|
75
|
+
predictionTimeMs
|
|
76
|
+
};
|
|
162
77
|
};
|
|
163
78
|
|
|
164
79
|
module.exports = {
|
|
165
|
-
checkIfFinished,
|
|
166
80
|
getCurRow,
|
|
167
81
|
runAssistantAndWait,
|
|
168
|
-
runAssistantWithRetries
|
|
169
|
-
executeAssistantAttempt
|
|
82
|
+
runAssistantWithRetries
|
|
170
83
|
};
|
|
@@ -138,6 +138,7 @@ async function insertMessage(values) {
|
|
|
138
138
|
origin: values.origin,
|
|
139
139
|
tools_executed: values.tools_executed || [],
|
|
140
140
|
raw: values.raw || null,
|
|
141
|
+
assistant_id: values.assistant_id || null,
|
|
141
142
|
statusInfo: values.statusInfo || (values.delivery_status ? {
|
|
142
143
|
status: values.delivery_status,
|
|
143
144
|
errorCode: values.delivery_error_code || null,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const { OpenAI } = require('openai');
|
|
2
|
+
const { Thread } = require('../models/threadModel');
|
|
2
3
|
const { retryWithBackoff } = require('../utils/retryHelper');
|
|
3
4
|
const { logger } = require('../utils/logger');
|
|
4
5
|
|
|
@@ -43,32 +44,13 @@ class OpenAIAssistantsProvider {
|
|
|
43
44
|
return this.client;
|
|
44
45
|
}
|
|
45
46
|
|
|
46
|
-
/**
|
|
47
|
-
* Retry helper wrapper that uses shared retry logic
|
|
48
|
-
* @private
|
|
49
|
-
*/
|
|
50
|
-
async _retryWithBackoff(operation, options = {}) {
|
|
51
|
-
return retryWithBackoff(operation, {
|
|
52
|
-
...options,
|
|
53
|
-
providerName: PROVIDER_NAME,
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* @deprecated Use _retryWithBackoff instead
|
|
59
|
-
* Kept for backward compatibility
|
|
60
|
-
*/
|
|
61
|
-
async _retryWithRateLimit(operation, maxRetries = 3, retryCount = 0) {
|
|
62
|
-
return this._retryWithBackoff(operation, { maxRetries, retryCount });
|
|
63
|
-
}
|
|
64
|
-
|
|
65
47
|
async createConversation({ metadata, messages = [], toolResources } = {}) {
|
|
66
|
-
const thread = await
|
|
48
|
+
const { result: thread } = await retryWithBackoff(() =>
|
|
67
49
|
this.client.beta.threads.create({
|
|
68
50
|
metadata,
|
|
69
51
|
tool_resources: toolResources,
|
|
70
52
|
})
|
|
71
|
-
);
|
|
53
|
+
, { providerName: PROVIDER_NAME });
|
|
72
54
|
|
|
73
55
|
if (Array.isArray(messages) && messages.length > 0) {
|
|
74
56
|
for (const message of messages) {
|
|
@@ -79,10 +61,6 @@ class OpenAIAssistantsProvider {
|
|
|
79
61
|
return thread;
|
|
80
62
|
}
|
|
81
63
|
|
|
82
|
-
async deleteConversation(threadId) {
|
|
83
|
-
await this.client.beta.threads.del(this._ensureId(threadId));
|
|
84
|
-
}
|
|
85
|
-
|
|
86
64
|
async addMessage({ threadId, messages, role = 'user', content, metadata }) {
|
|
87
65
|
const id = this._ensureId(threadId);
|
|
88
66
|
const messagesToAdd = messages || [{ role, content, metadata }];
|
|
@@ -99,9 +77,9 @@ class OpenAIAssistantsProvider {
|
|
|
99
77
|
payload.metadata = msg.metadata;
|
|
100
78
|
}
|
|
101
79
|
|
|
102
|
-
const result = await
|
|
80
|
+
const { result } = await retryWithBackoff(() =>
|
|
103
81
|
this.client.beta.threads.messages.create(id, payload)
|
|
104
|
-
);
|
|
82
|
+
, { providerName: PROVIDER_NAME });
|
|
105
83
|
results.push(result);
|
|
106
84
|
}
|
|
107
85
|
return messages ? results : results[0];
|
|
@@ -141,6 +119,83 @@ class OpenAIAssistantsProvider {
|
|
|
141
119
|
return fallback;
|
|
142
120
|
}
|
|
143
121
|
|
|
122
|
+
/**
|
|
123
|
+
* Normalize thread object to unified format
|
|
124
|
+
*/
|
|
125
|
+
_normalizeThread(thread) {
|
|
126
|
+
return {
|
|
127
|
+
conversationId: thread.thread_id || thread.getConversationId?.(),
|
|
128
|
+
assistantId: thread.assistant_id || thread.getAssistantId?.()
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Main entry point for running assistant
|
|
135
|
+
*/
|
|
136
|
+
async executeRun({ thread, assistant, tools = [], config = {}, polling = {} }) {
|
|
137
|
+
const { conversationId, assistantId } = this._normalizeThread(thread);
|
|
138
|
+
|
|
139
|
+
logger.info('[OpenAIAssistantsProvider] Starting run', {
|
|
140
|
+
conversationId,
|
|
141
|
+
assistantId
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
const filter = thread.code ? { code: thread.code, active: true } : null;
|
|
145
|
+
|
|
146
|
+
const run = await this.runConversation({
|
|
147
|
+
threadId: conversationId,
|
|
148
|
+
assistantId,
|
|
149
|
+
tools,
|
|
150
|
+
...config
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
if (filter) {
|
|
154
|
+
await Thread.updateOne(filter, { $set: { run_id: run.id } });
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
let result;
|
|
158
|
+
try {
|
|
159
|
+
logger.info('[OpenAIAssistantsProvider] Polling run status', { runId: run.id });
|
|
160
|
+
result = await this.checkRunStatus(assistant, conversationId, run.id);
|
|
161
|
+
} finally {
|
|
162
|
+
if (filter) {
|
|
163
|
+
await Thread.updateOne(filter, { $set: { run_id: null } });
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (!result.completed) {
|
|
168
|
+
logger.warn('[OpenAIAssistantsProvider] Run did not complete', { runId: run.id });
|
|
169
|
+
return {
|
|
170
|
+
run: result.run,
|
|
171
|
+
completed: false,
|
|
172
|
+
output: '',
|
|
173
|
+
tools_executed: result.tools_executed || [],
|
|
174
|
+
retries: run.retries || 0
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const output = await this.getRunText({
|
|
179
|
+
threadId: conversationId,
|
|
180
|
+
runId: result.run.id,
|
|
181
|
+
fallback: ''
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
logger.info('[OpenAIAssistantsProvider] Run complete', {
|
|
185
|
+
runId: result.run.id,
|
|
186
|
+
completed: true,
|
|
187
|
+
toolsExecuted: result.tools_executed?.length || 0
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
return {
|
|
191
|
+
run: result.run,
|
|
192
|
+
completed: true,
|
|
193
|
+
output,
|
|
194
|
+
tools_executed: result.tools_executed || [],
|
|
195
|
+
retries: run.retries || 0
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
|
|
144
199
|
async runConversation({
|
|
145
200
|
threadId,
|
|
146
201
|
assistantId,
|
|
@@ -167,27 +222,23 @@ class OpenAIAssistantsProvider {
|
|
|
167
222
|
tools,
|
|
168
223
|
};
|
|
169
224
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
delete payload.tools;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
if (payload.metadata && Object.keys(payload.metadata).length === 0) {
|
|
179
|
-
delete payload.metadata;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
Object.keys(payload).forEach((key) => {
|
|
183
|
-
if (payload[key] === undefined || payload[key] === null) {
|
|
225
|
+
// Clean up empty/null values
|
|
226
|
+
Object.keys(payload).forEach(key => {
|
|
227
|
+
if (payload[key] === null || payload[key] === undefined ||
|
|
228
|
+
(Array.isArray(payload[key]) && payload[key].length === 0) ||
|
|
229
|
+
(payload[key] && typeof payload[key] === 'object' && Object.keys(payload[key]).length === 0)) {
|
|
184
230
|
delete payload[key];
|
|
185
231
|
}
|
|
186
232
|
});
|
|
187
233
|
|
|
188
|
-
|
|
234
|
+
const { result, retries } = await retryWithBackoff(() =>
|
|
189
235
|
this.client.beta.threads.runs.create(this._ensureId(threadId), payload)
|
|
190
|
-
);
|
|
236
|
+
, { providerName: PROVIDER_NAME });
|
|
237
|
+
|
|
238
|
+
return {
|
|
239
|
+
...result,
|
|
240
|
+
retries: retries
|
|
241
|
+
};
|
|
191
242
|
}
|
|
192
243
|
|
|
193
244
|
async getRun({ threadId, runId }) {
|
|
@@ -195,23 +246,6 @@ class OpenAIAssistantsProvider {
|
|
|
195
246
|
return run;
|
|
196
247
|
}
|
|
197
248
|
|
|
198
|
-
async listRuns({ threadId, limit, order = 'desc', activeOnly = false } = {}) {
|
|
199
|
-
const runs = await this.client.beta.threads.runs.list(this._ensureId(threadId), {
|
|
200
|
-
limit,
|
|
201
|
-
order,
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
if (activeOnly) {
|
|
205
|
-
const activeStatuses = ['in_progress', 'queued', 'requires_action'];
|
|
206
|
-
return {
|
|
207
|
-
...runs,
|
|
208
|
-
data: runs.data.filter((run) => activeStatuses.includes(run.status)),
|
|
209
|
-
};
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
return runs;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
249
|
async submitToolOutputs({ threadId, runId, toolOutputs }) {
|
|
216
250
|
return this.client.beta.threads.runs.submitToolOutputs(
|
|
217
251
|
this._ensureId(runId),
|
|
@@ -222,33 +256,6 @@ class OpenAIAssistantsProvider {
|
|
|
222
256
|
);
|
|
223
257
|
}
|
|
224
258
|
|
|
225
|
-
async cancelRun({ threadId, runId }) {
|
|
226
|
-
return this.client.beta.threads.runs.cancel(
|
|
227
|
-
this._ensureId(runId),
|
|
228
|
-
{ thread_id: this._ensureId(threadId) }
|
|
229
|
-
);
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
async createChatCompletion({ model, messages, temperature, maxTokens, topP, metadata, responseFormat } = {}) {
|
|
233
|
-
return this.client.chat.completions.create({
|
|
234
|
-
model: model || this.defaults.chatModel,
|
|
235
|
-
messages,
|
|
236
|
-
temperature,
|
|
237
|
-
max_tokens: maxTokens,
|
|
238
|
-
top_p: topP,
|
|
239
|
-
metadata,
|
|
240
|
-
response_format: responseFormat,
|
|
241
|
-
});
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
async uploadFile({ file, purpose }) {
|
|
245
|
-
if (!file) {
|
|
246
|
-
throw new Error('uploadFile requires a readable file stream or object');
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
return this.client.files.create({ file, purpose: purpose || 'assistants' });
|
|
250
|
-
}
|
|
251
|
-
|
|
252
259
|
async transcribeAudio({ file, model, language, responseFormat, temperature, prompt } = {}) {
|
|
253
260
|
return this.client.audio.transcriptions.create({
|
|
254
261
|
model: model || this.defaults.transcriptionModel,
|
|
@@ -292,46 +299,40 @@ class OpenAIAssistantsProvider {
|
|
|
292
299
|
return outputs;
|
|
293
300
|
}
|
|
294
301
|
|
|
295
|
-
async checkRunStatus(assistant,
|
|
302
|
+
async checkRunStatus(assistant, threadId, runId, attempt = 0, maxRetries = DEFAULT_MAX_RETRIES) {
|
|
303
|
+
if (attempt >= maxRetries) return { run: null, completed: false };
|
|
304
|
+
|
|
296
305
|
try {
|
|
297
|
-
const run = await this.getRun({ threadId
|
|
298
|
-
logger.info(`Status: ${run.status} ${
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
306
|
+
const run = await this.getRun({ threadId, runId });
|
|
307
|
+
logger.info(`Status: ${run.status} ${threadId} ${runId} (attempt ${attempt + 1})`);
|
|
308
|
+
|
|
309
|
+
if (['failed', 'expired', 'incomplete', 'errored'].includes(run.status)) {
|
|
310
|
+
logger.info(`Run failed: ${run.status}`);
|
|
311
|
+
return { run, completed: false };
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
if (['completed', 'succeeded'].includes(run.status)) {
|
|
315
|
+
logger.info('Run completed.');
|
|
316
|
+
return { run, completed: true };
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
if (run.status === 'cancelled') {
|
|
320
|
+
logger.info('Run cancelled');
|
|
321
|
+
return { run, completed: true };
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
if (run.status === 'requires_action') {
|
|
310
325
|
logger.info('requires_action');
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
}
|
|
314
|
-
if (!actionHandled) {
|
|
315
|
-
await this.handleRequiresAction(assistant, run, thread_id);
|
|
316
|
-
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
317
|
-
return this.checkRunStatus(assistant, thread_id, run_id, retryCount + 1, maxRetries, true);
|
|
318
|
-
} else {
|
|
319
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
320
|
-
return this.checkRunStatus(assistant, thread_id, run_id, retryCount + 1, maxRetries, actionHandled);
|
|
321
|
-
}
|
|
322
|
-
} else if (!['completed', 'succeeded'].includes(run.status)) {
|
|
323
|
-
if (retryCount >= maxRetries) {
|
|
324
|
-
return {run, completed: false};
|
|
325
|
-
}
|
|
326
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
327
|
-
return this.checkRunStatus(assistant, thread_id, run_id, retryCount + 1, maxRetries, actionHandled);
|
|
326
|
+
await this.handleRequiresAction(assistant, run, threadId);
|
|
327
|
+
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
328
328
|
} else {
|
|
329
|
-
|
|
330
|
-
return {run, completed: true};
|
|
329
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
331
330
|
}
|
|
331
|
+
|
|
332
|
+
return this.checkRunStatus(assistant, threadId, runId, attempt + 1, maxRetries);
|
|
332
333
|
} catch (error) {
|
|
333
334
|
logger.error('Error checking run status:', error);
|
|
334
|
-
return {run: null, completed: false};
|
|
335
|
+
return { run: null, completed: false };
|
|
335
336
|
}
|
|
336
337
|
}
|
|
337
338
|
|