Files
OmniRoute/docs/compression/2026-06-20-unified-compression-config-panel-design.md
Diego Rodrigues de Sa e Souza bfaf459f3c Release v3.8.32 (#4418)
Release v3.8.32 — see CHANGELOG.md [3.8.32] for the full list. Merged via --admin over documented non-blocking checks: CodeQL alerts ratchet (#665 fixed by #4457/#4462, auto-closes on main rescan), Integration Tests (env-flaky batch-upstream), SonarCloud/SonarQube (advisory new-code).
2026-06-21 08:56:51 -03:00

241 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: "Unified Compression Config Panel — Design"
version: 3.8.32
lastUpdated: 2026-06-20
---
# Unified Compression Config Panel — Design
**Status:** approved direction (2026-06-20), pending spec review
**Base branch:** `release/v3.8.31`
**Goal:** Make `/dashboard/context/settings` the single management panel for the master
on/off and each compression engine's on/off + level, deriving the default pipeline from
those toggles. Keep the Combos page solely for *chaining* (ordered named pipelines) +
selecting the globally-active profile, and the per-engine pages solely for *detailed*
config. Plan for (but phase) multiple named profiles with an active selector and a
per-request override header.
---
## 1. Background — current state (the problem)
Compression on/off + level is split across **two stores and several UIs**, with real
duplication:
- **`/api/settings/compression`** (DB `key_value` ns=`compression`, via `src/lib/db/compression.ts`)
holds: `enabled` (master), `defaultMode`, `autoTriggerTokens`, `cavemanConfig`,
`cavemanOutputMode`, `rtkConfig`, `aggressive`, `ultra`, language config, etc.
- **`/api/context/combos/default`** (the *default combo pipeline*) holds the per-engine
`enabled` + config for the **structural** engines (lite, headroom, session-dedup, ccr,
llmlingua, aggressive, ultra) as pipeline steps. The per-engine detail pages
(`EngineConfigPage.tsx`) read/write here via `setEngineInDefaultCombo`.
- **`compression_combos`** table holds *named* pipelines assigned to routing combos.
Concrete duplications (from the UI audit):
- Caveman on/off in **3** places (TokenSaverCard, CompressionSettingsTab, CavemanContextPageClient).
- Caveman intensity in **3**; RTK intensity in **2**; Caveman output mode in **2**.
- `lite/session-dedup/headroom/ccr/llmlingua` on/off **absent** from the central settings —
only on their per-engine page (which writes the *default combo*, not the central config).
So "is engine X on?" is answered inconsistently (central config for caveman/rtk; default
combo for the structural engines), and the **Combos page edits the same default pipeline**
that a central panel would — the conceptual overlap the redesign must remove.
Out of scope as a *config* surface: `dashboard/compression/studio` is the Compression
Studio (waterfall/cockpit analytics), not toggles — untouched.
Engines (the 10 stackable units): `lite, caveman, aggressive, ultra, rtk, headroom,
session-dedup, ccr, llmlingua` (registered `CompressionEngine`s) + `mcpAccessibility`
(separate path: compresses MCP tool-result outputs, not the chat pipeline). Each engine's
`stackPriority` defines automatic ordering (session-dedup 3, ccr 4, lite 5, rtk 10,
headroom 15, caveman 20, aggressive 30, llmlingua 35, ultra 40).
---
## 2. Design principles — the boundary
| Surface | Concept | Owns | Never does |
|---|---|---|---|
| **Panel** (`context/settings`) | "My **Default**: what is on + level" | master on/off; per-engine on/off + level | ordering/chaining; per-route assignment |
| **Combos** (`context/combos`, menu #2) | "Named **profiles**: chaining + which is active + per-route assignment" | create/edit ordered named pipelines; pick the globally-active profile; assign to routing combos | engine on/off (inherits the active profile's membership) |
| **Per-engine pages** (menu, after combos) | "Deep config of one engine" | filters, rules, language packs, thresholds | on/off; level (those live in the panel) |
**No duplication rule:** the **Panel owns the Default profile** (membership + level, order
auto-derived by `stackPriority`). A **Combo is a *named alternative* profile** (membership
+ level + *explicit order*). Different scopes (the one default vs named alternatives) — not
the same object edited twice. The editable "default combo" store is **removed**; the
default pipeline becomes **derived** from the panel.
---
## 3. Architecture
### 3.1 Resolution model (per request, most-specific wins)
```
x-omniroute-compression header (per-request override)
→ routing-combo override (comboOverrides[comboId]) (per-route)
→ active profile (activeComboId: "default" | <comboId>) (global)
→ Default = derived from panel engines map
→ off (master disabled, or zero engines on)
```
A single `resolveCompressionPlan(config, { comboId, header })` produces the effective
`{ mode, stackedPipeline }` fed to the existing `applyCompressionAsync`. It supersedes
today's `getEffectiveMode` (which only does combo-override → autoTrigger → defaultMode).
### 3.2 Data model (Model A — single source + derived pipeline)
**CompressionConfig gains an engines map** (the single source for the Default's on/off +
level), replacing the editable default-combo store:
```ts
interface EngineToggle {
enabled: boolean;
level?: string; // caveman/cavemanOutput: lite|full|ultra ; rtk: minimal|standard|aggressive ; others: undefined
}
interface CompressionConfig {
enabled: boolean; // master
engines: Record<CompressionEngineId, EngineToggle>; // NEW — the Default profile
activeComboId: string | null; // NEW — null/"default" = derived default; else a compression_combos id
autoTriggerTokens: number;
autoTriggerMode?: CompressionMode; // kept (auto-trigger still selects a profile/mode on large prompts)
preserveSystemPrompt: boolean;
comboOverrides: Record<string, CompressionMode>; // existing per-routing-combo override
// detailed per-engine config keeps living in its existing sub-objects
// (cavemanConfig, rtkConfig, aggressive, ultra, …) — edited by the per-engine pages.
}
```
**Deriving the Default pipeline** from `engines` (pure function `deriveDefaultPlan`):
- master `enabled === false``off`.
- 0 engines enabled → `off`.
- exactly 1 enabled and it is a single-mode engine (`lite|caveman|aggressive|ultra|rtk`) →
that mode (single path — reuses today's `applyCompression(mode)`).
- otherwise → `stacked` with the enabled engines in `stackPriority` order, each step's
`intensity` from its `level` (the global `stackedPipeline` already accepts all 9 engines
after the B-PIPELINE-DIVERGENCE fix).
The **stored `defaultMode` field** and the editable default combo
(`/api/context/combos/default`, `setEngineInDefaultCombo`) are **removed**; the default is
derived from `engines`. (The `CompressionMode` *type* persists — `comboOverrides`,
`autoTriggerMode`, and the resolver's output still use it; only the stored `defaultMode`
field is dropped.) A DB migration backfills `engines` from the current `defaultMode` +
default-combo steps + caveman/rtk config so existing installs keep their behavior.
**Named combos** (`compression_combos`, existing table): N ordered pipelines. `activeComboId`
selects which profile is globally active (`Default` or a named combo). Per-routing-combo
assignment stays in `comboOverrides`.
`mcpAccessibility` keeps its own store (`/api/settings/compression/mcp-accessibility`,
migration 056) — surfaced in the panel as a row that writes there, with a scope note.
### 3.3 The per-request header
`x-omniroute-compression: <value>` (mirrors the `x-omniroute-no-memory`/`no-cache` pattern,
PR #4290; parsed in the request pipeline alongside the other omniroute headers). Values:
- `off` → no compression for this request.
- `default` → the derived Default profile.
- `<combo-name|id>` → that named combo.
- `engine:<id>` → a single engine (if that engine is enabled in the Default), e.g. `engine:rtk`.
Invalid/unknown value → ignored (falls through to the normal resolution); never errors the
request. Header parsing + validation has a unit test asserting each form and the
fall-through.
---
## 4. Screens
### 4.1 Panel — `context/settings` (engine grid)
A single client component (replacing the scattered `CompressionSettingsTab` +
`CompressionTokenSaverCard` toggles):
- **Master** on/off at top.
- **Engine grid** (one row per engine, ordered by `stackPriority` so the row order mirrors
run order): `[engine name + short desc] [on/off toggle] [level selector if applicable]
[→ detail page]`. Level selector appears only for engines with levels
(caveman lite|full|ultra, rtk minimal|standard|aggressive; caveman output mode as its own row).
- **General** (auto-trigger tokens, preserve-system-prompt) below the grid.
- Reads/writes the `engines` map + master via `GET/PUT /api/settings/compression` (single
endpoint). The displayed default pipeline (derived) is shown read-only ("runs: rtk →
caveman → …") so the user sees the effect without editing order here.
### 4.2 Combos — `context/combos` (menu #2)
- List of named combos; create/edit an **ordered** pipeline (drag/reorder + per-step level)
— the only place for explicit chaining.
- **Active profile selector**: `Default (panel)` | `<combo>` → writes `activeComboId`.
- Assign a combo to a routing combo (existing `comboOverrides`).
- Reuses the existing `CompressionCombosPageClient` / `comboFlowModel`; the `CompressionHub`
"master mode selector" is removed (mode is now derived; the Hub becomes a read-only
overview or is folded into the panel).
### 4.3 Per-engine pages (menu, after combos)
`EngineConfigPage` + the caveman/rtk custom pages: **lose** the on/off + level controls
(moved to the panel) and keep only **detailed** config (filters, rules, language packs,
thresholds, preview). They **stop writing** `/api/context/combos/default`; detailed config
writes to its own sub-object in `/api/settings/compression` (or the existing
caveman/rtk facade routes, which already proxy to it).
### 4.4 Navigation
`COMPRESSION_CONTEXT_GROUP` (`src/shared/constants/sidebarVisibility.ts`) reordered:
**Settings (panel) → Combos → per-engine pages → Studio (analytics)**.
---
## 5. Consolidation / migration
- `CompressionTokenSaverCard` quick toggles → **absorbed into the panel; the card is removed**.
- Duplicate caveman/rtk on/off + intensity in `CompressionSettingsTab` → removed.
- `EngineConfigPage` → on/off+level removed; stops writing the default combo.
- DB migration: backfill `engines` map + `activeComboId="default"` from current state
(defaultMode + default-combo steps + caveman/rtk/ultra/aggressive enabled), so live
installs preserve behavior. The editable default-combo route (`PUT /api/context/combos/default`)
becomes a **read-only shim for one release** (returns the derived default; rejects writes
with a deprecation note), then is removed.
---
## 6. Phasing
Each phase is its own implementation plan + PR, independently shippable and TDD'd
(Hard Rule #18). `writing-plans` will author **Phase 1 first**; Phases 23 get their own
plans later.
- **Phase 1 (core consolidation):** the `engines` map + `deriveDefaultPlan` + migration;
the engine-grid panel; remove scattered/duplicate toggles; per-engine pages lose on/off;
menu reorder. Delivers the single-panel goal. *No behavior change for existing installs
(migration backfills).*
- **Phase 2 (profiles):** multiple named combos + the `activeComboId` active-profile selector.
- **Phase 3 (header):** the `x-omniroute-compression` per-request override.
Phases 23 reuse the Phase-1 resolution model (`resolveCompressionPlan`), which is built
header/active-aware from the start so later phases only wire UI + header parsing.
---
## 7. Testing
- **Unit:** `deriveDefaultPlan` (every engines-map shape → expected mode/pipeline);
migration backfill (old config → equivalent engines map); `resolveCompressionPlan`
precedence (header > comboOverride > active > default > off); header parsing (each form +
fall-through); panel reducer (toggle/level edits → config patch).
- **Component (vitest):** the panel renders all engines, toggles persist, derived pipeline
preview updates.
- **Integration:** a config with engines `{rtk,caveman}` on → `applyCompressionAsync` runs the
derived stacked pipeline; single engine on → single-mode path; equivalence with the old
defaultMode behavior for the same logical config.
- Both runners green (`test:unit` + `test:vitest`); typecheck:core clean; lint 0 errors.
---
## 8. Non-goals (YAGNI)
- No new compression engines in this work (the model just makes adding them trivial later).
- No change to the engines' internal algorithms (the recent fixes are separate).
- The Compression Studio (analytics) is not restructured.
- Phases 23 UI polish (combo templates, sharing) is out of scope.