diff --git a/src/endpoints/backends/chat-completions.js b/src/endpoints/backends/chat-completions.js index 99b924b8c..34da7a77c 100644 --- a/src/endpoints/backends/chat-completions.js +++ b/src/endpoints/backends/chat-completions.js @@ -23,6 +23,7 @@ import { convertCohereMessages, convertMistralMessages, convertAI21Messages, + convertXAIMessages, mergeMessages, cachingAtDepthForOpenRouterClaude, cachingAtDepthForClaude, @@ -1159,6 +1160,7 @@ router.post('/generate', function (request, response) { apiKey = readSecret(request.user.directories, SECRET_KEYS.XAI); headers = {}; bodyParams = {}; + request.body.messages = convertXAIMessages(request.body.messages, getPromptNames(request)); } else { console.warn('This chat completion source is not supported yet.'); return response.status(400).send({ error: true }); diff --git a/src/prompt-converters.js b/src/prompt-converters.js index 633b8b81f..69769f0f9 100644 --- a/src/prompt-converters.js +++ b/src/prompt-converters.js @@ -679,6 +679,43 @@ export function convertMistralMessages(messages, names) { return messages; } +/** + * Convert a prompt from the messages objects to the format used by xAI. + * @param {object[]} messages Array of messages + * @param {PromptNames} names Prompt names + * @returns {object[]} Prompt for xAI + */ +export function convertXAIMessages(messages, names) { + if (!Array.isArray(messages)) { + return []; + } + + messages.forEach(msg => { + if (!msg.name || msg.role === 'user') { + return; + } + + const needsCharNamePrefix = [ + { role: 'assistant', condition: names.charName && !msg.content.startsWith(`${names.charName}: `) && !names.startsWithGroupName(msg.content) }, + { role: 'system', name: 'example_assistant', condition: names.charName && !msg.content.startsWith(`${names.charName}: `) && !names.startsWithGroupName(msg.content) }, + { role: 'system', name: 'example_user', condition: names.userName && !msg.content.startsWith(`${names.userName}: `) }, + ]; + + const matchingRule = needsCharNamePrefix.find(rule => + msg.role === rule.role && (!rule.name || msg.name === rule.name) && rule.condition, + ); + + if (matchingRule) { + const prefix = msg.role === 'system' && msg.name === 'example_user' ? names.userName : names.charName; + msg.content = `${prefix}: ${msg.content}`; + } + + delete msg.name; + }); + + return messages; +} + /** * Merge messages with the same consecutive role, removing names if they exist. * @param {any[]} messages Messages to merge