chopratejas commited on
Commit
81cb88d
·
1 Parent(s): 6505c43

Rewrite README + add Integration Guide

Browse files

README: 694 → 203 lines. Crisp, scannable, links to docs.
- compress() as the hero quickstart (not proxy)
- Integration table: compress(), LiteLLM, ASGI, proxy, Agno, LangChain
- LangChain marked as experimental
- "Already have a proxy?" callout linking to Integration Guide
- Architecture: ContentRouter (not SmartCrusher) as the primary compressor

New: docs/integration-guide.md
- Detailed setup for every integration path
- compress() with Anthropic, OpenAI, LiteLLM, raw HTTP
- LiteLLM callback + LiteLLM proxy ASGI middleware
- ASGI middleware for any FastAPI/Starlette app
- Compression hooks for advanced customization
- FAQ section

Fix: compress() uses default pipeline (CacheAligner + ContentRouter +
IntelligentContext) instead of manually specifying SmartCrusher.

Files changed (3) hide show
  1. README.md +92 -499
  2. docs/integration-guide.md +292 -0
  3. headroom/compress.py +8 -12
README.md CHANGED
@@ -29,7 +29,6 @@
29
  </a>
30
  </p>
31
 
32
-
33
  ---
34
 
35
  ## Demo
@@ -40,570 +39,164 @@
40
 
41
  ---
42
 
43
- ## Does It Actually Work? A Real Test
44
-
45
- **The setup:** 100 production log entries. One critical error buried at position 67.
46
-
47
- <details>
48
- <summary><b>BEFORE:</b> 100 log entries (18,952 chars) - click to expand</summary>
49
 
50
- ```json
51
- [
52
- {"timestamp": "2024-12-15T00:00:00Z", "level": "INFO", "service": "api-gateway", "message": "Request processed successfully - latency=50ms", "request_id": "req-000000", "status_code": 200},
53
- {"timestamp": "2024-12-15T01:01:00Z", "level": "INFO", "service": "user-service", "message": "Request processed successfully - latency=51ms", "request_id": "req-000001", "status_code": 200},
54
- {"timestamp": "2024-12-15T02:02:00Z", "level": "INFO", "service": "inventory", "message": "Request processed successfully - latency=52ms", "request_id": "req-000002", "status_code": 200},
55
- // ... 64 more INFO entries ...
56
- {"timestamp": "2024-12-15T03:47:23Z", "level": "FATAL", "service": "payment-gateway", "message": "Connection pool exhausted", "error_code": "PG-5523", "resolution": "Increase max_connections to 500 in config/database.yml", "affected_transactions": 1847},
57
- // ... 32 more INFO entries ...
58
- ]
59
- ```
60
- </details>
61
-
62
- **AFTER:** Headroom compresses to 6 entries (1,155 chars):
63
-
64
- ```json
65
- [
66
- {"timestamp": "2024-12-15T00:00:00Z", "level": "INFO", "service": "api-gateway", ...},
67
- {"timestamp": "2024-12-15T01:01:00Z", "level": "INFO", "service": "user-service", ...},
68
- {"timestamp": "2024-12-15T02:02:00Z", "level": "INFO", "service": "inventory", ...},
69
- {"timestamp": "2024-12-15T03:47:23Z", "level": "FATAL", "service": "payment-gateway", "error_code": "PG-5523", "resolution": "Increase max_connections to 500 in config/database.yml", "affected_transactions": 1847},
70
- {"timestamp": "2024-12-15T02:38:00Z", "level": "INFO", "service": "inventory", ...},
71
- {"timestamp": "2024-12-15T03:39:00Z", "level": "INFO", "service": "auth", ...}
72
- ]
73
  ```
74
 
75
- **What happened:** First 3 items + the FATAL error + last 2 items. The critical error at position 67 was automatically preserved.
76
-
77
- ---
78
-
79
- **The question we asked Claude:** "What caused the outage? What's the error code? What's the fix?"
80
-
81
- | | Baseline | Headroom |
82
- |--|----------|----------|
83
- | Input tokens | 10,144 | 1,260 |
84
- | Correct answers | **4/4** | **4/4** |
85
-
86
- Both responses: *"payment-gateway service, error PG-5523, fix: Increase max_connections to 500, 1,847 transactions affected"*
87
-
88
- **87.6% fewer tokens. Same answer.**
89
-
90
- Run it yourself: `python examples/needle_in_haystack_test.py`
91
-
92
- ---
93
-
94
- ## Accuracy Benchmarks
95
-
96
- > **Headroom's guarantee: compress without losing accuracy.**
97
-
98
- We validate against established open-source benchmarks. Full methodology and reproducible tests: [Benchmarks Documentation](https://chopratejas.github.io/headroom/benchmarks/)
99
-
100
- | Benchmark | Metric | Result | Status |
101
- |-----------|--------|--------|--------|
102
- | [Scrapinghub Article Extraction](https://huggingface.co/datasets/allenai/scrapinghub-article-extraction-benchmark) | F1 Score | **0.919** (baseline: 0.958) | :white_check_mark: |
103
- | [Scrapinghub Article Extraction](https://huggingface.co/datasets/allenai/scrapinghub-article-extraction-benchmark) | Recall | **98.2%** | :white_check_mark: |
104
- | [Scrapinghub Article Extraction](https://huggingface.co/datasets/allenai/scrapinghub-article-extraction-benchmark) | Compression | **94.9%** | :white_check_mark: |
105
- | SmartCrusher (JSON) | Accuracy | **100%** (4/4 correct) | :white_check_mark: |
106
- | SmartCrusher (JSON) | Compression | **87.6%** | :white_check_mark: |
107
- | Multi-Tool Agent | Accuracy | **100%** (all findings) | :white_check_mark: |
108
- | Multi-Tool Agent | Compression | **76.3%** | :white_check_mark: |
109
-
110
- **Why recall matters most**: For LLM applications, capturing all relevant information is critical. 98.2% recall means nearly all content is preserved — LLMs can answer questions accurately from compressed context.
111
-
112
- <details>
113
- <summary><b>Run benchmarks yourself</b></summary>
114
 
115
- ```bash
116
- # Install with benchmark dependencies
117
- pip install "headroom-ai[evals,html]" datasets
 
118
 
119
- # Run HTML extraction benchmark (no API key needed)
120
- pytest tests/test_evals/test_html_oss_benchmarks.py::TestExtractionBenchmark -v -s
 
 
121
 
122
- # Run QA accuracy tests (requires OPENAI_API_KEY)
123
- pytest tests/test_evals/test_html_oss_benchmarks.py::TestQAAccuracyPreservation -v -s
124
  ```
125
 
126
- </details>
127
 
128
  ---
129
 
130
- ## Multi-Tool Agent Test: Real Function Calling
131
-
132
- **The setup:** An Agno agent with 4 tools (GitHub Issues, ArXiv Papers, Code Search, Database Logs) investigating a memory leak. Total tool output: 62,323 chars (~15,580 tokens).
133
-
134
- ```python
135
- from agno.agent import Agent
136
- from agno.models.anthropic import Claude
137
- from headroom.integrations.agno import HeadroomAgnoModel
138
-
139
- # Wrap your model - that's it!
140
- base_model = Claude(id="claude-sonnet-4-20250514")
141
- model = HeadroomAgnoModel(wrapped_model=base_model)
142
-
143
- agent = Agent(model=model, tools=[search_github, search_arxiv, search_code, query_db])
144
- response = agent.run("Investigate the memory leak and recommend a fix")
145
- ```
146
-
147
- **Results with Claude Sonnet:**
148
-
149
- | | Baseline | Headroom |
150
- |--|----------|----------|
151
- | Tokens sent to API | 15,662 | 6,100 |
152
- | API requests | 2 | 2 |
153
- | Tool calls | 4 | 4 |
154
- | Duration | 26.5s | 27.0s |
155
 
156
- **76.3% fewer tokens. Same comprehensive answer.**
157
 
158
- Both found: Issue #42 (memory leak), the `cleanup_worker()` fix, OutOfMemoryError logs (7.8GB/8GB, 847 threads), and relevant research papers.
 
 
 
 
 
 
 
159
 
160
- Run it yourself: `python examples/multi_tool_agent_test.py`
161
 
162
  ---
163
 
164
  ## How It Works
165
 
166
- > Headroom optimizes LLM context *before* it hits the provider —
167
- > without changing your agent logic or tools.
168
-
169
- ```mermaid
170
- flowchart LR
171
- User["Your App"]
172
- Entry["Headroom"]
173
- Transform["Context<br/>Optimization"]
174
- LLM["LLM Provider"]
175
- Response["Response"]
176
-
177
- User --> Entry --> Transform --> LLM --> Response
178
  ```
179
-
180
- ### Inside Headroom
181
-
182
- ```mermaid
183
- flowchart TB
184
-
185
- subgraph Pipeline["Transform Pipeline"]
186
- CA["Cache Aligner<br/><i>Stabilizes dynamic tokens</i>"]
187
- SC["Smart Crusher<br/><i>Removes redundant tool output</i>"]
188
- CM["Intelligent Context<br/><i>Score-based token fitting</i>"]
189
- CA --> SC --> CM
190
- end
191
-
192
- subgraph CCR["CCR: Compress-Cache-Retrieve"]
193
- Store[("Compressed<br/>Store")]
194
- Tool["Retrieve Tool"]
195
- Tool <--> Store
196
- end
197
-
198
- LLM["LLM Provider"]
199
-
200
- CM --> LLM
201
- SC -. "Stores originals" .-> Store
202
- LLM -. "Requests full context<br/>if needed" .-> Tool
203
  ```
204
 
205
- > Headroom never throws data away.
206
- > It compresses aggressively and retrieves precisely.
207
-
208
- ### What actually happens
209
-
210
- 1. **Headroom intercepts context** — Tool outputs, logs, search results, and intermediate agent steps.
211
-
212
- 2. **Dynamic content is stabilized** — Timestamps, UUIDs, request IDs are normalized so prompts cache cleanly.
213
-
214
- 3. **Low-signal content is removed** — Repetitive or redundant data is crushed, not truncated.
215
-
216
- 4. **Original data is preserved** — Full content is stored separately and retrieved *only if the LLM asks*.
217
-
218
- 5. **Provider caches finally work** — Headroom aligns prompts so OpenAI, Anthropic, and Google caches actually hit.
219
-
220
- For deep technical details, see [Architecture Documentation](docs/ARCHITECTURE.md).
221
 
222
  ---
223
 
224
- ## Why Headroom?
225
-
226
- - **Zero code changes** - works as a transparent proxy
227
- - **47-92% savings** - depends on your workload (tool-heavy = more savings)
228
- - **Image compression** - 40-90% reduction via trained ML router (OpenAI, Anthropic, Google)
229
- - **Reversible compression** - LLM retrieves original data via CCR
230
- - **Content-aware** - code, logs, JSON, images each handled optimally
231
- - **Provider caching** - automatic prefix optimization for cache hits
232
- - **Framework native** - LangChain, Agno, MCP, agents supported
233
-
234
- ---
235
-
236
- ## 30-Second Quickstart
237
-
238
- ### Option 1: Proxy (Zero Code Changes)
239
-
240
- ```bash
241
- pip install "headroom-ai[all]" # Recommended for best performance
242
- headroom proxy --port 8787
243
- ```
244
-
245
- > **Note:** First startup downloads ML models (~500MB) for optimal compression. This is a one-time download.
246
-
247
- **Dashboard:** Open http://localhost:8787/dashboard to see real-time stats, token savings, and request history.
248
-
249
- Point your tools at the proxy:
250
-
251
- ```bash
252
- # Claude Code
253
- ANTHROPIC_BASE_URL=http://localhost:8787 claude
254
-
255
- # Any OpenAI-compatible client
256
- OPENAI_BASE_URL=http://localhost:8787/v1 cursor
257
- ```
258
-
259
- **Enable Persistent Memory** - Claude remembers across conversations:
260
-
261
- ```bash
262
- headroom proxy --memory
263
- ```
264
-
265
- Memory auto-detects your provider (Anthropic, OpenAI, Gemini) and uses the appropriate format:
266
- - **Anthropic**: Uses native memory tool (`memory_20250818`) - works with Claude Code subscriptions
267
- - **OpenAI/Gemini/Others**: Uses function calling format
268
- - All providers share the same semantic vector store for search
269
-
270
- Set `x-headroom-user-id` header for per-user memory isolation (defaults to 'default').
271
-
272
- **Claude Code Subscription Users** - Use MCP for CCR (Compress-Cache-Retrieve):
273
-
274
- If you use Claude Code with a subscription (not API key), you need MCP to enable the `headroom_retrieve` tool:
275
-
276
- ```bash
277
- # One-time setup
278
- pip install "headroom-ai[mcp]"
279
- headroom mcp install
280
-
281
- # Every time you code
282
- headroom proxy # Terminal 1
283
- claude # Terminal 2 - now has headroom_retrieve!
284
- ```
285
-
286
- What this does:
287
- - Configures Claude Code to use Headroom's MCP server (`~/.claude/mcp.json`)
288
- - When the proxy compresses large tool outputs, Claude sees markers like `[47 items compressed... hash=abc123]`
289
- - Claude can call `headroom_retrieve` to get the full original content when needed
290
-
291
- Check your setup:
292
- ```bash
293
- headroom mcp status
294
- ```
295
-
296
- <details>
297
- <summary><b>Why MCP for subscriptions?</b></summary>
298
-
299
- - **API users** can inject custom tools directly via the Messages API
300
- - **Subscription users** use Claude Code's built-in tool set and can't inject tools programmatically
301
- - **MCP** (Model Context Protocol) is Claude's official way to extend tools - it works with subscriptions
302
-
303
- The MCP server exposes `headroom_retrieve` so Claude can request uncompressed content when the compressed summary isn't enough.
304
- </details>
305
-
306
- **Using AWS Bedrock, Google Vertex, or Azure?** Route through Headroom:
307
-
308
- ```bash
309
- # AWS Bedrock - Terminal 1: Start proxy
310
- export AWS_ACCESS_KEY_ID="AKIA..."
311
- export AWS_SECRET_ACCESS_KEY="..."
312
- export AWS_REGION="us-east-1"
313
- headroom proxy --backend bedrock --region us-east-1
314
-
315
- # AWS Bedrock - Terminal 2: Run Claude Code
316
- export ANTHROPIC_API_KEY="sk-ant-dummy" # Any value works! Headroom ignores it.
317
- export ANTHROPIC_BASE_URL="http://localhost:8787"
318
- # IMPORTANT: Do NOT set CLAUDE_CODE_USE_BEDROCK=1 (Headroom handles Bedrock routing)
319
- claude
320
- ```
321
-
322
- <details>
323
- <summary><b>VS Code settings.json for Bedrock</b> (click to expand)</summary>
324
-
325
- ```json
326
- {
327
- "claudeCode.environmentVariables": [
328
- { "name": "ANTHROPIC_API_KEY", "value": "sk-ant-dummy" },
329
- { "name": "ANTHROPIC_BASE_URL", "value": "http://localhost:8787" },
330
- { "name": "AWS_ACCESS_KEY_ID", "value": "AKIA..." },
331
- { "name": "AWS_SECRET_ACCESS_KEY", "value": "..." },
332
- { "name": "AWS_REGION", "value": "us-east-1" }
333
- ]
334
- }
335
- ```
336
-
337
- **Do NOT include** `CLAUDE_CODE_USE_BEDROCK` - Headroom handles the Bedrock routing.
338
- </details>
339
-
340
- **Using OpenRouter?** Access 400+ models through a single API:
341
-
342
- ```bash
343
- # OpenRouter - Terminal 1: Start proxy
344
- export OPENROUTER_API_KEY="sk-or-v1-..."
345
- headroom proxy --backend openrouter
346
-
347
- # OpenRouter - Terminal 2: Run your client
348
- export ANTHROPIC_API_KEY="sk-ant-dummy" # Any value works! Headroom ignores it.
349
- export ANTHROPIC_BASE_URL="http://localhost:8787"
350
- # Use OpenRouter model names in your requests:
351
- # - anthropic/claude-3.5-sonnet
352
- # - openai/gpt-4o
353
- # - google/gemini-pro
354
- # - meta-llama/llama-3-70b-instruct
355
- # See all models: https://openrouter.ai/models
356
- ```
357
-
358
- ```bash
359
- # Google Vertex AI
360
- headroom proxy --backend vertex_ai --region us-central1
361
-
362
- # Azure OpenAI
363
- headroom proxy --backend azure --region eastus
364
- ```
365
-
366
- ### Option 2: LangChain Integration
367
-
368
- ```bash
369
- pip install "headroom-ai[langchain]"
370
- ```
371
-
372
- ```python
373
- from langchain_openai import ChatOpenAI
374
- from headroom.integrations import HeadroomChatModel
375
-
376
- # Wrap your model - that's it!
377
- llm = HeadroomChatModel(ChatOpenAI(model="gpt-4o"))
378
-
379
- # Use exactly like before
380
- response = llm.invoke("Hello!")
381
- ```
382
-
383
- See the full [LangChain Integration Guide](docs/langchain.md) for memory, retrievers, agents, and more.
384
-
385
- ### Option 3: Agno Integration
386
-
387
- ```bash
388
- pip install "headroom-ai[agno]"
389
- ```
390
-
391
- ```python
392
- from agno.agent import Agent
393
- from agno.models.openai import OpenAIChat
394
- from headroom.integrations.agno import HeadroomAgnoModel
395
-
396
- # Wrap your model - that's it!
397
- model = HeadroomAgnoModel(OpenAIChat(id="gpt-4o"))
398
- agent = Agent(model=model)
399
-
400
- # Use exactly like before
401
- response = agent.run("Hello!")
402
 
403
- # Check savings
404
- print(f"Tokens saved: {model.total_tokens_saved}")
405
- ```
 
 
 
406
 
407
- See the full [Agno Integration Guide](docs/agno.md) for hooks, multi-provider support, and more.
408
 
409
  ---
410
 
411
- ## Framework Integrations
412
 
413
- | Framework | Integration | Docs |
414
- |-----------|-------------|------|
415
- | **LangChain** | `HeadroomChatModel`, memory, retrievers, agents | [Guide](docs/langchain.md) |
416
- | **Agno** | `HeadroomAgnoModel`, hooks, multi-provider | [Guide](docs/agno.md) |
417
- | **MCP** | Claude Code subscription support via `headroom mcp install` | [Guide](docs/mcp.md) |
418
- | **Any OpenAI Client** | Proxy server | [Guide](docs/proxy.md) |
 
 
 
 
419
 
420
  ---
421
 
422
  ## Features
423
 
424
- | Feature | Description | Docs |
425
- |---------|-------------|------|
426
- | **Image Compression** | 40-90% token reduction for images via trained ML router | [Image Compression](docs/image-compression.md) |
427
- | **Memory** | Persistent memory across conversations (zero-latency inline extraction) | [Memory](docs/memory.md) |
428
- | **Universal Compression** | ML-based content detection + structure-preserving compression | [Compression](docs/compression.md) |
429
- | **SmartCrusher** | Compresses JSON tool outputs statistically | [Transforms](docs/transforms.md) |
430
- | **CacheAligner** | Stabilizes prefixes for provider caching | [Transforms](docs/transforms.md) |
431
- | **IntelligentContext** | Score-based context dropping with TOIN-learned importance | [Transforms](docs/transforms.md) |
432
- | **CCR** | Reversible compression with automatic retrieval | [CCR Guide](docs/ccr.md) |
433
- | **MCP Server** | Claude Code subscription support via `headroom mcp install` | [MCP Guide](docs/mcp.md) |
434
- | **LangChain** | Memory, retrievers, agents, streaming | [LangChain](docs/langchain.md) |
435
- | **Agno** | Agent framework integration with hooks | [Agno](docs/agno.md) |
436
- | **Text Utilities** | Opt-in compression for search/logs | [Text Compression](docs/text-compression.md) |
437
- | **LLMLingua-2** | ML-based 20x compression (opt-in) | [LLMLingua](docs/llmlingua.md) |
438
- | **Code-Aware** | AST-based code compression (tree-sitter) | [Transforms](docs/transforms.md) |
439
- | **Evals Framework** | Prove compression preserves accuracy (12+ datasets) | [Evals](headroom/evals/README.md) |
440
 
441
  ---
442
 
443
- ## Evaluation Framework: Prove It Works
444
-
445
- Skeptical? Good. We built a comprehensive evaluation framework to **prove** compression preserves accuracy.
446
 
447
  ```bash
448
- # Install evals
449
- pip install "headroom-ai[evals]"
450
-
451
- # Quick sanity check (5 samples)
452
- python -m headroom.evals quick
453
-
454
- # Run on real datasets
455
- python -m headroom.evals benchmark --dataset hotpotqa -n 100
456
- ```
457
-
458
- ### How Evals Work
459
-
460
- ```
461
- Original Context ───► LLM ───► Response A
462
-
463
- Compressed Context ─► LLM ───► Response B
464
-
465
- Compare A vs B │
466
- ─────────────────
467
- F1 Score: 0.95
468
- Semantic Similarity: 0.97
469
- Ground Truth Match: ✓
470
- ─────────────────
471
- PASS: Accuracy preserved
472
  ```
473
 
474
- ### Available Datasets (12+)
475
-
476
- | Category | Datasets |
477
- |----------|----------|
478
- | **RAG** | HotpotQA, Natural Questions, TriviaQA, MS MARCO, SQuAD |
479
- | **Long Context** | LongBench (4K-128K tokens), NarrativeQA |
480
- | **Tool Use** | BFCL (function calling), ToolBench, Built-in samples |
481
- | **Code** | CodeSearchNet, HumanEval |
482
-
483
- ### CI Integration
484
-
485
- ```yaml
486
- # GitHub Actions
487
- - name: Run Compression Evals
488
- run: python -m headroom.evals quick -n 20
489
- env:
490
- ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
491
- ```
492
-
493
- Exit code 0 if accuracy ≥ 90%, 1 otherwise.
494
-
495
- See the full [Evals Documentation](headroom/evals/README.md) for datasets, metrics, and programmatic API.
496
-
497
- ---
498
-
499
- ## Verified Performance
500
-
501
- These numbers are from actual API calls, not estimates:
502
-
503
- | Scenario | Before | After | Savings | Verified |
504
- |----------|--------|-------|---------|----------|
505
- | Code search (100 results) | 17,765 tokens | 1,408 tokens | 92% | Claude Sonnet |
506
- | SRE incident debugging | 65,694 tokens | 5,118 tokens | 92% | GPT-4o |
507
- | Codebase exploration | 78,502 tokens | 41,254 tokens | 47% | GPT-4o |
508
- | GitHub issue triage | 54,174 tokens | 14,761 tokens | 73% | GPT-4o |
509
-
510
- **Overhead**: ~1-5ms compression latency
511
-
512
- **When savings are highest**: Tool-heavy workloads (search, logs, database queries)
513
- **When savings are lowest**: Conversation-heavy workloads with minimal tool use
514
-
515
- ---
516
-
517
- ## Providers
518
-
519
- | Provider | Token Counting | Cache Optimization |
520
- |----------|----------------|-------------------|
521
- | OpenAI | tiktoken (exact) | Automatic prefix caching |
522
- | Anthropic | Official API | cache_control blocks |
523
- | Google | Official API | Context caching |
524
- | Cohere | Official API | - |
525
- | Mistral | Official tokenizer | - |
526
-
527
- New models auto-supported via naming pattern detection.
528
-
529
- ---
530
-
531
- ## Safety Guarantees
532
-
533
- - **Never removes human content** - user/assistant messages preserved
534
- - **Never breaks tool ordering** - tool calls and responses stay paired
535
- - **Parse failures are no-ops** - malformed content passes through unchanged
536
- - **Compression is reversible** - LLM retrieves original data via CCR
537
-
538
  ---
539
 
540
  ## Installation
541
 
542
  ```bash
543
- # Recommended: Install everything for best compression performance
544
- pip install "headroom-ai[all]"
545
-
546
- # Or install specific components
547
- pip install headroom-ai # SDK only
548
- pip install "headroom-ai[proxy]" # Proxy server
549
- pip install "headroom-ai[mcp]" # MCP server for Claude Code subscriptions
550
- pip install "headroom-ai[langchain]" # LangChain integration
551
- pip install "headroom-ai[agno]" # Agno agent framework
552
- pip install "headroom-ai[evals]" # Evaluation framework
553
- pip install "headroom-ai[code]" # AST-based code compression
554
- pip install "headroom-ai[llmlingua]" # ML-based compression
555
  ```
556
 
557
- **Requirements**: Python 3.10+
558
-
559
- > **First-time startup:** Headroom downloads ML models (~500MB) on first run for optimal compression. This is cached locally and only happens once.
560
 
561
  ---
562
 
563
  ## Documentation
564
 
565
- | Guide | Description |
566
- |-------|-------------|
567
- | [Memory Guide](docs/memory.md) | Persistent memory for LLMs |
568
- | [Compression Guide](docs/compression.md) | Universal compression with ML detection |
 
 
 
569
  | [Evals Framework](headroom/evals/README.md) | Prove compression preserves accuracy |
570
- | [LangChain Integration](docs/langchain.md) | Full LangChain support |
571
- | [Agno Integration](docs/agno.md) | Full Agno agent framework support |
572
- | [SDK Guide](docs/sdk.md) | Fine-grained control |
573
- | [Proxy Guide](docs/proxy.md) | Production deployment |
574
  | [Configuration](docs/configuration.md) | All options |
575
- | [CCR Guide](docs/ccr.md) | Reversible compression |
576
- | [MCP Guide](docs/mcp.md) | Claude Code subscription support |
577
- | [Metrics](docs/metrics.md) | Monitoring |
578
- | [Troubleshooting](docs/troubleshooting.md) | Common issues |
579
-
580
- ---
581
-
582
- ## Who's Using Headroom?
583
-
584
- > Add your project here! [Open a PR](https://github.com/chopratejas/headroom/pulls) or [start a discussion](https://github.com/chopratejas/headroom/discussions).
585
 
586
  ---
587
 
588
  ## Contributing
589
 
590
  ```bash
591
- git clone https://github.com/chopratejas/headroom.git
592
- cd headroom
593
- pip install -e ".[dev]"
594
- pytest
595
  ```
596
 
597
- See [CONTRIBUTING.md](CONTRIBUTING.md) for details.
598
-
599
  ---
600
 
601
  ## License
602
 
603
- Apache License 2.0 - see [LICENSE](LICENSE).
604
-
605
- ---
606
-
607
- <p align="center">
608
- <sub>Built for the AI developer community</sub>
609
- </p>
 
29
  </a>
30
  </p>
31
 
 
32
  ---
33
 
34
  ## Demo
 
39
 
40
  ---
41
 
42
+ ## Quick Start
 
 
 
 
 
43
 
44
+ ```bash
45
+ pip install "headroom-ai[all]"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
  ```
47
 
48
+ ```python
49
+ from headroom import compress
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
 
51
+ messages = [
52
+ {"role": "user", "content": "What caused the outage?"},
53
+ {"role": "tool", "content": huge_log_output, "tool_call_id": "call_1"},
54
+ ]
55
 
56
+ result = compress(messages, model="claude-sonnet-4-5-20250929")
57
+ # result.messages same format, 50-90% fewer tokens
58
+ # result.tokens_saved → 8,000
59
+ # result.compression_ratio → 0.87
60
 
61
+ response = client.messages.create(model="claude-sonnet-4-5-20250929", messages=result.messages)
 
62
  ```
63
 
64
+ **Same answer. 87% fewer tokens.**
65
 
66
  ---
67
 
68
+ ## How to Use Headroom
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
 
70
+ Headroom is a compression library, not just a proxy. Use whichever integration fits your stack:
71
 
72
+ | You have... | Use this | Code |
73
+ |-------------|----------|------|
74
+ | Any Python app | `compress()` | `result = compress(messages, model="gpt-4o")` |
75
+ | LiteLLM | Callback | `litellm.callbacks = [HeadroomCallback()]` |
76
+ | Python proxy (FastAPI) | ASGI Middleware | `app.add_middleware(CompressionMiddleware)` |
77
+ | Claude Code / Cursor | Proxy | `ANTHROPIC_BASE_URL=http://localhost:8787 claude` |
78
+ | Agno agents | Wrap model | `HeadroomAgnoModel(your_model)` |
79
+ | LangChain | Wrap model | `HeadroomChatModel(your_llm)` *(experimental)* |
80
 
81
+ **Already have a proxy?** You don't need another one. See the **[Integration Guide](docs/integration-guide.md)** for detailed setup with LiteLLM, ASGI middleware, and direct `compress()` usage.
82
 
83
  ---
84
 
85
  ## How It Works
86
 
 
 
 
 
 
 
 
 
 
 
 
 
87
  ```
88
+ Your App → Headroom → LLM Provider
89
+
90
+ CacheAligner: stabilizes prefix for KV cache hits
91
+ ContentRouter: routes to optimal compressor per content type
92
+ SmartCrusher (JSON) | CodeCompressor (code) | LLMLingua (text)
93
+ IntelligentContext: score-based token fitting
94
+ CCR: stores originals for retrieval if LLM needs more
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
  ```
96
 
97
+ Headroom never throws data away. It compresses aggressively and retrieves precisely.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
 
99
  ---
100
 
101
+ ## Verified Performance
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
 
103
+ | Scenario | Tokens Before | Tokens After | Savings |
104
+ |----------|--------------|-------------|---------|
105
+ | Code search (100 results) | 17,765 | 1,408 | **92%** |
106
+ | SRE incident debugging | 65,694 | 5,118 | **92%** |
107
+ | Codebase exploration | 78,502 | 41,254 | **47%** |
108
+ | GitHub issue triage | 54,174 | 14,761 | **73%** |
109
 
110
+ **Overhead**: 1-5ms. **Accuracy**: [benchmarked](docs/benchmarks.md) across 12+ datasets.
111
 
112
  ---
113
 
114
+ ## Integrations
115
 
116
+ | Integration | Status | Docs |
117
+ |-------------|--------|------|
118
+ | `compress()` one function | **Stable** | [Integration Guide](docs/integration-guide.md) |
119
+ | LiteLLM callback | **Stable** | [Integration Guide](docs/integration-guide.md#litellm) |
120
+ | ASGI middleware | **Stable** | [Integration Guide](docs/integration-guide.md#asgi-middleware) |
121
+ | Proxy server | **Stable** | [Proxy Docs](docs/proxy.md) |
122
+ | Agno | **Stable** | [Agno Guide](docs/agno.md) |
123
+ | MCP (Claude Code) | **Stable** | [MCP Guide](docs/mcp.md) |
124
+ | Strands | **Stable** | [Strands Guide](docs/strands.md) |
125
+ | LangChain | **Experimental** | [LangChain Guide](docs/langchain.md) |
126
 
127
  ---
128
 
129
  ## Features
130
 
131
+ | Feature | What it does |
132
+ |---------|-------------|
133
+ | **Content Router** | Auto-detects content type, routes to optimal compressor |
134
+ | **SmartCrusher** | Statistically compresses JSON arrays (tool outputs, API responses) |
135
+ | **CodeCompressor** | AST-aware code compression (Python, JS, Go, Rust, Java) |
136
+ | **LLMLingua-2** | ML-based 20x text compression |
137
+ | **CCR** | Reversible compression LLM retrieves originals when needed |
138
+ | **CacheAligner** | Stabilizes prefixes for provider KV cache hits |
139
+ | **IntelligentContext** | Score-based context management with learned importance |
140
+ | **Image Compression** | 40-90% token reduction via trained ML router |
141
+ | **Memory** | Persistent memory across conversations |
142
+ | **Compression Hooks** | Customize compression with pre/post hooks |
143
+ | **Query Echo** | Re-injects user question after compressed data for better attention |
 
 
 
144
 
145
  ---
146
 
147
+ ## Cloud Providers
 
 
148
 
149
  ```bash
150
+ headroom proxy --backend bedrock --region us-east-1 # AWS Bedrock
151
+ headroom proxy --backend vertex_ai --region us-central1 # Google Vertex
152
+ headroom proxy --backend azure # Azure OpenAI
153
+ headroom proxy --backend openrouter # OpenRouter (400+ models)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
154
  ```
155
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
156
  ---
157
 
158
  ## Installation
159
 
160
  ```bash
161
+ pip install headroom-ai # Core library
162
+ pip install "headroom-ai[all]" # Everything (recommended)
163
+ pip install "headroom-ai[proxy]" # Proxy server
164
+ pip install "headroom-ai[mcp]" # MCP for Claude Code
165
+ pip install "headroom-ai[agno]" # Agno integration
166
+ pip install "headroom-ai[langchain]" # LangChain (experimental)
167
+ pip install "headroom-ai[evals]" # Evaluation framework
 
 
 
 
 
168
  ```
169
 
170
+ Python 3.10+
 
 
171
 
172
  ---
173
 
174
  ## Documentation
175
 
176
+ | | |
177
+ |---|---|
178
+ | [Integration Guide](docs/integration-guide.md) | LiteLLM, ASGI, compress(), proxy |
179
+ | [Proxy Docs](docs/proxy.md) | Proxy server configuration |
180
+ | [Architecture](docs/ARCHITECTURE.md) | How the pipeline works |
181
+ | [CCR Guide](docs/ccr.md) | Reversible compression |
182
+ | [Benchmarks](docs/benchmarks.md) | Accuracy validation |
183
  | [Evals Framework](headroom/evals/README.md) | Prove compression preserves accuracy |
184
+ | [Memory](docs/memory.md) | Persistent memory |
185
+ | [Agno](docs/agno.md) | Agno agent framework |
186
+ | [MCP](docs/mcp.md) | Claude Code subscriptions |
 
187
  | [Configuration](docs/configuration.md) | All options |
 
 
 
 
 
 
 
 
 
 
188
 
189
  ---
190
 
191
  ## Contributing
192
 
193
  ```bash
194
+ git clone https://github.com/chopratejas/headroom.git && cd headroom
195
+ pip install -e ".[dev]" && pytest
 
 
196
  ```
197
 
 
 
198
  ---
199
 
200
  ## License
201
 
202
+ Apache License 2.0 see [LICENSE](LICENSE).
 
 
 
 
 
 
docs/integration-guide.md ADDED
@@ -0,0 +1,292 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Integration Guide
2
+
3
+ You don't need to run the Headroom proxy. Headroom is a compression library that works with **any** LLM client, proxy, or framework.
4
+
5
+ ## Pick Your Path
6
+
7
+ | You have... | Use this | Setup |
8
+ |-------------|----------|-------|
9
+ | Any Python app | [`compress()`](#compress-function) | 2 lines |
10
+ | LiteLLM | [LiteLLM callback](#litellm) | 1 line |
11
+ | A Python proxy (FastAPI, custom) | [ASGI middleware](#asgi-middleware) | 1 line |
12
+ | Claude Code / Cursor | [Headroom proxy](#proxy) | 1 env var |
13
+ | Agno agents | [Agno integration](#agno) | Wrap model |
14
+ | LangChain | [LangChain integration](#langchain) | Wrap model |
15
+ | Non-Python app | [Headroom proxy](#proxy) | HTTP |
16
+
17
+ ---
18
+
19
+ ## compress() Function
20
+
21
+ The simplest integration. Works with any LLM client.
22
+
23
+ ```python
24
+ from headroom import compress
25
+
26
+ # Before sending to your LLM:
27
+ result = compress(messages, model="claude-sonnet-4-5-20250929")
28
+ response = your_client.create(messages=result.messages) # Fewer tokens, same answer
29
+
30
+ print(f"Saved {result.tokens_saved} tokens ({result.compression_ratio:.0%})")
31
+ ```
32
+
33
+ ### With Anthropic SDK
34
+
35
+ ```python
36
+ from anthropic import Anthropic
37
+ from headroom import compress
38
+
39
+ client = Anthropic()
40
+ messages = [
41
+ {"role": "user", "content": "What went wrong?"},
42
+ {"role": "assistant", "content": "Let me check.", "tool_use": [...]},
43
+ {"role": "user", "content": [{"type": "tool_result", "content": huge_json}]},
44
+ ]
45
+
46
+ compressed = compress(messages, model="claude-sonnet-4-5-20250929")
47
+ response = client.messages.create(
48
+ model="claude-sonnet-4-5-20250929",
49
+ messages=compressed.messages,
50
+ max_tokens=1000,
51
+ )
52
+ ```
53
+
54
+ ### With OpenAI SDK
55
+
56
+ ```python
57
+ from openai import OpenAI
58
+ from headroom import compress
59
+
60
+ client = OpenAI()
61
+ messages = [
62
+ {"role": "user", "content": "Analyze these results"},
63
+ {"role": "tool", "content": big_json_output, "tool_call_id": "call_1"},
64
+ ]
65
+
66
+ compressed = compress(messages, model="gpt-4o")
67
+ response = client.chat.completions.create(
68
+ model="gpt-4o",
69
+ messages=compressed.messages,
70
+ )
71
+ ```
72
+
73
+ ### With LiteLLM (direct)
74
+
75
+ ```python
76
+ import litellm
77
+ from headroom import compress
78
+
79
+ messages = [...]
80
+ compressed = compress(messages, model="bedrock/claude-sonnet")
81
+ response = litellm.completion(model="bedrock/claude-sonnet", messages=compressed.messages)
82
+ ```
83
+
84
+ ### With any HTTP client
85
+
86
+ ```python
87
+ import httpx
88
+ from headroom import compress
89
+
90
+ compressed = compress(messages, model="claude-sonnet-4-5-20250929")
91
+ httpx.post("https://api.anthropic.com/v1/messages", json={
92
+ "model": "claude-sonnet-4-5-20250929",
93
+ "messages": compressed.messages,
94
+ }, headers={"X-Api-Key": api_key, "anthropic-version": "2023-06-01"})
95
+ ```
96
+
97
+ ### What compress() returns
98
+
99
+ ```python
100
+ result = compress(messages, model="gpt-4o")
101
+ result.messages # list[dict] — compressed messages, same format as input
102
+ result.tokens_before # int — original token count
103
+ result.tokens_after # int — compressed token count
104
+ result.tokens_saved # int — tokens removed
105
+ result.compression_ratio # float — 0.0 (no savings) to 1.0 (100% removed)
106
+ result.transforms_applied # list[str] — what ran (e.g., ["router:smart_crusher:0.35"])
107
+ ```
108
+
109
+ ---
110
+
111
+ ## LiteLLM
112
+
113
+ If you're already using LiteLLM as your LLM gateway, add Headroom as a callback:
114
+
115
+ ```python
116
+ import litellm
117
+ from headroom.integrations.litellm_callback import HeadroomCallback
118
+
119
+ litellm.callbacks = [HeadroomCallback()]
120
+
121
+ # All calls now compressed automatically
122
+ response = litellm.completion(model="gpt-4o", messages=[...])
123
+ response = litellm.completion(model="bedrock/claude-sonnet", messages=[...])
124
+ response = litellm.completion(model="azure/gpt-4o", messages=[...])
125
+ ```
126
+
127
+ The callback compresses messages in LiteLLM's `pre_call_hook` before they're sent to the provider. Works with all 100+ LiteLLM-supported providers.
128
+
129
+ ### With LiteLLM Proxy
130
+
131
+ If you run LiteLLM as a proxy server, use the ASGI middleware instead:
132
+
133
+ ```python
134
+ # In your LiteLLM proxy startup
135
+ from litellm.proxy.proxy_server import app
136
+ from headroom.integrations.asgi import CompressionMiddleware
137
+
138
+ app.add_middleware(CompressionMiddleware)
139
+ ```
140
+
141
+ Or use the callback in your LiteLLM config:
142
+
143
+ ```yaml
144
+ # litellm_config.yaml
145
+ litellm_settings:
146
+ callbacks: ["headroom.integrations.litellm_callback.HeadroomCallback"]
147
+ ```
148
+
149
+ ---
150
+
151
+ ## ASGI Middleware
152
+
153
+ Drop-in middleware for any ASGI application (FastAPI, Starlette, LiteLLM proxy, custom proxies).
154
+
155
+ ```python
156
+ from headroom.integrations.asgi import CompressionMiddleware
157
+
158
+ # FastAPI
159
+ app = FastAPI()
160
+ app.add_middleware(CompressionMiddleware)
161
+
162
+ # Starlette
163
+ app = Starlette(routes=[...])
164
+ app.add_middleware(CompressionMiddleware)
165
+
166
+ # LiteLLM proxy
167
+ from litellm.proxy.proxy_server import app
168
+ app.add_middleware(CompressionMiddleware)
169
+ ```
170
+
171
+ The middleware intercepts POST requests to `/v1/messages`, `/v1/chat/completions`, `/v1/responses`, and `/chat/completions`. All other requests pass through untouched.
172
+
173
+ Response headers include:
174
+ - `x-headroom-compressed: true` — compression was applied
175
+ - `x-headroom-tokens-saved: 1234` — tokens removed
176
+
177
+ ---
178
+
179
+ ## Proxy
180
+
181
+ The Headroom proxy is a standalone HTTP server. Best for non-Python apps or tools that only support base URL configuration (Claude Code, Cursor).
182
+
183
+ ```bash
184
+ pip install "headroom-ai[all]"
185
+ headroom proxy --port 8787
186
+ ```
187
+
188
+ ```bash
189
+ # Claude Code
190
+ ANTHROPIC_BASE_URL=http://localhost:8787 claude
191
+
192
+ # Cursor / Any OpenAI client
193
+ OPENAI_BASE_URL=http://localhost:8787/v1 cursor
194
+ ```
195
+
196
+ ### With Cloud Providers
197
+
198
+ ```bash
199
+ # AWS Bedrock
200
+ headroom proxy --backend bedrock --region us-east-1
201
+
202
+ # Google Vertex AI
203
+ headroom proxy --backend vertex_ai --region us-central1
204
+
205
+ # Azure OpenAI
206
+ headroom proxy --backend azure
207
+
208
+ # OpenRouter (400+ models)
209
+ OPENROUTER_API_KEY=sk-or-... headroom proxy --backend openrouter
210
+ ```
211
+
212
+ See [Proxy Documentation](proxy.md) for all options.
213
+
214
+ ---
215
+
216
+ ## Agno
217
+
218
+ Full integration with the Agno agent framework.
219
+
220
+ ```python
221
+ from agno.agent import Agent
222
+ from agno.models.anthropic import Claude
223
+ from headroom.integrations.agno import HeadroomAgnoModel
224
+
225
+ model = HeadroomAgnoModel(Claude(id="claude-sonnet-4-20250514"))
226
+ agent = Agent(model=model, tools=[your_tools])
227
+ response = agent.run("Investigate the issue")
228
+
229
+ print(f"Tokens saved: {model.total_tokens_saved}")
230
+ ```
231
+
232
+ See [Agno Guide](agno.md) for hooks, multi-provider, and streaming.
233
+
234
+ ---
235
+
236
+ ## LangChain
237
+
238
+ > **Experimental.** Core compression works. Streaming callbacks and async chains are still being tested.
239
+
240
+ ```python
241
+ from langchain_openai import ChatOpenAI
242
+ from headroom.integrations import HeadroomChatModel
243
+
244
+ llm = HeadroomChatModel(ChatOpenAI(model="gpt-4o"))
245
+ response = llm.invoke("Hello!")
246
+ ```
247
+
248
+ See [LangChain Guide](langchain.md) for details and known limitations.
249
+
250
+ ---
251
+
252
+ ## Compression Hooks (Advanced)
253
+
254
+ Customize compression behavior without modifying Headroom's code:
255
+
256
+ ```python
257
+ from headroom import compress, CompressionHooks, CompressContext
258
+
259
+ class MyHooks(CompressionHooks):
260
+ def pre_compress(self, messages, ctx):
261
+ # Modify messages before compression (dedup, filter, inject)
262
+ return messages
263
+
264
+ def compute_biases(self, messages, ctx):
265
+ # Per-message compression aggressiveness
266
+ # >1.0 = keep more, <1.0 = compress more
267
+ return {5: 1.5, 6: 0.5} # Keep message 5, compress message 6
268
+
269
+ def post_compress(self, event):
270
+ # Observe results (logging, analytics, learning)
271
+ print(f"Saved {event.tokens_saved} tokens")
272
+
273
+ result = compress(messages, model="gpt-4o", hooks=MyHooks())
274
+ ```
275
+
276
+ See [Architecture](ARCHITECTURE.md) for how hooks integrate with the pipeline.
277
+
278
+ ---
279
+
280
+ ## FAQ
281
+
282
+ **Q: Does Headroom change the response format?**
283
+ No. Your LLM returns the same response format. Headroom only modifies the input messages.
284
+
285
+ **Q: What if compression removes something the LLM needs?**
286
+ Headroom stores originals in CCR (Compress-Cache-Retrieve). The LLM can call `headroom_retrieve` to get full uncompressed content. Compression summaries tell the LLM what's available.
287
+
288
+ **Q: Does it work with streaming?**
289
+ Yes. Compression happens before the request is sent. Streaming responses are unaffected.
290
+
291
+ **Q: How much latency does it add?**
292
+ 1-5ms for compression. The token savings typically save more time on the LLM side than compression adds.
headroom/compress.py CHANGED
@@ -183,17 +183,13 @@ def _get_pipeline() -> Any:
183
  if _pipeline is not None:
184
  return _pipeline
185
 
186
- from headroom.transforms import ContentRouter, SmartCrusher, TransformPipeline
187
-
188
- _pipeline = TransformPipeline(
189
- transforms=[
190
- ContentRouter(),
191
- SmartCrusher(),
192
- ],
193
- # No provider needed — pipeline uses tokenizer registry which
194
- # auto-detects the right tokenizer per model:
195
- # OpenAI → tiktoken (exact), Anthropic → calibrated estimation,
196
- # Open models → HuggingFace (if installed)
197
- )
198
  logger.debug("Headroom compression pipeline initialized")
199
  return _pipeline
 
183
  if _pipeline is not None:
184
  return _pipeline
185
 
186
+ from headroom.transforms import TransformPipeline
187
+
188
+ # Default pipeline: CacheAligner → ContentRouter → IntelligentContext
189
+ # CacheAligner: stabilizes prefix for provider KV cache hits
190
+ # ContentRouter: routes to the right compressor per content type
191
+ # (SmartCrusher for JSON, CodeCompressor for code, LLMLingua for text)
192
+ # IntelligentContext: enforces token limits with score-based dropping
193
+ _pipeline = TransformPipeline()
 
 
 
 
194
  logger.debug("Headroom compression pipeline initialized")
195
  return _pipeline