mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-14 02:42:24 +03:00
feat(config): add support for runtime system prompt configuration and hot-reloading (#11841)
Boarded with #12003/#11840/#11839 in one combined worktree: typecheck:core, check:file-size, check:changelog-integrity, check:complexity, check:cognitive-complexity, check:cycles all green; 24/24 focused tests pass. Clean, well-contained addition mirroring the existing systemTransforms hot-reload pattern, tested for both set and cleared states. Thanks for the tidy runtime-config feature.
This commit is contained in:
@@ -21,6 +21,7 @@ export type RuntimeReloadSection =
|
||||
| "corsOrigins"
|
||||
| "ccBridgeTransforms"
|
||||
| "systemTransforms"
|
||||
| "systemPrompt"
|
||||
| "authzBypass"
|
||||
| "bannedSignals";
|
||||
|
||||
@@ -48,6 +49,7 @@ interface RuntimeSettingsSnapshot {
|
||||
corsOrigins: string;
|
||||
ccBridgeTransforms: unknown;
|
||||
systemTransforms: unknown;
|
||||
systemPrompt: unknown;
|
||||
authzBypass: AuthzBypassSnapshot;
|
||||
customBannedSignals: string[];
|
||||
providerErrorRules: Record<string, OperatorProviderErrorRule[]> | null;
|
||||
@@ -75,6 +77,7 @@ const DEFAULT_RUNTIME_SETTINGS_SNAPSHOT: RuntimeSettingsSnapshot = {
|
||||
corsOrigins: "",
|
||||
ccBridgeTransforms: null,
|
||||
systemTransforms: null,
|
||||
systemPrompt: null,
|
||||
authzBypass: DEFAULT_AUTHZ_BYPASS_SNAPSHOT,
|
||||
customBannedSignals: [],
|
||||
providerErrorRules: null,
|
||||
@@ -93,7 +96,6 @@ function isTruthyEnvFlag(value: string | undefined): boolean {
|
||||
return new Set(["1", "true", "yes", "on"]).has(value.trim().toLowerCase());
|
||||
}
|
||||
|
||||
|
||||
function toRecord(value: unknown): JsonRecord {
|
||||
return value && typeof value === "object" && !Array.isArray(value) ? (value as JsonRecord) : {};
|
||||
}
|
||||
@@ -276,6 +278,9 @@ export function buildRuntimeSettingsSnapshot(
|
||||
corsOrigins: typeof settings.corsOrigins === "string" ? settings.corsOrigins : "",
|
||||
ccBridgeTransforms: parseStoredJson(settings.ccBridgeTransforms, "ccBridgeTransforms"),
|
||||
systemTransforms: parseStoredJson(settings.systemTransforms, "systemTransforms"),
|
||||
systemPrompt: settings.systemPrompt
|
||||
? parseStoredJson(settings.systemPrompt, "systemPrompt")
|
||||
: null,
|
||||
authzBypass: normalizeAuthzBypass(settings),
|
||||
customBannedSignals: normalizeStringArray(settings.customBannedSignals),
|
||||
providerErrorRules: normalizeOperatorProviderErrorRules(settings.providerErrorRules),
|
||||
@@ -404,6 +409,21 @@ async function applySystemTransformsSection(systemTransforms: unknown) {
|
||||
setSystemTransformsConfig(systemTransforms);
|
||||
}
|
||||
|
||||
async function applySystemPromptSection(systemPrompt: unknown) {
|
||||
const { setSystemPromptConfig } = await import("@omniroute/open-sse/services/systemPrompt.ts");
|
||||
|
||||
if (systemPrompt && typeof systemPrompt === "object") {
|
||||
setSystemPromptConfig(systemPrompt as Record<string, unknown>);
|
||||
} else {
|
||||
setSystemPromptConfig({
|
||||
enabled: false,
|
||||
prefixPrompt: "",
|
||||
suffixPrompt: "",
|
||||
prompt: "",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function applyModelsDevSyncSection(
|
||||
previousSnapshot: RuntimeSettingsSnapshot,
|
||||
currentSnapshot: RuntimeSettingsSnapshot,
|
||||
@@ -562,6 +582,11 @@ export async function applyRuntimeSettings(
|
||||
markChanged("systemTransforms");
|
||||
}
|
||||
|
||||
if (force || hasChanged(currentSnapshot.systemPrompt, previousSnapshot.systemPrompt)) {
|
||||
await applySystemPromptSection(currentSnapshot.systemPrompt);
|
||||
markChanged("systemPrompt");
|
||||
}
|
||||
|
||||
if (force || hasChanged(currentSnapshot.authzBypass, previousSnapshot.authzBypass)) {
|
||||
applyAuthzBypassSection(currentSnapshot.authzBypass);
|
||||
markChanged("authzBypass");
|
||||
|
||||
46
tests/unit/system-prompt-runtime-hotreload.test.ts
Normal file
46
tests/unit/system-prompt-runtime-hotreload.test.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { test } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import {
|
||||
applyRuntimeSettings,
|
||||
resetRuntimeSettingsStateForTests,
|
||||
} from "../../src/lib/config/runtimeSettings";
|
||||
import { getSystemPromptConfig } from "../../open-sse/services/systemPrompt.ts";
|
||||
|
||||
test.afterEach(() => {
|
||||
resetRuntimeSettingsStateForTests();
|
||||
});
|
||||
|
||||
test("systemPrompt settings hot-reload updates globalThis in-memory config", async () => {
|
||||
const newSettings = {
|
||||
systemPrompt: {
|
||||
enabled: true,
|
||||
prefixPrompt: "Prefix rules for agent",
|
||||
suffixPrompt: "Suffix rules for agent",
|
||||
},
|
||||
};
|
||||
|
||||
const changes = await applyRuntimeSettings(newSettings, { force: true, source: "test" });
|
||||
assert.ok(
|
||||
changes.some((c) => c.section === "systemPrompt"),
|
||||
"systemPrompt section must be reported as reloaded"
|
||||
);
|
||||
|
||||
const cfg = getSystemPromptConfig();
|
||||
assert.equal(cfg.enabled, true, "systemPrompt enabled flag must be updated");
|
||||
assert.equal(
|
||||
cfg.prefixPrompt,
|
||||
"Prefix rules for agent",
|
||||
"prefixPrompt must match updated settings"
|
||||
);
|
||||
assert.equal(
|
||||
cfg.suffixPrompt,
|
||||
"Suffix rules for agent",
|
||||
"suffixPrompt must match updated settings"
|
||||
);
|
||||
|
||||
// Hot-reload clearing systemPrompt
|
||||
await applyRuntimeSettings({ systemPrompt: null }, { force: true, source: "test" });
|
||||
const clearedCfg = getSystemPromptConfig();
|
||||
assert.equal(clearedCfg.enabled, false, "systemPrompt must be disabled when set to null");
|
||||
assert.equal(clearedCfg.prefixPrompt, "", "prefixPrompt must be cleared when set to null");
|
||||
});
|
||||
Reference in New Issue
Block a user