chopratejas commited on
Commit
66ac1c8
·
1 Parent(s): 22987ea

Updating the README to reflect the right positioning for Headroom

Browse files
README.md CHANGED
@@ -1,10 +1,11 @@
1
  <p align="center">
2
  <h1 align="center">Headroom</h1>
3
  <p align="center">
4
- <strong>The Context Optimization Layer for LLM Applications</strong>
5
  </p>
6
  <p align="center">
7
- Tool outputs are 70-95% redundant boilerplate. Headroom compresses that away.
 
8
  </p>
9
  </p>
10
 
@@ -27,15 +28,38 @@
27
  <a href="https://chopratejas.github.io/headroom/">
28
  <img src="https://img.shields.io/badge/docs-GitHub%20Pages-blue.svg" alt="Documentation">
29
  </a>
 
 
 
30
  </p>
31
 
32
  ---
33
 
34
- ## Demo
35
 
36
- <p align="center">
37
- <img src="Headroom-2.gif" alt="Headroom Demo" width="800">
38
- </p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
 
40
  ---
41
 
@@ -45,7 +69,7 @@
45
  pip install "headroom-ai[all]"
46
  ```
47
 
48
- ### Simplest: Proxy (zero code changes)
49
 
50
  ```bash
51
  headroom proxy --port 8787
@@ -61,20 +85,6 @@ OPENAI_BASE_URL=http://localhost:8787/v1 cursor
61
 
62
  Works with any language, any tool, any framework. One env var. **[Proxy docs](docs/proxy.md)**
63
 
64
- ### Failure Learning (new)
65
-
66
- ```bash
67
- headroom learn # Analyze past Claude Code sessions, show recommendations
68
- headroom learn --apply # Write learnings to CLAUDE.md and MEMORY.md
69
- headroom learn --all --apply # Learn across all your projects
70
- ```
71
-
72
- Reads your conversation history, finds every failed tool call, correlates it with what eventually succeeded, and writes specific corrections into your project files. Next session starts smarter. **[Learn docs](docs/learn.md)**
73
-
74
- <p align="center">
75
- <img src="headroom_learn.gif" alt="headroom learn demo" width="800">
76
- </p>
77
-
78
  ### Python: One function
79
 
80
  ```python
@@ -103,6 +113,14 @@ You don't need to replace it. Drop Headroom into your existing stack:
103
 
104
  ---
105
 
 
 
 
 
 
 
 
 
106
  ## Does It Actually Work?
107
 
108
  **100 production log entries. One critical error buried at position 67.**
@@ -122,9 +140,18 @@ Both responses: *"payment-gateway, error PG-5523, fix: Increase max_connections
122
  From 100 log entries, SmartCrusher kept 6: first 3 (boundary), the FATAL error at position 67 (anomaly detection), and last 2 (recency). The error was automatically preserved — not by keyword matching, but by statistical analysis of field variance.
123
  </details>
124
 
 
 
 
 
 
 
 
 
 
125
  ### Accuracy Benchmarks
126
 
127
- Headroom is evaluated on real OSS benchmarks — compression preserves accuracy.
128
 
129
  **Standard Benchmarks** — Baseline (direct to API) vs Headroom (through proxy):
130
 
@@ -133,7 +160,7 @@ Headroom is evaluated on real OSS benchmarks — compression preserves accuracy.
133
  | [GSM8K](https://huggingface.co/datasets/openai/gsm8k) | Math | 100 | 0.870 | 0.870 | **0.000** |
134
  | [TruthfulQA](https://huggingface.co/datasets/truthfulqa/truthful_qa) | Factual | 100 | 0.530 | 0.560 | **+0.030** |
135
 
136
- **Compression Benchmarks** — Accuracy after compression + CCR (full stack):
137
 
138
  | Benchmark | Category | N | Accuracy | Compression | Method |
139
  |-----------|----------|---|----------|-------------|--------|
@@ -159,77 +186,40 @@ Full methodology: [Benchmarks](docs/benchmarks.md) | [Evals Framework](headroom/
159
 
160
  ---
161
 
162
- ## How It Works
163
 
164
- ```mermaid
165
- flowchart LR
166
- App["Your App"] --> H["Headroom"] --> LLM["LLM Provider"]
167
- LLM --> Resp["Response"]
168
- ```
169
 
170
- ### Inside Headroom
171
-
172
- ```mermaid
173
- flowchart TB
174
- subgraph Pipeline["Transform Pipeline"]
175
- CA["1. CacheAligner\nStabilizes prefix for KV cache"]
176
- CR["2. ContentRouter\nDetects content type, picks compressor"]
177
- IC["3. IntelligentContext\nScore-based token fitting"]
178
- QE["4. Query Echo\nRe-injects user question"]
179
- CA --> CR --> IC --> QE
180
- end
181
-
182
- subgraph Compressors["ContentRouter dispatches to"]
183
- SC["SmartCrusher\nAny JSON type"]
184
- CC["CodeCompressor\nAST-aware code"]
185
- LL["LLMLingua\nML-based text"]
186
- end
187
-
188
- subgraph CCR["CCR: Compress-Cache-Retrieve"]
189
- Store[("Compressed\nStore")]
190
- Tool["headroom_retrieve"]
191
- Tool <--> Store
192
- end
193
-
194
- CR --> Compressors
195
- SC -. "stores originals +\nsummary of what's omitted" .-> Store
196
- QE --> LLM["LLM Provider"]
197
- LLM -. "retrieves when\nit needs more" .-> Tool
198
- ```
199
 
200
- > Headroom never throws data away. It compresses aggressively and retrieves precisely.
201
- > When it compresses 500 items to 20, it tells the LLM *what was omitted*
202
- > ("87 passed, 2 failed, 1 error") so the LLM knows when to ask for more.
203
 
204
- ### Verified on Real Workloads
205
 
206
- | Scenario | Before | After | Savings |
207
- |----------|--------|-------|---------|
208
- | Code search (100 results) | 17,765 | 1,408 | **92%** |
209
- | SRE incident debugging | 65,694 | 5,118 | **92%** |
210
- | Codebase exploration | 78,502 | 41,254 | **47%** |
211
- | GitHub issue triage | 54,174 | 14,761 | **73%** |
212
 
213
- **Overhead**: 15-200ms compression latency (net positive for Sonnet/Opus). Full data: [Latency Benchmarks](docs/LATENCY_BENCHMARKS.md)
214
 
215
- ---
216
 
217
- ## Integrations
 
 
 
 
218
 
219
- | Integration | Status | Docs |
220
- |-------------|--------|------|
221
- | `compress()` — one function | **Stable** | [Integration Guide](docs/integration-guide.md) |
222
- | LiteLLM callback | **Stable** | [Integration Guide](docs/integration-guide.md#litellm) |
223
- | ASGI middleware | **Stable** | [Integration Guide](docs/integration-guide.md#asgi-middleware) |
224
- | Proxy server | **Stable** | [Proxy Docs](docs/proxy.md) |
225
- | Agno | **Stable** | [Agno Guide](docs/agno.md) |
226
- | MCP (Claude Code) | **Stable** | [MCP Guide](docs/mcp.md) |
227
- | Strands | **Stable** | [Strands Guide](docs/strands.md) |
228
- | LangChain | **Experimental** | [LangChain Guide](docs/langchain.md) |
229
 
230
- ---
 
 
 
 
231
 
232
- ## Features
 
 
 
233
 
234
  | Feature | What it does |
235
  |---------|-------------|
@@ -239,7 +229,6 @@ flowchart TB
239
  | **LLMLingua-2** | ML-based 20x text compression |
240
  | **CCR** | Reversible compression — LLM retrieves originals when needed |
241
  | **Compression Summaries** | Tells the LLM what was omitted ("3 errors, 12 failures") |
242
- | **Query Echo** | Re-injects user question after compressed data for better attention |
243
  | **CacheAligner** | Stabilizes prefixes for provider KV cache hits |
244
  | **IntelligentContext** | Score-based context management with learned importance |
245
  | **Image Compression** | 40-90% token reduction via trained ML router |
@@ -248,6 +237,69 @@ flowchart TB
248
  | **Read Lifecycle** | Detects stale/superseded Read outputs, replaces with CCR markers |
249
  | **`headroom learn`** | Analyzes past failures, writes project-specific learnings to CLAUDE.md/MEMORY.md |
250
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
251
  ---
252
 
253
  ## Cloud Providers
@@ -297,6 +349,12 @@ Python 3.10+
297
 
298
  ---
299
 
 
 
 
 
 
 
300
  ## Contributing
301
 
302
  ```bash
 
1
  <p align="center">
2
  <h1 align="center">Headroom</h1>
3
  <p align="center">
4
+ <strong>Compress everything your AI agent reads. Same answers, fraction of the tokens.</strong>
5
  </p>
6
  <p align="center">
7
+ Every tool call, DB query, file read, and RAG retrieval your agent makes is 70-95% boilerplate.<br>
8
+ Headroom compresses it away before it hits the model.
9
  </p>
10
  </p>
11
 
 
28
  <a href="https://chopratejas.github.io/headroom/">
29
  <img src="https://img.shields.io/badge/docs-GitHub%20Pages-blue.svg" alt="Documentation">
30
  </a>
31
+ <a href="https://discord.gg/QEyNhaGA">
32
+ <img src="https://img.shields.io/badge/Discord-Join%20us-5865F2?logo=discord&logoColor=white" alt="Discord">
33
+ </a>
34
  </p>
35
 
36
  ---
37
 
38
+ ## Where Headroom Fits
39
 
40
+ ```
41
+ Your Agent / App
42
+
43
+ │ tool calls, logs, DB reads, RAG results, file reads, API responses
44
+
45
+ Headroom ← transparent proxy, no code changes needed
46
+
47
+
48
+ LLM Provider (OpenAI, Anthropic, Google, Bedrock, 100+ via LiteLLM)
49
+ ```
50
+
51
+ Headroom sits between your application and the LLM provider. It intercepts requests, compresses the context, and forwards an optimized prompt. Your app doesn't change — just point it at Headroom.
52
+
53
+ ### What gets compressed
54
+
55
+ Headroom optimizes any data your agent injects into a prompt:
56
+
57
+ - **Tool outputs** — shell commands, API calls, search results
58
+ - **Database queries** — SQL results, key-value lookups
59
+ - **RAG retrievals** — document chunks, embeddings results
60
+ - **File reads** — code, logs, configs, CSVs
61
+ - **API responses** — JSON, XML, HTML
62
+ - **Conversation history** — long agent sessions with repetitive context
63
 
64
  ---
65
 
 
69
  pip install "headroom-ai[all]"
70
  ```
71
 
72
+ ### Proxy (zero code changes)
73
 
74
  ```bash
75
  headroom proxy --port 8787
 
85
 
86
  Works with any language, any tool, any framework. One env var. **[Proxy docs](docs/proxy.md)**
87
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
  ### Python: One function
89
 
90
  ```python
 
113
 
114
  ---
115
 
116
+ ## Demo
117
+
118
+ <p align="center">
119
+ <img src="Headroom-2.gif" alt="Headroom Demo" width="800">
120
+ </p>
121
+
122
+ ---
123
+
124
  ## Does It Actually Work?
125
 
126
  **100 production log entries. One critical error buried at position 67.**
 
140
  From 100 log entries, SmartCrusher kept 6: first 3 (boundary), the FATAL error at position 67 (anomaly detection), and last 2 (recency). The error was automatically preserved — not by keyword matching, but by statistical analysis of field variance.
141
  </details>
142
 
143
+ ### Real Workloads
144
+
145
+ | Scenario | Before | After | Savings |
146
+ |----------|--------|-------|---------|
147
+ | Code search (100 results) | 17,765 | 1,408 | **92%** |
148
+ | SRE incident debugging | 65,694 | 5,118 | **92%** |
149
+ | Codebase exploration | 78,502 | 41,254 | **47%** |
150
+ | GitHub issue triage | 54,174 | 14,761 | **73%** |
151
+
152
  ### Accuracy Benchmarks
153
 
154
+ Compression preserves accuracy — tested on real OSS benchmarks.
155
 
156
  **Standard Benchmarks** — Baseline (direct to API) vs Headroom (through proxy):
157
 
 
160
  | [GSM8K](https://huggingface.co/datasets/openai/gsm8k) | Math | 100 | 0.870 | 0.870 | **0.000** |
161
  | [TruthfulQA](https://huggingface.co/datasets/truthfulqa/truthful_qa) | Factual | 100 | 0.530 | 0.560 | **+0.030** |
162
 
163
+ **Compression Benchmarks** — Accuracy after full compression stack:
164
 
165
  | Benchmark | Category | N | Accuracy | Compression | Method |
166
  |-----------|----------|---|----------|-------------|--------|
 
186
 
187
  ---
188
 
189
+ ## Key Capabilities
190
 
191
+ ### Lossless Compression
 
 
 
 
192
 
193
+ Headroom never throws data away. It compresses aggressively, stores the originals, and gives the LLM a tool to retrieve full details when needed. When it compresses 500 items to 20, it tells the model *what was omitted* ("87 passed, 2 failed, 1 error") so the model knows when to ask for more.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
194
 
195
+ ### Smart Content Detection
 
 
196
 
197
+ Auto-detects what's in your context — JSON arrays, code, logs, plain text — and routes each to the best compressor. JSON goes to SmartCrusher, code goes through AST-aware compression (Python, JS, Go, Rust, Java, C++), prose goes to LLMLingua-2.
198
 
199
+ ### Cache Optimization
 
 
 
 
 
200
 
201
+ Stabilizes message prefixes so your provider's KV cache actually works. Claude offers a 90% read discount on cached prefixes — but almost no framework takes advantage of it. Headroom does.
202
 
203
+ ### Failure Learning
204
 
205
+ ```bash
206
+ headroom learn # Analyze past Claude Code sessions, show recommendations
207
+ headroom learn --apply # Write learnings to CLAUDE.md and MEMORY.md
208
+ headroom learn --all --apply # Learn across all your projects
209
+ ```
210
 
211
+ Reads your conversation history, finds every failed tool call, correlates it with what eventually succeeded, and writes specific corrections into your project files. Next session starts smarter. **[Learn docs](docs/learn.md)**
 
 
 
 
 
 
 
 
 
212
 
213
+ <p align="center">
214
+ <img src="headroom_learn.gif" alt="headroom learn demo" width="800">
215
+ </p>
216
+
217
+ ### Image Compression
218
 
219
+ 40-90% token reduction via trained ML router. Automatically selects the right resize/quality tradeoff per image.
220
+
221
+ <details>
222
+ <summary><b>All features</b></summary>
223
 
224
  | Feature | What it does |
225
  |---------|-------------|
 
229
  | **LLMLingua-2** | ML-based 20x text compression |
230
  | **CCR** | Reversible compression — LLM retrieves originals when needed |
231
  | **Compression Summaries** | Tells the LLM what was omitted ("3 errors, 12 failures") |
 
232
  | **CacheAligner** | Stabilizes prefixes for provider KV cache hits |
233
  | **IntelligentContext** | Score-based context management with learned importance |
234
  | **Image Compression** | 40-90% token reduction via trained ML router |
 
237
  | **Read Lifecycle** | Detects stale/superseded Read outputs, replaces with CCR markers |
238
  | **`headroom learn`** | Analyzes past failures, writes project-specific learnings to CLAUDE.md/MEMORY.md |
239
 
240
+ </details>
241
+
242
+ ---
243
+
244
+ ## Headroom vs Alternatives
245
+
246
+ Context compression is a new space. Here's how the approaches differ:
247
+
248
+ | | Approach | Scope | Deploy as | Framework integrations | Data stays local? | Reversible |
249
+ |---|---|---|---|---|---|---|
250
+ | **Headroom** | Multi-algorithm compression | All context (tool outputs, DB reads, RAG, files, logs, history) | Proxy, Python library, ASGI middleware, or callback | LangChain, Agno, LiteLLM, Strands, MCP | Yes (OSS) | Yes (CCR) |
251
+ | **[RTK](https://github.com/rtk-ai/rtk)** | CLI command rewriter | Shell command outputs | CLI wrapper | None | Yes (OSS) | No |
252
+ | **[Compresr](https://compresr.ai)** | Cloud compression API | Text sent to their API | API call | None | No | No |
253
+ | **[Token Company](https://thetokencompany.ai)** | Cloud compression API | Text sent to their API | API call | None | No | No |
254
+
255
+ **Use it however you want.** Headroom works as a standalone proxy (`headroom proxy`), a one-function Python library (`compress()`), ASGI middleware, or a LiteLLM callback. Already using LiteLLM, LangChain, or Agno? Drop Headroom in without replacing anything.
256
+
257
+ **Headroom + RTK work well together.** RTK rewrites CLI commands (`git show` → `git show --short`), Headroom compresses everything else (JSON arrays, code, logs, RAG results, conversation history). Use both.
258
+
259
+ **Headroom vs cloud APIs.** Compresr and Token Company are hosted services — you send your context to their servers, they compress and return it. Headroom runs locally. Your data never leaves your machine. You also get lossless compression (CCR): the LLM can retrieve the full original when it needs more detail.
260
+
261
+ ---
262
+
263
+ ## How It Works Inside
264
+
265
+ ```
266
+ Your prompt
267
+
268
+
269
+ 1. CacheAligner Stabilize prefix for KV cache
270
+
271
+
272
+ 2. ContentRouter Route each content type:
273
+ │ → SmartCrusher (JSON)
274
+ │ → CodeCompressor (code)
275
+ │ → LLMLingua (text)
276
+
277
+ 3. IntelligentContext Score-based token fitting
278
+
279
+
280
+ LLM Provider
281
+
282
+ Needs full details? LLM calls headroom_retrieve.
283
+ Originals are in the Compressed Store — nothing is thrown away.
284
+ ```
285
+
286
+ **Overhead**: 15-200ms compression latency (net positive for Sonnet/Opus). Full data: [Latency Benchmarks](docs/LATENCY_BENCHMARKS.md)
287
+
288
+ ---
289
+
290
+ ## Integrations
291
+
292
+ | Integration | Status | Docs |
293
+ |-------------|--------|------|
294
+ | `compress()` — one function | **Stable** | [Integration Guide](docs/integration-guide.md) |
295
+ | LiteLLM callback | **Stable** | [Integration Guide](docs/integration-guide.md#litellm) |
296
+ | ASGI middleware | **Stable** | [Integration Guide](docs/integration-guide.md#asgi-middleware) |
297
+ | Proxy server | **Stable** | [Proxy Docs](docs/proxy.md) |
298
+ | Agno | **Stable** | [Agno Guide](docs/agno.md) |
299
+ | MCP (Claude Code) | **Stable** | [MCP Guide](docs/mcp.md) |
300
+ | Strands | **Stable** | [Strands Guide](docs/strands.md) |
301
+ | LangChain | **Experimental** | [LangChain Guide](docs/langchain.md) |
302
+
303
  ---
304
 
305
  ## Cloud Providers
 
349
 
350
  ---
351
 
352
+ ## Community
353
+
354
+ Questions, feedback, or just want to follow along? **[Join us on Discord](https://discord.gg/QEyNhaGA)**
355
+
356
+ ---
357
+
358
  ## Contributing
359
 
360
  ```bash
headroom/integrations/asgi.py CHANGED
@@ -111,7 +111,7 @@ class CompressionMiddleware:
111
  body_chunks: list[bytes] = []
112
 
113
  async def buffering_receive() -> MutableMapping[str, Any]:
114
- message = await receive()
115
  if message["type"] == "http.request":
116
  chunk = message.get("body", b"")
117
  if chunk:
@@ -169,7 +169,7 @@ class CompressionMiddleware:
169
  if not body_sent:
170
  body_sent = True
171
  return {"type": "http.request", "body": full_body, "more_body": False}
172
- result = await receive()
173
  return result
174
 
175
  # Wrap send to inject compression headers
 
111
  body_chunks: list[bytes] = []
112
 
113
  async def buffering_receive() -> MutableMapping[str, Any]:
114
+ message: MutableMapping[str, Any] = await receive()
115
  if message["type"] == "http.request":
116
  chunk = message.get("body", b"")
117
  if chunk:
 
169
  if not body_sent:
170
  body_sent = True
171
  return {"type": "http.request", "body": full_body, "more_body": False}
172
+ result: MutableMapping[str, Any] = await receive()
173
  return result
174
 
175
  # Wrap send to inject compression headers
headroom/proxy/server.py CHANGED
@@ -250,9 +250,7 @@ def _build_prefix_cache_stats(
250
  _openai_prefixes = ("gpt", "o1", "o3", "o4")
251
  is_match = (
252
  (provider == "anthropic" and "claude" in model_name)
253
- or (provider == "openai" and any(
254
- p in model_name for p in _openai_prefixes
255
- ))
256
  or (provider == "gemini" and "gemini" in model_name)
257
  or (provider == "bedrock" and "claude" in model_name)
258
  )
@@ -2132,14 +2130,9 @@ class HeadroomProxy:
2132
  f"[{request_id}] Memory: Added beta header: {key}={headers[key]}"
2133
  )
2134
 
2135
- # Query Echo: re-inject user's question after compressed tool outputs
2136
- # Helps LLM attend to the question after reading dense compressed data
2137
- if tokens_saved > 0:
2138
- from headroom.transforms.query_echo import extract_user_query, inject_query_echo
2139
-
2140
- user_query = extract_user_query(messages) # From original messages
2141
- if inject_query_echo(optimized_messages, user_query, tokens_saved, original_tokens):
2142
- logger.debug(f"[{request_id}] Query echo injected after compression")
2143
 
2144
  # Update body
2145
  body["messages"] = optimized_messages
@@ -4475,13 +4468,7 @@ class HeadroomProxy:
4475
  f"[{request_id}] CCR: Tool already present (MCP?), skipped injection for hashes: {injector.detected_hashes}"
4476
  )
4477
 
4478
- # Query Echo: re-inject user's question after compressed tool outputs
4479
- if tokens_saved > 0:
4480
- from headroom.transforms.query_echo import extract_user_query, inject_query_echo
4481
-
4482
- user_query = extract_user_query(messages)
4483
- if inject_query_echo(optimized_messages, user_query, tokens_saved, original_tokens):
4484
- logger.debug(f"[{request_id}] Query echo injected after compression")
4485
 
4486
  body["messages"] = optimized_messages
4487
  if tools is not None:
@@ -5542,13 +5529,7 @@ class HeadroomProxy:
5542
  tokens_saved = max(0, original_tokens - optimized_tokens)
5543
  optimization_latency = (time.time() - start_time) * 1000
5544
 
5545
- # Query Echo: re-inject user's question after compressed tool outputs
5546
- if tokens_saved > 0:
5547
- from headroom.transforms.query_echo import extract_user_query, inject_query_echo
5548
-
5549
- user_query = extract_user_query(messages)
5550
- if inject_query_echo(optimized_messages, user_query, tokens_saved, original_tokens):
5551
- logger.debug(f"[{request_id}] Query echo injected after Gemini compression")
5552
 
5553
  # Convert back to Gemini format if optimized
5554
  if optimized_messages != messages:
@@ -5863,7 +5844,9 @@ class HeadroomProxy:
5863
  logger.debug(f"[{request_id}] Failed to parse Gemini token count response: {e}")
5864
 
5865
  # Track stats
5866
- tokens_saved = max(0, original_tokens - compressed_tokens) if compressed_tokens > 0 else 0
 
 
5867
 
5868
  await self.metrics.record_request(
5869
  provider="gemini",
 
250
  _openai_prefixes = ("gpt", "o1", "o3", "o4")
251
  is_match = (
252
  (provider == "anthropic" and "claude" in model_name)
253
+ or (provider == "openai" and any(p in model_name for p in _openai_prefixes))
 
 
254
  or (provider == "gemini" and "gemini" in model_name)
255
  or (provider == "bedrock" and "claude" in model_name)
256
  )
 
2130
  f"[{request_id}] Memory: Added beta header: {key}={headers[key]}"
2131
  )
2132
 
2133
+ # Query Echo: disabled hurts prefix caching in long conversations.
2134
+ # The echo changes every turn, invalidating the cached prefix.
2135
+ # To re-enable, uncomment and set query_echo_enabled on ProxyConfig.
 
 
 
 
 
2136
 
2137
  # Update body
2138
  body["messages"] = optimized_messages
 
4468
  f"[{request_id}] CCR: Tool already present (MCP?), skipped injection for hashes: {injector.detected_hashes}"
4469
  )
4470
 
4471
+ # Query Echo: disabled hurts prefix caching in long conversations.
 
 
 
 
 
 
4472
 
4473
  body["messages"] = optimized_messages
4474
  if tools is not None:
 
5529
  tokens_saved = max(0, original_tokens - optimized_tokens)
5530
  optimization_latency = (time.time() - start_time) * 1000
5531
 
5532
+ # Query Echo: disabled hurts prefix caching in long conversations.
 
 
 
 
 
 
5533
 
5534
  # Convert back to Gemini format if optimized
5535
  if optimized_messages != messages:
 
5844
  logger.debug(f"[{request_id}] Failed to parse Gemini token count response: {e}")
5845
 
5846
  # Track stats
5847
+ tokens_saved = (
5848
+ max(0, original_tokens - compressed_tokens) if compressed_tokens > 0 else 0
5849
+ )
5850
 
5851
  await self.metrics.record_request(
5852
  provider="gemini",