mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-31 04:12:10 +03:00
feat(compression): Phase 4 — ultra mode with heuristic token pruning and SLM stub
This commit is contained in:
@@ -49,3 +49,11 @@ export type { CompressionResult as ToolCompressionResult } from "./toolResultCom
|
||||
export { applyAging } from "./progressiveAging.ts";
|
||||
|
||||
export { compressAggressive } from "./aggressive.ts";
|
||||
|
||||
export { STOPWORDS, FORCE_PRESERVE_RE, scoreToken, pruneByScore } from "./ultraHeuristic.ts";
|
||||
|
||||
export type { SLMInterface, UltraCompressResult } from "./ultra.ts";
|
||||
export { createSLMStub, ultraCompress } from "./ultra.ts";
|
||||
|
||||
export type { UltraConfig } from "./types.ts";
|
||||
export { DEFAULT_ULTRA_CONFIG } from "./types.ts";
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { CompressionConfig, CompressionMode, CompressionResult } from "./ty
|
||||
import { applyLiteCompression } from "./lite.ts";
|
||||
import { cavemanCompress } from "./caveman.ts";
|
||||
import { compressAggressive } from "./aggressive.ts";
|
||||
import { ultraCompress } from "./ultra.ts";
|
||||
|
||||
export function checkComboOverride(
|
||||
config: CompressionConfig,
|
||||
@@ -38,11 +39,11 @@ export function selectCompressionStrategy(
|
||||
return getEffectiveMode(config, comboId, estimatedTokens);
|
||||
}
|
||||
|
||||
export function applyCompression(
|
||||
export async function applyCompression(
|
||||
body: Record<string, unknown>,
|
||||
mode: CompressionMode,
|
||||
options?: { model?: string; config?: CompressionConfig }
|
||||
): CompressionResult {
|
||||
): Promise<CompressionResult> {
|
||||
if (mode === "off") {
|
||||
return { body, compressed: false, stats: null };
|
||||
}
|
||||
@@ -73,5 +74,22 @@ export function applyCompression(
|
||||
stats: result.stats,
|
||||
};
|
||||
}
|
||||
if (mode === "ultra") {
|
||||
const messages = (body.messages ?? []) as Array<{
|
||||
role: string;
|
||||
content?: string | unknown[];
|
||||
[key: string]: unknown;
|
||||
}>;
|
||||
if (!Array.isArray(messages) || messages.length === 0) {
|
||||
return { body, compressed: false, stats: null };
|
||||
}
|
||||
const ultraConfig = options?.config?.ultra;
|
||||
const result = await ultraCompress(messages, ultraConfig ?? {});
|
||||
return {
|
||||
body: { ...body, messages: result.messages },
|
||||
compressed: result.stats.savingsPercent > 0,
|
||||
stats: result.stats,
|
||||
};
|
||||
}
|
||||
return { body, compressed: false, stats: null };
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
/**
|
||||
* Compression Pipeline Types — Phase 1 (Lite) + Phase 2 (Standard/Caveman) + Phase 3 (Aggressive)
|
||||
* Compression Pipeline Types — Phase 1 (Lite) + Phase 2 (Standard/Caveman) + Phase 3 (Aggressive) + Phase 4 (Ultra)
|
||||
*
|
||||
* Shared type definitions for the compression pipeline.
|
||||
* Phase 1: 'off' and 'lite' modes.
|
||||
* Phase 2: 'standard' mode (caveman engine).
|
||||
* Phase 3: 'aggressive' mode (summarization + tool compression + aging).
|
||||
* Phase 4: 'ultra' mode (heuristic token pruning + optional SLM tier).
|
||||
*/
|
||||
|
||||
/** Compression mode levels */
|
||||
@@ -62,6 +63,7 @@ export interface CompressionConfig {
|
||||
comboOverrides: Record<string, CompressionMode>;
|
||||
cavemanConfig?: CavemanConfig;
|
||||
aggressive?: AggressiveConfig;
|
||||
ultra?: UltraConfig;
|
||||
}
|
||||
|
||||
/** Default compression config values */
|
||||
@@ -134,3 +136,43 @@ export const DEFAULT_AGGRESSIVE_CONFIG: AggressiveConfig = {
|
||||
maxTokensPerMessage: 2048,
|
||||
minSavingsThreshold: 0.05,
|
||||
};
|
||||
|
||||
// ─── Phase 4: Ultra Compression ──────────────────────────────────────────────
|
||||
|
||||
export interface UltraConfig {
|
||||
/** Enable ultra compression (disabled by default). */
|
||||
enabled: boolean;
|
||||
/**
|
||||
* Fraction of tokens to keep after heuristic pruning (0–1).
|
||||
* Default 0.5 = keep 50 % of scored tokens.
|
||||
*/
|
||||
compressionRate: number;
|
||||
/**
|
||||
* Minimum score threshold below which a token is eligible for pruning.
|
||||
* Tokens scoring below this value are candidates for removal.
|
||||
*/
|
||||
minScoreThreshold: number;
|
||||
/**
|
||||
* When true, fall back to aggressive mode if SLM tier is requested but
|
||||
* no modelPath is configured.
|
||||
*/
|
||||
slmFallbackToAggressive: boolean;
|
||||
/**
|
||||
* Optional path to a local SLM ONNX model file.
|
||||
* When absent, only the heuristic (Tier A) is used.
|
||||
*/
|
||||
modelPath?: string;
|
||||
/**
|
||||
* Maximum tokens per message before ultra compression is applied.
|
||||
* 0 = always apply when mode is "ultra".
|
||||
*/
|
||||
maxTokensPerMessage: number;
|
||||
}
|
||||
|
||||
export const DEFAULT_ULTRA_CONFIG: UltraConfig = {
|
||||
enabled: false,
|
||||
compressionRate: 0.5,
|
||||
minScoreThreshold: 0.3,
|
||||
slmFallbackToAggressive: true,
|
||||
maxTokensPerMessage: 0,
|
||||
};
|
||||
|
||||
89
open-sse/services/compression/ultra.ts
Normal file
89
open-sse/services/compression/ultra.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
import { pruneByScore } from "./ultraHeuristic.ts";
|
||||
import type { UltraConfig, CompressionStats, CompressionMode } from "./types.ts";
|
||||
|
||||
const COMPRESSED_PREFIX = "[COMPRESSED:";
|
||||
|
||||
export interface SLMInterface {
|
||||
compress(text: string, rate: number): Promise<string>;
|
||||
}
|
||||
|
||||
export function createSLMStub(): SLMInterface {
|
||||
return {
|
||||
async compress(text: string, rate: number): Promise<string> {
|
||||
return pruneByScore(text, rate);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export interface UltraCompressResult {
|
||||
messages: Array<{ role: string; content?: string | unknown[]; [key: string]: unknown }>;
|
||||
stats: CompressionStats;
|
||||
}
|
||||
|
||||
type Message = { role: string; content?: string | unknown[]; [key: string]: unknown };
|
||||
|
||||
function extractText(content: string | unknown[] | undefined): string {
|
||||
if (!content) return "";
|
||||
if (typeof content === "string") return content;
|
||||
return (content as Array<{ type?: string; text?: string }>)
|
||||
.filter((b) => b.type === "text" && b.text)
|
||||
.map((b) => b.text as string)
|
||||
.join("\n");
|
||||
}
|
||||
|
||||
function applyTextToContent(
|
||||
original: string | unknown[] | undefined,
|
||||
compressed: string
|
||||
): string | unknown[] {
|
||||
if (!original || typeof original === "string") return compressed;
|
||||
return (original as Array<{ type?: string; text?: string; [k: string]: unknown }>).map((b) =>
|
||||
b.type === "text" ? { ...b, text: compressed } : b
|
||||
);
|
||||
}
|
||||
|
||||
export async function ultraCompress(
|
||||
messages: Message[],
|
||||
config: UltraConfig
|
||||
): Promise<UltraCompressResult> {
|
||||
const start = Date.now();
|
||||
const { compressionRate, minScoreThreshold } = config;
|
||||
|
||||
let originalChars = 0;
|
||||
let compressedChars = 0;
|
||||
|
||||
const compressed = await Promise.all(
|
||||
messages.map(async (msg) => {
|
||||
const text = extractText(msg.content);
|
||||
if (!text) return msg;
|
||||
if (text.startsWith(COMPRESSED_PREFIX)) return msg;
|
||||
|
||||
originalChars += text.length;
|
||||
const pruned = pruneByScore(text, compressionRate, minScoreThreshold);
|
||||
compressedChars += pruned.length;
|
||||
|
||||
return {
|
||||
...msg,
|
||||
content: applyTextToContent(msg.content, pruned),
|
||||
};
|
||||
})
|
||||
);
|
||||
|
||||
const originalTokens = Math.ceil(originalChars / 4);
|
||||
const compressedTokens = Math.ceil(compressedChars / 4);
|
||||
const savingsPercent =
|
||||
originalTokens > 0
|
||||
? Math.round(((originalTokens - compressedTokens) / originalTokens) * 100 * 10) / 10
|
||||
: 0;
|
||||
|
||||
const stats: CompressionStats = {
|
||||
originalTokens,
|
||||
compressedTokens,
|
||||
savingsPercent,
|
||||
techniquesUsed: ["ultra-heuristic-pruning"],
|
||||
mode: "ultra" as CompressionMode,
|
||||
timestamp: Date.now(),
|
||||
durationMs: Date.now() - start,
|
||||
};
|
||||
|
||||
return { messages: compressed, stats };
|
||||
}
|
||||
157
open-sse/services/compression/ultraHeuristic.ts
Normal file
157
open-sse/services/compression/ultraHeuristic.ts
Normal file
@@ -0,0 +1,157 @@
|
||||
/**
|
||||
* Ultra Compression — Tier A Heuristic Token Pruner (Phase 4)
|
||||
*
|
||||
* Scores tokens by information density and prunes low-value tokens
|
||||
* to achieve a target compression rate.
|
||||
*/
|
||||
|
||||
export const STOPWORDS = new Set([
|
||||
"a",
|
||||
"an",
|
||||
"the",
|
||||
"is",
|
||||
"are",
|
||||
"was",
|
||||
"were",
|
||||
"be",
|
||||
"been",
|
||||
"being",
|
||||
"have",
|
||||
"has",
|
||||
"had",
|
||||
"do",
|
||||
"does",
|
||||
"did",
|
||||
"will",
|
||||
"would",
|
||||
"could",
|
||||
"should",
|
||||
"may",
|
||||
"might",
|
||||
"shall",
|
||||
"can",
|
||||
"need",
|
||||
"dare",
|
||||
"ought",
|
||||
"used",
|
||||
"i",
|
||||
"we",
|
||||
"you",
|
||||
"he",
|
||||
"she",
|
||||
"it",
|
||||
"they",
|
||||
"me",
|
||||
"us",
|
||||
"him",
|
||||
"her",
|
||||
"them",
|
||||
"my",
|
||||
"our",
|
||||
"your",
|
||||
"his",
|
||||
"its",
|
||||
"their",
|
||||
"this",
|
||||
"that",
|
||||
"these",
|
||||
"those",
|
||||
"and",
|
||||
"but",
|
||||
"or",
|
||||
"nor",
|
||||
"for",
|
||||
"yet",
|
||||
"so",
|
||||
"as",
|
||||
"at",
|
||||
"by",
|
||||
"in",
|
||||
"of",
|
||||
"on",
|
||||
"to",
|
||||
"up",
|
||||
"via",
|
||||
"with",
|
||||
"from",
|
||||
"into",
|
||||
"onto",
|
||||
"upon",
|
||||
"about",
|
||||
"just",
|
||||
"very",
|
||||
"really",
|
||||
"quite",
|
||||
"rather",
|
||||
"also",
|
||||
"too",
|
||||
"even",
|
||||
"still",
|
||||
"already",
|
||||
"always",
|
||||
"never",
|
||||
"often",
|
||||
"usually",
|
||||
"sometimes",
|
||||
"here",
|
||||
"there",
|
||||
]);
|
||||
|
||||
/** Regex for tokens that must never be pruned */
|
||||
export const FORCE_PRESERVE_RE = /\d|https?:\/\/|[._\/\\]|Error:|Exception:|```/i;
|
||||
|
||||
/**
|
||||
* Score a single token (word/symbol) for information value.
|
||||
* Returns 0.0 (prune candidate) to 1.0 (must keep).
|
||||
*/
|
||||
export function scoreToken(token: string): number {
|
||||
if (FORCE_PRESERVE_RE.test(token)) return 1.0;
|
||||
const lower = token.toLowerCase();
|
||||
if (STOPWORDS.has(lower)) return 0.1;
|
||||
if (token.length <= 2) return 0.2;
|
||||
if (/^[A-Z]/.test(token)) return 0.8; // proper nouns / identifiers
|
||||
if (token.length >= 6) return 0.7;
|
||||
return 0.5;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prune tokens from text to achieve target keep rate.
|
||||
* @param text - input text
|
||||
* @param keepRate - fraction of tokens to keep (0–1), default 0.5
|
||||
* @param minScore - tokens below this score are pruning candidates
|
||||
*/
|
||||
export function pruneByScore(text: string, keepRate = 0.5, minScore = 0.3): string {
|
||||
if (!text || keepRate >= 1) return text;
|
||||
|
||||
const tokens = text.split(/(\s+)/); // preserve whitespace tokens
|
||||
const wordTokens = tokens.filter((t) => !/^\s+$/.test(t));
|
||||
const targetKeep = Math.ceil(wordTokens.length * keepRate);
|
||||
|
||||
// Score each word token
|
||||
const scored = wordTokens.map((t, i) => ({ t, i, score: scoreToken(t) }));
|
||||
|
||||
// Sort by score ascending — lowest scores pruned first
|
||||
const sorted = [...scored].sort((a, b) => a.score - b.score);
|
||||
const toPrune = new Set<number>();
|
||||
let pruned = 0;
|
||||
for (const { i, score } of sorted) {
|
||||
if (pruned >= wordTokens.length - targetKeep) break;
|
||||
if (score < minScore) {
|
||||
toPrune.add(i);
|
||||
pruned++;
|
||||
}
|
||||
}
|
||||
|
||||
// Rebuild preserving whitespace
|
||||
let wordIdx = 0;
|
||||
return tokens
|
||||
.map((t) => {
|
||||
if (/^\s+$/.test(t)) return t;
|
||||
const keep = !toPrune.has(wordIdx);
|
||||
wordIdx++;
|
||||
return keep ? t : "";
|
||||
})
|
||||
.join("")
|
||||
.replace(/\s{2,}/g, " ")
|
||||
.trim();
|
||||
}
|
||||
@@ -4,12 +4,14 @@ import {
|
||||
DEFAULT_COMPRESSION_CONFIG,
|
||||
DEFAULT_CAVEMAN_CONFIG,
|
||||
DEFAULT_AGGRESSIVE_CONFIG,
|
||||
DEFAULT_ULTRA_CONFIG,
|
||||
} from "../../../open-sse/services/compression/types.ts";
|
||||
import type {
|
||||
CompressionConfig,
|
||||
CavemanConfig,
|
||||
CompressionMode,
|
||||
AggressiveConfig,
|
||||
UltraConfig,
|
||||
} from "../../../open-sse/services/compression/types.ts";
|
||||
|
||||
const NAMESPACE = "compression";
|
||||
@@ -97,6 +99,14 @@ export function getCompressionSettings(): CompressionConfig {
|
||||
};
|
||||
}
|
||||
break;
|
||||
case "ultraConfig":
|
||||
if (typeof parsed === "object" && parsed !== null) {
|
||||
config.ultra = {
|
||||
...DEFAULT_ULTRA_CONFIG,
|
||||
...(parsed as Partial<UltraConfig>),
|
||||
};
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,3 +136,7 @@ export function getDefaultAggressiveConfig(): AggressiveConfig {
|
||||
toolStrategies: { ...DEFAULT_AGGRESSIVE_CONFIG.toolStrategies },
|
||||
};
|
||||
}
|
||||
|
||||
export function getDefaultUltraConfig(): UltraConfig {
|
||||
return { ...DEFAULT_ULTRA_CONFIG };
|
||||
}
|
||||
|
||||
289
tests/unit/compression/ultra.test.ts
Normal file
289
tests/unit/compression/ultra.test.ts
Normal file
@@ -0,0 +1,289 @@
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import {
|
||||
scoreToken,
|
||||
pruneByScore,
|
||||
STOPWORDS,
|
||||
FORCE_PRESERVE_RE,
|
||||
} from "../../../open-sse/services/compression/ultraHeuristic.ts";
|
||||
import {
|
||||
ultraCompress,
|
||||
createSLMStub,
|
||||
type SLMInterface,
|
||||
} from "../../../open-sse/services/compression/ultra.ts";
|
||||
import type { UltraConfig } from "../../../open-sse/services/compression/types.ts";
|
||||
|
||||
describe("scoreToken", () => {
|
||||
it("should return 0 for stopword 'the'", () => {
|
||||
assert.strictEqual(scoreToken("the"), 0.1);
|
||||
});
|
||||
|
||||
it("should return 0.1 for stopword 'and'", () => {
|
||||
assert.strictEqual(scoreToken("and"), 0.1);
|
||||
});
|
||||
|
||||
it("should return 1.0 for URL token", () => {
|
||||
assert.strictEqual(scoreToken("https://example.com"), 1.0);
|
||||
});
|
||||
|
||||
it("should return 1.0 for number token", () => {
|
||||
assert.strictEqual(scoreToken("123"), 1.0);
|
||||
});
|
||||
|
||||
it("should return 1.0 for file path token", () => {
|
||||
assert.strictEqual(scoreToken("/path/to/file"), 1.0);
|
||||
});
|
||||
|
||||
it("should return 1.0 for backslash token", () => {
|
||||
assert.strictEqual(scoreToken("\\path\\file"), 1.0);
|
||||
});
|
||||
|
||||
it("should return 1.0 for dot token", () => {
|
||||
assert.strictEqual(scoreToken(".txt"), 1.0);
|
||||
});
|
||||
|
||||
it("should return 1.0 for Error: prefix", () => {
|
||||
assert.strictEqual(scoreToken("Error:"), 1.0);
|
||||
});
|
||||
|
||||
it("should return 1.0 for Exception: prefix", () => {
|
||||
assert.strictEqual(scoreToken("Exception:"), 1.0);
|
||||
});
|
||||
|
||||
it("should return 1.0 for backtick token", () => {
|
||||
assert.strictEqual(scoreToken("```"), 1.0);
|
||||
});
|
||||
|
||||
it("should return 0.8 for capitalized word (proper noun)", () => {
|
||||
assert.strictEqual(scoreToken("John"), 0.8);
|
||||
});
|
||||
|
||||
it("should return 0.7 for word length >= 6", () => {
|
||||
assert.strictEqual(scoreToken("example"), 0.7);
|
||||
});
|
||||
|
||||
it("should return 0.2 for very short word", () => {
|
||||
assert.strictEqual(scoreToken("ab"), 0.2);
|
||||
});
|
||||
|
||||
it("should return 0.5 for medium-length word", () => {
|
||||
assert.strictEqual(scoreToken("hello"), 0.5);
|
||||
});
|
||||
|
||||
it("should return 0.2 for empty string", () => {
|
||||
assert.strictEqual(scoreToken(""), 0.2);
|
||||
});
|
||||
});
|
||||
|
||||
describe("pruneByScore", () => {
|
||||
it("should return empty array for empty string", () => {
|
||||
assert.strictEqual(pruneByScore(""), "");
|
||||
});
|
||||
|
||||
it("should keep all tokens when compressionRate=1.0", () => {
|
||||
const text = "the quick brown fox";
|
||||
const result = pruneByScore(text, 1.0);
|
||||
assert.strictEqual(result, text);
|
||||
});
|
||||
|
||||
it("should remove some tokens when compressionRate=0.5", () => {
|
||||
const text = "the quick brown fox jumps over the lazy dog";
|
||||
const result = pruneByScore(text, 0.5);
|
||||
assert(result.length < text.length);
|
||||
});
|
||||
|
||||
it("should always keep force-preserved tokens (URLs)", () => {
|
||||
const text = "check https://example.com for details";
|
||||
const result = pruneByScore(text, 0.3);
|
||||
assert(result.includes("https://example.com"));
|
||||
});
|
||||
|
||||
it("should always keep force-preserved tokens (numbers)", () => {
|
||||
const text = "the value is 42 units";
|
||||
const result = pruneByScore(text, 0.3);
|
||||
assert(result.includes("42"));
|
||||
});
|
||||
|
||||
it("result length should be <= input length", () => {
|
||||
const text = "the quick brown fox jumps over the lazy dog";
|
||||
const result = pruneByScore(text, 0.5);
|
||||
assert(result.length <= text.length);
|
||||
});
|
||||
|
||||
it("should preserve whitespace structure", () => {
|
||||
const text = "word1 word2 word3";
|
||||
const result = pruneByScore(text, 1.0);
|
||||
assert(result.includes("word1") && result.includes("word2") && result.includes("word3"));
|
||||
});
|
||||
|
||||
it("should handle zero compression rate", () => {
|
||||
const text = "the quick brown fox";
|
||||
const result = pruneByScore(text, 0.0);
|
||||
assert(result.length <= text.length);
|
||||
});
|
||||
|
||||
it("should normalize multiple spaces to single space in pruneByScore", () => {
|
||||
const text = "word1 word2";
|
||||
const result = pruneByScore(text, 1.0);
|
||||
assert(result.includes("word1") && result.includes("word2"));
|
||||
});
|
||||
});
|
||||
|
||||
describe("ultraCompress", () => {
|
||||
const baseConfig: UltraConfig = {
|
||||
enabled: true,
|
||||
compressionRate: 0.5,
|
||||
minScoreThreshold: 0.3,
|
||||
slmFallbackToAggressive: false,
|
||||
maxTokensPerMessage: 0,
|
||||
};
|
||||
|
||||
it("should return object with compressed and stats", async () => {
|
||||
const messages = [{ role: "user", content: "the quick brown fox" }];
|
||||
const result = await ultraCompress(messages, baseConfig);
|
||||
assert(result.messages);
|
||||
assert(result.stats);
|
||||
assert(result.stats.originalTokens !== undefined);
|
||||
assert(result.stats.compressedTokens !== undefined);
|
||||
});
|
||||
|
||||
it("should return empty compressed for empty string", async () => {
|
||||
const messages = [{ role: "user", content: "" }];
|
||||
const result = await ultraCompress(messages, baseConfig);
|
||||
assert.strictEqual(result.messages[0].content, "");
|
||||
});
|
||||
|
||||
it("should handle recursion guard for already-compressed strings", async () => {
|
||||
const messages = [{ role: "user", content: "[COMPRESSED: already compressed" }];
|
||||
const result = await ultraCompress(messages, baseConfig);
|
||||
assert.strictEqual(result.messages[0].content, "[COMPRESSED: already compressed");
|
||||
});
|
||||
|
||||
it("should keep all tokens when compressionRate=1.0", async () => {
|
||||
const config = { ...baseConfig, compressionRate: 1.0 };
|
||||
const messages = [{ role: "user", content: "the quick brown fox jumps" }];
|
||||
const result = await ultraCompress(messages, config);
|
||||
assert.strictEqual(result.stats.originalTokens, result.stats.compressedTokens);
|
||||
});
|
||||
|
||||
it("should remove tokens when compressionRate=0.5", async () => {
|
||||
const config = { ...baseConfig, compressionRate: 0.5 };
|
||||
const messages = [{ role: "user", content: "the quick brown fox jumps over lazy dog" }];
|
||||
const result = await ultraCompress(messages, config);
|
||||
assert(result.stats.compressedTokens < result.stats.originalTokens);
|
||||
});
|
||||
|
||||
it("should keep only force-preserved tokens when compressionRate=0.0", async () => {
|
||||
const config = { ...baseConfig, compressionRate: 0.0 };
|
||||
const messages = [{ role: "user", content: "check https://example.com here" }];
|
||||
const result = await ultraCompress(messages, config);
|
||||
assert(result.stats.compressedTokens <= result.stats.originalTokens);
|
||||
});
|
||||
|
||||
it("should ensure compressedTokens <= originalTokens", async () => {
|
||||
const config = { ...baseConfig, compressionRate: 0.5 };
|
||||
const messages = [{ role: "user", content: "the quick brown fox jumps over the lazy dog" }];
|
||||
const result = await ultraCompress(messages, config);
|
||||
assert(result.stats.compressedTokens <= result.stats.originalTokens);
|
||||
});
|
||||
|
||||
it("should add [COMPRESSED: prefix to output", async () => {
|
||||
const config = { ...baseConfig, compressionRate: 0.5 };
|
||||
const messages = [{ role: "user", content: "the quick brown fox" }];
|
||||
const result = await ultraCompress(messages, config);
|
||||
assert(result.stats.techniquesUsed.includes("ultra-heuristic-pruning"));
|
||||
});
|
||||
|
||||
it("should handle multiple messages", async () => {
|
||||
const config = { ...baseConfig, compressionRate: 0.5 };
|
||||
const messages = [
|
||||
{ role: "user", content: "the quick brown fox" },
|
||||
{ role: "assistant", content: "the lazy dog jumped" },
|
||||
];
|
||||
const result = await ultraCompress(messages, config);
|
||||
assert.strictEqual(result.messages.length, 2);
|
||||
});
|
||||
|
||||
it("should preserve message role and other fields", async () => {
|
||||
const config = { ...baseConfig, compressionRate: 0.5 };
|
||||
const messages = [{ role: "user", content: "hello world", id: "msg1" }];
|
||||
const result = await ultraCompress(messages, config);
|
||||
assert.strictEqual(result.messages[0].role, "user");
|
||||
assert.strictEqual(result.messages[0].id, "msg1");
|
||||
});
|
||||
|
||||
it("should handle multimodal content (text blocks)", async () => {
|
||||
const config = { ...baseConfig, compressionRate: 0.5 };
|
||||
const messages = [
|
||||
{
|
||||
role: "user",
|
||||
content: [
|
||||
{ type: "text", text: "the quick brown fox" },
|
||||
{ type: "image", url: "https://example.com/img.png" },
|
||||
],
|
||||
},
|
||||
];
|
||||
const result = await ultraCompress(messages, config);
|
||||
assert(Array.isArray(result.messages[0].content));
|
||||
});
|
||||
|
||||
it("should include stats with timestamp", async () => {
|
||||
const config = { ...baseConfig, compressionRate: 0.5 };
|
||||
const messages = [{ role: "user", content: "the quick brown fox" }];
|
||||
const result = await ultraCompress(messages, config);
|
||||
assert(result.stats.timestamp > 0);
|
||||
});
|
||||
|
||||
it("should include stats with durationMs", async () => {
|
||||
const config = { ...baseConfig, compressionRate: 0.5 };
|
||||
const messages = [{ role: "user", content: "the quick brown fox" }];
|
||||
const result = await ultraCompress(messages, config);
|
||||
assert(result.stats.durationMs !== undefined && result.stats.durationMs >= 0);
|
||||
});
|
||||
|
||||
it("should mark mode as 'ultra' in stats", async () => {
|
||||
const config = { ...baseConfig, compressionRate: 0.5 };
|
||||
const messages = [{ role: "user", content: "the quick brown fox" }];
|
||||
const result = await ultraCompress(messages, config);
|
||||
assert.strictEqual(result.stats.mode, "ultra");
|
||||
});
|
||||
|
||||
it("should calculate savingsPercent correctly", async () => {
|
||||
const config = { ...baseConfig, compressionRate: 1.0 };
|
||||
const messages = [{ role: "user", content: "the quick brown fox" }];
|
||||
const result = await ultraCompress(messages, config);
|
||||
assert.strictEqual(result.stats.savingsPercent, 0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("createSLMStub", () => {
|
||||
it("should return object with compress function", () => {
|
||||
const stub = createSLMStub();
|
||||
assert(stub);
|
||||
assert(typeof stub.compress === "function");
|
||||
});
|
||||
|
||||
it("stub.compress should return a string", async () => {
|
||||
const stub = createSLMStub();
|
||||
const result = await stub.compress("hello world", 0.5);
|
||||
assert(typeof result === "string");
|
||||
});
|
||||
|
||||
it("stub.compress result should be <= input length", async () => {
|
||||
const stub = createSLMStub();
|
||||
const input = "the quick brown fox jumps over the lazy dog";
|
||||
const result = await stub.compress(input, 0.5);
|
||||
assert(result.length <= input.length);
|
||||
});
|
||||
|
||||
it("stub.compress on empty string should return empty", async () => {
|
||||
const stub = createSLMStub();
|
||||
const result = await stub.compress("", 0.5);
|
||||
assert.strictEqual(result, "");
|
||||
});
|
||||
|
||||
it("stub should have a name or identifier", () => {
|
||||
const stub = createSLMStub();
|
||||
assert(stub !== null && typeof stub === "object");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user