diff --git a/client/src/common/types.ts b/client/src/common/types.ts index cd8b45f6b7..ab52bfb007 100644 --- a/client/src/common/types.ts +++ b/client/src/common/types.ts @@ -535,6 +535,7 @@ export type NewConversationParams = { buildDefault?: boolean; keepLatestMessage?: boolean; keepAddedConvos?: boolean; + disableParams?: boolean; }; export type ConvoGenerator = (params: NewConversationParams) => void | t.TConversation; diff --git a/client/src/components/Chat/Input/HeaderOptions.tsx b/client/src/components/Chat/Input/HeaderOptions.tsx index 2dcca3c1f2..ac4b039768 100644 --- a/client/src/components/Chat/Input/HeaderOptions.tsx +++ b/client/src/components/Chat/Input/HeaderOptions.tsx @@ -79,19 +79,19 @@ export default function HeaderOptions({ {!noSettings[endpoint] && interfaceConfig?.parameters === true && paramEndpoint === false && ( - - - - )} + + + + )} {interfaceConfig?.parameters === true && paramEndpoint === false && ( { diff --git a/client/src/hooks/Input/useQueryParams.ts b/client/src/hooks/Input/useQueryParams.ts index 53bd4bc9ae..52794a745d 100644 --- a/client/src/hooks/Input/useQueryParams.ts +++ b/client/src/hooks/Input/useQueryParams.ts @@ -258,35 +258,6 @@ export default function useQueryParams({ })(); }, [methods, submitMessage, conversation]); - useEffect(() => { - // Only proceed if we've already processed URL parameters but haven't yet handled submission - if ( - !processedRef.current || - submissionHandledRef.current || - settingsAppliedRef.current || - !validSettingsRef.current || - !conversation - ) { - return; - } - - const allSettingsApplied = areSettingsApplied(); - - if (allSettingsApplied) { - settingsAppliedRef.current = true; - - if (pendingSubmitRef.current) { - if (settingsTimeoutRef.current) { - clearTimeout(settingsTimeoutRef.current); - settingsTimeoutRef.current = null; - } - - console.log('Settings fully applied, processing submission'); - processSubmission(); - } - } - }, [conversation, processSubmission, areSettingsApplied]); - useEffect(() => { const processQueryParams = () => { const queryParams: Record = {}; @@ -332,14 +303,15 @@ export default function useQueryParams({ /** Mark processing as complete and clean up as needed */ const success = () => { - const currentParams = new URLSearchParams(searchParams.toString()); + const paramString = searchParams.toString(); + const currentParams = new URLSearchParams(paramString); currentParams.delete('prompt'); currentParams.delete('q'); currentParams.delete('submit'); setSearchParams(currentParams, { replace: true }); processedRef.current = true; - console.log('Parameters processed successfully'); + console.log('Parameters processed successfully', paramString); clearInterval(intervalId); // Only clean URL if there's no pending submission @@ -417,4 +389,33 @@ export default function useQueryParams({ queryClient, processSubmission, ]); + + useEffect(() => { + // Only proceed if we've already processed URL parameters but haven't yet handled submission + if ( + !processedRef.current || + submissionHandledRef.current || + settingsAppliedRef.current || + !validSettingsRef.current || + !conversation + ) { + return; + } + + const allSettingsApplied = areSettingsApplied(); + + if (allSettingsApplied) { + settingsAppliedRef.current = true; + + if (pendingSubmitRef.current) { + if (settingsTimeoutRef.current) { + clearTimeout(settingsTimeoutRef.current); + settingsTimeoutRef.current = null; + } + + console.log('Settings fully applied, processing submission'); + processSubmission(); + } + } + }, [conversation, processSubmission, areSettingsApplied]); } diff --git a/client/src/hooks/Input/useSelectMention.ts b/client/src/hooks/Input/useSelectMention.ts index af61447480..a5be633da0 100644 --- a/client/src/hooks/Input/useSelectMention.ts +++ b/client/src/hooks/Input/useSelectMention.ts @@ -225,6 +225,7 @@ export default function useSelectMention({ newPreset.iconURL = newPreset.iconURL ?? null; newPreset.modelLabel = newPreset.modelLabel ?? null; const isModular = isCurrentModular && isNewModular && shouldSwitch; + const disableParams = newPreset.defaultPreset === true; if (isExistingConversation && isModular) { template.endpointType = newEndpointType as EModelEndpoint | undefined; template.spec = null; @@ -244,12 +245,17 @@ export default function useSelectMention({ preset: newPreset, keepLatestMessage: true, keepAddedConvos: true, + disableParams, }); return; } logger.info('conversation', 'Switching conversation to new preset', template); - newConversation({ preset: newPreset, keepAddedConvos: isModular }); + newConversation({ + preset: newPreset, + keepAddedConvos: isModular, + disableParams, + }); }, [ modularChat, diff --git a/client/src/hooks/useNewConvo.ts b/client/src/hooks/useNewConvo.ts index 8867709a1e..ab2d177428 100644 --- a/client/src/hooks/useNewConvo.ts +++ b/client/src/hooks/useNewConvo.ts @@ -71,6 +71,7 @@ const useNewConvo = (index = 0) => { keepLatestMessage?: boolean, keepAddedConvos?: boolean, disableFocus?: boolean, + _disableParams?: boolean, ) => { const modelsConfig = modelsData ?? modelsQuery.data; const { endpoint = null } = conversation; @@ -87,6 +88,12 @@ const useNewConvo = (index = 0) => { ? defaultPreset : preset; + const disableParams = + _disableParams ?? + (activePreset?.presetId != null && + activePreset.presetId && + activePreset.presetId === defaultPreset?.presetId); + if (buildDefaultConversation) { let defaultEndpoint = getDefaultEndpoint({ convoSetup: activePreset ?? conversation, @@ -148,6 +155,10 @@ const useNewConvo = (index = 0) => { }); } + if (disableParams === true) { + conversation.disableParams = true; + } + if (!(keepAddedConvos ?? false)) { clearAllConversations(true); } @@ -160,7 +171,7 @@ const useNewConvo = (index = 0) => { ); setConversation({ ...conversation, - conversationId: 'new', + conversationId: Constants.NEW_CONVO as string, }); } else { logger.log('conversation', 'Setting conversation from `useNewConvo`', conversation); @@ -205,6 +216,7 @@ const useNewConvo = (index = 0) => { buildDefault = true, keepLatestMessage = false, keepAddedConvos = false, + disableParams, }: { template?: Partial; preset?: Partial; @@ -213,6 +225,7 @@ const useNewConvo = (index = 0) => { disableFocus?: boolean; keepLatestMessage?: boolean; keepAddedConvos?: boolean; + disableParams?: boolean; } = {}) { pauseGlobalAudio(); if (!saveBadgesState) { @@ -282,17 +295,19 @@ const useNewConvo = (index = 0) => { keepLatestMessage, keepAddedConvos, disableFocus, + disableParams, ); }, [ - pauseGlobalAudio, - startupConfig, - saveDrafts, - switchToConversation, files, setFiles, + saveDrafts, mutateAsync, resetBadges, + startupConfig, + saveBadgesState, + pauseGlobalAudio, + switchToConversation, ], ); diff --git a/client/src/store/families.ts b/client/src/store/families.ts index 37e2eaa3d2..947b77a428 100644 --- a/client/src/store/families.ts +++ b/client/src/store/families.ts @@ -106,10 +106,13 @@ const conversationByIndex = atomFamily({ JSON.stringify(newValue), ); + const disableParams = newValue.disableParams === true; const shouldUpdateParams = + index === 0 && + !disableParams && newValue.createdAt === '' && JSON.stringify(newValue) !== JSON.stringify(oldValue) && - (oldValue as TConversation)?.conversationId === 'new'; + (oldValue as TConversation)?.conversationId === Constants.NEW_CONVO; if (shouldUpdateParams) { const newParams = createChatSearchParams(newValue); @@ -299,10 +302,10 @@ const conversationByKeySelector = selectorFamily({ key: 'conversationByKeySelector', get: (index: string | number) => - ({ get }) => { - const conversation = get(conversationByIndex(index)); - return conversation; - }, + ({ get }) => { + const conversation = get(conversationByIndex(index)); + return conversation; + }, }); function useClearSubmissionState() { @@ -361,24 +364,24 @@ const updateConversationSelector = selectorFamily({ get: () => () => null as Partial | null, set: (conversationId: string) => - ({ set, get }, newPartialConversation) => { - if (newPartialConversation instanceof DefaultValue) { - return; - } + ({ set, get }, newPartialConversation) => { + if (newPartialConversation instanceof DefaultValue) { + return; + } - const keys = get(conversationKeysAtom); - keys.forEach((key) => { - set(conversationByIndex(key), (prevConversation) => { - if (prevConversation && prevConversation.conversationId === conversationId) { - return { - ...prevConversation, - ...newPartialConversation, - }; - } - return prevConversation; - }); + const keys = get(conversationKeysAtom); + keys.forEach((key) => { + set(conversationByIndex(key), (prevConversation) => { + if (prevConversation && prevConversation.conversationId === conversationId) { + return { + ...prevConversation, + ...newPartialConversation, + }; + } + return prevConversation; }); - }, + }); + }, }); export default { diff --git a/client/src/utils/createChatSearchParams.ts b/client/src/utils/createChatSearchParams.ts index a25ce284cf..c279a5e8ff 100644 --- a/client/src/utils/createChatSearchParams.ts +++ b/client/src/utils/createChatSearchParams.ts @@ -1,6 +1,12 @@ -import { isAgentsEndpoint, isAssistantsEndpoint, Constants } from 'librechat-data-provider'; +import { + Constants, + isAgentsEndpoint, + tQueryParamsSchema, + isAssistantsEndpoint, +} from 'librechat-data-provider'; import type { TConversation, TPreset } from 'librechat-data-provider'; +const allowedParams = Object.keys(tQueryParamsSchema.shape); export default function createChatSearchParams( input: TConversation | TPreset | Record | null, ): URLSearchParams { @@ -10,25 +16,6 @@ export default function createChatSearchParams( const params = new URLSearchParams(); - const allowedParams = [ - 'endpoint', - 'model', - 'temperature', - 'presence_penalty', - 'frequency_penalty', - 'stop', - 'top_p', - 'max_tokens', - 'topP', - 'topK', - 'maxOutputTokens', - 'promptCache', - 'region', - 'maxTokens', - 'agent_id', - 'assistant_id', - ]; - if (input && typeof input === 'object' && !('endpoint' in input) && !('model' in input)) { Object.entries(input as Record).forEach(([key, value]) => { if (value != null && allowedParams.includes(key)) { @@ -64,20 +51,15 @@ export default function createChatSearchParams( params.set('model', conversation.model); } - const paramMap = { - temperature: conversation.temperature, - presence_penalty: conversation.presence_penalty, - frequency_penalty: conversation.frequency_penalty, - stop: conversation.stop, - top_p: conversation.top_p, - max_tokens: conversation.max_tokens, - topP: conversation.topP, - topK: conversation.topK, - maxOutputTokens: conversation.maxOutputTokens, - promptCache: conversation.promptCache, - region: conversation.region, - maxTokens: conversation.maxTokens, - }; + const paramMap: Record = {}; + allowedParams.forEach((key) => { + if (key === 'agent_id' && conversation.agent_id === Constants.EPHEMERAL_AGENT_ID) { + return; + } + if (key !== 'endpoint' && key !== 'model') { + paramMap[key] = (conversation as any)[key]; + } + }); return Object.entries(paramMap).reduce((params, [key, value]) => { if (value != null) { diff --git a/package-lock.json b/package-lock.json index fd5e6ab75f..6d5d8b0d9d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -45306,7 +45306,7 @@ }, "packages/data-provider": { "name": "librechat-data-provider", - "version": "0.7.82", + "version": "0.7.83", "license": "ISC", "dependencies": { "axios": "^1.8.2", diff --git a/packages/data-provider/package.json b/packages/data-provider/package.json index 025dda23df..ca28fc2d4e 100644 --- a/packages/data-provider/package.json +++ b/packages/data-provider/package.json @@ -1,6 +1,6 @@ { "name": "librechat-data-provider", - "version": "0.7.82", + "version": "0.7.83", "description": "data services for librechat apps", "main": "dist/index.js", "module": "dist/index.es.js", diff --git a/packages/data-provider/src/config.ts b/packages/data-provider/src/config.ts index bdac70a0c6..817620494f 100644 --- a/packages/data-provider/src/config.ts +++ b/packages/data-provider/src/config.ts @@ -52,6 +52,7 @@ export const excludedKeys = new Set([ 'model', 'files', 'spec', + 'disableParams', ]); export enum SettingsViews { diff --git a/packages/data-provider/src/generate.ts b/packages/data-provider/src/generate.ts index 4a83c5aec6..c6a2eafbb0 100644 --- a/packages/data-provider/src/generate.ts +++ b/packages/data-provider/src/generate.ts @@ -358,7 +358,7 @@ export function validateSettingDefinitions(settings: SettingsConfiguration): voi // continue; } setting.includeInput = - setting.type === SettingTypes.Number ? setting.includeInput ?? true : false; // Default to true if type is number + setting.type === SettingTypes.Number ? (setting.includeInput ?? true) : false; // Default to true if type is number } if (setting.component === ComponentTypes.Slider && setting.type === SettingTypes.Number) { @@ -445,7 +445,8 @@ export function validateSettingDefinitions(settings: SettingsConfiguration): voi // Validate optionType and conversation schema if (setting.optionType !== OptionTypes.Custom) { - const conversationSchema = tConversationSchema.shape[setting.key as keyof TConversation]; + const conversationSchema = + tConversationSchema.shape[setting.key as keyof Omit]; if (!conversationSchema) { errors.push({ code: ZodIssueCode.custom, diff --git a/packages/data-provider/src/schemas.ts b/packages/data-provider/src/schemas.ts index d4f43785c6..d7fc2d23d8 100644 --- a/packages/data-provider/src/schemas.ts +++ b/packages/data-provider/src/schemas.ts @@ -745,6 +745,7 @@ export type TSetOption = ( export type TConversation = z.infer & { presetOverride?: Partial; + disableParams?: boolean; }; export const tSharedLinkSchema = z.object({