mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-31 04:12:10 +03:00
Hide combo compression controls when disabled (#1840)
Integrated into release/v3.7.8
This commit is contained in:
@@ -136,6 +136,7 @@ import {
|
||||
isFallbackDecision,
|
||||
EMERGENCY_FALLBACK_CONFIG,
|
||||
} from "../services/emergencyFallback.ts";
|
||||
import type { CompressionConfig } from "../services/compression/types.ts";
|
||||
import { prepareWebSearchFallbackBody } from "../services/webSearchFallback.ts";
|
||||
import {
|
||||
resolveExplicitStreamAlias,
|
||||
@@ -1561,15 +1562,37 @@ export async function handleChatCore({
|
||||
body?.messages || body?.input || body?.contents || body?.request?.contents || [];
|
||||
if (body && Array.isArray(allMessages) && allMessages.length > 0) {
|
||||
let estimatedTokens = estimateTokens(JSON.stringify(allMessages));
|
||||
let promptCompressionEnabled = false;
|
||||
let compressionSettings: CompressionConfig | null = null;
|
||||
|
||||
try {
|
||||
const { getCompressionSettings } = await import("../../src/lib/db/compression.ts");
|
||||
compressionSettings = await getCompressionSettings();
|
||||
promptCompressionEnabled = compressionSettings.enabled;
|
||||
} catch (err) {
|
||||
log?.warn?.(
|
||||
"COMPRESSION",
|
||||
"Compression settings lookup skipped: " + (err instanceof Error ? err.message : String(err))
|
||||
);
|
||||
}
|
||||
|
||||
// --- Modular Compression Pipeline (Phase 1 Lite + Phase 2 Standard/Caveman + Phase 3 Aggressive) ---
|
||||
// Runs BEFORE the existing reactive compressContext() to proactively reduce tokens.
|
||||
try {
|
||||
const { getCompressionSettings } = await import("../../src/lib/db/compression.ts");
|
||||
const { selectCompressionStrategy, applyCompression } =
|
||||
await import("../services/compression/strategySelector.ts");
|
||||
const { trackCompressionStats } = await import("../services/compression/stats.ts");
|
||||
let config = await getCompressionSettings();
|
||||
let config: CompressionConfig = compressionSettings ?? {
|
||||
enabled: false,
|
||||
defaultMode: "off",
|
||||
autoTriggerTokens: 0,
|
||||
cacheMinutes: 5,
|
||||
preserveSystemPrompt: true,
|
||||
comboOverrides: {},
|
||||
};
|
||||
if (!promptCompressionEnabled || !compressionSettings) {
|
||||
log?.debug?.("COMPRESSION", "Prompt compression disabled or unavailable");
|
||||
}
|
||||
let compressionComboKey = comboName ?? null;
|
||||
if (isCombo && comboName) {
|
||||
try {
|
||||
@@ -1704,6 +1727,12 @@ export async function handleChatCore({
|
||||
}
|
||||
// --- End Modular Compression Pipeline ---
|
||||
|
||||
if (!promptCompressionEnabled) {
|
||||
log?.debug?.(
|
||||
"CONTEXT",
|
||||
"Skipping proactive context compression: Prompt Compression disabled"
|
||||
);
|
||||
}
|
||||
let contextLimit = getTokenLimit(provider, effectiveModel);
|
||||
|
||||
if (isCombo && comboName) {
|
||||
@@ -1748,7 +1777,7 @@ export async function handleChatCore({
|
||||
`Checking compression: ${estimatedTokens} tokens vs ${threshold} threshold (${contextLimit} limit, ${reservedTokens} reserved)`
|
||||
);
|
||||
|
||||
if (estimatedTokens > threshold) {
|
||||
if (promptCompressionEnabled && estimatedTokens > threshold) {
|
||||
log?.info?.(
|
||||
"CONTEXT",
|
||||
`Proactive compression triggered: ${estimatedTokens} tokens > ${threshold} threshold (${contextLimit} limit)`
|
||||
|
||||
@@ -606,6 +606,7 @@ export default function CombosPage() {
|
||||
const [comboDragOverIndex, setComboDragOverIndex] = useState(null);
|
||||
const [savingComboOrder, setSavingComboOrder] = useState(false);
|
||||
const [comboConfigMode, setComboConfigMode] = useState("guided");
|
||||
const [promptCompressionEnabled, setPromptCompressionEnabled] = useState(false);
|
||||
const [selectedIntelligentComboId, setSelectedIntelligentComboId] = useState<string | null>(null);
|
||||
const comboDragIndexRef = useRef<number | null>(null);
|
||||
const activeFilter = normalizeIntelligentRoutingFilter(searchParams.get("filter"));
|
||||
@@ -650,6 +651,10 @@ export default function CombosPage() {
|
||||
.then((r) => (r.ok ? r.json() : null))
|
||||
.then((settings) => setComboConfigMode(normalizeComboConfigMode(settings?.comboConfigMode)))
|
||||
.catch(() => setComboConfigMode("guided"));
|
||||
fetch("/api/settings/compression")
|
||||
.then((r) => (r.ok ? r.json() : null))
|
||||
.then((settings) => setPromptCompressionEnabled(settings?.enabled === true))
|
||||
.catch(() => setPromptCompressionEnabled(false));
|
||||
fetch("/api/settings/proxy")
|
||||
.then((r) => (r.ok ? r.json() : null))
|
||||
.then((c) => setProxyConfig(c))
|
||||
@@ -1128,6 +1133,7 @@ export default function CombosPage() {
|
||||
<ComboCard
|
||||
combo={combo}
|
||||
metrics={metrics[combo.name]}
|
||||
compressionEnabled={promptCompressionEnabled}
|
||||
providerNodes={providerNodes}
|
||||
copied={copied}
|
||||
onCopy={copy}
|
||||
@@ -1499,6 +1505,7 @@ function ComboReadinessPanel({ checks, blockers, showDescription = true }) {
|
||||
function ComboCard({
|
||||
combo,
|
||||
metrics,
|
||||
compressionEnabled,
|
||||
copied,
|
||||
onCopy,
|
||||
onEdit,
|
||||
@@ -1524,10 +1531,20 @@ function ComboCard({
|
||||
const tc = useTranslations("common");
|
||||
const emailsVisible = useEmailPrivacyStore((s) => s.emailsVisible);
|
||||
const strategyDescription = getStrategyDescription(t, strategy);
|
||||
const initialCompressionMode = combo?.config?.compressionMode || combo.compressionOverride || "";
|
||||
const hasRuntimeConfig = combo?.config && typeof combo.config === "object";
|
||||
const initialCompressionMode =
|
||||
typeof combo?.config?.compressionMode === "string"
|
||||
? combo.config.compressionMode
|
||||
: hasRuntimeConfig
|
||||
? ""
|
||||
: combo.compressionOverride || "";
|
||||
const [compressionOverride, setCompressionOverride] = useState(initialCompressionMode);
|
||||
const [isSavingCompression, setIsSavingCompression] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setCompressionOverride(initialCompressionMode);
|
||||
}, [initialCompressionMode]);
|
||||
|
||||
const handleCompressionOverrideChange = async (value) => {
|
||||
setCompressionOverride(value);
|
||||
setIsSavingCompression(true);
|
||||
@@ -1687,20 +1704,22 @@ function ComboCard({
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-1.5 transition-opacity">
|
||||
<select
|
||||
value={compressionOverride}
|
||||
onChange={(e) => handleCompressionOverrideChange(e.target.value)}
|
||||
disabled={isSavingCompression}
|
||||
className="text-xs py-1 px-2 rounded border border-black/10 dark:border-white/10 bg-white dark:bg-bg-main text-text-main focus:border-primary focus:outline-none transition-colors disabled:opacity-50 max-w-[130px] md:max-w-none"
|
||||
title="Compression Override"
|
||||
>
|
||||
<option value="">Default</option>
|
||||
<option value="off">Off</option>
|
||||
<option value="lite">Lite</option>
|
||||
<option value="standard">Standard</option>
|
||||
<option value="aggressive">Aggressive</option>
|
||||
<option value="ultra">Ultra</option>
|
||||
</select>
|
||||
{compressionEnabled && (
|
||||
<select
|
||||
value={compressionOverride}
|
||||
onChange={(e) => handleCompressionOverrideChange(e.target.value)}
|
||||
disabled={isSavingCompression}
|
||||
className="text-xs py-1 px-2 rounded border border-black/10 dark:border-white/10 bg-white dark:bg-bg-main text-text-main focus:border-primary focus:outline-none transition-colors disabled:opacity-50 max-w-[130px] md:max-w-none"
|
||||
title="Compression Override"
|
||||
>
|
||||
<option value="">Default</option>
|
||||
<option value="off">Off</option>
|
||||
<option value="lite">Lite</option>
|
||||
<option value="standard">Standard</option>
|
||||
<option value="aggressive">Aggressive</option>
|
||||
<option value="ultra">Ultra</option>
|
||||
</select>
|
||||
)}
|
||||
<button
|
||||
onClick={onTest}
|
||||
disabled={testing}
|
||||
|
||||
@@ -47,6 +47,12 @@ test("chatCore integration: compressContext called proactively when context exce
|
||||
const provider = "openai";
|
||||
const model = "gpt-4";
|
||||
|
||||
await compressionDb.updateCompressionSettings({
|
||||
enabled: true,
|
||||
defaultMode: "off",
|
||||
autoTriggerTokens: 0,
|
||||
});
|
||||
|
||||
// Create multiple messages with history that can be compressed
|
||||
// Use the same pattern as test 3 which successfully tests compression
|
||||
const body = {
|
||||
@@ -120,9 +126,113 @@ test("chatCore integration: compressContext called proactively when context exce
|
||||
}
|
||||
});
|
||||
|
||||
test("chatCore integration: disabled prompt compression leaves combo override requests unchanged", async () => {
|
||||
const provider = "openai";
|
||||
const model = "gpt-4";
|
||||
const originalContextLength = process.env.CONTEXT_LENGTH_OPENAI;
|
||||
process.env.CONTEXT_LENGTH_OPENAI = "8192";
|
||||
|
||||
await compressionDb.updateCompressionSettings({
|
||||
enabled: false,
|
||||
defaultMode: "off",
|
||||
autoTriggerTokens: 1,
|
||||
comboOverrides: { "disabled-compression-combo": "lite" },
|
||||
});
|
||||
|
||||
const connection = await providersDb.createProviderConnection({
|
||||
provider,
|
||||
apiKey: "test-key",
|
||||
isActive: true,
|
||||
});
|
||||
|
||||
await combosDb.createCombo({
|
||||
name: "disabled-compression-combo",
|
||||
strategy: "priority",
|
||||
models: [
|
||||
{
|
||||
kind: "model",
|
||||
model: `${provider}/${model}`,
|
||||
connectionId: connection.id,
|
||||
},
|
||||
],
|
||||
config: {
|
||||
compressionMode: "lite",
|
||||
},
|
||||
});
|
||||
|
||||
const body = {
|
||||
model: "combo/disabled-compression-combo",
|
||||
stream: false,
|
||||
messages: [
|
||||
{ role: "system", content: "You are helpful." },
|
||||
{ role: "user", content: `${"Keep spacing.\n\n\n".repeat(2000)}First long turn.` },
|
||||
{ role: "assistant", content: "Response 1" },
|
||||
{ role: "user", content: `${"Keep spacing.\n\n\n".repeat(2000)}Second long turn.` },
|
||||
{ role: "assistant", content: "Response 2" },
|
||||
{ role: "user", content: `${"Keep spacing.\n\n\n".repeat(2000)}Final question.` },
|
||||
],
|
||||
};
|
||||
const contextLimit = getTokenLimit(provider, model);
|
||||
const proactiveThreshold = Math.floor(contextLimit * 0.7);
|
||||
assert.ok(
|
||||
estimateTokens(JSON.stringify(body.messages)) > proactiveThreshold,
|
||||
"Test body should exceed proactive compression threshold"
|
||||
);
|
||||
|
||||
let capturedBody: any = null;
|
||||
globalThis.fetch = async (_url: string | URL | Request, init?: RequestInit) => {
|
||||
if (init?.body) {
|
||||
capturedBody = JSON.parse(init.body as string);
|
||||
}
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
choices: [{ message: { role: "assistant", content: "test" } }],
|
||||
usage: { prompt_tokens: 10, completion_tokens: 5, total_tokens: 15 },
|
||||
}),
|
||||
{
|
||||
status: 200,
|
||||
headers: { "content-type": "application/json" },
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
try {
|
||||
const result = await handleChatCore({
|
||||
body,
|
||||
modelInfo: { provider, model },
|
||||
credentials: { apiKey: "test-key" },
|
||||
log: { debug: () => {}, info: () => {}, warn: () => {}, error: () => {} },
|
||||
clientRawRequest: { endpoint: "/v1/chat/completions", headers: new Map() },
|
||||
connectionId: connection.id,
|
||||
isCombo: true,
|
||||
comboName: "disabled-compression-combo",
|
||||
});
|
||||
|
||||
assert.ok(result.success, "Request should succeed");
|
||||
assert.ok(capturedBody, "Fetch should have been called");
|
||||
assert.deepEqual(capturedBody.messages, body.messages);
|
||||
|
||||
const summary = compressionAnalyticsDb.getCompressionAnalyticsSummary();
|
||||
assert.equal(summary.totalRequests, 0, "Disabled compression should not record analytics");
|
||||
} finally {
|
||||
globalThis.fetch = originalFetch;
|
||||
if (originalContextLength === undefined) {
|
||||
delete process.env.CONTEXT_LENGTH_OPENAI;
|
||||
} else {
|
||||
process.env.CONTEXT_LENGTH_OPENAI = originalContextLength;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test("chatCore integration: compressContext NOT called when context is below 85% threshold", async () => {
|
||||
const provider = "openai";
|
||||
const model = "gpt-4";
|
||||
|
||||
await compressionDb.updateCompressionSettings({
|
||||
enabled: true,
|
||||
defaultMode: "off",
|
||||
autoTriggerTokens: 0,
|
||||
});
|
||||
const contextLimit = getTokenLimit(provider, model);
|
||||
const threshold = Math.floor(contextLimit * 0.85);
|
||||
|
||||
@@ -199,6 +309,12 @@ test("chatCore integration: compression preserves message structure", async () =
|
||||
const provider = "openai";
|
||||
const model = "gpt-4";
|
||||
|
||||
await compressionDb.updateCompressionSettings({
|
||||
enabled: true,
|
||||
defaultMode: "off",
|
||||
autoTriggerTokens: 0,
|
||||
});
|
||||
|
||||
const body = {
|
||||
model,
|
||||
stream: false,
|
||||
@@ -343,6 +459,12 @@ test("chatCore integration: combo requests run proactive compression before Kiro
|
||||
const provider = "kiro";
|
||||
const model = "claude-sonnet-4.5";
|
||||
|
||||
await compressionDb.updateCompressionSettings({
|
||||
enabled: true,
|
||||
defaultMode: "off",
|
||||
autoTriggerTokens: 0,
|
||||
});
|
||||
|
||||
const connection = await providersDb.createProviderConnection({
|
||||
provider,
|
||||
apiKey: "test-key",
|
||||
|
||||
@@ -65,6 +65,17 @@ describe("getEffectiveMode", () => {
|
||||
assert.equal(getEffectiveMode(config, null, 100), "off");
|
||||
});
|
||||
|
||||
it("keeps disabled config off despite combo override and auto-trigger", () => {
|
||||
const config = {
|
||||
...baseConfig,
|
||||
enabled: false,
|
||||
autoTriggerTokens: 100,
|
||||
comboOverrides: { "my-combo": "lite" as const },
|
||||
};
|
||||
|
||||
assert.equal(getEffectiveMode(config, "my-combo", 500), "off");
|
||||
});
|
||||
|
||||
it("returns default mode when no overrides", () => {
|
||||
assert.equal(getEffectiveMode(baseConfig, null, 100), "lite");
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user