Skip to content

Commit

Permalink
🐛 fix: Ensure Default ModelSpecs Are Set Correctly (#5218)
Browse files Browse the repository at this point in the history
* 🐛 fix: default modelSpecs not being set

* feat: Add imageDetail parameter for OpenAI endpoints in tQueryParamsSchema

* feat: Implement processModelSpecs function to enhance model specs processing from configuration

* feat: Refactor configuration schemas and types for improved structure and clarity

* feat: Add append_current_datetime parameter to tQueryParamsSchema for enhanced endpoint functionality

* fix: Add endpointType to getSaveOptions and enhance endpoint handling in Settings component

* fix: Change endpointType to be nullable and optional in tConversationSchema for improved flexibility

* fix: allow save & submit for google endpoint
  • Loading branch information
danny-avila authored Jan 9, 2025
1 parent 916faf6 commit 69a9b8b
Show file tree
Hide file tree
Showing 15 changed files with 201 additions and 148 deletions.
1 change: 1 addition & 0 deletions api/app/clients/GoogleClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -862,6 +862,7 @@ class GoogleClient extends BaseClient {

getSaveOptions() {
return {
endpointType: null,
artifacts: this.options.artifacts,
promptPrefix: this.options.promptPrefix,
modelLabel: this.options.modelLabel,
Expand Down
3 changes: 2 additions & 1 deletion api/server/services/AppService.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const loadCustomConfig = require('./Config/loadCustomConfig');
const handleRateLimits = require('./Config/handleRateLimits');
const { loadDefaultInterface } = require('./start/interface');
const { azureConfigSetup } = require('./start/azureOpenAI');
const { processModelSpecs } = require('./start/modelSpecs');
const { loadAndFormatTools } = require('./ToolService');
const { agentsConfigSetup } = require('./start/agents');
const { initializeRoles } = require('~/models/Role');
Expand Down Expand Up @@ -122,9 +123,9 @@ const AppService = async (app) => {

app.locals = {
...defaultLocals,
modelSpecs: config.modelSpecs,
fileConfig: config?.fileConfig,
secureImageLinks: config?.secureImageLinks,
modelSpecs: processModelSpecs(endpoints, config.modelSpecs),
...endpointLocals,
};
};
Expand Down
61 changes: 61 additions & 0 deletions api/server/services/start/modelSpecs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
const { EModelEndpoint } = require('librechat-data-provider');
const { normalizeEndpointName } = require('~/server/utils');
const { logger } = require('~/config');

/**
* Sets up Model Specs from the config (`librechat.yaml`) file.
* @param {TCustomConfig['endpoints']} endpoints - The loaded custom configuration for endpoints.
* @param {TCustomConfig['modelSpecs'] | undefined} [modelSpecs] - The loaded custom configuration for model specs.
* @returns {TCustomConfig['modelSpecs'] | undefined} The processed model specs, if any.
*/
function processModelSpecs(endpoints, _modelSpecs) {
if (!_modelSpecs) {
return undefined;
}

/** @type {TCustomConfig['modelSpecs']['list']} */
const modelSpecs = [];
/** @type {TCustomConfig['modelSpecs']['list']} */
const list = _modelSpecs.list;

const customEndpoints = endpoints[EModelEndpoint.custom] ?? [];

for (const spec of list) {
if (EModelEndpoint[spec.preset.endpoint] && spec.preset.endpoint !== EModelEndpoint.custom) {
modelSpecs.push(spec);
continue;
} else if (spec.preset.endpoint === EModelEndpoint.custom) {
logger.warn(
`Model Spec with endpoint "${spec.preset.endpoint}" is not supported. You must specify the name of the custom endpoint (case-sensitive, as defined in your config). Skipping model spec...`,
);
continue;
}

const normalizedName = normalizeEndpointName(spec.preset.endpoint);
const endpoint = customEndpoints.find(
(customEndpoint) => normalizedName === normalizeEndpointName(customEndpoint.name),
);

if (!endpoint) {
logger.warn(`Model spec with endpoint "${spec.preset.endpoint}" was skipped: Endpoint not found in configuration. The \`endpoint\` value must exactly match either a system-defined endpoint or a custom endpoint defined by the user.
For more information, see the documentation at https://www.librechat.ai/docs/configuration/librechat_yaml/object_structure/model_specs#endpoint`);
continue;
}

modelSpecs.push({
...spec,
preset: {
...spec.preset,
endpoint: normalizedName,
},
});
}

return {
..._modelSpecs,
list: modelSpecs,
};
}

module.exports = { processModelSpecs };
9 changes: 2 additions & 7 deletions client/src/components/Chat/Messages/Content/EditMessage.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { useRecoilState, useRecoilValue } from 'recoil';
import { EModelEndpoint } from 'librechat-data-provider';
import { useRef, useEffect, useCallback } from 'react';
import { useRecoilState, useRecoilValue } from 'recoil';
import { useForm } from 'react-hook-form';
import { useUpdateMessageMutation } from 'librechat-data-provider/react-query';
import type { TEditProps } from '~/common';
Expand Down Expand Up @@ -31,8 +30,6 @@ const EditMessage = ({
const textAreaRef = useRef<HTMLTextAreaElement | null>(null);

const { conversationId, parentMessageId, messageId } = message;
const { endpoint: _endpoint, endpointType } = conversation ?? { endpoint: null };
const endpoint = endpointType ?? _endpoint;
const updateMessageMutation = useUpdateMessageMutation(conversationId ?? '');
const localize = useLocalize();

Expand Down Expand Up @@ -181,9 +178,7 @@ const EditMessage = ({
<button
ref={submitButtonRef}
className="btn btn-primary relative mr-2"
disabled={
isSubmitting || (endpoint === EModelEndpoint.google && !message.isCreatedByUser)
}
disabled={isSubmitting}
onClick={handleSubmit(resubmitMessage)}
>
{localize('com_ui_save_submit')}
Expand Down
18 changes: 10 additions & 8 deletions client/src/components/Endpoints/EndpointSettings.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { useRecoilValue } from 'recoil';
import { SettingsViews } from 'librechat-data-provider';
import { useGetModelsQuery } from 'librechat-data-provider/react-query';
import { SettingsViews, TConversation } from 'librechat-data-provider';
import { useGetModelsQuery, useGetEndpointsQuery } from 'librechat-data-provider/react-query';
import type { TSettingsProps } from '~/common';
import { getSettings } from './Settings';
import { cn } from '~/utils';
import { cn, getEndpointField } from '~/utils';
import store from '~/store';

export default function Settings({
Expand All @@ -13,15 +13,17 @@ export default function Settings({
className = '',
}: TSettingsProps) {
const modelsQuery = useGetModelsQuery();
const { data: endpointsConfig } = useGetEndpointsQuery();
const currentSettingsView = useRecoilValue(store.currentSettingsView);
if (!conversation?.endpoint || currentSettingsView !== SettingsViews.default) {
const endpointType = getEndpointField(endpointsConfig, conversation?.endpoint ?? '', 'type');
const endpoint = endpointType ?? conversation?.endpoint ?? '';
if (!endpoint || currentSettingsView !== SettingsViews.default) {
return null;
}

const { settings, multiViewSettings } = getSettings();
const { endpoint: _endpoint, endpointType } = conversation;
const models = modelsQuery?.data?.[_endpoint] ?? [];
const endpoint = endpointType ?? _endpoint;
const { endpoint: _endpoint } = conversation as TConversation;
const models = modelsQuery.data?.[_endpoint ?? ''] ?? [];
const OptionComponent = settings[endpoint];

if (OptionComponent) {
Expand All @@ -39,7 +41,7 @@ export default function Settings({

const MultiViewComponent = multiViewSettings[endpoint];

if (!MultiViewComponent) {
if (MultiViewComponent == null) {
return null;
}

Expand Down
2 changes: 1 addition & 1 deletion client/src/components/Endpoints/Settings/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import BedrockSettings from './Bedrock';
import BingAISettings from './BingAI';
import OpenAISettings from './OpenAI';

const settings: { [key: string]: FC<TModelSelectProps> } = {
const settings: { [key: string]: FC<TModelSelectProps> | undefined } = {
[EModelEndpoint.assistants]: AssistantsSettings,
[EModelEndpoint.azureAssistants]: AssistantsSettings,
[EModelEndpoint.agents]: OpenAISettings,
Expand Down
28 changes: 17 additions & 11 deletions client/src/hooks/Config/useAppStartup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { useRecoilState, useSetRecoilState } from 'recoil';
import { LocalStorageKeys } from 'librechat-data-provider';
import { useAvailablePluginsQuery } from 'librechat-data-provider/react-query';
import type { TStartupConfig, TPlugin, TUser } from 'librechat-data-provider';
import { data as modelSpecs } from '~/components/Chat/Menus/Models/fakeData';
import { mapPlugins, selectPlugins, processPlugins } from '~/utils';
import useConfigOverride from './useConfigOverride';
import store from '~/store';
Expand Down Expand Up @@ -36,18 +35,22 @@ export default function useAppStartup({

/** Set the app title */
useEffect(() => {
if (startupConfig?.appTitle) {
document.title = startupConfig.appTitle;
localStorage.setItem(LocalStorageKeys.APP_TITLE, startupConfig.appTitle);
const appTitle = startupConfig?.appTitle ?? '';
if (!appTitle) {
return;
}
document.title = appTitle;
localStorage.setItem(LocalStorageKeys.APP_TITLE, appTitle);
}, [startupConfig]);

/** Set the default spec's preset as default */
useEffect(() => {
if (defaultPreset && defaultPreset.spec) {
if (defaultPreset && defaultPreset.spec != null) {
return;
}

const modelSpecs = startupConfig?.modelSpecs?.list;

if (!modelSpecs || !modelSpecs.length) {
return;
}
Expand All @@ -63,7 +66,7 @@ export default function useAppStartup({
iconURL: defaultSpec.iconURL,
spec: defaultSpec.name,
});
}, [defaultPreset, setDefaultPreset]);
}, [defaultPreset, setDefaultPreset, startupConfig?.modelSpecs?.list]);

/** Set the available Plugins */
useEffect(() => {
Expand All @@ -75,17 +78,20 @@ export default function useAppStartup({
return;
}

if (!user.plugins || user.plugins.length === 0) {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
const userPlugins = user.plugins ?? [];

if (userPlugins.length === 0) {
setAvailableTools({ pluginStore });
return;
}

const tools = [...user.plugins]
const tools = [...userPlugins]
.map((el) => allPlugins.map[el])
.filter((el): el is TPlugin => el !== undefined);
.filter((el: TPlugin | undefined): el is TPlugin => el !== undefined);

/* Filter Last Selected Tools */
const localStorageItem = localStorage.getItem(LocalStorageKeys.LAST_TOOLS);
const localStorageItem = localStorage.getItem(LocalStorageKeys.LAST_TOOLS) ?? '';
if (!localStorageItem) {
return setAvailableTools({ pluginStore, ...mapPlugins(tools) });
}
Expand All @@ -94,7 +100,7 @@ export default function useAppStartup({
.filter((tool: TPlugin) =>
tools.some((existingTool) => existingTool.pluginKey === tool.pluginKey),
)
.filter((tool: TPlugin) => !!tool);
.filter((tool: TPlugin | undefined) => !!tool);
localStorage.setItem(LocalStorageKeys.LAST_TOOLS, JSON.stringify(filteredTools));

setAvailableTools({ pluginStore, ...mapPlugins(tools) });
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/data-provider/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "librechat-data-provider",
"version": "0.7.691",
"version": "0.7.692",
"description": "data services for librechat apps",
"main": "dist/index.js",
"module": "dist/index.es.js",
Expand Down
Loading

0 comments on commit 69a9b8b

Please sign in to comment.