Custom Default System Prompt (#4487)

* Add Default System Prompt Management

- Introduced a new route for fetching and updating the default system prompt in the backend.
- Added a new Admin page for managing the default system prompt, including a form for editing and saving changes.
- Updated the SettingsSidebar to include a link to the new Default System Prompt page.
- Implemented fetching of available system prompt variables for use in the prompt editor.
- Enhanced the ChatSettings and ChatPromptSettings components to support the new default system prompt functionality.

This commit lays the groundwork for improved management of system prompts across workspaces.

* Remove validation for system prompt in ChatSettings component

* Add comment for system prompt in workspaces model

* linting, simplify logic for default assumption

* dev build

---------

Co-authored-by: timothycarambat <rambat1010@gmail.com>
This commit is contained in:
Marcello Fitton 2025-11-24 13:24:10 -08:00 committed by GitHub
parent de11a06622
commit 5716ac5ed5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 477 additions and 69 deletions

View File

@ -6,7 +6,7 @@ concurrency:
on:
push:
branches: ['4595-refactor-pwa'] # put your current branch to create a build. Core team only.
branches: ['3906-global-default-system-prompt'] # put your current branch to create a build. Core team only.
paths-ignore:
- '**.md'
- 'cloud-deployments/*'

View File

@ -93,6 +93,9 @@ const SystemPromptVariables = lazy(
const MobileConnections = lazy(
() => import("@/pages/GeneralSettings/MobileConnections")
);
const DefaultSystemPrompt = lazy(
() => import("@/pages/Admin/DefaultSystemPrompt")
);
export default function App() {
return (
@ -215,6 +218,10 @@ export default function App() {
path="/settings/branding"
element={<ManagerRoute Component={BrandingSettings} />}
/>
<Route
path="/settings/default-system-prompt"
element={<AdminRoute Component={DefaultSystemPrompt} />}
/>
<Route
path="/settings/chat"
element={<ManagerRoute Component={ChatSettings} />}

View File

@ -285,6 +285,12 @@ const SidebarOptions = ({ user = null, t }) => (
href: paths.settings.invites(),
roles: ["admin", "manager"],
},
{
btnText: "Default System Prompt",
href: paths.settings.defaultSystemPrompt(),
flex: true,
roles: ["admin"],
},
]}
/>
<Option

View File

@ -346,6 +346,39 @@ const System = {
);
return { appName: customAppName, error: null };
},
/**
* Fetches the default system prompt from the server.
* @returns {Promise<{defaultSystemPrompt: string, saneDefaultSystemPrompt: string}>}
*/
fetchDefaultSystemPrompt: async function () {
return await fetch(`${API_BASE}/system/default-system-prompt`, {
method: "GET",
headers: baseHeaders(),
})
.then((res) => res.json())
.then((res) => ({
defaultSystemPrompt: res.defaultSystemPrompt,
saneDefaultSystemPrompt: res.saneDefaultSystemPrompt,
}))
.catch((e) => {
console.error(e);
return { defaultSystemPrompt: "", saneDefaultSystemPrompt: "" };
});
},
updateDefaultSystemPrompt: async function (defaultSystemPrompt) {
try {
const res = await fetch(`${API_BASE}/system/default-system-prompt`, {
method: "POST",
headers: baseHeaders(),
body: JSON.stringify({ defaultSystemPrompt }),
});
const data = await res.json();
return data;
} catch (e) {
console.error(e);
return { success: false, message: e.message };
}
},
fetchLogo: async function () {
const url = new URL(`${fullApiUrl()}/system/logo`);
url.searchParams.append(

View File

@ -0,0 +1,270 @@
import SettingsSidebar from "@/components/SettingsSidebar";
import { useEffect, useState, Fragment } from "react";
import { isMobile } from "react-device-detect";
import System from "@/models/system";
import showToast from "@/utils/toast";
import * as Skeleton from "react-loading-skeleton";
import "react-loading-skeleton/dist/skeleton.css";
import Highlighter from "react-highlight-words";
import SystemPromptVariable from "@/models/systemPromptVariable";
import { Link } from "react-router-dom";
import paths from "@/utils/paths";
export default function DefaultSystemPrompt() {
const [systemPromptForm, setSystemPromptForm] = useState({
value: "",
default: "",
isDirty: false,
isSubmitting: false,
isLoading: true,
isEditing: false,
});
const [saneDefaultSystemPrompt, setSaneDefaultSystemPrompt] = useState("");
const [availableVariables, setAvailableVariables] = useState([]);
useEffect(() => {
async function setupVariableHighlighting() {
const { variables } = await SystemPromptVariable.getAll();
setAvailableVariables(variables);
}
setupVariableHighlighting();
}, []);
useEffect(() => {
async function fetchDefaultSystemPrompt() {
setSystemPromptForm((prev) => ({
...prev,
isLoading: true,
}));
const { defaultSystemPrompt, saneDefaultSystemPrompt } =
await System.fetchDefaultSystemPrompt();
setSaneDefaultSystemPrompt(saneDefaultSystemPrompt);
if (!defaultSystemPrompt)
return setSystemPromptForm((prev) => ({
...prev,
isLoading: false,
}));
setSystemPromptForm((prev) => ({
...prev,
default: defaultSystemPrompt,
value: defaultSystemPrompt,
isLoading: false,
}));
}
fetchDefaultSystemPrompt();
}, []);
const handleChange = (e) => {
const value = e.target.value;
const isDirty = value !== systemPromptForm.default;
setSystemPromptForm((prev) => ({
...prev,
value,
isDirty,
isSubmitting: false,
}));
};
const handleSubmit = async (e) => {
e.preventDefault();
setSystemPromptForm((prev) => ({
...prev,
isSubmitting: true,
}));
const newSystemPrompt = systemPromptForm.value.trim();
await System.updateDefaultSystemPrompt(newSystemPrompt)
.then(({ success, message }) => {
if (!success) throw new Error(message);
// If the user has set the default system prompt to the sane default, reset the value to the sane default.
if (
!newSystemPrompt ||
newSystemPrompt.trim() === saneDefaultSystemPrompt
) {
return setSystemPromptForm((prev) => ({
...prev,
value: saneDefaultSystemPrompt,
}));
}
showToast("Default system prompt updated successfully.", "success");
setSystemPromptForm((prev) => ({
...prev,
default: newSystemPrompt,
isDirty: false,
isSubmitting: false,
}));
})
.catch((error) => {
showToast(
`Failed to update default system prompt: ${error.message}`,
"error"
);
setSystemPromptForm((prev) => ({
...prev,
isSubmitting: false,
}));
});
};
return (
<div className="w-screen h-screen overflow-hidden bg-theme-bg-container flex">
<SettingsSidebar />
<div
style={{ height: isMobile ? "100%" : "calc(100% - 32px)" }}
className="relative md:ml-[2px] md:mr-[16px] md:my-[16px] md:rounded-[16px] bg-theme-bg-secondary w-full h-full overflow-y-scroll p-4 md:p-0"
>
<div className="flex flex-col w-full px-1 md:pl-6 md:pr-[50px] md:py-6 py-16">
<div className="w-full flex flex-col gap-y-1 pb-6 border-white/10 border-b-2">
<div className="items-center flex gap-x-4">
<p className="text-lg leading-6 font-bold text-theme-text-primary">
Default System Prompt
</p>
</div>
<p className="text-xs leading-[18px] font-base text-theme-text-secondary">
This is the default system prompt that will be used for new
workspaces.
</p>
</div>
<div>
{systemPromptForm.isLoading ? (
<div className="mt-8 flex flex-col gap-y-4">
<Skeleton.default
height={20}
width={160}
highlightColor="var(--theme-bg-primary)"
baseColor="var(--theme-bg-secondary)"
/>
<Skeleton.default
height={120}
width="100%"
highlightColor="var(--theme-bg-primary)"
baseColor="var(--theme-bg-secondary)"
className="rounded-lg"
/>
<Skeleton.default
height={36}
width={140}
highlightColor="var(--theme-bg-primary)"
baseColor="var(--theme-bg-secondary)"
/>
</div>
) : (
<div className="mt-6">
<form onSubmit={handleSubmit} className="space-y-3">
<label
htmlFor="default-system-prompt"
className=" text-base font-bold text-white"
>
System Prompt
</label>
<div className="space-y-1">
<p className="text-white text-opacity-60 text-xs font-medium">
A system prompt provides instructions that shape the AIs
responses and behavior. This prompt will be automatically
applied to all newly created workspaces. To change the
system prompt of a{" "}
<span className="font-bold">specific workspace</span>,
edit the prompt in the{" "}
<span className="font-bold">workspace settings</span>. To
restore the system prompt to our sane default, leave this
field empty and save changes.
</p>
<p className="text-white text-opacity-60 text-xs font-medium mb-2">
You can insert{" "}
<Link
to={paths.settings.systemPromptVariables()}
className="text-primary-button"
>
system prompt variables
</Link>{" "}
like:{" "}
{availableVariables.slice(0, 3).map((v, i) => (
<Fragment key={v.key}>
<span className="bg-theme-settings-input-bg px-1 py-0.5 rounded">
{`{${v.key}}`}
</span>
{i < availableVariables.length - 1 && ", "}
</Fragment>
))}
{availableVariables.length > 3 && (
<Link
to={paths.settings.systemPromptVariables()}
className="text-primary-button"
>
+{availableVariables.length - 3} more...
</Link>
)}
</p>
</div>
{systemPromptForm.isEditing ? (
<textarea
autoFocus={true}
value={systemPromptForm.value}
onChange={handleChange}
onBlur={() =>
setSystemPromptForm((prev) => ({
...prev,
isEditing: false,
}))
}
placeholder={
systemPromptForm.isLoading
? "Loading..."
: "You are an AI assistant that can answer questions and help with tasks."
}
rows={5}
style={{
resize: "vertical",
overflowY: "scroll",
minHeight: "150px",
}}
className="w-full border-none bg-theme-settings-input-bg placeholder:text-theme-settings-input-placeholder text-white text-sm rounded-lg focus:outline-primary-button active:outline-primary-button outline-none block p-2.5"
/>
) : (
<div
onClick={() =>
setSystemPromptForm((prev) => ({
...prev,
isEditing: true,
}))
}
style={{
resize: "vertical",
overflowY: "scroll",
minHeight: "150px",
}}
className="w-full border-none bg-theme-settings-input-bg text-white text-sm rounded-lg focus:outline-primary-button active:outline-primary-button outline-none block p-2.5 cursor-text"
>
<Highlighter
className="whitespace-pre-wrap"
highlightClassName="bg-cta-button p-0.5 rounded-md"
searchWords={availableVariables.map(
(v) => `{${v.key}}`
)}
autoEscape={true}
caseSensitive={true}
textToHighlight={systemPromptForm.value || ""}
/>
</div>
)}
<button
disabled={
!systemPromptForm.isDirty || systemPromptForm.isSubmitting
}
className={`enabled:hover:bg-secondary enabled:hover:text-white rounded-lg bg-primary-button w-fit py-2 px-4 font-semibold text-xs disabled:opacity-20 disabled:cursor-not-allowed`}
type="submit"
>
Save Changes
</button>
</form>
</div>
)}
</div>
</div>
</div>
</div>
);
}

View File

@ -1,5 +1,5 @@
import { useEffect, useState, useRef, Fragment } from "react";
import { chatPrompt } from "@/utils/chat";
import { getWorkspaceSystemPrompt } from "@/utils/chat";
import { useTranslation } from "react-i18next";
import SystemPromptVariable from "@/models/systemPromptVariable";
import Highlighter from "react-highlight-words";
@ -8,47 +8,75 @@ import paths from "@/utils/paths";
import ChatPromptHistory from "./ChatPromptHistory";
import PublishEntityModal from "@/components/CommunityHub/PublishEntityModal";
import { useModal } from "@/hooks/useModal";
import System from "@/models/system";
// TODO: Move to backend and have user-language sensitive default prompt
const DEFAULT_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.";
export default function ChatPromptSettings({ workspace, setHasChanges }) {
export default function ChatPromptSettings({
workspace,
setHasChanges,
hasChanges,
}) {
const { t } = useTranslation();
const [availableVariables, setAvailableVariables] = useState([]);
const [prompt, setPrompt] = useState(chatPrompt(workspace));
const [searchParams] = useSearchParams();
// Prompt state
const initialPrompt = getWorkspaceSystemPrompt(workspace);
const [prompt, setPrompt] = useState(initialPrompt);
const [savedPrompt, setSavedPrompt] = useState(initialPrompt);
const [defaultSystemPrompt, setDefaultSystemPrompt] = useState("");
// UI state
const [isEditing, setIsEditing] = useState(false);
const [showPromptHistory, setShowPromptHistory] = useState(false);
const [availableVariables, setAvailableVariables] = useState([]);
// Refs
const promptRef = useRef(null);
const promptHistoryRef = useRef(null);
const historyButtonRef = useRef(null);
const [searchParams] = useSearchParams();
// Modals
const {
isOpen: showPublishModal,
closeModal: closePublishModal,
openModal: openPublishModal,
} = useModal();
const [currentPrompt, setCurrentPrompt] = useState(chatPrompt(workspace));
// Derived state
const isDirty = prompt !== savedPrompt;
const hasBeenModified = savedPrompt?.trim() !== initialPrompt?.trim();
const showPublishButton =
!isEditing && prompt?.trim().length >= 10 && (isDirty || hasBeenModified);
// Load variables and handle focus on mount
useEffect(() => {
async function setupVariableHighlighting() {
const { variables } = await SystemPromptVariable.getAll();
setAvailableVariables(variables);
}
setupVariableHighlighting();
}, []);
useEffect(() => {
if (searchParams.get("action") === "focus-system-prompt")
setIsEditing(true);
}, [searchParams]);
// Update saved prompt when parent clears hasChanges
useEffect(() => {
if (!hasChanges) setSavedPrompt(prompt);
}, [hasChanges, prompt]);
// Auto-focus textarea when editing
useEffect(() => {
if (isEditing && promptRef.current) {
promptRef.current.focus();
}
}, [isEditing]);
useEffect(() => {
System.fetchDefaultSystemPrompt().then(({ defaultSystemPrompt }) =>
setDefaultSystemPrompt(defaultSystemPrompt)
);
}, []);
// Handle click outside for history panel
useEffect(() => {
const handleClickOutside = (event) => {
if (
@ -61,22 +89,27 @@ export default function ChatPromptSettings({ workspace, setHasChanges }) {
}
};
document.addEventListener("mousedown", handleClickOutside);
return () => {
document.removeEventListener("mousedown", handleClickOutside);
};
return () => document.removeEventListener("mousedown", handleClickOutside);
}, []);
const handleRestore = (prompt) => {
setPrompt(prompt);
const handleRestoreFromHistory = (historicalPrompt) => {
setPrompt(historicalPrompt);
setShowPromptHistory(false);
setHasChanges(true);
};
const handlePublishClick = (prompt) => {
setCurrentPrompt(prompt);
setShowPromptHistory(false);
const handlePublishFromHistory = (historicalPrompt) => {
openPublishModal();
setShowPromptHistory(false);
setTimeout(() => setPrompt(historicalPrompt), 0);
};
// Restore to default system prompt, if no default system prompt is set
const handleRestoreToDefaultSystemPrompt = () => {
System.fetchDefaultSystemPrompt().then(({ defaultSystemPrompt }) => {
setPrompt(defaultSystemPrompt);
setHasChanges(true);
});
};
return (
@ -85,11 +118,9 @@ export default function ChatPromptSettings({ workspace, setHasChanges }) {
ref={promptHistoryRef}
workspaceSlug={workspace.slug}
show={showPromptHistory}
onRestore={handleRestore}
onPublishClick={handlePublishClick}
onClose={() => {
setShowPromptHistory(false);
}}
onRestore={handleRestoreFromHistory}
onPublishClick={handlePublishFromHistory}
onClose={() => setShowPromptHistory(false)}
/>
<div>
<div className="flex flex-col">
@ -129,7 +160,7 @@ export default function ChatPromptSettings({ workspace, setHasChanges }) {
</p>
</div>
<input type="hidden" name="openAiPrompt" defaultValue={prompt} />
<input type="hidden" name="openAiPrompt" value={prompt} />
<div className="relative w-full flex flex-col items-end">
<button
ref={historyButtonRef}
@ -143,11 +174,6 @@ export default function ChatPromptSettings({ workspace, setHasChanges }) {
{showPromptHistory ? "Hide History" : "View History"}
</button>
<div className="relative w-full">
<span
className={`${!!prompt ? "hidden" : "block"} text-sm pointer-events-none absolute top-2 left-0 p-2.5 w-full h-full !text-theme-settings-input-placeholder opacity-60`}
>
{DEFAULT_PROMPT}
</span>
{isEditing ? (
<textarea
ref={promptRef}
@ -199,28 +225,19 @@ export default function ChatPromptSettings({ workspace, setHasChanges }) {
)}
</div>
<div className="w-full flex flex-row items-center justify-between pt-2">
{prompt !== DEFAULT_PROMPT && (
<>
<button
type="button"
onClick={() => handleRestore(DEFAULT_PROMPT)}
className="text-theme-text-primary hover:text-white light:hover:text-black text-xs font-medium"
>
Clear
</button>
<PublishPromptCTA
hidden={
isEditing ||
prompt === DEFAULT_PROMPT ||
prompt?.trim().length < 10
}
onClick={() => {
setCurrentPrompt(prompt);
openPublishModal();
}}
/>
</>
{prompt !== defaultSystemPrompt && (
<button
type="button"
onClick={handleRestoreToDefaultSystemPrompt}
className="text-theme-text-primary hover:text-white light:hover:text-black text-xs font-medium"
>
Restore to Default
</button>
)}
<PublishPromptCTA
hidden={!showPublishButton}
onClick={openPublishModal}
/>
</div>
</div>
</div>
@ -228,7 +245,7 @@ export default function ChatPromptSettings({ workspace, setHasChanges }) {
show={showPublishModal}
onClose={closePublishModal}
entityType="system-prompt"
entity={currentPrompt}
entity={prompt}
/>
</>
);

View File

@ -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 }) {
<ChatPromptSettings
workspace={workspace}
setHasChanges={setHasChanges}
hasChanges={hasChanges}
/>
<ChatQueryRefusalResponse
workspace={workspace}

View File

@ -179,7 +179,7 @@ export default function handleChat(
}
}
export function chatPrompt(workspace) {
export function getWorkspaceSystemPrompt(workspace) {
return (
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."

View File

@ -120,6 +120,9 @@ export default {
audioPreference: () => {
return "/settings/audio-preference";
},
defaultSystemPrompt: () => {
return "/settings/default-system-prompt";
},
embedder: {
modelPreference: () => "/settings/embedding-preference",
chunkingPreference: () => "/settings/text-splitter-preference",

View File

@ -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",

View File

@ -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");

View File

@ -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: {

View File

@ -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?

View File

@ -89,9 +89,9 @@ async function recentChatHistory({
* @returns {Promise<string>} - 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,

View File

@ -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}`;
}
/**