76 lines
2.2 KiB
TypeScript
76 lines
2.2 KiB
TypeScript
export interface CompressionResult {
|
|
originalInput: string;
|
|
input: string;
|
|
applied: boolean;
|
|
method: string;
|
|
tokensBefore: number;
|
|
tokensAfter: number;
|
|
tokensSaved: number;
|
|
ratio: number;
|
|
strategy: string;
|
|
tags: string[];
|
|
notes: string[];
|
|
}
|
|
|
|
interface CompressionOptions {
|
|
enabled?: boolean;
|
|
mode?: string;
|
|
targetTokens?: number;
|
|
}
|
|
|
|
function estimateTokens(text: string): number {
|
|
return Math.max(1, Math.ceil(text.length / 4));
|
|
}
|
|
|
|
function noCompression(input: string, method = 'none:none'): CompressionResult {
|
|
const tokens = estimateTokens(input);
|
|
return {
|
|
originalInput: input,
|
|
input,
|
|
applied: false,
|
|
method,
|
|
tokensBefore: tokens,
|
|
tokensAfter: tokens,
|
|
tokensSaved: 0,
|
|
ratio: 0,
|
|
strategy: 'none',
|
|
tags: [],
|
|
notes: ['compression not applied'],
|
|
};
|
|
}
|
|
|
|
export function compressContext(input: string, options: CompressionOptions = {}): CompressionResult {
|
|
if (options.enabled === false || input.trim().length === 0) return noCompression(input);
|
|
|
|
const tokensBefore = estimateTokens(input);
|
|
const targetTokens = options.targetTokens ?? (tokensBefore > 12_000 ? 6_000 : 0);
|
|
if (!targetTokens || tokensBefore <= targetTokens) return noCompression(input);
|
|
|
|
const targetChars = Math.max(2_000, targetTokens * 4);
|
|
const headChars = Math.floor(targetChars * 0.62);
|
|
const tailChars = Math.max(800, targetChars - headChars);
|
|
const omittedChars = Math.max(0, input.length - headChars - tailChars);
|
|
const compacted = [
|
|
input.slice(0, headChars).trimEnd(),
|
|
'',
|
|
`[ctxlean omitted ${omittedChars} chars from the middle; preserve exact visible context]`,
|
|
'',
|
|
input.slice(-tailChars).trimStart(),
|
|
].join('\n');
|
|
|
|
const tokensAfter = estimateTokens(compacted);
|
|
return {
|
|
originalInput: input,
|
|
input: compacted,
|
|
applied: true,
|
|
method: `ctxlean:${options.mode ?? 'auto'}`,
|
|
tokensBefore,
|
|
tokensAfter,
|
|
tokensSaved: Math.max(0, tokensBefore - tokensAfter),
|
|
ratio: tokensBefore > 0 ? Math.max(0, 1 - tokensAfter / tokensBefore) : 0,
|
|
strategy: 'head-tail-excerpt',
|
|
tags: ['subscription-bridge-safe', 'lossy-excerpt'],
|
|
notes: ['long context compacted before model routing'],
|
|
};
|
|
}
|