feat: Implement Token Rates Configuration Loader and Update Config Types

This commit is contained in:
Ruben Talstra 2025-02-26 17:23:21 +01:00
parent e14df5956a
commit 7dfb386f5a
No known key found for this signature in database
GPG key ID: 2A5A7174A60F3BEA
3 changed files with 78 additions and 1 deletions

View file

@ -12,6 +12,7 @@ const { agentsConfigSetup } = require('./start/agents');
const { initializeRoles } = require('~/models/Role'); const { initializeRoles } = require('~/models/Role');
const { getMCPManager } = require('~/config'); const { getMCPManager } = require('~/config');
const paths = require('~/config/paths'); const paths = require('~/config/paths');
const { loadTokenRatesConfig } = require('./Config/loadTokenRatesConfig');
/** /**
* *
@ -21,9 +22,13 @@ const paths = require('~/config/paths');
*/ */
const AppService = async (app) => { const AppService = async (app) => {
await initializeRoles(); await initializeRoles();
/** @type {TCustomConfig}*/ /** @type {TCustomConfig} */
const config = (await loadCustomConfig()) ?? {}; const config = (await loadCustomConfig()) ?? {};
const configDefaults = getConfigDefaults(); const configDefaults = getConfigDefaults();
const tokenRatesConfig = loadTokenRatesConfig(config, configDefaults);
//
// // Set the global token rates configuration so that it can be used by the tx.js functions.
// setTokenRatesConfig(tokenRatesConfig);
const filteredTools = config.filteredTools; const filteredTools = config.filteredTools;
const includedTools = config.includedTools; const includedTools = config.includedTools;

View file

@ -0,0 +1,27 @@
const { removeNullishValues } = require('librechat-data-provider');
const { logger } = require('~/config');
/**
* Loads custom token rates from the user's YAML config, merging with default token rates if available.
*
* @param {TCustomConfig | undefined} config - The loaded custom configuration.
* @param {TConfigDefaults} [configDefaults] - Optional default configuration values.
* @returns {TCustomConfig['tokenRates']} - The final token rates configuration.
*/
function loadTokenRatesConfig(config, configDefaults) {
const userTokenRates = removeNullishValues(config?.tokenRates ?? {});
if (!configDefaults?.tokenRates) {
logger.info(`User tokenRates configuration:\n${JSON.stringify(userTokenRates, null, 2)}`);
return userTokenRates;
}
/** @type {TCustomConfig['tokenRates']} */
const defaultTokenRates = removeNullishValues(configDefaults.tokenRates);
const merged = { ...defaultTokenRates, ...userTokenRates };
logger.info(`Merged tokenRates configuration:\n${JSON.stringify(merged, null, 2)}`);
return merged;
}
module.exports = { loadTokenRatesConfig };

View file

@ -505,12 +505,56 @@ export type TStartupConfig = {
helpAndFaqURL: string; helpAndFaqURL: string;
customFooter?: string; customFooter?: string;
modelSpecs?: TSpecsConfig; modelSpecs?: TSpecsConfig;
tokenRates?: TTokenRates;
sharedLinksEnabled: boolean; sharedLinksEnabled: boolean;
publicSharedLinksEnabled: boolean; publicSharedLinksEnabled: boolean;
analyticsGtmId?: string; analyticsGtmId?: string;
instanceProjectId: string; instanceProjectId: string;
}; };
// Token cost schema type
export type TTokenCost = {
prompt?: number;
completion?: number;
cache?: {
write?: number;
read?: number;
};
};
// Endpoint token rates schema type
export type TEndpointTokenRates = Record<string, TTokenCost>;
// Token rates schema type
export type TTokenRates = {
openAI?: TEndpointTokenRates;
google?: TEndpointTokenRates;
anthropic?: TEndpointTokenRates;
bedrock?: TEndpointTokenRates;
custom?: TEndpointTokenRates;
};
const tokenCostSchema = z.object({
prompt: z.number().optional(), // e.g. 1.5 => $1.50 / 1M tokens
completion: z.number().optional(), // e.g. 2.0 => $2.00 / 1M tokens
cache: z
.object({
write: z.number().optional(),
read: z.number().optional(),
})
.optional(),
});
const endpointTokenRatesSchema = z.record(z.string(), tokenCostSchema);
const tokenRatesSchema = z.object({
openAI: endpointTokenRatesSchema.optional(),
google: endpointTokenRatesSchema.optional(),
anthropic: endpointTokenRatesSchema.optional(),
bedrock: endpointTokenRatesSchema.optional(),
custom: endpointTokenRatesSchema.optional(),
});
export const configSchema = z.object({ export const configSchema = z.object({
version: z.string(), version: z.string(),
cache: z.boolean().default(true), cache: z.boolean().default(true),
@ -542,6 +586,7 @@ export const configSchema = z.object({
rateLimits: rateLimitSchema.optional(), rateLimits: rateLimitSchema.optional(),
fileConfig: fileConfigSchema.optional(), fileConfig: fileConfigSchema.optional(),
modelSpecs: specsConfigSchema.optional(), modelSpecs: specsConfigSchema.optional(),
tokenRates: tokenRatesSchema.optional(),
endpoints: z endpoints: z
.object({ .object({
all: baseEndpointSchema.optional(), all: baseEndpointSchema.optional(),