31 KiB
title, version, lastUpdated
| title | version | lastUpdated |
|---|---|---|
| Kompresja RTK | 3.8.40 | 2026-06-28 |
Kompresja RTK
Kompresja RTK to silnik kompresji OmniRoute świadomy poleceń, przeznaczony na wyjście terminala i narzędzi. Jest zaprojektowany pod sesje agentów kodujących, w których większość wzrostu kontekstu pochodzi z logów testów, wyjścia builda, szumu menedżerów pakietów, transkryptów shella, wyjścia Dockera, wyjścia gita oraz stack trace'ów.
RTK może działać bezpośrednio z defaultMode: "rtk" albo jako pierwszy krok w potoku stacked, zwykle:
rtk -> caveman
Ta kolejność najpierw kompresuje hałaśliwe wyjście maszynowe, a potem pozwala Cavemanowi skondensować pozostałą prozę.
Upstreamowy RTK raportuje 60-90% oszczędności na wyjściu poleceń. Przykładowa sesja z jego README schodzi z
~118,000 standardowych tokenów do ~23,900 tokenów RTK, czyli 79.7% oszczędności (~80%). OmniRoute używa
tej upstreamowej średniej do kalkulacji oszczędności stacked z kompresją wejścia Cavemana:
RTK average: 80% saved
Caveman input: 46% saved
Stacked: 1 - (1 - 0.80) * (1 - 0.46) = 89.2% saved
Range: 1 - (1 - 0.60..0.90) * (1 - 0.46) = 78.4-94.6%
Co kompresuje
Wbudowany katalog obecnie dostarcza 49 filtrów w tych kategoriach:
| Kategoria | Przykłady |
|---|---|
git |
git status, git branch, git diff, git log |
test |
Vitest, Jest, Pytest, Playwright, Go tests, Cargo tests |
build |
TypeScript, ESLint, Biome, Prettier, Vite, Webpack, Turbo, Nx |
package |
npm install, npm audit, pip, uv sync, Poetry, Bundler |
shell |
ls, find, grep, generyczne logi shella |
docker |
docker ps, logi Dockera |
infra |
Terraform, OpenTofu, systemctl status |
generic |
wyjście JSON, stack trace'y, generyczny fallback wyjścia |
Detektor w open-sse/services/compression/engines/rtk/commandDetector.ts klasyfikuje wyjście
przed wyborem filtra. Filtry mogą też matchować po wzorcu polecenia lub regexie wyjścia, gdy klasa
polecenia nie wystarcza.
Rozwiązywanie filtrów
RTK ładuje filtry w tej kolejności:
- Filtry projektu z
.rtk/filters.tomli.rtk/filters.json, tylko gdy zaufane. - Filtry globalne z
DATA_DIR/rtk/filters.tomliDATA_DIR/rtk/filters.json. - Filtry wbudowane z
open-sse/services/compression/engines/rtk/filters/.
W tym samym zakresie filtry RTK TOML schema v1 mają pierwszeństwo przed filtrami JSON OmniRoute. Wyrażenia TOML
match_command są sprawdzane przed matchowaniem typu polecenia, więc zaimportowany filtr specyficzny dla polecenia
może nadpisać szerszy filtr w tym zakresie. Zakres projektu nadal ma pierwszeństwo przed zakresem globalnym,
niezależnie od formatu pliku.
Filtry projektu są celowo objęte bramką zaufania, bo filtry regex mogą zmienić sposób, w jaki wyjście narzędzi jest pokazywane agentom. Plik filtrów projektu jest akceptowany, gdy spełniony jest jeden z warunków:
rtkConfig.trustProjectFiltersma wartośćtrue.- Ustawiono
OMNIROUTE_RTK_TRUST_PROJECT_FILTERS=1. .rtk/trust.jsonzawiera pasujący hash SHA-256 pliku filtrów projektu.
Przykład pliku trust:
{
"filtersSha256": "0123456789abcdef...",
"filtersTomlSha256": "fedcba9876543210..."
}
Hashe są osobne: filtersSha256 ufa .rtk/filters.json, a filtersTomlSha256
ufa .rtk/filters.toml. Edycja któregokolwiek pliku unieważnia tylko jego własny wpis trust. Pliki globalne
są instalowane przez administratora i używają istniejącego zachowania zaufania filtrów globalnych.
Własne filtry mogą być jednym obiektem filtra albo tablicą obiektów filtrów. Nieprawidłowe własne filtry są
pomijane i raportowane w diagnostyce /api/context/rtk/filters. Nieprawidłowe filtry wbudowane failują od razu.
Zgodność z RTK TOML schema v1
OmniRoute potrafi parsować, walidować, testować i instalować deklaratywne pliki filtrów w RTK TOML schema v1.
Obsługiwane pola to description, match_command, strip_ansi, filter_stderr,
strip_lines_matching, keep_lines_matching, replace, match_output, truncate_lines_at,
head_lines, tail_lines, max_lines, on_empty oraz inline testy [[tests.<filter>]].
Nieznane pola, nieprawidłowe lub niebezpieczne wyrażenia regularne, jednoczesne reguły strip/keep, pliki powyżej
1 MiB oraz odwołania do nieznanych filtrów są odrzucane. Plik, którego inline testy padają, można
zwalidować do podglądu, ale nie da się go zainstalować ani załadować. Błędy ładowania plików custom pozostają
fail-open: nieprawidłowy plik jest pomijany, a pozostałe filtry działają dalej.
OmniRoute otrzymuje wyjście narzędzi dopiero po tym, jak klient je już przechwycił, więc filter_stderr = true
nie może zmienić przechwycenia procesu. Pole jest akceptowane jako no-op, a walidacja zwraca ostrzeżenie.
To jest celowo opisane jako zgodność z RTK TOML schema v1, a nie pełna zgodność
z executablami RTK, hookami shella, implementacjami poleceń w Rust ani układem trust-store.
Zaawansowany widok RTK w dashboardzie przyjmuje wklejony lub wgrany TOML. Walidacja jest tylko do odczytu.
Instalacja zapisuje DATA_DIR/rtk/filters.toml atomowo z restrykcyjnymi uprawnieniami i odświeża
żywy katalog filtrów bez restartu. Zastąpienie istniejącego pliku wymaga jawnego potwierdzenia overwrite
i najpierw tworzy DATA_DIR/rtk/filters.toml.bak.
DSL filtrów
Filtry używają schematu JSON opisanego w Compression Rules Format. Runtime stosuje te etapy w kolejności:
stripAnsi -> filterStderr -> replace -> matchOutput -> drop/include lines
-> truncateLineAt -> head/tail/maxLines -> onEmpty
Ważne pola:
| Pole | Przeznaczenie |
|---|---|
rules.stripAnsi |
Usuwa sekwencje kolorów/kontroli terminala przed matchowaniem |
rules.filterStderr |
Normalizuje typowe prefiksy stderr przed matchowaniem/filtrowaniem |
rules.replace |
Stosuje uporządkowane zamiany regex |
rules.matchOutput |
Zwraca zwięzłe podsumowanie, gdy wyjście pasuje do znanego warunku |
rules.matchOutput[].unless |
Pomija skrót, gdy obecny jest wzorzec błędu/porażki |
rules.dropPatterns |
Usuwa hałaśliwe linie |
rules.includePatterns |
Preferuje linie możliwe do działania |
rules.collapsePatterns |
Zwija powtarzające się pasujące linie |
rules.deduplicate |
Per-filter opt-in: zwija kolejne zduplikowane linie |
rules.truncateLineAt |
Bezpieczne dla Unicode obcinanie per linia |
rules.onEmpty |
Komunikat fallback, gdy wszystkie linie zostaną odfiltrowane |
tests[] |
Inline sample'e używane przez verify gate |
Od filtrów wbudowanych oczekuje się inline sample'i tests[]. Własne filtry też powinny je zawierać,
zwłaszcza gdy są współdzielone między projektami.
Deduplikacja linii (dwie warstwy)
RTK zwija zduplikowane linie na dwóch niezależnych warstwach:
- Per-filter
deduplicate(opt-in, domyślniefalse). Filtr może ustawićrules.deduplicate: true, aby zwinąć kolejne zduplikowane linie wewnątrz dopasowanego wyjścia tego filtra, przed obcięciem. Działa to wewnątrzlineFilter.ts. Dla legacy filtrów jest włączane automatycznie, gdy filtr definiujecollapsePatterns. Schemat:deduplicate: z.boolean().default(false)wopen-sse/services/compression/engines/rtk/filterSchema.ts. - Engine-wide
deduplicateThreshold(domyślnie3). Po uruchomieniu wszystkich filtrów silnik zwija każdą serię>= deduplicateThresholdidentycznych kolejnych linii w całym wyniku (deduplicateRepeatedLines, stosowane wengines/rtk/index.ts). Wartość jest ograniczona do 2–100 przy normalizacji.
Pass per filtr działa najpierw (wewnątrz filtra), pass w skali silnika na końcu (na połączonym wyjściu), więc obie warstwy składają się bez podwójnego liczenia.
Grupowanie linii (enableGrouping)
Gdy rtkConfig.enableGrouping ma wartość true (domyślnie false), RTK uruchamia dodatkowy pass groupSimilarLines
na wyniku po deduplikacji, który zwija serie blisko równoważnych (nie identycznych bajtowo)
kolejnych linii. rtkConfig.groupingThreshold (domyślnie 3) to minimalna długość serii uruchamiająca
grupowanie. To strukturalny odpowiednik deduplicateThreshold: dedup obsługuje dokładne powtórzenia,
grupowanie obsługuje „ten sam kształt z małymi różnicami". Oba flagi są częścią JSON rtkConfig
persystowanego w tabeli key_value (zob. Konfiguracja wyżej), więc ustawienie przetrwa restarty.
Usuwanie komentarzy w kodzie (stripCodeComments / preserveDocstrings)
Gdy włączone jest rtkConfig.applyToCodeBlocks, RTK może też usuwać komentarze z fenced code blocks:
stripCodeComments(domyślniefalse) — opt-in. Gdytrue, RTK usuwa komentarze z fenced blocks JavaScript i TypeScript. Flaga historycznie była odczytywana, ale nigdy nie stosowana, więc domyślnie pozostaje „preserve", by uniknąć cichej zmiany produkcyjnej.preserveDocstrings(domyślnietrue) — przy usuwaniu komentarzy bloki JSDoc//** … */są zachowywane (niosą dokumentację API wartą więcej niż kosztowane bajty). Ustawfalse, aby usuwać także je.
Usuwanie komentarzy jest zaimplementowane w open-sse/services/compression/engines/rtk/codeStripper.ts. Używa
parsera TypeScript (nie regexa), więc literały string, template i regex nigdy nie są mylone
z komentarzami, a przy wykryciu JSX całkowicie się wycofuje (więc komentarze w expression-container JSX nie są
nigdy psute). Usuwanie komentarzy dotyczy obecnie tylko JavaScript i TypeScript — inne
języki w zbiorze CodeLanguage strippera (Python, Rust, Go, Ruby, Java) mają zwijanie pustych linii i
białych znaków, ale bez usuwania komentarzy. Przebieg stripped-block jest tagowany rtk:code-strip w
rulesApplied.
Uwaga — GCF / tabular encoding to osobny silnik. RTK nie zawiera tabularnego/kolumnowego enkodera JSON „GCF" (Graph Compact Format). Ten enkoder — który zastąpił starszy enkoder
omni-tabular— żyje w silniku headroom (open-sse/services/compression/engines/headroom/, z vendored codec podheadroom/gcf/). Nie jest związany z potokiem filtrów RTK opisanym tutaj.
Konfiguracja
Ustawienia globalne są dostępne przez /api/settings/compression. Ustawienia specyficzne dla RTK są też
dostępne przez /api/context/rtk/config.
{
"defaultMode": "stacked",
"autoTriggerMode": "stacked",
"autoTriggerTokens": 32000,
"stackedPipeline": [
{ "engine": "rtk", "intensity": "standard" },
{ "engine": "caveman", "intensity": "full" }
],
"rtkConfig": {
"enabled": true,
"intensity": "standard",
"applyToToolResults": true,
"applyToCodeBlocks": false,
"applyToAssistantMessages": false,
"enabledFilters": [],
"disabledFilters": [],
"maxLinesPerResult": 120,
"maxCharsPerResult": 12000,
"deduplicateThreshold": 3,
"customFiltersEnabled": true,
"trustProjectFilters": false,
"rawOutputRetention": "never",
"rawOutputMaxBytes": 1048576,
"enableGrouping": false,
"groupingThreshold": 3,
"stripCodeComments": false,
"preserveDocstrings": true
}
}
enabledFilters i disabledFilters używają id filtrów, na przykład test-vitest lub git-diff.
Pełny kształt rtkConfig definiują RtkConfig / DEFAULT_RTK_CONFIG w
open-sse/services/compression/types.ts. Cały obiekt jest persystowany jako pojedyncza wartość JSON w
tabeli SQLite key_value pod namespace = "compression", key = "rtkConfig"
(src/lib/db/compression.ts) i normalizowany przy odczycie przez normalizeRtkConfig. Zatem każde pole poniżej
— w tym enableGrouping, groupingThreshold, stripCodeComments i preserveDocstrings —
przechodzi round-trip przez ten sam store i przetrwa restart.
| Klucz | Domyślnie | Przeznaczenie |
|---|---|---|
deduplicateThreshold |
3 |
W skali silnika: min. kolejnych identycznych linii do zwinięcia (ograniczone 2–100) |
enableGrouping |
false |
Opt-in: zwijaj serie blisko równoważnych kolejnych linii |
groupingThreshold |
3 |
Min. seria podobnych linii uruchamiająca grupowanie |
stripCodeComments |
false |
Opt-in: usuwaj komentarze z fenced code blocks (wymaga applyToCodeBlocks) |
preserveDocstrings |
true |
Przy usuwaniu komentarzy zachowuj bloki JSDoc//** … */ |
API
| Trasa | Metoda | Przeznaczenie |
|---|---|---|
/api/context/rtk/config |
GET | Odczyt konfiguracji RTK |
/api/context/rtk/config |
PUT | Aktualizacja konfiguracji RTK |
/api/context/rtk/filters |
GET | Lista katalogu filtrów i diagnostyki ładowania |
/api/context/rtk/import |
POST | Walidacja lub instalacja plików RTK TOML schema v1 |
/api/context/rtk/test |
POST | Podgląd kompresji RTK dla jednego payloadu tekstu |
/api/context/rtk/raw-output/[id] |
GET | Odczyt zachowanego zredagowanego surowego wyjścia |
/api/compression/preview |
POST | Podgląd dowolnego trybu kompresji |
Payload testu RTK:
{
"command": "npm test",
"text": "FAIL tests/example.test.ts\nAssertionError: expected true\nTest Files 1 failed",
"config": {
"intensity": "standard"
}
}
Payload podglądu kompresji:
{
"mode": "stacked",
"messages": [
{
"role": "tool",
"content": "FAIL tests/example.test.ts\nAssertionError: expected true\nTest Files 1 failed"
}
],
"config": {
"rtkConfig": {
"rawOutputRetention": "failures"
}
}
}
Trasy management wymagają dashboard management auth albo pasującej polityki klucza API.
Payload walidacji RTK TOML:
{
"action": "validate",
"content": "schema_version = 1\n\n[filters.my-tool]\nmatch_command = \"^my-tool\\\\b\"\nmax_lines = 20\n"
}
Użyj "action": "install", aby zainstalować zwalidowany plik globalnie. Dodaj "overwrite": true tylko
po przejrzeniu i potwierdzeniu zastąpienia istniejącego pliku globalnego.
Odzyskiwanie surowego wyjścia
RTK normalnie zwraca tylko skompresowany tekst. Do debugowania rawOutputRetention może zachować zredagowane
surowe wyjście:
| Wartość | Zachowanie |
|---|---|
never |
Nie zachowuj surowego wyjścia |
failures |
Zachowuj tylko prawdopodobne wyjście porażki |
always |
Zachowuj każde skompresowane surowe wyjście RTK, po redakcji |
Zachowane pliki są zapisywane pod:
DATA_DIR/rtk/raw-output/
Sekrety są redagowane przed persystencją, w tym typowe bearer tokeny, klucze API, tokeny Slack,
klucze dostępu AWS oraz wartości w stylu przypisania token=..., secret=..., password=.... Analityka
przechowuje tylko pointer id, rozmiar i metadane hasha.
Verify Gate
Skupiony verify gate uruchamia wbudowane inline testy filtrów bez odpalania zewnętrznych poleceń:
node --import tsx/esm --test tests/unit/compression/rtk-verify.test.ts
Szerszy gate RTK to:
node --import tsx/esm --test \
tests/unit/compression/rtk-*.test.ts \
tests/unit/compression/pipeline-integration.test.ts \
tests/unit/compression/context-compression-api.test.ts
Przed releasem uruchom szeroki gate kompresji:
node --import tsx/esm --test \
tests/unit/compression/*.test.ts \
tests/golden-set/*.test.ts \
tests/integration/compression-pipeline.test.ts \
tests/unit/api/compression/compression-api.test.ts
Rozszerzanie RTK
- Dodaj lub zaktualizuj plik JSON filtra.
- Dołącz co najmniej jeden sample
tests[], który udowadnia istotne zachowanie. - Dodaj fixture pod
tests/unit/compression/fixtures/rtk/dla nowych rodzin poleceń. - Dodaj pokrycie detekcji poleceń przy wprowadzaniu nowej klasy wyjścia.
- Uruchom verify i szerokie gate'y RTK.
- Jeśli filtr jest lokalny dla projektu, commitnij
.rtk/filters.jsoni odśwież.rtk/trust.jsondopiero po review.
Poziomy intensywności (v3.8.16+)
RTK wspiera 3 poziomy intensywności, które balansują między agresywnością kompresji a bezpieczeństwem. Poziom
ustawia się przez config.intensity w konfiguracji silnika.
3 poziomy
| Poziom | Próg obcinania | Oszczędność tokenów | Ryzyko | Najlepsze do |
|---|---|---|---|---|
minimal |
24 linii na sekcję | ~20-40% | Bardzo niskie | Produkcja z krytycznym kontekstem |
standard (default) |
24 linii na sekcję | ~50-70% | Niskie | Codzienne sesje kodowania |
aggressive |
16 linii na sekcję | ~70-90% | Średnie | Długie sesje, max oszczędności |
Gdzie następuje obcinanie
Próg obcinania wpływa na lineFilter.ts:
// From open-sse/services/compression/engines/rtk/index.ts:329-330
config.intensity === "aggressive" ? 16 : 24,
config.intensity === "aggressive" ? 16 : 24,
Zachowywane są zarówno head, jak i tail każdej sekcji; środkowa treść jest usuwana, gdy rusza obcinanie.
Co zostaje, a co jest wycinane
| Treść | minimal | standard | aggressive |
|---|---|---|---|
| Błędy / stack trace'y | ✅ zachowane | ✅ zachowane | ✅ zachowane |
| Porażki testów | ✅ zachowane | ✅ zachowane | ✅ zachowane |
| Błędy builda | ✅ zachowane | ✅ zachowane | ✅ zachowane |
| Przejścia testów (verbose) | ✅ zachowane | 🟡 zwinięte | 🟡 zwinięte |
| Rutynowe wyjście (info) | 🟡 zwinięte | 🟡 zwinięte | ❌ usunięte |
| Paski postępu | 🟡 zwinięte | ❌ usunięte | ❌ usunięte |
| Banner / ASCII art | 🟡 zwinięte | ❌ usunięte | ❌ usunięte |
Wybór właściwej intensywności
Is losing context catastrophic?
│
┌───────────┼───────────┐
│ │ │
YES NO NOT SURE
│ │ │
▼ │ │
minimal │ │
│ │ │
│ ▼ ▼
│ How critical Try `standard` first
│ is throughput? (works for 80% of
│ │ cases)
│ ┌────┴────┐
│ │ │
│ LOW HIGH
│ │ │
│ ▼ ▼
│ standard aggressive
│ │ │
└──────┴─────────┘
Konfiguracja intensywności
Per-combo (w konfiguracji combo):
{
"combo": "my-coding-combo",
"routing": {/* ... */},
"compression": {
"engine": "rtk",
"intensity": "aggressive"
}
}
Programatycznie:
rtkEngine (@omniroute/open-sse/services/compression/engines/rtk) jest
CompressionEngine i nie ma metody updateConfig. Aktualizuj konfigurację silnika
przez helper rejestru:
import { updateEngineConfig } from "@omniroute/open-sse/services/compression/engines/registry";
updateEngineConfig("rtk", { intensity: "aggressive" });
Weryfikacja efektu
Użyj Verify Gate (zob. niżej), aby potwierdzić, że filtr jest bezpieczny przy wybranej intensywności:
import { runRtkFilterTests } from "omniroute/compression/engines/rtk/verify";
const result = runRtkFilterTests({ intensity: "aggressive" });
if (!result.passed) {
console.error("Filters failed at aggressive intensity");
}
Tworzenie własnych filtrów (v3.8.16+)
Katalog engines/rtk/filters/ zawiera 49+ wbudowanych plików JSON filtrów. Możesz dodać własne, aby kompresować
wyjście z custom tools nieobjętych domyślnymi.
Schemat filtra (Zod)
{
"id": "string", // Required. Filter identifier (kebab-case, e.g., "python-traceback")
"label": "string", // Required. Human-readable filter name
"description": "string", // Optional (default: ""). Short description of what filter does
"category": "git|test|build|shell|docker|package|infra|cloud|generic",
"priority": number, // Optional (0-100, default: 50). Execution order (higher = first)
"match": {
"commands": ["string"], // Command names to match (e.g., "python", "pytest")
"patterns": ["string"], // Regex patterns to match output
"outputTypes": ["string"] // Detected output classes (e.g., "test-failure")
},
"rules": {
"stripAnsi": boolean, // Optional (default: false). Strip ANSI color codes
"replace": [ // Find-and-replace rules (default: [])
{ "pattern": "regex", "replacement": "..." }
],
"matchOutput": [ // Short-circuit on pattern match (default: [])
{
"pattern": "regex",
"message": "short summary",
"unless": "regex" // Skip if this pattern matches
}
],
"includePatterns": ["string"], // Lines to keep (regex patterns, default: [])
"dropPatterns": ["string"], // Lines to drop (regex patterns, default: [])
"collapsePatterns": ["string"], // Lines to collapse to single occurrence (default: [])
"deduplicate": boolean, // Optional (default: false). Remove duplicate lines
"truncateLineAt": number, // Optional (default: 0). Truncate lines to max chars
"maxLines": number, // Optional (default: 0). Hard cap on total lines
"headLines": number, // Optional (default: 20). Keep first N lines of matched output
"tailLines": number, // Optional (default: 20). Keep last N lines of matched output
"onEmpty": "string", // Optional (default: ""). Fallback message if all lines filtered
"filterStderr": boolean // Optional (default: false). Also filter stderr output
},
"preserve": {
"errorPatterns": ["string"], // Patterns that must always be preserved (default: [])
"summaryPatterns": ["string"] // Patterns for final summary line (default: [])
},
"tests": [ // Inline tests for verification (default: [])
{
"name": "string", // Required. Test name
"input": "sample output", // Required. Sample input text
"expected": "expected output", // Required. Expected compressed output
"command": "optional command" // Optional. Command context
}
]
}
Przykład: filtr Python Traceback
{
"id": "python-traceback",
"label": "Python Traceback Filter",
"description": "Compresses Python tracebacks to essential file/line locations and error type",
"category": "test",
"priority": 60,
"match": {
"commands": ["python", "python3", "pytest", "uv", "poetry"],
"patterns": ["Traceback \\(most recent call last\\)", "Error", "Exception"],
"outputTypes": ["error-traceback"]
},
"rules": {
"stripAnsi": true,
"includePatterns": [
"Traceback \\(most recent call last\\)",
"^\\s*File \".+\", line \\d+",
"^\\s*[A-Z][a-zA-Z]+Error:",
"^\\s*[A-Z][a-zA-Z]+Exception"
],
"dropPatterns": ["site-packages/", "^\\s+[a-z_]+\\([^)]*\\)$"],
"headLines": 5,
"tailLines": 3,
"maxLines": 25,
"filterStderr": true
},
"preserve": {
"errorPatterns": ["Error:", "Exception:", "Traceback"],
"summaryPatterns": ["^[A-Z][a-zA-Z]+(?:Error|Exception):"]
},
"tests": [
{
"name": "preserves-error-type-and-location",
"input": "Traceback (most recent call last):\n File \"app.py\", line 42, in main\n do_thing()\n File \"lib/utils.py\", line 17, in helper\n return 1 / 0\nZeroDivisionError: division by zero",
"expected": "Traceback (most recent call last):\n File \"app.py\", line 42, in main\n File \"lib/utils.py\", line 17, in helper\nZeroDivisionError: division by zero",
"command": "python app.py"
}
]
}
Ładowanie własnych filtrów
Umieść plik w rozpoznawanej lokalizacji:
~/.omniroute/rtk/filters/my-filter.json # User-level
<project>/.rtk/filters/my-filter.json # Project-level
Filtry są ładowane automatycznie przy starcie przez loadRtkFilters() w open-sse/services/compression/engines/rtk/filterLoader.ts. Loader odkrywa filtry z:
- Katalog wbudowany:
open-sse/services/compression/engines/rtk/filters/ - Katalog użytkownika:
~/.omniroute/rtk/filters/ - Katalog projektu:
<project>/.rtk/filters/
Aby ładować filtry programatycznie:
import { loadRtkFilters } from "@omniroute/open-sse/services/compression/engines/rtk/filterLoader";
// Options: customFiltersEnabled (load user/project filters, default on),
// trustProjectFilters, refresh.
const filters = loadRtkFilters({ customFiltersEnabled: true });
Walidacja
Filtry są walidowane względem schematu Zod przy ładowaniu. Filtr ze złą strukturą nie załaduje się i zaloguje błąd:
RTK_FILTER_LOADER: filter "my-filter" failed validation:
- rules.replace.0.pattern: Invalid regex
- match.commands: must not be empty
Aby zwalidować wszystkie zainstalowane filtry, wywołaj runRtkFilterTests(), eksportowane z open-sse/services/compression/engines/rtk/verify.ts.
Dobre praktyki
- Zawsze dołączaj
tests[]— udowadniają, że filtr działa, i chronią przed regresjami - Używaj
matchOutputdo short-circuitów — jeśli jedna linia mówi całą historię, zastąp cały blok - Preferuj
keepzamiaststrip— jawne reguły „zawsze zachowaj" są bezpieczniejsze niż „zawsze usuń" - Testuj na wszystkich 3 poziomach intensywności —
minimalpowinno być no-op,aggressivenadal powinno zachowywać błędy - Używaj pola
unless— chroń short-circuity regułą „nie odpalaj, jeśli X jest obecne"
Odzyskiwanie surowego wyjścia i Verify Gate
Gdy RTK kompresuje wyjście agresywnie, możesz odzyskać oryginalny tekst do debugowania, audytu lub replay.
Jak działa odzyskiwanie surowego wyjścia
Original output (10K tokens)
│
▼
RTK compress (with rawOutput.enabled=true)
│
├─▶ Compressed output (2K tokens) ──▶ to LLM
│
└─▶ Original output (10K tokens) ──▶ stored in DB
(linked by request_id)
Włączanie przechowywania surowego wyjścia
Per-request (w konfiguracji combo):
{
"compression": {
"engine": "rtk",
"intensity": "aggressive",
"rawOutput": {
"enabled": true,
"maxBytes": 1048576 // 1MB cap
}
}
}
Domyślnie: rawOutput.enabled: false (oszczędza storage).
Koszt storage
| Na request | Limit 1MB | Limit 10MB |
|---|---|---|
| Średnie skompresowane wyjście | ~5KB | ~5KB |
| Przechowywane surowe wyjście | ~50-500KB | ~500KB-5MB |
| Przy 1000 requestów/dzień | 50-500MB/dzień | 500MB-5GB/dzień |
Rekomendacja: Włączaj surowe wyjście tylko dla sesji debugowania lub próbkowanego audytu, nie always-on.
Odzyskiwanie oryginału
import { readRtkRawOutput } from "omniroute/compression/engines/rtk/rawOutput";
const raw = readRtkRawOutput(pointerId); // pointerId from compression stats
if (raw) {
console.log("Original output:", raw);
}
pointerId jest zwracany w CompressionStats.rtkRawOutputPointers[] po kompresji.
Zobacz open-sse/services/compression/engines/rtk/rawOutput.ts:102 dla sygnatury funkcji.
Verify Gate
RTK Filter Verification (open-sse/services/compression/engines/rtk/verify.ts) waliduje wszystkie filtry względem ich tests[] i zapewnia poprawne zachowanie na wszystkich 3 poziomach intensywności.
Wywołaj runRtkFilterTests(), aby uruchomić weryfikację:
import { runRtkFilterTests } from "open-sse/services/compression/engines/rtk/verify";
const result = runRtkFilterTests();
console.log(`Passed: ${result.outcomes.filter((o) => o.passed).length}`);
console.log(`Failed: ${result.outcomes.filter((o) => !o.passed).length}`);
if (!result.passed) {
console.error("Filters failed verification");
result.outcomes
.filter((o) => !o.passed)
.forEach((o) => {
console.error(
` - ${o.filterId} / ${o.testName}: expected "${o.expected}", got "${o.actual}"`
);
});
}
Co waliduje:
- Każdy filtr ładuje się i przechodzi walidację schematu
- Każdy wpis
tests[]produkuje oczekiwane wyjście - Intensywność
minimaljest no-op (zachowuje oryginał, stosuje tylko filtry strukturalne) - Intensywność
aggressivezachowuje błędy, porażki testów i stack trace'y - Skompresowane wyjście nigdy nie jest większe niż oryginalne wejście
-
Źródło:
open-sse/services/compression/engines/rtk/(63 files, ~70KB) -
Przed merge'em zmiany filtra — zawsze upewnij się, że testy przechodzą
-
Po upgrade silnika RTK — schemat mógł się zmienić
-
Okresowo w monitoringu — chroni przed dryfem fixture'ów testowych
-
Przy dodawaniu nowej rodziny tool/command — udowadnia, że nowy filtr działa
Zobacz też
- COMPRESSION_GUIDE.md — Pełny przegląd potoku kompresji
- COMPRESSION_ENGINES.md — Rejestr silników i wbudowane silniki
- EXTENDING_COMPRESSION.md — Własne silniki, language packi, potoki stacked
- Źródło:
open-sse/services/compression/engines/rtk/(63 files, ~70KB)