63 lines
2.9 KiB
JavaScript
63 lines
2.9 KiB
JavaScript
const HARD_RULES = Object.freeze([
|
|
"Do not perform destructive actions without a validated backend workflow and explicit confirmation.",
|
|
"Do not bypass permissions or impersonate users.",
|
|
"Do not directly edit source files, databases, configuration files, or system files.",
|
|
"Do not execute shell commands from model output.",
|
|
"Do not generate or execute raw SQL.",
|
|
"Do not forge transaction, moderation, or configuration history.",
|
|
"Do not assist abuse, privilege escalation, data theft, or permission bypass.",
|
|
"Do not claim an action was performed unless the backend workflow confirms it."
|
|
]);
|
|
|
|
const DEFAULT_SCOPE = Object.freeze({
|
|
allowed_topics: "Lumi Bot, its WebUI, installed plugins, community features, stream tools, moderation tools, and bot configuration.",
|
|
allowed_support_domains: "Lumi operation, configuration, troubleshooting, navigation, and installed plugin support.",
|
|
answer_style: "Helpful, concise, factual, and purpose-built for Lumi support.",
|
|
linking_behavior: "Use verified internal WebUI links when available.",
|
|
repo_lookup_enabled: true,
|
|
allow_deterministic_help_shortcuts: false,
|
|
allow_moderator_code_help: false,
|
|
clarification_behavior: "Ask a concise clarification question when the user's intended product, page, or setting is ambiguous.",
|
|
max_answer_length: 4000,
|
|
role_overrides: { admin: "", mod: "", user: "" }
|
|
});
|
|
|
|
function normalizeScope(value = {}) {
|
|
const defined = Object.fromEntries(
|
|
Object.entries(value || {}).filter(([, entry]) => entry !== undefined && entry !== null)
|
|
);
|
|
return {
|
|
...DEFAULT_SCOPE,
|
|
...defined,
|
|
repo_lookup_enabled: defined.repo_lookup_enabled !== false,
|
|
allow_deterministic_help_shortcuts: defined.allow_deterministic_help_shortcuts === true,
|
|
allow_moderator_code_help: defined.allow_moderator_code_help === true,
|
|
max_answer_length: bounded(defined.max_answer_length, 100, 4000, DEFAULT_SCOPE.max_answer_length),
|
|
role_overrides: { ...DEFAULT_SCOPE.role_overrides, ...(defined.role_overrides || {}) }
|
|
};
|
|
}
|
|
|
|
function buildPolicy({ scope, role }) {
|
|
const normalized = normalizeScope(scope);
|
|
return {
|
|
hard_rules: [...HARD_RULES],
|
|
normal_scope: [
|
|
`Allowed topics: ${normalized.allowed_topics}`,
|
|
`Allowed support domains: ${normalized.allowed_support_domains}`,
|
|
`Linking behavior: ${normalized.linking_behavior}`,
|
|
`Clarification behavior: ${normalized.clarification_behavior}`,
|
|
normalized.role_overrides[role] ? `Role-specific scope: ${normalized.role_overrides[role]}` : ""
|
|
].filter(Boolean),
|
|
style: normalized.answer_style,
|
|
max_answer_length: normalized.max_answer_length,
|
|
repo_lookup_enabled: normalized.repo_lookup_enabled
|
|
};
|
|
}
|
|
|
|
function bounded(value, min, max, fallback) {
|
|
const number = Number.parseInt(value, 10);
|
|
return Number.isFinite(number) ? Math.min(max, Math.max(min, number)) : fallback;
|
|
}
|
|
|
|
module.exports = { HARD_RULES, DEFAULT_SCOPE, normalizeScope, buildPolicy };
|