Commit graph

2630 commits

Author SHA1 Message Date
chopratejas
c197a14052 Update README with CompressConfig options and document compression example 2026-04-12 12:14:25 -07:00
chopratejas
62ba612c7c Add CompressConfig: user-facing compression options for compress() API
New CompressConfig dataclass controls what gets compressed and how.
Options: compress_user_messages, target_ratio, protect_recent,
protect_analysis_context, kompress_model.

Flows through: compress() → pipeline → ContentRouter → Kompress.
Proxy /v1/compress accepts config in request body.
Reverted demo hardcoded changes — defaults safe for coding agents.
2026-04-12 12:13:28 -07:00
Tejas Chopra
54ae7b9928
Merge pull request #147 from JerrettDavis/feat/anthropic-usage-insights
feat: AI quota & rate-limit tracking — Anthropic, OpenAI Codex, and GitHub Copilot
2026-04-12 10:54:22 -07:00
JerrettDavis
5d4694377c fix: reset QuotaTrackerRegistry at proxy startup to prevent duplicate-key errors
The global QuotaTrackerRegistry singleton persists across the process lifetime.
When tests spin up multiple proxy app instances in the same process, each call
to startup() tries to register the same tracker keys (subscription_window,
codex_rate_limits, copilot_quota) into the same registry, triggering:

  ValueError: A tracker with key 'subscription_window' is already registered.

Fix: call reset_quota_registry() at the start of startup() so each server
instance begins with a clean registry, then re-registers and re-starts all
trackers fresh. The tracker singletons themselves (configure_subscription_tracker,
get_codex_rate_limit_state, get_copilot_quota_tracker) remain alive and their
state is preserved across restarts.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-12 11:21:26 -05:00
chopratejas
b3a73641a0 Bump to 0.5.24 2026-04-12 09:17:49 -07:00
chopratejas
af3cd7f07f Fix #149: memory crash in Docker — missing vector index + pthread error
Three fixes for Docker-native install with --memory:

1. Add sqlite-vec to proxy extras — memory's vector index now installs
   with pip install headroom-ai[proxy]. No separate pip install needed.

2. Fix AUTO vector backend fallback — was: SQLITE_VEC → HNSW → crash.
   Now: SQLITE_VEC → HNSW → clear error message listing install options.

3. Fix ONNX pthread_setaffinity_np error in Docker containers — set
   intra/inter thread count to 1 in SessionOptions. Prevents the
   "Invalid argument" error on containers with limited CPU affinity.
2026-04-12 09:17:27 -07:00
Tejas Chopra
8bf4d29e3d
Merge pull request #148 from pacifio/main
new docs UI + ts doc coverage
2026-04-12 09:13:56 -07:00
Adib Mohsin
ef23064358 tokens saved grid 2026-04-12 13:42:20 +06:00
Adib Mohsin
911eb85a44 new docs UI + ts doc coverage 2026-04-12 13:15:58 +06:00
JerrettDavis
c03b9cca05 feat: pluggable QuotaTracker ABC + QuotaTrackerRegistry
Introduce headroom/subscription/base.py with:
- QuotaTracker ABC: key, label, is_available(), start(), stop(), get_stats()
- QuotaTrackerRegistry: register(), start_all(), stop_all(), get_all_stats()
- get_quota_registry() / reset_quota_registry() process-global singletons

Adapt all three existing trackers to implement QuotaTracker:
- SubscriptionTracker (Anthropic) — adds enabled param, key/label, get_stats(), is_available()
- CodexRateLimitState (Codex) — passive tracker, no-op start/stop already inherited
- _CopilotQuotaTracker (Copilot) — is_available() gates on discover_github_token()

Refactor server.py to use the registry:
- Single registry.start_all() / stop_all() replaces ad-hoc per-tracker calls
- /stats endpoint uses registry.get_all_stats() (dict-spread, keys unchanged)
- New /quota endpoint: unified view of all providers
- Removes _get_codex_rate_limit_stats() and _get_copilot_quota_stats() helpers

Add 19 tests in tests/test_quota_registry.py covering:
- registration, duplicate rejection, get/trackers snapshot
- start_all skips unavailable, stop_all continues on error
- get_all_stats excludes unavailable and None-returning trackers
- global singleton + reset isolation

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-12 00:58:01 -05:00
JerrettDavis
788d0e7265 feat(dashboard): expand Codex and Copilot cards to match Anthropic card layout
- Codex: 2-column Primary/Secondary window grid (h-3 bars, window labels,
  reset countdowns); Credits moved to bordered section like Anthropic
  extra-usage panel
- Copilot: 3-column category grid (Chat/Completions/Premium) with big
  used/entitlement numbers, color-coded % bars, overage-permitted status
  per category; Monthly Reset section with month-elapsed progress bar and
  formatMonthlyReset() helper
- All three provider cards now share consistent visual language:
  uppercase section labels, h-3 progress bars, border-t dividers

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-12 00:20:10 -05:00
JerrettDavis
a9f53cc104 style: apply ruff format to copilot_quota and test_copilot_quota
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-12 00:08:56 -05:00
JerrettDavis
d11feea511 feat: add GitHub Copilot monthly quota tracking
Adds passive tracking of GitHub Copilot per-category monthly quotas
(chat, completions, premium_interactions) via GET /copilot_internal/user
on api.github.com.

Token discovery checks environment variables in priority order:
  GITHUB_COPILOT_GITHUB_TOKEN > GITHUB_TOKEN >
  COPILOT_GITHUB_TOKEN > GITHUB_COPILOT_API_TOKEN

- headroom/subscription/copilot_quota.py: CopilotQuotaCategory,
  CopilotQuotaSnapshot, CopilotQuotaState, parse_copilot_quota(),
  discover_github_token(), _CopilotQuotaTracker singleton (60s poll)
- headroom/subscription/__init__.py: export new symbols
- headroom/proxy/server.py: start/stop tracker in lifecycle;
  _get_copilot_quota_stats(); copilot_quota key in /stats
- dashboard.html: GitHub Copilot Quota panel with per-category
  progress bars, remaining counts, overage alerts, reset date
- tests/test_copilot_quota.py: 25 unit tests (all pass)
- docs/screenshots/subscription_window_active.png: updated to show
  all three panels (Anthropic + Codex + GitHub Copilot)

Env vars sourced from @github/copilot v1.0.24 app.js (k6e array).
API schema sourced from copilot_internal/user via eBo/QRt zod schemas.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-11 23:58:44 -05:00
JerrettDavis
a3abbec4a3 feat: add OpenAI Codex rate-limit window tracking
Passively capture x-codex-* response headers from proxied Codex API
calls and surface them in /stats and the dashboard.

Unlike Anthropic subscription window tracking (which polls a dedicated
OAuth endpoint), Codex embeds rate-limit data directly in every API
response header — no polling, no new credentials needed.

Changes:
- headroom/subscription/codex_rate_limits.py: new module with
  CodexRateLimitWindow, CodexCreditsSnapshot, CodexRateLimitSnapshot
  data models and a thread-safe CodexRateLimitState singleton;
  parse_codex_rate_limits() parses x-codex-primary/secondary-used-percent,
  window-minutes, reset-at, credits, limit-name, and promo-message headers
- headroom/subscription/__init__.py: re-export new public symbols
- headroom/proxy/handlers/openai.py: call
  get_codex_rate_limit_state().update_from_headers() after each
  proxied /v1/chat/completions and /v1/responses response
- headroom/proxy/server.py: add codex_rate_limits key to /stats
  via _get_codex_rate_limit_stats() helper
- headroom/dashboard/templates/dashboard.html: new OpenAI Codex
  Rate-Limit Window panel (primary + secondary progress bars, credits
  balance, limit name, reset countdown); hidden when no data
- tests/test_codex_rate_limits.py: 25 unit tests covering parsing,
  window labels, reset time, credits, state updates
- docs/screenshots/subscription_window_active.png: updated screenshot
  showing both Anthropic and Codex panels in the real dashboard

Header schema (from codex-rs/codex-api/src/rate_limits.rs):
  x-codex-primary-used-percent / x-codex-primary-window-minutes /
  x-codex-primary-reset-at  (and secondary- variants)
  x-codex-credits-has-credits / -unlimited / -balance
  x-codex-limit-name / x-codex-promo-message

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-11 23:34:19 -05:00
JerrettDavis
86efb59615 docs: replace mock screenshots with real dashboard renders
Active state shows the full headroom dashboard with the Anthropic
Subscription Window panel integrated in-line after Savings Breakdown,
including 5h/7d utilisation bars, overage credit bar, Headroom
contribution grid, and anomaly detection alert.

Inactive state shows the standard dashboard without the panel —
it is conditionally rendered only when subscription_window data
is present in /stats.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-11 22:30:43 -05:00
JerrettDavis
357fe131c9 fix: ruff lint in test_subscription_tracker (unused imports, ordering)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-11 22:06:20 -05:00
JerrettDavis
958c731e75 docs: add dashboard screenshots for subscription window panel
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-11 21:58:28 -05:00
JerrettDavis
4329213e57 feat: add Anthropic Claude Code subscription window tracking
- New headroom/subscription/ package:
  - models.py: RateLimitWindow, ExtraUsage (cents->USD), SubscriptionSnapshot
    with per-model 7d windows (opus/sonnet), HeadroomContribution,
    WindowDiscrepancy, SubscriptionState
  - client.py: async httpx client for GET /api/oauth/usage with OAuth token
    resolution (env var -> credentials file -> live proxy header)
  - tracker.py: background polling singleton (asyncio Task), notify_active(),
    update_contribution(), anomaly detection (surge pricing, cache miss),
    atomic persistence, OTEL callback
  - session_tracking.py: JSONL transcript reader, Sonnet-normalised model
    weights, compute_window_tokens() for 5h/7d window boundaries
  - __init__.py: clean public re-exports

- Integration:
  - proxy/models.py: subscription_tracking_enabled, poll_interval_s,
    active_window_s config fields
  - proxy/server.py: tracker startup/shutdown, /subscription-window endpoint,
    subscription_window key in /stats
  - proxy/handlers/anthropic.py: OAuth Bearer detection, notify_active() +
    update_contribution() per request
  - observability/metrics.py: 5 observable gauges (5h/7d utilisation %,
    5h/7d seconds-to-reset, overage USD) using Observation type
  - dashboard/templates/dashboard.html: subscription window panel with 5h/7d
    progress bars, countdown, overage, Headroom contribution bar + anomaly
    alerts

- Tests: 33 new unit tests in tests/test_subscription_tracker.py (all pass)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-11 21:53:44 -05:00
chopratejas
ccc763a7b0 Bump version to 0.5.23 2026-04-11 19:45:08 -07:00
chopratejas
67aac2728b ONNX local embedder for memory — no torch dependency 2026-04-11 19:44:34 -07:00
chopratejas
00a6ab2dee Bump version to 0.5.22 2026-04-11 19:32:53 -07:00
chopratejas
3c0c540e1b Auto-download codebase-memory-mcp binary, add watchdog to proxy deps
No manual install needed. headroom wrap claude --code-graph:
1. Checks if binary exists (PATH or ~/.local/bin/)
2. Downloads from GitHub releases if not found (~15MB, one-time)
3. Indexes project + starts file watcher

Same pattern as rtk auto-download. Platform-aware:
darwin-arm64, darwin-amd64, linux-arm64, linux-amd64, windows-amd64.

Also: add watchdog>=4.0.0 to proxy extras.
2026-04-11 19:30:38 -07:00
chopratejas
95ce5ee761 Add live code graph watcher, remove --code-aware flag
Single flag: --code-graph does everything:
1. Indexes project via codebase-memory-mcp at startup
2. Starts background file watcher (watchdog) in the proxy
3. On source file changes: debounced incremental reindex (~0.4s)
4. Cross-platform: FSEvents (macOS), inotify (Linux), Windows

The watcher is agent-agnostic — watches the filesystem, not agent
hooks. Works for Claude Code, Codex, Gemini, Cursor, Aider, anything.

Removed --code-aware flag (broken AST compressor). One flag for code
intelligence, not two confusing options.

New module: headroom/graph/watcher.py (CodeGraphWatcher)
- Debounce: waits 2s after last change before reindexing
- Filters: only source file extensions, ignores .git/node_modules/etc.
- Stats: tracks reindex count, integrates with proxy lifecycle
2026-04-11 19:03:03 -07:00
Tejas Chopra
65ee4b1124
Merge pull request #145 from JerrettDavis/feat/persistent-installs
feat: add persistent install lifecycle management
2026-04-11 18:30:44 -07:00
JerrettDavis
5884f7fb41 fix: restore Windows mypy compatibility
Make Unix-only file locking imports type-safe on Windows, tighten beacon lock cleanup, and fix the remaining exposed typing issues so the repository's mypy check passes cleanly on Windows again.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-11 18:40:53 -05:00
JerrettDavis
bd242fc62d test: expand persistent install coverage
Add focused regression coverage for install, runtime, provider, state, health, supervisor, and persistent wrap flows so the new persistent deployment surfaces are exercised more thoroughly in CI.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-11 18:24:15 -05:00
JerrettDavis
865bef2216 fix: harden persistent install wrappers and review gaps
Align Docker-native wrapper help and runtime behavior with the Python install contract, including persistent deployment metadata, baked install-image defaults, and explicit unsupported wrap targets.

Harden the Python persistent-install path with profile validation, safer provider-scope handling, Windows environment restoration, runtime parity improvements, and rollback-safe apply/update behavior.

Update README, Docker install docs, CI, and focused regressions to cover the Windows BOM failure, wrapper parity, compose coverage, and Docker-native wrap behavior.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-11 18:03:21 -05:00
JerrettDavis
b325a06aae feat: harden persistent install wrappers
Tighten Docker-native bash and PowerShell wrapper validation for wrap and proxy flows, pin the bash wrapper to the install-time interpreter, clean up failed persistent container starts, and extend docs, CI, e2e, and native installer coverage for persistent Docker installs.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-11 15:56:18 -05:00
JerrettDavis
21896a095c feat: add persistent install lifecycle management
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-11 13:47:05 -05:00
chopratejas
1fee4ac8fd Revert version to 0.5.21, fix changelog header to 0.5.22 2026-04-11 11:05:10 -07:00
chopratejas
0f7f7b0f69 Release v0.6.0: cross-agent memory, plugin learn, code graph 2026-04-11 10:44:27 -07:00
chopratejas
331e59cf8d Make code graph opt-in (--code-graph), update README
Change codebase-memory-mcp from default to opt-in:
- --no-code-graph → --code-graph (explicit enable)
- No regression risk: code graph only activates when user wants it
- With Claude Code's MCP Tool Search, tool tax is ~200 tokens
  when enabled (lazy-loaded, not all 14 tools in every prompt)

Update README wrap examples to show --code-graph flag.
2026-04-11 10:43:16 -07:00
chopratejas
b0ed0de37c Fix tests: update default assertions for disabled CodeCompressor 2026-04-11 10:40:44 -07:00
chopratejas
d8a4ed3dc9 Integrate codebase-memory-mcp, disable CodeCompressor
Code graph (codebase-memory-mcp):
- Auto-index project at wrap time via _setup_code_graph()
- --no-code-graph flag on wrap claude/codex/aider to skip
- Silently skips if binary not installed (not a hard dependency)
- With Claude Code's MCP Tool Search, 14 graph tools add ~200
  tokens/request (lazy-loaded), not the full ~1,915

CodeCompressor disabled:
- code_aware_enabled defaults to False in ProxyConfig
- enable_code_aware + prefer_code_aware_for_code default False
  in ContentRouterConfig
- Code passes through uncompressed (LLMs handle code well)
- Headroom focuses on compressing non-code content (JSON, logs,
  tool outputs) where the real waste is
2026-04-11 10:19:14 -07:00
Tejas Chopra
a245234f5a
Merge pull request #130 from Gyeonghun-Park/feat/cli-llm-backend
feat(learn): add CLI-based LLM backends for keyless headroom learn
2026-04-11 09:05:26 -07:00
Tejas Chopra
12adb8ebd2
Merge pull request #136 from JerrettDavis/jd/openclaw-launch-fix
fix: lazy-load Headroom proxy startup for OpenClaw
2026-04-11 09:05:13 -07:00
Tejas Chopra
9f124c99ff
Merge pull request #139 from JerrettDavis/feat/docker-native-cli
feat(cli): add Docker-native install flow and parity docs
2026-04-11 09:05:00 -07:00
Tejas Chopra
fb953ebfe8
Merge pull request #141 from JerrettDavis/feat/copilot-wrap
feat: add GitHub Copilot CLI wrap support
2026-04-11 09:04:43 -07:00
JerrettDavis
9fa1763087 feat: add copilot CLI wrap support
Add headroom wrap copilot with backend-aware provider routing, health metadata for running proxy detection, focused Copilot tests, and docs updates across the main integration surfaces.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-11 01:20:17 -05:00
JerrettDavis
4d9c281749 fix(cli): align native wrapper help and version flags
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-11 00:40:16 -05:00
JerrettDavis
777faa85a7 docs: fix CLI parity matrix table
Separate the Docker-native parity legend from the table header so Markdown renders the matrix correctly in cli.md.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-11 00:11:10 -05:00
JerrettDavis
a1dcda6bc4 feat(cli): support OpenClaw in Docker-native installs
Add host-managed OpenClaw wrap and unwrap flows to the Docker-native wrappers so the installed headroom script can configure the OpenClaw plugin on the host while keeping Headroom itself in Docker. Reuse hidden prepare-only hooks for OpenClaw config payloads, preserve existing plugin metadata on unwrap, and update the Docker-native and integration docs to reflect the supported flow.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-11 00:04:15 -05:00
JerrettDavis
38b1483a76 feat(cli): add Docker-native install flow and parity docs
Add system-native install scripts and host wrappers for running Headroom from Docker while keeping wrapped tools on the host. Document the Docker-native path, add a complete CLI reference with help output and parity details, and add support for root help/version aliases and proxy env-based binding behavior.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-10 23:27:24 -05:00
JerrettDavis
70d0d0253b docs: restore models init comments
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-10 22:33:53 -05:00
JerrettDavis
8cf571421f docs: restore init export comments
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-10 22:25:07 -05:00
JerrettDavis
c4da04faab docs: preserve package entrypoint comments
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-10 22:10:43 -05:00
JerrettDavis
245241d2b4 fix: type cache lazy exports
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-10 21:39:10 -05:00
JerrettDavis
5998c8b0fe fix: type lazy package exports
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-10 21:31:44 -05:00
JerrettDavis
d5a33c1100 fix: type integration imports explicitly
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-10 21:23:20 -05:00
JerrettDavis
c7922d6de6 fix: honor litellm availability overrides
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-10 21:14:29 -05:00