Commit graph

2630 commits

Author SHA1 Message Date
Garm
47d0e4d5a8 Fix tests 2026-03-23 13:24:02 +01:00
Garm
af448a568f . 2026-03-23 13:21:06 +01:00
Garm
cb1c9aec7d Add path "." compatibility for headroom learn 2026-03-23 13:13:54 +01:00
Tejas Chopra
acddeff384 fix: close TOIN feedback loop — retrievals now flow back for learning
Three bugs fixed:

1. observations counter: get_recommendation() now increments an
   observations counter on the ToolPattern, so we can track whether
   TOIN is being consulted during compression.

2. streaming CCR feedback: when the LLM generates headroom_retrieve
   tool_use in a streaming response, the proxy now extracts the
   hash/query and calls store.retrieve() to trigger the full feedback
   chain (_log_retrieval → process_pending_feedback → toin.record_retrieval).
   Previously, streaming responses (all Claude Code traffic) never
   triggered TOIN feedback, leaving preserve_fields empty.

3. preserve_fields population: with retrievals now flowing to TOIN,
   field_retrieval_frequency gets populated, which feeds into
   _build_recommendation() → preserve_fields in CompressionHint.
   SmartCrusher can now learn which specific fields to preserve.

Root cause: headroom_retrieve tool calls in streaming responses were
returned to the client but never recorded as retrieval events in TOIN.
The entire feedback loop was write-only — TOIN learned compression
patterns but never learned from retrieval signals.

Adds 15 new tests covering observations counter, retrieval recording,
preserve_fields population, and CCR feedback extraction.
2026-03-22 14:18:30 -07:00
Tejas Chopra
d1fe0d47c4 feat: add license key validation + phone-home usage reporter
Enables managed/enterprise customers to run the proxy in their own
environment while reporting aggregate usage back to Headroom cloud.

- HEADROOM_LICENSE_KEY env var activates managed mode
- UsageReporter validates license on startup, caches to ~/.headroom/
- Reports aggregate stats every 5 min (tokens, costs, models — no content)
- Graceful degradation: 7-day grace period if cloud unreachable
- Expired license → passthrough mode (proxy works, compression stops)
- Zero impact on OSS users (no license key = no reporter)
2026-03-22 09:21:35 -07:00
Tejas Chopra
b4d2cb07dc chore: gitignore headroom-saas (lives in separate private repo) 2026-03-21 22:35:36 -07:00
Tejas Chopra
9897bd1a4a fix: memory handler overwrites system prompt when it's a list of content blocks
When Claude Code sends the system prompt as a list of content blocks
(with cache_control markers for prompt caching), the memory context
injection was replacing the entire system prompt with just the memory
context string. This caused 400 invalid_request_error from the
Anthropic API because Claude Code's full system instructions were lost.

Root cause: the else branch in inject_memory_context set
body["system"] = context instead of appending to the existing list.

Also adds:
- X-Headroom-Bypass / X-Headroom-Mode: passthrough header support
  to skip all compression (useful for debugging)
- Full diagnostic dump to ~/.headroom/logs/debug_400/ on any upstream
  4xx/5xx, capturing pre/post compression messages, tools, headers,
  and error response for offline analysis
- Bypass guards on CCR tool injection and image compression
2026-03-21 22:29:07 -07:00
Tejas Chopra
0fd6dfcadb feat: add live traffic learning + cross-agent memory writers (--learn flag)
Live Traffic Learner extracts patterns from proxy traffic in real-time:
- Error→recovery patterns (tool fails → next success teaches right approach)
- Environment facts (working venv paths, test commands)
- User preference signals (corrections, repeated choices)

Agent-native memory writers export learned patterns to each agent's format:
- Claude Code: MEMORY.md + per-topic files
- Cursor: .cursor/rules/headroom-memory.mdc (YAML frontmatter)
- Codex: AGENTS.md
- Generic: plain markdown (Aider, Gemini, any agent)

Memory Budget Manager handles token-optimized memory files:
- Per-agent token budgets (2K Claude, 3K Cursor/Codex)
- Temporal decay, staleness detection (git + filesystem)
- Jaccard-similarity memory merging, dedup

Opt-in via --learn flag on proxy/wrap commands:
- headroom proxy --learn
- headroom wrap claude --learn
- --learn implies --memory; --no-learn overrides
- compress() API completely unaffected (pure function)
- Default behavior unchanged (no memory, no learning)
2026-03-20 15:36:06 -07:00
Tejas Chopra
b5631cdf7e chore: bump version to 0.5.2 2026-03-20 12:56:12 -07:00
Tejas Chopra
017b864a2d fix: use cache-aware pricing from LiteLLM for dashboard cost display
Input cost was computed at list price for all tokens, ignoring that
~90% are cache reads at 10% price (Anthropic). Now uses LiteLLM's
native cache_read_input_token_cost and cache_creation_input_token_cost
for accurate cost calculation. Also adds dashboard note that cost
covers message tokens only (excludes system prompt & tool definitions).
2026-03-20 12:54:59 -07:00
Tejas Chopra
9c5580baee feat: make token_headroom the default mode + fix Gemini handler bug
- Change default HEADROOM_MODE from cost_savings to token_headroom
  across server.py, cli/proxy.py, and mcp_server.py. Prefix caching
  is native to providers; Headroom's value-add is compression.
- Fix undefined _compression_failed variable in Gemini handler
  (ruff + mypy error).
- Apply ruff format fixes.
2026-03-20 11:35:14 -07:00
Tejas Chopra
c7a76dbf98 refactor: centralize error/priority pattern detection into error_detection module
Extract duplicated regex patterns and error keywords from diff_compressor,
intelligent_context, search_compressor, smart_crusher, and text_compressor
into a shared headroom/transforms/error_detection.py module.
2026-03-20 11:35:07 -07:00
Tejas Chopra
cd258d7f85 fix: pass through unknown CLI flags to wrapped tools (claude, codex, aider, cursor)
Added ignore_unknown_options to all wrap subcommands so flags like
--resume, --model etc. are forwarded to the wrapped tool instead of
being rejected by Click.
2026-03-20 11:17:15 -07:00
Tejas Chopra
3066783365 fix: propagate HEADROOM_MODE through wrap CLI and drop cache write premium penalty
Two fixes:

1. `headroom wrap claude` ignored HEADROOM_MODE env var — the Click-based
   proxy CLI never passed `mode=` to ProxyConfig, so it always defaulted
   to cost_savings. Added --mode flag to `headroom proxy` and forwarded
   HEADROOM_MODE from wrap's _start_proxy().

2. Cache write premium (1.25x) was subtracted from savings as a penalty,
   but Claude Code already pays this baseline cost regardless of Headroom.
   Renamed bust_penalty_usd → write_premium_usd (observability only) and
   stopped deducting it from net_savings_usd.
2026-03-20 10:51:41 -07:00
Garm
a24daf35ab . 2026-03-20 18:45:28 +01:00
chopratejas
62a5183814 chore: bump version to 0.5.1 2026-03-19 13:15:38 -07:00
chopratejas
aa73c7bbe1 fix: capture Zone 1 + Zone 2 savings in token_headroom stats
In token_headroom mode, original_tokens was being overwritten with the
pipeline's input view (post-Zone-1-swap), causing tokens_saved to only
reflect Zone 2 compression. Zone 1 savings from cached content swaps
were invisible in stats, cost tracking, and the session summary.

Now keeps original_tokens as the real original (from Claude Code's
uncompressed messages) so tokens_saved = Zone 1 + Zone 2.
2026-03-19 13:14:30 -07:00
chopratejas
b435d4b27d chore: bump version to 0.5.0 2026-03-19 12:59:07 -07:00
chopratejas
4bda5a31be Merge feat/token-headroom-mode: dual-mode optimization + clean stats
Token headroom mode (HEADROOM_MODE=token_headroom) compresses older
messages to extend session length, trading prefix cache cost savings
for token reduction. Content-addressed CompressionCache avoids
re-compression across turns. Works for both Anthropic and OpenAI.

Also: claude-opus-4-6 model entry, clean session summary in /stats
and MCP headroom_stats tool.
2026-03-19 12:56:39 -07:00
chopratejas
04fecd7865 feat: add clean session summary to /stats and MCP headroom_stats
The /stats endpoint now includes a "summary" section at the top with:
- Avg/best compression % on requests that actually compressed
- Breakdown of why uncompressed requests were skipped
- Cost impact: without vs with Headroom, total saved
- Actionable tip when token_headroom mode would help

The MCP headroom_stats tool returns clean formatted text instead of
dumping raw JSON when the proxy is reachable.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 12:53:41 -07:00
chopratejas
87fec30c08 fix: prevent stat inflation in compute_frozen_count, fix token estimate
- compute_frozen_count now checks _cache directly instead of calling
  get_compressed, which was inflating hit/miss stats on every turn
- update_from_result uses len//4 for rough token estimate instead of
  raw character count

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 10:50:56 -07:00
chopratejas
2e8cb31117 test: add integration tests for token_headroom mode
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 10:05:01 -07:00
chopratejas
a9c14a5508 feat: add compression_cache stats to /stats endpoint
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 10:03:47 -07:00
chopratejas
3f2e4839ce feat: add token_headroom branch to OpenAI handler
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 10:02:02 -07:00
chopratejas
e0d10503c8 feat: add token_headroom branch to Anthropic handler
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 10:00:12 -07:00
chopratejas
603db75bc0 feat: configure pipeline based on HEADROOM_MODE at startup
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 09:58:35 -07:00
chopratejas
73ccf25051 feat: add HEADROOM_MODE config to ProxyConfig
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 09:55:35 -07:00
chopratejas
c125939a9e feat: export CompressionCache from cache package 2026-03-19 09:53:40 -07:00
chopratejas
0f2f992132 feat: add frozen count, apply_cached, update_from_result to CompressionCache
Add three methods and supporting helpers for token headroom mode:
- compute_frozen_count: counts consecutive stable messages from start
- apply_cached: swaps cached compressions into tool results (immutable)
- update_from_result: learns new compressions from original/compressed pairs

Supports both Anthropic and OpenAI tool result formats.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 09:52:33 -07:00
chopratejas
ee1bcc93bd feat: add CompressionCache with LRU eviction for token headroom mode
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 09:48:52 -07:00
chopratejas
544437701d fix: add claude-opus-4-6 (1M context) to ANTHROPIC_CONTEXT_LIMITS
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 09:44:30 -07:00
chopratejas
a399a9bb37 Add implementation plan for token headroom mode
11 tasks across 4 chunks: CompressionCache core, ProxyConfig/pipeline setup,
handler integration (Anthropic + OpenAI), and integration/E2E tests.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 09:30:26 -07:00
chopratejas
f9476a1c46 Update token headroom mode spec with review fixes
Address spec review findings: fix protect_recent_fraction plumbing (set at
startup, not per-call kwarg), clarify Zone 3 scope (excluded-tool messages
only), fix frozen count to treat user/assistant as stable, increase cache
to 10K entries, add observability section, define update_from_result contract,
handle force_compress_threshold interaction, add mode-switch and latency
edge cases.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 09:15:15 -07:00
chopratejas
42883c555d Add design spec for token headroom mode
Introduces dual-mode optimization (cost_savings vs token_headroom) to address
low compression rates in long Claude Code sessions caused by prefix freeze
consuming all messages.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 09:11:37 -07:00
chopratejas
6ab448800b Add SharedContext for multi-agent, rewrite README, fix proxy cleanup
- SharedContext: compressed inter-agent context sharing via put()/get()
over existing CCR compression pipeline. Zero new dependencies.
- README rewrite: lead with "any agent" positioning, not just coding
agents. Add headroom wrap, SharedContext, MCP tools to Quick Start.
Reorder integration table: universal first, coding shortcuts last.
Update compression pipeline references (LLMLingua → Kompress).
- Fix proxy cleanup in headroom wrap: don't kill shared proxy if other
clients are still using it (was orphaning terminals 2-N).
- New docs: docs/shared-context.md
2026-03-17 16:31:04 -07:00
chopratejas
891d4d0cad Updated README and mcp docs 2026-03-16 23:15:03 -07:00
chopratejas
87b54fc159 Enhanced MCP server with compress/stats tools, fix proxy torch crash
- Fix proxy crash when torch not installed: make kompress_compressor.py
imports lazy so `is_kompress_available()` works without [ml] extra
- Rewrite MCP server from 1 tool (retrieve-only) to 3 tools:
headroom_compress (on-demand compression, no proxy needed),
headroom_retrieve (local store first, proxy fallback),
headroom_stats (session stats + sub-agent aggregation + proxy cache)
- Add shared stats file (~/.headroom/session_stats.jsonl) so sub-agent
compression stats are visible from the main session
- Add mcp to [proxy] extras so proxy users get MCP tools automatically
- Remove dead TextCompressor from exports and pipeline (was never called)
- Update mcp install messaging to clarify proxy vs MCP roles
- Fix fcntl Windows compat, asyncio deprecation, httpx timeout race

Bump version to 0.4.6.
2026-03-16 22:56:30 -07:00
chopratejas
ede8589776 Fixing tests 2026-03-15 12:07:27 -07:00
chopratejas
fb4ab08856 Fix proxy crash when torch not installed (kompress lazy imports)
The proxy startup crashed with `ModuleNotFoundError: No module named
'torch'` when installed with just `[proxy]` extras because
kompress_compressor.py had unconditional top-level torch imports.
Moved torch/transformers imports to be lazy so the module is safely
importable without the [ml] extra. Added tests for import safety.
Bumped version to 0.4.5
2026-03-15 11:51:21 -07:00
chopratejas
1415a325d3 Bump version to 0.4.4 2026-03-14 08:54:46 -07:00
chopratejas
e2aac4863a Add wrap commands for Codex/Cursor/Aider with rtk instructions, fix savings metrics
- headroom wrap codex: injects rtk instructions into AGENTS.md
- headroom wrap cursor: injects into .cursorrules, prints config steps
- headroom wrap aider: injects into CONVENTIONS.md, sets both env vars
- All with --no-rtk flag to skip rtk setup

Unified savings metrics across three layers:
- cli_filtering: tokens avoided by rtk before reaching context
- compression: tokens removed by proxy (SmartCrusher, etc.)
- prefix_cache: provider cache discount with honest attribution

Fix flaky test_process_stats_collected when psutil not installed.
2026-03-13 22:02:47 -07:00
chopratejas
0e09097735 Bump version to 0.4.3 2026-03-13 16:51:23 -07:00
chopratejas
93d41b66b1 Commit message:
Fix OpenAI streaming with backends and /v1 double-path bug

Add stream_openai_message() to LiteLLM and any-llm backends so
/v1/chat/completions with stream:true returns SSE events instead
of a JSON blob. Clients (Kilo Code, Cursor, etc.) were hanging
because the proxy ignored the stream flag when routing through
a backend.

Also strip trailing /v1 from OPENAI_TARGET_API_URL to prevent
double-path URLs like /v1/v1/models.
2026-03-13 16:49:18 -07:00
chopratejas
18118af5ce Slim core dependencies: 2.5GB → 195MB install size
Move heavy deps to optional extras: sentence-transformers, torch,
numpy, pillow, datasets, accelerate out of core. Remove unused deps
entirely (semantic-router, protobuf, sentencepiece).

New extras: [ml] for Kompress, [image] for image compression,
[langchain] for LangChain integration. Guard memory/image imports
so core install works without numpy/torch.

Core (tiktoken, pydantic, litellm, click, rich) gives full
compression: SmartCrusher, ContentRouter, CCR, TOIN, CLI.
2026-03-13 15:35:49 -07:00
Tejas Chopra
384ac34d10 fix(wrap): route through proxy, prevent pipe deadlock, bump to 0.4.2
- Fix ANTHROPIC_API_URL → ANTHROPIC_BASE_URL (SDK uses BASE_URL)
- Write proxy logs to ~/.headroom/logs/proxy.log instead of PIPE
  (macOS 64KB pipe buffer fills up, blocking the proxy process)
- Add --auto-patch to rtk init to avoid interactive prompt timeout
- Bump version to 0.4.2

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-13 13:40:30 -07:00
Tejas Chopra
b49144111d Fixing headroom wrap claude 2026-03-13 13:31:03 -07:00
chopratejas
18e31be23a Fix mypy no-any-return errors in kompress_compressor.py 2026-03-12 22:15:11 -07:00
chopratejas
1474355f1c Format prefix_cache_benchmark.py for ruff 0.15 compatibility 2026-03-12 22:03:38 -07:00
chopratejas
d2e88d362a Fix pricing lookup for retired Claude models
LiteLLM removed claude-3-5-sonnet-20241022 from its cost database.
Add alias fallback map so retired model names resolve to current
equivalents for pricing lookups.
2026-03-12 21:11:18 -07:00
chopratejas
4bea17ba8a Fix proxy backend bugs: env vars, tool forwarding, and provider support
- CLI now reads OPENAI_TARGET_API_URL, GEMINI_TARGET_API_URL, and
HEADROOM_ANYLLM_PROVIDER environment variables
- Add --openai-api-url and --gemini-api-url CLI flags
- Remove --backend choices restriction so litellm-* backends work
- Forward tools/tool_choice through LiteLLM and any-llm backends
- Parse tool call arguments from JSON string to dict (Anthropic format)
- Forward top_p, stop_sequences, tools in streaming paths
- Update Vertex AI model map with Claude 3 through 4.6 (from official docs)
- Bump version to 0.4.1
2026-03-12 20:55:26 -07:00