system prompt backend
This commit is contained in:
@@ -34,6 +34,10 @@ function getDB() {
|
|||||||
db.exec(`ALTER TABLE projects ADD COLUMN notes TEXT`); // ← add this
|
db.exec(`ALTER TABLE projects ADD COLUMN notes TEXT`); // ← add this
|
||||||
} catch {}
|
} catch {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
db.exec(`ALTER TABLE projects ADD COLUMN system_prompt TEXT`);
|
||||||
|
} catch {}
|
||||||
|
|
||||||
// Sync FTS index with any existing episodes data
|
// Sync FTS index with any existing episodes data
|
||||||
db.exec(`INSERT OR REPLACE INTO episodes_fts(rowid, user_message, ai_response)
|
db.exec(`INSERT OR REPLACE INTO episodes_fts(rowid, user_message, ai_response)
|
||||||
SELECT id, user_message, ai_response FROM episodes`);
|
SELECT id, user_message, ai_response FROM episodes`);
|
||||||
|
|||||||
@@ -4,10 +4,9 @@ const embedding = require("../services/embedding");
|
|||||||
const qdrant = require("../services/qdrant");
|
const qdrant = require("../services/qdrant");
|
||||||
const { ORCHESTRATION } = require("@nexusai/shared");
|
const { ORCHESTRATION } = require("@nexusai/shared");
|
||||||
const appSettings = require("../config/settings");
|
const appSettings = require("../config/settings");
|
||||||
const { SYSTEM_PROMPT } = ORCHESTRATION;
|
|
||||||
|
|
||||||
function buildPrompt(recentEpisodes, semanticEpisodes, entities, userMessage) {
|
function buildPrompt(recentEpisodes, semanticEpisodes, entities, userMessage, systemPrompt) {
|
||||||
const parts = [SYSTEM_PROMPT];
|
const parts = [systemPrompt ?? ORCHESTRATION.SYSTEM_PROMPT];
|
||||||
|
|
||||||
if (entities.length > 0) {
|
if (entities.length > 0) {
|
||||||
parts.push(
|
parts.push(
|
||||||
@@ -126,30 +125,21 @@ async function getRelevantEntities(userMessage, projectId=null) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function chat(externalId, userMessage, options = {}) {
|
async function chat(externalId, userMessage, options = {}) {
|
||||||
const { recentEpisodeLimit, semanticLimit, scoreThreshold, temperature, repeatPenalty, topP, topK} =
|
const { recentEpisodeLimit, semanticLimit, scoreThreshold, temperature, repeatPenalty, topP, topK, systemPrompt} =
|
||||||
appSettings.load();
|
appSettings.load();
|
||||||
// 1. Resolve or create session
|
// 1. Resolve or create session
|
||||||
let session = await memory.getSessionByExternalId(externalId);
|
let session = await memory.getSessionByExternalId(externalId);
|
||||||
if (!session) session = await memory.createSession(externalId);
|
if (!session) session = await memory.createSession(externalId);
|
||||||
|
|
||||||
let projectSessionIds = null;
|
let projectSessionIds = null;
|
||||||
|
let activeSystemPrompt = systemPrompt ?? ORCHESTRATION.SYSTEM_PROMPT;
|
||||||
if (session.project_id) {
|
if (session.project_id) {
|
||||||
try {
|
try {
|
||||||
const project = await memory.getProject(session.project_id);
|
const project = await memory.getProject(session.project_id);
|
||||||
if (project) {
|
if (project) {
|
||||||
const projectSessions = await memory.getProjectSessions(
|
const projectSessions = await memory.getProjectSessions(session.project_id);
|
||||||
session.project_id,
|
if (project?.system_prompt) activeSystemPrompt = project.system_prompt;
|
||||||
);
|
|
||||||
projectSessionIds = projectSessions.map((s) => s.id);
|
projectSessionIds = projectSessions.map((s) => s.id);
|
||||||
if (project.isolated === 1) {
|
|
||||||
console.log(
|
|
||||||
`[orchestration] Isolated project — restricting to ${projectSessionIds.length} sessions`,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
console.log(
|
|
||||||
`[orchestration] Non-isolated project — expanding search to ${projectSessionIds.length} sessions`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.warn(
|
console.warn(
|
||||||
@@ -184,6 +174,7 @@ async function chat(externalId, userMessage, options = {}) {
|
|||||||
semanticEpisodes,
|
semanticEpisodes,
|
||||||
entities,
|
entities,
|
||||||
userMessage,
|
userMessage,
|
||||||
|
activeSystemPrompt,
|
||||||
);
|
);
|
||||||
|
|
||||||
// 5. Run inference
|
// 5. Run inference
|
||||||
@@ -218,11 +209,12 @@ async function chat(externalId, userMessage, options = {}) {
|
|||||||
|
|
||||||
async function chatStream(externalId, userMessage, onChunk, options = {}) {
|
async function chatStream(externalId, userMessage, onChunk, options = {}) {
|
||||||
try {
|
try {
|
||||||
const { recentEpisodeLimit, semanticLimit, scoreThreshold, temperature, repeatPenalty, topP, topK } = appSettings.load();
|
const { recentEpisodeLimit, semanticLimit, scoreThreshold, temperature, repeatPenalty, topP, topK, systemPrompt } = appSettings.load();
|
||||||
let session = await memory.getSessionByExternalId(externalId);
|
let session = await memory.getSessionByExternalId(externalId);
|
||||||
if (!session) session = await memory.createSession(externalId);
|
if (!session) session = await memory.createSession(externalId);
|
||||||
|
|
||||||
let projectSessionIds = null;
|
let projectSessionIds = null;
|
||||||
|
let activeSystemPrompt = systemPrompt ?? ORCHESTRATION.SYSTEM_PROMPT;
|
||||||
if (session.project_id) {
|
if (session.project_id) {
|
||||||
try {
|
try {
|
||||||
const project = await memory.getProject(session.project_id);
|
const project = await memory.getProject(session.project_id);
|
||||||
@@ -231,16 +223,9 @@ async function chatStream(externalId, userMessage, onChunk, options = {}) {
|
|||||||
session.project_id,
|
session.project_id,
|
||||||
);
|
);
|
||||||
projectSessionIds = projectSessions.map((s) => s.id);
|
projectSessionIds = projectSessions.map((s) => s.id);
|
||||||
if (project.isolated === 1) {
|
if (project?.system_prompt) activeSystemPrompt = project.system_prompt;
|
||||||
console.log(
|
|
||||||
`[orchestration] Isolated project — restricting to ${projectSessionIds.length} sessions`,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
console.log(
|
|
||||||
`[orchestration] Non-isolated project — expanding search to ${projectSessionIds.length} sessions`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.warn(
|
console.warn(
|
||||||
"[orchestration] Failed to resolve project context:",
|
"[orchestration] Failed to resolve project context:",
|
||||||
@@ -270,6 +255,7 @@ async function chatStream(externalId, userMessage, onChunk, options = {}) {
|
|||||||
semanticEpisodes,
|
semanticEpisodes,
|
||||||
entities,
|
entities,
|
||||||
userMessage,
|
userMessage,
|
||||||
|
activeSystemPrompt,
|
||||||
);
|
);
|
||||||
const res = await inference.completeStream(prompt, {...options, temperature, repeatPenalty, topP, topK});
|
const res = await inference.completeStream(prompt, {...options, temperature, repeatPenalty, topP, topK});
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,8 @@ const DEFAULTS = {
|
|||||||
temperature: INFERENCE_DEFAULTS.TEMPERATURE,
|
temperature: INFERENCE_DEFAULTS.TEMPERATURE,
|
||||||
repeatPenalty: INFERENCE_DEFAULTS.REPEAT_PENALTY,
|
repeatPenalty: INFERENCE_DEFAULTS.REPEAT_PENALTY,
|
||||||
topP: INFERENCE_DEFAULTS.TOP_P,
|
topP: INFERENCE_DEFAULTS.TOP_P,
|
||||||
topK: INFERENCE_DEFAULTS.TOP_K
|
topK: INFERENCE_DEFAULTS.TOP_K,
|
||||||
|
systemPrompt: ORCHESTRATION.SYSTEM_PROMPT,
|
||||||
};
|
};
|
||||||
|
|
||||||
function load() {
|
function load() {
|
||||||
|
|||||||
@@ -73,6 +73,13 @@ if (req.body.topK !== undefined) {
|
|||||||
updates.topK = val;
|
updates.topK = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (req.body.systemPrompt !== undefined) {
|
||||||
|
const val = req.body.systemPrompt;
|
||||||
|
if (typeof val !== 'string')
|
||||||
|
return res.status(400).json({ error: 'systemPrompt must be a string' });
|
||||||
|
updates.systemPrompt = val.trim() || null; // null reverts to default
|
||||||
|
}
|
||||||
|
|
||||||
res.json(settings.save(updates));
|
res.json(settings.save(updates));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user