u
This commit is contained in:
@@ -6,7 +6,8 @@ Upsert company setting
|
||||
|
||||
Sets (upserts) a company setting for the selected company.
|
||||
Only a fixed allow-list of keys can be set: `ui.theme`, `keys.tavily`,
|
||||
`keys.openrouter`, `keys.serper`, `labelprinter.addr`, `labelprinter.type`.
|
||||
`keys.openrouter`, `keys.serper`, `systemprompt-prefix`,
|
||||
`systemprompt-suffix`, `default-model`.
|
||||
|
||||
|
||||
## Path parameters
|
||||
|
||||
@@ -5,8 +5,9 @@ const ALLOWED_KEYS = [
|
||||
'keys.tavily',
|
||||
'keys.openrouter',
|
||||
'keys.serper',
|
||||
'labelprinter.addr',
|
||||
'labelprinter.type',
|
||||
'systemprompt-prefix',
|
||||
'systemprompt-suffix',
|
||||
'default-model',
|
||||
];
|
||||
|
||||
function requireSelectedCompany(req) {
|
||||
@@ -206,7 +207,8 @@ export function register(app, basePath = '') {
|
||||
* description: |
|
||||
* Sets (upserts) a company setting for the selected company.
|
||||
* Only a fixed allow-list of keys can be set: `ui.theme`, `keys.tavily`,
|
||||
* `keys.openrouter`, `keys.serper`, `labelprinter.addr`, `labelprinter.type`.
|
||||
* `keys.openrouter`, `keys.serper`, `systemprompt-prefix`,
|
||||
* `systemprompt-suffix`, `default-model`.
|
||||
* security:
|
||||
* - cookieAuth: []
|
||||
* x-markdown: companysetting/set.md
|
||||
|
||||
@@ -73,9 +73,27 @@ function buildSkillIndex(vfsRoot) {
|
||||
* (docs/api/routes.md), read on each run so it stays current.
|
||||
*
|
||||
* @param {string} vfsRoot Resolved VFS root for this user's company, used to list SKILL files.
|
||||
* @returns {string}
|
||||
* @param {number} [googleAuthId]
|
||||
* @returns {Promise<string>}
|
||||
*/
|
||||
async function buildSystemPrompt(vfsRoot) {
|
||||
async function buildSystemPrompt(vfsRoot, googleAuthId) {
|
||||
let prefix = '';
|
||||
let suffix = '';
|
||||
if (googleAuthId) {
|
||||
try {
|
||||
const prefixSetting = await dbCompanySetting.getByKey(googleAuthId, 'systemprompt-prefix', { maskWriteonly: false });
|
||||
prefix = prefixSetting?.value?.trim() || '';
|
||||
} catch (err) {
|
||||
console.error('conversation: failed to read systemprompt-prefix:', err.message);
|
||||
}
|
||||
try {
|
||||
const suffixSetting = await dbCompanySetting.getByKey(googleAuthId, 'systemprompt-suffix', { maskWriteonly: false });
|
||||
suffix = suffixSetting?.value?.trim() || '';
|
||||
} catch (err) {
|
||||
console.error('conversation: failed to read systemprompt-suffix:', err.message);
|
||||
}
|
||||
}
|
||||
|
||||
let routesDoc = '';
|
||||
try {
|
||||
routesDoc = readFileSync(ROUTES_DOC_PATH, 'utf8').trim();
|
||||
@@ -83,7 +101,7 @@ async function buildSystemPrompt(vfsRoot) {
|
||||
console.error('conversation: failed to read routes doc:', err);
|
||||
}
|
||||
const today = new Date().toISOString().split('T')[0];
|
||||
return [
|
||||
const basePrompt = [
|
||||
'You are an intelligent assistant specialized in exploring, querying, and managing data from the Dashback REST API.',
|
||||
`Today's date: ${today}`,
|
||||
'',
|
||||
@@ -129,6 +147,12 @@ async function buildSystemPrompt(vfsRoot) {
|
||||
'- Format responses clearly using markdown tables, bullet lists, or bold key-value pairs where appropriate.',
|
||||
...(routesDoc ? ['', 'DASHBACK API ROUTES:', routesDoc] : []),
|
||||
].join('\n');
|
||||
|
||||
const sections = [];
|
||||
if (prefix) sections.push(prefix);
|
||||
sections.push(basePrompt);
|
||||
if (suffix) sections.push(suffix);
|
||||
return sections.join('\n\n');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -351,7 +375,7 @@ export class ConversationManager {
|
||||
const defaultModel = await resolveDefaultModel(googleAuthId);
|
||||
const hasCustomKey = await hasConfiguredOpenRouterKey(googleAuthId);
|
||||
const storedModel = typeof conversation.model === 'string' ? conversation.model.trim() : '';
|
||||
const model = (!storedModel || RETIRED_MODELS.has(storedModel) || (storedModel === env.openrouterFreeModel && hasCustomKey))
|
||||
const model = (!storedModel || RETIRED_MODELS.has(storedModel) || (storedModel === env.openrouterFreeModel && (hasCustomKey || defaultModel !== env.openrouterFreeModel)))
|
||||
? defaultModel
|
||||
: storedModel;
|
||||
const apiKey = await resolveOpenRouterKey(googleAuthId);
|
||||
@@ -369,7 +393,7 @@ export class ConversationManager {
|
||||
}
|
||||
|
||||
const messages = [
|
||||
{ role: 'system', content: await buildSystemPrompt(vfsRoot) },
|
||||
{ role: 'system', content: await buildSystemPrompt(vfsRoot, googleAuthId) },
|
||||
...history.map(toLlmMessage),
|
||||
];
|
||||
|
||||
|
||||
@@ -47,13 +47,27 @@ export async function hasConfiguredOpenRouterKey(googleAuthId) {
|
||||
|
||||
/**
|
||||
* Resolve the default model for a user/company:
|
||||
* - As soon as the user/company has configured `keys.openrouter`, use `env.openrouterPaidModel`.
|
||||
* - Otherwise (using the server's free key), use `env.openrouterFreeModel`.
|
||||
* - If companysetting `default-model` is set, return it (works in both paid and no-key modes).
|
||||
* - Otherwise, if the user/company has configured `keys.openrouter`, use `env.openrouterPaidModel`
|
||||
* (which defaults to 'openai/gpt-6-luna:floor').
|
||||
* - Otherwise (no key set / free mode), use `env.openrouterFreeModel`
|
||||
* (which defaults to 'openrouter/free').
|
||||
*
|
||||
* @param {number} [googleAuthId]
|
||||
* @returns {Promise<string>}
|
||||
*/
|
||||
export async function resolveDefaultModel(googleAuthId) {
|
||||
if (googleAuthId) {
|
||||
try {
|
||||
const setting = await dbCompanySetting.getByKey(googleAuthId, 'default-model', { maskWriteonly: false });
|
||||
const customModel = setting?.value?.trim();
|
||||
if (customModel) return customModel;
|
||||
} catch (err) {
|
||||
console.error('default-model: failed to read company setting:', err.message);
|
||||
}
|
||||
}
|
||||
const hasKey = await hasConfiguredOpenRouterKey(googleAuthId);
|
||||
return hasKey ? env.openrouterPaidModel : env.openrouterFreeModel;
|
||||
return hasKey
|
||||
? (env.openrouterPaidModel || 'openai/gpt-6-luna:floor')
|
||||
: (env.openrouterFreeModel || 'openrouter/free');
|
||||
}
|
||||
Reference in New Issue
Block a user