mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-31 04:12:10 +03:00
* feat(compression): dependência omniglyph (file:) + smoke de import * feat(compression): engine omniglyph — contexto-como-imagem com gates fail-closed * fix(compression): omniglyph adapter fail-open no transform (try/catch) * feat(compression): registra omniglyph no registry e catálogo (single mode, stackPriority 90) * feat(compression): modo único omniglyph (async), selecionar o modo é o enable * feat(compression): plumbing supportsVision + providerTransport até os engines * feat(compression): estimador de tokens image-aware — modo stacked mantém a saída do omniglyph * docs(compression): corrige comentário do prefixo base64 no decode PNG (64 chars) * feat(compression): registra omniglyph nas listas de modo/engine (db, combo, deriveDefaultPlan, mcp) * feat(dashboard): dedicated OmniGlyph engine screen (context-as-image) Adds a per-engine detail page at /dashboard/context/omniglyph, alongside the other compression engines in the sidebar. Four sections: the economics (measured savings), a REAL before→after (dense text vs the rendered PNG page, not a mockup), the fail-closed gate flow, and the enable control wired to /api/settings/compression (preview engine, off by default). Sidebar entry + i18n label across all locales. * chore(compression): consume published omniglyph@^1.0.0 from the npm registry Replaces the local file: dependency used during the preview phase — npm ci now resolves omniglyph from the registry with integrity, unblocking CI. * fix(compression): satisfy v3.8.47 quality gates for the omniglyph engine - dependency-allowlist: approve omniglyph (own package, published from diegosouzapw/OmniGlyph; supply-chain review done by the maintainer) - ladder maps (#6533 guard): rank omniglyph 80 (stackPriority 90, runs after every text engine) with expectedReductionFactor 0.35 (measured 0.23-0.33) - drop the two explicit any casts in omniglyph tests (no-explicit-any is error-level in tests since #6218) * chore(compression): rebaseline strategySelector for the omniglyph mode dispatch +18 lines of cohesive dispatch/type wiring at the existing mode chokepoints (sync no-op + async single-mode branch + providerTransport on the options types) — not extractable without hiding the dispatch boundary, mirroring the prior compression rebaselines. Also drops an unused eslint-disable directive in image-aware-tokens.test.ts (warning-level red under --max-warnings 0). * chore(quality): register inherited base tests in stryker tap.testFiles masked-200-exhaustion-fallback-6427 and headroom-codex-quota-snapshot-6379 arrived via the base merge without their stryker registration — check:mutation-test-coverage --strict requires covering tests to be listed. * refactor(compression): keep omniglyph wiring under the complexity gate - extract the async single-mode resolution to engines/omniglyphSingleMode.ts (runCompressionAsync was at complexity 17 after the mode branch; back <=15) - split OmniglyphContextPageClient into section components (was 161 lines in one function; every function now under the 80-line cap) - complexity baseline 2052->2053: the +1 is inherited base drift (the ratchet does not run on fast-path merges — same pattern as the v3.8.44/46 rebaselines); this PR's own code is measured complexity-net-zero * chore(quality): register 3 more inherited base tests in stryker tap.testFiles route-guard-middleware-local-only, combo-diagnostics-trace and idempotency-fusion-collision arrived via the latest base merge without their stryker registration (fast-path merges skip check:mutation-test-coverage). * chore(quality): cognitive-complexity baseline 883->884 (inherited base drift) check:cognitive-complexity measures 884 identically on the pristine origin/release/v3.8.47 tip and on this HEAD — the PR itself is cognitive-net-zero (single-mode resolution extracted to its own module, page client split into section components). Same inherited-drift pattern as the v3.8.4x release rebaselines. --------- Co-authored-by: diegosouzapw <diegosouzapw@devbox.local>
84 lines
4.3 KiB
TypeScript
84 lines
4.3 KiB
TypeScript
import type { LadderStage } from "./types.ts";
|
||
|
||
/**
|
||
* Default escalation ladder (design D-C2): cheapest/most-lossless → most aggressive.
|
||
* Ordered by the engine catalog's stackPriority. `ccr` and `llmlingua` are intentionally
|
||
* excluded from the AUTOMATIC ladder (ccr = retrieval markers, llmlingua = optional ONNX
|
||
* SLM tier wired through `ultra`); an operator can still add them via ladderOverride.
|
||
*/
|
||
export const DEFAULT_LADDER: LadderStage[] = [
|
||
{ engine: "session-dedup" }, // lossless cross-turn dedup (catalog pri 3)
|
||
{ engine: "rtk", intensity: "standard" }, // command-output filtering (pri 10)
|
||
{ engine: "headroom" }, // tabular JSON compaction (pri 15)
|
||
{ engine: "lite" }, // whitespace/format cleanup (pri 5, but cheap prose pass)
|
||
{ engine: "caveman", intensity: "full" }, // rule-based prose (pri 20)
|
||
{ engine: "aggressive" }, // summarize + age old turns (pri 30)
|
||
{ engine: "ultra" }, // heuristic token pruning + optional SLM (pri 40)
|
||
];
|
||
|
||
/**
|
||
* Aggressiveness rank used to know where a base plan sits so `floor` mode escalates
|
||
* BEYOND it (design §4.2). Keyed by engine id AND by the equivalent CompressionMode name
|
||
* ("standard" === caveman) so a base plan's `mode` string maps cleanly.
|
||
*
|
||
* Rescaled ×10 vs the original 7-entry scale (#6533) to make room for the novel catalog
|
||
* engines that ship in `open-sse/services/compression/engines/index.ts` but are not part
|
||
* of DEFAULT_LADDER: `ccr` and `llmlingua` are intentionally excluded from the AUTOMATIC
|
||
* ladder (see DEFAULT_LADDER doc comment) yet must still rank correctly when an operator
|
||
* adds them via `ladderOverride` — same for `ionizer`, `relevance`, `llm`, and
|
||
* `read-lifecycle`. Placement follows each engine's documented `stackPriority` in
|
||
* `engineCatalog.ts` / its own module header, interpolated onto the existing 7-tier scale
|
||
* (the `lite` exception — ranked after `headroom` despite a lower stackPriority — is a
|
||
* pre-existing, deliberate design call and is left untouched).
|
||
*/
|
||
const AGGRESSIVENESS: Record<string, number> = {
|
||
off: 0,
|
||
"session-dedup": 10, // stackPriority 3 — lossless cross-turn dedup
|
||
ccr: 15, // stackPriority 4 — reversible retrieval marker, only if it shrinks
|
||
rtk: 20, // stackPriority 10 — command-output filtering
|
||
ionizer: 25, // stackPriority 13 — tabular row sampling (lighter than headroom)
|
||
headroom: 30, // stackPriority 15 — tabular JSON compaction
|
||
lite: 40, // pri 5, but cheap prose pass (pre-existing reorder, kept as-is)
|
||
"read-lifecycle": 42, // stackPriority 5 (ties lite) — narrow-scope, opt-in, fully lossy
|
||
relevance: 45, // stackPriority 18 — extractive sentence scoring, opt-in
|
||
caveman: 50,
|
||
standard: 50, // mode-name alias for caveman
|
||
stacked: 50, // a derived/stacked base plan sits at the prose tier; floor escalates past it
|
||
aggressive: 60,
|
||
llmlingua: 65, // stackPriority 35 — semantic pruning (ONNX), after aggressive, before ultra/llm
|
||
llm: 68, // stackPriority 38 — full LLM-tier compressor, opt-in default-off
|
||
ultra: 70,
|
||
omniglyph: 80, // stackPriority 90 — context-as-image (lossy render), runs after every text engine
|
||
};
|
||
|
||
export function aggressivenessOf(engineOrMode: string): number {
|
||
return AGGRESSIVENESS[engineOrMode] ?? 0;
|
||
}
|
||
|
||
/**
|
||
* Cheap per-engine EXPECTED reduction factor (output/input). Used by the default injected
|
||
* estimator to model "apply this stage" WITHOUT a dry-run (design §9: no per-stage dry-run
|
||
* in the hot path). Conservative, monotonic with aggressiveness; never 0 (content preserved).
|
||
*/
|
||
const REDUCTION_FACTOR: Record<string, number> = {
|
||
"session-dedup": 0.95,
|
||
ccr: 0.9, // conservative: only replaces a block when the marker is shorter than it
|
||
rtk: 0.85,
|
||
ionizer: 0.83, // row sampling, lighter than headroom's full tabular compaction
|
||
headroom: 0.8,
|
||
lite: 0.92,
|
||
"read-lifecycle": 0.88, // scope-limited to stale/superseded Read tool-results
|
||
relevance: 0.75, // extractive sentence dropping
|
||
caveman: 0.7,
|
||
standard: 0.7,
|
||
aggressive: 0.55,
|
||
llmlingua: 0.5, // semantic pruning (ONNX)
|
||
llm: 0.45, // full LLM-tier compressor, stronger than llmlingua
|
||
ultra: 0.4,
|
||
omniglyph: 0.35, // measured 0.23-0.33 on converted blocks (254->84 tokens); 0.35 stays conservative
|
||
};
|
||
|
||
export function expectedReductionFactor(engine: string): number {
|
||
return REDUCTION_FACTOR[engine] ?? 0.9;
|
||
}
|