@@ -129,7 +160,7 @@ export default function ChatPromptSettings({ workspace, setHasChanges }) {
-
+
@@ -228,7 +245,7 @@ export default function ChatPromptSettings({ workspace, setHasChanges }) {
show={showPublishModal}
onClose={closePublishModal}
entityType="system-prompt"
- entity={currentPrompt}
+ entity={prompt}
/>
>
);
diff --git a/frontend/src/pages/WorkspaceSettings/ChatSettings/index.jsx b/frontend/src/pages/WorkspaceSettings/ChatSettings/index.jsx
index d551183e..e133dfac 100644
--- a/frontend/src/pages/WorkspaceSettings/ChatSettings/index.jsx
+++ b/frontend/src/pages/WorkspaceSettings/ChatSettings/index.jsx
@@ -26,22 +26,24 @@ export default function ChatSettings({ workspace }) {
}, []);
const handleUpdate = async (e) => {
- setSaving(true);
e.preventDefault();
+ setSaving(true);
const data = {};
const form = new FormData(formEl.current);
for (var [key, value] of form.entries()) data[key] = castToType(key, value);
+
const { workspace: updatedWorkspace, message } = await Workspace.update(
workspace.slug,
data
);
- if (!!updatedWorkspace) {
+ if (updatedWorkspace) {
showToast("Workspace updated!", "success", { clear: true });
+ setHasChanges(false);
} else {
showToast(`Error: ${message}`, "error", { clear: true });
+ // Keep hasChanges true on error so user can retry
}
setSaving(false);
- setHasChanges(false);
};
if (!workspace) return null;
@@ -76,6 +78,7 @@ export default function ChatSettings({ workspace }) {
{
return "/settings/audio-preference";
},
+ defaultSystemPrompt: () => {
+ return "/settings/default-system-prompt";
+ },
embedder: {
modelPreference: () => "/settings/embedding-preference",
chunkingPreference: () => "/settings/text-splitter-preference",
diff --git a/server/endpoints/system.js b/server/endpoints/system.js
index fcefd338..f4e9099a 100644
--- a/server/endpoints/system.js
+++ b/server/endpoints/system.js
@@ -734,6 +734,57 @@ function systemEndpoints(app) {
}
}
);
+ app.get(
+ "/system/default-system-prompt",
+ [validatedRequest, flexUserRoleValid([ROLES.all])],
+ async (_, response) => {
+ try {
+ const defaultSystemPrompt = await SystemSettings.get({
+ label: "default_system_prompt",
+ });
+
+ response.status(200).json({
+ success: true,
+ defaultSystemPrompt:
+ defaultSystemPrompt?.value ||
+ SystemSettings.saneDefaultSystemPrompt,
+ saneDefaultSystemPrompt: SystemSettings.saneDefaultSystemPrompt,
+ });
+ } catch (error) {
+ console.error("Error fetching default system prompt:", error);
+ response
+ .status(500)
+ .json({ success: false, message: "Internal server error" });
+ }
+ }
+ );
+
+ app.post(
+ "/system/default-system-prompt",
+ [validatedRequest, flexUserRoleValid([ROLES.admin])],
+ async (request, response) => {
+ try {
+ const { defaultSystemPrompt } = reqBody(request);
+ const { success, error } = await SystemSettings.updateSettings({
+ default_system_prompt: defaultSystemPrompt,
+ });
+ if (!success)
+ throw new Error(
+ error.message || "Failed to update default system prompt."
+ );
+ response.status(200).json({
+ success: true,
+ message: "Default system prompt updated successfully.",
+ });
+ } catch (error) {
+ console.error("Error updating default system prompt:", error);
+ response.status(500).json({
+ success: false,
+ message: error.message || "Internal server error",
+ });
+ }
+ }
+ );
app.delete(
"/system/remove-pfp",
diff --git a/server/models/systemSettings.js b/server/models/systemSettings.js
index ce3a0063..facc466f 100644
--- a/server/models/systemSettings.js
+++ b/server/models/systemSettings.js
@@ -17,6 +17,9 @@ function isNullOrNaN(value) {
}
const SystemSettings = {
+ /** A default system prompt that is used when no other system prompt is set or available to the function caller. */
+ saneDefaultSystemPrompt:
+ "Given the following conversation, relevant context, and a follow up question, reply with an answer to the current question the user is asking. Return only your response to the question given the above information following the users instructions as needed.",
protectedFields: ["multi_user_mode", "hub_api_key"],
publicFields: [
"footer_data",
@@ -47,6 +50,7 @@ const SystemSettings = {
"disabled_agent_skills",
"agent_sql_connections",
"custom_app_name",
+ "default_system_prompt",
// Meta page customization
"meta_page_title",
@@ -192,6 +196,12 @@ const SystemSettings = {
if (!apiKey) return null;
return String(apiKey);
},
+ default_system_prompt: (prompt) => {
+ if (typeof prompt !== "string" || !prompt) return null;
+ if (prompt.trim() === SystemSettings.saneDefaultSystemPrompt)
+ return SystemSettings.saneDefaultSystemPrompt;
+ return String(prompt.trim());
+ },
},
currentSettings: async function () {
const { hasVectorCachedFiles } = require("../utils/files");
diff --git a/server/models/workspace.js b/server/models/workspace.js
index 6b361d6b..219030df 100644
--- a/server/models/workspace.js
+++ b/server/models/workspace.js
@@ -6,6 +6,7 @@ const { ROLES } = require("../utils/middleware/multiUserProtected");
const { v4: uuidv4 } = require("uuid");
const { User } = require("./user");
const { PromptHistory } = require("./promptHistory");
+const { SystemSettings } = require("./systemSettings");
function isNullOrNaN(value) {
if (value === null) return true;
@@ -32,8 +33,7 @@ function isNullOrNaN(value) {
*/
const Workspace = {
- defaultPrompt:
- "Given the following conversation, relevant context, and a follow up question, reply with an answer to the current question the user is asking. Return only your response to the question given the above information following the users instructions as needed.",
+ defaultPrompt: SystemSettings.saneDefaultSystemPrompt,
// Used for generic updates so we can validate keys in request body
// commented fields are not writable, but are available on the db object
@@ -193,6 +193,14 @@ const Workspace = {
slug = this.slugify(`${name}-${slugSeed}`, { lower: true });
}
+ // Get the default system prompt
+ const defaultSystemPrompt = await SystemSettings.get({
+ label: "default_system_prompt",
+ });
+ if (!!defaultSystemPrompt?.value)
+ additionalFields.openAiPrompt = defaultSystemPrompt.value;
+ else additionalFields.openAiPrompt = this.defaultPrompt;
+
try {
const workspace = await prisma.workspaces.create({
data: {
diff --git a/server/prisma/schema.prisma b/server/prisma/schema.prisma
index a3db69f1..eda6878b 100644
--- a/server/prisma/schema.prisma
+++ b/server/prisma/schema.prisma
@@ -132,6 +132,7 @@ model workspaces {
openAiTemp Float?
openAiHistory Int @default(20)
lastUpdatedAt DateTime @default(now())
+ // THIS IS THE SYSTEM PROMPT FOR THE WORKSPACE
openAiPrompt String?
similarityThreshold Float? @default(0.25)
chatProvider String?
diff --git a/server/utils/chats/index.js b/server/utils/chats/index.js
index aaf46bc2..19654dec 100644
--- a/server/utils/chats/index.js
+++ b/server/utils/chats/index.js
@@ -89,9 +89,9 @@ async function recentChatHistory({
* @returns {Promise} - the base prompt
*/
async function chatPrompt(workspace, user = null) {
+ const { SystemSettings } = require("../../models/systemSettings");
const basePrompt =
- workspace?.openAiPrompt ??
- "Given the following conversation, relevant context, and a follow up question, reply with an answer to the current question the user is asking. Return only your response to the question given the above information following the users instructions as needed.";
+ workspace?.openAiPrompt ?? SystemSettings.saneDefaultSystemPrompt;
return await SystemPromptVariables.expandSystemPromptVariables(
basePrompt,
user?.id,
diff --git a/server/utils/helpers/chat/convertTo.js b/server/utils/helpers/chat/convertTo.js
index 9ec2b838..a3d94bb0 100644
--- a/server/utils/helpers/chat/convertTo.js
+++ b/server/utils/helpers/chat/convertTo.js
@@ -4,6 +4,7 @@
const { WorkspaceChats } = require("../../../models/workspaceChats");
const { EmbedChats } = require("../../../models/embedChats");
const { safeJsonParse } = require("../../http");
+const { SystemSettings } = require("../../../models/systemSettings");
async function convertToCSV(preparedData) {
const headers = new Set(["id", "workspace", "prompt", "response", "sent_at"]);
@@ -146,8 +147,8 @@ async function prepareChatsForExport(format = "jsonl", chatType = "workspace") {
{
type: "text",
text:
- chat.workspace?.openAiPrompt ||
- "Given the following conversation, relevant context, and a follow up question, reply with an answer to the current question the user is asking. Return only your response to the question given the above information following the users instructions as needed.",
+ chat.workspace?.openAiPrompt ??
+ SystemSettings.saneDefaultSystemPrompt,
},
],
},
@@ -223,8 +224,6 @@ async function exportChatsAsType(format = "jsonl", chatType = "workspace") {
};
}
-const STANDARD_PROMPT =
- "Given the following conversation, relevant context, and a follow up question, reply with an answer to the current question the user is asking. Return only your response to the question given the above information following the users instructions as needed.";
function buildSystemPrompt(chat, prompt = null) {
const sources = safeJsonParse(chat.response)?.sources || [];
const contextTexts = sources.map((source) => source.text);
@@ -237,7 +236,7 @@ function buildSystemPrompt(chat, prompt = null) {
})
.join("")
: "";
- return `${prompt ?? STANDARD_PROMPT}${context}`;
+ return `${prompt ?? SystemSettings.saneDefaultSystemPrompt}${context}`;
}
/**