| const { Telemetry } = require("../../models/telemetry"); |
| const { |
| SUPPORTED_CONNECTION_METHODS, |
| } = require("../AiProviders/bedrock/utils"); |
| const { resetAllVectorStores } = require("../vectorStore/resetAllVectorStores"); |
|
|
| const KEY_MAPPING = { |
| LLMProvider: { |
| envKey: "LLM_PROVIDER", |
| checks: [isNotEmpty, supportedLLM], |
| }, |
| |
| OpenAiKey: { |
| envKey: "OPEN_AI_KEY", |
| checks: [isNotEmpty, validOpenAIKey], |
| }, |
| OpenAiModelPref: { |
| envKey: "OPEN_MODEL_PREF", |
| checks: [isNotEmpty], |
| }, |
| |
| AzureOpenAiEndpoint: { |
| envKey: "AZURE_OPENAI_ENDPOINT", |
| checks: [isNotEmpty], |
| }, |
| AzureOpenAiTokenLimit: { |
| envKey: "AZURE_OPENAI_TOKEN_LIMIT", |
| checks: [validOpenAiTokenLimit], |
| }, |
| AzureOpenAiKey: { |
| envKey: "AZURE_OPENAI_KEY", |
| checks: [isNotEmpty], |
| }, |
| AzureOpenAiModelPref: { |
| envKey: "OPEN_MODEL_PREF", |
| checks: [isNotEmpty], |
| }, |
| AzureOpenAiEmbeddingModelPref: { |
| envKey: "EMBEDDING_MODEL_PREF", |
| checks: [isNotEmpty], |
| }, |
| AzureOpenAiModelType: { |
| envKey: "AZURE_OPENAI_MODEL_TYPE", |
| checks: [ |
| (input) => |
| ["default", "reasoning"].includes(input) |
| ? null |
| : "Invalid model type. Must be one of: default, reasoning.", |
| ], |
| }, |
|
|
| |
| AnthropicApiKey: { |
| envKey: "ANTHROPIC_API_KEY", |
| checks: [isNotEmpty, validAnthropicApiKey], |
| }, |
| AnthropicModelPref: { |
| envKey: "ANTHROPIC_MODEL_PREF", |
| checks: [isNotEmpty], |
| }, |
|
|
| GeminiLLMApiKey: { |
| envKey: "GEMINI_API_KEY", |
| checks: [isNotEmpty], |
| }, |
| GeminiLLMModelPref: { |
| envKey: "GEMINI_LLM_MODEL_PREF", |
| checks: [isNotEmpty], |
| }, |
| GeminiSafetySetting: { |
| envKey: "GEMINI_SAFETY_SETTING", |
| checks: [validGeminiSafetySetting], |
| }, |
|
|
| |
| LMStudioBasePath: { |
| envKey: "LMSTUDIO_BASE_PATH", |
| checks: [isNotEmpty, validLLMExternalBasePath, validDockerizedUrl], |
| }, |
| LMStudioModelPref: { |
| envKey: "LMSTUDIO_MODEL_PREF", |
| checks: [], |
| }, |
| LMStudioTokenLimit: { |
| envKey: "LMSTUDIO_MODEL_TOKEN_LIMIT", |
| checks: [nonZero], |
| }, |
|
|
| |
| LocalAiBasePath: { |
| envKey: "LOCAL_AI_BASE_PATH", |
| checks: [isNotEmpty, validLLMExternalBasePath, validDockerizedUrl], |
| }, |
| LocalAiModelPref: { |
| envKey: "LOCAL_AI_MODEL_PREF", |
| checks: [], |
| }, |
| LocalAiTokenLimit: { |
| envKey: "LOCAL_AI_MODEL_TOKEN_LIMIT", |
| checks: [nonZero], |
| }, |
| LocalAiApiKey: { |
| envKey: "LOCAL_AI_API_KEY", |
| checks: [], |
| }, |
|
|
| OllamaLLMBasePath: { |
| envKey: "OLLAMA_BASE_PATH", |
| checks: [isNotEmpty, validOllamaLLMBasePath, validDockerizedUrl], |
| }, |
| OllamaLLMModelPref: { |
| envKey: "OLLAMA_MODEL_PREF", |
| checks: [], |
| }, |
| OllamaLLMTokenLimit: { |
| envKey: "OLLAMA_MODEL_TOKEN_LIMIT", |
| checks: [nonZero], |
| }, |
| OllamaLLMPerformanceMode: { |
| envKey: "OLLAMA_PERFORMANCE_MODE", |
| checks: [], |
| }, |
| OllamaLLMKeepAliveSeconds: { |
| envKey: "OLLAMA_KEEP_ALIVE_TIMEOUT", |
| checks: [isInteger], |
| }, |
| OllamaLLMAuthToken: { |
| envKey: "OLLAMA_AUTH_TOKEN", |
| checks: [], |
| }, |
|
|
| |
| MistralApiKey: { |
| envKey: "MISTRAL_API_KEY", |
| checks: [isNotEmpty], |
| }, |
| MistralModelPref: { |
| envKey: "MISTRAL_MODEL_PREF", |
| checks: [isNotEmpty], |
| }, |
|
|
| |
| HuggingFaceLLMEndpoint: { |
| envKey: "HUGGING_FACE_LLM_ENDPOINT", |
| checks: [isNotEmpty, isValidURL, validHuggingFaceEndpoint], |
| }, |
| HuggingFaceLLMAccessToken: { |
| envKey: "HUGGING_FACE_LLM_API_KEY", |
| checks: [isNotEmpty], |
| }, |
| HuggingFaceLLMTokenLimit: { |
| envKey: "HUGGING_FACE_LLM_TOKEN_LIMIT", |
| checks: [nonZero], |
| }, |
|
|
| |
| KoboldCPPBasePath: { |
| envKey: "KOBOLD_CPP_BASE_PATH", |
| checks: [isNotEmpty, isValidURL], |
| }, |
| KoboldCPPModelPref: { |
| envKey: "KOBOLD_CPP_MODEL_PREF", |
| checks: [isNotEmpty], |
| }, |
| KoboldCPPTokenLimit: { |
| envKey: "KOBOLD_CPP_MODEL_TOKEN_LIMIT", |
| checks: [nonZero], |
| }, |
| KoboldCPPMaxTokens: { |
| envKey: "KOBOLD_CPP_MAX_TOKENS", |
| checks: [nonZero], |
| }, |
|
|
| |
| TextGenWebUIBasePath: { |
| envKey: "TEXT_GEN_WEB_UI_BASE_PATH", |
| checks: [isValidURL], |
| }, |
| TextGenWebUITokenLimit: { |
| envKey: "TEXT_GEN_WEB_UI_MODEL_TOKEN_LIMIT", |
| checks: [nonZero], |
| }, |
| TextGenWebUIAPIKey: { |
| envKey: "TEXT_GEN_WEB_UI_API_KEY", |
| checks: [], |
| }, |
|
|
| |
| LiteLLMModelPref: { |
| envKey: "LITE_LLM_MODEL_PREF", |
| checks: [isNotEmpty], |
| }, |
| LiteLLMTokenLimit: { |
| envKey: "LITE_LLM_MODEL_TOKEN_LIMIT", |
| checks: [nonZero], |
| }, |
| LiteLLMBasePath: { |
| envKey: "LITE_LLM_BASE_PATH", |
| checks: [isValidURL], |
| }, |
| LiteLLMApiKey: { |
| envKey: "LITE_LLM_API_KEY", |
| checks: [], |
| }, |
|
|
| |
| GenericOpenAiBasePath: { |
| envKey: "GENERIC_OPEN_AI_BASE_PATH", |
| checks: [isValidURL], |
| }, |
| GenericOpenAiModelPref: { |
| envKey: "GENERIC_OPEN_AI_MODEL_PREF", |
| checks: [isNotEmpty], |
| }, |
| GenericOpenAiTokenLimit: { |
| envKey: "GENERIC_OPEN_AI_MODEL_TOKEN_LIMIT", |
| checks: [nonZero], |
| }, |
| GenericOpenAiKey: { |
| envKey: "GENERIC_OPEN_AI_API_KEY", |
| checks: [], |
| }, |
| GenericOpenAiMaxTokens: { |
| envKey: "GENERIC_OPEN_AI_MAX_TOKENS", |
| checks: [nonZero], |
| }, |
|
|
| |
| AwsBedrockLLMConnectionMethod: { |
| envKey: "AWS_BEDROCK_LLM_CONNECTION_METHOD", |
| checks: [ |
| (input) => |
| SUPPORTED_CONNECTION_METHODS.includes(input) ? null : "invalid Value", |
| ], |
| }, |
| AwsBedrockLLMAccessKeyId: { |
| envKey: "AWS_BEDROCK_LLM_ACCESS_KEY_ID", |
| checks: [isNotEmpty], |
| }, |
| AwsBedrockLLMAccessKey: { |
| envKey: "AWS_BEDROCK_LLM_ACCESS_KEY", |
| checks: [isNotEmpty], |
| }, |
| AwsBedrockLLMSessionToken: { |
| envKey: "AWS_BEDROCK_LLM_SESSION_TOKEN", |
| checks: [], |
| }, |
| AwsBedrockLLMRegion: { |
| envKey: "AWS_BEDROCK_LLM_REGION", |
| checks: [isNotEmpty], |
| }, |
| AwsBedrockLLMModel: { |
| envKey: "AWS_BEDROCK_LLM_MODEL_PREFERENCE", |
| checks: [isNotEmpty], |
| }, |
| AwsBedrockLLMTokenLimit: { |
| envKey: "AWS_BEDROCK_LLM_MODEL_TOKEN_LIMIT", |
| checks: [nonZero], |
| }, |
| AwsBedrockLLMMaxOutputTokens: { |
| envKey: "AWS_BEDROCK_LLM_MAX_OUTPUT_TOKENS", |
| checks: [nonZero], |
| }, |
|
|
| |
| DellProAiStudioBasePath: { |
| envKey: "DPAIS_LLM_BASE_PATH", |
| checks: [isNotEmpty, validDockerizedUrl], |
| }, |
| DellProAiStudioModelPref: { |
| envKey: "DPAIS_LLM_MODEL_PREF", |
| checks: [isNotEmpty], |
| }, |
| DellProAiStudioTokenLimit: { |
| envKey: "DPAIS_LLM_MODEL_TOKEN_LIMIT", |
| checks: [nonZero], |
| }, |
|
|
| EmbeddingEngine: { |
| envKey: "EMBEDDING_ENGINE", |
| checks: [supportedEmbeddingModel], |
| postUpdate: [handleVectorStoreReset], |
| }, |
| EmbeddingBasePath: { |
| envKey: "EMBEDDING_BASE_PATH", |
| checks: [isNotEmpty, validDockerizedUrl], |
| }, |
| EmbeddingModelPref: { |
| envKey: "EMBEDDING_MODEL_PREF", |
| checks: [isNotEmpty], |
| postUpdate: [handleVectorStoreReset, downloadEmbeddingModelIfRequired], |
| }, |
| EmbeddingModelMaxChunkLength: { |
| envKey: "EMBEDDING_MODEL_MAX_CHUNK_LENGTH", |
| checks: [nonZero], |
| }, |
|
|
| |
| GeminiEmbeddingApiKey: { |
| envKey: "GEMINI_EMBEDDING_API_KEY", |
| checks: [isNotEmpty], |
| }, |
|
|
| |
| GenericOpenAiEmbeddingApiKey: { |
| envKey: "GENERIC_OPEN_AI_EMBEDDING_API_KEY", |
| checks: [], |
| }, |
| GenericOpenAiEmbeddingMaxConcurrentChunks: { |
| envKey: "GENERIC_OPEN_AI_EMBEDDING_MAX_CONCURRENT_CHUNKS", |
| checks: [nonZero], |
| }, |
|
|
| |
| VectorDB: { |
| envKey: "VECTOR_DB", |
| checks: [isNotEmpty, supportedVectorDB], |
| postUpdate: [handleVectorStoreReset], |
| }, |
|
|
| |
| ChromaEndpoint: { |
| envKey: "CHROMA_ENDPOINT", |
| checks: [isValidURL, validChromaURL, validDockerizedUrl], |
| }, |
| ChromaApiHeader: { |
| envKey: "CHROMA_API_HEADER", |
| checks: [], |
| }, |
| ChromaApiKey: { |
| envKey: "CHROMA_API_KEY", |
| checks: [], |
| }, |
|
|
| |
| ChromaCloudApiKey: { |
| envKey: "CHROMACLOUD_API_KEY", |
| checks: [isNotEmpty], |
| }, |
| ChromaCloudTenant: { |
| envKey: "CHROMACLOUD_TENANT", |
| checks: [isNotEmpty], |
| }, |
| ChromaCloudDatabase: { |
| envKey: "CHROMACLOUD_DATABASE", |
| checks: [isNotEmpty], |
| }, |
|
|
| |
| WeaviateEndpoint: { |
| envKey: "WEAVIATE_ENDPOINT", |
| checks: [isValidURL, validDockerizedUrl], |
| }, |
| WeaviateApiKey: { |
| envKey: "WEAVIATE_API_KEY", |
| checks: [], |
| }, |
|
|
| |
| QdrantEndpoint: { |
| envKey: "QDRANT_ENDPOINT", |
| checks: [isValidURL, validDockerizedUrl], |
| }, |
| QdrantApiKey: { |
| envKey: "QDRANT_API_KEY", |
| checks: [], |
| }, |
| PineConeKey: { |
| envKey: "PINECONE_API_KEY", |
| checks: [], |
| }, |
| PineConeIndex: { |
| envKey: "PINECONE_INDEX", |
| checks: [], |
| }, |
|
|
| |
| MilvusAddress: { |
| envKey: "MILVUS_ADDRESS", |
| checks: [isValidURL, validDockerizedUrl], |
| }, |
| MilvusUsername: { |
| envKey: "MILVUS_USERNAME", |
| checks: [isNotEmpty], |
| }, |
| MilvusPassword: { |
| envKey: "MILVUS_PASSWORD", |
| checks: [isNotEmpty], |
| }, |
|
|
| |
| ZillizEndpoint: { |
| envKey: "ZILLIZ_ENDPOINT", |
| checks: [isValidURL], |
| }, |
| ZillizApiToken: { |
| envKey: "ZILLIZ_API_TOKEN", |
| checks: [isNotEmpty], |
| }, |
|
|
| |
| AstraDBApplicationToken: { |
| envKey: "ASTRA_DB_APPLICATION_TOKEN", |
| checks: [isNotEmpty], |
| }, |
| AstraDBEndpoint: { |
| envKey: "ASTRA_DB_ENDPOINT", |
| checks: [isNotEmpty], |
| }, |
|
|
| |
| |
| |
| |
| |
| |
| PGVectorConnectionString: { |
| envKey: "PGVECTOR_CONNECTION_STRING", |
| checks: [isNotEmpty, looksLikePostgresConnectionString], |
| preUpdate: [validatePGVectorConnectionString], |
| }, |
| PGVectorTableName: { |
| envKey: "PGVECTOR_TABLE_NAME", |
| checks: [isNotEmpty], |
| preUpdate: [validatePGVectorTableName], |
| }, |
|
|
| |
| TogetherAiApiKey: { |
| envKey: "TOGETHER_AI_API_KEY", |
| checks: [isNotEmpty], |
| }, |
| TogetherAiModelPref: { |
| envKey: "TOGETHER_AI_MODEL_PREF", |
| checks: [isNotEmpty], |
| }, |
|
|
| |
| FireworksAiLLMApiKey: { |
| envKey: "FIREWORKS_AI_LLM_API_KEY", |
| checks: [isNotEmpty], |
| }, |
| FireworksAiLLMModelPref: { |
| envKey: "FIREWORKS_AI_LLM_MODEL_PREF", |
| checks: [isNotEmpty], |
| }, |
|
|
| |
| PerplexityApiKey: { |
| envKey: "PERPLEXITY_API_KEY", |
| checks: [isNotEmpty], |
| }, |
| PerplexityModelPref: { |
| envKey: "PERPLEXITY_MODEL_PREF", |
| checks: [isNotEmpty], |
| }, |
|
|
| |
| OpenRouterApiKey: { |
| envKey: "OPENROUTER_API_KEY", |
| checks: [isNotEmpty], |
| }, |
| OpenRouterModelPref: { |
| envKey: "OPENROUTER_MODEL_PREF", |
| checks: [isNotEmpty], |
| }, |
| OpenRouterTimeout: { |
| envKey: "OPENROUTER_TIMEOUT_MS", |
| checks: [], |
| }, |
|
|
| |
| NovitaLLMApiKey: { |
| envKey: "NOVITA_LLM_API_KEY", |
| checks: [isNotEmpty], |
| }, |
| NovitaLLMModelPref: { |
| envKey: "NOVITA_LLM_MODEL_PREF", |
| checks: [isNotEmpty], |
| }, |
| NovitaLLMTimeout: { |
| envKey: "NOVITA_LLM_TIMEOUT_MS", |
| checks: [], |
| }, |
|
|
| |
| GroqApiKey: { |
| envKey: "GROQ_API_KEY", |
| checks: [isNotEmpty], |
| }, |
| GroqModelPref: { |
| envKey: "GROQ_MODEL_PREF", |
| checks: [isNotEmpty], |
| }, |
|
|
| |
| CohereApiKey: { |
| envKey: "COHERE_API_KEY", |
| checks: [isNotEmpty], |
| }, |
| CohereModelPref: { |
| envKey: "COHERE_MODEL_PREF", |
| checks: [isNotEmpty], |
| }, |
|
|
| |
| VoyageAiApiKey: { |
| envKey: "VOYAGEAI_API_KEY", |
| checks: [isNotEmpty], |
| }, |
|
|
| |
| WhisperProvider: { |
| envKey: "WHISPER_PROVIDER", |
| checks: [isNotEmpty, supportedTranscriptionProvider], |
| postUpdate: [], |
| }, |
| WhisperModelPref: { |
| envKey: "WHISPER_MODEL_PREF", |
| checks: [validLocalWhisper], |
| postUpdate: [], |
| }, |
|
|
| |
| AuthToken: { |
| envKey: "AUTH_TOKEN", |
| checks: [requiresForceMode, noRestrictedChars], |
| }, |
| JWTSecret: { |
| envKey: "JWT_SECRET", |
| checks: [requiresForceMode], |
| }, |
| DisableTelemetry: { |
| envKey: "DISABLE_TELEMETRY", |
| checks: [], |
| preUpdate: [ |
| (_, __, nextValue) => { |
| if (nextValue === "true") Telemetry.sendTelemetry("telemetry_disabled"); |
| }, |
| ], |
| }, |
|
|
| |
| AgentGoogleSearchEngineId: { |
| envKey: "AGENT_GSE_CTX", |
| checks: [], |
| }, |
| AgentGoogleSearchEngineKey: { |
| envKey: "AGENT_GSE_KEY", |
| checks: [], |
| }, |
| AgentSearchApiKey: { |
| envKey: "AGENT_SEARCHAPI_API_KEY", |
| checks: [], |
| }, |
| AgentSearchApiEngine: { |
| envKey: "AGENT_SEARCHAPI_ENGINE", |
| checks: [], |
| }, |
| AgentSerperApiKey: { |
| envKey: "AGENT_SERPER_DEV_KEY", |
| checks: [], |
| }, |
| AgentBingSearchApiKey: { |
| envKey: "AGENT_BING_SEARCH_API_KEY", |
| checks: [], |
| }, |
| AgentSerplyApiKey: { |
| envKey: "AGENT_SERPLY_API_KEY", |
| checks: [], |
| }, |
| AgentSearXNGApiUrl: { |
| envKey: "AGENT_SEARXNG_API_URL", |
| checks: [], |
| }, |
| AgentTavilyApiKey: { |
| envKey: "AGENT_TAVILY_API_KEY", |
| checks: [], |
| }, |
| AgentExaApiKey: { |
| envKey: "AGENT_EXA_API_KEY", |
| checks: [], |
| }, |
|
|
| |
| TextToSpeechProvider: { |
| envKey: "TTS_PROVIDER", |
| checks: [supportedTTSProvider], |
| }, |
|
|
| |
| TTSOpenAIKey: { |
| envKey: "TTS_OPEN_AI_KEY", |
| checks: [validOpenAIKey], |
| }, |
| TTSOpenAIVoiceModel: { |
| envKey: "TTS_OPEN_AI_VOICE_MODEL", |
| checks: [], |
| }, |
|
|
| |
| TTSElevenLabsKey: { |
| envKey: "TTS_ELEVEN_LABS_KEY", |
| checks: [isNotEmpty], |
| }, |
| TTSElevenLabsVoiceModel: { |
| envKey: "TTS_ELEVEN_LABS_VOICE_MODEL", |
| checks: [], |
| }, |
|
|
| |
| TTSPiperTTSVoiceModel: { |
| envKey: "TTS_PIPER_VOICE_MODEL", |
| checks: [], |
| }, |
|
|
| |
| TTSOpenAICompatibleKey: { |
| envKey: "TTS_OPEN_AI_COMPATIBLE_KEY", |
| checks: [], |
| }, |
| TTSOpenAICompatibleModel: { |
| envKey: "TTS_OPEN_AI_COMPATIBLE_MODEL", |
| checks: [], |
| }, |
| TTSOpenAICompatibleVoiceModel: { |
| envKey: "TTS_OPEN_AI_COMPATIBLE_VOICE_MODEL", |
| checks: [isNotEmpty], |
| }, |
| TTSOpenAICompatibleEndpoint: { |
| envKey: "TTS_OPEN_AI_COMPATIBLE_ENDPOINT", |
| checks: [isValidURL], |
| }, |
|
|
| |
| DeepSeekApiKey: { |
| envKey: "DEEPSEEK_API_KEY", |
| checks: [isNotEmpty], |
| }, |
| DeepSeekModelPref: { |
| envKey: "DEEPSEEK_MODEL_PREF", |
| checks: [isNotEmpty], |
| }, |
|
|
| |
| ApipieLLMApiKey: { |
| envKey: "APIPIE_LLM_API_KEY", |
| checks: [isNotEmpty], |
| }, |
| ApipieLLMModelPref: { |
| envKey: "APIPIE_LLM_MODEL_PREF", |
| checks: [isNotEmpty], |
| }, |
|
|
| |
| XAIApiKey: { |
| envKey: "XAI_LLM_API_KEY", |
| checks: [isNotEmpty], |
| }, |
| XAIModelPref: { |
| envKey: "XAI_LLM_MODEL_PREF", |
| checks: [isNotEmpty], |
| }, |
|
|
| |
| NvidiaNimLLMBasePath: { |
| envKey: "NVIDIA_NIM_LLM_BASE_PATH", |
| checks: [isValidURL], |
| postUpdate: [ |
| (_, __, nextValue) => { |
| const { parseNvidiaNimBasePath } = require("../AiProviders/nvidiaNim"); |
| process.env.NVIDIA_NIM_LLM_BASE_PATH = |
| parseNvidiaNimBasePath(nextValue); |
| }, |
| ], |
| }, |
| NvidiaNimLLMModelPref: { |
| envKey: "NVIDIA_NIM_LLM_MODEL_PREF", |
| checks: [], |
| postUpdate: [ |
| async (_, __, nextValue) => { |
| const { NvidiaNimLLM } = require("../AiProviders/nvidiaNim"); |
| await NvidiaNimLLM.setModelTokenLimit(nextValue); |
| }, |
| ], |
| }, |
|
|
| |
| PPIOApiKey: { |
| envKey: "PPIO_API_KEY", |
| checks: [isNotEmpty], |
| }, |
| PPIOModelPref: { |
| envKey: "PPIO_MODEL_PREF", |
| checks: [isNotEmpty], |
| }, |
|
|
| |
| MoonshotAiApiKey: { |
| envKey: "MOONSHOT_AI_API_KEY", |
| checks: [isNotEmpty], |
| }, |
| MoonshotAiModelPref: { |
| envKey: "MOONSHOT_AI_MODEL_PREF", |
| checks: [isNotEmpty], |
| }, |
|
|
| |
| CometApiLLMApiKey: { |
| envKey: "COMETAPI_LLM_API_KEY", |
| checks: [isNotEmpty], |
| }, |
| CometApiLLMModelPref: { |
| envKey: "COMETAPI_LLM_MODEL_PREF", |
| checks: [isNotEmpty], |
| }, |
| CometApiLLMTimeout: { |
| envKey: "COMETAPI_LLM_TIMEOUT_MS", |
| checks: [], |
| }, |
| }; |
|
|
| function isNotEmpty(input = "") { |
| return !input || input.length === 0 ? "Value cannot be empty" : null; |
| } |
|
|
| function nonZero(input = "") { |
| if (isNaN(Number(input))) return "Value must be a number"; |
| return Number(input) <= 0 ? "Value must be greater than zero" : null; |
| } |
|
|
| function isInteger(input = "") { |
| if (isNaN(Number(input))) return "Value must be a number"; |
| return Number(input); |
| } |
|
|
| function isValidURL(input = "") { |
| try { |
| new URL(input); |
| return null; |
| } catch (e) { |
| return "URL is not a valid URL."; |
| } |
| } |
|
|
| function validOpenAIKey(input = "") { |
| return input.startsWith("sk-") ? null : "OpenAI Key must start with sk-"; |
| } |
|
|
| function validAnthropicApiKey(input = "") { |
| return input.startsWith("sk-ant-") |
| ? null |
| : "Anthropic Key must start with sk-ant-"; |
| } |
|
|
| function validLLMExternalBasePath(input = "") { |
| try { |
| new URL(input); |
| if (!input.includes("v1")) return "URL must include /v1"; |
| if (input.split("").slice(-1)?.[0] === "/") |
| return "URL cannot end with a slash"; |
| return null; |
| } catch { |
| return "Not a valid URL"; |
| } |
| } |
|
|
| function validOllamaLLMBasePath(input = "") { |
| try { |
| new URL(input); |
| if (input.split("").slice(-1)?.[0] === "/") |
| return "URL cannot end with a slash"; |
| return null; |
| } catch { |
| return "Not a valid URL"; |
| } |
| } |
|
|
| function supportedTTSProvider(input = "") { |
| const validSelection = [ |
| "native", |
| "openai", |
| "elevenlabs", |
| "piper_local", |
| "generic-openai", |
| ].includes(input); |
| return validSelection ? null : `${input} is not a valid TTS provider.`; |
| } |
|
|
| function validLocalWhisper(input = "") { |
| const validSelection = [ |
| "Xenova/whisper-small", |
| "Xenova/whisper-large", |
| ].includes(input); |
| return validSelection |
| ? null |
| : `${input} is not a valid Whisper model selection.`; |
| } |
|
|
| function supportedLLM(input = "") { |
| const validSelection = [ |
| "openai", |
| "azure", |
| "anthropic", |
| "gemini", |
| "lmstudio", |
| "localai", |
| "ollama", |
| "togetherai", |
| "fireworksai", |
| "mistral", |
| "huggingface", |
| "perplexity", |
| "openrouter", |
| "novita", |
| "groq", |
| "koboldcpp", |
| "textgenwebui", |
| "cohere", |
| "litellm", |
| "generic-openai", |
| "bedrock", |
| "deepseek", |
| "apipie", |
| "xai", |
| "nvidia-nim", |
| "ppio", |
| "dpais", |
| "moonshotai", |
| "cometapi", |
| ].includes(input); |
| return validSelection ? null : `${input} is not a valid LLM provider.`; |
| } |
|
|
| function supportedTranscriptionProvider(input = "") { |
| const validSelection = ["openai", "local"].includes(input); |
| return validSelection |
| ? null |
| : `${input} is not a valid transcription model provider.`; |
| } |
|
|
| function validGeminiSafetySetting(input = "") { |
| const validModes = [ |
| "BLOCK_NONE", |
| "BLOCK_ONLY_HIGH", |
| "BLOCK_MEDIUM_AND_ABOVE", |
| "BLOCK_LOW_AND_ABOVE", |
| ]; |
| return validModes.includes(input) |
| ? null |
| : `Invalid Safety setting. Must be one of ${validModes.join(", ")}.`; |
| } |
|
|
| function supportedEmbeddingModel(input = "") { |
| const supported = [ |
| "openai", |
| "azure", |
| "gemini", |
| "localai", |
| "native", |
| "ollama", |
| "lmstudio", |
| "cohere", |
| "voyageai", |
| "litellm", |
| "generic-openai", |
| "mistral", |
| ]; |
| return supported.includes(input) |
| ? null |
| : `Invalid Embedding model type. Must be one of ${supported.join(", ")}.`; |
| } |
|
|
| function supportedVectorDB(input = "") { |
| const supported = [ |
| "chroma", |
| "chromacloud", |
| "pinecone", |
| "lancedb", |
| "weaviate", |
| "qdrant", |
| "milvus", |
| "zilliz", |
| "astra", |
| "pgvector", |
| ]; |
| return supported.includes(input) |
| ? null |
| : `Invalid VectorDB type. Must be one of ${supported.join(", ")}.`; |
| } |
|
|
| function validChromaURL(input = "") { |
| return input.slice(-1) === "/" |
| ? `Chroma Instance URL should not end in a trailing slash.` |
| : null; |
| } |
|
|
| function validOpenAiTokenLimit(input = "") { |
| const tokenLimit = Number(input); |
| if (isNaN(tokenLimit)) return "Token limit is not a number"; |
| return null; |
| } |
|
|
| function requiresForceMode(_, forceModeEnabled = false) { |
| return forceModeEnabled === true ? null : "Cannot set this setting."; |
| } |
|
|
| async function validDockerizedUrl(input = "") { |
| if (process.env.ANYTHING_LLM_RUNTIME !== "docker") return null; |
|
|
| try { |
| const { isPortInUse, getLocalHosts } = require("./portAvailabilityChecker"); |
| const localInterfaces = getLocalHosts(); |
| const url = new URL(input); |
| const hostname = url.hostname.toLowerCase(); |
| const port = parseInt(url.port, 10); |
|
|
| |
| if (!localInterfaces.includes(hostname)) return null; |
| if (isNaN(port)) return "Invalid URL: Port is not specified or invalid"; |
|
|
| const isPortAvailableFromDocker = await isPortInUse(port, hostname); |
| if (isPortAvailableFromDocker) |
| return "Port is not running a reachable service on loopback address from inside the AnythingLLM container. Please use host.docker.internal (for linux use 172.17.0.1), a real machine ip, or domain to connect to your service."; |
| } catch (error) { |
| console.error(error.message); |
| return "An error occurred while validating the URL"; |
| } |
|
|
| return null; |
| } |
|
|
| function validHuggingFaceEndpoint(input = "") { |
| return input.slice(-6) !== ".cloud" |
| ? `Your HF Endpoint should end in ".cloud"` |
| : null; |
| } |
|
|
| function noRestrictedChars(input = "") { |
| const regExp = new RegExp(/^[a-zA-Z0-9_\-!@$%^&*();]+$/); |
| return !regExp.test(input) |
| ? `Your password has restricted characters in it. Allowed symbols are _,-,!,@,$,%,^,&,*,(,),;` |
| : null; |
| } |
|
|
| async function handleVectorStoreReset(key, prevValue, nextValue) { |
| if (prevValue === nextValue) return; |
| if (key === "VectorDB") { |
| console.log( |
| `Vector configuration changed from ${prevValue} to ${nextValue} - resetting ${prevValue} namespaces` |
| ); |
| return await resetAllVectorStores({ vectorDbKey: prevValue }); |
| } |
|
|
| if (key === "EmbeddingEngine" || key === "EmbeddingModelPref") { |
| console.log( |
| `${key} changed from ${prevValue} to ${nextValue} - resetting ${process.env.VECTOR_DB} namespaces` |
| ); |
| return await resetAllVectorStores({ vectorDbKey: process.env.VECTOR_DB }); |
| } |
| return false; |
| } |
|
|
| |
| |
| |
| |
| |
| async function downloadEmbeddingModelIfRequired(key, prevValue, nextValue) { |
| if (prevValue === nextValue) return; |
| if (key !== "EmbeddingModelPref" || process.env.EMBEDDING_ENGINE !== "native") |
| return; |
|
|
| const { NativeEmbedder } = require("../EmbeddingEngines/native"); |
| if (!NativeEmbedder.supportedModels[nextValue]) return; |
| new NativeEmbedder().embedderClient(); |
| return false; |
| } |
|
|
| |
| |
| |
| |
| |
| async function looksLikePostgresConnectionString(connectionString = null) { |
| if (!connectionString || !connectionString.startsWith("postgresql://")) |
| return "Invalid Postgres connection string. Must start with postgresql://"; |
| if (connectionString.includes(" ")) |
| return "Invalid Postgres connection string. Must not contain spaces."; |
| return null; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| async function validatePGVectorConnectionString(key, prevValue, nextValue) { |
| const envKey = KEY_MAPPING[key].envKey; |
|
|
| if (prevValue === nextValue) return; |
| if (!nextValue) return; |
| if (nextValue === process.env[envKey]) return; |
|
|
| const { PGVector } = require("../vectorDbProviders/pgvector"); |
| const { error, success } = await PGVector.validateConnection({ |
| connectionString: nextValue, |
| }); |
| if (!success) return error; |
|
|
| |
| process.env[envKey] = nextValue; |
| return null; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| async function validatePGVectorTableName(key, prevValue, nextValue) { |
| const envKey = KEY_MAPPING[key].envKey; |
|
|
| if (prevValue === nextValue) return; |
| if (!nextValue) return; |
| if (nextValue === process.env[envKey]) return; |
| if (!process.env.PGVECTOR_CONNECTION_STRING) return; |
|
|
| const { PGVector } = require("../vectorDbProviders/pgvector"); |
| const { error, success } = await PGVector.validateConnection({ |
| connectionString: process.env.PGVECTOR_CONNECTION_STRING, |
| tableName: nextValue, |
| }); |
| if (!success) return error; |
|
|
| return null; |
| } |
|
|
| |
| |
| |
| |
| async function updateENV(newENVs = {}, force = false, userId = null) { |
| let error = ""; |
| const validKeys = Object.keys(KEY_MAPPING); |
| const ENV_KEYS = Object.keys(newENVs).filter( |
| (key) => validKeys.includes(key) && !newENVs[key].includes("******") |
| ); |
| const newValues = {}; |
|
|
| for (const key of ENV_KEYS) { |
| const { |
| envKey, |
| checks, |
| preUpdate = [], |
| postUpdate = [], |
| } = KEY_MAPPING[key]; |
| const prevValue = process.env[envKey]; |
| const nextValue = newENVs[key]; |
| let errors = await executeValidationChecks(checks, nextValue, force); |
|
|
| |
| |
| if (errors.length > 0) { |
| error += errors.join("\n"); |
| break; |
| } |
|
|
| |
| errors = []; |
| for (const preUpdateFunc of preUpdate) { |
| const errorMsg = await preUpdateFunc(key, prevValue, nextValue); |
| if (!!errorMsg && typeof errorMsg === "string") errors.push(errorMsg); |
| } |
|
|
| |
| |
| if (errors.length > 0) { |
| error += errors.join("\n"); |
| break; |
| } |
|
|
| newValues[key] = nextValue; |
| process.env[envKey] = nextValue; |
|
|
| for (const postUpdateFunc of postUpdate) |
| await postUpdateFunc(key, prevValue, nextValue); |
| } |
|
|
| await logChangesToEventLog(newValues, userId); |
| if (process.env.NODE_ENV === "production") dumpENV(); |
| return { newValues, error: error?.length > 0 ? error : false }; |
| } |
|
|
| async function executeValidationChecks(checks, value, force) { |
| const results = await Promise.all( |
| checks.map((validator) => validator(value, force)) |
| ); |
| return results.filter((err) => typeof err === "string"); |
| } |
|
|
| async function logChangesToEventLog(newValues = {}, userId = null) { |
| const { EventLogs } = require("../../models/eventLogs"); |
| const eventMapping = { |
| LLMProvider: "update_llm_provider", |
| EmbeddingEngine: "update_embedding_engine", |
| VectorDB: "update_vector_db", |
| }; |
|
|
| for (const [key, eventName] of Object.entries(eventMapping)) { |
| if (!newValues.hasOwnProperty(key)) continue; |
| await EventLogs.logEvent(eventName, {}, userId); |
| } |
| return; |
| } |
|
|
| function dumpENV() { |
| const fs = require("fs"); |
| const path = require("path"); |
|
|
| const frozenEnvs = {}; |
| const protectedKeys = [ |
| ...Object.values(KEY_MAPPING).map((values) => values.envKey), |
| |
| |
| "JWT_EXPIRY", |
|
|
| "STORAGE_DIR", |
| "SERVER_PORT", |
| |
| "SIG_KEY", |
| "SIG_SALT", |
| |
| "PASSWORDMINCHAR", |
| "PASSWORDMAXCHAR", |
| "PASSWORDLOWERCASE", |
| "PASSWORDUPPERCASE", |
| "PASSWORDNUMERIC", |
| "PASSWORDSYMBOL", |
| "PASSWORDREQUIREMENTS", |
| |
| "ENABLE_HTTPS", |
| "HTTPS_CERT_PATH", |
| "HTTPS_KEY_PATH", |
| |
| "DISABLE_VIEW_CHAT_HISTORY", |
| |
| "SIMPLE_SSO_ENABLED", |
| "SIMPLE_SSO_NO_LOGIN", |
| "SIMPLE_SSO_NO_LOGIN_REDIRECT", |
| |
| "COMMUNITY_HUB_BUNDLE_DOWNLOADS_ENABLED", |
|
|
| |
| "NVIDIA_NIM_LLM_MODEL_TOKEN_LIMIT", |
|
|
| |
| "TARGET_OCR_LANG", |
|
|
| |
| "COLLECTOR_ALLOW_ANY_IP", |
|
|
| |
| "GENERIC_OPENAI_STREAMING_DISABLED", |
|
|
| |
| "ANYTHINGLLM_CHROMIUM_ARGS", |
| ]; |
|
|
| |
| function sanitizeValue(value) { |
| const offendingChars = |
| /[\n\r\t\v\f\u0085\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000"'`#]/; |
| const firstOffendingCharIndex = value.search(offendingChars); |
| if (firstOffendingCharIndex === -1) return value; |
|
|
| return value.substring(0, firstOffendingCharIndex); |
| } |
|
|
| for (const key of protectedKeys) { |
| const envValue = process.env?.[key] || null; |
| if (!envValue) continue; |
| frozenEnvs[key] = process.env?.[key] || null; |
| } |
|
|
| var envResult = `# Auto-dump ENV from system call on ${new Date().toTimeString()}\n`; |
| envResult += Object.entries(frozenEnvs) |
| .map(([key, value]) => `${key}='${sanitizeValue(value)}'`) |
| .join("\n"); |
|
|
| const envPath = path.join(__dirname, "../../.env"); |
| fs.writeFileSync(envPath, envResult, { encoding: "utf8", flag: "w" }); |
| return true; |
| } |
|
|
| module.exports = { |
| dumpENV, |
| updateENV, |
| }; |
|
|