mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-09-22 08:12:00 +02:00
🐛 fix: Prevent Node Server Crash Due to Unhandled ChatCompletionMessage Error (#1278)
* refactor(addTitle): avoid generating title when a request was aborted * chore: bump openai to latest * fix: catch OpenAIError Uncaught error as last resort * fix: handle final messages excludes role=assistant * Update OpenAIClient.js * chore: fix linting errors
This commit is contained in:
parent
076a9b9b9c
commit
f1bc711cd7
7 changed files with 95 additions and 30 deletions
|
@ -771,6 +771,7 @@ ${convo}
|
|||
...opts,
|
||||
});
|
||||
|
||||
let UnexpectedRoleError = false;
|
||||
if (modelOptions.stream) {
|
||||
const stream = await openai.beta.chat.completions
|
||||
.stream({
|
||||
|
@ -782,6 +783,12 @@ ${convo}
|
|||
})
|
||||
.on('error', (err) => {
|
||||
handleOpenAIErrors(err, errorCallback, 'stream');
|
||||
})
|
||||
.on('finalMessage', (message) => {
|
||||
if (message?.role !== 'assistant') {
|
||||
stream.messages.push({ role: 'assistant', content: intermediateReply });
|
||||
UnexpectedRoleError = true;
|
||||
}
|
||||
});
|
||||
|
||||
for await (const chunk of stream) {
|
||||
|
@ -794,10 +801,12 @@ ${convo}
|
|||
}
|
||||
}
|
||||
|
||||
if (!UnexpectedRoleError) {
|
||||
chatCompletion = await stream.finalChatCompletion().catch((err) => {
|
||||
handleOpenAIErrors(err, errorCallback, 'finalChatCompletion');
|
||||
});
|
||||
}
|
||||
}
|
||||
// regular completion
|
||||
else {
|
||||
chatCompletion = await openai.chat.completions
|
||||
|
@ -809,7 +818,11 @@ ${convo}
|
|||
});
|
||||
}
|
||||
|
||||
if (!chatCompletion && error) {
|
||||
if (!chatCompletion && UnexpectedRoleError) {
|
||||
throw new Error(
|
||||
'OpenAIError: Invalid final message: OpenAI expects final message to include role=assistant',
|
||||
);
|
||||
} else if (!chatCompletion && error) {
|
||||
throw new Error(error);
|
||||
} else if (!chatCompletion) {
|
||||
throw new Error('Chat completion failed');
|
||||
|
@ -829,7 +842,9 @@ ${convo}
|
|||
return '';
|
||||
}
|
||||
if (
|
||||
err?.message?.includes('stream ended') ||
|
||||
err?.message?.includes(
|
||||
'OpenAIError: Invalid final message: OpenAI expects final message to include role=assistant',
|
||||
) ||
|
||||
err?.message?.includes('The server had an error processing your request') ||
|
||||
err?.message?.includes('missing finish_reason') ||
|
||||
(err instanceof OpenAI.OpenAIError && err?.message?.includes('missing finish_reason'))
|
||||
|
|
|
@ -17,17 +17,40 @@ class AzureAISearch extends StructuredTool {
|
|||
super();
|
||||
|
||||
// Initialize properties using helper function
|
||||
this.serviceEndpoint = this._initializeField(fields.AZURE_AI_SEARCH_SERVICE_ENDPOINT, 'AZURE_AI_SEARCH_SERVICE_ENDPOINT');
|
||||
this.indexName = this._initializeField(fields.AZURE_AI_SEARCH_INDEX_NAME, 'AZURE_AI_SEARCH_INDEX_NAME');
|
||||
this.serviceEndpoint = this._initializeField(
|
||||
fields.AZURE_AI_SEARCH_SERVICE_ENDPOINT,
|
||||
'AZURE_AI_SEARCH_SERVICE_ENDPOINT',
|
||||
);
|
||||
this.indexName = this._initializeField(
|
||||
fields.AZURE_AI_SEARCH_INDEX_NAME,
|
||||
'AZURE_AI_SEARCH_INDEX_NAME',
|
||||
);
|
||||
this.apiKey = this._initializeField(fields.AZURE_AI_SEARCH_API_KEY, 'AZURE_AI_SEARCH_API_KEY');
|
||||
this.apiVersion = this._initializeField(fields.AZURE_AI_SEARCH_API_VERSION, 'AZURE_AI_SEARCH_API_VERSION', AzureAISearch.DEFAULT_API_VERSION);
|
||||
this.queryType = this._initializeField(fields.AZURE_AI_SEARCH_SEARCH_OPTION_QUERY_TYPE, 'AZURE_AI_SEARCH_SEARCH_OPTION_QUERY_TYPE', AzureAISearch.DEFAULT_QUERY_TYPE);
|
||||
this.top = this._initializeField(fields.AZURE_AI_SEARCH_SEARCH_OPTION_TOP, 'AZURE_AI_SEARCH_SEARCH_OPTION_TOP', AzureAISearch.DEFAULT_TOP);
|
||||
this.select = this._initializeField(fields.AZURE_AI_SEARCH_SEARCH_OPTION_SELECT, 'AZURE_AI_SEARCH_SEARCH_OPTION_SELECT');
|
||||
this.apiVersion = this._initializeField(
|
||||
fields.AZURE_AI_SEARCH_API_VERSION,
|
||||
'AZURE_AI_SEARCH_API_VERSION',
|
||||
AzureAISearch.DEFAULT_API_VERSION,
|
||||
);
|
||||
this.queryType = this._initializeField(
|
||||
fields.AZURE_AI_SEARCH_SEARCH_OPTION_QUERY_TYPE,
|
||||
'AZURE_AI_SEARCH_SEARCH_OPTION_QUERY_TYPE',
|
||||
AzureAISearch.DEFAULT_QUERY_TYPE,
|
||||
);
|
||||
this.top = this._initializeField(
|
||||
fields.AZURE_AI_SEARCH_SEARCH_OPTION_TOP,
|
||||
'AZURE_AI_SEARCH_SEARCH_OPTION_TOP',
|
||||
AzureAISearch.DEFAULT_TOP,
|
||||
);
|
||||
this.select = this._initializeField(
|
||||
fields.AZURE_AI_SEARCH_SEARCH_OPTION_SELECT,
|
||||
'AZURE_AI_SEARCH_SEARCH_OPTION_SELECT',
|
||||
);
|
||||
|
||||
// Check for required fields
|
||||
if (!this.serviceEndpoint || !this.indexName || !this.apiKey) {
|
||||
throw new Error('Missing AZURE_AI_SEARCH_SERVICE_ENDPOINT, AZURE_AI_SEARCH_INDEX_NAME, or AZURE_AI_SEARCH_API_KEY environment variable.');
|
||||
throw new Error(
|
||||
'Missing AZURE_AI_SEARCH_SERVICE_ENDPOINT, AZURE_AI_SEARCH_INDEX_NAME, or AZURE_AI_SEARCH_API_KEY environment variable.',
|
||||
);
|
||||
}
|
||||
|
||||
// Create SearchClient
|
||||
|
@ -35,7 +58,7 @@ class AzureAISearch extends StructuredTool {
|
|||
this.serviceEndpoint,
|
||||
this.indexName,
|
||||
new AzureKeyCredential(this.apiKey),
|
||||
{ apiVersion: this.apiVersion }
|
||||
{ apiVersion: this.apiVersion },
|
||||
);
|
||||
|
||||
// Define schema
|
||||
|
|
|
@ -17,17 +17,40 @@ class AzureAISearch extends StructuredTool {
|
|||
super();
|
||||
|
||||
// Initialize properties using helper function
|
||||
this.serviceEndpoint = this._initializeField(fields.AZURE_AI_SEARCH_SERVICE_ENDPOINT, 'AZURE_AI_SEARCH_SERVICE_ENDPOINT');
|
||||
this.indexName = this._initializeField(fields.AZURE_AI_SEARCH_INDEX_NAME, 'AZURE_AI_SEARCH_INDEX_NAME');
|
||||
this.serviceEndpoint = this._initializeField(
|
||||
fields.AZURE_AI_SEARCH_SERVICE_ENDPOINT,
|
||||
'AZURE_AI_SEARCH_SERVICE_ENDPOINT',
|
||||
);
|
||||
this.indexName = this._initializeField(
|
||||
fields.AZURE_AI_SEARCH_INDEX_NAME,
|
||||
'AZURE_AI_SEARCH_INDEX_NAME',
|
||||
);
|
||||
this.apiKey = this._initializeField(fields.AZURE_AI_SEARCH_API_KEY, 'AZURE_AI_SEARCH_API_KEY');
|
||||
this.apiVersion = this._initializeField(fields.AZURE_AI_SEARCH_API_VERSION, 'AZURE_AI_SEARCH_API_VERSION', AzureAISearch.DEFAULT_API_VERSION);
|
||||
this.queryType = this._initializeField(fields.AZURE_AI_SEARCH_SEARCH_OPTION_QUERY_TYPE, 'AZURE_AI_SEARCH_SEARCH_OPTION_QUERY_TYPE', AzureAISearch.DEFAULT_QUERY_TYPE);
|
||||
this.top = this._initializeField(fields.AZURE_AI_SEARCH_SEARCH_OPTION_TOP, 'AZURE_AI_SEARCH_SEARCH_OPTION_TOP', AzureAISearch.DEFAULT_TOP);
|
||||
this.select = this._initializeField(fields.AZURE_AI_SEARCH_SEARCH_OPTION_SELECT, 'AZURE_AI_SEARCH_SEARCH_OPTION_SELECT');
|
||||
this.apiVersion = this._initializeField(
|
||||
fields.AZURE_AI_SEARCH_API_VERSION,
|
||||
'AZURE_AI_SEARCH_API_VERSION',
|
||||
AzureAISearch.DEFAULT_API_VERSION,
|
||||
);
|
||||
this.queryType = this._initializeField(
|
||||
fields.AZURE_AI_SEARCH_SEARCH_OPTION_QUERY_TYPE,
|
||||
'AZURE_AI_SEARCH_SEARCH_OPTION_QUERY_TYPE',
|
||||
AzureAISearch.DEFAULT_QUERY_TYPE,
|
||||
);
|
||||
this.top = this._initializeField(
|
||||
fields.AZURE_AI_SEARCH_SEARCH_OPTION_TOP,
|
||||
'AZURE_AI_SEARCH_SEARCH_OPTION_TOP',
|
||||
AzureAISearch.DEFAULT_TOP,
|
||||
);
|
||||
this.select = this._initializeField(
|
||||
fields.AZURE_AI_SEARCH_SEARCH_OPTION_SELECT,
|
||||
'AZURE_AI_SEARCH_SEARCH_OPTION_SELECT',
|
||||
);
|
||||
|
||||
// Check for required fields
|
||||
if (!this.serviceEndpoint || !this.indexName || !this.apiKey) {
|
||||
throw new Error('Missing AZURE_AI_SEARCH_SERVICE_ENDPOINT, AZURE_AI_SEARCH_INDEX_NAME, or AZURE_AI_SEARCH_API_KEY environment variable.');
|
||||
throw new Error(
|
||||
'Missing AZURE_AI_SEARCH_SERVICE_ENDPOINT, AZURE_AI_SEARCH_INDEX_NAME, or AZURE_AI_SEARCH_API_KEY environment variable.',
|
||||
);
|
||||
}
|
||||
|
||||
// Create SearchClient
|
||||
|
@ -35,7 +58,7 @@ class AzureAISearch extends StructuredTool {
|
|||
this.serviceEndpoint,
|
||||
this.indexName,
|
||||
new AzureKeyCredential(this.apiKey),
|
||||
{ apiVersion: this.apiVersion }
|
||||
{ apiVersion: this.apiVersion },
|
||||
);
|
||||
|
||||
// Define schema
|
||||
|
|
|
@ -59,7 +59,7 @@
|
|||
"multer": "^1.4.5-lts.1",
|
||||
"nodejs-gpt": "^1.37.4",
|
||||
"nodemailer": "^6.9.4",
|
||||
"openai": "^4.16.1",
|
||||
"openai": "^4.20.1",
|
||||
"openai-chat-tokens": "^0.2.8",
|
||||
"openid-client": "^5.4.2",
|
||||
"passport": "^0.6.0",
|
||||
|
|
|
@ -105,7 +105,7 @@ process.on('uncaughtException', (err) => {
|
|||
return;
|
||||
}
|
||||
|
||||
if (err.message.includes('OpenAIError')) {
|
||||
if (err.message.includes('OpenAIError') || err.message.includes('ChatCompletionMessage')) {
|
||||
console.error(
|
||||
'\n\nAn Uncaught `OpenAIError` error may be due to your reverse-proxy setup or stream configuration, or a bug in the `openai` node package.',
|
||||
);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
const { isEnabled } = require('../../../utils');
|
||||
const { saveConvo } = require('../../../../models');
|
||||
const { saveConvo } = require('~/models');
|
||||
const { isEnabled } = require('~/server/utils');
|
||||
|
||||
const addTitle = async (req, { text, response, client }) => {
|
||||
const { TITLE_CONVO = 'true' } = process.env ?? {};
|
||||
|
@ -7,6 +7,11 @@ const addTitle = async (req, { text, response, client }) => {
|
|||
return;
|
||||
}
|
||||
|
||||
// If the request was aborted, don't generate the title.
|
||||
if (client.abortController.signal.aborted) {
|
||||
return;
|
||||
}
|
||||
|
||||
const title = await client.titleConvo({ text, responseText: response?.text });
|
||||
await saveConvo(req.user.id, {
|
||||
conversationId: response.conversationId,
|
||||
|
|
9
package-lock.json
generated
9
package-lock.json
generated
|
@ -7,7 +7,6 @@
|
|||
"": {
|
||||
"name": "LibreChat",
|
||||
"version": "0.6.1",
|
||||
"hasInstallScript": true,
|
||||
"license": "ISC",
|
||||
"workspaces": [
|
||||
"api",
|
||||
|
@ -74,7 +73,7 @@
|
|||
"multer": "^1.4.5-lts.1",
|
||||
"nodejs-gpt": "^1.37.4",
|
||||
"nodemailer": "^6.9.4",
|
||||
"openai": "^4.16.1",
|
||||
"openai": "^4.20.1",
|
||||
"openai-chat-tokens": "^0.2.8",
|
||||
"openid-client": "^5.4.2",
|
||||
"passport": "^0.6.0",
|
||||
|
@ -18170,9 +18169,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/openai": {
|
||||
"version": "4.17.4",
|
||||
"resolved": "https://registry.npmjs.org/openai/-/openai-4.17.4.tgz",
|
||||
"integrity": "sha512-ThRFkl6snLbcAKS58St7N3CaKuI5WdYUvIjPvf4s+8SdymgNtOfzmZcZXVcCefx04oKFnvZJvIcTh3eAFUUhAQ==",
|
||||
"version": "4.20.1",
|
||||
"resolved": "https://registry.npmjs.org/openai/-/openai-4.20.1.tgz",
|
||||
"integrity": "sha512-Dd3q8EvINfganZFtg6V36HjrMaihqRgIcKiHua4Nq9aw/PxOP48dhbsk8x5klrxajt5Lpnc1KTOG5i1S6BKAJA==",
|
||||
"dependencies": {
|
||||
"@types/node": "^18.11.18",
|
||||
"@types/node-fetch": "^2.6.4",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue