mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-17 08:50:15 +01:00
* chore: bump anthropic SDK * chore: update anthropic config settings (fileSupport, default models) * feat: anthropic multi modal formatting * refactor: update vision models and use endpoint specific max long side resizing * feat(anthropic): multimodal messages, retry logic, and messages payload * chore: add more safety to trimming content due to whitespace error for assistant messages * feat(anthropic): token accounting and resending multiple images in progress * chore: bump data-provider * feat(anthropic): resendImages feature * chore: optimize Edit/Ask controllers, switch model back to req model * fix: false positive of invalid model * refactor(validateVisionModel): use object as arg, pass in additional/available models * refactor(validateModel): use helper function, `getModelsConfig` * feat: add modelsConfig to endpointOption so it gets passed to all clients, use for properly validating vision models * refactor: initialize default vision model and make sure it's available before assigning it * refactor(useSSE): avoid resetting model if user selected a new model between request and response * feat: show rate in transaction logging * fix: return tokenCountMap regardless of payload shape
134 lines
5.3 KiB
JavaScript
134 lines
5.3 KiB
JavaScript
const { EModelEndpoint } = require('librechat-data-provider');
|
|
const { HumanMessage, AIMessage, SystemMessage } = require('langchain/schema');
|
|
|
|
/**
|
|
* Formats a message to OpenAI Vision API payload format.
|
|
*
|
|
* @param {Object} params - The parameters for formatting.
|
|
* @param {Object} params.message - The message object to format.
|
|
* @param {string} [params.message.role] - The role of the message sender (must be 'user').
|
|
* @param {string} [params.message.content] - The text content of the message.
|
|
* @param {EModelEndpoint} [params.endpoint] - Identifier for specific endpoint handling
|
|
* @param {Array<string>} [params.image_urls] - The image_urls to attach to the message.
|
|
* @returns {(Object)} - The formatted message.
|
|
*/
|
|
const formatVisionMessage = ({ message, image_urls, endpoint }) => {
|
|
if (endpoint === EModelEndpoint.anthropic) {
|
|
message.content = [...image_urls, { type: 'text', text: message.content }];
|
|
return message;
|
|
}
|
|
|
|
message.content = [{ type: 'text', text: message.content }, ...image_urls];
|
|
|
|
return message;
|
|
};
|
|
|
|
/**
|
|
* Formats a message to OpenAI payload format based on the provided options.
|
|
*
|
|
* @param {Object} params - The parameters for formatting.
|
|
* @param {Object} params.message - The message object to format.
|
|
* @param {string} [params.message.role] - The role of the message sender (e.g., 'user', 'assistant').
|
|
* @param {string} [params.message._name] - The name associated with the message.
|
|
* @param {string} [params.message.sender] - The sender of the message.
|
|
* @param {string} [params.message.text] - The text content of the message.
|
|
* @param {string} [params.message.content] - The content of the message.
|
|
* @param {Array<string>} [params.message.image_urls] - The image_urls attached to the message for Vision API.
|
|
* @param {string} [params.userName] - The name of the user.
|
|
* @param {string} [params.assistantName] - The name of the assistant.
|
|
* @param {string} [params.endpoint] - Identifier for specific endpoint handling
|
|
* @param {boolean} [params.langChain=false] - Whether to return a LangChain message object.
|
|
* @returns {(Object|HumanMessage|AIMessage|SystemMessage)} - The formatted message.
|
|
*/
|
|
const formatMessage = ({ message, userName, assistantName, endpoint, langChain = false }) => {
|
|
let { role: _role, _name, sender, text, content: _content, lc_id } = message;
|
|
if (lc_id && lc_id[2] && !langChain) {
|
|
const roleMapping = {
|
|
SystemMessage: 'system',
|
|
HumanMessage: 'user',
|
|
AIMessage: 'assistant',
|
|
};
|
|
_role = roleMapping[lc_id[2]];
|
|
}
|
|
const role = _role ?? (sender && sender?.toLowerCase() === 'user' ? 'user' : 'assistant');
|
|
const content = text ?? _content ?? '';
|
|
const formattedMessage = {
|
|
role,
|
|
content,
|
|
};
|
|
|
|
const { image_urls } = message;
|
|
if (Array.isArray(image_urls) && image_urls.length > 0 && role === 'user') {
|
|
return formatVisionMessage({
|
|
message: formattedMessage,
|
|
image_urls: message.image_urls,
|
|
endpoint,
|
|
});
|
|
}
|
|
|
|
if (_name) {
|
|
formattedMessage.name = _name;
|
|
}
|
|
|
|
if (userName && formattedMessage.role === 'user') {
|
|
formattedMessage.name = userName;
|
|
}
|
|
|
|
if (assistantName && formattedMessage.role === 'assistant') {
|
|
formattedMessage.name = assistantName;
|
|
}
|
|
|
|
if (formattedMessage.name) {
|
|
// Conform to API regex: ^[a-zA-Z0-9_-]{1,64}$
|
|
// https://community.openai.com/t/the-format-of-the-name-field-in-the-documentation-is-incorrect/175684/2
|
|
formattedMessage.name = formattedMessage.name.replace(/[^a-zA-Z0-9_-]/g, '_');
|
|
|
|
if (formattedMessage.name.length > 64) {
|
|
formattedMessage.name = formattedMessage.name.substring(0, 64);
|
|
}
|
|
}
|
|
|
|
if (!langChain) {
|
|
return formattedMessage;
|
|
}
|
|
|
|
if (role === 'user') {
|
|
return new HumanMessage(formattedMessage);
|
|
} else if (role === 'assistant') {
|
|
return new AIMessage(formattedMessage);
|
|
} else {
|
|
return new SystemMessage(formattedMessage);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Formats an array of messages for LangChain.
|
|
*
|
|
* @param {Array<Object>} messages - The array of messages to format.
|
|
* @param {Object} formatOptions - The options for formatting each message.
|
|
* @param {string} [formatOptions.userName] - The name of the user.
|
|
* @param {string} [formatOptions.assistantName] - The name of the assistant.
|
|
* @returns {Array<(HumanMessage|AIMessage|SystemMessage)>} - The array of formatted LangChain messages.
|
|
*/
|
|
const formatLangChainMessages = (messages, formatOptions) =>
|
|
messages.map((msg) => formatMessage({ ...formatOptions, message: msg, langChain: true }));
|
|
|
|
/**
|
|
* Formats a LangChain message object by merging properties from `lc_kwargs` or `kwargs` and `additional_kwargs`.
|
|
*
|
|
* @param {Object} message - The message object to format.
|
|
* @param {Object} [message.lc_kwargs] - Contains properties to be merged. Either this or `message.kwargs` should be provided.
|
|
* @param {Object} [message.kwargs] - Contains properties to be merged. Either this or `message.lc_kwargs` should be provided.
|
|
* @param {Object} [message.kwargs.additional_kwargs] - Additional properties to be merged.
|
|
*
|
|
* @returns {Object} The formatted LangChain message.
|
|
*/
|
|
const formatFromLangChain = (message) => {
|
|
const { additional_kwargs, ...message_kwargs } = message.lc_kwargs ?? message.kwargs;
|
|
return {
|
|
...message_kwargs,
|
|
...additional_kwargs,
|
|
};
|
|
};
|
|
|
|
module.exports = { formatMessage, formatLangChainMessages, formatFromLangChain };
|