chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import {
|
||||
selectCompressionStrategy,
|
||||
selectCompressionPlan,
|
||||
activeComboResolves,
|
||||
} from "../../../open-sse/services/compression/strategySelector.ts";
|
||||
import {
|
||||
DEFAULT_COMPRESSION_CONFIG,
|
||||
type CompressionConfig,
|
||||
} from "../../../open-sse/services/compression/types.ts";
|
||||
|
||||
const combos = { c1: [{ engine: "rtk", intensity: "standard" }, { engine: "caveman", intensity: "full" }] };
|
||||
|
||||
function cfg(overrides: Partial<CompressionConfig> = {}): CompressionConfig {
|
||||
return { ...DEFAULT_COMPRESSION_CONFIG, enabled: true, ...overrides };
|
||||
}
|
||||
|
||||
describe("active named combo resolution (Phase 2)", () => {
|
||||
it("activeComboId + combo present => that combo's stacked pipeline (regardless of enginesExplicit)", () => {
|
||||
const config = cfg({ activeComboId: "c1", enginesExplicit: false });
|
||||
const plan = selectCompressionPlan(config, null, 0, undefined, undefined, combos);
|
||||
assert.equal(plan.mode, "stacked");
|
||||
assert.deepEqual(plan.stackedPipeline, combos.c1);
|
||||
});
|
||||
it("activeComboId null => falls through to derived default (not the combo)", () => {
|
||||
const config = cfg({ activeComboId: null, enginesExplicit: true, engines: { rtk: { enabled: true } } });
|
||||
assert.equal(selectCompressionStrategy(config, null, 0, undefined, undefined, combos), "rtk");
|
||||
});
|
||||
it("activeComboId set but combo missing => graceful fall-through to default", () => {
|
||||
const config = cfg({ activeComboId: "ghost", defaultMode: "lite", enginesExplicit: false });
|
||||
assert.equal(selectCompressionStrategy(config, null, 0, undefined, undefined, combos), "lite");
|
||||
});
|
||||
it("routing-combo override wins over the active profile", () => {
|
||||
const config = cfg({ activeComboId: "c1", comboOverrides: { "my-combo": "off" } });
|
||||
assert.equal(selectCompressionStrategy(config, "my-combo", 0, undefined, undefined, combos), "off");
|
||||
});
|
||||
it("active profile wins over auto-trigger", () => {
|
||||
const config = cfg({ activeComboId: "c1", autoTriggerTokens: 1000, autoTriggerMode: "aggressive" });
|
||||
assert.equal(selectCompressionStrategy(config, null, 5000, undefined, undefined, combos), "stacked");
|
||||
});
|
||||
});
|
||||
|
||||
describe("activeComboResolves", () => {
|
||||
it("true only when activeComboId is set AND present in combos", () => {
|
||||
assert.equal(activeComboResolves(cfg({ activeComboId: "c1" }), combos), true);
|
||||
assert.equal(activeComboResolves(cfg({ activeComboId: "ghost" }), combos), false);
|
||||
assert.equal(activeComboResolves(cfg({ activeComboId: null }), combos), false);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,43 @@
|
||||
import { test, after } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import fs from "node:fs";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
|
||||
const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-active-combo-"));
|
||||
const ORIGINAL = process.env.DATA_DIR;
|
||||
process.env.DATA_DIR = TEST_DATA_DIR;
|
||||
|
||||
const { getDbInstance, resetDbInstance } = await import("../../../src/lib/db/core.ts");
|
||||
const combosDb = await import("../../../src/lib/db/compressionCombos.ts");
|
||||
const { updateCompressionSettings } = await import("../../../src/lib/db/compression.ts");
|
||||
const { selectCompressionPlan } = await import("../../../open-sse/services/compression/strategySelector.ts");
|
||||
const { DEFAULT_COMPRESSION_CONFIG } = await import("../../../open-sse/services/compression/types.ts");
|
||||
|
||||
after(() => {
|
||||
resetDbInstance();
|
||||
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
|
||||
if (ORIGINAL === undefined) delete process.env.DATA_DIR;
|
||||
else process.env.DATA_DIR = ORIGINAL;
|
||||
});
|
||||
|
||||
test("an active named combo's pipeline is what selectCompressionPlan resolves, fed from the DB combos map", async () => {
|
||||
resetDbInstance();
|
||||
getDbInstance();
|
||||
const created = combosDb.createCompressionCombo({
|
||||
name: "RTK only",
|
||||
pipeline: [{ engine: "rtk", intensity: "standard" }],
|
||||
});
|
||||
await updateCompressionSettings({ enabled: true, activeComboId: created.id });
|
||||
|
||||
// Mirror chatCore's load: build the combos map from the DB.
|
||||
const combos = Object.fromEntries(combosDb.listCompressionCombos().map((c) => [c.id, c.pipeline]));
|
||||
const config = { ...DEFAULT_COMPRESSION_CONFIG, enabled: true, activeComboId: created.id };
|
||||
const plan = selectCompressionPlan(config, null, 5000, undefined, undefined, combos);
|
||||
assert.equal(plan.mode, "stacked");
|
||||
assert.deepEqual(plan.stackedPipeline, [{ engine: "rtk", intensity: "standard" }]);
|
||||
|
||||
// Setting activeComboId did NOT change which combo is is_default (legacy untouched).
|
||||
const def = combosDb.getDefaultCompressionCombo();
|
||||
assert.notEqual(def?.id, created.id);
|
||||
});
|
||||
@@ -0,0 +1,20 @@
|
||||
import { test } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { readFileSync } from "node:fs";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const chatCore = readFileSync(
|
||||
fileURLToPath(new URL("../../../open-sse/handlers/chatCore.ts", import.meta.url)),
|
||||
"utf8"
|
||||
);
|
||||
|
||||
test("chatCore threads modelContextLimit + requestMaxTokens into selectCompressionPlan", () => {
|
||||
// the adaptive options object literal must reference both inputs
|
||||
assert.match(chatCore, /modelContextLimit:/);
|
||||
assert.match(chatCore, /requestMaxTokens:/);
|
||||
});
|
||||
|
||||
test("chatCore emits the adaptive telemetry block via onAdaptive", () => {
|
||||
assert.match(chatCore, /onAdaptive/);
|
||||
assert.match(chatCore, /adaptiveTelemetry/);
|
||||
});
|
||||
@@ -0,0 +1,30 @@
|
||||
import { test } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { computeTarget } from "@omniroute/open-sse/services/compression/adaptiveCompression/computeTarget.ts";
|
||||
import { DEFAULT_CONTEXT_BUDGET } from "@omniroute/open-sse/services/compression/adaptiveCompression/types.ts";
|
||||
|
||||
const base = { ...DEFAULT_CONTEXT_BUDGET, outputReserve: 4096, safetyMargin: 1024 };
|
||||
|
||||
test("reserve-output: request.max_tokens wins over outputReserve default", () => {
|
||||
// 200000 − 8000 (request max_tokens) − 1024 (safetyMargin) = 190976
|
||||
const t = computeTarget("reserve-output", 200000, 8000, base);
|
||||
assert.equal(t, 190976);
|
||||
});
|
||||
|
||||
test("reserve-output: falls back to outputReserve when no max_tokens", () => {
|
||||
// 200000 − 4096 (outputReserve) − 1024 (safetyMargin) = 194880
|
||||
assert.equal(computeTarget("reserve-output", 200000, null, base), 194880);
|
||||
assert.equal(computeTarget("reserve-output", 200000, 0, base), 194880); // 0 is not a positive reserve
|
||||
});
|
||||
|
||||
test("percentage policy: limit × pct, floored", () => {
|
||||
assert.equal(computeTarget("percentage", 200000, null, { ...base, pct: 0.7 }), 140000);
|
||||
// invalid pct (out of (0,1]) → treated as 1.0 (no shrink)
|
||||
assert.equal(computeTarget("percentage", 200000, null, { ...base, pct: 0 }), 200000);
|
||||
assert.equal(computeTarget("percentage", 200000, null, { ...base, pct: 1.5 }), 200000);
|
||||
});
|
||||
|
||||
test("absolute policy: model-independent budget", () => {
|
||||
assert.equal(computeTarget("absolute", 200000, 8000, { ...base, absoluteBudget: 50000 }), 50000);
|
||||
assert.equal(computeTarget("absolute", 8000, null, { ...base, absoluteBudget: 50000 }), 50000);
|
||||
});
|
||||
@@ -0,0 +1,31 @@
|
||||
import { test } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { formatAdaptiveTarget } from "../../../src/app/(dashboard)/dashboard/context/settings/adaptiveTargetLabel.ts";
|
||||
|
||||
test("formatAdaptiveTarget shows policy + computed target for reserve-output", () => {
|
||||
const label = formatAdaptiveTarget(
|
||||
{ mode: "floor", policy: "reserve-output", outputReserve: 4096, safetyMargin: 1024, pct: 0.85, absoluteBudget: 0 },
|
||||
200000
|
||||
);
|
||||
assert.match(label, /reserve-output/);
|
||||
// 200000 − 4096 − 1024 = 194880; tolerate any digit-group separator (locale-dependent toLocaleString).
|
||||
assert.match(label, /194[.,\s ]?880|194880/);
|
||||
});
|
||||
|
||||
test("formatAdaptiveTarget shows off when disabled", () => {
|
||||
const label = formatAdaptiveTarget(
|
||||
{ mode: "off", policy: "reserve-output", outputReserve: 4096, safetyMargin: 1024, pct: 0.85, absoluteBudget: 0 },
|
||||
200000
|
||||
);
|
||||
assert.match(label, /off|disabled/i);
|
||||
});
|
||||
|
||||
test("formatAdaptiveTarget reflects percentage policy target", () => {
|
||||
const label = formatAdaptiveTarget(
|
||||
{ mode: "floor", policy: "percentage", outputReserve: 4096, safetyMargin: 1024, pct: 0.7, absoluteBudget: 0 },
|
||||
200000
|
||||
);
|
||||
assert.match(label, /percentage/);
|
||||
// 200000 × 0.7 = 140000
|
||||
assert.match(label, /140[.,\s ]?000|140000/);
|
||||
});
|
||||
@@ -0,0 +1,150 @@
|
||||
import { test } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import {
|
||||
DEFAULT_LADDER,
|
||||
aggressivenessOf,
|
||||
expectedReductionFactor,
|
||||
} from "@omniroute/open-sse/services/compression/adaptiveCompression/ladder.ts";
|
||||
|
||||
test("default ladder is cheapest → most aggressive (stackPriority order)", () => {
|
||||
assert.deepEqual(
|
||||
DEFAULT_LADDER.map((s) => s.engine),
|
||||
["session-dedup", "rtk", "headroom", "lite", "caveman", "aggressive", "ultra"]
|
||||
);
|
||||
});
|
||||
|
||||
test("aggressivenessOf increases monotonically along the ladder", () => {
|
||||
const ranks = DEFAULT_LADDER.map((s) => aggressivenessOf(s.engine));
|
||||
for (let i = 1; i < ranks.length; i++) {
|
||||
assert.ok(ranks[i] > ranks[i - 1], `rank must increase at index ${i}`);
|
||||
}
|
||||
// a base "lite" plan ranks below caveman/aggressive/ultra (so floor escalates beyond it)
|
||||
assert.ok(aggressivenessOf("lite") < aggressivenessOf("caveman"));
|
||||
assert.ok(aggressivenessOf("standard") === aggressivenessOf("caveman")); // mode-name alias
|
||||
});
|
||||
|
||||
test("expectedReductionFactor is in (0,1) and heavier engines reduce more", () => {
|
||||
assert.ok(expectedReductionFactor("rtk") < 1 && expectedReductionFactor("rtk") > 0);
|
||||
assert.ok(expectedReductionFactor("ultra") < expectedReductionFactor("rtk"));
|
||||
});
|
||||
|
||||
import { resolveAdaptivePlan } from "@omniroute/open-sse/services/compression/adaptiveCompression/resolveAdaptivePlan.ts";
|
||||
import { DEFAULT_CONTEXT_BUDGET } from "@omniroute/open-sse/services/compression/adaptiveCompression/types.ts";
|
||||
|
||||
const cfg = (over = {}) => ({ ...DEFAULT_CONTEXT_BUDGET, mode: "floor" as const, ...over });
|
||||
const basePlan = { mode: "off", stackedPipeline: [] as Array<{ engine: string; intensity?: string }> };
|
||||
|
||||
test("already fits → base plan unchanged, fit=true, no stages", () => {
|
||||
const { plan, telemetry } = resolveAdaptivePlan({
|
||||
basePlan,
|
||||
estimatedTokens: 1000, // well under target
|
||||
modelContextLimit: 200000,
|
||||
requestMaxTokens: 8000,
|
||||
config: cfg(),
|
||||
});
|
||||
assert.deepEqual(plan, basePlan);
|
||||
assert.ok(telemetry);
|
||||
assert.equal(telemetry!.fit, true);
|
||||
assert.deepEqual(telemetry!.stagesApplied, []);
|
||||
assert.equal(telemetry!.target, 200000 - 8000 - 1024);
|
||||
assert.ok(telemetry!.headroomBefore > 0);
|
||||
assert.equal(telemetry!.headroomAfter, telemetry!.headroomBefore);
|
||||
});
|
||||
|
||||
test("over target → escalates and stops at first fitting stage (no over-escalation)", () => {
|
||||
// Injected estimator: each stage halves the prompt. target = 200000-8000-1024 = 190976.
|
||||
// Start over target at 400000: stage1 → 200000 (still over), stage2 → 100000 (fits) → STOP.
|
||||
const halve = (prior: number) => Math.round(prior / 2);
|
||||
const { plan, telemetry } = resolveAdaptivePlan({
|
||||
basePlan: { mode: "off", stackedPipeline: [] },
|
||||
estimatedTokens: 400000,
|
||||
modelContextLimit: 200000,
|
||||
requestMaxTokens: 8000,
|
||||
config: cfg(),
|
||||
estimate: halve,
|
||||
});
|
||||
assert.equal(telemetry!.fit, true);
|
||||
assert.equal(telemetry!.stagesApplied.length, 2); // stopped after the 2nd stage
|
||||
assert.equal(plan.mode, "stacked");
|
||||
assert.equal(plan.stackedPipeline.length, 2);
|
||||
// first two ladder engines above "off": session-dedup then rtk
|
||||
assert.deepEqual(telemetry!.stagesApplied, ["session-dedup", "rtk"]);
|
||||
assert.ok(telemetry!.headroomAfter >= 0);
|
||||
});
|
||||
|
||||
test("floor escalates beyond a light base plan (base lite → starts above lite)", () => {
|
||||
const halve = (prior: number) => Math.round(prior / 2);
|
||||
const { telemetry } = resolveAdaptivePlan({
|
||||
basePlan: { mode: "lite", stackedPipeline: [] },
|
||||
estimatedTokens: 400000,
|
||||
modelContextLimit: 200000,
|
||||
requestMaxTokens: 8000,
|
||||
config: cfg(),
|
||||
estimate: halve,
|
||||
});
|
||||
// base "lite" rank=4; ladder stages above rank 4 = caveman(5), aggressive(6), ultra(7).
|
||||
assert.equal(telemetry!.stagesApplied[0], "caveman");
|
||||
assert.ok(!telemetry!.stagesApplied.includes("session-dedup")); // did NOT restart below lite
|
||||
assert.ok(!telemetry!.stagesApplied.includes("rtk"));
|
||||
});
|
||||
|
||||
test("ladder exhausted, still over target → fit=false, all stages applied, plan still set", () => {
|
||||
const noop = (prior: number) => prior; // estimator never reduces → never fits
|
||||
const { plan, telemetry } = resolveAdaptivePlan({
|
||||
basePlan: { mode: "off", stackedPipeline: [] },
|
||||
estimatedTokens: 999999,
|
||||
modelContextLimit: 200000,
|
||||
requestMaxTokens: 8000,
|
||||
config: cfg(),
|
||||
estimate: noop,
|
||||
});
|
||||
assert.equal(telemetry!.fit, false); // budget-exceeded
|
||||
assert.equal(telemetry!.stagesApplied.length, 7); // entire DEFAULT_LADDER above "off"
|
||||
assert.equal(plan.mode, "stacked");
|
||||
assert.ok(plan.stackedPipeline.length >= 7); // best-effort plan, content NOT dropped
|
||||
assert.ok(telemetry!.headroomAfter < 0);
|
||||
});
|
||||
|
||||
test("replace-autotrigger: fires on bare off base, defers to an explicit base plan", () => {
|
||||
const halve = (prior: number) => Math.round(prior / 2);
|
||||
// bare off base → it acts
|
||||
const acts = resolveAdaptivePlan({
|
||||
basePlan: { mode: "off", stackedPipeline: [] },
|
||||
estimatedTokens: 400000, modelContextLimit: 200000, requestMaxTokens: 8000,
|
||||
config: cfg({ mode: "replace-autotrigger" }), estimate: halve,
|
||||
});
|
||||
assert.ok(acts.telemetry!.stagesApplied.length > 0);
|
||||
|
||||
// explicit aggressive base → defer (choice wins, may overflow)
|
||||
const defers = resolveAdaptivePlan({
|
||||
basePlan: { mode: "aggressive", stackedPipeline: [] },
|
||||
estimatedTokens: 400000, modelContextLimit: 200000, requestMaxTokens: 8000,
|
||||
config: cfg({ mode: "replace-autotrigger" }), estimate: halve,
|
||||
});
|
||||
assert.deepEqual(defers.plan, { mode: "aggressive", stackedPipeline: [] });
|
||||
assert.deepEqual(defers.telemetry!.stagesApplied, []);
|
||||
assert.equal(defers.telemetry!.fit, false); // 400000 > target, recorded as not fitting
|
||||
});
|
||||
|
||||
test("unknown model context limit → skip adaptive (null telemetry, base unchanged)", () => {
|
||||
for (const lim of [null, 0, -1]) {
|
||||
const { plan, telemetry } = resolveAdaptivePlan({
|
||||
basePlan, estimatedTokens: 999999, modelContextLimit: lim,
|
||||
requestMaxTokens: 8000, config: cfg(),
|
||||
});
|
||||
assert.equal(telemetry, null);
|
||||
assert.deepEqual(plan, basePlan);
|
||||
}
|
||||
});
|
||||
|
||||
test("hard-off: floor still escalates an overflowing 'off' base plan (spec §9)", () => {
|
||||
const halve = (prior: number) => Math.round(prior / 2);
|
||||
const { telemetry } = resolveAdaptivePlan({
|
||||
basePlan: { mode: "off", stackedPipeline: [] }, // explicit off (header off resolves to this)
|
||||
estimatedTokens: 400000, modelContextLimit: 200000, requestMaxTokens: 8000,
|
||||
config: cfg(), // mode: "floor"
|
||||
estimate: halve,
|
||||
});
|
||||
assert.ok(telemetry!.stagesApplied.length > 0); // floor escalated despite off
|
||||
assert.equal(telemetry!.fit, true);
|
||||
});
|
||||
@@ -0,0 +1,82 @@
|
||||
import { test } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import {
|
||||
selectCompressionPlan,
|
||||
shouldAutoTrigger,
|
||||
} from "@omniroute/open-sse/services/compression/strategySelector.ts";
|
||||
import { getDefaultCompressionConfig } from "@omniroute/open-sse/services/compression/stats.ts";
|
||||
|
||||
function legacyCfg() {
|
||||
return {
|
||||
...getDefaultCompressionConfig(),
|
||||
enabled: true,
|
||||
enginesExplicit: false,
|
||||
defaultMode: "lite" as const,
|
||||
autoTriggerMode: "aggressive" as const,
|
||||
autoTriggerTokens: 100000,
|
||||
};
|
||||
}
|
||||
|
||||
test("no contextBudget → auto-trigger path is byte-identical to legacy", () => {
|
||||
const cfg = legacyCfg(); // no contextBudget field
|
||||
// under threshold → derived default ("lite")
|
||||
const small = selectCompressionPlan(cfg, null, 1000);
|
||||
assert.equal(small.mode, "lite");
|
||||
// over threshold → auto-trigger fires → "aggressive"
|
||||
const big = selectCompressionPlan(cfg, null, 200000);
|
||||
assert.equal(big.mode, "aggressive");
|
||||
assert.equal(shouldAutoTrigger(cfg, 200000), true);
|
||||
});
|
||||
|
||||
test("contextBudget.mode='off' → identical to no contextBudget", () => {
|
||||
const cfg = { ...legacyCfg(), contextBudget: { mode: "off" as const } };
|
||||
assert.equal(selectCompressionPlan(cfg as any, null, 200000).mode, "aggressive");
|
||||
});
|
||||
|
||||
test("adaptive floor: bypasses auto-trigger, escalates a base plan to fit", () => {
|
||||
const cfg = {
|
||||
...legacyCfg(),
|
||||
autoTriggerTokens: 100000,
|
||||
autoTriggerMode: "lite" as const,
|
||||
contextBudget: {
|
||||
mode: "floor" as const,
|
||||
policy: "reserve-output" as const,
|
||||
outputReserve: 4096,
|
||||
safetyMargin: 1024,
|
||||
pct: 0.85,
|
||||
absoluteBudget: 0,
|
||||
},
|
||||
};
|
||||
const tel: {
|
||||
value: import("@omniroute/open-sse/services/compression/adaptiveCompression/types.ts").AdaptiveTelemetry | null;
|
||||
} = { value: null };
|
||||
// estimatedTokens far over the 200000-window target → adaptive must escalate.
|
||||
const plan = selectCompressionPlan(
|
||||
cfg as any, null, 5_000_000, undefined, undefined, {}, null,
|
||||
{ modelContextLimit: 200000, requestMaxTokens: 8000, onAdaptive: (t) => { tel.value = t; } }
|
||||
);
|
||||
assert.equal(plan.mode, "stacked");
|
||||
assert.ok(plan.stackedPipeline.length > 0);
|
||||
assert.ok(tel.value, "adaptive telemetry must be surfaced");
|
||||
assert.equal(tel.value!.policy, "reserve-output");
|
||||
assert.equal(tel.value!.target, 200000 - 8000 - 1024);
|
||||
assert.ok(tel.value!.stagesApplied.length > 0);
|
||||
});
|
||||
|
||||
test("adaptive escalation still respects caching downgrade (D-C / §6 cache-safety)", () => {
|
||||
const cfg = {
|
||||
...legacyCfg(),
|
||||
contextBudget: { mode: "floor" as const, policy: "reserve-output" as const, outputReserve: 4096, safetyMargin: 1024, pct: 0.85, absoluteBudget: 0 },
|
||||
};
|
||||
// A caching provider context downgrades aggressive/ultra → standard; the adaptive plan's
|
||||
// mode is "stacked", which getCacheAwareStrategy passes through unchanged, but the
|
||||
// pipeline engines remain those that the existing apply path already cache-guards.
|
||||
const body = { model: "openai/gpt-5", messages: [{ role: "user", content: "x" }] };
|
||||
const plan = selectCompressionPlan(
|
||||
cfg as any, null, 5_000_000, body, { provider: "openai", model: "openai/gpt-5" }, {}, null,
|
||||
{ modelContextLimit: 200000, requestMaxTokens: 8000 }
|
||||
);
|
||||
// mode is still a valid CompressionMode string after the cache-aware pass
|
||||
assert.ok(typeof plan.mode === "string");
|
||||
assert.ok(plan.stackedPipeline.length > 0);
|
||||
});
|
||||
@@ -0,0 +1,209 @@
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import {
|
||||
extractTextContent,
|
||||
replaceTextContent,
|
||||
type ChatMessageLike,
|
||||
} from "../../../open-sse/services/compression/messageContent.ts";
|
||||
import { applyAging } from "../../../open-sse/services/compression/progressiveAging.ts";
|
||||
import { compressAggressive } from "../../../open-sse/services/compression/aggressive.ts";
|
||||
import type { AgingThresholds } from "../../../open-sse/services/compression/types.ts";
|
||||
|
||||
// ─── ISSUE 1 — B-AGG-TEXTDROP ────────────────────────────────────────────────
|
||||
// `replaceTextContent` previously dropped every text block after the first via
|
||||
// flatMap → []. With the standard call pattern (newText = compressed JOIN of all
|
||||
// text blocks), the joined original content must remain recoverable: nothing the
|
||||
// model can no longer see may be silently lost.
|
||||
describe("replaceTextContent — multi-text-block fidelity (B-AGG-TEXTDROP)", () => {
|
||||
it("does not silently drop trailing text-block content absent from newText", () => {
|
||||
const msg: ChatMessageLike = {
|
||||
role: "user",
|
||||
content: [
|
||||
{ type: "text", text: "FIRST block alpha" },
|
||||
{ type: "image", source: { foo: 1 } },
|
||||
{ type: "text", text: "SECOND block bravo" },
|
||||
{ type: "text", text: "THIRD block charlie" },
|
||||
],
|
||||
};
|
||||
|
||||
// newText does NOT subsume the trailing blocks (worst case): a caller that
|
||||
// only summarized the first block. The trailing blocks' content must not
|
||||
// silently vanish.
|
||||
const replaced = replaceTextContent(msg, "NEWTEXT-only-first");
|
||||
|
||||
const out = extractTextContent(replaced.content);
|
||||
assert.ok(out.includes("NEWTEXT-only-first"), "replacement text missing");
|
||||
assert.ok(out.includes("SECOND block bravo"), "second block silently dropped");
|
||||
assert.ok(out.includes("THIRD block charlie"), "third block silently dropped");
|
||||
|
||||
// Non-text blocks (image) must survive unchanged.
|
||||
const blocks = replaced.content as Array<{ type?: string }>;
|
||||
assert.ok(
|
||||
blocks.some((b) => b.type === "image"),
|
||||
"non-text block must be preserved"
|
||||
);
|
||||
});
|
||||
|
||||
it("collapses trailing blocks when newText already subsumes them (no duplication)", () => {
|
||||
const msg: ChatMessageLike = {
|
||||
role: "user",
|
||||
content: [
|
||||
{ type: "text", text: "alpha" },
|
||||
{ type: "text", text: "bravo" },
|
||||
],
|
||||
};
|
||||
// Standard call pattern: newText = compressed JOIN of all text blocks.
|
||||
const joined = extractTextContent(msg.content); // "alpha\nbravo"
|
||||
const replaced = replaceTextContent(msg, joined);
|
||||
const blocks = replaced.content as Array<{ type?: string; text?: string }>;
|
||||
const textBlocks = blocks.filter((b) => b.type === "text" || b.text !== undefined);
|
||||
// Should collapse to a single text block — no duplicated "alpha"/"bravo".
|
||||
assert.equal(textBlocks.length, 1, "subsumed trailing blocks should be collapsed");
|
||||
assert.equal(extractTextContent(replaced.content), joined);
|
||||
});
|
||||
|
||||
it("aging a multi-text-block message keeps all original text represented", () => {
|
||||
// Build a long conversation so the first (multi-block) message ages out.
|
||||
const first: ChatMessageLike = {
|
||||
role: "user",
|
||||
content: [
|
||||
{ type: "text", text: "alpha-marker request: fix login" },
|
||||
{ type: "text", text: "bravo-marker error: TypeError: boom" },
|
||||
],
|
||||
};
|
||||
const msgs: ChatMessageLike[] = [first];
|
||||
for (let i = 1; i < 8; i++) {
|
||||
msgs.push({ role: i % 2 ? "assistant" : "user", content: `filler ${i} ${"z".repeat(60)}` });
|
||||
}
|
||||
const result = applyAging(msgs, { fullSummary: 10, moderate: 10, light: 3, verbatim: 1 });
|
||||
const out = extractTextContent(result.messages[0].content as ChatMessageLike["content"]);
|
||||
// Light tier keeps content; both blocks' text must still be present (joined).
|
||||
assert.ok(out.includes("alpha-marker"), "first text block lost during aging");
|
||||
assert.ok(out.includes("bravo-marker"), "second text block silently dropped during aging");
|
||||
});
|
||||
});
|
||||
|
||||
// ─── ISSUE 2 — B-AGG-ANTHROPIC-TR ────────────────────────────────────────────
|
||||
// Anthropic-shape tool_result blocks (a {type:"tool_result"} content block inside
|
||||
// a user message) must be compressed too, preserving tool_use_id + block type.
|
||||
describe("aggressive — Anthropic tool_result compression (B-AGG-ANTHROPIC-TR)", () => {
|
||||
it("compresses the text inside an Anthropic tool_result block", () => {
|
||||
const bigJsonArray = JSON.stringify(
|
||||
Array.from({ length: 200 }, (_, i) => ({ id: i, name: `item${i}`, data: "x".repeat(40) }))
|
||||
);
|
||||
const userMsg: ChatMessageLike = {
|
||||
role: "user",
|
||||
content: [
|
||||
{
|
||||
type: "tool_result",
|
||||
tool_use_id: "toolu_ABC123",
|
||||
content: [{ type: "text", text: bigJsonArray }],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const result = compressAggressive([userMsg]);
|
||||
const outMsg = result.messages[0];
|
||||
const blocks = outMsg.content as Array<Record<string, unknown>>;
|
||||
const tr = blocks.find((b) => b.type === "tool_result");
|
||||
|
||||
assert.ok(tr, "tool_result block must survive");
|
||||
assert.equal(tr!.type, "tool_result", "block type must be unchanged");
|
||||
assert.equal(tr!.tool_use_id, "toolu_ABC123", "tool_use_id must be preserved");
|
||||
|
||||
// The inner text must be smaller than the original (it was compressed).
|
||||
const innerText =
|
||||
typeof tr!.content === "string"
|
||||
? (tr!.content as string)
|
||||
: ((tr!.content as Array<{ type?: string; text?: string }>) ?? [])
|
||||
.filter((c) => c.type === "text")
|
||||
.map((c) => c.text ?? "")
|
||||
.join("\n");
|
||||
assert.ok(
|
||||
innerText.length < bigJsonArray.length,
|
||||
`tool_result inner text was not compressed (orig ${bigJsonArray.length}, got ${innerText.length})`
|
||||
);
|
||||
assert.ok(result.stats.aggressive!.toolResultSavings > 0, "toolResultSavings must be > 0");
|
||||
});
|
||||
|
||||
it("compresses a string-form Anthropic tool_result block", () => {
|
||||
const errorOutput =
|
||||
"TypeError: Cannot read property 'x' of undefined\n" +
|
||||
Array.from({ length: 40 }, (_, i) => ` at fn${i} (file${i}.ts:${i + 1}:${i + 5})`).join(
|
||||
"\n"
|
||||
);
|
||||
const userMsg: ChatMessageLike = {
|
||||
role: "user",
|
||||
content: [{ type: "tool_result", tool_use_id: "toolu_ERR", content: errorOutput }],
|
||||
};
|
||||
const result = compressAggressive([userMsg]);
|
||||
const tr = (result.messages[0].content as Array<Record<string, unknown>>).find(
|
||||
(b) => b.type === "tool_result"
|
||||
);
|
||||
assert.ok(tr, "tool_result block must survive");
|
||||
assert.equal(tr!.tool_use_id, "toolu_ERR");
|
||||
assert.ok((tr!.content as string).length < errorOutput.length, "string tool_result not compressed");
|
||||
});
|
||||
});
|
||||
|
||||
// ─── ISSUE 3 — B-AGG-JSONTAG ─────────────────────────────────────────────────
|
||||
// Aging must not corrupt structured content (JSON / fenced code block) with a
|
||||
// literal [COMPRESSED:...] inline prefix.
|
||||
describe("progressiveAging — structured-content tag safety (B-AGG-JSONTAG)", () => {
|
||||
const thresholds: AgingThresholds = { fullSummary: 10, moderate: 10, light: 3, verbatim: 1 };
|
||||
|
||||
function agedFirstContent(content: string, t: AgingThresholds): string {
|
||||
const msgs: ChatMessageLike[] = [
|
||||
{ role: "user", content },
|
||||
{ role: "assistant", content: "a " + "z".repeat(60) },
|
||||
{ role: "user", content: "b " + "z".repeat(60) },
|
||||
{ role: "assistant", content: "c" },
|
||||
];
|
||||
const result = applyAging(msgs, t);
|
||||
const c = result.messages[0].content;
|
||||
return typeof c === "string" ? c : extractTextContent(c as ChatMessageLike["content"]);
|
||||
}
|
||||
|
||||
it("keeps pure-JSON content JSON.parse-able after aging", () => {
|
||||
const json = JSON.stringify({
|
||||
status: "ok",
|
||||
items: Array.from({ length: 5 }, (_, i) => ({ id: i, name: `n${i}` })),
|
||||
meta: { a: 1, b: 2 },
|
||||
});
|
||||
const aged = agedFirstContent(json, thresholds);
|
||||
// Must remain valid JSON (no inline tag corruption).
|
||||
assert.doesNotThrow(() => JSON.parse(aged), `aged JSON not parseable: ${aged.slice(0, 80)}`);
|
||||
});
|
||||
|
||||
it("keeps a fenced code block valid after aging (tag outside the fence)", () => {
|
||||
const fenced = "```json\n{\n \"a\": 1,\n \"b\": [1, 2, 3]\n}\n```";
|
||||
const aged = agedFirstContent(fenced, thresholds);
|
||||
// The fenced block must still be present and intact.
|
||||
assert.ok(aged.includes("```json"), "opening fence lost");
|
||||
assert.ok(aged.trimEnd().endsWith("```"), "closing fence lost");
|
||||
assert.ok(aged.includes('"a": 1'), "fenced payload corrupted");
|
||||
});
|
||||
|
||||
it("does not re-compress structured content on a second aging pass (recursion guard)", () => {
|
||||
const json = JSON.stringify({ status: "ok", items: [{ id: 0 }, { id: 1 }], meta: { a: 1 } });
|
||||
const msgs: ChatMessageLike[] = [
|
||||
{ role: "user", content: json },
|
||||
{ role: "assistant", content: "a " + "z".repeat(60) },
|
||||
{ role: "user", content: "b " + "z".repeat(60) },
|
||||
{ role: "assistant", content: "c" },
|
||||
];
|
||||
const first = applyAging(msgs, thresholds);
|
||||
const second = applyAging(first.messages as ChatMessageLike[], thresholds);
|
||||
const firstContent = JSON.stringify(
|
||||
first.messages.map((m) => (m as ChatMessageLike).content)
|
||||
);
|
||||
const secondContent = JSON.stringify(
|
||||
second.messages.map((m) => (m as ChatMessageLike).content)
|
||||
);
|
||||
assert.equal(secondContent, firstContent, "second aging pass changed structured content");
|
||||
// And it must still be parseable.
|
||||
const c0 = (second.messages[0] as ChatMessageLike).content;
|
||||
const text0 = typeof c0 === "string" ? c0 : extractTextContent(c0 as ChatMessageLike["content"]);
|
||||
assert.doesNotThrow(() => JSON.parse(text0), "JSON corrupted after two aging passes");
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,84 @@
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { compressAggressive } from "../../../open-sse/services/compression/aggressive.ts";
|
||||
import type { AggressiveConfig } from "../../../open-sse/services/compression/types.ts";
|
||||
|
||||
function makeMessages(count: number): Array<{ role: string; content: string }> {
|
||||
return Array.from({ length: count }, (_, i) => ({
|
||||
role: i % 2 === 0 ? "user" : "assistant",
|
||||
content: `Message ${i}: ${"x".repeat(200)}`,
|
||||
}));
|
||||
}
|
||||
|
||||
describe("compressAggressive", () => {
|
||||
it("returns messages unchanged for empty input", () => {
|
||||
const result = compressAggressive([]);
|
||||
assert.equal(result.messages.length, 0);
|
||||
assert.equal(result.stats.mode, "aggressive");
|
||||
});
|
||||
|
||||
it("returns messages for single message (no compression needed)", () => {
|
||||
const msgs = [{ role: "user", content: "Hello" }];
|
||||
const result = compressAggressive(msgs);
|
||||
assert.equal(result.messages.length, 1);
|
||||
});
|
||||
|
||||
it("compresses 20-message conversation and returns stats", () => {
|
||||
const msgs = makeMessages(20);
|
||||
const result = compressAggressive(msgs);
|
||||
assert.ok(result.messages.length > 0);
|
||||
assert.equal(result.stats.mode, "aggressive");
|
||||
assert.ok(typeof result.stats.originalTokens === "number");
|
||||
assert.ok(typeof result.stats.compressedTokens === "number");
|
||||
});
|
||||
|
||||
it("skips messages with [COMPRESSED: prefix (recursion guard)", () => {
|
||||
const msgs = [{ role: "assistant", content: "[COMPRESSED:aging:fullSummary] prior summary" }];
|
||||
const result = compressAggressive(msgs);
|
||||
const content =
|
||||
typeof result.messages[0].content === "string" ? result.messages[0].content : "";
|
||||
assert.ok(content.startsWith("[COMPRESSED:"));
|
||||
assert.ok(!content.includes("[COMPRESSED:aging:fullSummary][COMPRESSED:"));
|
||||
});
|
||||
|
||||
it("step failure triggers downgrade, not crash", () => {
|
||||
const msgs = makeMessages(10);
|
||||
const config: Partial<AggressiveConfig> = {
|
||||
toolStrategies: {
|
||||
fileContent: false,
|
||||
grepSearch: false,
|
||||
shellOutput: false,
|
||||
json: false,
|
||||
errorMessage: false,
|
||||
},
|
||||
};
|
||||
const result = compressAggressive(msgs, config);
|
||||
assert.ok(result.messages.length > 0);
|
||||
assert.ok(typeof result.stats.savingsPercent === "number");
|
||||
});
|
||||
|
||||
it("config merge overrides defaults", () => {
|
||||
const msgs = makeMessages(10);
|
||||
const config: Partial<AggressiveConfig> = {
|
||||
maxTokensPerMessage: 100,
|
||||
minSavingsThreshold: 0.5,
|
||||
};
|
||||
const result = compressAggressive(msgs, config);
|
||||
assert.ok(result.messages.length > 0);
|
||||
});
|
||||
|
||||
it("aggressive stats breakdown is populated", () => {
|
||||
const msgs = makeMessages(20);
|
||||
const result = compressAggressive(msgs);
|
||||
assert.ok(result.stats.aggressive !== undefined);
|
||||
assert.ok(typeof result.stats.aggressive!.summarizerSavings === "number");
|
||||
assert.ok(typeof result.stats.aggressive!.toolResultSavings === "number");
|
||||
assert.ok(typeof result.stats.aggressive!.agingSavings === "number");
|
||||
});
|
||||
|
||||
it("techniquesUsed lists applied strategies", () => {
|
||||
const msgs = makeMessages(20);
|
||||
const result = compressAggressive(msgs);
|
||||
assert.ok(Array.isArray(result.stats.techniquesUsed));
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,76 @@
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
|
||||
import { applyCompression } from "../../../open-sse/services/compression/strategySelector.ts";
|
||||
import { registerCompressionEngine } from "../../../open-sse/services/compression/index.ts";
|
||||
import type { CompressionEngine } from "../../../open-sse/services/compression/engines/types.ts";
|
||||
import type { CompressionConfig } from "../../../open-sse/services/compression/types.ts";
|
||||
|
||||
// The combo proactive-fallback path calls applyCompression(stacked); a throwing engine there
|
||||
// propagates and is swallowed as a "Speculative task error", silently dropping the target. The
|
||||
// fix lets that caller opt into the TV1 bail-out (enabled, minGainPercent 0 = skip-on-throw
|
||||
// without changing the min-gain advance behavior). This documents the opt-in contract.
|
||||
const THROWING_ENGINE: CompressionEngine = {
|
||||
id: "applycompress-bailout-throw",
|
||||
name: "Throwing Test Engine",
|
||||
description: "test fixture",
|
||||
icon: "",
|
||||
targets: ["messages"],
|
||||
stackable: true,
|
||||
stackPriority: 999,
|
||||
metadata: {
|
||||
id: "applycompress-bailout-throw",
|
||||
name: "Throwing Test Engine",
|
||||
description: "test",
|
||||
inputScope: "messages",
|
||||
targetLatencyMs: 1,
|
||||
supportsPreview: false,
|
||||
stable: false,
|
||||
},
|
||||
apply() {
|
||||
throw new Error("boom from fallback engine");
|
||||
},
|
||||
compress() {
|
||||
throw new Error("boom from fallback engine");
|
||||
},
|
||||
getConfigSchema() {
|
||||
return [];
|
||||
},
|
||||
validateConfig() {
|
||||
return { valid: true, errors: [] };
|
||||
},
|
||||
};
|
||||
|
||||
function stackedConfig(): CompressionConfig {
|
||||
return {
|
||||
stackedPipeline: [{ engine: "applycompress-bailout-throw" }],
|
||||
} as unknown as CompressionConfig;
|
||||
}
|
||||
|
||||
describe("applyCompression — combo fallback bail-out opt-in", () => {
|
||||
it("opting into bail-out skips a throwing engine instead of propagating (no silent drop)", () => {
|
||||
registerCompressionEngine(THROWING_ENGINE);
|
||||
const body = { messages: [{ role: "user", content: "hello world" }] };
|
||||
|
||||
let result: ReturnType<typeof applyCompression> | undefined;
|
||||
assert.doesNotThrow(() => {
|
||||
result = applyCompression(body, "stacked", {
|
||||
config: stackedConfig(),
|
||||
bailout: { enabled: true, minGainPercent: 0 },
|
||||
});
|
||||
});
|
||||
assert.ok(result, "returns a result instead of throwing");
|
||||
assert.equal(result!.compressed, false, "a crashing engine compresses nothing");
|
||||
});
|
||||
|
||||
it("without bail-out, a throwing engine still propagates (TV1 default unchanged)", () => {
|
||||
registerCompressionEngine(THROWING_ENGINE);
|
||||
const body = { messages: [{ role: "user", content: "hello world" }] };
|
||||
|
||||
assert.throws(
|
||||
() => applyCompression(body, "stacked", { config: stackedConfig() }),
|
||||
/boom from fallback engine/,
|
||||
"the default (opt-out) path is unchanged — bail-out is strictly opt-in"
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,313 @@
|
||||
/**
|
||||
* TV1 — Transversal compression bail-out discipline (OPT-IN).
|
||||
*
|
||||
* Proves:
|
||||
* 1. An engine that THROWS in apply() → step skipped (no throw, original body kept).
|
||||
* 2. An engine whose gain is < minGainPercent (10%) → step skipped.
|
||||
* 3. An engine with gain ≥ 10% → applied normally.
|
||||
* 4. With bail-out DISABLED (default) → a <10%-gain engine IS applied
|
||||
* (proving that opt-in default never changes existing behaviour).
|
||||
*/
|
||||
import { describe, it, before, after } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
|
||||
import {
|
||||
applyStackedCompression,
|
||||
applyStackedCompressionAsync,
|
||||
} from "../../../open-sse/services/compression/index.ts";
|
||||
import {
|
||||
registerCompressionEngine,
|
||||
unregisterCompressionEngine,
|
||||
} from "../../../open-sse/services/compression/engines/registry.ts";
|
||||
import type {
|
||||
CompressionEngine,
|
||||
CompressionEngineTarget,
|
||||
} from "../../../open-sse/services/compression/engines/types.ts";
|
||||
import type {
|
||||
CompressionPipelineStep,
|
||||
CompressionResult,
|
||||
} from "../../../open-sse/services/compression/types.ts";
|
||||
|
||||
// ── helpers ──────────────────────────────────────────────────────────────────
|
||||
|
||||
/** Base skeleton shared by all fake engines. */
|
||||
function makeBaseEngine(id: string): Omit<CompressionEngine, "apply"> {
|
||||
return {
|
||||
id,
|
||||
name: id,
|
||||
description: id,
|
||||
icon: "x",
|
||||
targets: ["messages"] as CompressionEngineTarget[],
|
||||
stackable: true,
|
||||
stackPriority: 0,
|
||||
metadata: {
|
||||
id,
|
||||
name: id,
|
||||
description: id,
|
||||
inputScope: "messages",
|
||||
targetLatencyMs: 1,
|
||||
supportsPreview: false,
|
||||
stable: true,
|
||||
},
|
||||
compress: (body) => ({ body, compressed: false, stats: null }),
|
||||
getConfigSchema: () => [],
|
||||
validateConfig: () => ({ valid: true, errors: [] }),
|
||||
};
|
||||
}
|
||||
|
||||
/** Engine that always throws during apply(). */
|
||||
const THROW_ENGINE_ID = "bailout-throw-engine";
|
||||
const throwEngine: CompressionEngine = {
|
||||
...makeBaseEngine(THROW_ENGINE_ID),
|
||||
apply: (_body) => {
|
||||
throw new Error("simulated engine failure");
|
||||
},
|
||||
};
|
||||
|
||||
/** Engine that returns a low gain (5% < 10% threshold). */
|
||||
const LOW_GAIN_ENGINE_ID = "bailout-low-gain-engine";
|
||||
function makeLowGainEngine(id = LOW_GAIN_ENGINE_ID): CompressionEngine {
|
||||
return {
|
||||
...makeBaseEngine(id),
|
||||
apply: (body) => {
|
||||
const messages = (body.messages as Array<{ role: string; content: string }>) ?? [];
|
||||
// Tag the user message; drop any padding (non-user) content so the body shrinks.
|
||||
const next = messages.map((m) =>
|
||||
m.role === "user" ? { ...m, content: m.content + "|low" } : { ...m, content: "" }
|
||||
);
|
||||
return {
|
||||
body: { ...body, messages: next },
|
||||
compressed: true,
|
||||
stats: {
|
||||
originalTokens: 100,
|
||||
compressedTokens: 95,
|
||||
savingsPercent: 5, // 5% < 10% threshold
|
||||
techniquesUsed: [id],
|
||||
mode: "stacked",
|
||||
timestamp: 0,
|
||||
durationMs: 0.1,
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/** Engine that returns a high gain (20% ≥ 10% threshold). */
|
||||
const HIGH_GAIN_ENGINE_ID = "bailout-high-gain-engine";
|
||||
const highGainEngine: CompressionEngine = {
|
||||
...makeBaseEngine(HIGH_GAIN_ENGINE_ID),
|
||||
apply: (body) => {
|
||||
const messages = (body.messages as Array<{ role: string; content: string }>) ?? [];
|
||||
// Tag the user message; drop any padding (non-user) content so the body shrinks.
|
||||
const next = messages.map((m) =>
|
||||
m.role === "user" ? { ...m, content: m.content + "|high" } : { ...m, content: "" }
|
||||
);
|
||||
return {
|
||||
body: { ...body, messages: next },
|
||||
compressed: true,
|
||||
stats: {
|
||||
originalTokens: 100,
|
||||
compressedTokens: 80,
|
||||
savingsPercent: 20, // 20% ≥ 10% threshold
|
||||
techniquesUsed: [HIGH_GAIN_ENGINE_ID],
|
||||
mode: "stacked",
|
||||
timestamp: 0,
|
||||
durationMs: 0.1,
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
/** Async variant of the low-gain engine. */
|
||||
const LOW_GAIN_ASYNC_ID = "bailout-low-gain-async";
|
||||
const lowGainAsyncEngine: CompressionEngine = {
|
||||
...makeLowGainEngine(LOW_GAIN_ASYNC_ID),
|
||||
apply: (body) => ({ body, compressed: false, stats: null }), // sync pass-through (async-only pattern)
|
||||
applyAsync: async (body) => makeLowGainEngine(LOW_GAIN_ASYNC_ID).apply(body),
|
||||
};
|
||||
|
||||
/** Async variant of the throw engine. */
|
||||
const THROW_ASYNC_ID = "bailout-throw-async";
|
||||
const throwAsyncEngine: CompressionEngine = {
|
||||
...makeBaseEngine(THROW_ASYNC_ID),
|
||||
apply: (body) => ({ body, compressed: false, stats: null }), // sync pass-through
|
||||
applyAsync: async (_body) => {
|
||||
throw new Error("simulated async engine failure");
|
||||
},
|
||||
};
|
||||
|
||||
function pipeline(...ids: string[]): CompressionPipelineStep[] {
|
||||
return ids.map((engine) => ({ engine })) as unknown as CompressionPipelineStep[];
|
||||
}
|
||||
|
||||
function userContent(result: CompressionResult): string {
|
||||
const messages = result.body.messages as Array<{ role: string; content: string }>;
|
||||
return messages.find((m) => m.role === "user")!.content;
|
||||
}
|
||||
|
||||
const BAILOUT_ON = { bailout: { enabled: true, minGainPercent: 10 } };
|
||||
const BAILOUT_OFF = {}; // default — no bailout field
|
||||
|
||||
// A fixture body carrying a large droppable padding message. When an engine runs it
|
||||
// drops that padding (and tags the user message), so the FINAL stacked body genuinely
|
||||
// shrinks — keeping the #5527 (T02) inflation guard from reverting these advancement
|
||||
// fixtures. The guard only reverts a pipeline whose final body did NOT shrink in tokens;
|
||||
// these tests exercise bail-out/advancement, an orthogonal concern, so the body must
|
||||
// realistically shrink for the marker assertions to survive the guard.
|
||||
const PADDING = "padding tokens ".repeat(40);
|
||||
function mkBody(): { messages: Array<{ role: string; content: string }> } {
|
||||
return {
|
||||
messages: [
|
||||
{ role: "user", content: "hello" },
|
||||
{ role: "assistant", content: PADDING },
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
// ── suite ────────────────────────────────────────────────────────────────────
|
||||
|
||||
describe("TV1 — stacked pipeline bail-out discipline (OPT-IN)", () => {
|
||||
before(() => {
|
||||
registerCompressionEngine(throwEngine);
|
||||
registerCompressionEngine(makeLowGainEngine());
|
||||
registerCompressionEngine(highGainEngine);
|
||||
registerCompressionEngine(lowGainAsyncEngine);
|
||||
registerCompressionEngine(throwAsyncEngine);
|
||||
});
|
||||
|
||||
after(() => {
|
||||
unregisterCompressionEngine(THROW_ENGINE_ID);
|
||||
unregisterCompressionEngine(LOW_GAIN_ENGINE_ID);
|
||||
unregisterCompressionEngine(HIGH_GAIN_ENGINE_ID);
|
||||
unregisterCompressionEngine(LOW_GAIN_ASYNC_ID);
|
||||
unregisterCompressionEngine(THROW_ASYNC_ID);
|
||||
});
|
||||
|
||||
// ── SYNC tests ────────────────────────────────────────────────────────────
|
||||
|
||||
describe("sync — applyStackedCompression", () => {
|
||||
it("bail-out ON: throwing engine → step skipped, pipeline does NOT throw", () => {
|
||||
const body = mkBody();
|
||||
|
||||
// Must not throw and original body is kept (throw engine was the only step)
|
||||
const result = applyStackedCompression(body, pipeline(THROW_ENGINE_ID), BAILOUT_ON);
|
||||
|
||||
assert.equal(result.compressed, false);
|
||||
assert.equal(userContent(result), "hello"); // body unchanged
|
||||
|
||||
// TV1 fix: a crashing engine must be RECORDED in telemetry, not silently gone.
|
||||
assert.equal(result.stats?.fallbackApplied, true, "throw must set fallbackApplied");
|
||||
assert.ok(
|
||||
result.stats?.validationErrors?.some((e) => e.includes(THROW_ENGINE_ID)),
|
||||
"throwing engine must be recorded in validationErrors"
|
||||
);
|
||||
});
|
||||
|
||||
it("bail-out ON: throwing engine before a good engine → good engine still runs", () => {
|
||||
const body = mkBody();
|
||||
|
||||
// throw engine first, then high-gain engine — the high-gain must still run
|
||||
const result = applyStackedCompression(
|
||||
body,
|
||||
pipeline(THROW_ENGINE_ID, HIGH_GAIN_ENGINE_ID),
|
||||
BAILOUT_ON
|
||||
);
|
||||
|
||||
// high-gain engine appends "|high"
|
||||
assert.equal(userContent(result), "hello|high");
|
||||
assert.equal(result.compressed, true);
|
||||
});
|
||||
|
||||
it("bail-out ON: low-gain engine (5%) → body NOT advanced (step skipped)", () => {
|
||||
const body = mkBody();
|
||||
|
||||
const result = applyStackedCompression(body, pipeline(LOW_GAIN_ENGINE_ID), BAILOUT_ON);
|
||||
|
||||
// low-gain would append "|low" but it should be skipped
|
||||
assert.equal(userContent(result), "hello");
|
||||
// compressed is false because the only step was skipped
|
||||
assert.equal(result.compressed, false);
|
||||
});
|
||||
|
||||
it("bail-out ON: high-gain engine (20%) → body IS advanced normally", () => {
|
||||
const body = mkBody();
|
||||
|
||||
const result = applyStackedCompression(body, pipeline(HIGH_GAIN_ENGINE_ID), BAILOUT_ON);
|
||||
|
||||
assert.equal(userContent(result), "hello|high");
|
||||
assert.equal(result.compressed, true);
|
||||
});
|
||||
|
||||
it("bail-out ON: low-gain then high-gain → only high-gain advances body", () => {
|
||||
const body = mkBody();
|
||||
|
||||
const result = applyStackedCompression(
|
||||
body,
|
||||
pipeline(LOW_GAIN_ENGINE_ID, HIGH_GAIN_ENGINE_ID),
|
||||
BAILOUT_ON
|
||||
);
|
||||
|
||||
// "|low" should be absent; "|high" should be present
|
||||
assert.equal(userContent(result), "hello|high");
|
||||
});
|
||||
|
||||
it("bail-out OFF (default): low-gain engine IS applied (opt-in guard)", () => {
|
||||
const body = mkBody();
|
||||
|
||||
// No bailout config at all — original behavior
|
||||
const result = applyStackedCompression(body, pipeline(LOW_GAIN_ENGINE_ID), BAILOUT_OFF);
|
||||
|
||||
// Without bail-out, the step is always applied
|
||||
assert.equal(userContent(result), "hello|low");
|
||||
assert.equal(result.compressed, true);
|
||||
});
|
||||
|
||||
it("bail-out OFF (default): throwing engine propagates — unchanged existing behavior", () => {
|
||||
const body = mkBody();
|
||||
|
||||
// Without bail-out, a throw is NOT caught → pipeline throws
|
||||
assert.throws(() => {
|
||||
applyStackedCompression(body, pipeline(THROW_ENGINE_ID), BAILOUT_OFF);
|
||||
}, /simulated engine failure/);
|
||||
});
|
||||
});
|
||||
|
||||
// ── ASYNC tests ───────────────────────────────────────────────────────────
|
||||
|
||||
describe("async — applyStackedCompressionAsync", () => {
|
||||
it("bail-out ON: async throwing engine → step skipped, no throw", async () => {
|
||||
const body = mkBody();
|
||||
|
||||
const result = await applyStackedCompressionAsync(body, pipeline(THROW_ASYNC_ID), BAILOUT_ON);
|
||||
|
||||
assert.equal(userContent(result), "hello");
|
||||
assert.equal(result.compressed, false);
|
||||
});
|
||||
|
||||
it("bail-out ON: async low-gain engine (5%) → step skipped", async () => {
|
||||
const body = mkBody();
|
||||
|
||||
const result = await applyStackedCompressionAsync(
|
||||
body,
|
||||
pipeline(LOW_GAIN_ASYNC_ID),
|
||||
BAILOUT_ON
|
||||
);
|
||||
|
||||
assert.equal(userContent(result), "hello");
|
||||
assert.equal(result.compressed, false);
|
||||
});
|
||||
|
||||
it("bail-out OFF (default): async low-gain engine IS applied", async () => {
|
||||
const body = mkBody();
|
||||
|
||||
const result = await applyStackedCompressionAsync(
|
||||
body,
|
||||
pipeline(LOW_GAIN_ASYNC_ID),
|
||||
BAILOUT_OFF
|
||||
);
|
||||
|
||||
assert.equal(userContent(result), "hello|low");
|
||||
assert.equal(result.compressed, true);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,174 @@
|
||||
import { describe, it, before } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
|
||||
import {
|
||||
BENCHMARK_CORPUS,
|
||||
engineToCompressFn,
|
||||
benchmarkEngines,
|
||||
compareReports,
|
||||
runBenchmarkGate,
|
||||
} from "../../../open-sse/services/compression/harness/benchmark.ts";
|
||||
|
||||
// ── RED/GREEN proof: all assertions here must hold once benchmark.ts exists ──
|
||||
|
||||
describe("benchmark — engineToCompressFn adapter", () => {
|
||||
it("returns a function for a known engine id", () => {
|
||||
const fn = engineToCompressFn("rtk");
|
||||
assert.equal(typeof fn, "function");
|
||||
});
|
||||
|
||||
it("compressFn returns a string for any text input", async () => {
|
||||
const fn = engineToCompressFn("rtk");
|
||||
const noisy =
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n".repeat(10) +
|
||||
"Unnecessary filler words that add no value whatsoever indeed actually.";
|
||||
const out = await fn(noisy);
|
||||
assert.equal(typeof out, "string");
|
||||
});
|
||||
|
||||
it("compressFn output is shorter or equal for clearly compressible prose", async () => {
|
||||
// A highly redundant input that caveman rules should shorten
|
||||
const fn = engineToCompressFn("caveman");
|
||||
const repetitive =
|
||||
"This is a very redundant message. This is a very redundant message.\n".repeat(8);
|
||||
const out = await fn(repetitive);
|
||||
// The adapter must return a string and it must not be longer than the input
|
||||
assert.ok(
|
||||
out.length <= repetitive.length,
|
||||
`expected shorter output, got ${out.length} vs ${repetitive.length}`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("benchmark — benchmarkEngines", () => {
|
||||
let reports: Awaited<ReturnType<typeof benchmarkEngines>>;
|
||||
|
||||
before(async () => {
|
||||
reports = await benchmarkEngines(BENCHMARK_CORPUS, ["rtk", "caveman", "headroom"]);
|
||||
});
|
||||
|
||||
it("returns one report per requested engine", () => {
|
||||
assert.deepEqual(Object.keys(reports).sort(), ["caveman", "headroom", "rtk"]);
|
||||
});
|
||||
|
||||
it("each report has a valid meanSavingsPercent (a number)", () => {
|
||||
for (const [engineId, report] of Object.entries(reports)) {
|
||||
assert.equal(
|
||||
typeof report.meanSavingsPercent,
|
||||
"number",
|
||||
`${engineId}: meanSavingsPercent must be a number`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it("each report has meanRetention in [0, 1]", () => {
|
||||
for (const [engineId, report] of Object.entries(reports)) {
|
||||
assert.ok(
|
||||
report.meanRetention >= 0 && report.meanRetention <= 1,
|
||||
`${engineId}: meanRetention ${report.meanRetention} must be in [0,1]`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it("each report has results for every corpus item", () => {
|
||||
for (const [engineId, report] of Object.entries(reports)) {
|
||||
assert.equal(
|
||||
report.results.length,
|
||||
BENCHMARK_CORPUS.length,
|
||||
`${engineId}: expected ${BENCHMARK_CORPUS.length} result(s), got ${report.results.length}`
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("benchmark — compareReports", () => {
|
||||
it("returns one summary row per engine", async () => {
|
||||
const reports = await benchmarkEngines(BENCHMARK_CORPUS, ["rtk", "caveman"]);
|
||||
const summary = compareReports(reports);
|
||||
assert.equal(summary.length, 2);
|
||||
for (const row of summary) {
|
||||
assert.ok("engine" in row);
|
||||
assert.ok("meanSavingsPercent" in row);
|
||||
assert.ok("meanRetention" in row);
|
||||
assert.ok("totalCompressedTokens" in row);
|
||||
}
|
||||
});
|
||||
|
||||
it("is sorted by meanSavingsPercent descending (best saver first)", async () => {
|
||||
const reports = await benchmarkEngines(BENCHMARK_CORPUS, ["rtk", "caveman"]);
|
||||
const summary = compareReports(reports);
|
||||
for (let i = 1; i < summary.length; i++) {
|
||||
assert.ok(
|
||||
summary[i - 1].meanSavingsPercent >= summary[i].meanSavingsPercent,
|
||||
`row ${i - 1} savings ${summary[i - 1].meanSavingsPercent} should be >= row ${i} savings ${summary[i].meanSavingsPercent}`
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("benchmark — runBenchmarkGate (N4)", () => {
|
||||
it("passes when baselines match current costs", async () => {
|
||||
const reports = await benchmarkEngines(BENCHMARK_CORPUS, ["rtk"]);
|
||||
// Baseline = exact current tokensPerTask → must pass
|
||||
const rtkReport = reports["rtk"];
|
||||
const baselines: Record<string, { tasks: Record<string, number> }> = {};
|
||||
const taskTotals: Record<string, { sum: number; count: number }> = {};
|
||||
for (const r of rtkReport.results) {
|
||||
const t = taskTotals[r.task] ?? { sum: 0, count: 0 };
|
||||
t.sum += r.compressedTokens;
|
||||
t.count += 1;
|
||||
taskTotals[r.task] = t;
|
||||
}
|
||||
baselines["rtk"] = {
|
||||
tasks: Object.fromEntries(
|
||||
Object.entries(taskTotals).map(([k, v]) => [k, Math.round(v.sum / v.count)])
|
||||
),
|
||||
};
|
||||
|
||||
const gateResults = runBenchmarkGate(reports, baselines);
|
||||
const rtkGate = gateResults.find((g) => g.engine === "rtk");
|
||||
assert.ok(rtkGate, "rtk gate result missing");
|
||||
assert.equal(rtkGate.gate.passed, true, "gate should pass when baseline matches current");
|
||||
});
|
||||
|
||||
it("fails (regression) when baseline is tighter than actual cost", async () => {
|
||||
const reports = await benchmarkEngines(BENCHMARK_CORPUS, ["rtk"]);
|
||||
// Set an impossibly tight baseline (1 token per task) → regression guaranteed
|
||||
const impossibleBaselines: Record<string, { tasks: Record<string, number> }> = {
|
||||
rtk: { tasks: { prose: 1, "tool-output": 1, json: 1 } },
|
||||
};
|
||||
const gateResults = runBenchmarkGate(reports, impossibleBaselines);
|
||||
const rtkGate = gateResults.find((g) => g.engine === "rtk");
|
||||
assert.ok(rtkGate, "rtk gate result missing");
|
||||
assert.equal(rtkGate.gate.passed, false, "gate should fail when baseline is impossibly tight");
|
||||
assert.ok(rtkGate.gate.regressions.length > 0, "regressions array must be non-empty");
|
||||
});
|
||||
});
|
||||
|
||||
describe("benchmark — reproducibility", () => {
|
||||
it("two runs on the same corpus yield identical meanSavingsPercent", async () => {
|
||||
const engines = ["rtk", "caveman"];
|
||||
// Run the two passes SEQUENTIALLY: this asserts determinism (same input → same
|
||||
// output), not concurrency-safety. Running them in parallel (Promise.all) shares the
|
||||
// engine singletons across both passes and races their internal state under load.
|
||||
const r1 = await benchmarkEngines(BENCHMARK_CORPUS, engines);
|
||||
const r2 = await benchmarkEngines(BENCHMARK_CORPUS, engines);
|
||||
for (const id of engines) {
|
||||
assert.equal(
|
||||
r1[id].meanSavingsPercent,
|
||||
r2[id].meanSavingsPercent,
|
||||
`${id}: non-deterministic meanSavingsPercent`
|
||||
);
|
||||
assert.equal(
|
||||
r1[id].meanRetention,
|
||||
r2[id].meanRetention,
|
||||
`${id}: non-deterministic meanRetention`
|
||||
);
|
||||
assert.equal(
|
||||
r1[id].totalCompressedTokens,
|
||||
r2[id].totalCompressedTokens,
|
||||
`${id}: non-deterministic totalCompressedTokens`
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,189 @@
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
|
||||
import { applyCompression } from "../../../open-sse/services/compression/strategySelector.ts";
|
||||
import { applyRtkCompression } from "../../../open-sse/services/compression/engines/rtk/index.ts";
|
||||
|
||||
describe("compression body adapter", () => {
|
||||
it("applies Caveman compression to OpenAI Responses input messages", () => {
|
||||
const body = {
|
||||
model: "gpt-5.5-codex",
|
||||
input: [
|
||||
{
|
||||
type: "message",
|
||||
role: "user",
|
||||
content: [
|
||||
{
|
||||
type: "input_text",
|
||||
text: "Please could you provide a detailed explanation of this implementation? Thank you so much for your help!",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: "function_call",
|
||||
call_id: "call_1",
|
||||
name: "read_file",
|
||||
arguments: "{}",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const result = applyCompression(body, "standard", {
|
||||
config: {
|
||||
enabled: true,
|
||||
defaultMode: "standard",
|
||||
autoTriggerTokens: 0,
|
||||
cacheMinutes: 5,
|
||||
preserveSystemPrompt: true,
|
||||
comboOverrides: {},
|
||||
cavemanConfig: {
|
||||
enabled: true,
|
||||
compressRoles: ["user"],
|
||||
skipRules: [],
|
||||
minMessageLength: 10,
|
||||
preservePatterns: [],
|
||||
intensity: "full",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
assert.equal(result.compressed, true);
|
||||
assert.ok(!("messages" in result.body), "Responses body must not leak synthetic messages");
|
||||
const input = result.body.input as typeof body.input;
|
||||
assert.equal(input[1], body.input[1], "non-message Responses items should be preserved");
|
||||
const text = input[0].content[0].text;
|
||||
assert.ok(!text.includes("Please could you"));
|
||||
assert.ok(!text.includes("Thank you so much"));
|
||||
assert.ok(text.includes("explain"));
|
||||
});
|
||||
|
||||
it("applies RTK compression to Responses function_call_output items", () => {
|
||||
const repeatedOutput = Array.from({ length: 20 }, () => "same noisy line").join("\n");
|
||||
const body = {
|
||||
input: [
|
||||
{
|
||||
type: "function_call_output",
|
||||
call_id: "call_1",
|
||||
output: repeatedOutput,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const result = applyRtkCompression(body);
|
||||
|
||||
assert.equal(result.compressed, true);
|
||||
assert.ok(!("messages" in result.body), "Responses body must not leak synthetic messages");
|
||||
const input = result.body.input as typeof body.input;
|
||||
assert.match(input[0].output, /\[rtk:dropped/);
|
||||
assert.equal(input[0].call_id, "call_1");
|
||||
});
|
||||
|
||||
it("restores compressed array output on Responses function_call_output items", () => {
|
||||
const repeatedOutput = Array.from({ length: 20 }, () => "same noisy line").join("\n");
|
||||
const body = {
|
||||
input: [
|
||||
{
|
||||
type: "function_call_output",
|
||||
call_id: "call_1",
|
||||
output: [{ type: "input_text", text: repeatedOutput }],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const result = applyRtkCompression(body);
|
||||
const input = result.body.input as typeof body.input;
|
||||
|
||||
assert.equal(result.compressed, true);
|
||||
assert.match(input[0].output[0].text, /\[rtk:dropped/);
|
||||
assert.ok(!("content" in input[0]), "function_call_output should keep canonical output field");
|
||||
});
|
||||
|
||||
it("restores adapted Responses bodies even when no compression is applied", () => {
|
||||
const body = {
|
||||
input: [
|
||||
{
|
||||
type: "message",
|
||||
role: "user",
|
||||
content: [{ type: "input_text", text: "short" }],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const result = applyCompression(body, "standard", {
|
||||
config: {
|
||||
enabled: true,
|
||||
defaultMode: "standard",
|
||||
autoTriggerTokens: 0,
|
||||
cacheMinutes: 5,
|
||||
preserveSystemPrompt: true,
|
||||
comboOverrides: {},
|
||||
cavemanConfig: {
|
||||
enabled: true,
|
||||
compressRoles: ["user"],
|
||||
skipRules: [],
|
||||
minMessageLength: 50,
|
||||
preservePatterns: [],
|
||||
intensity: "full",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
assert.equal(result.compressed, false);
|
||||
assert.ok(!("messages" in result.body));
|
||||
assert.deepEqual(result.body.input, body.input);
|
||||
});
|
||||
|
||||
it("does not misalign Responses input items if an engine removes a synthetic message", () => {
|
||||
const body = {
|
||||
input: [
|
||||
{ type: "message", role: "user", content: "duplicate" },
|
||||
{ type: "message", role: "user", content: "duplicate" },
|
||||
{ type: "message", role: "user", content: "unique" },
|
||||
],
|
||||
};
|
||||
|
||||
const result = applyCompression(body, "lite", {
|
||||
config: {
|
||||
enabled: true,
|
||||
defaultMode: "lite",
|
||||
autoTriggerTokens: 0,
|
||||
cacheMinutes: 5,
|
||||
preserveSystemPrompt: true,
|
||||
comboOverrides: {},
|
||||
},
|
||||
});
|
||||
|
||||
assert.equal(result.compressed, true);
|
||||
assert.deepEqual(result.body.input, body.input);
|
||||
});
|
||||
|
||||
it("compresses string Responses input without converting the request shape", () => {
|
||||
const body = {
|
||||
input:
|
||||
"Please could you provide a detailed explanation of this implementation? Thank you so much for your help!",
|
||||
};
|
||||
|
||||
const result = applyCompression(body, "standard", {
|
||||
config: {
|
||||
enabled: true,
|
||||
defaultMode: "standard",
|
||||
autoTriggerTokens: 0,
|
||||
cacheMinutes: 5,
|
||||
preserveSystemPrompt: true,
|
||||
comboOverrides: {},
|
||||
cavemanConfig: {
|
||||
enabled: true,
|
||||
compressRoles: ["user"],
|
||||
skipRules: [],
|
||||
minMessageLength: 10,
|
||||
preservePatterns: [],
|
||||
intensity: "full",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
assert.equal(result.compressed, true);
|
||||
assert.equal(typeof result.body.input, "string");
|
||||
assert.ok(!(result.body.input as string).includes("Please could you"));
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* T05/C5 — resolveCacheAwareConfig materializes the `preserveSystemPromptMode` enum
|
||||
* into the engine-facing `preserveSystemPrompt` boolean using the cache signal.
|
||||
* The legacy boolean behaviour is covered by strategySelector-cache-aware.test.ts /
|
||||
* compression-cache-guard-3955.test.ts (unchanged); this file covers the new enum.
|
||||
*/
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { resolveCacheAwareConfig } from "../../../open-sse/services/compression/cacheAwareConfig.ts";
|
||||
import type {
|
||||
CompressionConfig,
|
||||
PreserveSystemPromptMode,
|
||||
} from "../../../open-sse/services/compression/types.ts";
|
||||
|
||||
function cfg(overrides: Partial<CompressionConfig> = {}): CompressionConfig {
|
||||
return {
|
||||
enabled: true,
|
||||
defaultMode: "standard",
|
||||
autoTriggerTokens: 0,
|
||||
cacheMinutes: 5,
|
||||
preserveSystemPrompt: true,
|
||||
comboOverrides: {},
|
||||
...overrides,
|
||||
} as CompressionConfig;
|
||||
}
|
||||
|
||||
// A request whose prefix the upstream caches (anthropic + explicit cache_control).
|
||||
const CACHING_BODY = {
|
||||
messages: [{ role: "system", content: "x", cache_control: { type: "ephemeral" } }],
|
||||
};
|
||||
const CACHING_CTX = { provider: "anthropic", targetFormat: "claude" } as const;
|
||||
// google has no prompt caching → no cacheable prefix to protect.
|
||||
const NON_CACHING_BODY = { messages: [{ role: "system", content: "x" }] };
|
||||
const NON_CACHING_CTX = { provider: "google" } as const;
|
||||
|
||||
function resolved(mode: PreserveSystemPromptMode, caching: boolean): boolean {
|
||||
const out = resolveCacheAwareConfig(
|
||||
cfg({ preserveSystemPromptMode: mode, preserveSystemPrompt: true }),
|
||||
caching ? CACHING_BODY : NON_CACHING_BODY,
|
||||
caching ? CACHING_CTX : NON_CACHING_CTX
|
||||
);
|
||||
return out.preserveSystemPrompt;
|
||||
}
|
||||
|
||||
describe("T05/C5 preserveSystemPromptMode -> effective boolean", () => {
|
||||
it("always: preserves regardless of cache", () => {
|
||||
assert.equal(resolved("always", true), true);
|
||||
assert.equal(resolved("always", false), true);
|
||||
});
|
||||
|
||||
it("whenNoCache: preserves only when a cache is present", () => {
|
||||
assert.equal(resolved("whenNoCache", true), true);
|
||||
assert.equal(resolved("whenNoCache", false), false);
|
||||
});
|
||||
|
||||
it("never: compresses the system prompt even when it would break the prompt cache", () => {
|
||||
assert.equal(resolved("never", true), false);
|
||||
assert.equal(resolved("never", false), false);
|
||||
});
|
||||
|
||||
it("the explicit mode overrides a contradicting legacy boolean", () => {
|
||||
// mode=never wins even though the legacy boolean asks to preserve.
|
||||
const out = resolveCacheAwareConfig(
|
||||
cfg({ preserveSystemPromptMode: "never", preserveSystemPrompt: true }),
|
||||
CACHING_BODY,
|
||||
CACHING_CTX
|
||||
);
|
||||
assert.equal(out.preserveSystemPrompt, false);
|
||||
});
|
||||
|
||||
it("no body: honors the mode at its no-cache baseline", () => {
|
||||
assert.equal(
|
||||
resolveCacheAwareConfig(cfg({ preserveSystemPromptMode: "whenNoCache" })).preserveSystemPrompt,
|
||||
false
|
||||
);
|
||||
assert.equal(
|
||||
resolveCacheAwareConfig(cfg({ preserveSystemPromptMode: "always" })).preserveSystemPrompt,
|
||||
true
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,155 @@
|
||||
/**
|
||||
* Unit tests for open-sse/services/compression/cachingAware.ts
|
||||
*/
|
||||
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import {
|
||||
detectCachingContext,
|
||||
getCacheAwareStrategy,
|
||||
} from "../../../open-sse/services/compression/cachingAware.ts";
|
||||
|
||||
describe("detectCachingContext", () => {
|
||||
it("returns hasCacheControl=true when body has cache_control", () => {
|
||||
const ctx = detectCachingContext({ cache_control: { type: "ephemeral" } });
|
||||
assert.equal(ctx.hasCacheControl, true);
|
||||
});
|
||||
|
||||
it("returns hasCacheControl=false when body has no cache_control", () => {
|
||||
const ctx = detectCachingContext({ model: "anthropic/claude-3" });
|
||||
assert.equal(ctx.hasCacheControl, false);
|
||||
});
|
||||
|
||||
it("extracts anthropic provider from model string", () => {
|
||||
const ctx = detectCachingContext({ model: "anthropic/claude-3-sonnet" });
|
||||
assert.equal(ctx.provider, "anthropic");
|
||||
assert.equal(ctx.isCachingProvider, true);
|
||||
});
|
||||
|
||||
it("extracts openai provider from model string (automatic prefix caching, #3955)", () => {
|
||||
const ctx = detectCachingContext({ model: "openai/gpt-4o" });
|
||||
assert.equal(ctx.provider, "openai");
|
||||
// #3955 — OpenAI uses automatic prefix caching; it counts as a caching provider.
|
||||
assert.equal(ctx.isCachingProvider, true);
|
||||
});
|
||||
|
||||
it("extracts google provider from model string", () => {
|
||||
const ctx = detectCachingContext({ model: "google/gemini-pro" });
|
||||
assert.equal(ctx.provider, "google");
|
||||
assert.equal(ctx.isCachingProvider, false);
|
||||
});
|
||||
|
||||
it("keeps provider prefix and applies the shared caching policy", () => {
|
||||
const ctx = detectCachingContext({ model: "deepseek/deepseek-chat" });
|
||||
assert.equal(ctx.provider, "deepseek");
|
||||
assert.equal(ctx.isCachingProvider, true);
|
||||
});
|
||||
|
||||
it("handles null/undefined body gracefully", () => {
|
||||
const ctx = detectCachingContext(null);
|
||||
assert.equal(ctx.hasCacheControl, false);
|
||||
assert.equal(ctx.provider, null);
|
||||
assert.equal(ctx.isCachingProvider, false);
|
||||
});
|
||||
|
||||
it("handles empty object body", () => {
|
||||
const ctx = detectCachingContext({});
|
||||
assert.equal(ctx.hasCacheControl, false);
|
||||
assert.equal(ctx.provider, null);
|
||||
assert.equal(ctx.isCachingProvider, false);
|
||||
});
|
||||
|
||||
it("detects cache_control in Claude message content blocks", () => {
|
||||
const ctx = detectCachingContext(
|
||||
{
|
||||
messages: [
|
||||
{
|
||||
role: "user",
|
||||
content: [{ type: "text", text: "cached", cache_control: { type: "ephemeral" } }],
|
||||
},
|
||||
],
|
||||
},
|
||||
{ provider: "anthropic", targetFormat: "claude" }
|
||||
);
|
||||
|
||||
assert.equal(ctx.hasCacheControl, true);
|
||||
assert.equal(ctx.provider, "anthropic");
|
||||
assert.equal(ctx.targetFormat, "claude");
|
||||
assert.equal(ctx.isCachingProvider, true);
|
||||
});
|
||||
|
||||
it("detects cache_control in Claude tools", () => {
|
||||
const ctx = detectCachingContext(
|
||||
{
|
||||
tools: [{ name: "lookup", cache_control: { type: "ephemeral" } }],
|
||||
},
|
||||
{ provider: "qwen", targetFormat: "claude" }
|
||||
);
|
||||
|
||||
assert.equal(ctx.hasCacheControl, true);
|
||||
assert.equal(ctx.isCachingProvider, true);
|
||||
});
|
||||
|
||||
it("prefers explicit provider context over the body model prefix", () => {
|
||||
const ctx = detectCachingContext(
|
||||
{ model: "openai/gpt-4o", cache_control: { type: "ephemeral" } },
|
||||
{ provider: "anthropic", targetFormat: "claude", model: "claude-3-5-sonnet" }
|
||||
);
|
||||
|
||||
assert.equal(ctx.provider, "anthropic");
|
||||
assert.equal(ctx.isCachingProvider, true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("getCacheAwareStrategy", () => {
|
||||
it("downgrades aggressive to standard for caching provider with cache_control", () => {
|
||||
const ctx = { hasCacheControl: true, provider: "anthropic", isCachingProvider: true };
|
||||
const result = getCacheAwareStrategy("aggressive", ctx);
|
||||
assert.equal(result.strategy, "standard");
|
||||
assert.equal(result.skipSystemPrompt, true);
|
||||
assert.equal(result.deterministicOnly, true);
|
||||
});
|
||||
|
||||
it("downgrades ultra to standard for caching provider with cache_control", () => {
|
||||
const ctx = { hasCacheControl: true, provider: "openai", isCachingProvider: true };
|
||||
const result = getCacheAwareStrategy("ultra", ctx);
|
||||
assert.equal(result.strategy, "standard");
|
||||
assert.equal(result.skipSystemPrompt, true);
|
||||
assert.equal(result.deterministicOnly, true);
|
||||
});
|
||||
|
||||
it("keeps standard strategy unchanged for caching provider with cache_control", () => {
|
||||
const ctx = { hasCacheControl: true, provider: "anthropic", isCachingProvider: true };
|
||||
const result = getCacheAwareStrategy("standard", ctx);
|
||||
assert.equal(result.strategy, "standard");
|
||||
assert.equal(result.skipSystemPrompt, true);
|
||||
assert.equal(result.deterministicOnly, true);
|
||||
});
|
||||
|
||||
it("keeps strategy unchanged for non-caching provider", () => {
|
||||
const ctx = { hasCacheControl: true, provider: "deepseek", isCachingProvider: false };
|
||||
const result = getCacheAwareStrategy("aggressive", ctx);
|
||||
assert.equal(result.strategy, "aggressive");
|
||||
assert.equal(result.skipSystemPrompt, false);
|
||||
assert.equal(result.deterministicOnly, false);
|
||||
});
|
||||
|
||||
it("protects the prefix for a caching provider even WITHOUT cache_control (#3955)", () => {
|
||||
// #3955 — automatic prefix caching (OpenAI/Codex/Anthropic) sets no cache_control
|
||||
// markers, but the cacheable prefix must still be preserved. isCachingProvider alone
|
||||
// is sufficient to skip the system prompt and downgrade prefix-compressing modes.
|
||||
const ctx = { hasCacheControl: false, provider: "anthropic", isCachingProvider: true };
|
||||
const result = getCacheAwareStrategy("aggressive", ctx);
|
||||
assert.equal(result.strategy, "standard");
|
||||
assert.equal(result.skipSystemPrompt, true);
|
||||
assert.equal(result.deterministicOnly, true);
|
||||
});
|
||||
|
||||
it("returns none strategy unchanged", () => {
|
||||
const ctx = { hasCacheControl: false, provider: null, isCachingProvider: false };
|
||||
const result = getCacheAwareStrategy("none", ctx);
|
||||
assert.equal(result.strategy, "none");
|
||||
assert.equal(result.skipSystemPrompt, false);
|
||||
assert.equal(result.deterministicOnly, false);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,73 @@
|
||||
import { describe, it, beforeEach, afterEach, after } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import fs from "node:fs";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import type { CavemanConfig } from "../../../open-sse/services/compression/types.ts";
|
||||
|
||||
const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-caveman-db-"));
|
||||
const ORIGINAL_DATA_DIR = process.env.DATA_DIR;
|
||||
process.env.DATA_DIR = TEST_DATA_DIR;
|
||||
|
||||
const core = await import("../../../src/lib/db/core.ts");
|
||||
const { getCompressionSettings, updateCompressionSettings } =
|
||||
await import("../../../src/lib/db/compression.ts");
|
||||
|
||||
describe("compression DB module", () => {
|
||||
beforeEach(() => {
|
||||
core.resetDbInstance();
|
||||
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
|
||||
fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
core.resetDbInstance();
|
||||
});
|
||||
|
||||
after(() => {
|
||||
core.resetDbInstance();
|
||||
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
|
||||
if (ORIGINAL_DATA_DIR === undefined) {
|
||||
delete process.env.DATA_DIR;
|
||||
} else {
|
||||
process.env.DATA_DIR = ORIGINAL_DATA_DIR;
|
||||
}
|
||||
});
|
||||
|
||||
it("should return default config", async () => {
|
||||
const config = await getCompressionSettings();
|
||||
assert.equal(config.defaultMode, "off");
|
||||
assert.equal(config.enabled, false);
|
||||
assert.equal(config.autoTriggerTokens, 0);
|
||||
assert.equal(config.cacheMinutes, 5);
|
||||
assert.equal(config.preserveSystemPrompt, true);
|
||||
assert.ok(config.cavemanConfig);
|
||||
assert.equal(config.cavemanConfig.enabled, true);
|
||||
assert.deepEqual(config.cavemanConfig.compressRoles, ["user"]);
|
||||
assert.equal(config.cavemanConfig.minMessageLength, 50);
|
||||
});
|
||||
|
||||
it("should update and retrieve settings", async () => {
|
||||
await updateCompressionSettings({ enabled: true, defaultMode: "standard" });
|
||||
const config = await getCompressionSettings();
|
||||
assert.equal(config.enabled, true);
|
||||
assert.equal(config.defaultMode, "standard");
|
||||
|
||||
await updateCompressionSettings({ enabled: false, defaultMode: "off" });
|
||||
const reset = await getCompressionSettings();
|
||||
assert.equal(reset.enabled, false);
|
||||
assert.equal(reset.defaultMode, "off");
|
||||
});
|
||||
|
||||
it("should update cavemanConfig", async () => {
|
||||
const customConfig: Partial<CavemanConfig> = {
|
||||
enabled: true,
|
||||
compressRoles: ["user", "system"],
|
||||
minMessageLength: 100,
|
||||
};
|
||||
await updateCompressionSettings({ cavemanConfig: customConfig as CavemanConfig });
|
||||
const config = await getCompressionSettings();
|
||||
assert.deepEqual(config.cavemanConfig?.compressRoles, ["user", "system"]);
|
||||
assert.equal(config.cavemanConfig?.minMessageLength, 100);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,88 @@
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { getRulesForContext } from "../../../open-sse/services/compression/cavemanRules.ts";
|
||||
import { applyRulesToText } from "../../../open-sse/services/compression/caveman.ts";
|
||||
import { cavemanCompress } from "../../../open-sse/services/compression/caveman.ts";
|
||||
|
||||
describe("multi-turn dedup rules", () => {
|
||||
it("should replace repeated context references", () => {
|
||||
const rules = getRulesForContext("all").filter((r) => r.name === "repeated_context");
|
||||
assert.ok(rules.length > 0);
|
||||
const { text } = applyRulesToText("As we discussed earlier, this needs fixing", rules);
|
||||
assert.ok(text.includes("See above"));
|
||||
});
|
||||
|
||||
it("should replace repeated questions", () => {
|
||||
const rules = getRulesForContext("user").filter((r) => r.name === "repeated_question");
|
||||
assert.ok(rules.length > 0);
|
||||
const { text } = applyRulesToText("Same question as before about the API", rules);
|
||||
assert.ok(text.includes("[same question]"));
|
||||
});
|
||||
|
||||
it("should shorten reestablished context", () => {
|
||||
const rules = getRulesForContext("all").filter((r) => r.name === "reestablished_context");
|
||||
assert.ok(rules.length > 0);
|
||||
const { text } = applyRulesToText("Going back to the code above, I need help", rules);
|
||||
assert.ok(text.includes("Re:"));
|
||||
});
|
||||
|
||||
it("should replace summaries with 'Summary:'", () => {
|
||||
const rules = getRulesForContext("assistant").filter((r) => r.name === "summary_replacement");
|
||||
assert.ok(rules.length > 0);
|
||||
const { text } = applyRulesToText(
|
||||
"To summarize what we've discussed, here are the key points:",
|
||||
rules
|
||||
);
|
||||
assert.ok(text.includes("Summary:"));
|
||||
});
|
||||
|
||||
it("should handle multi-message scenarios", () => {
|
||||
const body = {
|
||||
messages: [
|
||||
{
|
||||
role: "user",
|
||||
content:
|
||||
"Please help me fix this TypeScript error: TypeError: Cannot read property of undefined",
|
||||
},
|
||||
{
|
||||
role: "assistant",
|
||||
content:
|
||||
"The error indicates you're trying to access a property on a null or undefined value. You should add a null check.",
|
||||
},
|
||||
{
|
||||
role: "user",
|
||||
content:
|
||||
"As we discussed earlier, I tried adding null checks but the error persists. Could you please provide a more detailed explanation of what might be causing this?",
|
||||
},
|
||||
],
|
||||
};
|
||||
const result = cavemanCompress(body, {
|
||||
enabled: true,
|
||||
compressRoles: ["user", "assistant"],
|
||||
skipRules: [],
|
||||
minMessageLength: 50,
|
||||
preservePatterns: [],
|
||||
});
|
||||
assert.equal(result.compressed, true);
|
||||
assert.ok(result.stats.rulesApplied && result.stats.rulesApplied.length > 0);
|
||||
});
|
||||
|
||||
it("should NOT dedupe unique content", () => {
|
||||
const body = {
|
||||
messages: [
|
||||
{ role: "user", content: "How do I implement OAuth 2.0 in my Express application?" },
|
||||
{ role: "assistant", content: "You can use the passport library with the OAuth2Strategy." },
|
||||
{ role: "user", content: "What about implementing rate limiting for the API endpoints?" },
|
||||
],
|
||||
};
|
||||
const result = cavemanCompress(body, {
|
||||
enabled: true,
|
||||
compressRoles: ["user"],
|
||||
skipRules: [],
|
||||
minMessageLength: 50,
|
||||
preservePatterns: [],
|
||||
});
|
||||
const lastUserMsg = result.body.messages[2].content as string;
|
||||
assert.ok(lastUserMsg.includes("rate limiting"), "Unique content should be preserved");
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,262 @@
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import {
|
||||
cavemanCompress,
|
||||
applyRulesToText,
|
||||
} from "../../../open-sse/services/compression/caveman.ts";
|
||||
import { CAVEMAN_RULES } from "../../../open-sse/services/compression/cavemanRules.ts";
|
||||
import type { CavemanRule } from "../../../open-sse/services/compression/types.ts";
|
||||
|
||||
describe("caveman engine", () => {
|
||||
it("should compress a verbose user prompt", () => {
|
||||
const body = {
|
||||
messages: [
|
||||
{
|
||||
role: "user",
|
||||
content:
|
||||
"Please could you help me analyze this code? I would like you to provide a detailed explanation of what the function does. Thank you so much for your help!",
|
||||
},
|
||||
],
|
||||
};
|
||||
const result = cavemanCompress(body, {
|
||||
enabled: true,
|
||||
compressRoles: ["user"],
|
||||
skipRules: [],
|
||||
minMessageLength: 50,
|
||||
preservePatterns: [],
|
||||
});
|
||||
assert.equal(result.compressed, true);
|
||||
assert.ok(
|
||||
result.stats.savingsPercent > 0,
|
||||
`Expected savings > 0, got ${result.stats.savingsPercent}`
|
||||
);
|
||||
assert.ok(
|
||||
result.stats.rulesApplied && result.stats.rulesApplied.length > 0,
|
||||
"Expected rules applied"
|
||||
);
|
||||
});
|
||||
|
||||
it("should skip messages below minMessageLength", () => {
|
||||
const body = { messages: [{ role: "user", content: "Hi" }] };
|
||||
const result = cavemanCompress(body, {
|
||||
enabled: true,
|
||||
compressRoles: ["user"],
|
||||
skipRules: [],
|
||||
minMessageLength: 50,
|
||||
preservePatterns: [],
|
||||
});
|
||||
assert.equal(result.compressed, false);
|
||||
});
|
||||
|
||||
it("should return unchanged body when disabled", () => {
|
||||
const body = { messages: [{ role: "user", content: "Please help me with this code" }] };
|
||||
const result = cavemanCompress(body, {
|
||||
enabled: false,
|
||||
compressRoles: ["user"],
|
||||
skipRules: [],
|
||||
minMessageLength: 50,
|
||||
preservePatterns: [],
|
||||
});
|
||||
assert.equal(result.compressed, false);
|
||||
});
|
||||
|
||||
it("should preserve code blocks", () => {
|
||||
const codeContent = "const x = 42;\nconsole.log(x);";
|
||||
const body = {
|
||||
messages: [
|
||||
{
|
||||
role: "user",
|
||||
content: `Please analyze this code:\n\`\`\`typescript\n${codeContent}\n\`\`\`\nThank you so much!`,
|
||||
},
|
||||
],
|
||||
};
|
||||
const result = cavemanCompress(body, {
|
||||
enabled: true,
|
||||
compressRoles: ["user"],
|
||||
skipRules: [],
|
||||
minMessageLength: 50,
|
||||
preservePatterns: [],
|
||||
});
|
||||
const text = result.body.messages[0].content as string;
|
||||
assert.ok(text.includes(codeContent), `Code block should be preserved exactly`);
|
||||
});
|
||||
|
||||
it("should preserve URLs", () => {
|
||||
const url = "https://example.com/api/v1/users";
|
||||
const body = {
|
||||
messages: [
|
||||
{
|
||||
role: "user",
|
||||
content: `Please check ${url} for the API docs. Thank you so much!`,
|
||||
},
|
||||
],
|
||||
};
|
||||
const result = cavemanCompress(body, {
|
||||
enabled: true,
|
||||
compressRoles: ["user"],
|
||||
skipRules: [],
|
||||
minMessageLength: 50,
|
||||
preservePatterns: [],
|
||||
});
|
||||
const text = result.body.messages[0].content as string;
|
||||
assert.equal(
|
||||
text.split(/\s+/).some((token) => token === url),
|
||||
true,
|
||||
`URL should be preserved`
|
||||
);
|
||||
});
|
||||
|
||||
it("should handle empty messages array", () => {
|
||||
const body = { messages: [] };
|
||||
const result = cavemanCompress(body, {
|
||||
enabled: true,
|
||||
compressRoles: ["user"],
|
||||
skipRules: [],
|
||||
minMessageLength: 50,
|
||||
preservePatterns: [],
|
||||
});
|
||||
assert.equal(result.compressed, false);
|
||||
});
|
||||
|
||||
it("should handle messages without content", () => {
|
||||
const body = { messages: [{ role: "user" }] };
|
||||
const result = cavemanCompress(body, {
|
||||
enabled: true,
|
||||
compressRoles: ["user"],
|
||||
skipRules: [],
|
||||
minMessageLength: 50,
|
||||
preservePatterns: [],
|
||||
});
|
||||
assert.equal(result.compressed, false);
|
||||
});
|
||||
|
||||
it("should skip rules in skipRules list", () => {
|
||||
const body = {
|
||||
messages: [{ role: "user", content: "Please help me with this code. Thank you so much!" }],
|
||||
};
|
||||
const resultWithSkip = cavemanCompress(body, {
|
||||
enabled: true,
|
||||
compressRoles: ["user"],
|
||||
skipRules: ["polite_framing"],
|
||||
minMessageLength: 50,
|
||||
preservePatterns: [],
|
||||
});
|
||||
assert.ok(
|
||||
!resultWithSkip.stats.rulesApplied?.includes("polite_framing"),
|
||||
"polite_framing should be skipped"
|
||||
);
|
||||
});
|
||||
|
||||
it("should respect compressRoles setting", () => {
|
||||
const body = {
|
||||
messages: [
|
||||
{
|
||||
role: "system",
|
||||
content:
|
||||
"You are a very helpful assistant. Please be extremely detailed in all your responses.",
|
||||
},
|
||||
{
|
||||
role: "user",
|
||||
content:
|
||||
"Please could you help me with this code problem? I would like you to provide a detailed explanation. Thank you so much!",
|
||||
},
|
||||
],
|
||||
};
|
||||
const result = cavemanCompress(body, {
|
||||
enabled: true,
|
||||
compressRoles: ["user"],
|
||||
skipRules: [],
|
||||
minMessageLength: 50,
|
||||
preservePatterns: [],
|
||||
});
|
||||
const systemMsg = result.body.messages[0].content as string;
|
||||
const userMsg = result.body.messages[1].content as string;
|
||||
assert.ok(
|
||||
systemMsg.includes("very"),
|
||||
"System message should not be compressed (not in compressRoles)"
|
||||
);
|
||||
assert.ok(
|
||||
!userMsg.includes("Please could you"),
|
||||
"User message should have 'Please could you' removed"
|
||||
);
|
||||
assert.ok(
|
||||
!userMsg.includes("Thank you so much"),
|
||||
"User message should have 'Thank you so much' removed"
|
||||
);
|
||||
});
|
||||
|
||||
it("should compute stats accurately", () => {
|
||||
const body = {
|
||||
messages: [
|
||||
{ role: "user", content: "Please could you help me with this problem? Thank you so much!" },
|
||||
],
|
||||
};
|
||||
const result = cavemanCompress(body, {
|
||||
enabled: true,
|
||||
compressRoles: ["user"],
|
||||
skipRules: [],
|
||||
minMessageLength: 50,
|
||||
preservePatterns: [],
|
||||
});
|
||||
assert.ok(result.stats.originalTokens > 0);
|
||||
assert.ok(result.stats.compressedTokens >= 0);
|
||||
assert.ok(result.stats.savingsPercent >= 0);
|
||||
assert.ok(result.stats.durationMs >= 0);
|
||||
assert.ok(
|
||||
// Loose catastrophic budget (see the 10K-token test below for rationale).
|
||||
result.stats.durationMs < 500,
|
||||
`Duration ${result.stats.durationMs}ms should stay under the 500ms catastrophic budget`
|
||||
);
|
||||
});
|
||||
|
||||
it("applyRulesToText should track applied rules", () => {
|
||||
const { text, appliedRules } = applyRulesToText(
|
||||
"Please help me",
|
||||
CAVEMAN_RULES.filter((r) => r.context === "all" || r.context === "user")
|
||||
);
|
||||
assert.ok(appliedRules.length > 0, "Should track applied rules");
|
||||
assert.ok(appliedRules.includes("polite_framing"), "polite_framing should be in applied rules");
|
||||
});
|
||||
|
||||
it("should complete in under 5ms for 10K token messages", () => {
|
||||
const longContent = "Please help me analyze this code. ".repeat(1000);
|
||||
const body = { messages: [{ role: "user", content: longContent }] };
|
||||
const result = cavemanCompress(body, {
|
||||
enabled: true,
|
||||
compressRoles: ["user"],
|
||||
skipRules: [],
|
||||
minMessageLength: 50,
|
||||
preservePatterns: [],
|
||||
});
|
||||
// Catastrophic-regression budget, not a benchmark: under a saturated full
|
||||
// suite (concurrency 20) this measured 175ms on a healthy engine — absolute
|
||||
// wall-clock asserts flake under load (re-wired by 6A.1c, 2026-06-09).
|
||||
// Real perf tracking belongs in tests/benchmarks/.
|
||||
assert.ok(result.stats.durationMs < 500, `Expected <500ms, got ${result.stats.durationMs}ms`);
|
||||
});
|
||||
|
||||
it("cleans whitespace and punctuation artifacts without regex backtracking", () => {
|
||||
const body = {
|
||||
messages: [
|
||||
{
|
||||
role: "user",
|
||||
content: "\n\nPlease\t make sure to keep this stable !!! \n\n\n\nThank you.",
|
||||
},
|
||||
],
|
||||
};
|
||||
const result = cavemanCompress(body, {
|
||||
enabled: true,
|
||||
compressRoles: ["user"],
|
||||
skipRules: [],
|
||||
minMessageLength: 0,
|
||||
preservePatterns: [],
|
||||
});
|
||||
const text = result.body.messages[0].content as string;
|
||||
|
||||
assert.doesNotMatch(text, /^\n/);
|
||||
assert.doesNotMatch(text, /\n$/);
|
||||
assert.doesNotMatch(text, /\n\n\n/);
|
||||
assert.doesNotMatch(text, /[ \t]+[,.!?;:]/);
|
||||
assert.doesNotMatch(text, /[ \t]{2,}/);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,67 @@
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { getRulesForContext } from "../../../open-sse/services/compression/cavemanRules.ts";
|
||||
import { applyRulesToText } from "../../../open-sse/services/compression/caveman.ts";
|
||||
|
||||
describe("hedging and context condensation rules", () => {
|
||||
it("should remove hedging phrases", () => {
|
||||
const rules = getRulesForContext("all").filter((r) => r.name === "hedging");
|
||||
assert.ok(rules.length > 0);
|
||||
const { text } = applyRulesToText("It seems like this function is working correctly", rules);
|
||||
assert.ok(!text.toLowerCase().includes("it seems like"));
|
||||
});
|
||||
|
||||
it("should convert explanatory prefix to shorter form", () => {
|
||||
const rules = getRulesForContext("all").filter((r) => r.name === "explanatory_prefix");
|
||||
assert.ok(rules.length > 0);
|
||||
const { text } = applyRulesToText(
|
||||
"The function appears to be handling the data processing",
|
||||
rules
|
||||
);
|
||||
assert.ok(text.includes("Function:"));
|
||||
});
|
||||
|
||||
it("should convert questions to directives", () => {
|
||||
const rules = getRulesForContext("user").filter((r) => r.name === "question_to_directive");
|
||||
assert.ok(rules.length > 0);
|
||||
const { text } = applyRulesToText("Can you explain why this error occurs?", rules);
|
||||
assert.ok(text.includes("Explain why"), `Expected 'Explain why' in output, got: ${text}`);
|
||||
});
|
||||
|
||||
it("should convert context setup phrases", () => {
|
||||
const rules = getRulesForContext("user").filter((r) => r.name === "context_setup");
|
||||
assert.ok(rules.length > 0);
|
||||
const { text } = applyRulesToText("I have the following code for review:", rules);
|
||||
assert.ok(text.includes("Code:"));
|
||||
});
|
||||
|
||||
it("should convert intent clarification to Goal:", () => {
|
||||
const rules = getRulesForContext("user").filter((r) => r.name === "intent_clarification");
|
||||
assert.ok(rules.length > 0);
|
||||
const { text } = applyRulesToText("What I'm trying to do is fix the authentication bug", rules);
|
||||
assert.ok(text.startsWith("Goal:"));
|
||||
});
|
||||
|
||||
it("should remove background phrases", () => {
|
||||
const rules = getRulesForContext("all").filter((r) => r.name === "background_removal");
|
||||
assert.ok(rules.length > 0);
|
||||
const { text } = applyRulesToText("As you may know, this is important", rules);
|
||||
assert.ok(!text.toLowerCase().includes("as you may know"));
|
||||
});
|
||||
|
||||
it("should convert purpose statements", () => {
|
||||
const rules = getRulesForContext("all").filter((r) => r.name === "purpose_statement");
|
||||
assert.ok(rules.length > 0);
|
||||
const { text } = applyRulesToText("for the purpose of testing", rules);
|
||||
assert.ok(text.includes("for testing"));
|
||||
assert.ok(!text.includes("purpose"));
|
||||
});
|
||||
|
||||
it("should preserve meaning — key terms not removed", () => {
|
||||
const allRules = getRulesForContext("all");
|
||||
const { text } = applyRulesToText("Fix the authentication error in the login module", allRules);
|
||||
assert.ok(text.includes("authentication"), "Key term 'authentication' should be preserved");
|
||||
assert.ok(text.includes("error"), "Key term 'error' should be preserved");
|
||||
assert.ok(text.includes("login"), "Key term 'login' should be preserved");
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,69 @@
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import {
|
||||
extractPreservedBlocks,
|
||||
restorePreservedBlocks,
|
||||
shouldPreserve,
|
||||
} from "../../../open-sse/services/compression/preservation.ts";
|
||||
|
||||
describe("preservation", () => {
|
||||
it("should extract and restore code blocks", () => {
|
||||
const code = "const x = 42;\nconsole.log(x);";
|
||||
const text = `Please fix this:\n\`\`\`js\n${code}\n\`\`\`\nThanks!`;
|
||||
const { text: extracted, blocks } = extractPreservedBlocks(text);
|
||||
assert.ok(!extracted.includes(code), "Code should be replaced with placeholder");
|
||||
assert.ok(blocks.length > 0, "Should have preserved blocks");
|
||||
const restored = restorePreservedBlocks(extracted, blocks);
|
||||
assert.equal(restored, text, "Should restore to original");
|
||||
});
|
||||
|
||||
it("should preserve URLs", () => {
|
||||
const url = "https://example.com/api/v1/users";
|
||||
const text = `Check ${url} please`;
|
||||
const { text: extracted, blocks } = extractPreservedBlocks(text);
|
||||
const restored = restorePreservedBlocks(extracted, blocks);
|
||||
assert.equal(restored, text, "URL should be preserved");
|
||||
});
|
||||
|
||||
it("should preserve file paths", () => {
|
||||
const path = "/src/utils/helper.ts";
|
||||
const text = `Fix the file ${path} please`;
|
||||
const { text: extracted, blocks } = extractPreservedBlocks(text);
|
||||
const restored = restorePreservedBlocks(extracted, blocks);
|
||||
assert.ok(restored.includes(path), "Path should be preserved");
|
||||
});
|
||||
|
||||
it("should preserve error messages", () => {
|
||||
const text = "I got TypeError: Cannot read property of undefined";
|
||||
const { blocks } = extractPreservedBlocks(text);
|
||||
assert.ok(
|
||||
blocks.some((b) => b.content.includes("TypeError")),
|
||||
"Error should be preserved"
|
||||
);
|
||||
});
|
||||
|
||||
it("shouldPreserve matches user patterns", () => {
|
||||
assert.ok(shouldPreserve("my-secret-key", [/secret/i]));
|
||||
assert.ok(!shouldPreserve("hello world", [/secret/i]));
|
||||
});
|
||||
|
||||
it("should handle nested code blocks and URLs", () => {
|
||||
const text = "See https://docs.example.com for:\n```\nfetch('https://api.example.com')\n```";
|
||||
const { text: extracted, blocks } = extractPreservedBlocks(text);
|
||||
const restored = restorePreservedBlocks(extracted, blocks);
|
||||
assert.equal(restored, text);
|
||||
});
|
||||
|
||||
it("should handle empty text", () => {
|
||||
const { text, blocks } = extractPreservedBlocks("");
|
||||
assert.equal(text, "");
|
||||
assert.equal(blocks.length, 0);
|
||||
});
|
||||
|
||||
it("should handle text with nothing to preserve", () => {
|
||||
const text = "Just regular text here";
|
||||
const { text: extracted, blocks } = extractPreservedBlocks(text);
|
||||
assert.equal(blocks.length, 0);
|
||||
assert.equal(extracted, text);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,165 @@
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import {
|
||||
CAVEMAN_RULES,
|
||||
getRulesForContext,
|
||||
getRuleByName,
|
||||
} from "../../../open-sse/services/compression/cavemanRules.ts";
|
||||
|
||||
describe("cavemanRules", () => {
|
||||
it("should have 29+ rules", () => {
|
||||
assert.ok(CAVEMAN_RULES.length >= 29, `Expected 29+ rules, got ${CAVEMAN_RULES.length}`);
|
||||
});
|
||||
|
||||
it("every rule should have a name, pattern, replacement, and context", () => {
|
||||
for (const rule of CAVEMAN_RULES) {
|
||||
assert.ok(rule.name, "Rule missing name");
|
||||
assert.ok(rule.pattern instanceof RegExp, `Rule ${rule.name} missing pattern`);
|
||||
assert.ok(rule.replacement !== undefined, `Rule ${rule.name} missing replacement`);
|
||||
assert.ok(
|
||||
["all", "user", "system", "assistant"].includes(rule.context),
|
||||
`Rule ${rule.name} has invalid context: ${rule.context}`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it("all regex patterns should compile", () => {
|
||||
for (const rule of CAVEMAN_RULES) {
|
||||
assert.doesNotThrow(() => rule.pattern.test("test"), `Rule ${rule.name} pattern fails`);
|
||||
}
|
||||
});
|
||||
|
||||
it("getRulesForContext filters correctly", () => {
|
||||
const userRules = getRulesForContext("user");
|
||||
const systemRules = getRulesForContext("system");
|
||||
const assistantRules = getRulesForContext("assistant");
|
||||
|
||||
assert.ok(userRules.length >= 20, `Expected 20+ user rules, got ${userRules.length}`);
|
||||
assert.ok(systemRules.length >= 15, `Expected 15+ system rules, got ${systemRules.length}`);
|
||||
assert.ok(
|
||||
assistantRules.length >= 15,
|
||||
`Expected 15+ assistant rules, got ${assistantRules.length}`
|
||||
);
|
||||
|
||||
for (const rule of userRules) {
|
||||
assert.ok(
|
||||
rule.context === "all" || rule.context === "user",
|
||||
`User rules should include ${rule.name}`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it("getRuleByName returns correct rule", () => {
|
||||
const rule = getRuleByName("polite_framing");
|
||||
assert.ok(rule);
|
||||
assert.equal(rule.name, "polite_framing");
|
||||
|
||||
const missing = getRuleByName("nonexistent_rule");
|
||||
assert.equal(missing, undefined);
|
||||
});
|
||||
|
||||
it("polite_framing removes 'please'", () => {
|
||||
const rule = getRuleByName("polite_framing");
|
||||
assert.ok(rule);
|
||||
const result = "Please analyze this code".replace(rule.pattern, rule.replacement);
|
||||
assert.ok(
|
||||
!result.toLowerCase().includes("please"),
|
||||
`Expected 'please' removed, got: ${result}`
|
||||
);
|
||||
});
|
||||
|
||||
it("hedging removes 'it seems like'", () => {
|
||||
const rule = getRuleByName("hedging");
|
||||
assert.ok(rule);
|
||||
const result = "It seems like this works".replace(rule.pattern, rule.replacement);
|
||||
assert.ok(
|
||||
!result.toLowerCase().includes("it seems like"),
|
||||
`Expected hedging removed, got: ${result}`
|
||||
);
|
||||
});
|
||||
|
||||
it("verbose_instructions compresses", () => {
|
||||
const rule = getRuleByName("verbose_instructions");
|
||||
assert.ok(rule);
|
||||
const result = "provide a detailed explanation".replace(
|
||||
rule.pattern,
|
||||
typeof rule.replacement === "function"
|
||||
? (...args: string[]) => rule.replacement(args[0], ...args.slice(1))
|
||||
: rule.replacement
|
||||
);
|
||||
assert.ok(result.includes("provide"), `Expected 'provide', got: ${result}`);
|
||||
assert.ok(!result.includes("detailed"), `Expected 'detailed' removed, got: ${result}`);
|
||||
});
|
||||
|
||||
it("filler_adverbs removes 'basically'", () => {
|
||||
const rule = getRuleByName("filler_adverbs");
|
||||
assert.ok(rule);
|
||||
const result = "This is basically a test".replace(rule.pattern, rule.replacement);
|
||||
assert.ok(
|
||||
!result.toLowerCase().includes("basically"),
|
||||
`Expected 'basically' removed, got: ${result}`
|
||||
);
|
||||
});
|
||||
|
||||
it("excessive_gratitude removes 'Thank you so much'", () => {
|
||||
const rule = getRuleByName("excessive_gratitude");
|
||||
assert.ok(rule);
|
||||
const result = "Thank you so much for your help!".replace(rule.pattern, rule.replacement);
|
||||
assert.ok(
|
||||
!result.toLowerCase().includes("thank you so much"),
|
||||
`Expected gratitude removed, got: ${result}`
|
||||
);
|
||||
});
|
||||
|
||||
it("context_setup converts 'Here is my code' to 'Code:'", () => {
|
||||
const rule = getRuleByName("context_setup");
|
||||
assert.ok(rule);
|
||||
const result = "Here is my code for review:".replace(rule.pattern, rule.replacement);
|
||||
assert.ok(result.includes("Code:"), `Expected 'Code:', got: ${result}`);
|
||||
});
|
||||
|
||||
it("intent_clarification converts intent to 'Goal:'", () => {
|
||||
const rule = getRuleByName("intent_clarification");
|
||||
assert.ok(rule);
|
||||
const result = "What I'm trying to do is fix the bug".replace(rule.pattern, rule.replacement);
|
||||
assert.ok(result.startsWith("Goal:"), `Expected 'Goal:', got: ${result}`);
|
||||
});
|
||||
|
||||
it("purpose_phrases converts 'in order to' to 'to'", () => {
|
||||
const rule = getRuleByName("purpose_phrases");
|
||||
assert.ok(rule);
|
||||
const result = "in order to fix this".replace(rule.pattern, rule.replacement);
|
||||
assert.ok(result.startsWith("to "), `Expected 'to ', got: ${result}`);
|
||||
assert.ok(!result.includes("in order"), `Expected 'in order' removed, got: ${result}`);
|
||||
});
|
||||
|
||||
it("passive_voice converts 'is being used' to 'uses'", () => {
|
||||
const rule = getRuleByName("passive_voice");
|
||||
assert.ok(rule);
|
||||
const result = "The function is being used".replace(
|
||||
rule.pattern,
|
||||
typeof rule.replacement === "function"
|
||||
? (...args: string[]) => rule.replacement(args[0])
|
||||
: rule.replacement
|
||||
);
|
||||
assert.ok(result.includes("uses"), `Expected 'uses', got: ${result}`);
|
||||
});
|
||||
|
||||
it("repeated_context converts to 'See above'", () => {
|
||||
const rule = getRuleByName("repeated_context");
|
||||
assert.ok(rule);
|
||||
const result = "As we discussed earlier, this needs fixing".replace(
|
||||
rule.pattern,
|
||||
rule.replacement
|
||||
);
|
||||
assert.ok(result.includes("See above"), `Expected 'See above', got: ${result}`);
|
||||
});
|
||||
|
||||
it("emphasis_removal removes 'very' before adjectives", () => {
|
||||
const rule = getRuleByName("emphasis_removal");
|
||||
assert.ok(rule);
|
||||
const result = "This is very important".replace(rule.pattern, rule.replacement);
|
||||
assert.ok(!result.includes("very"), `Expected 'very' removed, got: ${result}`);
|
||||
assert.ok(result.includes("important"), `Expected 'important' kept, got: ${result}`);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,75 @@
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { getRulesForContext } from "../../../open-sse/services/compression/cavemanRules.ts";
|
||||
import { applyRulesToText } from "../../../open-sse/services/compression/caveman.ts";
|
||||
import { cavemanCompress } from "../../../open-sse/services/compression/caveman.ts";
|
||||
|
||||
describe("structural compression rules", () => {
|
||||
it("should simplify list conjunctions", () => {
|
||||
const rules = getRulesForContext("all").filter((r) => r.name === "list_conjunction");
|
||||
assert.ok(rules.length > 0);
|
||||
const { text } = applyRulesToText("handles routing, and also load balancing", rules);
|
||||
assert.ok(!text.includes("and also"));
|
||||
});
|
||||
|
||||
it("should simplify purpose phrases", () => {
|
||||
const rules = getRulesForContext("all").filter((r) => r.name === "purpose_phrases");
|
||||
assert.ok(rules.length > 0);
|
||||
const { text } = applyRulesToText("in order to fix this bug", rules);
|
||||
assert.ok(text.startsWith("to "));
|
||||
});
|
||||
|
||||
it("should simplify redundant quantifiers", () => {
|
||||
const rules = getRulesForContext("all").filter((r) => r.name === "redundant_quantifiers");
|
||||
assert.ok(rules.length > 0);
|
||||
const { text } = applyRulesToText("each and every item", rules);
|
||||
assert.ok(text.includes("each"));
|
||||
assert.ok(!text.includes("every"));
|
||||
});
|
||||
|
||||
it("should replace verbose connectors with 'also'", () => {
|
||||
const rules = getRulesForContext("all").filter((r) => r.name === "verbose_connectors");
|
||||
assert.ok(rules.length > 0);
|
||||
const { text } = applyRulesToText("furthermore, this handles caching", rules);
|
||||
assert.ok(text.startsWith("also"));
|
||||
});
|
||||
|
||||
it("should remove emphasis adverbs", () => {
|
||||
const rules = getRulesForContext("all").filter((r) => r.name === "emphasis_removal");
|
||||
assert.ok(rules.length > 0);
|
||||
const { text } = applyRulesToText("this is very important", rules);
|
||||
assert.ok(!text.includes("very"));
|
||||
assert.ok(text.includes("important"));
|
||||
});
|
||||
|
||||
it("should convert passive voice to active", () => {
|
||||
const rules = getRulesForContext("all").filter((r) => r.name === "passive_voice");
|
||||
assert.ok(rules.length > 0);
|
||||
const { text } = applyRulesToText("The function is being used throughout the app", rules);
|
||||
assert.ok(text.includes("uses"));
|
||||
});
|
||||
|
||||
it("should apply combined structural compression", () => {
|
||||
const body = {
|
||||
messages: [
|
||||
{
|
||||
role: "user",
|
||||
content:
|
||||
"I need you to provide a detailed analysis of the routing system. Furthermore, I would like you to explain each and every component in order to understand how they work together. Thank you so much!",
|
||||
},
|
||||
],
|
||||
};
|
||||
const result = cavemanCompress(body, {
|
||||
enabled: true,
|
||||
compressRoles: ["user"],
|
||||
skipRules: [],
|
||||
minMessageLength: 50,
|
||||
preservePatterns: [],
|
||||
});
|
||||
assert.equal(result.compressed, true);
|
||||
assert.ok(
|
||||
result.stats.savingsPercent > 10,
|
||||
`Expected meaningful savings, got ${result.stats.savingsPercent}%`
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,182 @@
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { cavemanCompress } from "../../../open-sse/services/compression/caveman.ts";
|
||||
import {
|
||||
getCavemanRuleMetadata,
|
||||
getRuleByName,
|
||||
} from "../../../open-sse/services/compression/cavemanRules.ts";
|
||||
import { applyCompression } from "../../../open-sse/services/compression/strategySelector.ts";
|
||||
|
||||
function compress(content: string, options = {}) {
|
||||
const result = cavemanCompress(
|
||||
{ messages: [{ role: "user", content }] },
|
||||
{
|
||||
enabled: true,
|
||||
compressRoles: ["user"],
|
||||
skipRules: [],
|
||||
minMessageLength: 0,
|
||||
preservePatterns: [],
|
||||
intensity: "full",
|
||||
...options,
|
||||
}
|
||||
);
|
||||
return result.body.messages[0].content as string;
|
||||
}
|
||||
|
||||
describe("Caveman v3.7.9 rule parity", () => {
|
||||
it("removes articles, pleasantries, leader phrases, and redundant phrasing", () => {
|
||||
const text = compress(
|
||||
"Sure, I will make sure to explain the reason is because the function uses a database."
|
||||
);
|
||||
assert.doesNotMatch(text, /\bSure\b/i);
|
||||
assert.doesNotMatch(text, /^I will\b/i);
|
||||
assert.doesNotMatch(text, /\bmake sure to\b/i);
|
||||
assert.doesNotMatch(text, /\bthe reason is because\b/i);
|
||||
assert.doesNotMatch(text, /\bthe function\b/i);
|
||||
assert.match(text, /\bensure\b/i);
|
||||
assert.match(text, /\bbecause\b/i);
|
||||
assert.match(text, /\bdatabase\b/i);
|
||||
});
|
||||
|
||||
it("recapitalizes sentence starts after removals", () => {
|
||||
const text = compress("Sure, the database connection fails. of course the fix is simple.");
|
||||
assert.match(text, /^Database/);
|
||||
assert.match(text, /\. Fix/);
|
||||
});
|
||||
|
||||
it("supports intensity sub-levels for standard mode", () => {
|
||||
const lite = compress("The database request uses the response object.", { intensity: "lite" });
|
||||
const full = compress("The database request uses the response object.", { intensity: "full" });
|
||||
const ultra = compress("The database request uses the response object.", {
|
||||
intensity: "ultra",
|
||||
});
|
||||
|
||||
assert.match(lite, /\bThe\b/);
|
||||
assert.doesNotMatch(full, /\bThe\b/);
|
||||
assert.match(ultra, /\bDB\b/);
|
||||
assert.match(ultra, /\breq\b/);
|
||||
assert.match(ultra, /\bres\b/);
|
||||
});
|
||||
|
||||
it("preserves articles before proper nouns, numbers, and code-like tokens", () => {
|
||||
const text = compress(
|
||||
"Use the OpenAI API, the 404 error, the config.api.endpoint() function, and the database."
|
||||
);
|
||||
|
||||
assert.match(text, /\bthe OpenAI API\b/);
|
||||
assert.match(text, /\bthe 404 error\b/);
|
||||
assert.match(text, /\bthe config\.api\.endpoint\(\) function\b/);
|
||||
assert.doesNotMatch(text, /\bthe database\b/i);
|
||||
});
|
||||
|
||||
it("removes upstream Caveman pleasantry variants without breaking make sure to", () => {
|
||||
const text = compress(
|
||||
"Thanks, thank you, glad to help, I'd be glad to, no problem, you're welcome, absolutely. Please make sure to review the database."
|
||||
);
|
||||
|
||||
for (const phrase of [
|
||||
"thanks",
|
||||
"thank you",
|
||||
"glad to help",
|
||||
"I'd be glad to",
|
||||
"no problem",
|
||||
"you're welcome",
|
||||
"absolutely",
|
||||
]) {
|
||||
assert.doesNotMatch(text, new RegExp(phrase.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "i"));
|
||||
}
|
||||
assert.match(text, /\bensure review database\b/i);
|
||||
});
|
||||
|
||||
it("keeps system prompts unchanged when preserveSystemPrompt is enabled", () => {
|
||||
const body = {
|
||||
messages: [
|
||||
{
|
||||
role: "system",
|
||||
content: "The assistant should make sure to preserve the detailed policy.",
|
||||
},
|
||||
{
|
||||
role: "user",
|
||||
content: "Please make sure to summarize the database response.",
|
||||
},
|
||||
],
|
||||
};
|
||||
const result = applyCompression(body, "standard", {
|
||||
config: {
|
||||
enabled: true,
|
||||
defaultMode: "standard",
|
||||
autoTriggerMode: "standard",
|
||||
autoTriggerTokens: 0,
|
||||
cacheMinutes: 5,
|
||||
preserveSystemPrompt: true,
|
||||
comboOverrides: {},
|
||||
cavemanConfig: {
|
||||
enabled: true,
|
||||
compressRoles: ["system", "user"],
|
||||
skipRules: [],
|
||||
minMessageLength: 0,
|
||||
preservePatterns: [],
|
||||
intensity: "full",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const messages = result.body.messages as Array<{ role: string; content: string }>;
|
||||
assert.equal(messages[0].content, body.messages[0].content);
|
||||
assert.doesNotMatch(messages[1].content, /\bPlease\b/i);
|
||||
});
|
||||
|
||||
it("preserves multimodal non-text parts in aggressive and ultra modes", () => {
|
||||
const body = {
|
||||
messages: [
|
||||
{
|
||||
role: "user",
|
||||
content: [
|
||||
{ type: "text", text: "Please make sure to explain the database response.".repeat(20) },
|
||||
{ type: "image_url", image_url: { url: "data:image/png;base64,abc" } },
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
for (const mode of ["aggressive", "ultra"] as const) {
|
||||
const result = applyCompression(body, mode, {
|
||||
config: {
|
||||
enabled: true,
|
||||
defaultMode: mode,
|
||||
autoTriggerTokens: 0,
|
||||
cacheMinutes: 5,
|
||||
preserveSystemPrompt: true,
|
||||
comboOverrides: {},
|
||||
aggressive: undefined,
|
||||
ultra: {
|
||||
enabled: true,
|
||||
compressionRate: 0.5,
|
||||
minScoreThreshold: 0.3,
|
||||
slmFallbackToAggressive: true,
|
||||
maxTokensPerMessage: 0,
|
||||
},
|
||||
},
|
||||
});
|
||||
const content = (result.body.messages as typeof body.messages)[0].content;
|
||||
assert.ok(Array.isArray(content));
|
||||
assert.deepEqual(content[1], body.messages[0].content[1]);
|
||||
}
|
||||
});
|
||||
|
||||
it("exposes metadata for new rule names", () => {
|
||||
const metadata = getCavemanRuleMetadata();
|
||||
for (const ruleName of [
|
||||
"articles",
|
||||
"pleasantries",
|
||||
"leader_phrases",
|
||||
"redundant_phrasing",
|
||||
"ultra_abbreviations",
|
||||
]) {
|
||||
assert.ok(getRuleByName(ruleName), `missing rule ${ruleName}`);
|
||||
const rule = metadata.find((entry) => entry.name === ruleName);
|
||||
assert.ok(rule?.category, `missing metadata category for ${ruleName}`);
|
||||
assert.ok(rule?.intensities?.length, `missing metadata intensities for ${ruleName}`);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,44 @@
|
||||
import { test } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import {
|
||||
SHARED_BOUNDARIES,
|
||||
buildCavemanOutputInstruction,
|
||||
} from "../../../open-sse/services/compression/outputMode.ts";
|
||||
|
||||
test("SHARED_BOUNDARIES is exported and non-empty string", () => {
|
||||
assert.equal(typeof SHARED_BOUNDARIES, "string");
|
||||
assert.ok(SHARED_BOUNDARIES.length > 0);
|
||||
});
|
||||
|
||||
test("SHARED_BOUNDARIES instructs model to write normal for security warnings", () => {
|
||||
assert.match(SHARED_BOUNDARIES, /security/i);
|
||||
assert.match(SHARED_BOUNDARIES, /normal/i);
|
||||
});
|
||||
|
||||
test("SHARED_BOUNDARIES instructs model to resume terse style after", () => {
|
||||
assert.match(SHARED_BOUNDARIES, /resume/i);
|
||||
});
|
||||
|
||||
test("SHARED_BOUNDARIES covers irreversible actions", () => {
|
||||
assert.match(SHARED_BOUNDARIES, /irreversible/i);
|
||||
});
|
||||
|
||||
test("SHARED_BOUNDARIES covers multi-step ordered sequences", () => {
|
||||
assert.match(SHARED_BOUNDARIES, /sequence|ordered/i);
|
||||
});
|
||||
|
||||
test("buildCavemanOutputInstruction includes SHARED_BOUNDARIES text", () => {
|
||||
const instruction = buildCavemanOutputInstruction({ enabled: true, intensity: "full" });
|
||||
assert.ok(instruction.includes(SHARED_BOUNDARIES), "instruction must embed SHARED_BOUNDARIES");
|
||||
});
|
||||
|
||||
test("buildCavemanOutputInstruction includes persistence clause for all intensities", () => {
|
||||
for (const intensity of ["lite", "full", "ultra"] as const) {
|
||||
const instr = buildCavemanOutputInstruction({ enabled: true, intensity });
|
||||
assert.match(
|
||||
instr,
|
||||
/active every response|until user asks/i,
|
||||
`${intensity} must have persistence clause`
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,268 @@
|
||||
/**
|
||||
* TDD security tests: CCR cross-tenant IDOR + bounded memory + scoped feedback.
|
||||
* Run: node --import tsx/esm --test tests/unit/compression/ccr-cross-tenant.test.ts
|
||||
*
|
||||
* RED → GREEN: these tests define the security contract and must drive the fix.
|
||||
*
|
||||
* Security assertions:
|
||||
* 1. Cross-tenant IDOR blocked: principal B cannot retrieve a block stored by A.
|
||||
* 2. Anonymous principal cannot retrieve a block stored by a named principal.
|
||||
* 3. Memory bound: store never exceeds MAX_CCR_ENTRIES (FIFO eviction).
|
||||
* 4. Scoped feedback: A's retrievals do NOT flip B's shouldSkipCompression.
|
||||
* 5. handleCcrRetrieve end-to-end: cross-tenant retrieve returns not-found error.
|
||||
*/
|
||||
|
||||
import crypto from "node:crypto";
|
||||
import { describe, it, beforeEach } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
|
||||
import {
|
||||
storeBlock,
|
||||
retrieveBlock,
|
||||
recordRetrieval,
|
||||
shouldSkipCompression,
|
||||
resetCcrStore,
|
||||
handleCcrRetrieve,
|
||||
ccrEngine,
|
||||
MAX_CCR_ENTRIES,
|
||||
} from "../../../open-sse/services/compression/engines/ccr/index.ts";
|
||||
|
||||
// ─── helpers ──────────────────────────────────────────────────────────────────
|
||||
|
||||
function makeText(seed: string, length: number = 700): string {
|
||||
return seed.repeat(Math.ceil(length / seed.length)).slice(0, length);
|
||||
}
|
||||
|
||||
const TEXT_A = makeText("content for principal A — confidential data");
|
||||
const TEXT_B = makeText("content for principal B — different tenant");
|
||||
|
||||
function contentHash(text: string): string {
|
||||
return crypto.createHash("sha256").update(text).digest("hex").slice(0, 24);
|
||||
}
|
||||
|
||||
// ─── cross-tenant IDOR isolation ─────────────────────────────────────────────
|
||||
|
||||
describe("ccr security: cross-tenant IDOR isolation", () => {
|
||||
beforeEach(() => resetCcrStore());
|
||||
|
||||
it("[HIGH] principal B cannot retrieve a block stored by principal A", () => {
|
||||
const hash = storeBlock(TEXT_A, "principalA");
|
||||
|
||||
// Same principal can retrieve
|
||||
const resultA = retrieveBlock(hash, "principalA");
|
||||
assert.equal(resultA, TEXT_A, "principal A must be able to retrieve its own block");
|
||||
|
||||
// Different principal is blocked — THE CORE SECURITY ASSERTION
|
||||
const resultB = retrieveBlock(hash, "principalB");
|
||||
assert.equal(
|
||||
resultB,
|
||||
null,
|
||||
"[HIGH IDOR] principal B must NOT be able to retrieve principal A's block"
|
||||
);
|
||||
});
|
||||
|
||||
it("[HIGH] anonymous principal cannot retrieve a block stored by a named principal", () => {
|
||||
const hash = storeBlock(TEXT_A, "principalA");
|
||||
|
||||
const resultAnon = retrieveBlock(hash, undefined);
|
||||
assert.equal(
|
||||
resultAnon,
|
||||
null,
|
||||
"[HIGH IDOR] anonymous principal must NOT retrieve a named principal's block"
|
||||
);
|
||||
});
|
||||
|
||||
it("named principal cannot retrieve a block stored by anonymous", () => {
|
||||
const hash = storeBlock(TEXT_B, undefined);
|
||||
|
||||
const resultA = retrieveBlock(hash, "principalA");
|
||||
assert.equal(resultA, null, "principal A must NOT retrieve an anonymous block");
|
||||
|
||||
// The anonymous store owner can retrieve
|
||||
const resultAnon = retrieveBlock(hash, undefined);
|
||||
assert.equal(resultAnon, TEXT_B, "anonymous can retrieve its own block");
|
||||
});
|
||||
|
||||
it("principal with no stored block cannot retrieve via another principal's hash", () => {
|
||||
// Store TEXT_A only under principalA — principalB never stores anything.
|
||||
const hashA = storeBlock(TEXT_A, "principalA");
|
||||
|
||||
// principalA can retrieve their own block
|
||||
assert.equal(retrieveBlock(hashA, "principalA"), TEXT_A, "A can retrieve its own block");
|
||||
|
||||
// principalB never stored anything — cannot retrieve even with the correct hash
|
||||
assert.equal(
|
||||
retrieveBlock(hashA, "principalB"),
|
||||
null,
|
||||
"[HIGH IDOR] B (never stored) cannot retrieve A's block by reusing A's hash"
|
||||
);
|
||||
|
||||
// anonymous similarly cannot
|
||||
assert.equal(
|
||||
retrieveBlock(hashA, undefined),
|
||||
null,
|
||||
"[HIGH IDOR] anonymous cannot retrieve A's block"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
// ─── handleCcrRetrieve end-to-end isolation ───────────────────────────────────
|
||||
|
||||
describe("ccr security: handleCcrRetrieve end-to-end isolation", () => {
|
||||
beforeEach(() => resetCcrStore());
|
||||
|
||||
it("handleCcrRetrieve with correct callerId returns content", () => {
|
||||
const hash = storeBlock(TEXT_A, "callerA");
|
||||
const result = handleCcrRetrieve({ hash }, "callerA");
|
||||
assert.ok("content" in result, "same-caller retrieve must return content");
|
||||
assert.equal((result as { content: string }).content, TEXT_A);
|
||||
});
|
||||
|
||||
it("[HIGH] handleCcrRetrieve with wrong callerId returns not-found error", () => {
|
||||
const hash = storeBlock(TEXT_A, "callerA");
|
||||
const result = handleCcrRetrieve({ hash }, "callerB");
|
||||
assert.ok(
|
||||
"error" in result,
|
||||
"[HIGH IDOR] cross-tenant retrieve via handleCcrRetrieve must return error, not content"
|
||||
);
|
||||
assert.ok(!("content" in result), "[HIGH IDOR] cross-tenant retrieve must NOT return content");
|
||||
});
|
||||
|
||||
it("handleCcrRetrieve without callerId cannot access named-principal block", () => {
|
||||
const hash = storeBlock(TEXT_A, "callerA");
|
||||
const result = handleCcrRetrieve({ hash }, undefined);
|
||||
assert.ok("error" in result, "anonymous retrieve of named-principal block must return error");
|
||||
});
|
||||
|
||||
it("handleCcrRetrieve returns error for completely unknown hash", () => {
|
||||
const result = handleCcrRetrieve({ hash: "000000000000000000000000" }, "anyPrincipal");
|
||||
assert.ok("error" in result, "unknown hash must return error");
|
||||
assert.ok(typeof (result as { error: string }).error === "string");
|
||||
});
|
||||
|
||||
it("handleCcrRetrieve returns error for missing hash parameter", () => {
|
||||
// @ts-expect-error — intentional wrong call to verify guard
|
||||
const result = handleCcrRetrieve({}, "caller");
|
||||
assert.ok("error" in result, "missing hash must return error");
|
||||
});
|
||||
});
|
||||
|
||||
// ─── scoped retrieval feedback ────────────────────────────────────────────────
|
||||
|
||||
describe("ccr security: [MEDIUM] scoped retrieval feedback (shouldSkipCompression)", () => {
|
||||
beforeEach(() => resetCcrStore());
|
||||
|
||||
it("A's retrievals do NOT flip B's shouldSkipCompression", () => {
|
||||
const hash = storeBlock(TEXT_A, "principalA");
|
||||
storeBlock(TEXT_A, "principalB"); // same content stored under B
|
||||
|
||||
// Record retrievals for A above the threshold (default 3)
|
||||
recordRetrieval(hash, "principalA");
|
||||
recordRetrieval(hash, "principalA");
|
||||
recordRetrieval(hash, "principalA");
|
||||
|
||||
// A's compression should be skipped
|
||||
assert.equal(
|
||||
shouldSkipCompression(hash, "principalA"),
|
||||
true,
|
||||
"A's compression should be skipped after threshold retrievals"
|
||||
);
|
||||
|
||||
// B's compression must NOT be affected
|
||||
assert.equal(
|
||||
shouldSkipCompression(hash, "principalB"),
|
||||
false,
|
||||
"[MEDIUM] A's retrievals must NOT flip B's shouldSkipCompression"
|
||||
);
|
||||
});
|
||||
|
||||
it("shouldSkipCompression returns false for a principal with no retrievals", () => {
|
||||
const hash = storeBlock(TEXT_A, "principalA");
|
||||
assert.equal(shouldSkipCompression(hash, "principalA"), false);
|
||||
assert.equal(shouldSkipCompression(hash, "principalB"), false);
|
||||
assert.equal(shouldSkipCompression(hash, undefined), false);
|
||||
});
|
||||
});
|
||||
|
||||
// ─── bounded memory (FIFO eviction) ──────────────────────────────────────────
|
||||
|
||||
describe("ccr security: [MEDIUM] bounded memory (FIFO eviction)", () => {
|
||||
beforeEach(() => resetCcrStore());
|
||||
|
||||
it("MAX_CCR_ENTRIES is exported and positive", () => {
|
||||
assert.ok(typeof MAX_CCR_ENTRIES === "number", "MAX_CCR_ENTRIES must be a number");
|
||||
assert.ok(MAX_CCR_ENTRIES > 0, "MAX_CCR_ENTRIES must be positive");
|
||||
});
|
||||
|
||||
it("FIFO eviction: oldest entry is evicted when cap is reached", () => {
|
||||
const principal = "evictionTest";
|
||||
|
||||
// Fill to exactly cap with unique blocks
|
||||
const firstText = `eviction block 0 ${"y".repeat(30)}`;
|
||||
const firstHash = storeBlock(firstText, principal);
|
||||
|
||||
for (let i = 1; i < MAX_CCR_ENTRIES; i++) {
|
||||
storeBlock(`eviction block ${i} ${"y".repeat(30)}`, principal);
|
||||
}
|
||||
|
||||
// Confirm first block is present before overflow
|
||||
assert.equal(
|
||||
retrieveBlock(firstHash, principal),
|
||||
firstText,
|
||||
"first block must be present at exactly-cap state"
|
||||
);
|
||||
|
||||
// Insert one more unique block — should evict the first (oldest) entry
|
||||
storeBlock(`eviction overflow block ${"z".repeat(50)}`, principal);
|
||||
|
||||
// First block should now be gone
|
||||
assert.equal(
|
||||
retrieveBlock(firstHash, principal),
|
||||
null,
|
||||
"[MEDIUM] FIFO eviction: oldest block must be evicted when cap is reached"
|
||||
);
|
||||
});
|
||||
|
||||
it("store does not grow unboundedly beyond MAX_CCR_ENTRIES distinct principals", () => {
|
||||
// Insert MAX+5 distinct (principal, content) pairs and verify the overall store
|
||||
// did not go unbounded by checking that the first inserted block is evicted.
|
||||
const firstText = `overflow test block 0 ${"a".repeat(40)}`;
|
||||
const firstPrincipal = "overflow-p-0";
|
||||
const firstHash = storeBlock(firstText, firstPrincipal);
|
||||
|
||||
for (let i = 1; i < MAX_CCR_ENTRIES + 5; i++) {
|
||||
storeBlock(`overflow test block ${i} ${"a".repeat(40)}`, `overflow-p-${i}`);
|
||||
}
|
||||
|
||||
// The first inserted store-key should have been evicted by FIFO
|
||||
assert.equal(
|
||||
retrieveBlock(firstHash, firstPrincipal),
|
||||
null,
|
||||
"[MEDIUM] unbounded-growth prevented: first inserted entry must be evicted after MAX+5 inserts"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
// ─── engine-level scoping: apply() threads principalId end-to-end ─────────────
|
||||
|
||||
describe("ccr security: [HIGH] ccrEngine.apply scopes the stored block to the principal", () => {
|
||||
beforeEach(() => resetCcrStore());
|
||||
|
||||
const bigBlock = makeText("a large block that CCR would normally compress ", 5000);
|
||||
const makeBody = () => ({ messages: [{ role: "user", content: bigBlock }] });
|
||||
|
||||
it("apply with a principalId stores the block retrievable ONLY by that principal", () => {
|
||||
const result = ccrEngine.apply(makeBody(), {
|
||||
principalId: "principalA",
|
||||
stepConfig: { minChars: 100 },
|
||||
});
|
||||
assert.equal(result.compressed, true, "CCR compresses the large block");
|
||||
const hash = contentHash(bigBlock);
|
||||
assert.equal(retrieveBlock(hash, "principalA"), bigBlock, "owner principal A can retrieve");
|
||||
assert.equal(
|
||||
retrieveBlock(hash, "principalB"),
|
||||
null,
|
||||
"[HIGH IDOR] principal B must NOT retrieve principal A's apply()-stored block"
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,239 @@
|
||||
/**
|
||||
* TDD tests for the CCR (Content-Compression-Retrieve) engine (H4).
|
||||
* Run: node --import tsx/esm --test tests/unit/compression/ccr-marker-retrieve.test.ts
|
||||
*
|
||||
* RED phase: these tests should FAIL before implementing the engine.
|
||||
* GREEN phase: these tests should PASS after implementation.
|
||||
*/
|
||||
|
||||
import { describe, it, before } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
|
||||
import {
|
||||
ccrEngine,
|
||||
retrieveBlock,
|
||||
recordRetrieval,
|
||||
shouldSkipCompression,
|
||||
resetCcrStore,
|
||||
handleCcrRetrieve,
|
||||
} from "../../../open-sse/services/compression/engines/ccr/index.ts";
|
||||
import {
|
||||
registerBuiltinCompressionEngines,
|
||||
getCompressionEngine,
|
||||
} from "../../../open-sse/services/compression/index.ts";
|
||||
|
||||
// ─── helpers ──────────────────────────────────────────────────────────────────
|
||||
|
||||
const LARGE_TEXT = `This is a large block of content that should trigger CCR compression.
|
||||
It contains multiple lines and substantial text.
|
||||
The CCR engine compresses large contiguous blocks of text.
|
||||
Replacing them with a content-addressed retrieve marker.
|
||||
This allows the model to retrieve the verbatim content on demand.
|
||||
Using the retrieve MCP tool with the hash from the marker.
|
||||
The block must be large enough to exceed the minimum threshold.
|
||||
Default minimum is 600 characters, so this block is crafted accordingly.
|
||||
We need to be thorough and ensure the block is truly large enough.
|
||||
This is line ten and still counting to make the block big enough.`;
|
||||
|
||||
const SMALL_TEXT = "Short content that should NOT be compressed.";
|
||||
|
||||
const SYSTEM_TEXT = "You are a helpful assistant with system instructions.";
|
||||
|
||||
function makeBody(messages: Array<{ role: string; content: string }>) {
|
||||
return { model: "gpt-4", messages };
|
||||
}
|
||||
|
||||
// ─── tests ────────────────────────────────────────────────────────────────────
|
||||
|
||||
describe("ccr engine", () => {
|
||||
before(() => {
|
||||
resetCcrStore();
|
||||
registerBuiltinCompressionEngines();
|
||||
});
|
||||
|
||||
it("is registered and retrievable by id", () => {
|
||||
const engine = getCompressionEngine("ccr");
|
||||
assert.ok(engine, "getCompressionEngine('ccr') must return the engine");
|
||||
assert.equal(engine.id, "ccr");
|
||||
assert.equal(typeof engine.apply, "function");
|
||||
assert.equal(typeof engine.compress, "function");
|
||||
assert.equal(typeof engine.getConfigSchema, "function");
|
||||
assert.equal(typeof engine.validateConfig, "function");
|
||||
assert.equal(engine.stackable, true);
|
||||
assert.ok(typeof engine.stackPriority === "number");
|
||||
});
|
||||
|
||||
it("replaces a large block with a CCR marker", () => {
|
||||
resetCcrStore();
|
||||
const body = makeBody([{ role: "user", content: LARGE_TEXT }]);
|
||||
const result = ccrEngine.apply(body as Record<string, unknown>);
|
||||
|
||||
assert.equal(result.compressed, true, "should report compressed=true");
|
||||
|
||||
const messages = result.body.messages as Array<{ role: string; content: string }>;
|
||||
const content = messages[0].content;
|
||||
|
||||
// Marker must be present
|
||||
assert.match(
|
||||
content,
|
||||
/\[CCR retrieve hash=[0-9a-f]{24} chars=\d+\]/,
|
||||
"content must contain a [CCR retrieve hash=<24hex> chars=N] marker"
|
||||
);
|
||||
|
||||
// Original large text must be gone
|
||||
assert.ok(!content.includes(LARGE_TEXT), "original large block text must be replaced");
|
||||
|
||||
// Body must be shorter
|
||||
const originalLen = JSON.stringify(body).length;
|
||||
const compressedLen = JSON.stringify(result.body).length;
|
||||
assert.ok(compressedLen < originalLen, "compressed body must be shorter than original");
|
||||
});
|
||||
|
||||
it("stores and retrieves the verbatim block by hash", () => {
|
||||
resetCcrStore();
|
||||
const body = makeBody([{ role: "user", content: LARGE_TEXT }]);
|
||||
const result = ccrEngine.apply(body as Record<string, unknown>);
|
||||
|
||||
const messages = result.body.messages as Array<{ role: string; content: string }>;
|
||||
const content = messages[0].content;
|
||||
|
||||
// Extract hash from marker
|
||||
const match = content.match(/\[CCR retrieve hash=([0-9a-f]{24}) chars=\d+\]/);
|
||||
assert.ok(match, "marker must be present to extract hash");
|
||||
const hash = match[1];
|
||||
|
||||
// Retrieve the block
|
||||
const retrieved = retrieveBlock(hash);
|
||||
assert.ok(retrieved !== null, "retrieveBlock must return the stored block");
|
||||
assert.equal(retrieved, LARGE_TEXT, "retrieved block must equal the original verbatim text");
|
||||
});
|
||||
|
||||
it("does NOT compress small blocks (below minChars threshold)", () => {
|
||||
resetCcrStore();
|
||||
const body = makeBody([{ role: "user", content: SMALL_TEXT }]);
|
||||
const result = ccrEngine.apply(body as Record<string, unknown>);
|
||||
|
||||
assert.equal(result.compressed, false, "small text should NOT be compressed");
|
||||
|
||||
const messages = result.body.messages as Array<{ role: string; content: string }>;
|
||||
assert.equal(messages[0].content, SMALL_TEXT, "small text must remain unchanged");
|
||||
});
|
||||
|
||||
it("does NOT compress system messages", () => {
|
||||
resetCcrStore();
|
||||
const body = makeBody([{ role: "system", content: SYSTEM_TEXT + " ".repeat(700) }]);
|
||||
const result = ccrEngine.apply(body as Record<string, unknown>);
|
||||
|
||||
assert.equal(result.compressed, false, "system messages must NOT be compressed");
|
||||
|
||||
const messages = result.body.messages as Array<{ role: string; content: string }>;
|
||||
assert.ok(
|
||||
!messages[0].content.match(/\[CCR retrieve/),
|
||||
"system message must not contain a CCR marker"
|
||||
);
|
||||
});
|
||||
|
||||
it("does NOT compress if output would not be shorter", () => {
|
||||
resetCcrStore();
|
||||
// A text that's just barely at the threshold but the marker is longer than the text
|
||||
const shortishText = "X".repeat(601); // just above 600 but marker is ~50 chars
|
||||
const body = makeBody([{ role: "user", content: shortishText }]);
|
||||
// The marker is [CCR retrieve hash=<24hex> chars=601] ≈ 48 chars
|
||||
// So 601 chars → 48 char marker = savings, so this WILL compress
|
||||
// To test "not shorter", we'd need a tiny text — but that's already handled by minChars.
|
||||
// This test just confirms a borderline-large block compresses fine.
|
||||
const result = ccrEngine.apply(body as Record<string, unknown>);
|
||||
// Since 601 > 600 (default min), it should compress
|
||||
assert.equal(result.compressed, true, "text above minChars should compress");
|
||||
});
|
||||
|
||||
it("feedback: shouldSkipCompression returns true after enough retrievals", () => {
|
||||
resetCcrStore();
|
||||
const body = makeBody([{ role: "user", content: LARGE_TEXT }]);
|
||||
const result = ccrEngine.apply(body as Record<string, unknown>);
|
||||
|
||||
const messages = result.body.messages as Array<{ role: string; content: string }>;
|
||||
const content = messages[0].content;
|
||||
const match = content.match(/\[CCR retrieve hash=([0-9a-f]{24}) chars=\d+\]/);
|
||||
assert.ok(match, "marker must be present");
|
||||
const hash = match[1];
|
||||
|
||||
// Initially should not skip
|
||||
assert.equal(shouldSkipCompression(hash), false, "initially should not skip compression");
|
||||
|
||||
// Record retrievals above threshold (default 3)
|
||||
recordRetrieval(hash);
|
||||
recordRetrieval(hash);
|
||||
recordRetrieval(hash);
|
||||
|
||||
// After 3 retrievals, shouldSkipCompression should return true
|
||||
assert.equal(
|
||||
shouldSkipCompression(hash),
|
||||
true,
|
||||
"after enough retrievals, shouldSkipCompression must return true"
|
||||
);
|
||||
});
|
||||
|
||||
it("retrieveBlock returns null for unknown hash", () => {
|
||||
resetCcrStore();
|
||||
const result = retrieveBlock("000000000000000000000000");
|
||||
assert.equal(result, null, "unknown hash must return null");
|
||||
});
|
||||
|
||||
it("handles multipart content (type:text parts)", () => {
|
||||
resetCcrStore();
|
||||
const body = {
|
||||
model: "gpt-4",
|
||||
messages: [
|
||||
{
|
||||
role: "user",
|
||||
content: [
|
||||
{ type: "text", text: LARGE_TEXT },
|
||||
{ type: "text", text: "and a small follow-up" },
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const result = ccrEngine.apply(body as Record<string, unknown>);
|
||||
assert.equal(result.compressed, true, "multipart message with large text-part should compress");
|
||||
|
||||
const messages = result.body.messages as Array<{
|
||||
role: string;
|
||||
content: Array<{ type: string; text: string }>;
|
||||
}>;
|
||||
const largePart = messages[0].content[0];
|
||||
assert.ok(
|
||||
largePart.text.match(/\[CCR retrieve hash=[0-9a-f]{24} chars=\d+\]/),
|
||||
"large text part must be replaced by a CCR marker"
|
||||
);
|
||||
// Small part untouched
|
||||
const smallPart = messages[0].content[1];
|
||||
assert.equal(smallPart.text, "and a small follow-up");
|
||||
});
|
||||
});
|
||||
|
||||
describe("ccr MCP retrieve handler (pure function)", () => {
|
||||
it("handleCcrRetrieve returns content for known hash", () => {
|
||||
resetCcrStore();
|
||||
|
||||
const body = makeBody([{ role: "user", content: LARGE_TEXT }]);
|
||||
const result = ccrEngine.apply(body as Record<string, unknown>);
|
||||
const messages = result.body.messages as Array<{ role: string; content: string }>;
|
||||
const match = messages[0].content.match(/\[CCR retrieve hash=([0-9a-f]{24}) chars=\d+\]/);
|
||||
assert.ok(match, "marker must be present");
|
||||
const hash = match[1];
|
||||
|
||||
const handlerResult = handleCcrRetrieve({ hash });
|
||||
assert.ok("content" in handlerResult, "handler must return content field");
|
||||
assert.equal((handlerResult as { content: string }).content, LARGE_TEXT);
|
||||
});
|
||||
|
||||
it("handleCcrRetrieve returns error for unknown hash", () => {
|
||||
resetCcrStore();
|
||||
const result = handleCcrRetrieve({ hash: "deadbeef000000000000000a" });
|
||||
assert.ok("error" in result, "unknown hash must return error field");
|
||||
assert.ok(typeof (result as { error: string }).error === "string");
|
||||
assert.ok((result as { error: string }).error.length > 0);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* #5649 — CCR MCP retrieve principal resolution.
|
||||
*
|
||||
* CCR stores blocks keyed by `String(apiKeyInfo.id)` at compression time. The MCP
|
||||
* `omniroute_ccr_retrieve` tool used to resolve the caller via `extra.authInfo.clientId`
|
||||
* (never populated for API-key auth) → "anonymous" → a store-key miss ("block not
|
||||
* found"). The fix resolves the caller's API-key id from the auth headers via the SAME
|
||||
* `getApiKeyMetadata` lookup, so retrieval matches storage — without weakening
|
||||
* cross-tenant IDOR isolation.
|
||||
*/
|
||||
import { test } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
|
||||
import { resolvePrincipalFromHeaders } from "../../../open-sse/mcp-server/mcpCallerIdentity.ts";
|
||||
import {
|
||||
storeBlock,
|
||||
retrieveBlock,
|
||||
handleCcrRetrieve,
|
||||
resetCcrStore,
|
||||
} from "../../../open-sse/services/compression/engines/ccr/index.ts";
|
||||
|
||||
// A fake key→metadata lookup: maps a raw key to a DB-row id, exactly like getApiKeyMetadata.
|
||||
const fakeLookup = (map: Record<string, string>) => async (rawKey: string) =>
|
||||
map[rawKey] ? { id: map[rawKey] } : null;
|
||||
|
||||
test("#5649 resolves a Bearer API key to its principal id (not anonymous)", async () => {
|
||||
const id = await resolvePrincipalFromHeaders(
|
||||
{ Authorization: "Bearer sk-tenant-A" },
|
||||
fakeLookup({ "sk-tenant-A": "42" })
|
||||
);
|
||||
assert.equal(id, "42", "a valid Bearer key must resolve to its api-key id, not undefined/anonymous");
|
||||
});
|
||||
|
||||
test("#5649 resolves x-api-key (with anthropic-version gate) to its principal id", async () => {
|
||||
const id = await resolvePrincipalFromHeaders(
|
||||
{ "x-api-key": "sk-anthropic", "anthropic-version": "2023-06-01" },
|
||||
fakeLookup({ "sk-anthropic": "99" })
|
||||
);
|
||||
assert.equal(id, "99");
|
||||
});
|
||||
|
||||
test("#5649 distinct keys resolve to distinct principals (IDOR isolation preserved)", async () => {
|
||||
const lookup = fakeLookup({ "sk-A": "42", "sk-B": "77" });
|
||||
const a = await resolvePrincipalFromHeaders({ Authorization: "Bearer sk-A" }, lookup);
|
||||
const b = await resolvePrincipalFromHeaders({ Authorization: "Bearer sk-B" }, lookup);
|
||||
assert.equal(a, "42");
|
||||
assert.equal(b, "77");
|
||||
assert.notEqual(a, b);
|
||||
});
|
||||
|
||||
test("#5649 no auth headers → undefined (never calls the lookup)", async () => {
|
||||
let called = false;
|
||||
const id = await resolvePrincipalFromHeaders({}, async () => {
|
||||
called = true;
|
||||
return { id: "x" };
|
||||
});
|
||||
assert.equal(id, undefined);
|
||||
assert.equal(called, false, "must not hit the DB when there is no key");
|
||||
});
|
||||
|
||||
test("#5649 unknown / unresolvable key → undefined (fail closed to anonymous bucket)", async () => {
|
||||
const id = await resolvePrincipalFromHeaders(
|
||||
{ Authorization: "Bearer sk-unknown" },
|
||||
fakeLookup({ "sk-A": "42" })
|
||||
);
|
||||
assert.equal(id, undefined);
|
||||
});
|
||||
|
||||
test("#5649 end-to-end: a block stored under the api-key id is retrievable by the resolved principal, not by another tenant", async () => {
|
||||
resetCcrStore();
|
||||
const lookup = fakeLookup({ "sk-A": "42", "sk-B": "77" });
|
||||
const bigText = "confidential block for tenant 42 ".repeat(40);
|
||||
|
||||
// Storage side (mirrors chatCore: principal = String(apiKeyInfo.id)).
|
||||
const hash = storeBlock(bigText, "42");
|
||||
|
||||
// Retrieval side: resolve the SAME key's headers → "42" → block found.
|
||||
const owner = await resolvePrincipalFromHeaders({ Authorization: "Bearer sk-A" }, lookup);
|
||||
assert.equal(owner, "42");
|
||||
assert.equal(retrieveBlock(hash, owner), bigText, "owner key must retrieve its own block");
|
||||
const ownerResult = handleCcrRetrieve({ hash }, owner);
|
||||
assert.ok("content" in ownerResult, "owner retrieve returns content");
|
||||
|
||||
// A different tenant's key resolves to a different principal → blocked.
|
||||
const other = await resolvePrincipalFromHeaders({ Authorization: "Bearer sk-B" }, lookup);
|
||||
assert.equal(other, "77");
|
||||
assert.equal(retrieveBlock(hash, other), null, "[HIGH IDOR] other tenant must not retrieve the block");
|
||||
const otherResult = handleCcrRetrieve({ hash }, other);
|
||||
assert.ok("error" in otherResult, "[HIGH IDOR] cross-tenant retrieve returns error");
|
||||
});
|
||||
@@ -0,0 +1,116 @@
|
||||
import { describe, it, beforeEach } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import {
|
||||
ccrEngine,
|
||||
effectiveMinChars,
|
||||
resolveRetrievalRampFactor,
|
||||
recordRetrieval,
|
||||
storeBlock,
|
||||
resetCcrStore,
|
||||
} from "../../../open-sse/services/compression/engines/ccr/index.ts";
|
||||
|
||||
// T08/H8 — graduated retrieval feedback. Frequently-retrieved CCR blocks resist compression
|
||||
// progressively (effective minChars ramps up), and at/above the threshold are never compressed.
|
||||
|
||||
const BASE = 600;
|
||||
const P = "p1";
|
||||
|
||||
beforeEach(() => resetCcrStore());
|
||||
|
||||
function retrieve(hash: string, n: number) {
|
||||
for (let i = 0; i < n; i++) recordRetrieval(hash, P);
|
||||
}
|
||||
|
||||
describe("effectiveMinChars (H8 ramp)", () => {
|
||||
it("never-retrieved block keeps the base minimum", () => {
|
||||
assert.equal(effectiveMinChars(BASE, "h", P, 2), BASE);
|
||||
});
|
||||
|
||||
it("ramps linearly with retrieval count below the threshold (factor 2)", () => {
|
||||
retrieve("h", 1);
|
||||
assert.equal(effectiveMinChars(BASE, "h", P, 2), BASE * 2); // 1200
|
||||
retrieve("h", 1); // count = 2
|
||||
assert.equal(effectiveMinChars(BASE, "h", P, 2), BASE * 3); // 1800
|
||||
});
|
||||
|
||||
it("returns Infinity at/above the retrieval threshold (subsumes the binary cliff)", () => {
|
||||
retrieve("h", 3);
|
||||
assert.equal(effectiveMinChars(BASE, "h", P, 2), Number.POSITIVE_INFINITY);
|
||||
});
|
||||
|
||||
it("rampFactor <= 1 disables the ramp (binary: base until the cliff)", () => {
|
||||
retrieve("h", 2);
|
||||
assert.equal(effectiveMinChars(BASE, "h", P, 1), BASE);
|
||||
retrieve("h", 1); // count = 3 → cliff still applies
|
||||
assert.equal(effectiveMinChars(BASE, "h", P, 1), Number.POSITIVE_INFINITY);
|
||||
});
|
||||
|
||||
it("isolates retrieval feedback per (principal, hash)", () => {
|
||||
retrieve("h", 2);
|
||||
// different hash → unaffected
|
||||
assert.equal(effectiveMinChars(BASE, "other", P, 2), BASE);
|
||||
});
|
||||
});
|
||||
|
||||
describe("resolveRetrievalRampFactor (env)", () => {
|
||||
it("defaults to 2 with no env", () => {
|
||||
assert.equal(resolveRetrievalRampFactor({} as NodeJS.ProcessEnv), 2);
|
||||
});
|
||||
it("reads a valid env value", () => {
|
||||
assert.equal(
|
||||
resolveRetrievalRampFactor({
|
||||
COMPRESSION_CCR_RETRIEVAL_RAMP_FACTOR: "3",
|
||||
} as NodeJS.ProcessEnv),
|
||||
3
|
||||
);
|
||||
});
|
||||
it("falls back to the default on an invalid value", () => {
|
||||
assert.equal(
|
||||
resolveRetrievalRampFactor({
|
||||
COMPRESSION_CCR_RETRIEVAL_RAMP_FACTOR: "0",
|
||||
} as NodeJS.ProcessEnv),
|
||||
2
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("ccrEngine.apply — retrieval-aware compression (H8)", () => {
|
||||
const block = (len: number) => "x".repeat(len);
|
||||
const run = (content: string, retrievalRampFactor = 2) =>
|
||||
ccrEngine.apply(
|
||||
{ messages: [{ role: "user", content }] },
|
||||
{ stepConfig: { minChars: BASE, retrievalRampFactor }, principalId: P }
|
||||
);
|
||||
|
||||
it("compresses a large never-retrieved block normally", () => {
|
||||
const out = run(block(1000));
|
||||
assert.equal(out.compressed, true);
|
||||
});
|
||||
|
||||
it("a block retrieved twice (effMin 1800) is skipped at 1000 chars but compressed at 2000", () => {
|
||||
const hash = storeBlock(block(1000), P); // hash of the 1000-char block
|
||||
retrieve(hash, 2); // count 2 → effMin = base*3 = 1800
|
||||
assert.equal(run(block(1000)).compressed, false, "1000 < 1800 → skipped by the ramp");
|
||||
|
||||
// a distinct, larger block that has NOT been retrieved still compresses
|
||||
assert.equal(run(block(2000)).compressed, true);
|
||||
});
|
||||
|
||||
it("a block retrieved >= threshold is never compressed", () => {
|
||||
const hash = storeBlock(block(5000), P);
|
||||
retrieve(hash, 3);
|
||||
assert.equal(run(block(5000)).compressed, false, "retrieved 3x → excluded (Infinity)");
|
||||
});
|
||||
|
||||
it("rampFactor 1 keeps the legacy binary behavior (retrieved-twice still compresses)", () => {
|
||||
const hash = storeBlock(block(1000), P);
|
||||
retrieve(hash, 2);
|
||||
assert.equal(
|
||||
run(block(1000), 1).compressed,
|
||||
true,
|
||||
"no ramp → still compressed below threshold"
|
||||
);
|
||||
retrieve(hash, 1); // count 3
|
||||
assert.equal(run(block(1000), 1).compressed, false, "cliff still applies at the threshold");
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,68 @@
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import {
|
||||
queryBlock,
|
||||
MAX_GREP_MATCHES,
|
||||
} from "../../../open-sse/services/compression/engines/ccr/ccrQuery.ts";
|
||||
|
||||
const block = ["l1 ok", "l2 ERROR foo", "l3 ok", "l4 ERROR bar", "l5 ok"].join("\n");
|
||||
|
||||
test("full / ausente → texto inteiro (backward-compat)", () => {
|
||||
assert.deepEqual(queryBlock(block, {}), { content: block });
|
||||
assert.deepEqual(queryBlock(block, { mode: "full" }), { content: block });
|
||||
});
|
||||
|
||||
test("head:n e tail:n", () => {
|
||||
assert.deepEqual(queryBlock(block, { mode: "head", n: 2 }), { content: "l1 ok\nl2 ERROR foo" });
|
||||
assert.deepEqual(queryBlock(block, { mode: "tail", n: 2 }), { content: "l4 ERROR bar\nl5 ok" });
|
||||
assert.deepEqual(queryBlock(block, { mode: "head", n: 99 }), { content: block });
|
||||
});
|
||||
|
||||
test("lines:start-end 1-indexed inclusive, clamp", () => {
|
||||
assert.deepEqual(queryBlock(block, { mode: "lines", start: 2, end: 3 }), {
|
||||
content: "l2 ERROR foo\nl3 ok",
|
||||
});
|
||||
assert.deepEqual(queryBlock(block, { mode: "lines", start: 4, end: 99 }), {
|
||||
content: "l4 ERROR bar\nl5 ok",
|
||||
});
|
||||
assert.ok("error" in queryBlock(block, { mode: "lines", start: 3, end: 1 }));
|
||||
});
|
||||
|
||||
test("grep casa linhas; unique deduplica", () => {
|
||||
const r = queryBlock(block, { mode: "grep", pattern: "ERROR" });
|
||||
assert.deepEqual(r, { content: "l2 ERROR foo\nl4 ERROR bar" });
|
||||
const dup = ["x ERR", "x ERR", "y ERR"].join("\n");
|
||||
const u = queryBlock(dup, { mode: "grep", pattern: "ERR", unique: true });
|
||||
assert.deepEqual(u, { content: "x ERR\ny ERR" });
|
||||
});
|
||||
|
||||
test("grep ReDoS rejeitado por safe-regex", () => {
|
||||
const r = queryBlock(block, { mode: "grep", pattern: "(a+)+$" });
|
||||
assert.ok("error" in r);
|
||||
assert.match((r as { error: string }).error, /backtrack|unsafe|reject/i);
|
||||
});
|
||||
|
||||
test("grep regex inválido → erro; pattern grande → erro", () => {
|
||||
assert.ok("error" in queryBlock(block, { mode: "grep", pattern: "[" }));
|
||||
assert.ok("error" in queryBlock(block, { mode: "grep", pattern: "a".repeat(600) }));
|
||||
});
|
||||
|
||||
test("grep cap de matches", () => {
|
||||
const big = Array.from({ length: MAX_GREP_MATCHES + 50 }, (_, i) => `row ${i} HIT`).join("\n");
|
||||
const r = queryBlock(big, { mode: "grep", pattern: "HIT" }) as { content: string };
|
||||
const lines = r.content.split("\n").filter((l) => l.includes("HIT"));
|
||||
assert.ok(lines.length <= MAX_GREP_MATCHES);
|
||||
assert.match(r.content, /truncat/i);
|
||||
});
|
||||
|
||||
test("stats → JSON lines/chars/bytes", () => {
|
||||
const r = queryBlock(block, { mode: "stats" }) as { content: string };
|
||||
const s = JSON.parse(r.content);
|
||||
assert.equal(s.lines, 5);
|
||||
assert.equal(s.chars, block.length);
|
||||
assert.equal(s.bytes, Buffer.byteLength(block, "utf8"));
|
||||
});
|
||||
|
||||
test("queryBlock nunca lança (fail-safe)", () => {
|
||||
assert.doesNotThrow(() => queryBlock(block, { mode: "head", n: -5 }));
|
||||
});
|
||||
@@ -0,0 +1,39 @@
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import {
|
||||
storeBlock,
|
||||
handleCcrRetrieve,
|
||||
resetCcrStore,
|
||||
} from "../../../open-sse/services/compression/engines/ccr/index.ts";
|
||||
|
||||
test.beforeEach(() => resetCcrStore());
|
||||
|
||||
const block = ["a ok", "b ERROR", "c ok", "d ERROR"].join("\n");
|
||||
|
||||
test("sem mode → bloco inteiro (backward-compat)", () => {
|
||||
const h = storeBlock(block, "p1");
|
||||
assert.deepEqual(handleCcrRetrieve({ hash: h }, "p1"), { content: block });
|
||||
});
|
||||
|
||||
test("modos ranged via handler", () => {
|
||||
const h = storeBlock(block, "p1");
|
||||
assert.deepEqual(handleCcrRetrieve({ hash: h, mode: "head", n: 1 }, "p1"), { content: "a ok" });
|
||||
assert.deepEqual(handleCcrRetrieve({ hash: h, mode: "grep", pattern: "ERROR" }, "p1"), {
|
||||
content: "b ERROR\nd ERROR",
|
||||
});
|
||||
const stats = handleCcrRetrieve({ hash: h, mode: "stats" }, "p1") as { content: string };
|
||||
assert.equal(JSON.parse(stats.content).lines, 4);
|
||||
});
|
||||
|
||||
test("scoping preservado: principal errado → not found", () => {
|
||||
const h = storeBlock(block, "p1");
|
||||
const r = handleCcrRetrieve({ hash: h, mode: "head", n: 1 }, "p2");
|
||||
assert.ok("error" in r);
|
||||
assert.match((r as { error: string }).error, /not found/i);
|
||||
});
|
||||
|
||||
test("grep ReDoS via handler → erro (não crash)", () => {
|
||||
const h = storeBlock(block, "p1");
|
||||
const r = handleCcrRetrieve({ hash: h, mode: "grep", pattern: "(a+)+$" }, "p1");
|
||||
assert.ok("error" in r);
|
||||
});
|
||||
@@ -0,0 +1,51 @@
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
|
||||
import {
|
||||
STACKED_PIPELINE_ENGINE_INTENSITIES,
|
||||
stackedPipelineStepSchema,
|
||||
} from "../../../src/shared/validation/compressionConfigSchemas.ts";
|
||||
|
||||
// Regression guard for #4955: the Engine Combos pipeline editor used to offer engines
|
||||
// (headroom, session-dedup, ccr, llmlingua) that `stackedPipelineStepSchema` rejects, so
|
||||
// selecting one made `PUT /api/context/combos/[id]` fail with HTTP 400 and the UI swallowed
|
||||
// it. The fix routes the dropdown through STACKED_PIPELINE_ENGINE_INTENSITIES, which MUST stay
|
||||
// in lockstep with the discriminated union below.
|
||||
describe("Engine Combos UI ↔ stackedPipelineStepSchema parity (#4955)", () => {
|
||||
const unionEngines = stackedPipelineStepSchema.options
|
||||
.map((option: { shape: { engine: { value: string } } }) => option.shape.engine.value)
|
||||
.sort();
|
||||
|
||||
it("offers exactly the engines the API update schema accepts (no drift)", () => {
|
||||
const uiEngines = Object.keys(STACKED_PIPELINE_ENGINE_INTENSITIES).sort();
|
||||
assert.deepEqual(uiEngines, unionEngines);
|
||||
});
|
||||
|
||||
it("every (engine, intensity) the UI can emit is accepted by the schema", () => {
|
||||
for (const [engine, intensities] of Object.entries(STACKED_PIPELINE_ENGINE_INTENSITIES)) {
|
||||
for (const intensity of intensities) {
|
||||
const result = stackedPipelineStepSchema.safeParse({ engine, intensity });
|
||||
assert.equal(
|
||||
result.success,
|
||||
true,
|
||||
`expected { engine: "${engine}", intensity: "${intensity}" } to be accepted`
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it("the engines removed from the UI in #4955 are indeed rejected by the schema", () => {
|
||||
for (const engine of ["headroom", "session-dedup", "ccr", "llmlingua"]) {
|
||||
assert.equal(
|
||||
stackedPipelineStepSchema.safeParse({ engine, intensity: "standard" }).success,
|
||||
false,
|
||||
`engine "${engine}" must not be a valid stacked-pipeline step`
|
||||
);
|
||||
assert.equal(
|
||||
STACKED_PIPELINE_ENGINE_INTENSITIES[engine],
|
||||
undefined,
|
||||
`engine "${engine}" must not be offered by the combos UI`
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,36 @@
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { join } from "node:path";
|
||||
import { mkdtempSync, rmSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
const TEST_DATA_DIR = mkdtempSync(join(tmpdir(), "compare-"));
|
||||
process.env.DATA_DIR = TEST_DATA_DIR;
|
||||
process.env.API_KEY_SECRET = process.env.API_KEY_SECRET ?? "test-secret-32-chars-min-aaaaaaaa";
|
||||
delete process.env.INITIAL_PASSWORD;
|
||||
const core = await import("../../../src/lib/db/core.ts");
|
||||
const route = await import("../../../src/app/api/compression/compare/route.ts");
|
||||
function makeReq(body: unknown) {
|
||||
return new Request("http://localhost/api/compression/compare", {
|
||||
method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(body),
|
||||
});
|
||||
}
|
||||
test.beforeEach(() => core.resetDbInstance());
|
||||
test.after(() => { core.resetDbInstance(); rmSync(TEST_DATA_DIR, { recursive: true, force: true }); });
|
||||
test("ranks a high-savings engine above a no-op for repetitive tool output", async () => {
|
||||
const text = ["$ npm install",
|
||||
"npm warn deprecated glob@7.2.3: no longer supported",
|
||||
"npm warn deprecated glob@7.2.3: no longer supported",
|
||||
"npm warn deprecated glob@7.2.3: no longer supported",
|
||||
"added 1234 packages"].join("\n");
|
||||
const res = await route.POST(makeReq({ messages: [{ role: "user", content: text }], engineIds: ["rtk", "lite"] }));
|
||||
assert.equal(res.status, 200);
|
||||
const body = await res.json();
|
||||
assert.ok(Array.isArray(body.rows) && body.rows.length === 2);
|
||||
assert.equal(body.rows[0].engine, "rtk");
|
||||
assert.ok(body.rows[0].meanSavingsPercent >= body.rows[1].meanSavingsPercent);
|
||||
assert.ok(typeof body.rows[0].meanRetention === "number");
|
||||
});
|
||||
test("400 on empty messages", async () => {
|
||||
const res = await route.POST(makeReq({ messages: [] }));
|
||||
assert.equal(res.status, 400);
|
||||
});
|
||||
@@ -0,0 +1,192 @@
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import {
|
||||
applyCompression,
|
||||
selectCompressionStrategy,
|
||||
} from "../../../open-sse/services/compression/strategySelector.ts";
|
||||
import { compressAggressive } from "../../../open-sse/services/compression/aggressive.ts";
|
||||
import { DEFAULT_AGGRESSIVE_CONFIG } from "../../../open-sse/services/compression/types.ts";
|
||||
import type {
|
||||
AggressiveConfig,
|
||||
CompressionConfig,
|
||||
} from "../../../open-sse/services/compression/types.ts";
|
||||
|
||||
function makeMessages(count: number): Array<{ role: string; content: string }> {
|
||||
return Array.from({ length: count }, (_, i) => ({
|
||||
role: i % 2 === 0 ? "user" : "assistant",
|
||||
content: `Message ${i}: ${"x".repeat(200)}`,
|
||||
}));
|
||||
}
|
||||
|
||||
describe("Integration: strategySelector → aggressive pipeline", () => {
|
||||
it("applyCompression with mode='aggressive' compresses messages", () => {
|
||||
const messages = makeMessages(20);
|
||||
const body = { messages };
|
||||
const config: CompressionConfig = {
|
||||
enabled: true,
|
||||
defaultMode: "aggressive",
|
||||
autoTriggerTokens: 0,
|
||||
cacheMinutes: 5,
|
||||
preserveSystemPrompt: true,
|
||||
comboOverrides: {},
|
||||
aggressive: DEFAULT_AGGRESSIVE_CONFIG,
|
||||
};
|
||||
|
||||
const result = applyCompression(body as Record<string, unknown>, "aggressive", {
|
||||
model: "test-model",
|
||||
config,
|
||||
});
|
||||
|
||||
assert.ok(result.compressed !== undefined);
|
||||
assert.ok(result.stats !== null);
|
||||
assert.equal(result.stats!.mode, "aggressive");
|
||||
assert.ok(Array.isArray((result.body as Record<string, unknown>).messages));
|
||||
});
|
||||
|
||||
it("applyCompression with mode='aggressive' returns unchanged for empty messages", () => {
|
||||
const body = { messages: [] };
|
||||
const config: CompressionConfig = {
|
||||
enabled: true,
|
||||
defaultMode: "aggressive",
|
||||
autoTriggerTokens: 0,
|
||||
cacheMinutes: 5,
|
||||
preserveSystemPrompt: true,
|
||||
comboOverrides: {},
|
||||
aggressive: DEFAULT_AGGRESSIVE_CONFIG,
|
||||
};
|
||||
|
||||
const result = applyCompression(body as Record<string, unknown>, "aggressive", {
|
||||
model: "test-model",
|
||||
config,
|
||||
});
|
||||
|
||||
assert.equal(result.compressed, false);
|
||||
assert.equal(result.stats, null);
|
||||
});
|
||||
|
||||
it("applyCompression with mode='off' returns unchanged", () => {
|
||||
const messages = makeMessages(20);
|
||||
const body = { messages };
|
||||
|
||||
const result = applyCompression(body as Record<string, unknown>, "off");
|
||||
|
||||
assert.equal(result.compressed, false);
|
||||
assert.equal(result.stats, null);
|
||||
assert.deepEqual((result.body as Record<string, unknown>).messages, messages);
|
||||
});
|
||||
|
||||
it("applyCompression with mode='lite' still works after aggressive addition", () => {
|
||||
const messages = makeMessages(10);
|
||||
const body = { messages };
|
||||
|
||||
const result = applyCompression(body as Record<string, unknown>, "lite");
|
||||
|
||||
// Lite mode should still work — no regression
|
||||
assert.ok(result.compressed !== undefined);
|
||||
});
|
||||
|
||||
it("compressAggressive with custom config overrides defaults", () => {
|
||||
const messages = makeMessages(20);
|
||||
const customConfig: Partial<AggressiveConfig> = {
|
||||
maxTokensPerMessage: 500,
|
||||
minSavingsThreshold: 0.5,
|
||||
summarizerEnabled: false,
|
||||
};
|
||||
|
||||
const result = compressAggressive(messages, customConfig);
|
||||
assert.ok(result.messages.length > 0);
|
||||
assert.equal(result.stats.mode, "aggressive");
|
||||
// With summarizer disabled, no summarizer savings
|
||||
assert.equal(result.stats.aggressive!.summarizerSavings, 0);
|
||||
});
|
||||
|
||||
it("compressAggressive handles tool result messages", () => {
|
||||
const messages = [
|
||||
{ role: "user", content: "Show me the file" },
|
||||
{
|
||||
role: "assistant",
|
||||
content: null,
|
||||
tool_calls: [
|
||||
{ id: "call_1", type: "function", function: { name: "read_file", arguments: "{}" } },
|
||||
],
|
||||
},
|
||||
{
|
||||
role: "tool",
|
||||
content: `File contents:\n${"line of code\n".repeat(100)}`,
|
||||
tool_call_id: "call_1",
|
||||
name: "read_file",
|
||||
},
|
||||
{ role: "assistant", content: "Here's the file content." },
|
||||
];
|
||||
|
||||
const result = compressAggressive(messages, {
|
||||
toolStrategies: {
|
||||
fileContent: true,
|
||||
grepSearch: true,
|
||||
shellOutput: true,
|
||||
json: true,
|
||||
errorMessage: true,
|
||||
},
|
||||
});
|
||||
|
||||
assert.ok(result.messages.length > 0);
|
||||
assert.equal(result.stats.mode, "aggressive");
|
||||
// Tool result should have been compressed
|
||||
assert.ok(result.stats.aggressive!.toolResultSavings >= 0);
|
||||
});
|
||||
|
||||
it("compressAggressive preserves system messages", () => {
|
||||
const messages = [
|
||||
{ role: "system", content: "You are a helpful coding assistant." },
|
||||
...makeMessages(15),
|
||||
];
|
||||
|
||||
const result = compressAggressive(messages);
|
||||
// System message should be preserved
|
||||
const systemMsg = result.messages.find((m) => m.role === "system");
|
||||
assert.ok(systemMsg, "System message should be preserved");
|
||||
assert.equal(systemMsg!.content, "You are a helpful coding assistant.");
|
||||
});
|
||||
|
||||
it("compressAggressive preserves duplicate system prompts during lite fallback", () => {
|
||||
const messages = [
|
||||
{ role: "system", content: "Policy exact. Keep exact." },
|
||||
{ role: "system", content: "Policy exact. Keep exact." },
|
||||
{ role: "user", content: "Short" },
|
||||
];
|
||||
|
||||
const result = compressAggressive(messages, {
|
||||
preserveSystemPrompt: true,
|
||||
minSavingsThreshold: 0.9,
|
||||
summarizerEnabled: false,
|
||||
maxTokensPerMessage: 999999,
|
||||
});
|
||||
|
||||
assert.deepEqual(
|
||||
result.messages.filter((message) => message.role === "system"),
|
||||
messages.filter((message) => message.role === "system")
|
||||
);
|
||||
});
|
||||
|
||||
it("compressAggressive downgrade chain works when aggressive fails", () => {
|
||||
// Empty messages should trigger downgrade gracefully
|
||||
const result = compressAggressive([]);
|
||||
assert.ok(result.messages.length === 0);
|
||||
assert.equal(result.stats.mode, "aggressive");
|
||||
});
|
||||
|
||||
it("full pipeline: strategySelector selects aggressive mode from config", () => {
|
||||
const config: CompressionConfig = {
|
||||
enabled: true,
|
||||
defaultMode: "aggressive",
|
||||
autoTriggerTokens: 0,
|
||||
cacheMinutes: 5,
|
||||
preserveSystemPrompt: true,
|
||||
comboOverrides: {},
|
||||
aggressive: DEFAULT_AGGRESSIVE_CONFIG,
|
||||
};
|
||||
|
||||
const mode = selectCompressionStrategy(config, null, 0);
|
||||
assert.equal(mode, "aggressive");
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,49 @@
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import {
|
||||
BENCHMARK_CORPUS,
|
||||
DEFAULT_BENCHMARK_ENGINES,
|
||||
benchmarkEngines,
|
||||
compareReports,
|
||||
formatBenchmarkTable,
|
||||
} from "../../../open-sse/services/compression/harness/benchmark.ts";
|
||||
|
||||
// F2.4: the benchmark harness existed but nothing invoked it and there was no report output.
|
||||
// These cover the CLI's core: a markdown formatter + a default engine set that resolves and
|
||||
// runs the corpus end-to-end, so `npm run bench:compression` produces a real A/B table.
|
||||
describe("compression benchmark CLI core", () => {
|
||||
it("formatBenchmarkTable renders a markdown table with the best engine bolded", () => {
|
||||
const md = formatBenchmarkTable([
|
||||
{ engine: "rtk", meanSavingsPercent: 42.5, meanRetention: 0.9, totalCompressedTokens: 100 },
|
||||
{ engine: "lite", meanSavingsPercent: 10, meanRetention: 0.99, totalCompressedTokens: 200 },
|
||||
]);
|
||||
assert.match(md, /\| Engine \|/, "has a header row");
|
||||
assert.match(md, /\*\*rtk\*\*/, "best (first) engine is bolded");
|
||||
assert.match(md, /42\.5/, "renders the savings number");
|
||||
assert.match(md, /\blite\b/, "renders the runner-up");
|
||||
assert.ok(!md.includes("**lite**"), "only the best engine is bolded");
|
||||
});
|
||||
|
||||
it("DEFAULT_BENCHMARK_ENGINES all resolve and run the corpus end-to-end", async () => {
|
||||
assert.ok(DEFAULT_BENCHMARK_ENGINES.length > 0, "has a default engine set");
|
||||
assert.ok(
|
||||
!DEFAULT_BENCHMARK_ENGINES.includes("llmlingua"),
|
||||
"excludes llmlingua (needs the ONNX model at runtime)"
|
||||
);
|
||||
|
||||
const reports = await benchmarkEngines(BENCHMARK_CORPUS, DEFAULT_BENCHMARK_ENGINES);
|
||||
const rows = compareReports(reports);
|
||||
assert.equal(rows.length, DEFAULT_BENCHMARK_ENGINES.length);
|
||||
for (const id of DEFAULT_BENCHMARK_ENGINES) {
|
||||
assert.ok(
|
||||
rows.some((r) => r.engine === id),
|
||||
`${id} present in the comparison table`
|
||||
);
|
||||
}
|
||||
// The formatted table is non-empty and lists every engine.
|
||||
const md = formatBenchmarkTable(rows);
|
||||
for (const id of DEFAULT_BENCHMARK_ENGINES) {
|
||||
assert.ok(md.includes(id), `${id} appears in the markdown table`);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,55 @@
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
import {
|
||||
BENCHMARK_CORPUS,
|
||||
DEFAULT_BENCHMARK_ENGINES,
|
||||
benchmarkEngines,
|
||||
runBenchmarkGate,
|
||||
} from "../../../open-sse/services/compression/harness/benchmark.ts";
|
||||
import {
|
||||
tokensPerTask,
|
||||
type BudgetBaseline,
|
||||
} from "../../../open-sse/services/compression/harness/budgetGate.ts";
|
||||
|
||||
const BASELINE_PATH = path.join(
|
||||
path.dirname(fileURLToPath(import.meta.url)),
|
||||
"../../../scripts/check/compression-budget-baseline.json"
|
||||
);
|
||||
|
||||
describe("compression budget gate (F2.4 / N4 ratchet)", () => {
|
||||
it("the committed baseline matches the current benchmark (not stale, no regression)", async () => {
|
||||
const baselines = JSON.parse(fs.readFileSync(BASELINE_PATH, "utf8")) as Record<
|
||||
string,
|
||||
BudgetBaseline
|
||||
>;
|
||||
const reports = await benchmarkEngines(BENCHMARK_CORPUS, DEFAULT_BENCHMARK_ENGINES);
|
||||
const failed = runBenchmarkGate(reports, baselines, 2).filter((r) => !r.gate.passed);
|
||||
assert.equal(
|
||||
failed.length,
|
||||
0,
|
||||
`tokens-per-task regressed vs the committed baseline: ${JSON.stringify(failed)} — ` +
|
||||
`if intentional, run: npm run check:compression-budget -- --update`
|
||||
);
|
||||
});
|
||||
|
||||
it("flags a regression when tokens-per-task rises beyond tolerance", async () => {
|
||||
// ultra is stateless/deterministic. Build a baseline tighter than reality → current regresses.
|
||||
const reports = await benchmarkEngines(BENCHMARK_CORPUS, ["ultra"]);
|
||||
const tight: Record<string, BudgetBaseline> = {
|
||||
ultra: {
|
||||
tasks: Object.fromEntries(
|
||||
Object.entries(tokensPerTask(reports.ultra)).map(([task, n]) => [
|
||||
task,
|
||||
Math.max(1, Math.floor(n / 2)),
|
||||
])
|
||||
),
|
||||
},
|
||||
};
|
||||
const failed = runBenchmarkGate(reports, tight, 2).filter((r) => !r.gate.passed);
|
||||
assert.ok(failed.length > 0, "a halved baseline must be flagged as a regression");
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,132 @@
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import fs from "node:fs";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
|
||||
const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-compression-combos-"));
|
||||
const ORIGINAL_DATA_DIR = process.env.DATA_DIR;
|
||||
process.env.DATA_DIR = TEST_DATA_DIR;
|
||||
|
||||
const core = await import("../../../src/lib/db/core.ts");
|
||||
const combosDb = await import("../../../src/lib/db/compressionCombos.ts");
|
||||
|
||||
async function resetStorage() {
|
||||
core.resetDbInstance();
|
||||
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
|
||||
fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
|
||||
}
|
||||
|
||||
test.beforeEach(async () => {
|
||||
await resetStorage();
|
||||
});
|
||||
|
||||
test.after(() => {
|
||||
core.resetDbInstance();
|
||||
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
|
||||
if (ORIGINAL_DATA_DIR === undefined) {
|
||||
delete process.env.DATA_DIR;
|
||||
} else {
|
||||
process.env.DATA_DIR = ORIGINAL_DATA_DIR;
|
||||
}
|
||||
});
|
||||
|
||||
test("creates default compression combo automatically", () => {
|
||||
const combos = combosDb.listCompressionCombos();
|
||||
const combo = combos.find((item) => item.id === "default-caveman");
|
||||
|
||||
assert.equal(combo?.isDefault, true);
|
||||
assert.equal(combo?.description, "Default RTK + Caveman compression pipeline");
|
||||
assert.deepEqual(combo?.pipeline, [
|
||||
{ engine: "rtk", intensity: "standard" },
|
||||
{ engine: "caveman", intensity: "full" },
|
||||
]);
|
||||
});
|
||||
|
||||
test("upgrades the legacy seeded default compression combo pipeline", () => {
|
||||
const db = core.getDbInstance();
|
||||
db.prepare(
|
||||
`
|
||||
UPDATE compression_combos
|
||||
SET description = ?, pipeline = ?
|
||||
WHERE id = ?
|
||||
`
|
||||
).run(
|
||||
"Default Caveman compression pipeline",
|
||||
JSON.stringify([{ engine: "caveman", intensity: "full" }]),
|
||||
"default-caveman"
|
||||
);
|
||||
|
||||
const combo = combosDb.getDefaultCompressionCombo();
|
||||
assert.equal(combo?.id, "default-caveman");
|
||||
assert.equal(combo?.description, "Default RTK + Caveman compression pipeline");
|
||||
assert.deepEqual(combo?.pipeline, [
|
||||
{ engine: "rtk", intensity: "standard" },
|
||||
{ engine: "caveman", intensity: "full" },
|
||||
]);
|
||||
});
|
||||
|
||||
test("does not overwrite a customized default compression combo", () => {
|
||||
const db = core.getDbInstance();
|
||||
db.prepare(
|
||||
`
|
||||
UPDATE compression_combos
|
||||
SET name = ?, description = ?, pipeline = ?
|
||||
WHERE id = ?
|
||||
`
|
||||
).run(
|
||||
"Custom Default",
|
||||
"User changed",
|
||||
JSON.stringify([{ engine: "caveman", intensity: "lite" }]),
|
||||
"default-caveman"
|
||||
);
|
||||
|
||||
const combo = combosDb.getDefaultCompressionCombo();
|
||||
assert.equal(combo?.id, "default-caveman");
|
||||
assert.equal(combo?.name, "Custom Default");
|
||||
assert.equal(combo?.description, "User changed");
|
||||
assert.deepEqual(combo?.pipeline, [{ engine: "caveman", intensity: "lite" }]);
|
||||
});
|
||||
|
||||
test("creates, updates and protects default compression combos", () => {
|
||||
const combo = combosDb.createCompressionCombo({
|
||||
name: "RTK first",
|
||||
pipeline: [{ engine: "rtk", intensity: "standard" }],
|
||||
languagePacks: ["en", "pt-BR"],
|
||||
});
|
||||
assert.equal(combo.name, "RTK first");
|
||||
assert.equal(combo.pipeline[0].engine, "rtk");
|
||||
|
||||
const updated = combosDb.updateCompressionCombo(combo.id, {
|
||||
description: "Updated",
|
||||
isDefault: true,
|
||||
});
|
||||
assert.equal(updated?.description, "Updated");
|
||||
assert.equal(combosDb.getDefaultCompressionCombo()?.id, combo.id);
|
||||
|
||||
assert.equal(combosDb.deleteCompressionCombo("default-caveman"), true);
|
||||
assert.equal(combosDb.deleteCompressionCombo(combo.id), false);
|
||||
});
|
||||
|
||||
test("assigns routing combos to compression combos", () => {
|
||||
const combo = combosDb.createCompressionCombo({
|
||||
name: "Stacked",
|
||||
pipeline: [
|
||||
{ engine: "rtk", intensity: "standard" },
|
||||
{ engine: "caveman", intensity: "full" },
|
||||
],
|
||||
});
|
||||
|
||||
assert.equal(combosDb.assignRoutingCombo(combo.id, "routing-a"), true);
|
||||
assert.equal(combosDb.getCompressionComboForRoutingCombo("routing-a")?.id, combo.id);
|
||||
assert.deepEqual(
|
||||
combosDb
|
||||
.getAssignmentsForCompressionCombo(combo.id)
|
||||
.map((assignment) => assignment.routingComboId),
|
||||
["routing-a"]
|
||||
);
|
||||
|
||||
assert.equal(combosDb.updateAssignments(combo.id, ["routing-b", "routing-c"]), true);
|
||||
assert.equal(combosDb.getCompressionComboForRoutingCombo("routing-a"), null);
|
||||
assert.equal(combosDb.getCompressionComboForRoutingCombo("routing-b")?.id, combo.id);
|
||||
});
|
||||
@@ -0,0 +1,69 @@
|
||||
import { test, after } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import fs from "node:fs";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
|
||||
const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-compression-engines-"));
|
||||
const ORIGINAL_DATA_DIR = process.env.DATA_DIR;
|
||||
process.env.DATA_DIR = TEST_DATA_DIR;
|
||||
|
||||
const { getDbInstance, resetDbInstance } = await import("../../../src/lib/db/core.ts");
|
||||
const { getCompressionSettings, updateCompressionSettings } = await import(
|
||||
"../../../src/lib/db/compression.ts"
|
||||
);
|
||||
|
||||
function freshDir() {
|
||||
resetDbInstance();
|
||||
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
|
||||
fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
|
||||
}
|
||||
|
||||
after(() => {
|
||||
resetDbInstance();
|
||||
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
|
||||
if (ORIGINAL_DATA_DIR === undefined) {
|
||||
delete process.env.DATA_DIR;
|
||||
} else {
|
||||
process.env.DATA_DIR = ORIGINAL_DATA_DIR;
|
||||
}
|
||||
});
|
||||
|
||||
test("migration backfills engines map from prior defaultMode + default combo", async () => {
|
||||
freshDir();
|
||||
const db = getDbInstance(); // runs migrations incl. 102
|
||||
// simulate a pre-102 install: master on, defaultMode 'standard', caveman enabled
|
||||
db.prepare(
|
||||
"INSERT OR REPLACE INTO key_value(namespace,key,value) VALUES('compression','enabled','true')"
|
||||
).run();
|
||||
db.prepare(
|
||||
"INSERT OR REPLACE INTO key_value(namespace,key,value) VALUES('compression','defaultMode','\"standard\"')"
|
||||
).run();
|
||||
db.prepare(
|
||||
"INSERT OR REPLACE INTO key_value(namespace,key,value) VALUES('compression','cavemanConfig','{\"enabled\":true}')"
|
||||
).run();
|
||||
const cfg = await getCompressionSettings();
|
||||
assert.equal(cfg.engines.caveman.enabled, true);
|
||||
assert.equal(cfg.activeComboId, null);
|
||||
// No stored engines row → backfilled map is display-only; dispatch stays on the legacy path.
|
||||
assert.equal(cfg.enginesExplicit, false);
|
||||
});
|
||||
|
||||
test("engines map persists round-trip + activeComboId", async () => {
|
||||
freshDir();
|
||||
getDbInstance();
|
||||
await updateCompressionSettings({
|
||||
enabled: true,
|
||||
engines: {
|
||||
rtk: { enabled: true, level: "standard" },
|
||||
caveman: { enabled: true, level: "full" },
|
||||
},
|
||||
activeComboId: null,
|
||||
});
|
||||
const cfg = await getCompressionSettings();
|
||||
assert.equal(cfg.engines.rtk.enabled, true);
|
||||
assert.equal(cfg.engines.rtk.level, "standard");
|
||||
assert.equal(cfg.engines.caveman.level, "full");
|
||||
// A stored engines row exists → the panel configured engines; dispatch trusts the map.
|
||||
assert.equal(cfg.enginesExplicit, true);
|
||||
});
|
||||
@@ -0,0 +1,191 @@
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import {
|
||||
selectCompressionStrategy,
|
||||
selectCompressionPlan,
|
||||
planFromHeader,
|
||||
formatCompressionMeta,
|
||||
buildNamedComboLookup,
|
||||
} from "../../../open-sse/services/compression/strategySelector.ts";
|
||||
import {
|
||||
DEFAULT_COMPRESSION_CONFIG,
|
||||
type CompressionConfig,
|
||||
} from "../../../open-sse/services/compression/types.ts";
|
||||
|
||||
const combos = {
|
||||
c1: [
|
||||
{ engine: "rtk", intensity: "standard" },
|
||||
{ engine: "caveman", intensity: "full" },
|
||||
],
|
||||
"fast combo": [{ engine: "lite" }],
|
||||
};
|
||||
|
||||
function cfg(overrides: Partial<CompressionConfig> = {}): CompressionConfig {
|
||||
return { ...DEFAULT_COMPRESSION_CONFIG, enabled: true, ...overrides };
|
||||
}
|
||||
|
||||
// header is the 7th positional arg of selectCompressionPlan/selectCompressionStrategy.
|
||||
function planWithHeader(config: CompressionConfig, header: string | null) {
|
||||
return selectCompressionPlan(config, null, 0, undefined, undefined, combos, header);
|
||||
}
|
||||
|
||||
describe("planFromHeader (Phase 3)", () => {
|
||||
it("off => mode off, source request-header", () => {
|
||||
const p = planFromHeader(cfg(), "off", combos);
|
||||
assert.deepEqual(p, { mode: "off", stackedPipeline: [], source: "request-header" });
|
||||
});
|
||||
|
||||
it("default => the panel-derived default, ignoring the active profile", () => {
|
||||
const config = cfg({
|
||||
activeComboId: "c1",
|
||||
enginesExplicit: true,
|
||||
engines: { rtk: { enabled: true } },
|
||||
});
|
||||
const p = planFromHeader(config, "default", combos);
|
||||
assert.equal(p?.mode, "rtk"); // engines map default, NOT the c1 active profile
|
||||
assert.equal(p?.source, "request-header");
|
||||
});
|
||||
|
||||
it("engine:<id> => that single engine when enabled (case-insensitive)", () => {
|
||||
const config = cfg({ enginesExplicit: true, engines: { rtk: { enabled: true } } });
|
||||
assert.equal(planFromHeader(config, "engine:RTK", combos)?.mode, "rtk");
|
||||
});
|
||||
|
||||
it("engine:<id> => null (fall-through) when the engine is disabled", () => {
|
||||
const config = cfg({ engines: { rtk: { enabled: false } } });
|
||||
assert.equal(planFromHeader(config, "engine:rtk", combos), null);
|
||||
});
|
||||
|
||||
it("engine: <id> => tolerates whitespace after the colon", () => {
|
||||
const config = cfg({ enginesExplicit: true, engines: { rtk: { enabled: true } } });
|
||||
assert.equal(planFromHeader(config, "engine: rtk", combos)?.mode, "rtk");
|
||||
});
|
||||
|
||||
it("<combo> matches by name (case-insensitive) and by id", () => {
|
||||
assert.deepEqual(
|
||||
planFromHeader(cfg(), "FAST COMBO", combos)?.stackedPipeline,
|
||||
combos["fast combo"]
|
||||
);
|
||||
assert.deepEqual(planFromHeader(cfg(), "c1", combos)?.stackedPipeline, combos.c1);
|
||||
});
|
||||
|
||||
it("unknown value => null (fall-through)", () => {
|
||||
assert.equal(planFromHeader(cfg(), "nonsense", combos), null);
|
||||
});
|
||||
});
|
||||
|
||||
describe("header precedence in resolveBasePlan (Phase 3)", () => {
|
||||
it("a valid header beats the active profile", () => {
|
||||
const config = cfg({ activeComboId: "c1" });
|
||||
assert.equal(planWithHeader(config, "off").mode, "off");
|
||||
assert.equal(planWithHeader(config, "off").source, "request-header");
|
||||
});
|
||||
|
||||
it("a valid header beats a routing-combo override", () => {
|
||||
const config = cfg({ comboOverrides: { "route-x": "stacked" } });
|
||||
const plan = selectCompressionPlan(config, "route-x", 0, undefined, undefined, combos, "off");
|
||||
assert.equal(plan.mode, "off");
|
||||
assert.equal(plan.source, "request-header");
|
||||
});
|
||||
|
||||
it("a valid header bypasses auto-trigger (Decision B)", () => {
|
||||
const config = cfg({
|
||||
autoTriggerTokens: 1000,
|
||||
autoTriggerMode: "aggressive",
|
||||
enginesExplicit: true,
|
||||
engines: { rtk: { enabled: true } },
|
||||
});
|
||||
// Large prompt would auto-escalate to aggressive; the header pins the panel default.
|
||||
assert.equal(planWithHeader(config, "default").mode, "rtk");
|
||||
});
|
||||
|
||||
it("an unknown header falls through to the normal resolution", () => {
|
||||
const config = cfg({ activeComboId: "c1" });
|
||||
const plan = planWithHeader(config, "bogus");
|
||||
assert.equal(plan.mode, "stacked");
|
||||
assert.equal(plan.source, "active-profile");
|
||||
});
|
||||
|
||||
it("master-off beats the header (hard kill switch)", () => {
|
||||
const config = cfg({ enabled: false, engines: { rtk: { enabled: true } } });
|
||||
const plan = planWithHeader(config, "engine:rtk");
|
||||
assert.equal(plan.mode, "off");
|
||||
assert.equal(plan.source, "off");
|
||||
});
|
||||
});
|
||||
|
||||
describe("source on non-header paths", () => {
|
||||
it("routing-override / active-profile / auto-trigger / default / off", () => {
|
||||
assert.equal(
|
||||
selectCompressionPlan(
|
||||
cfg({ comboOverrides: { r: "lite" } }),
|
||||
"r",
|
||||
0,
|
||||
undefined,
|
||||
undefined,
|
||||
combos,
|
||||
null
|
||||
).source,
|
||||
"routing-override"
|
||||
);
|
||||
assert.equal(planWithHeader(cfg({ activeComboId: "c1" }), null).source, "active-profile");
|
||||
// auto-trigger only fires once estimatedTokens crosses autoTriggerTokens, so pass an
|
||||
// estimate above the threshold (planWithHeader pins estimatedTokens=0 and never trips it).
|
||||
assert.equal(
|
||||
selectCompressionPlan(
|
||||
cfg({ autoTriggerTokens: 10, autoTriggerMode: "lite" }),
|
||||
null,
|
||||
50,
|
||||
undefined,
|
||||
undefined,
|
||||
combos,
|
||||
null
|
||||
).source,
|
||||
"auto-trigger"
|
||||
);
|
||||
assert.equal(
|
||||
planWithHeader(cfg({ enginesExplicit: true, engines: { rtk: { enabled: true } } }), null)
|
||||
.source,
|
||||
"default"
|
||||
);
|
||||
assert.equal(planWithHeader(cfg({ enabled: false }), null).source, "off");
|
||||
});
|
||||
});
|
||||
|
||||
describe("formatCompressionMeta", () => {
|
||||
it("renders '<mode>; source=<source>'", () => {
|
||||
assert.equal(
|
||||
formatCompressionMeta({ mode: "aggressive", stackedPipeline: [], source: "request-header" }),
|
||||
"aggressive; source=request-header"
|
||||
);
|
||||
assert.equal(formatCompressionMeta({ mode: "off", stackedPipeline: [] }), "off; source=off");
|
||||
});
|
||||
});
|
||||
|
||||
describe("buildNamedComboLookup", () => {
|
||||
const pipe = [{ engine: "lite" }];
|
||||
|
||||
it("keys each combo by both id and lowercased name", () => {
|
||||
const map = buildNamedComboLookup([{ id: "abc-123", name: "My Fast Combo", pipeline: pipe }]);
|
||||
assert.deepEqual(map["abc-123"], pipe);
|
||||
assert.deepEqual(map["my fast combo"], pipe);
|
||||
});
|
||||
|
||||
it("skips the name key (no '' key, no crash) when the name is blank/whitespace/missing", () => {
|
||||
const map = buildNamedComboLookup([
|
||||
{ id: "id-empty", name: "", pipeline: pipe },
|
||||
{ id: "id-space", name: " ", pipeline: pipe },
|
||||
{ id: "id-null", name: null, pipeline: pipe },
|
||||
]);
|
||||
assert.deepEqual(map["id-empty"], pipe); // id key always present
|
||||
assert.deepEqual(map["id-space"], pipe);
|
||||
assert.deepEqual(map["id-null"], pipe);
|
||||
assert.equal(Object.prototype.hasOwnProperty.call(map, ""), false); // no blank key
|
||||
assert.equal(Object.keys(map).length, 3); // only the three id keys
|
||||
});
|
||||
|
||||
it("trims surrounding whitespace on the name key", () => {
|
||||
const map = buildNamedComboLookup([{ id: "x", name: " Spaced ", pipeline: pipe }]);
|
||||
assert.deepEqual(map["spaced"], pipe);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,65 @@
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
|
||||
import {
|
||||
PreviewCompressionConfigSchema,
|
||||
PreviewRequestSchema,
|
||||
} from "../../../src/app/api/compression/preview/route.ts";
|
||||
|
||||
describe("compression preview API contract", () => {
|
||||
it("accepts RTK and stacked preview payloads", () => {
|
||||
assert.equal(
|
||||
PreviewRequestSchema.safeParse({
|
||||
messages: [{ role: "tool", content: "same\nsame\nsame" }],
|
||||
mode: "rtk",
|
||||
config: {
|
||||
rtkConfig: {
|
||||
intensity: "standard",
|
||||
applyToToolResults: true,
|
||||
customFiltersEnabled: true,
|
||||
rawOutputRetention: "never",
|
||||
},
|
||||
},
|
||||
}).success,
|
||||
true
|
||||
);
|
||||
|
||||
assert.equal(
|
||||
PreviewRequestSchema.safeParse({
|
||||
messages: [{ role: "tool", content: "same\nsame\nsame" }],
|
||||
mode: "stacked",
|
||||
config: {
|
||||
stackedPipeline: [
|
||||
{ engine: "rtk", intensity: "standard" },
|
||||
{ engine: "caveman", intensity: "full" },
|
||||
],
|
||||
},
|
||||
}).success,
|
||||
true
|
||||
);
|
||||
});
|
||||
|
||||
it("rejects invalid preview config instead of accepting arbitrary records", () => {
|
||||
assert.equal(PreviewCompressionConfigSchema.safeParse({ unknown: true }).success, false);
|
||||
assert.equal(
|
||||
PreviewRequestSchema.safeParse({
|
||||
messages: [{ role: "tool", content: "x" }],
|
||||
mode: "rtk",
|
||||
config: { rtkConfig: { intensity: "extreme" } },
|
||||
}).success,
|
||||
false
|
||||
);
|
||||
assert.equal(
|
||||
PreviewCompressionConfigSchema.safeParse({
|
||||
stackedPipeline: [{ engine: "rtk", intensity: "bogus" }],
|
||||
}).success,
|
||||
false
|
||||
);
|
||||
assert.equal(
|
||||
PreviewCompressionConfigSchema.safeParse({
|
||||
stackedPipeline: [{ engine: "rtk", config: { maxLinesPerResult: -1 } }],
|
||||
}).success,
|
||||
false
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,155 @@
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import fs from "node:fs";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
|
||||
import { makeManagementSessionRequest } from "../../helpers/managementSession.ts";
|
||||
|
||||
const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-compression-preview-"));
|
||||
const originalDataDir = process.env.DATA_DIR;
|
||||
const originalJwtSecret = process.env.JWT_SECRET;
|
||||
|
||||
process.env.DATA_DIR = TEST_DATA_DIR;
|
||||
|
||||
const core = await import("../../../src/lib/db/core.ts");
|
||||
const settingsDb = await import("../../../src/lib/db/settings.ts");
|
||||
const previewRoute = await import("../../../src/app/api/compression/preview/route.ts");
|
||||
const languagePacksRoute = await import("../../../src/app/api/compression/language-packs/route.ts");
|
||||
const rulesRoute = await import("../../../src/app/api/compression/rules/route.ts");
|
||||
|
||||
type ErrorResponseBody = {
|
||||
error: string | { message?: string };
|
||||
};
|
||||
|
||||
async function resetAuthRequiredStorage(): Promise<void> {
|
||||
core.resetDbInstance();
|
||||
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
|
||||
fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
|
||||
await settingsDb.updateSettings({
|
||||
requireLogin: true,
|
||||
setupComplete: true,
|
||||
password: "test-password-hash",
|
||||
});
|
||||
}
|
||||
|
||||
test.beforeEach(async () => {
|
||||
process.env.DATA_DIR = TEST_DATA_DIR;
|
||||
await resetAuthRequiredStorage();
|
||||
});
|
||||
|
||||
test.after(() => {
|
||||
if (originalDataDir === undefined) delete process.env.DATA_DIR;
|
||||
else process.env.DATA_DIR = originalDataDir;
|
||||
if (originalJwtSecret === undefined) delete process.env.JWT_SECRET;
|
||||
else process.env.JWT_SECRET = originalJwtSecret;
|
||||
core.resetDbInstance();
|
||||
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
test("compression preview requires management auth before reading preview input", async () => {
|
||||
const response = await previewRoute.POST(
|
||||
new Request("http://localhost/api/compression/preview", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
messages: [{ role: "tool", content: "same\nsame\nsame" }],
|
||||
mode: "rtk",
|
||||
}),
|
||||
})
|
||||
);
|
||||
const body = (await response.json()) as ErrorResponseBody;
|
||||
|
||||
assert.equal(response.status, 401);
|
||||
assert.equal(
|
||||
typeof body.error === "object" ? body.error.message : null,
|
||||
"Authentication required"
|
||||
);
|
||||
});
|
||||
|
||||
test("compression preview rejects bearer tokens without a dashboard session", async () => {
|
||||
const response = await previewRoute.POST(
|
||||
new Request("http://localhost/api/compression/preview", {
|
||||
method: "POST",
|
||||
headers: { authorization: "Bearer invalid-management-token" },
|
||||
body: JSON.stringify({
|
||||
messages: [{ role: "tool", content: "same\nsame\nsame" }],
|
||||
mode: "rtk",
|
||||
}),
|
||||
})
|
||||
);
|
||||
const body = (await response.json()) as ErrorResponseBody;
|
||||
|
||||
assert.equal(response.status, 403);
|
||||
assert.equal(
|
||||
typeof body.error === "object" ? body.error.message : null,
|
||||
"Invalid management token"
|
||||
);
|
||||
});
|
||||
|
||||
test("compression preview still runs for authenticated management sessions", async () => {
|
||||
const request = await makeManagementSessionRequest("http://localhost/api/compression/preview", {
|
||||
method: "POST",
|
||||
body: {
|
||||
messages: [{ role: "tool", content: "same\nsame\nsame" }],
|
||||
mode: "rtk",
|
||||
config: {
|
||||
rtkConfig: {
|
||||
intensity: "standard",
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const response = await previewRoute.POST(request);
|
||||
const body = (await response.json()) as { mode?: string; original?: string };
|
||||
|
||||
assert.equal(response.status, 200);
|
||||
assert.equal(body.mode, "rtk");
|
||||
assert.match(body.original || "", /same/);
|
||||
});
|
||||
|
||||
test("compression language pack metadata requires management auth", async () => {
|
||||
const response = await languagePacksRoute.GET(
|
||||
new Request("http://localhost/api/compression/language-packs")
|
||||
);
|
||||
const body = (await response.json()) as ErrorResponseBody;
|
||||
|
||||
assert.equal(response.status, 401);
|
||||
assert.equal(
|
||||
typeof body.error === "object" ? body.error.message : null,
|
||||
"Authentication required"
|
||||
);
|
||||
});
|
||||
|
||||
test("compression rules metadata rejects bearer tokens without a dashboard session", async () => {
|
||||
const response = await rulesRoute.GET(
|
||||
new Request("http://localhost/api/compression/rules", {
|
||||
headers: { authorization: "Bearer invalid-management-token" },
|
||||
})
|
||||
);
|
||||
const body = (await response.json()) as ErrorResponseBody;
|
||||
|
||||
assert.equal(response.status, 403);
|
||||
assert.equal(
|
||||
typeof body.error === "object" ? body.error.message : null,
|
||||
"Invalid management token"
|
||||
);
|
||||
});
|
||||
|
||||
test("compression metadata routes return data for authenticated management sessions", async () => {
|
||||
const languageRequest = await makeManagementSessionRequest(
|
||||
"http://localhost/api/compression/language-packs"
|
||||
);
|
||||
const rulesRequest = await makeManagementSessionRequest("http://localhost/api/compression/rules");
|
||||
|
||||
const languageResponse = await languagePacksRoute.GET(languageRequest);
|
||||
const rulesResponse = await rulesRoute.GET(rulesRequest);
|
||||
const languageBody = (await languageResponse.json()) as { languages?: unknown; packs?: unknown };
|
||||
const rulesBody = (await rulesResponse.json()) as { rules?: unknown };
|
||||
|
||||
assert.equal(languageResponse.status, 200);
|
||||
assert.ok(Array.isArray(languageBody.languages));
|
||||
assert.ok(Array.isArray(languageBody.packs));
|
||||
assert.equal(rulesResponse.status, 200);
|
||||
assert.ok(Array.isArray(rulesBody.rules));
|
||||
});
|
||||
@@ -0,0 +1,28 @@
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
|
||||
import {
|
||||
registerBuiltinCompressionEngines,
|
||||
clearCompressionEngineRegistry,
|
||||
getCompressionEngine,
|
||||
} from "../../../open-sse/services/compression/index.ts";
|
||||
|
||||
// F5.3: registerBuiltinCompressionEngines() guards on a module-level `registered` latch.
|
||||
// clearCompressionEngineRegistry() empties the engine map but does NOT reset that latch, so
|
||||
// a subsequent registerBuiltinCompressionEngines() no-ops and leaves the registry empty —
|
||||
// any getCompressionEngine() then returns null. This file runs in its own process so the
|
||||
// latch starts false (no cross-file interference).
|
||||
describe("builtin compression engine registration after clear", () => {
|
||||
it("re-registers builtin engines after the registry is cleared", () => {
|
||||
registerBuiltinCompressionEngines();
|
||||
assert.ok(getCompressionEngine("rtk"), "builtins registered initially");
|
||||
|
||||
clearCompressionEngineRegistry();
|
||||
assert.equal(getCompressionEngine("rtk"), null, "registry emptied by clear");
|
||||
|
||||
// The `registered` latch must not block this re-registration.
|
||||
registerBuiltinCompressionEngines();
|
||||
assert.ok(getCompressionEngine("rtk"), "builtins must repopulate after a clear");
|
||||
assert.ok(getCompressionEngine("session-dedup"), "all builtins restored, not just one");
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,135 @@
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
|
||||
import {
|
||||
stepEventsToRunModel,
|
||||
appendInFlightStep,
|
||||
clearInFlightOnComplete,
|
||||
} from "../../../src/app/(dashboard)/dashboard/compression/studio/compressionFlowModel.ts";
|
||||
import { applyStackedCompression } from "../../../open-sse/services/compression/strategySelector.ts";
|
||||
import { registerCompressionEngine } from "../../../open-sse/services/compression/index.ts";
|
||||
import type { CompressionEngine } from "../../../open-sse/services/compression/engines/types.ts";
|
||||
import type { CompressionStepPayload } from "../../../src/lib/events/types.ts";
|
||||
|
||||
function step(over: Partial<CompressionStepPayload>): CompressionStepPayload {
|
||||
return {
|
||||
requestId: "r1",
|
||||
comboId: null,
|
||||
mode: "stacked",
|
||||
stepIndex: 0,
|
||||
totalSteps: 2,
|
||||
engine: "e",
|
||||
state: "done",
|
||||
originalTokens: 1000,
|
||||
compressedTokens: 800,
|
||||
savingsPercent: 20,
|
||||
timestamp: 1,
|
||||
...over,
|
||||
};
|
||||
}
|
||||
|
||||
describe("stepEventsToRunModel", () => {
|
||||
it("builds a run model from accumulated step events (run-level totals span first→last)", () => {
|
||||
const model = stepEventsToRunModel([
|
||||
step({ engine: "a", stepIndex: 0, originalTokens: 1000, compressedTokens: 900, savingsPercent: 10, timestamp: 1 }),
|
||||
step({ engine: "b", stepIndex: 1, originalTokens: 900, compressedTokens: 700, savingsPercent: 22, timestamp: 2 }),
|
||||
]);
|
||||
assert.equal(model.requestId, "r1");
|
||||
assert.equal(model.mode, "stacked");
|
||||
assert.equal(model.originalTokens, 1000); // first step's input
|
||||
assert.equal(model.compressedTokens, 700); // last step's output
|
||||
assert.equal(model.savingsPercent, 30); // (1000-700)/1000
|
||||
assert.equal(model.steps.length, 2);
|
||||
assert.equal(model.steps[1].engine, "b");
|
||||
assert.equal(model.timestamp, 2);
|
||||
});
|
||||
});
|
||||
|
||||
describe("in-flight step reducer", () => {
|
||||
it("appends steps for the same requestId and starts fresh on a new requestId", () => {
|
||||
let s = appendInFlightStep(null, step({ requestId: "r1", engine: "a" }));
|
||||
assert.equal(s.requestId, "r1");
|
||||
assert.equal(s.steps.length, 1);
|
||||
s = appendInFlightStep(s, step({ requestId: "r1", engine: "b" }));
|
||||
assert.equal(s.steps.length, 2);
|
||||
// A new requestId replaces the in-flight run (latest wins).
|
||||
s = appendInFlightStep(s, step({ requestId: "r2", engine: "x" }));
|
||||
assert.equal(s.requestId, "r2");
|
||||
assert.equal(s.steps.length, 1);
|
||||
});
|
||||
|
||||
it("clears the in-flight run only when the completing requestId matches", () => {
|
||||
const s = appendInFlightStep(null, step({ requestId: "r1" }));
|
||||
assert.equal(clearInFlightOnComplete(s, "other"), s);
|
||||
assert.equal(clearInFlightOnComplete(s, "r1"), null);
|
||||
});
|
||||
});
|
||||
|
||||
// ── Integration: applyStackedCompression emits a step per engine ───────────────
|
||||
function fakeEngine(id: string, compressed: boolean, orig: number, comp: number): CompressionEngine {
|
||||
return {
|
||||
id,
|
||||
name: id,
|
||||
description: "",
|
||||
icon: "",
|
||||
targets: ["messages"],
|
||||
stackable: true,
|
||||
stackPriority: 1,
|
||||
metadata: {
|
||||
id,
|
||||
name: id,
|
||||
description: "",
|
||||
inputScope: "messages",
|
||||
targetLatencyMs: 1,
|
||||
supportsPreview: false,
|
||||
stable: false,
|
||||
},
|
||||
apply(body) {
|
||||
return {
|
||||
body,
|
||||
compressed,
|
||||
stats: {
|
||||
originalTokens: orig,
|
||||
compressedTokens: comp,
|
||||
savingsPercent: orig > 0 ? Math.round(((orig - comp) / orig) * 100) : 0,
|
||||
techniquesUsed: [],
|
||||
mode: "stacked",
|
||||
timestamp: 0,
|
||||
durationMs: 2,
|
||||
},
|
||||
};
|
||||
},
|
||||
compress(body) {
|
||||
return this.apply(body);
|
||||
},
|
||||
getConfigSchema() {
|
||||
return [];
|
||||
},
|
||||
validateConfig() {
|
||||
return { valid: true, errors: [] };
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
describe("applyStackedCompression — onEngineStep emission", () => {
|
||||
it("fires onEngineStep once per engine with index/total/state", () => {
|
||||
registerCompressionEngine(fakeEngine("step-e1", true, 1000, 900));
|
||||
registerCompressionEngine(fakeEngine("step-e2", false, 900, 900));
|
||||
|
||||
const captured: Array<{ stepIndex: number; totalSteps: number; engine: string; state: string }> = [];
|
||||
applyStackedCompression(
|
||||
{ messages: [{ role: "user", content: "hello" }] },
|
||||
[{ engine: "step-e1" }, { engine: "step-e2" }],
|
||||
{ onEngineStep: (s) => captured.push(s) }
|
||||
);
|
||||
|
||||
assert.equal(captured.length, 2, "one step per engine");
|
||||
assert.equal(captured[0].engine, "step-e1");
|
||||
assert.equal(captured[0].stepIndex, 0);
|
||||
assert.equal(captured[0].totalSteps, 2);
|
||||
assert.equal(captured[0].state, "done");
|
||||
assert.equal(captured[1].engine, "step-e2");
|
||||
assert.equal(captured[1].stepIndex, 1);
|
||||
assert.equal(captured[1].state, "skipped");
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,36 @@
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import {
|
||||
readMcpToolProfileFromEnv,
|
||||
reduceToolManifest,
|
||||
} from "../../../open-sse/mcp-server/toolCardinality.ts";
|
||||
|
||||
// F4.3 wiring: the MCP server now consults an opt-in tool profile (MCP_TOOL_DENY / MCP_TOOL_ALLOW)
|
||||
// and disables denied tools so they are not announced to the model (token savings). Default (no
|
||||
// env) is a no-op — every tool stays registered.
|
||||
describe("MCP tool profile from env (cardinality opt-in)", () => {
|
||||
it("returns null when no deny/allow env is set (no-op)", () => {
|
||||
assert.equal(readMcpToolProfileFromEnv({}), null);
|
||||
assert.equal(readMcpToolProfileFromEnv({ MCP_TOOL_DENY: "", MCP_TOOL_ALLOW: " " }), null);
|
||||
});
|
||||
|
||||
it("parses MCP_TOOL_DENY / MCP_TOOL_ALLOW into a profile (trimmed, empties dropped)", () => {
|
||||
const p = readMcpToolProfileFromEnv({ MCP_TOOL_DENY: "a, b ,c", MCP_TOOL_ALLOW: "x ," });
|
||||
assert.deepEqual(p?.denyTools, ["a", "b", "c"]);
|
||||
assert.deepEqual(p?.allowTools, ["x"]);
|
||||
});
|
||||
|
||||
it("the deny gate drops a denied tool and keeps others (single-entry manifest decision)", () => {
|
||||
const profile = readMcpToolProfileFromEnv({ MCP_TOOL_DENY: "noisy_tool" });
|
||||
assert.ok(profile);
|
||||
assert.equal(reduceToolManifest([{ name: "noisy_tool", scopes: [] }], profile).length, 0);
|
||||
assert.equal(reduceToolManifest([{ name: "useful_tool", scopes: [] }], profile).length, 1);
|
||||
});
|
||||
|
||||
it("allow-list mode keeps only the listed tools", () => {
|
||||
const profile = readMcpToolProfileFromEnv({ MCP_TOOL_ALLOW: "keep_me" });
|
||||
assert.ok(profile);
|
||||
assert.equal(reduceToolManifest([{ name: "keep_me", scopes: [] }], profile).length, 1);
|
||||
assert.equal(reduceToolManifest([{ name: "other", scopes: [] }], profile).length, 0);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,454 @@
|
||||
import { describe, it, before, beforeEach, after } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { mkdtempSync, rmSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
|
||||
const tmpDir = mkdtempSync(join(tmpdir(), "omniroute-test-"));
|
||||
process.env.DATA_DIR = tmpDir;
|
||||
|
||||
const core = await import("../../../src/lib/db/core.ts");
|
||||
core.resetDbInstance();
|
||||
const { insertCompressionAnalyticsRow, getCompressionAnalyticsSummary } =
|
||||
await import("../../../src/lib/db/compressionAnalytics.ts");
|
||||
const { attachCompressionUsageReceipt } =
|
||||
await import("../../../src/lib/db/compressionAnalytics.ts");
|
||||
const { getDbInstance } = core;
|
||||
|
||||
describe("compressionAnalytics", () => {
|
||||
before(() => {
|
||||
const db = getDbInstance();
|
||||
db.exec(`
|
||||
CREATE TABLE IF NOT EXISTS compression_analytics (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
timestamp TEXT NOT NULL,
|
||||
combo_id TEXT,
|
||||
provider TEXT,
|
||||
mode TEXT NOT NULL,
|
||||
original_tokens INTEGER NOT NULL,
|
||||
compressed_tokens INTEGER NOT NULL,
|
||||
tokens_saved INTEGER NOT NULL,
|
||||
duration_ms INTEGER,
|
||||
request_id TEXT
|
||||
)
|
||||
`);
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
// Clear table before each test for full isolation
|
||||
const db = getDbInstance();
|
||||
db.exec("DELETE FROM compression_analytics");
|
||||
});
|
||||
|
||||
after(() => {
|
||||
core.closeDbInstance();
|
||||
rmSync(tmpDir, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
it("empty table returns zeroed summary", () => {
|
||||
const summary = getCompressionAnalyticsSummary();
|
||||
assert.deepEqual(summary, {
|
||||
totalRequests: 0,
|
||||
totalTokensSaved: 0,
|
||||
avgSavingsPct: 0,
|
||||
avgDurationMs: 0,
|
||||
byMode: {},
|
||||
byEngine: {},
|
||||
byCompressionCombo: {},
|
||||
byProvider: {},
|
||||
last24h: summary.last24h,
|
||||
totalSkipped: 0,
|
||||
bySkipReason: {},
|
||||
validationFallbacks: 0,
|
||||
realUsage: {
|
||||
requestsWithReceipts: 0,
|
||||
promptTokens: 0,
|
||||
completionTokens: 0,
|
||||
totalTokens: 0,
|
||||
cacheReadTokens: 0,
|
||||
cacheWriteTokens: 0,
|
||||
estimatedUsdSaved: 0,
|
||||
bySource: {},
|
||||
},
|
||||
mcpDescriptionCompression: {
|
||||
snapshots: 0,
|
||||
estimatedTokensSaved: 0,
|
||||
},
|
||||
});
|
||||
assert.equal(summary.last24h.length, 24);
|
||||
});
|
||||
|
||||
it("insert single row does not throw", () => {
|
||||
const row = {
|
||||
timestamp: new Date().toISOString(),
|
||||
mode: "lite",
|
||||
original_tokens: 1000,
|
||||
compressed_tokens: 800,
|
||||
tokens_saved: 200,
|
||||
};
|
||||
assert.doesNotThrow(() => insertCompressionAnalyticsRow(row));
|
||||
const summary = getCompressionAnalyticsSummary();
|
||||
assert.equal(summary.totalRequests, 1);
|
||||
});
|
||||
|
||||
it("stores all RTK raw output pointers when provided", () => {
|
||||
insertCompressionAnalyticsRow({
|
||||
timestamp: new Date().toISOString(),
|
||||
mode: "rtk",
|
||||
original_tokens: 1000,
|
||||
compressed_tokens: 500,
|
||||
tokens_saved: 500,
|
||||
rtk_raw_output_pointer: "raw_1",
|
||||
rtk_raw_output_bytes: 100,
|
||||
rtk_raw_output_pointers: JSON.stringify(["raw_1", "raw_2"]),
|
||||
rtk_raw_output_total_bytes: 250,
|
||||
});
|
||||
|
||||
const db = getDbInstance();
|
||||
const row = db
|
||||
.prepare(
|
||||
"SELECT rtk_raw_output_pointer, rtk_raw_output_bytes, rtk_raw_output_pointers, rtk_raw_output_total_bytes FROM compression_analytics LIMIT 1"
|
||||
)
|
||||
.get() as {
|
||||
rtk_raw_output_pointer: string;
|
||||
rtk_raw_output_bytes: number;
|
||||
rtk_raw_output_pointers: string;
|
||||
rtk_raw_output_total_bytes: number;
|
||||
};
|
||||
|
||||
assert.equal(row.rtk_raw_output_pointer, "raw_1");
|
||||
assert.equal(row.rtk_raw_output_bytes, 100);
|
||||
assert.equal(row.rtk_raw_output_pointers, JSON.stringify(["raw_1", "raw_2"]));
|
||||
assert.equal(row.rtk_raw_output_total_bytes, 250);
|
||||
});
|
||||
|
||||
it("summary counts correctly after multiple inserts", () => {
|
||||
insertCompressionAnalyticsRow({
|
||||
timestamp: new Date().toISOString(),
|
||||
mode: "lite",
|
||||
original_tokens: 1000,
|
||||
compressed_tokens: 800,
|
||||
tokens_saved: 200,
|
||||
});
|
||||
insertCompressionAnalyticsRow({
|
||||
timestamp: new Date().toISOString(),
|
||||
mode: "standard",
|
||||
original_tokens: 300,
|
||||
compressed_tokens: 280,
|
||||
tokens_saved: 20,
|
||||
});
|
||||
insertCompressionAnalyticsRow({
|
||||
timestamp: new Date().toISOString(),
|
||||
mode: "aggressive",
|
||||
original_tokens: 500,
|
||||
compressed_tokens: 400,
|
||||
tokens_saved: 100,
|
||||
});
|
||||
const summary = getCompressionAnalyticsSummary();
|
||||
assert.equal(summary.totalRequests, 3);
|
||||
});
|
||||
|
||||
it("totalTokensSaved sums correctly", () => {
|
||||
insertCompressionAnalyticsRow({
|
||||
timestamp: new Date().toISOString(),
|
||||
mode: "lite",
|
||||
original_tokens: 1000,
|
||||
compressed_tokens: 800,
|
||||
tokens_saved: 200,
|
||||
});
|
||||
insertCompressionAnalyticsRow({
|
||||
timestamp: new Date().toISOString(),
|
||||
mode: "standard",
|
||||
original_tokens: 300,
|
||||
compressed_tokens: 280,
|
||||
tokens_saved: 20,
|
||||
});
|
||||
const summary = getCompressionAnalyticsSummary();
|
||||
assert.equal(summary.totalTokensSaved, 220);
|
||||
});
|
||||
|
||||
it("byMode groups correctly", () => {
|
||||
insertCompressionAnalyticsRow({
|
||||
timestamp: new Date().toISOString(),
|
||||
mode: "lite",
|
||||
original_tokens: 1000,
|
||||
compressed_tokens: 800,
|
||||
tokens_saved: 200,
|
||||
});
|
||||
insertCompressionAnalyticsRow({
|
||||
timestamp: new Date().toISOString(),
|
||||
mode: "lite",
|
||||
original_tokens: 500,
|
||||
compressed_tokens: 400,
|
||||
tokens_saved: 100,
|
||||
});
|
||||
insertCompressionAnalyticsRow({
|
||||
timestamp: new Date().toISOString(),
|
||||
mode: "standard",
|
||||
original_tokens: 300,
|
||||
compressed_tokens: 270,
|
||||
tokens_saved: 30,
|
||||
});
|
||||
const summary = getCompressionAnalyticsSummary();
|
||||
assert.equal(summary.byMode["lite"].count, 2);
|
||||
assert.equal(summary.byMode["lite"].tokensSaved, 300);
|
||||
assert.equal(summary.byMode["standard"].count, 1);
|
||||
});
|
||||
|
||||
it("byProvider groups correctly", () => {
|
||||
insertCompressionAnalyticsRow({
|
||||
timestamp: new Date().toISOString(),
|
||||
mode: "lite",
|
||||
original_tokens: 1000,
|
||||
compressed_tokens: 800,
|
||||
tokens_saved: 200,
|
||||
provider: "ProviderA",
|
||||
});
|
||||
insertCompressionAnalyticsRow({
|
||||
timestamp: new Date().toISOString(),
|
||||
mode: "lite",
|
||||
original_tokens: 500,
|
||||
compressed_tokens: 400,
|
||||
tokens_saved: 100,
|
||||
provider: "ProviderB",
|
||||
});
|
||||
const summary = getCompressionAnalyticsSummary();
|
||||
assert.deepEqual(summary.byProvider["ProviderA"], { count: 1, tokensSaved: 200 });
|
||||
assert.deepEqual(summary.byProvider["ProviderB"], { count: 1, tokensSaved: 100 });
|
||||
});
|
||||
|
||||
it("since=24h filters rows older than 24h", () => {
|
||||
const oldTimestamp = new Date(Date.now() - 48 * 60 * 60 * 1000).toISOString();
|
||||
const recentTimestamp = new Date().toISOString();
|
||||
|
||||
insertCompressionAnalyticsRow({
|
||||
timestamp: oldTimestamp,
|
||||
mode: "lite",
|
||||
original_tokens: 2000,
|
||||
compressed_tokens: 1800,
|
||||
tokens_saved: 200,
|
||||
});
|
||||
insertCompressionAnalyticsRow({
|
||||
timestamp: recentTimestamp,
|
||||
mode: "lite",
|
||||
original_tokens: 1000,
|
||||
compressed_tokens: 900,
|
||||
tokens_saved: 100,
|
||||
});
|
||||
|
||||
const summary24h = getCompressionAnalyticsSummary("24h");
|
||||
assert.equal(summary24h.totalRequests, 1);
|
||||
assert.equal(summary24h.totalTokensSaved, 100);
|
||||
});
|
||||
|
||||
it("since=undefined returns all rows including old ones", () => {
|
||||
const oldTimestamp = new Date(Date.now() - 48 * 60 * 60 * 1000).toISOString();
|
||||
const recentTimestamp = new Date().toISOString();
|
||||
|
||||
insertCompressionAnalyticsRow({
|
||||
timestamp: oldTimestamp,
|
||||
mode: "lite",
|
||||
original_tokens: 2000,
|
||||
compressed_tokens: 1800,
|
||||
tokens_saved: 200,
|
||||
});
|
||||
insertCompressionAnalyticsRow({
|
||||
timestamp: recentTimestamp,
|
||||
mode: "lite",
|
||||
original_tokens: 1000,
|
||||
compressed_tokens: 900,
|
||||
tokens_saved: 100,
|
||||
});
|
||||
|
||||
const summaryAll = getCompressionAnalyticsSummary();
|
||||
assert.equal(summaryAll.totalRequests, 2);
|
||||
assert.equal(summaryAll.totalTokensSaved, 300);
|
||||
});
|
||||
|
||||
it("avgSavingsPct calculates correctly", () => {
|
||||
// 200/1000 = 20%, 100/500 = 20% → avg = 20%
|
||||
insertCompressionAnalyticsRow({
|
||||
timestamp: new Date().toISOString(),
|
||||
mode: "lite",
|
||||
original_tokens: 1000,
|
||||
compressed_tokens: 800,
|
||||
tokens_saved: 200,
|
||||
});
|
||||
insertCompressionAnalyticsRow({
|
||||
timestamp: new Date().toISOString(),
|
||||
mode: "standard",
|
||||
original_tokens: 500,
|
||||
compressed_tokens: 400,
|
||||
tokens_saved: 100,
|
||||
});
|
||||
const summary = getCompressionAnalyticsSummary();
|
||||
assert.equal(summary.avgSavingsPct, 20);
|
||||
});
|
||||
|
||||
it("last24h hourly buckets have correct shape", () => {
|
||||
insertCompressionAnalyticsRow({
|
||||
timestamp: new Date().toISOString(),
|
||||
mode: "lite",
|
||||
original_tokens: 1000,
|
||||
compressed_tokens: 800,
|
||||
tokens_saved: 200,
|
||||
});
|
||||
const hourly = getCompressionAnalyticsSummary("24h").last24h;
|
||||
assert(Array.isArray(hourly));
|
||||
assert(hourly.length <= 24);
|
||||
hourly.forEach((bucket) => {
|
||||
assert(typeof bucket.hour === "string");
|
||||
assert(typeof bucket.count === "number");
|
||||
assert(typeof bucket.tokensSaved === "number");
|
||||
});
|
||||
});
|
||||
|
||||
it("attaches real usage receipts to the latest compression row", () => {
|
||||
insertCompressionAnalyticsRow({
|
||||
timestamp: new Date().toISOString(),
|
||||
mode: "standard",
|
||||
original_tokens: 1000,
|
||||
compressed_tokens: 700,
|
||||
tokens_saved: 300,
|
||||
request_id: "req-receipt",
|
||||
});
|
||||
attachCompressionUsageReceipt(
|
||||
"req-receipt",
|
||||
{
|
||||
prompt_tokens: 710,
|
||||
completion_tokens: 42,
|
||||
total_tokens: 752,
|
||||
prompt_tokens_details: { cached_tokens: 100, cache_creation_tokens: 12 },
|
||||
},
|
||||
"provider"
|
||||
);
|
||||
const summary = getCompressionAnalyticsSummary();
|
||||
assert.equal(summary.realUsage.requestsWithReceipts, 1);
|
||||
assert.equal(summary.realUsage.promptTokens, 710);
|
||||
assert.equal(summary.realUsage.completionTokens, 42);
|
||||
assert.equal(summary.realUsage.totalTokens, 752);
|
||||
assert.equal(summary.realUsage.cacheReadTokens, 100);
|
||||
assert.equal(summary.realUsage.cacheWriteTokens, 12);
|
||||
assert.equal(summary.realUsage.bySource.provider, 1);
|
||||
});
|
||||
|
||||
it("aggregates estimated USD savings separately from token estimates", () => {
|
||||
insertCompressionAnalyticsRow({
|
||||
timestamp: new Date().toISOString(),
|
||||
mode: "standard",
|
||||
original_tokens: 1000,
|
||||
compressed_tokens: 700,
|
||||
tokens_saved: 300,
|
||||
request_id: "req-usd",
|
||||
estimated_usd_saved: 0.0015,
|
||||
});
|
||||
attachCompressionUsageReceipt("req-usd", { prompt_tokens: 700, total_tokens: 700 }, "provider");
|
||||
|
||||
const summary = getCompressionAnalyticsSummary();
|
||||
assert.equal(summary.realUsage.requestsWithReceipts, 1);
|
||||
assert.equal(summary.realUsage.estimatedUsdSaved, 0.0015);
|
||||
});
|
||||
|
||||
it("summarizes validation fallback and output mode rows", () => {
|
||||
insertCompressionAnalyticsRow({
|
||||
timestamp: new Date().toISOString(),
|
||||
mode: "output-caveman",
|
||||
original_tokens: 900,
|
||||
compressed_tokens: 900,
|
||||
tokens_saved: 0,
|
||||
request_id: "req-output",
|
||||
validation_fallback: true,
|
||||
output_mode: "full",
|
||||
});
|
||||
attachCompressionUsageReceipt(
|
||||
"req-output",
|
||||
{ prompt_tokens: 900, completion_tokens: 120, total_tokens: 1020 },
|
||||
"provider"
|
||||
);
|
||||
|
||||
const summary = getCompressionAnalyticsSummary();
|
||||
assert.equal(summary.validationFallbacks, 1);
|
||||
assert.equal(summary.byMode["output-caveman"].count, 1);
|
||||
assert.equal(summary.realUsage.requestsWithReceipts, 1);
|
||||
assert.equal(summary.realUsage.totalTokens, 1020);
|
||||
});
|
||||
|
||||
it("summarizes MCP description estimates without counting them as provider receipts", () => {
|
||||
insertCompressionAnalyticsRow({
|
||||
timestamp: new Date().toISOString(),
|
||||
mode: "mcp-description",
|
||||
engine: "mcp-description",
|
||||
original_tokens: 20,
|
||||
compressed_tokens: 12,
|
||||
tokens_saved: 8,
|
||||
mcp_description_tokens_saved: 8,
|
||||
});
|
||||
|
||||
const summary = getCompressionAnalyticsSummary();
|
||||
assert.equal(summary.mcpDescriptionCompression.snapshots, 1);
|
||||
assert.equal(summary.mcpDescriptionCompression.estimatedTokensSaved, 8);
|
||||
assert.equal(summary.realUsage.requestsWithReceipts, 0);
|
||||
assert.equal(summary.realUsage.bySource.mcp_metadata_estimate, undefined);
|
||||
});
|
||||
|
||||
// #4268: attempted-but-no-op runs are recorded with skip_reason so Stacked is
|
||||
// visible even when it saves nothing, while saving aggregates stay net-saving-only.
|
||||
it("records skipped (no-op) runs separately without polluting saving aggregates", () => {
|
||||
// One real saving run...
|
||||
insertCompressionAnalyticsRow({
|
||||
timestamp: new Date().toISOString(),
|
||||
mode: "stacked",
|
||||
original_tokens: 1000,
|
||||
compressed_tokens: 600,
|
||||
tokens_saved: 400,
|
||||
});
|
||||
// ...and two no-op stacked attempts (saved nothing).
|
||||
insertCompressionAnalyticsRow({
|
||||
timestamp: new Date().toISOString(),
|
||||
mode: "stacked",
|
||||
original_tokens: 500,
|
||||
compressed_tokens: 500,
|
||||
tokens_saved: 0,
|
||||
skip_reason: "no_savings",
|
||||
});
|
||||
insertCompressionAnalyticsRow({
|
||||
timestamp: new Date().toISOString(),
|
||||
mode: "stacked",
|
||||
original_tokens: 800,
|
||||
compressed_tokens: 800,
|
||||
tokens_saved: 0,
|
||||
skip_reason: "no_savings",
|
||||
});
|
||||
|
||||
const summary = getCompressionAnalyticsSummary();
|
||||
|
||||
// Saving aggregates count the net-saving run ONLY (skip rows excluded).
|
||||
assert.equal(summary.totalRequests, 1, "totalRequests must exclude skip rows");
|
||||
assert.equal(summary.totalTokensSaved, 400);
|
||||
assert.equal(summary.byMode.stacked.count, 1, "byMode count excludes skip rows");
|
||||
assert.equal(summary.byMode.stacked.tokensSaved, 400);
|
||||
|
||||
// ...but the skips are now visible instead of dropped.
|
||||
assert.equal(summary.byMode.stacked.skipped, 2, "skipped attempts surfaced per mode");
|
||||
assert.equal(summary.totalSkipped, 2);
|
||||
assert.equal(summary.bySkipReason.no_savings, 2);
|
||||
});
|
||||
|
||||
it("a mode with only no-op runs still appears (count 0, skipped > 0)", () => {
|
||||
insertCompressionAnalyticsRow({
|
||||
timestamp: new Date().toISOString(),
|
||||
mode: "stacked",
|
||||
original_tokens: 300,
|
||||
compressed_tokens: 300,
|
||||
tokens_saved: 0,
|
||||
skip_reason: "no_savings",
|
||||
});
|
||||
|
||||
const summary = getCompressionAnalyticsSummary();
|
||||
assert.equal(summary.totalRequests, 0, "no net-saving runs");
|
||||
assert.ok(summary.byMode.stacked, "stacked must appear even with only skip rows");
|
||||
assert.equal(summary.byMode.stacked.count, 0);
|
||||
assert.equal(summary.byMode.stacked.skipped, 1);
|
||||
assert.equal(summary.totalSkipped, 1);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,90 @@
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import {
|
||||
formatCompressionAnnotation,
|
||||
formatCompressionMeta,
|
||||
} from "../../../open-sse/services/compression/planResolution.ts";
|
||||
import type { CompressionStats } from "../../../open-sse/services/compression/types.ts";
|
||||
|
||||
function makeStats(overrides: Partial<CompressionStats> = {}): CompressionStats {
|
||||
return {
|
||||
originalTokens: 847,
|
||||
compressedTokens: 312,
|
||||
savingsPercent: 63.16,
|
||||
techniquesUsed: ["caveman"],
|
||||
mode: "standard",
|
||||
timestamp: 0,
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
describe("formatCompressionAnnotation", () => {
|
||||
it("returns empty string when no rulesApplied and no techniquesUsed", () => {
|
||||
const stats = makeStats({ rulesApplied: [], techniquesUsed: [] });
|
||||
assert.equal(formatCompressionAnnotation(stats), "");
|
||||
});
|
||||
|
||||
it("returns empty string when rulesApplied is absent", () => {
|
||||
const stats = makeStats({ rulesApplied: undefined, techniquesUsed: [] });
|
||||
assert.equal(formatCompressionAnnotation(stats), "");
|
||||
});
|
||||
|
||||
it("aggregates rulesApplied counts deterministically", () => {
|
||||
const stats = makeStats({
|
||||
rulesApplied: ["filler", "filler", "filler", "filler", "filler", "filler", "filler", "filler", "dedup", "dedup"],
|
||||
techniquesUsed: ["caveman"],
|
||||
});
|
||||
const result = formatCompressionAnnotation(stats);
|
||||
assert.ok(result.includes("tokens=847->312"), `missing token range in: ${result}`);
|
||||
assert.ok(result.includes("fillerx8"), `missing fillerx8 in: ${result}`);
|
||||
assert.ok(result.includes("dedupx2"), `missing dedupx2 in: ${result}`);
|
||||
});
|
||||
|
||||
it("is ASCII-only so it survives HTTP header (X-OmniRoute-Compression) construction", () => {
|
||||
// Regression: the annotation is appended to the X-OmniRoute-Compression response
|
||||
// header, a latin-1 ByteString. A non-ASCII char (e.g. U+2192 →) throws at
|
||||
// Headers/Response construction → 500 on every compressed response with rules.
|
||||
const stats = makeStats({
|
||||
rulesApplied: ["filler", "filler", "dedup"],
|
||||
techniquesUsed: ["caveman"],
|
||||
});
|
||||
const value = `standard; source=auto; ${formatCompressionAnnotation(stats)}`;
|
||||
for (const ch of value) {
|
||||
assert.ok(ch.codePointAt(0)! <= 0xff, `non-latin1 char ${JSON.stringify(ch)} in header value: ${value}`);
|
||||
}
|
||||
// Must not throw at real Headers/Response construction.
|
||||
assert.doesNotThrow(() => new Headers({ "X-OmniRoute-Compression": value }));
|
||||
const res = new Response(null, { headers: { "X-OmniRoute-Compression": value } });
|
||||
assert.equal(res.headers.get("X-OmniRoute-Compression"), value);
|
||||
});
|
||||
|
||||
it("orders rule counts descending by count", () => {
|
||||
const stats = makeStats({
|
||||
rulesApplied: ["dedup", "filler", "filler", "filler"],
|
||||
techniquesUsed: [],
|
||||
});
|
||||
const result = formatCompressionAnnotation(stats);
|
||||
const fillerIdx = result.indexOf("fillerx3");
|
||||
const dedupIdx = result.indexOf("dedupx1");
|
||||
assert.ok(fillerIdx < dedupIdx, `filler (count=3) should appear before dedup (count=1): ${result}`);
|
||||
});
|
||||
|
||||
it("is deterministic (same input → same output)", () => {
|
||||
const stats = makeStats({
|
||||
rulesApplied: ["filler", "dedup", "filler"],
|
||||
techniquesUsed: [],
|
||||
});
|
||||
assert.equal(formatCompressionAnnotation(stats), formatCompressionAnnotation(stats));
|
||||
});
|
||||
|
||||
it("prefix mode; source=X is never mutated by appending the annotation", () => {
|
||||
const plan = { mode: "standard" as const, stackedPipeline: [], source: "auto" as const };
|
||||
const prefix = formatCompressionMeta(plan);
|
||||
assert.equal(prefix, "standard; source=auto");
|
||||
|
||||
const stats = makeStats({ rulesApplied: ["filler", "dedup"], techniquesUsed: [] });
|
||||
const annotation = formatCompressionAnnotation(stats);
|
||||
const combined = `${prefix}; ${annotation}`;
|
||||
assert.ok(combined.startsWith("standard; source=auto"), `prefix mutated: ${combined}`);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,42 @@
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
|
||||
import {
|
||||
type DashboardChannel,
|
||||
CHANNEL_EVENTS,
|
||||
getChannelForEvent,
|
||||
} from "../../../src/lib/events/types.ts";
|
||||
|
||||
describe("compression WS channel (U5)", () => {
|
||||
it("DashboardChannel includes 'compression'", () => {
|
||||
// The type must include 'compression' — we verify it at runtime by ensuring
|
||||
// CHANNEL_EVENTS has the key (TypeScript narrows keys to DashboardChannel).
|
||||
const channels = Object.keys(CHANNEL_EVENTS) as DashboardChannel[];
|
||||
assert.ok(
|
||||
channels.includes("compression" as DashboardChannel),
|
||||
"CHANNEL_EVENTS must have a 'compression' key"
|
||||
);
|
||||
});
|
||||
|
||||
it("CHANNEL_EVENTS.compression contains 'compression.completed'", () => {
|
||||
const events = (CHANNEL_EVENTS as Record<string, string[]>)["compression"];
|
||||
assert.ok(Array.isArray(events), "CHANNEL_EVENTS.compression should be an array");
|
||||
assert.ok(
|
||||
events.includes("compression.completed"),
|
||||
"compression channel must list 'compression.completed'"
|
||||
);
|
||||
});
|
||||
|
||||
it("getChannelForEvent maps 'compression.completed' → 'compression'", () => {
|
||||
const channel = getChannelForEvent(
|
||||
"compression.completed" as Parameters<typeof getChannelForEvent>[0]
|
||||
);
|
||||
assert.equal(channel, "compression");
|
||||
});
|
||||
|
||||
it("existing channels still route correctly", () => {
|
||||
assert.equal(getChannelForEvent("request.started"), "requests");
|
||||
assert.equal(getChannelForEvent("combo.target.attempt"), "combo");
|
||||
assert.equal(getChannelForEvent("credential.health.changed"), "credentials");
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,180 @@
|
||||
import { describe, it, before } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { mkdtempSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
|
||||
const tmpDir = mkdtempSync(join(tmpdir(), "omniroute-mcp-test-"));
|
||||
process.env.DATA_DIR = tmpDir;
|
||||
|
||||
const {
|
||||
handleCompressionStatus,
|
||||
handleCompressionConfigure,
|
||||
handleSetCompressionEngine,
|
||||
handleListCompressionCombos,
|
||||
handleCompressionComboStats,
|
||||
} = await import("../../../open-sse/mcp-server/tools/compressionTools.ts");
|
||||
const {
|
||||
compressionConfigureTool,
|
||||
compressionStatusTool,
|
||||
setCompressionEngineTool,
|
||||
listCompressionCombosTool,
|
||||
compressionComboStatsTool,
|
||||
} = await import("../../../open-sse/mcp-server/schemas/tools.ts");
|
||||
const { maybeCompressMcpDescription, resetMcpDescriptionCompressionStats } =
|
||||
await import("../../../open-sse/mcp-server/descriptionCompressor.ts");
|
||||
|
||||
describe("compression MCP tool schemas", () => {
|
||||
it("uses canonical read/write compression scopes", () => {
|
||||
assert.deepEqual(compressionStatusTool.scopes, ["read:compression"]);
|
||||
assert.deepEqual(compressionConfigureTool.scopes, ["write:compression"]);
|
||||
assert.deepEqual(setCompressionEngineTool.scopes, ["write:compression"]);
|
||||
assert.deepEqual(listCompressionCombosTool.scopes, ["read:compression"]);
|
||||
assert.deepEqual(compressionComboStatsTool.scopes, ["read:compression"]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("handleCompressionStatus", () => {
|
||||
it("returns an object with enabled field", async () => {
|
||||
const result = await handleCompressionStatus({});
|
||||
assert.ok("enabled" in result);
|
||||
assert.equal(typeof result.enabled, "boolean");
|
||||
});
|
||||
|
||||
it("returns strategy string", async () => {
|
||||
const result = await handleCompressionStatus({});
|
||||
assert.equal(typeof result.strategy, "string");
|
||||
});
|
||||
|
||||
it("returns settings with maxTokens number", async () => {
|
||||
const result = await handleCompressionStatus({});
|
||||
assert.ok("settings" in result);
|
||||
assert.equal(typeof result.settings.maxTokens, "number");
|
||||
});
|
||||
|
||||
it("returns settings with targetRatio 0.7", async () => {
|
||||
const result = await handleCompressionStatus({});
|
||||
assert.equal(result.settings.targetRatio, 0.7);
|
||||
});
|
||||
|
||||
it("returns analytics with totalRequests number", async () => {
|
||||
const result = await handleCompressionStatus({});
|
||||
assert.ok("analytics" in result);
|
||||
assert.equal(typeof result.analytics.totalRequests, "number");
|
||||
});
|
||||
|
||||
it("returns analytics with tokensSaved number", async () => {
|
||||
const result = await handleCompressionStatus({});
|
||||
assert.equal(typeof result.analytics.tokensSaved, "number");
|
||||
});
|
||||
|
||||
it("returns cacheStats as null or object", async () => {
|
||||
const result = await handleCompressionStatus({});
|
||||
assert.ok(result.cacheStats === null || typeof result.cacheStats === "object");
|
||||
});
|
||||
|
||||
it("returns analytics compressedRequests as number", async () => {
|
||||
const result = await handleCompressionStatus({});
|
||||
assert.equal(typeof result.analytics.compressedRequests, "number");
|
||||
});
|
||||
|
||||
it("labels MCP description savings as metadata estimates, not provider usage", async () => {
|
||||
const result = await handleCompressionStatus({});
|
||||
assert.equal(result.analytics.mcpDescriptionCompression.source, "mcp_metadata_estimate");
|
||||
assert.equal(result.analytics.mcpDescriptionCompression.notProviderUsage, true);
|
||||
assert.equal(typeof result.analytics.mcpDescriptionCompression.charsBefore, "number");
|
||||
assert.equal(typeof result.analytics.mcpDescriptionCompression.charsAfter, "number");
|
||||
});
|
||||
|
||||
it("snapshots MCP description savings into analytics separately", async () => {
|
||||
resetMcpDescriptionCompressionStats();
|
||||
const compressed = maybeCompressMcpDescription(
|
||||
"The function returns the current weather for a city and the detailed forecast summary.",
|
||||
{ enabled: true }
|
||||
);
|
||||
assert.match(compressed, /weather/i);
|
||||
|
||||
const result = await handleCompressionStatus({});
|
||||
assert.ok(result.analytics.mcpDescriptionCompression.estimatedTokensSaved > 0);
|
||||
assert.ok(result.analytics.mcpDescriptionCompression.persistedEstimatedTokensSaved > 0);
|
||||
assert.ok(result.analytics.mcpDescriptionCompression.persistedSnapshots > 0);
|
||||
|
||||
const stats = await handleCompressionComboStats({ since: "all" });
|
||||
const mcp = stats.mcpDescriptionCompression as { estimatedTokensSaved?: number };
|
||||
const realUsage = stats.realUsage as { bySource?: Record<string, number> };
|
||||
assert.ok((mcp.estimatedTokensSaved ?? 0) > 0);
|
||||
assert.equal(realUsage.bySource?.mcp_metadata_estimate, undefined);
|
||||
});
|
||||
});
|
||||
|
||||
describe("handleCompressionConfigure", () => {
|
||||
it("returns success=true when called with empty args", async () => {
|
||||
const result = await handleCompressionConfigure({});
|
||||
assert.equal(result.success, true);
|
||||
});
|
||||
|
||||
it("returns settings object after configure", async () => {
|
||||
const result = await handleCompressionConfigure({});
|
||||
assert.ok("settings" in result);
|
||||
assert.equal(typeof result.settings.enabled, "boolean");
|
||||
});
|
||||
|
||||
it("returns updated object", async () => {
|
||||
const result = await handleCompressionConfigure({ enabled: true });
|
||||
assert.ok("updated" in result);
|
||||
});
|
||||
|
||||
it("sets enabled=false and returns success", async () => {
|
||||
const result = await handleCompressionConfigure({ enabled: false });
|
||||
assert.equal(result.success, true);
|
||||
});
|
||||
|
||||
it("sets strategy and returns success", async () => {
|
||||
const result = await handleCompressionConfigure({ strategy: "aggressive" });
|
||||
assert.equal(result.success, true);
|
||||
});
|
||||
|
||||
it("sets RTK and stacked strategies", async () => {
|
||||
const rtkResult = await handleCompressionConfigure({ strategy: "rtk" });
|
||||
const stackedResult = await handleCompressionConfigure({ strategy: "stacked" });
|
||||
assert.equal(rtkResult.success, true);
|
||||
assert.equal(stackedResult.success, true);
|
||||
});
|
||||
|
||||
it("sets maxTokens and returns success", async () => {
|
||||
const result = await handleCompressionConfigure({ maxTokens: 8000 });
|
||||
assert.equal(result.success, true);
|
||||
assert.ok("updated" in result);
|
||||
});
|
||||
|
||||
it("returns settings.maxTokens as number", async () => {
|
||||
const result = await handleCompressionConfigure({ maxTokens: 2000 });
|
||||
assert.equal(typeof result.settings.maxTokens, "number");
|
||||
});
|
||||
|
||||
it("returns settings.targetRatio as 0.7", async () => {
|
||||
const result = await handleCompressionConfigure({});
|
||||
assert.equal(result.settings.targetRatio, 0.7);
|
||||
});
|
||||
});
|
||||
|
||||
describe("compression MCP RTK/combo tools", () => {
|
||||
it("sets RTK engine through MCP", async () => {
|
||||
const result = await handleSetCompressionEngine({ engine: "rtk", rtkIntensity: "aggressive" });
|
||||
assert.equal(result.success, true);
|
||||
assert.equal(result.settings.defaultMode, "rtk");
|
||||
assert.equal((result.settings.rtkConfig as { intensity?: string }).intensity, "aggressive");
|
||||
});
|
||||
|
||||
it("lists compression combos", async () => {
|
||||
const result = await handleListCompressionCombos();
|
||||
assert.ok(Array.isArray(result.combos));
|
||||
assert.ok(result.combos.length >= 1);
|
||||
});
|
||||
|
||||
it("returns combo stats summary", async () => {
|
||||
const result = await handleCompressionComboStats({ since: "all" });
|
||||
assert.ok("byCompressionCombo" in result);
|
||||
assert.ok("byEngine" in result);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,56 @@
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
|
||||
import { rtkConfigSchema } from "../../../src/app/api/context/rtk/config/route.ts";
|
||||
import { rtkTestSchema } from "../../../src/app/api/context/rtk/test/route.ts";
|
||||
import { compressionComboCreateSchema } from "../../../src/app/api/context/combos/route.ts";
|
||||
import { compressionComboUpdateSchema } from "../../../src/app/api/context/combos/[id]/route.ts";
|
||||
import { assignmentsUpdateSchema } from "../../../src/app/api/context/combos/[id]/assignments/route.ts";
|
||||
|
||||
describe("context compression API schemas", () => {
|
||||
it("rejects invalid RTK config and test payloads", () => {
|
||||
assert.equal(rtkConfigSchema.safeParse({ intensity: "extreme" }).success, false);
|
||||
assert.equal(rtkConfigSchema.safeParse({ applyToCodeBlocks: true }).success, true);
|
||||
assert.equal(
|
||||
rtkConfigSchema.safeParse({
|
||||
customFiltersEnabled: true,
|
||||
trustProjectFilters: false,
|
||||
rawOutputRetention: "failures",
|
||||
rawOutputMaxBytes: 4096,
|
||||
}).success,
|
||||
true
|
||||
);
|
||||
assert.equal(rtkConfigSchema.safeParse({ rawOutputRetention: "plaintext" }).success, false);
|
||||
assert.equal(rtkTestSchema.safeParse({ text: "" }).success, false);
|
||||
assert.equal(rtkTestSchema.safeParse({ text: "ok", extra: true }).success, false);
|
||||
assert.equal(
|
||||
rtkTestSchema.safeParse({
|
||||
text: "ok",
|
||||
config: { maxLinesPerResult: -1, madeUp: true },
|
||||
}).success,
|
||||
false
|
||||
);
|
||||
});
|
||||
|
||||
it("rejects invalid compression combo payloads", () => {
|
||||
assert.equal(compressionComboCreateSchema.safeParse({ name: "" }).success, false);
|
||||
assert.equal(
|
||||
compressionComboCreateSchema.safeParse({
|
||||
name: "Stacked",
|
||||
pipeline: [{ engine: "rtk", intensity: "standard" }],
|
||||
}).success,
|
||||
true
|
||||
);
|
||||
assert.equal(compressionComboUpdateSchema.safeParse({ isDefault: true }).success, true);
|
||||
assert.equal(compressionComboUpdateSchema.safeParse({ pipeline: [] }).success, false);
|
||||
assert.equal(assignmentsUpdateSchema.safeParse({ routingComboIds: ["combo-a"] }).success, true);
|
||||
assert.equal(assignmentsUpdateSchema.safeParse({ routingComboIds: [""] }).success, false);
|
||||
assert.equal(
|
||||
compressionComboCreateSchema.safeParse({
|
||||
name: "Bad",
|
||||
pipeline: [{ engine: "rtk", intensity: "bogus" }],
|
||||
}).success,
|
||||
false
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,149 @@
|
||||
/**
|
||||
* tests/unit/compression/context-editing-telemetry.test.ts
|
||||
*
|
||||
* TDD for F4.1 — extractContextEditingTelemetry: pulls the server-side context
|
||||
* editing receipt (`applied_edits[].cleared_input_tokens` / `cleared_tool_uses`)
|
||||
* out of a Claude (Anthropic Messages) response body. Defensive over the exact
|
||||
* response shape: the array may live at `context_management.applied_edits`
|
||||
* (top-level) or nested under `usage` — we tolerate both rather than hardcode a
|
||||
* single guess (the spec's Task-1 caution).
|
||||
*
|
||||
* Run: node --import tsx/esm --test tests/unit/compression/context-editing-telemetry.test.ts
|
||||
*/
|
||||
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
|
||||
import { extractContextEditingTelemetry } from "../../../open-sse/config/contextEditing.ts";
|
||||
|
||||
describe("extractContextEditingTelemetry", () => {
|
||||
it("returns null for null/undefined/non-object bodies", () => {
|
||||
assert.equal(extractContextEditingTelemetry(null), null);
|
||||
assert.equal(extractContextEditingTelemetry(undefined), null);
|
||||
assert.equal(extractContextEditingTelemetry("nope"), null);
|
||||
assert.equal(extractContextEditingTelemetry(42), null);
|
||||
});
|
||||
|
||||
it("returns null when there is no context_management / applied_edits", () => {
|
||||
assert.equal(extractContextEditingTelemetry({ usage: { input_tokens: 10 } }), null);
|
||||
assert.equal(extractContextEditingTelemetry({ context_management: {} }), null);
|
||||
assert.equal(
|
||||
extractContextEditingTelemetry({ context_management: { applied_edits: [] } }),
|
||||
null
|
||||
);
|
||||
});
|
||||
|
||||
it("reads applied_edits from the top-level context_management object", () => {
|
||||
const body = {
|
||||
context_management: {
|
||||
applied_edits: [
|
||||
{ type: "clear_tool_uses_20250919", cleared_tool_uses: 8, cleared_input_tokens: 50000 },
|
||||
],
|
||||
},
|
||||
};
|
||||
const out = extractContextEditingTelemetry(body);
|
||||
assert.ok(out);
|
||||
assert.equal(out.editCount, 1);
|
||||
assert.equal(out.clearedInputTokens, 50000);
|
||||
assert.equal(out.clearedToolUses, 8);
|
||||
});
|
||||
|
||||
it("reads applied_edits nested under usage.context_management (alt shape)", () => {
|
||||
const body = {
|
||||
usage: {
|
||||
input_tokens: 120000,
|
||||
context_management: {
|
||||
applied_edits: [{ type: "clear_tool_uses_20250919", cleared_input_tokens: 30000 }],
|
||||
},
|
||||
},
|
||||
};
|
||||
const out = extractContextEditingTelemetry(body);
|
||||
assert.ok(out);
|
||||
assert.equal(out.clearedInputTokens, 30000);
|
||||
});
|
||||
|
||||
it("reads applied_edits directly under usage.applied_edits (alt shape)", () => {
|
||||
const body = {
|
||||
usage: {
|
||||
applied_edits: [{ type: "clear_tool_uses_20250919", cleared_input_tokens: 12345 }],
|
||||
},
|
||||
};
|
||||
const out = extractContextEditingTelemetry(body);
|
||||
assert.ok(out);
|
||||
assert.equal(out.clearedInputTokens, 12345);
|
||||
});
|
||||
|
||||
it("sums cleared tokens/tool_uses across multiple edits", () => {
|
||||
const body = {
|
||||
context_management: {
|
||||
applied_edits: [
|
||||
{ type: "clear_thinking_20251015", cleared_input_tokens: 4000, cleared_tool_uses: 0 },
|
||||
{ type: "clear_tool_uses_20250919", cleared_input_tokens: 6000, cleared_tool_uses: 5 },
|
||||
],
|
||||
},
|
||||
};
|
||||
const out = extractContextEditingTelemetry(body);
|
||||
assert.ok(out);
|
||||
assert.equal(out.editCount, 2);
|
||||
assert.equal(out.clearedInputTokens, 10000);
|
||||
assert.equal(out.clearedToolUses, 5);
|
||||
});
|
||||
|
||||
it("falls back to camelCase field names if present", () => {
|
||||
const body = {
|
||||
context_management: {
|
||||
applied_edits: [
|
||||
{ type: "clear_tool_uses_20250919", clearedInputTokens: 777, clearedToolUses: 2 },
|
||||
],
|
||||
},
|
||||
};
|
||||
const out = extractContextEditingTelemetry(body);
|
||||
assert.ok(out);
|
||||
assert.equal(out.clearedInputTokens, 777);
|
||||
assert.equal(out.clearedToolUses, 2);
|
||||
});
|
||||
|
||||
it("returns null when edits exist but cleared nothing (no real telemetry)", () => {
|
||||
const body = {
|
||||
context_management: {
|
||||
applied_edits: [
|
||||
{ type: "clear_tool_uses_20250919", cleared_input_tokens: 0, cleared_tool_uses: 0 },
|
||||
],
|
||||
},
|
||||
};
|
||||
assert.equal(extractContextEditingTelemetry(body), null);
|
||||
});
|
||||
|
||||
it("skips malformed (non-object) edit entries and still sums the valid ones", () => {
|
||||
const body = {
|
||||
context_management: {
|
||||
applied_edits: [
|
||||
null,
|
||||
"garbage",
|
||||
{ type: "clear_tool_uses_20250919", cleared_input_tokens: 999 },
|
||||
],
|
||||
},
|
||||
};
|
||||
const out = extractContextEditingTelemetry(body);
|
||||
assert.ok(out);
|
||||
assert.equal(out.clearedInputTokens, 999);
|
||||
});
|
||||
|
||||
it("coerces numeric strings and ignores non-numeric junk", () => {
|
||||
const body = {
|
||||
context_management: {
|
||||
applied_edits: [
|
||||
{
|
||||
type: "clear_tool_uses_20250919",
|
||||
cleared_input_tokens: "1500",
|
||||
cleared_tool_uses: "x",
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
const out = extractContextEditingTelemetry(body);
|
||||
assert.ok(out);
|
||||
assert.equal(out.clearedInputTokens, 1500);
|
||||
assert.equal(out.clearedToolUses, 0);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,104 @@
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
|
||||
import {
|
||||
applyContextEditingToBody,
|
||||
CLEAR_TOOL_USES_STRATEGY,
|
||||
CONTEXT_EDITING_DEFAULT_TRIGGER_TOKENS,
|
||||
CONTEXT_EDITING_DEFAULT_KEEP_TOOL_USES,
|
||||
} from "../../../open-sse/config/contextEditing.ts";
|
||||
|
||||
const CLEAR_THINKING_STRATEGY = "clear_thinking_20251015";
|
||||
|
||||
describe("applyContextEditingToBody", () => {
|
||||
it("does nothing when disabled", () => {
|
||||
const body: Record<string, unknown> = { model: "claude-opus-4-8" };
|
||||
applyContextEditingToBody(body, { enabled: false });
|
||||
assert.equal(body.context_management, undefined);
|
||||
});
|
||||
|
||||
it("is a no-op for null/non-object bodies", () => {
|
||||
// Should not throw.
|
||||
applyContextEditingToBody(null, { enabled: true });
|
||||
applyContextEditingToBody(undefined, { enabled: true });
|
||||
assert.ok(true);
|
||||
});
|
||||
|
||||
it("adds the clear_tool_uses edit with default trigger/keep on an empty body", () => {
|
||||
const body: Record<string, unknown> = { model: "claude-opus-4-8" };
|
||||
applyContextEditingToBody(body, { enabled: true });
|
||||
|
||||
const cm = body.context_management as Record<string, unknown>;
|
||||
assert.ok(cm, "context_management should be set");
|
||||
const edits = cm.edits as Array<Record<string, unknown>>;
|
||||
assert.equal(edits.length, 1);
|
||||
assert.deepEqual(edits[0], {
|
||||
type: CLEAR_TOOL_USES_STRATEGY,
|
||||
trigger: { type: "input_tokens", value: CONTEXT_EDITING_DEFAULT_TRIGGER_TOKENS },
|
||||
keep: { type: "tool_uses", value: CONTEXT_EDITING_DEFAULT_KEEP_TOOL_USES },
|
||||
});
|
||||
});
|
||||
|
||||
it("composes with an existing clear_thinking edit, keeping thinking FIRST", () => {
|
||||
const body: Record<string, unknown> = {
|
||||
model: "claude-opus-4-8",
|
||||
context_management: {
|
||||
edits: [{ type: CLEAR_THINKING_STRATEGY, keep: "all" }],
|
||||
},
|
||||
};
|
||||
applyContextEditingToBody(body, { enabled: true });
|
||||
|
||||
const edits = (body.context_management as Record<string, unknown>).edits as Array<
|
||||
Record<string, unknown>
|
||||
>;
|
||||
assert.equal(edits.length, 2);
|
||||
assert.equal(edits[0].type, CLEAR_THINKING_STRATEGY, "clear_thinking must be first");
|
||||
assert.equal(edits[1].type, CLEAR_TOOL_USES_STRATEGY);
|
||||
});
|
||||
|
||||
it("is idempotent — calling twice does not duplicate the tool-use edit", () => {
|
||||
const body: Record<string, unknown> = { model: "claude-opus-4-8" };
|
||||
applyContextEditingToBody(body, { enabled: true });
|
||||
applyContextEditingToBody(body, { enabled: true });
|
||||
|
||||
const edits = (body.context_management as Record<string, unknown>).edits as Array<
|
||||
Record<string, unknown>
|
||||
>;
|
||||
assert.equal(
|
||||
edits.filter((e) => e.type === CLEAR_TOOL_USES_STRATEGY).length,
|
||||
1,
|
||||
"only one clear_tool_uses edit should exist"
|
||||
);
|
||||
});
|
||||
|
||||
it("does not duplicate when a tool-use edit already exists (preserves caller's edit)", () => {
|
||||
const preset = {
|
||||
type: CLEAR_TOOL_USES_STRATEGY,
|
||||
trigger: { type: "input_tokens", value: 50000 },
|
||||
keep: { type: "tool_uses", value: 1 },
|
||||
};
|
||||
const body: Record<string, unknown> = {
|
||||
model: "claude-opus-4-8",
|
||||
context_management: { edits: [preset] },
|
||||
};
|
||||
applyContextEditingToBody(body, { enabled: true });
|
||||
|
||||
const edits = (body.context_management as Record<string, unknown>).edits as Array<
|
||||
Record<string, unknown>
|
||||
>;
|
||||
assert.equal(edits.length, 1);
|
||||
assert.deepEqual(edits[0], preset, "existing tool-use edit must be left untouched");
|
||||
});
|
||||
|
||||
it("preserves unrelated context_management properties", () => {
|
||||
const body: Record<string, unknown> = {
|
||||
model: "claude-opus-4-8",
|
||||
context_management: { edits: [], some_future_flag: true },
|
||||
};
|
||||
applyContextEditingToBody(body, { enabled: true });
|
||||
|
||||
const cm = body.context_management as Record<string, unknown>;
|
||||
assert.equal(cm.some_future_flag, true);
|
||||
assert.equal((cm.edits as unknown[]).length, 1);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,177 @@
|
||||
import { describe, it, beforeEach, afterEach, after } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import fs from "node:fs";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
|
||||
const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-compression-db-"));
|
||||
const ORIGINAL_DATA_DIR = process.env.DATA_DIR;
|
||||
process.env.DATA_DIR = TEST_DATA_DIR;
|
||||
|
||||
const core = await import("../../../src/lib/db/core.ts");
|
||||
const { getCompressionSettings, updateCompressionSettings } =
|
||||
await import("../../../src/lib/db/compression.ts");
|
||||
|
||||
beforeEach(() => {
|
||||
core.resetDbInstance();
|
||||
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
|
||||
fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
core.resetDbInstance();
|
||||
});
|
||||
|
||||
after(() => {
|
||||
core.resetDbInstance();
|
||||
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
|
||||
if (ORIGINAL_DATA_DIR === undefined) {
|
||||
delete process.env.DATA_DIR;
|
||||
} else {
|
||||
process.env.DATA_DIR = ORIGINAL_DATA_DIR;
|
||||
}
|
||||
});
|
||||
|
||||
describe("getCompressionSettings", () => {
|
||||
it("returns default settings structure", async () => {
|
||||
const settings = await getCompressionSettings();
|
||||
assert.equal(typeof settings.enabled, "boolean");
|
||||
assert.equal(typeof settings.defaultMode, "string");
|
||||
assert.equal(typeof settings.autoTriggerTokens, "number");
|
||||
assert.equal(typeof settings.cacheMinutes, "number");
|
||||
assert.equal(typeof settings.preserveSystemPrompt, "boolean");
|
||||
assert.equal(typeof settings.comboOverrides, "object");
|
||||
assert.equal(typeof settings.ultra, "object");
|
||||
});
|
||||
|
||||
it("has correct default values", async () => {
|
||||
const settings = await getCompressionSettings();
|
||||
assert.equal(settings.enabled, false);
|
||||
assert.equal(settings.defaultMode, "off");
|
||||
assert.equal(settings.autoTriggerTokens, 0);
|
||||
assert.equal(settings.cacheMinutes, 5);
|
||||
assert.equal(settings.preserveSystemPrompt, true);
|
||||
assert.equal(settings.preserveSystemPromptMode, "always");
|
||||
assert.deepEqual(settings.comboOverrides, {});
|
||||
assert.equal(settings.ultra?.enabled, false);
|
||||
assert.equal(settings.ultra?.compressionRate, 0.5);
|
||||
assert.equal(settings.ultra?.minScoreThreshold, 0.3);
|
||||
assert.equal(settings.ultra?.slmFallbackToAggressive, true);
|
||||
assert.equal(settings.ultra?.maxTokensPerMessage, 0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("updateCompressionSettings", () => {
|
||||
it("updates enabled flag", async () => {
|
||||
await updateCompressionSettings({ enabled: true } as any);
|
||||
const settings = await getCompressionSettings();
|
||||
assert.equal(settings.enabled, true);
|
||||
// Reset
|
||||
await updateCompressionSettings({ enabled: false } as any);
|
||||
});
|
||||
|
||||
it("updates defaultMode", async () => {
|
||||
await updateCompressionSettings({ defaultMode: "lite" } as any);
|
||||
const settings = await getCompressionSettings();
|
||||
assert.equal(settings.defaultMode, "lite");
|
||||
// Reset
|
||||
await updateCompressionSettings({ defaultMode: "off" } as any);
|
||||
});
|
||||
|
||||
it("round-trips preserveSystemPromptMode and ignores unknown tokens (T05/C5)", async () => {
|
||||
await updateCompressionSettings({ preserveSystemPromptMode: "never" } as any);
|
||||
let settings = await getCompressionSettings();
|
||||
assert.equal(settings.preserveSystemPromptMode, "never");
|
||||
|
||||
await updateCompressionSettings({ preserveSystemPromptMode: "whenNoCache" } as any);
|
||||
settings = await getCompressionSettings();
|
||||
assert.equal(settings.preserveSystemPromptMode, "whenNoCache");
|
||||
|
||||
// An unknown persisted token is rejected on read and falls back to the safe
|
||||
// default mode ("always"), never crashing the settings load.
|
||||
await updateCompressionSettings({ preserveSystemPromptMode: "garbage" } as any);
|
||||
settings = await getCompressionSettings();
|
||||
assert.equal(settings.preserveSystemPromptMode, "always");
|
||||
|
||||
// Reset
|
||||
await updateCompressionSettings({ preserveSystemPromptMode: "always" } as any);
|
||||
});
|
||||
|
||||
it("updates autoTriggerTokens", async () => {
|
||||
await updateCompressionSettings({ autoTriggerTokens: 5000 } as any);
|
||||
const settings = await getCompressionSettings();
|
||||
assert.equal(settings.autoTriggerTokens, 5000);
|
||||
// Reset
|
||||
await updateCompressionSettings({ autoTriggerTokens: 0 } as any);
|
||||
});
|
||||
|
||||
it("updates multiple settings at once", async () => {
|
||||
await updateCompressionSettings({
|
||||
enabled: true,
|
||||
defaultMode: "lite",
|
||||
autoTriggerTokens: 1000,
|
||||
cacheMinutes: 10,
|
||||
} as any);
|
||||
const settings = await getCompressionSettings();
|
||||
assert.equal(settings.enabled, true);
|
||||
assert.equal(settings.defaultMode, "lite");
|
||||
assert.equal(settings.autoTriggerTokens, 1000);
|
||||
assert.equal(settings.cacheMinutes, 10);
|
||||
// Reset all
|
||||
await updateCompressionSettings({
|
||||
enabled: false,
|
||||
defaultMode: "off",
|
||||
autoTriggerTokens: 0,
|
||||
cacheMinutes: 5,
|
||||
} as any);
|
||||
});
|
||||
|
||||
it("preserves unmodified settings", async () => {
|
||||
const before = await getCompressionSettings();
|
||||
await updateCompressionSettings({ enabled: true } as any);
|
||||
const after = await getCompressionSettings();
|
||||
assert.equal(after.enabled, true);
|
||||
assert.equal(after.defaultMode, before.defaultMode);
|
||||
assert.equal(after.cacheMinutes, before.cacheMinutes);
|
||||
// Reset
|
||||
await updateCompressionSettings({ enabled: false } as any);
|
||||
});
|
||||
|
||||
it("updates and normalizes ultra config", async () => {
|
||||
await updateCompressionSettings({
|
||||
defaultMode: "ultra",
|
||||
ultra: {
|
||||
enabled: true,
|
||||
compressionRate: 0.25,
|
||||
minScoreThreshold: 0.4,
|
||||
slmFallbackToAggressive: false,
|
||||
modelPath: " /tmp/model.onnx ",
|
||||
maxTokensPerMessage: 512,
|
||||
},
|
||||
} as any);
|
||||
|
||||
const settings = await getCompressionSettings();
|
||||
assert.equal(settings.defaultMode, "ultra");
|
||||
assert.equal(settings.ultra?.enabled, true);
|
||||
assert.equal(settings.ultra?.compressionRate, 0.25);
|
||||
assert.equal(settings.ultra?.minScoreThreshold, 0.4);
|
||||
assert.equal(settings.ultra?.slmFallbackToAggressive, false);
|
||||
assert.equal(settings.ultra?.modelPath, "/tmp/model.onnx");
|
||||
assert.equal(settings.ultra?.maxTokensPerMessage, 512);
|
||||
});
|
||||
|
||||
it("round-trips ultraEngine + ultraSlmPrewarm (Phase 4 B), defaulting off", async () => {
|
||||
const before = await getCompressionSettings();
|
||||
assert.equal(before.ultraEngine, "heuristic");
|
||||
assert.equal(before.ultraSlmPrewarm, false);
|
||||
|
||||
await updateCompressionSettings({
|
||||
ultraEngine: "slm",
|
||||
ultraSlmPrewarm: true,
|
||||
} as any);
|
||||
|
||||
const after = await getCompressionSettings();
|
||||
assert.equal(after.ultraEngine, "slm");
|
||||
assert.equal(after.ultraSlmPrewarm, true);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,33 @@
|
||||
import { test } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { deriveDefaultPlan } from "@omniroute/open-sse/services/compression/deriveDefaultPlan.ts";
|
||||
|
||||
const on = (level?: string) => ({ enabled: true, ...(level ? { level } : {}) });
|
||||
|
||||
test("master off / empty / none-on => off", () => {
|
||||
assert.deepEqual(deriveDefaultPlan({}, false), { mode: "off", stackedPipeline: [] });
|
||||
assert.deepEqual(deriveDefaultPlan({}, true), { mode: "off", stackedPipeline: [] });
|
||||
assert.deepEqual(deriveDefaultPlan({ rtk: { enabled: false } }, true), { mode: "off", stackedPipeline: [] });
|
||||
});
|
||||
|
||||
test("exactly one single-mode engine => that mode", () => {
|
||||
assert.deepEqual(deriveDefaultPlan({ caveman: on("full") }, true), { mode: "standard", stackedPipeline: [] });
|
||||
assert.deepEqual(deriveDefaultPlan({ rtk: on("minimal") }, true), { mode: "rtk", stackedPipeline: [] });
|
||||
assert.deepEqual(deriveDefaultPlan({ lite: on() }, true), { mode: "lite", stackedPipeline: [] });
|
||||
});
|
||||
|
||||
test("one non-single-mode engine => stacked with that engine", () => {
|
||||
const p = deriveDefaultPlan({ headroom: on() }, true);
|
||||
assert.equal(p.mode, "stacked");
|
||||
assert.deepEqual(p.stackedPipeline, [{ engine: "headroom" }]);
|
||||
});
|
||||
|
||||
test("multiple engines => stacked in stackPriority order, levels as intensity", () => {
|
||||
const p = deriveDefaultPlan({ caveman: on("full"), rtk: on("standard"), headroom: on() }, true);
|
||||
assert.equal(p.mode, "stacked");
|
||||
assert.deepEqual(p.stackedPipeline, [
|
||||
{ engine: "rtk", intensity: "standard" }, // pri 10
|
||||
{ engine: "headroom" }, // pri 15
|
||||
{ engine: "caveman", intensity: "full" }, // pri 20
|
||||
]);
|
||||
});
|
||||
@@ -0,0 +1,133 @@
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
|
||||
import { applyCompressionAsync } from "../../../open-sse/services/compression/index.ts";
|
||||
import { selectCompressionPlan } from "../../../open-sse/services/compression/strategySelector.ts";
|
||||
import { DEFAULT_COMPRESSION_CONFIG } from "../../../open-sse/services/compression/types.ts";
|
||||
import type {
|
||||
CompressionConfig,
|
||||
CompressionPipelineStep,
|
||||
} from "../../../open-sse/services/compression/types.ts";
|
||||
|
||||
/**
|
||||
* End-to-end coverage for the derived stacked pipeline (Task 12).
|
||||
*
|
||||
* Proves that the per-engine toggle map (`config.engines`) drives a derived
|
||||
* `stacked` plan whose pipeline, when fed back to {@link applyCompressionAsync},
|
||||
* runs the real rtk → caveman engines — and that the derived run is equivalent to
|
||||
* an explicit `stackedPipeline` config. i.e. "derived == explicit".
|
||||
*/
|
||||
describe("compression derived-pipeline integration (Task 12)", () => {
|
||||
// A realistic body: a noisy tool result (rtk dedupes) plus a prose user turn.
|
||||
function makeBody(): Record<string, unknown> {
|
||||
return {
|
||||
messages: [
|
||||
{
|
||||
role: "tool",
|
||||
content: Array.from({ length: 8 }, () => "same noisy tool output line").join("\n"),
|
||||
},
|
||||
{
|
||||
role: "user",
|
||||
content:
|
||||
"Please provide a detailed explanation of the authentication configuration and how it works",
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
// Engines map: only rtk + caveman(full) on. rtk has no level → no intensity in the
|
||||
// derived step; caveman level "full" → intensity "full".
|
||||
function deriveConfig(): CompressionConfig {
|
||||
return {
|
||||
...DEFAULT_COMPRESSION_CONFIG,
|
||||
enabled: true,
|
||||
// Clear the seeded default stackedPipeline so the derived plan is the only source.
|
||||
stackedPipeline: [],
|
||||
// Panel-configured: the engines map drives dispatch (a stored engines row exists).
|
||||
enginesExplicit: true,
|
||||
engines: {
|
||||
...DEFAULT_COMPRESSION_CONFIG.engines,
|
||||
rtk: { enabled: true },
|
||||
caveman: { enabled: true, level: "full" },
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const EXPLICIT_PIPELINE: CompressionPipelineStep[] = [
|
||||
{ engine: "rtk" },
|
||||
{ engine: "caveman", intensity: "full" },
|
||||
] as unknown as CompressionPipelineStep[];
|
||||
|
||||
it("derives a stacked plan with rtk → caveman(full) in stackPriority order", () => {
|
||||
const config = deriveConfig();
|
||||
// Enough tokens that auto-trigger is irrelevant (autoTriggerTokens is 0 by default,
|
||||
// so the derived default path is what we want — pass a real estimate anyway).
|
||||
const plan = selectCompressionPlan(config, null, 5000);
|
||||
|
||||
assert.equal(plan.mode, "stacked");
|
||||
assert.deepEqual(plan.stackedPipeline, [
|
||||
{ engine: "rtk" },
|
||||
{ engine: "caveman", intensity: "full" },
|
||||
]);
|
||||
});
|
||||
|
||||
it("runs BOTH rtk and caveman when applying the derived pipeline", async () => {
|
||||
const config = deriveConfig();
|
||||
const plan = selectCompressionPlan(config, null, 5000);
|
||||
assert.equal(plan.mode, "stacked");
|
||||
|
||||
// Feed the derived pipeline back through the real async apply path.
|
||||
const runConfig: CompressionConfig = {
|
||||
...config,
|
||||
stackedPipeline: plan.stackedPipeline as CompressionPipelineStep[],
|
||||
};
|
||||
const result = await applyCompressionAsync(makeBody(), "stacked", { config: runConfig });
|
||||
|
||||
assert.equal(result.stats?.engine, "stacked");
|
||||
const ran = result.stats?.engineBreakdown?.map((e) => e.engine) ?? [];
|
||||
assert.deepEqual(ran, ["rtk", "caveman"], "both engines must run, rtk before caveman");
|
||||
});
|
||||
|
||||
it("derived pipeline is equivalent to an explicit stackedPipeline (derived == explicit)", async () => {
|
||||
const derivedConfig = deriveConfig();
|
||||
const derivedPlan = selectCompressionPlan(derivedConfig, null, 5000);
|
||||
assert.deepEqual(derivedPlan.stackedPipeline, EXPLICIT_PIPELINE);
|
||||
|
||||
const derivedResult = await applyCompressionAsync(makeBody(), "stacked", {
|
||||
config: {
|
||||
...derivedConfig,
|
||||
stackedPipeline: derivedPlan.stackedPipeline as CompressionPipelineStep[],
|
||||
},
|
||||
});
|
||||
|
||||
// Second config: NO engines map driving the plan — an explicit stackedPipeline only.
|
||||
const explicitConfig: CompressionConfig = {
|
||||
...DEFAULT_COMPRESSION_CONFIG,
|
||||
enabled: true,
|
||||
stackedPipeline: EXPLICIT_PIPELINE,
|
||||
engines: {}, // explicit-only: the engines map plays no part here
|
||||
};
|
||||
const explicitResult = await applyCompressionAsync(makeBody(), "stacked", {
|
||||
config: explicitConfig,
|
||||
});
|
||||
|
||||
// Same engines ran, in the same order.
|
||||
assert.deepEqual(
|
||||
derivedResult.stats?.engineBreakdown?.map((e) => e.engine),
|
||||
explicitResult.stats?.engineBreakdown?.map((e) => e.engine),
|
||||
"derived and explicit must run the same engine set in the same order"
|
||||
);
|
||||
|
||||
// Same compressed output text for the prose user turn.
|
||||
const userText = (r: typeof derivedResult): string => {
|
||||
const messages = r.body.messages as Array<{ role: string; content: unknown }>;
|
||||
const user = messages.find((m) => m.role === "user");
|
||||
return typeof user?.content === "string" ? user.content : JSON.stringify(user?.content);
|
||||
};
|
||||
assert.equal(
|
||||
userText(derivedResult),
|
||||
userText(explicitResult),
|
||||
"derived and explicit must produce identical compressed text"
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,45 @@
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { buildCompressionPreviewDiff } from "../../../open-sse/services/compression/diffHelper.ts";
|
||||
|
||||
describe("compression preview diff", () => {
|
||||
it("reports diff segments, preserved blocks, rules, validation warnings, and fallback status", () => {
|
||||
const original = "Please use `exact_token` and the API.";
|
||||
const compressed = "Use `exact_token` and API.";
|
||||
const preview = buildCompressionPreviewDiff(original, compressed, {
|
||||
originalTokens: 10,
|
||||
compressedTokens: 6,
|
||||
savingsPercent: 40,
|
||||
techniquesUsed: ["caveman-rules"],
|
||||
mode: "standard",
|
||||
timestamp: Date.now(),
|
||||
rulesApplied: ["polite_framing", "articles"],
|
||||
validationWarnings: ["sample warning"],
|
||||
});
|
||||
|
||||
assert.ok(preview.segments.some((segment) => segment.type === "removed"));
|
||||
assert.ok(preview.preservedBlocks.some((block) => block.kind === "inline_code"));
|
||||
assert.deepEqual(preview.ruleRemovals, ["polite_framing", "articles"]);
|
||||
assert.match(preview.validationWarnings.join("\n"), /sample warning/);
|
||||
assert.equal(preview.fallbackApplied, false);
|
||||
});
|
||||
|
||||
it("reports validation errors for protected content loss", () => {
|
||||
const preview = buildCompressionPreviewDiff(
|
||||
"Use `exact_token` and https://example.com.",
|
||||
"Use token.",
|
||||
null
|
||||
);
|
||||
assert.equal(preview.fallbackApplied, true);
|
||||
assert.ok(preview.validationErrors.length >= 2);
|
||||
});
|
||||
|
||||
it("degrades preview diff generation when token product exceeds the safe limit", () => {
|
||||
const original = Array.from({ length: 1500 }, (_, index) => `original-${index}`).join(" ");
|
||||
const compressed = Array.from({ length: 1500 }, (_, index) => `compressed-${index}`).join(" ");
|
||||
const preview = buildCompressionPreviewDiff(original, compressed, null);
|
||||
|
||||
assert.deepEqual(preview.segments, [{ type: "same", text: "[diff omitted: input too large]" }]);
|
||||
assert.match(preview.validationWarnings.join("\n"), /Preview diff omitted/);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,35 @@
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { summarizeEncoderCandidates } from "../../../open-sse/services/compression/engines/headroom/encoderComparison.ts";
|
||||
|
||||
const byteLen = (s: string) => Buffer.byteLength(s, "utf8");
|
||||
|
||||
test("agrega sizes e elege winner por tokens", () => {
|
||||
const messages = [
|
||||
{
|
||||
role: "user",
|
||||
content: JSON.stringify(Array.from({ length: 20 }, (_, i) => ({ id: i, ok: true }))),
|
||||
},
|
||||
];
|
||||
const cmp = summarizeEncoderCandidates(messages, 8, byteLen);
|
||||
assert.equal(cmp.arraysCompared, 1);
|
||||
assert.ok(cmp.json.bytes > 0 && cmp.gcf.bytes > 0);
|
||||
assert.ok(["gcf", "toon", "json"].includes(cmp.winner));
|
||||
const sizes: Record<string, number> = { gcf: cmp.gcf.tokens, json: cmp.json.tokens };
|
||||
if (cmp.toonAvailable) sizes["toon"] = cmp.toon.tokens;
|
||||
const min = Math.min(...Object.values(sizes));
|
||||
assert.equal(sizes[cmp.winner], min);
|
||||
});
|
||||
|
||||
test("sem array compactável → zerado, sem winner espúrio", () => {
|
||||
const cmp = summarizeEncoderCandidates([{ role: "user", content: "oi" }], 8, byteLen);
|
||||
assert.equal(cmp.arraysCompared, 0);
|
||||
assert.equal(cmp.json.bytes, 0);
|
||||
assert.equal(cmp.gcf.bytes, 0);
|
||||
});
|
||||
|
||||
test("system messages são ignoradas (igual ao smartcrusher)", () => {
|
||||
const arr = JSON.stringify(Array.from({ length: 20 }, (_, i) => ({ id: i })));
|
||||
const cmp = summarizeEncoderCandidates([{ role: "system", content: arr }], 8, byteLen);
|
||||
assert.equal(cmp.arraysCompared, 0);
|
||||
});
|
||||
@@ -0,0 +1,66 @@
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { ensureEngineBreakdown } from "../../../open-sse/services/compression/engineBreakdown.ts";
|
||||
import type { CompressionStats } from "../../../open-sse/services/compression/types.ts";
|
||||
|
||||
function stats(over: Partial<CompressionStats>): CompressionStats {
|
||||
return {
|
||||
originalTokens: 1000,
|
||||
compressedTokens: 700,
|
||||
savingsPercent: 30,
|
||||
techniquesUsed: [],
|
||||
mode: "rtk",
|
||||
timestamp: 0,
|
||||
...over,
|
||||
};
|
||||
}
|
||||
|
||||
// Single-engine compression modes (rtk/lite/standard/aggressive/ultra) produce stats with an
|
||||
// empty engineBreakdown — only the stacked pipeline fills it. The dashboard studio then renders
|
||||
// an empty Input→Output pipeline (no engine node, inert replay) for the most common case.
|
||||
// ensureEngineBreakdown synthesizes a 1-entry breakdown from the overall stats so the studio
|
||||
// always shows at least one real engine node.
|
||||
describe("ensureEngineBreakdown", () => {
|
||||
it("returns the existing breakdown unchanged when present (stacked)", () => {
|
||||
const bd = [
|
||||
{
|
||||
engine: "rtk",
|
||||
originalTokens: 1000,
|
||||
compressedTokens: 700,
|
||||
savingsPercent: 30,
|
||||
techniquesUsed: ["a"],
|
||||
},
|
||||
];
|
||||
assert.deepEqual(ensureEngineBreakdown(stats({ engineBreakdown: bd })), bd);
|
||||
});
|
||||
|
||||
it("synthesizes a 1-entry breakdown for single-engine modes (empty/undefined breakdown)", () => {
|
||||
const out = ensureEngineBreakdown(
|
||||
stats({
|
||||
mode: "lite",
|
||||
engine: "lite",
|
||||
originalTokens: 2000,
|
||||
compressedTokens: 1500,
|
||||
savingsPercent: 25,
|
||||
techniquesUsed: ["lite-strip"],
|
||||
rulesApplied: ["r1"],
|
||||
durationMs: 3,
|
||||
})
|
||||
);
|
||||
assert.equal(out.length, 1);
|
||||
assert.equal(out[0].engine, "lite");
|
||||
assert.equal(out[0].originalTokens, 2000);
|
||||
assert.equal(out[0].compressedTokens, 1500);
|
||||
assert.equal(out[0].savingsPercent, 25);
|
||||
assert.deepEqual(out[0].techniquesUsed, ["lite-strip"]);
|
||||
assert.deepEqual(out[0].rulesApplied, ["r1"]);
|
||||
assert.equal(out[0].durationMs, 3);
|
||||
});
|
||||
|
||||
it("falls back to mode for the engine label when stats.engine is absent", () => {
|
||||
const out = ensureEngineBreakdown(stats({ mode: "standard", engineBreakdown: [] }));
|
||||
assert.equal(out.length, 1);
|
||||
assert.equal(out[0].engine, "standard");
|
||||
assert.deepEqual(out[0].techniquesUsed, []);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,28 @@
|
||||
import { test } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { ENGINE_CATALOG, engineMeta, ENGINE_IDS } from "@omniroute/open-sse/services/compression/engineCatalog.ts";
|
||||
import { DEFAULT_COMPRESSION_CONFIG } from "@omniroute/open-sse/services/compression/types.ts";
|
||||
|
||||
test("catalog lists every engine with stackPriority", () => {
|
||||
for (const id of ["session-dedup","ccr","lite","rtk","headroom","caveman","aggressive","llmlingua","ultra"]) {
|
||||
assert.ok(engineMeta(id), `${id} present`);
|
||||
assert.equal(typeof engineMeta(id).stackPriority, "number");
|
||||
}
|
||||
});
|
||||
test("levels + single-mode flags are correct", () => {
|
||||
assert.deepEqual(engineMeta("rtk").levels, ["minimal","standard","aggressive"]);
|
||||
assert.deepEqual(engineMeta("caveman").levels, ["lite","full","ultra"]);
|
||||
assert.equal(engineMeta("headroom").levels, undefined);
|
||||
assert.equal(engineMeta("caveman").isSingleMode, true);
|
||||
assert.equal(engineMeta("headroom").isSingleMode, false);
|
||||
});
|
||||
test("ENGINE_IDS is ordered by stackPriority", () => {
|
||||
const ps = ENGINE_IDS.map((id) => engineMeta(id).stackPriority);
|
||||
assert.deepEqual(ps, [...ps].sort((a,b)=>a-b));
|
||||
});
|
||||
test("default config has an engines map + activeComboId", () => {
|
||||
assert.equal(typeof DEFAULT_COMPRESSION_CONFIG.engines, "object");
|
||||
assert.equal(DEFAULT_COMPRESSION_CONFIG.activeComboId, null);
|
||||
// default-off: every engine disabled by default (opt-in preserved)
|
||||
for (const id of ENGINE_IDS) assert.equal(DEFAULT_COMPRESSION_CONFIG.engines[id]?.enabled, false);
|
||||
});
|
||||
@@ -0,0 +1,128 @@
|
||||
/**
|
||||
* Registry `enabled` toggle — the stacked loop must honor setEngineEnabled.
|
||||
*
|
||||
* `enabled` was a flag the stacked pipeline never consulted: getCompressionEngine
|
||||
* returned the engine regardless, so flipping it via setEngineEnabled had no effect
|
||||
* (the toggle "lied"). Both the sync and async stacked loops now skip a step whose
|
||||
* engine is disabled.
|
||||
*/
|
||||
import { describe, it, before, after, beforeEach } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
|
||||
import {
|
||||
applyStackedCompression,
|
||||
applyStackedCompressionAsync,
|
||||
} from "../../../open-sse/services/compression/index.ts";
|
||||
import {
|
||||
registerCompressionEngine,
|
||||
unregisterCompressionEngine,
|
||||
setEngineEnabled,
|
||||
} from "../../../open-sse/services/compression/engines/registry.ts";
|
||||
import type {
|
||||
CompressionEngine,
|
||||
CompressionEngineTarget,
|
||||
} from "../../../open-sse/services/compression/engines/types.ts";
|
||||
import type {
|
||||
CompressionPipelineStep,
|
||||
CompressionResult,
|
||||
} from "../../../open-sse/services/compression/types.ts";
|
||||
|
||||
const ENGINE_ID = "enabled-toggle-engine";
|
||||
|
||||
/** Engine that tags user content and reports a real gain when it runs. */
|
||||
function makeTaggingEngine(id: string): CompressionEngine {
|
||||
return {
|
||||
id,
|
||||
name: id,
|
||||
description: id,
|
||||
icon: "x",
|
||||
targets: ["messages"] as CompressionEngineTarget[],
|
||||
stackable: true,
|
||||
stackPriority: 0,
|
||||
metadata: {
|
||||
id,
|
||||
name: id,
|
||||
description: id,
|
||||
inputScope: "messages",
|
||||
targetLatencyMs: 1,
|
||||
supportsPreview: false,
|
||||
stable: true,
|
||||
},
|
||||
compress: (body) => ({ body, compressed: false, stats: null }),
|
||||
getConfigSchema: () => [],
|
||||
validateConfig: () => ({ valid: true, errors: [] }),
|
||||
apply: (body) => {
|
||||
const messages = (body.messages as Array<{ role: string; content: string }>) ?? [];
|
||||
// Tag the user message; drop any padding (non-user) content so the body shrinks
|
||||
// and the #5527 (T02) inflation guard keeps the tagged output instead of reverting.
|
||||
const next = messages.map((m) =>
|
||||
m.role === "user" ? { ...m, content: m.content + "|tagged" } : { ...m, content: "" }
|
||||
);
|
||||
return {
|
||||
body: { ...body, messages: next },
|
||||
compressed: true,
|
||||
stats: {
|
||||
originalTokens: 100,
|
||||
compressedTokens: 70,
|
||||
savingsPercent: 30,
|
||||
techniquesUsed: [id],
|
||||
mode: "stacked",
|
||||
timestamp: 0,
|
||||
durationMs: 0.1,
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function pipeline(...ids: string[]): CompressionPipelineStep[] {
|
||||
return ids.map((engine) => ({ engine })) as unknown as CompressionPipelineStep[];
|
||||
}
|
||||
|
||||
function userContent(result: CompressionResult): string {
|
||||
const messages = result.body.messages as Array<{ role: string; content: string }>;
|
||||
return messages.find((m) => m.role === "user")!.content;
|
||||
}
|
||||
|
||||
function freshBody() {
|
||||
// Includes a droppable padding message so an engine that runs nets a real token shrink
|
||||
// (the engine empties non-user content), keeping the #5527 inflation guard from reverting.
|
||||
return {
|
||||
messages: [
|
||||
{ role: "user", content: "hi" },
|
||||
{ role: "assistant", content: "padding tokens ".repeat(40) },
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
describe("registry enabled toggle — stacked loop honors setEngineEnabled", () => {
|
||||
before(() => registerCompressionEngine(makeTaggingEngine(ENGINE_ID)));
|
||||
beforeEach(() => setEngineEnabled(ENGINE_ID, true)); // default-on before each case
|
||||
after(() => unregisterCompressionEngine(ENGINE_ID));
|
||||
|
||||
it("applies the engine while enabled (sync)", () => {
|
||||
const result = applyStackedCompression(freshBody(), pipeline(ENGINE_ID));
|
||||
assert.equal(result.compressed, true);
|
||||
assert.equal(userContent(result), "hi|tagged");
|
||||
});
|
||||
|
||||
it("skips the engine once disabled (sync)", () => {
|
||||
setEngineEnabled(ENGINE_ID, false);
|
||||
const result = applyStackedCompression(freshBody(), pipeline(ENGINE_ID));
|
||||
assert.equal(result.compressed, false);
|
||||
assert.equal(userContent(result), "hi"); // unchanged — step skipped
|
||||
});
|
||||
|
||||
it("applies the engine while enabled (async)", async () => {
|
||||
const result = await applyStackedCompressionAsync(freshBody(), pipeline(ENGINE_ID));
|
||||
assert.equal(result.compressed, true);
|
||||
assert.equal(userContent(result), "hi|tagged");
|
||||
});
|
||||
|
||||
it("skips the engine once disabled (async)", async () => {
|
||||
setEngineEnabled(ENGINE_ID, false);
|
||||
const result = await applyStackedCompressionAsync(freshBody(), pipeline(ENGINE_ID));
|
||||
assert.equal(result.compressed, false);
|
||||
assert.equal(userContent(result), "hi");
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,95 @@
|
||||
import { describe, it, beforeEach } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
|
||||
import {
|
||||
aggressiveEngine,
|
||||
cavemanEngine,
|
||||
liteEngine,
|
||||
ultraEngine,
|
||||
} from "../../../open-sse/services/compression/engines/cavemanAdapter.ts";
|
||||
import { rtkEngine as realRtkEngine } from "../../../open-sse/services/compression/engines/rtk/index.ts";
|
||||
import {
|
||||
clearCompressionEngineRegistry,
|
||||
getEngine,
|
||||
getEngineEntry,
|
||||
listEnabledEngines,
|
||||
listEngines,
|
||||
registerEngine,
|
||||
setEngineEnabled,
|
||||
updateEngineConfig,
|
||||
} from "../../../open-sse/services/compression/index.ts";
|
||||
|
||||
describe("compression engine registry contract", () => {
|
||||
beforeEach(() => {
|
||||
clearCompressionEngineRegistry();
|
||||
});
|
||||
|
||||
it("registers and retrieves an engine by id", () => {
|
||||
registerEngine(cavemanEngine);
|
||||
|
||||
assert.equal(getEngine("caveman"), cavemanEngine);
|
||||
assert.equal(getEngine("missing"), null);
|
||||
});
|
||||
|
||||
it("lists engine entries and filters enabled entries", () => {
|
||||
registerEngine(cavemanEngine);
|
||||
registerEngine(realRtkEngine);
|
||||
|
||||
assert.equal(listEngines().length, 2);
|
||||
assert.equal(listEnabledEngines().length, 2);
|
||||
|
||||
assert.equal(setEngineEnabled("rtk", false), true);
|
||||
assert.equal(
|
||||
listEnabledEngines()
|
||||
.map((entry) => entry.engine.id)
|
||||
.join(","),
|
||||
"caveman"
|
||||
);
|
||||
});
|
||||
|
||||
it("updates config only after engine validation passes", () => {
|
||||
registerEngine(realRtkEngine);
|
||||
|
||||
const invalid = updateEngineConfig("rtk", { intensity: "extreme" });
|
||||
assert.equal(invalid.valid, false);
|
||||
assert.match(invalid.errors.join(" "), /intensity/);
|
||||
|
||||
const valid = updateEngineConfig("rtk", {
|
||||
intensity: "aggressive",
|
||||
applyToCodeBlocks: true,
|
||||
});
|
||||
assert.equal(valid.valid, true);
|
||||
assert.deepEqual(getEngineEntry("rtk")?.config, {
|
||||
intensity: "aggressive",
|
||||
applyToCodeBlocks: true,
|
||||
});
|
||||
});
|
||||
|
||||
it("exposes schema and validation for built-in adapters", () => {
|
||||
const cavemanSchema = cavemanEngine.getConfigSchema();
|
||||
const rtkSchema = realRtkEngine.getConfigSchema();
|
||||
const aggressiveSchema = aggressiveEngine.getConfigSchema();
|
||||
const ultraSchema = ultraEngine.getConfigSchema();
|
||||
|
||||
assert.ok(cavemanSchema.some((field) => field.key === "intensity"));
|
||||
assert.ok(rtkSchema.some((field) => field.key === "applyToCodeBlocks"));
|
||||
assert.ok(aggressiveSchema.some((field) => field.key === "maxTokensPerMessage"));
|
||||
assert.ok(ultraSchema.some((field) => field.key === "compressionRate"));
|
||||
|
||||
// Lite exposes its OWN minimal schema (preserveSystemPrompt), NOT the aggressive
|
||||
// summarizer/threshold fields it previously leaked.
|
||||
const liteSchema = liteEngine.getConfigSchema();
|
||||
assert.ok(liteSchema.some((field) => field.key === "preserveSystemPrompt"));
|
||||
assert.ok(!liteSchema.some((field) => field.key === "maxTokensPerMessage"));
|
||||
assert.ok(!liteSchema.some((field) => field.key === "summarizerEnabled"));
|
||||
assert.equal(liteEngine.validateConfig({ preserveSystemPrompt: true }).valid, true);
|
||||
assert.equal(liteEngine.validateConfig({ preserveSystemPrompt: "yes" }).valid, false);
|
||||
assert.equal(cavemanEngine.validateConfig({ intensity: "full" }).valid, true);
|
||||
assert.equal(cavemanEngine.validateConfig({ intensity: "bad" }).valid, false);
|
||||
assert.equal(realRtkEngine.validateConfig({ maxLinesPerResult: 20 }).valid, true);
|
||||
assert.equal(aggressiveEngine.validateConfig({ maxTokensPerMessage: 2048 }).valid, true);
|
||||
assert.equal(aggressiveEngine.validateConfig({ maxTokensPerMessage: 10 }).valid, false);
|
||||
assert.equal(ultraEngine.validateConfig({ compressionRate: 0.4 }).valid, true);
|
||||
assert.equal(ultraEngine.validateConfig({ compressionRate: 4 }).valid, false);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,45 @@
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { aggregateRecords } from "../../../open-sse/services/compression/eval/aggregate.ts";
|
||||
import type { EvalRecord, RunStamps } from "../../../open-sse/services/compression/eval/types.ts";
|
||||
|
||||
const stamps: RunStamps = { answerModel: "m", judgeModel: "j", corpusHash: "abc", sampleSize: "all" };
|
||||
|
||||
const records: EvalRecord[] = [
|
||||
{ id: "p1", kind: "prose", fidelity: "same", goldFull: true, goldCompressed: true,
|
||||
savings: { tokensBefore: 100, tokensAfter: 50, ratio: 0.5 }, errored: false },
|
||||
{ id: "p2", kind: "prose", fidelity: "materially-differs", goldFull: true, goldCompressed: false,
|
||||
savings: { tokensBefore: 200, tokensAfter: 80, ratio: 0.4 }, errored: false },
|
||||
{ id: "c1", kind: "code", fidelity: "same", goldFull: null, goldCompressed: null,
|
||||
savings: { tokensBefore: 60, tokensAfter: 30, ratio: 0.5 }, errored: false },
|
||||
{ id: "e1", kind: "logs", fidelity: "unparseable", goldFull: null, goldCompressed: null,
|
||||
savings: { tokensBefore: 0, tokensAfter: 0, ratio: 1 }, errored: true },
|
||||
];
|
||||
|
||||
describe("eval aggregate", () => {
|
||||
it("excludes errored records from aggregates but counts them", () => {
|
||||
const report = aggregateRecords(records, stamps, { partial: false, totalCostUsd: 0 });
|
||||
assert.equal(report.overall.casesScored, 3);
|
||||
assert.equal(report.overall.casesErrored, 1);
|
||||
});
|
||||
|
||||
it("computes fidelity-preserved % overall (same / scored)", () => {
|
||||
const report = aggregateRecords(records, stamps, { partial: false, totalCostUsd: 0 });
|
||||
// 2 of 3 scored are "same"
|
||||
assert.equal(report.overall.fidelityPreservedPct, 66.7);
|
||||
});
|
||||
|
||||
it("computes gold-accuracy delta (compressed-correct minus full-correct) over gold cases", () => {
|
||||
const report = aggregateRecords(records, stamps, { partial: false, totalCostUsd: 0 });
|
||||
// prose gold cases: full 2/2 correct, compressed 1/2 correct => delta -50%
|
||||
const prose = report.perKind.find((k) => k.kind === "prose")!;
|
||||
assert.equal(prose.goldAccuracyDeltaPct, -50);
|
||||
});
|
||||
|
||||
it("carries the stamps and the partial flag through", () => {
|
||||
const report = aggregateRecords(records, stamps, { partial: true, totalCostUsd: 1.23 });
|
||||
assert.equal(report.stamps.corpusHash, "abc");
|
||||
assert.equal(report.partial, true);
|
||||
assert.equal(report.totalCostUsd, 1.23);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,39 @@
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { loadCorpus, hashCorpus } from "../../../open-sse/services/compression/eval/corpus.ts";
|
||||
import type { EvalCase } from "../../../open-sse/services/compression/eval/types.ts";
|
||||
|
||||
const cases: EvalCase[] = [
|
||||
{ id: "a", kind: "prose", context: "hello world", question: "what is it?" },
|
||||
{ id: "b", kind: "code", context: "function f(){return 1}", question: "what does f return?", gold: "1" },
|
||||
];
|
||||
|
||||
describe("eval corpus loader", () => {
|
||||
it("loads valid cases unchanged", () => {
|
||||
const loaded = loadCorpus(cases);
|
||||
assert.equal(loaded.length, 2);
|
||||
assert.equal(loaded[1].gold, "1");
|
||||
});
|
||||
|
||||
it("rejects a case missing required fields", () => {
|
||||
assert.throws(() => loadCorpus([{ id: "x", kind: "prose", context: "", question: "q" } as EvalCase]));
|
||||
});
|
||||
|
||||
it("rejects a captured case with an obvious PII marker (email)", () => {
|
||||
assert.throws(() =>
|
||||
loadCorpus([{ id: "p", kind: "logs", context: "user alice@example.com failed", question: "who?", captured: true }])
|
||||
);
|
||||
});
|
||||
|
||||
it("allows a curated seed case even if it contains an email-like token (curated is vetted)", () => {
|
||||
const loaded = loadCorpus([{ id: "s", kind: "logs", context: "noreply@x.test sent", question: "who?", captured: false }]);
|
||||
assert.equal(loaded.length, 1);
|
||||
});
|
||||
|
||||
it("hashCorpus is stable and order-independent over case ids", () => {
|
||||
const h1 = hashCorpus(cases);
|
||||
const h2 = hashCorpus([cases[1], cases[0]]);
|
||||
assert.equal(h1, h2);
|
||||
assert.match(h1, /^[0-9a-f]{64}$/);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,34 @@
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { createCostMeter } from "../../../open-sse/services/compression/eval/costMeter.ts";
|
||||
|
||||
describe("eval cost meter", () => {
|
||||
it("accumulates spend and reports it", () => {
|
||||
const m = createCostMeter(1.0);
|
||||
m.add(0.2);
|
||||
m.add(0.3);
|
||||
assert.equal(Math.round(m.spent * 100) / 100, 0.5);
|
||||
assert.equal(m.exceeded, false);
|
||||
});
|
||||
|
||||
it("wouldExceed is true when the next charge crosses the cap", () => {
|
||||
const m = createCostMeter(1.0);
|
||||
m.add(0.8);
|
||||
assert.equal(m.wouldExceed(0.3), true);
|
||||
assert.equal(m.wouldExceed(0.1), false);
|
||||
});
|
||||
|
||||
it("marks exceeded once spend crosses the cap", () => {
|
||||
const m = createCostMeter(1.0);
|
||||
m.add(0.9);
|
||||
m.add(0.2);
|
||||
assert.equal(m.exceeded, true);
|
||||
});
|
||||
|
||||
it("a cap of 0 or undefined means unbounded (never exceeds)", () => {
|
||||
const m = createCostMeter(0);
|
||||
m.add(1000);
|
||||
assert.equal(m.wouldExceed(1000), false);
|
||||
assert.equal(m.exceeded, false);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,22 @@
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { buildGradePrompt, parseGradeVerdict } from "../../../open-sse/services/compression/eval/grader.ts";
|
||||
|
||||
describe("gold grader", () => {
|
||||
it("buildGradePrompt embeds the answer and the gold", () => {
|
||||
const msgs = buildGradePrompt("returns three", "3");
|
||||
const joined = msgs.map((m) => m.content).join("\n");
|
||||
assert.match(joined, /returns three/);
|
||||
assert.match(joined, /3/);
|
||||
assert.match(joined.toUpperCase(), /CORRECT|INCORRECT/);
|
||||
});
|
||||
|
||||
it("parseGradeVerdict reads CORRECT / INCORRECT", () => {
|
||||
assert.equal(parseGradeVerdict("VERDICT: CORRECT").correct, true);
|
||||
assert.equal(parseGradeVerdict("verdict: incorrect — wrong number").correct, false);
|
||||
});
|
||||
|
||||
it("parseGradeVerdict defaults to incorrect on unparseable output (never credits a wrong answer)", () => {
|
||||
assert.equal(parseGradeVerdict("hmm, hard to say").correct, false);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,26 @@
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { buildJudgePrompt, parseJudgeVerdict } from "../../../open-sse/services/compression/eval/judge.ts";
|
||||
|
||||
describe("fidelity judge", () => {
|
||||
it("buildJudgePrompt embeds both answers and asks for a SAME/DIFFERENT verdict", () => {
|
||||
const msgs = buildJudgePrompt("the cat sat", "a cat was sitting");
|
||||
const joined = msgs.map((m) => m.content).join("\n");
|
||||
assert.match(joined, /the cat sat/);
|
||||
assert.match(joined, /a cat was sitting/);
|
||||
assert.match(joined.toUpperCase(), /SAME|MATERIALLY/);
|
||||
});
|
||||
|
||||
it("parseJudgeVerdict maps a SAME verdict", () => {
|
||||
assert.equal(parseJudgeVerdict("Verdict: SAME"), "same");
|
||||
});
|
||||
|
||||
it("parseJudgeVerdict maps a MATERIALLY_DIFFERS verdict (case/format tolerant)", () => {
|
||||
assert.equal(parseJudgeVerdict("VERDICT: materially_differs\nreason: omitted the error"), "materially-differs");
|
||||
assert.equal(parseJudgeVerdict("differs materially"), "materially-differs");
|
||||
});
|
||||
|
||||
it("parseJudgeVerdict returns 'unparseable' for noise", () => {
|
||||
assert.equal(parseJudgeVerdict("I am not sure, could you clarify?"), "unparseable");
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,36 @@
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { formatReport } from "../../../open-sse/services/compression/eval/report.ts";
|
||||
import type { EvalReport } from "../../../open-sse/services/compression/eval/types.ts";
|
||||
|
||||
const report: EvalReport = {
|
||||
stamps: { answerModel: "gpt-x", judgeModel: "judge-y", corpusHash: "deadbeef", sampleSize: 5 },
|
||||
partial: true,
|
||||
totalCostUsd: 0.42,
|
||||
overall: { casesScored: 4, casesErrored: 1, fidelityPreservedPct: 75, goldAccuracyDeltaPct: -25, meanRatio: 0.5 },
|
||||
perKind: [{ kind: "prose", casesScored: 2, fidelityPreservedPct: 50, goldAccuracyDeltaPct: -50, meanRatio: 0.45 }],
|
||||
};
|
||||
|
||||
describe("eval report writer", () => {
|
||||
it("stamps the answer model, judge model and corpus hash in the header", () => {
|
||||
const md = formatReport(report);
|
||||
assert.match(md, /gpt-x/);
|
||||
assert.match(md, /judge-y/);
|
||||
assert.match(md, /deadbeef/);
|
||||
});
|
||||
|
||||
it("flags a partial run prominently (never silent)", () => {
|
||||
assert.match(formatReport(report), /PARTIAL/i);
|
||||
});
|
||||
|
||||
it("renders a per-kind table row and the overall fidelity %", () => {
|
||||
const md = formatReport(report);
|
||||
assert.match(md, /prose/);
|
||||
assert.match(md, /75/);
|
||||
});
|
||||
|
||||
it("a complete run is not labelled partial", () => {
|
||||
const md = formatReport({ ...report, partial: false });
|
||||
assert.doesNotMatch(md, /PARTIAL/i);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,94 @@
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { runEval } from "../../../open-sse/services/compression/eval/runner.ts";
|
||||
import { CONTROL_PAIR } from "../../../open-sse/services/compression/eval/judge.ts";
|
||||
import type { EvalCase, ModelClient } from "../../../open-sse/services/compression/eval/types.ts";
|
||||
|
||||
const corpus: EvalCase[] = [
|
||||
{ id: "p1", kind: "prose", context: "the sky is blue", question: "what color is the sky?", gold: "blue" },
|
||||
{ id: "c1", kind: "code", context: "function f(){return 7}", question: "what does f return?", gold: "7" },
|
||||
];
|
||||
|
||||
/** Stub that answers questions, judges fidelity, grades gold — keyed off prompt content. */
|
||||
function smartStub(opts: { answerModel: string; judgeModel: string }): ModelClient {
|
||||
return {
|
||||
async complete(model, messages) {
|
||||
const sys = messages.find((m) => m.role === "system")?.content ?? "";
|
||||
const user = messages.find((m) => m.role === "user")?.content ?? "";
|
||||
// Self-test control pair (judge): rank degraded vs good correctly.
|
||||
if (model === opts.judgeModel && user.includes(CONTROL_PAIR.degraded)) {
|
||||
return { text: "VERDICT: MATERIALLY_DIFFERS", usdCost: 0.01 };
|
||||
}
|
||||
if (model === opts.judgeModel && /judge|materially/i.test(sys)) {
|
||||
return { text: "VERDICT: SAME", usdCost: 0.01 };
|
||||
}
|
||||
// Gold grader: always CORRECT for this stub.
|
||||
if (/grader|correct\|incorrect/i.test(sys)) return { text: "VERDICT: CORRECT", usdCost: 0.01 };
|
||||
// Answer generation.
|
||||
return { text: "blue and seven", usdCost: 0.01 };
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const baseOpts = {
|
||||
config: { enabled: true, defaultMode: "lite", enginesExplicit: false } as any,
|
||||
comboId: null,
|
||||
combos: {},
|
||||
answerModel: "answer-model",
|
||||
judgeModel: "judge-model",
|
||||
provider: "test",
|
||||
costCapUsd: 0,
|
||||
sample: undefined as number | undefined,
|
||||
};
|
||||
|
||||
describe("eval runner", () => {
|
||||
it("aborts when the judge fails self-test (no scores emitted)", async () => {
|
||||
const broken: ModelClient = { async complete() { return { text: "VERDICT: SAME" }; } };
|
||||
const r = await runEval({ ...baseOpts, corpus, client: broken });
|
||||
assert.equal(r.aborted, true);
|
||||
assert.match(r.abortReason ?? "", /self-test/i);
|
||||
assert.equal(r.report, null);
|
||||
});
|
||||
|
||||
it("produces an aggregated report with a passing judge", async () => {
|
||||
const r = await runEval({ ...baseOpts, corpus, client: smartStub({ answerModel: "answer-model", judgeModel: "judge-model" }) });
|
||||
assert.equal(r.aborted, false);
|
||||
assert.ok(r.report);
|
||||
assert.equal(r.report!.overall.casesScored, 2);
|
||||
assert.equal(r.report!.stamps.answerModel, "answer-model");
|
||||
assert.match(r.report!.stamps.corpusHash, /^[0-9a-f]{64}$/);
|
||||
});
|
||||
|
||||
it("an errored case (model throws) is excluded but counted", async () => {
|
||||
let n = 0;
|
||||
const flaky: ModelClient = {
|
||||
async complete(model, messages) {
|
||||
const user = messages.find((m) => m.role === "user")?.content ?? "";
|
||||
if (model === "judge-model" && user.includes(CONTROL_PAIR.degraded)) return { text: "VERDICT: MATERIALLY_DIFFERS" };
|
||||
if (model === "judge-model") return { text: "VERDICT: SAME" };
|
||||
n += 1;
|
||||
if (n === 2) throw new Error("upstream 500"); // fail the 2nd answer call
|
||||
return { text: "ok", usdCost: 0.01 };
|
||||
},
|
||||
};
|
||||
const r = await runEval({ ...baseOpts, corpus, client: flaky });
|
||||
assert.equal(r.aborted, false);
|
||||
assert.equal(r.report!.overall.casesErrored, 1);
|
||||
});
|
||||
|
||||
it("the cost cap stops the run and flags partial", async () => {
|
||||
const r = await runEval({
|
||||
...baseOpts,
|
||||
costCapUsd: 0.025, // self-test (2 calls) + a little; cap trips during the case loop
|
||||
corpus,
|
||||
client: smartStub({ answerModel: "answer-model", judgeModel: "judge-model" }),
|
||||
});
|
||||
assert.equal(r.aborted, false);
|
||||
assert.equal(r.report!.partial, true);
|
||||
});
|
||||
|
||||
it("--sample N limits the cases scored", async () => {
|
||||
const r = await runEval({ ...baseOpts, sample: 1, corpus, client: smartStub({ answerModel: "answer-model", judgeModel: "judge-model" }) });
|
||||
assert.equal(r.report!.overall.casesScored + r.report!.overall.casesErrored, 1);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,27 @@
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { computeSavings } from "../../../open-sse/services/compression/eval/savings.ts";
|
||||
|
||||
describe("eval savings", () => {
|
||||
it("computes tokensBefore/after + ratio from the bodies", () => {
|
||||
const full = { messages: [{ role: "user", content: "a".repeat(400) }] };
|
||||
const compressed = { messages: [{ role: "user", content: "a".repeat(100) }] };
|
||||
const s = computeSavings(full, compressed);
|
||||
assert.ok(s.tokensBefore > s.tokensAfter);
|
||||
assert.ok(s.ratio < 1 && s.ratio > 0);
|
||||
assert.equal(s.costDelta, undefined);
|
||||
});
|
||||
|
||||
it("computes a positive costDelta when a per-1k input price is supplied", () => {
|
||||
const full = { messages: [{ role: "user", content: "a".repeat(4000) }] };
|
||||
const compressed = { messages: [{ role: "user", content: "a".repeat(1000) }] };
|
||||
const s = computeSavings(full, compressed, 0.003); // $0.003 / 1k input tokens
|
||||
assert.ok((s.costDelta ?? 0) > 0);
|
||||
});
|
||||
|
||||
it("ratio is 1 (no savings) when bodies are identical", () => {
|
||||
const body = { messages: [{ role: "user", content: "x" }] };
|
||||
const s = computeSavings(body, body);
|
||||
assert.equal(s.ratio, 1);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,24 @@
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { SEED_CORPUS } from "../../../open-sse/services/compression/eval/seedCorpus.ts";
|
||||
import { loadCorpus } from "../../../open-sse/services/compression/eval/corpus.ts";
|
||||
import type { ContentKind } from "../../../open-sse/services/compression/eval/types.ts";
|
||||
|
||||
describe("eval seed corpus", () => {
|
||||
it("loads cleanly through loadCorpus (no malformed/PII cases)", () => {
|
||||
assert.doesNotThrow(() => loadCorpus(SEED_CORPUS));
|
||||
});
|
||||
|
||||
it("covers every content kind", () => {
|
||||
const kinds = new Set<ContentKind>(SEED_CORPUS.map((c) => c.kind));
|
||||
for (const k of ["tool-output-json", "logs", "code", "prose", "multi-turn"] as ContentKind[]) {
|
||||
assert.ok(kinds.has(k), `missing kind ${k}`);
|
||||
}
|
||||
});
|
||||
|
||||
it("has unique ids and at least one gold-bearing case", () => {
|
||||
const ids = SEED_CORPUS.map((c) => c.id);
|
||||
assert.equal(new Set(ids).size, ids.length);
|
||||
assert.ok(SEED_CORPUS.some((c) => typeof c.gold === "string"));
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,33 @@
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { runSelfTest, CONTROL_PAIR } from "../../../open-sse/services/compression/eval/judge.ts";
|
||||
import type { ModelClient } from "../../../open-sse/services/compression/eval/types.ts";
|
||||
|
||||
/** A judge that correctly ranks the control pair (degraded => MATERIALLY_DIFFERS, good => SAME). */
|
||||
function correctJudge(): ModelClient {
|
||||
return {
|
||||
async complete(_model, messages) {
|
||||
const u = messages.find((m) => m.role === "user")?.content ?? "";
|
||||
const degraded = u.includes(CONTROL_PAIR.degraded);
|
||||
return { text: degraded ? "VERDICT: MATERIALLY_DIFFERS" : "VERDICT: SAME" };
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/** A broken judge that always says SAME — must FAIL self-test. */
|
||||
function brokenJudge(): ModelClient {
|
||||
return { async complete() { return { text: "VERDICT: SAME" }; } };
|
||||
}
|
||||
|
||||
describe("judge self-test gate (D-D3)", () => {
|
||||
it("a correct judge passes self-test", async () => {
|
||||
const r = await runSelfTest(correctJudge(), "judge-model");
|
||||
assert.equal(r.passed, true);
|
||||
});
|
||||
|
||||
it("a broken judge (always SAME) fails self-test", async () => {
|
||||
const r = await runSelfTest(brokenJudge(), "judge-model");
|
||||
assert.equal(r.passed, false);
|
||||
assert.match(r.detail, /degraded|control/i);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,66 @@
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { judgeFidelityBatch } from "../../../open-sse/services/compression/eval/fidelityCheck.ts";
|
||||
import type { ModelClient, ChatTurn } from "../../../open-sse/services/compression/eval/types.ts";
|
||||
function fakeClient(verdictLine: string, usdPerCall: number): ModelClient {
|
||||
return {
|
||||
async complete(_m: string, _msgs: ChatTurn[]) {
|
||||
return { text: `reasoning...\nVERDICT: ${verdictLine}`, usdCost: usdPerCall };
|
||||
},
|
||||
};
|
||||
}
|
||||
test("returns one verdict per item under the cap", async () => {
|
||||
const client = fakeClient("SAME", 0.01);
|
||||
const items = [
|
||||
{ id: "rtk", original: "hello world foo", compressed: "hello world" },
|
||||
{ id: "caveman", original: "hello world foo", compressed: "hello" },
|
||||
];
|
||||
const out = await judgeFidelityBatch(client, "judge-model", items, 1.0);
|
||||
assert.equal(out.results.length, 2);
|
||||
assert.equal(out.results[0].verdict, "same");
|
||||
assert.equal(out.capped, false);
|
||||
assert.ok(out.totalUsd > 0);
|
||||
});
|
||||
test("stops at the USD cap and marks the rest skippedCapped", async () => {
|
||||
const client = fakeClient("MATERIALLY_DIFFERS", 0.04);
|
||||
const items = [
|
||||
{ id: "a", original: "x", compressed: "y" },
|
||||
{ id: "b", original: "x", compressed: "y" },
|
||||
{ id: "c", original: "x", compressed: "y" },
|
||||
{ id: "d", original: "x", compressed: "y" },
|
||||
];
|
||||
const out = await judgeFidelityBatch(client, "judge-model", items, 0.1); // 0.04*3=0.12>0.10
|
||||
assert.equal(out.capped, true);
|
||||
assert.equal(out.results.filter((r) => !r.skippedCapped).length, 3);
|
||||
assert.equal(out.results.filter((r) => r.skippedCapped).length, 1);
|
||||
assert.equal(out.results[0].verdict, "materially-differs");
|
||||
});
|
||||
import { readFileSync } from "node:fs";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { dirname, join } from "node:path";
|
||||
test("verify route enforces auth before reading the body and sanitizes errors", () => {
|
||||
const here = dirname(fileURLToPath(import.meta.url));
|
||||
const src = readFileSync(
|
||||
join(here, "../../../src/app/api/compression/compare/verify/route.ts"),
|
||||
"utf8"
|
||||
);
|
||||
const authIdx = src.indexOf("requireManagementAuth(req)");
|
||||
const bodyIdx = src.indexOf("req.json()");
|
||||
assert.ok(authIdx > -1 && bodyIdx > -1 && authIdx < bodyIdx, "auth gate must precede body read");
|
||||
assert.match(src, /sanitizeErrorMessage/);
|
||||
assert.match(src, /judgeFidelityBatch/);
|
||||
});
|
||||
test("verify route uses the priced judge client so the USD cap is not inert", () => {
|
||||
const here = dirname(fileURLToPath(import.meta.url));
|
||||
const src = readFileSync(
|
||||
join(here, "../../../src/app/api/compression/compare/verify/route.ts"),
|
||||
"utf8"
|
||||
);
|
||||
// must build the cost-aware client (computes usdCost via pricing lookup)
|
||||
assert.match(src, /createPricedJudgeClient/);
|
||||
// must NOT use the bare cost-blind createExecutorModelClient (that reintroduces the inert cap)
|
||||
assert.ok(
|
||||
!/createExecutorModelClient\s*\(/.test(src),
|
||||
"route must not use the cost-blind createExecutorModelClient"
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,60 @@
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { checkFidelity } from "../../../open-sse/services/compression/fidelityGate.ts";
|
||||
|
||||
const ON = { enabled: true };
|
||||
|
||||
test("protected-tokens: dropping a URL/path/ident fails", () => {
|
||||
const input = "see https://api.example.com/v2 and src/lib/db/core.ts and getDbInstance()";
|
||||
const out = "see and and";
|
||||
const r = checkFidelity(input, out, ON);
|
||||
assert.equal(r.passed, false);
|
||||
assert.equal(r.failedInvariant, "protected-tokens");
|
||||
});
|
||||
|
||||
test("protected-tokens: preserving them passes", () => {
|
||||
const input = "call getDbInstance() at src/lib/db/core.ts";
|
||||
const out = "call getDbInstance() at src/lib/db/core.ts (terse)";
|
||||
assert.equal(checkFidelity(input, out, ON).passed, true);
|
||||
});
|
||||
|
||||
test("numeric: a dropped/altered number fails", () => {
|
||||
assert.equal(
|
||||
checkFidelity("14 passed, 1 failed", "4 passed, 1 failed", ON).failedInvariant,
|
||||
"numeric"
|
||||
);
|
||||
assert.equal(checkFidelity("14 passed, 1 failed", "14 passed, 1 failed (ok)", ON).passed, true);
|
||||
});
|
||||
|
||||
test("json-keys: dropping keys below threshold fails", () => {
|
||||
// Output preserves all input numbers but renames all keys → numeric passes, json-keys fails
|
||||
const input = JSON.stringify({ packages: 1, audited: 2, vulnerabilities: 0, funding: 3 });
|
||||
const out = '{"renamed_pkg":1,"aud":2,"vulns":0,"f":3}';
|
||||
assert.equal(checkFidelity(input, out, ON).failedInvariant, "json-keys");
|
||||
});
|
||||
|
||||
test("json-keys: all keys + numbers preserved passes", () => {
|
||||
// keys alpha/beta survive AND numbers 1/2 survive → json-keys (and numeric/tokens) all pass
|
||||
assert.equal(
|
||||
checkFidelity('{"alpha":1,"beta":2}', '{"alpha":1,"beta":2} (compacted)', ON).passed,
|
||||
true
|
||||
);
|
||||
});
|
||||
|
||||
test("diff-hunks: dropping a @@ header fails", () => {
|
||||
const input = "@@ -1,3 +1,4 @@\n-old\n+new";
|
||||
const out = "-old\n+new";
|
||||
assert.equal(checkFidelity(input, out, ON).failedInvariant, "diff-hunks");
|
||||
});
|
||||
|
||||
test("diff-hunks: header preserved passes", () => {
|
||||
assert.equal(checkFidelity("@@ -1,3 +1,4 @@\n-old", "@@ -1,3 +1,4 @@\n+new", ON).passed, true);
|
||||
});
|
||||
|
||||
test("fail-open + disabled-config defaults", () => {
|
||||
assert.equal(checkFidelity("", "", ON).passed, true);
|
||||
assert.equal(
|
||||
checkFidelity("port 8080", "port", { enabled: true, checkNumericIntegrity: false }).passed,
|
||||
true
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,90 @@
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { applyStackedCompression } from "../../../open-sse/services/compression/strategySelector.ts";
|
||||
import { registerCompressionEngine, unregisterCompressionEngine } from "../../../open-sse/services/compression/engines/registry.ts";
|
||||
import type { CompressionEngine } from "../../../open-sse/services/compression/engines/types.ts";
|
||||
|
||||
const corruptor: CompressionEngine = {
|
||||
id: "corruptor",
|
||||
name: "Corruptor",
|
||||
description: "Test engine that drops port numbers",
|
||||
icon: "🔧",
|
||||
targets: ["messages"],
|
||||
stackable: true,
|
||||
stackPriority: 0,
|
||||
metadata: {
|
||||
id: "corruptor",
|
||||
name: "Corruptor",
|
||||
description: "Test engine that drops port numbers",
|
||||
inputScope: "messages",
|
||||
targetLatencyMs: 0,
|
||||
supportsPreview: false,
|
||||
stable: false,
|
||||
},
|
||||
apply(body) {
|
||||
const messages = (body.messages as Array<{ role: string; content: string }>).map((m) => ({
|
||||
...m, content: m.content.replace("8080", ""),
|
||||
}));
|
||||
return {
|
||||
body: { ...body, messages }, compressed: true,
|
||||
stats: { originalTokens: 10, compressedTokens: 8, savingsPercent: 20,
|
||||
techniquesUsed: ["corrupt"], mode: "stacked", timestamp: 0 } as never,
|
||||
};
|
||||
},
|
||||
compress(body) {
|
||||
return this.apply(body);
|
||||
},
|
||||
getConfigSchema: () => ([]),
|
||||
validateConfig: () => ({ valid: true, errors: [] }),
|
||||
};
|
||||
const body = () => ({ messages: [{ role: "user", content: "listen on port 8080 now" }] });
|
||||
test.beforeEach(() => registerCompressionEngine(corruptor));
|
||||
test.after(() => unregisterCompressionEngine("corruptor"));
|
||||
|
||||
test("gate ON rejects the corrupting step (keeps input, marks rejected)", () => {
|
||||
const res = applyStackedCompression(body(), [{ engine: "corruptor" }], { fidelityGate: { enabled: true } });
|
||||
const msg = (res.body.messages as Array<{ content: string }>)[0].content;
|
||||
assert.ok(msg.includes("8080"), "input preserved — corrupting step was rejected");
|
||||
const entry = res.stats?.engineBreakdown?.find((e) => e.engine === "corruptor");
|
||||
assert.equal(entry?.rejected, true);
|
||||
assert.equal(entry?.savingsPercent, 0);
|
||||
});
|
||||
test("gate OFF (absent) is byte-identical legacy — corrupting step advances", () => {
|
||||
const res = applyStackedCompression(body(), [{ engine: "corruptor" }]);
|
||||
const msg = (res.body.messages as Array<{ content: string }>)[0].content;
|
||||
assert.ok(!msg.includes("8080"), "no gate → corrupting step advances");
|
||||
const entry = res.stats?.engineBreakdown?.find((e) => e.engine === "corruptor");
|
||||
assert.notEqual(entry?.rejected, true);
|
||||
});
|
||||
|
||||
const cleanEngine: CompressionEngine = {
|
||||
...corruptor, id: "cleanish",
|
||||
apply(body) {
|
||||
// produces stats + advances, does NOT corrupt (keeps 8080)
|
||||
return { body, compressed: true, stats: { originalTokens: 10, compressedTokens: 9, savingsPercent: 10, techniquesUsed: ["clean"], mode: "stacked", timestamp: 0 } as never };
|
||||
},
|
||||
};
|
||||
const noStatsCorruptor: CompressionEngine = {
|
||||
...corruptor, id: "nostats",
|
||||
apply(body) {
|
||||
const messages = (body.messages as Array<{ role: string; content: string }>).map((m) => ({ ...m, content: m.content.replace("8080", "") }));
|
||||
return { body: { ...body, messages }, compressed: true, stats: null as never }; // compressed:true but NO stats
|
||||
},
|
||||
};
|
||||
|
||||
test("a no-stats rejected step does not wrongly mark the prior engine's breakdown entry", () => {
|
||||
registerCompressionEngine(cleanEngine);
|
||||
registerCompressionEngine(noStatsCorruptor);
|
||||
try {
|
||||
const res = applyStackedCompression(
|
||||
{ messages: [{ role: "user", content: "listen on port 8080 now" }] },
|
||||
[{ engine: "cleanish" }, { engine: "nostats" }],
|
||||
{ fidelityGate: { enabled: true } }
|
||||
);
|
||||
const cleanEntry = res.stats?.engineBreakdown?.find((e) => e.engine === "cleanish");
|
||||
assert.notEqual(cleanEntry?.rejected, true, "prior clean engine must NOT be marked rejected by the no-stats step");
|
||||
} finally {
|
||||
unregisterCompressionEngine("cleanish");
|
||||
unregisterCompressionEngine("nostats");
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,13 @@
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import type { CompressionConfig, CompressionStats } from "../../../open-sse/services/compression/types.ts";
|
||||
import type { FidelityGateConfig } from "../../../open-sse/services/compression/fidelityGate.ts";
|
||||
test("CompressionConfig accepts a fidelityGate block and breakdown carries rejected fields", () => {
|
||||
const cfg: CompressionConfig = { fidelityGate: { enabled: true } as FidelityGateConfig };
|
||||
assert.equal(cfg.fidelityGate?.enabled, true);
|
||||
const entry: NonNullable<CompressionStats["engineBreakdown"]>[number] = {
|
||||
engine: "caveman", originalTokens: 10, compressedTokens: 10, savingsPercent: 0,
|
||||
techniquesUsed: [], rejected: true, rejectReason: "numeric: 14 ausente",
|
||||
};
|
||||
assert.equal(entry.rejected, true);
|
||||
});
|
||||
@@ -0,0 +1,202 @@
|
||||
{
|
||||
"name": "long-coding-session",
|
||||
"description": "Simulates a 50-message coding session with tool results, file contents, and error messages",
|
||||
"messages": [
|
||||
{
|
||||
"role": "system",
|
||||
"content": "You are a helpful coding assistant. Follow instructions carefully."
|
||||
},
|
||||
{ "role": "user", "content": "I need to fix the authentication module. Can you help me?" },
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": "Of course! Let me start by examining the authentication module. I'll look at the relevant files first."
|
||||
},
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": null,
|
||||
"tool_calls": [
|
||||
{
|
||||
"id": "call_001",
|
||||
"type": "function",
|
||||
"function": { "name": "read_file", "arguments": "{\"path\": \"src/auth/login.ts\"}" }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"role": "tool",
|
||||
"tool_call_id": "call_001",
|
||||
"name": "read_file",
|
||||
"content": "File: src/auth/login.ts (lines 1-150)\n```typescript\nimport { Request, Response } from 'express';\nimport jwt from 'jsonwebtoken';\nimport bcrypt from 'bcryptjs';\nimport { UserRepository } from '../repositories/UserRepository';\nimport { SessionManager } from '../services/SessionManager';\nimport { RateLimiter } from '../middleware/RateLimiter';\nimport { Logger } from '../utils/Logger';\n\nconst JWT_SECRET = process.env.JWT_SECRET || 'default-secret-change-me';\nconst JWT_EXPIRY = '24h';\nconst MAX_LOGIN_ATTEMPTS = 5;\nconst LOCKOUT_DURATION_MS = 15 * 60 * 1000;\n\nexport async function handleLogin(req: Request, res: Response): Promise<void> {\n const { email, password } = req.body;\n \n if (!email || !password) {\n return res.status(400).json({ error: 'Email and password are required' });\n }\n \n const rateLimitResult = await RateLimiter.check(email);\n if (rateLimitResult.locked) {\n return res.status(429).json({ error: 'Too many login attempts. Try again later.' });\n }\n \n try {\n const user = await UserRepository.findByEmail(email);\n if (!user) {\n await RateLimiter.recordFailure(email);\n return res.status(401).json({ error: 'Invalid credentials' });\n }\n \n const isValid = await bcrypt.compare(password, user.passwordHash);\n if (!isValid) {\n await RateLimiter.recordFailure(email);\n return res.status(401).json({ error: 'Invalid credentials' });\n }\n \n await RateLimiter.reset(email);\n const token = jwt.sign({ userId: user.id, email: user.email }, JWT_SECRET, { expiresIn: JWT_EXPIRY });\n await SessionManager.create(user.id, token);\n \n Logger.info('auth:login', { userId: user.id, email: user.email });\n return res.json({ token, user: { id: user.id, email: user.email, name: user.name } });\n } catch (error) {\n Logger.error('auth:login', error);\n return res.status(500).json({ error: 'Internal server error' });\n }\n}\n```"
|
||||
},
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": "I can see the login handler. It has rate limiting, JWT token generation, and session management. Let me also check the session manager to understand the full flow."
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Yes, check the session manager too. Also I'm getting a 500 error when trying to log in."
|
||||
},
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": null,
|
||||
"tool_calls": [
|
||||
{
|
||||
"id": "call_002",
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "read_file",
|
||||
"arguments": "{\"path\": \"src/services/SessionManager.ts\"}"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"role": "tool",
|
||||
"tool_call_id": "call_002",
|
||||
"name": "read_file",
|
||||
"content": "File: src/services/SessionManager.ts (lines 1-80)\n```typescript\nimport { Redis } from 'ioredis';\nimport { Logger } from '../utils/Logger';\n\nconst SESSION_TTL = 86400;\nconst SESSION_PREFIX = 'session:';\n\nexport class SessionManager {\n private static redis: Redis;\n \n static async initialize(): Promise<void> {\n SessionManager.redis = new Redis(process.env.REDIS_URL || 'redis://localhost:6379');\n Logger.info('session:initialized', { status: 'connected' });\n }\n \n static async create(userId: string, token: string): Promise<void> {\n const key = `${SESSION_PREFIX}${token}`;\n await SessionManager.redis.setex(key, SESSION_TTL, JSON.stringify({ userId, createdAt: Date.now() }));\n Logger.info('session:created', { userId });\n }\n \n static async validate(token: string): Promise<{ userId: string } | null> {\n const key = `${SESSION_PREFIX}${token}`;\n const data = await SessionManager.redis.get(key);\n if (!data) return null;\n return JSON.parse(data);\n }\n \n static async destroy(token: string): Promise<void> {\n const key = `${SESSION_PREFIX}${token}`;\n await SessionManager.redis.del(key);\n Logger.info('session:destroyed', { token: token.substring(0, 8) + '...' });\n }\n}\n```"
|
||||
},
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": "I see the issue. The SessionManager uses Redis but doesn't handle connection failures gracefully. If Redis is down, the `create` method will throw an unhandled error, causing the 500 you're seeing."
|
||||
},
|
||||
{ "role": "user", "content": "That makes sense. Can you also check the error logs?" },
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": null,
|
||||
"tool_calls": [
|
||||
{
|
||||
"id": "call_003",
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "shell",
|
||||
"arguments": "{\"command\": \"grep -r 'ECONNREFUSED\\|ETIMEDOUT\\|Redis connection' /var/log/app/ | tail -20\"}"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"role": "tool",
|
||||
"tool_call_id": "call_003",
|
||||
"name": "shell",
|
||||
"content": "2024-01-15 10:23:45 [ERROR] Redis connection refused: ECONNREFUSED 127.0.0.1:6379\n2024-01-15 10:23:46 [ERROR] Redis connection refused: ECONNREFUSED 127.0.0.1:6379\n2024-01-15 10:23:47 [ERROR] Redis connection refused: ECONNREFUSED 127.0.0.1:6379\n2024-01-15 10:24:01 [WARN] Session fallback: using in-memory store\n2024-01-15 10:24:15 [ERROR] Redis connection refused: ECONNREFUSED 127.0.0.1:6379\n2024-01-15 10:24:16 [ERROR] Redis connection refused: ECONNREFUSED 127.0.0.1:6379\n2024-01-15 10:24:17 [ERROR] Redis connection refused: ECONNREFUSED 127.0.0.1:6379\n2024-01-15 10:25:30 [ERROR] Redis connection refused: ECONNREFUSED 127.0.0.1:6379\n2024-01-15 10:25:31 [ERROR] Redis connection refused: ECONNREFUSED 127.0.0.1:6379\n2024-01-15 10:25:32 [ERROR] Redis connection refused: ECONNREFUSED 127.0.0.1:6379\n2024-01-15 10:26:00 [ERROR] Redis connection refused: ECONNREFUSED 127.0.0.1:6379\n2024-01-15 10:26:01 [ERROR] Redis connection refused: ECONNREFUSED 127.0.0.1:6379\n2024-01-15 10:26:02 [ERROR] Redis connection refused: ECONNREFUSED 127.0.0.1:6379\n2024-01-15 10:26:30 [ERROR] Redis connection refused: ECONNREFUSED 127.0.0.1:6379\n2024-01-15 10:26:31 [ERROR] Redis connection refused: ECONNREFUSED 127.0.0.1:6379\n2024-01-15 10:26:32 [ERROR] Redis connection refused: ECONNREFUSED 127.0.0.1:6379\n2024-01-15 10:27:00 [ERROR] Redis connection refused: ECONNREFUSED 127.0.0.1:6379\n2024-01-15 10:27:01 [ERROR] Redis connection refused: ECONNREFUSED 127.0.0.1:6379\n2024-01-15 10:27:02 [ERROR] Redis connection refused: ECONNREFUSED 127.0.0.1:6379\n2024-01-15 10:27:30 [ERROR] Redis connection refused: ECONNREFUSED 127.0.0.1:6379"
|
||||
},
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": "The logs confirm it — Redis is consistently refusing connections. The SessionManager needs a fallback mechanism. Let me write the fix."
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Great, please fix it. Also add proper error handling and a fallback to in-memory storage."
|
||||
},
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": "I'll update the SessionManager with proper error handling and an in-memory fallback. Here's my plan:\n\n1. Add try/catch around all Redis operations\n2. Implement an in-memory Map as fallback\n3. Add connection health checks\n4. Add automatic Redis reconnection"
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Sounds good. Let me also see the test results after you make the changes."
|
||||
},
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": null,
|
||||
"tool_calls": [
|
||||
{
|
||||
"id": "call_004",
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "shell",
|
||||
"arguments": "{\"command\": \"npm test 2>&1 | tail -30\"}"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"role": "tool",
|
||||
"tool_call_id": "call_004",
|
||||
"name": "shell",
|
||||
"content": "Running tests...\n\n auth/login.test.ts\n ✓ should return 400 for missing email\n ✓ should return 400 for missing password\n ✓ should return 401 for invalid credentials\n ✓ should return 401 for wrong password\n ✓ should return 429 when rate limited\n ✓ should return 500 on internal error\n ✓ should return token on successful login\n ✓ should create session on successful login\n ✓ should reset rate limiter on successful login\n\n services/SessionManager.test.ts\n ✓ should create session in Redis\n ✓ should validate existing session\n ✓ should return null for invalid session\n ✓ should destroy session\n ✓ should handle Redis connection errors gracefully\n\n 14 tests passed\n 0 tests failed\n Duration: 2.3s"
|
||||
},
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": "All tests pass. Now let me implement the fix for the SessionManager."
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Perfect. Also, I noticed the password hashing is using bcryptjs which is synchronous. Can we switch to the async version?"
|
||||
},
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": "Good catch. The `bcrypt.compare` call in the login handler is actually already async — `bcryptjs` exports both sync and async versions, and we're using the async one. But let me double-check the import."
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": "I also want to add rate limiting per IP address, not just per email. Can you look into that?"
|
||||
},
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": "Sure. Let me check the current rate limiter implementation first."
|
||||
},
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": null,
|
||||
"tool_calls": [
|
||||
{
|
||||
"id": "call_005",
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "read_file",
|
||||
"arguments": "{\"path\": \"src/middleware/RateLimiter.ts\"}"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"role": "tool",
|
||||
"tool_call_id": "call_005",
|
||||
"name": "read_file",
|
||||
"content": "File: src/middleware/RateLimiter.ts (lines 1-60)\n```typescript\nimport { Redis } from 'ioredis';\n\nconst MAX_ATTEMPTS = 5;\nconst WINDOW_MS = 15 * 60 * 1000;\n\nexport class RateLimiter {\n private static redis: Redis;\n private static attempts = new Map<string, { count: number; expiresAt: number }>();\n \n static async check(key: string): Promise<{ locked: boolean; remaining: number }> {\n const now = Date.now();\n const entry = RateLimiter.attempts.get(key);\n if (!entry || entry.expiresAt < now) {\n return { locked: false, remaining: MAX_ATTEMPTS };\n }\n return { locked: entry.count >= MAX_ATTEMPTS, remaining: MAX_ATTEMPTS - entry.count };\n }\n \n static async recordFailure(key: string): Promise<void> {\n const now = Date.now();\n const entry = RateLimiter.attempts.get(key) || { count: 0, expiresAt: now + WINDOW_MS };\n entry.count++;\n RateLimiter.attempts.set(key, entry);\n }\n \n static async reset(key: string): Promise<void> {\n RateLimiter.attempts.delete(key);\n }\n}\n```"
|
||||
},
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": "I see — the RateLimiter uses an in-memory Map but doesn't use Redis. It also only keys by email, not IP. I'll add IP-based rate limiting as a separate layer."
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Good. Make sure the IP rate limiting has a higher threshold than the email-based one."
|
||||
},
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": "Will do. I'll set IP rate limiting at 100 requests per 15 minutes, while keeping email-based at 5 attempts."
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Also, I want to add logging for all failed login attempts with the IP address."
|
||||
},
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": "Understood. I'll add structured logging for failed attempts including IP, email, and timestamp."
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": "One more thing — can you add CORS headers to the auth endpoints?"
|
||||
},
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": "Yes, I'll add CORS middleware. What origins should we allow?"
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Allow https://app.example.com and https://admin.example.com for production, and http://localhost:3000 for development."
|
||||
},
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": "Got it. I'll configure CORS with those origins and proper preflight handling."
|
||||
},
|
||||
{ "role": "user", "content": "Thanks. Let me review the changes once you're done." },
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": "All changes are ready. Here's a summary:\n\n1. **SessionManager**: Added try/catch with in-memory fallback\n2. **RateLimiter**: Added IP-based rate limiting (100/15min)\n3. **Login handler**: Added structured error logging with IP\n4. **CORS**: Configured for app.example.com, admin.example.com, localhost:3000\n\nAll 14 tests pass. Ready for your review."
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
Completed 1.0 MiB/2.0 MiB
|
||||
Completed 2.0 MiB/2.0 MiB
|
||||
upload: ./app.log to s3://omniroute-logs/app.log
|
||||
An error occurred (AccessDenied) when calling the PutObject operation: denied
|
||||
@@ -0,0 +1,4 @@
|
||||
src/app.ts:1:1 lint/suspicious/noExplicitAny
|
||||
! Unexpected any. Specify a different type.
|
||||
|
||||
Checked 12 files in 18ms. No fixes applied.
|
||||
@@ -0,0 +1,3 @@
|
||||
vite v5.4.0 building for production...
|
||||
transforming (42) src/app.ts
|
||||
✓ built in 1.23s
|
||||
@@ -0,0 +1,3 @@
|
||||
webpack 5.91.0 compiled with 1 error in 1200 ms
|
||||
asset main.js 120 KiB [emitted] [minimized]
|
||||
ERROR in ./src/app.ts
|
||||
@@ -0,0 +1,4 @@
|
||||
Fetching gem metadata from https://rubygems.org/
|
||||
Installing rack 3.0.9
|
||||
Installing puma 6.4.2
|
||||
Bundle complete! 12 Gemfile dependencies, 42 gems now installed.
|
||||
@@ -0,0 +1,4 @@
|
||||
% Total % Received % Xferd Average Speed Time Time Time Current
|
||||
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
|
||||
HTTP/1.1 500 Internal Server Error
|
||||
curl: (22) The requested URL returned error: 500
|
||||
@@ -0,0 +1,4 @@
|
||||
Filesystem Size Used Avail Use% Mounted on
|
||||
udev 2.0G 0 2.0G 0% /dev
|
||||
/dev/sda1 50G 45G 5.0G 90% /
|
||||
/dev/sdb1 200G 120G 80G 60% /data
|
||||
@@ -0,0 +1,4 @@
|
||||
2026-05-02T12:00:00Z INFO starting worker
|
||||
2026-05-02T12:00:01Z WARN retrying provider request
|
||||
2026-05-02T12:00:02Z ERROR upstream timeout
|
||||
2026-05-02T12:00:03Z INFO shutdown
|
||||
@@ -0,0 +1,4 @@
|
||||
4.0K package.json
|
||||
12K src
|
||||
120M node_modules
|
||||
120M node_modules
|
||||
@@ -0,0 +1,4 @@
|
||||
Traceback (most recent call last):
|
||||
File "app.py", line 1, in <module>
|
||||
raise RuntimeError("boom")
|
||||
RuntimeError: boom
|
||||
@@ -0,0 +1,5 @@
|
||||
/repo/src/app.ts
|
||||
12:7 error Unexpected any. Specify a different type @typescript-eslint/no-explicit-any
|
||||
18:3 warning Missing return type on function @typescript-eslint/explicit-function-return-type
|
||||
|
||||
✖ 2 problems (1 error, 1 warning)
|
||||
@@ -0,0 +1,3 @@
|
||||
Waiting for operation [deploy] to complete...
|
||||
Updated property [core/project].
|
||||
ERROR: (gcloud.run.deploy) PERMISSION_DENIED: Permission denied on resource project omniroute.
|
||||
@@ -0,0 +1,3 @@
|
||||
* feature/rtk-compression-roadmap
|
||||
feature/caveman-compression-update
|
||||
main
|
||||
@@ -0,0 +1,8 @@
|
||||
diff --git a/src/app.ts b/src/app.ts
|
||||
index 1111111..2222222 100644
|
||||
--- a/src/app.ts
|
||||
+++ b/src/app.ts
|
||||
@@ -1,3 +1,4 @@
|
||||
export function run() {
|
||||
+ return "rtk";
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
On branch feature/rtk-compression-roadmap
|
||||
Changes not staged for commit:
|
||||
modified: open-sse/services/compression/engines/rtk/commandDetector.ts
|
||||
Untracked files:
|
||||
tests/unit/compression/fixtures/rtk/git-status-sample.txt
|
||||
@@ -0,0 +1,5 @@
|
||||
pkg/router/router.go:10:2: SA4006: this value of err is never used (staticcheck)
|
||||
pkg/main.go:22:1: File is not `gofmt`-ed (gofmt)
|
||||
2 issues:
|
||||
* staticcheck: 1
|
||||
* gofmt: 1
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"status": "ok",
|
||||
"filters": [
|
||||
"rtk",
|
||||
"caveman"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
make[1]: Entering directory '/repo'
|
||||
gcc -O2 -c src/main.c
|
||||
gcc -O2 -c src/main.c
|
||||
src/main.c:12:3: error: expected ';' before 'return'
|
||||
make[1]: Leaving directory '/repo'
|
||||
make: *** [Makefile:12: build] Error 2
|
||||
@@ -0,0 +1,2 @@
|
||||
src/app.py:12: error: Incompatible return value type (got "str", expected "int") [return-value]
|
||||
Found 1 error in 1 file (checked 5 source files)
|
||||
@@ -0,0 +1,2 @@
|
||||
found 1 vulnerabilities (1 critical)
|
||||
run `npm audit fix` to fix them, or `npm audit` for details
|
||||
@@ -0,0 +1,6 @@
|
||||
> nx run web:build
|
||||
|
||||
> nx run api:test
|
||||
|
||||
NX Running target build for 2 projects
|
||||
NX Successfully ran target build for 2 projects
|
||||
@@ -0,0 +1,4 @@
|
||||
Collecting requests
|
||||
Downloading requests-2.31.0-py3-none-any.whl
|
||||
Installing collected packages: requests
|
||||
Successfully installed requests-2.31.0
|
||||
@@ -0,0 +1,6 @@
|
||||
Running 3 tests using 1 worker
|
||||
ok 1 tests/login.spec.ts:3:1 › login works (1.2s)
|
||||
x 2 tests/app.spec.ts:8:1 › app renders (4.0s)
|
||||
|
||||
1 failed
|
||||
tests/app.spec.ts:8:1 › app renders
|
||||
@@ -0,0 +1,5 @@
|
||||
Installing dependencies from lock file
|
||||
|
||||
Package operations: 2 installs, 0 updates, 0 removals
|
||||
- Installing pydantic (2.9.2)
|
||||
- Installing httpx (0.28.1)
|
||||
@@ -0,0 +1,4 @@
|
||||
Checking formatting...
|
||||
[warn] src/app.ts
|
||||
[warn] src/routes.ts
|
||||
[warn] Code style issues found in 2 files. Run Prettier with --write to fix.
|
||||
@@ -0,0 +1,4 @@
|
||||
USER PID %CPU COMMAND
|
||||
root 1 0.0 /sbin/init
|
||||
node 1234 5.0 node server.js
|
||||
diego 2345 0.2 bash
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user