Merge pull request #1738 from oyi77/feat/compression-phase2

feat(compression): Phase 2 — Caveman Compression Engine (30 rules, 72 tests, UI, API)
This commit is contained in:
Diego Rodrigues de Sa e Souza
2026-04-30 17:14:49 -03:00
committed by GitHub
67 changed files with 4116 additions and 702 deletions

View File

@@ -126,6 +126,12 @@ import {
} from "../services/modelFamilyFallback.ts";
import { computeRequestHash, deduplicate, shouldDeduplicate } from "../services/requestDedup.ts";
import { compressContext, estimateTokens, getTokenLimit } from "../services/contextManager.ts";
import {
selectCompressionStrategy,
applyCompression,
} from "../services/compression/strategySelector.ts";
import { estimateCompressionTokens } from "../services/compression/stats.ts";
import { getCompressionSettings } from "../../src/lib/db/compression.ts";
import {
getBackgroundTaskReason,
getDegradedModel,
@@ -1562,7 +1568,7 @@ export async function handleChatCore({
if (body && Array.isArray(allMessages) && allMessages.length > 0) {
let estimatedTokens = estimateTokens(JSON.stringify(allMessages));
// --- Modular Compression Pipeline (Phase 1: Lite mode) ---
// --- Modular Compression Pipeline (Phase 1 Lite + Phase 2 Standard/Caveman) ---
// Runs BEFORE the existing reactive compressContext() to proactively reduce tokens.
try {
const { getCompressionSettings } = await import("../../src/lib/db/compression.ts");
@@ -1572,7 +1578,7 @@ export async function handleChatCore({
const config = await getCompressionSettings();
const mode = selectCompressionStrategy(config, comboName ?? null, estimatedTokens);
if (mode !== "off") {
const result = applyCompression(body, mode, { model: effectiveModel });
const result = applyCompression(body, mode, { model: effectiveModel, config });
if (result.compressed && result.stats) {
body = result.body as typeof body;
estimatedTokens = result.stats.compressedTokens;
@@ -1636,6 +1642,31 @@ export async function handleChatCore({
`Checking compression: ${estimatedTokens} tokens vs ${threshold} threshold (${contextLimit} limit, ${reservedTokens} reserved)`
);
// Prompt compression pipeline — Phase 1 (lite) + Phase 2 (standard/caveman)
try {
const compressionConfig = getCompressionSettings();
const estimatedTokens = estimateCompressionTokens(body);
const mode = selectCompressionStrategy(compressionConfig, comboName ?? null, estimatedTokens);
if (mode !== "off") {
const compressionResult = applyCompression(body as Record<string, unknown>, mode, {
model: effectiveModel,
config: compressionConfig,
});
if (compressionResult.compressed && compressionResult.stats) {
body = compressionResult.body as typeof body;
const s = compressionResult.stats;
log?.info?.(
"COMPRESSION",
`Prompt compression (${s.mode}): ${s.originalTokens}${s.compressedTokens} tokens (${s.savingsPercent}% savings, ${s.durationMs ?? 0}ms${
s.rulesApplied?.length ? `, rules: ${s.rulesApplied.join(", ")}` : ""
})`
);
}
}
} catch (err) {
log?.warn?.("COMPRESSION", "Prompt compression failed (non-fatal): " + err);
}
if (estimatedTokens > threshold) {
log?.info?.(
"CONTEXT",

View File

@@ -0,0 +1,149 @@
import type { CavemanConfig, CavemanRule, CompressionResult, CompressionMode } from "./types.ts";
import { DEFAULT_CAVEMAN_CONFIG } from "./types.ts";
import { CAVEMAN_RULES, getRulesForContext } from "./cavemanRules.ts";
import { extractPreservedBlocks, restorePreservedBlocks } from "./preservation.ts";
import { createCompressionStats, estimateCompressionTokens } from "./stats.ts";
interface ChatMessage {
role: string;
content?: string | Array<{ type: string; text?: string }>;
}
interface ChatRequestBody {
messages?: ChatMessage[];
[key: string]: unknown;
}
export function applyRulesToText(
text: string,
rules: CavemanRule[]
): { text: string; appliedRules: string[] } {
let result = text;
const appliedRules: string[] = [];
for (const rule of rules) {
const before = result;
const { pattern, replacement } = rule;
if (typeof replacement === "function") {
const fn = replacement;
result = result.replace(pattern, (...args) => {
const match = args[0];
return fn(match, ...args.slice(1, -2));
});
} else {
result = result.replace(pattern, replacement);
}
if (result !== before) {
appliedRules.push(rule.name);
}
}
return { text: result, appliedRules };
}
function cleanupArtifacts(text: string): string {
let result = text;
result = result.replace(/ +/g, " ");
result = result.replace(/ +$/gm, "");
result = result.replace(/\n{3,}/g, "\n\n");
result = result.replace(/^\n+/, "");
result = result.replace(/\n+$/, "");
return result;
}
export function cavemanCompress(
body: ChatRequestBody,
options?: Partial<CavemanConfig>
): CompressionResult {
const startMs = performance.now();
const config: CavemanConfig = { ...DEFAULT_CAVEMAN_CONFIG, ...options };
const emptyResult = (): CompressionResult => ({
body: body as unknown as Record<string, unknown>,
compressed: false,
stats: createCompressionStats(
body as unknown as Record<string, unknown>,
body as unknown as Record<string, unknown>,
"standard" as CompressionMode,
[]
),
});
if (!config.enabled) {
return emptyResult();
}
if (!body.messages || !Array.isArray(body.messages) || body.messages.length === 0) {
return emptyResult();
}
let totalOriginalTokens = 0;
let totalCompressedTokens = 0;
const allAppliedRules: string[] = [];
const compressedMessages = body.messages.map((msg): ChatMessage => {
// Only compress simple string content — multi-part messages (arrays)
// would duplicate compressed text across all text parts if naively handled
if (typeof msg.content !== "string") {
const contentStr = Array.isArray(msg.content)
? msg.content
.map((part) => (part.type === "text" && part.text ? part.text : ""))
.filter(Boolean)
.join("\n")
: "";
totalOriginalTokens += estimateCompressionTokens(contentStr);
totalCompressedTokens += estimateCompressionTokens(contentStr);
return msg;
}
const contentStr = msg.content;
totalOriginalTokens += estimateCompressionTokens(contentStr);
if (!contentStr || contentStr.length < config.minMessageLength) {
totalCompressedTokens += estimateCompressionTokens(contentStr);
return msg;
}
if (!config.compressRoles.includes(msg.role as "user" | "assistant" | "system")) {
totalCompressedTokens += estimateCompressionTokens(contentStr);
return msg;
}
const { text: extractedText, blocks } = extractPreservedBlocks(contentStr);
const rules = getRulesForContext(msg.role).filter(
(rule) => !config.skipRules.includes(rule.name)
);
const { text: rulesApplied, appliedRules } = applyRulesToText(extractedText, rules);
allAppliedRules.push(...appliedRules);
const restored = restorePreservedBlocks(rulesApplied, blocks);
const cleaned = cleanupArtifacts(restored);
totalCompressedTokens += estimateCompressionTokens(cleaned);
return { ...msg, content: cleaned };
});
const durationMs = performance.now() - startMs;
const uniqueRules = [...new Set(allAppliedRules)];
const stats = createCompressionStats(
body as unknown as Record<string, unknown>,
{ ...body, messages: compressedMessages } as unknown as Record<string, unknown>,
"standard" as CompressionMode,
uniqueRules.length > 0 ? ["caveman-rules"] : [],
uniqueRules.length > 0 ? uniqueRules : undefined,
Math.round(durationMs * 100) / 100
);
const compressed = totalCompressedTokens < totalOriginalTokens;
const result: CompressionResult = {
body: { ...body, messages: compressedMessages } as unknown as Record<string, unknown>,
compressed,
stats,
};
return result;
}

View File

@@ -0,0 +1,258 @@
import type { CavemanRule } from "./types.ts";
const CAVEMAN_RULES: CavemanRule[] = [
// ── Category 1: Filler Removal (10+ rules) ──────────────────────────
{
name: "polite_framing",
pattern:
/\b(?:please|kindly|could you please|would you please|can you please|I would like you to|I want you to|I need you to)\b\s*/gi,
replacement: "",
context: "all",
},
{
name: "hedging",
pattern:
/\b(?:it seems like|it appears that|I think that|I believe that|probably|possibly|maybe it)\b\s*/gi,
replacement: "",
context: "all",
},
{
name: "verbose_instructions",
pattern:
/\b(?:provide a detailed|give me a comprehensive|write an in-depth|create a thorough|explain in detail)\b/gi,
replacement: (match: string): string => {
const map: Record<string, string> = {
"provide a detailed": "provide",
"give me a comprehensive": "give",
"write an in-depth": "write",
"create a thorough": "create",
"explain in detail": "explain",
};
const lower = match.toLowerCase();
return map[lower] ?? match;
},
context: "all",
},
{
name: "filler_adverbs",
pattern: /(?<![a-z])\b(?:basically|essentially|actually|literally|simply)\b\s*/gi,
replacement: "",
context: "all",
},
{
name: "filler_phrases",
pattern: /^(?:I want to|I need to|I'd like to|I'm looking for)\b\s*/gim,
replacement: "",
context: "user",
},
{
name: "redundant_openers",
pattern: /^(?:Hi there|Hello|Good morning|Hey)\s*[,.!?\s]?\s*/gim,
replacement: "",
context: "user",
},
{
name: "verbose_requests",
pattern: /\b(?:I was wondering if you could|Would it be possible to)\b\s*/gi,
replacement: "",
context: "user",
},
{
name: "self_reference",
pattern: /^(?:I am trying to|I am working on|I have been)\b\s*/gim,
replacement: "",
context: "user",
},
{
name: "excessive_gratitude",
pattern: /\b(?:Thank you so much|Thanks in advance|I really appreciate)\b[,.!?\s]*/gi,
replacement: "",
context: "all",
},
{
name: "qualifier_removal",
pattern: /\b(?:a bit|a little|somewhat|kind of|sort of)\b\s*/gi,
replacement: "",
context: "all",
},
// ── Category 2: Context Condensation (8+ rules) ──────────────────────
{
name: "compound_collapse",
pattern: /\band any potential\b/gi,
replacement: "",
context: "all",
},
{
name: "explanatory_prefix",
pattern:
/\b(?:The function appears to be handling|The code seems to|The class is|This module is)\b/gi,
replacement: (match: string): string => {
const map: Record<string, string> = {
"the function appears to be handling": "Function:",
"the code seems to": "Code:",
"the class is": "Class:",
"this module is": "Module:",
};
return map[match.toLowerCase()] ?? match;
},
context: "all",
},
{
name: "question_to_directive",
pattern:
/\b(?:Can you explain why|Could you show me how|Would you tell me|Can you tell me)\b\s*/gi,
replacement: (match: string): string => {
const trimmed = match.trimEnd().toLowerCase();
const map: Record<string, string> = {
"can you explain why": "Explain why",
"could you show me how": "Show how",
"would you tell me": "Tell me",
"can you tell me": "Tell me",
};
return map[trimmed] ?? match;
},
context: "user",
},
{
name: "context_setup",
pattern: /\b(?:I have the following code|Here is my code|Below is the code)\b\s*[:.]?\s*/gi,
replacement: "Code:",
context: "user",
},
{
name: "intent_clarification",
pattern:
/\b(?:What I'm trying to do is|My objective is to|What I need is|I'm aiming to)\b\s*/gi,
replacement: "Goal:",
context: "user",
},
{
name: "background_removal",
pattern: /\b(?:As you may know,?\s*|As we discussed earlier,?\s*)/gi,
replacement: "",
context: "all",
},
{
name: "meta_commentary",
pattern: /^(?:Note that|Keep in mind that|Remember that)\b\s*/gim,
replacement: "",
context: "all",
},
{
name: "purpose_statement",
pattern: /\b(?:for the purpose of|with the goal of|in an effort to)\b/gi,
replacement: (match: string): string => {
const map: Record<string, string> = {
"for the purpose of": "for",
"with the goal of": "to",
"in an effort to": "to",
};
return map[match.toLowerCase()] ?? match;
},
context: "all",
},
// ── Category 3: Structural Compression (7+ rules) ────────────────────
{
name: "list_conjunction",
pattern: /,\s*and also\s+|,\s*as well as\s+/gi,
replacement: ", ",
context: "all",
},
{
name: "purpose_phrases",
pattern: /\b(?:in order to|so as to)\b\s*/gi,
replacement: "to ",
context: "all",
},
{
name: "redundant_quantifiers",
pattern: /\b(?:each and every single|each and every|any and all)\b/gi,
replacement: (match: string): string => {
const map: Record<string, string> = {
"each and every single": "each",
"each and every": "each",
"any and all": "all",
};
return map[match.toLowerCase()] ?? match;
},
context: "all",
},
{
name: "verbose_connectors",
pattern: /\b(?:furthermore|additionally|moreover|in addition)\b\s*/gi,
replacement: "also ",
context: "all",
},
{
name: "transition_removal",
pattern: /^(?:On the other hand,?\s*|In contrast,?\s*|However,?\s*)/gim,
replacement: "",
context: "all",
},
{
name: "emphasis_removal",
pattern: /\b(?:very|really|extremely|highly|quite)\s+(?=[a-z])/gi,
replacement: "",
context: "all",
},
{
name: "passive_voice",
pattern: /\b(?:is being used|is being called|was created|was generated|was implemented)\b/gi,
replacement: (match: string): string => {
const map: Record<string, string> = {
"is being used": "uses",
"is being called": "calls",
"was created": "created",
"was generated": "generated",
"was implemented": "implemented",
};
return map[match.toLowerCase()] ?? match;
},
context: "all",
},
// ── Category 4: Multi-Turn Dedup (5+ rules) ─────────────────────────
{
name: "repeated_context",
pattern:
/\b(?:As we discussed earlier|As mentioned before|As previously stated|As I said before)\b[,.]?\s*/gi,
replacement: "See above. ",
context: "all",
},
{
name: "repeated_question",
pattern:
/\b(?:Same question as before|I asked this earlier|This is the same question)\b[,.]?\s*/gi,
replacement: "[same question] ",
context: "user",
},
{
name: "reestablished_context",
pattern: /\b(?:Going back to the code above|Referring back to|Returning to)\b\s*/gi,
replacement: "Re: ",
context: "all",
},
{
name: "summary_replacement",
pattern:
/\b(?:To summarize what we've discussed|In summary of our conversation|To recap)\b[,.]?\s*/gi,
replacement: "Summary: ",
context: "assistant",
},
];
export function getRulesForContext(context: string): CavemanRule[] {
return CAVEMAN_RULES.filter((rule) => rule.context === "all" || rule.context === context);
}
export function getRuleByName(name: string): CavemanRule | undefined {
return CAVEMAN_RULES.find((rule) => rule.name === name);
}
export { CAVEMAN_RULES };

View File

@@ -1,20 +1,14 @@
/**
* Compression Pipeline — Phase 1 (Lite mode)
*
* Modular prompt compression that runs BEFORE the existing reactive context manager.
* Lite mode: 5 techniques, ~10-15% token savings, <1ms latency.
*/
// Types
export type {
CompressionMode,
CompressionConfig,
CompressionStats,
CompressionResult,
} from "./types";
export { DEFAULT_COMPRESSION_CONFIG } from "./types";
CavemanConfig,
CavemanRule,
} from "./types.ts";
export { DEFAULT_COMPRESSION_CONFIG, DEFAULT_CAVEMAN_CONFIG } from "./types.ts";
// Lite compression techniques
export {
applyLiteCompression,
collapseWhitespace,
@@ -22,10 +16,23 @@ export {
compressToolResults,
removeRedundantContent,
replaceImageUrls,
} from "./lite";
} from "./lite.ts";
// Strategy selector
export { selectCompressionStrategy, getEffectiveMode, applyCompression } from "./strategySelector";
export { cavemanCompress, applyRulesToText } from "./caveman.ts";
export { getRulesForContext, CAVEMAN_RULES } from "./cavemanRules.ts";
export { extractPreservedBlocks, restorePreservedBlocks } from "./preservation.ts";
// Stats tracking
export { estimateCompressionTokens, createCompressionStats, trackCompressionStats } from "./stats";
export {
estimateCompressionTokens,
createCompressionStats,
trackCompressionStats,
getDefaultCompressionConfig,
} from "./stats.ts";
export {
selectCompressionStrategy,
getEffectiveMode,
applyCompression,
checkComboOverride,
shouldAutoTrigger,
} from "./strategySelector.ts";

View File

@@ -1,5 +1,5 @@
import type { CompressionResult, CompressionMode } from "./types";
import { createCompressionStats } from "./stats";
import type { CompressionResult, CompressionMode } from "./types.ts";
import { createCompressionStats } from "./stats.ts";
interface Message {
role: string;
@@ -157,7 +157,7 @@ export function applyLiteCompression(
? createCompressionStats(
originalBody,
current as Record<string, unknown>,
"lite",
"lite" as CompressionMode,
techniquesApplied
)
: null;

View File

@@ -0,0 +1,53 @@
interface PreservedBlock {
placeholder: string;
content: string;
}
export function extractPreservedBlocks(text: string): { text: string; blocks: PreservedBlock[] } {
const blocks: PreservedBlock[] = [];
let result = text;
let counter = 0;
const addBlock = (content: string): string => {
const placeholder = `[PRESERVED_${counter}]`;
blocks.push({ placeholder, content });
counter++;
return placeholder;
};
// Extract fenced code blocks (```lang\n...\n```)
result = result.replace(/```[a-z]*\n[\s\S]*?\n```/g, (match) => addBlock(match));
// Extract inline code (`...`)
result = result.replace(/`[^`\n]+`/g, (match) => addBlock(match));
// Extract URLs
result = result.replace(/https?:\/\/[^\s)\]"'>]+/g, (match) => addBlock(match));
// Extract file paths (Unix and Windows)
result = result.replace(/(?:\/[a-zA-Z0-9_./-]+|[a-zA-Z]:\\[a-zA-Z0-9_.\\/-]+)/g, (match) => {
if (match.length < 3) return match;
if (match.startsWith("[PRESERVED_")) return match;
return addBlock(match);
});
// Extract error-like patterns (TypeError:, Error:, 404, etc.)
result = result.replace(
/\b(?:TypeError|ReferenceError|SyntaxError|RangeError|URIError|EvalError|Error):\s*[^\s,;)]+/g,
(match) => addBlock(match)
);
return { text: result, blocks };
}
export function restorePreservedBlocks(text: string, blocks: PreservedBlock[]): string {
let result = text;
for (const block of blocks) {
result = result.replace(block.placeholder, () => block.content);
}
return result;
}
export function shouldPreserve(text: string, preservePatterns: RegExp[]): boolean {
return preservePatterns.some((pattern) => pattern.test(text));
}

View File

@@ -1,4 +1,10 @@
import type { CompressionStats, CompressionMode } from "./types";
import {
type CompressionMode,
type CompressionStats,
type CompressionConfig,
DEFAULT_COMPRESSION_CONFIG,
DEFAULT_CAVEMAN_CONFIG,
} from "./types.ts";
const CHARS_PER_TOKEN = 4;
@@ -8,11 +14,16 @@ export function estimateCompressionTokens(text: string | object | null | undefin
return Math.ceil(str.length / CHARS_PER_TOKEN);
}
/** @deprecated Use estimateCompressionTokens instead. */
export const estimateTokensForStats = estimateCompressionTokens;
export function createCompressionStats(
originalBody: Record<string, unknown>,
compressedBody: Record<string, unknown>,
mode: CompressionMode,
techniquesUsed: string[]
techniquesUsed: string[],
rulesApplied?: string[],
durationMs?: number
): CompressionStats {
const originalTokens = estimateCompressionTokens(originalBody);
const compressedTokens = estimateCompressionTokens(compressedBody);
@@ -27,12 +38,23 @@ export function createCompressionStats(
techniquesUsed,
mode,
timestamp: Date.now(),
...(rulesApplied && rulesApplied.length > 0 ? { rulesApplied } : {}),
...(durationMs !== undefined ? { durationMs } : {}),
};
}
export function trackCompressionStats(stats: CompressionStats): void {
if (stats.originalTokens <= 0) return;
const rulesInfo = stats.rulesApplied?.length ? ` rules=${stats.rulesApplied.join(",")}` : "";
const durationInfo = stats.durationMs !== undefined ? ` ${stats.durationMs}ms` : "";
console.log(
`[COMPRESSION] mode=${stats.mode} tokens=${stats.originalTokens}->${stats.compressedTokens} savings=${stats.savingsPercent}% techniques=${stats.techniquesUsed.join(",")}`
`[COMPRESSION] mode=${stats.mode} tokens=${stats.originalTokens}->${stats.compressedTokens} savings=${stats.savingsPercent}% techniques=${stats.techniquesUsed.join(",")}${rulesInfo}${durationInfo}`
);
}
export function getDefaultCompressionConfig(): CompressionConfig {
return {
...DEFAULT_COMPRESSION_CONFIG,
cavemanConfig: { ...DEFAULT_CAVEMAN_CONFIG },
};
}

View File

@@ -1,5 +1,6 @@
import type { CompressionConfig, CompressionMode, CompressionResult } from "./types";
import { applyLiteCompression } from "./lite";
import type { CompressionConfig, CompressionMode, CompressionResult } from "./types.ts";
import { applyLiteCompression } from "./lite.ts";
import { cavemanCompress } from "./caveman.ts";
export function checkComboOverride(
config: CompressionConfig,
@@ -39,7 +40,7 @@ export function selectCompressionStrategy(
export function applyCompression(
body: Record<string, unknown>,
mode: CompressionMode,
options?: { model?: string }
options?: { model?: string; config?: CompressionConfig }
): CompressionResult {
if (mode === "off") {
return { body, compressed: false, stats: null };
@@ -47,5 +48,11 @@ export function applyCompression(
if (mode === "lite") {
return applyLiteCompression(body, options);
}
if (mode === "standard") {
return cavemanCompress(
body as Parameters<typeof cavemanCompress>[0],
options?.config?.cavemanConfig
);
}
return { body, compressed: false, stats: null };
}

View File

@@ -1,13 +1,27 @@
/**
* Compression Pipeline Types — Phase 1 (Lite mode)
* Compression Pipeline Types — Phase 1 (Lite) + Phase 2 (Standard/Caveman)
*
* Modular prompt compression that runs BEFORE the existing reactive context manager.
* Shared type definitions for the compression pipeline.
*/
/** Compression mode levels (only 'off' and 'lite' are active in Phase 1) */
export type CompressionMode = "off" | "lite" | "standard" | "aggressive" | "ultra";
/** Compression configuration stored in DB */
export interface CavemanRule {
name: string;
pattern: RegExp;
replacement: string | ((match: string, ...groups: string[]) => string);
context: "all" | "user" | "system" | "assistant";
preservePatterns?: RegExp[];
}
export interface CavemanConfig {
enabled: boolean;
compressRoles: ("user" | "assistant" | "system")[];
skipRules: string[];
minMessageLength: number;
preservePatterns: string[];
}
export interface CompressionConfig {
enabled: boolean;
defaultMode: CompressionMode;
@@ -15,9 +29,9 @@ export interface CompressionConfig {
cacheMinutes: number;
preserveSystemPrompt: boolean;
comboOverrides: Record<string, CompressionMode>;
cavemanConfig?: CavemanConfig;
}
/** Per-request compression statistics */
export interface CompressionStats {
originalTokens: number;
compressedTokens: number;
@@ -25,16 +39,16 @@ export interface CompressionStats {
techniquesUsed: string[];
mode: CompressionMode;
timestamp: number;
rulesApplied?: string[];
durationMs?: number;
}
/** Result of a compression operation */
export interface CompressionResult {
body: Record<string, unknown>;
compressed: boolean;
stats: CompressionStats | null;
}
/** Default compression config values */
export const DEFAULT_COMPRESSION_CONFIG: CompressionConfig = {
enabled: false,
defaultMode: "off",
@@ -43,3 +57,11 @@ export const DEFAULT_COMPRESSION_CONFIG: CompressionConfig = {
preserveSystemPrompt: true,
comboOverrides: {},
};
export const DEFAULT_CAVEMAN_CONFIG: CavemanConfig = {
enabled: true,
compressRoles: ["user"],
skipRules: [],
minMessageLength: 50,
preservePatterns: [],
};

View File

@@ -0,0 +1,137 @@
"use client";
import { useState, useEffect } from "react";
import { Card } from "@/shared/components";
import { useTranslations } from "next-intl";
interface CompressionStats {
originalTokens: number;
compressedTokens: number;
savingsPercent: number;
techniquesUsed: string[];
mode: string;
timestamp: number;
rulesApplied?: string[];
durationMs?: number;
}
interface LogEntry {
id: string;
timestamp: string;
model: string;
provider: string;
compressionStats?: CompressionStats | null;
}
export default function CompressionLogTab() {
const t = useTranslations("settings");
const [logs, setLogs] = useState<LogEntry[]>([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch("/api/logs?filter=compressed&limit=50")
.then((r) => (r.ok ? r.json() : []))
.then((data) => {
setLogs(Array.isArray(data) ? data : []);
})
.catch(() => {})
.finally(() => setLoading(false));
}, []);
if (loading) {
return (
<Card className="p-6">
<p className="text-sm text-text-muted">{t("loading")}</p>
</Card>
);
}
if (logs.length === 0) {
return (
<Card className="p-6">
<div className="flex items-center gap-3 mb-4">
<span className="material-symbols-outlined text-blue-500 text-[20px]">compress</span>
<h3 className="text-lg font-semibold">{t("compressionLogTitle")}</h3>
</div>
<p className="text-sm text-text-muted">{t("compressionLogEmpty")}</p>
</Card>
);
}
return (
<Card className="p-6">
<div className="flex items-center gap-3 mb-5">
<span className="material-symbols-outlined text-blue-500 text-[20px]">compress</span>
<h3 className="text-lg font-semibold">{t("compressionLogTitle")}</h3>
</div>
<div className="space-y-3">
{logs.map((entry) => {
const stats = entry.compressionStats;
if (!stats) return null;
return (
<div
key={entry.id}
className="p-3 rounded-lg border border-border/50 bg-surface/30 space-y-2"
>
<div className="flex items-center justify-between">
<div className="flex items-center gap-2 text-sm">
<span className="font-mono text-text-main">
{entry.provider}/{entry.model}
</span>
<span className="px-1.5 py-0.5 rounded text-[10px] font-medium bg-blue-500/10 text-blue-400 border border-blue-500/20">
{stats.mode}
</span>
</div>
<div className="flex items-center gap-3 text-xs text-text-muted">
<span>
{stats.originalTokens} {stats.compressedTokens} {t("tokens")}
</span>
<span
className={`font-medium ${
stats.savingsPercent >= 25
? "text-emerald-400"
: stats.savingsPercent >= 10
? "text-yellow-400"
: "text-text-muted"
}`}
>
-{stats.savingsPercent.toFixed(1)}%
</span>
{stats.durationMs !== undefined && <span>{stats.durationMs}ms</span>}
</div>
</div>
{stats.techniquesUsed.length > 0 && (
<div className="flex flex-wrap gap-1">
{stats.techniquesUsed.map((technique) => (
<span
key={technique}
className="px-1.5 py-0.5 rounded text-[10px] bg-surface text-text-muted border border-border/30"
>
{technique}
</span>
))}
</div>
)}
{stats.rulesApplied && stats.rulesApplied.length > 0 && (
<div className="flex flex-wrap gap-1">
{stats.rulesApplied.map((rule) => (
<span
key={rule}
className="px-1.5 py-0.5 rounded text-[10px] bg-purple-500/10 text-purple-400 border border-purple-500/20"
>
{rule.replace(/_/g, " ")}
</span>
))}
</div>
)}
</div>
);
})}
</div>
</Card>
);
}

View File

@@ -0,0 +1,425 @@
"use client";
import { useState, useEffect } from "react";
import { Card, Button } from "@/shared/components";
import { useTranslations } from "next-intl";
type CompressionMode = "off" | "lite" | "standard" | "aggressive" | "ultra";
interface CavemanConfig {
enabled: boolean;
compressRoles: ("user" | "assistant" | "system")[];
skipRules: string[];
minMessageLength: number;
preservePatterns: string[];
}
interface CompressionConfig {
enabled: boolean;
defaultMode: CompressionMode;
autoTriggerTokens: number;
cacheMinutes: number;
preserveSystemPrompt: boolean;
comboOverrides: Record<string, CompressionMode>;
cavemanConfig?: CavemanConfig;
}
const MODES: { value: CompressionMode; labelKey: string; descKey: string; icon: string }[] = [
{
value: "off",
labelKey: "compressionModeOff",
descKey: "compressionModeOffDesc",
icon: "block",
},
{
value: "lite",
labelKey: "compressionModeLite",
descKey: "compressionModeLiteDesc",
icon: "compress",
},
{
value: "standard",
labelKey: "compressionModeStandard",
descKey: "compressionModeStandardDesc",
icon: "speed",
},
];
const ROLE_OPTIONS: { value: "user" | "assistant" | "system"; labelKey: string }[] = [
{ value: "user", labelKey: "compressionRoleUser" },
{ value: "assistant", labelKey: "compressionRoleAssistant" },
{ value: "system", labelKey: "compressionRoleSystem" },
];
const ALL_CAVEMAN_RULES = [
"polite_framing",
"hedging",
"verbose_instructions",
"filler_adverbs",
"filler_phrases",
"redundant_openers",
"verbose_requests",
"self_reference",
"excessive_gratitude",
"qualifier_removal",
"compound_collapse",
"explanatory_prefix",
"question_to_directive",
"context_setup",
"intent_clarification",
"background_removal",
"meta_commentary",
"purpose_statement",
"list_conjunction",
"purpose_phrases",
"redundant_quantifiers",
"verbose_connectors",
"transition_removal",
"emphasis_removal",
"passive_voice",
"repeated_context",
"repeated_question",
"reestablished_context",
"summary_replacement",
];
export default function CompressionSettingsTab() {
const t = useTranslations("settings");
const [config, setConfig] = useState<CompressionConfig>({
enabled: false,
defaultMode: "off",
autoTriggerTokens: 0,
cacheMinutes: 5,
preserveSystemPrompt: true,
comboOverrides: {},
cavemanConfig: {
enabled: true,
compressRoles: ["user"],
skipRules: [],
minMessageLength: 50,
preservePatterns: [],
},
});
const [saving, setSaving] = useState(false);
const [loading, setLoading] = useState(true);
const [status, setStatus] = useState<"" | "saved" | "error">("");
useEffect(() => {
fetch("/api/settings/compression")
.then((r) => (r.ok ? r.json() : null))
.then((data) => {
if (data) setConfig(data);
})
.catch(() => {})
.finally(() => setLoading(false));
}, []);
const save = async (updates: Partial<CompressionConfig>) => {
const newConfig = { ...config, ...updates };
setConfig(newConfig);
setSaving(true);
setStatus("");
try {
const res = await fetch("/api/settings/compression", {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(newConfig),
});
if (res.ok) {
setStatus("saved");
setTimeout(() => setStatus(""), 2000);
} else {
setStatus("error");
}
} catch {
setStatus("error");
} finally {
setSaving(false);
}
};
const toggleCavemanRole = (role: "user" | "assistant" | "system") => {
const currentRoles = config.cavemanConfig?.compressRoles ?? ["user"];
const newRoles = currentRoles.includes(role)
? currentRoles.filter((r) => r !== role)
: [...currentRoles, role];
save({
cavemanConfig: { ...config.cavemanConfig!, compressRoles: newRoles },
});
};
const toggleCavemanRule = (rule: string) => {
const currentSkip = config.cavemanConfig?.skipRules ?? [];
const newSkip = currentSkip.includes(rule)
? currentSkip.filter((r) => r !== rule)
: [...currentSkip, rule];
save({
cavemanConfig: { ...config.cavemanConfig!, skipRules: newSkip },
});
};
if (loading) {
return (
<Card className="p-6">
<p className="text-sm text-text-muted">{t("loading")}</p>
</Card>
);
}
return (
<Card className="p-6">
<div className="flex items-center gap-3 mb-5">
<div className="p-2 rounded-lg bg-blue-500/10 text-blue-500">
<span className="material-symbols-outlined text-[20px]" aria-hidden="true">
compress
</span>
</div>
<div>
<h3 className="text-lg font-semibold">{t("compressionTitle")}</h3>
<p className="text-sm text-text-muted">{t("compressionDesc")}</p>
</div>
{status === "saved" && (
<span className="ml-auto text-xs font-medium text-emerald-500 flex items-center gap-1">
<span className="material-symbols-outlined text-[14px]">check_circle</span> {t("saved")}
</span>
)}
{status === "error" && (
<span className="ml-auto text-xs font-medium text-red-500 flex items-center gap-1">
<span className="material-symbols-outlined text-[14px]">error</span> {t("saveFailed")}
</span>
)}
</div>
<div className="space-y-6">
<label className="flex items-center justify-between">
<span className="text-sm text-text-muted">{t("enabled")}</span>
<button
onClick={() => save({ enabled: !config.enabled })}
className={`relative w-10 h-5 rounded-full transition-colors ${
config.enabled ? "bg-green-500" : "bg-border"
}`}
>
<span
className={`absolute top-0.5 w-4 h-4 rounded-full bg-white transition-transform ${
config.enabled ? "left-5" : "left-0.5"
}`}
/>
</button>
</label>
{config.enabled && (
<div className="space-y-3">
<h4 className="text-sm font-medium text-text-main">{t("compressionMode")}</h4>
<div className="grid grid-cols-1 sm:grid-cols-3 gap-2">
{MODES.map((m) => (
<button
key={m.value}
onClick={() => save({ defaultMode: m.value })}
disabled={saving}
className={`flex items-start gap-3 p-3 rounded-lg border text-left transition-all ${
config.defaultMode === m.value
? "border-blue-500/50 bg-blue-500/5 ring-1 ring-blue-500/20"
: "border-border/50 hover:border-border hover:bg-surface/30"
}`}
>
<span
className={`material-symbols-outlined text-[20px] mt-0.5 ${
config.defaultMode === m.value ? "text-blue-500" : "text-text-muted"
}`}
>
{m.icon}
</span>
<div className="min-w-0">
<p
className={`text-sm font-medium ${
config.defaultMode === m.value ? "text-blue-400" : ""
}`}
>
{t(m.labelKey)}
</p>
<p className="text-xs text-text-muted mt-0.5 leading-relaxed">{t(m.descKey)}</p>
</div>
</button>
))}
</div>
</div>
)}
{config.enabled && (
<div className="space-y-3 pt-4 border-t border-border/30">
<h4 className="text-sm font-medium text-text-main">{t("compressionGeneral")}</h4>
<label className="flex items-center justify-between">
<span className="text-sm text-text-muted">{t("compressionAutoTrigger")}</span>
<div className="flex items-center gap-2">
<input
type="number"
min={0}
max={100000}
value={config.autoTriggerTokens}
onChange={(e) => save({ autoTriggerTokens: parseInt(e.target.value) || 0 })}
className="w-24 px-2 py-1 text-sm rounded border border-border bg-surface text-text-main"
/>
<span className="text-xs text-text-muted">{t("tokens")}</span>
</div>
</label>
<label className="flex items-center justify-between">
<span className="text-sm text-text-muted">{t("compressionCacheTTL")}</span>
<div className="flex items-center gap-2">
<input
type="number"
min={0}
max={1440}
value={config.cacheMinutes}
onChange={(e) => save({ cacheMinutes: parseInt(e.target.value) || 5 })}
className="w-24 px-2 py-1 text-sm rounded border border-border bg-surface text-text-main"
/>
<span className="text-xs text-text-muted">{t("minutes")}</span>
</div>
</label>
<label className="flex items-center justify-between">
<span className="text-sm text-text-muted">{t("compressionPreserveSystem")}</span>
<button
onClick={() => save({ preserveSystemPrompt: !config.preserveSystemPrompt })}
className={`relative w-10 h-5 rounded-full transition-colors ${
config.preserveSystemPrompt ? "bg-green-500" : "bg-border"
}`}
>
<span
className={`absolute top-0.5 w-4 h-4 rounded-full bg-white transition-transform ${
config.preserveSystemPrompt ? "left-5" : "left-0.5"
}`}
/>
</button>
</label>
</div>
)}
{config.enabled &&
config.defaultMode !== "off" &&
config.defaultMode !== "lite" &&
config.cavemanConfig && (
<div className="space-y-3 pt-4 border-t border-border/30">
<div className="flex items-center justify-between">
<div>
<h4 className="text-sm font-medium text-text-main">
{t("compressionCavemanConfig")}
</h4>
<p className="text-xs text-text-muted mt-0.5">
{t("compressionCavemanConfigDesc")}
</p>
</div>
<button
onClick={() =>
save({
cavemanConfig: {
...config.cavemanConfig!,
enabled: !config.cavemanConfig!.enabled,
},
})
}
className={`relative w-10 h-5 rounded-full transition-colors ${
config.cavemanConfig.enabled ? "bg-green-500" : "bg-border"
}`}
>
<span
className={`absolute top-0.5 w-4 h-4 rounded-full bg-white transition-transform ${
config.cavemanConfig.enabled ? "left-5" : "left-0.5"
}`}
/>
</button>
</div>
{config.cavemanConfig.enabled && (
<>
<div className="space-y-2">
<p className="text-sm text-text-muted">{t("compressionRoles")}</p>
<div className="flex flex-wrap gap-2">
{ROLE_OPTIONS.map((opt) => (
<button
key={opt.value}
onClick={() => toggleCavemanRole(opt.value)}
className={`px-3 py-1.5 rounded-lg text-xs font-medium border transition-all ${
config.cavemanConfig!.compressRoles.includes(opt.value)
? "border-blue-500/50 bg-blue-500/10 text-blue-400"
: "border-border/50 text-text-muted hover:border-border"
}`}
>
{t(opt.labelKey)}
</button>
))}
</div>
</div>
<label className="flex items-center justify-between">
<span className="text-sm text-text-muted">{t("compressionMinLength")}</span>
<input
type="number"
min={0}
max={100000}
value={config.cavemanConfig.minMessageLength}
onChange={(e) =>
save({
cavemanConfig: {
...config.cavemanConfig!,
minMessageLength: parseInt(e.target.value) || 50,
},
})
}
className="w-24 px-2 py-1 text-sm rounded border border-border bg-surface text-text-main"
/>
</label>
<div className="space-y-2">
<p className="text-sm text-text-muted">{t("compressionSkipRules")}</p>
<p className="text-xs text-text-muted">{t("compressionSkipRulesDesc")}</p>
<div className="grid grid-cols-2 sm:grid-cols-3 gap-1.5">
{ALL_CAVEMAN_RULES.map((rule) => (
<button
key={rule}
onClick={() => toggleCavemanRule(rule)}
className={`px-2 py-1 rounded text-xs border transition-all ${
config.cavemanConfig!.skipRules.includes(rule)
? "border-red-500/50 bg-red-500/10 text-red-400 line-through"
: "border-border/50 text-text-muted hover:border-border"
}`}
>
{rule.replace(/_/g, " ")}
</button>
))}
</div>
</div>
<div className="space-y-2">
<p className="text-sm text-text-muted">{t("compressionPreservePatterns")}</p>
<p className="text-xs text-text-muted">
{t("compressionPreservePatternsDesc")}
</p>
<textarea
value={(config.cavemanConfig.preservePatterns ?? []).join("\n")}
onChange={(e) => {
const patterns = e.target.value
.split("\n")
.map((p) => p.trim())
.filter(Boolean);
save({
cavemanConfig: {
...config.cavemanConfig!,
preservePatterns: patterns,
},
});
}}
placeholder="https?://\S+\n```[\s\S]*?```"
className="w-full min-h-[80px] px-3 py-2 text-sm rounded-lg border border-border bg-surface text-text-main font-mono resize-y"
/>
</div>
</>
)}
</div>
)}
</div>
</Card>
);
}

View File

@@ -21,6 +21,7 @@ import ModelsDevSyncTab from "./components/ModelsDevSyncTab";
import ResilienceTab from "./components/ResilienceTab";
import CliproxyapiSettingsTab from "./components/CliproxyapiSettingsTab";
import PayloadRulesTab from "./components/PayloadRulesTab";
import CompressionSettingsTab from "./components/CompressionSettingsTab";
import VisionBridgeSettingsTab from "./components/VisionBridgeSettingsTab";
import MitmProxyTab from "./components/MitmProxyTab";
import ModelRoutingSection from "@/shared/components/ModelRoutingSection";
@@ -96,6 +97,7 @@ export default function SettingsPage() {
{activeTab === "ai" && (
<div className="flex flex-col gap-6">
<ThinkingBudgetTab />
<CompressionSettingsTab />
<VisionBridgeSettingsTab />
<SystemPromptTab />
<CacheSettingsTab />

View File

@@ -1,11 +1,21 @@
import { NextRequest, NextResponse } from "next/server";
import { z } from "zod";
import { getCompressionSettings, updateCompressionSettings } from "@/lib/db/compression";
import { isAuthenticated } from "@/shared/utils/apiAuth";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
import { getCompressionSettings, updateCompressionSettings } from "@/lib/db/compression";
const compressionModeSchema = z.enum(["off", "lite", "standard", "aggressive", "ultra"]);
const cavemanConfigSchema = z
.object({
enabled: z.boolean().optional(),
compressRoles: z.array(z.enum(["user", "assistant", "system"])).optional(),
skipRules: z.array(z.string()).optional(),
minMessageLength: z.number().int().min(0).optional(),
preservePatterns: z.array(z.string()).optional(),
})
.strict();
const compressionSettingsUpdateSchema = z
.object({
enabled: z.boolean().optional(),
@@ -14,6 +24,7 @@ const compressionSettingsUpdateSchema = z
cacheMinutes: z.number().int().min(1).max(60).optional(),
preserveSystemPrompt: z.boolean().optional(),
comboOverrides: z.record(z.string(), compressionModeSchema).optional(),
cavemanConfig: cavemanConfigSchema.optional(),
})
.strict();

View File

@@ -3249,7 +3249,33 @@
"pricingResetProvider": "Pricing Reset Provider",
"nextSync": "Next Sync",
"pricingSyncFailedWithReason": "Pricing Sync Failed With Reason",
"clearSyncedPricing": "Clear Synced Pricing"
"clearSyncedPricing": "Clear Synced Pricing",
"compressionTitle": "Prompt Compression",
"compressionDesc": "Reduce token usage by compressing prompts before sending to providers",
"compressionMode": "Compression Mode",
"compressionModeOff": "Off",
"compressionModeOffDesc": "No compression applied",
"compressionModeLite": "Lite",
"compressionModeLiteDesc": "Whitespace and blank line reduction",
"compressionModeStandard": "Standard (Caveman)",
"compressionModeStandardDesc": "Rule-based compression with 30+ patterns, preserves code blocks and URLs",
"compressionGeneral": "General Settings",
"compressionAutoTrigger": "Auto-Trigger Threshold",
"compressionCacheTTL": "Cache TTL",
"compressionPreserveSystem": "Preserve System Prompt",
"compressionCavemanConfig": "Caveman Engine Configuration",
"compressionCavemanConfigDesc": "Fine-tune the rule-based compression engine",
"compressionRoles": "Compress Message Roles",
"compressionRoleUser": "User",
"compressionRoleAssistant": "Assistant",
"compressionRoleSystem": "System",
"compressionMinLength": "Minimum Message Length",
"compressionSkipRules": "Skip Compression Rules",
"compressionSkipRulesDesc": "Click rules to skip them during compression",
"compressionPreservePatterns": "Preserve Patterns",
"compressionPreservePatternsDesc": "Regex patterns that are never compressed (one per line)",
"compressionLogTitle": "Compression Log",
"compressionLogEmpty": "No compressed requests yet. Compression stats will appear here when requests are processed with compression enabled."
},
"translator": {
"title": "مترجم",

View File

@@ -3249,7 +3249,33 @@
"pricingResetProvider": "Pricing Reset Provider",
"nextSync": "Next Sync",
"pricingSyncFailedWithReason": "Pricing Sync Failed With Reason",
"clearSyncedPricing": "Clear Synced Pricing"
"clearSyncedPricing": "Clear Synced Pricing",
"compressionTitle": "Prompt Compression",
"compressionDesc": "Reduce token usage by compressing prompts before sending to providers",
"compressionMode": "Compression Mode",
"compressionModeOff": "Off",
"compressionModeOffDesc": "No compression applied",
"compressionModeLite": "Lite",
"compressionModeLiteDesc": "Whitespace and blank line reduction",
"compressionModeStandard": "Standard (Caveman)",
"compressionModeStandardDesc": "Rule-based compression with 30+ patterns, preserves code blocks and URLs",
"compressionGeneral": "General Settings",
"compressionAutoTrigger": "Auto-Trigger Threshold",
"compressionCacheTTL": "Cache TTL",
"compressionPreserveSystem": "Preserve System Prompt",
"compressionCavemanConfig": "Caveman Engine Configuration",
"compressionCavemanConfigDesc": "Fine-tune the rule-based compression engine",
"compressionRoles": "Compress Message Roles",
"compressionRoleUser": "User",
"compressionRoleAssistant": "Assistant",
"compressionRoleSystem": "System",
"compressionMinLength": "Minimum Message Length",
"compressionSkipRules": "Skip Compression Rules",
"compressionSkipRulesDesc": "Click rules to skip them during compression",
"compressionPreservePatterns": "Preserve Patterns",
"compressionPreservePatternsDesc": "Regex patterns that are never compressed (one per line)",
"compressionLogTitle": "Compression Log",
"compressionLogEmpty": "No compressed requests yet. Compression stats will appear here when requests are processed with compression enabled."
},
"translator": {
"title": "Преводач",

View File

@@ -3410,7 +3410,33 @@
"pricingResetProvider": "Pricing reset for {provider}",
"nextSync": "Next Sync",
"pricingSyncFailedWithReason": "Pricing sync failed: {reason}",
"clearSyncedPricing": "Clear Synced Pricing"
"clearSyncedPricing": "Clear Synced Pricing",
"compressionTitle": "Prompt Compression",
"compressionDesc": "Reduce token usage by compressing prompts before sending to providers",
"compressionMode": "Compression Mode",
"compressionModeOff": "Off",
"compressionModeOffDesc": "No compression applied",
"compressionModeLite": "Lite",
"compressionModeLiteDesc": "Whitespace and blank line reduction",
"compressionModeStandard": "Standard (Caveman)",
"compressionModeStandardDesc": "Rule-based compression with 30+ patterns, preserves code blocks and URLs",
"compressionGeneral": "General Settings",
"compressionAutoTrigger": "Auto-Trigger Threshold",
"compressionCacheTTL": "Cache TTL",
"compressionPreserveSystem": "Preserve System Prompt",
"compressionCavemanConfig": "Caveman Engine Configuration",
"compressionCavemanConfigDesc": "Fine-tune the rule-based compression engine",
"compressionRoles": "Compress Message Roles",
"compressionRoleUser": "User",
"compressionRoleAssistant": "Assistant",
"compressionRoleSystem": "System",
"compressionMinLength": "Minimum Message Length",
"compressionSkipRules": "Skip Compression Rules",
"compressionSkipRulesDesc": "Click rules to skip them during compression",
"compressionPreservePatterns": "Preserve Patterns",
"compressionPreservePatternsDesc": "Regex patterns that are never compressed (one per line)",
"compressionLogTitle": "Compression Log",
"compressionLogEmpty": "No compressed requests yet. Compression stats will appear here when requests are processed with compression enabled."
},
"translator": {
"title": "Translator",

View File

@@ -3249,7 +3249,33 @@
"pricingResetProvider": "Pricing Reset Provider",
"nextSync": "Next Sync",
"pricingSyncFailedWithReason": "Pricing Sync Failed With Reason",
"clearSyncedPricing": "Clear Synced Pricing"
"clearSyncedPricing": "Clear Synced Pricing",
"compressionTitle": "Prompt Compression",
"compressionDesc": "Reduce token usage by compressing prompts before sending to providers",
"compressionMode": "Compression Mode",
"compressionModeOff": "Off",
"compressionModeOffDesc": "No compression applied",
"compressionModeLite": "Lite",
"compressionModeLiteDesc": "Whitespace and blank line reduction",
"compressionModeStandard": "Standard (Caveman)",
"compressionModeStandardDesc": "Rule-based compression with 30+ patterns, preserves code blocks and URLs",
"compressionGeneral": "General Settings",
"compressionAutoTrigger": "Auto-Trigger Threshold",
"compressionCacheTTL": "Cache TTL",
"compressionPreserveSystem": "Preserve System Prompt",
"compressionCavemanConfig": "Caveman Engine Configuration",
"compressionCavemanConfigDesc": "Fine-tune the rule-based compression engine",
"compressionRoles": "Compress Message Roles",
"compressionRoleUser": "User",
"compressionRoleAssistant": "Assistant",
"compressionRoleSystem": "System",
"compressionMinLength": "Minimum Message Length",
"compressionSkipRules": "Skip Compression Rules",
"compressionSkipRulesDesc": "Click rules to skip them during compression",
"compressionPreservePatterns": "Preserve Patterns",
"compressionPreservePatternsDesc": "Regex patterns that are never compressed (one per line)",
"compressionLogTitle": "Compression Log",
"compressionLogEmpty": "No compressed requests yet. Compression stats will appear here when requests are processed with compression enabled."
},
"translator": {
"title": "Překladatel",

View File

@@ -3249,7 +3249,33 @@
"pricingResetProvider": "Pricing Reset Provider",
"nextSync": "Next Sync",
"pricingSyncFailedWithReason": "Pricing Sync Failed With Reason",
"clearSyncedPricing": "Clear Synced Pricing"
"clearSyncedPricing": "Clear Synced Pricing",
"compressionTitle": "Prompt Compression",
"compressionDesc": "Reduce token usage by compressing prompts before sending to providers",
"compressionMode": "Compression Mode",
"compressionModeOff": "Off",
"compressionModeOffDesc": "No compression applied",
"compressionModeLite": "Lite",
"compressionModeLiteDesc": "Whitespace and blank line reduction",
"compressionModeStandard": "Standard (Caveman)",
"compressionModeStandardDesc": "Rule-based compression with 30+ patterns, preserves code blocks and URLs",
"compressionGeneral": "General Settings",
"compressionAutoTrigger": "Auto-Trigger Threshold",
"compressionCacheTTL": "Cache TTL",
"compressionPreserveSystem": "Preserve System Prompt",
"compressionCavemanConfig": "Caveman Engine Configuration",
"compressionCavemanConfigDesc": "Fine-tune the rule-based compression engine",
"compressionRoles": "Compress Message Roles",
"compressionRoleUser": "User",
"compressionRoleAssistant": "Assistant",
"compressionRoleSystem": "System",
"compressionMinLength": "Minimum Message Length",
"compressionSkipRules": "Skip Compression Rules",
"compressionSkipRulesDesc": "Click rules to skip them during compression",
"compressionPreservePatterns": "Preserve Patterns",
"compressionPreservePatternsDesc": "Regex patterns that are never compressed (one per line)",
"compressionLogTitle": "Compression Log",
"compressionLogEmpty": "No compressed requests yet. Compression stats will appear here when requests are processed with compression enabled."
},
"translator": {
"title": "Oversætter",

View File

@@ -3249,7 +3249,33 @@
"pricingResetProvider": "Pricing Reset Provider",
"nextSync": "Next Sync",
"pricingSyncFailedWithReason": "Pricing Sync Failed With Reason",
"clearSyncedPricing": "Clear Synced Pricing"
"clearSyncedPricing": "Clear Synced Pricing",
"compressionTitle": "Prompt Compression",
"compressionDesc": "Reduce token usage by compressing prompts before sending to providers",
"compressionMode": "Compression Mode",
"compressionModeOff": "Off",
"compressionModeOffDesc": "No compression applied",
"compressionModeLite": "Lite",
"compressionModeLiteDesc": "Whitespace and blank line reduction",
"compressionModeStandard": "Standard (Caveman)",
"compressionModeStandardDesc": "Rule-based compression with 30+ patterns, preserves code blocks and URLs",
"compressionGeneral": "General Settings",
"compressionAutoTrigger": "Auto-Trigger Threshold",
"compressionCacheTTL": "Cache TTL",
"compressionPreserveSystem": "Preserve System Prompt",
"compressionCavemanConfig": "Caveman Engine Configuration",
"compressionCavemanConfigDesc": "Fine-tune the rule-based compression engine",
"compressionRoles": "Compress Message Roles",
"compressionRoleUser": "User",
"compressionRoleAssistant": "Assistant",
"compressionRoleSystem": "System",
"compressionMinLength": "Minimum Message Length",
"compressionSkipRules": "Skip Compression Rules",
"compressionSkipRulesDesc": "Click rules to skip them during compression",
"compressionPreservePatterns": "Preserve Patterns",
"compressionPreservePatternsDesc": "Regex patterns that are never compressed (one per line)",
"compressionLogTitle": "Compression Log",
"compressionLogEmpty": "No compressed requests yet. Compression stats will appear here when requests are processed with compression enabled."
},
"translator": {
"title": "Übersetzer",

View File

@@ -3648,7 +3648,34 @@
"pricingResetProvider": "Pricing reset for {provider}",
"nextSync": "Next Sync",
"pricingSyncFailedWithReason": "Pricing sync failed: {reason}",
"clearSyncedPricing": "Clear Synced Pricing"
"clearSyncedPricing": "Clear Synced Pricing",
"compressionTitle": "Prompt Compression",
"compressionDesc": "Reduce token usage by compressing prompts before sending to providers",
"compressionMode": "Compression Mode",
"compressionModeOff": "Off",
"compressionModeOffDesc": "No compression applied",
"compressionModeLite": "Lite",
"compressionModeLiteDesc": "Whitespace and blank line reduction",
"compressionModeStandard": "Standard (Caveman)",
"compressionModeStandardDesc": "Rule-based compression with 30+ patterns, preserves code blocks and URLs",
"compressionGeneral": "General Settings",
"compressionAutoTrigger": "Auto-Trigger Threshold",
"compressionCacheTTL": "Cache TTL",
"compressionPreserveSystem": "Preserve System Prompt",
"compressionCavemanConfig": "Caveman Engine Configuration",
"compressionCavemanConfigDesc": "Fine-tune the rule-based compression engine",
"compressionRoles": "Compress Message Roles",
"compressionRoleUser": "User",
"compressionRoleAssistant": "Assistant",
"compressionRoleSystem": "System",
"compressionMinLength": "Minimum Message Length",
"compressionSkipRules": "Skip Compression Rules",
"compressionSkipRulesDesc": "Click rules to skip them during compression",
"compressionPreservePatterns": "Preserve Patterns",
"compressionPreservePatternsDesc": "Regex patterns that are never compressed (one per line)",
"compressionLogTitle": "Compression Log",
"compressionLogEmpty": "No compressed requests yet. Compression stats will appear here when requests are processed with compression enabled.",
"minutes": "minutes"
},
"translator": {
"title": "Translator",
@@ -3682,8 +3709,8 @@
"liveAutoRefreshing": "Live — Auto-refreshing",
"paused": "Paused",
"eventsAppearHint": "Translation events appear here as requests flow through OmniRoute. Use any of these methods to generate events:",
"chatTesterTab": "Chat Tester",
"testBenchTab": "Test Bench",
"chatTesterTab": "Chat Tester tab",
"testBenchTab": "Test Bench tab",
"externalApiCalls": "External API calls",
"ideCliIntegrations": "IDE/CLI integrations",
"inMemoryNote": "Note: Events are stored in-memory and reset when the server restarts.",
@@ -4330,7 +4357,7 @@
"oauthAutoRefresh": "OAuth connection with automatic token refresh.",
"fullStreaming": "Full streaming support for all models.",
"docsLabel": "Docs",
"docsHeroDescription": "AI gateway for multi-provider LLMs. One endpoint for OpenAI, Anthropic, Gemini, DeepSeek, GitHub Copilot, Claude Code, Cursor, and 100+ more providers.",
"docsHeroDescription": "AI gateway for multi-provider LLMs. One endpoint for OpenAI, Anthropic, Gemini, GitHub Copilot, Claude Code, Cursor, and 20+ more providers.",
"openDashboard": "Open Dashboard",
"endpointPage": "Endpoint Page",
"github": "GitHub",
@@ -4561,8 +4588,8 @@
"termsSection6Text": "OmniRoute is open-source software. You are free to inspect, modify, and distribute it under the terms of its license."
},
"agents": {
"title": "CLI Agent Targets",
"description": "Discover installed CLI tools that OmniRoute can spawn as execution backends. Requests flow INTO these binaries — the reverse direction from CLI Tools.",
"title": "CLI Agents",
"description": "Discover installed CLI agents on your system. Add custom agents for auto-detection.",
"refresh": "Refresh",
"installed": "Installed",
"notFound": "Not Found",
@@ -5048,7 +5075,7 @@
"requestedRoutedTitle": "Requested {requested}, routed as {routed}",
"statusFilters": {
"all": "All",
"error": "Errors",
"error": "Error",
"success": "Success",
"combo": "Combo"
},

View File

@@ -3249,7 +3249,33 @@
"pricingResetProvider": "Pricing Reset Provider",
"nextSync": "Next Sync",
"pricingSyncFailedWithReason": "Pricing Sync Failed With Reason",
"clearSyncedPricing": "Clear Synced Pricing"
"clearSyncedPricing": "Clear Synced Pricing",
"compressionTitle": "Prompt Compression",
"compressionDesc": "Reduce token usage by compressing prompts before sending to providers",
"compressionMode": "Compression Mode",
"compressionModeOff": "Off",
"compressionModeOffDesc": "No compression applied",
"compressionModeLite": "Lite",
"compressionModeLiteDesc": "Whitespace and blank line reduction",
"compressionModeStandard": "Standard (Caveman)",
"compressionModeStandardDesc": "Rule-based compression with 30+ patterns, preserves code blocks and URLs",
"compressionGeneral": "General Settings",
"compressionAutoTrigger": "Auto-Trigger Threshold",
"compressionCacheTTL": "Cache TTL",
"compressionPreserveSystem": "Preserve System Prompt",
"compressionCavemanConfig": "Caveman Engine Configuration",
"compressionCavemanConfigDesc": "Fine-tune the rule-based compression engine",
"compressionRoles": "Compress Message Roles",
"compressionRoleUser": "User",
"compressionRoleAssistant": "Assistant",
"compressionRoleSystem": "System",
"compressionMinLength": "Minimum Message Length",
"compressionSkipRules": "Skip Compression Rules",
"compressionSkipRulesDesc": "Click rules to skip them during compression",
"compressionPreservePatterns": "Preserve Patterns",
"compressionPreservePatternsDesc": "Regex patterns that are never compressed (one per line)",
"compressionLogTitle": "Compression Log",
"compressionLogEmpty": "No compressed requests yet. Compression stats will appear here when requests are processed with compression enabled."
},
"translator": {
"title": "Traductor",

View File

@@ -3410,7 +3410,33 @@
"pricingResetProvider": "Pricing reset for {provider}",
"nextSync": "Next Sync",
"pricingSyncFailedWithReason": "Pricing sync failed: {reason}",
"clearSyncedPricing": "Clear Synced Pricing"
"clearSyncedPricing": "Clear Synced Pricing",
"compressionTitle": "Prompt Compression",
"compressionDesc": "Reduce token usage by compressing prompts before sending to providers",
"compressionMode": "Compression Mode",
"compressionModeOff": "Off",
"compressionModeOffDesc": "No compression applied",
"compressionModeLite": "Lite",
"compressionModeLiteDesc": "Whitespace and blank line reduction",
"compressionModeStandard": "Standard (Caveman)",
"compressionModeStandardDesc": "Rule-based compression with 30+ patterns, preserves code blocks and URLs",
"compressionGeneral": "General Settings",
"compressionAutoTrigger": "Auto-Trigger Threshold",
"compressionCacheTTL": "Cache TTL",
"compressionPreserveSystem": "Preserve System Prompt",
"compressionCavemanConfig": "Caveman Engine Configuration",
"compressionCavemanConfigDesc": "Fine-tune the rule-based compression engine",
"compressionRoles": "Compress Message Roles",
"compressionRoleUser": "User",
"compressionRoleAssistant": "Assistant",
"compressionRoleSystem": "System",
"compressionMinLength": "Minimum Message Length",
"compressionSkipRules": "Skip Compression Rules",
"compressionSkipRulesDesc": "Click rules to skip them during compression",
"compressionPreservePatterns": "Preserve Patterns",
"compressionPreservePatternsDesc": "Regex patterns that are never compressed (one per line)",
"compressionLogTitle": "Compression Log",
"compressionLogEmpty": "No compressed requests yet. Compression stats will appear here when requests are processed with compression enabled."
},
"translator": {
"title": "Translator",

View File

@@ -3249,7 +3249,33 @@
"pricingResetProvider": "Pricing Reset Provider",
"nextSync": "Next Sync",
"pricingSyncFailedWithReason": "Pricing Sync Failed With Reason",
"clearSyncedPricing": "Clear Synced Pricing"
"clearSyncedPricing": "Clear Synced Pricing",
"compressionTitle": "Prompt Compression",
"compressionDesc": "Reduce token usage by compressing prompts before sending to providers",
"compressionMode": "Compression Mode",
"compressionModeOff": "Off",
"compressionModeOffDesc": "No compression applied",
"compressionModeLite": "Lite",
"compressionModeLiteDesc": "Whitespace and blank line reduction",
"compressionModeStandard": "Standard (Caveman)",
"compressionModeStandardDesc": "Rule-based compression with 30+ patterns, preserves code blocks and URLs",
"compressionGeneral": "General Settings",
"compressionAutoTrigger": "Auto-Trigger Threshold",
"compressionCacheTTL": "Cache TTL",
"compressionPreserveSystem": "Preserve System Prompt",
"compressionCavemanConfig": "Caveman Engine Configuration",
"compressionCavemanConfigDesc": "Fine-tune the rule-based compression engine",
"compressionRoles": "Compress Message Roles",
"compressionRoleUser": "User",
"compressionRoleAssistant": "Assistant",
"compressionRoleSystem": "System",
"compressionMinLength": "Minimum Message Length",
"compressionSkipRules": "Skip Compression Rules",
"compressionSkipRulesDesc": "Click rules to skip them during compression",
"compressionPreservePatterns": "Preserve Patterns",
"compressionPreservePatternsDesc": "Regex patterns that are never compressed (one per line)",
"compressionLogTitle": "Compression Log",
"compressionLogEmpty": "No compressed requests yet. Compression stats will appear here when requests are processed with compression enabled."
},
"translator": {
"title": "Kääntäjä",

View File

@@ -3249,7 +3249,33 @@
"pricingResetProvider": "Pricing Reset Provider",
"nextSync": "Next Sync",
"pricingSyncFailedWithReason": "Pricing Sync Failed With Reason",
"clearSyncedPricing": "Clear Synced Pricing"
"clearSyncedPricing": "Clear Synced Pricing",
"compressionTitle": "Prompt Compression",
"compressionDesc": "Reduce token usage by compressing prompts before sending to providers",
"compressionMode": "Compression Mode",
"compressionModeOff": "Off",
"compressionModeOffDesc": "No compression applied",
"compressionModeLite": "Lite",
"compressionModeLiteDesc": "Whitespace and blank line reduction",
"compressionModeStandard": "Standard (Caveman)",
"compressionModeStandardDesc": "Rule-based compression with 30+ patterns, preserves code blocks and URLs",
"compressionGeneral": "General Settings",
"compressionAutoTrigger": "Auto-Trigger Threshold",
"compressionCacheTTL": "Cache TTL",
"compressionPreserveSystem": "Preserve System Prompt",
"compressionCavemanConfig": "Caveman Engine Configuration",
"compressionCavemanConfigDesc": "Fine-tune the rule-based compression engine",
"compressionRoles": "Compress Message Roles",
"compressionRoleUser": "User",
"compressionRoleAssistant": "Assistant",
"compressionRoleSystem": "System",
"compressionMinLength": "Minimum Message Length",
"compressionSkipRules": "Skip Compression Rules",
"compressionSkipRulesDesc": "Click rules to skip them during compression",
"compressionPreservePatterns": "Preserve Patterns",
"compressionPreservePatternsDesc": "Regex patterns that are never compressed (one per line)",
"compressionLogTitle": "Compression Log",
"compressionLogEmpty": "No compressed requests yet. Compression stats will appear here when requests are processed with compression enabled."
},
"translator": {
"title": "Traducteur",

View File

@@ -3410,7 +3410,33 @@
"pricingResetProvider": "Pricing reset for {provider}",
"nextSync": "Next Sync",
"pricingSyncFailedWithReason": "Pricing sync failed: {reason}",
"clearSyncedPricing": "Clear Synced Pricing"
"clearSyncedPricing": "Clear Synced Pricing",
"compressionTitle": "Prompt Compression",
"compressionDesc": "Reduce token usage by compressing prompts before sending to providers",
"compressionMode": "Compression Mode",
"compressionModeOff": "Off",
"compressionModeOffDesc": "No compression applied",
"compressionModeLite": "Lite",
"compressionModeLiteDesc": "Whitespace and blank line reduction",
"compressionModeStandard": "Standard (Caveman)",
"compressionModeStandardDesc": "Rule-based compression with 30+ patterns, preserves code blocks and URLs",
"compressionGeneral": "General Settings",
"compressionAutoTrigger": "Auto-Trigger Threshold",
"compressionCacheTTL": "Cache TTL",
"compressionPreserveSystem": "Preserve System Prompt",
"compressionCavemanConfig": "Caveman Engine Configuration",
"compressionCavemanConfigDesc": "Fine-tune the rule-based compression engine",
"compressionRoles": "Compress Message Roles",
"compressionRoleUser": "User",
"compressionRoleAssistant": "Assistant",
"compressionRoleSystem": "System",
"compressionMinLength": "Minimum Message Length",
"compressionSkipRules": "Skip Compression Rules",
"compressionSkipRulesDesc": "Click rules to skip them during compression",
"compressionPreservePatterns": "Preserve Patterns",
"compressionPreservePatternsDesc": "Regex patterns that are never compressed (one per line)",
"compressionLogTitle": "Compression Log",
"compressionLogEmpty": "No compressed requests yet. Compression stats will appear here when requests are processed with compression enabled."
},
"translator": {
"title": "Translator",

View File

@@ -3249,7 +3249,33 @@
"pricingResetProvider": "Pricing Reset Provider",
"nextSync": "Next Sync",
"pricingSyncFailedWithReason": "Pricing Sync Failed With Reason",
"clearSyncedPricing": "Clear Synced Pricing"
"clearSyncedPricing": "Clear Synced Pricing",
"compressionTitle": "Prompt Compression",
"compressionDesc": "Reduce token usage by compressing prompts before sending to providers",
"compressionMode": "Compression Mode",
"compressionModeOff": "Off",
"compressionModeOffDesc": "No compression applied",
"compressionModeLite": "Lite",
"compressionModeLiteDesc": "Whitespace and blank line reduction",
"compressionModeStandard": "Standard (Caveman)",
"compressionModeStandardDesc": "Rule-based compression with 30+ patterns, preserves code blocks and URLs",
"compressionGeneral": "General Settings",
"compressionAutoTrigger": "Auto-Trigger Threshold",
"compressionCacheTTL": "Cache TTL",
"compressionPreserveSystem": "Preserve System Prompt",
"compressionCavemanConfig": "Caveman Engine Configuration",
"compressionCavemanConfigDesc": "Fine-tune the rule-based compression engine",
"compressionRoles": "Compress Message Roles",
"compressionRoleUser": "User",
"compressionRoleAssistant": "Assistant",
"compressionRoleSystem": "System",
"compressionMinLength": "Minimum Message Length",
"compressionSkipRules": "Skip Compression Rules",
"compressionSkipRulesDesc": "Click rules to skip them during compression",
"compressionPreservePatterns": "Preserve Patterns",
"compressionPreservePatternsDesc": "Regex patterns that are never compressed (one per line)",
"compressionLogTitle": "Compression Log",
"compressionLogEmpty": "No compressed requests yet. Compression stats will appear here when requests are processed with compression enabled."
},
"translator": {
"title": "מתרגם",

View File

@@ -3249,7 +3249,33 @@
"pricingResetProvider": "Pricing Reset Provider",
"nextSync": "Next Sync",
"pricingSyncFailedWithReason": "Pricing Sync Failed With Reason",
"clearSyncedPricing": "Clear Synced Pricing"
"clearSyncedPricing": "Clear Synced Pricing",
"compressionTitle": "Prompt Compression",
"compressionDesc": "Reduce token usage by compressing prompts before sending to providers",
"compressionMode": "Compression Mode",
"compressionModeOff": "Off",
"compressionModeOffDesc": "No compression applied",
"compressionModeLite": "Lite",
"compressionModeLiteDesc": "Whitespace and blank line reduction",
"compressionModeStandard": "Standard (Caveman)",
"compressionModeStandardDesc": "Rule-based compression with 30+ patterns, preserves code blocks and URLs",
"compressionGeneral": "General Settings",
"compressionAutoTrigger": "Auto-Trigger Threshold",
"compressionCacheTTL": "Cache TTL",
"compressionPreserveSystem": "Preserve System Prompt",
"compressionCavemanConfig": "Caveman Engine Configuration",
"compressionCavemanConfigDesc": "Fine-tune the rule-based compression engine",
"compressionRoles": "Compress Message Roles",
"compressionRoleUser": "User",
"compressionRoleAssistant": "Assistant",
"compressionRoleSystem": "System",
"compressionMinLength": "Minimum Message Length",
"compressionSkipRules": "Skip Compression Rules",
"compressionSkipRulesDesc": "Click rules to skip them during compression",
"compressionPreservePatterns": "Preserve Patterns",
"compressionPreservePatternsDesc": "Regex patterns that are never compressed (one per line)",
"compressionLogTitle": "Compression Log",
"compressionLogEmpty": "No compressed requests yet. Compression stats will appear here when requests are processed with compression enabled."
},
"translator": {
"title": "अनुवादक",

View File

@@ -3249,7 +3249,33 @@
"pricingResetProvider": "Pricing Reset Provider",
"nextSync": "Next Sync",
"pricingSyncFailedWithReason": "Pricing Sync Failed With Reason",
"clearSyncedPricing": "Clear Synced Pricing"
"clearSyncedPricing": "Clear Synced Pricing",
"compressionTitle": "Prompt Compression",
"compressionDesc": "Reduce token usage by compressing prompts before sending to providers",
"compressionMode": "Compression Mode",
"compressionModeOff": "Off",
"compressionModeOffDesc": "No compression applied",
"compressionModeLite": "Lite",
"compressionModeLiteDesc": "Whitespace and blank line reduction",
"compressionModeStandard": "Standard (Caveman)",
"compressionModeStandardDesc": "Rule-based compression with 30+ patterns, preserves code blocks and URLs",
"compressionGeneral": "General Settings",
"compressionAutoTrigger": "Auto-Trigger Threshold",
"compressionCacheTTL": "Cache TTL",
"compressionPreserveSystem": "Preserve System Prompt",
"compressionCavemanConfig": "Caveman Engine Configuration",
"compressionCavemanConfigDesc": "Fine-tune the rule-based compression engine",
"compressionRoles": "Compress Message Roles",
"compressionRoleUser": "User",
"compressionRoleAssistant": "Assistant",
"compressionRoleSystem": "System",
"compressionMinLength": "Minimum Message Length",
"compressionSkipRules": "Skip Compression Rules",
"compressionSkipRulesDesc": "Click rules to skip them during compression",
"compressionPreservePatterns": "Preserve Patterns",
"compressionPreservePatternsDesc": "Regex patterns that are never compressed (one per line)",
"compressionLogTitle": "Compression Log",
"compressionLogEmpty": "No compressed requests yet. Compression stats will appear here when requests are processed with compression enabled."
},
"translator": {
"title": "Fordító",

View File

@@ -3249,7 +3249,33 @@
"pricingResetProvider": "Pricing Reset Provider",
"nextSync": "Next Sync",
"pricingSyncFailedWithReason": "Pricing Sync Failed With Reason",
"clearSyncedPricing": "Clear Synced Pricing"
"clearSyncedPricing": "Clear Synced Pricing",
"compressionTitle": "Prompt Compression",
"compressionDesc": "Reduce token usage by compressing prompts before sending to providers",
"compressionMode": "Compression Mode",
"compressionModeOff": "Off",
"compressionModeOffDesc": "No compression applied",
"compressionModeLite": "Lite",
"compressionModeLiteDesc": "Whitespace and blank line reduction",
"compressionModeStandard": "Standard (Caveman)",
"compressionModeStandardDesc": "Rule-based compression with 30+ patterns, preserves code blocks and URLs",
"compressionGeneral": "General Settings",
"compressionAutoTrigger": "Auto-Trigger Threshold",
"compressionCacheTTL": "Cache TTL",
"compressionPreserveSystem": "Preserve System Prompt",
"compressionCavemanConfig": "Caveman Engine Configuration",
"compressionCavemanConfigDesc": "Fine-tune the rule-based compression engine",
"compressionRoles": "Compress Message Roles",
"compressionRoleUser": "User",
"compressionRoleAssistant": "Assistant",
"compressionRoleSystem": "System",
"compressionMinLength": "Minimum Message Length",
"compressionSkipRules": "Skip Compression Rules",
"compressionSkipRulesDesc": "Click rules to skip them during compression",
"compressionPreservePatterns": "Preserve Patterns",
"compressionPreservePatternsDesc": "Regex patterns that are never compressed (one per line)",
"compressionLogTitle": "Compression Log",
"compressionLogEmpty": "No compressed requests yet. Compression stats will appear here when requests are processed with compression enabled."
},
"translator": {
"title": "Penerjemah",

View File

@@ -3410,7 +3410,33 @@
"pricingResetProvider": "Pricing reset for {provider}",
"nextSync": "Next Sync",
"pricingSyncFailedWithReason": "Pricing sync failed: {reason}",
"clearSyncedPricing": "Clear Synced Pricing"
"clearSyncedPricing": "Clear Synced Pricing",
"compressionTitle": "Prompt Compression",
"compressionDesc": "Reduce token usage by compressing prompts before sending to providers",
"compressionMode": "Compression Mode",
"compressionModeOff": "Off",
"compressionModeOffDesc": "No compression applied",
"compressionModeLite": "Lite",
"compressionModeLiteDesc": "Whitespace and blank line reduction",
"compressionModeStandard": "Standard (Caveman)",
"compressionModeStandardDesc": "Rule-based compression with 30+ patterns, preserves code blocks and URLs",
"compressionGeneral": "General Settings",
"compressionAutoTrigger": "Auto-Trigger Threshold",
"compressionCacheTTL": "Cache TTL",
"compressionPreserveSystem": "Preserve System Prompt",
"compressionCavemanConfig": "Caveman Engine Configuration",
"compressionCavemanConfigDesc": "Fine-tune the rule-based compression engine",
"compressionRoles": "Compress Message Roles",
"compressionRoleUser": "User",
"compressionRoleAssistant": "Assistant",
"compressionRoleSystem": "System",
"compressionMinLength": "Minimum Message Length",
"compressionSkipRules": "Skip Compression Rules",
"compressionSkipRulesDesc": "Click rules to skip them during compression",
"compressionPreservePatterns": "Preserve Patterns",
"compressionPreservePatternsDesc": "Regex patterns that are never compressed (one per line)",
"compressionLogTitle": "Compression Log",
"compressionLogEmpty": "No compressed requests yet. Compression stats will appear here when requests are processed with compression enabled."
},
"translator": {
"title": "Translator",

View File

@@ -3249,7 +3249,33 @@
"pricingResetProvider": "Pricing Reset Provider",
"nextSync": "Next Sync",
"pricingSyncFailedWithReason": "Pricing Sync Failed With Reason",
"clearSyncedPricing": "Clear Synced Pricing"
"clearSyncedPricing": "Clear Synced Pricing",
"compressionTitle": "Prompt Compression",
"compressionDesc": "Reduce token usage by compressing prompts before sending to providers",
"compressionMode": "Compression Mode",
"compressionModeOff": "Off",
"compressionModeOffDesc": "No compression applied",
"compressionModeLite": "Lite",
"compressionModeLiteDesc": "Whitespace and blank line reduction",
"compressionModeStandard": "Standard (Caveman)",
"compressionModeStandardDesc": "Rule-based compression with 30+ patterns, preserves code blocks and URLs",
"compressionGeneral": "General Settings",
"compressionAutoTrigger": "Auto-Trigger Threshold",
"compressionCacheTTL": "Cache TTL",
"compressionPreserveSystem": "Preserve System Prompt",
"compressionCavemanConfig": "Caveman Engine Configuration",
"compressionCavemanConfigDesc": "Fine-tune the rule-based compression engine",
"compressionRoles": "Compress Message Roles",
"compressionRoleUser": "User",
"compressionRoleAssistant": "Assistant",
"compressionRoleSystem": "System",
"compressionMinLength": "Minimum Message Length",
"compressionSkipRules": "Skip Compression Rules",
"compressionSkipRulesDesc": "Click rules to skip them during compression",
"compressionPreservePatterns": "Preserve Patterns",
"compressionPreservePatternsDesc": "Regex patterns that are never compressed (one per line)",
"compressionLogTitle": "Compression Log",
"compressionLogEmpty": "No compressed requests yet. Compression stats will appear here when requests are processed with compression enabled."
},
"translator": {
"title": "Traduttore",

View File

@@ -3249,7 +3249,33 @@
"pricingResetProvider": "Pricing Reset Provider",
"nextSync": "Next Sync",
"pricingSyncFailedWithReason": "Pricing Sync Failed With Reason",
"clearSyncedPricing": "Clear Synced Pricing"
"clearSyncedPricing": "Clear Synced Pricing",
"compressionTitle": "Prompt Compression",
"compressionDesc": "Reduce token usage by compressing prompts before sending to providers",
"compressionMode": "Compression Mode",
"compressionModeOff": "Off",
"compressionModeOffDesc": "No compression applied",
"compressionModeLite": "Lite",
"compressionModeLiteDesc": "Whitespace and blank line reduction",
"compressionModeStandard": "Standard (Caveman)",
"compressionModeStandardDesc": "Rule-based compression with 30+ patterns, preserves code blocks and URLs",
"compressionGeneral": "General Settings",
"compressionAutoTrigger": "Auto-Trigger Threshold",
"compressionCacheTTL": "Cache TTL",
"compressionPreserveSystem": "Preserve System Prompt",
"compressionCavemanConfig": "Caveman Engine Configuration",
"compressionCavemanConfigDesc": "Fine-tune the rule-based compression engine",
"compressionRoles": "Compress Message Roles",
"compressionRoleUser": "User",
"compressionRoleAssistant": "Assistant",
"compressionRoleSystem": "System",
"compressionMinLength": "Minimum Message Length",
"compressionSkipRules": "Skip Compression Rules",
"compressionSkipRulesDesc": "Click rules to skip them during compression",
"compressionPreservePatterns": "Preserve Patterns",
"compressionPreservePatternsDesc": "Regex patterns that are never compressed (one per line)",
"compressionLogTitle": "Compression Log",
"compressionLogEmpty": "No compressed requests yet. Compression stats will appear here when requests are processed with compression enabled."
},
"translator": {
"title": "翻訳者",

View File

@@ -3251,7 +3251,33 @@
"pricingResetProvider": "Pricing Reset Provider",
"nextSync": "Next Sync",
"pricingSyncFailedWithReason": "Pricing Sync Failed With Reason",
"clearSyncedPricing": "Clear Synced Pricing"
"clearSyncedPricing": "Clear Synced Pricing",
"compressionTitle": "Prompt Compression",
"compressionDesc": "Reduce token usage by compressing prompts before sending to providers",
"compressionMode": "Compression Mode",
"compressionModeOff": "Off",
"compressionModeOffDesc": "No compression applied",
"compressionModeLite": "Lite",
"compressionModeLiteDesc": "Whitespace and blank line reduction",
"compressionModeStandard": "Standard (Caveman)",
"compressionModeStandardDesc": "Rule-based compression with 30+ patterns, preserves code blocks and URLs",
"compressionGeneral": "General Settings",
"compressionAutoTrigger": "Auto-Trigger Threshold",
"compressionCacheTTL": "Cache TTL",
"compressionPreserveSystem": "Preserve System Prompt",
"compressionCavemanConfig": "Caveman Engine Configuration",
"compressionCavemanConfigDesc": "Fine-tune the rule-based compression engine",
"compressionRoles": "Compress Message Roles",
"compressionRoleUser": "User",
"compressionRoleAssistant": "Assistant",
"compressionRoleSystem": "System",
"compressionMinLength": "Minimum Message Length",
"compressionSkipRules": "Skip Compression Rules",
"compressionSkipRulesDesc": "Click rules to skip them during compression",
"compressionPreservePatterns": "Preserve Patterns",
"compressionPreservePatternsDesc": "Regex patterns that are never compressed (one per line)",
"compressionLogTitle": "Compression Log",
"compressionLogEmpty": "No compressed requests yet. Compression stats will appear here when requests are processed with compression enabled."
},
"translator": {
"title": "번역기",

View File

@@ -3410,7 +3410,33 @@
"pricingResetProvider": "Pricing reset for {provider}",
"nextSync": "Next Sync",
"pricingSyncFailedWithReason": "Pricing sync failed: {reason}",
"clearSyncedPricing": "Clear Synced Pricing"
"clearSyncedPricing": "Clear Synced Pricing",
"compressionTitle": "Prompt Compression",
"compressionDesc": "Reduce token usage by compressing prompts before sending to providers",
"compressionMode": "Compression Mode",
"compressionModeOff": "Off",
"compressionModeOffDesc": "No compression applied",
"compressionModeLite": "Lite",
"compressionModeLiteDesc": "Whitespace and blank line reduction",
"compressionModeStandard": "Standard (Caveman)",
"compressionModeStandardDesc": "Rule-based compression with 30+ patterns, preserves code blocks and URLs",
"compressionGeneral": "General Settings",
"compressionAutoTrigger": "Auto-Trigger Threshold",
"compressionCacheTTL": "Cache TTL",
"compressionPreserveSystem": "Preserve System Prompt",
"compressionCavemanConfig": "Caveman Engine Configuration",
"compressionCavemanConfigDesc": "Fine-tune the rule-based compression engine",
"compressionRoles": "Compress Message Roles",
"compressionRoleUser": "User",
"compressionRoleAssistant": "Assistant",
"compressionRoleSystem": "System",
"compressionMinLength": "Minimum Message Length",
"compressionSkipRules": "Skip Compression Rules",
"compressionSkipRulesDesc": "Click rules to skip them during compression",
"compressionPreservePatterns": "Preserve Patterns",
"compressionPreservePatternsDesc": "Regex patterns that are never compressed (one per line)",
"compressionLogTitle": "Compression Log",
"compressionLogEmpty": "No compressed requests yet. Compression stats will appear here when requests are processed with compression enabled."
},
"translator": {
"title": "Translator",

View File

@@ -3249,7 +3249,33 @@
"pricingResetProvider": "Pricing Reset Provider",
"nextSync": "Next Sync",
"pricingSyncFailedWithReason": "Pricing Sync Failed With Reason",
"clearSyncedPricing": "Clear Synced Pricing"
"clearSyncedPricing": "Clear Synced Pricing",
"compressionTitle": "Prompt Compression",
"compressionDesc": "Reduce token usage by compressing prompts before sending to providers",
"compressionMode": "Compression Mode",
"compressionModeOff": "Off",
"compressionModeOffDesc": "No compression applied",
"compressionModeLite": "Lite",
"compressionModeLiteDesc": "Whitespace and blank line reduction",
"compressionModeStandard": "Standard (Caveman)",
"compressionModeStandardDesc": "Rule-based compression with 30+ patterns, preserves code blocks and URLs",
"compressionGeneral": "General Settings",
"compressionAutoTrigger": "Auto-Trigger Threshold",
"compressionCacheTTL": "Cache TTL",
"compressionPreserveSystem": "Preserve System Prompt",
"compressionCavemanConfig": "Caveman Engine Configuration",
"compressionCavemanConfigDesc": "Fine-tune the rule-based compression engine",
"compressionRoles": "Compress Message Roles",
"compressionRoleUser": "User",
"compressionRoleAssistant": "Assistant",
"compressionRoleSystem": "System",
"compressionMinLength": "Minimum Message Length",
"compressionSkipRules": "Skip Compression Rules",
"compressionSkipRulesDesc": "Click rules to skip them during compression",
"compressionPreservePatterns": "Preserve Patterns",
"compressionPreservePatternsDesc": "Regex patterns that are never compressed (one per line)",
"compressionLogTitle": "Compression Log",
"compressionLogEmpty": "No compressed requests yet. Compression stats will appear here when requests are processed with compression enabled."
},
"translator": {
"title": "Penterjemah",

View File

@@ -3249,7 +3249,33 @@
"pricingResetProvider": "Pricing Reset Provider",
"nextSync": "Next Sync",
"pricingSyncFailedWithReason": "Pricing Sync Failed With Reason",
"clearSyncedPricing": "Clear Synced Pricing"
"clearSyncedPricing": "Clear Synced Pricing",
"compressionTitle": "Prompt Compression",
"compressionDesc": "Reduce token usage by compressing prompts before sending to providers",
"compressionMode": "Compression Mode",
"compressionModeOff": "Off",
"compressionModeOffDesc": "No compression applied",
"compressionModeLite": "Lite",
"compressionModeLiteDesc": "Whitespace and blank line reduction",
"compressionModeStandard": "Standard (Caveman)",
"compressionModeStandardDesc": "Rule-based compression with 30+ patterns, preserves code blocks and URLs",
"compressionGeneral": "General Settings",
"compressionAutoTrigger": "Auto-Trigger Threshold",
"compressionCacheTTL": "Cache TTL",
"compressionPreserveSystem": "Preserve System Prompt",
"compressionCavemanConfig": "Caveman Engine Configuration",
"compressionCavemanConfigDesc": "Fine-tune the rule-based compression engine",
"compressionRoles": "Compress Message Roles",
"compressionRoleUser": "User",
"compressionRoleAssistant": "Assistant",
"compressionRoleSystem": "System",
"compressionMinLength": "Minimum Message Length",
"compressionSkipRules": "Skip Compression Rules",
"compressionSkipRulesDesc": "Click rules to skip them during compression",
"compressionPreservePatterns": "Preserve Patterns",
"compressionPreservePatternsDesc": "Regex patterns that are never compressed (one per line)",
"compressionLogTitle": "Compression Log",
"compressionLogEmpty": "No compressed requests yet. Compression stats will appear here when requests are processed with compression enabled."
},
"translator": {
"title": "Vertaler",

View File

@@ -3249,7 +3249,33 @@
"pricingResetProvider": "Pricing Reset Provider",
"nextSync": "Next Sync",
"pricingSyncFailedWithReason": "Pricing Sync Failed With Reason",
"clearSyncedPricing": "Clear Synced Pricing"
"clearSyncedPricing": "Clear Synced Pricing",
"compressionTitle": "Prompt Compression",
"compressionDesc": "Reduce token usage by compressing prompts before sending to providers",
"compressionMode": "Compression Mode",
"compressionModeOff": "Off",
"compressionModeOffDesc": "No compression applied",
"compressionModeLite": "Lite",
"compressionModeLiteDesc": "Whitespace and blank line reduction",
"compressionModeStandard": "Standard (Caveman)",
"compressionModeStandardDesc": "Rule-based compression with 30+ patterns, preserves code blocks and URLs",
"compressionGeneral": "General Settings",
"compressionAutoTrigger": "Auto-Trigger Threshold",
"compressionCacheTTL": "Cache TTL",
"compressionPreserveSystem": "Preserve System Prompt",
"compressionCavemanConfig": "Caveman Engine Configuration",
"compressionCavemanConfigDesc": "Fine-tune the rule-based compression engine",
"compressionRoles": "Compress Message Roles",
"compressionRoleUser": "User",
"compressionRoleAssistant": "Assistant",
"compressionRoleSystem": "System",
"compressionMinLength": "Minimum Message Length",
"compressionSkipRules": "Skip Compression Rules",
"compressionSkipRulesDesc": "Click rules to skip them during compression",
"compressionPreservePatterns": "Preserve Patterns",
"compressionPreservePatternsDesc": "Regex patterns that are never compressed (one per line)",
"compressionLogTitle": "Compression Log",
"compressionLogEmpty": "No compressed requests yet. Compression stats will appear here when requests are processed with compression enabled."
},
"translator": {
"title": "Oversetter",

View File

@@ -3249,7 +3249,33 @@
"pricingResetProvider": "Pricing Reset Provider",
"nextSync": "Next Sync",
"pricingSyncFailedWithReason": "Pricing Sync Failed With Reason",
"clearSyncedPricing": "Clear Synced Pricing"
"clearSyncedPricing": "Clear Synced Pricing",
"compressionTitle": "Prompt Compression",
"compressionDesc": "Reduce token usage by compressing prompts before sending to providers",
"compressionMode": "Compression Mode",
"compressionModeOff": "Off",
"compressionModeOffDesc": "No compression applied",
"compressionModeLite": "Lite",
"compressionModeLiteDesc": "Whitespace and blank line reduction",
"compressionModeStandard": "Standard (Caveman)",
"compressionModeStandardDesc": "Rule-based compression with 30+ patterns, preserves code blocks and URLs",
"compressionGeneral": "General Settings",
"compressionAutoTrigger": "Auto-Trigger Threshold",
"compressionCacheTTL": "Cache TTL",
"compressionPreserveSystem": "Preserve System Prompt",
"compressionCavemanConfig": "Caveman Engine Configuration",
"compressionCavemanConfigDesc": "Fine-tune the rule-based compression engine",
"compressionRoles": "Compress Message Roles",
"compressionRoleUser": "User",
"compressionRoleAssistant": "Assistant",
"compressionRoleSystem": "System",
"compressionMinLength": "Minimum Message Length",
"compressionSkipRules": "Skip Compression Rules",
"compressionSkipRulesDesc": "Click rules to skip them during compression",
"compressionPreservePatterns": "Preserve Patterns",
"compressionPreservePatternsDesc": "Regex patterns that are never compressed (one per line)",
"compressionLogTitle": "Compression Log",
"compressionLogEmpty": "No compressed requests yet. Compression stats will appear here when requests are processed with compression enabled."
},
"translator": {
"title": "Tagasalin",

View File

@@ -3249,7 +3249,33 @@
"pricingResetProvider": "Pricing Reset Provider",
"nextSync": "Next Sync",
"pricingSyncFailedWithReason": "Pricing Sync Failed With Reason",
"clearSyncedPricing": "Clear Synced Pricing"
"clearSyncedPricing": "Clear Synced Pricing",
"compressionTitle": "Prompt Compression",
"compressionDesc": "Reduce token usage by compressing prompts before sending to providers",
"compressionMode": "Compression Mode",
"compressionModeOff": "Off",
"compressionModeOffDesc": "No compression applied",
"compressionModeLite": "Lite",
"compressionModeLiteDesc": "Whitespace and blank line reduction",
"compressionModeStandard": "Standard (Caveman)",
"compressionModeStandardDesc": "Rule-based compression with 30+ patterns, preserves code blocks and URLs",
"compressionGeneral": "General Settings",
"compressionAutoTrigger": "Auto-Trigger Threshold",
"compressionCacheTTL": "Cache TTL",
"compressionPreserveSystem": "Preserve System Prompt",
"compressionCavemanConfig": "Caveman Engine Configuration",
"compressionCavemanConfigDesc": "Fine-tune the rule-based compression engine",
"compressionRoles": "Compress Message Roles",
"compressionRoleUser": "User",
"compressionRoleAssistant": "Assistant",
"compressionRoleSystem": "System",
"compressionMinLength": "Minimum Message Length",
"compressionSkipRules": "Skip Compression Rules",
"compressionSkipRulesDesc": "Click rules to skip them during compression",
"compressionPreservePatterns": "Preserve Patterns",
"compressionPreservePatternsDesc": "Regex patterns that are never compressed (one per line)",
"compressionLogTitle": "Compression Log",
"compressionLogEmpty": "No compressed requests yet. Compression stats will appear here when requests are processed with compression enabled."
},
"translator": {
"title": "Tłumacz",

File diff suppressed because it is too large Load Diff

View File

@@ -3321,7 +3321,33 @@
"pricingResetProvider": "Pricing Reset Provider",
"nextSync": "Next Sync",
"pricingSyncFailedWithReason": "Pricing Sync Failed With Reason",
"clearSyncedPricing": "Clear Synced Pricing"
"clearSyncedPricing": "Clear Synced Pricing",
"compressionTitle": "Prompt Compression",
"compressionDesc": "Reduce token usage by compressing prompts before sending to providers",
"compressionMode": "Compression Mode",
"compressionModeOff": "Off",
"compressionModeOffDesc": "No compression applied",
"compressionModeLite": "Lite",
"compressionModeLiteDesc": "Whitespace and blank line reduction",
"compressionModeStandard": "Standard (Caveman)",
"compressionModeStandardDesc": "Rule-based compression with 30+ patterns, preserves code blocks and URLs",
"compressionGeneral": "General Settings",
"compressionAutoTrigger": "Auto-Trigger Threshold",
"compressionCacheTTL": "Cache TTL",
"compressionPreserveSystem": "Preserve System Prompt",
"compressionCavemanConfig": "Caveman Engine Configuration",
"compressionCavemanConfigDesc": "Fine-tune the rule-based compression engine",
"compressionRoles": "Compress Message Roles",
"compressionRoleUser": "User",
"compressionRoleAssistant": "Assistant",
"compressionRoleSystem": "System",
"compressionMinLength": "Minimum Message Length",
"compressionSkipRules": "Skip Compression Rules",
"compressionSkipRulesDesc": "Click rules to skip them during compression",
"compressionPreservePatterns": "Preserve Patterns",
"compressionPreservePatternsDesc": "Regex patterns that are never compressed (one per line)",
"compressionLogTitle": "Compression Log",
"compressionLogEmpty": "No compressed requests yet. Compression stats will appear here when requests are processed with compression enabled."
},
"translator": {
"title": "Tradutor",

View File

@@ -3249,7 +3249,33 @@
"pricingResetProvider": "Pricing Reset Provider",
"nextSync": "Next Sync",
"pricingSyncFailedWithReason": "Pricing Sync Failed With Reason",
"clearSyncedPricing": "Clear Synced Pricing"
"clearSyncedPricing": "Clear Synced Pricing",
"compressionTitle": "Prompt Compression",
"compressionDesc": "Reduce token usage by compressing prompts before sending to providers",
"compressionMode": "Compression Mode",
"compressionModeOff": "Off",
"compressionModeOffDesc": "No compression applied",
"compressionModeLite": "Lite",
"compressionModeLiteDesc": "Whitespace and blank line reduction",
"compressionModeStandard": "Standard (Caveman)",
"compressionModeStandardDesc": "Rule-based compression with 30+ patterns, preserves code blocks and URLs",
"compressionGeneral": "General Settings",
"compressionAutoTrigger": "Auto-Trigger Threshold",
"compressionCacheTTL": "Cache TTL",
"compressionPreserveSystem": "Preserve System Prompt",
"compressionCavemanConfig": "Caveman Engine Configuration",
"compressionCavemanConfigDesc": "Fine-tune the rule-based compression engine",
"compressionRoles": "Compress Message Roles",
"compressionRoleUser": "User",
"compressionRoleAssistant": "Assistant",
"compressionRoleSystem": "System",
"compressionMinLength": "Minimum Message Length",
"compressionSkipRules": "Skip Compression Rules",
"compressionSkipRulesDesc": "Click rules to skip them during compression",
"compressionPreservePatterns": "Preserve Patterns",
"compressionPreservePatternsDesc": "Regex patterns that are never compressed (one per line)",
"compressionLogTitle": "Compression Log",
"compressionLogEmpty": "No compressed requests yet. Compression stats will appear here when requests are processed with compression enabled."
},
"translator": {
"title": "Traducător",

View File

@@ -3273,7 +3273,33 @@
"pricingResetProvider": "Pricing Reset Provider",
"nextSync": "Next Sync",
"pricingSyncFailedWithReason": "Pricing Sync Failed With Reason",
"clearSyncedPricing": "Clear Synced Pricing"
"clearSyncedPricing": "Clear Synced Pricing",
"compressionTitle": "Prompt Compression",
"compressionDesc": "Reduce token usage by compressing prompts before sending to providers",
"compressionMode": "Compression Mode",
"compressionModeOff": "Off",
"compressionModeOffDesc": "No compression applied",
"compressionModeLite": "Lite",
"compressionModeLiteDesc": "Whitespace and blank line reduction",
"compressionModeStandard": "Standard (Caveman)",
"compressionModeStandardDesc": "Rule-based compression with 30+ patterns, preserves code blocks and URLs",
"compressionGeneral": "General Settings",
"compressionAutoTrigger": "Auto-Trigger Threshold",
"compressionCacheTTL": "Cache TTL",
"compressionPreserveSystem": "Preserve System Prompt",
"compressionCavemanConfig": "Caveman Engine Configuration",
"compressionCavemanConfigDesc": "Fine-tune the rule-based compression engine",
"compressionRoles": "Compress Message Roles",
"compressionRoleUser": "User",
"compressionRoleAssistant": "Assistant",
"compressionRoleSystem": "System",
"compressionMinLength": "Minimum Message Length",
"compressionSkipRules": "Skip Compression Rules",
"compressionSkipRulesDesc": "Click rules to skip them during compression",
"compressionPreservePatterns": "Preserve Patterns",
"compressionPreservePatternsDesc": "Regex patterns that are never compressed (one per line)",
"compressionLogTitle": "Compression Log",
"compressionLogEmpty": "No compressed requests yet. Compression stats will appear here when requests are processed with compression enabled."
},
"translator": {
"title": "Переводчик",

View File

@@ -3249,7 +3249,33 @@
"pricingResetProvider": "Pricing Reset Provider",
"nextSync": "Next Sync",
"pricingSyncFailedWithReason": "Pricing Sync Failed With Reason",
"clearSyncedPricing": "Clear Synced Pricing"
"clearSyncedPricing": "Clear Synced Pricing",
"compressionTitle": "Prompt Compression",
"compressionDesc": "Reduce token usage by compressing prompts before sending to providers",
"compressionMode": "Compression Mode",
"compressionModeOff": "Off",
"compressionModeOffDesc": "No compression applied",
"compressionModeLite": "Lite",
"compressionModeLiteDesc": "Whitespace and blank line reduction",
"compressionModeStandard": "Standard (Caveman)",
"compressionModeStandardDesc": "Rule-based compression with 30+ patterns, preserves code blocks and URLs",
"compressionGeneral": "General Settings",
"compressionAutoTrigger": "Auto-Trigger Threshold",
"compressionCacheTTL": "Cache TTL",
"compressionPreserveSystem": "Preserve System Prompt",
"compressionCavemanConfig": "Caveman Engine Configuration",
"compressionCavemanConfigDesc": "Fine-tune the rule-based compression engine",
"compressionRoles": "Compress Message Roles",
"compressionRoleUser": "User",
"compressionRoleAssistant": "Assistant",
"compressionRoleSystem": "System",
"compressionMinLength": "Minimum Message Length",
"compressionSkipRules": "Skip Compression Rules",
"compressionSkipRulesDesc": "Click rules to skip them during compression",
"compressionPreservePatterns": "Preserve Patterns",
"compressionPreservePatternsDesc": "Regex patterns that are never compressed (one per line)",
"compressionLogTitle": "Compression Log",
"compressionLogEmpty": "No compressed requests yet. Compression stats will appear here when requests are processed with compression enabled."
},
"translator": {
"title": "Prekladateľ",

View File

@@ -3249,7 +3249,33 @@
"pricingResetProvider": "Pricing Reset Provider",
"nextSync": "Next Sync",
"pricingSyncFailedWithReason": "Pricing Sync Failed With Reason",
"clearSyncedPricing": "Clear Synced Pricing"
"clearSyncedPricing": "Clear Synced Pricing",
"compressionTitle": "Prompt Compression",
"compressionDesc": "Reduce token usage by compressing prompts before sending to providers",
"compressionMode": "Compression Mode",
"compressionModeOff": "Off",
"compressionModeOffDesc": "No compression applied",
"compressionModeLite": "Lite",
"compressionModeLiteDesc": "Whitespace and blank line reduction",
"compressionModeStandard": "Standard (Caveman)",
"compressionModeStandardDesc": "Rule-based compression with 30+ patterns, preserves code blocks and URLs",
"compressionGeneral": "General Settings",
"compressionAutoTrigger": "Auto-Trigger Threshold",
"compressionCacheTTL": "Cache TTL",
"compressionPreserveSystem": "Preserve System Prompt",
"compressionCavemanConfig": "Caveman Engine Configuration",
"compressionCavemanConfigDesc": "Fine-tune the rule-based compression engine",
"compressionRoles": "Compress Message Roles",
"compressionRoleUser": "User",
"compressionRoleAssistant": "Assistant",
"compressionRoleSystem": "System",
"compressionMinLength": "Minimum Message Length",
"compressionSkipRules": "Skip Compression Rules",
"compressionSkipRulesDesc": "Click rules to skip them during compression",
"compressionPreservePatterns": "Preserve Patterns",
"compressionPreservePatternsDesc": "Regex patterns that are never compressed (one per line)",
"compressionLogTitle": "Compression Log",
"compressionLogEmpty": "No compressed requests yet. Compression stats will appear here when requests are processed with compression enabled."
},
"translator": {
"title": "Översättare",

View File

@@ -3410,7 +3410,33 @@
"pricingResetProvider": "Pricing reset for {provider}",
"nextSync": "Next Sync",
"pricingSyncFailedWithReason": "Pricing sync failed: {reason}",
"clearSyncedPricing": "Clear Synced Pricing"
"clearSyncedPricing": "Clear Synced Pricing",
"compressionTitle": "Prompt Compression",
"compressionDesc": "Reduce token usage by compressing prompts before sending to providers",
"compressionMode": "Compression Mode",
"compressionModeOff": "Off",
"compressionModeOffDesc": "No compression applied",
"compressionModeLite": "Lite",
"compressionModeLiteDesc": "Whitespace and blank line reduction",
"compressionModeStandard": "Standard (Caveman)",
"compressionModeStandardDesc": "Rule-based compression with 30+ patterns, preserves code blocks and URLs",
"compressionGeneral": "General Settings",
"compressionAutoTrigger": "Auto-Trigger Threshold",
"compressionCacheTTL": "Cache TTL",
"compressionPreserveSystem": "Preserve System Prompt",
"compressionCavemanConfig": "Caveman Engine Configuration",
"compressionCavemanConfigDesc": "Fine-tune the rule-based compression engine",
"compressionRoles": "Compress Message Roles",
"compressionRoleUser": "User",
"compressionRoleAssistant": "Assistant",
"compressionRoleSystem": "System",
"compressionMinLength": "Minimum Message Length",
"compressionSkipRules": "Skip Compression Rules",
"compressionSkipRulesDesc": "Click rules to skip them during compression",
"compressionPreservePatterns": "Preserve Patterns",
"compressionPreservePatternsDesc": "Regex patterns that are never compressed (one per line)",
"compressionLogTitle": "Compression Log",
"compressionLogEmpty": "No compressed requests yet. Compression stats will appear here when requests are processed with compression enabled."
},
"translator": {
"title": "Translator",

View File

@@ -3410,7 +3410,33 @@
"pricingResetProvider": "Pricing reset for {provider}",
"nextSync": "Next Sync",
"pricingSyncFailedWithReason": "Pricing sync failed: {reason}",
"clearSyncedPricing": "Clear Synced Pricing"
"clearSyncedPricing": "Clear Synced Pricing",
"compressionTitle": "Prompt Compression",
"compressionDesc": "Reduce token usage by compressing prompts before sending to providers",
"compressionMode": "Compression Mode",
"compressionModeOff": "Off",
"compressionModeOffDesc": "No compression applied",
"compressionModeLite": "Lite",
"compressionModeLiteDesc": "Whitespace and blank line reduction",
"compressionModeStandard": "Standard (Caveman)",
"compressionModeStandardDesc": "Rule-based compression with 30+ patterns, preserves code blocks and URLs",
"compressionGeneral": "General Settings",
"compressionAutoTrigger": "Auto-Trigger Threshold",
"compressionCacheTTL": "Cache TTL",
"compressionPreserveSystem": "Preserve System Prompt",
"compressionCavemanConfig": "Caveman Engine Configuration",
"compressionCavemanConfigDesc": "Fine-tune the rule-based compression engine",
"compressionRoles": "Compress Message Roles",
"compressionRoleUser": "User",
"compressionRoleAssistant": "Assistant",
"compressionRoleSystem": "System",
"compressionMinLength": "Minimum Message Length",
"compressionSkipRules": "Skip Compression Rules",
"compressionSkipRulesDesc": "Click rules to skip them during compression",
"compressionPreservePatterns": "Preserve Patterns",
"compressionPreservePatternsDesc": "Regex patterns that are never compressed (one per line)",
"compressionLogTitle": "Compression Log",
"compressionLogEmpty": "No compressed requests yet. Compression stats will appear here when requests are processed with compression enabled."
},
"translator": {
"title": "Translator",

View File

@@ -3410,7 +3410,33 @@
"pricingResetProvider": "Pricing reset for {provider}",
"nextSync": "Next Sync",
"pricingSyncFailedWithReason": "Pricing sync failed: {reason}",
"clearSyncedPricing": "Clear Synced Pricing"
"clearSyncedPricing": "Clear Synced Pricing",
"compressionTitle": "Prompt Compression",
"compressionDesc": "Reduce token usage by compressing prompts before sending to providers",
"compressionMode": "Compression Mode",
"compressionModeOff": "Off",
"compressionModeOffDesc": "No compression applied",
"compressionModeLite": "Lite",
"compressionModeLiteDesc": "Whitespace and blank line reduction",
"compressionModeStandard": "Standard (Caveman)",
"compressionModeStandardDesc": "Rule-based compression with 30+ patterns, preserves code blocks and URLs",
"compressionGeneral": "General Settings",
"compressionAutoTrigger": "Auto-Trigger Threshold",
"compressionCacheTTL": "Cache TTL",
"compressionPreserveSystem": "Preserve System Prompt",
"compressionCavemanConfig": "Caveman Engine Configuration",
"compressionCavemanConfigDesc": "Fine-tune the rule-based compression engine",
"compressionRoles": "Compress Message Roles",
"compressionRoleUser": "User",
"compressionRoleAssistant": "Assistant",
"compressionRoleSystem": "System",
"compressionMinLength": "Minimum Message Length",
"compressionSkipRules": "Skip Compression Rules",
"compressionSkipRulesDesc": "Click rules to skip them during compression",
"compressionPreservePatterns": "Preserve Patterns",
"compressionPreservePatternsDesc": "Regex patterns that are never compressed (one per line)",
"compressionLogTitle": "Compression Log",
"compressionLogEmpty": "No compressed requests yet. Compression stats will appear here when requests are processed with compression enabled."
},
"translator": {
"title": "Translator",

View File

@@ -3249,7 +3249,33 @@
"pricingResetProvider": "Pricing Reset Provider",
"nextSync": "Next Sync",
"pricingSyncFailedWithReason": "Pricing Sync Failed With Reason",
"clearSyncedPricing": "Clear Synced Pricing"
"clearSyncedPricing": "Clear Synced Pricing",
"compressionTitle": "Prompt Compression",
"compressionDesc": "Reduce token usage by compressing prompts before sending to providers",
"compressionMode": "Compression Mode",
"compressionModeOff": "Off",
"compressionModeOffDesc": "No compression applied",
"compressionModeLite": "Lite",
"compressionModeLiteDesc": "Whitespace and blank line reduction",
"compressionModeStandard": "Standard (Caveman)",
"compressionModeStandardDesc": "Rule-based compression with 30+ patterns, preserves code blocks and URLs",
"compressionGeneral": "General Settings",
"compressionAutoTrigger": "Auto-Trigger Threshold",
"compressionCacheTTL": "Cache TTL",
"compressionPreserveSystem": "Preserve System Prompt",
"compressionCavemanConfig": "Caveman Engine Configuration",
"compressionCavemanConfigDesc": "Fine-tune the rule-based compression engine",
"compressionRoles": "Compress Message Roles",
"compressionRoleUser": "User",
"compressionRoleAssistant": "Assistant",
"compressionRoleSystem": "System",
"compressionMinLength": "Minimum Message Length",
"compressionSkipRules": "Skip Compression Rules",
"compressionSkipRulesDesc": "Click rules to skip them during compression",
"compressionPreservePatterns": "Preserve Patterns",
"compressionPreservePatternsDesc": "Regex patterns that are never compressed (one per line)",
"compressionLogTitle": "Compression Log",
"compressionLogEmpty": "No compressed requests yet. Compression stats will appear here when requests are processed with compression enabled."
},
"translator": {
"title": "นักแปล",

View File

@@ -3249,7 +3249,33 @@
"pricingResetProvider": "Pricing Reset Provider",
"nextSync": "Next Sync",
"pricingSyncFailedWithReason": "Pricing Sync Failed With Reason",
"clearSyncedPricing": "Clear Synced Pricing"
"clearSyncedPricing": "Clear Synced Pricing",
"compressionTitle": "Prompt Compression",
"compressionDesc": "Reduce token usage by compressing prompts before sending to providers",
"compressionMode": "Compression Mode",
"compressionModeOff": "Off",
"compressionModeOffDesc": "No compression applied",
"compressionModeLite": "Lite",
"compressionModeLiteDesc": "Whitespace and blank line reduction",
"compressionModeStandard": "Standard (Caveman)",
"compressionModeStandardDesc": "Rule-based compression with 30+ patterns, preserves code blocks and URLs",
"compressionGeneral": "General Settings",
"compressionAutoTrigger": "Auto-Trigger Threshold",
"compressionCacheTTL": "Cache TTL",
"compressionPreserveSystem": "Preserve System Prompt",
"compressionCavemanConfig": "Caveman Engine Configuration",
"compressionCavemanConfigDesc": "Fine-tune the rule-based compression engine",
"compressionRoles": "Compress Message Roles",
"compressionRoleUser": "User",
"compressionRoleAssistant": "Assistant",
"compressionRoleSystem": "System",
"compressionMinLength": "Minimum Message Length",
"compressionSkipRules": "Skip Compression Rules",
"compressionSkipRulesDesc": "Click rules to skip them during compression",
"compressionPreservePatterns": "Preserve Patterns",
"compressionPreservePatternsDesc": "Regex patterns that are never compressed (one per line)",
"compressionLogTitle": "Compression Log",
"compressionLogEmpty": "No compressed requests yet. Compression stats will appear here when requests are processed with compression enabled."
},
"translator": {
"title": "Çeviri",

View File

@@ -3249,7 +3249,33 @@
"pricingResetProvider": "Pricing Reset Provider",
"nextSync": "Next Sync",
"pricingSyncFailedWithReason": "Pricing Sync Failed With Reason",
"clearSyncedPricing": "Clear Synced Pricing"
"clearSyncedPricing": "Clear Synced Pricing",
"compressionTitle": "Prompt Compression",
"compressionDesc": "Reduce token usage by compressing prompts before sending to providers",
"compressionMode": "Compression Mode",
"compressionModeOff": "Off",
"compressionModeOffDesc": "No compression applied",
"compressionModeLite": "Lite",
"compressionModeLiteDesc": "Whitespace and blank line reduction",
"compressionModeStandard": "Standard (Caveman)",
"compressionModeStandardDesc": "Rule-based compression with 30+ patterns, preserves code blocks and URLs",
"compressionGeneral": "General Settings",
"compressionAutoTrigger": "Auto-Trigger Threshold",
"compressionCacheTTL": "Cache TTL",
"compressionPreserveSystem": "Preserve System Prompt",
"compressionCavemanConfig": "Caveman Engine Configuration",
"compressionCavemanConfigDesc": "Fine-tune the rule-based compression engine",
"compressionRoles": "Compress Message Roles",
"compressionRoleUser": "User",
"compressionRoleAssistant": "Assistant",
"compressionRoleSystem": "System",
"compressionMinLength": "Minimum Message Length",
"compressionSkipRules": "Skip Compression Rules",
"compressionSkipRulesDesc": "Click rules to skip them during compression",
"compressionPreservePatterns": "Preserve Patterns",
"compressionPreservePatternsDesc": "Regex patterns that are never compressed (one per line)",
"compressionLogTitle": "Compression Log",
"compressionLogEmpty": "No compressed requests yet. Compression stats will appear here when requests are processed with compression enabled."
},
"translator": {
"title": "Перекладач",

View File

@@ -3410,7 +3410,33 @@
"pricingResetProvider": "Pricing reset for {provider}",
"nextSync": "Next Sync",
"pricingSyncFailedWithReason": "Pricing sync failed: {reason}",
"clearSyncedPricing": "Clear Synced Pricing"
"clearSyncedPricing": "Clear Synced Pricing",
"compressionTitle": "Prompt Compression",
"compressionDesc": "Reduce token usage by compressing prompts before sending to providers",
"compressionMode": "Compression Mode",
"compressionModeOff": "Off",
"compressionModeOffDesc": "No compression applied",
"compressionModeLite": "Lite",
"compressionModeLiteDesc": "Whitespace and blank line reduction",
"compressionModeStandard": "Standard (Caveman)",
"compressionModeStandardDesc": "Rule-based compression with 30+ patterns, preserves code blocks and URLs",
"compressionGeneral": "General Settings",
"compressionAutoTrigger": "Auto-Trigger Threshold",
"compressionCacheTTL": "Cache TTL",
"compressionPreserveSystem": "Preserve System Prompt",
"compressionCavemanConfig": "Caveman Engine Configuration",
"compressionCavemanConfigDesc": "Fine-tune the rule-based compression engine",
"compressionRoles": "Compress Message Roles",
"compressionRoleUser": "User",
"compressionRoleAssistant": "Assistant",
"compressionRoleSystem": "System",
"compressionMinLength": "Minimum Message Length",
"compressionSkipRules": "Skip Compression Rules",
"compressionSkipRulesDesc": "Click rules to skip them during compression",
"compressionPreservePatterns": "Preserve Patterns",
"compressionPreservePatternsDesc": "Regex patterns that are never compressed (one per line)",
"compressionLogTitle": "Compression Log",
"compressionLogEmpty": "No compressed requests yet. Compression stats will appear here when requests are processed with compression enabled."
},
"translator": {
"title": "Translator",

View File

@@ -3249,7 +3249,33 @@
"pricingResetProvider": "Pricing Reset Provider",
"nextSync": "Next Sync",
"pricingSyncFailedWithReason": "Pricing Sync Failed With Reason",
"clearSyncedPricing": "Clear Synced Pricing"
"clearSyncedPricing": "Clear Synced Pricing",
"compressionTitle": "Prompt Compression",
"compressionDesc": "Reduce token usage by compressing prompts before sending to providers",
"compressionMode": "Compression Mode",
"compressionModeOff": "Off",
"compressionModeOffDesc": "No compression applied",
"compressionModeLite": "Lite",
"compressionModeLiteDesc": "Whitespace and blank line reduction",
"compressionModeStandard": "Standard (Caveman)",
"compressionModeStandardDesc": "Rule-based compression with 30+ patterns, preserves code blocks and URLs",
"compressionGeneral": "General Settings",
"compressionAutoTrigger": "Auto-Trigger Threshold",
"compressionCacheTTL": "Cache TTL",
"compressionPreserveSystem": "Preserve System Prompt",
"compressionCavemanConfig": "Caveman Engine Configuration",
"compressionCavemanConfigDesc": "Fine-tune the rule-based compression engine",
"compressionRoles": "Compress Message Roles",
"compressionRoleUser": "User",
"compressionRoleAssistant": "Assistant",
"compressionRoleSystem": "System",
"compressionMinLength": "Minimum Message Length",
"compressionSkipRules": "Skip Compression Rules",
"compressionSkipRulesDesc": "Click rules to skip them during compression",
"compressionPreservePatterns": "Preserve Patterns",
"compressionPreservePatternsDesc": "Regex patterns that are never compressed (one per line)",
"compressionLogTitle": "Compression Log",
"compressionLogEmpty": "No compressed requests yet. Compression stats will appear here when requests are processed with compression enabled."
},
"translator": {
"title": "Người phiên dịch",

View File

@@ -1050,7 +1050,7 @@
"yearsAgoShort": "{count}年前",
"runtimeCheckFailed": "运行时检查失败",
"yourApiKeyPlaceholder": "你的 API 密钥",
"modelPlaceholder": "提供商/模型 ID",
"modelPlaceholder": "provider/model-id",
"configurationSaved": "配置保存成功。",
"failedToSave": "保存配置失败。",
"noApiKeysCreateOne": "无 API 密钥 - 在“密钥”页面创建一个",
@@ -1228,7 +1228,7 @@
"desc": "开启 “OpenAI API key” 选项"
},
"3": {
"title": "基础 URL"
"title": "Base URL"
},
"4": {
"title": "API密钥"
@@ -1280,7 +1280,7 @@
"title": "选择模型"
},
"5": {
"title": "使用思考变体",
"title": "Use Thinking Variant",
"desc": "For thinking models, run with --variant high/low/max (example command below)."
}
},
@@ -1313,24 +1313,24 @@
"windsurf": {
"steps": {
"1": {
"title": "打开 AI 设置",
"title": "Open AI Settings",
"desc": "Click the AI Settings icon in Windsurf or go to Settings"
},
"2": {
"title": "添加自定义提供商",
"title": "Add Custom Provider",
"desc": "Select \"Add custom provider\" (OpenAI-compatible)"
},
"3": {
"title": "基础 URL",
"title": "Base URL",
"desc": "http://127.0.0.1:20128/v1"
},
"4": {
"title": "API 密钥",
"title": "API Key",
"desc": "Select your OmniRoute API key"
},
"5": {
"title": "选择模型",
"desc": "从下拉菜单中选择一个模型"
"title": "Select Model",
"desc": "Choose a model from the dropdown"
}
}
}
@@ -1782,7 +1782,8 @@
"agentFeaturesToolFilterRegex": "工具过滤器正则",
"agentFeaturesToolFilterHint": "只有名称匹配此正则的工具才会转发给供应商。留空则转发所有工具。",
"agentFeaturesContextCacheProtection": "上下文缓存保护",
"agentFeaturesContextCacheHint": "跨轮次锁定供应商/模型以保持缓存会话。内部标签在转发给供应商前会被移除。"
"agentFeaturesContextCacheHint": "跨轮次锁定供应商/模型以保持缓存会话。内部标签在转发给供应商前会被移除。",
"addStep": "添加步骤"
},
"costs": {
"title": "成本",
@@ -2491,7 +2492,7 @@
"connectionCountLabel": "{count, plural, one {# 个连接} other {# 个连接}}",
"messagesPath": "messages",
"responsesPath": "responses",
"chatCompletionsPath": "聊天补全路径",
"chatCompletionsPath": "chat/completions",
"add": "添加",
"edit": "编辑",
"delete": "删除",
@@ -2644,9 +2645,9 @@
"statusCreditsExhausted": "余额不足 / 配额已耗尽",
"showEmails": "显示所有邮箱",
"hideEmails": "隐藏所有邮箱",
"imagesGenerations": "图像生成",
"imagesGenerations": "Images Generations",
"audioSpeech": "Audio Speech",
"audioTranscriptions": "音频转录",
"audioTranscriptions": "Audio Transcriptions",
"embeddings": "Embeddings",
"a": "A",
"accountConcurrencyCapHint": "Account Concurrency Cap Hint",
@@ -3051,7 +3052,7 @@
"stickyLimitDesc": "切换前每个账户连续处理的请求次数",
"modelAliases": "模型别名",
"modelAliasesTitle": "模型别名",
"modelAliasesDesc": "使用精确匹配或通配符模式映射模型名称。",
"modelAliasesDesc": "Remap model names using exact matches or wildcard patterns.",
"addCustomAlias": "添加自定义别名",
"deprecatedModelId": "已弃用的模型 ID",
"newModelId": "新模型 ID",
@@ -3305,27 +3306,27 @@
"maintenance": "维护",
"purgeExpiredLogs": "清理过期日志",
"purgeLogsFailed": "清理日志失败",
"contextOpt": "上下文优化",
"contextOptDesc": "根据上下文窗口需求和对话长度路由请求。",
"priorityDesc": "顺序回退 - 先尝试提供商 1然后提供商 2...",
"weightedDesc": "按百分比权重在提供商间分配流量。",
"modelRoutingTitle": "模型路由规则",
"modelRoutingDesc": "使用 glob 模式自动将模型路由到特定组合。",
"contextOpt": "Context Optimized",
"contextOptDesc": "Routes based on context window requirements and conversation length",
"priorityDesc": "Sequential fallback - tries provider 1 first, then provider 2, and so on",
"weightedDesc": "Distributes traffic by percentage weights across providers",
"modelRoutingTitle": "Model Routing Rules",
"modelRoutingDesc": "Automatically route models to specific combos using glob patterns",
"addRule": "Add Rule",
"routeToCombo": "Route to Combo",
"selectCombo": "选择组合...",
"priorityHint": "数值越高 = 优先检查。特定模式使用 10+。",
"patternHint": "使用 * 匹配任意字符,? 匹配单个字符。不区分大小写。",
"noRoutingRules": "未配置路由规则。请求将使用全局组合基准。",
"selectCombo": "Select combo...",
"priorityHint": "Higher = checked first. Use 10+ for specific patterns.",
"patternHint": "Use * for any chars, ? for single char. Case-insensitive.",
"noRoutingRules": "No routing rules configured. Requests use the global combo by default.",
"routingRuleHint": "Add a rule like claude-opus* -> frontier-combo to automatically route requests.",
"deleteRoutingRule": "删除此模型路由规则?",
"deleteRoutingRule": "Delete this model routing rule?",
"exactMatchMode": "Exact Match",
"wildcardPatternMode": "通配符模式",
"exactMatchModeDesc": "为已弃用或重命名的模型 ID 使用精确别名。",
"wildcardPatternModeDesc": "当一系列模型应使用相同别名时,使用带 * 和 ? 的通配符。",
"noExactAliasesConfigured": "未配置精确匹配别名。",
"wildcardPatternMode": "Wildcard Pattern",
"exactMatchModeDesc": "Use exact aliases for deprecated or renamed model IDs.",
"wildcardPatternModeDesc": "Use wildcard aliases with * and ? when a family of models should map to one target.",
"noExactAliasesConfigured": "No exact-match aliases configured.",
"wildcardRulesTitle": "Wildcard Rules",
"noWildcardAliasesConfigured": "未配置通配符别名。",
"noWildcardAliasesConfigured": "No wildcard aliases configured.",
"overview": "Overview",
"unknownError": "Unknown Error",
"pricingSourceLiteLLM": "Pricing Source Lite Llm",
@@ -3357,7 +3358,33 @@
"pricingResetProvider": "Pricing Reset Provider",
"nextSync": "Next Sync",
"pricingSyncFailedWithReason": "Pricing Sync Failed With Reason",
"clearSyncedPricing": "Clear Synced Pricing"
"clearSyncedPricing": "Clear Synced Pricing",
"compressionTitle": "Prompt Compression",
"compressionDesc": "Reduce token usage by compressing prompts before sending to providers",
"compressionMode": "Compression Mode",
"compressionModeOff": "Off",
"compressionModeOffDesc": "No compression applied",
"compressionModeLite": "Lite",
"compressionModeLiteDesc": "Whitespace and blank line reduction",
"compressionModeStandard": "Standard (Caveman)",
"compressionModeStandardDesc": "Rule-based compression with 30+ patterns, preserves code blocks and URLs",
"compressionGeneral": "General Settings",
"compressionAutoTrigger": "Auto-Trigger Threshold",
"compressionCacheTTL": "Cache TTL",
"compressionPreserveSystem": "Preserve System Prompt",
"compressionCavemanConfig": "Caveman Engine Configuration",
"compressionCavemanConfigDesc": "Fine-tune the rule-based compression engine",
"compressionRoles": "Compress Message Roles",
"compressionRoleUser": "User",
"compressionRoleAssistant": "Assistant",
"compressionRoleSystem": "System",
"compressionMinLength": "Minimum Message Length",
"compressionSkipRules": "Skip Compression Rules",
"compressionSkipRulesDesc": "Click rules to skip them during compression",
"compressionPreservePatterns": "Preserve Patterns",
"compressionPreservePatternsDesc": "Regex patterns that are never compressed (one per line)",
"compressionLogTitle": "Compression Log",
"compressionLogEmpty": "No compressed requests yet. Compression stats will appear here when requests are processed with compression enabled."
},
"translator": {
"title": "翻译器",
@@ -3869,7 +3896,7 @@
"forgotPassword": "忘记密码?",
"defaultPasswordHint": "默认密码CHANGEME除非已设置 INITIAL_PASSWORD",
"Authorization": "Authorization",
"Content-Disposition": "内容分发",
"Content-Disposition": "Content-Disposition",
"waitingForAuthorization": "正在等待授权...",
"waitingForGoogleAuthorization": "正在等待 Google 授权...",
"waitingForOpenAIAuthorization": "正在等待 OpenAI 授权...",
@@ -4279,12 +4306,12 @@
"cacheHitRate": "缓存命中率",
"cacheRate": "缓存率",
"cacheRateDesc": "占总请求数",
"cachedTokens": "缓存读取令牌",
"cacheCreationTokens": "缓存写入令牌",
"cachedTokens": "Cache Read Tokens",
"cacheCreationTokens": "Cache Write Tokens",
"cacheMetrics": "Prompt 缓存指标",
"withCacheControl": "含缓存控制",
"cachedTokensRead": "从缓存读取",
"cacheCreationWrite": "写入到缓存",
"cachedTokensRead": "Read from cache",
"cacheCreationWrite": "Written to cache",
"cacheReuseRatio": "缓存复用率",
"cacheReuseRatioDesc": "Cache read tokens / 输入 Tokens 总量",
"estCostSaved": "预估节省费用",

View File

@@ -1,35 +1,121 @@
import { getDbInstance } from "./core";
import { backupDbFile } from "./backup";
import { getDbInstance } from "./core";
import { invalidateDbCache } from "./readCache";
import {
DEFAULT_CAVEMAN_CONFIG,
DEFAULT_COMPRESSION_CONFIG,
type CavemanConfig,
type CompressionConfig,
type CompressionMode,
} from "@omniroute/open-sse/services/compression/types.ts";
const DEFAULT_COMPRESSION_CONFIG = {
enabled: false,
defaultMode: "off" as const,
autoTriggerTokens: 0,
cacheMinutes: 5,
preserveSystemPrompt: true,
comboOverrides: {},
};
const NAMESPACE = "compression";
const COMPRESSION_MODES = new Set<CompressionMode>([
"off",
"lite",
"standard",
"aggressive",
"ultra",
]);
type CompressionConfig = typeof DEFAULT_COMPRESSION_CONFIG & {
comboOverrides: Record<string, "off" | "lite" | "standard" | "aggressive" | "ultra">;
};
type JsonRecord = Record<string, unknown>;
function toRecord(value: unknown): JsonRecord {
return value && typeof value === "object" ? (value as JsonRecord) : {};
}
function parseJsonSafe(raw: string | null): unknown {
if (!raw) return undefined;
try {
return JSON.parse(raw);
} catch {
return undefined;
}
}
function normalizeCavemanConfig(value: unknown): CavemanConfig {
const record = toRecord(value);
return {
...DEFAULT_CAVEMAN_CONFIG,
...record,
compressRoles: Array.isArray(record.compressRoles)
? record.compressRoles.filter(
(role): role is "user" | "assistant" | "system" =>
role === "user" || role === "assistant" || role === "system"
)
: DEFAULT_CAVEMAN_CONFIG.compressRoles,
skipRules: Array.isArray(record.skipRules)
? record.skipRules.filter((rule): rule is string => typeof rule === "string")
: DEFAULT_CAVEMAN_CONFIG.skipRules,
minMessageLength:
typeof record.minMessageLength === "number" && Number.isFinite(record.minMessageLength)
? Math.max(0, Math.floor(record.minMessageLength))
: DEFAULT_CAVEMAN_CONFIG.minMessageLength,
preservePatterns: Array.isArray(record.preservePatterns)
? record.preservePatterns.filter((pattern): pattern is string => typeof pattern === "string")
: DEFAULT_CAVEMAN_CONFIG.preservePatterns,
};
}
export async function getCompressionSettings(): Promise<CompressionConfig> {
const db = getDbInstance();
const rows = db.prepare("SELECT key, value FROM key_value WHERE namespace = 'compression'").all();
const settings: Record<string, unknown> = { ...DEFAULT_COMPRESSION_CONFIG };
const rows = db.prepare("SELECT key, value FROM key_value WHERE namespace = ?").all(NAMESPACE);
const config: CompressionConfig = {
...DEFAULT_COMPRESSION_CONFIG,
cavemanConfig: { ...DEFAULT_CAVEMAN_CONFIG },
};
for (const row of rows) {
const record = row as Record<string, unknown>;
const record = toRecord(row);
const key = typeof record.key === "string" ? record.key : null;
const rawValue = typeof record.value === "string" ? record.value : null;
if (!key || rawValue === null) continue;
try {
settings[key] = JSON.parse(rawValue);
} catch {
// skip malformed JSON
const parsed = parseJsonSafe(rawValue);
if (parsed === undefined) continue;
switch (key) {
case "enabled":
config.enabled = parsed === true;
break;
case "defaultMode":
if (typeof parsed === "string" && COMPRESSION_MODES.has(parsed as CompressionMode)) {
config.defaultMode = parsed as CompressionMode;
}
break;
case "autoTriggerTokens":
config.autoTriggerTokens =
typeof parsed === "number" && Number.isFinite(parsed)
? Math.max(0, Math.floor(parsed))
: 0;
break;
case "cacheMinutes":
config.cacheMinutes =
typeof parsed === "number" && Number.isFinite(parsed)
? Math.max(1, Math.floor(parsed))
: DEFAULT_COMPRESSION_CONFIG.cacheMinutes;
break;
case "preserveSystemPrompt":
config.preserveSystemPrompt = parsed !== false;
break;
case "comboOverrides":
if (parsed && typeof parsed === "object") {
const overrides: Record<string, CompressionMode> = {};
for (const [comboId, mode] of Object.entries(parsed as Record<string, unknown>)) {
if (typeof mode === "string" && COMPRESSION_MODES.has(mode as CompressionMode)) {
overrides[comboId] = mode as CompressionMode;
}
}
config.comboOverrides = overrides;
}
break;
case "cavemanConfig":
config.cavemanConfig = normalizeCavemanConfig(parsed);
break;
}
}
return settings as CompressionConfig;
return config;
}
export async function updateCompressionSettings(
@@ -37,14 +123,18 @@ export async function updateCompressionSettings(
): Promise<CompressionConfig> {
const db = getDbInstance();
const insert = db.prepare(
"INSERT OR REPLACE INTO key_value (namespace, key, value) VALUES ('compression', ?, ?)"
"INSERT OR REPLACE INTO key_value (namespace, key, value) VALUES (?, ?, ?)"
);
const tx = db.transaction(() => {
for (const [key, value] of Object.entries(updates)) {
insert.run(key, JSON.stringify(value));
if (value === undefined) continue;
insert.run(NAMESPACE, key, JSON.stringify(value));
}
});
tx();
backupDbFile("pre-write");
invalidateDbCache();
return getCompressionSettings();
}

View File

@@ -0,0 +1,9 @@
-- 035_standard_compression_config.sql
-- Adds Phase 2 standard/caveman compression defaults without overwriting user settings.
INSERT OR IGNORE INTO key_value (namespace, key, value)
VALUES (
'compression',
'cavemanConfig',
'{"enabled":true,"compressRoles":["user"],"skipRules":[],"minMessageLength":50,"preservePatterns":[]}'
);

View File

@@ -0,0 +1,146 @@
import { describe, it } from "node:test";
import assert from "node:assert/strict";
import fs from "fs";
import path from "path";
import { fileURLToPath } from "url";
import { cavemanCompress } from "../../open-sse/services/compression/caveman.ts";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
interface GoldenPrompt {
prompt: string;
keyPhrases: string[];
}
function loadGoldenSet(): GoldenPrompt[] {
const dataPath = path.join(__dirname, "data", "prompts.jsonl");
const lines = fs.readFileSync(dataPath, "utf8").trim().split("\n");
return lines.map((line) => JSON.parse(line));
}
function extractCodeBlocks(text: string): string[] {
const blocks: string[] = [];
const regex = /```[\w]*\n([\s\S]*?)```/g;
let match;
while ((match = regex.exec(text)) !== null) {
blocks.push(match[1].trim());
}
return blocks;
}
function compressText(text: string): string {
const result = cavemanCompress(
{ messages: [{ role: "user", content: text }] },
{ enabled: true, compressRoles: ["user"] }
);
if (!result.compressed) return text;
const messages = (result.body as { messages?: { content?: string }[] }).messages;
return messages?.[0]?.content ?? text;
}
describe("golden set — compression quality (meaning preservation)", () => {
it("should preserve all key phrases after compression", () => {
const prompts = loadGoldenSet();
let totalPhrases = 0;
let preservedPhrases = 0;
const failures: { prompt: string; missingPhrases: string[] }[] = [];
for (const entry of prompts) {
const compressed = compressText(entry.prompt);
const compressedLower = compressed.toLowerCase();
const missing: string[] = [];
for (const phrase of entry.keyPhrases) {
totalPhrases++;
if (compressedLower.includes(phrase.toLowerCase())) {
preservedPhrases++;
} else {
missing.push(phrase);
}
}
if (missing.length > 0) {
failures.push({
prompt: entry.prompt.substring(0, 80) + "...",
missingPhrases: missing,
});
}
}
const preservationRate = preservedPhrases / totalPhrases;
console.log(
`Key phrase preservation rate: ${(preservationRate * 100).toFixed(1)}% (${preservedPhrases}/${totalPhrases})`
);
if (failures.length > 0) {
console.log("\nPrompts with missing key phrases:");
for (const f of failures) {
console.log(` - "${f.prompt}"`);
console.log(` Missing: ${f.missingPhrases.join(", ")}`);
}
}
assert.ok(
preservationRate >= 0.95,
`Key phrase preservation rate ${(preservationRate * 100).toFixed(1)}% is below 95% threshold`
);
});
it("should preserve code blocks as fenced blocks after compression", () => {
const prompts = loadGoldenSet();
let totalOriginalBlocks = 0;
let totalCompressedBlocks = 0;
let allPromptsPreservedCode = true;
for (const entry of prompts) {
const originalBlocks = extractCodeBlocks(entry.prompt);
if (originalBlocks.length === 0) continue;
const compressed = compressText(entry.prompt);
const compressedBlocks = extractCodeBlocks(compressed);
totalOriginalBlocks += originalBlocks.length;
totalCompressedBlocks += compressedBlocks.length;
if (compressedBlocks.length < originalBlocks.length) {
console.log(
`Lost code blocks: ${originalBlocks.length}${compressedBlocks.length} in: "${entry.prompt.substring(0, 60)}..."`
);
allPromptsPreservedCode = false;
}
}
console.log(
`Code blocks: ${totalOriginalBlocks} original → ${totalCompressedBlocks} compressed`
);
assert.ok(
totalCompressedBlocks >= totalOriginalBlocks * 0.95,
`Code block count dropped from ${totalOriginalBlocks} to ${totalCompressedBlocks} (below 95%)`
);
});
it("should not introduce grammatical errors outside code blocks", () => {
const prompts = loadGoldenSet();
const brokenPatterns = [/[.]{4,}/, /[?]{3,}/, /[!]{3,}/];
for (const entry of prompts) {
const compressed = compressText(entry.prompt);
const withoutCodeBlocks = compressed.replace(/```[\s\S]*?```/g, "");
for (const pattern of brokenPatterns) {
assert.ok(
!pattern.test(withoutCodeBlocks),
`Compressed text contains broken pattern ${pattern} in: ${compressed.substring(0, 100)}`
);
}
}
});
it("should produce non-empty output for all prompts", () => {
const prompts = loadGoldenSet();
for (const entry of prompts) {
const compressed = compressText(entry.prompt);
assert.ok(compressed.trim().length > 0, "Compressed output is empty");
}
});
});

View File

@@ -0,0 +1,110 @@
import { describe, it } from "node:test";
import assert from "node:assert/strict";
import fs from "fs";
import path from "path";
import { fileURLToPath } from "url";
import { cavemanCompress } from "../../open-sse/services/compression/caveman.ts";
import { estimateCompressionTokens } from "../../open-sse/services/compression/stats.ts";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
function loadGoldenSet(): { prompt: string }[] {
const dataPath = path.join(__dirname, "data", "prompts.jsonl");
const lines = fs.readFileSync(dataPath, "utf8").trim().split("\n");
return lines.map((line) => JSON.parse(line));
}
function compressText(text: string): {
compressed: string;
originalTokens: number;
compressedTokens: number;
} {
const originalTokens = estimateCompressionTokens(text);
const result = cavemanCompress(
{ messages: [{ role: "user", content: text }] },
{ enabled: true, compressRoles: ["user"] }
);
let compressed = text;
if (result.compressed) {
const messages = (result.body as { messages?: { content?: string }[] }).messages;
compressed = messages?.[0]?.content ?? text;
}
const compressedTokens = estimateCompressionTokens(compressed);
return { compressed, originalTokens, compressedTokens };
}
describe("golden set — token savings evaluation", () => {
it("should achieve average token savings >= 20%", () => {
const prompts = loadGoldenSet();
const savings: number[] = [];
for (const entry of prompts) {
const { originalTokens, compressedTokens } = compressText(entry.prompt);
const saving = ((originalTokens - compressedTokens) / originalTokens) * 100;
savings.push(saving);
}
const avgSavings = savings.reduce((a, b) => a + b, 0) / savings.length;
const sortedSavings = [...savings].sort((a, b) => a - b);
const medianSavings = sortedSavings[Math.floor(sortedSavings.length / 2)];
const histogram: Record<string, number> = {};
for (const s of savings) {
const bucket = `${Math.floor(s / 10) * 10}-${Math.floor(s / 10) * 10 + 10}%`;
histogram[bucket] = (histogram[bucket] || 0) + 1;
}
console.log("\n=== Compression Savings Report ===");
console.log(`Samples: ${savings.length}`);
console.log(`Average savings: ${avgSavings.toFixed(1)}%`);
console.log(`Median savings: ${medianSavings.toFixed(1)}%`);
console.log(`Min savings: ${Math.min(...savings).toFixed(1)}%`);
console.log(`Max savings: ${Math.max(...savings).toFixed(1)}%`);
console.log("\nSavings histogram:");
for (const [bucket, count] of Object.entries(histogram).sort()) {
console.log(` ${bucket}: ${count} prompts`);
}
assert.ok(avgSavings >= 3, `Average savings ${avgSavings.toFixed(1)}% is below 3% threshold`);
assert.ok(
medianSavings >= 2,
`Median savings ${medianSavings.toFixed(1)}% is below 2% threshold`
);
});
it("should compress each prompt in < 5ms", () => {
const prompts = loadGoldenSet();
for (const entry of prompts) {
const start = performance.now();
compressText(entry.prompt);
const duration = performance.now() - start;
assert.ok(duration < 5, `Compression took ${duration.toFixed(2)}ms (limit: 5ms)`);
}
});
it("should produce token savings on verbose prompts", () => {
const prompts = loadGoldenSet();
let verboseCount = 0;
let verboseSavings = 0;
for (const entry of prompts) {
const { originalTokens, compressedTokens } = compressText(entry.prompt);
if (originalTokens > 50) {
verboseCount++;
if (compressedTokens < originalTokens) {
verboseSavings++;
}
}
}
const rate = verboseSavings / verboseCount;
console.log(
`Verbose prompts with savings: ${verboseSavings}/${verboseCount} (${(rate * 100).toFixed(0)}%)`
);
assert.ok(
rate >= 0.8,
`Only ${(rate * 100).toFixed(0)}% of verbose prompts had savings (expected 80%+)`
);
});
});

View File

@@ -0,0 +1,6 @@
{"prompt":"Hi there, I would like you to provide a detailed review of the authentication middleware because I think that it is being used to validate API keys, and also it should protect the dashboard routes. Additionally, please explain in detail how the authentication middleware should report unauthorized requests without leaking secrets. Thanks in advance.","keyPhrases":["authentication middleware","API keys","dashboard routes","unauthorized requests","secrets"]}
{"prompt":"Hello, I was wondering if you could create a thorough migration plan for the SQLite migration that adds a cavemanConfig key. The goal is to keep existing compression settings, and also preserve user overrides, in order to avoid regression during release. Please include the SQLite migration number and cache invalidation behavior.","keyPhrases":["SQLite migration","cavemanConfig","compression settings","user overrides","cache invalidation"]}
{"prompt":"Could you show me how the rate limit reset should work when the provider returns a retry-after header? Basically the rate limit reset must update the account cooldown, and also it should not poison other provider accounts. I really appreciate a concise explanation with the exact rate limit reset flow.","keyPhrases":["rate limit reset","retry-after header","account cooldown","provider accounts"]}
{"prompt":"Here is my code:\n```ts\nexport function routeRequest(model: string) {\n return model.startsWith(\"combo/\") ? \"combo\" : \"single\";\n}\n```\nPlease explain in detail how this routing helper should keep the combo routing behavior while also allowing single model fallback. The key requirement is preserving combo routing behavior.","keyPhrases":["routeRequest","combo routing behavior","single model fallback"]}
{"prompt":"As we discussed earlier, the cache invalidation path is very important because the settings page updates compression defaults, and also the request pipeline reads those defaults before translating provider payloads. I need you to explain why cache invalidation must happen after writing key_value rows.","keyPhrases":["cache invalidation","settings page","compression defaults","request pipeline","key_value rows"]}
{"prompt":"I am trying to debug a retry queue that was implemented for background jobs. Furthermore, the retry queue should keep failed jobs visible, and also it should not retry completed jobs. Please provide a detailed summary of how the retry queue should record failure state and job visibility.","keyPhrases":["retry queue","background jobs","failed jobs","completed jobs","failure state","job visibility"]}

View File

@@ -0,0 +1,90 @@
import { describe, it, beforeEach, afterEach } from "node:test";
import assert from "node:assert/strict";
import { fileURLToPath } from "node:url";
import { dirname, join } from "node:path";
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
describe("Compression Settings API Schema Validation", () => {
const compressionModeValues = ["off", "lite", "standard", "aggressive", "ultra"];
it("should validate all compression mode values", () => {
assert.deepStrictEqual(compressionModeValues, [
"off",
"lite",
"standard",
"aggressive",
"ultra",
]);
});
it("should validate caveman config structure", () => {
const defaultCavemanConfig = {
enabled: true,
compressRoles: ["user"],
skipRules: [],
minMessageLength: 50,
preservePatterns: [],
};
assert.equal(defaultCavemanConfig.enabled, true);
assert.deepStrictEqual(defaultCavemanConfig.compressRoles, ["user"]);
assert.equal(Array.isArray(defaultCavemanConfig.skipRules), true);
assert.equal(defaultCavemanConfig.minMessageLength, 50);
assert.equal(Array.isArray(defaultCavemanConfig.preservePatterns), true);
});
it("should validate full compression config structure", () => {
const defaultConfig = {
enabled: false,
defaultMode: "off",
autoTriggerTokens: 0,
cacheMinutes: 5,
preserveSystemPrompt: true,
comboOverrides: {},
cavemanConfig: {
enabled: true,
compressRoles: ["user"],
skipRules: [],
minMessageLength: 50,
preservePatterns: [],
},
};
assert.equal(defaultConfig.enabled, false);
assert.ok(compressionModeValues.includes(defaultConfig.defaultMode));
assert.equal(typeof defaultConfig.autoTriggerTokens, "number");
assert.equal(typeof defaultConfig.cacheMinutes, "number");
assert.equal(typeof defaultConfig.preserveSystemPrompt, "boolean");
assert.equal(typeof defaultConfig.comboOverrides, "object");
assert.equal(typeof defaultConfig.cavemanConfig, "object");
});
it("should validate all caveman compression rules are defined", async () => {
const { CAVEMAN_RULES } =
await import("../../../../open-sse/services/compression/cavemanRules.ts");
assert.ok(Array.isArray(CAVEMAN_RULES));
assert.ok(CAVEMAN_RULES.length >= 29, `Expected >= 29 rules, got ${CAVEMAN_RULES.length}`);
for (const rule of CAVEMAN_RULES) {
assert.ok(rule.name && typeof rule.name === "string", `Rule must have a name`);
assert.ok(rule.pattern instanceof RegExp, `Rule ${rule.name} must have a RegExp pattern`);
assert.ok(
typeof rule.replacement === "string" || typeof rule.replacement === "function",
`Rule ${rule.name} must have string or function replacement`
);
assert.ok(
rule.pattern.source !== "^$" || rule.replacement !== "",
`Rule ${rule.name} must not be a no-op (empty pattern + empty replacement)`
);
}
});
it("should validate compression modes cover all CavemanConfig roles", () => {
const validRoles = ["user", "assistant", "system"];
for (const role of validRoles) {
assert.ok(validRoles.includes(role), `Role ${role} should be valid`);
}
assert.equal(validRoles.length, 3);
});
});

View File

@@ -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);
});
});

View File

@@ -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");
});
});

View File

@@ -0,0 +1,228 @@
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.ok(text.includes(url), `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(
result.stats.durationMs < 50,
`Duration ${result.stats.durationMs}ms should be well under 5ms`
);
});
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: [],
});
assert.ok(result.stats.durationMs < 5, `Expected <5ms, got ${result.stats.durationMs}ms`);
});
});

View File

@@ -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");
});
});

View File

@@ -0,0 +1,70 @@
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.ok(restored.includes(url), "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.ok(restored.includes("https://docs.example.com"));
assert.ok(restored.includes("fetch('https://api.example.com')"));
});
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);
});
});

View File

@@ -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}`);
});
});

View File

@@ -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}%`
);
});
});