mirror of
https://github.com/headroomlabs-ai/headroom.git
synced 2026-08-27 14:17:10 -04:00
fix: align docs and prune dead compatibility surfaces
This commit is contained in:
parent
eaf5980b4a
commit
359e8c9a5b
32 changed files with 203 additions and 264 deletions
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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 | -- |
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -95,8 +95,7 @@ curl http://localhost:8787/health
|
|||
{
|
||||
"status": "healthy",
|
||||
"version": "0.1.0",
|
||||
"uptime_seconds": 3600,
|
||||
"llmlingua_enabled": false
|
||||
"uptime_seconds": 3600
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 |
|
||||
|
|
|
|||
|
|
@ -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
|
||||
```
|
||||
|
||||
---
|
||||
|
|
|
|||
|
|
@ -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 |
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -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:**
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -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 |
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -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 |
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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`).
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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."""
|
||||
|
||||
|
|
|
|||
|
|
@ -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."
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue