mirror of
https://github.com/headroomlabs-ai/headroom.git
synced 2026-08-27 14:17:10 -04:00
- wiki/cli.md: add --anthropic-pre-upstream-concurrency option row and HEADROOM_ANTHROPIC_PRE_UPSTREAM_CONCURRENCY env-var note. - CHANGELOG.md: under Unreleased add Added/Fixed/Internal entries for the codex-proxy resilience work — stage timings, shared warmup, WS session registry, pre-upstream semaphore, loopback debug endpoints, repro harness, the fixes (Event.wait leak, py3.10 compat, proxy_headers, first-frame timeout, sem leak, gauge drift), and the internal refactors (IPv6 loopback, lock-free accumulators, narrow suppress, jitter helper).
16 KiB
16 KiB
Changelog
All notable changes to Headroom will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Unreleased
Added
- Canonical filesystem contract (issue #175) — new
HEADROOM_CONFIG_DIR(default~/.headroom/config, read-mostly) andHEADROOM_WORKSPACE_DIR(default~/.headroom, read-write state) env vars recognized by the Python proxy/CLI and the npm SDK. Additive; all existing per-resource env vars (HEADROOM_SAVINGS_PATH,HEADROOM_TOIN_PATH,HEADROOM_SUBSCRIPTION_STATE_PATH,HEADROOM_MODEL_LIMITS) continue to work with identical semantics. Docker install scripts anddocker-compose.native.ymlforward the new vars into containers so savings, logs, and telemetry resolve to the bind-mounted.headroompath. Seewiki/filesystem-contract.md.
[0.5.22] - 2026-04-11
Added
- Cross-agent memory — Claude saves a fact, Codex reads it back. All agents sharing one proxy share one memory store. Project-scoped DB at
.headroom/memory.db, auto user_id from$USER. - Agent provenance tracking — every memory records which agent saved it (
source_agent,source_provider,created_via), with edit history on updates. - LLM-mediated dedup — on
memory_save, enriched response hints similar existing memories to the LLM. Background async dedup auto-removes >92% cosine duplicates. Zero extra LLM calls. - Memory for OpenAI and Gemini handlers — context injection + tool handling wired into all three provider handlers (Anthropic, OpenAI, Gemini).
- Plugin architecture for
headroom learn— each agent (Claude, Codex, Gemini) is a self-contained plugin. External plugins register viaheadroom.learn_pluginentry points.--agentflag for CLI. - GeminiScanner for
headroom learn— reads~/.gemini/tmp/*/chats/session-*.jsonand.jsonl. - Code graph integration —
headroom wrap claude --code-graphauto-indexes the project via codebase-memory-mcp for call-chain traversal, impact analysis, and architectural queries. Opt-in, ~200 token overhead with Claude Code's MCP Tool Search. - OpenAI embedder auto-detection — memory backend uses OpenAI embeddings when
sentence-transformersis unavailable (no torch/2GB dependency needed). - Live traffic learning flush —
headroom wrap <agent> --learnflushes learned patterns to the correct agent-native file (MEMORY.md / AGENTS.md / GEMINI.md) at proxy shutdown.
Changed
- CodeCompressor disabled by default — AST-based code compression produced invalid syntax on 40% of real files. Code now passes through uncompressed. Use
--code-graphfor code intelligence instead, or re-enable with--code-aware. - Shared tool name map — consolidated tool normalization across all learn plugins into
_shared.py. - Dynamic CLI agent detection —
headroom learndiscovers agents via plugin registry, no hardcoded choices.
Fixed
- CodeCompressor statement-based truncation — body truncation now walks AST statements (not lines), never cuts mid-expression. Fixes syntax errors on multi-line dict literals and function calls.
- Docstring FIRST_LINE mode — uses source lines directly instead of reconstructing from byte offsets. Properly handles all quote styles.
- Memory shutdown queue drain — patterns in the save queue were lost on proxy shutdown. Now drained before exit.
Unreleased
Added
- Codex-proxy resilience hardening — reduces event-loop starvation under cold-start reconnect storms
- Stage-timing instrumentation — per-stage durations for both Codex WS accept and Anthropic
/v1/messagespre-upstream phases emitted as a singleSTAGE_TIMINGSstructured log line per request plus Prometheus histograms - Per-pipeline shared warmup — Anthropic + OpenAI pipelines eagerly load compressors/parsers once at startup; status merged into
WarmupRegistryfor/debug/warmupand/readyz - WS session registry — first-class tracking of active Codex WS sessions with deterministic relay-task cancellation and termination-cause classification (
client_disconnect,upstream_error,client_timeout, etc.) - Bounded pre-upstream Anthropic concurrency —
--anthropic-pre-upstream-concurrency/HEADROOM_ANTHROPIC_PRE_UPSTREAM_CONCURRENCYcaps simultaneous/v1/messagespre-upstream work (body read, deep copy, first compression stage, memory-context lookup, upstream connect) so replay storms cannot starve/livez,/readyz, and new Codex WS opens. Default: automax(2, min(8, cpu_count));0or negative disables (unbounded) - Loopback-only debug endpoints —
/debug/tasks,/debug/ws-sessions,/debug/warmupreturn404(not403) to non-loopback callers so external scanners cannot enumerate them - Reconnect-storm repro harness —
scripts/repro_codex_replay.pydrives concurrent WS + HTTP replay traffic against a local proxy and asserts/livezp99 under threshold;--jsonoutput routes JSON to stdout and the human summary to stderr
- Stage-timing instrumentation — per-stage durations for both Codex WS accept and Anthropic
- Proxy liveness and readiness health checks
- Adds
GET /livezfor process liveness andGET /readyzfor traffic readiness - Keeps
GET /healthbackward compatible while expanding it with readiness details and subsystem checks - Eagerly initializes configured memory backends during proxy startup so readiness reflects real serving capability
- Wires
/readyzinto the Docker imageHEALTHCHECKand the exampledocker-compose.yml
- Adds
- Durable proxy savings history
- Persists proxy compression savings history locally at
~/.headroom/proxy_savings.json - Supports
HEADROOM_SAVINGS_PATHto override the storage location - Adds
/stats-historywith lifetime totals plus hourly/daily/weekly/monthly rollups - Supports JSON and CSV export from
/stats-history - Extends
/statswith apersistent_savingsblock while keepingsavings_historybackward compatible - Adds a historical mode to
/dashboardbacked by/stats-history, including export actions
- Persists proxy compression savings history locally at
- Proxy telemetry SDK override via
HEADROOM_SDK- Downstream apps can override the anonymous telemetry
sdkfield without patching installed files - Blank values fall back to the default
proxylabel
- Downstream apps can override the anonymous telemetry
headroom learn— Offline failure learning for coding agents- Analyzes past conversation history (Claude Code, extensible to Cursor/Codex)
- Success correlation: for each failure, finds what succeeded after and extracts the specific correction
- 5 analyzers: Environment, Structure, Command Patterns, Retry Prevention, Cross-Session
- Writes specific learnings to CLAUDE.md (stable project facts) and MEMORY.md (session patterns)
- Generic architecture: tool-agnostic
ToolCallmodel, pluggable Scanner/Writer adapters - Dry-run by default,
--applyto write,--allfor all projects - Example output: "FirstClassEntity.java is not at axion-formats/ — actually at axion-scala-common/"
- Read Lifecycle Management — Event-driven compression of stale/superseded Read outputs
- Detects when a Read output becomes stale (file was edited after) or superseded (file was re-read)
- Replaces stale/superseded content with compact CCR markers, stores originals for retrieval
- 75% of Read output bytes are provably stale or redundant (from real-world analysis of 66K tool calls)
- Fresh Reads (latest read, no subsequent edit) are never touched — Edit safety preserved
- Opt-in via
ReadLifecycleConfig(enabled=True), disabled by default - Handles both OpenAI and Anthropic message formats
- any-llm backend - Route requests through 38+ LLM providers (OpenAI, Mistral, Groq, Ollama, etc.) via any-llm
- Enable with
--backend anyllm --anyllm-provider <provider> - Install with:
pip install 'headroom-ai[anyllm]'
- Enable with
- Production-ready proxy server with caching, rate limiting, and metrics
- CLI command
headroom proxyto start the proxy server - IntelligentContextManager (semantic-aware context management)
- Multi-factor importance scoring: recency, semantic similarity, TOIN importance, error indicators, forward references, token density
- No hardcoded patterns - all importance signals learned from TOIN or computed from metrics
- TOIN integration for retrieval_rate and field_semantics-based scoring
- Strategy selection: NONE, COMPRESS_FIRST, DROP_BY_SCORE based on budget overage
- Atomic tool unit handling (call + response dropped together)
- Configurable scoring weights via
ScoringWeightsdataclass IntelligentContextConfigfor full configuration control- Backwards compatible with
RollingWindowConfig
- LLMLingua-2 Integration (opt-in ML-based compression)
LLMLinguaCompressortransform using Microsoft's LLMLingua-2 model- Content-aware compression rates (code: 0.4, JSON: 0.35, text: 0.3)
- Memory management utilities:
unload_llmlingua_model(),is_llmlingua_model_loaded() - Proxy integration via
--llmlinguaflag - Device selection:
--llmlingua-device(auto/cuda/cpu/mps) - Custom compression rate:
--llmlingua-rate - Helpful startup hints when llmlingua is available but not enabled
- Install with:
pip install headroom-ai[llmlingua]
- Code-Aware Compression (AST-based, syntax-preserving)
CodeAwareCompressortransform using tree-sitter for AST parsing- Supports Python, JavaScript, TypeScript, Go, Rust, Java, C, C++
- Preserves imports, function signatures, type annotations, error handlers
- Compresses function bodies while maintaining structural integrity
- Guarantees syntactically valid output (no broken code)
- Automatic language detection from code patterns
- Memory management:
is_tree_sitter_available(),unload_tree_sitter() - Uses
tree-sitter-language-packfor broad language support - Install with:
pip install headroom-ai[code]
- ContentRouter (intelligent compression orchestrator)
- Auto-routes content to optimal compressor based on type detection
- Source hint support for high-confidence routing (file paths, tool names)
- Handles mixed content (e.g., markdown with code blocks)
- Strategies: CODE_AWARE, SMART_CRUSHER, SEARCH, LOG, TEXT, LLMLINGUA
- Configurable strategy preferences and fallbacks
- Routing decision log for transparency and debugging
- Custom Model Configuration
- Support for new models: Claude 4.5 (Opus), Claude 4 (Sonnet, Haiku), o3, o3-mini
- Pattern-based inference for unknown models (opus/sonnet/haiku tiers)
- Custom model config via
HEADROOM_MODEL_LIMITSenvironment variable - Config file support:
~/.headroom/models.json - Graceful fallback for unknown models (no crashes)
- Updated pricing data for all current models
Fixed
- Event.wait task leak in subscription trackers —
asyncio.shieldpattern prevents cancellation of the outerwait_forfrom leaking the innerEvent.waittask - Python 3.10 compatibility for memory-context fail-open — catches
asyncio.TimeoutError(the 3.10-compatible alias) rather thanTimeoutErrorto preserve behaviour on older runtimes - uvicorn
proxy_headers=False— refusesForwarded/X-Forwarded-Forrewrites so the loopback guard on/debug/*cannot be spoofed by a misconfigured reverse proxy - First-frame timeout for Codex WS accepts — guards against a client that opens a handshake and never sends the first frame; relays cancel deterministically with
client_timeout - Semaphore leak on unexpected exception in Anthropic pre-upstream path — the finalizer now releases the pre-upstream semaphore on every exit path (early 4xx, cache hit, upstream error, streaming handoff)
active_relay_tasksgauge double-decrement —deregister_and_countreturns(handle, released_task_count)atomically so the handler decrements the Prometheus gauge by the exact number it registered, eliminating drift
Internal
- IPv6-mapped loopback recognition — the loopback guard parses
::ffff:127.0.0.1and other dual-stack literals throughipaddress.ip_address(...).is_loopback - Lock-free stage-timing accumulators —
record_stage_timingswrites to per-path counters that do not contend with/metricsexport orrecord_request - Narrow
contextlib.suppressin relay classification — onlyCancelledErroris suppressed where we reclassify it; other exceptions propagate so termination cause stays truthful jitter_delay_mshelper — shared exponential-backoff + 50-150% jitter formula inheadroom/proxy/helpers.py; used by three proxy retry sites and mirrored inline in the repro harness
0.2.0 - 2025-01-07
Added
- SmartCrusher: Statistical compression for tool outputs
- Keeps first/last K items, errors, anomalies, and relevance matches
- Variance-based change point detection
- Pattern detection (time series, logs, search results)
- Relevance Scoring Engine: ML-powered item relevance
BM25Scorer: Fast keyword matching (zero dependencies)EmbeddingScorer: Semantic similarity with sentence-transformersHybridScorer: Adaptive combination of both methods
- CacheAligner: Prefix stabilization for better cache hits
- Dynamic date extraction
- Whitespace normalization
- Stable prefix hashing
- RollingWindow: Context management within token limits
- Drops oldest tool units first
- Never orphans tool results
- Preserves recent turns
- Multi-Provider Support:
- Anthropic with official
count_tokensAPI - Google with official
countTokensAPI - Cohere with official
tokenizeAPI - Mistral with official tokenizer
- LiteLLM for unified interface
- Anthropic with official
- Integrations:
- LangChain callback handler (
HeadroomOptimizer) - MCP (Model Context Protocol) utilities
- LangChain callback handler (
- Proxy Server (
headroom.proxy):- Semantic caching with LRU eviction
- Token bucket rate limiting
- Retry with exponential backoff
- Cost tracking with budget enforcement
- Prometheus metrics endpoint
- Request logging (JSONL)
- Pricing Registry: Centralized model pricing with staleness tracking
- Benchmarks: Performance benchmarks for transforms and relevance scoring
Changed
- Improved token counting accuracy across all providers
- Enhanced tool output compression with relevance-aware selection
Fixed
- Mistral tokenizer API compatibility
- Google token counting for multi-turn conversations
0.1.0 - 2025-01-05
Added
- Initial release
HeadroomClient: OpenAI-compatible client wrapperToolCrusher: Basic tool output compression- Audit mode for observation without modification
- Optimize mode for applying transforms
- Simulate mode for previewing changes
- SQLite and JSONL storage backends
- HTML report generation
- Streaming support
Safety Guarantees
- Never removes human content
- Never breaks tool ordering
- Parse failures are no-ops
- Preserves recency (last N turns)
Migration Guide
From 0.1.x to 0.2.x
The 0.2.0 release is backward compatible. New features are opt-in:
# Old code still works
from headroom import HeadroomClient, OpenAIProvider
# New SmartCrusher (replaces ToolCrusher for better compression)
from headroom import SmartCrusher, SmartCrusherConfig
config = SmartCrusherConfig(
min_tokens_to_crush=200,
max_items_after_crush=50,
)
crusher = SmartCrusher(config)
# New relevance scoring
from headroom import create_scorer
scorer = create_scorer("hybrid") # or "bm25" for zero deps
Using the Proxy
New in 0.2.0 - run Headroom as a proxy server:
# Start the proxy
python -m headroom.proxy.server --port 8787
# Use with Claude Code
ANTHROPIC_BASE_URL=http://localhost:8787 claude