2023-08-24 04:15:07 +02:00
|
|
|
process.env.NODE_ENV === "development"
|
|
|
|
? require("dotenv").config({ path: `.env.${process.env.NODE_ENV}` })
|
|
|
|
: require("dotenv").config();
|
|
|
|
|
2024-05-16 19:38:21 +02:00
|
|
|
const { default: slugify } = require("slugify");
|
|
|
|
const { isValidUrl, safeJsonParse } = require("../utils/http");
|
2023-09-28 23:00:03 +02:00
|
|
|
const prisma = require("../utils/prisma");
|
2024-05-16 19:38:21 +02:00
|
|
|
const { v4 } = require("uuid");
|
2024-07-20 00:58:43 +02:00
|
|
|
const { MetaGenerator } = require("../utils/boot/MetaGenerator");
|
2023-09-28 23:00:03 +02:00
|
|
|
|
2024-04-07 01:38:07 +02:00
|
|
|
function isNullOrNaN(value) {
|
|
|
|
if (value === null) return true;
|
|
|
|
return isNaN(value);
|
|
|
|
}
|
|
|
|
|
2023-07-25 19:37:04 +02:00
|
|
|
const SystemSettings = {
|
2024-03-29 18:56:32 +01:00
|
|
|
protectedFields: ["multi_user_mode"],
|
2024-09-11 02:06:02 +02:00
|
|
|
publicFields: [
|
|
|
|
"footer_data",
|
|
|
|
"support_email",
|
|
|
|
"text_splitter_chunk_size",
|
|
|
|
"text_splitter_chunk_overlap",
|
|
|
|
"max_embed_chunk_size",
|
|
|
|
"agent_search_provider",
|
|
|
|
"agent_sql_connections",
|
|
|
|
"default_agent_skills",
|
|
|
|
"imported_agent_skills",
|
|
|
|
"custom_app_name",
|
|
|
|
"feature_flags",
|
|
|
|
"meta_page_title",
|
|
|
|
"meta_page_favicon",
|
|
|
|
],
|
2023-07-25 19:37:04 +02:00
|
|
|
supportedFields: [
|
2023-08-15 00:22:55 +02:00
|
|
|
"logo_filename",
|
2023-08-15 02:42:17 +02:00
|
|
|
"telemetry_id",
|
2024-02-08 21:17:01 +01:00
|
|
|
"footer_data",
|
2024-02-19 19:30:41 +01:00
|
|
|
"support_email",
|
2024-07-20 00:58:43 +02:00
|
|
|
|
2024-04-07 01:38:07 +02:00
|
|
|
"text_splitter_chunk_size",
|
|
|
|
"text_splitter_chunk_overlap",
|
2024-04-16 19:50:10 +02:00
|
|
|
"agent_search_provider",
|
|
|
|
"default_agent_skills",
|
2024-05-16 19:38:21 +02:00
|
|
|
"agent_sql_connections",
|
2024-05-23 23:14:53 +02:00
|
|
|
"custom_app_name",
|
2024-06-21 22:38:50 +02:00
|
|
|
|
2024-07-20 00:58:43 +02:00
|
|
|
// Meta page customization
|
|
|
|
"meta_page_title",
|
|
|
|
"meta_page_favicon",
|
|
|
|
|
2024-06-21 22:38:50 +02:00
|
|
|
// beta feature flags
|
|
|
|
"experimental_live_file_sync",
|
2023-07-25 19:37:04 +02:00
|
|
|
],
|
2024-02-08 21:17:01 +01:00
|
|
|
validations: {
|
|
|
|
footer_data: (updates) => {
|
|
|
|
try {
|
2024-03-29 21:39:11 +01:00
|
|
|
const array = JSON.parse(updates)
|
|
|
|
.filter((setting) => isValidUrl(setting.url))
|
|
|
|
.slice(0, 3); // max of 3 items in footer.
|
|
|
|
return JSON.stringify(array);
|
2024-02-08 21:17:01 +01:00
|
|
|
} catch (e) {
|
|
|
|
console.error(`Failed to run validation function on footer_data`);
|
|
|
|
return JSON.stringify([]);
|
|
|
|
}
|
|
|
|
},
|
2024-04-07 01:38:07 +02:00
|
|
|
text_splitter_chunk_size: (update) => {
|
|
|
|
try {
|
|
|
|
if (isNullOrNaN(update)) throw new Error("Value is not a number.");
|
|
|
|
if (Number(update) <= 0) throw new Error("Value must be non-zero.");
|
|
|
|
return Number(update);
|
|
|
|
} catch (e) {
|
|
|
|
console.error(
|
|
|
|
`Failed to run validation function on text_splitter_chunk_size`,
|
|
|
|
e.message
|
|
|
|
);
|
|
|
|
return 1000;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
text_splitter_chunk_overlap: (update) => {
|
|
|
|
try {
|
|
|
|
if (isNullOrNaN(update)) throw new Error("Value is not a number");
|
|
|
|
if (Number(update) < 0) throw new Error("Value cannot be less than 0.");
|
|
|
|
return Number(update);
|
|
|
|
} catch (e) {
|
|
|
|
console.error(
|
|
|
|
`Failed to run validation function on text_splitter_chunk_overlap`,
|
|
|
|
e.message
|
|
|
|
);
|
|
|
|
return 20;
|
|
|
|
}
|
|
|
|
},
|
2024-04-16 19:50:10 +02:00
|
|
|
agent_search_provider: (update) => {
|
|
|
|
try {
|
2024-05-16 19:38:21 +02:00
|
|
|
if (update === "none") return null;
|
2024-05-24 01:49:30 +02:00
|
|
|
if (
|
2024-06-11 00:22:32 +02:00
|
|
|
![
|
|
|
|
"google-search-engine",
|
2024-09-05 19:36:46 +02:00
|
|
|
"searchapi",
|
2024-06-11 00:22:32 +02:00
|
|
|
"serper-dot-dev",
|
|
|
|
"bing-search",
|
|
|
|
"serply-engine",
|
2024-06-20 23:08:00 +02:00
|
|
|
"searxng-engine",
|
2024-10-01 23:52:57 +02:00
|
|
|
"tavily-search",
|
2024-06-11 00:22:32 +02:00
|
|
|
].includes(update)
|
2024-05-24 01:49:30 +02:00
|
|
|
)
|
2024-04-16 19:50:10 +02:00
|
|
|
throw new Error("Invalid SERP provider.");
|
|
|
|
return String(update);
|
|
|
|
} catch (e) {
|
|
|
|
console.error(
|
|
|
|
`Failed to run validation function on agent_search_provider`,
|
|
|
|
e.message
|
|
|
|
);
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
default_agent_skills: (updates) => {
|
|
|
|
try {
|
|
|
|
const skills = updates.split(",").filter((skill) => !!skill);
|
|
|
|
return JSON.stringify(skills);
|
|
|
|
} catch (e) {
|
|
|
|
console.error(`Could not validate agent skills.`);
|
|
|
|
return JSON.stringify([]);
|
|
|
|
}
|
|
|
|
},
|
2024-05-16 19:38:21 +02:00
|
|
|
agent_sql_connections: async (updates) => {
|
|
|
|
const existingConnections = safeJsonParse(
|
|
|
|
(await SystemSettings.get({ label: "agent_sql_connections" }))?.value,
|
|
|
|
[]
|
|
|
|
);
|
|
|
|
try {
|
|
|
|
const updatedConnections = mergeConnections(
|
|
|
|
existingConnections,
|
|
|
|
safeJsonParse(updates, [])
|
|
|
|
);
|
|
|
|
return JSON.stringify(updatedConnections);
|
|
|
|
} catch (e) {
|
|
|
|
console.error(`Failed to merge connections`);
|
|
|
|
return JSON.stringify(existingConnections ?? []);
|
|
|
|
}
|
|
|
|
},
|
2024-06-21 22:38:50 +02:00
|
|
|
experimental_live_file_sync: (update) => {
|
|
|
|
if (typeof update === "boolean")
|
|
|
|
return update === true ? "enabled" : "disabled";
|
|
|
|
if (!["enabled", "disabled"].includes(update)) return "disabled";
|
|
|
|
return String(update);
|
|
|
|
},
|
2024-07-20 00:58:43 +02:00
|
|
|
meta_page_title: (newTitle) => {
|
|
|
|
try {
|
|
|
|
if (typeof newTitle !== "string" || !newTitle) return null;
|
|
|
|
return String(newTitle);
|
|
|
|
} catch {
|
|
|
|
return null;
|
|
|
|
} finally {
|
|
|
|
new MetaGenerator().clearConfig();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
meta_page_favicon: (faviconUrl) => {
|
|
|
|
if (!faviconUrl) return null;
|
|
|
|
try {
|
|
|
|
const url = new URL(faviconUrl);
|
|
|
|
return url.toString();
|
|
|
|
} catch {
|
|
|
|
return null;
|
|
|
|
} finally {
|
|
|
|
new MetaGenerator().clearConfig();
|
|
|
|
}
|
|
|
|
},
|
2024-02-08 21:17:01 +01:00
|
|
|
},
|
2023-08-24 04:15:07 +02:00
|
|
|
currentSettings: async function () {
|
2024-04-19 18:51:58 +02:00
|
|
|
const { hasVectorCachedFiles } = require("../utils/files");
|
2023-12-07 23:48:27 +01:00
|
|
|
const llmProvider = process.env.LLM_PROVIDER;
|
|
|
|
const vectorDB = process.env.VECTOR_DB;
|
2023-08-24 04:15:07 +02:00
|
|
|
return {
|
2024-04-04 22:47:33 +02:00
|
|
|
// --------------------------------------------------------
|
|
|
|
// General Settings
|
|
|
|
// --------------------------------------------------------
|
2023-08-24 04:15:07 +02:00
|
|
|
RequiresAuth: !!process.env.AUTH_TOKEN,
|
|
|
|
AuthToken: !!process.env.AUTH_TOKEN,
|
|
|
|
JWTSecret: !!process.env.JWT_SECRET,
|
|
|
|
StorageDir: process.env.STORAGE_DIR,
|
|
|
|
MultiUserMode: await this.isMultiUserMode(),
|
2024-04-04 22:47:33 +02:00
|
|
|
DisableTelemetry: process.env.DISABLE_TELEMETRY || "false",
|
|
|
|
|
|
|
|
// --------------------------------------------------------
|
|
|
|
// Embedder Provider Selection Settings & Configs
|
|
|
|
// --------------------------------------------------------
|
2023-10-30 23:44:03 +01:00
|
|
|
EmbeddingEngine: process.env.EMBEDDING_ENGINE,
|
2024-04-19 18:51:58 +02:00
|
|
|
HasExistingEmbeddings: await this.hasEmbeddings(), // check if they have any currently embedded documents active in workspaces.
|
|
|
|
HasCachedEmbeddings: hasVectorCachedFiles(), // check if they any currently cached embedded docs.
|
2023-11-14 22:49:31 +01:00
|
|
|
EmbeddingBasePath: process.env.EMBEDDING_BASE_PATH,
|
|
|
|
EmbeddingModelPref: process.env.EMBEDDING_MODEL_PREF,
|
2023-12-08 01:27:36 +01:00
|
|
|
EmbeddingModelMaxChunkLength:
|
|
|
|
process.env.EMBEDDING_MODEL_MAX_CHUNK_LENGTH,
|
2024-06-22 01:27:02 +02:00
|
|
|
GenericOpenAiEmbeddingApiKey:
|
|
|
|
!!process.env.GENERIC_OPEN_AI_EMBEDDING_API_KEY,
|
2023-11-14 21:31:44 +01:00
|
|
|
|
2024-04-04 22:47:33 +02:00
|
|
|
// --------------------------------------------------------
|
|
|
|
// VectorDB Provider Selection Settings & Configs
|
|
|
|
// --------------------------------------------------------
|
|
|
|
VectorDB: vectorDB,
|
2024-04-05 19:58:36 +02:00
|
|
|
...this.vectorDBPreferenceKeys(),
|
2024-04-04 22:47:33 +02:00
|
|
|
|
|
|
|
// --------------------------------------------------------
|
|
|
|
// LLM Provider Selection Settings & Configs
|
|
|
|
// --------------------------------------------------------
|
|
|
|
LLMProvider: llmProvider,
|
2024-04-05 19:58:36 +02:00
|
|
|
...this.llmPreferenceKeys(),
|
2024-04-04 22:47:33 +02:00
|
|
|
|
|
|
|
// --------------------------------------------------------
|
|
|
|
// Whisper (Audio transcription) Selection Settings & Configs
|
|
|
|
// - Currently the only 3rd party is OpenAI, so is OPEN_AI_KEY is set
|
|
|
|
// - then it can be shared.
|
|
|
|
// --------------------------------------------------------
|
2024-03-14 23:43:26 +01:00
|
|
|
WhisperProvider: process.env.WHISPER_PROVIDER || "local",
|
2024-05-18 06:31:29 +02:00
|
|
|
WhisperModelPref:
|
|
|
|
process.env.WHISPER_MODEL_PREF || "Xenova/whisper-small",
|
2024-04-16 19:50:10 +02:00
|
|
|
|
2024-05-14 20:57:21 +02:00
|
|
|
// --------------------------------------------------------
|
|
|
|
// TTS/STT Selection Settings & Configs
|
|
|
|
// - Currently the only 3rd party is OpenAI or the native browser-built in
|
|
|
|
// --------------------------------------------------------
|
|
|
|
TextToSpeechProvider: process.env.TTS_PROVIDER || "native",
|
|
|
|
TTSOpenAIKey: !!process.env.TTS_OPEN_AI_KEY,
|
|
|
|
TTSOpenAIVoiceModel: process.env.TTS_OPEN_AI_VOICE_MODEL,
|
2024-10-16 06:39:31 +02:00
|
|
|
|
2024-05-14 20:57:21 +02:00
|
|
|
// Eleven Labs TTS
|
|
|
|
TTSElevenLabsKey: !!process.env.TTS_ELEVEN_LABS_KEY,
|
|
|
|
TTSElevenLabsVoiceModel: process.env.TTS_ELEVEN_LABS_VOICE_MODEL,
|
2024-08-07 20:09:51 +02:00
|
|
|
// Piper TTS
|
|
|
|
TTSPiperTTSVoiceModel:
|
|
|
|
process.env.TTS_PIPER_VOICE_MODEL ?? "en_US-hfc_female-medium",
|
2024-10-16 06:39:31 +02:00
|
|
|
// OpenAI Generic TTS
|
|
|
|
TTSOpenAICompatibleKey: !!process.env.TTS_OPEN_AI_COMPATIBLE_KEY,
|
|
|
|
TTSOpenAICompatibleVoiceModel:
|
|
|
|
process.env.TTS_OPEN_AI_COMPATIBLE_VOICE_MODEL,
|
|
|
|
TTSOpenAICompatibleEndpoint: process.env.TTS_OPEN_AI_COMPATIBLE_ENDPOINT,
|
2024-05-14 20:57:21 +02:00
|
|
|
|
2024-04-16 19:50:10 +02:00
|
|
|
// --------------------------------------------------------
|
|
|
|
// Agent Settings & Configs
|
|
|
|
// --------------------------------------------------------
|
|
|
|
AgentGoogleSearchEngineId: process.env.AGENT_GSE_CTX || null,
|
2024-06-20 23:08:00 +02:00
|
|
|
AgentGoogleSearchEngineKey: !!process.env.AGENT_GSE_KEY || null,
|
2024-09-05 19:36:46 +02:00
|
|
|
AgentSearchApiKey: !!process.env.AGENT_SEARCHAPI_API_KEY || null,
|
|
|
|
AgentSearchApiEngine: process.env.AGENT_SEARCHAPI_ENGINE || "google",
|
2024-06-20 23:08:00 +02:00
|
|
|
AgentSerperApiKey: !!process.env.AGENT_SERPER_DEV_KEY || null,
|
|
|
|
AgentBingSearchApiKey: !!process.env.AGENT_BING_SEARCH_API_KEY || null,
|
|
|
|
AgentSerplyApiKey: !!process.env.AGENT_SERPLY_API_KEY || null,
|
|
|
|
AgentSearXNGApiUrl: process.env.AGENT_SEARXNG_API_URL || null,
|
2024-10-01 23:52:57 +02:00
|
|
|
AgentTavilyApiKey: !!process.env.AGENT_TAVILY_API_KEY || null,
|
2024-10-21 22:19:19 +02:00
|
|
|
|
|
|
|
// --------------------------------------------------------
|
|
|
|
// Compliance Settings
|
|
|
|
// --------------------------------------------------------
|
|
|
|
// Disable View Chat History for the whole instance.
|
|
|
|
DisableViewChatHistory:
|
|
|
|
"DISABLE_VIEW_CHAT_HISTORY" in process.env || false,
|
2023-08-24 04:15:07 +02:00
|
|
|
};
|
|
|
|
},
|
2023-07-25 19:37:04 +02:00
|
|
|
|
2023-09-28 23:00:03 +02:00
|
|
|
get: async function (clause = {}) {
|
|
|
|
try {
|
|
|
|
const setting = await prisma.system_settings.findFirst({ where: clause });
|
|
|
|
return setting || null;
|
|
|
|
} catch (error) {
|
|
|
|
console.error(error.message);
|
|
|
|
return null;
|
|
|
|
}
|
2023-07-25 19:37:04 +02:00
|
|
|
},
|
|
|
|
|
2024-04-07 01:38:07 +02:00
|
|
|
getValueOrFallback: async function (clause = {}, fallback = null) {
|
|
|
|
try {
|
|
|
|
return (await this.get(clause))?.value ?? fallback;
|
|
|
|
} catch (error) {
|
|
|
|
console.error(error.message);
|
|
|
|
return fallback;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2023-09-28 23:00:03 +02:00
|
|
|
where: async function (clause = {}, limit) {
|
|
|
|
try {
|
|
|
|
const settings = await prisma.system_settings.findMany({
|
|
|
|
where: clause,
|
|
|
|
take: limit || undefined,
|
|
|
|
});
|
|
|
|
return settings;
|
|
|
|
} catch (error) {
|
|
|
|
console.error(error.message);
|
|
|
|
return [];
|
|
|
|
}
|
2023-07-25 19:37:04 +02:00
|
|
|
},
|
2023-09-28 23:00:03 +02:00
|
|
|
|
2024-03-29 18:56:32 +01:00
|
|
|
// Can take generic keys and will pre-filter invalid keys
|
|
|
|
// from the set before sending to the explicit update function
|
|
|
|
// that will then enforce validations as well.
|
2023-07-25 19:37:04 +02:00
|
|
|
updateSettings: async function (updates = {}) {
|
2024-03-29 18:56:32 +01:00
|
|
|
const validFields = Object.keys(updates).filter((key) =>
|
|
|
|
this.supportedFields.includes(key)
|
|
|
|
);
|
|
|
|
|
|
|
|
Object.entries(updates).forEach(([key]) => {
|
|
|
|
if (validFields.includes(key)) return;
|
|
|
|
delete updates[key];
|
|
|
|
});
|
|
|
|
|
|
|
|
return this._updateSettings(updates);
|
|
|
|
},
|
|
|
|
|
|
|
|
// Explicit update of settings + key validations.
|
|
|
|
// Only use this method when directly setting a key value
|
|
|
|
// that takes no user input for the keys being modified.
|
|
|
|
_updateSettings: async function (updates = {}) {
|
2023-09-28 23:00:03 +02:00
|
|
|
try {
|
2024-05-16 19:38:21 +02:00
|
|
|
const updatePromises = [];
|
|
|
|
for (const key of Object.keys(updates)) {
|
|
|
|
let validatedValue = updates[key];
|
|
|
|
if (this.validations.hasOwnProperty(key)) {
|
|
|
|
if (this.validations[key].constructor.name === "AsyncFunction") {
|
|
|
|
validatedValue = await this.validations[key](updates[key]);
|
|
|
|
} else {
|
|
|
|
validatedValue = this.validations[key](updates[key]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
updatePromises.push(
|
|
|
|
prisma.system_settings.upsert({
|
|
|
|
where: { label: key },
|
|
|
|
update: {
|
|
|
|
value: validatedValue === null ? null : String(validatedValue),
|
|
|
|
},
|
|
|
|
create: {
|
|
|
|
label: key,
|
|
|
|
value: validatedValue === null ? null : String(validatedValue),
|
|
|
|
},
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
2023-07-25 19:37:04 +02:00
|
|
|
|
2023-09-28 23:00:03 +02:00
|
|
|
await Promise.all(updatePromises);
|
|
|
|
return { success: true, error: null };
|
|
|
|
} catch (error) {
|
|
|
|
console.error("FAILED TO UPDATE SYSTEM SETTINGS", error.message);
|
|
|
|
return { success: false, error: error.message };
|
2023-07-25 19:37:04 +02:00
|
|
|
}
|
|
|
|
},
|
2023-09-28 23:00:03 +02:00
|
|
|
|
2023-07-25 19:37:04 +02:00
|
|
|
isMultiUserMode: async function () {
|
2023-09-28 23:00:03 +02:00
|
|
|
try {
|
|
|
|
const setting = await this.get({ label: "multi_user_mode" });
|
|
|
|
return setting?.value === "true";
|
|
|
|
} catch (error) {
|
|
|
|
console.error(error.message);
|
|
|
|
return false;
|
|
|
|
}
|
2023-07-25 19:37:04 +02:00
|
|
|
},
|
2023-09-28 23:00:03 +02:00
|
|
|
|
2023-08-15 00:22:55 +02:00
|
|
|
currentLogoFilename: async function () {
|
2023-09-28 23:00:03 +02:00
|
|
|
try {
|
|
|
|
const setting = await this.get({ label: "logo_filename" });
|
|
|
|
return setting?.value || null;
|
|
|
|
} catch (error) {
|
|
|
|
console.error(error.message);
|
|
|
|
return null;
|
|
|
|
}
|
2023-08-15 00:22:55 +02:00
|
|
|
},
|
2023-09-28 23:00:03 +02:00
|
|
|
|
2023-11-16 23:35:14 +01:00
|
|
|
hasEmbeddings: async function () {
|
|
|
|
try {
|
|
|
|
const { Document } = require("./documents");
|
|
|
|
const count = await Document.count({}, 1);
|
|
|
|
return count > 0;
|
|
|
|
} catch (error) {
|
|
|
|
console.error(error.message);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
},
|
2024-04-05 19:58:36 +02:00
|
|
|
|
|
|
|
vectorDBPreferenceKeys: function () {
|
|
|
|
return {
|
|
|
|
// Pinecone DB Keys
|
|
|
|
PineConeKey: !!process.env.PINECONE_API_KEY,
|
|
|
|
PineConeIndex: process.env.PINECONE_INDEX,
|
|
|
|
|
|
|
|
// Chroma DB Keys
|
|
|
|
ChromaEndpoint: process.env.CHROMA_ENDPOINT,
|
|
|
|
ChromaApiHeader: process.env.CHROMA_API_HEADER,
|
|
|
|
ChromaApiKey: !!process.env.CHROMA_API_KEY,
|
|
|
|
|
|
|
|
// Weaviate DB Keys
|
|
|
|
WeaviateEndpoint: process.env.WEAVIATE_ENDPOINT,
|
|
|
|
WeaviateApiKey: process.env.WEAVIATE_API_KEY,
|
|
|
|
|
|
|
|
// QDrant DB Keys
|
|
|
|
QdrantEndpoint: process.env.QDRANT_ENDPOINT,
|
|
|
|
QdrantApiKey: process.env.QDRANT_API_KEY,
|
|
|
|
|
|
|
|
// Milvus DB Keys
|
|
|
|
MilvusAddress: process.env.MILVUS_ADDRESS,
|
|
|
|
MilvusUsername: process.env.MILVUS_USERNAME,
|
|
|
|
MilvusPassword: !!process.env.MILVUS_PASSWORD,
|
|
|
|
|
|
|
|
// Zilliz DB Keys
|
|
|
|
ZillizEndpoint: process.env.ZILLIZ_ENDPOINT,
|
|
|
|
ZillizApiToken: process.env.ZILLIZ_API_TOKEN,
|
|
|
|
|
|
|
|
// AstraDB Keys
|
|
|
|
AstraDBApplicationToken: process?.env?.ASTRA_DB_APPLICATION_TOKEN,
|
|
|
|
AstraDBEndpoint: process?.env?.ASTRA_DB_ENDPOINT,
|
|
|
|
};
|
|
|
|
},
|
|
|
|
|
|
|
|
llmPreferenceKeys: function () {
|
|
|
|
return {
|
|
|
|
// OpenAI Keys
|
|
|
|
OpenAiKey: !!process.env.OPEN_AI_KEY,
|
2024-05-13 23:31:49 +02:00
|
|
|
OpenAiModelPref: process.env.OPEN_MODEL_PREF || "gpt-4o",
|
2024-04-05 19:58:36 +02:00
|
|
|
|
|
|
|
// Azure + OpenAI Keys
|
|
|
|
AzureOpenAiEndpoint: process.env.AZURE_OPENAI_ENDPOINT,
|
|
|
|
AzureOpenAiKey: !!process.env.AZURE_OPENAI_KEY,
|
|
|
|
AzureOpenAiModelPref: process.env.OPEN_MODEL_PREF,
|
|
|
|
AzureOpenAiEmbeddingModelPref: process.env.EMBEDDING_MODEL_PREF,
|
|
|
|
AzureOpenAiTokenLimit: process.env.AZURE_OPENAI_TOKEN_LIMIT || 4096,
|
|
|
|
|
|
|
|
// Anthropic Keys
|
|
|
|
AnthropicApiKey: !!process.env.ANTHROPIC_API_KEY,
|
|
|
|
AnthropicModelPref: process.env.ANTHROPIC_MODEL_PREF || "claude-2",
|
|
|
|
|
|
|
|
// Gemini Keys
|
|
|
|
GeminiLLMApiKey: !!process.env.GEMINI_API_KEY,
|
|
|
|
GeminiLLMModelPref: process.env.GEMINI_LLM_MODEL_PREF || "gemini-pro",
|
2024-05-20 20:17:00 +02:00
|
|
|
GeminiSafetySetting:
|
|
|
|
process.env.GEMINI_SAFETY_SETTING || "BLOCK_MEDIUM_AND_ABOVE",
|
2024-04-05 19:58:36 +02:00
|
|
|
|
|
|
|
// LMStudio Keys
|
|
|
|
LMStudioBasePath: process.env.LMSTUDIO_BASE_PATH,
|
|
|
|
LMStudioTokenLimit: process.env.LMSTUDIO_MODEL_TOKEN_LIMIT,
|
|
|
|
LMStudioModelPref: process.env.LMSTUDIO_MODEL_PREF,
|
|
|
|
|
|
|
|
// LocalAI Keys
|
|
|
|
LocalAiApiKey: !!process.env.LOCAL_AI_API_KEY,
|
|
|
|
LocalAiBasePath: process.env.LOCAL_AI_BASE_PATH,
|
|
|
|
LocalAiModelPref: process.env.LOCAL_AI_MODEL_PREF,
|
|
|
|
LocalAiTokenLimit: process.env.LOCAL_AI_MODEL_TOKEN_LIMIT,
|
|
|
|
|
|
|
|
// Ollama LLM Keys
|
|
|
|
OllamaLLMBasePath: process.env.OLLAMA_BASE_PATH,
|
|
|
|
OllamaLLMModelPref: process.env.OLLAMA_MODEL_PREF,
|
|
|
|
OllamaLLMTokenLimit: process.env.OLLAMA_MODEL_TOKEN_LIMIT,
|
2024-07-22 23:44:47 +02:00
|
|
|
OllamaLLMKeepAliveSeconds: process.env.OLLAMA_KEEP_ALIVE_TIMEOUT ?? 300,
|
2024-08-02 22:29:17 +02:00
|
|
|
OllamaLLMPerformanceMode: process.env.OLLAMA_PERFORMANCE_MODE ?? "base",
|
2024-04-05 19:58:36 +02:00
|
|
|
|
|
|
|
// TogetherAI Keys
|
|
|
|
TogetherAiApiKey: !!process.env.TOGETHER_AI_API_KEY,
|
|
|
|
TogetherAiModelPref: process.env.TOGETHER_AI_MODEL_PREF,
|
|
|
|
|
2024-09-16 21:10:44 +02:00
|
|
|
// Fireworks AI API Keys
|
|
|
|
FireworksAiLLMApiKey: !!process.env.FIREWORKS_AI_LLM_API_KEY,
|
|
|
|
FireworksAiLLMModelPref: process.env.FIREWORKS_AI_LLM_MODEL_PREF,
|
|
|
|
|
2024-04-05 19:58:36 +02:00
|
|
|
// Perplexity AI Keys
|
|
|
|
PerplexityApiKey: !!process.env.PERPLEXITY_API_KEY,
|
|
|
|
PerplexityModelPref: process.env.PERPLEXITY_MODEL_PREF,
|
|
|
|
|
|
|
|
// OpenRouter Keys
|
|
|
|
OpenRouterApiKey: !!process.env.OPENROUTER_API_KEY,
|
|
|
|
OpenRouterModelPref: process.env.OPENROUTER_MODEL_PREF,
|
2024-07-29 20:49:14 +02:00
|
|
|
OpenRouterTimeout: process.env.OPENROUTER_TIMEOUT_MS,
|
2024-04-05 19:58:36 +02:00
|
|
|
|
|
|
|
// Mistral AI (API) Keys
|
|
|
|
MistralApiKey: !!process.env.MISTRAL_API_KEY,
|
|
|
|
MistralModelPref: process.env.MISTRAL_MODEL_PREF,
|
|
|
|
|
|
|
|
// Groq AI API Keys
|
|
|
|
GroqApiKey: !!process.env.GROQ_API_KEY,
|
|
|
|
GroqModelPref: process.env.GROQ_MODEL_PREF,
|
|
|
|
|
|
|
|
// Native LLM Keys
|
|
|
|
NativeLLMModelPref: process.env.NATIVE_LLM_MODEL_PREF,
|
|
|
|
NativeLLMTokenLimit: process.env.NATIVE_LLM_MODEL_TOKEN_LIMIT,
|
|
|
|
|
|
|
|
// HuggingFace Dedicated Inference
|
|
|
|
HuggingFaceLLMEndpoint: process.env.HUGGING_FACE_LLM_ENDPOINT,
|
|
|
|
HuggingFaceLLMAccessToken: !!process.env.HUGGING_FACE_LLM_API_KEY,
|
|
|
|
HuggingFaceLLMTokenLimit: process.env.HUGGING_FACE_LLM_TOKEN_LIMIT,
|
2024-04-23 22:06:07 +02:00
|
|
|
|
2024-05-02 21:12:44 +02:00
|
|
|
// KoboldCPP Keys
|
|
|
|
KoboldCPPModelPref: process.env.KOBOLD_CPP_MODEL_PREF,
|
|
|
|
KoboldCPPBasePath: process.env.KOBOLD_CPP_BASE_PATH,
|
|
|
|
KoboldCPPTokenLimit: process.env.KOBOLD_CPP_MODEL_TOKEN_LIMIT,
|
|
|
|
|
2024-05-08 20:56:30 +02:00
|
|
|
// Text Generation Web UI Keys
|
|
|
|
TextGenWebUIBasePath: process.env.TEXT_GEN_WEB_UI_BASE_PATH,
|
|
|
|
TextGenWebUITokenLimit: process.env.TEXT_GEN_WEB_UI_MODEL_TOKEN_LIMIT,
|
2024-05-13 21:58:16 +02:00
|
|
|
TextGenWebUIAPIKey: !!process.env.TEXT_GEN_WEB_UI_API_KEY,
|
2024-05-08 20:56:30 +02:00
|
|
|
|
2024-05-16 22:56:28 +02:00
|
|
|
// LiteLLM Keys
|
|
|
|
LiteLLMModelPref: process.env.LITE_LLM_MODEL_PREF,
|
|
|
|
LiteLLMTokenLimit: process.env.LITE_LLM_MODEL_TOKEN_LIMIT,
|
|
|
|
LiteLLMBasePath: process.env.LITE_LLM_BASE_PATH,
|
|
|
|
LiteLLMApiKey: !!process.env.LITE_LLM_API_KEY,
|
|
|
|
|
2024-04-23 22:06:07 +02:00
|
|
|
// Generic OpenAI Keys
|
|
|
|
GenericOpenAiBasePath: process.env.GENERIC_OPEN_AI_BASE_PATH,
|
|
|
|
GenericOpenAiModelPref: process.env.GENERIC_OPEN_AI_MODEL_PREF,
|
|
|
|
GenericOpenAiTokenLimit: process.env.GENERIC_OPEN_AI_MODEL_TOKEN_LIMIT,
|
|
|
|
GenericOpenAiKey: !!process.env.GENERIC_OPEN_AI_API_KEY,
|
2024-05-10 23:49:02 +02:00
|
|
|
GenericOpenAiMaxTokens: process.env.GENERIC_OPEN_AI_MAX_TOKENS,
|
2024-05-02 19:35:50 +02:00
|
|
|
|
2024-07-24 01:35:37 +02:00
|
|
|
AwsBedrockLLMAccessKeyId: !!process.env.AWS_BEDROCK_LLM_ACCESS_KEY_ID,
|
|
|
|
AwsBedrockLLMAccessKey: !!process.env.AWS_BEDROCK_LLM_ACCESS_KEY,
|
|
|
|
AwsBedrockLLMRegion: process.env.AWS_BEDROCK_LLM_REGION,
|
|
|
|
AwsBedrockLLMModel: process.env.AWS_BEDROCK_LLM_MODEL_PREFERENCE,
|
|
|
|
AwsBedrockLLMTokenLimit: process.env.AWS_BEDROCK_LLM_MODEL_TOKEN_LIMIT,
|
|
|
|
|
2024-05-02 19:35:50 +02:00
|
|
|
// Cohere API Keys
|
|
|
|
CohereApiKey: !!process.env.COHERE_API_KEY,
|
|
|
|
CohereModelPref: process.env.COHERE_MODEL_PREF,
|
2024-05-19 20:20:23 +02:00
|
|
|
|
|
|
|
// VoyageAi API Keys
|
|
|
|
VoyageAiApiKey: !!process.env.VOYAGEAI_API_KEY,
|
2024-09-26 21:55:12 +02:00
|
|
|
|
|
|
|
// DeepSeek API Keys
|
|
|
|
DeepSeekApiKey: !!process.env.DEEPSEEK_API_KEY,
|
|
|
|
DeepSeekModelPref: process.env.DEEPSEEK_MODEL_PREF,
|
2024-10-15 21:36:06 +02:00
|
|
|
|
|
|
|
// APIPie LLM API Keys
|
|
|
|
ApipieLLMApiKey: !!process.env.APIPIE_LLM_API_KEY,
|
|
|
|
ApipieLLMModelPref: process.env.APIPIE_LLM_MODEL_PREF,
|
2024-10-22 01:32:49 +02:00
|
|
|
|
|
|
|
// xAI LLM API Keys
|
|
|
|
XAIApiKey: !!process.env.XAI_LLM_API_KEY,
|
|
|
|
XAIModelPref: process.env.XAI_LLM_MODEL_PREF,
|
2024-04-05 19:58:36 +02:00
|
|
|
};
|
|
|
|
},
|
2024-05-16 19:38:21 +02:00
|
|
|
|
|
|
|
// For special retrieval of a key setting that does not expose any credential information
|
|
|
|
brief: {
|
|
|
|
agent_sql_connections: async function () {
|
|
|
|
const setting = await SystemSettings.get({
|
|
|
|
label: "agent_sql_connections",
|
|
|
|
});
|
|
|
|
if (!setting) return [];
|
|
|
|
return safeJsonParse(setting.value, []).map((dbConfig) => {
|
|
|
|
const { connectionString, ...rest } = dbConfig;
|
|
|
|
return rest;
|
|
|
|
});
|
|
|
|
},
|
|
|
|
},
|
2024-06-21 22:38:50 +02:00
|
|
|
getFeatureFlags: async function () {
|
|
|
|
return {
|
|
|
|
experimental_live_file_sync:
|
|
|
|
(await SystemSettings.get({ label: "experimental_live_file_sync" }))
|
|
|
|
?.value === "enabled",
|
|
|
|
};
|
|
|
|
},
|
2023-07-25 19:37:04 +02:00
|
|
|
};
|
|
|
|
|
2024-05-16 19:38:21 +02:00
|
|
|
function mergeConnections(existingConnections = [], updates = []) {
|
|
|
|
let updatedConnections = [...existingConnections];
|
|
|
|
const existingDbIds = existingConnections.map((conn) => conn.database_id);
|
|
|
|
|
|
|
|
// First remove all 'action:remove' candidates from existing connections.
|
|
|
|
const toRemove = updates
|
|
|
|
.filter((conn) => conn.action === "remove")
|
|
|
|
.map((conn) => conn.database_id);
|
|
|
|
updatedConnections = updatedConnections.filter(
|
|
|
|
(conn) => !toRemove.includes(conn.database_id)
|
|
|
|
);
|
|
|
|
|
|
|
|
// Next add all 'action:add' candidates into the updatedConnections; We DO NOT validate the connection strings.
|
|
|
|
// but we do validate their database_id is unique.
|
|
|
|
updates
|
|
|
|
.filter((conn) => conn.action === "add")
|
|
|
|
.forEach((update) => {
|
|
|
|
if (!update.connectionString) return; // invalid connection string
|
|
|
|
|
|
|
|
// Remap name to be unique to entire set.
|
|
|
|
if (existingDbIds.includes(update.database_id)) {
|
|
|
|
update.database_id = slugify(
|
|
|
|
`${update.database_id}-${v4().slice(0, 4)}`
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
update.database_id = slugify(update.database_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
updatedConnections.push({
|
|
|
|
engine: update.engine,
|
|
|
|
database_id: update.database_id,
|
|
|
|
connectionString: update.connectionString,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
return updatedConnections;
|
|
|
|
}
|
|
|
|
|
2023-07-25 19:37:04 +02:00
|
|
|
module.exports.SystemSettings = SystemSettings;
|