fix: align docs and prune dead compatibility surfaces

This commit is contained in:
Tejas Chopra 2026-05-09 14:07:59 -07:00
parent eaf5980b4a
commit 359e8c9a5b
32 changed files with 203 additions and 264 deletions

View file

@ -156,11 +156,8 @@ response = client.chat.completions.create(
messages=messages,
)
# CCR is enabled by default. To disable:
# headroom proxy --no-ccr-responses
# To disable proactive expansion:
# headroom proxy --no-ccr-expansion
# CCR is enabled by default in the current proxy path. Use --no-optimize for
# full passthrough behavior.
```
</Tab>
</Tabs>

View file

@ -89,7 +89,7 @@ config = CodeCompressorConfig(
max_body_lines=5, # Lines to keep per function body
min_tokens_for_compression=100, # Skip small content
language_hint=None, # Auto-detect if None
fallback_to_llmlingua=True, # Use LLMLingua for unknown langs
fallback_to_kompress=True, # Use Kompress for unknown langs
)
compressor = CodeAwareCompressor(config)
@ -110,7 +110,7 @@ result = compressor.compress(code)
| `max_body_lines` | `5` | Max lines to keep per function body |
| `min_tokens_for_compression` | `100` | Skip files smaller than this |
| `language_hint` | `None` | Override language detection |
| `fallback_to_llmlingua` | `True` | Use LLMLingua for unsupported languages |
| `fallback_to_kompress` | `True` | Use Kompress for unsupported languages |
## Before and After

View file

@ -221,6 +221,7 @@ normalized = weights.normalized()
headroom proxy \
--port 8787 \ # Port to listen on
--host 0.0.0.0 \ # Host to bind to
--mode token \ # token compression mode; use cache for prefix-cache stability
--budget 10.00 \ # Daily budget limit in USD
--log-file headroom.jsonl # Log file path
```
@ -234,18 +235,28 @@ headroom proxy --no-optimize
# Disable semantic caching
headroom proxy --no-cache
# Enable LLMLingua ML compression
headroom proxy --llmlingua
headroom proxy --llmlingua --llmlingua-device cuda --llmlingua-rate 0.4
# Preserve provider prefix-cache stability instead of maximizing token removal
headroom proxy --mode cache
# Enable memory and live learning
headroom proxy --memory
headroom proxy --learn --min-evidence 3
```
## Environment Variables
| Variable | Description | Default |
|----------|-------------|---------|
| `HEADROOM_LOG_LEVEL` | Logging level | `INFO` |
| `HEADROOM_STORE_URL` | Database URL | temp directory |
| `HEADROOM_DEFAULT_MODE` | Default mode | `optimize` |
| `HEADROOM_HOST` | Proxy bind host | `127.0.0.1` |
| `HEADROOM_PORT` | Proxy bind port | `8787` |
| `HEADROOM_MODE` | Proxy optimization mode: `token` or `cache` | `token` |
| `HEADROOM_WORKERS` | Uvicorn worker count | `1` |
| `HEADROOM_LIMIT_CONCURRENCY` | Maximum concurrent connections before 503 | `1000` |
| `HEADROOM_MAX_CONNECTIONS` | Maximum upstream HTTP connections | `500` |
| `HEADROOM_MAX_KEEPALIVE` | Maximum upstream keep-alive connections | `100` |
| `HEADROOM_BUDGET` | Daily budget limit in USD | -- |
| `HEADROOM_TELEMETRY` | Set to `off` to disable anonymous telemetry | enabled |
| `HEADROOM_STATELESS` | Set to `true` to disable filesystem writes | `false` |
| `HEADROOM_MODEL_LIMITS` | Custom model config (JSON string or file path) | -- |
| `HEADROOM_BASE_URL` | Base URL of the Headroom proxy (TypeScript SDK) | `http://localhost:8787` |
| `HEADROOM_API_KEY` | API key for Headroom Cloud authentication | -- |

View file

@ -130,11 +130,10 @@ compressor = ImageCompressor(
### Proxy Configuration
```bash
# Enable image compression (default)
headroom proxy --image-optimize
# Disable image compression
headroom proxy --no-image-optimize
# Image optimization is part of the ContentRouter path when the optional image
# dependencies are installed. There are no public proxy CLI image toggles in
# the current release.
headroom proxy
```
## Performance

View file

@ -173,9 +173,9 @@ These variables configure Headroom at runtime. Set them in your shell, `.env` fi
| Variable | Default | Description |
|---|---|---|
| `HEADROOM_PORT` | `8787` | Port the proxy listens on |
| `HEADROOM_HOST` | `0.0.0.0` | Host the proxy binds to |
| `HEADROOM_MODE` | `optimize` | Default mode: `optimize`, `audit`, or `passthrough` |
| `HEADROOM_LOG_LEVEL` | `INFO` | Logging level |
| `HEADROOM_HOST` | `127.0.0.1` | Host the proxy binds to |
| `HEADROOM_MODE` | `token` | Default optimization mode: `token` or `cache` |
| `HEADROOM_TELEMETRY` | enabled | Set to `off` to disable anonymous telemetry |
### TypeScript SDK

View file

@ -95,8 +95,7 @@ curl http://localhost:8787/health
{
"status": "healthy",
"version": "0.1.0",
"uptime_seconds": 3600,
"llmlingua_enabled": false
"uptime_seconds": 3600
}
```

View file

@ -30,48 +30,67 @@ Telemetry is enabled by default. Opt out with `HEADROOM_TELEMETRY=off` or `--no-
|--------|---------|-------------|
| `--host` | `127.0.0.1` | Host to bind to |
| `--port` | `8787` | Port to bind to |
| `--workers` | `1` | Number of Uvicorn worker processes |
| `--limit-concurrency` | `1000` | Maximum concurrent connections before Uvicorn returns 503 |
| `--max-connections` | `500` | Maximum upstream HTTP connections |
| `--max-keepalive` | `100` | Maximum upstream keep-alive connections |
| `--mode` | `token` | Optimization mode: `token` prioritizes compression, `cache` preserves provider prefix-cache stability |
| `--no-optimize` | `false` | Disable optimization (passthrough mode) |
| `--no-cache` | `false` | Disable semantic caching |
| `--no-rate-limit` | `false` | Disable rate limiting |
| `--log-file` | None | Path to JSONL log file |
| `--log-messages` | `false` | Store full request/response content for the live feed |
| `--budget` | None | Daily budget limit in USD |
| `--openai-api-url` | `https://api.openai.com` | Custom OpenAI API URL |
| `--anthropic-api-url` | Anthropic default | Custom Anthropic API URL |
| `--gemini-api-url` | Gemini default | Custom Gemini API URL |
| `--backend` | `anthropic` | Backend: `anthropic`, `bedrock`, `openrouter`, `anyllm`, or `litellm-<provider>` |
| `--no-telemetry` | `false` | Disable anonymous telemetry |
| `--stateless` | `false` | Disable filesystem writes and keep runtime state in memory |
### Context management
| Option | Default | Description |
|--------|---------|-------------|
| `--no-intelligent-context` | `false` | Fall back to RollingWindow (oldest-first drops) |
| `--no-intelligent-scoring` | `false` | Disable multi-factor importance scoring |
| `--no-compress-first` | `false` | Disable trying deeper compression before dropping |
| `--mode token` | `token` | Prioritize token compression. This is the default. |
| `--mode cache` | `token` | Preserve prior turns to maximize provider prefix-cache hit rate. |
| `--intercept-tool-results` | `false` | Opt into tool-result interceptors such as ast-grep Read outlining. |
| `--no-read-lifecycle` | `false` | Disable stale/superseded Read-output compression. |
| `--code-aware` / `--no-code-aware` | disabled | Enable or disable AST-based code compression. Requires `headroom-ai[code]`. |
| `--code-graph` | `false` | Index the current project and watch files via codebase-memory-mcp. |
By default, the proxy uses **IntelligentContextManager** which scores messages by recency, semantic similarity, TOIN-learned patterns, error indicators, and forward references. Dropped messages are stored in CCR for retrieval.
By default, the proxy uses the shared **ContentRouter** pipeline. It routes text, logs, JSON, code, images, and tool outputs through the currently enabled compressors and preserves reversible CCR markers where applicable.
```bash
# Use legacy RollingWindow
headroom proxy --no-intelligent-context
# Maximize compression
headroom proxy --mode token
# Faster but less intelligent scoring
headroom proxy --no-intelligent-scoring
# Preserve provider prefix cache stability
headroom proxy --mode cache
```
### LLMLingua (ML compression)
### Optional features
| Option | Default | Description |
|--------|---------|-------------|
| `--llmlingua` | `false` | Enable LLMLingua-2 ML-based compression |
| `--llmlingua-device` | `auto` | Device: `auto`, `cuda`, `cpu`, `mps` |
| `--llmlingua-rate` | `0.3` | Target compression rate (0.3 = keep 30%) |
| `--memory` | `false` | Enable persistent user memory and provider-appropriate memory tools |
| `--memory-db-path` | `{cwd}/.headroom/memory.db` | Override the memory SQLite path |
| `--no-memory-tools` | `false` | Disable automatic memory tool injection |
| `--no-memory-context` | `false` | Disable automatic memory context injection |
| `--memory-top-k` | `10` | Number of memories to inject as context |
| `--learn` | `false` | Enable live traffic learning; implies `--memory` |
| `--no-learn` | `false` | Explicitly disable traffic learning |
| `--min-evidence` | `5` | Minimum observations before a learned pattern is persisted |
| `--codex-wire-debug` | `false` | Write local Codex wire snapshots and matching proxy log traces |
```bash
pip install "headroom-ai[llmlingua]"
headroom proxy --llmlingua --llmlingua-device cuda
headroom proxy --llmlingua --llmlingua-rate 0.2
headroom proxy --memory
headroom proxy --learn --min-evidence 3
headroom proxy --codex-wire-debug
```
<Callout type="info" title="LLMLingua resource cost">
LLMLingua adds ~2 GB of dependencies (torch, transformers), 10-30s cold start, and ~1 GB RAM. Enable when maximum compression justifies the cost.
<Callout type="info" title="LLMLingua removed from the proxy CLI">
The old LLMLingua proxy toggles are no longer part of the CLI. Headroom's proxy compression path uses ContentRouter plus the current built-in compressors, including Kompress where applicable.
</Callout>
## API endpoints

View file

@ -11,7 +11,7 @@ Headroom provides specialized compressors for text-based content that isn't JSON
| `LogCompressor` | Build/test logs | Errors, stack traces, summaries | 85-95% |
| `DiffCompressor` | Unified diffs | Changed lines, context | 60-80% |
| `TextCompressor` | General text | Relevant paragraphs, anchors | 60-80% |
| `LLMLinguaCompressor` | Any text (max compression) | Semantic meaning via ML | 80-95% |
| `KompressCompressor` | General text fallback | Learned token scoring via ONNX | 30-50% |
## SearchCompressor
@ -134,21 +134,12 @@ print(result.compressed)
- Headers and section markers
- Document structure and organization
## LLMLingua (Optional, Maximum Compression)
For maximum compression on any text, Headroom integrates with Microsoft's LLMLingua-2, a BERT-based token classifier trained via GPT-4 distillation. It achieves up to 20x compression while preserving semantic meaning.
## Kompress
```python
from headroom.transforms import LLMLinguaCompressor, LLMLinguaConfig
from headroom.transforms.kompress_compressor import KompressCompressor
config = LLMLinguaConfig(
device="auto", # auto, cuda, cpu, mps
code_compression_rate=0.4, # Conservative for code
json_compression_rate=0.35, # Moderate for JSON
text_compression_rate=0.25, # Aggressive for text
)
compressor = LLMLinguaCompressor(config)
compressor = KompressCompressor()
result = compressor.compress(long_output)
print(f"Before: {result.original_tokens} tokens")
@ -156,22 +147,10 @@ print(f"After: {result.compressed_tokens} tokens")
print(f"Saved: {result.savings_percentage:.1f}%")
```
<Callout type="info" title="LLMLingua is opt-in">
LLMLingua adds ~2GB of model weights and 50-200ms latency per request. Install it only when you need maximum compression: `pip install "headroom-ai[llmlingua]"`
<Callout type="info" title="LLMLingua was removed">
The old LLMLingua transform and helper functions are no longer exported. Use Kompress and ContentRouter for text compression.
</Callout>
### Memory Management
```python
from headroom.transforms import unload_llmlingua_model, is_llmlingua_model_loaded
# Check if model is loaded
print(is_llmlingua_model_loaded()) # True
# Free ~1GB RAM when done
unload_llmlingua_model()
```
## Content Type Detection
If you're building your own routing logic, you can use the content type detector directly:
@ -200,7 +179,7 @@ The ContentRouter selects the right compressor automatically. Here's when each f
| pytest, npm, cargo markers | LogCompressor | Build tool output patterns |
| `---/+++` and `@@` markers | DiffCompressor | Unified diff format |
| Prose, documentation | TextCompressor | Fallback for non-structured text |
| Any (max compression mode) | LLMLinguaCompressor | Explicitly enabled |
| Long plain text | KompressCompressor | ContentRouter fallback |
## Performance
@ -210,4 +189,4 @@ The ContentRouter selects the right compressor automatically. Here's when each f
| LogCompressor | 5,000 lines | 100-200 lines | ~3ms |
| DiffCompressor | Large diff | Changed hunks only | ~2ms |
| TextCompressor | 10,000 chars | 2,000 chars | ~2ms |
| LLMLinguaCompressor | Any text | 5-20% of original | 50-200ms |
| KompressCompressor | Plain text | 50-70% of original | model-dependent |

View file

@ -25,8 +25,7 @@ The developer using an AI coding agent with Headroom.
export ANTHROPIC_API_KEY=sk-...
# Optional overrides
export HEADROOM_MODE=compress
export HEADROOM_CACHE_ENABLED=true
export HEADROOM_MODE=token
```
---
@ -140,10 +139,9 @@ The person assessing Headroom for organizational adoption.
**Security Configuration:**
```bash
# Maximum privacy settings
HEADROOM_CACHE_ENABLED=false
HEADROOM_TELEMETRY_ENABLED=false
HEADROOM_LEARN_ENABLED=false
HEADROOM_DASHBOARD_ENABLED=false
HEADROOM_TELEMETRY=off
HEADROOM_STATELESS=true
headroom proxy --no-cache --no-optimize
```
---

View file

@ -4,7 +4,7 @@
## Proxy Modes
### Passthrough Mode
### Passthrough
Headroom forwards requests without modification.
@ -14,7 +14,7 @@ Headroom forwards requests without modification.
- No compression applied
- Useful for testing or debugging
**Configuration:** `HEADROOM_MODE=audit`
**Configuration:** `headroom proxy --no-optimize`
**Request Flow:**
```
@ -23,7 +23,7 @@ Client → Proxy → Provider API → Response
---
### Optimize Mode
### Token Mode
Headroom applies deterministic transforms to requests.
@ -34,7 +34,7 @@ Headroom applies deterministic transforms to requests.
- CCR caching enabled
- Token budget enforced
**Configuration:** `HEADROOM_MODE=optimize`
**Configuration:** `HEADROOM_MODE=token` or `headroom proxy --mode token`
**Request Flow:**
```
@ -45,17 +45,16 @@ Client → Proxy → [SmartCrusher] → [CacheAligner]
---
### Simulate Mode
### Cache Mode
Headroom returns transform plan without API call.
Headroom preserves prior turns where possible to maximize provider prefix-cache hit rate.
**Behavior:**
- Analyzes content for compression opportunity
- Returns TransformResult with planned transforms
- No actual compression or provider call
- Useful for debugging/optimization
- Freezes provider-confirmed cached prefixes
- Compresses the mutable tail of the request
- Trades some token savings for better cache stability
**Configuration:** `HEADROOM_MODE=simulate`
**Configuration:** `HEADROOM_MODE=cache` or `headroom proxy --mode cache`
---
@ -65,9 +64,9 @@ Session modes control how Headroom handles context windows.
| Mode | Description | Use Case |
|------|-------------|----------|
| `audit` | Observe only, no modifications | Monitoring |
| `optimize` | Apply deterministic transforms | Production |
| `simulate` | Return plan without API call | Debugging |
| `token` | Prioritize token removal | Default proxy mode |
| `cache` | Preserve prior turns for provider prefix-cache stability | Long Claude/Codex sessions |
| passthrough | Disable optimization with `--no-optimize` | Debugging |
---

View file

@ -22,15 +22,14 @@
## Compression Capabilities
### Semantic Cache
### Proxy Cache
**Description:** Caches semantically similar requests using CCR pattern.
**Description:** The proxy has semantic cache support and CCR-backed retrieval, controlled by CLI configuration.
**Configuration:**
```bash
HEADROOM_CACHE_ENABLED=true
HEADROOM_CACHE_TTL=3600
HEADROOM_CACHE_MAX_SIZE=10000
headroom proxy # cache enabled by default
headroom proxy --no-cache
```
**Behavior:**

View file

@ -62,17 +62,16 @@
## Configuration for Maximum Privacy
```bash
HEADROOM_CACHE_ENABLED=false
HEADROOM_TELEMETRY_ENABLED=false
HEADROOM_LEARN_ENABLED=false
HEADROOM_DASHBOARD_ENABLED=false
HEADROOM_TELEMETRY=off
HEADROOM_STATELESS=true
headroom proxy --no-cache --no-optimize
```
This configuration results in:
- No prompt data stored
- No data exported
- No analytics collected
- Headroom acts as pure compression proxy
- Headroom acts as a passthrough proxy
---

View file

@ -101,9 +101,9 @@ CREATE TABLE compression_store (
| Variable | Default | Description |
|----------|---------|-------------|
| `HEADROOM_CACHE_ENABLED` | `true` | Enable compression cache |
| `HEADROOM_CACHE_TTL` | `3600` | Cache TTL in seconds |
| `HEADROOM_CACHE_MAX_SIZE` | `10000` | Max cache entries |
| CLI `--no-cache` | unset | Disable semantic cache for the proxy process |
| `HEADROOM_WORKSPACE_DIR` | `~/.headroom` | Workspace root for proxy state, logs, memory, and savings |
| `HEADROOM_STATELESS` | `false` | Disable filesystem writes and keep runtime state in memory |
---

View file

@ -30,8 +30,7 @@ services:
- "8787:8787"
environment:
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
- HEADROOM_MODE=compress
- HEADROOM_CACHE_ENABLED=true
- HEADROOM_MODE=token
volumes:
- headroom-data:/root/.headroom
@ -121,14 +120,12 @@ deployment:
| Variable | Default | Description |
|----------|---------|-------------|
| `HEADROOM_MODE` | `audit` | Proxy mode (audit/optimize/simulate) |
| `HEADROOM_MODE` | `token` | Proxy mode (`token` or `cache`) |
| `HEADROOM_PORT` | `8787` | Proxy port |
| `HEADROOM_HOST` | `0.0.0.0` | Proxy host |
| `HEADROOM_HOST` | `127.0.0.1` | Proxy host |
| `ANTHROPIC_API_KEY` | - | Anthropic API key |
| `OPENAI_API_KEY` | - | OpenAI API key |
| `HEADROOM_CACHE_ENABLED` | `true` | Enable cache |
| `HEADROOM_CACHE_TTL` | `3600` | Cache TTL |
| `HEADROOM_TELEMETRY_ENABLED` | `true` | Enable telemetry |
| `HEADROOM_TELEMETRY` | enabled | Set to `off` to disable telemetry |
### Config File

View file

@ -15,10 +15,19 @@ headroom proxy [OPTIONS]
**Options:**
| Flag | Default | Description |
|------|---------|-------------|
| `--host` | `0.0.0.0` | Bind host |
| `--host` | `127.0.0.1` | Bind host |
| `--port` | `8787` | Bind port |
| `--llmlingua-device` | `cpu` | LLMLingua device (cpu/cuda) |
| `--config` | - | Config file path |
| `--mode` | `token` | Optimization mode: `token` or `cache` |
| `--workers` | `1` | Uvicorn worker processes |
| `--limit-concurrency` | `1000` | Maximum concurrent connections before 503 |
| `--no-optimize` | `false` | Passthrough mode |
| `--no-cache` | `false` | Disable semantic cache |
| `--no-rate-limit` | `false` | Disable rate limiting |
| `--memory` | `false` | Enable persistent memory |
| `--learn` | `false` | Enable live traffic learning |
| `--backend` | `anthropic` | Backend: anthropic, bedrock, openrouter, anyllm, or litellm-* |
| `--no-telemetry` | `false` | Disable anonymous telemetry |
| `--stateless` | `false` | Disable filesystem writes |
---
@ -55,16 +64,17 @@ headroom install [OPTIONS]
### `headroom mcp`
Start MCP server.
Manage the Headroom MCP server.
```bash
headroom mcp [OPTIONS]
headroom mcp [OPTIONS] COMMAND [ARGS]...
```
**Options:**
| Flag | Default | Description |
|------|---------|-------------|
| `--port` | `8766` | MCP server port |
**Commands:**
- `install` — Install the MCP server into detected coding agents
- `serve` — Start the stdio MCP server
- `status` — Check configuration status
- `uninstall` — Remove Headroom MCP config
---
@ -128,9 +138,12 @@ headroom learn [OPTIONS]
**Options:**
| Flag | Default | Description |
|------|---------|-------------|
| `--agent` | `auto` | Agent type |
| `--mode` | `auto` | Learn mode |
| `--session` | - | Session ID |
| `--project` | current directory | Project directory to analyze |
| `--all` | `false` | Analyze all discovered projects |
| `--apply` | `false` | Write recommendations instead of dry-run |
| `--agent` | `auto` | Agent to analyze: auto, claude, codex, gemini, or plugin |
| `--model` | auto | LLM model for analysis |
| `--workers` | auto | Parallel workers for session scanning |
---
@ -210,12 +223,16 @@ X-Headroom-Compressed-Tokens: 5325
| Variable | Default | Description |
|----------|---------|-------------|
| `HEADROOM_MODE` | `audit` | Operation mode (audit/optimize/simulate) |
| `HEADROOM_MODE` | `token` | Proxy optimization mode (`token` or `cache`) |
| `HEADROOM_PORT` | `8787` | Proxy port |
| `HEADROOM_HOST` | `0.0.0.0` | Proxy host |
| `HEADROOM_STORE_URL` | `sqlite:///headroom.db` | Storage URL |
| `HEADROOM_PROXY_URL` | `http://localhost:8787` | Proxy URL |
| `HEADROOM_LOG_LEVEL` | `INFO` | Log level |
| `HEADROOM_HOST` | `127.0.0.1` | Proxy host |
| `HEADROOM_WORKERS` | `1` | Uvicorn worker count |
| `HEADROOM_LIMIT_CONCURRENCY` | `1000` | Maximum concurrent connections before 503 |
| `HEADROOM_MAX_CONNECTIONS` | `500` | Maximum upstream HTTP connections |
| `HEADROOM_MAX_KEEPALIVE` | `100` | Maximum upstream keep-alive connections |
| `HEADROOM_BUDGET` | - | Daily budget limit in USD |
| `HEADROOM_TELEMETRY` | enabled | Set to `off` to disable anonymous telemetry |
| `HEADROOM_STATELESS` | `false` | Disable filesystem writes |
### Provider
@ -230,12 +247,11 @@ X-Headroom-Compressed-Tokens: 5325
| Variable | Default | Description |
|----------|---------|-------------|
| `HEADROOM_CACHE_ENABLED` | `true` | Enable cache |
| `HEADROOM_CACHE_TTL` | `3600` | Cache TTL in seconds |
| `HEADROOM_CACHE_MAX_SIZE` | `10000` | Max cache entries |
| `HEADROOM_LEARN_ENABLED` | `false` | Enable learn |
| `HEADROOM_DASHBOARD_ENABLED` | `false` | Enable dashboard |
| `HEADROOM_TELEMETRY_ENABLED` | `true` | Enable telemetry |
| `HEADROOM_TELEMETRY` | enabled | Set to `off` to disable telemetry |
| `HEADROOM_MIN_EVIDENCE` | `5` | Minimum observations before live learning persists a pattern |
| `HEADROOM_PROXY_EXTENSIONS` | - | Comma-separated proxy extensions to enable |
| `HEADROOM_STATELESS` | `false` | Disable filesystem writes |
| `HEADROOM_MODEL_LIMITS` | - | Model limits override as JSON or file path |
### Compression

View file

@ -102,7 +102,7 @@ logging:
- Top compressed endpoints
- Session overview
**Requires:** `HEADROOM_DASHBOARD_ENABLED=true`
**Requires:** the proxy process to be running. The dashboard is served by default at `/dashboard`.
---

View file

@ -165,8 +165,8 @@ rate(headroom_cache_hits_total[5m]) / (rate(headroom_cache_hits_total[5m]) + rat
| Symptom | Cause | Solution |
|---------|-------|----------|
| "Connection refused" | Proxy not running | `headroom proxy start` |
| "Cache miss on every request" | Cache disabled | Set `HEADROOM_CACHE_ENABLED=true` |
| "Connection refused" | Proxy not running | Start it with `headroom proxy` |
| "Cache miss on every request" | Cache disabled | Start without `--no-cache` |
| "No savings shown" | Database locked | Check file permissions |
| "Provider timeout" | Network issue | Check firewall/proxy |

View file

@ -37,9 +37,8 @@
All settings can be overridden via environment variables:
```bash
HEADROOM_CACHE_ENABLED=false
HEADROOM_MODE=passthrough
HEADROOM_MAX_TOKENS=8192
HEADROOM_MODE=token
headroom proxy --no-cache
```
### Config File

View file

@ -299,7 +299,7 @@ def mcp_status() -> None:
@click.option(
"--direct",
is_flag=True,
help="Use direct CompressionStore access (same process as proxy)",
help="(Deprecated, ignored) Direct CompressionStore access is no longer supported",
)
@click.option(
"--debug",
@ -343,10 +343,13 @@ def mcp_serve(proxy_url: str | None, direct: bool, debug: bool) -> None:
# Use default if not specified
effective_proxy_url = proxy_url or DEFAULT_PROXY_URL
server = create_ccr_mcp_server(
proxy_url=effective_proxy_url,
direct_mode=direct,
)
if direct:
click.echo(
"Warning: --direct is deprecated and ignored; MCP retrieval uses the proxy URL.",
err=True,
)
server = create_ccr_mcp_server(proxy_url=effective_proxy_url)
async def run() -> None:
try:

View file

@ -2,7 +2,7 @@
from __future__ import annotations
from dataclasses import dataclass, field
from dataclasses import InitVar, dataclass, field
from datetime import datetime
from enum import Enum
from typing import Any, Literal
@ -473,10 +473,10 @@ class HeadroomConfig:
# to the top-level config when PR-B1 retired the rolling-window stage.
output_buffer_tokens: int = 4000
# Content Router - intelligent content-type based compression
# Routes content to appropriate compressor (Kompress for text, SmartCrusher for JSON,
# CodeCompressor for code, LogCompressor for logs, etc.)
content_router_enabled: bool = True
# Deprecated compatibility argument. ContentRouter is always present
# in the default pipeline; accepting this avoids breaking old config
# constructors while keeping it out of runtime state.
content_router_enabled: InitVar[bool | None] = None
# Tool-result interceptors (ast-grep Read outline, etc.). Opt-in for now.
# Env var HEADROOM_INTERCEPT_ENABLED=1 also enables (for CLI `--intercept-tool-results`).

View file

@ -1599,12 +1599,13 @@ class OpenAIHandlerMixin:
metadata={"path": request.url.path, "stream": stream},
)
# PR-C5: Python no longer compresses /v1/responses — Rust handles
# item-aware compression natively (see crates/headroom-proxy/src/
# handlers/responses.rs). We synthesise a minimal `messages` list
# purely for downstream memory injection + telemetry; list-typed
# `input` is consulted via `body["input"]` directly via the
# live-zone-tail helpers below.
# /v1/responses uses provider-specific CompressionUnit extraction
# below, then routes mutable text through ContentRouter. The
# standalone Rust proxy has native item-aware handling, but the
# Python CLI runtime does not run that proxy today. We synthesise a
# minimal `messages` list purely for downstream memory injection and
# telemetry; list-typed `input` is consulted directly by the unit
# extraction helpers.
input_data = body.get("input", "")
instructions = body.get("instructions")
@ -1698,10 +1699,9 @@ class OpenAIHandlerMixin:
tokenizer = get_tokenizer(model)
original_tokens = tokenizer.count_messages(messages)
# PR-C5: Python compression on /v1/responses is retired — the Rust
# handler at crates/headroom-proxy/src/handlers/responses.rs is the
# canonical compression path. Defaults below feed downstream
# telemetry and memory injection without invoking the pipeline.
# Defaults below feed downstream telemetry and memory injection.
# If optimization remains enabled, the Responses payload is compressed
# later through `_compress_openai_responses_payload`.
optimized_messages = messages
optimized_tokens = original_tokens
tokens_saved = 0
@ -1864,16 +1864,11 @@ class OpenAIHandlerMixin:
else:
url = build_copilot_upstream_url(self.OPENAI_API_URL, "/v1/responses")
# Hot-fix (post-PR-C5): re-enable /v1/responses compression via the
# PyO3 inline call to the Rust live-zone dispatcher. PR-C5 retired
# the Python pipeline expecting that the standalone
# `crates/headroom-proxy` Rust binary would sit in front of the
# Python proxy and compress here. That binary is not deployed by
# the CLI today (`headroom proxy`, `headroom wrap codex` both run
# only the Python proxy), so /v1/responses traffic has been
# uncompressed since v0.20.16. This call closes that gap by
# invoking the same dispatcher in-process via `headroom._core`.
# All policy gating already happened upstream (auth_mode classify,
# The standalone Rust proxy has native /v1/responses item handling,
# but the default CLI runtime is this Python proxy. Compress the
# Python runtime path here by extracting mutable Responses text into
# CompressionUnits and routing them through ContentRouter. Policy
# gating already happened upstream (auth_mode classify,
# CompressionPolicy resolve at request entry).
if self.config.optimize and not _bypass:
try:
@ -2207,8 +2202,8 @@ class OpenAIHandlerMixin:
1. Accepts the client WebSocket
2. Receives the first message (``response.create`` request)
3. Opens an upstream WebSocket to OpenAI
4. Sends the request upstream as-is (PR-C5: Python compression on
/v1/responses retired Rust handles item-aware compression)
4. Compresses eligible `response.create` text through the Python
ContentRouter path, then sends the request upstream
5. Relays all subsequent messages bidirectionally
"""
try:
@ -2504,12 +2499,10 @@ class OpenAIHandlerMixin:
# deregister / metrics / stage-timings emission as usual.
return
# PR-C5 retired Python compression on this path expecting the
# standalone Rust proxy binary to take over. That binary is not
# deployed by the CLI today (`headroom proxy` runs only Python
# via uvicorn). Hot-fix follow-up to PR #406: the first frame
# is now compressed via the inline PyO3 binding right before
# upstream send (see the compression block further below).
# The standalone Rust proxy has a native Responses path, but the
# CLI runtime runs this Python proxy. Compress eligible
# `response.create` frames through the shared Python
# CompressionUnit + ContentRouter path before upstream send.
# Subsequent client→upstream frames are now ALSO compressed
# via `_maybe_compress_response_create_frame` in
# `_client_to_upstream` so long-lived subscription Codex

View file

@ -6,7 +6,7 @@ Extracted from server.py to keep the codebase maintainable.
from __future__ import annotations
from dataclasses import dataclass, field
from dataclasses import InitVar, dataclass, field
from datetime import datetime
from typing import Any, Literal
@ -139,8 +139,10 @@ class ProxyConfig:
# Read lifecycle management
read_lifecycle: bool = True
# Smart content routing
smart_routing: bool = True
# Deprecated compatibility argument. ContentRouter is always active in
# the Python proxy; accepting this avoids breaking old config constructors
# while keeping it out of runtime state.
smart_routing: InitVar[bool | None] = None
# Caching
cache_enabled: bool = True

View file

@ -2985,7 +2985,6 @@ if __name__ == "__main__":
if args.log_file
else os.environ.get("HEADROOM_LOG_FILE"),
log_full_messages=args.log_messages or _get_env_bool("HEADROOM_LOG_MESSAGES", False),
smart_routing=True,
code_aware_enabled=code_aware_enabled,
# Connection pool settings
max_connections=_get_env_int("HEADROOM_MAX_CONNECTIONS", args.max_connections),

View file

@ -69,7 +69,7 @@ import time
import warnings
from collections.abc import Callable
from dataclasses import dataclass, field
from typing import Any, Final, Literal
from typing import Any, Final
from .models import FieldSemantics, ToolSignature
@ -380,45 +380,6 @@ class ToolPattern:
return pattern
@dataclass
class _CompressionHint:
"""Internal recommendation envelope (PR-B5: private, observation-only).
Pre-B5 this was the public return type of `get_recommendation()`
the request-time hint API now retired. The dataclass is retained as
`_CompressionHint` purely for the deprecated stub's signature and
for the publish CLI's internal aggregation; no new code should
construct or consume it. Read recommendations from
`recommendations.toml` produced by `headroom.cli.toin_publish`.
"""
# Should we compress at all?
skip_compression: bool = False
# How aggressively to compress
max_items: int = 20
compression_level: Literal["none", "conservative", "moderate", "aggressive"] = "moderate"
# Which fields to preserve (never remove)
preserve_fields: list[str] = field(default_factory=list)
# Which strategy to use
recommended_strategy: str = "default"
# Why this recommendation
reason: str = ""
confidence: float = 0.0
# Source of recommendation
source: Literal["network", "local", "default"] = "default"
based_on_samples: int = 0
# === TOIN Evolution: Learned Field Semantics ===
# These enable zero-latency signal detection in SmartCrusher.
# field_hash -> FieldSemantics (learned semantic type, important values, etc.)
field_semantics: dict[str, FieldSemantics] = field(default_factory=dict)
@dataclass
class TOINConfig:
"""Configuration for the Tool Output Intelligence Network."""
@ -1008,7 +969,7 @@ class ToolIntelligenceNetwork:
sites from flooding logs.
Returns:
Always `None`. The legacy `_CompressionHint` envelope is no
Always `None`. The legacy compression-hint envelope is no
longer constructed at request time.
"""
cls = type(self)

View file

@ -98,11 +98,6 @@ class TransformPipeline:
# - Logs -> LogCompressor
# - Search results -> SearchCompressor
# - HTML -> HTMLExtractor
if not self.config.content_router_enabled:
logger.warning(
"HeadroomConfig.content_router_enabled=False is deprecated and ignored; "
"ContentRouter is always present in the default pipeline"
)
transforms.append(ContentRouter())
logger.info("Pipeline using ContentRouter for intelligent content-aware compression")

View file

@ -149,7 +149,7 @@ def test_pipeline_extension_manager_uses_canonical_stage_contract():
def test_default_transform_pipeline_always_uses_content_router() -> None:
config = HeadroomConfig(content_router_enabled=False)
config = HeadroomConfig()
pipeline = TransformPipeline(config)

View file

@ -420,7 +420,6 @@ class TestEndToEndTOINIntegration:
reset_compression_store()
config = ProxyConfig(
optimize=True, # Enable optimization
smart_routing=False, # Use legacy mode for simpler testing
cache_enabled=False,
rate_limit_enabled=False,
cost_tracking_enabled=False,

View file

@ -131,7 +131,6 @@ def _stub_pipelines(monkeypatch):
cache_enabled=False,
rate_limit_enabled=False,
cost_tracking_enabled=False,
smart_routing=False,
code_aware_enabled=False,
)
proxy = HeadroomProxy(config)
@ -168,7 +167,6 @@ async def test_startup_optimize_false_leaves_slots_null():
cache_enabled=False,
rate_limit_enabled=False,
cost_tracking_enabled=False,
smart_routing=False,
)
proxy = HeadroomProxy(config)

View file

@ -1,10 +1,9 @@
"""Hot-fix tests: PyO3 inline `/v1/responses` compression.
"""Rust binding tests for `/v1/responses` live-zone compression.
Re-enables compression after PR-C5 retired the Python pipeline. The
standalone Rust proxy binary (`crates/headroom-proxy`) was supposed to
handle this, but it's not deployed by the CLI today. This module
exposes a PyO3 binding so the Python proxy can call the live-zone
dispatcher in-process.
The default Python CLI runtime currently compresses Responses payloads
through CompressionUnit extraction plus ContentRouter. This module keeps
the lower-level PyO3 live-zone binding covered so Rust migration work
cannot silently break the exposed bridge.
These tests pin:

View file

@ -1,11 +1,9 @@
"""WebSocket /v1/responses compression integration tests.
"""WebSocket-shaped `/v1/responses` Rust binding tests.
PR-C5 retired Python compression on the WS path expecting the standalone
Rust proxy binary to take over (it isn't deployed by the CLI). PR #406
re-enabled compression on the HTTP path via the inline PyO3 binding.
This module pins the WS-side equivalent: the first frame from the client
must be compressed via the same PyO3 dispatcher before forwarding to
the upstream WebSocket.
The default Python CLI runtime now compresses WS `response.create` frames
through its CompressionUnit + ContentRouter path. These tests keep the
lower-level PyO3 live-zone binding covered on WebSocket-shaped envelopes
so Rust migration work cannot silently break the exposed bridge.
The tests exercise the compression *transformation logic* in isolation
they replicate the body-shape handling the WS handler does (envelope

View file

@ -145,24 +145,6 @@ class TestToolPattern:
assert pattern.full_retrieval_rate == 0.0
@pytest.mark.skip(
reason=(
"PR-B5: CompressionHint is now private (_CompressionHint) and "
"the request-time hint API is retired. See "
"tests/test_toin_observation_only.py for the replacement contract."
)
)
class TestCompressionHint:
"""Retired: CompressionHint was the public envelope for the
request-time hint API removed in PR-B5."""
def test_default_values(self):
pass
def test_custom_values(self):
pass
class TestTOINConfig:
"""Test TOINConfig data model."""

View file

@ -75,8 +75,7 @@ def test_compression_hint_is_not_publicly_exported():
import headroom.telemetry as telemetry_pkg
assert not hasattr(telemetry_pkg, "CompressionHint"), (
"PR-B5: CompressionHint became private (_CompressionHint) and "
"must not be importable from headroom.telemetry."
"PR-B5: CompressionHint was retired and must not be importable from headroom.telemetry."
)