| | import { |
| | Constants, |
| | EModelEndpoint, |
| | defaultEndpoints, |
| | modularEndpoints, |
| | LocalStorageKeys, |
| | getEndpointField, |
| | isAgentsEndpoint, |
| | isAssistantsEndpoint, |
| | } from 'librechat-data-provider'; |
| | import type * as t from 'librechat-data-provider'; |
| | import type { LocalizeFunction, IconsRecord } from '~/common'; |
| |
|
| | export const getEntityName = ({ |
| | name = '', |
| | localize, |
| | isAgent, |
| | }: { |
| | name?: string; |
| | isAgent?: boolean; |
| | localize: LocalizeFunction; |
| | }) => { |
| | if (name && name.length > 0) { |
| | return name; |
| | } else { |
| | return isAgent === true ? localize('com_ui_agent') : localize('com_ui_assistant'); |
| | } |
| | }; |
| |
|
| | export const getEndpointsFilter = (endpointsConfig: t.TEndpointsConfig) => { |
| | const filter: Record<string, boolean> = {}; |
| | if (!endpointsConfig) { |
| | return filter; |
| | } |
| | for (const key of Object.keys(endpointsConfig)) { |
| | filter[key] = !!endpointsConfig[key]; |
| | } |
| | return filter; |
| | }; |
| |
|
| | export const getAvailableEndpoints = ( |
| | filter: Record<string, boolean>, |
| | endpointsConfig: t.TEndpointsConfig, |
| | ) => { |
| | const defaultSet = new Set(defaultEndpoints); |
| | const availableEndpoints: EModelEndpoint[] = []; |
| |
|
| | for (const endpoint in endpointsConfig) { |
| | |
| | if ( |
| | filter[endpoint] || |
| | (endpointsConfig[endpoint]?.type && |
| | defaultSet.has(endpointsConfig[endpoint]?.type as EModelEndpoint)) |
| | ) { |
| | availableEndpoints.push(endpoint as EModelEndpoint); |
| | } |
| | } |
| |
|
| | return availableEndpoints; |
| | }; |
| |
|
| | export function mapEndpoints(endpointsConfig: t.TEndpointsConfig) { |
| | const filter = getEndpointsFilter(endpointsConfig); |
| | return getAvailableEndpoints(filter, endpointsConfig).sort( |
| | (a, b) => (endpointsConfig?.[a]?.order ?? 0) - (endpointsConfig?.[b]?.order ?? 0), |
| | ); |
| | } |
| |
|
| | const firstLocalConvoKey = LocalStorageKeys.LAST_CONVO_SETUP + '_0'; |
| |
|
| | |
| | |
| | |
| | export function updateLastSelectedModel({ |
| | endpoint, |
| | model = '', |
| | }: { |
| | endpoint: string; |
| | model?: string; |
| | }) { |
| | if (!model) { |
| | return; |
| | } |
| | |
| | const lastConversationSetup = JSON.parse( |
| | (localStorage.getItem(firstLocalConvoKey) ?? '{}') || '{}', |
| | ); |
| |
|
| | if (lastConversationSetup.endpoint === endpoint) { |
| | lastConversationSetup.model = model; |
| | localStorage.setItem(firstLocalConvoKey, JSON.stringify(lastConversationSetup)); |
| | } |
| |
|
| | const lastSelectedModels = JSON.parse( |
| | (localStorage.getItem(LocalStorageKeys.LAST_MODEL) ?? '{}') || '{}', |
| | ); |
| | lastSelectedModels[endpoint] = model; |
| | localStorage.setItem(LocalStorageKeys.LAST_MODEL, JSON.stringify(lastSelectedModels)); |
| | } |
| |
|
| | interface ConversationInitParams { |
| | conversation: t.TConversation | null; |
| | newEndpoint: EModelEndpoint | string | null; |
| | endpointsConfig: t.TEndpointsConfig; |
| | modularChat?: boolean; |
| | } |
| |
|
| | interface InitiatedTemplateResult { |
| | template: Partial<t.TPreset>; |
| | shouldSwitch: boolean; |
| | isExistingConversation: boolean; |
| | isCurrentModular: boolean; |
| | isNewModular: boolean; |
| | newEndpointType: EModelEndpoint | undefined; |
| | } |
| |
|
| | |
| | export function getConvoSwitchLogic(params: ConversationInitParams): InitiatedTemplateResult { |
| | const { conversation, newEndpoint, endpointsConfig, modularChat = false } = params; |
| |
|
| | const currentEndpoint = conversation?.endpoint; |
| | const template: Partial<t.TPreset> = { |
| | ...conversation, |
| | endpoint: newEndpoint, |
| | conversationId: 'new', |
| | }; |
| |
|
| | const isAssistantSwitch = |
| | isAssistantsEndpoint(newEndpoint) && |
| | isAssistantsEndpoint(currentEndpoint) && |
| | currentEndpoint === newEndpoint; |
| |
|
| | const conversationId = conversation?.conversationId ?? ''; |
| | const isExistingConversation = !!(conversationId && conversationId !== 'new'); |
| |
|
| | const currentEndpointType = |
| | getEndpointField(endpointsConfig, currentEndpoint, 'type') ?? currentEndpoint; |
| | const newEndpointType = |
| | getEndpointField(endpointsConfig, newEndpoint, 'type') ?? |
| | (newEndpoint as EModelEndpoint | undefined); |
| |
|
| | const hasEndpoint = modularEndpoints.has(currentEndpoint ?? ''); |
| | const hasCurrentEndpointType = modularEndpoints.has(currentEndpointType ?? ''); |
| | const isCurrentModular = hasEndpoint || hasCurrentEndpointType || isAssistantSwitch; |
| |
|
| | const hasNewEndpoint = modularEndpoints.has(newEndpoint ?? ''); |
| | const hasNewEndpointType = modularEndpoints.has(newEndpointType ?? ''); |
| | const isNewModular = hasNewEndpoint || hasNewEndpointType || isAssistantSwitch; |
| |
|
| | const endpointsMatch = currentEndpoint === newEndpoint; |
| | const shouldSwitch = endpointsMatch || modularChat || isAssistantSwitch; |
| |
|
| | return { |
| | template, |
| | shouldSwitch, |
| | isExistingConversation, |
| | isCurrentModular, |
| | newEndpointType, |
| | isNewModular, |
| | }; |
| | } |
| |
|
| | export function getModelSpec({ |
| | specName, |
| | startupConfig, |
| | }: { |
| | specName?: string | null; |
| | startupConfig?: t.TStartupConfig; |
| | }): t.TModelSpec | undefined { |
| | if (!startupConfig || !specName) { |
| | return; |
| | } |
| | return startupConfig.modelSpecs?.list?.find((spec) => spec.name === specName); |
| | } |
| |
|
| | export function applyModelSpecEphemeralAgent({ |
| | convoId, |
| | modelSpec, |
| | updateEphemeralAgent, |
| | }: { |
| | convoId?: string | null; |
| | modelSpec?: t.TModelSpec; |
| | updateEphemeralAgent: ((convoId: string, agent: t.TEphemeralAgent | null) => void) | undefined; |
| | }) { |
| | if (!modelSpec || !updateEphemeralAgent) { |
| | return; |
| | } |
| | updateEphemeralAgent((convoId ?? Constants.NEW_CONVO) || Constants.NEW_CONVO, { |
| | mcp: modelSpec.mcpServers ?? [Constants.mcp_clear as string], |
| | web_search: modelSpec.webSearch ?? false, |
| | file_search: modelSpec.fileSearch ?? false, |
| | execute_code: modelSpec.executeCode ?? false, |
| | }); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | export function getDefaultModelSpec(startupConfig?: t.TStartupConfig): |
| | | { |
| | default?: t.TModelSpec; |
| | last?: t.TModelSpec; |
| | } |
| | | undefined { |
| | const { modelSpecs, interface: interfaceConfig } = startupConfig ?? {}; |
| | const { list, prioritize } = modelSpecs ?? {}; |
| | if (!list) { |
| | return; |
| | } |
| | const defaultSpec = list?.find((spec) => spec.default); |
| | if (prioritize === true || !interfaceConfig?.modelSelect) { |
| | const lastSelectedSpecName = localStorage.getItem(LocalStorageKeys.LAST_SPEC); |
| | const lastSelectedSpec = list?.find((spec) => spec.name === lastSelectedSpecName); |
| | return { default: defaultSpec || lastSelectedSpec || list?.[0] }; |
| | } else if (defaultSpec) { |
| | return { default: defaultSpec }; |
| | } |
| | const lastConversationSetup = JSON.parse( |
| | localStorage.getItem(LocalStorageKeys.LAST_CONVO_SETUP + '_0') ?? '{}', |
| | ); |
| | if (!lastConversationSetup.spec) { |
| | return; |
| | } |
| | return { last: list?.find((spec) => spec.name === lastConversationSetup.spec) }; |
| | } |
| |
|
| | export function getModelSpecPreset(modelSpec?: t.TModelSpec) { |
| | if (!modelSpec) { |
| | return; |
| | } |
| | return { |
| | ...modelSpec.preset, |
| | spec: modelSpec.name, |
| | iconURL: getModelSpecIconURL(modelSpec), |
| | }; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | export function getModelSpecIconURL(modelSpec: t.TModelSpec) { |
| | return modelSpec.iconURL ?? modelSpec.preset.iconURL ?? modelSpec.preset.endpoint ?? ''; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | export function getIconEndpoint({ |
| | endpointsConfig, |
| | iconURL, |
| | endpoint, |
| | }: { |
| | endpointsConfig?: t.TEndpointsConfig; |
| | iconURL?: string | null; |
| | endpoint?: string | null; |
| | }) { |
| | return (endpointsConfig?.[iconURL ?? ''] ? (iconURL ?? endpoint) : endpoint) ?? ''; |
| | } |
| |
|
| | |
| | export function getIconKey({ |
| | endpoint, |
| | endpointType: _eType, |
| | endpointsConfig, |
| | endpointIconURL: iconURL, |
| | }: { |
| | endpoint?: string | null; |
| | endpointsConfig?: t.TEndpointsConfig | null; |
| | endpointType?: string | null; |
| | endpointIconURL?: string; |
| | }): keyof IconsRecord { |
| | const endpointType = _eType ?? getEndpointField(endpointsConfig, endpoint, 'type') ?? ''; |
| | const endpointIconURL = iconURL ?? getEndpointField(endpointsConfig, endpoint, 'iconURL') ?? ''; |
| | if (endpointIconURL && EModelEndpoint[endpointIconURL] != null) { |
| | return endpointIconURL; |
| | } |
| | return endpointType ? 'unknown' : (endpoint ?? 'unknown'); |
| | } |
| |
|
| | export const getEntity = ({ |
| | endpoint, |
| | assistant_id, |
| | agent_id, |
| | agentsMap, |
| | assistantMap, |
| | }: { |
| | endpoint: EModelEndpoint | string | null | undefined; |
| | assistant_id: string | undefined; |
| | agent_id: string | undefined; |
| | agentsMap: t.TAgentsMap | undefined; |
| | assistantMap: t.TAssistantsMap | undefined; |
| | }): { |
| | entity: t.Agent | t.Assistant | undefined | null; |
| | isAgent: boolean; |
| | isAssistant: boolean; |
| | } => { |
| | const isAgent = isAgentsEndpoint(endpoint); |
| | const isAssistant = isAssistantsEndpoint(endpoint); |
| |
|
| | if (isAgent) { |
| | const agent = agentsMap?.[agent_id ?? '']; |
| | return { entity: agent, isAgent, isAssistant }; |
| | } else if (isAssistant) { |
| | const assistant = assistantMap?.[endpoint ?? '']?.[assistant_id ?? '']; |
| | return { entity: assistant, isAgent, isAssistant }; |
| | } |
| | return { entity: null, isAgent, isAssistant }; |
| | }; |
| |
|