Commit graph

2630 commits

Author SHA1 Message Date
github-actions[bot]
f7c2552264
chore: release main 2026-06-04 14:05:56 +00:00
Divyanshu Singh
a01c7219de docs: add troubleshooting section 2026-06-04 18:21:57 +05:30
ashishpatel26
e8ecd08829 fix(codex): fail open for proxy compression timeout 2026-06-04 14:04:49 +05:30
Tejas Chopra
f4dff9b488
Merge pull request #576 from chopratejas/fix/copilot-subscription-auth
feat(copilot): GitHub Copilot subscription mode through Headroom
2026-06-04 00:28:29 -07:00
Tejas Chopra
6ed43027b7 style(copilot): ruff-format test_copilot_auth.py
Parenthesize a multi-line conditional lambda so 'ruff format --check .'
passes (the original commit added it unformatted).
2026-06-04 00:22:04 -07:00
Tejas Chopra
e94a36cb6d test(codex): de-flake semaphore-tail ratio check on fast runners
test_concurrent_compression_has_no_semaphore_tail computed
p99/max(p50,1). On a fast/quiet CI runner p50 rounds to 0ms, so the
ratio collapses to p99-in-ms and a few ms of ordinary scheduler jitter
(p50=0ms, p99=5ms) read as ~4.8x, tripping the <4x gate — noise, not the
semaphore-contention tail it targets (tens of ms, ~27x).

Only enforce the ratio once p99 clears a 25ms scheduler-noise floor
(assert ratio < 4.0 or p99 < 25ms). A real contention regression still
trips it (large absolute tail + high ratio); sub-ms jitter no longer
does. Verified locally: the test passes.
2026-06-03 23:57:31 -07:00
Tejas Chopra
a5ff663a5e
Merge pull request #579 from praneetware/issue-561-anthropic-api-url
Issue 561 anthropic api url
2026-06-03 23:55:35 -07:00
Praneet
b9d36db7ea docs(proxy): document Anthropic API URL overrides 2026-06-04 12:07:16 +05:30
Praneet
b1d1f8cd66 docs(proxy): document ANTHROPIC_TARGET_API_URL 2026-06-04 12:04:12 +05:30
ashishpatel26
0d8de25bfc fix(proxy): remove invalid savings tracker flock 2026-06-04 11:55:14 +05:30
Tejas Chopra
f58340d11f
Merge pull request #573 from jamesx0416/codex-openai-responses-parallel-units
Speed up Headroom compression by 4x for large agent traffic
2026-06-03 23:23:46 -07:00
Tejas Chopra
5904e3fc3b docs(copilot): add cross-platform subscription testing guide + issue template
Adds TESTING-copilot-subscription.md (per-OS copy-paste test flows, what's
proven vs. needs verification, the host-native-vs-Docker discovery caveat) and a
GitHub issue template to collect structured test reports from Linux/Windows
users.
2026-06-03 23:18:32 -07:00
Tejas Chopra
72da461217 fix(copilot): deterministic subscription token handoff to the proxy
Pass the wrapper-resolved (and, for --subscription, GitHub-validated) Copilot
token to the proxy as an explicit launch argument instead of mutating the
parent process's global os.environ. The proxy pins it as
GITHUB_COPILOT_API_TOKEN, so upstream auth is deterministic rather than the
proxy re-running unvalidated token discovery (which could otherwise inject a
different token and 401). Removes the global-state mutation and the test
isolation it forced.

Add a hermetic cross-platform smoke suite (no Keychain/secret-tool/network)
proving the env-var token path resolves on any OS, each OS secret reader is
inert off-platform, and the proxy injects exactly the validated token.
2026-06-03 23:11:02 -07:00
jamesx0416
cfcaf0e364 Rename tool output compression parallelism env 2026-06-04 14:54:21 +10:00
jamesx0416
4c86826eab Cover OpenAI Responses unit cache edge cases 2026-06-04 14:20:25 +10:00
jamesx0416
d160f391d5 Speed up OpenAI Responses compression units 2026-06-04 12:52:00 +10:00
M Barry
bd0e84562c Merge branch 'chopratejas:main' into fix/thread-local-tree-sitter-parser 2026-06-03 21:45:10 -05:00
Devanshi Vyas
982d01b9c9
Merge pull request #541 from evanclan/fix/learn-gemini-flash-latest-default
fix(learn): finish gemini-flash-latest default model sweep
2026-06-03 16:23:00 -07:00
M Barry
6a70ea653c test(code_compressor): add unsendable-panic repro and thread-local parser tests 2026-06-03 17:02:07 -05:00
Mubashir R
0e551de9d8
fix: correct tiktoken encoding for unknown gpt-4 model snapshots (#552)
get_encoding_for_model() resolved an unknown model to an encoding by
scanning MODEL_TO_ENCODING for the first key that starts with the
matched prefix. Because the gpt-4o entries are defined before the
plain gpt-4 entries, the "gpt-4" prefix matched "gpt-4o" first and
returned o200k_base for any gpt-4 snapshot not already in the table
(e.g. a future dated build like gpt-4-2025-01-01). The gpt-4 family
uses cl100k_base, so token counts for those models were computed with
the wrong encoding, skewing every downstream budget/truncation
decision.

Map each prefix directly to its encoding (still ordered most-specific
first) so the result is deterministic and independent of dict
insertion order.

Regression test in tests/test_tokenizers.py asserts unknown gpt-4 /
gpt-4-turbo snapshots resolve to cl100k_base while gpt-4o snapshots
stay on o200k_base. It fails before this change and passes after.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 13:12:16 -07:00
Mubashir R
bdcfc322da
fix: ignore brackets inside JSON strings when splitting mixed content (#553)
_extract_json_block() counted raw [ ] { } per line via str.count() to
find where a JSON block ends. Any bracket/brace inside a JSON string
value (e.g. the "]" in {"path": "a]b"}) was counted as structural, so
the running balance hit zero early and the block was cut mid-array.

In ContentRouter._compress_mixed() this fragments one JSON array into
multiple sections: the array is truncated, a non-array fragment gets
mislabeled JSON_ARRAY, and the trailing "]" leaks into the next prose
section — so content is routed to the wrong compressor.

Walk the characters with a small in-string/escape state machine and
only count brackets/braces that are outside string literals. Behavior
is unchanged for JSON without brackets-in-strings.

Regression tests in tests/test_transforms_content_router.py cover both
the helper (_extract_json_block) and the end-to-end split
(split_into_sections). They fail before this change and pass after.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 12:32:56 -07:00
Michael Barry
38aefc1d34 fix: use thread-local tree-sitter parsers to prevent unsendable panic
tree-sitter >= 0.23 marks Parser as PyO3 #[pyclass(unsendable)], which
hard-panics if the object is accessed from any thread other than its
creator. The previous code cached parsers in a module-global dict and
returned them to ThreadPoolExecutor workers, triggering:

    pyo3_runtime.PanicException: _native::Parser is unsendable,
    but sent to another thread

Replace the shared dict + lock with threading.local() so each pool
thread creates and owns its own Parser instance. Switch from
tree_sitter_language_pack.get_parser() (returns wrapper types with
method-based API) to stock tree_sitter.Parser + get_language() to
preserve property-based Node/Tree access across all call sites.
2026-06-03 11:46:01 -05:00
Tejas Chopra
92075b95af
Merge pull request #536 from SuperMarioYL/fix/utf8-encoding-owned-assets
fix: decode/encode owned config, state and template assets as UTF-8 (fixes #533)
2026-06-03 08:02:41 -07:00
Tejas Chopra
6272de63d0
Merge pull request #560 from technote-space/fix-readme-perf-command
docs: fix get started perf command
2026-06-03 07:59:07 -07:00
Technote
d99df78b24 docs: fix get started perf command 2026-06-03 23:51:40 +09:00
Devdeep Sarkar
a0c54c7f22 style: fix linting and formatting issues 2026-06-03 20:08:26 +05:30
Devdeep Sarkar
896a093399 refactor: extract litellm model resolution to shared utility 2026-06-03 17:45:39 +05:30
ashishpatel26
a8b62a77d9 fix(dashboard): rebind hero tile to file-backed savings, add cross-process lock
Fixes #481.

Three changes:

1. dashboard.html: bind the 'Proxy $ Saved' hero tile and its x-show
   guards to stats.persistent_savings?.lifetime?.compression_savings_usd
   instead of stats.cost?.savings_usd. The cost field comes from the
   in-memory CostTracker which is per-process, so round-robin /stats
   polls across --workers > 1 show a different worker's partial total on
   every reload. persistent_savings.lifetime is written by SavingsTracker
   to proxy_savings.json and is read from disk on every /stats call, so
   it converges regardless of which worker handles the poll.

2. server.py: add CostTracker to the multi-worker warning printed at
   startup so operators see it alongside the existing CCR / prefix-tracker
   notice.

3. savings_tracker.py: acquire an exclusive cross-process flock on the
   target file before the atomic rename in _save_locked(). Without this,
   concurrent workers each read the same baseline at boot, accumulate
   their own deltas, and write back via tempfile+rename, clobbering each
   other's increments. flock is Unix-only; Windows silently skips it.
   The pattern matches the existing fcntl usage in ccr/mcp_server.py.
2026-06-03 15:27:00 +05:30
Tejas Chopra
ff4a0c6bc6 fix(copilot): support subscription auth through Headroom
Route GitHub Copilot CLI subscription traffic through the Headroom
OpenAI-compatible proxy path and resolve the account-specific Copilot API
endpoint before launch.

Add source-aware Copilot token discovery for explicit Copilot env vars,
macOS Keychain, Windows Credential Manager, Linux Secret Service, credential
files, and generic GitHub fallbacks. Validate subscription candidates against
GitHub Copilot user metadata so generic GH_TOKEN/GITHUB_TOKEN values do not
shadow Copilot CLI auth.

Document the subscription command and platform status in README: macOS
Keychain auth reuse has been smoke-tested, while Windows, Linux, Docker, and
CI auth-discovery paths still need real OS validation.

Tests: .venv/bin/python -m pytest tests/test_copilot_auth.py
tests/test_copilot_macos_keychain.py tests/test_copilot_linux_secret.py
tests/test_cli/test_wrap_copilot.py tests/test_cli/test_wrap_persistent.py
tests/test_proxy_copilot_auth_hooks.py
2026-06-02 21:24:47 -07:00
Devanshi Vyas
378d77e79d
fix: update dashboard doc link (#544) 2026-06-02 18:22:18 -07:00
Devanshi Vyas
55579445f8
fix(docs): mkdocs configuration to build with correct folder (#543)
* fix(docs): mkdocs configuration to build with correct folder

* fix(format): fix ruff format for test file
2026-06-02 18:07:11 -07:00
Tejas Chopra
a6a09e6cfb
Merge pull request #522 from Leathal1/main
fix(docs): bump next.js to 16.2.6 for GHSA-h64f-5h5j-jqjh (CVE-2026-44577)
2026-06-02 17:14:29 -07:00
Evan Alferez
d7973665f4 fix(learn): finish gemini-flash-latest default model sweep (#532)
Google deprecated gemini/gemini-2.0-flash; headroom learn silently fails
when GEMINI_API_KEY is set. PR #532 updated the default in analyzer.py
but left stale references in the CLI help text and unit test assertion.
2026-06-03 08:32:43 +09:00
Patrick Ancillotti
0375f7f0aa docs: fix stale API references, retired class imports, and incorrect examples
- Remove rolling_window_config from HeadroomClient Python constructor table
  (RollingWindowConfig was retired in 0.9.x)
- Fix HeadroomConfig Python example: replace config.rolling_window.preserve_recent_turns
  with a note that rolling_window was removed
- Fix ccrHashes description: cross-conversation retrieval -> Compress-Cache-Retrieve
- All other doc fixes were already applied in prior commits
2026-06-02 19:19:19 -04:00
Tejas Chopra
a359dae38f
Add Trendshift badge to README
Added a Trendshift badge to the README.
2026-06-02 16:14:30 -07:00
Tejas Chopra
1e8beb02cf
Updated README 2026-06-02 15:44:25 -07:00
supermario_leo
2f1538a641 fix: decode/encode owned config, state and template assets as UTF-8
Headroom reads and writes its own dashboard template, JSON deployment/sync
state and provider config files using the platform default text codec. On
systems whose default encoding is not UTF-8 (e.g. Windows cp949/cp1252
locales) this raises UnicodeDecodeError when the file contains non-ASCII
bytes.

The dashboard template ships with non-ASCII UTF-8 content, so loading the
dashboard crashes on a Korean Windows locale at byte 20523 (fixes #533).
The same latent bug exists in the sibling JSON state/config I/O; since these
files are owned by Headroom and JSON is UTF-8 by spec (RFC 8259 §8.1), read
and write them with an explicit encoding="utf-8" so they round-trip on every
platform.

Add a regression test covering the dashboard load and a non-ASCII JSON
state round-trip.
2026-06-03 03:25:42 +08:00
Tejas Chopra
9f8b621eb1
Updated README 2026-06-02 09:35:01 -07:00
Hermes Agent
91e0937243 fix(docs): update bun.lock to next 16.2.6 for GHSA-h64f-5h5j-jqjh (CVE-2026-44577)
The package-lock.json was already bumped to 16.2.6 in a prior commit,
but bun.lock still pinned next at 16.2.4 (vulnerable to Image Optimization
API DoS per GHSA-h64f-5h5j-jqjh). This ensures all lockfiles are consistent.

VIPER hash: 835f8d5b1d2d350d
Refs: GHSA-h64f-5h5j-jqjh / CVE-2026-44577
2026-06-02 04:25:21 +00:00
Tejas Chopra
abe4ef3b4f
Merge pull request #519 from ehendrix23/codex/fix-codex-oauth-model-discovery
Leverage /backend-api/models for Codex to pull models instead of fixed list
2026-06-01 17:08:41 -07:00
ehendrix23
cf7ac4dcc3 Document Codex model metadata helpers 2026-06-01 18:02:38 -06:00
ehendrix23
5f0c5f0fe1 Minimize Codex model metadata changes 2026-06-01 17:27:31 -06:00
ehendrix23
4be6717864 Remove Codex model registry cache 2026-06-01 17:20:12 -06:00
ehendrix23
8325c8a5c9 Remove temporary debug log level plumbing 2026-06-01 16:54:30 -06:00
ehendrix23
e0b863cb6d Add codex model discovery and logging fixes 2026-06-01 14:10:15 -06:00
Tejas Chopra
7940360b4a
Merge pull request #512 from brandonrubico/patch-1
Update formatting in README for consistency
2026-06-01 09:41:47 -07:00
Steven Cuz Leath
db5d15f99e Fix: Update Next.js to 16.2.6 in docs/package.json and package-lock.json to address GHSA-h64f-5h5j-jqjh (CVE-2026-44577) 2026-06-01 10:32:23 +00:00
Steven Cuz Leath
6eb6fb5941 fix(docs): update brace-expansion to 5.0.6 to remediate GHSA-jxxr-4gwj-5jf2 (CVE-2026-45149) 2026-06-01 10:24:34 +00:00
Steven Cuz Leath
0b9f11a223 Fix: Update Next.js to 16.2.4 in docs/bun.lock to address GHSA-gx5p-jg67-6x7h (CVE-2026-44580) 2026-06-01 10:16:15 +00:00
Steven Cuz Leath
07581b9e80 Fix: Upgrade litellm to 1.86.2 to remediate CVE-2026-42271 2026-06-01 09:57:39 +00:00